Introduce options.markdownItFactory (and remove options.markdownItPlugins) so the markdown-it parser can be removed as a direct dependency because it is no longer used by default.

This commit is contained in:
David Anson 2024-12-25 20:42:32 -08:00
parent 3cbe1cb6c5
commit d4b981bcb3
11 changed files with 172 additions and 67 deletions

View file

@ -14,8 +14,8 @@ Match the coding style of the files you edit. Although everyone has their own
preferences and opinions, a pull request is not the right forum to debate them. preferences and opinions, a pull request is not the right forum to debate them.
Do not add new [`dependencies` to `package.json`][dependencies]. The Markdown Do not add new [`dependencies` to `package.json`][dependencies]. The Markdown
parsers [`markdown-it`][markdown-it] and [`micromark`][micromark] are the parser [`micromark`][micromark] (and its extensions) is this project's only
project's only dependencies. dependency.
Package versions for `dependencies` and `devDependencies` should be specified Package versions for `dependencies` and `devDependencies` should be specified
exactly (also known as "pinning"). The short explanation is that doing otherwise exactly (also known as "pinning"). The short explanation is that doing otherwise

View file

@ -24,7 +24,7 @@ for Markdown files. It was inspired by - and heavily influenced by - Mark
Harrison's [markdownlint][markdownlint-ruby] for Ruby. The initial rules, rule Harrison's [markdownlint][markdownlint-ruby] for Ruby. The initial rules, rule
documentation, and test cases came from that project. documentation, and test cases came from that project.
`markdownlint` uses the [`micromark`][micromark] parser and honors the `markdownlint` uses the [`micromark` parser][micromark] and honors the
[CommonMark][commonmark] specification for Markdown. It additionally supports [CommonMark][commonmark] specification for Markdown. It additionally supports
popular [GitHub Flavored Markdown (GFM)][gfm] syntax like autolinks and tables popular [GitHub Flavored Markdown (GFM)][gfm] syntax like autolinks and tables
as well as directives, footnotes, and math syntax - all implemented by as well as directives, footnotes, and math syntax - all implemented by
@ -567,28 +567,35 @@ This setting can be useful in the presence of (custom) rules that encounter
unexpected syntax and fail. By enabling this option, the linting process unexpected syntax and fail. By enabling this option, the linting process
is allowed to continue and report any violations that were found. is allowed to continue and report any violations that were found.
##### options.markdownItPlugins ##### options.markdownItFactory
Type: `Array` of `Array` of `Function` and plugin parameters Type: `Function` returning an instance of a [`markdown-it` parser][markdown-it]
Specifies additional [`markdown-it` plugins][markdown-it-plugin] to use when Provides a factory function for creating instances of the `markdown-it` parser.
parsing input. Plugins can be used to support additional syntax and features for
advanced scenarios. *Deprecated.*
[markdown-it-plugin]: https://www.npmjs.com/search?q=keywords:markdown-it-plugin Previous versions of the `markdownlint` library declared `markdown-it` as a
direct dependency. This function makes it possible to avoid that dependency
entirely. In cases where `markdown-it` is needed, the caller is responsible for
declaring the dependency and returning an instance from this factory. If any
[`markdown-it` plugins][markdown-it-plugin] are needed, they should be `use`d by
the caller before returning the `markdown-it` instance.
Each item in the top-level `Array` should be of the form: For compatibility with previous versions of `markdownlint`, this function can be
implemented like:
```javascript ```javascript
[ require("markdown-it-plugin"), plugin_param_0, plugin_param_1, ... ] import markdownIt from "markdown-it";
const markdownItFactory = () => markdownIt({ "html": true });
``` ```
> Note that `markdown-it` plugins are only called when the `markdown-it` parser > Note that this function is only invoked when a `markdown-it` parser is
> is invoked. None of the built-in rules use the `markdown-it` parser, so > needed. None of the built-in rules use the `markdown-it` parser, so it is only
> `markdown-it` plugins will only be invoked when one or more > invoked when one or more [custom rules][custom-rules] are present that use the
> [custom rules][custom-rules] that use the `markdown-it` parser are present. > `markdown-it` parser.
[custom-rules]: #custom-rules [custom-rules]: #custom-rules
[markdown-it]: https://github.com/markdown-it/markdown-it
[markdown-it-plugin]: https://www.npmjs.com/search?q=keywords:markdown-it-plugin
##### options.noInlineConfig ##### options.noInlineConfig

