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

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/dist/cli.js CHANGED
@@ -2842,7 +2842,34 @@ function getElementTypeImport(element) {
2842
2842
  }
2843
2843
 
2844
2844
  // src/transform/attrs-for-transform.ts
2845
- function transformAttrsForCalls(s, source, neededImports) {
2845
+ function generateReactiveAttrsWrapper(attrs) {
2846
+ const parts = [];
2847
+ for (const attr of attrs) {
2848
+ parts.push(`get ${attr.key}() { return ${attr.key} }`);
2849
+ if (attr.bindable) {
2850
+ parts.push(`set ${attr.key}(v) { ${attr.key} = v }`);
2851
+ }
2852
+ }
2853
+ return `{ ${parts.join(", ")} }`;
2854
+ }
2855
+ function generateAttrsForMerge(attrs) {
2856
+ const parts = [];
2857
+ for (const attr of attrs) {
2858
+ if (attr.bindable) {
2859
+ if (attr.hasDefault) {
2860
+ parts.push(`${attr.key} = $bindable(${attr.defaultValue})`);
2861
+ } else {
2862
+ parts.push(`${attr.key} = $bindable()`);
2863
+ }
2864
+ } else if (attr.hasDefault) {
2865
+ parts.push(`${attr.key} = ${attr.defaultValue}`);
2866
+ } else {
2867
+ parts.push(attr.key);
2868
+ }
2869
+ }
2870
+ return parts.join(", ");
2871
+ }
2872
+ function transformAttrsForCallsSync(s, source, neededImports) {
2846
2873
  let changed = false;
2847
2874
  const existingPropsMatch = source.match(/let\s*\{([^}]*)\}\s*(?::\s*[^=]+)?\s*=\s*\$props\s*\(\s*\)/);
2848
2875
  let restVarName = null;
@@ -2908,6 +2935,111 @@ function transformAttrsForCalls(s, source, neededImports) {
2908
2935
  }
2909
2936
  return changed;
2910
2937
  }
