diff --git a/src/language/markdown-source-code.js b/src/language/markdown-source-code.js index ddb8f84c..96092e6b 100644 --- a/src/language/markdown-source-code.js +++ b/src/language/markdown-source-code.js @@ -23,7 +23,7 @@ import { lineEndingPattern } from "../util.js"; * @import { Position } from "unist"; * @import { Root, Node, Html } from "mdast"; * @import { TraversalStep, FileProblem, DirectiveType, RulesConfig } from "@eslint/core"; - * @import { MarkdownLanguageOptions } from "../types.js"; + * @import { MarkdownLanguageOptions, MarkdownSyntaxElement } from "../types.js"; */ //----------------------------------------------------------------------------- @@ -113,7 +113,7 @@ function extractInlineConfigCommentsFromHTML(node, sourceCode) { /** * Markdown Source Code Object - * @extends {TextSourceCodeBase<{LangOptions: MarkdownLanguageOptions, RootNode: Root, SyntaxElementWithLoc: Node, ConfigNode: { value: string; position: Position }}>} + * @extends {TextSourceCodeBase<{LangOptions: MarkdownLanguageOptions, RootNode: Root, SyntaxElementWithLoc: MarkdownSyntaxElement, ConfigNode: { value: string; position: Position }}>} */ export class MarkdownSourceCode extends TextSourceCodeBase { /** diff --git a/src/types.ts b/src/types.ts index 8ab4c8a8..6066d566 100644 --- a/src/types.ts +++ b/src/types.ts @@ -8,35 +8,11 @@ import type { Data, Literal, Parent, - // Nodes - Blockquote, - Break, + Parents, + // Node unions + Nodes, Code, - Definition, - Emphasis, - Heading, - Html, - Image, - ImageReference, - InlineCode, - Link, - LinkReference, - List, - ListItem, - Paragraph, Root, - Strong, - Text, - ThematicBreak, - // Extensions (GFM) - Delete, - FootnoteDefinition, - FootnoteReference, - Table, - TableCell, - TableRow, - // Extensions (front matter) - Yaml, } from "mdast"; import type { CustomRuleDefinitionType, @@ -58,6 +34,25 @@ type WithExit = { | `${Key & string}:exit`]: RuleVisitorType[Key]; }; +/** + * Compute the precise parent type for a given node `T`. + * - Root has no parent (returns `never`). + * - Custom frontmatter nodes (`toml` / `json`) only appear directly under `Root`. + * - For nodes, include every parent `P` where `T` is assignable to one of + * `P['children'][number]` (i.e. `T` can appear in `P.children`). + */ +type ParentOf = T extends Root + ? never + : T extends Toml | Json + ? Root + : Parents extends infer P + ? P extends Parent + ? T extends P["children"][number] + ? P + : never + : never + : never; + //------------------------------------------------------------------------------ // Exports //------------------------------------------------------------------------------ @@ -129,45 +124,19 @@ export interface MarkdownLanguageOptions extends LanguageOptions { */ export type MarkdownLanguageContext = LanguageContext; +export type MarkdownSyntaxElement = Node; + +type MarkdownNode = Nodes | Json | Toml; + +type MarkdownNodeVisitor = { + [Node in MarkdownNode as Node["type"]]: Node extends Root + ? ((node: Node) => void) | undefined + : ((node: Node, parent: ParentOf) => void) | undefined; +}; + export interface MarkdownRuleVisitor extends RuleVisitor, - WithExit< - { - root?(node: Root): void; - } & { - [NodeType in - | Blockquote // Nodes - | Break - | Code - | Definition - | Emphasis - | Heading - | Html - | Image - | ImageReference - | InlineCode - | Link - | LinkReference - | List - | ListItem - | Paragraph - | Strong - | Text - | ThematicBreak - | Delete // Extensions (GFM) - | FootnoteDefinition - | FootnoteReference - | Table - | TableCell - | TableRow - | Yaml // Extensions (front matter) - | Toml - | Json as NodeType["type"]]?: ( - node: NodeType, - parent?: Parent, - ) => void; - } - > {} + Partial> {} export type MarkdownRuleDefinitionTypeOptions = CustomRuleTypeDefinitions; @@ -178,7 +147,7 @@ export type MarkdownRuleDefinition< LangOptions: MarkdownLanguageOptions; Code: MarkdownSourceCode; Visitor: MarkdownRuleVisitor; - Node: Node; + Node: MarkdownSyntaxElement; }, Options >;