declaration-helpers.ts

Utility functions for working with declaration and member types.

Display formatting, code generation, serialization, type narrowing, and TypeJson tokenization for DeclarationJson and MemberJson.

@see types.ts for DeclarationJson, MemberJson, TypeJson Zod schemas

view source

Declarations
#

7 declarations

compactReplacer
#

declaration-helpers.ts view source

also exported from index.ts

(key: string, value: unknown): unknown import {compactReplacer} from 'svelte-docinfo/declaration-helpers.js';

JSON replacer that strips Zod default values for compact serialization.

Strips empty arrays and false booleans — both are Zod .default() values restored on .parse(), so the round-trip is lossless for svelte-docinfo types. Assumes all boolean fields in the schema default to false — a true-defaulted boolean would need its false values preserved, breaking the round-trip.

One keyed exemption: value is never stripped. TypeJson's literal nodes carry data there ({kind: 'literal', value: false} is the literal type false, required by the schema), not a defaulted flag — no other output field is named value, and any future one must not be a false-defaulted boolean.

Root-value caveat: JSON.stringify([], compactReplacer) returns the JS undefined (not the string '[]'), and JSON.stringify(false, compactReplacer) returns the JS undefined too. Object-rooted callers (AnalyzeResultJson envelope, CLI output) don't hit this — empty inner arrays strip and AnalyzeResultJson.parse restores them on the consumer side. Array-rooted callers (Vite plugin, anyone splicing the JSON into a source template) must handle the empty case themselves before calling this; see vite.ts:updateOutputFromQuery for the pattern.

