sveld 0.31.0 → 0.32.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 CHANGED
@@ -127,6 +127,7 @@ export default class Button extends SvelteComponentTyped<
127
127
  - [CLI](#cli)
128
128
  - [Publishing to NPM](#publishing-to-npm)
129
129
  - [Available Options](#available-options)
130
+ - [JSON Output](#json-output)
130
131
  - [API Reference](#api-reference)
131
132
  - [@type](#type)
132
133
  - [@default](#default)
@@ -333,6 +334,121 @@ sveld({
333
334
  })
334
335
  ```
335
336
 
337
+ ## JSON Output
338
+
339
+ When `json: true` is enabled, `sveld` emits a `COMPONENT_API.json` file with schema and generator metadata plus the parsed
340
+ component API.
341
+
342
+ The public JSON Schema for the combined output is hosted 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 document or validate
343
+ generated `COMPONENT_API.json` files. The schema describes the emitted metadata contract; optional fields may be absent when
344
+ the parser does not have a stable source for that metadata.
345
+
346
+ ```ts
347
+ interface ComponentApiJson {
348
+ schemaVersion: 1;
349
+ generator: {
350
+ name: string;
351
+ version: string;
352
+ svelteVersion: string;
353
+ };
354
+ total: number;
355
+ components: ComponentDocApi[];
356
+ }
357
+
358
+ interface SourceRange {
359
+ start: SourcePosition;
360
+ end: SourcePosition;
361
+ }
362
+
363
+ interface SourcePosition {
364
+ line: number;
365
+ column: number;
366
+ }
367
+
368
+ interface ComponentDocApi {
369
+ moduleName: string;
370
+ filePath: string;
371
+ source?: SourceRange;
372
+ syntaxMode: "legacy" | "runes";
373
+ scriptLanguage?: "js" | "ts";
374
+ props: ComponentProp[];
375
+ moduleExports: ComponentProp[];
376
+ slots: ComponentSlot[];
377
+ events: ComponentEvent[];
378
+ typedefs: TypeDef[];
379
+ generics: null | [name: string, type: string];
380
+ rest_props?: RestProps;
381
+ extends?: { interface: string; import: string };
382
+ componentComment?: string;
383
+ componentCommentSource?: SourceRange;
384
+ contexts?: ComponentContext[];
385
+ }
386
+
387
+ interface ComponentProp {
388
+ name: string;
389
+ localName?: string;
390
+ kind: "let" | "const" | "function";
391
+ constant: boolean;
392
+ type?: string;
393
+ typeSource?: "typescript" | "jsdoc" | "default" | "inferred" | "unknown";
394
+ value?: string;
395
+ defaultValue?: {
396
+ raw: string;
397
+ kind: "literal" | "array" | "object" | "expression" | "function" | "unknown";
398
+ value?: unknown;
399
+ };
400
+ description?: string;
401
+ params?: Array<{ name: string; type: string; description?: string; optional?: boolean }>;
402
+ returnType?: string;
403
+ isFunction: boolean;
404
+ isFunctionDeclaration: boolean;
405
+ isRequired: boolean;
406
+ reactive: boolean;
407
+ binding?: "readonly" | "writable";
408
+ bindable?: true;
409
+ source?: SourceRange;
410
+ }
411
+
412
+ interface ComponentSlot {
413
+ name?: string | null;
414
+ default: boolean;
415
+ fallback?: string;
416
+ slot_props?: string;
417
+ description?: string;
418
+ tags?: Array<{ name: string; body: string }>;
419
+ source?: SourceRange;
420
+ }
421
+
422
+ type ComponentEvent =
423
+ | {
424
+ type: "forwarded";
425
+ name: string;
426
+ element: string;
427
+ description?: string;
428
+ detail?: string;
429
+ source?: SourceRange;
430
+ }
431
+ | {
432
+ type: "dispatched";
433
+ name: string;
434
+ detail?: string;
435
+ description?: string;
436
+ source?: SourceRange;
437
+ };
438
+ ```
439
+
440
+ `source` fields are optional and are included only when the Svelte or JavaScript AST provides stable positions. They do not
441
+ include source text or raw character offsets.
442
+
443
+ Note that `SourcePosition.line` is 1-based and `SourcePosition.column` is 0-based.
444
+
445
+ Prop metadata is additive and preserves the older public fields:
446
+
447
+ - `name` is always the public prop name. For runes `$props()` aliases such as `let { class: className } = $props()`, `localName` is emitted only when the local binding differs.
448
+ - `typeSource` identifies the conservative source of the emitted `type`: TypeScript annotation, JSDoc, initializer/default inference, other parser inference, or unknown fallback.
449
+ - `value` remains the raw default expression string. `defaultValue` adds structured metadata with the same raw expression, a coarse `kind`, and a parsed `value` only for JSON-safe literals, arrays, and plain objects. `sveld` does not evaluate arbitrary code.
450
+ - `bindable: true` is emitted only for props explicitly declared with Svelte 5 `$bindable(...)`. Missing `bindable` should be treated as false.
451
+
336
452
  ## API Reference
337
453
 
338
454
  ### `reactive`
@@ -350,6 +466,38 @@ Local variables or parameters that shadow a prop name do not count as writes to
350
466
 
351
467
  `reactive: false` means `sveld` found no such evidence. It does not imply that parent-side `bind:` usage is impossible.
352
468
 
469
+ ### `binding`
470
+
471
+ The optional `binding` field in generated JSON is explicit documentation metadata for a prop's intended `bind:` contract. It is separate from `reactive`, and it is never inferred from internal writes or `$bindable()`.
472
+
473
+ Use `@bindable readonly` for component-owned or output-style bindings where the consumer binds to the current value emitted by the component:
474
+
475
+ ```svelte
476
+ <script>
477
+ /**
478
+ * Bind to the current value emitted by the component.
479
+ * @bindable readonly
480
+ */
481
+ export let size = undefined;
482
+ </script>
483
+ ```
484
+
485
+ Use `@bindable writable` for two-way or shared state bindings where either the consumer or component may control the value:
486
+
487
+ ```svelte
488
+ <script>
489
+ /**
490
+ * Bind to state controlled by either the consumer or component.
491
+ * @bindable writable
492
+ */
493
+ export let open = false;
494
+ </script>
495
+ ```
496
+
497
+ Generated JSON includes `"binding": "readonly"` or `"binding": "writable"` for annotated props. Unannotated props omit the field.
498
+
499
+ This is documentation metadata only. Generated `.svelte.d.ts` prop types are unchanged because TypeScript cannot reliably express Svelte component binding direction.
500
+
353
501
  For stable output, generated `events` arrays are emitted in deterministic sorted order.
354
502
 
355
503
  ### `@type`