@sigil-dev/compiler 0.7.7 → 0.8.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/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@sigil-dev/compiler",
3
3
  "module": "index.ts",
4
4
  "type": "module",
5
- "version": "0.7.7",
5
+ "version": "0.8.0",
6
6
  "private": false,
7
7
  "description": "Compiler for the Sigil framework",
8
8
  "peerDependencies": {
@@ -1,59 +1,101 @@
1
1
  import { types as t } from "@babel/core";
2
2
 
3
3
  export const ATTR_MAP: Record<string, string> = {
4
- class: "className",
5
- for: "htmlFor",
4
+ class: "className",
5
+ for: "htmlFor",
6
6
  };
7
7
 
8
8
  export function containsSignal(
9
- expr: t.Expression,
10
- signals: Set<string>,
9
+ expr: t.Expression | t.Node,
10
+ signals: Set<string>,
11
11
  ): boolean {
12
- if (t.isIdentifier(expr)) return signals.has(expr.name);
13
- if (t.isCallExpression(expr)) {
14
- return containsSignal(expr.callee as t.Expression, signals);
15
- }
16
- if (t.isBinaryExpression(expr)) {
17
- return (
18
- containsSignal(expr.left as t.Expression, signals) ||
19
- containsSignal(expr.right, signals)
20
- );
21
- }
22
- if (t.isMemberExpression(expr)) {
23
- return containsSignal(expr.object as t.Expression, signals);
24
- }
25
- if (t.isLogicalExpression(expr)) {
26
- return (
27
- containsSignal(expr.left as t.Expression, signals) ||
28
- containsSignal(expr.right as t.Expression, signals)
29
- );
30
- }
31
- if (t.isConditionalExpression(expr)) {
32
- return (
33
- containsSignal(expr.test as t.Expression, signals) ||
34
- containsSignal(expr.consequent as t.Expression, signals) ||
35
- containsSignal(expr.alternate as t.Expression, signals)
36
- );
37
- }
38
- if (t.isUnaryExpression(expr)) {
39
- return containsSignal(expr.argument as t.Expression, signals);
40
- }
41
- if (t.isTemplateLiteral(expr)) {
42
- return expr.expressions.some((e) =>
43
- containsSignal(e as t.Expression, signals),
44
- );
45
- }
46
- return false;
12
+ if (!expr) return false;
13
+ if (t.isIdentifier(expr)) return signals.has(expr.name);
14
+ if (t.isCallExpression(expr)) {
15
+ return (
16
+ containsSignal(expr.callee as t.Expression, signals) ||
17
+ expr.arguments.some((a) => containsSignal(a as t.Expression, signals))
18
+ );
19
+ }
20
+ if (t.isBinaryExpression(expr)) {
21
+ return (
22
+ containsSignal(expr.left as t.Expression, signals) ||
23
+ containsSignal(expr.right, signals)
24
+ );
25
+ }
26
+ if (t.isMemberExpression(expr)) {
27
+ return containsSignal(expr.object as t.Expression, signals);
28
+ }
29
+ if (t.isLogicalExpression(expr)) {
30
+ return (
31
+ containsSignal(expr.left as t.Expression, signals) ||
32
+ containsSignal(expr.right as t.Expression, signals)
33
+ );
34
+ }
35
+ if (t.isConditionalExpression(expr)) {
36
+ return (
37
+ containsSignal(expr.test as t.Expression, signals) ||
38
+ containsSignal(expr.consequent as t.Expression, signals) ||
39
+ containsSignal(expr.alternate as t.Expression, signals)
40
+ );
41
+ }
42
+ if (t.isUnaryExpression(expr)) {
43
+ return containsSignal(expr.argument as t.Expression, signals);
44
+ }
45
+ if (t.isTemplateLiteral(expr)) {
46
+ return expr.expressions.some((e) =>
47
+ containsSignal(e as t.Expression, signals),
48
+ );
49
+ }
50
+ // ── additions ──
51
+ if (t.isArrayExpression(expr)) {
52
+ return expr.elements.some(
53
+ (e) => e !== null && containsSignal(e as t.Expression, signals),
54
+ );
55
+ }
56
+ if (t.isObjectExpression(expr)) {
57
+ return expr.properties.some((p) => {
58
+ if (t.isObjectProperty(p)) return containsSignal(p.value as t.Expression, signals);
59
+ if (t.isSpreadElement(p)) return containsSignal(p.argument, signals);
60
+ return false;
61
+ });
62
+ }
63
+ if (t.isSequenceExpression(expr)) {
64
+ return expr.expressions.some((e) => containsSignal(e, signals));
65
+ }
66
+ if (t.isAssignmentExpression(expr)) {
67
+ return containsSignal(expr.right, signals);
68
+ }
69
+ if (t.isSpreadElement(expr)) {
70
+ return containsSignal(expr.argument, signals);
71
+ }
72
+ // ArrowFunction/Function — don't traverse, signals inside are captured
73
+ // not reactive at the call site (onclick={() => count()} is fine as-is)
74
+ if (t.isArrowFunctionExpression(expr) || t.isFunctionExpression(expr)) {
75
+ return false;
76
+ }
77
+ // Babel represents ?. as distinct node types not in t.is* guards
78
+ if ((expr as any).type === "OptionalMemberExpression") {
79
+ return containsSignal((expr as any).object, signals);
80
+ }
81
+ if ((expr as any).type === "OptionalCallExpression") {
82
+ const n = expr as any;
83
+ return (
84
+ containsSignal(n.callee, signals) ||
85
+ n.arguments.some((a: t.Node) => containsSignal(a, signals))
86
+ );
87
+ }
88
+ return false;
47
89
  }
48
90
 
49
91
  export function isPrimitive(expr: t.Expression): boolean {
50
- if (t.isCallExpression(expr) && t.isIdentifier(expr.callee)) return true;
51
- if (t.isBinaryExpression(expr)) return true;
52
- if (t.isTemplateLiteral(expr)) return true;
53
- if (t.isIdentifier(expr)) return true;
54
- // user().name is a MemberExpression after state handler rewrites user → user()
55
- if (t.isMemberExpression(expr)) return true;
56
- return false;
92
+ if (t.isCallExpression(expr) && t.isIdentifier(expr.callee)) return true;
93
+ if (t.isBinaryExpression(expr)) return true;
94
+ if (t.isTemplateLiteral(expr)) return true;
95
+ if (t.isIdentifier(expr)) return true;
96
+ // user().name is a MemberExpression after state handler rewrites user → user()
97
+ if (t.isMemberExpression(expr)) return true;
98
+ return false;
57
99
  }
58
100
 
59
101
  /**
@@ -61,22 +103,22 @@ export function isPrimitive(expr: t.Expression): boolean {
61
103
  * When parentVar is provided, passes it to claim() for SPA fallback (append on create).
62
104
  */
63
105
  export function getCreateElement(
64
- tag: string,
65
- hydrate: boolean,
66
- nodesVar = "__nodes",
67
- parentVar?: string,
106
+ tag: string,
107
+ hydrate: boolean,
108
+ nodesVar = "__nodes",
109
+ parentVar?: string,
68
110
  ): t.Expression {
69
- if (hydrate) {
70
- const args: t.Expression[] = [t.identifier(nodesVar), t.stringLiteral(tag)];
71
- if (parentVar) {
72
- args.push(t.identifier(parentVar));
73
- }
74
- return t.callExpression(t.identifier("claim"), args);
75
- }
76
- return t.callExpression(
77
- t.memberExpression(t.identifier("document"), t.identifier("createElement")),
78
- [t.stringLiteral(tag)],
79
- );
111
+ if (hydrate) {
112
+ const args: t.Expression[] = [t.identifier(nodesVar), t.stringLiteral(tag)];
113
+ if (parentVar) {
114
+ args.push(t.identifier(parentVar));
115
+ }
116
+ return t.callExpression(t.identifier("claim"), args);
117
+ }
118
+ return t.callExpression(
119
+ t.memberExpression(t.identifier("document"), t.identifier("createElement")),
120
+ [t.stringLiteral(tag)],
121
+ );
80
122
  }
81
123
 
82
124
  /**
@@ -84,24 +126,24 @@ export function getCreateElement(
84
126
  * When parentVar is provided, passes it to claimText() for SPA fallback.
85
127
  */
86
128
  export function getCreateText(
87
- hydrate: boolean,
88
- nodesVar = "__nodes",
89
- parentVar?: string,
129
+ hydrate: boolean,
130
+ nodesVar = "__nodes",
131
+ parentVar?: string,
90
132
  ): t.Expression {
91
- if (hydrate) {
92
- const args: t.Expression[] = [t.identifier(nodesVar)];
93
- if (parentVar) {
94
- args.push(t.identifier(parentVar));
95
- }
96
- return t.callExpression(t.identifier("claimText"), args);
97
- }
98
- return t.callExpression(
99
- t.memberExpression(
100
- t.identifier("document"),
101
- t.identifier("createTextNode"),
102
- ),
103
- [t.stringLiteral("")],
104
- );
133
+ if (hydrate) {
134
+ const args: t.Expression[] = [t.identifier(nodesVar)];
135
+ if (parentVar) {
136
+ args.push(t.identifier(parentVar));
137
+ }
138
+ return t.callExpression(t.identifier("claimText"), args);
139
+ }
140
+ return t.callExpression(
141
+ t.memberExpression(
142
+ t.identifier("document"),
143
+ t.identifier("createTextNode"),
144
+ ),
145
+ [t.stringLiteral("")],
146
+ );
105
147
  }
106
148
 
107
149
  /**
@@ -109,24 +151,24 @@ export function getCreateText(
109
151
  * Returns the generated variable name for use by children.
110
152
  */
111
153
  export function buildHydrationScope(
112
- parentVar: string,
113
- statements: t.Statement[],
114
- nodesVar: string,
154
+ parentVar: string,
155
+ statements: t.Statement[],
156
+ nodesVar: string,
115
157
  ): void {
116
- statements.push(
117
- t.variableDeclaration("const", [
118
- t.variableDeclarator(
119
- t.identifier(nodesVar),
120
- t.callExpression(
121
- t.memberExpression(t.identifier("Array"), t.identifier("from")),
122
- [
123
- t.memberExpression(
124
- t.identifier(parentVar),
125
- t.identifier("childNodes"),
126
- ),
127
- ],
128
- ),
129
- ),
130
- ]),
131
- );
158
+ statements.push(
159
+ t.variableDeclaration("const", [
160
+ t.variableDeclarator(
161
+ t.identifier(nodesVar),
162
+ t.callExpression(
163
+ t.memberExpression(t.identifier("Array"), t.identifier("from")),
164
+ [
165
+ t.memberExpression(
166
+ t.identifier(parentVar),
167
+ t.identifier("childNodes"),
168
+ ),
169
+ ],
170
+ ),
171
+ ),
172
+ ]),
173
+ );
132
174
  }