sveld 0.37.9 → 0.38.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.
@@ -1,8 +1,45 @@
1
- /// <reference types="node" />
2
-
3
- import type { Node, Property } from "estree";
1
+ interface ComponentParserDiagnostics {
2
+ moduleName: string;
3
+ filePath: string;
4
+ }
4
5
 
5
- import type { FunctionDeclaration, VariableDeclaration } from "estree";
6
+ export class ComponentParser {
7
+ /**
8
+ * All per-parse mutable state (props, slots, events, scopes, source, etc.).
9
+ * See {@link ParserContext} for field-by-field documentation. Replaced
10
+ * wholesale by `cleanup()` between parses.
11
+ */
12
+ private ctx;
13
+ /**
14
+ * Resets parser state for reuse between parses.
15
+ *
16
+ * @example
17
+ * ```ts
18
+ * parser.parseSvelteComponent(source1, diagnostics1);
19
+ * parser.cleanup();
20
+ * parser.parseSvelteComponent(source2, diagnostics2);
21
+ * ```
22
+ */
23
+ cleanup(): void;
24
+ /**
25
+ * @example
26
+ * ```ts
27
+ * const parser = new ComponentParser();
28
+ * const result = parser.parseSvelteComponent(source, {
29
+ * moduleName: "Button",
30
+ * filePath: "./Button.svelte"
31
+ * });
32
+ * // { props, slots, events, typedefs, ... }
33
+ * ```
34
+ */
35
+ parseSvelteComponent(source: string, diagnostics: ComponentParserDiagnostics): ParsedComponent;
36
+ /**
37
+ * Like {@link parseSvelteComponent}, but returns the candidates only a
38
+ * pass with file access can resolve beside the component rather than
39
+ * inside its metadata.
40
+ */
41
+ parse(source: string, diagnostics: ComponentParserDiagnostics): ComponentParseResult;
42
+ }
6
43
 
