@barefootjs/go-template 0.31.8 → 0.31.10
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/adapter/go-template-adapter.d.ts +71 -0
- package/dist/adapter/go-template-adapter.d.ts.map +1 -1
- package/dist/adapter/index.js +97 -15
- package/dist/adapter/lib/compile-state.d.ts +43 -1
- package/dist/adapter/lib/compile-state.d.ts.map +1 -1
- package/dist/adapter/props/prop-types.d.ts +25 -2
- package/dist/adapter/props/prop-types.d.ts.map +1 -1
- package/dist/adapter/type/type-codegen.d.ts.map +1 -1
- package/dist/index.js +99 -16
- package/dist/render-divergences.d.ts +8 -0
- package/dist/render-divergences.d.ts.map +1 -1
- package/dist/test-render.d.ts.map +1 -1
- package/dist/vite.js +160 -17
- package/package.json +5 -5
- package/src/__tests__/go-template-adapter.test.ts +276 -16
- package/src/adapter/go-template-adapter.ts +249 -11
- package/src/adapter/lib/compile-state.ts +50 -0
- package/src/adapter/props/prop-types.ts +36 -8
- package/src/adapter/type/type-codegen.ts +19 -2
- package/src/render-divergences.ts +31 -5
- package/src/test-render.ts +273 -52
package/dist/index.js
CHANGED
|
@@ -358,8 +358,13 @@ class CompileState {
|
|
|
358
358
|
localTypeAliases = new Map;
|
|
359
359
|
localStructFields = new Map;
|
|
360
360
|
synthStructTypes = new Map;
|
|
361
|
+
synthObjectStructNames = new Map;
|
|
361
362
|
needsStringsImport = false;
|
|
362
363
|
}
|
|
364
|
+
function resolveSignalParsedThroughSeedPlan(state, signal) {
|
|
365
|
+
const step = state.ssrSeedPlan.steps.find((s) => s.kind === "derived" && s.origin === "signal" && s.name === signal.getter);
|
|
366
|
+
return step?.kind === "derived" ? step.parsed : signal.parsed;
|
|
367
|
+
}
|
|
363
368
|
|
|
364
369
|
// src/adapter/analysis/component-tree.ts
|
|
365
370
|
function hasClientInteractivity(ir) {
|
|
@@ -1024,8 +1029,10 @@ function typeInfoToGo(ctx, _typeInfo, defaultValue, preParsed) {
|
|
|
1024
1029
|
return `[]${typeInfoToGo(ctx, typeInfo.elementType)}`;
|
|
1025
1030
|
}
|
|
1026
1031
|
return "[]interface{}";
|
|
1027
|
-
case "object":
|
|
1028
|
-
|
|
1032
|
+
case "object": {
|
|
1033
|
+
const synthName = ctx.state.synthObjectStructNames.get(typeInfo);
|
|
1034
|
+
return synthName ?? "map[string]interface{}";
|
|
1035
|
+
}
|
|
1029
1036
|
case "interface":
|
|
1030
1037
|
if (typeInfo.raw && (ctx.state.localStructFields.has(typeInfo.raw) || ctx.state.localTypeAliases.has(typeInfo.raw))) {
|
|
1031
1038
|
return typeInfo.raw;
|
|
@@ -2583,11 +2590,11 @@ function buildPropTypeOverrides(ctx, ir) {
|
|
|
2583
2590
|
if (!param)
|
|
2584
2591
|
continue;
|
|
2585
2592
|
const propGoType = typeInfoToGo(ctx, param.type, param.defaultValue, param.parsed);
|
|
2586
|
-
|
|
2587
|
-
|
|
2588
|
-
|
|
2589
|
-
|
|
2590
|
-
|
|
2593
|
+
const signalGoType = typeInfoToGo(ctx, signal.type, signal.initialValue, signal.parsed);
|
|
2594
|
+
if (signalGoType.includes("interface{}"))
|
|
2595
|
+
continue;
|
|
2596
|
+
if (propGoType.includes("interface{}") || signalGoType !== propGoType) {
|
|
2597
|
+
overrides.set(propName, signalGoType);
|
|
2591
2598
|
}
|
|
2592
2599
|
}
|
|
2593
2600
|
}
|
|
@@ -2670,7 +2677,7 @@ function collectNullishConsumedPropNames(ctx, ir) {
|
|
|
2670
2677
|
};
|
|
2671
2678
|
walk(ir.root);
|
|
2672
2679
|
for (const signal of ir.metadata.signals) {
|
|
2673
|
-
const match = ctx.extractPropFallback(signal.initialValue, signal
|
|
2680
|
+
const match = ctx.extractPropFallback(signal.initialValue, resolveSignalParsedThroughSeedPlan(ctx.state, signal));
|
|
2674
2681
|
if (!match || !optionalParams.has(match.propName))
|
|
2675
2682
|
continue;
|
|
2676
2683
|
const f = match.goFallback;
|
|
@@ -2818,6 +2825,11 @@ function collectStringValueNames(ir) {
|
|
|
2818
2825
|
}
|
|
2819
2826
|
|
|
2820
2827
|
// src/adapter/go-template-adapter.ts
|
|
2828
|
+
var SYNTH_TYPE_LOC = {
|
|
2829
|
+
file: "<synthesized>",
|
|
2830
|
+
start: { line: 0, column: 0 },
|
|
2831
|
+
end: { line: 0, column: 0 }
|
|
2832
|
+
};
|
|
2821
2833
|
var STRING_METHODS = new Set([
|
|
2822
2834
|
"replace",
|
|
2823
2835
|
"trim",
|
|
@@ -3179,6 +3191,7 @@ ${scriptRegistrations}${templateBody}
|
|
|
3179
3191
|
const lines = [];
|
|
3180
3192
|
const componentName = ir.metadata.componentName;
|
|
3181
3193
|
this.buildLocalTypeTables(ir, componentName);
|
|
3194
|
+
this.emitSynthPropStructs(lines, ir, componentName);
|
|
3182
3195
|
this.emitLocalTypeStructs(lines, ir, componentName);
|
|
3183
3196
|
this.emitSynthStructs(lines, ir, componentName);
|
|
3184
3197
|
const nestedComponents = findNestedComponents(ir.root);
|
|
@@ -3682,7 +3695,7 @@ ${goFields.join(`
|
|
|
3682
3695
|
const fieldName = capitalizeFieldName(signal.getter);
|
|
3683
3696
|
if (propFieldNames.has(fieldName))
|
|
3684
3697
|
continue;
|
|
3685
|
-
const fallbackMatch = this.extractPropFallback(signal.initialValue, signal
|
|
3698
|
+
const fallbackMatch = this.extractPropFallback(signal.initialValue, this.resolvedSignalParsed(signal));
|
|
3686
3699
|
const hoisted = fallbackMatch ? propFallbackVars.get(fallbackMatch.propName) : undefined;
|
|
3687
3700
|
if (hoisted) {
|
|
3688
3701
|
lines.push(` ${fieldName}: ${hoisted.varName},`);
|
|
@@ -4038,6 +4051,65 @@ ${goFields.join(`
|
|
|
4038
4051
|
}
|
|
4039
4052
|
}
|
|
4040
4053
|
}
|
|
4054
|
+
emitSynthPropStructs(lines, ir, componentName) {
|
|
4055
|
+
this.state.synthObjectStructNames = new Map;
|
|
4056
|
+
this.state.currentTypeDefinitions = [...this.state.currentTypeDefinitions];
|
|
4057
|
+
const visitObject = (typeInfo, desiredName) => {
|
|
4058
|
+
if (this.state.synthObjectStructNames.has(typeInfo))
|
|
4059
|
+
return;
|
|
4060
|
+
if (this.state.localTypeNames.has(desiredName))
|
|
4061
|
+
return;
|
|
4062
|
+
this.state.localTypeNames.add(desiredName);
|
|
4063
|
+
this.state.synthObjectStructNames.set(typeInfo, desiredName);
|
|
4064
|
+
for (const prop of typeInfo.properties ?? []) {
|
|
4065
|
+
visit(prop.type, desiredName, prop.name);
|
|
4066
|
+
}
|
|
4067
|
+
const fields = this.structFieldsFor(typeInfo);
|
|
4068
|
+
this.state.localStructFields.set(desiredName, new Map(fields.map((f) => [f.tsName, f.goName])));
|
|
4069
|
+
this.state.currentTypeDefinitions.push({
|
|
4070
|
+
kind: "type",
|
|
4071
|
+
name: desiredName,
|
|
4072
|
+
definition: "",
|
|
4073
|
+
properties: typeInfo.properties ?? [],
|
|
4074
|
+
loc: SYNTH_TYPE_LOC
|
|
4075
|
+
});
|
|
4076
|
+
const goFields = fields.map((f) => ` ${f.goName} ${f.goType} \`json:"${this.toJsonTag(f.tsName)}"\``);
|
|
4077
|
+
lines.push(`// ${desiredName} is a synthesised type for an anonymous object type (#2674).`);
|
|
4078
|
+
lines.push(`type ${desiredName} struct {
|
|
4079
|
+
${goFields.join(`
|
|
4080
|
+
`)}
|
|
4081
|
+
}`);
|
|
4082
|
+
lines.push("");
|
|
4083
|
+
};
|
|
4084
|
+
const visitArrayElem = (elemType, parentName, propName) => {
|
|
4085
|
+
if (!elemType)
|
|
4086
|
+
return;
|
|
4087
|
+
if (elemType.kind === "array") {
|
|
4088
|
+
visitArrayElem(elemType.elementType, parentName, propName);
|
|
4089
|
+
} else if (elemType.kind === "object") {
|
|
4090
|
+
visitObject(elemType, `${parentName}${goFieldNameForKey(propName)}Item`);
|
|
4091
|
+
}
|
|
4092
|
+
};
|
|
4093
|
+
const visit = (typeInfo, parentName, propName) => {
|
|
4094
|
+
if (typeInfo.kind === "array") {
|
|
4095
|
+
visitArrayElem(typeInfo.elementType, parentName, propName);
|
|
4096
|
+
} else if (typeInfo.kind === "object") {
|
|
4097
|
+
visitObject(typeInfo, `${parentName}${goFieldNameForKey(propName)}`);
|
|
4098
|
+
}
|
|
4099
|
+
};
|
|
4100
|
+
for (const td of ir.metadata.typeDefinitions) {
|
|
4101
|
+
if (td.name === "Props" || td.name === `${componentName}Props`)
|
|
4102
|
+
continue;
|
|
4103
|
+
if (td.name.endsWith("Props"))
|
|
4104
|
+
continue;
|
|
4105
|
+
for (const prop of td.properties ?? []) {
|
|
4106
|
+
visit(prop.type, td.name, prop.name);
|
|
4107
|
+
}
|
|
4108
|
+
}
|
|
4109
|
+
for (const param of ir.metadata.propsParams) {
|
|
4110
|
+
visit(param.type, componentName, param.name);
|
|
4111
|
+
}
|
|
4112
|
+
}
|
|
4041
4113
|
emitLocalTypeStructs(lines, ir, componentName) {
|
|
4042
4114
|
for (const td of ir.metadata.typeDefinitions) {
|
|
4043
4115
|
if (td.name === "Props" || td.name === `${componentName}Props`)
|
|
@@ -4121,7 +4193,7 @@ ${goFields.join(`
|
|
|
4121
4193
|
emitPropsStructHeader(lines, ir, propsTypeName, componentName) {
|
|
4122
4194
|
lines.push(`// ${propsTypeName} is the props type for the ${componentName} component.`);
|
|
4123
4195
|
lines.push(`type ${propsTypeName} struct {`);
|
|
4124
|
-
lines.push('\tScopeID string `json:"
|
|
4196
|
+
lines.push('\tScopeID string `json:"-"`');
|
|
4125
4197
|
lines.push('\tBfIsRoot bool `json:"-"`');
|
|
4126
4198
|
lines.push('\tBfIsChild bool `json:"-"`');
|
|
4127
4199
|
lines.push('\tBfParent string `json:"-"`');
|
|
@@ -4151,7 +4223,7 @@ ${goFields.join(`
|
|
|
4151
4223
|
const fieldName = capitalizeFieldName(signal.getter);
|
|
4152
4224
|
if (propFieldNames.has(fieldName))
|
|
4153
4225
|
continue;
|
|
4154
|
-
const jsonTag =
|
|
4226
|
+
const jsonTag = "-";
|
|
4155
4227
|
const synthType = this.state.synthStructTypes.get(signal.getter);
|
|
4156
4228
|
if (synthType) {
|
|
4157
4229
|
lines.push(` ${fieldName} ${typeInfoToGo(this.emitCtx, synthType)} \`json:"${jsonTag}"\``);
|
|
@@ -4183,7 +4255,7 @@ ${goFields.join(`
|
|
|
4183
4255
|
const fieldName = capitalizeFieldName(memo.name);
|
|
4184
4256
|
if (propFieldNames.has(fieldName))
|
|
4185
4257
|
continue;
|
|
4186
|
-
const jsonTag =
|
|
4258
|
+
const jsonTag = "-";
|
|
4187
4259
|
const goType = this.inferMemoType(memo, ir.metadata.signals, propsParamMap);
|
|
4188
4260
|
lines.push(` ${fieldName} ${goType} \`json:"${jsonTag}"\``);
|
|
4189
4261
|
}
|
|
@@ -4203,15 +4275,22 @@ ${goFields.join(`
|
|
|
4203
4275
|
...ir.metadata.memos.map((m) => capitalizeFieldName(m.name))
|
|
4204
4276
|
]);
|
|
4205
4277
|
for (const c of this.nonCollidingContextConsumers(takenProps)) {
|
|
4206
|
-
const jsonTag =
|
|
4278
|
+
const jsonTag = "-";
|
|
4207
4279
|
lines.push(` ${this.contextFieldName(c)} ${this.contextConsumerGoType(c)} \`json:"${jsonTag}"\``);
|
|
4208
4280
|
}
|
|
4281
|
+
const propDrivingFieldNames = new Set;
|
|
4282
|
+
for (const p of ir.metadata.propsParams) {
|
|
4283
|
+
propDrivingFieldNames.add(capitalizeFieldName(p.name));
|
|
4284
|
+
propDrivingFieldNames.add(capitalizeFieldName(p.sourceName ?? p.name));
|
|
4285
|
+
}
|
|
4209
4286
|
for (const nested of nestedComponents) {
|
|
4210
4287
|
if (this.isOrphanedClientOnlyNested(nested))
|
|
4211
4288
|
continue;
|
|
4212
4289
|
const elemType = nested.bodyChildren?.length ? this.loopBodyWrapperName(componentName, nested) : `${nested.name}Props`;
|
|
4213
4290
|
if (nested.isDynamic && !nested.isPropDerived) {
|
|
4214
4291
|
lines.push(` ${nested.name}s []${elemType} \`json:"-"\``);
|
|
4292
|
+
} else if (nested.isDynamic && nested.isPropDerived && !propDrivingFieldNames.has(`${nested.name}s`)) {
|
|
4293
|
+
lines.push(` ${nested.name}s []${elemType} \`json:"-"\``);
|
|
4215
4294
|
} else {
|
|
4216
4295
|
const jsonTag = this.claimJsonTag(this.toJsonTag(`${nested.name.charAt(0).toLowerCase()}${nested.name.slice(1)}s`), takenJsonTags);
|
|
4217
4296
|
lines.push(` ${nested.name}s []${elemType} \`json:"${jsonTag}"\``);
|
|
@@ -4222,7 +4301,7 @@ ${goFields.join(`
|
|
|
4222
4301
|
lines.push(` ${child.fieldName} ${child.name}Props \`json:"-"\``);
|
|
4223
4302
|
}
|
|
4224
4303
|
for (const slot of spreadSlots) {
|
|
4225
|
-
const jsonTag =
|
|
4304
|
+
const jsonTag = "-";
|
|
4226
4305
|
lines.push(` ${slot.slotId} map[string]any \`json:"${jsonTag}"\``);
|
|
4227
4306
|
}
|
|
4228
4307
|
}
|
|
@@ -4535,7 +4614,7 @@ ${goFields.join(`
|
|
|
4535
4614
|
}
|
|
4536
4615
|
const propTypeOverrides = buildPropTypeOverrides(this.emitCtx, ir);
|
|
4537
4616
|
for (const signal of ir.metadata.signals) {
|
|
4538
|
-
const match = this.extractPropFallback(signal.initialValue, signal
|
|
4617
|
+
const match = this.extractPropFallback(signal.initialValue, this.resolvedSignalParsed(signal));
|
|
4539
4618
|
if (!match)
|
|
4540
4619
|
continue;
|
|
4541
4620
|
if (result.has(match.propName))
|
|
@@ -4579,6 +4658,9 @@ ${goFields.join(`
|
|
|
4579
4658
|
}
|
|
4580
4659
|
return result;
|
|
4581
4660
|
}
|
|
4661
|
+
resolvedSignalParsed(signal) {
|
|
4662
|
+
return resolveSignalParsedThroughSeedPlan(this.state, signal);
|
|
4663
|
+
}
|
|
4582
4664
|
extractPropFallback(initialValue, preParsed) {
|
|
4583
4665
|
const structural = preParsed ? this.extractPropFallbackFromParsed(preParsed) : null;
|
|
4584
4666
|
if (structural)
|
|
@@ -6676,7 +6758,8 @@ var conformancePins = {
|
|
|
6676
6758
|
};
|
|
6677
6759
|
// src/render-divergences.ts
|
|
6678
6760
|
var renderDivergences = {
|
|
6679
|
-
"
|
|
6761
|
+
"signal-prop-same-name-derived": "self-derived signal collides with its prop field name in the generated Go props struct — the non-idempotent `* 2` derivation is dropped and the signal renders the raw prop value instead (https://github.com/piconic-ai/barefootjs/issues/2683)",
|
|
6762
|
+
"signal-prop-same-name-via-const-derived": "self-derived signal (reached through a component-scope const) collides with its prop field name in the generated Go props struct — the non-idempotent `* 2` derivation is dropped and the signal renders the raw prop value instead (https://github.com/piconic-ai/barefootjs/issues/2683)"
|
|
6680
6763
|
};
|
|
6681
6764
|
export {
|
|
6682
6765
|
renderDivergences,
|
|
@@ -5,6 +5,14 @@
|
|
|
5
5
|
* one object, so the skip list and the declaration can't drift. Keep the
|
|
6
6
|
* file even when the set is empty — the next divergence lands here, not in
|
|
7
7
|
* a re-created file.
|
|
8
|
+
*
|
|
9
|
+
* (#2630's `static-array-from-props-with-component-precomputed` divergence
|
|
10
|
+
* graduated once the harness (`test-render.ts`'s
|
|
11
|
+
* `buildDynamicChildLoopSeeding`, despite the name — see its doc comment)
|
|
12
|
+
* learned to seed a prop-backed static child-component loop's Props slice
|
|
13
|
+
* the same way it already seeded a signal-backed dynamic one: the adapter's
|
|
14
|
+
* own `emission` was never the bug, only this harness's route-handler
|
|
15
|
+
* stand-in was missing the prop-derived case.)
|
|
8
16
|
*/
|
|
9
17
|
import type { RenderDivergences } from '@barefootjs/jsx';
|
|
10
18
|
export declare const renderDivergences: RenderDivergences;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"render-divergences.d.ts","sourceRoot":"","sources":["../src/render-divergences.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"render-divergences.d.ts","sourceRoot":"","sources":["../src/render-divergences.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAA;AAExD,eAAO,MAAM,iBAAiB,EAAE,iBAwB/B,CAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"test-render.d.ts","sourceRoot":"","sources":["../src/test-render.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,KAAK,EAAE,eAAe,EAA2B,MAAM,iBAAiB,CAAA;AAY/E,qBAAa,mBAAoB,SAAQ,KAAK;IAC5C,YAAY,OAAO,EAAE,MAAM,EAG1B;CACF;AAgCD,MAAM,WAAW,aAAa;IAC5B,sBAAsB;IACtB,MAAM,EAAE,MAAM,CAAA;IACd,8BAA8B;IAC9B,OAAO,EAAE,eAAe,CAAA;IACxB,iCAAiC;IACjC,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IAC/B,qDAAqD;IACrD,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IACnC;;;;;;OAMG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IACzC;;;;;OAKG;IACH,aAAa,CAAC,EAAE,MAAM,CAAA;CACvB;AAED,wBAAsB,yBAAyB,CAAC,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,MAAM,CAAC,
|
|
1
|
+
{"version":3,"file":"test-render.d.ts","sourceRoot":"","sources":["../src/test-render.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,KAAK,EAAE,eAAe,EAA2B,MAAM,iBAAiB,CAAA;AAY/E,qBAAa,mBAAoB,SAAQ,KAAK;IAC5C,YAAY,OAAO,EAAE,MAAM,EAG1B;CACF;AAgCD,MAAM,WAAW,aAAa;IAC5B,sBAAsB;IACtB,MAAM,EAAE,MAAM,CAAA;IACd,8BAA8B;IAC9B,OAAO,EAAE,eAAe,CAAA;IACxB,iCAAiC;IACjC,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IAC/B,qDAAqD;IACrD,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IACnC;;;;;;OAMG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IACzC;;;;;OAKG;IACH,aAAa,CAAC,EAAE,MAAM,CAAA;CACvB;AAED,wBAAsB,yBAAyB,CAAC,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,MAAM,CAAC,CA2WvF"}
|
package/dist/vite.js
CHANGED
|
@@ -3095,6 +3095,34 @@ var SVG_ROOT_TAGS = new Set([
|
|
|
3095
3095
|
"animateTransform",
|
|
3096
3096
|
"animateMotion"
|
|
3097
3097
|
]);
|
|
3098
|
+
var MATHML_ROOT_TAGS = new Set([
|
|
3099
|
+
"math",
|
|
3100
|
+
"mrow",
|
|
3101
|
+
"mfrac",
|
|
3102
|
+
"msup",
|
|
3103
|
+
"msub",
|
|
3104
|
+
"msubsup",
|
|
3105
|
+
"mn",
|
|
3106
|
+
"mi",
|
|
3107
|
+
"mo",
|
|
3108
|
+
"mtext",
|
|
3109
|
+
"munder",
|
|
3110
|
+
"mover",
|
|
3111
|
+
"munderover",
|
|
3112
|
+
"mtable",
|
|
3113
|
+
"mtr",
|
|
3114
|
+
"mtd",
|
|
3115
|
+
"msqrt",
|
|
3116
|
+
"mroot",
|
|
3117
|
+
"mstyle",
|
|
3118
|
+
"merror",
|
|
3119
|
+
"mpadded",
|
|
3120
|
+
"mphantom",
|
|
3121
|
+
"menclose",
|
|
3122
|
+
"semantics",
|
|
3123
|
+
"annotation",
|
|
3124
|
+
"annotation-xml"
|
|
3125
|
+
]);
|
|
3098
3126
|
|
|
3099
3127
|
// ../jsx/src/ir-to-client-js/collect-elements.ts
|
|
3100
3128
|
var EMPTY_RENDER_EXPRS = new Set(["null", "undefined", "false", "''", '""', "``"]);
|
|
@@ -3901,6 +3929,38 @@ function classify(name, origin, expr, parsed, available) {
|
|
|
3901
3929
|
}
|
|
3902
3930
|
return { kind: "derived", name, origin, expr, parsed, frees: [...frees] };
|
|
3903
3931
|
}
|
|
3932
|
+
function localConstExprsByName(metadata) {
|
|
3933
|
+
const out = new Map;
|
|
3934
|
+
for (const c of metadata.localConstants ?? []) {
|
|
3935
|
+
if (c.isModule || c.declarationKind !== "const" || c.value === undefined)
|
|
3936
|
+
continue;
|
|
3937
|
+
out.set(c.name, c.parsed ?? parseExpression(c.value.trim()));
|
|
3938
|
+
}
|
|
3939
|
+
return out;
|
|
3940
|
+
}
|
|
3941
|
+
function resolveThroughLocalConsts(parsed, localConsts) {
|
|
3942
|
+
let current = parsed;
|
|
3943
|
+
const maxIter = localConsts.size + 1;
|
|
3944
|
+
for (let i = 0;i < maxIter; i++) {
|
|
3945
|
+
const frees = freeIdentifiers(current);
|
|
3946
|
+
if (frees === null)
|
|
3947
|
+
break;
|
|
3948
|
+
let changed = false;
|
|
3949
|
+
for (const name of frees) {
|
|
3950
|
+
const value = localConsts.get(name);
|
|
3951
|
+
if (!value)
|
|
3952
|
+
continue;
|
|
3953
|
+
const inlined = inlineBinding(current, name, value);
|
|
3954
|
+
if (inlined === null)
|
|
3955
|
+
continue;
|
|
3956
|
+
current = inlined;
|
|
3957
|
+
changed = true;
|
|
3958
|
+
}
|
|
3959
|
+
if (!changed)
|
|
3960
|
+
break;
|
|
3961
|
+
}
|
|
3962
|
+
return current;
|
|
3963
|
+
}
|
|
3904
3964
|
function computeSsrSeedPlan(metadata) {
|
|
3905
3965
|
const baseScope = metadata.propsParams.map((p) => p.name);
|
|
3906
3966
|
if (metadata.propsObjectName)
|
|
@@ -3909,6 +3969,7 @@ function computeSsrSeedPlan(metadata) {
|
|
|
3909
3969
|
baseScope.push(name);
|
|
3910
3970
|
}
|
|
3911
3971
|
const available = new Set(baseScope);
|
|
3972
|
+
const localConsts = localConstExprsByName(metadata);
|
|
3912
3973
|
const steps = [];
|
|
3913
3974
|
for (const signal of metadata.signals) {
|
|
3914
3975
|
if (signal.envReader) {
|
|
@@ -3920,13 +3981,13 @@ function computeSsrSeedPlan(metadata) {
|
|
|
3920
3981
|
}
|
|
3921
3982
|
}
|
|
3922
3983
|
const expr = signal.initialValue.trim();
|
|
3923
|
-
steps.push(expr === "" ? { kind: "opaque", name: signal.getter, origin: "signal" } : classify(signal.getter, "signal", expr, parseExpression(expr), available));
|
|
3984
|
+
steps.push(expr === "" ? { kind: "opaque", name: signal.getter, origin: "signal" } : classify(signal.getter, "signal", expr, resolveThroughLocalConsts(parseExpression(expr), localConsts), available));
|
|
3924
3985
|
available.add(signal.getter);
|
|
3925
3986
|
}
|
|
3926
3987
|
for (const memo of metadata.memos) {
|
|
3927
3988
|
const body = extractArrowBodyExpression(memo.computation);
|
|
3928
3989
|
const expr = body?.trim() ?? "";
|
|
3929
|
-
steps.push(expr === "" ? { kind: "opaque", name: memo.name, origin: "memo" } : classify(memo.name, "memo", expr, memo.parsed ?? parseExpression(expr), available));
|
|
3990
|
+
steps.push(expr === "" ? { kind: "opaque", name: memo.name, origin: "memo" } : classify(memo.name, "memo", expr, resolveThroughLocalConsts(memo.parsed ?? parseExpression(expr), localConsts), available));
|
|
3930
3991
|
available.add(memo.name);
|
|
3931
3992
|
}
|
|
3932
3993
|
return { baseScope, steps };
|
|
@@ -5427,8 +5488,13 @@ class CompileState {
|
|
|
5427
5488
|
localTypeAliases = new Map;
|
|
5428
5489
|
localStructFields = new Map;
|
|
5429
5490
|
synthStructTypes = new Map;
|
|
5491
|
+
synthObjectStructNames = new Map;
|
|
5430
5492
|
needsStringsImport = false;
|
|
5431
5493
|
}
|
|
5494
|
+
function resolveSignalParsedThroughSeedPlan(state, signal) {
|
|
5495
|
+
const step = state.ssrSeedPlan.steps.find((s) => s.kind === "derived" && s.origin === "signal" && s.name === signal.getter);
|
|
5496
|
+
return step?.kind === "derived" ? step.parsed : signal.parsed;
|
|
5497
|
+
}
|
|
5432
5498
|
|
|
5433
5499
|
// src/adapter/analysis/component-tree.ts
|
|
5434
5500
|
function hasClientInteractivity(ir) {
|
|
@@ -6075,8 +6141,10 @@ function typeInfoToGo(ctx, _typeInfo, defaultValue, preParsed) {
|
|
|
6075
6141
|
return `[]${typeInfoToGo(ctx, typeInfo.elementType)}`;
|
|
6076
6142
|
}
|
|
6077
6143
|
return "[]interface{}";
|
|
6078
|
-
case "object":
|
|
6079
|
-
|
|
6144
|
+
case "object": {
|
|
6145
|
+
const synthName = ctx.state.synthObjectStructNames.get(typeInfo);
|
|
6146
|
+
return synthName ?? "map[string]interface{}";
|
|
6147
|
+
}
|
|
6080
6148
|
case "interface":
|
|
6081
6149
|
if (typeInfo.raw && (ctx.state.localStructFields.has(typeInfo.raw) || ctx.state.localTypeAliases.has(typeInfo.raw))) {
|
|
6082
6150
|
return typeInfo.raw;
|
|
@@ -7622,11 +7690,11 @@ function buildPropTypeOverrides(ctx, ir) {
|
|
|
7622
7690
|
if (!param)
|
|
7623
7691
|
continue;
|
|
7624
7692
|
const propGoType = typeInfoToGo(ctx, param.type, param.defaultValue, param.parsed);
|
|
7625
|
-
|
|
7626
|
-
|
|
7627
|
-
|
|
7628
|
-
|
|
7629
|
-
|
|
7693
|
+
const signalGoType = typeInfoToGo(ctx, signal.type, signal.initialValue, signal.parsed);
|
|
7694
|
+
if (signalGoType.includes("interface{}"))
|
|
7695
|
+
continue;
|
|
7696
|
+
if (propGoType.includes("interface{}") || signalGoType !== propGoType) {
|
|
7697
|
+
overrides.set(propName, signalGoType);
|
|
7630
7698
|
}
|
|
7631
7699
|
}
|
|
7632
7700
|
}
|
|
@@ -7709,7 +7777,7 @@ function collectNullishConsumedPropNames(ctx, ir) {
|
|
|
7709
7777
|
};
|
|
7710
7778
|
walk(ir.root);
|
|
7711
7779
|
for (const signal of ir.metadata.signals) {
|
|
7712
|
-
const match = ctx.extractPropFallback(signal.initialValue, signal
|
|
7780
|
+
const match = ctx.extractPropFallback(signal.initialValue, resolveSignalParsedThroughSeedPlan(ctx.state, signal));
|
|
7713
7781
|
if (!match || !optionalParams.has(match.propName))
|
|
7714
7782
|
continue;
|
|
7715
7783
|
const f = match.goFallback;
|
|
@@ -7856,6 +7924,11 @@ function collectStringValueNames(ir) {
|
|
|
7856
7924
|
}
|
|
7857
7925
|
|
|
7858
7926
|
// src/adapter/go-template-adapter.ts
|
|
7927
|
+
var SYNTH_TYPE_LOC = {
|
|
7928
|
+
file: "<synthesized>",
|
|
7929
|
+
start: { line: 0, column: 0 },
|
|
7930
|
+
end: { line: 0, column: 0 }
|
|
7931
|
+
};
|
|
7859
7932
|
var STRING_METHODS = new Set([
|
|
7860
7933
|
"replace",
|
|
7861
7934
|
"trim",
|
|
@@ -8217,6 +8290,7 @@ ${scriptRegistrations}${templateBody}
|
|
|
8217
8290
|
const lines = [];
|
|
8218
8291
|
const componentName = ir.metadata.componentName;
|
|
8219
8292
|
this.buildLocalTypeTables(ir, componentName);
|
|
8293
|
+
this.emitSynthPropStructs(lines, ir, componentName);
|
|
8220
8294
|
this.emitLocalTypeStructs(lines, ir, componentName);
|
|
8221
8295
|
this.emitSynthStructs(lines, ir, componentName);
|
|
8222
8296
|
const nestedComponents = findNestedComponents(ir.root);
|
|
@@ -8720,7 +8794,7 @@ ${goFields.join(`
|
|
|
8720
8794
|
const fieldName = capitalizeFieldName(signal.getter);
|
|
8721
8795
|
if (propFieldNames.has(fieldName))
|
|
8722
8796
|
continue;
|
|
8723
|
-
const fallbackMatch = this.extractPropFallback(signal.initialValue, signal
|
|
8797
|
+
const fallbackMatch = this.extractPropFallback(signal.initialValue, this.resolvedSignalParsed(signal));
|
|
8724
8798
|
const hoisted = fallbackMatch ? propFallbackVars.get(fallbackMatch.propName) : undefined;
|
|
8725
8799
|
if (hoisted) {
|
|
8726
8800
|
lines.push(` ${fieldName}: ${hoisted.varName},`);
|
|
@@ -9076,6 +9150,65 @@ ${goFields.join(`
|
|
|
9076
9150
|
}
|
|
9077
9151
|
}
|
|
9078
9152
|
}
|
|
9153
|
+
emitSynthPropStructs(lines, ir, componentName) {
|
|
9154
|
+
this.state.synthObjectStructNames = new Map;
|
|
9155
|
+
this.state.currentTypeDefinitions = [...this.state.currentTypeDefinitions];
|
|
9156
|
+
const visitObject = (typeInfo, desiredName) => {
|
|
9157
|
+
if (this.state.synthObjectStructNames.has(typeInfo))
|
|
9158
|
+
return;
|
|
9159
|
+
if (this.state.localTypeNames.has(desiredName))
|
|
9160
|
+
return;
|
|
9161
|
+
this.state.localTypeNames.add(desiredName);
|
|
9162
|
+
this.state.synthObjectStructNames.set(typeInfo, desiredName);
|
|
9163
|
+
for (const prop of typeInfo.properties ?? []) {
|
|
9164
|
+
visit(prop.type, desiredName, prop.name);
|
|
9165
|
+
}
|
|
9166
|
+
const fields = this.structFieldsFor(typeInfo);
|
|
9167
|
+
this.state.localStructFields.set(desiredName, new Map(fields.map((f) => [f.tsName, f.goName])));
|
|
9168
|
+
this.state.currentTypeDefinitions.push({
|
|
9169
|
+
kind: "type",
|
|
9170
|
+
name: desiredName,
|
|
9171
|
+
definition: "",
|
|
9172
|
+
properties: typeInfo.properties ?? [],
|
|
9173
|
+
loc: SYNTH_TYPE_LOC
|
|
9174
|
+
});
|
|
9175
|
+
const goFields = fields.map((f) => ` ${f.goName} ${f.goType} \`json:"${this.toJsonTag(f.tsName)}"\``);
|
|
9176
|
+
lines.push(`// ${desiredName} is a synthesised type for an anonymous object type (#2674).`);
|
|
9177
|
+
lines.push(`type ${desiredName} struct {
|
|
9178
|
+
${goFields.join(`
|
|
9179
|
+
`)}
|
|
9180
|
+
}`);
|
|
9181
|
+
lines.push("");
|
|
9182
|
+
};
|
|
9183
|
+
const visitArrayElem = (elemType, parentName, propName) => {
|
|
9184
|
+
if (!elemType)
|
|
9185
|
+
return;
|
|
9186
|
+
if (elemType.kind === "array") {
|
|
9187
|
+
visitArrayElem(elemType.elementType, parentName, propName);
|
|
9188
|
+
} else if (elemType.kind === "object") {
|
|
9189
|
+
visitObject(elemType, `${parentName}${goFieldNameForKey(propName)}Item`);
|
|
9190
|
+
}
|
|
9191
|
+
};
|
|
9192
|
+
const visit = (typeInfo, parentName, propName) => {
|
|
9193
|
+
if (typeInfo.kind === "array") {
|
|
9194
|
+
visitArrayElem(typeInfo.elementType, parentName, propName);
|
|
9195
|
+
} else if (typeInfo.kind === "object") {
|
|
9196
|
+
visitObject(typeInfo, `${parentName}${goFieldNameForKey(propName)}`);
|
|
9197
|
+
}
|
|
9198
|
+
};
|
|
9199
|
+
for (const td of ir.metadata.typeDefinitions) {
|
|
9200
|
+
if (td.name === "Props" || td.name === `${componentName}Props`)
|
|
9201
|
+
continue;
|
|
9202
|
+
if (td.name.endsWith("Props"))
|
|
9203
|
+
continue;
|
|
9204
|
+
for (const prop of td.properties ?? []) {
|
|
9205
|
+
visit(prop.type, td.name, prop.name);
|
|
9206
|
+
}
|
|
9207
|
+
}
|
|
9208
|
+
for (const param of ir.metadata.propsParams) {
|
|
9209
|
+
visit(param.type, componentName, param.name);
|
|
9210
|
+
}
|
|
9211
|
+
}
|
|
9079
9212
|
emitLocalTypeStructs(lines, ir, componentName) {
|
|
9080
9213
|
for (const td of ir.metadata.typeDefinitions) {
|
|
9081
9214
|
if (td.name === "Props" || td.name === `${componentName}Props`)
|
|
@@ -9159,7 +9292,7 @@ ${goFields.join(`
|
|
|
9159
9292
|
emitPropsStructHeader(lines, ir, propsTypeName, componentName) {
|
|
9160
9293
|
lines.push(`// ${propsTypeName} is the props type for the ${componentName} component.`);
|
|
9161
9294
|
lines.push(`type ${propsTypeName} struct {`);
|
|
9162
|
-
lines.push('\tScopeID string `json:"
|
|
9295
|
+
lines.push('\tScopeID string `json:"-"`');
|
|
9163
9296
|
lines.push('\tBfIsRoot bool `json:"-"`');
|
|
9164
9297
|
lines.push('\tBfIsChild bool `json:"-"`');
|
|
9165
9298
|
lines.push('\tBfParent string `json:"-"`');
|
|
@@ -9189,7 +9322,7 @@ ${goFields.join(`
|
|
|
9189
9322
|
const fieldName = capitalizeFieldName(signal.getter);
|
|
9190
9323
|
if (propFieldNames.has(fieldName))
|
|
9191
9324
|
continue;
|
|
9192
|
-
const jsonTag =
|
|
9325
|
+
const jsonTag = "-";
|
|
9193
9326
|
const synthType = this.state.synthStructTypes.get(signal.getter);
|
|
9194
9327
|
if (synthType) {
|
|
9195
9328
|
lines.push(` ${fieldName} ${typeInfoToGo(this.emitCtx, synthType)} \`json:"${jsonTag}"\``);
|
|
@@ -9221,7 +9354,7 @@ ${goFields.join(`
|
|
|
9221
9354
|
const fieldName = capitalizeFieldName(memo.name);
|
|
9222
9355
|
if (propFieldNames.has(fieldName))
|
|
9223
9356
|
continue;
|
|
9224
|
-
const jsonTag =
|
|
9357
|
+
const jsonTag = "-";
|
|
9225
9358
|
const goType = this.inferMemoType(memo, ir.metadata.signals, propsParamMap);
|
|
9226
9359
|
lines.push(` ${fieldName} ${goType} \`json:"${jsonTag}"\``);
|
|
9227
9360
|
}
|
|
@@ -9241,15 +9374,22 @@ ${goFields.join(`
|
|
|
9241
9374
|
...ir.metadata.memos.map((m) => capitalizeFieldName(m.name))
|
|
9242
9375
|
]);
|
|
9243
9376
|
for (const c of this.nonCollidingContextConsumers(takenProps)) {
|
|
9244
|
-
const jsonTag =
|
|
9377
|
+
const jsonTag = "-";
|
|
9245
9378
|
lines.push(` ${this.contextFieldName(c)} ${this.contextConsumerGoType(c)} \`json:"${jsonTag}"\``);
|
|
9246
9379
|
}
|
|
9380
|
+
const propDrivingFieldNames = new Set;
|
|
9381
|
+
for (const p of ir.metadata.propsParams) {
|
|
9382
|
+
propDrivingFieldNames.add(capitalizeFieldName(p.name));
|
|
9383
|
+
propDrivingFieldNames.add(capitalizeFieldName(p.sourceName ?? p.name));
|
|
9384
|
+
}
|
|
9247
9385
|
for (const nested of nestedComponents) {
|
|
9248
9386
|
if (this.isOrphanedClientOnlyNested(nested))
|
|
9249
9387
|
continue;
|
|
9250
9388
|
const elemType = nested.bodyChildren?.length ? this.loopBodyWrapperName(componentName, nested) : `${nested.name}Props`;
|
|
9251
9389
|
if (nested.isDynamic && !nested.isPropDerived) {
|
|
9252
9390
|
lines.push(` ${nested.name}s []${elemType} \`json:"-"\``);
|
|
9391
|
+
} else if (nested.isDynamic && nested.isPropDerived && !propDrivingFieldNames.has(`${nested.name}s`)) {
|
|
9392
|
+
lines.push(` ${nested.name}s []${elemType} \`json:"-"\``);
|
|
9253
9393
|
} else {
|
|
9254
9394
|
const jsonTag = this.claimJsonTag(this.toJsonTag(`${nested.name.charAt(0).toLowerCase()}${nested.name.slice(1)}s`), takenJsonTags);
|
|
9255
9395
|
lines.push(` ${nested.name}s []${elemType} \`json:"${jsonTag}"\``);
|
|
@@ -9260,7 +9400,7 @@ ${goFields.join(`
|
|
|
9260
9400
|
lines.push(` ${child.fieldName} ${child.name}Props \`json:"-"\``);
|
|
9261
9401
|
}
|
|
9262
9402
|
for (const slot of spreadSlots) {
|
|
9263
|
-
const jsonTag =
|
|
9403
|
+
const jsonTag = "-";
|
|
9264
9404
|
lines.push(` ${slot.slotId} map[string]any \`json:"${jsonTag}"\``);
|
|
9265
9405
|
}
|
|
9266
9406
|
}
|
|
@@ -9573,7 +9713,7 @@ ${goFields.join(`
|
|
|
9573
9713
|
}
|
|
9574
9714
|
const propTypeOverrides = buildPropTypeOverrides(this.emitCtx, ir);
|
|
9575
9715
|
for (const signal of ir.metadata.signals) {
|
|
9576
|
-
const match = this.extractPropFallback(signal.initialValue, signal
|
|
9716
|
+
const match = this.extractPropFallback(signal.initialValue, this.resolvedSignalParsed(signal));
|
|
9577
9717
|
if (!match)
|
|
9578
9718
|
continue;
|
|
9579
9719
|
if (result.has(match.propName))
|
|
@@ -9617,6 +9757,9 @@ ${goFields.join(`
|
|
|
9617
9757
|
}
|
|
9618
9758
|
return result;
|
|
9619
9759
|
}
|
|
9760
|
+
resolvedSignalParsed(signal) {
|
|
9761
|
+
return resolveSignalParsedThroughSeedPlan(this.state, signal);
|
|
9762
|
+
}
|
|
9620
9763
|
extractPropFallback(initialValue, preParsed) {
|
|
9621
9764
|
const structural = preParsed ? this.extractPropFallbackFromParsed(preParsed) : null;
|
|
9622
9765
|
if (structural)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@barefootjs/go-template",
|
|
3
|
-
"version": "0.31.
|
|
3
|
+
"version": "0.31.10",
|
|
4
4
|
"description": "Go html/template adapter for BarefootJS - generates Go template files from IR",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -49,7 +49,7 @@
|
|
|
49
49
|
"directory": "packages/adapter-go-template"
|
|
50
50
|
},
|
|
51
51
|
"dependencies": {
|
|
52
|
-
"@barefootjs/shared": "0.31.
|
|
52
|
+
"@barefootjs/shared": "0.31.10"
|
|
53
53
|
},
|
|
54
54
|
"peerDependencies": {
|
|
55
55
|
"@barefootjs/jsx": ">=0.2.0",
|
|
@@ -67,9 +67,9 @@
|
|
|
67
67
|
},
|
|
68
68
|
"devDependencies": {
|
|
69
69
|
"@barefootjs/adapter-tests": "0.1.0",
|
|
70
|
-
"@barefootjs/client": "0.31.
|
|
71
|
-
"@barefootjs/jsx": "0.31.
|
|
72
|
-
"@barefootjs/vite": "0.31.
|
|
70
|
+
"@barefootjs/client": "0.31.10",
|
|
71
|
+
"@barefootjs/jsx": "0.31.10",
|
|
72
|
+
"@barefootjs/vite": "0.31.10",
|
|
73
73
|
"vite": "^6.0.0"
|
|
74
74
|
}
|
|
75
75
|
}
|