Two guard tests in declaration-helpers.test.ts lock this in:

  • every z.boolean().default in types.ts uses false — source-regex check that fails on a new z.boolean().default(true).
  • `parse → stringify(compactReplacer) → parse is a faithful round-trip across every variant` — exercises every variant and member through a full round-trip, catching regressions where a .default(false) or .default([]) is removed (or a new field is added that the replacer drops but Zod doesn't restore).

key

type string

value

type unknown

returns

unknown

examples

const result = await analyze({sourceFiles, sourceOptions}); const json = JSON.stringify(result, compactReplacer); // On the consumer side, restore Zod defaults: const restored = AnalyzeResultJson.parse(JSON.parse(json));

generateImport
#

declaration-helpers.ts view source

also exported from index.ts

(declaration: { kind: "function"; parameters: { name: string; type: string; optional: boolean; rest: boolean; typeInfo?: TypeJson | undefined; description?: string | undefined; defaultValue?: string | undefined; propertyDescriptions?: Record<...> | undefined; }[]; ... 19 more ...; sourceLine?: number | undefined; } | ... 7 more ... | { ...; }, modulePath: string, libraryName: string): string import {generateImport} from 'svelte-docinfo/declaration-helpers.js';

Generate TypeScript import statement for a declaration.

Produces import type for type/interface declarations, import for values — including type/interface declarations marked mergedValue (a merged value+type symbol like a schema/type pair is importable as a runtime value, so a type-only import would break value use).

Default export handling: when declaration.name === 'default', emits import X from '...' with the binding derived by PascalCasing the module path. ('default' is the symbol's actual name in JS — import X from 'mod' is sugar for import {default as X} from 'mod'.)

declaration

the DeclarationJson to generate an import for

type { kind: "function"; parameters: { name: string; type: string; optional: boolean; rest: boolean; typeInfo?: TypeJson | undefined; description?: string | undefined; defaultValue?: string | undefined; propertyDescriptions?: Record<...> | undefined; }[]; ... 19 more ...; sourceLine?: number | undefined; } | ... 7 more ....

modulePath

module path relative to source root (e.g., foo.ts)

type string

libraryName

package name for the import specifier (e.g., @pkg/lib)

type string

returns

string

formatted import statement string

examples

generateImport({name: 'Foo', kind: 'type'}, 'foo.ts', '@pkg/lib') // => "import type {Foo} from '@pkg/lib/foo.js';" generateImport({name: 'default', kind: 'function'}, 'foo-bar.ts', '@pkg/lib') // => "import FooBar from '@pkg/lib/foo-bar.js';"

see also

  • ``getDisplayName`` for the divergent default-slot fallback used as a display label (the literal 'default', since a label has no use for a synthesized JS binding).

getDisplayName
#

declaration-helpers.ts view source

also exported from index.ts

(declaration: { kind: "function"; name: string; optional: boolean; parameters: { name: string; type: string; optional: boolean; rest: boolean; typeInfo?: TypeJson | undefined; description?: string | undefined; defaultValue?: string | undefined; propertyDescriptions?: Record<...> | undefined; }[]; ... 17 more ...; sourceLine?: number | undefined; } | ... 10 more ... | { ...; }): string import {getDisplayName} from 'svelte-docinfo/declaration-helpers.js';

Format declaration or member name with generic parameters for display.

Default-slot entries return the literal 'default' (the symbol's actual name in JS). Renderers that want a richer label (PascalCased module path, an explicit "default export" header) should branch on name === 'default' themselves before calling this.

declaration

the DeclarationJson or MemberJson to format

type { kind: "function"; name: string; optional: boolean; parameters: { name: string; type: string; optional: boolean; rest: boolean; typeInfo?: TypeJson | undefined; description?: string | undefined; defaultValue?: string | undefined; propertyDescriptions?: Record<...> | undefined; }[]; ... 17 more ...; sourceLine?: num...

returns

string

name with generic parameters appended (e.g., Map<K, V>)

examples

getDisplayName({name: 'Map', kind: 'type', genericParams: [{name: 'K'}, {name: 'V'}]}) // => 'Map<K, V>'

see also

  • ``generateImport`` for the divergent default-slot fallback used in import-statement generation (PascalCased module path, since an import needs a JS identifier binding, not a label).

isKind
#

declaration-helpers.ts view source

also exported from index.ts

<K extends DeclarationKind | MemberKind>(declaration: { kind: "function"; name: string; optional: boolean; parameters: { name: string; type: string; optional: boolean; rest: boolean; typeInfo?: TypeJson | undefined; description?: string | undefined; defaultValue?: string | undefined; propertyDescriptions?: Record<...> | undefined; }[]; ... 17 more ...; sourceLine?: number | undefined; } | ... 10 more ... | { ...; }, kind: K): declaration is Extract<...> | ... 10 more ... | Extract<...> import {isKind} from 'svelte-docinfo/declaration-helpers.js';

Narrow a declaration by kind for type-safe field access.

Works with both DeclarationJson (top-level) and MemberJson (nested). Accepts DeclarationKind | MemberKind so isKind(member, 'constructor') compiles.

declaration

type { kind: "function"; name: string; optional: boolean; parameters: { name: string; type: string; optional: boolean; rest: boolean; typeInfo?: TypeJson | undefined; description?: string | undefined; defaultValue?: string | undefined; propertyDescriptions?: Record<...> | undefined; }[]; ... 17 more ...; sourceLine?: num...

kind

type K

returns

boolean

generics

isKind<K extends DeclarationKind | MemberKind>
K
constraint DeclarationKind | MemberKind

examples

if (isKind(declaration, 'function')) { declaration.parameters; // FunctionDeclarationJson — has parameters declaration.returnType; // has returnType } if (isKind(member, 'constructor')) { member.parameters; // ConstructorMemberJson — has parameters }

TypeJsonToken
#

declaration-helpers.ts view source

also exported from index.ts

TypeJsonToken import type {TypeJsonToken} from 'svelte-docinfo/declaration-helpers.js';

One rendered piece of a TypeJson tree, produced by typeJsonToTokens: name tokens are candidate references for a renderer to link (or print plainly) — reference names, alias names of alias-carrying unions/intersections — code tokens are terminal type text (intrinsics, literals, anonymous objects/functions, depth-capped nodes) for a renderer to syntax-highlight, and text tokens are structural punctuation (<, | , [], tuple labels). A name token carries module when its reference node does (registry-recovered references — the declaring ModuleJson.path), so a renderer can scope the link; alias-name tokens never carry it.

typeJsonToText
#

declaration-helpers.ts view source

also exported from index.ts

(node: TypeJson): string import {typeJsonToText} from 'svelte-docinfo/declaration-helpers.js';

The plain-text printed form of a TypeJson tree — typeJsonToTokens concatenated. For consumers with no linkification or highlighting surface (CLI output, markdown code spans, log lines) and for test assertions.

node

returns

string

examples

typeJsonToText({kind: 'union', members: [ {kind: 'reference', name: 'Tome'}, {kind: 'intrinsic', text: 'null'} ]}) // => 'Tome | null'

typeJsonToTokens
#

declaration-helpers.ts view source

also exported from index.ts

(node: TypeJson): TypeJsonToken[] import {typeJsonToTokens} from 'svelte-docinfo/declaration-helpers.js';

Flatten a TypeJson tree into a render-ready token list.

The semantic linearization for renderers: spacing, separators, parenthesization (((x) => void) | null, (A | B)[]), and tuple labels ([a: string, b?: number, ...rest: boolean[]]) are decided here — in lockstep with the TypeJson schema's projection rules — so a renderer maps tokens to output without re-deriving type syntax. What a token *looks like* stays the consumer's decision: fuz_ui links name tokens to API docs and syntax-highlights code tokens; a CLI might print them all plainly. Adjacent punctuation merges into single text tokens.

node

the TypeJson tree to flatten (a typeInfo/returnTypeInfo field)

returns

TypeJsonToken[]

tokens in source order; concatenating their text yields the printed type

examples

typeJsonToTokens({kind: 'reference', name: 'Map', typeArgs: [ {kind: 'intrinsic', text: 'string'}, {kind: 'reference', name: 'Tome'} ]}) // => [{kind: 'name', name: 'Map'}, {kind: 'text', text: '<'}, // {kind: 'code', text: 'string'}, {kind: 'text', text: ', '}, // {kind: 'name', name: 'Tome'}, {kind: 'text', text: '>'}]

Depends on
#

Imported by
#