From efbc2ffe6a1ee5ec38a4396305561d6515d0943e Mon Sep 17 00:00:00 2001 From: littleblack111 Date: Fri, 30 Aug 2024 17:21:18 +0800 Subject: node fixes, updates --- .../README.md | 66 ++++++ .../lib/array-collapser.js | 52 +++++ .../lib/array-property-collapser.js | 99 +++++++++ .../lib/collapser.js | 32 +++ .../lib/index.js | 228 +++++++++++++++++++++ .../lib/object-collapser.js | 60 ++++++ .../lib/set-collapser.js | 61 ++++++ .../package.json | 14 ++ 8 files changed, 612 insertions(+) create mode 100644 node_modules/babel-plugin-transform-inline-consecutive-adds/README.md create mode 100644 node_modules/babel-plugin-transform-inline-consecutive-adds/lib/array-collapser.js create mode 100644 node_modules/babel-plugin-transform-inline-consecutive-adds/lib/array-property-collapser.js create mode 100644 node_modules/babel-plugin-transform-inline-consecutive-adds/lib/collapser.js create mode 100644 node_modules/babel-plugin-transform-inline-consecutive-adds/lib/index.js create mode 100644 node_modules/babel-plugin-transform-inline-consecutive-adds/lib/object-collapser.js create mode 100644 node_modules/babel-plugin-transform-inline-consecutive-adds/lib/set-collapser.js create mode 100644 node_modules/babel-plugin-transform-inline-consecutive-adds/package.json (limited to 'node_modules/babel-plugin-transform-inline-consecutive-adds') diff --git a/node_modules/babel-plugin-transform-inline-consecutive-adds/README.md b/node_modules/babel-plugin-transform-inline-consecutive-adds/README.md new file mode 100644 index 00000000..541358b5 --- /dev/null +++ b/node_modules/babel-plugin-transform-inline-consecutive-adds/README.md @@ -0,0 +1,66 @@ +# babel-plugin-transform-inline-consecutive-adds + +This plugin inlines consecutive property assignments, array pushes, etc. + +## Example + +**In** + +```javascript +const foo = {}; +foo.a = 42; +foo.b = ["hi"]; +foo.c = bar(); +foo.d = "str"; + +... +const bar = []; +bar.push(1); +bar.push(2); +``` + +**Out** + +```javascript +const foo = { + a: 42, + b: ["hi"], + c: bar(), + d: "str" +}; + +... +const bar = [1, 2]; +``` + +## Installation + +```sh +npm install babel-plugin-transform-inline-consecutive-adds --save-dev +``` + +## Usage + +### Via `.babelrc` (Recommended) + +**.babelrc** + +```json +{ + "plugins": ["transform-inline-consecutive-adds"] +} +``` + +### Via CLI + +```sh +babel --plugins transform-inline-consecutive-adds script.js +``` + +### Via Node API + +```javascript +require("@babel/core").transform("code", { + plugins: ["transform-inline-consecutive-adds"] +}); +``` diff --git a/node_modules/babel-plugin-transform-inline-consecutive-adds/lib/array-collapser.js b/node_modules/babel-plugin-transform-inline-consecutive-adds/lib/array-collapser.js new file mode 100644 index 00000000..540c92aa --- /dev/null +++ b/node_modules/babel-plugin-transform-inline-consecutive-adds/lib/array-collapser.js @@ -0,0 +1,52 @@ +"use strict"; + +const Collapser = require("./collapser"); + +class ArrayCollapser extends Collapser { + isInitTypeValid(init) { + return init.isArrayExpression(); + } + + isExpressionTypeValid(expr) { + return expr.isCallExpression(); + } + + getExpressionChecker(objName, checkReference) { + return expr => { + // checks expr is of form: + // foo.push(rval1, ...nrvals) + const callee = expr.get("callee"); + + if (!callee.isMemberExpression()) { + return false; + } + + const obj = callee.get("object"), + prop = callee.get("property"); + + if (!obj.isIdentifier() || obj.node.name !== objName || !prop.isIdentifier() || prop.node.name !== "push") { + return false; + } + + const args = expr.get("arguments"); + + if (args.some(checkReference)) { + return false; + } + + return true; + }; + } + + extractAssignment(expr) { + return expr.node.arguments; + } + + addSuccessfully(t, args, init) { + args.map(a => init.elements.push(a)); + return true; + } + +} + +module.exports = ArrayCollapser; \ No newline at end of file diff --git a/node_modules/babel-plugin-transform-inline-consecutive-adds/lib/array-property-collapser.js b/node_modules/babel-plugin-transform-inline-consecutive-adds/lib/array-property-collapser.js new file mode 100644 index 00000000..9e83b38f --- /dev/null +++ b/node_modules/babel-plugin-transform-inline-consecutive-adds/lib/array-property-collapser.js @@ -0,0 +1,99 @@ +"use strict"; + +const Collapser = require("./collapser"); + +class ArrayPropertyCollapser extends Collapser { + isInitTypeValid(init) { + return init.isArrayExpression(); + } + + isExpressionTypeValid(expr) { + return expr.isAssignmentExpression(); + } + + getExpressionChecker(objName, checkReference) { + return expr => { + // checks expr is of form: + // foo[num] = rval + const left = expr.get("left"); + + if (!left.isMemberExpression()) { + return false; + } + + const obj = left.get("object"), + prop = left.get("property"); + + if (!obj.isIdentifier() || obj.node.name !== objName) { + return false; + } + + const checkIndex = num => Number.isInteger(num) && num >= 0; + + if (!(prop.isNumericLiteral() || prop.isStringLiteral()) || !checkIndex(Number(prop.node.value))) { + return false; + } + + const right = expr.get("right"); + + if (checkReference(right)) { + return false; + } + + return true; + }; + } + + extractAssignment(expr) { + return [expr.node.left.property.value, expr.get("right")]; + } + + addSuccessfully(t, [index, rval], init) { + const elements = init.elements; + + for (let i = elements.length; i <= index; i++) { + elements.push(null); + } + + if (elements[index] !== null) { + return false; + } + + elements[index] = rval.node; + return true; + } + + isSizeSmaller({ + newInit, + oldInit, + varDecl, + assignments, + statements + }) { + const anyUndefined = args => args.some(a => a === undefined); // We make an inexact calculation of how much space we save. + // It's inexact because we don't know how whitespaces will get minimized, + // and other factors. + + + if (anyUndefined([statements[statements.length - 1].node.end, varDecl.node.end])) { + return false; + } + + const statementsLength = statements[statements.length - 1].node.end - varDecl.node.end; // Approx. formula of the change in `init`'s length = + // (# commas added) + (size of all the new rvals added), where + // # commas added = (difference between the lengths of the old and new arrays) + + const numCommaAdded = newInit.elements.length - oldInit.elements.length; + + if (anyUndefined(assignments.map(([, rval]) => rval.node.end)) || anyUndefined(assignments.map(([, rval]) => rval.node.start))) { + return false; + } + + const sizeOfRvals = assignments.map(([, rval]) => rval.node.end - rval.node.start + 1).reduce((a, b) => a + b, 0); // add 1 for space in front // sum + + return numCommaAdded + sizeOfRvals < statementsLength; + } + +} + +module.exports = ArrayPropertyCollapser; \ No newline at end of file diff --git a/node_modules/babel-plugin-transform-inline-consecutive-adds/lib/collapser.js b/node_modules/babel-plugin-transform-inline-consecutive-adds/lib/collapser.js new file mode 100644 index 00000000..5d1f2c01 --- /dev/null +++ b/node_modules/babel-plugin-transform-inline-consecutive-adds/lib/collapser.js @@ -0,0 +1,32 @@ +"use strict"; + +const NotImplementedError = Error("NotImplementedError"); + +class Collapser { + isInitTypeValid() { + throw NotImplementedError; + } + + isExpressionTypeValid() { + throw NotImplementedError; + } + + getExpressionChecker() { + throw NotImplementedError; + } + + extractAssignment() { + throw NotImplementedError; + } + + addSuccessfully() { + throw NotImplementedError; + } + + isSizeSmaller() { + return true; + } + +} + +module.exports = Collapser; \ No newline at end of file diff --git a/node_modules/babel-plugin-transform-inline-consecutive-adds/lib/index.js b/node_modules/babel-plugin-transform-inline-consecutive-adds/lib/index.js new file mode 100644 index 00000000..80811010 --- /dev/null +++ b/node_modules/babel-plugin-transform-inline-consecutive-adds/lib/index.js @@ -0,0 +1,228 @@ +"use strict"; + +function _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _nonIterableRest(); } + +function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance"); } + +function _iterableToArrayLimit(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"] != null) _i["return"](); } finally { if (_d) throw _e; } } return _arr; } + +function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; } + +const COLLAPSERS = [require("./object-collapser"), require("./array-collapser"), require("./array-property-collapser"), require("./set-collapser")].map(Collapser => { + return new Collapser(); +}); + +function getFunctionParent(path, scopeParent) { + const parent = path.findParent(p => p.isFunction()); // don"t traverse higher than the function the var is defined in. + + return parent === scopeParent ? null : parent; +} + +function getFunctionReferences(path, scopeParent, references = new Set()) { + for (let func = getFunctionParent(path, scopeParent); func; func = getFunctionParent(func, scopeParent)) { + const id = func.node.id; + const binding = id && func.scope.getBinding(id.name); + + if (!binding) { + continue; + } + + binding.referencePaths.forEach(path => { + if (!references.has(path)) { + references.add(path); + getFunctionReferences(path, scopeParent, references); + } + }); + } + + return references; +} + +function getIdAndFunctionReferences(name, parent) { + // Returns false if there's an error. Otherwise returns a list of references. + const binding = parent.scope.getBinding(name); + + if (!binding) { + return false; + } + + const references = binding.referencePaths.reduce((references, ref) => { + references.add(ref); + getFunctionReferences(ref, parent, references); + return references; + }, new Set()); + return Array.from(references); +} + +function validateTopLevel(path) { + // Ensures the structure is of the form (roughly): + // { + // ... + // var foo = expr; + // ... + // } + // returns null if not of this form + // otherwise returns [foo as string, ?rval, index of the variable declaration] + const declarations = path.get("declarations"); + + if (declarations.length !== 1) { + return; + } + + const declaration = declarations[0]; + const id = declaration.get("id"), + init = declaration.get("init"); + + if (!id.isIdentifier()) { + return; + } + + const parent = path.parentPath; + + if (!parent.isBlockParent() || !parent.isScopable()) { + return; + } + + const body = parent.get("body"); + + if (!Array.isArray(body)) { + return; + } + + const startIndex = body.indexOf(path); + + if (startIndex === -1) { + return; + } + + return [id.node.name, init, startIndex]; +} + +function collectExpressions(path, isExprTypeValid) { + // input: ExprStatement => 'a | SequenceExpression + // SequenceExpression => 'a list + // Validates 'a is of the right type + // returns null if found inconsistency, else returns Array<"a> + if (path.isExpressionStatement()) { + const exprs = collectExpressions(path.get("expression"), isExprTypeValid); + return exprs !== null ? exprs : null; + } + + if (path.isSequenceExpression()) { + const exprs = path.get("expressions").map(p => collectExpressions(p, isExprTypeValid)); + + if (exprs.some(e => e === null)) { + return null; + } else { + return exprs.reduce((s, n) => s.concat(n), []); // === Array.flatten + } + } + + if (isExprTypeValid(path)) { + return [path]; + } + + return null; +} + +function getContiguousStatementsAndExpressions(body, start, end, isExprTypeValid, checkExpr) { + const statements = []; + let allExprs = []; + + for (let i = start; i < end; i++) { + const exprs = collectExpressions(body[i], isExprTypeValid); + + if (exprs === null || !exprs.every(e => checkExpr(e))) { + break; + } + + statements.push(body[i]); + allExprs = allExprs.concat(exprs); + } + + return [statements, allExprs]; +} + +function getReferenceChecker(references) { + // returns a function s.t. given an expr, returns true iff expr is an ancestor of a reference + return expr => references.some(r => r === expr || r.isDescendant(expr)); +} + +function tryUseCollapser(t, collapser, varDecl, topLevel, checkReference) { + // Returns true iff successfully used the collapser. Otherwise returns undefined. + const _topLevel = _slicedToArray(topLevel, 3), + name = _topLevel[0], + init = _topLevel[1], + startIndex = _topLevel[2]; + + if (!collapser.isInitTypeValid(init)) { + return; + } + + const body = varDecl.parentPath.get("body"); + + const _getContiguousStateme = getContiguousStatementsAndExpressions(body, startIndex + 1, body.length, collapser.isExpressionTypeValid, collapser.getExpressionChecker(name, checkReference)), + _getContiguousStateme2 = _slicedToArray(_getContiguousStateme, 2), + statements = _getContiguousStateme2[0], + exprs = _getContiguousStateme2[1]; + + if (statements.length === 0) { + return; + } + + const assignments = exprs.map(e => collapser.extractAssignment(e)); + const oldInit = init.node; + const newInit = t.cloneDeep(oldInit); + + if (!assignments.every(assignment => collapser.addSuccessfully(t, assignment, newInit))) { + return; + } // some collapses may increase the size + + + if (!collapser.isSizeSmaller({ + newInit, + oldInit, + varDecl, + assignments, + statements + })) { + return; + } + + init.replaceWith(newInit); + statements.forEach(s => s.remove()); + return true; +} + +module.exports = function ({ + types: t +}) { + return { + name: "transform-inline-consecutive-adds", + visitor: { + VariableDeclaration(varDecl) { + const topLevel = validateTopLevel(varDecl); + + if (!topLevel) { + return; + } + + const _topLevel2 = _slicedToArray(topLevel, 1), + name = _topLevel2[0]; + + const references = getIdAndFunctionReferences(name, varDecl.parentPath); + + if (references === false) { + return; + } + + const checkReference = getReferenceChecker(references); + + if (COLLAPSERS.some(c => tryUseCollapser(t, c, varDecl, topLevel, checkReference))) { + return; + } + } + + } + }; +}; \ No newline at end of file diff --git a/node_modules/babel-plugin-transform-inline-consecutive-adds/lib/object-collapser.js b/node_modules/babel-plugin-transform-inline-consecutive-adds/lib/object-collapser.js new file mode 100644 index 00000000..c8fe59ad --- /dev/null +++ b/node_modules/babel-plugin-transform-inline-consecutive-adds/lib/object-collapser.js @@ -0,0 +1,60 @@ +"use strict"; + +const Collapser = require("./collapser"); + +class ObjectCollapser extends Collapser { + isInitTypeValid(init) { + return init.isObjectExpression(); + } + + isExpressionTypeValid(expr) { + return expr.isAssignmentExpression(); + } + + getExpressionChecker(objName, checkReference) { + return expr => { + // checks expr is of form: + // foo.a = rval | foo[a] = rval + const left = expr.get("left"); + + if (!left.isMemberExpression()) { + return false; + } + + const obj = left.get("object"), + prop = left.get("property"); + + if (!obj.isIdentifier() || obj.node.name !== objName) { + return false; + } + + if (!prop.isIdentifier() && checkReference(prop)) { + return false; + } + + if (left.node.computed && !(prop.isStringLiteral() || prop.isNumericLiteral())) { + return false; + } + + const right = expr.get("right"); + + if (checkReference(right)) { + return false; + } + + return true; + }; + } + + extractAssignment(expr) { + return [expr.node.left.property, expr.node.right]; + } + + addSuccessfully(t, [left, right], init) { + init.properties.push(t.objectProperty(left, right)); + return true; + } + +} + +module.exports = ObjectCollapser; \ No newline at end of file diff --git a/node_modules/babel-plugin-transform-inline-consecutive-adds/lib/set-collapser.js b/node_modules/babel-plugin-transform-inline-consecutive-adds/lib/set-collapser.js new file mode 100644 index 00000000..e4b37b31 --- /dev/null +++ b/node_modules/babel-plugin-transform-inline-consecutive-adds/lib/set-collapser.js @@ -0,0 +1,61 @@ +"use strict"; + +const Collapser = require("./collapser"); + +class SetCollapser extends Collapser { + isInitTypeValid(init) { + return init.isNewExpression() && init.get("callee").isIdentifier() && init.node.callee.name === "Set" && ( // other iterables might not be append-able + init.node.arguments.length === 0 || init.node.arguments.length === 1 && init.get("arguments")[0].isArrayExpression()); + } + + isExpressionTypeValid(expr) { + return expr.isCallExpression(); + } + + getExpressionChecker(objName, checkReference) { + return expr => { + // checks expr is of form: + // foo.add(rval) + const callee = expr.get("callee"); + + if (!callee.isMemberExpression()) { + return false; + } + + const obj = callee.get("object"), + prop = callee.get("property"); + + if (!obj.isIdentifier() || obj.node.name !== objName || !prop.isIdentifier() || prop.node.name !== "add") { + return false; + } + + const args = expr.get("arguments"); + + if (args.length !== 1) { + return false; + } + + if (checkReference(args[0])) { + return false; + } + + return true; + }; + } + + extractAssignment(expr) { + return expr.node.arguments[0]; + } + + addSuccessfully(t, arg, init) { + if (init.arguments.length === 0) { + init.arguments.push(t.arrayExpression()); + } + + init.arguments[0].elements.push(arg); + return true; + } + +} + +module.exports = SetCollapser; \ No newline at end of file diff --git a/node_modules/babel-plugin-transform-inline-consecutive-adds/package.json b/node_modules/babel-plugin-transform-inline-consecutive-adds/package.json new file mode 100644 index 00000000..b79a2f75 --- /dev/null +++ b/node_modules/babel-plugin-transform-inline-consecutive-adds/package.json @@ -0,0 +1,14 @@ +{ + "name": "babel-plugin-transform-inline-consecutive-adds", + "version": "0.4.3", + "description": "This plugin inlines consecutive property assignments, array pushes, etc.", + "keywords": [ + "babel-plugin" + ], + "homepage": "https://github.com/babel/minify#readme", + "bugs": "https://github.com/babel/minify/issues", + "license": "MIT", + "author": "shinew", + "main": "lib/index.js", + "repository": "https://github.com/babel/minify/tree/master/packages/babel-plugin-transform-inline-consecutive-adds" +} -- cgit v1.2.3