2938
+ async function transformAttrsForCalls(s, source, neededImports, schemaResolver) {
2939
+ let changed = false;
2940
+ const existingPropsMatch = source.match(/let\s*\{([^}]*)\}\s*(?::\s*[^=]+)?\s*=\s*\$props\s*\(\s*\)/);
2941
+ let restVarName = null;
2942
+ let existingPropsStart = -1;
2943
+ let existingDestructureContent = "";
2944
+ if (existingPropsMatch) {
2945
+ existingPropsStart = existingPropsMatch.index;
2946
+ existingDestructureContent = existingPropsMatch[1];
2947
+ const restMatch = existingDestructureContent.match(/\.\.\.\s*(\w+)\s*$/);
2948
+ if (restMatch) {
2949
+ restVarName = restMatch[1];
2950
+ }
2951
+ }
2952
+ const declarations = findVariableDeclarationsWithMacro(source, "$attrs.for");
2953
+ for (const decl of declarations) {
2954
+ const { varName, startIndex, macroOpenParen } = decl;
2955
+ const closeParenIndex = findMatchingBracket(source, macroOpenParen);
2956
+ if (closeParenIndex === -1)
2957
+ continue;
2958
+ const arg = source.slice(macroOpenParen + 1, closeParenIndex).trim();
2959
+ const endIndex = closeParenIndex + 1;
2960
+ const stringMatch = arg.match(/^['"](\w+)['"]$/);
2961
+ if (stringMatch) {
2962
+ const element = stringMatch[1];
2963
+ const typeImport = getElementTypeImport(element);
2964
+ if (existingPropsMatch && existingPropsStart !== -1) {
2965
+ if (!restVarName) {
2966
+ restVarName = "___restAttrs";
2967
+ const newDestructure = existingDestructureContent.trimEnd() ? `${existingDestructureContent.trimEnd()}, ...${restVarName}` : `...${restVarName}`;
2968
+ const braceEnd = source.indexOf("}", existingPropsStart + 5);
2969
+ if (braceEnd !== -1) {
2970
+ s.overwrite(existingPropsStart + 5, braceEnd, ` ${newDestructure} `);
2971
+ }
2972
+ }
2973
+ s.overwrite(startIndex, endIndex, `let ${varName} = ${restVarName} as ${typeImport}`);
2974
+ } else {
2975
+ const expansion = `let { ...${varName} } = $props<${typeImport}>()`;
2976
+ s.overwrite(startIndex, endIndex, expansion);
2977
+ }
2978
+ } else {
2979
+ const factoryName = arg;
2980
+ let transformed = false;
2981
+ if (schemaResolver) {
2982
+ const importPath = findImportPath(source, factoryName);
2983
+ if (importPath) {
2984
+ const schema = await schemaResolver.resolve(importPath, factoryName);
2985
+ if (schema && schema.attrs.length > 0) {
2986
+ if (existingPropsMatch && existingPropsStart !== -1) {
2987
+ const additionalAttrs = generateAttrsForMerge(schema.attrs);
2988
+ const restMatch = existingDestructureContent.match(/,?\s*\.\.\.\s*(\w+)\s*$/);
2989
+ let baseContent = existingDestructureContent;
2990
+ let restPart = "";
2991
+ if (restMatch) {
2992
+ restPart = restMatch[0];
2993
+ baseContent = existingDestructureContent.slice(0, restMatch.index);
2994
+ }
2995
+ const mergedDestructure = baseContent.trimEnd() ? `${baseContent.trimEnd()}, ${additionalAttrs}${restPart}` : `${additionalAttrs}${restPart}`;
2996
+ const braceEnd = source.indexOf("}", existingPropsStart + 5);
2997
+ if (braceEnd !== -1) {
2998
+ s.overwrite(existingPropsStart + 5, braceEnd, ` ${mergedDestructure} `);
2999
+ }
3000
+ const wrapper = generateReactiveAttrsWrapper(schema.attrs);
3001
+ s.overwrite(startIndex, endIndex, `let ${varName} = __attrsFor(${factoryName}, ${wrapper})`);
3002
+ transformed = true;
3003
+ } else {
3004
+ const propsDestructure = generatePropsDestructuring(schema.attrs, factoryName);
3005
+ const wrapper = generateReactiveAttrsWrapper(schema.attrs);
3006
+ const expansion = [
3007
+ propsDestructure,
3008
+ `let ${varName} = __attrsFor(${factoryName}, ${wrapper})`
3009
+ ].join(`
3010
+ `);
3011
+ s.overwrite(startIndex, endIndex, expansion);
3012
+ transformed = true;
3013
+ }
3014
+ }
3015
+ }
3016
+ }
3017
+ if (!transformed) {
3018
+ if (existingPropsMatch && existingPropsStart !== -1) {
3019
+ if (!restVarName) {
3020
+ restVarName = "___restAttrs";
3021
+ const newDestructure = existingDestructureContent.trimEnd() ? `${existingDestructureContent.trimEnd()}, ...${restVarName}` : `...${restVarName}`;
3022
+ const braceEnd = source.indexOf("}", existingPropsStart + 5);
3023
+ if (braceEnd !== -1) {
3024
+ s.overwrite(existingPropsStart + 5, braceEnd, ` ${newDestructure} `);
3025
+ }
3026
+ }
3027
+ s.overwrite(startIndex, endIndex, `let ${varName} = __attrsFor(${factoryName}, ${restVarName})`);
3028
+ } else {
3029
+ const expansion = [
3030
+ `let ___attrs: $attrs.Of<typeof ${factoryName}> = $props()`,
3031
+ `let ${varName} = __attrsFor(${factoryName}, ___attrs)`
3032
+ ].join(`
3033
+ `);
3034
+ s.overwrite(startIndex, endIndex, expansion);
3035
+ }
3036
+ }
3037
+ neededImports.add("__attrsFor");
3038
+ }
3039
+ changed = true;
3040
+ }
3041
+ return changed;
3042
+ }
2911
3043
 
2912
3044
  // src/transform/core.ts
2913
3045
  function transformScript(source, options = {}) {
@@ -2933,7 +3065,7 @@ function transformScript(source, options = {}) {
2933
3065
  propsTypeDeclaration = result.propsTypeDeclaration;
2934
3066
  }
2935
3067
  if (isComponent) {
2936
- changed = transformAttrsForCalls(s, source, neededImports) || changed;
3068
+ changed = transformAttrsForCallsSync(s, source, neededImports) || changed;
2937
3069
  }
2938
3070
  const needsPropsInjection = propsTypeDeclaration && propsTypeDeclaration.length > 0;
2939
3071
  if (isComponent && (neededImports.size > 0 || needsPropsInjection)) {
@@ -3004,7 +3136,7 @@ async function transformScriptAsync(source, options) {
3004
3136
  propsTypeDeclaration = result.propsTypeDeclaration;
3005
3137
  }
3006
3138
  if (isComponent) {
3007
- changed = transformAttrsForCalls(s, source, neededImports) || changed;
3139
+ changed = await transformAttrsForCalls(s, source, neededImports, schemaResolver) || changed;
3008
3140
  }
3009
3141
  const needsPropsInjectionAsync = propsTypeDeclaration && propsTypeDeclaration.length > 0;
3010
3142
  if (isComponent && (neededImports.size > 0 || needsPropsInjectionAsync)) {
@@ -3074,7 +3206,7 @@ async function transformScriptContent(source, options) {
3074
3206
  propsTypeDeclaration = result.propsTypeDeclaration;
3075
3207
  }
3076
3208
  if (isComponent) {
3077
- changed = transformAttrsForCalls(s, source, neededImports) || changed;
3209
+ changed = await transformAttrsForCalls(s, source, neededImports, schemaResolver) || changed;
3078
3210
  }
3079
3211
  if (neededImports.size > 0) {
3080
3212
  const importStatement = generateRuntimeImport([...neededImports]);
package/dist/index.js CHANGED
@@ -3473,34 +3473,22 @@ function __attrsFor(factory, rawAttrs) {
3473
3473
  const factoryWithSchema = factory;
3474
3474
  const schema = getMergedAttrSchema(factoryWithSchema);
3475
3475
  const wrapper = {};
3476
- const localValues = {};
3477
- const hasLocalValue = {};
3478
3476
  const defineExposedProp = (key2, info) => {
3479
3477
  if (Object.prototype.hasOwnProperty.call(wrapper, key2))
3480
3478
  return;
3481
- const base = {
3479
+ const descriptor = {
3482
3480
  get() {
3483
- if (hasLocalValue[key2])
3484
- return localValues[key2];
3485
3481
  return rawAttrs[key2];
3486
3482
  },
3487
3483
  enumerable: true,
3488
3484
  configurable: true
3489
3485
  };
3490
3486
  if (info.bindable) {
3491
- Object.defineProperty(wrapper, key2, {
3492
- ...base,
3493
- set(value) {
3494
- localValues[key2] = value;
3495
- hasLocalValue[key2] = true;
3496
- try {
3497
- rawAttrs[key2] = value;
3498
- } catch {}
3499
- }
3500
- });
3501
- } else {
3502
- Object.defineProperty(wrapper, key2, base);
3487
+ descriptor.set = function(value) {
3488
+ rawAttrs[key2] = value;
3489
+ };
3503
3490
  }
3491
+ Object.defineProperty(wrapper, key2, descriptor);
3504
3492
  };
3505
3493
  for (const [key2, info] of Object.entries(schema)) {
3506
3494
  const parentValue = rawAttrs[key2];
@@ -3521,8 +3509,6 @@ function __attrsFor(factory, rawAttrs) {
3521
3509
  return new Proxy(wrapper, {
3522
3510
  get(target, prop2) {
3523
3511
  if (typeof prop2 === "string" && prop2 in schema) {
3524
- if (hasLocalValue[prop2])
3525
- return localValues[prop2];
3526
3512
  return rawAttrs[prop2];
3527
3513
  }
3528
3514
  if (prop2 in target)
@@ -3531,15 +3517,11 @@ function __attrsFor(factory, rawAttrs) {
3531
3517
  },
3532
3518
  set(target, prop2, value) {
3533
3519
  if (typeof prop2 === "string" && prop2 in schema) {
3534
- localValues[prop2] = value;
3535
- hasLocalValue[prop2] = true;
3536
3520
  if (!Object.prototype.hasOwnProperty.call(wrapper, prop2)) {
3537
3521
  defineExposedProp(prop2, schema[prop2]);
3538
3522
  }
3539
3523
  if (schema[prop2].bindable) {
3540
- try {
3541
- rawAttrs[prop2] = value;
3542
- } catch {}
3524
+ rawAttrs[prop2] = value;
3543
3525
  }
3544
3526
  return true;
3545
3527
  }
@@ -3551,18 +3533,10 @@ function __attrsFor(factory, rawAttrs) {
3551
3533
  }
3552
3534
  try {
3553
3535
  rawAttrs[prop2] = value;
3554
- } catch {
3555
- if (typeof prop2 === "string") {
3556
- localValues[prop2] = value;
3557
- hasLocalValue[prop2] = true;
3558
- }
3559
- }
3536
+ } catch {}
3560
3537
  return true;
3561
3538
  },
3562
3539
  has(target, prop2) {
3563
- if (typeof prop2 === "string" && prop2 in schema) {
3564
- return prop2 in target || hasLocalValue[prop2];
3565
- }
3566
3540
  return prop2 in target || prop2 in rawAttrs;
3567
3541
  },
3568
3542
  ownKeys() {
@@ -6661,7 +6635,34 @@ function getElementTypeImport(element2) {
6661
6635
  }
6662
6636
 
6663
6637
  // src/transform/attrs-for-transform.ts
6664
- function transformAttrsForCalls(s, source2, neededImports) {
6638
+ function generateReactiveAttrsWrapper(attrs) {
6639
+ const parts = [];
6640
+ for (const attr2 of attrs) {
6641
+ parts.push(`get ${attr2.key}() { return ${attr2.key} }`);
6642
+ if (attr2.bindable) {
6643
+ parts.push(`set ${attr2.key}(v) { ${attr2.key} = v }`);
6644
+ }
6645
+ }
6646
+ return `{ ${parts.join(", ")} }`;
6647
+ }
6648
+ function generateAttrsForMerge(attrs) {
6649
+ const parts = [];
6650
+ for (const attr2 of attrs) {
6651
+ if (attr2.bindable) {
6652
+ if (attr2.hasDefault) {
6653
+ parts.push(`${attr2.key} = $bindable(${attr2.defaultValue})`);
6654
+ } else {
6655
+ parts.push(`${attr2.key} = $bindable()`);
6656
+ }
6657
+ } else if (attr2.hasDefault) {
6658
+ parts.push(`${attr2.key} = ${attr2.defaultValue}`);
6659
+ } else {
6660
+ parts.push(attr2.key);
6661
+ }
6662
+ }
6663
+ return parts.join(", ");
6664
+ }
6665
+ function transformAttrsForCallsSync(s, source2, neededImports) {
6665
6666
  let changed = false;
6666
6667
  const existingPropsMatch = source2.match(/let\s*\{([^}]*)\}\s*(?::\s*[^=]+)?\s*=\s*\$props\s*\(\s*\)/);
6667
6668
  let restVarName = null;
@@ -6727,6 +6728,111 @@ function transformAttrsForCalls(s, source2, neededImports) {
6727
6728
  }
6728
6729
  return changed;
6729
6730
  }
6731
+ async function transformAttrsForCalls(s, source2, neededImports, schemaResolver) {
6732
+ let changed = false;
6733
+ const existingPropsMatch = source2.match(/let\s*\{([^}]*)\}\s*(?::\s*[^=]+)?\s*=\s*\$props\s*\(\s*\)/);
6734
+ let restVarName = null;
6735
+ let existingPropsStart = -1;
6736
+ let existingDestructureContent = "";
6737
+ if (existingPropsMatch) {
6738
+ existingPropsStart = existingPropsMatch.index;
6739
+ existingDestructureContent = existingPropsMatch[1];
6740
+ const restMatch = existingDestructureContent.match(/\.\.\.\s*(\w+)\s*$/);
6741
+ if (restMatch) {
6742
+ restVarName = restMatch[1];
6743
+ }
6744
+ }
6745
+ const declarations = findVariableDeclarationsWithMacro(source2, "$attrs.for");
6746
+ for (const decl of declarations) {
6747
+ const { varName, startIndex, macroOpenParen } = decl;
6748
+ const closeParenIndex = findMatchingBracket(source2, macroOpenParen);
6749
+ if (closeParenIndex === -1)
6750
+ continue;
6751
+ const arg = source2.slice(macroOpenParen + 1, closeParenIndex).trim();
6752
+ const endIndex = closeParenIndex + 1;
6753
+ const stringMatch = arg.match(/^['"](\w+)['"]$/);
6754
+ if (stringMatch) {
6755
+ const element2 = stringMatch[1];
6756
+ const typeImport = getElementTypeImport(element2);
6757
+ if (existingPropsMatch && existingPropsStart !== -1) {
6758
+ if (!restVarName) {
6759
+ restVarName = "___restAttrs";
6760
+ const newDestructure = existingDestructureContent.trimEnd() ? `${existingDestructureContent.trimEnd()}, ...${restVarName}` : `...${restVarName}`;
6761
+ const braceEnd = source2.indexOf("}", existingPropsStart + 5);
6762
+ if (braceEnd !== -1) {
6763
+ s.overwrite(existingPropsStart + 5, braceEnd, ` ${newDestructure} `);
6764
+ }
6765
+ }
6766
+ s.overwrite(startIndex, endIndex, `let ${varName} = ${restVarName} as ${typeImport}`);
6767
+ } else {
6768
+ const expansion = `let { ...${varName} } = $props<${typeImport}>()`;
6769
+ s.overwrite(startIndex, endIndex, expansion);
6770
+ }
6771
+ } else {
6772
+ const factoryName = arg;
6773
+ let transformed = false;
6774
+ if (schemaResolver) {
6775
+ const importPath = findImportPath(source2, factoryName);
6776
+ if (importPath) {
6777
+ const schema = await schemaResolver.resolve(importPath, factoryName);
6778
+ if (schema && schema.attrs.length > 0) {
6779
+ if (existingPropsMatch && existingPropsStart !== -1) {
6780
+ const additionalAttrs = generateAttrsForMerge(schema.attrs);
6781
+ const restMatch = existingDestructureContent.match(/,?\s*\.\.\.\s*(\w+)\s*$/);
6782
+ let baseContent = existingDestructureContent;
6783
+ let restPart = "";
6784
+ if (restMatch) {
6785
+ restPart = restMatch[0];
6786
+ baseContent = existingDestructureContent.slice(0, restMatch.index);
6787
+ }
6788
+ const mergedDestructure = baseContent.trimEnd() ? `${baseContent.trimEnd()}, ${additionalAttrs}${restPart}` : `${additionalAttrs}${restPart}`;
6789
+ const braceEnd = source2.indexOf("}", existingPropsStart + 5);
6790
+ if (braceEnd !== -1) {
6791
+ s.overwrite(existingPropsStart + 5, braceEnd, ` ${mergedDestructure} `);
6792
+ }
6793
+ const wrapper = generateReactiveAttrsWrapper(schema.attrs);
6794
+ s.overwrite(startIndex, endIndex, `let ${varName} = __attrsFor(${factoryName}, ${wrapper})`);
6795
+ transformed = true;
6796
+ } else {
6797
+ const propsDestructure = generatePropsDestructuring(schema.attrs, factoryName);
6798
+ const wrapper = generateReactiveAttrsWrapper(schema.attrs);
6799
+ const expansion = [
6800
+ propsDestructure,
6801
+ `let ${varName} = __attrsFor(${factoryName}, ${wrapper})`
6802
+ ].join(`
6803
+ `);
6804
+ s.overwrite(startIndex, endIndex, expansion);
6805
+ transformed = true;
6806
+ }
6807
+ }
6808
+ }
6809
+ }
6810
+ if (!transformed) {
6811
+ if (existingPropsMatch && existingPropsStart !== -1) {
6812
+ if (!restVarName) {
6813
+ restVarName = "___restAttrs";
6814
+ const newDestructure = existingDestructureContent.trimEnd() ? `${existingDestructureContent.trimEnd()}, ...${restVarName}` : `...${restVarName}`;
6815
+ const braceEnd = source2.indexOf("}", existingPropsStart + 5);
6816
+ if (braceEnd !== -1) {
6817
+ s.overwrite(existingPropsStart + 5, braceEnd, ` ${newDestructure} `);
6818
+ }
6819
+ }
6820
+ s.overwrite(startIndex, endIndex, `let ${varName} = __attrsFor(${factoryName}, ${restVarName})`);
6821
+ } else {
6822
+ const expansion = [
6823
+ `let ___attrs: $attrs.Of<typeof ${factoryName}> = $props()`,
6824
+ `let ${varName} = __attrsFor(${factoryName}, ___attrs)`
6825
+ ].join(`
6826
+ `);
6827
+ s.overwrite(startIndex, endIndex, expansion);
6828
+ }
6829
+ }
6830
+ neededImports.add("__attrsFor");
6831
+ }
6832
+ changed = true;
6833
+ }
6834
+ return changed;
6835
+ }
6730
6836
 
6731
6837
  // src/transform/core.ts
6732
6838
  function transformScript(source2, options = {}) {
@@ -6752,7 +6858,7 @@ function transformScript(source2, options = {}) {
6752
6858
  propsTypeDeclaration = result.propsTypeDeclaration;
6753
6859
  }
6754
6860
  if (isComponent) {
6755
- changed = transformAttrsForCalls(s, source2, neededImports) || changed;
6861
+ changed = transformAttrsForCallsSync(s, source2, neededImports) || changed;
6756
6862
  }
6757
6863
  const needsPropsInjection = propsTypeDeclaration && propsTypeDeclaration.length > 0;
6758
6864
  if (isComponent && (neededImports.size > 0 || needsPropsInjection)) {
@@ -6823,7 +6929,7 @@ async function transformScriptAsync(source2, options) {
6823
6929
  propsTypeDeclaration = result.propsTypeDeclaration;
6824
6930
  }
6825
6931
  if (isComponent) {
6826
- changed = transformAttrsForCalls(s, source2, neededImports) || changed;
6932
+ changed = await transformAttrsForCalls(s, source2, neededImports, schemaResolver) || changed;
6827
6933
  }
6828
6934
  const needsPropsInjectionAsync = propsTypeDeclaration && propsTypeDeclaration.length > 0;
6829
6935
  if (isComponent && (neededImports.size > 0 || needsPropsInjectionAsync)) {
@@ -6893,7 +6999,7 @@ async function transformScriptContent(source2, options) {
6893
6999
  propsTypeDeclaration = result.propsTypeDeclaration;
6894
7000
  }
6895
7001
  if (isComponent) {
6896
- changed = transformAttrsForCalls(s, source2, neededImports) || changed;
7002
+ changed = await transformAttrsForCalls(s, source2, neededImports, schemaResolver) || changed;
6897
7003
  }
6898
7004
  if (neededImports.size > 0) {
6899
7005
  const importStatement = generateRuntimeImport([...neededImports]);
package/dist/plugin.js CHANGED
@@ -2836,7 +2836,34 @@ function getElementTypeImport(element) {
2836
2836
  }
2837
2837
 
2838
2838
  // src/transform/attrs-for-transform.ts
2839
- function transformAttrsForCalls(s, source, neededImports) {
2839
+ function generateReactiveAttrsWrapper(attrs) {
2840
+ const parts = [];
2841
+ for (const attr of attrs) {
2842
+ parts.push(`get ${attr.key}() { return ${attr.key} }`);
2843
+ if (attr.bindable) {
2844
+ parts.push(`set ${attr.key}(v) { ${attr.key} = v }`);
2845
+ }
2846
+ }
2847
+ return `{ ${parts.join(", ")} }`;
2848
+ }
2849
+ function generateAttrsForMerge(attrs) {
2850
+ const parts = [];
2851
+ for (const attr of attrs) {
2852
+ if (attr.bindable) {
2853
+ if (attr.hasDefault) {
2854
+ parts.push(`${attr.key} = $bindable(${attr.defaultValue})`);
2855
+ } else {
2856
+ parts.push(`${attr.key} = $bindable()`);
2857
+ }
2858
+ } else if (attr.hasDefault) {
2859
+ parts.push(`${attr.key} = ${attr.defaultValue}`);
2860
+ } else {
2861
+ parts.push(attr.key);
2862
+ }
2863
+ }
2864
+ return parts.join(", ");
2865
+ }
2866
+ function transformAttrsForCallsSync(s, source, neededImports) {
2840
2867
  let changed = false;
2841
2868
  const existingPropsMatch = source.match(/let\s*\{([^}]*)\}\s*(?::\s*[^=]+)?\s*=\s*\$props\s*\(\s*\)/);
2842
2869
  let restVarName = null;
@@ -2902,6 +2929,111 @@ function transformAttrsForCalls(s, source, neededImports) {
2902
2929
  }
2903
2930
  return changed;
2904
2931
  }
2932
+ async function transformAttrsForCalls(s, source, neededImports, schemaResolver) {
2933
+ let changed = false;
2934
+ const existingPropsMatch = source.match(/let\s*\{([^}]*)\}\s*(?::\s*[^=]+)?\s*=\s*\$props\s*\(\s*\)/);
2935
+ let restVarName = null;
2936
+ let existingPropsStart = -1;
2937
+ let existingDestructureContent = "";
2938
+ if (existingPropsMatch) {
2939
+ existingPropsStart = existingPropsMatch.index;
2940
+ existingDestructureContent = existingPropsMatch[1];
2941
+ const restMatch = existingDestructureContent.match(/\.\.\.\s*(\w+)\s*$/);
2942
+ if (restMatch) {
2943
+ restVarName = restMatch[1];
2944
+ }
2945
+ }
2946
+ const declarations = findVariableDeclarationsWithMacro(source, "$attrs.for");
2947
+ for (const decl of declarations) {
2948
+ const { varName, startIndex, macroOpenParen } = decl;
2949
+ const closeParenIndex = findMatchingBracket(source, macroOpenParen);
2950
+ if (closeParenIndex === -1)
2951
+ continue;
2952
+ const arg = source.slice(macroOpenParen + 1, closeParenIndex).trim();
2953
+ const endIndex = closeParenIndex + 1;
2954
+ const stringMatch = arg.match(/^['"](\w+)['"]$/);
2955
+ if (stringMatch) {
2956
+ const element = stringMatch[1];
2957
+ const typeImport = getElementTypeImport(element);
2958
+ if (existingPropsMatch && existingPropsStart !== -1) {
2959
+ if (!restVarName) {
2960
+ restVarName = "___restAttrs";
2961
+ const newDestructure = existingDestructureContent.trimEnd() ? `${existingDestructureContent.trimEnd()}, ...${restVarName}` : `...${restVarName}`;
2962
+ const braceEnd = source.indexOf("}", existingPropsStart + 5);
2963
+ if (braceEnd !== -1) {
2964
+ s.overwrite(existingPropsStart + 5, braceEnd, ` ${newDestructure} `);
2965
+ }
2966
+ }
2967
+ s.overwrite(startIndex, endIndex, `let ${varName} = ${restVarName} as ${typeImport}`);
2968
+ } else {
2969
+ const expansion = `let { ...${varName} } = $props<${typeImport}>()`;
2970
+ s.overwrite(startIndex, endIndex, expansion);
2971
+ }
2972
+ } else {
2973
+ const factoryName = arg;
2974
+ let transformed = false;
2975
+ if (schemaResolver) {
2976
+ const importPath = findImportPath(source, factoryName);
2977
+ if (importPath) {
2978
+ const schema = await schemaResolver.resolve(importPath, factoryName);
2979
+ if (schema && schema.attrs.length > 0) {
2980
+ if (existingPropsMatch && existingPropsStart !== -1) {
2981
+ const additionalAttrs = generateAttrsForMerge(schema.attrs);
2982
+ const restMatch = existingDestructureContent.match(/,?\s*\.\.\.\s*(\w+)\s*$/);
2983
+ let baseContent = existingDestructureContent;
2984
+ let restPart = "";
2985
+ if (restMatch) {
2986
+ restPart = restMatch[0];
2987
+ baseContent = existingDestructureContent.slice(0, restMatch.index);
2988
+ }
2989
+ const mergedDestructure = baseContent.trimEnd() ? `${baseContent.trimEnd()}, ${additionalAttrs}${restPart}` : `${additionalAttrs}${restPart}`;
2990
+ const braceEnd = source.indexOf("}", existingPropsStart + 5);
2991
+ if (braceEnd !== -1) {
2992
+ s.overwrite(existingPropsStart + 5, braceEnd, ` ${mergedDestructure} `);
2993
+ }
2994
+ const wrapper = generateReactiveAttrsWrapper(schema.attrs);
2995
+ s.overwrite(startIndex, endIndex, `let ${varName} = __attrsFor(${factoryName}, ${wrapper})`);
2996
+ transformed = true;
2997
+ } else {
2998
+ const propsDestructure = generatePropsDestructuring(schema.attrs, factoryName);
2999
+ const wrapper = generateReactiveAttrsWrapper(schema.attrs);
3000
+ const expansion = [
3001
+ propsDestructure,
3002
+ `let ${varName} = __attrsFor(${factoryName}, ${wrapper})`
3003
+ ].join(`
3004
+ `);
3005
+ s.overwrite(startIndex, endIndex, expansion);
3006
+ transformed = true;
3007
+ }
3008
+ }
3009
+ }
3010
+ }
3011
+ if (!transformed) {
3012
+ if (existingPropsMatch && existingPropsStart !== -1) {
3013
+ if (!restVarName) {
3014
+ restVarName = "___restAttrs";
3015
+ const newDestructure = existingDestructureContent.trimEnd() ? `${existingDestructureContent.trimEnd()}, ...${restVarName}` : `...${restVarName}`;
3016
+ const braceEnd = source.indexOf("}", existingPropsStart + 5);
3017
+ if (braceEnd !== -1) {
3018
+ s.overwrite(existingPropsStart + 5, braceEnd, ` ${newDestructure} `);
3019
+ }
3020
+ }
3021
+ s.overwrite(startIndex, endIndex, `let ${varName} = __attrsFor(${factoryName}, ${restVarName})`);
3022
+ } else {
3023
+ const expansion = [
3024
+ `let ___attrs: $attrs.Of<typeof ${factoryName}> = $props()`,
3025
+ `let ${varName} = __attrsFor(${factoryName}, ___attrs)`
3026
+ ].join(`
3027
+ `);
3028
+ s.overwrite(startIndex, endIndex, expansion);
3029
+ }
3030
+ }
3031
+ neededImports.add("__attrsFor");
3032
+ }
3033
+ changed = true;
3034
+ }
3035
+ return changed;
3036
+ }
2905
3037
 
2906
3038
  // src/transform/core.ts
2907
3039
  function transformScript(source, options = {}) {
@@ -2927,7 +3059,7 @@ function transformScript(source, options = {}) {
2927
3059
  propsTypeDeclaration = result.propsTypeDeclaration;
2928
3060
  }
2929
3061
  if (isComponent) {
2930
- changed = transformAttrsForCalls(s, source, neededImports) || changed;
3062
+ changed = transformAttrsForCallsSync(s, source, neededImports) || changed;
2931
3063
  }
2932
3064
  const needsPropsInjection = propsTypeDeclaration && propsTypeDeclaration.length > 0;
2933
3065
  if (isComponent && (neededImports.size > 0 || needsPropsInjection)) {
@@ -2998,7 +3130,7 @@ async function transformScriptAsync(source, options) {
2998
3130
  propsTypeDeclaration = result.propsTypeDeclaration;
2999
3131
  }
3000
3132
  if (isComponent) {
3001
- changed = transformAttrsForCalls(s, source, neededImports) || changed;
3133
+ changed = await transformAttrsForCalls(s, source, neededImports, schemaResolver) || changed;
3002
3134
  }
3003
3135
  const needsPropsInjectionAsync = propsTypeDeclaration && propsTypeDeclaration.length > 0;
3004
3136
  if (isComponent && (neededImports.size > 0 || needsPropsInjectionAsync)) {
@@ -3068,7 +3200,7 @@ async function transformScriptContent(source, options) {
3068
3200
  propsTypeDeclaration = result.propsTypeDeclaration;
3069
3201
  }
3070
3202
  if (isComponent) {
3071
- changed = transformAttrsForCalls(s, source, neededImports) || changed;
3203
+ changed = await transformAttrsForCalls(s, source, neededImports, schemaResolver) || changed;
3072
3204
  }
3073
3205
  if (neededImports.size > 0) {
3074
3206
  const importStatement = generateRuntimeImport([...neededImports]);
@@ -3766,15 +3898,53 @@ async function resolveSchema(importPath, exportName, importerId, cache, debug, a
3766
3898
  }
3767
3899
  if (schema.propsRef) {
3768
3900
  const propsRefImportPath = findImportPath(source, schema.propsRef);
3901
+ let propsRefSchema = null;
3769
3902
  if (propsRefImportPath) {
3770
- const propsRefSchema = await resolveAttrsSchema(propsRefImportPath, schema.propsRef, filePath, cache, debug, aliases);
3771
- if (propsRefSchema) {
3903
+ if (debug) {
3904
+ console.log(`[svelte-origin] Resolving propsRef: ${schema.propsRef} from import ${propsRefImportPath}`);
3905
+ }
3906
+ propsRefSchema = await resolveAttrsSchema(propsRefImportPath, schema.propsRef, filePath, cache, debug, aliases);
3907
+ } else {
3908
+ if (debug) {
3909
+ console.log(`[svelte-origin] Resolving propsRef: ${schema.propsRef} from same file`);
3910
+ }
3911
+ propsRefSchema = parseAttrsSchemaFromSource(source, schema.propsRef);
3912
+ if (propsRefSchema && propsRefSchema.parentNames.length > 0) {
3913
+ const resolvedParentAttrs = [];
3914
+ for (const parentName of propsRefSchema.parentNames) {
3915
+ const parentImportPath = findImportPath(source, parentName);
3916
+ let parentSchema = null;
3917
+ if (parentImportPath) {
3918
+ parentSchema = await resolveAttrsSchema(parentImportPath, parentName, filePath, cache, debug, aliases);
3919
+ } else {
3920
+ parentSchema = parseAttrsSchemaFromSource(source, parentName);
3921
+ }
3922
+ if (parentSchema) {
3923
+ for (const attr of parentSchema.attrs) {
3924
+ const existingIndex = resolvedParentAttrs.findIndex((a) => a.key === attr.key);
3925
+ if (existingIndex === -1) {
3926
+ resolvedParentAttrs.push(attr);
3927
+ }
3928
+ }
3929
+ }
3930
+ }
3772
3931
  for (const attr of propsRefSchema.attrs) {
3773
- const existingIndex = mergedAttrs.findIndex((a) => a.key === attr.key);
3774
- if (existingIndex === -1) {
3775
- mergedAttrs.push(attr);
3932
+ const existingIndex = resolvedParentAttrs.findIndex((a) => a.key === attr.key);
3933
+ if (existingIndex !== -1) {
3934
+ resolvedParentAttrs[existingIndex] = attr;
3935
+ } else {
3936
+ resolvedParentAttrs.push(attr);
3776
3937
  }
3777
3938
  }
3939
+ propsRefSchema = { attrs: resolvedParentAttrs, parentNames: propsRefSchema.parentNames };
3940
+ }
3941
+ }
3942
+ if (propsRefSchema) {
3943
+ for (const attr of propsRefSchema.attrs) {
3944
+ const existingIndex = mergedAttrs.findIndex((a) => a.key === attr.key);
3945
+ if (existingIndex === -1) {
3946
+ mergedAttrs.push(attr);
3947
+ }
3778
3948
  }
3779
3949
  }
3780
3950
  }
@@ -2840,7 +2840,34 @@ function getElementTypeImport(element) {
2840
2840
  }
2841
2841
 
2842
2842
  // src/transform/attrs-for-transform.ts
2843
- function transformAttrsForCalls(s, source, neededImports) {
2843
+ function generateReactiveAttrsWrapper(attrs) {
2844
+ const parts = [];
2845
+ for (const attr of attrs) {
2846
+ parts.push(`get ${attr.key}() { return ${attr.key} }`);
2847
+ if (attr.bindable) {
2848
+ parts.push(`set ${attr.key}(v) { ${attr.key} = v }`);
2849
+ }
2850
+ }
2851
+ return `{ ${parts.join(", ")} }`;
2852
+ }
2853
+ function generateAttrsForMerge(attrs) {
2854
+ const parts = [];
2855
+ for (const attr of attrs) {
2856
+ if (attr.bindable) {
2857
+ if (attr.hasDefault) {
2858
+ parts.push(`${attr.key} = $bindable(${attr.defaultValue})`);
2859
+ } else {
2860
+ parts.push(`${attr.key} = $bindable()`);
2861
+ }
2862
+ } else if (attr.hasDefault) {
2863
+ parts.push(`${attr.key} = ${attr.defaultValue}`);
2864
+ } else {
2865
+ parts.push(attr.key);
2866
+ }
2867
+ }
2868
+ return parts.join(", ");
2869
+ }
2870
+ function transformAttrsForCallsSync(s, source, neededImports) {
2844
2871
  let changed = false;
2845
2872
  const existingPropsMatch = source.match(/let\s*\{([^}]*)\}\s*(?::\s*[^=]+)?\s*=\s*\$props\s*\(\s*\)/);
2846
2873
  let restVarName = null;
@@ -2906,6 +2933,111 @@ function transformAttrsForCalls(s, source, neededImports) {
2906
2933
  }
2907
2934
  return changed;
2908
2935
  }
2936
+ async function transformAttrsForCalls(s, source, neededImports, schemaResolver) {
2937
+ let changed = false;
2938
+ const existingPropsMatch = source.match(/let\s*\{([^}]*)\}\s*(?::\s*[^=]+)?\s*=\s*\$props\s*\(\s*\)/);
2939
+ let restVarName = null;
2940
+ let existingPropsStart = -1;
2941
+ let existingDestructureContent = "";
2942
+ if (existingPropsMatch) {
2943
+ existingPropsStart = existingPropsMatch.index;
2944
+ existingDestructureContent = existingPropsMatch[1];
2945
+ const restMatch = existingDestructureContent.match(/\.\.\.\s*(\w+)\s*$/);
2946
+ if (restMatch) {
2947
+ restVarName = restMatch[1];
2948
+ }
2949
+ }
2950
+ const declarations = findVariableDeclarationsWithMacro(source, "$attrs.for");
2951
+ for (const decl of declarations) {
2952
+ const { varName, startIndex, macroOpenParen } = decl;
2953
+ const closeParenIndex = findMatchingBracket(source, macroOpenParen);
2954
+ if (closeParenIndex === -1)
2955
+ continue;
2956
+ const arg = source.slice(macroOpenParen + 1, closeParenIndex).trim();
2957
+ const endIndex = closeParenIndex + 1;
2958
+ const stringMatch = arg.match(/^['"](\w+)['"]$/);
2959
+ if (stringMatch) {
2960
+ const element = stringMatch[1];
2961
+ const typeImport = getElementTypeImport(element);
2962
+ if (existingPropsMatch && existingPropsStart !== -1) {
2963
+ if (!restVarName) {
2964
+ restVarName = "___restAttrs";
2965
+ const newDestructure = existingDestructureContent.trimEnd() ? `${existingDestructureContent.trimEnd()}, ...${restVarName}` : `...${restVarName}`;
2966
+ const braceEnd = source.indexOf("}", existingPropsStart + 5);
2967
+ if (braceEnd !== -1) {
2968
+ s.overwrite(existingPropsStart + 5, braceEnd, ` ${newDestructure} `);
2969
+ }
2970
+ }
2971
+ s.overwrite(startIndex, endIndex, `let ${varName} = ${restVarName} as ${typeImport}`);
2972
+ } else {
2973
+ const expansion = `let { ...${varName} } = $props<${typeImport}>()`;
2974
+ s.overwrite(startIndex, endIndex, expansion);
2975
+ }
2976
+ } else {
2977
+ const factoryName = arg;
2978
+ let transformed = false;
2979
+ if (schemaResolver) {
2980
+ const importPath = findImportPath(source, factoryName);
2981
+ if (importPath) {
2982
+ const schema = await schemaResolver.resolve(importPath, factoryName);
2983
+ if (schema && schema.attrs.length > 0) {
2984
+ if (existingPropsMatch && existingPropsStart !== -1) {
2985
+ const additionalAttrs = generateAttrsForMerge(schema.attrs);
2986
+ const restMatch = existingDestructureContent.match(/,?\s*\.\.\.\s*(\w+)\s*$/);
2987
+ let baseContent = existingDestructureContent;
2988
+ let restPart = "";
2989
+ if (restMatch) {
2990
+ restPart = restMatch[0];
2991
+ baseContent = existingDestructureContent.slice(0, restMatch.index);
2992
+ }
2993
+ const mergedDestructure = baseContent.trimEnd() ? `${baseContent.trimEnd()}, ${additionalAttrs}${restPart}` : `${additionalAttrs}${restPart}`;
2994
+ const braceEnd = source.indexOf("}", existingPropsStart + 5);
2995
+ if (braceEnd !== -1) {
2996
+ s.overwrite(existingPropsStart + 5, braceEnd, ` ${mergedDestructure} `);
2997
+ }
2998
+ const wrapper = generateReactiveAttrsWrapper(schema.attrs);
2999
+ s.overwrite(startIndex, endIndex, `let ${varName} = __attrsFor(${factoryName}, ${wrapper})`);
3000
+ transformed = true;
3001
+ } else {
3002
+ const propsDestructure = generatePropsDestructuring(schema.attrs, factoryName);
3003
+ const wrapper = generateReactiveAttrsWrapper(schema.attrs);
3004
+ const expansion = [
3005
+ propsDestructure,
3006
+ `let ${varName} = __attrsFor(${factoryName}, ${wrapper})`
3007
+ ].join(`
3008
+ `);
3009
+ s.overwrite(startIndex, endIndex, expansion);
3010
+ transformed = true;
3011
+ }
3012
+ }
3013
+ }
3014
+ }
3015
+ if (!transformed) {
3016
+ if (existingPropsMatch && existingPropsStart !== -1) {
3017
+ if (!restVarName) {
3018
+ restVarName = "___restAttrs";
3019
+ const newDestructure = existingDestructureContent.trimEnd() ? `${existingDestructureContent.trimEnd()}, ...${restVarName}` : `...${restVarName}`;
3020
+ const braceEnd = source.indexOf("}", existingPropsStart + 5);
3021
+ if (braceEnd !== -1) {
3022
+ s.overwrite(existingPropsStart + 5, braceEnd, ` ${newDestructure} `);
3023
+ }
3024
+ }
3025
+ s.overwrite(startIndex, endIndex, `let ${varName} = __attrsFor(${factoryName}, ${restVarName})`);
3026
+ } else {
3027
+ const expansion = [
3028
+ `let ___attrs: $attrs.Of<typeof ${factoryName}> = $props()`,
3029
+ `let ${varName} = __attrsFor(${factoryName}, ___attrs)`
3030
+ ].join(`
3031
+ `);
3032
+ s.overwrite(startIndex, endIndex, expansion);
3033
+ }
3034
+ }
3035
+ neededImports.add("__attrsFor");
3036
+ }
3037
+ changed = true;
3038
+ }
3039
+ return changed;
3040
+ }
2909
3041
 
2910
3042
  // src/transform/core.ts
2911
3043
  function transformScript(source, options = {}) {
@@ -2931,7 +3063,7 @@ function transformScript(source, options = {}) {
2931
3063
  propsTypeDeclaration = result.propsTypeDeclaration;
2932
3064
  }
2933
3065
  if (isComponent) {
2934
- changed = transformAttrsForCalls(s, source, neededImports) || changed;
3066
+ changed = transformAttrsForCallsSync(s, source, neededImports) || changed;
2935
3067
  }
2936
3068
  const needsPropsInjection = propsTypeDeclaration && propsTypeDeclaration.length > 0;
2937
3069
  if (isComponent && (neededImports.size > 0 || needsPropsInjection)) {
@@ -3002,7 +3134,7 @@ async function transformScriptAsync(source, options) {
3002
3134
  propsTypeDeclaration = result.propsTypeDeclaration;
3003
3135
  }
3004
3136
  if (isComponent) {
3005
- changed = transformAttrsForCalls(s, source, neededImports) || changed;
3137
+ changed = await transformAttrsForCalls(s, source, neededImports, schemaResolver) || changed;
3006
3138
  }
3007
3139
  const needsPropsInjectionAsync = propsTypeDeclaration && propsTypeDeclaration.length > 0;
3008
3140
  if (isComponent && (neededImports.size > 0 || needsPropsInjectionAsync)) {
@@ -3072,7 +3204,7 @@ async function transformScriptContent(source, options) {
3072
3204
  propsTypeDeclaration = result.propsTypeDeclaration;
3073
3205
  }
3074
3206
  if (isComponent) {
3075
- changed = transformAttrsForCalls(s, source, neededImports) || changed;
3207
+ changed = await transformAttrsForCalls(s, source, neededImports, schemaResolver) || changed;
3076
3208
  }
3077
3209
  if (neededImports.size > 0) {
3078
3210
  const importStatement = generateRuntimeImport([...neededImports]);
@@ -2836,7 +2836,34 @@ function getElementTypeImport(element) {
2836
2836
  }
2837
2837
 
2838
2838
  // src/transform/attrs-for-transform.ts
2839
- function transformAttrsForCalls(s, source, neededImports) {
2839
+ function generateReactiveAttrsWrapper(attrs) {
2840
+ const parts = [];
2841
+ for (const attr of attrs) {
2842
+ parts.push(`get ${attr.key}() { return ${attr.key} }`);
2843
+ if (attr.bindable) {
2844
+ parts.push(`set ${attr.key}(v) { ${attr.key} = v }`);
2845
+ }
2846
+ }
2847
+ return `{ ${parts.join(", ")} }`;
2848
+ }
2849
+ function generateAttrsForMerge(attrs) {
2850
+ const parts = [];
2851
+ for (const attr of attrs) {
2852
+ if (attr.bindable) {
2853
+ if (attr.hasDefault) {
2854
+ parts.push(`${attr.key} = $bindable(${attr.defaultValue})`);
2855
+ } else {
2856
+ parts.push(`${attr.key} = $bindable()`);
2857
+ }
2858
+ } else if (attr.hasDefault) {
2859
+ parts.push(`${attr.key} = ${attr.defaultValue}`);
2860
+ } else {
2861
+ parts.push(attr.key);
2862
+ }
2863
+ }
2864
+ return parts.join(", ");
2865
+ }
2866
+ function transformAttrsForCallsSync(s, source, neededImports) {
2840
2867
  let changed = false;
2841
2868
  const existingPropsMatch = source.match(/let\s*\{([^}]*)\}\s*(?::\s*[^=]+)?\s*=\s*\$props\s*\(\s*\)/);
2842
2869
  let restVarName = null;
@@ -2902,6 +2929,111 @@ function transformAttrsForCalls(s, source, neededImports) {
2902
2929
  }
2903
2930
  return changed;
2904
2931
  }
2932
+ async function transformAttrsForCalls(s, source, neededImports, schemaResolver) {
2933
+ let changed = false;
2934
+ const existingPropsMatch = source.match(/let\s*\{([^}]*)\}\s*(?::\s*[^=]+)?\s*=\s*\$props\s*\(\s*\)/);
2935
+ let restVarName = null;
2936
+ let existingPropsStart = -1;
2937
+ let existingDestructureContent = "";
2938
+ if (existingPropsMatch) {
2939
+ existingPropsStart = existingPropsMatch.index;
2940
+ existingDestructureContent = existingPropsMatch[1];
2941
+ const restMatch = existingDestructureContent.match(/\.\.\.\s*(\w+)\s*$/);
2942
+ if (restMatch) {
2943
+ restVarName = restMatch[1];
2944
+ }
2945
+ }
2946
+ const declarations = findVariableDeclarationsWithMacro(source, "$attrs.for");
2947
+ for (const decl of declarations) {
2948
+ const { varName, startIndex, macroOpenParen } = decl;
2949
+ const closeParenIndex = findMatchingBracket(source, macroOpenParen);
2950
+ if (closeParenIndex === -1)
2951
+ continue;
2952
+ const arg = source.slice(macroOpenParen + 1, closeParenIndex).trim();
2953
+ const endIndex = closeParenIndex + 1;
2954
+ const stringMatch = arg.match(/^['"](\w+)['"]$/);
2955
+ if (stringMatch) {
2956
+ const element = stringMatch[1];
2957
+ const typeImport = getElementTypeImport(element);
2958
+ if (existingPropsMatch && existingPropsStart !== -1) {
2959
+ if (!restVarName) {
2960
+ restVarName = "___restAttrs";
2961
+ const newDestructure = existingDestructureContent.trimEnd() ? `${existingDestructureContent.trimEnd()}, ...${restVarName}` : `...${restVarName}`;
2962
+ const braceEnd = source.indexOf("}", existingPropsStart + 5);
2963
+ if (braceEnd !== -1) {
2964
+ s.overwrite(existingPropsStart + 5, braceEnd, ` ${newDestructure} `);
2965
+ }
2966
+ }
2967
+ s.overwrite(startIndex, endIndex, `let ${varName} = ${restVarName} as ${typeImport}`);
2968
+ } else {
2969
+ const expansion = `let { ...${varName} } = $props<${typeImport}>()`;
2970
+ s.overwrite(startIndex, endIndex, expansion);
2971
+ }
2972
+ } else {
2973
+ const factoryName = arg;
2974
+ let transformed = false;
2975
+ if (schemaResolver) {
2976
+ const importPath = findImportPath(source, factoryName);
2977
+ if (importPath) {
2978
+ const schema = await schemaResolver.resolve(importPath, factoryName);
2979
+ if (schema && schema.attrs.length > 0) {
2980
+ if (existingPropsMatch && existingPropsStart !== -1) {
2981
+ const additionalAttrs = generateAttrsForMerge(schema.attrs);
2982
+ const restMatch = existingDestructureContent.match(/,?\s*\.\.\.\s*(\w+)\s*$/);
2983
+ let baseContent = existingDestructureContent;
2984
+ let restPart = "";
2985
+ if (restMatch) {
2986
+ restPart = restMatch[0];
2987
+ baseContent = existingDestructureContent.slice(0, restMatch.index);
2988
+ }
2989
+ const mergedDestructure = baseContent.trimEnd() ? `${baseContent.trimEnd()}, ${additionalAttrs}${restPart}` : `${additionalAttrs}${restPart}`;
2990
+ const braceEnd = source.indexOf("}", existingPropsStart + 5);
2991
+ if (braceEnd !== -1) {
2992
+ s.overwrite(existingPropsStart + 5, braceEnd, ` ${mergedDestructure} `);
2993
+ }
2994
+ const wrapper = generateReactiveAttrsWrapper(schema.attrs);
2995
+ s.overwrite(startIndex, endIndex, `let ${varName} = __attrsFor(${factoryName}, ${wrapper})`);
2996
+ transformed = true;
2997
+ } else {
2998
+ const propsDestructure = generatePropsDestructuring(schema.attrs, factoryName);
2999
+ const wrapper = generateReactiveAttrsWrapper(schema.attrs);
3000
+ const expansion = [
3001
+ propsDestructure,
3002
+ `let ${varName} = __attrsFor(${factoryName}, ${wrapper})`
3003
+ ].join(`
3004
+ `);
3005
+ s.overwrite(startIndex, endIndex, expansion);
3006
+ transformed = true;
3007
+ }
3008
+ }
3009
+ }
3010
+ }
3011
+ if (!transformed) {
3012
+ if (existingPropsMatch && existingPropsStart !== -1) {
3013
+ if (!restVarName) {
3014
+ restVarName = "___restAttrs";
3015
+ const newDestructure = existingDestructureContent.trimEnd() ? `${existingDestructureContent.trimEnd()}, ...${restVarName}` : `...${restVarName}`;
3016
+ const braceEnd = source.indexOf("}", existingPropsStart + 5);
3017
+ if (braceEnd !== -1) {
3018
+ s.overwrite(existingPropsStart + 5, braceEnd, ` ${newDestructure} `);
3019
+ }
3020
+ }
3021
+ s.overwrite(startIndex, endIndex, `let ${varName} = __attrsFor(${factoryName}, ${restVarName})`);
3022
+ } else {
3023
+ const expansion = [
3024
+ `let ___attrs: $attrs.Of<typeof ${factoryName}> = $props()`,
3025
+ `let ${varName} = __attrsFor(${factoryName}, ___attrs)`
3026
+ ].join(`
3027
+ `);
3028
+ s.overwrite(startIndex, endIndex, expansion);
3029
+ }
3030
+ }
3031
+ neededImports.add("__attrsFor");
3032
+ }
3033
+ changed = true;
3034
+ }
3035
+ return changed;
3036
+ }
2905
3037
 
2906
3038
  // src/transform/core.ts
2907
3039
  function transformScript(source, options = {}) {
@@ -2927,7 +3059,7 @@ function transformScript(source, options = {}) {
2927
3059
  propsTypeDeclaration = result.propsTypeDeclaration;
2928
3060
  }
2929
3061
  if (isComponent) {
2930
- changed = transformAttrsForCalls(s, source, neededImports) || changed;
3062
+ changed = transformAttrsForCallsSync(s, source, neededImports) || changed;
2931
3063
  }
2932
3064
  const needsPropsInjection = propsTypeDeclaration && propsTypeDeclaration.length > 0;
2933
3065
  if (isComponent && (neededImports.size > 0 || needsPropsInjection)) {
@@ -2998,7 +3130,7 @@ async function transformScriptAsync(source, options) {
2998
3130
  propsTypeDeclaration = result.propsTypeDeclaration;
2999
3131
  }
3000
3132
  if (isComponent) {
3001
- changed = transformAttrsForCalls(s, source, neededImports) || changed;
3133
+ changed = await transformAttrsForCalls(s, source, neededImports, schemaResolver) || changed;
3002
3134
  }
3003
3135
  const needsPropsInjectionAsync = propsTypeDeclaration && propsTypeDeclaration.length > 0;
3004
3136
  if (isComponent && (neededImports.size > 0 || needsPropsInjectionAsync)) {
@@ -3068,7 +3200,7 @@ async function transformScriptContent(source, options) {
3068
3200
  propsTypeDeclaration = result.propsTypeDeclaration;
3069
3201
  }
3070
3202
  if (isComponent) {
3071
- changed = transformAttrsForCalls(s, source, neededImports) || changed;
3203
+ changed = await transformAttrsForCalls(s, source, neededImports, schemaResolver) || changed;
3072
3204
  }
3073
3205
  if (neededImports.size > 0) {
3074
3206
  const importStatement = generateRuntimeImport([...neededImports]);
@@ -3565,20 +3697,55 @@ async function resolveSchema(importPath, exportName, importerId, cache, debug, a
3565
3697
  }
3566
3698
  if (schema.propsRef) {
3567
3699
  const propsRefImportPath = findImportPath(source, schema.propsRef);
3700
+ let propsRefSchema = null;
3568
3701
  if (propsRefImportPath) {
3569
3702
  if (debug) {
3570
- console.log(`[svelte-origin-preprocess] Resolving propsRef: ${schema.propsRef} from ${propsRefImportPath}`);
3703
+ console.log(`[svelte-origin-preprocess] Resolving propsRef: ${schema.propsRef} from import ${propsRefImportPath}`);
3704
+ }
3705
+ propsRefSchema = await resolveAttrsSchema(propsRefImportPath, schema.propsRef, filePath, cache, debug, aliases);
3706
+ } else {
3707
+ if (debug) {
3708
+ console.log(`[svelte-origin-preprocess] Resolving propsRef: ${schema.propsRef} from same file`);
3571
3709
  }
3572
- const propsRefSchema = await resolveAttrsSchema(propsRefImportPath, schema.propsRef, filePath, cache, debug, aliases);
3573
- if (propsRefSchema) {
3710
+ propsRefSchema = parseAttrsSchemaFromSource(source, schema.propsRef);
3711
+ if (propsRefSchema && propsRefSchema.parentNames.length > 0) {
3712
+ const resolvedParentAttrs = [];
3713
+ for (const parentName of propsRefSchema.parentNames) {
3714
+ const parentImportPath = findImportPath(source, parentName);
3715
+ let parentSchema = null;
3716
+ if (parentImportPath) {
3717
+ parentSchema = await resolveAttrsSchema(parentImportPath, parentName, filePath, cache, debug, aliases);
3718
+ } else {
3719
+ parentSchema = parseAttrsSchemaFromSource(source, parentName);
3720
+ }
3721
+ if (parentSchema) {
3722
+ for (const attr of parentSchema.attrs) {
3723
+ const existingIndex = resolvedParentAttrs.findIndex((a) => a.key === attr.key);
3724
+ if (existingIndex === -1) {
3725
+ resolvedParentAttrs.push(attr);
3726
+ }
3727
+ }
3728
+ }
3729
+ }
3574
3730
  for (const attr of propsRefSchema.attrs) {
3575
- const existingIndex = mergedAttrs.findIndex((a) => a.key === attr.key);
3576
- if (existingIndex === -1) {
3577
- mergedAttrs.push(attr);
3731
+ const existingIndex = resolvedParentAttrs.findIndex((a) => a.key === attr.key);
3732
+ if (existingIndex !== -1) {
3733
+ resolvedParentAttrs[existingIndex] = attr;
3578
3734
  } else {
3579
- mergedAttrs[existingIndex] = attr;
3735
+ resolvedParentAttrs.push(attr);
3580
3736
  }
3581
3737
  }
3738
+ propsRefSchema = { attrs: resolvedParentAttrs, parentNames: propsRefSchema.parentNames };
3739
+ }
3740
+ }
3741
+ if (propsRefSchema) {
3742
+ for (const attr of propsRefSchema.attrs) {
3743
+ const existingIndex = mergedAttrs.findIndex((a) => a.key === attr.key);
3744
+ if (existingIndex === -1) {
3745
+ mergedAttrs.push(attr);
3746
+ } else {
3747
+ mergedAttrs[existingIndex] = attr;
3748
+ }
3582
3749
  }
3583
3750
  }
3584
3751
  }
@@ -3473,34 +3473,22 @@ function __attrsFor(factory, rawAttrs) {
3473
3473
  const factoryWithSchema = factory;
3474
3474
  const schema = getMergedAttrSchema(factoryWithSchema);
3475
3475
  const wrapper = {};
3476
- const localValues = {};
3477
- const hasLocalValue = {};
3478
3476
  const defineExposedProp = (key2, info) => {
3479
3477
  if (Object.prototype.hasOwnProperty.call(wrapper, key2))
3480
3478
  return;
3481
- const base = {
3479
+ const descriptor = {
3482
3480
  get() {
3483
- if (hasLocalValue[key2])
3484
- return localValues[key2];
3485
3481
  return rawAttrs[key2];
3486
3482
  },
3487
3483
  enumerable: true,
3488
3484
  configurable: true
3489
3485
  };
3490
3486
  if (info.bindable) {
3491
- Object.defineProperty(wrapper, key2, {
3492
- ...base,
3493
- set(value) {
3494
- localValues[key2] = value;
3495
- hasLocalValue[key2] = true;
3496
- try {
3497
- rawAttrs[key2] = value;
3498
- } catch {}
3499
- }
3500
- });
3501
- } else {
3502
- Object.defineProperty(wrapper, key2, base);
3487
+ descriptor.set = function(value) {
3488
+ rawAttrs[key2] = value;
3489
+ };
3503
3490
  }
3491
+ Object.defineProperty(wrapper, key2, descriptor);
3504
3492
  };
3505
3493
  for (const [key2, info] of Object.entries(schema)) {
3506
3494
  const parentValue = rawAttrs[key2];
@@ -3521,8 +3509,6 @@ function __attrsFor(factory, rawAttrs) {
3521
3509
  return new Proxy(wrapper, {
3522
3510
  get(target, prop2) {
3523
3511
  if (typeof prop2 === "string" && prop2 in schema) {
3524
- if (hasLocalValue[prop2])
3525
- return localValues[prop2];
3526
3512
  return rawAttrs[prop2];
3527
3513
  }
3528
3514
  if (prop2 in target)
@@ -3531,15 +3517,11 @@ function __attrsFor(factory, rawAttrs) {
3531
3517
  },
3532
3518
  set(target, prop2, value) {
3533
3519
  if (typeof prop2 === "string" && prop2 in schema) {
3534
- localValues[prop2] = value;
3535
- hasLocalValue[prop2] = true;
3536
3520
  if (!Object.prototype.hasOwnProperty.call(wrapper, prop2)) {
3537
3521
  defineExposedProp(prop2, schema[prop2]);
3538
3522
  }
3539
3523
  if (schema[prop2].bindable) {
3540
- try {
3541
- rawAttrs[prop2] = value;
3542
- } catch {}
3524
+ rawAttrs[prop2] = value;
3543
3525
  }
3544
3526
  return true;
3545
3527
  }
@@ -3551,18 +3533,10 @@ function __attrsFor(factory, rawAttrs) {
3551
3533
  }
3552
3534
  try {
3553
3535
  rawAttrs[prop2] = value;
3554
- } catch {
3555
- if (typeof prop2 === "string") {
3556
- localValues[prop2] = value;
3557
- hasLocalValue[prop2] = true;
3558
- }
3559
- }
3536
+ } catch {}
3560
3537
  return true;
3561
3538
  },
3562
3539
  has(target, prop2) {
3563
- if (typeof prop2 === "string" && prop2 in schema) {
3564
- return prop2 in target || hasLocalValue[prop2];
3565
- }
3566
3540
  return prop2 in target || prop2 in rawAttrs;
3567
3541
  },
3568
3542
  ownKeys() {
@@ -6,12 +6,13 @@
6
6
  * - $attrs.for('input') - get typed element attrs
7
7
  */
8
8
  import type MagicString from 'magic-string';
9
+ import { type SchemaResolver } from './schema';
9
10
  /**
10
- * Transform $attrs.for(X) calls.
11
- * Handles both origin factories ($attrs.for(OriginFactory)) and element names ($attrs.for('input'))
11
+ * Transform $attrs.for(X) calls (sync fallback version).
12
12
  *
13
- * If $props() already exists, we extend the existing destructuring with rest syntax.
14
- * Otherwise, we generate a new $props() call.
13
+ * This version always uses the fallback approach since no schema resolver is provided.
14
+ * Fallback generates a raw $props() proxy which does NOT support two-way binding
15
+ * through parent components (the props proxy is read-only for non-destructured props).
15
16
  *
16
17
  * Supports all TypeScript declaration patterns:
17
18
  * - let x = $attrs.for(Factory)
@@ -21,4 +22,34 @@ import type MagicString from 'magic-string';
21
22
  * - export let x = $attrs.for(Factory)
22
23
  * - export const x: Type = $attrs.for('input')
23
24
  */
24
- export declare function transformAttrsForCalls(s: MagicString, source: string, neededImports: Set<string>): boolean;
25
+ export declare function transformAttrsForCallsSync(s: MagicString, source: string, neededImports: Set<string>): boolean;
26
+ /**
27
+ * Transform $attrs.for(X) calls (async version with schema resolution).
28
+ *
29
+ * When schema is available via static resolution:
30
+ * ```svelte
31
+ * let childAttrs = $attrs.for(Counter)
32
+ * ```
33
+ * Becomes:
34
+ * ```svelte
35
+ * let { label = 'Counter', count = $bindable(0), step = 1 }: $attrs.Of<typeof Counter> = $props()
36
+ * let childAttrs = __attrsFor(Counter, { get label() { return label }, get count() { return count }, set count(v) { count = v }, get step() { return step } })
37
+ * ```
38
+ *
39
+ * This approach works because:
40
+ * 1. Props are destructured with $bindable(), making them writable
41
+ * 2. The getter/setter wrapper passes reactive accessors to __attrsFor
42
+ * 3. When child components update bindable props, the setters propagate changes back
43
+ *
44
+ * Fallback (when schema isn't statically known):
45
+ * ```svelte
46
+ * let ___attrs: $attrs.Of<typeof Counter> = $props()
47
+ * let childAttrs = __attrsFor(Counter, ___attrs)
48
+ * ```
49
+ *
50
+ * @param s MagicString instance for source manipulation
51
+ * @param source Original source code
52
+ * @param neededImports Set to track required runtime imports
53
+ * @param schemaResolver Optional resolver for static schema extraction
54
+ */
55
+ export declare function transformAttrsForCalls(s: MagicString, source: string, neededImports: Set<string>, schemaResolver?: SchemaResolver): Promise<boolean>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "svelte-origin",
3
- "version": "1.0.0-next.22",
3
+ "version": "1.0.0-next.23",
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",