@firsthandjs/compiler 0.9.1 → 0.10.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/attributes.d.ts +13 -0
- package/dist/attributes.d.ts.map +1 -0
- package/dist/chunk-JEIWCE46.js +1998 -0
- package/dist/components.d.ts +25 -0
- package/dist/components.d.ts.map +1 -0
- package/dist/guarded.d.ts +22 -0
- package/dist/guarded.d.ts.map +1 -0
- package/dist/html.d.ts +12 -0
- package/dist/html.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/jsx.d.ts +39 -0
- package/dist/jsx.d.ts.map +1 -0
- package/dist/lists.d.ts +24 -0
- package/dist/lists.d.ts.map +1 -0
- package/dist/marks.d.ts +31 -0
- package/dist/marks.d.ts.map +1 -0
- package/dist/markup.d.ts +27 -0
- package/dist/markup.d.ts.map +1 -0
- package/dist/nodes.d.ts +55 -0
- package/dist/nodes.d.ts.map +1 -0
- package/dist/options.d.ts +48 -0
- package/dist/options.d.ts.map +1 -0
- package/dist/plugin.d.ts +12 -0
- package/dist/plugin.d.ts.map +1 -0
- package/dist/positions.d.ts +50 -0
- package/dist/positions.d.ts.map +1 -0
- package/dist/props.d.ts +25 -0
- package/dist/props.d.ts.map +1 -0
- package/dist/runs.d.ts +69 -0
- package/dist/runs.d.ts.map +1 -0
- package/dist/site.d.ts +12 -0
- package/dist/site.d.ts.map +1 -0
- package/dist/state.d.ts +84 -0
- package/dist/state.d.ts.map +1 -0
- package/dist/strict.d.ts +72 -0
- package/dist/strict.d.ts.map +1 -0
- package/dist/template.d.ts +11 -0
- package/dist/template.d.ts.map +1 -0
- package/dist/transform.d.ts +14 -86
- package/dist/transform.d.ts.map +1 -1
- package/dist/vite.js +1 -1
- package/package.json +1 -1
- package/dist/chunk-GUVVHV7H.js +0 -1845
package/dist/chunk-GUVVHV7H.js
DELETED
|
@@ -1,1845 +0,0 @@
|
|
|
1
|
-
// packages/compiler/src/ids.ts
|
|
2
|
-
import { createHash } from "node:crypto";
|
|
3
|
-
function stableId(packageName, filename) {
|
|
4
|
-
const normalised = filename.split(String.fromCharCode(92)).join("/").replace(/^(?:.*\/)?(?:src|lib)\//, "");
|
|
5
|
-
return createHash("sha256").update(`${packageName}:${normalised}`).digest("hex").slice(0, 8);
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
// packages/compiler/src/transform.ts
|
|
9
|
-
import * as t from "@babel/types";
|
|
10
|
-
|
|
11
|
-
// packages/compiler/src/html.ts
|
|
12
|
-
var VOID_ELEMENTS = /* @__PURE__ */ new Set([
|
|
13
|
-
"area",
|
|
14
|
-
"base",
|
|
15
|
-
"br",
|
|
16
|
-
"col",
|
|
17
|
-
"embed",
|
|
18
|
-
"hr",
|
|
19
|
-
"img",
|
|
20
|
-
"input",
|
|
21
|
-
"link",
|
|
22
|
-
"meta",
|
|
23
|
-
"param",
|
|
24
|
-
"source",
|
|
25
|
-
"track",
|
|
26
|
-
"wbr"
|
|
27
|
-
]);
|
|
28
|
-
var BOOLEAN_PROPERTIES = /* @__PURE__ */ new Set([
|
|
29
|
-
"checked",
|
|
30
|
-
"disabled",
|
|
31
|
-
"multiple",
|
|
32
|
-
"muted",
|
|
33
|
-
"readOnly",
|
|
34
|
-
"selected",
|
|
35
|
-
"autofocus",
|
|
36
|
-
"autoplay",
|
|
37
|
-
"controls",
|
|
38
|
-
"loop",
|
|
39
|
-
"open",
|
|
40
|
-
"required"
|
|
41
|
-
]);
|
|
42
|
-
var DOM_PROPERTIES = /* @__PURE__ */ new Set([
|
|
43
|
-
"value",
|
|
44
|
-
"textContent",
|
|
45
|
-
"innerHTML",
|
|
46
|
-
"innerText",
|
|
47
|
-
"scrollTop",
|
|
48
|
-
"scrollLeft",
|
|
49
|
-
"volume",
|
|
50
|
-
"currentTime",
|
|
51
|
-
"playbackRate",
|
|
52
|
-
"srcObject"
|
|
53
|
-
]);
|
|
54
|
-
var SVG_ELEMENTS = /* @__PURE__ */ new Set([
|
|
55
|
-
"svg",
|
|
56
|
-
"path",
|
|
57
|
-
"circle",
|
|
58
|
-
"rect",
|
|
59
|
-
"line",
|
|
60
|
-
"polyline",
|
|
61
|
-
"polygon",
|
|
62
|
-
"ellipse",
|
|
63
|
-
"g",
|
|
64
|
-
"defs",
|
|
65
|
-
"use",
|
|
66
|
-
"text",
|
|
67
|
-
"tspan",
|
|
68
|
-
"symbol",
|
|
69
|
-
"mask",
|
|
70
|
-
"pattern",
|
|
71
|
-
"clipPath",
|
|
72
|
-
"linearGradient",
|
|
73
|
-
"radialGradient",
|
|
74
|
-
"stop",
|
|
75
|
-
"filter"
|
|
76
|
-
]);
|
|
77
|
-
function escapeText(value) {
|
|
78
|
-
return value.replace(/&/g, "&").replace(/</g, "<");
|
|
79
|
-
}
|
|
80
|
-
function escapeAttribute(value) {
|
|
81
|
-
return value.replace(/&/g, "&").replace(/"/g, """);
|
|
82
|
-
}
|
|
83
|
-
function eventName(attribute) {
|
|
84
|
-
return attribute.slice(2).toLowerCase();
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
// packages/compiler/src/transform.ts
|
|
88
|
-
var RUNTIME = "@firsthandjs/dom/internal";
|
|
89
|
-
var SERVER_RUNTIME = "@firsthandjs/server/internal";
|
|
90
|
-
var CORE = "@firsthandjs/core";
|
|
91
|
-
var CHILD_THUNK = /* @__PURE__ */ Symbol("firsthand.childThunk");
|
|
92
|
-
var GENERATED = /* @__PURE__ */ Symbol("firsthand.generated");
|
|
93
|
-
function generated(arrow) {
|
|
94
|
-
arrow[GENERATED] = true;
|
|
95
|
-
return arrow;
|
|
96
|
-
}
|
|
97
|
-
function pushOnce(build, statement) {
|
|
98
|
-
build.once.push(statement);
|
|
99
|
-
}
|
|
100
|
-
function pushEach(build, statement) {
|
|
101
|
-
build.each.push(statement);
|
|
102
|
-
}
|
|
103
|
-
function firsthandPlugin(_api, options = {}) {
|
|
104
|
-
return {
|
|
105
|
-
name: "firsthand",
|
|
106
|
-
visitor: {
|
|
107
|
-
Program: {
|
|
108
|
-
enter(path, state) {
|
|
109
|
-
state.firsthand = {
|
|
110
|
-
imports: /* @__PURE__ */ new Map(),
|
|
111
|
-
templates: [],
|
|
112
|
-
counter: 0,
|
|
113
|
-
moduleId: stableId(options.packageName ?? "app", state.filename ?? "module"),
|
|
114
|
-
views: /* @__PURE__ */ new Map(),
|
|
115
|
-
viewNodes: /* @__PURE__ */ new Set(),
|
|
116
|
-
runs: /* @__PURE__ */ new Map(),
|
|
117
|
-
ssr: options.ssr === true,
|
|
118
|
-
hydratable: options.hydratable === true && options.ssr !== true
|
|
119
|
-
};
|
|
120
|
-
collectViews(path, state);
|
|
121
|
-
if (options.ssr !== true) {
|
|
122
|
-
collectRuns(path, state);
|
|
123
|
-
}
|
|
124
|
-
},
|
|
125
|
-
exit(path, state) {
|
|
126
|
-
const { imports, templates, views } = state.firsthand;
|
|
127
|
-
for (const [, local] of views) {
|
|
128
|
-
path.node.body.push(
|
|
129
|
-
expressionStatement2(t.callExpression(runtime(state, "view"), [t.cloneNode(local)]))
|
|
130
|
-
);
|
|
131
|
-
}
|
|
132
|
-
if (templates.length > 0) {
|
|
133
|
-
path.node.body.unshift(t.variableDeclaration("const", templates));
|
|
134
|
-
}
|
|
135
|
-
for (const [source, names] of groupBySource(imports)) {
|
|
136
|
-
path.node.body.unshift(
|
|
137
|
-
t.importDeclaration(
|
|
138
|
-
names.map(([exported, local]) => t.importSpecifier(local, t.identifier(exported))),
|
|
139
|
-
t.stringLiteral(source)
|
|
140
|
-
)
|
|
141
|
-
);
|
|
142
|
-
}
|
|
143
|
-
}
|
|
144
|
-
},
|
|
145
|
-
// Babel enters the outermost JSX node first. Its nested elements are
|
|
146
|
-
// folded into the template and discarded; the nodes that survive (a
|
|
147
|
-
// component's children, a dynamic expression) are re-visited later, by
|
|
148
|
-
// which time they are no longer inside JSX.
|
|
149
|
-
JSXElement(path, state) {
|
|
150
|
-
if (!state.firsthand.ssr) {
|
|
151
|
-
rewriteKeyedMaps(path, state);
|
|
152
|
-
}
|
|
153
|
-
path.replaceWith(compileNode(path, state));
|
|
154
|
-
},
|
|
155
|
-
JSXFragment(path, state) {
|
|
156
|
-
if (!state.firsthand.ssr) {
|
|
157
|
-
rewriteKeyedMaps(path, state);
|
|
158
|
-
}
|
|
159
|
-
path.replaceWith(compileNode(path, state));
|
|
160
|
-
},
|
|
161
|
-
CallExpression(path, state) {
|
|
162
|
-
annotateComponent(path, state, options);
|
|
163
|
-
},
|
|
164
|
-
VariableDeclarator(path, state) {
|
|
165
|
-
if (options.devtools === true && options.ssr !== true) {
|
|
166
|
-
nameCell(path, state);
|
|
167
|
-
}
|
|
168
|
-
}
|
|
169
|
-
}
|
|
170
|
-
};
|
|
171
|
-
}
|
|
172
|
-
function groupBySource(imports) {
|
|
173
|
-
const grouped = /* @__PURE__ */ new Map();
|
|
174
|
-
for (const [key, local] of imports) {
|
|
175
|
-
const separator = key.indexOf("#");
|
|
176
|
-
const source = key.slice(0, separator);
|
|
177
|
-
const exported = key.slice(separator + 1);
|
|
178
|
-
const bucket = grouped.get(source);
|
|
179
|
-
if (bucket === void 0) {
|
|
180
|
-
grouped.set(source, [[exported, local]]);
|
|
181
|
-
} else {
|
|
182
|
-
bucket.push([exported, local]);
|
|
183
|
-
}
|
|
184
|
-
}
|
|
185
|
-
return grouped;
|
|
186
|
-
}
|
|
187
|
-
function runtime(state, name, source) {
|
|
188
|
-
return runtimeFrom(state, name, source ?? (state.firsthand.ssr ? SERVER_RUNTIME : RUNTIME));
|
|
189
|
-
}
|
|
190
|
-
function runtimeFrom(state, name, source) {
|
|
191
|
-
const key = `${source}#${name}`;
|
|
192
|
-
let local = state.firsthand.imports.get(key);
|
|
193
|
-
if (local === void 0) {
|
|
194
|
-
local = t.identifier(`_$${name}`);
|
|
195
|
-
state.firsthand.imports.set(key, local);
|
|
196
|
-
}
|
|
197
|
-
return t.cloneNode(local);
|
|
198
|
-
}
|
|
199
|
-
function annotateComponent(path, state, options) {
|
|
200
|
-
const callee = path.node.callee;
|
|
201
|
-
if (!t.isIdentifier(callee, { name: "component" }) || path.node.arguments.length > 2) {
|
|
202
|
-
return;
|
|
203
|
-
}
|
|
204
|
-
const binding = path.scope.getBinding("component");
|
|
205
|
-
if (binding === void 0 || !isFirsthandImport(binding)) {
|
|
206
|
-
return;
|
|
207
|
-
}
|
|
208
|
-
const setup = path.node.arguments[0];
|
|
209
|
-
if (!t.isArrowFunctionExpression(setup) && !t.isFunctionExpression(setup)) {
|
|
210
|
-
return;
|
|
211
|
-
}
|
|
212
|
-
const name = declaredName(path);
|
|
213
|
-
rewritePropsDestructuring(path, name, state);
|
|
214
|
-
if (options.strictReactivity !== false) {
|
|
215
|
-
const setupPath = path.get("arguments.0");
|
|
216
|
-
checkKeptReads(setupPath, name);
|
|
217
|
-
checkDecidedOnce(setupPath, name);
|
|
218
|
-
checkRunBody(setupPath, name);
|
|
219
|
-
}
|
|
220
|
-
path.node.arguments = [
|
|
221
|
-
setup,
|
|
222
|
-
path.node.arguments[1] ?? t.identifier("undefined"),
|
|
223
|
-
t.stringLiteral(`${state.firsthand.moduleId}/${name}`),
|
|
224
|
-
t.stringLiteral(name)
|
|
225
|
-
];
|
|
226
|
-
}
|
|
227
|
-
function checkKeptReads(setup, name) {
|
|
228
|
-
const parameter = setup.node.params[0];
|
|
229
|
-
const propsName = t.isIdentifier(parameter) ? parameter.name : null;
|
|
230
|
-
const body = setup.get("body");
|
|
231
|
-
if (!body.isBlockStatement()) {
|
|
232
|
-
return;
|
|
233
|
-
}
|
|
234
|
-
body.traverse({
|
|
235
|
-
Function(nested) {
|
|
236
|
-
nested.skip();
|
|
237
|
-
},
|
|
238
|
-
VariableDeclarator(declarator) {
|
|
239
|
-
const init = declarator.node.init;
|
|
240
|
-
if (init === null || init === void 0 || !readsOnly(init, propsName)) {
|
|
241
|
-
return;
|
|
242
|
-
}
|
|
243
|
-
const target = declarator.node.id;
|
|
244
|
-
const label = t.isIdentifier(target) ? `\`${target.name}\`` : "This value";
|
|
245
|
-
throw declarator.buildCodeFrameError(
|
|
246
|
-
`${name}: ${label} is read once, here, and then kept. A setup runs one time per instance, so this value will not change again.
|
|
247
|
-
|
|
248
|
-
Move the read into the part, handler, effect or computed that should re-read it \u2014 or wrap it in snapshot(() => \u2026) if reading once is what you meant.`
|
|
249
|
-
);
|
|
250
|
-
}
|
|
251
|
-
});
|
|
252
|
-
}
|
|
253
|
-
function checkDecidedOnce(setup, name) {
|
|
254
|
-
const report = (at) => {
|
|
255
|
-
throw at.buildCodeFrameError(
|
|
256
|
-
`${name}: this view is chosen once, here, from a value that changes. A setup runs one time per instance, so the other branch will never appear.
|
|
257
|
-
|
|
258
|
-
Either put the choice inside the markup, where it is a part:
|
|
259
|
-
|
|
260
|
-
return <>{open.value ? <A /> : <B />}</>;
|
|
261
|
-
|
|
262
|
-
or return a render function, which is a reactive scope of its own and may use ordinary control flow:
|
|
263
|
-
|
|
264
|
-
return () => (open.value ? <A /> : <B />);`
|
|
265
|
-
);
|
|
266
|
-
};
|
|
267
|
-
const check = (returned, at) => {
|
|
268
|
-
if (t.isConditionalExpression(returned)) {
|
|
269
|
-
if (!hasView(returned.consequent) && !hasView(returned.alternate)) {
|
|
270
|
-
return;
|
|
271
|
-
}
|
|
272
|
-
if (readsSignal(returned.test)) {
|
|
273
|
-
report(at);
|
|
274
|
-
}
|
|
275
|
-
return;
|
|
276
|
-
}
|
|
277
|
-
if (t.isLogicalExpression(returned) && returned.operator !== "??") {
|
|
278
|
-
if (!hasView(returned.right) && !hasView(returned.left)) {
|
|
279
|
-
return;
|
|
280
|
-
}
|
|
281
|
-
if (readsSignal(returned.left)) {
|
|
282
|
-
report(at);
|
|
283
|
-
}
|
|
284
|
-
}
|
|
285
|
-
};
|
|
286
|
-
const body = setup.get("body");
|
|
287
|
-
if (!body.isBlockStatement()) {
|
|
288
|
-
check(setup.node.body, body);
|
|
289
|
-
return;
|
|
290
|
-
}
|
|
291
|
-
body.traverse({
|
|
292
|
-
Function(nested) {
|
|
293
|
-
nested.skip();
|
|
294
|
-
},
|
|
295
|
-
ReturnStatement(statement) {
|
|
296
|
-
const returned = statement.node.argument;
|
|
297
|
-
if (returned !== null && returned !== void 0) {
|
|
298
|
-
check(returned, statement);
|
|
299
|
-
}
|
|
300
|
-
},
|
|
301
|
-
/**
|
|
302
|
-
* The same mistake spelled with a keyword, and the one that actually
|
|
303
|
-
* shipped: a route guard that returned `<Navigate />` early left the page
|
|
304
|
-
* it was meant to hide on the screen after a sign-out.
|
|
305
|
-
*/
|
|
306
|
-
IfStatement(statement) {
|
|
307
|
-
if (!readsSignal(statement.node.test)) {
|
|
308
|
-
return;
|
|
309
|
-
}
|
|
310
|
-
if (returnsView(statement.node.consequent) || returnsView(statement.node.alternate)) {
|
|
311
|
-
report(statement.get("test"));
|
|
312
|
-
}
|
|
313
|
-
}
|
|
314
|
-
});
|
|
315
|
-
}
|
|
316
|
-
function checkRunBody(setup, name) {
|
|
317
|
-
const runs = [];
|
|
318
|
-
const body = setup.get("body");
|
|
319
|
-
body.traverse({
|
|
320
|
-
Function(nested) {
|
|
321
|
-
nested.skip();
|
|
322
|
-
},
|
|
323
|
-
ReturnStatement(statement) {
|
|
324
|
-
const argument = statement.get("argument");
|
|
325
|
-
if (argument.isArrowFunctionExpression() || argument.isFunctionExpression()) {
|
|
326
|
-
runs.push(argument);
|
|
327
|
-
}
|
|
328
|
-
}
|
|
329
|
-
});
|
|
330
|
-
for (const run of runs) {
|
|
331
|
-
checkNothingPersistent(run, name);
|
|
332
|
-
checkRepeatedMarkup(run, name);
|
|
333
|
-
}
|
|
334
|
-
}
|
|
335
|
-
var PERSISTENT = /* @__PURE__ */ new Map([
|
|
336
|
-
["signal", "a signal"],
|
|
337
|
-
["computed", "a computed"],
|
|
338
|
-
["effect", "an effect"],
|
|
339
|
-
["deepSignal", "a deep signal"],
|
|
340
|
-
["useResource", "a resource"],
|
|
341
|
-
["useAction", "an action"],
|
|
342
|
-
["onCleanup", "a cleanup"],
|
|
343
|
-
["provide", "a context value"]
|
|
344
|
-
]);
|
|
345
|
-
function checkNothingPersistent(run, name) {
|
|
346
|
-
run.traverse({
|
|
347
|
-
Function(nested) {
|
|
348
|
-
nested.skip();
|
|
349
|
-
},
|
|
350
|
-
CallExpression(call) {
|
|
351
|
-
const callee = call.node.callee;
|
|
352
|
-
if (!t.isIdentifier(callee)) {
|
|
353
|
-
return;
|
|
354
|
-
}
|
|
355
|
-
const what = PERSISTENT.get(callee.name);
|
|
356
|
-
if (what === void 0) {
|
|
357
|
-
return;
|
|
358
|
-
}
|
|
359
|
-
const binding = call.scope.getBinding(callee.name);
|
|
360
|
-
if (binding === void 0 || !isFirsthandImport(binding)) {
|
|
361
|
-
return;
|
|
362
|
-
}
|
|
363
|
-
throw call.buildCodeFrameError(
|
|
364
|
-
`${name}: this render function makes ${what}, and it runs again whenever something it read changes \u2014 so this would be made again, and the one before it thrown away.
|
|
365
|
-
|
|
366
|
-
Move it into the setup, above the render function. Persistent things are made once, where the setup runs once.`
|
|
367
|
-
);
|
|
368
|
-
}
|
|
369
|
-
});
|
|
370
|
-
}
|
|
371
|
-
function checkRepeatedMarkup(run, name) {
|
|
372
|
-
const report = (at) => {
|
|
373
|
-
throw at.buildCodeFrameError(
|
|
374
|
-
`${name}: this markup is written once and appears many times, so where it stands cannot say which of them is which.
|
|
375
|
-
|
|
376
|
-
Give it a key:
|
|
377
|
-
|
|
378
|
-
{rows.map((row) => <Row key={row.id} row={row} />)}`
|
|
379
|
-
);
|
|
380
|
-
};
|
|
381
|
-
run.traverse({
|
|
382
|
-
Function(nested) {
|
|
383
|
-
nested.skip();
|
|
384
|
-
},
|
|
385
|
-
"ForStatement|ForOfStatement|ForInStatement|WhileStatement|DoWhileStatement"(loop) {
|
|
386
|
-
loop.traverse({
|
|
387
|
-
JSXElement(element) {
|
|
388
|
-
element.skip();
|
|
389
|
-
if (!hasKey(element.node)) {
|
|
390
|
-
report(element);
|
|
391
|
-
}
|
|
392
|
-
}
|
|
393
|
-
});
|
|
394
|
-
},
|
|
395
|
-
CallExpression(call) {
|
|
396
|
-
const callee = call.node.callee;
|
|
397
|
-
if (LIST_CALL in call.node || !t.isMemberExpression(callee) || callee.computed || !t.isIdentifier(callee.property, { name: "map" })) {
|
|
398
|
-
return;
|
|
399
|
-
}
|
|
400
|
-
call.traverse({
|
|
401
|
-
JSXElement(element) {
|
|
402
|
-
element.skip();
|
|
403
|
-
if (!hasKey(element.node)) {
|
|
404
|
-
report(element);
|
|
405
|
-
}
|
|
406
|
-
}
|
|
407
|
-
});
|
|
408
|
-
}
|
|
409
|
-
});
|
|
410
|
-
}
|
|
411
|
-
function hasKey(element) {
|
|
412
|
-
return element.openingElement.attributes.some(
|
|
413
|
-
(attribute) => t.isJSXAttribute(attribute) && attributeName(attribute) === "key"
|
|
414
|
-
);
|
|
415
|
-
}
|
|
416
|
-
function returnsView(node) {
|
|
417
|
-
if (node === null || node === void 0) {
|
|
418
|
-
return false;
|
|
419
|
-
}
|
|
420
|
-
if (t.isReturnStatement(node)) {
|
|
421
|
-
return node.argument !== null && node.argument !== void 0 && hasView(node.argument);
|
|
422
|
-
}
|
|
423
|
-
if (t.isBlockStatement(node)) {
|
|
424
|
-
return node.body.some((inner) => returnsView(inner));
|
|
425
|
-
}
|
|
426
|
-
return false;
|
|
427
|
-
}
|
|
428
|
-
function hasView(node) {
|
|
429
|
-
if (t.isConditionalExpression(node)) {
|
|
430
|
-
return hasView(node.consequent) || hasView(node.alternate);
|
|
431
|
-
}
|
|
432
|
-
return t.isJSXElement(node) || t.isJSXFragment(node);
|
|
433
|
-
}
|
|
434
|
-
function readsSignal(node) {
|
|
435
|
-
let found = false;
|
|
436
|
-
const walk = (current) => {
|
|
437
|
-
if (current === null || current === void 0 || found) {
|
|
438
|
-
return;
|
|
439
|
-
}
|
|
440
|
-
if (t.isMemberExpression(current)) {
|
|
441
|
-
if (!current.computed && t.isIdentifier(current.property, { name: "value" })) {
|
|
442
|
-
found = true;
|
|
443
|
-
return;
|
|
444
|
-
}
|
|
445
|
-
walk(current.object);
|
|
446
|
-
return;
|
|
447
|
-
}
|
|
448
|
-
if (t.isUnaryExpression(current)) {
|
|
449
|
-
walk(current.argument);
|
|
450
|
-
return;
|
|
451
|
-
}
|
|
452
|
-
if (t.isBinaryExpression(current) || t.isLogicalExpression(current)) {
|
|
453
|
-
walk(current.left);
|
|
454
|
-
walk(current.right);
|
|
455
|
-
return;
|
|
456
|
-
}
|
|
457
|
-
if (t.isConditionalExpression(current)) {
|
|
458
|
-
walk(current.test);
|
|
459
|
-
}
|
|
460
|
-
};
|
|
461
|
-
walk(node);
|
|
462
|
-
return found;
|
|
463
|
-
}
|
|
464
|
-
function readsOnly(node, propsName) {
|
|
465
|
-
let read = false;
|
|
466
|
-
const walk = (current) => {
|
|
467
|
-
if (t.isIdentifier(current) || t.isLiteral(current)) {
|
|
468
|
-
if (t.isTemplateLiteral(current)) {
|
|
469
|
-
return current.expressions.every((part) => walk(part));
|
|
470
|
-
}
|
|
471
|
-
return true;
|
|
472
|
-
}
|
|
473
|
-
if (t.isMemberExpression(current)) {
|
|
474
|
-
const property = current.property;
|
|
475
|
-
if (!current.computed && t.isIdentifier(property, { name: "value" })) {
|
|
476
|
-
read = true;
|
|
477
|
-
}
|
|
478
|
-
if (propsName !== null && t.isIdentifier(current.object, { name: propsName })) {
|
|
479
|
-
read = true;
|
|
480
|
-
}
|
|
481
|
-
return walk(current.object) && (!current.computed || walk(property));
|
|
482
|
-
}
|
|
483
|
-
if (t.isUnaryExpression(current)) {
|
|
484
|
-
return walk(current.argument);
|
|
485
|
-
}
|
|
486
|
-
if (t.isBinaryExpression(current) || t.isLogicalExpression(current)) {
|
|
487
|
-
return walk(current.left) && walk(current.right);
|
|
488
|
-
}
|
|
489
|
-
if (t.isConditionalExpression(current)) {
|
|
490
|
-
return walk(current.test) && walk(current.consequent) && walk(current.alternate);
|
|
491
|
-
}
|
|
492
|
-
return false;
|
|
493
|
-
};
|
|
494
|
-
return walk(node) && read;
|
|
495
|
-
}
|
|
496
|
-
var NAMED = /* @__PURE__ */ new Map([
|
|
497
|
-
["signal", "signal"],
|
|
498
|
-
["computed", "computed"],
|
|
499
|
-
["deepSignal", "signal"]
|
|
500
|
-
]);
|
|
501
|
-
function nameCell(path, state) {
|
|
502
|
-
const init = path.node.init;
|
|
503
|
-
const target = path.node.id;
|
|
504
|
-
if (!t.isCallExpression(init) || !t.isIdentifier(target) || !t.isIdentifier(init.callee)) {
|
|
505
|
-
return;
|
|
506
|
-
}
|
|
507
|
-
const kind = NAMED.get(init.callee.name);
|
|
508
|
-
if (kind === void 0) {
|
|
509
|
-
return;
|
|
510
|
-
}
|
|
511
|
-
const binding = path.scope.getBinding(init.callee.name);
|
|
512
|
-
if (binding === void 0 || !isFirsthandImport(binding)) {
|
|
513
|
-
return;
|
|
514
|
-
}
|
|
515
|
-
const line = init.loc.start.line;
|
|
516
|
-
const source = state.filename;
|
|
517
|
-
const cut = Math.max(source.lastIndexOf("/"), source.lastIndexOf(String.fromCharCode(92)));
|
|
518
|
-
const where = `${source.slice(cut + 1)}:${String(line)}`;
|
|
519
|
-
const call = t.callExpression(runtime(state, "label"), [
|
|
520
|
-
init,
|
|
521
|
-
t.stringLiteral(kind),
|
|
522
|
-
t.stringLiteral(`${target.name} (${where})`)
|
|
523
|
-
]);
|
|
524
|
-
path.node.init = call;
|
|
525
|
-
}
|
|
526
|
-
function isFirsthandImport(binding) {
|
|
527
|
-
const parent = binding.path.parentPath;
|
|
528
|
-
if (!parent.isImportDeclaration()) {
|
|
529
|
-
return false;
|
|
530
|
-
}
|
|
531
|
-
const source = parent.node.source.value;
|
|
532
|
-
return source === CORE || source.startsWith("@firsthandjs/") || source === "firsthand";
|
|
533
|
-
}
|
|
534
|
-
function declaredName(path) {
|
|
535
|
-
const parent = path.parentPath;
|
|
536
|
-
if (parent.isVariableDeclarator() && t.isIdentifier(parent.node.id)) {
|
|
537
|
-
return parent.node.id.name;
|
|
538
|
-
}
|
|
539
|
-
return "Component";
|
|
540
|
-
}
|
|
541
|
-
function rewritePropsDestructuring(call, name, state) {
|
|
542
|
-
const setup = call.get("arguments.0");
|
|
543
|
-
const params = setup.get("params");
|
|
544
|
-
const param = params[0];
|
|
545
|
-
if (param === void 0 || param.isIdentifier()) {
|
|
546
|
-
return;
|
|
547
|
-
}
|
|
548
|
-
if (!param.isObjectPattern()) {
|
|
549
|
-
throw call.buildCodeFrameError(
|
|
550
|
-
`${name}: a component's props parameter must be an object pattern or a plain identifier. Props are an object, so an array pattern cannot destructure them.`
|
|
551
|
-
);
|
|
552
|
-
}
|
|
553
|
-
const propsId = setup.scope.generateUidIdentifier("props");
|
|
554
|
-
const reads = [];
|
|
555
|
-
const restNames = [];
|
|
556
|
-
collectPattern(param.node, t.cloneNode(propsId), reads, restNames, call, name);
|
|
557
|
-
setup.scope.crawl();
|
|
558
|
-
const references = [];
|
|
559
|
-
for (const read of [...reads, ...restNames.map((r) => ({ local: r.local, access: propsId }))]) {
|
|
560
|
-
const binding = setup.scope.getBinding(read.local);
|
|
561
|
-
if (binding.constantViolations.length > 0) {
|
|
562
|
-
throw call.buildCodeFrameError(
|
|
563
|
-
`${name}: \`${read.local}\` is destructured from props and then assigned to. Props are readonly; assign to a signal instead.`
|
|
564
|
-
);
|
|
565
|
-
}
|
|
566
|
-
references.push({ paths: binding.referencePaths, access: read.access });
|
|
567
|
-
}
|
|
568
|
-
param.replaceWith(propsId);
|
|
569
|
-
for (const entry of references) {
|
|
570
|
-
for (const reference of entry.paths) {
|
|
571
|
-
if (entry.access !== propsId) {
|
|
572
|
-
reference.replaceWith(located(t.cloneNode(entry.access), reference.node));
|
|
573
|
-
}
|
|
574
|
-
}
|
|
575
|
-
}
|
|
576
|
-
if (restNames.length > 0) {
|
|
577
|
-
if (!setup.get("body").isBlockStatement()) {
|
|
578
|
-
const body = setup.node.body;
|
|
579
|
-
setup.node.body = t.blockStatement([t.returnStatement(body)]);
|
|
580
|
-
}
|
|
581
|
-
const block = setup.get("body");
|
|
582
|
-
for (const rest of restNames) {
|
|
583
|
-
block.node.body.unshift(
|
|
584
|
-
t.variableDeclaration("const", [
|
|
585
|
-
t.variableDeclarator(
|
|
586
|
-
t.identifier(rest.local),
|
|
587
|
-
t.callExpression(runtime(state, "rest"), [
|
|
588
|
-
t.cloneNode(propsId),
|
|
589
|
-
t.arrayExpression(rest.omit.map((key) => t.stringLiteral(key)))
|
|
590
|
-
])
|
|
591
|
-
)
|
|
592
|
-
])
|
|
593
|
-
);
|
|
594
|
-
}
|
|
595
|
-
}
|
|
596
|
-
}
|
|
597
|
-
function collectPattern(pattern, base, reads, rests, call, name) {
|
|
598
|
-
const seen = [];
|
|
599
|
-
for (const property of pattern.properties) {
|
|
600
|
-
if (t.isRestElement(property)) {
|
|
601
|
-
rests.push({ local: property.argument.name, omit: [...seen] });
|
|
602
|
-
continue;
|
|
603
|
-
}
|
|
604
|
-
if (property.computed || !t.isIdentifier(property.key)) {
|
|
605
|
-
throw call.buildCodeFrameError(
|
|
606
|
-
`${name}: props can only be destructured by plain key. A computed key would have to be resolved at setup time, which is exactly the snapshot this rewrite avoids.`
|
|
607
|
-
);
|
|
608
|
-
}
|
|
609
|
-
seen.push(property.key.name);
|
|
610
|
-
const access = t.memberExpression(
|
|
611
|
-
t.cloneNode(base),
|
|
612
|
-
t.identifier(property.key.name)
|
|
613
|
-
);
|
|
614
|
-
const value = property.value;
|
|
615
|
-
if (t.isIdentifier(value)) {
|
|
616
|
-
reads.push({ local: value.name, access });
|
|
617
|
-
} else if (t.isAssignmentPattern(value) && t.isIdentifier(value.left)) {
|
|
618
|
-
reads.push({
|
|
619
|
-
local: value.left.name,
|
|
620
|
-
access: t.logicalExpression("??", access, value.right)
|
|
621
|
-
});
|
|
622
|
-
} else if (t.isObjectPattern(value)) {
|
|
623
|
-
collectPattern(value, access, reads, rests, call, name);
|
|
624
|
-
} else {
|
|
625
|
-
throw call.buildCodeFrameError(
|
|
626
|
-
`${name}: this destructuring pattern cannot be rewritten into live reads. Take the props object and read from it where you need the value.`
|
|
627
|
-
);
|
|
628
|
-
}
|
|
629
|
-
}
|
|
630
|
-
}
|
|
631
|
-
function compileNode(path, state) {
|
|
632
|
-
if (path.isJSXFragment()) {
|
|
633
|
-
return t.arrayExpression(compileChildren(path.node.children, state));
|
|
634
|
-
}
|
|
635
|
-
const node = path.node;
|
|
636
|
-
if (isComponentTag(node)) {
|
|
637
|
-
return compileComponent(path, state);
|
|
638
|
-
}
|
|
639
|
-
return state.firsthand.ssr ? compileMarkup(path, state) : compileTemplate(path, state);
|
|
640
|
-
}
|
|
641
|
-
function collectViews(program, state) {
|
|
642
|
-
const { views, viewNodes } = state.firsthand;
|
|
643
|
-
const record = (path) => {
|
|
644
|
-
let fn = path.getFunctionParent();
|
|
645
|
-
while (fn !== null) {
|
|
646
|
-
viewNodes.add(fn.node);
|
|
647
|
-
const named = moduleLevelName(fn);
|
|
648
|
-
if (named !== null) {
|
|
649
|
-
views.set(named, t.identifier(named));
|
|
650
|
-
}
|
|
651
|
-
fn = fn.getFunctionParent();
|
|
652
|
-
}
|
|
653
|
-
};
|
|
654
|
-
program.traverse({
|
|
655
|
-
JSXElement: record,
|
|
656
|
-
JSXFragment: record
|
|
657
|
-
});
|
|
658
|
-
}
|
|
659
|
-
function moduleLevelName(fn) {
|
|
660
|
-
if (fn.isFunctionDeclaration()) {
|
|
661
|
-
const id = fn.node.id;
|
|
662
|
-
if (id === null || id === void 0) {
|
|
663
|
-
return null;
|
|
664
|
-
}
|
|
665
|
-
return t.isProgram(fn.parentPath.scope.block) ? id.name : null;
|
|
666
|
-
}
|
|
667
|
-
const declarator = fn.parentPath;
|
|
668
|
-
if (!declarator.isVariableDeclarator() || !t.isIdentifier(declarator.node.id)) {
|
|
669
|
-
return null;
|
|
670
|
-
}
|
|
671
|
-
return t.isProgram(declarator.scope.block) ? declarator.node.id.name : null;
|
|
672
|
-
}
|
|
673
|
-
function isLocalView(path, state) {
|
|
674
|
-
const name = path.node.openingElement.name;
|
|
675
|
-
if (!t.isJSXIdentifier(name)) {
|
|
676
|
-
return false;
|
|
677
|
-
}
|
|
678
|
-
const binding = path.scope.getBinding(name.name);
|
|
679
|
-
if (binding === void 0 || binding.kind === "module" || binding.constantViolations.length > 0) {
|
|
680
|
-
return false;
|
|
681
|
-
}
|
|
682
|
-
if (binding.path.isFunctionDeclaration()) {
|
|
683
|
-
return state.firsthand.viewNodes.has(binding.path.node);
|
|
684
|
-
}
|
|
685
|
-
if (!binding.path.isVariableDeclarator()) {
|
|
686
|
-
return false;
|
|
687
|
-
}
|
|
688
|
-
const init = binding.path.node.init;
|
|
689
|
-
if (!t.isArrowFunctionExpression(init) && !t.isFunctionExpression(init)) {
|
|
690
|
-
return false;
|
|
691
|
-
}
|
|
692
|
-
return state.firsthand.viewNodes.has(init);
|
|
693
|
-
}
|
|
694
|
-
function collectRuns(program, state) {
|
|
695
|
-
program.traverse({
|
|
696
|
-
CallExpression(call) {
|
|
697
|
-
if (!isComponentCall(call)) {
|
|
698
|
-
return;
|
|
699
|
-
}
|
|
700
|
-
const setup = call.get("arguments.0");
|
|
701
|
-
if (!setup.isArrowFunctionExpression() && !setup.isFunctionExpression()) {
|
|
702
|
-
return;
|
|
703
|
-
}
|
|
704
|
-
const found = [];
|
|
705
|
-
const body = setup.get("body");
|
|
706
|
-
if (!body.isBlockStatement()) {
|
|
707
|
-
if (body.isArrowFunctionExpression() || body.isFunctionExpression()) {
|
|
708
|
-
found.push(body);
|
|
709
|
-
}
|
|
710
|
-
} else {
|
|
711
|
-
body.traverse({
|
|
712
|
-
// A handler or a callback returns its own things; only what the
|
|
713
|
-
// setup itself hands back is the view.
|
|
714
|
-
Function(nested) {
|
|
715
|
-
nested.skip();
|
|
716
|
-
},
|
|
717
|
-
ReturnStatement(statement) {
|
|
718
|
-
const argument = statement.get("argument");
|
|
719
|
-
if (argument.isArrowFunctionExpression() || argument.isFunctionExpression()) {
|
|
720
|
-
found.push(argument);
|
|
721
|
-
}
|
|
722
|
-
}
|
|
723
|
-
});
|
|
724
|
-
}
|
|
725
|
-
if (found.length === 0) {
|
|
726
|
-
return;
|
|
727
|
-
}
|
|
728
|
-
setup.ensureBlock();
|
|
729
|
-
const block = setup.get("body");
|
|
730
|
-
for (const run of found) {
|
|
731
|
-
const store = setup.scope.generateUidIdentifier("store");
|
|
732
|
-
block.unshiftContainer(
|
|
733
|
-
"body",
|
|
734
|
-
t.variableDeclaration("const", [
|
|
735
|
-
t.variableDeclarator(
|
|
736
|
-
store,
|
|
737
|
-
t.callExpression(runtime(state, "store"), [t.stringLiteral(declaredName(call))])
|
|
738
|
-
)
|
|
739
|
-
])
|
|
740
|
-
);
|
|
741
|
-
let index = 0;
|
|
742
|
-
state.firsthand.runs.set(run.node, {
|
|
743
|
-
node: run.node,
|
|
744
|
-
store,
|
|
745
|
-
next: () => index++
|
|
746
|
-
});
|
|
747
|
-
closeRun(run, store, state);
|
|
748
|
-
}
|
|
749
|
-
}
|
|
750
|
-
});
|
|
751
|
-
}
|
|
752
|
-
function closeRun(run, store, state) {
|
|
753
|
-
const body = run.get("body");
|
|
754
|
-
if (!body.isBlockStatement()) {
|
|
755
|
-
body.replaceWith(
|
|
756
|
-
t.callExpression(runtime(state, "ran"), [t.cloneNode(store), body.node])
|
|
757
|
-
);
|
|
758
|
-
return;
|
|
759
|
-
}
|
|
760
|
-
const returns = [];
|
|
761
|
-
body.traverse({
|
|
762
|
-
Function(nested) {
|
|
763
|
-
nested.skip();
|
|
764
|
-
},
|
|
765
|
-
ReturnStatement(statement) {
|
|
766
|
-
returns.push(statement);
|
|
767
|
-
}
|
|
768
|
-
});
|
|
769
|
-
for (const statement of returns) {
|
|
770
|
-
statement.node.argument = t.callExpression(runtime(state, "ran"), [
|
|
771
|
-
t.cloneNode(store),
|
|
772
|
-
statement.node.argument ?? t.identifier("undefined")
|
|
773
|
-
]);
|
|
774
|
-
}
|
|
775
|
-
}
|
|
776
|
-
function isComponentCall(path) {
|
|
777
|
-
if (!t.isIdentifier(path.node.callee, { name: "component" })) {
|
|
778
|
-
return false;
|
|
779
|
-
}
|
|
780
|
-
const binding = path.scope.getBinding("component");
|
|
781
|
-
return binding !== void 0 && isFirsthandImport(binding);
|
|
782
|
-
}
|
|
783
|
-
function enclosingRun(path, state) {
|
|
784
|
-
let fn = path.getFunctionParent();
|
|
785
|
-
while (fn !== null && GENERATED in fn.node) {
|
|
786
|
-
fn = fn.getFunctionParent();
|
|
787
|
-
}
|
|
788
|
-
if (fn === null) {
|
|
789
|
-
return null;
|
|
790
|
-
}
|
|
791
|
-
return state.firsthand.runs.get(fn.node) ?? null;
|
|
792
|
-
}
|
|
793
|
-
function dependsOnRun(node, run, at) {
|
|
794
|
-
if (run === null) {
|
|
795
|
-
return false;
|
|
796
|
-
}
|
|
797
|
-
const names = /* @__PURE__ */ new Set();
|
|
798
|
-
collectNames(node, names);
|
|
799
|
-
for (const name of names) {
|
|
800
|
-
const binding = at.scope.getBinding(name);
|
|
801
|
-
if (binding === void 0) {
|
|
802
|
-
continue;
|
|
803
|
-
}
|
|
804
|
-
if (binding.scope.block === run.node || binding.path.findParent((parent) => parent.node === run.node) !== null) {
|
|
805
|
-
return true;
|
|
806
|
-
}
|
|
807
|
-
}
|
|
808
|
-
return false;
|
|
809
|
-
}
|
|
810
|
-
function collectNames(node, into) {
|
|
811
|
-
if (t.isIdentifier(node)) {
|
|
812
|
-
into.add(node.name);
|
|
813
|
-
return;
|
|
814
|
-
}
|
|
815
|
-
for (const key of t.VISITOR_KEYS[node.type]) {
|
|
816
|
-
if (t.isMemberExpression(node) && !node.computed && key === "property") {
|
|
817
|
-
continue;
|
|
818
|
-
}
|
|
819
|
-
if ((t.isObjectProperty(node) || t.isObjectMethod(node)) && !node.computed && key === "key") {
|
|
820
|
-
continue;
|
|
821
|
-
}
|
|
822
|
-
const value = node[key];
|
|
823
|
-
for (const child of Array.isArray(value) ? value : [value]) {
|
|
824
|
-
if (typeof child === "object" && child !== null) {
|
|
825
|
-
collectNames(child, into);
|
|
826
|
-
}
|
|
827
|
-
}
|
|
828
|
-
}
|
|
829
|
-
}
|
|
830
|
-
function canRetain(node, build) {
|
|
831
|
-
let possible = true;
|
|
832
|
-
const visit = (element) => {
|
|
833
|
-
for (const attribute of element.openingElement.attributes) {
|
|
834
|
-
if (t.isJSXSpreadAttribute(attribute)) {
|
|
835
|
-
if (dependsOnRun(attribute.argument, build.run, build.at)) {
|
|
836
|
-
possible = false;
|
|
837
|
-
}
|
|
838
|
-
continue;
|
|
839
|
-
}
|
|
840
|
-
const value = attribute.value;
|
|
841
|
-
if (attributeName(attribute) === "ref" && t.isJSXExpressionContainer(value) && !t.isJSXEmptyExpression(value.expression) && dependsOnRun(value.expression, build.run, build.at)) {
|
|
842
|
-
possible = false;
|
|
843
|
-
}
|
|
844
|
-
}
|
|
845
|
-
for (const child of element.children) {
|
|
846
|
-
if (t.isJSXElement(child)) {
|
|
847
|
-
if (!isComponentTag(child)) {
|
|
848
|
-
visit(child);
|
|
849
|
-
}
|
|
850
|
-
continue;
|
|
851
|
-
}
|
|
852
|
-
if (t.isJSXExpressionContainer(child) && !t.isJSXEmptyExpression(child.expression) && isKeyedList(child.expression) && dependsOnRun(child.expression, build.run, build.at)) {
|
|
853
|
-
possible = false;
|
|
854
|
-
}
|
|
855
|
-
}
|
|
856
|
-
};
|
|
857
|
-
visit(node);
|
|
858
|
-
return possible;
|
|
859
|
-
}
|
|
860
|
-
function isKeyedList(node) {
|
|
861
|
-
return t.isCallExpression(node) && LIST_CALL in node;
|
|
862
|
-
}
|
|
863
|
-
function isComponentTag(node) {
|
|
864
|
-
const name = node.openingElement.name;
|
|
865
|
-
if (t.isJSXMemberExpression(name)) {
|
|
866
|
-
return true;
|
|
867
|
-
}
|
|
868
|
-
if (!t.isJSXIdentifier(name)) {
|
|
869
|
-
return false;
|
|
870
|
-
}
|
|
871
|
-
return /^[A-Z]/.test(name.name);
|
|
872
|
-
}
|
|
873
|
-
function tagExpression(name) {
|
|
874
|
-
if (t.isJSXIdentifier(name)) {
|
|
875
|
-
return t.identifier(name.name);
|
|
876
|
-
}
|
|
877
|
-
return t.memberExpression(tagExpression(name.object), t.identifier(name.property.name));
|
|
878
|
-
}
|
|
879
|
-
function compileComponent(path, state) {
|
|
880
|
-
const node = path.node;
|
|
881
|
-
const run = enclosingRun(path, state);
|
|
882
|
-
const properties = [];
|
|
883
|
-
const cells = [];
|
|
884
|
-
const throughCell = (value) => {
|
|
885
|
-
const holder = t.identifier(`_cell$${String(run.next())}`);
|
|
886
|
-
cells.push(
|
|
887
|
-
t.variableDeclaration("const", [
|
|
888
|
-
t.variableDeclarator(
|
|
889
|
-
holder,
|
|
890
|
-
t.callExpression(runtime(state, "cell"), [
|
|
891
|
-
t.cloneNode(run.store),
|
|
892
|
-
t.numericLiteral(run.next()),
|
|
893
|
-
value
|
|
894
|
-
])
|
|
895
|
-
)
|
|
896
|
-
])
|
|
897
|
-
);
|
|
898
|
-
return t.memberExpression(t.cloneNode(holder), t.identifier("value"));
|
|
899
|
-
};
|
|
900
|
-
for (const attribute of node.openingElement.attributes) {
|
|
901
|
-
if (t.isJSXSpreadAttribute(attribute)) {
|
|
902
|
-
properties.push(t.spreadElement(attribute.argument));
|
|
903
|
-
continue;
|
|
904
|
-
}
|
|
905
|
-
const name = attributeName(attribute);
|
|
906
|
-
const value = attributeValue(attribute);
|
|
907
|
-
if (state.firsthand.ssr && name === "key") {
|
|
908
|
-
continue;
|
|
909
|
-
}
|
|
910
|
-
if (value === null || isStaticValue(value)) {
|
|
911
|
-
properties.push(t.objectProperty(propertyKey(name), value ?? t.booleanLiteral(true)));
|
|
912
|
-
} else {
|
|
913
|
-
const held = dependsOnRun(value, run, path) ? throughCell(value) : value;
|
|
914
|
-
if (state.firsthand.ssr && isPure(value)) {
|
|
915
|
-
properties.push(t.objectProperty(propertyKey(name), held));
|
|
916
|
-
} else {
|
|
917
|
-
const read = t.returnStatement(held);
|
|
918
|
-
takePosition(read, value);
|
|
919
|
-
properties.push(t.objectMethod("get", propertyKey(name), [], t.blockStatement([read])));
|
|
920
|
-
}
|
|
921
|
-
}
|
|
922
|
-
}
|
|
923
|
-
const throughRunCell = (value) => t.callExpression(throughCell(t.arrowFunctionExpression([], value)), []);
|
|
924
|
-
const children = compileChildren(node.children, state, {
|
|
925
|
-
depends: (value) => dependsOnRun(value, run, path),
|
|
926
|
-
cell: throughRunCell,
|
|
927
|
-
value: throughCell
|
|
928
|
-
});
|
|
929
|
-
if (children.length === 1) {
|
|
930
|
-
properties.push(
|
|
931
|
-
t.objectMethod(
|
|
932
|
-
"get",
|
|
933
|
-
t.identifier("children"),
|
|
934
|
-
[],
|
|
935
|
-
t.blockStatement([t.returnStatement(children[0])])
|
|
936
|
-
)
|
|
937
|
-
);
|
|
938
|
-
} else if (children.length > 1) {
|
|
939
|
-
properties.push(
|
|
940
|
-
t.objectMethod(
|
|
941
|
-
"get",
|
|
942
|
-
t.identifier("children"),
|
|
943
|
-
[],
|
|
944
|
-
t.blockStatement([t.returnStatement(t.arrayExpression(children))])
|
|
945
|
-
)
|
|
946
|
-
);
|
|
947
|
-
}
|
|
948
|
-
const tag = tagExpression(node.openingElement.name);
|
|
949
|
-
const make = isLocalView(path, state) ? t.callExpression(tag, [t.objectExpression(properties)]) : t.callExpression(runtime(state, "createComponent"), [tag, t.objectExpression(properties)]);
|
|
950
|
-
if (run !== null) {
|
|
951
|
-
return keptChild(state, run, make, cells);
|
|
952
|
-
}
|
|
953
|
-
if (isLocalView(path, state)) {
|
|
954
|
-
if (state.firsthand.ssr) {
|
|
955
|
-
return make;
|
|
956
|
-
}
|
|
957
|
-
const parent = path.parentPath;
|
|
958
|
-
if (parent.isArrowFunctionExpression() && parent.node.body === node && CHILD_THUNK in parent.node) {
|
|
959
|
-
return make;
|
|
960
|
-
}
|
|
961
|
-
return t.callExpression(runtime(state, "part"), [t.arrowFunctionExpression([], make)]);
|
|
962
|
-
}
|
|
963
|
-
return make;
|
|
964
|
-
}
|
|
965
|
-
function keptChild(state, run, make, cells) {
|
|
966
|
-
const slot = t.identifier(`_kept$${String(run.next())}`);
|
|
967
|
-
const held = t.identifier(`_own$${String(run.next())}`);
|
|
968
|
-
const made = () => t.memberExpression(t.cloneNode(slot), t.identifier("last"));
|
|
969
|
-
const body = [
|
|
970
|
-
...cells,
|
|
971
|
-
t.variableDeclaration("const", [
|
|
972
|
-
t.variableDeclarator(
|
|
973
|
-
slot,
|
|
974
|
-
t.callExpression(runtime(state, "site"), [
|
|
975
|
-
t.cloneNode(run.store),
|
|
976
|
-
t.numericLiteral(run.next())
|
|
977
|
-
])
|
|
978
|
-
)
|
|
979
|
-
]),
|
|
980
|
-
t.ifStatement(
|
|
981
|
-
t.binaryExpression("===", made(), t.identifier("undefined")),
|
|
982
|
-
t.blockStatement([
|
|
983
|
-
t.variableDeclaration("const", [
|
|
984
|
-
t.variableDeclarator(
|
|
985
|
-
held,
|
|
986
|
-
t.callExpression(runtime(state, "open"), [t.cloneNode(run.store), t.cloneNode(slot)])
|
|
987
|
-
)
|
|
988
|
-
]),
|
|
989
|
-
expressionStatement2(
|
|
990
|
-
t.assignmentExpression(
|
|
991
|
-
"=",
|
|
992
|
-
made(),
|
|
993
|
-
t.callExpression(runtime(state, "part"), [t.arrowFunctionExpression([], make)])
|
|
994
|
-
)
|
|
995
|
-
),
|
|
996
|
-
expressionStatement2(t.callExpression(runtime(state, "close"), [t.cloneNode(held)]))
|
|
997
|
-
])
|
|
998
|
-
),
|
|
999
|
-
t.returnStatement(made())
|
|
1000
|
-
];
|
|
1001
|
-
return t.callExpression(generated(t.arrowFunctionExpression([], t.blockStatement(body))), []);
|
|
1002
|
-
}
|
|
1003
|
-
function isPure(node) {
|
|
1004
|
-
switch (node.type) {
|
|
1005
|
-
case "Identifier":
|
|
1006
|
-
case "ThisExpression":
|
|
1007
|
-
case "StringLiteral":
|
|
1008
|
-
case "NumericLiteral":
|
|
1009
|
-
case "BooleanLiteral":
|
|
1010
|
-
case "NullLiteral":
|
|
1011
|
-
case "BigIntLiteral":
|
|
1012
|
-
case "RegExpLiteral":
|
|
1013
|
-
return true;
|
|
1014
|
-
case "MemberExpression":
|
|
1015
|
-
case "OptionalMemberExpression":
|
|
1016
|
-
return isPure(node.object) && (!node.computed || isPure(node.property));
|
|
1017
|
-
case "UnaryExpression":
|
|
1018
|
-
return node.operator !== "delete" && isPure(node.argument);
|
|
1019
|
-
case "BinaryExpression":
|
|
1020
|
-
return isPure(node.left) && isPure(node.right);
|
|
1021
|
-
case "LogicalExpression":
|
|
1022
|
-
return isPure(node.left) && isPure(node.right);
|
|
1023
|
-
case "ConditionalExpression":
|
|
1024
|
-
return isPure(node.test) && isPure(node.consequent) && isPure(node.alternate);
|
|
1025
|
-
case "TemplateLiteral":
|
|
1026
|
-
return node.expressions.every((one) => t.isExpression(one) && isPure(one));
|
|
1027
|
-
case "ArrayExpression":
|
|
1028
|
-
return node.elements.every((one) => one === null || t.isExpression(one) && isPure(one));
|
|
1029
|
-
case "ObjectExpression":
|
|
1030
|
-
return node.properties.every(
|
|
1031
|
-
(one) => t.isObjectProperty(one) && !one.computed && t.isExpression(one.value) && isPure(one.value)
|
|
1032
|
-
);
|
|
1033
|
-
default:
|
|
1034
|
-
return false;
|
|
1035
|
-
}
|
|
1036
|
-
}
|
|
1037
|
-
function propertyKey(name) {
|
|
1038
|
-
return t.isValidIdentifier(name) ? t.identifier(name) : t.stringLiteral(name);
|
|
1039
|
-
}
|
|
1040
|
-
function attributeName(attribute) {
|
|
1041
|
-
const name = attribute.name;
|
|
1042
|
-
return t.isJSXNamespacedName(name) ? `${name.namespace.name}:${name.name.name}` : name.name;
|
|
1043
|
-
}
|
|
1044
|
-
function attributeValue(attribute) {
|
|
1045
|
-
const value = attribute.value;
|
|
1046
|
-
if (value === null || value === void 0) {
|
|
1047
|
-
return null;
|
|
1048
|
-
}
|
|
1049
|
-
if (t.isStringLiteral(value)) {
|
|
1050
|
-
return value;
|
|
1051
|
-
}
|
|
1052
|
-
if (t.isJSXExpressionContainer(value)) {
|
|
1053
|
-
return value.expression;
|
|
1054
|
-
}
|
|
1055
|
-
throw new Error("An element is not a valid attribute value. Wrap it in braces: attr={<El />}.");
|
|
1056
|
-
}
|
|
1057
|
-
function isStaticValue(value) {
|
|
1058
|
-
return t.isStringLiteral(value) || t.isNumericLiteral(value) || t.isBooleanLiteral(value) || t.isNullLiteral(value);
|
|
1059
|
-
}
|
|
1060
|
-
function pushText(markup, text) {
|
|
1061
|
-
markup.parts[markup.parts.length - 1] = markup.parts[markup.parts.length - 1] + text;
|
|
1062
|
-
}
|
|
1063
|
-
function pushHole(markup, value) {
|
|
1064
|
-
markup.values.push(value);
|
|
1065
|
-
markup.parts.push("");
|
|
1066
|
-
}
|
|
1067
|
-
function compileMarkup(path, state) {
|
|
1068
|
-
const markup = { parts: [""], values: [] };
|
|
1069
|
-
emitMarkupElement(path.node, markup, state);
|
|
1070
|
-
if (markup.values.length === 0) {
|
|
1071
|
-
return t.callExpression(runtime(state, "ssr"), [
|
|
1072
|
-
t.arrayExpression([t.stringLiteral(markup.parts[0])])
|
|
1073
|
-
]);
|
|
1074
|
-
}
|
|
1075
|
-
return t.callExpression(runtime(state, "ssr"), [
|
|
1076
|
-
t.arrayExpression(markup.parts.map((part) => t.stringLiteral(part))),
|
|
1077
|
-
...markup.values
|
|
1078
|
-
]);
|
|
1079
|
-
}
|
|
1080
|
-
function emitMarkupElement(node, markup, state) {
|
|
1081
|
-
const name = node.openingElement.name;
|
|
1082
|
-
if (!t.isJSXIdentifier(name)) {
|
|
1083
|
-
const namespaced = name;
|
|
1084
|
-
throw new Error(
|
|
1085
|
-
`Namespaced element names are not supported: <${namespaced.namespace.name}:${namespaced.name.name}>. Write the element without a namespace; SVG children are resolved by the parser.`
|
|
1086
|
-
);
|
|
1087
|
-
}
|
|
1088
|
-
const tag = name.name;
|
|
1089
|
-
pushText(markup, `<${tag}`);
|
|
1090
|
-
for (const attribute of node.openingElement.attributes) {
|
|
1091
|
-
emitMarkupAttribute(attribute, markup, state);
|
|
1092
|
-
}
|
|
1093
|
-
pushText(markup, ">");
|
|
1094
|
-
emitMarkupChildren(node.children, markup, state);
|
|
1095
|
-
if (!VOID_ELEMENTS.has(tag)) {
|
|
1096
|
-
pushText(markup, `</${tag}>`);
|
|
1097
|
-
}
|
|
1098
|
-
}
|
|
1099
|
-
function emitMarkupAttribute(attribute, markup, state) {
|
|
1100
|
-
if (t.isJSXSpreadAttribute(attribute)) {
|
|
1101
|
-
pushHole(markup, t.callExpression(runtime(state, "spread"), [attribute.argument]));
|
|
1102
|
-
return;
|
|
1103
|
-
}
|
|
1104
|
-
const name = attributeName(attribute);
|
|
1105
|
-
const value = attributeValue(attribute);
|
|
1106
|
-
if (name === "ref" || name.startsWith("on") && name.length > 2 && /[A-Z:]/.test(name[2])) {
|
|
1107
|
-
return;
|
|
1108
|
-
}
|
|
1109
|
-
if (name === "key") {
|
|
1110
|
-
return;
|
|
1111
|
-
}
|
|
1112
|
-
if (value === null) {
|
|
1113
|
-
pushText(markup, ` ${name}=""`);
|
|
1114
|
-
return;
|
|
1115
|
-
}
|
|
1116
|
-
if (isStaticValue(value)) {
|
|
1117
|
-
if (t.isBooleanLiteral(value) && !value.value) {
|
|
1118
|
-
return;
|
|
1119
|
-
}
|
|
1120
|
-
if (t.isNullLiteral(value)) {
|
|
1121
|
-
return;
|
|
1122
|
-
}
|
|
1123
|
-
const literal = t.isStringLiteral(value) ? value.value : t.isNumericLiteral(value) ? String(value.value) : "";
|
|
1124
|
-
pushText(markup, ` ${name}="${escapeAttribute(literal)}"`);
|
|
1125
|
-
return;
|
|
1126
|
-
}
|
|
1127
|
-
pushHole(markup, markupAttributeCall(name, value, state));
|
|
1128
|
-
}
|
|
1129
|
-
function markupAttributeCall(name, value, state) {
|
|
1130
|
-
if (name.startsWith("prop:")) {
|
|
1131
|
-
return t.callExpression(runtime(state, "setProperty"), [t.stringLiteral(name.slice(5)), value]);
|
|
1132
|
-
}
|
|
1133
|
-
if (name.startsWith("attr:")) {
|
|
1134
|
-
return t.callExpression(runtime(state, "setAttribute"), [
|
|
1135
|
-
t.stringLiteral(name.slice(5)),
|
|
1136
|
-
value
|
|
1137
|
-
]);
|
|
1138
|
-
}
|
|
1139
|
-
if (name === "class" || name === "className") {
|
|
1140
|
-
return t.callExpression(runtime(state, "setClass"), [value]);
|
|
1141
|
-
}
|
|
1142
|
-
if (name === "style") {
|
|
1143
|
-
return t.callExpression(runtime(state, "setStyle"), [value]);
|
|
1144
|
-
}
|
|
1145
|
-
if (BOOLEAN_PROPERTIES.has(name)) {
|
|
1146
|
-
return t.callExpression(runtime(state, "setBoolean"), [t.stringLiteral(name), value]);
|
|
1147
|
-
}
|
|
1148
|
-
if (DOM_PROPERTIES.has(name)) {
|
|
1149
|
-
return t.callExpression(runtime(state, "setProperty"), [t.stringLiteral(name), value]);
|
|
1150
|
-
}
|
|
1151
|
-
return t.callExpression(runtime(state, "setAttribute"), [t.stringLiteral(name), value]);
|
|
1152
|
-
}
|
|
1153
|
-
function emitMarkupChildren(children, markup, state) {
|
|
1154
|
-
const entries = planChildren(children);
|
|
1155
|
-
for (let i = 0; i < entries.length; i++) {
|
|
1156
|
-
const entry = entries[i];
|
|
1157
|
-
if (entry.kind === "text") {
|
|
1158
|
-
pushText(markup, escapeText(entry.text));
|
|
1159
|
-
continue;
|
|
1160
|
-
}
|
|
1161
|
-
if (entry.kind === "element") {
|
|
1162
|
-
emitMarkupElement(entry.element, markup, state);
|
|
1163
|
-
continue;
|
|
1164
|
-
}
|
|
1165
|
-
if (entries.length > 1) {
|
|
1166
|
-
pushText(markup, "<!--[-->");
|
|
1167
|
-
}
|
|
1168
|
-
pushHole(markup, t.callExpression(runtime(state, "child"), [entry.expression]));
|
|
1169
|
-
if (i !== entries.length - 1) {
|
|
1170
|
-
pushText(markup, "<!---->");
|
|
1171
|
-
}
|
|
1172
|
-
}
|
|
1173
|
-
}
|
|
1174
|
-
function compileTemplate(path, state) {
|
|
1175
|
-
let names = 0;
|
|
1176
|
-
const statements = [];
|
|
1177
|
-
const build = {
|
|
1178
|
-
html: [],
|
|
1179
|
-
statements,
|
|
1180
|
-
// Where a site is built once, these are three lists; where it is not, they
|
|
1181
|
-
// are one, and everything simply happens in the order it was written.
|
|
1182
|
-
once: statements,
|
|
1183
|
-
each: statements,
|
|
1184
|
-
run: null,
|
|
1185
|
-
at: path,
|
|
1186
|
-
next: /* @__PURE__ */ (() => {
|
|
1187
|
-
let n = 0;
|
|
1188
|
-
return () => t.identifier(`_el$${String(++n)}`);
|
|
1189
|
-
})(),
|
|
1190
|
-
name: (prefix) => t.identifier(`${prefix}${String(++names)}`)
|
|
1191
|
-
};
|
|
1192
|
-
const run = enclosingRun(path, state);
|
|
1193
|
-
if (run !== null) {
|
|
1194
|
-
build.run = run;
|
|
1195
|
-
if (canRetain(path.node, build)) {
|
|
1196
|
-
build.once = [];
|
|
1197
|
-
build.each = [];
|
|
1198
|
-
} else {
|
|
1199
|
-
build.run = null;
|
|
1200
|
-
}
|
|
1201
|
-
}
|
|
1202
|
-
const kept = build.run !== null;
|
|
1203
|
-
const root = t.identifier("_el$");
|
|
1204
|
-
emitElement(path.node, build, root, state);
|
|
1205
|
-
const templateId = t.identifier(`_tmpl$${String(++state.firsthand.counter)}`);
|
|
1206
|
-
state.firsthand.templates.push(
|
|
1207
|
-
t.variableDeclarator(
|
|
1208
|
-
templateId,
|
|
1209
|
-
t.addComment(
|
|
1210
|
-
t.callExpression(runtime(state, "template"), [t.stringLiteral(build.html.join(""))]),
|
|
1211
|
-
"leading",
|
|
1212
|
-
"#__PURE__"
|
|
1213
|
-
)
|
|
1214
|
-
)
|
|
1215
|
-
);
|
|
1216
|
-
if (!kept) {
|
|
1217
|
-
const body2 = [
|
|
1218
|
-
t.variableDeclaration("const", [
|
|
1219
|
-
t.variableDeclarator(root, t.callExpression(t.cloneNode(templateId), []))
|
|
1220
|
-
]),
|
|
1221
|
-
...build.statements,
|
|
1222
|
-
t.returnStatement(t.cloneNode(root))
|
|
1223
|
-
];
|
|
1224
|
-
return t.callExpression(generated(t.arrowFunctionExpression([], t.blockStatement(body2))), []);
|
|
1225
|
-
}
|
|
1226
|
-
const slot = build.name("_site$");
|
|
1227
|
-
const fresh = build.name("_new$");
|
|
1228
|
-
const held = build.name("_own$");
|
|
1229
|
-
const owner = build.run;
|
|
1230
|
-
const body = [
|
|
1231
|
-
t.variableDeclaration("const", [
|
|
1232
|
-
t.variableDeclarator(
|
|
1233
|
-
slot,
|
|
1234
|
-
t.callExpression(runtime(state, "site"), [
|
|
1235
|
-
t.cloneNode(owner.store),
|
|
1236
|
-
t.numericLiteral(owner.next())
|
|
1237
|
-
])
|
|
1238
|
-
)
|
|
1239
|
-
]),
|
|
1240
|
-
t.variableDeclaration("let", [
|
|
1241
|
-
t.variableDeclarator(root, t.memberExpression(t.cloneNode(slot), t.identifier("node")))
|
|
1242
|
-
]),
|
|
1243
|
-
t.variableDeclaration("const", [
|
|
1244
|
-
t.variableDeclarator(
|
|
1245
|
-
fresh,
|
|
1246
|
-
t.binaryExpression("===", t.cloneNode(root), t.identifier("undefined"))
|
|
1247
|
-
)
|
|
1248
|
-
]),
|
|
1249
|
-
t.variableDeclaration("let", [t.variableDeclarator(held)]),
|
|
1250
|
-
t.ifStatement(
|
|
1251
|
-
t.cloneNode(fresh),
|
|
1252
|
-
t.blockStatement([
|
|
1253
|
-
// What this site makes belongs to the instance. A run's own scope is
|
|
1254
|
-
// cleared before it runs again, and a part left there would be
|
|
1255
|
-
// disposed by the very next run.
|
|
1256
|
-
expressionStatement2(
|
|
1257
|
-
t.assignmentExpression(
|
|
1258
|
-
"=",
|
|
1259
|
-
t.cloneNode(held),
|
|
1260
|
-
t.callExpression(runtime(state, "open"), [t.cloneNode(owner.store), t.cloneNode(slot)])
|
|
1261
|
-
)
|
|
1262
|
-
),
|
|
1263
|
-
expressionStatement2(
|
|
1264
|
-
t.assignmentExpression(
|
|
1265
|
-
"=",
|
|
1266
|
-
t.cloneNode(root),
|
|
1267
|
-
t.assignmentExpression(
|
|
1268
|
-
"=",
|
|
1269
|
-
t.memberExpression(t.cloneNode(slot), t.identifier("node")),
|
|
1270
|
-
t.callExpression(t.cloneNode(templateId), [])
|
|
1271
|
-
)
|
|
1272
|
-
)
|
|
1273
|
-
)
|
|
1274
|
-
])
|
|
1275
|
-
),
|
|
1276
|
-
...build.statements,
|
|
1277
|
-
t.ifStatement(
|
|
1278
|
-
t.cloneNode(fresh),
|
|
1279
|
-
t.blockStatement([
|
|
1280
|
-
...build.once,
|
|
1281
|
-
expressionStatement2(t.callExpression(runtime(state, "close"), [t.cloneNode(held)]))
|
|
1282
|
-
])
|
|
1283
|
-
)
|
|
1284
|
-
];
|
|
1285
|
-
body.push(...build.each, t.returnStatement(t.cloneNode(root)));
|
|
1286
|
-
return t.callExpression(generated(t.arrowFunctionExpression([], t.blockStatement(body))), []);
|
|
1287
|
-
}
|
|
1288
|
-
function guardedWrite(build, state, value, write) {
|
|
1289
|
-
const run = build.run;
|
|
1290
|
-
const slot = build.name("_w$");
|
|
1291
|
-
const held = build.name("_x$");
|
|
1292
|
-
const last = () => t.memberExpression(t.cloneNode(slot), t.identifier("last"));
|
|
1293
|
-
pushEach(
|
|
1294
|
-
build,
|
|
1295
|
-
t.variableDeclaration("const", [
|
|
1296
|
-
t.variableDeclarator(
|
|
1297
|
-
slot,
|
|
1298
|
-
t.callExpression(runtime(state, "site"), [
|
|
1299
|
-
t.cloneNode(run.store),
|
|
1300
|
-
t.numericLiteral(run.next())
|
|
1301
|
-
])
|
|
1302
|
-
),
|
|
1303
|
-
t.variableDeclarator(held, value)
|
|
1304
|
-
])
|
|
1305
|
-
);
|
|
1306
|
-
pushEach(
|
|
1307
|
-
build,
|
|
1308
|
-
t.ifStatement(
|
|
1309
|
-
t.binaryExpression("!==", last(), t.cloneNode(held)),
|
|
1310
|
-
t.blockStatement([
|
|
1311
|
-
expressionStatement2(t.assignmentExpression("=", last(), t.cloneNode(held))),
|
|
1312
|
-
expressionStatement2(t.callExpression(runtime(state, "wrote"), [t.cloneNode(run.store)])),
|
|
1313
|
-
expressionStatement2(write(t.cloneNode(held)))
|
|
1314
|
-
])
|
|
1315
|
-
)
|
|
1316
|
-
);
|
|
1317
|
-
}
|
|
1318
|
-
function emitElement(node, build, self, state) {
|
|
1319
|
-
const name = node.openingElement.name;
|
|
1320
|
-
if (!t.isJSXIdentifier(name)) {
|
|
1321
|
-
const namespaced = name;
|
|
1322
|
-
throw new Error(
|
|
1323
|
-
`Namespaced element names are not supported: <${namespaced.namespace.name}:${namespaced.name.name}>. Write the element without a namespace; SVG children are resolved by the parser.`
|
|
1324
|
-
);
|
|
1325
|
-
}
|
|
1326
|
-
const tag = name.name;
|
|
1327
|
-
build.html.push(`<${tag}`);
|
|
1328
|
-
const deferred = [];
|
|
1329
|
-
for (const attribute of node.openingElement.attributes) {
|
|
1330
|
-
emitAttribute(attribute, build, self, state, deferred, tag);
|
|
1331
|
-
}
|
|
1332
|
-
build.html.push(">");
|
|
1333
|
-
for (const emit of deferred) {
|
|
1334
|
-
emit();
|
|
1335
|
-
}
|
|
1336
|
-
emitChildren(node.children, build, self, state);
|
|
1337
|
-
if (!VOID_ELEMENTS.has(tag)) {
|
|
1338
|
-
build.html.push(`</${tag}>`);
|
|
1339
|
-
}
|
|
1340
|
-
}
|
|
1341
|
-
function emitAttribute(attribute, build, self, state, deferred, tag) {
|
|
1342
|
-
if (t.isJSXSpreadAttribute(attribute)) {
|
|
1343
|
-
deferred.push(() => {
|
|
1344
|
-
pushOnce(
|
|
1345
|
-
build,
|
|
1346
|
-
expressionStatement2(
|
|
1347
|
-
t.callExpression(runtime(state, "bind"), [
|
|
1348
|
-
t.arrowFunctionExpression(
|
|
1349
|
-
[],
|
|
1350
|
-
t.callExpression(runtime(state, "spread"), [t.cloneNode(self), attribute.argument])
|
|
1351
|
-
)
|
|
1352
|
-
])
|
|
1353
|
-
)
|
|
1354
|
-
);
|
|
1355
|
-
});
|
|
1356
|
-
return;
|
|
1357
|
-
}
|
|
1358
|
-
const name = attributeName(attribute);
|
|
1359
|
-
const value = attributeValue(attribute);
|
|
1360
|
-
if (name === "ref") {
|
|
1361
|
-
deferred.push(() => {
|
|
1362
|
-
pushOnce(
|
|
1363
|
-
build,
|
|
1364
|
-
expressionStatement2(t.callExpression(value, [t.cloneNode(self)]))
|
|
1365
|
-
);
|
|
1366
|
-
});
|
|
1367
|
-
return;
|
|
1368
|
-
}
|
|
1369
|
-
if (name.startsWith("on") && name.length > 2 && /[A-Z:]/.test(name[2])) {
|
|
1370
|
-
const parts = name.split(":");
|
|
1371
|
-
const literal = parts[0] === "on";
|
|
1372
|
-
const type = literal ? parts[1] : eventName(parts[0]);
|
|
1373
|
-
const modifier = parts[literal ? 2 : 1];
|
|
1374
|
-
deferred.push(() => {
|
|
1375
|
-
const args = [
|
|
1376
|
-
t.cloneNode(self),
|
|
1377
|
-
t.stringLiteral(type),
|
|
1378
|
-
value
|
|
1379
|
-
];
|
|
1380
|
-
if (modifier === "native") {
|
|
1381
|
-
args.push(t.booleanLiteral(true));
|
|
1382
|
-
} else if (modifier !== void 0) {
|
|
1383
|
-
args.push(
|
|
1384
|
-
t.objectExpression([t.objectProperty(propertyKey(modifier), t.booleanLiteral(true))])
|
|
1385
|
-
);
|
|
1386
|
-
}
|
|
1387
|
-
const attach = expressionStatement2(t.callExpression(runtime(state, "on"), args));
|
|
1388
|
-
if (dependsOnRun(value, build.run, build.at)) {
|
|
1389
|
-
pushEach(build, attach);
|
|
1390
|
-
} else {
|
|
1391
|
-
pushOnce(build, attach);
|
|
1392
|
-
}
|
|
1393
|
-
});
|
|
1394
|
-
return;
|
|
1395
|
-
}
|
|
1396
|
-
if (value !== null && isStaticValue(value) && canInlineAttribute(name)) {
|
|
1397
|
-
if (t.isBooleanLiteral(value) && !value.value) {
|
|
1398
|
-
return;
|
|
1399
|
-
}
|
|
1400
|
-
if (t.isNullLiteral(value)) {
|
|
1401
|
-
return;
|
|
1402
|
-
}
|
|
1403
|
-
const literal = t.isStringLiteral(value) ? value.value : t.isNumericLiteral(value) ? String(value.value) : "";
|
|
1404
|
-
build.html.push(` ${name}="${escapeAttribute(literal)}"`);
|
|
1405
|
-
return;
|
|
1406
|
-
}
|
|
1407
|
-
if (value === null) {
|
|
1408
|
-
build.html.push(` ${name}=""`);
|
|
1409
|
-
return;
|
|
1410
|
-
}
|
|
1411
|
-
deferred.push(() => {
|
|
1412
|
-
if (dependsOnRun(value, build.run, build.at)) {
|
|
1413
|
-
guardedWrite(
|
|
1414
|
-
build,
|
|
1415
|
-
state,
|
|
1416
|
-
value,
|
|
1417
|
-
(held) => dynamicAttributeCall(name, held, self, state, tag)
|
|
1418
|
-
);
|
|
1419
|
-
return;
|
|
1420
|
-
}
|
|
1421
|
-
pushOnce(
|
|
1422
|
-
build,
|
|
1423
|
-
expressionStatement2(
|
|
1424
|
-
t.callExpression(runtime(state, "bind"), [
|
|
1425
|
-
located(
|
|
1426
|
-
t.arrowFunctionExpression([], dynamicAttributeCall(name, value, self, state, tag)),
|
|
1427
|
-
value
|
|
1428
|
-
)
|
|
1429
|
-
])
|
|
1430
|
-
)
|
|
1431
|
-
);
|
|
1432
|
-
});
|
|
1433
|
-
}
|
|
1434
|
-
function canInlineAttribute(name) {
|
|
1435
|
-
return !name.startsWith("prop:") && !name.startsWith("attr:") && !DOM_PROPERTIES.has(name) && !BOOLEAN_PROPERTIES.has(name);
|
|
1436
|
-
}
|
|
1437
|
-
function dynamicAttributeCall(name, value, self, state, tag) {
|
|
1438
|
-
if (name.startsWith("prop:")) {
|
|
1439
|
-
return t.callExpression(runtime(state, "setProperty"), [
|
|
1440
|
-
t.cloneNode(self),
|
|
1441
|
-
t.stringLiteral(name.slice(5)),
|
|
1442
|
-
value
|
|
1443
|
-
]);
|
|
1444
|
-
}
|
|
1445
|
-
if (name.startsWith("attr:")) {
|
|
1446
|
-
return t.callExpression(runtime(state, "setAttribute"), [
|
|
1447
|
-
t.cloneNode(self),
|
|
1448
|
-
t.stringLiteral(name.slice(5)),
|
|
1449
|
-
value
|
|
1450
|
-
]);
|
|
1451
|
-
}
|
|
1452
|
-
if (name === "class" || name === "className" || name === "style") {
|
|
1453
|
-
return t.callExpression(runtime(state, "applyProp"), [
|
|
1454
|
-
t.cloneNode(self),
|
|
1455
|
-
t.stringLiteral(name),
|
|
1456
|
-
value
|
|
1457
|
-
]);
|
|
1458
|
-
}
|
|
1459
|
-
if (BOOLEAN_PROPERTIES.has(name)) {
|
|
1460
|
-
return t.callExpression(runtime(state, "setBoolean"), [
|
|
1461
|
-
t.cloneNode(self),
|
|
1462
|
-
t.stringLiteral(name),
|
|
1463
|
-
value
|
|
1464
|
-
]);
|
|
1465
|
-
}
|
|
1466
|
-
if (DOM_PROPERTIES.has(name) && !SVG_ELEMENTS.has(tag)) {
|
|
1467
|
-
return t.callExpression(runtime(state, "setProperty"), [
|
|
1468
|
-
t.cloneNode(self),
|
|
1469
|
-
t.stringLiteral(name),
|
|
1470
|
-
value
|
|
1471
|
-
]);
|
|
1472
|
-
}
|
|
1473
|
-
return t.callExpression(runtime(state, "setAttribute"), [
|
|
1474
|
-
t.cloneNode(self),
|
|
1475
|
-
t.stringLiteral(name),
|
|
1476
|
-
value
|
|
1477
|
-
]);
|
|
1478
|
-
}
|
|
1479
|
-
var LIST_CALL = /* @__PURE__ */ Symbol("firsthand.list");
|
|
1480
|
-
function rewriteKeyedMaps(path, state) {
|
|
1481
|
-
path.traverse({
|
|
1482
|
-
CallExpression(call) {
|
|
1483
|
-
if (!isChildPosition(call)) {
|
|
1484
|
-
return;
|
|
1485
|
-
}
|
|
1486
|
-
const callee = call.node.callee;
|
|
1487
|
-
if (!t.isMemberExpression(callee) || callee.computed || !t.isIdentifier(callee.property, { name: "map" }) || call.node.arguments.length !== 1) {
|
|
1488
|
-
return;
|
|
1489
|
-
}
|
|
1490
|
-
const callback = call.get("arguments.0");
|
|
1491
|
-
if (!callback.isArrowFunctionExpression() && !callback.isFunctionExpression()) {
|
|
1492
|
-
return;
|
|
1493
|
-
}
|
|
1494
|
-
const params = callback.node.params;
|
|
1495
|
-
const itemParam = params[0];
|
|
1496
|
-
const indexParam = params[1];
|
|
1497
|
-
if (!t.isIdentifier(itemParam) || indexParam !== void 0 && !t.isIdentifier(indexParam)) {
|
|
1498
|
-
return;
|
|
1499
|
-
}
|
|
1500
|
-
const root = keyedRoot(callback);
|
|
1501
|
-
if (root === null) {
|
|
1502
|
-
return;
|
|
1503
|
-
}
|
|
1504
|
-
const keyExpression = t.cloneNode(root.key);
|
|
1505
|
-
root.element.openingElement.attributes = root.element.openingElement.attributes.filter(
|
|
1506
|
-
(attribute) => attribute !== root.attribute
|
|
1507
|
-
);
|
|
1508
|
-
const itemCell = callback.scope.generateUidIdentifier("item");
|
|
1509
|
-
const indexCell = callback.scope.generateUidIdentifier("index");
|
|
1510
|
-
callback.scope.crawl();
|
|
1511
|
-
liveRead(callback, itemParam.name, itemCell);
|
|
1512
|
-
if (indexParam !== void 0) {
|
|
1513
|
-
liveRead(callback, indexParam.name, indexCell);
|
|
1514
|
-
}
|
|
1515
|
-
callback.node.params = [itemCell, indexCell];
|
|
1516
|
-
const listCall = t.callExpression(runtime(state, "list"), [
|
|
1517
|
-
t.arrowFunctionExpression([], callee.object),
|
|
1518
|
-
t.arrowFunctionExpression(
|
|
1519
|
-
[t.cloneNode(itemParam), indexParam ?? callback.scope.generateUidIdentifier("i")],
|
|
1520
|
-
keyExpression
|
|
1521
|
-
),
|
|
1522
|
-
callback.node
|
|
1523
|
-
]);
|
|
1524
|
-
listCall[LIST_CALL] = true;
|
|
1525
|
-
call.replaceWith(listCall);
|
|
1526
|
-
call.skip();
|
|
1527
|
-
}
|
|
1528
|
-
});
|
|
1529
|
-
}
|
|
1530
|
-
function isChildPosition(call) {
|
|
1531
|
-
let child = call;
|
|
1532
|
-
let parent = child.parentPath;
|
|
1533
|
-
while (!parent.isJSXExpressionContainer()) {
|
|
1534
|
-
const key = child.key;
|
|
1535
|
-
const throughConditional = parent.isConditionalExpression() && (key === "consequent" || key === "alternate");
|
|
1536
|
-
const throughLogical = parent.isLogicalExpression() && key === "right";
|
|
1537
|
-
if (!throughConditional && !throughLogical) {
|
|
1538
|
-
return false;
|
|
1539
|
-
}
|
|
1540
|
-
child = parent;
|
|
1541
|
-
parent = parent.parentPath;
|
|
1542
|
-
}
|
|
1543
|
-
const holder = parent.parentPath;
|
|
1544
|
-
return holder.isJSXElement() || holder.isJSXFragment();
|
|
1545
|
-
}
|
|
1546
|
-
function keyedRoot(callback) {
|
|
1547
|
-
const body = callback.node.body;
|
|
1548
|
-
let element = null;
|
|
1549
|
-
if (t.isJSXElement(body)) {
|
|
1550
|
-
element = body;
|
|
1551
|
-
} else if (t.isBlockStatement(body)) {
|
|
1552
|
-
const last = body.body[body.body.length - 1];
|
|
1553
|
-
if (t.isReturnStatement(last) && t.isJSXElement(last.argument)) {
|
|
1554
|
-
element = last.argument;
|
|
1555
|
-
}
|
|
1556
|
-
}
|
|
1557
|
-
if (element === null || !t.isJSXElement(element)) {
|
|
1558
|
-
return null;
|
|
1559
|
-
}
|
|
1560
|
-
for (const attribute of element.openingElement.attributes) {
|
|
1561
|
-
if (t.isJSXAttribute(attribute) && t.isJSXIdentifier(attribute.name, { name: "key" }) && t.isJSXExpressionContainer(attribute.value)) {
|
|
1562
|
-
return { element, attribute, key: attribute.value.expression };
|
|
1563
|
-
}
|
|
1564
|
-
}
|
|
1565
|
-
return null;
|
|
1566
|
-
}
|
|
1567
|
-
function liveRead(scopePath, name, cell) {
|
|
1568
|
-
const binding = scopePath.scope.getBinding(name);
|
|
1569
|
-
for (const reference of binding.referencePaths) {
|
|
1570
|
-
reference.replaceWith(t.memberExpression(t.cloneNode(cell), t.identifier("value")));
|
|
1571
|
-
}
|
|
1572
|
-
}
|
|
1573
|
-
function emitChildren(children, build, self, state) {
|
|
1574
|
-
const entries = planChildren(children);
|
|
1575
|
-
let previous = null;
|
|
1576
|
-
let previousIndex = 0;
|
|
1577
|
-
let index = 0;
|
|
1578
|
-
const reference = () => {
|
|
1579
|
-
const id = build.next();
|
|
1580
|
-
build.statements.push(
|
|
1581
|
-
t.variableDeclaration("const", [
|
|
1582
|
-
t.variableDeclarator(id, navigate(self, previous, previousIndex, index, state))
|
|
1583
|
-
])
|
|
1584
|
-
);
|
|
1585
|
-
previous = id;
|
|
1586
|
-
previousIndex = index;
|
|
1587
|
-
return id;
|
|
1588
|
-
};
|
|
1589
|
-
for (let i = 0; i < entries.length; i++) {
|
|
1590
|
-
const entry = entries[i];
|
|
1591
|
-
if (entry.kind === "text") {
|
|
1592
|
-
build.html.push(escapeText(entry.text));
|
|
1593
|
-
index++;
|
|
1594
|
-
continue;
|
|
1595
|
-
}
|
|
1596
|
-
if (entry.kind === "element") {
|
|
1597
|
-
const element = entry.element;
|
|
1598
|
-
if (needsReference(element)) {
|
|
1599
|
-
const id = reference();
|
|
1600
|
-
emitElement(element, build, id, state);
|
|
1601
|
-
} else {
|
|
1602
|
-
emitElement(element, build, t.identifier("_unused$"), state);
|
|
1603
|
-
}
|
|
1604
|
-
index++;
|
|
1605
|
-
continue;
|
|
1606
|
-
}
|
|
1607
|
-
const isLast = i === entries.length - 1;
|
|
1608
|
-
const expression = entry.expression;
|
|
1609
|
-
let marker = null;
|
|
1610
|
-
if (!isLast) {
|
|
1611
|
-
build.html.push("<!>");
|
|
1612
|
-
marker = t.cloneNode(reference());
|
|
1613
|
-
}
|
|
1614
|
-
if (entry.kind !== "list" && dependsOnRun(expression, build.run, build.at)) {
|
|
1615
|
-
const run = build.run;
|
|
1616
|
-
pushEach(
|
|
1617
|
-
build,
|
|
1618
|
-
expressionStatement2(
|
|
1619
|
-
t.callExpression(runtime(state, "writeChild"), [
|
|
1620
|
-
t.cloneNode(run.store),
|
|
1621
|
-
t.numericLiteral(run.next()),
|
|
1622
|
-
t.cloneNode(self),
|
|
1623
|
-
marker ?? t.nullLiteral(),
|
|
1624
|
-
expression
|
|
1625
|
-
])
|
|
1626
|
-
)
|
|
1627
|
-
);
|
|
1628
|
-
index++;
|
|
1629
|
-
continue;
|
|
1630
|
-
}
|
|
1631
|
-
const args = [
|
|
1632
|
-
t.cloneNode(self),
|
|
1633
|
-
// A list part is already a thunk that owns its rows; wrapping it would
|
|
1634
|
-
// rebuild the whole list on every evaluation.
|
|
1635
|
-
entry.kind === "list" ? expression : thunk(expression)
|
|
1636
|
-
];
|
|
1637
|
-
if (marker !== null) {
|
|
1638
|
-
args.push(marker);
|
|
1639
|
-
}
|
|
1640
|
-
pushOnce(build, expressionStatement2(t.callExpression(runtime(state, "insert"), args)));
|
|
1641
|
-
index++;
|
|
1642
|
-
}
|
|
1643
|
-
}
|
|
1644
|
-
function needsReference(element) {
|
|
1645
|
-
for (const attribute of element.openingElement.attributes) {
|
|
1646
|
-
if (t.isJSXSpreadAttribute(attribute)) {
|
|
1647
|
-
return true;
|
|
1648
|
-
}
|
|
1649
|
-
const name = attributeName(attribute);
|
|
1650
|
-
if (name === "ref" || name.startsWith("on")) {
|
|
1651
|
-
return true;
|
|
1652
|
-
}
|
|
1653
|
-
const value = attributeValue(attribute);
|
|
1654
|
-
if (value !== null && (!isStaticValue(value) || !canInlineAttribute(name))) {
|
|
1655
|
-
return true;
|
|
1656
|
-
}
|
|
1657
|
-
}
|
|
1658
|
-
for (const entry of planChildren(element.children)) {
|
|
1659
|
-
if (entry.kind === "dynamic" || entry.kind === "list") {
|
|
1660
|
-
return true;
|
|
1661
|
-
}
|
|
1662
|
-
if (entry.kind === "element" && needsReference(entry.element)) {
|
|
1663
|
-
return true;
|
|
1664
|
-
}
|
|
1665
|
-
}
|
|
1666
|
-
return false;
|
|
1667
|
-
}
|
|
1668
|
-
function navigate(self, previous, previousIndex, index, state) {
|
|
1669
|
-
const hydratable = state.firsthand.hydratable;
|
|
1670
|
-
const first = hydratable ? runtime(state, "first") : null;
|
|
1671
|
-
const next = hydratable ? runtime(state, "next") : null;
|
|
1672
|
-
let expression;
|
|
1673
|
-
let steps;
|
|
1674
|
-
if (previous === null) {
|
|
1675
|
-
expression = hydratable ? t.callExpression(first, [t.cloneNode(self)]) : t.memberExpression(t.cloneNode(self), t.identifier("firstChild"));
|
|
1676
|
-
steps = index;
|
|
1677
|
-
} else {
|
|
1678
|
-
expression = t.cloneNode(previous);
|
|
1679
|
-
steps = index - previousIndex;
|
|
1680
|
-
}
|
|
1681
|
-
for (let i = 0; i < steps; i++) {
|
|
1682
|
-
expression = hydratable ? t.callExpression(next, [expression]) : t.memberExpression(expression, t.identifier("nextSibling"));
|
|
1683
|
-
}
|
|
1684
|
-
return expression;
|
|
1685
|
-
}
|
|
1686
|
-
function planChildren(children) {
|
|
1687
|
-
const entries = [];
|
|
1688
|
-
let pending = "";
|
|
1689
|
-
const flush = () => {
|
|
1690
|
-
if (pending !== "") {
|
|
1691
|
-
entries.push({ kind: "text", text: pending });
|
|
1692
|
-
pending = "";
|
|
1693
|
-
}
|
|
1694
|
-
};
|
|
1695
|
-
for (const child of children) {
|
|
1696
|
-
if (t.isJSXText(child)) {
|
|
1697
|
-
pending += cleanText(child.value);
|
|
1698
|
-
continue;
|
|
1699
|
-
}
|
|
1700
|
-
if (t.isJSXExpressionContainer(child)) {
|
|
1701
|
-
const expression = child.expression;
|
|
1702
|
-
if (t.isJSXEmptyExpression(expression)) {
|
|
1703
|
-
continue;
|
|
1704
|
-
}
|
|
1705
|
-
if (t.isStringLiteral(expression) || t.isNumericLiteral(expression)) {
|
|
1706
|
-
pending += String(expression.value);
|
|
1707
|
-
continue;
|
|
1708
|
-
}
|
|
1709
|
-
flush();
|
|
1710
|
-
const isList = expression[LIST_CALL] === true;
|
|
1711
|
-
entries.push({ kind: isList ? "list" : "dynamic", expression });
|
|
1712
|
-
continue;
|
|
1713
|
-
}
|
|
1714
|
-
flush();
|
|
1715
|
-
if (t.isJSXElement(child) && !isComponentTag(child)) {
|
|
1716
|
-
entries.push({ kind: "element", element: child });
|
|
1717
|
-
continue;
|
|
1718
|
-
}
|
|
1719
|
-
entries.push({ kind: "dynamic", expression: child });
|
|
1720
|
-
}
|
|
1721
|
-
flush();
|
|
1722
|
-
return entries;
|
|
1723
|
-
}
|
|
1724
|
-
function cleanText(value) {
|
|
1725
|
-
const lines = value.split(/\r\n|\n|\r/);
|
|
1726
|
-
const kept = [];
|
|
1727
|
-
for (let i = 0; i < lines.length; i++) {
|
|
1728
|
-
let line = lines[i];
|
|
1729
|
-
if (i > 0) {
|
|
1730
|
-
line = line.replace(/^[\t ]+/, "");
|
|
1731
|
-
}
|
|
1732
|
-
if (i < lines.length - 1) {
|
|
1733
|
-
line = line.replace(/[\t ]+$/, "");
|
|
1734
|
-
}
|
|
1735
|
-
if (line !== "") {
|
|
1736
|
-
kept.push(line);
|
|
1737
|
-
}
|
|
1738
|
-
}
|
|
1739
|
-
return kept.join(" ");
|
|
1740
|
-
}
|
|
1741
|
-
function compileChildren(children, state, kept) {
|
|
1742
|
-
const result = [];
|
|
1743
|
-
for (const entry of planChildren(children)) {
|
|
1744
|
-
if (entry.kind === "text") {
|
|
1745
|
-
result.push(t.stringLiteral(entry.text));
|
|
1746
|
-
} else if (entry.kind === "element") {
|
|
1747
|
-
result.push(entry.element);
|
|
1748
|
-
} else if (state.firsthand.ssr) {
|
|
1749
|
-
result.push(entry.expression);
|
|
1750
|
-
} else if (entry.kind === "list") {
|
|
1751
|
-
const list = entry.expression;
|
|
1752
|
-
keepReading(list, kept);
|
|
1753
|
-
result.push(t.callExpression(runtime(state, "part"), [list]));
|
|
1754
|
-
} else {
|
|
1755
|
-
const value = entry.expression;
|
|
1756
|
-
const read = kept !== void 0 && kept.depends(value) ? kept.cell(value) : value;
|
|
1757
|
-
result.push(t.callExpression(runtime(state, "part"), [thunk(read)]));
|
|
1758
|
-
}
|
|
1759
|
-
}
|
|
1760
|
-
return result;
|
|
1761
|
-
}
|
|
1762
|
-
function keepReading(list, kept) {
|
|
1763
|
-
const each = list.arguments[0];
|
|
1764
|
-
if (kept === void 0 || !t.isArrowFunctionExpression(each) || !t.isExpression(each.body)) {
|
|
1765
|
-
return;
|
|
1766
|
-
}
|
|
1767
|
-
if (!kept.depends(each.body)) {
|
|
1768
|
-
return;
|
|
1769
|
-
}
|
|
1770
|
-
each.body = kept.value(each.body);
|
|
1771
|
-
}
|
|
1772
|
-
function thunk(expression) {
|
|
1773
|
-
const arrow = t.arrowFunctionExpression([], expression);
|
|
1774
|
-
arrow[CHILD_THUNK] = true;
|
|
1775
|
-
takePosition(arrow, expression);
|
|
1776
|
-
return arrow;
|
|
1777
|
-
}
|
|
1778
|
-
function takePosition(target, expression) {
|
|
1779
|
-
const loc = expression.loc;
|
|
1780
|
-
if (loc !== null && loc !== void 0) {
|
|
1781
|
-
target.loc = { ...loc, end: loc.start };
|
|
1782
|
-
expression.loc = null;
|
|
1783
|
-
}
|
|
1784
|
-
}
|
|
1785
|
-
function expressionStatement2(expression) {
|
|
1786
|
-
return located(t.expressionStatement(expression), expression);
|
|
1787
|
-
}
|
|
1788
|
-
function located(node, source) {
|
|
1789
|
-
if (source == null || source.loc == null) {
|
|
1790
|
-
return node;
|
|
1791
|
-
}
|
|
1792
|
-
node.loc = source.loc;
|
|
1793
|
-
return node;
|
|
1794
|
-
}
|
|
1795
|
-
|
|
1796
|
-
// packages/compiler/src/api.ts
|
|
1797
|
-
import { transformSync } from "@babel/core";
|
|
1798
|
-
import jsxSyntax from "@babel/plugin-syntax-jsx";
|
|
1799
|
-
import typescriptSyntax from "@babel/plugin-syntax-typescript";
|
|
1800
|
-
function compileModule(code, options = {}) {
|
|
1801
|
-
const result = transformSync(code, {
|
|
1802
|
-
...options.filename === void 0 ? {} : {
|
|
1803
|
-
filename: options.filename,
|
|
1804
|
-
// The full path, not the basename Babel would default to. A map
|
|
1805
|
-
// whose `sources` is `comp.tsx` resolves, relative to a module
|
|
1806
|
-
// served at `/src/comp.tsx`, to that very URL — so a debugger ends
|
|
1807
|
-
// up with two files under one address, shows both, and puts the
|
|
1808
|
-
// breakpoint in the wrong one.
|
|
1809
|
-
sourceFileName: options.filename
|
|
1810
|
-
},
|
|
1811
|
-
babelrc: false,
|
|
1812
|
-
configFile: false,
|
|
1813
|
-
sourceMaps: options.sourceMaps === true,
|
|
1814
|
-
plugins: buildPlugins(options)
|
|
1815
|
-
});
|
|
1816
|
-
return { code: result.code, map: result.map };
|
|
1817
|
-
}
|
|
1818
|
-
function transform(code, options = {}) {
|
|
1819
|
-
return compileModule(code, options).code;
|
|
1820
|
-
}
|
|
1821
|
-
function buildPlugins(options) {
|
|
1822
|
-
const plugins = [];
|
|
1823
|
-
if (options.typescript === true) {
|
|
1824
|
-
plugins.push([typescriptSyntax, { isTSX: true }]);
|
|
1825
|
-
}
|
|
1826
|
-
plugins.push(jsxSyntax);
|
|
1827
|
-
plugins.push([
|
|
1828
|
-
firsthandPlugin,
|
|
1829
|
-
{
|
|
1830
|
-
packageName: options.packageName,
|
|
1831
|
-
strictReactivity: options.strictReactivity,
|
|
1832
|
-
devtools: options.devtools,
|
|
1833
|
-
ssr: options.ssr,
|
|
1834
|
-
hydratable: options.hydratable
|
|
1835
|
-
}
|
|
1836
|
-
]);
|
|
1837
|
-
return plugins;
|
|
1838
|
-
}
|
|
1839
|
-
|
|
1840
|
-
export {
|
|
1841
|
-
stableId,
|
|
1842
|
-
firsthandPlugin,
|
|
1843
|
-
compileModule,
|
|
1844
|
-
transform
|
|
1845
|
-
};
|