CoolFace
Apppublic

AK-21/Graphite-Industrial-Intelligence

sourceHugging Faceupdated 3mo agoView on Hugging Face
0likes
label-end.js560 linesDownload Raw Back to lib
1/**2 * @import {3 *   Construct,4 *   Event,5 *   Resolver,6 *   State,7 *   TokenizeContext,8 *   Tokenizer,9 *   Token10 * } from 'micromark-util-types'11 */12 13import { factoryDestination } from 'micromark-factory-destination';14import { factoryLabel } from 'micromark-factory-label';15import { factoryTitle } from 'micromark-factory-title';16import { factoryWhitespace } from 'micromark-factory-whitespace';17import { markdownLineEndingOrSpace } from 'micromark-util-character';18import { push, splice } from 'micromark-util-chunked';19import { normalizeIdentifier } from 'micromark-util-normalize-identifier';20import { resolveAll } from 'micromark-util-resolve-all';21/** @type {Construct} */22export const labelEnd = {23  name: 'labelEnd',24  resolveAll: resolveAllLabelEnd,25  resolveTo: resolveToLabelEnd,26  tokenize: tokenizeLabelEnd27};28 29/** @type {Construct} */30const resourceConstruct = {31  tokenize: tokenizeResource32};33/** @type {Construct} */34const referenceFullConstruct = {35  tokenize: tokenizeReferenceFull36};37/** @type {Construct} */38const referenceCollapsedConstruct = {39  tokenize: tokenizeReferenceCollapsed40};41 42/** @type {Resolver} */43function resolveAllLabelEnd(events) {44  let index = -1;45  /** @type {Array<Event>} */46  const newEvents = [];47  while (++index < events.length) {48    const token = events[index][1];49    newEvents.push(events[index]);50    if (token.type === "labelImage" || token.type === "labelLink" || token.type === "labelEnd") {51      // Remove the marker.52      const offset = token.type === "labelImage" ? 4 : 2;53      token.type = "data";54      index += offset;55    }56  }57 58  // If the events are equal, we don't have to copy newEvents to events59  if (events.length !== newEvents.length) {60    splice(events, 0, events.length, newEvents);61  }62  return events;63}64 65/** @type {Resolver} */66function resolveToLabelEnd(events, context) {67  let index = events.length;68  let offset = 0;69  /** @type {Token} */70  let token;71  /** @type {number | undefined} */72  let open;73  /** @type {number | undefined} */74  let close;75  /** @type {Array<Event>} */76  let media;77 78  // Find an opening.79  while (index--) {80    token = events[index][1];81    if (open) {82      // If we see another link, or inactive link label, we’ve been here before.83      if (token.type === "link" || token.type === "labelLink" && token._inactive) {84        break;85      }86 87      // Mark other link openings as inactive, as we can’t have links in88      // links.89      if (events[index][0] === 'enter' && token.type === "labelLink") {90        token._inactive = true;91      }92    } else if (close) {93      if (events[index][0] === 'enter' && (token.type === "labelImage" || token.type === "labelLink") && !token._balanced) {94        open = index;95        if (token.type !== "labelLink") {96          offset = 2;97          break;98        }99      }100    } else if (token.type === "labelEnd") {101      close = index;102    }103  }104  const group = {105    type: events[open][1].type === "labelLink" ? "link" : "image",106    start: {107      ...events[open][1].start108    },109    end: {110      ...events[events.length - 1][1].end111    }112  };113  const label = {114    type: "label",115    start: {116      ...events[open][1].start117    },118    end: {119      ...events[close][1].end120    }121  };122  const text = {123    type: "labelText",124    start: {125      ...events[open + offset + 2][1].end126    },127    end: {128      ...events[close - 2][1].start129    }130  };131  media = [['enter', group, context], ['enter', label, context]];132 133  // Opening marker.134  media = push(media, events.slice(open + 1, open + offset + 3));135 136  // Text open.137  media = push(media, [['enter', text, context]]);138 139  // Always populated by defaults.140 141  // Between.142  media = push(media, resolveAll(context.parser.constructs.insideSpan.null, events.slice(open + offset + 4, close - 3), context));143 144  // Text close, marker close, label close.145  media = push(media, [['exit', text, context], events[close - 2], events[close - 1], ['exit', label, context]]);146 147  // Reference, resource, or so.148  media = push(media, events.slice(close + 1));149 150  // Media close.151  media = push(media, [['exit', group, context]]);152  splice(events, open, events.length, media);153  return events;154}155 156/**157 * @this {TokenizeContext}158 *   Context.159 * @type {Tokenizer}160 */161function tokenizeLabelEnd(effects, ok, nok) {162  const self = this;163  let index = self.events.length;164  /** @type {Token} */165  let labelStart;166  /** @type {boolean} */167  let defined;168 169  // Find an opening.170  while (index--) {171    if ((self.events[index][1].type === "labelImage" || self.events[index][1].type === "labelLink") && !self.events[index][1]._balanced) {172      labelStart = self.events[index][1];173      break;174    }175  }176  return start;177 178  /**179   * Start of label end.180   *181   * ```markdown182   * > | [a](b) c183   *       ^184   * > | [a][b] c185   *       ^186   * > | [a][] b187   *       ^188   * > | [a] b189   * ```190   *191   * @type {State}192   */193  function start(code) {194    // If there is not an okay opening.195    if (!labelStart) {196      return nok(code);197    }198 199    // If the corresponding label (link) start is marked as inactive,200    // it means we’d be wrapping a link, like this:201    //202    // ```markdown203    // > | a [b [c](d) e](f) g.204    //                  ^205    // ```206    //207    // We can’t have that, so it’s just balanced brackets.208    if (labelStart._inactive) {209      return labelEndNok(code);210    }211    defined = self.parser.defined.includes(normalizeIdentifier(self.sliceSerialize({212      start: labelStart.end,213      end: self.now()214    })));215    effects.enter("labelEnd");216    effects.enter("labelMarker");217    effects.consume(code);218    effects.exit("labelMarker");219    effects.exit("labelEnd");220    return after;221  }222 223  /**224   * After `]`.225   *226   * ```markdown227   * > | [a](b) c228   *       ^229   * > | [a][b] c230   *       ^231   * > | [a][] b232   *       ^233   * > | [a] b234   *       ^235   * ```236   *237   * @type {State}238   */239  function after(code) {240    // Note: `markdown-rs` also parses GFM footnotes here, which for us is in241    // an extension.242 243    // Resource (`[asd](fgh)`)?244    if (code === 40) {245      return effects.attempt(resourceConstruct, labelEndOk, defined ? labelEndOk : labelEndNok)(code);246    }247 248    // Full (`[asd][fgh]`) or collapsed (`[asd][]`) reference?249    if (code === 91) {250      return effects.attempt(referenceFullConstruct, labelEndOk, defined ? referenceNotFull : labelEndNok)(code);251    }252 253    // Shortcut (`[asd]`) reference?254    return defined ? labelEndOk(code) : labelEndNok(code);255  }256 257  /**258   * After `]`, at `[`, but not at a full reference.259   *260   * > 👉 **Note**: we only get here if the label is defined.261   *262   * ```markdown263   * > | [a][] b264   *        ^265   * > | [a] b266   *        ^267   * ```268   *269   * @type {State}270   */271  function referenceNotFull(code) {272    return effects.attempt(referenceCollapsedConstruct, labelEndOk, labelEndNok)(code);273  }274 275  /**276   * Done, we found something.277   *278   * ```markdown279   * > | [a](b) c280   *           ^281   * > | [a][b] c282   *           ^283   * > | [a][] b284   *          ^285   * > | [a] b286   *        ^287   * ```288   *289   * @type {State}290   */291  function labelEndOk(code) {292    // Note: `markdown-rs` does a bunch of stuff here.293    return ok(code);294  }295 296  /**297   * Done, it’s nothing.298   *299   * There was an okay opening, but we didn’t match anything.300   *301   * ```markdown302   * > | [a](b c303   *        ^304   * > | [a][b c305   *        ^306   * > | [a] b307   *        ^308   * ```309   *310   * @type {State}311   */312  function labelEndNok(code) {313    labelStart._balanced = true;314    return nok(code);315  }316}317 318/**319 * @this {TokenizeContext}320 *   Context.321 * @type {Tokenizer}322 */323function tokenizeResource(effects, ok, nok) {324  return resourceStart;325 326  /**327   * At a resource.328   *329   * ```markdown330   * > | [a](b) c331   *        ^332   * ```333   *334   * @type {State}335   */336  function resourceStart(code) {337    effects.enter("resource");338    effects.enter("resourceMarker");339    effects.consume(code);340    effects.exit("resourceMarker");341    return resourceBefore;342  }343 344  /**345   * In resource, after `(`, at optional whitespace.346   *347   * ```markdown348   * > | [a](b) c349   *         ^350   * ```351   *352   * @type {State}353   */354  function resourceBefore(code) {355    return markdownLineEndingOrSpace(code) ? factoryWhitespace(effects, resourceOpen)(code) : resourceOpen(code);356  }357 358  /**359   * In resource, after optional whitespace, at `)` or a destination.360   *361   * ```markdown362   * > | [a](b) c363   *         ^364   * ```365   *366   * @type {State}367   */368  function resourceOpen(code) {369    if (code === 41) {370      return resourceEnd(code);371    }372    return factoryDestination(effects, resourceDestinationAfter, resourceDestinationMissing, "resourceDestination", "resourceDestinationLiteral", "resourceDestinationLiteralMarker", "resourceDestinationRaw", "resourceDestinationString", 32)(code);373  }374 375  /**376   * In resource, after destination, at optional whitespace.377   *378   * ```markdown379   * > | [a](b) c380   *          ^381   * ```382   *383   * @type {State}384   */385  function resourceDestinationAfter(code) {386    return markdownLineEndingOrSpace(code) ? factoryWhitespace(effects, resourceBetween)(code) : resourceEnd(code);387  }388 389  /**390   * At invalid destination.391   *392   * ```markdown393   * > | [a](<<) b394   *         ^395   * ```396   *397   * @type {State}398   */399  function resourceDestinationMissing(code) {400    return nok(code);401  }402 403  /**404   * In resource, after destination and whitespace, at `(` or title.405   *406   * ```markdown407   * > | [a](b ) c408   *           ^409   * ```410   *411   * @type {State}412   */413  function resourceBetween(code) {414    if (code === 34 || code === 39 || code === 40) {415      return factoryTitle(effects, resourceTitleAfter, nok, "resourceTitle", "resourceTitleMarker", "resourceTitleString")(code);416    }417    return resourceEnd(code);418  }419 420  /**421   * In resource, after title, at optional whitespace.422   *423   * ```markdown424   * > | [a](b "c") d425   *              ^426   * ```427   *428   * @type {State}429   */430  function resourceTitleAfter(code) {431    return markdownLineEndingOrSpace(code) ? factoryWhitespace(effects, resourceEnd)(code) : resourceEnd(code);432  }433 434  /**435   * In resource, at `)`.436   *437   * ```markdown438   * > | [a](b) d439   *          ^440   * ```441   *442   * @type {State}443   */444  function resourceEnd(code) {445    if (code === 41) {446      effects.enter("resourceMarker");447      effects.consume(code);448      effects.exit("resourceMarker");449      effects.exit("resource");450      return ok;451    }452    return nok(code);453  }454}455 456/**457 * @this {TokenizeContext}458 *   Context.459 * @type {Tokenizer}460 */461function tokenizeReferenceFull(effects, ok, nok) {462  const self = this;463  return referenceFull;464 465  /**466   * In a reference (full), at the `[`.467   *468   * ```markdown469   * > | [a][b] d470   *        ^471   * ```472   *473   * @type {State}474   */475  function referenceFull(code) {476    return factoryLabel.call(self, effects, referenceFullAfter, referenceFullMissing, "reference", "referenceMarker", "referenceString")(code);477  }478 479  /**480   * In a reference (full), after `]`.481   *482   * ```markdown483   * > | [a][b] d484   *          ^485   * ```486   *487   * @type {State}488   */489  function referenceFullAfter(code) {490    return self.parser.defined.includes(normalizeIdentifier(self.sliceSerialize(self.events[self.events.length - 1][1]).slice(1, -1))) ? ok(code) : nok(code);491  }492 493  /**494   * In reference (full) that was missing.495   *496   * ```markdown497   * > | [a][b d498   *        ^499   * ```500   *501   * @type {State}502   */503  function referenceFullMissing(code) {504    return nok(code);505  }506}507 508/**509 * @this {TokenizeContext}510 *   Context.511 * @type {Tokenizer}512 */513function tokenizeReferenceCollapsed(effects, ok, nok) {514  return referenceCollapsedStart;515 516  /**517   * In reference (collapsed), at `[`.518   *519   * > 👉 **Note**: we only get here if the label is defined.520   *521   * ```markdown522   * > | [a][] d523   *        ^524   * ```525   *526   * @type {State}527   */528  function referenceCollapsedStart(code) {529    // We only attempt a collapsed label if there’s a `[`.530 531    effects.enter("reference");532    effects.enter("referenceMarker");533    effects.consume(code);534    effects.exit("referenceMarker");535    return referenceCollapsedOpen;536  }537 538  /**539   * In reference (collapsed), at `]`.540   *541   * > 👉 **Note**: we only get here if the label is defined.542   *543   * ```markdown544   * > | [a][] d545   *         ^546   * ```547   *548   *  @type {State}549   */550  function referenceCollapsedOpen(code) {551    if (code === 93) {552      effects.enter("referenceMarker");553      effects.consume(code);554      effects.exit("referenceMarker");555      effects.exit("reference");556      return ok;557    }558    return nok(code);559  }560}