@tsdoctor/model 0.4.1 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/Render.js CHANGED
@@ -31,6 +31,9 @@ const KIND_SLUG = {
31
31
  * `ApiExportedMixin`. Every other item, including any lacking the flag, is
32
32
  * kept.
33
33
  *
34
+ * @deprecated Use `prepareWorkItems` from `@tsdoctor/pages`, which decides
35
+ * which items receive a page (`isPageKind` for the kind, `SyntheticBases.detect`
36
+ * for the hoisted `*_base` declarations this rule was written to drop).
34
37
  * @public
35
38
  */
36
39
  const isEmittable = (item) => item.isExported !== false;
@@ -42,6 +45,8 @@ const signatureOf = (item) => {
42
45
  * Render one API item's markdown body as flow nodes — the pre-serialization
43
46
  * form of {@link item}.
44
47
  *
48
+ * @deprecated Use `buildPage` + `markdownTree` from `@tsdoctor/pages`, which
49
+ * yields the same `FlowContent` nodes from a typed `Page`.
45
50
  * @alpha
46
51
  */
47
52
  function tree(apiItem, opts) {
@@ -128,6 +133,7 @@ function tree(apiItem, opts) {
128
133
  /**
129
134
  * Render one API item to a markdown body string (no frontmatter).
130
135
  *
136
+ * @deprecated Use `buildPage` + `renderMarkdown` from `@tsdoctor/pages`.
131
137
  * @public
132
138
  */
133
139
  function item(apiItem, opts) {
@@ -139,6 +145,9 @@ function item(apiItem, opts) {
139
145
  * Walk a package's first entry point and assemble one RenderedDoc per
140
146
  * top-level member.
141
147
  *
148
+ * @deprecated Use `prepareWorkItems` + `buildPage` + `renderMarkdown` from
149
+ * `@tsdoctor/pages`; frontmatter is assembled by the adapter from the
150
+ * `Page`'s facts and head tags.
142
151
  * @public
143
152
  */
144
153
  function docs(apiPackage, opts) {
@@ -0,0 +1,201 @@
1
+ import { ApiItemKind } from "@microsoft/api-extractor-model";
2
+
3
+ //#region src/TypeReferenceExtractor.ts
4
+ /**
5
+ * Extracts type references from API Extractor models to generate import statements.
6
+ *
7
+ * This class analyzes API items and their excerpt tokens to identify external type
8
+ * references that need to be imported in the generated TypeScript declaration files.
9
+ *
10
+ * **How it works:**
11
+ * 1. Walks through all API items (classes, interfaces, functions, etc.)
12
+ * 2. Extracts type references from excerpt tokens
13
+ * 3. Filters out built-in types and internal references
14
+ * 4. Groups external references by package
15
+ * 5. Generates `import type` statements
16
+ *
17
+ * **Reference Types:**
18
+ * - **Built-in:** TypeScript types like `Promise`, `Record`, `NonNullable` (skipped)
19
+ * - **Internal:** References to types in the same package (skipped)
20
+ * - **External:** References to types from npm packages (imported)
21
+ *
22
+ * **Canonical Reference Format:**
23
+ * API Extractor uses canonical references like:
24
+ * - `"zod!ZodType:interface"` → External reference to `zod` package
25
+ * - `"mypackage!MyType:type"` → Internal reference (same package)
26
+ * - `"!Promise:interface"` → Built-in TypeScript type
27
+ * - `"!\"node:buffer\".__global.Buffer:interface"` → Node.js built-in (treated as built-in)
28
+ *
29
+ * @example
30
+ * ```ts
31
+ * const extractor = new TypeReferenceExtractor(apiPackage, "my-package");
32
+ * const imports = extractor.extractImports();
33
+ *
34
+ * for (const stmt of imports) {
35
+ * console.log(`import type { ${[...stmt.symbols].join(", ")} } from "${stmt.packageName}";`);
36
+ * }
37
+ * // Output:
38
+ * // import type { ZodType } from "zod";
39
+ * // import type { Effect } from "@effect/schema";
40
+ * ```
41
+ *
42
+ * @public
43
+ */
44
+ var TypeReferenceExtractor = class {
45
+ apiPackage;
46
+ currentPackageName;
47
+ /**
48
+ * All type references found in the API package
49
+ */
50
+ references = /* @__PURE__ */ new Map();
51
+ constructor(apiPackage, currentPackageName) {
52
+ this.apiPackage = apiPackage;
53
+ this.currentPackageName = currentPackageName;
54
+ }
55
+ /**
56
+ * Extract all type references from the API package and generate import statements.
57
+ * Returns an array of import statements grouped by package.
58
+ */
59
+ extractImports() {
60
+ this.walkApiPackage();
61
+ return this.generateImportStatements();
62
+ }
63
+ /**
64
+ * Extract type references for a specific entry point only.
65
+ * This enables per-entry-point import optimization for multi-entry packages.
66
+ *
67
+ * @param entryPoint - The specific entry point to extract imports for
68
+ * @returns Import statements containing only types used in this entry point
69
+ */
70
+ extractImportsForEntryPoint(entryPoint) {
71
+ this.references.clear();
72
+ for (const member of entryPoint.members) this.walkApiItem(member);
73
+ return this.generateImportStatements();
74
+ }
75
+ /**
76
+ * Extract type references for a single API item.
77
+ * This enables generating imports for individual signatures.
78
+ *
79
+ * @param apiItem - The specific API item to extract imports for
80
+ * @returns Import statements containing only types used in this item
81
+ */
82
+ extractImportsForApiItem(apiItem) {
83
+ this.references.clear();
84
+ this.walkApiItem(apiItem);
85
+ return this.generateImportStatements();
86
+ }
87
+ /**
88
+ * Generate import statements from collected references.
89
+ * Used by both extractImports() and extractImportsForEntryPoint().
90
+ */
91
+ generateImportStatements() {
92
+ const packageMap = /* @__PURE__ */ new Map();
93
+ for (const ref of this.references.values()) {
94
+ if (ref.isBuiltIn || ref.isInternal) continue;
95
+ if (!packageMap.has(ref.packageName)) packageMap.set(ref.packageName, /* @__PURE__ */ new Set());
96
+ packageMap.get(ref.packageName)?.add(ref.symbolName);
97
+ }
98
+ const imports = [];
99
+ for (const [packageName, symbols] of packageMap.entries()) imports.push({
100
+ packageName,
101
+ symbols,
102
+ typeOnly: true
103
+ });
104
+ imports.sort((a, b) => a.packageName.localeCompare(b.packageName));
105
+ return imports;
106
+ }
107
+ /**
108
+ * Generate import statement strings from ImportStatement objects.
109
+ * Returns an array of formatted import statements.
110
+ */
111
+ static formatImports(imports) {
112
+ const statements = [];
113
+ for (const stmt of imports) {
114
+ const sortedSymbols = Array.from(stmt.symbols).sort();
115
+ const statement = `${stmt.typeOnly ? "import type" : "import"} { ${sortedSymbols.join(", ")} } from "${stmt.packageName}";`;
116
+ statements.push(statement);
117
+ }
118
+ return statements;
119
+ }
120
+ /**
121
+ * Walk through the entire API package and extract all type references
122
+ */
123
+ walkApiPackage() {
124
+ for (const entryPoint of this.apiPackage.entryPoints) for (const member of entryPoint.members) this.walkApiItem(member);
125
+ }
126
+ /**
127
+ * Recursively walk through an API item and its children to extract type references
128
+ */
129
+ walkApiItem(apiItem) {
130
+ this.extractFromExcerpt(apiItem);
131
+ if ("members" in apiItem) {
132
+ const members = apiItem.members;
133
+ if (Array.isArray(members)) for (const member of members) this.walkApiItem(member);
134
+ }
135
+ }
136
+ /**
137
+ * Extract type references from an API item using its excerpt
138
+ */
139
+ extractFromExcerpt(apiItem) {
140
+ const excerpt = this.getExcerpt(apiItem);
141
+ if (!excerpt) return;
142
+ this.extractFromExcerptTokens(excerpt);
143
+ }
144
+ /**
145
+ * Get the appropriate excerpt from an API item based on its kind
146
+ */
147
+ getExcerpt(apiItem) {
148
+ const item = apiItem;
149
+ if (item.excerpt) return item.excerpt;
150
+ if (apiItem.kind === ApiItemKind.TypeAlias && item.typeExcerpt) return item.typeExcerpt;
151
+ if ((apiItem.kind === ApiItemKind.Property || apiItem.kind === ApiItemKind.PropertySignature) && item.propertyTypeExcerpt) return item.propertyTypeExcerpt;
152
+ if (item.returnTypeExcerpt) return item.returnTypeExcerpt;
153
+ return null;
154
+ }
155
+ /**
156
+ * Extract type references from excerpt tokens
157
+ */
158
+ extractFromExcerptTokens(excerpt) {
159
+ if (!excerpt.spannedTokens || excerpt.spannedTokens.length === 0) return;
160
+ for (const token of excerpt.spannedTokens) {
161
+ if (token.kind !== "Reference") continue;
162
+ const canonicalRef = token.canonicalReference?.toString();
163
+ if (!canonicalRef || typeof canonicalRef !== "string") continue;
164
+ const ref = this.parseCanonicalReference(canonicalRef, token.text);
165
+ if (ref) this.references.set(ref.canonicalReference, ref);
166
+ }
167
+ }
168
+ /**
169
+ * Parse a canonical reference string to extract type reference information.
170
+ *
171
+ * Canonical reference format: "packageName!symbolName:kind"
172
+ * Examples:
173
+ * - "zod!ZodType:interface" → External reference
174
+ * - "mypackage!MyType:type" → Internal reference
175
+ * - "!Promise:interface" → Built-in type
176
+ * - "!\"node:buffer\".__global.Buffer:interface" → Node.js built-in
177
+ */
178
+ parseCanonicalReference(canonicalRef, symbolText) {
179
+ const exclamationIndex = canonicalRef.indexOf("!");
180
+ if (exclamationIndex === -1) return null;
181
+ const packagePart = canonicalRef.substring(0, exclamationIndex);
182
+ const rest = canonicalRef.substring(exclamationIndex + 1);
183
+ const colonIndex = rest.indexOf(":");
184
+ const symbolFromCanonical = colonIndex !== -1 ? rest.substring(0, colonIndex) : rest;
185
+ const isBuiltIn = packagePart === "" || packagePart.startsWith("\"");
186
+ const isInternal = packagePart === this.currentPackageName;
187
+ let symbolName;
188
+ if (symbolText.includes(".")) symbolName = symbolText.split(".")[0].trim();
189
+ else symbolName = symbolFromCanonical.trim();
190
+ return {
191
+ symbolName,
192
+ packageName: packagePart,
193
+ canonicalReference: canonicalRef,
194
+ isBuiltIn,
195
+ isInternal
196
+ };
197
+ }
198
+ };
199
+
200
+ //#endregion
201
+ export { TypeReferenceExtractor };
package/index.d.ts CHANGED
@@ -1,7 +1,106 @@
1
- import { ApiClass, ApiInterface, ApiItem, ApiModel, ApiNamespace, ApiPackage, Excerpt } from "@microsoft/api-extractor-model";
1
+ import { ApiClass, ApiEntryPoint, ApiInterface, ApiItem, ApiModel, ApiNamespace, ApiPackage, Excerpt } from "@microsoft/api-extractor-model";
2
+ import { VirtualPackage } from "@tsdoctor/vfs";
2
3
  import { Effect, Schema } from "effect";
3
4
  import { FlowContent, MarkdownNode } from "@effected/markdown";
4
5
  import { DocNode } from "@microsoft/tsdoc";
6
+ //#endregion
7
+ //#region src/ApiExtractedPackage.d.ts
8
+ /**
9
+ * Reconstructs TypeScript declaration files from an API Extractor model.
10
+ *
11
+ * Extends `VirtualPackage` with the ability to generate high-fidelity
12
+ * `.d.ts` output from API Extractor's `ApiPackage` — including enum values,
13
+ * full JSDoc, namespace members, and all interface member kinds.
14
+ *
15
+ * Use the factory methods `fromApiModel` or `fromPackage` to create instances.
16
+ *
17
+ * @public
18
+ */
19
+ declare class ApiExtractedPackage extends VirtualPackage {
20
+ readonly apiPackage: ApiPackage;
21
+ private constructor();
22
+ /**
23
+ * Create an ApiExtractedPackage from an API model JSON file path.
24
+ */
25
+ static fromApiModel(modelPath: string): ApiExtractedPackage;
26
+ /**
27
+ * Create an ApiExtractedPackage from an existing ApiPackage instance.
28
+ */
29
+ static fromPackage(apiPackage: ApiPackage, packageName: string): ApiExtractedPackage;
30
+ /**
31
+ * Generate the .d.ts content for a specific entry point.
32
+ */
33
+ generateDeclarations(entryPoint?: ApiEntryPoint): string;
34
+ /**
35
+ * Generate a TypeScript declaration for a single API item.
36
+ */
37
+ private generateDeclaration;
38
+ private generateClassDeclaration;
39
+ private generateInterfaceDeclaration;
40
+ private generateTypeAliasDeclaration;
41
+ private generateFunctionDeclaration;
42
+ private generateEnumDeclaration;
43
+ private generateVariableDeclaration;
44
+ private generateNamespaceDeclaration;
45
+ private generateNamespaceMember;
46
+ private generateNamespaceFunction;
47
+ private generateNamespaceInterface;
48
+ private generateNamespaceEnum;
49
+ private generateNamespaceTypeAlias;
50
+ private generateNamespaceVariable;
51
+ private generateNamespaceClass;
52
+ private generateClassMember;
53
+ private generateInterfaceMember;
54
+ private generateMemberFromExcerpt;
55
+ /**
56
+ * Render an excerpt to source text, normalizing dts-rollup disambiguation
57
+ * aliases. The dts rollup renames a re-imported symbol as `Name$1`, but its
58
+ * canonical reference is the un-suffixed `Name` (the same symbol). The import
59
+ * prepender ({@link TypeReferenceExtractor}) imports the canonical name, so
60
+ * emitting the suffixed text would leave `Name$1` undefined (TS2304). Emit the
61
+ * canonical name so the body and the prepended import agree.
62
+ *
63
+ * Equivalent to `excerpt.text` for excerpts without rollup aliases (the text
64
+ * is the concatenation of the spanned tokens), so unaliased output is unchanged.
65
+ */
66
+ private renderExcerpt;
67
+ /**
68
+ * Strip a dts-rollup `$N` suffix from a reference token when the de-suffixed
69
+ * text matches the token's canonical symbol. Never touches a non-reference
70
+ * token or a legitimate identifier that genuinely ends in `$N` (its canonical
71
+ * name would carry the suffix too).
72
+ */
73
+ private normalizeTokenText;
74
+ /**
75
+ * Clean an excerpt text: strip export/declare keywords and trailing semicolons/whitespace.
76
+ */
77
+ private cleanExcerpt;
78
+ private formatTypeParameters;
79
+ private extractPackageDocumentation;
80
+ /**
81
+ * Format JSDoc comment from an API item's TSDoc.
82
+ * Produces output matching the TypeScript compiler's JSDoc style.
83
+ */
84
+ private formatJSDoc;
85
+ /**
86
+ * Recursively extract plain text from a TSDoc DocNode tree.
87
+ *
88
+ * @remarks
89
+ * NOT interchangeable with this package's `Tsdoc` prose extraction, despite
90
+ * the overlapping name and shape. This one **preserves** `{@link X.Y}` TSDoc
91
+ * syntax and reconstructs fenced code blocks, because its output is a
92
+ * `.d.ts` file whose JSDoc must survive round-tripping into a virtual
93
+ * TypeScript environment. `Tsdoc`'s flattens `{@link}` to its display text
94
+ * and drops code fences, because its output is rendered prose.
95
+ *
96
+ * They looked like duplicates from two packages away and now sit in one, so
97
+ * this is the note that should stop the merge: collapsing them would either
98
+ * put display text where a declaration reference belongs, or leak link
99
+ * syntax into rendered documentation.
100
+ */
101
+ private extractPlainText;
102
+ private getEntryPointName;
103
+ }
5
104
  declare namespace EntryPoints_d_exports {
6
105
  export { ResolvedEntryItem, entryPointName, resolve };
7
106
  }
@@ -182,6 +281,8 @@ interface ApiItemRef {
182
281
  /**
183
282
  * Metadata handed to the injected frontmatter renderer for one doc.
184
283
  *
284
+ * @deprecated Exists only for `Render.docs`; use the `Page` facts from
285
+ * `@tsdoctor/pages` (`buildPage`) instead.
185
286
  * @public
186
287
  */
187
288
  interface DocMeta extends ApiItemRef {
@@ -197,12 +298,16 @@ type RouteFormatter = (ref: ApiItemRef) => string;
197
298
  /**
198
299
  * Injected: produce the frontmatter block (incl. trailing blank line) for a doc, or "".
199
300
  *
301
+ * @deprecated Exists only for `Render.docs`; adapters assemble frontmatter
302
+ * from a `@tsdoctor/pages` `Page` (see `emitFrontmatterBlock`).
200
303
  * @public
201
304
  */
202
305
  type FrontmatterRenderer = (meta: DocMeta) => string;
203
306
  /**
204
307
  * One rendered API doc = its metadata plus the assembled markdown (frontmatter + body).
205
308
  *
309
+ * @deprecated Exists only for `Render.docs`; use `buildPage` +
310
+ * `renderMarkdown` from `@tsdoctor/pages`.
206
311
  * @public
207
312
  */
208
313
  interface RenderedDoc extends DocMeta {
@@ -212,6 +317,8 @@ interface RenderedDoc extends DocMeta {
212
317
  * Options for `Render.docs`: the package name plus the optional injected
213
318
  * route, frontmatter, and filter services.
214
319
  *
320
+ * @deprecated Exists only for `Render.docs`; use `BuildPageInput` from
321
+ * `@tsdoctor/pages`.
215
322
  * @public
216
323
  */
217
324
  interface RenderPackageOptions {
@@ -265,6 +372,109 @@ declare class CrossLinker {
265
372
  */
266
373
  linkHtml(text: string): string;
267
374
  }
375
+ //#endregion
376
+ //#region src/Frontmatter.d.ts
377
+ /**
378
+ * A parsed frontmatter document: the decoded frontmatter data and the body
379
+ * content that followed the closing delimiter.
380
+ *
381
+ * @public
382
+ */
383
+ interface ParsedFrontmatter {
384
+ /** Decoded frontmatter data (`{}` when there is no frontmatter block). */
385
+ readonly data: Record<string, unknown>;
386
+ /** Body content after the closing delimiter (whole input when no block). */
387
+ readonly content: string;
388
+ }
389
+ /**
390
+ * Split markdown source into frontmatter data and body content, preserving
391
+ * gray-matter's exact boundary semantics.
392
+ *
393
+ * @remarks
394
+ * This is a byte-for-byte port of the `gray-matter` split contract the
395
+ * snapshot system's hashes depend on (see `@tsdoctor/snapshot`
396
+ * `hashContent`/`hashFrontmatter` and the disk-fallback comparison in
397
+ * `build-stages.ts`), with `@effected/yaml` (`Yaml.parse`, YAML 1.2) as the
398
+ * YAML engine instead of js-yaml:
399
+ *
400
+ * - No opening `---` line at offset 0 → `data: {}` and the whole input as
401
+ * `content` (a leading BOM is stripped first, as gray-matter does).
402
+ * - The closing delimiter is the first `\n---` after the opening line
403
+ * (gray-matter uses a plain `indexOf`, so `\n----` also closes and the
404
+ * leftover `-` stays in the body — preserved deliberately).
405
+ * - Exactly one newline (`\n` or `\r\n`) immediately after the closing `---`
406
+ * is consumed; everything else is the body verbatim. A build's generated
407
+ * page (`---\n…\n---\n\n# Title`) therefore yields a body starting with a
408
+ * single `\n`, exactly as gray-matter returned it.
409
+ * - A block with no closing delimiter is all frontmatter and yields an empty
410
+ * body; an empty/blank block yields `data: {}`.
411
+ * - Invalid YAML throws (a defect), matching gray-matter's js-yaml throw.
412
+ *
413
+ * One deliberate delta: gray-matter treats text on the opening line
414
+ * (`---toml`) as an engine name and throws for unregistered engines; this
415
+ * split treats such input as "no frontmatter" instead. The plugin never emits
416
+ * or consumes language-tagged frontmatter.
417
+ *
418
+ * `@effected/markdown`'s `FrontmatterSource.split` was evaluated for this
419
+ * path and deliberately NOT adopted: its grammar is strict by design (a
420
+ * fence line is exactly `---`, an unterminated block is not frontmatter),
421
+ * while this contract pins gray-matter's `indexOf`-based quirks (`\n----`
422
+ * closes, trailing-space close lines close, a missing close means
423
+ * all-frontmatter). The emission half (`stringifyFrontmatter` /
424
+ * `emitFrontmatterBlock`) does use `FrontmatterSource.join`.
425
+ *
426
+ * Representation parity with js-yaml is verified by characterization tests
427
+ * (`__test__/frontmatter.test.ts`) pinning hashes captured under gray-matter.
428
+ * The one input where the engines disagree — an *unquoted* ISO timestamp
429
+ * (js-yaml: `Date`, YAML 1.2: string) — is unreachable from this plugin's
430
+ * emitters, which always quote timestamp values, and hashes identically
431
+ * anyway because `hashFrontmatter` JSON-serializes (a `Date` serializes to
432
+ * the same ISO string).
433
+ *
434
+ * @param source - The markdown source, with or without a frontmatter block
435
+ * @returns The decoded frontmatter data and the body content
436
+ *
437
+ * @public
438
+ */
439
+ declare function parseFrontmatter(source: string): ParsedFrontmatter;
440
+ /**
441
+ * Serialize frontmatter data and body content back into a markdown document,
442
+ * preserving gray-matter's `matter.stringify` contract.
443
+ *
444
+ * @remarks
445
+ * Emits `---\n<yaml>---\n<content>` with the body's trailing newline ensured,
446
+ * and returns the body unchanged (no fences) when `data` has no keys — both
447
+ * gray-matter behaviors the write path relied on. The YAML is emitted by
448
+ * `@effected/yaml` with every string value double-quoted (see
449
+ * `STRINGIFY_OPTIONS` for why); byte output differs from js-yaml's dump, but
450
+ * the decoded representation is identical, which is the invariant the
451
+ * snapshot hashes depend on. Unchanged pages are never rewritten, so the byte
452
+ * difference only ever lands in files that were being rewritten anyway.
453
+ *
454
+ * @param content - The body content
455
+ * @param data - The frontmatter data to serialize
456
+ * @returns The combined markdown document
457
+ *
458
+ * @public
459
+ */
460
+ declare function stringifyFrontmatter(content: string, data: Record<string, unknown>): string;
461
+ /**
462
+ * Serialize a data object to a YAML frontmatter block (fences included, plus
463
+ * the trailing blank line the page generators emit before the body).
464
+ *
465
+ * @remarks
466
+ * Used by `generateFrontmatter` (`markdown/helpers.ts`) as the emission half
467
+ * of the page generators' frontmatter. Every string value is double-quoted
468
+ * (see `STRINGIFY_OPTIONS`), so values that a YAML 1.1 consumer would
469
+ * otherwise coerce (timestamps, `yes`/`no`, numeric-looking strings) stay
470
+ * strings for RSPress's js-yaml parse.
471
+ *
472
+ * @param data - The frontmatter data to serialize
473
+ * @returns A `---`-fenced YAML block ending with a blank line
474
+ *
475
+ * @public
476
+ */
477
+ declare function emitFrontmatterBlock(data: Record<string, unknown>): string;
268
478
  declare namespace Model_d_exports {
269
479
  export { EmptyModelError, ModelNotFoundError, ModelParseError, firstPackage, load };
270
480
  }
@@ -327,6 +537,9 @@ declare namespace Render_d_exports {
327
537
  * `ApiExportedMixin`. Every other item, including any lacking the flag, is
328
538
  * kept.
329
539
  *
540
+ * @deprecated Use `prepareWorkItems` from `@tsdoctor/pages`, which decides
541
+ * which items receive a page (`isPageKind` for the kind, `SyntheticBases.detect`
542
+ * for the hoisted `*_base` declarations this rule was written to drop).
330
543
  * @public
331
544
  */
332
545
  declare const isEmittable: (item: ApiItem) => boolean;
@@ -334,6 +547,8 @@ declare const isEmittable: (item: ApiItem) => boolean;
334
547
  * Options for {@link item} and {@link tree}: the package name used in
335
548
  * fallbacks and an optional crosslinker applied to the rendered prose.
336
549
  *
550
+ * @deprecated Use `BuildPageInput` from `@tsdoctor/pages`, which carries the
551
+ * per-API `CrossLinker` as `linker`.
337
552
  * @public
338
553
  */
339
554
  interface RenderItemOptions {
@@ -345,12 +560,15 @@ interface RenderItemOptions {
345
560
  * Render one API item's markdown body as flow nodes — the pre-serialization
346
561
  * form of {@link item}.
347
562
  *
563
+ * @deprecated Use `buildPage` + `markdownTree` from `@tsdoctor/pages`, which
564
+ * yields the same `FlowContent` nodes from a typed `Page`.
348
565
  * @alpha
349
566
  */
350
567
  declare function tree(apiItem: ApiItem, opts: RenderItemOptions): ReadonlyArray<FlowContent>;
351
568
  /**
352
569
  * Render one API item to a markdown body string (no frontmatter).
353
570
  *
571
+ * @deprecated Use `buildPage` + `renderMarkdown` from `@tsdoctor/pages`.
354
572
  * @public
355
573
  */
356
574
  declare function item(apiItem: ApiItem, opts: RenderItemOptions): string;
@@ -358,6 +576,9 @@ declare function item(apiItem: ApiItem, opts: RenderItemOptions): string;
358
576
  * Walk a package's first entry point and assemble one RenderedDoc per
359
577
  * top-level member.
360
578
  *
579
+ * @deprecated Use `prepareWorkItems` + `buildPage` + `renderMarkdown` from
580
+ * `@tsdoctor/pages`; frontmatter is assembled by the adapter from the
581
+ * `Page`'s facts and head tags.
361
582
  * @public
362
583
  */
363
584
  declare function docs(apiPackage: ApiPackage, opts: RenderPackageOptions): RenderedDoc[];
@@ -724,5 +945,167 @@ declare function seeReferences(item: ApiItem): ReadonlyArray<{
724
945
  readonly text: string;
725
946
  }>;
726
947
  //#endregion
727
- export { type ApiItemRef, ApiItems_d_exports as ApiItems, CrossLinker, type DocMeta, EntryPoints_d_exports as EntryPoints, type FrontmatterRenderer, type ItemKindSlug, Model_d_exports as Model, Render_d_exports as Render, type RenderPackageOptions, type RenderedDoc, type RouteFormatter, Routes_d_exports as Routes, Signature_d_exports as Signature, SyntheticBases_d_exports as SyntheticBases, Tsdoc_d_exports as Tsdoc };
948
+ //#region src/TypeReferenceExtractor.d.ts
949
+ /**
950
+ * Represents a type reference extracted from an API item.
951
+ * Contains information about where the type comes from and how to import it.
952
+ *
953
+ * @public
954
+ */
955
+ interface TypeReference {
956
+ /**
957
+ * The symbol name to import (e.g., "ZodType", "Effect")
958
+ */
959
+ symbolName: string;
960
+ /**
961
+ * The package name (e.g., "zod", "\@effect/schema").
962
+ * Empty string for built-in TypeScript types.
963
+ */
964
+ packageName: string;
965
+ /**
966
+ * The canonical reference from API Extractor
967
+ * Format: "packageName!symbolName:kind"
968
+ */
969
+ canonicalReference: string;
970
+ /**
971
+ * Whether this is a built-in TypeScript type (Promise, Record, etc.)
972
+ */
973
+ isBuiltIn: boolean;
974
+ /**
975
+ * Whether this reference is from the current package being documented
976
+ */
977
+ isInternal: boolean;
978
+ }
979
+ /**
980
+ * Import statement to be generated for a package
981
+ *
982
+ * @public
983
+ */
984
+ interface ImportStatement {
985
+ /**
986
+ * Package name to import from
987
+ */
988
+ packageName: string;
989
+ /**
990
+ * Named imports from this package
991
+ */
992
+ symbols: Set<string>;
993
+ /**
994
+ * Whether to use type-only import
995
+ */
996
+ typeOnly: boolean;
997
+ }
998
+ /**
999
+ * Extracts type references from API Extractor models to generate import statements.
1000
+ *
1001
+ * This class analyzes API items and their excerpt tokens to identify external type
1002
+ * references that need to be imported in the generated TypeScript declaration files.
1003
+ *
1004
+ * **How it works:**
1005
+ * 1. Walks through all API items (classes, interfaces, functions, etc.)
1006
+ * 2. Extracts type references from excerpt tokens
1007
+ * 3. Filters out built-in types and internal references
1008
+ * 4. Groups external references by package
1009
+ * 5. Generates `import type` statements
1010
+ *
1011
+ * **Reference Types:**
1012
+ * - **Built-in:** TypeScript types like `Promise`, `Record`, `NonNullable` (skipped)
1013
+ * - **Internal:** References to types in the same package (skipped)
1014
+ * - **External:** References to types from npm packages (imported)
1015
+ *
1016
+ * **Canonical Reference Format:**
1017
+ * API Extractor uses canonical references like:
1018
+ * - `"zod!ZodType:interface"` → External reference to `zod` package
1019
+ * - `"mypackage!MyType:type"` → Internal reference (same package)
1020
+ * - `"!Promise:interface"` → Built-in TypeScript type
1021
+ * - `"!\"node:buffer\".__global.Buffer:interface"` → Node.js built-in (treated as built-in)
1022
+ *
1023
+ * @example
1024
+ * ```ts
1025
+ * const extractor = new TypeReferenceExtractor(apiPackage, "my-package");
1026
+ * const imports = extractor.extractImports();
1027
+ *
1028
+ * for (const stmt of imports) {
1029
+ * console.log(`import type { ${[...stmt.symbols].join(", ")} } from "${stmt.packageName}";`);
1030
+ * }
1031
+ * // Output:
1032
+ * // import type { ZodType } from "zod";
1033
+ * // import type { Effect } from "@effect/schema";
1034
+ * ```
1035
+ *
1036
+ * @public
1037
+ */
1038
+ declare class TypeReferenceExtractor {
1039
+ private readonly apiPackage;
1040
+ private readonly currentPackageName;
1041
+ /**
1042
+ * All type references found in the API package
1043
+ */
1044
+ private readonly references;
1045
+ constructor(apiPackage: ApiPackage, currentPackageName: string);
1046
+ /**
1047
+ * Extract all type references from the API package and generate import statements.
1048
+ * Returns an array of import statements grouped by package.
1049
+ */
1050
+ extractImports(): ImportStatement[];
1051
+ /**
1052
+ * Extract type references for a specific entry point only.
1053
+ * This enables per-entry-point import optimization for multi-entry packages.
1054
+ *
1055
+ * @param entryPoint - The specific entry point to extract imports for
1056
+ * @returns Import statements containing only types used in this entry point
1057
+ */
1058
+ extractImportsForEntryPoint(entryPoint: ApiEntryPoint): ImportStatement[];
1059
+ /**
1060
+ * Extract type references for a single API item.
1061
+ * This enables generating imports for individual signatures.
1062
+ *
1063
+ * @param apiItem - The specific API item to extract imports for
1064
+ * @returns Import statements containing only types used in this item
1065
+ */
1066
+ extractImportsForApiItem(apiItem: ApiItem): ImportStatement[];
1067
+ /**
1068
+ * Generate import statements from collected references.
1069
+ * Used by both extractImports() and extractImportsForEntryPoint().
1070
+ */
1071
+ private generateImportStatements;
1072
+ /**
1073
+ * Generate import statement strings from ImportStatement objects.
1074
+ * Returns an array of formatted import statements.
1075
+ */
1076
+ static formatImports(imports: ImportStatement[]): string[];
1077
+ /**
1078
+ * Walk through the entire API package and extract all type references
1079
+ */
1080
+ private walkApiPackage;
1081
+ /**
1082
+ * Recursively walk through an API item and its children to extract type references
1083
+ */
1084
+ private walkApiItem;
1085
+ /**
1086
+ * Extract type references from an API item using its excerpt
1087
+ */
1088
+ private extractFromExcerpt;
1089
+ /**
1090
+ * Get the appropriate excerpt from an API item based on its kind
1091
+ */
1092
+ private getExcerpt;
1093
+ /**
1094
+ * Extract type references from excerpt tokens
1095
+ */
1096
+ private extractFromExcerptTokens;
1097
+ /**
1098
+ * Parse a canonical reference string to extract type reference information.
1099
+ *
1100
+ * Canonical reference format: "packageName!symbolName:kind"
1101
+ * Examples:
1102
+ * - "zod!ZodType:interface" → External reference
1103
+ * - "mypackage!MyType:type" → Internal reference
1104
+ * - "!Promise:interface" → Built-in type
1105
+ * - "!\"node:buffer\".__global.Buffer:interface" → Node.js built-in
1106
+ */
1107
+ private parseCanonicalReference;
1108
+ }
1109
+ //#endregion
1110
+ export { ApiExtractedPackage, type ApiItemRef, ApiItems_d_exports as ApiItems, CrossLinker, type DocMeta, EntryPoints_d_exports as EntryPoints, type FrontmatterRenderer, type ImportStatement, type ItemKindSlug, Model_d_exports as Model, type ParsedFrontmatter, Render_d_exports as Render, type RenderPackageOptions, type RenderedDoc, type RouteFormatter, Routes_d_exports as Routes, Signature_d_exports as Signature, SyntheticBases_d_exports as SyntheticBases, Tsdoc_d_exports as Tsdoc, type TypeReference, TypeReferenceExtractor, emitFrontmatterBlock, parseFrontmatter, stringifyFrontmatter };
728
1111
  //# sourceMappingURL=index.d.ts.map