sveld 0.37.5 → 0.37.7
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.
- package/README.md +157 -24
- package/lib/browser.d.ts +140 -7
- package/lib/browser.js +190 -162
- package/lib/{chunk-8s0hjkmq.js → chunk-0r8vwqdc.js} +9 -9
- package/lib/chunk-7w571557.js +1 -0
- package/lib/chunk-8xbe5qy3.js +356 -0
- package/lib/chunk-95xn5q1p.js +1 -0
- package/lib/chunk-aw6a570w.js +6 -0
- package/lib/chunk-mxv2ftxe.js +6 -0
- package/lib/cli-entry.js +1 -1
- package/lib/index.js +1 -1
- package/package.json +1 -1
- package/schema/component-api.schema.json +59 -3
- package/lib/chunk-a2krprqa.js +0 -6
- package/lib/chunk-bxzbn9eg.js +0 -1
- package/lib/chunk-k2w5f49f.js +0 -331
- package/lib/chunk-x9qsjgpb.js +0 -6
- package/lib/chunk-znjmdeca.js +0 -1
package/README.md
CHANGED
|
@@ -308,7 +308,7 @@ Parsed output is written to disk and reused when the source file has not changed
|
|
|
308
308
|
await sveld({ json: true });
|
|
309
309
|
```
|
|
310
310
|
|
|
311
|
-
By default this writes to `node_modules/.cache/sveld/parse-cache.json`. Pass a string to use a different location, e.g. `cache: ".cache/sveld.json"
|
|
311
|
+
By default this writes to `node_modules/.cache/sveld/parse-cache.json` in the project root, the nearest directory above the entry that has a `package.json`. Pass a string to use a different location, e.g. `cache: ".cache/sveld.json"` (relative paths resolve against the same project root), or `cache: false` to disable it. Also available as `--cache` / `--cache=<path>` / `--cache=false` on the CLI.
|
|
312
312
|
|
|
313
313
|
If a component [`@extendProps`](#extendprops) / [`@extends`](#extendprops) another file, it is re-parsed when that dependency changes, same as in [`watch`](#available-options) mode. Bumping the `sveld` or Svelte version clears the cache.
|
|
314
314
|
|
|
@@ -429,13 +429,16 @@ Every diagnostic carries a stable, namespaced `code` (`"sveld/<kind>"`) alongsid
|
|
|
429
429
|
| `sveld/context-any-type` | `warning` | Annotate the `setContext` value's declaration with `@type` or a native TypeScript type. |
|
|
430
430
|
| `sveld/slot-missing-type` | `warning` | Add the required `{Type}` annotation to the `@slot`/`@snippet` tag (e.g. `@slot {{}} name`); until then it falls back to `Record<string, never>`. |
|
|
431
431
|
| `sveld/event-no-source` | `warning` | Dispatch the event (`createEventDispatcher`/`dispatch`), forward it (`on:name`), or add a matching `on<Name>` callback prop; otherwise remove the stale `@event` tag. |
|
|
432
|
+
| `sveld/dispatch-escapes` | `warning` | The `createEventDispatcher()` result is passed to a function sveld can't follow: one that isn't imported from a local module, names an event with something other than a string literal, or passes the dispatcher on. Document the events it dispatches with `@event` tags. Add `@sveld-ignore sveld/dispatch-escapes` to the dispatcher's JSDoc once they're covered. |
|
|
432
433
|
| `sveld/example-compile-error` | `error` | Fix the `@example` TS/JS code block so it type-checks, or remove the broken example. |
|
|
433
434
|
| `sveld/example-syntax-error` | `error` | Fix the `@example` `svelte`/`html` markup so it parses, or remove the broken example. |
|
|
434
435
|
| `sveld/syntax-skipped` | `error` | Rewrite the flagged syntax in a form sveld can model (see the diagnostic's `message` for what was skipped). |
|
|
435
436
|
| `sveld/rest-props-unresolved` | `warning` | Spread `$$restProps` onto a plain element (or `svelte:element`) instead of a component, or add an `@restProps` tag to type it manually. |
|
|
436
437
|
| `sveld/context-duplicate-key` | `warning` | Remove the duplicate `setContext` call, or give it a distinct key; only the first call's shape is used. |
|
|
438
|
+
| `sveld/context-key-unresolved` | `warning` | Use a string literal, a `const`-bound string, `Symbol()`, or a string or `Symbol()` `export const` imported from a relative module as the `setContext` key; otherwise the context is left out of every output. |
|
|
439
|
+
| `sveld/context-value-unresolved` | `warning` | Pass an object literal or a typed variable as the `setContext` value (e.g. `const store = writable(0);` with a `@type` annotation, or `{ store }`); a call or other expression has no shape sveld can describe, so the context is left out of every output. |
|
|
437
440
|
| `sveld/spread-unresolved` | `warning` | Spread a local object literal or a variable with a resolvable type instead; otherwise the spread widens the generated type to `Record<string, any>`. |
|
|
438
|
-
| `sveld/export-unresolved` | `warning` | Export a local declaration directly. Instance-script exports are props, so move a re-export (`export { x } from "..."`, or `export { x }` of an import) into `<script context="module">`, where sveld writes it to the `.d.ts` as-is. |
|
|
441
|
+
| `sveld/export-unresolved` | `warning` | Export a local declaration directly. Instance-script exports are props, so move a re-export (`export { x } from "..."`, or `export { x }` of an import) into `<script context="module">`, where sveld writes it to the `.d.ts` as-is. A class can't be a prop either, so export it from `<script context="module">`, where sveld documents it. |
|
|
439
442
|
| `sveld/module-export-conflict` | `warning` | Rename the module-script export. `default` is always skipped (it collides with the component itself); a name matching the generated `<Name>Props`/`<Name>Exports` type breaks the `.d.ts` if the export carries a type. |
|
|
440
443
|
| `sveld/extend-props-target-missing` | `error` | Point `@extends`/`@extendProps` at a file that exists, and (for a bundled `.svelte` target) name its generated `<Name>Props` interface exactly. |
|
|
441
444
|
| `sveld/extend-props-duplicate` | `warning` | Remove the extra `@extends`/`@extendProps` tag; only the last one is used. |
|
|
@@ -448,10 +451,12 @@ Every diagnostic carries a stable, namespaced `code` (`"sveld/<kind>"`) alongsid
|
|
|
448
451
|
| `sveld/jsdoc-tag-dropped` | `warning` | Move the tag next to a `@slot`/`@snippet`/`@event`/`@typedef`/`@callback` tag in the same comment block so it has something to attach to. |
|
|
449
452
|
| `sveld/internal-typedef-referenced` | `error` | Remove `@internal`/`@ignore` from the referenced typedef, or stop referencing it from public type text (inline the shape, or make the referencing item `@internal` too). |
|
|
450
453
|
| `sveld/types-inline-unresolved` | `warning` | The import is kept as-is. Point it at a relative `.ts` file that exports a `type`/`interface`, or rename the colliding type. |
|
|
454
|
+
| `sveld/cross-file-unresolved` | `warning` | Only recorded by [`finalizeWithoutCrossFileResolution`](#browser) on a standalone parse: an imported `setContext` key, prop default, or dispatch helper needs the imported file read. Run `sveld` through the CLI or `generateBundle` to resolve it, or inline the value in the component. |
|
|
455
|
+
| `sveld/export-ambiguous` | `warning` | Two `export *` statements in the entry barrel bring in the same name from different modules, so (as in ES modules) the barrel doesn't export it and the [entry exports](#documenting-entry-exports) leave it out. Export it explicitly from the barrel (`export { format } from "./a.js"`) to pick one. Reported with the barrel file (e.g. `./index.js`) as its `component`, and only when `documentExports` is on. |
|
|
451
456
|
|
|
452
457
|
#### Severity and `--strict=errors`
|
|
453
458
|
|
|
454
|
-
Each diagnostic's `severity` is `"error"` (`example-compile-error`, `example-syntax-error`, `syntax-skipped`, `extend-props-target-missing`, `internal-typedef-referenced` — sveld emitted broken or unmodeled output) or `"warning"` (`prop-unknown-type`, `context-any-type`, `slot-missing-type`, `event-no-source`, `rest-props-unresolved`, `context-duplicate-key`, `spread-unresolved`, `export-unresolved`, `module-export-conflict`, `extend-props-duplicate`, `extend-props-override`, `jsdoc-unknown-tag`, `typedef-duplicate`, `property-duplicate`, `generics-conflict`, `event-description-ambiguous`, `jsdoc-tag-dropped`, `types-inline-unresolved` — a type fell back to `any
|
|
459
|
+
Each diagnostic's `severity` is `"error"` (`example-compile-error`, `example-syntax-error`, `syntax-skipped`, `extend-props-target-missing`, `internal-typedef-referenced` — sveld emitted broken or unmodeled output) or `"warning"` (`prop-unknown-type`, `context-any-type`, `slot-missing-type`, `event-no-source`, `dispatch-escapes`, `rest-props-unresolved`, `context-duplicate-key`, `context-key-unresolved`, `context-value-unresolved`, `spread-unresolved`, `export-unresolved`, `module-export-conflict`, `extend-props-duplicate`, `extend-props-override`, `jsdoc-unknown-tag`, `typedef-duplicate`, `property-duplicate`, `generics-conflict`, `event-description-ambiguous`, `jsdoc-tag-dropped`, `types-inline-unresolved`, `cross-file-unresolved`, `export-ambiguous` — a type fell back to `any`, or something was left out of the docs). Plain `strict: true` / `--strict` fails on both, unchanged from before. Pass `strict: "errors"` (or `--strict=errors`) to fail CI only on `error`-severity diagnostics, letting `any`-fallback warnings through:
|
|
455
460
|
|
|
456
461
|
```sh
|
|
457
462
|
npx sveld --json --strict=errors
|
|
@@ -481,7 +486,7 @@ export default defineConfig({
|
|
|
481
486
|
});
|
|
482
487
|
```
|
|
483
488
|
|
|
484
|
-
**Inline `@sveld-ignore <code>`**, on the same JSDoc comment as the prop, `@event` tag,
|
|
489
|
+
**Inline `@sveld-ignore <code>`**, on the same JSDoc comment as the prop, `@event` tag, context variable, or event dispatcher it applies to:
|
|
485
490
|
|
|
486
491
|
```svelte
|
|
487
492
|
<script>
|
|
@@ -806,6 +811,7 @@ It covers parsing one component's source and rendering that result to any output
|
|
|
806
811
|
import {
|
|
807
812
|
asNormalizedPath,
|
|
808
813
|
ComponentParser,
|
|
814
|
+
finalizeWithoutCrossFileResolution,
|
|
809
815
|
buildComponentApiDocument,
|
|
810
816
|
writeMarkdownCore,
|
|
811
817
|
writeTsDefinition,
|
|
@@ -815,7 +821,10 @@ import {
|
|
|
815
821
|
const parser = new ComponentParser();
|
|
816
822
|
const moduleName = "Button";
|
|
817
823
|
const filePath = "Button.svelte";
|
|
818
|
-
const parsed =
|
|
824
|
+
const parsed = finalizeWithoutCrossFileResolution(
|
|
825
|
+
parser.parseSvelteComponent(source, { moduleName, filePath }),
|
|
826
|
+
{ filePath },
|
|
827
|
+
);
|
|
819
828
|
|
|
820
829
|
// `parseSvelteComponent` returns component metadata only; add `moduleName`
|
|
821
830
|
// and `filePath` yourself to match the `ComponentDocApi` shape the writers expect.
|
|
@@ -837,6 +846,8 @@ const cem = buildCustomElementsManifest(components, {
|
|
|
837
846
|
});
|
|
838
847
|
```
|
|
839
848
|
|
|
849
|
+
A standalone parse can't read the files a component imports from, so some output the CLI and `generateBundle` produce is missing: a context whose `setContext` key is imported, the value of a prop default that names an imported `const`, the return type of a default that calls an imported function, and events dispatched by an imported helper (`wire(dispatch)`). `parseSvelteComponent` leaves these pending for the cross-file pass, which never runs here. Pass the result through `finalizeWithoutCrossFileResolution(parsed, { filePath })` to record a `sveld/cross-file-unresolved` warning for each one, naming the import (e.g. `` setContext key `keys.THEME` is imported from "./keys.js" ``), and to release the `sveld/event-no-source` warnings held back while a helper's events were unknown. It returns a new component and leaves the input unchanged.
|
|
850
|
+
|
|
840
851
|
`ComponentParser` is stateful but reusable across parses — call `parseSvelteComponent` again on the same instance for the next component instead of constructing a new one each time.
|
|
841
852
|
|
|
842
853
|
See [`playground/`](playground) in this repo for a working example: it parses Svelte source typed into an editor and renders JSON, Markdown, TypeScript, and Custom Elements Manifest tabs, all client-side. Deployed at [sveld.onrender.com](https://sveld.onrender.com).
|
|
@@ -1055,7 +1066,23 @@ typesOptions: {
|
|
|
1055
1066
|
|
|
1056
1067
|
Any key left out defaults to `true`.
|
|
1057
1068
|
|
|
1058
|
-
`<script context="module">` exports (`export declare const` / `export declare function`) are real runtime exports and are always emitted as exports, regardless of `exportTypes`.
|
|
1069
|
+
`<script context="module">` exports (`export declare const` / `export declare function` / `export declare class`) are real runtime exports and are always emitted as exports, regardless of `exportTypes`. So are the types a module script exports (`export interface Item`, `export type Mode`, `export type { Local }`), since they're part of the component module's API.
|
|
1070
|
+
|
|
1071
|
+
A module-script class (`export class Store {}`, or `class Store {}` then `export { Store }`) is emitted with its public surface: the constructor, methods (with their overload signatures, if any), fields, constructor parameter properties, getter/setter pairs, and `static`/`readonly`/`abstract`/optional modifiers. Types come from TypeScript annotations, then JSDoc (`@param`, `@returns`, `@type`, and `@template` on the class or a method), and are `any` otherwise. In a JS script, a `this.x = ...` assignment in the constructor declares property `x`. Private (`#x`, `private`), `protected`, computed-key, and `@internal` members are left out. `extends` and `implements` clauses are kept, and an imported base class or interface gets an `import type`. A class that extends something the `.d.ts` can't reference (a non-exported local class, or an expression like `mixin(Base)`) is declared without `extends`, with an `export-unresolved` warning, since its inherited members would be missing.
|
|
1072
|
+
|
|
1073
|
+
```ts
|
|
1074
|
+
export declare class Store<T> {
|
|
1075
|
+
constructor(initial: T);
|
|
1076
|
+
|
|
1077
|
+
value: T;
|
|
1078
|
+
|
|
1079
|
+
static create<U>(value: U): Store<U>;
|
|
1080
|
+
|
|
1081
|
+
subscribe(run: (value: T) => void): () => void;
|
|
1082
|
+
}
|
|
1083
|
+
```
|
|
1084
|
+
|
|
1085
|
+
In JSON the class is a `moduleExports` entry with `kind: "class"`, `type: "typeof Store"`, and its members under `members`; the Markdown and `llms-full.txt` output list them in a members table after the Module exports table.
|
|
1059
1086
|
|
|
1060
1087
|
One exception: when a bundled component uses [`@extendProps`](#extendprops) to extend another bundled component, sveld emits `import type { ButtonProps } from "./Button.svelte"` in the extending component's `.d.ts`. If `Button`'s props type stopped being exported, that import would break — so sveld always keeps a component's props type exported when another component in the same run extends it, even under `exportTypes: false`.
|
|
1061
1088
|
|
|
@@ -1084,7 +1111,7 @@ sveld({
|
|
|
1084
1111
|
+ export default class Button extends SvelteComponentTyped<IButtonProps, ...> {}
|
|
1085
1112
|
```
|
|
1086
1113
|
|
|
1087
|
-
Each template must contain `{name}` and produce a valid identifier once substituted; sveld throws otherwise. Any key left out of the object keeps its default (`"{name}Props"` / `"{name}Exports"`).
|
|
1114
|
+
Each template must contain `{name}` and produce a valid identifier once substituted, and the two must produce different names that aren't the component's own (`{name}`) or its generic-component interface's (`{name}Component`); sveld throws otherwise. Any key left out of the object keeps its default (`"{name}Props"` / `"{name}Exports"`).
|
|
1088
1115
|
|
|
1089
1116
|
If a bundled component then [`@extendProps`](#extendprops)/`@extends`-es another one, the tag must name the *templated* interface — `@extendProps {"./Button.svelte"} IButtonProps`, not `ButtonProps` — or sveld reports [`extend-props-target-missing`](#type-inference-diagnostics).
|
|
1090
1117
|
|
|
@@ -1145,6 +1172,8 @@ sveld({
|
|
|
1145
1172
|
});
|
|
1146
1173
|
```
|
|
1147
1174
|
|
|
1175
|
+
The same levels apply to the comments on slots, events, their snippet and `on<event>` callback props, `@restProps`, typedefs, contexts, module exports, and the component itself. A `@property` description inside a `@typedef` is part of the type's own text, so it stays at every level.
|
|
1176
|
+
|
|
1148
1177
|
`@internal`/`@ignore` members are removed from every output regardless of this option — see [`@ignore` / `@internal`](#ignore--internal). `comments` only controls how much JSDoc survives for members that *do* get emitted.
|
|
1149
1178
|
|
|
1150
1179
|
Also available as `--types-comments=<all|descriptions|none>` on the CLI.
|
|
@@ -1311,8 +1340,10 @@ It leaves alone:
|
|
|
1311
1340
|
- `enum`, `class`, and `function` exports, which can't be safely copied as a `type`/`interface`.
|
|
1312
1341
|
|
|
1313
1342
|
An import that can't be safely inlined (a missing file, a missing export, one of the unsupported
|
|
1314
|
-
export kinds above, or a name collision with something the component already declares
|
|
1315
|
-
typedef, a context type, a local `type`/`interface`,
|
|
1343
|
+
export kinds above, or a name collision with something the component's `.d.ts` already declares
|
|
1344
|
+
or imports — a typedef, a context type, a local `type`/`interface`, its `Props`/`Exports` type
|
|
1345
|
+
name, the component's own name, `$Props`/`$RestProps`, the svelte types the `.d.ts` imports, or a
|
|
1346
|
+
name bound by an import that stays) is left
|
|
1316
1347
|
as an import, with a [`types-inline-unresolved`](#diagnostic-codes) warning explaining why. If an
|
|
1317
1348
|
`import type { A, B } from "./x"` statement imports several names and even one of them can't be
|
|
1318
1349
|
inlined, the whole statement is kept and nothing from it is inlined — simpler, and always correct.
|
|
@@ -1459,7 +1490,7 @@ Nested barrels are followed too: `export { X } from "./dir"`, where `./dir/index
|
|
|
1459
1490
|
|
|
1460
1491
|
JSON adds `exports` and `totalExports`. Markdown adds an "Exports" section. Each item has `name`, `kind`, type text, optional JSDoc `description`, `source`, and — same as props — optional `@deprecated` and pass-through `tags`. A deprecated export's name is struck through in the Markdown table, same as a deprecated prop. See [`@deprecated`](#deprecated).
|
|
1461
1492
|
|
|
1462
|
-
An overloaded function (repeated `export function f(...)` signatures, or an import re-exported through a barrel) always documents the implementation signature, i.e. the last declaration. An `enum` export's `type` is the literal union of its members' values (`"A" | "B"` for a string enum, `0 | 1` for a numeric one), falling back to the bare enum name when a member's value can't be determined (e.g. a computed initializer). When two
|
|
1493
|
+
An overloaded function (repeated `export function f(...)` signatures, or an import re-exported through a barrel) always documents the implementation signature, i.e. the last declaration. An `enum` export's `type` is the literal union of its members' values (`"A" | "B"` for a string enum, `0 | 1` for a numeric one), falling back to the bare enum name when a member's value can't be determined (e.g. a computed initializer). A name the barrel exports itself (`export const X` or `export { X } from "./x"`) wins over the same name from an `export *`, as it does at runtime. When two `export *` statements bring in the same name from different modules (`export * from "./a"; export * from "./b"`), the name is ambiguous: the barrel doesn't export it at all, so `sveld` leaves it out and reports a [`sveld/export-ambiguous`](#diagnostic-codes) diagnostic naming both modules. Export it explicitly from the barrel (`export { format } from "./a"`) to pick one; that export wins silently. A namespace re-export (`export * as utils from "./utils"`, or an `import * as utils` the barrel re-exports) documents the one `const` export `utils`, with the wrapped module as its `source` and `typeof import("./utils.ts")` as its `type` (the module's path relative to the entry file, so the Markdown Type column names it); the names inside `./utils` aren't exports of the barrel, so they aren't listed. A re-exported default (`export { default as track } from "./track"`) is documented when that default export is a function, a class, or a named binding, with the JSDoc above `export default` as a named export would have; any other default (an object literal, say) is left out.
|
|
1463
1494
|
|
|
1464
1495
|
## JSON Output
|
|
1465
1496
|
|
|
@@ -1536,7 +1567,8 @@ interface ComponentDocApi {
|
|
|
1536
1567
|
interface ComponentProp {
|
|
1537
1568
|
name: string;
|
|
1538
1569
|
localName?: string;
|
|
1539
|
-
|
|
1570
|
+
// "re-export" and "class" are module exports only.
|
|
1571
|
+
kind: "let" | "const" | "function" | "re-export" | "class";
|
|
1540
1572
|
constant: boolean;
|
|
1541
1573
|
type?: string;
|
|
1542
1574
|
typeSource?: "typescript" | "jsdoc" | "default" | "inferred" | "unknown";
|
|
@@ -1555,6 +1587,23 @@ interface ComponentProp {
|
|
|
1555
1587
|
reactive: boolean;
|
|
1556
1588
|
binding?: "readonly" | "writable";
|
|
1557
1589
|
bindable?: true;
|
|
1590
|
+
// Set when `kind` is "class".
|
|
1591
|
+
members?: Array<{
|
|
1592
|
+
kind: "constructor" | "method" | "property";
|
|
1593
|
+
name: string;
|
|
1594
|
+
type?: string;
|
|
1595
|
+
params?: Array<{ name: string; type: string; description?: string; optional?: boolean }>;
|
|
1596
|
+
returnType?: string;
|
|
1597
|
+
typeParameters?: string;
|
|
1598
|
+
static?: true;
|
|
1599
|
+
readonly?: true;
|
|
1600
|
+
optional?: true;
|
|
1601
|
+
abstract?: true;
|
|
1602
|
+
description?: string;
|
|
1603
|
+
deprecated?: string | true;
|
|
1604
|
+
tags?: Array<{ name: string; body: string }>;
|
|
1605
|
+
}>;
|
|
1606
|
+
abstract?: true;
|
|
1558
1607
|
source?: SourceRange;
|
|
1559
1608
|
}
|
|
1560
1609
|
|
|
@@ -1687,7 +1736,7 @@ With that in place:
|
|
|
1687
1736
|
|
|
1688
1737
|
## llms.txt Output
|
|
1689
1738
|
|
|
1690
|
-
Set `llms: true` to emit an [`llms.txt`](https://llmstxt.org) / `llms-full.txt` pair: `llms.txt` is an index of every exported component (one link plus a one-line summary each), and `llms-full.txt` is the flattened full reference (every component's Props, Bindings, Events, Slots/Snippets, Typedefs, and Module exports, as terse Markdown tables). Props and Events Description columns include `@since`/`@example` tags, same as `COMPONENT_INDEX.md`.
|
|
1739
|
+
Set `llms: true` to emit an [`llms.txt`](https://llmstxt.org) / `llms-full.txt` pair: `llms.txt` is an index of every exported component (one link plus a one-line summary each), and `llms-full.txt` is the flattened full reference (every component's Props, Bindings, Events, Slots/Snippets, Typedefs, and Module exports, as terse Markdown tables). Props and Events Description columns include `@since`/`@example` tags, same as `COMPONENT_INDEX.md`. Fenced code in a Description cell is printed after its table as a regular fenced block, with `(code below)` left in the cell.
|
|
1691
1740
|
|
|
1692
1741
|
```diff
|
|
1693
1742
|
sveld({
|
|
@@ -1877,6 +1926,8 @@ listing one exported component name per line.
|
|
|
1877
1926
|
|
|
1878
1927
|
## API Reference
|
|
1879
1928
|
|
|
1929
|
+
A JSDoc block documents the declaration below it. Blank lines and ordinary comments may sit between the two, such as a `// biome-ignore ...` or `/* istanbul ignore next */` line.
|
|
1930
|
+
|
|
1880
1931
|
### `reactive`
|
|
1881
1932
|
|
|
1882
1933
|
The `reactive` field in generated JSON is a heuristic. It does not fully answer whether a parent can use `bind:prop` in Svelte.
|
|
@@ -2126,6 +2177,24 @@ By default, `sveld` infers the `@default` value from the prop's initializer and
|
|
|
2126
2177
|
open?: boolean;
|
|
2127
2178
|
```
|
|
2128
2179
|
|
|
2180
|
+
A fallback or conditional initializer (`??`, `||`, `&&`, `?:`) shows its source text, folded onto one line, in the `.d.ts`, the JSON `value`, and the Markdown "Default value" column:
|
|
2181
|
+
|
|
2182
|
+
```svelte
|
|
2183
|
+
<script>
|
|
2184
|
+
export let theme = undefined;
|
|
2185
|
+
const defaultSize = theme === "dense" ? "sm" : "md";
|
|
2186
|
+
|
|
2187
|
+
export let size = defaultSize ?? "md";
|
|
2188
|
+
</script>
|
|
2189
|
+
```
|
|
2190
|
+
|
|
2191
|
+
```ts
|
|
2192
|
+
/**
|
|
2193
|
+
* @default defaultSize ?? "md"
|
|
2194
|
+
*/
|
|
2195
|
+
size?: string;
|
|
2196
|
+
```
|
|
2197
|
+
|
|
2129
2198
|
Use `@default` to document the default value. When you supply `@default`, `sveld` uses it instead of the inferred value and avoids duplicate `@default` tags in the output.
|
|
2130
2199
|
|
|
2131
2200
|
Use `@default` when the initializer references a variable or expression that means nothing to consumers:
|
|
@@ -2189,7 +2258,7 @@ count?: number;
|
|
|
2189
2258
|
|
|
2190
2259
|
Resolution follows up to 5 levels of indirection. Beyond that, the last resolved identifier name is used as the default value.
|
|
2191
2260
|
|
|
2192
|
-
A named import resolves when the imported module (followed through re-exports) declares it as an `export const` with a string, number, boolean, or static template literal:
|
|
2261
|
+
A named import, or a member of a namespace import (`import * as timing from "./timing.js"` with `timing.TOOLTIP_LEAVE_DELAY_MS`, also through a namespace the module re-exports with `export * as`), resolves when the imported module (followed through re-exports) declares it as an `export const` with a string, number, boolean, or static template literal:
|
|
2193
2262
|
|
|
2194
2263
|
```svelte
|
|
2195
2264
|
<script>
|
|
@@ -2689,7 +2758,7 @@ function render(value: unknown, props: ComponentProps) {
|
|
|
2689
2758
|
|
|
2690
2759
|
Both forms support the same modifiers as typedef properties elsewhere in this doc: optional properties (`[name]`), default values (`[name=value]`), and nested/discriminated-union shapes. See the linked sections above for full signatures and worked examples with generated output.
|
|
2691
2760
|
|
|
2692
|
-
A description can wrap onto continuation lines, which run until the next tag. Indent them past the `*` gutter to keep them attached to the tag unambiguously; an unindented line right above an `@event`/`@typedef`/`@slot` with no description of its own is read as that tag's description instead, and an unindented line after an event's last `@property` describes the event.
|
|
2761
|
+
A description can wrap onto continuation lines, which run until the next tag. Indent them past the `*` gutter to keep them attached to the tag unambiguously; an unindented line right above an `@event`/`@typedef`/`@slot` with no description of its own is read as that tag's description instead, and an unindented line after an event's last `@property` describes the event. A blank line between indented paragraphs doesn't end the description; it's kept as a paragraph break. Lines inside a ```` ``` ```` code fence keep their indentation relative to the fence.
|
|
2693
2762
|
|
|
2694
2763
|
```js
|
|
2695
2764
|
/**
|
|
@@ -2699,6 +2768,16 @@ A description can wrap onto continuation lines, which run until the next tag. In
|
|
|
2699
2768
|
*/
|
|
2700
2769
|
```
|
|
2701
2770
|
|
|
2771
|
+
A `{type}` can wrap too. The text after its closing `}` and the name is the tag's own description, exactly as if the type fit on one line:
|
|
2772
|
+
|
|
2773
|
+
```js
|
|
2774
|
+
/**
|
|
2775
|
+
* @property {"ascending"
|
|
2776
|
+
* | "descending"} [dir] - The next sort direction,
|
|
2777
|
+
* reported regardless.
|
|
2778
|
+
*/
|
|
2779
|
+
```
|
|
2780
|
+
|
|
2702
2781
|
### `@callback`
|
|
2703
2782
|
|
|
2704
2783
|
The `@callback` tag defines a function type with `@param` and `@returns`, following the [TypeScript JSDoc `@callback` spec](https://www.typescriptlang.org/docs/handbook/jsdoc-supported-types.html#callback). Like `@typedef`, callbacks are exported from the generated `.d.ts`.
|
|
@@ -3001,6 +3080,28 @@ In Svelte 5 runes components, callback props like `onclick` are props, not event
|
|
|
3001
3080
|
|
|
3002
3081
|
Use `null` as the value if no event detail is provided.
|
|
3003
3082
|
|
|
3083
|
+
`sveld` infers events from `dispatch("name")` calls. When the dispatcher is passed to a function imported from a local module, as `helper(dispatch)` or `helper({ dispatch })` (a named or default import) or `helpers.open(dispatch)` (a namespace import, or a namespace another module re-exports with `export * as helpers from "./helpers.js"`), it reads that function too and picks up the events it dispatches:
|
|
3084
|
+
|
|
3085
|
+
```js
|
|
3086
|
+
// dispatch-open-close.js
|
|
3087
|
+
export function createOpenCloseDispatcher(dispatch) {
|
|
3088
|
+
return (open) => dispatch(open ? "open" : "close");
|
|
3089
|
+
}
|
|
3090
|
+
```
|
|
3091
|
+
|
|
3092
|
+
```svelte
|
|
3093
|
+
<script>
|
|
3094
|
+
import { createEventDispatcher } from "svelte";
|
|
3095
|
+
import { createOpenCloseDispatcher } from "./dispatch-open-close.js";
|
|
3096
|
+
|
|
3097
|
+
const dispatch = createEventDispatcher();
|
|
3098
|
+
// Types `open` and `close` as `CustomEvent<null>`
|
|
3099
|
+
const notifyOpenChange = createOpenCloseDispatcher(dispatch);
|
|
3100
|
+
</script>
|
|
3101
|
+
```
|
|
3102
|
+
|
|
3103
|
+
This happens when sveld builds the whole library (CLI, `sveld()`, or the Vite plugin), not when parsing a single component on its own. Each event name there must be a string literal, or a conditional between them. The detail is typed from a literal argument, and an object or array literal is typed member by member as for a dispatch in the component (`{ id: "a" }` is `{ id: string; }`); a member or argument the helper computes, including one of its own variables, is `any`, so add an `@event` tag to type it more precisely. When sveld can't follow the dispatcher (a package import, a local function, a computed event name, or a helper that passes the dispatcher on), it reports `sveld/dispatch-escapes`, and you document those events with `@event` tags.
|
|
3104
|
+
|
|
3004
3105
|
**Signature:**
|
|
3005
3106
|
|
|
3006
3107
|
```js
|
|
@@ -3090,6 +3191,9 @@ Without an `@event` tag or a typed dispatcher, `sveld` infers a dispatched event
|
|
|
3090
3191
|
|
|
3091
3192
|
- A scalar literal argument narrows to its literal type: `dispatch("count", 5)` types the detail as `5`, not `number`. Use `@event` or a typed dispatcher (below) to widen it.
|
|
3092
3193
|
- An object or array literal argument infers a structural type per field/element: `dispatch("save", { id })` types the detail as `{ id: string }` (resolving the `id` variable's own type), and `dispatch("items", [1, 2])` types it as `number[]`. Fields or elements sveld can't resolve fall back to `any` individually, not for the whole detail.
|
|
3194
|
+
- A variable, as the whole detail (`dispatch("count", count)`) or as a field or element, takes its JSDoc `@type` or TS annotation. Without one, it's typed from its initializer the way a prop default is: `let count = 0` and `let count = $state(0)` are `number`, `$state<Item[]>([])` is `Item[]`, and `$derived(total * 2)` is `number`. A literal widens to its primitive, since a `let` can be reassigned. A variable initialized from a call (`let roll = Math.random()`), a destructured binding without an annotation, or a function parameter or nested variable is `any`.
|
|
3195
|
+
- `$host().dispatchEvent(new CustomEvent("name", { detail }))` in a custom element types `detail` the same way.
|
|
3196
|
+
- An empty object literal (`dispatch("reset", {})`) types the detail as `Record<string, never>`. A spread or computed key (`{ ...state }`, `{ [key]: 1 }`) adds fields sveld can't name, so the detail becomes `Record<string, any>`, or keeps the named fields next to a `[key: string]: any` index signature (`{ id: number; [key: string]: any }`).
|
|
3093
3197
|
|
|
3094
3198
|
#### Typed dispatchers
|
|
3095
3199
|
|
|
@@ -3551,7 +3655,7 @@ A width prop.<br />@see https://example.com/width-docs
|
|
|
3551
3655
|
|
|
3552
3656
|
`{@link target}` (optionally `{@link target|display text}`) is an inline JSDoc tag used inside prose, not a block-level tag like the others on this page. `sveld`'s comment parser only treats a *line* as starting a new tag when it begins with `@` — `{@link ...}` always starts with `{`, so it's never intercepted. It is always literal text.
|
|
3553
3657
|
|
|
3554
|
-
**Valid contexts:** anywhere free-form description text is read — prop and module export descriptions, event descriptions, slot descriptions, entry export descriptions, typedef descriptions, `@component` HTML comments, and `@example` bodies. `sveld` never resolves or validates the target. JSON `description` and `.d.ts` JSDoc always keep the tag verbatim. **Markdown is the one exception:** in a prop, event, slot, or entry export's Description table cell, `{@link target|text}` / `{@link target}` is rewritten to a Markdown link, `[text](target)` / `[target](target)
|
|
3658
|
+
**Valid contexts:** anywhere free-form description text is read — prop and module export descriptions, event descriptions, slot descriptions, entry export descriptions, typedef descriptions, `@component` HTML comments, and `@example` bodies. `sveld` never resolves or validates the target. JSON `description` and `.d.ts` JSDoc always keep the tag verbatim. **Markdown is the one exception:** in a prop, event, slot, or entry export's Description table cell, `{@link target|text}` / `{@link target}` is rewritten to a Markdown link, `[text](target)` / `[target](target)`, except inside a fenced code block. Typedef descriptions (rendered as a `.d.ts`-style code block) and `@component` comments keep the tag literal in Markdown too, since neither goes through the table-cell renderer.
|
|
3555
3659
|
|
|
3556
3660
|
**Example:**
|
|
3557
3661
|
|
|
@@ -3616,15 +3720,23 @@ Output (`.d.ts`):
|
|
|
3616
3720
|
/**
|
|
3617
3721
|
* Formats a value.
|
|
3618
3722
|
* @example
|
|
3619
|
-
*
|
|
3620
|
-
*
|
|
3621
|
-
*
|
|
3723
|
+
* ```js
|
|
3724
|
+
* formatValue("ok");
|
|
3725
|
+
* ```
|
|
3622
3726
|
*/
|
|
3623
3727
|
formatValue: (value: string) => string;
|
|
3624
3728
|
```
|
|
3625
3729
|
|
|
3626
3730
|
`@param`/`@returns` are consumed into the function's type signature rather than kept as separate JSDoc lines.
|
|
3627
3731
|
|
|
3732
|
+
In Markdown table cells, a fenced block (in an `@example` body or anywhere in a description) renders as `<pre><code>` with one `<br />` per line, since a table row can't span lines. `<pre>` keeps the indentation, and GitHub renders it as a monospaced block inside the cell. The example above shows up in the Description column as:
|
|
3733
|
+
|
|
3734
|
+
```
|
|
3735
|
+
Formats a value.<br />@example <pre><code>formatValue("ok");</code></pre>
|
|
3736
|
+
```
|
|
3737
|
+
|
|
3738
|
+
`llms-full.txt` instead puts `(code below)` in the cell and prints the code after the table as a regular multi-line fenced block, under a ``Code for `formatValue`:`` line.
|
|
3739
|
+
|
|
3628
3740
|
Output (Markdown props table Description column, newlines rendered as `<br />`):
|
|
3629
3741
|
|
|
3630
3742
|
````
|
|
@@ -3654,12 +3766,18 @@ The key becomes the `{PascalCase}Context` type name. `sveld` can resolve:
|
|
|
3654
3766
|
| Static template literal | `` setContext(`simple-modal`, …) `` | `SimpleModalContext` |
|
|
3655
3767
|
| `const`-bound string | `const KEY = "simple-modal";`<br>`setContext(KEY, …)` | `SimpleModalContext` |
|
|
3656
3768
|
| `Symbol()` / `Symbol.for()` | `setContext(Symbol("tabs"), …)` | `TabsContext` |
|
|
3769
|
+
| Imported `export const` string | `import { KEY } from "./keys.js";`<br>`setContext(KEY, …)` | `SimpleModalContext` |
|
|
3770
|
+
| Namespace-imported `export const` string | `import * as keys from "./keys.js";`<br>`setContext(keys.KEY, …)` | `SimpleModalContext` |
|
|
3771
|
+
|
|
3772
|
+
Characters that can't appear in a TypeScript identifier are dropped and start a new PascalCase word, and a name starting with a digit gets a leading `_`: `"@scope/ctx"` becomes `ScopeCtxContext` and `"123"` becomes `_123Context`.
|
|
3657
3773
|
|
|
3658
3774
|
`const` identifiers are followed up to 5 levels deep (`const A = "x"; const B = A;`). Only `const` bindings count. `let`, `var`, and props are skipped because they can change at runtime.
|
|
3659
3775
|
|
|
3660
3776
|
Symbol keys take their name from the description: `Symbol("tabs")` and `Symbol.for("tabs")` both become `TabsContext`. For `const ModalKey = Symbol()` with no description, the binding name wins: `ModalKeyContext`.
|
|
3661
3777
|
|
|
3662
|
-
|
|
3778
|
+
An imported key (named, or read off a namespace import, including one another module re-exports with `export * as keys from "./keys.js"`) is read from its module, following re-exports, when that module is a relative `.js`/`.ts` file declaring it as `export const KEY = "simple-modal"` (or a static template literal). This works when sveld builds a whole library (CLI, `sveld()`, or the Vite plugin), not when parsing a single component on its own.
|
|
3779
|
+
|
|
3780
|
+
Anything else (dynamic identifiers, `let` exports, template interpolation, other function calls) records a `sveld/context-key-unresolved` diagnostic. No context type is generated.
|
|
3663
3781
|
|
|
3664
3782
|
#### Example
|
|
3665
3783
|
|
|
@@ -3803,14 +3921,15 @@ There are several ways to type contexts:
|
|
|
3803
3921
|
</script>
|
|
3804
3922
|
```
|
|
3805
3923
|
|
|
3806
|
-
**Option 3:
|
|
3924
|
+
**Option 3: Passing a typed variable as the whole value**
|
|
3807
3925
|
|
|
3808
3926
|
```svelte
|
|
3809
3927
|
<script>
|
|
3810
3928
|
import { setContext } from 'svelte';
|
|
3811
3929
|
|
|
3812
3930
|
/**
|
|
3813
|
-
*
|
|
3931
|
+
* Modal controls
|
|
3932
|
+
* @type {import("./types").ModalAPI}
|
|
3814
3933
|
*/
|
|
3815
3934
|
const modalAPI = {
|
|
3816
3935
|
open: () => {},
|
|
@@ -3821,6 +3940,17 @@ There are several ways to type contexts:
|
|
|
3821
3940
|
</script>
|
|
3822
3941
|
```
|
|
3823
3942
|
|
|
3943
|
+
`getContext('modal')` returns `modalAPI` itself, so the context type is the variable's type, and the variable's description documents it:
|
|
3944
|
+
|
|
3945
|
+
```ts
|
|
3946
|
+
/**
|
|
3947
|
+
* Modal controls
|
|
3948
|
+
*/
|
|
3949
|
+
export type ModalContext = import("./types").ModalAPI;
|
|
3950
|
+
```
|
|
3951
|
+
|
|
3952
|
+
When the variable's type is an object type literal (`@type {{ open: () => void }}` or `const api: { open: () => void } = ...`), its members become the context type's members instead. An untyped `const` holding an object literal is described from that literal, as with `{ ...api }`. Any other untyped variable is typed from its initializer the way a prop default is (`let count = $state(0)` or `let count = 0` gives `number`, `$state<Item[]>([])` gives `Item[]`), and one sveld can't type gives `any` with a `sveld/context-any-type` diagnostic. In `COMPONENT_API.json`, a context typed this way has a `type` field holding the whole type and an empty `properties` array.
|
|
3953
|
+
|
|
3824
3954
|
**Option 4: Direct object literal with inline functions**
|
|
3825
3955
|
|
|
3826
3956
|
```svelte
|
|
@@ -3839,9 +3969,10 @@ There are several ways to type contexts:
|
|
|
3839
3969
|
|
|
3840
3970
|
#### Notes
|
|
3841
3971
|
|
|
3842
|
-
- Context keys must be statically resolvable: a string literal, a static template literal, a `const`-bound string, or a `Symbol()` / `Symbol.for()` call with a static description
|
|
3843
|
-
- Variables passed to `setContext` should have JSDoc `@type` annotations for accurate types
|
|
3844
|
-
- The
|
|
3972
|
+
- Context keys must be statically resolvable: a string literal, a static template literal, a `const`-bound string, or a `Symbol()` / `Symbol.for()` call with a static description, either local or an imported `export const`. Dynamic expressions (runtime identifiers, template interpolation, other function calls) are skipped with a `sveld/context-key-unresolved` diagnostic.
|
|
3973
|
+
- Variables passed to `setContext` should have JSDoc `@type` annotations (or native TypeScript types) for accurate types. Without one, a variable is typed from its initializer the way a prop default is, unwrapping `$state`, `$state.raw`, and `$derived` (a rune's type argument, as in `$state<number>(0)`, wins). A variable passed as the whole value (`setContext("modal", modalAPI)`) types the context as that variable's type; one passed inside an object literal (`setContext("modal", { modalAPI })`) becomes a property
|
|
3974
|
+
- The value must be an object literal or a variable. Any other expression (such as `setContext("store", writable(0))`) is skipped with a `sveld/context-value-unresolved` diagnostic.
|
|
3975
|
+
- The generated type name follows the pattern: `{PascalCase}Context`. Separators (underscores and any character that can't appear in an identifier, such as hyphens, dots, colons, slashes, `@`, and spaces) are stripped and each segment is capitalized. A name starting with a digit gets a leading `_`:
|
|
3845
3976
|
| Context Key | Generated Type Name |
|
|
3846
3977
|
| --- | --- |
|
|
3847
3978
|
| `"simple-modal"` | `SimpleModalContext` |
|
|
@@ -3850,6 +3981,8 @@ There are several ways to type contexts:
|
|
|
3850
3981
|
| `"Carbon:Modal"` | `CarbonModalContext` |
|
|
3851
3982
|
| `"app/modal"` | `AppModalContext` |
|
|
3852
3983
|
| `"My Context"` | `MyContextContext` |
|
|
3984
|
+
| `"@scope/ctx"` | `ScopeCtxContext` |
|
|
3985
|
+
| `"123"` | `_123Context` |
|
|
3853
3986
|
| `"Tabs"` | `TabsContext` |
|
|
3854
3987
|
- If no type annotation is found, the type defaults to `any` with a warning
|
|
3855
3988
|
|