output format #

svelte-docinfo outputs JSON describing your project's exported API. The data format is a hierarchy: modules contain declarations, and some declarations contain members or props.

Top-level structure
#

Programmatic entry points (analyze, analyzeFromFiles) return both modules and accumulated diagnostics:

{ modules: ModuleJson[], diagnostics: Diagnostic[] }

All surfaces emit this shape. The CLI's stdout JSON and the Vite plugin's virtual module both expose modules and diagnostics (matching AnalyzeResultJson). The CLI runs output through compactReplacer so empty arrays strip on the wire (an empty-project run emits {}); parse JSON consumers through AnalyzeResultJson to restore Zod defaults.

ModuleJson
#

A ModuleJson describes a single source file and its exports:

  • path: file path relative to the source root (e.g., "math.ts")
  • declarations: exported items from this module
  • moduleComment: file-level JSDoc comment, if present
  • dependencies: paths of modules this file imports
  • dependents: paths of modules that import this file
  • starExports: export * from './module' patterns

Array fields (declarations, dependencies, etc.) are omitted from JSON when empty and default to [] at runtime after parsing.

DeclarationJson
#

Each declaration is a DeclarationJson, a discriminated union on the kind field with nine variants:

  • "function": adds parameters, returnType, returnDescription, overloads
  • "variable": adds optional defaultValue (from @default), plus reactivity when the initializer is a Svelte rune ($state, $state.raw, $derived, $derived.by)
  • "class": adds members, extends, implements
  • "interface": adds members, extends
  • "type": adds members, intersects
  • "enum": adds members (enum values)
  • "component": adds props, intersects, acceptsChildren, lang (Svelte components)
  • "snippet": adds parameters (exported Svelte template snippets)
  • "namespace": adds module (the source module path projected under this binding); synthesized for export * as ns from './x'

Shared fields on all variants:

  • name, kind: identity. Default exports carry name === "default" (see Re-exports below)
  • docComment: JSDoc comment text
  • typeSignature: full type as a string
  • sourceLine: line number in the source file
  • modifiers: e.g., "readonly", "static", "getter"
  • genericParams: type parameters with constraints and defaults
  • examples, deprecatedMessage, seeAlso, throws, since: from standard JSDoc tags
  • mutates: from the non-standard @mutates tag, stored as Record<string, string> mapping target keys to descriptions. Keys are typically parameter names but compound paths (this.foo) and external state references are accepted as-is
  • alsoExportedFrom: modules that re-export this declaration
  • aliasOf: original name if this is a renamed re-export
  • partial: true when extraction failed partway through the declaration, indicating incomplete data

Declarations tagged with @nodocs are excluded from the output entirely and are also excluded from duplicate name checking.

Re-exports
#

Re-exports are encoded with two shapes, chosen by content:

  • Same-name: the canonical declaration carries an alsoExportedFrom array listing the modules that re-export it. One declaration, multiple import paths.
  • Renamed: a synthesized declaration appears in the re-exporting module with aliasOf: {module, name} pointing at the canonical. Inherits typeSignature, docComment, parameters, reactivity, and defaultValue from the canonical; sourceLine is undefined.
  • Star exports: export * from './x' patterns are tracked separately on ModuleJson.starExports and don't synthesize per-declaration entries.

When a re-export statement carries its own JSDoc or @nodocs, an alias is also synthesized in the re-exporting module so the local content has somewhere to live, even when the name is unchanged. The trigger is "presence of local content," not "presence of rename." Local doc-comment fields apply first and stick; canonical fields only fill gaps. @nodocs on a re-export suppresses both the link and the synthesis.

Default-slot entries carry name === "default" (see the shared-fields note above for why). Renames out of the default slot (export {default as Foo} from './x') carry name: "Foo" and aliasOf: {module, name: "default"}. Duplicate-name checks skip "default" since the default slot is module-scoped per the JS spec.

Namespace re-exports (export * as ns from './x') synthesize a NamespaceDeclarationJson with module pointing at the source the namespace projects. Consumers render ns.a / ns.b by reading the source module's declarations; namespaces don't inline members.

MemberJson
#

Classes, interfaces, types, and enums can contain MemberJson entries in their members arrays. MemberJson is a discriminated union on kind with three variants:

  • "function": methods and call signatures. Adds parameters, returnType, returnDescription, overloads
  • "constructor": class constructors and construct signatures. Adds parameters, overloads
  • "variable": properties, accessors, and index signatures. Adds optional defaultValue (from @default), plus reactivity for class fields initialized with a Svelte rune

Member kind is restricted to these three variants. Nesting is exactly one level deep: members never contain their own members.

Member name is the user-chosen identifier in most cases, but three synthesized sentinels appear when no source identifier exists: "constructor" (class constructor), "(construct)" (construct signature on an interface or type alias), and "(call)" (call signature on an interface or type alias).

ComponentPropJson
#

Component declarations have a props array of ComponentPropJson entries:

  • name, type: prop name and TypeScript type
  • optional: whether the prop is optional
  • description: from JSDoc on the prop
  • defaultValue: default value as a string, if present
  • bindable: set when the prop is declared with the $bindable() rune, so <Foo bind:value /> is supported. Modeled here (not via the variable-level reactivity field) because $props/$bindable are component-prop concerns
  • parameters: structured parameters for snippet-typed props (e.g., Snippet<[text: string]>), absent for non-snippet props
  • examples, deprecatedMessage, seeAlso, throws, since: symbol-scope JSDoc tags parsed from the prop's own doc comment (same shape as the declaration shared fields)

Asymmetry with ParameterJson. Props carry the symbol-scope tag fields above; function parameters deliberately don't. A prop is a named slot with its own documentation surface. A parameter is positional, and its @example/@deprecated/@since/@see/@throws belong on the enclosing function symbol per the TSDoc spec. Per-parameter content lives on ParameterJson.description from @param only.

