/** * Diagnostic collection for source analysis. * * Provides structured error/warning collection during TypeScript and Svelte * analysis, replacing silent catch blocks with actionable diagnostics. * * ## Error Handling Contract * * The pipeline accumulates failures into the `diagnostics` array and keeps * going — analysis continues, declarations/members reach the output with * `partial: true` when extraction failed mid-flight, and the caller decides * how to react. Producers include type resolution failures, individual * member/prop extraction failures, svelte2tsx transform failures, source-map * construction failures, import lex / resolver failures, and duplicate * declarations. * * A small set of conditions still throws from public entry points — these are * setup-level, not per-file: missing `tsconfig.json` (`loadTsconfig`), Svelte * <5 detected (`transformSvelteSource`), or strict `discovery: 'exports'` * mode with no resolvable exports (`discoverSourceFiles`). Wrap the top-level * `analyze` / `analyzeFromFiles` call if you want to handle these. * * ## Usage Pattern * * ```ts * const {modules, diagnostics} = await analyze({sourceFiles, sourceOptions}); * * if (hasErrors(diagnostics)) { * for (const err of errorsOf(diagnostics)) { * console.error(formatDiagnostic(err)); * } * } * for (const warning of warningsOf(diagnostics)) { * console.warn(formatDiagnostic(warning)); * } * ``` * * ## Schema-Validated Plain Data * * `AnalyzeResultJson.diagnostics` is `Array<Diagnostic>` — no wrapper object, * no methods, no private fields. Round-trip-safe through `JSON.stringify` / * `z.array(Diagnostic).parse` and symmetric with `AnalyzeResultJson.modules` * (also Zod-validated). The full envelope is itself a Zod schema * (`AnalyzeResultJson` in `analyze-core.ts`) with both fields defaulting to * `[]`, so the whole `{modules, diagnostics}` shape round-trips through * `JSON.stringify(result, compactReplacer)` / `AnalyzeResultJson.parse` even * when one or both arrays are empty (the wire form becomes `{}` and `.parse()` * restores the defaults). Use the free helpers `hasErrors`, `errorsOf`, * `byKind` for queries; mutate the array with native `Array.push`. * * ## File Path Contract * * `Diagnostic.file` is always project-root-relative — no leading slash, * no `./` prefix. `analyze` / `analyzeFromFiles` normalize paths from all * sources (extraction, discovery, dependency resolution) before returning. * Consumers that need an absolute path can rejoin with `projectRoot`. * * @module */ import {z} from 'zod'; // ── Severity ───────────────────────────────────────────────────────────────── /** * Diagnostic severity levels. * * - `'error'` — analysis failed, declaration may be incomplete or missing data * - `'warning'` — partial success, something seems off but analysis continued */ export const DiagnosticSeverity = z.enum(['error', 'warning']); export type DiagnosticSeverity = z.infer<typeof DiagnosticSeverity>; // ── Kind ───────────────────────────────────────────────────────────────────── /** * Discriminant for `Diagnostic` variant types. */ export const DiagnosticKind = z.enum([ 'type_extraction_failed', 'signature_analysis_failed', 'class_member_failed', 'svelte_prop_failed', 'module_skipped', 'module_unreadable', 'import_parse_failed', 'duplicate_comment', 'misplaced_tag', 'unknown_param', 'source_map_failed', 'duplicate_declaration', 'transform_failed', 'resolver_failed', ]); export type DiagnosticKind = z.infer<typeof DiagnosticKind>; // ── Variants ───────────────────────────────────────────────────────────────── /** * Base diagnostic fields shared by every variant. * * `line` / `column` are 1-based and `.optional()` — absent when the diagnostic * has no precise source location (e.g., a module-level skip with no specific * AST node). Mirrors the rest of the schema's "absent = missing key" rule; * use `??` at the call site if you need a placeholder. */ const baseDiagnosticFields = { /** * File path relative to project root (no leading slash, no `./` prefix). * * Normalized at every public API boundary — `session.setFile`/`setFiles` * (ingest-time), `session.query` (query-time, via `analyzeCore`), and the * one-shot wrappers `analyze` / `analyzeFromFiles`. Producers inside the * pipeline may write absolute or virtual paths (e.g., * `Foo.svelte.__svelte2tsx__.ts`); normalization rewrites them to * project-relative form before they reach consumers. */ file: z.string(), /** Line number (1-based), absent if location unavailable. */ line: z.number().int().positive().optional(), /** Column number (1-based), absent if location unavailable. */ column: z.number().int().positive().optional(), /** Human-readable description of the issue. */ message: z.string(), severity: DiagnosticSeverity, }; /** * Type extraction failed (e.g., complex or recursive types). */ export const TypeExtractionDiagnostic = z.strictObject({ kind: z.literal('type_extraction_failed'), ...baseDiagnosticFields, /** Name of the symbol whose type couldn't be extracted. */ symbolName: z.string(), }); export type TypeExtractionDiagnostic = z.infer<typeof TypeExtractionDiagnostic>; /** * Function/method signature analysis failed. */ export const SignatureAnalysisDiagnostic = z.strictObject({ kind: z.literal('signature_analysis_failed'), ...baseDiagnosticFields, /** Name of the function or method. */ functionName: z.string(), }); export type SignatureAnalysisDiagnostic = z.infer<typeof SignatureAnalysisDiagnostic>; /** * Class member analysis failed. */ export const ClassMemberDiagnostic = z.strictObject({ kind: z.literal('class_member_failed'), ...baseDiagnosticFields, /** Name of the class. */ className: z.string(), /** Name of the member that failed. */ memberName: z.string(), }); export type ClassMemberDiagnostic = z.infer<typeof ClassMemberDiagnostic>; /** * Svelte prop type resolution failed. */ export const SveltePropDiagnostic = z.strictObject({ kind: z.literal('svelte_prop_failed'), ...baseDiagnosticFields, /** Name of the component. */ componentName: z.string(), /** Name of the prop. */ propName: z.string(), }); export type SveltePropDiagnostic = z.infer<typeof SveltePropDiagnostic>; /** * Module was skipped during the analysis pass. * * Always `warning` severity — the rest of the analysis still runs and the * module's absence in `modules` reflects the skip. Reasons: * * - `not_in_program` — the file wasn't in the `ts.Program` (race between * session ingest and `query`, or virtual file missing for a `.svelte`) * - `no_analyzer` — file extension didn't match any analyzer * - `requires_program` — Svelte file reached the non-Svelte dispatcher (caller * should use the session API instead of `analyzeModule` directly) * * Discovery-time file-read failures are a separate kind: `module_unreadable`. */ export const ModuleSkippedDiagnostic = z.strictObject({ kind: z.literal('module_skipped'), ...baseDiagnosticFields, /** Reason the module was skipped. */ reason: z.enum(['not_in_program', 'no_analyzer', 'requires_program']), }); export type ModuleSkippedDiagnostic = z.infer<typeof ModuleSkippedDiagnostic>; /** * File discovered via package.json `exports` exists but couldn't be read. * * Always `error` severity — discovery-time, emitted by `discoverFromExports` * when `readFile` fails (permission denied, FS error). Distinct from * `module_skipped` so severity is a stable per-kind property and downstream * consumers can route discovery failures separately from analysis-pass skips. */ export const ModuleUnreadableDiagnostic = z.strictObject({ kind: z.literal('module_unreadable'), ...baseDiagnosticFields, }); export type ModuleUnreadableDiagnostic = z.infer<typeof ModuleUnreadableDiagnostic>; /** * Import parsing failed during dependency resolution. */ export const ImportParseDiagnostic = z.strictObject({ kind: z.literal('import_parse_failed'), ...baseDiagnosticFields, }); export type ImportParseDiagnostic = z.infer<typeof ImportParseDiagnostic>; /** * Duplicate comment sources detected (e.g., both HTML and JSDoc `@module`, * or both HTML `@component` and JSDoc for component `docComment`). */ export const DuplicateCommentDiagnostic = z.strictObject({ kind: z.literal('duplicate_comment'), ...baseDiagnosticFields, /** Which comment type is duplicated. */ commentType: z.enum(['module_comment', 'doc_comment']), }); export type DuplicateCommentDiagnostic = z.infer<typeof DuplicateCommentDiagnostic>; /** * A JSDoc tag found somewhere it has no effect. * * Two contexts emit this: * * - **Non-primary overload signature** — symbol-scope tags (`@example`, * `@deprecated`, `@since`, `@see`, `@throws`, `@mutates`, `@default`, * `@nodocs`) describe the function as a whole, not individual signatures. * The primary signature's JSDoc feeds the parent declaration's symbol-level * extraction; tags on non-primary overload signatures are silently dropped * from output. This diagnostic surfaces them so authors can move them to * the primary signature. `@default` and `@nodocs` are included even though * overloads never carry a `defaultValue` or per-overload exclusion: their * presence on a non-primary signature is always a misplacement. * - **Module comment** — `@nodocs` has no module-level meaning (it applies to * declarations and export statements); in a `@module` comment the tag does * nothing except remain verbatim in `moduleComment` text. To omit a module * from analysis, use `exclude` patterns instead. */ export const MisplacedTagDiagnostic = z.strictObject({ kind: z.literal('misplaced_tag'), ...baseDiagnosticFields, /** The tag name without the `@` prefix (e.g., `'example'`, `'deprecated'`). */ tagName: z.enum([ 'example', 'deprecated', 'since', 'see', 'throws', 'mutates', 'default', 'nodocs', ]), /** * Name of the function or method whose overload carries the misplaced tag. * Absent for module-comment misplacements (no enclosing symbol). */ functionName: z.string().optional(), }); export type MisplacedTagDiagnostic = z.infer<typeof MisplacedTagDiagnostic>; /** * `@param` tag references a name that doesn't match any actual parameter. * * Usually a typo (`@param argz` for parameter `args`) or stale doc after a * rename. The description is dropped; analysis continues. */ export const UnknownParamDiagnostic = z.strictObject({ kind: z.literal('unknown_param'), ...baseDiagnosticFields, /** The `@param` key that didn't match a real parameter. */ paramName: z.string(), /** Name of the function or method. */ functionName: z.string(), }); export type UnknownParamDiagnostic = z.infer<typeof UnknownParamDiagnostic>; /** * A declaration `name` appears in more than one module. * * Library docs assume a flat namespace — two modules exporting the same name * collide when consumers `import {name}`. Emitted at `warning` severity so * the analysis result remains usable; consumers who want it fatal can promote * via `onDuplicates: 'throw'` or by inspecting the diagnostic. The default * slot (`name === 'default'`) is excluded — every module owns its own. */ export const DuplicateDeclarationDiagnostic = z.strictObject({ kind: z.literal('duplicate_declaration'), ...baseDiagnosticFields, /** The duplicated declaration name. */ declarationName: z.string(), /** Module paths where the name was defined (>= 2). */ modules: z.array(z.string()).min(2), }); export type DuplicateDeclarationDiagnostic = z.infer<typeof DuplicateDeclarationDiagnostic>; /** * Source map parsing failed for a Svelte virtual file. * * Analysis continues using virtual-file positions, so downstream `line`/`column` * fields on other diagnostics may point into the svelte2tsx-generated TS rather * than the original `.svelte` source. Rare; usually signals a malformed or * incompatible svelte2tsx output. * * Emitted at ingest time by `transformSvelteSource` (in `svelte.ts`); flows * through `setFile`/`setFiles` ingest diagnostics rather than the analysis * pass. */ export const SourceMapFailedDiagnostic = z.strictObject({ kind: z.literal('source_map_failed'), ...baseDiagnosticFields, }); export type SourceMapFailedDiagnostic = z.infer<typeof SourceMapFailedDiagnostic>; /** * svelte2tsx transform threw for a `.svelte` file. * * Unrecoverable at ingest — the file's owned-entry stays in the session * (`virtual: undefined`, `unfilteredDeps: []`, `transformFailed: true`) so * `query()` can synthesize a placeholder `ModuleJson` (`partial: true`, * empty `declarations`). The originating error message lives in `message`; * this diagnostic is the authoritative cause-of-failure signal. */ export const TransformFailedDiagnostic = z.strictObject({ kind: z.literal('transform_failed'), ...baseDiagnosticFields, }); export type TransformFailedDiagnostic = z.infer<typeof TransformFailedDiagnostic>; /** * Import resolver threw while resolving a specifier. * * Distinguishes a buggy resolver from a legitimately unresolvable specifier: * resolvers that return `null` for unknown specifiers stay silent (the normal * "external package" case); resolvers that *throw* surface here so consumers * can fix the resolver. Recoverable — the session treats the throw as `null` * and continues, so analysis still runs but with a missing dependency edge. * * Emitted at ingest time by the session's resolve phase. */ export const ResolverFailedDiagnostic = z.strictObject({ kind: z.literal('resolver_failed'), ...baseDiagnosticFields, /** The import specifier the resolver failed on. */ specifier: z.string(), }); export type ResolverFailedDiagnostic = z.infer<typeof ResolverFailedDiagnostic>; /** * Discriminated union of all diagnostic variants. */ export const Diagnostic: z.ZodDiscriminatedUnion< [ typeof TypeExtractionDiagnostic, typeof SignatureAnalysisDiagnostic, typeof ClassMemberDiagnostic, typeof SveltePropDiagnostic, typeof ModuleSkippedDiagnostic, typeof ModuleUnreadableDiagnostic, typeof ImportParseDiagnostic, typeof DuplicateCommentDiagnostic, typeof MisplacedTagDiagnostic, typeof UnknownParamDiagnostic, typeof SourceMapFailedDiagnostic, typeof DuplicateDeclarationDiagnostic, typeof TransformFailedDiagnostic, typeof ResolverFailedDiagnostic, ], 'kind' > = z.discriminatedUnion('kind', [ TypeExtractionDiagnostic, SignatureAnalysisDiagnostic, ClassMemberDiagnostic, SveltePropDiagnostic, ModuleSkippedDiagnostic, ModuleUnreadableDiagnostic, ImportParseDiagnostic, DuplicateCommentDiagnostic, MisplacedTagDiagnostic, UnknownParamDiagnostic, SourceMapFailedDiagnostic, DuplicateDeclarationDiagnostic, TransformFailedDiagnostic, ResolverFailedDiagnostic, ]); export type Diagnostic = z.infer<typeof Diagnostic>; // ── Helpers ──────────────────────────────────────────────────────────────── /** * Check if any error-severity diagnostics were collected. */ export const hasErrors = (diagnostics: Array<Diagnostic>): boolean => diagnostics.some((d) => d.severity === 'error'); /** * Check if any warning-severity diagnostics were collected. */ export const hasWarnings = (diagnostics: Array<Diagnostic>): boolean => diagnostics.some((d) => d.severity === 'warning'); /** * Get all error-severity diagnostics. */ export const errorsOf = (diagnostics: Array<Diagnostic>): Array<Diagnostic> => diagnostics.filter((d) => d.severity === 'error'); /** * Get all warning-severity diagnostics. */ export const warningsOf = (diagnostics: Array<Diagnostic>): Array<Diagnostic> => diagnostics.filter((d) => d.severity === 'warning'); /** * Get diagnostics of a specific kind, narrowed to the matching variant. */ export const byKind = <K extends DiagnosticKind>( diagnostics: Array<Diagnostic>, kind: K, ): Array<Extract<Diagnostic, {kind: K}>> => diagnostics.filter((d) => d.kind === kind) as Array<Extract<Diagnostic, {kind: K}>>; /** * Format a diagnostic for display. * * Assumes `diagnostic.file` is project-root-relative (the contract enforced * by `analyze` / `analyzeFromFiles`). The displayed path is prefixed with `./`. * * @param diagnostic - the diagnostic to format * @returns formatted string like `'./file.ts:10:5: error: message'` * * @example * ```ts * for (const d of errorsOf(diagnostics)) { * console.error(formatDiagnostic(d)); * } * ``` */ export const formatDiagnostic = (diagnostic: Diagnostic): string => { const {file, line, column, severity, message} = diagnostic; const location = line !== undefined ? (column !== undefined ? `${line}:${column}` : `${line}`) : ''; const filePart = location ? `./${file}:${location}` : `./${file}`; return `${filePart}: ${severity}: ${message}`; };
{ "path": "diagnostics.ts", "declarations": [ { "name": "DiagnosticSeverity", "kind": "type", "docComment": "Diagnostic severity levels.\n\n- `'error'` — analysis failed, declaration may be incomplete or missing data\n- `'warning'` — partial success, something seems off but analysis continued", "typeSignature": "ZodEnum<{ error: \"error\"; warning: \"warning\"; }>", "sourceLine": 71, "alsoExportedFrom": [ "index.ts" ] }, { "name": "DiagnosticKind", "kind": "type", "docComment": "Discriminant for `Diagnostic` variant types.", "typeSignature": "ZodEnum<{ type_extraction_failed: \"type_extraction_failed\"; signature_analysis_failed: \"signature_analysis_failed\"; class_member_failed: \"class_member_failed\"; svelte_prop_failed: \"svelte_prop_failed\"; ... 9 more ...; resolver_failed: \"resolver_failed\"; }>", "sourceLine": 79, "alsoExportedFrom": [ "index.ts" ] }, { "name": "TypeExtractionDiagnostic", "kind": "type", "docComment": "Type extraction failed (e.g., complex or recursive types).", "typeSignature": "ZodObject<{ symbolName: ZodString; file: ZodString; line: ZodOptional<ZodNumber>; column: ZodOptional<ZodNumber>; message: ZodString; severity: ZodEnum<...>; kind: ZodLiteral<...>; }, $strict>", "sourceLine": 131 }, { "name": "SignatureAnalysisDiagnostic", "kind": "type", "docComment": "Function/method signature analysis failed.", "typeSignature": "ZodObject<{ functionName: ZodString; file: ZodString; line: ZodOptional<ZodNumber>; column: ZodOptional<ZodNumber>; message: ZodString; severity: ZodEnum<...>; kind: ZodLiteral<...>; }, $strict>", "sourceLine": 142 }, { "name": "ClassMemberDiagnostic", "kind": "type", "docComment": "Class member analysis failed.", "typeSignature": "ZodObject<{ className: ZodString; memberName: ZodString; file: ZodString; line: ZodOptional<ZodNumber>; column: ZodOptional<ZodNumber>; message: ZodString; severity: ZodEnum<...>; kind: ZodLiteral<...>; }, $strict>", "sourceLine": 153 }, { "name": "SveltePropDiagnostic", "kind": "type", "docComment": "Svelte prop type resolution failed.", "typeSignature": "ZodObject<{ componentName: ZodString; propName: ZodString; file: ZodString; line: ZodOptional<ZodNumber>; column: ZodOptional<ZodNumber>; message: ZodString; severity: ZodEnum<...>; kind: ZodLiteral<...>; }, $strict>", "sourceLine": 166 }, { "name": "ModuleSkippedDiagnostic", "kind": "type", "docComment": "Module was skipped during the analysis pass.\n\nAlways `warning` severity — the rest of the analysis still runs and the\nmodule's absence in `modules` reflects the skip. Reasons:\n\n- `not_in_program` — the file wasn't in the `ts.Program` (race between\n session ingest and `query`, or virtual file missing for a `.svelte`)\n- `no_analyzer` — file extension didn't match any analyzer\n- `requires_program` — Svelte file reached the non-Svelte dispatcher (caller\n should use the session API instead of `analyzeModule` directly)\n\nDiscovery-time file-read failures are a separate kind: `module_unreadable`.", "typeSignature": "ZodObject<{ reason: ZodEnum<{ not_in_program: \"not_in_program\"; no_analyzer: \"no_analyzer\"; requires_program: \"requires_program\"; }>; file: ZodString; line: ZodOptional<ZodNumber>; column: ZodOptional<...>; message: ZodString; severity: ZodEnum<...>; kind: ZodLiteral<...>; }, $strict>", "sourceLine": 190 }, { "name": "ModuleUnreadableDiagnostic", "kind": "type", "docComment": "File discovered via package.json `exports` exists but couldn't be read.\n\nAlways `error` severity — discovery-time, emitted by `discoverFromExports`\nwhen `readFile` fails (permission denied, FS error). Distinct from\n`module_skipped` so severity is a stable per-kind property and downstream\nconsumers can route discovery failures separately from analysis-pass skips.", "typeSignature": "ZodObject<{ file: ZodString; line: ZodOptional<ZodNumber>; column: ZodOptional<ZodNumber>; message: ZodString; severity: ZodEnum<...>; kind: ZodLiteral<...>; }, $strict>", "sourceLine": 206 }, { "name": "ImportParseDiagnostic", "kind": "type", "docComment": "Import parsing failed during dependency resolution.", "typeSignature": "ZodObject<{ file: ZodString; line: ZodOptional<ZodNumber>; column: ZodOptional<ZodNumber>; message: ZodString; severity: ZodEnum<...>; kind: ZodLiteral<...>; }, $strict>", "sourceLine": 215 }, { "name": "DuplicateCommentDiagnostic", "kind": "type", "docComment": "Duplicate comment sources detected (e.g., both HTML and JSDoc `@module`,\nor both HTML `@component` and JSDoc for component `docComment`).", "typeSignature": "ZodObject<{ commentType: ZodEnum<{ module_comment: \"module_comment\"; doc_comment: \"doc_comment\"; }>; file: ZodString; line: ZodOptional<ZodNumber>; column: ZodOptional<...>; message: ZodString; severity: ZodEnum<...>; kind: ZodLiteral<...>; }, $strict>", "sourceLine": 225 }, { "name": "MisplacedTagDiagnostic", "kind": "type", "docComment": "A JSDoc tag found somewhere it has no effect.\n\nTwo contexts emit this:\n\n- **Non-primary overload signature** — symbol-scope tags (`@example`,\n `@deprecated`, `@since`, `@see`, `@throws`, `@mutates`, `@default`,\n `@nodocs`) describe the function as a whole, not individual signatures.\n The primary signature's JSDoc feeds the parent declaration's symbol-level\n extraction; tags on non-primary overload signatures are silently dropped\n from output. This diagnostic surfaces them so authors can move them to\n the primary signature. `@default` and `@nodocs` are included even though\n overloads never carry a `defaultValue` or per-overload exclusion: their\n presence on a non-primary signature is always a misplacement.\n- **Module comment** — `@nodocs` has no module-level meaning (it applies to\n declarations and export statements); in a `@module` comment the tag does\n nothing except remain verbatim in `moduleComment` text. To omit a module\n from analysis, use `exclude` patterns instead.", "typeSignature": "ZodObject<{ tagName: ZodEnum<{ default: \"default\"; mutates: \"mutates\"; throws: \"throws\"; since: \"since\"; example: \"example\"; deprecated: \"deprecated\"; see: \"see\"; nodocs: \"nodocs\"; }>; functionName: ZodOptional<...>; ... 5 more ...; kind: ZodLiteral<...>; }, $strict>", "sourceLine": 252 }, { "name": "UnknownParamDiagnostic", "kind": "type", "docComment": "`@param` tag references a name that doesn't match any actual parameter.\n\nUsually a typo (`@param argz` for parameter `args`) or stale doc after a\nrename. The description is dropped; analysis continues.", "typeSignature": "ZodObject<{ paramName: ZodString; functionName: ZodString; file: ZodString; line: ZodOptional<ZodNumber>; column: ZodOptional<ZodNumber>; message: ZodString; severity: ZodEnum<...>; kind: ZodLiteral<...>; }, $strict>", "sourceLine": 280 }, { "name": "DuplicateDeclarationDiagnostic", "kind": "type", "docComment": "A declaration `name` appears in more than one module.\n\nLibrary docs assume a flat namespace — two modules exporting the same name\ncollide when consumers `import {name}`. Emitted at `warning` severity so\nthe analysis result remains usable; consumers who want it fatal can promote\nvia `onDuplicates: 'throw'` or by inspecting the diagnostic. The default\nslot (`name === 'default'`) is excluded — every module owns its own.", "typeSignature": "ZodObject<{ declarationName: ZodString; modules: ZodArray<ZodString>; file: ZodString; line: ZodOptional<ZodNumber>; column: ZodOptional<...>; message: ZodString; severity: ZodEnum<...>; kind: ZodLiteral<...>; }, $strict>", "sourceLine": 299 }, { "name": "SourceMapFailedDiagnostic", "kind": "type", "docComment": "Source map parsing failed for a Svelte virtual file.\n\nAnalysis continues using virtual-file positions, so downstream `line`/`column`\nfields on other diagnostics may point into the svelte2tsx-generated TS rather\nthan the original `.svelte` source. Rare; usually signals a malformed or\nincompatible svelte2tsx output.\n\nEmitted at ingest time by `transformSvelteSource` (in `svelte.ts`); flows\nthrough `setFile`/`setFiles` ingest diagnostics rather than the analysis\npass.", "typeSignature": "ZodObject<{ file: ZodString; line: ZodOptional<ZodNumber>; column: ZodOptional<ZodNumber>; message: ZodString; severity: ZodEnum<...>; kind: ZodLiteral<...>; }, $strict>", "sourceLine": 321 }, { "name": "TransformFailedDiagnostic", "kind": "type", "docComment": "svelte2tsx transform threw for a `.svelte` file.\n\nUnrecoverable at ingest — the file's owned-entry stays in the session\n(`virtual: undefined`, `unfilteredDeps: []`, `transformFailed: true`) so\n`query()` can synthesize a placeholder `ModuleJson` (`partial: true`,\nempty `declarations`). The originating error message lives in `message`;\nthis diagnostic is the authoritative cause-of-failure signal.", "typeSignature": "ZodObject<{ file: ZodString; line: ZodOptional<ZodNumber>; column: ZodOptional<ZodNumber>; message: ZodString; severity: ZodEnum<...>; kind: ZodLiteral<...>; }, $strict>", "sourceLine": 336 }, { "name": "ResolverFailedDiagnostic", "kind": "type", "docComment": "Import resolver threw while resolving a specifier.\n\nDistinguishes a buggy resolver from a legitimately unresolvable specifier:\nresolvers that return `null` for unknown specifiers stay silent (the normal\n\"external package\" case); resolvers that *throw* surface here so consumers\ncan fix the resolver. Recoverable — the session treats the throw as `null`\nand continues, so analysis still runs but with a missing dependency edge.\n\nEmitted at ingest time by the session's resolve phase.", "typeSignature": "ZodObject<{ specifier: ZodString; file: ZodString; line: ZodOptional<ZodNumber>; column: ZodOptional<ZodNumber>; message: ZodString; severity: ZodEnum<...>; kind: ZodLiteral<...>; }, $strict>", "sourceLine": 353 }, { "name": "Diagnostic", "kind": "type", "docComment": "Discriminated union of all diagnostic variants.", "typeSignature": "ZodDiscriminatedUnion<[ZodObject<{ symbolName: ZodString; file: ZodString; line: ZodOptional<ZodNumber>; column: ZodOptional<ZodNumber>; message: ZodString; severity: ZodEnum<...>; kind: ZodLiteral<...>; }, $strict>, ... 12 more ..., ZodObject<...>], \"kind\">", "sourceLine": 364, "alsoExportedFrom": [ "index.ts" ] }, { "name": "hasErrors", "kind": "function", "docComment": "Check if any error-severity diagnostics were collected.", "typeSignature": "(diagnostics: ({ symbolName: string; file: string; message: string; severity: \"error\" | \"warning\"; kind: \"type_extraction_failed\"; line?: number | undefined; column?: number | undefined; } | { functionName: string; ... 5 more ...; column?: number | undefined; } | ... 11 more ... | { ...; })[]): boolean", "sourceLine": 405, "alsoExportedFrom": [ "index.ts" ], "parameters": [ { "name": "diagnostics", "type": "({ symbolName: string; file: string; message: string; severity: \"error\" | \"warning\"; kind: \"type_extraction_failed\"; line?: number | undefined; column?: number | undefined; } | { functionName: string; ... 5 more ...; column?: number | undefined; } | ... 11 more ... | { ...; })[]" } ], "returnType": "boolean" }, { "name": "hasWarnings", "kind": "function", "docComment": "Check if any warning-severity diagnostics were collected.", "typeSignature": "(diagnostics: ({ symbolName: string; file: string; message: string; severity: \"error\" | \"warning\"; kind: \"type_extraction_failed\"; line?: number | undefined; column?: number | undefined; } | { functionName: string; ... 5 more ...; column?: number | undefined; } | ... 11 more ... | { ...; })[]): boolean", "sourceLine": 411, "alsoExportedFrom": [ "index.ts" ], "parameters": [ { "name": "diagnostics", "type": "({ symbolName: string; file: string; message: string; severity: \"error\" | \"warning\"; kind: \"type_extraction_failed\"; line?: number | undefined; column?: number | undefined; } | { functionName: string; ... 5 more ...; column?: number | undefined; } | ... 11 more ... | { ...; })[]" } ], "returnType": "boolean" }, { "name": "errorsOf", "kind": "function", "docComment": "Get all error-severity diagnostics.", "typeSignature": "(diagnostics: ({ symbolName: string; file: string; message: string; severity: \"error\" | \"warning\"; kind: \"type_extraction_failed\"; line?: number | undefined; column?: number | undefined; } | { functionName: string; ... 5 more ...; column?: number | undefined; } | ... 11 more ... | { ...; })[]): ({ ...; } | ... 12 more ... | { ...; })[]", "sourceLine": 417, "alsoExportedFrom": [ "index.ts" ], "parameters": [ { "name": "diagnostics", "type": "({ symbolName: string; file: string; message: string; severity: \"error\" | \"warning\"; kind: \"type_extraction_failed\"; line?: number | undefined; column?: number | undefined; } | { functionName: string; ... 5 more ...; column?: number | undefined; } | ... 11 more ... | { ...; })[]" } ], "returnType": "({ symbolName: string; file: string; message: string; severity: \"error\" | \"warning\"; kind: \"type_extraction_failed\"; line?: number | undefined; column?: number | undefined; } | { functionName: string; ... 5 more ...; column?: number | undefined; } | ... 11 more ... | { ...; })[]" }, { "name": "warningsOf", "kind": "function", "docComment": "Get all warning-severity diagnostics.", "typeSignature": "(diagnostics: ({ symbolName: string; file: string; message: string; severity: \"error\" | \"warning\"; kind: \"type_extraction_failed\"; line?: number | undefined; column?: number | undefined; } | { functionName: string; ... 5 more ...; column?: number | undefined; } | ... 11 more ... | { ...; })[]): ({ ...; } | ... 12 more ... | { ...; })[]", "sourceLine": 423, "alsoExportedFrom": [ "index.ts" ], "parameters": [ { "name": "diagnostics", "type": "({ symbolName: string; file: string; message: string; severity: \"error\" | \"warning\"; kind: \"type_extraction_failed\"; line?: number | undefined; column?: number | undefined; } | { functionName: string; ... 5 more ...; column?: number | undefined; } | ... 11 more ... | { ...; })[]" } ], "returnType": "({ symbolName: string; file: string; message: string; severity: \"error\" | \"warning\"; kind: \"type_extraction_failed\"; line?: number | undefined; column?: number | undefined; } | { functionName: string; ... 5 more ...; column?: number | undefined; } | ... 11 more ... | { ...; })[]" }, { "name": "byKind", "kind": "function", "docComment": "Get diagnostics of a specific kind, narrowed to the matching variant.", "typeSignature": "<K extends DiagnosticKind>(diagnostics: ({ symbolName: string; file: string; message: string; severity: \"error\" | \"warning\"; kind: \"type_extraction_failed\"; line?: number | undefined; column?: number | undefined; } | ... 12 more ... | { ...; })[], kind: K): (Extract<...> | ... 12 more ... | Extract<...>)[]", "sourceLine": 429, "genericParams": [ { "name": "K", "constraint": "DiagnosticKind" } ], "alsoExportedFrom": [ "index.ts" ], "parameters": [ { "name": "diagnostics", "type": "({ symbolName: string; file: string; message: string; severity: \"error\" | \"warning\"; kind: \"type_extraction_failed\"; line?: number | undefined; column?: number | undefined; } | { functionName: string; ... 5 more ...; column?: number | undefined; } | ... 11 more ... | { ...; })[]" }, { "name": "kind", "type": "K" } ], "returnType": "(Extract<{ symbolName: string; file: string; message: string; severity: \"error\" | \"warning\"; kind: \"type_extraction_failed\"; line?: number | undefined; column?: number | undefined; }, { kind: K; }> | ... 12 more ... | Extract<...>)[]" }, { "name": "formatDiagnostic", "kind": "function", "docComment": "Format a diagnostic for display.\n\nAssumes `diagnostic.file` is project-root-relative (the contract enforced\nby `analyze` / `analyzeFromFiles`). The displayed path is prefixed with `./`.", "typeSignature": "(diagnostic: { symbolName: string; file: string; message: string; severity: \"error\" | \"warning\"; kind: \"type_extraction_failed\"; line?: number | undefined; column?: number | undefined; } | { functionName: string; ... 5 more ...; column?: number | undefined; } | ... 11 more ... | { ...; }): string", "sourceLine": 451, "examples": [ "```ts\nfor (const d of errorsOf(diagnostics)) {\n console.error(formatDiagnostic(d));\n}\n```" ], "alsoExportedFrom": [ "index.ts" ], "parameters": [ { "name": "diagnostic", "type": "{ symbolName: string; file: string; message: string; severity: \"error\" | \"warning\"; kind: \"type_extraction_failed\"; line?: number | undefined; column?: number | undefined; } | { functionName: string; ... 5 more ...; column?: number | undefined; } | ... 11 more ... | { ...; }", "description": "the diagnostic to format" } ], "returnType": "string", "returnDescription": "formatted string like `'./file.ts:10:5: error: message'`" } ], "moduleComment": "Diagnostic collection for source analysis.\n\nProvides structured error/warning collection during TypeScript and Svelte\nanalysis, replacing silent catch blocks with actionable diagnostics.\n\n## Error Handling Contract\n\nThe pipeline accumulates failures into the `diagnostics` array and keeps\ngoing — analysis continues, declarations/members reach the output with\n`partial: true` when extraction failed mid-flight, and the caller decides\nhow to react. Producers include type resolution failures, individual\nmember/prop extraction failures, svelte2tsx transform failures, source-map\nconstruction failures, import lex / resolver failures, and duplicate\ndeclarations.\n\nA small set of conditions still throws from public entry points — these are\nsetup-level, not per-file: missing `tsconfig.json` (`loadTsconfig`), Svelte\n<5 detected (`transformSvelteSource`), or strict `discovery: 'exports'`\nmode with no resolvable exports (`discoverSourceFiles`). Wrap the top-level\n`analyze` / `analyzeFromFiles` call if you want to handle these.\n\n## Usage Pattern\n\n```ts\nconst {modules, diagnostics} = await analyze({sourceFiles, sourceOptions});\n\nif (hasErrors(diagnostics)) {\n for (const err of errorsOf(diagnostics)) {\n console.error(formatDiagnostic(err));\n }\n}\nfor (const warning of warningsOf(diagnostics)) {\n console.warn(formatDiagnostic(warning));\n}\n```\n\n## Schema-Validated Plain Data\n\n`AnalyzeResultJson.diagnostics` is `Array<Diagnostic>` — no wrapper object,\nno methods, no private fields. Round-trip-safe through `JSON.stringify` /\n`z.array(Diagnostic).parse` and symmetric with `AnalyzeResultJson.modules`\n(also Zod-validated). The full envelope is itself a Zod schema\n(`AnalyzeResultJson` in `analyze-core.ts`) with both fields defaulting to\n`[]`, so the whole `{modules, diagnostics}` shape round-trips through\n`JSON.stringify(result, compactReplacer)` / `AnalyzeResultJson.parse` even\nwhen one or both arrays are empty (the wire form becomes `{}` and `.parse()`\nrestores the defaults). Use the free helpers `hasErrors`, `errorsOf`,\n`byKind` for queries; mutate the array with native `Array.push`.\n\n## File Path Contract\n\n`Diagnostic.file` is always project-root-relative — no leading slash,\nno `./` prefix. `analyze` / `analyzeFromFiles` normalize paths from all\nsources (extraction, discovery, dependency resolution) before returning.\nConsumers that need an absolute path can rejoin with `projectRoot`.", "dependents": [ "analyze-core.ts", "analyze.ts", "cli.ts", "discovery.ts", "exports.ts", "index.ts", "session.ts", "svelte.ts", "typescript-exports.ts", "typescript-extract-class.ts", "typescript-extract-function.ts", "typescript-extract-shared.ts", "typescript-extract-type-properties.ts", "typescript-extract-type.ts", "vite.ts" ] }