svelte-origin 1.0.0-next.23 → 1.0.0-next.25

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.

Potentially problematic release.


This version of svelte-origin might be problematic. Click here for more details.

@@ -6,12 +6,27 @@
6
6
  */
7
7
  import type MagicString from 'magic-string';
8
8
  import { type SchemaResolver } from './schema';
9
+ /**
10
+ * Information about a tracked origin instance (for destructuring transform)
11
+ */
12
+ export interface TrackedOriginInstance {
13
+ /** Variable name holding the origin instance */
14
+ varName: string;
15
+ /** The factory name/expression used to create it */
16
+ factoryExpr: string;
17
+ /** Start position in source */
18
+ startPos: number;
19
+ /** End position in source */
20
+ endPos: number;
21
+ }
9
22
  /**
10
23
  * Result from transformAttrsOriginCalls including $$Props info for later injection
11
24
  */
12
25
  export interface AttrsOriginTransformResult {
13
26
  changed: boolean;
14
27
  propsTypeDeclaration: string | null;
28
+ /** Tracked origin instances for destructuring transform */
29
+ originInstances: Map<string, TrackedOriginInstance>;
15
30
  }
16
31
  /**
17
32
  * Transform $attrs.origin(X) calls in component scripts (sync fallback version).
@@ -0,0 +1,62 @@
1
+ /**
2
+ * Origin destructuring transformation logic.
3
+ *
4
+ * Handles patterns like:
5
+ * - `let { increment } = counter` - destructure methods with this-binding
6
+ * - `let { value } = counter.props` - destructure props directly
7
+ * - `let { props: { value } } = counter` - nested props destructuring
8
+ * - `let { value = $bindable(0) } = counter.props` - override with bindable
9
+ *
10
+ * Methods are bound to preserve `this` context.
11
+ * Props are converted to reactive $derived values.
12
+ */
13
+ import type MagicString from 'magic-string';
14
+ import type { TrackedOriginInstance } from './attrs-origin-transform';
15
+ /**
16
+ * Parsed destructuring pattern from origin
17
+ */
18
+ export interface OriginDestructure {
19
+ /** Full match start position */
20
+ startPos: number;
21
+ /** Full match end position */
22
+ endPos: number;
23
+ /** The source variable being destructured from */
24
+ sourceVar: string;
25
+ /** Whether destructuring from .props (e.g., counter.props) */
26
+ isPropsAccess: boolean;
27
+ /** Destructured method names (need this binding) */
28
+ methods: DestructuredItem[];
29
+ /** Destructured props (need reactive access) */
30
+ props: DestructuredProp[];
31
+ /** Props pattern within nested `props: { ... }` */
32
+ nestedPropsPattern: NestedPropsPattern | null;
33
+ }
34
+ export interface DestructuredItem {
35
+ /** Original key in the origin */
36
+ key: string;
37
+ /** Alias if renamed (e.g., `increment: inc`) */
38
+ alias: string | null;
39
+ /** Default value if provided */
40
+ defaultValue: string | null;
41
+ }
42
+ export interface DestructuredProp extends DestructuredItem {
43
+ /** Whether $bindable() was used in the default */
44
+ isBindable: boolean;
45
+ /** The value inside $bindable() if bindable */
46
+ bindableDefault: string | null;
47
+ }
48
+ export interface NestedPropsPattern {
49
+ /** Start of the `props: { ... }` pattern */
50
+ startPos: number;
51
+ /** End of the `props: { ... }` pattern */
52
+ endPos: number;
53
+ /** Props within the nested pattern */
54
+ props: DestructuredProp[];
55
+ }
56
+ /**
57
+ * Transform origin destructuring patterns in the source.
58
+ *
59
+ * Tracks origin instances created via $attrs.origin() or direct factory calls,
60
+ * then transforms destructuring patterns that reference them.
61
+ */
62
+ export declare function transformOriginDestructuring(s: MagicString, source: string, originInstances: Map<string, TrackedOriginInstance>): boolean;
@@ -0,0 +1,87 @@
1
+ /**
2
+ * Reserved keyword handling for generated code.
3
+ *
4
+ * JavaScript/TypeScript reserved keywords cannot be used as bare identifiers
5
+ * in destructuring patterns. When a prop name is a reserved keyword (like 'class'),
6
+ * we need to use a renamed internal variable.
7
+ *
8
+ * Example:
9
+ * ```ts
10
+ * // This is INVALID:
11
+ * let { class = '' } = $props()
12
+ *
13
+ * // This is VALID:
14
+ * let { class: ___class = '' } = $props()
15
+ * ```
16
+ */
17
+ /**
18
+ * Check if a string is a reserved keyword that needs renaming
19
+ */
20
+ export declare function isReservedKeyword(name: string): boolean;
21
+ /**
22
+ * Get the internal variable name for a prop.
23
+ *
24
+ * For reserved keywords and collision prevention, we prefix with `___`.
25
+ * This ensures the generated code is valid JavaScript.
26
+ *
27
+ * @param propName The original prop name
28
+ * @param forcePrefix If true, always add prefix (for collision prevention)
29
+ * @returns The internal variable name to use
30
+ *
31
+ * @example
32
+ * getInternalVarName('class') // '___class'
33
+ * getInternalVarName('value') // '___value'
34
+ * getInternalVarName('count', true) // '___count'
35
+ */
36
+ export declare function getInternalVarName(propName: string, forcePrefix?: boolean): string;
37
+ /**
38
+ * Generate the prop destructuring part for a single prop.
39
+ * Handles reserved keywords by using property renaming.
40
+ *
41
+ * @param propName The original prop name
42
+ * @param defaultValue The default value expression (already formatted)
43
+ * @returns The destructuring part for this prop
44
+ *
45
+ * @example
46
+ * // Reserved keyword
47
+ * generatePropDestructure('class', "''")
48
+ * // Returns: "class: ___class = ''"
49
+ *
50
+ * // Normal prop
51
+ * generatePropDestructure('value', '$bindable()')
52
+ * // Returns: "value: ___value = $bindable()"
53
+ */
54
+ export declare function generatePropDestructure(propName: string, defaultValue: string): string;
55
+ /**
56
+ * Generate the prop destructuring part for a prop without a default value.
57
+ *
58
+ * @param propName The original prop name
59
+ * @returns The destructuring part for this prop
60
+ *
61
+ * @example
62
+ * generatePropDestructureNoDefault('class')
63
+ * // Returns: "class: ___class"
64
+ */
65
+ export declare function generatePropDestructureNoDefault(propName: string): string;
66
+ /**
67
+ * Generate a getter for the reactive attrs wrapper.
68
+ *
69
+ * @param propName The original prop name
70
+ * @returns The getter definition
71
+ *
72
+ * @example
73
+ * generateGetter('class')
74
+ * // Returns: "get class() { return ___class }"
75
+ */
76
+ export declare function generateGetter(propName: string): string;
77
+ /**
78
+ * Generate a setter for the reactive attrs wrapper.
79
+ *
80
+ * @param propName The original prop name
81
+ * @returns The setter definition
82
+ *
83
+ * @example
84
+ * generateSetter('class')
85
+ * // Returns: "set class(v) { ___class = v }"
86
+ */
87
+ export declare function generateSetter(propName: string): string;
@@ -64,12 +64,16 @@ export declare function parseAttrsSchemaFromSource(source: string, exportName: s
64
64
  * to the factory type. This approach is required for svelte-check to properly
65
65
  * infer component props from the origin factory definition.
66
66
  *
67
+ * All props use internal variable names (prefixed with ___) to:
68
+ * 1. Avoid reserved keyword conflicts (e.g., 'class' -> 'class: ___class')
69
+ * 2. Prevent accidental naming collisions with user code
70
+ *
67
71
  * @example
68
72
  * generatePropsDestructuring([
69
- * { key: 'label', defaultValue: "'Counter'", bindable: false, hasDefault: true },
73
+ * { key: 'class', defaultValue: "''", bindable: false, hasDefault: true },
70
74
  * { key: 'count', defaultValue: '0', bindable: true, hasDefault: true }
71
75
  * ], 'Counter')
72
- * // Returns: "let { label = 'Counter', count = $bindable(0) }: $attrs.Of<typeof Counter> = $props()"
76
+ * // Returns: "let { class: ___class = '', count: ___count = $bindable(0) }: $attrs.Of<typeof Counter> = $props()"
73
77
  */
74
78
  export declare function generatePropsDestructuring(attrs: ParsedAttrInfo[], factoryName: string): string;
75
79
  /**
@@ -77,12 +81,15 @@ export declare function generatePropsDestructuring(attrs: ParsedAttrInfo[], fact
77
81
  * For bindable attrs, we create getters AND setters to maintain two-way binding.
78
82
  * For non-bindable attrs, we only create getters.
79
83
  *
84
+ * Getters/setters reference internal variable names (___key) that were
85
+ * destructured from $props().
86
+ *
80
87
  * @example
81
88
  * generateFactoryCallFromAttrs('Counter', [
82
- * { key: 'label', defaultValue: "'Counter'", bindable: false, hasDefault: true },
89
+ * { key: 'class', defaultValue: "''", bindable: false, hasDefault: true },
83
90
  * { key: 'count', defaultValue: '0', bindable: true, hasDefault: true }
84
91
  * ])
85
- * // Returns: "Counter({ get label() { return label }, get count() { return count }, set count(v) { count = v } })"
92
+ * // Returns: "Counter({ get class() { return ___class }, get count() { return ___count }, set count(v) { ___count = v } })"
86
93
  */
87
94
  export declare function generateFactoryCallFromAttrs(factoryName: string, attrs: ParsedAttrInfo[]): string;
88
95
  /**
package/dist/vite-dts.js CHANGED
@@ -200,6 +200,79 @@ function findMatchingBracket(source, openIndex, openChar = "(", closeChar = ")")
200
200
  return -1;
201
201
  }
202
202
 
203
+ // src/transform/reserved-keywords.ts
204
+ var RESERVED_KEYWORDS = new Set([
205
+ "break",
206
+ "case",
207
+ "catch",
208
+ "continue",
209
+ "debugger",
210
+ "default",
211
+ "delete",
212
+ "do",
213
+ "else",
214
+ "finally",
215
+ "for",
216
+ "function",
217
+ "if",
218
+ "in",
219
+ "instanceof",
220
+ "new",
221
+ "return",
222
+ "switch",
223
+ "this",
224
+ "throw",
225
+ "try",
226
+ "typeof",
227
+ "var",
228
+ "void",
229
+ "while",
230
+ "with",
231
+ "class",
232
+ "const",
233
+ "enum",
234
+ "export",
235
+ "extends",
236
+ "import",
237
+ "super",
238
+ "implements",
239
+ "interface",
240
+ "let",
241
+ "package",
242
+ "private",
243
+ "protected",
244
+ "public",
245
+ "static",
246
+ "yield",
247
+ "await",
248
+ "async",
249
+ "true",
250
+ "false",
251
+ "null",
252
+ "undefined",
253
+ "arguments",
254
+ "eval"
255
+ ]);
256
+ function getInternalVarName(propName, forcePrefix = true) {
257
+ return `___${propName}`;
258
+ }
259
+ function generatePropDestructure(propName, defaultValue) {
260
+ const internalName = getInternalVarName(propName);
261
+ return `${propName}: ${internalName} = ${defaultValue}`;
262
+ }
263
+ function generatePropDestructureNoDefault(propName) {
264
+ const internalName = getInternalVarName(propName);
265
+ return `${propName}: ${internalName}`;
266
+ }
267
+ function generateGetter(propName) {
268
+ const internalName = getInternalVarName(propName);
269
+ return `get ${propName}() { return ${internalName} }`;
270
+ }
271
+ function generateSetter(propName) {
272
+ const internalName = getInternalVarName(propName);
273
+ return `set ${propName}(v) { ${internalName} = v }`;
274
+ }
275
+
203
276
  // src/transform/schema.ts
204
277
  function parseOriginSchemaFromSource(source, exportName) {
205
278
  const sourceResult = parseSourceOrigin(source, exportName);
@@ -426,6 +499,7 @@ function parseAttrsContent(content) {
426
499
  continue;
427
500
  const key = trimmed.slice(0, colonIndex).trim();
428
501
  let value = trimmed.slice(colonIndex + 1).trim();
502
+ value = stripTrailingComments(value);
429
503
  const asIndex = findTopLevelAs(value);
430
504
  if (asIndex !== -1) {
431
505
  value = value.slice(0, asIndex).trim();
@@ -533,19 +607,69 @@ function stripComments(str) {
533
607
  }
534
608
  return result;
535
609
  }
610
+ function stripTrailingComments(str) {
611
+ let result = str.trim();
612
+ let i = 0;
613
+ while (i < result.length) {
614
+ const char = result[i];
615
+ if (char === '"' || char === "'" || char === "`") {
616
+ const quote = char;
617
+ i++;
618
+ while (i < result.length && result[i] !== quote) {
619
+ if (result[i] === "\\")
620
+ i++;
621
+ i++;
622
+ }
623
+ i++;
624
+ continue;
625
+ }
626
+ if (char === "{" || char === "(" || char === "[") {
627
+ let depth = 1;
628
+ i++;
629
+ while (i < result.length && depth > 0) {
630
+ const c = result[i];
631
+ if (c === "{" || c === "(" || c === "[")
632
+ depth++;
633
+ else if (c === "}" || c === ")" || c === "]")
634
+ depth--;
635
+ else if (c === '"' || c === "'" || c === "`") {
636
+ const quote = c;
637
+ i++;
638
+ while (i < result.length && result[i] !== quote) {
639
+ if (result[i] === "\\")
640
+ i++;
641
+ i++;
642
+ }
643
+ }
644
+ i++;
645
+ }
646
+ continue;
647
+ }
648
+ if (char === "/" && result[i + 1] === "*") {
649
+ result = result.slice(0, i).trim();
650
+ break;
651
+ }
652
+ if (char === "/" && result[i + 1] === "/") {
653
+ result = result.slice(0, i).trim();
654
+ break;
655
+ }
656
+ i++;
657
+ }
658
+ return result;
659
+ }
536
660
  function generatePropsDestructuring(attrs, factoryName) {
537
661
  const parts = [];
538
662
  for (const attr of attrs) {
539
663
  if (attr.bindable) {
540
664
  if (attr.hasDefault) {
541
- parts.push(`${attr.key} = $bindable(${attr.defaultValue})`);
665
+ parts.push(generatePropDestructure(attr.key, `$bindable(${attr.defaultValue})`));
542
666
  } else {
543
- parts.push(`${attr.key} = $bindable()`);
667
+ parts.push(generatePropDestructure(attr.key, "$bindable()"));
544
668
  }
545
669
  } else if (attr.hasDefault) {
546
- parts.push(`${attr.key} = ${attr.defaultValue}`);
670
+ parts.push(generatePropDestructure(attr.key, attr.defaultValue));
547
671
  } else {
548
- parts.push(attr.key);
672
+ parts.push(generatePropDestructureNoDefault(attr.key));
549
673
  }
550
674
  }
551
675
  return `let { ${parts.join(", ")} }: $attrs.Of<typeof ${factoryName}> = $props()`;
@@ -553,9 +677,9 @@ function generatePropsDestructuring(attrs, factoryName) {
553
677
  function generateFactoryCallFromAttrs(factoryName, attrs) {
554
678
  const parts = [];
555
679
  for (const attr of attrs) {
556
- parts.push(`get ${attr.key}() { return ${attr.key} }`);
680
+ parts.push(generateGetter(attr.key));
557
681
  if (attr.bindable) {
558
- parts.push(`set ${attr.key}(v) { ${attr.key} = v }`);
682
+ parts.push(generateSetter(attr.key));
559
683
  }
560
684
  }
561
685
  return `${factoryName}({ ${parts.join(", ")} })`;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "svelte-origin",
3
- "version": "1.0.0-next.23",
3
+ "version": "1.0.0-next.25",
4
4
  "description": "Compiler-assisted state and prop ergonomics for Svelte 5",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",