From 9dfcf0f116bb9040966351c0dd61625d713e5a7d Mon Sep 17 00:00:00 2001 From: Logan Smyth Date: Mon, 25 Sep 2017 15:02:20 -0700 Subject: [PATCH] Split the simple-access transforms out of the module transform into a general helper. --- .../package.json | 1 + .../src/rewrite-live-references.js | 72 +++------------ .../babel-helper-simple-access/.npmignore | 3 + packages/babel-helper-simple-access/README.md | 18 ++++ .../babel-helper-simple-access/package.json | 15 ++++ .../babel-helper-simple-access/src/index.js | 87 +++++++++++++++++++ .../test/fixtures/amd/remap/expected.js | 2 +- .../test/fixtures/interop/remap/expected.js | 2 +- .../test/fixtures/umd/remap/expected.js | 2 +- 9 files changed, 137 insertions(+), 65 deletions(-) create mode 100644 packages/babel-helper-simple-access/.npmignore create mode 100644 packages/babel-helper-simple-access/README.md create mode 100644 packages/babel-helper-simple-access/package.json create mode 100644 packages/babel-helper-simple-access/src/index.js diff --git a/packages/babel-helper-module-transforms/package.json b/packages/babel-helper-module-transforms/package.json index f989c44eee..f5c27e14a1 100644 --- a/packages/babel-helper-module-transforms/package.json +++ b/packages/babel-helper-module-transforms/package.json @@ -9,6 +9,7 @@ "main": "lib/index.js", "dependencies": { "babel-helper-module-imports": "7.0.0-beta.2", + "babel-helper-simple-access": "7.0.0-beta.2", "babel-template": "7.0.0-beta.2", "babel-types": "7.0.0-beta.2", "lodash": "^4.2.0" diff --git a/packages/babel-helper-module-transforms/src/rewrite-live-references.js b/packages/babel-helper-module-transforms/src/rewrite-live-references.js index 466a90554a..c09e7a3cfe 100644 --- a/packages/babel-helper-module-transforms/src/rewrite-live-references.js +++ b/packages/babel-helper-module-transforms/src/rewrite-live-references.js @@ -1,5 +1,7 @@ +import assert from "assert"; import * as t from "babel-types"; import template from "babel-template"; +import simplifyAccess from "babel-helper-simple-access"; import type { ModuleMetadata } from "./"; @@ -44,6 +46,12 @@ export default function rewriteLiveReferences( exported, // local name => exported name list }); + simplifyAccess( + programPath, + // NOTE(logan): The 'Array.from' calls are to make this code with in loose mode. + new Set([...Array.from(imported.keys()), ...Array.from(exported.keys())]), + ); + // Rewrite reads/writes from imports and exports to have the correct behavior. programPath.traverse(rewriteReferencesVisitor, { seen: new WeakSet(), @@ -188,57 +196,6 @@ const rewriteReferencesVisitor = { } }, - UpdateExpression: { - exit(path) { - const { scope, imported, exported } = this; - - const arg = path.get("argument"); - if (!arg.isIdentifier()) return; - const localName = arg.node.name; - - if (!imported.has(localName) && !exported.has(localName)) { - return; - } - - // redeclared in this scope - if (scope.getBinding(localName) !== path.scope.getBinding(localName)) { - return; - } - - const exportedNames = exported.get(localName) || []; - - if (exportedNames.length > 0 || imported.has(localName)) { - if ( - path.node.prefix || - (path.parentPath.isExpressionStatement() && - !path.isCompletionRecord()) - ) { - // ++i => (i += 1); - path.replaceWith( - t.assignmentExpression("+=", arg.node, t.numericLiteral(1)), - ); - } else { - const varName = path.scope.generateDeclaredUidIdentifier("old"); - - const assignment = t.binaryExpression( - path.node.operator.slice(0, 1), - varName, - t.numericLiteral(1), - ); - - // i++ => (_tmp = i, i = _tmp + 1, _tmp) - path.replaceWith( - t.sequenceExpression([ - t.assignmentExpression("=", varName, arg.node), - t.assignmentExpression("=", arg.node, assignment), - varName, - ]), - ); - } - } - }, - }, - AssignmentExpression: { exit(path) { const { @@ -267,23 +224,14 @@ const rewriteReferencesVisitor = { const exportedNames = exported.get(localName) || []; const importData = imported.get(localName); if (exportedNames.length > 0 || importData) { + assert(path.node.operator === "=", "Path was not simplified"); + const assignment = path.node; if (importData) { assignment.left = buildImportReference(importData) || assignment.left; - if (path.node.operator !== "=") { - const op = path.node.operator.slice(0, -1); - path.node.operator = "="; - - assignment.right = t.binaryExpression( - op, - assignment.left, - assignment.right, - ); - } - assignment.right = t.sequenceExpression([ assignment.right, buildImportThrow(localName), diff --git a/packages/babel-helper-simple-access/.npmignore b/packages/babel-helper-simple-access/.npmignore new file mode 100644 index 0000000000..f980694583 --- /dev/null +++ b/packages/babel-helper-simple-access/.npmignore @@ -0,0 +1,3 @@ +src +test +*.log diff --git a/packages/babel-helper-simple-access/README.md b/packages/babel-helper-simple-access/README.md new file mode 100644 index 0000000000..bbb7fb791d --- /dev/null +++ b/packages/babel-helper-simple-access/README.md @@ -0,0 +1,18 @@ +# babel-helper-simple-assignment + +There are many cases where it is hard to perform transformations because a +piece of code using complex structures. Say you want to rewrite all accesses +to a given variable, and there are cases like + +``` +i += 1 +--i; +``` + +It is difficult to work with. + +This helper can handle converting these to simple access patterns of + +## Usage + +TODO diff --git a/packages/babel-helper-simple-access/package.json b/packages/babel-helper-simple-access/package.json new file mode 100644 index 0000000000..1cb5e87cca --- /dev/null +++ b/packages/babel-helper-simple-access/package.json @@ -0,0 +1,15 @@ +{ + "name": "babel-helper-simple-access", + "version": "7.0.0-beta.2", + "description": "Babel helper for ensuring that access to a given value is performed through simple accesses", + "author": "Logan Smyth ", + "homepage": "https://babeljs.io/", + "license": "MIT", + "repository": "https://github.com/babel/babel/tree/master/packages/babel-helper-simple-access", + "main": "lib/index.js", + "dependencies": { + "babel-template": "7.0.0-beta.2", + "babel-types": "7.0.0-beta.2", + "lodash": "^4.2.0" + } +} diff --git a/packages/babel-helper-simple-access/src/index.js b/packages/babel-helper-simple-access/src/index.js new file mode 100644 index 0000000000..23fd22ffec --- /dev/null +++ b/packages/babel-helper-simple-access/src/index.js @@ -0,0 +1,87 @@ +import * as t from "babel-types"; + +export default function simplifyAccess(path: NodePath, bindingNames) { + path.traverse(simpleAssignmentVisitor, { + scope: path.scope, + bindingNames, + seen: new WeakSet(), + }); +} + +const simpleAssignmentVisitor = { + UpdateExpression: { + exit(path) { + const { scope, bindingNames } = this; + + const arg = path.get("argument"); + if (!arg.isIdentifier()) return; + const localName = arg.node.name; + + if (!bindingNames.has(localName)) return; + + // redeclared in this scope + if (scope.getBinding(localName) !== path.scope.getBinding(localName)) { + return; + } + + if ( + path.node.prefix || + (path.parentPath.isExpressionStatement() && !path.isCompletionRecord()) + ) { + // ++i => (i += 1); + path.replaceWith( + t.assignmentExpression("+=", arg.node, t.numericLiteral(1)), + ); + } else { + const varName = path.scope.generateDeclaredUidIdentifier("old"); + + const assignment = t.binaryExpression( + path.node.operator.slice(0, 1), + varName, + t.numericLiteral(1), + ); + + // i++ => (_tmp = i, i = _tmp + 1, _tmp) + path.replaceWith( + t.sequenceExpression([ + t.assignmentExpression("=", varName, arg.node), + t.assignmentExpression("=", arg.node, assignment), + varName, + ]), + ); + } + }, + }, + + AssignmentExpression: { + exit(path) { + const { scope, seen, bindingNames } = this; + + if (path.node.operator === "=") return; + + if (seen.has(path.node)) return; + seen.add(path.node); + + const left = path.get("left"); + if (!left.isIdentifier()) return; + + // Simple update-assign foo += 1; + // => exports.foo = (foo += 1); + const localName = left.node.name; + + if (!bindingNames.has(localName)) return; + + // redeclared in this scope + if (scope.getBinding(localName) !== path.scope.getBinding(localName)) { + return; + } + + path.node.right = t.binaryExpression( + path.node.operator.slice(0, -1), + path.node.left, + path.node.right, + ); + path.node.operator = "="; + }, + }, +}; diff --git a/packages/babel-plugin-transform-es2015-modules-amd/test/fixtures/amd/remap/expected.js b/packages/babel-plugin-transform-es2015-modules-amd/test/fixtures/amd/remap/expected.js index a86943f369..f66b5b3862 100644 --- a/packages/babel-plugin-transform-es2015-modules-amd/test/fixtures/amd/remap/expected.js +++ b/packages/babel-plugin-transform-es2015-modules-amd/test/fixtures/amd/remap/expected.js @@ -8,7 +8,7 @@ define(["exports"], function (_exports) { var test = 2; _exports.test = test; _exports.test = test = 5; - _exports.test = test += 1; + _exports.test = test = test + 1; (function () { var test = 2; diff --git a/packages/babel-plugin-transform-es2015-modules-commonjs/test/fixtures/interop/remap/expected.js b/packages/babel-plugin-transform-es2015-modules-commonjs/test/fixtures/interop/remap/expected.js index 9d5d989969..b54ad1d491 100644 --- a/packages/babel-plugin-transform-es2015-modules-commonjs/test/fixtures/interop/remap/expected.js +++ b/packages/babel-plugin-transform-es2015-modules-commonjs/test/fixtures/interop/remap/expected.js @@ -7,7 +7,7 @@ exports.f = exports.e = exports.c = exports.a = exports.test = void 0; var test = 2; exports.test = test; exports.test = test = 5; -exports.test = test += 1; +exports.test = test = test + 1; (function () { var test = 2; diff --git a/packages/babel-plugin-transform-es2015-modules-umd/test/fixtures/umd/remap/expected.js b/packages/babel-plugin-transform-es2015-modules-umd/test/fixtures/umd/remap/expected.js index 652f644cdf..45fd662b37 100644 --- a/packages/babel-plugin-transform-es2015-modules-umd/test/fixtures/umd/remap/expected.js +++ b/packages/babel-plugin-transform-es2015-modules-umd/test/fixtures/umd/remap/expected.js @@ -20,7 +20,7 @@ var test = 2; _exports.test = test; _exports.test = test = 5; - _exports.test = test += 1; + _exports.test = test = test + 1; (function () { var test = 2;