juxscript 1.1.279 → 1.1.281
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/machinery/autowrap.js +132 -16
- package/package.json +1 -1
package/machinery/autowrap.js
CHANGED
|
@@ -69,20 +69,36 @@ function isAlreadyWrapped(stmt) {
|
|
|
69
69
|
stmt.expression?.callee?.property?.name === '__watch';
|
|
70
70
|
}
|
|
71
71
|
|
|
72
|
+
/**
|
|
73
|
+
* Extract the body statements from an existing __watch callback.
|
|
74
|
+
* Returns null if the statement is not a __watch or has no block body.
|
|
75
|
+
*/
|
|
76
|
+
function getWatchBody(stmt) {
|
|
77
|
+
if (!isAlreadyWrapped(stmt)) return null;
|
|
78
|
+
const arg = stmt.expression.arguments?.[0];
|
|
79
|
+
if (!arg) return null;
|
|
80
|
+
if (arg.type === 'ArrowFunctionExpression' || arg.type === 'FunctionExpression') {
|
|
81
|
+
if (arg.body?.type === 'BlockStatement') {
|
|
82
|
+
return arg.body.body; // array of statements
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
return null;
|
|
86
|
+
}
|
|
87
|
+
|
|
72
88
|
function isSetupStatement(stmt) {
|
|
89
|
+
// Never treat statements referencing pageState as setup
|
|
90
|
+
if (containsPageStateRef(stmt)) return false;
|
|
91
|
+
|
|
73
92
|
if (stmt.type === 'ImportDeclaration') return true;
|
|
74
93
|
if (stmt.type === 'FunctionDeclaration') return true;
|
|
75
94
|
if (stmt.type === 'ExpressionStatement') {
|
|
76
95
|
const expr = stmt.expression;
|
|
77
96
|
if (expr.type === 'CallExpression' &&
|
|
78
|
-
expr.callee?.object?.name === 'jux'
|
|
79
|
-
!containsPageStateRef(stmt)) return true;
|
|
97
|
+
expr.callee?.object?.name === 'jux') return true;
|
|
80
98
|
if (expr.type === 'AwaitExpression' &&
|
|
81
|
-
expr.argument?.callee?.object?.name === 'jux'
|
|
82
|
-
!containsPageStateRef(stmt)) return true;
|
|
99
|
+
expr.argument?.callee?.object?.name === 'jux') return true;
|
|
83
100
|
}
|
|
84
|
-
if (stmt.type === 'VariableDeclaration'
|
|
85
|
-
if (stmt.type === 'VariableDeclaration' && containsJuxCall(stmt) && !containsPageStateRef(stmt)) return true;
|
|
101
|
+
if (stmt.type === 'VariableDeclaration') return true;
|
|
86
102
|
return false;
|
|
87
103
|
}
|
|
88
104
|
|
|
@@ -119,7 +135,30 @@ export function autowrap(source, filename = '') {
|
|
|
119
135
|
const stmt = ast.body[i];
|
|
120
136
|
|
|
121
137
|
if (isSetupStatement(stmt)) { i++; continue; }
|
|
122
|
-
|
|
138
|
+
|
|
139
|
+
// Check if this is a single __watch that contains multiple independent concerns
|
|
140
|
+
// If so, unwrap it and re-wrap each concern separately
|
|
141
|
+
if (isAlreadyWrapped(stmt)) {
|
|
142
|
+
const bodyStmts = getWatchBody(stmt);
|
|
143
|
+
if (bodyStmts && bodyStmts.length > 1) {
|
|
144
|
+
// Check if the body has multiple independent reactive groups
|
|
145
|
+
const groups = groupBodyStatements(bodyStmts, source);
|
|
146
|
+
if (groups.length > 1) {
|
|
147
|
+
// Replace single watch with multiple watches
|
|
148
|
+
// Record the original watch range for removal
|
|
149
|
+
const watchStart = getLineNumber(source, stmt.start);
|
|
150
|
+
const watchEnd = getLineNumber(source, stmt.end);
|
|
151
|
+
needsWatch.push({
|
|
152
|
+
line: watchStart,
|
|
153
|
+
endLine: watchEnd,
|
|
154
|
+
replace: true,
|
|
155
|
+
groups: groups,
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
i++;
|
|
160
|
+
continue;
|
|
161
|
+
}
|
|
123
162
|
|
|
124
163
|
// VariableDeclaration reading pageState — group with subsequent stmts that use declared vars
|
|
125
164
|
if (stmt.type === 'VariableDeclaration' && containsPageStateRef(stmt)) {
|
|
@@ -172,17 +211,33 @@ export function autowrap(source, filename = '') {
|
|
|
172
211
|
for (const item of sorted) {
|
|
173
212
|
const startIdx = item.line - 1;
|
|
174
213
|
const endIdx = item.endLine - 1;
|
|
175
|
-
const blockLines = lines.slice(startIdx, endIdx + 1);
|
|
176
|
-
const indent = blockLines[0].match(/^(\s*)/)[1];
|
|
177
214
|
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
215
|
+
if (item.replace && item.groups) {
|
|
216
|
+
// Replace a single big __watch with multiple smaller ones
|
|
217
|
+
const indent = lines[startIdx].match(/^(\s*)/)[1];
|
|
218
|
+
const newLines = [];
|
|
219
|
+
for (const group of item.groups) {
|
|
220
|
+
newLines.push(`${indent}pageState.__watch(() => {`);
|
|
221
|
+
for (const gLine of group.lines) {
|
|
222
|
+
newLines.push(`${indent} ${gLine.trim()}`);
|
|
223
|
+
}
|
|
224
|
+
newLines.push(`${indent}});`);
|
|
225
|
+
}
|
|
226
|
+
lines.splice(startIdx, endIdx - startIdx + 1, ...newLines);
|
|
227
|
+
details.push(`L${item.line}-${item.endLine} (split ${item.groups.length})`);
|
|
228
|
+
} else {
|
|
229
|
+
const blockLines = lines.slice(startIdx, endIdx + 1);
|
|
230
|
+
const indent = blockLines[0].match(/^(\s*)/)[1];
|
|
231
|
+
|
|
232
|
+
const wrapped = [
|
|
233
|
+
`${indent}pageState.__watch(() => {`,
|
|
234
|
+
...blockLines.map(l => `${indent} ${l.trim()}`),
|
|
235
|
+
`${indent}});`,
|
|
236
|
+
];
|
|
183
237
|
|
|
184
|
-
|
|
185
|
-
|
|
238
|
+
lines.splice(startIdx, endIdx - startIdx + 1, ...wrapped);
|
|
239
|
+
details.push(`L${item.line}-${item.endLine}`);
|
|
240
|
+
}
|
|
186
241
|
}
|
|
187
242
|
|
|
188
243
|
return {
|
|
@@ -191,3 +246,64 @@ export function autowrap(source, filename = '') {
|
|
|
191
246
|
details
|
|
192
247
|
};
|
|
193
248
|
}
|
|
249
|
+
|
|
250
|
+
/**
|
|
251
|
+
* Groups statements inside a __watch body into independent reactive groups.
|
|
252
|
+
* Uses the same logic as the top-level grouping: VariableDeclarations that
|
|
253
|
+
* read pageState get grouped with following statements that use those vars.
|
|
254
|
+
* Standalone if-statements with pageState become their own group.
|
|
255
|
+
*/
|
|
256
|
+
function groupBodyStatements(bodyStmts, source) {
|
|
257
|
+
const groups = [];
|
|
258
|
+
let i = 0;
|
|
259
|
+
|
|
260
|
+
while (i < bodyStmts.length) {
|
|
261
|
+
const stmt = bodyStmts[i];
|
|
262
|
+
|
|
263
|
+
// VariableDeclaration reading pageState — group with dependents
|
|
264
|
+
if (stmt.type === 'VariableDeclaration' && containsPageStateRef(stmt)) {
|
|
265
|
+
const varNames = getDeclaredVarNames(stmt);
|
|
266
|
+
const groupStmts = [stmt];
|
|
267
|
+
let j = i + 1;
|
|
268
|
+
|
|
269
|
+
while (j < bodyStmts.length) {
|
|
270
|
+
const next = bodyStmts[j];
|
|
271
|
+
if (varNames.some(v => usesIdentifier(next, v))) {
|
|
272
|
+
groupStmts.push(next);
|
|
273
|
+
j++;
|
|
274
|
+
} else {
|
|
275
|
+
break;
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
groups.push({
|
|
280
|
+
stmts: groupStmts,
|
|
281
|
+
lines: extractSourceLines(groupStmts, source),
|
|
282
|
+
});
|
|
283
|
+
i = j;
|
|
284
|
+
continue;
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
// Any statement referencing pageState — standalone group
|
|
288
|
+
if (containsPageStateRef(stmt)) {
|
|
289
|
+
groups.push({
|
|
290
|
+
stmts: [stmt],
|
|
291
|
+
lines: extractSourceLines([stmt], source),
|
|
292
|
+
});
|
|
293
|
+
i++;
|
|
294
|
+
continue;
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
// Non-reactive statement — attach to next reactive group or skip
|
|
298
|
+
i++;
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
return groups;
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
function extractSourceLines(stmts, source) {
|
|
305
|
+
if (stmts.length === 0) return [];
|
|
306
|
+
const start = stmts[0].start;
|
|
307
|
+
const end = stmts[stmts.length - 1].end;
|
|
308
|
+
return source.slice(start, end).split('\n');
|
|
309
|
+
}
|