@barefootjs/erb 0.31.1 → 0.31.3
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/index.js +1 -3
- package/dist/render-divergences.d.ts.map +1 -1
- package/dist/vite.js +415 -100
- package/package.json +5 -5
- package/src/render-divergences.ts +0 -14
- package/src/test-render.ts +32 -15
package/dist/index.js
CHANGED
|
@@ -189284,9 +189284,7 @@ var conformancePins = {
|
|
|
189284
189284
|
"date-method-uncatalogued": [{ code: "BF021", severity: "error", issue: "https://github.com/piconic-ai/barefootjs/issues/2356" }]
|
|
189285
189285
|
};
|
|
189286
189286
|
// src/render-divergences.ts
|
|
189287
|
-
var renderDivergences = {
|
|
189288
|
-
"aliased-destructured-prop": "aliased destructured prop `{ n: count }` loses its rename — template vars, ssr-defaults, and the props bridge all key off the local name, so the prop is always undefined (https://github.com/piconic-ai/barefootjs/issues/2524)"
|
|
189289
|
-
};
|
|
189287
|
+
var renderDivergences = {};
|
|
189290
189288
|
export {
|
|
189291
189289
|
renderDivergences,
|
|
189292
189290
|
erbAdapter,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"render-divergences.d.ts","sourceRoot":"","sources":["../src/render-divergences.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAA;AAExD,eAAO,MAAM,iBAAiB,EAAE,
|
|
1
|
+
{"version":3,"file":"render-divergences.d.ts","sourceRoot":"","sources":["../src/render-divergences.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAA;AAExD,eAAO,MAAM,iBAAiB,EAAE,iBAM/B,CAAA"}
|
package/dist/vite.js
CHANGED
|
@@ -4,8 +4,11 @@ import { dirname, resolve } from "node:path";
|
|
|
4
4
|
import { barefoot as coreBarefoot } from "@barefootjs/vite";
|
|
5
5
|
import { devModuleUrl, loadManifest, resolveDevOrigin, resolveScriptAssets, toPosixRelative } from "@barefootjs/vite";
|
|
6
6
|
|
|
7
|
+
// ../jsx/src/compiler.ts
|
|
8
|
+
import ts23 from "typescript";
|
|
9
|
+
|
|
7
10
|
// ../jsx/src/analyzer.ts
|
|
8
|
-
import
|
|
11
|
+
import ts9 from "typescript";
|
|
9
12
|
|
|
10
13
|
// ../jsx/src/expression-parser.ts
|
|
11
14
|
import ts from "typescript";
|
|
@@ -1922,6 +1925,29 @@ import ts5 from "typescript";
|
|
|
1922
1925
|
// ../jsx/src/ir-to-client-js/utils.ts
|
|
1923
1926
|
import ts3 from "typescript";
|
|
1924
1927
|
|
|
1928
|
+
// ../jsx/src/template-parts.ts
|
|
1929
|
+
function lookupPartToJsExpr(part, opts) {
|
|
1930
|
+
const key = opts?.useTemplate && part.templateKey ? part.templateKey : part.key;
|
|
1931
|
+
const obj = "{" + Object.entries(part.cases).map(([k, v]) => `${JSON.stringify(k)}: ${JSON.stringify(v)}`).join(", ") + "}";
|
|
1932
|
+
const typed = opts?.typed ? " as Record<string, string>" : "";
|
|
1933
|
+
return `(${obj}${typed})[${key}]`;
|
|
1934
|
+
}
|
|
1935
|
+
function templatePartsToJsExpr(parts, opts) {
|
|
1936
|
+
let result = "`";
|
|
1937
|
+
for (const part of parts) {
|
|
1938
|
+
if (part.type === "string") {
|
|
1939
|
+
result += opts?.useTemplate && part.templateValue ? part.templateValue : part.value;
|
|
1940
|
+
} else if (part.type === "ternary") {
|
|
1941
|
+
const cond = opts?.useTemplate && part.templateCondition ? part.templateCondition : part.condition;
|
|
1942
|
+
result += `\${${cond} ? '${part.whenTrue}' : '${part.whenFalse}'}`;
|
|
1943
|
+
} else if (part.type === "lookup") {
|
|
1944
|
+
result += `\${${lookupPartToJsExpr(part, opts)}}`;
|
|
1945
|
+
}
|
|
1946
|
+
}
|
|
1947
|
+
result += "`";
|
|
1948
|
+
return result;
|
|
1949
|
+
}
|
|
1950
|
+
|
|
1925
1951
|
// ../jsx/src/scanner/js-scanner.ts
|
|
1926
1952
|
import ts2 from "typescript";
|
|
1927
1953
|
|
|
@@ -2023,6 +2049,16 @@ function escapeHtml(text) {
|
|
|
2023
2049
|
}
|
|
2024
2050
|
// ../jsx/src/ir-to-client-js/csr-substitute.ts
|
|
2025
2051
|
import ts4 from "typescript";
|
|
2052
|
+
function extractFreeIdentifiersFromText(text) {
|
|
2053
|
+
if (!text || text.trim().length === 0)
|
|
2054
|
+
return new Set;
|
|
2055
|
+
const sf = ts4.createSourceFile("__free_ids__.ts", `(${text});`, ts4.ScriptTarget.Latest, true, ts4.ScriptKind.TS);
|
|
2056
|
+
const stmt = sf.statements[0];
|
|
2057
|
+
if (!stmt || !ts4.isExpressionStatement(stmt))
|
|
2058
|
+
return new Set;
|
|
2059
|
+
const expr = ts4.isParenthesizedExpression(stmt.expression) ? stmt.expression.expression : stmt.expression;
|
|
2060
|
+
return extractFreeIdentifiersFromNode(expr);
|
|
2061
|
+
}
|
|
2026
2062
|
|
|
2027
2063
|
// ../jsx/src/adapters/child-scope.ts
|
|
2028
2064
|
function derivesScopeFromSlot(comp) {
|
|
@@ -2073,6 +2109,27 @@ var SKELETON_PATH_FORCE_CLOSE_GROUPS = [
|
|
|
2073
2109
|
new Set(["li"])
|
|
2074
2110
|
];
|
|
2075
2111
|
|
|
2112
|
+
// ../jsx/src/props-binding.ts
|
|
2113
|
+
import ts6 from "typescript";
|
|
2114
|
+
function isIdentifierName(key) {
|
|
2115
|
+
if (key.length === 0)
|
|
2116
|
+
return false;
|
|
2117
|
+
for (let i = 0;i < key.length; ) {
|
|
2118
|
+
const cp = key.codePointAt(i);
|
|
2119
|
+
const ok = i === 0 ? ts6.isIdentifierStart(cp, ts6.ScriptTarget.Latest) : ts6.isIdentifierPart(cp, ts6.ScriptTarget.Latest);
|
|
2120
|
+
if (!ok)
|
|
2121
|
+
return false;
|
|
2122
|
+
i += cp > 65535 ? 2 : 1;
|
|
2123
|
+
}
|
|
2124
|
+
return true;
|
|
2125
|
+
}
|
|
2126
|
+
function propsDestructureBinding(p) {
|
|
2127
|
+
const callerKey = p.sourceName ?? p.name;
|
|
2128
|
+
const localName = p.name;
|
|
2129
|
+
const binding = callerKey === localName ? localName : `${isIdentifierName(callerKey) ? callerKey : JSON.stringify(callerKey)}: ${localName}`;
|
|
2130
|
+
return p.defaultValue ? `${binding} = ${p.defaultValue}` : binding;
|
|
2131
|
+
}
|
|
2132
|
+
|
|
2076
2133
|
// ../jsx/src/instrumentation.ts
|
|
2077
2134
|
var _counters = freshCounters();
|
|
2078
2135
|
function freshCounters() {
|
|
@@ -2086,14 +2143,14 @@ function freshCounters() {
|
|
|
2086
2143
|
}
|
|
2087
2144
|
|
|
2088
2145
|
// ../jsx/src/analyzer-context.ts
|
|
2089
|
-
import
|
|
2146
|
+
import ts8 from "typescript";
|
|
2090
2147
|
|
|
2091
2148
|
// ../jsx/src/strip-types.ts
|
|
2092
|
-
import
|
|
2149
|
+
import ts7 from "typescript";
|
|
2093
2150
|
|
|
2094
2151
|
// ../jsx/src/analyzer-context.ts
|
|
2095
|
-
var _typePrinter =
|
|
2096
|
-
var _blankTypeSourceFile =
|
|
2152
|
+
var _typePrinter = ts8.createPrinter({ removeComments: true, omitTrailingSemicolon: true });
|
|
2153
|
+
var _blankTypeSourceFile = ts8.createSourceFile("__bf_types__.ts", "", ts8.ScriptTarget.Latest);
|
|
2097
2154
|
|
|
2098
2155
|
// ../jsx/src/errors.ts
|
|
2099
2156
|
var ErrorCodes = {
|
|
@@ -2109,6 +2166,7 @@ var ErrorCodes = {
|
|
|
2109
2166
|
JSX_IN_LOCAL_FUNCTION: "BF045",
|
|
2110
2167
|
COMPONENT_REQUIRED_PROP_MISSING: "BF046",
|
|
2111
2168
|
JSX_BRANCH_LOCAL_IN_CALLBACK: "BF047",
|
|
2169
|
+
SIBLING_COMPONENT_NOT_COMPILED: "BF048",
|
|
2112
2170
|
SHARED_PROGRAM_REQUIRED: "BF050",
|
|
2113
2171
|
WRONG_PACKAGE_IMPORT: "BF051",
|
|
2114
2172
|
BUILTIN_REQUIRES_IMPORT: "BF054",
|
|
@@ -2138,6 +2196,7 @@ var errorMessages = {
|
|
|
2138
2196
|
[ErrorCodes.JSX_IN_LOCAL_FUNCTION]: "Local function returns JSX but cannot be inlined. Extract it as a top-level PascalCase component or use a single return statement.",
|
|
2139
2197
|
[ErrorCodes.COMPONENT_REQUIRED_PROP_MISSING]: "Built-in component is missing a required prop.",
|
|
2140
2198
|
[ErrorCodes.JSX_BRANCH_LOCAL_IN_CALLBACK]: "JSX-typed local declared inside an `if`-block cannot be referenced from a callback body (ref / event handler). " + "Render it as a child instead: `<div ref={...}>{local}</div>`.",
|
|
2199
|
+
[ErrorCodes.SIBLING_COMPONENT_NOT_COMPILED]: "Referenced component did not compile to a template, so this reference would throw " + "`ReferenceError` at render time. Multi-return JSX dispatch (a `switch` or `if`/`else` " + "chain across multiple JSX-returning branches) cannot compile as a component in a " + `'use client' file. Extract it to a separate non-"use client" file (where it is preserved ` + "verbatim, see #932), or rewrite it as a single-return ternary/conditional chain so the " + "component pipeline can compile it.",
|
|
2141
2200
|
[ErrorCodes.SHARED_PROGRAM_REQUIRED]: "Shared ts.Program required for type-based reactivity classification. This source imports a Reactive<T>-branded library (e.g. @barefootjs/form) whose getters cannot be classified by regex alone. Pass `options.program` (built via `createProgramForCorpus`) so the analyzer can resolve the brand through the TypeChecker.",
|
|
2142
2201
|
[ErrorCodes.WRONG_PACKAGE_IMPORT]: "Import from wrong package.",
|
|
2143
2202
|
[ErrorCodes.BUILTIN_REQUIRES_IMPORT]: "Built-in <Async> / <Region> must be imported from '@barefootjs/client'. " + "The compiler recognises these tags by their import (not by tag name), " + "so an unimported tag with this name is treated as an undeclared component.",
|
|
@@ -2311,6 +2370,54 @@ var CLIENT_EXPORTS = new Set([
|
|
|
2311
2370
|
"Async",
|
|
2312
2371
|
"Region"
|
|
2313
2372
|
]);
|
|
2373
|
+
function extractFreeIdentifiersFromNode(node) {
|
|
2374
|
+
const ids = new Set;
|
|
2375
|
+
const boundNames = new Set;
|
|
2376
|
+
function addBindingNames(name, out) {
|
|
2377
|
+
if (ts9.isIdentifier(name))
|
|
2378
|
+
out.push(name.text);
|
|
2379
|
+
else if (ts9.isObjectBindingPattern(name))
|
|
2380
|
+
name.elements.forEach((e) => addBindingNames(e.name, out));
|
|
2381
|
+
else if (ts9.isArrayBindingPattern(name))
|
|
2382
|
+
name.elements.forEach((e) => {
|
|
2383
|
+
if (!ts9.isOmittedExpression(e))
|
|
2384
|
+
addBindingNames(e.name, out);
|
|
2385
|
+
});
|
|
2386
|
+
}
|
|
2387
|
+
function visit(n) {
|
|
2388
|
+
if (ts9.isTypeNode(n))
|
|
2389
|
+
return;
|
|
2390
|
+
if (ts9.isIdentifier(n)) {
|
|
2391
|
+
const parent = n.parent;
|
|
2392
|
+
if (parent && ts9.isPropertyAccessExpression(parent) && parent.name === n)
|
|
2393
|
+
return;
|
|
2394
|
+
if (parent && ts9.isPropertyAssignment(parent) && parent.name === n)
|
|
2395
|
+
return;
|
|
2396
|
+
if (parent && ts9.isParameter(parent) && parent.name === n)
|
|
2397
|
+
return;
|
|
2398
|
+
if (parent && ts9.isVariableDeclaration(parent) && parent.name === n)
|
|
2399
|
+
return;
|
|
2400
|
+
if (boundNames.has(n.text))
|
|
2401
|
+
return;
|
|
2402
|
+
ids.add(n.text);
|
|
2403
|
+
return;
|
|
2404
|
+
}
|
|
2405
|
+
if (ts9.isArrowFunction(n)) {
|
|
2406
|
+
const params = [];
|
|
2407
|
+
for (const p of n.parameters)
|
|
2408
|
+
addBindingNames(p.name, params);
|
|
2409
|
+
for (const name of params)
|
|
2410
|
+
boundNames.add(name);
|
|
2411
|
+
ts9.forEachChild(n, visit);
|
|
2412
|
+
for (const name of params)
|
|
2413
|
+
boundNames.delete(name);
|
|
2414
|
+
return;
|
|
2415
|
+
}
|
|
2416
|
+
ts9.forEachChild(n, visit);
|
|
2417
|
+
}
|
|
2418
|
+
visit(node);
|
|
2419
|
+
return ids;
|
|
2420
|
+
}
|
|
2314
2421
|
var BROWSER_ONLY_CLIENT_APIS = new Set([
|
|
2315
2422
|
"useContext",
|
|
2316
2423
|
"provideContext",
|
|
@@ -2329,7 +2436,7 @@ var REACTIVE_PRIMITIVES = new Set([
|
|
|
2329
2436
|
]);
|
|
2330
2437
|
|
|
2331
2438
|
// ../jsx/src/jsx-to-ir.ts
|
|
2332
|
-
import
|
|
2439
|
+
import ts12 from "typescript";
|
|
2333
2440
|
|
|
2334
2441
|
// ../jsx/src/types.ts
|
|
2335
2442
|
var SCOPE_FORBIDDEN = {
|
|
@@ -2411,10 +2518,10 @@ function findReachableNames(primaryRefs, declarations) {
|
|
|
2411
2518
|
}
|
|
2412
2519
|
|
|
2413
2520
|
// ../jsx/src/reactivity-checker.ts
|
|
2414
|
-
import
|
|
2521
|
+
import ts10 from "typescript";
|
|
2415
2522
|
|
|
2416
2523
|
// ../jsx/src/free-refs.ts
|
|
2417
|
-
import
|
|
2524
|
+
import ts11 from "typescript";
|
|
2418
2525
|
var _bindingMapCache = new WeakMap;
|
|
2419
2526
|
|
|
2420
2527
|
// ../jsx/src/to-locale-date-lowering.ts
|
|
@@ -2732,6 +2839,83 @@ var toLocaleDatePlugin = {
|
|
|
2732
2839
|
}
|
|
2733
2840
|
};
|
|
2734
2841
|
|
|
2842
|
+
// ../jsx/src/scope/binding-scope.ts
|
|
2843
|
+
class BindingScope {
|
|
2844
|
+
frames;
|
|
2845
|
+
static EMPTY = new BindingScope([]);
|
|
2846
|
+
constructor(frames) {
|
|
2847
|
+
this.frames = frames;
|
|
2848
|
+
}
|
|
2849
|
+
enterLoopRow(loop) {
|
|
2850
|
+
const bindings = new Map;
|
|
2851
|
+
if (loop.paramBindings && loop.paramBindings.length > 0) {
|
|
2852
|
+
for (const b of loop.paramBindings)
|
|
2853
|
+
bindings.set(b.name, { source: "destructure" });
|
|
2854
|
+
} else {
|
|
2855
|
+
bindings.set(loop.param, { source: "item" });
|
|
2856
|
+
}
|
|
2857
|
+
if (loop.index != null)
|
|
2858
|
+
bindings.set(loop.index, { source: "index" });
|
|
2859
|
+
for (const name of loop.preamble?.declaredNames ?? [])
|
|
2860
|
+
bindings.set(name, { source: "preamble" });
|
|
2861
|
+
const frame = { kind: "loop-row", bindings };
|
|
2862
|
+
return new BindingScope([frame, ...this.frames]);
|
|
2863
|
+
}
|
|
2864
|
+
enterCallback(params) {
|
|
2865
|
+
const bindings = new Map;
|
|
2866
|
+
for (const name of params)
|
|
2867
|
+
bindings.set(name, { source: "param" });
|
|
2868
|
+
const frame = { kind: "callback", bindings };
|
|
2869
|
+
return new BindingScope([frame, ...this.frames]);
|
|
2870
|
+
}
|
|
2871
|
+
isBound(name) {
|
|
2872
|
+
for (const frame of this.frames) {
|
|
2873
|
+
if (frame.bindings.has(name))
|
|
2874
|
+
return true;
|
|
2875
|
+
}
|
|
2876
|
+
return false;
|
|
2877
|
+
}
|
|
2878
|
+
lookup(name) {
|
|
2879
|
+
for (let depth = 0;depth < this.frames.length; depth++) {
|
|
2880
|
+
const frame = this.frames[depth];
|
|
2881
|
+
const binding = frame.bindings.get(name);
|
|
2882
|
+
if (binding)
|
|
2883
|
+
return { depth, frame, binding };
|
|
2884
|
+
}
|
|
2885
|
+
return null;
|
|
2886
|
+
}
|
|
2887
|
+
boundNames() {
|
|
2888
|
+
if (this.boundNamesCache)
|
|
2889
|
+
return this.boundNamesCache;
|
|
2890
|
+
const names = new Set;
|
|
2891
|
+
for (const frame of this.frames) {
|
|
2892
|
+
for (const name of frame.bindings.keys())
|
|
2893
|
+
names.add(name);
|
|
2894
|
+
}
|
|
2895
|
+
this.boundNamesCache = names;
|
|
2896
|
+
return names;
|
|
2897
|
+
}
|
|
2898
|
+
boundNamesCache;
|
|
2899
|
+
valueBoundNamesCache;
|
|
2900
|
+
valueBoundNames() {
|
|
2901
|
+
if (this.valueBoundNamesCache)
|
|
2902
|
+
return this.valueBoundNamesCache;
|
|
2903
|
+
const names = new Set;
|
|
2904
|
+
for (const frame of this.frames) {
|
|
2905
|
+
for (const [name, binding] of frame.bindings) {
|
|
2906
|
+
if (binding.source === "item" || binding.source === "index" || binding.source === "destructure") {
|
|
2907
|
+
names.add(name);
|
|
2908
|
+
}
|
|
2909
|
+
}
|
|
2910
|
+
}
|
|
2911
|
+
this.valueBoundNamesCache = names;
|
|
2912
|
+
return names;
|
|
2913
|
+
}
|
|
2914
|
+
asShadowPredicate() {
|
|
2915
|
+
return (name) => this.isBound(name);
|
|
2916
|
+
}
|
|
2917
|
+
}
|
|
2918
|
+
|
|
2735
2919
|
// ../jsx/src/jsx-to-ir.ts
|
|
2736
2920
|
var EMPTY_BOUND = new Set;
|
|
2737
2921
|
var constInitializerCache = new WeakMap;
|
|
@@ -2828,13 +3012,13 @@ var KEYWORDS_AND_GLOBALS = new Set([
|
|
|
2828
3012
|
]);
|
|
2829
3013
|
|
|
2830
3014
|
// ../jsx/src/ir-to-client-js/walk-prop-accesses.ts
|
|
2831
|
-
import
|
|
3015
|
+
import ts13 from "typescript";
|
|
2832
3016
|
|
|
2833
3017
|
// ../jsx/src/value-references.ts
|
|
2834
|
-
import
|
|
3018
|
+
import ts14 from "typescript";
|
|
2835
3019
|
|
|
2836
3020
|
// ../jsx/src/relocate.ts
|
|
2837
|
-
import
|
|
3021
|
+
import ts15 from "typescript";
|
|
2838
3022
|
|
|
2839
3023
|
// ../jsx/src/lowering-registry.ts
|
|
2840
3024
|
var plugins = [];
|
|
@@ -3051,10 +3235,10 @@ function matchSearchParamsMethodCall(callee, args, localNames) {
|
|
|
3051
3235
|
}
|
|
3052
3236
|
|
|
3053
3237
|
// ../jsx/src/ir-to-client-js/prune-unused-prop-extractions.ts
|
|
3054
|
-
import
|
|
3238
|
+
import ts16 from "typescript";
|
|
3055
3239
|
|
|
3056
3240
|
// ../jsx/src/ir-to-client-js/control-flow/plan/lazy-preamble.ts
|
|
3057
|
-
import
|
|
3241
|
+
import ts17 from "typescript";
|
|
3058
3242
|
var NO_PREAMBLE = {
|
|
3059
3243
|
lazySafe: true,
|
|
3060
3244
|
facts: { declaredNames: new Set, freeNames: new Set }
|
|
@@ -3104,7 +3288,7 @@ var INERT_BINDING_GLOBALS = new Set([
|
|
|
3104
3288
|
]);
|
|
3105
3289
|
|
|
3106
3290
|
// ../jsx/src/ir-to-client-js/emit-reactive.ts
|
|
3107
|
-
import
|
|
3291
|
+
import ts18 from "typescript";
|
|
3108
3292
|
|
|
3109
3293
|
// ../jsx/src/ir-to-client-js/control-flow/stringify/event-delegation.ts
|
|
3110
3294
|
var NON_BUBBLING_EVENTS = new Set([
|
|
@@ -3119,7 +3303,7 @@ var NON_BUBBLING_EVENTS = new Set([
|
|
|
3119
3303
|
]);
|
|
3120
3304
|
|
|
3121
3305
|
// ../jsx/src/ir-to-client-js/rewrite-props-object.ts
|
|
3122
|
-
import
|
|
3306
|
+
import ts19 from "typescript";
|
|
3123
3307
|
|
|
3124
3308
|
// ../jsx/src/ir-to-client-js/source-map.ts
|
|
3125
3309
|
var BASE64_CHARS = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
|
@@ -3210,15 +3394,15 @@ class SourceMapGenerator {
|
|
|
3210
3394
|
}
|
|
3211
3395
|
|
|
3212
3396
|
// ../jsx/src/preprocess-inline-jsx-callbacks.ts
|
|
3213
|
-
import
|
|
3397
|
+
import ts20 from "typescript";
|
|
3214
3398
|
|
|
3215
3399
|
// ../jsx/src/ssr-defaults.ts
|
|
3216
|
-
import
|
|
3400
|
+
import ts21 from "typescript";
|
|
3217
3401
|
var UNRESOLVED = Symbol("unresolved");
|
|
3218
3402
|
var NO_RETURN = Symbol("no-return");
|
|
3219
3403
|
|
|
3220
3404
|
// ../jsx/src/augment-inherited-props.ts
|
|
3221
|
-
import
|
|
3405
|
+
import ts22 from "typescript";
|
|
3222
3406
|
function collectContextConsumers(metadata) {
|
|
3223
3407
|
const constants = metadata.localConstants ?? [];
|
|
3224
3408
|
const contextDefaults = new Map;
|
|
@@ -3250,47 +3434,47 @@ function collectContextConsumers(metadata) {
|
|
|
3250
3434
|
}
|
|
3251
3435
|
function parseUseContextArg(source) {
|
|
3252
3436
|
const expr = parseSingleExpression(source);
|
|
3253
|
-
if (!expr || !
|
|
3437
|
+
if (!expr || !ts22.isCallExpression(expr))
|
|
3254
3438
|
return null;
|
|
3255
|
-
if (!
|
|
3439
|
+
if (!ts22.isIdentifier(expr.expression) || expr.expression.text !== "useContext")
|
|
3256
3440
|
return null;
|
|
3257
3441
|
if (expr.arguments.length !== 1)
|
|
3258
3442
|
return null;
|
|
3259
3443
|
const arg = expr.arguments[0];
|
|
3260
|
-
return
|
|
3444
|
+
return ts22.isIdentifier(arg) ? arg.text : null;
|
|
3261
3445
|
}
|
|
3262
3446
|
function parseCreateContextDefault(source) {
|
|
3263
3447
|
const expr = parseSingleExpression(source);
|
|
3264
|
-
if (!expr || !
|
|
3448
|
+
if (!expr || !ts22.isCallExpression(expr))
|
|
3265
3449
|
return null;
|
|
3266
3450
|
if (expr.arguments.length === 0)
|
|
3267
3451
|
return null;
|
|
3268
3452
|
const arg = expr.arguments[0];
|
|
3269
|
-
if (
|
|
3453
|
+
if (ts22.isStringLiteral(arg) || ts22.isNoSubstitutionTemplateLiteral(arg))
|
|
3270
3454
|
return arg.text;
|
|
3271
|
-
if (
|
|
3455
|
+
if (ts22.isNumericLiteral(arg))
|
|
3272
3456
|
return Number(arg.text);
|
|
3273
|
-
if (arg.kind ===
|
|
3457
|
+
if (arg.kind === ts22.SyntaxKind.TrueKeyword)
|
|
3274
3458
|
return true;
|
|
3275
|
-
if (arg.kind ===
|
|
3459
|
+
if (arg.kind === ts22.SyntaxKind.FalseKeyword)
|
|
3276
3460
|
return false;
|
|
3277
3461
|
return null;
|
|
3278
3462
|
}
|
|
3279
3463
|
function isObjectLiteralCreateContextDefault(source) {
|
|
3280
3464
|
const expr = parseSingleExpression(source);
|
|
3281
|
-
if (!expr || !
|
|
3465
|
+
if (!expr || !ts22.isCallExpression(expr))
|
|
3282
3466
|
return false;
|
|
3283
3467
|
if (expr.arguments.length === 0)
|
|
3284
3468
|
return false;
|
|
3285
|
-
return
|
|
3469
|
+
return ts22.isObjectLiteralExpression(expr.arguments[0]);
|
|
3286
3470
|
}
|
|
3287
3471
|
function parseSingleExpression(source) {
|
|
3288
|
-
const sf =
|
|
3472
|
+
const sf = ts22.createSourceFile("__ctx.ts", `(${source})`, ts22.ScriptTarget.Latest, false);
|
|
3289
3473
|
const stmt = sf.statements[0];
|
|
3290
|
-
if (!stmt || !
|
|
3474
|
+
if (!stmt || !ts22.isExpressionStatement(stmt))
|
|
3291
3475
|
return null;
|
|
3292
3476
|
let e = stmt.expression;
|
|
3293
|
-
while (
|
|
3477
|
+
while (ts22.isParenthesizedExpression(e))
|
|
3294
3478
|
e = e.expression;
|
|
3295
3479
|
return e;
|
|
3296
3480
|
}
|
|
@@ -3315,25 +3499,25 @@ function augmentInheritedPropAccesses(ir) {
|
|
|
3315
3499
|
const pinCoalesceLiterals = (s) => {
|
|
3316
3500
|
if (!s || !s.includes(propsObj))
|
|
3317
3501
|
return;
|
|
3318
|
-
const sf =
|
|
3502
|
+
const sf = ts22.createSourceFile("__aug.ts", `(${s})`, ts22.ScriptTarget.Latest, false);
|
|
3319
3503
|
const visit = (n) => {
|
|
3320
|
-
if (
|
|
3504
|
+
if (ts22.isBinaryExpression(n) && (n.operatorToken.kind === ts22.SyntaxKind.QuestionQuestionToken || n.operatorToken.kind === ts22.SyntaxKind.BarBarToken)) {
|
|
3321
3505
|
let left = n.left;
|
|
3322
|
-
while (
|
|
3506
|
+
while (ts22.isParenthesizedExpression(left))
|
|
3323
3507
|
left = left.expression;
|
|
3324
|
-
if (
|
|
3508
|
+
if (ts22.isPropertyAccessExpression(left) && ts22.isIdentifier(left.expression) && left.expression.text === propsObj) {
|
|
3325
3509
|
const name = left.name.text;
|
|
3326
3510
|
let right = n.right;
|
|
3327
|
-
while (
|
|
3511
|
+
while (ts22.isParenthesizedExpression(right))
|
|
3328
3512
|
right = right.expression;
|
|
3329
|
-
if (
|
|
3513
|
+
if (ts22.isPrefixUnaryExpression(right))
|
|
3330
3514
|
right = right.operand;
|
|
3331
|
-
const kind =
|
|
3515
|
+
const kind = ts22.isNumericLiteral(right) ? "number" : right.kind === ts22.SyntaxKind.TrueKeyword || right.kind === ts22.SyntaxKind.FalseKeyword ? "boolean" : ts22.isStringLiteralLike(right) ? "string" : null;
|
|
3332
3516
|
if (kind && !coalesceLiteralTypes.has(name))
|
|
3333
3517
|
coalesceLiteralTypes.set(name, kind);
|
|
3334
3518
|
}
|
|
3335
3519
|
}
|
|
3336
|
-
|
|
3520
|
+
ts22.forEachChild(n, visit);
|
|
3337
3521
|
};
|
|
3338
3522
|
visit(sf);
|
|
3339
3523
|
};
|
|
@@ -3444,33 +3628,33 @@ function augmentInheritedPropAccesses(ir) {
|
|
|
3444
3628
|
}
|
|
3445
3629
|
}
|
|
3446
3630
|
function parseStaticStringConst(source) {
|
|
3447
|
-
const sf =
|
|
3631
|
+
const sf = ts22.createSourceFile("__const.ts", `const __x = (${source});`, ts22.ScriptTarget.Latest, false);
|
|
3448
3632
|
const stmt = sf.statements[0];
|
|
3449
|
-
if (!stmt || !
|
|
3633
|
+
if (!stmt || !ts22.isVariableStatement(stmt))
|
|
3450
3634
|
return null;
|
|
3451
3635
|
let init = stmt.declarationList.declarations[0]?.initializer;
|
|
3452
|
-
while (init &&
|
|
3636
|
+
while (init && ts22.isParenthesizedExpression(init))
|
|
3453
3637
|
init = init.expression;
|
|
3454
3638
|
if (!init)
|
|
3455
3639
|
return null;
|
|
3456
|
-
if (
|
|
3640
|
+
if (ts22.isStringLiteral(init) || ts22.isNoSubstitutionTemplateLiteral(init)) {
|
|
3457
3641
|
return init.text;
|
|
3458
3642
|
}
|
|
3459
3643
|
return evalStringArrayJoin(source);
|
|
3460
3644
|
}
|
|
3461
3645
|
function evalTemplateOfStringConsts(source, resolved) {
|
|
3462
|
-
const sf =
|
|
3646
|
+
const sf = ts22.createSourceFile("__const.ts", `const __x = (${source});`, ts22.ScriptTarget.Latest, false);
|
|
3463
3647
|
const stmt = sf.statements[0];
|
|
3464
|
-
if (!stmt || !
|
|
3648
|
+
if (!stmt || !ts22.isVariableStatement(stmt))
|
|
3465
3649
|
return null;
|
|
3466
3650
|
let init = stmt.declarationList.declarations[0]?.initializer;
|
|
3467
|
-
while (init &&
|
|
3651
|
+
while (init && ts22.isParenthesizedExpression(init))
|
|
3468
3652
|
init = init.expression;
|
|
3469
|
-
if (!init || !
|
|
3653
|
+
if (!init || !ts22.isTemplateExpression(init))
|
|
3470
3654
|
return null;
|
|
3471
3655
|
let out = init.head.text;
|
|
3472
3656
|
for (const span of init.templateSpans) {
|
|
3473
|
-
if (!
|
|
3657
|
+
if (!ts22.isIdentifier(span.expression))
|
|
3474
3658
|
return null;
|
|
3475
3659
|
const value = resolved.get(span.expression.text);
|
|
3476
3660
|
if (value === undefined)
|
|
@@ -3501,30 +3685,30 @@ function lookupStaticRecordLiteral(objectName, key, constants) {
|
|
|
3501
3685
|
const constInfo = (constants ?? []).find((c) => c.name === objectName && c.isModule);
|
|
3502
3686
|
if (constInfo?.value === undefined)
|
|
3503
3687
|
return null;
|
|
3504
|
-
const sf =
|
|
3688
|
+
const sf = ts22.createSourceFile("__rec.ts", `(${constInfo.value})`, ts22.ScriptTarget.Latest, true);
|
|
3505
3689
|
if (sf.statements.length !== 1)
|
|
3506
3690
|
return null;
|
|
3507
3691
|
const stmt = sf.statements[0];
|
|
3508
|
-
if (!
|
|
3692
|
+
if (!ts22.isExpressionStatement(stmt))
|
|
3509
3693
|
return null;
|
|
3510
3694
|
let parsed = stmt.expression;
|
|
3511
|
-
while (
|
|
3695
|
+
while (ts22.isParenthesizedExpression(parsed))
|
|
3512
3696
|
parsed = parsed.expression;
|
|
3513
|
-
if (!
|
|
3697
|
+
if (!ts22.isObjectLiteralExpression(parsed))
|
|
3514
3698
|
return null;
|
|
3515
3699
|
for (const prop of parsed.properties) {
|
|
3516
|
-
if (!
|
|
3700
|
+
if (!ts22.isPropertyAssignment(prop))
|
|
3517
3701
|
continue;
|
|
3518
3702
|
const name = prop.name;
|
|
3519
|
-
const propKey =
|
|
3703
|
+
const propKey = ts22.isIdentifier(name) || ts22.isStringLiteral(name) || ts22.isNoSubstitutionTemplateLiteral(name) ? name.text : null;
|
|
3520
3704
|
if (propKey !== key)
|
|
3521
3705
|
continue;
|
|
3522
3706
|
let v = prop.initializer;
|
|
3523
|
-
while (
|
|
3707
|
+
while (ts22.isParenthesizedExpression(v))
|
|
3524
3708
|
v = v.expression;
|
|
3525
|
-
if (
|
|
3709
|
+
if (ts22.isNumericLiteral(v))
|
|
3526
3710
|
return { kind: "number", text: v.text };
|
|
3527
|
-
if (
|
|
3711
|
+
if (ts22.isStringLiteral(v) || ts22.isNoSubstitutionTemplateLiteral(v)) {
|
|
3528
3712
|
return { kind: "string", text: v.text };
|
|
3529
3713
|
}
|
|
3530
3714
|
return null;
|
|
@@ -3532,28 +3716,28 @@ function lookupStaticRecordLiteral(objectName, key, constants) {
|
|
|
3532
3716
|
return null;
|
|
3533
3717
|
}
|
|
3534
3718
|
function evalStringArrayJoin(source) {
|
|
3535
|
-
const sf =
|
|
3719
|
+
const sf = ts22.createSourceFile("__join.ts", `const __x = (${source});`, ts22.ScriptTarget.Latest, false);
|
|
3536
3720
|
const stmt = sf.statements[0];
|
|
3537
|
-
if (!stmt || !
|
|
3721
|
+
if (!stmt || !ts22.isVariableStatement(stmt))
|
|
3538
3722
|
return null;
|
|
3539
3723
|
let node = stmt.declarationList.declarations[0]?.initializer;
|
|
3540
|
-
while (node &&
|
|
3724
|
+
while (node && ts22.isParenthesizedExpression(node))
|
|
3541
3725
|
node = node.expression;
|
|
3542
|
-
if (!node || !
|
|
3726
|
+
if (!node || !ts22.isCallExpression(node))
|
|
3543
3727
|
return null;
|
|
3544
3728
|
const callee = node.expression;
|
|
3545
|
-
if (!
|
|
3729
|
+
if (!ts22.isPropertyAccessExpression(callee))
|
|
3546
3730
|
return null;
|
|
3547
3731
|
if (callee.name.text !== "join")
|
|
3548
3732
|
return null;
|
|
3549
3733
|
let recv = callee.expression;
|
|
3550
|
-
while (
|
|
3734
|
+
while (ts22.isParenthesizedExpression(recv))
|
|
3551
3735
|
recv = recv.expression;
|
|
3552
|
-
if (!
|
|
3736
|
+
if (!ts22.isArrayLiteralExpression(recv))
|
|
3553
3737
|
return null;
|
|
3554
3738
|
const parts = [];
|
|
3555
3739
|
for (const el of recv.elements) {
|
|
3556
|
-
if (
|
|
3740
|
+
if (ts22.isStringLiteral(el) || ts22.isNoSubstitutionTemplateLiteral(el)) {
|
|
3557
3741
|
parts.push(el.text);
|
|
3558
3742
|
} else {
|
|
3559
3743
|
return null;
|
|
@@ -3562,7 +3746,7 @@ function evalStringArrayJoin(source) {
|
|
|
3562
3746
|
let sep = ",";
|
|
3563
3747
|
if (node.arguments.length >= 1) {
|
|
3564
3748
|
const arg = node.arguments[0];
|
|
3565
|
-
if (
|
|
3749
|
+
if (ts22.isStringLiteral(arg) || ts22.isNoSubstitutionTemplateLiteral(arg))
|
|
3566
3750
|
sep = arg.text;
|
|
3567
3751
|
else
|
|
3568
3752
|
return null;
|
|
@@ -3570,11 +3754,11 @@ function evalStringArrayJoin(source) {
|
|
|
3570
3754
|
return parts.join(sep);
|
|
3571
3755
|
}
|
|
3572
3756
|
function parseRecordIndexAccess(val, localConstants, propsParams, resolveKey) {
|
|
3573
|
-
if (!
|
|
3757
|
+
if (!ts22.isElementAccessExpression(val))
|
|
3574
3758
|
return null;
|
|
3575
3759
|
const obj = val.expression;
|
|
3576
3760
|
const arg = val.argumentExpression;
|
|
3577
|
-
if (!
|
|
3761
|
+
if (!ts22.isIdentifier(obj) || !ts22.isIdentifier(arg))
|
|
3578
3762
|
return null;
|
|
3579
3763
|
let indexPropName;
|
|
3580
3764
|
let defaultKey;
|
|
@@ -3590,35 +3774,35 @@ function parseRecordIndexAccess(val, localConstants, propsParams, resolveKey) {
|
|
|
3590
3774
|
const constInfo = localConstants.find((c) => c.name === obj.text && c.isModule);
|
|
3591
3775
|
if (constInfo?.value === undefined)
|
|
3592
3776
|
return null;
|
|
3593
|
-
const sf =
|
|
3777
|
+
const sf = ts22.createSourceFile("__rec.ts", `(${constInfo.value})`, ts22.ScriptTarget.Latest, true);
|
|
3594
3778
|
if (sf.statements.length !== 1)
|
|
3595
3779
|
return null;
|
|
3596
3780
|
const stmt = sf.statements[0];
|
|
3597
|
-
if (!
|
|
3781
|
+
if (!ts22.isExpressionStatement(stmt))
|
|
3598
3782
|
return null;
|
|
3599
3783
|
let parsed = stmt.expression;
|
|
3600
|
-
while (
|
|
3784
|
+
while (ts22.isParenthesizedExpression(parsed))
|
|
3601
3785
|
parsed = parsed.expression;
|
|
3602
|
-
if (!
|
|
3786
|
+
if (!ts22.isObjectLiteralExpression(parsed))
|
|
3603
3787
|
return null;
|
|
3604
3788
|
const entries = [];
|
|
3605
3789
|
for (const prop of parsed.properties) {
|
|
3606
|
-
if (!
|
|
3790
|
+
if (!ts22.isPropertyAssignment(prop))
|
|
3607
3791
|
return null;
|
|
3608
3792
|
let key;
|
|
3609
|
-
if (
|
|
3793
|
+
if (ts22.isIdentifier(prop.name)) {
|
|
3610
3794
|
key = prop.name.text;
|
|
3611
|
-
} else if (
|
|
3795
|
+
} else if (ts22.isStringLiteral(prop.name) || ts22.isNoSubstitutionTemplateLiteral(prop.name)) {
|
|
3612
3796
|
key = prop.name.text;
|
|
3613
3797
|
} else {
|
|
3614
3798
|
return null;
|
|
3615
3799
|
}
|
|
3616
3800
|
let v = prop.initializer;
|
|
3617
|
-
while (
|
|
3801
|
+
while (ts22.isParenthesizedExpression(v))
|
|
3618
3802
|
v = v.expression;
|
|
3619
|
-
if (
|
|
3803
|
+
if (ts22.isNumericLiteral(v)) {
|
|
3620
3804
|
entries.push({ key, value: { kind: "number", text: v.text } });
|
|
3621
|
-
} else if (
|
|
3805
|
+
} else if (ts22.isStringLiteral(v) || ts22.isNoSubstitutionTemplateLiteral(v)) {
|
|
3622
3806
|
entries.push({ key, value: { kind: "string", text: v.text } });
|
|
3623
3807
|
} else {
|
|
3624
3808
|
return null;
|
|
@@ -3674,7 +3858,7 @@ function computeSsrSeedPlan(metadata) {
|
|
|
3674
3858
|
// ../jsx/src/rich-type-refusal.ts
|
|
3675
3859
|
var EMPTY_BINDINGS2 = new Map;
|
|
3676
3860
|
// ../jsx/src/shared-program.ts
|
|
3677
|
-
import
|
|
3861
|
+
import ts24 from "typescript";
|
|
3678
3862
|
// ../jsx/src/adapters/interface.ts
|
|
3679
3863
|
class BaseAdapter {
|
|
3680
3864
|
renderChildren(children) {
|
|
@@ -3750,7 +3934,7 @@ class JsxAdapter extends BaseAdapter {
|
|
|
3750
3934
|
}
|
|
3751
3935
|
const rawInitialValue = preserveTypes ? signal.typedInitialValue ?? signal.initialValue : signal.initialValue;
|
|
3752
3936
|
const initialValue = rawInitialValue.trim().startsWith("{") ? `(${rawInitialValue})` : rawInitialValue;
|
|
3753
|
-
const needsTypeAssertion = preserveTypes && !signal.typedInitialValue && signal.type.kind !== "unknown" && signal.type.kind !== "primitive";
|
|
3937
|
+
const needsTypeAssertion = preserveTypes && !signal.typedInitialValue && signal.type.kind !== "unknown" && signal.type.kind !== "primitive" && signal.type.raw !== "object";
|
|
3754
3938
|
if (needsTypeAssertion) {
|
|
3755
3939
|
lines.push(` const ${signal.getter} = () => ${initialValue} as ${signal.type.raw}`);
|
|
3756
3940
|
} else {
|
|
@@ -3769,12 +3953,16 @@ class JsxAdapter extends BaseAdapter {
|
|
|
3769
3953
|
const computation = preserveTypes ? memo.typedComputation ?? memo.computation : memo.computation;
|
|
3770
3954
|
lines.push(` const ${memo.name} = ${computation}`);
|
|
3771
3955
|
}
|
|
3956
|
+
const moduleScopeNames = this.moduleScopeDeclarationNames(ir);
|
|
3772
3957
|
for (const constant of ir.metadata.localConstants) {
|
|
3773
3958
|
if (constant.isExported)
|
|
3774
3959
|
continue;
|
|
3960
|
+
if (moduleScopeNames.has(constant.name))
|
|
3961
|
+
continue;
|
|
3775
3962
|
const keyword = constant.declarationKind ?? "const";
|
|
3776
3963
|
if (!constant.value) {
|
|
3777
|
-
|
|
3964
|
+
const typeAnnotation = preserveTypes && (constant.typeAnnotation ?? constant.type) ? `: ${constant.typeAnnotation ?? constant.type?.raw}` : "";
|
|
3965
|
+
lines.push(` ${keyword} ${constant.name}${typeAnnotation}`);
|
|
3778
3966
|
continue;
|
|
3779
3967
|
}
|
|
3780
3968
|
const value = constant.value.trim();
|
|
@@ -3783,9 +3971,12 @@ class JsxAdapter extends BaseAdapter {
|
|
|
3783
3971
|
if (!reachable.has(constant.name))
|
|
3784
3972
|
continue;
|
|
3785
3973
|
const constValue = preserveTypes ? constant.typedValue ?? constant.value : constant.value;
|
|
3786
|
-
|
|
3974
|
+
const letTypeAnnotation = preserveTypes && keyword === "let" && constant.typeAnnotation ? `: ${constant.typeAnnotation}` : "";
|
|
3975
|
+
lines.push(` ${keyword} ${constant.name}${letTypeAnnotation} = ${constValue}`);
|
|
3787
3976
|
}
|
|
3788
3977
|
for (const func of localFunctions) {
|
|
3978
|
+
if (moduleScopeNames.has(func.name))
|
|
3979
|
+
continue;
|
|
3789
3980
|
if (!reachable.has(func.name))
|
|
3790
3981
|
continue;
|
|
3791
3982
|
const params = preserveTypes && func.typedParams !== undefined ? func.typedParams : func.params.map(formatParamWithType).join(", ");
|
|
@@ -3795,6 +3986,127 @@ class JsxAdapter extends BaseAdapter {
|
|
|
3795
3986
|
lines.push(` ${asyncKw}function ${func.name}(${params})${returnAnnotation} ${body}`);
|
|
3796
3987
|
}
|
|
3797
3988
|
return lines.join(`
|
|
3989
|
+
`);
|
|
3990
|
+
}
|
|
3991
|
+
moduleScopeNamesCache = new WeakMap;
|
|
3992
|
+
moduleScopeDeclarationNames(ir) {
|
|
3993
|
+
const cached = this.moduleScopeNamesCache.get(ir);
|
|
3994
|
+
if (cached)
|
|
3995
|
+
return cached;
|
|
3996
|
+
const componentScope = new Set;
|
|
3997
|
+
for (const sig of ir.metadata.signals) {
|
|
3998
|
+
if (sig.isModule)
|
|
3999
|
+
continue;
|
|
4000
|
+
componentScope.add(sig.getter);
|
|
4001
|
+
if (sig.setter)
|
|
4002
|
+
componentScope.add(sig.setter);
|
|
4003
|
+
}
|
|
4004
|
+
for (const memo of ir.metadata.memos) {
|
|
4005
|
+
if (!memo.isModule)
|
|
4006
|
+
componentScope.add(memo.name);
|
|
4007
|
+
}
|
|
4008
|
+
for (const p of ir.metadata.propsParams)
|
|
4009
|
+
componentScope.add(p.name);
|
|
4010
|
+
if (ir.metadata.propsObjectName)
|
|
4011
|
+
componentScope.add(ir.metadata.propsObjectName);
|
|
4012
|
+
if (ir.metadata.restPropsName)
|
|
4013
|
+
componentScope.add(ir.metadata.restPropsName);
|
|
4014
|
+
for (const c of ir.metadata.localConstants) {
|
|
4015
|
+
if (!c.isModule)
|
|
4016
|
+
componentScope.add(c.name);
|
|
4017
|
+
}
|
|
4018
|
+
for (const f of ir.metadata.localFunctions) {
|
|
4019
|
+
if (!f.isModule)
|
|
4020
|
+
componentScope.add(f.name);
|
|
4021
|
+
}
|
|
4022
|
+
const exported = new Set;
|
|
4023
|
+
const candidates = new Map;
|
|
4024
|
+
for (const c of ir.metadata.localConstants) {
|
|
4025
|
+
if (!c.isModule)
|
|
4026
|
+
continue;
|
|
4027
|
+
if (c.isJsx || c.isJsxFunction)
|
|
4028
|
+
continue;
|
|
4029
|
+
if (c.isExported) {
|
|
4030
|
+
exported.add(c.name);
|
|
4031
|
+
continue;
|
|
4032
|
+
}
|
|
4033
|
+
candidates.set(c.name, c.freeIdentifiers ?? extractFreeIdentifiersFromText(c.value ?? ""));
|
|
4034
|
+
}
|
|
4035
|
+
for (const f of ir.metadata.localFunctions) {
|
|
4036
|
+
if (!f.isModule)
|
|
4037
|
+
continue;
|
|
4038
|
+
if (f.isJsxFunction || f.isMultiReturnJsxHelper)
|
|
4039
|
+
continue;
|
|
4040
|
+
if (f.isExported) {
|
|
4041
|
+
exported.add(f.name);
|
|
4042
|
+
continue;
|
|
4043
|
+
}
|
|
4044
|
+
const params = f.typedParams !== undefined ? f.typedParams : f.params.map(formatParamWithType).join(", ");
|
|
4045
|
+
candidates.set(f.name, extractFreeIdentifiersFromText(`(${params}) => ${f.body}`));
|
|
4046
|
+
}
|
|
4047
|
+
const referencesAny = (refs, names) => {
|
|
4048
|
+
for (const ref of refs) {
|
|
4049
|
+
if (names.has(ref))
|
|
4050
|
+
return true;
|
|
4051
|
+
}
|
|
4052
|
+
return false;
|
|
4053
|
+
};
|
|
4054
|
+
let changed = true;
|
|
4055
|
+
while (changed) {
|
|
4056
|
+
changed = false;
|
|
4057
|
+
for (const [name, refs] of candidates) {
|
|
4058
|
+
if (referencesAny(refs, componentScope)) {
|
|
4059
|
+
candidates.delete(name);
|
|
4060
|
+
componentScope.add(name);
|
|
4061
|
+
changed = true;
|
|
4062
|
+
}
|
|
4063
|
+
}
|
|
4064
|
+
}
|
|
4065
|
+
const result = new Set([...exported, ...candidates.keys()]);
|
|
4066
|
+
this.moduleScopeNamesCache.set(ir, result);
|
|
4067
|
+
return result;
|
|
4068
|
+
}
|
|
4069
|
+
generateModuleScopeDeclarations(ir) {
|
|
4070
|
+
const { preserveTypes } = this.jsxConfig;
|
|
4071
|
+
const moduleNames = this.moduleScopeDeclarationNames(ir);
|
|
4072
|
+
const entries = [];
|
|
4073
|
+
for (const t of ir.metadata.typeDefinitions) {
|
|
4074
|
+
entries.push({ line: t.loc.start.line, text: t.definition });
|
|
4075
|
+
}
|
|
4076
|
+
for (const c of ir.metadata.localConstants) {
|
|
4077
|
+
if (!c.isModule || !moduleNames.has(c.name))
|
|
4078
|
+
continue;
|
|
4079
|
+
const keyword = c.declarationKind ?? "const";
|
|
4080
|
+
const exportKw = c.isExported ? "export " : "";
|
|
4081
|
+
if (!c.value) {
|
|
4082
|
+
const typeAnnotation = preserveTypes && (c.typeAnnotation ?? c.type) ? `: ${c.typeAnnotation ?? c.type?.raw}` : "";
|
|
4083
|
+
entries.push({ line: c.loc.start.line, text: `${exportKw}${keyword} ${c.name}${typeAnnotation}` });
|
|
4084
|
+
continue;
|
|
4085
|
+
}
|
|
4086
|
+
const trimmed = c.value.trim();
|
|
4087
|
+
if (/^new WeakMap\b/.test(trimmed))
|
|
4088
|
+
continue;
|
|
4089
|
+
if (c.isExported && /^createContext\b/.test(trimmed))
|
|
4090
|
+
continue;
|
|
4091
|
+
const value = preserveTypes ? c.typedValue ?? c.value : c.value;
|
|
4092
|
+
const letTypeAnnotation = preserveTypes && keyword === "let" && c.typeAnnotation ? `: ${c.typeAnnotation}` : "";
|
|
4093
|
+
entries.push({ line: c.loc.start.line, text: `${exportKw}${keyword} ${c.name}${letTypeAnnotation} = ${value}` });
|
|
4094
|
+
}
|
|
4095
|
+
for (const f of ir.metadata.localFunctions) {
|
|
4096
|
+
if (!f.isModule || !moduleNames.has(f.name))
|
|
4097
|
+
continue;
|
|
4098
|
+
const params = preserveTypes && f.typedParams !== undefined ? f.typedParams : f.params.map(formatParamWithType).join(", ");
|
|
4099
|
+
const returnAnnotation = preserveTypes && f.typedReturnType ? `: ${f.typedReturnType}` : "";
|
|
4100
|
+
const body = preserveTypes ? f.typedBody ?? f.body : f.body;
|
|
4101
|
+
const asyncKw = f.isAsync ? "async " : "";
|
|
4102
|
+
const exportKw = f.isExported ? "export " : "";
|
|
4103
|
+
entries.push({
|
|
4104
|
+
line: f.loc.start.line,
|
|
4105
|
+
text: `${exportKw}${asyncKw}function ${f.name}(${params})${returnAnnotation} ${body}`
|
|
4106
|
+
});
|
|
4107
|
+
}
|
|
4108
|
+
entries.sort((a, b) => a.line - b.line);
|
|
4109
|
+
return entries.map((e) => e.text).join(`
|
|
3798
4110
|
`);
|
|
3799
4111
|
}
|
|
3800
4112
|
renderNodeRaw(node) {
|
|
@@ -3806,6 +4118,15 @@ class JsxAdapter extends BaseAdapter {
|
|
|
3806
4118
|
}
|
|
3807
4119
|
return this.renderNode(node);
|
|
3808
4120
|
}
|
|
4121
|
+
renderTemplatePartsAsJs(parts) {
|
|
4122
|
+
return templatePartsToJsExpr(parts, { typed: this.jsxConfig.preserveTypes });
|
|
4123
|
+
}
|
|
4124
|
+
expressionValueToJs(value) {
|
|
4125
|
+
if (this.jsxConfig.preserveTypes && value.parts && value.expr === templatePartsToJsExpr(value.parts)) {
|
|
4126
|
+
return this.renderTemplatePartsAsJs(value.parts);
|
|
4127
|
+
}
|
|
4128
|
+
return value.expr;
|
|
4129
|
+
}
|
|
3809
4130
|
renderScopeMarker(instanceIdExpr) {
|
|
3810
4131
|
return `${BF_SCOPE}={${instanceIdExpr}}`;
|
|
3811
4132
|
}
|
|
@@ -3873,6 +4194,7 @@ class TestAdapter extends JsxAdapter {
|
|
|
3873
4194
|
generate(ir) {
|
|
3874
4195
|
this.componentName = ir.metadata.componentName;
|
|
3875
4196
|
const imports = this.generateImports(ir);
|
|
4197
|
+
const moduleConstants = this.generateModuleScopeDeclarations(ir);
|
|
3876
4198
|
const types = this.generateTypes(ir);
|
|
3877
4199
|
const component = this.generateComponent(ir);
|
|
3878
4200
|
const defaultExport = ir.metadata.hasDefaultExport ? `
|
|
@@ -3881,9 +4203,11 @@ export default ${this.componentName}` : "";
|
|
|
3881
4203
|
imports,
|
|
3882
4204
|
types: types || "",
|
|
3883
4205
|
component,
|
|
3884
|
-
defaultExport
|
|
4206
|
+
defaultExport,
|
|
4207
|
+
moduleConstants,
|
|
4208
|
+
moduleConstantsIncludeExports: true
|
|
3885
4209
|
};
|
|
3886
|
-
const template = [imports, types, component].filter(Boolean).join(`
|
|
4210
|
+
const template = [imports, moduleConstants, types, component].filter(Boolean).join(`
|
|
3887
4211
|
|
|
3888
4212
|
`) + defaultExport;
|
|
3889
4213
|
return {
|
|
@@ -3914,9 +4238,6 @@ export default ${this.componentName}` : "";
|
|
|
3914
4238
|
}
|
|
3915
4239
|
generateTypes(ir) {
|
|
3916
4240
|
const lines = [];
|
|
3917
|
-
for (const typeDef of ir.metadata.typeDefinitions) {
|
|
3918
|
-
lines.push(typeDef.definition);
|
|
3919
|
-
}
|
|
3920
4241
|
const propsTypeName = ir.metadata.propsType?.raw;
|
|
3921
4242
|
if (propsTypeName && !ir.metadata.propsObjectName) {
|
|
3922
4243
|
lines.push("");
|
|
@@ -3939,7 +4260,7 @@ export default ${this.componentName}` : "";
|
|
|
3939
4260
|
const bodyRefText = [jsxBody, signalInits, scopeIdLine].join(`
|
|
3940
4261
|
`);
|
|
3941
4262
|
const bfScopeAlias = /\b__bfScope\b/.test(bodyRefText) ? "__bfScope" : "__bfScope: _bfScope";
|
|
3942
|
-
const propsParams = ir.metadata.propsParams.map((p) => p
|
|
4263
|
+
const propsParams = ir.metadata.propsParams.map((p) => propsDestructureBinding(p)).join(", ");
|
|
3943
4264
|
const restPropsName = ir.metadata.restPropsName;
|
|
3944
4265
|
const hydrationProps = `__instanceId, ${bfScopeAlias}`;
|
|
3945
4266
|
const parts = [];
|
|
@@ -4086,13 +4407,7 @@ export default ${this.componentName}` : "";
|
|
|
4086
4407
|
}
|
|
4087
4408
|
flattenTemplate(value) {
|
|
4088
4409
|
const v = value;
|
|
4089
|
-
return
|
|
4090
|
-
if (p.type === "string")
|
|
4091
|
-
return p.value;
|
|
4092
|
-
if (p.type === "ternary")
|
|
4093
|
-
return `\${${p.condition} ? '${p.whenTrue}' : '${p.whenFalse}'}`;
|
|
4094
|
-
return `\${(${JSON.stringify(p.cases)})[${p.key}]}`;
|
|
4095
|
-
}).join("") + "`";
|
|
4410
|
+
return this.renderTemplatePartsAsJs(v.parts);
|
|
4096
4411
|
}
|
|
4097
4412
|
renderComponentProps(comp) {
|
|
4098
4413
|
const parts = [];
|
|
@@ -4497,7 +4812,7 @@ function dangerousInnerHtmlDiagnostic(expr, loc, reason) {
|
|
|
4497
4812
|
};
|
|
4498
4813
|
}
|
|
4499
4814
|
// ../jsx/src/combine-client-js.ts
|
|
4500
|
-
import
|
|
4815
|
+
import ts25 from "typescript";
|
|
4501
4816
|
// ../jsx/src/loop-destructure.ts
|
|
4502
4817
|
function isLowerableLoopDestructure(loop) {
|
|
4503
4818
|
const bindings = loop.paramBindings;
|
|
@@ -4637,9 +4952,9 @@ function escapeRe(s) {
|
|
|
4637
4952
|
return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
4638
4953
|
}
|
|
4639
4954
|
// ../jsx/src/debug.ts
|
|
4640
|
-
import
|
|
4955
|
+
import ts26 from "typescript";
|
|
4641
4956
|
// ../jsx/src/profiler.ts
|
|
4642
|
-
import
|
|
4957
|
+
import ts27 from "typescript";
|
|
4643
4958
|
|
|
4644
4959
|
// ../jsx/src/index.ts
|
|
4645
4960
|
registerBuiltinLoweringPlugins();
|
|
@@ -5510,7 +5825,7 @@ function collectImportedLoopChildComponentErrors(ir, componentName) {
|
|
|
5510
5825
|
}
|
|
5511
5826
|
|
|
5512
5827
|
// src/adapter/spread/spread-codegen.ts
|
|
5513
|
-
import
|
|
5828
|
+
import ts28 from "typescript";
|
|
5514
5829
|
function conditionalSpreadToRuby(ctx, expr) {
|
|
5515
5830
|
if (!expr || expr.kind !== "conditional")
|
|
5516
5831
|
return null;
|
|
@@ -5565,7 +5880,7 @@ function recordIndexAccessToRuby(ctx, val) {
|
|
|
5565
5880
|
if (val.kind !== "index-access" || val.object.kind !== "identifier" || val.index.kind !== "identifier") {
|
|
5566
5881
|
return null;
|
|
5567
5882
|
}
|
|
5568
|
-
const tsVal =
|
|
5883
|
+
const tsVal = ts28.factory.createElementAccessExpression(ts28.factory.createIdentifier(val.object.name), ts28.factory.createIdentifier(val.index.name));
|
|
5569
5884
|
const parsed = parseRecordIndexAccess(tsVal, ctx.localConstants, ctx.propsParams);
|
|
5570
5885
|
if (!parsed)
|
|
5571
5886
|
return null;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@barefootjs/erb",
|
|
3
|
-
"version": "0.31.
|
|
3
|
+
"version": "0.31.3",
|
|
4
4
|
"description": "ERB (Embedded Ruby) adapter for BarefootJS — compiles IR to .erb templates and ships the Ruby rendering backend; runs under any Rack app (Sinatra, Rails)",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -54,7 +54,7 @@
|
|
|
54
54
|
"directory": "packages/adapter-erb"
|
|
55
55
|
},
|
|
56
56
|
"dependencies": {
|
|
57
|
-
"@barefootjs/shared": "0.31.
|
|
57
|
+
"@barefootjs/shared": "0.31.3"
|
|
58
58
|
},
|
|
59
59
|
"peerDependencies": {
|
|
60
60
|
"@barefootjs/jsx": ">=0.2.0",
|
|
@@ -71,9 +71,9 @@
|
|
|
71
71
|
},
|
|
72
72
|
"devDependencies": {
|
|
73
73
|
"@barefootjs/adapter-tests": "0.1.0",
|
|
74
|
-
"@barefootjs/jsx": "0.31.
|
|
75
|
-
"@barefootjs/vite": "0.31.
|
|
76
|
-
"@barefootjs/client": "0.31.
|
|
74
|
+
"@barefootjs/jsx": "0.31.3",
|
|
75
|
+
"@barefootjs/vite": "0.31.3",
|
|
76
|
+
"@barefootjs/client": "0.31.3",
|
|
77
77
|
"typescript": "^5.0.0",
|
|
78
78
|
"vite": "^6.0.0"
|
|
79
79
|
}
|
|
@@ -20,18 +20,4 @@ export const renderDivergences: RenderDivergences = {
|
|
|
20
20
|
// instead of a fixed regex-shape catalogue) now correctly seeds `todos`
|
|
21
21
|
// from `(props.initialTodos ?? []).map(t => ({ ...t, editing: false }))`.
|
|
22
22
|
|
|
23
|
-
// Onboarding TSX-fidelity fixtures (PR #2461): `expectedHtml` was
|
|
24
|
-
// hand-authored to the CORRECT output while the emission bug lived in
|
|
25
|
-
// the shared compiler layer — every adapter, including the Hono
|
|
26
|
-
// reference, used to emit the broken form. That shared-layer defect
|
|
27
|
-
// (#2460) is now FIXED (b4f5075): `expectedHtml` is generated from the
|
|
28
|
-
// Hono reference like any other fixture. The remaining gap is
|
|
29
|
-
// per-template-adapter — this adapter still keys its template vars /
|
|
30
|
-
// ssr-defaults / props bridge off the local binding instead of
|
|
31
|
-
// `sourceName ?? name` — tracked by #2524 (the 7 silent template
|
|
32
|
-
// adapters). Graduate by applying the same `sourceName ?? name` fix to
|
|
33
|
-
// this adapter's emission path and deleting this line (and the
|
|
34
|
-
// matching hono `skipJsx` entries, already gone).
|
|
35
|
-
'aliased-destructured-prop':
|
|
36
|
-
'aliased destructured prop `{ n: count }` loses its rename — template vars, ssr-defaults, and the props bridge all key off the local name, so the prop is always undefined (https://github.com/piconic-ai/barefootjs/issues/2524)',
|
|
37
23
|
}
|
package/src/test-render.ts
CHANGED
|
@@ -36,7 +36,7 @@
|
|
|
36
36
|
* regression test.
|
|
37
37
|
*/
|
|
38
38
|
|
|
39
|
-
import { compileJSX, extractSsrDefaults, importsSearchParams, evaluateSignalInit
|
|
39
|
+
import { compileJSX, extractSsrDefaults, deriveStashFromDefaults, importsSearchParams, evaluateSignalInit } from '@barefootjs/jsx'
|
|
40
40
|
import type { ComponentIR, SsrDefault } from '@barefootjs/jsx'
|
|
41
41
|
import { mkdir, rm } from 'node:fs/promises'
|
|
42
42
|
import { resolve } from 'node:path'
|
|
@@ -415,7 +415,11 @@ function buildChildRenderersRuby(
|
|
|
415
415
|
// branch and JSX rest semantics: a caller prop the child didn't
|
|
416
416
|
// destructure belongs in the bag, not as a top-level vars key the
|
|
417
417
|
// template never reads.
|
|
418
|
-
|
|
418
|
+
// Caller-facing keys — `child_props` (below) is keyed by whatever the
|
|
419
|
+
// CALLING template passed (the JSX attribute name), so the keep-set
|
|
420
|
+
// must match that spelling, not an aliased child's local binding
|
|
421
|
+
// (#2524).
|
|
422
|
+
const paramNames = (childIR.metadata.propsParams ?? []).map(p => p.sourceName ?? p.name)
|
|
419
423
|
const keep = [...new Set([...paramNames, restPropsName, 'children', 'key', '_bf_slot'])]
|
|
420
424
|
const keepList = keep.map(rubySymbol).join(', ')
|
|
421
425
|
lines.push(` keep = [${keepList}]`)
|
|
@@ -499,24 +503,29 @@ function buildRubyProps(
|
|
|
499
503
|
obj.scope_id = explicitScope
|
|
500
504
|
|
|
501
505
|
// Prop params with defaults (before signals, so signals can reference them).
|
|
506
|
+
// Seeded through the shared `deriveStashFromDefaults` (the TS twin of the
|
|
507
|
+
// production `derive_vars_from_defaults` this harness ALSO calls below for
|
|
508
|
+
// child components) so an aliased destructured prop's CALLER-facing key
|
|
509
|
+
// (`propName`, e.g. `n` for `{ n: count }`) is honoured, not just the
|
|
510
|
+
// local template var name (#2524 SSR half). `props` is keyed by the
|
|
511
|
+
// caller-facing name, exactly what `propName` resolves against.
|
|
512
|
+
const rootSsrDefaults = extractSsrDefaults(ir.metadata) ?? {}
|
|
513
|
+
const derivedProps = deriveStashFromDefaults(rootSsrDefaults, props ?? {})
|
|
502
514
|
for (const param of ir.metadata.propsParams) {
|
|
503
|
-
if (
|
|
504
|
-
if (param.defaultValue) {
|
|
505
|
-
const result = tryEvaluateSignalInit(param.defaultValue.trim(), props)
|
|
506
|
-
if (result.ok) {
|
|
507
|
-
obj[param.name] = result.value
|
|
508
|
-
continue
|
|
509
|
-
}
|
|
510
|
-
}
|
|
515
|
+
if (param.isRest) continue
|
|
511
516
|
// No default + no caller value: seed `nil` so a bare reference to an
|
|
512
517
|
// optional prop's vars-Hash key resolves (to nil) instead of the key
|
|
513
518
|
// being wholly absent — matches the Perl harnesses' explicit `undef`.
|
|
514
|
-
obj[param.name] = null
|
|
519
|
+
obj[param.name] = derivedProps[param.name] ?? null
|
|
515
520
|
}
|
|
516
521
|
|
|
517
522
|
// Route undeclared props into the rest bag (`spread_attrs(v[:<rest>])`).
|
|
518
523
|
const restPropsName = ir.metadata.restPropsName
|
|
519
|
-
|
|
524
|
+
// Caller-facing keys, per prop — an aliased destructured prop's DECLARED
|
|
525
|
+
// set for rest-bag routing purposes must match what the caller actually
|
|
526
|
+
// sent (`n`), not the local binding (`count`), or the caller's own prop
|
|
527
|
+
// silently gets swept into the rest bag as an undeclared extra (#2524).
|
|
528
|
+
const declaredParams = new Set(ir.metadata.propsParams.map(p => p.sourceName ?? p.name))
|
|
520
529
|
const restBagEntries: Array<[string, unknown]> = []
|
|
521
530
|
if (restPropsName && props) {
|
|
522
531
|
for (const [key, value] of Object.entries(props)) {
|
|
@@ -531,11 +540,20 @@ function buildRubyProps(
|
|
|
531
540
|
obj[restPropsName] = Object.fromEntries(restBagEntries)
|
|
532
541
|
}
|
|
533
542
|
|
|
534
|
-
// User props.
|
|
543
|
+
// User props. Skip a key that's already a declared param's LOCAL template
|
|
544
|
+
// var name — `derivedProps` above already resolved that var correctly
|
|
545
|
+
// (through `propName`, for an aliased prop); re-assigning the raw
|
|
546
|
+
// `props[key]` here would silently clobber it with an UNRELATED value
|
|
547
|
+
// whenever a caller happens to also pass a same-spelled-as-local-name prop
|
|
548
|
+
// that isn't this param's actual `propName` (#2524 — surfaced by the
|
|
549
|
+
// aliased-destructured-prop generated data points, which pass both `n`
|
|
550
|
+
// (the real propName) and an incidental `count` key).
|
|
551
|
+
const localParamNames = new Set(ir.metadata.propsParams.map(p => p.name))
|
|
535
552
|
if (props) {
|
|
536
553
|
for (const [key, value] of Object.entries(props)) {
|
|
537
554
|
if (key.startsWith('__')) continue
|
|
538
555
|
if (routedKeys.has(key)) continue
|
|
556
|
+
if (localParamNames.has(key)) continue
|
|
539
557
|
obj[key] = value
|
|
540
558
|
}
|
|
541
559
|
}
|
|
@@ -553,9 +571,8 @@ function buildRubyProps(
|
|
|
553
571
|
|
|
554
572
|
// Memo values seeded from the statically-evaluated ssrDefaults, same
|
|
555
573
|
// as the production plugin's before_render hook.
|
|
556
|
-
const ssrDefaults = extractSsrDefaults(ir.metadata) ?? {}
|
|
557
574
|
for (const memo of ir.metadata.memos) {
|
|
558
|
-
obj[memo.name] =
|
|
575
|
+
obj[memo.name] = rootSsrDefaults[memo.name]?.value ?? 0
|
|
559
576
|
}
|
|
560
577
|
|
|
561
578
|
const needsSearchParams = importsSearchParams(ir.metadata)
|