From bbe33ee6913fbf935e6deb0028fdfba802af0a12 Mon Sep 17 00:00:00 2001 From: Harold Campbell Date: Tue, 2 Jun 2026 10:14:32 -0500 Subject: [PATCH 1/4] Add AST placeholder and tests for abbreviations directive --- .gitignore | 3 + .../myst-directives/src/abbreviations.spec.ts | 71 +++++++++++++++++++ packages/myst-directives/src/abbreviations.ts | 33 +++++++++ packages/myst-directives/src/index.ts | 3 + .../tests/abbreviations-directive/README.md | 46 ++++++++++++ .../tests/abbreviations-directive/index.md | 10 +++ .../tests/abbreviations-directive/myst.yml | 11 +++ .../tests/abbreviations-directive/page.md | 13 ++++ 8 files changed, 190 insertions(+) create mode 100644 packages/myst-directives/src/abbreviations.spec.ts create mode 100644 packages/myst-directives/src/abbreviations.ts create mode 100644 packages/mystmd/tests/abbreviations-directive/README.md create mode 100644 packages/mystmd/tests/abbreviations-directive/index.md create mode 100644 packages/mystmd/tests/abbreviations-directive/myst.yml create mode 100644 packages/mystmd/tests/abbreviations-directive/page.md diff --git a/.gitignore b/.gitignore index 86cb67592d..ab7d5f7fc1 100644 --- a/.gitignore +++ b/.gitignore @@ -46,3 +46,6 @@ yalc.lock # vim swap files *.swp + +# local logs +logs \ No newline at end of file diff --git a/packages/myst-directives/src/abbreviations.spec.ts b/packages/myst-directives/src/abbreviations.spec.ts new file mode 100644 index 0000000000..c0c8ef9902 --- /dev/null +++ b/packages/myst-directives/src/abbreviations.spec.ts @@ -0,0 +1,71 @@ +import { describe, expect, test } from 'vitest'; +import type { DirectiveData } from 'myst-common'; +import { abbreviationsDirective } from './abbreviations.js'; +import { defaultDirectives } from './index.js'; + +function run(data: Partial = {}) { + return abbreviationsDirective.run!({ + name: 'abbreviations', + node: {} as any, + options: {}, + ...data, + }); +} + +function log(arg: any) { + console.dir(arg, { depth: null }); + return arg +} +describe('abbreviations directive', () => { + test('creates a placeholder node', () => { + expect(run()).toEqual([{ type: 'abbreviations', children: [] }]); + }); + + test('wraps argument content in a heading', () => { + expect(run({ arg: [{ type: 'text', value: 'Abbreviations' }] })).toEqual([ + { + type: 'abbreviations', + children: [ + { + type: 'heading', + depth: 2, + enumerated: false, + children: [{ type: 'text', value: 'Abbreviations' }], + }, + ], + }, + ]); + }); + + test('preserves heading arguments', () => { + const heading = { + type: 'heading', + depth: 3, + children: [{ type: 'text', value: 'Terms' }], + }; + expect(run({ arg: [heading] })).toEqual([{ type: 'abbreviations', children: [heading] }]); + }); + + test('preserves common directive options', () => { + expect( + run({ + options: { + class: 'compact', + label: 'abbreviations-list', + }, + }), + ).toEqual([ + { + type: 'abbreviations', + children: [], + class: 'compact', + label: 'abbreviations-list', + identifier: 'abbreviations-list', + }, + ]); + }); + + test('is registered by default', () => { + expect(defaultDirectives).toContain(abbreviationsDirective); + }); +}); diff --git a/packages/myst-directives/src/abbreviations.ts b/packages/myst-directives/src/abbreviations.ts new file mode 100644 index 0000000000..863934b279 --- /dev/null +++ b/packages/myst-directives/src/abbreviations.ts @@ -0,0 +1,33 @@ +import type { DirectiveData, DirectiveSpec, GenericNode } from 'myst-common'; +import { addCommonDirectiveOptions, commonDirectiveOptions } from './utils.js'; + +export const abbreviationsDirective: DirectiveSpec = { + name: 'abbreviations', + doc: 'Inserts a list of known abbreviations in the page.', + arg: { + type: 'myst', + doc: 'Heading to be included with the abbreviations list', + }, + options: { + ...commonDirectiveOptions('abbreviations'), + }, + run(data: DirectiveData): GenericNode[] { + const children: GenericNode[] = []; + if (data.arg) { + const parsedArg = data.arg as GenericNode[]; + if (parsedArg[0]?.type === 'heading') { + children.push(...parsedArg); + } else { + children.push({ + type: 'heading', + depth: 2, + enumerated: false, + children: parsedArg, + }); + } + } + const abbreviations = { type: 'abbreviations', children }; + addCommonDirectiveOptions(data, abbreviations); + return [abbreviations]; + }, +}; diff --git a/packages/myst-directives/src/index.ts b/packages/myst-directives/src/index.ts index 28ae60aa5e..5de36011b4 100644 --- a/packages/myst-directives/src/index.ts +++ b/packages/myst-directives/src/index.ts @@ -10,6 +10,7 @@ import { includeDirective } from './include.js'; import { indexDirective, genIndexDirective } from './indices.js'; import { csvTableDirective, tableDirective, listTableDirective } from './table.js'; import { asideDirective } from './aside.js'; +import { abbreviationsDirective } from './abbreviations.js'; import { glossaryDirective } from './glossary.js'; import { mathDirective } from './math.js'; import { mdastDirective } from './mdast.js'; @@ -39,6 +40,7 @@ export const defaultDirectives = [ tableDirective, listTableDirective, asideDirective, + abbreviationsDirective, glossaryDirective, mathDirective, mdastDirective, @@ -65,6 +67,7 @@ export { includeDirective } from './include.js'; export { indexDirective, genIndexDirective } from './indices.js'; export { csvTableDirective, listTableDirective, tableDirective } from './table.js'; export { asideDirective } from './aside.js'; +export { abbreviationsDirective } from './abbreviations.js'; export { mathDirective } from './math.js'; export { mdastDirective } from './mdast.js'; export { mermaidDirective } from './mermaid.js'; diff --git a/packages/mystmd/tests/abbreviations-directive/README.md b/packages/mystmd/tests/abbreviations-directive/README.md new file mode 100644 index 0000000000..65ca2dd782 --- /dev/null +++ b/packages/mystmd/tests/abbreviations-directive/README.md @@ -0,0 +1,46 @@ +# Abbreviations Directive Sample + +This sample is intentionally not an automated test yet. + +Use it while implementing issue 1098 in a quasi-TDD loop: + +```sh +myst build --html --ci +``` + +Expected eventual behavior: + +- `index.md` renders an `Abbreviations` heading followed by a definition list. +- The list includes `API`, `CLI`, and `MyST`. +- The list omits `SHRILL` because its metadata value is `null`. +- `page.md` preserves the directive `label` and `class` metadata on the generated wrapper block. +- Once project-wide aggregation is implemented, `page.md` can include both project abbreviations and page-level `AST`. + +Before 1098 is implemented, this sample is expected to expose missing directive support. + + +### Local testing +Building the changes requires: + +1. Build the changes +``` + cd mystmd + bun run build +``` +2. Then run the local built CLI against the sample fixture: +``` + cd packages/mystmd/tests/abbreviations-directive + bun ../../dist/myst.cjs build --html --ci +``` + The expected result is limited: MyST should recognize {abbreviations} as a known directive + and parse it into a placeholder. You should not expect a rendered abbreviation list yet; that comes later. + +3. Run the focused tests: +``` + cd mystmd + bun test packages/myst-directives/src/abbreviations.spec.ts +``` + And the directive package regression: +``` + bun test packages/myst-directives/src +``` \ No newline at end of file diff --git a/packages/mystmd/tests/abbreviations-directive/index.md b/packages/mystmd/tests/abbreviations-directive/index.md new file mode 100644 index 0000000000..42f2362a45 --- /dev/null +++ b/packages/mystmd/tests/abbreviations-directive/index.md @@ -0,0 +1,10 @@ +# Abbreviations Directive + +This page uses API, CLI, and MyST so the existing inline abbreviation transform +can still be checked alongside the new directive. + +```{abbreviations} Abbreviations +``` + +SHRILL is configured with a null expansion and should not appear in the +generated abbreviation list. diff --git a/packages/mystmd/tests/abbreviations-directive/myst.yml b/packages/mystmd/tests/abbreviations-directive/myst.yml new file mode 100644 index 0000000000..95dc899b40 --- /dev/null +++ b/packages/mystmd/tests/abbreviations-directive/myst.yml @@ -0,0 +1,11 @@ +version: 1 +project: + title: Abbreviations Directive Sample + abbreviations: + API: Application Programming Interface + CLI: Command Line Interface + MyST: Markedly Structured Text + SHRILL: null + toc: + - file: index.md + - file: page.md diff --git a/packages/mystmd/tests/abbreviations-directive/page.md b/packages/mystmd/tests/abbreviations-directive/page.md new file mode 100644 index 0000000000..966afb786d --- /dev/null +++ b/packages/mystmd/tests/abbreviations-directive/page.md @@ -0,0 +1,13 @@ +--- +abbreviations: + AST: Abstract Syntax Tree +--- + +# Page-Level Abbreviations + +This page uses AST plus project abbreviations like API and MyST. + +```{abbreviations} +:label: abbreviations-list +:class: compact +``` From 454178d6299a14d0a3b06c4fbb4795619ed56e45 Mon Sep 17 00:00:00 2001 From: Harold Campbell Date: Tue, 2 Jun 2026 12:53:48 -0500 Subject: [PATCH 2/4] Add abbreviations list transform --- packages/myst-transforms/src/abbreviations.ts | 42 ++++- packages/myst-transforms/src/index.ts | 6 +- .../tests/abbreviations-list.spec.ts | 81 +++++++++ .../tests/abbreviations-list.yml | 158 ++++++++++++++++++ .../tests/abbreviations-directive/README.md | 46 ++--- 5 files changed, 312 insertions(+), 21 deletions(-) create mode 100644 packages/myst-transforms/tests/abbreviations-list.spec.ts create mode 100644 packages/myst-transforms/tests/abbreviations-list.yml diff --git a/packages/myst-transforms/src/abbreviations.ts b/packages/myst-transforms/src/abbreviations.ts index 6aec1dab0e..eaf5e9a2cf 100644 --- a/packages/myst-transforms/src/abbreviations.ts +++ b/packages/myst-transforms/src/abbreviations.ts @@ -1,5 +1,5 @@ import type { Plugin } from 'unified'; -import type { GenericParent } from 'myst-common'; +import type { GenericNode, GenericParent } from 'myst-common'; import { toText } from 'myst-common'; import { selectAll } from 'unist-util-select'; import type { Abbreviation, Text } from 'myst-spec'; @@ -80,3 +80,43 @@ export const abbreviationPlugin: Plugin<[Options], GenericParent, GenericParent> (opts) => (tree) => { abbreviationTransform(tree, opts); }; + +export function abbreviationListChildren(abbreviations?: Record) { + const entries = Object.entries(abbreviations ?? {}) + .filter((entry): entry is [string, string] => !!entry[1]) + .sort(([a], [b]) => a.localeCompare(b)); + + if (!entries.length) return []; + + return [ + { + type: 'definitionList', + children: entries + .map(([abbr, title]) => [ + { + type: 'definitionTerm', + children: [{ type: 'text', value: abbr }], + }, + { + type: 'definitionDescription', + children: [ + { + type: 'paragraph', + children: [{ type: 'text', value: title }], + }, + ], + }, + ]) + .flat(), + }, + ]; +} + +export function abbreviationsListTransform(mdast: GenericParent, opts?: Options) { + const nodes = selectAll('abbreviations', mdast) as GenericNode[]; + nodes.forEach((node) => { + node.type = 'block'; + node.data = { ...(node.data ?? {}), part: 'abbreviations' }; + node.children = [...(node.children ?? []), ...abbreviationListChildren(opts?.abbreviations)]; + }); +} diff --git a/packages/myst-transforms/src/index.ts b/packages/myst-transforms/src/index.ts index ce91632c47..2481492a19 100644 --- a/packages/myst-transforms/src/index.ts +++ b/packages/myst-transforms/src/index.ts @@ -58,7 +58,11 @@ export { } from './targets.js'; export { joinGatesPlugin, joinGatesTransform } from './joinGates.js'; export { glossaryPlugin, glossaryTransform } from './glossary.js'; -export { abbreviationPlugin, abbreviationTransform } from './abbreviations.js'; +export { + abbreviationPlugin, + abbreviationTransform, + abbreviationsListTransform, +} from './abbreviations.js'; export { includeDirectivePlugin, includeDirectiveTransform } from './include.js'; export { containerChildrenPlugin, containerChildrenTransform } from './containers.js'; export { headingDepthPlugin, headingDepthTransform } from './headings.js'; diff --git a/packages/myst-transforms/tests/abbreviations-list.spec.ts b/packages/myst-transforms/tests/abbreviations-list.spec.ts new file mode 100644 index 0000000000..8580ed19f1 --- /dev/null +++ b/packages/myst-transforms/tests/abbreviations-list.spec.ts @@ -0,0 +1,81 @@ +import { describe, expect, test } from 'vitest'; +import fs from 'node:fs'; +import path from 'node:path'; +import yaml from 'js-yaml'; +import { abbreviationsListTransform } from '../src'; +import { abbreviationListChildren } from '../src/abbreviations'; + +type TestFile = { + cases: TestCase[]; +}; +type TestCase = { + title: string; + before: any; + after: any; + opts?: { + abbreviations?: Record; + }; +}; + +const fixtures = path.join('tests', 'abbreviations-list.yml'); +const testYaml = fs.readFileSync(fixtures).toString(); +const cases = (yaml.load(testYaml) as TestFile).cases; + +describe('abbreviationListChildren', () => { + test('returns no children without abbreviations', () => { + expect(abbreviationListChildren()).toEqual([]); + expect(abbreviationListChildren({})).toEqual([]); + }); + + test('creates a sorted definition list and omits null values', () => { + expect( + abbreviationListChildren({ + MyST: 'Markedly Structured Text', + SHRILL: null, + API: 'Application Programming Interface', + }), + ).toEqual([ + { + type: 'definitionList', + children: [ + { + type: 'definitionTerm', + children: [{ type: 'text', value: 'API' }], + }, + { + type: 'definitionDescription', + children: [ + { + type: 'paragraph', + children: [{ type: 'text', value: 'Application Programming Interface' }], + }, + ], + }, + { + type: 'definitionTerm', + children: [{ type: 'text', value: 'MyST' }], + }, + { + type: 'definitionDescription', + children: [ + { + type: 'paragraph', + children: [{ type: 'text', value: 'Markedly Structured Text' }], + }, + ], + }, + ], + }, + ]); + }); +}); + +describe('abbreviations list', () => { + test.each(cases.map((c): [string, TestCase] => [c.title, c]))( + '%s', + (_, { before, after, opts }) => { + abbreviationsListTransform(before, opts); + expect(yaml.dump(before)).toEqual(yaml.dump(after)); + }, + ); +}); diff --git a/packages/myst-transforms/tests/abbreviations-list.yml b/packages/myst-transforms/tests/abbreviations-list.yml new file mode 100644 index 0000000000..f2f4cea07a --- /dev/null +++ b/packages/myst-transforms/tests/abbreviations-list.yml @@ -0,0 +1,158 @@ +cases: + - title: simple generated list + opts: + abbreviations: + MyST: Markedly Structured Text + API: Application Programming Interface + before: + type: root + children: + - type: abbreviations + children: [] + after: + type: root + children: + - type: block + children: + - type: definitionList + children: + - type: definitionTerm + children: + - type: text + value: API + - type: definitionDescription + children: + - type: paragraph + children: + - type: text + value: Application Programming Interface + - type: definitionTerm + children: + - type: text + value: MyST + - type: definitionDescription + children: + - type: paragraph + children: + - type: text + value: Markedly Structured Text + data: + part: abbreviations + - title: null abbreviations omitted + opts: + abbreviations: + HR: Heart Rate + SHRILL: null + before: + type: root + children: + - type: abbreviations + children: [] + after: + type: root + children: + - type: block + children: + - type: definitionList + children: + - type: definitionTerm + children: + - type: text + value: HR + - type: definitionDescription + children: + - type: paragraph + children: + - type: text + value: Heart Rate + data: + part: abbreviations + - title: heading preserved + opts: + abbreviations: + API: Application Programming Interface + before: + type: root + children: + - type: abbreviations + children: + - type: heading + depth: 2 + enumerated: false + children: + - type: text + value: Abbreviations + after: + type: root + children: + - type: block + children: + - type: heading + depth: 2 + enumerated: false + children: + - type: text + value: Abbreviations + - type: definitionList + children: + - type: definitionTerm + children: + - type: text + value: API + - type: definitionDescription + children: + - type: paragraph + children: + - type: text + value: Application Programming Interface + data: + part: abbreviations + - title: no abbreviations + opts: + abbreviations: {} + before: + type: root + children: + - type: abbreviations + children: [] + after: + type: root + children: + - type: block + children: [] + data: + part: abbreviations + - title: common options stay on wrapper + opts: + abbreviations: + API: Application Programming Interface + before: + type: root + children: + - type: abbreviations + label: abbreviations-list + identifier: abbreviations-list + class: compact + children: [] + after: + type: root + children: + - type: block + label: abbreviations-list + identifier: abbreviations-list + class: compact + children: + - type: definitionList + children: + - type: definitionTerm + children: + - type: text + value: API + - type: definitionDescription + children: + - type: paragraph + children: + - type: text + value: Application Programming Interface + data: + part: abbreviations diff --git a/packages/mystmd/tests/abbreviations-directive/README.md b/packages/mystmd/tests/abbreviations-directive/README.md index 65ca2dd782..de746649b0 100644 --- a/packages/mystmd/tests/abbreviations-directive/README.md +++ b/packages/mystmd/tests/abbreviations-directive/README.md @@ -19,28 +19,36 @@ Expected eventual behavior: Before 1098 is implemented, this sample is expected to expose missing directive support. -### Local testing -Building the changes requires: +## Local Testing -1. Build the changes -``` - cd mystmd - bun run build -``` -2. Then run the local built CLI against the sample fixture: -``` - cd packages/mystmd/tests/abbreviations-directive - bun ../../dist/myst.cjs build --html --ci +Build the changes: + +```sh +cd mystmd +bun run build ``` - The expected result is limited: MyST should recognize {abbreviations} as a known directive - and parse it into a placeholder. You should not expect a rendered abbreviation list yet; that comes later. -3. Run the focused tests: +Run the local built CLI against the sample fixture: + +```sh +cd packages/mystmd/tests/abbreviations-directive +bun ../../dist/myst.cjs build --html --ci ``` - cd mystmd - bun test packages/myst-directives/src/abbreviations.spec.ts + +At the parser stage, the expected result is limited: MyST should recognize `{abbreviations}` as a known directive and parse it into a placeholder. You should not expect a rendered abbreviation list yet. + +Validate the placeholder-to-definition-list transform directly: + +```sh +cd mystmd/packages/myst-transforms +bun test tests/abbreviations-list.spec.ts ``` - And the directive package regression: + +Run the existing inline abbreviation regression: + +```sh +cd mystmd/packages/myst-transforms +bun test tests/abbreviations.spec.ts ``` - bun test packages/myst-directives/src -``` \ No newline at end of file + +The local transform test does not wire the transform into the CLI/site build. Rendered sample pages should not show the generated abbreviation list until project/site wiring is implemented. From 51a16058053897121ad8e46a87fbdb9f00ddec7c Mon Sep 17 00:00:00 2001 From: Harold Campbell Date: Thu, 2 Jul 2026 16:39:40 -0500 Subject: [PATCH 3/4] Add project-wide abbreviations directive build support --- packages/myst-cli/src/process/mdast.ts | 14 +++++ packages/myst-transforms/src/abbreviations.ts | 5 +- .../tests/abbreviations-directive/README.md | 53 +++++++++++++------ .../tests/abbreviations-directive/index.md | 2 +- .../tests/abbreviations-directive/myst.yml | 19 ++++++- .../{page.md => page-1.md} | 5 +- .../tests/abbreviations-directive/page-2.md | 10 ++++ .../tests/abbreviations-directive/page-3.md | 10 ++++ packages/mystmd/tests/exports.yml | 8 +++ 9 files changed, 105 insertions(+), 21 deletions(-) rename packages/mystmd/tests/abbreviations-directive/{page.md => page-1.md} (53%) create mode 100644 packages/mystmd/tests/abbreviations-directive/page-2.md create mode 100644 packages/mystmd/tests/abbreviations-directive/page-3.md diff --git a/packages/myst-cli/src/process/mdast.ts b/packages/myst-cli/src/process/mdast.ts index 24602edd2f..db180515e8 100644 --- a/packages/myst-cli/src/process/mdast.ts +++ b/packages/myst-cli/src/process/mdast.ts @@ -30,6 +30,7 @@ import { checkLinkTextTransform, indexIdentifierPlugin, buildTocTransform, + abbreviationsListTransform, } from 'myst-transforms'; import { unified } from 'unified'; import { select, selectAll } from 'unist-util-select'; @@ -98,6 +99,16 @@ const htmlHandlers = { }, }; +function collectAbbreviations(session: ISession, pageReferenceStates: ReferenceState[]) { + const cache = castSession(session); + const abbreviations: Record = {}; + pageReferenceStates.forEach((state) => { + const pageAbbreviations = cache.$getMdast(state.filePath)?.post?.frontmatter?.abbreviations; + if (pageAbbreviations) Object.assign(abbreviations, pageAbbreviations); + }); + return abbreviations; +} + export type TransformFn = ( session: ISession, opts: Parameters[1], @@ -344,6 +355,9 @@ export async function postProcessMdast( projectSlug, mdastPost.slug, ); + abbreviationsListTransform(mdast, { + abbreviations: collectAbbreviations(session, pageReferenceStates), + }); } // NOTE: This is doing things in place, we should potentially make this a different state? const transformers = [ diff --git a/packages/myst-transforms/src/abbreviations.ts b/packages/myst-transforms/src/abbreviations.ts index eaf5e9a2cf..55133aca73 100644 --- a/packages/myst-transforms/src/abbreviations.ts +++ b/packages/myst-transforms/src/abbreviations.ts @@ -82,9 +82,10 @@ export const abbreviationPlugin: Plugin<[Options], GenericParent, GenericParent> }; export function abbreviationListChildren(abbreviations?: Record) { + // turns an abbreviations object into a clean, sorted list of abbreviation entries. const entries = Object.entries(abbreviations ?? {}) - .filter((entry): entry is [string, string] => !!entry[1]) - .sort(([a], [b]) => a.localeCompare(b)); + .filter((entry): entry is [string, string] => !!entry[1]) // Keeps only entries where the value exists + .sort(([a], [b]) => a.localeCompare(b)); // Sort alphabetically by abbreviation key. if (!entries.length) return []; diff --git a/packages/mystmd/tests/abbreviations-directive/README.md b/packages/mystmd/tests/abbreviations-directive/README.md index de746649b0..84b4e8b053 100644 --- a/packages/mystmd/tests/abbreviations-directive/README.md +++ b/packages/mystmd/tests/abbreviations-directive/README.md @@ -1,41 +1,57 @@ # Abbreviations Directive Sample -This sample is intentionally not an automated test yet. +This fixture exercises the `{abbreviations}` directive during local development. -Use it while implementing issue 1098 in a quasi-TDD loop: +Current content files: + +- `index.md`: directive on the landing page, plus inline abbreviation text. +- `page-1.md`: page-level `AST` abbreviation and directive options. +- `page-2.md`: page-level `GPU` abbreviation without a directive. +- `page-3.md`: multiple page-level abbreviations without a directive. + +`README.md` is intentionally not listed in `project.toc`, so it is not built as a page. + +The current `myst.yml` was generated with: ```sh -myst build --html --ci +bun ../../dist/myst.cjs init --project --site --write-toc ``` -Expected eventual behavior: +Review `myst.yml` after regenerating it. The generated file may need manual edits for: -- `index.md` renders an `Abbreviations` heading followed by a definition list. -- The list includes `API`, `CLI`, and `MyST`. -- The list omits `SHRILL` because its metadata value is `null`. -- `page.md` preserves the directive `label` and `class` metadata on the generated wrapper block. -- Once project-wide aggregation is implemented, `page.md` can include both project abbreviations and page-level `AST`. +- `project.abbreviations`, if you want project-level definitions such as `API`, `CLI`, or `MyST`. +- `project.toc`, if you want to keep `README.md` excluded or reorder pages. +- `site.template`, if the generated template differs from the fixture expectation. -Before 1098 is implemented, this sample is expected to expose missing directive support. +Expected behavior: +- Pages with `{abbreviations}` render a generated definition list. +- The generated list includes non-null abbreviations collected from the project pages. +- Null-valued abbreviations are omitted. +- `page-1.md` preserves the directive `label` and `class` metadata on the generated wrapper block. ## Local Testing -Build the changes: +From the repo root, rebuild local packages: ```sh cd mystmd -bun run build +bun run build -- --force ``` Run the local built CLI against the sample fixture: ```sh cd packages/mystmd/tests/abbreviations-directive -bun ../../dist/myst.cjs build --html --ci +bun ../../dist/myst.cjs build --ci ``` -At the parser stage, the expected result is limited: MyST should recognize `{abbreviations}` as a known directive and parse it into a placeholder. You should not expect a rendered abbreviation list yet. +Inspect generated page JSON: + +```sh +ls _build/site/content +rg '"part": "abbreviations"|definitionList|AST|GPU|Algo|SA' _build/site/content +``` Validate the placeholder-to-definition-list transform directly: @@ -51,4 +67,11 @@ cd mystmd/packages/myst-transforms bun test tests/abbreviations.spec.ts ``` -The local transform test does not wire the transform into the CLI/site build. Rendered sample pages should not show the generated abbreviation list until project/site wiring is implemented. +Run the focused end-to-end fixture test: + +```sh +cd mystmd +bun test packages/mystmd/tests/endToEnd.spec.ts -t "Abbreviations directive site build" +``` + +The focused end-to-end case should stay aligned with `project.toc`; it checks that site JSON is generated for `index.md`, `page-1.md`, `page-2.md`, and `page-3.md`. diff --git a/packages/mystmd/tests/abbreviations-directive/index.md b/packages/mystmd/tests/abbreviations-directive/index.md index 42f2362a45..9efea51efc 100644 --- a/packages/mystmd/tests/abbreviations-directive/index.md +++ b/packages/mystmd/tests/abbreviations-directive/index.md @@ -1,4 +1,4 @@ -# Abbreviations Directive +# Abbreviations Directive (index.md) This page uses API, CLI, and MyST so the existing inline abbreviation transform can still be checked alongside the new directive. diff --git a/packages/mystmd/tests/abbreviations-directive/myst.yml b/packages/mystmd/tests/abbreviations-directive/myst.yml index 95dc899b40..4b37e11b43 100644 --- a/packages/mystmd/tests/abbreviations-directive/myst.yml +++ b/packages/mystmd/tests/abbreviations-directive/myst.yml @@ -1,11 +1,26 @@ +# See docs at: https://mystmd.org/guide/frontmatter version: 1 project: + id: 8e548486-6c71-442a-8e4e-33347b477f09 title: Abbreviations Directive Sample abbreviations: API: Application Programming Interface CLI: Command Line Interface MyST: Markedly Structured Text - SHRILL: null + # description: + # keywords: [] + # authors: [] + github: https://github.com/jupyter-book/mystmd + # To autogenerate a Table of Contents, run "myst init --write-toc" toc: + # Auto-generated by `myst init --write-toc` - file: index.md - - file: page.md + - file: page-1.md + - file: page-2.md + - file: page-3.md + +site: + template: book-theme + # options: + # favicon: favicon.ico + # logo: site_logo.png diff --git a/packages/mystmd/tests/abbreviations-directive/page.md b/packages/mystmd/tests/abbreviations-directive/page-1.md similarity index 53% rename from packages/mystmd/tests/abbreviations-directive/page.md rename to packages/mystmd/tests/abbreviations-directive/page-1.md index 966afb786d..8a35d2062f 100644 --- a/packages/mystmd/tests/abbreviations-directive/page.md +++ b/packages/mystmd/tests/abbreviations-directive/page-1.md @@ -7,7 +7,10 @@ abbreviations: This page uses AST plus project abbreviations like API and MyST. -```{abbreviations} +```{abbreviations} New Abbrevs :label: abbreviations-list :class: compact ``` + +I expect to see something related to text like API or CLI from the project. +Here's some text with GPU when it was defined in [](:page-2) \ No newline at end of file diff --git a/packages/mystmd/tests/abbreviations-directive/page-2.md b/packages/mystmd/tests/abbreviations-directive/page-2.md new file mode 100644 index 0000000000..2394a91346 --- /dev/null +++ b/packages/mystmd/tests/abbreviations-directive/page-2.md @@ -0,0 +1,10 @@ +--- +abbreviations: + GPU: Graphics Processing Unit +--- + +# Page 2 + +This is the second page on the micro-site + +Here's some text with GPU. \ No newline at end of file diff --git a/packages/mystmd/tests/abbreviations-directive/page-3.md b/packages/mystmd/tests/abbreviations-directive/page-3.md new file mode 100644 index 0000000000..6ca9d2b009 --- /dev/null +++ b/packages/mystmd/tests/abbreviations-directive/page-3.md @@ -0,0 +1,10 @@ +--- +abbreviations: + Fl: Fruity Loops + Algo: Algorithm + SA: South Africa +--- + +# Page 3 + +This is random content for page 3 and here we talk about Fl, Algo and SA. diff --git a/packages/mystmd/tests/exports.yml b/packages/mystmd/tests/exports.yml index 7180065189..f706701810 100644 --- a/packages/mystmd/tests/exports.yml +++ b/packages/mystmd/tests/exports.yml @@ -199,6 +199,14 @@ cases: content: outputs/basic-site-config.json - path: basic-site/_build/site/myst.xref.json content: outputs/basic-site-myst.xref.json + - title: Abbreviations directive site build + cwd: abbreviations-directive + command: myst build + outputs: + - path: abbreviations-directive/_build/site/content/index.json + - path: abbreviations-directive/_build/site/content/page-1.json + - path: abbreviations-directive/_build/site/content/page-2.json + - path: abbreviations-directive/_build/site/content/page-3.json - title: Alternate config file cwd: alternate-config command: myst --config foo.yml build From 6b3ee263eb174af5306d44ee1f633c74c944e8d1 Mon Sep 17 00:00:00 2001 From: Harold Campbell Date: Sun, 19 Jul 2026 04:36:34 -0500 Subject: [PATCH 4/4] Add documentation for abbreviations directive --- docs/directives.md | 3 +++ docs/glossaries-and-terms.md | 20 +++++++++++++++++++ packages/myst-directives/src/abbreviations.ts | 2 +- 3 files changed, 24 insertions(+), 1 deletion(-) diff --git a/docs/directives.md b/docs/directives.md index a3fc16c7db..1438124a52 100644 --- a/docs/directives.md +++ b/docs/directives.md @@ -6,6 +6,9 @@ label: directives_list To learn more about the syntax and usage of the directives, please refer to the [](#syntax:directives) section of the documentation. +:::{myst:directive} abbreviations +::: + :::{myst:directive} admonition ::: diff --git a/docs/glossaries-and-terms.md b/docs/glossaries-and-terms.md index 0afd315dc5..ce5d6413d6 100644 --- a/docs/glossaries-and-terms.md +++ b/docs/glossaries-and-terms.md @@ -228,3 +228,23 @@ abbreviations: We use ML to parse HTML. ``` + +### Generate a list of abbreviations + +The `{abbreviations}` directive displays a definition list of known abbreviates. The entries are sorted alphabetically by abbreviation key. + +In this context `known abbreviations` means that abbreviations are pulled from the projects `yml` and the frontmatter from available pages at build time. + +Example snippet: + +::::{dropdown} Show abbreviations used in these docs +:::{abbreviations} +::: +:::: + +:::{note} Order of abbreviations +Page-level abbreviates to will overwrite project-level abbreviations. +::: + +Entries with `null` values are not included in the generated list. + diff --git a/packages/myst-directives/src/abbreviations.ts b/packages/myst-directives/src/abbreviations.ts index 863934b279..47f02e0786 100644 --- a/packages/myst-directives/src/abbreviations.ts +++ b/packages/myst-directives/src/abbreviations.ts @@ -3,7 +3,7 @@ import { addCommonDirectiveOptions, commonDirectiveOptions } from './utils.js'; export const abbreviationsDirective: DirectiveSpec = { name: 'abbreviations', - doc: 'Inserts a list of known abbreviations in the page.', + doc: 'Inserts an alphabetized list of known abbreviations, collected the pages and project.', arg: { type: 'myst', doc: 'Heading to be included with the abbreviations list',