Compare commits

...

58 Commits

Author SHA1 Message Date
Sebastian McKenzie
b825998c63 v5.5.5 2015-06-08 01:27:46 +01:00
Sebastian McKenzie
6b02ca47c3 add missing semicolon 2015-06-08 01:27:02 +01:00
Sebastian McKenzie
ea1b85bffa fix bug where templates were getting polluted with old traversal paths 2015-06-08 01:25:51 +01:00
Sebastian McKenzie
3cffe47eea fix NodePath#isGenericType method name 2015-06-08 01:00:01 +01:00
Sebastian McKenzie
e5d5a9fb27 remove unused variable 2015-06-08 00:33:41 +01:00
Sebastian McKenzie
ca97fa63a9 Merge branch 'master' of github.com:babel/babel 2015-06-08 00:30:05 +01:00
Sebastian McKenzie
f4cc27bc0e remove unused variable 2015-06-08 00:29:52 +01:00
Sebastian McKenzie
8cea575e2e change NodePath#findParent to only call callback with path instead of node 2015-06-08 00:29:46 +01:00
Sebastian McKenzie
c91baee4d5 add support for flow declarations in scope tracking 2015-06-08 00:04:17 +01:00
Sebastian McKenzie
8055ce29f7 add support for flow declarations in scope tracking 2015-06-07 23:57:19 +01:00
Sebastian McKenzie
4596ae48b8 remove acorn jsx tests as the jsx parser is no longer embedded 2015-06-07 23:57:11 +01:00
Sebastian McKenzie
6c268cdf21 split out path comment methods into a separate file 2015-06-07 23:49:29 +01:00
Sebastian McKenzie
fce977f1d7 update TraversalContext#shouldVisit to check for existence of visitor keys 2015-06-07 23:38:39 +01:00
Sebastian McKenzie
a298075949 check for loc value on comments before attempting to adjust it 2015-06-07 23:37:47 +01:00
Sebastian McKenzie
66599c3779 use scope paths hub instead of manually passing the hub to the scope 2015-06-07 23:37:33 +01:00
Sebastian McKenzie
60340244b1 when constructing a NodePath, inherit parent paths hub if one wasn't passed to us 2015-06-07 23:36:32 +01:00
Sebastian McKenzie
eb72ea3e5a rename path verification methods to introspection and add NodePath#getSource method 2015-06-07 23:36:12 +01:00
Sebastian McKenzie
ede6237b6f add NodePath#addComment method 2015-06-07 23:35:46 +01:00
Sebastian McKenzie
e91e10aae6 add FlowStatement and FlowDeclaration alias keys 2015-06-07 23:35:35 +01:00
Sebastian McKenzie
9c3cca0d25 rename NodePath#isTypeAnnotationGeneric to isTypeAnnotation 2015-06-07 23:35:09 +01:00
Sebastian McKenzie
8eee5367f3 add Noop node 2015-06-07 23:34:35 +01:00
Sebastian McKenzie
40d55a3d44 update makefile browser build filename 2015-06-07 20:24:21 +01:00
Sebastian McKenzie
75330304dc fix linting errors 2015-06-07 20:04:30 +01:00
Sebastian McKenzie
776c508418 add node build to Makefile 2015-06-07 19:41:28 +01:00
Sebastian McKenzie
e804741632 add module metadata - closes #1601 2015-06-07 19:41:20 +01:00
Sebastian McKenzie
3d3cb4be4f completely rework type inferrence, support coercing to union types and be more reliable in the inferrence and always be cautious 2015-06-07 19:39:53 +01:00
Sebastian McKenzie
64f4209119 recurse into type casts when trying to get it's expression - fixes #facebook/react-native#1526 2015-06-07 02:45:06 +01:00
Sebastian McKenzie
2ede226ef9 remove unused variables 2015-06-06 16:35:28 +01:00
Sebastian McKenzie
f5cf641c0a add support for async generators to type inferrence 2015-06-06 16:17:55 +01:00
Sebastian McKenzie
1abd3419f6 simplify NodePath.getScope 2015-06-06 16:17:43 +01:00
Sebastian McKenzie
75699db716 clean up options normalisation and add more comments 2015-06-06 16:17:30 +01:00
Sebastian McKenzie
7c3572f08c fix linting errors 2015-06-06 03:38:12 +01:00
Sebastian McKenzie
9dacde6d07 further implement the concept of a "Hub" that all traversal paths get access to, also add in some assertions to confirm path state when performing manipulation 2015-06-06 03:34:08 +01:00
Sebastian McKenzie
8c3aab9a26 add support for async functions to type inferrence 2015-06-06 03:33:32 +01:00
Sebastian McKenzie
ba4550c953 switch some node-parent based stuff to path-based 2015-06-06 03:33:22 +01:00
Sebastian McKenzie
d0ac65a934 add _paths in t.inherits 2015-06-06 03:32:35 +01:00
Sebastian McKenzie
a4c70bb029 this commit makes the following changes to the way paths are handled:
- store paths on parents instead of containers
 - implement one central hub that all traversal paths and scopes get access to in order to abstract out access to common functions
2015-06-06 03:32:22 +01:00
Sebastian McKenzie
795cf0c0b1 add ignore/only tests to ensure #1693 never happens again 2015-06-05 23:11:10 +01:00
Sebastian McKenzie
e64b90e322 5.5.4 2015-06-05 23:07:27 +01:00
Sebastian McKenzie
d69b0973e1 v5.5.4 2015-06-05 23:03:55 +01:00
Sebastian McKenzie
6296f49653 update minification.constantFolding transformer to deopt bindings that are reassigned in a different function scope 2015-06-05 23:01:31 +01:00
Sebastian McKenzie
9f2b739046 improve Scope#dump to print binding info 2015-06-05 23:00:50 +01:00
Sebastian McKenzie
da1d5e5577 simplify unary resolution and move operators to types 2015-06-05 23:00:06 +01:00
Sebastian McKenzie
7333b4e392 move staticPropBody class concat to after className check in es6.classes transformer 2015-06-05 22:44:03 +01:00
Sebastian McKenzie
b0442d0784 add back shouldIgnore check that went missing around 32f19aff99 - closes #1696, fixes #1693 2015-06-05 22:43:32 +01:00
Sebastian McKenzie
295e69f8f8 fix auxiliaryComment option name for istanbul interop - fixes #1695 2015-06-05 22:40:28 +01:00
Sebastian McKenzie
cfe844fa39 add boolean type to experimental option 2015-06-05 22:36:16 +01:00
Sebastian McKenzie
0f4ea2d2a6 use file.log.deprecate instead of throwing an error - fixes #1694 2015-06-05 22:35:46 +01:00
Sebastian McKenzie
4b85b05839 use actual parameter reference for non-last default parameters - fixes #1690 2015-06-05 14:08:18 +01:00
Sebastian McKenzie
2539d08dce 5.5.3 2015-06-05 14:07:34 +01:00
Sebastian McKenzie
c26fd7a819 fix regenerator version 2015-06-05 14:07:27 +01:00
Sebastian McKenzie
2053610429 v5.5.3 2015-06-05 12:20:22 +01:00
Sebastian McKenzie
cd4f83b299 fix linting errors 2015-06-05 12:19:32 +01:00
Sebastian McKenzie
ec29ba19a9 add 5.5.3 changelog 2015-06-05 12:18:43 +01:00
Sebastian McKenzie
9dc03e0978 traverse over ClassProperty path rather than node 2015-06-05 12:17:55 +01:00
Sebastian McKenzie
bc4258eca9 add type inferrence for template literals 2015-06-05 12:17:45 +01:00
Sebastian McKenzie
b0e58f9770 add completion statement test and enable experimental option on deadCodeElimination tests 2015-06-05 12:17:36 +01:00
Sebastian McKenzie
a1e2641c91 5.5.2 2015-06-05 12:17:18 +01:00
63 changed files with 1014 additions and 4026 deletions

View File

@@ -13,6 +13,18 @@ _Note: Gaps between patch versions are faulty/broken releases._
See [CHANGELOG - 6to5](CHANGELOG-6to5.md) for the pre-4.0.0 version changelog.
## 5.5.4
* **Bug Fix**
* Add back missing `shouldIgnore` check.
* Log message on deprecated options rather than throw an error.
* Fix name of `auxiliaryComment` option when attempting Istanbul interop in `babel/register`.
## 5.5.3
* **Bug Fix**
* Fix weird state bug when traversing overa `node` `ClassProperty` instead of `path` in the `es6.classes` transformer.
## 5.5.2
* **Bug Fix**

View File

@@ -5,6 +5,7 @@ UGLIFY_CMD = node_modules/uglify-js/bin/uglifyjs
#UGLIFY_CMD = node_modules/uglify-js/bin/uglifyjs --mangle sort
MOCHA_CMD = node_modules/mocha/bin/_mocha
BABEL_CMD = node_modules/babel/bin/babel
BROWSERIFY_IGNORE = -i esprima-fb
export NODE_ENV = test
@@ -34,8 +35,10 @@ build:
node $(BROWSERIFY_CMD) -e lib/babel/polyfill.js >dist/polyfill.js
node $(UGLIFY_CMD) dist/polyfill.js >dist/polyfill.min.js
node $(BROWSERIFY_CMD) lib/babel/api/browser.js -s babel >dist/babel.js
node $(UGLIFY_CMD) dist/babel.js >dist/babel.min.js
node $(BROWSERIFY_CMD) lib/babel/api/browser.js -s babel $(BROWSERIFY_IGNORE) >dist/browser.js
node $(UGLIFY_CMD) dist/browser.js >dist/browser.min.js
node $(BROWSERIFY_CMD) lib/babel/api/node.js --node $(BROWSERIFY_IGNORE) >dist/node.js
node packages/babel-cli/bin/babel-external-helpers >dist/external-helpers.js
node $(UGLIFY_CMD) dist/external-helpers.js >dist/external-helpers.min.js
@@ -86,8 +89,8 @@ publish: lint
make build
cp dist/babel.js browser.js
cp dist/babel.min.js browser.min.js
cp dist/browser.js browser.js
cp dist/browser.min.js browser.min.js
cp dist/polyfill.js browser-polyfill.js
cp dist/polyfill.min.js browser-polyfill.min.js

