From 3f7b3a386e435599521a7c35de9b7e5f297bfa36 Mon Sep 17 00:00:00 2001 From: Lilleman auf Larv Date: Wed, 21 Oct 2026 23:49:15 +0200 Subject: [PATCH] =?UTF-8?q?Answer=20architecture=20round=201:=200=20?= =?UTF-8?q?=F0=9F=94=B4,=202=20=F0=9F=9F=A1;=20join=20empty-keys=20to=20th?= =?UTF-8?q?e=20directive=20grammar=20and=20name=20the=20readers=20by=20dir?= =?UTF-8?q?ection?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/conformance/module-boundaries.test.ts | 32 +++++++++++++------ .../{attributes.ts => attribute-reading.ts} | 0 src/markdown/directive/block-spelling.ts | 2 +- src/markdown/{ => directive}/empty-keys.ts | 10 +++--- src/markdown/directive/inline-spelling.ts | 2 +- .../directive/{marks.ts => mark-reading.ts} | 4 +-- .../directive/{nodes.ts => node-reading.ts} | 8 ++--- src/markdown/mark-spellings.ts | 2 +- src/markdown/parse/inline-content.ts | 4 +-- src/markdown/parse/markdown-to-adf.ts | 6 ++-- todo.md | 4 +++ 11 files changed, 46 insertions(+), 28 deletions(-) rename src/markdown/directive/{attributes.ts => attribute-reading.ts} (100%) rename src/markdown/{ => directive}/empty-keys.ts (83%) rename src/markdown/directive/{marks.ts => mark-reading.ts} (95%) rename src/markdown/directive/{nodes.ts => node-reading.ts} (97%) diff --git a/src/conformance/module-boundaries.test.ts b/src/conformance/module-boundaries.test.ts index 464b8d3..16a26f1 100644 --- a/src/conformance/module-boundaries.test.ts +++ b/src/conformance/module-boundaries.test.ts @@ -1,17 +1,22 @@ import assert from 'node:assert/strict' -import { dirname, join } from 'node:path' +import { dirname, join, relative } from 'node:path' import { fileURLToPath } from 'node:url' -import { readdirSync, readFileSync } from 'node:fs' +import { readdirSync, readFileSync, statSync } from 'node:fs' import test from 'node:test' const markdown = join(dirname(fileURLToPath(import.meta.url)), '..', 'markdown') const importSpecifier = /\bfrom '([^']+)'/g -function importsOf(directory: string): { file: string; specifier: string }[] { - const imports: { file: string; specifier: string }[] = [] - for (const file of readdirSync(join(markdown, directory)).filter((name) => name.endsWith('.ts') && !name.endsWith('.test.ts'))) { - for (const match of readFileSync(join(markdown, directory, file), 'utf8').matchAll(importSpecifier)) { - imports.push({ file: `${directory}/${file}`, specifier: match[1] ?? '' }) +function importsOf(directory: string): { file: string; target: string }[] { + const imports: { file: string; target: string }[] = [] + for (const name of readdirSync(join(markdown, directory))) { + const path = join(directory, name) + if (statSync(join(markdown, path)).isDirectory()) { + imports.push(...importsOf(path)) + } else if (name.endsWith('.ts') && !name.endsWith('.test.ts')) { + for (const match of readFileSync(join(markdown, path), 'utf8').matchAll(importSpecifier)) { + imports.push({ file: path, target: relative(markdown, join(markdown, directory, match[1] ?? '')) }) + } } } return imports @@ -19,10 +24,19 @@ function importsOf(directory: string): { file: string; specifier: string }[] { // docs/decisions.md §The source parts by ADF and format test('parse/ asks emit/ only through the module that names its questions', () => { - const reached = importsOf('parse').filter(({ specifier }) => specifier.startsWith('../emit/')) + const reached = importsOf('parse').filter(({ target }) => target.startsWith('emit/')) assert.ok(reached.length > 0) assert.deepEqual( - reached.filter(({ specifier }) => specifier !== '../emit/spelling-questions.ts'), + reached.filter(({ target }) => target !== 'emit/spelling-questions.ts'), + [], + ) +}) + +test('directive/ imports nothing from emit/ or parse/', () => { + const imports = importsOf('directive') + assert.ok(imports.length > 0) + assert.deepEqual( + imports.filter(({ target }) => target.startsWith('emit/') || target.startsWith('parse/')), [], ) }) diff --git a/src/markdown/directive/attributes.ts b/src/markdown/directive/attribute-reading.ts similarity index 100% rename from src/markdown/directive/attributes.ts rename to src/markdown/directive/attribute-reading.ts diff --git a/src/markdown/directive/block-spelling.ts b/src/markdown/directive/block-spelling.ts index 85e1cf3..b794625 100644 --- a/src/markdown/directive/block-spelling.ts +++ b/src/markdown/directive/block-spelling.ts @@ -4,7 +4,7 @@ import { attributeNestingMessage, nodeAttrs, nodeMarks } from '../../adf/documen import { blockArgument, marksAttribute, spellBlockMarks } from './block.ts' import { failure, success, type ConvertErrorPath, type Result } from '../../result.ts' import { isBareToken, spellAttributes, spellDirectiveOpener, spellVocabulary } from './syntax.ts' -import { spellEmptyKeys } from '../empty-keys.ts' +import { spellEmptyKeys } from './empty-keys.ts' import { vocabularyPairs } from '../../adf/attribute-vocabulary.ts' export function spellBlockDirectiveOpener(node: AdfNode, model: BlockNodeModel, path: ConvertErrorPath, spelledByBody: readonly string[] = []): Result | undefined { diff --git a/src/markdown/empty-keys.ts b/src/markdown/directive/empty-keys.ts similarity index 83% rename from src/markdown/empty-keys.ts rename to src/markdown/directive/empty-keys.ts index 900ad1a..cec90d3 100644 --- a/src/markdown/empty-keys.ts +++ b/src/markdown/directive/empty-keys.ts @@ -1,8 +1,8 @@ -import type { DirectiveAttributes, DirectiveValue } from './directive/syntax.ts' -import type { EmptyKey } from '../adf/document.ts' -import type { Read } from '../result.ts' -import { emptyKeys } from '../adf/document.ts' -import { unsupportedNodeShape } from './directive/syntax.ts' +import type { DirectiveAttributes, DirectiveValue } from './syntax.ts' +import type { EmptyKey } from '../../adf/document.ts' +import type { Read } from '../../result.ts' +import { emptyKeys } from '../../adf/document.ts' +import { unsupportedNodeShape } from './syntax.ts' type EmptyKeysRead = { empty: ReadonlySet; rest: Map } diff --git a/src/markdown/directive/inline-spelling.ts b/src/markdown/directive/inline-spelling.ts index 6f33cd6..bc1973d 100644 --- a/src/markdown/directive/inline-spelling.ts +++ b/src/markdown/directive/inline-spelling.ts @@ -2,7 +2,7 @@ import type { AdfNode } from '../../adf/document.ts' import type { InlineNodeModel } from '../../adf/inline-nodes.ts' import { nodeAttrs } from '../../adf/document.ts' import { spellAttributes, spellVocabulary } from './syntax.ts' -import { spellEmptyKeys } from '../empty-keys.ts' +import { spellEmptyKeys } from './empty-keys.ts' import { vocabularyPairs } from '../../adf/attribute-vocabulary.ts' export function spellInlineNodeAttributes(node: AdfNode, model: InlineNodeModel): string | undefined { diff --git a/src/markdown/directive/marks.ts b/src/markdown/directive/mark-reading.ts similarity index 95% rename from src/markdown/directive/marks.ts rename to src/markdown/directive/mark-reading.ts index 2800c71..7548fca 100644 --- a/src/markdown/directive/marks.ts +++ b/src/markdown/directive/mark-reading.ts @@ -6,8 +6,8 @@ import type { MarkSpelling } from '../mark-spellings.ts' import { directivePrefix } from './syntax.ts' import { failure, faulted, success, type ConvertErrorPath, type Result } from '../../result.ts' import { markSpelling } from '../mark-spellings.ts' -import { readEmptyKeys } from '../empty-keys.ts' -import { readVocabulary } from './attributes.ts' +import { readEmptyKeys } from './empty-keys.ts' +import { readVocabulary } from './attribute-reading.ts' export function readDirectiveMark(name: string, attributes: DirectiveAttributes, path: ConvertErrorPath): Result | undefined { const spelling = markSpelling(name) diff --git a/src/markdown/directive/nodes.ts b/src/markdown/directive/node-reading.ts similarity index 97% rename from src/markdown/directive/nodes.ts rename to src/markdown/directive/node-reading.ts index b4bbbee..fadae76 100644 --- a/src/markdown/directive/nodes.ts +++ b/src/markdown/directive/node-reading.ts @@ -2,18 +2,18 @@ import type { AdfAttributes, AdfMark, AdfNode, EmptyKey } from '../../adf/docume import type { BlockNodeModel } from '../../adf/block-nodes.ts' import type { ConvertFault } from '../../result.ts' import type { DirectiveAttributes, DirectiveValue } from './syntax.ts' -import type { Elsewhere } from './attributes.ts' +import type { Elsewhere } from './attribute-reading.ts' import { attributeNestingMessage, isUnmarkedSpellableText } from '../../adf/document.ts' import { attributePairCause, attributeValue, directivePrefix, readAttributes, readDirectiveName, unknownDirectiveFault } from './syntax.ts' import { blockArgument, blockDirectiveForm, marksAttribute, readMarkValues, spellBlockMarks } from './block.ts' import { blockNodeModel } from '../../adf/block-nodes.ts' import { carryFencePrefix, carryName } from '../opaque-carry.ts' import { failure, faulted, success, type ConvertErrorPath, type Result } from '../../result.ts' -import { inlineMarkSpellingFault, readMarkAttributes } from './marks.ts' +import { inlineMarkSpellingFault, readMarkAttributes } from './mark-reading.ts' import { inlineNodeModel } from '../../adf/inline-nodes.ts' import { markVocabularies } from '../../adf/mark-attributes.ts' -import { readEmptyKeys, spellsEmpty } from '../empty-keys.ts' -import { readVocabulary } from './attributes.ts' +import { readEmptyKeys, spellsEmpty } from './empty-keys.ts' +import { readVocabulary } from './attribute-reading.ts' import { slotFault } from './syntax.ts' import { textBreakName } from '../adjacent-text.ts' import { textDirectiveName } from './text.ts' diff --git a/src/markdown/mark-spellings.ts b/src/markdown/mark-spellings.ts index d78ea00..cb6fecd 100644 --- a/src/markdown/mark-spellings.ts +++ b/src/markdown/mark-spellings.ts @@ -8,7 +8,7 @@ import { holdsDirectivePrefix, spellAttributes, spellVocabulary } from './direct import { holdsEntityReference } from './commonmark/entity-references.ts' import { isAutolink } from './commonmark/grammar.ts' import { isMarkType, markAttributes } from '../adf/mark-attributes.ts' -import { spellEmptyKeys } from './empty-keys.ts' +import { spellEmptyKeys } from './directive/empty-keys.ts' import { vocabularyPairs } from '../adf/attribute-vocabulary.ts' type Spelling = { kind: 'code' | 'directive' | 'link'; spelling?: undefined } | { kind: 'emphasis'; spelling: string } diff --git a/src/markdown/parse/inline-content.ts b/src/markdown/parse/inline-content.ts index 788831b..6439d3e 100644 --- a/src/markdown/parse/inline-content.ts +++ b/src/markdown/parse/inline-content.ts @@ -19,8 +19,8 @@ import { normalizeLabel, readInlineTarget, readLabel } from '../commonmark/link- import { noSpans, readInlineDirective } from '../directive/syntax.ts' import { openingLinkTakesDirective } from '../emit/spelling-questions.ts' import { readCarriedInline } from '../opaque-carry.ts' -import { readDirectiveMark } from '../directive/marks.ts' -import { readInlineDirectiveNode } from '../directive/nodes.ts' +import { readDirectiveMark } from '../directive/mark-reading.ts' +import { readInlineDirectiveNode } from '../directive/node-reading.ts' import { inlineSource, readInlineToken } from '../inline-tokens.ts' import { readTextDirective } from '../directive/text.ts' diff --git a/src/markdown/parse/markdown-to-adf.ts b/src/markdown/parse/markdown-to-adf.ts index f35a9b2..dc1e2c6 100644 --- a/src/markdown/parse/markdown-to-adf.ts +++ b/src/markdown/parse/markdown-to-adf.ts @@ -1,6 +1,6 @@ import type { AdfDocument, AdfNode } from '../../adf/document.ts' import type { Block, DirectiveBlock } from './blocks.ts' -import type { BlockDirectiveNode } from '../directive/nodes.ts' +import type { BlockDirectiveNode } from '../directive/node-reading.ts' import type { ConvertFault } from '../../result.ts' import type { Flavour } from '../flavour.ts' import type { LineContainer } from '../line-container.ts' @@ -17,9 +17,9 @@ import { leadingMarker, readAlertMarker, readTaskMarker } from '../portable/conv import { mintTaskIds } from '../portable/task-ids.ts' import { parseBlocks } from './blocks.ts' import { parseInlineContent } from './inline-content.ts' -import { readBlockDirectiveNode } from '../directive/nodes.ts' +import { readBlockDirectiveNode } from '../directive/node-reading.ts' import { spellStringAttribute, unsupportedNodeShape } from '../directive/syntax.ts' -import { spellsEmpty } from '../empty-keys.ts' +import { spellsEmpty } from '../directive/empty-keys.ts' import { splitPlace, splitTaskList } from '../portable/task-list.ts' import { withinEngineLimits } from '../length-bound.ts' diff --git a/todo.md b/todo.md index 9cca82d..c99111e 100644 --- a/todo.md +++ b/todo.md @@ -225,6 +225,10 @@ documents markdown, its comparison table names HTML, and its tagline and `packag description and keywords name HTML again. `htmlToAdf` refuses a value that is not a string as `not-a-string` (`docs/decisions.md` §Which code a cause takes). +`html/` may not import `markdown/`, so it learns here which of the carry (`opaque-carry.ts`) and the +mark spellings (`mark-spellings.ts`) it shares and moves them out of `markdown/`; a composed call +naming a markdown `Flavour` sits above both peers. + ### 46. Publish the bundle size in the README, failing the release pipeline when it drifts. Item 7 changes the size. The quantity is what a consumer downloads and loads: the