View file

@ -7,7 +7,7 @@ import { lint as lintPromise, readConfig as readConfigPromise } from "../../lib/
import { lint as lintSync, readConfig as readConfigSync } from "../../lib/exports-sync.mjs"; import { lint as lintSync, readConfig as readConfigSync } from "../../lib/exports-sync.mjs";
import assert from "assert"; import assert from "assert";
import markdownItSub from "markdown-it-sub"; import markdownIt from "markdown-it";
const markdownlintJsonPath = "../../.markdownlint.json"; const markdownlintJsonPath = "../../.markdownlint.json";
const version: string = getVersion(); const version: string = getVersion();
@ -98,7 +98,7 @@ options = {
"frontMatter": /---/, "frontMatter": /---/,
"handleRuleFailures": false, "handleRuleFailures": false,
"noInlineConfig": false, "noInlineConfig": false,
"markdownItPlugins": [ [ markdownItSub ] ] "markdownItFactory": () => new markdownIt()
}; };
assertLintResults(lintSync(options)); assertLintResults(lintSync(options));

View file

@ -7,6 +7,7 @@ export type LintCallback = import("./markdownlint.mjs").LintCallback;
export type LintContentCallback = import("./markdownlint.mjs").LintContentCallback; export type LintContentCallback = import("./markdownlint.mjs").LintContentCallback;
export type LintError = import("./markdownlint.mjs").LintError; export type LintError = import("./markdownlint.mjs").LintError;
export type LintResults = import("./markdownlint.mjs").LintResults; export type LintResults = import("./markdownlint.mjs").LintResults;
export type MarkdownItFactory = import("./markdownlint.mjs").MarkdownItFactory;
export type MarkdownItToken = import("./markdownlint.mjs").MarkdownItToken; export type MarkdownItToken = import("./markdownlint.mjs").MarkdownItToken;
export type MarkdownParsers = import("./markdownlint.mjs").MarkdownParsers; export type MarkdownParsers = import("./markdownlint.mjs").MarkdownParsers;
export type MicromarkToken = import("./markdownlint.mjs").MicromarkToken; export type MicromarkToken = import("./markdownlint.mjs").MicromarkToken;

View file

@ -11,6 +11,7 @@ export { resolveModule } from "./resolve-module.cjs";
/** @typedef {import("./markdownlint.mjs").LintContentCallback} LintContentCallback */ /** @typedef {import("./markdownlint.mjs").LintContentCallback} LintContentCallback */
/** @typedef {import("./markdownlint.mjs").LintError} LintError */ /** @typedef {import("./markdownlint.mjs").LintError} LintError */
/** @typedef {import("./markdownlint.mjs").LintResults} LintResults */ /** @typedef {import("./markdownlint.mjs").LintResults} LintResults */
/** @typedef {import("./markdownlint.mjs").MarkdownItFactory} MarkdownItFactory */
/** @typedef {import("./markdownlint.mjs").MarkdownItToken} MarkdownItToken */ /** @typedef {import("./markdownlint.mjs").MarkdownItToken} MarkdownItToken */
/** @typedef {import("./markdownlint.mjs").MarkdownParsers} MarkdownParsers */ /** @typedef {import("./markdownlint.mjs").MarkdownParsers} MarkdownParsers */
/** @typedef {import("./markdownlint.mjs").MicromarkToken} MicromarkToken */ /** @typedef {import("./markdownlint.mjs").MicromarkToken} MicromarkToken */

View file

