sveld 0.34.0 → 0.35.0

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.
@@ -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,6 +27,56 @@ 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
+ };
56
+ export type ModernRunesTypeMember = {
57
+ type?: string;
58
+ computed?: boolean;
59
+ optional?: boolean;
60
+ start?: number;
61
+ end?: number;
62
+ key?: Property["key"];
63
+ typeAnnotation?: {
64
+ start?: number;
65
+ end?: number;
66
+ typeAnnotation?: ModernRunesTypeNode;
67
+ };
68
+ };
69
+ export interface TypeImportBinding {
70
+ importedName?: string;
71
+ localName: string;
72
+ source: string;
73
+ specifierType: "default" | "named" | "namespace";
74
+ }
75
+ export interface LocalTypeDeclaration {
76
+ code: string;
77
+ node: ModernRunesTypeNode;
78
+ start: number;
79
+ }
21
80
  export interface ParsedComponentTypeScriptMetadata {
22
81
  canonicalPropsType?: string;
23
82
  canonicalPropNames: string[];
@@ -37,15 +96,44 @@ export interface ResolvedComponentProp {
37
96
  }
38
97
  /** Append checker-resolved props. Names the AST walker already found are left alone. */
39
98
  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 {
99
+ export type SyntaxMode = "legacy" | "runes";
100
+ export type ScriptLanguage = "js" | "ts";
101
+ export type ScopeBindingKind = "prop" | "local";
102
+ export type ScopeBinding = {
103
+ kind: ScopeBindingKind;
104
+ publicPropName?: string;
105
+ };
106
+ export type LexicalScope = Map<string, ScopeBinding>;
107
+ export type ComponentPropTypeSource = "typescript" | "jsdoc" | "default" | "inferred" | "unknown";
108
+ export type ComponentPropDefaultValueKind = "literal" | "array" | "object" | "expression" | "function" | "unknown";
109
+ export interface ComponentPropDefaultValue {
45
110
  raw: string;
46
111
  kind: ComponentPropDefaultValueKind;
47
112
  value?: unknown;
48
113
  }
114
+ export interface ProcessedInitializer {
115
+ value?: string;
116
+ type?: string;
117
+ isFunction: boolean;
118
+ defaultValue?: ComponentPropDefaultValue;
119
+ /** JSDoc from identifier default when the prop has none. */
120
+ resolvedType?: string;
121
+ resolvedDescription?: string;
122
+ resolvedParams?: ComponentPropParam[];
123
+ resolvedReturnType?: string;
124
+ }
125
+ type ModernScriptAttribute = {
126
+ name?: string;
127
+ value?: Array<{
128
+ data?: string;
129
+ raw?: string;
130
+ }> | boolean;
131
+ start?: number;
132
+ end?: number;
133
+ };
134
+ export type ModernScriptNode = {
135
+ attributes?: ModernScriptAttribute[];
136
+ };
49
137
  /**
50
138
  * Diagnostic information for component parsing.
51
139
  *
@@ -58,20 +146,13 @@ interface ComponentParserDiagnostics {
58
146
  /** The file path to the component (e.g., "./Button.svelte") */
59
147
  filePath: string;
60
148
  }
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";
149
+ export type ComponentPropBinding = "readonly" | "writable";
69
150
  /**
70
151
  * Parameter information for function props.
71
152
  *
72
153
  * Extracted from JSDoc `@param` tags to provide detailed function signatures.
73
154
  */
74
- interface ComponentPropParam {
155
+ export interface ComponentPropParam {
75
156
  /** The parameter name */
76
157
  name: string;
77
158
  /** The parameter type (e.g., "string", "number", "CustomType") */
@@ -157,13 +238,51 @@ export interface ComponentSlot {
157
238
  /** Source range for the slot/snippet declaration or documentation tag, when available */
158
239
  source?: SourceRange;
159
240
  }
241
+ /**
242
+ * Slot prop value definition.
243
+ *
244
+ * Used internally to track slot prop types and whether they should be
245
+ * replaced with prop type references.
246
+ */
247
+ export interface SlotPropValue {
248
+ /** The prop type value or reference */
249
+ value?: string;
250
+ /** Whether this value should be replaced with a prop type reference */
251
+ replace: boolean;
252
+ }
253
+ export type SlotProps = Record<string, SlotPropValue>;
254
+ /**
255
+ * Event that is forwarded from a child component or element.
256
+ *
257
+ * Forwarded events are those that use `on:eventname` syntax without
258
+ * a handler, passing the event through to the parent.
259
+ */
260
+ export interface ForwardedEvent {
261
+ /** Always "forwarded" for forwarded events */
262
+ type: "forwarded";
263
+ /** The event name (e.g., "click", "change") */
264
+ name: string;
265
+ /** The element or component that forwards this event */
266
+ element: ComponentInlineElement | ComponentElement;
267
+ /** Description extracted from JSDoc `@event` tags */
268
+ description?: string;
269
+ /** From `@deprecated` JSDoc. */
270
+ deprecated?: DeprecatedValue;
271
+ /** The detail type if explicitly specified in `@event` tag */
272
+ detail?: string;
273
+ /** Structured `@since` / `@example` tags, in source order. */
274
+ tags?: JsDocPassthroughTag[];
275
+ /** Source range for the forwarded event declaration or documentation tag, when available */
276
+ source?: SourceRange;
277
+ }
160
278
  /**
161
279
  * Event that is dispatched by the component.
162
280
  *
163
- * Dispatched events are those created with `createEventDispatcher()`
164
- * and dispatched via `dispatch("eventname", detail)`.
281
+ * Dispatched events are those created with `createEventDispatcher()` and
282
+ * dispatched via `dispatch("eventname", detail)`, or dispatched from a custom
283
+ * element via `$host().dispatchEvent(new CustomEvent("eventname", { detail }))`.
165
284
  */
166
- interface DispatchedEvent {
285
+ export interface DispatchedEvent {
167
286
  /** Always "dispatched" for dispatched events */
168
287
  type: "dispatched";
169
288
  /** The event name (e.g., "click", "change") */
@@ -179,6 +298,7 @@ interface DispatchedEvent {
179
298
  /** Source range for the dispatched event call or documentation tag, when available */
180
299
  source?: SourceRange;
181
300
  }
301
+ export type ComponentEvent = ForwardedEvent | DispatchedEvent;
182
302
  /**
183
303
  * Serialized version of {@link ForwardedEvent} for JSON output.
184
304
  *
@@ -223,7 +343,7 @@ export type SerializedComponentEvent = SerializedForwardedEvent | DispatchedEven
223
343
  * Represents custom types defined in component comments that can be
224
344
  * referenced by props, events, and other type annotations.
225
345
  */
226
- interface TypeDef {
346
+ export interface TypeDef {
227
347
  /** The type string representation (e.g., "{ x: number; y: number }") */
228
348
  type: string;
229
349
  /** The type name (e.g., "Point", "User") */
@@ -233,19 +353,19 @@ interface TypeDef {
233
353
  /** The full TypeScript type definition string (e.g., "type Point = { x: number; y: number }") */
234
354
  ts: string;
235
355
  }
236
- type ComponentGenerics = [name: string, type: string] | null;
356
+ export type ComponentGenerics = [name: string, type: string] | null;
237
357
  /**
238
358
  * Represents an inline Svelte component element.
239
359
  *
240
360
  * Used to identify which component forwards an event or accepts rest props.
241
361
  */
242
- interface ComponentInlineElement {
362
+ export interface ComponentInlineElement {
243
363
  /** Always "InlineComponent" for component elements */
244
364
  type: "InlineComponent";
245
365
  /** The component name (e.g., "Button", "Modal") */
246
366
  name: string;
247
367
  }
248
- interface ComponentElement {
368
+ export interface ComponentElement {
249
369
  type: "Element";
250
370
  name: string;
251
371
  /**
@@ -269,25 +389,28 @@ interface ComponentElement {
269
389
  /** Inline or block description from the `@restProps` JSDoc tag */
270
390
  description?: string;
271
391
  }
272
- type RestProps = undefined | ComponentInlineElement | ComponentElement;
392
+ export type RestProps = undefined | ComponentInlineElement | ComponentElement;
273
393
  /**
274
394
  * Interface extension information from JSDoc `@extends` tag.
275
395
  *
276
396
  * Allows components to extend external TypeScript interfaces for
277
397
  * better type safety and code reuse.
278
398
  */
279
- interface Extends {
399
+ export interface Extends {
280
400
  /** The interface name to extend (e.g., "ButtonProps") */
281
401
  interface: string;
282
402
  /** The import path for the interface (e.g., "./types" or "carbon-components-svelte") */
283
403
  import: string;
284
404
  }
405
+ export interface ComponentPropBindings {
406
+ elements: string[];
407
+ }
285
408
  /**
286
409
  * Property definition for a component context.
287
410
  *
288
411
  * Represents a single property in a context object created with `setContext`.
289
412
  */
290
- interface ComponentContextProp {
413
+ export interface ComponentContextProp {
291
414
  /** The property name */
292
415
  name: string;
293
416
  /** The property type (inferred from JSDoc or variable types) */
@@ -303,7 +426,7 @@ interface ComponentContextProp {
303
426
  * Represents a context created with `setContext(key, value)` that can be
304
427
  * accessed by child components via `getContext(key)`.
305
428
  */
306
- interface ComponentContext {
429
+ export interface ComponentContext {
307
430
  /** The context key (e.g., "modal", "tabs") */
308
431
  key: string;
309
432
  /** The generated TypeScript type name (e.g., "ModalContext", "TabsContext") */
@@ -365,6 +488,8 @@ export interface ParsedComponent {
365
488
  componentCommentSource?: SourceRange;
366
489
  /** Contexts created with `setContext` in the component */
367
490
  contexts?: ComponentContext[];
491
+ /** Custom-element tag name from `<svelte:options customElement="x-foo" />` (or the object form's `tag`), when present */
492
+ customElementTag?: string;
368
493
  /**
369
494
  * Type guesses from this parse (unknown props, `any` contexts, orphan `@event` tags).
370
495
  * Set on every {@link ComponentParser.parseSvelteComponent} call.
@@ -374,209 +499,39 @@ export interface ParsedComponent {
374
499
  [PARSED_COMPONENT_TYPE_SCRIPT_METADATA]?: ParsedComponentTypeScriptMetadata;
375
500
  }
376
501
  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);
502
+ /**
503
+ * All per-parse mutable state (props, slots, events, scopes, source, etc.).
504
+ * See {@link ParserContext} for field-by-field documentation. Replaced
505
+ * wholesale by `cleanup()` between parses.
506
+ */
507
+ private ctx;
462
508
  private static mapToArray;
463
509
  private static getStaticAttributeValue;
464
- private static resolveScriptLanguage;
510
+ resolveScriptLanguage(parsed: {
511
+ instance?: ModernScriptNode;
512
+ module?: ModernScriptNode;
513
+ }): ScriptLanguage | undefined;
514
+ /**
515
+ * Reads the `generics` attribute off the instance script (Svelte only allows
516
+ * it there, and only alongside `lang="ts"`). Returns the raw value for later
517
+ * precedence resolution against `@generics`/`@template` JSDoc tags, or
518
+ * `undefined` if absent. Records a `syntax-skipped` diagnostic and returns
519
+ * `undefined` if the attribute is present without `lang="ts"`, since sveld
520
+ * can't safely guess how to parse it as plain JavaScript.
521
+ */
522
+ resolveScriptGenericsAttribute(parsed: {
523
+ instance?: ModernScriptNode;
524
+ }): {
525
+ value: string;
526
+ source?: SourceRange;
527
+ } | undefined;
465
528
  private static assignValue;
466
- private recordDiagnostic;
467
529
  private resolvePublicPropName;
468
- private trackPropLocalName;
530
+ trackPropLocalName(propName: string, localName?: string): void;
469
531
  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;
532
+ getPropTypeByLocalOrPublic(name: string): string | undefined;
533
+ getExplicitPropType(name: string): string | undefined;
534
+ getPropertyName(node: Property["key"]): string | undefined;
580
535
  /**
581
536
  * Checks if a MemberExpression represents a well-known numeric constant.
582
537
  *
@@ -599,135 +554,25 @@ export default class ComponentParser {
599
554
  * Number.UNKNOWN // false
600
555
  * ```
601
556
  */
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;
557
+ isNumericConstant(memberExpr: unknown): boolean;
558
+ resolveTypeSource({ hasTypeScriptType, hasJSDocType, inferredType, finalType, }: {
559
+ hasTypeScriptType?: boolean;
560
+ hasJSDocType?: boolean;
561
+ inferredType?: string;
562
+ finalType?: string;
563
+ }): ComponentPropTypeSource;
660
564
  /**
661
565
  * Look up JSDoc on a local variable declaration by name.
662
566
  */
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;
567
+ resolveLocalVarJSDoc(name: string): {
568
+ type?: string;
569
+ params?: ComponentPropParam[];
570
+ returnType?: string;
571
+ description?: string;
572
+ binding?: ComponentPropBinding;
573
+ deprecated?: DeprecatedValue;
574
+ tags?: JsDocPassthroughTag[];
575
+ } | undefined;
731
576
  /**
732
577
  * Adds or merges a module export to the moduleExports map.
733
578
  *
@@ -766,157 +611,7 @@ export default class ComponentParser {
766
611
  * aliasType("number") // Returns: "number"
767
612
  * ```
768
613
  */
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;
614
+ aliasType(type: string): string;
920
615
  /**
921
616
  * Builds a cache of variable type information from JSDoc comments.
922
617
  *
@@ -991,72 +686,10 @@ export default class ComponentParser {
991
686
  * // Returns: { type: "number", description: "The count value" }
992
687
  * ```
993
688
  */
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;
689
+ findVariableTypeAndDescription(varName: string): {
690
+ type: string;
691
+ description?: string;
692
+ } | null;
1060
693
  /**
1061
694
  * Cleans up all parser state, resetting the instance for reuse.
1062
695
  *
@@ -1071,7 +704,7 @@ export default class ComponentParser {
1071
704
  * parser.parseSvelteComponent(source2, diagnostics2); // Fresh parse
1072
705
  * ```
1073
706
  */
1074
- private accumulateGeneric;
707
+ accumulateGeneric(name: string, constraint: string): void;
1075
708
  cleanup(): void;
1076
709
  /**
1077
710
  * Pre-compiled regex for matching script blocks in Svelte components.