AK-21/Graphite-Industrial-Intelligence
0
1/**2 * @import {3 * Code,4 * Construct,5 * Resolver,6 * State,7 * TokenizeContext,8 * Tokenizer9 * } from 'micromark-util-types'10 */11 12import { factorySpace } from 'micromark-factory-space';13import { markdownLineEnding, markdownSpace } from 'micromark-util-character';14/** @type {Construct} */15export const setextUnderline = {16 name: 'setextUnderline',17 resolveTo: resolveToSetextUnderline,18 tokenize: tokenizeSetextUnderline19};20 21/** @type {Resolver} */22function resolveToSetextUnderline(events, context) {23 // To do: resolve like `markdown-rs`.24 let index = events.length;25 /** @type {number | undefined} */26 let content;27 /** @type {number | undefined} */28 let text;29 /** @type {number | undefined} */30 let definition;31 32 // Find the opening of the content.33 // It’ll always exist: we don’t tokenize if it isn’t there.34 while (index--) {35 if (events[index][0] === 'enter') {36 if (events[index][1].type === "content") {37 content = index;38 break;39 }40 if (events[index][1].type === "paragraph") {41 text = index;42 }43 }44 // Exit45 else {46 if (events[index][1].type === "content") {47 // Remove the content end (if needed we’ll add it later)48 events.splice(index, 1);49 }50 if (!definition && events[index][1].type === "definition") {51 definition = index;52 }53 }54 }55 const heading = {56 type: "setextHeading",57 start: {58 ...events[content][1].start59 },60 end: {61 ...events[events.length - 1][1].end62 }63 };64 65 // Change the paragraph to setext heading text.66 events[text][1].type = "setextHeadingText";67 68 // If we have definitions in the content, we’ll keep on having content,69 // but we need move it.70 if (definition) {71 events.splice(text, 0, ['enter', heading, context]);72 events.splice(definition + 1, 0, ['exit', events[content][1], context]);73 events[content][1].end = {74 ...events[definition][1].end75 };76 } else {77 events[content][1] = heading;78 }79 80 // Add the heading exit at the end.81 events.push(['exit', heading, context]);82 return events;83}84 85/**86 * @this {TokenizeContext}87 * Context.88 * @type {Tokenizer}89 */90function tokenizeSetextUnderline(effects, ok, nok) {91 const self = this;92 /** @type {NonNullable<Code>} */93 let marker;94 return start;95 96 /**97 * At start of heading (setext) underline.98 *99 * ```markdown100 * | aa101 * > | ==102 * ^103 * ```104 *105 * @type {State}106 */107 function start(code) {108 let index = self.events.length;109 /** @type {boolean | undefined} */110 let paragraph;111 // Find an opening.112 while (index--) {113 // Skip enter/exit of line ending, line prefix, and content.114 // We can now either have a definition or a paragraph.115 if (self.events[index][1].type !== "lineEnding" && self.events[index][1].type !== "linePrefix" && self.events[index][1].type !== "content") {116 paragraph = self.events[index][1].type === "paragraph";117 break;118 }119 }120 121 // To do: handle lazy/pierce like `markdown-rs`.122 // To do: parse indent like `markdown-rs`.123 if (!self.parser.lazy[self.now().line] && (self.interrupt || paragraph)) {124 effects.enter("setextHeadingLine");125 marker = code;126 return before(code);127 }128 return nok(code);129 }130 131 /**132 * After optional whitespace, at `-` or `=`.133 *134 * ```markdown135 * | aa136 * > | ==137 * ^138 * ```139 *140 * @type {State}141 */142 function before(code) {143 effects.enter("setextHeadingLineSequence");144 return inside(code);145 }146 147 /**148 * In sequence.149 *150 * ```markdown151 * | aa152 * > | ==153 * ^154 * ```155 *156 * @type {State}157 */158 function inside(code) {159 if (code === marker) {160 effects.consume(code);161 return inside;162 }163 effects.exit("setextHeadingLineSequence");164 return markdownSpace(code) ? factorySpace(effects, after, "lineSuffix")(code) : after(code);165 }166 167 /**168 * After sequence, after optional whitespace.169 *170 * ```markdown171 * | aa172 * > | ==173 * ^174 * ```175 *176 * @type {State}177 */178 function after(code) {179 if (code === null || markdownLineEnding(code)) {180 effects.exit("setextHeadingLine");181 return ok(code);182 }183 return nok(code);184 }185}