sveld 0.32.8 → 0.33.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 +169 -3
- package/lib/ComponentParser.d.ts +86 -10
- package/lib/bundle.d.ts +140 -0
- package/lib/cli.d.ts +10 -1
- package/lib/diagnostics.d.ts +29 -0
- package/lib/index.d.ts +2 -0
- package/lib/index.js +709 -684
- package/lib/load-config.d.ts +44 -0
- package/lib/parse-entry-exports.d.ts +30 -0
- package/lib/plugin.d.ts +27 -40
- package/lib/resolve-types.d.ts +29 -0
- package/lib/sveld.d.ts +13 -1
- package/lib/watch.d.ts +34 -0
- package/lib/writer/markdown-format-utils.d.ts +30 -1
- package/lib/writer/markdown-render-utils.d.ts +2 -1
- package/lib/writer/writer-json.d.ts +3 -0
- package/lib/writer/writer-markdown.d.ts +3 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -123,8 +123,10 @@ export default class Button extends SvelteComponentTyped<
|
|
|
123
123
|
- [Vite](#vite)
|
|
124
124
|
- [Node.js](#nodejs)
|
|
125
125
|
- [CLI](#cli)
|
|
126
|
+
- [Config File](#config-file)
|
|
126
127
|
- [Publishing to NPM](#publishing-to-npm)
|
|
127
128
|
- [Available Options](#available-options)
|
|
129
|
+
- [Documenting Entry Exports](#documenting-entry-exports)
|
|
128
130
|
- [JSON Output](#json-output)
|
|
129
131
|
- [API Reference](#api-reference)
|
|
130
132
|
- [@type](#type)
|
|
@@ -135,6 +137,7 @@ export default class Button extends SvelteComponentTyped<
|
|
|
135
137
|
- [Extra JSDoc tags before `@slot`](#extra-jsdoc-tags-before-slot)
|
|
136
138
|
- [Svelte 5 Snippet Compatibility](#svelte-5-snippet-compatibility)
|
|
137
139
|
- [@event](#event)
|
|
140
|
+
- [@deprecated](#deprecated)
|
|
138
141
|
- [Context API](#context-api)
|
|
139
142
|
- [@restProps](#restprops)
|
|
140
143
|
- [@extendProps](#extendprops)
|
|
@@ -169,6 +172,36 @@ When both TypeScript syntax and JSDoc are present, `sveld` resolves prop types i
|
|
|
169
172
|
|
|
170
173
|
`sveld` stays AST-only. It copies imported and local type text into generated `.d.ts` output but does not run project-wide semantic resolution with the TypeScript compiler. Opaque imported whole-object `$props()` types can therefore stay in declarations without being fully expanded into JSON metadata.
|
|
171
174
|
|
|
175
|
+
#### Opt-in semantic resolution (`resolveTypes`)
|
|
176
|
+
|
|
177
|
+
Imported whole-object `$props()` types stay opaque in JSON by default (`"props": []`). Turn on `resolveTypes` when a docs site or prop table needs the individual fields.
|
|
178
|
+
|
|
179
|
+
```ts
|
|
180
|
+
await sveld({ json: true, resolveTypes: true });
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
```svelte
|
|
184
|
+
<script lang="ts">
|
|
185
|
+
import type { Props } from "./types";
|
|
186
|
+
|
|
187
|
+
let props: Props = $props();
|
|
188
|
+
</script>
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
Without `resolveTypes`, JSON lists no props. With it, each field shows up with `"typeSource": "typescript"`:
|
|
192
|
+
|
|
193
|
+
```jsonc
|
|
194
|
+
{
|
|
195
|
+
"props": [
|
|
196
|
+
{ "name": "disabled", "type": "boolean", "isRequired": false, "typeSource": "typescript" },
|
|
197
|
+
{ "name": "href", "type": "string", "isRequired": true, "typeSource": "typescript" },
|
|
198
|
+
{ "name": "variant", "type": "\"primary\" | \"secondary\"", "isRequired": true, "typeSource": "typescript" }
|
|
199
|
+
]
|
|
200
|
+
}
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
**Performance.** Off by default. This is the only path that loads TypeScript. It needs `typescript` and a `tsconfig.json`, 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.
|
|
204
|
+
|
|
172
205
|
## Usage
|
|
173
206
|
|
|
174
207
|
### Installation
|
|
@@ -291,6 +324,31 @@ sveld({
|
|
|
291
324
|
});
|
|
292
325
|
```
|
|
293
326
|
|
|
327
|
+
### Config File
|
|
328
|
+
|
|
329
|
+
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.
|
|
330
|
+
|
|
331
|
+
Import `defineConfig` from `sveld` for typed options. Config files must use ESM syntax (`export default`).
|
|
332
|
+
|
|
333
|
+
```js
|
|
334
|
+
// sveld.config.js
|
|
335
|
+
import { defineConfig } from "sveld";
|
|
336
|
+
|
|
337
|
+
export default defineConfig({
|
|
338
|
+
glob: true,
|
|
339
|
+
json: true,
|
|
340
|
+
markdown: true,
|
|
341
|
+
});
|
|
342
|
+
```
|
|
343
|
+
|
|
344
|
+
Later sources win when options overlap:
|
|
345
|
+
|
|
346
|
+
CLI flags > config file > `package.json#svelte` inference / defaults
|
|
347
|
+
|
|
348
|
+
With the config above, `npx sveld --json` keeps `glob` and `markdown` from the file. A CLI flag overrides the same key in the config.
|
|
349
|
+
|
|
350
|
+
A bad config (syntax error, throws at load time, or no default-export object) fails with an error that names the file.
|
|
351
|
+
|
|
294
352
|
### Publishing to NPM
|
|
295
353
|
|
|
296
354
|
TypeScript definitions land in the `types` folder by default. Include that folder in `package.json` when you publish to npm.
|
|
@@ -314,12 +372,15 @@ TypeScript definitions land in the `types` folder by default. Include that folde
|
|
|
314
372
|
|
|
315
373
|
- **`entry`** (string, optional): Specify the entry point to uncompiled Svelte source. If not provided, sveld will use the `"svelte"` field from `package.json`.
|
|
316
374
|
- **`glob`** (boolean, optional): Enable glob mode to analyze all `*.svelte` files.
|
|
375
|
+
- **`documentExports`** (boolean, optional): Include consts, functions, and types from the entry barrel in JSON (`exports`) and Markdown ("Exports"). Off by default. See [Documenting Entry Exports](#documenting-entry-exports).
|
|
317
376
|
- **`types`** (boolean, optional, default: `true`): Generate TypeScript definitions.
|
|
318
377
|
- **`typesOptions`** (object, optional): Options for TypeScript definition generation, including `outDir`, `preamble`, and `printWidth`.
|
|
319
378
|
- **`json`** (boolean, optional): Generate component documentation in JSON format.
|
|
320
379
|
- **`jsonOptions`** (object, optional): Options for JSON output.
|
|
321
380
|
- **`markdown`** (boolean, optional): Generate component documentation in Markdown format.
|
|
322
381
|
- **`markdownOptions`** (object, optional): Options for Markdown output.
|
|
382
|
+
- **`watch`** (boolean, optional, default: `false`): Regenerate output incrementally when `.svelte` source changes during `vite dev` / `vite build --watch`. Only the changed component and the components that depend on it via [`@extendProps`](#extendprops) / `@extends` are re-parsed, rather than rebuilding every component. Without this option, the plugin only runs during `vite build`.
|
|
383
|
+
- **`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.
|
|
323
384
|
|
|
324
385
|
By default, only TypeScript definitions are generated.
|
|
325
386
|
|
|
@@ -332,6 +393,32 @@ sveld({
|
|
|
332
393
|
})
|
|
333
394
|
```
|
|
334
395
|
|
|
396
|
+
## Documenting Entry Exports
|
|
397
|
+
|
|
398
|
+
Most entry barrels re-export more than `.svelte` components. Set `documentExports: true` to add consts, functions, and types to the JSON and Markdown output.
|
|
399
|
+
|
|
400
|
+
```diff
|
|
401
|
+
sveld({
|
|
402
|
+
json: true,
|
|
403
|
+
markdown: true,
|
|
404
|
+
+ documentExports: true,
|
|
405
|
+
})
|
|
406
|
+
```
|
|
407
|
+
|
|
408
|
+
Example entry file:
|
|
409
|
+
|
|
410
|
+
```ts
|
|
411
|
+
// src/index.ts
|
|
412
|
+
export { default as Button } from "./Button.svelte";
|
|
413
|
+
export { VERSION } from "./constants";
|
|
414
|
+
export { clamp } from "./utils";
|
|
415
|
+
export type { Theme } from "./types";
|
|
416
|
+
```
|
|
417
|
+
|
|
418
|
+
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.
|
|
419
|
+
|
|
420
|
+
JSON adds `exports` and `totalExports`. Markdown adds an "Exports" section. Each item has `name`, `kind`, type text, optional JSDoc `description`, and `source`.
|
|
421
|
+
|
|
335
422
|
## JSON Output
|
|
336
423
|
|
|
337
424
|
When `json: true` is enabled, `sveld` emits a `COMPONENT_API.json` file with schema and generator metadata plus the parsed
|
|
@@ -349,6 +436,19 @@ interface ComponentApiJson {
|
|
|
349
436
|
};
|
|
350
437
|
total: number;
|
|
351
438
|
components: ComponentDocApi[];
|
|
439
|
+
// Present only when `documentExports` is enabled.
|
|
440
|
+
totalExports?: number;
|
|
441
|
+
exports?: EntryExport[];
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
interface EntryExport {
|
|
445
|
+
name: string;
|
|
446
|
+
kind: "const" | "let" | "var" | "function" | "class" | "type" | "interface" | "enum";
|
|
447
|
+
type?: string;
|
|
448
|
+
value?: string;
|
|
449
|
+
description?: string;
|
|
450
|
+
source?: string;
|
|
451
|
+
isTypeOnly: boolean;
|
|
352
452
|
}
|
|
353
453
|
|
|
354
454
|
interface SourceRange {
|
|
@@ -1361,9 +1461,11 @@ Omit the `slot-name` to type the default slot.
|
|
|
1361
1461
|
|
|
1362
1462
|
#### Extra JSDoc tags before `@slot`
|
|
1363
1463
|
|
|
1364
|
-
Tags such as `@example`, `@
|
|
1464
|
+
Tags such as `@example`, `@see`, or `@since` that appear after the prose description and before the `@slot` / `@snippet` line are copied into generated `.d.ts` files. The emitted JSDoc above each slot's snippet prop (and the traditional `SlotDefs` shape) lists the description, then those tags in source order. The same entries appear in JSON as `tags: [{ "name", "body" }, ...]`.
|
|
1465
|
+
|
|
1466
|
+
`@deprecated` is handled separately from passthrough slot tags. It fills the slot's `deprecated` JSON field, adds a Markdown badge, and emits `@deprecated` in the `.d.ts`. See [@deprecated](#deprecated).
|
|
1365
1467
|
|
|
1366
|
-
Put `@slot` / `@snippet` last in the block (description, optional extra tags, slot tag). Tags after `@slot` / `@snippet` in the same comment are not tied to that slot. Unknown tag names pass through as-is. Markdown docs
|
|
1468
|
+
Put `@slot` / `@snippet` last in the block (description, optional extra tags, slot tag). Tags after `@slot` / `@snippet` in the same comment are not tied to that slot. Unknown tag names pass through as-is. Markdown docs render the description and these tags in the slot's **Description** column (newlines and tag boundaries become `<br />`), alongside TypeScript hover and JSON.
|
|
1367
1469
|
|
|
1368
1470
|
**Example (default slot with `@example` and `@deprecated`):**
|
|
1369
1471
|
|
|
@@ -1803,6 +1905,53 @@ export default class Component extends SvelteComponentTyped<
|
|
|
1803
1905
|
|
|
1804
1906
|
Any free-text prose after the tags is attached to the event description, not to a property doc.
|
|
1805
1907
|
|
|
1908
|
+
### `@deprecated`
|
|
1909
|
+
|
|
1910
|
+
Add `@deprecated` to a prop, event, slot, or exported accessor. An optional message after the tag can explain why or name a replacement.
|
|
1911
|
+
|
|
1912
|
+
```svelte
|
|
1913
|
+
<script>
|
|
1914
|
+
/**
|
|
1915
|
+
* The visible label.
|
|
1916
|
+
* @deprecated Use the `text` prop instead.
|
|
1917
|
+
*/
|
|
1918
|
+
export let label = "";
|
|
1919
|
+
|
|
1920
|
+
/**
|
|
1921
|
+
* Programmatically focus the field.
|
|
1922
|
+
* @deprecated Focus the underlying element directly.
|
|
1923
|
+
*/
|
|
1924
|
+
export function focus() {}
|
|
1925
|
+
|
|
1926
|
+
/**
|
|
1927
|
+
* @event {{ value: string }} change
|
|
1928
|
+
* @deprecated Listen for the native `input` event instead.
|
|
1929
|
+
*/
|
|
1930
|
+
|
|
1931
|
+
/**
|
|
1932
|
+
* Badge content rendered next to the label.
|
|
1933
|
+
* @deprecated Render the badge inline instead.
|
|
1934
|
+
* @slot {{ count: number }} badge
|
|
1935
|
+
*/
|
|
1936
|
+
</script>
|
|
1937
|
+
```
|
|
1938
|
+
|
|
1939
|
+
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.
|
|
1940
|
+
|
|
1941
|
+
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.
|
|
1942
|
+
|
|
1943
|
+
```ts
|
|
1944
|
+
/**
|
|
1945
|
+
* The visible label.
|
|
1946
|
+
* @deprecated Use the `text` prop instead.
|
|
1947
|
+
*/
|
|
1948
|
+
label?: string;
|
|
1949
|
+
```
|
|
1950
|
+
|
|
1951
|
+
```json
|
|
1952
|
+
{ "name": "label", "deprecated": "Use the `text` prop instead." }
|
|
1953
|
+
```
|
|
1954
|
+
|
|
1806
1955
|
### Context API
|
|
1807
1956
|
|
|
1808
1957
|
`sveld` generates TypeScript definitions for Svelte's `setContext`/`getContext` by extracting types from JSDoc on context values.
|
|
@@ -1812,10 +1961,27 @@ Any free-text prose after the tags is attached to the event description, not to
|
|
|
1812
1961
|
When you call `setContext` in a component, `sveld`:
|
|
1813
1962
|
|
|
1814
1963
|
1. Detects the `setContext` call
|
|
1815
|
-
2.
|
|
1964
|
+
2. Resolves the context key (see [Supported context keys](#supported-context-keys))
|
|
1816
1965
|
3. Finds JSDoc `@type` annotations on the variables being passed
|
|
1817
1966
|
4. Generates a TypeScript type export for the context
|
|
1818
1967
|
|
|
1968
|
+
#### Supported context keys
|
|
1969
|
+
|
|
1970
|
+
The key becomes the `{PascalCase}Context` type name. `sveld` can resolve:
|
|
1971
|
+
|
|
1972
|
+
| Key form | Example | Generated type |
|
|
1973
|
+
| --- | --- | --- |
|
|
1974
|
+
| String literal | `setContext("simple-modal", …)` | `SimpleModalContext` |
|
|
1975
|
+
| Static template literal | `` setContext(`simple-modal`, …) `` | `SimpleModalContext` |
|
|
1976
|
+
| `const`-bound string | `const KEY = "simple-modal";`<br>`setContext(KEY, …)` | `SimpleModalContext` |
|
|
1977
|
+
| `Symbol()` / `Symbol.for()` | `setContext(Symbol("tabs"), …)` | `TabsContext` |
|
|
1978
|
+
|
|
1979
|
+
`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.
|
|
1980
|
+
|
|
1981
|
+
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`.
|
|
1982
|
+
|
|
1983
|
+
Anything else (dynamic identifiers, template interpolation, other function calls) logs a warning. No context type is generated.
|
|
1984
|
+
|
|
1819
1985
|
#### Example
|
|
1820
1986
|
|
|
1821
1987
|
**Modal.svelte**
|
package/lib/ComponentParser.d.ts
CHANGED
|
@@ -1,3 +1,13 @@
|
|
|
1
|
+
import type { SveldDiagnostic } from "./diagnostics";
|
|
2
|
+
/** Structured JSDoc tag (e.g. `{ name: "since", body: "1.2.0" }`). */
|
|
3
|
+
interface JsDocPassthroughTag {
|
|
4
|
+
name: string;
|
|
5
|
+
body: string;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* From `@deprecated` JSDoc: a message string, or `true` when the tag has no message.
|
|
9
|
+
*/
|
|
10
|
+
export type DeprecatedValue = string | true;
|
|
1
11
|
export interface SourcePosition {
|
|
2
12
|
/** 1-based source line number */
|
|
3
13
|
line: number;
|
|
@@ -18,6 +28,15 @@ export declare const PARSED_COMPONENT_TYPE_SCRIPT_METADATA: unique symbol;
|
|
|
18
28
|
export declare function getParsedComponentTypeScriptMetadata(component: {
|
|
19
29
|
[PARSED_COMPONENT_TYPE_SCRIPT_METADATA]?: ParsedComponentTypeScriptMetadata;
|
|
20
30
|
}): ParsedComponentTypeScriptMetadata | undefined;
|
|
31
|
+
/** One prop returned by the TypeScript checker during `resolveTypes`. */
|
|
32
|
+
export interface ResolvedComponentProp {
|
|
33
|
+
name: string;
|
|
34
|
+
type: string;
|
|
35
|
+
isRequired: boolean;
|
|
36
|
+
description?: string;
|
|
37
|
+
}
|
|
38
|
+
/** Append checker-resolved props. Names the AST walker already found are left alone. */
|
|
39
|
+
export declare function applyResolvedProps(component: ParsedComponent, resolved: ResolvedComponentProp[]): void;
|
|
21
40
|
type SyntaxMode = "legacy" | "runes";
|
|
22
41
|
type ScriptLanguage = "js" | "ts";
|
|
23
42
|
type ComponentPropTypeSource = "typescript" | "jsdoc" | "default" | "inferred" | "unknown";
|
|
@@ -104,6 +123,10 @@ interface ComponentProp {
|
|
|
104
123
|
binding?: ComponentPropBinding;
|
|
105
124
|
/** True when the prop is explicitly declared with Svelte 5 `$bindable()` */
|
|
106
125
|
bindable?: true;
|
|
126
|
+
/** From `@deprecated` JSDoc. */
|
|
127
|
+
deprecated?: DeprecatedValue;
|
|
128
|
+
/** Structured `@since` / `@example` tags, in source order. */
|
|
129
|
+
tags?: JsDocPassthroughTag[];
|
|
107
130
|
/** Source range for the prop declaration, when available */
|
|
108
131
|
source?: SourceRange;
|
|
109
132
|
}
|
|
@@ -124,14 +147,13 @@ interface ComponentSlot {
|
|
|
124
147
|
slot_props?: string;
|
|
125
148
|
/** Description extracted from JSDoc `@slot` or `@snippet` tags */
|
|
126
149
|
description?: string;
|
|
150
|
+
/** From `@deprecated` JSDoc. */
|
|
151
|
+
deprecated?: DeprecatedValue;
|
|
127
152
|
/**
|
|
128
153
|
* JSDoc tags that appeared after the prose description and before `@slot` / `@snippet`
|
|
129
|
-
* (e.g. `@example
|
|
154
|
+
* (e.g. `@example`), in source order.
|
|
130
155
|
*/
|
|
131
|
-
tags?:
|
|
132
|
-
name: string;
|
|
133
|
-
body: string;
|
|
134
|
-
}>;
|
|
156
|
+
tags?: JsDocPassthroughTag[];
|
|
135
157
|
/** Source range for the slot/snippet declaration or documentation tag, when available */
|
|
136
158
|
source?: SourceRange;
|
|
137
159
|
}
|
|
@@ -150,6 +172,10 @@ interface DispatchedEvent {
|
|
|
150
172
|
detail?: string;
|
|
151
173
|
/** Description extracted from JSDoc `@event` tags */
|
|
152
174
|
description?: string;
|
|
175
|
+
/** From `@deprecated` JSDoc. */
|
|
176
|
+
deprecated?: DeprecatedValue;
|
|
177
|
+
/** Structured `@since` / `@example` tags, in source order. */
|
|
178
|
+
tags?: JsDocPassthroughTag[];
|
|
153
179
|
/** Source range for the dispatched event call or documentation tag, when available */
|
|
154
180
|
source?: SourceRange;
|
|
155
181
|
}
|
|
@@ -181,8 +207,12 @@ export interface SerializedForwardedEvent {
|
|
|
181
207
|
element: string;
|
|
182
208
|
/** Description extracted from JSDoc `@event` tags */
|
|
183
209
|
description?: string;
|
|
210
|
+
/** From `@deprecated` JSDoc. */
|
|
211
|
+
deprecated?: DeprecatedValue;
|
|
184
212
|
/** The detail type if explicitly specified in `@event` tag */
|
|
185
213
|
detail?: string;
|
|
214
|
+
/** Structured `@since` / `@example` tags, in source order. */
|
|
215
|
+
tags?: JsDocPassthroughTag[];
|
|
186
216
|
/** Source range for the forwarded event declaration or documentation tag, when available */
|
|
187
217
|
source?: SourceRange;
|
|
188
218
|
}
|
|
@@ -335,6 +365,11 @@ export interface ParsedComponent {
|
|
|
335
365
|
componentCommentSource?: SourceRange;
|
|
336
366
|
/** Contexts created with `setContext` in the component */
|
|
337
367
|
contexts?: ComponentContext[];
|
|
368
|
+
/**
|
|
369
|
+
* Type guesses from this parse (unknown props, `any` contexts, orphan `@event` tags).
|
|
370
|
+
* Set on every {@link ComponentParser.parseSvelteComponent} call.
|
|
371
|
+
*/
|
|
372
|
+
diagnostics?: SveldDiagnostic[];
|
|
338
373
|
/** Internal writer-only TypeScript metadata. Not serialized to JSON. */
|
|
339
374
|
[PARSED_COMPONENT_TYPE_SCRIPT_METADATA]?: ParsedComponentTypeScriptMetadata;
|
|
340
375
|
}
|
|
@@ -411,6 +446,12 @@ export default class ComponentParser {
|
|
|
411
446
|
private scopeDeclarations;
|
|
412
447
|
/** Active lexical scopes while walking the component AST */
|
|
413
448
|
private readonly activeScopes;
|
|
449
|
+
/** Diagnostics for the parse in progress. */
|
|
450
|
+
private readonly diagnosticRecords;
|
|
451
|
+
/** File path tagged onto each diagnostic. */
|
|
452
|
+
private componentFilePath;
|
|
453
|
+
/** `@event` names from JSDoc, checked against dispatches at end of parse. */
|
|
454
|
+
private readonly jsDocEventNames;
|
|
414
455
|
/** Cached array of source code lines split by newline for efficient line-based operations */
|
|
415
456
|
private sourceLinesCache?;
|
|
416
457
|
/** Cached 0-based source offsets for the start of each line */
|
|
@@ -420,6 +461,7 @@ export default class ComponentParser {
|
|
|
420
461
|
private static getStaticAttributeValue;
|
|
421
462
|
private static resolveScriptLanguage;
|
|
422
463
|
private static assignValue;
|
|
464
|
+
private recordDiagnostic;
|
|
423
465
|
private resolvePublicPropName;
|
|
424
466
|
private trackPropLocalName;
|
|
425
467
|
private getPropByLocalOrPublic;
|
|
@@ -478,7 +520,8 @@ export default class ComponentParser {
|
|
|
478
520
|
* { tag: "param", name: "value", type: "string" }
|
|
479
521
|
* ],
|
|
480
522
|
* returns: { tag: "returns", type: "void" },
|
|
481
|
-
* additional: [{ tag: "
|
|
523
|
+
* additional: [{ tag: "see", name: "OtherType" }],
|
|
524
|
+
* passthrough: [{ tag: "since", name: "1.0.0" }],
|
|
482
525
|
* description: "Main description text"
|
|
483
526
|
* }
|
|
484
527
|
* ```
|
|
@@ -602,6 +645,16 @@ export default class ComponentParser {
|
|
|
602
645
|
* Returns the init node if found, or undefined.
|
|
603
646
|
*/
|
|
604
647
|
private resolveLocalVarInitializer;
|
|
648
|
+
/**
|
|
649
|
+
* Look up the initializer for a local `const` by name.
|
|
650
|
+
*
|
|
651
|
+
* {@link resolveLocalVarInitializer} also walks `let`/`var`. This method does not.
|
|
652
|
+
* Props and mutable bindings can change at runtime, so they cannot be context keys.
|
|
653
|
+
*
|
|
654
|
+
* @param name - The variable name to look up
|
|
655
|
+
* @returns The initializer node for a matching `const` binding, or undefined
|
|
656
|
+
*/
|
|
657
|
+
private resolveConstInitializer;
|
|
605
658
|
/**
|
|
606
659
|
* Look up JSDoc on a local variable declaration by name.
|
|
607
660
|
*/
|
|
@@ -960,12 +1013,32 @@ export default class ComponentParser {
|
|
|
960
1013
|
* ```
|
|
961
1014
|
*/
|
|
962
1015
|
private parseContextValue;
|
|
1016
|
+
/**
|
|
1017
|
+
* Resolve a `setContext` key to the string used in `{PascalCase}Context`.
|
|
1018
|
+
*
|
|
1019
|
+
* Accepts string literals, static template literals, `const`-bound identifiers
|
|
1020
|
+
* (up to 5 indirection levels, same as `@default`), and `Symbol()` /
|
|
1021
|
+
* `Symbol.for()`. Description-less symbols fall back to the binding name.
|
|
1022
|
+
*
|
|
1023
|
+
* @param keyArg - The first argument of the `setContext` call
|
|
1024
|
+
* @param depth - Current identifier-resolution depth (internal recursion guard)
|
|
1025
|
+
* @returns The resolved key string, or `null` when the key cannot be resolved at parse time
|
|
1026
|
+
*/
|
|
1027
|
+
private resolveContextKey;
|
|
1028
|
+
/**
|
|
1029
|
+
* Extracts the description string from a `Symbol(...)` or `Symbol.for(...)` call
|
|
1030
|
+
* used as a context key.
|
|
1031
|
+
*
|
|
1032
|
+
* @param node - A CallExpression or NewExpression AST node
|
|
1033
|
+
* @returns The symbol description (`""` when the symbol has no static description),
|
|
1034
|
+
* or `null` when the node is not a `Symbol()` / `Symbol.for()` call
|
|
1035
|
+
*/
|
|
1036
|
+
private resolveSymbolKeyDescription;
|
|
963
1037
|
/**
|
|
964
1038
|
* Parses a `setContext` call expression to extract context information.
|
|
965
1039
|
*
|
|
966
|
-
*
|
|
967
|
-
*
|
|
968
|
-
* Only processes static keys - dynamic keys are skipped with a warning.
|
|
1040
|
+
* Reads the context key from the first argument and the value from the second.
|
|
1041
|
+
* Unresolved keys log a warning and are skipped.
|
|
969
1042
|
*
|
|
970
1043
|
* @param node - The AST node (should be a CallExpression)
|
|
971
1044
|
* @param _parent - The parent node (unused)
|
|
@@ -975,7 +1048,10 @@ export default class ComponentParser {
|
|
|
975
1048
|
* // Parses: setContext('modal', { open, close })
|
|
976
1049
|
* // Extracts: key = "modal", value = { open, close }
|
|
977
1050
|
*
|
|
978
|
-
* //
|
|
1051
|
+
* // Parses: const KEY = "modal"; setContext(KEY, value) // resolves to "modal"
|
|
1052
|
+
* // Parses: setContext(Symbol("modal"), value) // resolves to "modal"
|
|
1053
|
+
*
|
|
1054
|
+
* // Diagnostic: setContext(dynamicKey, value) // key cannot be statically resolved
|
|
979
1055
|
* ```
|
|
980
1056
|
*/
|
|
981
1057
|
private parseSetContextCall;
|
package/lib/bundle.d.ts
ADDED
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
import { type NormalizedPath } from "./brands";
|
|
2
|
+
import { type ParsedComponent } from "./ComponentParser";
|
|
3
|
+
import { type SveldDiagnostic } from "./diagnostics";
|
|
4
|
+
import { type EntryExports } from "./parse-entry-exports";
|
|
5
|
+
import { type ParsedExports } from "./parse-exports";
|
|
6
|
+
export interface ComponentDocApi extends ParsedComponent {
|
|
7
|
+
filePath: NormalizedPath;
|
|
8
|
+
moduleName: string;
|
|
9
|
+
}
|
|
10
|
+
export type ComponentDocs = Map<string, ComponentDocApi>;
|
|
11
|
+
/**
|
|
12
|
+
* A parse failure for a single component, captured so the rest of the run
|
|
13
|
+
* can continue. Surfaced via {@link GenerateBundleResult.errors}.
|
|
14
|
+
*/
|
|
15
|
+
export interface ComponentParseError {
|
|
16
|
+
filePath: string;
|
|
17
|
+
moduleName: string;
|
|
18
|
+
message: string;
|
|
19
|
+
stack?: string;
|
|
20
|
+
}
|
|
21
|
+
export interface GenerateBundleResult {
|
|
22
|
+
exports: ParsedExports;
|
|
23
|
+
/** Entry-barrel exports other than components. Empty when `documentExports` is off. */
|
|
24
|
+
entryExports: EntryExports;
|
|
25
|
+
components: ComponentDocs;
|
|
26
|
+
allComponentsForTypes: ComponentDocs;
|
|
27
|
+
/**
|
|
28
|
+
* Components that failed to parse. Empty unless `failFast` is disabled and
|
|
29
|
+
* one or more components threw during parsing.
|
|
30
|
+
*/
|
|
31
|
+
errors: ComponentParseError[];
|
|
32
|
+
/** Unknown props, `any` contexts, and orphan `@event` tags across the bundle. */
|
|
33
|
+
diagnostics: SveldDiagnostic[];
|
|
34
|
+
}
|
|
35
|
+
export interface GenerateBundleOptions {
|
|
36
|
+
/**
|
|
37
|
+
* Throw on the first component that fails to parse instead of collecting
|
|
38
|
+
* the failure and continuing with the remaining components.
|
|
39
|
+
*/
|
|
40
|
+
failFast?: boolean;
|
|
41
|
+
/**
|
|
42
|
+
* Load the TypeScript program to expand opaque imported whole-object `$props()`
|
|
43
|
+
* types into JSON/Markdown props. Off by default; requires `typescript`.
|
|
44
|
+
*/
|
|
45
|
+
resolveTypes?: boolean;
|
|
46
|
+
/** Record consts, functions, and types from the entry barrel. Off by default. */
|
|
47
|
+
documentExports?: boolean;
|
|
48
|
+
}
|
|
49
|
+
export declare function toGenerateBundleOptions(opts?: Pick<GenerateBundleOptions, "failFast" | "resolveTypes" | "documentExports">): GenerateBundleOptions;
|
|
50
|
+
/** A function that resolves a (possibly relative) component path to an absolute path. */
|
|
51
|
+
export type ResolveComponentFilePath = (filePath: string) => string;
|
|
52
|
+
/** Options controlling how a single component parse failure is handled. */
|
|
53
|
+
export interface ProcessComponentOptions {
|
|
54
|
+
/** Rethrow on parse failure instead of reporting it via `onParseError`. */
|
|
55
|
+
failFast?: boolean;
|
|
56
|
+
/** Invoked with a diagnostic when a component fails to parse (and `failFast` is off). */
|
|
57
|
+
onParseError?: (error: ComponentParseError) => void;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Discovered component sources for an entry point, before parsing.
|
|
61
|
+
*
|
|
62
|
+
* `exports` holds explicitly exported components (used for JSON/Markdown);
|
|
63
|
+
* `allComponents` additionally includes glob-discovered components (used for
|
|
64
|
+
* `.d.ts` generation). `resolveComponentFilePath` maps a component `source`
|
|
65
|
+
* to its absolute path on disk.
|
|
66
|
+
*/
|
|
67
|
+
export interface CollectedComponents {
|
|
68
|
+
exports: ParsedExports;
|
|
69
|
+
allComponents: ParsedExports;
|
|
70
|
+
rootDir: string;
|
|
71
|
+
resolveComponentFilePath: ResolveComponentFilePath;
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Discovers component sources for an entry point without parsing them.
|
|
75
|
+
*
|
|
76
|
+
* Parses the entry's exports (when `input` is a file) and, when `glob` is set,
|
|
77
|
+
* augments the set with every `.svelte` file under the entry directory.
|
|
78
|
+
*
|
|
79
|
+
* @param documentExports - When `true`, log and continue if the entry file fails
|
|
80
|
+
* the acorn component-export parse (TypeScript-only syntax is common).
|
|
81
|
+
*/
|
|
82
|
+
export declare function collectComponents(input: string, glob: boolean, documentExports?: boolean): CollectedComponents;
|
|
83
|
+
/**
|
|
84
|
+
* Reads the given component file paths into a map of path -> contents.
|
|
85
|
+
*
|
|
86
|
+
* Failed reads are recorded as `null` (and logged) so callers can skip them
|
|
87
|
+
* gracefully rather than aborting the whole bundle.
|
|
88
|
+
*/
|
|
89
|
+
export declare function readFileMap(filePaths: Iterable<string>): Promise<Map<string, string | null>>;
|
|
90
|
+
/**
|
|
91
|
+
* Parses a single component entry into its documentation API.
|
|
92
|
+
*
|
|
93
|
+
* Reads the component contents from `fileMap`, removes top-level styles for
|
|
94
|
+
* metadata parsing, and parses it to extract component metadata. Returns `null`
|
|
95
|
+
* for non-Svelte entries or files that could not be read.
|
|
96
|
+
*
|
|
97
|
+
* A component that throws while parsing is captured via `options.onParseError`
|
|
98
|
+
* (and `null` is returned) so callers can continue with the rest, unless
|
|
99
|
+
* `options.failFast` is set, in which case the error is rethrown.
|
|
100
|
+
*
|
|
101
|
+
* @param entry - Export entry tuple `[exportName, exportInfo]`
|
|
102
|
+
* @param entries - All sibling entries, used to resolve the module name
|
|
103
|
+
* @param fileMap - Map of resolved file paths to their contents
|
|
104
|
+
* @param resolveComponentFilePath - Resolves a component `source` to its absolute path
|
|
105
|
+
* @param options - Parse-failure handling (`failFast` / `onParseError`)
|
|
106
|
+
*/
|
|
107
|
+
export declare function processComponent([exportName, entry]: [string, ParsedExports[string]], entries: Array<[string, ParsedExports[string]]>, fileMap: Map<string, string | null>, resolveComponentFilePath: ResolveComponentFilePath, options?: ProcessComponentOptions): ComponentDocApi | null;
|
|
108
|
+
/** Collects the resolved, absolute paths of all `.svelte` entries. */
|
|
109
|
+
export declare function collectSvelteFilePaths(entriesList: Array<Array<[string, ParsedExports[string]]>>, resolveComponentFilePath: ResolveComponentFilePath): Set<string>;
|
|
110
|
+
/** Reports collected component parse errors to stderr. No-op when empty. */
|
|
111
|
+
export declare function reportParseErrors(errors: ComponentParseError[]): void;
|
|
112
|
+
/**
|
|
113
|
+
* Generates component documentation bundle from Svelte source files.
|
|
114
|
+
*
|
|
115
|
+
* Parses exports, discovers components (optionally via glob), and processes
|
|
116
|
+
* all Svelte files to extract component metadata. Returns both exported
|
|
117
|
+
* components (for JSON/Markdown) and all components (for TypeScript definitions).
|
|
118
|
+
*
|
|
119
|
+
* A single component that fails to parse is captured as a diagnostic (see
|
|
120
|
+
* {@link GenerateBundleResult.errors}) so the remaining components still emit
|
|
121
|
+
* output. Pass `{ failFast: true }` to restore abort-on-first-error behavior.
|
|
122
|
+
*
|
|
123
|
+
* @param input - Entry point file or directory containing Svelte components
|
|
124
|
+
* @param glob - Whether to glob for all .svelte files in the directory
|
|
125
|
+
* @param options - Bundle options (e.g. `failFast`, `resolveTypes`, `documentExports`)
|
|
126
|
+
* @returns Bundle result containing exports, entryExports, components, allComponentsForTypes, and errors
|
|
127
|
+
*
|
|
128
|
+
* @example
|
|
129
|
+
* ```ts
|
|
130
|
+
* // Generate from single file:
|
|
131
|
+
* const result = await generateBundle("./src/App.svelte", false);
|
|
132
|
+
*
|
|
133
|
+
* // Generate from directory with glob:
|
|
134
|
+
* const result = await generateBundle("./src", true);
|
|
135
|
+
*
|
|
136
|
+
* // Abort on the first parse failure:
|
|
137
|
+
* const result = await generateBundle("./src", true, { failFast: true });
|
|
138
|
+
* ```
|
|
139
|
+
*/
|
|
140
|
+
export declare function generateBundle(input: string, glob: boolean, options?: GenerateBundleOptions): Promise<GenerateBundleResult>;
|
package/lib/cli.d.ts
CHANGED
|
@@ -1,5 +1,13 @@
|
|
|
1
|
+
import { type PluginSveldOptions } from "./plugin";
|
|
2
|
+
/** CLI options layered on top of the shared plugin options. */
|
|
3
|
+
interface CliOptions extends PluginSveldOptions {
|
|
4
|
+
/** Set exit code 1 when diagnostics are present. */
|
|
5
|
+
strict?: boolean;
|
|
6
|
+
}
|
|
7
|
+
export declare function parseCliOptions(argv: string[]): CliOptions;
|
|
1
8
|
/**
|
|
2
|
-
* CLI entry point: parse flags, run Rollup, generate
|
|
9
|
+
* CLI entry point: parse flags, load any config file, run Rollup, generate
|
|
10
|
+
* docs, write outputs.
|
|
3
11
|
*
|
|
4
12
|
* @example
|
|
5
13
|
* ```ts
|
|
@@ -8,3 +16,4 @@
|
|
|
8
16
|
* ```
|
|
9
17
|
*/
|
|
10
18
|
export declare function cli(process: NodeJS.Process): Promise<void>;
|
|
19
|
+
export {};
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Why sveld could not pin a type during parsing.
|
|
3
|
+
*
|
|
4
|
+
* - `prop-unknown-type`: prop `typeSource` is `"unknown"`.
|
|
5
|
+
* - `context-any-type`: `setContext` value inferred as `any`.
|
|
6
|
+
* - `event-no-source`: `@event` with no dispatch, forward, or callback prop.
|
|
7
|
+
*/
|
|
8
|
+
export type SveldDiagnosticKind = "prop-unknown-type" | "context-any-type" | "event-no-source";
|
|
9
|
+
/**
|
|
10
|
+
* One place sveld had to guess a type instead of inferring it.
|
|
11
|
+
*/
|
|
12
|
+
export interface SveldDiagnostic {
|
|
13
|
+
/** File this came from, e.g. `"./Button.svelte"`. */
|
|
14
|
+
component: string;
|
|
15
|
+
kind: SveldDiagnosticKind;
|
|
16
|
+
/** Prop, context field, or event name. */
|
|
17
|
+
name: string;
|
|
18
|
+
/** What went wrong and what type sveld used. */
|
|
19
|
+
message: string;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Drop duplicates (same component, kind, and name). Each file is parsed twice
|
|
23
|
+
* when building exports and `.d.ts`, so without this the CLI summary doubles.
|
|
24
|
+
*/
|
|
25
|
+
export declare function dedupeDiagnostics(diagnostics: SveldDiagnostic[]): SveldDiagnostic[];
|
|
26
|
+
/**
|
|
27
|
+
* Group diagnostics by kind and component for CLI output.
|
|
28
|
+
*/
|
|
29
|
+
export declare function formatDiagnosticsSummary(diagnostics: SveldDiagnostic[]): string;
|
package/lib/index.d.ts
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
export { default as ComponentParser, type SerializedComponentEvent } from "./ComponentParser";
|
|
2
2
|
export { cli } from "./cli";
|
|
3
|
+
export type { SveldDiagnostic, SveldDiagnosticKind } from "./diagnostics";
|
|
3
4
|
export type { SvelteEntryPoint } from "./get-svelte-entry";
|
|
5
|
+
export { defineConfig, type SveldConfig } from "./load-config";
|
|
4
6
|
export { default } from "./plugin";
|
|
5
7
|
export { sveld } from "./sveld";
|