octane 0.1.39 → 0.1.40
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/version.cjs +1 -1
- package/dist/compiler/compile.js +4 -3
- package/dist/compiler/hook-deps.js +210 -40
- package/dist/compiler/parser.browser.js +1 -0
- package/dist/compiler/parser.node.js +1 -0
- package/dist/compiler/strong-mode.js +764 -170
- package/dist/version.js +1 -1
- package/package.json +11 -4
package/dist/cjs/version.cjs
CHANGED
|
@@ -21,7 +21,7 @@ __export(version_exports, {
|
|
|
21
21
|
version: () => version
|
|
22
22
|
});
|
|
23
23
|
module.exports = __toCommonJS(version_exports);
|
|
24
|
-
const version = "0.1.
|
|
24
|
+
const version = "0.1.40";
|
|
25
25
|
// Annotate the CommonJS export names for ESM import in node:
|
|
26
26
|
0 && (module.exports = {
|
|
27
27
|
version
|
package/dist/compiler/compile.js
CHANGED
|
@@ -3,8 +3,9 @@
|
|
|
3
3
|
* runtime.
|
|
4
4
|
*
|
|
5
5
|
* Architecture:
|
|
6
|
-
* 1. Parse TSRX
|
|
7
|
-
*
|
|
6
|
+
* 1. Parse TSRX through the environment-selected @tsrx/core-compatible
|
|
7
|
+
* parser (native oxc-tsrx in Node, pure JavaScript elsewhere), then run
|
|
8
|
+
* @tsrx/core's target-neutral semantic analysis on the authored module.
|
|
8
9
|
* 2. For each top-level node:
|
|
9
10
|
* - Component (`@{ … }` body or a return-JSX function) → compile to a
|
|
10
11
|
* function taking the props-first ABI `(…userParams, __s, __extra)`.
|
|
@@ -30,7 +31,6 @@
|
|
|
30
31
|
import {
|
|
31
32
|
analyzeCss,
|
|
32
33
|
analyzeTsrx,
|
|
33
|
-
parseModule,
|
|
34
34
|
prepareStylesheetForRender,
|
|
35
35
|
renderStylesheets,
|
|
36
36
|
builders as b,
|
|
@@ -38,6 +38,7 @@ import {
|
|
|
38
38
|
clone_ast_node as cloneAstNode,
|
|
39
39
|
strongHash,
|
|
40
40
|
} from '@tsrx/core';
|
|
41
|
+
import { parseModule } from '#octane/compiler-parser';
|
|
41
42
|
import { print as esrapPrint } from 'esrap';
|
|
42
43
|
import esrapTsx from 'esrap/languages/tsx';
|
|
43
44
|
import { buildFatSegments } from './fat-segments.js';
|
|
@@ -118,12 +118,14 @@ function unwrapExport(node) {
|
|
|
118
118
|
return node;
|
|
119
119
|
}
|
|
120
120
|
|
|
121
|
-
function predeclareDirect(statements, scope, hookRuntimeModules) {
|
|
121
|
+
function predeclareDirect(statements, scope, hookRuntimeModules, bindingsOnly = false) {
|
|
122
122
|
for (const original of statements || []) {
|
|
123
123
|
if (original.type === 'ImportDeclaration') {
|
|
124
|
+
if (bindingsOnly && original.importKind === 'type') continue;
|
|
124
125
|
const isHookRuntime = hookRuntimeModules.has(original.source?.value);
|
|
125
126
|
const isOctane = original.source?.value === 'octane';
|
|
126
127
|
for (const specifier of original.specifiers || []) {
|
|
128
|
+
if (bindingsOnly && specifier.importKind === 'type') continue;
|
|
127
129
|
const imported = specifier.imported?.name;
|
|
128
130
|
declareName(scope, specifier.local.name, {
|
|
129
131
|
imported: true,
|
|
@@ -156,19 +158,29 @@ function predeclareDirect(statements, scope, hookRuntimeModules) {
|
|
|
156
158
|
}
|
|
157
159
|
}
|
|
158
160
|
|
|
159
|
-
function collectHoistedVars(node, functionScope, root = true) {
|
|
161
|
+
function collectHoistedVars(node, functionScope, root = true, bindingsOnly = false) {
|
|
160
162
|
if (!node || typeof node !== 'object') return;
|
|
161
163
|
if (Array.isArray(node)) {
|
|
162
|
-
for (const child of node) collectHoistedVars(child, functionScope, false);
|
|
164
|
+
for (const child of node) collectHoistedVars(child, functionScope, false, bindingsOnly);
|
|
163
165
|
return;
|
|
164
166
|
}
|
|
165
167
|
if (!root && isFunction(node)) return;
|
|
168
|
+
if (
|
|
169
|
+
bindingsOnly &&
|
|
170
|
+
(isFunction(node) ||
|
|
171
|
+
(!root && node.type === 'StaticBlock') ||
|
|
172
|
+
node.type === 'ClassDeclaration' ||
|
|
173
|
+
node.type === 'ClassExpression' ||
|
|
174
|
+
node.type === 'TSModuleDeclaration')
|
|
175
|
+
) {
|
|
176
|
+
return;
|
|
177
|
+
}
|
|
166
178
|
if (node.type === 'VariableDeclaration' && node.kind === 'var') {
|
|
167
179
|
for (const decl of node.declarations || []) declarePattern(decl.id, functionScope);
|
|
168
180
|
}
|
|
169
181
|
for (const key in node) {
|
|
170
182
|
if (AST_META_KEYS.has(key)) continue;
|
|
171
|
-
collectHoistedVars(node[key], functionScope, false);
|
|
183
|
+
collectHoistedVars(node[key], functionScope, false, bindingsOnly);
|
|
172
184
|
}
|
|
173
185
|
}
|
|
174
186
|
|
|
@@ -277,7 +289,7 @@ function markReassignedPattern(pattern, scope) {
|
|
|
277
289
|
}
|
|
278
290
|
}
|
|
279
291
|
|
|
280
|
-
function buildScopes(ast, onlyImported, hookRuntimeModules) {
|
|
292
|
+
function buildScopes(ast, onlyImported, hookRuntimeModules, bindingsOnly = false) {
|
|
281
293
|
nextBindingId = 0;
|
|
282
294
|
const moduleScope = createScope(null, 'module');
|
|
283
295
|
const nodeScopes = new WeakMap();
|
|
@@ -289,8 +301,35 @@ function buildScopes(ast, onlyImported, hookRuntimeModules) {
|
|
|
289
301
|
const functionRecords = new WeakMap();
|
|
290
302
|
const trustedHookNames = new WeakMap();
|
|
291
303
|
const callAnnotations = new Map();
|
|
292
|
-
|
|
293
|
-
|
|
304
|
+
const declarationBindings = bindingsOnly ? new Map() : null;
|
|
305
|
+
const firstDefinitions = bindingsOnly ? new Map() : null;
|
|
306
|
+
predeclareDirect(ast.body, moduleScope, hookRuntimeModules, bindingsOnly);
|
|
307
|
+
collectHoistedVars(ast, moduleScope, true, bindingsOnly);
|
|
308
|
+
|
|
309
|
+
function rememberBindings(bindings, definesValue = true) {
|
|
310
|
+
if (declarationBindings === null || firstDefinitions === null) return;
|
|
311
|
+
for (const { pattern, binding } of bindings) {
|
|
312
|
+
declarationBindings.set(pattern, binding);
|
|
313
|
+
if (!definesValue) continue;
|
|
314
|
+
const previous = firstDefinitions.get(binding);
|
|
315
|
+
if (previous !== undefined && previous !== pattern) binding.reassigned = true;
|
|
316
|
+
else firstDefinitions.set(binding, pattern);
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
function rememberPattern(pattern, scope, definesValue = true) {
|
|
321
|
+
if (!bindingsOnly) return;
|
|
322
|
+
if (pattern?.type === 'TSParameterProperty') pattern = pattern.parameter;
|
|
323
|
+
const bindings = [];
|
|
324
|
+
collectPatternBindings(pattern, scope, bindings);
|
|
325
|
+
rememberBindings(bindings, definesValue);
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
function invalidateVisibleBindings(scope) {
|
|
329
|
+
for (let current = scope; current !== null; current = current.parent) {
|
|
330
|
+
for (const binding of current.bindings.values()) binding.reassigned = true;
|
|
331
|
+
}
|
|
332
|
+
}
|
|
294
333
|
|
|
295
334
|
function walk(node, scope) {
|
|
296
335
|
if (!node || typeof node !== 'object') return;
|
|
@@ -298,34 +337,103 @@ function buildScopes(ast, onlyImported, hookRuntimeModules) {
|
|
|
298
337
|
for (const child of node) walk(child, scope);
|
|
299
338
|
return;
|
|
300
339
|
}
|
|
301
|
-
nodeScopes.set(node, scope);
|
|
340
|
+
if (!bindingsOnly) nodeScopes.set(node, scope);
|
|
341
|
+
if (
|
|
342
|
+
bindingsOnly &&
|
|
343
|
+
(node.type === 'TSInstantiationExpression' || node.type === 'TSExportAssignment')
|
|
344
|
+
) {
|
|
345
|
+
walk(node.expression, scope);
|
|
346
|
+
return;
|
|
347
|
+
}
|
|
302
348
|
|
|
303
349
|
if (isFunction(node)) {
|
|
304
350
|
const fnScope = createScope(scope, 'function');
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
351
|
+
const record = bindingsOnly
|
|
352
|
+
? null
|
|
353
|
+
: {
|
|
354
|
+
node,
|
|
355
|
+
scope: fnScope,
|
|
356
|
+
binding:
|
|
357
|
+
node.type === 'FunctionDeclaration' && node.id
|
|
358
|
+
? resolveBinding(scope, node.id.name)
|
|
359
|
+
: null,
|
|
360
|
+
parameters: null,
|
|
361
|
+
stableDefinition: node.type === 'FunctionDeclaration',
|
|
362
|
+
};
|
|
363
|
+
if (record !== null) {
|
|
364
|
+
functionScopes.set(node, fnScope);
|
|
365
|
+
functions.push(record);
|
|
366
|
+
functionRecords.set(node, record);
|
|
367
|
+
}
|
|
368
|
+
if (bindingsOnly && node.type === 'FunctionDeclaration' && node.id) {
|
|
369
|
+
rememberPattern(node.id, scope);
|
|
370
|
+
}
|
|
318
371
|
if (node.type === 'FunctionExpression' && node.id) {
|
|
319
372
|
declareName(fnScope, node.id.name);
|
|
373
|
+
if (bindingsOnly) rememberPattern(node.id, fnScope);
|
|
320
374
|
}
|
|
321
375
|
if (node.type !== 'ArrowFunctionExpression') declareName(fnScope, 'arguments');
|
|
322
|
-
for (const param of node.params || [])
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
376
|
+
for (const param of node.params || []) {
|
|
377
|
+
declarePattern(
|
|
378
|
+
bindingsOnly && param.type === 'TSParameterProperty' ? param.parameter : param,
|
|
379
|
+
fnScope,
|
|
380
|
+
);
|
|
381
|
+
}
|
|
382
|
+
if (record !== null) {
|
|
383
|
+
record.parameters = (node.params || []).map((param) =>
|
|
384
|
+
directParameterBinding(param, fnScope),
|
|
385
|
+
);
|
|
386
|
+
}
|
|
387
|
+
if (bindingsOnly) {
|
|
388
|
+
for (const param of node.params || []) rememberPattern(param, fnScope);
|
|
389
|
+
// Parameter defaults cannot see declarations in the function body.
|
|
390
|
+
// Afterwards, share the direct body with the parameters so legal var
|
|
391
|
+
// and function redeclarations count as competing value definitions.
|
|
392
|
+
for (const param of node.params || []) walkPatternDefaults(param, fnScope);
|
|
393
|
+
collectHoistedVars(node.body, fnScope, true, true);
|
|
394
|
+
if (node.body?.type === 'BlockStatement' || node.body?.type === 'JSXCodeBlock') {
|
|
395
|
+
predeclareDirect(node.body.body, fnScope, hookRuntimeModules, true);
|
|
396
|
+
for (const statement of node.body.body || []) walk(statement, fnScope);
|
|
397
|
+
if (node.body.type === 'JSXCodeBlock') walk(node.body.render, fnScope);
|
|
398
|
+
} else {
|
|
399
|
+
walk(node.body, fnScope);
|
|
400
|
+
}
|
|
401
|
+
} else {
|
|
402
|
+
collectHoistedVars(node.body, fnScope);
|
|
403
|
+
for (const param of node.params || []) walkPatternDefaults(param, fnScope);
|
|
404
|
+
walk(node.body, fnScope);
|
|
405
|
+
}
|
|
406
|
+
return;
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
if (bindingsOnly && node.type === 'ImportDeclaration') {
|
|
410
|
+
if (node.importKind !== 'type') {
|
|
411
|
+
for (const specifier of node.specifiers || []) {
|
|
412
|
+
if (specifier.importKind !== 'type') rememberPattern(specifier.local, scope);
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
return;
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
if (
|
|
419
|
+
bindingsOnly &&
|
|
420
|
+
node.declare !== true &&
|
|
421
|
+
((node.type === 'TSModuleDeclaration' && node.kind !== 'global') ||
|
|
422
|
+
node.type === 'TSEnumDeclaration')
|
|
423
|
+
) {
|
|
424
|
+
// The dependency walk deliberately skips TypeScript-only syntax. Runtime
|
|
425
|
+
// namespaces and enum initializers can still write their enclosing scope.
|
|
426
|
+
invalidateVisibleBindings(scope);
|
|
427
|
+
return;
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
if (bindingsOnly && (node.type === 'ClassDeclaration' || node.type === 'ClassExpression')) {
|
|
431
|
+
if (node.type === 'ClassDeclaration' && node.id) rememberPattern(node.id, scope);
|
|
432
|
+
const classScope = createScope(scope, 'block');
|
|
433
|
+
if (node.id) declarePattern(node.id, classScope);
|
|
434
|
+
for (const decorator of node.decorators || []) walk(decorator, scope);
|
|
435
|
+
walk(node.superClass, classScope);
|
|
436
|
+
walk(node.body, classScope);
|
|
329
437
|
return;
|
|
330
438
|
}
|
|
331
439
|
|
|
@@ -334,8 +442,14 @@ function buildScopes(ast, onlyImported, hookRuntimeModules) {
|
|
|
334
442
|
node.type === 'StaticBlock' ||
|
|
335
443
|
node.type === 'JSXCodeBlock'
|
|
336
444
|
) {
|
|
337
|
-
const blockScope = createScope(
|
|
338
|
-
|
|
445
|
+
const blockScope = createScope(
|
|
446
|
+
scope,
|
|
447
|
+
bindingsOnly && node.type === 'StaticBlock' ? 'function' : 'block',
|
|
448
|
+
);
|
|
449
|
+
if (bindingsOnly && node.type === 'StaticBlock') {
|
|
450
|
+
collectHoistedVars(node, blockScope, true, true);
|
|
451
|
+
}
|
|
452
|
+
predeclareDirect(node.body, blockScope, hookRuntimeModules, bindingsOnly);
|
|
339
453
|
for (const statement of node.body || []) walk(statement, blockScope);
|
|
340
454
|
// TSRX's final render node lives beside the setup-statement list.
|
|
341
455
|
if (node.type === 'JSXCodeBlock') walk(node.render, blockScope);
|
|
@@ -345,12 +459,17 @@ function buildScopes(ast, onlyImported, hookRuntimeModules) {
|
|
|
345
459
|
if (node.type === 'CatchClause') {
|
|
346
460
|
const catchScope = createScope(scope, 'block');
|
|
347
461
|
declarePattern(node.param, catchScope);
|
|
462
|
+
if (bindingsOnly) rememberPattern(node.param, catchScope);
|
|
463
|
+
if (bindingsOnly && node.resetParam) {
|
|
464
|
+
declarePattern(node.resetParam, catchScope);
|
|
465
|
+
rememberPattern(node.resetParam, catchScope);
|
|
466
|
+
}
|
|
348
467
|
walkPatternDefaults(node.param, catchScope);
|
|
349
468
|
walk(node.body, catchScope);
|
|
350
469
|
return;
|
|
351
470
|
}
|
|
352
471
|
|
|
353
|
-
if (node.type === 'SwitchStatement') {
|
|
472
|
+
if (node.type === 'SwitchStatement' || (bindingsOnly && node.type === 'JSXSwitchExpression')) {
|
|
354
473
|
// A switch body is one lexical scope shared by every unbraced case.
|
|
355
474
|
// Predeclare the direct case statements together so let/const/function
|
|
356
475
|
// captures resolve even when their declaration appears in a case list
|
|
@@ -360,10 +479,10 @@ function buildScopes(ast, onlyImported, hookRuntimeModules) {
|
|
|
360
479
|
for (const switchCase of node.cases || []) {
|
|
361
480
|
statements.push(...(switchCase.consequent || []));
|
|
362
481
|
}
|
|
363
|
-
predeclareDirect(statements, switchScope, hookRuntimeModules);
|
|
482
|
+
predeclareDirect(statements, switchScope, hookRuntimeModules, bindingsOnly);
|
|
364
483
|
walk(node.discriminant, scope);
|
|
365
484
|
for (const switchCase of node.cases || []) {
|
|
366
|
-
nodeScopes.set(switchCase, switchScope);
|
|
485
|
+
if (!bindingsOnly) nodeScopes.set(switchCase, switchScope);
|
|
367
486
|
walk(switchCase.test, switchScope);
|
|
368
487
|
for (const statement of switchCase.consequent || []) walk(statement, switchScope);
|
|
369
488
|
}
|
|
@@ -373,32 +492,45 @@ function buildScopes(ast, onlyImported, hookRuntimeModules) {
|
|
|
373
492
|
if (
|
|
374
493
|
node.type === 'ForStatement' ||
|
|
375
494
|
node.type === 'ForInStatement' ||
|
|
376
|
-
node.type === 'ForOfStatement'
|
|
495
|
+
node.type === 'ForOfStatement' ||
|
|
496
|
+
(bindingsOnly && node.type === 'JSXForExpression')
|
|
377
497
|
) {
|
|
378
498
|
const loopScope = createScope(scope, 'block');
|
|
379
|
-
const
|
|
499
|
+
const loopType = node.type === 'JSXForExpression' ? node.statementType : node.type;
|
|
500
|
+
const declaration = loopType === 'ForStatement' ? node.init : node.left;
|
|
380
501
|
if (declaration?.type === 'VariableDeclaration' && declaration.kind !== 'var') {
|
|
381
502
|
for (const decl of declaration.declarations || []) declarePattern(decl.id, loopScope);
|
|
382
503
|
}
|
|
383
|
-
if (
|
|
504
|
+
if (loopType === 'ForStatement') {
|
|
384
505
|
walk(node.init, loopScope);
|
|
385
506
|
walk(node.test, loopScope);
|
|
386
507
|
walk(node.update, loopScope);
|
|
387
508
|
} else {
|
|
388
509
|
walk(node.left, loopScope);
|
|
389
510
|
if (node.left?.type !== 'VariableDeclaration') markReassignedPattern(node.left, loopScope);
|
|
390
|
-
|
|
511
|
+
else if (bindingsOnly && node.left.kind === 'var') {
|
|
512
|
+
for (const decl of node.left.declarations || [])
|
|
513
|
+
markReassignedPattern(decl.id, loopScope);
|
|
514
|
+
}
|
|
515
|
+
walk(node.right, node.type === 'JSXForExpression' ? scope : loopScope);
|
|
516
|
+
}
|
|
517
|
+
if (bindingsOnly && node.type === 'JSXForExpression') {
|
|
518
|
+
declarePattern(node.index, loopScope);
|
|
519
|
+
rememberPattern(node.index, loopScope);
|
|
520
|
+
walk(node.key, loopScope);
|
|
391
521
|
}
|
|
392
522
|
walk(node.body, loopScope);
|
|
523
|
+
if (bindingsOnly && node.type === 'JSXForExpression') walk(node.empty, scope);
|
|
393
524
|
return;
|
|
394
525
|
}
|
|
395
526
|
|
|
396
527
|
if (node.type === 'VariableDeclaration') {
|
|
397
528
|
for (const decl of node.declarations || []) {
|
|
398
|
-
nodeScopes.set(decl, scope);
|
|
529
|
+
if (!bindingsOnly) nodeScopes.set(decl, scope);
|
|
399
530
|
const bindings = [];
|
|
400
531
|
collectPatternBindings(decl.id, scope, bindings);
|
|
401
|
-
|
|
532
|
+
if (bindingsOnly) rememberBindings(bindings, node.kind !== 'var' || decl.init != null);
|
|
533
|
+
else declarators.push({ decl, bindings, kind: node.kind });
|
|
402
534
|
walkPatternDefaults(decl.id, scope);
|
|
403
535
|
walk(decl.init, scope);
|
|
404
536
|
}
|
|
@@ -411,7 +543,21 @@ function buildScopes(ast, onlyImported, hookRuntimeModules) {
|
|
|
411
543
|
markReassignedPattern(node.argument, scope);
|
|
412
544
|
}
|
|
413
545
|
|
|
414
|
-
if (node.type === 'CallExpression') {
|
|
546
|
+
if (bindingsOnly && node.type === 'CallExpression') {
|
|
547
|
+
let callee = unwrapValue(node.callee);
|
|
548
|
+
while (callee?.type === 'TSInstantiationExpression') {
|
|
549
|
+
callee = unwrapValue(callee.expression);
|
|
550
|
+
}
|
|
551
|
+
if (
|
|
552
|
+
node.optional !== true &&
|
|
553
|
+
callee?.type === 'Identifier' &&
|
|
554
|
+
callee.name === 'eval' &&
|
|
555
|
+
resolveBinding(scope, callee.name) === null
|
|
556
|
+
) {
|
|
557
|
+
// Direct eval can reassign any lexically reachable writable binding.
|
|
558
|
+
invalidateVisibleBindings(scope);
|
|
559
|
+
}
|
|
560
|
+
} else if (node.type === 'CallExpression') {
|
|
415
561
|
// Preserve lexical import identity for the later slotting pass. A module-
|
|
416
562
|
// level name map is insufficient: a component can shadow either a named
|
|
417
563
|
// alias or an Octane namespace inside any nested scope. The annotation is
|
|
@@ -471,6 +617,9 @@ function buildScopes(ast, onlyImported, hookRuntimeModules) {
|
|
|
471
617
|
function walkPatternDefaults(pattern, scope) {
|
|
472
618
|
if (!pattern) return;
|
|
473
619
|
switch (pattern.type) {
|
|
620
|
+
case 'TSParameterProperty':
|
|
621
|
+
if (bindingsOnly) walkPatternDefaults(pattern.parameter, scope);
|
|
622
|
+
return;
|
|
474
623
|
case 'AssignmentPattern':
|
|
475
624
|
walkPatternDefaults(pattern.left, scope);
|
|
476
625
|
walk(pattern.right, scope);
|
|
@@ -513,7 +662,9 @@ function buildScopes(ast, onlyImported, hookRuntimeModules) {
|
|
|
513
662
|
functions,
|
|
514
663
|
trustedHookNames,
|
|
515
664
|
callAnnotations,
|
|
665
|
+
declarationBindings,
|
|
516
666
|
};
|
|
667
|
+
if (bindingsOnly) return analysis;
|
|
517
668
|
// The surgical plain-TS pass slots base hooks only; without a custom-hook
|
|
518
669
|
// withSlot boundary, two local wrapper calls would share their inner slots.
|
|
519
670
|
// Restrict custom-call inference to the full TSRX/TSX compiler, which emits
|
|
@@ -1252,6 +1403,25 @@ function analyzeInternal(ast, options) {
|
|
|
1252
1403
|
return { analysis, inferred };
|
|
1253
1404
|
}
|
|
1254
1405
|
|
|
1406
|
+
/**
|
|
1407
|
+
* Return authored declaration identifiers whose bindings have a write or a
|
|
1408
|
+
* competing value definition. This is a read-only, scope-aware proof for callers
|
|
1409
|
+
* that recreate lexical scopes per invocation. Absence from the set does not
|
|
1410
|
+
* make a mutable declaration kind immutable by itself.
|
|
1411
|
+
*
|
|
1412
|
+
* @param {any} ast
|
|
1413
|
+
* @returns {WeakSet<import('estree').Identifier>}
|
|
1414
|
+
*/
|
|
1415
|
+
export function collectReassignedBindings(ast) {
|
|
1416
|
+
const { declarationBindings } = buildScopes(ast, true, new Set(), true);
|
|
1417
|
+
/** @type {WeakSet<import('estree').Identifier>} */
|
|
1418
|
+
const reassigned = new WeakSet();
|
|
1419
|
+
for (const [node, binding] of declarationBindings ?? []) {
|
|
1420
|
+
if (binding.reassigned) reassigned.add(node);
|
|
1421
|
+
}
|
|
1422
|
+
return reassigned;
|
|
1423
|
+
}
|
|
1424
|
+
|
|
1255
1425
|
/**
|
|
1256
1426
|
* Return inferred dependency expressions for every supported hook call whose
|
|
1257
1427
|
* dependency argument is omitted. Explicit arrays, `null`, and any other
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { parseModule } from '@tsrx/core';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { parseModule } from 'oxc-tsrx/tsrx-core-compat';
|