1111
1212import { MarkdownSourceCode } from "./markdown-source-code.js" ;
1313import { fromMarkdown } from "mdast-util-from-markdown" ;
14+ import { frontmatterFromMarkdown } from "mdast-util-frontmatter" ;
1415import { gfmFromMarkdown } from "mdast-util-gfm" ;
16+ import { frontmatter } from "micromark-extension-frontmatter" ;
1517import { gfm } from "micromark-extension-gfm" ;
1618
1719//-----------------------------------------------------------------------------
1820// Types
1921//-----------------------------------------------------------------------------
2022
2123/** @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 */
2226/** @typedef {import("@eslint/core").Language } Language */
2327/** @typedef {import("@eslint/core").File } File */
2428/** @typedef {import("@eslint/core").ParseResult<RootNode> } ParseResult */
2529/** @typedef {import("@eslint/core").OkParseResult<RootNode> } OkParseResult */
30+ /** @typedef {import("../types.ts").MarkdownLanguageOptions } MarkdownLanguageOptions */
31+ /** @typedef {import("../types.ts").MarkdownLanguageContext } MarkdownLanguageContext */
2632/** @typedef {"commonmark"|"gfm" } ParserMode */
2733
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+
2876//-----------------------------------------------------------------------------
2977// Exports
3078//-----------------------------------------------------------------------------
@@ -58,6 +106,14 @@ export class MarkdownLanguage {
58106 */
59107 nodeTypeKey = "type" ;
60108
109+ /**
110+ * Default language options. User-defined options are merged with this object.
111+ * @type {MarkdownLanguageOptions }
112+ */
113+ defaultLanguageOptions = {
114+ frontmatter : false ,
115+ } ;
116+
61117 /**
62118 * The Markdown parser mode.
63119 * @type {ParserMode }
@@ -75,24 +131,33 @@ export class MarkdownLanguage {
75131 }
76132 }
77133
78- /* eslint-disable no-unused-vars -- Required to complete interface. */
79134 /**
80135 * Validates the language options.
81- * @param {Object } languageOptions The language options to validate.
136+ * @param {MarkdownLanguageOptions } languageOptions The language options to validate.
82137 * @returns {void }
83138 * @throws {Error } When the language options are invalid.
84139 */
85140 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+ }
87152 }
88- /* eslint-enable no-unused-vars -- Required to complete interface. */
89153
90154 /**
91155 * Parses the given file into an AST.
92156 * @param {File } file The virtual file to parse.
157+ * @param {MarkdownLanguageContext } context The options to use for parsing.
93158 * @returns {ParseResult } The result of parsing.
94159 */
95- parse ( file ) {
160+ parse ( file , context ) {
96161 // Note: BOM already removed
97162 const text = /** @type {string } */ ( file . body ) ;
98163
@@ -103,13 +168,10 @@ export class MarkdownLanguage {
103168 * problem that ESLint identified just like any other.
104169 */
105170 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+ ) ;
113175 const root = fromMarkdown ( text , options ) ;
114176
115177 return {
0 commit comments