eslint-plugin-markdown-preferences 0.26.1 → 0.28.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/index.js CHANGED
@@ -3,6 +3,16 @@ import stringWidth from "string-width";
3
3
  import emojiRegex from "emoji-regex-xs";
4
4
  import path from "node:path";
5
5
  import markdown from "@eslint/markdown";
6
+ import { fromMarkdown } from "mdast-util-from-markdown";
7
+ import { frontmatterFromMarkdown } from "mdast-util-frontmatter";
8
+ import { gfmFromMarkdown } from "mdast-util-gfm";
9
+ import { frontmatter } from "micromark-extension-frontmatter";
10
+ import { gfm } from "micromark-extension-gfm";
11
+ import { math } from "micromark-extension-math";
12
+ import { mathFromMarkdown } from "mdast-util-math";
13
+ import { markdownLineEnding, markdownSpace } from "micromark-util-character";
14
+ import { codes, constants, types } from "micromark-util-symbol";
15
+ import { factorySpace } from "micromark-factory-space";
6
16
 
7
17
  //#region src/utils/index.ts
8
18
  /**
@@ -957,14 +967,14 @@ var bullet_list_marker_style_default = createRule("bullet-list-marker-style", {
957
967
  if (node.ordered) return;
958
968
  checkBulletList(node);
959
969
  },
960
- "root, blockquote, listItem, footnoteDefinition"(node) {
970
+ "root, blockquote, listItem, footnoteDefinition, customContainer"(node) {
961
971
  containerStack = {
962
972
  node,
963
973
  level: node.type === "listItem" ? containerStack.level + 1 : 1,
964
974
  upper: containerStack
965
975
  };
966
976
  },
967
- "root, blockquote, listItem, footnoteDefinition:exit"() {
977
+ "root, blockquote, listItem, footnoteDefinition, customContainer:exit"() {
968
978
  containerStack = containerStack.upper;
969
979
  }
970
980
  };
@@ -979,28 +989,14 @@ const RE_LANGUAGE = /^(\w*)/u;
979
989
  * Parse the fenced code block.
980
990
  */
