Skip to content
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
2ae787e
refactor: align rule type definitions with conventions from other plu…
lumirlumir May 9, 2025
d9b4be6
wip
lumirlumir May 9, 2025
f023049
wip: update `dedupe-types`
lumirlumir May 9, 2025
c65d558
wip: update `rules` type import path
lumirlumir May 9, 2025
7e73c58
wip: complete migration
lumirlumir May 9, 2025
bfb7894
wip: fix errors
lumirlumir May 9, 2025
31d2a1b
wip: cleanup
lumirlumir May 9, 2025
e66c951
wip: complete migration
lumirlumir May 9, 2025
1ead275
wip
lumirlumir May 9, 2025
b1e6298
Merge branch 'main' of https://github.com/eslint/markdown into refact…
lumirlumir Jun 21, 2025
6daf0a6
wip: revert type testing
lumirlumir Jun 21, 2025
200a2e9
wip: update `index.js`
lumirlumir Jun 21, 2025
d047161
wip: update `fenced-code-language.js`
lumirlumir Jun 21, 2025
1c62c89
wip: update `heading-increment.js`
lumirlumir Jun 21, 2025
ffa31ed
wip: update `no-bare-urls`
lumirlumir Jun 21, 2025
2e6f981
wip: update `no-duplicate-definitions.js`
lumirlumir Jun 21, 2025
eb27cc1
wip: update `no-duplicate-headings.js`
lumirlumir Jun 21, 2025
a0db87f
wip: add optional property to `no-duplicate-definitions`
lumirlumir Jun 21, 2025
3aea485
wip: update `no-empty-definitions.js`
lumirlumir Jun 21, 2025
c2df307
wip: update `no-empty-images.js`
lumirlumir Jun 21, 2025
89d8406
wip: update `no-empty-links.js`
lumirlumir Jun 21, 2025
b046450
wip: update `no-html.js`
lumirlumir Jun 21, 2025
655d241
wip: update `no-invalid-label-refs.js`
lumirlumir Jun 21, 2025
2dfb75f
wip: update `no-missing-atx-heading-space.js`
lumirlumir Jun 21, 2025
36f64d4
wip: update `no-missing-label-refs.js`
lumirlumir Jun 21, 2025
5b992fe
wip: update `index.js`
lumirlumir Jun 21, 2025
6e6c436
wip: fix CI error
lumirlumir Jun 21, 2025
cb574f4
wip: update `no-missing-link-fragements.js`
lumirlumir Jun 21, 2025
c1f6c24
wip: update `types.ts`
lumirlumir Jun 21, 2025
6cac104
wip: update `no-multiple-h1.js`
lumirlumir Jun 21, 2025
af428d2
wip: update `no-reversed-media-syntax.js`
lumirlumir Jun 21, 2025
fa288c2
wip: update `require-alt-text.js`
lumirlumir Jun 21, 2025
4f73f4d
wip: update `table-column-count.js`
lumirlumir Jun 21, 2025
be286e6
wip: more accurate type
lumirlumir Jun 22, 2025
7de7180
wip: typo
lumirlumir Jun 22, 2025
c01f54e
Merge branch 'main' of https://github.com/eslint/markdown into refact…
lumirlumir Jun 23, 2025
47f06b7
wip: extra blank line
lumirlumir Jun 23, 2025
a001891
wip: address comment
lumirlumir Jun 25, 2025
7e3f031
Merge branch 'main' into refactor-align-rule-type-definitions-with-co…
lumirlumir Jul 1, 2025
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
17 changes: 1 addition & 16 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,26 +13,11 @@ import { MarkdownSourceCode } from "./language/markdown-source-code.js";
import recommendedRules from "./build/recommended-config.js";
import rules from "./build/rules.js";

//-----------------------------------------------------------------------------
// Type Definitions
//-----------------------------------------------------------------------------

/** @typedef {import("eslint").Linter.RulesRecord} RulesRecord*/
/** @typedef {import("eslint").Linter.Config} Config*/
/** @typedef {import("eslint").ESLint.Plugin} Plugin */
/**
* @typedef {import("./types.ts").MarkdownRuleDefinition<Options>} MarkdownRuleDefinition<Options>
* @template {Partial<import("./types.ts").MarkdownRuleDefinitionTypeOptions>} [Options={}]
*/
/** @typedef {MarkdownRuleDefinition} RuleModule */
/** @typedef {import("./types.ts").MarkdownRuleVisitor} MarkdownRuleVisitor */
/** @typedef {import("@eslint/core").Language} Language */