7
44
  interface JsDocPassthroughTag {
8
45
  name: string;
@@ -76,31 +113,18 @@ interface PendingDispatchEscapeCandidate {
76
113
  ignored?: boolean;
77
114
  }
78
115
 
79
- interface ParsedComponentTypeScriptMetadata {
80
- canonicalPropsType?: string;
81
- canonicalPropNames: string[];
82
- localTypeDeclarations: string[];
83
- /** Types the module script exports (`export interface Item`), emitted with `export`. */
84
- moduleTypeDeclarations?: string[];
85
- typeImportStatements: string[];
86
- /**
87
- * Whether `canonicalPropsType` mentions one of the component's own
88
- * `<script generics="...">` parameters (e.g. `Props<T>`). The semantic
89
- * resolver has no binding for `T`, so `resolveTypes` must leave this
90
- * component's props as their AST-derived text rather than expand them.
91
- */
92
- referencesComponentGenerics?: boolean;
93
- /** Unresolved CallExpression defaults for the cross-file pass in `generateBundle`. */
116
+ interface PendingCrossFileCandidates {
117
+ /** Unresolved CallExpression defaults. */
94
118
  pendingCallDefaultCandidates?: PendingCallDefaultCandidate[];
95
- /** Imported-identifier defaults for the cross-file pass in `generateBundle`. */
119
+ /** Imported-identifier defaults. */
96
120
  pendingConstDefaultCandidates?: PendingConstDefaultCandidate[];
97
- /** Unresolved `setContext` import keys for the cross-file pass in `generateBundle`. */
121
+ /** Unresolved `setContext` import keys. */
98
122
  pendingContextKeyCandidates?: PendingContextKeyCandidate[];
99
- /** Dispatchers passed to imported functions, for the cross-file pass in `generateBundle`. */
123
+ /** Dispatchers passed to imported functions. */
100
124
  pendingDispatchEscapeCandidates?: PendingDispatchEscapeCandidate[];
101
125
  /**
102
126
  * `event-no-source` diagnostics held back while the dispatcher escapes to
103
- * imported functions: `generateBundle` keeps those the functions don't dispatch.
127
+ * imported functions: the cross-file pass keeps those the functions don't dispatch.
104
128
  */
105
129
  deferredEventNoSourceDiagnostics?: SveldDiagnostic[];
106
130
  /**
@@ -110,6 +134,21 @@ interface ParsedComponentTypeScriptMetadata {
110
134
  untypedJsDocEventNames?: string[];
111
135
  }
112
136
 
137
+ interface ParsedComponentTypeScriptMetadata extends PendingCrossFileCandidates {
138
+ canonicalPropsType?: string;
139
+ canonicalPropNames: string[];
140
+ localTypeDeclarations: string[];
141
+ /** Types the module script exports (`export interface Item`), emitted with `export`. */
142
+ moduleTypeDeclarations?: string[];
143
+ typeImportStatements: string[];
144
+ }
145
+
146
+ interface ComponentParseResult {
147
+ component: ParsedComponent;
148
+ /** Undefined when the component depends on no other file's contents. */
149
+ pending?: PendingCrossFileCandidates;
150
+ }
151
+
113
152
  type SyntaxMode = "legacy" | "runes";
114
153
 
115
154
  type ScriptLanguage = "js" | "ts";
@@ -124,25 +163,6 @@ interface ComponentPropDefaultValue {
124
163
  value?: unknown;
125
164
  }
126
165
 
127
- type ModernScriptAttribute = {
128
- name?: string;
129
- value?: Array<{
130
- data?: string;
131
- raw?: string;
132
- }> | boolean;
133
- start?: number;
134
- end?: number;
135
- };
136
-
137
- type ModernScriptNode = {
138
- attributes?: ModernScriptAttribute[];
139
- };
140
-
141
- interface ComponentParserDiagnostics {
142
- moduleName: string;
143
- filePath: string;
144
- }
145
-
146
166
  type ComponentPropBinding = "readonly" | "writable";
147
167
 
148
168
  interface ComponentPropParam {
@@ -481,154 +501,7 @@ interface ParsedComponent {
481
501
  [PARSED_COMPONENT_TYPE_SCRIPT_METADATA]?: ParsedComponentTypeScriptMetadata;
482
502
  }
483
503
 
484
- export class ComponentParser {
485
- /**
486
- * All per-parse mutable state (props, slots, events, scopes, source, etc.).
487
- * See {@link ParserContext} for field-by-field documentation. Replaced
488
- * wholesale by `cleanup()` between parses.
489
- */
490
- private ctx;
491
- private static mapToArray;
492
- private static getStaticAttributeValue;
493
- resolveScriptLanguage(parsed: {
494
- instance?: ModernScriptNode;
495
- module?: ModernScriptNode;
496
- }): ScriptLanguage | undefined;
497
- /**
498
- * Reads the `generics` attribute off the instance script (Svelte only allows
499
- * it there, and only alongside `lang="ts"`). Returns the raw value for later
500
- * precedence resolution against `@generics`/`@template` JSDoc tags, or
501
- * `undefined` if absent. Records a `syntax-skipped` diagnostic and returns
502
- * `undefined` if the attribute is present without `lang="ts"`, since sveld
503
- * can't safely guess how to parse it as plain JavaScript.
504
- */
505
- resolveScriptGenericsAttribute(parsed: {
506
- instance?: ModernScriptNode;
507
- }): {
508
- value: string;
509
- source?: SourceRange;
510
- } | undefined;
511
- private resolvePublicPropName;
512
- trackPropLocalName(propName: string, localName?: string): void;
513
- private getPropByLocalOrPublic;
514
- getPropTypeByLocalOrPublic(name: string): string | undefined;
515
- getExplicitPropType(name: string): string | undefined;
516
- getPropertyName(node: Property["key"]): string | undefined;
517
- isNumericConstant(memberExpr: unknown): boolean;
518
- resolveLocalVarJSDoc(name: string): {
519
- type?: string;
520
- params?: ComponentPropParam[];
521
- returnType?: string;
522
- description?: string;
523
- binding?: ComponentPropBinding;
524
- deprecated?: DeprecatedValue;
525
- tags?: JsDocPassthroughTag[];
526
- sveldIgnore?: string[];
527
- internal: boolean;
528
- typeParameters?: string;
529
- } | undefined;
530
- private addModuleExport;
531
- /**
532
- * Resolves one `export { local as exported }` specifier to the top-level
533
- * function, class, or variable declarator (including one destructured
534
- * from a pattern) it names. Each specifier resolves on its own, so
535
- * `export { a, b }` exports both, and `const a = 1, b = ""; export { b }`
536
- * exports `b`'s declarator rather than the first one in the declaration.
537
- *
538
- * `program` is the script the export sits in: only its top-level
539
- * declarations count, not a same-named variable inside a function. An
540
- * instance-script export can also name a module-script declaration, or a
541
- * variable that a `$: local = ...` reactive declaration declares implicitly.
542
- */
543
- private resolveExportSpecifier;
544
- private recordUnresolvedExportSpecifier;
545
- /**
546
- * Doc comment for a declaration exported by `node`. A specifier uses the
547
- * comment on the declaration it names. An `export { ... }` list's own
548
- * comment documents it too, but only when the list has a single specifier;
549
- * its tags and description then override the declaration's.
550
- */
551
- private exportJSDoc;
552
- /** An instance-script `export class Foo {}` or `export { Foo }` of a class: neither a prop nor a documented accessor. */
553
- private recordClassExport;
554
- /**
555
- * The `.d.ts` can only say `extends Base` when `Base` is in scope there:
556
- * imported, or another exported class. A class extending anything else
557
- * (a local class, a call like `mixin(Base)`) is declared without it, and
558
- * flagged, since consumers won't see its inherited members.
559
- */
560
- private dropUndeclaredClassBases;
561
- /** A module-script `export class Foo {}` or `export { Foo }` of a class, with its public members. */
562
- private addModuleClassExport;
563
- /**
564
- * @example
565
- * ```ts
566
- * aliasType("*"); // "any"
567
- * aliasType(" string "); // "string"
568
- * ```
569
- */
570
- aliasType(type: string): string;
571
- /**
572
- * @example
573
- * ```ts
574
- * // Given:
575
- * // /**
576
- * // * @type {number}
577
- * // * The count value
578
- * // *\/
579
- * // const count = 0;
580
- *
581
- * findVariableTypeAndDescription("count");
582
- * // { type: "number", description: "The count value" }
583
- * ```
584
- */
585
- findVariableTypeAndDescription(varName: string): {
586
- type: string;
587
- description?: string;
588
- internal?: boolean;
589
- } | null;
590
- /**
591
- * The description and `@internal` flag of the JSDoc above `varName`,
592
- * whether or not it has a `@type`. For a variable typed some other way,
593
- * such as from its initializer.
594
- */
595
- findVariableJsDoc(varName: string): {
596
- description?: string;
597
- internal?: boolean;
598
- };
599
- /** The JSDoc table entry for `varName`, building the table on first use. */
600
- private variableJsDocEntry;
601
- accumulateGeneric(name: string, constraint: string): void;
602
- /**
603
- * Resets parser state for reuse between parses.
604
- *
605
- * @example
606
- * ```ts
607
- * parser.parseSvelteComponent(source1, diagnostics1);
608
- * parser.cleanup();
609
- * parser.parseSvelteComponent(source2, diagnostics2);
610
- * ```
611
- */
612
- cleanup(): void;
613
- private static readonly SCRIPT_BLOCK_REGEX;
614
- /** A `// @ts-...` comment, but not one on a `*` line of a JSDoc block (e.g. in an `@example`). */
615
- private static readonly TS_DIRECTIVE_REGEX;
616
- private static stripTypeScriptDirectivesFromScripts;
617
- /**
618
- * @example
619
- * ```ts
620
- * const parser = new ComponentParser();
621
- * const result = parser.parseSvelteComponent(source, {
622
- * moduleName: "Button",
623
- * filePath: "./Button.svelte"
624
- * });
625
- * // { props, slots, events, typedefs, ... }
626
- * ```
627
- */
628
- parseSvelteComponent(source: string, diagnostics: ComponentParserDiagnostics): ParsedComponent;
629
- }
630
-
631
- export type SveldDiagnosticKind = "prop-unknown-type" | "context-any-type" | "slot-missing-type" | "event-no-source" | "dispatch-escapes" | "example-compile-error" | "example-syntax-error" | "syntax-skipped" | "rest-props-unresolved" | "context-duplicate-key" | "context-key-unresolved" | "context-value-unresolved" | "spread-unresolved" | "export-unresolved" | "module-export-conflict" | "extend-props-target-missing" | "extend-props-duplicate" | "extend-props-override" | "jsdoc-unknown-tag" | "typedef-duplicate" | "property-duplicate" | "generics-conflict" | "event-description-ambiguous" | "jsdoc-tag-dropped" | "internal-typedef-referenced" | "types-inline-unresolved" | "cross-file-unresolved" | "export-ambiguous";
504
+ export type SveldDiagnosticKind = "prop-unknown-type" | "context-any-type" | "slot-missing-type" | "event-no-source" | "dispatch-escapes" | "example-compile-error" | "example-syntax-error" | "syntax-skipped" | "type-syntax-error" | "rest-props-unresolved" | "context-duplicate-key" | "context-key-unresolved" | "context-value-unresolved" | "spread-unresolved" | "export-unresolved" | "module-export-conflict" | "extend-props-target-missing" | "extend-props-duplicate" | "extend-props-override" | "jsdoc-unknown-tag" | "typedef-duplicate" | "property-duplicate" | "generics-conflict" | "event-description-ambiguous" | "jsdoc-tag-dropped" | "internal-typedef-referenced" | "cross-file-unresolved" | "export-ambiguous";
632
505
 
633
506
  export type SveldDiagnosticSeverity = "error" | "warning";
634
507
 
@@ -735,11 +608,6 @@ interface GenerateBundleOptions {
735
608
  * the failure and continuing with the remaining components.
736
609
  */
737
610
  failFast?: boolean;
738
- /**
739
- * Load the TypeScript program to expand opaque imported whole-object `$props()`
740
- * types into JSON/Markdown props. Off by default; requires `typescript`.
741
- */
742
- resolveTypes?: boolean;
743
611
  /** Record consts, functions, and types from the entry barrel. Off by default. */
744
612
  documentExports?: boolean;
745
613
  /**
@@ -753,17 +621,12 @@ interface GenerateBundleOptions {
753
621
  * Check `@example` blocks on props, module exports, slots, and events.
754
622
  * `true` runs plain TS/JS examples through the TypeScript program
755
623
  * (`example-compile-error` diagnostics; requires `typescript`) and
756
- * Svelte/HTML examples through sveld's own template parser
624
+ * Svelte/HTML examples through sveld's template parser (sveast)
757
625
  * (`example-syntax-error` diagnostics; no `typescript` needed). Pass
758
626
  * `"syntax"` to run only the markup path, so `typescript` is never loaded
759
627
  * even when TS/JS examples exist. Off by default.
760
628
  */
761
629
  checkExamples?: boolean | "syntax";
762
- /**
763
- * Parse as usual (so cache reads and real errors still apply) but skip
764
- * persisting the parse cache to disk. Set by the CLI's `--dry-run`.
765
- */
766
- dryRun?: boolean;
767
630
  /**
768
631
  * `ignore`: diagnostics matching at least one `{ code?, component?, name? }`
769
632
  * matcher are marked `ignored` (an omitted field matches anything;
@@ -774,16 +637,6 @@ interface GenerateBundleOptions {
774
637
  diagnostics?: {
775
638
  ignore?: DiagnosticIgnoreMatcher[];
776
639
  };
777
- /**
778
- * Mirrors `typesOptions.typeNames`: templates for the `<Name>Props`
779
- * interface name that `@extends`/`@extendProps` validation checks against.
780
- */
781
- typesTypeNames?: WriteTsDefinitionOptions["typeNames"];
782
- /**
783
- * Mirrors `typesOptions.inline`: `"local"`/`"all"` runs the cross-file
784
- * inlining pass (see `inline-types.ts`) after every component has parsed.
785
- */
786
- typesInline?: WriteTsDefinitionOptions["inline"];
787
640
  }
788
641
 
789
642
  declare const brand: unique symbol;
@@ -796,84 +649,75 @@ export type SvelteEntryPoint = Brand<string, "SvelteEntryPoint">;
796
649
 
797
650
  type NormalizedPath = Brand<string, "NormalizedPath">;
798
651
 
799
- type RelativeSourcePath = Brand<string, "RelativeSourcePath">;
800
-
801
- interface InlinedTypes {
802
- /** Exact `typeImportStatements` entries the writer must drop. */
803
- droppedImportStatements: string[];
804
- /** Declarations to emit (already stripped of `export`), in dependency order. */
805
- declarations: string[];
806
- /** Absolute paths of every file read, for watch-mode invalidation. */
807
- dependencies: string[];
808
- }
809
-
810
- interface WriteTsDefinitionOptions {
652
+ interface EntryExport {
653
+ name: string;
654
+ kind: "const" | "let" | "var" | "function" | "class" | "type" | "interface" | "enum";
811
655
  /**
812
- * `"class"` (default) extends the deprecated `SvelteComponentTyped`.
813
- * `"component"` emits `declare const X: Component<Props, Exports, Bindings>`
814
- * instead, for Svelte 5+ consumers. Generic components get a per-component
815
- * interface with a generic call signature instead of `Component<...>`
816
- * directly, since a `declare const` can't itself carry a generic type
817
- * parameter (see `genGenericComponentDeclaration`).
656
+ * Type text from the source, when present. A namespace export
657
+ * (`export * as ns from "./x"`) gets `typeof import("./x.ts")`, the
658
+ * wrapped module relative to the entry file.
818
659
  */
819
- format?: "class" | "component";
660
+ type?: string;
661
+ /** Initializer text for simple constants. */
662
+ value?: string;
663
+ description?: string;
664
+ /** From `@deprecated` JSDoc. */
665
+ deprecated?: DeprecatedValue;
666
+ /** `@since` / `@example` / `@see` tags in source order. */
667
+ tags?: JsDocPassthroughTag[];
668
+ /** True from `@ignore`/`@internal` JSDoc; excluded from every output by `buildComponentApiDocument`. */
669
+ internal?: boolean;
670
+ /** Declaring module, relative to the entry file. */
671
+ source?: string;
672
+ isTypeOnly: boolean;
673
+ }
674
+
675
+ type EntryExports = EntryExport[];
676
+
677
+ export interface SveldRuntimeOptions extends PluginSveldOptions {
678
+ /** Print unresolved-type diagnostics to stderr. */
679
+ reportDiagnostics?: boolean;
820
680
  /**
821
- * Which generated type declarations get an `export` keyword. `true`
822
- * (default) exports all; `false` exports none; an object picks per kind.
823
- * Module-script exports (`export declare const/function`) are runtime
824
- * exports and are always emitted as exports.
681
+ * Exit code 4 when diagnostics exist. Implies `reportDiagnostics`. Pass
682
+ * `"errors"` to fail only on `severity: "error"` diagnostics
683
+ * (`example-compile-error`, `syntax-skipped`), letting warnings
684
+ * (`prop-unknown-type`, `context-any-type`, `event-no-source`) through.
825
685
  */
826
- exportTypes?: boolean | {
827
- props?: boolean;
828
- exports?: boolean;
829
- typedefs?: boolean;
830
- contexts?: boolean;
831
- };
832
- /** @internal Set by `writeTsDefinitions` for `@extends` targets; overrides `exportTypes.props`. */
833
- forceExportProps?: boolean;
686
+ strict?: boolean | "errors";
834
687
  /**
835
- * Templates for generated type names. `{name}` is replaced with the
836
- * component's module name. Defaults: `"{name}Props"`, `"{name}Exports"`.
688
+ * Diff the parsed component API against a committed snapshot (default:
689
+ * the `json` writer's `outFile`, or `COMPONENT_API.json`) and assign a
690
+ * semver bump to each change. Exits `3` on a breaking change. Pass a
691
+ * string for a custom snapshot path.
837
692
  */
838
- typeNames?: {
839
- props?: string;
840
- exports?: string;
841
- };
693
+ check?: boolean | string;
842
694
  /**
843
- * How much JSDoc to emit. `"all"` (default) keeps descriptions,
844
- * `@deprecated`, `@default`, and passthrough tags (`@since`, `@see`,
845
- * `@example`, `@link`). `"descriptions"` keeps descriptions and
846
- * `@deprecated` only. `"none"` emits no comments at all.
695
+ * Minimum bump `--check` fails the run (exit `3`) on: `"major"` (default,
696
+ * preserves prior behavior), `"minor"`, or `"patch"`.
847
697
  */
848
- comments?: "all" | "descriptions" | "none";
698
+ checkLevel?: "major" | "minor" | "patch";
699
+ /** Suppress writer progress logs (`created "..."` / `unchanged "..."`). */
700
+ quiet?: boolean;
849
701
  /**
850
- * `"type"` (default) emits the props type as a type alias.
851
- * `"interface"` emits `interface <Name>Props { ... }` when the props are a
852
- * plain object (no `@restProps`, no `@extendProps`, no whole-object
853
- * `$props()` type); other shapes are intersections and stay aliases.
702
+ * Print the single selected `json` / `markdown` document to stdout
703
+ * instead of writing it to disk. Requires exactly one of those two
704
+ * outputs; CLI-only (the Vite plugin ignores it).
854
705
  */
855
- propsDeclaration?: "type" | "interface";
706
+ stdout?: boolean;
856
707
  /**
857
- * Copies `type`/`interface` declarations imported from a relative source (or a
858
- * tsconfig/jsconfig path alias) directly into the `.d.ts`, dropping the import. `"local"`
859
- * follows relative sources, path aliases, re-exports, and same-file dependencies; bare package
860
- * imports, `.svelte` sources, and unsupported exports (enums, classes, functions, consts,
861
- * namespaces) stay imports and get a `types-inline-unresolved` warning. `"all"` additionally
862
- * inlines bare/package imports (e.g. `import type { Foo } from "some-lib"`) using the real
863
- * TypeScript checker - same unsupported-export/collision rules, same warning on failure - with
864
- * two exceptions kept as plain imports regardless: `svelte`/`svelte/elements` (a hard-coded
865
- * allow-list; copying framework types would freeze a Svelte version into consumer output) and
866
- * `@extendProps`/`@extends` targets (deferred; unrelated mechanism). `"all"` needs `typescript`
867
- * 7+ and a `tsconfig.json`, same hard requirement as `resolveTypes`. `false` (default)
868
- * preserves every import as-is.
869
- * @default false
708
+ * Output format for the `--check` report and the `--report-diagnostics` /
709
+ * `--strict` diagnostics summary: `"text"` (default) or `"json"`.
710
+ * Channels are unchanged, the check report on stdout and diagnostics on
711
+ * stderr. CLI-only; `sveld()` ignores `format` for its own console output.
870
712
  */
871
- inline?: false | "local" | "all";
872
- /** @internal Set by `writeTsDefinitions` from `GenerateBundleResult.inlinedTypesByFilePath` when `inline` resolved something for this component. */
873
- inlined?: InlinedTypes;
713
+ format?: "text" | "json";
874
714
  }
875
715
 
876
- interface PluginSveldOptions extends Pick<GenerateBundleOptions, "resolveTypes" | "cache" | "checkExamples" | "diagnostics"> {
716
+ export type SveldConfig = SveldRuntimeOptions;
717
+
718
+ export declare function defineConfig(config: SveldConfig): SveldConfig;
719
+
720
+ interface PluginSveldOptions extends Pick<GenerateBundleOptions, "cache" | "checkExamples" | "diagnostics"> {
877
721
  /**
878
722
  * Specify the entry point to uncompiled Svelte source.
879
723
  * If not provided, sveld will use the "svelte" field from package.json.
@@ -893,23 +737,11 @@ interface PluginSveldOptions extends Pick<GenerateBundleOptions, "resolveTypes"
893
737
  /** Record consts, functions, and types from the entry barrel. Off by default. */
894
738
  documentExports?: boolean;
895
739
  types?: boolean;
896
- typesOptions?: Partial<Omit<WriteTsDefinitionsOptions, "inputDir">>;
740
+ typesOptions?: TypesOptions;
897
741
  json?: boolean;
898
- jsonOptions?: Partial<Omit<WriteJsonOptions, "inputDir">>;
742
+ jsonOptions?: JsonOptions;
899
743
  markdown?: boolean;
900
- markdownOptions?: Partial<WriteMarkdownOptions>;
901
- /** Generate a Custom Elements Manifest (`custom-elements.json`, schemaVersion "1.0.0"). */
902
- customElements?: boolean;
903
- customElementsOptions?: Partial<Omit<WriteCustomElementsOptions, "inputDir">>;
904
- /** Generate a first-party `llms.txt` / `llms-full.txt` pair (per https://llmstxt.org). */
905
- llms?: boolean;
906
- llmsOptions?: Partial<WriteLlmsOptions>;
907
- /**
908
- * Run additional, userland-registered writers (via `registerWriter` from
909
- * "sveld") beyond the built-in `json`/`markdown`/`types` outputs. Keyed by
910
- * the writer's registered `name`, valued by that writer's options.
911
- */
912
- additionalWriters?: Record<string, unknown>;
744
+ markdownOptions?: MarkdownOptions;
913
745
  /**
914
746
  * Abort the entire run when a single component fails to parse.
915
747
  * When `false` (the default), parse failures are collected as diagnostics
@@ -919,9 +751,10 @@ interface PluginSveldOptions extends Pick<GenerateBundleOptions, "resolveTypes"
919
751
  /**
920
752
  * Regenerate output incrementally when relevant source changes during
921
753
  * `vite dev` / `vite build --watch`: a component, the entry barrel itself
922
- * (adding/removing an export), or a non-`.svelte` file a component depends
923
- * on via `@extendProps` / `@extends` or a typedef `import("./x")`
924
- * reference. Only the affected components are re-parsed.
754
+ * (adding/removing an export), a module a component reads a value from,
755
+ * or a non-`.svelte` file a component names via `@extendProps` /
756
+ * `@extends`. Only the edited components and those that read an edited
757
+ * module are re-parsed.
925
758
  * @default false
926
759
  */
927
760
  watch?: boolean;
@@ -956,27 +789,18 @@ interface SveldPlugin {
956
789
 
957
790
  export default function pluginSveld(opts?: PluginSveldOptions): SveldPlugin;
958
791
 
959
- interface WriteCustomElementsOptions {
960
- /** @internal Resolved from `entry` and always injected by the caller (`plugin.ts`); not user-configurable via `customElementsOptions`. */
961
- inputDir: string;
962
- outFile: string;
963
- /** @internal Report the resolved path instead of writing. Always set by the caller from `sveld --dry-run`. */
964
- dryRun?: boolean;
965
- }
966
-
967
- interface WriteJsonOptions {
968
- /** @internal Unused by this writer; kept for backward compatibility. Always set by the caller. */
969
- input: string;
970
- /** @internal Resolved from `entry` and always injected by the caller (`plugin.ts`); not user-configurable via `jsonOptions`. */
971
- inputDir: string;
972
- outFile: string;
973
- outDir?: string;
792
+ export interface JsonOptions {
974
793
  /**
975
- * @internal Entry-barrel exports when `documentExports` is on. Always
976
- * computed from the parsed bundle and injected by the caller; setting it
977
- * via `jsonOptions` has no effect.
794
+ * Path (relative to the project root) for the single combined JSON
795
+ * document. Ignored when `outDir` is set.
796
+ * @default "COMPONENT_API.json"
978
797
  */
979
- entryExports?: EntryExports;
798
+ outFile?: string;
799
+ /**
800
+ * Emit one `<ComponentName>.api.json` file per component into this
801
+ * directory instead of the single combined `outFile`.
802
+ */
803
+ outDir?: string;
980
804
  /**
981
805
  * Include `source`/`componentCommentSource` position ranges in the
982
806
  * output. These are the bulk of a large component library's
@@ -986,52 +810,36 @@ interface WriteJsonOptions {
986
810
  * @default true
987
811
  */
988
812
  source?: boolean;
989
- /** @internal Report resolved paths instead of writing. Always set by the caller from `sveld --dry-run`. */
990
- dryRun?: boolean;
991
813
  }
992
814
 
993
- interface EntryExport {
994
- name: string;
995
- kind: "const" | "let" | "var" | "function" | "class" | "type" | "interface" | "enum";
996
- /**
997
- * Type text from the source, when present. A namespace export
998
- * (`export * as ns from "./x"`) gets `typeof import("./x.ts")`, the
999
- * wrapped module relative to the entry file.
1000
- */
1001
- type?: string;
1002
- /** Initializer text for simple constants. */
1003
- value?: string;
1004
- description?: string;
1005
- /** From `@deprecated` JSDoc. */
1006
- deprecated?: DeprecatedValue;
1007
- /** `@since` / `@example` / `@see` tags in source order. */
1008
- tags?: JsDocPassthroughTag[];
1009
- /** True from `@ignore`/`@internal` JSDoc; excluded from every output by `buildComponentApiDocument`. */
1010
- internal?: boolean;
1011
- /** Declaring module, relative to the entry file. */
1012
- source?: string;
1013
- isTypeOnly: boolean;
815
+ export interface ComponentApiDocument {
816
+ schemaVersion: 1;
817
+ generator: {
818
+ name: string;
819
+ version: string;
820
+ svelteVersion: string;
821
+ };
822
+ total: number;
823
+ components: ComponentDocApi[];
824
+ /** Only when `documentExports` is on. */
825
+ totalExports?: number;
826
+ exports?: EntryExports;
1014
827
  }
1015
828
 
1016
- type EntryExports = EntryExport[];
1017
-
1018
- interface WriteLlmsOptions {
1019
- outDir?: string;
1020
- /** Prefixed to each component's link path, e.g. `[Name](<linkBase>/Name)`. @default "" */
1021
- linkBase?: string;
1022
- /** @default the "name" field from the project's package.json */
1023
- title?: string;
1024
- /** @default the "description" field from the project's package.json */
1025
- summary?: string;
1026
- /** @internal Entry-barrel exports when `documentExports` is on. Always computed from the parsed bundle and injected by the caller. */
829
+ interface BuildComponentApiDocumentOptions {
830
+ /** Entry-barrel exports when `documentExports` is on. */
1027
831
  entryExports?: EntryExports;
1028
- /** @internal Report the resolved paths instead of writing. Always set by the caller from `sveld --dry-run`. */
1029
- dryRun?: boolean;
1030
832
  }
1031
833
 
1032
- interface WriteMarkdownOptions {
1033
- write?: boolean;
1034
- outFile: string;
834
+ export declare function buildComponentApiDocument(components: ComponentDocs, options?: BuildComponentApiDocumentOptions): ComponentApiDocument;
835
+
836
+ export interface MarkdownOptions {
837
+ /**
838
+ * Path (relative to the project root) for the single combined Markdown
839
+ * document. Ignored when `outDir` is set.
840
+ * @default "COMPONENT_INDEX.md"
841
+ */
842
+ outFile?: string;
1035
843
  /**
1036
844
  * Emit one `<ModuleName>.md` file per component into this directory,
1037
845
  * plus an index `README.md` linking to each, instead of the single
@@ -1040,33 +848,10 @@ interface WriteMarkdownOptions {
1040
848
  */
1041
849
  outDir?: string;
1042
850
  /**
1043
- * @internal Entry-barrel exports when `documentExports` is on. Always
1044
- * computed from the parsed bundle and injected by the caller; setting it
1045
- * via `markdownOptions` has no effect.
851
+ * Called every time a heading, quote, paragraph, divider, or raw block is
852
+ * appended to the document, to inject extra content.
1046
853
  */
1047
- entryExports?: EntryExports;
1048
- onAppend?: (type: AppendType, document: WriterMarkdown, components: ComponentDocs) => void;
1049
- /** @internal Report the resolved path instead of writing. Always set by the caller from `sveld --dry-run`. */
1050
- dryRun?: boolean;
1051
- }
1052
-
1053
- type OnAppend = (type: AppendType, document: WriterMarkdown) => void;
1054
-
1055
- interface MarkdownOptions {
1056
- onAppend?: OnAppend;
1057
- }
1058
-
1059
- declare class WriterMarkdown extends Writer {
1060
- onAppend?: OnAppend;
1061
- private markdownBase;
1062
- constructor(options: MarkdownOptions);
1063
- get source(): string;
1064
- get hasToC(): boolean;
1065
- get toc(): TocLine[];
1066
- appendLineBreaks(): this;
1067
- append(type: AppendType, raw?: string): this;
1068
- tableOfContents(): this;
1069
- end(): string;
854
+ onAppend?: (type: AppendType, document: MarkdownDocument, components: ComponentDocs) => void;
1070
855
  }
1071
856
 
1072
857
  type AppendType = "h1" | "h2" | "h3" | "h4" | "h5" | "h6" | "quote" | "p" | "divider" | "raw";
@@ -1077,30 +862,23 @@ interface TocLine {
1077
862
  raw: string;
1078
863
  }
1079
864
 
1080
- interface WriterOptions {
1081
- /** Report the resolved path to stdout instead of writing. Set by `sveld --dry-run`. */
1082
- dryRun?: boolean;
865
+ type MarkdownAppendCallback = (type: AppendType, document: MarkdownDocument) => void;
866
+
867
+ interface MarkdownDocumentOptions {
868
+ onAppend?: MarkdownAppendCallback;
1083
869
  }
1084
870
 
1085
- declare class Writer {
1086
- private readonly dryRun;
1087
- /** Directories already created by this writer, so sibling files skip the `mkdir` round trip. */
1088
- private readonly ensuredDirs;
1089
- constructor(options?: WriterOptions);
1090
- /**
1091
- * Skips the write when `filePath` already contains `raw`, so repeated runs
1092
- * over unchanged sources don't touch the file (or its mtime). In dry-run
1093
- * mode, prints `would write "<path>"` to stdout and touches nothing.
1094
- *
1095
- * @returns `true` if the file was written, `false` if it was already up to date.
1096
- *
1097
- * @example
1098
- * ```ts
1099
- * const writer = new Writer();
1100
- * await writer.write("./dist/index.d.ts", "export type Props = {};");
1101
- * ```
1102
- */
1103
- write(filePath: string, raw: string): Promise<boolean>;
871
+ declare class MarkdownDocument {
872
+ sourceParts: string[];
873
+ hasToC: boolean;
874
+ toc: TocLine[];
875
+ onAppend?: MarkdownAppendCallback;
876
+ constructor(options?: MarkdownDocumentOptions);
877
+ get source(): string;
878
+ appendLineBreaks(): this;
879
+ append(type: AppendType, raw?: string): this;
880
+ tableOfContents(): this;
881
+ end(): string;
1104
882
  }
1105
883
 
1106
884
  type TransformContext = {
@@ -1112,34 +890,19 @@ type TransformContext = {
1112
890
  filePath: string;
1113
891
  };
1114
892
 
1115
- interface WriteTsDefinitionsOptions extends WriteTsDefinitionOptions {
1116
- outDir: string;
1117
- /** @internal Resolved from `entry` and always injected by the caller (`plugin.ts`); not user-configurable via `typesOptions`. */
1118
- inputDir: string;
1119
- preamble: string;
1120
- /** @internal Always computed from the parsed bundle and injected by the caller; not user-configurable via `typesOptions`. */
1121
- exports: ParsedExports;
1122
- /** @internal Report resolved paths instead of writing. Always set by the caller from `sveld --dry-run`. */
1123
- dryRun?: boolean;
1124
- /**
1125
- * @internal Reuses generated `.d.ts` text across runs for components whose
1126
- * source (and every emit option from `serializeEmitOptions`) hasn't
1127
- * changed. Requires `resolvedPathByFilePath` to key lookups; both come
1128
- * from `GenerateBundleResult`.
1129
- */
1130
- cache?: ParseCache;
1131
- /** @internal See `cache`. Lookups use `component.filePath`. */
1132
- resolvedPathByFilePath?: Map<string, string>;
893
+ export interface TypesOptions extends WriteTsDefinitionOptions {
1133
894
  /**
1134
- * @internal See `cache`. For components whose output was resolved from
1135
- * other files, so their text is keyed on their content too.
895
+ * Output directory for generated `.d.ts` files, relative to the project
896
+ * root.
897
+ * @default "types"
1136
898
  */
1137
- crossFileResolvedPathByFilePath?: Map<string, string>;
899
+ outDir?: string;
1138
900
  /**
1139
- * @internal From `GenerateBundleResult.inlinedTypesByFilePath`, populated when
1140
- * `typesOptions.inline` is `"local"`/`"all"`. Lookups use `component.filePath`.
901
+ * Raw text prepended to the generated `index.d.ts` barrel, e.g. a license
902
+ * header.
903
+ * @default ""
1141
904
  */
1142
- inlinedTypesByFilePath?: Map<string, InlinedTypes>;
905
+ preamble?: string;
1143
906
  /**
1144
907
  * Post-processes each generated file's text before it is written. Runs
1145
908
  * after the generated-text cache, so it applies on every run. Config file
@@ -1147,159 +910,24 @@ interface WriteTsDefinitionsOptions extends WriteTsDefinitionOptions {
1147
910
  */
1148
911
  transform?: (text: string, context: TransformContext) => string | Promise<string>;
1149
912
  /**
1150
- * Also re-export generated types from `index.d.ts`. `true` re-exports each
1151
- * component's `Props` type (and `Exports` under `format: "component"`); an
1152
- * object can additionally include typedefs and contexts. Skips any type
1153
- * that `exportTypes` keeps local.
913
+ * Also re-export generated types from `index.d.ts`: each component's
914
+ * `Props` type, and its `Exports` type under `format: "component"`.
1154
915
  */
1155
- indexTypes?: boolean | {
1156
- props?: boolean;
1157
- exports?: boolean;
1158
- typedefs?: boolean;
1159
- contexts?: boolean;
1160
- };
916
+ indexTypes?: boolean;
1161
917
  }
1162
918
 
1163
- declare class ParseCache {
1164
- private readonly cacheFilePath;
1165
- private readonly file;
1166
- private readonly next;
1167
- /** Paths forced to miss this run (e.g. dependents of a changed `@extends` target). */
1168
- private readonly blocked;
1169
- /**
1170
- * Whether `next` differs from what's on disk: an entry was added or its
1171
- * generated text changed. Dropped entries show up as `next` holding fewer
1172
- * entries than `savedEntryCount`, since without a `set()` every entry in
1173
- * `next` came from the file.
1174
- */
1175
- private dirty;
1176
- private savedEntryCount;
1177
- constructor(cacheFilePath: string);
1178
- /** True when `get()` would return a hit for `resolvedPath` and `hash`. */
1179
- has(resolvedPath: string, hash: string): boolean;
1180
- /** Returns the cached parse for `resolvedPath` when its content hash still matches. */
1181
- get(resolvedPath: string, hash: string): ParsedComponent | null;
1182
- /**
1183
- * Records a freshly parsed component so it can be reused on a future run.
1184
- * Stores a copy, for the same reason `get()` returns one.
1185
- */
1186
- set(resolvedPath: string, hash: string, parsed: ParsedComponent): void;
1187
- /** Skip cache for `resolvedPath` this run (e.g. an @extends dependent). */
1188
- invalidate(resolvedPath: string): void;
1189
- /**
1190
- * Returns the cached generated `.d.ts` text for `resolvedPath`, if this
1191
- * run's parse entry for it (a fresh parse or a hash-verified hit - see
1192
- * `get()`/`set()`) already carries text generated for `key`, the
1193
- * serialized emit options (see `serializeEmitOptions`).
1194
- */
1195
- getGeneratedText(resolvedPath: string, key: string): string | undefined;
1196
- /**
1197
- * Records generated `.d.ts` text against this run's parse entry for
1198
- * `resolvedPath`. No-op if that entry hasn't been recorded via `get()`/`set()`
1199
- * (shouldn't happen: the write phase only runs after every component has
1200
- * been parsed).
1201
- */
1202
- setGeneratedText(resolvedPath: string, key: string, text: string): void;
1203
- /**
1204
- * Persists this run's cache entries back to disk. Writes to a pid-suffixed
1205
- * temp file and renames it over the target so concurrent sveld processes
1206
- * sharing a cache dir can't interleave writes into a truncated file; a
1207
- * failed rename (e.g. read-only cache dir) falls back to a direct write so
1208
- * generation never fails just because the cache couldn't be saved.
1209
- * Skipped when nothing changed since the file was read or last saved.
1210
- */
1211
- save(): void;
1212
- }
1213
-
1214
- type ParsedExports = Record<string, {
1215
- source: RelativeSourcePath;
1216
- default: boolean;
1217
- mixed?: boolean;
1218
- }>;
1219
-
1220
- export interface SveldRuntimeOptions extends PluginSveldOptions {
1221
- /** Print unresolved-type diagnostics to stderr. */
1222
- reportDiagnostics?: boolean;
1223
- /**
1224
- * Exit code 4 when diagnostics exist. Implies `reportDiagnostics`. Pass
1225
- * `"errors"` to fail only on `severity: "error"` diagnostics
1226
- * (`example-compile-error`, `syntax-skipped`), letting warnings
1227
- * (`prop-unknown-type`, `context-any-type`, `event-no-source`) through.
1228
- *
1229
- * `"ci"` and `"local"` are strictness profiles, expanded by
1230
- * {@link expandStrictProfile} into a set of other options before this
1231
- * object's own explicit keys are applied (so they can still opt back out
1232
- * of one, e.g. `{ strict: "ci", checkExamples: false }`):
1233
- * - `"ci"`: `{ strict: true, reportDiagnostics: true, check: true, checkExamples: true }`.
1234
- * - `"local"`: `{ reportDiagnostics: true }` (does not itself enable `strict`).
1235
- */
1236
- strict?: boolean | "errors" | "ci" | "local";
1237
- /**
1238
- * Diff the parsed component API against a committed snapshot (default:
1239
- * the `json` writer's `outFile`, or `COMPONENT_API.json`) and assign a
1240
- * semver bump to each change. Exits `3` on a breaking change. Pass a
1241
- * string for a custom snapshot path.
1242
- */
1243
- check?: boolean | string;
1244
- /**
1245
- * Minimum bump `--check` fails the run (exit `3`) on: `"major"` (default,
1246
- * preserves prior behavior), `"minor"`, or `"patch"`.
1247
- */
1248
- checkLevel?: "major" | "minor" | "patch";
1249
- /** Suppress writer progress logs (`created "..."` / `unchanged "..."`). */
1250
- quiet?: boolean;
1251
- /**
1252
- * Print the single selected `json` / `markdown` / `customElements` document
1253
- * to stdout instead of writing it to disk. Requires exactly one of those
1254
- * three outputs; CLI-only (the Vite plugin ignores it). `"ndjson"` is only
1255
- * valid with `json` and prints one minified JSON object per component per
1256
- * line instead of the single combined document.
1257
- */
1258
- stdout?: boolean | "json" | "ndjson";
1259
- /**
1260
- * Output format for the `--check` report and the `--report-diagnostics` /
1261
- * `--strict` diagnostics summary: `"text"` (default), `"json"`, or
1262
- * `"github"` (GitHub Actions `::error`/`::warning` workflow commands, plus
1263
- * a `GITHUB_STEP_SUMMARY` Markdown table when that env var is set).
1264
- * Channels are unchanged, the check report on stdout and diagnostics on
1265
- * stderr. CLI-only; `sveld()` ignores `format` for its own console output.
1266
- */
1267
- format?: "text" | "json" | "github";
919
+ interface WriteTsDefinitionOptions {
1268
920
  /**
1269
- * Resolve the entry, load config, and parse components as usual, but print
1270
- * `would write "<path>"` for each output file to stdout instead of writing
1271
- * it (including the parse cache). CLI-only; the Vite plugin ignores it.
921
+ * `"class"` (default) extends the deprecated `SvelteComponentTyped`.
922
+ * `"component"` emits `declare const X: Component<Props, Exports, Bindings>`
923
+ * instead, for Svelte 5+ consumers. Generic components get a per-component
924
+ * interface with a generic call signature instead of `Component<...>`
925
+ * directly, since a `declare const` can't itself carry a generic type
926
+ * parameter (see `genGenericComponentDeclaration`).
1272
927
  */
1273
- dryRun?: boolean;
1274
- }
1275
-
1276
- export type SveldConfig = SveldRuntimeOptions;
1277
-
1278
- export declare function defineConfig(config: SveldConfig): SveldConfig;
1279
-
1280
- export interface ComponentApiDocument {
1281
- schemaVersion: 1;
1282
- generator: {
1283
- name: string;
1284
- version: string;
1285
- svelteVersion: string;
1286
- };
1287
- total: number;
1288
- components: ComponentDocApi[];
1289
- /** Only when `documentExports` is on. */
1290
- totalExports?: number;
1291
- exports?: EntryExports;
1292
- }
1293
-
1294
- interface BuildComponentApiDocumentOptions {
1295
- /** Entry-barrel exports when `documentExports` is on. */
1296
- entryExports?: EntryExports;
928
+ format?: "class" | "component";
1297
929
  }
1298
930
 
1299
- export declare function buildComponentApiDocument(components: ComponentDocs, options?: BuildComponentApiDocumentOptions): ComponentApiDocument;
1300
-
1301
- export declare function cli(process: NodeJS.Process): Promise<void>;
1302
-
1303
931
  type SveldOptions = SveldRuntimeOptions;
1304
932
 
1305
933
  export interface SveldResult {
@@ -1310,41 +938,19 @@ export interface SveldResult {
1310
938
  /** Parse errors for components that failed to parse (empty unless `failFast` is disabled and a component errors). */
1311
939
  errors: ComponentParseError[];
1312
940
  /**
1313
- * Suggested process exit code for this run, using the same mapping as the
1314
- * CLI (a breaking `check` result wins over `strict` diagnostics): `0` on
1315
- * success, `3` on a breaking API change, `4` when `strict` diagnostics
1316
- * exist. `sveld()` never mutates `process.exitCode` itself; assign this
1317
- * value yourself if you want the process to exit non-zero.
941
+ * The component API document for the exported components, exactly as the
942
+ * `json` writer writes `COMPONENT_API.json`. Populated whether or not
943
+ * `json` is enabled, so custom output can be rendered from it directly.
1318
944
  */
1319
- exitCode: 0 | 3 | 4;
1320
- }
1321
-
1322
- export declare function sveld(opts?: SveldOptions): Promise<SveldResult>;
1323
-
1324
- type WriterComponentSet = "exported" | "all";
1325
-
1326
- export interface OutputWriter<TOptions = unknown> {
1327
- name: string;
1328
- /** Which component set this writer expects — see {@link WriterComponentSet}. @default "exported" */
1329
- componentSet?: WriterComponentSet;
945
+ document: ComponentApiDocument;
1330
946
  /**
1331
- * `options` always carries `dryRun: true` under `sveld --dry-run` (or
1332
- * `{ dryRun: true }` from the programmatic API), alongside whatever
1333
- * `TOptions` fields the writer defines. `write` must check it and skip
1334
- * touching disk; sveld does not do this for you. A thrown error (sync or
1335
- * async) is re-thrown by the caller as `sveld: writer "<name>" failed: ...`
1336
- * with the original error as `cause`.
947
+ * Suggested process exit code for this run, using the same mapping as the
948
+ * CLI (see {@link resolveExitCode}). `sveld()` never mutates `process.exitCode` itself; assign this
949
+ * value yourself if you want the process to exit non-zero.
1337
950
  */
1338
- write(components: ComponentDocs, options: TOptions): Promise<unknown> | unknown;
1339
- }
1340
-
1341
- export interface RegisterWriterOptions {
1342
- /** Overwrite an existing writer registered under the same `name` instead of throwing. @default false */
1343
- replace?: boolean;
951
+ exitCode: ExitCode;
1344
952
  }
1345
953
 
1346
- export declare function registerWriter<TOptions = unknown>(writer: OutputWriter<TOptions>, options?: RegisterWriterOptions): void;
954
+ type ExitCode = 0 | 1 | 2 | 3 | 4;
1347
955
 
1348
- export declare function getWriter(name: string): OutputWriter<unknown> | undefined;
1349
-
1350
- export declare function listWriters(): OutputWriter<unknown>[];
956
+ export declare function sveld(opts?: SveldOptions): Promise<SveldResult>;