981
991
  function parseFencedCodeBlock(sourceCode, node) {
992
+ if (getCodeBlockKind(sourceCode, node) === "indented") return null;
982
993
  const loc = sourceCode.getLoc(node);
983
994
  const range = sourceCode.getRange(node);
984
995
  const text = sourceCode.text.slice(...range);
985
996
  const match = RE_OPENING_FENCE.exec(text);
986
997
  if (!match) return null;
987
998
  const [, fenceText] = match;
988
- const fenceChar = fenceText[0];
989
- let closingFenceText = "";
990
- const trimmed = text.trimEnd();
991
- const trailingSpacesLength = text.length - trimmed.length;
992
- for (let index = trimmed.length - 1; index >= 0; index--) {
993
- const c = trimmed[index];
994
- if (c === fenceChar || isSpaceOrTab(c)) {
995
- closingFenceText = c + closingFenceText;
996
- continue;
997
- }
998
- if (c === "\n") break;
999
- return null;
1000
- }
1001
- closingFenceText = closingFenceText.trimStart();
1002
- if (!closingFenceText || !closingFenceText.startsWith(fenceText)) return null;
1003
- const afterOpeningFence = getParsedLines(sourceCode).get(loc.start.line).text.slice(fenceText.length);
999
+ const afterOpeningFence = sourceCode.lines[loc.start.line - 1].slice(loc.start.column - 1 + fenceText.length);
1004
1000
  const trimmedAfterOpeningFence = afterOpeningFence.trimStart();
1005
1001
  const spaceAfterOpeningFenceLength = afterOpeningFence.length - trimmedAfterOpeningFence.length;
1006
1002
  let languageText = "";
@@ -1009,45 +1005,49 @@ function parseFencedCodeBlock(sourceCode, node) {
1009
1005
  const trimmedAfterLanguage = afterLanguage.trimStart();
1010
1006
  const spaceAfterLanguageLength = afterLanguage.length - trimmedAfterLanguage.length;
1011
1007
  const metaText = trimmedAfterLanguage.trimEnd();
1008
+ const openingFenceRange = [range[0], range[0] + fenceText.length];
1012
1009
  const openingFence = {
1013
1010
  text: fenceText,
1014
- range: [range[0], range[0] + fenceText.length],
1015
- loc: {
1016
- start: loc.start,
1017
- end: {
1018
- line: loc.start.line,
1019
- column: loc.start.column + fenceText.length
1020
- }
1021
- }
1011
+ range: openingFenceRange,
1012
+ loc: getSourceLocationFromRange(sourceCode, node, openingFenceRange)
1022
1013
  };
1023
- const language$2 = languageText ? {
1014
+ const languageRange = languageText ? [openingFence.range[1] + spaceAfterOpeningFenceLength, openingFence.range[1] + spaceAfterOpeningFenceLength + languageText.length] : null;
1015
+ const language$2 = languageText && languageRange ? {
1024
1016
  text: languageText,
1025
- range: [openingFence.range[1] + spaceAfterOpeningFenceLength, openingFence.range[1] + spaceAfterOpeningFenceLength + languageText.length],
1026
- loc: {
1027
- start: {
1028
- line: openingFence.loc.end.line,
1029
- column: openingFence.loc.end.column + spaceAfterOpeningFenceLength
1030
- },
1031
- end: {
1032
- line: openingFence.loc.end.line,
1033
- column: openingFence.loc.end.column + spaceAfterOpeningFenceLength + languageText.length
1034
- }
1035
- }
1017
+ range: languageRange,
1018
+ loc: getSourceLocationFromRange(sourceCode, node, languageRange)
1036
1019
  } : null;
1037
- const meta = language$2 && metaText ? {
1020
+ const metaRange = language$2 && metaText ? [language$2.range[1] + spaceAfterLanguageLength, language$2.range[1] + spaceAfterLanguageLength + metaText.length] : null;
1021
+ const meta = language$2 && metaText && metaRange ? {
1038
1022
  text: metaText,
1039
- range: [language$2.range[1] + spaceAfterLanguageLength, language$2.range[1] + spaceAfterLanguageLength + metaText.length],
1040
- loc: {
1041
- start: {
1042
- line: language$2.loc.end.line,
1043
- column: language$2.loc.end.column + spaceAfterLanguageLength
1044
- },
1045
- end: {
1046
- line: language$2.loc.end.line,
1047
- column: language$2.loc.end.column + spaceAfterLanguageLength + metaText.length
1048
- }
1049
- }
1023
+ range: metaRange,
1024
+ loc: getSourceLocationFromRange(sourceCode, node, metaRange)
1050
1025
  } : null;
1026
+ const fenceChar = fenceText[0];
1027
+ let closingFenceText = "";
1028
+ const trimmed = text.trimEnd();
1029
+ const trailingSpacesLength = text.length - trimmed.length;
1030
+ for (let index = trimmed.length - 1; index >= 0; index--) {
1031
+ const c = trimmed[index];
1032
+ if (c === fenceChar || isSpaceOrTab(c)) {
1033
+ closingFenceText = c + closingFenceText;
1034
+ continue;
1035
+ }
1036
+ if (c === ">") {
1037
+ closingFenceText = ` ${closingFenceText}`;
1038
+ continue;
1039
+ }
1040
+ if (c === "\n") break;
1041
+ closingFenceText = "";
1042
+ break;
1043
+ }
1044
+ closingFenceText = closingFenceText.trimStart();
1045
+ if (!closingFenceText || !closingFenceText.startsWith(fenceText)) return {
1046
+ openingFence,
1047
+ language: language$2,
1048
+ meta,
1049
+ closingFence: null
1050
+ };
1051
1051
  return {
1052
1052
  openingFence,
1053
1053
  language: language$2,
@@ -1117,10 +1117,10 @@ var canonical_code_block_language_default = createRule("canonical-code-block-lan
1117
1117
  },
1118
1118
  create(context) {
1119
1119
  const sourceCode = context.sourceCode;
1120
- const languages = context.options[0]?.languages || DEFAULT_LANGUAGES;
1120
+ const languages$1 = context.options[0]?.languages || DEFAULT_LANGUAGES;
1121
1121
  return { code(node) {
1122
- if (!node.lang || !languages[node.lang]) return;
1123
- const canonical = languages[node.lang];
1122
+ if (!node.lang || !languages$1[node.lang]) return;
1123
+ const canonical = languages$1[node.lang];
1124
1124
  const current = node.lang;
1125
1125
  if (current === canonical) return;
1126
1126
  const parsed = parseFencedCodeBlock(sourceCode, node);
@@ -1217,8 +1217,9 @@ var code_fence_length_default = createRule("code-fence-length", {
1217
1217
  actual: parsed.openingFence.text
1218
1218
  },
1219
1219
  messageId: "notPreferred",
1220
- fix(fixer) {
1221
- return [fixer.replaceTextRange(parsed.openingFence.range, expectedFence), fixer.replaceTextRange(parsed.closingFence.range, expectedFence)];
1220
+ *fix(fixer) {
1221
+ yield fixer.replaceTextRange(parsed.openingFence.range, expectedFence);
1222
+ if (parsed.closingFence) yield fixer.replaceTextRange(parsed.closingFence.range, expectedFence);
1222
1223
  }
1223
1224
  });
1224
1225
  }
@@ -1257,14 +1258,14 @@ var code_fence_length_default = createRule("code-fence-length", {
1257
1258
  /**
1258
1259
  * Verify that the opening and closing fence lengths match.
1259
1260
  */
1260
- function verifyClosingFenceLength(node, parsed) {
1261
- if (parsed.openingFence.text.length === parsed.closingFence.text.length) return true;
1261
+ function verifyClosingFenceLength(node, { openingFence, closingFence }) {
1262
+ if (!closingFence || openingFence.text.length === closingFence.text.length) return true;
1262
1263
  context.report({
1263
1264
  node,
1264
- loc: parsed.closingFence.loc,
1265
+ loc: closingFence.loc,
1265
1266
  messageId: "notMatch",
1266
1267
  fix(fixer) {
1267
- return [fixer.replaceTextRange(parsed.closingFence.range, parsed.openingFence.text)];
1268
+ return [fixer.replaceTextRange(closingFence.range, openingFence.text)];
1268
1269
  }
1269
1270
  });
1270
1271
  return false;
@@ -1317,8 +1318,9 @@ var code_fence_style_default = createRule("code-fence-style", {
1317
1318
  actual: parsed.openingFence.text
1318
1319
  },
1319
1320
  messageId: "useCodeFenceStyle",
1320
- fix(fixer) {
1321
- return [fixer.replaceTextRange(parsed.openingFence.range, expectedOpeningFence), fixer.replaceTextRange(parsed.closingFence.range, expectedChar.repeat(Math.max(3, parsed.closingFence.text.length)))];
1321
+ *fix(fixer) {
1322
+ yield fixer.replaceTextRange(parsed.openingFence.range, expectedOpeningFence);
1323
+ if (parsed.closingFence) yield fixer.replaceTextRange(parsed.closingFence.range, expectedChar.repeat(Math.max(3, parsed.closingFence.text.length)));
1322
1324
  }
1323
1325
  });
1324
1326
  } };
@@ -5296,6 +5298,120 @@ function parseListItem(sourceCode, node) {
5296
5298
  };
5297
5299
  }
5298
5300
 
5301
+ //#endregion
5302
+ //#region src/utils/math-block.ts
5303
+ /**
5304
+ * Parse the math block.
5305
+ */
5306
+ function parseMathBlock(sourceCode, node) {
5307
+ const range = sourceCode.getRange(node);
5308
+ const text = sourceCode.text.slice(...range);
5309
+ const parsedOpening = parseMathOpeningSequenceFromText(text);
5310
+ if (parsedOpening === null) return null;
5311
+ const openingSequenceRange = [range[0], range[0] + parsedOpening.openingSequence.length];
5312
+ const openingSequence = {
5313
+ text: parsedOpening.openingSequence,
5314
+ range: openingSequenceRange,
5315
+ loc: getSourceLocationFromRange(sourceCode, node, openingSequenceRange)
5316
+ };
5317
+ const parsedClosing = parseMathClosingSequenceFromText(text);
5318
+ if (parsedClosing == null || parsedClosing.closingSequence !== parsedOpening.openingSequence) {
5319
+ const contentRange$1 = [openingSequence.range[1] + parsedOpening.after.length, range[1]];
5320
+ return {
5321
+ openingSequence,
5322
+ content: {
5323
+ text: text.slice(parsedOpening.after.length),
5324
+ range: contentRange$1,
5325
+ loc: getSourceLocationFromRange(sourceCode, node, contentRange$1)
5326
+ },
5327
+ closingSequence: null,
5328
+ after: null
5329
+ };
5330
+ }
5331
+ const spaceAfterClosingRange = [range[1] - parsedClosing.after.length, range[1]];
5332
+ const spaceAfterClosing = {
5333
+ text: parsedClosing.after,
5334
+ range: spaceAfterClosingRange,
5335
+ loc: getSourceLocationFromRange(sourceCode, node, spaceAfterClosingRange)
5336
+ };
5337
+ const closingSequenceRange = [spaceAfterClosing.range[0] - parsedClosing.closingSequence.length, spaceAfterClosing.range[0]];
5338
+ const closingSequence = {
5339
+ text: parsedClosing.closingSequence,
5340
+ range: closingSequenceRange,
5341
+ loc: getSourceLocationFromRange(sourceCode, node, closingSequenceRange)
5342
+ };
5343
+ const contentRange = [openingSequence.range[1] + parsedOpening.after.length, closingSequence.range[0] - parsedClosing.before.length];
5344
+ const contentText = sourceCode.text.slice(...contentRange);
5345
+ return {
5346
+ openingSequence,
5347
+ content: {
5348
+ text: contentText,
5349
+ range: contentRange,
5350
+ loc: getSourceLocationFromRange(sourceCode, node, contentRange)
5351
+ },
5352
+ closingSequence,
5353
+ after: spaceAfterClosing.range[0] < spaceAfterClosing.range[1] ? spaceAfterClosing : null
5354
+ };
5355
+ }
5356
+ /**
5357
+ * Parse the opening sequence from a text string.
5358
+ */
5359
+ function parseMathOpeningSequenceFromText(text) {
5360
+ if (!text.startsWith("$")) return null;
5361
+ let openingSequenceAfterOffset = 1;
5362
+ while (openingSequenceAfterOffset < text.length && text[openingSequenceAfterOffset] === "$") openingSequenceAfterOffset++;
5363
+ const afterOffset = skipWhitespace(openingSequenceAfterOffset);
5364
+ if (afterOffset === openingSequenceAfterOffset || afterOffset >= text.length) return null;
5365
+ return {
5366
+ openingSequence: text.slice(0, openingSequenceAfterOffset),
5367
+ after: text.slice(openingSequenceAfterOffset, afterOffset)
5368
+ };
5369
+ /**
5370
+ * Skip whitespace characters at the start of the text.
5371
+ */
5372
+ function skipWhitespace(index) {
5373
+ let inIndent = false;
5374
+ let result = index;
5375
+ let c;
5376
+ while (result < text.length && (c = text[result]) && (isWhitespace(c) || inIndent && c === ">")) {
5377
+ result++;
5378
+ if (c === "\n") inIndent = true;
5379
+ else if (inIndent) inIndent = isWhitespace(c) || c === ">";
5380
+ }
5381
+ return result;
5382
+ }
5383
+ }
5384
+ /**
5385
+ * Parse the closing sequence from a text string.
5386
+ */
5387
+ function parseMathClosingSequenceFromText(text) {
5388
+ const trimmedEndOffset = skipEndWhitespace(text.length - 1) + 1;
5389
+ if (trimmedEndOffset <= 0 || text[trimmedEndOffset - 1] !== "$") return null;
5390
+ let closingSequenceBeforeOffset = trimmedEndOffset - 2;
5391
+ while (closingSequenceBeforeOffset >= 0 && text[closingSequenceBeforeOffset] === "$") closingSequenceBeforeOffset--;
5392
+ const beforeOffset = skipEndWhitespace(closingSequenceBeforeOffset);
5393
+ if (beforeOffset === closingSequenceBeforeOffset || beforeOffset < 0) return null;
5394
+ return {
5395
+ before: text.slice(beforeOffset + 1, closingSequenceBeforeOffset + 1),
5396
+ closingSequence: text.slice(closingSequenceBeforeOffset + 1, trimmedEndOffset),
5397
+ after: text.slice(trimmedEndOffset)
5398
+ };
5399
+ /**
5400
+ * Skip whitespace characters at the end of the text.
5401
+ */
5402
+ function skipEndWhitespace(index) {
5403
+ let result = index;
5404
+ let c;
5405
+ while (result >= 0 && (c = text[result]) && isWhitespace(c)) result--;
5406
+ if (c === ">") {
5407
+ let index2 = result - 1;
5408
+ while (index2 >= 0 && (c = text[index2]) && (isSpaceOrTab(c) || c === ">")) index2--;
5409
+ if (c === "\n") return skipEndWhitespace(index2);
5410
+ }
5411
+ return result;
5412
+ }
5413
+ }
5414
+
5299
5415
  //#endregion
5300
5416
  //#region src/rules/indent.ts
5301
5417
  /**
@@ -5575,7 +5691,10 @@ var indent_default = createRule("indent", {
5575
5691
  definition: verifyLinkDefinition,
5576
5692
  table: verifyTable,
5577
5693
  list: verifyList,
5578
- inlineCode: verifyInlineCode,
5694
+ customContainer: verifyCustomContainer,
5695
+ math: verifyMathBlock,
5696
+ importCodeSnippet: verifyImportCodeSnippet,
5697
+ inlineCode: verifyInlineCodeOrInlineMath,
5579
5698
  emphasis: verifyEmphasisOrStrongOrDelete,
5580
5699
  strong: verifyEmphasisOrStrongOrDelete,
5581
5700
  delete: verifyEmphasisOrStrongOrDelete,
@@ -5584,6 +5703,7 @@ var indent_default = createRule("indent", {
5584
5703
  footnoteReference: verifyInline,
5585
5704
  break: verifyInline,
5586
5705
  text: verifyText,
5706
+ inlineMath: verifyInlineCodeOrInlineMath,
5587
5707
  blockquote(node) {
5588
5708
  verifyBlockquote(node);
5589
5709
  blockStack = new BlockquoteStack(node);
@@ -5640,32 +5760,9 @@ var indent_default = createRule("indent", {
5640
5760
  verifyLinesIndent([loc.start.line, loc.end.line], (lineNumber) => blockStack.getExpectedIndent({
5641
5761
  lineNumber,
5642
5762
  block: true
5643
- }), additionalFixes);
5644
- /**
5645
- * Additional fixes for code block content lines.
5646
- */
5647
- function* additionalFixes(fixer, info) {
5648
- if (info.loc.start.line !== loc.start.line) return;
5649
- for (let lineNumber = loc.start.line + 1; lineNumber < loc.end.line; lineNumber++) {
5650
- const line = getParsedLines(sourceCode).get(lineNumber);
5651
- if (!line) continue;
5652
- if (info.expectedIndentWidth > info.actualIndentWidth) {
5653
- const before = sliceWidth(line.text, 0, info.actualIndentWidth);
5654
- const after = sliceWidth(line.text, info.actualIndentWidth);
5655
- const diffWidth = info.expectedIndentWidth - info.actualIndentWidth;
5656
- yield fixer.replaceTextRange([line.range[0], line.range[0] + line.text.length], before + " ".repeat(diffWidth) + after);
5657
- } else {
5658
- let before = sliceWidth(line.text, 0, info.expectedIndentWidth);
5659
- let between = sliceWidth(line.text, info.expectedIndentWidth, info.actualIndentWidth);
5660
- const after = sliceWidth(line.text, info.actualIndentWidth);
5661
- while (between && !isSpaceOrTab(between)) {
5662
- before += between[0];
5663
- between = between.slice(1);
5664
- }
5665
- yield fixer.replaceTextRange([line.range[0], line.range[0] + line.text.length], before + after);
5666
- }
5667
- }
5668
- }
5763
+ }), (fixer, info) => {
5764
+ return additionalFixesForCodeBlock(node, fixer, info, loc.start.line + 1, loc.end.line - 1);
5765
+ });
5669
5766
  }
5670
5767
  /**
5671
5768
  * Verify an HTML node.
@@ -5782,6 +5879,41 @@ var indent_default = createRule("indent", {
5782
5879
  }
5783
5880
  }
5784
5881
  /**
5882
+ * Verify a custom container node.
5883
+ */
5884
+ function verifyCustomContainer(node) {
5885
+ const loc = sourceCode.getLoc(node);
5886
+ verifyLinesIndent([loc.start.line, loc.end.line], (lineNumber) => blockStack.getExpectedIndent({
5887
+ lineNumber,
5888
+ block: true
5889
+ }));
5890
+ }
5891
+ /**
5892
+ * Verify a math node.
5893
+ */
5894
+ function verifyMathBlock(node) {
5895
+ const parsed = parseMathBlock(sourceCode, node);
5896
+ if (!parsed) return;
5897
+ const loc = sourceCode.getLoc(node);
5898
+ const endLineToBeChecked = parsed.closingSequence && inlineToBeChecked(parsed.closingSequence.loc.start);
5899
+ verifyLinesIndent(endLineToBeChecked ? [loc.start.line, loc.end.line] : [loc.start.line], (lineNumber) => blockStack.getExpectedIndent({
5900
+ lineNumber,
5901
+ block: true
5902
+ }), (fixer, info) => {
5903
+ return additionalFixesForCodeBlock(node, fixer, info, loc.start.line + 1, endLineToBeChecked ? loc.end.line - 1 : loc.end.line);
5904
+ });
5905
+ }
5906
+ /**
5907
+ * Verify an import code snippet node.
5908
+ */
5909
+ function verifyImportCodeSnippet(node) {
5910
+ const loc = sourceCode.getLoc(node);
5911
+ verifyLinesIndent(lineNumbersFromRange(loc.start.line, loc.end.line), (lineNumber) => blockStack.getExpectedIndent({
5912
+ lineNumber,
5913
+ block: true
5914
+ }));
5915
+ }
5916
+ /**
5785
5917
  * Verify a footnote definition node.
5786
5918
  */
5787
5919
  function verifyFootnoteDefinition(node) {
@@ -5792,9 +5924,9 @@ var indent_default = createRule("indent", {
5792
5924
  }));
5793
5925
  }
5794
5926
  /**
5795
- * Verify an inline code node.
5927
+ * Verify an inline code/math node.
5796
5928
  */
5797
- function verifyInlineCode(node) {
5929
+ function verifyInlineCodeOrInlineMath(node) {
5798
5930
  const loc = sourceCode.getLoc(node);
5799
5931
  if (!inlineToBeChecked(loc.start)) return;
5800
5932
  verifyLinesIndent([loc.start.line], (lineNumber) => blockStack.getExpectedIndent({
@@ -6176,6 +6308,32 @@ var indent_default = createRule("indent", {
6176
6308
  actualIndentWidth
6177
6309
  };
6178
6310
  }
6311
+ /**
6312
+ * Additional fixes for code/math block content lines.
6313
+ */
6314
+ function* additionalFixesForCodeBlock(node, fixer, info, fixStartLine, fixEndLine) {
6315
+ const loc = sourceCode.getLoc(node);
6316
+ if (info.loc.start.line !== loc.start.line) return;
6317
+ for (let lineNumber = fixStartLine; lineNumber <= fixEndLine; lineNumber++) {
6318
+ const line = getParsedLines(sourceCode).get(lineNumber);
6319
+ if (!line) continue;
6320
+ if (info.expectedIndentWidth > info.actualIndentWidth) {
6321
+ const before = sliceWidth(line.text, 0, info.actualIndentWidth);
6322
+ const after = sliceWidth(line.text, info.actualIndentWidth);
6323
+ const diffWidth = info.expectedIndentWidth - info.actualIndentWidth;
6324
+ yield fixer.replaceTextRange([line.range[0], line.range[0] + line.text.length], before + " ".repeat(diffWidth) + after);
6325
+ } else {
6326
+ let before = sliceWidth(line.text, 0, info.expectedIndentWidth);
6327
+ let between = sliceWidth(line.text, info.expectedIndentWidth, info.actualIndentWidth);
6328
+ const after = sliceWidth(line.text, info.actualIndentWidth);
6329
+ while (between && !isSpaceOrTab(between)) {
6330
+ before += between[0];
6331
+ between = between.slice(1);
6332
+ }
6333
+ yield fixer.replaceTextRange([line.range[0], line.range[0] + line.text.length], before + after);
6334
+ }
6335
+ }
6336
+ }
6179
6337
  }
6180
6338
  });
6181
6339
 
@@ -7387,6 +7545,143 @@ var list_marker_alignment_default = createRule("list-marker-alignment", {
7387
7545
  }
7388
7546
  });
7389
7547
 
7548
+ //#endregion
7549
+ //#region src/utils/custom-container.ts
7550
+ const RE_OPENING_SEQUENCE = /^(:{3,})/u;
7551
+ /**
7552
+ * Parse the custom container.
7553
+ */
7554
+ function parseCustomContainer(sourceCode, node) {
7555
+ const loc = sourceCode.getLoc(node);
7556
+ const range = sourceCode.getRange(node);
7557
+ const text = sourceCode.text.slice(...range);
7558
+ const match = RE_OPENING_SEQUENCE.exec(text);
7559
+ if (!match) return null;
7560
+ const [, sequenceText] = match;
7561
+ const afterOpeningSequence = sourceCode.lines[loc.start.line - 1].slice(loc.start.column - 1 + sequenceText.length);
7562
+ const trimmedAfterOpeningSequence = afterOpeningSequence.trimStart();
7563
+ const spaceAfterOpeningSequenceLength = afterOpeningSequence.length - trimmedAfterOpeningSequence.length;
7564
+ const infoText = trimmedAfterOpeningSequence.trimEnd();
7565
+ if (!infoText) return null;
7566
+ const openingSequenceRange = [range[0], range[0] + sequenceText.length];
7567
+ const openingSequence = {
7568
+ text: sequenceText,
7569
+ range: openingSequenceRange,
7570
+ loc: getSourceLocationFromRange(sourceCode, node, openingSequenceRange)
7571
+ };
7572
+ const infoRange = [openingSequence.range[1] + spaceAfterOpeningSequenceLength, openingSequence.range[1] + spaceAfterOpeningSequenceLength + infoText.length];
7573
+ const info = {
7574
+ text: infoText,
7575
+ range: infoRange,
7576
+ loc: getSourceLocationFromRange(sourceCode, node, infoRange)
7577
+ };
7578
+ const sequenceChar = sequenceText[0];
7579
+ let closingSequenceText = "";
7580
+ const trimmed = text.trimEnd();
7581
+ const trailingSpacesLength = text.length - trimmed.length;
7582
+ for (let index = trimmed.length - 1; index >= 0; index--) {
7583
+ const c = trimmed[index];
7584
+ if (c === sequenceChar || isSpaceOrTab(c)) {
7585
+ closingSequenceText = c + closingSequenceText;
7586
+ continue;
7587
+ }
7588
+ if (c === ">") {
7589
+ closingSequenceText = ` ${closingSequenceText}`;
7590
+ continue;
7591
+ }
7592
+ if (c === "\n") break;
7593
+ closingSequenceText = "";
7594
+ break;
7595
+ }
7596
+ closingSequenceText = closingSequenceText.trimStart();
7597
+ if (!closingSequenceText || !closingSequenceText.startsWith(sequenceText)) return {
7598
+ openingSequence,
7599
+ info,
7600
+ closingSequence: null
7601
+ };
7602
+ const closingSequenceRange = [range[1] - trailingSpacesLength - closingSequenceText.length, range[1] - trailingSpacesLength];
7603
+ return {
7604
+ openingSequence,
7605
+ info,
7606
+ closingSequence: {
7607
+ text: closingSequenceText,
7608
+ range: closingSequenceRange,
7609
+ loc: getSourceLocationFromRange(sourceCode, node, closingSequenceRange)
7610
+ }
7611
+ };
7612
+ }
7613
+
7614
+ //#endregion
7615
+ //#region src/rules/no-implicit-block-closing.ts
7616
+ var no_implicit_block_closing_default = createRule("no-implicit-block-closing", {
7617
+ meta: {
7618
+ type: "suggestion",
7619
+ docs: {
7620
+ description: "disallow implicit block closing for fenced code blocks, math blocks, and custom blocks",
7621
+ categories: ["recommended", "standard"],
7622
+ listCategory: "Notation"
7623
+ },
7624
+ fixable: "code",
7625
+ hasSuggestions: false,
7626
+ schema: [],
7627
+ messages: {
7628
+ missingClosingFence: "Missing closing fence for fenced code block.",
7629
+ missingClosingMath: "Missing closing sequence for math block.",
7630
+ missingClosingContainer: "Missing closing sequence for custom container."
7631
+ }
7632
+ },
7633
+ create(context) {
7634
+ const sourceCode = context.sourceCode;
7635
+ return {
7636
+ code(node) {
7637
+ const parsed = parseFencedCodeBlock(sourceCode, node);
7638
+ if (!parsed) return;
7639
+ if (!parsed.closingFence) context.report({
7640
+ node,
7641
+ loc: parsed.openingFence.loc,
7642
+ messageId: "missingClosingFence",
7643
+ fix(fixer) {
7644
+ const openingLoc = parsed.openingFence.loc;
7645
+ const prefix = sourceCode.lines[openingLoc.start.line - 1].slice(0, openingLoc.start.column - 1).replace(/[^\s>]/gu, " ");
7646
+ const closingFence = parsed.openingFence.text;
7647
+ return fixer.insertTextAfter(node, `\n${prefix}${closingFence}`);
7648
+ }
7649
+ });
7650
+ },
7651
+ math(node) {
7652
+ const parsed = parseMathBlock(sourceCode, node);
7653
+ if (!parsed) return;
7654
+ if (!parsed.closingSequence) context.report({
7655
+ node,
7656
+ loc: parsed.openingSequence.loc,
7657
+ messageId: "missingClosingMath",
7658
+ fix(fixer) {
7659
+ const openingLoc = parsed.openingSequence.loc;
7660
+ const prefix = sourceCode.lines[openingLoc.start.line - 1].slice(0, openingLoc.start.column - 1).replace(/[^\s>]/gu, " ");
7661
+ const closingSequence = parsed.openingSequence.text;
7662
+ return fixer.insertTextAfter(node, `\n${prefix}${closingSequence}`);
7663
+ }
7664
+ });
7665
+ },
7666
+ customContainer(node) {
7667
+ const parsed = parseCustomContainer(sourceCode, node);
7668
+ if (!parsed) return;
7669
+ if (!parsed.closingSequence) context.report({
7670
+ node,
7671
+ loc: parsed.openingSequence.loc,
7672
+ messageId: "missingClosingContainer",
7673
+ fix(fixer) {
7674
+ const openingLoc = parsed.openingSequence.loc;
7675
+ const prefix = sourceCode.lines[openingLoc.start.line - 1].slice(0, openingLoc.start.column - 1).replace(/[^\s>]/gu, " ");
7676
+ const closingSequence = parsed.openingSequence.text;
7677
+ return fixer.insertTextAfter(node, `\n${prefix}${closingSequence}`);
7678
+ }
7679
+ });
7680
+ }
7681
+ };
7682
+ }
7683
+ });
7684
+
7390
7685
  //#endregion
7391
7686
  //#region src/rules/no-laziness-blockquotes.ts
7392
7687
  var no_laziness_blockquotes_default = createRule("no-laziness-blockquotes", {
@@ -7700,31 +7995,37 @@ var no_multi_spaces_default = createRule("no-multi-spaces", {
7700
7995
  const sourceCode = context.sourceCode;
7701
7996
  let codeText = sourceCode.text;
7702
7997
  return {
7998
+ customContainer: verifyCustomContainer,
7999
+ code: verifyCodeBlock,
7703
8000
  definition: verifyLinkDefinition,
7704
8001
  footnoteDefinition: verifyFootnoteDefinition,
7705
8002
  heading: verifyHeading,
7706
8003
  image: verifyImage,
7707
8004
  imageReference: verifyImageReference,
8005
+ inlineMath: verifyInlineMath,
7708
8006
  link: verifyLink,
7709
8007
  linkReference: verifyLinkReference,
7710
8008
  listItem: verifyListItem,
7711
- blockquote: processBlockquote,
8009
+ table: verifyTable,
7712
8010
  text: verifyText,
7713
- table: verifyTable
8011
+ math: verifyMathBlock,
8012
+ blockquote: processBlockquote
7714
8013
  };
7715
8014
  /**
7716
- * Verify a text node.
8015
+ * Verify a code block node.
7717
8016
  */
7718
- function verifyText(node) {
7719
- verifyTextInNode(node);
8017
+ function verifyCustomContainer(node) {
8018
+ const parsed = parseCustomContainer(sourceCode, node);
8019
+ if (!parsed) return;
8020
+ verifyTextInRange(node, [parsed.openingSequence.range[0], parsed.info.range[1]]);
7720
8021
  }
7721
8022
  /**
7722
- * Verify a table node.
8023
+ * Verify a code block node.
7723
8024
  */
7724
- function verifyTable(node) {
7725
- const parsedDelimiterRow = parseTableDelimiterRow(sourceCode, node);
7726
- if (!parsedDelimiterRow) return;
7727
- verifyTextInRange(node, parsedDelimiterRow.range);
8025
+ function verifyCodeBlock(node) {
8026
+ const parsed = parseFencedCodeBlock(sourceCode, node);
8027
+ if (!parsed) return;
8028
+ verifyTextInRange(node, [parsed.openingFence.range[0], (parsed.meta ?? parsed.language ?? parsed.openingFence).range[1]]);
7728
8029
  }
7729
8030
  /**
7730
8031
  * Verify a definition node.
@@ -7765,6 +8066,12 @@ var no_multi_spaces_default = createRule("no-multi-spaces", {
7765
8066
  verifyTextInNode(node);
7766
8067
  }
7767
8068
  /**
8069
+ * Verify an inline math node
8070
+ */
8071
+ function verifyInlineMath(node) {
8072
+ verifyTextInNode(node);
8073
+ }
8074
+ /**
7768
8075
  * Verify a link node
7769
8076
  */
7770
8077
  function verifyLink(node) {
@@ -7800,6 +8107,26 @@ var no_multi_spaces_default = createRule("no-multi-spaces", {
7800
8107
  codeText = newCodeText;
7801
8108
  }
7802
8109
  /**
8110
+ * Verify a table node.
8111
+ */
8112
+ function verifyTable(node) {
8113
+ const parsedDelimiterRow = parseTableDelimiterRow(sourceCode, node);
8114
+ if (!parsedDelimiterRow) return;
8115
+ verifyTextInRange(node, parsedDelimiterRow.range);
8116
+ }
8117
+ /**
8118
+ * Verify a text node.
8119
+ */
8120
+ function verifyText(node) {
8121
+ verifyTextInNode(node);
8122
+ }
8123
+ /**
8124
+ * Verify a math block node
8125
+ */
8126
+ function verifyMathBlock(node) {
8127
+ verifyTextInNode(node);
8128
+ }
8129
+ /**
7803
8130
  * Verify spaces in a node
7804
8131
  */
7805
8132
  function verifyTextInNode(node) {
@@ -8312,14 +8639,14 @@ var ordered_list_marker_sequence_default = createRule("ordered-list-marker-seque
8312
8639
  }
8313
8640
  }
8314
8641
  return {
8315
- "blockquote, listItem, footnoteDefinition"(node) {
8642
+ "blockquote, listItem, footnoteDefinition, customContainer"(node) {
8316
8643
  scope = {
8317
8644
  node,
8318
8645
  upper: scope,
8319
8646
  last: null
8320
8647
  };
8321
8648
  },
8322
- "blockquote, listItem, footnoteDefinition:exit"(node) {
8649
+ "blockquote, listItem, footnoteDefinition, customContainer:exit"(node) {
8323
8650
  if (scope.node === node) scope = scope.upper;
8324
8651
  },
8325
8652
  heading() {
@@ -8401,14 +8728,14 @@ var ordered_list_marker_start_default = createRule("ordered-list-marker-start",
8401
8728
  });
8402
8729
  }
8403
8730
  return {
8404
- "blockquote, listItem, footnoteDefinition"(node) {
8731
+ "blockquote, listItem, footnoteDefinition, customContainer"(node) {
8405
8732
  scope = {
8406
8733
  node,
8407
8734
  upper: scope,
8408
8735
  last: null
8409
8736
  };
8410
8737
  },
8411
- "blockquote, listItem, footnoteDefinition:exit"(node) {
8738
+ "blockquote, listItem, footnoteDefinition, customContainer:exit"(node) {
8412
8739
  if (scope.node === node) scope = scope.upper;
8413
8740
  },
8414
8741
  heading() {
@@ -8581,14 +8908,14 @@ var ordered_list_marker_style_default = createRule("ordered-list-marker-style",
8581
8908
  if (!node.ordered) return;
8582
8909
  checkOrderedList(node);
8583
8910
  },
8584
- "root, blockquote, listItem, footnoteDefinition"(node) {
8911
+ "root, blockquote, listItem, footnoteDefinition, customContainer"(node) {
8585
8912
  containerStack = {
8586
8913
  node,
8587
8914
  level: node.type === "listItem" ? containerStack.level + 1 : 1,
8588
8915
  upper: containerStack
8589
8916
  };
8590
8917
  },
8591
- "root, blockquote, listItem, footnoteDefinition:exit"() {
8918
+ "root, blockquote, listItem, footnoteDefinition, customContainer:exit"() {
8592
8919
  containerStack = containerStack.upper;
8593
8920
  }
8594
8921
  };
@@ -8636,6 +8963,9 @@ const BLOCK_TYPES = [
8636
8963
  "link-definition",
8637
8964
  "footnote-definition",
8638
8965
  "frontmatter",
8966
+ "custom-container",
8967
+ "math",
8968
+ "import-code-snippet",
8639
8969
  "*"
8640
8970
  ];
8641
8971
  const BLOCK_TYPE_SCHEMAS = [{
@@ -8675,7 +9005,10 @@ const BLOCK_TYPE_MAP = {
8675
9005
  footnoteDefinition: "footnote-definition",
8676
9006
  json: "frontmatter",
8677
9007
  toml: "frontmatter",
8678
- yaml: "frontmatter"
9008
+ yaml: "frontmatter",
9009
+ customContainer: "custom-container",
9010
+ math: "math",
9011
+ importCodeSnippet: "import-code-snippet"
8679
9012
  };
8680
9013
  /**
8681
9014
  * Get the block type of a node
@@ -8871,10 +9204,10 @@ var padding_line_between_blocks_default = createRule("padding-line-between-block
8871
9204
  }
8872
9205
  }
8873
9206
  return {
8874
- "root, blockquote, listItem, footnoteDefinition"(node) {
9207
+ "root, blockquote, listItem, footnoteDefinition, customContainer"(node) {
8875
9208
  containerStack.unshift(node);
8876
9209
  },
8877
- "root, blockquote, listItem, footnoteDefinition:exit"(node) {
9210
+ "root, blockquote, listItem, footnoteDefinition, customContainer:exit"(node) {
8878
9211
  checkBlockPadding(node);
8879
9212
  containerStack.shift();
8880
9213
  }
@@ -11100,6 +11433,7 @@ const rules$1 = [
11100
11433
  link_paren_spacing_default,
11101
11434
  link_title_style_default,
11102
11435
  list_marker_alignment_default,
11436
+ no_implicit_block_closing_default,
11103
11437
  no_laziness_blockquotes_default,
11104
11438
  no_multi_spaces_default,
11105
11439
  no_multiple_empty_lines_default,
@@ -11150,6 +11484,7 @@ const rules$3 = {
11150
11484
  "markdown-preferences/blockquote-marker-alignment": "error",
11151
11485
  "markdown-preferences/hard-linebreak-style": "error",
11152
11486
  "markdown-preferences/list-marker-alignment": "error",
11487
+ "markdown-preferences/no-implicit-block-closing": "error",
11153
11488
  "markdown-preferences/no-laziness-blockquotes": "error",
11154
11489
  "markdown-preferences/no-text-backslash-linebreak": "error",
11155
11490
  "markdown-preferences/prefer-autolinks": "error",
@@ -11195,6 +11530,7 @@ const rules$2 = {
11195
11530
  "markdown-preferences/link-paren-spacing": "error",
11196
11531
  "markdown-preferences/link-title-style": "error",
11197
11532
  "markdown-preferences/list-marker-alignment": "error",
11533
+ "markdown-preferences/no-implicit-block-closing": "error",
11198
11534
  "markdown-preferences/no-laziness-blockquotes": "error",
11199
11535
  "markdown-preferences/no-multi-spaces": "error",
11200
11536
  "markdown-preferences/no-multiple-empty-lines": "error",
@@ -11224,7 +11560,440 @@ var meta_exports = /* @__PURE__ */ __export({
11224
11560
  version: () => version
11225
11561
  });
11226
11562
  const name = "eslint-plugin-markdown-preferences";
11227
- const version = "0.26.1";
11563
+ const version = "0.28.0";
11564
+
11565
+ //#endregion
11566
+ //#region src/language/extensions/micromark-custom-container.ts
11567
+ /**
11568
+ * Micromark extension to support custom containers (e.g., ::: warning ... :::).
11569
+ */
11570
+ function customContainer() {
11571
+ const customContainerOpenConstruct = {
11572
+ name: "customContainer",
11573
+ continuation: {
11574
+ name: "customContainerContinuation",
11575
+ tokenize(effects, ok, nok) {
11576
+ return tokenizeCustomContainerContinuation(this, effects, ok, nok);
11577
+ }
11578
+ },
11579
+ exit(effects) {
11580
+ effects.exit("customContainer");
11581
+ },
11582
+ tokenize(effects, ok, nok) {
11583
+ return tokenizeCustomContainerOpen(this, effects, ok, nok);
11584
+ }
11585
+ };
11586
+ const customContainerCloseConstruct = {
11587
+ name: "customContainerCloseConstruct",
11588
+ tokenize(effects, ok, nok) {
11589
+ return tokenizeCustomContainerClose(this, effects, ok, nok);
11590
+ }
11591
+ };
11592
+ return { document: { [codes.colon]: customContainerOpenConstruct } };
11593
+ /**
11594
+ * Continuation tokenizer for the opening marker of the custom container.
11595
+ */
11596
+ function tokenizeCustomContainerOpen(self, effects, ok, nok) {
11597
+ let size = 0;
11598
+ let openToken;
11599
+ const infoCodes = [];
11600
+ return start;
11601
+ /**
11602
+ * Process start for the opening marker of the custom container.
11603
+ */
11604
+ function start(code) {
11605
+ if (code !== codes.colon) return nok(code);
11606
+ size = 0;
11607
+ openToken = effects.enter("customContainer", { _container: true });
11608
+ effects.enter("customContainerFence");
11609
+ effects.enter("customContainerFenceSequence");
11610
+ return sequence;
11611
+ }
11612
+ /**
11613
+ * Process sequence for the opening marker of the custom container.
11614
+ *
11615
+ * ```markdown
11616
+ * > | ::: info
11617
+ * ^
11618
+ * ```
11619
+ */
11620
+ function sequence(code) {
11621
+ if (code === codes.colon) {
11622
+ size++;
11623
+ effects.consume(code);
11624
+ return sequence;
11625
+ }
11626
+ if (size < 3) return nok(code);
11627
+ effects.exit("customContainerFenceSequence");
11628
+ return markdownSpace(code) ? factorySpace(effects, infoBefore, types.whitespace)(code) : infoBefore(code);
11629
+ }
11630
+ /**
11631
+ * Process before info for the opening marker of the custom container.
11632
+ *
11633
+ * ```markdown
11634
+ * > | ::: info
11635
+ * ^
11636
+ * ```
11637
+ */
11638
+ function infoBefore(code) {
11639
+ if (code === codes.eof || markdownLineEnding(code)) return nok(code);
11640
+ openToken._customContainer = { size };
11641
+ self.containerState._customContainer = { open: openToken };
11642
+ effects.enter("customContainerFenceInfo");
11643
+ effects.enter(types.chunkString, { contentType: constants.contentTypeString });
11644
+ infoCodes.length = 0;
11645
+ return info(code);
11646
+ }
11647
+ /**
11648
+ * Process info for the opening marker of the custom container.
11649
+ *
11650
+ * ```markdown
11651
+ * > | ::: info
11652
+ * ^
11653
+ * ```
11654
+ *
11655
+ * @type {State}
11656
+ */
11657
+ function info(code) {
11658
+ if (code === codes.eof || markdownLineEnding(code)) {
11659
+ effects.exit(types.chunkString);
11660
+ effects.exit("customContainerFenceInfo");
11661
+ effects.exit("customContainerFence");
11662
+ openToken._customContainer.info = String.fromCharCode(...infoCodes);
11663
+ return ok(code);
11664
+ }
11665
+ infoCodes.push(code);
11666
+ effects.consume(code);
11667
+ return info;
11668
+ }
11669
+ }
11670
+ /**
11671
+ * Continuation tokenizer for the closing marker of the custom container.
11672
+ */
11673
+ function tokenizeCustomContainerClose(self, effects, ok, nok) {
11674
+ let size = 0;
11675
+ return start;
11676
+ /**
11677
+ * Process start for the closing marker of the custom container.
11678
+ */
11679
+ function start(code) {
11680
+ if (code !== codes.colon) return nok(code);
11681
+ size = 0;
11682
+ effects.enter("customContainerFence");
11683
+ effects.enter("customContainerFenceSequence");
11684
+ return sequence;
11685
+ }
11686
+ /**
11687
+ * Process sequence for the closing marker of the custom container.
11688
+ *
11689
+ * ```markdown
11690
+ * > | :::
11691
+ * ```
11692
+ */
11693
+ function sequence(code) {
11694
+ if (code === codes.colon) {
11695
+ size++;
11696
+ effects.consume(code);
11697
+ return sequence;
11698
+ }
11699
+ if (size < 3) return nok(code);
11700
+ effects.exit("customContainerFenceSequence");
11701
+ return markdownSpace(code) ? factorySpace(effects, after, types.whitespace)(code) : after(code);
11702
+ }
11703
+ /**
11704
+ * Process after for the closing marker of the custom container.
11705
+ *
11706
+ * ```markdown
11707
+ * > | :::
11708
+ * ^
11709
+ * ```
11710
+ */
11711
+ function after(code) {
11712
+ if (code === codes.eof || markdownLineEnding(code)) {
11713
+ if (!self.containerState) throw new Error("containerState is undefined");
11714
+ const openToken = self.containerState._customContainer?.open;
11715
+ if (openToken?._customContainer?.size === size) {
11716
+ openToken._customContainer.closed = true;
11717
+ self.containerState._closeFlow = true;
11718
+ effects.exit("customContainerFence");
11719
+ return ok(code);
11720
+ }
11721
+ }
11722
+ return nok(code);
11723
+ }
11724
+ }
11725
+ /**
11726
+ * Continuation tokenizer for the custom container.
11727
+ */
11728
+ function tokenizeCustomContainerContinuation(self, effects, ok, nok) {
11729
+ if (self.containerState?._customContainer?.open?._customContainer?.closed) {
11730
+ self.containerState._closeFlow = true;
11731
+ return nok;
11732
+ }
11733
+ return start;
11734
+ /**
11735
+ * Process start for the custom container.
11736
+ */
11737
+ function start(code) {
11738
+ if (code !== codes.colon) return ok(code);
11739
+ return effects.attempt(customContainerCloseConstruct, () => {
11740
+ self.containerState._closeFlow = true;
11741
+ return ok;
11742
+ }, ok);
11743
+ }
11744
+ }
11745
+ }
11746
+
11747
+ //#endregion
11748
+ //#region src/language/extensions/mdast-custom-container.ts
11749
+ /**
11750
+ * Mdast extension to support custom containers (e.g., ::: warning ... :::).
11751
+ */
11752
+ function customContainerFromMarkdown() {
11753
+ return {
11754
+ enter: {
11755
+ customContainer(token) {
11756
+ this.enter({
11757
+ type: "customContainer",
11758
+ children: [],
11759
+ info: null
11760
+ }, token);
11761
+ },
11762
+ customContainerFenceInfo() {
11763
+ this.buffer();
11764
+ }
11765
+ },
11766
+ exit: {
11767
+ customContainer(token) {
11768
+ this.exit(token);
11769
+ },
11770
+ customContainerFenceInfo() {
11771
+ const data = this.resume();
11772
+ const node = this.stack[this.stack.length - 1];
11773
+ node.info = data;
11774
+ }
11775
+ }
11776
+ };
11777
+ }
11778
+
11779
+ //#endregion
11780
+ //#region src/language/extensions/micromark-import-code-snippet.ts
11781
+ /**
11782
+ * Micromark extension to support [VitePress-style Import Code Snippets](https://vitepress.dev/guide/markdown#import-code-snippets) syntax using triple left angle brackets.
11783
+ */
11784
+ function importCodeSnippet() {
11785
+ const importCodeSnippetConstruct = {
11786
+ name: "importCodeSnippet",
11787
+ tokenize(effects, ok, nok) {
11788
+ return tokenizeImportCodeSnippet(this, effects, ok, nok);
11789
+ }
11790
+ };
11791
+ return { flow: { [codes.lessThan]: importCodeSnippetConstruct } };
11792
+ /**
11793
+ * Tokenizer for the import code snippet.
11794
+ */
11795
+ function tokenizeImportCodeSnippet(_self, effects, ok, nok) {
11796
+ let size = 0;
11797
+ return start;
11798
+ /**
11799
+ * Process start for the opening marker of the import code snippet.
11800
+ */
11801
+ function start(code) {
11802
+ if (code !== codes.lessThan) return nok(code);
11803
+ size = 0;
11804
+ effects.enter("importCodeSnippet");
11805
+ effects.enter("importCodeSnippetMarkerSequence");
11806
+ return sequence(code);
11807
+ }
11808
+ /**
11809
+ * Process the sequence of opening markers for the import code snippet.
11810
+ *
11811
+ * ```markdown
11812
+ * > | <<< ./path/to/code.ts
11813
+ * ^^^
11814
+ * ```
11815
+ */
11816
+ function sequence(code) {
11817
+ if (code === codes.lessThan) {
11818
+ size++;
11819
+ effects.consume(code);
11820
+ return sequence;
11821
+ }
11822
+ if (size < 3) return nok(code);
11823
+ effects.exit("importCodeSnippetMarkerSequence");
11824
+ return markdownSpace(code) ? factorySpace(effects, afterMarker, types.whitespace)(code) : afterMarker(code);
11825
+ }
11826
+ /**
11827
+ * Process after the opening marker of the import code snippet.
11828
+ *
11829
+ * ```markdown
11830
+ * > | <<< ./path/to/code.ts
11831
+ * ^
11832
+ * ```
11833
+ */
11834
+ function afterMarker(code) {
11835
+ if (code === codes.eof || markdownLineEnding(code)) return nok(code);
11836
+ effects.enter("importCodeSnippetPath");
11837
+ effects.enter(types.chunkString, { contentType: constants.contentTypeString });
11838
+ return importPath(code);
11839
+ }
11840
+ /**
11841
+ * Process the path of the import code snippet.
11842
+ *
11843
+ * ```markdown
11844
+ * > | <<< ./path/to/code.ts
11845
+ * ^^^^^^^^^^^^^^^^^
11846
+ * ```
11847
+ */
11848
+ function importPath(code) {
11849
+ if (code === codes.eof || markdownLineEnding(code) || markdownSpace(code)) {
11850
+ effects.exit(types.chunkString);
11851
+ effects.exit("importCodeSnippetPath");
11852
+ effects.exit("importCodeSnippet");
11853
+ return afterPath(code);
11854
+ }
11855
+ effects.consume(code);
11856
+ return importPath;
11857
+ }
11858
+ /**
11859
+ * Process after the path of the import code snippet.
11860
+ *
11861
+ * ```markdown
11862
+ * > | <<< ./path/to/code.ts
11863
+ * ^
11864
+ * ```
11865
+ */
11866
+ function afterPath(code) {
11867
+ if (code === codes.eof || markdownLineEnding(code)) return ok(code);
11868
+ if (markdownSpace(code)) return factorySpace(effects, afterPath, types.whitespace)(code);
11869
+ return nok(code);
11870
+ }
11871
+ }
11872
+ }
11873
+
11874
+ //#endregion
11875
+ //#region src/language/extensions/mdast-import-code-snippet.ts
11876
+ /**
11877
+ * Mdast extension to support [VitePress-style Import Code Snippets](https://vitepress.dev/guide/markdown#import-code-snippets) syntax using triple left angle brackets.
11878
+ */
11879
+ function importCodeSnippetFromMarkdown() {
11880
+ return {
11881
+ enter: {
11882
+ importCodeSnippet(token) {
11883
+ this.enter({
11884
+ type: "importCodeSnippet",
11885
+ value: ""
11886
+ }, token);
11887
+ },
11888
+ importCodeSnippetPath() {
11889
+ this.buffer();
11890
+ }
11891
+ },
11892
+ exit: {
11893
+ importCodeSnippet(token) {
11894
+ this.exit(token);
11895
+ },
11896
+ importCodeSnippetPath() {
11897
+ const data = this.resume();
11898
+ const node = this.stack[this.stack.length - 1];
11899
+ node.value = data;
11900
+ }
11901
+ }
11902
+ };
11903
+ }
11904
+
11905
+ //#endregion
11906
+ //#region src/language/parser.ts
11907
+ /**
11908
+ * Parse Extended Markdown to MDAST.
11909
+ */
11910
+ function parseExtendedMarkdown(code) {
11911
+ const options = {
11912
+ extensions: [
11913
+ gfm(),
11914
+ frontmatter(["yaml", "toml"]),
11915
+ math(),
11916
+ customContainer(),
11917
+ importCodeSnippet()
11918
+ ],
11919
+ mdastExtensions: [
11920
+ gfmFromMarkdown(),
11921
+ frontmatterFromMarkdown(["yaml", "toml"]),
11922
+ mathFromMarkdown(),
11923
+ customContainerFromMarkdown(),
11924
+ importCodeSnippetFromMarkdown()
11925
+ ]
11926
+ };
11927
+ return fromMarkdown(code, options);
11928
+ }
11929
+
11930
+ //#endregion
11931
+ //#region src/language/extended-markdown-language.ts
11932
+ var ExtendedMarkdownLanguage = class {
11933
+ /**
11934
+ * The type of file to read.
11935
+ * @type {"text"}
11936
+ */
11937
+ fileType = markdown.languages.gfm.fileType;
11938
+ /**
11939
+ * The line number at which the parser starts counting.
11940
+ * @type {0|1}
11941
+ */
11942
+ lineStart = markdown.languages.gfm.lineStart;
11943
+ /**
11944
+ * The column number at which the parser starts counting.
11945
+ * @type {0|1}
11946
+ */
11947
+ columnStart = markdown.languages.gfm.columnStart;
11948
+ /**
11949
+ * The name of the key that holds the type of the node.
11950
+ * @type {string}
11951
+ */
11952
+ nodeTypeKey = markdown.languages.gfm.nodeTypeKey;
11953
+ /**
11954
+ * Default language options. User-defined options are merged with this object.
11955
+ * @type {MarkdownLanguageOptions}
11956
+ */
11957
+ defaultLanguageOptions = markdown.languages.gfm.defaultLanguageOptions;
11958
+ /**
11959
+ * Validates the language options.
11960
+ * @param {MarkdownLanguageOptions} languageOptions The language options to validate.
11961
+ * @returns {void}
11962
+ * @throws {Error} When the language options are invalid.
11963
+ */
11964
+ validateLanguageOptions(languageOptions$2) {
11965
+ return markdown.languages.gfm.validateLanguageOptions(languageOptions$2);
11966
+ }
11967
+ /**
11968
+ * Parses the given file into an AST.
11969
+ * @param {File} file The virtual file to parse.
11970
+ * @param {MarkdownLanguageContext} _context The options to use for parsing.
11971
+ * @returns {ParseResult<Root>} The result of parsing.
11972
+ */
11973
+ parse(file, _context) {
11974
+ const text = file.body;
11975
+ try {
11976
+ return {
11977
+ ok: true,
11978
+ ast: parseExtendedMarkdown(text)
11979
+ };
11980
+ } catch (ex) {
11981
+ return {
11982
+ ok: false,
11983
+ errors: [ex]
11984
+ };
11985
+ }
11986
+ }
11987
+ /**
11988
+ * Creates a new `MarkdownSourceCode` object from the given information.
11989
+ * @param {File} file The virtual file to create a `MarkdownSourceCode` object from.
11990
+ * @param {OkParseResult<Root>} parseResult The result returned from `parse()`.
11991
+ * @returns {MarkdownSourceCode} The new `MarkdownSourceCode` object.
11992
+ */
11993
+ createSourceCode(file, parseResult) {
11994
+ return markdown.languages.gfm.createSourceCode(file, parseResult);
11995
+ }
11996
+ };
11228
11997
 
11229
11998
  //#endregion
11230
11999
  //#region src/index.ts
@@ -11240,12 +12009,14 @@ const resources = {
11240
12009
  defaultPreserveWords,
11241
12010
  defaultMinorWords
11242
12011
  };
12012
+ const languages = { "extended-syntax": new ExtendedMarkdownLanguage() };
11243
12013
  var src_default = {
11244
12014
  meta: meta_exports,
12015
+ languages,
11245
12016
  configs,
11246
12017
  rules,
11247
12018
  resources
11248
12019
  };
11249
12020
 
11250
12021
  //#endregion
11251
- export { configs, src_default as default, meta_exports as meta, resources, rules };
12022
+ export { configs, src_default as default, languages, meta_exports as meta, resources, rules };