1
0
mirror of https://github.com/S2-/minifyfromhtml.git synced 2025-08-03 04:10:04 +02:00

add some packages

This commit is contained in:
s2
2018-05-05 13:54:07 +02:00
parent 48c1138518
commit ff6e20677d
3738 changed files with 215920 additions and 0 deletions

View File

@@ -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
```
## 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"]
});
```

View File

@@ -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;

View File

@@ -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;

View File

@@ -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;

View File

@@ -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;
}
}
}
};
};

View File

@@ -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;

View File

@@ -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;

View File

@@ -0,0 +1,46 @@
{
"_from": "babel-plugin-transform-inline-consecutive-adds@^0.4.1",
"_id": "babel-plugin-transform-inline-consecutive-adds@0.4.1",
"_inBundle": false,
"_integrity": "sha1-F13t/odsL/enjHUe1NncBZfRFx0=",
"_location": "/babel-plugin-transform-inline-consecutive-adds",
"_phantomChildren": {},
"_requested": {
"type": "range",
"registry": true,
"raw": "babel-plugin-transform-inline-consecutive-adds@^0.4.1",
"name": "babel-plugin-transform-inline-consecutive-adds",
"escapedName": "babel-plugin-transform-inline-consecutive-adds",
"rawSpec": "^0.4.1",
"saveSpec": null,
"fetchSpec": "^0.4.1"
},
"_requiredBy": [
"/babel-preset-minify"
],
"_resolved": "https://registry.npmjs.org/babel-plugin-transform-inline-consecutive-adds/-/babel-plugin-transform-inline-consecutive-adds-0.4.1.tgz",
"_shasum": "175dedfe876c2ff7a78c751ed4d9dc0597d1171d",
"_spec": "babel-plugin-transform-inline-consecutive-adds@^0.4.1",
"_where": "/home/s2/Documents/Code/minifyfromhtml/node_modules/babel-preset-minify",
"author": {
"name": "shinew"
},
"bugs": {
"url": "https://github.com/babel/minify/issues"
},
"bundleDependencies": false,
"deprecated": false,
"description": "This plugin inlines consecutive property assignments, array pushes, etc.",
"homepage": "https://github.com/babel/minify#readme",
"keywords": [
"babel-plugin"
],
"license": "MIT",
"main": "lib/index.js",
"name": "babel-plugin-transform-inline-consecutive-adds",
"repository": {
"type": "git",
"url": "https://github.com/babel/minify/tree/master/packages/babel-plugin-transform-inline-consecutive-adds"
},
"version": "0.4.1"
}