Merge branch 'experimental'
# Conflicts: # src/babel/transformation/transformers/playground/method-binding.js
This commit is contained in:
commit
4afd0f553e
@ -2,32 +2,38 @@
|
||||
|
||||
var commander = require("commander");
|
||||
var transform = require("../../lib/babel/transformation");
|
||||
var kebabCase = require("lodash/string/kebabCase");
|
||||
var File = require("../../lib/babel/transformation/file");
|
||||
var util = require("../../lib/babel/util");
|
||||
var fs = require("fs");
|
||||
var each = require("lodash/collection/each");
|
||||
var keys = require("lodash/object/keys");
|
||||
var fs = require("fs");
|
||||
|
||||
each(File.options, function (option, key) {
|
||||
if (option.hidden) return;
|
||||
|
||||
var arg = kebabCase(key);
|
||||
|
||||
if (option.type !== "boolean") {
|
||||
arg += ` [${option.type || "string"}]`;
|
||||
}
|
||||
|
||||
if (option.type === "boolean" && option.default === true) {
|
||||
arg = `no-${key}`;
|
||||
}
|
||||
|
||||
arg = `--${arg}`;
|
||||
|
||||
if (option.shorthand) {
|
||||
arg = `-${option.shorthand}, ${arg}`;
|
||||
}
|
||||
|
||||
commander.option(arg, option.description);
|
||||
})
|
||||
|
||||
commander.option("-t, --source-maps-inline", "Append sourceMappingURL comment to bottom of code");
|
||||
commander.option("-s, --source-maps", "Save source map alongside the compiled code");
|
||||
commander.option("-f, --filename [filename]", "Filename to use when reading from stdin - this will be used in source-maps, errors etc [stdin]", "stdin");
|
||||
commander.option("-w, --watch", "Recompile files on changes");
|
||||
commander.option("-r, --external-helpers", "Replace helpers with references to a `babelHelpers` global");
|
||||
commander.option("-e, --experimental", "Enable experimental support for proposed ES7 features");
|
||||
commander.option("-p, --playground", "Enable playground support");
|
||||
|
||||
commander.option("-c, --compact [mode]", "When set to \"auto\" compact is `true` when the input size exceeds 100KB. (auto|true|false)", "auto");
|
||||
commander.option("-m, --modules [modules]", "Module formatter type to use [common]", "common");
|
||||
commander.option("-l, --whitelist [whitelist]", "Whitelist of transformers to ONLY use", util.list);
|
||||
commander.option("-b, --blacklist [blacklist]", "Blacklist of transformers to NOT use", util.list);
|
||||
commander.option("-i, --optional [list]", "List of optional transformers to enable", util.list);
|
||||
commander.option("-L, --loose [list]", "List of transformers to enable loose mode ON", util.list);
|
||||
commander.option("-o, --out-file [out]", "Compile all input files into a single file");
|
||||
commander.option("-d, --out-dir [out]", "Compile an input directory of modules into an output directory");
|
||||
commander.option("-c, --remove-comments", "Remove comments from the compiled code", false);
|
||||
commander.option("-M, --module-ids", "Insert module id in modules", false);
|
||||
commander.option("-R, --react-compat", "Makes the react transformer produce pre-v0.12 code");
|
||||
commander.option("--keep-module-id-extensions", "Keep extensions when generating module ids", false);
|
||||
commander.option("-a, --auxiliary-comment [comment]", "Comment text to prepend to all auxiliary code");
|
||||
commander.option("-D, --copy-files", "When compiling a directory copy over non-compilable files");
|
||||
|
||||
commander.on("--help", function () {
|
||||
@ -38,9 +44,7 @@ commander.on("--help", function () {
|
||||
each(keys(obj).sort(), function (key) {
|
||||
if (key[0] === "_") return;
|
||||
|
||||
if (obj[key].optional) {
|
||||
key = "[" + key + "]";
|
||||
}
|
||||
if (obj[key].optional) key = `[${key}]`;
|
||||
|
||||
console.log(" - " + key);
|
||||
});
|
||||
@ -100,24 +104,11 @@ if (errors.length) {
|
||||
|
||||
//
|
||||
|
||||
exports.opts = {
|
||||
keepModuleIdExtensions: commander.keepModuleIdExtensions,
|
||||
auxiliaryComment: commander.auxiliaryComment,
|
||||
externalHelpers: commander.externalHelpers,
|
||||
sourceMapName: commander.outFile,
|
||||
experimental: commander.experimental,
|
||||
reactCompat: commander.reactCompat,
|
||||
playground: commander.playground,
|
||||
moduleIds: commander.moduleIds,
|
||||
blacklist: commander.blacklist,
|
||||
whitelist: commander.whitelist,
|
||||
sourceMap: commander.sourceMaps || commander.sourceMapsInline,
|
||||
optional: commander.optional,
|
||||
comments: !commander.removeComments,
|
||||
modules: commander.modules,
|
||||
compact: commander.compact,
|
||||
loose: commander.loose
|
||||
};
|
||||
exports.opts = {};
|
||||
|
||||
each(File.options, function (opt, key) {
|
||||
exports.opts[key] = commander[key];
|
||||
});
|
||||
|
||||
var fn;
|
||||
|
||||
|
||||
@ -1,11 +1,10 @@
|
||||
var resolveRc = require("../../lib/babel/api/register/resolve-rc");
|
||||
var readdir = require("fs-readdir-recursive");
|
||||
var index = require("./index");
|
||||
var babel = require("../../lib/babel/api/node");
|
||||
var util = require("../../lib/babel/util");
|
||||
var path = require("path");
|
||||
var fs = require("fs");
|
||||
var _ = require("lodash");
|
||||
var readdir = require("fs-readdir-recursive");
|
||||
var index = require("./index");
|
||||
var babel = require("../../lib/babel/api/node");
|
||||
var util = require("../../lib/babel/util");
|
||||
var path = require("path");
|
||||
var fs = require("fs");
|
||||
var _ = require("lodash");
|
||||
|
||||
exports.readdirFilter = function (filename) {
|
||||
return readdir(filename).filter(function (filename) {
|
||||
@ -24,7 +23,6 @@ exports.addSourceMappingUrl = function (code, loc) {
|
||||
exports.transform = function (filename, code, opts) {
|
||||
opts = _.defaults(opts || {}, index.opts);
|
||||
opts.filename = filename;
|
||||
resolveRc(filename, opts);
|
||||
|
||||
var result = babel.transform(code, opts);
|
||||
result.filename = filename;
|
||||
|
||||
@ -54,6 +54,7 @@
|
||||
"leven": "^1.0.1",
|
||||
"line-numbers": "0.2.0",
|
||||
"lodash": "^3.2.0",
|
||||
"minimatch": "^2.0.3",
|
||||
"output-file-sync": "^1.1.0",
|
||||
"path-is-absolute": "^1.0.0",
|
||||
"private": "^0.1.6",
|
||||
|
||||
@ -1,12 +1,13 @@
|
||||
import isFunction from "lodash/lang/isFunction";
|
||||
import transform from "../transformation";
|
||||
import * as util from "../util";
|
||||
import fs from "fs";
|
||||
|
||||
import * as util from "../util";
|
||||
export { util as _util };
|
||||
export { util };
|
||||
export { canCompile } from "../util";
|
||||
|
||||
export { default as acorn } from "acorn-babel";
|
||||
export { default as Transformer } from "../transformation/transformer";
|
||||
export { default as transform } from "../transformation";
|
||||
export { default as traverse } from "../traversal";
|
||||
export { default as buildExternalHelpers } from "../tools/build-external-helpers";
|
||||
@ -15,7 +16,7 @@ export { version } from "../../../package";
|
||||
import * as t from "../types";
|
||||
export { t as types };
|
||||
|
||||
export function register(opts) {
|
||||
export function register(opts?: Object) {
|
||||
var callback = require("./register/node");
|
||||
if (opts != null) callback(opts);
|
||||
return callback;
|
||||
@ -25,7 +26,7 @@ export function polyfill() {
|
||||
require("../polyfill");
|
||||
}
|
||||
|
||||
export function transformFile(filename, opts, callback) {
|
||||
export function transformFile(filename: string, opts?: Object, callback: Function) {
|
||||
if (isFunction(opts)) {
|
||||
callback = opts;
|
||||
opts = {};
|
||||
@ -48,7 +49,7 @@ export function transformFile(filename, opts, callback) {
|
||||
});
|
||||
}
|
||||
|
||||
export function transformFileSync(filename, opts = {}) {
|
||||
export function transformFileSync(filename: string, opts?: Object = {}) {
|
||||
opts.filename = filename;
|
||||
return transform(fs.readFileSync(filename), opts);
|
||||
}
|
||||
|
||||
@ -2,7 +2,7 @@ import path from "path";
|
||||
import os from "os";
|
||||
import fs from "fs";
|
||||
|
||||
var FILENAME = process.env.BABEL_CACHE_PATH || path.join(os.tmpdir(), "babel.json");
|
||||
const FILENAME = process.env.BABEL_CACHE_PATH || path.join(os.tmpdir(), "babel.json");
|
||||
var data = {};
|
||||
|
||||
export function save() {
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import "../../polyfill";
|
||||
import sourceMapSupport from "source-map-support";
|
||||
import * as registerCache from "./cache";
|
||||
import resolveRc from "./resolve-rc";
|
||||
import resolveRc from "../../tools/resolve-rc";
|
||||
import extend from "lodash/object/extend";
|
||||
import * as babel from "../node";
|
||||
import each from "lodash/collection/each";
|
||||
@ -44,6 +44,9 @@ var compile = function (filename) {
|
||||
var result;
|
||||
|
||||
var opts = extend({}, transformOpts);
|
||||
|
||||
// this will be done when the file is transformed anyway but we need all
|
||||
// the options so we can generate the cache key
|
||||
resolveRc(filename, opts);
|
||||
|
||||
var cacheKey = `${filename}:${JSON.stringify(opts)}:${babel.version}`;
|
||||
|
||||
@ -66,8 +66,10 @@ export function ImportDeclaration(node, print) {
|
||||
if (specfiers && specfiers.length) {
|
||||
var foundImportSpecifier = false;
|
||||
|
||||
each(node.specifiers, (spec, i) => {
|
||||
if (+i > 0) {
|
||||
for (var i = 0; i < node.specifiers.length; i++) {
|
||||
var spec = node.specifiers[i];
|
||||
|
||||
if (i > 0) {
|
||||
this.push(", ");
|
||||
}
|
||||
|
||||
@ -79,7 +81,7 @@ export function ImportDeclaration(node, print) {
|
||||
}
|
||||
|
||||
print(spec);
|
||||
});
|
||||
}
|
||||
|
||||
if (foundImportSpecifier) {
|
||||
this.push(" }");
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import each from "lodash/collection/each";
|
||||
import * as t from "../../types";
|
||||
|
||||
var PRECEDENCE = {};
|
||||
const PRECEDENCE = {};
|
||||
|
||||
each([
|
||||
["||"],
|
||||
|
||||
@ -55,10 +55,10 @@ var highlight = function (text) {
|
||||
});
|
||||
};
|
||||
|
||||
export default function (lines, lineNumber, colNumber) {
|
||||
export default function (lines: number, lineNumber: number, colNumber: number, color?): string {
|
||||
colNumber = Math.max(colNumber, 0);
|
||||
|
||||
if (chalk.supportsColor) {
|
||||
if (color && chalk.supportsColor) {
|
||||
lines = highlight(lines);
|
||||
}
|
||||
|
||||
|
||||
@ -32,12 +32,12 @@ export default function (opts, code, callback) {
|
||||
} catch (err) {
|
||||
if (!err._babel) {
|
||||
err._babel = true;
|
||||
|
||||
var message = `${opts.filename}: ${err.message}`;
|
||||
|
||||
var loc = err.loc;
|
||||
if (loc) {
|
||||
var frame = codeFrame(code, loc.line, loc.column + 1);
|
||||
message += frame;
|
||||
message += codeFrame(code, loc.line, loc.column + 1, opts.highlightErrors);
|
||||
}
|
||||
|
||||
if (err.stack) {
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
import * as util from "util";
|
||||
|
||||
export var messages = {
|
||||
export const MESSAGES = {
|
||||
tailCallReassignmentDeopt: "Function reference has been reassigned so it's probably be dereferenced so we can't optimise this with confidence",
|
||||
JSXNamespacedTags: "Namespace tags are not supported. ReactJSX is not XML.",
|
||||
classesIllegalBareSuper: "Illegal use of bare super",
|
||||
@ -25,7 +25,7 @@ export var messages = {
|
||||
};
|
||||
|
||||
export function get(key: String, ...args) {
|
||||
var msg = messages[key];
|
||||
var msg = MESSAGES[key];
|
||||
if (!msg) throw new ReferenceError(`Unknown message ${JSON.stringify(key)}`);
|
||||
|
||||
args = parseArgs(args);
|
||||
|
||||
@ -1,20 +1,25 @@
|
||||
import convertSourceMap from "convert-source-map";
|
||||
import * as optionParsers from "./option-parsers";
|
||||
import shebangRegex from "shebang-regex";
|
||||
import TraversalPath from "../../traversal/path";
|
||||
import isFunction from "lodash/lang/isFunction";
|
||||
import isAbsolute from "path-is-absolute";
|
||||
import resolveRc from "../../tools/resolve-rc";
|
||||
import sourceMap from "source-map";
|
||||
import transform from "./index";
|
||||
import generate from "../generation";
|
||||
import transform from "./../index";
|
||||
import generate from "../../generation";
|
||||
import defaults from "lodash/object/defaults";
|
||||
import includes from "lodash/collection/includes";
|
||||
import traverse from "../../traversal";
|
||||
import assign from "lodash/object/assign";
|
||||
import Logger from "./logger";
|
||||
import parse from "../helpers/parse";
|
||||
import Scope from "../traversal/scope";
|
||||
import parse from "../../helpers/parse";
|
||||
import Scope from "../../traversal/scope";
|
||||
import slash from "slash";
|
||||
import * as util from "../util";
|
||||
import * as util from "../../util";
|
||||
import path from "path";
|
||||
import each from "lodash/collection/each";
|
||||
import * as t from "../types";
|
||||
import * as t from "../../types";
|
||||
|
||||
var checkTransformerVisitor = {
|
||||
enter(node, parent, scope, state) {
|
||||
@ -78,84 +83,37 @@ export default class File {
|
||||
"self-global"
|
||||
];
|
||||
|
||||
static validOptions = [
|
||||
"filename",
|
||||
"filenameRelative",
|
||||
|
||||
"blacklist",
|
||||
"whitelist",
|
||||
"optional",
|
||||
|
||||
"loose",
|
||||
"playground",
|
||||
"experimental",
|
||||
|
||||
"modules",
|
||||
"moduleIds",
|
||||
"moduleId",
|
||||
"resolveModuleSource",
|
||||
"keepModuleIdExtensions",
|
||||
|
||||
"code",
|
||||
"ast",
|
||||
|
||||
"comments",
|
||||
"compact",
|
||||
|
||||
"auxiliaryComment",
|
||||
"externalHelpers",
|
||||
"returnUsedHelpers",
|
||||
|
||||
"inputSourceMap",
|
||||
"sourceMap",
|
||||
"sourceMapName",
|
||||
"sourceFileName",
|
||||
"sourceRoot",
|
||||
"moduleRoot",
|
||||
|
||||
// legacy
|
||||
"format",
|
||||
"reactCompat",
|
||||
|
||||
// these are used by plugins
|
||||
"ignore",
|
||||
"only",
|
||||
"extensions",
|
||||
"accept"
|
||||
];
|
||||
static options = require("./options");
|
||||
|
||||
normalizeOptions(opts: Object) {
|
||||
opts = assign({}, opts);
|
||||
|
||||
for (var key in opts) {
|
||||
if (key[0] !== "_" && File.validOptions.indexOf(key) < 0) {
|
||||
throw new ReferenceError(`Unknown option: ${key}`);
|
||||
}
|
||||
if (opts.filename && isAbsolute(opts.filename)) {
|
||||
opts = resolveRc(opts.filename, opts);
|
||||
}
|
||||
|
||||
defaults(opts, {
|
||||
keepModuleIdExtensions: false,
|
||||
resolveModuleSource: null,
|
||||
returnUsedHelpers: false,
|
||||
externalHelpers: false,
|
||||
auxilaryComment: "",
|
||||
inputSourceMap: null,
|
||||
experimental: false,
|
||||
reactCompat: false,
|
||||
playground: false,
|
||||
moduleIds: false,
|
||||
blacklist: [],
|
||||
whitelist: [],
|
||||
sourceMap: false,
|
||||
optional: [],
|
||||
comments: true,
|
||||
filename: "unknown",
|
||||
modules: "common",
|
||||
compact: "auto",
|
||||
loose: [],
|
||||
code: true,
|
||||
ast: true
|
||||
});
|
||||
//
|
||||
|
||||
for (let key in opts) {
|
||||
if (key[0] === "_") continue;
|
||||
|
||||
let option = File.options[key];
|
||||
if (!option) throw new ReferenceError(`Unknown option: ${key}`);
|
||||
}
|
||||
|
||||
for (let key in File.options) {
|
||||
let option = File.options[key];
|
||||
|
||||
var val = opts[key];
|
||||
if (val == null) val = option.default || null;
|
||||
|
||||
var optionParser = optionParsers[option.type];
|
||||
if (optionParser) {
|
||||
val = optionParser(key, val);
|
||||
}
|
||||
|
||||
opts[key] = val;
|
||||
}
|
||||
|
||||
if (opts.inputSourceMap) {
|
||||
opts.sourceMap = true;
|
||||
@ -173,15 +131,8 @@ export default class File {
|
||||
|
||||
opts.basename = path.basename(opts.filename, path.extname(opts.filename));
|
||||
|
||||
opts.blacklist = util.arrayify(opts.blacklist);
|
||||
opts.whitelist = util.arrayify(opts.whitelist);
|
||||
opts.optional = util.arrayify(opts.optional);
|
||||
opts.compact = util.booleanify(opts.compact);
|
||||
opts.loose = util.arrayify(opts.loose);
|
||||
|
||||
if (includes(opts.loose, "all") || includes(opts.loose, true)) {
|
||||
opts.loose = Object.keys(transform.transformers);
|
||||
}
|
||||
opts.ignore = util.arrayify(opts.ignore, util.regexify);
|
||||
opts.only = util.arrayify(opts.only, util.regexify);
|
||||
|
||||
defaults(opts, {
|
||||
moduleRoot: opts.sourceRoot
|
||||
@ -200,33 +151,12 @@ export default class File {
|
||||
sourceMapName: opts.filenameRelative
|
||||
});
|
||||
|
||||
if (opts.playground) {
|
||||
opts.experimental = true;
|
||||
}
|
||||
//
|
||||
|
||||
if (opts.externalHelpers) {
|
||||
this.set("helpersNamespace", t.identifier("babelHelpers"));
|
||||
}
|
||||
|
||||
opts.blacklist = transform._ensureTransformerNames("blacklist", opts.blacklist);
|
||||
opts.whitelist = transform._ensureTransformerNames("whitelist", opts.whitelist);
|
||||
opts.optional = transform._ensureTransformerNames("optional", opts.optional);
|
||||
opts.loose = transform._ensureTransformerNames("loose", opts.loose);
|
||||
|
||||
if (opts.reactCompat) {
|
||||
opts.optional.push("reactCompat");
|
||||
console.error("The reactCompat option has been moved into the optional transformer `reactCompat`");
|
||||
}
|
||||
|
||||
var ensureEnabled = function (key) {
|
||||
var namespace = transform.transformerNamespaces[key];
|
||||
if (namespace === "es7") opts.experimental = true;
|
||||
if (namespace === "playground") opts.playground = true;
|
||||
};
|
||||
|
||||
each(opts.whitelist, ensureEnabled);
|
||||
each(opts.optional, ensureEnabled);
|
||||
|
||||
return opts;
|
||||
};
|
||||
|
||||
@ -234,6 +164,10 @@ export default class File {
|
||||
return includes(this.opts.loose, key);
|
||||
}
|
||||
|
||||
buildPlugins(stack) {
|
||||
|
||||
}
|
||||
|
||||
buildTransformers() {
|
||||
var file = this;
|
||||
|
||||
@ -242,6 +176,8 @@ export default class File {
|
||||
var secondaryStack = [];
|
||||
var stack = [];
|
||||
|
||||
this.buildPlugins(stack);
|
||||
|
||||
each(transform.transformers, function (transformer, key) {
|
||||
var pass = transformers[key] = transformer.buildPass(file);
|
||||
|
||||
@ -377,7 +313,7 @@ export default class File {
|
||||
this.usedHelpers[name] = true;
|
||||
|
||||
var generator = this.get("helperGenerator");
|
||||
var runtime = this.get("helpersNamespace");
|
||||
var runtime = this.get("helpersNamespace");
|
||||
if (generator) {
|
||||
return generator(name);
|
||||
} else if (runtime) {
|
||||
@ -410,7 +346,36 @@ export default class File {
|
||||
return this.parseShebang(code);
|
||||
}
|
||||
|
||||
shouldIgnore() {
|
||||
var opts = this.opts;
|
||||
|
||||
var filename = opts.filename;
|
||||
var ignore = opts.ignore;
|
||||
var only = opts.only;
|
||||
|
||||
if (only.length) {
|
||||
for (var i = 0; i < only.length; i++) {
|
||||
if (only[i].test(filename)) return false;
|
||||
}
|
||||
return true;
|
||||
} else if (ignore.length) {
|
||||
for (var i = 0; i < ignore.length; i++) {
|
||||
if (ignore[i].test(filename)) return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
parse(code: string) {
|
||||
if (this.shouldIgnore()) {
|
||||
return {
|
||||
code: code,
|
||||
map: null,
|
||||
ast: null
|
||||
};
|
||||
}
|
||||
|
||||
code = this.addCode(code);
|
||||
|
||||
var opts = this.opts;
|
||||
@ -424,12 +389,28 @@ export default class File {
|
||||
});
|
||||
}
|
||||
|
||||
setAst(ast) {
|
||||
this.path = TraversalPath.get(null, null, ast, ast, "program", this);
|
||||
this.scope = this.path.scope;
|
||||
this.ast = ast;
|
||||
|
||||
this.path.traverse({
|
||||
enter(node, parent, scope) {
|
||||
if (this.isScope()) {
|
||||
for (var key in scope.bindings) {
|
||||
scope.bindings[key].setTypeAnnotation();
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
transform(ast) {
|
||||
this.log.debug();
|
||||
|
||||
this.ast = ast;
|
||||
this.setAst(ast);
|
||||
|
||||
this.lastStatements = t.getLastStatements(ast.program);
|
||||
this.scope = new Scope(ast.program, ast, null, this);
|
||||
|
||||
var modFormatter = this.moduleFormatter = this.getModuleFormatter(this.opts.modules);
|
||||
if (modFormatter.init && this.transformers["es6.modules"].canRun()) {
|
||||
@ -483,14 +464,14 @@ export default class File {
|
||||
if (inputMap) {
|
||||
map.sources[0] = inputMap.file;
|
||||
|
||||
var inputMapConsumer = new sourceMap.SourceMapConsumer(inputMap);
|
||||
var outputMapConsumer = new sourceMap.SourceMapConsumer(map);
|
||||
var inputMapConsumer = new sourceMap.SourceMapConsumer(inputMap);
|
||||
var outputMapConsumer = new sourceMap.SourceMapConsumer(map);
|
||||
var outputMapGenerator = sourceMap.SourceMapGenerator.fromSourceMap(outputMapConsumer);
|
||||
outputMapGenerator.applySourceMap(inputMapConsumer);
|
||||
|
||||
var mergedMap = outputMapGenerator.toJSON();
|
||||
mergedMap.sources = inputMap.sources
|
||||
mergedMap.file = inputMap.file;
|
||||
mergedMap.file = inputMap.file;
|
||||
return mergedMap;
|
||||
}
|
||||
|
||||
@ -498,6 +479,7 @@ export default class File {
|
||||
}
|
||||
|
||||
generate(): {
|
||||
usedHelpers?: Array<string>;
|
||||
code: string;
|
||||
map?: Object;
|
||||
ast?: Object;
|
||||
@ -507,8 +489,8 @@ export default class File {
|
||||
|
||||
var result = {
|
||||
code: "",
|
||||
map: null,
|
||||
ast: null
|
||||
map: null,
|
||||
ast: null
|
||||
};
|
||||
|
||||
if (this.opts.returnUsedHelpers) {
|
||||
@ -1,4 +1,4 @@
|
||||
import * as util from "../util";
|
||||
import * as util from "../../util";
|
||||
|
||||
export default class Logger {
|
||||
constructor(file: File) {
|
||||
@ -12,6 +12,12 @@ export default class Logger {
|
||||
return parts;
|
||||
}
|
||||
|
||||
deprecate(msg) {
|
||||
if (!file.opts.suppressDeprecationMessages) {
|
||||
console.error(msg);
|
||||
}
|
||||
}
|
||||
|
||||
debug(msg: string) {
|
||||
util.debug(this._buildMessage(msg));
|
||||
}
|
||||
20
src/babel/transformation/file/option-parsers.js
Normal file
20
src/babel/transformation/file/option-parsers.js
Normal file
@ -0,0 +1,20 @@
|
||||
import transform from "./../index";
|
||||
import * as util from "../../util";
|
||||
|
||||
export function transformerList(key, val) {
|
||||
val = util.arrayify(val);
|
||||
|
||||
if (val.indexOf("all") >= 0 || val.indexOf(true) >= 0) {
|
||||
val = Object.keys(transform.transformers);
|
||||
}
|
||||
|
||||
return transform._ensureTransformerNames(key, val);
|
||||
}
|
||||
|
||||
export function boolean(key, val) {
|
||||
return util.booleanify(val);
|
||||
}
|
||||
|
||||
export function list(key, val) {
|
||||
return util.list(val);
|
||||
}
|
||||
164
src/babel/transformation/file/options.json
Normal file
164
src/babel/transformation/file/options.json
Normal file
@ -0,0 +1,164 @@
|
||||
{
|
||||
"filename": {
|
||||
"type": "string",
|
||||
"description": "Filename to use when reading from stdin - this will be used in source-maps, errors etc",
|
||||
"default": "unknown",
|
||||
"shorthand": "f"
|
||||
},
|
||||
|
||||
"filenameRelative": {
|
||||
"hidden": true,
|
||||
"type": "string"
|
||||
},
|
||||
|
||||
"inputSourceMap": {
|
||||
"hidden": true
|
||||
},
|
||||
|
||||
"moduleId": {
|
||||
|
||||
},
|
||||
|
||||
"highlightErrors": {
|
||||
"description": "ANSI syntax highlight error messages"
|
||||
"type": "boolean",
|
||||
"default": true
|
||||
},
|
||||
|
||||
"suppressDeprecationMessages": {
|
||||
"type": "boolean",
|
||||
"default": false,
|
||||
"hidden": true
|
||||
},
|
||||
|
||||
"resolveModuleSource": {
|
||||
"hidden": true
|
||||
},
|
||||
|
||||
"experimental": {
|
||||
"description": "Enable all ES7+ transformers",
|
||||
"shorthand": "e",
|
||||
"type": "boolean",
|
||||
"default": false
|
||||
},
|
||||
|
||||
"playground": {
|
||||
"description": "Enable all playground transformers",
|
||||
"shorthand": "p",
|
||||
"type": "boolean",
|
||||
"default": false
|
||||
},
|
||||
|
||||
"blacklist": {
|
||||
"type": "transformerList",
|
||||
"description": "Blacklist of transformers to NOT use",
|
||||
"shorthand": "b"
|
||||
},
|
||||
|
||||
"whitelist": {
|
||||
"type": "transformerList",
|
||||
"description": "Whitelist of transformers to ONLY use",
|
||||
"shorthand": "l"
|
||||
},
|
||||
|
||||
"optional": {
|
||||
"type": "transformerList",
|
||||
"description": "List of optional transformers to enable"
|
||||
},
|
||||
|
||||
"modules": {
|
||||
"type": "string",
|
||||
"description": "Module formatter type to use [common]",
|
||||
"default": "common",
|
||||
"shorthand": "m"
|
||||
},
|
||||
|
||||
"moduleIds": {
|
||||
"type": "boolean",
|
||||
"default": false,
|
||||
"shorthand": "M"
|
||||
},
|
||||
|
||||
"loose": {
|
||||
"type": "transformerList",
|
||||
"description": "List of transformers to enable loose mode ON",
|
||||
"shorthand": "L"
|
||||
},
|
||||
|
||||
"ignore": {
|
||||
"type": "list"
|
||||
},
|
||||
|
||||
"only": {
|
||||
"type": "list"
|
||||
},
|
||||
|
||||
"code": {
|
||||
"hidden": true,
|
||||
"default": true,
|
||||
"type": "boolean"
|
||||
},
|
||||
|
||||
"ast": {
|
||||
"hidden": true,
|
||||
"default": true,
|
||||
"type": "boolean"
|
||||
},
|
||||
|
||||
"comments": {
|
||||
"type": "boolean",
|
||||
"default": true
|
||||
},
|
||||
|
||||
"compact": {
|
||||
"type": "string",
|
||||
"default": "auto"
|
||||
},
|
||||
|
||||
"keepModuleIdExtensions": {
|
||||
"type": "boolean",
|
||||
"description": "Keep extensions when generating module ids",
|
||||
"default": false,
|
||||
"shorthand": "k"
|
||||
},
|
||||
|
||||
"auxiliaryComment": {
|
||||
"type": "string",
|
||||
"default": "",
|
||||
"shorthand": "a"
|
||||
},
|
||||
|
||||
"externalHelpers": {
|
||||
"type": "string",
|
||||
"default": false,
|
||||
"shorthand": "r"
|
||||
},
|
||||
|
||||
"returnUsedHelpers": {
|
||||
"type": "boolean",
|
||||
"default": false,
|
||||
"hidden": true
|
||||
},
|
||||
|
||||
"sourceMap": {
|
||||
"type": "string",
|
||||
"default": false,
|
||||
"shorthand": "s"
|
||||
},
|
||||
|
||||
"sourceMapName": {
|
||||
"type": "string"
|
||||
},
|
||||
|
||||
"sourceFileName": {
|
||||
"type": "string"
|
||||
},
|
||||
|
||||
"sourceRoot": {
|
||||
"type": "string"
|
||||
},
|
||||
|
||||
"moduleRoot": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
@ -27,7 +27,7 @@ export default function (exports, opts) {
|
||||
};
|
||||
|
||||
exports.JSXNamespacedName = function (node, parent, scope, file) {
|
||||
throw file.errorWithNode(node, messages.get("JSXNamespacedTags"));
|
||||
throw this.errorWithNode(messages.get("JSXNamespacedTags"));
|
||||
};
|
||||
|
||||
exports.JSXMemberExpression = {
|
||||
|
||||
@ -39,7 +39,7 @@ var visitor = {
|
||||
|
||||
var callback = self.specHandle;
|
||||
if (self.isLoose) callback = self.looseHandle;
|
||||
return callback.call(self, getThisReference, node, parent);
|
||||
return callback.call(self, this, getThisReference);
|
||||
}
|
||||
};
|
||||
|
||||
@ -191,11 +191,12 @@ export default class ReplaceSupers {
|
||||
* Description
|
||||
*/
|
||||
|
||||
looseHandle(getThisReference: Function, node: Object, parent: Object) {
|
||||
if (t.isIdentifier(node, { name: "super" })) {
|
||||
looseHandle(path: TraversalPath, getThisReference: Function) {
|
||||
var node = path.node;
|
||||
if (path.isIdentifier({ name: "super" })) {
|
||||
this.hasSuper = true;
|
||||
return this.getLooseSuperProperty(node, parent);
|
||||
} else if (t.isCallExpression(node)) {
|
||||
return this.getLooseSuperProperty(node, path.parent);
|
||||
} else if (path.isCallExpression()) {
|
||||
var callee = node.callee;
|
||||
if (!t.isMemberExpression(callee)) return;
|
||||
if (callee.object.name !== "super") return;
|
||||
@ -211,15 +212,18 @@ export default class ReplaceSupers {
|
||||
* Description
|
||||
*/
|
||||
|
||||
specHandle(getThisReference: Function, node: Object, parent: Object) {
|
||||
specHandle(path: TraversalPath, getThisReference: Function) {
|
||||
var methodNode = this.methodNode;
|
||||
var property;
|
||||
var computed;
|
||||
var args;
|
||||
var thisReference;
|
||||
|
||||
var parent = path.parent;
|
||||
var node = path.node;
|
||||
|
||||
if (isIllegalBareSuper(node, parent)) {
|
||||
throw this.file.errorWithNode(node, messages.get("classesIllegalBareSuper"));
|
||||
throw path.errorWithNode(messages.get("classesIllegalBareSuper"));
|
||||
}
|
||||
|
||||
if (t.isCallExpression(node)) {
|
||||
|
||||
@ -4,7 +4,7 @@ import object from "../helpers/object";
|
||||
import File from "./file";
|
||||
import each from "lodash/collection/each";
|
||||
|
||||
export default function transform(code: code, opts?: Object) {
|
||||
export default function transform(code: string, opts?: Object) {
|
||||
var file = new File(opts);
|
||||
return file.parse(code);
|
||||
}
|
||||
|
||||
@ -45,7 +45,7 @@ var importsVisitor = {
|
||||
ImportDeclaration: {
|
||||
enter(node, parent, scope, formatter) {
|
||||
formatter.hasLocalImports = true;
|
||||
extend(formatter.localImports, t.getBindingIdentifiers(node));
|
||||
extend(formatter.localImports, this.getBindingIdentifiers());
|
||||
formatter.bumpImportOccurences(node);
|
||||
}
|
||||
}
|
||||
@ -54,11 +54,11 @@ var importsVisitor = {
|
||||
var exportsVisitor = {
|
||||
ExportDeclaration: {
|
||||
enter(node, parent, scope, formatter) {
|
||||
var declar = node.declaration;
|
||||
var declar = this.get("declaration");
|
||||
formatter.hasLocalImports = true;
|
||||
|
||||
if (declar && t.isStatement(declar)) {
|
||||
extend(formatter.localExports, t.getBindingIdentifiers(declar));
|
||||
if (declar.isStatement()) {
|
||||
extend(formatter.localExports, declar.getBindingIdentifiers());
|
||||
}
|
||||
|
||||
if (!node.default) {
|
||||
@ -105,16 +105,16 @@ export default class DefaultFormatter {
|
||||
}
|
||||
|
||||
getLocalExports() {
|
||||
this.file.scope.traverse(this.file.ast, exportsVisitor, this);
|
||||
this.file.path.traverse(exportsVisitor, this);
|
||||
}
|
||||
|
||||
getLocalImports() {
|
||||
this.file.scope.traverse(this.file.ast, importsVisitor, this);
|
||||
this.file.path.traverse(importsVisitor, this);
|
||||
}
|
||||
|
||||
remapAssignments() {
|
||||
if (this.hasLocalImports) {
|
||||
this.file.scope.traverse(this.file.ast, remapVisitor, this);
|
||||
this.file.path.traverse(remapVisitor, this);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
1
src/babel/transformation/templates/for-of-array.js
Normal file
1
src/babel/transformation/templates/for-of-array.js
Normal file
@ -0,0 +1 @@
|
||||
for (var KEY = 0; KEY < ARR.length; KEY++) BODY;
|
||||
@ -1,4 +1,5 @@
|
||||
import includes from "lodash/collection/includes";
|
||||
import traverse from "../traversal";
|
||||
|
||||
/**
|
||||
* This class is responsible for traversing over the provided `File`s
|
||||
@ -31,14 +32,14 @@ export default class TransformerPass {
|
||||
var whitelist = opts.whitelist;
|
||||
if (whitelist.length) return includes(whitelist, key);
|
||||
|
||||
// optional
|
||||
if (transformer.optional && !includes(opts.optional, key)) return false;
|
||||
|
||||
// experimental
|
||||
if (transformer.experimental && !opts.experimental) return false;
|
||||
if (transformer.experimental && opts.experimental) return true;
|
||||
|
||||
// playground
|
||||
if (transformer.playground && !opts.playground) return false;
|
||||
if (transformer.playground && opts.playground) return true;
|
||||
|
||||
// optional
|
||||
if (transformer.optional && !includes(opts.optional, key)) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -59,7 +60,7 @@ export default class TransformerPass {
|
||||
|
||||
file.log.debug(`Running transformer ${this.transformer.key}`);
|
||||
|
||||
file.scope.traverse(file.ast, this.handlers, file);
|
||||
traverse(file.ast, this.handlers, file.scope, file);
|
||||
|
||||
this.ran = true;
|
||||
}
|
||||
|
||||
@ -3,6 +3,7 @@ import isFunction from "lodash/lang/isFunction";
|
||||
import traverse from "../traversal";
|
||||
import isObject from "lodash/lang/isObject";
|
||||
import assign from "lodash/object/assign";
|
||||
import File from "./file";
|
||||
import each from "lodash/collection/each";
|
||||
|
||||
/**
|
||||
@ -66,6 +67,10 @@ export default class Transformer {
|
||||
}
|
||||
|
||||
buildPass(file: File): TransformerPass {
|
||||
if (!(file instanceof File)) {
|
||||
throw new Error("Multiple versions of babel are interacting, this is either due to a version mismatch in a plugin or it was resolved incorrectly");
|
||||
}
|
||||
|
||||
return new TransformerPass(file, this);
|
||||
}
|
||||
}
|
||||
|
||||
@ -32,7 +32,7 @@ export function BlockStatement(node, parent, scope, file) {
|
||||
var letRefs = node._letReferences;
|
||||
if (!letRefs) return;
|
||||
|
||||
scope.traverse(node, visitor, {
|
||||
this.traverse(visitor, {
|
||||
letRefs: letRefs,
|
||||
file: file
|
||||
});
|
||||
|
||||
@ -111,7 +111,7 @@ function traverseReplace(node, parent, scope, remaps) {
|
||||
var letReferenceBlockVisitor = {
|
||||
enter(node, parent, scope, state) {
|
||||
if (this.isFunction()) {
|
||||
scope.traverse(node, letReferenceFunctionVisitor, state);
|
||||
this.traverse(letReferenceFunctionVisitor, state);
|
||||
return this.skip();
|
||||
}
|
||||
}
|
||||
@ -173,7 +173,7 @@ var loopVisitor = {
|
||||
|
||||
if (this.isLoop()) {
|
||||
state.ignoreLabeless = true;
|
||||
scope.traverse(node, loopVisitor, state);
|
||||
this.traverse(loopVisitor, state);
|
||||
state.ignoreLabeless = false;
|
||||
}
|
||||
|
||||
|
||||
@ -15,7 +15,7 @@ export function ClassDeclaration(node, parent, scope, file) {
|
||||
}
|
||||
|
||||
export function ClassExpression(node, parent, scope, file) {
|
||||
return new ClassTransformer(node, parent, scope, file).run();
|
||||
return new ClassTransformer(this, file).run();
|
||||
}
|
||||
|
||||
var verifyConstructorVisitor = traverse.explode({
|
||||
@ -33,11 +33,11 @@ var verifyConstructorVisitor = traverse.explode({
|
||||
|
||||
CallExpression: {
|
||||
enter(node, parent, scope, state) {
|
||||
if (t.isIdentifier(node.callee, { name: "super" })) {
|
||||
if (this.get("callee").isIdentifier({ name: "super" })) {
|
||||
state.hasBareSuper = true;
|
||||
|
||||
if (!state.hasSuper) {
|
||||
throw state.file.errorWithNode(node, "super call is only allowed in derived constructor");
|
||||
throw this.errorWithNode("super call is only allowed in derived constructor");
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -46,7 +46,7 @@ var verifyConstructorVisitor = traverse.explode({
|
||||
ThisExpression: {
|
||||
enter(node, parent, scope, state) {
|
||||
if (state.hasSuper && !state.hasBareSuper) {
|
||||
throw state.file.errorWithNode(node, "'this' is not allowed before super()");
|
||||
throw this.errorWithNode("'this' is not allowed before super()");
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -58,10 +58,11 @@ class ClassTransformer {
|
||||
* Description
|
||||
*/
|
||||
|
||||
constructor(node: Object, parent: Object, scope: Scope, file: File) {
|
||||
this.parent = parent;
|
||||
this.scope = scope;
|
||||
this.node = node;
|
||||
constructor(path: TraversalPath, file: File) {
|
||||
this.parent = path.parent;
|
||||
this.scope = path.scope;
|
||||
this.node = path.node;
|
||||
this.path = path;
|
||||
this.file = file;
|
||||
|
||||
this.hasInstanceMutators = false;
|
||||
@ -71,11 +72,11 @@ class ClassTransformer {
|
||||
this.staticMutatorMap = {};
|
||||
|
||||
this.hasConstructor = false;
|
||||
this.className = node.id;
|
||||
this.classRef = node.id || scope.generateUidIdentifier("class");
|
||||
this.className = this.node.id;
|
||||
this.classRef = this.node.id || this.scope.generateUidIdentifier("class");
|
||||
|
||||
this.superName = node.superClass || t.identifier("Function");
|
||||
this.hasSuper = !!node.superClass;
|
||||
this.superName = this.node.superClass || t.identifier("Function");
|
||||
this.hasSuper = !!this.node.superClass;
|
||||
|
||||
this.isLoose = file.isLoose("es6.classes");
|
||||
}
|
||||
@ -174,11 +175,13 @@ class ClassTransformer {
|
||||
var classBody = this.node.body.body;
|
||||
var body = this.body;
|
||||
|
||||
var classBodyPaths = this.path.get("body").get("body");
|
||||
|
||||
for (var i = 0; i < classBody.length; i++) {
|
||||
var node = classBody[i];
|
||||
if (t.isMethodDefinition(node)) {
|
||||
var isConstructor = (!node.computed && t.isIdentifier(node.key, { name: "constructor" })) || t.isLiteral(node.key, { value: "constructor" });
|
||||
if (isConstructor) this.verifyConstructor(node);
|
||||
if (isConstructor) this.verifyConstructor(classBodyPaths[i]);
|
||||
|
||||
var replaceSupers = new ReplaceSupers({
|
||||
methodNode: node,
|
||||
@ -205,8 +208,8 @@ class ClassTransformer {
|
||||
}
|
||||
}
|
||||
|
||||
// we have no constructor, we have a super, and the super doesn't appear to be falsy
|
||||
if (!this.hasConstructor && this.hasSuper && t.evaluateTruthy(superName, this.scope) !== false) {
|
||||
// we have no constructor, but we're a derived class
|
||||
if (!this.hasConstructor && this.hasSuper) {
|
||||
var helperName = "class-super-constructor-call";
|
||||
if (this.isLoose) helperName += "-loose";
|
||||
constructor.body.body.push(util.template(helperName, {
|
||||
@ -249,19 +252,17 @@ class ClassTransformer {
|
||||
* Description
|
||||
*/
|
||||
|
||||
verifyConstructor(node: Object) {
|
||||
return; // enable this for the next major
|
||||
|
||||
verifyConstructor(path: TraversalPath) {
|
||||
var state = {
|
||||
hasBareSuper: false,
|
||||
hasSuper: this.hasSuper,
|
||||
file: this.file
|
||||
};
|
||||
|
||||
traverse(node, verifyConstructorVisitor, this.scope, state);
|
||||
path.traverse(verifyConstructorVisitor, state);
|
||||
|
||||
if (!state.hasBareSuper && this.hasSuper) {
|
||||
throw this.file.errorWithNode(node, "Derived constructor must call super()");
|
||||
throw path.errorWithNode("Derived constructor must call super()");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -37,7 +37,7 @@ var visitor = {
|
||||
};
|
||||
|
||||
export function Scopable(node, parent, scope, file) {
|
||||
scope.traverse(node, visitor, {
|
||||
this.traverse(visitor, {
|
||||
constants: scope.getAllBindingsOfKind("const"),
|
||||
file: file
|
||||
});
|
||||
|
||||
@ -432,7 +432,7 @@ class DestructuringTransformer {
|
||||
} else {
|
||||
arrayRef = this.scope.generateUidBasedOnNode(arrayRef);
|
||||
this.nodes.push(this.buildVariableDeclaration(arrayRef, toArray));
|
||||
this.scope.assignTypeGeneric(arrayRef.name, "Array");
|
||||
//this.getBinding(arrayRef.name).assignTypeGeneric("Array");
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
@ -5,6 +5,10 @@ import * as t from "../../../types";
|
||||
export var check = t.isForOfStatement;
|
||||
|
||||
export function ForOfStatement(node, parent, scope, file) {
|
||||
if (this.get("right").isArrayExpression()) {
|
||||
return _ForOfStatementArray.call(this, node, scope, file);
|
||||
}
|
||||
|
||||
var callback = spec;
|
||||
if (file.isLoose("es6.forOf")) callback = loose;
|
||||
|
||||
@ -29,13 +33,48 @@ export function ForOfStatement(node, parent, scope, file) {
|
||||
|
||||
t.inherits(loop, node);
|
||||
|
||||
// todo: find out why this is necessary? #538
|
||||
loop._scopeInfo = node._scopeInfo;
|
||||
|
||||
if (build.replaceParent) this.parentPath.node = build.node;
|
||||
return build.node;
|
||||
}
|
||||
|
||||
export function _ForOfStatementArray(node, scope, file) {
|
||||
var nodes = [];
|
||||
var right = node.right;
|
||||
|
||||
if (!t.isIdentifier(right) || !scope.hasBinding(right.name)) {
|
||||
var uid = scope.generateUidIdentifier("arr");
|
||||
nodes.push(t.variableDeclaration("var", [
|
||||
t.variableDeclarator(uid, right)
|
||||
]));
|
||||
right = uid;
|
||||
}
|
||||
|
||||
var iterationKey = scope.generateUidIdentifier("i");
|
||||
|
||||
var loop = util.template("for-of-array", {
|
||||
BODY: node.body,
|
||||
KEY: iterationKey,
|
||||
ARR: right
|
||||
});
|
||||
|
||||
t.inherits(loop, node);
|
||||
t.ensureBlock(loop);
|
||||
|
||||
var iterationValue = t.memberExpression(right, iterationKey, true);
|
||||
|
||||
var left = node.left;
|
||||
if (t.isVariableDeclaration(left)) {
|
||||
left.declarations[0].init = iterationValue;
|
||||
loop.body.body.unshift(left);
|
||||
} else {
|
||||
loop.body.body.unshift(t.expressionStatement(t.assignmentExpression("=", left, iterationValue)));
|
||||
}
|
||||
|
||||
nodes.push(loop);
|
||||
|
||||
return nodes;
|
||||
}
|
||||
|
||||
var loose = function (node, parent, scope, file) {
|
||||
var left = node.left;
|
||||
var declar, id;
|
||||
|
||||
@ -26,7 +26,7 @@ export function ImportDeclaration(node, parent, scope, file) {
|
||||
|
||||
export function ExportDeclaration(node, parent, scope, file) {
|
||||
// flow type
|
||||
if (t.isTypeAlias(node.declaration)) return;
|
||||
if (this.get("declaration").isTypeAlias()) return;
|
||||
|
||||
var nodes = [];
|
||||
var i;
|
||||
|
||||
@ -49,41 +49,42 @@ exports.Function = function (node, parent, scope, file) {
|
||||
body.push(defNode);
|
||||
};
|
||||
|
||||
for (var i = 0; i < node.params.length; i++) {
|
||||
var param = node.params[i];
|
||||
var params = this.get("params");
|
||||
for (var i = 0; i < params.length; i++) {
|
||||
var param = params[i];
|
||||
|
||||
if (!t.isAssignmentPattern(param)) {
|
||||
if (!t.isRestElement(param)) {
|
||||
if (!param.isAssignmentPattern()) {
|
||||
if (!param.isRestElement()) {
|
||||
lastNonDefaultParam = i + 1;
|
||||
}
|
||||
|
||||
if (!t.isIdentifier(param)) {
|
||||
scope.traverse(param, iifeVisitor, state);
|
||||
if (!param.isIdentifier()) {
|
||||
param.traverse(iifeVisitor, state);
|
||||
}
|
||||
|
||||
if (file.transformers["es6.blockScopingTDZ"].canRun() && t.isIdentifier(param)) {
|
||||
pushDefNode(param, t.identifier("undefined"), i);
|
||||
if (file.transformers["es6.blockScopingTDZ"].canRun() && param.isIdentifier()) {
|
||||
pushDefNode(param.node, t.identifier("undefined"), i);
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
var left = param.left;
|
||||
var right = param.right;
|
||||
var left = param.get("left");
|
||||
var right = param.get("right");
|
||||
|
||||
var placeholder = scope.generateUidIdentifier("x");
|
||||
placeholder._isDefaultPlaceholder = true;
|
||||
node.params[i] = placeholder;
|
||||
|
||||
if (!state.iife) {
|
||||
if (t.isIdentifier(right) && scope.hasOwnBinding(right.name)) {
|
||||
if (right.isIdentifier() && scope.hasOwnBinding(right.node.name)) {
|
||||
state.iife = true;
|
||||
} else {
|
||||
scope.traverse(right, iifeVisitor, state);
|
||||
right.traverse(iifeVisitor, state);
|
||||
}
|
||||
}
|
||||
|
||||
pushDefNode(left, right, i);
|
||||
pushDefNode(left.node, right.node, i);
|
||||
}
|
||||
|
||||
// we need to cut off all trailing default parameters
|
||||
|
||||
@ -15,7 +15,7 @@ var memberExpressionOptimisationVisitor = {
|
||||
// to the wrong function
|
||||
if (this.isFunctionDeclaration() || this.isFunctionExpression()) {
|
||||
state.noOptimise = true;
|
||||
scope.traverse(node, memberExpressionOptimisationVisitor, state);
|
||||
this.traverse(memberExpressionOptimisationVisitor, state);
|
||||
state.noOptimise = false;
|
||||
return this.skip();
|
||||
}
|
||||
@ -88,7 +88,7 @@ exports.Function = function (node, parent, scope, file) {
|
||||
name: rest.name
|
||||
};
|
||||
|
||||
scope.traverse(node, memberExpressionOptimisationVisitor, state);
|
||||
this.traverse(memberExpressionOptimisationVisitor, state);
|
||||
|
||||
// we only have shorthands and there's no other references
|
||||
if (state.canOptimise && state.candidates.length) {
|
||||
@ -127,16 +127,14 @@ exports.Function = function (node, parent, scope, file) {
|
||||
);
|
||||
}
|
||||
|
||||
scope.assignTypeGeneric(rest.name, "Array");
|
||||
|
||||
var loop = util.template("rest", {
|
||||
ARGUMENTS: argsId,
|
||||
ARRAY_KEY: arrKey,
|
||||
ARRAY_LEN: arrLen,
|
||||
START: start,
|
||||
ARRAY: rest,
|
||||
KEY: key,
|
||||
LEN: len,
|
||||
START: start,
|
||||
ARRAY: rest,
|
||||
KEY: key,
|
||||
LEN: len
|
||||
});
|
||||
loop._blockHoist = node.params.length + 1;
|
||||
node.body.body.unshift(loop);
|
||||
|
||||
@ -81,7 +81,7 @@ export function CallExpression(node, parent, scope) {
|
||||
|
||||
var callee = node.callee;
|
||||
|
||||
if (t.isMemberExpression(callee)) {
|
||||
if (this.get("callee").isMemberExpression()) {
|
||||
var temp = scope.generateTempBasedOnNode(callee.object);
|
||||
if (temp) {
|
||||
callee.object = t.assignmentExpression("=", temp, callee.object);
|
||||
@ -101,7 +101,7 @@ export function NewExpression(node, parent, scope, file) {
|
||||
var args = node.arguments;
|
||||
if (!hasSpread(args)) return;
|
||||
|
||||
var nativeType = t.isIdentifier(node.callee) && includes(t.NATIVE_TYPE_NAMES, node.callee.name);
|
||||
var nativeType = this.get("callee").isIdentifier() && includes(t.NATIVE_TYPE_NAMES, node.callee.name);
|
||||
|
||||
var nodes = build(args, scope);
|
||||
|
||||
|
||||
@ -7,7 +7,7 @@ export function UnaryExpression(node, parent, scope, file) {
|
||||
|
||||
if (node.operator === "typeof") {
|
||||
var call = t.callExpression(file.addHelper("typeof"), [node.argument]);
|
||||
if (t.isIdentifier(node.argument)) {
|
||||
if (this.get("argument").isIdentifier()) {
|
||||
var undefLiteral = t.literal("undefined");
|
||||
return t.conditionalExpression(
|
||||
t.binaryExpression("===", t.unaryExpression("typeof", node.argument), undefLiteral),
|
||||
|
||||
@ -6,7 +6,7 @@ import map from "lodash/collection/map";
|
||||
import * as t from "../../../types";
|
||||
|
||||
exports.Function = function (node, parent, scope, file) {
|
||||
var tailCall = new TailCallTransformer(node, scope, file);
|
||||
var tailCall = new TailCallTransformer(this, scope, file);
|
||||
tailCall.run();
|
||||
};
|
||||
|
||||
@ -18,11 +18,11 @@ function returnBlock(expr) {
|
||||
var firstPass = {
|
||||
enter(node, parent, scope, state) {
|
||||
if (this.isIfStatement()) {
|
||||
if (t.isReturnStatement(node.alternate)) {
|
||||
if (this.get("alternate").isReturnStatement()) {
|
||||
t.ensureBlock(node, "alternate");
|
||||
}
|
||||
|
||||
if (t.isReturnStatement(node.consequent)) {
|
||||
if (this.get("consequent").isReturnStatement()) {
|
||||
t.ensureBlock(node, "consequent");
|
||||
}
|
||||
} else if (this.isReturnStatement()) {
|
||||
@ -85,17 +85,18 @@ var thirdPass = {
|
||||
};
|
||||
|
||||
class TailCallTransformer {
|
||||
constructor(node, scope, file) {
|
||||
constructor(path, scope, file) {
|
||||
this.hasTailRecursion = false;
|
||||
this.needsArguments = false;
|
||||
this.setsArguments = false;
|
||||
this.needsThis = false;
|
||||
this.ownerId = node.id;
|
||||
this.ownerId = path.node.id;
|
||||
this.vars = [];
|
||||
|
||||
this.scope = scope;
|
||||
this.path = path;
|
||||
this.file = file;
|
||||
this.node = node;
|
||||
this.node = path.node;
|
||||
}
|
||||
|
||||
getArgumentsId() {
|
||||
@ -142,8 +143,8 @@ class TailCallTransformer {
|
||||
hasDeopt() {
|
||||
// check if the ownerId has been reassigned, if it has then it's not safe to
|
||||
// perform optimisations
|
||||
var ownerIdInfo = this.scope.getBindingInfo(this.ownerId.name);
|
||||
return ownerIdInfo && ownerIdInfo.reassigned;
|
||||
var ownerIdInfo = this.scope.getBinding(this.ownerId.name);
|
||||
return ownerIdInfo && !ownerIdInfo.constant;
|
||||
}
|
||||
|
||||
run() {
|
||||
@ -156,7 +157,7 @@ class TailCallTransformer {
|
||||
if (!ownerId) return;
|
||||
|
||||
// traverse the function and look for tail recursion
|
||||
scope.traverse(node, firstPass, this);
|
||||
this.path.traverse(firstPass, this);
|
||||
|
||||
if (!this.hasTailRecursion) return;
|
||||
|
||||
@ -167,10 +168,10 @@ class TailCallTransformer {
|
||||
|
||||
//
|
||||
|
||||
scope.traverse(node, secondPass, this);
|
||||
this.path.traverse(secondPass, this);
|
||||
|
||||
if (!this.needsThis || !this.needsArguments) {
|
||||
scope.traverse(node, thirdPass, this);
|
||||
this.path.traverse(thirdPass, this);
|
||||
}
|
||||
|
||||
var body = t.ensureBlock(node).body;
|
||||
|
||||
@ -9,11 +9,11 @@ export function check(node) {
|
||||
}
|
||||
|
||||
export function TaggedTemplateExpression(node, parent, scope, file) {
|
||||
var args = [];
|
||||
var quasi = node.quasi;
|
||||
var args = [];
|
||||
|
||||
var strings = [];
|
||||
var raw = [];
|
||||
var raw = [];
|
||||
|
||||
for (var i = 0; i < quasi.quasis.length; i++) {
|
||||
var elem = quasi.quasis[i];
|
||||
|
||||
@ -4,6 +4,7 @@ import * as util from "../../../util";
|
||||
import * as t from "../../../types";
|
||||
|
||||
export var experimental = true;
|
||||
export var optional = true;
|
||||
|
||||
var container = function (parent, call, ret, file) {
|
||||
if (t.isExpressionStatement(parent) && !file.isConsequenceExpressionStatement(parent)) {
|
||||
|
||||
@ -4,6 +4,7 @@ import * as util from "../../../util";
|
||||
import * as t from "../../../types";
|
||||
|
||||
export var experimental = true;
|
||||
export var optional = true;
|
||||
|
||||
export function ComprehensionExpression(node, parent, scope, file) {
|
||||
var callback = array;
|
||||
|
||||
@ -4,6 +4,7 @@ import build from "../../helpers/build-binary-assignment-operator-transformer";
|
||||
import * as t from "../../../types";
|
||||
|
||||
export var experimental = true;
|
||||
export var optional = true;
|
||||
|
||||
var MATH_POW = t.memberExpression(t.identifier("Math"), t.identifier("pow"));
|
||||
|
||||
|
||||
@ -3,6 +3,7 @@
|
||||
import * as t from "../../../types";
|
||||
|
||||
export var experimental = true;
|
||||
export var optional = true;
|
||||
|
||||
export function manipulateOptions(opts) {
|
||||
if (opts.whitelist.length) opts.whitelist.push("es6.destructuring");
|
||||
|
||||
@ -20,7 +20,6 @@ export default {
|
||||
"playground.objectGetterMemoization": require("./playground/object-getter-memoization"),
|
||||
|
||||
reactCompat: require("./other/react-compat"),
|
||||
flow: require("./other/flow"),
|
||||
react: require("./other/react"),
|
||||
|
||||
_modules: require("./internal/modules"),
|
||||
@ -45,6 +44,7 @@ export default {
|
||||
// needs to be before `_aliasFunction` due to define property closure
|
||||
"es6.properties.computed": require("./es6/properties.computed"),
|
||||
|
||||
"optimisation.es6.forOf": require("./optimisation/flow.for-of"),
|
||||
"es6.forOf": require("./es6/for-of"),
|
||||
|
||||
"es6.regex.sticky": require("./es6/regex.sticky"),
|
||||
@ -110,5 +110,6 @@ export default {
|
||||
"utility.inlineExpressions": require("./utility/inline-expressions"),
|
||||
"utility.deadCodeElimination": require("./utility/dead-code-elimination"),
|
||||
|
||||
flow: require("./other/flow"),
|
||||
_cleanUp: require("./internal/cleanup")
|
||||
};
|
||||
|
||||
@ -34,13 +34,13 @@ var functionVisitor = {
|
||||
}
|
||||
|
||||
// traverse all child nodes of this function and find `arguments` and `this`
|
||||
scope.traverse(node, functionChildrenVisitor, state);
|
||||
this.traverse(functionChildrenVisitor, state);
|
||||
|
||||
return this.skip();
|
||||
}
|
||||
};
|
||||
|
||||
var go = function (getBody, node, scope) {
|
||||
function aliasFunction(getBody, path, scope) {
|
||||
var argumentsId;
|
||||
var thisId;
|
||||
|
||||
@ -56,7 +56,7 @@ var go = function (getBody, node, scope) {
|
||||
|
||||
// traverse the function and find all alias functions so we can alias
|
||||
// `arguments` and `this` if necessary
|
||||
scope.traverse(node, functionVisitor, state);
|
||||
path.traverse(functionVisitor, state);
|
||||
|
||||
var body;
|
||||
|
||||
@ -77,16 +77,16 @@ var go = function (getBody, node, scope) {
|
||||
};
|
||||
|
||||
export function Program(node, parent, scope) {
|
||||
go(function () {
|
||||
aliasFunction(function () {
|
||||
return node.body;
|
||||
}, node, scope);
|
||||
}, this, scope);
|
||||
};
|
||||
|
||||
export function FunctionDeclaration(node, parent, scope) {
|
||||
go(function () {
|
||||
aliasFunction(function () {
|
||||
t.ensureBlock(node);
|
||||
return node.body.body;
|
||||
}, node, scope);
|
||||
}, this, scope);
|
||||
}
|
||||
|
||||
export { FunctionDeclaration as FunctionExpression };
|
||||
|
||||
@ -50,7 +50,12 @@ export function ExportDeclaration(node, parent, scope) {
|
||||
return [getDeclar(), node];
|
||||
}
|
||||
} else {
|
||||
if (t.isFunctionDeclaration(declar)) {
|
||||
if (t.isClassDeclaration(declar)) {
|
||||
// export class Foo {}
|
||||
node.specifiers = [t.importSpecifier(declar.id, declar.id)];
|
||||
node.declaration = null;
|
||||
return [getDeclar(), node];
|
||||
} else if (t.isFunctionDeclaration(declar)) {
|
||||
// export function Foo() {}
|
||||
node.specifiers = [t.importSpecifier(declar.id, declar.id)];
|
||||
node.declaration = null;
|
||||
@ -59,7 +64,7 @@ export function ExportDeclaration(node, parent, scope) {
|
||||
} else if (t.isVariableDeclaration(declar)) {
|
||||
// export var foo = "bar";
|
||||
var specifiers = [];
|
||||
var bindings = t.getBindingIdentifiers(declar);
|
||||
var bindings = this.get("declaration").getBindingIdentifiers();
|
||||
for (var key in bindings) {
|
||||
var id = bindings[key];
|
||||
specifiers.push(t.exportSpecifier(id, id));
|
||||
|
||||
@ -0,0 +1,11 @@
|
||||
import { _ForOfStatementArray } from "../es6/for-of";
|
||||
import * as t from "../../../types";
|
||||
|
||||
export var check = t.isForOfStatement;
|
||||
export var optional = true;
|
||||
|
||||
export function ForOfStatement(node, parent, scope, file) {
|
||||
if (this.get("right").isTypeGeneric("Array")) {
|
||||
return _ForOfStatementArray.call(this, node, scope, file);
|
||||
}
|
||||
}
|
||||
@ -29,5 +29,5 @@ export function ImportDeclaration(node) {
|
||||
}
|
||||
|
||||
export function ExportDeclaration(node) {
|
||||
if (t.isTypeAlias(node.declaration)) this.remove();
|
||||
if (this.get("declaration").isTypeAlias()) this.remove();
|
||||
}
|
||||
|
||||
@ -4,7 +4,7 @@ import core from "core-js/library";
|
||||
import has from "lodash/object/has";
|
||||
import * as t from "../../../types";
|
||||
|
||||
var isSymboliterator = t.buildMatchMemberExpression("Symbol.iterator");
|
||||
var isSymbolIterator = t.buildMatchMemberExpression("Symbol.iterator");
|
||||
|
||||
var coreHas = function (node) {
|
||||
return node.name !== "_" && has(core, node.name);
|
||||
@ -47,7 +47,7 @@ var astVisitor = {
|
||||
if (!callee.computed) return false;
|
||||
|
||||
prop = callee.property;
|
||||
if (!isSymboliterator(prop)) return false;
|
||||
if (!isSymbolIterator(prop)) return false;
|
||||
|
||||
return util.template("corejs-iterator", {
|
||||
CORE_ID: file.get("coreIdentifier"),
|
||||
@ -59,7 +59,7 @@ var astVisitor = {
|
||||
if (node.operator !== "in") return;
|
||||
|
||||
var left = node.left;
|
||||
if (!isSymboliterator(left)) return;
|
||||
if (!isSymbolIterator(left)) return;
|
||||
|
||||
return util.template("corejs-is-iterator", {
|
||||
CORE_ID: file.get("coreIdentifier"),
|
||||
@ -76,7 +76,7 @@ export function manipulateOptions(opts) {
|
||||
}
|
||||
|
||||
export function Program(node, parent, scope, file) {
|
||||
scope.traverse(node, astVisitor, file);
|
||||
this.traverse(astVisitor, file);
|
||||
}
|
||||
|
||||
export function pre(file) {
|
||||
|
||||
@ -3,6 +3,7 @@ import build from "../../helpers/build-conditional-assignment-operator-transform
|
||||
import * as t from "../../../types";
|
||||
|
||||
export var playground = true;
|
||||
export var optional = true;
|
||||
|
||||
build(exports, {
|
||||
is(node, file) {
|
||||
|
||||
@ -2,6 +2,7 @@ import build from "../../helpers/build-conditional-assignment-operator-transform
|
||||
import * as t from "../../../types";
|
||||
|
||||
export var playground = true;
|
||||
export var optional = true;
|
||||
|
||||
build(exports, {
|
||||
is(node) {
|
||||
|
||||
@ -1,9 +1,10 @@
|
||||
import * as t from "../../../types";
|
||||
|
||||
export var playground = true;
|
||||
export var optional = true;
|
||||
|
||||
export function BindMemberExpression(node, parent, scope) {
|
||||
console.error("Method binding is deprecated and will be removed in 5.0.0");
|
||||
export function BindMemberExpression(node, parent, scope, file) {
|
||||
file.log.deprecate("Method binding is deprecated and will be removed in 5.0.0");
|
||||
|
||||
var object = node.object;
|
||||
var prop = node.property;
|
||||
@ -26,8 +27,8 @@ export function BindMemberExpression(node, parent, scope) {
|
||||
}
|
||||
}
|
||||
|
||||
export function BindFunctionExpression(node, parent, scope) {
|
||||
console.error("Method binding is deprecated and will be removed in 5.0.0");
|
||||
export function BindFunctionExpression(node, parent, scope, file) {
|
||||
file.log.deprecate("Method binding is deprecated and will be removed in 5.0.0");
|
||||
|
||||
var buildCall = function (args) {
|
||||
var param = scope.generateUidIdentifier("val");
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
import * as t from "../../../types";
|
||||
|
||||
export var playground = true;
|
||||
export var optional = true;
|
||||
|
||||
var visitor = {
|
||||
enter(node, parent, scope, state) {
|
||||
@ -20,10 +21,9 @@ export function MethodDefinition(node, parent, scope, file) {
|
||||
if (node.kind !== "memo") return;
|
||||
node.kind = "get";
|
||||
|
||||
console.error("Object getter memoization is deprecated and will be removed in 5.0.0");
|
||||
file.log.deprecate("Object getter memoization is deprecated and will be removed in 5.0.0");
|
||||
|
||||
var value = node.value;
|
||||
t.ensureBlock(value);
|
||||
t.ensureBlock(node.value);
|
||||
|
||||
var key = node.key;
|
||||
|
||||
@ -36,7 +36,7 @@ export function MethodDefinition(node, parent, scope, file) {
|
||||
file: file
|
||||
};
|
||||
|
||||
scope.traverse(value, visitor, state);
|
||||
this.get("value").traverse(visitor, state);
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
@ -20,7 +20,7 @@ function toStatements(node) {
|
||||
export var optional = true;
|
||||
|
||||
export function ConditionalExpression(node, parent, scope) {
|
||||
var evaluateTest = t.evaluateTruthy(node.test, scope);
|
||||
var evaluateTest = this.get("test").evaluateTruthy();
|
||||
if (evaluateTest === true) {
|
||||
return node.consequent;
|
||||
} else if (evaluateTest === false) {
|
||||
@ -32,9 +32,8 @@ export var IfStatement = {
|
||||
exit(node, parent, scope) {
|
||||
var consequent = node.consequent;
|
||||
var alternate = node.alternate;
|
||||
var test = node.test;
|
||||
|
||||
var evaluateTest = t.evaluateTruthy(test, scope);
|
||||
var evaluateTest = this.get("test").evaluateTruthy();
|
||||
|
||||
// we can check if a test will be truthy 100% and if so then we can inline
|
||||
// the consequent and completely ignore the alternate
|
||||
|
||||
@ -6,7 +6,7 @@ var match = t.buildMatchMemberExpression("process.env");
|
||||
|
||||
export function MemberExpression(node) {
|
||||
if (match(node.object)) {
|
||||
var key = t.toComputedKey(node, node.property);
|
||||
var key = this.toComputedKey();
|
||||
if (t.isLiteral(key)) {
|
||||
return t.valueToNode(process.env[key.value]);
|
||||
}
|
||||
|
||||
@ -3,7 +3,7 @@ import * as t from "../../../types";
|
||||
export var optional = true;
|
||||
|
||||
export function Expression(node, parent, scope) {
|
||||
var res = t.evaluate(node, scope);
|
||||
var res = this.evaluate();
|
||||
if (res.confident) return t.valueToNode(res.value);
|
||||
}
|
||||
|
||||
|
||||
@ -1,11 +1,9 @@
|
||||
import * as t from "../../../types";
|
||||
|
||||
var isConsole = t.buildMatchMemberExpression("console", true);
|
||||
|
||||
export var optional = true;
|
||||
|
||||
export function CallExpression(node, parent) {
|
||||
if (isConsole(node.callee)) {
|
||||
if (this.get("callee").matchesPattern("console", true)) {
|
||||
if (t.isExpressionStatement(parent)) {
|
||||
this.parentPath.remove();
|
||||
} else {
|
||||
|
||||
@ -14,7 +14,7 @@ function check(source, file) {
|
||||
}
|
||||
|
||||
export function CallExpression(node, parent, scope, file) {
|
||||
if (t.isIdentifier(node.callee, { name: "require" }) && node.arguments.length === 1) {
|
||||
if (this.get("callee").isIdentifier({ name: "require" }) && node.arguments.length === 1) {
|
||||
check(node.arguments[0], file);
|
||||
}
|
||||
}
|
||||
|
||||
68
src/babel/traversal/binding.js
Normal file
68
src/babel/traversal/binding.js
Normal file
@ -0,0 +1,68 @@
|
||||
import * as t from "../types";
|
||||
|
||||
export default class Binding {
|
||||
constructor({ identifier, scope, path, kind }) {
|
||||
this.identifier = identifier;
|
||||
this.constant = true;
|
||||
this.scope = scope;
|
||||
this.path = path;
|
||||
this.kind = kind;
|
||||
}
|
||||
|
||||
/**
|
||||
* Description
|
||||
*/
|
||||
|
||||
setTypeAnnotation() {
|
||||
var typeInfo = this.path.getTypeAnnotation();
|
||||
this.typeAnnotationInferred = typeInfo.inferred;
|
||||
this.typeAnnotation = typeInfo.annotation;
|
||||
}
|
||||
|
||||
/**
|
||||
* Description
|
||||
*/
|
||||
|
||||
isTypeGeneric(): boolean {
|
||||
return this.path.isTypeGeneric(...arguments);
|
||||
}
|
||||
|
||||
/**
|
||||
* Description
|
||||
*/
|
||||
|
||||
assignTypeGeneric(type: Object, params?) {
|
||||
var typeParams = null;
|
||||
if (params) params = t.typeParameterInstantiation(params);
|
||||
this.assignType(t.genericTypeAnnotation(t.identifier(type), typeParams));
|
||||
}
|
||||
|
||||
/**
|
||||
* Description
|
||||
*/
|
||||
|
||||
assignType(type: Object) {
|
||||
this.typeAnnotation = type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Description
|
||||
*/
|
||||
|
||||
reassign() {
|
||||
this.constant = false;
|
||||
|
||||
if (this.typeAnnotationInferred) {
|
||||
// destroy the inferred typeAnnotation
|
||||
this.typeAnnotation = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Description
|
||||
*/
|
||||
|
||||
isCompatibleWithType(newType): boolean {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@ -1,10 +1,8 @@
|
||||
module.exports = traverse;
|
||||
|
||||
import TraversalContext from "./context";
|
||||
import includes from "lodash/collection/includes";
|
||||
import * as t from "../types";
|
||||
|
||||
function traverse(parent, opts, scope, state) {
|
||||
export default function traverse(parent, opts, scope, state, parentPath) {
|
||||
if (!parent) return;
|
||||
|
||||
if (!opts.noScope && !scope) {
|
||||
@ -20,10 +18,10 @@ function traverse(parent, opts, scope, state) {
|
||||
// array of nodes
|
||||
if (Array.isArray(parent)) {
|
||||
for (var i = 0; i < parent.length; i++) {
|
||||
traverse.node(parent[i], opts, scope, state);
|
||||
traverse.node(parent[i], opts, scope, state, parentPath);
|
||||
}
|
||||
} else {
|
||||
traverse.node(parent, opts, scope, state);
|
||||
traverse.node(parent, opts, scope, state, parentPath);
|
||||
}
|
||||
}
|
||||
|
||||
@ -42,7 +40,6 @@ traverse.node = function (node, opts, scope, state, parentPath) {
|
||||
function clearNode(node) {
|
||||
node._declarations = null;
|
||||
node.extendedRange = null;
|
||||
node._scopeInfo = null;
|
||||
node._paths = null;
|
||||
node.tokens = null;
|
||||
node.range = null;
|
||||
|
||||
@ -1,226 +0,0 @@
|
||||
import traverse from "./index";
|
||||
import includes from "lodash/collection/includes";
|
||||
import Scope from "./scope";
|
||||
import * as t from "../types";
|
||||
|
||||
export default class TraversalPath {
|
||||
constructor(parent, container) {
|
||||
this.container = container;
|
||||
this.parent = parent;
|
||||
this.data = {};
|
||||
}
|
||||
|
||||
static get(parentPath, context, parent, container, key) {
|
||||
var targetNode = container[key];
|
||||
var paths = container._paths ||= [];
|
||||
var path;
|
||||
|
||||
for (var i = 0; i < paths.length; i++) {
|
||||
var pathCheck = paths[i];
|
||||
if (pathCheck.node === targetNode) {
|
||||
path = pathCheck;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!path) {
|
||||
path = new TraversalPath(parent, container);
|
||||
paths.push(path);
|
||||
}
|
||||
|
||||
path.setContext(parentPath, context, key);
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
static getScope(node, parent, scope) {
|
||||
var ourScope = scope;
|
||||
|
||||
// we're entering a new scope so let's construct it!
|
||||
if (t.isScope(node, parent)) {
|
||||
ourScope = new Scope(node, parent, scope);
|
||||
}
|
||||
|
||||
return ourScope;
|
||||
}
|
||||
|
||||
insertBefore(node) {
|
||||
|
||||
}
|
||||
|
||||
insertAfter(node) {
|
||||
|
||||
}
|
||||
|
||||
setData(key, val) {
|
||||
return this.data[key] = val;
|
||||
}
|
||||
|
||||
getData(key) {
|
||||
return this.data[key];
|
||||
}
|
||||
|
||||
setScope() {
|
||||
this.scope = TraversalPath.getScope(this.node, this.parent, this.context.scope);
|
||||
}
|
||||
|
||||
setContext(parentPath, context, key) {
|
||||
this.shouldSkip = false;
|
||||
this.shouldStop = false;
|
||||
|
||||
this.parentPath = parentPath || this.parentPath;
|
||||
this.context = context;
|
||||
this.state = context.state;
|
||||
this.opts = context.opts;
|
||||
this.key = key;
|
||||
|
||||
this.setScope();
|
||||
}
|
||||
|
||||
remove() {
|
||||
this._refresh(this.node, []);
|
||||
this.container[this.key] = null;
|
||||
this.flatten();
|
||||
}
|
||||
|
||||
skip() {
|
||||
this.shouldSkip = true;
|
||||
}
|
||||
|
||||
stop() {
|
||||
this.shouldStop = true;
|
||||
this.shouldSkip = true;
|
||||
}
|
||||
|
||||
flatten() {
|
||||
this.context.flatten();
|
||||
}
|
||||
|
||||
_refresh(oldNode, newNodes) {
|
||||
// todo
|
||||
}
|
||||
|
||||
refresh() {
|
||||
var node = this.node;
|
||||
this._refresh(node, [node]);
|
||||
}
|
||||
|
||||
get node() {
|
||||
return this.container[this.key];
|
||||
}
|
||||
|
||||
set node(replacement) {
|
||||
if (!replacement) return this.remove();
|
||||
|
||||
var oldNode = this.node;
|
||||
var isArray = Array.isArray(replacement);
|
||||
var replacements = isArray ? replacement : [replacement];
|
||||
|
||||
// inherit comments from original node to the first replacement node
|
||||
var inheritTo = replacements[0];
|
||||
if (inheritTo) t.inheritsComments(inheritTo, oldNode);
|
||||
|
||||
// replace the node
|
||||
this.container[this.key] = replacement;
|
||||
|
||||
// potentially create new scope
|
||||
this.setScope();
|
||||
|
||||
// refresh scope with new/removed bindings
|
||||
this._refresh(oldNode, replacements);
|
||||
|
||||
var file = this.scope && this.scope.file;
|
||||
if (file) {
|
||||
for (var i = 0; i < replacements.length; i++) {
|
||||
file.checkNode(replacements[i], this.scope);
|
||||
}
|
||||
}
|
||||
|
||||
// we're replacing a statement or block node with an array of statements so we better
|
||||
// ensure that it's a block
|
||||
if (isArray) {
|
||||
if (includes(t.STATEMENT_OR_BLOCK_KEYS, this.key) && !t.isBlockStatement(this.container)) {
|
||||
t.ensureBlock(this.container, this.key);
|
||||
}
|
||||
|
||||
this.flatten();
|
||||
// TODO: duplicate internal path metadata across the new node paths
|
||||
}
|
||||
}
|
||||
|
||||
call(key) {
|
||||
var node = this.node;
|
||||
if (!node) return;
|
||||
|
||||
var opts = this.opts;
|
||||
var fn = opts[key] || opts;
|
||||
if (opts[node.type]) fn = opts[node.type][key] || fn;
|
||||
|
||||
var replacement = fn.call(this, node, this.parent, this.scope, this.state);
|
||||
|
||||
if (replacement) {
|
||||
this.node = replacement;
|
||||
}
|
||||
}
|
||||
|
||||
isBlacklisted() {
|
||||
var blacklist = this.opts.blacklist;
|
||||
return blacklist && blacklist.indexOf(this.node.type) > -1;
|
||||
}
|
||||
|
||||
visit() {
|
||||
if (this.isBlacklisted()) return false;
|
||||
|
||||
this.call("enter");
|
||||
|
||||
if (this.shouldSkip) {
|
||||
return this.shouldStop;
|
||||
}
|
||||
|
||||
var node = this.node;
|
||||
var opts = this.opts;
|
||||
|
||||
if (node) {
|
||||
if (Array.isArray(node)) {
|
||||
// traverse over these replacement nodes we purposely don't call exitNode
|
||||
// as the original node has been destroyed
|
||||
for (var i = 0; i < node.length; i++) {
|
||||
traverse.node(node[i], opts, this.scope, this.state, this);
|
||||
}
|
||||
} else {
|
||||
traverse.node(node, opts, this.scope, this.state, this);
|
||||
this.call("exit");
|
||||
}
|
||||
}
|
||||
|
||||
return this.shouldStop;
|
||||
}
|
||||
|
||||
get(key) {
|
||||
return TraversalPath.get(this, this.context, this.node, this.node, key);
|
||||
}
|
||||
|
||||
isReferencedIdentifier(opts) {
|
||||
return t.isReferencedIdentifier(this.node, this.parent, opts);
|
||||
}
|
||||
|
||||
isReferenced() {
|
||||
return t.isReferenced(this.node, this.parent);
|
||||
}
|
||||
|
||||
isScope() {
|
||||
return t.isScope(this.node, this.parent);
|
||||
}
|
||||
|
||||
getBindingIdentifiers() {
|
||||
return t.getBindingIdentifiers(this.node);
|
||||
}
|
||||
}
|
||||
|
||||
for (var i = 0; i < t.TYPES.length; i++) {
|
||||
let type = t.TYPES[i];
|
||||
let typeKey = `is${type}`;
|
||||
TraversalPath.prototype[typeKey] = function (opts) {
|
||||
return t[typeKey](this.node, opts);
|
||||
};
|
||||
}
|
||||
24
src/babel/traversal/path/conversion.js
Normal file
24
src/babel/traversal/path/conversion.js
Normal file
@ -0,0 +1,24 @@
|
||||
import * as t from "../../types";
|
||||
|
||||
/**
|
||||
* Description
|
||||
*/
|
||||
|
||||
export function toComputedKey(): Object {
|
||||
var node = this.node;
|
||||
|
||||
var key;
|
||||
if (this.isMemberExpression()) {
|
||||
key = node.property;
|
||||
} else if (this.isProperty()) {
|
||||
key = node.key;
|
||||
} else {
|
||||
throw new ReferenceError("todo");
|
||||
}
|
||||
|
||||
if (!node.computed) {
|
||||
if (t.isIdentifier(key)) key = t.literal(key.name);
|
||||
}
|
||||
|
||||
return key;
|
||||
}
|
||||
@ -1,5 +1,3 @@
|
||||
import * as t from "./index";
|
||||
|
||||
/**
|
||||
* Walk the input `node` and statically evaluate if it's truthy.
|
||||
*
|
||||
@ -18,15 +16,15 @@ import * as t from "./index";
|
||||
*
|
||||
*/
|
||||
|
||||
export function evaluateTruthy(node: Object, scope: Scope): boolean {
|
||||
var res = evaluate(node, scope);
|
||||
export function evaluateTruthy(): boolean {
|
||||
var res = this.evaluate();
|
||||
if (res.confident) return !!res.value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Walk the input `node` and statically evaluate it.
|
||||
*
|
||||
* Returns an pbject in the form `{ confident, value }`. `confident` indicates
|
||||
* Returns an object in the form `{ confident, value }`. `confident` indicates
|
||||
* whether or not we had to drop out of evaluating the expression because of
|
||||
* hitting an unknown node that we couldn't confidently find the value of.
|
||||
*
|
||||
@ -38,24 +36,27 @@ export function evaluateTruthy(node: Object, scope: Scope): boolean {
|
||||
*
|
||||
*/
|
||||
|
||||
export function evaluate(node: Object, scope: Scope): { confident: boolean; value: any } {
|
||||
export function evaluate(): { confident: boolean; value: any } {
|
||||
var confident = true;
|
||||
|
||||
var value = evaluate(node);
|
||||
var value = evaluate(this);
|
||||
if (!confident) value = undefined;
|
||||
return {
|
||||
confident: confident,
|
||||
value: value
|
||||
};
|
||||
|
||||
function evaluate(node) {
|
||||
function evaluate(path) {
|
||||
if (!confident) return;
|
||||
|
||||
if (t.isSequenceExpression(node)) {
|
||||
return evaluate(node.expressions[node.expressions.length - 1]);
|
||||
var node = path.node;
|
||||
|
||||
if (path.isSequenceExpression()) {
|
||||
var exprs = path.get("expressions");
|
||||
return evaluate(exprs[exprs.length - 1]);
|
||||
}
|
||||
|
||||
if (t.isLiteral(node)) {
|
||||
if (path.isLiteral()) {
|
||||
if (node.regex && node.value === null) {
|
||||
// we have a regex and we can't represent it natively
|
||||
} else {
|
||||
@ -63,24 +64,29 @@ export function evaluate(node: Object, scope: Scope): { confident: boolean; valu
|
||||
}
|
||||
}
|
||||
|
||||
if (t.isConditionalExpression(node)) {
|
||||
if (evaluate(node.test)) {
|
||||
return evaluate(node.consequent);
|
||||
if (path.isConditionalExpression()) {
|
||||
if (evaluate(path.get("test"))) {
|
||||
return evaluate(path.get("consequent"));
|
||||
} else {
|
||||
return evaluate(node.alternate);
|
||||
return evaluate(path.get("alternate"));
|
||||
}
|
||||
}
|
||||
|
||||
if (t.isIdentifier(node)) {
|
||||
if (node.name === "undefined") {
|
||||
return undefined;
|
||||
if (path.isIdentifier({ name: "undefined" })) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
if (path.isIdentifier() || path.isMemberExpression()) {
|
||||
path = path.resolve();
|
||||
if (path) {
|
||||
return evaluate(path);
|
||||
} else {
|
||||
return evaluate(scope.getImmutableBindingValue(node.name));
|
||||
return confident = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (t.isUnaryExpression(node, { prefix: true })) {
|
||||
var arg = evaluate(node.argument);
|
||||
if (path.isUnaryExpression({ prefix: true })) {
|
||||
var arg = evaluate(path.get("argument"));
|
||||
switch (node.operator) {
|
||||
case "void": return undefined;
|
||||
case "!": return !arg;
|
||||
@ -89,13 +95,13 @@ export function evaluate(node: Object, scope: Scope): { confident: boolean; valu
|
||||
}
|
||||
}
|
||||
|
||||
if (t.isArrayExpression(node) || t.isObjectExpression(node)) {
|
||||
if (path.isArrayExpression() || path.isObjectExpression()) {
|
||||
// we could evaluate these but it's probably impractical and not very useful
|
||||
}
|
||||
|
||||
if (t.isLogicalExpression(node)) {
|
||||
let left = evaluate(node.left);
|
||||
let right = evaluate(node.right);
|
||||
if (path.isLogicalExpression()) {
|
||||
let left = evaluate(path.get("left"));
|
||||
let right = evaluate(path.get("right"));
|
||||
|
||||
switch (node.operator) {
|
||||
case "||": return left || right;
|
||||
@ -103,9 +109,9 @@ export function evaluate(node: Object, scope: Scope): { confident: boolean; valu
|
||||
}
|
||||
}
|
||||
|
||||
if (t.isBinaryExpression(node)) {
|
||||
let left = evaluate(node.left);
|
||||
let right = evaluate(node.right);
|
||||
if (path.isBinaryExpression()) {
|
||||
let left = evaluate(path.get("left"));
|
||||
let right = evaluate(path.get("right"));
|
||||
|
||||
switch (node.operator) {
|
||||
case "-": return left - right;
|
||||
464
src/babel/traversal/path/index.js
Normal file
464
src/babel/traversal/path/index.js
Normal file
@ -0,0 +1,464 @@
|
||||
import isBoolean from "lodash/lang/isBoolean";
|
||||
import isNumber from "lodash/lang/isNumber";
|
||||
import isRegExp from "lodash/lang/isRegExp";
|
||||
import isString from "lodash/lang/isString";
|
||||
import traverse from "../index";
|
||||
import includes from "lodash/collection/includes";
|
||||
import assign from "lodash/object/assign";
|
||||
import Scope from "../scope";
|
||||
import * as t from "../../types";
|
||||
|
||||
export default class TraversalPath {
|
||||
constructor(parent, container) {
|
||||
this.container = container;
|
||||
this.parent = parent;
|
||||
this.data = {};
|
||||
}
|
||||
|
||||
static get(parentPath: TraversalPath, context?: TraversalContext, parent, container, key, file?: File) {
|
||||
var targetNode = container[key];
|
||||
var paths = container._paths ||= [];
|
||||
var path;
|
||||
|
||||
for (var i = 0; i < paths.length; i++) {
|
||||
var pathCheck = paths[i];
|
||||
if (pathCheck.node === targetNode) {
|
||||
path = pathCheck;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!path) {
|
||||
path = new TraversalPath(parent, container);
|
||||
paths.push(path);
|
||||
}
|
||||
|
||||
path.setContext(parentPath, context, key, file);
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
static getScope(path: TraversalPath, scope: Scope, file?: File) {
|
||||
var ourScope = scope;
|
||||
|
||||
// we're entering a new scope so let's construct it!
|
||||
if (path.isScope()) {
|
||||
ourScope = new Scope(path, scope, file);
|
||||
}
|
||||
|
||||
return ourScope;
|
||||
}
|
||||
|
||||
insertBefore(node) {
|
||||
|
||||
}
|
||||
|
||||
insertAfter(node) {
|
||||
|
||||
}
|
||||
|
||||
setData(key, val) {
|
||||
return this.data[key] = val;
|
||||
}
|
||||
|
||||
getData(key, def) {
|
||||
var val = this.data[key];
|
||||
if (!val && def) val = this.data[key] = def;
|
||||
return val;
|
||||
}
|
||||
|
||||
setScope(file?) {
|
||||
this.scope = TraversalPath.getScope(this, this.context && this.context.scope, file);
|
||||
}
|
||||
|
||||
setContext(parentPath, context, key, file?) {
|
||||
this.shouldSkip = false;
|
||||
this.shouldStop = false;
|
||||
|
||||
this.parentPath = parentPath || this.parentPath;
|
||||
this.key = key;
|
||||
|
||||
if (context) {
|
||||
this.context = context;
|
||||
this.state = context.state;
|
||||
this.opts = context.opts;
|
||||
}
|
||||
|
||||
this.setScope(file);
|
||||
}
|
||||
|
||||
remove() {
|
||||
this._refresh(this.node, []);
|
||||
this.container[this.key] = null;
|
||||
this.flatten();
|
||||
}
|
||||
|
||||
skip() {
|
||||
this.shouldSkip = true;
|
||||
}
|
||||
|
||||
stop() {
|
||||
this.shouldStop = true;
|
||||
this.shouldSkip = true;
|
||||
}
|
||||
|
||||
flatten() {
|
||||
this.context.flatten();
|
||||
}
|
||||
|
||||
_refresh(oldNode, newNodes) {
|
||||
// todo
|
||||
}
|
||||
|
||||
refresh() {
|
||||
var node = this.node;
|
||||
this._refresh(node, [node]);
|
||||
}
|
||||
|
||||
errorWithNode(msg, Error = SyntaxError) {
|
||||
var loc = this.node.loc.start;
|
||||
var err = new Error(`Line ${loc.line}: ${msg}`);
|
||||
err.loc = loc;
|
||||
return err;
|
||||
}
|
||||
|
||||
get node() {
|
||||
return this.container[this.key];
|
||||
}
|
||||
|
||||
set node(replacement) {
|
||||
if (!replacement) return this.remove();
|
||||
|
||||
var oldNode = this.node;
|
||||
var isArray = Array.isArray(replacement);
|
||||
var replacements = isArray ? replacement : [replacement];
|
||||
|
||||
// inherit comments from original node to the first replacement node
|
||||
var inheritTo = replacements[0];
|
||||
if (inheritTo) t.inheritsComments(inheritTo, oldNode);
|
||||
|
||||
// replace the node
|
||||
this.container[this.key] = replacement;
|
||||
|
||||
// potentially create new scope
|
||||
this.setScope();
|
||||
|
||||
var file = this.scope && this.scope.file;
|
||||
if (file) {
|
||||
for (var i = 0; i < replacements.length; i++) {
|
||||
file.checkNode(replacements[i], this.scope);
|
||||
}
|
||||
}
|
||||
|
||||
// we're replacing a statement or block node with an array of statements so we better
|
||||
// ensure that it's a block
|
||||
if (isArray) {
|
||||
if (includes(t.STATEMENT_OR_BLOCK_KEYS, this.key) && !t.isBlockStatement(this.container)) {
|
||||
t.ensureBlock(this.container, this.key);
|
||||
}
|
||||
|
||||
this.flatten();
|
||||
// TODO: duplicate internal path metadata across the new node paths
|
||||
}
|
||||
}
|
||||
|
||||
call(key) {
|
||||
var node = this.node;
|
||||
if (!node) return;
|
||||
|
||||
var opts = this.opts;
|
||||
var fn = opts[key] || opts;
|
||||
if (opts[node.type]) fn = opts[node.type][key] || fn;
|
||||
|
||||
var replacement = fn.call(this, node, this.parent, this.scope, this.state);
|
||||
|
||||
if (replacement) {
|
||||
this.node = replacement;
|
||||
}
|
||||
}
|
||||
|
||||
isBlacklisted(): boolean {
|
||||
var blacklist = this.opts.blacklist;
|
||||
return blacklist && blacklist.indexOf(this.node.type) > -1;
|
||||
}
|
||||
|
||||
visit(): boolean {
|
||||
if (this.isBlacklisted()) return false;
|
||||
|
||||
this.call("enter");
|
||||
|
||||
if (this.shouldSkip) {
|
||||
return this.shouldStop;
|
||||
}
|
||||
|
||||
var node = this.node;
|
||||
var opts = this.opts;
|
||||
|
||||
if (node) {
|
||||
if (Array.isArray(node)) {
|
||||
// traverse over these replacement nodes we purposely don't call exitNode
|
||||
// as the original node has been destroyed
|
||||
for (var i = 0; i < node.length; i++) {
|
||||
traverse.node(node[i], opts, this.scope, this.state, this);
|
||||
}
|
||||
} else {
|
||||
traverse.node(node, opts, this.scope, this.state, this);
|
||||
this.call("exit");
|
||||
}
|
||||
}
|
||||
|
||||
return this.shouldStop;
|
||||
}
|
||||
|
||||
get(key) {
|
||||
var node = this.node;
|
||||
var container = node[key];
|
||||
if (Array.isArray(container)) {
|
||||
return container.map((_, i) => {
|
||||
return TraversalPath.get(this, this.context, node, container, i);
|
||||
});
|
||||
} else {
|
||||
return TraversalPath.get(this, this.context, node, node, key);
|
||||
}
|
||||
}
|
||||
|
||||
has(key): boolean {
|
||||
return !!this.node[key];
|
||||
}
|
||||
|
||||
is(key): boolean {
|
||||
return this.has(key);
|
||||
}
|
||||
|
||||
isnt(key): boolean {
|
||||
return !this.has(key);
|
||||
}
|
||||
|
||||
getTypeAnnotation(): {
|
||||
inferred: boolean;
|
||||
annotation: ?Object;
|
||||
} {
|
||||
if (this.typeInfo) {
|
||||
return this.typeInfo;
|
||||
}
|
||||
|
||||
var info = this.typeInfo = {
|
||||
inferred: false,
|
||||
annotation: null
|
||||
};
|
||||
|
||||
var type = this.node.typeAnnotation;
|
||||
|
||||
if (!type) {
|
||||
info.inferred = true;
|
||||
type = this.inferType(this);
|
||||
}
|
||||
|
||||
if (type) {
|
||||
if (t.isTypeAnnotation(type)) type = type.typeAnnotation;
|
||||
info.annotation = type;
|
||||
}
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
resolve(): ?TraversalPath {
|
||||
if (this.isVariableDeclarator()) {
|
||||
if (this.get("id").isIdentifier()) {
|
||||
return this.get("init").resolve();
|
||||
} else {
|
||||
// otherwise it's a request for a destructuring declarator and i'm not
|
||||
// ready to resolve those just yet
|
||||
}
|
||||
} else if (this.isIdentifier()) {
|
||||
var binding = this.scope.getBinding(this.node.name);
|
||||
if (!binding || !binding.constant) return;
|
||||
|
||||
if (binding.path === this) {
|
||||
return this;
|
||||
} else {
|
||||
return binding.path.resolve();
|
||||
}
|
||||
} else if (this.isMemberExpression()) {
|
||||
// this is dangerous, as non-direct target assignments will mutate it's state
|
||||
// making this resolution inaccurate
|
||||
|
||||
var targetKey = this.toComputedKey();
|
||||
if (!t.isLiteral(targetKey)) return;
|
||||
var targetName = targetKey.value;
|
||||
|
||||
var target = this.get("object").resolve();
|
||||
if (!target || !target.isObjectExpression()) return;
|
||||
|
||||
var props = target.get("properties");
|
||||
for (var i = 0; i < props.length; i++) {
|
||||
var prop = props[i];
|
||||
if (!prop.isProperty()) continue;
|
||||
|
||||
var key = prop.get("key");
|
||||
|
||||
// { foo: obj }
|
||||
var match = prop.isnt("computed") && key.isIdentifier({ name: targetName });
|
||||
|
||||
// { "foo": "obj" } or { ["foo"]: "obj" }
|
||||
match ||= key.isLiteral({ value: targetName });
|
||||
|
||||
if (match) return prop.get("value");
|
||||
}
|
||||
} else {
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
inferType(path: TraversalPath): ?Object {
|
||||
path = path.resolve();
|
||||
if (!path) return;
|
||||
|
||||
if (path.isRestElement() || path.parentPath.isRestElement() || path.isArrayExpression()) {
|
||||
return t.genericTypeAnnotation(t.identifier("Array"));
|
||||
}
|
||||
|
||||
if (path.parentPath.isTypeCastExpression()) {
|
||||
return path.parentPath.node.typeAnnotation;
|
||||
}
|
||||
|
||||
if (path.isTypeCastExpression()) {
|
||||
return path.node.typeAnnotation;
|
||||
}
|
||||
|
||||
if (path.isObjectExpression()) {
|
||||
return t.genericTypeAnnotation(t.identifier("Object"));
|
||||
}
|
||||
|
||||
if (path.isFunction()) {
|
||||
return t.identifier("Function");
|
||||
}
|
||||
|
||||
if (path.isLiteral()) {
|
||||
var value = path.node.value;
|
||||
if (isString(value)) return t.stringTypeAnnotation();
|
||||
if (isNumber(value)) return t.numberTypeAnnotation();
|
||||
if (isBoolean(value)) return t.booleanTypeAnnotation();
|
||||
}
|
||||
|
||||
if (path.isCallExpression()) {
|
||||
var callee = path.get("callee").resolve();
|
||||
if (callee && callee.isFunction()) return callee.node.returnType;
|
||||
}
|
||||
}
|
||||
|
||||
isScope(): boolean {
|
||||
return t.isScope(this.node, this.parent);
|
||||
}
|
||||
|
||||
isReferencedIdentifier(opts): boolean {
|
||||
return t.isReferencedIdentifier(this.node, this.parent, opts);
|
||||
}
|
||||
|
||||
isReferenced(): boolean {
|
||||
return t.isReferenced(this.node, this.parent);
|
||||
}
|
||||
|
||||
isBlockScoped(): boolean {
|
||||
return t.isBlockScoped(this.node);
|
||||
}
|
||||
|
||||
isVar(): boolean {
|
||||
return t.isVar(this.node);
|
||||
}
|
||||
|
||||
isScope(): boolean {
|
||||
return t.isScope(this.node, this.parent);
|
||||
}
|
||||
|
||||
isTypeGeneric(genericName: string, opts = {}): boolean {
|
||||
var typeInfo = this.getTypeAnnotation();
|
||||
var type = typeInfo.annotation;
|
||||
if (!type) return false;
|
||||
|
||||
if (type.inferred && opts.inference === false) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!t.isGenericTypeAnnotation(type) || !t.isIdentifier(type.id, { name: genericName })) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (opts.requireTypeParameters && !type.typeParameters) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
getBindingIdentifiers() {
|
||||
return t.getBindingIdentifiers(this.node);
|
||||
}
|
||||
|
||||
traverse(opts, state) {
|
||||
traverse(this.node, opts, this.scope, state, this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Match the current node if it matches the provided `pattern`.
|
||||
*
|
||||
* For example, given the match `React.createClass` it would match the
|
||||
* parsed nodes of `React.createClass` and `React["createClass"]`.
|
||||
*/
|
||||
|
||||
matchesPattern(pattern: string, allowPartial?: boolean): boolean {
|
||||
var parts = pattern.split(".");
|
||||
|
||||
// not a member expression
|
||||
if (!this.isMemberExpression()) return false;
|
||||
|
||||
var search = [this.node];
|
||||
var i = 0;
|
||||
|
||||
while (search.length) {
|
||||
var node = search.shift();
|
||||
|
||||
if (allowPartial && i === parts.length) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (t.isIdentifier(node)) {
|
||||
// this part doesn't match
|
||||
if (parts[i] !== node.name) return false;
|
||||
} else if (t.isLiteral(node)) {
|
||||
// this part doesn't match
|
||||
if (parts[i] !== node.value) return false;
|
||||
} else if (t.isMemberExpression(node)) {
|
||||
if (node.computed && !t.isLiteral(node.property)) {
|
||||
// we can't deal with this
|
||||
return false;
|
||||
} else {
|
||||
search.push(node.object);
|
||||
search.push(node.property);
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
// we can't deal with this
|
||||
return false;
|
||||
}
|
||||
|
||||
// too many parts
|
||||
if (++i > parts.length) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
assign(TraversalPath.prototype, require("./evaluation"));
|
||||
assign(TraversalPath.prototype, require("./conversion"));
|
||||
|
||||
for (var i = 0; i < t.TYPES.length; i++) {
|
||||
let type = t.TYPES[i];
|
||||
let typeKey = `is${type}`;
|
||||
TraversalPath.prototype[typeKey] = function (opts) {
|
||||
return t[typeKey](this.node, opts);
|
||||
};
|
||||
}
|
||||
@ -2,6 +2,7 @@ import includes from "lodash/collection/includes";
|
||||
import traverse from "./index";
|
||||
import defaults from "lodash/object/defaults";
|
||||
import * as messages from "../messages";
|
||||
import Binding from "./binding";
|
||||
import globals from "globals";
|
||||
import flatten from "lodash/array/flatten";
|
||||
import extend from "lodash/object/extend";
|
||||
@ -12,27 +13,27 @@ import * as t from "../types";
|
||||
var functionVariableVisitor = {
|
||||
enter(node, parent, scope, state) {
|
||||
if (t.isFor(node)) {
|
||||
each(t.FOR_INIT_KEYS, function (key) {
|
||||
var declar = node[key];
|
||||
if (t.isVar(declar)) state.scope.registerBinding("var", declar);
|
||||
each(t.FOR_INIT_KEYS, (key) => {
|
||||
var declar = this.get(key);
|
||||
if (declar.isVar()) state.scope.registerBinding("var", declar);
|
||||
});
|
||||
}
|
||||
|
||||
// this block is a function so we'll stop since none of the variables
|
||||
// declared within are accessible
|
||||
if (t.isFunction(node)) return this.skip();
|
||||
if (this.isFunction()) return this.skip();
|
||||
|
||||
// function identifier doesn't belong to this scope
|
||||
if (state.blockId && node === state.blockId) return;
|
||||
|
||||
// delegate block scope handling to the `blockVariableVisitor`
|
||||
if (t.isBlockScoped(node)) return;
|
||||
if (this.isBlockScoped()) return;
|
||||
|
||||
// this will be hit again once we traverse into it after this iteration
|
||||
if (t.isExportDeclaration(node) && t.isDeclaration(node.declaration)) return;
|
||||
if (this.isExportDeclaration() && t.isDeclaration(node.declaration)) return;
|
||||
|
||||
// we've ran into a declaration!
|
||||
if (t.isDeclaration(node)) state.scope.registerDeclaration(node);
|
||||
if (this.isDeclaration()) state.scope.registerDeclaration(this);
|
||||
}
|
||||
};
|
||||
|
||||
@ -42,16 +43,20 @@ var programReferenceVisitor = {
|
||||
state.addGlobal(node);
|
||||
} else if (t.isLabeledStatement(node)) {
|
||||
state.addGlobal(node);
|
||||
} else if (t.isAssignmentExpression(node) || t.isUpdateExpression(node) || (t.isUnaryExpression(node) && node.operator === "delete")) {
|
||||
scope.registerBindingReassignment(node);
|
||||
} else if (t.isAssignmentExpression(node)) {
|
||||
scope.registerConstantViolation(this.get("left"), this.get("right"));
|
||||
} else if (t.isUpdateExpression(node)) {
|
||||
scope.registerConstantViolation(this.get("argument"), null);
|
||||
} else if (t.isUnaryExpression(node) && node.operator === "delete") {
|
||||
scope.registerConstantViolation(this.get("left"), null);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
var blockVariableVisitor = {
|
||||
enter(node, parent, scope, state) {
|
||||
if (t.isFunctionDeclaration(node) || t.isBlockScoped(node)) {
|
||||
state.registerDeclaration(node);
|
||||
if (this.isFunctionDeclaration() || this.isBlockScoped()) {
|
||||
state.registerDeclaration(this);
|
||||
} else if (t.isScope(node, parent)) {
|
||||
this.skip();
|
||||
}
|
||||
@ -65,12 +70,20 @@ export default class Scope {
|
||||
* within.
|
||||
*/
|
||||
|
||||
constructor(block: Object, parentBlock: Object, parent?: Scope, file?: File) {
|
||||
constructor(path: TraversalPath, parent?: Scope, file?: File) {
|
||||
var cached = path.getData("scope");
|
||||
if (cached) {
|
||||
return cached;
|
||||
} else {
|
||||
//path.setData("scope", this);
|
||||
}
|
||||
|
||||
this.parent = parent;
|
||||
this.file = parent ? parent.file : file;
|
||||
|
||||
this.parentBlock = parentBlock;
|
||||
this.block = block;
|
||||
this.parentBlock = path.parent;
|
||||
this.block = path.node;
|
||||
this.path = path;
|
||||
|
||||
this.crawl();
|
||||
}
|
||||
@ -104,9 +117,7 @@ export default class Scope {
|
||||
*/
|
||||
|
||||
generateUidIdentifier(name: string) {
|
||||
var id = t.identifier(this.generateUid(name));
|
||||
this.getFunctionParent().registerBinding("uid", id);
|
||||
return id;
|
||||
return t.identifier(this.generateUid(name));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -121,7 +132,8 @@ export default class Scope {
|
||||
do {
|
||||
uid = this._generateUid(name, i);
|
||||
i++;
|
||||
} while (this.hasBinding(uid) || this.hasGlobal(uid));
|
||||
} while (this.hasBinding(uid) || this.hasGlobal(uid) || this.hasUid(uid));
|
||||
this.getFunctionParent().uids[uid] = true;
|
||||
return uid;
|
||||
}
|
||||
|
||||
@ -131,6 +143,19 @@ export default class Scope {
|
||||
return `_${id}`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Description
|
||||
*/
|
||||
|
||||
hasUid(name): boolean {
|
||||
var scope = this;
|
||||
do {
|
||||
if (scope.uids[name]) return true;
|
||||
scope = scope.parent;
|
||||
} while (scope);
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* Description
|
||||
*/
|
||||
@ -209,7 +234,7 @@ export default class Scope {
|
||||
rename(oldName: string, newName: string) {
|
||||
newName ||= this.generateUidIdentifier(oldName).name;
|
||||
|
||||
var info = this.getBindingInfo(oldName);
|
||||
var info = this.getBinding(oldName);
|
||||
if (!info) return;
|
||||
|
||||
var binding = info.identifier;
|
||||
@ -220,7 +245,7 @@ export default class Scope {
|
||||
if (t.isReferencedIdentifier(node, parent) && node.name === oldName) {
|
||||
node.name = newName;
|
||||
} else if (t.isDeclaration(node)) {
|
||||
var ids = t.getBindingIdentifiers(node);
|
||||
var ids = this.getBindingIdentifiers();
|
||||
for (var name in ids) {
|
||||
if (name === oldName) ids[name].name = newName;
|
||||
}
|
||||
@ -238,102 +263,6 @@ export default class Scope {
|
||||
binding.name = newName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Description
|
||||
*/
|
||||
|
||||
inferType(node: Object) {
|
||||
var target;
|
||||
|
||||
if (t.isVariableDeclarator(node)) {
|
||||
target = node.init;
|
||||
}
|
||||
|
||||
if (t.isArrayExpression(target)) {
|
||||
return t.genericTypeAnnotation(t.identifier("Array"));
|
||||
}
|
||||
|
||||
if (t.isObjectExpression(target)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (t.isLiteral(target)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (t.isCallExpression(target) && t.isIdentifier(target.callee)) {
|
||||
var funcInfo = this.getBindingInfo(target.callee.name);
|
||||
if (funcInfo) {
|
||||
var funcNode = funcInfo.node;
|
||||
return !funcInfo.reassigned && t.isFunction(funcNode) && node.returnType;
|
||||
}
|
||||
}
|
||||
|
||||
if (t.isIdentifier(target)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Description
|
||||
*/
|
||||
|
||||
isTypeGeneric(name: string, genericName: string) {
|
||||
var info = this.getBindingInfo(name);
|
||||
if (!info) return false;
|
||||
|
||||
var type = info.typeAnnotation;
|
||||
return t.isGenericTypeAnnotation(type) && t.isIdentifier(type.id, { name: genericName });
|
||||
}
|
||||
|
||||
/**
|
||||
* Description
|
||||
*/
|
||||
|
||||
assignTypeGeneric(name: string, type: Object) {
|
||||
this.assignType(name, t.genericTypeAnnotation(t.identifier(type)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Description
|
||||
*/
|
||||
|
||||
assignType(name: string, type: Object) {
|
||||
var info = this.getBindingInfo(name);
|
||||
if (!info) return;
|
||||
|
||||
info.typeAnnotation = type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Description
|
||||
*/
|
||||
|
||||
getTypeAnnotation(id: Object, node: Object): Object {
|
||||
var info = {
|
||||
annotation: null,
|
||||
inferred: false
|
||||
};
|
||||
|
||||
var type;
|
||||
|
||||
if (id.typeAnnotation) {
|
||||
type = id.typeAnnotation;
|
||||
}
|
||||
|
||||
if (!type) {
|
||||
info.inferred = true;
|
||||
type = this.inferType(node);
|
||||
}
|
||||
|
||||
if (type) {
|
||||
if (t.isTypeAnnotation(type)) type = type.typeAnnotation;
|
||||
info.annotation = type;
|
||||
}
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
/**
|
||||
* Description
|
||||
*/
|
||||
@ -341,8 +270,9 @@ export default class Scope {
|
||||
toArray(node: Object, i?: number) {
|
||||
var file = this.file;
|
||||
|
||||
if (t.isIdentifier(node) && this.isTypeGeneric(node.name, "Array")) {
|
||||
return node;
|
||||
if (t.isIdentifier(node)) {
|
||||
var binding = this.getBinding(node.name);
|
||||
if (binding && binding.isTypeGeneric("Array", { inference: false })) return node;
|
||||
}
|
||||
|
||||
if (t.isArrayExpression(node)) {
|
||||
@ -368,33 +298,21 @@ export default class Scope {
|
||||
* Description
|
||||
*/
|
||||
|
||||
refreshDeclaration(node: Object) {
|
||||
if (t.isBlockScoped(node)) {
|
||||
this.getBlockParent().registerDeclaration(node);
|
||||
} else if (t.isVariableDeclaration(node, { kind: "var" })) {
|
||||
this.getFunctionParent().registerDeclaration(node);
|
||||
} else if (node === this.block) {
|
||||
this.recrawl();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Description
|
||||
*/
|
||||
|
||||
registerDeclaration(node: Object) {
|
||||
registerDeclaration(path: TraversalPath) {
|
||||
var node = path.node;
|
||||
if (t.isFunctionDeclaration(node)) {
|
||||
this.registerBinding("hoisted", node);
|
||||
this.registerBinding("hoisted", path);
|
||||
} else if (t.isVariableDeclaration(node)) {
|
||||
for (var i = 0; i < node.declarations.length; i++) {
|
||||
this.registerBinding(node.kind, node.declarations[i]);
|
||||
var declarations = path.get("declarations");
|
||||
for (var i = 0; i < declarations.length; i++) {
|
||||
this.registerBinding(node.kind, declarations[i]);
|
||||
}
|
||||
} else if (t.isClassDeclaration(node)) {
|
||||
this.registerBinding("let", node);
|
||||
this.registerBinding("let", path);
|
||||
} else if (t.isImportDeclaration(node) || t.isExportDeclaration(node)) {
|
||||
this.registerBinding("module", node);
|
||||
this.registerBinding("module", path);
|
||||
} else {
|
||||
this.registerBinding("unknown", node);
|
||||
this.registerBinding("unknown", path);
|
||||
}
|
||||
}
|
||||
|
||||
@ -402,18 +320,16 @@ export default class Scope {
|
||||
* Description
|
||||
*/
|
||||
|
||||
registerBindingReassignment(node: Object) {
|
||||
var ids = t.getBindingIdentifiers(node);
|
||||
registerConstantViolation(left: TraversalPath, right: TraversalPath) {
|
||||
var ids = left.getBindingIdentifiers();
|
||||
for (var name in ids) {
|
||||
var info = this.getBindingInfo(name);
|
||||
if (info) {
|
||||
info.reassigned = true;
|
||||
|
||||
if (info.typeAnnotationInferred) {
|
||||
// destroy the inferred typeAnnotation
|
||||
info.typeAnnotation = null;
|
||||
}
|
||||
var binding = this.getBinding(name);
|
||||
if (!binding) continue;
|
||||
if (right) {
|
||||
var rightType = right.typeAnnotation;
|
||||
if (rightType && binding.isCompatibleWithType(rightType)) continue;
|
||||
}
|
||||
binding.reassign();
|
||||
}
|
||||
}
|
||||
|
||||
@ -421,27 +337,22 @@ export default class Scope {
|
||||
* Description
|
||||
*/
|
||||
|
||||
registerBinding(kind: string, node: Object) {
|
||||
registerBinding(kind: string, path: TraversalPath) {
|
||||
if (!kind) throw new ReferenceError("no `kind`");
|
||||
|
||||
var ids = t.getBindingIdentifiers(node);
|
||||
var ids = path.getBindingIdentifiers();
|
||||
|
||||
for (var name in ids) {
|
||||
var id = ids[name];
|
||||
|
||||
this.checkBlockScopedCollisions(kind, name, id);
|
||||
|
||||
var typeInfo = this.getTypeAnnotation(id, node);
|
||||
|
||||
this.bindings[name] = {
|
||||
typeAnnotationInferred: typeInfo.inferred,
|
||||
typeAnnotation: typeInfo.annotation,
|
||||
reassigned: false,
|
||||
identifier: id,
|
||||
scope: this,
|
||||
node: node,
|
||||
kind: kind
|
||||
};
|
||||
this.bindings[name] = new Binding({
|
||||
identifier: id,
|
||||
scope: this,
|
||||
path: path,
|
||||
kind: kind
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@ -472,7 +383,7 @@ export default class Scope {
|
||||
*/
|
||||
|
||||
recrawl() {
|
||||
this.block._scopeInfo = null;
|
||||
this.path.setData("scopeInfo", null);
|
||||
this.crawl();
|
||||
}
|
||||
|
||||
@ -481,91 +392,88 @@ export default class Scope {
|
||||
*/
|
||||
|
||||
crawl() {
|
||||
var block = this.block;
|
||||
var i;
|
||||
var path = this.path;
|
||||
|
||||
//
|
||||
|
||||
var info = block._scopeInfo;
|
||||
if (info) {
|
||||
extend(this, info);
|
||||
return;
|
||||
}
|
||||
var info = path.getData("scopeInfo");
|
||||
if (info) return extend(this, info);
|
||||
|
||||
info = block._scopeInfo = {
|
||||
info = path.setData("scopeInfo", {
|
||||
bindings: object(),
|
||||
globals: object()
|
||||
};
|
||||
globals: object(),
|
||||
uids: object()
|
||||
});
|
||||
|
||||
extend(this, info);
|
||||
|
||||
// ForStatement - left, init
|
||||
|
||||
if (t.isLoop(block)) {
|
||||
for (i = 0; i < t.FOR_INIT_KEYS.length; i++) {
|
||||
var node = block[t.FOR_INIT_KEYS[i]];
|
||||
if (t.isBlockScoped(node)) this.registerBinding("let", node);
|
||||
if (path.isLoop()) {
|
||||
for (let i = 0; i < t.FOR_INIT_KEYS.length; i++) {
|
||||
var node = path.get(t.FOR_INIT_KEYS[i]);
|
||||
if (node.isBlockScoped()) this.registerBinding("let", node);
|
||||
}
|
||||
|
||||
if (t.isBlockStatement(block.body)) {
|
||||
block = block.body;
|
||||
}
|
||||
var body = path.get("body");
|
||||
if (body.isBlockStatement()) path = path.get("body");
|
||||
}
|
||||
|
||||
// FunctionExpression - id
|
||||
|
||||
if (t.isFunctionExpression(block) && block.id) {
|
||||
if (!t.isProperty(this.parentBlock, { method: true })) {
|
||||
this.registerBinding("var", block.id);
|
||||
if (path.isFunctionExpression() && path.has("id")) {
|
||||
if (!t.isProperty(path.parent, { method: true })) {
|
||||
this.registerBinding("var", path.get("id"));
|
||||
}
|
||||
}
|
||||
|
||||
// Class
|
||||
|
||||
if (t.isClass(block) && block.id) {
|
||||
this.registerBinding("var", block.id);
|
||||
if (path.isClass() && path.has("id")) {
|
||||
this.registerBinding("var", path.get("id"));
|
||||
}
|
||||
|
||||
// Function - params, rest
|
||||
|
||||
if (t.isFunction(block)) {
|
||||
for (i = 0; i < block.params.length; i++) {
|
||||
this.registerBinding("param", block.params[i]);
|
||||
if (path.isFunction()) {
|
||||
var params = path.get("params");
|
||||
for (let i = 0; i < params.length; i++) {
|
||||
this.registerBinding("param", params[i]);
|
||||
}
|
||||
this.traverse(block.body, blockVariableVisitor, this);
|
||||
this.traverse(path.get("body").node, blockVariableVisitor, this);
|
||||
}
|
||||
|
||||
// Program, BlockStatement, Function - let variables
|
||||
|
||||
if (t.isBlockStatement(block) || t.isProgram(block)) {
|
||||
this.traverse(block, blockVariableVisitor, this);
|
||||
if (path.isBlockStatement() || path.isProgram()) {
|
||||
this.traverse(path.node, blockVariableVisitor, this);
|
||||
}
|
||||
|
||||
// CatchClause - param
|
||||
|
||||
if (t.isCatchClause(block)) {
|
||||
this.registerBinding("let", block.param);
|
||||
if (path.isCatchClause()) {
|
||||
this.registerBinding("let", path.get("param"));
|
||||
}
|
||||
|
||||
// ComprehensionExpression - blocks
|
||||
|
||||
if (t.isComprehensionExpression(block)) {
|
||||
this.registerBinding("let", block);
|
||||
if (path.isComprehensionExpression()) {
|
||||
this.registerBinding("let", path);
|
||||
}
|
||||
|
||||
// Program, Function - var variables
|
||||
|
||||
if (t.isProgram(block) || t.isFunction(block)) {
|
||||
this.traverse(block, functionVariableVisitor, {
|
||||
blockId: block.id,
|
||||
if (path.isProgram() || path.isFunction()) {
|
||||
this.traverse(path.node, functionVariableVisitor, {
|
||||
blockId: path.get("id").node,
|
||||
scope: this
|
||||
});
|
||||
}
|
||||
|
||||
// Program
|
||||
|
||||
if (t.isProgram(block)) {
|
||||
this.traverse(block, programReferenceVisitor, this);
|
||||
if (path.isProgram()) {
|
||||
this.traverse(path.node, programReferenceVisitor, this);
|
||||
}
|
||||
}
|
||||
|
||||
@ -666,7 +574,7 @@ export default class Scope {
|
||||
* Description
|
||||
*/
|
||||
|
||||
getBindingInfo(name: string) {
|
||||
getBinding(name: string) {
|
||||
var scope = this;
|
||||
|
||||
do {
|
||||
@ -688,7 +596,7 @@ export default class Scope {
|
||||
*/
|
||||
|
||||
getBindingIdentifier(name: string) {
|
||||
var info = this.getBindingInfo(name);
|
||||
var info = this.getBinding(name);
|
||||
return info && info.identifier;
|
||||
}
|
||||
|
||||
@ -701,44 +609,6 @@ export default class Scope {
|
||||
return binding && binding.identifier;
|
||||
}
|
||||
|
||||
/**
|
||||
* Description
|
||||
*/
|
||||
|
||||
getOwnImmutableBindingValue(name: string) {
|
||||
return this._immutableBindingInfoToValue(this.getOwnBindingInfo(name));
|
||||
}
|
||||
|
||||
/**
|
||||
* Description
|
||||
*/
|
||||
|
||||
getImmutableBindingValue(name: string) {
|
||||
return this._immutableBindingInfoToValue(this.getBindingInfo(name));
|
||||
}
|
||||
|
||||
_immutableBindingInfoToValue(info) {
|
||||
if (!info) return;
|
||||
|
||||
// can't guarantee this value is the same
|
||||
if (info.reassigned) return;
|
||||
|
||||
var node = info.node;
|
||||
if (t.isVariableDeclarator(node)) {
|
||||
if (t.isIdentifier(node.id)) {
|
||||
node = node.init;
|
||||
} else {
|
||||
// otherwise it's probably a destructuring like:
|
||||
// var { foo } = "foo";
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (t.isImmutable(node)) {
|
||||
return node;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Description
|
||||
*/
|
||||
@ -781,7 +651,7 @@ export default class Scope {
|
||||
*/
|
||||
|
||||
removeBinding(name: string) {
|
||||
var info = this.getBindingInfo(name);
|
||||
var info = this.getBinding(name);
|
||||
if (info) info.scope.removeOwnBinding(name);
|
||||
}
|
||||
}
|
||||
|
||||
@ -10,7 +10,7 @@ import * as t from "./index";
|
||||
* Description
|
||||
*/
|
||||
|
||||
export function toComputedKey(node: Object, key: Object = node.key): Object {
|
||||
export function toComputedKey(node: Object, key: Object = node.key || node.property): Object {
|
||||
if (!node.computed) {
|
||||
if (t.isIdentifier(key)) key = t.literal(key.name);
|
||||
}
|
||||
|
||||
@ -24,15 +24,15 @@ function registerType(type: string, skipAliasCheck?: boolean) {
|
||||
};
|
||||
}
|
||||
|
||||
export var STATEMENT_OR_BLOCK_KEYS = ["consequent", "body", "alternate"];
|
||||
export var NATIVE_TYPE_NAMES = ["Array", "Object", "Number", "Boolean", "Date", "Array", "String"];
|
||||
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 NATIVE_TYPE_NAMES = ["Array", "Object", "Number", "Boolean", "Date", "Array", "String"];
|
||||
export const FLATTENABLE_KEYS = ["body", "expressions"];
|
||||
export const FOR_INIT_KEYS = ["left", "init"];
|
||||
export const COMMENT_KEYS = ["leadingComments", "trailingComments"];
|
||||
|
||||
export var VISITOR_KEYS = require("./visitor-keys");
|
||||
export var BUILDER_KEYS = require("./builder-keys");
|
||||
export var ALIAS_KEYS = require("./alias-keys");
|
||||
export const VISITOR_KEYS = require("./visitor-keys");
|
||||
export const BUILDER_KEYS = require("./builder-keys");
|
||||
export const ALIAS_KEYS = require("./alias-keys");
|
||||
|
||||
t.FLIPPED_ALIAS_KEYS = {};
|
||||
|
||||
@ -52,7 +52,7 @@ each(t.FLIPPED_ALIAS_KEYS, function (types, type) {
|
||||
registerType(type, false);
|
||||
});
|
||||
|
||||
export var TYPES = Object.keys(t.VISITOR_KEYS).concat(Object.keys(t.FLIPPED_ALIAS_KEYS));
|
||||
export const TYPES = Object.keys(t.VISITOR_KEYS).concat(Object.keys(t.FLIPPED_ALIAS_KEYS));
|
||||
|
||||
/**
|
||||
* Returns whether `node` is of given `type`.
|
||||
@ -281,7 +281,6 @@ export function inheritsComments(child: Object, parent: Object): Object {
|
||||
|
||||
export function inherits(child: Object, parent: Object): Object {
|
||||
child._declarations = parent._declarations;
|
||||
child._scopeInfo = parent._scopeInfo;
|
||||
child.range = parent.range;
|
||||
child.start = parent.start;
|
||||
child.loc = parent.loc;
|
||||
@ -298,7 +297,6 @@ toFastProperties(t);
|
||||
toFastProperties(t.VISITOR_KEYS);
|
||||
|
||||
exports.__esModule = true;
|
||||
assign(t, require("./evaluators"));
|
||||
assign(t, require("./retrievers"));
|
||||
assign(t, require("./validators"));
|
||||
assign(t, require("./converters"));
|
||||
|
||||
@ -93,7 +93,7 @@
|
||||
"TypeofTypeAnnotation": ["argument"],
|
||||
"TypeAlias": ["id", "typeParameters", "right"],
|
||||
"TypeAnnotation": ["typeAnnotation"],
|
||||
"TypeCastExpression": ["expression"],
|
||||
"TypeCastExpression": ["expression", "typeAnnotation"],
|
||||
"TypeParameterDeclaration": ["params"],
|
||||
"TypeParameterInstantiation": ["params"],
|
||||
"ObjectTypeAnnotation": ["key", "value"],
|
||||
|
||||
@ -4,6 +4,7 @@ import buildDebug from "debug/node";
|
||||
import cloneDeep from "lodash/lang/cloneDeep";
|
||||
import isBoolean from "lodash/lang/isBoolean";
|
||||
import * as messages from "./messages";
|
||||
import minimatch from "minimatch";
|
||||
import contains from "lodash/collection/contains";
|
||||
import traverse from "./traversal";
|
||||
import isString from "lodash/lang/isString";
|
||||
@ -43,16 +44,21 @@ export function list(val: string): Array<string> {
|
||||
export function regexify(val: any): RegExp {
|
||||
if (!val) return new RegExp(/.^/);
|
||||
if (Array.isArray(val)) val = val.join("|");
|
||||
if (isString(val)) return new RegExp(val);
|
||||
if (isString(val)) return minimatch.makeRe(val, { nocase: true });
|
||||
if (isRegExp(val)) return val;
|
||||
throw new TypeError("illegal type for regexify");
|
||||
}
|
||||
|
||||
export function arrayify(val: any): Array {
|
||||
export function arrayify(val: any, mapFn?: Function): Array {
|
||||
if (!val) return [];
|
||||
if (isBoolean(val)) return [val];
|
||||
if (isString(val)) return list(val);
|
||||
if (Array.isArray(val)) return val;
|
||||
if (isBoolean(val)) return arrayify([val], mapFn);
|
||||
if (isString(val)) return arrayify(list(val), mapFn);
|
||||
|
||||
if (Array.isArray(val)) {
|
||||
if (mapFn) val = val.map(mapFn);
|
||||
return val;
|
||||
}
|
||||
|
||||
throw new TypeError("illegal type for arrayify");
|
||||
}
|
||||
|
||||
|
||||
@ -55,6 +55,7 @@ var run = function (task, done) {
|
||||
|
||||
var getOpts = function (self) {
|
||||
return _.merge({
|
||||
suppressDeprecationMessages: true,
|
||||
filename: self.loc
|
||||
}, opts);
|
||||
};
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
for (let i of [1, 2, 3]) {
|
||||
for (let i of nums) {
|
||||
var x = 5;
|
||||
fns.push(function () {
|
||||
return i * x;
|
||||
|
||||
@ -5,7 +5,7 @@ var _didIteratorError = false;
|
||||
var _iteratorError = undefined;
|
||||
|
||||
try {
|
||||
for (var _iterator = [1, 2, 3][Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
|
||||
for (var _iterator = nums[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
|
||||
var x;
|
||||
|
||||
(function () {
|
||||
@ -30,4 +30,4 @@ try {
|
||||
throw _iteratorError;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -26,7 +26,9 @@ define(["exports"], function (exports) {
|
||||
|
||||
function foo7() {}
|
||||
|
||||
var foo8 = exports.foo8 = function foo8() {
|
||||
var foo8 = function foo8() {
|
||||
_classCallCheck(this, foo8);
|
||||
};
|
||||
});
|
||||
|
||||
exports.foo8 = foo8;
|
||||
});
|
||||
|
||||
@ -25,6 +25,8 @@ exports.foo6 = foo6;
|
||||
|
||||
function foo7() {}
|
||||
|
||||
var foo8 = exports.foo8 = function foo8() {
|
||||
var foo8 = function foo8() {
|
||||
_classCallCheck(this, foo8);
|
||||
};
|
||||
};
|
||||
|
||||
exports.foo8 = foo8;
|
||||
|
||||
@ -34,11 +34,13 @@ System.register([], function (_export) {
|
||||
|
||||
_export("foo6", foo6);
|
||||
|
||||
foo8 = _export("foo8", function foo8() {
|
||||
foo8 = function foo8() {
|
||||
_classCallCheck(this, foo8);
|
||||
});
|
||||
};
|
||||
|
||||
_export("foo8", foo8);
|
||||
|
||||
_export("foo3", foo3 = 5);
|
||||
}
|
||||
};
|
||||
});
|
||||
});
|
||||
|
||||
@ -32,7 +32,9 @@
|
||||
|
||||
function foo7() {}
|
||||
|
||||
var foo8 = exports.foo8 = function foo8() {
|
||||
var foo8 = function foo8() {
|
||||
_classCallCheck(this, foo8);
|
||||
};
|
||||
});
|
||||
|
||||
exports.foo8 = foo8;
|
||||
});
|
||||
|
||||
@ -1,2 +0,0 @@
|
||||
var arr: Array = bar;
|
||||
[...arr];
|
||||
@ -1,4 +0,0 @@
|
||||
"use strict";
|
||||
|
||||
var arr = bar;
|
||||
[].concat(arr);
|
||||
@ -1,5 +1,5 @@
|
||||
function add() {
|
||||
return [for (i of [1, 2, 3]) i * arguments[0]];
|
||||
return [for (i of nums) i * arguments[0]];
|
||||
}
|
||||
|
||||
add(5);
|
||||
|
||||
@ -10,7 +10,7 @@ function add() {
|
||||
var _iteratorError = undefined;
|
||||
|
||||
try {
|
||||
for (var _iterator = [1, 2, 3][Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
|
||||
for (var _iterator = nums[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
|
||||
var i = _step.value;
|
||||
|
||||
_ref.push(i * _arguments[0]);
|
||||
@ -34,4 +34,4 @@ function add() {
|
||||
})();
|
||||
}
|
||||
|
||||
add(5);
|
||||
add(5);
|
||||
|
||||
@ -2,32 +2,15 @@
|
||||
|
||||
var arr = (function () {
|
||||
var _arr = [];
|
||||
var _iteratorNormalCompletion = true;
|
||||
var _didIteratorError = false;
|
||||
var _iteratorError = undefined;
|
||||
var _arr2 = [1, 2, 3];
|
||||
|
||||
try {
|
||||
for (var _iterator = [1, 2, 3][Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
|
||||
var i = _step.value;
|
||||
for (var _i = 0; _i < _arr2.length; _i++) {
|
||||
var i = _arr2[_i];
|
||||
|
||||
if (i > 1) {
|
||||
_arr.push(i * i);
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
_didIteratorError = true;
|
||||
_iteratorError = err;
|
||||
} finally {
|
||||
try {
|
||||
if (!_iteratorNormalCompletion && _iterator["return"]) {
|
||||
_iterator["return"]();
|
||||
}
|
||||
} finally {
|
||||
if (_didIteratorError) {
|
||||
throw _iteratorError;
|
||||
}
|
||||
if (i > 1) {
|
||||
_arr.push(i * i);
|
||||
}
|
||||
}
|
||||
|
||||
return _arr;
|
||||
})();
|
||||
})();
|
||||
|
||||
@ -2,30 +2,13 @@
|
||||
|
||||
var arr = (function () {
|
||||
var _arr = [];
|
||||
var _iteratorNormalCompletion = true;
|
||||
var _didIteratorError = false;
|
||||
var _iteratorError = undefined;
|
||||
var _arr2 = [1, 2, 3];
|
||||
|
||||
try {
|
||||
for (var _iterator = [1, 2, 3][Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
|
||||
var i = _step.value;
|
||||
for (var _i = 0; _i < _arr2.length; _i++) {
|
||||
var i = _arr2[_i];
|
||||
|
||||
_arr.push(i * i);
|
||||
}
|
||||
} catch (err) {
|
||||
_didIteratorError = true;
|
||||
_iteratorError = err;
|
||||
} finally {
|
||||
try {
|
||||
if (!_iteratorNormalCompletion && _iterator["return"]) {
|
||||
_iterator["return"]();
|
||||
}
|
||||
} finally {
|
||||
if (_didIteratorError) {
|
||||
throw _iteratorError;
|
||||
}
|
||||
}
|
||||
_arr.push(i * i);
|
||||
}
|
||||
|
||||
return _arr;
|
||||
})();
|
||||
})();
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
function add() {
|
||||
return [for (i of [1, 2, 3]) i * this.multiplier];
|
||||
return [for (i of nums) i * this.multiplier];
|
||||
}
|
||||
|
||||
add.call({ multiplier: 5 });
|
||||
|
||||
@ -10,7 +10,7 @@ function add() {
|
||||
var _iteratorError = undefined;
|
||||
|
||||
try {
|
||||
for (var _iterator = [1, 2, 3][Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
|
||||
for (var _iterator = nums[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
|
||||
var i = _step.value;
|
||||
|
||||
_ref.push(i * _this.multiplier);
|
||||
@ -34,4 +34,4 @@ function add() {
|
||||
})();
|
||||
}
|
||||
|
||||
add.call({ multiplier: 5 });
|
||||
add.call({ multiplier: 5 });
|
||||
|
||||
3
vendor/.babelrc
vendored
Normal file
3
vendor/.babelrc
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
{
|
||||
"breakConfig": true
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user