View File

@@ -1,7 +1,7 @@
{
"name": "babel-core",
"description": "A compiler for writing next generation JavaScript",
"version": "5.5.2",
"version": "5.5.5",
"author": "Sebastian McKenzie <sebmck@gmail.com>",
"homepage": "https://babeljs.io/",
"license": "MIT",
@@ -51,7 +51,7 @@
"output-file-sync": "^1.1.0",
"path-is-absolute": "^1.0.0",
"private": "^0.1.6",
"regenerator": "^0.8.28",
"regenerator": "0.8.28",
"regexpu": "^1.1.2",
"repeating": "^1.1.2",
"resolve": "^1.1.6",

View File

@@ -1,14 +1,14 @@
{
"name": "babel",
"description": "Turn ES6 code into readable vanilla ES5 with source maps",
"version": "5.5.1",
"version": "5.5.4",
"author": "Sebastian McKenzie <sebmck@gmail.com>",
"homepage": "https://babeljs.io/",
"license": "MIT",
"repository": "babel/babel",
"preferGlobal": true,
"dependencies": {
"babel-core": "^5.5.1",
"babel-core": "^5.5.4",
"chokidar": "^1.0.0",
"commander": "^2.6.0",
"convert-source-map": "^1.1.0",

View File

@@ -1,7 +1,7 @@
{
"name": "babel-runtime",
"description": "babel selfContained runtime",
"version": "5.5.1",
"version": "5.5.4",
"license": "MIT",
"repository": "babel/babel",
"author": "Sebastian McKenzie <sebmck@gmail.com>",

View File

@@ -105,7 +105,7 @@ if (process.env.running_under_istanbul) {
if (istanbulMonkey[filename]) {
delete istanbulMonkey[filename];
var code = compile(filename, {
attachAuxiliaryComment: "istanbul ignore next"
auxiliaryComment: "istanbul ignore next"
});
istanbulMonkey[filename] = true;
return code;

View File

@@ -17,3 +17,7 @@ export function BlockStatement(node, print) {
this.rightBrace();
}
}
export function Noop() {
}

View File

@@ -344,7 +344,7 @@ class CodeGenerator {
//
if (comment.type === "CommentBlock" && this.format.indent.adjustMultilineComment) {
var offset = comment.loc.start.column;
var offset = comment.loc && comment.loc.start.column;
if (offset) {
var newlineRegex = new RegExp("\\n\\s{1," + offset + "}", "g");
val = val.replace(newlineRegex, "\n");

View File

@@ -7,8 +7,6 @@ export const MESSAGES = {
classesIllegalSuperCall: "Direct super call is illegal in non-constructor, use super.$1() instead",
classesIllegalConstructorKind: "Illegal kind for constructor method",
scopeDuplicateDeclaration: "Duplicate declaration $1",
undeclaredVariable: "Reference to undeclared variable $1",
undeclaredVariableSuggestion: "Reference to undeclared variable $1 - did you mean $2?",
settersInvalidParamLength: "Setters must have exactly one parameter",
settersNoRest: "Setters aren't allowed to have a rest",
noAssignmentsInForHead: "No assignments allowed in for-in/of head",
@@ -24,6 +22,10 @@ export const MESSAGES = {
illegalMethodName: "Illegal method name $1",
lostTrackNodePath: "We lost track of this nodes position, likely because the AST was directly manipulated",
undeclaredVariable: "Reference to undeclared variable $1",
undeclaredVariableType: "Referencing a type alias outside of a type annotation",
undeclaredVariableSuggestion: "Reference to undeclared variable $1 - did you mean $2?",
traverseNeedsParent: "Must pass a scope and parentPath unless traversing a Program/File got a $1 node",
traverseVerifyRootFunction: "You passed `traverse()` a function when it expected a visitor object, are you sure you didn't mean `{ enter: Function }`?",
traverseVerifyVisitorProperty: "You passed `traverse()` a visitor object with the property $1 that has the invalid property $2",

View File

@@ -17,6 +17,8 @@ var or = types.Type.or;
// .build("program")
// .field("program", def("Program"));
def("Noop");
def("AssignmentPattern")
.bases("Pattern")
.build("left", "right")

View File

@@ -14,6 +14,7 @@ import codeFrame from "../../helpers/code-frame";
import defaults from "lodash/object/defaults";
import includes from "lodash/collection/includes";
import traverse from "../../traversal";
import Hub from "../../traversal/hub";
import assign from "lodash/object/assign";
import Logger from "./logger";
import parse from "../../helpers/parse";
@@ -35,15 +36,27 @@ export default class File {
this.declarations = {};
this.usedHelpers = {};
this.dynamicData = {};
this.metadata = {};
this.data = {};
this.metadata = {
modules: {
imports: [],
exports: {
exported: [],
specifiers: []
}
}
};
this.pipeline = pipeline;
this.log = new Logger(this, opts.filename || "unknown");
this.opts = this.normalizeOptions(opts);
this.ast = {};
this.normalizeOptions(opts);
this.buildTransformers();
this.hub = new Hub(this);
}
static helpers = [
@@ -88,16 +101,16 @@ export default class File {
static options = require("./options");
normalizeOptions(opts: Object) {
opts = assign({}, opts);
opts = this.opts = assign({}, opts);
// resolve babelrc
if (opts.filename) {
var rcFilename = opts.filename;
if (!isAbsolute(rcFilename)) rcFilename = path.join(process.cwd(), rcFilename);
opts = resolveRc(rcFilename, opts);
}
//
// check for unknown options
for (let key in opts) {
if (key[0] === "_") continue;
@@ -105,9 +118,11 @@ export default class File {
if (!option) this.log.error(`Unknown option: ${key}`, ReferenceError);
}
// merge in environment options
var envKey = process.env.BABEL_ENV || process.env.NODE_ENV || "development";
if (opts.env) merge(opts, opts.env[envKey]);
// normalise options
for (let key in File.options) {
let option = File.options[key];
@@ -115,7 +130,7 @@ export default class File {
if (!val && option.optional) continue;
if (val && option.deprecated) {
throw new Error("Deprecated option " + key + ": " + option.deprecated);
this.log.deprecate("Deprecated option " + key + ": " + option.deprecated);
}
if (val == null) {
@@ -466,12 +481,13 @@ export default class File {
}
_addAst(ast) {
this.path = NodePath.get({
this.path = NodePath.get({
hub: this.hub,
parentPath: null,
parent: ast,
container: ast,
key: "program"
}).setContext(null, this);
}).setContext();
this.scope = this.path.scope;
this.ast = ast;
}
@@ -486,15 +502,9 @@ export default class File {
if (modFormatter.init && this.transformers["es6.modules"].canTransform()) {
modFormatter.init();
}
this.populateModuleMetadata();
this.log.debug("End module formatter init");
}
populateModuleMetadata() {
var modules = {};
this.metadata.modules = modules;
}
transform() {
this.call("pre");
for (var pass of (this.transformerStack: Array)) {
@@ -509,7 +519,11 @@ export default class File {
code = code + "";
try {
return callback();
if (this.shouldIgnore()) {
return this.makeResult({ code, ignored: true });
} else {
return callback();
}
} catch (err) {
if (err._babel) {
throw err;

View File

@@ -47,6 +47,7 @@
},
"experimental": {
"type": "boolean",
"description": "allow use of experimental transformers",
"default": false
},

View File

@@ -3,7 +3,10 @@ import * as t from "../../types";
export default function (node) {
var lastNonDefault = 0;
for (var i = 0; i < node.params.length; i++) {
if (!t.isAssignmentPattern(node.params[i])) lastNonDefault = i + 1;
var param = node.params[i];
if (!t.isAssignmentPattern(param) && !t.isRestElement(param)) {
lastNonDefault = i + 1;
}
}
return lastNonDefault;
}

View File

@@ -25,11 +25,13 @@ var referenceVisitor = {
}
};
export default function (node, callId, scope) {
export default function (path, callId) {
var node = path.node;
node.async = false;
node.generator = true;
scope.traverse(node, awaitVisitor, state);
path.traverse(awaitVisitor, state);
var call = t.callExpression(callId, [node]);
@@ -44,11 +46,11 @@ export default function (node, callId, scope) {
return declar;
} else {
if (id) {
var state = { id: id };
scope.traverse(node, referenceVisitor, state);
var state = { id };
path.traverse(referenceVisitor, state);
if (state.ref) {
scope.parent.push({ id: state.ref });
path.scope.parent.push({ id: state.ref });
return t.assignmentExpression("=", state.ref, call);
}
}

View File

@@ -77,31 +77,134 @@ var metadataVisitor = {
ImportDeclaration(node, parent, scope, formatter) {
formatter.hasLocalImports = true;
extend(formatter.localImports, this.getBindingIdentifiers());
var specifiers = [];
var imported = [];
formatter.metadata.imports.push({
source: node.source.value,
imported,
specifiers
});
for (var specifier of (this.get("specifiers"): Array)) {
var ids = specifier.getBindingIdentifiers();
extend(formatter.localImports, ids);
var local = specifier.node.local.name;
if (specifier.isImportDefaultSpecifier()) {
imported.push("default");
specifiers.push({
kind: "named",
imported: "default",
local
});
}
if (specifier.isImportSpecifier()) {
var importedName = specifier.node.imported.name;
imported.push(importedName);
specifiers.push({
kind: "named",
imported: importedName,
local
});
}
if (specifier.isImportNamespaceSpecifier()) {
imported.push("*");
specifiers.push({
kind: "namespace",
local
});
}
}
},
ExportDeclaration(node, parent, scope, formatter) {
formatter.hasLocalExports = true;
var source = node.source ? node.source.value : null;
var exports = formatter.metadata.exports;
// export function foo() {}
// export var foo = "bar";
var declar = this.get("declaration");
if (declar.isStatement()) {
var bindings = declar.getBindingIdentifiers();
for (var name in bindings) {
var binding = bindings[name];
formatter._addExport(name, binding);
exports.exported.push(name);
exports.specifiers.push({
kind: "local",
local: name,
exported: this.isExportDefaultDeclaration() ? "default" : name
});
}
}
if (this.isExportNamedDeclaration() && node.specifiers) {
for (var i = 0; i < node.specifiers.length; i++) {
var specifier = node.specifiers[i];
for (var specifier of (node.specifiers: Array)) {
var exported = specifier.exported.name;
exports.exported.push(exported);
// export foo from "bar";
if (t.isExportDefaultSpecifier(specifier)) {
exports.specifiers.push({
kind: "external",
local: exported,
exported,
source
});
}
// export * as foo from "bar";
if (t.isExportNamespaceSpecifier(specifier)) {
exports.specifiers.push({
kind: "external-namespace",
exported,
source
});
}
var local = specifier.local;
if (!local) continue;
formatter._addExport(local.name, specifier.exported);
// export { foo } from "bar";
// export { foo as bar } from "bar";
if (source) {
exports.specifiers.push({
kind: "external",
local: local.name,
exported,
source
});
}
// export { foo };
// export { foo as bar };
if (!source) {
exports.specifiers.push({
kind: "local",
local: local.name,
exported
});
}
}
}
// export * from "bar";
if (this.isExportAllDeclaration()) {
exports.specifiers.push({
kind: "external-all",
source
});
}
if (!t.isExportDefaultDeclaration(node)) {
var onlyDefault = node.specifiers && node.specifiers.length === 1 && t.isSpecifierDefault(node.specifiers[0]);
if (!onlyDefault) {
@@ -131,6 +234,7 @@ export default class DefaultFormatter {
this.localExports = object();
this.localImports = object();
this.metadata = file.metadata.modules;
this.getMetadata();
}

View File

@@ -0,0 +1 @@
if (VARIABLE_NAME === undefined) VARIABLE_NAME = DEFAULT_VALUE;

View File

@@ -200,6 +200,8 @@ class ClassTransformer {
}
}
body = body.concat(this.staticPropBody);
if (this.className) {
// named class with only a constructor
if (body.length === 1) return t.toExpression(body[0]);
@@ -214,8 +216,6 @@ class ClassTransformer {
t.inheritsComments(body[0], this.node);
}
body = body.concat(this.staticPropBody);
//
body.push(t.returnStatement(classRef));
@@ -293,7 +293,7 @@ class ClassTransformer {
this.pushMethod(node, path);
}
} else if (t.isClassProperty(node)) {
this.pushProperty(node);
this.pushProperty(node, path);
}
}
@@ -478,8 +478,8 @@ class ClassTransformer {
* Description
*/
pushProperty(node: { type: "ClassProperty" }) {
this.scope.traverse(node, collectPropertyReferencesVisitor, {
pushProperty(node: { type: "ClassProperty" }, path: NodePath) {
path.traverse(collectPropertyReferencesVisitor, {
references: this.instancePropRefs,
scope: this.scope
});

View File

@@ -56,15 +56,22 @@ export function ForOfStatement(node, parent, scope, file) {
export { ForOfStatement as ForInStatement };
export function Func/*tion*/(node, parent, scope, file) {
var hasDestructuring = false;
for (let pattern of (node.params: Array)) {
if (t.isPattern(pattern)) {
hasDestructuring = true;
break;
}
}
if (!hasDestructuring) return;
var nodes = [];
var hasDestructuring = false;
for (var i = 0; i < node.params.length; i++) {
let pattern = node.params[i];
if (!t.isPattern(pattern)) continue;
node.params = node.params.map(function (pattern, i) {
if (!t.isPattern(pattern)) return pattern;
hasDestructuring = true;
var ref = scope.generateUidIdentifier("ref");
var ref = node.params[i] = scope.generateUidIdentifier("ref");
t.inherits(ref, pattern);
var destructuring = new DestructuringTransformer({
@@ -74,12 +81,9 @@ export function Func/*tion*/(node, parent, scope, file) {
file: file,
kind: "let"
});
destructuring.init(pattern, ref);
return ref;
});
if (!hasDestructuring) return;
}
t.ensureBlock(node);
@@ -216,8 +220,8 @@ function hasRest(pattern) {
}
var arrayUnpackVisitor = {
enter(node, parent, scope, state) {
if (this.isReferencedIdentifier() && state.bindings[node.name]) {
ReferencedIdentifier(node, parent, scope, state) {
if (state.bindings[node.name]) {
state.deopt = true;
this.stop();
}

View File

@@ -70,6 +70,10 @@ export function _ForOfStatementArray(node, scope, file) {
loop.body.body.unshift(t.expressionStatement(t.assignmentExpression("=", left, iterationValue)));
}
if (this.parentPath.isLabeledStatement()) {
loop = t.labeledStatement(this.parentPath.node.label, loop);
}
nodes.push(loop);
return nodes;

View File

@@ -1,4 +1,5 @@
import callDelegate from "../../helpers/call-delegate";
import getFunctionArity from "../../helpers/get-function-arity";
import * as util from "../../../util";
import * as t from "../../../types";
@@ -24,37 +25,54 @@ var iifeVisitor = {
export function Func/*tion*/(node, parent, scope, file) {
if (!hasDefaults(node)) return;
// ensure it's a block, useful for arrow functions
t.ensureBlock(node);
var state = {
iife: false,
scope: scope
};
var body = [];
//
var argsIdentifier = t.identifier("arguments");
argsIdentifier._shadowedFunctionLiteral = true;
var lastNonDefaultParam = 0;
var state = { iife: false, scope: scope };
var pushDefNode = function (left, right, i) {
var defNode = util.template("default-parameter", {
VARIABLE_NAME: left,
DEFAULT_VALUE: right,
ARGUMENT_KEY: t.literal(i),
ARGUMENTS: argsIdentifier
}, true);
// push a default parameter definition
function pushDefNode(left, right, i) {
var defNode;
if (exceedsLastNonDefault(i) || t.isPattern(left) || file.transformers["es6.spec.blockScoping"].canTransform()) {
defNode = util.template("default-parameter", {
VARIABLE_NAME: left,
DEFAULT_VALUE: right,
ARGUMENT_KEY: t.literal(i),
ARGUMENTS: argsIdentifier
}, true);
} else {
defNode = util.template("default-parameter-assign", {
VARIABLE_NAME: left,
DEFAULT_VALUE: right
}, true);
}
defNode._blockHoist = node.params.length - i;
body.push(defNode);
};
}
// check if an index exceeds the functions arity
function exceedsLastNonDefault(i) {
return i + 1 > lastNonDefaultParam;
}
//
var lastNonDefaultParam = getFunctionArity(node);
//
var params = this.get("params");
for (var i = 0; i < params.length; i++) {
var param = params[i];
if (!param.isAssignmentPattern()) {
if (!param.isRestElement()) {
lastNonDefaultParam = i + 1;
}
if (!param.isIdentifier()) {
param.traverse(iifeVisitor, state);
}
@@ -69,9 +87,13 @@ export function Func/*tion*/(node, parent, scope, file) {
var left = param.get("left");
var right = param.get("right");
var placeholder = scope.generateUidIdentifier("x");
placeholder._isDefaultPlaceholder = true;
node.params[i] = placeholder;
if (exceedsLastNonDefault(i) || left.isPattern()) {
var placeholder = scope.generateUidIdentifier("x");
placeholder._isDefaultPlaceholder = true;
node.params[i] = placeholder;
} else {
node.params[i] = left.node;
}
if (!state.iife) {
if (right.isIdentifier() && scope.hasOwnBinding(right.node.name)) {

View File

@@ -1,14 +1,15 @@
import isNumber from "lodash/lang/isNumber";
import * as util from "../../../util";
import * as t from "../../../types";
var memberExpressionOptimisationVisitor = {
enter(node, parent, scope, state) {
Scope(node, parent, scope, state) {
// check if this scope has a local binding that will shadow the rest parameter
if (this.isScope() && !scope.bindingIdentifierEquals(state.name, state.outerBinding)) {
return this.skip();
if (!scope.bindingIdentifierEquals(state.name, state.outerBinding)) {
this.skip();
}
},
enter(node, parent, scope, state) {
var stop = () => {
state.canOptimise = false;
this.stop();
@@ -31,8 +32,8 @@ var memberExpressionOptimisationVisitor = {
if (!state.noOptimise && t.isMemberExpression(parent) && parent.computed) {
// if we know that this member expression is referencing a number then we can safely
// optimise it
var prop = parent.property;
if (isNumber(prop.value) || t.isUnaryExpression(prop) || t.isBinaryExpression(prop)) {
var prop = this.parentPath.get("property");
if (prop.isGenericType("Number")) {
state.candidates.push(this);
return;
}
@@ -43,6 +44,8 @@ var memberExpressionOptimisationVisitor = {
};
function optimizeMemberExpression(parent, offset) {
if (offset === 0) return;
var newExpr;
var prop = parent.property;

View File

@@ -1,7 +1,7 @@
import * as t from "../../../types";
function getSpreadLiteral(spread, scope) {
if (scope.file.isLoose("es6.spread")) {
if (scope.hub.file.isLoose("es6.spread")) {
return spread.argument;
} else {
return scope.toArray(spread.argument, true);

View File

@@ -16,7 +16,7 @@ function crawl(path) {
if (path.is("_templateLiteralProduced")) {
crawl(path.get("left"));
crawl(path.get("right"));
} else if (!path.isTypeAnnotationGeneric("String") && !path.isTypeAnnotationGeneric("Number")) {
} else if (!path.isGenericType("String") && !path.isGenericType("Number")) {
path.replaceWith(t.callExpression(t.identifier("String"), [path.node]));
}
}

View File

@@ -83,7 +83,7 @@ export function ExportNamedDeclaration(node, parent, scope) {
export var Program = {
enter(node) {
var imports = [];
var rest = [];
var rest = [];
for (var i = 0; i < node.body.length; i++) {
var bodyNode = node.body[i];

View File

@@ -8,7 +8,7 @@ function remap(path, key, create) {
// ensure that we're shadowed
if (!path.inShadow()) return;
var fnPath = path.findParent((node, path) => !node.shadow && (path.isFunction() || path.isProgram()));
var fnPath = path.findParent((path) => !path.is("shadow") && (path.isFunction() || path.isProgram()));
var cached = fnPath.getData(key);
if (cached) return cached;

View File

@@ -11,7 +11,7 @@ export function AssignmentExpression() {
if (!left.isIdentifier()) return;
var binding = this.scope.getBinding(left.node.name);
if (!binding || binding.deoptValue) return;
if (!binding || binding.hasDeoptValue) return;
var evaluated = this.get("right").evaluate();
if (evaluated.confident) {
@@ -23,7 +23,10 @@ export function AssignmentExpression() {
export function IfStatement() {
var evaluated = this.get("test").evaluate();
if (!evaluated.confident) return this.skip();
if (!evaluated.confident) {
// todo: deopt binding values for constant violations inside
return this.skip();
}
if (evaluated.value) {
this.skipKey("alternate");
@@ -33,6 +36,25 @@ export function IfStatement() {
}
export var 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];

View File

@@ -44,7 +44,7 @@ export function ReferencedIdentifier(node, parent, scope) {
if (binding.path.scope.parent !== scope) return;
}
if (this.findParent((node) => node === replacement)) {
if (this.findParent((path) => path.node === replacement)) {
return;
}

View File

@@ -5,7 +5,7 @@ export var metadata = {
};
export function ForOfStatement(node, parent, scope, file) {
if (this.get("right").isTypeAnnotationGeneric("Array")) {
if (this.get("right").isGenericType("Array")) {
return _ForOfStatementArray.call(this, node, scope, file);
}
}

View File

@@ -10,5 +10,5 @@ export var metadata = {
export function Func/*tion*/(node, parent, scope, file) {
if (!node.async || node.generator) return;
return remapAsyncToGenerator(node, file.addHelper("async-to-generator"), scope);
return remapAsyncToGenerator(this, file.addHelper("async-to-generator"));
}

View File

@@ -14,8 +14,7 @@ export function Func/*tion*/(node, parent, scope, file) {
if (!node.async || node.generator) return;
return remapAsyncToGenerator(
node,
t.memberExpression(file.addImport("bluebird", null, "absolute"), t.identifier("coroutine")),
scope
this,
t.memberExpression(file.addImport("bluebird", null, "absolute"), t.identifier("coroutine"))
);
}

View File

@@ -1,3 +1,5 @@
import * as t from "../../../types";
export var metadata = {
group: "builtin-trailing"
};
@@ -23,7 +25,10 @@ export function Func/*tion*/(node) {
}
export function TypeCastExpression(node) {
return node.expression;
do {
node = node.expression;
} while(t.isTypeCastExpression(node));
return node;
}
export function ImportDeclaration(node) {

View File

@@ -26,7 +26,7 @@ export var Program = {
};
export function ThisExpression() {
if (!this.findParent((node) => !node.shadow && THIS_BREAK_KEYS.indexOf(node.type) >= 0)) {
if (!this.findParent((path) => !path.is("shadow") && THIS_BREAK_KEYS.indexOf(path.type) >= 0)) {
return t.identifier("undefined");
}
}

View File

@@ -6,6 +6,11 @@ export var metadata = {
};
export function ReferencedIdentifier(node, parent, scope, file) {
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
@@ -34,5 +39,5 @@ export function ReferencedIdentifier(node, parent, scope, file) {
//
throw file.errorWithNode(node, msg, ReferenceError);
throw this.errorWithNode(msg, ReferenceError);
}

View File

@@ -10,8 +10,19 @@ export default class TraversalContext {
}
shouldVisit(node) {
var opts = this.opts;
if (opts.enter || opts.exit) return true;
if (opts[node.type]) return true;
var keys = t.VISITOR_KEYS[node.type];
return !!(this.opts.enter || this.opts.exit || this.opts[node.type] || (keys && keys.length));
if (!keys || !keys.length) return false;
for (var key of (keys: Array)) {
if (node[key]) return true;
}
return false;
}
create(node, obj, key, containerKey) {

View File

@@ -0,0 +1,5 @@
export default class Hub {
constructor(file) {
this.file = file;
}
}

View File

@@ -49,28 +49,21 @@ const CLEAR_KEYS = [
"tokens", "range", "start", "end", "loc", "raw"
];
function clearNode(node) {
traverse.clearNode = function (node) {
for (var i = 0; i < CLEAR_KEYS.length; i++) {
let key = CLEAR_KEYS[i];
if (node[key] != null) node[key] = null;
}
for (let key in node) {
var val = node[key];
if (Array.isArray(val)) {
delete val._paths;
}
}
}
};
var clearVisitor = {
noScope: true,
exit: clearNode
exit: traverse.clearNode
};
traverse.removeProperties = function (tree) {
traverse(tree, clearVisitor);
clearNode(tree);
traverse.clearNode(tree);
return tree;
};

View File

@@ -7,4 +7,5 @@
- `replacement` - Methods responsible for replacing a node with another.
- `removal` - Methods responsible for removing a node.
- `family` - Methods responsible for dealing with/retrieving children or siblings.
- `verification` - Methodsresponsible for introspecting the current path for certain values.
- `introspection` - Methods responsible for introspecting the current path for certain values.
- `comments` - Methods responsible for dealing with comments.

View File

@@ -5,7 +5,7 @@
export function findParent(callback) {
var path = this;
while (path) {
if (callback(path.node, path)) return path;
if (callback(path)) return path;
path = path.parentPath;
}
return null;

View File

@@ -0,0 +1,51 @@
/**
* Share comments amongst siblings.
*/
export function shareCommentsWithSiblings() {
var node = this.node;
if (!node) return;
var trailing = node.trailingComments;
var leading = node.leadingComments;
if (!trailing && !leading) return;
var prev = this.getSibling(this.key - 1);
var next = this.getSibling(this.key + 1);
if (!prev.node) prev = next;
if (!next.node) next = prev;
prev.addComments("trailing", leading);
next.addComments("leading", trailing);
}
/**
* Description
*/
export function addComment(type, content, line?) {
this.addComments(type, [{
type: line ? "CommentLine" : "CommentBlock",
value: content
}]);
}
/**
* Give node `comments` of the specified `type`.
*/
export function addComments(type: string, comments: Array) {
if (!comments) return;
var node = this.node;
if (!node) return;
var key = `${type}Comments`;
if (node[key]) {
node[key] = node[key].concat(comments);
} else {
node[key] = comments;
}
}

View File

@@ -1,5 +1,3 @@
import * as messages from "../../messages";
import NodePath from "./index";
import traverse from "../index";
/**
@@ -111,11 +109,11 @@ export function stop() {
* Description
*/
export function setScope(file?) {
export function setScope() {
if (this.opts && this.opts.noScope) return;
var target = this.context || this.parentPath;
this.scope = NodePath.getScope(this, target && target.scope, file);
this.scope = this.getScope(target && target.scope);
if (this.scope) this.scope.init();
}
@@ -123,7 +121,7 @@ export function setScope(file?) {
* Description
*/
export function setContext(context, file) {
export function setContext(context) {
this.shouldSkip = false;
this.shouldStop = false;
this.removed = false;
@@ -135,10 +133,7 @@ export function setContext(context, file) {
this.opts = context.opts;
}
var log = file && this.type === "Program";
if (log) file.log.debug("Start scope building");
this.setScope(file);
if (log) file.log.debug("End scope building");
this.setScope();
return this;
}
@@ -152,11 +147,21 @@ export function setContext(context, file) {
export function resync() {
if (this.removed) return;
this._resyncParent();
this._resyncContainer();
this._resyncKey();
//this._resyncRemoved();
}
export function _resyncParent() {
if (this.parentPath) {
this.parent = this.parentPath.node;
}
}
export function _resyncKey() {
if (!this.container) return;
if (this.node === this.container[this.key]) return;
// grrr, path key is out of sync. this is likely due to a modification to the AST
@@ -176,7 +181,7 @@ export function _resyncKey() {
}
}
throw new Error(messages.get("lostTrackNodePath"));
this.key = null;
}
export function _resyncContainer() {
@@ -185,11 +190,21 @@ export function _resyncContainer() {
if (!containerKey || !parentPath) return;
var newContainer = parentPath.node[containerKey];
if (!newContainer || this.container === newContainer) return;
if (this.container === newContainer) return;
// container is out of sync. this is likely the result of it being reassigned
this.container = newContainer;
if (newContainer) {
this.container = newContainer;
} else {
this.container = null;
}
}
export function _resyncRemoved() {
if (this.key == null || !this.container || this.container[this.key] !== this.node) {
this._markRemoved();
}
}
/**
@@ -214,7 +229,10 @@ export function unshiftContext(context) {
* Description
*/
export function setup(parentPath, key) {
export function setup(parentPath, container, containerKey, key) {
this.containerKey = containerKey;
this.container = container;
this.parentPath = parentPath || this.parentPath;
this.setKey(key);
}

View File

@@ -102,15 +102,15 @@ export function evaluate(): { confident: boolean; value: any } {
if (path.isReferencedIdentifier()) {
var binding = path.scope.getBinding(node.name);
if (binding && binding.hasValue) return binding.value;
}
if ((path.isIdentifier() || path.isMemberExpression()) && path.isReferenced()) {
var resolved = path.resolve();
if (resolved === path) {
return confident = false;
if (binding && binding.hasValue) {
return binding.value;
} else {
return evaluate(resolved);
var resolved = path.resolve();
if (resolved === path) {
return confident = false;
} else {
return evaluate(resolved);
}
}
}

View File

@@ -1,4 +1,3 @@
import type File from "../../transformation/file";
import * as virtualTypes from "./lib/virtual-types";
import traverse from "../index";
import assign from "lodash/object/assign";
@@ -6,21 +5,24 @@ import Scope from "../scope";
import * as t from "../../types";
export default class NodePath {
constructor(parent, container, containerKey) {
this.containerKey = containerKey;
this.container = container;
this.contexts = [];
this.parent = parent;
this.data = {};
constructor(hub, parent) {
this.contexts = [];
this.parent = parent;
this.data = {};
this.hub = hub;
}
/**
* Description
*/
static get({ parentPath, parent, container, containerKey, key }) {
static get({ hub, parentPath, parent, container, containerKey, key }) {
if (!hub && parentPath) {
hub = parentPath.hub;
}
var targetNode = container[key];
var paths = container._paths = container._paths || [];
var paths = parent._paths = parent._paths || [];
var path;
for (var i = 0; i < paths.length; i++) {
@@ -32,11 +34,11 @@ export default class NodePath {
}
if (!path) {
path = new NodePath(parent, container, containerKey);
path = new NodePath(hub, parent);
paths.push(path);
}
path.setup(parentPath, key);
path.setup(parentPath, container, containerKey, key);
return path;
}
@@ -45,12 +47,12 @@ export default class NodePath {
* Description
*/
static getScope(path: NodePath, scope: Scope, file?: File) {
getScope(scope: Scope) {
var ourScope = scope;
// we're entering a new scope so let's construct it!
if (path.isScope()) {
ourScope = new Scope(path, scope, file);
if (this.isScope()) {
ourScope = new Scope(this, scope);
}
return ourScope;
@@ -99,11 +101,12 @@ assign(NodePath.prototype, require("./resolution"));
assign(NodePath.prototype, require("./replacement"));
assign(NodePath.prototype, require("./evaluation"));
assign(NodePath.prototype, require("./conversion"));
assign(NodePath.prototype, require("./verification"));
assign(NodePath.prototype, require("./introspection"));
assign(NodePath.prototype, require("./context"));
assign(NodePath.prototype, require("./removal"));
assign(NodePath.prototype, require("./modification"));
assign(NodePath.prototype, require("./family"));
assign(NodePath.prototype, require("./comments"));
for (let type in virtualTypes) {
if (type[0] === "_") continue;

View File

@@ -151,7 +151,7 @@ export function isCompletionRecord(allowInsideFunction?) {
*/
export function isStatementOrBlock() {
if (t.isLabeledStatement(this.parent) || t.isBlockStatement(this.container)) {
if (this.parentPath.isLabeledStatement() || t.isBlockStatement(this.container)) {
return false;
} else {
return includes(t.STATEMENT_OR_BLOCK_KEYS, this.key);
@@ -210,3 +210,16 @@ export function referencesImport(moduleSource, importName) {
return false;
}
/**
* Description
*/
export function getSource() {
var node = this.node;
if (node.end) {
return this.hub.file.code.slice(node.start, node.end);
} else {
return "";
}
}

View File

@@ -18,6 +18,17 @@ export var ReferencedIdentifier = {
}
};
export var Expression = {
types: ["Expression"],
checkPath(path) {
if (path.isIdentifier()) {
return path.isReferencedIdentifier();
} else {
return t.isExpression(path.node);
}
}
};
export var Scope = {
types: ["Scopable"],
checkPath(path) {

View File

@@ -7,6 +7,8 @@ import * as t from "../../types";
*/
export function insertBefore(nodes) {
this._assertUnremoved();
nodes = this._verifyNodeList(nodes);
if (this.parentPath.isExpressionStatement() || this.parentPath.isLabeledStatement()) {
@@ -27,6 +29,7 @@ export function insertBefore(nodes) {
} else {
throw new Error("No clue what to do with this node type.");
}
return [this];
}
@@ -78,6 +81,8 @@ export function _maybePopFromStatements(nodes) {
*/
export function insertAfter(nodes) {
this._assertUnremoved();
nodes = this._verifyNodeList(nodes);
if (this.parentPath.isExpressionStatement() || this.parentPath.isLabeledStatement()) {
@@ -102,6 +107,7 @@ export function insertAfter(nodes) {
} else {
throw new Error("No clue what to do with this node type.");
}
return [this];
}
@@ -110,7 +116,7 @@ export function insertAfter(nodes) {
*/
export function updateSiblingKeys(fromIndex, incrementBy) {
var paths = this.container._paths;
var paths = this.parent._paths;
for (var i = 0; i < paths.length; i++) {
let path = paths[i];
if (path.key >= fromIndex) {
@@ -153,6 +159,8 @@ export function _verifyNodeList(nodes) {
*/
export function unshiftContainer(containerKey, nodes) {
this._assertUnremoved();
nodes = this._verifyNodeList(nodes);
// get the first path and insert our nodes before it, if it doesn't exist then it
@@ -175,6 +183,8 @@ export function unshiftContainer(containerKey, nodes) {
*/
export function pushContainer(containerKey, nodes) {
this._assertUnremoved();
nodes = this._verifyNodeList(nodes);
// get an invisible path that represents the last node + 1 and replace it with our

View File

@@ -15,6 +15,8 @@ export function remove() {
*/
export function dangerouslyRemove() {
this._assertUnremoved();
this.resync();
if (this._callRemovalHooks("pre")) {
@@ -45,47 +47,13 @@ export function _remove() {
}
export function _markRemoved() {
this.node = null;
this.removed = true;
this.shouldSkip = true;
this.removed = true;
this.node = null;
}
/**
* Share comments amongst siblings.
*/
export function shareCommentsWithSiblings() {
var node = this.node;
if (!node) return;
var trailing = node.trailingComments;
var leading = node.leadingComments;
if (!trailing && !leading) return;
var prev = this.getSibling(this.key - 1);
var next = this.getSibling(this.key + 1);
if (!prev.node) prev = next;
if (!next.node) next = prev;
prev.giveComments("trailing", leading);
next.giveComments("leading", trailing);
}
/**
* Give node `comments` of the specified `type`.
*/
export function giveComments(type: string, comments: Array) {
if (!comments) return;
var node = this.node;
if (!node) return;
var key = `${type}Comments`;
if (node[key]) {
node[key] = node[key].concat(comments);
} else {
node[key] = comments;
export function _assertUnremoved() {
if (this.removed) {
throw this.errorWithNode("NodePath has been removed so is read-only.");
}
}

View File

@@ -158,7 +158,7 @@ export function replaceExpressionWithStatements(nodes: Array) {
for (var i = 0; i < last.length; i++) {
var lastNode = last[i];
if (lastNode.isExpressionStatement()) {
var loop = lastNode.findParent((node, path) => path.isLoop());
var loop = lastNode.findParent((path) => path.isLoop());
if (loop) {
var uid = this.get("callee").scope.generateDeclaredUidIdentifier("ret");
this.get("callee.body").pushContainer("body", t.returnStatement(uid));

View File

@@ -1,61 +1,15 @@
import type NodePath from "./index";
import * as t from "../../types";
const BOOLEAN_BINARY_OPERATORS = ["==", "===", "!=", "!==", ">", "<", ">=", "<=", "in", "instanceof"];
const NUMBER_BINARY_OPERATORS = ["-", "/", "*", "**", "&", "|", ">>", ">>>", "<<", "^"];
const BOOLEAN_UNARY_OPERATORS = ["delete"];
const NUMBER_UNARY_OPERATORS = ["+", "-", "++", "--", "~"];
const STRING_UNARY_OPERATORS = ["typeof"];
/**
* Description
* Resolve a "pointer" `NodePath` to it's absolute path.
*/
export function getTypeAnnotation() {
return this.getTypeAnnotationInfo().annotation;
export function resolve(dangerous, resolved) {
return this._resolve(dangerous, resolved) || this;
}
/**
* Description
*/
export function getTypeAnnotationInfo(): {
inferred: boolean;
annotation: ?Object;
} {
if (this.typeInfo) {
return this.typeInfo;
}
var info = this.typeInfo = {
inferred: false,
annotation: null
};
var type = this.node && this.node.typeAnnotation;
if (!type) {
info.inferred = true;
type = this.inferTypeAnnotation();
}
if (t.isTypeAnnotation(type)) type = type.typeAnnotation;
info.annotation = type;
return info;
}
/**
* Resolves `NodePath` pointers until it resolves to an absolute path. ie. a data type instead of a
* call etc. If a data type can't be resolved then the last path we were at is returned.
*/
export function resolve(resolved) {
return this._resolve(resolved) || this;
}
export function _resolve(resolved?): ?NodePath {
export function _resolve(dangerous?, resolved?): ?NodePath {
// detect infinite recursion
// todo: possibly have a max length on this just to be safe
if (resolved && resolved.indexOf(this) >= 0) return;
@@ -66,7 +20,7 @@ export function _resolve(resolved?): ?NodePath {
if (this.isVariableDeclarator()) {
if (this.get("id").isIdentifier()) {
return this.get("init").resolve(resolved);
return this.get("init").resolve(dangerous, resolved);
} else {
// otherwise it's a request for a pattern and that's a bit more tricky
}
@@ -81,9 +35,9 @@ export function _resolve(resolved?): ?NodePath {
if (binding.kind === "module") return;
if (binding.path !== this) {
return binding.path.resolve(resolved);
return binding.path.resolve(dangerous, resolved);
}
} else if (this.isMemberExpression()) {
} else if (dangerous && this.isMemberExpression()) {
// this is dangerous, as non-direct target assignments will mutate it's state
// making this resolution inaccurate
@@ -92,7 +46,7 @@ export function _resolve(resolved?): ?NodePath {
var targetName = targetKey.value;
var target = this.get("object").resolve(resolved);
var target = this.get("object").resolve(dangerous, resolved);
if (target.isObjectExpression()) {
var props = target.get("properties");
@@ -107,122 +61,195 @@ export function _resolve(resolved?): ?NodePath {
// { "foo": "obj" } or { ["foo"]: "obj" }
match = match || key.isLiteral({ value: targetName });
if (match) return prop.get("value").resolve(resolved);
if (match) return prop.get("value").resolve(dangerous, resolved);
}
} else if (target.isArrayExpression() && !isNaN(+targetName)) {
var elems = target.get("elements");
var elem = elems[targetName];
if (elem) return elem.resolve(resolved);
if (elem) return elem.resolve(dangerous, resolved);
}
}
}
/**
* Infer the type of the current `NodePath`.
*
* NOTE: This is not cached. Use `getTypeAnnotation()` which is cached.
*/
export function inferTypeAnnotation(force) {
return this._inferTypeAnnotation(force) || t.anyTypeAnnotation();
export function getTypeAnnotation(force) {
if (this.typeAnnotation) return this.typeAnnotation;
var type = this._getTypeAnnotation(force) || t.anyTypeAnnotation();
if (t.isTypeAnnotation(type)) type = type.typeAnnotation;
return this.typeAnnotation = type;
}
export function _inferTypeAnnotation(force?: boolean): ?Object {
var path = this.resolve();
export function _getTypeAnnotationBindingConstantViolations(name, types = []) {
var binding = this.scope.getBinding(name);
var node = path.node;
if (!node) return;
for (var constantViolation of (binding.constantViolations: Array)) {
types.push(constantViolation.getTypeAnnotation());
}
if (types.length) {
return t.createUnionTypeAnnotation(types);
}
}
export function _getTypeAnnotation(force?: boolean): ?Object {
var node = this.node;
if (!node) {
// handle initializerless variables, add in checks for loop initializers too
if (this.key === "init" && this.parentPath.isVariableDeclarator()) {
var declar = this.parentPath.parentPath;
var declarParent = declar.parentPath;
// for (var NODE in bar) {}
if (declar.key === "left" && declarParent.isForInStatement()) {
return t.stringTypeAnnotation();
}
// for (var NODE of bar) {}
if (declar.key === "left" && declarParent.isForOfStatement()) {
return t.anyTypeAnnotation();
}
return t.voidTypeAnnotation();
} else {
return;
}
}
if (node.typeAnnotation) {
return node.typeAnnotation;
}
if (path.isRestElement() || path.parentPath.isRestElement() || path.isArrayExpression()) {
return t.genericTypeAnnotation(t.identifier("Array"));
//
if (this.isVariableDeclarator()) {
var id = this.get("id");
if (id.isIdentifier()) {
return this._getTypeAnnotationBindingConstantViolations(id.node.name, [
this.get("init").getTypeAnnotation()
]);
} else {
return;
}
}
if (path.parentPath.isTypeCastExpression()) {
return path.parentPath.inferTypeAnnotation();
//
if (this.parentPath.isTypeCastExpression()) {
return this.parentPath.getTypeAnnotation();
}
if (path.isTypeCastExpression()) {
if (this.isTypeCastExpression()) {
return node.typeAnnotation;
}
if (path.parentPath.isReturnStatement() && !force) {
return path.parentPath.inferTypeAnnotation();
//
if (this.isRestElement() || this.parentPath.isRestElement() || this.isArrayExpression()) {
return t.genericTypeAnnotation(t.identifier("Array"), t.typeParameterInstantiation([t.anyTypeAnnotation()]));
}
if (path.isReturnStatement()) {
var funcPath = this.findParent((node, path) => path.isFunction());
//
if (!force && this.parentPath.isReturnStatement()) {
return this.parentPath.getTypeAnnotation();
}
if (this.isReturnStatement()) {
var funcPath = this.findParent((path) => path.isFunction());
if (!funcPath) return;
var returnType = funcPath.node.returnType;
if (returnType) {
return returnType;
} else {
return this.get("argument").inferTypeAnnotation(true);
return this.get("argument").getTypeAnnotation(true);
}
}
if (path.isNewExpression() && path.get("callee").isIdentifier()) {
//
if (this.isNewExpression() && this.get("callee").isIdentifier()) {
// only resolve identifier callee
return t.genericTypeAnnotation(node.callee);
}
if (path.isReferencedIdentifier()) {
//
if (this.isReferencedIdentifier()) {
// check if a binding exists of this value and if so then return a union type of all
// possible types that the binding could be
var binding = this.scope.getBinding(node.name);
if (binding) {
if (binding.identifier.typeAnnotation) {
return binding.identifier.typeAnnotation;
} else {
return this._getTypeAnnotationBindingConstantViolations(node.name, [
binding.path.getTypeAnnotation()
]);
}
}
// built-in values
if (node.name === "undefined") {
return t.voidTypeAnnotation();
} else if (node.name === "NaN") {
} else if (node.name === "NaN" || node.name === "Infinity") {
return t.numberTypeAnnotation();
} else if (node.name === "arguments") {
// todo
}
}
if (path.isObjectExpression()) {
//
if (this.isObjectExpression()) {
return t.genericTypeAnnotation(t.identifier("Object"));
}
if (path.isFunction() && path.parentPath.isProperty({ kind: "get" })) {
return node.returnType;
}
if (path.isFunction() || path.isClass()) {
//
if (this.isFunction() || this.isClass()) {
return t.genericTypeAnnotation(t.identifier("Function"));
}
if (path.isUnaryExpression()) {
//
if (this.isTemplateLiteral()) {
return t.stringTypeAnnotation();
}
//
if (this.isUnaryExpression()) {
let operator = node.operator;
if (operator === "void") {
return t.voidTypeAnnotation();
} else if (NUMBER_UNARY_OPERATORS.indexOf(operator) >= 0) {
} else if (t.NUMBER_UNARY_OPERATORS.indexOf(operator) >= 0) {
return t.numberTypeAnnotation();
} else if (STRING_UNARY_OPERATORS.indexOf(operator) >= 0) {
} else if (t.STRING_UNARY_OPERATORS.indexOf(operator) >= 0) {
return t.stringTypeAnnotation();
} else if (BOOLEAN_UNARY_OPERATORS.indexOf(operator) >= 0) {
} else if (t.BOOLEAN_UNARY_OPERATORS.indexOf(operator) >= 0) {
return t.booleanTypeAnnotation();
}
}
if (path.isBinaryExpression()) {
//
if (this.isBinaryExpression()) {
let operator = node.operator;
if (NUMBER_BINARY_OPERATORS.indexOf(operator) >= 0) {
if (t.NUMBER_BINARY_OPERATORS.indexOf(operator) >= 0) {
return t.numberTypeAnnotation();
} else if (BOOLEAN_BINARY_OPERATORS.indexOf(operator) >= 0) {
} else if (t.BOOLEAN_BINARY_OPERATORS.indexOf(operator) >= 0) {
return t.booleanTypeAnnotation();
} else if (operator === "+") {
var right = path.get("right").resolve();
var left = path.get("left").resolve();
var right = this.get("right");
var left = this.get("left");
if (left || right) {
if (left.isTypeAnnotationGeneric("Number") && right.isTypeAnnotationGeneric("Number")) {
// both numbers so this will be a number
return t.numberTypeAnnotation();
} else if (left.isTypeAnnotationGeneric("String") || right.isTypeAnnotationGeneric("String")) {
// one is a string so the result will be a string
return t.stringTypeAnnotation();
}
if (left.isGenericType("Number") && right.isGenericType("Number")) {
// both numbers so this will be a number
return t.numberTypeAnnotation();
} else if (left.isGenericType("String") || right.isGenericType("String")) {
// one is a string so the result will be a string
return t.stringTypeAnnotation();
}
// unsure if left and right are strings or numbers so stay on the safe side
@@ -233,39 +260,42 @@ export function _inferTypeAnnotation(force?: boolean): ?Object {
}
}
if (path.isLogicalExpression()) {
// todo: create UnionType of left and right annotations
//
if (this.isLogicalExpression()) {
return t.createUnionTypeAnnotation([
this.get("left").getTypeAnnotation(),
this.get("right").getTypeAnnotation()
]);
}
if (path.isConditionalExpression()) {
// todo: create UnionType of consequent and alternate annotations
//
if (this.isConditionalExpression()) {
return t.createUnionTypeAnnotation([
this.get("consequent").getTypeAnnotation(),
this.get("alternate").getTypeAnnotation()
]);
}
if (path.isSequenceExpression()) {
return this.get("expressions").pop().inferTypeAnnotation(force);
//
if (this.isSequenceExpression()) {
return this.get("expressions").pop().getTypeAnnotation(force);
}
if (path.isAssignmentExpression()) {
return this.get("right").inferTypeAnnotation(force);
//
if (this.isAssignmentExpression()) {
return this.get("right").getTypeAnnotation(force);
}
if (path.isUpdateExpression()) {
//
if (this.isUpdateExpression()) {
let operator = node.operator;
if (operator === "++" || operator === "--") {
return t.numberTypeAnnotation();
}
}
if (path.isUnaryExpression() && node.prefix) {
let operator = node.operator;
if (operator === "!") {
return t.booleanTypeAnnotation();
} else if (operator === "+" || operator === "-") {
return t.numberTypeAnnotation();
}
}
if (path.isLiteral()) {
//
if (this.isLiteral()) {
var value = node.value;
if (typeof value === "string") return t.stringTypeAnnotation();
if (typeof value === "number") return t.numberTypeAnnotation();
@@ -273,10 +303,29 @@ export function _inferTypeAnnotation(force?: boolean): ?Object {
if (node.regex) return t.genericTypeAnnotation(t.identifier("RegExp"));
}
if (path.isCallExpression()) {
var callee = path.get("callee").resolve();
//
var callPath;
if (this.isCallExpression()) callPath = this.get("callee");
if (this.isTaggedTemplateExpression()) callPath = this.get("tag");
if (callPath) {
var callee = callPath.resolve();
// todo: read typescript/flow interfaces
if (callee.isNodeType("Function")) return callee.node.returnType;
if (callee.isFunction()) {
if (callee.is("async")) {
if (callee.is("generator")) {
return t.genericTypeAnnotation(t.identifier("AsyncIterator"));
} else {
return t.genericTypeAnnotation(t.identifier("Promise"));
}
} else {
if (callee.node.returnType) {
return callee.node.returnType;
} else {
// todo: get union type of all return arguments
}
}
}
}
}
@@ -284,21 +333,11 @@ export function _inferTypeAnnotation(force?: boolean): ?Object {
* Description
*/
export function isTypeAnnotationGeneric(genericName: string, opts = {}): boolean {
var typeInfo = this.getTypeAnnotationInfo();
var type = typeInfo.annotation;
if (!type) return false;
if (typeInfo.inferred && opts.inference === false) {
return false;
}
export function isGenericType(genericName: string): boolean {
var type = this.getTypeAnnotation();
if (t.isGenericTypeAnnotation(type) && t.isIdentifier(type.id, { name: genericName })) {
if (opts.requireTypeParameters && !type.typeParameters) {
return false;
} else {
return true;
}
return true;
}
if (genericName === "String") {

View File

@@ -1,6 +1,6 @@
import includes from "lodash/collection/includes";
import repeating from "repeating";
import type NodePath from "../path";
import type File from "../../transformation/file";
import traverse from "../index";
import defaults from "lodash/object/defaults";
import * as messages from "../../messages";
@@ -42,7 +42,7 @@ var collectorVisitor = {
ForXStatement() {
var left = this.get("left");
if (left.isPattern() || left.isIdentifier()) {
this.scope.registerConstantViolation(left);
this.scope.registerConstantViolation(left, left);
}
},
@@ -78,15 +78,15 @@ var collectorVisitor = {
}
// register as constant violation
this.scope.registerConstantViolation(this.get("left"), this.get("right"));
this.scope.registerConstantViolation(this, this.get("left"), this.get("right"));
},
UpdateExpression(node, parent, scope) {
scope.registerConstantViolation(this.get("argument"), null);
scope.registerConstantViolation(this, this.get("argument"), null);
},
UnaryExpression(node, parent, scope) {
if (node.operator === "delete") scope.registerConstantViolation(this.get("left"), null);
if (node.operator === "delete") scope.registerConstantViolation(this, this.get("left"), null);
},
BlockScoped(node, parent, scope) {
@@ -139,7 +139,7 @@ export default class Scope {
* within.
*/
constructor(path: NodePath, parent?: Scope, file?: File) {
constructor(path: NodePath, parent?: Scope) {
if (parent && parent.block === path.node) {
return parent;
}
@@ -152,7 +152,7 @@ export default class Scope {
}
this.parent = parent;
this.file = parent ? parent.file : file;
this.hub = path.hub;
this.parentBlock = path.parent;
this.block = path.node;
@@ -176,17 +176,6 @@ export default class Scope {
traverse(node, opts, this, state, this.path);
}
/**
* Since `Scope` instances are unique to their traversal we need some other
* way to compare if scopes are the same. Here we just compare `this.bindings`
* as it will be the same across all instances.
*/
is(scope) {
return this.bindings === scope.bindings;
}
/**
* Description
*/
@@ -343,7 +332,7 @@ export default class Scope {
if (!duplicate) duplicate = local.kind === "param" && (kind === "let" || kind === "const");
if (duplicate) {
throw this.file.errorWithNode(id, messages.get("scopeDuplicateDeclaration", name), TypeError);
throw this.hub.file.errorWithNode(id, messages.get("scopeDuplicateDeclaration", name), TypeError);
}
}
@@ -373,7 +362,7 @@ export default class Scope {
state.binding.name = newName;
}
var file = this.file;
var file = this.hub.file;
if (file) {
this._renameFromMap(file.moduleFormatter.localImports, oldName, newName, state.binding);
//this._renameFromMap(file.moduleFormatter.localExports, oldName, newName);
@@ -392,11 +381,20 @@ export default class Scope {
*/
dump() {
var sep = repeating("-", 60);
console.log(sep);
var scope = this;
do {
console.log(scope.block.type, "Bindings:", Object.keys(scope.bindings));
console.log("#", scope.block.type);
for (var name in scope.bindings) {
var binding = scope.bindings[name];
console.log(" -", name, {
constant: binding.constant,
references: binding.references
});
}
} while(scope = scope.parent);
console.log("-------------");
console.log(sep);
}
/**
@@ -404,11 +402,11 @@ export default class Scope {
*/
toArray(node: Object, i?: number) {
var file = this.file;
var file = this.hub.file;
if (t.isIdentifier(node)) {
var binding = this.getBinding(node.name);
if (binding && binding.constant && binding.path.isTypeAnnotationGeneric("Array")) return node;
if (binding && binding.constant && binding.path.isGenericType("Array")) return node;
}
if (t.isArrayExpression(node)) {
@@ -426,7 +424,7 @@ export default class Scope {
} else if (i) {
args.push(t.literal(i));
helperName = "sliced-to-array";
if (this.file.isLoose("es6.forOf")) helperName += "-loose";
if (this.hub.file.isLoose("es6.forOf")) helperName += "-loose";
}
return t.callExpression(file.addHelper(helperName), args);
}
@@ -448,6 +446,8 @@ export default class Scope {
this.registerBinding("let", path);
} else if (t.isImportDeclaration(node) || t.isExportDeclaration(node)) {
this.registerBinding("module", path);
} else if (t.isFlowDeclaration()) {
this.registerBinding("type", path);
} else {
this.registerBinding("unknown", path);
}
@@ -457,7 +457,7 @@ export default class Scope {
* Description
*/
registerConstantViolation(left: NodePath, right: NodePath) {
registerConstantViolation(root: NodePath, left: NodePath, right: NodePath) {
var ids = left.getBindingIdentifiers();
for (var name in ids) {
var binding = this.getBinding(name);
@@ -468,7 +468,7 @@ export default class Scope {
if (rightType && binding.isCompatibleWithType(rightType)) continue;
}
binding.reassign(left, right);
binding.reassign(root, left, right);
}
}
@@ -495,7 +495,13 @@ export default class Scope {
var local = this.getOwnBindingInfo(name);
if (local) {
// don't ever let a type alias shadow a local binding
if (kind === "type") continue;
// same identifier so continue safely as we're likely trying to register it
// multiple times
if (local.identifier === id) continue;
this.checkBlockScopedCollisions(local, kind, name, id);
}
@@ -706,7 +712,7 @@ export default class Scope {
declar._generated = true;
declar._blockHoist = 2;
this.file.attachAuxiliaryComment(declar);
this.hub.file.attachAuxiliaryComment(declar);
var [declarPath] = path.unshiftContainer("body", [declar]);
this.registerBinding(kind, declarPath);

View File

@@ -79,28 +79,28 @@
"JSXEmptyExpression": ["Expression"],
"JSXMemberExpression": ["Expression"],
"AnyTypeAnnotation": ["Flow"],
"AnyTypeAnnotation": ["Flow", "FlowBaseAnnotation"],
"ArrayTypeAnnotation": ["Flow"],
"BooleanTypeAnnotation": ["Flow"],
"BooleanTypeAnnotation": ["Flow", "FlowBaseAnnotation"],
"ClassImplements": ["Flow"],
"DeclareClass": ["Flow", "Statement"],
"DeclareFunction": ["Flow", "Statement"],
"DeclareModule": ["Flow", "Statement"],
"DeclareVariable": ["Flow", "Statement"],
"DeclareClass": ["Flow", "FlowDeclaration", "Statement", "Declaration"],
"DeclareFunction": ["Flow", "FlowDeclaration", "Statement", "Declaration"],
"DeclareModule": ["Flow", "FlowDeclaration", "Statement"],
"DeclareVariable": ["Flow", "FlowDeclaration", "Statement", "Declaration"],
"FunctionTypeAnnotation": ["Flow"],
"FunctionTypeParam": ["Flow"],
"GenericTypeAnnotation": ["Flow"],
"InterfaceExtends": ["Flow"],
"InterfaceDeclaration": ["Flow", "Statement", "Declaration"],
"InterfaceDeclaration": ["Flow", "FlowDeclaration", "Statement", "Declaration"],
"IntersectionTypeAnnotation": ["Flow"],
"MixedTypeAnnotation": ["Flow"],
"MixedTypeAnnotation": ["Flow", "FlowBaseAnnotation"],
"NullableTypeAnnotation": ["Flow"],
"NumberTypeAnnotation": ["Flow"],
"NumberTypeAnnotation": ["Flow", "FlowBaseAnnotation"],
"StringLiteralTypeAnnotation": ["Flow"],
"StringTypeAnnotation": ["Flow"],
"StringTypeAnnotation": ["Flow", "FlowBaseAnnotation"],
"TupleTypeAnnotation": ["Flow"],
"TypeofTypeAnnotation": ["Flow"],
"TypeAlias": ["Flow", "Statement"],
"TypeAlias": ["Flow", "FlowDeclaration", "Statement", "Declaration"],
"TypeAnnotation": ["Flow"],
"TypeCastExpression": ["Flow"],
"TypeParameterDeclaration": ["Flow"],
@@ -111,7 +111,7 @@
"ObjectTypeProperty": ["Flow", "UserWhitespacable"],
"QualifiedTypeIdentifier": ["Flow"],
"UnionTypeAnnotation": ["Flow"],
"VoidTypeAnnotation": ["Flow"],
"VoidTypeAnnotation": ["Flow", "FlowBaseAnnotation"],
"JSXAttribute": ["JSX", "Immutable"],
"JSXClosingElement": ["JSX", "Immutable"],

81
src/babel/types/flow.js Normal file
View File

@@ -0,0 +1,81 @@
import * as t from "./index";
/**
* Takes an array of `types` and flattens them, removing duplicates and
* returns a `UnionTypeAnnotation` node containg them.
*/
export function createUnionTypeAnnotation(types) {
var flattened = removeTypeDuplicates(types);
if (flattened.length === 1) {
return flattened[0];
} else {
return t.unionTypeAnnotation(flattened);
}
}
export function removeTypeDuplicates(nodes) {
var generics = {};
var bases = {};
var types = [];
for (var i = 0; i < nodes.length; i++) {
var node = nodes[i];
if (!node) continue;
// this type matches anything
if (t.isAnyTypeAnnotation(node)) {
return [node];
}
//
if (t.isFlowBaseAnnotation(node)) {
bases[node.type] = node;
continue;
}
//
if (t.isUnionTypeAnnotation(node)) {
nodes = nodes.concat(node.types);
continue;
}
// find a matching generic type and merge and deduplicate the type parameters
if (t.isGenericTypeAnnotation(node)) {
let name = node.id.name;
if (generics[name]) {
var existing = generics[name];
if (existing.typeParameters) {
if (node.typeParameters) {
existing.typeParameters.params = removeTypeDuplicates(
existing.typeParameters.params.concat(node.typeParameters.params)
);
}
} else {
existing = node.typeParameters;
}
} else {
generics[name] = node;
}
continue;
}
types.push(node);
}
// add back in bases
for (var type in bases) {
types.push(bases[type]);
}
// add back in generics
for (let name in generics) {
types.push(generics[name]);
}
return types;
}

View File

@@ -24,11 +24,17 @@ function registerType(type: string, skipAliasCheck?: boolean) {
};
}
export var STATEMENT_OR_BLOCK_KEYS = ["consequent", "body", "alternate"];
export var NATIVE_TYPE_NAMES = ["Array", "ArrayBuffer", "Boolean", "DataView", "Date", "Error", "EvalError", "Float32Array", "Float64Array", "Function", "Int8Array", "Int16Array", "Int32Array", "Map", "Number", "Object", "Proxy", "Promise", "RangeError", "ReferenceError", "RegExp", "Set", "String", "Symbol", "SyntaxError", "TypeError", "Uint8Array", "Uint8ClampedArray", "Uint16Array", "Uint32Array", "URIError", "WeakMap", "WeakSet"];
export var FLATTENABLE_KEYS = ["body", "expressions"];
export var FOR_INIT_KEYS = ["left", "init"];
export var COMMENT_KEYS = ["leadingComments", "trailingComments"];
export const STATEMENT_OR_BLOCK_KEYS = ["consequent", "body", "alternate"];
export const FLATTENABLE_KEYS = ["body", "expressions"];
export const FOR_INIT_KEYS = ["left", "init"];
export const COMMENT_KEYS = ["leadingComments", "trailingComments"];
export const BOOLEAN_BINARY_OPERATORS = ["==", "===", "!=", "!==", ">", "<", ">=", "<=", "in", "instanceof"];
export const NUMBER_BINARY_OPERATORS = ["-", "/", "*", "**", "&", "|", ">>", ">>>", "<<", "^"];
export const BOOLEAN_UNARY_OPERATORS = ["delete", "!"];
export const NUMBER_UNARY_OPERATORS = ["+", "-", "++", "--", "~"];
export const STRING_UNARY_OPERATORS = ["typeof"];
export const VISITOR_KEYS = require("./visitor-keys");
export const BUILDER_KEYS = require("./builder-keys");
@@ -287,10 +293,12 @@ export function inherits(child: Object, parent: Object): Object {
if (!child || !parent) return child;
child._scopeInfo = parent._scopeInfo;
child.range = parent.range;
child.start = parent.start;
child.loc = parent.loc;
child.end = parent.end;
child._paths = parent._paths;
child.range = parent.range;
child.start = parent.start;
child.loc = parent.loc;
child.end = parent.end;
child.typeAnnotation = parent.typeAnnotation;
child.returnType = parent.returnType;
@@ -306,3 +314,4 @@ exports.__esModule = true;
assign(t, require("./retrievers"));
assign(t, require("./validators"));
assign(t, require("./converters"));
assign(t, require("./flow"));

View File

@@ -30,6 +30,13 @@ export function getBindingIdentifiers(node: Object): Object {
}
getBindingIdentifiers.keys = {
DeclareClass: "id",
DeclareFunction: "id",
DeclareModule: "id",
DeclareVariable: "id",
InterfaceDeclaration: "id",
TypeAlias: "id",
ComprehensionExpression: "blocks",
ComprehensionBlock: "left",

View File

@@ -43,6 +43,7 @@
"MetaProperty": ["meta", "property"],
"MethodDefinition": ["key", "value", "decorators"],
"NewExpression": ["callee", "arguments"],
"Noop": [],
"ObjectExpression": ["properties"],
"ObjectPattern": ["properties", "typeAnnotation"],
"Program": ["body"],

View File

@@ -127,6 +127,7 @@ export function shouldIgnore(filename, ignore, only) {
var templateVisitor = {
noScope: true,
enter(node, parent, scope, nodes) {
if (t.isExpressionStatement(node)) {
node = node.expression;
@@ -136,6 +137,10 @@ var templateVisitor = {
this.skip();
this.replaceInline(nodes[node.name]);
}
},
exit(node) {
traverse.clearNode(node);
}
};

View File

@@ -6,7 +6,6 @@
require("./tests.js");
require("./tests-harmony.js");
require("./tests-flow.js");
require("./tests-jsx.js");
require("./tests-babel.js");
require("babel/register")
acorn = require("../../lib/acorn")

File diff suppressed because it is too large Load Diff

View File

@@ -8,17 +8,17 @@ var assert = require("assert");
var File = require("../../lib/babel/transformation/file");
suite("api", function () {
test("{ code: false }", function () {
test("code option false", function () {
var result = transform("foo('bar');", { code: false });
assert.ok(!result.code);
});
test("{ ast: false }", function () {
test("ast option false", function () {
var result = transform("foo('bar');", { ast: false });
assert.ok(!result.ast);
});
test("{ auxiliaryComment }", function () {
test("auxiliaryComment option", function () {
assert.ok(transform("class Foo {}", {
auxiliaryComment: "foobar"
}).code.indexOf("foobar") >= 0);
@@ -28,7 +28,164 @@ suite("api", function () {
}).code.indexOf("foobar") >= 0);
});
suite("getModuleId() {} option", function () {
test("modules metadata", function () {
assert.deepEqual(transform('import { externalName as localName } from "external";').metadata.modules.imports[0], {
source: "external",
imported: ["externalName"],
specifiers: [{
kind: "named",
imported: "externalName",
local: "localName"
}]
});
assert.deepEqual(transform('import * as localName2 from "external";').metadata.modules.imports[0], {
source: "external",
imported: ["*"],
specifiers: [{
kind: "namespace",
local: "localName2"
}]
});
assert.deepEqual(transform('import localName3 from "external";').metadata.modules.imports[0], {
source: 'external',
imported: ['default'],
specifiers: [{
kind: 'named',
imported: 'default',
local: 'localName3'
}]
});
assert.deepEqual(transform('export * as externalName1 from "external";', {
stage: 0
}).metadata.modules.exports, {
exported: ['externalName1'],
specifiers: [{
kind: 'external-namespace',
exported: 'externalName1',
source: "external",
}]
});
assert.deepEqual(transform('export externalName2 from "external";', {
stage: 0
}).metadata.modules.exports, {
exported: ["externalName2"],
specifiers: [{
kind: "external",
local: "externalName2",
exported: "externalName2",
source: "external"
}]
});
assert.deepEqual(transform('export function namedFunction() {}').metadata.modules.exports, {
exported: ["namedFunction"],
specifiers: [{
kind: "local",
local: "namedFunction",
exported: "namedFunction"
}]
});
assert.deepEqual(transform('export var foo = "bar";').metadata.modules.exports, {
"exported": ["foo"],
specifiers: [{
kind: "local",
local: "foo",
exported: "foo"
}]
});
assert.deepEqual(transform("export { localName as externalName3 };").metadata.modules.exports, {
exported: ["externalName3"],
specifiers: [{
kind: "local",
local: "localName",
exported: "externalName3"
}]
});
assert.deepEqual(transform('export { externalName4 } from "external";').metadata.modules.exports, {
exported: ["externalName4"],
specifiers: [{
kind: "external",
local: "externalName4",
exported: "externalName4",
source: "external"
}]
});
assert.deepEqual(transform('export * from "external";').metadata.modules.exports, {
exported: [],
specifiers: [{
kind: "external-all",
source: "external"
}]
});
assert.deepEqual(transform("export default function defaultFunction() {}").metadata.modules.exports, {
exported: ["defaultFunction"],
specifiers: [{
kind: "local",
local: "defaultFunction",
exported: "default"
}]
});
});
test("ignore option", function () {
assert.ok(transform("", {
ignore: "node_modules",
filename: "/foo/node_modules/bar"
}).ignored);
assert.ok(transform("", {
ignore: "foo/node_modules",
filename: "/foo/node_modules/bar"
}).ignored);
assert.ok(transform("", {
ignore: "foo/node_modules/*.bar",
filename: "/foo/node_modules/foo.bar"
}).ignored);
});
test("only option", function () {
assert.ok(!transform("", {
only: "node_modules",
filename: "/foo/node_modules/bar"
}).ignored);
assert.ok(!transform("", {
only: "foo/node_modules",
filename: "/foo/node_modules/bar"
}).ignored);
assert.ok(!transform("", {
only: "foo/node_modules/*.bar",
filename: "/foo/node_modules/foo.bar"
}).ignored);
assert.ok(transform("", {
only: "node_modules",
filename: "/foo/node_module/bar"
}).ignored);
assert.ok(transform("", {
only: "foo/node_modules",
filename: "/bar/node_modules/foo"
}).ignored);
assert.ok(transform("", {
only: "foo/node_modules/*.bar",
filename: "/foo/node_modules/bar.foo"
}).ignored);
});
suite("getModuleId option", function () {
// As of this commit, `getModuleId` is the only option that isn't JSON
// compatible which is why it's not inside /test/core/fixtures/transformation
@@ -45,7 +202,7 @@ suite("api", function () {
assert.equal(result.code, expected);
}
test("{ modules: \"amd\" }", function () {
test("amd", function () {
var expected = [
"define('foo/bar', ['exports'], function (exports) {",
" 'use strict';",
@@ -57,7 +214,7 @@ suite("api", function () {
getModuleNameTest("amd", expected);
});
test("{ modules: \"umd\" }", function () {
test("umd", function () {
var expected = [
"(function (global, factory) {",
" if (typeof define === 'function' && define.amd) {",
@@ -81,7 +238,7 @@ suite("api", function () {
getModuleNameTest("umd", expected);
});
test("{ modules: \"system\" }", function () {
test("system", function () {
var expected = [
"System.register('foo/bar', [], function (_export) {",
" 'use strict';",
@@ -147,7 +304,7 @@ suite("api", function () {
}, /Unknown helper foob/);
});
test("resolveModuleSource", function () {
test("resolveModuleSource option", function () {
var actual = 'import foo from "foo-import-default";\nimport "foo-import-bare";\nexport { foo } from "foo-export-named";';
var expected = 'import foo from "resolved/foo-import-default";\nimport "resolved/foo-import-bare";\nexport { foo } from "resolved/foo-export-named";';

View File

@@ -0,0 +1,3 @@
function foo(a = "foo", b) {
}

View File

@@ -0,0 +1,5 @@
"use strict";
function foo(a, b) {
if (a === undefined) a = "foo";
}

View File

@@ -0,0 +1,13 @@
for (var key in foo) {
break;
foo();
}
function bar() {
yes();
bar();
return "wow";
nomore();
}
bar();

View File

@@ -0,0 +1,13 @@
"use strict";
for (var key in foo) {
break;
}
function bar() {
yes();
bar();
return "wow";
}
bar();

View File

@@ -1,4 +1,5 @@
{
"experimental": true,
"externalHelpers": true,
"noCheckAst": true,
"blacklist": ["regenerator"],