//-----------------------------------------------------------------------------
// Exports
//-----------------------------------------------------------------------------

/** @type {RulesRecord} */
/** @type {import("eslint").Linter.RulesRecord} */
const processorRulesConfig = {
// The Markdown parser automatically trims trailing
// newlines from code blocks.
Expand Down
23 changes: 11 additions & 12 deletions src/language/markdown-language.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,16 +20,15 @@ import { gfm } from "micromark-extension-gfm";
// Types
//-----------------------------------------------------------------------------

/** @typedef {import("mdast").Root} RootNode */
/** @typedef {import("mdast-util-from-markdown").Options['extensions']} Extensions */
/** @typedef {import("mdast-util-from-markdown").Options['mdastExtensions']} MdastExtensions */
/** @typedef {import("@eslint/core").Language} Language */
/** @typedef {import("@eslint/core").File} File */
/** @typedef {import("@eslint/core").ParseResult<RootNode>} ParseResult */
/** @typedef {import("@eslint/core").OkParseResult<RootNode>} OkParseResult */
/** @typedef {import("../types.ts").MarkdownLanguageOptions} MarkdownLanguageOptions */
/** @typedef {import("../types.ts").MarkdownLanguageContext} MarkdownLanguageContext */
/** @typedef {"commonmark"|"gfm"} ParserMode */
/**
* @import { Language, File, ParseResult, OkParseResult } from "@eslint/core";
* @import { Root } from "mdast";
* @import { Options } from "mdast-util-from-markdown";
* @import { MarkdownLanguageOptions, MarkdownLanguageContext } from "../types.js";
* @typedef {Options['extensions']} Extensions
* @typedef {Options['mdastExtensions']} MdastExtensions
* @typedef {"commonmark"|"gfm"} ParserMode
*/

//-----------------------------------------------------------------------------
// Helpers
Expand Down Expand Up @@ -155,7 +154,7 @@ export class MarkdownLanguage {
* Parses the given file into an AST.
* @param {File} file The virtual file to parse.
* @param {MarkdownLanguageContext} context The options to use for parsing.
* @returns {ParseResult} The result of parsing.
* @returns {ParseResult<Root>} The result of parsing.
*/
parse(file, context) {
// Note: BOM already removed
Expand Down Expand Up @@ -189,7 +188,7 @@ export class MarkdownLanguage {
/**
* Creates a new `MarkdownSourceCode` object from the given information.
* @param {File} file The virtual file to create a `MarkdownSourceCode` object from.
* @param {OkParseResult} parseResult The result returned from `parse()`.
* @param {OkParseResult<Root>} parseResult The result returned from `parse()`.
* @returns {MarkdownSourceCode} The new `MarkdownSourceCode` object.
*/
createSourceCode(file, parseResult) {
Expand Down
35 changes: 13 additions & 22 deletions src/language/markdown-source-code.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,20 +19,11 @@ import { findOffsets } from "../util.js";
// Types
//-----------------------------------------------------------------------------

/** @typedef {import("mdast").Root} RootNode */
/** @typedef {import("mdast").Node} MarkdownNode */
/** @typedef {import("mdast").Html} HTMLNode */
/** @typedef {import("@eslint/core").Language} Language */
/** @typedef {import("@eslint/core").File} File */
/** @typedef {import("@eslint/core").TraversalStep} TraversalStep */
/** @typedef {import("@eslint/core").VisitTraversalStep} VisitTraversalStep */
/** @typedef {import("@eslint/core").ParseResult<RootNode>} ParseResult */
/** @typedef {import("@eslint/core").SourceLocation} SourceLocation */
/** @typedef {import("@eslint/core").SourceRange} SourceRange */
/** @typedef {import("@eslint/core").FileProblem} FileProblem */
/** @typedef {import("@eslint/core").DirectiveType} DirectiveType */
/** @typedef {import("@eslint/core").RulesConfig} RulesConfig */
/** @typedef {import("../types.ts").MarkdownLanguageOptions} MarkdownLanguageOptions */
/**
* @import { Root, Node, Html } from "mdast";
* @import { TraversalStep, SourceLocation, FileProblem, DirectiveType, RulesConfig } from "@eslint/core";
* @import { MarkdownLanguageOptions } from "../types.js";
*/

//-----------------------------------------------------------------------------
// Helpers
Expand Down Expand Up @@ -73,7 +64,7 @@ class InlineConfigComment {

/**
* Extracts inline configuration comments from an HTML node.
* @param {HTMLNode} node The HTML node to extract comments from.
* @param {Html} node The HTML node to extract comments from.
* @returns {Array<InlineConfigComment>} The inline configuration comments found in the node.
*/
function extractInlineConfigCommentsFromHTML(node) {
Expand Down Expand Up @@ -136,7 +127,7 @@ function extractInlineConfigCommentsFromHTML(node) {

/**
* Markdown Source Code Object
* @extends {TextSourceCodeBase<{LangOptions: MarkdownLanguageOptions, RootNode: RootNode, SyntaxElementWithLoc: MarkdownNode, ConfigNode: { value: string; position: SourceLocation }}>}
* @extends {TextSourceCodeBase<{LangOptions: MarkdownLanguageOptions, RootNode: Root, SyntaxElementWithLoc: Node, ConfigNode: { value: string; position: SourceLocation }}>}
*/
export class MarkdownSourceCode extends TextSourceCodeBase {
/**
Expand All @@ -147,13 +138,13 @@ export class MarkdownSourceCode extends TextSourceCodeBase {

/**
* Cache of parent nodes.
* @type {WeakMap<MarkdownNode, MarkdownNode>}
* @type {WeakMap<Node, Node>}
*/
#parents = new WeakMap();

/**
* Collection of HTML nodes. Used to find directive comments.
* @type {Array<HTMLNode>}
* @type {Array<Html>}
*/
#htmlNodes = [];

Expand All @@ -165,15 +156,15 @@ export class MarkdownSourceCode extends TextSourceCodeBase {

/**
* The AST of the source code.
* @type {RootNode}
* @type {Root}
*/
ast = undefined;

/**
* Creates a new instance.
* @param {Object} options The options for the instance.
* @param {string} options.text The source code text.
* @param {RootNode} options.ast The root AST node.
* @param {Root} options.ast The root AST node.
*/
constructor({ text, ast }) {
super({ ast, text });
Expand All @@ -185,8 +176,8 @@ export class MarkdownSourceCode extends TextSourceCodeBase {

/**
* Returns the parent of the given node.
* @param {MarkdownNode} node The node to get the parent of.
* @returns {MarkdownNode|undefined} The parent of the node.
* @param {Node} node The node to get the parent of.
* @returns {Node|undefined} The parent of the node.
*/
getParent(node) {
return this.#parents.get(node);
Expand Down
23 changes: 11 additions & 12 deletions src/processor.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,14 @@ import { fromMarkdown } from "mdast-util-from-markdown";
// Type Definitions
//-----------------------------------------------------------------------------

/** @typedef {import("./types.ts").Block} Block */
/** @typedef {import("./types.ts").RangeMap} RangeMap */
/** @typedef {import("mdast").Node} Node */
/** @typedef {import("mdast").Parent} ParentNode */
/** @typedef {import("mdast").Code} CodeNode */
/** @typedef {import("mdast").Html} HtmlNode */
/** @typedef {import("eslint").Linter.LintMessage} Message */
/** @typedef {import("eslint").Rule.Fix} Fix */
/** @typedef {import("eslint").AST.Range} Range */
/**
* @import { Node, Parent, Code, Html } from "mdast";
* @import { Linter, Rule, AST } from "eslint";
* @import { Block, RangeMap } from "./types.js";
* @typedef {Linter.LintMessage} Message
* @typedef {Rule.Fix} Fix
* @typedef {AST.Range} Range
*/

//-----------------------------------------------------------------------------
// Helpers
Expand Down Expand Up @@ -53,7 +52,7 @@ function traverse(node, callbacks) {
callbacks["*"]();
}

const parent = /** @type {ParentNode} */ (node);
const parent = /** @type {Parent} */ (node);

if (typeof parent.children !== "undefined") {
for (let i = 0; i < parent.children.length; i++) {
Expand Down Expand Up @@ -291,7 +290,7 @@ function preprocess(sourceText, filename) {

/**
* Visit a code node.
* @param {CodeNode} node The visited node.
* @param {Code} node The visited node.
* @returns {void}
*/
code(node) {
Expand Down Expand Up @@ -320,7 +319,7 @@ function preprocess(sourceText, filename) {

/**
* Visit an HTML node.
* @param {HtmlNode} node The visited node.
* @param {Html} node The visited node.
* @returns {void}
*/
html(node) {
Expand Down
5 changes: 3 additions & 2 deletions src/rules/fenced-code-language.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,9 @@
//-----------------------------------------------------------------------------

/**
* @typedef {import("../types.ts").MarkdownRuleDefinition<{ RuleOptions: [{ required?: string[]; }]; }>}
* FencedCodeLanguageRuleDefinition
* @import { MarkdownRuleDefinition } from "../types.js";
* @typedef {"missingLanguage" | "disallowedLanguage"} FencedCodeLanguageMessageIds
* @typedef {MarkdownRuleDefinition<{ RuleOptions: [{ required?: string[]; }], MessageIds: FencedCodeLanguageMessageIds }>} FencedCodeLanguageRuleDefinition
*/

//-----------------------------------------------------------------------------
Expand Down
5 changes: 3 additions & 2 deletions src/rules/heading-increment.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,9 @@
//-----------------------------------------------------------------------------

/**
* @typedef {import("../types.ts").MarkdownRuleDefinition<{ RuleOptions: []; }>}
* HeadingIncrementRuleDefinition
* @import { MarkdownRuleDefinition } from "../types.js";
* @typedef {"skippedHeading"} HeadingIncrementMessageIds
* @typedef {MarkdownRuleDefinition<{ RuleOptions: [], MessageIds: HeadingIncrementMessageIds }>} HeadingIncrementRuleDefinition
*/

//-----------------------------------------------------------------------------
Expand Down
5 changes: 3 additions & 2 deletions src/rules/no-duplicate-headings.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,9 @@
//-----------------------------------------------------------------------------

/**
* @typedef {import("../types.ts").MarkdownRuleDefinition<{ RuleOptions: []; }>}
* NoDuplicateHeadingsRuleDefinition
* @import { MarkdownRuleDefinition } from "../types.js";
* @typedef {"duplicateHeading"} NoDuplicateHeadingsMessageIds
* @typedef {MarkdownRuleDefinition<{ RuleOptions: [], MessageIds: NoDuplicateHeadingsMessageIds }>} NoDuplicateHeadingsRuleDefinition
*/

//-----------------------------------------------------------------------------
Expand Down
5 changes: 3 additions & 2 deletions src/rules/no-empty-images.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,9 @@
//-----------------------------------------------------------------------------

/**
* @typedef {import("../types.ts").MarkdownRuleDefinition<{ RuleOptions: []; }>}
* NoEmptyImagesRuleDefinition
* @import { MarkdownRuleDefinition } from "../types.js";
* @typedef {"emptyImage"} NoEmptyImagesMessageIds
* @typedef {MarkdownRuleDefinition<{ RuleOptions: [], MessageIds: NoEmptyImagesMessageIds }>} NoEmptyImagesRuleDefinition
*/

//-----------------------------------------------------------------------------
Expand Down
5 changes: 3 additions & 2 deletions src/rules/no-empty-links.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,9 @@
//-----------------------------------------------------------------------------

/**
* @typedef {import("../types.ts").MarkdownRuleDefinition<{ RuleOptions: []; }>}
* NoEmptyLinksRuleDefinition
* @import { MarkdownRuleDefinition } from "../types.js";
* @typedef {"emptyLink"} NoEmptyLinksMessageIds
* @typedef {MarkdownRuleDefinition<{ RuleOptions: [], MessageIds: NoEmptyLinksMessageIds }>} NoEmptyLinksRuleDefinition
*/

//-----------------------------------------------------------------------------
Expand Down
5 changes: 3 additions & 2 deletions src/rules/no-html.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,9 @@ import { findOffsets } from "../util.js";
//-----------------------------------------------------------------------------

/**
* @typedef {import("../types.ts").MarkdownRuleDefinition<{ RuleOptions: [{ allowed?: string[]; }]; }>}
* NoHtmlRuleDefinition
* @import { MarkdownRuleDefinition } from "../types.js";
* @typedef {"disallowedElement"} NoHtmlMessageIds
* @typedef {MarkdownRuleDefinition<{ RuleOptions: [{ allowed?: string[] }], MessageIds: NoHtmlMessageIds }>} NoHtmlRuleDefinition
*/

//-----------------------------------------------------------------------------
Expand Down
13 changes: 7 additions & 6 deletions src/rules/no-invalid-label-refs.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,12 @@ import { findOffsets, illegalShorthandTailPattern } from "../util.js";
// Type Definitions
//-----------------------------------------------------------------------------

/** @typedef {import("unist").Position} Position */
/** @typedef {import("mdast").Text} TextNode */
/**
* @typedef {import("../types.ts").MarkdownRuleDefinition<{ RuleOptions: []; }>}
* NoInvalidLabelRuleDefinition
* @import { Position } from "unist";
* @import { Text } from "mdast";
* @import { MarkdownRuleDefinition } from "../types.js";
* @typedef {"invalidLabelRef"} NoInvalidLabelRefsMessageIds
* @typedef {MarkdownRuleDefinition<{ RuleOptions: [], MessageIds: NoInvalidLabelRefsMessageIds }>} NoInvalidLabelRefsRuleDefinition
*/

//-----------------------------------------------------------------------------
Expand All @@ -29,7 +30,7 @@ const labelPattern = /\]\[([^\]]+)\]/u;

/**
* Finds missing references in a node.
* @param {TextNode} node The node to check.
* @param {Text} node The node to check.
* @param {string} docText The text of the node.
* @returns {Array<{label:string,position:Position}>} The missing references.
*/
Expand Down Expand Up @@ -123,7 +124,7 @@ function findInvalidLabelReferences(node, docText) {
// Rule Definition
//-----------------------------------------------------------------------------

/** @type {NoInvalidLabelRuleDefinition} */
/** @type {NoInvalidLabelRefsRuleDefinition} */
export default {
meta: {
type: "problem",
Expand Down
13 changes: 7 additions & 6 deletions src/rules/no-missing-label-refs.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,12 @@ import { findOffsets, illegalShorthandTailPattern } from "../util.js";
// Type Definitions
//-----------------------------------------------------------------------------

/** @typedef {import("unist").Position} Position */
/** @typedef {import("mdast").Text} TextNode */
/**
* @typedef {import("../types.ts").MarkdownRuleDefinition<{ RuleOptions: []; }>}
* NoMissingLabelRuleDefinition
* @import { Position } from "unist";
* @import { Text } from "mdast";
* @import { MarkdownRuleDefinition } from "../types.js";
* @typedef {"notFound"} NoMissingLabelRefsMessageIds
* @typedef {MarkdownRuleDefinition<{ RuleOptions: [], MessageIds: NoMissingLabelRefsMessageIds }>} NoMissingLabelRefsRuleDefinition
*/

//-----------------------------------------------------------------------------
Expand All @@ -26,7 +27,7 @@ import { findOffsets, illegalShorthandTailPattern } from "../util.js";

/**
* Finds missing references in a node.
* @param {TextNode} node The node to check.
* @param {Text} node The node to check.
* @param {string} nodeText The text of the node.
* @returns {Array<{label:string,position:Position}>} The missing references.
*/
Expand Down Expand Up @@ -105,7 +106,7 @@ function findMissingReferences(node, nodeText) {
// Rule Definition
//-----------------------------------------------------------------------------

/** @type {NoMissingLabelRuleDefinition} */
/** @type {NoMissingLabelRefsRuleDefinition} */
export default {
meta: {
type: "problem",
Expand Down
2 changes: 2 additions & 0 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -177,3 +177,5 @@ export type MarkdownRuleDefinition<
Omit<MarkdownRuleDefinitionTypeOptions, keyof Options>
>
>;

export type RuleModule = MarkdownRuleDefinition;
18 changes: 8 additions & 10 deletions tests/types/types.test.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,12 @@
import markdown, {
MarkdownSourceCode,
MarkdownNode,
import markdown, { MarkdownSourceCode } from "@eslint/markdown";
import {
Toml,
MarkdownRuleDefinition,
MarkdownRuleVisitor,
SourceLocation,
SourceRange,
type RuleModule,
} from "@eslint/markdown";
import { Toml } from "@eslint/markdown/types";
RuleModule,
} from "@eslint/markdown/types";
import { ESLint, Linter } from "eslint";
import type { SourceLocation, SourceRange } from "@eslint/core";
import type {
// Nodes (abstract)
Node,
Expand Down Expand Up @@ -166,8 +164,8 @@ typeof processorPlugins satisfies {};
"toml:exit": (...args) => testVisitor<Toml>(...args),

// Unknown selectors allowed
"heading[depth=1]"(node: MarkdownNode, parent?: ParentNode) {},
"randomSelector:exit"(node: MarkdownNode, parent?: ParentNode) {},
"heading[depth=1]"(node: Node, parent?: ParentNode) {},
"randomSelector:exit"(node: Node, parent?: ParentNode) {},
};
},
});
Expand Down
Loading