@barefootjs/xslate 0.31.1 → 0.31.2
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 -4
- package/dist/render-divergences.d.ts.map +1 -1
- package/dist/vite.js +334 -99
- package/lib/BarefootJS/Backend/Xslate.pm +1 -1
- package/package.json +5 -5
- package/src/render-divergences.ts +0 -16
- package/src/test-render.ts +73 -32
package/dist/index.js
CHANGED
|
@@ -189208,10 +189208,7 @@ var conformancePins = {
|
|
|
189208
189208
|
"date-method-uncatalogued": [{ code: "BF021", severity: "error", issue: "https://github.com/piconic-ai/barefootjs/issues/2356" }]
|
|
189209
189209
|
};
|
|
189210
189210
|
// src/render-divergences.ts
|
|
189211
|
-
var renderDivergences = {
|
|
189212
|
-
"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)",
|
|
189213
|
-
"composite-row-child-aliased-prop": "same defect as `aliased-destructured-prop` (#2524), inside a keyed `.map()` loop row: the nested child's renamed prop (`{ n: count }`) is always undefined, so both rows render an empty count (https://github.com/piconic-ai/barefootjs/issues/2524)"
|
|
189214
|
-
};
|
|
189211
|
+
var renderDivergences = {};
|
|
189215
189212
|
export {
|
|
189216
189213
|
xslateAdapter,
|
|
189217
189214
|
renderDivergences,
|
|
@@ -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
|
|
@@ -2828,13 +2935,13 @@ var KEYWORDS_AND_GLOBALS = new Set([
|
|
|
2828
2935
|
]);
|
|
2829
2936
|
|
|
2830
2937
|
// ../jsx/src/ir-to-client-js/walk-prop-accesses.ts
|
|
2831
|
-
import
|
|
2938
|
+
import ts13 from "typescript";
|
|
2832
2939
|
|
|
2833
2940
|
// ../jsx/src/value-references.ts
|
|
2834
|
-
import
|
|
2941
|
+
import ts14 from "typescript";
|
|
2835
2942
|
|
|
2836
2943
|
// ../jsx/src/relocate.ts
|
|
2837
|
-
import
|
|
2944
|
+
import ts15 from "typescript";
|
|
2838
2945
|
|
|
2839
2946
|
// ../jsx/src/lowering-registry.ts
|
|
2840
2947
|
var plugins = [];
|
|
@@ -3051,10 +3158,10 @@ function matchSearchParamsMethodCall(callee, args, localNames) {
|
|
|
3051
3158
|
}
|
|
3052
3159
|
|
|
3053
3160
|
// ../jsx/src/ir-to-client-js/prune-unused-prop-extractions.ts
|
|
3054
|
-
import
|
|
3161
|
+
import ts16 from "typescript";
|
|
3055
3162
|
|
|
3056
3163
|
// ../jsx/src/ir-to-client-js/control-flow/plan/lazy-preamble.ts
|
|
3057
|
-
import
|
|
3164
|
+
import ts17 from "typescript";
|
|
3058
3165
|
var NO_PREAMBLE = {
|
|
3059
3166
|
lazySafe: true,
|
|
3060
3167
|
facts: { declaredNames: new Set, freeNames: new Set }
|
|
@@ -3104,7 +3211,7 @@ var INERT_BINDING_GLOBALS = new Set([
|
|
|
3104
3211
|
]);
|
|
3105
3212
|
|
|
3106
3213
|
// ../jsx/src/ir-to-client-js/emit-reactive.ts
|
|
3107
|
-
import
|
|
3214
|
+
import ts18 from "typescript";
|
|
3108
3215
|
|
|
3109
3216
|
// ../jsx/src/ir-to-client-js/control-flow/stringify/event-delegation.ts
|
|
3110
3217
|
var NON_BUBBLING_EVENTS = new Set([
|
|
@@ -3119,7 +3226,7 @@ var NON_BUBBLING_EVENTS = new Set([
|
|
|
3119
3226
|
]);
|
|
3120
3227
|
|
|
3121
3228
|
// ../jsx/src/ir-to-client-js/rewrite-props-object.ts
|
|
3122
|
-
import
|
|
3229
|
+
import ts19 from "typescript";
|
|
3123
3230
|
|
|
3124
3231
|
// ../jsx/src/ir-to-client-js/source-map.ts
|
|
3125
3232
|
var BASE64_CHARS = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
|
@@ -3210,15 +3317,15 @@ class SourceMapGenerator {
|
|
|
3210
3317
|
}
|
|
3211
3318
|
|
|
3212
3319
|
// ../jsx/src/preprocess-inline-jsx-callbacks.ts
|
|
3213
|
-
import
|
|
3320
|
+
import ts20 from "typescript";
|
|
3214
3321
|
|
|
3215
3322
|
// ../jsx/src/ssr-defaults.ts
|
|
3216
|
-
import
|
|
3323
|
+
import ts21 from "typescript";
|
|
3217
3324
|
var UNRESOLVED = Symbol("unresolved");
|
|
3218
3325
|
var NO_RETURN = Symbol("no-return");
|
|
3219
3326
|
|
|
3220
3327
|
// ../jsx/src/augment-inherited-props.ts
|
|
3221
|
-
import
|
|
3328
|
+
import ts22 from "typescript";
|
|
3222
3329
|
function collectContextConsumers(metadata) {
|
|
3223
3330
|
const constants = metadata.localConstants ?? [];
|
|
3224
3331
|
const contextDefaults = new Map;
|
|
@@ -3250,47 +3357,47 @@ function collectContextConsumers(metadata) {
|
|
|
3250
3357
|
}
|
|
3251
3358
|
function parseUseContextArg(source) {
|
|
3252
3359
|
const expr = parseSingleExpression(source);
|
|
3253
|
-
if (!expr || !
|
|
3360
|
+
if (!expr || !ts22.isCallExpression(expr))
|
|
3254
3361
|
return null;
|
|
3255
|
-
if (!
|
|
3362
|
+
if (!ts22.isIdentifier(expr.expression) || expr.expression.text !== "useContext")
|
|
3256
3363
|
return null;
|
|
3257
3364
|
if (expr.arguments.length !== 1)
|
|
3258
3365
|
return null;
|
|
3259
3366
|
const arg = expr.arguments[0];
|
|
3260
|
-
return
|
|
3367
|
+
return ts22.isIdentifier(arg) ? arg.text : null;
|
|
3261
3368
|
}
|
|
3262
3369
|
function parseCreateContextDefault(source) {
|
|
3263
3370
|
const expr = parseSingleExpression(source);
|
|
3264
|
-
if (!expr || !
|
|
3371
|
+
if (!expr || !ts22.isCallExpression(expr))
|
|
3265
3372
|
return null;
|
|
3266
3373
|
if (expr.arguments.length === 0)
|
|
3267
3374
|
return null;
|
|
3268
3375
|
const arg = expr.arguments[0];
|
|
3269
|
-
if (
|
|
3376
|
+
if (ts22.isStringLiteral(arg) || ts22.isNoSubstitutionTemplateLiteral(arg))
|
|
3270
3377
|
return arg.text;
|
|
3271
|
-
if (
|
|
3378
|
+
if (ts22.isNumericLiteral(arg))
|
|
3272
3379
|
return Number(arg.text);
|
|
3273
|
-
if (arg.kind ===
|
|
3380
|
+
if (arg.kind === ts22.SyntaxKind.TrueKeyword)
|
|
3274
3381
|
return true;
|
|
3275
|
-
if (arg.kind ===
|
|
3382
|
+
if (arg.kind === ts22.SyntaxKind.FalseKeyword)
|
|
3276
3383
|
return false;
|
|
3277
3384
|
return null;
|
|
3278
3385
|
}
|
|
3279
3386
|
function isObjectLiteralCreateContextDefault(source) {
|
|
3280
3387
|
const expr = parseSingleExpression(source);
|
|
3281
|
-
if (!expr || !
|
|
3388
|
+
if (!expr || !ts22.isCallExpression(expr))
|
|
3282
3389
|
return false;
|
|
3283
3390
|
if (expr.arguments.length === 0)
|
|
3284
3391
|
return false;
|
|
3285
|
-
return
|
|
3392
|
+
return ts22.isObjectLiteralExpression(expr.arguments[0]);
|
|
3286
3393
|
}
|
|
3287
3394
|
function parseSingleExpression(source) {
|
|
3288
|
-
const sf =
|
|
3395
|
+
const sf = ts22.createSourceFile("__ctx.ts", `(${source})`, ts22.ScriptTarget.Latest, false);
|
|
3289
3396
|
const stmt = sf.statements[0];
|
|
3290
|
-
if (!stmt || !
|
|
3397
|
+
if (!stmt || !ts22.isExpressionStatement(stmt))
|
|
3291
3398
|
return null;
|
|
3292
3399
|
let e = stmt.expression;
|
|
3293
|
-
while (
|
|
3400
|
+
while (ts22.isParenthesizedExpression(e))
|
|
3294
3401
|
e = e.expression;
|
|
3295
3402
|
return e;
|
|
3296
3403
|
}
|
|
@@ -3315,25 +3422,25 @@ function augmentInheritedPropAccesses(ir) {
|
|
|
3315
3422
|
const pinCoalesceLiterals = (s) => {
|
|
3316
3423
|
if (!s || !s.includes(propsObj))
|
|
3317
3424
|
return;
|
|
3318
|
-
const sf =
|
|
3425
|
+
const sf = ts22.createSourceFile("__aug.ts", `(${s})`, ts22.ScriptTarget.Latest, false);
|
|
3319
3426
|
const visit = (n) => {
|
|
3320
|
-
if (
|
|
3427
|
+
if (ts22.isBinaryExpression(n) && (n.operatorToken.kind === ts22.SyntaxKind.QuestionQuestionToken || n.operatorToken.kind === ts22.SyntaxKind.BarBarToken)) {
|
|
3321
3428
|
let left = n.left;
|
|
3322
|
-
while (
|
|
3429
|
+
while (ts22.isParenthesizedExpression(left))
|
|
3323
3430
|
left = left.expression;
|
|
3324
|
-
if (
|
|
3431
|
+
if (ts22.isPropertyAccessExpression(left) && ts22.isIdentifier(left.expression) && left.expression.text === propsObj) {
|
|
3325
3432
|
const name = left.name.text;
|
|
3326
3433
|
let right = n.right;
|
|
3327
|
-
while (
|
|
3434
|
+
while (ts22.isParenthesizedExpression(right))
|
|
3328
3435
|
right = right.expression;
|
|
3329
|
-
if (
|
|
3436
|
+
if (ts22.isPrefixUnaryExpression(right))
|
|
3330
3437
|
right = right.operand;
|
|
3331
|
-
const kind =
|
|
3438
|
+
const kind = ts22.isNumericLiteral(right) ? "number" : right.kind === ts22.SyntaxKind.TrueKeyword || right.kind === ts22.SyntaxKind.FalseKeyword ? "boolean" : ts22.isStringLiteralLike(right) ? "string" : null;
|
|
3332
3439
|
if (kind && !coalesceLiteralTypes.has(name))
|
|
3333
3440
|
coalesceLiteralTypes.set(name, kind);
|
|
3334
3441
|
}
|
|
3335
3442
|
}
|
|
3336
|
-
|
|
3443
|
+
ts22.forEachChild(n, visit);
|
|
3337
3444
|
};
|
|
3338
3445
|
visit(sf);
|
|
3339
3446
|
};
|
|
@@ -3444,33 +3551,33 @@ function augmentInheritedPropAccesses(ir) {
|
|
|
3444
3551
|
}
|
|
3445
3552
|
}
|
|
3446
3553
|
function parseStaticStringConst(source) {
|
|
3447
|
-
const sf =
|
|
3554
|
+
const sf = ts22.createSourceFile("__const.ts", `const __x = (${source});`, ts22.ScriptTarget.Latest, false);
|
|
3448
3555
|
const stmt = sf.statements[0];
|
|
3449
|
-
if (!stmt || !
|
|
3556
|
+
if (!stmt || !ts22.isVariableStatement(stmt))
|
|
3450
3557
|
return null;
|
|
3451
3558
|
let init = stmt.declarationList.declarations[0]?.initializer;
|
|
3452
|
-
while (init &&
|
|
3559
|
+
while (init && ts22.isParenthesizedExpression(init))
|
|
3453
3560
|
init = init.expression;
|
|
3454
3561
|
if (!init)
|
|
3455
3562
|
return null;
|
|
3456
|
-
if (
|
|
3563
|
+
if (ts22.isStringLiteral(init) || ts22.isNoSubstitutionTemplateLiteral(init)) {
|
|
3457
3564
|
return init.text;
|
|
3458
3565
|
}
|
|
3459
3566
|
return evalStringArrayJoin(source);
|
|
3460
3567
|
}
|
|
3461
3568
|
function evalTemplateOfStringConsts(source, resolved) {
|
|
3462
|
-
const sf =
|
|
3569
|
+
const sf = ts22.createSourceFile("__const.ts", `const __x = (${source});`, ts22.ScriptTarget.Latest, false);
|
|
3463
3570
|
const stmt = sf.statements[0];
|
|
3464
|
-
if (!stmt || !
|
|
3571
|
+
if (!stmt || !ts22.isVariableStatement(stmt))
|
|
3465
3572
|
return null;
|
|
3466
3573
|
let init = stmt.declarationList.declarations[0]?.initializer;
|
|
3467
|
-
while (init &&
|
|
3574
|
+
while (init && ts22.isParenthesizedExpression(init))
|
|
3468
3575
|
init = init.expression;
|
|
3469
|
-
if (!init || !
|
|
3576
|
+
if (!init || !ts22.isTemplateExpression(init))
|
|
3470
3577
|
return null;
|
|
3471
3578
|
let out = init.head.text;
|
|
3472
3579
|
for (const span of init.templateSpans) {
|
|
3473
|
-
if (!
|
|
3580
|
+
if (!ts22.isIdentifier(span.expression))
|
|
3474
3581
|
return null;
|
|
3475
3582
|
const value = resolved.get(span.expression.text);
|
|
3476
3583
|
if (value === undefined)
|
|
@@ -3501,30 +3608,30 @@ function lookupStaticRecordLiteral(objectName, key, constants) {
|
|
|
3501
3608
|
const constInfo = (constants ?? []).find((c) => c.name === objectName && c.isModule);
|
|
3502
3609
|
if (constInfo?.value === undefined)
|
|
3503
3610
|
return null;
|
|
3504
|
-
const sf =
|
|
3611
|
+
const sf = ts22.createSourceFile("__rec.ts", `(${constInfo.value})`, ts22.ScriptTarget.Latest, true);
|
|
3505
3612
|
if (sf.statements.length !== 1)
|
|
3506
3613
|
return null;
|
|
3507
3614
|
const stmt = sf.statements[0];
|
|
3508
|
-
if (!
|
|
3615
|
+
if (!ts22.isExpressionStatement(stmt))
|
|
3509
3616
|
return null;
|
|
3510
3617
|
let parsed = stmt.expression;
|
|
3511
|
-
while (
|
|
3618
|
+
while (ts22.isParenthesizedExpression(parsed))
|
|
3512
3619
|
parsed = parsed.expression;
|
|
3513
|
-
if (!
|
|
3620
|
+
if (!ts22.isObjectLiteralExpression(parsed))
|
|
3514
3621
|
return null;
|
|
3515
3622
|
for (const prop of parsed.properties) {
|
|
3516
|
-
if (!
|
|
3623
|
+
if (!ts22.isPropertyAssignment(prop))
|
|
3517
3624
|
continue;
|
|
3518
3625
|
const name = prop.name;
|
|
3519
|
-
const propKey =
|
|
3626
|
+
const propKey = ts22.isIdentifier(name) || ts22.isStringLiteral(name) || ts22.isNoSubstitutionTemplateLiteral(name) ? name.text : null;
|
|
3520
3627
|
if (propKey !== key)
|
|
3521
3628
|
continue;
|
|
3522
3629
|
let v = prop.initializer;
|
|
3523
|
-
while (
|
|
3630
|
+
while (ts22.isParenthesizedExpression(v))
|
|
3524
3631
|
v = v.expression;
|
|
3525
|
-
if (
|
|
3632
|
+
if (ts22.isNumericLiteral(v))
|
|
3526
3633
|
return { kind: "number", text: v.text };
|
|
3527
|
-
if (
|
|
3634
|
+
if (ts22.isStringLiteral(v) || ts22.isNoSubstitutionTemplateLiteral(v)) {
|
|
3528
3635
|
return { kind: "string", text: v.text };
|
|
3529
3636
|
}
|
|
3530
3637
|
return null;
|
|
@@ -3532,28 +3639,28 @@ function lookupStaticRecordLiteral(objectName, key, constants) {
|
|
|
3532
3639
|
return null;
|
|
3533
3640
|
}
|
|
3534
3641
|
function evalStringArrayJoin(source) {
|
|
3535
|
-
const sf =
|
|
3642
|
+
const sf = ts22.createSourceFile("__join.ts", `const __x = (${source});`, ts22.ScriptTarget.Latest, false);
|
|
3536
3643
|
const stmt = sf.statements[0];
|
|
3537
|
-
if (!stmt || !
|
|
3644
|
+
if (!stmt || !ts22.isVariableStatement(stmt))
|
|
3538
3645
|
return null;
|
|
3539
3646
|
let node = stmt.declarationList.declarations[0]?.initializer;
|
|
3540
|
-
while (node &&
|
|
3647
|
+
while (node && ts22.isParenthesizedExpression(node))
|
|
3541
3648
|
node = node.expression;
|
|
3542
|
-
if (!node || !
|
|
3649
|
+
if (!node || !ts22.isCallExpression(node))
|
|
3543
3650
|
return null;
|
|
3544
3651
|
const callee = node.expression;
|
|
3545
|
-
if (!
|
|
3652
|
+
if (!ts22.isPropertyAccessExpression(callee))
|
|
3546
3653
|
return null;
|
|
3547
3654
|
if (callee.name.text !== "join")
|
|
3548
3655
|
return null;
|
|
3549
3656
|
let recv = callee.expression;
|
|
3550
|
-
while (
|
|
3657
|
+
while (ts22.isParenthesizedExpression(recv))
|
|
3551
3658
|
recv = recv.expression;
|
|
3552
|
-
if (!
|
|
3659
|
+
if (!ts22.isArrayLiteralExpression(recv))
|
|
3553
3660
|
return null;
|
|
3554
3661
|
const parts = [];
|
|
3555
3662
|
for (const el of recv.elements) {
|
|
3556
|
-
if (
|
|
3663
|
+
if (ts22.isStringLiteral(el) || ts22.isNoSubstitutionTemplateLiteral(el)) {
|
|
3557
3664
|
parts.push(el.text);
|
|
3558
3665
|
} else {
|
|
3559
3666
|
return null;
|
|
@@ -3562,7 +3669,7 @@ function evalStringArrayJoin(source) {
|
|
|
3562
3669
|
let sep = ",";
|
|
3563
3670
|
if (node.arguments.length >= 1) {
|
|
3564
3671
|
const arg = node.arguments[0];
|
|
3565
|
-
if (
|
|
3672
|
+
if (ts22.isStringLiteral(arg) || ts22.isNoSubstitutionTemplateLiteral(arg))
|
|
3566
3673
|
sep = arg.text;
|
|
3567
3674
|
else
|
|
3568
3675
|
return null;
|
|
@@ -3570,11 +3677,11 @@ function evalStringArrayJoin(source) {
|
|
|
3570
3677
|
return parts.join(sep);
|
|
3571
3678
|
}
|
|
3572
3679
|
function parseRecordIndexAccess(val, localConstants, propsParams, resolveKey) {
|
|
3573
|
-
if (!
|
|
3680
|
+
if (!ts22.isElementAccessExpression(val))
|
|
3574
3681
|
return null;
|
|
3575
3682
|
const obj = val.expression;
|
|
3576
3683
|
const arg = val.argumentExpression;
|
|
3577
|
-
if (!
|
|
3684
|
+
if (!ts22.isIdentifier(obj) || !ts22.isIdentifier(arg))
|
|
3578
3685
|
return null;
|
|
3579
3686
|
let indexPropName;
|
|
3580
3687
|
let defaultKey;
|
|
@@ -3590,35 +3697,35 @@ function parseRecordIndexAccess(val, localConstants, propsParams, resolveKey) {
|
|
|
3590
3697
|
const constInfo = localConstants.find((c) => c.name === obj.text && c.isModule);
|
|
3591
3698
|
if (constInfo?.value === undefined)
|
|
3592
3699
|
return null;
|
|
3593
|
-
const sf =
|
|
3700
|
+
const sf = ts22.createSourceFile("__rec.ts", `(${constInfo.value})`, ts22.ScriptTarget.Latest, true);
|
|
3594
3701
|
if (sf.statements.length !== 1)
|
|
3595
3702
|
return null;
|
|
3596
3703
|
const stmt = sf.statements[0];
|
|
3597
|
-
if (!
|
|
3704
|
+
if (!ts22.isExpressionStatement(stmt))
|
|
3598
3705
|
return null;
|
|
3599
3706
|
let parsed = stmt.expression;
|
|
3600
|
-
while (
|
|
3707
|
+
while (ts22.isParenthesizedExpression(parsed))
|
|
3601
3708
|
parsed = parsed.expression;
|
|
3602
|
-
if (!
|
|
3709
|
+
if (!ts22.isObjectLiteralExpression(parsed))
|
|
3603
3710
|
return null;
|
|
3604
3711
|
const entries = [];
|
|
3605
3712
|
for (const prop of parsed.properties) {
|
|
3606
|
-
if (!
|
|
3713
|
+
if (!ts22.isPropertyAssignment(prop))
|
|
3607
3714
|
return null;
|
|
3608
3715
|
let key;
|
|
3609
|
-
if (
|
|
3716
|
+
if (ts22.isIdentifier(prop.name)) {
|
|
3610
3717
|
key = prop.name.text;
|
|
3611
|
-
} else if (
|
|
3718
|
+
} else if (ts22.isStringLiteral(prop.name) || ts22.isNoSubstitutionTemplateLiteral(prop.name)) {
|
|
3612
3719
|
key = prop.name.text;
|
|
3613
3720
|
} else {
|
|
3614
3721
|
return null;
|
|
3615
3722
|
}
|
|
3616
3723
|
let v = prop.initializer;
|
|
3617
|
-
while (
|
|
3724
|
+
while (ts22.isParenthesizedExpression(v))
|
|
3618
3725
|
v = v.expression;
|
|
3619
|
-
if (
|
|
3726
|
+
if (ts22.isNumericLiteral(v)) {
|
|
3620
3727
|
entries.push({ key, value: { kind: "number", text: v.text } });
|
|
3621
|
-
} else if (
|
|
3728
|
+
} else if (ts22.isStringLiteral(v) || ts22.isNoSubstitutionTemplateLiteral(v)) {
|
|
3622
3729
|
entries.push({ key, value: { kind: "string", text: v.text } });
|
|
3623
3730
|
} else {
|
|
3624
3731
|
return null;
|
|
@@ -3674,7 +3781,7 @@ function computeSsrSeedPlan(metadata) {
|
|
|
3674
3781
|
// ../jsx/src/rich-type-refusal.ts
|
|
3675
3782
|
var EMPTY_BINDINGS2 = new Map;
|
|
3676
3783
|
// ../jsx/src/shared-program.ts
|
|
3677
|
-
import
|
|
3784
|
+
import ts24 from "typescript";
|
|
3678
3785
|
// ../jsx/src/adapters/interface.ts
|
|
3679
3786
|
class BaseAdapter {
|
|
3680
3787
|
renderChildren(children) {
|
|
@@ -3750,7 +3857,7 @@ class JsxAdapter extends BaseAdapter {
|
|
|
3750
3857
|
}
|
|
3751
3858
|
const rawInitialValue = preserveTypes ? signal.typedInitialValue ?? signal.initialValue : signal.initialValue;
|
|
3752
3859
|
const initialValue = rawInitialValue.trim().startsWith("{") ? `(${rawInitialValue})` : rawInitialValue;
|
|
3753
|
-
const needsTypeAssertion = preserveTypes && !signal.typedInitialValue && signal.type.kind !== "unknown" && signal.type.kind !== "primitive";
|
|
3860
|
+
const needsTypeAssertion = preserveTypes && !signal.typedInitialValue && signal.type.kind !== "unknown" && signal.type.kind !== "primitive" && signal.type.raw !== "object";
|
|
3754
3861
|
if (needsTypeAssertion) {
|
|
3755
3862
|
lines.push(` const ${signal.getter} = () => ${initialValue} as ${signal.type.raw}`);
|
|
3756
3863
|
} else {
|
|
@@ -3769,12 +3876,16 @@ class JsxAdapter extends BaseAdapter {
|
|
|
3769
3876
|
const computation = preserveTypes ? memo.typedComputation ?? memo.computation : memo.computation;
|
|
3770
3877
|
lines.push(` const ${memo.name} = ${computation}`);
|
|
3771
3878
|
}
|
|
3879
|
+
const moduleScopeNames = this.moduleScopeDeclarationNames(ir);
|
|
3772
3880
|
for (const constant of ir.metadata.localConstants) {
|
|
3773
3881
|
if (constant.isExported)
|
|
3774
3882
|
continue;
|
|
3883
|
+
if (moduleScopeNames.has(constant.name))
|
|
3884
|
+
continue;
|
|
3775
3885
|
const keyword = constant.declarationKind ?? "const";
|
|
3776
3886
|
if (!constant.value) {
|
|
3777
|
-
|
|
3887
|
+
const typeAnnotation = preserveTypes && constant.type ? `: ${constant.type.raw}` : "";
|
|
3888
|
+
lines.push(` ${keyword} ${constant.name}${typeAnnotation}`);
|
|
3778
3889
|
continue;
|
|
3779
3890
|
}
|
|
3780
3891
|
const value = constant.value.trim();
|
|
@@ -3786,6 +3897,8 @@ class JsxAdapter extends BaseAdapter {
|
|
|
3786
3897
|
lines.push(` ${keyword} ${constant.name} = ${constValue}`);
|
|
3787
3898
|
}
|
|
3788
3899
|
for (const func of localFunctions) {
|
|
3900
|
+
if (moduleScopeNames.has(func.name))
|
|
3901
|
+
continue;
|
|
3789
3902
|
if (!reachable.has(func.name))
|
|
3790
3903
|
continue;
|
|
3791
3904
|
const params = preserveTypes && func.typedParams !== undefined ? func.typedParams : func.params.map(formatParamWithType).join(", ");
|
|
@@ -3795,6 +3908,125 @@ class JsxAdapter extends BaseAdapter {
|
|
|
3795
3908
|
lines.push(` ${asyncKw}function ${func.name}(${params})${returnAnnotation} ${body}`);
|
|
3796
3909
|
}
|
|
3797
3910
|
return lines.join(`
|
|
3911
|
+
`);
|
|
3912
|
+
}
|
|
3913
|
+
moduleScopeNamesCache = new WeakMap;
|
|
3914
|
+
moduleScopeDeclarationNames(ir) {
|
|
3915
|
+
const cached = this.moduleScopeNamesCache.get(ir);
|
|
3916
|
+
if (cached)
|
|
3917
|
+
return cached;
|
|
3918
|
+
const componentScope = new Set;
|
|
3919
|
+
for (const sig of ir.metadata.signals) {
|
|
3920
|
+
if (sig.isModule)
|
|
3921
|
+
continue;
|
|
3922
|
+
componentScope.add(sig.getter);
|
|
3923
|
+
if (sig.setter)
|
|
3924
|
+
componentScope.add(sig.setter);
|
|
3925
|
+
}
|
|
3926
|
+
for (const memo of ir.metadata.memos) {
|
|
3927
|
+
if (!memo.isModule)
|
|
3928
|
+
componentScope.add(memo.name);
|
|
3929
|
+
}
|
|
3930
|
+
for (const p of ir.metadata.propsParams)
|
|
3931
|
+
componentScope.add(p.name);
|
|
3932
|
+
if (ir.metadata.propsObjectName)
|
|
3933
|
+
componentScope.add(ir.metadata.propsObjectName);
|
|
3934
|
+
if (ir.metadata.restPropsName)
|
|
3935
|
+
componentScope.add(ir.metadata.restPropsName);
|
|
3936
|
+
for (const c of ir.metadata.localConstants) {
|
|
3937
|
+
if (!c.isModule)
|
|
3938
|
+
componentScope.add(c.name);
|
|
3939
|
+
}
|
|
3940
|
+
for (const f of ir.metadata.localFunctions) {
|
|
3941
|
+
if (!f.isModule)
|
|
3942
|
+
componentScope.add(f.name);
|
|
3943
|
+
}
|
|
3944
|
+
const exported = new Set;
|
|
3945
|
+
const candidates = new Map;
|
|
3946
|
+
for (const c of ir.metadata.localConstants) {
|
|
3947
|
+
if (!c.isModule)
|
|
3948
|
+
continue;
|
|
3949
|
+
if (c.isJsx || c.isJsxFunction)
|
|
3950
|
+
continue;
|
|
3951
|
+
if (c.isExported) {
|
|
3952
|
+
exported.add(c.name);
|
|
3953
|
+
continue;
|
|
3954
|
+
}
|
|
3955
|
+
candidates.set(c.name, c.freeIdentifiers ?? extractFreeIdentifiersFromText(c.value ?? ""));
|
|
3956
|
+
}
|
|
3957
|
+
for (const f of ir.metadata.localFunctions) {
|
|
3958
|
+
if (!f.isModule)
|
|
3959
|
+
continue;
|
|
3960
|
+
if (f.isJsxFunction || f.isMultiReturnJsxHelper)
|
|
3961
|
+
continue;
|
|
3962
|
+
if (f.isExported) {
|
|
3963
|
+
exported.add(f.name);
|
|
3964
|
+
continue;
|
|
3965
|
+
}
|
|
3966
|
+
const params = f.typedParams !== undefined ? f.typedParams : f.params.map(formatParamWithType).join(", ");
|
|
3967
|
+
candidates.set(f.name, extractFreeIdentifiersFromText(`(${params}) => ${f.body}`));
|
|
3968
|
+
}
|
|
3969
|
+
const referencesAny = (refs, names) => {
|
|
3970
|
+
for (const ref of refs) {
|
|
3971
|
+
if (names.has(ref))
|
|
3972
|
+
return true;
|
|
3973
|
+
}
|
|
3974
|
+
return false;
|
|
3975
|
+
};
|
|
3976
|
+
let changed = true;
|
|
3977
|
+
while (changed) {
|
|
3978
|
+
changed = false;
|
|
3979
|
+
for (const [name, refs] of candidates) {
|
|
3980
|
+
if (referencesAny(refs, componentScope)) {
|
|
3981
|
+
candidates.delete(name);
|
|
3982
|
+
componentScope.add(name);
|
|
3983
|
+
changed = true;
|
|
3984
|
+
}
|
|
3985
|
+
}
|
|
3986
|
+
}
|
|
3987
|
+
const result = new Set([...exported, ...candidates.keys()]);
|
|
3988
|
+
this.moduleScopeNamesCache.set(ir, result);
|
|
3989
|
+
return result;
|
|
3990
|
+
}
|
|
3991
|
+
generateModuleScopeDeclarations(ir) {
|
|
3992
|
+
const { preserveTypes } = this.jsxConfig;
|
|
3993
|
+
const moduleNames = this.moduleScopeDeclarationNames(ir);
|
|
3994
|
+
const entries = [];
|
|
3995
|
+
for (const t of ir.metadata.typeDefinitions) {
|
|
3996
|
+
entries.push({ line: t.loc.start.line, text: t.definition });
|
|
3997
|
+
}
|
|
3998
|
+
for (const c of ir.metadata.localConstants) {
|
|
3999
|
+
if (!c.isModule || !moduleNames.has(c.name))
|
|
4000
|
+
continue;
|
|
4001
|
+
const keyword = c.declarationKind ?? "const";
|
|
4002
|
+
const exportKw = c.isExported ? "export " : "";
|
|
4003
|
+
if (!c.value) {
|
|
4004
|
+
entries.push({ line: c.loc.start.line, text: `${exportKw}${keyword} ${c.name}` });
|
|
4005
|
+
continue;
|
|
4006
|
+
}
|
|
4007
|
+
const trimmed = c.value.trim();
|
|
4008
|
+
if (/^new WeakMap\b/.test(trimmed))
|
|
4009
|
+
continue;
|
|
4010
|
+
if (c.isExported && /^createContext\b/.test(trimmed))
|
|
4011
|
+
continue;
|
|
4012
|
+
const value = preserveTypes ? c.typedValue ?? c.value : c.value;
|
|
4013
|
+
entries.push({ line: c.loc.start.line, text: `${exportKw}${keyword} ${c.name} = ${value}` });
|
|
4014
|
+
}
|
|
4015
|
+
for (const f of ir.metadata.localFunctions) {
|
|
4016
|
+
if (!f.isModule || !moduleNames.has(f.name))
|
|
4017
|
+
continue;
|
|
4018
|
+
const params = preserveTypes && f.typedParams !== undefined ? f.typedParams : f.params.map(formatParamWithType).join(", ");
|
|
4019
|
+
const returnAnnotation = preserveTypes && f.typedReturnType ? `: ${f.typedReturnType}` : "";
|
|
4020
|
+
const body = preserveTypes ? f.typedBody ?? f.body : f.body;
|
|
4021
|
+
const asyncKw = f.isAsync ? "async " : "";
|
|
4022
|
+
const exportKw = f.isExported ? "export " : "";
|
|
4023
|
+
entries.push({
|
|
4024
|
+
line: f.loc.start.line,
|
|
4025
|
+
text: `${exportKw}${asyncKw}function ${f.name}(${params})${returnAnnotation} ${body}`
|
|
4026
|
+
});
|
|
4027
|
+
}
|
|
4028
|
+
entries.sort((a, b) => a.line - b.line);
|
|
4029
|
+
return entries.map((e) => e.text).join(`
|
|
3798
4030
|
`);
|
|
3799
4031
|
}
|
|
3800
4032
|
renderNodeRaw(node) {
|
|
@@ -3806,6 +4038,15 @@ class JsxAdapter extends BaseAdapter {
|
|
|
3806
4038
|
}
|
|
3807
4039
|
return this.renderNode(node);
|
|
3808
4040
|
}
|
|
4041
|
+
renderTemplatePartsAsJs(parts) {
|
|
4042
|
+
return templatePartsToJsExpr(parts, { typed: this.jsxConfig.preserveTypes });
|
|
4043
|
+
}
|
|
4044
|
+
expressionValueToJs(value) {
|
|
4045
|
+
if (this.jsxConfig.preserveTypes && value.parts && value.expr === templatePartsToJsExpr(value.parts)) {
|
|
4046
|
+
return this.renderTemplatePartsAsJs(value.parts);
|
|
4047
|
+
}
|
|
4048
|
+
return value.expr;
|
|
4049
|
+
}
|
|
3809
4050
|
renderScopeMarker(instanceIdExpr) {
|
|
3810
4051
|
return `${BF_SCOPE}={${instanceIdExpr}}`;
|
|
3811
4052
|
}
|
|
@@ -3873,6 +4114,7 @@ class TestAdapter extends JsxAdapter {
|
|
|
3873
4114
|
generate(ir) {
|
|
3874
4115
|
this.componentName = ir.metadata.componentName;
|
|
3875
4116
|
const imports = this.generateImports(ir);
|
|
4117
|
+
const moduleConstants = this.generateModuleScopeDeclarations(ir);
|
|
3876
4118
|
const types = this.generateTypes(ir);
|
|
3877
4119
|
const component = this.generateComponent(ir);
|
|
3878
4120
|
const defaultExport = ir.metadata.hasDefaultExport ? `
|
|
@@ -3881,9 +4123,11 @@ export default ${this.componentName}` : "";
|
|
|
3881
4123
|
imports,
|
|
3882
4124
|
types: types || "",
|
|
3883
4125
|
component,
|
|
3884
|
-
defaultExport
|
|
4126
|
+
defaultExport,
|
|
4127
|
+
moduleConstants,
|
|
4128
|
+
moduleConstantsIncludeExports: true
|
|
3885
4129
|
};
|
|
3886
|
-
const template = [imports, types, component].filter(Boolean).join(`
|
|
4130
|
+
const template = [imports, moduleConstants, types, component].filter(Boolean).join(`
|
|
3887
4131
|
|
|
3888
4132
|
`) + defaultExport;
|
|
3889
4133
|
return {
|
|
@@ -3914,9 +4158,6 @@ export default ${this.componentName}` : "";
|
|
|
3914
4158
|
}
|
|
3915
4159
|
generateTypes(ir) {
|
|
3916
4160
|
const lines = [];
|
|
3917
|
-
for (const typeDef of ir.metadata.typeDefinitions) {
|
|
3918
|
-
lines.push(typeDef.definition);
|
|
3919
|
-
}
|
|
3920
4161
|
const propsTypeName = ir.metadata.propsType?.raw;
|
|
3921
4162
|
if (propsTypeName && !ir.metadata.propsObjectName) {
|
|
3922
4163
|
lines.push("");
|
|
@@ -3939,7 +4180,7 @@ export default ${this.componentName}` : "";
|
|
|
3939
4180
|
const bodyRefText = [jsxBody, signalInits, scopeIdLine].join(`
|
|
3940
4181
|
`);
|
|
3941
4182
|
const bfScopeAlias = /\b__bfScope\b/.test(bodyRefText) ? "__bfScope" : "__bfScope: _bfScope";
|
|
3942
|
-
const propsParams = ir.metadata.propsParams.map((p) => p
|
|
4183
|
+
const propsParams = ir.metadata.propsParams.map((p) => propsDestructureBinding(p)).join(", ");
|
|
3943
4184
|
const restPropsName = ir.metadata.restPropsName;
|
|
3944
4185
|
const hydrationProps = `__instanceId, ${bfScopeAlias}`;
|
|
3945
4186
|
const parts = [];
|
|
@@ -4086,13 +4327,7 @@ export default ${this.componentName}` : "";
|
|
|
4086
4327
|
}
|
|
4087
4328
|
flattenTemplate(value) {
|
|
4088
4329
|
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("") + "`";
|
|
4330
|
+
return this.renderTemplatePartsAsJs(v.parts);
|
|
4096
4331
|
}
|
|
4097
4332
|
renderComponentProps(comp) {
|
|
4098
4333
|
const parts = [];
|
|
@@ -4587,7 +4822,7 @@ function dangerousInnerHtmlDiagnostic(expr, loc, reason) {
|
|
|
4587
4822
|
};
|
|
4588
4823
|
}
|
|
4589
4824
|
// ../jsx/src/combine-client-js.ts
|
|
4590
|
-
import
|
|
4825
|
+
import ts25 from "typescript";
|
|
4591
4826
|
// ../jsx/src/loop-destructure.ts
|
|
4592
4827
|
function isLowerableLoopDestructure(loop) {
|
|
4593
4828
|
const bindings = loop.paramBindings;
|
|
@@ -4727,9 +4962,9 @@ function escapeRe(s) {
|
|
|
4727
4962
|
return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
4728
4963
|
}
|
|
4729
4964
|
// ../jsx/src/debug.ts
|
|
4730
|
-
import
|
|
4965
|
+
import ts26 from "typescript";
|
|
4731
4966
|
// ../jsx/src/profiler.ts
|
|
4732
|
-
import
|
|
4967
|
+
import ts27 from "typescript";
|
|
4733
4968
|
|
|
4734
4969
|
// ../jsx/src/index.ts
|
|
4735
4970
|
registerBuiltinLoweringPlugins();
|
|
@@ -5500,7 +5735,7 @@ function collectImportedLoopChildComponentErrors(ir, componentName) {
|
|
|
5500
5735
|
}
|
|
5501
5736
|
|
|
5502
5737
|
// src/adapter/spread/spread-codegen.ts
|
|
5503
|
-
import
|
|
5738
|
+
import ts28 from "typescript";
|
|
5504
5739
|
function conditionalSpreadToKolon(ctx, expr) {
|
|
5505
5740
|
if (!expr || expr.kind !== "conditional")
|
|
5506
5741
|
return null;
|
|
@@ -5555,7 +5790,7 @@ function recordIndexAccessToKolon(ctx, val) {
|
|
|
5555
5790
|
if (val.kind !== "index-access" || val.object.kind !== "identifier" || val.index.kind !== "identifier") {
|
|
5556
5791
|
return null;
|
|
5557
5792
|
}
|
|
5558
|
-
const tsVal =
|
|
5793
|
+
const tsVal = ts28.factory.createElementAccessExpression(ts28.factory.createIdentifier(val.object.name), ts28.factory.createIdentifier(val.index.name));
|
|
5559
5794
|
const parsed = parseRecordIndexAccess(tsVal, ctx.localConstants ?? [], ctx.propsParams);
|
|
5560
5795
|
if (!parsed)
|
|
5561
5796
|
return null;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@barefootjs/xslate",
|
|
3
|
-
"version": "0.31.
|
|
3
|
+
"version": "0.31.2",
|
|
4
4
|
"description": "Text::Xslate (Kolon) adapter for BarefootJS — compiles IR to .tx templates and ships the Xslate rendering backend; runs under any PSGI/Plack app",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -55,7 +55,7 @@
|
|
|
55
55
|
"directory": "packages/adapter-xslate"
|
|
56
56
|
},
|
|
57
57
|
"dependencies": {
|
|
58
|
-
"@barefootjs/shared": "0.31.
|
|
58
|
+
"@barefootjs/shared": "0.31.2"
|
|
59
59
|
},
|
|
60
60
|
"peerDependencies": {
|
|
61
61
|
"@barefootjs/jsx": ">=0.2.0",
|
|
@@ -72,9 +72,9 @@
|
|
|
72
72
|
},
|
|
73
73
|
"devDependencies": {
|
|
74
74
|
"@barefootjs/adapter-tests": "0.1.0",
|
|
75
|
-
"@barefootjs/jsx": "0.31.
|
|
76
|
-
"@barefootjs/vite": "0.31.
|
|
77
|
-
"@barefootjs/client": "0.31.
|
|
75
|
+
"@barefootjs/jsx": "0.31.2",
|
|
76
|
+
"@barefootjs/vite": "0.31.2",
|
|
77
|
+
"@barefootjs/client": "0.31.2",
|
|
78
78
|
"typescript": "^5.0.0",
|
|
79
79
|
"vite": "^6.0.0"
|
|
80
80
|
}
|
|
@@ -20,20 +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 these lines (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
|
-
'composite-row-child-aliased-prop':
|
|
38
|
-
'same defect as `aliased-destructured-prop` (#2524), inside a keyed `.map()` loop row: the nested child\'s renamed prop (`{ n: count }`) is always undefined, so both rows render an empty count (https://github.com/piconic-ai/barefootjs/issues/2524)',
|
|
39
23
|
}
|
package/src/test-render.ts
CHANGED
|
@@ -17,8 +17,8 @@
|
|
|
17
17
|
* than the Mojo harness's literal `test_<sN>`.
|
|
18
18
|
*/
|
|
19
19
|
|
|
20
|
-
import { compileJSX, extractSsrDefaults, importsSearchParams, evaluateSignalInit
|
|
21
|
-
import type { ComponentIR } from '@barefootjs/jsx'
|
|
20
|
+
import { compileJSX, extractSsrDefaults, deriveStashFromDefaults, importsSearchParams, evaluateSignalInit } from '@barefootjs/jsx'
|
|
21
|
+
import type { ComponentIR, SsrDefault } from '@barefootjs/jsx'
|
|
22
22
|
import { mkdir, rm } from 'node:fs/promises'
|
|
23
23
|
import { resolve } from 'node:path'
|
|
24
24
|
|
|
@@ -343,6 +343,15 @@ function collectImportedComponentNames(ir: ComponentIR): string[] {
|
|
|
343
343
|
* `ssrDefaults`, shares the parent's script list, and renders the child
|
|
344
344
|
* `.tx` through the same backend. Loop children (no `_bf_slot`) fall back
|
|
345
345
|
* to `<snake_name>` like the Mojo harness.
|
|
346
|
+
*
|
|
347
|
+
* Template vars seed through the production `BarefootJS::_derive_stash_from_
|
|
348
|
+
* defaults` (the same sub `derive_vars_from_defaults`'s Ruby twin and
|
|
349
|
+
* `register_components_from_manifest`'s Python/PHP twins call) rather than a
|
|
350
|
+
* flat `(%$defaults, %$child_props)` merge: the flat merge never resolves an
|
|
351
|
+
* aliased destructured prop's CALLER-facing key (`n`) onto its local
|
|
352
|
+
* template var (`count`) — `$defaults` carries the FULL `{value, propName?,
|
|
353
|
+
* isRestProps?}` shape (not flattened to bare values) so the propName
|
|
354
|
+
* resolution has something to read (#2524 SSR half).
|
|
346
355
|
*/
|
|
347
356
|
function buildChildRenderers(
|
|
348
357
|
childTemplates: Map<string, { template: string; ir: ComponentIR }>,
|
|
@@ -356,8 +365,10 @@ function buildChildRenderers(
|
|
|
356
365
|
for (const [componentName, { ir: childIR }] of childTemplates) {
|
|
357
366
|
const snakeName = toSnakeCase(componentName)
|
|
358
367
|
// Statically-derived ssrDefaults the child template's vars seed from
|
|
359
|
-
// (prop defaults + signal / memo initial values), serialised
|
|
360
|
-
// Perl hashref literal
|
|
368
|
+
// (prop defaults + signal / memo initial values), serialised VERBATIM
|
|
369
|
+
// (propName / isRestProps intact) to a Perl hashref literal — resolved
|
|
370
|
+
// per-call against the REAL child props by `_derive_stash_from_defaults`
|
|
371
|
+
// below, not flattened here.
|
|
361
372
|
const ssrDefaults = extractSsrDefaults(childIR.metadata) ?? {}
|
|
362
373
|
const defaultsPerl = ssrDefaultsToPerl(ssrDefaults)
|
|
363
374
|
const restPropsName = childIR.metadata.restPropsName
|
|
@@ -379,8 +390,9 @@ function buildChildRenderers(
|
|
|
379
390
|
// branch and JSX rest semantics: a caller prop the child didn't
|
|
380
391
|
// destructure (`href` on PaginationPrevious's `{...props}` anchor)
|
|
381
392
|
// belongs in the bag, not as a top-level stash var the template
|
|
382
|
-
// never reads.
|
|
383
|
-
|
|
393
|
+
// never reads. Keep-set uses CALLER-facing names (`sourceName ?? name`)
|
|
394
|
+
// — `$child_props` is keyed by whatever the calling template passed.
|
|
395
|
+
const paramNames = (childIR.metadata.propsParams ?? []).map(p => p.sourceName ?? p.name)
|
|
384
396
|
const keep = JSON.stringify([...new Set([...paramNames, restPropsName, 'children', 'key', '_bf_slot'])])
|
|
385
397
|
lines.push(` {`)
|
|
386
398
|
lines.push(` my %keep = map { $_ => 1 } @{ ${perlArrayLiteral(keep)} };`)
|
|
@@ -409,8 +421,13 @@ function buildChildRenderers(
|
|
|
409
421
|
lines.push(` $child_bf->_child_renderers($bf->_child_renderers);`)
|
|
410
422
|
lines.push(` $child_bf->_scripts($bf->_scripts);`)
|
|
411
423
|
lines.push(` $child_bf->_script_seen($bf->_script_seen);`)
|
|
412
|
-
// Seed template vars
|
|
413
|
-
|
|
424
|
+
// Seed template vars through the production `_derive_stash_from_defaults`
|
|
425
|
+
// — resolves each entry's `propName` against the REAL `$child_props`,
|
|
426
|
+
// falling back to the static `value`; `isRestProps` entries pass the
|
|
427
|
+
// already-routed rest bag through. Caller props still win overall via
|
|
428
|
+
// the final merge (mirrors the ERB harness's `child_props.merge(extra)`).
|
|
429
|
+
lines.push(` my %extra = BarefootJS::_derive_stash_from_defaults($defaults, $child_props);`)
|
|
430
|
+
lines.push(` my %vars = (%$child_props, %extra);`)
|
|
414
431
|
lines.push(` my $rendered = $backend->render_named('${snakeName}', $child_bf, \\%vars);`)
|
|
415
432
|
lines.push(` chomp $rendered;`)
|
|
416
433
|
lines.push(` return $rendered;`)
|
|
@@ -430,22 +447,31 @@ function perlArrayLiteral(jsonArray: string): string {
|
|
|
430
447
|
return `[${names.map(n => `'${n.replace(/[\\']/g, m => `\\${m}`)}'`).join(', ')}]`
|
|
431
448
|
}
|
|
432
449
|
|
|
433
|
-
/**
|
|
434
|
-
|
|
450
|
+
/**
|
|
451
|
+
* Serialise an ssrDefaults map to a Perl hashref literal, VERBATIM — `value`
|
|
452
|
+
* / `propName` / `isRestProps` intact, exactly the shape
|
|
453
|
+
* `BarefootJS::_derive_stash_from_defaults` expects (and exactly what the
|
|
454
|
+
* production build manifest embeds). Do NOT flatten to bare `value`s here:
|
|
455
|
+
* that was the #2524 SSR-half bug — a flattened entry has nothing left for
|
|
456
|
+
* the propName-aware resolution to read, so an aliased destructured prop's
|
|
457
|
+
* caller-facing key is silently dropped.
|
|
458
|
+
*/
|
|
459
|
+
function ssrDefaultsToPerl(defaults: Record<string, SsrDefault>): string {
|
|
435
460
|
const entries: string[] = []
|
|
436
461
|
for (const [name, d] of Object.entries(defaults)) {
|
|
437
|
-
|
|
438
|
-
// bare value. The child renderer's caller props win, so we only need
|
|
439
|
-
// the static fallback `value` here.
|
|
440
|
-
let value: unknown = d
|
|
441
|
-
if (d && typeof d === 'object' && 'value' in (d as Record<string, unknown>)) {
|
|
442
|
-
value = (d as Record<string, unknown>).value
|
|
443
|
-
}
|
|
444
|
-
entries.push(`${perlSingleQuote(name)} => ${toPerlLiteral(value)}`)
|
|
462
|
+
entries.push(`${perlSingleQuote(name)} => ${ssrDefaultEntryToPerl(d)}`)
|
|
445
463
|
}
|
|
446
464
|
return `{${entries.join(', ')}}`
|
|
447
465
|
}
|
|
448
466
|
|
|
467
|
+
/** Serialise a single `SsrDefault` entry to a Perl hashref literal. */
|
|
468
|
+
function ssrDefaultEntryToPerl(d: SsrDefault): string {
|
|
469
|
+
const parts: string[] = [`value => ${toPerlLiteral(d.value)}`]
|
|
470
|
+
if (d.propName !== undefined) parts.push(`propName => ${perlSingleQuote(d.propName)}`)
|
|
471
|
+
if (d.isRestProps) parts.push(`isRestProps => 1`)
|
|
472
|
+
return `{${parts.join(', ')}}`
|
|
473
|
+
}
|
|
474
|
+
|
|
449
475
|
/**
|
|
450
476
|
* Convert PascalCase to snake_case for template naming (matches the
|
|
451
477
|
* adapter's `toTemplateName`).
|
|
@@ -471,23 +497,30 @@ function buildPerlProps(
|
|
|
471
497
|
entries.push(`scope_id => '${escapePerlSingleQuoted(explicitScope)}'`)
|
|
472
498
|
|
|
473
499
|
// Prop params with defaults (before signals, so signals can reference them).
|
|
500
|
+
// Seeded through the shared `deriveStashFromDefaults` (the TS twin of the
|
|
501
|
+
// production `BarefootJS::_derive_stash_from_defaults` this harness ALSO
|
|
502
|
+
// calls at render time for child components) so an aliased destructured
|
|
503
|
+
// prop's CALLER-facing key (`propName`, e.g. `n` for `{ n: count }`) is
|
|
504
|
+
// honoured, not just the local template var name (#2524 SSR half).
|
|
505
|
+
// `props` is keyed by the caller-facing name, exactly what `propName`
|
|
506
|
+
// resolves against.
|
|
507
|
+
const rootSsrDefaults = extractSsrDefaults(ir.metadata) ?? {}
|
|
508
|
+
const derivedProps = deriveStashFromDefaults(rootSsrDefaults, props ?? {})
|
|
474
509
|
for (const param of ir.metadata.propsParams) {
|
|
475
|
-
if (
|
|
476
|
-
if (param.defaultValue) {
|
|
477
|
-
const result = tryEvaluateSignalInit(param.defaultValue.trim(), props)
|
|
478
|
-
if (result.ok) {
|
|
479
|
-
entries.push(`${param.name} => ${toPerlLiteral(result.value)}`)
|
|
480
|
-
continue
|
|
481
|
-
}
|
|
482
|
-
}
|
|
510
|
+
if (param.isRest) continue
|
|
483
511
|
// No default + no caller value: pass `undef` so Kolon's var lookup
|
|
484
512
|
// for an optional prop doesn't fault before its falsy branch elides.
|
|
485
|
-
|
|
513
|
+
const value = derivedProps[param.name] ?? null
|
|
514
|
+
entries.push(`${param.name} => ${toPerlLiteral(value)}`)
|
|
486
515
|
}
|
|
487
516
|
|
|
488
517
|
// Route undeclared props into the rest bag (`spread_attrs($<rest>)`).
|
|
489
518
|
const restPropsName = ir.metadata.restPropsName
|
|
490
|
-
|
|
519
|
+
// Caller-facing keys — an aliased destructured prop's DECLARED set for
|
|
520
|
+
// rest-bag routing must match what the caller actually sent (`n`), not
|
|
521
|
+
// the local binding (`count`), or the caller's own prop silently gets
|
|
522
|
+
// swept into the rest bag as an undeclared extra (#2524).
|
|
523
|
+
const declaredParams = new Set(ir.metadata.propsParams.map(p => p.sourceName ?? p.name))
|
|
491
524
|
const restBagEntries: Array<[string, unknown]> = []
|
|
492
525
|
if (restPropsName && props) {
|
|
493
526
|
for (const [key, value] of Object.entries(props)) {
|
|
@@ -502,11 +535,20 @@ function buildPerlProps(
|
|
|
502
535
|
entries.push(`${restPropsName} => ${toPerlLiteral(Object.fromEntries(restBagEntries))}`)
|
|
503
536
|
}
|
|
504
537
|
|
|
505
|
-
// User props.
|
|
538
|
+
// User props. Skip a key that's already a declared param's LOCAL template
|
|
539
|
+
// var name — `derivedProps` above already resolved that var correctly
|
|
540
|
+
// (through `propName`, for an aliased prop); re-pushing the raw
|
|
541
|
+
// `props[key]` here would silently clobber it with an UNRELATED value
|
|
542
|
+
// whenever a caller happens to also pass a same-spelled-as-local-name prop
|
|
543
|
+
// that isn't this param's actual `propName` (#2524 — surfaced by the
|
|
544
|
+
// aliased-destructured-prop generated data points, which pass both `n`
|
|
545
|
+
// (the real propName) and an incidental `count` key).
|
|
546
|
+
const localParamNames = new Set(ir.metadata.propsParams.map(p => p.name))
|
|
506
547
|
if (props) {
|
|
507
548
|
for (const [key, value] of Object.entries(props)) {
|
|
508
549
|
if (key.startsWith('__')) continue
|
|
509
550
|
if (routedKeys.has(key)) continue
|
|
551
|
+
if (localParamNames.has(key)) continue
|
|
510
552
|
if (typeof value === 'string') {
|
|
511
553
|
entries.push(`${key} => '${value.replace(/\\/g, '\\\\').replace(/'/g, "\\'")}'`)
|
|
512
554
|
} else if (typeof value === 'number') {
|
|
@@ -534,10 +576,9 @@ function buildPerlProps(
|
|
|
534
576
|
|
|
535
577
|
// Memo values seeded from the statically-evaluated ssrDefaults, same
|
|
536
578
|
// as the production plugin's before_render hook.
|
|
537
|
-
const ssrDefaults = extractSsrDefaults(ir.metadata) ?? {}
|
|
538
579
|
for (const memo of ir.metadata.memos) {
|
|
539
|
-
const entry =
|
|
540
|
-
const value = entry
|
|
580
|
+
const entry = rootSsrDefaults[memo.name]
|
|
581
|
+
const value = entry ? entry.value : 0
|
|
541
582
|
entries.push(`${memo.name} => ${toPerlLiteral(value ?? 0)}`)
|
|
542
583
|
}
|
|
543
584
|
|