@barefootjs/mojolicious 0.14.0 → 0.15.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/adapter/boolean-result.d.ts.map +1 -1
- package/dist/adapter/index.js +147 -47
- package/dist/adapter/mojo-adapter.d.ts +62 -10
- package/dist/adapter/mojo-adapter.d.ts.map +1 -1
- package/dist/build.js +147 -47
- package/dist/index.js +147 -47
- package/dist/test-render.d.ts.map +1 -1
- package/lib/BarefootJS/Backend/Mojo.pm +1 -1
- package/lib/Mojolicious/Plugin/BarefootJS/DevReload.pm +1 -1
- package/lib/Mojolicious/Plugin/BarefootJS.pm +11 -1
- package/package.json +3 -3
- package/src/__tests__/mojo-adapter.test.ts +53 -4
- package/src/adapter/boolean-result.ts +5 -0
- package/src/adapter/mojo-adapter.ts +287 -39
- package/src/test-render.ts +98 -8
package/dist/build.js
CHANGED
|
@@ -6,6 +6,8 @@ import {
|
|
|
6
6
|
parseExpression as parseExpression2,
|
|
7
7
|
parseStyleObjectEntries,
|
|
8
8
|
isSupported,
|
|
9
|
+
exprToString,
|
|
10
|
+
parseProviderObjectLiteral,
|
|
9
11
|
identifierPath,
|
|
10
12
|
emitParsedExpr,
|
|
11
13
|
emitIRNode,
|
|
@@ -16,7 +18,10 @@ import {
|
|
|
16
18
|
extractArrowBodyExpression,
|
|
17
19
|
collectContextConsumers,
|
|
18
20
|
isLowerableObjectRestDestructure,
|
|
19
|
-
|
|
21
|
+
collectModuleStringConsts,
|
|
22
|
+
lookupStaticRecordLiteral,
|
|
23
|
+
searchParamsLocalNames,
|
|
24
|
+
matchSearchParamsMethodCall
|
|
20
25
|
} from "@barefootjs/jsx";
|
|
21
26
|
|
|
22
27
|
// src/adapter/boolean-result.ts
|
|
@@ -63,6 +68,8 @@ var ARIA_BOOLEAN_ATTRS = new Set([
|
|
|
63
68
|
"aria-multiselectable",
|
|
64
69
|
"aria-readonly",
|
|
65
70
|
"aria-required",
|
|
71
|
+
"aria-selected",
|
|
72
|
+
"aria-expanded",
|
|
66
73
|
"aria-checked",
|
|
67
74
|
"aria-pressed"
|
|
68
75
|
]);
|
|
@@ -71,7 +78,7 @@ function isAriaBooleanAttr(name) {
|
|
|
71
78
|
}
|
|
72
79
|
|
|
73
80
|
// src/adapter/mojo-adapter.ts
|
|
74
|
-
import { BF_SLOT, BF_COND } from "@barefootjs/shared";
|
|
81
|
+
import { BF_SLOT, BF_COND, BF_REGION } from "@barefootjs/shared";
|
|
75
82
|
var MOJO_TEMPLATE_PRIMITIVES = {
|
|
76
83
|
"JSON.stringify": { arity: 1, emit: (args) => `bf->json(${args[0]})` },
|
|
77
84
|
String: { arity: 1, emit: (args) => `bf->string(${args[0]})` },
|
|
@@ -89,22 +96,6 @@ function resolveJsxChildrenProp(props) {
|
|
|
89
96
|
return [];
|
|
90
97
|
return prop.value.children;
|
|
91
98
|
}
|
|
92
|
-
function parsePureStringLiteral(source) {
|
|
93
|
-
const sf = ts.createSourceFile("__const.ts", `const __x = (${source});`, ts.ScriptTarget.Latest, false);
|
|
94
|
-
const stmt = sf.statements[0];
|
|
95
|
-
if (!stmt || !ts.isVariableStatement(stmt))
|
|
96
|
-
return null;
|
|
97
|
-
const decl = stmt.declarationList.declarations[0];
|
|
98
|
-
let init = decl?.initializer;
|
|
99
|
-
while (init && ts.isParenthesizedExpression(init))
|
|
100
|
-
init = init.expression;
|
|
101
|
-
if (!init)
|
|
102
|
-
return null;
|
|
103
|
-
if (ts.isStringLiteral(init) || ts.isNoSubstitutionTemplateLiteral(init)) {
|
|
104
|
-
return init.text;
|
|
105
|
-
}
|
|
106
|
-
return evalStringArrayJoin(source);
|
|
107
|
-
}
|
|
108
99
|
function perlHashKey(name) {
|
|
109
100
|
return /^[A-Za-z_][A-Za-z0-9_]*$/.test(name) ? name : `'${name.replace(/'/g, "\\'")}'`;
|
|
110
101
|
}
|
|
@@ -152,7 +143,9 @@ class MojoAdapter extends BaseAdapter {
|
|
|
152
143
|
inLoop = false;
|
|
153
144
|
propsObjectName = null;
|
|
154
145
|
propsParams = [];
|
|
146
|
+
booleanTypedProps = new Set;
|
|
155
147
|
stringValueNames = new Set;
|
|
148
|
+
_searchParamsLocals = new Set;
|
|
156
149
|
moduleStringConsts = new Map;
|
|
157
150
|
localConstants = [];
|
|
158
151
|
loopBoundNames = new Map;
|
|
@@ -169,6 +162,7 @@ class MojoAdapter extends BaseAdapter {
|
|
|
169
162
|
this.propsObjectName = ir.metadata.propsObjectName ?? null;
|
|
170
163
|
augmentInheritedPropAccesses(ir);
|
|
171
164
|
this.propsParams = ir.metadata.propsParams.map((p) => ({ name: p.name }));
|
|
165
|
+
this.booleanTypedProps = new Set(ir.metadata.propsParams.filter((prop) => prop.type?.primitive === "boolean" || prop.type?.raw === "boolean").map((prop) => prop.name));
|
|
172
166
|
this.nullableOptionalProps = new Set(ir.metadata.propsParams.filter((p) => p.defaultValue === undefined && !p.isRest && p.type?.kind !== "primitive").map((p) => p.name));
|
|
173
167
|
this.stringValueNames = new Set;
|
|
174
168
|
for (const s of ir.metadata.signals) {
|
|
@@ -180,7 +174,8 @@ class MojoAdapter extends BaseAdapter {
|
|
|
180
174
|
if (isStringTypeInfo(p.type))
|
|
181
175
|
this.stringValueNames.add(p.name);
|
|
182
176
|
}
|
|
183
|
-
this.moduleStringConsts =
|
|
177
|
+
this.moduleStringConsts = collectModuleStringConsts(ir.metadata.localConstants);
|
|
178
|
+
this._searchParamsLocals = searchParamsLocalNames(ir.metadata);
|
|
184
179
|
this.localConstants = ir.metadata.localConstants ?? [];
|
|
185
180
|
this.loopBoundNames.clear();
|
|
186
181
|
this.errors = [];
|
|
@@ -210,18 +205,49 @@ class MojoAdapter extends BaseAdapter {
|
|
|
210
205
|
extension: this.extension
|
|
211
206
|
};
|
|
212
207
|
}
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
continue;
|
|
218
|
-
if (c.value === undefined)
|
|
219
|
-
continue;
|
|
220
|
-
const literal = parsePureStringLiteral(c.value);
|
|
221
|
-
if (literal !== null)
|
|
222
|
-
map.set(c.name, literal);
|
|
208
|
+
isBooleanTypedPropRef(expr) {
|
|
209
|
+
let bare = expr.trim();
|
|
210
|
+
if (this.propsObjectName && bare.startsWith(`${this.propsObjectName}.`)) {
|
|
211
|
+
bare = bare.slice(this.propsObjectName.length + 1);
|
|
223
212
|
}
|
|
224
|
-
|
|
213
|
+
if (!/^[A-Za-z_$][\w$]*$/.test(bare))
|
|
214
|
+
return false;
|
|
215
|
+
return this.booleanTypedProps.has(bare);
|
|
216
|
+
}
|
|
217
|
+
parseUndefinedAlternateTernary(expr) {
|
|
218
|
+
const parsed = parseExpression2(expr.trim());
|
|
219
|
+
if (parsed?.kind !== "conditional")
|
|
220
|
+
return null;
|
|
221
|
+
const alt = parsed.alternate;
|
|
222
|
+
const isUndef = alt.kind === "identifier" && (alt.name === "undefined" || alt.name === "null") || alt.kind === "literal" && (alt.value === null || alt.value === undefined);
|
|
223
|
+
if (!isUndef)
|
|
224
|
+
return null;
|
|
225
|
+
return {
|
|
226
|
+
condition: exprToString(parsed.test),
|
|
227
|
+
consequent: exprToString(parsed.consequent)
|
|
228
|
+
};
|
|
229
|
+
}
|
|
230
|
+
resolveLiteralConst(name) {
|
|
231
|
+
if (this.loopBoundNames?.has?.(name))
|
|
232
|
+
return null;
|
|
233
|
+
const c = (this.localConstants ?? []).find((lc) => lc.name === name);
|
|
234
|
+
if (c?.value === undefined)
|
|
235
|
+
return null;
|
|
236
|
+
const v = c.value.trim();
|
|
237
|
+
if (/^-?\d+(\.\d+)?$/.test(v))
|
|
238
|
+
return v;
|
|
239
|
+
const strLit = /^'([^'\\]*)'$/.exec(v) ?? /^"([^"\\]*)"$/.exec(v);
|
|
240
|
+
if (strLit)
|
|
241
|
+
return `'${strLit[1].replace(/[\\']/g, (m) => `\\${m}`)}'`;
|
|
242
|
+
return null;
|
|
243
|
+
}
|
|
244
|
+
resolveStaticRecordLiteral(objectName, key) {
|
|
245
|
+
if (this.loopBoundNames?.has?.(objectName))
|
|
246
|
+
return null;
|
|
247
|
+
const hit = lookupStaticRecordLiteral(objectName, key, this.localConstants);
|
|
248
|
+
if (!hit)
|
|
249
|
+
return null;
|
|
250
|
+
return hit.kind === "number" ? hit.text : `'${hit.text.replace(/[\\']/g, (m) => `\\${m}`)}'`;
|
|
225
251
|
}
|
|
226
252
|
resolveModuleStringConst(name) {
|
|
227
253
|
if (this.loopBoundNames.has(name))
|
|
@@ -289,12 +315,29 @@ class MojoAdapter extends BaseAdapter {
|
|
|
289
315
|
if (v.kind === "literal") {
|
|
290
316
|
return typeof v.value === "string" ? `'${v.value.replace(/[\\']/g, (m) => `\\${m}`)}'` : String(v.value);
|
|
291
317
|
}
|
|
292
|
-
if (v.kind === "expression")
|
|
318
|
+
if (v.kind === "expression") {
|
|
319
|
+
const hashref = this.providerObjectLiteralPerl(v.expr);
|
|
320
|
+
if (hashref !== null)
|
|
321
|
+
return hashref;
|
|
293
322
|
return this.convertExpressionToPerl(v.expr);
|
|
323
|
+
}
|
|
294
324
|
if (v.kind === "template")
|
|
295
325
|
return this.convertTemplateLiteralPartsToPerl(v.parts);
|
|
296
326
|
return "undef";
|
|
297
327
|
}
|
|
328
|
+
providerObjectLiteralPerl(expr) {
|
|
329
|
+
const members = parseProviderObjectLiteral(expr.trim());
|
|
330
|
+
if (members === null)
|
|
331
|
+
return null;
|
|
332
|
+
const entries = members.map((m) => {
|
|
333
|
+
const key = `'${m.name.replace(/[\\']/g, (c) => `\\${c}`)}'`;
|
|
334
|
+
if (m.kind === "function" || /^on[A-Z]/.test(m.name))
|
|
335
|
+
return `${key} => undef`;
|
|
336
|
+
const src = m.kind === "getter" ? m.body : m.expr;
|
|
337
|
+
return `${key} => ${this.convertExpressionToPerl(src)}`;
|
|
338
|
+
});
|
|
339
|
+
return `{ ${entries.join(", ")} }`;
|
|
340
|
+
}
|
|
298
341
|
contextDefaultPerl(c) {
|
|
299
342
|
const d = c.defaultValue;
|
|
300
343
|
if (d === null || d === undefined)
|
|
@@ -318,7 +361,6 @@ class MojoAdapter extends BaseAdapter {
|
|
|
318
361
|
const signals = ir.metadata.signals ?? [];
|
|
319
362
|
if (memos.length === 0 && signals.length === 0)
|
|
320
363
|
return "";
|
|
321
|
-
const ssrDefaults = extractSsrDefaults(ir.metadata) ?? {};
|
|
322
364
|
const available = new Set(ir.metadata.propsParams.map((p) => p.name));
|
|
323
365
|
const lines = [];
|
|
324
366
|
for (const signal of signals) {
|
|
@@ -328,18 +370,12 @@ class MojoAdapter extends BaseAdapter {
|
|
|
328
370
|
available.add(signal.getter);
|
|
329
371
|
}
|
|
330
372
|
for (const memo of memos) {
|
|
331
|
-
const def = ssrDefaults[memo.name];
|
|
332
|
-
const isNull = !def || typeof def === "object" && "value" in def && def.value === null;
|
|
333
|
-
if (!isNull) {
|
|
334
|
-
available.add(memo.name);
|
|
335
|
-
continue;
|
|
336
|
-
}
|
|
337
373
|
const body = extractArrowBodyExpression(memo.computation);
|
|
338
|
-
if (body
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
374
|
+
if (body !== null) {
|
|
375
|
+
const perl = this.tryLowerToPerl(body, available);
|
|
376
|
+
if (perl !== null)
|
|
377
|
+
lines.push(`% my $${memo.name} = ${perl};`);
|
|
378
|
+
}
|
|
343
379
|
available.add(memo.name);
|
|
344
380
|
}
|
|
345
381
|
return lines.length > 0 ? lines.join(`
|
|
@@ -374,6 +410,9 @@ class MojoAdapter extends BaseAdapter {
|
|
|
374
410
|
if (element.slotId) {
|
|
375
411
|
hydrationAttrs += ` ${this.renderSlotMarker(element.slotId)}`;
|
|
376
412
|
}
|
|
413
|
+
if (element.regionId) {
|
|
414
|
+
hydrationAttrs += ` ${BF_REGION}="${element.regionId}"`;
|
|
415
|
+
}
|
|
377
416
|
const voidElements = [
|
|
378
417
|
"area",
|
|
379
418
|
"base",
|
|
@@ -654,7 +693,7 @@ ${renderedChildren}` : renderedChildren;
|
|
|
654
693
|
renderComponent(comp) {
|
|
655
694
|
const propParts = [];
|
|
656
695
|
for (const p of comp.props) {
|
|
657
|
-
if (p.name.match(/^on[A-Z]/) && p.value.kind === "expression")
|
|
696
|
+
if ((p.name.match(/^on[A-Z]/) || p.name === "ref") && p.value.kind === "expression")
|
|
658
697
|
continue;
|
|
659
698
|
const lowered = emitAttrValue(p.value, this.componentPropEmitter, p.name);
|
|
660
699
|
if (lowered)
|
|
@@ -667,13 +706,17 @@ ${renderedChildren}` : renderedChildren;
|
|
|
667
706
|
const tplName = this.toTemplateName(comp.name);
|
|
668
707
|
const effectiveChildren = comp.children.length > 0 ? comp.children : resolveJsxChildrenProp(comp.props);
|
|
669
708
|
if (effectiveChildren.length > 0) {
|
|
709
|
+
const prevInLoop = this.inLoop;
|
|
710
|
+
this.inLoop = false;
|
|
670
711
|
const childrenBody = this.renderChildren(effectiveChildren);
|
|
712
|
+
this.inLoop = prevInLoop;
|
|
671
713
|
const varName = `$bf_children_${comp.slotId ?? "c" + this.childrenCaptureCounter++}`;
|
|
672
714
|
return `<% my ${varName} = begin %>${childrenBody}<% end %><%== bf->render_child('${tplName}'${propsStr}, children => ${varName}) %>`;
|
|
673
715
|
}
|
|
674
716
|
return `<%== bf->render_child('${tplName}'${propsStr}) %>`;
|
|
675
717
|
}
|
|
676
718
|
childrenCaptureCounter = 0;
|
|
719
|
+
presenceVarCounter = 0;
|
|
677
720
|
toTemplateName(componentName) {
|
|
678
721
|
return componentName.replace(/([A-Z])/g, "_$1").toLowerCase().replace(/^_/, "");
|
|
679
722
|
}
|
|
@@ -729,14 +772,28 @@ ${children}`;
|
|
|
729
772
|
const normalizedBareId = this.propsObjectName && bareId.startsWith(`${this.propsObjectName}.`) ? bareId.slice(this.propsObjectName.length + 1) : bareId;
|
|
730
773
|
if (!isBooleanAttr(name) && !value.presenceOrUndefined && /^[A-Za-z_$][\w$]*$/.test(normalizedBareId) && this.nullableOptionalProps.has(normalizedBareId)) {
|
|
731
774
|
const perl2 = this.convertExpressionToPerl(value.expr);
|
|
732
|
-
const body = isBooleanResultExpr(value.expr) || isAriaBooleanAttr(name) ? `${name}="<%= bf->bool_str(${perl2}) %>"` : `${name}="<%= ${perl2} %>"`;
|
|
775
|
+
const body = isBooleanResultExpr(value.expr) || isAriaBooleanAttr(name) || this.isBooleanTypedPropRef(value.expr) ? `${name}="<%= bf->bool_str(${perl2}) %>"` : `${name}="<%= ${perl2} %>"`;
|
|
733
776
|
return `<% if (defined ${perl2}) { %>${body}<% } %>`;
|
|
734
777
|
}
|
|
735
|
-
if (isBooleanAttr(name)
|
|
778
|
+
if (isBooleanAttr(name)) {
|
|
736
779
|
return `<%= ${this.convertExpressionToPerl(value.expr)} ? '${name}' : '' %>`;
|
|
737
780
|
}
|
|
781
|
+
if (value.presenceOrUndefined) {
|
|
782
|
+
const perl2 = this.convertExpressionToPerl(value.expr);
|
|
783
|
+
const tmp = `$bf_pu${this.presenceVarCounter++}`;
|
|
784
|
+
const body = isBooleanResultExpr(value.expr) || isAriaBooleanAttr(name) || this.isBooleanTypedPropRef(value.expr) ? `${name}="<%= bf->bool_str(${tmp}) %>"` : `${name}="<%= ${tmp} %>"`;
|
|
785
|
+
return `<% my ${tmp} = ${perl2}; if (${tmp}) { %>${body}<% } %>`;
|
|
786
|
+
}
|
|
787
|
+
{
|
|
788
|
+
const m = this.parseUndefinedAlternateTernary(value.expr);
|
|
789
|
+
if (m) {
|
|
790
|
+
const cond = this.convertExpressionToPerl(m.condition);
|
|
791
|
+
const val = this.convertExpressionToPerl(m.consequent);
|
|
792
|
+
return `<% if (${cond}) { %>${name}="<%= ${val} %>"<% } %>`;
|
|
793
|
+
}
|
|
794
|
+
}
|
|
738
795
|
const perl = this.convertExpressionToPerl(value.expr);
|
|
739
|
-
if (isBooleanResultExpr(value.expr) || isAriaBooleanAttr(name)) {
|
|
796
|
+
if (isBooleanResultExpr(value.expr) || isAriaBooleanAttr(name) || this.isBooleanTypedPropRef(value.expr)) {
|
|
740
797
|
return `${name}="<%= bf->bool_str(${perl}) %>"`;
|
|
741
798
|
}
|
|
742
799
|
return `${name}="<%= ${perl} %>"`;
|
|
@@ -995,6 +1052,18 @@ ${reason}` : "";
|
|
|
995
1052
|
return n;
|
|
996
1053
|
})();
|
|
997
1054
|
const indexed = this.recordIndexAccessToPerl(initNode);
|
|
1055
|
+
if (indexed === null && ts.isElementAccessExpression(initNode) && initNode.argumentExpression && !ts.isNumericLiteral(initNode.argumentExpression) && !ts.isStringLiteral(initNode.argumentExpression)) {
|
|
1056
|
+
this.errors.push({
|
|
1057
|
+
code: "BF101",
|
|
1058
|
+
severity: "error",
|
|
1059
|
+
message: `Spread object value '${initNode.getText(sf)}' indexes a record map whose values aren't scalar literals — it can't lower to an inline Perl hashref.`,
|
|
1060
|
+
loc: { file: this.componentName + ".tsx", start: { line: 1, column: 0 }, end: { line: 1, column: 0 } },
|
|
1061
|
+
suggestion: {
|
|
1062
|
+
message: "Index a record whose values are number/string literals, or move the spread into a `'use client'` component so hydration computes it."
|
|
1063
|
+
}
|
|
1064
|
+
});
|
|
1065
|
+
return null;
|
|
1066
|
+
}
|
|
998
1067
|
const valPerl = indexed !== null ? indexed : this.convertExpressionToPerl(prop.initializer.getText(sf));
|
|
999
1068
|
entries.push(`'${key.replace(/'/g, "\\'")}' => ${valPerl}`);
|
|
1000
1069
|
}
|
|
@@ -1118,6 +1187,11 @@ function renderArrayMethod(method, object, args, emit) {
|
|
|
1118
1187
|
const recv = emit(object);
|
|
1119
1188
|
return `bf->trim(${recv})`;
|
|
1120
1189
|
}
|
|
1190
|
+
case "toFixed": {
|
|
1191
|
+
const recv = emit(object);
|
|
1192
|
+
const digits = args.length >= 1 ? emit(args[0]) : "0";
|
|
1193
|
+
return `bf->to_fixed(${recv}, ${digits})`;
|
|
1194
|
+
}
|
|
1121
1195
|
case "split": {
|
|
1122
1196
|
const recv = emit(object);
|
|
1123
1197
|
if (args.length === 0) {
|
|
@@ -1220,6 +1294,10 @@ function isStringTypedOperand(expr, isStringName) {
|
|
|
1220
1294
|
}
|
|
1221
1295
|
return false;
|
|
1222
1296
|
}
|
|
1297
|
+
function emitIndexAccessPerl(object, index, emit, isStringName) {
|
|
1298
|
+
const i = emit(index);
|
|
1299
|
+
return isStringTypedOperand(index, isStringName) ? `${emit(object)}->{${i}}` : `${emit(object)}->[${i}]`;
|
|
1300
|
+
}
|
|
1223
1301
|
|
|
1224
1302
|
class MojoFilterEmitter {
|
|
1225
1303
|
param;
|
|
@@ -1253,6 +1331,9 @@ class MojoFilterEmitter {
|
|
|
1253
1331
|
}
|
|
1254
1332
|
return `${emit(object)}->{${property}}`;
|
|
1255
1333
|
}
|
|
1334
|
+
indexAccess(object, index, emit) {
|
|
1335
|
+
return emitIndexAccessPerl(object, index, emit, this.isStringName);
|
|
1336
|
+
}
|
|
1256
1337
|
call(callee, args, emit) {
|
|
1257
1338
|
if (callee.kind === "identifier" && args.length === 0) {
|
|
1258
1339
|
return `$${callee.name}`;
|
|
@@ -1353,9 +1434,14 @@ class MojoTopLevelEmitter {
|
|
|
1353
1434
|
this.adapter = adapter;
|
|
1354
1435
|
}
|
|
1355
1436
|
identifier(name) {
|
|
1437
|
+
if (name === "undefined" || name === "null")
|
|
1438
|
+
return "undef";
|
|
1356
1439
|
const inlined = this.adapter.resolveModuleStringConst(name);
|
|
1357
1440
|
if (inlined !== null)
|
|
1358
1441
|
return inlined;
|
|
1442
|
+
const literalConst = this.adapter.resolveLiteralConst(name);
|
|
1443
|
+
if (literalConst !== null)
|
|
1444
|
+
return literalConst;
|
|
1359
1445
|
return `$${name}`;
|
|
1360
1446
|
}
|
|
1361
1447
|
literal(value, literalType) {
|
|
@@ -1371,15 +1457,29 @@ class MojoTopLevelEmitter {
|
|
|
1371
1457
|
if (object.kind === "identifier" && object.name === "props") {
|
|
1372
1458
|
return `$${property}`;
|
|
1373
1459
|
}
|
|
1460
|
+
if (object.kind === "identifier") {
|
|
1461
|
+
const staticValue = this.adapter.resolveStaticRecordLiteral(object.name, property);
|
|
1462
|
+
if (staticValue !== null)
|
|
1463
|
+
return staticValue;
|
|
1464
|
+
}
|
|
1374
1465
|
const obj = emit(object);
|
|
1375
1466
|
if (property === "length")
|
|
1376
1467
|
return `scalar(@{${obj}})`;
|
|
1377
1468
|
return `${obj}->{${property}}`;
|
|
1378
1469
|
}
|
|
1470
|
+
indexAccess(object, index, emit) {
|
|
1471
|
+
return emitIndexAccessPerl(object, index, emit, (n) => this.adapter._isStringValueName(n));
|
|
1472
|
+
}
|
|
1379
1473
|
call(callee, args, emit) {
|
|
1380
1474
|
if (callee.kind === "identifier" && args.length === 0) {
|
|
1381
1475
|
return `$${callee.name}`;
|
|
1382
1476
|
}
|
|
1477
|
+
if (this.adapter._searchParamsLocals.size > 0) {
|
|
1478
|
+
const sp = matchSearchParamsMethodCall(callee, args, this.adapter._searchParamsLocals);
|
|
1479
|
+
if (sp) {
|
|
1480
|
+
return `$searchParams->${sp.method}(${sp.args.map(emit).join(", ")})`;
|
|
1481
|
+
}
|
|
1482
|
+
}
|
|
1383
1483
|
const path = identifierPath(callee);
|
|
1384
1484
|
const spec = path ? MOJO_TEMPLATE_PRIMITIVES[path] : undefined;
|
|
1385
1485
|
if (path && spec) {
|