Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ deno add jsr:@eslint/markdown

| **Configuration Name** | **Description** |
| ---------------------- | ---------------------------------------------------------------------------------------------------------- |
| `recommended` | Lints all `.md` files with the recommended rules and assumes [CommonMark](https://commonmark.org/) format. |
| `recommended` | Lints all `.md` files with the recommended rules and assumes [GFM](https://github.github.com/gfm/) format. |
| `processor` | Enables extracting code blocks from all `.md` files so code blocks can be individually linted. |

In your `eslint.config.js` file, import `@eslint/markdown` and include the recommended config to enable Markdown parsing and linting:
Expand Down
2 changes: 1 addition & 1 deletion examples/typescript/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
},
"devDependencies": {
"@eslint/js": "^10.0.1",
"eslint": "^10.0.3",
"eslint": "^10.6.0",
"typescript": "^6.0.3",
"typescript-eslint": "^8.59.1"
}
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@
"@types/unist": "^3.0.3",
"c8": "^11.0.0",
"dedent": "^1.7.1",
"eslint": "^10.0.3",
"eslint": "^10.6.0",
"eslint-v9": "npm:eslint@9.x",
"eslint-config-eslint": "^14.0.0",
"eslint-plugin-eslint-plugin": "^7.3.2",
Expand Down
3 changes: 2 additions & 1 deletion src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ let recommendedPlugins, processorPlugins;
const plugin = {
meta: {
name: "@eslint/markdown",
namespace: "markdown",
version: "8.0.3", // x-release-please-version
},
processors: {
Expand Down Expand Up @@ -92,7 +93,7 @@ const plugin = {
{
name: "markdown/recommended",
files: ["**/*.md"],
language: "markdown/commonmark",
language: "markdown/gfm",

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since the table-column-count rule only works in GFM mode, using the recommended config with commonmark causes the following error:

Oops! Something went wrong! :(

ESLint: 10.6.0

The following rules do not support the language "markdown/commonmark":
	- "markdown/table-column-count"

To fix this error, either:
- Remove the rule from your configuration, or set its severity to "off".
- Use the "files" option to apply the rule only to files of the supported language, for example:
  {
    files: ["**/*.js"],
    rules: { "markdown/table-column-count": "error" }
  }

See https://eslint.org/docs/latest/use/configure/rules for more information.

I think there are two possible approaches to resolve this:

The first is to set the recommended config's language to gfm.

The second is to remove the table-column-count rule from the recommended config and keep commonmark mode.

I'm personally inclined to use gfm since GFM syntax is widely used in Markdown documentation, but I'd like to bring this up in case others have a different perspective.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since rules currently can't tell which language they're running under (the rule context exposes languageOptions but not language) this doesn’t seem solvable in the rule itself.

Given that, I wonder if the better option might be to keep markdown/commonmark as the default language, since it's the more general subset, and remove rules that aren't compatible with CommonMark from the recommended config. Interested to hear what others think. @eslint/eslint-team

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree that the default recommended config should stay with commonmark mode.
As such I think we should introduce recommended-gfm which sets the language to markdown/gfm and includes table-column-count.
For recommended we can remove table-column-count as it would never report anyway as there are no table elements in commonmark.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does the table selector used in table-column-count only exist in GFM? If so, perhaps we could declare that the rule supports both "markdown/commonmark" and "markdown/gfm", but it would only report problems in GFM.

plugins: (recommendedPlugins = {}),
Comment thread
lumirlumir marked this conversation as resolved.
rules: recommendedRules,
},
Expand Down
2 changes: 2 additions & 0 deletions src/rules/fenced-code-language.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,12 @@ const fencedCodeCharacters = new Set(["`", "~"]);
export default /** @satisfies {FencedCodeLanguageRuleDefinition} */ ({
meta: {
type: "problem",
languages: ["markdown/commonmark", "markdown/gfm"],

docs: {
recommended: true,
description: "Require languages for fenced code blocks",
dialects: ["CommonMark", "GFM"],
url: "https://github.com/eslint/markdown/blob/main/docs/rules/fenced-code-language.md",
},

Expand Down
2 changes: 2 additions & 0 deletions src/rules/fenced-code-meta.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,12 @@
export default /** @satisfies {FencedCodeMetaRuleDefinition} */ ({
meta: {
type: "problem",
languages: ["markdown/commonmark", "markdown/gfm"],

docs: {
recommended: false,
description: "Require or disallow metadata for fenced code blocks",
dialects: ["CommonMark", "GFM"],
url: "https://github.com/eslint/markdown/blob/main/docs/rules/fenced-code-meta.md",
},

Expand Down
2 changes: 2 additions & 0 deletions src/rules/heading-increment.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,12 @@ import { frontmatterHasTitle } from "../util.js";
export default /** @satisfies {HeadingIncrementRuleDefinition} */ ({
meta: {
type: "problem",
languages: ["markdown/commonmark", "markdown/gfm"],

docs: {
recommended: true,
description: "Enforce heading levels increment by one",
dialects: ["CommonMark", "GFM"],
url: "https://github.com/eslint/markdown/blob/main/docs/rules/heading-increment.md",
},

Expand Down
2 changes: 2 additions & 0 deletions src/rules/no-bare-urls.js
Original file line number Diff line number Diff line change
Expand Up @@ -69,9 +69,11 @@ function parseHtmlTag(tagText) {
export default /** @satisfies {NoBareUrlsRuleDefinition} */ ({
meta: {
type: "problem",
languages: ["markdown/gfm"],

docs: {
description: "Disallow bare URLs",
dialects: ["GFM"],
url: "https://github.com/eslint/markdown/blob/main/docs/rules/no-bare-urls.md",
},

Expand Down
2 changes: 2 additions & 0 deletions src/rules/no-duplicate-definitions.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,12 @@ import { normalizeIdentifier } from "micromark-util-normalize-identifier";
export default /** @satisfies {NoDuplicateDefinitionsRuleDefinition} */ ({
meta: {
type: "problem",
languages: ["markdown/commonmark", "markdown/gfm"],

docs: {
recommended: true,
description: "Disallow duplicate definitions",
dialects: ["CommonMark", "GFM"],
url: "https://github.com/eslint/markdown/blob/main/docs/rules/no-duplicate-definitions.md",
},

Expand Down
2 changes: 2 additions & 0 deletions src/rules/no-duplicate-headings.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,11 @@
export default /** @satisfies {NoDuplicateHeadingsRuleDefinition} */ ({
meta: {
type: "problem",
languages: ["markdown/commonmark", "markdown/gfm"],

docs: {
description: "Disallow duplicate headings in the same document",
dialects: ["CommonMark", "GFM"],
url: "https://github.com/eslint/markdown/blob/main/docs/rules/no-duplicate-headings.md",
},

Expand Down
2 changes: 2 additions & 0 deletions src/rules/no-empty-definitions.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,10 +43,12 @@ function isOnlyComments(value) {
export default /** @satisfies {NoEmptyDefinitionsRuleDefinition} */ ({
meta: {
type: "problem",
languages: ["markdown/commonmark", "markdown/gfm"],

docs: {
recommended: true,
description: "Disallow empty definitions",
dialects: ["CommonMark", "GFM"],
url: "https://github.com/eslint/markdown/blob/main/docs/rules/no-empty-definitions.md",
},

Expand Down
2 changes: 2 additions & 0 deletions src/rules/no-empty-images.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,12 @@
export default /** @satisfies {NoEmptyImagesRuleDefinition} */ ({
meta: {
type: "problem",
languages: ["markdown/commonmark", "markdown/gfm"],

docs: {
recommended: true,
description: "Disallow empty images",
dialects: ["CommonMark", "GFM"],
url: "https://github.com/eslint/markdown/blob/main/docs/rules/no-empty-images.md",
},

Expand Down
2 changes: 2 additions & 0 deletions src/rules/no-empty-links.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,12 @@
export default /** @satisfies {NoEmptyLinksRuleDefinition} */ ({
meta: {
type: "problem",
languages: ["markdown/commonmark", "markdown/gfm"],

docs: {
recommended: true,
description: "Disallow empty links",
dialects: ["CommonMark", "GFM"],
url: "https://github.com/eslint/markdown/blob/main/docs/rules/no-empty-links.md",
},

Expand Down
2 changes: 2 additions & 0 deletions src/rules/no-html.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,11 @@ const htmlTagPattern =
export default /** @satisfies {NoHtmlRuleDefinition} */ ({
meta: {
type: "problem",
languages: ["markdown/commonmark", "markdown/gfm"],

docs: {
description: "Disallow HTML tags",
dialects: ["CommonMark", "GFM"],
url: "https://github.com/eslint/markdown/blob/main/docs/rules/no-html.md",
},

Expand Down
2 changes: 2 additions & 0 deletions src/rules/no-invalid-label-refs.js
Original file line number Diff line number Diff line change
Expand Up @@ -108,10 +108,12 @@ function findInvalidLabelReferences(node, sourceCode) {
export default /** @satisfies {NoInvalidLabelRefsRuleDefinition} */ ({
meta: {
type: "problem",
languages: ["markdown/commonmark", "markdown/gfm"],

docs: {
recommended: true,
description: "Disallow invalid label references",
dialects: ["CommonMark", "GFM"],
url: "https://github.com/eslint/markdown/blob/main/docs/rules/no-invalid-label-refs.md",
},

Expand Down
2 changes: 2 additions & 0 deletions src/rules/no-missing-atx-heading-space.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,13 @@ const trailingAtxHeadingHashPattern =
export default /** @satisfies {NoMissingAtxHeadingSpaceRuleDefinition} */ ({
meta: {
type: "problem",
languages: ["markdown/commonmark", "markdown/gfm"],

docs: {
recommended: true,
description:
"Disallow headings without a space after the hash characters",
dialects: ["CommonMark", "GFM"],
url: "https://github.com/eslint/markdown/blob/main/docs/rules/no-missing-atx-heading-space.md",
},

Expand Down
2 changes: 2 additions & 0 deletions src/rules/no-missing-label-refs.js
Original file line number Diff line number Diff line change
Expand Up @@ -98,10 +98,12 @@ function findMissingReferences(node, sourceCode) {
export default /** @satisfies {NoMissingLabelRefsRuleDefinition} */ ({
meta: {
type: "problem",
languages: ["markdown/commonmark", "markdown/gfm"],

docs: {
recommended: true,
description: "Disallow missing label references",
dialects: ["CommonMark", "GFM"],
url: "https://github.com/eslint/markdown/blob/main/docs/rules/no-missing-label-refs.md",
},

Expand Down
2 changes: 2 additions & 0 deletions src/rules/no-missing-link-fragments.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,11 +42,13 @@ const htmlTagPattern =
export default /** @satisfies {NoMissingLinkFragmentsRuleDefinition} */ ({
meta: {
type: "problem",
languages: ["markdown/commonmark", "markdown/gfm"],

docs: {
recommended: true,
description:
"Disallow link fragments that do not reference valid headings",
dialects: ["CommonMark", "GFM"],
url: "https://github.com/eslint/markdown/blob/main/docs/rules/no-missing-link-fragments.md",
},

Expand Down
2 changes: 2 additions & 0 deletions src/rules/no-multiple-h1.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,12 @@ const h1TagPattern = /<h1[^>]*>[\s\S]*?<\/h1\s*>/giu;
export default /** @satisfies {NoMultipleH1RuleDefinition} */ ({
meta: {
type: "problem",
languages: ["markdown/commonmark", "markdown/gfm"],

docs: {
recommended: true,
description: "Disallow multiple H1 headings in the same document",
dialects: ["CommonMark", "GFM"],
url: "https://github.com/eslint/markdown/blob/main/docs/rules/no-multiple-h1.md",
},

Expand Down
2 changes: 2 additions & 0 deletions src/rules/no-reference-like-urls.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,11 +36,13 @@ const linkOrImagePattern =
export default /** @satisfies {NoReferenceLikeUrlsRuleDefinition} */ ({
meta: {
type: "problem",
languages: ["markdown/commonmark", "markdown/gfm"],

docs: {
recommended: true,
description:
"Disallow URLs that match defined reference identifiers",
dialects: ["CommonMark", "GFM"],
url: "https://github.com/eslint/markdown/blob/main/docs/rules/no-reference-like-urls.md",
},

Expand Down
2 changes: 2 additions & 0 deletions src/rules/no-reversed-media-syntax.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,12 @@ const reversedPattern =
export default /** @satisfies {NoReversedMediaSyntaxRuleDefinition} */ ({
meta: {
type: "problem",
languages: ["markdown/commonmark", "markdown/gfm"],

docs: {
recommended: true,
description: "Disallow reversed link and image syntax",
dialects: ["CommonMark", "GFM"],
url: "https://github.com/eslint/markdown/blob/main/docs/rules/no-reversed-media-syntax.md",
},

Expand Down
2 changes: 2 additions & 0 deletions src/rules/no-space-in-emphasis.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,10 +40,12 @@ function createMarkerPattern(checkStrikethrough) {
export default /** @satisfies {NoSpaceInEmphasisRuleDefinition} */ ({
meta: {
type: "problem",
languages: ["markdown/commonmark", "markdown/gfm"],

docs: {
recommended: true,
description: "Disallow spaces around emphasis markers",
dialects: ["CommonMark", "GFM"],
url: "https://github.com/eslint/markdown/blob/main/docs/rules/no-space-in-emphasis.md",
},

Expand Down
2 changes: 2 additions & 0 deletions src/rules/no-unused-definitions.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,12 @@ import { normalizeIdentifier } from "micromark-util-normalize-identifier";
export default /** @satisfies {NoUnusedDefinitionsRuleDefinition} */ ({
meta: {
type: "problem",
languages: ["markdown/commonmark", "markdown/gfm"],

docs: {
recommended: true,
description: "Disallow unused definitions",
dialects: ["CommonMark", "GFM"],
url: "https://github.com/eslint/markdown/blob/main/docs/rules/no-unused-definitions.md",
},

Expand Down
2 changes: 2 additions & 0 deletions src/rules/require-alt-text.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,10 +43,12 @@ function getHtmlAttributeRe(name) {
export default /** @satisfies {RequireAltTextRuleDefinition} */ ({
meta: {
type: "problem",
languages: ["markdown/commonmark", "markdown/gfm"],

docs: {
recommended: true,
description: "Require alternative text for images",
dialects: ["CommonMark", "GFM"],
url: "https://github.com/eslint/markdown/blob/main/docs/rules/require-alt-text.md",
},

Expand Down
2 changes: 2 additions & 0 deletions src/rules/table-column-count.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,13 @@
export default /** @satisfies {TableColumnCountRuleDefinition} */ ({
meta: {
type: "problem",
languages: ["markdown/gfm"],

docs: {
recommended: true,
description:
"Disallow data rows in a GitHub Flavored Markdown table from having more cells than the header row",
dialects: ["GFM"],
url: "https://github.com/eslint/markdown/blob/main/docs/rules/table-column-count.md",
},

Expand Down
47 changes: 47 additions & 0 deletions tests/plugin.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ describe("meta", () => {
it("should export meta property", () => {
assert.deepStrictEqual(plugin.meta, {
name: "@eslint/markdown",
namespace: "markdown",
version: pkg.version,
});
});
Expand Down Expand Up @@ -2393,4 +2394,50 @@ describe("FlatESLint", () => {
assert.strictEqual(results[0].messages.length, 0);
});
});

describe("Languages", () => {
Object.keys(plugin.configs).forEach(configName => {
it(`Using "${configName}" config should not throw`, async () => {
const eslint = new ESLint({
overrideConfigFile: true,
overrideConfig: plugin.configs[configName],
});

await eslint.lintText("Foo Bar Baz", { filePath: "test.md" });
});
});

it("rules should work when the plugin is registered under a custom namespace", async () => {
for (const language of ["commonmark", "gfm"]) {
const eslint = new ESLint({
overrideConfigFile: true,
overrideConfig: {
files: ["**/*.md"],
plugins: {
eslintmarkdown: plugin,
},
language: `eslintmarkdown/${language}`,
rules: {
"eslintmarkdown/no-empty-images": "error",
},
},
});

const results = await eslint.lintText("![alt]()", {
filePath: "test.md",
});

assert.strictEqual(results.length, 1);
assert.strictEqual(results[0].messages.length, 1);
assert.strictEqual(
results[0].messages[0].ruleId,
"eslintmarkdown/no-empty-images",
);
assert.strictEqual(
results[0].messages[0].messageId,
"emptyImage",
);
}
});
});
});
1 change: 1 addition & 0 deletions tests/types/types.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ markdown satisfies Plugin;
// See: https://github.com/eslint/markdown/pull/648
markdown satisfies ESLint.Plugin;
markdown.meta.name satisfies string;
markdown.meta.namespace satisfies string;
markdown.meta.version satisfies string;

// Check that the processor is defined:
Expand Down
Loading