| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225 |
- /**
- * @import {
- * Construct,
- * Previous,
- * Resolver,
- * State,
- * TokenizeContext,
- * Tokenizer,
- * Token
- * } from 'micromark-util-types'
- */
- import { markdownLineEnding } from 'micromark-util-character';
- /** @type {Construct} */
- export const codeText = {
- name: 'codeText',
- previous,
- resolve: resolveCodeText,
- tokenize: tokenizeCodeText
- };
- // To do: next major: don’t resolve, like `markdown-rs`.
- /** @type {Resolver} */
- function resolveCodeText(events) {
- let tailExitIndex = events.length - 4;
- let headEnterIndex = 3;
- /** @type {number} */
- let index;
- /** @type {number | undefined} */
- let enter;
- // If we start and end with an EOL or a space.
- if ((events[headEnterIndex][1].type === "lineEnding" || events[headEnterIndex][1].type === 'space') && (events[tailExitIndex][1].type === "lineEnding" || events[tailExitIndex][1].type === 'space')) {
- index = headEnterIndex;
- // And we have data.
- while (++index < tailExitIndex) {
- if (events[index][1].type === "codeTextData") {
- // Then we have padding.
- events[headEnterIndex][1].type = "codeTextPadding";
- events[tailExitIndex][1].type = "codeTextPadding";
- headEnterIndex += 2;
- tailExitIndex -= 2;
- break;
- }
- }
- }
- // Merge adjacent spaces and data.
- index = headEnterIndex - 1;
- tailExitIndex++;
- while (++index <= tailExitIndex) {
- if (enter === undefined) {
- if (index !== tailExitIndex && events[index][1].type !== "lineEnding") {
- enter = index;
- }
- } else if (index === tailExitIndex || events[index][1].type === "lineEnding") {
- events[enter][1].type = "codeTextData";
- if (index !== enter + 2) {
- events[enter][1].end = events[index - 1][1].end;
- events.splice(enter + 2, index - enter - 2);
- tailExitIndex -= index - enter - 2;
- index = enter + 2;
- }
- enter = undefined;
- }
- }
- return events;
- }
- /**
- * @this {TokenizeContext}
- * Context.
- * @type {Previous}
- */
- function previous(code) {
- // If there is a previous code, there will always be a tail.
- return code !== 96 || this.events[this.events.length - 1][1].type === "characterEscape";
- }
- /**
- * @this {TokenizeContext}
- * Context.
- * @type {Tokenizer}
- */
- function tokenizeCodeText(effects, ok, nok) {
- const self = this;
- let sizeOpen = 0;
- /** @type {number} */
- let size;
- /** @type {Token} */
- let token;
- return start;
- /**
- * Start of code (text).
- *
- * ```markdown
- * > | `a`
- * ^
- * > | \`a`
- * ^
- * ```
- *
- * @type {State}
- */
- function start(code) {
- effects.enter("codeText");
- effects.enter("codeTextSequence");
- return sequenceOpen(code);
- }
- /**
- * In opening sequence.
- *
- * ```markdown
- * > | `a`
- * ^
- * ```
- *
- * @type {State}
- */
- function sequenceOpen(code) {
- if (code === 96) {
- effects.consume(code);
- sizeOpen++;
- return sequenceOpen;
- }
- effects.exit("codeTextSequence");
- return between(code);
- }
- /**
- * Between something and something else.
- *
- * ```markdown
- * > | `a`
- * ^^
- * ```
- *
- * @type {State}
- */
- function between(code) {
- // EOF.
- if (code === null) {
- return nok(code);
- }
- // To do: next major: don’t do spaces in resolve, but when compiling,
- // like `markdown-rs`.
- // Tabs don’t work, and virtual spaces don’t make sense.
- if (code === 32) {
- effects.enter('space');
- effects.consume(code);
- effects.exit('space');
- return between;
- }
- // Closing fence? Could also be data.
- if (code === 96) {
- token = effects.enter("codeTextSequence");
- size = 0;
- return sequenceClose(code);
- }
- if (markdownLineEnding(code)) {
- effects.enter("lineEnding");
- effects.consume(code);
- effects.exit("lineEnding");
- return between;
- }
- // Data.
- effects.enter("codeTextData");
- return data(code);
- }
- /**
- * In data.
- *
- * ```markdown
- * > | `a`
- * ^
- * ```
- *
- * @type {State}
- */
- function data(code) {
- if (code === null || code === 32 || code === 96 || markdownLineEnding(code)) {
- effects.exit("codeTextData");
- return between(code);
- }
- effects.consume(code);
- return data;
- }
- /**
- * In closing sequence.
- *
- * ```markdown
- * > | `a`
- * ^
- * ```
- *
- * @type {State}
- */
- function sequenceClose(code) {
- // More.
- if (code === 96) {
- effects.consume(code);
- size++;
- return sequenceClose;
- }
- // Done!
- if (size === sizeOpen) {
- effects.exit("codeTextSequence");
- effects.exit("codeText");
- return ok(code);
- }
- // More or less accents: mark as data.
- token.type = "codeTextData";
- return data(code);
- }
- }
|