@vertz/ui-compiler 0.2.3 → 1.0.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/README.md +1 -17
- package/dist/index.d.ts +60 -61
- package/dist/index.js +566 -996
- package/package.json +19 -11
package/dist/index.js
CHANGED
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
import { createRequire } from "node:module";
|
|
2
|
+
var __require = /* @__PURE__ */ createRequire(import.meta.url);
|
|
3
|
+
|
|
1
4
|
// src/analyzers/component-analyzer.ts
|
|
2
5
|
import {
|
|
3
6
|
SyntaxKind
|
|
@@ -169,40 +172,12 @@ class CSSAnalyzer {
|
|
|
169
172
|
if (!init || !init.isKind(SyntaxKind2.ArrayLiteralExpression))
|
|
170
173
|
return false;
|
|
171
174
|
for (const el of init.getElements()) {
|
|
172
|
-
if (el.isKind(SyntaxKind2.StringLiteral))
|
|
173
|
-
continue;
|
|
174
|
-
if (el.isKind(SyntaxKind2.ObjectLiteralExpression)) {
|
|
175
|
-
if (this.isStaticRawDeclaration(el))
|
|
176
|
-
continue;
|
|
175
|
+
if (!el.isKind(SyntaxKind2.StringLiteral))
|
|
177
176
|
return false;
|
|
178
|
-
}
|
|
179
|
-
return false;
|
|
180
177
|
}
|
|
181
178
|
}
|
|
182
179
|
return true;
|
|
183
180
|
}
|
|
184
|
-
isStaticRawDeclaration(node) {
|
|
185
|
-
if (!node.isKind(SyntaxKind2.ObjectLiteralExpression))
|
|
186
|
-
return false;
|
|
187
|
-
const props = node.getProperties();
|
|
188
|
-
if (props.length !== 2)
|
|
189
|
-
return false;
|
|
190
|
-
let hasProperty = false;
|
|
191
|
-
let hasValue = false;
|
|
192
|
-
for (const prop of props) {
|
|
193
|
-
if (!prop.isKind(SyntaxKind2.PropertyAssignment))
|
|
194
|
-
return false;
|
|
195
|
-
const init = prop.getInitializer();
|
|
196
|
-
if (!init || !init.isKind(SyntaxKind2.StringLiteral))
|
|
197
|
-
return false;
|
|
198
|
-
const name = prop.getName();
|
|
199
|
-
if (name === "property")
|
|
200
|
-
hasProperty = true;
|
|
201
|
-
else if (name === "value")
|
|
202
|
-
hasValue = true;
|
|
203
|
-
}
|
|
204
|
-
return hasProperty && hasValue;
|
|
205
|
-
}
|
|
206
181
|
extractBlockNames(node) {
|
|
207
182
|
if (!node.isKind(SyntaxKind2.ObjectLiteralExpression))
|
|
208
183
|
return [];
|
|
@@ -235,24 +210,6 @@ function findBodyNode(sourceFile, component) {
|
|
|
235
210
|
class JsxAnalyzer {
|
|
236
211
|
analyze(sourceFile, component, variables) {
|
|
237
212
|
const reactiveNames = new Set(variables.filter((v) => v.kind === "signal" || v.kind === "computed").map((v) => v.name));
|
|
238
|
-
const signalApiVars = new Map;
|
|
239
|
-
const plainPropVars = new Map;
|
|
240
|
-
const fieldSignalPropVars = new Map;
|
|
241
|
-
const reactiveSourceVars = new Set;
|
|
242
|
-
for (const v of variables) {
|
|
243
|
-
if (v.signalProperties && v.signalProperties.size > 0) {
|
|
244
|
-
signalApiVars.set(v.name, v.signalProperties);
|
|
245
|
-
}
|
|
246
|
-
if (v.plainProperties && v.plainProperties.size > 0) {
|
|
247
|
-
plainPropVars.set(v.name, v.plainProperties);
|
|
248
|
-
}
|
|
249
|
-
if (v.fieldSignalProperties && v.fieldSignalProperties.size > 0) {
|
|
250
|
-
fieldSignalPropVars.set(v.name, v.fieldSignalProperties);
|
|
251
|
-
}
|
|
252
|
-
if (v.isReactiveSource) {
|
|
253
|
-
reactiveSourceVars.add(v.name);
|
|
254
|
-
}
|
|
255
|
-
}
|
|
256
213
|
const bodyNode = findBodyNode(sourceFile, component);
|
|
257
214
|
if (!bodyNode)
|
|
258
215
|
return [];
|
|
@@ -262,71 +219,16 @@ class JsxAnalyzer {
|
|
|
262
219
|
const identifiers = collectIdentifiers(expr);
|
|
263
220
|
const deps = identifiers.filter((id) => reactiveNames.has(id));
|
|
264
221
|
const uniqueDeps = [...new Set(deps)];
|
|
265
|
-
const hasSignalApiAccess = containsSignalApiPropertyAccess(expr, signalApiVars, plainPropVars, fieldSignalPropVars);
|
|
266
|
-
const hasReactiveSourceAccess = containsReactiveSourceAccess(expr, reactiveSourceVars);
|
|
267
222
|
results.push({
|
|
268
223
|
start: expr.getStart(),
|
|
269
224
|
end: expr.getEnd(),
|
|
270
|
-
reactive: uniqueDeps.length > 0
|
|
225
|
+
reactive: uniqueDeps.length > 0,
|
|
271
226
|
deps: uniqueDeps
|
|
272
227
|
});
|
|
273
228
|
}
|
|
274
229
|
return results;
|
|
275
230
|
}
|
|
276
231
|
}
|
|
277
|
-
function containsSignalApiPropertyAccess(node, signalApiVars, plainPropVars, fieldSignalPropVars) {
|
|
278
|
-
if (signalApiVars.size === 0 && fieldSignalPropVars.size === 0)
|
|
279
|
-
return false;
|
|
280
|
-
const propAccesses = node.getDescendantsOfKind(SyntaxKind4.PropertyAccessExpression);
|
|
281
|
-
for (const pa of propAccesses) {
|
|
282
|
-
const obj = pa.getExpression();
|
|
283
|
-
const propName = pa.getName();
|
|
284
|
-
if (obj.isKind(SyntaxKind4.Identifier)) {
|
|
285
|
-
const varName = obj.getText();
|
|
286
|
-
const signalProps = signalApiVars.get(varName);
|
|
287
|
-
if (signalProps?.has(propName)) {
|
|
288
|
-
return true;
|
|
289
|
-
}
|
|
290
|
-
}
|
|
291
|
-
if (obj.isKind(SyntaxKind4.PropertyAccessExpression)) {
|
|
292
|
-
const innerExpr = obj.asKindOrThrow(SyntaxKind4.PropertyAccessExpression);
|
|
293
|
-
const rootExpr = innerExpr.getExpression();
|
|
294
|
-
const middleProp = innerExpr.getName();
|
|
295
|
-
if (rootExpr.isKind(SyntaxKind4.Identifier)) {
|
|
296
|
-
const rootName = rootExpr.getText();
|
|
297
|
-
const fieldSignalProps = fieldSignalPropVars.get(rootName);
|
|
298
|
-
if (!fieldSignalProps)
|
|
299
|
-
continue;
|
|
300
|
-
const signalProps = signalApiVars.get(rootName);
|
|
301
|
-
const plainProps = plainPropVars.get(rootName);
|
|
302
|
-
if (signalProps?.has(middleProp) || plainProps?.has(middleProp))
|
|
303
|
-
continue;
|
|
304
|
-
if (fieldSignalProps.has(propName)) {
|
|
305
|
-
return true;
|
|
306
|
-
}
|
|
307
|
-
}
|
|
308
|
-
}
|
|
309
|
-
}
|
|
310
|
-
return false;
|
|
311
|
-
}
|
|
312
|
-
function containsReactiveSourceAccess(node, reactiveSourceVars) {
|
|
313
|
-
if (reactiveSourceVars.size === 0)
|
|
314
|
-
return false;
|
|
315
|
-
const propAccesses = node.getDescendantsOfKind(SyntaxKind4.PropertyAccessExpression);
|
|
316
|
-
for (const pa of propAccesses) {
|
|
317
|
-
const obj = pa.getExpression();
|
|
318
|
-
if (obj.isKind(SyntaxKind4.Identifier) && reactiveSourceVars.has(obj.getText())) {
|
|
319
|
-
return true;
|
|
320
|
-
}
|
|
321
|
-
}
|
|
322
|
-
const identifiers = node.getDescendantsOfKind(SyntaxKind4.Identifier);
|
|
323
|
-
for (const id of identifiers) {
|
|
324
|
-
if (reactiveSourceVars.has(id.getText())) {
|
|
325
|
-
return true;
|
|
326
|
-
}
|
|
327
|
-
}
|
|
328
|
-
return false;
|
|
329
|
-
}
|
|
330
232
|
function collectIdentifiers(node) {
|
|
331
233
|
const ids = [];
|
|
332
234
|
const walk = (n) => {
|
|
@@ -453,26 +355,21 @@ import { SyntaxKind as SyntaxKind6 } from "ts-morph";
|
|
|
453
355
|
// src/signal-api-registry.ts
|
|
454
356
|
var SIGNAL_API_REGISTRY = {
|
|
455
357
|
query: {
|
|
456
|
-
signalProperties: new Set(["data", "loading", "error"
|
|
457
|
-
plainProperties: new Set(["refetch"
|
|
358
|
+
signalProperties: new Set(["data", "loading", "error"]),
|
|
359
|
+
plainProperties: new Set(["refetch"])
|
|
458
360
|
},
|
|
459
361
|
form: {
|
|
460
|
-
signalProperties: new Set(["submitting", "
|
|
461
|
-
plainProperties: new Set(["
|
|
462
|
-
fieldSignalProperties: new Set(["error", "dirty", "touched", "value"])
|
|
362
|
+
signalProperties: new Set(["submitting", "errors", "values"]),
|
|
363
|
+
plainProperties: new Set(["reset", "submit", "handleSubmit"])
|
|
463
364
|
},
|
|
464
365
|
createLoader: {
|
|
465
366
|
signalProperties: new Set(["data", "loading", "error"]),
|
|
466
367
|
plainProperties: new Set(["refetch"])
|
|
467
368
|
}
|
|
468
369
|
};
|
|
469
|
-
var REACTIVE_SOURCE_APIS = new Set(["useContext"]);
|
|
470
370
|
function isSignalApi(functionName) {
|
|
471
371
|
return functionName in SIGNAL_API_REGISTRY;
|
|
472
372
|
}
|
|
473
|
-
function isReactiveSourceApi(functionName) {
|
|
474
|
-
return REACTIVE_SOURCE_APIS.has(functionName);
|
|
475
|
-
}
|
|
476
373
|
function getSignalApiConfig(functionName) {
|
|
477
374
|
return SIGNAL_API_REGISTRY[functionName];
|
|
478
375
|
}
|
|
@@ -483,14 +380,10 @@ class ReactivityAnalyzer {
|
|
|
483
380
|
const bodyNode = findBodyNode(sourceFile, component);
|
|
484
381
|
if (!bodyNode)
|
|
485
382
|
return [];
|
|
486
|
-
const
|
|
487
|
-
const declaredNames = collectDeclaredNames(bodyNode);
|
|
383
|
+
const importAliases = buildImportAliasMap(sourceFile);
|
|
488
384
|
const lets = new Map;
|
|
489
385
|
const consts = new Map;
|
|
490
386
|
const signalApiVars = new Map;
|
|
491
|
-
const reactiveSourceVars = new Set;
|
|
492
|
-
const destructuredFromMap = new Map;
|
|
493
|
-
const syntheticCounters = new Map;
|
|
494
387
|
for (const stmt of bodyNode.getChildSyntaxList()?.getChildren() ?? []) {
|
|
495
388
|
if (!stmt.isKind(SyntaxKind6.VariableStatement))
|
|
496
389
|
continue;
|
|
@@ -504,52 +397,14 @@ class ReactivityAnalyzer {
|
|
|
504
397
|
const nameNode = decl.getNameNode();
|
|
505
398
|
const init = decl.getInitializer();
|
|
506
399
|
if (nameNode.isKind(SyntaxKind6.ObjectBindingPattern)) {
|
|
507
|
-
|
|
508
|
-
let syntheticName;
|
|
509
|
-
const hasUnsupportedBindings = nameNode.getElements().some((el) => el.getInitializer() || el.getNameNode().isKind(SyntaxKind6.ObjectBindingPattern));
|
|
510
|
-
if (isConst && !hasUnsupportedBindings && init?.isKind(SyntaxKind6.CallExpression)) {
|
|
511
|
-
const callExpr = init.asKindOrThrow(SyntaxKind6.CallExpression);
|
|
512
|
-
const callName = callExpr.getExpression();
|
|
513
|
-
if (callName.isKind(SyntaxKind6.Identifier)) {
|
|
514
|
-
const fnName = callName.getText();
|
|
515
|
-
const originalName = importAliases.get(fnName);
|
|
516
|
-
if (originalName) {
|
|
517
|
-
signalApiConfig = getSignalApiConfig(originalName);
|
|
518
|
-
if (signalApiConfig) {
|
|
519
|
-
let counter = syntheticCounters.get(originalName) ?? 0;
|
|
520
|
-
syntheticName = `__${originalName}_${counter}`;
|
|
521
|
-
while (declaredNames.has(syntheticName)) {
|
|
522
|
-
counter++;
|
|
523
|
-
syntheticName = `__${originalName}_${counter}`;
|
|
524
|
-
}
|
|
525
|
-
syntheticCounters.set(originalName, counter + 1);
|
|
526
|
-
signalApiVars.set(syntheticName, signalApiConfig);
|
|
527
|
-
consts.set(syntheticName, {
|
|
528
|
-
start: decl.getStart(),
|
|
529
|
-
end: decl.getEnd(),
|
|
530
|
-
deps: []
|
|
531
|
-
});
|
|
532
|
-
}
|
|
533
|
-
}
|
|
534
|
-
}
|
|
535
|
-
}
|
|
400
|
+
const deps2 = init ? collectIdentifierRefs(init) : [];
|
|
536
401
|
for (const element of nameNode.getElements()) {
|
|
537
402
|
const bindingName = element.getName();
|
|
538
|
-
const
|
|
539
|
-
if (
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
const entry2 = { start: decl.getStart(), end: decl.getEnd(), deps: deps2 };
|
|
403
|
+
const entry2 = { start: decl.getStart(), end: decl.getEnd(), deps: deps2 };
|
|
404
|
+
if (isLet) {
|
|
405
|
+
lets.set(bindingName, entry2);
|
|
406
|
+
} else if (isConst) {
|
|
543
407
|
consts.set(bindingName, entry2);
|
|
544
|
-
destructuredFromMap.set(bindingName, syntheticName);
|
|
545
|
-
} else {
|
|
546
|
-
const deps2 = init ? collectIdentifierRefs(init) : [];
|
|
547
|
-
const entry2 = { start: decl.getStart(), end: decl.getEnd(), deps: deps2 };
|
|
548
|
-
if (isLet) {
|
|
549
|
-
lets.set(bindingName, entry2);
|
|
550
|
-
} else if (isConst) {
|
|
551
|
-
consts.set(bindingName, entry2);
|
|
552
|
-
}
|
|
553
408
|
}
|
|
554
409
|
}
|
|
555
410
|
continue;
|
|
@@ -562,16 +417,13 @@ class ReactivityAnalyzer {
|
|
|
562
417
|
const callName = callExpr.getExpression();
|
|
563
418
|
if (callName.isKind(SyntaxKind6.Identifier)) {
|
|
564
419
|
const fnName = callName.getText();
|
|
565
|
-
const originalName = importAliases.get(fnName);
|
|
566
|
-
if (originalName) {
|
|
420
|
+
const originalName = importAliases.get(fnName) ?? fnName;
|
|
421
|
+
if (isSignalApi(originalName)) {
|
|
567
422
|
const config = getSignalApiConfig(originalName);
|
|
568
423
|
if (config) {
|
|
569
|
-
signalApiVars.set(name, config);
|
|
424
|
+
signalApiVars.set(name, config.signalProperties);
|
|
570
425
|
}
|
|
571
426
|
}
|
|
572
|
-
if (reactiveSourceAliases.has(fnName)) {
|
|
573
|
-
reactiveSourceVars.add(name);
|
|
574
|
-
}
|
|
575
427
|
}
|
|
576
428
|
}
|
|
577
429
|
if (isLet) {
|
|
@@ -610,7 +462,7 @@ class ReactivityAnalyzer {
|
|
|
610
462
|
for (const [name, info] of consts) {
|
|
611
463
|
if (computeds.has(name))
|
|
612
464
|
continue;
|
|
613
|
-
const dependsOnReactive = info.deps.some((dep) => signals.has(dep) || computeds.has(dep)
|
|
465
|
+
const dependsOnReactive = info.deps.some((dep) => signals.has(dep) || computeds.has(dep));
|
|
614
466
|
if (dependsOnReactive) {
|
|
615
467
|
computeds.add(name);
|
|
616
468
|
changed = true;
|
|
@@ -625,11 +477,8 @@ class ReactivityAnalyzer {
|
|
|
625
477
|
start: info.start,
|
|
626
478
|
end: info.end
|
|
627
479
|
};
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
varInfo.signalProperties = apiConfig.signalProperties;
|
|
631
|
-
varInfo.plainProperties = apiConfig.plainProperties;
|
|
632
|
-
varInfo.fieldSignalProperties = apiConfig.fieldSignalProperties;
|
|
480
|
+
if (signalApiVars.has(name)) {
|
|
481
|
+
varInfo.signalProperties = signalApiVars.get(name);
|
|
633
482
|
}
|
|
634
483
|
results.push(varInfo);
|
|
635
484
|
}
|
|
@@ -640,18 +489,8 @@ class ReactivityAnalyzer {
|
|
|
640
489
|
start: info.start,
|
|
641
490
|
end: info.end
|
|
642
491
|
};
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
varInfo.signalProperties = apiConfig.signalProperties;
|
|
646
|
-
varInfo.plainProperties = apiConfig.plainProperties;
|
|
647
|
-
varInfo.fieldSignalProperties = apiConfig.fieldSignalProperties;
|
|
648
|
-
}
|
|
649
|
-
if (reactiveSourceVars.has(name)) {
|
|
650
|
-
varInfo.isReactiveSource = true;
|
|
651
|
-
}
|
|
652
|
-
const syntheticSource = destructuredFromMap.get(name);
|
|
653
|
-
if (syntheticSource) {
|
|
654
|
-
varInfo.destructuredFrom = syntheticSource;
|
|
492
|
+
if (signalApiVars.has(name)) {
|
|
493
|
+
varInfo.signalProperties = signalApiVars.get(name);
|
|
655
494
|
}
|
|
656
495
|
results.push(varInfo);
|
|
657
496
|
}
|
|
@@ -688,8 +527,7 @@ function collectIdentifierRefs(node) {
|
|
|
688
527
|
return refs;
|
|
689
528
|
}
|
|
690
529
|
function buildImportAliasMap(sourceFile) {
|
|
691
|
-
const
|
|
692
|
-
const reactiveSourceAliases = new Set;
|
|
530
|
+
const aliases = new Map;
|
|
693
531
|
for (const importDecl of sourceFile.getImportDeclarations()) {
|
|
694
532
|
const moduleSpecifier = importDecl.getModuleSpecifierValue();
|
|
695
533
|
if (moduleSpecifier !== "@vertz/ui")
|
|
@@ -697,37 +535,20 @@ function buildImportAliasMap(sourceFile) {
|
|
|
697
535
|
const namedImports = importDecl.getNamedImports();
|
|
698
536
|
for (const namedImport of namedImports) {
|
|
699
537
|
const originalName = namedImport.getName();
|
|
700
|
-
const
|
|
701
|
-
if (
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
}
|
|
707
|
-
}
|
|
708
|
-
}
|
|
709
|
-
return { signalApiAliases, reactiveSourceAliases };
|
|
710
|
-
}
|
|
711
|
-
function collectDeclaredNames(bodyNode) {
|
|
712
|
-
const names = new Set;
|
|
713
|
-
for (const stmt of bodyNode.getChildSyntaxList()?.getChildren() ?? []) {
|
|
714
|
-
if (!stmt.isKind(SyntaxKind6.VariableStatement))
|
|
715
|
-
continue;
|
|
716
|
-
const declList = stmt.getChildrenOfKind(SyntaxKind6.VariableDeclarationList)[0];
|
|
717
|
-
if (!declList)
|
|
718
|
-
continue;
|
|
719
|
-
for (const decl of declList.getDeclarations()) {
|
|
720
|
-
const nameNode = decl.getNameNode();
|
|
721
|
-
if (nameNode.isKind(SyntaxKind6.Identifier)) {
|
|
722
|
-
names.add(nameNode.getText());
|
|
538
|
+
const aliasNode = namedImport.getAliasNode();
|
|
539
|
+
if (aliasNode) {
|
|
540
|
+
const aliasName = aliasNode.getText();
|
|
541
|
+
if (isSignalApi(originalName)) {
|
|
542
|
+
aliases.set(aliasName, originalName);
|
|
543
|
+
}
|
|
723
544
|
}
|
|
724
545
|
}
|
|
725
546
|
}
|
|
726
|
-
return
|
|
547
|
+
return aliases;
|
|
727
548
|
}
|
|
728
549
|
// src/compiler.ts
|
|
729
550
|
import MagicString from "magic-string";
|
|
730
|
-
import { Project, SyntaxKind as
|
|
551
|
+
import { Project, SyntaxKind as SyntaxKind11, ts } from "ts-morph";
|
|
731
552
|
|
|
732
553
|
// src/diagnostics/mutation-diagnostics.ts
|
|
733
554
|
import { SyntaxKind as SyntaxKind7 } from "ts-morph";
|
|
@@ -838,160 +659,8 @@ class PropsDestructuringDiagnostics {
|
|
|
838
659
|
}
|
|
839
660
|
}
|
|
840
661
|
|
|
841
|
-
// src/diagnostics/ssr-safety-diagnostics.ts
|
|
842
|
-
import { SyntaxKind as SyntaxKind8 } from "ts-morph";
|
|
843
|
-
var BROWSER_ONLY_GLOBALS = new Set([
|
|
844
|
-
"localStorage",
|
|
845
|
-
"sessionStorage",
|
|
846
|
-
"navigator",
|
|
847
|
-
"IntersectionObserver",
|
|
848
|
-
"ResizeObserver",
|
|
849
|
-
"MutationObserver",
|
|
850
|
-
"requestAnimationFrame",
|
|
851
|
-
"cancelAnimationFrame",
|
|
852
|
-
"requestIdleCallback",
|
|
853
|
-
"cancelIdleCallback"
|
|
854
|
-
]);
|
|
855
|
-
var BROWSER_ONLY_DOCUMENT_PROPS = new Set([
|
|
856
|
-
"querySelector",
|
|
857
|
-
"querySelectorAll",
|
|
858
|
-
"getElementById",
|
|
859
|
-
"cookie"
|
|
860
|
-
]);
|
|
861
|
-
|
|
862
|
-
class SSRSafetyDiagnostics {
|
|
863
|
-
analyze(sourceFile, component) {
|
|
864
|
-
const bodyNode = findBodyNode(sourceFile, component);
|
|
865
|
-
if (!bodyNode)
|
|
866
|
-
return [];
|
|
867
|
-
const diagnostics = [];
|
|
868
|
-
bodyNode.forEachDescendant((node) => {
|
|
869
|
-
if (!node.isKind(SyntaxKind8.Identifier))
|
|
870
|
-
return;
|
|
871
|
-
const name = node.getText();
|
|
872
|
-
if (BROWSER_ONLY_GLOBALS.has(name)) {
|
|
873
|
-
if (isInNestedFunction(node, bodyNode))
|
|
874
|
-
return;
|
|
875
|
-
if (isInTypeofGuard(node))
|
|
876
|
-
return;
|
|
877
|
-
const pos = sourceFile.getLineAndColumnAtPos(node.getStart());
|
|
878
|
-
diagnostics.push({
|
|
879
|
-
code: "ssr-unsafe-api",
|
|
880
|
-
message: `\`${name}\` is a browser-only API that is not available during SSR. Move it inside \`onMount()\` or wrap in a \`typeof\` guard.`,
|
|
881
|
-
severity: "warning",
|
|
882
|
-
line: pos.line,
|
|
883
|
-
column: pos.column - 1,
|
|
884
|
-
fix: `Move the \`${name}\` usage inside \`onMount(() => { ... })\` or guard with \`typeof ${name} !== 'undefined'\`.`
|
|
885
|
-
});
|
|
886
|
-
return;
|
|
887
|
-
}
|
|
888
|
-
if (name === "document") {
|
|
889
|
-
const parent = node.getParent();
|
|
890
|
-
if (parent?.isKind(SyntaxKind8.PropertyAccessExpression) && parent.getExpression() === node) {
|
|
891
|
-
const propName = parent.getName();
|
|
892
|
-
if (BROWSER_ONLY_DOCUMENT_PROPS.has(propName)) {
|
|
893
|
-
if (isInNestedFunction(node, bodyNode))
|
|
894
|
-
return;
|
|
895
|
-
if (isInTypeofGuard(node))
|
|
896
|
-
return;
|
|
897
|
-
const pos = sourceFile.getLineAndColumnAtPos(node.getStart());
|
|
898
|
-
diagnostics.push({
|
|
899
|
-
code: "ssr-unsafe-api",
|
|
900
|
-
message: `\`document.${propName}\` is a browser-only API that is not available during SSR. Move it inside \`onMount()\` or wrap in a \`typeof\` guard.`,
|
|
901
|
-
severity: "warning",
|
|
902
|
-
line: pos.line,
|
|
903
|
-
column: pos.column - 1,
|
|
904
|
-
fix: `Move the \`document.${propName}\` usage inside \`onMount(() => { ... })\`.`
|
|
905
|
-
});
|
|
906
|
-
}
|
|
907
|
-
}
|
|
908
|
-
}
|
|
909
|
-
});
|
|
910
|
-
return diagnostics;
|
|
911
|
-
}
|
|
912
|
-
}
|
|
913
|
-
function isInNestedFunction(node, bodyNode) {
|
|
914
|
-
let current = node.getParent();
|
|
915
|
-
while (current && current !== bodyNode) {
|
|
916
|
-
if (current.isKind(SyntaxKind8.ArrowFunction) || current.isKind(SyntaxKind8.FunctionExpression) || current.isKind(SyntaxKind8.FunctionDeclaration) || current.isKind(SyntaxKind8.MethodDeclaration) || current.isKind(SyntaxKind8.Constructor) || current.isKind(SyntaxKind8.GetAccessor) || current.isKind(SyntaxKind8.SetAccessor)) {
|
|
917
|
-
return true;
|
|
918
|
-
}
|
|
919
|
-
current = current.getParent();
|
|
920
|
-
}
|
|
921
|
-
return false;
|
|
922
|
-
}
|
|
923
|
-
function isInTypeofGuard(node) {
|
|
924
|
-
const parent = node.getParent();
|
|
925
|
-
if (parent?.isKind(SyntaxKind8.TypeOfExpression))
|
|
926
|
-
return true;
|
|
927
|
-
const name = node.getText();
|
|
928
|
-
let current = node.getParent();
|
|
929
|
-
while (current) {
|
|
930
|
-
if (current.isKind(SyntaxKind8.IfStatement)) {
|
|
931
|
-
const condition = current.getExpression();
|
|
932
|
-
const thenStatement = current.getThenStatement();
|
|
933
|
-
if (conditionContainsTypeofFor(condition, name)) {
|
|
934
|
-
if (isDescendantOf(node, thenStatement))
|
|
935
|
-
return true;
|
|
936
|
-
}
|
|
937
|
-
if (conditionContainsTypeofFor(condition, "window")) {
|
|
938
|
-
if (isDescendantOf(node, thenStatement))
|
|
939
|
-
return true;
|
|
940
|
-
}
|
|
941
|
-
}
|
|
942
|
-
if (current.isKind(SyntaxKind8.ConditionalExpression)) {
|
|
943
|
-
const condition = current.getCondition();
|
|
944
|
-
if (conditionContainsTypeofFor(condition, name)) {
|
|
945
|
-
const whenTrue = current.getWhenTrue();
|
|
946
|
-
if (isDescendantOf(node, whenTrue))
|
|
947
|
-
return true;
|
|
948
|
-
}
|
|
949
|
-
if (conditionContainsTypeofFor(condition, "window")) {
|
|
950
|
-
const whenTrue = current.getWhenTrue();
|
|
951
|
-
if (isDescendantOf(node, whenTrue))
|
|
952
|
-
return true;
|
|
953
|
-
}
|
|
954
|
-
}
|
|
955
|
-
if (current.isKind(SyntaxKind8.BinaryExpression)) {
|
|
956
|
-
const op = current.getOperatorToken();
|
|
957
|
-
if (op.getKind() === SyntaxKind8.AmpersandAmpersandToken) {
|
|
958
|
-
const left = current.getLeft();
|
|
959
|
-
if (conditionContainsTypeofFor(left, name)) {
|
|
960
|
-
if (isDescendantOf(node, current.getRight()))
|
|
961
|
-
return true;
|
|
962
|
-
}
|
|
963
|
-
if (conditionContainsTypeofFor(left, "window")) {
|
|
964
|
-
if (isDescendantOf(node, current.getRight()))
|
|
965
|
-
return true;
|
|
966
|
-
}
|
|
967
|
-
}
|
|
968
|
-
}
|
|
969
|
-
current = current.getParent();
|
|
970
|
-
}
|
|
971
|
-
return false;
|
|
972
|
-
}
|
|
973
|
-
function conditionContainsTypeofFor(condition, name) {
|
|
974
|
-
if (condition.isKind(SyntaxKind8.TypeOfExpression)) {
|
|
975
|
-
return condition.getExpression().getText() === name;
|
|
976
|
-
}
|
|
977
|
-
for (const desc of condition.getDescendantsOfKind(SyntaxKind8.TypeOfExpression)) {
|
|
978
|
-
if (desc.getExpression().getText() === name)
|
|
979
|
-
return true;
|
|
980
|
-
}
|
|
981
|
-
return false;
|
|
982
|
-
}
|
|
983
|
-
function isDescendantOf(node, ancestor) {
|
|
984
|
-
let current = node.getParent();
|
|
985
|
-
while (current) {
|
|
986
|
-
if (current === ancestor)
|
|
987
|
-
return true;
|
|
988
|
-
current = current.getParent();
|
|
989
|
-
}
|
|
990
|
-
return false;
|
|
991
|
-
}
|
|
992
|
-
|
|
993
662
|
// src/transformers/computed-transformer.ts
|
|
994
|
-
import { SyntaxKind as
|
|
663
|
+
import { SyntaxKind as SyntaxKind8 } from "ts-morph";
|
|
995
664
|
class ComputedTransformer {
|
|
996
665
|
transform(source, sourceFile, component, variables) {
|
|
997
666
|
const computeds = new Set(variables.filter((v) => v.kind === "computed").map((v) => v.name));
|
|
@@ -1000,21 +669,11 @@ class ComputedTransformer {
|
|
|
1000
669
|
const bodyNode = findBodyNode(sourceFile, component);
|
|
1001
670
|
if (!bodyNode)
|
|
1002
671
|
return;
|
|
1003
|
-
const destructuredFromMap = new Map;
|
|
1004
|
-
const syntheticVarInfo = new Map;
|
|
1005
|
-
for (const v of variables) {
|
|
1006
|
-
if (v.destructuredFrom) {
|
|
1007
|
-
destructuredFromMap.set(v.name, v.destructuredFrom);
|
|
1008
|
-
}
|
|
1009
|
-
if (v.name.startsWith("__") && v.signalProperties) {
|
|
1010
|
-
syntheticVarInfo.set(v.name, v);
|
|
1011
|
-
}
|
|
1012
|
-
}
|
|
1013
672
|
transformComputedReads(source, bodyNode, computeds);
|
|
1014
673
|
for (const stmt of bodyNode.getChildSyntaxList()?.getChildren() ?? []) {
|
|
1015
|
-
if (!stmt.isKind(
|
|
674
|
+
if (!stmt.isKind(SyntaxKind8.VariableStatement))
|
|
1016
675
|
continue;
|
|
1017
|
-
const declList = stmt.getChildrenOfKind(
|
|
676
|
+
const declList = stmt.getChildrenOfKind(SyntaxKind8.VariableDeclarationList)[0];
|
|
1018
677
|
if (!declList)
|
|
1019
678
|
continue;
|
|
1020
679
|
for (const decl of declList.getDeclarations()) {
|
|
@@ -1022,34 +681,8 @@ class ComputedTransformer {
|
|
|
1022
681
|
const init = decl.getInitializer();
|
|
1023
682
|
if (!init)
|
|
1024
683
|
continue;
|
|
1025
|
-
if (nameNode.isKind(
|
|
684
|
+
if (nameNode.isKind(SyntaxKind8.ObjectBindingPattern)) {
|
|
1026
685
|
const elements = nameNode.getElements();
|
|
1027
|
-
const firstBindingName = elements[0]?.getName();
|
|
1028
|
-
const syntheticName = firstBindingName ? destructuredFromMap.get(firstBindingName) : undefined;
|
|
1029
|
-
if (syntheticName) {
|
|
1030
|
-
const initText = source.slice(init.getStart(), init.getEnd());
|
|
1031
|
-
const synthetic = syntheticVarInfo.get(syntheticName);
|
|
1032
|
-
const signalProps = synthetic?.signalProperties ?? new Set;
|
|
1033
|
-
const lines = [];
|
|
1034
|
-
lines.push(`const ${syntheticName} = ${initText}`);
|
|
1035
|
-
for (const el of elements) {
|
|
1036
|
-
if (el.getDotDotDotToken()) {
|
|
1037
|
-
const restName = el.getName();
|
|
1038
|
-
lines.push(`const { ...${restName} } = ${syntheticName}`);
|
|
1039
|
-
continue;
|
|
1040
|
-
}
|
|
1041
|
-
const bindingName = el.getName();
|
|
1042
|
-
const propName = el.getPropertyNameNode()?.getText() ?? bindingName;
|
|
1043
|
-
if (computeds.has(bindingName) && signalProps.has(propName)) {
|
|
1044
|
-
lines.push(`const ${bindingName} = computed(() => ${syntheticName}.${propName}.value)`);
|
|
1045
|
-
} else {
|
|
1046
|
-
lines.push(`const ${bindingName} = ${syntheticName}.${propName}`);
|
|
1047
|
-
}
|
|
1048
|
-
}
|
|
1049
|
-
source.overwrite(stmt.getStart(), stmt.getEnd(), `${lines.join(`;
|
|
1050
|
-
`)};`);
|
|
1051
|
-
continue;
|
|
1052
|
-
}
|
|
1053
686
|
const computedElements = elements.filter((el) => computeds.has(el.getName()));
|
|
1054
687
|
if (computedElements.length > 0) {
|
|
1055
688
|
const initText = source.slice(init.getStart(), init.getEnd());
|
|
@@ -1077,7 +710,7 @@ class ComputedTransformer {
|
|
|
1077
710
|
}
|
|
1078
711
|
function transformComputedReads(source, bodyNode, computeds) {
|
|
1079
712
|
bodyNode.forEachDescendant((node) => {
|
|
1080
|
-
if (!node.isKind(
|
|
713
|
+
if (!node.isKind(SyntaxKind8.Identifier))
|
|
1081
714
|
return;
|
|
1082
715
|
const name = node.getText();
|
|
1083
716
|
if (!computeds.has(name))
|
|
@@ -1085,19 +718,19 @@ function transformComputedReads(source, bodyNode, computeds) {
|
|
|
1085
718
|
const parent = node.getParent();
|
|
1086
719
|
if (!parent)
|
|
1087
720
|
return;
|
|
1088
|
-
if (parent.isKind(
|
|
721
|
+
if (parent.isKind(SyntaxKind8.VariableDeclaration) && parent.getNameNode() === node) {
|
|
1089
722
|
return;
|
|
1090
723
|
}
|
|
1091
|
-
if (parent.isKind(
|
|
724
|
+
if (parent.isKind(SyntaxKind8.PropertyAccessExpression) && parent.getNameNode() === node) {
|
|
1092
725
|
return;
|
|
1093
726
|
}
|
|
1094
|
-
if (parent.isKind(
|
|
727
|
+
if (parent.isKind(SyntaxKind8.PropertyAssignment) && parent.getNameNode() === node) {
|
|
1095
728
|
return;
|
|
1096
729
|
}
|
|
1097
|
-
if (parent.isKind(
|
|
730
|
+
if (parent.isKind(SyntaxKind8.ShorthandPropertyAssignment)) {
|
|
1098
731
|
return;
|
|
1099
732
|
}
|
|
1100
|
-
if (parent.isKind(
|
|
733
|
+
if (parent.isKind(SyntaxKind8.BindingElement)) {
|
|
1101
734
|
return;
|
|
1102
735
|
}
|
|
1103
736
|
source.overwrite(node.getStart(), node.getEnd(), `${name}.value`);
|
|
@@ -1105,7 +738,7 @@ function transformComputedReads(source, bodyNode, computeds) {
|
|
|
1105
738
|
}
|
|
1106
739
|
|
|
1107
740
|
// src/transformers/jsx-transformer.ts
|
|
1108
|
-
import { SyntaxKind as
|
|
741
|
+
import { SyntaxKind as SyntaxKind9 } from "ts-morph";
|
|
1109
742
|
var varCounter = 0;
|
|
1110
743
|
function genVar() {
|
|
1111
744
|
return `__el${varCounter++}`;
|
|
@@ -1122,73 +755,51 @@ class JsxTransformer {
|
|
|
1122
755
|
return;
|
|
1123
756
|
const reactiveNames = new Set(variables.filter((v) => v.kind === "signal" || v.kind === "computed").map((v) => v.name));
|
|
1124
757
|
const jsxMap = new Map(jsxExpressions.map((e) => [e.start, e]));
|
|
1125
|
-
|
|
1126
|
-
for (const v of variables) {
|
|
1127
|
-
if (v.fieldSignalProperties && v.fieldSignalProperties.size > 0) {
|
|
1128
|
-
formVarNames.add(v.name);
|
|
1129
|
-
}
|
|
1130
|
-
}
|
|
1131
|
-
this.transformAllJsx(bodyNode, reactiveNames, jsxMap, source, formVarNames);
|
|
758
|
+
this.transformAllJsx(bodyNode, reactiveNames, jsxMap, source);
|
|
1132
759
|
}
|
|
1133
|
-
transformAllJsx(node, reactiveNames, jsxMap, source
|
|
760
|
+
transformAllJsx(node, reactiveNames, jsxMap, source) {
|
|
1134
761
|
if (isJsxTopLevel(node)) {
|
|
1135
|
-
const transformed = transformJsxNode(node, reactiveNames, jsxMap, source
|
|
762
|
+
const transformed = transformJsxNode(node, reactiveNames, jsxMap, source);
|
|
1136
763
|
source.overwrite(node.getStart(), node.getEnd(), transformed);
|
|
1137
764
|
return;
|
|
1138
765
|
}
|
|
1139
766
|
for (const child of node.getChildren()) {
|
|
1140
|
-
this.transformAllJsx(child, reactiveNames, jsxMap, source
|
|
767
|
+
this.transformAllJsx(child, reactiveNames, jsxMap, source);
|
|
1141
768
|
}
|
|
1142
769
|
}
|
|
1143
770
|
}
|
|
1144
771
|
function isJsxTopLevel(node) {
|
|
1145
|
-
return node.isKind(
|
|
772
|
+
return node.isKind(SyntaxKind9.JsxElement) || node.isKind(SyntaxKind9.JsxSelfClosingElement) || node.isKind(SyntaxKind9.JsxFragment);
|
|
1146
773
|
}
|
|
1147
|
-
function transformJsxNode(node, reactiveNames, jsxMap, source
|
|
1148
|
-
if (node.isKind(
|
|
1149
|
-
return transformJsxNode(node.getExpression(), reactiveNames, jsxMap, source
|
|
774
|
+
function transformJsxNode(node, reactiveNames, jsxMap, source) {
|
|
775
|
+
if (node.isKind(SyntaxKind9.ParenthesizedExpression)) {
|
|
776
|
+
return transformJsxNode(node.getExpression(), reactiveNames, jsxMap, source);
|
|
1150
777
|
}
|
|
1151
|
-
if (node.isKind(
|
|
1152
|
-
return transformJsxElement(node, reactiveNames, jsxMap, source
|
|
778
|
+
if (node.isKind(SyntaxKind9.JsxElement)) {
|
|
779
|
+
return transformJsxElement(node, reactiveNames, jsxMap, source);
|
|
1153
780
|
}
|
|
1154
|
-
if (node.isKind(
|
|
1155
|
-
return transformSelfClosingElement(node, reactiveNames, jsxMap, source
|
|
781
|
+
if (node.isKind(SyntaxKind9.JsxSelfClosingElement)) {
|
|
782
|
+
return transformSelfClosingElement(node, reactiveNames, jsxMap, source);
|
|
1156
783
|
}
|
|
1157
|
-
if (node.isKind(
|
|
1158
|
-
return transformFragment(node, reactiveNames, jsxMap, source
|
|
784
|
+
if (node.isKind(SyntaxKind9.JsxFragment)) {
|
|
785
|
+
return transformFragment(node, reactiveNames, jsxMap, source);
|
|
1159
786
|
}
|
|
1160
|
-
if (node.isKind(
|
|
787
|
+
if (node.isKind(SyntaxKind9.JsxText)) {
|
|
1161
788
|
const text = node.getText().trim();
|
|
1162
789
|
if (!text)
|
|
1163
790
|
return "";
|
|
1164
|
-
return `
|
|
791
|
+
return `document.createTextNode(${JSON.stringify(text)})`;
|
|
1165
792
|
}
|
|
1166
793
|
return node.getText();
|
|
1167
794
|
}
|
|
1168
|
-
function transformJsxElement(node, reactiveNames, jsxMap, source
|
|
1169
|
-
const openingElement = node.getFirstChildByKind(
|
|
795
|
+
function transformJsxElement(node, reactiveNames, jsxMap, source) {
|
|
796
|
+
const openingElement = node.getFirstChildByKind(SyntaxKind9.JsxOpeningElement);
|
|
1170
797
|
if (!openingElement)
|
|
1171
798
|
return node.getText();
|
|
1172
799
|
const tagName = openingElement.getTagNameNode().getText();
|
|
1173
800
|
const isComponent = /^[A-Z]/.test(tagName);
|
|
1174
801
|
if (isComponent) {
|
|
1175
|
-
const
|
|
1176
|
-
let extraEntries;
|
|
1177
|
-
if (!hasExplicitChildren) {
|
|
1178
|
-
const children2 = getJsxChildren(node);
|
|
1179
|
-
const nonEmptyChildren = children2.filter((child) => {
|
|
1180
|
-
if (child.isKind(SyntaxKind10.JsxText))
|
|
1181
|
-
return !!child.getText().trim();
|
|
1182
|
-
return true;
|
|
1183
|
-
});
|
|
1184
|
-
if (nonEmptyChildren.length > 0) {
|
|
1185
|
-
const thunkCode = buildComponentChildrenThunk(nonEmptyChildren, reactiveNames, jsxMap, source, formVarNames);
|
|
1186
|
-
if (thunkCode) {
|
|
1187
|
-
extraEntries = new Map([["children", thunkCode]]);
|
|
1188
|
-
}
|
|
1189
|
-
}
|
|
1190
|
-
}
|
|
1191
|
-
const propsObj = buildPropsObject(openingElement, jsxMap, source, reactiveNames, formVarNames, extraEntries);
|
|
802
|
+
const propsObj = buildPropsObject(openingElement, jsxMap, source);
|
|
1192
803
|
return `${tagName}(${propsObj})`;
|
|
1193
804
|
}
|
|
1194
805
|
const elVar = genVar();
|
|
@@ -1196,45 +807,31 @@ function transformJsxElement(node, reactiveNames, jsxMap, source, formVarNames =
|
|
|
1196
807
|
statements.push(`const ${elVar} = __element(${JSON.stringify(tagName)})`);
|
|
1197
808
|
const attrs = openingElement.getAttributes();
|
|
1198
809
|
for (const attr of attrs) {
|
|
1199
|
-
if (!attr.isKind(
|
|
810
|
+
if (!attr.isKind(SyntaxKind9.JsxAttribute))
|
|
1200
811
|
continue;
|
|
1201
812
|
const attrStmt = processAttribute(attr, elVar, jsxMap, source);
|
|
1202
813
|
if (attrStmt)
|
|
1203
814
|
statements.push(attrStmt);
|
|
1204
815
|
}
|
|
1205
|
-
const bindStmt = tryBindElement(tagName, openingElement, elVar, formVarNames);
|
|
1206
|
-
if (bindStmt)
|
|
1207
|
-
statements.push(bindStmt);
|
|
1208
816
|
const children = getJsxChildren(node);
|
|
1209
|
-
const hasChildren = children.some((child) => {
|
|
1210
|
-
if (child.isKind(SyntaxKind10.JsxText))
|
|
1211
|
-
return !!child.getText().trim();
|
|
1212
|
-
return true;
|
|
1213
|
-
});
|
|
1214
|
-
if (hasChildren) {
|
|
1215
|
-
statements.push(`__enterChildren(${elVar})`);
|
|
1216
|
-
}
|
|
1217
817
|
for (const child of children) {
|
|
1218
|
-
const childCode = transformChild(child, reactiveNames, jsxMap, elVar, source
|
|
818
|
+
const childCode = transformChild(child, reactiveNames, jsxMap, elVar, source);
|
|
1219
819
|
if (childCode)
|
|
1220
820
|
statements.push(childCode);
|
|
1221
821
|
}
|
|
1222
|
-
if (hasChildren) {
|
|
1223
|
-
statements.push(`__exitChildren()`);
|
|
1224
|
-
}
|
|
1225
822
|
return `(() => {
|
|
1226
823
|
${statements.map((s) => ` ${s};`).join(`
|
|
1227
824
|
`)}
|
|
1228
825
|
return ${elVar};
|
|
1229
826
|
})()`;
|
|
1230
827
|
}
|
|
1231
|
-
function transformSelfClosingElement(node,
|
|
1232
|
-
if (!node.isKind(
|
|
828
|
+
function transformSelfClosingElement(node, _reactiveNames, jsxMap, source) {
|
|
829
|
+
if (!node.isKind(SyntaxKind9.JsxSelfClosingElement))
|
|
1233
830
|
return node.getText();
|
|
1234
831
|
const tagName = node.getTagNameNode().getText();
|
|
1235
832
|
const isComponent = /^[A-Z]/.test(tagName);
|
|
1236
833
|
if (isComponent) {
|
|
1237
|
-
const propsObj = buildPropsObject(node, jsxMap, source
|
|
834
|
+
const propsObj = buildPropsObject(node, jsxMap, source);
|
|
1238
835
|
return `${tagName}(${propsObj})`;
|
|
1239
836
|
}
|
|
1240
837
|
const elVar = genVar();
|
|
@@ -1242,28 +839,25 @@ function transformSelfClosingElement(node, reactiveNames, jsxMap, source, formVa
|
|
|
1242
839
|
statements.push(`const ${elVar} = __element(${JSON.stringify(tagName)})`);
|
|
1243
840
|
const attrs = node.getAttributes();
|
|
1244
841
|
for (const attr of attrs) {
|
|
1245
|
-
if (!attr.isKind(
|
|
842
|
+
if (!attr.isKind(SyntaxKind9.JsxAttribute))
|
|
1246
843
|
continue;
|
|
1247
844
|
const attrStmt = processAttribute(attr, elVar, jsxMap, source);
|
|
1248
845
|
if (attrStmt)
|
|
1249
846
|
statements.push(attrStmt);
|
|
1250
847
|
}
|
|
1251
|
-
const bindStmt = tryBindElement(tagName, node, elVar, formVarNames);
|
|
1252
|
-
if (bindStmt)
|
|
1253
|
-
statements.push(bindStmt);
|
|
1254
848
|
return `(() => {
|
|
1255
849
|
${statements.map((s) => ` ${s};`).join(`
|
|
1256
850
|
`)}
|
|
1257
851
|
return ${elVar};
|
|
1258
852
|
})()`;
|
|
1259
853
|
}
|
|
1260
|
-
function transformFragment(node, reactiveNames, jsxMap, source
|
|
854
|
+
function transformFragment(node, reactiveNames, jsxMap, source) {
|
|
1261
855
|
const fragVar = genVar();
|
|
1262
856
|
const statements = [];
|
|
1263
857
|
statements.push(`const ${fragVar} = document.createDocumentFragment()`);
|
|
1264
858
|
const children = getJsxChildren(node);
|
|
1265
859
|
for (const child of children) {
|
|
1266
|
-
const childCode = transformChild(child, reactiveNames, jsxMap, fragVar, source
|
|
860
|
+
const childCode = transformChild(child, reactiveNames, jsxMap, fragVar, source);
|
|
1267
861
|
if (childCode)
|
|
1268
862
|
statements.push(childCode);
|
|
1269
863
|
}
|
|
@@ -1274,7 +868,7 @@ ${statements.map((s) => ` ${s};`).join(`
|
|
|
1274
868
|
})()`;
|
|
1275
869
|
}
|
|
1276
870
|
function processAttribute(attr, elVar, jsxMap, source) {
|
|
1277
|
-
if (!attr.isKind(
|
|
871
|
+
if (!attr.isKind(SyntaxKind9.JsxAttribute))
|
|
1278
872
|
return null;
|
|
1279
873
|
const attrName = attr.getNameNode().getText();
|
|
1280
874
|
const init = attr.getInitializer();
|
|
@@ -1282,35 +876,35 @@ function processAttribute(attr, elVar, jsxMap, source) {
|
|
|
1282
876
|
return null;
|
|
1283
877
|
if (attrName.startsWith("on") && attrName.length > 2) {
|
|
1284
878
|
const eventName = attrName[2]?.toLowerCase() + attrName.slice(3);
|
|
1285
|
-
if (init.isKind(
|
|
879
|
+
if (init.isKind(SyntaxKind9.JsxExpression)) {
|
|
1286
880
|
const exprNode = init.getExpression();
|
|
1287
881
|
const handlerText = exprNode ? source.slice(exprNode.getStart(), exprNode.getEnd()) : "";
|
|
1288
882
|
return `__on(${elVar}, ${JSON.stringify(eventName)}, ${handlerText})`;
|
|
1289
883
|
}
|
|
1290
884
|
return null;
|
|
1291
885
|
}
|
|
1292
|
-
if (init.isKind(
|
|
886
|
+
if (init.isKind(SyntaxKind9.StringLiteral)) {
|
|
1293
887
|
return `${elVar}.setAttribute(${JSON.stringify(attrName)}, ${init.getText()})`;
|
|
1294
888
|
}
|
|
1295
|
-
if (init.isKind(
|
|
889
|
+
if (init.isKind(SyntaxKind9.JsxExpression)) {
|
|
1296
890
|
const exprInfo = jsxMap.get(init.getStart());
|
|
1297
891
|
const exprNode = init.getExpression();
|
|
1298
892
|
const exprText = exprNode ? source.slice(exprNode.getStart(), exprNode.getEnd()) : "";
|
|
1299
893
|
if (exprInfo?.reactive) {
|
|
1300
894
|
return `__attr(${elVar}, ${JSON.stringify(attrName)}, () => ${exprText})`;
|
|
1301
895
|
}
|
|
1302
|
-
return
|
|
896
|
+
return `${elVar}.setAttribute(${JSON.stringify(attrName)}, ${exprText})`;
|
|
1303
897
|
}
|
|
1304
898
|
return null;
|
|
1305
899
|
}
|
|
1306
|
-
function transformChild(child, reactiveNames, jsxMap, parentVar, source
|
|
1307
|
-
if (child.isKind(
|
|
900
|
+
function transformChild(child, reactiveNames, jsxMap, parentVar, source) {
|
|
901
|
+
if (child.isKind(SyntaxKind9.JsxText)) {
|
|
1308
902
|
const text = child.getText().trim();
|
|
1309
903
|
if (!text)
|
|
1310
904
|
return null;
|
|
1311
|
-
return
|
|
905
|
+
return `${parentVar}.appendChild(document.createTextNode(${JSON.stringify(text)}))`;
|
|
1312
906
|
}
|
|
1313
|
-
if (child.isKind(
|
|
907
|
+
if (child.isKind(SyntaxKind9.JsxExpression)) {
|
|
1314
908
|
const exprInfo = jsxMap.get(child.getStart());
|
|
1315
909
|
const exprNode = child.getExpression();
|
|
1316
910
|
if (!exprNode)
|
|
@@ -1318,7 +912,7 @@ function transformChild(child, reactiveNames, jsxMap, parentVar, source, formVar
|
|
|
1318
912
|
if (exprInfo?.reactive) {
|
|
1319
913
|
const conditionalCode = tryTransformConditional(exprNode, reactiveNames, jsxMap, source);
|
|
1320
914
|
if (conditionalCode) {
|
|
1321
|
-
return
|
|
915
|
+
return `${parentVar}.appendChild(${conditionalCode})`;
|
|
1322
916
|
}
|
|
1323
917
|
const listCode = tryTransformList(exprNode, reactiveNames, jsxMap, parentVar, source);
|
|
1324
918
|
if (listCode) {
|
|
@@ -1327,60 +921,18 @@ function transformChild(child, reactiveNames, jsxMap, parentVar, source, formVar
|
|
|
1327
921
|
}
|
|
1328
922
|
const exprText = source.slice(exprNode.getStart(), exprNode.getEnd());
|
|
1329
923
|
if (exprInfo?.reactive) {
|
|
1330
|
-
return
|
|
924
|
+
return `${parentVar}.appendChild(__child(() => ${exprText}))`;
|
|
1331
925
|
}
|
|
1332
926
|
return `__insert(${parentVar}, ${exprText})`;
|
|
1333
927
|
}
|
|
1334
|
-
if (child.isKind(
|
|
1335
|
-
const childCode = transformJsxNode(child, reactiveNames, jsxMap, source
|
|
1336
|
-
return
|
|
1337
|
-
}
|
|
1338
|
-
return null;
|
|
1339
|
-
}
|
|
1340
|
-
function transformChildAsValue(child, reactiveNames, jsxMap, source, formVarNames = new Set) {
|
|
1341
|
-
if (child.isKind(SyntaxKind10.JsxText)) {
|
|
1342
|
-
const text = child.getText().trim();
|
|
1343
|
-
if (!text)
|
|
1344
|
-
return null;
|
|
1345
|
-
return `__staticText(${JSON.stringify(text)})`;
|
|
1346
|
-
}
|
|
1347
|
-
if (child.isKind(SyntaxKind10.JsxExpression)) {
|
|
1348
|
-
const exprInfo = jsxMap.get(child.getStart());
|
|
1349
|
-
const exprNode = child.getExpression();
|
|
1350
|
-
if (!exprNode)
|
|
1351
|
-
return null;
|
|
1352
|
-
if (exprInfo?.reactive) {
|
|
1353
|
-
const conditionalCode = tryTransformConditional(exprNode, reactiveNames, jsxMap, source);
|
|
1354
|
-
if (conditionalCode) {
|
|
1355
|
-
return conditionalCode;
|
|
1356
|
-
}
|
|
1357
|
-
}
|
|
1358
|
-
const exprText = source.slice(exprNode.getStart(), exprNode.getEnd());
|
|
1359
|
-
if (exprInfo?.reactive) {
|
|
1360
|
-
return `__child(() => ${exprText})`;
|
|
1361
|
-
}
|
|
1362
|
-
return exprText;
|
|
1363
|
-
}
|
|
1364
|
-
if (child.isKind(SyntaxKind10.JsxElement) || child.isKind(SyntaxKind10.JsxSelfClosingElement) || child.isKind(SyntaxKind10.JsxFragment)) {
|
|
1365
|
-
return transformJsxNode(child, reactiveNames, jsxMap, source, formVarNames);
|
|
928
|
+
if (child.isKind(SyntaxKind9.JsxElement) || child.isKind(SyntaxKind9.JsxSelfClosingElement)) {
|
|
929
|
+
const childCode = transformJsxNode(child, reactiveNames, jsxMap, source);
|
|
930
|
+
return `${parentVar}.appendChild(${childCode})`;
|
|
1366
931
|
}
|
|
1367
932
|
return null;
|
|
1368
933
|
}
|
|
1369
|
-
function buildComponentChildrenThunk(children, reactiveNames, jsxMap, source, formVarNames) {
|
|
1370
|
-
const values = [];
|
|
1371
|
-
for (const child of children) {
|
|
1372
|
-
const value = transformChildAsValue(child, reactiveNames, jsxMap, source, formVarNames);
|
|
1373
|
-
if (value)
|
|
1374
|
-
values.push(value);
|
|
1375
|
-
}
|
|
1376
|
-
if (values.length === 0)
|
|
1377
|
-
return "";
|
|
1378
|
-
if (values.length === 1)
|
|
1379
|
-
return `() => ${values[0]}`;
|
|
1380
|
-
return `() => [${values.join(", ")}]`;
|
|
1381
|
-
}
|
|
1382
934
|
function tryTransformConditional(exprNode, reactiveNames, jsxMap, source) {
|
|
1383
|
-
if (exprNode.isKind(
|
|
935
|
+
if (exprNode.isKind(SyntaxKind9.ConditionalExpression)) {
|
|
1384
936
|
const condition = exprNode.getCondition();
|
|
1385
937
|
const whenTrue = exprNode.getWhenTrue();
|
|
1386
938
|
const whenFalse = exprNode.getWhenFalse();
|
|
@@ -1389,7 +941,7 @@ function tryTransformConditional(exprNode, reactiveNames, jsxMap, source) {
|
|
|
1389
941
|
const falseBranch = transformBranch(whenFalse, reactiveNames, jsxMap, source);
|
|
1390
942
|
return `__conditional(() => ${condText}, () => ${trueBranch}, () => ${falseBranch})`;
|
|
1391
943
|
}
|
|
1392
|
-
if (exprNode.isKind(
|
|
944
|
+
if (exprNode.isKind(SyntaxKind9.BinaryExpression) && exprNode.getOperatorToken().getKind() === SyntaxKind9.AmpersandAmpersandToken) {
|
|
1393
945
|
const left = exprNode.getLeft();
|
|
1394
946
|
const right = exprNode.getRight();
|
|
1395
947
|
const condText = source.slice(left.getStart(), left.getEnd());
|
|
@@ -1399,13 +951,13 @@ function tryTransformConditional(exprNode, reactiveNames, jsxMap, source) {
|
|
|
1399
951
|
return null;
|
|
1400
952
|
}
|
|
1401
953
|
function transformBranch(node, reactiveNames, jsxMap, source) {
|
|
1402
|
-
if (node.isKind(
|
|
954
|
+
if (node.isKind(SyntaxKind9.ParenthesizedExpression)) {
|
|
1403
955
|
return transformBranch(node.getExpression(), reactiveNames, jsxMap, source);
|
|
1404
956
|
}
|
|
1405
|
-
if (node.isKind(
|
|
957
|
+
if (node.isKind(SyntaxKind9.JsxElement) || node.isKind(SyntaxKind9.JsxSelfClosingElement) || node.isKind(SyntaxKind9.JsxFragment)) {
|
|
1406
958
|
return transformJsxNode(node, reactiveNames, jsxMap, source);
|
|
1407
959
|
}
|
|
1408
|
-
if (node.isKind(
|
|
960
|
+
if (node.isKind(SyntaxKind9.ConditionalExpression)) {
|
|
1409
961
|
const nested = tryTransformConditional(node, reactiveNames, jsxMap, source);
|
|
1410
962
|
if (nested)
|
|
1411
963
|
return nested;
|
|
@@ -1413,10 +965,10 @@ function transformBranch(node, reactiveNames, jsxMap, source) {
|
|
|
1413
965
|
return source.slice(node.getStart(), node.getEnd());
|
|
1414
966
|
}
|
|
1415
967
|
function tryTransformList(exprNode, reactiveNames, jsxMap, parentVar, source) {
|
|
1416
|
-
if (!exprNode.isKind(
|
|
968
|
+
if (!exprNode.isKind(SyntaxKind9.CallExpression))
|
|
1417
969
|
return null;
|
|
1418
970
|
const propAccess = exprNode.getExpression();
|
|
1419
|
-
if (!propAccess.isKind(
|
|
971
|
+
if (!propAccess.isKind(SyntaxKind9.PropertyAccessExpression))
|
|
1420
972
|
return null;
|
|
1421
973
|
const methodName = propAccess.getNameNode().getText();
|
|
1422
974
|
if (methodName !== "map")
|
|
@@ -1432,7 +984,7 @@ function tryTransformList(exprNode, reactiveNames, jsxMap, parentVar, source) {
|
|
|
1432
984
|
let itemParam = null;
|
|
1433
985
|
let indexParam = null;
|
|
1434
986
|
let callbackBody = null;
|
|
1435
|
-
if (callbackArg.isKind(
|
|
987
|
+
if (callbackArg.isKind(SyntaxKind9.ArrowFunction)) {
|
|
1436
988
|
const params = callbackArg.getParameters();
|
|
1437
989
|
itemParam = params[0]?.getName() ?? null;
|
|
1438
990
|
indexParam = params[1]?.getName() ?? null;
|
|
@@ -1459,36 +1011,36 @@ function extractKeyFunction(callbackBody, itemParam, indexParam) {
|
|
|
1459
1011
|
return `(_item, __i) => __i`;
|
|
1460
1012
|
}
|
|
1461
1013
|
function findJsxInBody(node) {
|
|
1462
|
-
if (node.isKind(
|
|
1014
|
+
if (node.isKind(SyntaxKind9.JsxElement) || node.isKind(SyntaxKind9.JsxSelfClosingElement)) {
|
|
1463
1015
|
return node;
|
|
1464
1016
|
}
|
|
1465
|
-
if (node.isKind(
|
|
1466
|
-
const returnStmt = node.getFirstDescendantByKind(
|
|
1017
|
+
if (node.isKind(SyntaxKind9.Block)) {
|
|
1018
|
+
const returnStmt = node.getFirstDescendantByKind(SyntaxKind9.ReturnStatement);
|
|
1467
1019
|
if (returnStmt) {
|
|
1468
1020
|
const expr = returnStmt.getExpression();
|
|
1469
1021
|
if (expr)
|
|
1470
1022
|
return findJsxInBody(expr);
|
|
1471
1023
|
}
|
|
1472
1024
|
}
|
|
1473
|
-
if (node.isKind(
|
|
1025
|
+
if (node.isKind(SyntaxKind9.ParenthesizedExpression)) {
|
|
1474
1026
|
return findJsxInBody(node.getExpression());
|
|
1475
1027
|
}
|
|
1476
1028
|
return null;
|
|
1477
1029
|
}
|
|
1478
1030
|
function extractKeyPropValue(jsxNode) {
|
|
1479
|
-
const attrs = jsxNode.getDescendantsOfKind(
|
|
1031
|
+
const attrs = jsxNode.getDescendantsOfKind(SyntaxKind9.JsxAttribute);
|
|
1480
1032
|
for (const attr of attrs) {
|
|
1481
1033
|
if (attr.getNameNode().getText() !== "key")
|
|
1482
1034
|
continue;
|
|
1483
1035
|
const init = attr.getInitializer();
|
|
1484
1036
|
if (!init)
|
|
1485
1037
|
continue;
|
|
1486
|
-
if (init.isKind(
|
|
1038
|
+
if (init.isKind(SyntaxKind9.JsxExpression)) {
|
|
1487
1039
|
const expr = init.getExpression();
|
|
1488
1040
|
if (expr)
|
|
1489
1041
|
return expr.getText();
|
|
1490
1042
|
}
|
|
1491
|
-
if (init.isKind(
|
|
1043
|
+
if (init.isKind(SyntaxKind9.StringLiteral)) {
|
|
1492
1044
|
return init.getText();
|
|
1493
1045
|
}
|
|
1494
1046
|
}
|
|
@@ -1503,38 +1055,9 @@ function buildListRenderFunction(callbackBody, itemParam, reactiveNames, jsxMap,
|
|
|
1503
1055
|
const bodyText = source.slice(callbackBody.getStart(), callbackBody.getEnd());
|
|
1504
1056
|
return `(${itemParam}) => ${bodyText}`;
|
|
1505
1057
|
}
|
|
1506
|
-
function
|
|
1507
|
-
const
|
|
1508
|
-
|
|
1509
|
-
const jsxNodes = [];
|
|
1510
|
-
collectJsxInExpression(node, reactiveNames, jsxMap, source, formVarNames, jsxNodes);
|
|
1511
|
-
if (jsxNodes.length === 0) {
|
|
1512
|
-
return source.slice(start, end);
|
|
1513
|
-
}
|
|
1514
|
-
jsxNodes.sort((a, b) => a.start - b.start);
|
|
1515
|
-
let result = "";
|
|
1516
|
-
let cursor = start;
|
|
1517
|
-
for (const jsx of jsxNodes) {
|
|
1518
|
-
result += source.slice(cursor, jsx.start);
|
|
1519
|
-
result += jsx.transformed;
|
|
1520
|
-
cursor = jsx.end;
|
|
1521
|
-
}
|
|
1522
|
-
result += source.slice(cursor, end);
|
|
1523
|
-
return result;
|
|
1524
|
-
}
|
|
1525
|
-
function collectJsxInExpression(node, reactiveNames, jsxMap, source, formVarNames, results) {
|
|
1526
|
-
if (isJsxTopLevel(node)) {
|
|
1527
|
-
const transformed = transformJsxNode(node, reactiveNames, jsxMap, source, formVarNames);
|
|
1528
|
-
results.push({ start: node.getStart(), end: node.getEnd(), transformed });
|
|
1529
|
-
return;
|
|
1530
|
-
}
|
|
1531
|
-
for (const child of node.getChildren()) {
|
|
1532
|
-
collectJsxInExpression(child, reactiveNames, jsxMap, source, formVarNames, results);
|
|
1533
|
-
}
|
|
1534
|
-
}
|
|
1535
|
-
function buildPropsObject(element, jsxMap, source, reactiveNames, formVarNames, extraEntries) {
|
|
1536
|
-
const attrs = element.isKind(SyntaxKind10.JsxOpeningElement) || element.isKind(SyntaxKind10.JsxSelfClosingElement) ? element.getAttributes().filter((a) => a.isKind(SyntaxKind10.JsxAttribute)) : element.getDescendantsOfKind(SyntaxKind10.JsxAttribute);
|
|
1537
|
-
if (attrs.length === 0 && (!extraEntries || extraEntries.size === 0))
|
|
1058
|
+
function buildPropsObject(element, jsxMap, source) {
|
|
1059
|
+
const attrs = element.getDescendantsOfKind(SyntaxKind9.JsxAttribute);
|
|
1060
|
+
if (attrs.length === 0)
|
|
1538
1061
|
return "{}";
|
|
1539
1062
|
const props = [];
|
|
1540
1063
|
for (const attr of attrs) {
|
|
@@ -1544,14 +1067,14 @@ function buildPropsObject(element, jsxMap, source, reactiveNames, formVarNames,
|
|
|
1544
1067
|
props.push(`${name}: true`);
|
|
1545
1068
|
continue;
|
|
1546
1069
|
}
|
|
1547
|
-
if (init.isKind(
|
|
1070
|
+
if (init.isKind(SyntaxKind9.StringLiteral)) {
|
|
1548
1071
|
props.push(`${name}: ${init.getText()}`);
|
|
1549
1072
|
continue;
|
|
1550
1073
|
}
|
|
1551
|
-
if (init.isKind(
|
|
1074
|
+
if (init.isKind(SyntaxKind9.JsxExpression)) {
|
|
1552
1075
|
const exprInfo = jsxMap.get(init.getStart());
|
|
1553
1076
|
const exprNode = init.getExpression();
|
|
1554
|
-
const exprText = exprNode ?
|
|
1077
|
+
const exprText = exprNode ? source.slice(exprNode.getStart(), exprNode.getEnd()) : "";
|
|
1555
1078
|
if (exprInfo?.reactive) {
|
|
1556
1079
|
props.push(`get ${name}() { return ${exprText}; }`);
|
|
1557
1080
|
} else {
|
|
@@ -1559,11 +1082,6 @@ function buildPropsObject(element, jsxMap, source, reactiveNames, formVarNames,
|
|
|
1559
1082
|
}
|
|
1560
1083
|
}
|
|
1561
1084
|
}
|
|
1562
|
-
if (extraEntries) {
|
|
1563
|
-
for (const [key, value] of extraEntries) {
|
|
1564
|
-
props.push(`${key}: ${value}`);
|
|
1565
|
-
}
|
|
1566
|
-
}
|
|
1567
1085
|
return `{ ${props.join(", ")} }`;
|
|
1568
1086
|
}
|
|
1569
1087
|
function getJsxChildren(node) {
|
|
@@ -1571,7 +1089,7 @@ function getJsxChildren(node) {
|
|
|
1571
1089
|
for (const child of node.getChildren()) {
|
|
1572
1090
|
if (isJsxChild(child)) {
|
|
1573
1091
|
children.push(child);
|
|
1574
|
-
} else if (child.isKind(
|
|
1092
|
+
} else if (child.isKind(SyntaxKind9.SyntaxList)) {
|
|
1575
1093
|
for (const grandchild of child.getChildren()) {
|
|
1576
1094
|
if (isJsxChild(grandchild)) {
|
|
1577
1095
|
children.push(grandchild);
|
|
@@ -1582,30 +1100,7 @@ function getJsxChildren(node) {
|
|
|
1582
1100
|
return children;
|
|
1583
1101
|
}
|
|
1584
1102
|
function isJsxChild(node) {
|
|
1585
|
-
return node.isKind(
|
|
1586
|
-
}
|
|
1587
|
-
function tryBindElement(tagName, element, elVar, formVarNames) {
|
|
1588
|
-
if (tagName !== "form" || formVarNames.size === 0)
|
|
1589
|
-
return null;
|
|
1590
|
-
const attrs = element.getDescendantsOfKind(SyntaxKind10.JsxAttribute);
|
|
1591
|
-
for (const attr of attrs) {
|
|
1592
|
-
if (attr.getNameNode().getText() !== "onSubmit")
|
|
1593
|
-
continue;
|
|
1594
|
-
const init = attr.getInitializer();
|
|
1595
|
-
if (!init?.isKind(SyntaxKind10.JsxExpression))
|
|
1596
|
-
continue;
|
|
1597
|
-
const exprNode = init.getExpression();
|
|
1598
|
-
if (!exprNode?.isKind(SyntaxKind10.PropertyAccessExpression))
|
|
1599
|
-
continue;
|
|
1600
|
-
const obj = exprNode.getExpression();
|
|
1601
|
-
if (!obj.isKind(SyntaxKind10.Identifier))
|
|
1602
|
-
continue;
|
|
1603
|
-
const varName = obj.getText();
|
|
1604
|
-
if (formVarNames.has(varName)) {
|
|
1605
|
-
return `${varName}.__bindElement(${elVar})`;
|
|
1606
|
-
}
|
|
1607
|
-
}
|
|
1608
|
-
return null;
|
|
1103
|
+
return node.isKind(SyntaxKind9.JsxText) || node.isKind(SyntaxKind9.JsxExpression) || node.isKind(SyntaxKind9.JsxElement) || node.isKind(SyntaxKind9.JsxSelfClosingElement);
|
|
1609
1104
|
}
|
|
1610
1105
|
|
|
1611
1106
|
// src/transformers/mutation-transformer.ts
|
|
@@ -1671,23 +1166,15 @@ class MutationTransformer {
|
|
|
1671
1166
|
}
|
|
1672
1167
|
|
|
1673
1168
|
// src/transformers/signal-transformer.ts
|
|
1674
|
-
import { SyntaxKind as
|
|
1169
|
+
import { SyntaxKind as SyntaxKind10 } from "ts-morph";
|
|
1675
1170
|
class SignalTransformer {
|
|
1676
1171
|
transform(source, sourceFile, component, variables, mutationRanges = []) {
|
|
1677
1172
|
const signals = new Set(variables.filter((v) => v.kind === "signal").map((v) => v.name));
|
|
1678
1173
|
const signalApiVars = new Map;
|
|
1679
|
-
const plainPropVars = new Map;
|
|
1680
|
-
const fieldSignalPropVars = new Map;
|
|
1681
1174
|
for (const v of variables) {
|
|
1682
1175
|
if (v.signalProperties && v.signalProperties.size > 0) {
|
|
1683
1176
|
signalApiVars.set(v.name, v.signalProperties);
|
|
1684
1177
|
}
|
|
1685
|
-
if (v.plainProperties && v.plainProperties.size > 0) {
|
|
1686
|
-
plainPropVars.set(v.name, v.plainProperties);
|
|
1687
|
-
}
|
|
1688
|
-
if (v.fieldSignalProperties && v.fieldSignalProperties.size > 0) {
|
|
1689
|
-
fieldSignalPropVars.set(v.name, v.fieldSignalProperties);
|
|
1690
|
-
}
|
|
1691
1178
|
}
|
|
1692
1179
|
const bodyNode = findBodyNode(sourceFile, component);
|
|
1693
1180
|
if (!bodyNode)
|
|
@@ -1696,16 +1183,16 @@ class SignalTransformer {
|
|
|
1696
1183
|
transformDeclarations(source, bodyNode, signals);
|
|
1697
1184
|
transformReferences(source, bodyNode, signals, mutationRanges);
|
|
1698
1185
|
}
|
|
1699
|
-
if (signalApiVars.size > 0
|
|
1700
|
-
transformSignalApiProperties(source, bodyNode, signalApiVars
|
|
1186
|
+
if (signalApiVars.size > 0) {
|
|
1187
|
+
transformSignalApiProperties(source, bodyNode, signalApiVars);
|
|
1701
1188
|
}
|
|
1702
1189
|
}
|
|
1703
1190
|
}
|
|
1704
1191
|
function transformDeclarations(source, bodyNode, signals) {
|
|
1705
1192
|
for (const stmt of bodyNode.getChildSyntaxList()?.getChildren() ?? []) {
|
|
1706
|
-
if (!stmt.isKind(
|
|
1193
|
+
if (!stmt.isKind(SyntaxKind10.VariableStatement))
|
|
1707
1194
|
continue;
|
|
1708
|
-
const declList = stmt.getChildrenOfKind(
|
|
1195
|
+
const declList = stmt.getChildrenOfKind(SyntaxKind10.VariableDeclarationList)[0];
|
|
1709
1196
|
if (!declList)
|
|
1710
1197
|
continue;
|
|
1711
1198
|
for (const decl of declList.getDeclarations()) {
|
|
@@ -1715,7 +1202,7 @@ function transformDeclarations(source, bodyNode, signals) {
|
|
|
1715
1202
|
const init = decl.getInitializer();
|
|
1716
1203
|
if (!init)
|
|
1717
1204
|
continue;
|
|
1718
|
-
const letKeyword = declList.getFirstChildByKind(
|
|
1205
|
+
const letKeyword = declList.getFirstChildByKind(SyntaxKind10.LetKeyword);
|
|
1719
1206
|
if (letKeyword) {
|
|
1720
1207
|
source.overwrite(letKeyword.getStart(), letKeyword.getEnd(), "const");
|
|
1721
1208
|
}
|
|
@@ -1729,7 +1216,7 @@ function isInsideMutationRange(pos, ranges) {
|
|
|
1729
1216
|
}
|
|
1730
1217
|
function transformReferences(source, bodyNode, signals, mutationRanges) {
|
|
1731
1218
|
bodyNode.forEachDescendant((node) => {
|
|
1732
|
-
if (!node.isKind(
|
|
1219
|
+
if (!node.isKind(SyntaxKind10.Identifier))
|
|
1733
1220
|
return;
|
|
1734
1221
|
const name = node.getText();
|
|
1735
1222
|
if (!signals.has(name))
|
|
@@ -1737,19 +1224,16 @@ function transformReferences(source, bodyNode, signals, mutationRanges) {
|
|
|
1737
1224
|
const parent = node.getParent();
|
|
1738
1225
|
if (!parent)
|
|
1739
1226
|
return;
|
|
1740
|
-
if (parent.isKind(
|
|
1741
|
-
return;
|
|
1742
|
-
}
|
|
1743
|
-
if (parent.isKind(SyntaxKind11.PropertyAccessExpression) && parent.getNameNode() === node) {
|
|
1227
|
+
if (parent.isKind(SyntaxKind10.VariableDeclaration) && parent.getNameNode() === node) {
|
|
1744
1228
|
return;
|
|
1745
1229
|
}
|
|
1746
|
-
if (parent.isKind(
|
|
1230
|
+
if (parent.isKind(SyntaxKind10.PropertyAccessExpression) && parent.getNameNode() === node) {
|
|
1747
1231
|
return;
|
|
1748
1232
|
}
|
|
1749
|
-
if (parent.isKind(
|
|
1233
|
+
if (parent.isKind(SyntaxKind10.PropertyAssignment) && parent.getNameNode() === node) {
|
|
1750
1234
|
return;
|
|
1751
1235
|
}
|
|
1752
|
-
if (parent.isKind(
|
|
1236
|
+
if (parent.isKind(SyntaxKind10.ShorthandPropertyAssignment)) {
|
|
1753
1237
|
return;
|
|
1754
1238
|
}
|
|
1755
1239
|
if (isInsideMutationRange(node.getStart(), mutationRanges)) {
|
|
@@ -1758,72 +1242,32 @@ function transformReferences(source, bodyNode, signals, mutationRanges) {
|
|
|
1758
1242
|
source.overwrite(node.getStart(), node.getEnd(), `${name}.value`);
|
|
1759
1243
|
});
|
|
1760
1244
|
}
|
|
1761
|
-
function transformSignalApiProperties(source, bodyNode, signalApiVars
|
|
1762
|
-
const threeLevelRanges = [];
|
|
1763
|
-
bodyNode.forEachDescendant((node) => {
|
|
1764
|
-
if (!node.isKind(SyntaxKind11.PropertyAccessExpression))
|
|
1765
|
-
return;
|
|
1766
|
-
const outerExpr = node.asKindOrThrow(SyntaxKind11.PropertyAccessExpression);
|
|
1767
|
-
const middleExpr = outerExpr.getExpression();
|
|
1768
|
-
const leafProp = outerExpr.getName();
|
|
1769
|
-
if (!middleExpr.isKind(SyntaxKind11.PropertyAccessExpression))
|
|
1770
|
-
return;
|
|
1771
|
-
const innerExpr = middleExpr.asKindOrThrow(SyntaxKind11.PropertyAccessExpression);
|
|
1772
|
-
const rootExpr = innerExpr.getExpression();
|
|
1773
|
-
const middleProp = innerExpr.getName();
|
|
1774
|
-
if (!rootExpr.isKind(SyntaxKind11.Identifier))
|
|
1775
|
-
return;
|
|
1776
|
-
const rootName = rootExpr.getText();
|
|
1777
|
-
const fieldSignalProps = fieldSignalPropVars.get(rootName);
|
|
1778
|
-
if (!fieldSignalProps)
|
|
1779
|
-
return;
|
|
1780
|
-
const signalProps = signalApiVars.get(rootName);
|
|
1781
|
-
const plainProps = plainPropVars.get(rootName);
|
|
1782
|
-
if (signalProps?.has(middleProp) || plainProps?.has(middleProp))
|
|
1783
|
-
return;
|
|
1784
|
-
if (!fieldSignalProps.has(leafProp))
|
|
1785
|
-
return;
|
|
1786
|
-
const parent = outerExpr.getParent();
|
|
1787
|
-
if (parent?.isKind(SyntaxKind11.PropertyAccessExpression)) {
|
|
1788
|
-
const parentProp = parent.asKindOrThrow(SyntaxKind11.PropertyAccessExpression);
|
|
1789
|
-
if (parentProp.getExpression() === outerExpr && parentProp.getName() === "value") {
|
|
1790
|
-
threeLevelRanges.push({ start: outerExpr.getStart(), end: outerExpr.getEnd() });
|
|
1791
|
-
return;
|
|
1792
|
-
}
|
|
1793
|
-
}
|
|
1794
|
-
source.appendLeft(outerExpr.getEnd(), ".value");
|
|
1795
|
-
threeLevelRanges.push({ start: outerExpr.getStart(), end: outerExpr.getEnd() });
|
|
1796
|
-
});
|
|
1245
|
+
function transformSignalApiProperties(source, bodyNode, signalApiVars) {
|
|
1797
1246
|
bodyNode.forEachDescendant((node) => {
|
|
1798
|
-
if (!node.isKind(
|
|
1799
|
-
return;
|
|
1800
|
-
const expr = node.asKindOrThrow(SyntaxKind11.PropertyAccessExpression);
|
|
1801
|
-
const nodeStart = expr.getStart();
|
|
1802
|
-
if (threeLevelRanges.some((r) => nodeStart >= r.start && nodeStart < r.end))
|
|
1247
|
+
if (!node.isKind(SyntaxKind10.PropertyAccessExpression))
|
|
1803
1248
|
return;
|
|
1249
|
+
const expr = node.asKindOrThrow(SyntaxKind10.PropertyAccessExpression);
|
|
1804
1250
|
const objExpr = expr.getExpression();
|
|
1805
1251
|
const propName = expr.getName();
|
|
1806
|
-
if (!objExpr.isKind(
|
|
1252
|
+
if (!objExpr.isKind(SyntaxKind10.Identifier))
|
|
1807
1253
|
return;
|
|
1808
1254
|
const varName = objExpr.getText();
|
|
1809
1255
|
const signalProps = signalApiVars.get(varName);
|
|
1810
1256
|
if (!signalProps || !signalProps.has(propName))
|
|
1811
1257
|
return;
|
|
1812
1258
|
const parent = expr.getParent();
|
|
1813
|
-
if (parent?.isKind(
|
|
1814
|
-
const parentProp = parent.asKindOrThrow(
|
|
1259
|
+
if (parent?.isKind(SyntaxKind10.PropertyAccessExpression)) {
|
|
1260
|
+
const parentProp = parent.asKindOrThrow(SyntaxKind10.PropertyAccessExpression);
|
|
1815
1261
|
if (parentProp.getExpression() === expr && parentProp.getName() === "value") {
|
|
1816
1262
|
return;
|
|
1817
1263
|
}
|
|
1818
1264
|
}
|
|
1819
|
-
source.
|
|
1265
|
+
source.appendRight(expr.getEnd(), ".value");
|
|
1820
1266
|
});
|
|
1821
1267
|
}
|
|
1822
1268
|
|
|
1823
1269
|
// src/compiler.ts
|
|
1824
|
-
function compile(source,
|
|
1825
|
-
const options = typeof optionsOrFilename === "string" ? { filename: optionsOrFilename } : optionsOrFilename ?? {};
|
|
1826
|
-
const filename = options.filename ?? "input.tsx";
|
|
1270
|
+
function compile(source, filename = "input.tsx") {
|
|
1827
1271
|
const project = new Project({
|
|
1828
1272
|
useInMemoryFileSystem: true,
|
|
1829
1273
|
compilerOptions: {
|
|
@@ -1874,7 +1318,7 @@ function compile(source, optionsOrFilename) {
|
|
|
1874
1318
|
usedFeatures.add("__text");
|
|
1875
1319
|
usedFeatures.add("__attr");
|
|
1876
1320
|
}
|
|
1877
|
-
const hasEvents = sourceFile.getDescendantsOfKind(
|
|
1321
|
+
const hasEvents = sourceFile.getDescendantsOfKind(SyntaxKind11.JsxAttribute).some((attr) => {
|
|
1878
1322
|
const name = attr.getNameNode().getText();
|
|
1879
1323
|
return name.startsWith("on") && name.length > 2;
|
|
1880
1324
|
});
|
|
@@ -1885,14 +1329,11 @@ function compile(source, optionsOrFilename) {
|
|
|
1885
1329
|
jsxTransformer.transform(s, sourceFile, component, variables, jsxExpressions);
|
|
1886
1330
|
const mutationDiags = new MutationDiagnostics;
|
|
1887
1331
|
allDiagnostics.push(...mutationDiags.analyze(sourceFile, component, variables));
|
|
1888
|
-
const ssrDiags = new SSRSafetyDiagnostics;
|
|
1889
|
-
allDiagnostics.push(...ssrDiags.analyze(sourceFile, component));
|
|
1890
1332
|
}
|
|
1891
1333
|
const propsDiags = new PropsDestructuringDiagnostics;
|
|
1892
1334
|
allDiagnostics.push(...propsDiags.analyze(sourceFile, components));
|
|
1893
1335
|
detectDomHelpers(s.toString(), usedFeatures);
|
|
1894
|
-
const
|
|
1895
|
-
const imports = buildImportStatement(usedFeatures, target);
|
|
1336
|
+
const imports = buildImportStatement(usedFeatures);
|
|
1896
1337
|
if (imports) {
|
|
1897
1338
|
s.prepend(`${imports}
|
|
1898
1339
|
`);
|
|
@@ -1908,16 +1349,12 @@ function compile(source, optionsOrFilename) {
|
|
|
1908
1349
|
};
|
|
1909
1350
|
}
|
|
1910
1351
|
var DOM_HELPERS = [
|
|
1911
|
-
"__append",
|
|
1912
1352
|
"__child",
|
|
1913
|
-
"__enterChildren",
|
|
1914
|
-
"__exitChildren",
|
|
1915
1353
|
"__insert",
|
|
1916
1354
|
"__conditional",
|
|
1917
1355
|
"__list",
|
|
1918
1356
|
"__show",
|
|
1919
|
-
"__classList"
|
|
1920
|
-
"__staticText"
|
|
1357
|
+
"__classList"
|
|
1921
1358
|
];
|
|
1922
1359
|
function detectDomHelpers(output, usedFeatures) {
|
|
1923
1360
|
for (const helper of DOM_HELPERS) {
|
|
@@ -1926,7 +1363,7 @@ function detectDomHelpers(output, usedFeatures) {
|
|
|
1926
1363
|
}
|
|
1927
1364
|
}
|
|
1928
1365
|
}
|
|
1929
|
-
function buildImportStatement(features
|
|
1366
|
+
function buildImportStatement(features) {
|
|
1930
1367
|
const runtimeImports = [];
|
|
1931
1368
|
const domImports = [];
|
|
1932
1369
|
for (const feature of features) {
|
|
@@ -1936,13 +1373,12 @@ function buildImportStatement(features, target) {
|
|
|
1936
1373
|
domImports.push(feature);
|
|
1937
1374
|
}
|
|
1938
1375
|
}
|
|
1939
|
-
const internalsSource = target === "tui" ? "@vertz/tui/internals" : "@vertz/ui/internals";
|
|
1940
1376
|
const parts = [];
|
|
1941
1377
|
if (runtimeImports.length > 0) {
|
|
1942
1378
|
parts.push(`import { ${runtimeImports.sort().join(", ")} } from '@vertz/ui';`);
|
|
1943
1379
|
}
|
|
1944
1380
|
if (domImports.length > 0) {
|
|
1945
|
-
parts.push(`import { ${domImports.sort().join(", ")} } from '
|
|
1381
|
+
parts.push(`import { ${domImports.sort().join(", ")} } from '@vertz/ui/internals';`);
|
|
1946
1382
|
}
|
|
1947
1383
|
return parts.length > 0 ? parts.join(`
|
|
1948
1384
|
`) : null;
|
|
@@ -2013,7 +1449,6 @@ import {
|
|
|
2013
1449
|
FONT_SIZE_SCALE,
|
|
2014
1450
|
FONT_WEIGHT_SCALE,
|
|
2015
1451
|
HEIGHT_AXIS_PROPERTIES,
|
|
2016
|
-
KEYWORD_MAP,
|
|
2017
1452
|
LINE_HEIGHT_SCALE,
|
|
2018
1453
|
PROPERTY_MAP,
|
|
2019
1454
|
PSEUDO_MAP,
|
|
@@ -2023,7 +1458,7 @@ import {
|
|
|
2023
1458
|
SIZE_KEYWORDS,
|
|
2024
1459
|
SPACING_SCALE
|
|
2025
1460
|
} from "@vertz/ui/internals";
|
|
2026
|
-
import { Project as Project2, SyntaxKind as
|
|
1461
|
+
import { Project as Project2, SyntaxKind as SyntaxKind12, ts as ts2 } from "ts-morph";
|
|
2027
1462
|
|
|
2028
1463
|
class CSSExtractor {
|
|
2029
1464
|
extract(source, filePath) {
|
|
@@ -2034,28 +1469,28 @@ class CSSExtractor {
|
|
|
2034
1469
|
const sourceFile = project.createSourceFile(filePath, source);
|
|
2035
1470
|
const allCssRules = [];
|
|
2036
1471
|
const allBlockNames = [];
|
|
2037
|
-
const callExpressions = sourceFile.getDescendantsOfKind(
|
|
1472
|
+
const callExpressions = sourceFile.getDescendantsOfKind(SyntaxKind12.CallExpression);
|
|
2038
1473
|
for (const call of callExpressions) {
|
|
2039
1474
|
const expression = call.getExpression();
|
|
2040
|
-
if (!expression.isKind(
|
|
1475
|
+
if (!expression.isKind(SyntaxKind12.Identifier) || expression.getText() !== "css") {
|
|
2041
1476
|
continue;
|
|
2042
1477
|
}
|
|
2043
1478
|
const args = call.getArguments();
|
|
2044
1479
|
if (args.length === 0)
|
|
2045
1480
|
continue;
|
|
2046
1481
|
const firstArg = args[0];
|
|
2047
|
-
if (!firstArg.isKind(
|
|
1482
|
+
if (!firstArg.isKind(SyntaxKind12.ObjectLiteralExpression))
|
|
2048
1483
|
continue;
|
|
2049
1484
|
if (!isStaticCSSCall(firstArg))
|
|
2050
1485
|
continue;
|
|
2051
1486
|
for (const prop of firstArg.getProperties()) {
|
|
2052
|
-
if (!prop.isKind(
|
|
1487
|
+
if (!prop.isKind(SyntaxKind12.PropertyAssignment))
|
|
2053
1488
|
continue;
|
|
2054
1489
|
const blockName = prop.getName();
|
|
2055
1490
|
allBlockNames.push(blockName);
|
|
2056
1491
|
const className = generateClassName(filePath, blockName);
|
|
2057
1492
|
const init = prop.getInitializer();
|
|
2058
|
-
if (!init || !init.isKind(
|
|
1493
|
+
if (!init || !init.isKind(SyntaxKind12.ArrayLiteralExpression))
|
|
2059
1494
|
continue;
|
|
2060
1495
|
const entries = extractEntries(init);
|
|
2061
1496
|
const rules = buildCSSRules(className, entries);
|
|
@@ -2070,18 +1505,18 @@ class CSSExtractor {
|
|
|
2070
1505
|
}
|
|
2071
1506
|
}
|
|
2072
1507
|
function isStaticCSSCall(node) {
|
|
2073
|
-
if (!node.isKind(
|
|
1508
|
+
if (!node.isKind(SyntaxKind12.ObjectLiteralExpression))
|
|
2074
1509
|
return false;
|
|
2075
1510
|
for (const prop of node.getProperties()) {
|
|
2076
|
-
if (!prop.isKind(
|
|
1511
|
+
if (!prop.isKind(SyntaxKind12.PropertyAssignment))
|
|
2077
1512
|
return false;
|
|
2078
1513
|
const initializer = prop.getInitializer();
|
|
2079
|
-
if (!initializer || !initializer.isKind(
|
|
1514
|
+
if (!initializer || !initializer.isKind(SyntaxKind12.ArrayLiteralExpression))
|
|
2080
1515
|
return false;
|
|
2081
1516
|
for (const element of initializer.getElements()) {
|
|
2082
|
-
if (element.isKind(
|
|
1517
|
+
if (element.isKind(SyntaxKind12.StringLiteral))
|
|
2083
1518
|
continue;
|
|
2084
|
-
if (element.isKind(
|
|
1519
|
+
if (element.isKind(SyntaxKind12.ObjectLiteralExpression)) {
|
|
2085
1520
|
if (!isStaticNestedObject(element))
|
|
2086
1521
|
return false;
|
|
2087
1522
|
continue;
|
|
@@ -2092,110 +1527,55 @@ function isStaticCSSCall(node) {
|
|
|
2092
1527
|
return true;
|
|
2093
1528
|
}
|
|
2094
1529
|
function isStaticNestedObject(node) {
|
|
2095
|
-
if (!node.isKind(
|
|
1530
|
+
if (!node.isKind(SyntaxKind12.ObjectLiteralExpression))
|
|
2096
1531
|
return false;
|
|
2097
1532
|
for (const prop of node.getProperties()) {
|
|
2098
|
-
if (!prop.isKind(
|
|
1533
|
+
if (!prop.isKind(SyntaxKind12.PropertyAssignment))
|
|
2099
1534
|
return false;
|
|
2100
1535
|
const init = prop.getInitializer();
|
|
2101
|
-
if (!init || !init.isKind(
|
|
1536
|
+
if (!init || !init.isKind(SyntaxKind12.ArrayLiteralExpression))
|
|
2102
1537
|
return false;
|
|
2103
1538
|
for (const el of init.getElements()) {
|
|
2104
|
-
if (el.isKind(
|
|
2105
|
-
continue;
|
|
2106
|
-
if (el.isKind(SyntaxKind13.ObjectLiteralExpression)) {
|
|
2107
|
-
if (isStaticRawDeclaration(el))
|
|
2108
|
-
continue;
|
|
1539
|
+
if (!el.isKind(SyntaxKind12.StringLiteral))
|
|
2109
1540
|
return false;
|
|
2110
|
-
}
|
|
2111
|
-
return false;
|
|
2112
1541
|
}
|
|
2113
1542
|
}
|
|
2114
1543
|
return true;
|
|
2115
1544
|
}
|
|
2116
|
-
function isStaticRawDeclaration(node) {
|
|
2117
|
-
if (!node.isKind(SyntaxKind13.ObjectLiteralExpression))
|
|
2118
|
-
return false;
|
|
2119
|
-
const props = node.getProperties();
|
|
2120
|
-
if (props.length !== 2)
|
|
2121
|
-
return false;
|
|
2122
|
-
let hasProperty = false;
|
|
2123
|
-
let hasValue = false;
|
|
2124
|
-
for (const prop of props) {
|
|
2125
|
-
if (!prop.isKind(SyntaxKind13.PropertyAssignment))
|
|
2126
|
-
return false;
|
|
2127
|
-
const init = prop.getInitializer();
|
|
2128
|
-
if (!init || !init.isKind(SyntaxKind13.StringLiteral))
|
|
2129
|
-
return false;
|
|
2130
|
-
const name = prop.getName();
|
|
2131
|
-
if (name === "property")
|
|
2132
|
-
hasProperty = true;
|
|
2133
|
-
else if (name === "value")
|
|
2134
|
-
hasValue = true;
|
|
2135
|
-
}
|
|
2136
|
-
return hasProperty && hasValue;
|
|
2137
|
-
}
|
|
2138
1545
|
function extractEntries(arrayNode) {
|
|
2139
|
-
if (!arrayNode.isKind(
|
|
1546
|
+
if (!arrayNode.isKind(SyntaxKind12.ArrayLiteralExpression))
|
|
2140
1547
|
return [];
|
|
2141
1548
|
const results = [];
|
|
2142
1549
|
for (const element of arrayNode.getElements()) {
|
|
2143
|
-
if (element.isKind(
|
|
1550
|
+
if (element.isKind(SyntaxKind12.StringLiteral)) {
|
|
2144
1551
|
results.push({ kind: "shorthand", value: element.getLiteralValue() });
|
|
2145
|
-
} else if (element.isKind(
|
|
1552
|
+
} else if (element.isKind(SyntaxKind12.ObjectLiteralExpression)) {
|
|
2146
1553
|
for (const prop of element.getProperties()) {
|
|
2147
|
-
if (!prop.isKind(
|
|
1554
|
+
if (!prop.isKind(SyntaxKind12.PropertyAssignment))
|
|
2148
1555
|
continue;
|
|
2149
1556
|
const selector = prop.getName();
|
|
2150
1557
|
const nameNode = prop.getNameNode();
|
|
2151
|
-
const actualSelector = nameNode.isKind(
|
|
1558
|
+
const actualSelector = nameNode.isKind(SyntaxKind12.StringLiteral) ? nameNode.getLiteralValue() : selector;
|
|
2152
1559
|
const init = prop.getInitializer();
|
|
2153
|
-
if (!init || !init.isKind(
|
|
1560
|
+
if (!init || !init.isKind(SyntaxKind12.ArrayLiteralExpression))
|
|
2154
1561
|
continue;
|
|
2155
1562
|
const nestedEntries = [];
|
|
2156
|
-
const rawDeclarations = [];
|
|
2157
1563
|
for (const el of init.getElements()) {
|
|
2158
|
-
if (el.isKind(
|
|
1564
|
+
if (el.isKind(SyntaxKind12.StringLiteral)) {
|
|
2159
1565
|
nestedEntries.push(el.getLiteralValue());
|
|
2160
|
-
} else if (el.isKind(SyntaxKind13.ObjectLiteralExpression)) {
|
|
2161
|
-
const rawDecl = extractRawDeclaration(el);
|
|
2162
|
-
if (rawDecl)
|
|
2163
|
-
rawDeclarations.push(rawDecl);
|
|
2164
1566
|
}
|
|
2165
1567
|
}
|
|
2166
1568
|
results.push({
|
|
2167
1569
|
kind: "nested",
|
|
2168
1570
|
value: "",
|
|
2169
1571
|
selector: actualSelector,
|
|
2170
|
-
entries: nestedEntries
|
|
2171
|
-
rawDeclarations
|
|
1572
|
+
entries: nestedEntries
|
|
2172
1573
|
});
|
|
2173
1574
|
}
|
|
2174
1575
|
}
|
|
2175
1576
|
}
|
|
2176
1577
|
return results;
|
|
2177
1578
|
}
|
|
2178
|
-
function extractRawDeclaration(node) {
|
|
2179
|
-
if (!node.isKind(SyntaxKind13.ObjectLiteralExpression))
|
|
2180
|
-
return null;
|
|
2181
|
-
let property = null;
|
|
2182
|
-
let value = null;
|
|
2183
|
-
for (const prop of node.getProperties()) {
|
|
2184
|
-
if (!prop.isKind(SyntaxKind13.PropertyAssignment))
|
|
2185
|
-
return null;
|
|
2186
|
-
const name = prop.getName();
|
|
2187
|
-
const init = prop.getInitializer();
|
|
2188
|
-
if (!init || !init.isKind(SyntaxKind13.StringLiteral))
|
|
2189
|
-
return null;
|
|
2190
|
-
if (name === "property")
|
|
2191
|
-
property = init.getLiteralValue();
|
|
2192
|
-
else if (name === "value")
|
|
2193
|
-
value = init.getLiteralValue();
|
|
2194
|
-
}
|
|
2195
|
-
if (property && value)
|
|
2196
|
-
return { property, value };
|
|
2197
|
-
return null;
|
|
2198
|
-
}
|
|
2199
1579
|
function buildCSSRules(className, entries) {
|
|
2200
1580
|
const rules = [];
|
|
2201
1581
|
const baseDecls = [];
|
|
@@ -2226,12 +1606,7 @@ function buildCSSRules(className, entries) {
|
|
|
2226
1606
|
continue;
|
|
2227
1607
|
nestedDecls.push(...resolved);
|
|
2228
1608
|
}
|
|
2229
|
-
|
|
2230
|
-
for (const raw of entry.rawDeclarations) {
|
|
2231
|
-
nestedDecls.push(`${raw.property}: ${raw.value};`);
|
|
2232
|
-
}
|
|
2233
|
-
}
|
|
2234
|
-
const resolvedSelector = entry.selector.replaceAll("&", `.${className}`);
|
|
1609
|
+
const resolvedSelector = entry.selector.replace("&", `.${className}`);
|
|
2235
1610
|
if (nestedDecls.length > 0) {
|
|
2236
1611
|
rules.push(formatCSSRule(resolvedSelector, nestedDecls));
|
|
2237
1612
|
}
|
|
@@ -2278,10 +1653,6 @@ function resolveDeclarations(parsed) {
|
|
|
2278
1653
|
if (DISPLAY_MAP[property] !== undefined && value === null) {
|
|
2279
1654
|
return [`display: ${DISPLAY_MAP[property]};`];
|
|
2280
1655
|
}
|
|
2281
|
-
const keyword = KEYWORD_MAP[property];
|
|
2282
|
-
if (keyword !== undefined && value === null) {
|
|
2283
|
-
return keyword.map((d) => `${d.property}: ${d.value};`);
|
|
2284
|
-
}
|
|
2285
1656
|
const mapping = PROPERTY_MAP[property];
|
|
2286
1657
|
if (!mapping || value === null)
|
|
2287
1658
|
return null;
|
|
@@ -2418,39 +1789,39 @@ class RouteCSSManifest {
|
|
|
2418
1789
|
import {
|
|
2419
1790
|
COLOR_NAMESPACES as COLOR_NAMESPACES2,
|
|
2420
1791
|
CSS_COLOR_KEYWORDS as CSS_COLOR_KEYWORDS2,
|
|
2421
|
-
KEYWORD_MAP
|
|
1792
|
+
KEYWORD_MAP,
|
|
2422
1793
|
PROPERTY_MAP as PROPERTY_MAP2,
|
|
2423
1794
|
PSEUDO_PREFIXES as PSEUDO_PREFIXES2,
|
|
2424
1795
|
SPACING_SCALE as SPACING_SCALE2
|
|
2425
1796
|
} from "@vertz/ui/internals";
|
|
2426
|
-
import { SyntaxKind as
|
|
2427
|
-
var KNOWN_PROPERTIES = new Set([...Object.keys(PROPERTY_MAP2), ...Object.keys(
|
|
1797
|
+
import { SyntaxKind as SyntaxKind13 } from "ts-morph";
|
|
1798
|
+
var KNOWN_PROPERTIES = new Set([...Object.keys(PROPERTY_MAP2), ...Object.keys(KEYWORD_MAP)]);
|
|
2428
1799
|
var SPACING_VALUES = new Set(Object.keys(SPACING_SCALE2));
|
|
2429
1800
|
var SPACING_PROPERTIES = new Set(Object.entries(PROPERTY_MAP2).filter(([_, mapping]) => mapping.valueType === "spacing").map(([key]) => key));
|
|
2430
1801
|
|
|
2431
1802
|
class CSSDiagnostics {
|
|
2432
1803
|
analyze(sourceFile) {
|
|
2433
1804
|
const diagnostics = [];
|
|
2434
|
-
const callExpressions = sourceFile.getDescendantsOfKind(
|
|
1805
|
+
const callExpressions = sourceFile.getDescendantsOfKind(SyntaxKind13.CallExpression);
|
|
2435
1806
|
for (const call of callExpressions) {
|
|
2436
1807
|
const expression = call.getExpression();
|
|
2437
|
-
if (!expression.isKind(
|
|
1808
|
+
if (!expression.isKind(SyntaxKind13.Identifier) || expression.getText() !== "css") {
|
|
2438
1809
|
continue;
|
|
2439
1810
|
}
|
|
2440
1811
|
const args = call.getArguments();
|
|
2441
1812
|
if (args.length === 0)
|
|
2442
1813
|
continue;
|
|
2443
1814
|
const firstArg = args[0];
|
|
2444
|
-
if (!firstArg || !firstArg.isKind(
|
|
1815
|
+
if (!firstArg || !firstArg.isKind(SyntaxKind13.ObjectLiteralExpression))
|
|
2445
1816
|
continue;
|
|
2446
1817
|
for (const prop of firstArg.getProperties()) {
|
|
2447
|
-
if (!prop.isKind(
|
|
1818
|
+
if (!prop.isKind(SyntaxKind13.PropertyAssignment))
|
|
2448
1819
|
continue;
|
|
2449
1820
|
const init = prop.getInitializer();
|
|
2450
|
-
if (!init || !init.isKind(
|
|
1821
|
+
if (!init || !init.isKind(SyntaxKind13.ArrayLiteralExpression))
|
|
2451
1822
|
continue;
|
|
2452
1823
|
for (const element of init.getElements()) {
|
|
2453
|
-
if (!element.isKind(
|
|
1824
|
+
if (!element.isKind(SyntaxKind13.StringLiteral))
|
|
2454
1825
|
continue;
|
|
2455
1826
|
const value = element.getLiteralValue();
|
|
2456
1827
|
const pos = sourceFile.getLineAndColumnAtPos(element.getStart());
|
|
@@ -2568,152 +1939,6 @@ class CSSDiagnostics {
|
|
|
2568
1939
|
}
|
|
2569
1940
|
}
|
|
2570
1941
|
}
|
|
2571
|
-
// src/library-plugin.ts
|
|
2572
|
-
import { readFile } from "node:fs/promises";
|
|
2573
|
-
import remapping from "@ampproject/remapping";
|
|
2574
|
-
import MagicString2 from "magic-string";
|
|
2575
|
-
import { Project as Project3, ts as ts3 } from "ts-morph";
|
|
2576
|
-
|
|
2577
|
-
// src/transformers/hydration-transformer.ts
|
|
2578
|
-
import { SyntaxKind as SyntaxKind15 } from "ts-morph";
|
|
2579
|
-
class HydrationTransformer {
|
|
2580
|
-
transform(s, sourceFile) {
|
|
2581
|
-
const componentAnalyzer = new ComponentAnalyzer;
|
|
2582
|
-
const components = componentAnalyzer.analyze(sourceFile);
|
|
2583
|
-
for (const component of components) {
|
|
2584
|
-
if (this._isInteractive(sourceFile, component)) {
|
|
2585
|
-
this._addHydrationMarker(s, sourceFile, component);
|
|
2586
|
-
}
|
|
2587
|
-
}
|
|
2588
|
-
}
|
|
2589
|
-
_isInteractive(sourceFile, component) {
|
|
2590
|
-
const bodyNode = findBodyNode(sourceFile, component);
|
|
2591
|
-
if (!bodyNode)
|
|
2592
|
-
return false;
|
|
2593
|
-
for (const stmt of bodyNode.getChildSyntaxList()?.getChildren() ?? []) {
|
|
2594
|
-
if (!stmt.isKind(SyntaxKind15.VariableStatement))
|
|
2595
|
-
continue;
|
|
2596
|
-
const declList = stmt.getChildrenOfKind(SyntaxKind15.VariableDeclarationList)[0];
|
|
2597
|
-
if (!declList)
|
|
2598
|
-
continue;
|
|
2599
|
-
if (declList.getText().startsWith("let ")) {
|
|
2600
|
-
return true;
|
|
2601
|
-
}
|
|
2602
|
-
}
|
|
2603
|
-
return false;
|
|
2604
|
-
}
|
|
2605
|
-
_addHydrationMarker(s, sourceFile, component) {
|
|
2606
|
-
const bodyNode = findBodyNode(sourceFile, component);
|
|
2607
|
-
if (!bodyNode)
|
|
2608
|
-
return;
|
|
2609
|
-
const returnStmts = bodyNode.getDescendantsOfKind(SyntaxKind15.ReturnStatement);
|
|
2610
|
-
for (const ret of returnStmts) {
|
|
2611
|
-
const expr = ret.getExpression();
|
|
2612
|
-
if (!expr)
|
|
2613
|
-
continue;
|
|
2614
|
-
const rootJsx = this._findRootJsx(expr);
|
|
2615
|
-
if (rootJsx) {
|
|
2616
|
-
this._injectAttribute(s, rootJsx, component.name);
|
|
2617
|
-
return;
|
|
2618
|
-
}
|
|
2619
|
-
}
|
|
2620
|
-
const arrowBodies = sourceFile.getDescendantsOfKind(SyntaxKind15.ArrowFunction);
|
|
2621
|
-
for (const arrow of arrowBodies) {
|
|
2622
|
-
const body = arrow.getBody();
|
|
2623
|
-
if (body.getStart() === component.bodyStart && body.getEnd() === component.bodyEnd) {
|
|
2624
|
-
const rootJsx = this._findRootJsx(body);
|
|
2625
|
-
if (rootJsx) {
|
|
2626
|
-
this._injectAttribute(s, rootJsx, component.name);
|
|
2627
|
-
return;
|
|
2628
|
-
}
|
|
2629
|
-
}
|
|
2630
|
-
}
|
|
2631
|
-
}
|
|
2632
|
-
_findRootJsx(node) {
|
|
2633
|
-
if (node.isKind(SyntaxKind15.JsxElement) || node.isKind(SyntaxKind15.JsxSelfClosingElement)) {
|
|
2634
|
-
return node;
|
|
2635
|
-
}
|
|
2636
|
-
if (node.isKind(SyntaxKind15.ParenthesizedExpression)) {
|
|
2637
|
-
const inner = node.getExpression();
|
|
2638
|
-
return this._findRootJsx(inner);
|
|
2639
|
-
}
|
|
2640
|
-
for (const child of node.getChildren()) {
|
|
2641
|
-
const found = this._findRootJsx(child);
|
|
2642
|
-
if (found)
|
|
2643
|
-
return found;
|
|
2644
|
-
}
|
|
2645
|
-
return null;
|
|
2646
|
-
}
|
|
2647
|
-
_injectAttribute(s, jsxNode, componentName) {
|
|
2648
|
-
if (jsxNode.isKind(SyntaxKind15.JsxSelfClosingElement)) {
|
|
2649
|
-
const tagName = jsxNode.getChildrenOfKind(SyntaxKind15.Identifier)[0];
|
|
2650
|
-
if (tagName) {
|
|
2651
|
-
const insertPos = tagName.getEnd();
|
|
2652
|
-
s.appendLeft(insertPos, ` data-v-id="${componentName}"`);
|
|
2653
|
-
}
|
|
2654
|
-
} else if (jsxNode.isKind(SyntaxKind15.JsxElement)) {
|
|
2655
|
-
const openingElement = jsxNode.getChildrenOfKind(SyntaxKind15.JsxOpeningElement)[0];
|
|
2656
|
-
if (openingElement) {
|
|
2657
|
-
const tagName = openingElement.getChildrenOfKind(SyntaxKind15.Identifier)[0];
|
|
2658
|
-
if (tagName) {
|
|
2659
|
-
const insertPos = tagName.getEnd();
|
|
2660
|
-
s.appendLeft(insertPos, ` data-v-id="${componentName}"`);
|
|
2661
|
-
}
|
|
2662
|
-
}
|
|
2663
|
-
}
|
|
2664
|
-
}
|
|
2665
|
-
}
|
|
2666
|
-
|
|
2667
|
-
// src/library-plugin.ts
|
|
2668
|
-
function createVertzLibraryPlugin(options) {
|
|
2669
|
-
const filter = options?.filter ?? /\.tsx$/;
|
|
2670
|
-
return {
|
|
2671
|
-
name: "vertz-library-plugin",
|
|
2672
|
-
setup(build) {
|
|
2673
|
-
build.onLoad({ filter }, async (args) => {
|
|
2674
|
-
const source = await readFile(args.path, "utf-8");
|
|
2675
|
-
const hydrationS = new MagicString2(source);
|
|
2676
|
-
const hydrationProject = new Project3({
|
|
2677
|
-
useInMemoryFileSystem: true,
|
|
2678
|
-
compilerOptions: {
|
|
2679
|
-
jsx: ts3.JsxEmit.Preserve,
|
|
2680
|
-
strict: true
|
|
2681
|
-
}
|
|
2682
|
-
});
|
|
2683
|
-
const hydrationSourceFile = hydrationProject.createSourceFile(args.path, source);
|
|
2684
|
-
const hydrationTransformer = new HydrationTransformer;
|
|
2685
|
-
hydrationTransformer.transform(hydrationS, hydrationSourceFile);
|
|
2686
|
-
const hydratedCode = hydrationS.toString();
|
|
2687
|
-
const hydrationMap = hydrationS.generateMap({
|
|
2688
|
-
source: args.path,
|
|
2689
|
-
includeContent: true
|
|
2690
|
-
});
|
|
2691
|
-
const compileResult = compile(hydratedCode, {
|
|
2692
|
-
filename: args.path,
|
|
2693
|
-
target: options?.target
|
|
2694
|
-
});
|
|
2695
|
-
const errors = compileResult.diagnostics.filter((d) => d.severity === "error");
|
|
2696
|
-
if (errors.length > 0) {
|
|
2697
|
-
const messages = errors.map((d) => `${d.code}: ${d.message} (line ${d.line})`);
|
|
2698
|
-
throw new Error(`Vertz compilation errors in ${args.path}:
|
|
2699
|
-
${messages.join(`
|
|
2700
|
-
`)}`);
|
|
2701
|
-
}
|
|
2702
|
-
for (const d of compileResult.diagnostics) {
|
|
2703
|
-
if (d.severity === "warning") {
|
|
2704
|
-
console.warn(`[vertz-library-plugin] ${args.path}:${d.line} ${d.code}: ${d.message}`);
|
|
2705
|
-
}
|
|
2706
|
-
}
|
|
2707
|
-
const remapped = remapping([compileResult.map, hydrationMap], () => null);
|
|
2708
|
-
const mapBase64 = Buffer.from(remapped.toString()).toString("base64");
|
|
2709
|
-
const sourceMapComment = `
|
|
2710
|
-
//# sourceMappingURL=data:application/json;base64,${mapBase64}`;
|
|
2711
|
-
const contents = compileResult.code + sourceMapComment;
|
|
2712
|
-
return { contents, loader: "tsx" };
|
|
2713
|
-
});
|
|
2714
|
-
}
|
|
2715
|
-
};
|
|
2716
|
-
}
|
|
2717
1942
|
// src/transformers/css-transformer.ts
|
|
2718
1943
|
import {
|
|
2719
1944
|
ALIGNMENT_MAP as ALIGNMENT_MAP2,
|
|
@@ -2724,7 +1949,6 @@ import {
|
|
|
2724
1949
|
FONT_SIZE_SCALE as FONT_SIZE_SCALE2,
|
|
2725
1950
|
FONT_WEIGHT_SCALE as FONT_WEIGHT_SCALE2,
|
|
2726
1951
|
HEIGHT_AXIS_PROPERTIES as HEIGHT_AXIS_PROPERTIES2,
|
|
2727
|
-
KEYWORD_MAP as KEYWORD_MAP3,
|
|
2728
1952
|
LINE_HEIGHT_SCALE as LINE_HEIGHT_SCALE2,
|
|
2729
1953
|
PROPERTY_MAP as PROPERTY_MAP3,
|
|
2730
1954
|
PSEUDO_MAP as PSEUDO_MAP2,
|
|
@@ -2734,7 +1958,7 @@ import {
|
|
|
2734
1958
|
SIZE_KEYWORDS as SIZE_KEYWORDS2,
|
|
2735
1959
|
SPACING_SCALE as SPACING_SCALE3
|
|
2736
1960
|
} from "@vertz/ui/internals";
|
|
2737
|
-
import { SyntaxKind as
|
|
1961
|
+
import { SyntaxKind as SyntaxKind14 } from "ts-morph";
|
|
2738
1962
|
|
|
2739
1963
|
class CSSTransformer {
|
|
2740
1964
|
transform(s, sourceFile, cssCalls, filePath) {
|
|
@@ -2767,17 +1991,17 @@ class CSSTransformer {
|
|
|
2767
1991
|
if (args.length === 0)
|
|
2768
1992
|
return { classNames, cssRules };
|
|
2769
1993
|
const firstArg = args[0];
|
|
2770
|
-
if (!firstArg || !firstArg.isKind(
|
|
1994
|
+
if (!firstArg || !firstArg.isKind(SyntaxKind14.ObjectLiteralExpression)) {
|
|
2771
1995
|
return { classNames, cssRules };
|
|
2772
1996
|
}
|
|
2773
1997
|
for (const prop of firstArg.getProperties()) {
|
|
2774
|
-
if (!prop.isKind(
|
|
1998
|
+
if (!prop.isKind(SyntaxKind14.PropertyAssignment))
|
|
2775
1999
|
continue;
|
|
2776
2000
|
const blockName = prop.getName();
|
|
2777
2001
|
const className = generateClassName2(filePath, blockName);
|
|
2778
2002
|
classNames[blockName] = className;
|
|
2779
2003
|
const init = prop.getInitializer();
|
|
2780
|
-
if (!init || !init.isKind(
|
|
2004
|
+
if (!init || !init.isKind(SyntaxKind14.ArrayLiteralExpression))
|
|
2781
2005
|
continue;
|
|
2782
2006
|
const entries = extractEntries2(init);
|
|
2783
2007
|
const rules = buildCSSRules2(className, entries);
|
|
@@ -2791,7 +2015,7 @@ class CSSTransformer {
|
|
|
2791
2015
|
}
|
|
2792
2016
|
}
|
|
2793
2017
|
function findCallAtPosition(sourceFile, start) {
|
|
2794
|
-
const calls = sourceFile.getDescendantsOfKind(
|
|
2018
|
+
const calls = sourceFile.getDescendantsOfKind(SyntaxKind14.CallExpression);
|
|
2795
2019
|
for (const call of calls) {
|
|
2796
2020
|
if (call.getStart() === start)
|
|
2797
2021
|
return call;
|
|
@@ -2799,66 +2023,39 @@ function findCallAtPosition(sourceFile, start) {
|
|
|
2799
2023
|
return null;
|
|
2800
2024
|
}
|
|
2801
2025
|
function extractEntries2(arrayNode) {
|
|
2802
|
-
if (!arrayNode.isKind(
|
|
2026
|
+
if (!arrayNode.isKind(SyntaxKind14.ArrayLiteralExpression))
|
|
2803
2027
|
return [];
|
|
2804
2028
|
const results = [];
|
|
2805
2029
|
for (const element of arrayNode.getElements()) {
|
|
2806
|
-
if (element.isKind(
|
|
2030
|
+
if (element.isKind(SyntaxKind14.StringLiteral)) {
|
|
2807
2031
|
results.push({ kind: "shorthand", value: element.getLiteralValue() });
|
|
2808
|
-
} else if (element.isKind(
|
|
2032
|
+
} else if (element.isKind(SyntaxKind14.ObjectLiteralExpression)) {
|
|
2809
2033
|
for (const prop of element.getProperties()) {
|
|
2810
|
-
if (!prop.isKind(
|
|
2034
|
+
if (!prop.isKind(SyntaxKind14.PropertyAssignment))
|
|
2811
2035
|
continue;
|
|
2812
2036
|
const selector = prop.getName();
|
|
2813
2037
|
const nameNode = prop.getNameNode();
|
|
2814
|
-
const actualSelector = nameNode.isKind(
|
|
2038
|
+
const actualSelector = nameNode.isKind(SyntaxKind14.StringLiteral) ? nameNode.getLiteralValue() : selector;
|
|
2815
2039
|
const init = prop.getInitializer();
|
|
2816
|
-
if (!init || !init.isKind(
|
|
2040
|
+
if (!init || !init.isKind(SyntaxKind14.ArrayLiteralExpression))
|
|
2817
2041
|
continue;
|
|
2818
2042
|
const nestedEntries = [];
|
|
2819
|
-
const rawDeclarations = [];
|
|
2820
2043
|
for (const el of init.getElements()) {
|
|
2821
|
-
if (el.isKind(
|
|
2044
|
+
if (el.isKind(SyntaxKind14.StringLiteral)) {
|
|
2822
2045
|
nestedEntries.push(el.getLiteralValue());
|
|
2823
|
-
} else if (el.isKind(SyntaxKind16.ObjectLiteralExpression)) {
|
|
2824
|
-
const rawDecl = extractRawDeclaration2(el);
|
|
2825
|
-
if (rawDecl)
|
|
2826
|
-
rawDeclarations.push(rawDecl);
|
|
2827
2046
|
}
|
|
2828
2047
|
}
|
|
2829
2048
|
results.push({
|
|
2830
2049
|
kind: "nested",
|
|
2831
2050
|
value: "",
|
|
2832
2051
|
selector: actualSelector,
|
|
2833
|
-
entries: nestedEntries
|
|
2834
|
-
rawDeclarations
|
|
2052
|
+
entries: nestedEntries
|
|
2835
2053
|
});
|
|
2836
2054
|
}
|
|
2837
2055
|
}
|
|
2838
2056
|
}
|
|
2839
2057
|
return results;
|
|
2840
2058
|
}
|
|
2841
|
-
function extractRawDeclaration2(node) {
|
|
2842
|
-
if (!node.isKind(SyntaxKind16.ObjectLiteralExpression))
|
|
2843
|
-
return null;
|
|
2844
|
-
let property = null;
|
|
2845
|
-
let value = null;
|
|
2846
|
-
for (const prop of node.getProperties()) {
|
|
2847
|
-
if (!prop.isKind(SyntaxKind16.PropertyAssignment))
|
|
2848
|
-
return null;
|
|
2849
|
-
const name = prop.getName();
|
|
2850
|
-
const init = prop.getInitializer();
|
|
2851
|
-
if (!init || !init.isKind(SyntaxKind16.StringLiteral))
|
|
2852
|
-
return null;
|
|
2853
|
-
if (name === "property")
|
|
2854
|
-
property = init.getLiteralValue();
|
|
2855
|
-
else if (name === "value")
|
|
2856
|
-
value = init.getLiteralValue();
|
|
2857
|
-
}
|
|
2858
|
-
if (property && value)
|
|
2859
|
-
return { property, value };
|
|
2860
|
-
return null;
|
|
2861
|
-
}
|
|
2862
2059
|
function generateClassName2(filePath, blockName) {
|
|
2863
2060
|
const input = `${filePath}::${blockName}`;
|
|
2864
2061
|
const hash = djb2Hash2(input);
|
|
@@ -2901,12 +2098,7 @@ function buildCSSRules2(className, entries) {
|
|
|
2901
2098
|
continue;
|
|
2902
2099
|
nestedDecls.push(...resolved);
|
|
2903
2100
|
}
|
|
2904
|
-
|
|
2905
|
-
for (const raw of entry.rawDeclarations) {
|
|
2906
|
-
nestedDecls.push(`${raw.property}: ${raw.value};`);
|
|
2907
|
-
}
|
|
2908
|
-
}
|
|
2909
|
-
const resolvedSelector = entry.selector.replaceAll("&", `.${className}`);
|
|
2101
|
+
const resolvedSelector = entry.selector.replace("&", `.${className}`);
|
|
2910
2102
|
if (nestedDecls.length > 0) {
|
|
2911
2103
|
rules.push(formatCSSRule2(resolvedSelector, nestedDecls));
|
|
2912
2104
|
}
|
|
@@ -2953,10 +2145,6 @@ function resolveInline(parsed) {
|
|
|
2953
2145
|
if (DISPLAY_MAP2[property] !== undefined && value === null) {
|
|
2954
2146
|
return [`display: ${DISPLAY_MAP2[property]};`];
|
|
2955
2147
|
}
|
|
2956
|
-
const keyword = KEYWORD_MAP3[property];
|
|
2957
|
-
if (keyword !== undefined && value === null) {
|
|
2958
|
-
return keyword.map((d) => `${d.property}: ${d.value};`);
|
|
2959
|
-
}
|
|
2960
2148
|
const mapping = PROPERTY_MAP3[property];
|
|
2961
2149
|
if (!mapping || value === null)
|
|
2962
2150
|
return null;
|
|
@@ -3018,8 +2206,97 @@ function resolveColorInline(value) {
|
|
|
3018
2206
|
return value;
|
|
3019
2207
|
return null;
|
|
3020
2208
|
}
|
|
2209
|
+
// src/transformers/hydration-transformer.ts
|
|
2210
|
+
import { SyntaxKind as SyntaxKind15 } from "ts-morph";
|
|
2211
|
+
class HydrationTransformer {
|
|
2212
|
+
transform(s, sourceFile) {
|
|
2213
|
+
const componentAnalyzer = new ComponentAnalyzer;
|
|
2214
|
+
const components = componentAnalyzer.analyze(sourceFile);
|
|
2215
|
+
for (const component of components) {
|
|
2216
|
+
if (this._isInteractive(sourceFile, component)) {
|
|
2217
|
+
this._addHydrationMarker(s, sourceFile, component);
|
|
2218
|
+
}
|
|
2219
|
+
}
|
|
2220
|
+
}
|
|
2221
|
+
_isInteractive(sourceFile, component) {
|
|
2222
|
+
const bodyNode = findBodyNode(sourceFile, component);
|
|
2223
|
+
if (!bodyNode)
|
|
2224
|
+
return false;
|
|
2225
|
+
for (const stmt of bodyNode.getChildSyntaxList()?.getChildren() ?? []) {
|
|
2226
|
+
if (!stmt.isKind(SyntaxKind15.VariableStatement))
|
|
2227
|
+
continue;
|
|
2228
|
+
const declList = stmt.getChildrenOfKind(SyntaxKind15.VariableDeclarationList)[0];
|
|
2229
|
+
if (!declList)
|
|
2230
|
+
continue;
|
|
2231
|
+
if (declList.getText().startsWith("let ")) {
|
|
2232
|
+
return true;
|
|
2233
|
+
}
|
|
2234
|
+
}
|
|
2235
|
+
return false;
|
|
2236
|
+
}
|
|
2237
|
+
_addHydrationMarker(s, sourceFile, component) {
|
|
2238
|
+
const bodyNode = findBodyNode(sourceFile, component);
|
|
2239
|
+
if (!bodyNode)
|
|
2240
|
+
return;
|
|
2241
|
+
const returnStmts = bodyNode.getDescendantsOfKind(SyntaxKind15.ReturnStatement);
|
|
2242
|
+
for (const ret of returnStmts) {
|
|
2243
|
+
const expr = ret.getExpression();
|
|
2244
|
+
if (!expr)
|
|
2245
|
+
continue;
|
|
2246
|
+
const rootJsx = this._findRootJsx(expr);
|
|
2247
|
+
if (rootJsx) {
|
|
2248
|
+
this._injectAttribute(s, rootJsx, component.name);
|
|
2249
|
+
return;
|
|
2250
|
+
}
|
|
2251
|
+
}
|
|
2252
|
+
const arrowBodies = sourceFile.getDescendantsOfKind(SyntaxKind15.ArrowFunction);
|
|
2253
|
+
for (const arrow of arrowBodies) {
|
|
2254
|
+
const body = arrow.getBody();
|
|
2255
|
+
if (body.getStart() === component.bodyStart && body.getEnd() === component.bodyEnd) {
|
|
2256
|
+
const rootJsx = this._findRootJsx(body);
|
|
2257
|
+
if (rootJsx) {
|
|
2258
|
+
this._injectAttribute(s, rootJsx, component.name);
|
|
2259
|
+
return;
|
|
2260
|
+
}
|
|
2261
|
+
}
|
|
2262
|
+
}
|
|
2263
|
+
}
|
|
2264
|
+
_findRootJsx(node) {
|
|
2265
|
+
if (node.isKind(SyntaxKind15.JsxElement) || node.isKind(SyntaxKind15.JsxSelfClosingElement)) {
|
|
2266
|
+
return node;
|
|
2267
|
+
}
|
|
2268
|
+
if (node.isKind(SyntaxKind15.ParenthesizedExpression)) {
|
|
2269
|
+
const inner = node.getExpression();
|
|
2270
|
+
return this._findRootJsx(inner);
|
|
2271
|
+
}
|
|
2272
|
+
for (const child of node.getChildren()) {
|
|
2273
|
+
const found = this._findRootJsx(child);
|
|
2274
|
+
if (found)
|
|
2275
|
+
return found;
|
|
2276
|
+
}
|
|
2277
|
+
return null;
|
|
2278
|
+
}
|
|
2279
|
+
_injectAttribute(s, jsxNode, componentName) {
|
|
2280
|
+
if (jsxNode.isKind(SyntaxKind15.JsxSelfClosingElement)) {
|
|
2281
|
+
const tagName = jsxNode.getChildrenOfKind(SyntaxKind15.Identifier)[0];
|
|
2282
|
+
if (tagName) {
|
|
2283
|
+
const insertPos = tagName.getEnd();
|
|
2284
|
+
s.appendLeft(insertPos, ` data-v-id="${componentName}"`);
|
|
2285
|
+
}
|
|
2286
|
+
} else if (jsxNode.isKind(SyntaxKind15.JsxElement)) {
|
|
2287
|
+
const openingElement = jsxNode.getChildrenOfKind(SyntaxKind15.JsxOpeningElement)[0];
|
|
2288
|
+
if (openingElement) {
|
|
2289
|
+
const tagName = openingElement.getChildrenOfKind(SyntaxKind15.Identifier)[0];
|
|
2290
|
+
if (tagName) {
|
|
2291
|
+
const insertPos = tagName.getEnd();
|
|
2292
|
+
s.appendLeft(insertPos, ` data-v-id="${componentName}"`);
|
|
2293
|
+
}
|
|
2294
|
+
}
|
|
2295
|
+
}
|
|
2296
|
+
}
|
|
2297
|
+
}
|
|
3021
2298
|
// src/transformers/prop-transformer.ts
|
|
3022
|
-
import { SyntaxKind as
|
|
2299
|
+
import { SyntaxKind as SyntaxKind16 } from "ts-morph";
|
|
3023
2300
|
|
|
3024
2301
|
class PropTransformer {
|
|
3025
2302
|
transform(_source, _sourceFile, _component, _variables, _jsxExpressions) {}
|
|
@@ -3028,7 +2305,7 @@ class PropTransformer {
|
|
|
3028
2305
|
return "{}";
|
|
3029
2306
|
const props = [];
|
|
3030
2307
|
for (const attr of attrs) {
|
|
3031
|
-
if (!attr.isKind(
|
|
2308
|
+
if (!attr.isKind(SyntaxKind16.JsxAttribute))
|
|
3032
2309
|
continue;
|
|
3033
2310
|
const name = attr.getNameNode().getText();
|
|
3034
2311
|
const init = attr.getInitializer();
|
|
@@ -3036,11 +2313,11 @@ class PropTransformer {
|
|
|
3036
2313
|
props.push(`${name}: true`);
|
|
3037
2314
|
continue;
|
|
3038
2315
|
}
|
|
3039
|
-
if (init.isKind(
|
|
2316
|
+
if (init.isKind(SyntaxKind16.StringLiteral)) {
|
|
3040
2317
|
props.push(`${name}: ${init.getText()}`);
|
|
3041
2318
|
continue;
|
|
3042
2319
|
}
|
|
3043
|
-
if (init.isKind(
|
|
2320
|
+
if (init.isKind(SyntaxKind16.JsxExpression)) {
|
|
3044
2321
|
const exprInfo = jsxMap.get(init.getStart());
|
|
3045
2322
|
const exprNode = init.getExpression();
|
|
3046
2323
|
const exprText = exprNode?.getText() ?? "";
|
|
@@ -3110,13 +2387,306 @@ ${entries.join(`
|
|
|
3110
2387
|
`)}
|
|
3111
2388
|
};`;
|
|
3112
2389
|
}
|
|
2390
|
+
// src/vite-plugin.ts
|
|
2391
|
+
import remapping from "@ampproject/remapping";
|
|
2392
|
+
import MagicString2 from "magic-string";
|
|
2393
|
+
import { Project as Project3, ts as ts3 } from "ts-morph";
|
|
2394
|
+
var VIRTUAL_CSS_PREFIX = "\x00vertz-css:";
|
|
2395
|
+
var DEFAULT_INCLUDE = ["**/*.tsx", "**/*.jsx"];
|
|
2396
|
+
function vertzPlugin(options) {
|
|
2397
|
+
const include = options?.include ?? DEFAULT_INCLUDE;
|
|
2398
|
+
const exclude = options?.exclude ?? [];
|
|
2399
|
+
const enableCssExtraction = options?.cssExtraction ?? true;
|
|
2400
|
+
let resolvedConfig;
|
|
2401
|
+
let isProduction = false;
|
|
2402
|
+
const cssHmrHandler = new CSSHMRHandler;
|
|
2403
|
+
const cssExtractor = new CSSExtractor;
|
|
2404
|
+
const fileExtractions = new Map;
|
|
2405
|
+
function shouldTransform(id) {
|
|
2406
|
+
const cleanId = id.split("?")[0] ?? id;
|
|
2407
|
+
for (const pattern of exclude) {
|
|
2408
|
+
if (matchGlob(cleanId, pattern))
|
|
2409
|
+
return false;
|
|
2410
|
+
}
|
|
2411
|
+
for (const pattern of include) {
|
|
2412
|
+
if (matchGlob(cleanId, pattern))
|
|
2413
|
+
return true;
|
|
2414
|
+
}
|
|
2415
|
+
return false;
|
|
2416
|
+
}
|
|
2417
|
+
return {
|
|
2418
|
+
name: "vertz",
|
|
2419
|
+
enforce: "pre",
|
|
2420
|
+
config(_userConfig, env) {
|
|
2421
|
+
if (options?.ssr && env.isSsrBuild) {
|
|
2422
|
+
return {
|
|
2423
|
+
resolve: {
|
|
2424
|
+
alias: {
|
|
2425
|
+
"@vertz/ui/jsx-runtime": "@vertz/ui-server/jsx-runtime",
|
|
2426
|
+
"@vertz/ui/jsx-dev-runtime": "@vertz/ui-server/jsx-runtime"
|
|
2427
|
+
}
|
|
2428
|
+
}
|
|
2429
|
+
};
|
|
2430
|
+
}
|
|
2431
|
+
return;
|
|
2432
|
+
},
|
|
2433
|
+
configResolved(cfg) {
|
|
2434
|
+
resolvedConfig = cfg;
|
|
2435
|
+
isProduction = resolvedConfig.command === "build" || resolvedConfig.mode === "production";
|
|
2436
|
+
},
|
|
2437
|
+
configureServer(server) {
|
|
2438
|
+
if (!options?.ssr)
|
|
2439
|
+
return;
|
|
2440
|
+
const ssrOptions = typeof options.ssr === "object" ? options.ssr : {};
|
|
2441
|
+
server.middlewares.use(async (req, res, next) => {
|
|
2442
|
+
const url = req.url || "/";
|
|
2443
|
+
if (!req.headers.accept?.includes("text/html") && !req.url?.endsWith(".html") && req.url !== "/") {
|
|
2444
|
+
return next();
|
|
2445
|
+
}
|
|
2446
|
+
if (url.startsWith("/@") || url.startsWith("/node_modules") || url.includes("?") || /\.(js|css|png|jpg|jpeg|gif|svg|woff|woff2|ttf|eot)$/.test(url)) {
|
|
2447
|
+
return next();
|
|
2448
|
+
}
|
|
2449
|
+
try {
|
|
2450
|
+
const { readFileSync } = await import("node:fs");
|
|
2451
|
+
const { resolve } = await import("node:path");
|
|
2452
|
+
let template = readFileSync(resolve(server.config.root, "index.html"), "utf-8");
|
|
2453
|
+
template = await server.transformIndexHtml(url, template);
|
|
2454
|
+
let entry = ssrOptions.entry;
|
|
2455
|
+
if (!entry) {
|
|
2456
|
+
const scriptMatch = template.match(/<script[^>]*type="module"[^>]*src="([^"]+)"/);
|
|
2457
|
+
if (scriptMatch?.[1]) {
|
|
2458
|
+
entry = scriptMatch[1];
|
|
2459
|
+
} else {
|
|
2460
|
+
throw new Error("Could not auto-detect entry from index.html. Please specify ssr.entry in vertz plugin options.");
|
|
2461
|
+
}
|
|
2462
|
+
}
|
|
2463
|
+
const ssrEntryMod = server.moduleGraph.getModuleById("\x00vertz:ssr-entry");
|
|
2464
|
+
if (ssrEntryMod) {
|
|
2465
|
+
server.moduleGraph.invalidateModule(ssrEntryMod);
|
|
2466
|
+
}
|
|
2467
|
+
const ssrEntry = await server.ssrLoadModule("\x00vertz:ssr-entry");
|
|
2468
|
+
const appHtml = await ssrEntry.renderToString(url);
|
|
2469
|
+
let html;
|
|
2470
|
+
if (template.includes("<!--ssr-outlet-->")) {
|
|
2471
|
+
html = template.replace("<!--ssr-outlet-->", appHtml);
|
|
2472
|
+
} else {
|
|
2473
|
+
html = template.replace(/(<div[^>]*id="app"[^>]*>)([\s\S]*?)(<\/div>)/, `$1${appHtml}$3`);
|
|
2474
|
+
}
|
|
2475
|
+
res.writeHead(200, { "Content-Type": "text/html; charset=utf-8" });
|
|
2476
|
+
res.end(html);
|
|
2477
|
+
} catch (err) {
|
|
2478
|
+
server.ssrFixStacktrace(err);
|
|
2479
|
+
next(err);
|
|
2480
|
+
}
|
|
2481
|
+
});
|
|
2482
|
+
},
|
|
2483
|
+
resolveId(id) {
|
|
2484
|
+
if (id.startsWith(VIRTUAL_CSS_PREFIX)) {
|
|
2485
|
+
return id;
|
|
2486
|
+
}
|
|
2487
|
+
if (id === "\x00vertz:ssr-entry") {
|
|
2488
|
+
return id;
|
|
2489
|
+
}
|
|
2490
|
+
return;
|
|
2491
|
+
},
|
|
2492
|
+
load(id) {
|
|
2493
|
+
if (id.startsWith(VIRTUAL_CSS_PREFIX)) {
|
|
2494
|
+
const sourceFile = id.slice(VIRTUAL_CSS_PREFIX.length);
|
|
2495
|
+
const extraction = fileExtractions.get(sourceFile);
|
|
2496
|
+
if (extraction) {
|
|
2497
|
+
return extraction.css;
|
|
2498
|
+
}
|
|
2499
|
+
return "";
|
|
2500
|
+
}
|
|
2501
|
+
if (id === "\x00vertz:ssr-entry") {
|
|
2502
|
+
const ssrOptions = typeof options?.ssr === "object" ? options.ssr : {};
|
|
2503
|
+
const entry = ssrOptions.entry || "/src/index.ts";
|
|
2504
|
+
return generateSSREntry(entry);
|
|
2505
|
+
}
|
|
2506
|
+
return;
|
|
2507
|
+
},
|
|
2508
|
+
transform(code, id) {
|
|
2509
|
+
if (!shouldTransform(id)) {
|
|
2510
|
+
return;
|
|
2511
|
+
}
|
|
2512
|
+
const cleanId = id.split("?")[0] ?? id;
|
|
2513
|
+
const hydrationS = new MagicString2(code);
|
|
2514
|
+
const hydrationProject = new Project3({
|
|
2515
|
+
useInMemoryFileSystem: true,
|
|
2516
|
+
compilerOptions: {
|
|
2517
|
+
jsx: ts3.JsxEmit.Preserve,
|
|
2518
|
+
strict: true
|
|
2519
|
+
}
|
|
2520
|
+
});
|
|
2521
|
+
const hydrationSourceFile = hydrationProject.createSourceFile(cleanId, code);
|
|
2522
|
+
const hydrationTransformer = new HydrationTransformer;
|
|
2523
|
+
hydrationTransformer.transform(hydrationS, hydrationSourceFile);
|
|
2524
|
+
const hydratedCode = hydrationS.toString();
|
|
2525
|
+
const hydrationMap = hydrationS.generateMap({
|
|
2526
|
+
source: cleanId,
|
|
2527
|
+
includeContent: true
|
|
2528
|
+
});
|
|
2529
|
+
const compileResult = compile(hydratedCode, cleanId);
|
|
2530
|
+
const remapped = remapping([
|
|
2531
|
+
compileResult.map,
|
|
2532
|
+
hydrationMap
|
|
2533
|
+
], () => null);
|
|
2534
|
+
const rawChainedMap = JSON.parse(remapped.toString());
|
|
2535
|
+
const chainedMap = {
|
|
2536
|
+
...rawChainedMap,
|
|
2537
|
+
sourcesContent: rawChainedMap.sourcesContent?.map((c) => c ?? "")
|
|
2538
|
+
};
|
|
2539
|
+
let transformedCode = compileResult.code;
|
|
2540
|
+
const extraction = cssExtractor.extract(code, cleanId);
|
|
2541
|
+
if (extraction.css.length > 0) {
|
|
2542
|
+
fileExtractions.set(cleanId, extraction);
|
|
2543
|
+
if (isProduction && enableCssExtraction) {
|
|
2544
|
+
transformedCode = `import '${VIRTUAL_CSS_PREFIX}${cleanId}';
|
|
2545
|
+
${transformedCode}`;
|
|
2546
|
+
}
|
|
2547
|
+
cssHmrHandler.register(cleanId, extraction.css);
|
|
2548
|
+
}
|
|
2549
|
+
return {
|
|
2550
|
+
code: transformedCode,
|
|
2551
|
+
map: chainedMap
|
|
2552
|
+
};
|
|
2553
|
+
},
|
|
2554
|
+
handleHotUpdate(ctx) {
|
|
2555
|
+
const { file, modules } = ctx;
|
|
2556
|
+
if (file.includes(".vertz/generated/") || file.includes(".vertz\\generated\\")) {
|
|
2557
|
+
const affectedModules = [];
|
|
2558
|
+
for (const mod of modules) {
|
|
2559
|
+
affectedModules.push(mod);
|
|
2560
|
+
for (const importer of mod.importers) {
|
|
2561
|
+
affectedModules.push(importer);
|
|
2562
|
+
}
|
|
2563
|
+
}
|
|
2564
|
+
return affectedModules.length > 0 ? affectedModules : undefined;
|
|
2565
|
+
}
|
|
2566
|
+
if (!shouldTransform(file))
|
|
2567
|
+
return;
|
|
2568
|
+
const content = ctx.read();
|
|
2569
|
+
const processContent = (newCode) => {
|
|
2570
|
+
const extraction = cssExtractor.extract(newCode, file);
|
|
2571
|
+
const hmrResult = cssHmrHandler.update(file, extraction.css);
|
|
2572
|
+
if (hmrResult.hasChanged) {
|
|
2573
|
+
fileExtractions.set(file, extraction);
|
|
2574
|
+
const virtualId = VIRTUAL_CSS_PREFIX + file;
|
|
2575
|
+
const cssModule = ctx.server.moduleGraph.getModuleById(virtualId);
|
|
2576
|
+
if (cssModule) {
|
|
2577
|
+
ctx.server.moduleGraph.invalidateModule(cssModule);
|
|
2578
|
+
return [cssModule, ...modules];
|
|
2579
|
+
}
|
|
2580
|
+
}
|
|
2581
|
+
return;
|
|
2582
|
+
};
|
|
2583
|
+
if (typeof content === "string") {
|
|
2584
|
+
return processContent(content);
|
|
2585
|
+
}
|
|
2586
|
+
return content.then(processContent);
|
|
2587
|
+
},
|
|
2588
|
+
generateBundle() {
|
|
2589
|
+
if (!isProduction || !enableCssExtraction)
|
|
2590
|
+
return;
|
|
2591
|
+
const usedFiles = new Set(fileExtractions.keys());
|
|
2592
|
+
const deadCssEliminator = new DeadCSSEliminator;
|
|
2593
|
+
const liveCSS = deadCssEliminator.eliminate(fileExtractions, usedFiles);
|
|
2594
|
+
if (options?.routeMap && options.routeMap.size > 0) {
|
|
2595
|
+
const routeManifest = new RouteCSSManifest;
|
|
2596
|
+
const manifest = routeManifest.build(options.routeMap, fileExtractions);
|
|
2597
|
+
const codeSplitter = new CSSCodeSplitter;
|
|
2598
|
+
const chunks = codeSplitter.split(manifest, fileExtractions);
|
|
2599
|
+
for (const [route, css] of Object.entries(chunks)) {
|
|
2600
|
+
if (css.length === 0)
|
|
2601
|
+
continue;
|
|
2602
|
+
const fileName = route === "__common" ? "assets/common.css" : `assets/route-${sanitizeRoute(route)}.css`;
|
|
2603
|
+
this.emitFile({
|
|
2604
|
+
type: "asset",
|
|
2605
|
+
fileName,
|
|
2606
|
+
source: css
|
|
2607
|
+
});
|
|
2608
|
+
}
|
|
2609
|
+
} else if (liveCSS.length > 0) {
|
|
2610
|
+
this.emitFile({
|
|
2611
|
+
type: "asset",
|
|
2612
|
+
fileName: "assets/vertz.css",
|
|
2613
|
+
source: liveCSS
|
|
2614
|
+
});
|
|
2615
|
+
}
|
|
2616
|
+
}
|
|
2617
|
+
};
|
|
2618
|
+
}
|
|
2619
|
+
function generateSSREntry(userEntry) {
|
|
2620
|
+
return `
|
|
2621
|
+
import { installDomShim, toVNode } from '@vertz/ui-server/dom-shim';
|
|
2622
|
+
import { renderToStream, streamToString } from '@vertz/ui-server';
|
|
2623
|
+
|
|
2624
|
+
/**
|
|
2625
|
+
* Render the app to an HTML string for the given URL.
|
|
2626
|
+
*/
|
|
2627
|
+
export async function renderToString(url) {
|
|
2628
|
+
// Normalize URL: strip /index.html suffix that Vite's SPA fallback may add
|
|
2629
|
+
const normalizedUrl = url.endsWith('/index.html')
|
|
2630
|
+
? url.slice(0, -'/index.html'.length) || '/'
|
|
2631
|
+
: url;
|
|
2632
|
+
|
|
2633
|
+
// Set SSR context flag — invalidate and re-set on every call so
|
|
2634
|
+
// module-scope code (e.g. createRouter) picks up the current URL.
|
|
2635
|
+
globalThis.__SSR_URL__ = normalizedUrl;
|
|
2636
|
+
|
|
2637
|
+
// Install DOM shim so @vertz/ui components work
|
|
2638
|
+
installDomShim();
|
|
2639
|
+
|
|
2640
|
+
// Import the user's app entry (dynamic import for fresh module state)
|
|
2641
|
+
const userModule = await import('${userEntry}');
|
|
2642
|
+
|
|
2643
|
+
// Call the default export or named App export
|
|
2644
|
+
const createApp = userModule.default || userModule.App;
|
|
2645
|
+
if (typeof createApp !== 'function') {
|
|
2646
|
+
throw new Error('App entry must export a default function or named App function');
|
|
2647
|
+
}
|
|
2648
|
+
|
|
2649
|
+
const app = createApp();
|
|
2650
|
+
|
|
2651
|
+
// Convert to VNode if needed
|
|
2652
|
+
const vnode = toVNode(app);
|
|
2653
|
+
|
|
2654
|
+
// Render to stream and convert to string
|
|
2655
|
+
const stream = renderToStream(vnode);
|
|
2656
|
+
const html = await streamToString(stream);
|
|
2657
|
+
|
|
2658
|
+
return html;
|
|
2659
|
+
}
|
|
2660
|
+
`;
|
|
2661
|
+
}
|
|
2662
|
+
function matchGlob(filePath, pattern) {
|
|
2663
|
+
if (pattern.startsWith("**/") && pattern.endsWith("/**")) {
|
|
2664
|
+
const segment = pattern.slice(3, -3);
|
|
2665
|
+
return filePath.includes(`/${segment}/`) || filePath.includes(`\\${segment}\\`);
|
|
2666
|
+
}
|
|
2667
|
+
if (pattern.startsWith("**/")) {
|
|
2668
|
+
const suffix = pattern.slice(3);
|
|
2669
|
+
if (suffix.startsWith("*.")) {
|
|
2670
|
+
const ext = suffix.slice(1);
|
|
2671
|
+
return filePath.endsWith(ext);
|
|
2672
|
+
}
|
|
2673
|
+
return filePath.includes(suffix);
|
|
2674
|
+
}
|
|
2675
|
+
if (pattern.startsWith("*.")) {
|
|
2676
|
+
const ext = pattern.slice(1);
|
|
2677
|
+
return filePath.endsWith(ext);
|
|
2678
|
+
}
|
|
2679
|
+
return filePath.includes(pattern);
|
|
2680
|
+
}
|
|
2681
|
+
function sanitizeRoute(route) {
|
|
2682
|
+
return route.replace(/^\//, "").replace(/\//g, "-").replace(/[^a-zA-Z0-9-]/g, "_").replace(/^$/, "index");
|
|
2683
|
+
}
|
|
3113
2684
|
export {
|
|
3114
2685
|
generateThemeTypes,
|
|
3115
2686
|
generateCSSProperties,
|
|
3116
|
-
|
|
2687
|
+
vertzPlugin as default,
|
|
3117
2688
|
compile,
|
|
3118
2689
|
SignalTransformer,
|
|
3119
|
-
SSRSafetyDiagnostics,
|
|
3120
2690
|
RouteCSSManifest,
|
|
3121
2691
|
ReactivityAnalyzer,
|
|
3122
2692
|
PropsDestructuringDiagnostics,
|