mystjs
Version:
Markdown parser for MyST markdown in JavaScript
116 lines • 4.57 kB
JavaScript
Object.defineProperty(exports, "__esModule", { value: true });
exports.MarkdownParseState = void 0;
const unist_builder_1 = require("unist-builder");
const utils_1 = require("./utils");
const UNHIDDEN_TOKENS = new Set([
'parsed_directive_open',
'parsed_directive_close',
'parsed_role_open',
'parsed_role_close',
]);
function addPositionsToNode(node, token) {
if (token.map) {
node.position = {
start: { line: token.map[0], column: 0 },
end: { line: token.map[1], column: 0 },
};
}
}
/** MarkdownParseState tracks the context of a running token stream.
*
* Loosly based on prosemirror-markdown
*/
class MarkdownParseState {
constructor(handlers) {
this.stack = [(0, unist_builder_1.u)('root', [])];
this.handlers = getTokenHandlers(handlers);
}
top() {
return this.stack[this.stack.length - 1];
}
addNode(node) {
var _a;
const top = this.top();
if (this.stack.length && node && 'children' in top)
(_a = top.children) === null || _a === void 0 ? void 0 : _a.push(node);
return node;
}
addText(text, token, type = 'text', attrs) {
var _a, _b;
const top = this.top();
const value = text;
if (!value || !this.stack.length || !type || !('children' in top))
return;
const last = (_a = top.children) === null || _a === void 0 ? void 0 : _a[top.children.length - 1];
if (type === 'text' && (last === null || last === void 0 ? void 0 : last.type) === type) {
// The last node is also text, merge it with a space
last.value += `${value}`;
return last;
}
const node = Object.assign(Object.assign({ type: type }, attrs), { value });
(_b = top.children) === null || _b === void 0 ? void 0 : _b.push(node);
addPositionsToNode(node, token);
return node;
}
openNode(type, token, attrs, isLeaf = false) {
const node = Object.assign({ type }, attrs);
addPositionsToNode(node, token);
if (!isLeaf)
node.children = [];
this.stack.push(node);
}
closeNode() {
const node = this.stack.pop();
return this.addNode(node);
}
parseTokens(tokens) {
tokens === null || tokens === void 0 ? void 0 : tokens.forEach((token, index) => {
if (token.hidden && !UNHIDDEN_TOKENS.has(token.type))
return;
const handler = this.handlers[token.type];
if (!handler)
throw new Error(`Token type ${token.type} not supported by tokensToMyst parser`);
handler(this, token, tokens, index);
});
}
}
exports.MarkdownParseState = MarkdownParseState;
function getAttrs(spec, token, tokens, index) {
var _a;
const attrs = ((_a = spec.getAttrs) === null || _a === void 0 ? void 0 : _a.call(spec, token, tokens, index)) || spec.attrs || {};
if ('type' in attrs)
throw new Error('You can not have "type" as attrs.');
if ('children' in attrs)
throw new Error('You can not have "children" as attrs.');
return attrs;
}
function noCloseToken(spec, type) {
return spec.noCloseToken || type == 'code_inline' || type == 'code_block' || type == 'fence';
}
function getTokenHandlers(specHandlers) {
const handlers = {};
Object.entries(specHandlers).forEach(([type, spec]) => {
const nodeType = spec.type;
if (noCloseToken(spec, type)) {
handlers[type] = (state, tok, tokens, i) => {
if (spec.isText) {
state.addText((0, utils_1.withoutTrailingNewline)(tok.content), tok, spec.type, getAttrs(spec, tok, tokens, i));
return;
}
state.openNode(nodeType, tok, getAttrs(spec, tok, tokens, i), spec.isLeaf);
state.addText((0, utils_1.withoutTrailingNewline)(tok.content), tok);
state.closeNode();
};
}
else {
handlers[type + '_open'] = (state, tok, tokens, i) => state.openNode(nodeType, tok, getAttrs(spec, tok, tokens, i));
handlers[type + '_close'] = (state) => state.closeNode();
}
});
handlers.text = (state, tok) => state.addText(tok.content, tok);
handlers.inline = (state, tok) => state.parseTokens(tok.children);
handlers.softbreak = handlers.softbreak || ((state, tok) => state.addText('\n', tok));
return handlers;
}
//# sourceMappingURL=fromMarkdown.js.map
;