postprocess.ts

Post-processing for analyzed library metadata.

These functions transform analysis results after module-level analysis is complete:

  1. ValidationfindDuplicates checks flat namespace constraints
  2. TransformationmergeReExports resolves re-export relationships, computeDependents builds bidirectional dependency graphs
  3. OutputsortModules prepares deterministic output

Every function here is pure — transformation passes return new arrays with structural sharing (unchanged objects flow through ===-equal) and never mutate their input.

@see analyze.ts for the main analysis entry point

view source

Declarations
#

10 declarations

compareStrings
#

postprocess.ts view source

(a: string, b: string): number import {compareStrings} from 'svelte-docinfo/postprocess.js';

Case-insensitive string comparator for deterministic output ordering.

Case-folded comparison first (so Analyze and analyze sort together instead of all uppercase before all lowercase), then a code-unit tiebreak — so equal-ignoring-case strings still compare unequal and the result is an exact total order. Unlike localeCompare (host-locale/ICU-dependent, so byte-identical input can serialize in different orders on different machines), both passes use Unicode default mappings only and are environment-independent. All output ordering goes through this comparator — never bare localeCompare or default Array.prototype.sort.

a

type string

b

type string

returns

number

computeDependents
#

postprocess.ts view source

(files: readonly SourceFileInfo[]): (SourceFileInfo & { dependents?: readonly string[] | undefined; })[] import {computeDependents} from 'svelte-docinfo/postprocess.js';

Compute bidirectional dependencies from source files.

This function ensures that if file A has file B in its dependencies, then file B will have file A in its dependents. This provides consistent output regardless of whether callers provide one-directional or bidirectional dependency information.

Returns new SourceFileInfo objects when computed dependents exist or when paths needed posixification; otherwise the original input objects flow through ===-equal (fast path for session callers, who already pass POSIX paths and may have no inferable dependents for a given file).

files

source files with optional dependency information

type readonly SourceFileInfo[]

returns

(SourceFileInfo & { dependents?: readonly string[] | undefined; })[]

new array with bidirectional dependencies computed

examples

// Input: Calculator.svelte has dependencies: [math.ts] // Output: Calculator.svelte has dependencies: [math.ts] // math.ts has dependents: [Calculator.svelte] const filesWithBidirectional = computeDependents(files);

DuplicateDeclaration
#

postprocess.ts view source

also exported from index.ts

DuplicateDeclaration import type {DuplicateDeclaration} from 'svelte-docinfo/postprocess.js';

A duplicate declaration with its full metadata and module path.

declaration

The full declaration metadata.

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 ....

module

Module path where this declaration is defined.

type string

ExportSurface
#

postprocess.ts view source

also exported from index.ts

ExportSurface import type {ExportSurface} from 'svelte-docinfo/postprocess.js';

A module's resolved export surface — see resolveExportSurface.

entries

Surface entries, sorted by name (case-insensitive order, compareStrings).

type ExportSurfaceEntry[]

unresolvedStarExports

Star targets (own or transitive) absent from the analyzed set — their projected names are unknown, so the surface is incomplete.

type string[]

externalStarExports

External star specifiers reachable from this module (own or transitive) — their projected names are unknowable without analyzing the package.

type string[]

ExportSurfaceEntry
#

postprocess.ts view source

also exported from index.ts

ExportSurfaceEntry import type {ExportSurfaceEntry} from 'svelte-docinfo/postprocess.js';

One name on a module's resolved export surface.

name

Exported name, in the docinfo model's terms — Svelte components appear under their filename-derived name (the model's convention for default exports of .svelte files), not 'default'.

type string

via

How the name reaches this module's surface: an own declaration (including synthesized aliases), a same-name re-export edge, a direct external re-export, or projection through export * from './x'.

type "declaration" | "reExport" | "external" | "star"

module?

Canonical module path, when known (undefined for external entries).

type string

declaration?

