Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

terser

Package Overview
Dependencies
Maintainers
1
Versions
182
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

terser - npm Package Compare versions

Comparing version 5.32.0 to 5.33.0

4

CHANGELOG.md
# Changelog
## v5.33.0
- `reduce_vars` improved when dealing with hoisted function definitions (#1544)
## v5.32.0

@@ -4,0 +8,0 @@

4

lib/compress/common.js

@@ -336,5 +336,5 @@ /***********************************************************************

/** Check if a ref refers to the name of a function/class it's defined within */
export function is_recursive_ref(compressor, def) {
export function is_recursive_ref(tw, def) {
var node;
for (var i = 0; node = compressor.parent(i); i++) {
for (var i = 0; node = tw.parent(i); i++) {
if (node instanceof AST_Lambda || node instanceof AST_Class) {

@@ -341,0 +341,0 @@ var name = node.name;

@@ -97,4 +97,3 @@ /***********************************************************************

walk_body,
TreeWalker,
walk_parent,
} from "../ast.js";

@@ -500,3 +499,20 @@ import { HOP, make_node, noop } from "../utils/index.js";

*
* This function is called on the parent to handle this issue.
* Or even indirectly:
*
* B();
* var defined_after = true;
* function A() {
* // use defined_after
* }
* function B() {
* A();
* }
*
* Access a variable before declaration will either throw a ReferenceError
* (if the variable is declared with `let` or `const`),
* or get an `undefined` (if the variable is declared with `var`).
*
* If the variable is inlined into the function, the behavior will change.
*
* This function is called on the parent to disallow inlining of such variables,
*/

@@ -507,3 +523,6 @@ function handle_defined_after_hoist(parent) {

if (node === parent) return;
if (node instanceof AST_Defun) defuns.push(node);
if (node instanceof AST_Defun) {
defuns.push(node);
return true;
}
if (

@@ -515,11 +534,13 @@ node instanceof AST_Scope

// `defun` id to array of `defun` it uses
const defun_dependencies_map = new Map();
// `defun` id to array of enclosing `def` that are used by the function
const dependencies_map = new Map();
// all symbol ids that will be tracked for read/write
const symbols_of_interest = new Set();
const defuns_of_interest = new Set();
const potential_conflicts = [];
for (const defun of defuns) {
const fname_def = defun.name.definition();
const found_self_ref_in_other_defuns = defuns.some(
d => d !== defun && d.enclosed.indexOf(fname_def) !== -1
);
const enclosing_defs = [];

@@ -535,3 +556,5 @@ for (const def of defun.enclosed) {

// defun is hoisted, so always safe
symbols_of_interest.add(def.id);
// found a reference to another function
if (

@@ -542,83 +565,95 @@ def.assignments === 0

) {
continue;
}
defuns_of_interest.add(def.id);
symbols_of_interest.add(def.id);
if (found_self_ref_in_other_defuns) {
def.fixed = false;
defuns_of_interest.add(fname_def.id);
symbols_of_interest.add(fname_def.id);
if (!defun_dependencies_map.has(fname_def.id)) {
defun_dependencies_map.set(fname_def.id, []);
}
defun_dependencies_map.get(fname_def.id).push(def.id);
continue;
}
// for the slower checks below this loop
potential_conflicts.push({ defun, def, fname_def });
symbols_of_interest.add(def.id);
enclosing_defs.push(def);
}
if (enclosing_defs.length) {
dependencies_map.set(fname_def.id, enclosing_defs);
defuns_of_interest.add(fname_def.id);
symbols_of_interest.add(fname_def.id);
defuns_of_interest.add(defun);
}
}
// linearize all symbols, and locate defs that are read after the defun
if (potential_conflicts.length) {
// All "symbols of interest", that is, defuns or defs, that we found.
// These are placed in order so we can check which is after which.
const found_symbols = [];
// Indices of `found_symbols` which are writes
const found_symbol_writes = new Set();
// Defun ranges are recorded because we don't care if a function uses the def internally
const defun_ranges = new Map();
// No defuns use outside constants
if (!dependencies_map.size) {
return;
}
let tw;
parent.walk((tw = new TreeWalker((node, descend) => {
if (node instanceof AST_Defun && defuns_of_interest.has(node)) {
const start = found_symbols.length;
descend();
const end = found_symbols.length;
// Increment to count "symbols of interest" (defuns or defs) that we found.
// These are tracked in AST order so we can check which is after which.
let symbol_index = 1;
// Map a defun ID to its first read (a `symbol_index`)
const defun_first_read_map = new Map();
// Map a symbol ID to its last write (a `symbol_index`)
const symbol_last_write_map = new Map();
defun_ranges.set(node, { start, end });
return true;
walk_parent(parent, (node, walk_info) => {
if (node instanceof AST_Symbol && node.thedef) {
const id = node.definition().id;
symbol_index++;
// Track last-writes to symbols
if (symbols_of_interest.has(id)) {
if (node instanceof AST_SymbolDeclaration || is_lhs(node, walk_info.parent())) {
symbol_last_write_map.set(id, symbol_index);
}
}
// if we found a defun on the list, mark IN_DEFUN=id and descend
if (node instanceof AST_Symbol && node.thedef) {
const id = node.definition().id;
if (symbols_of_interest.has(id)) {
if (node instanceof AST_SymbolDeclaration || is_lhs(node, tw)) {
found_symbol_writes.add(found_symbols.length);
}
found_symbols.push(id);
// Track first-reads of defuns (refined later)
if (defuns_of_interest.has(id)) {
if (!defun_first_read_map.has(id) && !is_recursive_ref(walk_info, id)) {
defun_first_read_map.set(id, symbol_index);
}
}
})));
}
});
for (const { def, defun, fname_def } of potential_conflicts) {
const defun_range = defun_ranges.get(defun);
// Refine `defun_first_read_map` to be as high as possible
for (const [defun, defun_first_read] of defun_first_read_map) {
// Update all depdencies of `defun`
const queue = new Set(defun_dependencies_map.get(defun));
for (const enclosed_defun of queue) {
let enclosed_defun_first_read = defun_first_read_map.get(enclosed_defun);
if (enclosed_defun_first_read != null && enclosed_defun_first_read < defun_first_read) {
continue;
}
// find the index in `found_symbols`, with some special rules:
const find = (sym_id, starting_at = 0, must_be_write = false) => {
let index = starting_at;
defun_first_read_map.set(enclosed_defun, defun_first_read);
for (;;) {
index = found_symbols.indexOf(sym_id, index);
for (const enclosed_enclosed_defun of defun_dependencies_map.get(enclosed_defun) || []) {
queue.add(enclosed_enclosed_defun);
}
}
}
if (index === -1) {
break;
} else if (index >= defun_range.start && index < defun_range.end) {
index = defun_range.end;
continue;
} else if (must_be_write && !found_symbol_writes.has(index)) {
index++;
continue;
} else {
break;
}
}
// ensure write-then-read order, otherwise clear `fixed`
// 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.
for (const [defun, defs] of dependencies_map) {
const defun_first_read = defun_first_read_map.get(defun);
if (defun_first_read === undefined) {
continue;
}
return index;
};
for (const def of defs) {
if (def.fixed === false) {
continue;
}
const read_defun_at = find(fname_def.id);
const wrote_def_at = find(def.id, read_defun_at + 1, true);
let def_last_write = symbol_last_write_map.get(def.id) || 0;
const wrote_def_after_reading_defun = read_defun_at != -1 && wrote_def_at != -1 && wrote_def_at > read_defun_at;
if (wrote_def_after_reading_defun) {
if (defun_first_read < def_last_write) {
def.fixed = false;

@@ -625,0 +660,0 @@ }

@@ -7,3 +7,3 @@ {

"license": "BSD-2-Clause",
"version": "5.32.0",
"version": "5.33.0",
"engines": {

@@ -10,0 +10,0 @@ "node": ">=10"

Sorry, the diff of this file is too big to display

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc