@kithinji/pod 1.0.21 → 1.0.22

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.
Files changed (39) hide show
  1. package/README.md +439 -0
  2. package/dist/main.js +5 -5
  3. package/dist/main.js.map +2 -2
  4. package/package.json +31 -8
  5. package/build.js +0 -22
  6. package/src/add/component/component.ts +0 -496
  7. package/src/add/component/index.ts +0 -1
  8. package/src/add/index.ts +0 -3
  9. package/src/add/module/index.ts +0 -1
  10. package/src/add/module/module.ts +0 -545
  11. package/src/add/new/index.ts +0 -198
  12. package/src/config/config.ts +0 -141
  13. package/src/config/index.ts +0 -1
  14. package/src/deploy/deploy.ts +0 -592
  15. package/src/deploy/index.ts +0 -1
  16. package/src/dev/index.ts +0 -1
  17. package/src/dev/project.ts +0 -45
  18. package/src/dev/server.ts +0 -191
  19. package/src/docker/docker.ts +0 -697
  20. package/src/docker/index.ts +0 -1
  21. package/src/macros/expand_macros.ts +0 -791
  22. package/src/macros/index.ts +0 -2
  23. package/src/macros/macro_executer.ts +0 -189
  24. package/src/main.ts +0 -106
  25. package/src/plugins/analyzers/graph.ts +0 -279
  26. package/src/plugins/css/index.ts +0 -25
  27. package/src/plugins/generators/generate_controller.ts +0 -308
  28. package/src/plugins/generators/generate_rsc.ts +0 -274
  29. package/src/plugins/generators/generate_server_component.ts +0 -455
  30. package/src/plugins/generators/tsx_server_stub.ts +0 -315
  31. package/src/plugins/index.ts +0 -3
  32. package/src/plugins/my.ts +0 -282
  33. package/src/plugins/transformers/j2d.ts +0 -1080
  34. package/src/store/index.ts +0 -1
  35. package/src/store/store.ts +0 -44
  36. package/src/utils/cases.ts +0 -15
  37. package/src/utils/create.ts +0 -26
  38. package/src/utils/index.ts +0 -2
  39. package/tsconfig.json +0 -27
@@ -1,1080 +0,0 @@
1
- import type { PluginObj, NodePath } from "@babel/core";
2
- import * as BabelTypes from "@babel/types";
3
-
4
- interface PluginContext {
5
- types: typeof BabelTypes;
6
- }
7
-
8
- interface PluginState {
9
- helpersImported?: boolean;
10
- }
11
-
12
- interface TransformContext {
13
- observables: Map<string, BabelTypes.Expression>;
14
- observableSignals: Map<string, BabelTypes.Identifier>;
15
- }
16
-
17
- interface TransformResult {
18
- id: BabelTypes.Identifier;
19
- statements: BabelTypes.Statement[];
20
- }
21
-
22
- class NodeTypeGuards {
23
- constructor(private t: typeof BabelTypes) {}
24
-
25
- isSignalMember(expr: BabelTypes.Node): expr is BabelTypes.MemberExpression {
26
- return (
27
- this.t.isMemberExpression(expr) &&
28
- this.t.isIdentifier(expr.property, { name: "value" })
29
- );
30
- }
31
-
32
- isObservableMember(
33
- expr: BabelTypes.Node
34
- ): expr is BabelTypes.MemberExpression {
35
- return (
36
- this.t.isMemberExpression(expr) &&
37
- this.t.isIdentifier(expr.property, { name: "$value" })
38
- );
39
- }
40
- }
41
-
42
- class ASTUtilities {
43
- constructor(private t: typeof BabelTypes, private guards: NodeTypeGuards) {}
44
-
45
- getObject(expr: BabelTypes.Expression): BabelTypes.Expression {
46
- if (
47
- this.guards.isSignalMember(expr) ||
48
- this.guards.isObservableMember(expr)
49
- ) {
50
- return expr.object as BabelTypes.Expression;
51
- }
52
- return expr;
53
- }
54
-
55
- replaceThisWithSelf<T extends BabelTypes.Node>(node: T): T {
56
- const cloned = this.t.cloneNode(node, true) as T;
57
- this.walkAndTransform(cloned, (n: any) => {
58
- if (this.t.isThisExpression(n)) {
59
- Object.assign(n, this.t.identifier("self"));
60
- }
61
- });
62
- return cloned;
63
- }
64
-
65
- private walkAndTransform(node: any, transform: (node: any) => void): void {
66
- if (!node || typeof node !== "object") return;
67
-
68
- transform(node);
69
-
70
- for (const key in node) {
71
- if (this.shouldSkipKey(key)) continue;
72
-
73
- const value = node[key];
74
- if (Array.isArray(value)) {
75
- value.forEach((item) => this.walkAndTransform(item, transform));
76
- } else if (value && typeof value === "object") {
77
- this.walkAndTransform(value, transform);
78
- }
79
- }
80
- }
81
-
82
- private shouldSkipKey(key: string): boolean {
83
- return ["loc", "start", "end", "extra"].includes(key);
84
- }
85
-
86
- buildMemberExpression(name: string): BabelTypes.Expression {
87
- const parts = name.split(".");
88
- let expr: BabelTypes.Expression = this.t.identifier(parts[0]);
89
- for (let i = 1; i < parts.length; i++) {
90
- expr = this.t.memberExpression(expr, this.t.identifier(parts[i]));
91
- }
92
- return expr;
93
- }
94
-
95
- insertBeforeReturn(
96
- body: BabelTypes.Statement[],
97
- statements: BabelTypes.Statement[]
98
- ): void {
99
- const returnIndex = body.findIndex((stmt) =>
100
- this.t.isReturnStatement(stmt)
101
- );
102
- if (returnIndex !== -1) {
103
- body.splice(returnIndex, 0, ...statements);
104
- } else {
105
- body.push(...statements);
106
- }
107
- }
108
-
109
- addEffectCleanup(
110
- scope: any,
111
- effectCall: BabelTypes.CallExpression
112
- ): BabelTypes.Statement[] {
113
- const cleanupId = scope.generateUidIdentifier("cleanup");
114
-
115
- return [
116
- // const _cleanup1 = $effect(...)
117
- this.t.variableDeclaration("const", [
118
- this.t.variableDeclarator(cleanupId, effectCall),
119
- ]),
120
- // self.__cleanup = [...(self.__cleanup || []), _cleanup1]
121
- this.t.expressionStatement(
122
- this.t.assignmentExpression(
123
- "=",
124
- this.t.memberExpression(
125
- this.t.identifier("self"),
126
- this.t.identifier("__cleanup")
127
- ),
128
- this.t.arrayExpression([
129
- this.t.spreadElement(
130
- this.t.logicalExpression(
131
- "||",
132
- this.t.memberExpression(
133
- this.t.identifier("self"),
134
- this.t.identifier("__cleanup")
135
- ),
136
- this.t.arrayExpression([])
137
- )
138
- ),
139
- cleanupId,
140
- ])
141
- )
142
- ),
143
- ];
144
- }
145
- }
146
-
147
- class JSXUtilities {
148
- constructor(private t: typeof BabelTypes) {}
149
-
150
- getComponentName(
151
- nameNode:
152
- | BabelTypes.JSXIdentifier
153
- | BabelTypes.JSXMemberExpression
154
- | BabelTypes.JSXNamespacedName
155
- ): string | null {
156
- if (this.t.isJSXIdentifier(nameNode)) {
157
- return nameNode.name;
158
- }
159
-
160
- if (this.t.isJSXMemberExpression(nameNode)) {
161
- const parts: string[] = [];
162
- let current: BabelTypes.JSXMemberExpression | BabelTypes.JSXIdentifier =
163
- nameNode;
164
-
165
- while (this.t.isJSXMemberExpression(current)) {
166
- parts.unshift(current.property.name);
167
- current = current.object;
168
- }
169
-
170
- if (this.t.isJSXIdentifier(current)) {
171
- parts.unshift(current.name);
172
- }
173
-
174
- return parts.join(".");
175
- }
176
-
177
- return null;
178
- }
179
-
180
- isComponentTag(tag: string | null): boolean {
181
- return tag ? /^[A-Z]/.test(tag) : false;
182
- }
183
- }
184
-
185
- class ObservableManager {
186
- constructor(private t: typeof BabelTypes, private guards: NodeTypeGuards) {}
187
-
188
- getObservableKey(expr: BabelTypes.Node): string {
189
- return this.stringifyNode(expr);
190
- }
191
-
192
- private stringifyNode(node: any): string {
193
- if (!node) return "";
194
- if (this.t.isThisExpression(node)) return "this";
195
- if (this.t.isIdentifier(node)) return node.name;
196
-
197
- if (this.t.isMemberExpression(node)) {
198
- const obj = this.stringifyNode(node.object);
199
- const prop = node.computed
200
- ? `[${this.stringifyNode(node.property)}]`
201
- : `.${(node.property as BabelTypes.Identifier).name}`;
202
- return obj + prop;
203
- }
204
-
205
- if (this.t.isCallExpression(node)) {
206
- const callee = this.stringifyNode(node.callee);
207
- const args = node.arguments
208
- .map((arg) => this.stringifyNode(arg))
209
- .join(",");
210
- return `${callee}(${args})`;
211
- }
212
-
213
- if (this.t.isStringLiteral(node)) return `"${node.value}"`;
214
- if (this.t.isNumericLiteral(node)) return String(node.value);
215
-
216
- return node.type + JSON.stringify(node.name || node.value || "");
217
- }
218
-
219
- collectObservables(
220
- node: BabelTypes.Node,
221
- observables: Map<string, BabelTypes.Expression>,
222
- astUtils: ASTUtilities
223
- ): void {
224
- this.walkNode(node, (n: any) => {
225
- if (this.guards.isObservableMember(n)) {
226
- const observable = astUtils.replaceThisWithSelf(
227
- n.object as BabelTypes.Expression
228
- );
229
- const key = this.getObservableKey(observable);
230
- if (!observables.has(key)) {
231
- observables.set(key, observable);
232
- }
233
- }
234
- });
235
- }
236
-
237
- replaceObservablesWithSignals<T extends BabelTypes.Node>(
238
- node: T,
239
- observableSignals: Map<string, BabelTypes.Identifier>,
240
- astUtils: ASTUtilities
241
- ): T {
242
- const cloned = this.t.cloneNode(node, true) as T;
243
-
244
- this.walkNode(cloned, (n: any) => {
245
- if (this.guards.isObservableMember(n)) {
246
- const observable = astUtils.replaceThisWithSelf(n.object);
247
- const key = this.getObservableKey(observable);
248
- const signalId = observableSignals.get(key);
249
-
250
- if (signalId) {
251
- n.object = signalId;
252
- n.property = this.t.identifier("value");
253
- }
254
- }
255
- });
256
-
257
- return cloned;
258
- }
259
-
260
- private walkNode(node: any, callback: (node: any) => void): void {
261
- if (!node || typeof node !== "object") return;
262
-
263
- callback(node);
264
-
265
- for (const key in node) {
266
- if (["loc", "start", "end", "extra"].includes(key)) continue;
267
-
268
- const value = node[key];
269
- if (Array.isArray(value)) {
270
- value.forEach((item) => this.walkNode(item, callback));
271
- } else if (value && typeof value === "object") {
272
- this.walkNode(value, callback);
273
- }
274
- }
275
- }
276
- }
277
-
278
- class ElementTransformer {
279
- constructor(
280
- private t: typeof BabelTypes,
281
- private guards: NodeTypeGuards,
282
- private astUtils: ASTUtilities,
283
- private jsxUtils: JSXUtilities,
284
- private observableManager: ObservableManager
285
- ) {}
286
-
287
- transformElement(
288
- path: { node: BabelTypes.JSXElement | BabelTypes.JSXFragment },
289
- scope: any,
290
- context: TransformContext
291
- ): TransformResult {
292
- if (this.t.isJSXFragment(path.node)) {
293
- return this.transformFragment(
294
- path as { node: BabelTypes.JSXFragment },
295
- scope,
296
- context
297
- );
298
- }
299
- return this.transformJSXElement(
300
- path as { node: BabelTypes.JSXElement },
301
- scope,
302
- context
303
- );
304
- }
305
-
306
- private transformJSXElement(
307
- path: { node: BabelTypes.JSXElement },
308
- scope: any,
309
- context: TransformContext
310
- ): TransformResult {
311
- const jsxElement = path.node;
312
- const tag = this.jsxUtils.getComponentName(jsxElement.openingElement.name);
313
- const isComponent = this.jsxUtils.isComponentTag(tag);
314
-
315
- if (isComponent && tag) {
316
- return this.transformComponentElement(jsxElement, tag, scope, context);
317
- } else if (tag) {
318
- return this.transformDOMElement(jsxElement, tag, scope, context);
319
- }
320
-
321
- return {
322
- id: scope.generateUidIdentifier("el"),
323
- statements: [],
324
- };
325
- }
326
-
327
- private transformComponentElement(
328
- jsxElement: BabelTypes.JSXElement,
329
- tag: string,
330
- scope: any,
331
- context: TransformContext
332
- ): TransformResult {
333
- const elId = scope.generateUidIdentifier("el");
334
- const statements: BabelTypes.Statement[] = [];
335
- const props: Array<
336
- | BabelTypes.ObjectProperty
337
- | BabelTypes.ObjectMethod
338
- | BabelTypes.SpreadElement
339
- > = [];
340
- const children: Array<BabelTypes.Expression> = [];
341
-
342
- this.processComponentAttributes(
343
- jsxElement.openingElement.attributes,
344
- props,
345
- context
346
- );
347
-
348
- this.processChildren(
349
- jsxElement.children,
350
- children,
351
- statements,
352
- scope,
353
- context
354
- );
355
-
356
- if (children.length > 0) {
357
- props.push(
358
- this.t.objectProperty(
359
- this.t.identifier("children"),
360
- children.length === 1 ? children[0] : this.t.arrayExpression(children)
361
- )
362
- );
363
- }
364
-
365
- statements.push(
366
- this.t.variableDeclaration("var", [
367
- this.t.variableDeclarator(
368
- elId,
369
- this.t.callExpression(this.t.identifier("$createComponent"), [
370
- this.astUtils.buildMemberExpression(tag),
371
- this.t.objectExpression(props),
372
- this.t.identifier("self"),
373
- ])
374
- ),
375
- ])
376
- );
377
-
378
- return { id: elId, statements };
379
- }
380
-
381
- private transformDOMElement(
382
- jsxElement: BabelTypes.JSXElement,
383
- tag: string,
384
- scope: any,
385
- context: TransformContext
386
- ): TransformResult {
387
- const elId = scope.generateUidIdentifier("el");
388
- const statements: BabelTypes.Statement[] = [];
389
-
390
- statements.push(
391
- this.t.variableDeclaration("var", [
392
- this.t.variableDeclarator(
393
- elId,
394
- this.t.callExpression(
395
- this.t.memberExpression(
396
- this.t.identifier("document"),
397
- this.t.identifier("createElement")
398
- ),
399
- [this.t.stringLiteral(tag)]
400
- )
401
- ),
402
- ])
403
- );
404
-
405
- const { hasRef, refValue, hasDangerousHTML, dangerousHTMLValue } =
406
- this.processDOMAttributes(
407
- jsxElement.openingElement.attributes,
408
- elId,
409
- statements,
410
- scope,
411
- context
412
- );
413
-
414
- if (hasRef && refValue) {
415
- statements.push(
416
- this.t.expressionStatement(
417
- this.t.assignmentExpression("=", refValue as BabelTypes.LVal, elId)
418
- )
419
- );
420
- }
421
-
422
- /*
423
- let cleanup = effect(() => {
424
- el.innerHTML = {
425
- __html: value
426
- }.__html
427
- })
428
- */
429
-
430
- if (hasDangerousHTML && dangerousHTMLValue) {
431
- const effectCall = this.t.callExpression(this.t.identifier("$effect"), [
432
- this.t.arrowFunctionExpression(
433
- [],
434
- this.t.assignmentExpression(
435
- "=",
436
- this.t.memberExpression(elId, this.t.identifier("innerHTML")),
437
- this.t.memberExpression(
438
- dangerousHTMLValue,
439
- this.t.identifier("__html")
440
- )
441
- )
442
- ),
443
- ]);
444
-
445
- const cleanupStatements = this.astUtils.addEffectCleanup(
446
- scope,
447
- effectCall
448
- );
449
-
450
- statements.push(...cleanupStatements);
451
- }
452
-
453
- if (!hasDangerousHTML) {
454
- this.processDOMChildren(
455
- jsxElement.children,
456
- elId,
457
- statements,
458
- scope,
459
- context
460
- );
461
- }
462
-
463
- return { id: elId, statements };
464
- }
465
-
466
- private transformFragment(
467
- path: { node: BabelTypes.JSXFragment },
468
- scope: any,
469
- context: TransformContext
470
- ): TransformResult {
471
- const fragId = scope.generateUidIdentifier("frag");
472
- const statements: BabelTypes.Statement[] = [];
473
-
474
- statements.push(
475
- this.t.variableDeclaration("var", [
476
- this.t.variableDeclarator(
477
- fragId,
478
- this.t.callExpression(
479
- this.t.memberExpression(
480
- this.t.identifier("document"),
481
- this.t.identifier("createDocumentFragment")
482
- ),
483
- []
484
- )
485
- ),
486
- ])
487
- );
488
-
489
- this.processDOMChildren(
490
- path.node.children,
491
- fragId,
492
- statements,
493
- scope,
494
- context
495
- );
496
-
497
- return { id: fragId, statements };
498
- }
499
-
500
- private processComponentAttributes(
501
- attributes: Array<BabelTypes.JSXAttribute | BabelTypes.JSXSpreadAttribute>,
502
- props: Array<
503
- | BabelTypes.ObjectProperty
504
- | BabelTypes.ObjectMethod
505
- | BabelTypes.SpreadElement
506
- >,
507
- context: TransformContext
508
- ): void {
509
- for (const attr of attributes) {
510
- if (this.t.isJSXSpreadAttribute(attr)) {
511
- this.observableManager.collectObservables(
512
- attr.argument,
513
- context.observables,
514
- this.astUtils
515
- );
516
- const replaced = this.observableManager.replaceObservablesWithSignals(
517
- attr.argument,
518
- context.observableSignals,
519
- this.astUtils
520
- );
521
- props.push(
522
- this.t.spreadElement(this.astUtils.replaceThisWithSelf(replaced))
523
- );
524
- continue;
525
- }
526
-
527
- const key = (attr.name as BabelTypes.JSXIdentifier).name;
528
-
529
- if (this.t.isStringLiteral(attr.value)) {
530
- props.push(this.t.objectProperty(this.t.identifier(key), attr.value));
531
- } else if (this.t.isJSXExpressionContainer(attr.value)) {
532
- const expr = attr.value.expression as BabelTypes.Expression;
533
- this.observableManager.collectObservables(
534
- expr,
535
- context.observables,
536
- this.astUtils
537
- );
538
-
539
- if (
540
- this.guards.isSignalMember(expr) ||
541
- this.guards.isObservableMember(expr)
542
- ) {
543
- const replaced = this.observableManager.replaceObservablesWithSignals(
544
- expr,
545
- context.observableSignals,
546
- this.astUtils
547
- );
548
- props.push(
549
- this.t.objectMethod(
550
- "get",
551
- this.t.identifier(key),
552
- [],
553
- this.t.blockStatement([
554
- this.t.returnStatement(
555
- this.astUtils.replaceThisWithSelf(replaced)
556
- ),
557
- ])
558
- )
559
- );
560
- } else {
561
- const replaced = this.observableManager.replaceObservablesWithSignals(
562
- expr,
563
- context.observableSignals,
564
- this.astUtils
565
- );
566
- props.push(
567
- this.t.objectProperty(
568
- this.t.identifier(key),
569
- this.astUtils.replaceThisWithSelf(replaced)
570
- )
571
- );
572
- }
573
- } else {
574
- props.push(
575
- this.t.objectProperty(
576
- this.t.identifier(key),
577
- this.t.booleanLiteral(true)
578
- )
579
- );
580
- }
581
- }
582
- }
583
-
584
- private processDOMAttributes(
585
- attributes: Array<BabelTypes.JSXAttribute | BabelTypes.JSXSpreadAttribute>,
586
- elId: BabelTypes.Identifier,
587
- statements: BabelTypes.Statement[],
588
- scope: any,
589
- context: TransformContext
590
- ): {
591
- hasRef: boolean;
592
- refValue: BabelTypes.Expression | null;
593
- hasDangerousHTML: boolean;
594
- dangerousHTMLValue: BabelTypes.Expression | null;
595
- } {
596
- let hasRef = false;
597
- let refValue: BabelTypes.Expression | null = null;
598
- let hasDangerousHTML = false;
599
- let dangerousHTMLValue: BabelTypes.Expression | null = null;
600
-
601
- for (const attr of attributes) {
602
- if (this.t.isJSXSpreadAttribute(attr)) {
603
- this.observableManager.collectObservables(
604
- attr.argument,
605
- context.observables,
606
- this.astUtils
607
- );
608
- const replaced = this.observableManager.replaceObservablesWithSignals(
609
- attr.argument,
610
- context.observableSignals,
611
- this.astUtils
612
- );
613
-
614
- const effectCall = this.t.callExpression(this.t.identifier("$effect"), [
615
- this.t.arrowFunctionExpression(
616
- [],
617
- this.t.callExpression(this.t.identifier("$spread"), [
618
- elId,
619
- this.astUtils.replaceThisWithSelf(replaced),
620
- ])
621
- ),
622
- ]);
623
-
624
- const cleanupStatements = this.astUtils.addEffectCleanup(
625
- scope,
626
- effectCall
627
- );
628
-
629
- statements.push(...cleanupStatements);
630
-
631
- continue;
632
- }
633
-
634
- const key = (attr.name as BabelTypes.JSXIdentifier).name;
635
-
636
- if (key === "ref") {
637
- hasRef = true;
638
- if (this.t.isJSXExpressionContainer(attr.value)) {
639
- this.observableManager.collectObservables(
640
- attr.value.expression,
641
- context.observables,
642
- this.astUtils
643
- );
644
- const replaced = this.observableManager.replaceObservablesWithSignals(
645
- attr.value.expression as BabelTypes.Expression,
646
- context.observableSignals,
647
- this.astUtils
648
- );
649
- refValue = this.astUtils.replaceThisWithSelf(replaced);
650
- }
651
- continue;
652
- }
653
-
654
- if (key === "dangerouslySetInnerHTML") {
655
- hasDangerousHTML = true;
656
- if (this.t.isJSXExpressionContainer(attr.value)) {
657
- this.observableManager.collectObservables(
658
- attr.value.expression,
659
- context.observables,
660
- this.astUtils
661
- );
662
- const replaced = this.observableManager.replaceObservablesWithSignals(
663
- attr.value.expression as BabelTypes.Expression,
664
- context.observableSignals,
665
- this.astUtils
666
- );
667
- dangerousHTMLValue = this.astUtils.replaceThisWithSelf(replaced);
668
- }
669
- continue;
670
- }
671
-
672
- if (/^on[A-Z]/.test(key)) {
673
- this.processEventListener(key, attr, elId, statements, context);
674
- continue;
675
- }
676
-
677
- if (key === "style" && this.t.isJSXExpressionContainer(attr.value)) {
678
- this.processStyleAttribute(attr, elId, statements, scope, context);
679
- continue;
680
- }
681
-
682
- this.processRegularAttribute(key, attr, elId, statements, context);
683
- }
684
-
685
- return { hasRef, refValue, hasDangerousHTML, dangerousHTMLValue };
686
- }
687
-
688
- private processEventListener(
689
- key: string,
690
- attr: BabelTypes.JSXAttribute,
691
- elId: BabelTypes.Identifier,
692
- statements: BabelTypes.Statement[],
693
- context: TransformContext
694
- ): void {
695
- const eventName = key.slice(2).toLowerCase();
696
- let handler: BabelTypes.Expression = this.t.nullLiteral();
697
-
698
- if (this.t.isJSXExpressionContainer(attr.value)) {
699
- this.observableManager.collectObservables(
700
- attr.value.expression,
701
- context.observables,
702
- this.astUtils
703
- );
704
- const replaced = this.observableManager.replaceObservablesWithSignals(
705
- attr.value.expression as BabelTypes.Expression,
706
- context.observableSignals,
707
- this.astUtils
708
- );
709
- handler = this.astUtils.replaceThisWithSelf(replaced);
710
- }
711
-
712
- statements.push(
713
- this.t.expressionStatement(
714
- this.t.callExpression(
715
- this.t.memberExpression(elId, this.t.identifier("addEventListener")),
716
- [this.t.stringLiteral(eventName), handler]
717
- )
718
- )
719
- );
720
- }
721
-
722
- private processStyleAttribute(
723
- attr: BabelTypes.JSXAttribute,
724
- elId: BabelTypes.Identifier,
725
- statements: BabelTypes.Statement[],
726
- scope: any,
727
- context: TransformContext
728
- ): void {
729
- if (!this.t.isJSXExpressionContainer(attr.value)) return;
730
-
731
- this.observableManager.collectObservables(
732
- attr.value.expression,
733
- context.observables,
734
- this.astUtils
735
- );
736
- const replaced = this.observableManager.replaceObservablesWithSignals(
737
- attr.value.expression as BabelTypes.Expression,
738
- context.observableSignals,
739
- this.astUtils
740
- );
741
-
742
- const effectCall = this.t.callExpression(this.t.identifier("$effect"), [
743
- this.t.arrowFunctionExpression(
744
- [],
745
- this.t.callExpression(this.t.identifier("$style"), [
746
- elId,
747
- this.astUtils.replaceThisWithSelf(replaced),
748
- ])
749
- ),
750
- ]);
751
- const cleanupStatements = this.astUtils.addEffectCleanup(scope, effectCall);
752
-
753
- statements.push(...cleanupStatements);
754
- }
755
-
756
- private processRegularAttribute(
757
- key: string,
758
- attr: BabelTypes.JSXAttribute,
759
- elId: BabelTypes.Identifier,
760
- statements: BabelTypes.Statement[],
761
- context: TransformContext
762
- ): void {
763
- const attrName = key === "className" ? "class" : key;
764
- let value: BabelTypes.Expression;
765
-
766
- if (this.t.isStringLiteral(attr.value)) {
767
- value = attr.value;
768
- } else if (this.t.isJSXExpressionContainer(attr.value)) {
769
- this.observableManager.collectObservables(
770
- attr.value.expression,
771
- context.observables,
772
- this.astUtils
773
- );
774
- const replaced = this.observableManager.replaceObservablesWithSignals(
775
- attr.value.expression as BabelTypes.Expression,
776
- context.observableSignals,
777
- this.astUtils
778
- );
779
- value = this.astUtils.replaceThisWithSelf(replaced);
780
- } else {
781
- value = this.t.booleanLiteral(true);
782
- }
783
-
784
- statements.push(
785
- this.t.expressionStatement(
786
- this.t.callExpression(
787
- this.t.memberExpression(elId, this.t.identifier("setAttribute")),
788
- [this.t.stringLiteral(attrName), value]
789
- )
790
- )
791
- );
792
- }
793
-
794
- private processChildren(
795
- children: Array<
796
- | BabelTypes.JSXText
797
- | BabelTypes.JSXExpressionContainer
798
- | BabelTypes.JSXElement
799
- | BabelTypes.JSXFragment
800
- | BabelTypes.JSXSpreadChild
801
- >,
802
- childExpressions: Array<BabelTypes.Expression>,
803
- statements: BabelTypes.Statement[],
804
- scope: any,
805
- context: TransformContext
806
- ): void {
807
- for (const child of children) {
808
- if (this.t.isJSXText(child)) {
809
- const text = child.value.trim();
810
- if (text) childExpressions.push(this.t.stringLiteral(text));
811
- } else if (this.t.isJSXExpressionContainer(child)) {
812
- const expr = child.expression;
813
- if (!this.t.isJSXEmptyExpression(expr)) {
814
- this.observableManager.collectObservables(
815
- expr,
816
- context.observables,
817
- this.astUtils
818
- );
819
- const replaced = this.observableManager.replaceObservablesWithSignals(
820
- expr as BabelTypes.Expression,
821
- context.observableSignals,
822
- this.astUtils
823
- );
824
- childExpressions.push(this.astUtils.replaceThisWithSelf(replaced));
825
- }
826
- } else if (this.t.isJSXElement(child) || this.t.isJSXFragment(child)) {
827
- const childEl = this.transformElement({ node: child }, scope, context);
828
- statements.push(...childEl.statements);
829
- childExpressions.push(childEl.id);
830
- }
831
- }
832
- }
833
-
834
- private processDOMChildren(
835
- children: Array<
836
- | BabelTypes.JSXText
837
- | BabelTypes.JSXExpressionContainer
838
- | BabelTypes.JSXElement
839
- | BabelTypes.JSXFragment
840
- | BabelTypes.JSXSpreadChild
841
- >,
842
- parentId: BabelTypes.Identifier,
843
- statements: BabelTypes.Statement[],
844
- scope: any,
845
- context: TransformContext
846
- ): void {
847
- for (const child of children) {
848
- if (this.t.isJSXText(child)) {
849
- const text = child.value.trim();
850
- if (!text) continue;
851
- statements.push(
852
- this.t.expressionStatement(
853
- this.t.callExpression(this.t.identifier("$insert"), [
854
- parentId,
855
- this.t.stringLiteral(text),
856
- ])
857
- )
858
- );
859
- } else if (this.t.isJSXExpressionContainer(child)) {
860
- const expr = child.expression;
861
- if (this.t.isJSXEmptyExpression(expr)) continue;
862
-
863
- this.observableManager.collectObservables(
864
- expr,
865
- context.observables,
866
- this.astUtils
867
- );
868
-
869
- let insertedValue: BabelTypes.Expression;
870
- if (this.guards.isSignalMember(expr)) {
871
- insertedValue = this.astUtils.getObject(
872
- expr as BabelTypes.Expression
873
- );
874
- } else if (this.guards.isObservableMember(expr)) {
875
- const replaced = this.observableManager.replaceObservablesWithSignals(
876
- expr as BabelTypes.Expression,
877
- context.observableSignals,
878
- this.astUtils
879
- );
880
- insertedValue = this.astUtils.getObject(replaced);
881
- } else {
882
- const replaced = this.observableManager.replaceObservablesWithSignals(
883
- expr as BabelTypes.Expression,
884
- context.observableSignals,
885
- this.astUtils
886
- );
887
- insertedValue = this.t.arrowFunctionExpression(
888
- [],
889
- this.astUtils.replaceThisWithSelf(replaced)
890
- );
891
- }
892
-
893
- statements.push(
894
- this.t.expressionStatement(
895
- this.t.callExpression(this.t.identifier("$insert"), [
896
- parentId,
897
- insertedValue,
898
- ])
899
- )
900
- );
901
- } else if (this.t.isJSXElement(child) || this.t.isJSXFragment(child)) {
902
- const childEl = this.transformElement({ node: child }, scope, context);
903
- statements.push(...childEl.statements);
904
- statements.push(
905
- this.t.expressionStatement(
906
- this.t.callExpression(this.t.identifier("$insert"), [
907
- parentId,
908
- childEl.id,
909
- ])
910
- )
911
- );
912
- }
913
- }
914
- }
915
- }
916
-
917
- export function j2d({ types: t }: PluginContext): PluginObj<PluginState> {
918
- const guards = new NodeTypeGuards(t);
919
- const astUtils = new ASTUtilities(t, guards);
920
- const jsxUtils = new JSXUtilities(t);
921
- const observableManager = new ObservableManager(t, guards);
922
- const elementTransformer = new ElementTransformer(
923
- t,
924
- guards,
925
- astUtils,
926
- jsxUtils,
927
- observableManager
928
- );
929
-
930
- return {
931
- name: "jsx-to-dom",
932
- visitor: {
933
- Program: {
934
- exit(path: NodePath<BabelTypes.Program>, state: PluginState) {
935
- if (state.helpersImported) return;
936
-
937
- const helpers = [
938
- { local: "$insert", imported: "insert" },
939
- { local: "$createComponent", imported: "createComponent" },
940
- { local: "$style", imported: "style" },
941
- { local: "$spread", imported: "spread" },
942
- { local: "$toSignal", imported: "toSignal" },
943
- { local: "$effect", imported: "effect" },
944
- ];
945
-
946
- for (const helper of helpers) {
947
- path.unshiftContainer(
948
- "body",
949
- t.importDeclaration(
950
- [
951
- t.importSpecifier(
952
- t.identifier(helper.local),
953
- t.identifier(helper.imported)
954
- ),
955
- ],
956
- t.stringLiteral("@kithinji/orca")
957
- )
958
- );
959
- }
960
-
961
- state.helpersImported = true;
962
- },
963
- },
964
-
965
- ClassMethod(path: NodePath<BabelTypes.ClassMethod>) {
966
- if (path.getData("processed")) return;
967
-
968
- // Check if method contains JSX
969
- let hasJSX = false;
970
- path.traverse({
971
- JSXElement() {
972
- hasJSX = true;
973
- },
974
- JSXFragment() {
975
- hasJSX = true;
976
- },
977
- });
978
-
979
- if (!hasJSX) return;
980
- path.setData("processed", true);
981
-
982
- const body = path.node.body;
983
- if (!t.isBlockStatement(body)) return;
984
-
985
- const observables = new Map<string, BabelTypes.Expression>();
986
- path.traverse({
987
- JSXElement(jsxPath: NodePath<BabelTypes.JSXElement>) {
988
- observableManager.collectObservables(
989
- jsxPath.node,
990
- observables,
991
- astUtils
992
- );
993
- },
994
- JSXFragment(jsxPath: NodePath<BabelTypes.JSXFragment>) {
995
- observableManager.collectObservables(
996
- jsxPath.node,
997
- observables,
998
- astUtils
999
- );
1000
- },
1001
- });
1002
-
1003
- body.body.unshift(
1004
- t.variableDeclaration("const", [
1005
- t.variableDeclarator(t.identifier("self"), t.thisExpression()),
1006
- ])
1007
- );
1008
-
1009
- const observableSignals = new Map<string, BabelTypes.Identifier>();
1010
- const signalDeclarations: BabelTypes.Statement[] = [];
1011
-
1012
- for (const [key, observable] of observables) {
1013
- const signalId = path.scope.generateUidIdentifier("sig");
1014
- observableSignals.set(key, signalId);
1015
- signalDeclarations.push(
1016
- t.variableDeclaration("const", [
1017
- t.variableDeclarator(
1018
- signalId,
1019
- t.callExpression(t.identifier("$toSignal"), [
1020
- observable,
1021
- t.identifier("self"),
1022
- ])
1023
- ),
1024
- ])
1025
- );
1026
- }
1027
-
1028
- if (signalDeclarations.length > 0) {
1029
- astUtils.insertBeforeReturn(body.body, signalDeclarations);
1030
- }
1031
-
1032
- const context: TransformContext = { observables, observableSignals };
1033
-
1034
- // Transform JSX elements and fragments
1035
- path.traverse({
1036
- JSXElement(jsxPath: NodePath<BabelTypes.JSXElement>) {
1037
- if (jsxPath.getData("processed")) return;
1038
- jsxPath.setData("processed", true);
1039
-
1040
- const { id, statements } = elementTransformer.transformElement(
1041
- jsxPath as any,
1042
- jsxPath.scope,
1043
- context
1044
- );
1045
-
1046
- jsxPath.replaceWith(
1047
- t.callExpression(
1048
- t.arrowFunctionExpression(
1049
- [],
1050
- t.blockStatement([...statements, t.returnStatement(id)])
1051
- ),
1052
- []
1053
- )
1054
- );
1055
- },
1056
- JSXFragment(jsxPath: NodePath<BabelTypes.JSXFragment>) {
1057
- if (jsxPath.getData("processed")) return;
1058
- jsxPath.setData("processed", true);
1059
-
1060
- const { id, statements } = elementTransformer.transformElement(
1061
- jsxPath as any,
1062
- jsxPath.scope,
1063
- context
1064
- );
1065
-
1066
- jsxPath.replaceWith(
1067
- t.callExpression(
1068
- t.arrowFunctionExpression(
1069
- [],
1070
- t.blockStatement([...statements, t.returnStatement(id)])
1071
- ),
1072
- []
1073
- )
1074
- );
1075
- },
1076
- });
1077
- },
1078
- },
1079
- };
1080
- }