The canonical declaration, when present in the analyzed set.

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 ....

specifier?

Package specifier for external entries (as written in the statement).

type string

originalName?

Name inside the external package when renamed.

type string

typeOnly?

Type-only re-export — the name is erased at runtime.

type boolean

starFrom?

For star-projected entries: the starExports target the name arrived through.

type string

findDuplicates
#

postprocess.ts view source

also exported from index.ts

(modules: { path: string; declarations: ({ 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 ... | { ...; })[]; ... 7 more ...; moduleComment?: string | undefined; }[]): Map<...> import {findDuplicates} from 'svelte-docinfo/postprocess.js';

Find duplicate declaration names across modules.

A duplicate is two *different things* sharing a name in the flat namespace. Occurrences are compared by canonical identity — aliasOf chains are resolved first, so an alias and its canonical (or two aliases of the same canonical) are one thing, not a collision. Documenting a same-name re-export (which synthesizes an alias) or re-exporting a component under its own name (export {default as Foo} from './Foo.svelte') therefore doesn't flag. When a name does flag, all occurrences are reported, aliases included.

Callers can decide how to handle duplicates (throw, warn, ignore).

modules

type { path: string; declarations: ({ 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?: numbe...

returns

Map<string, DuplicateDeclaration[]>

Map of declaration names to their DuplicateDeclaration occurrences (only includes duplicates)

examples

const duplicates = findDuplicates(modules); if (duplicates.size > 0) { for (const [name, occurrences] of duplicates) { console.error(`"${name}" found in:`); for (const {declaration, module} of occurrences) { console.error(` - ${module}:${declaration.sourceLine} (${declaration.kind})`); } } throw new Error(`Found ${duplicates.size} duplicate declaration names`); }

mergeReExports
#

postprocess.ts view source

also exported from index.ts

(modules: { path: string; declarations: ({ 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 ... | { ...; })[]; ... 7 more ...; moduleComment?: string | undefined; }[]): { ...; }[] import {mergeReExports} from 'svelte-docinfo/postprocess.js';

Build alsoExportedFrom arrays from the modules' forward re-export edges.

Each module carries its same-name re-export edges as ModuleJson.reExports (collected in phase 1); this phase-2 pass inverts them onto the canonical declarations so both directions of the same fact are queryable. Edges whose canonical module or declaration is absent from modules are skipped — the forward entry remains without a back-link (see ReExportJson for the presence caveats).

Component-only fields on renamed component aliases (props, acceptsChildren, etc.) are populated separately by resolveComponentAliases — call it after this function. They split because they touch disjoint fields and have different inputs.

Pure: the input array and its objects are never mutated. Modules and declarations that gain no back-link flow through ===-equal (structural sharing), so a re-run over already-merged output returns the same object references. New re-exporters union with existing alsoExportedFrom entries (deduped + sorted), keeping repeated merges idempotent by content.

modules

the analyzed modules. Must be parsed ModuleJsons — wire JSON strips empty arrays, so run raw JSON through AnalyzeResultJson.parse first or reExports may be undefined

type { path: string; declarations: ({ 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?: numbe...

returns

{ path: string; declarations: ({ 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?: numbe...

a new array; declarations with new back-links are copies with alsoExportedFrom unioned, everything else is the input object

examples

// helpers.ts exports: foo, bar // index.ts does: export {foo, bar} from './helpers.js' // (so index.ts's ModuleJson carries reExports: // [{name: 'foo', module: 'helpers.ts'}, {name: 'bar', module: 'helpers.ts'}]) // const merged = mergeReExports(modules); // - helpers.ts foo declaration gets: alsoExportedFrom: ['index.ts'] // - helpers.ts bar declaration gets: alsoExportedFrom: ['index.ts']

resolveComponentAliases
#

postprocess.ts view source

also exported from index.ts

(modules: { path: string; declarations: ({ 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 ... | { ...; })[]; ... 7 more ...; moduleComment?: string | undefined; }[], contextModules?: readonly { ...; }[]): { ...; }[] import {resolveComponentAliases} from 'svelte-docinfo/postprocess.js';

Copy props/acceptsChildren/lang/etc. from canonical component declarations onto synthesized component-aliased declarations.

Renamed Svelte component re-exports (export {default as Foo} from './X.svelte') are emitted as kind: 'component' placeholders by analyzeExports, with aliasOf pointing at the canonical. The canonical's component-specific fields are only available after analyzeSvelteModule synthesizes the canonical declaration, so the copy happens here in phase 2 once all modules are analyzed.

Call this *after* mergeReExports — both walk the same modules array but read/write disjoint fields, so order between them only matters for clarity.

Pure: the input array and its objects are never mutated. Aliases with a resolvable canonical are replaced by filled copies (canonical field values are shared by reference, not cloned); everything else flows through ===-equal.

modules

the analyzed modules (parsed ModuleJsons)

type { path: string; declarations: ({ 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?: numbe...

contextModules

canonical-lookup-only modules that never appear in output — gated component canonicals (the internal/ convention) analyzed as fill context by analyzeCore. An alias whose aliasOf.module is gated fills from here; an emitted module with the same path (impossible by construction) would win the lookup

type readonly { path: string; declarations: ({ 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 ...; sourceLin...
default []

returns

{ path: string; declarations: ({ 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?: numbe...

a new array with component-only fields filled on aliased component declarations

resolveExportSurface
#

postprocess.ts view source

also exported from index.ts

(modules: { path: string; declarations: ({ 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 ... | { ...; })[]; ... 7 more ...; moduleComment?: string | undefined; }[], path: string): ExportSurface | null import {resolveExportSurface} from 'svelte-docinfo/postprocess.js';

Resolve a module's full export surface from the analyzed model, applying ES module semantics to star exports.

Combines the module's own declarations (including synthesized aliases), reExports edges, externalReExports, and transitively-resolved starExports into one deduped, name-sorted list. The ES rules applied to star projection:

  • explicit exports (declarations, edges, externals) shadow star-projected names
  • a name projected by two stars that resolve to *different* canonicals is ambiguous and excluded (same canonical through a diamond is included once)
  • default is never star-projected — including canonical Svelte component declarations, which represent their file's default export. (Caveat: a star-projected re-export edge whose canonical is a component is treated as a default-slot re-export and skipped; a <script module> const sharing the component's exact name would be skipped with it.)

A Position-3 alias and its reExports edge are the same fact — the declaration entry wins, inheriting the edge's typeOnly.

Cyclic star graphs terminate by contributing nothing along the back-edge (an approximation of ES fixpoint resolution — fine in practice). Surfaces resolved inside a cycle are path-relative and not memoized, so sibling star paths resolve independently rather than inheriting them. Star targets missing from modules are reported in unresolvedStarExports rather than guessed at; externalStarExports aggregates external star specifiers reachable from the module, whose names are unknowable.

modules

the analyzed modules (parsed ModuleJsons — run wire JSON through AnalyzeResultJson.parse first)

type { path: string; declarations: ({ 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?: numbe...

path

the module to resolve, as a ModuleJson.path value

type string

returns

ExportSurface | null

the resolved surface, or null when path isn't in modules

sortModules
#

postprocess.ts view source

(modules: { path: string; declarations: ({ 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 ... | { ...; })[]; ... 7 more ...; moduleComment?: string | undefined; }[]): { ...; }[] import {sortModules} from 'svelte-docinfo/postprocess.js';

Sort modules alphabetically by path for deterministic output and cleaner diffs.

Case-insensitive order (compareStrings) so the output is environment-independent.

modules

the modules to sort

type { path: string; declarations: ({ 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?: numbe...

returns

{ path: string; declarations: ({ 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?: numbe...

a new sorted array (does not mutate input)

Depends on
#

Imported by
#