sveld 0.34.1 → 0.35.1

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.
Files changed (42) hide show
  1. package/README.md +357 -89
  2. package/cli.js +6 -1
  3. package/lib/ComponentParser.d.ts +229 -568
  4. package/lib/ast-guards.d.ts +7 -1
  5. package/lib/browser.d.ts +39 -0
  6. package/lib/browser.js +290 -0
  7. package/lib/bundle.d.ts +23 -3
  8. package/lib/check.d.ts +6 -0
  9. package/lib/cli.d.ts +18 -18
  10. package/lib/diagnostics.d.ts +5 -1
  11. package/lib/example-check.d.ts +3 -1
  12. package/lib/index.js +306 -720
  13. package/lib/load-config.d.ts +20 -2
  14. package/lib/parse-exports.d.ts +5 -1
  15. package/lib/parser/bindings.d.ts +6 -0
  16. package/lib/parser/context.d.ts +114 -0
  17. package/lib/parser/contexts.d.ts +19 -0
  18. package/lib/parser/diagnostics.d.ts +8 -0
  19. package/lib/parser/events.d.ts +23 -0
  20. package/lib/parser/generics.d.ts +24 -0
  21. package/lib/parser/jsdoc.d.ts +59 -0
  22. package/lib/parser/props.d.ts +73 -0
  23. package/lib/parser/rest-props.d.ts +6 -0
  24. package/lib/parser/runes-detection.d.ts +16 -0
  25. package/lib/parser/runes-props.d.ts +18 -0
  26. package/lib/parser/scopes.d.ts +58 -0
  27. package/lib/parser/slots.d.ts +29 -0
  28. package/lib/parser/source-position.d.ts +30 -0
  29. package/lib/parser/type-resolution.d.ts +32 -0
  30. package/lib/parser/typescript-casts.d.ts +2 -0
  31. package/lib/plugin.d.ts +7 -3
  32. package/lib/resolve-types.d.ts +1 -1
  33. package/lib/sveld.d.ts +6 -19
  34. package/lib/writer/MarkdownWriterBase.d.ts +2 -1
  35. package/lib/writer/Writer.d.ts +13 -49
  36. package/lib/writer/WriterMarkdown.d.ts +1 -1
  37. package/lib/writer/format-generated-ts.d.ts +8 -0
  38. package/lib/writer/writer-custom-elements-core.d.ts +86 -0
  39. package/lib/writer/writer-custom-elements.d.ts +15 -0
  40. package/lib/writer/writer-ts-definitions-core.d.ts +12 -1
  41. package/lib/writer/writer-ts-definitions.d.ts +4 -3
  42. package/package.json +6 -4
@@ -1,6 +1,10 @@
1
+ import type { Property } from "estree";
2
+ import type { Node } from "estree-walker";
1
3
  import type { SveldDiagnostic } from "./diagnostics";
4
+ /** Returns `value`, or `undefined` when it's `undefined` or the empty string. */
5
+ export declare function assignValue(value?: "" | string): string | undefined;
2
6
  /** Structured JSDoc tag (e.g. `{ name: "since", body: "1.2.0" }`). */
