eslint-plugin-markdown-preferences 0.26.1 → 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 +640 -45
- 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);
|
|
@@ -5296,6 +5306,108 @@ function parseListItem(sourceCode, node) {
|
|
|
5296
5306
|
};
|
|
5297
5307
|
}
|
|
5298
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
|
+
|
|
5299
5411
|
//#endregion
|
|
5300
5412
|
//#region src/rules/indent.ts
|
|
5301
5413
|
/**
|
|
@@ -5575,7 +5687,10 @@ var indent_default = createRule("indent", {
|
|
|
5575
5687
|
definition: verifyLinkDefinition,
|
|
5576
5688
|
table: verifyTable,
|
|
5577
5689
|
list: verifyList,
|
|
5578
|
-
|
|
5690
|
+
customContainer: verifyCustomContainer,
|
|
5691
|
+
math: verifyMathBlock,
|
|
5692
|
+
importCodeSnippet: verifyImportCodeSnippet,
|
|
5693
|
+
inlineCode: verifyInlineCodeOrInlineMath,
|
|
5579
5694
|
emphasis: verifyEmphasisOrStrongOrDelete,
|
|
5580
5695
|
strong: verifyEmphasisOrStrongOrDelete,
|
|
5581
5696
|
delete: verifyEmphasisOrStrongOrDelete,
|
|
@@ -5584,6 +5699,7 @@ var indent_default = createRule("indent", {
|
|
|
5584
5699
|
footnoteReference: verifyInline,
|
|
5585
5700
|
break: verifyInline,
|
|
5586
5701
|
text: verifyText,
|
|
5702
|
+
inlineMath: verifyInlineCodeOrInlineMath,
|
|
5587
5703
|
blockquote(node) {
|
|
5588
5704
|
verifyBlockquote(node);
|
|
5589
5705
|
blockStack = new BlockquoteStack(node);
|
|
@@ -5640,32 +5756,9 @@ var indent_default = createRule("indent", {
|
|
|
5640
5756
|
verifyLinesIndent([loc.start.line, loc.end.line], (lineNumber) => blockStack.getExpectedIndent({
|
|
5641
5757
|
lineNumber,
|
|
5642
5758
|
block: true
|
|
5643
|
-
}),
|
|
5644
|
-
|
|
5645
|
-
|
|
5646
|
-
*/
|
|
5647
|
-
function* additionalFixes(fixer, info) {
|
|
5648
|
-
if (info.loc.start.line !== loc.start.line) return;
|
|
5649
|
-
for (let lineNumber = loc.start.line + 1; lineNumber < loc.end.line; lineNumber++) {
|
|
5650
|
-
const line = getParsedLines(sourceCode).get(lineNumber);
|
|
5651
|
-
if (!line) continue;
|
|
5652
|
-
if (info.expectedIndentWidth > info.actualIndentWidth) {
|
|
5653
|
-
const before = sliceWidth(line.text, 0, info.actualIndentWidth);
|
|
5654
|
-
const after = sliceWidth(line.text, info.actualIndentWidth);
|
|
5655
|
-
const diffWidth = info.expectedIndentWidth - info.actualIndentWidth;
|
|
5656
|
-
yield fixer.replaceTextRange([line.range[0], line.range[0] + line.text.length], before + " ".repeat(diffWidth) + after);
|
|
5657
|
-
} else {
|
|
5658
|
-
let before = sliceWidth(line.text, 0, info.expectedIndentWidth);
|
|
5659
|
-
let between = sliceWidth(line.text, info.expectedIndentWidth, info.actualIndentWidth);
|
|
5660
|
-
const after = sliceWidth(line.text, info.actualIndentWidth);
|
|
5661
|
-
while (between && !isSpaceOrTab(between)) {
|
|
5662
|
-
before += between[0];
|
|
5663
|
-
between = between.slice(1);
|
|
5664
|
-
}
|
|
5665
|
-
yield fixer.replaceTextRange([line.range[0], line.range[0] + line.text.length], before + after);
|
|
5666
|
-
}
|
|
5667
|
-
}
|
|
5668
|
-
}
|
|
5759
|
+
}), (fixer, info) => {
|
|
5760
|
+
return additionalFixesForCodeBlock(node, fixer, info, loc.start.line + 1, loc.end.line - 1);
|
|
5761
|
+
});
|
|
5669
5762
|
}
|
|
5670
5763
|
/**
|
|
5671
5764
|
* Verify an HTML node.
|
|
@@ -5782,6 +5875,41 @@ var indent_default = createRule("indent", {
|
|
|
5782
5875
|
}
|
|
5783
5876
|
}
|
|
5784
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
|
+
/**
|
|
5785
5913
|
* Verify a footnote definition node.
|
|
5786
5914
|
*/
|
|
5787
5915
|
function verifyFootnoteDefinition(node) {
|
|
@@ -5792,9 +5920,9 @@ var indent_default = createRule("indent", {
|
|
|
5792
5920
|
}));
|
|
5793
5921
|
}
|
|
5794
5922
|
/**
|
|
5795
|
-
* Verify an inline code node.
|
|
5923
|
+
* Verify an inline code/math node.
|
|
5796
5924
|
*/
|
|
5797
|
-
function
|
|
5925
|
+
function verifyInlineCodeOrInlineMath(node) {
|
|
5798
5926
|
const loc = sourceCode.getLoc(node);
|
|
5799
5927
|
if (!inlineToBeChecked(loc.start)) return;
|
|
5800
5928
|
verifyLinesIndent([loc.start.line], (lineNumber) => blockStack.getExpectedIndent({
|
|
@@ -6176,6 +6304,32 @@ var indent_default = createRule("indent", {
|
|
|
6176
6304
|
actualIndentWidth
|
|
6177
6305
|
};
|
|
6178
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
|
+
}
|
|
6179
6333
|
}
|
|
6180
6334
|
});
|
|
6181
6335
|
|
|
@@ -8312,14 +8466,14 @@ var ordered_list_marker_sequence_default = createRule("ordered-list-marker-seque
|
|
|
8312
8466
|
}
|
|
8313
8467
|
}
|
|
8314
8468
|
return {
|
|
8315
|
-
"blockquote, listItem, footnoteDefinition"(node) {
|
|
8469
|
+
"blockquote, listItem, footnoteDefinition, customContainer"(node) {
|
|
8316
8470
|
scope = {
|
|
8317
8471
|
node,
|
|
8318
8472
|
upper: scope,
|
|
8319
8473
|
last: null
|
|
8320
8474
|
};
|
|
8321
8475
|
},
|
|
8322
|
-
"blockquote, listItem, footnoteDefinition:exit"(node) {
|
|
8476
|
+
"blockquote, listItem, footnoteDefinition, customContainer:exit"(node) {
|
|
8323
8477
|
if (scope.node === node) scope = scope.upper;
|
|
8324
8478
|
},
|
|
8325
8479
|
heading() {
|
|
@@ -8401,14 +8555,14 @@ var ordered_list_marker_start_default = createRule("ordered-list-marker-start",
|
|
|
8401
8555
|
});
|
|
8402
8556
|
}
|
|
8403
8557
|
return {
|
|
8404
|
-
"blockquote, listItem, footnoteDefinition"(node) {
|
|
8558
|
+
"blockquote, listItem, footnoteDefinition, customContainer"(node) {
|
|
8405
8559
|
scope = {
|
|
8406
8560
|
node,
|
|
8407
8561
|
upper: scope,
|
|
8408
8562
|
last: null
|
|
8409
8563
|
};
|
|
8410
8564
|
},
|
|
8411
|
-
"blockquote, listItem, footnoteDefinition:exit"(node) {
|
|
8565
|
+
"blockquote, listItem, footnoteDefinition, customContainer:exit"(node) {
|
|
8412
8566
|
if (scope.node === node) scope = scope.upper;
|
|
8413
8567
|
},
|
|
8414
8568
|
heading() {
|
|
@@ -8581,14 +8735,14 @@ var ordered_list_marker_style_default = createRule("ordered-list-marker-style",
|
|
|
8581
8735
|
if (!node.ordered) return;
|
|
8582
8736
|
checkOrderedList(node);
|
|
8583
8737
|
},
|
|
8584
|
-
"root, blockquote, listItem, footnoteDefinition"(node) {
|
|
8738
|
+
"root, blockquote, listItem, footnoteDefinition, customContainer"(node) {
|
|
8585
8739
|
containerStack = {
|
|
8586
8740
|
node,
|
|
8587
8741
|
level: node.type === "listItem" ? containerStack.level + 1 : 1,
|
|
8588
8742
|
upper: containerStack
|
|
8589
8743
|
};
|
|
8590
8744
|
},
|
|
8591
|
-
"root, blockquote, listItem, footnoteDefinition:exit"() {
|
|
8745
|
+
"root, blockquote, listItem, footnoteDefinition, customContainer:exit"() {
|
|
8592
8746
|
containerStack = containerStack.upper;
|
|
8593
8747
|
}
|
|
8594
8748
|
};
|
|
@@ -8636,6 +8790,9 @@ const BLOCK_TYPES = [
|
|
|
8636
8790
|
"link-definition",
|
|
8637
8791
|
"footnote-definition",
|
|
8638
8792
|
"frontmatter",
|
|
8793
|
+
"custom-container",
|
|
8794
|
+
"math",
|
|
8795
|
+
"import-code-snippet",
|
|
8639
8796
|
"*"
|
|
8640
8797
|
];
|
|
8641
8798
|
const BLOCK_TYPE_SCHEMAS = [{
|
|
@@ -8675,7 +8832,10 @@ const BLOCK_TYPE_MAP = {
|
|
|
8675
8832
|
footnoteDefinition: "footnote-definition",
|
|
8676
8833
|
json: "frontmatter",
|
|
8677
8834
|
toml: "frontmatter",
|
|
8678
|
-
yaml: "frontmatter"
|
|
8835
|
+
yaml: "frontmatter",
|
|
8836
|
+
customContainer: "custom-container",
|
|
8837
|
+
math: "math",
|
|
8838
|
+
importCodeSnippet: "import-code-snippet"
|
|
8679
8839
|
};
|
|
8680
8840
|
/**
|
|
8681
8841
|
* Get the block type of a node
|
|
@@ -8871,10 +9031,10 @@ var padding_line_between_blocks_default = createRule("padding-line-between-block
|
|
|
8871
9031
|
}
|
|
8872
9032
|
}
|
|
8873
9033
|
return {
|
|
8874
|
-
"root, blockquote, listItem, footnoteDefinition"(node) {
|
|
9034
|
+
"root, blockquote, listItem, footnoteDefinition, customContainer"(node) {
|
|
8875
9035
|
containerStack.unshift(node);
|
|
8876
9036
|
},
|
|
8877
|
-
"root, blockquote, listItem, footnoteDefinition:exit"(node) {
|
|
9037
|
+
"root, blockquote, listItem, footnoteDefinition, customContainer:exit"(node) {
|
|
8878
9038
|
checkBlockPadding(node);
|
|
8879
9039
|
containerStack.shift();
|
|
8880
9040
|
}
|
|
@@ -11224,7 +11384,440 @@ var meta_exports = /* @__PURE__ */ __export({
|
|
|
11224
11384
|
version: () => version
|
|
11225
11385
|
});
|
|
11226
11386
|
const name = "eslint-plugin-markdown-preferences";
|
|
11227
|
-
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
|
+
};
|
|
11228
11821
|
|
|
11229
11822
|
//#endregion
|
|
11230
11823
|
//#region src/index.ts
|
|
@@ -11240,12 +11833,14 @@ const resources = {
|
|
|
11240
11833
|
defaultPreserveWords,
|
|
11241
11834
|
defaultMinorWords
|
|
11242
11835
|
};
|
|
11836
|
+
const languages = { "extended-syntax": new ExtendedMarkdownLanguage() };
|
|
11243
11837
|
var src_default = {
|
|
11244
11838
|
meta: meta_exports,
|
|
11839
|
+
languages,
|
|
11245
11840
|
configs,
|
|
11246
11841
|
rules,
|
|
11247
11842
|
resources
|
|
11248
11843
|
};
|
|
11249
11844
|
|
|
11250
11845
|
//#endregion
|
|
11251
|
-
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": {
|