Compare commits
58 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b825998c63 | ||
|
|
6b02ca47c3 | ||
|
|
ea1b85bffa | ||
|
|
3cffe47eea | ||
|
|
e5d5a9fb27 | ||
|
|
ca97fa63a9 | ||
|
|
f4cc27bc0e | ||
|
|
8cea575e2e | ||
|
|
c91baee4d5 | ||
|
|
8055ce29f7 | ||
|
|
4596ae48b8 | ||
|
|
6c268cdf21 | ||
|
|
fce977f1d7 | ||
|
|
a298075949 | ||
|
|
66599c3779 | ||
|
|
60340244b1 | ||
|
|
eb72ea3e5a | ||
|
|
ede6237b6f | ||
|
|
e91e10aae6 | ||
|
|
9c3cca0d25 | ||
|
|
8eee5367f3 | ||
|
|
40d55a3d44 | ||
|
|
75330304dc | ||
|
|
776c508418 | ||
|
|
e804741632 | ||
|
|
3d3cb4be4f | ||
|
|
64f4209119 | ||
|
|
2ede226ef9 | ||
|
|
f5cf641c0a | ||
|
|
1abd3419f6 | ||
|
|
75699db716 | ||
|
|
7c3572f08c | ||
|
|
9dacde6d07 | ||
|
|
8c3aab9a26 | ||
|
|
ba4550c953 | ||
|
|
d0ac65a934 | ||
|
|
a4c70bb029 | ||
|
|
795cf0c0b1 | ||
|
|
e64b90e322 | ||
|
|
d69b0973e1 | ||
|
|
6296f49653 | ||
|
|
9f2b739046 | ||
|
|
da1d5e5577 | ||
|
|
7333b4e392 | ||
|
|
b0442d0784 | ||
|
|
295e69f8f8 | ||
|
|
cfe844fa39 | ||
|
|
0f4ea2d2a6 | ||
|
|
4b85b05839 | ||
|
|
2539d08dce | ||
|
|
c26fd7a819 | ||
|
|
2053610429 | ||
|
|
cd4f83b299 | ||
|
|
ec29ba19a9 | ||
|
|
9dc03e0978 | ||
|
|
bc4258eca9 | ||
|
|
b0e58f9770 | ||
|
|
a1e2641c91 |
12
CHANGELOG.md
12
CHANGELOG.md
@@ -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**
|
||||
|
||||
11
Makefile
11
Makefile
@@ -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
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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>",
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -17,3 +17,7 @@ export function BlockStatement(node, print) {
|
||||
this.rightBrace();
|
||||
}
|
||||
}
|
||||
|
||||
export function Noop() {
|
||||
|
||||
}
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -17,6 +17,8 @@ var or = types.Type.or;
|
||||
// .build("program")
|
||||
// .field("program", def("Program"));
|
||||
|
||||
def("Noop");
|
||||
|
||||
def("AssignmentPattern")
|
||||
.bases("Pattern")
|
||||
.build("left", "right")
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -47,6 +47,7 @@
|
||||
},
|
||||
|
||||
"experimental": {
|
||||
"type": "boolean",
|
||||
"description": "allow use of experimental transformers",
|
||||
"default": false
|
||||
},
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
if (VARIABLE_NAME === undefined) VARIABLE_NAME = DEFAULT_VALUE;
|
||||
@@ -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
|
||||
});
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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)) {
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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]));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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];
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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];
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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"));
|
||||
}
|
||||
|
||||
@@ -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"))
|
||||
);
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
5
src/babel/traversal/hub.js
Normal file
5
src/babel/traversal/hub.js
Normal file
@@ -0,0 +1,5 @@
|
||||
export default class Hub {
|
||||
constructor(file) {
|
||||
this.file = 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;
|
||||
};
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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;
|
||||
|
||||
51
src/babel/traversal/path/comments.js
Normal file
51
src/babel/traversal/path/comments.js
Normal 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;
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 "";
|
||||
}
|
||||
}
|
||||
@@ -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) {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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") {
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
81
src/babel/types/flow.js
Normal 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;
|
||||
}
|
||||
@@ -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"));
|
||||
|
||||
@@ -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",
|
||||
|
||||
|
||||
@@ -43,6 +43,7 @@
|
||||
"MetaProperty": ["meta", "property"],
|
||||
"MethodDefinition": ["key", "value", "decorators"],
|
||||
"NewExpression": ["callee", "arguments"],
|
||||
"Noop": [],
|
||||
"ObjectExpression": ["properties"],
|
||||
"ObjectPattern": ["properties", "typeAnnotation"],
|
||||
"Program": ["body"],
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -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
173
test/core/api.js
173
test/core/api.js
@@ -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";';
|
||||
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
function foo(a = "foo", b) {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
"use strict";
|
||||
|
||||
function foo(a, b) {
|
||||
if (a === undefined) a = "foo";
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
for (var key in foo) {
|
||||
break;
|
||||
foo();
|
||||
}
|
||||
|
||||
function bar() {
|
||||
yes();
|
||||
bar();
|
||||
return "wow";
|
||||
nomore();
|
||||
}
|
||||
|
||||
bar();
|
||||
@@ -0,0 +1,13 @@
|
||||
"use strict";
|
||||
|
||||
for (var key in foo) {
|
||||
break;
|
||||
}
|
||||
|
||||
function bar() {
|
||||
yes();
|
||||
bar();
|
||||
return "wow";
|
||||
}
|
||||
|
||||
bar();
|
||||
@@ -1,4 +1,5 @@
|
||||
{
|
||||
"experimental": true,
|
||||
"externalHelpers": true,
|
||||
"noCheckAst": true,
|
||||
"blacklist": ["regenerator"],
|
||||
|
||||
Reference in New Issue
Block a user