eslint-plugin-markdown-preferences 0.20.0 → 0.22.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
@@ -30,6 +30,12 @@ function createRule(ruleName, rule) {
30
30
  //#endregion
31
31
  //#region src/utils/ast.ts
32
32
  /**
33
+ * Get the parent of a node.
34
+ */
35
+ function getParent(sourceCode, node) {
36
+ return sourceCode.getParent(node);
37
+ }
38
+ /**
33
39
  * Get the kind of heading.
34
40
  */
35
41
  function getHeadingKind(sourceCode, node) {
@@ -150,6 +156,12 @@ function isSpaceOrTab(string) {
150
156
  function isPunctuation(char) {
151
157
  return /^[\p{P}\p{S}]+$/u.test(char);
152
158
  }
159
+ /**
160
+ * Check if the character is an ASCII control character
161
+ */
162
+ function isAsciiControlCharacter(char) {
163
+ return /^[\x00-\x1f\x7f]+$/u.test(char);
164
+ }
153
165
 
154
166
  //#endregion
155
167
  //#region src/utils/atx-heading.ts
@@ -387,7 +399,7 @@ var atx_heading_closing_sequence_length_default = createRule("atx-heading-closin
387
399
  type: "layout",
388
400
  docs: {
389
401
  description: "enforce consistent length for the closing sequence (trailing #s) in ATX headings.",
390
- categories: [],
402
+ categories: ["standard"],
391
403
  listCategory: "Stylistic"
392
404
  },
393
405
  fixable: "code",
@@ -413,7 +425,8 @@ var atx_heading_closing_sequence_length_default = createRule("atx-heading-closin
413
425
  },
414
426
  create(context) {
415
427
  const sourceCode = context.sourceCode;
416
- const option = Object.assign({ mode: "match-opening" }, context.options[0] || {});
428
+ const option = context.options[0] || {};
429
+ const mode = option.mode || "match-opening";
417
430
  /**
418
431
  * Verify the closing sequence length of an ATX heading.
419
432
  */
@@ -433,12 +446,12 @@ var atx_heading_closing_sequence_length_default = createRule("atx-heading-closin
433
446
  }
434
447
  });
435
448
  }
436
- if (option.mode === "match-opening") return { heading(node) {
449
+ if (mode === "match-opening") return { heading(node) {
437
450
  const parsed = parseATXHeading(sourceCode, node);
438
451
  if (!parsed || parsed.closingSequence == null) return;
439
452
  verifyATXHeadingClosingSequenceLength(parsed, node, node.depth);
440
453
  } };
441
- if (option.mode === "length") {
454
+ if (mode === "length") {
442
455
  const expected = option.length || 2;
443
456
  return { heading(node) {
444
457
  const parsed = parseATXHeading(sourceCode, node);
@@ -446,7 +459,7 @@ var atx_heading_closing_sequence_length_default = createRule("atx-heading-closin
446
459
  verifyATXHeadingClosingSequenceLength(parsed, node, expected);
447
460
  } };
448
461
  }
449
- if (option.mode === "fixed-line-length") {
462
+ if (mode === "fixed-line-length") {
450
463
  const totalLength = option.length || 80;
451
464
  return { heading(node) {
452
465
  const parsed = parseATXHeading(sourceCode, node);
@@ -454,7 +467,7 @@ var atx_heading_closing_sequence_length_default = createRule("atx-heading-closin
454
467
  verifyATXHeadingClosingSequenceLength(parsed, node, totalLength - getContentLength(parsed));
455
468
  } };
456
469
  }
457
- if (option.mode === "consistent") {
470
+ if (mode === "consistent") {
458
471
  let expectedLength = null;
459
472
  return { heading(node) {
460
473
  const parsed = parseATXHeading(sourceCode, node);
@@ -463,7 +476,7 @@ var atx_heading_closing_sequence_length_default = createRule("atx-heading-closin
463
476
  else verifyATXHeadingClosingSequenceLength(parsed, node, expectedLength);
464
477
  } };
465
478
  }
466
- if (option.mode === "consistent-line-length") {
479
+ if (mode === "consistent-line-length") {
467
480
  const headings = [];
468
481
  return {
469
482
  heading(node) {
@@ -502,8 +515,7 @@ var atx_heading_closing_sequence_length_default = createRule("atx-heading-closin
502
515
  * Get the content length of the heading.
503
516
  */
504
517
  function getContentLength(parsed) {
505
- const lines = getParsedLines(sourceCode);
506
- const line = lines.get(parsed.closingSequence.loc.start.line);
518
+ const line = getParsedLines(sourceCode).get(parsed.closingSequence.loc.start.line);
507
519
  const beforeClosing = sourceCode.text.slice(line.range[0], parsed.closingSequence.range[0]);
508
520
  return getTextWidth(beforeClosing);
509
521
  }
@@ -511,8 +523,7 @@ var atx_heading_closing_sequence_length_default = createRule("atx-heading-closin
511
523
  * Get the line length of the heading.
512
524
  */
513
525
  function getLineLength(parsed) {
514
- const lines = getParsedLines(sourceCode);
515
- const line = lines.get(parsed.closingSequence.loc.start.line);
526
+ const line = getParsedLines(sourceCode).get(parsed.closingSequence.loc.start.line);
516
527
  const lineText = sourceCode.text.slice(line.range[0], parsed.closingSequence.range[1]);
517
528
  return getTextWidth(lineText);
518
529
  }
@@ -526,7 +537,7 @@ var atx_heading_closing_sequence_default = createRule("atx-heading-closing-seque
526
537
  type: "layout",
527
538
  docs: {
528
539
  description: "enforce consistent use of closing sequence in ATX headings.",
529
- categories: [],
540
+ categories: ["standard"],
530
541
  listCategory: "Stylistic"
531
542
  },
532
543
  fixable: "code",
@@ -628,7 +639,7 @@ var blockquote_marker_alignment_default = createRule("blockquote-marker-alignmen
628
639
  type: "layout",
629
640
  docs: {
630
641
  description: "enforce consistent alignment of blockquote markers",
631
- categories: ["recommended"],
642
+ categories: ["recommended", "standard"],
632
643
  listCategory: "Stylistic"
633
644
  },
634
645
  fixable: "whitespace",
@@ -677,8 +688,7 @@ var blockquote_marker_alignment_default = createRule("blockquote-marker-alignmen
677
688
  },
678
689
  messageId: "inconsistentAlignment",
679
690
  fix(fixer) {
680
- const lines = getParsedLines(sourceCode);
681
- const line = lines.get(lineNumber);
691
+ const line = getParsedLines(sourceCode).get(lineNumber);
682
692
  if (marker.index < base.index) {
683
693
  const addSpaces = " ".repeat(base.index - marker.index);
684
694
  return fixer.insertTextBeforeRange([line.range[0] + marker.index, line.range[0] + marker.index], addSpaces);
@@ -687,8 +697,7 @@ var blockquote_marker_alignment_default = createRule("blockquote-marker-alignmen
687
697
  const expectedSpaces = " ".repeat(base.index);
688
698
  return fixer.replaceTextRange([line.range[0], line.range[0] + marker.index], expectedSpaces);
689
699
  }
690
- const itemBefore = line.text.slice(0, line.range[0] + marker.index);
691
- if (itemBefore.includes(" ")) return null;
700
+ if (line.text.slice(0, line.range[0] + marker.index).includes(" ")) return null;
692
701
  let removeStartIndex = marker.index;
693
702
  for (; removeStartIndex > base.index; removeStartIndex--) if (line.text[removeStartIndex - 1] !== " ") break;
694
703
  return fixer.removeRange([line.range[0] + removeStartIndex, line.range[0] + marker.index]);
@@ -719,7 +728,7 @@ function getOtherMarker(unavailableMarker) {
719
728
  /**
720
729
  * Parse rule options.
721
730
  */
722
- function parseOptions$1(options) {
731
+ function parseOptions$2(options) {
723
732
  const primary = options.primary || "-";
724
733
  const secondary = options.secondary || getOtherMarker(primary);
725
734
  if (primary === secondary) throw new Error(`\`primary\` and \`secondary\` cannot be the same (primary: "${primary}", secondary: "${secondary}").`);
@@ -750,7 +759,7 @@ var bullet_list_marker_style_default = createRule("bullet-list-marker-style", {
750
759
  type: "layout",
751
760
  docs: {
752
761
  description: "enforce consistent bullet list (unordered list) marker style",
753
- categories: [],
762
+ categories: ["standard"],
754
763
  listCategory: "Stylistic"
755
764
  },
756
765
  fixable: "code",
@@ -787,7 +796,7 @@ var bullet_list_marker_style_default = createRule("bullet-list-marker-style", {
787
796
  },
788
797
  create(context) {
789
798
  const sourceCode = context.sourceCode;
790
- const options = parseOptions$1(context.options[0] || {});
799
+ const options = parseOptions$2(context.options[0] || {});
791
800
  let containerStack = {
792
801
  node: sourceCode.ast,
793
802
  level: 1,
@@ -831,8 +840,7 @@ var bullet_list_marker_style_default = createRule("bullet-list-marker-style", {
831
840
  for (let index = nodeIndex + 1; index < containerStack.node.children.length; index++) {
832
841
  const nextNode = containerStack.node.children[index];
833
842
  if (nextNode.type !== "list") break;
834
- const nextMarker = getListItemMarker(sourceCode, nextNode);
835
- if (nextMarker.kind !== prevMarker) break;
843
+ if (getListItemMarker(sourceCode, nextNode).kind !== prevMarker) break;
836
844
  let expectedNextMarker = prevMarker === primary ? secondary : primary;
837
845
  if (expectedNextMarker === "any") expectedNextMarker = getOtherMarker(prevMarker);
838
846
  yield* fixMarkers(nextNode, expectedNextMarker);
@@ -902,15 +910,11 @@ function parseFencedCodeBlock(sourceCode, node) {
902
910
  }
903
911
  closingFenceText = closingFenceText.trimStart();
904
912
  if (!closingFenceText || !closingFenceText.startsWith(fenceText)) return null;
905
- const lines = getParsedLines(sourceCode);
906
- const afterOpeningFence = lines.get(loc.start.line).text.slice(fenceText.length);
913
+ const afterOpeningFence = getParsedLines(sourceCode).get(loc.start.line).text.slice(fenceText.length);
907
914
  const trimmedAfterOpeningFence = afterOpeningFence.trimStart();
908
915
  const spaceAfterOpeningFenceLength = afterOpeningFence.length - trimmedAfterOpeningFence.length;
909
916
  let languageText = "";
910
- if (trimmedAfterOpeningFence) {
911
- const langMatch = RE_LANGUAGE.exec(trimmedAfterOpeningFence);
912
- languageText = langMatch[1];
913
- }
917
+ if (trimmedAfterOpeningFence) languageText = RE_LANGUAGE.exec(trimmedAfterOpeningFence)[1];
914
918
  const afterLanguage = trimmedAfterOpeningFence.slice(languageText.length);
915
919
  const trimmedAfterLanguage = afterLanguage.trimStart();
916
920
  const spaceAfterLanguageLength = afterLanguage.length - trimmedAfterLanguage.length;
@@ -926,7 +930,7 @@ function parseFencedCodeBlock(sourceCode, node) {
926
930
  }
927
931
  }
928
932
  };
929
- const language$1 = languageText ? {
933
+ const language$2 = languageText ? {
930
934
  text: languageText,
931
935
  range: [openingFence.range[1] + spaceAfterOpeningFenceLength, openingFence.range[1] + spaceAfterOpeningFenceLength + languageText.length],
932
936
  loc: {
@@ -940,23 +944,23 @@ function parseFencedCodeBlock(sourceCode, node) {
940
944
  }
941
945
  }
942
946
  } : null;
943
- const meta = language$1 && metaText ? {
947
+ const meta = language$2 && metaText ? {
944
948
  text: metaText,
945
- range: [language$1.range[1] + spaceAfterLanguageLength, language$1.range[1] + spaceAfterLanguageLength + metaText.length],
949
+ range: [language$2.range[1] + spaceAfterLanguageLength, language$2.range[1] + spaceAfterLanguageLength + metaText.length],
946
950
  loc: {
947
951
  start: {
948
- line: language$1.loc.end.line,
949
- column: language$1.loc.end.column + spaceAfterLanguageLength
952
+ line: language$2.loc.end.line,
953
+ column: language$2.loc.end.column + spaceAfterLanguageLength
950
954
  },
951
955
  end: {
952
- line: language$1.loc.end.line,
953
- column: language$1.loc.end.column + spaceAfterLanguageLength + metaText.length
956
+ line: language$2.loc.end.line,
957
+ column: language$2.loc.end.column + spaceAfterLanguageLength + metaText.length
954
958
  }
955
959
  }
956
960
  } : null;
957
961
  return {
958
962
  openingFence,
959
- language: language$1,
963
+ language: language$2,
960
964
  meta,
961
965
  closingFence: {
962
966
  text: closingFenceText,
@@ -1054,7 +1058,7 @@ var code_fence_length_default = createRule("code-fence-length", {
1054
1058
  type: "layout",
1055
1059
  docs: {
1056
1060
  description: "enforce consistent code fence length in fenced code blocks.",
1057
- categories: [],
1061
+ categories: ["standard"],
1058
1062
  listCategory: "Stylistic"
1059
1063
  },
1060
1064
  fixable: "code",
@@ -1104,7 +1108,7 @@ var code_fence_length_default = createRule("code-fence-length", {
1104
1108
  * Get the effective options for the given code block node.
1105
1109
  */
1106
1110
  function getOptionForCode(node) {
1107
- const override = options.overrides?.find((o) => o.lang === node.lang);
1111
+ const override = options.overrides ? [...options.overrides].reverse().find((o) => o.lang === node.lang) : null;
1108
1112
  return {
1109
1113
  length: override?.length ?? options.length ?? 3,
1110
1114
  fallbackLength: override?.fallbackLength ?? options.fallbackLength ?? "minimum"
@@ -1158,8 +1162,7 @@ var code_fence_length_default = createRule("code-fence-length", {
1158
1162
  * Get the expected fence string for the given length.
1159
1163
  */
1160
1164
  function getExpectedFence(parsed, length) {
1161
- const fenceChar = parsed.openingFence.text[0];
1162
- return fenceChar.repeat(Math.max(3, length));
1165
+ return parsed.openingFence.text[0].repeat(Math.max(3, length));
1163
1166
  }
1164
1167
  /**
1165
1168
  * Verify that the opening and closing fence lengths match.
@@ -1192,7 +1195,7 @@ var code_fence_style_default = createRule("code-fence-style", {
1192
1195
  type: "layout",
1193
1196
  docs: {
1194
1197
  description: "enforce a consistent code fence style (backtick or tilde) in Markdown fenced code blocks.",
1195
- categories: [],
1198
+ categories: ["standard"],
1196
1199
  listCategory: "Stylistic"
1197
1200
  },
1198
1201
  fixable: "code",
@@ -1209,8 +1212,7 @@ var code_fence_style_default = createRule("code-fence-style", {
1209
1212
  },
1210
1213
  create(context) {
1211
1214
  const sourceCode = context.sourceCode;
1212
- const styleOption = context.options[0]?.style ?? "backtick";
1213
- const expectedChar = styleOption === "tilde" ? "~" : "`";
1215
+ const expectedChar = (context.options[0]?.style ?? "backtick") === "tilde" ? "~" : "`";
1214
1216
  return { code(node) {
1215
1217
  const parsed = parseFencedCodeBlock(sourceCode, node);
1216
1218
  if (!parsed) return;
@@ -1262,8 +1264,7 @@ var definitions_last_default = createRule("definitions-last", {
1262
1264
  *fix(fixer) {
1263
1265
  let rangeStart = range[0];
1264
1266
  for (let index = range[0] - 1; index >= 0; index--) {
1265
- const c = sourceCode.text[index];
1266
- if (c.trim()) break;
1267
+ if (sourceCode.text[index].trim()) break;
1267
1268
  rangeStart = index;
1268
1269
  }
1269
1270
  yield fixer.removeRange([rangeStart, range[1]]);
@@ -3229,13 +3230,13 @@ var EmojiData = class {
3229
3230
  get emojiToColon() {
3230
3231
  if (this._emojiToColon) return this._emojiToColon;
3231
3232
  const emojiToCode = this._emojiToColon = Object.create(null);
3232
- for (const [name$2, unicode] of this.entries) emojiToCode[unicode] = `:${name$2}:`;
3233
+ for (const [name$3, unicode] of this.entries) emojiToCode[unicode] = `:${name$3}:`;
3233
3234
  return emojiToCode;
3234
3235
  }
3235
3236
  get colonToEmoji() {
3236
3237
  if (this._colonToEmoji) return this._colonToEmoji;
3237
3238
  const colonToEmoji = this._colonToEmoji = Object.create(null);
3238
- for (const [name$2, unicode] of this.entries) colonToEmoji[`:${name$2}:`] = unicode;
3239
+ for (const [name$3, unicode] of this.entries) colonToEmoji[`:${name$3}:`] = unicode;
3239
3240
  return colonToEmoji;
3240
3241
  }
3241
3242
  };
@@ -3284,7 +3285,7 @@ var emoji_notation_default = createRule("emoji-notation", {
3284
3285
  const ignoreUnknown = options.ignoreUnknown ?? true;
3285
3286
  const ignoreList = (options.ignoreList || []).map((s) => toRegExp(s)).flatMap((re) => {
3286
3287
  const result = [re];
3287
- for (const [name$2, unicode] of emojiData.entries) if (re.test(`:${name$2}:`) || re.test(unicode)) result.push(toRegExp(`:${name$2}:`), toRegExp(unicode));
3288
+ for (const [name$3, unicode] of emojiData.entries) if (re.test(`:${name$3}:`) || re.test(unicode)) result.push(toRegExp(`:${name$3}:`), toRegExp(unicode));
3288
3289
  return result;
3289
3290
  });
3290
3291
  const isIgnoreBase = (s) => ignoreList.some((re) => re.test(s));
@@ -3365,7 +3366,7 @@ var emphasis_delimiters_style_default = createRule("emphasis-delimiters-style",
3365
3366
  type: "layout",
3366
3367
  docs: {
3367
3368
  description: "enforce a consistent delimiter style for emphasis and strong emphasis",
3368
- categories: [],
3369
+ categories: ["standard"],
3369
3370
  listCategory: "Stylistic"
3370
3371
  },
3371
3372
  fixable: "code",
@@ -3547,7 +3548,7 @@ var hard_linebreak_style_default = createRule("hard-linebreak-style", {
3547
3548
  type: "layout",
3548
3549
  docs: {
3549
3550
  description: "enforce consistent hard linebreak style.",
3550
- categories: ["recommended"],
3551
+ categories: ["recommended", "standard"],
3551
3552
  listCategory: "Stylistic"
3552
3553
  },
3553
3554
  fixable: "code",
@@ -4159,10 +4160,7 @@ var PreserveWordsContext = class {
4159
4160
  }
4160
4161
  if (subWords.every((word, i) => word.toLowerCase() === phrase[i].toLowerCase())) {
4161
4162
  let matchCount = 0;
4162
- for (let i = 0; i < subWords.length; i++) {
4163
- const word = subWords[i];
4164
- if (word === phrase[i]) matchCount++;
4165
- }
4163
+ for (let i = 0; i < subWords.length; i++) if (subWords[i] === phrase[i]) matchCount++;
4166
4164
  if (!returnCandidate || matchCount > returnCandidate.matchCount) returnCandidate = {
4167
4165
  preservePhrase: phrase,
4168
4166
  matchCount
@@ -4472,7 +4470,7 @@ var level1_heading_style_default = createRule("level1-heading-style", {
4472
4470
  type: "layout",
4473
4471
  docs: {
4474
4472
  description: "enforce consistent style for level 1 headings",
4475
- categories: [],
4473
+ categories: ["standard"],
4476
4474
  listCategory: "Stylistic"
4477
4475
  },
4478
4476
  fixable: "code",
@@ -4503,8 +4501,7 @@ var level1_heading_style_default = createRule("level1-heading-style", {
4503
4501
  if (headingKind !== "setext") return;
4504
4502
  const parsed = parseSetextHeading(sourceCode, node);
4505
4503
  if (!parsed) return;
4506
- const isMultiline = parsed.contentLines.length > 1;
4507
- if (isMultiline) {
4504
+ if (parsed.contentLines.length > 1) {
4508
4505
  if (allowMultilineSetext) return;
4509
4506
  context.report({
4510
4507
  node,
@@ -4534,8 +4531,7 @@ var level1_heading_style_default = createRule("level1-heading-style", {
4534
4531
  if (parsed.closingSequence) yield fixer.removeRange([parsed.closingSequence.raws.spaceBefore.range[0], parsed.closingSequence.raws.spaceAfter.range[1]]);
4535
4532
  const lines = getParsedLines(sourceCode);
4536
4533
  const underline = "=".repeat(Math.max(getTextWidth(parsed.content.text), 3));
4537
- const prefix = lines.get(parsed.openingSequence.loc.start.line).text.slice(0, parsed.openingSequence.loc.start.column - 1);
4538
- const appendingText = `\n${prefix}${underline}`;
4534
+ const appendingText = `\n${lines.get(parsed.openingSequence.loc.start.line).text.slice(0, parsed.openingSequence.loc.start.column - 1)}${underline}`;
4539
4535
  yield fixer.insertTextAfter(node, appendingText);
4540
4536
  }
4541
4537
  });
@@ -4551,7 +4547,7 @@ var level2_heading_style_default = createRule("level2-heading-style", {
4551
4547
  type: "layout",
4552
4548
  docs: {
4553
4549
  description: "enforce consistent style for level 2 headings",
4554
- categories: [],
4550
+ categories: ["standard"],
4555
4551
  listCategory: "Stylistic"
4556
4552
  },
4557
4553
  fixable: "code",
@@ -4582,8 +4578,7 @@ var level2_heading_style_default = createRule("level2-heading-style", {
4582
4578
  if (headingKind !== "setext") return;
4583
4579
  const parsed = parseSetextHeading(sourceCode, node);
4584
4580
  if (!parsed) return;
4585
- const isMultiline = parsed.contentLines.length > 1;
4586
- if (isMultiline) {
4581
+ if (parsed.contentLines.length > 1) {
4587
4582
  if (allowMultilineSetext) return;
4588
4583
  context.report({
4589
4584
  node,
@@ -4613,8 +4608,7 @@ var level2_heading_style_default = createRule("level2-heading-style", {
4613
4608
  if (parsed.closingSequence) yield fixer.removeRange([parsed.closingSequence.raws.spaceBefore.range[0], parsed.closingSequence.raws.spaceAfter.range[1]]);
4614
4609
  const lines = getParsedLines(sourceCode);
4615
4610
  const underline = "-".repeat(Math.max(getTextWidth(parsed.content.text), 3));
4616
- const prefix = lines.get(parsed.openingSequence.loc.start.line).text.slice(0, parsed.openingSequence.loc.start.column - 1);
4617
- const appendingText = `\n${prefix}${underline}`;
4611
+ const appendingText = `\n${lines.get(parsed.openingSequence.loc.start.line).text.slice(0, parsed.openingSequence.loc.start.column - 1)}${underline}`;
4618
4612
  yield fixer.insertTextAfter(node, appendingText);
4619
4613
  }
4620
4614
  });
@@ -4624,93 +4618,1197 @@ var level2_heading_style_default = createRule("level2-heading-style", {
4624
4618
  });
4625
4619
 
4626
4620
  //#endregion
4627
- //#region src/rules/list-marker-alignment.ts
4628
- const ALIGN_TO_POSITION_NAME = {
4629
- left: "start",
4630
- right: "end"
4631
- };
4632
- var list_marker_alignment_default = createRule("list-marker-alignment", {
4621
+ //#region src/utils/link.ts
4622
+ /**
4623
+ * Parse the inline link.
4624
+ */
4625
+ function parseInlineLink(sourceCode, node) {
4626
+ if (getLinkKind(sourceCode, node) !== "inline") return null;
4627
+ const nodeRange = sourceCode.getRange(node);
4628
+ let textRange;
4629
+ if (node.children.length === 0) textRange = [nodeRange[0], sourceCode.text.indexOf("]", nodeRange[0]) + 1];
4630
+ else {
4631
+ const lastChildRange = sourceCode.getRange(node.children[node.children.length - 1]);
4632
+ textRange = [nodeRange[0], sourceCode.text.indexOf("]", lastChildRange[1]) + 1];
4633
+ }
4634
+ const parsed = parseInlineLinkDestAndTitleFromText(sourceCode.text.slice(textRange[1], nodeRange[1]));
4635
+ if (!parsed) return null;
4636
+ const destinationRange = [textRange[1] + parsed.destination.range[0], textRange[1] + parsed.destination.range[1]];
4637
+ return {
4638
+ text: {
4639
+ range: textRange,
4640
+ loc: getSourceLocationFromRange(sourceCode, node, textRange)
4641
+ },
4642
+ destination: {
4643
+ type: parsed.destination.type,
4644
+ text: parsed.destination.text,
4645
+ range: destinationRange,
4646
+ loc: getSourceLocationFromRange(sourceCode, node, destinationRange)
4647
+ },
4648
+ title: parsed.title ? {
4649
+ type: parsed.title.type,
4650
+ text: parsed.title.text,
4651
+ range: [textRange[1] + parsed.title.range[0], textRange[1] + parsed.title.range[1]],
4652
+ loc: getSourceLocationFromRange(sourceCode, node, [textRange[1] + parsed.title.range[0], textRange[1] + parsed.title.range[1]])
4653
+ } : null
4654
+ };
4655
+ }
4656
+ /**
4657
+ * Parse the inline link destination and link title from the given text.
4658
+ */
4659
+ function parseInlineLinkDestAndTitleFromText(text) {
4660
+ let index = 0;
4661
+ if (text[index] !== "(") return null;
4662
+ index++;
4663
+ skipSpaces();
4664
+ let destination;
4665
+ const destinationStartIndex = index;
4666
+ if (text[index] === "<") {
4667
+ index++;
4668
+ if (!skipUntilEnd((c) => c === ">")) return null;
4669
+ index++;
4670
+ const destinationRange = [destinationStartIndex, index];
4671
+ destination = {
4672
+ type: "pointy-bracketed",
4673
+ text: text.slice(...destinationRange),
4674
+ range: destinationRange
4675
+ };
4676
+ } else {
4677
+ if (text.length <= index) return null;
4678
+ skipUntilEnd((c) => isWhitespace(c) || isAsciiControlCharacter(c) || c === ")");
4679
+ const destinationRange = [destinationStartIndex, index];
4680
+ destination = {
4681
+ type: "bare",
4682
+ text: text.slice(...destinationRange),
4683
+ range: destinationRange
4684
+ };
4685
+ }
4686
+ skipSpaces();
4687
+ if (text[index] === ")") {
4688
+ index++;
4689
+ skipSpaces();
4690
+ if (index < text.length) return null;
4691
+ return {
4692
+ destination,
4693
+ title: null
4694
+ };
4695
+ }
4696
+ if (text.length <= index) return null;
4697
+ let title;
4698
+ const titleStartIndex = index;
4699
+ const startChar = text[index];
4700
+ if (startChar === "'" || startChar === "\"" || startChar === "(") {
4701
+ index++;
4702
+ const endChar = startChar === "(" ? ")" : startChar;
4703
+ if (!skipUntilEnd((c) => c === endChar)) return null;
4704
+ index++;
4705
+ const titleRange = [titleStartIndex, index];
4706
+ title = {
4707
+ type: startChar === "'" ? "single-quoted" : startChar === "\"" ? "double-quoted" : "parenthesized",
4708
+ text: text.slice(...titleRange),
4709
+ range: titleRange
4710
+ };
4711
+ } else return null;
4712
+ skipSpaces();
4713
+ if (text[index] !== ")") return null;
4714
+ index++;
4715
+ skipSpaces();
4716
+ if (index < text.length) return null;
4717
+ return {
4718
+ destination,
4719
+ title
4720
+ };
4721
+ /**
4722
+ * Skip spaces
4723
+ */
4724
+ function skipSpaces() {
4725
+ while (index < text.length && isWhitespace(text[index])) index++;
4726
+ }
4727
+ /**
4728
+ * Skip until the end by the given condition
4729
+ */
4730
+ function skipUntilEnd(checkEnd) {
4731
+ while (index < text.length) {
4732
+ const c = text[index];
4733
+ if (checkEnd(c)) return true;
4734
+ index++;
4735
+ if (c !== "\\") continue;
4736
+ if (index < text.length && (text[index] === "\\" || checkEnd(text[index])) && !isWhitespace(text[index])) index++;
4737
+ }
4738
+ return false;
4739
+ }
4740
+ }
4741
+
4742
+ //#endregion
4743
+ //#region src/utils/link-reference.ts
4744
+ /**
4745
+ * Parse the link reference.
4746
+ */
4747
+ function parseLinkReference(sourceCode, node) {
4748
+ const nodeRange = sourceCode.getRange(node);
4749
+ let textRange;
4750
+ if (node.children.length === 0) textRange = [nodeRange[0], sourceCode.text.indexOf("]", nodeRange[0]) + 1];
4751
+ else {
4752
+ const lastChildRange = sourceCode.getRange(node.children[node.children.length - 1]);
4753
+ textRange = [nodeRange[0], sourceCode.text.indexOf("]", lastChildRange[1]) + 1];
4754
+ }
4755
+ if (node.referenceType === "shortcut") return {
4756
+ text: {
4757
+ range: textRange,
4758
+ loc: getSourceLocationFromRange(sourceCode, node, textRange)
4759
+ },
4760
+ label: null
4761
+ };
4762
+ if (node.referenceType === "collapsed") {
4763
+ const labelRange$1 = [textRange[1], textRange[1] + 1];
4764
+ return {
4765
+ text: {
4766
+ range: textRange,
4767
+ loc: getSourceLocationFromRange(sourceCode, node, textRange)
4768
+ },
4769
+ label: {
4770
+ type: "collapsed",
4771
+ range: labelRange$1,
4772
+ loc: getSourceLocationFromRange(sourceCode, node, labelRange$1)
4773
+ }
4774
+ };
4775
+ }
4776
+ let index = textRange[1] + 1;
4777
+ while (index < sourceCode.text.length) {
4778
+ const c = sourceCode.text[index];
4779
+ if (c === "]") break;
4780
+ index++;
4781
+ if (c !== "\\") continue;
4782
+ if (index < sourceCode.text.length && (sourceCode.text[index] === "\\" || sourceCode.text[index] === "]")) index++;
4783
+ }
4784
+ if (sourceCode.text[index] !== "]") return null;
4785
+ const labelRange = [textRange[1], index + 1];
4786
+ return {
4787
+ text: {
4788
+ range: textRange,
4789
+ loc: getSourceLocationFromRange(sourceCode, node, textRange)
4790
+ },
4791
+ label: {
4792
+ type: "full",
4793
+ text: sourceCode.text.slice(...labelRange),
4794
+ range: labelRange,
4795
+ loc: getSourceLocationFromRange(sourceCode, node, labelRange)
4796
+ }
4797
+ };
4798
+ }
4799
+
4800
+ //#endregion
4801
+ //#region src/utils/image.ts
4802
+ /**
4803
+ * Parse the image.
4804
+ */
4805
+ function parseImage(sourceCode, node) {
4806
+ const text = sourceCode.getText(node);
4807
+ const parsed = parseImageFromText(text);
4808
+ if (!parsed) return null;
4809
+ const nodeRange = sourceCode.getRange(node);
4810
+ const textRange = [nodeRange[0] + parsed.text.range[0], nodeRange[0] + parsed.text.range[1]];
4811
+ const destinationRange = [nodeRange[0] + parsed.destination.range[0], nodeRange[0] + parsed.destination.range[1]];
4812
+ return {
4813
+ text: {
4814
+ range: textRange,
4815
+ loc: getSourceLocationFromRange(sourceCode, node, textRange)
4816
+ },
4817
+ destination: {
4818
+ type: parsed.destination.type,
4819
+ text: parsed.destination.text,
4820
+ range: destinationRange,
4821
+ loc: getSourceLocationFromRange(sourceCode, node, destinationRange)
4822
+ },
4823
+ title: parsed.title ? {
4824
+ type: parsed.title.type,
4825
+ text: parsed.title.text,
4826
+ range: [nodeRange[0] + parsed.title.range[0], nodeRange[0] + parsed.title.range[1]],
4827
+ loc: getSourceLocationFromRange(sourceCode, node, [nodeRange[0] + parsed.title.range[0], nodeRange[0] + parsed.title.range[1]])
4828
+ } : null
4829
+ };
4830
+ }
4831
+ /**
4832
+ * Parse the image from the given text.
4833
+ */
4834
+ function parseImageFromText(text) {
4835
+ if (!text.startsWith("![")) return null;
4836
+ let index = text.length - 1;
4837
+ skipSpaces();
4838
+ if (text[index] !== ")") return null;
4839
+ index--;
4840
+ skipSpaces();
4841
+ let title = null;
4842
+ const titleEndIndex = index + 1;
4843
+ const endChar = text[index];
4844
+ if (endChar === "'" || endChar === "\"" || endChar === ")") {
4845
+ index--;
4846
+ const startChar = endChar === ")" ? "(" : endChar;
4847
+ if (skipUntilStart((c) => c === startChar)) {
4848
+ const titleRange = [index, titleEndIndex];
4849
+ index--;
4850
+ title = {
4851
+ type: startChar === "'" ? "single-quoted" : startChar === "\"" ? "double-quoted" : "parenthesized",
4852
+ text: text.slice(...titleRange),
4853
+ range: titleRange
4854
+ };
4855
+ skipSpaces();
4856
+ }
4857
+ }
4858
+ if (title == null) index = titleEndIndex - 1;
4859
+ let destination;
4860
+ const destinationEndIndex = index + 1;
4861
+ if (text[index] === ">") {
4862
+ index--;
4863
+ if (!skipUntilStart((c) => c === "<")) return null;
4864
+ const destinationRange = [index, destinationEndIndex];
4865
+ index--;
4866
+ destination = {
4867
+ type: "pointy-bracketed",
4868
+ text: text.slice(...destinationRange),
4869
+ range: destinationRange
4870
+ };
4871
+ } else {
4872
+ if (text.length <= index) return null;
4873
+ skipUntilStart((c) => isWhitespace(c) || isAsciiControlCharacter(c) || c === "(");
4874
+ const destinationRange = [index + 1, destinationEndIndex];
4875
+ destination = {
4876
+ type: "bare",
4877
+ text: text.slice(...destinationRange),
4878
+ range: destinationRange
4879
+ };
4880
+ }
4881
+ skipSpaces();
4882
+ if (text[index] !== "(") return null;
4883
+ index--;
4884
+ if (text[index] !== "]") return null;
4885
+ return {
4886
+ text: { range: [1, index + 1] },
4887
+ destination,
4888
+ title
4889
+ };
4890
+ /**
4891
+ * Skip spaces
4892
+ */
4893
+ function skipSpaces() {
4894
+ while (index >= 0 && isWhitespace(text[index])) index--;
4895
+ }
4896
+ /**
4897
+ * Skip until the start by the given condition
4898
+ */
4899
+ function skipUntilStart(checkStart) {
4900
+ while (index >= 0) {
4901
+ const c = text[index];
4902
+ if (checkStart(c)) {
4903
+ if (index > 1 && !isWhitespace(c)) {
4904
+ let escapeText = "";
4905
+ while (text.endsWith(`${escapeText}\\`, index)) escapeText += "\\";
4906
+ if (escapeText.length % 2 === 1) {
4907
+ index -= escapeText.length + 1;
4908
+ continue;
4909
+ }
4910
+ }
4911
+ return true;
4912
+ }
4913
+ index--;
4914
+ }
4915
+ return false;
4916
+ }
4917
+ }
4918
+
4919
+ //#endregion
4920
+ //#region src/utils/image-reference.ts
4921
+ /**
4922
+ * Parse the image reference.
4923
+ */
4924
+ function parseImageReference(sourceCode, node) {
4925
+ const nodeRange = sourceCode.getRange(node);
4926
+ if (node.referenceType === "shortcut") {
4927
+ const textRange$1 = [nodeRange[0] + 1, nodeRange[1]];
4928
+ return {
4929
+ text: {
4930
+ range: textRange$1,
4931
+ text: sourceCode.text.slice(...textRange$1),
4932
+ loc: getSourceLocationFromRange(sourceCode, node, textRange$1)
4933
+ },
4934
+ label: null
4935
+ };
4936
+ }
4937
+ if (node.referenceType === "collapsed") {
4938
+ const textRange$1 = [nodeRange[0] + 1, nodeRange[1] - 2];
4939
+ const labelRange$1 = [textRange$1[1], nodeRange[1]];
4940
+ return {
4941
+ text: {
4942
+ range: textRange$1,
4943
+ text: sourceCode.text.slice(...textRange$1),
4944
+ loc: getSourceLocationFromRange(sourceCode, node, textRange$1)
4945
+ },
4946
+ label: {
4947
+ type: "collapsed",
4948
+ range: labelRange$1,
4949
+ loc: getSourceLocationFromRange(sourceCode, node, labelRange$1)
4950
+ }
4951
+ };
4952
+ }
4953
+ const parsed = parseFullImageReferenceFromText(sourceCode.getText(node));
4954
+ if (!parsed) return null;
4955
+ const textRange = [nodeRange[0] + parsed.text.range[0], nodeRange[0] + parsed.text.range[1]];
4956
+ const labelRange = [nodeRange[0] + parsed.label.range[0], nodeRange[0] + parsed.label.range[1]];
4957
+ return {
4958
+ text: {
4959
+ range: textRange,
4960
+ text: parsed.text.text,
4961
+ loc: getSourceLocationFromRange(sourceCode, node, textRange)
4962
+ },
4963
+ label: {
4964
+ type: "full",
4965
+ text: parsed.label.text,
4966
+ range: labelRange,
4967
+ loc: getSourceLocationFromRange(sourceCode, node, labelRange)
4968
+ }
4969
+ };
4970
+ }
4971
+ /**
4972
+ * Parse the full image reference from the given text.
4973
+ */
4974
+ function parseFullImageReferenceFromText(text) {
4975
+ if (!text.startsWith("![")) return null;
4976
+ let index = text.length - 1;
4977
+ skipSpaces();
4978
+ if (text[index] !== "]") return null;
4979
+ const labelEndIndex = index + 1;
4980
+ index--;
4981
+ skipSpaces();
4982
+ if (!skipUntilStart((c) => c === "[")) return null;
4983
+ const labelRange = [index, labelEndIndex];
4984
+ index--;
4985
+ const label = {
4986
+ text: text.slice(...labelRange),
4987
+ range: labelRange
4988
+ };
4989
+ if (text[index] !== "]") return null;
4990
+ const textRange = [1, index + 1];
4991
+ return {
4992
+ text: {
4993
+ text: text.slice(...textRange),
4994
+ range: textRange
4995
+ },
4996
+ label
4997
+ };
4998
+ /**
4999
+ * Skip spaces
5000
+ */
5001
+ function skipSpaces() {
5002
+ while (index >= 0 && isWhitespace(text[index])) index--;
5003
+ }
5004
+ /**
5005
+ * Skip until the start by the given condition
5006
+ */
5007
+ function skipUntilStart(checkStart) {
5008
+ while (index >= 0) {
5009
+ const c = text[index];
5010
+ if (checkStart(c)) {
5011
+ if (index > 1) {
5012
+ let escapeText = "";
5013
+ while (text.endsWith(`${escapeText}\\`, index)) escapeText += "\\";
5014
+ if (escapeText.length % 2 === 1) {
5015
+ index -= escapeText.length + 1;
5016
+ continue;
5017
+ }
5018
+ }
5019
+ return true;
5020
+ }
5021
+ index--;
5022
+ }
5023
+ return false;
5024
+ }
5025
+ }
5026
+
5027
+ //#endregion
5028
+ //#region src/utils/link-definition.ts
5029
+ /**
5030
+ * Parse the link definition.
5031
+ */
5032
+ function parseLinkDefinition(sourceCode, node) {
5033
+ const text = sourceCode.getText(node);
5034
+ const parsed = parseLinkDefinitionFromText(text);
5035
+ if (!parsed) return null;
5036
+ const nodeRange = sourceCode.getRange(node);
5037
+ const labelRange = [nodeRange[0] + parsed.label.range[0], nodeRange[0] + parsed.label.range[1]];
5038
+ const destinationRange = [nodeRange[0] + parsed.destination.range[0], nodeRange[0] + parsed.destination.range[1]];
5039
+ return {
5040
+ label: {
5041
+ text: parsed.label.text,
5042
+ range: labelRange,
5043
+ loc: getSourceLocationFromRange(sourceCode, node, labelRange)
5044
+ },
5045
+ destination: {
5046
+ type: parsed.destination.type,
5047
+ text: parsed.destination.text,
5048
+ range: destinationRange,
5049
+ loc: getSourceLocationFromRange(sourceCode, node, destinationRange)
5050
+ },
5051
+ title: parsed.title ? {
5052
+ type: parsed.title.type,
5053
+ text: parsed.title.text,
5054
+ range: [nodeRange[0] + parsed.title.range[0], nodeRange[0] + parsed.title.range[1]],
5055
+ loc: getSourceLocationFromRange(sourceCode, node, [nodeRange[0] + parsed.title.range[0], nodeRange[0] + parsed.title.range[1]])
5056
+ } : null
5057
+ };
5058
+ }
5059
+ /**
5060
+ * Parse the link definition from the given text.
5061
+ */
5062
+ function parseLinkDefinitionFromText(text) {
5063
+ let index = 0;
5064
+ if (text[index] !== "[") return null;
5065
+ const labelStartIndex = index;
5066
+ index++;
5067
+ if (!skipUntilEnd((c) => c === "]")) return null;
5068
+ index++;
5069
+ const labelRange = [labelStartIndex, index];
5070
+ if (!text.slice(labelRange[0] + 1, labelRange[1] - 1).trim()) return null;
5071
+ if (text[index] !== ":") return null;
5072
+ const label = {
5073
+ text: text.slice(...labelRange),
5074
+ range: labelRange
5075
+ };
5076
+ index++;
5077
+ skipSpaces();
5078
+ let destination;
5079
+ const destinationStartIndex = index;
5080
+ if (text[index] === "<") {
5081
+ index++;
5082
+ if (!skipUntilEnd((c) => c === ">")) return null;
5083
+ index++;
5084
+ const destinationRange = [destinationStartIndex, index];
5085
+ destination = {
5086
+ type: "pointy-bracketed",
5087
+ text: text.slice(...destinationRange),
5088
+ range: destinationRange
5089
+ };
5090
+ } else {
5091
+ if (text.length <= index) return null;
5092
+ skipUntilEnd((c) => isWhitespace(c) || isAsciiControlCharacter(c));
5093
+ const destinationRange = [destinationStartIndex, index];
5094
+ destination = {
5095
+ type: "bare",
5096
+ text: text.slice(...destinationRange),
5097
+ range: destinationRange
5098
+ };
5099
+ }
5100
+ skipSpaces();
5101
+ if (text.length <= index) return {
5102
+ label,
5103
+ destination,
5104
+ title: null
5105
+ };
5106
+ let title;
5107
+ const titleStartIndex = index;
5108
+ const startChar = text[index];
5109
+ if (startChar === "'" || startChar === "\"" || startChar === "(") {
5110
+ index++;
5111
+ const endChar = startChar === "(" ? ")" : startChar;
5112
+ if (!skipUntilEnd((c) => c === endChar)) return null;
5113
+ index++;
5114
+ const titleRange = [titleStartIndex, index];
5115
+ title = {
5116
+ type: startChar === "'" ? "single-quoted" : startChar === "\"" ? "double-quoted" : "parenthesized",
5117
+ text: text.slice(...titleRange),
5118
+ range: titleRange
5119
+ };
5120
+ } else return null;
5121
+ skipSpaces();
5122
+ if (index < text.length) return null;
5123
+ return {
5124
+ label,
5125
+ destination,
5126
+ title
5127
+ };
5128
+ /**
5129
+ * Skip spaces
5130
+ */
5131
+ function skipSpaces() {
5132
+ while (index < text.length && isWhitespace(text[index])) index++;
5133
+ }
5134
+ /**
5135
+ * Skip until the end by the given condition
5136
+ */
5137
+ function skipUntilEnd(checkEnd) {
5138
+ while (index < text.length) {
5139
+ const c = text[index];
5140
+ if (checkEnd(c)) return true;
5141
+ index++;
5142
+ if (c !== "\\") continue;
5143
+ if (index < text.length && (text[index] === "\\" || checkEnd(text[index])) && !isWhitespace(text[index])) index++;
5144
+ }
5145
+ return false;
5146
+ }
5147
+ }
5148
+
5149
+ //#endregion
5150
+ //#region src/rules/link-bracket-newline.ts
5151
+ var link_bracket_newline_default = createRule("link-bracket-newline", {
4633
5152
  meta: {
4634
5153
  type: "layout",
4635
5154
  docs: {
4636
- description: "enforce consistent alignment of list markers",
4637
- categories: ["recommended"],
5155
+ description: "enforce linebreaks after opening and before closing link brackets",
5156
+ categories: ["standard"],
4638
5157
  listCategory: "Stylistic"
4639
5158
  },
4640
5159
  fixable: "whitespace",
4641
5160
  hasSuggestions: false,
4642
5161
  schema: [{
4643
5162
  type: "object",
4644
- properties: { align: { enum: ["left", "right"] } },
5163
+ properties: {
5164
+ newline: { enum: [
5165
+ "always",
5166
+ "never",
5167
+ "consistent"
5168
+ ] },
5169
+ multiline: { type: "boolean" }
5170
+ },
4645
5171
  additionalProperties: false
4646
5172
  }],
4647
- messages: { incorrectAlignment: "List marker alignment is inconsistent. Expected {{expected}} characters of indentation, but got {{actual}}." }
5173
+ messages: {
5174
+ expectedNewlineAfterOpeningBracket: "Expected a linebreak after this opening bracket.",
5175
+ unexpectedNewlineAfterOpeningBracket: "Unexpected linebreak after this opening bracket.",
5176
+ expectedNewlineBeforeClosingBracket: "Expected a linebreak before this closing bracket.",
5177
+ unexpectedNewlineBeforeClosingBracket: "Unexpected linebreak before this closing bracket."
5178
+ }
4648
5179
  },
4649
5180
  create(context) {
4650
5181
  const sourceCode = context.sourceCode;
4651
- const alignPositionName = ALIGN_TO_POSITION_NAME[context.options[0]?.align ?? "left"];
5182
+ const optionProvider = parseOptions$3(context.options[0]);
4652
5183
  /**
4653
- * Get the marker location of a list item
5184
+ * Parse the options.
4654
5185
  */
4655
- function getMarkerLocation(node) {
4656
- const start = sourceCode.getLoc(node).start;
4657
- const startColumnIndex = start.column - 1;
4658
- const marker = getListItemMarker(sourceCode, node);
4659
- return {
4660
- line: start.line,
4661
- start: startColumnIndex,
4662
- end: startColumnIndex + marker.raw.length
5186
+ function parseOptions$3(option) {
5187
+ const newline = option?.newline ?? "never";
5188
+ const multiline = option?.multiline ?? false;
5189
+ return (bracketsRange) => {
5190
+ if (multiline) {
5191
+ if (sourceCode.text.slice(bracketsRange[0] + 1, bracketsRange[1] - 1).trim().includes("\n")) return "always";
5192
+ }
5193
+ return newline;
4663
5194
  };
4664
5195
  }
4665
5196
  /**
4666
- * Check if list items have consistent alignment
5197
+ * Verify the newline around the brackets.
4667
5198
  */
4668
- function checkListAlignment(listNode) {
4669
- const items = listNode.children;
4670
- if (items.length <= 1) return;
4671
- const referenceMarkerLocation = getMarkerLocation(items[0]);
4672
- for (const item of items.slice(1)) {
4673
- const markerLocation = getMarkerLocation(item);
4674
- const diff = markerLocation[alignPositionName] - referenceMarkerLocation[alignPositionName];
4675
- if (diff === 0) continue;
5199
+ function verifyNewlineAroundBrackets(node, bracketsRange) {
5200
+ const newline = optionProvider(bracketsRange);
5201
+ const openingBracketIndex = bracketsRange[0];
5202
+ const spaceAfterOpeningBracket = getSpaceAfterOpeningBracket(openingBracketIndex);
5203
+ verifyNewlineAfterOpeningBracket(node, spaceAfterOpeningBracket, openingBracketIndex, newline);
5204
+ const closingBracketIndex = bracketsRange[1] - 1;
5205
+ const newlineOptionBeforeClosingBracket = newline === "consistent" ? getSpaceAfterOpeningBracket(bracketsRange[0]).includes("\n") ? "always" : "never" : newline;
5206
+ verifyNewlineBeforeClosingBracket(node, getSpaceBeforeClosingBracket(closingBracketIndex), openingBracketIndex, closingBracketIndex, newlineOptionBeforeClosingBracket);
5207
+ }
5208
+ /**
5209
+ * Verify the newline after the opening bracket and before the closing bracket.
5210
+ */
5211
+ function verifyNewlineAfterOpeningBracket(node, spaceAfterOpeningBracket, openingBracketIndex, newline) {
5212
+ if (newline === "always") {
5213
+ if (spaceAfterOpeningBracket.includes("\n")) return;
5214
+ const loc = getSourceLocationFromRange(sourceCode, node, [openingBracketIndex, openingBracketIndex + 1]);
4676
5215
  context.report({
4677
- node: item,
4678
- loc: {
4679
- start: {
4680
- line: markerLocation.line,
4681
- column: markerLocation.start + 1
4682
- },
4683
- end: {
4684
- line: markerLocation.line,
4685
- column: markerLocation.end + 1
4686
- }
4687
- },
4688
- messageId: "incorrectAlignment",
4689
- data: {
4690
- expected: String(markerLocation.start - diff),
4691
- actual: String(markerLocation.start)
4692
- },
4693
- fix(fixer) {
4694
- const lines = getParsedLines(sourceCode);
4695
- const line = lines.get(markerLocation.line);
4696
- if (diff < 0) {
4697
- const addSpaces = " ".repeat(-diff);
4698
- return fixer.insertTextBeforeRange([line.range[0] + markerLocation.start, line.range[0] + markerLocation.start], addSpaces);
4699
- }
4700
- const itemBefore = line.text.slice(0, markerLocation.start - diff);
4701
- if (itemBefore.includes(" ")) return null;
4702
- const referenceMarkerBefore = lines.get(referenceMarkerLocation.line).text.slice(0, referenceMarkerLocation.start);
4703
- if (referenceMarkerBefore === itemBefore) {
4704
- const removeEndIndex = line.range[0] + markerLocation.start;
4705
- const removeStartIndex = removeEndIndex - diff;
4706
- return fixer.removeRange([removeStartIndex, removeEndIndex]);
4707
- }
4708
- return null;
5216
+ node,
5217
+ loc,
5218
+ messageId: "expectedNewlineAfterOpeningBracket",
5219
+ fix: (fixer) => fixer.insertTextAfterRange([openingBracketIndex, openingBracketIndex + 1], `\n${" ".repeat(loc.start.column)}${spaceAfterOpeningBracket}`)
5220
+ });
5221
+ } else if (newline === "never") {
5222
+ if (!spaceAfterOpeningBracket.includes("\n")) return;
5223
+ context.report({
5224
+ node,
5225
+ loc: getSourceLocationFromRange(sourceCode, node, [openingBracketIndex + 1, openingBracketIndex + 1 + spaceAfterOpeningBracket.length]),
5226
+ messageId: "unexpectedNewlineAfterOpeningBracket",
5227
+ fix: (fixer) => fixer.replaceTextRange([openingBracketIndex + 1, openingBracketIndex + 1 + spaceAfterOpeningBracket.length], " ")
5228
+ });
5229
+ }
5230
+ }
5231
+ /**
5232
+ * Verify the newline before the closing bracket.
5233
+ */
5234
+ function verifyNewlineBeforeClosingBracket(node, spaceBeforeClosingBracket, openingBracketIndex, closingBracketIndex, newline) {
5235
+ if (openingBracketIndex + 1 === closingBracketIndex - spaceBeforeClosingBracket.length) return;
5236
+ if (newline === "always") {
5237
+ if (spaceBeforeClosingBracket.includes("\n")) return;
5238
+ context.report({
5239
+ node,
5240
+ loc: getSourceLocationFromRange(sourceCode, node, [closingBracketIndex, closingBracketIndex + 1]),
5241
+ messageId: "expectedNewlineBeforeClosingBracket",
5242
+ fix: (fixer) => {
5243
+ const openingBracketLoc = getSourceLocationFromRange(sourceCode, node, [openingBracketIndex, openingBracketIndex + 1]);
5244
+ return fixer.insertTextBeforeRange([closingBracketIndex, closingBracketIndex + 1], `\n${" ".repeat(openingBracketLoc.start.column)}`);
4709
5245
  }
4710
5246
  });
5247
+ } else if (newline === "never") {
5248
+ if (!spaceBeforeClosingBracket.includes("\n")) return;
5249
+ context.report({
5250
+ node,
5251
+ loc: getSourceLocationFromRange(sourceCode, node, [closingBracketIndex - spaceBeforeClosingBracket.length, closingBracketIndex]),
5252
+ messageId: "unexpectedNewlineBeforeClosingBracket",
5253
+ fix: (fixer) => fixer.replaceTextRange([closingBracketIndex - spaceBeforeClosingBracket.length, closingBracketIndex], " ")
5254
+ });
4711
5255
  }
4712
5256
  }
4713
- return { list: checkListAlignment };
5257
+ return {
5258
+ link(node) {
5259
+ if (getLinkKind(sourceCode, node) !== "inline") return;
5260
+ const parsed = parseInlineLink(sourceCode, node);
5261
+ if (!parsed) return;
5262
+ verifyNewlineAroundBrackets(node, parsed.text.range);
5263
+ },
5264
+ linkReference(node) {
5265
+ const parsed = parseLinkReference(sourceCode, node);
5266
+ if (!parsed) return;
5267
+ verifyNewlineAroundBrackets(node, parsed.text.range);
5268
+ if (parsed.label?.type === "full") verifyNewlineAroundBrackets(node, parsed.label.range);
5269
+ },
5270
+ image(node) {
5271
+ const parsed = parseImage(sourceCode, node);
5272
+ if (!parsed) return;
5273
+ verifyNewlineAroundBrackets(node, parsed.text.range);
5274
+ },
5275
+ imageReference(node) {
5276
+ const parsed = parseImageReference(sourceCode, node);
5277
+ if (!parsed) return;
5278
+ verifyNewlineAroundBrackets(node, parsed.text.range);
5279
+ if (parsed.label?.type === "full") verifyNewlineAroundBrackets(node, parsed.label.range);
5280
+ },
5281
+ definition(node) {
5282
+ const parsed = parseLinkDefinition(sourceCode, node);
5283
+ if (!parsed) return;
5284
+ verifyNewlineAroundBrackets(node, parsed.label.range);
5285
+ }
5286
+ };
5287
+ /**
5288
+ * Get the spaces after the opening bracket.
5289
+ */
5290
+ function getSpaceAfterOpeningBracket(openingBracketIndex) {
5291
+ for (let i = openingBracketIndex + 1; i < sourceCode.text.length; i++) {
5292
+ const char = sourceCode.text[i];
5293
+ if (isWhitespace(char)) continue;
5294
+ return sourceCode.text.slice(openingBracketIndex + 1, i);
5295
+ }
5296
+ return sourceCode.text.slice(openingBracketIndex + 1);
5297
+ }
5298
+ /**
5299
+ * Get the spaces before the closing bracket.
5300
+ */
5301
+ function getSpaceBeforeClosingBracket(closingBracketIndex) {
5302
+ for (let i = closingBracketIndex - 1; i >= 0; i--) {
5303
+ const char = sourceCode.text[i];
5304
+ if (isWhitespace(char)) continue;
5305
+ return sourceCode.text.slice(i + 1, closingBracketIndex);
5306
+ }
5307
+ return sourceCode.text.slice(0, closingBracketIndex);
5308
+ }
5309
+ }
5310
+ });
5311
+
5312
+ //#endregion
5313
+ //#region src/rules/link-bracket-spacing.ts
5314
+ /**
5315
+ * The basic option for links and images.
5316
+ */
5317
+ function parseOptions$1(option) {
5318
+ const space = option?.space ?? "never";
5319
+ const imagesInLinks = option?.imagesInLinks;
5320
+ return {
5321
+ space,
5322
+ spaceForText: getOptionForText
5323
+ };
5324
+ /**
5325
+ * Get the spacing option for the given node.
5326
+ */
5327
+ function getOptionForText(node) {
5328
+ if (imagesInLinks != null) {
5329
+ const children = [...node.children];
5330
+ let child;
5331
+ while (children.length && (child = children[0]) && child.type === "text" && isWhitespace(child.value)) children.shift();
5332
+ while (children.length && (child = children[children.length - 1]) && child.type === "text" && isWhitespace(child.value)) children.pop();
5333
+ const loneChild = children.length === 1 ? children[0] : null;
5334
+ if (loneChild?.type === "image" || loneChild?.type === "imageReference") return imagesInLinks ? "always" : "never";
5335
+ }
5336
+ if (node.children.length === 0 || node.children.length === 1 && node.children[0]?.type === "text" && isWhitespace(node.children[0].value)) return "ignore";
5337
+ return space;
5338
+ }
5339
+ }
5340
+ var link_bracket_spacing_default = createRule("link-bracket-spacing", {
5341
+ meta: {
5342
+ type: "layout",
5343
+ docs: {
5344
+ description: "enforce consistent spacing inside link brackets",
5345
+ categories: ["standard"],
5346
+ listCategory: "Stylistic"
5347
+ },
5348
+ fixable: "whitespace",
5349
+ hasSuggestions: false,
5350
+ schema: [{
5351
+ type: "object",
5352
+ properties: {
5353
+ space: { enum: ["always", "never"] },
5354
+ imagesInLinks: { type: "boolean" }
5355
+ },
5356
+ additionalProperties: false
5357
+ }],
5358
+ messages: {
5359
+ unexpectedSpaceAfterOpeningBracket: "Unexpected space after opening bracket.",
5360
+ expectedSpaceAfterOpeningBracket: "Expected space after opening bracket.",
5361
+ unexpectedSpaceBeforeClosingBracket: "Unexpected space before closing bracket.",
5362
+ expectedSpaceBeforeClosingBracket: "Expected space before closing bracket."
5363
+ }
5364
+ },
5365
+ create(context) {
5366
+ const sourceCode = context.sourceCode;
5367
+ const options = parseOptions$1(context.options[0]);
5368
+ /**
5369
+ * Verify the space after the opening bracket and before the closing bracket.
5370
+ */
5371
+ function verifySpaceAfterOpeningBracket(node, openingBracketIndex, spaceOption) {
5372
+ const space = getSpaceAfterOpeningBracket(openingBracketIndex);
5373
+ if (space.includes("\n")) return;
5374
+ if (spaceOption === "always") {
5375
+ if (space.length > 0) return;
5376
+ context.report({
5377
+ node,
5378
+ loc: getSourceLocationFromRange(sourceCode, node, [openingBracketIndex, openingBracketIndex + 1]),
5379
+ messageId: "expectedSpaceAfterOpeningBracket",
5380
+ fix: (fixer) => fixer.insertTextAfterRange([openingBracketIndex, openingBracketIndex + 1], " ")
5381
+ });
5382
+ } else if (spaceOption === "never") {
5383
+ if (space.length === 0) return;
5384
+ context.report({
5385
+ node,
5386
+ loc: getSourceLocationFromRange(sourceCode, node, [openingBracketIndex + 1, openingBracketIndex + 1 + space.length]),
5387
+ messageId: "unexpectedSpaceAfterOpeningBracket",
5388
+ fix: (fixer) => fixer.removeRange([openingBracketIndex + 1, openingBracketIndex + 1 + space.length])
5389
+ });
5390
+ }
5391
+ }
5392
+ /**
5393
+ * Verify the space before the closing bracket.
5394
+ */
5395
+ function verifySpaceBeforeClosingBracket(node, openingBracketIndex, closingBracketIndex, spaceOption) {
5396
+ const space = getSpaceBeforeClosingBracket(closingBracketIndex);
5397
+ if (openingBracketIndex + 1 === closingBracketIndex - space.length) return;
5398
+ if (space.includes("\n")) return;
5399
+ if (spaceOption === "always") {
5400
+ if (space.length > 0) return;
5401
+ context.report({
5402
+ node,
5403
+ loc: getSourceLocationFromRange(sourceCode, node, [closingBracketIndex, closingBracketIndex + 1]),
5404
+ messageId: "expectedSpaceBeforeClosingBracket",
5405
+ fix: (fixer) => fixer.insertTextBeforeRange([closingBracketIndex, closingBracketIndex + 1], " ")
5406
+ });
5407
+ } else if (spaceOption === "never") {
5408
+ if (space.length === 0) return;
5409
+ context.report({
5410
+ node,
5411
+ loc: getSourceLocationFromRange(sourceCode, node, [closingBracketIndex - space.length, closingBracketIndex]),
5412
+ messageId: "unexpectedSpaceBeforeClosingBracket",
5413
+ fix: (fixer) => fixer.removeRange([closingBracketIndex - space.length, closingBracketIndex])
5414
+ });
5415
+ }
5416
+ }
5417
+ return {
5418
+ link(node) {
5419
+ if (getLinkKind(sourceCode, node) !== "inline") return;
5420
+ const parsed = parseInlineLink(sourceCode, node);
5421
+ if (!parsed) return;
5422
+ const spaceForText = options.spaceForText(node);
5423
+ if (spaceForText === "ignore") return;
5424
+ verifySpaceAfterOpeningBracket(node, parsed.text.range[0], spaceForText);
5425
+ verifySpaceBeforeClosingBracket(node, parsed.text.range[0], parsed.text.range[1] - 1, spaceForText);
5426
+ },
5427
+ linkReference(node) {
5428
+ const parsed = parseLinkReference(sourceCode, node);
5429
+ if (!parsed) return;
5430
+ const spaceForText = options.spaceForText(node);
5431
+ if (spaceForText !== "ignore") {
5432
+ if (spaceForText !== "never" || !sourceCode.text.slice(parsed.text.range[0] + 1, parsed.text.range[1] - 1).trimStart().startsWith("^")) {
5433
+ verifySpaceAfterOpeningBracket(node, parsed.text.range[0], spaceForText);
5434
+ verifySpaceBeforeClosingBracket(node, parsed.text.range[0], parsed.text.range[1] - 1, spaceForText);
5435
+ }
5436
+ }
5437
+ if (parsed.label?.type === "full") {
5438
+ verifySpaceAfterOpeningBracket(node, parsed.label.range[0], options.space);
5439
+ verifySpaceBeforeClosingBracket(node, parsed.label.range[0], parsed.label.range[1] - 1, options.space);
5440
+ }
5441
+ },
5442
+ image(node) {
5443
+ const parsed = parseImage(sourceCode, node);
5444
+ if (!parsed) return;
5445
+ verifySpaceAfterOpeningBracket(node, parsed.text.range[0], options.space);
5446
+ verifySpaceBeforeClosingBracket(node, parsed.text.range[0], parsed.text.range[1] - 1, options.space);
5447
+ },
5448
+ imageReference(node) {
5449
+ const parsed = parseImageReference(sourceCode, node);
5450
+ if (!parsed) return;
5451
+ verifySpaceAfterOpeningBracket(node, parsed.text.range[0], options.space);
5452
+ verifySpaceBeforeClosingBracket(node, parsed.text.range[0], parsed.text.range[1] - 1, options.space);
5453
+ if (parsed.label?.type === "full") {
5454
+ verifySpaceAfterOpeningBracket(node, parsed.label.range[0], options.space);
5455
+ verifySpaceBeforeClosingBracket(node, parsed.label.range[0], parsed.label.range[1] - 1, options.space);
5456
+ }
5457
+ },
5458
+ definition(node) {
5459
+ const parsed = parseLinkDefinition(sourceCode, node);
5460
+ if (!parsed) return;
5461
+ if (options.space !== "never" || !sourceCode.text.slice(parsed.label.range[0] + 1, parsed.label.range[1] - 1).trimStart().startsWith("^")) {
5462
+ verifySpaceAfterOpeningBracket(node, parsed.label.range[0], options.space);
5463
+ verifySpaceBeforeClosingBracket(node, parsed.label.range[0], parsed.label.range[1] - 1, options.space);
5464
+ }
5465
+ }
5466
+ };
5467
+ /**
5468
+ * Get the spaces after the opening bracket.
5469
+ */
5470
+ function getSpaceAfterOpeningBracket(openingBracketIndex) {
5471
+ for (let i = openingBracketIndex + 1; i < sourceCode.text.length; i++) {
5472
+ const char = sourceCode.text[i];
5473
+ if (isWhitespace(char)) continue;
5474
+ return sourceCode.text.slice(openingBracketIndex + 1, i);
5475
+ }
5476
+ return sourceCode.text.slice(openingBracketIndex + 1);
5477
+ }
5478
+ /**
5479
+ * Get the spaces before the closing bracket.
5480
+ */
5481
+ function getSpaceBeforeClosingBracket(closingBracketIndex) {
5482
+ for (let i = closingBracketIndex - 1; i >= 0; i--) {
5483
+ const char = sourceCode.text[i];
5484
+ if (isWhitespace(char)) continue;
5485
+ return sourceCode.text.slice(i + 1, closingBracketIndex);
5486
+ }
5487
+ return sourceCode.text.slice(0, closingBracketIndex);
5488
+ }
5489
+ }
5490
+ });
5491
+
5492
+ //#endregion
5493
+ //#region src/rules/link-destination-style.ts
5494
+ const STYLES$1 = {
5495
+ bare: {
5496
+ messageId: "expectedBare",
5497
+ typeName: "bare"
5498
+ },
5499
+ "pointy-brackets": {
5500
+ messageId: "expectedPointyBrackets",
5501
+ typeName: "pointy-bracketed"
5502
+ }
5503
+ };
5504
+ var link_destination_style_default = createRule("link-destination-style", {
5505
+ meta: {
5506
+ type: "layout",
5507
+ docs: {
5508
+ description: "enforce a consistent style for link destinations",
5509
+ categories: ["standard"],
5510
+ listCategory: "Stylistic"
5511
+ },
5512
+ fixable: "code",
5513
+ hasSuggestions: false,
5514
+ schema: [{
5515
+ type: "object",
5516
+ properties: {
5517
+ style: { enum: ["bare", "pointy-brackets"] },
5518
+ avoidEscape: { type: "boolean" }
5519
+ }
5520
+ }],
5521
+ messages: {
5522
+ expectedBare: "Link destination should not be enclosed in pointy brackets.",
5523
+ expectedPointyBrackets: "Expected link destination to be pointy bracketed."
5524
+ }
5525
+ },
5526
+ create(context) {
5527
+ const sourceCode = context.sourceCode;
5528
+ const options = context.options[0] || {};
5529
+ const preferStyle = STYLES$1[options.style || "bare"];
5530
+ const avoidEscape = options.avoidEscape ?? true;
5531
+ /**
5532
+ * Verify destination style.
5533
+ */
5534
+ function verifyDestination(node, destination) {
5535
+ if (preferStyle.typeName === destination.type) return;
5536
+ if (avoidEscape) {
5537
+ if (preferStyle.typeName === "bare") {
5538
+ if (hasWhitespaceOrControlCharacter(destination.text) || !isBalancedDestinationParentheses(destination.text)) return;
5539
+ } else if (preferStyle.typeName === "pointy-bracketed") {
5540
+ if (hasLoneLastBackslash(destination.text)) return;
5541
+ }
5542
+ }
5543
+ context.report({
5544
+ node,
5545
+ loc: destination.loc,
5546
+ messageId: preferStyle.messageId,
5547
+ *fix(fixer) {
5548
+ if (destination.type === "bare" && preferStyle.typeName === "pointy-bracketed") {
5549
+ yield fixer.insertTextBeforeRange([destination.range[0], destination.range[0]], "<");
5550
+ if (hasLoneLastBackslash(destination.text)) yield fixer.insertTextBeforeRange([destination.range[1] - 1, destination.range[1]], "\\");
5551
+ yield fixer.insertTextAfterRange([destination.range[1], destination.range[1]], ">");
5552
+ } else if (destination.type === "pointy-bracketed" && preferStyle.typeName === "bare") {
5553
+ yield fixer.removeRange([destination.range[0], destination.range[0] + 1]);
5554
+ const balancedParentheses = isBalancedDestinationParentheses(destination.text);
5555
+ const textStartIndex = destination.range[0] + 1;
5556
+ const textEndIndex = destination.range[1] - 1;
5557
+ for (let index = textStartIndex; index < textEndIndex; index++) {
5558
+ const c = sourceCode.text[index];
5559
+ if (c === "(" || c === ")") {
5560
+ if (!balancedParentheses) yield fixer.insertTextBeforeRange([index, index], "\\");
5561
+ } else if (isWhitespace(c) || isAsciiControlCharacter(c)) yield fixer.replaceTextRange([index, index + 1], encodeURI(c));
5562
+ else if (c === "\\") index++;
5563
+ }
5564
+ yield fixer.removeRange([destination.range[1] - 1, destination.range[1]]);
5565
+ }
5566
+ }
5567
+ });
5568
+ }
5569
+ return {
5570
+ link(node) {
5571
+ if (getLinkKind(sourceCode, node) !== "inline") return;
5572
+ const parsed = parseInlineLink(sourceCode, node);
5573
+ if (!parsed) return;
5574
+ verifyDestination(node, parsed.destination);
5575
+ },
5576
+ image(node) {
5577
+ const parsed = parseImage(sourceCode, node);
5578
+ if (!parsed) return;
5579
+ verifyDestination(node, parsed.destination);
5580
+ },
5581
+ definition(node) {
5582
+ if (!node.url && preferStyle.typeName === "bare") return;
5583
+ const parsed = parseLinkDefinition(sourceCode, node);
5584
+ if (!parsed) return;
5585
+ verifyDestination(node, parsed.destination);
5586
+ }
5587
+ };
5588
+ }
5589
+ });
5590
+ /**
5591
+ * Checks if the text has whitespace or control characters.
5592
+ */
5593
+ function hasWhitespaceOrControlCharacter(text) {
5594
+ for (let index = 0; index < text.length; index++) {
5595
+ const c = text[index];
5596
+ if (isWhitespace(c) || isAsciiControlCharacter(c)) return true;
5597
+ else if (c === "\\") index++;
5598
+ }
5599
+ return false;
5600
+ }
5601
+ /**
5602
+ * Checks if the destination text is balanced parentheses.
5603
+ */
5604
+ function isBalancedDestinationParentheses(text) {
5605
+ let parentheses = 0;
5606
+ for (let index = 0; index < text.length; index++) {
5607
+ const c = text[index];
5608
+ if (c === "(") parentheses++;
5609
+ else if (c === ")") {
5610
+ parentheses--;
5611
+ if (parentheses < 0) return false;
5612
+ } else if (c === "\\") index++;
5613
+ }
5614
+ if (parentheses > 0) return false;
5615
+ return true;
5616
+ }
5617
+ /**
5618
+ * Checks if the text has a lone last backslash.
5619
+ */
5620
+ function hasLoneLastBackslash(text) {
5621
+ if (!text.endsWith("\\")) return false;
5622
+ let escapeText = "";
5623
+ while (text.endsWith(`${escapeText}\\`)) escapeText += "\\";
5624
+ return escapeText.length % 2 === 1;
5625
+ }
5626
+
5627
+ //#endregion
5628
+ //#region src/rules/link-title-style.ts
5629
+ const STYLES = {
5630
+ double: {
5631
+ messageId: "expectedDouble",
5632
+ open: "\"",
5633
+ close: "\"",
5634
+ typeName: "double-quoted"
5635
+ },
5636
+ single: {
5637
+ messageId: "expectedSingle",
5638
+ open: "'",
5639
+ close: "'",
5640
+ typeName: "single-quoted"
5641
+ },
5642
+ parentheses: {
5643
+ messageId: "expectedParentheses",
5644
+ open: "(",
5645
+ close: ")",
5646
+ typeName: "parenthesized"
5647
+ }
5648
+ };
5649
+ var link_title_style_default = createRule("link-title-style", {
5650
+ meta: {
5651
+ type: "layout",
5652
+ docs: {
5653
+ description: "enforce a consistent style for link titles",
5654
+ categories: ["standard"],
5655
+ listCategory: "Stylistic"
5656
+ },
5657
+ fixable: "code",
5658
+ hasSuggestions: false,
5659
+ schema: [{
5660
+ type: "object",
5661
+ properties: {
5662
+ style: { enum: [
5663
+ "double",
5664
+ "single",
5665
+ "parentheses"
5666
+ ] },
5667
+ avoidEscape: { type: "boolean" }
5668
+ }
5669
+ }],
5670
+ messages: {
5671
+ expectedDouble: "Expected link title to be double quoted.",
5672
+ expectedSingle: "Expected link title to be single quoted.",
5673
+ expectedParentheses: "Expected link title to be parenthesized."
5674
+ }
5675
+ },
5676
+ create(context) {
5677
+ const sourceCode = context.sourceCode;
5678
+ const options = context.options[0] || {};
5679
+ const preferStyle = STYLES[options.style || "double"];
5680
+ const avoidEscape = options.avoidEscape ?? true;
5681
+ /**
5682
+ * Verify title style.
5683
+ */
5684
+ function verifyTitle(node, title) {
5685
+ if (preferStyle.typeName === title.type) return;
5686
+ if (avoidEscape) {
5687
+ if (title.text.slice(1, -1).includes(preferStyle.close)) return;
5688
+ }
5689
+ context.report({
5690
+ node,
5691
+ loc: title.loc,
5692
+ messageId: preferStyle.messageId,
5693
+ *fix(fixer) {
5694
+ yield fixer.replaceTextRange([title.range[0], title.range[0] + 1], preferStyle.open);
5695
+ for (let index = title.range[0] + 1; index < title.range[1] - 1; index++) {
5696
+ const c = sourceCode.text[index];
5697
+ if (c === preferStyle.close) yield fixer.insertTextBeforeRange([index, index], "\\");
5698
+ else if (c === "\\") index++;
5699
+ }
5700
+ yield fixer.replaceTextRange([title.range[1] - 1, title.range[1]], preferStyle.close);
5701
+ }
5702
+ });
5703
+ }
5704
+ return {
5705
+ link(node) {
5706
+ if (getLinkKind(sourceCode, node) !== "inline") return;
5707
+ const parsed = parseInlineLink(sourceCode, node);
5708
+ if (!parsed || !parsed.title) return;
5709
+ verifyTitle(node, parsed.title);
5710
+ },
5711
+ image(node) {
5712
+ const parsed = parseImage(sourceCode, node);
5713
+ if (!parsed || !parsed.title) return;
5714
+ verifyTitle(node, parsed.title);
5715
+ },
5716
+ definition(node) {
5717
+ const parsed = parseLinkDefinition(sourceCode, node);
5718
+ if (!parsed || !parsed.title) return;
5719
+ verifyTitle(node, parsed.title);
5720
+ }
5721
+ };
5722
+ }
5723
+ });
5724
+
5725
+ //#endregion
5726
+ //#region src/rules/list-marker-alignment.ts
5727
+ const ALIGN_TO_POSITION_NAME = {
5728
+ left: "start",
5729
+ right: "end"
5730
+ };
5731
+ var list_marker_alignment_default = createRule("list-marker-alignment", {
5732
+ meta: {
5733
+ type: "layout",
5734
+ docs: {
5735
+ description: "enforce consistent alignment of list markers",
5736
+ categories: ["recommended", "standard"],
5737
+ listCategory: "Stylistic"
5738
+ },
5739
+ fixable: "whitespace",
5740
+ hasSuggestions: false,
5741
+ schema: [{
5742
+ type: "object",
5743
+ properties: { align: { enum: ["left", "right"] } },
5744
+ additionalProperties: false
5745
+ }],
5746
+ messages: { incorrectAlignment: "List marker alignment is inconsistent. Expected {{expected}} characters of indentation, but got {{actual}}." }
5747
+ },
5748
+ create(context) {
5749
+ const sourceCode = context.sourceCode;
5750
+ const alignPositionName = ALIGN_TO_POSITION_NAME[context.options[0]?.align ?? "left"];
5751
+ /**
5752
+ * Get the marker location of a list item
5753
+ */
5754
+ function getMarkerLocation(node) {
5755
+ const start = sourceCode.getLoc(node).start;
5756
+ const startColumnIndex = start.column - 1;
5757
+ const marker = getListItemMarker(sourceCode, node);
5758
+ return {
5759
+ line: start.line,
5760
+ start: startColumnIndex,
5761
+ end: startColumnIndex + marker.raw.length
5762
+ };
5763
+ }
5764
+ /**
5765
+ * Check if list items have consistent alignment
5766
+ */
5767
+ function checkListAlignment(listNode) {
5768
+ const items = listNode.children;
5769
+ if (items.length <= 1) return;
5770
+ const referenceMarkerLocation = getMarkerLocation(items[0]);
5771
+ for (const item of items.slice(1)) {
5772
+ const markerLocation = getMarkerLocation(item);
5773
+ const diff = markerLocation[alignPositionName] - referenceMarkerLocation[alignPositionName];
5774
+ if (diff === 0) continue;
5775
+ context.report({
5776
+ node: item,
5777
+ loc: {
5778
+ start: {
5779
+ line: markerLocation.line,
5780
+ column: markerLocation.start + 1
5781
+ },
5782
+ end: {
5783
+ line: markerLocation.line,
5784
+ column: markerLocation.end + 1
5785
+ }
5786
+ },
5787
+ messageId: "incorrectAlignment",
5788
+ data: {
5789
+ expected: String(markerLocation.start - diff),
5790
+ actual: String(markerLocation.start)
5791
+ },
5792
+ fix(fixer) {
5793
+ const lines = getParsedLines(sourceCode);
5794
+ const line = lines.get(markerLocation.line);
5795
+ if (diff < 0) {
5796
+ const addSpaces = " ".repeat(-diff);
5797
+ return fixer.insertTextBeforeRange([line.range[0] + markerLocation.start, line.range[0] + markerLocation.start], addSpaces);
5798
+ }
5799
+ const itemBefore = line.text.slice(0, markerLocation.start - diff);
5800
+ if (itemBefore.includes(" ")) return null;
5801
+ if (lines.get(referenceMarkerLocation.line).text.slice(0, referenceMarkerLocation.start) === itemBefore) {
5802
+ const removeEndIndex = line.range[0] + markerLocation.start;
5803
+ const removeStartIndex = removeEndIndex - diff;
5804
+ return fixer.removeRange([removeStartIndex, removeEndIndex]);
5805
+ }
5806
+ return null;
5807
+ }
5808
+ });
5809
+ }
5810
+ }
5811
+ return { list: checkListAlignment };
4714
5812
  }
4715
5813
  });
4716
5814
 
@@ -4721,7 +5819,7 @@ var no_laziness_blockquotes_default = createRule("no-laziness-blockquotes", {
4721
5819
  type: "problem",
4722
5820
  docs: {
4723
5821
  description: "disallow laziness in blockquotes",
4724
- categories: ["recommended"],
5822
+ categories: ["recommended", "standard"],
4725
5823
  listCategory: "Stylistic"
4726
5824
  },
4727
5825
  fixable: void 0,
@@ -4821,6 +5919,182 @@ var no_laziness_blockquotes_default = createRule("no-laziness-blockquotes", {
4821
5919
  }
4822
5920
  });
4823
5921
 
5922
+ //#endregion
5923
+ //#region src/rules/no-multi-spaces.ts
5924
+ var no_multi_spaces_default = createRule("no-multi-spaces", {
5925
+ meta: {
5926
+ type: "layout",
5927
+ docs: {
5928
+ description: "disallow multiple spaces",
5929
+ categories: ["standard"],
5930
+ listCategory: "Stylistic"
5931
+ },
5932
+ fixable: "whitespace",
5933
+ hasSuggestions: false,
5934
+ schema: [],
5935
+ messages: { multipleSpaces: "Multiple spaces are not allowed." }
5936
+ },
5937
+ create(context) {
5938
+ const sourceCode = context.sourceCode;
5939
+ return {
5940
+ definition: verifyLinkDefinition,
5941
+ footnoteDefinition: verifyFootnoteDefinition,
5942
+ heading: verifyHeading,
5943
+ image: verifyImage,
5944
+ imageReference: verifyImageReference,
5945
+ link: verifyLink,
5946
+ linkReference: verifyLinkReference,
5947
+ listItem: verifyListItem,
5948
+ text: verifyText
5949
+ };
5950
+ /**
5951
+ * Verify a text node.
5952
+ */
5953
+ function verifyText(node) {
5954
+ verifyTextInNode(node);
5955
+ }
5956
+ /**
5957
+ * Verify a definition node.
5958
+ */
5959
+ function verifyLinkDefinition(node) {
5960
+ const parsed = parseLinkDefinition(sourceCode, node);
5961
+ if (!parsed) return;
5962
+ const nodeRange = sourceCode.getRange(node);
5963
+ verifyTextInRange(node, [nodeRange[0], parsed.destination.range[0]]);
5964
+ verifyTextInRange(node, [parsed.destination.range[1], nodeRange[1]]);
5965
+ }
5966
+ /**
5967
+ * Verify a footnote definition node
5968
+ */
5969
+ function verifyFootnoteDefinition(node) {
5970
+ verifyTextOutsideChildren(node);
5971
+ }
5972
+ /**
5973
+ * Verify a heading node
5974
+ */
5975
+ function verifyHeading(node) {
5976
+ verifyTextOutsideChildren(node);
5977
+ }
5978
+ /**
5979
+ * Verify an image node
5980
+ */
5981
+ function verifyImage(node) {
5982
+ const parsed = parseImage(sourceCode, node);
5983
+ if (!parsed) return;
5984
+ const nodeRange = sourceCode.getRange(node);
5985
+ verifyTextInRange(node, [nodeRange[0], parsed.destination.range[0]]);
5986
+ verifyTextInRange(node, [parsed.destination.range[1], nodeRange[1]]);
5987
+ }
5988
+ /**
5989
+ * Verify an image reference node
5990
+ */
5991
+ function verifyImageReference(node) {
5992
+ verifyTextInNode(node);
5993
+ }
5994
+ /**
5995
+ * Verify a link node
5996
+ */
5997
+ function verifyLink(node) {
5998
+ const parsed = parseInlineLink(sourceCode, node);
5999
+ if (!parsed) return;
6000
+ const nodeRange = sourceCode.getRange(node);
6001
+ if (node.children.length > 0) {
6002
+ const first = node.children[0];
6003
+ const last = node.children[node.children.length - 1];
6004
+ const firstRange = sourceCode.getRange(first);
6005
+ const lastRange = sourceCode.getRange(last);
6006
+ verifyTextInRange(node, [nodeRange[0], firstRange[0]]);
6007
+ verifyTextInRange(node, [lastRange[1], parsed.destination.range[0]]);
6008
+ } else verifyTextInRange(node, [nodeRange[0], parsed.destination.range[0]]);
6009
+ verifyTextInRange(node, [parsed.destination.range[1], nodeRange[1]]);
6010
+ }
6011
+ /**
6012
+ * Verify a link reference node
6013
+ */
6014
+ function verifyLinkReference(node) {
6015
+ verifyTextOutsideChildren(node);
6016
+ }
6017
+ /**
6018
+ * Verify a list item node
6019
+ */
6020
+ function verifyListItem(node) {
6021
+ verifyTextOutsideChildren(node);
6022
+ }
6023
+ /**
6024
+ * Verify spaces in a node
6025
+ */
6026
+ function verifyTextInNode(node) {
6027
+ const nodeRange = sourceCode.getRange(node);
6028
+ verifyTextInRange(node, nodeRange);
6029
+ }
6030
+ /**
6031
+ * Verify spaces in a node excluding children
6032
+ */
6033
+ function verifyTextOutsideChildren(node) {
6034
+ const nodeRange = sourceCode.getRange(node);
6035
+ if (node.children.length > 0) {
6036
+ const first = node.children[0];
6037
+ const last = node.children[node.children.length - 1];
6038
+ const firstRange = sourceCode.getRange(first);
6039
+ const lastRange = sourceCode.getRange(last);
6040
+ verifyTextInRange(node, [nodeRange[0], firstRange[0]]);
6041
+ verifyTextInRange(node, [lastRange[1], nodeRange[1]]);
6042
+ } else verifyTextInRange(node, nodeRange);
6043
+ }
6044
+ /**
6045
+ * Verify spaces in a node
6046
+ */
6047
+ function verifyTextInRange(node, textRange) {
6048
+ const nodeRange = sourceCode.getRange(node);
6049
+ const text = sourceCode.text.slice(...textRange);
6050
+ const reSpaces = /\s{2,}|\n/gu;
6051
+ let match;
6052
+ while ((match = reSpaces.exec(text)) !== null) {
6053
+ const spaces = match[0];
6054
+ if (spaces.includes("\n")) {
6055
+ let c = "";
6056
+ while ((c = text[reSpaces.lastIndex]) && (c === ">" || !c.trim())) reSpaces.lastIndex++;
6057
+ continue;
6058
+ }
6059
+ if (spaces.length < 2) continue;
6060
+ const start = textRange[0] + match.index;
6061
+ const end = start + spaces.length;
6062
+ const range = [start, end];
6063
+ if (nodeRange[0] === range[0]) {
6064
+ let isIndentation = true;
6065
+ for (let index = nodeRange[0] - 1; index >= 0; index--) {
6066
+ const c = sourceCode.text[index];
6067
+ if (c === "\n") break;
6068
+ if (isWhitespace(c)) continue;
6069
+ isIndentation = false;
6070
+ break;
6071
+ }
6072
+ if (isIndentation) continue;
6073
+ }
6074
+ if (nodeRange[1] === range[1]) {
6075
+ let isTrailingSpaces = true;
6076
+ for (let index = nodeRange[1]; index < sourceCode.text.length; index++) {
6077
+ const c = sourceCode.text[index];
6078
+ if (c === "\n") break;
6079
+ if (isWhitespace(c)) continue;
6080
+ isTrailingSpaces = false;
6081
+ break;
6082
+ }
6083
+ if (isTrailingSpaces) continue;
6084
+ }
6085
+ context.report({
6086
+ node,
6087
+ messageId: "multipleSpaces",
6088
+ loc: getSourceLocationFromRange(sourceCode, node, range),
6089
+ fix(fixer) {
6090
+ return fixer.replaceTextRange(range, " ");
6091
+ }
6092
+ });
6093
+ }
6094
+ }
6095
+ }
6096
+ });
6097
+
4824
6098
  //#endregion
4825
6099
  //#region src/rules/no-multiple-empty-lines.ts
4826
6100
  var no_multiple_empty_lines_default = createRule("no-multiple-empty-lines", {
@@ -4828,7 +6102,7 @@ var no_multiple_empty_lines_default = createRule("no-multiple-empty-lines", {
4828
6102
  type: "layout",
4829
6103
  docs: {
4830
6104
  description: "disallow multiple empty lines in Markdown files.",
4831
- categories: null,
6105
+ categories: ["standard"],
4832
6106
  listCategory: "Stylistic"
4833
6107
  },
4834
6108
  fixable: "whitespace",
@@ -4987,7 +6261,7 @@ var no_text_backslash_linebreak_default = createRule("no-text-backslash-linebrea
4987
6261
  type: "layout",
4988
6262
  docs: {
4989
6263
  description: "disallow text backslash at the end of a line.",
4990
- categories: ["recommended"],
6264
+ categories: ["recommended", "standard"],
4991
6265
  listCategory: "Stylistic"
4992
6266
  },
4993
6267
  fixable: void 0,
@@ -5032,7 +6306,7 @@ var no_trailing_spaces_default = createRule("no-trailing-spaces", {
5032
6306
  type: "layout",
5033
6307
  docs: {
5034
6308
  description: "disallow trailing whitespace at the end of lines in Markdown files.",
5035
- categories: [],
6309
+ categories: ["standard"],
5036
6310
  listCategory: "Stylistic"
5037
6311
  },
5038
6312
  fixable: "whitespace",
@@ -5093,7 +6367,31 @@ var no_trailing_spaces_default = createRule("no-trailing-spaces", {
5093
6367
  html(node) {
5094
6368
  if (htmlComment.test(node.value)) comments.push(node);
5095
6369
  },
5096
- "break, code, inlineCode, text, yaml, toml, json"(node) {
6370
+ break(node) {
6371
+ ignoreNodes.push(node);
6372
+ const range = sourceCode.getRange(node);
6373
+ let trailingSpaceCount = 0;
6374
+ for (let index = range[1] - 1; index >= range[0]; index--) {
6375
+ const c = sourceCode.text[index];
6376
+ if (c === "\n" || c === "\r") {
6377
+ trailingSpaceCount = 0;
6378
+ continue;
6379
+ }
6380
+ if (!isWhitespace(c)) return;
6381
+ trailingSpaceCount++;
6382
+ }
6383
+ const extraSpaces = trailingSpaceCount - 2;
6384
+ if (extraSpaces <= 0) return;
6385
+ context.report({
6386
+ node,
6387
+ loc: getSourceLocationFromRange(sourceCode, node, [range[0], range[0] + extraSpaces]),
6388
+ messageId: "trailingSpace",
6389
+ fix(fixer) {
6390
+ return fixer.removeRange([range[0], range[0] + extraSpaces]);
6391
+ }
6392
+ });
6393
+ },
6394
+ "code, inlineCode, text, yaml, toml, json"(node) {
5097
6395
  ignoreNodes.push(node);
5098
6396
  },
5099
6397
  "root:exit"() {
@@ -5134,7 +6432,7 @@ var ordered_list_marker_sequence_default = createRule("ordered-list-marker-seque
5134
6432
  type: "layout",
5135
6433
  docs: {
5136
6434
  description: "enforce that ordered list markers use sequential numbers",
5137
- categories: [],
6435
+ categories: ["standard"],
5138
6436
  listCategory: "Stylistic"
5139
6437
  },
5140
6438
  fixable: "code",
@@ -5250,7 +6548,7 @@ var ordered_list_marker_start_default = createRule("ordered-list-marker-start",
5250
6548
  type: "layout",
5251
6549
  docs: {
5252
6550
  description: "enforce that ordered list markers start with 1 or 0",
5253
- categories: [],
6551
+ categories: ["standard"],
5254
6552
  listCategory: "Preference"
5255
6553
  },
5256
6554
  fixable: "code",
@@ -5267,8 +6565,7 @@ var ordered_list_marker_start_default = createRule("ordered-list-marker-start",
5267
6565
  },
5268
6566
  create(context) {
5269
6567
  const sourceCode = context.sourceCode;
5270
- const option = context.options[0] || {};
5271
- const expectedStart = option.start ?? 1;
6568
+ const expectedStart = (context.options[0] || {}).start ?? 1;
5272
6569
  let scope = {
5273
6570
  node: sourceCode.ast,
5274
6571
  upper: null,
@@ -5376,7 +6673,7 @@ var ordered_list_marker_style_default = createRule("ordered-list-marker-style",
5376
6673
  type: "layout",
5377
6674
  docs: {
5378
6675
  description: "enforce consistent ordered list marker style",
5379
- categories: [],
6676
+ categories: ["standard"],
5380
6677
  listCategory: "Stylistic"
5381
6678
  },
5382
6679
  fixable: "code",
@@ -5457,8 +6754,7 @@ var ordered_list_marker_style_default = createRule("ordered-list-marker-style",
5457
6754
  for (let index = nodeIndex + 1; index < containerStack.node.children.length; index++) {
5458
6755
  const nextNode = containerStack.node.children[index];
5459
6756
  if (nextNode.type !== "list") break;
5460
- const nextMarker = getListItemMarker(sourceCode, nextNode);
5461
- if (nextMarker.kind !== prevMarker) break;
6757
+ if (getListItemMarker(sourceCode, nextNode).kind !== prevMarker) break;
5462
6758
  const expectedNextMarker = prevMarker === prefer ? getOtherMarkerKind(prefer) : prefer;
5463
6759
  yield* fixMarkers(nextNode, expectedNextMarker);
5464
6760
  prevMarker = expectedNextMarker;
@@ -5567,7 +6863,7 @@ const SELECTOR_SCHEMA = { oneOf: [...BLOCK_TYPE_SCHEMAS, {
5567
6863
  required: ["type"],
5568
6864
  additionalProperties: false
5569
6865
  }] };
5570
- const BLOCK_TYPE_MAP0 = {
6866
+ const BLOCK_TYPE_MAP = {
5571
6867
  heading: "heading",
5572
6868
  paragraph: "paragraph",
5573
6869
  list: "list",
@@ -5582,7 +6878,6 @@ const BLOCK_TYPE_MAP0 = {
5582
6878
  toml: "frontmatter",
5583
6879
  yaml: "frontmatter"
5584
6880
  };
5585
- const BLOCK_TYPE_MAP = BLOCK_TYPE_MAP0;
5586
6881
  /**
5587
6882
  * Get the block type of a node
5588
6883
  */
@@ -5597,7 +6892,7 @@ var padding_line_between_blocks_default = createRule("padding-line-between-block
5597
6892
  type: "layout",
5598
6893
  docs: {
5599
6894
  description: "require or disallow padding lines between blocks",
5600
- categories: ["recommended"],
6895
+ categories: ["standard"],
5601
6896
  listCategory: "Stylistic"
5602
6897
  },
5603
6898
  fixable: "whitespace",
@@ -5633,7 +6928,31 @@ var padding_line_between_blocks_default = createRule("padding-line-between-block
5633
6928
  },
5634
6929
  create(context) {
5635
6930
  const sourceCode = context.sourceCode;
5636
- const options = [...context.options || []].reverse();
6931
+ const options = [...context.options?.length ? context.options : [
6932
+ {
6933
+ prev: "*",
6934
+ next: "*",
6935
+ blankLine: "always"
6936
+ },
6937
+ {
6938
+ prev: "link-definition",
6939
+ next: "link-definition",
6940
+ blankLine: "never"
6941
+ },
6942
+ {
6943
+ prev: "footnote-definition",
6944
+ next: "footnote-definition",
6945
+ blankLine: "never"
6946
+ },
6947
+ {
6948
+ prev: "paragraph",
6949
+ next: {
6950
+ type: "list",
6951
+ in: "list"
6952
+ },
6953
+ blankLine: "never"
6954
+ }
6955
+ ]].reverse();
5637
6956
  const containerStack = [];
5638
6957
  /**
5639
6958
  * Check if the actual type matches the expected type pattern
@@ -5694,8 +7013,7 @@ var padding_line_between_blocks_default = createRule("padding-line-between-block
5694
7013
  if (expected === null) continue;
5695
7014
  const prevLoc = sourceCode.getLoc(prevBlock);
5696
7015
  const nextLoc = sourceCode.getLoc(nextBlock);
5697
- const actualBlankLine = nextLoc.start.line - prevLoc.end.line - 1;
5698
- const hasBlankLine = actualBlankLine > 0;
7016
+ const hasBlankLine = nextLoc.start.line - prevLoc.end.line - 1 > 0;
5699
7017
  let messageId = "expectedBlankLine";
5700
7018
  if (expected.blankLine === "always") {
5701
7019
  if (hasBlankLine) continue;
@@ -5742,8 +7060,7 @@ var padding_line_between_blocks_default = createRule("padding-line-between-block
5742
7060
  const blockquoteLoc = sourceCode.getLoc(blockquote);
5743
7061
  text += getBlockquoteLevelFromLine(sourceCode, blockquoteLoc.start.line).prefix.trimEnd();
5744
7062
  }
5745
- const nextRange = sourceCode.getRange(nextBlock);
5746
- const startNext = nextRange[0] - nextLoc.start.column;
7063
+ const startNext = sourceCode.getRange(nextBlock)[0] - nextLoc.start.column;
5747
7064
  return fixer.insertTextBeforeRange([startNext, startNext], text);
5748
7065
  }
5749
7066
  const lines = getParsedLines(sourceCode);
@@ -5773,7 +7090,7 @@ var prefer_autolinks_default = createRule("prefer-autolinks", {
5773
7090
  type: "layout",
5774
7091
  docs: {
5775
7092
  description: "enforce the use of autolinks for URLs",
5776
- categories: ["recommended"],
7093
+ categories: ["recommended", "standard"],
5777
7094
  listCategory: "Stylistic"
5778
7095
  },
5779
7096
  fixable: "code",
@@ -5811,7 +7128,7 @@ var prefer_fenced_code_blocks_default = createRule("prefer-fenced-code-blocks",
5811
7128
  type: "layout",
5812
7129
  docs: {
5813
7130
  description: "enforce the use of fenced code blocks over indented code blocks",
5814
- categories: ["recommended"],
7131
+ categories: ["recommended", "standard"],
5815
7132
  listCategory: "Stylistic"
5816
7133
  },
5817
7134
  fixable: "code",
@@ -5871,8 +7188,7 @@ var prefer_fenced_code_blocks_default = createRule("prefer-fenced-code-blocks",
5871
7188
  const firstLine = lines.get(loc.start.line);
5872
7189
  const codeBlockFirstLine = normalizePrefix(node.value.split(/\r?\n/u)[0]);
5873
7190
  const startColumnOffset = loc.start.column - 1;
5874
- const normalizedFirstLine = normalizePrefix(firstLine.text.slice(startColumnOffset));
5875
- return normalizedFirstLine.startsWith(codeBlockFirstLine);
7191
+ return normalizePrefix(firstLine.text.slice(startColumnOffset)).startsWith(codeBlockFirstLine);
5876
7192
  }
5877
7193
  }
5878
7194
  });
@@ -6061,8 +7377,7 @@ var prefer_link_reference_definitions_default = createRule("prefer-link-referenc
6061
7377
  },
6062
7378
  create(context) {
6063
7379
  const sourceCode = context.sourceCode;
6064
- const options = context.options[0] || {};
6065
- const minLinks = options.minLinks ?? 2;
7380
+ const minLinks = (context.options[0] || {}).minLinks ?? 2;
6066
7381
  const definitions = [];
6067
7382
  const links = [];
6068
7383
  const references = [];
@@ -6165,8 +7480,7 @@ var prefer_link_reference_definitions_default = createRule("prefer-link-referenc
6165
7480
  const range = sourceCode.getRange(link);
6166
7481
  if (link.type === "link") {
6167
7482
  const bracketsRange$1 = getLinkBracketsRange(link);
6168
- const linkBracketsText$1 = sourceCode.text.slice(...bracketsRange$1);
6169
- const linkLabelText$1 = linkBracketsText$1.slice(1, -1).trim();
7483
+ const linkLabelText$1 = sourceCode.text.slice(...bracketsRange$1).slice(1, -1).trim();
6170
7484
  const urlStartIndex$1 = sourceCode.text.indexOf("(", bracketsRange$1[1]);
6171
7485
  return {
6172
7486
  label: linkLabelText$1,
@@ -6175,8 +7489,7 @@ var prefer_link_reference_definitions_default = createRule("prefer-link-referenc
6175
7489
  };
6176
7490
  }
6177
7491
  const bracketsRange = getImageBracketsRange(link);
6178
- const linkBracketsText = sourceCode.text.slice(...bracketsRange);
6179
- const linkLabelText = linkBracketsText.slice(1, -1).trim();
7492
+ const linkLabelText = sourceCode.text.slice(...bracketsRange).slice(1, -1).trim();
6180
7493
  const urlStartIndex = sourceCode.text.indexOf("(", bracketsRange[1]);
6181
7494
  return {
6182
7495
  label: linkLabelText,
@@ -6324,7 +7637,7 @@ var setext_heading_underline_length_default = createRule("setext-heading-underli
6324
7637
  type: "layout",
6325
7638
  docs: {
6326
7639
  description: "enforce setext heading underline length",
6327
- categories: [],
7640
+ categories: ["standard"],
6328
7641
  listCategory: "Stylistic"
6329
7642
  },
6330
7643
  fixable: "whitespace",
@@ -6562,7 +7875,7 @@ var sort_definitions_default = createRule("sort-definitions", {
6562
7875
  type: "layout",
6563
7876
  docs: {
6564
7877
  description: "enforce a specific order for link definitions and footnote definitions",
6565
- categories: [],
7878
+ categories: ["standard"],
6566
7879
  listCategory: "Stylistic"
6567
7880
  },
6568
7881
  fixable: "code",
@@ -6650,8 +7963,7 @@ var sort_definitions_default = createRule("sort-definitions", {
6650
7963
  if (moveNode.type === "definition" && index > 0) {
6651
7964
  if (movedNodes[index - 1].type === "footnoteDefinition") {
6652
7965
  const footnoteLoc = sourceCode.getLoc(definitions[index - 1]);
6653
- const linkLoc = sourceCode.getLoc(definitions[index]);
6654
- if (linkLoc.start.line - footnoteLoc.end.line <= 1) text = `\n${text}`;
7966
+ if (sourceCode.getLoc(definitions[index]).start.line - footnoteLoc.end.line <= 1) text = `\n${text}`;
6655
7967
  }
6656
7968
  }
6657
7969
  return fixer.replaceText(definitions[index], text);
@@ -6678,10 +7990,9 @@ var sort_definitions_default = createRule("sort-definitions", {
6678
7990
  return {
6679
7991
  "*"(node) {
6680
7992
  const last = group.at(-1);
6681
- if (last && (node.type !== "definition" && node.type !== "footnoteDefinition" || sourceCode.getParent(node) !== sourceCode.getParent(last))) {
7993
+ if (last && (node.type !== "definition" && node.type !== "footnoteDefinition" || getParent(sourceCode, node) !== getParent(sourceCode, last))) {
6682
7994
  const range = sourceCode.getRange(node);
6683
- const lastDefinitionRange = sourceCode.getRange(last);
6684
- if (lastDefinitionRange[1] <= range[0]) {
7995
+ if (sourceCode.getRange(last)[1] <= range[0]) {
6685
7996
  verify(group);
6686
7997
  group.length = 0;
6687
7998
  }
@@ -6694,14 +8005,13 @@ var sort_definitions_default = createRule("sort-definitions", {
6694
8005
  };
6695
8006
  /** Parse options */
6696
8007
  function parseOption(userOption) {
6697
- const order = userOption?.order ?? [{
8008
+ const compiled = (userOption?.order ?? [{
6698
8009
  match: String.raw`!/^\[\\^/u`,
6699
8010
  sort: "alphabetical"
6700
8011
  }, {
6701
8012
  match: String.raw`/./u`,
6702
8013
  sort: "alphabetical"
6703
- }];
6704
- const compiled = order.map(compileOption);
8014
+ }]).map(compileOption);
6705
8015
  return {
6706
8016
  ignore: (node) => {
6707
8017
  return !compiled.some((c) => c.match(node));
@@ -6743,20 +8053,14 @@ var sort_definitions_default = createRule("sort-definitions", {
6743
8053
  }
6744
8054
  /** Compile order option without cache */
6745
8055
  function compileOptionWithoutCache(orderOption) {
6746
- if (typeof orderOption === "string") {
6747
- const match$1 = compileMatcher([orderOption]);
6748
- return {
6749
- match: match$1,
6750
- sort: "ignore"
6751
- };
6752
- }
6753
- if (Array.isArray(orderOption)) {
6754
- const match$1 = compileMatcher(orderOption);
6755
- return {
6756
- match: match$1,
6757
- sort: "ignore"
6758
- };
6759
- }
8056
+ if (typeof orderOption === "string") return {
8057
+ match: compileMatcher([orderOption]),
8058
+ sort: "ignore"
8059
+ };
8060
+ if (Array.isArray(orderOption)) return {
8061
+ match: compileMatcher(orderOption),
8062
+ sort: "ignore"
8063
+ };
6760
8064
  const { match } = compileOptionWithoutCache(orderOption.match);
6761
8065
  return {
6762
8066
  match,
@@ -6765,7 +8069,7 @@ var sort_definitions_default = createRule("sort-definitions", {
6765
8069
  }
6766
8070
  /** Compile matcher */
6767
8071
  function compileMatcher(pattern) {
6768
- const rules$3 = [];
8072
+ const rules$4 = [];
6769
8073
  for (const p of pattern) {
6770
8074
  let negative, patternStr;
6771
8075
  if (p.startsWith("!")) {
@@ -6776,11 +8080,11 @@ var sort_definitions_default = createRule("sort-definitions", {
6776
8080
  patternStr = p;
6777
8081
  }
6778
8082
  const regex = toRegExp(patternStr);
6779
- if (isRegExp(patternStr)) rules$3.push({
8083
+ if (isRegExp(patternStr)) rules$4.push({
6780
8084
  negative,
6781
8085
  match: (node) => regex.test(getDefinitionText(node))
6782
8086
  });
6783
- else rules$3.push({
8087
+ else rules$4.push({
6784
8088
  negative,
6785
8089
  match: (node) => {
6786
8090
  if (node.label === patternStr || node.identifier === patternStr) return true;
@@ -6788,8 +8092,7 @@ var sort_definitions_default = createRule("sort-definitions", {
6788
8092
  if (node.url === patternStr) return true;
6789
8093
  if (URL.canParse(patternStr) && URL.canParse(node.url)) {
6790
8094
  const normalizedPattern = normalizedURL(patternStr);
6791
- const normalizedUrl = normalizedURL(node.url);
6792
- if (normalizedUrl.startsWith(normalizedPattern)) return true;
8095
+ if (normalizedURL(node.url).startsWith(normalizedPattern)) return true;
6793
8096
  }
6794
8097
  }
6795
8098
  return regex.test(getDefinitionText(node));
@@ -6797,8 +8100,8 @@ var sort_definitions_default = createRule("sort-definitions", {
6797
8100
  });
6798
8101
  }
6799
8102
  return (node) => {
6800
- let result = Boolean(rules$3[0]?.negative);
6801
- for (const { negative, match } of rules$3) {
8103
+ let result = Boolean(rules$4[0]?.negative);
8104
+ for (const { negative, match } of rules$4) {
6802
8105
  if (result === !negative) continue;
6803
8106
  if (match(node)) result = !negative;
6804
8107
  }
@@ -6845,7 +8148,7 @@ var strikethrough_delimiters_style_default = createRule("strikethrough-delimiter
6845
8148
  type: "layout",
6846
8149
  docs: {
6847
8150
  description: "enforce a consistent delimiter style for strikethrough",
6848
- categories: [],
8151
+ categories: ["standard"],
6849
8152
  listCategory: "Stylistic"
6850
8153
  },
6851
8154
  fixable: "code",
@@ -6859,8 +8162,7 @@ var strikethrough_delimiters_style_default = createRule("strikethrough-delimiter
6859
8162
  },
6860
8163
  create(context) {
6861
8164
  const sourceCode = context.sourceCode;
6862
- const option = context.options[0] ?? {};
6863
- const delimiter = option.delimiter ?? "~~";
8165
+ const delimiter = (context.options[0] ?? {}).delimiter ?? "~~";
6864
8166
  return { delete(node) {
6865
8167
  const range = sourceCode.getRange(node);
6866
8168
  const actualDelimiter = ["~~", "~"].find((d) => sourceCode.text.startsWith(d, range[0]) && sourceCode.text.endsWith(d, range[1]));
@@ -7021,7 +8323,7 @@ var thematic_break_character_style_default = createRule("thematic-break-characte
7021
8323
  type: "layout",
7022
8324
  docs: {
7023
8325
  description: "enforce consistent character style for thematic breaks (horizontal rules) in Markdown.",
7024
- categories: [],
8326
+ categories: ["standard"],
7025
8327
  listCategory: "Stylistic"
7026
8328
  },
7027
8329
  fixable: "code",
@@ -7041,8 +8343,7 @@ var thematic_break_character_style_default = createRule("thematic-break-characte
7041
8343
  messages: { unexpected: "Thematic break should use '{{expected}}' but found '{{actual}}'." }
7042
8344
  },
7043
8345
  create(context) {
7044
- const option = context.options[0];
7045
- const style = option?.style || "-";
8346
+ const style = context.options[0]?.style || "-";
7046
8347
  return { thematicBreak(node) {
7047
8348
  const marker = getThematicBreakMarker(context.sourceCode, node);
7048
8349
  if (marker.kind !== style) context.report({
@@ -7054,8 +8355,7 @@ var thematic_break_character_style_default = createRule("thematic-break-characte
7054
8355
  },
7055
8356
  fix(fixer) {
7056
8357
  const range = context.sourceCode.getRange(node);
7057
- const text = context.sourceCode.getText(node);
7058
- const rep = text.replaceAll(marker.kind, style);
8358
+ const rep = context.sourceCode.getText(node).replaceAll(marker.kind, style);
7059
8359
  return fixer.replaceTextRange(range, rep);
7060
8360
  }
7061
8361
  });
@@ -7102,7 +8402,7 @@ var thematic_break_length_default = createRule("thematic-break-length", {
7102
8402
  type: "layout",
7103
8403
  docs: {
7104
8404
  description: "enforce consistent length for thematic breaks (horizontal rules) in Markdown.",
7105
- categories: [],
8405
+ categories: ["standard"],
7106
8406
  listCategory: "Stylistic"
7107
8407
  },
7108
8408
  fixable: "code",
@@ -7118,8 +8418,7 @@ var thematic_break_length_default = createRule("thematic-break-length", {
7118
8418
  messages: { unexpected: "Thematic break should be {{expected}} characters, but found {{actual}}." }
7119
8419
  },
7120
8420
  create(context) {
7121
- const option = context.options[0] || {};
7122
- const expectedLength = option.length ?? 3;
8421
+ const expectedLength = (context.options[0] || {}).length ?? 3;
7123
8422
  const sourceCode = context.sourceCode;
7124
8423
  return { thematicBreak(node) {
7125
8424
  const marker = getThematicBreakMarker(sourceCode, node);
@@ -7169,7 +8468,7 @@ var thematic_break_sequence_pattern_default = createRule("thematic-break-sequenc
7169
8468
  type: "layout",
7170
8469
  docs: {
7171
8470
  description: "enforce consistent repeating patterns for thematic breaks (horizontal rules) in Markdown.",
7172
- categories: [],
8471
+ categories: ["standard"],
7173
8472
  listCategory: "Stylistic"
7174
8473
  },
7175
8474
  fixable: "code",
@@ -7199,8 +8498,7 @@ var thematic_break_sequence_pattern_default = createRule("thematic-break-sequenc
7199
8498
  messages: { inconsistentPattern: "Thematic break does not match the preferred repeating pattern '{{pattern}}'." }
7200
8499
  },
7201
8500
  create(context) {
7202
- const option = context.options[0] || {};
7203
- const pattern = option.pattern ?? "-";
8501
+ const pattern = (context.options[0] || {}).pattern ?? "-";
7204
8502
  const sourceCode = context.sourceCode;
7205
8503
  const patterns = {
7206
8504
  "-": pattern.replaceAll(/[*_]/gu, "-"),
@@ -7242,8 +8540,13 @@ const rules$1 = [
7242
8540
  heading_casing_default,
7243
8541
  level1_heading_style_default,
7244
8542
  level2_heading_style_default,
8543
+ link_bracket_newline_default,
8544
+ link_bracket_spacing_default,
8545
+ link_destination_style_default,
8546
+ link_title_style_default,
7245
8547
  list_marker_alignment_default,
7246
8548
  no_laziness_blockquotes_default,
8549
+ no_multi_spaces_default,
7247
8550
  no_multiple_empty_lines_default,
7248
8551
  no_text_backslash_linebreak_default,
7249
8552
  no_trailing_spaces_default,
@@ -7269,6 +8572,37 @@ const rules$1 = [
7269
8572
  //#region src/configs/recommended.ts
7270
8573
  var recommended_exports = {};
7271
8574
  __export(recommended_exports, {
8575
+ files: () => files$1,
8576
+ language: () => language$1,
8577
+ languageOptions: () => languageOptions$1,
8578
+ name: () => name$2,
8579
+ plugins: () => plugins$1,
8580
+ rules: () => rules$3
8581
+ });
8582
+ const name$2 = "markdown-preferences/recommended";
8583
+ const files$1 = ["*.md", "**/*.md"];
8584
+ const language$1 = "markdown/gfm";
8585
+ const languageOptions$1 = { frontmatter: "yaml" };
8586
+ const plugins$1 = {
8587
+ markdown,
8588
+ get "markdown-preferences"() {
8589
+ return src_default;
8590
+ }
8591
+ };
8592
+ const rules$3 = {
8593
+ "markdown-preferences/blockquote-marker-alignment": "error",
8594
+ "markdown-preferences/hard-linebreak-style": "error",
8595
+ "markdown-preferences/list-marker-alignment": "error",
8596
+ "markdown-preferences/no-laziness-blockquotes": "error",
8597
+ "markdown-preferences/no-text-backslash-linebreak": "error",
8598
+ "markdown-preferences/prefer-autolinks": "error",
8599
+ "markdown-preferences/prefer-fenced-code-blocks": "error"
8600
+ };
8601
+
8602
+ //#endregion
8603
+ //#region src/configs/standard.ts
8604
+ var standard_exports = {};
8605
+ __export(standard_exports, {
7272
8606
  files: () => files,
7273
8607
  language: () => language,
7274
8608
  languageOptions: () => languageOptions,
@@ -7287,14 +8621,38 @@ const plugins = {
7287
8621
  }
7288
8622
  };
7289
8623
  const rules$2 = {
8624
+ "markdown-preferences/atx-heading-closing-sequence-length": "error",
8625
+ "markdown-preferences/atx-heading-closing-sequence": "error",
7290
8626
  "markdown-preferences/blockquote-marker-alignment": "error",
8627
+ "markdown-preferences/bullet-list-marker-style": "error",
8628
+ "markdown-preferences/code-fence-length": "error",
8629
+ "markdown-preferences/code-fence-style": "error",
8630
+ "markdown-preferences/emphasis-delimiters-style": "error",
7291
8631
  "markdown-preferences/hard-linebreak-style": "error",
8632
+ "markdown-preferences/level1-heading-style": "error",
8633
+ "markdown-preferences/level2-heading-style": "error",
8634
+ "markdown-preferences/link-bracket-newline": "error",
8635
+ "markdown-preferences/link-bracket-spacing": "error",
8636
+ "markdown-preferences/link-destination-style": "error",
8637
+ "markdown-preferences/link-title-style": "error",
7292
8638
  "markdown-preferences/list-marker-alignment": "error",
7293
8639
  "markdown-preferences/no-laziness-blockquotes": "error",
8640
+ "markdown-preferences/no-multi-spaces": "error",
8641
+ "markdown-preferences/no-multiple-empty-lines": "error",
7294
8642
  "markdown-preferences/no-text-backslash-linebreak": "error",
8643
+ "markdown-preferences/no-trailing-spaces": "error",
8644
+ "markdown-preferences/ordered-list-marker-sequence": "error",
8645
+ "markdown-preferences/ordered-list-marker-start": "error",
8646
+ "markdown-preferences/ordered-list-marker-style": "error",
7295
8647
  "markdown-preferences/padding-line-between-blocks": "error",
7296
8648
  "markdown-preferences/prefer-autolinks": "error",
7297
- "markdown-preferences/prefer-fenced-code-blocks": "error"
8649
+ "markdown-preferences/prefer-fenced-code-blocks": "error",
8650
+ "markdown-preferences/setext-heading-underline-length": "error",
8651
+ "markdown-preferences/sort-definitions": "error",
8652
+ "markdown-preferences/strikethrough-delimiters-style": "error",
8653
+ "markdown-preferences/thematic-break-character-style": "error",
8654
+ "markdown-preferences/thematic-break-length": "error",
8655
+ "markdown-preferences/thematic-break-sequence-pattern": "error"
7298
8656
  };
7299
8657
 
7300
8658
  //#endregion
@@ -7305,11 +8663,14 @@ __export(meta_exports, {
7305
8663
  version: () => version
7306
8664
  });
7307
8665
  const name = "eslint-plugin-markdown-preferences";
7308
- const version = "0.20.0";
8666
+ const version = "0.22.0";
7309
8667
 
7310
8668
  //#endregion
7311
8669
  //#region src/index.ts
7312
- const configs = { recommended: recommended_exports };
8670
+ const configs = {
8671
+ recommended: recommended_exports,
8672
+ standard: standard_exports
8673
+ };
7313
8674
  const rules = rules$1.reduce((obj, r) => {
7314
8675
  obj[r.meta.docs.ruleName] = r;
7315
8676
  return obj;