3
- interface JsDocPassthroughTag {
7
+ export interface JsDocPassthroughTag {
4
8
  name: string;
5
9
  body: string;
6
10
  }
@@ -8,6 +12,11 @@ interface JsDocPassthroughTag {
8
12
  * From `@deprecated` JSDoc: a message string, or `true` when the tag has no message.
9
13
  */
10
14
  export type DeprecatedValue = string | true;
15
+ export interface LegacyAstRoot {
16
+ module?: Node;
17
+ html?: Node;
18
+ instance?: Node;
19
+ }
11
20
  export interface SourcePosition {
12
21
  /** 1-based source line number */
13
22
  line: number;
@@ -18,11 +27,78 @@ export interface SourceRange {
18
27
  start: SourcePosition;
19
28
  end: SourcePosition;
20
29
  }
30
+ export interface RunesPropTypeMetadata {
31
+ optional: boolean;
32
+ source?: SourceRange;
33
+ type: string;
34
+ }
35
+ export interface RunesPropsDeclarationMetadata {
36
+ canonicalType?: string;
37
+ props: Map<string, RunesPropTypeMetadata>;
38
+ referencedImportedTypes: Set<string>;
39
+ referencedLocalTypes: Set<string>;
40
+ }
41
+ export type ModernRunesTypeNode = {
42
+ type?: string;
43
+ id?: {
44
+ name?: string;
45
+ };
46
+ start?: number;
47
+ end?: number;
48
+ body?: {
49
+ body?: ModernRunesTypeMember[];
50
+ };
51
+ typeAnnotation?: ModernRunesTypeNode;
52
+ typeName?: unknown;
53
+ types?: ModernRunesTypeNode[];
54
+ members?: ModernRunesTypeMember[];
55
+ /** Declaration-side `<T, U = Default>` (interfaces/type aliases). */
56
+ typeParameters?: {
57
+ params?: Array<{
58
+ name?: string;
59
+ }>;
60
+ };
61
+ /** Reference-side `<string, number>` concrete arguments (`TSTypeReference`). */
62
+ typeArguments?: {
63
+ params?: ModernRunesTypeNode[];
64
+ };
65
+ };
66
+ export type ModernRunesTypeMember = {
67
+ type?: string;
68
+ computed?: boolean;
69
+ optional?: boolean;
70
+ start?: number;
71
+ end?: number;
72
+ key?: Property["key"];
73
+ typeAnnotation?: {
74
+ start?: number;
75
+ end?: number;
76
+ typeAnnotation?: ModernRunesTypeNode;
77
+ };
78
+ };
79
+ export interface TypeImportBinding {
80
+ importedName?: string;
81
+ localName: string;
82
+ source: string;
83
+ specifierType: "default" | "named" | "namespace";
84
+ }
85
+ export interface LocalTypeDeclaration {
86
+ code: string;
87
+ node: ModernRunesTypeNode;
88
+ start: number;
89
+ }
21
90
  export interface ParsedComponentTypeScriptMetadata {
22
91
  canonicalPropsType?: string;
23
92
  canonicalPropNames: string[];
24
93
  localTypeDeclarations: string[];
25
94
  typeImportStatements: string[];
95
+ /**
96
+ * Whether `canonicalPropsType` mentions one of the component's own
97
+ * `<script generics="...">` parameters (e.g. `Props<T>`). The semantic
98
+ * resolver has no binding for `T`, so `resolveTypes` must leave this
99
+ * component's props as their AST-derived text rather than expand them.
100
+ */
101
+ referencesComponentGenerics?: boolean;
26
102
  }
27
103
  export declare const PARSED_COMPONENT_TYPE_SCRIPT_METADATA: unique symbol;
28
104
  export declare function getParsedComponentTypeScriptMetadata(component: {
@@ -37,15 +113,44 @@ export interface ResolvedComponentProp {
37
113
  }
38
114
  /** Append checker-resolved props. Names the AST walker already found are left alone. */
39
115
  export declare function applyResolvedProps(component: ParsedComponent, resolved: ResolvedComponentProp[]): void;
40
- type SyntaxMode = "legacy" | "runes";
41
- type ScriptLanguage = "js" | "ts";
42
- type ComponentPropTypeSource = "typescript" | "jsdoc" | "default" | "inferred" | "unknown";
43
- type ComponentPropDefaultValueKind = "literal" | "array" | "object" | "expression" | "function" | "unknown";
44
- interface ComponentPropDefaultValue {
116
+ export type SyntaxMode = "legacy" | "runes";
117
+ export type ScriptLanguage = "js" | "ts";
118
+ export type ScopeBindingKind = "prop" | "local";
119
+ export type ScopeBinding = {
120
+ kind: ScopeBindingKind;
121
+ publicPropName?: string;
122
+ };
123
+ export type LexicalScope = Map<string, ScopeBinding>;
124
+ export type ComponentPropTypeSource = "typescript" | "jsdoc" | "default" | "inferred" | "unknown";
125
+ export type ComponentPropDefaultValueKind = "literal" | "array" | "object" | "expression" | "function" | "unknown";
126
+ export interface ComponentPropDefaultValue {
45
127
  raw: string;
46
128
  kind: ComponentPropDefaultValueKind;
47
129
  value?: unknown;
48
130
  }
131
+ export interface ProcessedInitializer {
132
+ value?: string;
133
+ type?: string;
134
+ isFunction: boolean;
135
+ defaultValue?: ComponentPropDefaultValue;
136
+ /** JSDoc from identifier default when the prop has none. */
137
+ resolvedType?: string;
138
+ resolvedDescription?: string;
139
+ resolvedParams?: ComponentPropParam[];
140
+ resolvedReturnType?: string;
141
+ }
142
+ type ModernScriptAttribute = {
143
+ name?: string;
144
+ value?: Array<{
145
+ data?: string;
146
+ raw?: string;
147
+ }> | boolean;
148
+ start?: number;
149
+ end?: number;
150
+ };
151
+ export type ModernScriptNode = {
152
+ attributes?: ModernScriptAttribute[];
153
+ };
49
154
  /**
50
155
  * Diagnostic information for component parsing.
51
156
  *
@@ -58,20 +163,13 @@ interface ComponentParserDiagnostics {
58
163
  /** The file path to the component (e.g., "./Button.svelte") */
59
164
  filePath: string;
60
165
  }
61
- /**
62
- * Options for configuring the ComponentParser behavior.
63
- */
64
- interface ComponentParserOptions {
65
- /** Enable verbose logging for debugging parsing issues */
66
- verbose?: boolean;
67
- }
68
- type ComponentPropBinding = "readonly" | "writable";
166
+ export type ComponentPropBinding = "readonly" | "writable";
69
167
  /**
70
168
  * Parameter information for function props.
71
169
  *
72
170
  * Extracted from JSDoc `@param` tags to provide detailed function signatures.
73
171
  */
74
- interface ComponentPropParam {
172
+ export interface ComponentPropParam {
75
173
  /** The parameter name */
76
174
  name: string;
77
175
  /** The parameter type (e.g., "string", "number", "CustomType") */
@@ -157,13 +255,62 @@ export interface ComponentSlot {
157
255
  /** Source range for the slot/snippet declaration or documentation tag, when available */
158
256
  source?: SourceRange;
159
257
  }
258
+ /**
259
+ * Slot prop value definition.
260
+ *
261
+ * Used internally to track slot prop types and whether they should be
262
+ * replaced with prop type references.
263
+ */
264
+ export interface SlotPropValue {
265
+ /** The prop type value or reference */
266
+ value?: string;
267
+ /** Whether this value should be replaced with a prop type reference */
268
+ replace: boolean;
269
+ }
270
+ export type SlotProps = Record<string, SlotPropValue>;
271
+ /**
272
+ * Internal representation of {@link ComponentSlot} used while parsing.
273
+ *
274
+ * `slot_props` is either raw TS type text (from a JSDoc `@slot`/`@snippet` tag,
275
+ * used as-is) or a structured {@link SlotProps} map (from template parsing,
276
+ * formatted into TS type text once at the end of the parse). Keeping it
277
+ * structured until then avoids a JSON.stringify/JSON.parse round-trip per slot.
278
+ */
279
+ export type InternalComponentSlot = Omit<ComponentSlot, "slot_props"> & {
280
+ slot_props?: string | SlotProps;
281
+ };
282
+ /**
283
+ * Event that is forwarded from a child component or element.
284
+ *
285
+ * Forwarded events are those that use `on:eventname` syntax without
286
+ * a handler, passing the event through to the parent.
287
+ */
288
+ export interface ForwardedEvent {
289
+ /** Always "forwarded" for forwarded events */
290
+ type: "forwarded";
291
+ /** The event name (e.g., "click", "change") */
292
+ name: string;
293
+ /** The element or component that forwards this event */
294
+ element: ComponentInlineElement | ComponentElement;
295
+ /** Description extracted from JSDoc `@event` tags */
296
+ description?: string;
297
+ /** From `@deprecated` JSDoc. */
298
+ deprecated?: DeprecatedValue;
299
+ /** The detail type if explicitly specified in `@event` tag */
300
+ detail?: string;
301
+ /** Structured `@since` / `@example` tags, in source order. */
302
+ tags?: JsDocPassthroughTag[];
303
+ /** Source range for the forwarded event declaration or documentation tag, when available */
304
+ source?: SourceRange;
305
+ }
160
306
  /**
161
307
  * Event that is dispatched by the component.
162
308
  *
163
- * Dispatched events are those created with `createEventDispatcher()`
164
- * and dispatched via `dispatch("eventname", detail)`.
309
+ * Dispatched events are those created with `createEventDispatcher()` and
310
+ * dispatched via `dispatch("eventname", detail)`, or dispatched from a custom
311
+ * element via `$host().dispatchEvent(new CustomEvent("eventname", { detail }))`.
165
312
  */
166
- interface DispatchedEvent {
313
+ export interface DispatchedEvent {
167
314
  /** Always "dispatched" for dispatched events */
168
315
  type: "dispatched";
169
316
  /** The event name (e.g., "click", "change") */
@@ -179,6 +326,7 @@ interface DispatchedEvent {
179
326
  /** Source range for the dispatched event call or documentation tag, when available */
180
327
  source?: SourceRange;
181
328
  }
329
+ export type ComponentEvent = ForwardedEvent | DispatchedEvent;
182
330
  /**
183
331
  * Serialized version of {@link ForwardedEvent} for JSON output.
184
332
  *
@@ -223,7 +371,7 @@ export type SerializedComponentEvent = SerializedForwardedEvent | DispatchedEven
223
371
  * Represents custom types defined in component comments that can be
224
372
  * referenced by props, events, and other type annotations.
225
373
  */
226
- interface TypeDef {
374
+ export interface TypeDef {
227
375
  /** The type string representation (e.g., "{ x: number; y: number }") */
228
376
  type: string;
229
377
  /** The type name (e.g., "Point", "User") */
@@ -233,19 +381,19 @@ interface TypeDef {
233
381
  /** The full TypeScript type definition string (e.g., "type Point = { x: number; y: number }") */
234
382
  ts: string;
235
383
  }
236
- type ComponentGenerics = [name: string, type: string] | null;
384
+ export type ComponentGenerics = [name: string, type: string] | null;
237
385
  /**
238
386
  * Represents an inline Svelte component element.
239
387
  *
240
388
  * Used to identify which component forwards an event or accepts rest props.
241
389
  */
242
- interface ComponentInlineElement {
390
+ export interface ComponentInlineElement {
243
391
  /** Always "InlineComponent" for component elements */
244
392
  type: "InlineComponent";
245
393
  /** The component name (e.g., "Button", "Modal") */
246
394
  name: string;
247
395
  }
248
- interface ComponentElement {
396
+ export interface ComponentElement {
249
397
  type: "Element";
250
398
  name: string;
251
399
  /**
@@ -269,25 +417,28 @@ interface ComponentElement {
269
417
  /** Inline or block description from the `@restProps` JSDoc tag */
270
418
  description?: string;
271
419
  }
272
- type RestProps = undefined | ComponentInlineElement | ComponentElement;
420
+ export type RestProps = undefined | ComponentInlineElement | ComponentElement;
273
421
  /**
274
422
  * Interface extension information from JSDoc `@extends` tag.
275
423
  *
276
424
  * Allows components to extend external TypeScript interfaces for
277
425
  * better type safety and code reuse.
278
426
  */
279
- interface Extends {
427
+ export interface Extends {
280
428
  /** The interface name to extend (e.g., "ButtonProps") */
281
429
  interface: string;
282
430
  /** The import path for the interface (e.g., "./types" or "carbon-components-svelte") */
283
431
  import: string;
284
432
  }
433
+ export interface ComponentPropBindings {
434
+ elements: string[];
435
+ }
285
436
  /**
286
437
  * Property definition for a component context.
287
438
  *
288
439
  * Represents a single property in a context object created with `setContext`.
289
440
  */
290
- interface ComponentContextProp {
441
+ export interface ComponentContextProp {
291
442
  /** The property name */
292
443
  name: string;
293
444
  /** The property type (inferred from JSDoc or variable types) */
@@ -303,7 +454,7 @@ interface ComponentContextProp {
303
454
  * Represents a context created with `setContext(key, value)` that can be
304
455
  * accessed by child components via `getContext(key)`.
305
456
  */
306
- interface ComponentContext {
457
+ export interface ComponentContext {
307
458
  /** The context key (e.g., "modal", "tabs") */
308
459
  key: string;
309
460
  /** The generated TypeScript type name (e.g., "ModalContext", "TabsContext") */
@@ -365,6 +516,8 @@ export interface ParsedComponent {
365
516
  componentCommentSource?: SourceRange;
366
517
  /** Contexts created with `setContext` in the component */
367
518
  contexts?: ComponentContext[];
519
+ /** Custom-element tag name from `<svelte:options customElement="x-foo" />` (or the object form's `tag`), when present */
520
+ customElementTag?: string;
368
521
  /**
369
522
  * Type guesses from this parse (unknown props, `any` contexts, orphan `@event` tags).
370
523
  * Set on every {@link ComponentParser.parseSvelteComponent} call.
@@ -374,209 +527,39 @@ export interface ParsedComponent {
374
527
  [PARSED_COMPONENT_TYPE_SCRIPT_METADATA]?: ParsedComponentTypeScriptMetadata;
375
528
  }
376
529
  export default class ComponentParser {
377
- /** Parser configuration options (e.g., verbose logging) */
378
- private options?;
379
- /** Whether the component uses legacy or runes syntax according to compiler metadata */
380
- private syntaxMode;
381
- /** Language used by the component's instance or module script, when supported */
382
- private scriptLanguage?;
383
- /** Raw source code of the Svelte component being parsed */
384
- private source?;
385
- /** Compiled Svelte code containing extracted variables and AST */
386
- private compiled?;
387
- /** Parsed abstract syntax tree from the Svelte compiler */
388
- private parsed?;
389
- /** Rest props configuration (e.g., `$$restProps`) if present in component */
390
- private rest_props?;
391
- /** Component extension information (e.g., `extends` attribute) */
392
- private extends?;
393
- /** Component-level description extracted from `@component` HTML comment */
394
- private componentComment?;
395
- /** Source range for the `@component` HTML comment, when available */
396
- private componentCommentSource?;
397
- /** Set of reactive variable names found in the component */
398
- private readonly reactive_vars;
399
- /** Set of all variable declarations found in the component script */
400
- private readonly vars;
401
- /** Function declarations in the component script, by name */
402
- private readonly funcDecls;
403
- /** Map of component props keyed by prop name */
404
- private readonly props;
405
- /** Map of module exports (functions/variables exported from script) keyed by name */
406
- private readonly moduleExports;
407
- /** Map of component slots keyed by slot name (null for default slot) */
408
- private readonly slots;
409
- /** Map of component events (dispatched events) keyed by event name */
410
- private readonly events;
411
- /** Map of event descriptions extracted from JSDoc comments keyed by event name */
412
- private readonly eventDescriptions;
413
- /** Map of forwarded events (events forwarded from child components) keyed by event name */
414
- private readonly forwardedEvents;
415
- /** Map of type definitions (typedefs) extracted from JSDoc comments keyed by type name */
416
- private readonly typedefs;
417
- /** Component generic type parameters (null if no generics) */
418
- private generics;
419
- /** @template tags in a @slot/@snippet block (no @extends), held until finalization. */
420
- private deferredSlotBlockGenerics;
421
- /** Map of prop bindings (e.g., `bind:value`) keyed by prop name */
422
- private readonly bindings;
423
- /** Map of component contexts (created with `setContext`) keyed by context name */
424
- private readonly contexts;
425
- /** Cache for variable type and description information to avoid redundant lookups */
426
- private variableInfoCache;
427
- /** Maps local binding names back to their public prop names */
428
- private readonly propLocalToPublicName;
429
- /** Tracks `$props()` bindings that are used as spread/rest props */
430
- private readonly restPropLocals;
431
- /** Tracks identifier bindings that capture the entire `$props()` object */
432
- private readonly wholePropsLocals;
433
- /** Tracks prop locals that are used as snippet/render props */
434
- private readonly snippetPropLocals;
435
- /** Per-declarator type metadata extracted from modern AST `$props()` annotations */
436
- private readonly runesPropsDeclarationMetadataByDeclaratorStart;
437
- /** Explicit TypeScript prop annotations for legacy `export let` declarations keyed by local name */
438
- private readonly explicitPropTypesByName;
439
- /** Type-only imports keyed by their local binding names */
440
- private readonly typeImportBindingsByLocalName;
441
- /** Local interface/type declarations keyed by type name */
442
- private readonly localTypeDeclarationsByName;
443
- /** Typed `$props()` declarations discovered in source order */
444
- private readonly typedRunesPropsDeclarations;
445
- /** Component-level lexical scope shared by instance script and template */
446
- private readonly componentScope;
447
- /** Precomputed lexical scopes for nested AST nodes */
448
- private scopeDeclarations;
449
- /** Active lexical scopes while walking the component AST */
450
- private readonly activeScopes;
451
- /** Diagnostics for the parse in progress. */
452
- private readonly diagnosticRecords;
453
- /** File path tagged onto each diagnostic. */
454
- private componentFilePath;
455
- /** `@event` names from JSDoc, checked against dispatches at end of parse. */
456
- private readonly jsDocEventNames;
457
- /** Cached array of source code lines split by newline for efficient line-based operations */
458
- private sourceLinesCache?;
459
- /** Cached 0-based source offsets for the start of each line */
460
- private sourceLineStartOffsetsCache?;
461
- constructor(options?: ComponentParserOptions);
530
+ /**
531
+ * All per-parse mutable state (props, slots, events, scopes, source, etc.).
532
+ * See {@link ParserContext} for field-by-field documentation. Replaced
533
+ * wholesale by `cleanup()` between parses.
534
+ */
535
+ private ctx;
462
536
  private static mapToArray;
463
537
  private static getStaticAttributeValue;
464
- private static resolveScriptLanguage;
538
+ resolveScriptLanguage(parsed: {
539
+ instance?: ModernScriptNode;
540
+ module?: ModernScriptNode;
541
+ }): ScriptLanguage | undefined;
542
+ /**
543
+ * Reads the `generics` attribute off the instance script (Svelte only allows
544
+ * it there, and only alongside `lang="ts"`). Returns the raw value for later
545
+ * precedence resolution against `@generics`/`@template` JSDoc tags, or
546
+ * `undefined` if absent. Records a `syntax-skipped` diagnostic and returns
547
+ * `undefined` if the attribute is present without `lang="ts"`, since sveld
548
+ * can't safely guess how to parse it as plain JavaScript.
549
+ */
550
+ resolveScriptGenericsAttribute(parsed: {
551
+ instance?: ModernScriptNode;
552
+ }): {
553
+ value: string;
554
+ source?: SourceRange;
555
+ } | undefined;
465
556
  private static assignValue;
466
- private recordDiagnostic;
467
557
  private resolvePublicPropName;
468
- private trackPropLocalName;
558
+ trackPropLocalName(propName: string, localName?: string): void;
469
559
  private getPropByLocalOrPublic;
470
- private getPropTypeByLocalOrPublic;
471
- private getExplicitPropType;
472
- private getRunesPropsDeclarationMetadata;
473
- private getRunesPropTypeMetadata;
474
- private getTypeReferenceName;
475
- private getTypeDependencyName;
476
- private getTypeAnnotationText;
477
- private getSourceLineStartOffsets;
478
- private sourcePositionFromOffset;
479
- private sourceRangeFromOffsets;
480
- private sourceRangeFromNode;
481
- private sourceRangeFromCommentTag;
482
- private collectReferencedTypeDependencies;
483
- private buildTypeImportStatements;
484
- private buildTypeScriptMetadata;
485
- private buildRunesPropTypeMetadataMap;
486
- private declareScopeBinding;
487
- private resolveIdentifierToReactiveProp;
488
- private collectPatternIdentifiers;
489
- private markReactivePropsFromMutationTarget;
490
- private isScopeOwner;
491
- private isFunctionScopeOwner;
492
- private getOrCreateScope;
493
- private declareVariableDeclaration;
494
- private declareFunctionLikeScopeBindings;
495
- private collectDirectBlockDeclarations;
496
- private extractRunesScopeBindings;
497
- private collectComponentScopeDeclarations;
498
- private collectNestedScopeDeclarations;
499
- private buildScopeDeclarations;
500
- private createRestPropsFromParent;
501
- private maybeSetRestProps;
502
- private getPropertyName;
503
- private logUnsupportedRunesPattern;
504
- private logParserWarning;
505
- private static formatComment;
506
- /**
507
- * Extracts and categorizes JSDoc tags from a parsed comment.
508
- *
509
- * Separates tags into type, param, returns, and additional categories while
510
- * excluding tags that are handled separately (extends, restProps, slot/snippet, event, typedef).
511
- *
512
- * @param parsed - The parsed comment result from comment-parser
513
- * @returns An object containing categorized tags and the comment description
514
- *
515
- * @example
516
- * ```ts
517
- * // Input: Parsed comment with tags
518
- * // Output:
519
- * {
520
- * type: { tag: "type", type: "string" },
521
- * param: [
522
- * { tag: "param", name: "value", type: "string" }
523
- * ],
524
- * returns: { tag: "returns", type: "void" },
525
- * additional: [{ tag: "see", name: "OtherType" }],
526
- * passthrough: [{ tag: "since", name: "1.0.0" }],
527
- * description: "Main description text"
528
- * }
529
- * ```
530
- */
531
- private getCommentTags;
532
- /**
533
- * Finds the last comment from an array of leading comments.
534
- *
535
- * TypeScript directives are stripped before parsing, so we can safely take
536
- * the last comment as it will be the JSDoc comment if present.
537
- *
538
- * @param leadingComments - Array of comment nodes from the AST
539
- * @returns The last comment's value if found, undefined otherwise
540
- *
541
- * @example
542
- * ```ts
543
- * // Given leadingComments with multiple comments:
544
- * // [/* regular comment *\/, /** JSDoc comment *\/]
545
- * // Returns: { value: " JSDoc comment " }
546
- *
547
- * // If no comments:
548
- * // Returns: undefined
549
- * ```
550
- */
551
- private static findJSDocComment;
552
- private findAdjacentJSDocComment;
553
- private processNodeJSDoc;
554
- private processLeadingCommentsJSDoc;
555
- /**
556
- * Processes JSDoc comments from leadingComments and extracts structured information.
557
- *
558
- * Parses JSDoc comments to extract type information, parameters, return types,
559
- * and descriptions. Handles both inline and block-level descriptions.
560
- *
561
- * @param leadingComments - Array of comment nodes from the AST
562
- * @returns Structured JSDoc information or undefined if no JSDoc comment is found
563
- *
564
- * @example
565
- * ```ts
566
- * // Input JSDoc:
567
- * /**
568
- * * @type {string}
569
- * * @param {number} x - The x coordinate
570
- * * @param {number} y - The y coordinate
571
- * * @returns {void}
572
- * * Description text
573
- * *\/
574
- * // Output:
575
- * { type: "string", params: [ { name: "x", type: "number", description: "The x coordinate", optional: false }, { name: "y", type: "number", description: "The y coordinate", optional: false } ], returnType: "void", description: "Description text" }
576
- * ```
577
- */
578
- private processJSDocComment;
579
- private buildRunesPropTypeMetadata;
560
+ getPropTypeByLocalOrPublic(name: string): string | undefined;
561
+ getExplicitPropType(name: string): string | undefined;
562
+ getPropertyName(node: Property["key"]): string | undefined;
580
563
  /**
581
564
  * Checks if a MemberExpression represents a well-known numeric constant.
582
565
  *
@@ -599,135 +582,25 @@ export default class ComponentParser {
599
582
  * Number.UNKNOWN // false
600
583
  * ```
601
584
  */
602
- private isNumericConstant;
603
- /**
604
- * Extracts source code at the given position range.
605
- *
606
- * @param start - Start position in the source
607
- * @param end - End position in the source
608
- * @returns The source code substring, or undefined if source is not available
609
- */
610
- private sourceAtPos;
611
- private sourceForExpression;
612
- private jsonSafeValueFromExpression;
613
- private classifyDefaultValue;
614
- private resolveTypeSource;
615
- /**
616
- * Processes an initializer expression to extract its value, type, and function status.
617
- *
618
- * Handles various expression types including object literals, arrays, binary expressions,
619
- * arrow functions, unary expressions, identifiers, member expressions, template literals,
620
- * and primitive literals. Extracts the source code representation and infers types
621
- * where possible.
622
- *
623
- * @param init - The initializer AST node
624
- * @returns An object containing the value (source code), inferred type, and whether it's a function
625
- *
626
- * @example
627
- * ```ts
628
- * // ObjectExpression: { x: 1, y: 2 }
629
- * // Returns: { value: "{ x: 1, y: 2 }", type: "{ x: 1, y: 2 }", isFunction: false }
630
- *
631
- * // ArrowFunctionExpression: () => {}
632
- * // Returns: { value: undefined, type: "(...args: any[]) => any", isFunction: true }
633
- *
634
- * // Literal: "hello"
635
- * // Returns: { value: '"hello"', type: "string", isFunction: false }
636
- *
637
- * // BinaryExpression: "a" + "b"
638
- * // Returns: { value: '"a" + "b"', type: "string", isFunction: false }
639
- *
640
- * // MemberExpression: Math.PI
641
- * // Returns: { value: "Math.PI", type: "number" (if numeric constant), isFunction: false }
642
- * ```
643
- */
644
- private processInitializer;
645
- /**
646
- * Look up a local variable's initializer AST node by name.
647
- * Returns the init node if found, or undefined.
648
- */
649
- private resolveLocalVarInitializer;
650
- /**
651
- * Look up the initializer for a local `const` by name.
652
- *
653
- * {@link resolveLocalVarInitializer} also walks `let`/`var`. This method does not.
654
- * Props and mutable bindings can change at runtime, so they cannot be context keys.
655
- *
656
- * @param name - The variable name to look up
657
- * @returns The initializer node for a matching `const` binding, or undefined
658
- */
659
- private resolveConstInitializer;
585
+ isNumericConstant(memberExpr: unknown): boolean;
586
+ resolveTypeSource({ hasTypeScriptType, hasJSDocType, inferredType, finalType, }: {
587
+ hasTypeScriptType?: boolean;
588
+ hasJSDocType?: boolean;
589
+ inferredType?: string;
590
+ finalType?: string;
591
+ }): ComponentPropTypeSource;
660
592
  /**
661
593
  * Look up JSDoc on a local variable declaration by name.
662
594
  */
663
- private resolveLocalVarJSDoc;
664
- /**
665
- * Build a function type from `@param`/`@returns` when `@type` is missing.
666
- * If JSDoc has no params or return either, try the function `node`, then
667
- * `(...args: any[]) => any`.
668
- */
669
- private buildFunctionTypeFromParts;
670
- /**
671
- * Guess arity and return type for a function default with no JSDoc `@type`.
672
- * Explicit `@type`/`@param`/`@returns` on the prop beat this every time.
673
- * A default's body is a weak signal for the prop contract. We only read
674
- * named params and literal returns. Everything else becomes `any`.
675
- */
676
- private inferFunctionTypeFromNode;
677
- /**
678
- * Turn params into `name: any`, or use `...args: any[]` when arity is unclear:
679
- * no params, destructuring, rest, or defaults.
680
- */
681
- private inferParamsFromNode;
682
- /**
683
- * Infer return type from literal returns only. Every `return` must agree on
684
- * the same primitive. Bare `return;`, no returns, identifiers, calls,
685
- * objects, ternaries, async, or generators all become `any`.
686
- */
687
- private inferReturnTypeFromNode;
688
- /**
689
- * Walk a block body and collect each `return`'s argument, skipping nested
690
- * functions. Bare `return;` becomes `null`.
691
- */
692
- private collectReturnArguments;
693
- /**
694
- * Map one return expression to `string`, `number`, or `boolean`, or `null`
695
- * if it isn't a literal, template literal, or `String`/`Number`/`Boolean` call.
696
- */
697
- private inferReturnPrimitive;
698
- /**
699
- * Unwraps `$bindable(...)` calls so defaults are documented as their underlying values.
700
- */
701
- private unwrapBindableInitializer;
702
- /**
703
- * Extracts component props from top-level `$props()` declarations in runes components.
704
- */
705
- private parseRunesPropsDeclaration;
706
- private inferSlotPropValueFromExpression;
707
- private buildSlotPropsFromObjectExpression;
708
- private resolveRenderTagPropReference;
709
- private extractRenderTagInfo;
710
- /**
711
- * Adds or merges a component prop to the props map.
712
- *
713
- * If a prop with the same name already exists, the new data is merged
714
- * with the existing prop, with new values taking precedence.
715
- *
716
- * @param prop_name - The name of the prop
717
- * @param data - The prop data to add or merge
718
- *
719
- * @example
720
- * ```ts
721
- * // First call:
722
- * addProp("count", { name: "count", type: "number", kind: "let" })
723
- * // Props map: { "count" => { name: "count", type: "number", kind: "let" } }
724
- *
725
- * // Second call (merge):
726
- * addProp("count", { description: "The count value" })
727
- * // Props map: { "count" => { name: "count", type: "number", kind: "let", description: "The count value" } }
728
- * ```
729
- */
730
- private addProp;
595
+ resolveLocalVarJSDoc(name: string): {
596
+ type?: string;
597
+ params?: ComponentPropParam[];
598
+ returnType?: string;
599
+ description?: string;
600
+ binding?: ComponentPropBinding;
601
+ deprecated?: DeprecatedValue;
602
+ tags?: JsDocPassthroughTag[];
603
+ } | undefined;
731
604
  /**
732
605
  * Adds or merges a module export to the moduleExports map.
733
606
  *
@@ -766,157 +639,7 @@ export default class ComponentParser {
766
639
  * aliasType("number") // Returns: "number"
767
640
  * ```
768
641
  */
769
- private aliasType;
770
- /**
771
- * Extracts a property's type from an object type string.
772
- *
773
- * Parses type strings like `{ value: string; other: number }` and returns
774
- * the type for the requested property name. Handles nested braces, generics,
775
- * and optional properties.
776
- *
777
- * @returns The property type string, or undefined if not found
778
- */
779
- private extractPropertyType;
780
- /**
781
- * Resolves the type of a MemberExpression (e.g., `obj.value`) by looking up
782
- * the object's type annotation and extracting the property type.
783
- *
784
- * @returns The resolved type string, or undefined if it cannot be resolved
785
- */
786
- private resolveMemberExpressionType;
787
- /**
788
- * Adds or merges a slot definition to the slots map.
789
- *
790
- * Handles both named slots and the default slot. If a slot with the same
791
- * name already exists, merges the data with existing values taking precedence
792
- * where appropriate.
793
- *
794
- * @param slot_name - Optional slot name (undefined/empty = default slot)
795
- * @param slot_props - Optional slot props type definition
796
- * @param slot_fallback - Optional fallback content for the slot
797
- * @param slot_description - Optional description for the slot
798
- *
799
- * @example
800
- * ```ts
801
- * // Default slot:
802
- * addSlot({ slot_name: undefined, slot_props: "{ children: string }" })
803
- *
804
- * // Named slot:
805
- * addSlot({
806
- * slot_name: "header",
807
- * slot_props: "{ title: string }",
808
- * slot_description: "Header slot with title prop"
809
- * })
810
- *
811
- * // Slot with fallback:
812
- * addSlot({
813
- * slot_name: "footer",
814
- * slot_fallback: "<p>Default footer</p>"
815
- * })
816
- * ```
817
- */
818
- private addSlot;
819
- /**
820
- * Adds or merges a dispatched event to the events map.
821
- *
822
- * Handles event detail type inference: if no argument is provided to the
823
- * dispatcher and no `@event` tag specifies a detail type, the detail defaults
824
- * to `null`. Otherwise, uses the provided detail type.
825
- *
826
- * @param name - The event name
827
- * @param detail - The event detail type string
828
- * @param has_argument - Whether the dispatcher call includes a detail argument
829
- * @param description - Optional event description
830
- *
831
- * @example
832
- * ```ts
833
- * // Event without detail:
834
- * // createEventDispatcher()("click")
835
- * addDispatchedEvent({
836
- * name: "click",
837
- * detail: "",
838
- * has_argument: false,
839
- * description: "Fires on click"
840
- * })
841
- * // Result: { type: "dispatched", name: "click", detail: "null" }
842
- *
843
- * // Event with detail:
844
- * // dispatch("change", { value: 42 })
845
- * addDispatchedEvent({
846
- * name: "change",
847
- * detail: "{ value: number }",
848
- * has_argument: true,
849
- * description: "Fires when value changes"
850
- * })
851
- * // Result: { type: "dispatched", name: "change", detail: "{ value: number }" }
852
- * ```
853
- */
854
- private addDispatchedEvent;
855
- private normalizeRunesCallbackProps;
856
- /**
857
- * Parses custom types, events, slots, and other JSDoc annotations from component comments.
858
- *
859
- * Scans the entire source for JSDoc comment blocks and extracts structured information
860
- * about events, typedefs, callbacks, slots, extends, restProps, and generics. Handles complex
861
- * description extraction logic that supports both inline descriptions and preceding
862
- * line descriptions.
863
- *
864
- * @example
865
- * ```ts
866
- * // Parses comments like:
867
- * /**
868
- * * @event {CustomEvent} change - Fires when value changes
869
- * * @property {string} value - The new value
870
- * * @property {number} timestamp - When it changed
871
- * *\/
872
- *
873
- * // Or:
874
- * /**
875
- * * Description for the event
876
- * * @event change
877
- * *\/
878
- * ```
879
- */
880
- private parseCustomTypes;
881
- /**
882
- * Builds an event detail type string from an array of property definitions.
883
- *
884
- * Creates an inline object type with JSDoc comments for each property,
885
- * including descriptions and default values. Used for both event details
886
- * and typedef property definitions.
887
- *
888
- * @param properties - Array of property definitions with name, type, description, etc.
889
- * @param _eventName - Optional event name (unused, kept for API consistency)
890
- * @returns A string representation of the object type with JSDoc comments
891
- *
892
- * @example
893
- * ```ts
894
- * // Input:
895
- * [ { name: "value", type: "string", description: "The new value" }, { name: "count", type: "number", optional: true, default: "0" } ]
896
- * // Output:
897
- * "{ /** The new value *\/ value: string; /** @default 0 *\/ count?: number; }"
898
- * ```
899
- */
900
- private buildEventDetailFromProperties;
901
- /**
902
- * Generates a TypeScript type name for a context key.
903
- *
904
- * Converts kebab-case, snake_case, or space-separated keys into PascalCase
905
- * with "Context" suffix. Splits on dashes, underscores, and spaces, then
906
- * capitalizes each part.
907
- *
908
- * @param key - The context key (e.g., "simple-modal", "tabs_context", "My Context")
909
- * @returns The generated type name (e.g., "SimpleModalContext", "TabsContext", "MyContextContext")
910
- *
911
- * @example
912
- * ```ts
913
- * generateContextTypeName("simple-modal") // Returns: "SimpleModalContext"
914
- * generateContextTypeName("Tabs") // Returns: "TabsContext"
915
- * generateContextTypeName("user_settings") // Returns: "UserSettingsContext"
916
- * generateContextTypeName("my context") // Returns: "MyContextContext"
917
- * ```
918
- */
919
- private generateContextTypeName;
642
+ aliasType(type: string): string;
920
643
  /**
921
644
  * Builds a cache of variable type information from JSDoc comments.
922
645
  *
@@ -991,72 +714,10 @@ export default class ComponentParser {
991
714
  * // Returns: { type: "number", description: "The count value" }
992
715
  * ```
993
716
  */
994
- private findVariableTypeAndDescription;
995
- /**
996
- * Parses a context value from an AST node to extract type information.
997
- *
998
- * Handles two cases:
999
- * 1. ObjectExpression: Parses object literal properties and infers types from variable references
1000
- * 2. Identifier: Looks up the variable's type from JSDoc comments
1001
- *
1002
- * @param node - The AST node representing the context value
1003
- * @param key - The context key name
1004
- * @returns A ComponentContext object with parsed properties, or null if parsing fails
1005
- *
1006
- * @example
1007
- * ```ts
1008
- * // Case 1: Object literal
1009
- * // setContext('modal', { open, close })
1010
- * // Returns: { key: "modal", typeName: "ModalContext", properties: [...] }
1011
- *
1012
- * // Case 2: Variable reference
1013
- * // setContext('tabs', tabContext)
1014
- * // Returns: { key: "tabs", typeName: "TabsContext", properties: [...] }
1015
- * ```
1016
- */
1017
- private parseContextValue;
1018
- /**
1019
- * Resolve a `setContext` key to the string used in `{PascalCase}Context`.
1020
- *
1021
- * Accepts string literals, static template literals, `const`-bound identifiers
1022
- * (up to 5 indirection levels, same as `@default`), and `Symbol()` /
1023
- * `Symbol.for()`. Description-less symbols fall back to the binding name.
1024
- *
1025
- * @param keyArg - The first argument of the `setContext` call
1026
- * @param depth - Current identifier-resolution depth (internal recursion guard)
1027
- * @returns The resolved key string, or `null` when the key cannot be resolved at parse time
1028
- */
1029
- private resolveContextKey;
1030
- /**
1031
- * Extracts the description string from a `Symbol(...)` or `Symbol.for(...)` call
1032
- * used as a context key.
1033
- *
1034
- * @param node - A CallExpression or NewExpression AST node
1035
- * @returns The symbol description (`""` when the symbol has no static description),
1036
- * or `null` when the node is not a `Symbol()` / `Symbol.for()` call
1037
- */
1038
- private resolveSymbolKeyDescription;
1039
- /**
1040
- * Parses a `setContext` call expression to extract context information.
1041
- *
1042
- * Reads the context key from the first argument and the value from the second.
1043
- * Unresolved keys log a warning and are skipped.
1044
- *
1045
- * @param node - The AST node (should be a CallExpression)
1046
- * @param _parent - The parent node (unused)
1047
- *
1048
- * @example
1049
- * ```ts
1050
- * // Parses: setContext('modal', { open, close })
1051
- * // Extracts: key = "modal", value = { open, close }
1052
- *
1053
- * // Parses: const KEY = "modal"; setContext(KEY, value) // resolves to "modal"
1054
- * // Parses: setContext(Symbol("modal"), value) // resolves to "modal"
1055
- *
1056
- * // Diagnostic: setContext(dynamicKey, value) // key cannot be statically resolved
1057
- * ```
1058
- */
1059
- private parseSetContextCall;
717
+ findVariableTypeAndDescription(varName: string): {
718
+ type: string;
719
+ description?: string;
720
+ } | null;
1060
721
  /**
1061
722
  * Cleans up all parser state, resetting the instance for reuse.
1062
723
  *
@@ -1071,7 +732,7 @@ export default class ComponentParser {
1071
732
  * parser.parseSvelteComponent(source2, diagnostics2); // Fresh parse
1072
733
  * ```
1073
734
  */
1074
- private accumulateGeneric;
735
+ accumulateGeneric(name: string, constraint: string): void;
1075
736
  cleanup(): void;
1076
737
  /**
1077
738
  * Pre-compiled regex for matching script blocks in Svelte components.