diff --git a/packages/babel-plugin-constant-folding/.npmignore b/packages/babel-plugin-constant-folding/.npmignore new file mode 100644 index 0000000000..cace0d6ddc --- /dev/null +++ b/packages/babel-plugin-constant-folding/.npmignore @@ -0,0 +1,3 @@ +node_modules +*.log +src diff --git a/packages/babel-plugin-constant-folding/README.md b/packages/babel-plugin-constant-folding/README.md new file mode 100644 index 0000000000..ea3628c133 --- /dev/null +++ b/packages/babel-plugin-constant-folding/README.md @@ -0,0 +1,35 @@ +# babel-plugin-constant-folding + +Compile static constants (ie. code that we can statically determine to be constant at runtime) + +## Installation + +```sh +$ npm install babel-plugin-constant-folding +``` + +## Usage + +### Via `.babelrc` (Recommended) + +**.babelrc** + +```json +{ + "plugins": ["constant-folding"] +} +``` + +### Via CLI + +```sh +$ babel --plugins constant-folding script.js +``` + +### Via Node API + +```javascript +require("babel-core").transform("code", { + plugins: ["constant-folding"] +}); +``` diff --git a/packages/babel-plugin-constant-folding/package.json b/packages/babel-plugin-constant-folding/package.json new file mode 100644 index 0000000000..e08254ff9e --- /dev/null +++ b/packages/babel-plugin-constant-folding/package.json @@ -0,0 +1,19 @@ +{ + "name": "babel-plugin-constant-folding", + "version": "1.0.1", + "description": "Compile static constants (ie. code that we can statically determine to be constant at runtime)", + "repository": "babel-plugins/babel-plugin-constant-folding", + "license": "MIT", + "main": "lib/index.js", + "devDependencies": { + "babel": "^5.6.0" + }, + "scripts": { + "build": "babel-plugin build", + "push": "babel-plugin publish", + "test": "babel-plugin test" + }, + "keywords": [ + "babel-plugin" + ] +} diff --git a/packages/babel-plugin-constant-folding/src/index.js b/packages/babel-plugin-constant-folding/src/index.js new file mode 100644 index 0000000000..e610b8a7a5 --- /dev/null +++ b/packages/babel-plugin-constant-folding/src/index.js @@ -0,0 +1,74 @@ +export default function ({ Plugin, types: t }) { + return new Plugin("constant-folding", { + metadata: { + group: "builtin-prepass", + experimental: true + }, + + visitor: { + AssignmentExpression() { + var left = this.get("left"); + if (!left.isIdentifier()) return; + + var binding = this.scope.getBinding(left.node.name); + if (!binding || binding.hasDeoptValue) return; + + var evaluated = this.get("right").evaluate(); + if (evaluated.confident) { + binding.setValue(evaluated.value); + } else { + binding.deoptValue(); + } + }, + + IfStatement() { + var evaluated = this.get("test").evaluate(); + if (!evaluated.confident) { + // todo: deopt binding values for constant violations inside + return this.skip(); + } + + if (evaluated.value) { + this.skipKey("alternate"); + } else { + this.skipKey("consequent"); + } + }, + + Scopable: { + enter() { + var funcScope = this.scope.getFunctionParent(); + + for (var name in this.scope.bindings) { + var binding = this.scope.bindings[name]; + var deopt = false; + + for (var path of (binding.constantViolations: Array)) { + var funcViolationScope = path.scope.getFunctionParent(); + if (funcViolationScope !== funcScope) { + deopt = true; + break; + } + } + + if (deopt) binding.deoptValue(); + } + }, + + exit() { + for (var name in this.scope.bindings) { + var binding = this.scope.bindings[name]; + binding.clearValue(); + } + } + }, + + Expression: { + exit() { + var res = this.evaluate(); + if (res.confident) return t.valueToNode(res.value); + } + } + } + }); +} diff --git a/packages/babel-plugin-dead-code-elimination/.npmignore b/packages/babel-plugin-dead-code-elimination/.npmignore new file mode 100644 index 0000000000..cace0d6ddc --- /dev/null +++ b/packages/babel-plugin-dead-code-elimination/.npmignore @@ -0,0 +1,3 @@ +node_modules +*.log +src diff --git a/packages/babel-plugin-dead-code-elimination/README.md b/packages/babel-plugin-dead-code-elimination/README.md new file mode 100644 index 0000000000..af182e81e8 --- /dev/null +++ b/packages/babel-plugin-dead-code-elimination/README.md @@ -0,0 +1,35 @@ +# babel-plugin-dead-code-elimination + +Eliminate dead code + +## Installation + +```sh +$ npm install babel-plugin-dead-code-elimination +``` + +## Usage + +### Via `.babelrc` (Recommended) + +**.babelrc** + +```json +{ + "plugins": ["dead-code-elimination"] +} +``` + +### Via CLI + +```sh +$ babel --plugins dead-code-elimination script.js +``` + +### Via Node API + +```javascript +require("babel-core").transform("code", { + plugins: ["dead-code-elimination"] +}); +``` diff --git a/packages/babel-plugin-dead-code-elimination/package.json b/packages/babel-plugin-dead-code-elimination/package.json new file mode 100644 index 0000000000..dd728a7545 --- /dev/null +++ b/packages/babel-plugin-dead-code-elimination/package.json @@ -0,0 +1,19 @@ +{ + "name": "babel-plugin-dead-code-elimination", + "version": "1.0.2", + "description": "Eliminate dead code", + "repository": "babel-plugins/babel-plugin-dead-code-elimination", + "license": "MIT", + "main": "lib/index.js", + "devDependencies": { + "babel": "^5.6.0" + }, + "scripts": { + "build": "babel-plugin build", + "push": "babel-plugin publish", + "test": "babel-plugin test" + }, + "keywords": [ + "babel-plugin" + ] +} diff --git a/packages/babel-plugin-dead-code-elimination/src/index.js b/packages/babel-plugin-dead-code-elimination/src/index.js new file mode 100644 index 0000000000..c869422e75 --- /dev/null +++ b/packages/babel-plugin-dead-code-elimination/src/index.js @@ -0,0 +1,157 @@ +export default function ({ Plugin, types: t }) { + function toStatements(node) { + if (t.isBlockStatement(node)) { + var hasBlockScoped = false; + + for (var i = 0; i < node.body.length; i++) { + var bodyNode = node.body[i]; + if (t.isBlockScoped(bodyNode)) hasBlockScoped = true; + } + + if (!hasBlockScoped) { + return node.body; + } + } + + return node; + } + + var visitor = { + ReferencedIdentifier(node, parent, scope) { + var binding = scope.getBinding(node.name); + if (!binding || binding.references > 1 || !binding.constant) return; + if (binding.kind === "param" || binding.kind === "module") return; + + var replacement = binding.path.node; + if (t.isVariableDeclarator(replacement)) { + replacement = replacement.init; + } + if (!replacement) return; + + // ensure it's a "pure" type + if (!scope.isPure(replacement, true)) return; + + if (t.isClass(replacement) || t.isFunction(replacement)) { + // don't change this if it's in a different scope, this can be bad + // for performance since it may be inside a loop or deeply nested in + // hot code + if (binding.path.scope.parent !== scope) return; + } + + if (this.findParent((path) => path.node === replacement)) { + return; + } + + t.toExpression(replacement); + scope.removeBinding(node.name); + binding.path.dangerouslyRemove(); + return replacement; + }, + + "ClassDeclaration|FunctionDeclaration"(node, parent, scope) { + var binding = scope.getBinding(node.id.name); + if (binding && !binding.referenced) { + this.dangerouslyRemove(); + } + }, + + VariableDeclarator(node, parent, scope) { + if (!t.isIdentifier(node.id) || !scope.isPure(node.init, true)) return; + visitor["ClassDeclaration|FunctionDeclaration"].apply(this, arguments); + }, + + ConditionalExpression(node) { + var evaluateTest = this.get("test").evaluateTruthy(); + if (evaluateTest === true) { + return node.consequent; + } else if (evaluateTest === false) { + return node.alternate; + } + }, + + BlockStatement() { + var paths = this.get("body"); + + var purge = false; + + for (var i = 0; i < paths.length; i++) { + let path = paths[i]; + + if (!purge && path.isCompletionStatement()) { + purge = true; + continue; + } + + if (purge && !path.isFunctionDeclaration()) { + path.dangerouslyRemove(); + } + } + }, + + IfStatement: { + exit(node) { + var consequent = node.consequent; + var alternate = node.alternate; + var test = node.test; + + var evaluateTest = this.get("test").evaluateTruthy(); + + // we can check if a test will be truthy 100% and if so then we can inline + // the consequent and completely ignore the alternate + // + // if (true) { foo; } -> { foo; } + // if ("foo") { foo; } -> { foo; } + // + + if (evaluateTest === true) { + return toStatements(consequent); + } + + // we can check if a test will be falsy 100% and if so we can inline the + // alternate if there is one and completely remove the consequent + // + // if ("") { bar; } else { foo; } -> { foo; } + // if ("") { bar; } -> + // + + if (evaluateTest === false) { + if (alternate) { + return toStatements(alternate); + } else { + return this.dangerouslyRemove(); + } + } + + // remove alternate blocks that are empty + // + // if (foo) { foo; } else {} -> if (foo) { foo; } + // + + if (t.isBlockStatement(alternate) && !alternate.body.length) { + alternate = node.alternate = null; + } + + // if the consequent block is empty turn alternate blocks into a consequent + // and flip the test + // + // if (foo) {} else { bar; } -> if (!foo) { bar; } + // + + if (t.isBlockStatement(consequent) && !consequent.body.length && t.isBlockStatement(alternate) && alternate.body.length) { + node.consequent = node.alternate; + node.alternate = null; + node.test = t.unaryExpression("!", test, true); + } + } + } + }; + + return new Plugin("dead-code-elimination", { + metadata: { + group: "builtin-pre", + experimental: true + }, + + visitor + }); +} diff --git a/packages/babel-plugin-eval/.npmignore b/packages/babel-plugin-eval/.npmignore new file mode 100644 index 0000000000..cace0d6ddc --- /dev/null +++ b/packages/babel-plugin-eval/.npmignore @@ -0,0 +1,3 @@ +node_modules +*.log +src diff --git a/packages/babel-plugin-eval/README.md b/packages/babel-plugin-eval/README.md new file mode 100644 index 0000000000..cae0be25d5 --- /dev/null +++ b/packages/babel-plugin-eval/README.md @@ -0,0 +1,49 @@ +# babel-plugin-eval + +Compile eval calls with string literals + +## Example + +**In** + +```javascript +eval("(() => 'foo')"); +``` + +**Out** + +```javascript +eval("(function () { return 'foo'; })"); +``` + +## Installation + +```sh +$ npm install babel-plugin-eval +``` + +## Usage + +### Via `.babelrc` (Recommended) + +**.babelrc** + +```json +{ + "plugins": ["eval"] +} +``` + +### Via CLI + +```sh +$ babel --plugins eval script.js +``` + +### Via Node API + +```javascript +require("babel-core").transform("code", { + plugins: ["eval"] +}); +``` diff --git a/packages/babel-plugin-eval/package.json b/packages/babel-plugin-eval/package.json new file mode 100644 index 0000000000..5eaddfdb57 --- /dev/null +++ b/packages/babel-plugin-eval/package.json @@ -0,0 +1,14 @@ +{ + "name": "babel-plugin-eval", + "version": "1.0.1", + "description": "Compile eval calls with string literals", + "repository": "babel-plugins/babel-plugin-eval", + "license": "MIT", + "main": "lib/index.js", + "devDependencies": { + "babel": "^5.6.0" + }, + "keywords": [ + "babel-plugin" + ] +} diff --git a/packages/babel-plugin-eval/src/index.js b/packages/babel-plugin-eval/src/index.js new file mode 100644 index 0000000000..0066fd3d25 --- /dev/null +++ b/packages/babel-plugin-eval/src/index.js @@ -0,0 +1,23 @@ +export default function ({ Plugin, parse, traverse }) { + return new Plugin("eval", { + metadata: { + group: "builtin-pre", + }, + + visitor: { + CallExpression(node) { + if (this.get("callee").isIdentifier({ name: "eval" }) && node.arguments.length === 1) { + var evaluate = this.get("arguments")[0].evaluate(); + if (!evaluate.confident) return; + + var code = evaluate.value; + if (typeof code !== "string") return; + + var ast = parse(code); + traverse.removeProperties(ast); + return ast.program; + } + } + } + }); +} diff --git a/packages/babel-plugin-inline-environment-variables/.npmignore b/packages/babel-plugin-inline-environment-variables/.npmignore new file mode 100644 index 0000000000..cace0d6ddc --- /dev/null +++ b/packages/babel-plugin-inline-environment-variables/.npmignore @@ -0,0 +1,3 @@ +node_modules +*.log +src diff --git a/packages/babel-plugin-inline-environment-variables/README.md b/packages/babel-plugin-inline-environment-variables/README.md new file mode 100644 index 0000000000..8e4a154852 --- /dev/null +++ b/packages/babel-plugin-inline-environment-variables/README.md @@ -0,0 +1,35 @@ +# babel-plugin-inline-environment-variables + +Inline environment variables + +## Installation + +```sh +$ npm install babel-plugin-inline-environment-variables +``` + +## Usage + +### Via `.babelrc` (Recommended) + +**.babelrc** + +```json +{ + "plugins": ["inline-environment-variables"] +} +``` + +### Via CLI + +```sh +$ babel --plugins inline-environment-variables script.js +``` + +### Via Node API + +```javascript +require("babel-core").transform("code", { + plugins: ["inline-environment-variables"] +}); +``` diff --git a/packages/babel-plugin-inline-environment-variables/package.json b/packages/babel-plugin-inline-environment-variables/package.json new file mode 100644 index 0000000000..8691170cac --- /dev/null +++ b/packages/babel-plugin-inline-environment-variables/package.json @@ -0,0 +1,11 @@ +{ + "name": "babel-plugin-inline-environment-variables", + "version": "1.0.1", + "description": "Inline environment variables", + "repository": "babel-plugins/babel-plugin-inline-environment-variables", + "license": "MIT", + "main": "lib/index.js", + "keywords": [ + "babel-plugin" + ] +} diff --git a/packages/babel-plugin-inline-environment-variables/src/index.js b/packages/babel-plugin-inline-environment-variables/src/index.js new file mode 100644 index 0000000000..7425774dfb --- /dev/null +++ b/packages/babel-plugin-inline-environment-variables/src/index.js @@ -0,0 +1,18 @@ +export default function ({ Plugin, types: t }) { + return new Plugin("inline-environment-variables", { + metadata: { + group: "builtin-pre" + }, + + visitor: { + MemberExpression(node) { + if (this.get("object").matchesPattern("process.env")) { + var key = this.toComputedKey(); + if (t.isLiteral(key)) { + return t.valueToNode(process.env[key.value]); + } + } + } + } + }); +} diff --git a/packages/babel-plugin-jscript/.npmignore b/packages/babel-plugin-jscript/.npmignore new file mode 100644 index 0000000000..cace0d6ddc --- /dev/null +++ b/packages/babel-plugin-jscript/.npmignore @@ -0,0 +1,3 @@ +node_modules +*.log +src diff --git a/packages/babel-plugin-jscript/README.md b/packages/babel-plugin-jscript/README.md new file mode 100644 index 0000000000..7c508422eb --- /dev/null +++ b/packages/babel-plugin-jscript/README.md @@ -0,0 +1,35 @@ +# babel-plugin-jscript + +Babel plugin to fix buggy JScript named function expressions + +## Installation + +```sh +$ npm install babel-plugin-jscript +``` + +## Usage + +### Via `.babelrc` (Recommended) + +**.babelrc** + +```json +{ + "plugins": ["jscript"] +} +``` + +### Via CLI + +```sh +$ babel --plugins jscript script.js +``` + +### Via Node API + +```javascript +require("babel-core").transform("code", { + plugins: ["jscript"] +}); +``` diff --git a/packages/babel-plugin-jscript/package.json b/packages/babel-plugin-jscript/package.json new file mode 100644 index 0000000000..dbbe3846f0 --- /dev/null +++ b/packages/babel-plugin-jscript/package.json @@ -0,0 +1,11 @@ +{ + "name": "babel-plugin-jscript", + "version": "1.0.4", + "description": "Babel plugin to fix buggy JScript named function expressions", + "repository": "babel-plugins/babel-plugin-jscript", + "license": "MIT", + "main": "lib/index.js", + "keywords": [ + "babel-plugin" + ] +} diff --git a/packages/babel-plugin-jscript/src/index.js b/packages/babel-plugin-jscript/src/index.js new file mode 100644 index 0000000000..4f7462a931 --- /dev/null +++ b/packages/babel-plugin-jscript/src/index.js @@ -0,0 +1,24 @@ +export default function ({ Plugin, types: t }) { + return new Plugin("jscript", { + metadata: { + group: "builtin-trailing" + }, + + visitor: { + FunctionExpression: { + exit(node) { + if (!node.id) return; + node._ignoreUserWhitespace = true; + + return t.callExpression( + t.functionExpression(null, [], t.blockStatement([ + t.toStatement(node), + t.returnStatement(node.id) + ])), + [] + ); + } + } + } + }); +} diff --git a/packages/babel-plugin-member-expression-literals/.npmignore b/packages/babel-plugin-member-expression-literals/.npmignore new file mode 100644 index 0000000000..cace0d6ddc --- /dev/null +++ b/packages/babel-plugin-member-expression-literals/.npmignore @@ -0,0 +1,3 @@ +node_modules +*.log +src diff --git a/packages/babel-plugin-member-expression-literals/README.md b/packages/babel-plugin-member-expression-literals/README.md new file mode 100644 index 0000000000..0785c2549f --- /dev/null +++ b/packages/babel-plugin-member-expression-literals/README.md @@ -0,0 +1,55 @@ +# babel-plugin-member-expression-literals + +Turn valid member expression property literals into plain identifiers + +## Example + +**In** + +```javascript +obj["foo"] = "isValid"; + +obj.const = "isKeyword"; +obj["var"] = "isKeyword"; +``` + +**Out** + +```javascript +obj.foo = "isValid"; + +obj["const"] = "isKeyword"; +obj["var"] = "isKeyword"; +``` + +## Installation + +```sh +$ npm install babel-plugin-member-expression-literals +``` + +## Usage + +### Via `.babelrc` (Recommended) + +**.babelrc** + +```json +{ + "plugins": ["member-expression-literals"] +} +``` + +### Via CLI + +```sh +$ babel --plugins member-expression-literals script.js +``` + +### Via Node API + +```javascript +require("babel-core").transform("code", { + plugins: ["member-expression-literals"] +}); +``` diff --git a/packages/babel-plugin-member-expression-literals/package.json b/packages/babel-plugin-member-expression-literals/package.json new file mode 100644 index 0000000000..e2338904d2 --- /dev/null +++ b/packages/babel-plugin-member-expression-literals/package.json @@ -0,0 +1,11 @@ +{ + "name": "babel-plugin-member-expression-literals", + "version": "1.0.1", + "description": "Turn valid member expression property literals into plain identifiers", + "repository": "babel-plugins/babel-plugin-member-expression-literals", + "license": "MIT", + "main": "lib/index.js", + "keywords": [ + "babel-plugin" + ] +} diff --git a/packages/babel-plugin-member-expression-literals/src/index.js b/packages/babel-plugin-member-expression-literals/src/index.js new file mode 100644 index 0000000000..547dbe2c5d --- /dev/null +++ b/packages/babel-plugin-member-expression-literals/src/index.js @@ -0,0 +1,20 @@ +export default function ({ Plugin, types: t }) { + return new Plugin("member-expression-literals", { + metadata: { + group: "builtin-trailing" + }, + + visitor: { + MemberExpression: { + exit(node) { + var prop = node.property; + if (node.computed && t.isLiteral(prop) && t.isValidIdentifier(prop.value)) { + // foo["bar"] => foo.bar + node.property = t.identifier(prop.value); + node.computed = false; + } + } + } + } + }); +} diff --git a/packages/babel-plugin-property-literals/.npmignore b/packages/babel-plugin-property-literals/.npmignore new file mode 100644 index 0000000000..cace0d6ddc --- /dev/null +++ b/packages/babel-plugin-property-literals/.npmignore @@ -0,0 +1,3 @@ +node_modules +*.log +src diff --git a/packages/babel-plugin-property-literals/README.md b/packages/babel-plugin-property-literals/README.md new file mode 100644 index 0000000000..ed282d96c6 --- /dev/null +++ b/packages/babel-plugin-property-literals/README.md @@ -0,0 +1,57 @@ +# babel-plugin-property-literals + +Turn valid property key literals to plain identifiers + +## Example + +**In** + +```javascript +var obj = { + "foo": "isValid", + var: "isKeyword", + "const": "isKeyword" +}; +``` + +**Out** + +```javascript +var obj = { + foo: "isValid", + "var": "isKeyword", + "const": "isKeyword" +}; +``` + +## Installation + +```sh +$ npm install babel-plugin-property-literals +``` + +## Usage + +### Via `.babelrc` (Recommended) + +**.babelrc** + +```json +{ + "plugins": ["property-literals"] +} +``` + +### Via CLI + +```sh +$ babel --plugins property-literals script.js +``` + +### Via Node API + +```javascript +require("babel-core").transform("code", { + plugins: ["property-literals"] +}); +``` diff --git a/packages/babel-plugin-property-literals/package.json b/packages/babel-plugin-property-literals/package.json new file mode 100644 index 0000000000..22fb554ce6 --- /dev/null +++ b/packages/babel-plugin-property-literals/package.json @@ -0,0 +1,11 @@ +{ + "name": "babel-plugin-property-literals", + "version": "1.0.1", + "description": "Turn valid property key literals to plain identifiers", + "repository": "babel-plugins/babel-plugin-property-literals", + "license": "MIT", + "main": "lib/index.js", + "keywords": [ + "babel-plugin" + ] +} diff --git a/packages/babel-plugin-property-literals/src/index.js b/packages/babel-plugin-property-literals/src/index.js new file mode 100644 index 0000000000..b6c9b9520e --- /dev/null +++ b/packages/babel-plugin-property-literals/src/index.js @@ -0,0 +1,20 @@ +export default function ({ Plugin, types: t }) { + return new Plugin("property-literals", { + metadata: { + group: "builtin-trailing" + }, + + visitor: { + Property: { + exit(node) { + var key = node.key; + if (t.isLiteral(key) && t.isValidIdentifier(key.value)) { + // "foo": "bar" -> foo: "bar" + node.key = t.identifier(key.value); + node.computed = false; + } + } + } + } + }); +} diff --git a/packages/babel-plugin-proto-to-assign/.npmignore b/packages/babel-plugin-proto-to-assign/.npmignore new file mode 100644 index 0000000000..cace0d6ddc --- /dev/null +++ b/packages/babel-plugin-proto-to-assign/.npmignore @@ -0,0 +1,3 @@ +node_modules +*.log +src diff --git a/packages/babel-plugin-proto-to-assign/README.md b/packages/babel-plugin-proto-to-assign/README.md new file mode 100644 index 0000000000..cb06ec7428 --- /dev/null +++ b/packages/babel-plugin-proto-to-assign/README.md @@ -0,0 +1,75 @@ +# babel-plugin-proto-to-assign + +The `proto-to-assign`plugin will transform all `__proto__` assignments to a method that will do a shallow copy of +all properties. + +This means that the following **will** work: + +```javascript +var foo = { a: 1 }; +var bar = { b: 2 }; +bar.__proto__ = foo; +bar.a; // 1 +bar.b; // 2 +``` + +however the following **will not**: + +```javascript +var foo = { a: 1 }; +var bar = { b: 2 }; +bar.__proto__ = foo; +bar.a; // 1 +foo.a = 2; +bar.a; // 1 - should be 2 but remember that nothing is bound and it's a straight copy +``` + +This is a case that you have to be aware of if you intend to use this plugin. + +## Example + +**In** + +```javascript +bar.__proto__ = foo; +``` + +**Out** + +```javascript +var _defaults = ...; + +_defaults(bar, foo); +``` + +## Installation + +```sh +$ npm install babel-plugin-proto-to-assign +``` + +## Usage + +### Via `.babelrc` (Recommended) + +**.babelrc** + +```json +{ + "plugins": ["proto-to-assign"] +} +``` + +### Via CLI + +```sh +$ babel --plugins proto-to-assign script.js +``` + +### Via Node API + +```javascript +require("babel-core").transform("code", { + plugins: ["proto-to-assign"] +}); +``` diff --git a/packages/babel-plugin-proto-to-assign/package.json b/packages/babel-plugin-proto-to-assign/package.json new file mode 100644 index 0000000000..038f7b7c91 --- /dev/null +++ b/packages/babel-plugin-proto-to-assign/package.json @@ -0,0 +1,14 @@ +{ + "name": "babel-plugin-proto-to-assign", + "version": "1.0.4", + "description": "Babel plugin for turning __proto__ into a shallow property clone", + "repository": "babel-plugins/babel-plugin-proto-to-assign", + "license": "MIT", + "main": "lib/index.js", + "keywords": [ + "babel-plugin" + ], + "dependencies": { + "lodash": "^3.9.3" + } +} diff --git a/packages/babel-plugin-proto-to-assign/src/index.js b/packages/babel-plugin-proto-to-assign/src/index.js new file mode 100644 index 0000000000..e172b71892 --- /dev/null +++ b/packages/babel-plugin-proto-to-assign/src/index.js @@ -0,0 +1,66 @@ +import pull from "lodash/array/pull"; + +export default function ({ Plugin, types: t }) { + function isProtoKey(node) { + return t.isLiteral(t.toComputedKey(node, node.key), { value: "__proto__" }); + } + + function isProtoAssignmentExpression(node) { + var left = node.left; + return t.isMemberExpression(left) && t.isLiteral(t.toComputedKey(left, left.property), { value: "__proto__" }); + } + + function buildDefaultsCallExpression(expr, ref, file) { + return t.expressionStatement(t.callExpression(file.addHelper("defaults"), [ref, expr.right])); + } + + return new Plugin("proto-to-assign", { + metadata: { + secondPass: true + }, + + visitor: { + AssignmentExpression(node, parent, scope, file) { + if (!isProtoAssignmentExpression(node)) return; + + var nodes = []; + var left = node.left.object; + var temp = scope.maybeGenerateMemoised(left); + + if (temp) nodes.push(t.expressionStatement(t.assignmentExpression("=", temp, left))); + nodes.push(buildDefaultsCallExpression(node, temp || left, file)); + if (temp) nodes.push(temp); + + return nodes; + }, + + ExpressionStatement(node, parent, scope, file) { + var expr = node.expression; + if (!t.isAssignmentExpression(expr, { operator: "=" })) return; + + if (isProtoAssignmentExpression(expr)) { + return buildDefaultsCallExpression(expr, expr.left.object, file); + } + }, + + ObjectExpression(node, parent, scope, file) { + var proto; + + for (var i = 0; i < node.properties.length; i++) { + var prop = node.properties[i]; + + if (isProtoKey(prop)) { + proto = prop.value; + pull(node.properties, prop); + } + } + + if (proto) { + var args = [t.objectExpression([]), proto]; + if (node.properties.length) args.push(node); + return t.callExpression(file.addHelper("extends"), args); + } + } + } + }); +} diff --git a/packages/babel-plugin-react-constant-elements/.npmignore b/packages/babel-plugin-react-constant-elements/.npmignore new file mode 100644 index 0000000000..cace0d6ddc --- /dev/null +++ b/packages/babel-plugin-react-constant-elements/.npmignore @@ -0,0 +1,3 @@ +node_modules +*.log +src diff --git a/packages/babel-plugin-react-constant-elements/README.md b/packages/babel-plugin-react-constant-elements/README.md new file mode 100644 index 0000000000..fddaabd60f --- /dev/null +++ b/packages/babel-plugin-react-constant-elements/README.md @@ -0,0 +1,35 @@ +# babel-plugin-react-constant-elements + +Treat React JSX elements as value types and hoist them to the highest scope + +## Installation + +```sh +$ npm install babel-plugin-react-constant-elements +``` + +## Usage + +### Via `.babelrc` (Recommended) + +**.babelrc** + +```json +{ + "plugins": ["react-constant-elements"] +} +``` + +### Via CLI + +```sh +$ babel --plugins react-constant-elements script.js +``` + +### Via Node API + +```javascript +require("babel-core").transform("code", { + plugins: ["react-constant-elements"] +}); +``` diff --git a/packages/babel-plugin-react-constant-elements/package.json b/packages/babel-plugin-react-constant-elements/package.json new file mode 100644 index 0000000000..ab31ef069d --- /dev/null +++ b/packages/babel-plugin-react-constant-elements/package.json @@ -0,0 +1,11 @@ +{ + "name": "babel-plugin-react-constant-elements", + "version": "1.0.3", + "description": "Treat React JSX elements as value types and hoist them to the highest scope", + "repository": "babel-plugins/babel-plugin-react-constant-elements", + "license": "MIT", + "main": "lib/index.js", + "keywords": [ + "babel-plugin" + ] +} diff --git a/packages/babel-plugin-react-constant-elements/src/index.js b/packages/babel-plugin-react-constant-elements/src/index.js new file mode 100644 index 0000000000..f5dce29f65 --- /dev/null +++ b/packages/babel-plugin-react-constant-elements/src/index.js @@ -0,0 +1,46 @@ +export default function ({ Plugin }) { + var immutabilityVisitor = { + enter(node, parent, scope, state) { + var stop = () => { + state.isImmutable = false; + this.stop(); + }; + + if (this.isJSXClosingElement()) { + this.skip(); + return; + } + + if (this.isJSXIdentifier({ name: "ref" }) && this.parentPath.isJSXAttribute({ name: node })) { + return stop(); + } + + if (this.isJSXIdentifier() || this.isIdentifier() || this.isJSXMemberExpression()) { + return; + } + + if (!this.isImmutable()) stop(); + } + }; + + return new Plugin("react-constant-elements", { + metadata: { + group: "builtin-basic" + }, + + visitor: { + JSXElement(node) { + if (node._hoisted) return; + + var state = { isImmutable: true }; + this.traverse(immutabilityVisitor, state); + + if (state.isImmutable) { + this.hoist(); + } else { + node._hoisted = true; + } + } + } + }); +} diff --git a/packages/babel-plugin-react-display-name/.npmignore b/packages/babel-plugin-react-display-name/.npmignore new file mode 100644 index 0000000000..cace0d6ddc --- /dev/null +++ b/packages/babel-plugin-react-display-name/.npmignore @@ -0,0 +1,3 @@ +node_modules +*.log +src diff --git a/packages/babel-plugin-react-display-name/README.md b/packages/babel-plugin-react-display-name/README.md new file mode 100644 index 0000000000..56fc028159 --- /dev/null +++ b/packages/babel-plugin-react-display-name/README.md @@ -0,0 +1,35 @@ +# babel-plugin-react-display-name + +Add displayName to React.createClass calls + +## Installation + +```sh +$ npm install babel-plugin-react-display-name +``` + +## Usage + +### Via `.babelrc` (Recommended) + +**.babelrc** + +```json +{ + "plugins": ["react-display-name"] +} +``` + +### Via CLI + +```sh +$ babel --plugins react-display-name script.js +``` + +### Via Node API + +```javascript +require("babel-core").transform("code", { + plugins: ["react-display-name"] +}); +``` diff --git a/packages/babel-plugin-react-display-name/package.json b/packages/babel-plugin-react-display-name/package.json new file mode 100644 index 0000000000..9909916661 --- /dev/null +++ b/packages/babel-plugin-react-display-name/package.json @@ -0,0 +1,11 @@ +{ + "name": "babel-plugin-react-display-name", + "version": "2.0.0", + "description": "Add displayName to React.createClass calls", + "repository": "babel-plugins/babel-plugin-react-display-name", + "license": "MIT", + "main": "lib/index.js", + "keywords": [ + "babel-plugin" + ] +} diff --git a/packages/babel-plugin-react-display-name/src/index.js b/packages/babel-plugin-react-display-name/src/index.js new file mode 100644 index 0000000000..bc85364538 --- /dev/null +++ b/packages/babel-plugin-react-display-name/src/index.js @@ -0,0 +1,84 @@ +import path from "path"; + +export default function ({ Plugin, types: t }) { + function addDisplayName(id, call) { + var props = call.arguments[0].properties; + var safe = true; + + for (var i = 0; i < props.length; i++) { + var prop = props[i]; + var key = t.toComputedKey(prop); + if (t.isLiteral(key, { value: "displayName" })) { + safe = false; + break; + } + } + + if (safe) { + props.unshift(t.property("init", t.identifier("displayName"), t.literal(id))); + } + } + + var isCreateClassCallExpression = t.buildMatchMemberExpression("React.createClass"); + + function isCreateClass(node) { + if (!node || !t.isCallExpression(node)) return false; + + // not React.createClass call member object + if (!isCreateClassCallExpression(node.callee)) return false; + + // no call arguments + var args = node.arguments; + if (args.length !== 1) return false; + + // first node arg is not an object + var first = args[0]; + if (!t.isObjectExpression(first)) return false; + + return true; + } + + return new Plugin("react-display-name", { + metadata: { + group: "builtin-pre" + }, + + visitor: { + ExportDefaultDeclaration(node, parent, scope, file) { + if (isCreateClass(node.declaration)) { + var displayName = file.opts.basename; + + // ./{module name}/index.js + if (displayName === "index") { + displayName = path.basename(path.dirname(file.opts.filename)); + } + + addDisplayName(displayName, node.declaration); + } + }, + + "AssignmentExpression|Property|VariableDeclarator"(node) { + var left, right; + + if (t.isAssignmentExpression(node)) { + left = node.left; + right = node.right; + } else if (t.isProperty(node)) { + left = node.key; + right = node.value; + } else if (t.isVariableDeclarator(node)) { + left = node.id; + right = node.init; + } + + if (t.isMemberExpression(left)) { + left = left.property; + } + + if (t.isIdentifier(left) && isCreateClass(right)) { + addDisplayName(left.name, right); + } + } + } + }); +} diff --git a/packages/babel-plugin-remove-console/.npmignore b/packages/babel-plugin-remove-console/.npmignore new file mode 100644 index 0000000000..cace0d6ddc --- /dev/null +++ b/packages/babel-plugin-remove-console/.npmignore @@ -0,0 +1,3 @@ +node_modules +*.log +src diff --git a/packages/babel-plugin-remove-console/README.md b/packages/babel-plugin-remove-console/README.md new file mode 100644 index 0000000000..5518aa1532 --- /dev/null +++ b/packages/babel-plugin-remove-console/README.md @@ -0,0 +1,35 @@ +# babel-plugin-remove-console + +Remove console.* calls + +## Installation + +```sh +$ npm install babel-plugin-remove-console +``` + +## Usage + +### Via `.babelrc` (Recommended) + +**.babelrc** + +```json +{ + "plugins": ["remove-console"] +} +``` + +### Via CLI + +```sh +$ babel --plugins remove-console script.js +``` + +### Via Node API + +```javascript +require("babel-core").transform("code", { + plugins: ["remove-console"] +}); +``` diff --git a/packages/babel-plugin-remove-console/package.json b/packages/babel-plugin-remove-console/package.json new file mode 100644 index 0000000000..6e8a11388f --- /dev/null +++ b/packages/babel-plugin-remove-console/package.json @@ -0,0 +1,11 @@ +{ + "name": "babel-plugin-remove-console", + "version": "1.0.1", + "description": "Remove console.* calls", + "repository": "babel-plugins/babel-plugin-remove-console", + "license": "MIT", + "main": "lib/index.js", + "keywords": [ + "babel-plugin" + ] +} diff --git a/packages/babel-plugin-remove-console/src/index.js b/packages/babel-plugin-remove-console/src/index.js new file mode 100644 index 0000000000..ca73d14794 --- /dev/null +++ b/packages/babel-plugin-remove-console/src/index.js @@ -0,0 +1,15 @@ +export default function ({ Plugin, types: t }) { + return new Plugin("remove-console", { + metadata: { + group: "builtin-pre" + }, + + visitor: { + CallExpression() { + if (this.get("callee").matchesPattern("console", true)) { + this.dangerouslyRemove(); + } + } + } + }); +} diff --git a/packages/babel-plugin-remove-debugger/.npmignore b/packages/babel-plugin-remove-debugger/.npmignore new file mode 100644 index 0000000000..cace0d6ddc --- /dev/null +++ b/packages/babel-plugin-remove-debugger/.npmignore @@ -0,0 +1,3 @@ +node_modules +*.log +src diff --git a/packages/babel-plugin-remove-debugger/README.md b/packages/babel-plugin-remove-debugger/README.md new file mode 100644 index 0000000000..295dcf659c --- /dev/null +++ b/packages/babel-plugin-remove-debugger/README.md @@ -0,0 +1,35 @@ +# babel-plugin-remove-debugger + +Remove debugger statements + +## Installation + +```sh +$ npm install babel-plugin-remove-debugger +``` + +## Usage + +### Via `.babelrc` (Recommended) + +**.babelrc** + +```json +{ + "plugins": ["remove-debugger"] +} +``` + +### Via CLI + +```sh +$ babel --plugins remove-debugger script.js +``` + +### Via Node API + +```javascript +require("babel-core").transform("code", { + plugins: ["remove-debugger"] +}); +``` diff --git a/packages/babel-plugin-remove-debugger/package.json b/packages/babel-plugin-remove-debugger/package.json new file mode 100644 index 0000000000..ff05e23346 --- /dev/null +++ b/packages/babel-plugin-remove-debugger/package.json @@ -0,0 +1,11 @@ +{ + "name": "babel-plugin-remove-debugger", + "version": "1.0.1", + "description": "Remove debugger statements", + "repository": "babel-plugins/babel-plugin-remove-debugger", + "license": "MIT", + "main": "lib/index.js", + "keywords": [ + "babel-plugin" + ] +} diff --git a/packages/babel-plugin-remove-debugger/src/index.js b/packages/babel-plugin-remove-debugger/src/index.js new file mode 100644 index 0000000000..62f6ca194c --- /dev/null +++ b/packages/babel-plugin-remove-debugger/src/index.js @@ -0,0 +1,13 @@ +export default function ({ Plugin, types: t }) { + return new Plugin("remove-debugger", { + metadata: { + group: "builtin-pre" + }, + + visitor: { + DebuggerStatement() { + this.dangerouslyRemove(); + } + } + }); +} diff --git a/packages/babel-plugin-runtime/.npmignore b/packages/babel-plugin-runtime/.npmignore new file mode 100644 index 0000000000..cace0d6ddc --- /dev/null +++ b/packages/babel-plugin-runtime/.npmignore @@ -0,0 +1,3 @@ +node_modules +*.log +src diff --git a/packages/babel-plugin-runtime/README.md b/packages/babel-plugin-runtime/README.md new file mode 100644 index 0000000000..9abd3c2ff2 --- /dev/null +++ b/packages/babel-plugin-runtime/README.md @@ -0,0 +1,35 @@ +# babel-plugin-runtime + +Externalise references to helpers and builtins, automatically polyfilling your code without polluting globals + +## Installation + +```sh +$ npm install babel-plugin-runtime +``` + +## Usage + +### Via `.babelrc` (Recommended) + +**.babelrc** + +```json +{ + "plugins": ["runtime"] +} +``` + +### Via CLI + +```sh +$ babel --plugins runtime script.js +``` + +### Via Node API + +```javascript +require("babel-core").transform("code", { + plugins: ["runtime"] +}); +``` diff --git a/packages/babel-plugin-runtime/package.json b/packages/babel-plugin-runtime/package.json new file mode 100644 index 0000000000..43432e30f4 --- /dev/null +++ b/packages/babel-plugin-runtime/package.json @@ -0,0 +1,11 @@ +{ + "name": "babel-plugin-runtime", + "version": "1.0.7", + "description": "Externalise references to helpers and builtins, automatically polyfilling your code without polluting globals", + "repository": "babel-plugins/babel-plugin-runtime", + "license": "MIT", + "main": "lib/index.js", + "keywords": [ + "babel-plugin" + ] +} diff --git a/packages/babel-plugin-runtime/src/definitions.json b/packages/babel-plugin-runtime/src/definitions.json new file mode 100644 index 0000000000..9c82814bc5 --- /dev/null +++ b/packages/babel-plugin-runtime/src/definitions.json @@ -0,0 +1,168 @@ +{ + "builtins": { + "Symbol": "symbol", + "Promise": "promise", + "Map": "map", + "WeakMap": "weak-map", + "Set": "set", + "WeakSet": "weak-set" + }, + + "methods": { + "Array": { + "concat": "array/concat", + "copyWithin": "array/copy-within", + "entries": "array/entries", + "every": "array/every", + "fill": "array/fill", + "filter": "array/filter", + "findIndex": "array/find-index", + "find": "array/find", + "forEach": "array/for-each", + "from": "array/from", + "includes": "array/includes", + "indexOf": "array/index-of", + "join": "array/join", + "keys": "array/keys", + "lastIndexOf": "array/last-index-of", + "map": "array/map", + "of": "array/of", + "pop": "array/pop", + "push": "array/push", + "reduceRight": "array/reduce-right", + "reduce": "array/reduce", + "reverse": "array/reverse", + "shift": "array/shift", + "slice": "array/slice", + "some": "array/some", + "sort": "array/sort", + "splice": "array/splice", + "turn": "array/turn", + "unshift": "array/unshift", + "values": "array/values" + }, + + "Object": { + "assign": "object/assign", + "classof": "object/classof", + "create": "object/create", + "define": "object/define", + "defineProperties": "object/define-properties", + "defineProperty": "object/define-property", + "entries": "object/entries", + "freeze": "object/freeze", + "getOwnPropertyDescriptor": "object/get-own-property-descriptor", + "getOwnPropertyDescriptors": "object/get-own-property-descriptors", + "getOwnPropertyNames": "object/get-own-property-names", + "getOwnPropertySymbols": "object/get-own-property-symbols", + "getPrototypePf": "object/get-prototype-of", + "index": "object/index", + "isExtensible": "object/is-extensible", + "isFrozen": "object/is-frozen", + "isObject": "object/is-object", + "isSealed": "object/is-sealed", + "is": "object/is", + "keys": "object/keys", + "make": "object/make", + "preventExtensions": "object/prevent-extensions", + "seal": "object/seal", + "setPrototypeOf": "object/set-prototype-of", + "values": "object/values" + }, + + "RegExp": { + "escape": "regexp/escape" + }, + + "Function": { + "only": "function/only", + "part": "function/part" + }, + + "Math": { + "acosh": "math/acosh", + "asinh": "math/asinh", + "atanh": "math/atanh", + "cbrt": "math/cbrt", + "clz32": "math/clz32", + "cosh": "math/cosh", + "expm1": "math/expm1", + "fround": "math/fround", + "hypot": "math/hypot", + "pot": "math/pot", + "imul": "math/imul", + "log10": "math/log10", + "log1p": "math/log1p", + "log2": "math/log2", + "sign": "math/sign", + "sinh": "math/sinh", + "tanh": "math/tanh", + "trunc": "math/trunc" + }, + + "Date": { + "addLocale": "date/add-locale", + "formatUTC": "date/format-utc", + "format": "date/format" + }, + + "Symbol": { + "for": "symbol/for", + "hasInstance": "symbol/has-instance", + "is-concat-spreadable": "symbol/is-concat-spreadable", + "iterator": "symbol/iterator", + "keyFor": "symbol/key-for", + "match": "symbol/match", + "replace": "symbol/replace", + "search": "symbol/search", + "species": "symbol/species", + "split": "symbol/split", + "toPrimitive": "symbol/to-primitive", + "toStringTag": "symbol/to-string-tag", + "unscopables": "symbol/unscopables" + }, + + "String": { + "at": "string/at", + "codePointAt": "string/code-point-at", + "endsWith": "string/ends-with", + "escapeHTML": "string/escape-html", + "fromCodePoint": "string/from-code-point", + "includes": "string/includes", + "raw": "string/raw", + "repeat": "string/repeat", + "startsWith": "string/starts-with", + "unescapeHTML": "string/unescape-html" + }, + + "Number": { + "EPSILON": "number/epsilon", + "isFinite": "number/is-finite", + "isInteger": "number/is-integer", + "isNaN": "number/is-nan", + "isSafeInteger": "number/is-safe-integer", + "MAX_SAFE_INTEGER": "number/max-safe-integer", + "MIN_SAFE_INTEGER": "number/min-safe-integer", + "parseFloat": "number/parse-float", + "parseInt": "number/parse-int", + "random": "number/random" + }, + + "Reflect": { + "apply": "reflect/apply", + "construct": "reflect/construct", + "defineProperty": "reflect/define-property", + "deleteProperty": "reflect/delete-property", + "enumerate": "reflect/enumerate", + "getOwnPropertyDescriptor": "reflect/get-own-property-descriptor", + "getPrototypeOf": "reflect/get-prototype-of", + "get": "reflect/get", + "has": "reflect/has", + "isExtensible": "reflect/is-extensible", + "ownKeys": "reflect/own-keys", + "preventExtensions": "reflect/prevent-extensions", + "setPrototypeOf": "reflect/set-prototype-of", + "set": "reflect/set" + } + } +} diff --git a/packages/babel-plugin-runtime/src/index.js b/packages/babel-plugin-runtime/src/index.js new file mode 100644 index 0000000000..8baba46ddb --- /dev/null +++ b/packages/babel-plugin-runtime/src/index.js @@ -0,0 +1,114 @@ +import definitions from "./definitions"; + +export default function ({ Plugin, types: t }) { + const RUNTIME_MODULE_NAME = "babel-runtime"; + + function has(obj, key) { + return Object.prototype.hasOwnProperty.call(obj, key); + } + + return new Plugin("runtime", { + metadata: { + group: "builtin-post-modules" + }, + + pre(file) { + file.set("helperGenerator", function (name) { + return file.addImport(`${RUNTIME_MODULE_NAME}/helpers/${name}`, name, "absoluteDefault"); + }); + + file.setDynamic("regeneratorIdentifier", function () { + return file.addImport(`${RUNTIME_MODULE_NAME}/regenerator`, "regeneratorRuntime", "absoluteDefault"); + }); + }, + + visitor: { + ReferencedIdentifier(node, parent, scope, file) { + if (node.name === "regeneratorRuntime") { + return file.get("regeneratorIdentifier"); + } + + if (t.isMemberExpression(parent)) return; + if (!has(definitions.builtins, node.name)) return; + if (scope.getBindingIdentifier(node.name)) return; + + // Symbol() -> _core.Symbol(); new Promise -> new _core.Promise + var modulePath = definitions.builtins[node.name]; + return file.addImport(`${RUNTIME_MODULE_NAME}/core-js/${modulePath}`, node.name, "absoluteDefault"); + }, + + CallExpression(node, parent, scope, file) { + // arr[Symbol.iterator]() -> _core.$for.getIterator(arr) + + if (node.arguments.length) return; + + var callee = node.callee; + if (!t.isMemberExpression(callee)) return; + if (!callee.computed) return; + if (!this.get("callee.property").matchesPattern("Symbol.iterator")) return; + + return t.callExpression(file.addImport(`${RUNTIME_MODULE_NAME}/core-js/get-iterator`, "getIterator", "absoluteDefault"), [callee.object]); + }, + + BinaryExpression(node, parent, scope, file) { + // Symbol.iterator in arr -> core.$for.isIterable(arr) + + if (node.operator !== "in") return; + if (!this.get("left").matchesPattern("Symbol.iterator")) return; + + return t.callExpression( + file.addImport(`${RUNTIME_MODULE_NAME}/core-js/is-iterable`, "isIterable", "absoluteDefault"), + [node.right] + ); + }, + + MemberExpression: { + enter(node, parent, scope, file) { + // Array.from -> _core.Array.from + + if (!this.isReferenced()) return; + + var obj = node.object; + var prop = node.property; + + if (!t.isReferenced(obj, node)) return; + + if (node.computed) return; + + if (!has(definitions.methods, obj.name)) return; + + var methods = definitions.methods[obj.name]; + if (!has(methods, prop.name)) return; + + // doesn't reference the global + if (scope.getBindingIdentifier(obj.name)) return; + + // special case Object.defineProperty to not use core-js when using string keys + if (obj.name === "Object" && prop.name === "defineProperty" && this.parentPath.isCallExpression()) { + var call = this.parentPath.node; + if (call.arguments.length === 3 && t.isLiteral(call.arguments[1])) return; + } + + var modulePath = methods[prop.name]; + return file.addImport(`${RUNTIME_MODULE_NAME}/core-js/${modulePath}`, `${obj.name}$${prop.name}`, "absoluteDefault"); + }, + + exit(node, parent, scope, file) { + if (!this.isReferenced()) return; + + var prop = node.property; + var obj = node.object; + + if (!has(definitions.builtins, obj.name)) return; + if (scope.getBindingIdentifier(obj.name)) return; + + var modulePath = definitions.builtins[obj.name]; + return t.memberExpression( + file.addImport(`${RUNTIME_MODULE_NAME}/core-js/${modulePath}`, `${obj.name}`, "absoluteDefault"), + prop + ); + } + } + } + }); +} diff --git a/packages/babel-plugin-undeclared-variables-check/.npmignore b/packages/babel-plugin-undeclared-variables-check/.npmignore new file mode 100644 index 0000000000..cace0d6ddc --- /dev/null +++ b/packages/babel-plugin-undeclared-variables-check/.npmignore @@ -0,0 +1,3 @@ +node_modules +*.log +src diff --git a/packages/babel-plugin-undeclared-variables-check/README.md b/packages/babel-plugin-undeclared-variables-check/README.md new file mode 100644 index 0000000000..8051e67a12 --- /dev/null +++ b/packages/babel-plugin-undeclared-variables-check/README.md @@ -0,0 +1,35 @@ +# babel-plugin-undeclared-variables-check + +Throw a compile-time error on references to undeclared variables + +## Installation + +```sh +$ npm install babel-plugin-undeclared-variables-check +``` + +## Usage + +### Via `.babelrc` (Recommended) + +**.babelrc** + +```json +{ + "plugins": ["undeclared-variables-check"] +} +``` + +### Via CLI + +```sh +$ babel --plugins undeclared-variables-check script.js +``` + +### Via Node API + +```javascript +require("babel-core").transform("code", { + plugins: ["undeclared-variables-check"] +}); +``` diff --git a/packages/babel-plugin-undeclared-variables-check/package.json b/packages/babel-plugin-undeclared-variables-check/package.json new file mode 100644 index 0000000000..5d8fcfffee --- /dev/null +++ b/packages/babel-plugin-undeclared-variables-check/package.json @@ -0,0 +1,14 @@ +{ + "name": "babel-plugin-undeclared-variables-check", + "version": "1.0.2", + "description": "Throw a compile-time error on references to undeclared variables", + "repository": "babel-plugins/babel-plugin-undeclared-variables-check", + "license": "MIT", + "main": "lib/index.js", + "keywords": [ + "babel-plugin" + ], + "dependencies": { + "leven": "^1.0.2" + } +} diff --git a/packages/babel-plugin-undeclared-variables-check/src/index.js b/packages/babel-plugin-undeclared-variables-check/src/index.js new file mode 100644 index 0000000000..94178baafc --- /dev/null +++ b/packages/babel-plugin-undeclared-variables-check/src/index.js @@ -0,0 +1,48 @@ +import levenshtein from "leven"; + +export default function ({ Plugin, types: t, messages }) { + return new Plugin("undeclared-variables-check", { + metadata: { + group: "builtin-pre" + }, + + visitor: { + ReferencedIdentifier(node, parent, scope) { + var binding = scope.getBinding(node.name); + if (binding && binding.kind === "type" && !this.parentPath.isFlow()) { + throw this.errorWithNode(messages.get("undeclaredVariableType", node.name), ReferenceError); + } + + if (scope.hasBinding(node.name)) return; + + // get the closest declaration to offer as a suggestion + // the variable name may have just been mistyped + + var bindings = scope.getAllBindings(); + + var closest; + var shortest = -1; + + for (var name in bindings) { + var distance = levenshtein(node.name, name); + if (distance <= 0 || distance > 3) continue; + if (distance <= shortest) continue; + + closest = name; + shortest = distance; + } + + var msg; + if (closest) { + msg = messages.get("undeclaredVariableSuggestion", node.name, closest); + } else { + msg = messages.get("undeclaredVariable", node.name); + } + + // + + throw this.errorWithNode(msg, ReferenceError); + } + } + }); +} diff --git a/packages/babel-plugin-undefined-to-void/.npmignore b/packages/babel-plugin-undefined-to-void/.npmignore new file mode 100644 index 0000000000..cace0d6ddc --- /dev/null +++ b/packages/babel-plugin-undefined-to-void/.npmignore @@ -0,0 +1,3 @@ +node_modules +*.log +src diff --git a/packages/babel-plugin-undefined-to-void/README.md b/packages/babel-plugin-undefined-to-void/README.md new file mode 100644 index 0000000000..874189d710 --- /dev/null +++ b/packages/babel-plugin-undefined-to-void/README.md @@ -0,0 +1,53 @@ +# babel-plugin-undefined-to-void + +Some JavaScript implementations allow `undefined` to be overwritten, this +may lead to peculiar bugs that are extremely hard to track down. + +This plugin transforms `undefined` into `void 0` which returns `undefined` +regardless of if it's been reassigned. + +## Example + +**In** + +```javascript +foo === undefined; +``` + +**Out** + +```javascript +foo === void 0; +``` + +## Installation + +```sh +$ npm install babel-plugin-undefined-to-void +``` + +## Usage + +### Via `.babelrc` (Recommended) + +**.babelrc** + +```json +{ + "plugins": ["undefined-to-void"] +} +``` + +### Via CLI + +```sh +$ babel --plugins undefined-to-void script.js +``` + +### Via Node API + +```javascript +require("babel-core").transform("code", { + plugins: ["undefined-to-void"] +}); +``` diff --git a/packages/babel-plugin-undefined-to-void/package.json b/packages/babel-plugin-undefined-to-void/package.json new file mode 100644 index 0000000000..a26e5a108e --- /dev/null +++ b/packages/babel-plugin-undefined-to-void/package.json @@ -0,0 +1,11 @@ +{ + "name": "babel-plugin-undefined-to-void", + "version": "1.1.6", + "description": "Replace references to `undefined` with `void 0`", + "repository": "babel-plugins/babel-plugin-undefined-to-void", + "license": "MIT", + "main": "lib/index.js", + "keywords": [ + "babel-plugin" + ] +} diff --git a/packages/babel-plugin-undefined-to-void/src/index.js b/packages/babel-plugin-undefined-to-void/src/index.js new file mode 100644 index 0000000000..ddbf70be76 --- /dev/null +++ b/packages/babel-plugin-undefined-to-void/src/index.js @@ -0,0 +1,15 @@ +export default function ({ Plugin, types: t }) { + return new Plugin("undefined-to-void", { + metadata: { + group: "builtin-basic" + }, + + visitor: { + ReferencedIdentifier(node, parent) { + if (node.name === "undefined") { + return t.unaryExpression("void", t.literal(0), true); + } + } + } + }); +}