basant307/AI_Governance_Project
048
1/**2 * @import {3 * Code,4 * InitialConstruct,5 * Initializer,6 * Resolver,7 * State,8 * TokenizeContext9 * } from 'micromark-util-types'10 */11 12export const resolver = {13 resolveAll: createResolver()14};15export const string = initializeFactory('string');16export const text = initializeFactory('text');17 18/**19 * @param {'string' | 'text'} field20 * Field.21 * @returns {InitialConstruct}22 * Construct.23 */24function initializeFactory(field) {25 return {26 resolveAll: createResolver(field === 'text' ? resolveAllLineSuffixes : undefined),27 tokenize: initializeText28 };29 30 /**31 * @this {TokenizeContext}32 * Context.33 * @type {Initializer}34 */35 function initializeText(effects) {36 const self = this;37 const constructs = this.parser.constructs[field];38 const text = effects.attempt(constructs, start, notText);39 return start;40 41 /** @type {State} */42 function start(code) {43 return atBreak(code) ? text(code) : notText(code);44 }45 46 /** @type {State} */47 function notText(code) {48 if (code === null) {49 effects.consume(code);50 return;51 }52 effects.enter("data");53 effects.consume(code);54 return data;55 }56 57 /** @type {State} */58 function data(code) {59 if (atBreak(code)) {60 effects.exit("data");61 return text(code);62 }63 64 // Data.65 effects.consume(code);66 return data;67 }68 69 /**70 * @param {Code} code71 * Code.72 * @returns {boolean}73 * Whether the code is a break.74 */75 function atBreak(code) {76 if (code === null) {77 return true;78 }79 const list = constructs[code];80 let index = -1;81 if (list) {82 // Always populated by defaults.83 84 while (++index < list.length) {85 const item = list[index];86 if (!item.previous || item.previous.call(self, self.previous)) {87 return true;88 }89 }90 }91 return false;92 }93 }94}95 96/**97 * @param {Resolver | undefined} [extraResolver]98 * Resolver.99 * @returns {Resolver}100 * Resolver.101 */102function createResolver(extraResolver) {103 return resolveAllText;104 105 /** @type {Resolver} */106 function resolveAllText(events, context) {107 let index = -1;108 /** @type {number | undefined} */109 let enter;110 111 // A rather boring computation (to merge adjacent `data` events) which112 // improves mm performance by 29%.113 while (++index <= events.length) {114 if (enter === undefined) {115 if (events[index] && events[index][1].type === "data") {116 enter = index;117 index++;118 }119 } else if (!events[index] || events[index][1].type !== "data") {120 // Don’t do anything if there is one data token.121 if (index !== enter + 2) {122 events[enter][1].end = events[index - 1][1].end;123 events.splice(enter + 2, index - enter - 2);124 index = enter + 2;125 }126 enter = undefined;127 }128 }129 return extraResolver ? extraResolver(events, context) : events;130 }131}132 133/**134 * A rather ugly set of instructions which again looks at chunks in the input135 * stream.136 * The reason to do this here is that it is *much* faster to parse in reverse.137 * And that we can’t hook into `null` to split the line suffix before an EOF.138 * To do: figure out if we can make this into a clean utility, or even in core.139 * As it will be useful for GFMs literal autolink extension (and maybe even140 * tables?)141 *142 * @type {Resolver}143 */144function resolveAllLineSuffixes(events, context) {145 let eventIndex = 0; // Skip first.146 147 while (++eventIndex <= events.length) {148 if ((eventIndex === events.length || events[eventIndex][1].type === "lineEnding") && events[eventIndex - 1][1].type === "data") {149 const data = events[eventIndex - 1][1];150 const chunks = context.sliceStream(data);151 let index = chunks.length;152 let bufferIndex = -1;153 let size = 0;154 /** @type {boolean | undefined} */155 let tabs;156 while (index--) {157 const chunk = chunks[index];158 if (typeof chunk === 'string') {159 bufferIndex = chunk.length;160 while (chunk.charCodeAt(bufferIndex - 1) === 32) {161 size++;162 bufferIndex--;163 }164 if (bufferIndex) break;165 bufferIndex = -1;166 }167 // Number168 else if (chunk === -2) {169 tabs = true;170 size++;171 } else if (chunk === -1) {172 // Empty173 } else {174 // Replacement character, exit.175 index++;176 break;177 }178 }179 180 // Allow final trailing whitespace.181 if (context._contentTypeTextTrailing && eventIndex === events.length) {182 size = 0;183 }184 if (size) {185 const token = {186 type: eventIndex === events.length || tabs || size < 2 ? "lineSuffix" : "hardBreakTrailing",187 start: {188 _bufferIndex: index ? bufferIndex : data.start._bufferIndex + bufferIndex,189 _index: data.start._index + index,190 line: data.end.line,191 column: data.end.column - size,192 offset: data.end.offset - size193 },194 end: {195 ...data.end196 }197 };198 data.end = {199 ...token.start200 };201 if (data.start.offset === data.end.offset) {202 Object.assign(data, token);203 } else {204 events.splice(eventIndex, 0, ['enter', token, context], ['exit', token, context]);205 eventIndex += 2;206 }207 }208 eventIndex++;209 }210 }211 return events;212}