eslint-plugin-markdown-preferences 0.26.0 → 0.27.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/README.md +46 -2
- package/lib/index.d.ts +172 -7
- package/lib/index.js +646 -46
- package/package.json +11 -1
package/README.md
CHANGED
|
@@ -58,17 +58,18 @@ Example **eslint.config.js**:
|
|
|
58
58
|
import { defineConfig } from "eslint/config";
|
|
59
59
|
// import markdown from "@eslint/markdown";
|
|
60
60
|
import markdownPreferences from "eslint-plugin-markdown-preferences";
|
|
61
|
-
export default [
|
|
61
|
+
export default defineConfig([
|
|
62
62
|
// add more generic rule sets here, such as:
|
|
63
63
|
// markdown.configs.recommended,
|
|
64
64
|
markdownPreferences.configs.recommended,
|
|
65
65
|
{
|
|
66
|
+
files: ["**/*.md", "*.md"],
|
|
66
67
|
rules: {
|
|
67
68
|
// override/add rules settings here, such as:
|
|
68
69
|
// 'markdown-preferences/prefer-linked-words': 'error'
|
|
69
70
|
},
|
|
70
71
|
},
|
|
71
|
-
];
|
|
72
|
+
]);
|
|
72
73
|
```
|
|
73
74
|
|
|
74
75
|
This plugin provides configs:
|
|
@@ -78,6 +79,49 @@ This plugin provides configs:
|
|
|
78
79
|
|
|
79
80
|
See [the rule list](https://ota-meshi.github.io/eslint-plugin-markdown-preferences/rules/) to get the `rules` that this plugin provides.
|
|
80
81
|
|
|
82
|
+
##### Using Extended Syntax
|
|
83
|
+
|
|
84
|
+
This plugin experimentally supports some extended Markdown syntax.\
|
|
85
|
+
To use these extended syntaxes, set the `markdown-preferences/extended-syntax` language option.
|
|
86
|
+
|
|
87
|
+
```js
|
|
88
|
+
import { defineConfig } from "eslint/config";
|
|
89
|
+
import markdownPreferences from "eslint-plugin-markdown-preferences";
|
|
90
|
+
export default defineConfig([
|
|
91
|
+
{
|
|
92
|
+
extends: [markdownPreferences.configs.recommended],
|
|
93
|
+
language: "markdown-preferences/extended-syntax",
|
|
94
|
+
},
|
|
95
|
+
]);
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
The following syntaxes are supported:
|
|
99
|
+
|
|
100
|
+
- [Custom Containers](https://vitepress.dev/guide/markdown#custom-containers)\
|
|
101
|
+
Example:
|
|
102
|
+
|
|
103
|
+
```md
|
|
104
|
+
::: warning
|
|
105
|
+
This is a warning box.
|
|
106
|
+
:::
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
- [Mathematical Expressions](https://docs.github.com/get-started/writing-on-github/working-with-advanced-formatting/writing-mathematical-expressions)\
|
|
110
|
+
Example:
|
|
111
|
+
|
|
112
|
+
```md
|
|
113
|
+
$$
|
|
114
|
+
E = mc^2
|
|
115
|
+
$$
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
- [VitePress-style Import Code Snippets](https://vitepress.dev/guide/markdown#import-code-snippets) syntax using triple left angle brackets\
|
|
119
|
+
Example:
|
|
120
|
+
|
|
121
|
+
```md
|
|
122
|
+
<<< @/filepath
|
|
123
|
+
```
|
|
124
|
+
|
|
81
125
|
#### Legacy Config (`.eslintrc`)
|
|
82
126
|
|
|
83
127
|
Is not supported.
|
package/lib/index.d.ts
CHANGED
|
@@ -1,7 +1,12 @@
|
|
|
1
1
|
import markdown from "@eslint/markdown";
|
|
2
|
+
import * as math from "mdast-util-math";
|
|
2
3
|
import * as _eslint_core0 from "@eslint/core";
|
|
3
|
-
import { RuleDefinition } from "@eslint/core";
|
|
4
|
+
import { File, Language, OkParseResult, ParseResult, RuleDefinition, SourceLocation } from "@eslint/core";
|
|
4
5
|
import { ESLint, Linter } from "eslint";
|
|
6
|
+
import * as eslint from "@eslint/markdown/types";
|
|
7
|
+
import { MarkdownLanguageContext, MarkdownLanguageOptions } from "@eslint/markdown/types";
|
|
8
|
+
import * as mdast from "mdast";
|
|
9
|
+
import { TextSourceCodeBase } from "@eslint/plugin-kit";
|
|
5
10
|
|
|
6
11
|
//#region src/rule-types.d.ts
|
|
7
12
|
declare module 'eslint' {
|
|
@@ -380,12 +385,12 @@ type MarkdownPreferencesOrderedListMarkerStyle = [] | [{
|
|
|
380
385
|
}[];
|
|
381
386
|
}];
|
|
382
387
|
type MarkdownPreferencesPaddingLineBetweenBlocks = {
|
|
383
|
-
prev: (("blockquote" | "code" | "heading" | "html" | "list" | "paragraph" | "thematic-break" | "table" | "link-definition" | "footnote-definition" | "frontmatter" | "*") | [("blockquote" | "code" | "heading" | "html" | "list" | "paragraph" | "thematic-break" | "table" | "link-definition" | "footnote-definition" | "frontmatter" | "*"), ...(("blockquote" | "code" | "heading" | "html" | "list" | "paragraph" | "thematic-break" | "table" | "link-definition" | "footnote-definition" | "frontmatter" | "*"))[]] | {
|
|
384
|
-
type: (("blockquote" | "code" | "heading" | "html" | "list" | "paragraph" | "thematic-break" | "table" | "link-definition" | "footnote-definition" | "frontmatter" | "*") | [("blockquote" | "code" | "heading" | "html" | "list" | "paragraph" | "thematic-break" | "table" | "link-definition" | "footnote-definition" | "frontmatter" | "*"), ...(("blockquote" | "code" | "heading" | "html" | "list" | "paragraph" | "thematic-break" | "table" | "link-definition" | "footnote-definition" | "frontmatter" | "*"))[]]);
|
|
388
|
+
prev: (("blockquote" | "code" | "heading" | "html" | "list" | "paragraph" | "thematic-break" | "table" | "link-definition" | "footnote-definition" | "frontmatter" | "custom-container" | "math" | "import-code-snippet" | "*") | [("blockquote" | "code" | "heading" | "html" | "list" | "paragraph" | "thematic-break" | "table" | "link-definition" | "footnote-definition" | "frontmatter" | "custom-container" | "math" | "import-code-snippet" | "*"), ...(("blockquote" | "code" | "heading" | "html" | "list" | "paragraph" | "thematic-break" | "table" | "link-definition" | "footnote-definition" | "frontmatter" | "custom-container" | "math" | "import-code-snippet" | "*"))[]] | {
|
|
389
|
+
type: (("blockquote" | "code" | "heading" | "html" | "list" | "paragraph" | "thematic-break" | "table" | "link-definition" | "footnote-definition" | "frontmatter" | "custom-container" | "math" | "import-code-snippet" | "*") | [("blockquote" | "code" | "heading" | "html" | "list" | "paragraph" | "thematic-break" | "table" | "link-definition" | "footnote-definition" | "frontmatter" | "custom-container" | "math" | "import-code-snippet" | "*"), ...(("blockquote" | "code" | "heading" | "html" | "list" | "paragraph" | "thematic-break" | "table" | "link-definition" | "footnote-definition" | "frontmatter" | "custom-container" | "math" | "import-code-snippet" | "*"))[]]);
|
|
385
390
|
in?: ("list" | "blockquote" | "footnote-definition");
|
|
386
391
|
});
|
|
387
|
-
next: (("blockquote" | "code" | "heading" | "html" | "list" | "paragraph" | "thematic-break" | "table" | "link-definition" | "footnote-definition" | "frontmatter" | "*") | [("blockquote" | "code" | "heading" | "html" | "list" | "paragraph" | "thematic-break" | "table" | "link-definition" | "footnote-definition" | "frontmatter" | "*"), ...(("blockquote" | "code" | "heading" | "html" | "list" | "paragraph" | "thematic-break" | "table" | "link-definition" | "footnote-definition" | "frontmatter" | "*"))[]] | {
|
|
388
|
-
type: (("blockquote" | "code" | "heading" | "html" | "list" | "paragraph" | "thematic-break" | "table" | "link-definition" | "footnote-definition" | "frontmatter" | "*") | [("blockquote" | "code" | "heading" | "html" | "list" | "paragraph" | "thematic-break" | "table" | "link-definition" | "footnote-definition" | "frontmatter" | "*"), ...(("blockquote" | "code" | "heading" | "html" | "list" | "paragraph" | "thematic-break" | "table" | "link-definition" | "footnote-definition" | "frontmatter" | "*"))[]]);
|
|
392
|
+
next: (("blockquote" | "code" | "heading" | "html" | "list" | "paragraph" | "thematic-break" | "table" | "link-definition" | "footnote-definition" | "frontmatter" | "custom-container" | "math" | "import-code-snippet" | "*") | [("blockquote" | "code" | "heading" | "html" | "list" | "paragraph" | "thematic-break" | "table" | "link-definition" | "footnote-definition" | "frontmatter" | "custom-container" | "math" | "import-code-snippet" | "*"), ...(("blockquote" | "code" | "heading" | "html" | "list" | "paragraph" | "thematic-break" | "table" | "link-definition" | "footnote-definition" | "frontmatter" | "custom-container" | "math" | "import-code-snippet" | "*"))[]] | {
|
|
393
|
+
type: (("blockquote" | "code" | "heading" | "html" | "list" | "paragraph" | "thematic-break" | "table" | "link-definition" | "footnote-definition" | "frontmatter" | "custom-container" | "math" | "import-code-snippet" | "*") | [("blockquote" | "code" | "heading" | "html" | "list" | "paragraph" | "thematic-break" | "table" | "link-definition" | "footnote-definition" | "frontmatter" | "custom-container" | "math" | "import-code-snippet" | "*"), ...(("blockquote" | "code" | "heading" | "html" | "list" | "paragraph" | "thematic-break" | "table" | "link-definition" | "footnote-definition" | "frontmatter" | "custom-container" | "math" | "import-code-snippet" | "*"))[]]);
|
|
389
394
|
in?: ("list" | "blockquote" | "footnote-definition");
|
|
390
395
|
});
|
|
391
396
|
blankLine: ("any" | "never" | "always");
|
|
@@ -498,7 +503,161 @@ declare namespace meta_d_exports {
|
|
|
498
503
|
export { name, version };
|
|
499
504
|
}
|
|
500
505
|
declare const name: "eslint-plugin-markdown-preferences";
|
|
501
|
-
declare const version: "0.
|
|
506
|
+
declare const version: "0.27.0";
|
|
507
|
+
//#endregion
|
|
508
|
+
//#region src/language/ast-types.d.ts
|
|
509
|
+
type Node = mdast.Node;
|
|
510
|
+
type Root = ExtendChildren<mdast.Root, RootContent>;
|
|
511
|
+
type Blockquote = ExtendChildren<mdast.Blockquote, CustomContainer>;
|
|
512
|
+
type Break = mdast.Break;
|
|
513
|
+
type Code = mdast.Code;
|
|
514
|
+
type Definition = mdast.Definition;
|
|
515
|
+
type Delete = mdast.Delete;
|
|
516
|
+
type Emphasis = mdast.Emphasis;
|
|
517
|
+
type FootnoteDefinition = ExtendChildren<mdast.FootnoteDefinition, CustomContainer>;
|
|
518
|
+
type FootnoteReference = mdast.FootnoteReference;
|
|
519
|
+
type Heading = mdast.Heading;
|
|
520
|
+
type Html = mdast.Html;
|
|
521
|
+
type Image = mdast.Image;
|
|
522
|
+
type ImageReference = mdast.ImageReference;
|
|
523
|
+
type InlineCode = mdast.InlineCode;
|
|
524
|
+
type Link = mdast.Link;
|
|
525
|
+
type LinkReference = mdast.LinkReference;
|
|
526
|
+
type List = mdast.List;
|
|
527
|
+
type ListItem = ExtendChildren<mdast.ListItem, CustomContainer>;
|
|
528
|
+
type Paragraph = mdast.Paragraph;
|
|
529
|
+
type Strong = mdast.Strong;
|
|
530
|
+
type Table = mdast.Table;
|
|
531
|
+
type TableCell = mdast.TableCell;
|
|
532
|
+
type TableRow = mdast.TableRow;
|
|
533
|
+
type Text = mdast.Text;
|
|
534
|
+
type ThematicBreak = mdast.ThematicBreak;
|
|
535
|
+
type Yaml = mdast.Yaml;
|
|
536
|
+
type Math = math.Math;
|
|
537
|
+
type InlineMath = math.InlineMath;
|
|
538
|
+
type Toml = eslint.Toml;
|
|
539
|
+
type Json = eslint.Json;
|
|
540
|
+
interface CustomContainer extends ExtendChildren<mdast.Parent, CustomContainer | ImportCodeSnippet> {
|
|
541
|
+
/**
|
|
542
|
+
* Node type of mdast custom container.
|
|
543
|
+
*/
|
|
544
|
+
type: "customContainer";
|
|
545
|
+
/**
|
|
546
|
+
* Info string (e.g., "warning" in ::: warning ... :::).
|
|
547
|
+
*/
|
|
548
|
+
info: string | null;
|
|
549
|
+
/**
|
|
550
|
+
* Children of custom container.
|
|
551
|
+
*/
|
|
552
|
+
children: (CustomContainer | BlockContent | DefinitionContent)[];
|
|
553
|
+
}
|
|
554
|
+
interface ImportCodeSnippet extends mdast.Literal {
|
|
555
|
+
/**
|
|
556
|
+
* Node type of mdast import code snippet.
|
|
557
|
+
*/
|
|
558
|
+
type: "importCodeSnippet";
|
|
559
|
+
}
|
|
560
|
+
type RootContent = RootContentMap[keyof RootContentMap];
|
|
561
|
+
type BlockContent = RootContentMap[keyof mdast.BlockContentMap] | ImportCodeSnippet;
|
|
562
|
+
type DefinitionContent = RootContentMap[keyof mdast.DefinitionContentMap];
|
|
563
|
+
type ExtendChildren<N extends mdast.Node & {
|
|
564
|
+
children: mdast.Node[];
|
|
565
|
+
}, C extends mdast.Node> = Omit<N, "children"> & {
|
|
566
|
+
children: (MapChild<N["children"][number]> | C)[];
|
|
567
|
+
};
|
|
568
|
+
type MapChild<N extends mdast.Node> = N["type"] extends RootContent["type"] ? RootContentMap[N["type"]] : N;
|
|
569
|
+
interface RootContentMap {
|
|
570
|
+
blockquote: Blockquote;
|
|
571
|
+
break: Break;
|
|
572
|
+
code: Code;
|
|
573
|
+
definition: Definition;
|
|
574
|
+
delete: Delete;
|
|
575
|
+
emphasis: Emphasis;
|
|
576
|
+
footnoteDefinition: FootnoteDefinition;
|
|
577
|
+
footnoteReference: FootnoteReference;
|
|
578
|
+
heading: Heading;
|
|
579
|
+
html: Html;
|
|
580
|
+
image: Image;
|
|
581
|
+
imageReference: ImageReference;
|
|
582
|
+
inlineCode: InlineCode;
|
|
583
|
+
link: Link;
|
|
584
|
+
linkReference: LinkReference;
|
|
585
|
+
list: List;
|
|
586
|
+
listItem: ListItem;
|
|
587
|
+
paragraph: Paragraph;
|
|
588
|
+
strong: Strong;
|
|
589
|
+
table: Table;
|
|
590
|
+
tableCell: TableCell;
|
|
591
|
+
tableRow: TableRow;
|
|
592
|
+
text: Text;
|
|
593
|
+
thematicBreak: ThematicBreak;
|
|
594
|
+
yaml: Yaml;
|
|
595
|
+
toml: Toml;
|
|
596
|
+
json: Json;
|
|
597
|
+
customContainer: CustomContainer;
|
|
598
|
+
inlineMath: InlineMath;
|
|
599
|
+
math: Math;
|
|
600
|
+
importCodeSnippet: ImportCodeSnippet;
|
|
601
|
+
}
|
|
602
|
+
//#endregion
|
|
603
|
+
//#region src/language/extended-markdown-ianguage.d.ts
|
|
604
|
+
type ExtendedMarkdownSourceCode = TextSourceCodeBase<{
|
|
605
|
+
LangOptions: MarkdownLanguageOptions;
|
|
606
|
+
RootNode: Root;
|
|
607
|
+
SyntaxElementWithLoc: Node;
|
|
608
|
+
ConfigNode: {
|
|
609
|
+
value: string;
|
|
610
|
+
position: SourceLocation;
|
|
611
|
+
};
|
|
612
|
+
}>;
|
|
613
|
+
declare class ExtendedMarkdownLanguage implements Language {
|
|
614
|
+
/**
|
|
615
|
+
* The type of file to read.
|
|
616
|
+
* @type {"text"}
|
|
617
|
+
*/
|
|
618
|
+
readonly fileType: "text";
|
|
619
|
+
/**
|
|
620
|
+
* The line number at which the parser starts counting.
|
|
621
|
+
* @type {0|1}
|
|
622
|
+
*/
|
|
623
|
+
readonly lineStart: 0 | 1;
|
|
624
|
+
/**
|
|
625
|
+
* The column number at which the parser starts counting.
|
|
626
|
+
* @type {0|1}
|
|
627
|
+
*/
|
|
628
|
+
readonly columnStart: 0 | 1;
|
|
629
|
+
/**
|
|
630
|
+
* The name of the key that holds the type of the node.
|
|
631
|
+
* @type {string}
|
|
632
|
+
*/
|
|
633
|
+
readonly nodeTypeKey: string;
|
|
634
|
+
/**
|
|
635
|
+
* Default language options. User-defined options are merged with this object.
|
|
636
|
+
* @type {MarkdownLanguageOptions}
|
|
637
|
+
*/
|
|
638
|
+
readonly defaultLanguageOptions: MarkdownLanguageOptions;
|
|
639
|
+
/**
|
|
640
|
+
* Validates the language options.
|
|
641
|
+
* @param {MarkdownLanguageOptions} languageOptions The language options to validate.
|
|
642
|
+
* @returns {void}
|
|
643
|
+
* @throws {Error} When the language options are invalid.
|
|
644
|
+
*/
|
|
645
|
+
validateLanguageOptions(languageOptions: MarkdownLanguageOptions): void;
|
|
646
|
+
/**
|
|
647
|
+
* Parses the given file into an AST.
|
|
648
|
+
* @param {File} file The virtual file to parse.
|
|
649
|
+
* @param {MarkdownLanguageContext} _context The options to use for parsing.
|
|
650
|
+
* @returns {ParseResult<Root>} The result of parsing.
|
|
651
|
+
*/
|
|
652
|
+
parse(file: File, _context: MarkdownLanguageContext): ParseResult<Root>;
|
|
653
|
+
/**
|
|
654
|
+
* Creates a new `MarkdownSourceCode` object from the given information.
|
|
655
|
+
* @param {File} file The virtual file to create a `MarkdownSourceCode` object from.
|
|
656
|
+
* @param {OkParseResult<Root>} parseResult The result returned from `parse()`.
|
|
657
|
+
* @returns {MarkdownSourceCode} The new `MarkdownSourceCode` object.
|
|
658
|
+
*/
|
|
659
|
+
createSourceCode(file: File, parseResult: OkParseResult<Root>): ExtendedMarkdownSourceCode;
|
|
660
|
+
}
|
|
502
661
|
//#endregion
|
|
503
662
|
//#region src/index.d.ts
|
|
504
663
|
declare const configs: {
|
|
@@ -510,8 +669,14 @@ declare const resources: {
|
|
|
510
669
|
defaultPreserveWords: string[];
|
|
511
670
|
defaultMinorWords: string[];
|
|
512
671
|
};
|
|
672
|
+
declare const languages: {
|
|
673
|
+
"extended-syntax": ExtendedMarkdownLanguage;
|
|
674
|
+
};
|
|
513
675
|
declare const _default: {
|
|
514
676
|
meta: typeof meta_d_exports;
|
|
677
|
+
languages: {
|
|
678
|
+
"extended-syntax": ExtendedMarkdownLanguage;
|
|
679
|
+
};
|
|
515
680
|
configs: {
|
|
516
681
|
recommended: typeof recommended_d_exports;
|
|
517
682
|
standard: typeof standard_d_exports;
|
|
@@ -523,4 +688,4 @@ declare const _default: {
|
|
|
523
688
|
};
|
|
524
689
|
};
|
|
525
690
|
//#endregion
|
|
526
|
-
export { RuleOptions, configs, _default as default, meta_d_exports as meta, resources, rules };
|
|
691
|
+
export { RuleOptions, configs, _default as default, languages, meta_d_exports as meta, resources, rules };
|
package/lib/index.js
CHANGED
|
@@ -3,6 +3,16 @@ import stringWidth from "string-width";
|
|
|
3
3
|
import emojiRegex from "emoji-regex-xs";
|
|
4
4
|
import path from "node:path";
|
|
5
5
|
import markdown from "@eslint/markdown";
|
|
6
|
+
import { fromMarkdown } from "mdast-util-from-markdown";
|
|
7
|
+
import { frontmatterFromMarkdown } from "mdast-util-frontmatter";
|
|
8
|
+
import { gfmFromMarkdown } from "mdast-util-gfm";
|
|
9
|
+
import { frontmatter } from "micromark-extension-frontmatter";
|
|
10
|
+
import { gfm } from "micromark-extension-gfm";
|
|
11
|
+
import { math } from "micromark-extension-math";
|
|
12
|
+
import { mathFromMarkdown } from "mdast-util-math";
|
|
13
|
+
import { markdownLineEnding, markdownSpace } from "micromark-util-character";
|
|
14
|
+
import { codes, constants, types } from "micromark-util-symbol";
|
|
15
|
+
import { factorySpace } from "micromark-factory-space";
|
|
6
16
|
|
|
7
17
|
//#region src/utils/index.ts
|
|
8
18
|
/**
|
|
@@ -957,14 +967,14 @@ var bullet_list_marker_style_default = createRule("bullet-list-marker-style", {
|
|
|
957
967
|
if (node.ordered) return;
|
|
958
968
|
checkBulletList(node);
|
|
959
969
|
},
|
|
960
|
-
"root, blockquote, listItem, footnoteDefinition"(node) {
|
|
970
|
+
"root, blockquote, listItem, footnoteDefinition, customContainer"(node) {
|
|
961
971
|
containerStack = {
|
|
962
972
|
node,
|
|
963
973
|
level: node.type === "listItem" ? containerStack.level + 1 : 1,
|
|
964
974
|
upper: containerStack
|
|
965
975
|
};
|
|
966
976
|
},
|
|
967
|
-
"root, blockquote, listItem, footnoteDefinition:exit"() {
|
|
977
|
+
"root, blockquote, listItem, footnoteDefinition, customContainer:exit"() {
|
|
968
978
|
containerStack = containerStack.upper;
|
|
969
979
|
}
|
|
970
980
|
};
|
|
@@ -1117,10 +1127,10 @@ var canonical_code_block_language_default = createRule("canonical-code-block-lan
|
|
|
1117
1127
|
},
|
|
1118
1128
|
create(context) {
|
|
1119
1129
|
const sourceCode = context.sourceCode;
|
|
1120
|
-
const languages = context.options[0]?.languages || DEFAULT_LANGUAGES;
|
|
1130
|
+
const languages$1 = context.options[0]?.languages || DEFAULT_LANGUAGES;
|
|
1121
1131
|
return { code(node) {
|
|
1122
|
-
if (!node.lang || !languages[node.lang]) return;
|
|
1123
|
-
const canonical = languages[node.lang];
|
|
1132
|
+
if (!node.lang || !languages$1[node.lang]) return;
|
|
1133
|
+
const canonical = languages$1[node.lang];
|
|
1124
1134
|
const current = node.lang;
|
|
1125
1135
|
if (current === canonical) return;
|
|
1126
1136
|
const parsed = parseFencedCodeBlock(sourceCode, node);
|
|
@@ -1542,7 +1552,12 @@ var definitions_last_default = createRule("definitions-last", {
|
|
|
1542
1552
|
if (c === "\n") lineFeeds++;
|
|
1543
1553
|
}
|
|
1544
1554
|
yield fixer.removeRange([rangeStart, range[1]]);
|
|
1545
|
-
|
|
1555
|
+
const startColumnOffset = loc.start.column - 1;
|
|
1556
|
+
const insertLines = sourceCode.lines.slice(loc.start.line - 1, loc.end.line).map((lineText, i, arr) => {
|
|
1557
|
+
if (i === arr.length - 1) return lineText.slice(startColumnOffset, loc.end.column - 1);
|
|
1558
|
+
return lineText.slice(startColumnOffset);
|
|
1559
|
+
});
|
|
1560
|
+
let insertText = sourceCode.text.slice(rangeStart, lineStart) + insertLines.join(/\r?\n/u.exec(sourceCode.text)?.[0] ?? "\n");
|
|
1546
1561
|
if (prev.type === "footnoteDefinition" && node.type !== "footnoteDefinition" && lineFeeds <= 1) insertText = `\n${insertText}`;
|
|
1547
1562
|
if (next && node.type === "footnoteDefinition" && next.type !== "footnoteDefinition") {
|
|
1548
1563
|
const prevLoc = sourceCode.getLoc(prev);
|
|
@@ -5291,6 +5306,108 @@ function parseListItem(sourceCode, node) {
|
|
|
5291
5306
|
};
|
|
5292
5307
|
}
|
|
5293
5308
|
|
|
5309
|
+
//#endregion
|
|
5310
|
+
//#region src/utils/math-block.ts
|
|
5311
|
+
/**
|
|
5312
|
+
* Parse the math block.
|
|
5313
|
+
*/
|
|
5314
|
+
function parseMathBlock(sourceCode, node) {
|
|
5315
|
+
const range = sourceCode.getRange(node);
|
|
5316
|
+
const text = sourceCode.text.slice(...range);
|
|
5317
|
+
const parsedOpening = parseMathOpeningSequenceFromText(text);
|
|
5318
|
+
if (parsedOpening === null) return null;
|
|
5319
|
+
const openingSequenceRange = [range[0], range[0] + parsedOpening.openingSequence.length];
|
|
5320
|
+
const openingSequence = {
|
|
5321
|
+
text: parsedOpening.openingSequence,
|
|
5322
|
+
range: openingSequenceRange,
|
|
5323
|
+
loc: getSourceLocationFromRange(sourceCode, node, openingSequenceRange)
|
|
5324
|
+
};
|
|
5325
|
+
const parsedClosing = parseMathClosingSequenceFromText(text);
|
|
5326
|
+
if (parsedClosing == null) return null;
|
|
5327
|
+
const spaceAfterClosingRange = [range[1] - parsedClosing.after.length, range[1]];
|
|
5328
|
+
const spaceAfterClosing = {
|
|
5329
|
+
text: parsedClosing.after,
|
|
5330
|
+
range: spaceAfterClosingRange,
|
|
5331
|
+
loc: getSourceLocationFromRange(sourceCode, node, spaceAfterClosingRange)
|
|
5332
|
+
};
|
|
5333
|
+
const closingSequenceRange = [spaceAfterClosing.range[0] - parsedClosing.closingSequence.length, spaceAfterClosing.range[0]];
|
|
5334
|
+
const closingSequence = {
|
|
5335
|
+
text: parsedClosing.closingSequence,
|
|
5336
|
+
range: closingSequenceRange,
|
|
5337
|
+
loc: getSourceLocationFromRange(sourceCode, node, closingSequenceRange)
|
|
5338
|
+
};
|
|
5339
|
+
const contentRange = [openingSequence.range[1] + parsedOpening.after.length, closingSequence.range[0] - parsedClosing.before.length];
|
|
5340
|
+
const contentText = sourceCode.text.slice(...contentRange);
|
|
5341
|
+
return {
|
|
5342
|
+
openingSequence,
|
|
5343
|
+
content: {
|
|
5344
|
+
text: contentText,
|
|
5345
|
+
range: contentRange,
|
|
5346
|
+
loc: getSourceLocationFromRange(sourceCode, node, contentRange)
|
|
5347
|
+
},
|
|
5348
|
+
closingSequence,
|
|
5349
|
+
after: spaceAfterClosing.range[0] < spaceAfterClosing.range[1] ? spaceAfterClosing : null
|
|
5350
|
+
};
|
|
5351
|
+
}
|
|
5352
|
+
/**
|
|
5353
|
+
* Parse the opening sequence from a text string.
|
|
5354
|
+
*/
|
|
5355
|
+
function parseMathOpeningSequenceFromText(text) {
|
|
5356
|
+
if (!text.startsWith("$")) return null;
|
|
5357
|
+
let openingSequenceAfterOffset = 1;
|
|
5358
|
+
while (openingSequenceAfterOffset < text.length && text[openingSequenceAfterOffset] === "$") openingSequenceAfterOffset++;
|
|
5359
|
+
const afterOffset = skipWhitespace(openingSequenceAfterOffset);
|
|
5360
|
+
if (afterOffset === openingSequenceAfterOffset || afterOffset >= text.length) return null;
|
|
5361
|
+
return {
|
|
5362
|
+
openingSequence: text.slice(0, openingSequenceAfterOffset),
|
|
5363
|
+
after: text.slice(openingSequenceAfterOffset, afterOffset)
|
|
5364
|
+
};
|
|
5365
|
+
/**
|
|
5366
|
+
* Skip whitespace characters at the start of the text.
|
|
5367
|
+
*/
|
|
5368
|
+
function skipWhitespace(index) {
|
|
5369
|
+
let inIndent = false;
|
|
5370
|
+
let result = index;
|
|
5371
|
+
let c;
|
|
5372
|
+
while (result < text.length && (c = text[result]) && (isWhitespace(c) || inIndent && c === ">")) {
|
|
5373
|
+
result++;
|
|
5374
|
+
if (c === "\n") inIndent = true;
|
|
5375
|
+
else if (inIndent) inIndent = isWhitespace(c) || c === ">";
|
|
5376
|
+
}
|
|
5377
|
+
return result;
|
|
5378
|
+
}
|
|
5379
|
+
}
|
|
5380
|
+
/**
|
|
5381
|
+
* Parse the closing sequence from a text string.
|
|
5382
|
+
*/
|
|
5383
|
+
function parseMathClosingSequenceFromText(text) {
|
|
5384
|
+
const trimmedEndOffset = skipEndWhitespace(text.length - 1) + 1;
|
|
5385
|
+
if (trimmedEndOffset <= 0 || text[trimmedEndOffset - 1] !== "$") return null;
|
|
5386
|
+
let closingSequenceBeforeOffset = trimmedEndOffset - 2;
|
|
5387
|
+
while (closingSequenceBeforeOffset >= 0 && text[closingSequenceBeforeOffset] === "$") closingSequenceBeforeOffset--;
|
|
5388
|
+
const beforeOffset = skipEndWhitespace(closingSequenceBeforeOffset);
|
|
5389
|
+
if (beforeOffset === closingSequenceBeforeOffset || beforeOffset < 0) return null;
|
|
5390
|
+
return {
|
|
5391
|
+
before: text.slice(beforeOffset + 1, closingSequenceBeforeOffset + 1),
|
|
5392
|
+
closingSequence: text.slice(closingSequenceBeforeOffset + 1, trimmedEndOffset),
|
|
5393
|
+
after: text.slice(trimmedEndOffset)
|
|
5394
|
+
};
|
|
5395
|
+
/**
|
|
5396
|
+
* Skip whitespace characters at the end of the text.
|
|
5397
|
+
*/
|
|
5398
|
+
function skipEndWhitespace(index) {
|
|
5399
|
+
let result = index;
|
|
5400
|
+
let c;
|
|
5401
|
+
while (result >= 0 && (c = text[result]) && isWhitespace(c)) result--;
|
|
5402
|
+
if (c === ">") {
|
|
5403
|
+
let index2 = result - 1;
|
|
5404
|
+
while (index2 >= 0 && (c = text[index2]) && (isSpaceOrTab(c) || c === ">")) index2--;
|
|
5405
|
+
if (c === "\n") return skipEndWhitespace(index2);
|
|
5406
|
+
}
|
|
5407
|
+
return result;
|
|
5408
|
+
}
|
|
5409
|
+
}
|
|
5410
|
+
|
|
5294
5411
|
//#endregion
|
|
5295
5412
|
//#region src/rules/indent.ts
|
|
5296
5413
|
/**
|
|
@@ -5570,7 +5687,10 @@ var indent_default = createRule("indent", {
|
|
|
5570
5687
|
definition: verifyLinkDefinition,
|
|
5571
5688
|
table: verifyTable,
|
|
5572
5689
|
list: verifyList,
|
|
5573
|
-
|
|
5690
|
+
customContainer: verifyCustomContainer,
|
|
5691
|
+
math: verifyMathBlock,
|
|
5692
|
+
importCodeSnippet: verifyImportCodeSnippet,
|
|
5693
|
+
inlineCode: verifyInlineCodeOrInlineMath,
|
|
5574
5694
|
emphasis: verifyEmphasisOrStrongOrDelete,
|
|
5575
5695
|
strong: verifyEmphasisOrStrongOrDelete,
|
|
5576
5696
|
delete: verifyEmphasisOrStrongOrDelete,
|
|
@@ -5579,6 +5699,7 @@ var indent_default = createRule("indent", {
|
|
|
5579
5699
|
footnoteReference: verifyInline,
|
|
5580
5700
|
break: verifyInline,
|
|
5581
5701
|
text: verifyText,
|
|
5702
|
+
inlineMath: verifyInlineCodeOrInlineMath,
|
|
5582
5703
|
blockquote(node) {
|
|
5583
5704
|
verifyBlockquote(node);
|
|
5584
5705
|
blockStack = new BlockquoteStack(node);
|
|
@@ -5635,32 +5756,9 @@ var indent_default = createRule("indent", {
|
|
|
5635
5756
|
verifyLinesIndent([loc.start.line, loc.end.line], (lineNumber) => blockStack.getExpectedIndent({
|
|
5636
5757
|
lineNumber,
|
|
5637
5758
|
block: true
|
|
5638
|
-
}),
|
|
5639
|
-
|
|
5640
|
-
|
|
5641
|
-
*/
|
|
5642
|
-
function* additionalFixes(fixer, info) {
|
|
5643
|
-
if (info.loc.start.line !== loc.start.line) return;
|
|
5644
|
-
for (let lineNumber = loc.start.line + 1; lineNumber < loc.end.line; lineNumber++) {
|
|
5645
|
-
const line = getParsedLines(sourceCode).get(lineNumber);
|
|
5646
|
-
if (!line) continue;
|
|
5647
|
-
if (info.expectedIndentWidth > info.actualIndentWidth) {
|
|
5648
|
-
const before = sliceWidth(line.text, 0, info.actualIndentWidth);
|
|
5649
|
-
const after = sliceWidth(line.text, info.actualIndentWidth);
|
|
5650
|
-
const diffWidth = info.expectedIndentWidth - info.actualIndentWidth;
|
|
5651
|
-
yield fixer.replaceTextRange([line.range[0], line.range[0] + line.text.length], before + " ".repeat(diffWidth) + after);
|
|
5652
|
-
} else {
|
|
5653
|
-
let before = sliceWidth(line.text, 0, info.expectedIndentWidth);
|
|
5654
|
-
let between = sliceWidth(line.text, info.expectedIndentWidth, info.actualIndentWidth);
|
|
5655
|
-
const after = sliceWidth(line.text, info.actualIndentWidth);
|
|
5656
|
-
while (between && !isSpaceOrTab(between)) {
|
|
5657
|
-
before += between[0];
|
|
5658
|
-
between = between.slice(1);
|
|
5659
|
-
}
|
|
5660
|
-
yield fixer.replaceTextRange([line.range[0], line.range[0] + line.text.length], before + after);
|
|
5661
|
-
}
|
|
5662
|
-
}
|
|
5663
|
-
}
|
|
5759
|
+
}), (fixer, info) => {
|
|
5760
|
+
return additionalFixesForCodeBlock(node, fixer, info, loc.start.line + 1, loc.end.line - 1);
|
|
5761
|
+
});
|
|
5664
5762
|
}
|
|
5665
5763
|
/**
|
|
5666
5764
|
* Verify an HTML node.
|
|
@@ -5777,6 +5875,41 @@ var indent_default = createRule("indent", {
|
|
|
5777
5875
|
}
|
|
5778
5876
|
}
|
|
5779
5877
|
/**
|
|
5878
|
+
* Verify a custom container node.
|
|
5879
|
+
*/
|
|
5880
|
+
function verifyCustomContainer(node) {
|
|
5881
|
+
const loc = sourceCode.getLoc(node);
|
|
5882
|
+
verifyLinesIndent([loc.start.line, loc.end.line], (lineNumber) => blockStack.getExpectedIndent({
|
|
5883
|
+
lineNumber,
|
|
5884
|
+
block: true
|
|
5885
|
+
}));
|
|
5886
|
+
}
|
|
5887
|
+
/**
|
|
5888
|
+
* Verify a math node.
|
|
5889
|
+
*/
|
|
5890
|
+
function verifyMathBlock(node) {
|
|
5891
|
+
const parsed = parseMathBlock(sourceCode, node);
|
|
5892
|
+
if (!parsed) return;
|
|
5893
|
+
const loc = sourceCode.getLoc(node);
|
|
5894
|
+
const endLineToBeChecked = inlineToBeChecked(parsed.closingSequence.loc.start);
|
|
5895
|
+
verifyLinesIndent(endLineToBeChecked ? [loc.start.line, loc.end.line] : [loc.start.line], (lineNumber) => blockStack.getExpectedIndent({
|
|
5896
|
+
lineNumber,
|
|
5897
|
+
block: true
|
|
5898
|
+
}), (fixer, info) => {
|
|
5899
|
+
return additionalFixesForCodeBlock(node, fixer, info, loc.start.line + 1, endLineToBeChecked ? loc.end.line - 1 : loc.end.line);
|
|
5900
|
+
});
|
|
5901
|
+
}
|
|
5902
|
+
/**
|
|
5903
|
+
* Verify an import code snippet node.
|
|
5904
|
+
*/
|
|
5905
|
+
function verifyImportCodeSnippet(node) {
|
|
5906
|
+
const loc = sourceCode.getLoc(node);
|
|
5907
|
+
verifyLinesIndent(lineNumbersFromRange(loc.start.line, loc.end.line), (lineNumber) => blockStack.getExpectedIndent({
|
|
5908
|
+
lineNumber,
|
|
5909
|
+
block: true
|
|
5910
|
+
}));
|
|
5911
|
+
}
|
|
5912
|
+
/**
|
|
5780
5913
|
* Verify a footnote definition node.
|
|
5781
5914
|
*/
|
|
5782
5915
|
function verifyFootnoteDefinition(node) {
|
|
@@ -5787,9 +5920,9 @@ var indent_default = createRule("indent", {
|
|
|
5787
5920
|
}));
|
|
5788
5921
|
}
|
|
5789
5922
|
/**
|
|
5790
|
-
* Verify an inline code node.
|
|
5923
|
+
* Verify an inline code/math node.
|
|
5791
5924
|
*/
|
|
5792
|
-
function
|
|
5925
|
+
function verifyInlineCodeOrInlineMath(node) {
|
|
5793
5926
|
const loc = sourceCode.getLoc(node);
|
|
5794
5927
|
if (!inlineToBeChecked(loc.start)) return;
|
|
5795
5928
|
verifyLinesIndent([loc.start.line], (lineNumber) => blockStack.getExpectedIndent({
|
|
@@ -6171,6 +6304,32 @@ var indent_default = createRule("indent", {
|
|
|
6171
6304
|
actualIndentWidth
|
|
6172
6305
|
};
|
|
6173
6306
|
}
|
|
6307
|
+
/**
|
|
6308
|
+
* Additional fixes for code/math block content lines.
|
|
6309
|
+
*/
|
|
6310
|
+
function* additionalFixesForCodeBlock(node, fixer, info, fixStartLine, fixEndLine) {
|
|
6311
|
+
const loc = sourceCode.getLoc(node);
|
|
6312
|
+
if (info.loc.start.line !== loc.start.line) return;
|
|
6313
|
+
for (let lineNumber = fixStartLine; lineNumber <= fixEndLine; lineNumber++) {
|
|
6314
|
+
const line = getParsedLines(sourceCode).get(lineNumber);
|
|
6315
|
+
if (!line) continue;
|
|
6316
|
+
if (info.expectedIndentWidth > info.actualIndentWidth) {
|
|
6317
|
+
const before = sliceWidth(line.text, 0, info.actualIndentWidth);
|
|
6318
|
+
const after = sliceWidth(line.text, info.actualIndentWidth);
|
|
6319
|
+
const diffWidth = info.expectedIndentWidth - info.actualIndentWidth;
|
|
6320
|
+
yield fixer.replaceTextRange([line.range[0], line.range[0] + line.text.length], before + " ".repeat(diffWidth) + after);
|
|
6321
|
+
} else {
|
|
6322
|
+
let before = sliceWidth(line.text, 0, info.expectedIndentWidth);
|
|
6323
|
+
let between = sliceWidth(line.text, info.expectedIndentWidth, info.actualIndentWidth);
|
|
6324
|
+
const after = sliceWidth(line.text, info.actualIndentWidth);
|
|
6325
|
+
while (between && !isSpaceOrTab(between)) {
|
|
6326
|
+
before += between[0];
|
|
6327
|
+
between = between.slice(1);
|
|
6328
|
+
}
|
|
6329
|
+
yield fixer.replaceTextRange([line.range[0], line.range[0] + line.text.length], before + after);
|
|
6330
|
+
}
|
|
6331
|
+
}
|
|
6332
|
+
}
|
|
6174
6333
|
}
|
|
6175
6334
|
});
|
|
6176
6335
|
|
|
@@ -8307,14 +8466,14 @@ var ordered_list_marker_sequence_default = createRule("ordered-list-marker-seque
|
|
|
8307
8466
|
}
|
|
8308
8467
|
}
|
|
8309
8468
|
return {
|
|
8310
|
-
"blockquote, listItem, footnoteDefinition"(node) {
|
|
8469
|
+
"blockquote, listItem, footnoteDefinition, customContainer"(node) {
|
|
8311
8470
|
scope = {
|
|
8312
8471
|
node,
|
|
8313
8472
|
upper: scope,
|
|
8314
8473
|
last: null
|
|
8315
8474
|
};
|
|
8316
8475
|
},
|
|
8317
|
-
"blockquote, listItem, footnoteDefinition:exit"(node) {
|
|
8476
|
+
"blockquote, listItem, footnoteDefinition, customContainer:exit"(node) {
|
|
8318
8477
|
if (scope.node === node) scope = scope.upper;
|
|
8319
8478
|
},
|
|
8320
8479
|
heading() {
|
|
@@ -8396,14 +8555,14 @@ var ordered_list_marker_start_default = createRule("ordered-list-marker-start",
|
|
|
8396
8555
|
});
|
|
8397
8556
|
}
|
|
8398
8557
|
return {
|
|
8399
|
-
"blockquote, listItem, footnoteDefinition"(node) {
|
|
8558
|
+
"blockquote, listItem, footnoteDefinition, customContainer"(node) {
|
|
8400
8559
|
scope = {
|
|
8401
8560
|
node,
|
|
8402
8561
|
upper: scope,
|
|
8403
8562
|
last: null
|
|
8404
8563
|
};
|
|
8405
8564
|
},
|
|
8406
|
-
"blockquote, listItem, footnoteDefinition:exit"(node) {
|
|
8565
|
+
"blockquote, listItem, footnoteDefinition, customContainer:exit"(node) {
|
|
8407
8566
|
if (scope.node === node) scope = scope.upper;
|
|
8408
8567
|
},
|
|
8409
8568
|
heading() {
|
|
@@ -8576,14 +8735,14 @@ var ordered_list_marker_style_default = createRule("ordered-list-marker-style",
|
|
|
8576
8735
|
if (!node.ordered) return;
|
|
8577
8736
|
checkOrderedList(node);
|
|
8578
8737
|
},
|
|
8579
|
-
"root, blockquote, listItem, footnoteDefinition"(node) {
|
|
8738
|
+
"root, blockquote, listItem, footnoteDefinition, customContainer"(node) {
|
|
8580
8739
|
containerStack = {
|
|
8581
8740
|
node,
|
|
8582
8741
|
level: node.type === "listItem" ? containerStack.level + 1 : 1,
|
|
8583
8742
|
upper: containerStack
|
|
8584
8743
|
};
|
|
8585
8744
|
},
|
|
8586
|
-
"root, blockquote, listItem, footnoteDefinition:exit"() {
|
|
8745
|
+
"root, blockquote, listItem, footnoteDefinition, customContainer:exit"() {
|
|
8587
8746
|
containerStack = containerStack.upper;
|
|
8588
8747
|
}
|
|
8589
8748
|
};
|
|
@@ -8631,6 +8790,9 @@ const BLOCK_TYPES = [
|
|
|
8631
8790
|
"link-definition",
|
|
8632
8791
|
"footnote-definition",
|
|
8633
8792
|
"frontmatter",
|
|
8793
|
+
"custom-container",
|
|
8794
|
+
"math",
|
|
8795
|
+
"import-code-snippet",
|
|
8634
8796
|
"*"
|
|
8635
8797
|
];
|
|
8636
8798
|
const BLOCK_TYPE_SCHEMAS = [{
|
|
@@ -8670,7 +8832,10 @@ const BLOCK_TYPE_MAP = {
|
|
|
8670
8832
|
footnoteDefinition: "footnote-definition",
|
|
8671
8833
|
json: "frontmatter",
|
|
8672
8834
|
toml: "frontmatter",
|
|
8673
|
-
yaml: "frontmatter"
|
|
8835
|
+
yaml: "frontmatter",
|
|
8836
|
+
customContainer: "custom-container",
|
|
8837
|
+
math: "math",
|
|
8838
|
+
importCodeSnippet: "import-code-snippet"
|
|
8674
8839
|
};
|
|
8675
8840
|
/**
|
|
8676
8841
|
* Get the block type of a node
|
|
@@ -8866,10 +9031,10 @@ var padding_line_between_blocks_default = createRule("padding-line-between-block
|
|
|
8866
9031
|
}
|
|
8867
9032
|
}
|
|
8868
9033
|
return {
|
|
8869
|
-
"root, blockquote, listItem, footnoteDefinition"(node) {
|
|
9034
|
+
"root, blockquote, listItem, footnoteDefinition, customContainer"(node) {
|
|
8870
9035
|
containerStack.unshift(node);
|
|
8871
9036
|
},
|
|
8872
|
-
"root, blockquote, listItem, footnoteDefinition:exit"(node) {
|
|
9037
|
+
"root, blockquote, listItem, footnoteDefinition, customContainer:exit"(node) {
|
|
8873
9038
|
checkBlockPadding(node);
|
|
8874
9039
|
containerStack.shift();
|
|
8875
9040
|
}
|
|
@@ -11219,7 +11384,440 @@ var meta_exports = /* @__PURE__ */ __export({
|
|
|
11219
11384
|
version: () => version
|
|
11220
11385
|
});
|
|
11221
11386
|
const name = "eslint-plugin-markdown-preferences";
|
|
11222
|
-
const version = "0.
|
|
11387
|
+
const version = "0.27.0";
|
|
11388
|
+
|
|
11389
|
+
//#endregion
|
|
11390
|
+
//#region src/language/extensions/micromark-custom-container.ts
|
|
11391
|
+
/**
|
|
11392
|
+
* Micromark extension to support custom containers (e.g., ::: warning ... :::).
|
|
11393
|
+
*/
|
|
11394
|
+
function customContainer() {
|
|
11395
|
+
const customContainerOpenConstruct = {
|
|
11396
|
+
name: "customContainer",
|
|
11397
|
+
continuation: {
|
|
11398
|
+
name: "customContainerContinuation",
|
|
11399
|
+
tokenize(effects, ok, nok) {
|
|
11400
|
+
return tokenizeCustomContainerContinuation(this, effects, ok, nok);
|
|
11401
|
+
}
|
|
11402
|
+
},
|
|
11403
|
+
exit(effects) {
|
|
11404
|
+
effects.exit("customContainer");
|
|
11405
|
+
},
|
|
11406
|
+
tokenize(effects, ok, nok) {
|
|
11407
|
+
return tokenizeCustomContainerOpen(this, effects, ok, nok);
|
|
11408
|
+
}
|
|
11409
|
+
};
|
|
11410
|
+
const customContainerCloseConstruct = {
|
|
11411
|
+
name: "customContainerCloseConstruct",
|
|
11412
|
+
tokenize(effects, ok, nok) {
|
|
11413
|
+
return tokenizeCustomContainerClose(this, effects, ok, nok);
|
|
11414
|
+
}
|
|
11415
|
+
};
|
|
11416
|
+
return { document: { [codes.colon]: customContainerOpenConstruct } };
|
|
11417
|
+
/**
|
|
11418
|
+
* Continuation tokenizer for the opening marker of the custom container.
|
|
11419
|
+
*/
|
|
11420
|
+
function tokenizeCustomContainerOpen(self, effects, ok, nok) {
|
|
11421
|
+
let size = 0;
|
|
11422
|
+
let openToken;
|
|
11423
|
+
const infoCodes = [];
|
|
11424
|
+
return start;
|
|
11425
|
+
/**
|
|
11426
|
+
* Process start for the opening marker of the custom container.
|
|
11427
|
+
*/
|
|
11428
|
+
function start(code) {
|
|
11429
|
+
if (code !== codes.colon) return nok(code);
|
|
11430
|
+
size = 0;
|
|
11431
|
+
openToken = effects.enter("customContainer", { _container: true });
|
|
11432
|
+
effects.enter("customContainerFence");
|
|
11433
|
+
effects.enter("customContainerFenceSequence");
|
|
11434
|
+
return sequence;
|
|
11435
|
+
}
|
|
11436
|
+
/**
|
|
11437
|
+
* Process sequence for the opening marker of the custom container.
|
|
11438
|
+
*
|
|
11439
|
+
* ```markdown
|
|
11440
|
+
* > | ::: info
|
|
11441
|
+
* ^
|
|
11442
|
+
* ```
|
|
11443
|
+
*/
|
|
11444
|
+
function sequence(code) {
|
|
11445
|
+
if (code === codes.colon) {
|
|
11446
|
+
size++;
|
|
11447
|
+
effects.consume(code);
|
|
11448
|
+
return sequence;
|
|
11449
|
+
}
|
|
11450
|
+
if (size < 3) return nok(code);
|
|
11451
|
+
effects.exit("customContainerFenceSequence");
|
|
11452
|
+
return markdownSpace(code) ? factorySpace(effects, infoBefore, types.whitespace)(code) : infoBefore(code);
|
|
11453
|
+
}
|
|
11454
|
+
/**
|
|
11455
|
+
* Process before info for the opening marker of the custom container.
|
|
11456
|
+
*
|
|
11457
|
+
* ```markdown
|
|
11458
|
+
* > | ::: info
|
|
11459
|
+
* ^
|
|
11460
|
+
* ```
|
|
11461
|
+
*/
|
|
11462
|
+
function infoBefore(code) {
|
|
11463
|
+
if (code === codes.eof || markdownLineEnding(code)) return nok(code);
|
|
11464
|
+
openToken._customContainer = { size };
|
|
11465
|
+
self.containerState._customContainer = { open: openToken };
|
|
11466
|
+
effects.enter("customContainerFenceInfo");
|
|
11467
|
+
effects.enter(types.chunkString, { contentType: constants.contentTypeString });
|
|
11468
|
+
infoCodes.length = 0;
|
|
11469
|
+
return info(code);
|
|
11470
|
+
}
|
|
11471
|
+
/**
|
|
11472
|
+
* Process info for the opening marker of the custom container.
|
|
11473
|
+
*
|
|
11474
|
+
* ```markdown
|
|
11475
|
+
* > | ::: info
|
|
11476
|
+
* ^
|
|
11477
|
+
* ```
|
|
11478
|
+
*
|
|
11479
|
+
* @type {State}
|
|
11480
|
+
*/
|
|
11481
|
+
function info(code) {
|
|
11482
|
+
if (code === codes.eof || markdownLineEnding(code)) {
|
|
11483
|
+
effects.exit(types.chunkString);
|
|
11484
|
+
effects.exit("customContainerFenceInfo");
|
|
11485
|
+
effects.exit("customContainerFence");
|
|
11486
|
+
openToken._customContainer.info = String.fromCharCode(...infoCodes);
|
|
11487
|
+
return ok(code);
|
|
11488
|
+
}
|
|
11489
|
+
infoCodes.push(code);
|
|
11490
|
+
effects.consume(code);
|
|
11491
|
+
return info;
|
|
11492
|
+
}
|
|
11493
|
+
}
|
|
11494
|
+
/**
|
|
11495
|
+
* Continuation tokenizer for the closing marker of the custom container.
|
|
11496
|
+
*/
|
|
11497
|
+
function tokenizeCustomContainerClose(self, effects, ok, nok) {
|
|
11498
|
+
let size = 0;
|
|
11499
|
+
return start;
|
|
11500
|
+
/**
|
|
11501
|
+
* Process start for the closing marker of the custom container.
|
|
11502
|
+
*/
|
|
11503
|
+
function start(code) {
|
|
11504
|
+
if (code !== codes.colon) return nok(code);
|
|
11505
|
+
size = 0;
|
|
11506
|
+
effects.enter("customContainerFence");
|
|
11507
|
+
effects.enter("customContainerFenceSequence");
|
|
11508
|
+
return sequence;
|
|
11509
|
+
}
|
|
11510
|
+
/**
|
|
11511
|
+
* Process sequence for the closing marker of the custom container.
|
|
11512
|
+
*
|
|
11513
|
+
* ```markdown
|
|
11514
|
+
* > | :::
|
|
11515
|
+
* ```
|
|
11516
|
+
*/
|
|
11517
|
+
function sequence(code) {
|
|
11518
|
+
if (code === codes.colon) {
|
|
11519
|
+
size++;
|
|
11520
|
+
effects.consume(code);
|
|
11521
|
+
return sequence;
|
|
11522
|
+
}
|
|
11523
|
+
if (size < 3) return nok(code);
|
|
11524
|
+
effects.exit("customContainerFenceSequence");
|
|
11525
|
+
return markdownSpace(code) ? factorySpace(effects, after, types.whitespace)(code) : after(code);
|
|
11526
|
+
}
|
|
11527
|
+
/**
|
|
11528
|
+
* Process after for the closing marker of the custom container.
|
|
11529
|
+
*
|
|
11530
|
+
* ```markdown
|
|
11531
|
+
* > | :::
|
|
11532
|
+
* ^
|
|
11533
|
+
* ```
|
|
11534
|
+
*/
|
|
11535
|
+
function after(code) {
|
|
11536
|
+
if (code === codes.eof || markdownLineEnding(code)) {
|
|
11537
|
+
if (!self.containerState) throw new Error("containerState is undefined");
|
|
11538
|
+
const openToken = self.containerState._customContainer?.open;
|
|
11539
|
+
if (openToken?._customContainer?.size === size) {
|
|
11540
|
+
openToken._customContainer.closed = true;
|
|
11541
|
+
self.containerState._closeFlow = true;
|
|
11542
|
+
effects.exit("customContainerFence");
|
|
11543
|
+
return ok(code);
|
|
11544
|
+
}
|
|
11545
|
+
}
|
|
11546
|
+
return nok(code);
|
|
11547
|
+
}
|
|
11548
|
+
}
|
|
11549
|
+
/**
|
|
11550
|
+
* Continuation tokenizer for the custom container.
|
|
11551
|
+
*/
|
|
11552
|
+
function tokenizeCustomContainerContinuation(self, effects, ok, nok) {
|
|
11553
|
+
if (self.containerState?._customContainer?.open?._customContainer?.closed) {
|
|
11554
|
+
self.containerState._closeFlow = true;
|
|
11555
|
+
return nok;
|
|
11556
|
+
}
|
|
11557
|
+
return start;
|
|
11558
|
+
/**
|
|
11559
|
+
* Process start for the custom container.
|
|
11560
|
+
*/
|
|
11561
|
+
function start(code) {
|
|
11562
|
+
if (code !== codes.colon) return ok(code);
|
|
11563
|
+
return effects.attempt(customContainerCloseConstruct, () => {
|
|
11564
|
+
self.containerState._closeFlow = true;
|
|
11565
|
+
return ok;
|
|
11566
|
+
}, ok);
|
|
11567
|
+
}
|
|
11568
|
+
}
|
|
11569
|
+
}
|
|
11570
|
+
|
|
11571
|
+
//#endregion
|
|
11572
|
+
//#region src/language/extensions/mdast-custom-container.ts
|
|
11573
|
+
/**
|
|
11574
|
+
* Mdast extension to support custom containers (e.g., ::: warning ... :::).
|
|
11575
|
+
*/
|
|
11576
|
+
function customContainerFromMarkdown() {
|
|
11577
|
+
return {
|
|
11578
|
+
enter: {
|
|
11579
|
+
customContainer(token) {
|
|
11580
|
+
this.enter({
|
|
11581
|
+
type: "customContainer",
|
|
11582
|
+
children: [],
|
|
11583
|
+
info: null
|
|
11584
|
+
}, token);
|
|
11585
|
+
},
|
|
11586
|
+
customContainerFenceInfo() {
|
|
11587
|
+
this.buffer();
|
|
11588
|
+
}
|
|
11589
|
+
},
|
|
11590
|
+
exit: {
|
|
11591
|
+
customContainer(token) {
|
|
11592
|
+
this.exit(token);
|
|
11593
|
+
},
|
|
11594
|
+
customContainerFenceInfo() {
|
|
11595
|
+
const data = this.resume();
|
|
11596
|
+
const node = this.stack[this.stack.length - 1];
|
|
11597
|
+
node.info = data;
|
|
11598
|
+
}
|
|
11599
|
+
}
|
|
11600
|
+
};
|
|
11601
|
+
}
|
|
11602
|
+
|
|
11603
|
+
//#endregion
|
|
11604
|
+
//#region src/language/extensions/micromark-import-code-snippet.ts
|
|
11605
|
+
/**
|
|
11606
|
+
* Micromark extension to support [VitePress-style Import Code Snippets](https://vitepress.dev/guide/markdown#import-code-snippets) syntax using triple left angle brackets.
|
|
11607
|
+
*/
|
|
11608
|
+
function importCodeSnippet() {
|
|
11609
|
+
const importCodeSnippetConstruct = {
|
|
11610
|
+
name: "importCodeSnippet",
|
|
11611
|
+
tokenize(effects, ok, nok) {
|
|
11612
|
+
return tokenizeImportCodeSnippet(this, effects, ok, nok);
|
|
11613
|
+
}
|
|
11614
|
+
};
|
|
11615
|
+
return { flow: { [codes.lessThan]: importCodeSnippetConstruct } };
|
|
11616
|
+
/**
|
|
11617
|
+
* Tokenizer for the import code snippet.
|
|
11618
|
+
*/
|
|
11619
|
+
function tokenizeImportCodeSnippet(_self, effects, ok, nok) {
|
|
11620
|
+
let size = 0;
|
|
11621
|
+
return start;
|
|
11622
|
+
/**
|
|
11623
|
+
* Process start for the opening marker of the import code snippet.
|
|
11624
|
+
*/
|
|
11625
|
+
function start(code) {
|
|
11626
|
+
if (code !== codes.lessThan) return nok(code);
|
|
11627
|
+
size = 0;
|
|
11628
|
+
effects.enter("importCodeSnippet");
|
|
11629
|
+
effects.enter("importCodeSnippetMarkerSequence");
|
|
11630
|
+
return sequence(code);
|
|
11631
|
+
}
|
|
11632
|
+
/**
|
|
11633
|
+
* Process the sequence of opening markers for the import code snippet.
|
|
11634
|
+
*
|
|
11635
|
+
* ```markdown
|
|
11636
|
+
* > | <<< ./path/to/code.ts
|
|
11637
|
+
* ^^^
|
|
11638
|
+
* ```
|
|
11639
|
+
*/
|
|
11640
|
+
function sequence(code) {
|
|
11641
|
+
if (code === codes.lessThan) {
|
|
11642
|
+
size++;
|
|
11643
|
+
effects.consume(code);
|
|
11644
|
+
return sequence;
|
|
11645
|
+
}
|
|
11646
|
+
if (size < 3) return nok(code);
|
|
11647
|
+
effects.exit("importCodeSnippetMarkerSequence");
|
|
11648
|
+
return markdownSpace(code) ? factorySpace(effects, afterMarker, types.whitespace)(code) : afterMarker(code);
|
|
11649
|
+
}
|
|
11650
|
+
/**
|
|
11651
|
+
* Process after the opening marker of the import code snippet.
|
|
11652
|
+
*
|
|
11653
|
+
* ```markdown
|
|
11654
|
+
* > | <<< ./path/to/code.ts
|
|
11655
|
+
* ^
|
|
11656
|
+
* ```
|
|
11657
|
+
*/
|
|
11658
|
+
function afterMarker(code) {
|
|
11659
|
+
if (code === codes.eof || markdownLineEnding(code)) return nok(code);
|
|
11660
|
+
effects.enter("importCodeSnippetPath");
|
|
11661
|
+
effects.enter(types.chunkString, { contentType: constants.contentTypeString });
|
|
11662
|
+
return importPath(code);
|
|
11663
|
+
}
|
|
11664
|
+
/**
|
|
11665
|
+
* Process the path of the import code snippet.
|
|
11666
|
+
*
|
|
11667
|
+
* ```markdown
|
|
11668
|
+
* > | <<< ./path/to/code.ts
|
|
11669
|
+
* ^^^^^^^^^^^^^^^^^
|
|
11670
|
+
* ```
|
|
11671
|
+
*/
|
|
11672
|
+
function importPath(code) {
|
|
11673
|
+
if (code === codes.eof || markdownLineEnding(code) || markdownSpace(code)) {
|
|
11674
|
+
effects.exit(types.chunkString);
|
|
11675
|
+
effects.exit("importCodeSnippetPath");
|
|
11676
|
+
effects.exit("importCodeSnippet");
|
|
11677
|
+
return afterPath(code);
|
|
11678
|
+
}
|
|
11679
|
+
effects.consume(code);
|
|
11680
|
+
return importPath;
|
|
11681
|
+
}
|
|
11682
|
+
/**
|
|
11683
|
+
* Process after the path of the import code snippet.
|
|
11684
|
+
*
|
|
11685
|
+
* ```markdown
|
|
11686
|
+
* > | <<< ./path/to/code.ts
|
|
11687
|
+
* ^
|
|
11688
|
+
* ```
|
|
11689
|
+
*/
|
|
11690
|
+
function afterPath(code) {
|
|
11691
|
+
if (code === codes.eof || markdownLineEnding(code)) return ok(code);
|
|
11692
|
+
if (markdownSpace(code)) return factorySpace(effects, afterPath, types.whitespace)(code);
|
|
11693
|
+
return nok(code);
|
|
11694
|
+
}
|
|
11695
|
+
}
|
|
11696
|
+
}
|
|
11697
|
+
|
|
11698
|
+
//#endregion
|
|
11699
|
+
//#region src/language/extensions/mdast-import-code-snippet.ts
|
|
11700
|
+
/**
|
|
11701
|
+
* Mdast extension to support [VitePress-style Import Code Snippets](https://vitepress.dev/guide/markdown#import-code-snippets) syntax using triple left angle brackets.
|
|
11702
|
+
*/
|
|
11703
|
+
function importCodeSnippetFromMarkdown() {
|
|
11704
|
+
return {
|
|
11705
|
+
enter: {
|
|
11706
|
+
importCodeSnippet(token) {
|
|
11707
|
+
this.enter({
|
|
11708
|
+
type: "importCodeSnippet",
|
|
11709
|
+
value: ""
|
|
11710
|
+
}, token);
|
|
11711
|
+
},
|
|
11712
|
+
importCodeSnippetPath() {
|
|
11713
|
+
this.buffer();
|
|
11714
|
+
}
|
|
11715
|
+
},
|
|
11716
|
+
exit: {
|
|
11717
|
+
importCodeSnippet(token) {
|
|
11718
|
+
this.exit(token);
|
|
11719
|
+
},
|
|
11720
|
+
importCodeSnippetPath() {
|
|
11721
|
+
const data = this.resume();
|
|
11722
|
+
const node = this.stack[this.stack.length - 1];
|
|
11723
|
+
node.value = data;
|
|
11724
|
+
}
|
|
11725
|
+
}
|
|
11726
|
+
};
|
|
11727
|
+
}
|
|
11728
|
+
|
|
11729
|
+
//#endregion
|
|
11730
|
+
//#region src/language/parser.ts
|
|
11731
|
+
/**
|
|
11732
|
+
* Parse Extended Markdown to MDAST.
|
|
11733
|
+
*/
|
|
11734
|
+
function parseExtendedMarkdown(code) {
|
|
11735
|
+
const options = {
|
|
11736
|
+
extensions: [
|
|
11737
|
+
gfm(),
|
|
11738
|
+
frontmatter(["yaml", "toml"]),
|
|
11739
|
+
math(),
|
|
11740
|
+
customContainer(),
|
|
11741
|
+
importCodeSnippet()
|
|
11742
|
+
],
|
|
11743
|
+
mdastExtensions: [
|
|
11744
|
+
gfmFromMarkdown(),
|
|
11745
|
+
frontmatterFromMarkdown(["yaml", "toml"]),
|
|
11746
|
+
mathFromMarkdown(),
|
|
11747
|
+
customContainerFromMarkdown(),
|
|
11748
|
+
importCodeSnippetFromMarkdown()
|
|
11749
|
+
]
|
|
11750
|
+
};
|
|
11751
|
+
return fromMarkdown(code, options);
|
|
11752
|
+
}
|
|
11753
|
+
|
|
11754
|
+
//#endregion
|
|
11755
|
+
//#region src/language/extended-markdown-ianguage.ts
|
|
11756
|
+
var ExtendedMarkdownLanguage = class {
|
|
11757
|
+
/**
|
|
11758
|
+
* The type of file to read.
|
|
11759
|
+
* @type {"text"}
|
|
11760
|
+
*/
|
|
11761
|
+
fileType = markdown.languages.gfm.fileType;
|
|
11762
|
+
/**
|
|
11763
|
+
* The line number at which the parser starts counting.
|
|
11764
|
+
* @type {0|1}
|
|
11765
|
+
*/
|
|
11766
|
+
lineStart = markdown.languages.gfm.lineStart;
|
|
11767
|
+
/**
|
|
11768
|
+
* The column number at which the parser starts counting.
|
|
11769
|
+
* @type {0|1}
|
|
11770
|
+
*/
|
|
11771
|
+
columnStart = markdown.languages.gfm.columnStart;
|
|
11772
|
+
/**
|
|
11773
|
+
* The name of the key that holds the type of the node.
|
|
11774
|
+
* @type {string}
|
|
11775
|
+
*/
|
|
11776
|
+
nodeTypeKey = markdown.languages.gfm.nodeTypeKey;
|
|
11777
|
+
/**
|
|
11778
|
+
* Default language options. User-defined options are merged with this object.
|
|
11779
|
+
* @type {MarkdownLanguageOptions}
|
|
11780
|
+
*/
|
|
11781
|
+
defaultLanguageOptions = markdown.languages.gfm.defaultLanguageOptions;
|
|
11782
|
+
/**
|
|
11783
|
+
* Validates the language options.
|
|
11784
|
+
* @param {MarkdownLanguageOptions} languageOptions The language options to validate.
|
|
11785
|
+
* @returns {void}
|
|
11786
|
+
* @throws {Error} When the language options are invalid.
|
|
11787
|
+
*/
|
|
11788
|
+
validateLanguageOptions(languageOptions$2) {
|
|
11789
|
+
return markdown.languages.gfm.validateLanguageOptions(languageOptions$2);
|
|
11790
|
+
}
|
|
11791
|
+
/**
|
|
11792
|
+
* Parses the given file into an AST.
|
|
11793
|
+
* @param {File} file The virtual file to parse.
|
|
11794
|
+
* @param {MarkdownLanguageContext} _context The options to use for parsing.
|
|
11795
|
+
* @returns {ParseResult<Root>} The result of parsing.
|
|
11796
|
+
*/
|
|
11797
|
+
parse(file, _context) {
|
|
11798
|
+
const text = file.body;
|
|
11799
|
+
try {
|
|
11800
|
+
return {
|
|
11801
|
+
ok: true,
|
|
11802
|
+
ast: parseExtendedMarkdown(text)
|
|
11803
|
+
};
|
|
11804
|
+
} catch (ex) {
|
|
11805
|
+
return {
|
|
11806
|
+
ok: false,
|
|
11807
|
+
errors: [ex]
|
|
11808
|
+
};
|
|
11809
|
+
}
|
|
11810
|
+
}
|
|
11811
|
+
/**
|
|
11812
|
+
* Creates a new `MarkdownSourceCode` object from the given information.
|
|
11813
|
+
* @param {File} file The virtual file to create a `MarkdownSourceCode` object from.
|
|
11814
|
+
* @param {OkParseResult<Root>} parseResult The result returned from `parse()`.
|
|
11815
|
+
* @returns {MarkdownSourceCode} The new `MarkdownSourceCode` object.
|
|
11816
|
+
*/
|
|
11817
|
+
createSourceCode(file, parseResult) {
|
|
11818
|
+
return markdown.languages.gfm.createSourceCode(file, parseResult);
|
|
11819
|
+
}
|
|
11820
|
+
};
|
|
11223
11821
|
|
|
11224
11822
|
//#endregion
|
|
11225
11823
|
//#region src/index.ts
|
|
@@ -11235,12 +11833,14 @@ const resources = {
|
|
|
11235
11833
|
defaultPreserveWords,
|
|
11236
11834
|
defaultMinorWords
|
|
11237
11835
|
};
|
|
11836
|
+
const languages = { "extended-syntax": new ExtendedMarkdownLanguage() };
|
|
11238
11837
|
var src_default = {
|
|
11239
11838
|
meta: meta_exports,
|
|
11839
|
+
languages,
|
|
11240
11840
|
configs,
|
|
11241
11841
|
rules,
|
|
11242
11842
|
resources
|
|
11243
11843
|
};
|
|
11244
11844
|
|
|
11245
11845
|
//#endregion
|
|
11246
|
-
export { configs, src_default as default, meta_exports as meta, resources, rules };
|
|
11846
|
+
export { configs, src_default as default, languages, meta_exports as meta, resources, rules };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "eslint-plugin-markdown-preferences",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.27.0",
|
|
4
4
|
"description": "ESLint plugin that enforces our markdown preferences",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
|
@@ -63,6 +63,16 @@
|
|
|
63
63
|
},
|
|
64
64
|
"dependencies": {
|
|
65
65
|
"emoji-regex-xs": "^2.0.1",
|
|
66
|
+
"mdast-util-from-markdown": "^2.0.2",
|
|
67
|
+
"mdast-util-frontmatter": "^2.0.1",
|
|
68
|
+
"mdast-util-gfm": "^3.1.0",
|
|
69
|
+
"mdast-util-math": "^3.0.0",
|
|
70
|
+
"micromark-extension-frontmatter": "^2.0.0",
|
|
71
|
+
"micromark-extension-gfm": "^3.0.0",
|
|
72
|
+
"micromark-extension-math": "^3.1.0",
|
|
73
|
+
"micromark-factory-space": "^2.0.1",
|
|
74
|
+
"micromark-util-character": "^2.1.1",
|
|
75
|
+
"micromark-util-symbol": "^2.0.1",
|
|
66
76
|
"string-width": "^8.0.0"
|
|
67
77
|
},
|
|
68
78
|
"devDependencies": {
|