@unified-myst/role-extension
Version:
Extension to support the MyST role syntax (``{name}`content` ``) in unified
103 lines (83 loc) • 2.25 kB
JavaScript
import { tokenTypes, nodeTypes } from './constants.js';
/**
* @typedef {import('mdast-util-from-markdown').Extension} FromMarkdownExtension
* @typedef {import('mdast-util-from-markdown').Handle} FromMarkdownHandle
*
* @typedef {any} MystRoleNode
* mdast node type for mystRole
* @typedef {any} MystRoleNameNode
* mdast node type for mystRole name
* @typedef {any} InlineCodeNode
*/
/**
* The MDAST extension, to convert mystRole tokens to MDAST nodes.
* @type {FromMarkdownExtension}
*/
const mystRoleMdastExt = {
enter: {
[tokenTypes.mystRole]: enterMystRole,
[tokenTypes.mystRoleName]: enterMystRoleName
},
exit: {
[tokenTypes.mystRole]: exitMystRole,
[tokenTypes.mystRoleName]: exitMystRoleName
}
};
/**
* @type {FromMarkdownHandle}
*/
function enterMystRole(token) {
this.enter(
/** @type {MystRoleNode} */
{
type: nodeTypes.mystRole,
children: []
}, token);
}
/**
* @type {FromMarkdownHandle}
*/
function exitMystRole(token) {
/** @type {MystRoleNode} */
const node = this.stack[this.stack.length - 1];
/** @type {object[]} */
const children = node.children; // expecting a mystRoleName node, then an inlineCode node
if (children.length !== 2) {
throw new Error(`Expected 2 children for mystRole, but got ${children.length}`);
}
/** @type {MystRoleNameNode} */
const nameNode = children[0];
/** @type {InlineCodeNode} */
const codeNode = children[1];
if (nameNode.type !== nodeTypes.mystRoleName) {
throw new Error(`Expected mystRoleName node, but got ${nameNode.type}`);
}
if (codeNode.type !== 'inlineCode') {
throw new Error(`Expected inlineCode node, but got ${codeNode.type}`);
}
delete node.children;
node.name = nameNode.value;
node.value = codeNode.value;
this.exit(token);
}
/**
* @type {FromMarkdownHandle}
*/
function enterMystRoleName(token) {
this.enter(
/** @type {MystRoleNameNode} */
{
type: nodeTypes.mystRoleName
}, token);
this.buffer();
}
/**
* @type {FromMarkdownHandle}
*/
function exitMystRoleName(token) {
const name = this.resume();
const node = this.stack[this.stack.length - 1]; // @ts-ignore
node.value = name;
this.exit(token);
}
export { mystRoleMdastExt };