svelte-origin 1.0.0-next.21 → 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.
Potentially problematic release.
This version of svelte-origin might be problematic. Click here for more details.
- package/dist/cli.js +233 -6
- package/dist/index.js +240 -39
- package/dist/plugin.js +354 -6
- package/dist/post-process.js +233 -6
- package/dist/preprocess.js +356 -6
- package/dist/runtime/index.js +7 -33
- package/dist/transform/attrs-for-transform.d.ts +36 -5
- package/dist/transform/schema.d.ts +17 -0
- package/dist/vite-dts.js +77 -1
- package/package.json +1 -1
package/dist/preprocess.js
CHANGED
|
@@ -1969,6 +1969,7 @@ function transformOriginDefinition(content, svelteImports) {
|
|
|
1969
1969
|
let attrsContent = "";
|
|
1970
1970
|
let contentWithoutAttrs = bodyContent;
|
|
1971
1971
|
let attrPropertyName = "props";
|
|
1972
|
+
let propsRef = null;
|
|
1972
1973
|
if (attrsMatch) {
|
|
1973
1974
|
attrPropertyName = attrsMatch[1];
|
|
1974
1975
|
const attrsStart = attrsMatch.index;
|
|
@@ -1999,13 +2000,31 @@ function transformOriginDefinition(content, svelteImports) {
|
|
|
1999
2000
|
}
|
|
2000
2001
|
contentWithoutAttrs = bodyContent.slice(0, attrsStart) + bodyContent.slice(cutEnd);
|
|
2001
2002
|
}
|
|
2003
|
+
} else {
|
|
2004
|
+
const externalRefMatch = bodyContent.match(/(\w+)\s*:\s*(\w+)\s*,/);
|
|
2005
|
+
if (externalRefMatch) {
|
|
2006
|
+
const propName = externalRefMatch[1];
|
|
2007
|
+
const refName = externalRefMatch[2];
|
|
2008
|
+
if ((propName === "props" || propName === "attrs") && /^[A-Z]/.test(refName) && !["$state", "$derived", "$effect", "$bindable"].includes(refName)) {
|
|
2009
|
+
attrPropertyName = propName;
|
|
2010
|
+
propsRef = refName;
|
|
2011
|
+
const refStart = externalRefMatch.index;
|
|
2012
|
+
const refEnd = refStart + externalRefMatch[0].length;
|
|
2013
|
+
contentWithoutAttrs = bodyContent.slice(0, refStart) + bodyContent.slice(refEnd);
|
|
2014
|
+
}
|
|
2015
|
+
}
|
|
2002
2016
|
}
|
|
2003
2017
|
const attrDetails = parseAttrsSource(attrsContent);
|
|
2004
2018
|
const { body: createFnBody, attachments } = transformOriginBody(contentWithoutAttrs.trim(), parents, attrDetails, attrPropertyName, svelteImports);
|
|
2005
2019
|
const parentsCode = parents.length > 0 ? `[${parents.join(", ")}]` : "undefined";
|
|
2006
2020
|
let configCode = `{
|
|
2007
2021
|
__attrSchema: ${attrSchemaCode},
|
|
2008
|
-
__parents: ${parentsCode}
|
|
2022
|
+
__parents: ${parentsCode},`;
|
|
2023
|
+
if (propsRef) {
|
|
2024
|
+
configCode += `
|
|
2025
|
+
__propsRef: ${propsRef},`;
|
|
2026
|
+
}
|
|
2027
|
+
configCode += `
|
|
2009
2028
|
__create: (__inputAttrs${parents.length > 0 ? ", __super" : ""}) => {
|
|
2010
2029
|
${createFnBody}
|
|
2011
2030
|
}`;
|
|
@@ -2240,6 +2259,73 @@ function parseOriginSchemaFromSource(source, exportName) {
|
|
|
2240
2259
|
return compiledResult;
|
|
2241
2260
|
return null;
|
|
2242
2261
|
}
|
|
2262
|
+
function parseAttrsSchemaFromSource(source, exportName) {
|
|
2263
|
+
const sourceResult = parseSourceAttrs(source, exportName);
|
|
2264
|
+
if (sourceResult)
|
|
2265
|
+
return sourceResult;
|
|
2266
|
+
const compiledResult = parseCompiledAttrs(source, exportName);
|
|
2267
|
+
if (compiledResult)
|
|
2268
|
+
return compiledResult;
|
|
2269
|
+
return null;
|
|
2270
|
+
}
|
|
2271
|
+
function parseSourceAttrs(source, exportName) {
|
|
2272
|
+
const exportPattern = new RegExp(`export\\s+(?:const|var|let)\\s+${exportName}\\s*=\\s*\\$attrs\\s*\\(`, "s");
|
|
2273
|
+
const match = exportPattern.exec(source);
|
|
2274
|
+
if (!match)
|
|
2275
|
+
return null;
|
|
2276
|
+
const attrsStart = match.index + match[0].length - 1;
|
|
2277
|
+
const attrsEnd = findMatchingBracket(source, attrsStart);
|
|
2278
|
+
if (attrsEnd === -1)
|
|
2279
|
+
return null;
|
|
2280
|
+
let attrsContent = source.slice(attrsStart + 1, attrsEnd).trim();
|
|
2281
|
+
let parentNames = [];
|
|
2282
|
+
if (attrsContent.startsWith("[")) {
|
|
2283
|
+
const closeBracket = findMatchingBracket(attrsContent, 0, "[", "]");
|
|
2284
|
+
if (closeBracket !== -1) {
|
|
2285
|
+
const parentsContent = attrsContent.slice(1, closeBracket);
|
|
2286
|
+
parentNames = parentsContent.split(",").map((p) => p.trim()).filter((p) => p && /^\w+$/.test(p));
|
|
2287
|
+
let i = closeBracket + 1;
|
|
2288
|
+
while (i < attrsContent.length && /[\s,]/.test(attrsContent[i]))
|
|
2289
|
+
i++;
|
|
2290
|
+
attrsContent = attrsContent.slice(i);
|
|
2291
|
+
}
|
|
2292
|
+
}
|
|
2293
|
+
if (!attrsContent.startsWith("{")) {
|
|
2294
|
+
return { attrs: [], parentNames };
|
|
2295
|
+
}
|
|
2296
|
+
const objEnd = findMatchingBracket(attrsContent, 0, "{", "}");
|
|
2297
|
+
if (objEnd === -1)
|
|
2298
|
+
return { attrs: [], parentNames };
|
|
2299
|
+
const objContent = attrsContent.slice(1, objEnd);
|
|
2300
|
+
const attrs = parseAttrsContent(objContent);
|
|
2301
|
+
return { attrs, parentNames };
|
|
2302
|
+
}
|
|
2303
|
+
function parseCompiledAttrs(source, exportName) {
|
|
2304
|
+
const exportPattern = new RegExp(`export\\s+(?:const|var|let)\\s+${exportName}\\s*=\\s*__createAttrs\\s*\\(\\s*\\{`, "s");
|
|
2305
|
+
const match = exportPattern.exec(source);
|
|
2306
|
+
if (!match)
|
|
2307
|
+
return null;
|
|
2308
|
+
const braceStart = match.index + match[0].length - 1;
|
|
2309
|
+
const braceEnd = findMatchingBracket(source, braceStart, "{", "}");
|
|
2310
|
+
if (braceEnd === -1)
|
|
2311
|
+
return null;
|
|
2312
|
+
const configContent = source.slice(braceStart + 1, braceEnd);
|
|
2313
|
+
const schemaMatch = configContent.match(/__attrSchema\s*:\s*\{/);
|
|
2314
|
+
if (!schemaMatch)
|
|
2315
|
+
return { attrs: [], parentNames: [] };
|
|
2316
|
+
const schemaStart = schemaMatch.index + schemaMatch[0].length - 1;
|
|
2317
|
+
const schemaEnd = findMatchingBracket(configContent, schemaStart, "{", "}");
|
|
2318
|
+
if (schemaEnd === -1)
|
|
2319
|
+
return { attrs: [], parentNames: [] };
|
|
2320
|
+
const schemaContent = configContent.slice(schemaStart + 1, schemaEnd);
|
|
2321
|
+
const attrs = parseCompiledAttrSchema(schemaContent);
|
|
2322
|
+
const parentsMatch = configContent.match(/__parents\s*:\s*\[([^\]]*)\]/);
|
|
2323
|
+
let parentNames = [];
|
|
2324
|
+
if (parentsMatch && parentsMatch[1].trim()) {
|
|
2325
|
+
parentNames = parentsMatch[1].split(",").map((p) => p.trim()).filter((p) => p && /^\w+$/.test(p));
|
|
2326
|
+
}
|
|
2327
|
+
return { attrs, parentNames };
|
|
2328
|
+
}
|
|
2243
2329
|
function parseSourceOrigin(source, exportName) {
|
|
2244
2330
|
const exportPattern = new RegExp(`export\\s+(?:const|var|let)\\s+${exportName}\\s*=\\s*\\$origin\\s*\\(`, "s");
|
|
2245
2331
|
const match = exportPattern.exec(source);
|
|
@@ -2265,6 +2351,13 @@ function parseSourceOrigin(source, exportName) {
|
|
|
2265
2351
|
}
|
|
2266
2352
|
const attrsMatch = bodyContent.match(/(\w+)\s*:\s*\$attrs\s*\(\s*\{/);
|
|
2267
2353
|
if (!attrsMatch) {
|
|
2354
|
+
const externalRefMatch = bodyContent.match(/(?:props|attrs)\s*:\s*([A-Z]\w*)\b/);
|
|
2355
|
+
if (externalRefMatch) {
|
|
2356
|
+
const propsRef = externalRefMatch[1];
|
|
2357
|
+
if (!["Object", "Array", "String", "Number", "Boolean"].includes(propsRef)) {
|
|
2358
|
+
return { attrs: [], parentNames, propsRef };
|
|
2359
|
+
}
|
|
2360
|
+
}
|
|
2268
2361
|
return { attrs: [], parentNames };
|
|
2269
2362
|
}
|
|
2270
2363
|
const attrsStart = attrsMatch.index;
|
|
@@ -2301,7 +2394,9 @@ function parseCompiledOrigin(source, exportName) {
|
|
|
2301
2394
|
if (parentsMatch && parentsMatch[1].trim()) {
|
|
2302
2395
|
parentNames = parentsMatch[1].split(",").map((p) => p.trim()).filter((p) => p && /^\w+$/.test(p));
|
|
2303
2396
|
}
|
|
2304
|
-
|
|
2397
|
+
const propsRefMatch = configContent.match(/__propsRef\s*:\s*(\w+)/);
|
|
2398
|
+
const propsRef = propsRefMatch ? propsRefMatch[1] : undefined;
|
|
2399
|
+
return { attrs, parentNames, propsRef };
|
|
2305
2400
|
}
|
|
2306
2401
|
function parseCompiledAttrSchema(content) {
|
|
2307
2402
|
const result = [];
|
|
@@ -2741,7 +2836,34 @@ function getElementTypeImport(element) {
|
|
|
2741
2836
|
}
|
|
2742
2837
|
|
|
2743
2838
|
// src/transform/attrs-for-transform.ts
|
|
2744
|
-
function
|
|
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) {
|
|
2745
2867
|
let changed = false;
|
|
2746
2868
|
const existingPropsMatch = source.match(/let\s*\{([^}]*)\}\s*(?::\s*[^=]+)?\s*=\s*\$props\s*\(\s*\)/);
|
|
2747
2869
|
let restVarName = null;
|
|
@@ -2807,6 +2929,111 @@ function transformAttrsForCalls(s, source, neededImports) {
|
|
|
2807
2929
|
}
|
|
2808
2930
|
return changed;
|
|
2809
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
|
+
}
|
|
2810
3037
|
|
|
2811
3038
|
// src/transform/core.ts
|
|
2812
3039
|
function transformScript(source, options = {}) {
|
|
@@ -2832,7 +3059,7 @@ function transformScript(source, options = {}) {
|
|
|
2832
3059
|
propsTypeDeclaration = result.propsTypeDeclaration;
|
|
2833
3060
|
}
|
|
2834
3061
|
if (isComponent) {
|
|
2835
|
-
changed =
|
|
3062
|
+
changed = transformAttrsForCallsSync(s, source, neededImports) || changed;
|
|
2836
3063
|
}
|
|
2837
3064
|
const needsPropsInjection = propsTypeDeclaration && propsTypeDeclaration.length > 0;
|
|
2838
3065
|
if (isComponent && (neededImports.size > 0 || needsPropsInjection)) {
|
|
@@ -2903,7 +3130,7 @@ async function transformScriptAsync(source, options) {
|
|
|
2903
3130
|
propsTypeDeclaration = result.propsTypeDeclaration;
|
|
2904
3131
|
}
|
|
2905
3132
|
if (isComponent) {
|
|
2906
|
-
changed = transformAttrsForCalls(s, source, neededImports) || changed;
|
|
3133
|
+
changed = await transformAttrsForCalls(s, source, neededImports, schemaResolver) || changed;
|
|
2907
3134
|
}
|
|
2908
3135
|
const needsPropsInjectionAsync = propsTypeDeclaration && propsTypeDeclaration.length > 0;
|
|
2909
3136
|
if (isComponent && (neededImports.size > 0 || needsPropsInjectionAsync)) {
|
|
@@ -2973,7 +3200,7 @@ async function transformScriptContent(source, options) {
|
|
|
2973
3200
|
propsTypeDeclaration = result.propsTypeDeclaration;
|
|
2974
3201
|
}
|
|
2975
3202
|
if (isComponent) {
|
|
2976
|
-
changed = transformAttrsForCalls(s, source, neededImports) || changed;
|
|
3203
|
+
changed = await transformAttrsForCalls(s, source, neededImports, schemaResolver) || changed;
|
|
2977
3204
|
}
|
|
2978
3205
|
if (neededImports.size > 0) {
|
|
2979
3206
|
const importStatement = generateRuntimeImport([...neededImports]);
|
|
@@ -3468,6 +3695,60 @@ async function resolveSchema(importPath, exportName, importerId, cache, debug, a
|
|
|
3468
3695
|
}
|
|
3469
3696
|
}
|
|
3470
3697
|
}
|
|
3698
|
+
if (schema.propsRef) {
|
|
3699
|
+
const propsRefImportPath = findImportPath(source, schema.propsRef);
|
|
3700
|
+
let propsRefSchema = null;
|
|
3701
|
+
if (propsRefImportPath) {
|
|
3702
|
+
if (debug) {
|
|
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`);
|
|
3709
|
+
}
|
|
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
|
+
}
|
|
3730
|
+
for (const attr of propsRefSchema.attrs) {
|
|
3731
|
+
const existingIndex = resolvedParentAttrs.findIndex((a) => a.key === attr.key);
|
|
3732
|
+
if (existingIndex !== -1) {
|
|
3733
|
+
resolvedParentAttrs[existingIndex] = attr;
|
|
3734
|
+
} else {
|
|
3735
|
+
resolvedParentAttrs.push(attr);
|
|
3736
|
+
}
|
|
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
|
+
}
|
|
3749
|
+
}
|
|
3750
|
+
}
|
|
3751
|
+
}
|
|
3471
3752
|
for (const attr of schema.attrs) {
|
|
3472
3753
|
const existingIndex = mergedAttrs.findIndex((a) => a.key === attr.key);
|
|
3473
3754
|
if (existingIndex !== -1) {
|
|
@@ -3493,6 +3774,75 @@ async function resolveSchema(importPath, exportName, importerId, cache, debug, a
|
|
|
3493
3774
|
return null;
|
|
3494
3775
|
}
|
|
3495
3776
|
}
|
|
3777
|
+
async function resolveAttrsSchema(importPath, exportName, importerId, cache, debug, aliases) {
|
|
3778
|
+
const cacheKey = `attrs::${importPath}::${exportName}`;
|
|
3779
|
+
if (cache.has(cacheKey)) {
|
|
3780
|
+
if (debug) {
|
|
3781
|
+
console.log(`[svelte-origin-preprocess] Cache hit for ${cacheKey}`);
|
|
3782
|
+
}
|
|
3783
|
+
return cache.get(cacheKey) || null;
|
|
3784
|
+
}
|
|
3785
|
+
try {
|
|
3786
|
+
const importerDir = dirname2(importerId);
|
|
3787
|
+
if (debug) {
|
|
3788
|
+
console.log(`[svelte-origin-preprocess] Resolving attrs: ${exportName} from ${importPath}`);
|
|
3789
|
+
}
|
|
3790
|
+
const resolvedPath = resolveImportPath(importPath, aliases, importerDir);
|
|
3791
|
+
if (!resolvedPath) {
|
|
3792
|
+
cache.set(cacheKey, null);
|
|
3793
|
+
return null;
|
|
3794
|
+
}
|
|
3795
|
+
const filePath = resolveFilePath(resolvedPath);
|
|
3796
|
+
if (!filePath) {
|
|
3797
|
+
cache.set(cacheKey, null);
|
|
3798
|
+
return null;
|
|
3799
|
+
}
|
|
3800
|
+
const source = readFileSync2(filePath, "utf-8");
|
|
3801
|
+
const schema = parseAttrsSchemaFromSource(source, exportName);
|
|
3802
|
+
if (!schema) {
|
|
3803
|
+
cache.set(cacheKey, null);
|
|
3804
|
+
return null;
|
|
3805
|
+
}
|
|
3806
|
+
const mergedAttrs = [];
|
|
3807
|
+
for (const parentName of schema.parentNames) {
|
|
3808
|
+
const parentImportPath = findImportPath(source, parentName);
|
|
3809
|
+
if (parentImportPath) {
|
|
3810
|
+
const parentSchema = await resolveAttrsSchema(parentImportPath, parentName, filePath, cache, debug, aliases);
|
|
3811
|
+
if (parentSchema) {
|
|
3812
|
+
for (const attr of parentSchema.attrs) {
|
|
3813
|
+
const existingIndex = mergedAttrs.findIndex((a) => a.key === attr.key);
|
|
3814
|
+
if (existingIndex === -1) {
|
|
3815
|
+
mergedAttrs.push(attr);
|
|
3816
|
+
}
|
|
3817
|
+
}
|
|
3818
|
+
}
|
|
3819
|
+
}
|
|
3820
|
+
}
|
|
3821
|
+
for (const attr of schema.attrs) {
|
|
3822
|
+
const existingIndex = mergedAttrs.findIndex((a) => a.key === attr.key);
|
|
3823
|
+
if (existingIndex !== -1) {
|
|
3824
|
+
mergedAttrs[existingIndex] = attr;
|
|
3825
|
+
} else {
|
|
3826
|
+
mergedAttrs.push(attr);
|
|
3827
|
+
}
|
|
3828
|
+
}
|
|
3829
|
+
const mergedSchema = {
|
|
3830
|
+
attrs: mergedAttrs,
|
|
3831
|
+
parentNames: schema.parentNames
|
|
3832
|
+
};
|
|
3833
|
+
if (debug) {
|
|
3834
|
+
console.log(`[svelte-origin-preprocess] Resolved attrs schema for ${exportName}:`, mergedSchema.attrs.map((a) => a.key));
|
|
3835
|
+
}
|
|
3836
|
+
cache.set(cacheKey, mergedSchema);
|
|
3837
|
+
return mergedSchema;
|
|
3838
|
+
} catch (error) {
|
|
3839
|
+
if (debug) {
|
|
3840
|
+
console.error(`[svelte-origin-preprocess] Error resolving attrs schema for ${importPath}:`, error);
|
|
3841
|
+
}
|
|
3842
|
+
cache.set(cacheKey, null);
|
|
3843
|
+
return null;
|
|
3844
|
+
}
|
|
3845
|
+
}
|
|
3496
3846
|
function svelteOriginPreprocess(options = {}) {
|
|
3497
3847
|
const {
|
|
3498
3848
|
debug = false,
|
package/dist/runtime/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
|
|
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
|
-
|
|
3492
|
-
|
|
3493
|
-
|
|
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
|
-
|
|
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
|
-
*
|
|
14
|
-
*
|
|
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
|
|
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>;
|
|
@@ -19,6 +19,8 @@ export interface ParsedAttrInfo {
|
|
|
19
19
|
export interface ParsedOriginSchema {
|
|
20
20
|
attrs: ParsedAttrInfo[];
|
|
21
21
|
parentNames: string[];
|
|
22
|
+
/** Reference to external $attrs factory (e.g., 'TextAttrs' when props: TextAttrs is used) */
|
|
23
|
+
propsRef?: string;
|
|
22
24
|
}
|
|
23
25
|
/**
|
|
24
26
|
* Parse an origin's schema from its source code.
|
|
@@ -40,6 +42,21 @@ export interface ParsedOriginSchema {
|
|
|
40
42
|
* @returns Parsed schema or null if not found
|
|
41
43
|
*/
|
|
42
44
|
export declare function parseOriginSchemaFromSource(source: string, exportName: string): ParsedOriginSchema | null;
|
|
45
|
+
/**
|
|
46
|
+
* Parse an $attrs factory's schema from its source code.
|
|
47
|
+
*
|
|
48
|
+
* Looks for patterns like:
|
|
49
|
+
* ```ts
|
|
50
|
+
* export const TextAttrs = $attrs({ ... })
|
|
51
|
+
* export const TextAttrs = $attrs([BaseAttrs], { ... })
|
|
52
|
+
* ```
|
|
53
|
+
*
|
|
54
|
+
* Or compiled:
|
|
55
|
+
* ```js
|
|
56
|
+
* export var TextAttrs = __createAttrs({ __attrSchema: {...}, __parents: [...] })
|
|
57
|
+
* ```
|
|
58
|
+
*/
|
|
59
|
+
export declare function parseAttrsSchemaFromSource(source: string, exportName: string): ParsedOriginSchema | null;
|
|
43
60
|
/**
|
|
44
61
|
* Generate $props() destructuring code from parsed attrs
|
|
45
62
|
*
|