sveld 0.36.11 → 0.37.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.
- package/README.md +522 -66
- package/lib/browser.d.ts +121 -2
- package/lib/browser.js +160 -139
- package/lib/{chunk-3a9n8agv.js → chunk-550yx3gf.js} +9 -9
- package/lib/chunk-6n4d12tf.js +1 -0
- package/lib/chunk-74rbv9gf.js +1 -0
- package/lib/chunk-eybp3ae7.js +6 -0
- package/lib/chunk-jtm65qmd.js +300 -0
- package/lib/chunk-s1v2vjye.js +7 -0
- package/lib/cli-entry.js +1 -1
- package/lib/index.js +1 -1
- package/package.json +5 -3
- package/schema/component-api.schema.json +431 -0
- package/lib/chunk-04eb8yj0.js +0 -245
- package/lib/chunk-5b7hj275.js +0 -7
- package/lib/chunk-e1e89j27.js +0 -1
- package/lib/chunk-ncw3wbrj.js +0 -6
- package/lib/chunk-qnj6xmb6.js +0 -7
- package/lib/chunk-wq8f3w8t.js +0 -1
package/README.md
CHANGED
|
@@ -9,9 +9,9 @@ The goal is to get third-party Svelte libraries working with the Svelte Language
|
|
|
9
9
|
|
|
10
10
|
[Carbon Components Svelte](https://github.com/carbon-design-system/carbon-components-svelte) uses this library to auto-generate component types and API metadata.
|
|
11
11
|
|
|
12
|
-
`sveld`
|
|
12
|
+
`sveld` parses `.svelte` files with its own template parser (`src/template-parse/`), kept in parity with `svelte/compiler`'s parser by a differential test suite. That single parse path powers docgen and TypeScript output for Svelte 3, Svelte 4, and Svelte 5 without runes (`export let`, `<slot>`, `$$restProps`, …). It also covers Svelte 5 Runes (`$props()`, `$bindable()`, `{@render ...}`, callback props such as `onclick`, …).
|
|
13
13
|
|
|
14
|
-
For `lang="ts"` components, `sveld` keeps source-level prop type annotations when it can, instead of forcing JSDoc. That covers legacy `export let` props, typed `$props()` destructuring
|
|
14
|
+
For `lang="ts"` components, `sveld` keeps source-level prop type annotations when it can, instead of forcing JSDoc. That covers legacy `export let` props, typed `$props()` destructuring (whole-object and per-prop), local `interface`/`type`/`enum` declarations, and TypeScript signatures on accessor exports (`export function`). Any type a prop annotation or accessor signature depends on — whether imported with `import type` or as a plain value import used only in a type position — is re-emitted as an `import type` at the top of the generated `.d.ts`, and local `interface`/`type`/`enum` declarations it depends on are copied alongside it. Everything stays textual: no semantic expansion, and `satisfies`/`as` are treated alike. A `const enum` is widened to a literal union of its member values instead of being re-declared, since `const enum` isn't supported by common bundlers under `isolatedModules`.
|
|
15
15
|
|
|
16
16
|
By default, generated `.d.ts` files extend `SvelteComponentTyped` from `svelte`, so TypeScript and the Svelte Language Server work whether consumers use Svelte 3, Svelte 4, or Svelte 5. Set `typesOptions.format: "component"` to instead emit the Svelte 5 `Component` type; see [`typesOptions.format`](#typesoptionsformat).
|
|
17
17
|
|
|
@@ -125,6 +125,9 @@ export default class Button extends SvelteComponentTyped<
|
|
|
125
125
|
- [Persistent parse cache (`cache`)](#persistent-parse-cache-cache)
|
|
126
126
|
- [Compile-checked `@example` blocks (`checkExamples`)](#compile-checked-example-blocks-checkexamples)
|
|
127
127
|
- [Type inference diagnostics](#type-inference-diagnostics)
|
|
128
|
+
- [Diagnostic codes](#diagnostic-codes)
|
|
129
|
+
- [Severity and `--strict=errors`](#severity-and---stricterrors)
|
|
130
|
+
- [Ignoring diagnostics](#ignoring-diagnostics)
|
|
128
131
|
- [Requirements](#requirements)
|
|
129
132
|
- [Usage](#usage)
|
|
130
133
|
- [Installation](#installation)
|
|
@@ -132,6 +135,7 @@ export default class Button extends SvelteComponentTyped<
|
|
|
132
135
|
- [CLI](#cli)
|
|
133
136
|
- [Exit codes](#exit-codes)
|
|
134
137
|
- [CI: API-drift checks (`--check`)](#ci-api-drift-checks---check)
|
|
138
|
+
- [CI: strictness profiles (`--strict=ci`/`--strict=local`)](#ci-strictness-profiles---strictci---strictlocal)
|
|
135
139
|
- [Node.js](#nodejs)
|
|
136
140
|
- [Browser](#browser)
|
|
137
141
|
- [Config File](#config-file)
|
|
@@ -141,11 +145,12 @@ export default class Button extends SvelteComponentTyped<
|
|
|
141
145
|
- [JSON Output](#json-output)
|
|
142
146
|
- [Custom Elements Manifest](#custom-elements-manifest)
|
|
143
147
|
- [Consuming the manifest](#consuming-the-manifest)
|
|
148
|
+
- [llms.txt Output](#llmstxt-output)
|
|
144
149
|
- [Custom Writers](#custom-writers)
|
|
145
150
|
- [The `OutputWriter` contract](#the-outputwriter-contract)
|
|
146
151
|
- [Registering a writer](#registering-a-writer)
|
|
147
152
|
- [Running it via the plugin](#running-it-via-the-plugin)
|
|
148
|
-
- [Worked example: a
|
|
153
|
+
- [Worked example: a `components.txt` name-list writer](#worked-example-a-componentstxt-name-list-writer)
|
|
149
154
|
- [API Reference](#api-reference)
|
|
150
155
|
- [reactive](#reactive)
|
|
151
156
|
- [binding](#binding)
|
|
@@ -158,6 +163,7 @@ export default class Button extends SvelteComponentTyped<
|
|
|
158
163
|
- [Extra JSDoc tags before `@slot`](#extra-jsdoc-tags-before-slot)
|
|
159
164
|
- [Svelte 5 Snippet Compatibility](#svelte-5-snippet-compatibility)
|
|
160
165
|
- [@event](#event)
|
|
166
|
+
- [@ignore / @internal](#ignore--internal)
|
|
161
167
|
- [@deprecated](#deprecated)
|
|
162
168
|
- [@since](#since)
|
|
163
169
|
- [@see](#see)
|
|
@@ -176,7 +182,7 @@ export default class Button extends SvelteComponentTyped<
|
|
|
176
182
|
|
|
177
183
|
## Approach
|
|
178
184
|
|
|
179
|
-
`sveld`
|
|
185
|
+
`sveld` statically analyzes exported components and emits docs for consumers. Template parsing runs through sveld's own parser rather than `svelte/compiler`; `svelte/compiler` is imported only for its types, and `svelte/package.json` is read for the installed Svelte version. A differential test (`tests/svelte-template-parse-shim.test.ts`) parses every fixture `.svelte` file with both parsers and asserts the resulting ASTs match, and a weekly `svelte-canary` workflow re-runs that comparison against `svelte@latest` ahead of the lockfile pin.
|
|
180
186
|
|
|
181
187
|
It extracts:
|
|
182
188
|
|
|
@@ -292,7 +298,7 @@ Without `resolveTypes`, JSON lists no props. With it, each field shows up with `
|
|
|
292
298
|
}
|
|
293
299
|
```
|
|
294
300
|
|
|
295
|
-
**Performance.** Off by default. This is the
|
|
301
|
+
**Performance.** Off by default. This is one of the two paths that load TypeScript. It needs `typescript` 7+ and a `tsconfig.json` (see [Requirements](#requirements)); if either is missing, `resolveTypes` fails the run instead of silently producing empty props. It also runs slower than the AST-only pipeline and gets slower as your types grow. Use it only when you need expanded JSON. `.d.ts` output is unchanged.
|
|
296
302
|
|
|
297
303
|
### Persistent parse cache (`cache`)
|
|
298
304
|
|
|
@@ -308,7 +314,7 @@ If a component [`@extendProps`](#extendprops) / [`@extends`](#extendprops) anoth
|
|
|
308
314
|
|
|
309
315
|
### Compile-checked `@example` blocks (`checkExamples`)
|
|
310
316
|
|
|
311
|
-
`@example` blocks are just text. Rename a prop and the sample code can sit there broken for months. Set `checkExamples: true` to
|
|
317
|
+
`@example` blocks are just text. Rename a prop and the sample code can sit there broken for months. Set `checkExamples: true` to check them: plain TS/JS bodies run through the TypeScript program, and `svelte`/`html` bodies run through sveld's own template parser. Broken examples show up as `example-compile-error` (TS/JS) or `example-syntax-error` (markup) diagnostics.
|
|
312
318
|
|
|
313
319
|
```ts
|
|
314
320
|
await sveld({ json: true, checkExamples: true });
|
|
@@ -339,15 +345,23 @@ If `formatValue` is later renamed and the example is never updated, `checkExampl
|
|
|
339
345
|
- Line 1: Cannot find name 'formatValue'.
|
|
340
346
|
```
|
|
341
347
|
|
|
342
|
-
|
|
348
|
+
A `svelte`/`html`-fenced example is syntax-checked, not type-checked: sveld parses the markup and discards the AST, so it catches malformed markup (a mismatched closing tag, an unterminated attribute) but not a prop that doesn't exist or a type error inside an expression. Those still need `svelte-check` in the consumer's own tests. Bare unfenced markup (`<Button />` with no code fence) is skipped either way.
|
|
343
349
|
|
|
344
|
-
|
|
350
|
+
```
|
|
351
|
+
@example blocks that failed to parse (1):
|
|
352
|
+
./Component.svelte
|
|
353
|
+
- Line 1: sveld: invalid closing tag </span>.
|
|
354
|
+
```
|
|
355
|
+
|
|
356
|
+
The TS/JS check is narrow on purpose too. It catches renamed or removed symbols and wrong argument counts. Neither path is full type checking, and neither pulls in types sveld cannot see.
|
|
345
357
|
|
|
346
|
-
|
|
358
|
+
The TS/JS path needs `typescript` 7+ and a `tsconfig.json`, same as `resolveTypes` (see [Requirements](#requirements)); missing either fails the run rather than silently skipping every example. The markup path needs neither: pass `checkExamples: "syntax"` to run only it, so a project with only `svelte`/`html` examples (or no `tsconfig.json`) never loads TypeScript. Use `--strict` (or the `strict` option) to fail CI when an example breaks.
|
|
347
359
|
|
|
348
360
|
### Type inference diagnostics
|
|
349
361
|
|
|
350
|
-
`sveld` collects unresolved-type diagnostics on every run: props that fall back to `any`, context values typed as `any`, `@event` tags with no dispatch or callback, `$props()`/`{@render}` syntax sveld can't model, and (when `checkExamples` is enabled) `example-compile-error`. They are always returned from the programmatic `sveld()` API in `SveldResult.diagnostics`. Each diagnostic carries an optional `source` range (the same `{ start: { line, column }, end: { line, column } }` shape as JSON output source ranges) whenever the parser holds a stable position for it.
|
|
362
|
+
`sveld` collects unresolved-type diagnostics on every run: props that fall back to `any`, context values typed as `any`, `@event` tags with no dispatch or callback, `$props()`/`{@render}` syntax sveld can't model, and (when `checkExamples` is enabled) `example-compile-error`/`example-syntax-error`. They are always returned from the programmatic `sveld()` API in `SveldResult.diagnostics`. Each diagnostic carries an optional `source` range (the same `{ start: { line, column }, end: { line, column } }` shape as JSON output source ranges) whenever the parser holds a stable position for it.
|
|
363
|
+
|
|
364
|
+
A prop with no type annotation, no `@type` JSDoc, and no initializer has nothing to infer a type or a default from: its JSON `type` stays absent (`"typeSource": "unknown"`), it triggers a `prop-unknown-type` diagnostic, and the emitted `.d.ts` types it as `any` with no `@default` line (rather than the literal type `undefined`).
|
|
351
365
|
|
|
352
366
|
With `reportDiagnostics` or `strict`, the grouped summary looks like this:
|
|
353
367
|
|
|
@@ -356,28 +370,32 @@ sveld: 5 unresolved types found.
|
|
|
356
370
|
|
|
357
371
|
Props without inferred types (1):
|
|
358
372
|
./icons/Add.svelte
|
|
359
|
-
- Prop "title" type could not be inferred; falling back to "any". (./icons/Add.svelte:4:2)
|
|
373
|
+
- Prop "title" type could not be inferred; falling back to "any". (./icons/Add.svelte:4:2) [sveld/prop-unknown-type]
|
|
360
374
|
|
|
361
375
|
Context values typed as `any` (1):
|
|
362
376
|
./ThemeProvider.svelte
|
|
363
|
-
- Context "theme" variable "themeStore" has no type annotation; defaulted to "any". (./ThemeProvider.svelte:8:6)
|
|
377
|
+
- Context "theme" variable "themeStore" has no type annotation; defaulted to "any". (./ThemeProvider.svelte:8:6) [sveld/context-any-type]
|
|
364
378
|
|
|
365
379
|
@event tags with no dispatch or callback (2):
|
|
366
380
|
./Modal.svelte
|
|
367
|
-
- @event "open" has no matching dispatch or callback prop. (./Modal.svelte:3:5)
|
|
368
|
-
- @event "close" has no matching dispatch or callback prop. (./Modal.svelte:4:5)
|
|
381
|
+
- @event "open" has no matching dispatch or callback prop. (./Modal.svelte:3:5) [sveld/event-no-source]
|
|
382
|
+
- @event "close" has no matching dispatch or callback prop. (./Modal.svelte:4:5) [sveld/event-no-source]
|
|
369
383
|
|
|
370
384
|
Component syntax sveld skipped (1):
|
|
371
385
|
./Tabs.svelte
|
|
372
|
-
- {@render tabs(getTabProps())} argument is not a plain object literal; the render call was not mapped to slot metadata. (./Tabs.svelte:6:4)
|
|
386
|
+
- {@render tabs(getTabProps())} argument is not a plain object literal; the render call was not mapped to slot metadata. (./Tabs.svelte:6:4) [sveld/syntax-skipped]
|
|
373
387
|
```
|
|
374
388
|
|
|
375
|
-
When `checkExamples` is also enabled, `@example`
|
|
389
|
+
When `checkExamples` is also enabled, `@example` failures appear as additional groups: TS/JS failures under `example-compile-error`, `svelte`/`html` failures under `example-syntax-error`.
|
|
376
390
|
|
|
377
391
|
```
|
|
378
392
|
@example blocks that failed to compile (1):
|
|
379
393
|
./Component.svelte
|
|
380
|
-
- Line 1: Cannot find name 'formatValue'.
|
|
394
|
+
- Line 1: Cannot find name 'formatValue'. [sveld/example-compile-error]
|
|
395
|
+
|
|
396
|
+
@example blocks that failed to parse (1):
|
|
397
|
+
./Component.svelte
|
|
398
|
+
- Line 1: sveld: invalid closing tag </span>. [sveld/example-syntax-error]
|
|
381
399
|
```
|
|
382
400
|
|
|
383
401
|
By default, nothing is printed. Opt in when you are working on types or want CI output:
|
|
@@ -401,11 +419,94 @@ npx sveld --json --strict
|
|
|
401
419
|
|
|
402
420
|
`--check` is separate: it diffs `COMPONENT_API.json` for API drift and semver classification, not inference warnings.
|
|
403
421
|
|
|
422
|
+
#### Diagnostic codes
|
|
423
|
+
|
|
424
|
+
Every diagnostic carries a stable, namespaced `code` (`"sveld/<kind>"`) alongside the older `kind`, so CI config and `diagnostics.ignore` matchers (below) have something that won't shift if the human-readable `message` text changes:
|
|
425
|
+
|
|
426
|
+
| Code | Severity | Fix |
|
|
427
|
+
| --- | --- | --- |
|
|
428
|
+
| `sveld/prop-unknown-type` | `warning` | Add a native TypeScript annotation, a `@type` JSDoc tag, or an initializer sveld can infer a type from. |
|
|
429
|
+
| `sveld/context-any-type` | `warning` | Annotate the `setContext` value's declaration with `@type` or a native TypeScript type. |
|
|
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
|
+
| `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/example-compile-error` | `error` | Fix the `@example` TS/JS code block so it type-checks, or remove the broken example. |
|
|
433
|
+
| `sveld/example-syntax-error` | `error` | Fix the `@example` `svelte`/`html` markup so it parses, or remove the broken example. |
|
|
434
|
+
| `sveld/syntax-skipped` | `error` | Rewrite the flagged syntax in a form sveld can model (see the diagnostic's `message` for what was skipped). |
|
|
435
|
+
| `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
|
+
| `sveld/context-duplicate-key` | `warning` | Remove the duplicate `setContext` call, or give it a distinct key; only the first call's shape is used. |
|
|
437
|
+
| `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 instead of re-exporting an import or a binding from another file; sveld only resolves exports of a local declaration. |
|
|
439
|
+
| `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. |
|
|
440
|
+
| `sveld/extend-props-duplicate` | `warning` | Remove the extra `@extends`/`@extendProps` tag; only the last one is used. |
|
|
441
|
+
| `sveld/extend-props-override` | `warning` | Rename the own prop, or accept that it intentionally overrides the `@extends` target's prop of the same name. |
|
|
442
|
+
| `sveld/jsdoc-unknown-tag` | `warning` | Fix the tag name if it's a typo (e.g. `@depreacted` → `@deprecated`); otherwise no action needed, the tag still passes through unchanged. Only surfaced under `--strict`/`--report-diagnostics`. |
|
|
443
|
+
| `sveld/typedef-duplicate` | `warning` | Rename one of the `@typedef`/`@callback` declarations; only the later one is kept. |
|
|
444
|
+
| `sveld/property-duplicate` | `warning` | Remove the duplicate `@property`; only the later one is kept. |
|
|
445
|
+
| `sveld/generics-conflict` | `warning` | Rename one of the `@generics`/`@template` declarations to a distinct generic name. |
|
|
446
|
+
| `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. |
|
|
447
|
+
| `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). |
|
|
448
|
+
|
|
449
|
+
#### Severity and `--strict=errors`
|
|
450
|
+
|
|
451
|
+
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`, `extend-props-duplicate`, `extend-props-override`, `jsdoc-unknown-tag`, `typedef-duplicate`, `property-duplicate`, `generics-conflict`, `jsdoc-tag-dropped` — a type fell back to `any`). 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:
|
|
452
|
+
|
|
453
|
+
```sh
|
|
454
|
+
npx sveld --json --strict=errors
|
|
455
|
+
```
|
|
456
|
+
|
|
457
|
+
```ts
|
|
458
|
+
await sveld({ json: true, strict: "errors" });
|
|
459
|
+
```
|
|
460
|
+
|
|
461
|
+
#### Ignoring diagnostics
|
|
462
|
+
|
|
463
|
+
Two ways to suppress a diagnostic without disabling `strict` for the whole run. Either way, the diagnostic still appears in `SveldResult.diagnostics` (with `ignored: true`) and is still counted in the text summary (`sveld: 2 unresolved types found (1 ignored).`), but never fails `--strict` / `--strict=errors`.
|
|
464
|
+
|
|
465
|
+
**Config matchers** (`diagnostics.ignore`, an array of `{ code?, component?, name? }`): every field you set on a matcher must match for it to apply; an omitted field matches anything. `component` is a glob (`*` within a path segment, `**` across segments):
|
|
466
|
+
|
|
467
|
+
```ts
|
|
468
|
+
// sveld.config.js
|
|
469
|
+
export default defineConfig({
|
|
470
|
+
diagnostics: {
|
|
471
|
+
ignore: [
|
|
472
|
+
// Every prop-unknown-type diagnostic under legacy/.
|
|
473
|
+
{ code: "sveld/prop-unknown-type", component: "./legacy/**" },
|
|
474
|
+
// One named symbol, anywhere.
|
|
475
|
+
{ name: "internalOnly" },
|
|
476
|
+
],
|
|
477
|
+
},
|
|
478
|
+
});
|
|
479
|
+
```
|
|
480
|
+
|
|
481
|
+
**Inline `@sveld-ignore <code>`**, on the same JSDoc comment as the prop, `@event` tag, or context variable it applies to:
|
|
482
|
+
|
|
483
|
+
```svelte
|
|
484
|
+
<script>
|
|
485
|
+
/**
|
|
486
|
+
* @sveld-ignore sveld/prop-unknown-type
|
|
487
|
+
*/
|
|
488
|
+
export let value;
|
|
489
|
+
</script>
|
|
490
|
+
```
|
|
491
|
+
|
|
492
|
+
```svelte
|
|
493
|
+
<script>
|
|
494
|
+
/**
|
|
495
|
+
* @event {CustomEvent<null>} legacyEvent
|
|
496
|
+
* @sveld-ignore sveld/event-no-source
|
|
497
|
+
*/
|
|
498
|
+
export let label;
|
|
499
|
+
</script>
|
|
500
|
+
```
|
|
501
|
+
|
|
502
|
+
A bare `@sveld-ignore` (no code) suppresses every diagnostic for that symbol.
|
|
503
|
+
|
|
404
504
|
## Requirements
|
|
405
505
|
|
|
406
|
-
- Node 22
|
|
506
|
+
- Node 22+ if your config is `sveld.config.js` or `sveld.config.mjs` — `sveld` declares no `engines.node` floor. A `sveld.config.ts` file loads via a raw `import()`, with no transpile step, so it only works if the runtime strips TypeScript itself: on Node this needs unflagged type stripping (Node 22.18 / 23.6+; on older Node 22 patches it's behind `--experimental-strip-types`, so use a `.js`/`.mjs` config instead), which is why Node 24 — the first current major where type stripping is always on — is the only reason to require it. Bun (see `.bun-version`) loads `.ts` configs without Node at all. CI runs on Bun and does not pin a Node version; the release workflow pins Node 24 for `actions/setup-node` on the npm publish job only, not a requirement for consumers.
|
|
407
507
|
- `sveld` is ESM-only. `require("sveld")` does not work — use `import` or dynamic `import()`.
|
|
408
|
-
- `sveld` bundles its own
|
|
508
|
+
- `sveld` bundles its own template parser to parse `.svelte` files, kept in parity with `svelte/compiler` (see [Approach](#approach)). Parsing does not depend on the Svelte version installed in your project, so Svelte 3 and Svelte 4 codebases parse the same way Svelte 5 codebases do — there is no compiler version to match up.
|
|
509
|
+
- [`resolveTypes`](#opt-in-semantic-resolution-resolvetypes) and [`checkExamples`](#compile-checked-example-blocks-checkexamples) are optional and need `typescript` 7 or later (which provides `typescript/unstable/async`) plus a `tsconfig.json`. Everything else, including `.d.ts` generation, is AST-only and never loads TypeScript. If either is enabled and TypeScript can't be started (missing, too old, or no `tsconfig.json`), the run fails loudly: `sveld()` throws and the CLI exits `2` naming the requirement, rather than silently skipping the check.
|
|
409
510
|
|
|
410
511
|
## Usage
|
|
411
512
|
|
|
@@ -444,6 +545,15 @@ export default defineConfig({
|
|
|
444
545
|
|
|
445
546
|
Since Vite uses Rollup for production builds, the same plugin works in Rollup configs.
|
|
446
547
|
|
|
548
|
+
Unlike the CLI and the programmatic `sveld()` API, the plugin ignores `sveld.config.*` by default: pass `config: true` to load it and merge it with the options given here (these take precedence over the same key in the file), or a string to point at a specific config file.
|
|
549
|
+
|
|
550
|
+
```ts
|
|
551
|
+
sveld({
|
|
552
|
+
config: true,
|
|
553
|
+
json: true, // wins over `json` set in sveld.config.*
|
|
554
|
+
});
|
|
555
|
+
```
|
|
556
|
+
|
|
447
557
|
By default, `sveld` uses the `"svelte"` field from your `package.json` to determine the entry point. You can override this by specifying an explicit `entry` option:
|
|
448
558
|
|
|
449
559
|
```js
|
|
@@ -482,7 +592,7 @@ npx sveld --json --markdown
|
|
|
482
592
|
|
|
483
593
|
If no entry point can be resolved (no `package.json#svelte` field and no `--entry`), the CLI exits `1` and prints the reason to `stderr`. If `src/index.js` happens to exist relative to your working directory, sveld falls back to it and prints a one-line note asking you to set `package.json#svelte` (or `--entry`) instead of relying on the fallback.
|
|
484
594
|
|
|
485
|
-
Flags are kebab-case: `--entry`, `--glob`, `--types`, `--json`, `--markdown`, `--fail-fast`, `--dry-run`, `--cache`, `--resolve-types`, `--check-examples`, `--report-diagnostics`, `--strict`, `--check`, `--types-format`, `--quiet`, `--stdout`, `--format`. The camelCase spellings `--resolveTypes` and `--checkExamples` still work as deprecated aliases for compatibility with existing scripts. `--entry`, `--cache`, `--check`, and `--types-format` take their value either as `--flag=value` or as a separate `--flag value` argument (`sveld --entry src/index.js` and `sveld --entry=src/index.js` are equivalent); if the next argument starts with `--` it's not consumed as a value, so `--cache` and `--check` fall back to their default location and `--entry` and `--types-format` report a usage error naming the flag. Boolean flags (`--json`, `--glob`, `--strict`, and the like) never consume a following argument. An unrecognized flag (e.g. `--markdwon`) prints `Unknown flag: --markdwon` to `stderr`, exits `1`, and skips generation; when a close match exists it appends a suggestion, e.g. `Unknown flag: --markdwon Did you mean --markdown?`. sveld takes no positional arguments, so any non-flag argument errors the same way.
|
|
595
|
+
Flags are kebab-case: `--entry`, `--glob`, `--types`, `--json`, `--markdown`, `--custom-elements`, `--llms`, `--fail-fast`, `--dry-run`, `--cache`, `--resolve-types`, `--check-examples`, `--report-diagnostics`, `--strict`, `--check`, `--check-level`, `--types-format`, `--quiet`, `--stdout`, `--format`. The camelCase spellings `--resolveTypes` and `--checkExamples` still work as deprecated aliases for compatibility with existing scripts. `--entry`, `--cache`, `--check`, and `--types-format` take their value either as `--flag=value` or as a separate `--flag value` argument (`sveld --entry src/index.js` and `sveld --entry=src/index.js` are equivalent); if the next argument starts with `--` it's not consumed as a value, so `--cache` and `--check` fall back to their default location and `--entry` and `--types-format` report a usage error naming the flag. Boolean flags (`--json`, `--glob`, `--strict`, and the like) never consume a following argument. An unrecognized flag (e.g. `--markdwon`) prints `Unknown flag: --markdwon` to `stderr`, exits `1`, and skips generation; when a close match exists it appends a suggestion, e.g. `Unknown flag: --markdwon Did you mean --markdown?`. sveld takes no positional arguments, so any non-flag argument errors the same way.
|
|
486
596
|
|
|
487
597
|
Writer progress lines (`created "..."` / `unchanged "..."`) print to `stderr`, keeping `stdout` reserved for machine-readable data. Pass `--quiet` (or `quiet: true` in `sveld.config.*`) to suppress them; it does not suppress error messages, the diagnostics summary (`--report-diagnostics` / `--strict`), or the `--check` report.
|
|
488
598
|
|
|
@@ -492,16 +602,24 @@ Pass `--stdout` alongside exactly one of `--json`, `--markdown`, or `--custom-el
|
|
|
492
602
|
|
|
493
603
|
`--stdout=ndjson` (only valid with `--json`) prints one minified JSON object per exported component per line instead of the single combined document, in the same order as the combined document's `components` array, e.g. `sveld --json --stdout=ndjson | jq -c 'select(.props | length > 0)'`. Lines are only written after the run completes (component records are only final after cross-component resolution), so this is a line-oriented serialization format, not incremental streaming. Bare `--stdout` (or `--stdout=json`) keeps the single-document behavior; any other value is a usage error.
|
|
494
604
|
|
|
495
|
-
`--format=json` switches the `--check` report and the `--report-diagnostics` / `--strict` diagnostics summary from prose to JSON, so scripts and agents don't have to regex the text output, e.g. `sveld --json --check --format=json | jq '.bump'`. Channels are unchanged: the check report prints to `stdout` and the diagnostics summary to `stderr`, same as the text format. The default remains `--format=text`; an unrecognized value (e.g. `--format=yaml`) is a usage error that prints to `stderr` and exits `1` without generating anything.
|
|
605
|
+
`--format=json` switches the `--check` report and the `--report-diagnostics` / `--strict` diagnostics summary from prose to JSON, so scripts and agents don't have to regex the text output, e.g. `sveld --json --check --format=json | jq '.bump'`. Channels are unchanged: the check report prints to `stdout` and the diagnostics summary to `stderr`, same as the text format. Each envelope (`{ kind: "check-report", schemaVersion: 1, ... }` / `{ kind: "diagnostics", schemaVersion: 1, diagnostics: [...] }`) carries its own `schemaVersion`, bumped independently of `COMPONENT_API.json`'s if either shape ever changes incompatibly. The default remains `--format=text`; an unrecognized value (e.g. `--format=yaml`) is a usage error that prints to `stderr` and exits `1` without generating anything.
|
|
606
|
+
|
|
607
|
+
`--format=github` prints [GitHub Actions workflow commands](https://docs.github.com/en/actions/using-workflows/workflow-commands-for-github-actions) instead: `::warning`/`::error` for each diagnostic (by `severity`) and `::error` for each `--check` change that meets `--check-level` (`major` by default), annotating the offending line directly in the PR's "Files changed" tab. Ignored diagnostics and changes below `--check-level` produce no annotation. When the `GITHUB_STEP_SUMMARY` env var is set (GitHub Actions sets it automatically), sveld also appends a Markdown table mirroring the same rows to that file, so the job summary shows them even for someone not reviewing the diff. A minimal workflow step:
|
|
608
|
+
|
|
609
|
+
```yaml
|
|
610
|
+
- run: npx sveld --json --check --report-diagnostics --strict=errors --format=github
|
|
611
|
+
```
|
|
496
612
|
|
|
497
613
|
Run `npx sveld --help` for the full flag list with descriptions, or `npx sveld --version` to print the installed version.
|
|
498
614
|
|
|
615
|
+
Pass `--glob` with a directory as `--entry` (no barrel file) to document every `.svelte` file under it directly, with no re-export needed: each component's sanitized filename becomes its module name in JSON, Markdown, and the generated `index.d.ts`, in addition to the per-component `.d.ts` every `--glob` run already produces. This is the same set `mergeGlobbedComponents` discovers when `--glob` is combined with a file entry; a directory entry just has no barrel to layer it onto.
|
|
616
|
+
|
|
499
617
|
### Exit codes
|
|
500
618
|
|
|
501
619
|
| Code | Meaning |
|
|
502
620
|
|------|---------|
|
|
503
621
|
| `0` | Success |
|
|
504
|
-
| `1` | Usage or configuration error (unknown flag, bad flag value, unresolvable entry) |
|
|
622
|
+
| `1` | Usage or configuration error (unknown flag, bad flag value, unresolvable entry, unresolved re-export or path alias) |
|
|
505
623
|
| `2` | Generation failure (a component failed to parse under `--fail-fast`, or an unrecoverable pipeline error) |
|
|
506
624
|
| `3` | Breaking API change detected by `--check` |
|
|
507
625
|
| `4` | Diagnostics present under `--strict` |
|
|
@@ -528,16 +646,68 @@ Suggested semver bump: major.
|
|
|
528
646
|
[BREAKING] prop "href" removed
|
|
529
647
|
```
|
|
530
648
|
|
|
531
|
-
|
|
649
|
+
| Change | Bump |
|
|
650
|
+
| --- | --- |
|
|
651
|
+
| Component added | `minor` |
|
|
652
|
+
| Component removed | `major` |
|
|
653
|
+
| Prop/export added (optional) | `minor` |
|
|
654
|
+
| Prop/export added (required) | `major` |
|
|
655
|
+
| Prop/export removed | `major` |
|
|
656
|
+
| Prop/export became required | `major` |
|
|
657
|
+
| Prop/export became optional | `minor` |
|
|
658
|
+
| Prop/export type widened (union gained a member) | `minor` |
|
|
659
|
+
| Prop/export type narrowed (union lost a member) | `major` |
|
|
660
|
+
| Prop/export type changed (anything else) | `major` |
|
|
661
|
+
| Function-typed prop/export gained a trailing optional param | `minor` |
|
|
662
|
+
| Function-typed prop/export lost a param, or return type changed | `major` |
|
|
663
|
+
| Prop gained a writable binding (`bind:`-able) | `minor` |
|
|
664
|
+
| Prop lost a writable binding | `major` |
|
|
665
|
+
| Prop/export default value changed (type unchanged) | `patch` |
|
|
666
|
+
| `@deprecated` added | `minor` |
|
|
667
|
+
| `@deprecated` removed | `patch` |
|
|
668
|
+
| `constant`/`reactive` flag flipped | `minor` |
|
|
669
|
+
| Event/slot added | `minor` |
|
|
670
|
+
| Event/slot removed | `major` |
|
|
671
|
+
| Event detail / slot props type widened | `minor` |
|
|
672
|
+
| Event detail / slot props type narrowed or otherwise changed | `major` |
|
|
673
|
+
| `generics`, `@restProps`, `@extends`, or context shape changed | `major` (not classified further) |
|
|
674
|
+
| Description-only change | not reported |
|
|
532
675
|
|
|
533
676
|
`--check` does not write the snapshot. Run `sveld --json` (or `sveld --json --check`) and commit the file when you want to update it. If there is no snapshot yet, `--check` prints a notice and exits `0`.
|
|
534
677
|
|
|
535
678
|
Use `--check=<path>` to diff against a snapshot at a custom location (defaults to `jsonOptions.outFile`, or `COMPONENT_API.json`).
|
|
536
679
|
|
|
680
|
+
By default `--check` only fails the run (exit `3`) on a `major` bump; `minor` and `patch` changes are still reported but don't fail CI. Pass `--check-level=minor` or `--check-level=patch` to fail the run at a lower threshold, e.g. to gate a package that promises no additive changes without a minor release.
|
|
681
|
+
|
|
682
|
+
If the committed snapshot's `schemaVersion` doesn't match the version `sveld` currently emits, `--check` reports a `kind: "schema"` entry instead of diffing (a version mismatch isn't a semver bump) and exits `1` (usage error): regenerate the snapshot with `sveld --json`.
|
|
683
|
+
|
|
537
684
|
The CLI exits non-zero on any fatal error (an unreadable entry, a config file that throws, etc.), not just on `--strict`/`--check` findings, so it's safe to use either flag as a CI gate. See [Exit codes](#exit-codes) for how these are differentiated.
|
|
538
685
|
|
|
539
686
|
Pass `--format=json` for a machine-readable report on `stdout` instead of the prose above, e.g. `sveld --check --format=json | jq '.bump'` or `sveld --check --format=json | jq '.changes[] | select(.bump == "major")'`.
|
|
540
687
|
|
|
688
|
+
### CI: strictness profiles (`--strict=ci`/`--strict=local`)
|
|
689
|
+
|
|
690
|
+
CI and local runs usually want a different bundle of `strict`, `reportDiagnostics`, `check`, and `checkExamples` flags, previously assembled by hand. `--strict=ci`/`strict: "ci"` and `--strict=local`/`strict: "local"` are shorthands for two common bundles. Bare `--strict`/`strict: true` (and `--strict=errors`) are unchanged.
|
|
691
|
+
|
|
692
|
+
`--strict=ci` expands to `{ strict: true, reportDiagnostics: true, check: true, checkExamples: true }` — the full gate for a CI job:
|
|
693
|
+
|
|
694
|
+
```sh
|
|
695
|
+
npx sveld --json --strict=ci
|
|
696
|
+
```
|
|
697
|
+
|
|
698
|
+
`--strict=local` expands to `{ reportDiagnostics: true }` — diagnostics printed for a developer to see, without failing the command or requiring a committed `COMPONENT_API.json` snapshot:
|
|
699
|
+
|
|
700
|
+
```sh
|
|
701
|
+
npx sveld --json --strict=local
|
|
702
|
+
```
|
|
703
|
+
|
|
704
|
+
The profile's keys are applied first, then any other key set alongside `strict` overrides it, so you can opt back out of one piece:
|
|
705
|
+
|
|
706
|
+
```ts
|
|
707
|
+
// Everything --strict=ci implies, except the TypeScript-checked half of checkExamples.
|
|
708
|
+
await sveld({ json: true, strict: "ci", checkExamples: "syntax" });
|
|
709
|
+
```
|
|
710
|
+
|
|
541
711
|
### Node.js
|
|
542
712
|
|
|
543
713
|
You can also call `sveld` from Node.js. See [Requirements](#requirements) for supported Node versions and the ESM-only constraint.
|
|
@@ -570,19 +740,20 @@ const { diagnostics } = await sveld({
|
|
|
570
740
|
});
|
|
571
741
|
```
|
|
572
742
|
|
|
573
|
-
`diagnostics` is always populated; printing is opt-in via `reportDiagnostics` or `strict` (see [Type inference diagnostics](#type-inference-diagnostics)).
|
|
743
|
+
`diagnostics` is always populated; printing is opt-in via `reportDiagnostics` or `strict` (see [Type inference diagnostics](#type-inference-diagnostics)). `errors` is always populated too: components that failed to parse, whether or not `failFast` is set.
|
|
574
744
|
|
|
575
|
-
Pass `check: true` (or `check: "<path>"` for a custom snapshot location) to diff against a committed `COMPONENT_API.json`, the same way `--check` does on the CLI. The result lands on `SveldResult.check
|
|
745
|
+
Pass `check: true` (or `check: "<path>"` for a custom snapshot location) to diff against a committed `COMPONENT_API.json`, the same way `--check` does on the CLI. The result lands on `SveldResult.check`. `sveld()` never touches `process.exitCode` itself; it returns a suggested `exitCode` (`0`, `3` for a breaking `check` result, or `4` for `strict` diagnostics — the same mapping the CLI uses, `3` winning over `4`) so you can assign it yourself:
|
|
576
746
|
|
|
577
747
|
```js
|
|
578
748
|
import { formatCheckReport } from "sveld";
|
|
579
749
|
|
|
580
|
-
const { check } = await sveld({ json: true, check: true });
|
|
750
|
+
const { check, exitCode } = await sveld({ json: true, check: true });
|
|
581
751
|
|
|
582
752
|
if (check) {
|
|
583
753
|
console.log(formatCheckReport(check));
|
|
584
|
-
if (check.bump === "major") process.exitCode = 1;
|
|
585
754
|
}
|
|
755
|
+
|
|
756
|
+
process.exitCode = exitCode;
|
|
586
757
|
```
|
|
587
758
|
|
|
588
759
|
See [CI: API-drift checks (`--check`)](#ci-api-drift-checks---check) for how changes are classified.
|
|
@@ -604,6 +775,23 @@ sveld({
|
|
|
604
775
|
});
|
|
605
776
|
```
|
|
606
777
|
|
|
778
|
+
#### `jsonOptions.source`
|
|
779
|
+
|
|
780
|
+
Every prop, slot, event, typedef, and context in `COMPONENT_API.json` carries a `source` position range (plus `componentCommentSource` on the component itself) when the parser has a stable AST position for it. For a large component library this is a substantial share of the file — roughly a quarter of `COMPONENT_API.json` for a 150+ component library — and many consumers (docs sites, LLM context) never read it.
|
|
781
|
+
|
|
782
|
+
Set `jsonOptions.source` to `false` to omit every `source`/`componentCommentSource` range and shrink the file:
|
|
783
|
+
|
|
784
|
+
```js
|
|
785
|
+
sveld({
|
|
786
|
+
json: true,
|
|
787
|
+
jsonOptions: {
|
|
788
|
+
source: false,
|
|
789
|
+
},
|
|
790
|
+
});
|
|
791
|
+
```
|
|
792
|
+
|
|
793
|
+
`source: true` is the default; every other field is unaffected. `EntryExport.source` (the declaring module's relative path, from `documentExports`) is a different field with a string value and is never stripped.
|
|
794
|
+
|
|
607
795
|
### Browser
|
|
608
796
|
|
|
609
797
|
`sveld/browser` is a Node-free subpath export for running `sveld` client-side — e.g. an in-browser Svelte playground or REPL that parses whatever `.svelte` source the user typed and renders docs for it live. It bundles with Vite, esbuild, webpack, or Rollup without a `node:fs`/`node:path` polyfill.
|
|
@@ -647,11 +835,11 @@ const cem = buildCustomElementsManifest(components, {
|
|
|
647
835
|
|
|
648
836
|
`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.
|
|
649
837
|
|
|
650
|
-
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.
|
|
838
|
+
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).
|
|
651
839
|
|
|
652
840
|
### Config File
|
|
653
841
|
|
|
654
|
-
Put a `sveld.config.js`, `sveld.config.mjs`, or `sveld.config.ts` at your project root to set defaults for the CLI and the programmatic `sveld()` API.
|
|
842
|
+
Put a `sveld.config.js`, `sveld.config.mjs`, or `sveld.config.ts` at your project root to set defaults for the CLI and the programmatic `sveld()` API. The Vite/Rollup plugin ignores it unless you opt in with the [`config`](#vite) option.
|
|
655
843
|
|
|
656
844
|
Import `defineConfig` from `sveld` for typed options. Config files must use ESM syntax (`export default`).
|
|
657
845
|
|
|
@@ -683,6 +871,19 @@ export default {
|
|
|
683
871
|
};
|
|
684
872
|
```
|
|
685
873
|
|
|
874
|
+
Merging is one level deep for object-valued options (`typesOptions`, `jsonOptions`, `markdownOptions`, `customElementsOptions`, `additionalWriters`): setting one nested key at the CLI or in `sveld()` doesn't drop sibling keys set in the config file. Arrays and functions (e.g. `markdownOptions.onAppend`) are replaced outright, never merged.
|
|
875
|
+
|
|
876
|
+
```js
|
|
877
|
+
// sveld.config.js
|
|
878
|
+
export default {
|
|
879
|
+
typesOptions: { outDir: "dist", preamble: "// license" },
|
|
880
|
+
};
|
|
881
|
+
```
|
|
882
|
+
|
|
883
|
+
`npx sveld --types-format=component` keeps `outDir` and `preamble` from the file and adds `format: "component"`, rather than replacing `typesOptions` entirely.
|
|
884
|
+
|
|
885
|
+
An unrecognized option key (top-level, or inside a `*Options` object) is not an error: it prints a `console.warn` naming the key, with a "did you mean" suggestion when a known key is close enough.
|
|
886
|
+
|
|
686
887
|
A bad config (syntax error, throws at load time, or no default-export object) fails with an error that names the file.
|
|
687
888
|
|
|
688
889
|
### Publishing to NPM
|
|
@@ -726,22 +927,33 @@ The `svelte` condition lets bundlers that understand it (Vite, Rollup, webpack v
|
|
|
726
927
|
- **`jsonOptions`** (object, optional): Options for JSON output.
|
|
727
928
|
- **`outFile`** (string, optional, default: `"COMPONENT_API.json"`): Path (relative to the project root) for the single combined JSON document. Ignored when `outDir` is set.
|
|
728
929
|
- **`outDir`** (string, optional): Emit one JSON file per component (`<ComponentName>.api.json`) into this directory instead of a single combined file. See [`jsonOptions.outDir`](#jsonoptionsoutdir).
|
|
930
|
+
- **`source`** (boolean, optional, default: `true`): Set to `false` to omit every `source`/`componentCommentSource` position range from the output. See [`jsonOptions.source`](#jsonoptionssource).
|
|
729
931
|
- **`markdown`** (boolean, optional): Generate component documentation in Markdown format.
|
|
730
932
|
- **`markdownOptions`** (object, optional): Options for Markdown output.
|
|
731
|
-
- **`outFile`** (string, optional, default: `"COMPONENT_INDEX.md"`): Path (relative to the project root) for the
|
|
732
|
-
- **`
|
|
933
|
+
- **`outFile`** (string, optional, default: `"COMPONENT_INDEX.md"`): Path (relative to the project root) for the single combined Markdown document. Ignored when `outDir` is set.
|
|
934
|
+
- **`outDir`** (string, optional): Emit one `<ModuleName>.md` file per component into this directory, plus an index `README.md` linking to each, instead of a single combined file. See [`markdownOptions.outDir`](#markdownoptionsoutdir).
|
|
935
|
+
- **`write`** (boolean, optional, default: `true`): Set to `false` to skip writing to disk — the rendered combined document is still returned, or (with `outDir` set) no files are written at all.
|
|
733
936
|
- **`onAppend`** (function, optional): Callback invoked every time a heading, quote, paragraph, divider, or raw block is appended to the document. Lets you inject extra content, e.g. a summary line under the title. See [`markdownOptions.onAppend`](#markdownoptionsonappend) below.
|
|
734
937
|
- **`customElements`** (boolean, optional): Generate a [Custom Elements Manifest](#custom-elements-manifest) (`custom-elements.json`). Also available as the `--custom-elements` CLI flag.
|
|
735
938
|
- **`customElementsOptions`** (object, optional): Options for Custom Elements Manifest output.
|
|
736
939
|
- **`outFile`** (string, optional, default: `"custom-elements.json"`): Path (relative to the project root) for the generated manifest file.
|
|
737
|
-
- **`
|
|
940
|
+
- **`llms`** (boolean, optional): Generate an [`llms.txt` / `llms-full.txt`](#llmstxt-output) pair. Also available as the `--llms` CLI flag.
|
|
941
|
+
- **`llmsOptions`** (object, optional): Options for `llms.txt` / `llms-full.txt` output.
|
|
942
|
+
- **`outDir`** (string, optional): Directory (relative to the project root) both files are written into. Defaults to the project root.
|
|
943
|
+
- **`linkBase`** (string, optional, default: `""`): Prefixed to each component's link in `llms.txt`.
|
|
944
|
+
- **`title`** (string, optional, default: the `"name"` field from `package.json`): The `# <title>` heading both files start with.
|
|
945
|
+
- **`summary`** (string, optional, default: the `"description"` field from `package.json`): The `> <summary>` blockquote under the title.
|
|
946
|
+
- **`config`** (boolean | string, optional, default: `false`): Load `sveld.config.{js,mjs,ts}` and merge it with these options; these options win when a key is set in both. `true` resolves the config from the Vite project root (or `process.cwd()` outside Vite); a string is an explicit path to the config file. See [Config File](#config-file).
|
|
947
|
+
- **`watch`** (boolean, optional, default: `false`): Regenerate output incrementally when relevant source changes during `vite dev` / `vite build --watch`. A reparse is triggered by: editing a component; editing the entry barrel itself, which adds/removes the corresponding component; or editing a non-`.svelte` file a component depends on via [`@extendProps`](#extendprops) / `@extends` or a typedef `import("./x")` reference. Only the affected components are re-parsed, rather than rebuilding every component. Overlapping regenerations are queued, never run concurrently. Without this option, the plugin only runs during `vite build`.
|
|
738
948
|
- **`failFast`** (boolean, optional, default: `false`): Abort the entire run when a single component fails to parse. By default, parse failures are collected as diagnostics (and reported to `stderr`) so the remaining components still emit their output. Also available as the `--fail-fast` CLI flag.
|
|
739
949
|
- **`resolveTypes`** (boolean, optional, default: `false`): Load the TypeScript program to expand opaque imported whole-object `$props()` types into JSON. Also available as `--resolve-types` (`--resolveTypes` remains as a deprecated alias). See [Opt-in semantic resolution](#opt-in-semantic-resolution-resolvetypes).
|
|
740
950
|
- **`cache`** (boolean | string, optional, default: `true`): Write parsed component output to disk and skip re-parsing unchanged files on later runs. On by default, writing to `node_modules/.cache/sveld/parse-cache.json`; a string sets a custom path; pass `false` to disable. Also available as `--cache` / `--cache=<path>` / `--cache=false`. See [Persistent parse cache](#persistent-parse-cache-cache).
|
|
741
|
-
- **`checkExamples`** (boolean
|
|
951
|
+
- **`checkExamples`** (`boolean | "syntax"`, optional, default: `false`): `true` runs plain TS/JS `@example` blocks through the TypeScript program (`example-compile-error` diagnostics) and `svelte`/`html` blocks through sveld's own template parser (`example-syntax-error` diagnostics). `"syntax"` runs only the markup path, so `typescript` is never loaded. Also available as `--check-examples` / `--check-examples=syntax` (`--checkExamples` remains as a deprecated alias). See [Compile-checked `@example` blocks](#compile-checked-example-blocks-checkexamples).
|
|
742
952
|
- **`reportDiagnostics`** (boolean, optional, default: `false`): Print unresolved-type diagnostics to stderr (CLI) or `console.warn` (programmatic API). Also available as `--report-diagnostics`. See [Type inference diagnostics](#type-inference-diagnostics).
|
|
743
|
-
- **`strict`** (boolean
|
|
953
|
+
- **`strict`** (`boolean | "errors" | "ci" | "local"`, optional, default: `false`): Exit with code `4` when diagnostics exist. Implies `reportDiagnostics`. `"errors"` fails only on `severity: "error"` diagnostics, letting `warning` ones through. `"ci"` and `"local"` are strictness profiles that expand into other options before this object's own keys are applied. Also available as `--strict` / `--strict=errors` / `--strict=ci` / `--strict=local`. See [Type inference diagnostics](#type-inference-diagnostics) and [CI: strictness profiles](#ci-strictness-profiles---strictci---strictlocal).
|
|
954
|
+
- **`diagnostics.ignore`** (`Array<{ code?: string; component?: string; name?: string }>`, optional): Marks matching diagnostics `ignored` — they're still reported and counted, but never fail `strict`. `component` is a glob; an omitted field on a matcher matches anything. No CLI flag; config-file or `sveld()` only. See [Ignoring diagnostics](#ignoring-diagnostics).
|
|
744
955
|
- **`check`** (boolean | string, optional, default: `false`): Diff the parsed component API against a committed snapshot and assign a semver bump to each change. `true` uses the `json` writer's `outFile` (or `COMPONENT_API.json`); a string sets a custom snapshot path. Also available as `--check` / `--check=<path>`. On the CLI this exits `3` on a breaking change; from `sveld()` it's returned on `SveldResult.check` for you to act on. See [CI: API-drift checks (`--check`)](#ci-api-drift-checks---check).
|
|
956
|
+
- **`checkLevel`** (`"major" | "minor" | "patch"`, optional, default: `"major"`): Minimum bump `--check` fails the CLI run on. Also available as `--check-level`. See [CI: API-drift checks (`--check`)](#ci-api-drift-checks---check).
|
|
745
957
|
- **`quiet`** (boolean, optional, default: `false`): Suppress writer progress logs (`created "..."` / `unchanged "..."`), which print to `stderr` by default. Does not suppress error messages, the diagnostics summary, or the `--check` report. Also available as `--quiet`.
|
|
746
958
|
- **`dryRun`** (boolean, optional, default: `false`): Resolve the entry, load config, and parse components through the real pipeline, then print `would write "<path>"` to `stdout` for each output file instead of writing it, including the parse cache. Diagnostics, `strict`, and `check` behave as in a real run. CLI-only via `--dry-run`; the Vite plugin does not expose this option.
|
|
747
959
|
|
|
@@ -806,6 +1018,24 @@ sveld({
|
|
|
806
1018
|
> 1 components exported from sveld-scratch@1.0.0.
|
|
807
1019
|
```
|
|
808
1020
|
|
|
1021
|
+
#### `markdownOptions.outDir`
|
|
1022
|
+
|
|
1023
|
+
With `markdown: true`, `sveld` writes a single `COMPONENT_INDEX.md` at the project root, documenting every component.
|
|
1024
|
+
|
|
1025
|
+
Use `markdownOptions.outDir` to split that into one `<ModuleName>.md` file per component, plus an index `README.md` that links to each one (and holds the Exports section when `documentExports` is on — per-component sections live entirely in their own file):
|
|
1026
|
+
|
|
1027
|
+
```js
|
|
1028
|
+
sveld({
|
|
1029
|
+
markdown: true,
|
|
1030
|
+
markdownOptions: {
|
|
1031
|
+
// e.g. "docs/Button.md", "docs/README.md"
|
|
1032
|
+
outDir: "docs",
|
|
1033
|
+
},
|
|
1034
|
+
});
|
|
1035
|
+
```
|
|
1036
|
+
|
|
1037
|
+
`onAppend` still fires for both the index and every per-component file. `outFile` is ignored once `outDir` is set.
|
|
1038
|
+
|
|
809
1039
|
## Documenting Entry Exports
|
|
810
1040
|
|
|
811
1041
|
Most entry barrels re-export more than `.svelte` components. Set `documentExports: true` to add consts, functions, and types to the JSON and Markdown output.
|
|
@@ -830,7 +1060,11 @@ export type { Theme } from "./types";
|
|
|
830
1060
|
|
|
831
1061
|
From that barrel, `sveld` documents `VERSION`, `clamp`, and `Theme`. `Button` still goes through the component path. Type text is copied from source, not resolved with `tsc`, same as the rest of the tool.
|
|
832
1062
|
|
|
833
|
-
|
|
1063
|
+
Nested barrels are followed too: `export { X } from "./dir"`, where `./dir/index.js` itself re-exports `.svelte` files, resolves `X` to the underlying component without needing `--glob`.
|
|
1064
|
+
|
|
1065
|
+
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).
|
|
1066
|
+
|
|
1067
|
+
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 different modules export the same name (most commonly via `export * from "./a"; export * from "./b"`), `sveld` keeps whichever was declared first and prints a warning; it does not silently pick one or emit both.
|
|
834
1068
|
|
|
835
1069
|
## JSON Output
|
|
836
1070
|
|
|
@@ -839,6 +1073,14 @@ component API. For stable output, generated `events` arrays are emitted in deter
|
|
|
839
1073
|
|
|
840
1074
|
The JSON Schema lives on GitHub ([path to file](https://github.com/carbon-design-system/sveld/blob/main/schema/component-api.schema.json), [raw URL](https://raw.githubusercontent.com/carbon-design-system/sveld/main/schema/component-api.schema.json)). Use it to validate generated `COMPONENT_API.json` files. Optional fields may be missing when the parser has no stable source for that metadata.
|
|
841
1075
|
|
|
1076
|
+
`sveld` also ships the schema as a package subpath, so you don't need network access to validate at build time:
|
|
1077
|
+
|
|
1078
|
+
```ts
|
|
1079
|
+
import schema from "sveld/schema/component-api.schema.json" with { type: "json" };
|
|
1080
|
+
```
|
|
1081
|
+
|
|
1082
|
+
`require.resolve("sveld/schema/component-api.schema.json")` works too. The `$id` in the schema still points at the `main` branch on GitHub for tooling that dereferences it by URL, but that URL always reflects the latest release; the copy packaged with your installed `sveld` version is the authoritative one for the output it produced.
|
|
1083
|
+
|
|
842
1084
|
```ts
|
|
843
1085
|
interface ComponentApiJson {
|
|
844
1086
|
schemaVersion: 1;
|
|
@@ -860,6 +1102,8 @@ interface EntryExport {
|
|
|
860
1102
|
type?: string;
|
|
861
1103
|
value?: string;
|
|
862
1104
|
description?: string;
|
|
1105
|
+
deprecated?: string | true;
|
|
1106
|
+
tags?: Array<{ name: string; body: string }>;
|
|
863
1107
|
source?: string;
|
|
864
1108
|
isTypeOnly: boolean;
|
|
865
1109
|
}
|
|
@@ -974,15 +1218,62 @@ sveld({
|
|
|
974
1218
|
|
|
975
1219
|
Each exported component becomes one `javascript-module` with a class declaration:
|
|
976
1220
|
|
|
977
|
-
- **Members** — every prop becomes a `ClassField` (`name`, `type.text`, `default`, `description`, `deprecated`).
|
|
978
|
-
- **Attributes** —
|
|
1221
|
+
- **Members** — every `export let`/`const` prop becomes a `ClassField` (`name`, `type.text`, `default`, `description`, `deprecated`; `readonly: true` for an `export const`). An accessor prop (`export function`) becomes a `ClassMethod` (`name`, `static: false`, `parameters`, `return.type.text`) instead — see [Accessor methods](#accessor-methods) below.
|
|
1222
|
+
- **Attributes** — every prop becomes an attribute (Svelte's custom-element runtime observes one for every prop by default), excluding `export function` accessors. The attribute name is `prop.toLowerCase()` by default, or the `customElement.props.<name>.attribute` config when set — see [Object-form `customElement` config](#object-form-customelement-config) below. Props that collide on the same attribute name keep the first (in declaration order); the rest are skipped with a console warning, since which one wins at runtime is ambiguous.
|
|
979
1223
|
- **Events** — dispatched events (`createEventDispatcher()`, and `$host().dispatchEvent(...)` from inside a custom element) become `{ name, type: { text: "CustomEvent<...>" } }`. Forwarded (`on:click`) events are left out, since they aren't dispatched by the component's own class.
|
|
980
1224
|
- **Slots** — named and default slots, with descriptions. The default slot's `name` is `""`, matching the CEM convention.
|
|
1225
|
+
- **`cssParts`/`cssProperties`** — from `@csspart`/`@cssprop` JSDoc tags — see [CSS parts and custom properties](#css-parts-and-custom-properties) below.
|
|
981
1226
|
|
|
982
1227
|
When a component sets `<svelte:options customElement="x-foo" />` (or the object form, `<svelte:options customElement={{ tag: "x-foo" }} />`), its declaration gets `tagName: "x-foo"` and `customElement: true`, and the module's `exports` include a `custom-element-definition` export alongside the plain `js` export.
|
|
983
1228
|
|
|
984
1229
|
Components without `customElement` still emit a plain class declaration (no `tagName`/`customElement`) — useful for documenting the class shape even before it's compiled as a custom element, but the manifest is most useful for `customElement`-compiled builds, where downstream tooling can resolve `tagName`, `attributes`, and `events` for actual custom-element usage.
|
|
985
1230
|
|
|
1231
|
+
### Object-form `customElement` config
|
|
1232
|
+
|
|
1233
|
+
The object form of `<svelte:options customElement={{ ... }} />` is read in full, not just `tag`:
|
|
1234
|
+
|
|
1235
|
+
```svelte
|
|
1236
|
+
<svelte:options
|
|
1237
|
+
customElement={{
|
|
1238
|
+
tag: "x-widget",
|
|
1239
|
+
shadow: "none",
|
|
1240
|
+
props: {
|
|
1241
|
+
variant: { attribute: "data-variant" },
|
|
1242
|
+
active: { reflect: true },
|
|
1243
|
+
tags: { type: "Array" }
|
|
1244
|
+
},
|
|
1245
|
+
extend: (customElementConstructor) => customElementConstructor
|
|
1246
|
+
}}
|
|
1247
|
+
/>
|
|
1248
|
+
```
|
|
1249
|
+
|
|
1250
|
+
| Config | Effect on the manifest |
|
|
1251
|
+
| --- | --- |
|
|
1252
|
+
| `props.<name>.attribute` | Overrides that prop's attribute name (default: `name.toLowerCase()`). `attribute: false` omits the prop's attribute entirely. |
|
|
1253
|
+
| `props.<name>.reflect` | Adds `reflects: true` to that prop's attribute. |
|
|
1254
|
+
| `props.<name>.type` | `"Array"`/`"Object"` appends a note to the attribute's description that the value is JSON-serialized (matching Svelte's runtime `JSON.stringify`/`JSON.parse` for those types); the attribute's `type.text` is still the prop's own TS type, not this config value. |
|
|
1255
|
+
| `shadow`, `extend` | Parsed and available on the raw `ParsedComponent.customElement` (Node API), but don't affect the manifest. |
|
|
1256
|
+
|
|
1257
|
+
This full config (`tag`, `shadow`, `props`, `extend`) is also on `ParsedComponent.customElement` in the JSON output (`COMPONENT_API.json`), alongside the existing `customElementTag` shorthand.
|
|
1258
|
+
|
|
1259
|
+
### Accessor methods
|
|
1260
|
+
|
|
1261
|
+
An `export function` prop (a Svelte accessor, e.g. `export function focus() { ... }`) becomes a `ClassMethod`, not a `ClassField`, and is excluded from `attributes` (accessors aren't part of Svelte's props definition). `parameters`/`return` come from `@param`/`@returns` JSDoc when present, otherwise from splitting the function's TypeScript signature text (e.g. `(id: string) => boolean`).
|
|
1262
|
+
|
|
1263
|
+
### CSS parts and custom properties
|
|
1264
|
+
|
|
1265
|
+
Document shadow-DOM styling hooks with `@csspart`/`@cssprop` (alias `@cssproperty`) tags in the component's own JSDoc comment (the same comment block `@slot` tags go in):
|
|
1266
|
+
|
|
1267
|
+
```js
|
|
1268
|
+
/**
|
|
1269
|
+
* @csspart header - Styles the header region.
|
|
1270
|
+
* @cssprop {Color} [--card-background=white] - Background color of the card.
|
|
1271
|
+
* @cssprop --card-border-color - Border color of the card.
|
|
1272
|
+
*/
|
|
1273
|
+
```
|
|
1274
|
+
|
|
1275
|
+
`@cssprop`'s `{type}` and `[--name=default]` are both optional, following the [Custom Elements Manifest analyzer](https://custom-elements-manifest.open-wc.org/analyzer/getting-started/#css-custom-properties) grammar. These populate `cssParts`/`cssProperties` on the class declaration, and `ParsedComponent.cssParts`/`cssProperties` in the JSON output; the Markdown writer renders them as two extra tables when present.
|
|
1276
|
+
|
|
986
1277
|
### Consuming the manifest
|
|
987
1278
|
|
|
988
1279
|
Most tools discover `custom-elements.json` through a `customElements` field in `package.json`, pointing at the generated file:
|
|
@@ -999,6 +1290,25 @@ With that in place:
|
|
|
999
1290
|
- [Storybook](https://storybook.js.org/docs/api/doc-blocks/doc-block-argtypes#extracting-argtypes) for web components reads the manifest to auto-generate `argTypes` (controls, docs tables) for `customElement`-compiled components, once you point it at the file (e.g. `setCustomElementsManifest` from `@storybook/web-components`, or `customElements: "custom-elements.json"` in `.storybook/main.js`).
|
|
1000
1291
|
- Any other tool built against the [Custom Elements Manifest spec](https://github.com/webcomponents/custom-elements-manifest) (API viewers, doc generators, linters) can read the file directly without sveld-specific integration.
|
|
1001
1292
|
|
|
1293
|
+
## llms.txt Output
|
|
1294
|
+
|
|
1295
|
+
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`.
|
|
1296
|
+
|
|
1297
|
+
```diff
|
|
1298
|
+
sveld({
|
|
1299
|
+
+ llms: true,
|
|
1300
|
+
})
|
|
1301
|
+
```
|
|
1302
|
+
|
|
1303
|
+
- **`llms`** (boolean, optional): Generate `llms.txt` and `llms-full.txt`. Also available as the `--llms` CLI flag.
|
|
1304
|
+
- **`llmsOptions`** (object, optional):
|
|
1305
|
+
- **`outDir`** (string, optional): Directory (relative to the project root) both files are written into. Defaults to the project root.
|
|
1306
|
+
- **`linkBase`** (string, optional, default: `""`): Prefixed to each component's link in `llms.txt`, e.g. `[Button](<linkBase>/Button)`. Set this to your published docs site's base path.
|
|
1307
|
+
- **`title`** (string, optional, default: the `"name"` field from `package.json`): The `# <title>` heading both files start with.
|
|
1308
|
+
- **`summary`** (string, optional, default: the `"description"` field from `package.json`): The `> <summary>` blockquote under the title. Omitted when neither is set.
|
|
1309
|
+
|
|
1310
|
+
Each component's one-line summary in `llms.txt` is the first sentence of its [`@component` comment](#component-comments), falling back to `"Component"`. Set `documentExports: true` to also list entry-barrel exports (consts, functions, types) in `llms.txt` under an `## Exports` heading.
|
|
1311
|
+
|
|
1002
1312
|
## Custom Writers
|
|
1003
1313
|
|
|
1004
1314
|
`json`, `markdown`, `types`, and `custom-elements` are all built on the same
|
|
@@ -1035,6 +1345,8 @@ interface OutputWriter<TOptions = unknown> {
|
|
|
1035
1345
|
(also exported from `sveld`) to get the sorted, `diagnostics`-stripped,
|
|
1036
1346
|
schema-versioned document the built-in writers build from. It's memoized
|
|
1037
1347
|
per `components` map, so calling it more than once in one run is free.
|
|
1348
|
+
- **`options`** always carries `dryRun` alongside whatever fields the writer
|
|
1349
|
+
itself defines. See [The `dryRun` contract](#the-dryrun-contract) below.
|
|
1038
1350
|
|
|
1039
1351
|
### Registering a writer
|
|
1040
1352
|
|
|
@@ -1053,6 +1365,50 @@ registerWriter({
|
|
|
1053
1365
|
runs, e.g. at the top of `vite.config.ts` or `sveld.config.ts`, or in a file
|
|
1054
1366
|
either of those imports.
|
|
1055
1367
|
|
|
1368
|
+
Registering a `name` that's already taken — a built-in writer's name, or
|
|
1369
|
+
another `registerWriter` call — throws instead of silently overwriting it.
|
|
1370
|
+
Pass `{ replace: true }` as a second argument when overwriting is intentional
|
|
1371
|
+
(e.g. re-registering a writer module during development):
|
|
1372
|
+
|
|
1373
|
+
```ts
|
|
1374
|
+
registerWriter(
|
|
1375
|
+
{
|
|
1376
|
+
name: "my-format",
|
|
1377
|
+
write(components, options) {
|
|
1378
|
+
// ...
|
|
1379
|
+
},
|
|
1380
|
+
},
|
|
1381
|
+
{ replace: true },
|
|
1382
|
+
);
|
|
1383
|
+
```
|
|
1384
|
+
|
|
1385
|
+
### The `dryRun` contract
|
|
1386
|
+
|
|
1387
|
+
Every writer — built-in or `additionalWriters` — receives `dryRun: true` in
|
|
1388
|
+
its `options` when the run is `sveld --dry-run` (or `{ dryRun: true }` from
|
|
1389
|
+
the programmatic API). A writer must check it and skip touching disk; sveld
|
|
1390
|
+
does not do this for you:
|
|
1391
|
+
|
|
1392
|
+
```ts
|
|
1393
|
+
import { writeFileSync } from "node:fs";
|
|
1394
|
+
|
|
1395
|
+
registerWriter({
|
|
1396
|
+
name: "my-format",
|
|
1397
|
+
write(components, options: { outFile: string; dryRun?: boolean }) {
|
|
1398
|
+
if (options.dryRun) {
|
|
1399
|
+
console.log(`would write "${options.outFile}"`);
|
|
1400
|
+
return;
|
|
1401
|
+
}
|
|
1402
|
+
writeFileSync(options.outFile, "...");
|
|
1403
|
+
},
|
|
1404
|
+
});
|
|
1405
|
+
```
|
|
1406
|
+
|
|
1407
|
+
A writer that throws — synchronously or from a rejected promise — has its
|
|
1408
|
+
error re-thrown as `sveld: writer "<name>" failed: <message>`, with the
|
|
1409
|
+
original error attached as `cause`, so a broken third-party writer never
|
|
1410
|
+
fails silently or without saying which one.
|
|
1411
|
+
|
|
1056
1412
|
### Running it via the plugin
|
|
1057
1413
|
|
|
1058
1414
|
```ts
|
|
@@ -1079,36 +1435,28 @@ alongside whichever built-in outputs (`types` / `json` / `markdown` /
|
|
|
1079
1435
|
programmatic Node API and from `sveld.config.ts` (`additionalWriters` lives on
|
|
1080
1436
|
the options shared by all three entry points).
|
|
1081
1437
|
|
|
1082
|
-
### Worked example: a
|
|
1438
|
+
### Worked example: a `components.txt` name-list writer
|
|
1083
1439
|
|
|
1084
|
-
|
|
1085
|
-
[llms.txt](https://llmstxt.org)-aware tools look for — is a good demo because
|
|
1086
|
-
it needs nothing beyond `ComponentApiDocument`.
|
|
1440
|
+
Looking for an `llms.txt` writer specifically? Sveld ships one — see [llms.txt Output](#llmstxt-output). This example is a much smaller custom writer, just to show the pattern: a plain-text list of exported component names, needing nothing beyond `ComponentApiDocument`.
|
|
1087
1441
|
|
|
1088
1442
|
```ts
|
|
1089
|
-
// writers/
|
|
1443
|
+
// writers/components-txt-writer.ts
|
|
1090
1444
|
import { writeFileSync } from "node:fs";
|
|
1091
1445
|
import { join } from "node:path";
|
|
1092
1446
|
import { buildComponentApiDocument, registerWriter } from "sveld";
|
|
1093
1447
|
|
|
1094
|
-
interface
|
|
1448
|
+
interface ComponentsTxtWriterOptions {
|
|
1095
1449
|
outFile?: string;
|
|
1096
1450
|
}
|
|
1097
1451
|
|
|
1098
|
-
registerWriter<
|
|
1099
|
-
name: "
|
|
1452
|
+
registerWriter<ComponentsTxtWriterOptions>({
|
|
1453
|
+
name: "components-txt",
|
|
1100
1454
|
componentSet: "exported",
|
|
1101
1455
|
write(components, options = {}) {
|
|
1102
1456
|
const document = buildComponentApiDocument(components);
|
|
1457
|
+
const rendered = document.components.map((component) => component.moduleName).join("\n");
|
|
1103
1458
|
|
|
1104
|
-
|
|
1105
|
-
const props = component.props.map((prop) => `${prop.name}: ${prop.type ?? "unknown"}`).join(", ");
|
|
1106
|
-
return `## ${component.moduleName}\n\nProps: ${props || "none"}`;
|
|
1107
|
-
});
|
|
1108
|
-
|
|
1109
|
-
const rendered = ["# My Library", "", "> Auto-generated component reference.", "", ...sections].join("\n\n");
|
|
1110
|
-
|
|
1111
|
-
writeFileSync(join(process.cwd(), options.outFile ?? "llms.txt"), rendered);
|
|
1459
|
+
writeFileSync(join(process.cwd(), options.outFile ?? "components.txt"), rendered);
|
|
1112
1460
|
},
|
|
1113
1461
|
});
|
|
1114
1462
|
```
|
|
@@ -1116,21 +1464,21 @@ registerWriter<LlmsWriterOptions>({
|
|
|
1116
1464
|
```ts
|
|
1117
1465
|
// vite.config.ts
|
|
1118
1466
|
import sveld from "sveld";
|
|
1119
|
-
import "./writers/
|
|
1467
|
+
import "./writers/components-txt-writer";
|
|
1120
1468
|
|
|
1121
1469
|
export default {
|
|
1122
1470
|
plugins: [
|
|
1123
1471
|
sveld({
|
|
1124
1472
|
additionalWriters: {
|
|
1125
|
-
"
|
|
1473
|
+
"components-txt": { outFile: "components.txt" },
|
|
1126
1474
|
},
|
|
1127
1475
|
}),
|
|
1128
1476
|
],
|
|
1129
1477
|
};
|
|
1130
1478
|
```
|
|
1131
1479
|
|
|
1132
|
-
Running a build now produces
|
|
1133
|
-
one
|
|
1480
|
+
Running a build now produces a `components.txt` alongside the usual output,
|
|
1481
|
+
listing one exported component name per line.
|
|
1134
1482
|
|
|
1135
1483
|
## API Reference
|
|
1136
1484
|
|
|
@@ -2028,7 +2376,7 @@ Descriptions are optional for every slot, including the default slot. Put prose
|
|
|
2028
2376
|
*/
|
|
2029
2377
|
```
|
|
2030
2378
|
|
|
2031
|
-
Omit the `slot-name` to type the default slot.
|
|
2379
|
+
Omit the `slot-name` to type the default slot. `{Type}` itself is required; omitting it falls back to `Record<string, never>` and raises a [`sveld/slot-missing-type`](#diagnostic-codes) warning.
|
|
2032
2380
|
|
|
2033
2381
|
```js
|
|
2034
2382
|
/**
|
|
@@ -2311,6 +2659,27 @@ export default class Component extends SvelteComponentTyped<
|
|
|
2311
2659
|
> {}
|
|
2312
2660
|
```
|
|
2313
2661
|
|
|
2662
|
+
#### Detail inference without `@event`
|
|
2663
|
+
|
|
2664
|
+
Without an `@event` tag or a typed dispatcher, `sveld` infers a dispatched event's detail type from the `dispatch()` call site itself:
|
|
2665
|
+
|
|
2666
|
+
- 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.
|
|
2667
|
+
- 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.
|
|
2668
|
+
|
|
2669
|
+
#### Typed dispatchers
|
|
2670
|
+
|
|
2671
|
+
`createEventDispatcher<T>()`'s generic argument (`lang="ts"`, or the JSDoc `/** @type {import('svelte').EventDispatcher<T>} */` cast form) works like an `@event` block for every member of `T`, including ones never actually dispatched in the file:
|
|
2672
|
+
|
|
2673
|
+
```svelte
|
|
2674
|
+
<script lang="ts">
|
|
2675
|
+
import { createEventDispatcher } from "svelte";
|
|
2676
|
+
|
|
2677
|
+
const dispatch = createEventDispatcher<{ save: { id: string }; cancel: null }>();
|
|
2678
|
+
</script>
|
|
2679
|
+
```
|
|
2680
|
+
|
|
2681
|
+
`T` may also be a reference to a local `type`/`interface`. An `@event` tag for the same name still overrides the generic's detail type.
|
|
2682
|
+
|
|
2314
2683
|
#### Using `@property` for complex event details
|
|
2315
2684
|
|
|
2316
2685
|
For events with complex object payloads, use `@property` to document individual fields. The main comment becomes the event description. See the [`@property`](#property) reference for the tag's valid contexts.
|
|
@@ -2541,9 +2910,80 @@ export default class Component extends SvelteComponentTyped<
|
|
|
2541
2910
|
|
|
2542
2911
|
Any free-text prose after the tags is attached to the event description, not to a property doc.
|
|
2543
2912
|
|
|
2913
|
+
### `@ignore` / `@internal`
|
|
2914
|
+
|
|
2915
|
+
`@ignore` and `@internal` are equivalent aliases: either one excludes a prop, event, slot, typedef, module export, entry export, or context from every output — JSON, Markdown, `.d.ts`, and the Custom Elements Manifest. Use them for implementation details that would otherwise leak into the public API docs.
|
|
2916
|
+
|
|
2917
|
+
The tag's position mirrors [`@deprecated`](#deprecated): before `@slot`/`@snippet`/`@typedef`/`@callback`, alongside the description, and after the `@event` line.
|
|
2918
|
+
|
|
2919
|
+
```svelte
|
|
2920
|
+
<script>
|
|
2921
|
+
/** The visible label. */
|
|
2922
|
+
export let label = "";
|
|
2923
|
+
|
|
2924
|
+
/**
|
|
2925
|
+
* Implementation detail; not part of the public API.
|
|
2926
|
+
* @internal
|
|
2927
|
+
*/
|
|
2928
|
+
export let debugId = "";
|
|
2929
|
+
|
|
2930
|
+
/**
|
|
2931
|
+
* Fired when the value changes.
|
|
2932
|
+
* @event {{ value: string }} change
|
|
2933
|
+
*/
|
|
2934
|
+
|
|
2935
|
+
/**
|
|
2936
|
+
* Fired for internal diagnostics only.
|
|
2937
|
+
* @event {{ reason: string }} debug
|
|
2938
|
+
* @internal
|
|
2939
|
+
*/
|
|
2940
|
+
|
|
2941
|
+
/**
|
|
2942
|
+
* @internal
|
|
2943
|
+
* @slot {{}} debug-panel
|
|
2944
|
+
*/
|
|
2945
|
+
</script>
|
|
2946
|
+
```
|
|
2947
|
+
|
|
2948
|
+
`debugId`, the `debug` event, and the `debug-panel` slot never appear in `COMPONENT_INDEX.md`, `COMPONENT_API.json`, the generated `.d.ts`, or the Custom Elements Manifest — as if they were never declared. Internally, the parser still records them (with an `internal: true` flag) on the raw parsed component; only `buildComponentApiDocument` — the shared step every writer runs through — filters them out, so a custom writer built on the raw parse result can still see them if it chooses to.
|
|
2949
|
+
|
|
2950
|
+
For a context (`setContext(key, value)`), tag the JSDoc on the *value* variable, the same place its type annotation and description already live:
|
|
2951
|
+
|
|
2952
|
+
```svelte
|
|
2953
|
+
<script>
|
|
2954
|
+
/**
|
|
2955
|
+
* @type {{ token: string }}
|
|
2956
|
+
* @internal
|
|
2957
|
+
*/
|
|
2958
|
+
let authContext = { token: "" };
|
|
2959
|
+
|
|
2960
|
+
setContext("auth", authContext);
|
|
2961
|
+
</script>
|
|
2962
|
+
```
|
|
2963
|
+
|
|
2964
|
+
A whole inline object literal passed directly to `setContext` (no intermediate variable) has no JSDoc position of its own, so `@internal` isn't supported there. An individual property *inside* one can be marked `@internal`, though, as long as its value is an identifier carrying its own JSDoc:
|
|
2965
|
+
|
|
2966
|
+
```svelte
|
|
2967
|
+
<script>
|
|
2968
|
+
/**
|
|
2969
|
+
* @type {string}
|
|
2970
|
+
* @internal
|
|
2971
|
+
*/
|
|
2972
|
+
let debugToken = "";
|
|
2973
|
+
|
|
2974
|
+
let publicUser = { name: "" };
|
|
2975
|
+
|
|
2976
|
+
setContext("session", { user: publicUser, debug: debugToken });
|
|
2977
|
+
</script>
|
|
2978
|
+
```
|
|
2979
|
+
|
|
2980
|
+
Only the `debug` property is excluded from `session`'s generated shape; `user` and the context itself are unaffected.
|
|
2981
|
+
|
|
2982
|
+
Because an internal member never appears in output, adding `@internal` to a previously-public prop, event, slot, or typedef is a breaking change for `--check` purposes (it disappears from the generated `.d.ts` just like an outright removal). Removing an already-`@internal` member, by contrast, is not breaking — it was never part of the committed public snapshot to begin with.
|
|
2983
|
+
|
|
2544
2984
|
### `@deprecated`
|
|
2545
2985
|
|
|
2546
|
-
Add `@deprecated` to a prop, event, slot, or exported accessor. An optional message after the tag can explain why or name a replacement.
|
|
2986
|
+
Add `@deprecated` to a prop, event, slot, entry export, or exported accessor. An optional message after the tag can explain why or name a replacement.
|
|
2547
2987
|
|
|
2548
2988
|
```svelte
|
|
2549
2989
|
<script>
|
|
@@ -2572,7 +3012,7 @@ Add `@deprecated` to a prop, event, slot, or exported accessor. An optional mess
|
|
|
2572
3012
|
</script>
|
|
2573
3013
|
```
|
|
2574
3014
|
|
|
2575
|
-
For slots, put `@deprecated` before the `@slot` / `@snippet` line, alongside the description and any other [extra tags](#extra-jsdoc-tags-before-slot). For events, put it after the `@event` line.
|
|
3015
|
+
For slots, put `@deprecated` before the `@slot` / `@snippet` line, alongside the description and any other [extra tags](#extra-jsdoc-tags-before-slot). For events, put it after the `@event` line. For entry exports (see [Documenting Entry Exports](#documenting-entry-exports)), put it in the JSDoc directly above the `const`/`function`/`class`/`type`/`interface` declaration, same as a prop.
|
|
2576
3016
|
|
|
2577
3017
|
Generated `.d.ts` files include an `@deprecated` JSDoc line so editors strike the symbol through. JSON adds a `deprecated` field (the message string, or `true` when the tag has no message). Markdown strikes through the name and adds a **Deprecated** badge with the message when present.
|
|
2578
3018
|
|
|
@@ -2594,7 +3034,7 @@ label?: string;
|
|
|
2594
3034
|
|
|
2595
3035
|
**Valid contexts:**
|
|
2596
3036
|
|
|
2597
|
-
- **Prop / module export** — captured as a structured tag: JSON adds a `tags: [{ "name": "since", "body": "..." }]` array on the prop (kept separate from `description`),
|
|
3037
|
+
- **Prop / module export** — captured as a structured tag: JSON adds a `tags: [{ "name": "since", "body": "..." }]` array on the prop (kept separate from `description`), the generated `.d.ts` emits `@since ...` as its own JSDoc line above `@default`, and the Markdown table's Description column appends `@since ...` after the description, same as slots.
|
|
2598
3038
|
- **`@event`** — same structured behavior as props, but only when `@since` is placed **after** the `@event` line in the same comment block (matching the [`@deprecated`](#deprecated) rule for events). Placed before `@event`, it is silently dropped.
|
|
2599
3039
|
- **`@slot` / `@snippet`** — placed before the `@slot`/`@snippet` line, alongside the description. Fully surfaced in JSON, `.d.ts`, *and* the Markdown table. See [extra tags before `@slot`](#extra-jsdoc-tags-before-slot).
|
|
2600
3040
|
- **`@typedef`** — **not supported.** A `@since` before `@typedef` produces no output anywhere; it is silently dropped.
|
|
@@ -2632,7 +3072,11 @@ Output (JSON, relevant slice):
|
|
|
2632
3072
|
{ "name": "width", "description": "A width prop.", "tags": [{ "name": "since", "body": "1.2.0" }] }
|
|
2633
3073
|
```
|
|
2634
3074
|
|
|
2635
|
-
|
|
3075
|
+
Output (Markdown props table Description column):
|
|
3076
|
+
|
|
3077
|
+
```
|
|
3078
|
+
A width prop.<br />@since 1.2.0
|
|
3079
|
+
```
|
|
2636
3080
|
|
|
2637
3081
|
### `@see`
|
|
2638
3082
|
|
|
@@ -2682,7 +3126,7 @@ A width prop.<br />@see https://example.com/width-docs
|
|
|
2682
3126
|
|
|
2683
3127
|
`{@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.
|
|
2684
3128
|
|
|
2685
|
-
**Valid contexts:** anywhere free-form description text is read — prop and module export descriptions, event descriptions, slot descriptions, typedef descriptions, `@component` HTML comments, and `@example` bodies.
|
|
3129
|
+
**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)`. 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.
|
|
2686
3130
|
|
|
2687
3131
|
**Example:**
|
|
2688
3132
|
|
|
@@ -2708,7 +3152,7 @@ export type ScratchProps = {
|
|
|
2708
3152
|
};
|
|
2709
3153
|
```
|
|
2710
3154
|
|
|
2711
|
-
The same literal string appears unchanged in JSON `description
|
|
3155
|
+
The same literal string appears unchanged in JSON `description`. The Markdown table's Description column instead shows: `The element's width in pixels. See [width docs](https://example.com/width).`
|
|
2712
3156
|
|
|
2713
3157
|
### `@example`
|
|
2714
3158
|
|
|
@@ -2716,7 +3160,7 @@ The same literal string appears unchanged in JSON `description` and in the Markd
|
|
|
2716
3160
|
|
|
2717
3161
|
`@example` shares its underlying mechanism with `@since` (both are in the small set of tags `sveld` treats as structured "IDE passthrough" tags), so the valid contexts are the same:
|
|
2718
3162
|
|
|
2719
|
-
- **Prop / module export (including functions)** — structured `tags` entry in JSON, its own `@example` block in `.d.ts
|
|
3163
|
+
- **Prop / module export (including functions)** — structured `tags` entry in JSON, its own `@example` block in `.d.ts`, and appended to the Markdown table's Description column, same as `@since`.
|
|
2720
3164
|
- **`@event`** — only when placed **after** the `@event` line in the same block, same rule as `@since`.
|
|
2721
3165
|
- **`@slot` / `@snippet`** — placed before `@slot`/`@snippet`: fully supported in JSON, `.d.ts`, and Markdown. See [extra tags before `@slot`](#extra-jsdoc-tags-before-slot).
|
|
2722
3166
|
- **`@typedef`** — **not supported**, dropped silently, same as `@since`.
|
|
@@ -2754,7 +3198,13 @@ Output (`.d.ts`):
|
|
|
2754
3198
|
formatValue: (value: string) => string;
|
|
2755
3199
|
```
|
|
2756
3200
|
|
|
2757
|
-
`@param`/`@returns` are consumed into the function's type signature rather than kept as separate JSDoc lines.
|
|
3201
|
+
`@param`/`@returns` are consumed into the function's type signature rather than kept as separate JSDoc lines.
|
|
3202
|
+
|
|
3203
|
+
Output (Markdown props table Description column, newlines rendered as `<br />`):
|
|
3204
|
+
|
|
3205
|
+
````
|
|
3206
|
+
Formats a value.<br />@example ```js<br /> formatValue("ok");<br /> ```
|
|
3207
|
+
````
|
|
2758
3208
|
|
|
2759
3209
|
### Context API
|
|
2760
3210
|
|
|
@@ -3404,6 +3854,8 @@ export default class Component extends SvelteComponentTyped<
|
|
|
3404
3854
|
|
|
3405
3855
|
When only `@param` tags are present without `@returns`, the return type defaults to `any`. When only `@returns` is present without `@param`, the function signature is `() => returnType`.
|
|
3406
3856
|
|
|
3857
|
+
The Markdown writer marks the same exports (a `const`, or a real function declaration) with Kind `accessor` in the Props table, instead of their raw `const`/`function` kind, matching the `.d.ts` output above.
|
|
3858
|
+
|
|
3407
3859
|
## Troubleshooting
|
|
3408
3860
|
|
|
3409
3861
|
**A prop came out `any`.** Enable [`reportDiagnostics`](#type-inference-diagnostics) (or `strict` to fail CI) to see which props sveld couldn't infer, then tighten them with `@type` or a native TypeScript annotation.
|
|
@@ -3412,6 +3864,10 @@ When only `@param` tags are present without `@returns`, the return type defaults
|
|
|
3412
3864
|
|
|
3413
3865
|
**Output differs in CI.** Commit `COMPONENT_API.json` and run [`--check`](#ci-api-drift-checks---check) in CI so API drift fails the build instead of silently diverging.
|
|
3414
3866
|
|
|
3867
|
+
**`sveld: cannot resolve "..." from ...`.** An `export *` or a named re-export points at a module or path alias that doesn't resolve to a file on disk. Fix the specifier, or check the tsconfig/jsconfig `paths` entry it's supposed to match. This exits `1`; see [Exit codes](#exit-codes).
|
|
3868
|
+
|
|
3869
|
+
**A path alias (`$lib`, `@components`, ...) isn't picked up.** sveld only reads aliases from `compilerOptions.paths` in the nearest `tsconfig.json` or `jsconfig.json`, found by walking up from the file doing the importing. Vite/SvelteKit alias config (`vite.config.*`, `svelte.config.*`) is not read directly — add the same aliases to `paths` so both tools agree. When a pattern has more than one mapping (`"$lib/*": ["./src/lib/*", "./lib/*"]`), sveld tries them in order and uses the first one that exists on disk, falling back to the first mapping if none do; among multiple matching patterns, the one with the longest non-wildcard prefix wins, regardless of declaration order (matching `tsc`).
|
|
3870
|
+
|
|
3415
3871
|
## Contributing
|
|
3416
3872
|
|
|
3417
3873
|
See [contributing guidelines](CONTRIBUTING.md).
|