diff --git a/.oxlintrc.json b/.oxlintrc.json index 7898490..f460739 100644 --- a/.oxlintrc.json +++ b/.oxlintrc.json @@ -30,7 +30,7 @@ { "files": ["src/markdown/*.ts"], "rules": { - "no-restricted-imports": ["error", { "patterns": [{ "group": ["**/emit/**", "**/html/**", "**/parse/**", "**/portable/**"], "message": "A root file of src/markdown/ is read by the writers and the readers and imports neither: docs/decisions.md §The source parts by ADF and format" }] }] + "no-restricted-imports": ["error", { "patterns": [{ "group": ["**/emit/**", "**/html/**", "**/parse/**", "**/portable/**"], "message": "docs/decisions.md §The source parts by ADF and format" }] }] } }, { diff --git a/docs/decisions.md b/docs/decisions.md index 0f60a4a..4af4773 100644 --- a/docs/decisions.md +++ b/docs/decisions.md @@ -1175,7 +1175,8 @@ is the markdown flavour's choice, not ADF's. 2026-08-27, placement 2026-09-18, `adf/`'s bar 2026-09-21, `plain/` 2026-10-03, the import boundaries' lint 2026-10-22, the maintainer; `parse/` and `emit/` free of `portable/`, -2026-10-22; the root's imports and `emit/` free of `parse/`, 2026-11-10. Goal 2. Valid while each format has a reader and a writer through ADF. +2026-10-22; `markdown/`'s root free of `emit/`, `parse/` and `portable/`, and `emit/` free of +`parse/`, 2026-11-10. Goal 2. Valid while each format has a reader and a writer through ADF. `src/adf/` holds ADF's own knowledge, imports no format, and is where a construct both formats read lives: the question is answered in ADF's vocabulary — a node type, an attribute kind, a content @@ -1202,22 +1203,22 @@ whether a list marker interrupts a paragraph — is one function there too, neve direction, however conservative the copy would be. Where the rule is the emitter's own choice, input consults it rather than restating it, so no fixture the emitter writes can be refused, and a spelling the emitter refuses gives its own error rather than a second name for it. That consulting -is the only import `parse/` takes from `emit/`, through `emit/spelling-questions.ts`. The root -imports neither `emit/`, `parse/` nor `portable/`, and `emit/` does not import `parse/`. The scan in -`inline-content.ts` reports whether a spellable link opens the paragraph, and -`parse/inline-content.ts` alone asks the writer what that link needs. A read-back (`readLineBack`) -never asks the writer: the writer calls it as it spells a line, so a read-back that asked would -recurse without bound (§Nothing recurses unbounded). +is the only import `parse/` takes from `emit/`, through `emit/spelling-questions.ts`. The root of +`markdown/` imports none of `emit/`, `parse/` and `portable/`, and `emit/` does not import `parse/`. +The scan in `inline-content.ts` reports whether a spellable link opens the paragraph, and +`parse/inline-content.ts` alone asks the writer whether that link still needs its directive. A +read-back (`readLineBack`) never asks the writer: the writer calls it as it spells a line, so a +read-back that asked would recurse without bound (§Nothing recurses unbounded). `.oxlintrc.json` enforces that limit for `markdown/parse/`, keeps `html/parse/` from importing -`html/emit/`, keeps markdown's `parse/` and `emit/` from importing `portable/`, keeps the root's files from -importing `emit/`, `parse/` and `portable/`, keeps `emit/` from importing `parse/`, keeps -`markdown/directive/` from importing `emit/` or `parse/`, keeps `markdown/` and `html/` from +`html/emit/`, keeps markdown's `parse/` and `emit/` from importing `portable/`, keeps `markdown/`'s +root files from importing `emit/`, `parse/` or `portable/`, keeps `emit/` from importing `parse/`, +keeps `markdown/directive/` from importing `emit/` or `parse/`, keeps `markdown/` and `html/` from importing each other, and keeps `adf/` from importing either, as `no-restricted-imports` overrides. A later override replaces an earlier one's rule, so each subdirectory's override repeats its -format's ban on the other format, and `ci.sh` probes every override. They are lint rules because the technical principles refuse a -test that scans the source, and a lint rule reads every import spelling: `from`, a bare `import`, -double quotes and a dynamic `import()`. +format's ban on the other format, and `ci.sh` probes every override. They are lint rules because the +technical principles refuse a test that scans the source, and a lint rule reads every import +spelling: `from`, a bare `import`, double quotes and a dynamic `import()`. ## The comparison tables list every ADF converter that starts and converts diff --git a/src/markdown/inline-content.ts b/src/markdown/inline-content.ts index 28006f2..2d0748d 100644 --- a/src/markdown/inline-content.ts +++ b/src/markdown/inline-content.ts @@ -26,7 +26,7 @@ import { readTextDirective } from './directive/text.ts' // Only a `paragraph` block takes `image`, the `mediaSingle` a lone image builds; every other container takes `nodes`, where the image is its linked alt text. export type InlineContent = { image?: AdfNode; nodes: AdfNode[] } -// `openingSpellableLink`: a directive link opens the paragraph that CommonMark could spell; `parse/` asks the writer whether the line still needs the directive. +// `openingSpellableLink`: the paragraph opens with a directive link that CommonMark could spell. export type OutermostContent = InlineContent & { openingSpellableLink: boolean } // The text break leaf: it holds no marks, and stands between the nodes it parts until the outermost content checks and drops it. @@ -132,7 +132,7 @@ export function parseInlineContent(source: string, definitions: LinkDefinitions, return success(image === undefined ? { nodes: nodes.value, openingSpellableLink } : { image, nodes: nodes.value, openingSpellableLink }) } -// A read-back never asks the writer for anything: the writer calls it while it spells a line. The reading of a line that faults still holds what the reader took before the fault. +// The reading of a line that faults still holds what the reader took before the fault. export function readLineBack(line: string, container: LineContainer, claims: Claims): { faulted: boolean; reading: InlineReading } { const reading: InlineReading = { codeSpans: [], emphasis: new Map(), links: [] } const scan = freshScan(line, { definitions: noDefinitions, path: [], reading, targets: targetMemo(line) }, { claims, container, inLink: false, offset: 0, spans: noSpans }) @@ -271,7 +271,7 @@ function directiveMarkPieces(scan: Scan, name: string, mark: AdfMark, slot: read return success([...marked.filter((piece) => piece.kind === 'nodes'), ...besideLink(images, link)]) } -// spec/flavour.md, Marks. A link opening a paragraph may still need the directive form for the line it opens, which `parse/` asks the writer once `parseInlineContent` reports the opening. +// spec/flavour.md, Marks. A link opening a paragraph may still need the directive form for the line it opens. function refuseLinkDirective(scan: Scan, mark: AdfMark, nodes: readonly Inline[], index: number): Result | undefined { const href = linkHref(nodeAttrs(mark)) if (href === undefined) return failure('unsupported-node-shape', hreflessLink, scan.shared.path) diff --git a/src/markdown/parse/inline-content.ts b/src/markdown/parse/inline-content.ts index dea6604..b331378 100644 --- a/src/markdown/parse/inline-content.ts +++ b/src/markdown/parse/inline-content.ts @@ -6,7 +6,7 @@ import { failure, success } from '../../result.ts' import { openingLinkTakesDirective } from '../emit/spelling-questions.ts' import { parseInlineContent, spellableLink } from '../inline-content.ts' -// The only place a reader asks the writer: whether a spellable link opening the paragraph still needs its directive for the line it opens (spec/flavour.md, Marks). +// The only place a reader asks the writer whether the link opening a paragraph still needs its directive (spec/flavour.md, Marks). export function readInlineContent(source: string, definitions: LinkDefinitions, path: ConvertErrorPath, container: LineContainer, flavour: Flavour): Result { const content = parseInlineContent(source, definitions, path, container, flavour) if (!content.ok || !content.value.openingSpellableLink) return content