terser 5.31.6 → 5.33.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/CHANGELOG.md +10 -0
- package/dist/bundle.min.js +155 -85
- package/lib/compress/common.js +2 -2
- package/lib/compress/evaluate.js +17 -6
- package/lib/compress/reduce-vars.js +110 -75
- package/lib/mozilla-ast.js +33 -10
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
@@ -1,5 +1,15 @@
|
|
1
1
|
# Changelog
|
2
2
|
|
3
|
+
## v5.33.0
|
4
|
+
|
5
|
+
- `reduce_vars` improved when dealing with hoisted function definitions (#1544)
|
6
|
+
|
7
|
+
## v5.32.0
|
8
|
+
|
9
|
+
- `import("module")` can now be input and output from ESTree AST (#1557)
|
10
|
+
- `BigInt` literals can now be input and output from ESTree AST (#1555)
|
11
|
+
- `typeof` an object or array (`typeof {}` and `typeof []`) can now be statically evaluated. (#1546)
|
12
|
+
|
3
13
|
## v5.31.6
|
4
14
|
- Retain side effects in a `case` when the expression is a sequence (comma) expression
|
5
15
|
|
package/dist/bundle.min.js
CHANGED
@@ -7571,6 +7571,19 @@ def_transform(AST_PrefixedTemplateString, function(self, tw) {
|
|
7571
7571
|
});
|
7572
7572
|
},
|
7573
7573
|
|
7574
|
+
ImportExpression: function(M) {
|
7575
|
+
return new AST_Call({
|
7576
|
+
start: my_start_token(M),
|
7577
|
+
end: my_end_token(M),
|
7578
|
+
expression: from_moz({
|
7579
|
+
type: "Identifier",
|
7580
|
+
name: "import"
|
7581
|
+
}),
|
7582
|
+
optional: false,
|
7583
|
+
args: [from_moz(M.source)]
|
7584
|
+
});
|
7585
|
+
},
|
7586
|
+
|
7574
7587
|
ExportAllDeclaration: function(M) {
|
7575
7588
|
var foreign_name = M.exported == null ?
|
7576
7589
|
new AST_SymbolExportForeign({ name: "*" }) :
|
@@ -7638,6 +7651,11 @@ def_transform(AST_PrefixedTemplateString, function(self, tw) {
|
|
7638
7651
|
args.value = { source, flags };
|
7639
7652
|
return new AST_RegExp(args);
|
7640
7653
|
}
|
7654
|
+
const bi = typeof M.value === "bigint" ? M.value.toString() : M.bigint;
|
7655
|
+
if (typeof bi === "string") {
|
7656
|
+
args.value = bi;
|
7657
|
+
return new AST_BigInt(args);
|
7658
|
+
}
|
7641
7659
|
if (val === null) return new AST_Null(args);
|
7642
7660
|
switch (typeof val) {
|
7643
7661
|
case "string":
|
@@ -7705,14 +7723,6 @@ def_transform(AST_PrefixedTemplateString, function(self, tw) {
|
|
7705
7723
|
});
|
7706
7724
|
},
|
7707
7725
|
|
7708
|
-
BigIntLiteral(M) {
|
7709
|
-
return new AST_BigInt({
|
7710
|
-
start : my_start_token(M),
|
7711
|
-
end : my_end_token(M),
|
7712
|
-
value : M.value
|
7713
|
-
});
|
7714
|
-
},
|
7715
|
-
|
7716
7726
|
EmptyStatement: function(M) {
|
7717
7727
|
return new AST_EmptyStatement({
|
7718
7728
|
start: my_start_token(M),
|
@@ -8185,6 +8195,14 @@ def_transform(AST_PrefixedTemplateString, function(self, tw) {
|
|
8185
8195
|
};
|
8186
8196
|
});
|
8187
8197
|
def_to_moz(AST_Call, function To_Moz_CallExpression(M) {
|
8198
|
+
if (M.expression instanceof AST_SymbolRef && M.expression.name === "import") {
|
8199
|
+
const [source] = M.args.map(to_moz);
|
8200
|
+
return {
|
8201
|
+
type: "ImportExpression",
|
8202
|
+
source,
|
8203
|
+
};
|
8204
|
+
}
|
8205
|
+
|
8188
8206
|
return {
|
8189
8207
|
type: "CallExpression",
|
8190
8208
|
callee: to_moz(M.expression),
|
@@ -8730,8 +8748,13 @@ def_transform(AST_PrefixedTemplateString, function(self, tw) {
|
|
8730
8748
|
});
|
8731
8749
|
|
8732
8750
|
def_to_moz(AST_BigInt, M => ({
|
8733
|
-
type: "
|
8734
|
-
value
|
8751
|
+
type: "Literal",
|
8752
|
+
// value cannot be represented natively
|
8753
|
+
// see: https://github.com/estree/estree/blob/master/es2020.md#bigintliteral
|
8754
|
+
value: null,
|
8755
|
+
// `M.value` is a string that may be a hex number representation.
|
8756
|
+
// but "bigint" property should have only decimal digits
|
8757
|
+
bigint: typeof BigInt === "function" ? BigInt(M.value).toString() : M.value,
|
8735
8758
|
}));
|
8736
8759
|
|
8737
8760
|
AST_Boolean.DEFMETHOD("to_mozilla_ast", AST_Constant.prototype.to_mozilla_ast);
|
@@ -13268,9 +13291,9 @@ function is_reachable(scope_node, defs) {
|
|
13268
13291
|
}
|
13269
13292
|
|
13270
13293
|
/** Check if a ref refers to the name of a function/class it's defined within */
|
13271
|
-
function is_recursive_ref(
|
13294
|
+
function is_recursive_ref(tw, def) {
|
13272
13295
|
var node;
|
13273
|
-
for (var i = 0; node =
|
13296
|
+
for (var i = 0; node = tw.parent(i); i++) {
|
13274
13297
|
if (node instanceof AST_Lambda || node instanceof AST_Class) {
|
13275
13298
|
var name = node.name;
|
13276
13299
|
if (name && name.definition() === def) {
|
@@ -14579,14 +14602,25 @@ def_eval(AST_Object, function (compressor, depth) {
|
|
14579
14602
|
var non_converting_unary = makePredicate("! typeof void");
|
14580
14603
|
def_eval(AST_UnaryPrefix, function (compressor, depth) {
|
14581
14604
|
var e = this.expression;
|
14582
|
-
// Function would be evaluated to an array and so typeof would
|
14583
|
-
// incorrectly return 'object'. Hence making is a special case.
|
14584
14605
|
if (compressor.option("typeofs")
|
14585
|
-
&& this.operator == "typeof"
|
14586
|
-
|
14606
|
+
&& this.operator == "typeof") {
|
14607
|
+
// Function would be evaluated to an array and so typeof would
|
14608
|
+
// incorrectly return 'object'. Hence making is a special case.
|
14609
|
+
if (e instanceof AST_Lambda
|
14587
14610
|
|| e instanceof AST_SymbolRef
|
14588
|
-
&& e.fixed_value() instanceof AST_Lambda)
|
14589
|
-
|
14611
|
+
&& e.fixed_value() instanceof AST_Lambda) {
|
14612
|
+
return typeof function () { };
|
14613
|
+
}
|
14614
|
+
if (
|
14615
|
+
(e instanceof AST_Object
|
14616
|
+
|| e instanceof AST_Array
|
14617
|
+
|| (e instanceof AST_SymbolRef
|
14618
|
+
&& (e.fixed_value() instanceof AST_Object
|
14619
|
+
|| e.fixed_value() instanceof AST_Array)))
|
14620
|
+
&& !e.has_side_effects(compressor)
|
14621
|
+
) {
|
14622
|
+
return typeof {};
|
14623
|
+
}
|
14590
14624
|
}
|
14591
14625
|
if (!non_converting_unary.has(this.operator))
|
14592
14626
|
depth++;
|
@@ -16113,28 +16147,50 @@ function mark_lambda(tw, descend, compressor) {
|
|
16113
16147
|
* // use defined_after
|
16114
16148
|
* }
|
16115
16149
|
*
|
16116
|
-
*
|
16150
|
+
* Or even indirectly:
|
16151
|
+
*
|
16152
|
+
* B();
|
16153
|
+
* var defined_after = true;
|
16154
|
+
* function A() {
|
16155
|
+
* // use defined_after
|
16156
|
+
* }
|
16157
|
+
* function B() {
|
16158
|
+
* A();
|
16159
|
+
* }
|
16160
|
+
*
|
16161
|
+
* Access a variable before declaration will either throw a ReferenceError
|
16162
|
+
* (if the variable is declared with `let` or `const`),
|
16163
|
+
* or get an `undefined` (if the variable is declared with `var`).
|
16164
|
+
*
|
16165
|
+
* If the variable is inlined into the function, the behavior will change.
|
16166
|
+
*
|
16167
|
+
* This function is called on the parent to disallow inlining of such variables,
|
16117
16168
|
*/
|
16118
16169
|
function handle_defined_after_hoist(parent) {
|
16119
16170
|
const defuns = [];
|
16120
16171
|
walk(parent, node => {
|
16121
16172
|
if (node === parent) return;
|
16122
|
-
if (node instanceof AST_Defun)
|
16173
|
+
if (node instanceof AST_Defun) {
|
16174
|
+
defuns.push(node);
|
16175
|
+
return true;
|
16176
|
+
}
|
16123
16177
|
if (
|
16124
16178
|
node instanceof AST_Scope
|
16125
16179
|
|| node instanceof AST_SimpleStatement
|
16126
16180
|
) return true;
|
16127
16181
|
});
|
16128
16182
|
|
16183
|
+
// `defun` id to array of `defun` it uses
|
16184
|
+
const defun_dependencies_map = new Map();
|
16185
|
+
// `defun` id to array of enclosing `def` that are used by the function
|
16186
|
+
const dependencies_map = new Map();
|
16187
|
+
// all symbol ids that will be tracked for read/write
|
16129
16188
|
const symbols_of_interest = new Set();
|
16130
16189
|
const defuns_of_interest = new Set();
|
16131
|
-
const potential_conflicts = [];
|
16132
16190
|
|
16133
16191
|
for (const defun of defuns) {
|
16134
16192
|
const fname_def = defun.name.definition();
|
16135
|
-
const
|
16136
|
-
d => d !== defun && d.enclosed.indexOf(fname_def) !== -1
|
16137
|
-
);
|
16193
|
+
const enclosing_defs = [];
|
16138
16194
|
|
16139
16195
|
for (const def of defun.enclosed) {
|
16140
16196
|
if (
|
@@ -16145,93 +16201,107 @@ function handle_defined_after_hoist(parent) {
|
|
16145
16201
|
continue;
|
16146
16202
|
}
|
16147
16203
|
|
16148
|
-
|
16204
|
+
symbols_of_interest.add(def.id);
|
16205
|
+
|
16206
|
+
// found a reference to another function
|
16149
16207
|
if (
|
16150
16208
|
def.assignments === 0
|
16151
16209
|
&& def.orig.length === 1
|
16152
16210
|
&& def.orig[0] instanceof AST_SymbolDefun
|
16153
16211
|
) {
|
16154
|
-
|
16155
|
-
|
16212
|
+
defuns_of_interest.add(def.id);
|
16213
|
+
symbols_of_interest.add(def.id);
|
16214
|
+
|
16215
|
+
defuns_of_interest.add(fname_def.id);
|
16216
|
+
symbols_of_interest.add(fname_def.id);
|
16217
|
+
|
16218
|
+
if (!defun_dependencies_map.has(fname_def.id)) {
|
16219
|
+
defun_dependencies_map.set(fname_def.id, []);
|
16220
|
+
}
|
16221
|
+
defun_dependencies_map.get(fname_def.id).push(def.id);
|
16156
16222
|
|
16157
|
-
if (found_self_ref_in_other_defuns) {
|
16158
|
-
def.fixed = false;
|
16159
16223
|
continue;
|
16160
16224
|
}
|
16161
16225
|
|
16162
|
-
|
16163
|
-
|
16164
|
-
|
16226
|
+
enclosing_defs.push(def);
|
16227
|
+
}
|
16228
|
+
|
16229
|
+
if (enclosing_defs.length) {
|
16230
|
+
dependencies_map.set(fname_def.id, enclosing_defs);
|
16231
|
+
defuns_of_interest.add(fname_def.id);
|
16165
16232
|
symbols_of_interest.add(fname_def.id);
|
16166
|
-
defuns_of_interest.add(defun);
|
16167
16233
|
}
|
16168
16234
|
}
|
16169
16235
|
|
16170
|
-
//
|
16171
|
-
if (
|
16172
|
-
|
16173
|
-
|
16174
|
-
|
16175
|
-
|
16176
|
-
|
16177
|
-
|
16178
|
-
|
16236
|
+
// No defuns use outside constants
|
16237
|
+
if (!dependencies_map.size) {
|
16238
|
+
return;
|
16239
|
+
}
|
16240
|
+
|
16241
|
+
// Increment to count "symbols of interest" (defuns or defs) that we found.
|
16242
|
+
// These are tracked in AST order so we can check which is after which.
|
16243
|
+
let symbol_index = 1;
|
16244
|
+
// Map a defun ID to its first read (a `symbol_index`)
|
16245
|
+
const defun_first_read_map = new Map();
|
16246
|
+
// Map a symbol ID to its last write (a `symbol_index`)
|
16247
|
+
const symbol_last_write_map = new Map();
|
16179
16248
|
|
16180
|
-
|
16181
|
-
|
16182
|
-
|
16183
|
-
const start = found_symbols.length;
|
16184
|
-
descend();
|
16185
|
-
const end = found_symbols.length;
|
16249
|
+
walk_parent(parent, (node, walk_info) => {
|
16250
|
+
if (node instanceof AST_Symbol && node.thedef) {
|
16251
|
+
const id = node.definition().id;
|
16186
16252
|
|
16187
|
-
|
16188
|
-
return true;
|
16189
|
-
}
|
16190
|
-
// if we found a defun on the list, mark IN_DEFUN=id and descend
|
16253
|
+
symbol_index++;
|
16191
16254
|
|
16192
|
-
|
16193
|
-
|
16194
|
-
if (
|
16195
|
-
|
16196
|
-
found_symbol_writes.add(found_symbols.length);
|
16197
|
-
}
|
16198
|
-
found_symbols.push(id);
|
16255
|
+
// Track last-writes to symbols
|
16256
|
+
if (symbols_of_interest.has(id)) {
|
16257
|
+
if (node instanceof AST_SymbolDeclaration || is_lhs(node, walk_info.parent())) {
|
16258
|
+
symbol_last_write_map.set(id, symbol_index);
|
16199
16259
|
}
|
16200
16260
|
}
|
16201
|
-
})));
|
16202
16261
|
|
16203
|
-
|
16204
|
-
|
16262
|
+
// Track first-reads of defuns (refined later)
|
16263
|
+
if (defuns_of_interest.has(id)) {
|
16264
|
+
if (!defun_first_read_map.has(id) && !is_recursive_ref(walk_info, id)) {
|
16265
|
+
defun_first_read_map.set(id, symbol_index);
|
16266
|
+
}
|
16267
|
+
}
|
16268
|
+
}
|
16269
|
+
});
|
16205
16270
|
|
16206
|
-
|
16207
|
-
|
16208
|
-
|
16271
|
+
// Refine `defun_first_read_map` to be as high as possible
|
16272
|
+
for (const [defun, defun_first_read] of defun_first_read_map) {
|
16273
|
+
// Update all depdencies of `defun`
|
16274
|
+
const queue = new Set(defun_dependencies_map.get(defun));
|
16275
|
+
for (const enclosed_defun of queue) {
|
16276
|
+
let enclosed_defun_first_read = defun_first_read_map.get(enclosed_defun);
|
16277
|
+
if (enclosed_defun_first_read != null && enclosed_defun_first_read < defun_first_read) {
|
16278
|
+
continue;
|
16279
|
+
}
|
16209
16280
|
|
16210
|
-
|
16211
|
-
index = found_symbols.indexOf(sym_id, index);
|
16281
|
+
defun_first_read_map.set(enclosed_defun, defun_first_read);
|
16212
16282
|
|
16213
|
-
|
16214
|
-
|
16215
|
-
|
16216
|
-
|
16217
|
-
|
16218
|
-
} else if (must_be_write && !found_symbol_writes.has(index)) {
|
16219
|
-
index++;
|
16220
|
-
continue;
|
16221
|
-
} else {
|
16222
|
-
break;
|
16223
|
-
}
|
16224
|
-
}
|
16283
|
+
for (const enclosed_enclosed_defun of defun_dependencies_map.get(enclosed_defun) || []) {
|
16284
|
+
queue.add(enclosed_enclosed_defun);
|
16285
|
+
}
|
16286
|
+
}
|
16287
|
+
}
|
16225
16288
|
|
16226
|
-
|
16227
|
-
|
16289
|
+
// ensure write-then-read order, otherwise clear `fixed`
|
16290
|
+
// This is safe because last-writes (found_symbol_writes) are assumed to be as late as possible, and first-reads (defun_first_read_map) are assumed to be as early as possible.
|
16291
|
+
for (const [defun, defs] of dependencies_map) {
|
16292
|
+
const defun_first_read = defun_first_read_map.get(defun);
|
16293
|
+
if (defun_first_read === undefined) {
|
16294
|
+
continue;
|
16295
|
+
}
|
16228
16296
|
|
16229
|
-
|
16230
|
-
|
16297
|
+
for (const def of defs) {
|
16298
|
+
if (def.fixed === false) {
|
16299
|
+
continue;
|
16300
|
+
}
|
16231
16301
|
|
16232
|
-
|
16302
|
+
let def_last_write = symbol_last_write_map.get(def.id) || 0;
|
16233
16303
|
|
16234
|
-
if (
|
16304
|
+
if (defun_first_read < def_last_write) {
|
16235
16305
|
def.fixed = false;
|
16236
16306
|
}
|
16237
16307
|
}
|
package/lib/compress/common.js
CHANGED
@@ -333,9 +333,9 @@ export function is_reachable(scope_node, defs) {
|
|
333
333
|
}
|
334
334
|
|
335
335
|
/** Check if a ref refers to the name of a function/class it's defined within */
|
336
|
-
export function is_recursive_ref(
|
336
|
+
export function is_recursive_ref(tw, def) {
|
337
337
|
var node;
|
338
|
-
for (var i = 0; node =
|
338
|
+
for (var i = 0; node = tw.parent(i); i++) {
|
339
339
|
if (node instanceof AST_Lambda || node instanceof AST_Class) {
|
340
340
|
var name = node.name;
|
341
341
|
if (name && name.definition() === def) {
|
package/lib/compress/evaluate.js
CHANGED
@@ -218,14 +218,25 @@ def_eval(AST_Object, function (compressor, depth) {
|
|
218
218
|
var non_converting_unary = makePredicate("! typeof void");
|
219
219
|
def_eval(AST_UnaryPrefix, function (compressor, depth) {
|
220
220
|
var e = this.expression;
|
221
|
-
// Function would be evaluated to an array and so typeof would
|
222
|
-
// incorrectly return 'object'. Hence making is a special case.
|
223
221
|
if (compressor.option("typeofs")
|
224
|
-
&& this.operator == "typeof"
|
225
|
-
|
222
|
+
&& this.operator == "typeof") {
|
223
|
+
// Function would be evaluated to an array and so typeof would
|
224
|
+
// incorrectly return 'object'. Hence making is a special case.
|
225
|
+
if (e instanceof AST_Lambda
|
226
226
|
|| e instanceof AST_SymbolRef
|
227
|
-
&& e.fixed_value() instanceof AST_Lambda)
|
228
|
-
|
227
|
+
&& e.fixed_value() instanceof AST_Lambda) {
|
228
|
+
return typeof function () { };
|
229
|
+
}
|
230
|
+
if (
|
231
|
+
(e instanceof AST_Object
|
232
|
+
|| e instanceof AST_Array
|
233
|
+
|| (e instanceof AST_SymbolRef
|
234
|
+
&& (e.fixed_value() instanceof AST_Object
|
235
|
+
|| e.fixed_value() instanceof AST_Array)))
|
236
|
+
&& !e.has_side_effects(compressor)
|
237
|
+
) {
|
238
|
+
return typeof {};
|
239
|
+
}
|
229
240
|
}
|
230
241
|
if (!non_converting_unary.has(this.operator))
|
231
242
|
depth++;
|
@@ -94,8 +94,7 @@ import {
|
|
94
94
|
|
95
95
|
walk,
|
96
96
|
walk_body,
|
97
|
-
|
98
|
-
TreeWalker,
|
97
|
+
walk_parent,
|
99
98
|
} from "../ast.js";
|
100
99
|
import { HOP, make_node, noop } from "../utils/index.js";
|
101
100
|
|
@@ -496,28 +495,50 @@ function mark_lambda(tw, descend, compressor) {
|
|
496
495
|
* // use defined_after
|
497
496
|
* }
|
498
497
|
*
|
499
|
-
*
|
498
|
+
* Or even indirectly:
|
499
|
+
*
|
500
|
+
* B();
|
501
|
+
* var defined_after = true;
|
502
|
+
* function A() {
|
503
|
+
* // use defined_after
|
504
|
+
* }
|
505
|
+
* function B() {
|
506
|
+
* A();
|
507
|
+
* }
|
508
|
+
*
|
509
|
+
* Access a variable before declaration will either throw a ReferenceError
|
510
|
+
* (if the variable is declared with `let` or `const`),
|
511
|
+
* or get an `undefined` (if the variable is declared with `var`).
|
512
|
+
*
|
513
|
+
* If the variable is inlined into the function, the behavior will change.
|
514
|
+
*
|
515
|
+
* This function is called on the parent to disallow inlining of such variables,
|
500
516
|
*/
|
501
517
|
function handle_defined_after_hoist(parent) {
|
502
518
|
const defuns = [];
|
503
519
|
walk(parent, node => {
|
504
520
|
if (node === parent) return;
|
505
|
-
if (node instanceof AST_Defun)
|
521
|
+
if (node instanceof AST_Defun) {
|
522
|
+
defuns.push(node);
|
523
|
+
return true;
|
524
|
+
}
|
506
525
|
if (
|
507
526
|
node instanceof AST_Scope
|
508
527
|
|| node instanceof AST_SimpleStatement
|
509
528
|
) return true;
|
510
529
|
});
|
511
530
|
|
531
|
+
// `defun` id to array of `defun` it uses
|
532
|
+
const defun_dependencies_map = new Map();
|
533
|
+
// `defun` id to array of enclosing `def` that are used by the function
|
534
|
+
const dependencies_map = new Map();
|
535
|
+
// all symbol ids that will be tracked for read/write
|
512
536
|
const symbols_of_interest = new Set();
|
513
537
|
const defuns_of_interest = new Set();
|
514
|
-
const potential_conflicts = [];
|
515
538
|
|
516
539
|
for (const defun of defuns) {
|
517
540
|
const fname_def = defun.name.definition();
|
518
|
-
const
|
519
|
-
d => d !== defun && d.enclosed.indexOf(fname_def) !== -1
|
520
|
-
);
|
541
|
+
const enclosing_defs = [];
|
521
542
|
|
522
543
|
for (const def of defun.enclosed) {
|
523
544
|
if (
|
@@ -528,93 +549,107 @@ function handle_defined_after_hoist(parent) {
|
|
528
549
|
continue;
|
529
550
|
}
|
530
551
|
|
531
|
-
|
552
|
+
symbols_of_interest.add(def.id);
|
553
|
+
|
554
|
+
// found a reference to another function
|
532
555
|
if (
|
533
556
|
def.assignments === 0
|
534
557
|
&& def.orig.length === 1
|
535
558
|
&& def.orig[0] instanceof AST_SymbolDefun
|
536
559
|
) {
|
537
|
-
|
538
|
-
|
560
|
+
defuns_of_interest.add(def.id);
|
561
|
+
symbols_of_interest.add(def.id);
|
562
|
+
|
563
|
+
defuns_of_interest.add(fname_def.id);
|
564
|
+
symbols_of_interest.add(fname_def.id);
|
565
|
+
|
566
|
+
if (!defun_dependencies_map.has(fname_def.id)) {
|
567
|
+
defun_dependencies_map.set(fname_def.id, []);
|
568
|
+
}
|
569
|
+
defun_dependencies_map.get(fname_def.id).push(def.id);
|
539
570
|
|
540
|
-
if (found_self_ref_in_other_defuns) {
|
541
|
-
def.fixed = false;
|
542
571
|
continue;
|
543
572
|
}
|
544
573
|
|
545
|
-
|
546
|
-
|
547
|
-
|
574
|
+
enclosing_defs.push(def);
|
575
|
+
}
|
576
|
+
|
577
|
+
if (enclosing_defs.length) {
|
578
|
+
dependencies_map.set(fname_def.id, enclosing_defs);
|
579
|
+
defuns_of_interest.add(fname_def.id);
|
548
580
|
symbols_of_interest.add(fname_def.id);
|
549
|
-
defuns_of_interest.add(defun);
|
550
581
|
}
|
551
582
|
}
|
552
583
|
|
553
|
-
//
|
554
|
-
if (
|
555
|
-
|
556
|
-
|
557
|
-
|
558
|
-
|
559
|
-
|
560
|
-
|
561
|
-
|
562
|
-
|
563
|
-
|
564
|
-
|
565
|
-
|
566
|
-
|
567
|
-
|
568
|
-
|
569
|
-
|
570
|
-
|
571
|
-
|
572
|
-
|
573
|
-
|
574
|
-
|
575
|
-
|
576
|
-
const id = node.definition().id;
|
577
|
-
if (symbols_of_interest.has(id)) {
|
578
|
-
if (node instanceof AST_SymbolDeclaration || is_lhs(node, tw)) {
|
579
|
-
found_symbol_writes.add(found_symbols.length);
|
580
|
-
}
|
581
|
-
found_symbols.push(id);
|
584
|
+
// No defuns use outside constants
|
585
|
+
if (!dependencies_map.size) {
|
586
|
+
return;
|
587
|
+
}
|
588
|
+
|
589
|
+
// Increment to count "symbols of interest" (defuns or defs) that we found.
|
590
|
+
// These are tracked in AST order so we can check which is after which.
|
591
|
+
let symbol_index = 1;
|
592
|
+
// Map a defun ID to its first read (a `symbol_index`)
|
593
|
+
const defun_first_read_map = new Map();
|
594
|
+
// Map a symbol ID to its last write (a `symbol_index`)
|
595
|
+
const symbol_last_write_map = new Map();
|
596
|
+
|
597
|
+
walk_parent(parent, (node, walk_info) => {
|
598
|
+
if (node instanceof AST_Symbol && node.thedef) {
|
599
|
+
const id = node.definition().id;
|
600
|
+
|
601
|
+
symbol_index++;
|
602
|
+
|
603
|
+
// Track last-writes to symbols
|
604
|
+
if (symbols_of_interest.has(id)) {
|
605
|
+
if (node instanceof AST_SymbolDeclaration || is_lhs(node, walk_info.parent())) {
|
606
|
+
symbol_last_write_map.set(id, symbol_index);
|
582
607
|
}
|
583
608
|
}
|
584
|
-
|
585
|
-
|
586
|
-
|
587
|
-
|
588
|
-
|
589
|
-
// find the index in `found_symbols`, with some special rules:
|
590
|
-
const find = (sym_id, starting_at = 0, must_be_write = false) => {
|
591
|
-
let index = starting_at;
|
592
|
-
|
593
|
-
for (;;) {
|
594
|
-
index = found_symbols.indexOf(sym_id, index);
|
595
|
-
|
596
|
-
if (index === -1) {
|
597
|
-
break;
|
598
|
-
} else if (index >= defun_range.start && index < defun_range.end) {
|
599
|
-
index = defun_range.end;
|
600
|
-
continue;
|
601
|
-
} else if (must_be_write && !found_symbol_writes.has(index)) {
|
602
|
-
index++;
|
603
|
-
continue;
|
604
|
-
} else {
|
605
|
-
break;
|
606
|
-
}
|
609
|
+
|
610
|
+
// Track first-reads of defuns (refined later)
|
611
|
+
if (defuns_of_interest.has(id)) {
|
612
|
+
if (!defun_first_read_map.has(id) && !is_recursive_ref(walk_info, id)) {
|
613
|
+
defun_first_read_map.set(id, symbol_index);
|
607
614
|
}
|
615
|
+
}
|
616
|
+
}
|
617
|
+
});
|
608
618
|
|
609
|
-
|
610
|
-
|
619
|
+
// Refine `defun_first_read_map` to be as high as possible
|
620
|
+
for (const [defun, defun_first_read] of defun_first_read_map) {
|
621
|
+
// Update all depdencies of `defun`
|
622
|
+
const queue = new Set(defun_dependencies_map.get(defun));
|
623
|
+
for (const enclosed_defun of queue) {
|
624
|
+
let enclosed_defun_first_read = defun_first_read_map.get(enclosed_defun);
|
625
|
+
if (enclosed_defun_first_read != null && enclosed_defun_first_read < defun_first_read) {
|
626
|
+
continue;
|
627
|
+
}
|
628
|
+
|
629
|
+
defun_first_read_map.set(enclosed_defun, defun_first_read);
|
611
630
|
|
612
|
-
const
|
613
|
-
|
631
|
+
for (const enclosed_enclosed_defun of defun_dependencies_map.get(enclosed_defun) || []) {
|
632
|
+
queue.add(enclosed_enclosed_defun);
|
633
|
+
}
|
634
|
+
}
|
635
|
+
}
|
636
|
+
|
637
|
+
// ensure write-then-read order, otherwise clear `fixed`
|
638
|
+
// This is safe because last-writes (found_symbol_writes) are assumed to be as late as possible, and first-reads (defun_first_read_map) are assumed to be as early as possible.
|
639
|
+
for (const [defun, defs] of dependencies_map) {
|
640
|
+
const defun_first_read = defun_first_read_map.get(defun);
|
641
|
+
if (defun_first_read === undefined) {
|
642
|
+
continue;
|
643
|
+
}
|
644
|
+
|
645
|
+
for (const def of defs) {
|
646
|
+
if (def.fixed === false) {
|
647
|
+
continue;
|
648
|
+
}
|
614
649
|
|
615
|
-
|
650
|
+
let def_last_write = symbol_last_write_map.get(def.id) || 0;
|
616
651
|
|
617
|
-
if (
|
652
|
+
if (defun_first_read < def_last_write) {
|
618
653
|
def.fixed = false;
|
619
654
|
}
|
620
655
|
}
|
package/lib/mozilla-ast.js
CHANGED
@@ -595,6 +595,19 @@ import { is_basic_identifier_string } from "./parse.js";
|
|
595
595
|
});
|
596
596
|
},
|
597
597
|
|
598
|
+
ImportExpression: function(M) {
|
599
|
+
return new AST_Call({
|
600
|
+
start: my_start_token(M),
|
601
|
+
end: my_end_token(M),
|
602
|
+
expression: from_moz({
|
603
|
+
type: "Identifier",
|
604
|
+
name: "import"
|
605
|
+
}),
|
606
|
+
optional: false,
|
607
|
+
args: [from_moz(M.source)]
|
608
|
+
});
|
609
|
+
},
|
610
|
+
|
598
611
|
ExportAllDeclaration: function(M) {
|
599
612
|
var foreign_name = M.exported == null ?
|
600
613
|
new AST_SymbolExportForeign({ name: "*" }) :
|
@@ -662,6 +675,11 @@ import { is_basic_identifier_string } from "./parse.js";
|
|
662
675
|
args.value = { source, flags };
|
663
676
|
return new AST_RegExp(args);
|
664
677
|
}
|
678
|
+
const bi = typeof M.value === "bigint" ? M.value.toString() : M.bigint;
|
679
|
+
if (typeof bi === "string") {
|
680
|
+
args.value = bi;
|
681
|
+
return new AST_BigInt(args);
|
682
|
+
}
|
665
683
|
if (val === null) return new AST_Null(args);
|
666
684
|
switch (typeof val) {
|
667
685
|
case "string":
|
@@ -729,14 +747,6 @@ import { is_basic_identifier_string } from "./parse.js";
|
|
729
747
|
});
|
730
748
|
},
|
731
749
|
|
732
|
-
BigIntLiteral(M) {
|
733
|
-
return new AST_BigInt({
|
734
|
-
start : my_start_token(M),
|
735
|
-
end : my_end_token(M),
|
736
|
-
value : M.value
|
737
|
-
});
|
738
|
-
},
|
739
|
-
|
740
750
|
EmptyStatement: function(M) {
|
741
751
|
return new AST_EmptyStatement({
|
742
752
|
start: my_start_token(M),
|
@@ -1209,6 +1219,14 @@ import { is_basic_identifier_string } from "./parse.js";
|
|
1209
1219
|
};
|
1210
1220
|
});
|
1211
1221
|
def_to_moz(AST_Call, function To_Moz_CallExpression(M) {
|
1222
|
+
if (M.expression instanceof AST_SymbolRef && M.expression.name === "import") {
|
1223
|
+
const [source] = M.args.map(to_moz);
|
1224
|
+
return {
|
1225
|
+
type: "ImportExpression",
|
1226
|
+
source,
|
1227
|
+
};
|
1228
|
+
}
|
1229
|
+
|
1212
1230
|
return {
|
1213
1231
|
type: "CallExpression",
|
1214
1232
|
callee: to_moz(M.expression),
|
@@ -1754,8 +1772,13 @@ import { is_basic_identifier_string } from "./parse.js";
|
|
1754
1772
|
});
|
1755
1773
|
|
1756
1774
|
def_to_moz(AST_BigInt, M => ({
|
1757
|
-
type: "
|
1758
|
-
value
|
1775
|
+
type: "Literal",
|
1776
|
+
// value cannot be represented natively
|
1777
|
+
// see: https://github.com/estree/estree/blob/master/es2020.md#bigintliteral
|
1778
|
+
value: null,
|
1779
|
+
// `M.value` is a string that may be a hex number representation.
|
1780
|
+
// but "bigint" property should have only decimal digits
|
1781
|
+
bigint: typeof BigInt === "function" ? BigInt(M.value).toString() : M.value,
|
1759
1782
|
}));
|
1760
1783
|
|
1761
1784
|
AST_Boolean.DEFMETHOD("to_mozilla_ast", AST_Constant.prototype.to_mozilla_ast);
|