|
|
@@ -1,267 +1,2 @@
|
|
|
-/**
|
|
|
- * @typedef {import('mdast').BlockContent} BlockContent
|
|
|
- * @typedef {import('mdast').Root} Root
|
|
|
- * @typedef {import('mdast').Paragraph} Paragraph
|
|
|
- * @typedef {import('mdast-util-from-markdown').Handle} FromMarkdownHandle
|
|
|
- * @typedef {import('mdast-util-from-markdown').Extension} FromMarkdownExtension
|
|
|
- * @typedef {import('mdast-util-from-markdown').CompileContext} CompileContext
|
|
|
- * @typedef {import('mdast-util-from-markdown').Token} Token
|
|
|
- * @typedef {import('mdast-util-to-markdown/lib/types.js').Handle} ToMarkdownHandle
|
|
|
- * @typedef {import('mdast-util-to-markdown/lib/types.js').Context} Context
|
|
|
- * @typedef {import('mdast-util-to-markdown/lib/types.js').Options} ToMarkdownExtension
|
|
|
- * @typedef {import('./complex-types').LeafDirective} LeafDirective
|
|
|
- * @typedef {import('./complex-types').TextDirective} TextDirective
|
|
|
- * @typedef {LeafDirective|TextDirective} Directive
|
|
|
- */
|
|
|
-
|
|
|
-import { checkQuote } from 'mdast-util-to-markdown/lib/util/check-quote.js';
|
|
|
-import { containerPhrasing } from 'mdast-util-to-markdown/lib/util/container-phrasing.js';
|
|
|
-import { track } from 'mdast-util-to-markdown/lib/util/track.js';
|
|
|
-import { parseEntities } from 'parse-entities';
|
|
|
-import { stringifyEntitiesLight } from 'stringify-entities';
|
|
|
-
|
|
|
-import { DirectiveType } from './consts.js';
|
|
|
-
|
|
|
-const own = {}.hasOwnProperty;
|
|
|
-
|
|
|
-const shortcut = /^[^\t\n\r "#'.<=>`}]+$/;
|
|
|
-
|
|
|
-handleDirective.peek = peekDirective;
|
|
|
-
|
|
|
-/** @type {FromMarkdownExtension} */
|
|
|
-export const directiveFromMarkdown = {
|
|
|
- canContainEols: [DirectiveType.Text],
|
|
|
- enter: {
|
|
|
- directiveLeaf: enterLeaf,
|
|
|
- directiveLeafAttributes: enterAttributes,
|
|
|
-
|
|
|
- directiveText: enterText,
|
|
|
- directiveTextAttributes: enterAttributes,
|
|
|
- },
|
|
|
- exit: {
|
|
|
- directiveLeaf: exit,
|
|
|
- directiveLeafAttributeName: exitAttributeName,
|
|
|
- directiveLeafAttributeValue: exitAttributeValue,
|
|
|
- directiveLeafAttributes: exitAttributes,
|
|
|
- directiveLeafName: exitName,
|
|
|
-
|
|
|
- directiveText: exit,
|
|
|
- directiveTextAttributeName: exitAttributeName,
|
|
|
- directiveTextAttributeValue: exitAttributeValue,
|
|
|
- directiveTextAttributes: exitAttributes,
|
|
|
- directiveTextName: exitName,
|
|
|
- },
|
|
|
-};
|
|
|
-
|
|
|
-/** @type {ToMarkdownExtension} */
|
|
|
-export const directiveToMarkdown = {
|
|
|
- unsafe: [
|
|
|
- {
|
|
|
- character: '\r',
|
|
|
- inConstruct: [DirectiveType.Leaf],
|
|
|
- },
|
|
|
- {
|
|
|
- character: '\n',
|
|
|
- inConstruct: [DirectiveType.Leaf],
|
|
|
- },
|
|
|
- {
|
|
|
- before: '[^$]',
|
|
|
- character: '$',
|
|
|
- after: '[A-Za-z]',
|
|
|
- inConstruct: ['phrasing'],
|
|
|
- },
|
|
|
- { atBreak: true, character: '$', after: '$' },
|
|
|
- ],
|
|
|
- handlers: {
|
|
|
- [DirectiveType.Leaf]: handleDirective,
|
|
|
- [DirectiveType.Text]: handleDirective,
|
|
|
- },
|
|
|
-};
|
|
|
-
|
|
|
-/** @type {FromMarkdownHandle} */
|
|
|
-function enterLeaf(token) {
|
|
|
- enter.call(this, DirectiveType.Leaf, token);
|
|
|
-}
|
|
|
-
|
|
|
-/** @type {FromMarkdownHandle} */
|
|
|
-function enterText(token) {
|
|
|
- enter.call(this, DirectiveType.Text, token);
|
|
|
-}
|
|
|
-
|
|
|
-/**
|
|
|
- * @this {CompileContext}
|
|
|
- * @param {Directive['type']} type
|
|
|
- * @param {Token} token
|
|
|
- */
|
|
|
-function enter(type, token) {
|
|
|
- this.enter({
|
|
|
- type, name: '', attributes: {}, children: [],
|
|
|
- }, token);
|
|
|
-}
|
|
|
-
|
|
|
-/**
|
|
|
- * @this {CompileContext}
|
|
|
- * @param {Token} token
|
|
|
- */
|
|
|
-function exitName(token) {
|
|
|
- const node = /** @type {Directive} */ (this.stack[this.stack.length - 1]);
|
|
|
- node.name = this.sliceSerialize(token);
|
|
|
-}
|
|
|
-
|
|
|
-/** @type {FromMarkdownHandle} */
|
|
|
-function enterAttributes() {
|
|
|
- this.setData('directiveAttributes', []);
|
|
|
- this.buffer(); // Capture EOLs
|
|
|
-}
|
|
|
-
|
|
|
-/** @type {FromMarkdownHandle} */
|
|
|
-function exitAttributeValue(token) {
|
|
|
- const list = /** @type {Array.<[string, string]>} */ (
|
|
|
- this.getData('directiveAttributes')
|
|
|
- );
|
|
|
- list[list.length - 1][1] = parseEntities(this.sliceSerialize(token));
|
|
|
-}
|
|
|
-
|
|
|
-/** @type {FromMarkdownHandle} */
|
|
|
-function exitAttributeName(token) {
|
|
|
- const list = /** @type {Array.<[string, string]>} */ (
|
|
|
- this.getData('directiveAttributes')
|
|
|
- );
|
|
|
-
|
|
|
- // Attribute names in CommonMark are significantly limited, so character
|
|
|
- // references can’t exist.
|
|
|
- list.push([this.sliceSerialize(token), '']);
|
|
|
-}
|
|
|
-
|
|
|
-/** @type {FromMarkdownHandle} */
|
|
|
-function exitAttributes() {
|
|
|
- const list = /** @type {Array.<[string, string]>} */ (
|
|
|
- this.getData('directiveAttributes')
|
|
|
- );
|
|
|
- /** @type {Record.<string, string>} */
|
|
|
- const cleaned = {};
|
|
|
- let index = -1;
|
|
|
-
|
|
|
- while (++index < list.length) {
|
|
|
- const attribute = list[index];
|
|
|
-
|
|
|
- cleaned[attribute[0]] = attribute[1];
|
|
|
- }
|
|
|
-
|
|
|
- this.setData('directiveAttributes');
|
|
|
- this.resume(); // Drop EOLs
|
|
|
- const node = /** @type {Directive} */ (this.stack[this.stack.length - 1]);
|
|
|
- node.attributes = cleaned;
|
|
|
-}
|
|
|
-
|
|
|
-/** @type {FromMarkdownHandle} */
|
|
|
-function exit(token) {
|
|
|
- this.exit(token);
|
|
|
-}
|
|
|
-
|
|
|
-/**
|
|
|
- * @type {ToMarkdownHandle}
|
|
|
- * @param {Directive} node
|
|
|
- */
|
|
|
-function handleDirective(node, _, context, safeOptions) {
|
|
|
- const tracker = track(safeOptions);
|
|
|
- const sequence = fence(node);
|
|
|
- const exit = context.enter(node.type);
|
|
|
- let value = tracker.move(sequence + (node.name || ''));
|
|
|
- /** @type {Directive|Paragraph|undefined} */
|
|
|
- const label = node;
|
|
|
-
|
|
|
- if (label && label.children && label.children.length > 0) {
|
|
|
- const exit = context.enter('label');
|
|
|
- const subexit = context.enter(`${node.type}Label`);
|
|
|
- value += tracker.move('[');
|
|
|
- value += tracker.move(
|
|
|
- containerPhrasing(label, context, {
|
|
|
- ...tracker.current(),
|
|
|
- before: value,
|
|
|
- after: ']',
|
|
|
- }),
|
|
|
- );
|
|
|
- value += tracker.move(']');
|
|
|
- subexit();
|
|
|
- exit();
|
|
|
- }
|
|
|
-
|
|
|
- value += tracker.move(attributes(node, context));
|
|
|
-
|
|
|
- exit();
|
|
|
- return value;
|
|
|
-}
|
|
|
-
|
|
|
-/** @type {ToMarkdownHandle} */
|
|
|
-function peekDirective() {
|
|
|
- return '$';
|
|
|
-}
|
|
|
-
|
|
|
-/**
|
|
|
- * @param {Directive} node
|
|
|
- * @param {Context} context
|
|
|
- * @returns {string}
|
|
|
- */
|
|
|
-function attributes(node, context) {
|
|
|
- const quote = checkQuote(context);
|
|
|
- const subset = node.type === DirectiveType.Text ? [quote] : [quote, '\n', '\r'];
|
|
|
- const attrs = node.attributes || {};
|
|
|
- /** @type {Array.<string>} */
|
|
|
- const values = [];
|
|
|
- /** @type {string|undefined} */
|
|
|
- let classesFull;
|
|
|
- /** @type {string|undefined} */
|
|
|
- let classes;
|
|
|
- /** @type {string|undefined} */
|
|
|
- let id;
|
|
|
- /** @type {string} */
|
|
|
- let key;
|
|
|
-
|
|
|
- // eslint-disable-next-line no-restricted-syntax
|
|
|
- for (key in attrs) {
|
|
|
- if (
|
|
|
- own.call(attrs, key)
|
|
|
- && attrs[key] !== undefined
|
|
|
- && attrs[key] !== null
|
|
|
- ) {
|
|
|
- const value = String(attrs[key]);
|
|
|
-
|
|
|
- values.push(quoted(key, value));
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- return values.length > 0 ? `(${values.join(' ')})` : '';
|
|
|
-
|
|
|
- /**
|
|
|
- * @param {string} key
|
|
|
- * @param {string} value
|
|
|
- * @returns {string}
|
|
|
- */
|
|
|
- function quoted(key, value) {
|
|
|
- return (
|
|
|
- key
|
|
|
- + (value
|
|
|
- ? `=${quote}${stringifyEntitiesLight(value, { subset })}${quote}`
|
|
|
- : '')
|
|
|
- );
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-/**
|
|
|
- * @param {Directive} node
|
|
|
- * @returns {string}
|
|
|
- */
|
|
|
-function fence(node) {
|
|
|
- let size = 0;
|
|
|
-
|
|
|
- if (node.type === DirectiveType.Leaf) {
|
|
|
- size = 1;
|
|
|
- }
|
|
|
- else {
|
|
|
- size = 1;
|
|
|
- }
|
|
|
-
|
|
|
- return '$'.repeat(size);
|
|
|
-
|
|
|
-}
|
|
|
+export { directiveFromMarkdown, directiveToMarkdown } from './lib/index.js';
|
|
|
+export { DirectiveType as DirectiveTypeObject } from './lib/index.js';
|