From ec536332d5b17d4a016f83d40c6ac355c20686c9 Mon Sep 17 00:00:00 2001 From: Claudio Wunder Date: Tue, 3 Nov 2026 19:07:09 +0100 Subject: [PATCH 1/3] perf: drop node positions after metadata Nothing after `metadata` reads where a node came from in the source: the type warnings that print positions run while it parses. Dropping them shrinks every entry the main thread holds and copies to and from the workers. On Node.js's docs that is ~480k position objects, about 80MB, and builds are ~5% faster. `json-simple`, which writes the metadata as it is, no longer has them either, and is about a third of its size. Assisted-by: Claude Opus 5.5 Assisted-by: Claude Sonnet 5.5 --- .changeset/drop-positions.md | 5 +++ .../metadata/utils/__tests__/parse.test.mjs | 31 +++++++++++++++++++ .../src/generators/metadata/utils/parse.mjs | 12 +++++++ 3 files changed, 48 insertions(+) create mode 100644 .changeset/drop-positions.md diff --git a/.changeset/drop-positions.md b/.changeset/drop-positions.md new file mode 100644 index 000000000..6d2e789e0 --- /dev/null +++ b/.changeset/drop-positions.md @@ -0,0 +1,5 @@ +--- +'@doc-kit/core': minor +--- + +The nodes of `metadata`'s entries no longer keep their `position` in the source once they are parsed, since nothing after `metadata` reads it. Builds hold less in memory and are faster, and the output of `json-simple` no longer has them either, now about a third of its size. diff --git a/packages/core/src/generators/metadata/utils/__tests__/parse.test.mjs b/packages/core/src/generators/metadata/utils/__tests__/parse.test.mjs index 4458f5d24..1b9e0c928 100644 --- a/packages/core/src/generators/metadata/utils/__tests__/parse.test.mjs +++ b/packages/core/src/generators/metadata/utils/__tests__/parse.test.mjs @@ -4,6 +4,7 @@ import assert from 'node:assert/strict'; import { describe, it } from 'node:test'; import { u } from 'unist-builder'; +import { visit } from 'unist-util-visit'; import { parseApiDoc } from '../parse.mjs'; @@ -338,4 +339,34 @@ describe('parseApiDoc', () => { assert.strictEqual(secondContent[0].type, 'heading'); }); }); + + describe('source positions', () => { + it('drops where each node of an entry came from', () => { + const tree = u('root', [ + h('fs'), + stability('Stability: 2 - Stable'), + u('paragraph', [u('text', 'Content.')]), + ]); + const position = { + start: { line: 1, column: 1 }, + end: { line: 1, column: 1 }, + }; + + visit(tree, node => { + node.position = position; + }); + + const [entry] = parseApiDoc({ path, tree }, typeMap); + const positioned = []; + + visit(entry.content, node => { + if ('position' in node) { + positioned.push(node.type); + } + }); + + assert.strictEqual(entry.content.children.length, 3); + assert.deepStrictEqual(positioned, []); + }); + }); }); diff --git a/packages/core/src/generators/metadata/utils/parse.mjs b/packages/core/src/generators/metadata/utils/parse.mjs index c3eb41fb5..8a8050121 100644 --- a/packages/core/src/generators/metadata/utils/parse.mjs +++ b/packages/core/src/generators/metadata/utils/parse.mjs @@ -155,5 +155,17 @@ export const parseApiDoc = ({ path, tree, mdx = false }, typeMap) => { return SKIP; }); + // Nothing after this reads where a node came from: letting it go saves + // memory, and copying it to and from the worker threads + for (const { content, heading, stability } of metadataCollection) { + for (const root of [content, heading, stability]) { + if (root) { + visit(root, node => { + delete node.position; + }); + } + } + } + return metadataCollection; }; From db7ba56b2374f703e48b2a455a2b9afe89f9055b Mon Sep 17 00:00:00 2001 From: Claudio Wunder Date: Wed, 4 Nov 2026 19:08:12 +0100 Subject: [PATCH 2/3] refactor: drop positions with one walk over each entry's content An entry's heading and stability are nodes of its content, so walking the content alone covers them, without a loop over the three of them and a check for a missing one. The test now checks the heading and the stability too. Assisted-by: Claude Opus 5.5 --- .../metadata/utils/__tests__/parse.test.mjs | 2 ++ .../core/src/generators/metadata/utils/parse.mjs | 15 ++++++--------- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/packages/core/src/generators/metadata/utils/__tests__/parse.test.mjs b/packages/core/src/generators/metadata/utils/__tests__/parse.test.mjs index 1b9e0c928..17872567e 100644 --- a/packages/core/src/generators/metadata/utils/__tests__/parse.test.mjs +++ b/packages/core/src/generators/metadata/utils/__tests__/parse.test.mjs @@ -367,6 +367,8 @@ describe('parseApiDoc', () => { assert.strictEqual(entry.content.children.length, 3); assert.deepStrictEqual(positioned, []); + assert.ok(!('position' in entry.heading)); + assert.ok(entry.stability && !('position' in entry.stability)); }); }); }); diff --git a/packages/core/src/generators/metadata/utils/parse.mjs b/packages/core/src/generators/metadata/utils/parse.mjs index 8a8050121..df81dd243 100644 --- a/packages/core/src/generators/metadata/utils/parse.mjs +++ b/packages/core/src/generators/metadata/utils/parse.mjs @@ -156,15 +156,12 @@ export const parseApiDoc = ({ path, tree, mdx = false }, typeMap) => { }); // Nothing after this reads where a node came from: letting it go saves - // memory, and copying it to and from the worker threads - for (const { content, heading, stability } of metadataCollection) { - for (const root of [content, heading, stability]) { - if (root) { - visit(root, node => { - delete node.position; - }); - } - } + // memory, and copying it to and from the worker threads. An entry's heading + // and stability are nodes of its content + for (const { content } of metadataCollection) { + visit(content, node => { + delete node.position; + }); } return metadataCollection; From 2ab0ad037acf925486b209dbe9c37e38638ddcbd Mon Sep 17 00:00:00 2001 From: Claudio Wunder Date: Tue, 10 Nov 2026 22:44:43 +0100 Subject: [PATCH 3/3] test: name position where the metadata drops it The test and the comment say position rather than where a node came from, and the comment says which reader of it already ran. The test no longer checks how many children the entry's content has, which isn't about positions. Assisted-by: Claude Opus 5.5 --- .../src/generators/metadata/utils/__tests__/parse.test.mjs | 3 +-- packages/core/src/generators/metadata/utils/parse.mjs | 6 +++--- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/packages/core/src/generators/metadata/utils/__tests__/parse.test.mjs b/packages/core/src/generators/metadata/utils/__tests__/parse.test.mjs index 17872567e..02b9ecc99 100644 --- a/packages/core/src/generators/metadata/utils/__tests__/parse.test.mjs +++ b/packages/core/src/generators/metadata/utils/__tests__/parse.test.mjs @@ -341,7 +341,7 @@ describe('parseApiDoc', () => { }); describe('source positions', () => { - it('drops where each node of an entry came from', () => { + it('drops position from every node of an entry', () => { const tree = u('root', [ h('fs'), stability('Stability: 2 - Stable'), @@ -365,7 +365,6 @@ describe('parseApiDoc', () => { } }); - assert.strictEqual(entry.content.children.length, 3); assert.deepStrictEqual(positioned, []); assert.ok(!('position' in entry.heading)); assert.ok(entry.stability && !('position' in entry.stability)); diff --git a/packages/core/src/generators/metadata/utils/parse.mjs b/packages/core/src/generators/metadata/utils/parse.mjs index df81dd243..b218c88c8 100644 --- a/packages/core/src/generators/metadata/utils/parse.mjs +++ b/packages/core/src/generators/metadata/utils/parse.mjs @@ -155,9 +155,9 @@ export const parseApiDoc = ({ path, tree, mdx = false }, typeMap) => { return SKIP; }); - // Nothing after this reads where a node came from: letting it go saves - // memory, and copying it to and from the worker threads. An entry's heading - // and stability are nodes of its content + // Nothing after this reads a node's `position` (resolveTypes' warning + // already ran): dropping it saves memory, and copying it to and from the + // worker threads. An entry's heading and stability are nodes of its content for (const { content } of metadataCollection) { visit(content, node => { delete node.position;