UNPKG

@unified-myst/role-extension

Version:

Extension to support the MyST role syntax (``{name}`content` ``) in unified

100 lines (82 loc) 2.3 kB
import { codeText } from 'micromark-core-commonmark'; import { tokenTypes } from './constants.js'; /** * @typedef {import('micromark-util-types').Code} Code * @typedef {import('micromark-util-types').Extension} Extension * @typedef {import('micromark-util-types').Tokenizer} Tokenizer * @typedef {import('micromark-util-types').State} State */ /** * The micromark extension, to parse the source syntax to events. * Events are token enter/exits, which in-turn are references to slices of the source text. * * @type {Extension} */ const mystRoleMmarkExt = { text: { [123]: { name: 'mystRole', tokenize: tokenizeMystRole } } }; const nameCharRegex = /[a-zA-Z0-9_.\-+:]/; /** * Check whether a code matches the bound regex. * * @param {Code} code Character code * @returns {code is number} Whether the character code matches the bound regex */ function checkNameChar(code) { return code !== null && nameCharRegex.test(String.fromCharCode(code)); } /** @type {Tokenizer} */ function tokenizeMystRole(effects, ok, nok) { let emptyName = true; return start; /** @type {State} */ function start(code) { effects.enter(tokenTypes.mystRole); effects.enter(tokenTypes.mystRoleMarker); effects.consume(code); effects.exit(tokenTypes.mystRoleMarker); return afterOpen; } /** @type {State} */ function afterOpen(code) { if (!checkNameChar(code)) { return nok(code); } effects.enter(tokenTypes.mystRoleName); effects.enter("chunkString", { contentType: "string" }); return consumeName(code); } /** @type {State} */ function consumeName(code) { if (code === 125) { if (emptyName) { return nok(code); } effects.exit("chunkString"); effects.exit(tokenTypes.mystRoleName); effects.enter(tokenTypes.mystRoleMarker); effects.consume(code); effects.exit(tokenTypes.mystRoleMarker); return effects.attempt(codeText, closeRole, nok); } if (!checkNameChar(code)) { return nok(code); } effects.consume(code); emptyName = false; return consumeName; } /** @type {State} */ function closeRole(code) { effects.exit(tokenTypes.mystRole); return ok(code); } } export { mystRoleMmarkExt };