ParameterJson
#

Functions, snippets, constructors, and snippet-typed component props use ParameterJson entries in their parameters arrays:

  • name: parameter name (e.g., "options", "...args")
  • type: resolved TypeScript type as a string
  • optional: whether the parameter has a ? token
  • rest: whether the parameter uses rest syntax (...args)
  • description: from @param JSDoc
  • defaultValue: default value expression from the source, if present

OverloadJson
#

Functions and constructors with multiple signatures use OverloadJson entries in their overloads arrays. Each overload captures only signature-scope content, the fields that can vary meaningfully per signature:

  • typeSignature: the full overload signature as a string
  • parameters: parameter list for this overload, with per-overload @param descriptions
  • returnType: return type for this overload (functions only)
  • genericParams: type parameters for this overload
  • docComment: per-overload JSDoc text, if present
  • returnDescription: from @returns on this overload

Symbol-scope JSDoc tags (@example, @deprecated, @since, @see, @throws, @mutates) describe the function as a whole and live on the parent declaration only, not duplicated per overload. The primary overload's JSDoc feeds the parent's symbol-level extraction; placing one of those tags on a non-primary overload signature emits a misplaced_tag warning and the tag is dropped (no synthetic content, no silent loss). Typo'd or stale @param keys produce unknown_param warnings the same way.

Reactivity
#

The reactivity field appears on VariableDeclarationJson and VariableMemberJson when the initializer is a value-producing Svelte rune call: $state, $state.raw, $derived, or $derived.by. Detection is purely syntactic and runs on every analyzed file regardless of extension, capturing the same patterns in a plain .ts file as in .svelte.ts or a component's <script>.

It covers variables (top-level and class fields). Function parameters and destructured bindings are not annotated even when the value flows from a rune. $props and $bindable are component-prop concerns and surface on ComponentPropJson's bindable field instead.

GenericParamJson
#

Declarations and members with type parameters use GenericParamJson entries in their genericParams arrays:

  • name: type parameter name (e.g., "T")
  • constraint: extends constraint, if present
  • defaultType: default type, if present

Working with type strings
#

Type signatures are opaque strings produced by the TypeScript compiler. To discover which in-project declaration names appear in a type string (e.g., for rendering clickable links), use findTypeReferences:

import {findTypeReferences} from 'svelte-docinfo'; const names = new Set(modules.flatMap(m => m.declarations.map(d => d.name))); findTypeReferences('Map<string, ModuleJson[]>', names); // => ['ModuleJson']

When scanning many type strings against the same set of names, pre-compile the patterns with buildTypeReferencePatterns to avoid recompiling regexes on every call.

Compact JSON and absent-as-false
#

By default, output uses compact JSON via compactReplacer: empty arrays, false booleans, and undefined fields are stripped, so optional, acceptsChildren, partial, rest, bindable, and similar fields vanish from the wire form when their value is the default. After parsing with the Zod schemas from types.ts (or AnalyzeResultJson for the full {modules, diagnostics} envelope), all defaults are restored, and the round-trip is lossless.

Raw-JSON consumers (e.g., jq, hand-rolled pipelines that skip .parse()) must treat absent as false; a literal decl.optional === false check silently fails because the key is gone. Use the schemas, or truthy/falsy checks (if (decl.optional) …) on raw JSON.

Examples
#

A TypeScript function:

{ "modules": [ { "path": "math.ts", "declarations": [ { "name": "clamp", "kind": "function", "docComment": "Clamp a number to a range.", "typeSignature": "(value: number, min: number, max: number): number", "parameters": [ {"name": "value", "type": "number"}, {"name": "min", "type": "number"}, {"name": "max", "type": "number"} ], "returnType": "number", "sourceLine": 2 } ] } ] }

A Svelte component with a snippet prop, children, and an exported snippet:

{ "modules": [ { "path": "Card.svelte", "declarations": [ { "name": "Card", "kind": "component", "docComment": "A card with a customizable header.", "acceptsChildren": true, "props": [ {"name": "title", "type": "string"}, { "name": "header", "type": "Snippet<[title: string]>", "optional": true, "description": "Custom header rendering.", "parameters": [ {"name": "title", "type": "string"} ] } ], "sourceLine": 1 }, { "name": "card_footer", "kind": "snippet", "docComment": "Default footer snippet.", "typeSignature": "Snippet<[text: string]>", "parameters": [ {"name": "text", "type": "string"} ], "sourceLine": 12 } ] } ] }

A rune module exporting reactive state (e.g., a .svelte.ts file):

{ "modules": [ { "path": "counter.svelte.ts", "declarations": [ { "name": "count", "kind": "variable", "typeSignature": "number", "reactivity": "$state", "sourceLine": 1 }, { "name": "doubled", "kind": "variable", "typeSignature": "number", "reactivity": "$derived", "sourceLine": 2 } ] } ] }

A function defined in math.ts and re-exported under a new name from the barrel index.ts. The canonical entry carries alsoExportedFrom if any module re-exports it under the same name. Renames synthesize a separate declaration with aliasOf:

{ "modules": [ { "path": "math.ts", "declarations": [ { "name": "clamp", "kind": "function", "typeSignature": "(value: number, min: number, max: number): number", "sourceLine": 2 } ] }, { "path": "index.ts", "declarations": [ { "name": "clampNumber", "kind": "function", "typeSignature": "(value: number, min: number, max: number): number", "aliasOf": {"module": "math.ts", "name": "clamp"} } ], "starExports": ["other.ts"] } ] }

See the types module for the full Zod schemas, and the API reference for all exported types.