@ -4,6 +4,8 @@
const { newLineRe } = require("../helpers"); const { newLineRe } = require("../helpers");
// @ts-expect-error https://github.com/microsoft/TypeScript/issues/52529
/** @typedef {import("markdownlint").MarkdownItFactory} MarkdownItFactory */
// @ts-expect-error https://github.com/microsoft/TypeScript/issues/52529 // @ts-expect-error https://github.com/microsoft/TypeScript/issues/52529
/** @typedef {import("markdownlint").MarkdownItToken} MarkdownItToken */ /** @typedef {import("markdownlint").MarkdownItToken} MarkdownItToken */
// @ts-expect-error https://github.com/microsoft/TypeScript/issues/52529 // @ts-expect-error https://github.com/microsoft/TypeScript/issues/52529
@ -97,7 +99,7 @@ function freezeToken(token) {
/** /**
* Annotate tokens with line/lineNumber and freeze them. * Annotate tokens with line/lineNumber and freeze them.
* *
* @param {Object[]} tokens Array of markdown-it tokens. * @param {import("markdown-it").Token[]} tokens Array of markdown-it tokens.
* @param {string[]} lines Lines of Markdown content. * @param {string[]} lines Lines of Markdown content.
* @returns {void} * @returns {void}
*/ */
@ -152,21 +154,15 @@ function annotateAndFreezeTokens(tokens, lines) {
/** /**
* Gets an array of markdown-it tokens for the input. * Gets an array of markdown-it tokens for the input.
* *
* @param {Plugin[]} markdownItPlugins Additional plugins. * @param {MarkdownItFactory} markdownItFactory Function to create a markdown-it parser.
* @param {string} content Markdown content. * @param {string} content Markdown content.
* @param {string[]} lines Lines of Markdown content. * @param {string[]} lines Lines of Markdown content.
* @returns {MarkdownItToken} Array of markdown-it tokens. * @returns {MarkdownItToken[]} Array of markdown-it tokens.
*/ */
function getMarkdownItTokens(markdownItPlugins, content, lines) { function getMarkdownItTokens(markdownItFactory, content, lines) {
const markdownit = require("markdown-it"); const markdownIt = markdownItFactory();
const md = markdownit({ "html": true }); const tokens = markdownIt.parse(content, {});
for (const plugin of markdownItPlugins) {
// @ts-ignore
md.use(...plugin);
}
const tokens = md.parse(content, {});
annotateAndFreezeTokens(tokens, lines); annotateAndFreezeTokens(tokens, lines);
// @ts-ignore
return tokens; return tokens;
}; };

View file

@ -357,6 +357,23 @@ export type Rule = {
*/ */
function: RuleFunction; function: RuleFunction;
}; };
/**
* Method used by the markdown-it parser to parse input.
*/
export type MarkdownItParse = (src: string, env: any) => any[];
/**
* Instance of the markdown-it parser.
*/
export type MarkdownIt = {
/**
* Method to parse input.
*/
parse: MarkdownItParse;
};
/**
* Gets an instance of the markdown-it parser. Any plugins should already have been loaded.
*/
export type MarkdownItFactory = () => MarkdownIt;
/** /**
* Configuration options. * Configuration options.
*/ */
@ -390,9 +407,9 @@ export type Options = {
*/ */
handleRuleFailures?: boolean; handleRuleFailures?: boolean;
/** /**
* Additional plugins. * Function to create a markdown-it parser.
*/ */
markdownItPlugins?: Plugin[]; markdownItFactory?: MarkdownItFactory;
/** /**
* True to ignore HTML directives. * True to ignore HTML directives.
*/ */

View file

@ -447,7 +447,7 @@ function getEnabledRulesPerLineNumber(
* names. * names.
* @param {string} name Identifier for the content. * @param {string} name Identifier for the content.
* @param {string} content Markdown content. * @param {string} content Markdown content.
* @param {Plugin[]} markdownItPlugins Additional plugins. * @param {MarkdownItFactory} markdownItFactory Function to create a markdown-it parser.
* @param {Configuration} config Configuration object. * @param {Configuration} config Configuration object.
* @param {ConfigurationParser[] | null} configParsers Configuration parsers. * @param {ConfigurationParser[] | null} configParsers Configuration parsers.
* @param {RegExp | null} frontMatter Regular expression for front matter. * @param {RegExp | null} frontMatter Regular expression for front matter.
@ -462,7 +462,7 @@ function lintContent(
aliasToRuleNames, aliasToRuleNames,
name, name,
content, content,
markdownItPlugins, markdownItFactory,
config, config,
configParsers, configParsers,
frontMatter, frontMatter,
@ -502,7 +502,7 @@ function lintContent(
// Parse content into lines and get markdown-it tokens // Parse content into lines and get markdown-it tokens
const lines = content.split(helpers.newLineRe); const lines = content.split(helpers.newLineRe);
const markdownitTokens = needMarkdownItTokens ? const markdownitTokens = needMarkdownItTokens ?
requireMarkdownItCjs().getMarkdownItTokens(markdownItPlugins, preClearedContent, lines) : requireMarkdownItCjs().getMarkdownItTokens(markdownItFactory, preClearedContent, lines) :
[]; [];
// Create (frozen) parameters for rules // Create (frozen) parameters for rules
/** @type {MarkdownParsers} */ /** @type {MarkdownParsers} */
@ -754,10 +754,9 @@ function lintContent(
* Lints a file containing Markdown content. * Lints a file containing Markdown content.
* *
* @param {Rule[]} ruleList List of rules. * @param {Rule[]} ruleList List of rules.
* @param {Object.<string, string[]>} aliasToRuleNames Map of alias to rule * @param {Object.<string, string[]>} aliasToRuleNames Map of alias to rule names.
* names.
* @param {string} file Path of file to lint. * @param {string} file Path of file to lint.
* @param {Plugin[]} markdownItPlugins Additional plugins. * @param {MarkdownItFactory} markdownItFactory Function to create a markdown-it parser.
* @param {Configuration} config Configuration object. * @param {Configuration} config Configuration object.
* @param {ConfigurationParser[] | null} configParsers Configuration parsers. * @param {ConfigurationParser[] | null} configParsers Configuration parsers.
* @param {RegExp | null} frontMatter Regular expression for front matter. * @param {RegExp | null} frontMatter Regular expression for front matter.
@ -773,7 +772,7 @@ function lintFile(
ruleList, ruleList,
aliasToRuleNames, aliasToRuleNames,
file, file,
markdownItPlugins, markdownItFactory,
config, config,
configParsers, configParsers,
frontMatter, frontMatter,
@ -793,7 +792,7 @@ function lintFile(
aliasToRuleNames, aliasToRuleNames,
file, file,
content, content,
markdownItPlugins, markdownItFactory,
config, config,
configParsers, configParsers,
frontMatter, frontMatter,
@ -860,7 +859,9 @@ function lintInput(options, synchronous, callback) {
const resultVersion = (options.resultVersion === undefined) ? const resultVersion = (options.resultVersion === undefined) ?
3 : 3 :
options.resultVersion; options.resultVersion;
const markdownItPlugins = options.markdownItPlugins || []; const markdownItFactory =
options.markdownItFactory ||
(() => { throw new Error("The option 'markdownItFactory' was required (due to the option 'customRules' including a rule requiring the 'markdown-it' parser), but 'markdownItFactory' was not set."); });
const fs = options.fs || nodeFs; const fs = options.fs || nodeFs;
const aliasToRuleNames = mapAliasToRuleNames(ruleList); const aliasToRuleNames = mapAliasToRuleNames(ruleList);
const results = newResults(ruleList); const results = newResults(ruleList);
@ -892,7 +893,7 @@ function lintInput(options, synchronous, callback) {
ruleList, ruleList,
aliasToRuleNames, aliasToRuleNames,
currentItem, currentItem,
markdownItPlugins, markdownItFactory,
config, config,
configParsers, configParsers,
frontMatter, frontMatter,
@ -911,7 +912,7 @@ function lintInput(options, synchronous, callback) {
aliasToRuleNames, aliasToRuleNames,
currentItem, currentItem,
strings[currentItem] || "", strings[currentItem] || "",
markdownItPlugins, markdownItFactory,
config, config,
configParsers, configParsers,
frontMatter, frontMatter,
@ -1473,6 +1474,29 @@ export function getVersion() {
* @property {RuleFunction} function Rule implementation. * @property {RuleFunction} function Rule implementation.
*/ */
/**
* Method used by the markdown-it parser to parse input.
*
* @callback MarkdownItParse
* @param {string} src Source string.
* @param {Object} env Environment sandbox.
* @returns {import("markdown-it").Token[]} Tokens.
*/
/**
* Instance of the markdown-it parser.
*
* @typedef MarkdownIt
* @property {MarkdownItParse} parse Method to parse input.
*/
/**
* Gets an instance of the markdown-it parser. Any plugins should already have been loaded.
*
* @callback MarkdownItFactory
* @returns {MarkdownIt} Instance of the markdown-it parser.
*/
/** /**
* Configuration options. * Configuration options.
* *
@ -1484,7 +1508,7 @@ export function getVersion() {
* @property {RegExp | null} [frontMatter] Front matter pattern. * @property {RegExp | null} [frontMatter] Front matter pattern.
* @property {Object} [fs] File system implementation. * @property {Object} [fs] File system implementation.
* @property {boolean} [handleRuleFailures] True to catch exceptions. * @property {boolean} [handleRuleFailures] True to catch exceptions.
* @property {Plugin[]} [markdownItPlugins] Additional plugins. * @property {MarkdownItFactory} [markdownItFactory] Function to create a markdown-it parser.
* @property {boolean} [noInlineConfig] True to ignore HTML directives. * @property {boolean} [noInlineConfig] True to ignore HTML directives.
* @property {number} [resultVersion] Results object version. * @property {number} [resultVersion] Results object version.
* @property {Object.<string, string>} [strings] Strings to lint. * @property {Object.<string, string>} [strings] Strings to lint.
@ -1501,7 +1525,7 @@ export function getVersion() {
* *
* @callback ToStringCallback * @callback ToStringCallback
* @param {boolean} [ruleAliases] True to use rule aliases. * @param {boolean} [ruleAliases] True to use rule aliases.
* @returns {string} * @returns {string} Pretty-printed results.
*/ */
/** /**

View file

@ -73,7 +73,6 @@
"node": ">=18" "node": ">=18"
}, },
"dependencies": { "dependencies": {
"markdown-it": "14.1.0",
"micromark": "4.0.1", "micromark": "4.0.1",
"micromark-core-commonmark": "2.0.2", "micromark-core-commonmark": "2.0.2",
"micromark-extension-directive": "3.0.2", "micromark-extension-directive": "3.0.2",
@ -100,6 +99,7 @@
"js-yaml": "4.1.0", "js-yaml": "4.1.0",
"json-schema-to-typescript": "15.0.4", "json-schema-to-typescript": "15.0.4",
"jsonc-parser": "3.3.1", "jsonc-parser": "3.3.1",
"markdown-it": "14.1.0",
"markdown-it-for-inline": "2.0.1", "markdown-it-for-inline": "2.0.1",
"markdown-it-sub": "2.0.0", "markdown-it-sub": "2.0.0",
"markdown-it-sup": "2.0.0", "markdown-it-sup": "2.0.0",

View file

@ -4,6 +4,7 @@ import fs from "node:fs/promises";
import { createRequire } from "node:module"; import { createRequire } from "node:module";
const require = createRequire(import.meta.url); const require = createRequire(import.meta.url);
import test from "ava"; import test from "ava";
import markdownIt from "markdown-it";
import { lint as lintAsync } from "markdownlint/async"; import { lint as lintAsync } from "markdownlint/async";
import { lint as lintPromise } from "markdownlint/promise"; import { lint as lintPromise } from "markdownlint/promise";
import { lint as lintSync } from "markdownlint/sync"; import { lint as lintSync } from "markdownlint/sync";
@ -13,6 +14,8 @@ import { __filename, importWithTypeJson } from "./esm-helpers.mjs";
const packageJson = await importWithTypeJson(import.meta, "../package.json"); const packageJson = await importWithTypeJson(import.meta, "../package.json");
const { homepage, version } = packageJson; const { homepage, version } = packageJson;
const markdownItFactory = () => markdownIt({ "html": true });
test("customRulesV0", (t) => new Promise((resolve) => { test("customRulesV0", (t) => new Promise((resolve) => {
t.plan(4); t.plan(4);
const customRulesMd = "./test/custom-rules.md"; const customRulesMd = "./test/custom-rules.md";
@ -20,6 +23,7 @@ test("customRulesV0", (t) => new Promise((resolve) => {
const options = { const options = {
"customRules": customRules.all, "customRules": customRules.all,
"files": [ customRulesMd ], "files": [ customRulesMd ],
markdownItFactory,
"resultVersion": 0 "resultVersion": 0
}; };
lintAsync(options, function callback(err, actualResult) { lintAsync(options, function callback(err, actualResult) {
@ -92,6 +96,7 @@ test("customRulesV1", (t) => new Promise((resolve) => {
const options = { const options = {
"customRules": customRules.all, "customRules": customRules.all,
"files": [ customRulesMd ], "files": [ customRulesMd ],
markdownItFactory,
"resultVersion": 1 "resultVersion": 1
}; };
lintAsync(options, function callback(err, actualResult) { lintAsync(options, function callback(err, actualResult) {
@ -223,6 +228,7 @@ test("customRulesV2", (t) => new Promise((resolve) => {
const options = { const options = {
"customRules": customRules.all, "customRules": customRules.all,
"files": [ customRulesMd ], "files": [ customRulesMd ],
markdownItFactory,
"resultVersion": 2 "resultVersion": 2
}; };
lintAsync(options, function callback(err, actualResult) { lintAsync(options, function callback(err, actualResult) {
@ -351,6 +357,7 @@ test("customRulesConfig", (t) => new Promise((resolve) => {
}, },
"letters-e-x": false "letters-e-x": false
}, },
markdownItFactory,
"resultVersion": 0 "resultVersion": 0
}; };
lintAsync(options, function callback(err, actualResult) { lintAsync(options, function callback(err, actualResult) {
@ -376,6 +383,7 @@ test("customRulesNpmPackage", (t) => new Promise((resolve) => {
require("./rules/npm"), require("./rules/npm"),
require("markdownlint-rule-extended-ascii") require("markdownlint-rule-extended-ascii")
], ],
markdownItFactory,
"strings": { "strings": {
"string": "# Text\n\n---\n\nText ✅\n" "string": "# Text\n\n---\n\nText ✅\n"
}, },
@ -555,11 +563,12 @@ test("customRulesParserUndefined", (t) => {
} }
} }
], ],
markdownItFactory,
"strings": { "strings": {
"string": "# Heading\n" "string": "# Heading\n"
} }
}; };
return lintPromise(options).then(() => null); return lintPromise(options);
}); });
test("customRulesParserNone", (t) => { test("customRulesParserNone", (t) => {
@ -583,7 +592,7 @@ test("customRulesParserNone", (t) => {
"string": "# Heading\n" "string": "# Heading\n"
} }
}; };
return lintPromise(options).then(() => null); return lintPromise(options);
}); });
test("customRulesParserMarkdownIt", (t) => { test("customRulesParserMarkdownIt", (t) => {
@ -606,11 +615,12 @@ test("customRulesParserMarkdownIt", (t) => {
} }
} }
], ],
markdownItFactory,
"strings": { "strings": {
"string": "# Heading\n" "string": "# Heading\n"
} }
}; };
return lintPromise(options).then(() => null); return lintPromise(options);
}); });
test("customRulesParserMicromark", (t) => { test("customRulesParserMicromark", (t) => {
@ -637,7 +647,33 @@ test("customRulesParserMicromark", (t) => {
"string": "# Heading\n" "string": "# Heading\n"
} }
}; };
return lintPromise(options).then(() => null); return lintPromise(options);
});
test("customRulesMarkdownItFactoryUndefined", (t) => {
t.plan(1);
/** @type {import("markdownlint").Options} */
const options = {
"customRules": [
{
"names": [ "name" ],
"description": "description",
"tags": [ "tag" ],
"parser": "markdownit",
"function": () => {}
}
],
"strings": {
"string": "# Heading\n"
}
};
t.throws(
() => lintSync(options),
{
"message": "The option 'markdownItFactory' was required (due to the option 'customRules' including a rule requiring the 'markdown-it' parser), but 'markdownItFactory' was not set."
},
"No exception when markdownItFactory is undefined."
);
}); });
test("customRulesMarkdownItParamsTokensSameObject", (t) => { test("customRulesMarkdownItParamsTokensSameObject", (t) => {
@ -657,11 +693,12 @@ test("customRulesMarkdownItParamsTokensSameObject", (t) => {
} }
} }
], ],
markdownItFactory,
"strings": { "strings": {
"string": "# Heading\n" "string": "# Heading\n"
} }
}; };
return lintPromise(options).then(() => null); return lintPromise(options);
}); });
test("customRulesMarkdownItTokensSnapshot", (t) => { test("customRulesMarkdownItTokensSnapshot", (t) => {
@ -680,13 +717,14 @@ test("customRulesMarkdownItTokensSnapshot", (t) => {
} }
} }
], ],
markdownItFactory,
"noInlineConfig": true "noInlineConfig": true
}; };
return fs return fs
.readFile("./test/every-markdown-syntax.md", "utf8") .readFile("./test/every-markdown-syntax.md", "utf8")
.then((content) => { .then((content) => {
options.strings = { "content": content.split(newLineRe).join("\n") }; options.strings = { "content": content.split(newLineRe).join("\n") };
return lintPromise(options).then(() => null); return lintPromise(options);
}); });
}); });
@ -712,7 +750,7 @@ test("customRulesMicromarkTokensSnapshot", (t) => {
.readFile("./test/every-markdown-syntax.md", "utf8") .readFile("./test/every-markdown-syntax.md", "utf8")
.then((content) => { .then((content) => {
options.strings = { "content": content.split(newLineRe).join("\n") }; options.strings = { "content": content.split(newLineRe).join("\n") };
return lintPromise(options).then(() => null); return lintPromise(options);
}); });
}); });
@ -1665,7 +1703,8 @@ test("customRulesLintJavaScript", (t) => new Promise((resolve) => {
/** @type {import("markdownlint").Options} */ /** @type {import("markdownlint").Options} */
const options = { const options = {
"customRules": customRules.lintJavaScript, "customRules": customRules.lintJavaScript,
"files": "test/lint-javascript.md" "files": "test/lint-javascript.md",
markdownItFactory
}; };
lintAsync(options, (err, actual) => { lintAsync(options, (err, actual) => {
t.falsy(err); t.falsy(err);
@ -1693,7 +1732,8 @@ test("customRulesValidateJson", (t) => new Promise((resolve) => {
/** @type {import("markdownlint").Options} */ /** @type {import("markdownlint").Options} */
const options = { const options = {
"customRules": customRules.validateJson, "customRules": customRules.validateJson,
"files": "test/validate-json.md" "files": "test/validate-json.md",
markdownItFactory
}; };
lintAsync(options, (err, actual) => { lintAsync(options, (err, actual) => {
t.falsy(err); t.falsy(err);
@ -1792,9 +1832,10 @@ test("customRulesParamsAreFrozen", (t) => {
"function": assertParamsFrozen "function": assertParamsFrozen
} }
], ],
"files": [ "README.md" ] "files": [ "README.md" ],
markdownItFactory
}; };
return lintPromise(options).then(() => null); return lintPromise(options);
}); });
test("customRulesParamsAreStable", (t) => { test("customRulesParamsAreStable", (t) => {
@ -1862,7 +1903,7 @@ test("customRulesParamsAreStable", (t) => {
"string": "# Heading" "string": "# Heading"
} }
}; };
return lintPromise(options).then(() => null); return lintPromise(options);
}); });
test("customRulesAsyncReadFiles", (t) => { test("customRulesAsyncReadFiles", (t) => {

View file

@ -30,6 +30,23 @@ const ajvOptions = {
"allowUnionTypes": true "allowUnionTypes": true
}; };
/**
* Gets an instance of a markdown-it factory, suitable for use with options.markdownItFactory.
*
* @param {import("../lib/markdownlint.mjs").Plugin[]} markdownItPlugins Additional markdown-it plugins.
* @returns {import("../lib/markdownlint.mjs").MarkdownItFactory} Function to create a markdown-it parser.
*/
function getMarkdownItFactory(markdownItPlugins) {
return () => {
const md = markdownIt({ "html": true });
for (const markdownItPlugin of markdownItPlugins) {
// @ts-ignore
md.use(...markdownItPlugin);
}
return md;
};
}
test("simpleAsync", (t) => new Promise((resolve) => { test("simpleAsync", (t) => new Promise((resolve) => {
t.plan(2); t.plan(2);
const options = { const options = {
@ -622,7 +639,7 @@ test("readmeHeadings", (t) => new Promise((resolve) => {
"##### options.frontMatter", "##### options.frontMatter",
"##### options.fs", "##### options.fs",
"##### options.handleRuleFailures", "##### options.handleRuleFailures",
"##### options.markdownItPlugins", "##### options.markdownItFactory",
"##### options.noInlineConfig", "##### options.noInlineConfig",
"##### options.resultVersion", "##### options.resultVersion",
"##### options.strings", "##### options.strings",
@ -1054,9 +1071,9 @@ test("markdownItPluginsSingle", (t) => new Promise((resolve) => {
}, },
// Use a markdown-it custom rule so the markdown-it plugin will be run // Use a markdown-it custom rule so the markdown-it plugin will be run
"customRules": customRules.anyBlockquote, "customRules": customRules.anyBlockquote,
"markdownItPlugins": [ "markdownItFactory": getMarkdownItFactory([
[ pluginInline, "check_text_plugin", "text", () => t.true(true) ] [ pluginInline, "check_text_plugin", "text", () => t.true(true) ]
] ])
}, function callback(err, actual) { }, function callback(err, actual) {
t.falsy(err); t.falsy(err);
const expected = { "string": [] }; const expected = { "string": [] };
@ -1073,12 +1090,12 @@ test("markdownItPluginsMultiple", (t) => new Promise((resolve) => {
}, },
// Use a markdown-it custom rule so the markdown-it plugin will be run // Use a markdown-it custom rule so the markdown-it plugin will be run
"customRules": customRules.anyBlockquote, "customRules": customRules.anyBlockquote,
"markdownItPlugins": [ "markdownItFactory": getMarkdownItFactory([
[ pluginSub ], [ pluginSub ],
[ pluginSup ], [ pluginSup ],
[ pluginInline, "check_sub_plugin", "sub_open", () => t.true(true) ], [ pluginInline, "check_sub_plugin", "sub_open", () => t.true(true) ],
[ pluginInline, "check_sup_plugin", "sup_open", () => t.true(true) ] [ pluginInline, "check_sup_plugin", "sup_open", () => t.true(true) ]
] ])
}, function callback(err, actual) { }, function callback(err, actual) {
t.falsy(err); t.falsy(err);
const expected = { "string": [] }; const expected = { "string": [] };
@ -1093,9 +1110,9 @@ test("markdownItPluginsNoMarkdownIt", (t) => new Promise((resolve) => {
"strings": { "strings": {
"string": "# Heading\n\nText\n" "string": "# Heading\n\nText\n"
}, },
"markdownItPlugins": [ "markdownItFactory": getMarkdownItFactory([
[ pluginInline, "check_text_plugin", "text", () => t.fail() ] [ pluginInline, "check_text_plugin", "text", () => t.fail() ]
] ])
}, function callback(err, actual) { }, function callback(err, actual) {
t.falsy(err); t.falsy(err);
const expected = { "string": [] }; const expected = { "string": [] };
@ -1115,9 +1132,9 @@ test("markdownItPluginsUnusedUncalled", (t) => new Promise((resolve) => {
}, },
// Use a markdown-it custom rule so the markdown-it plugin will be run // Use a markdown-it custom rule so the markdown-it plugin will be run
"customRules": customRules.anyBlockquote, "customRules": customRules.anyBlockquote,
"markdownItPlugins": [ "markdownItFactory": getMarkdownItFactory([
[ pluginInline, "check_text_plugin", "text", () => t.fail() ] [ pluginInline, "check_text_plugin", "text", () => t.fail() ]
] ])
}, function callback(err, actual) { }, function callback(err, actual) {
t.falsy(err); t.falsy(err);
const expected = { "string": [] }; const expected = { "string": [] };
@ -1184,7 +1201,8 @@ test("token-map-spans", (t) => {
} }
} }
], ],
"files": [ "./test/token-map-spans.md" ] "files": [ "./test/token-map-spans.md" ],
"markdownItFactory": getMarkdownItFactory([])
}; };
lintSync(options); lintSync(options);
}); });