11
11
12
12
import { MarkdownSourceCode } from "./markdown-source-code.js" ;
13
13
import { fromMarkdown } from "mdast-util-from-markdown" ;
14
+ import { frontmatterFromMarkdown } from "mdast-util-frontmatter" ;
14
15
import { gfmFromMarkdown } from "mdast-util-gfm" ;
16
+ import { frontmatter } from "micromark-extension-frontmatter" ;
15
17
import { gfm } from "micromark-extension-gfm" ;
16
18
17
19
//-----------------------------------------------------------------------------
18
20
// Types
19
21
//-----------------------------------------------------------------------------
20
22
21
23
/** @typedef {import("mdast").Root } RootNode */
24
+ /** @typedef {import("mdast-util-from-markdown").Options['extensions'] } Extensions */
25
+ /** @typedef {import("mdast-util-from-markdown").Options['mdastExtensions'] } MdastExtensions */
22
26
/** @typedef {import("@eslint/core").Language } Language */
23
27
/** @typedef {import("@eslint/core").File } File */
24
28
/** @typedef {import("@eslint/core").ParseResult<RootNode> } ParseResult */
25
29
/** @typedef {import("@eslint/core").OkParseResult<RootNode> } OkParseResult */
30
+ /** @typedef {import("../types.ts").MarkdownLanguageOptions } MarkdownLanguageOptions */
31
+ /** @typedef {import("../types.ts").MarkdownLanguageContext } MarkdownLanguageContext */
26
32
/** @typedef {"commonmark"|"gfm" } ParserMode */
27
33
34
+ //-----------------------------------------------------------------------------
35
+ // Helpers
36
+ //-----------------------------------------------------------------------------
37
+
38
+ /**
39
+ * Create parser options based on `mode` and `languageOptions`.
40
+ * @param {ParserMode } mode The markdown parser mode.
41
+ * @param {MarkdownLanguageOptions } languageOptions Language options.
42
+ * @returns {{extensions: Extensions, mdastExtensions: MdastExtensions} } Parser options for micromark and mdast
43
+ */
44
+ function createParserOptions ( mode , languageOptions ) {
45
+ /** @type {Extensions } */
46
+ const extensions = [ ] ;
47
+ /** @type {MdastExtensions } */
48
+ const mdastExtensions = [ ] ;
49
+
50
+ // 1. `mode`: Add GFM extensions if mode is "gfm"
51
+ if ( mode === "gfm" ) {
52
+ extensions . push ( gfm ( ) ) ;
53
+ mdastExtensions . push ( gfmFromMarkdown ( ) ) ;
54
+ }
55
+
56
+ // 2. `languageOptions.frontmatter`: Handle frontmatter options
57
+ const frontmatterOption = languageOptions ?. frontmatter ;
58
+
59
+ // Skip frontmatter entirely if false
60
+ if ( frontmatterOption !== false ) {
61
+ if ( frontmatterOption === "yaml" ) {
62
+ extensions . push ( frontmatter ( [ "yaml" ] ) ) ;
63
+ mdastExtensions . push ( frontmatterFromMarkdown ( [ "yaml" ] ) ) ;
64
+ } else if ( frontmatterOption === "toml" ) {
65
+ extensions . push ( frontmatter ( [ "toml" ] ) ) ;
66
+ mdastExtensions . push ( frontmatterFromMarkdown ( [ "toml" ] ) ) ;
67
+ }
68
+ }
69
+
70
+ return {
71
+ extensions,
72
+ mdastExtensions,
73
+ } ;
74
+ }
75
+
28
76
//-----------------------------------------------------------------------------
29
77
// Exports
30
78
//-----------------------------------------------------------------------------
@@ -58,6 +106,14 @@ export class MarkdownLanguage {
58
106
*/
59
107
nodeTypeKey = "type" ;
60
108
109
+ /**
110
+ * Default language options. User-defined options are merged with this object.
111
+ * @type {MarkdownLanguageOptions }
112
+ */
113
+ defaultLanguageOptions = {
114
+ frontmatter : false ,
115
+ } ;
116
+
61
117
/**
62
118
* The Markdown parser mode.
63
119
* @type {ParserMode }
@@ -75,24 +131,33 @@ export class MarkdownLanguage {
75
131
}
76
132
}
77
133
78
- /* eslint-disable no-unused-vars -- Required to complete interface. */
79
134
/**
80
135
* Validates the language options.
81
- * @param {Object } languageOptions The language options to validate.
136
+ * @param {MarkdownLanguageOptions } languageOptions The language options to validate.
82
137
* @returns {void }
83
138
* @throws {Error } When the language options are invalid.
84
139
*/
85
140
validateLanguageOptions ( languageOptions ) {
86
- // no-op
141
+ const frontmatterOption = languageOptions ?. frontmatter ;
142
+ const validFrontmatterOptions = new Set ( [ false , "yaml" , "toml" ] ) ;
143
+
144
+ if (
145
+ frontmatterOption !== undefined &&
146
+ ! validFrontmatterOptions . has ( frontmatterOption )
147
+ ) {
148
+ throw new Error (
149
+ `Invalid language option value \`${ frontmatterOption } \` for frontmatter.` ,
150
+ ) ;
151
+ }
87
152
}
88
- /* eslint-enable no-unused-vars -- Required to complete interface. */
89
153
90
154
/**
91
155
* Parses the given file into an AST.
92
156
* @param {File } file The virtual file to parse.
157
+ * @param {MarkdownLanguageContext } context The options to use for parsing.
93
158
* @returns {ParseResult } The result of parsing.
94
159
*/
95
- parse ( file ) {
160
+ parse ( file , context ) {
96
161
// Note: BOM already removed
97
162
const text = /** @type {string } */ ( file . body ) ;
98
163
@@ -103,13 +168,10 @@ export class MarkdownLanguage {
103
168
* problem that ESLint identified just like any other.
104
169
*/
105
170
try {
106
- const options =
107
- this . #mode === "gfm"
108
- ? {
109
- extensions : [ gfm ( ) ] ,
110
- mdastExtensions : [ gfmFromMarkdown ( ) ] ,
111
- }
112
- : { extensions : [ ] } ;
171
+ const options = createParserOptions (
172
+ this . #mode,
173
+ context ?. languageOptions ,
174
+ ) ;
113
175
const root = fromMarkdown ( text , options ) ;
114
176
115
177
return {
0 commit comments