Skip to content

Commit

Permalink
feat(markdown): add support for GFM noteblocks proposal (#10168)
Browse files Browse the repository at this point in the history
* Add support for GFM noteblocks proposal

* Add support for caution, tip and important notecard types

* Keep with the three existing noteblock types

* Remove preparation for other three types

* Don't add space for Chinese locales

* chore(m2h): add getNotecardType() types

* chore(m2h): add getL10nCardMap() return type

* Update JSDoc...?

---------

Co-authored-by: Claas Augner <[email protected]>
  • Loading branch information
queengooborg and caugner authored May 2, 2024
1 parent 9c61077 commit afeb857
Showing 1 changed file with 77 additions and 23 deletions.
100 changes: 77 additions & 23 deletions markdown/m2h/handlers/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,9 @@ import { asDefinitionList, isDefinitionList } from "./dl.js";
import { Handler, Handlers, State } from "mdast-util-to-hast";

/* A utilitary function which parses a JSON gettext file
to return a Map with each localized string and its matching ID */
function getL10nCardMap(locale = DEFAULT_LOCALE) {
to return a Map with each key and its corresponding localized string.
If the locale specified is not found, it will fallback to English */
function getL10nCardMap(locale = DEFAULT_LOCALE): Map<string, string> {
// Test if target localization file exists, if
// not, fallback on English
let localeFilePath = new URL(
Expand All @@ -27,35 +28,61 @@ function getL10nCardMap(locale = DEFAULT_LOCALE) {

Object.keys(listMsgObj).forEach((msgName) => {
l10nCardMap.set(
listMsgObj[msgName]["msgstr"][0],
listMsgObj[msgName]["msgid"]
listMsgObj[msgName]["msgid"],
listMsgObj[msgName]["msgstr"][0]
);
});
return l10nCardMap;
}

function getNotecardType(node, locale) {
interface NotecardType {
type: string;
isGFM: boolean;
magicKeyword: string;
}

function getNotecardType(node: any, locale: string): NotecardType | null {
const types = ["note", "warning", "callout"];

if (!node.children) {
return null;
}
const [child] = node.children;
if (!child || !child.children) {
if (!child?.children) {
return null;
}
const [grandChild] = child.children;
if (grandChild.type != "strong" || !grandChild.children) {
return null;
}

// E.g. in en-US magicKeyword === Note:
const magicKeyword = grandChild.children[0].value;
const l10nCardMap = getL10nCardMap(locale);
let type;
if (l10nCardMap.has(magicKeyword)) {
const msgId = l10nCardMap.get(magicKeyword);
type = msgId.split("_")[1];

// GFM proposed notecard syntax -- https://github.com/orgs/community/discussions/16925
if (grandChild.type === "text") {
const firstLine = grandChild.value.split("\n")[0];
const match = firstLine.match(
new RegExp(`\\[!(${types.map((t) => t.toUpperCase()).join("|")})\\]`)
);
if (match) {
const type = match[1].toLowerCase();
const magicKeyword = l10nCardMap.get(`card_${type}_label`);
return { type, isGFM: true, magicKeyword };
}
}

if (grandChild.type === "strong" && grandChild.children) {
// E.g. in en-US magicKeyword === Note:
const magicKeyword = grandChild.children[0].value;

for (const entry of l10nCardMap.entries()) {
if (entry[1] === magicKeyword) {
const type = entry[0].split("_")[1];
return types.includes(type)
? { type, isGFM: false, magicKeyword }
: null;
}
}
}
return type == "warning" || type == "note" || type == "callout" ? type : null;

return null;
}

export function buildLocalizedHandlers(locale: string): Handlers {
Expand Down Expand Up @@ -86,18 +113,45 @@ export function buildLocalizedHandlers(locale: string): Handlers {
blockquote(state: State, node: any): ReturnType<Handler> {
const type = getNotecardType(node, locale);
if (type) {
const isCallout = type == "callout";
if (isCallout) {
if (node.children[0].children.length <= 1) {
node.children.splice(0, 1);
} else {
node.children[0].children.splice(0, 1);
const isCallout = type.type == "callout";

if (type.isGFM) {
// Handle GFM proposed syntax
node.children[0].children[0].value =
node.children[0].children[0].value.replace(/\[!\w+\]\n/, "");

// If the type isn't a callout, add the magic keyword
if (!isCallout) {
node.children[0].children.unshift({
type: "strong",
children: [
{
type: "text",
value: type.magicKeyword,
},
],
});
node.children[0].children[1].value =
(["zh-CN", "zh-TW"].includes(locale) ? "" : " ") +
node.children[0].children[1].value;
}
} else {
// Remove "Callout:" text
if (isCallout) {
if (node.children[0].children.length <= 1) {
node.children.splice(0, 1);
} else {
node.children[0].children.splice(0, 1);
}
}
}

return {
type: "element",
tagName: "div",
properties: { className: isCallout ? [type] : ["notecard", type] },
properties: {
className: isCallout ? [type.type] : ["notecard", type.type],
},
children: state.wrap(state.all(node), true),
};
}
Expand Down

0 comments on commit afeb857

Please sign in to comment.