Compare commits

...

65 Commits

Author SHA1 Message Date
Sebastian McKenzie
20d19735fc v5.5.7 2015-06-13 02:22:20 +01:00
Sebastian McKenzie
b5b6bf4ad5 add isDirective method, 2015-06-13 02:21:22 +01:00
Sebastian McKenzie
844c10cac0 fix reference to inferers 2015-06-13 02:20:04 +01:00
Sebastian McKenzie
43583e4e9d pick only current constant violation if it's of the same scope 2015-06-13 02:19:57 +01:00
Sebastian McKenzie
f5b921cda9 better errorWithNode that's consolidated across paths and files 2015-06-13 02:19:44 +01:00
Sebastian McKenzie
763892aa79 remove unused variable 2015-06-13 02:19:30 +01:00
Sebastian McKenzie
3e6eae4d1a Merge branch 'master' of github.com:babel/babel 2015-06-13 02:00:22 +01:00
Sebastian McKenzie
7c090c8580 Merge pull request #1740 from zertosh/cli-fixes
Really fix "--help"
2015-06-13 01:56:58 +01:00
Andres Suarez
a5f6c1c389 Really fix "--help" 2015-06-12 20:54:53 -04:00
Sebastian McKenzie
c159f2d982 Merge branch 'master' of github.com:babel/babel 2015-06-13 01:54:33 +01:00
Sebastian McKenzie
9205f10244 Merge pull request #1719 from jmm/internals-docs2
Internals documentation
2015-06-13 01:53:04 +01:00
Sebastian McKenzie
4cd7bcad59 Merge pull request #1727 from zertosh/cli-fixes
Fix "--help" distinguish optional transforms
2015-06-13 01:52:46 +01:00
Andres Suarez
7e9660efd3 Fix "--help" distinguish optional transforms 2015-06-12 20:51:52 -04:00
Sebastian McKenzie
2d66ce5224 Merge pull request #1724 from arthurvr/bool
Update `util.booleanify()` return type
2015-06-13 01:48:30 +01:00
Sebastian McKenzie
1257b2cf40 Merge pull request #1736 from grncdr/patch-1
Remove duplicate keys from alias-keys.json
2015-06-12 20:33:54 +01:00
Stephen Sugden
f21d935de5 Add aliases from JSX* tags to Expression 2015-06-12 12:24:24 -07:00
Stephen Sugden
2e20364793 Remove duplicate keys from alias-keys.json
Fixes #1734
2015-06-12 20:58:41 +02:00
Sebastian McKenzie
e47e8a187a Merge branch 'master' of github.com:babel/babel 2015-06-11 19:06:41 +01:00
Ingvar Stepanyan
26924d5944 Fix dependency reference of Symbol.hasInstance 2015-06-10 22:07:40 +03:00
Arthur Verschaeve
5eb1850a55 Update util.booleanify() return type
Ref 62f37c1e62
2015-06-10 16:54:43 +02:00
Sebastian McKenzie
333e287226 remove special minification.removeConsole ExpressionStatement handling 2015-06-10 13:14:44 +01:00
Sebastian McKenzie
80a77bd6a2 fix linting error 2015-06-10 03:16:07 +01:00
Sebastian McKenzie
c9286a1de1 rewrite option handling - fixes #1636 2015-06-10 03:07:06 +01:00
Sebastian McKenzie
52f614dcdf add better path execution status algo 2015-06-10 01:36:36 +01:00
Sebastian McKenzie
600367ae25 add t.COMPARISON_BINARY_OPERATORS 2015-06-10 01:34:51 +01:00
Sebastian McKenzie
b761cba135 split auxiliary comment option into before and after - fixes #1721 2015-06-10 01:34:44 +01:00
Sebastian McKenzie
947d3e262d push newline after decorator when doing code gen - fixes #1713 2015-06-10 01:19:58 +01:00
Sebastian McKenzie
4061bea528 change execution order of module metadata visitor to resolve module source before building up metadata tree - fixes #1720 2015-06-10 01:15:11 +01:00
Sebastian McKenzie
de195e5bfc Merge branch 'master' of github.com:babel/babel 2015-06-10 01:10:41 +01:00
Sebastian McKenzie
3bcef86973 Merge pull request #1720 from chadhietala/failing-metadata-test
Metadata object does not take in account resolveModuleSource()
2015-06-10 01:10:09 +01:00
Sebastian McKenzie
fa670ac71e visually split up inference inferer methods 2015-06-09 22:52:21 +01:00
Sebastian McKenzie
572261f9ce add support for typecasts in path static evaluation 2015-06-09 22:52:00 +01:00
Chad Hietala
8a320d53a5 Metadata object does not take in account resolveModuleSource()
This adds a failing test to illustrate the metadata object not reflecting what is returned from resolveModuleSource(). I might also not understand resolveModuleSource's purpose. However, this was the hook mentioned here https://github.com/babel/babel/issues/1602.
2015-06-09 14:26:33 -07:00
Jesse McCarthy
0650eedeb6 Add reference to doc dir to CONTRIBUTING. 2015-06-09 15:37:01 -04:00
Jesse McCarthy
2282d066a2 Start doc dir for internals documentation. 2015-06-09 15:37:01 -04:00
Sebastian McKenzie
f4d7cc55c1 split inference logic into separate folder 2015-06-09 14:02:57 +01:00
Sebastian McKenzie
eaaa279aa5 add let binding collision todo 2015-06-09 04:08:44 +01:00
Sebastian McKenzie
0595e06e29 5.5.6 2015-06-09 04:08:36 +01:00
Sebastian McKenzie
9b27a170ae v5.5.6 2015-06-09 04:07:15 +01:00
Sebastian McKenzie
1db232da9e add 5.5.6 changelog 2015-06-09 04:06:06 +01:00
Sebastian McKenzie
4cc844f410 take into consideration assignment expressions in loop heads when replacing let references - fixes #1707 2015-06-09 04:04:14 +01:00
Sebastian McKenzie
024ae670cb fix traceur test blacklist 2015-06-09 03:48:22 +01:00
Sebastian McKenzie
429edda9c0 ignore StringIterator traceur test 2015-06-09 03:40:08 +01:00
Sebastian McKenzie
05b13b9ea3 fix mistyped parameter name of t.createTypeAnnotationBasedOnTypeof 2015-06-09 03:26:40 +01:00
Sebastian McKenzie
b7320ce400 add t.createTypeAnnotationBasedOnTypeof method 2015-06-09 03:23:28 +01:00
Sebastian McKenzie
0c37b7b973 add typeof conditional inference 2015-06-09 03:20:32 +01:00
Sebastian McKenzie
bb36dbd8d9 update to latest traceur and enable now passing tests 2015-06-09 03:20:02 +01:00
Sebastian McKenzie
2dd8c40618 heavily simplify constants transformer 2015-06-09 00:31:18 +01:00
Sebastian McKenzie
33128b0ccf remove unused declaration 2015-06-08 23:59:53 +01:00
Sebastian McKenzie
cf25424295 fix duplicate declaration 2015-06-08 23:49:00 +01:00
Sebastian McKenzie
7492074794 infer types of bindings inside of conditionals based on usage 2015-06-08 23:43:46 +01:00
Sebastian McKenzie
c4a491123e disallow line terminator after async contextual keyword - fixes #1711 2015-06-08 21:25:16 +01:00
Sebastian McKenzie
55ad88fe4e don't override types parameter 2015-06-08 14:59:19 +01:00
Sebastian McKenzie
7170dbced8 Merge branch 'master' of github.com:babel/babel 2015-06-08 14:53:54 +01:00
Sebastian McKenzie
b0971412a2 add inference for null, remove any type parameter from inferred arrays, add todo comment 2015-06-08 14:52:35 +01:00
Sebastian McKenzie
a6b374a681 save union type in _getTypeAnnotationBindingConstantViolations to prevent infinite recursion 2015-06-08 14:52:13 +01:00
Sebastian McKenzie
2d0355b3b9 merge previous bindings constantViolations and path onto new bindings constantViolations 2015-06-08 14:49:09 +01:00
Sebastian McKenzie
7fade101be move down module TypeAlias check 2015-06-08 14:47:58 +01:00
Sebastian McKenzie
0918da8569 Merge pull request #1708 from hawkrives/patch-2
Update README.md for the Slack channel
2015-06-08 12:35:08 +01:00
Hawken Rives
917db622c4 Update README.md
Switch out the gitter link for slack.
2015-06-08 20:33:09 +09:00
Sebastian McKenzie
f7ee6fbd20 move travis notifications from gitter to slack 2015-06-08 12:20:38 +01:00
Sebastian McKenzie
5899e9a0be don't consider type aliases to be a default declaration - fixes #1705 2015-06-08 12:20:30 +01:00
Sebastian McKenzie
d41cb11545 fix registerDeclaration for FlowDeclarations 2015-06-08 01:46:05 +01:00
Sebastian McKenzie
3ad909a4ae add 5.5.5 changelog 2015-06-08 01:45:56 +01:00
Sebastian McKenzie
4bafdf733c 5.5.5 2015-06-08 01:29:54 +01:00
49 changed files with 1126 additions and 618 deletions

View File

@@ -11,9 +11,4 @@ before_script: "npm install -g codeclimate-test-reporter"
script: "make test-travis"
notifications:
webhooks:
urls:
- https://webhooks.gitter.im/e/acf1870e9d223c65e8d5
on_success: always
on_failure: always
on_start: false
slack: babeljs:5Wy4QX13KVkGy9CnU0rmvgeK

View File

@@ -13,6 +13,16 @@ _Note: Gaps between patch versions are faulty/broken releases._
See [CHANGELOG - 6to5](CHANGELOG-6to5.md) for the pre-4.0.0 version changelog.
## 5.5.6
* **Bug Fix**
* Fix `let` binding collision in loop head not properly replacing `AssignmentExpression`s.
## 5.5.5
* **Bug Fix**
* Fix `file.opts` not being set before `file.log.deprecate` was called causing a `ReferenceError` as it was checking for a property on it.
## 5.5.4
* **Bug Fix**

View File

@@ -12,6 +12,8 @@
<strong><a href="#dependencies">Dependencies</a></strong>
|
<strong><a href="#code-standards">Code Standards</a></strong>
|
<strong><a href="#internals">Internals</a></strong>
</p>
----
@@ -173,3 +175,6 @@ your [`$PATH`](http://unix.stackexchange.com/questions/26047/how-to-correctly-ad
* **Declaration**
* No unused variables
* No pollution of global variables and prototypes
#### Internals
Please see [`/doc`](/doc) for internals documentation relevant to developing babel.

View File

@@ -9,7 +9,7 @@
</p>
<p align="center">
For questions and support please visit the <a href="https://gitter.im/babel/babel">gitter room</a> or <a href="http://stackoverflow.com/questions/tagged/babeljs">StackOverflow</a>. The Babel issue tracker is <strong>exclusively</strong> for bug reports and feature requests.
For questions and support please visit the <a href="https://babel-slack.herokuapp.com">slack channel</a> or <a href="http://stackoverflow.com/questions/tagged/babeljs">StackOverflow</a>. The Babel issue tracker is <strong>exclusively</strong> for bug reports and feature requests.
</p>
<p align="center">

4
doc/index.md Normal file
View File

@@ -0,0 +1,4 @@
This is a collection of documentation about babel internals, for use in development of babel.
# [Properties of nodes](/doc/node-props.md)
These are properties babel stores in AST node objects for internal use, as opposed to properties that are part of the AST spec (ESTree at the time of this writing).

11
doc/node-props.md Normal file
View File

@@ -0,0 +1,11 @@
# Properties of nodes
These are properties babel stores in AST node objects for internal use, as opposed to properties that are part of the AST spec (ESTree at the time of this writing).
## `_blockHoist`
`node._blockHoist != null` triggers the [block-hoist transformer](/src/babel/transformation/transformers/internal/block-hoist.js). Value should be `true` or an integer in the range `0..3`. `true` is equivalent to `2`. The value indicates whether the node should be hoisted and to what degree. See the source code for more detailed information.
## `_paths`
Stores a representation of a node's position in the tree and relationship to other nodes.
## `shadow`
A truthy value on a function node triggers the [shadow-functions transformer](/src/babel/transformation/transformers/internal/shadow-functions.js), which transforms the node so that it references (or inherits) `arguments` and `this` from the parent scope. It is invoked for arrow functions, for example.

View File

@@ -1,7 +1,7 @@
{
"name": "babel-core",
"description": "A compiler for writing next generation JavaScript",
"version": "5.5.5",
"version": "5.5.7",
"author": "Sebastian McKenzie <sebmck@gmail.com>",
"homepage": "https://babeljs.io/",
"license": "MIT",

View File

@@ -35,7 +35,7 @@ each(options, function (option, key) {
if (option.description) desc.push(option.description);
commander.option(arg, desc.join(" "));
})
});
commander.option("-x, --extensions [extensions]", "List of extensions to compile when a directory has been input [.es6,.js,.es,.jsx]");
commander.option("-w, --watch", "Recompile files on changes");
@@ -51,7 +51,7 @@ commander.on("--help", function () {
each(keys(obj).sort(), function (key) {
if (key[0] === "_") return;
if (obj[key].optional) key = "[" + key + "]";
if (obj[key].metadata && obj[key].metadata.optional) key = "[" + key + "]";
console.log(" - " + key);
});
@@ -118,11 +118,16 @@ if (errors.length) {
var opts = exports.opts = {};
each(options, function (opt, key) {
opts[key] = commander[key];
if (commander[key] !== undefined) {
opts[key] = commander[key];
}
});
opts.ignore = util.arrayify(opts.ignore, util.regexify);
opts.only = util.arrayify(opts.only, util.regexify);
if (opts.only) {
opts.only = util.arrayify(opts.only, util.regexify);
}
var fn;

View File

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

View File

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

View File

@@ -292,7 +292,7 @@ pp.parseExprAtom = function(refShorthandDefaultPos) {
//
if (this.options.features["es7.asyncFunctions"]) {
// async functions!
if (id.name === "async") {
if (id.name === "async" && !this.canInsertSemicolon()) {
// arrow functions
if (this.type === tt.parenL) {
let expr = this.parseParenAndDistinguishExpression(start, true, true)

View File

@@ -9,6 +9,7 @@ var STATE_KEYS = [
"lastTokEnd",
"lineStart",
"startLoc",
"curLine",
"endLoc",
"start",
"pos",

View File

@@ -83,10 +83,13 @@ pp.parseStatement = function(declaration, topLevel) {
return starttype === tt._import ? this.parseImport(node) : this.parseExport(node)
case tt.name:
if (this.options.features["es7.asyncFunctions"] && this.value === "async" && this.lookahead().type === tt._function) {
this.next();
this.expect(tt._function);
return this.parseFunction(node, true, false, true);
if (this.options.features["es7.asyncFunctions"] && this.value === "async") {
var lookahead = this.lookahead();
if (lookahead.type === tt._function && !this.canInsertSemicolon.call(lookahead)) {
this.next();
this.expect(tt._function);
return this.parseFunction(node, true, false, true);
}
}
// If the statement does not start with a statement keyword or a

View File

@@ -8,7 +8,7 @@ export { util, acorn, transform };
export { pipeline } from "../transformation";
export { canCompile } from "../util";
export { default as options } from "../transformation/file/options";
export { default as options } from "../transformation/file/options/config";
export { default as Transformer } from "../transformation/transformer";
export { default as TransformerPipeline } from "../transformation/transformer-pipeline";
export { default as traverse } from "../traversal";

View File

@@ -1,6 +1,6 @@
import sourceMapSupport from "source-map-support";
import * as registerCache from "./cache";
import resolveRc from "../../tools/resolve-rc";
import resolveRc from "../../transformation/file/options/resolve-rc";
import extend from "lodash/object/extend";
import * as babel from "../node";
import each from "lodash/collection/each";
@@ -90,7 +90,7 @@ var shouldIgnore = function (filename) {
if (!ignore && !only) {
return getRelativePath(filename).split(path.sep).indexOf("node_modules") >= 0;
} else {
return util.shouldIgnore(filename, ignore || [], only || []);
return util.shouldIgnore(filename, ignore || [], only);
}
};

View File

@@ -70,6 +70,7 @@ export function Super() {
export function Decorator(node, print) {
this.push("@");
print.plain(node.expression);
this.newline();
}
export function CallExpression(node, print) {

View File

@@ -1,59 +1,5 @@
import stripJsonComments from "strip-json-comments";
import merge from "../helpers/merge";
import path from "path";
import fs from "fs";
console.trace("I know someone out there is hotlinking straight to this file. This is a " +
"PRIVATE API. I hate you, but I wont break your code just because you're a " +
"programmer who practices bad habits.");
var cache = {};
var jsons = {};
function exists(filename) {
if (!fs.existsSync) return false;
var cached = cache[filename];
if (cached != null) return cached;
return cache[filename] = fs.existsSync(filename);
}
export default function (loc, opts = {}) {
var rel = ".babelrc";
if (!opts.babelrc) {
opts.babelrc = [];
}
function find(start, rel) {
var file = path.join(start, rel);
if (opts.babelrc.indexOf(file) >= 0) {
return;
}
if (exists(file)) {
var content = fs.readFileSync(file, "utf8");
var json;
try {
json = jsons[content] = jsons[content] || JSON.parse(stripJsonComments(content));
} catch (err) {
err.message = `${file}: ${err.message}`;
throw err;
}
opts.babelrc.push(file);
if (json.breakConfig) return;
merge(opts, json);
}
var up = path.dirname(start);
if (up !== start) { // root
find(up, rel);
}
}
if (opts.babelrc.indexOf(loc) < 0 && opts.breakConfig !== true) {
find(loc, rel);
}
return opts;
}
export { default } from "../transformation/file/options/resolve-rc";

View File

@@ -1,5 +1,5 @@
import { validateOption, normaliseOptions, config as optionsConfig } from "./options";
import convertSourceMap from "convert-source-map";
import * as optionParsers from "./option-parsers";
import moduleFormatters from "../modules";
import PluginManager from "./plugin-manager";
import shebangRegex from "shebang-regex";
@@ -7,7 +7,7 @@ import NodePath from "../../traversal/path";
import Transformer from "../transformer";
import isFunction from "lodash/lang/isFunction";
import isAbsolute from "path-is-absolute";
import resolveRc from "../../tools/resolve-rc";
import resolveRc from "./options/resolve-rc";
import sourceMap from "source-map";
import generate from "../../generation";
import codeFrame from "../../helpers/code-frame";
@@ -52,7 +52,7 @@ export default class File {
this.log = new Logger(this, opts.filename || "unknown");
this.ast = {};
this.normalizeOptions(opts);
this.normaliseOptions(opts);
this.buildTransformers();
@@ -98,10 +98,10 @@ export default class File {
static soloHelpers = [];
static options = require("./options");
static options = optionsConfig;
normalizeOptions(opts: Object) {
opts = this.opts = assign({}, opts);
normaliseOptions(opts: Object) {
opts = this.opts = normaliseOptions(assign({}, opts));
// resolve babelrc
if (opts.filename) {
@@ -120,26 +120,28 @@ export default class File {
// merge in environment options
var envKey = process.env.BABEL_ENV || process.env.NODE_ENV || "development";
if (opts.env) merge(opts, opts.env[envKey]);
if (opts.env) merge(opts, normaliseOptions(opts.env[envKey]));
// normalise options
for (let key in File.options) {
let option = File.options[key];
var val = opts[key];
var val = opts[key];
// optional
if (!val && option.optional) continue;
// deprecated
if (val && option.deprecated) {
this.log.deprecate("Deprecated option " + key + ": " + option.deprecated);
}
if (val == null) {
val = clone(option.default);
}
// default
if (val == null) val = clone(option.default);
var optionParser = optionParsers[option.type];
if (optionParser) val = optionParser(key, val, this.pipeline);
// validate
if (val) val = validateOption(key, val, this.pipeline);
// aaliases
if (option.alias) {
opts[option.alias] = opts[option.alias] || val;
} else {
@@ -164,7 +166,10 @@ export default class File {
opts.basename = path.basename(opts.filename, path.extname(opts.filename));
opts.ignore = util.arrayify(opts.ignore, util.regexify);
opts.only = util.arrayify(opts.only, util.regexify);
if (opts.only) {
opts.only = util.arrayify(opts.only, util.regexify);
}
defaults(opts, {
moduleRoot: opts.sourceRoot
@@ -341,14 +346,24 @@ export default class File {
}
attachAuxiliaryComment(node: Object): Object {
var comment = this.opts.auxiliaryComment;
if (comment) {
var beforeComment = this.opts.auxiliaryCommentBefore;
if (beforeComment) {
node.leadingComments = node.leadingComments || [];
node.leadingComments.push({
type: "CommentLine",
value: " " + comment
value: " " + beforeComment
});
}
var afterComment = this.opts.auxiliaryCommentAfter;
if (afterComment) {
node.trailingComments = node.trailingComments || [];
node.trailingComments.push({
type: "CommentLine",
value: " " + afterComment
});
}
return node;
}
@@ -400,11 +415,12 @@ export default class File {
errorWithNode(node, msg, Error = SyntaxError) {
var err;
if (node.loc) {
if (node && node.loc) {
var loc = node.loc.start;
err = new Error(`Line ${loc.line}: ${msg}`);
err.loc = loc;
} else {
// todo: find errors with nodes inside to at least point to something
err = new Error("There's been an error on a dynamic node. This is almost certainly an internal error. Please report it.");
}
return err;

View File

@@ -1,27 +0,0 @@
import * as util from "../../util";
export function transformerList(key, val, pipeline) {
val = util.arrayify(val);
if (val.indexOf("all") >= 0 || val.indexOf(true) >= 0) {
val = Object.keys(pipeline.transformers);
}
return pipeline._ensureTransformerNames(key, val);
}
export function number(key, val) {
return +val;
}
export function boolean(key, val) {
return !!val;
}
export function booleanString(key, val) {
return util.booleanify(val);
}
export function list(key, val) {
return util.list(val);
}

View File

@@ -78,7 +78,8 @@
"blacklist": {
"type": "transformerList",
"description": "blacklist of transformers to NOT use",
"shorthand": "b"
"shorthand": "b",
"default": []
},
"whitelist": {
@@ -90,7 +91,8 @@
"optional": {
"type": "transformerList",
"description": "list of optional transformers to enable"
"description": "list of optional transformers to enable",
"default": []
},
"modules": {
@@ -122,12 +124,14 @@
"plugins": {
"type": "list",
"description": ""
"description": "",
"default": []
},
"ignore": {
"type": "list",
"description": "list of glob paths to **not** compile"
"description": "list of glob paths to **not** compile",
"default": []
},
"only": {
@@ -173,12 +177,23 @@
},
"auxiliaryComment": {
"deprecated": "renamed to auxiliaryCommentBefore",
"shorthand": "a",
"alias": "auxiliaryCommentBefore"
},
"auxiliaryCommentBefore": {
"type": "string",
"default": "",
"shorthand": "a",
"description": "attach a comment before all helper declarations and auxiliary code"
},
"auxiliaryCommentAfter": {
"type": "string",
"default": "",
"description": "attach a comment after all helper declarations and auxiliary code"
},
"externalHelpers": {
"type": "boolean",
"default": false,

View File

@@ -0,0 +1,31 @@
import * as parsers from "./parsers";
import config from "./config";
export { config };
export function validateOption(key, val, pipeline) {
var opt = config[key];
var parser = opt && parsers[opt.type];
if (parser && parser.validate) {
return parser.validate(key, val, pipeline);
} else {
return val;
}
}
export function normaliseOptions(options = {}) {
for (var key in options) {
var val = options[key];
if (val == null) continue;
var opt = config[key];
if (!opt) continue;
var parser = parsers[opt.type];
if (parser) val = parser(val);
options[key] = val;
}
return options;
}

View File

@@ -0,0 +1,29 @@
import * as util from "../../../util";
export function transformerList(val) {
return util.arrayify(val);
}
transformerList.validate = function (key, val, pipeline) {
if (val.indexOf("all") >= 0 || val.indexOf(true) >= 0) {
val = Object.keys(pipeline.transformers);
}
return pipeline._ensureTransformerNames(key, val);
};
export function number(val) {
return +val;
}
export function boolean(val) {
return !!val;
}
export function booleanString(val) {
return util.booleanify(val);
}
export function list(val) {
return util.list(val);
}

View File

@@ -0,0 +1,62 @@
import stripJsonComments from "strip-json-comments";
import { normaliseOptions } from "./index";
import merge from "../../../helpers/merge";
import path from "path";
import fs from "fs";
var cache = {};
var jsons = {};
function exists(filename) {
if (!fs.existsSync) return false;
var cached = cache[filename];
if (cached != null) return cached;
return cache[filename] = fs.existsSync(filename);
}
export default function (loc, opts = {}) {
var rel = ".babelrc";
if (!opts.babelrc) {
opts.babelrc = [];
}
function find(start, rel) {
var file = path.join(start, rel);
if (opts.babelrc.indexOf(file) >= 0) {
return;
}
if (exists(file)) {
var content = fs.readFileSync(file, "utf8");
var json;
try {
json = jsons[content] = jsons[content] || JSON.parse(stripJsonComments(content));
normaliseOptions(json);
} catch (err) {
err.message = `${file}: ${err.message}`;
throw err;
}
opts.babelrc.push(file);
if (json.breakConfig) return;
merge(opts, json);
}
var up = path.dirname(start);
if (up !== start) { // root
find(up, rel);
}
}
if (opts.babelrc.indexOf(loc) < 0 && opts.breakConfig !== true) {
find(loc, rel);
}
return opts;
}

View File

@@ -69,54 +69,58 @@ var remapVisitor = {
};
var metadataVisitor = {
ModuleDeclaration(node, parent, scope, formatter) {
if (node.source) {
node.source.value = formatter.file.resolveModuleSource(node.source.value);
ModuleDeclaration: {
enter(node, parent, scope, formatter) {
if (node.source) {
node.source.value = formatter.file.resolveModuleSource(node.source.value);
}
}
},
ImportDeclaration(node, parent, scope, formatter) {
formatter.hasLocalImports = true;
ImportDeclaration: {
exit(node, parent, scope, formatter) {
formatter.hasLocalImports = true;
var specifiers = [];
var imported = [];
formatter.metadata.imports.push({
source: node.source.value,
imported,
specifiers
});
var specifiers = [];
var imported = [];
formatter.metadata.imports.push({
source: node.source.value,
imported,
specifiers
});
for (var specifier of (this.get("specifiers"): Array)) {
var ids = specifier.getBindingIdentifiers();
extend(formatter.localImports, ids);
for (var specifier of (this.get("specifiers"): Array)) {
var ids = specifier.getBindingIdentifiers();
extend(formatter.localImports, ids);
var local = specifier.node.local.name;
var local = specifier.node.local.name;
if (specifier.isImportDefaultSpecifier()) {
imported.push("default");
specifiers.push({
kind: "named",
imported: "default",
local
});
}
if (specifier.isImportDefaultSpecifier()) {
imported.push("default");
specifiers.push({
kind: "named",
imported: "default",
local
});
}
if (specifier.isImportSpecifier()) {
var importedName = specifier.node.imported.name;
imported.push(importedName);
specifiers.push({
kind: "named",
imported: importedName,
local
});
}
if (specifier.isImportSpecifier()) {
var importedName = specifier.node.imported.name;
imported.push(importedName);
specifiers.push({
kind: "named",
imported: importedName,
local
});
}
if (specifier.isImportNamespaceSpecifier()) {
imported.push("*");
specifiers.push({
kind: "namespace",
local
});
if (specifier.isImportNamespaceSpecifier()) {
imported.push("*");
specifiers.push({
kind: "namespace",
local
});
}
}
}
},
@@ -132,6 +136,7 @@ var metadataVisitor = {
var declar = this.get("declaration");
if (declar.isStatement()) {
var bindings = declar.getBindingIdentifiers();
for (var name in bindings) {
var binding = bindings[name];
formatter._addExport(name, binding);
@@ -205,7 +210,7 @@ var metadataVisitor = {
});
}
if (!t.isExportDefaultDeclaration(node)) {
if (!t.isExportDefaultDeclaration(node) && !declar.isTypeAlias()) {
var onlyDefault = node.specifiers && node.specifiers.length === 1 && t.isSpecifierDefault(node.specifiers[0]);
if (!onlyDefault) {
formatter.hasNonDefaultExports = true;

View File

@@ -116,6 +116,13 @@ function traverseReplace(node, parent, scope, remaps) {
replace(node, parent, scope, remaps);
}
if (t.isAssignmentExpression(node)) {
var ids = t.getBindingIdentifiers(node);
for (var name in ids) {
replace(ids[name], parent, scope, remaps);
}
}
scope.traverse(node, replaceVisitor, remaps);
}
@@ -330,6 +337,7 @@ class BlockScoping {
// this is the defining identifier of a declaration
var ref = letRefs[key];
// todo: could skip this if the colliding binding is in another function
if (scope.parentHasBinding(key) || scope.hasGlobal(key)) {
var uid = scope.generateUidIdentifier(ref.name).name;
ref.name = uid;

View File

@@ -1,41 +1,18 @@
import * as messages from "../../../messages";
function checkPath(path, file) {
var ids = path.getBindingIdentifiers();
for (var name in ids) {
var id = ids[name];
var binding = path.scope.getBinding(name);
// no binding exists
if (!binding) continue;
export function Scope(node, parent, scope) {
for (var name in scope.bindings) {
var binding = scope.bindings[name];
// not a constant
if (binding.kind !== "const" && binding.kind !== "module") continue;
// check if the assignment id matches the constant declaration id
// if it does then it was the id used to initially declare the
// constant so we can just ignore it
if (binding.identifier === id) continue;
throw file.errorWithNode(id, messages.get("readOnly", name));
for (var violation of (binding.constantViolations: Array)) {
throw violation.errorWithNode(messages.get("readOnly", name));
}
}
}
export function AssignmentExpression(node, parent, scope, file) {
checkPath(this, file);
}
export { AssignmentExpression as UpdateExpression };
export function VariableDeclaration(node) {
if (node.kind === "const") node.kind = "let";
}
export function ForXStatement(node, parent, scope, file) {
var left = this.get("left");
if (left.isIdentifier() || left.isPattern()) {
checkPath(left, file);
}
}

View File

@@ -33,7 +33,7 @@ var memberExpressionOptimisationVisitor = {
// if we know that this member expression is referencing a number then we can safely
// optimise it
var prop = this.parentPath.get("property");
if (prop.isGenericType("Number")) {
if (prop.isBaseType("number")) {
state.candidates.push(this);
return;
}

View File

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

View File

@@ -1,5 +1,3 @@
import * as t from "../../../types";
export var metadata = {
optional: true,
group: "builtin-pre"
@@ -7,10 +5,6 @@ export var metadata = {
export function CallExpression(node, parent) {
if (this.get("callee").matchesPattern("console", true)) {
if (t.isExpressionStatement(parent)) {
this.parentPath.dangerouslyRemove();
} else {
this.dangerouslyRemove();
}
this.dangerouslyRemove();
}
}

View File

@@ -108,7 +108,7 @@
"Symbol": {
"for": "symbol/for",
"hasInstance": "symbol/for-instance",
"hasInstance": "symbol/has-instance",
"is-concat-spreadable": "symbol/is-concat-spreadable",
"iterator": "symbol/iterator",
"keyFor": "symbol/key-for",

View File

@@ -2,8 +2,8 @@
- `context` - Methods responsible for maintaing TraversalContexts.
- `conversion` - Methods that convert the path node into another node or some other type of data.
- `evaluation` - Methods responsible for statically evaluating code.
- `inference` - Methods responsible for type inferrence etc.
- `modification` - Methods that modify the path/node in some ways.
- `resolution` - Methods responsible for type inferrence etc.
- `replacement` - Methods responsible for replacing a node with another.
- `removal` - Methods responsible for removing a node.
- `family` - Methods responsible for dealing with/retrieving children or siblings.

View File

@@ -11,6 +11,19 @@ export function findParent(callback) {
return null;
}
/**
* Description
*/
export function getStatementParent() {
var path = this;
do {
if (Array.isArray(path.container)) {
return path;
}
} while(path = path.parentPath);
}
/**
* Description
*/

View File

@@ -76,6 +76,10 @@ export function evaluate(): { confident: boolean; value: any } {
}
}
if (path.isTypeCastExpression()) {
return evaluate(path.get("expression"));
}
if (path.isIdentifier() && !path.scope.hasBinding(node.name, true)) {
if (node.name === "undefined") {
return undefined;

View File

@@ -81,10 +81,7 @@ export default class NodePath {
*/
errorWithNode(msg, Error = SyntaxError) {
var loc = this.node.loc.start;
var err = new Error(`Line ${loc.line}: ${msg}`);
err.loc = loc;
return err;
return this.hub.file.errorWithNode(this.node, msg, Error);
}
/**
@@ -97,7 +94,7 @@ export default class NodePath {
}
assign(NodePath.prototype, require("./ancestry"));
assign(NodePath.prototype, require("./resolution"));
assign(NodePath.prototype, require("./inference"));
assign(NodePath.prototype, require("./replacement"));
assign(NodePath.prototype, require("./evaluation"));
assign(NodePath.prototype, require("./conversion"));

View File

@@ -0,0 +1,89 @@
import * as inferers from "./inferers";
import * as t from "../../../types";
/**
* Infer the type of the current `NodePath`.
*/
export function getTypeAnnotation() {
if (this.typeAnnotation) return this.typeAnnotation;
var type = this._getTypeAnnotation() || t.anyTypeAnnotation();
if (t.isTypeAnnotation(type)) type = type.typeAnnotation;
return this.typeAnnotation = type;
}
/**
* todo: split up this method
*/
export function _getTypeAnnotation(): ?Object {
var node = this.node;
if (!node) {
// handle initializerless variables, add in checks for loop initializers too
if (this.key === "init" && this.parentPath.isVariableDeclarator()) {
var declar = this.parentPath.parentPath;
var declarParent = declar.parentPath;
// for (var NODE in bar) {}
if (declar.key === "left" && declarParent.isForInStatement()) {
return t.stringTypeAnnotation();
}
// for (var NODE of bar) {}
if (declar.key === "left" && declarParent.isForOfStatement()) {
return t.anyTypeAnnotation();
}
return t.voidTypeAnnotation();
} else {
return;
}
}
if (node.typeAnnotation) {
return node.typeAnnotation;
}
var inferer = inferers[node.type];
if (inferer) {
return inferer.call(this, node);
}
inferer = inferers[this.parentPath.type];
if (inferer && inferer.validParent) {
return this.parentPath.getTypeAnnotation();
}
}
/**
* Description
*/
export function isBaseType(baseName: string): boolean {
var type = this.getTypeAnnotation();
if (baseName === "string") {
return t.isStringTypeAnnotation(type);
} else if (baseName === "number") {
return t.isNumberTypeAnnotation(type);
} else if (baseName === "boolean") {
return t.isBooleanTypeAnnotation(type);
} else if (baseName === "any") {
return t.isAnyTypeAnnotation(type);
} else if (baseName === "mixed") {
return t.isMixedTypeAnnotation(type);
} else {
throw new Error(`Unknown base type ${baseName}`);
}
}
/**
* Description
*/
export function isGenericType(genericName: string): boolean {
var type = this.getTypeAnnotation();
return t.isGenericTypeAnnotation(type) && t.isIdentifier(type.id, { name: genericName });
}

View File

@@ -0,0 +1,187 @@
import * as t from "../../../types";
export default function (node) {
if (!this.isReferenced()) return;
// check if a binding exists of this value and if so then return a union type of all
// possible types that the binding could be
var binding = this.scope.getBinding(node.name);
if (binding) {
if (binding.identifier.typeAnnotation) {
return binding.identifier.typeAnnotation;
} else {
return getTypeAnnotationBindingConstantViolations(this, node.name);
}
}
// built-in values
if (node.name === "undefined") {
return t.voidTypeAnnotation();
} else if (node.name === "NaN" || node.name === "Infinity") {
return t.numberTypeAnnotation();
} else if (node.name === "arguments") {
// todo
}
}
function getTypeAnnotationBindingConstantViolations(path, name) {
var binding = path.scope.getBinding(name);
var types = [];
path.typeAnnotation = t.unionTypeAnnotation(types);
var functionConstantViolations = [];
var constantViolations = getConstantViolationsBefore(binding, path, functionConstantViolations);
var testType = getConditionalAnnotation(path, name);
if (testType) {
var testConstantViolations = getConstantViolationsBefore(binding, testType.ifStatement);
// remove constant violations observed before the IfStatement
constantViolations = constantViolations.filter((path) => testConstantViolations.indexOf(path) < 0);
// clear current types and add in observed test type
types.push(testType.typeAnnotation);
}
if (constantViolations.length) {
// pick one constant from each scope which will represent the last possible
// control flow path that it could've taken/been
var rawConstantViolations = constantViolations.reverse();
var visitedScopes = [];
constantViolations = [];
for (let violation of (rawConstantViolations: Array)) {
var violationScope = violation.scope;
if (visitedScopes.indexOf(violationScope) >= 0) continue;
visitedScopes.push(violationScope);
constantViolations.push(violation);
if (violationScope === path.scope) {
constantViolations = [violation];
break;
}
}
// add back on function constant violations since we can't track calls
constantViolations = constantViolations.concat(functionConstantViolations);
// push on inferred types of violated paths
for (let violation of (constantViolations: Array)) {
types.push(violation.getTypeAnnotation());
}
}
if (types.length) {
return t.createUnionTypeAnnotation(types);
}
}
function getConstantViolationsBefore(binding, path, functions) {
var violations = binding.constantViolations.slice();
violations.unshift(binding.path);
return violations.filter((violation) => {
violation = violation.resolve();
var status = violation._guessExecutionStatusRelativeTo(path);
if (functions && status === "function") functions.push(violation);
return status === "before";
});
}
function inferAnnotationFromBinaryExpression(name, path) {
var operator = path.node.operator;
var right = path.get("right").resolve();
var left = path.get("left").resolve();
var target;
if (left.isIdentifier({ name })) {
target = right;
} else if (right.isIdentifier({ name })) {
target = left;
}
if (target) {
if (operator === "===") {
return target.getTypeAnnotation();
} else if (t.BOOLEAN_NUMBER_BINARY_OPERATORS.indexOf(operator) >= 0) {
return t.numberTypeAnnotation();
} else {
return;
}
} else {
if (operator !== "===") return;
}
//
var typeofPath;
var typePath;
if (left.isUnaryExpression({ operator: "typeof" })) {
typeofPath = left;
typePath = right;
} else if (right.isUnaryExpression({ operator: "typeof" })) {
typeofPath = right;
typePath = left;
}
if (!typePath && !typeofPath) return;
// ensure that the type path is a Literal
typePath = typePath.resolve();
if (!typePath.isLiteral()) return;
// and that it's a string so we can infer it
var typeValue = typePath.node.value;
if (typeof typeValue !== "string") return;
// and that the argument of the typeof path references us!
if (!typeofPath.get("argument").isIdentifier({ name })) return;
// turn type value into a type annotation
return t.createTypeAnnotationBasedOnTypeof(typePath.node.value);
}
function getParentConditionalPath(path) {
var parentPath;
while (parentPath = path.parentPath) {
if (parentPath.isIfStatement() || parentPath.isConditionalExpression()) {
if (path.key === "test") {
return;
} else {
return parentPath;
}
} else {
path = parentPath;
}
}
}
function getConditionalAnnotation(path, name) {
var ifStatement = getParentConditionalPath(path);
if (!ifStatement) return;
var test = ifStatement.get("test");
var paths = [test];
var types = [];
do {
let path = paths.shift().resolve();
if (path.isLogicalExpression()) {
paths.push(path.get("left"));
paths.push(path.get("right"));
}
if (path.isBinaryExpression()) {
var type = inferAnnotationFromBinaryExpression(name, path);
if (type) types.push(type);
}
} while(paths.length);
if (types.length) {
return {
typeAnnotation: t.createUnionTypeAnnotation(types),
ifStatement
};
} else {
return getConditionalAnnotation(ifStatement, name);
}
}

View File

@@ -0,0 +1,191 @@
import * as t from "../../../types";
export { default as Identifier } from "./inferer-reference";
//
export function VariableDeclarator() {
var id = this.get("id");
if (id.isIdentifier()) {
return this.get("init").getTypeAnnotation();
} else {
return;
}
}
//
export function TypeCastExpression(node) {
return node.typeAnnotation;
}
TypeCastExpression.validParent = true;
//
export function NewExpression(node) {
if (this.get("callee").isIdentifier()) {
// only resolve identifier callee
return t.genericTypeAnnotation(node.callee);
}
}
//
export function TemplateLiteral() {
return t.stringTypeAnnotation();
}
//
export function UnaryExpression(node) {
let operator = node.operator;
if (operator === "void") {
return t.voidTypeAnnotation();
} else if (t.NUMBER_UNARY_OPERATORS.indexOf(operator) >= 0) {
return t.numberTypeAnnotation();
} else if (t.STRING_UNARY_OPERATORS.indexOf(operator) >= 0) {
return t.stringTypeAnnotation();
} else if (t.BOOLEAN_UNARY_OPERATORS.indexOf(operator) >= 0) {
return t.booleanTypeAnnotation();
}
}
//
export function BinaryExpression(node) {
let operator = node.operator;
if (t.NUMBER_BINARY_OPERATORS.indexOf(operator) >= 0) {
return t.numberTypeAnnotation();
} else if (t.BOOLEAN_BINARY_OPERATORS.indexOf(operator) >= 0) {
return t.booleanTypeAnnotation();
} else if (operator === "+") {
var right = this.get("right");
var left = this.get("left");
if (left.isBaseType("number") && right.isBaseType("number")) {
// both numbers so this will be a number
return t.numberTypeAnnotation();
} else if (left.isBaseType("string") || right.isBaseType("string")) {
// one is a string so the result will be a string
return t.stringTypeAnnotation();
}
// unsure if left and right are strings or numbers so stay on the safe side
return t.unionTypeAnnotation([
t.stringTypeAnnotation(),
t.numberTypeAnnotation()
]);
}
}
//
export function LogicalExpression() {
return t.createUnionTypeAnnotation([
this.get("left").getTypeAnnotation(),
this.get("right").getTypeAnnotation()
]);
}
//
export function ConditionalExpression() {
return t.createUnionTypeAnnotation([
this.get("consequent").getTypeAnnotation(),
this.get("alternate").getTypeAnnotation()
]);
}
//
export function SequenceExpression(node) {
return this.get("expressions").pop().getTypeAnnotation();
}
//
export function AssignmentExpression(node) {
return this.get("right").getTypeAnnotation();
}
//
export function UpdateExpression(node) {
let operator = node.operator;
if (operator === "++" || operator === "--") {
return t.numberTypeAnnotation();
}
}
//
export function Literal(node) {
var value = node.value;
if (typeof value === "string") return t.stringTypeAnnotation();
if (typeof value === "number") return t.numberTypeAnnotation();
if (typeof value === "boolean") return t.booleanTypeAnnotation();
if (value === null) return t.voidTypeAnnotation();
if (node.regex) return t.genericTypeAnnotation(t.identifier("RegExp"));
}
//
export function ObjectExpression() {
return t.genericTypeAnnotation(t.identifier("Object"));
}
//
export function ArrayExpression () {
return t.genericTypeAnnotation(t.identifier("Array"));
}
//
export function RestElement() {
return ArrayExpression();
}
RestElement.validParent = true;
//
function Func() {
return t.genericTypeAnnotation(t.identifier("Function"));
}
export { Func as Function, Func as Class };
//
export function CallExpression() {
return resolveCall(this.get("callee"));
}
export function TaggedTemplateExpression() {
return resolveCall(this.get("tag"));
}
function resolveCall(callee) {
callee = callee.resolve();
if (callee.isFunction()) {
if (callee.is("async")) {
if (callee.is("generator")) {
return t.genericTypeAnnotation(t.identifier("AsyncIterator"));
} else {
return t.genericTypeAnnotation(t.identifier("Promise"));
}
} else {
if (callee.node.returnType) {
return callee.node.returnType;
} else {
// todo: get union type of all return arguments
}
}
}
}

View File

@@ -1,3 +1,4 @@
import type NodePath from "./index";
import includes from "lodash/collection/includes";
import * as t from "../../types";
@@ -145,6 +146,18 @@ export function isCompletionRecord(allowInsideFunction?) {
return true;
}
/**
* Description
*/
export function isDirective() {
if (this.isExpressionStatement()) {
return this.get("expression").isLiteral();
} else {
return this.isLiteral() && this.parentPath.isExpressionStatement();
}
}
/**
* Check whether or not the current `key` allows either a single statement or block statement
* so we can explode it if necessary.
@@ -223,3 +236,145 @@ export function getSource() {
return "";
}
}
/**
* Description
*/
export function willIMaybeExecuteBefore(target) {
return this._guessExecutionStatusRelativeTo(target) !== "after";
}
/**
* Given a `target` check the execution status of it relative to the current path.
*
* "Execution status" simply refers to where or not we **think** this will execuete
* before or after the input `target` element.
*/
export function _guessExecutionStatusRelativeTo(target) {
// check if the two paths are in different functions, we can't track execution of these
var targetFuncParent = target.scope.getFunctionParent();
var selfFuncParent = this.scope.getFunctionParent();
if (targetFuncParent !== selfFuncParent) {
return "function";
}
var targetPaths = getAncestry(target);
//if (targetPaths.indexOf(this) >= 0) return "after";
var selfPaths = getAncestry(this);
// get ancestor where the branches intersect
var commonPath;
var targetIndex;
var selfIndex;
for (selfIndex = 0; selfIndex < selfPaths.length; selfIndex++) {
var selfPath = selfPaths[selfIndex];
targetIndex = targetPaths.indexOf(selfPath);
if (targetIndex >= 0) {
commonPath = selfPath;
break;
}
}
if (!commonPath) {
return "before";
}
// get the relationship paths that associate these nodes to their common ancestor
var targetRelationship = targetPaths[targetIndex - 1];
var selfRelationship = selfPaths[selfIndex - 1];
if (!targetRelationship || !selfRelationship) {
return "before";
}
// container list so let's see which one is after the other
if (targetRelationship.containerKey && targetRelationship.container === selfRelationship.container) {
return targetRelationship.key > selfRelationship.key ? "before" : "after";
}
// otherwise we're associated by a parent node, check which key comes before the other
var targetKeyPosition = t.VISITOR_KEYS[targetRelationship.type].indexOf(targetRelationship.key);
var selfKeyPosition = t.VISITOR_KEYS[selfRelationship.type].indexOf(selfRelationship.key);
return targetKeyPosition > selfKeyPosition ? "before" : "after";
}
function getAncestry(path) {
var paths = [];
do {
paths.push(path);
} while(path = path.parentPath);
return paths;
}
/**
* Resolve a "pointer" `NodePath` to it's absolute path.
*/
export function resolve(dangerous, resolved) {
return this._resolve(dangerous, resolved) || this;
}
export function _resolve(dangerous?, resolved?): ?NodePath {
// detect infinite recursion
// todo: possibly have a max length on this just to be safe
if (resolved && resolved.indexOf(this) >= 0) return;
// we store all the paths we've "resolved" in this array to prevent infinite recursion
resolved = resolved || [];
resolved.push(this);
if (this.isVariableDeclarator()) {
if (this.get("id").isIdentifier()) {
return this.get("init").resolve(dangerous, resolved);
} else {
// otherwise it's a request for a pattern and that's a bit more tricky
}
} else if (this.isReferencedIdentifier()) {
var binding = this.scope.getBinding(this.node.name);
if (!binding) return;
// reassigned so we can't really resolve it
if (!binding.constant) return;
// todo - lookup module in dependency graph
if (binding.kind === "module") return;
if (binding.path !== this) {
return binding.path.resolve(dangerous, resolved);
}
} else if (this.isTypeCastExpression()) {
return this.get("expression").resolve(dangerous, resolved);
} else if (dangerous && 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(dangerous, resolved);
if (target.isObjectExpression()) {
var props = target.get("properties");
for (var prop of (props: Array)) {
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 = match || key.isLiteral({ value: targetName });
if (match) return prop.get("value").resolve(dangerous, resolved);
}
} else if (target.isArrayExpression() && !isNaN(+targetName)) {
var elems = target.get("elements");
var elem = elems[targetName];
if (elem) return elem.resolve(dangerous, resolved);
}
}
}

View File

@@ -1,352 +0,0 @@
import type NodePath from "./index";
import * as t from "../../types";
/**
* Resolve a "pointer" `NodePath` to it's absolute path.
*/
export function resolve(dangerous, resolved) {
return this._resolve(dangerous, resolved) || this;
}
export function _resolve(dangerous?, resolved?): ?NodePath {
// detect infinite recursion
// todo: possibly have a max length on this just to be safe
if (resolved && resolved.indexOf(this) >= 0) return;
// we store all the paths we've "resolved" in this array to prevent infinite recursion
resolved = resolved || [];
resolved.push(this);
if (this.isVariableDeclarator()) {
if (this.get("id").isIdentifier()) {
return this.get("init").resolve(dangerous, resolved);
} else {
// otherwise it's a request for a pattern and that's a bit more tricky
}
} else if (this.isReferencedIdentifier()) {
var binding = this.scope.getBinding(this.node.name);
if (!binding) return;
// reassigned so we can't really resolve it
if (!binding.constant) return;
// todo - lookup module in dependency graph
if (binding.kind === "module") return;
if (binding.path !== this) {
return binding.path.resolve(dangerous, resolved);
}
} else if (dangerous && 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(dangerous, resolved);
if (target.isObjectExpression()) {
var props = target.get("properties");
for (var prop of (props: Array)) {
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 = match || key.isLiteral({ value: targetName });
if (match) return prop.get("value").resolve(dangerous, resolved);
}
} else if (target.isArrayExpression() && !isNaN(+targetName)) {
var elems = target.get("elements");
var elem = elems[targetName];
if (elem) return elem.resolve(dangerous, resolved);
}
}
}
/**
* Infer the type of the current `NodePath`.
*
* NOTE: This is not cached. Use `getTypeAnnotation()` which is cached.
*/
export function getTypeAnnotation(force) {
if (this.typeAnnotation) return this.typeAnnotation;
var type = this._getTypeAnnotation(force) || t.anyTypeAnnotation();
if (t.isTypeAnnotation(type)) type = type.typeAnnotation;
return this.typeAnnotation = type;
}
export function _getTypeAnnotationBindingConstantViolations(name, types = []) {
var binding = this.scope.getBinding(name);
for (var constantViolation of (binding.constantViolations: Array)) {
types.push(constantViolation.getTypeAnnotation());
}
if (types.length) {
return t.createUnionTypeAnnotation(types);
}
}
export function _getTypeAnnotation(force?: boolean): ?Object {
var node = this.node;
if (!node) {
// handle initializerless variables, add in checks for loop initializers too
if (this.key === "init" && this.parentPath.isVariableDeclarator()) {
var declar = this.parentPath.parentPath;
var declarParent = declar.parentPath;
// for (var NODE in bar) {}
if (declar.key === "left" && declarParent.isForInStatement()) {
return t.stringTypeAnnotation();
}
// for (var NODE of bar) {}
if (declar.key === "left" && declarParent.isForOfStatement()) {
return t.anyTypeAnnotation();
}
return t.voidTypeAnnotation();
} else {
return;
}
}
if (node.typeAnnotation) {
return node.typeAnnotation;
}
//
if (this.isVariableDeclarator()) {
var id = this.get("id");
if (id.isIdentifier()) {
return this._getTypeAnnotationBindingConstantViolations(id.node.name, [
this.get("init").getTypeAnnotation()
]);
} else {
return;
}
}
//
if (this.parentPath.isTypeCastExpression()) {
return this.parentPath.getTypeAnnotation();
}
if (this.isTypeCastExpression()) {
return node.typeAnnotation;
}
//
if (this.isRestElement() || this.parentPath.isRestElement() || this.isArrayExpression()) {
return t.genericTypeAnnotation(t.identifier("Array"), t.typeParameterInstantiation([t.anyTypeAnnotation()]));
}
//
if (!force && this.parentPath.isReturnStatement()) {
return this.parentPath.getTypeAnnotation();
}
if (this.isReturnStatement()) {
var funcPath = this.findParent((path) => path.isFunction());
if (!funcPath) return;
var returnType = funcPath.node.returnType;
if (returnType) {
return returnType;
} else {
return this.get("argument").getTypeAnnotation(true);
}
}
//
if (this.isNewExpression() && this.get("callee").isIdentifier()) {
// only resolve identifier callee
return t.genericTypeAnnotation(node.callee);
}
//
if (this.isReferencedIdentifier()) {
// check if a binding exists of this value and if so then return a union type of all
// possible types that the binding could be
var binding = this.scope.getBinding(node.name);
if (binding) {
if (binding.identifier.typeAnnotation) {
return binding.identifier.typeAnnotation;
} else {
return this._getTypeAnnotationBindingConstantViolations(node.name, [
binding.path.getTypeAnnotation()
]);
}
}
// built-in values
if (node.name === "undefined") {
return t.voidTypeAnnotation();
} else if (node.name === "NaN" || node.name === "Infinity") {
return t.numberTypeAnnotation();
} else if (node.name === "arguments") {
// todo
}
}
//
if (this.isObjectExpression()) {
return t.genericTypeAnnotation(t.identifier("Object"));
}
//
if (this.isFunction() || this.isClass()) {
return t.genericTypeAnnotation(t.identifier("Function"));
}
//
if (this.isTemplateLiteral()) {
return t.stringTypeAnnotation();
}
//
if (this.isUnaryExpression()) {
let operator = node.operator;
if (operator === "void") {
return t.voidTypeAnnotation();
} else if (t.NUMBER_UNARY_OPERATORS.indexOf(operator) >= 0) {
return t.numberTypeAnnotation();
} else if (t.STRING_UNARY_OPERATORS.indexOf(operator) >= 0) {
return t.stringTypeAnnotation();
} else if (t.BOOLEAN_UNARY_OPERATORS.indexOf(operator) >= 0) {
return t.booleanTypeAnnotation();
}
}
//
if (this.isBinaryExpression()) {
let operator = node.operator;
if (t.NUMBER_BINARY_OPERATORS.indexOf(operator) >= 0) {
return t.numberTypeAnnotation();
} else if (t.BOOLEAN_BINARY_OPERATORS.indexOf(operator) >= 0) {
return t.booleanTypeAnnotation();
} else if (operator === "+") {
var right = this.get("right");
var left = this.get("left");
if (left.isGenericType("Number") && right.isGenericType("Number")) {
// both numbers so this will be a number
return t.numberTypeAnnotation();
} else if (left.isGenericType("String") || right.isGenericType("String")) {
// one is a string so the result will be a string
return t.stringTypeAnnotation();
}
// unsure if left and right are strings or numbers so stay on the safe side
return t.unionTypeAnnotation([
t.stringTypeAnnotation(),
t.numberTypeAnnotation()
]);
}
}
//
if (this.isLogicalExpression()) {
return t.createUnionTypeAnnotation([
this.get("left").getTypeAnnotation(),
this.get("right").getTypeAnnotation()
]);
}
//
if (this.isConditionalExpression()) {
return t.createUnionTypeAnnotation([
this.get("consequent").getTypeAnnotation(),
this.get("alternate").getTypeAnnotation()
]);
}
//
if (this.isSequenceExpression()) {
return this.get("expressions").pop().getTypeAnnotation(force);
}
//
if (this.isAssignmentExpression()) {
return this.get("right").getTypeAnnotation(force);
}
//
if (this.isUpdateExpression()) {
let operator = node.operator;
if (operator === "++" || operator === "--") {
return t.numberTypeAnnotation();
}
}
//
if (this.isLiteral()) {
var value = node.value;
if (typeof value === "string") return t.stringTypeAnnotation();
if (typeof value === "number") return t.numberTypeAnnotation();
if (typeof value === "boolean") return t.booleanTypeAnnotation();
if (node.regex) return t.genericTypeAnnotation(t.identifier("RegExp"));
}
//
var callPath;
if (this.isCallExpression()) callPath = this.get("callee");
if (this.isTaggedTemplateExpression()) callPath = this.get("tag");
if (callPath) {
var callee = callPath.resolve();
// todo: read typescript/flow interfaces
if (callee.isFunction()) {
if (callee.is("async")) {
if (callee.is("generator")) {
return t.genericTypeAnnotation(t.identifier("AsyncIterator"));
} else {
return t.genericTypeAnnotation(t.identifier("Promise"));
}
} else {
if (callee.node.returnType) {
return callee.node.returnType;
} else {
// todo: get union type of all return arguments
}
}
}
}
}
/**
* Description
*/
export function isGenericType(genericName: string): boolean {
var type = this.getTypeAnnotation();
if (t.isGenericTypeAnnotation(type) && t.isIdentifier(type.id, { name: genericName })) {
return true;
}
if (genericName === "String") {
return t.isStringTypeAnnotation(type);
} else if (genericName === "Number") {
return t.isNumberTypeAnnotation(type);
} else if (genericName === "Boolean") {
return t.isBooleanTypeAnnotation(type);
}
return false;
}

View File

@@ -1,5 +1,5 @@
export default class Binding {
constructor({ identifier, scope, path, kind }) {
constructor({ existing, identifier, scope, path, kind }) {
this.constantViolations = [];
this.constant = true;
@@ -12,6 +12,14 @@ export default class Binding {
this.kind = kind;
this.clearValue();
if (existing) {
this.constantViolations = [].concat(
existing.path,
existing.constantViolations,
this.constantViolations
);
}
}
/**

View File

@@ -434,19 +434,18 @@ export default class Scope {
*/
registerDeclaration(path: NodePath) {
var node = path.node;
if (t.isFunctionDeclaration(node)) {
if (path.isFunctionDeclaration()) {
this.registerBinding("hoisted", path);
} else if (t.isVariableDeclaration(node)) {
} else if (path.isVariableDeclaration()) {
var declarations = path.get("declarations");
for (var declar of (declarations: Array)) {
this.registerBinding(node.kind, declar);
this.registerBinding(path.node.kind, declar);
}
} else if (t.isClassDeclaration(node)) {
} else if (path.isClassDeclaration()) {
this.registerBinding("let", path);
} else if (t.isImportDeclaration(node) || t.isExportDeclaration(node)) {
} else if (path.isImportDeclaration() || path.isExportDeclaration()) {
this.registerBinding("module", path);
} else if (t.isFlowDeclaration()) {
} else if (path.isFlowDeclaration()) {
this.registerBinding("type", path);
} else {
this.registerBinding("unknown", path);
@@ -509,6 +508,7 @@ export default class Scope {
this.bindings[name] = new Binding({
identifier: id,
existing: local,
scope: this,
path: path,
kind: kind

View File

@@ -76,8 +76,6 @@
"ThisExpression": ["Expression"],
"Super": ["Expression"],
"UpdateExpression": ["Expression"],
"JSXEmptyExpression": ["Expression"],
"JSXMemberExpression": ["Expression"],
"AnyTypeAnnotation": ["Flow", "FlowBaseAnnotation"],
"ArrayTypeAnnotation": ["Flow"],
@@ -116,10 +114,10 @@
"JSXAttribute": ["JSX", "Immutable"],
"JSXClosingElement": ["JSX", "Immutable"],
"JSXElement": ["JSX", "Immutable", "Expression"],
"JSXEmptyExpression": ["JSX", "Immutable"],
"JSXEmptyExpression": ["JSX", "Immutable", "Expression"],
"JSXExpressionContainer": ["JSX", "Immutable"],
"JSXIdentifier": ["JSX"],
"JSXMemberExpression": ["JSX"],
"JSXMemberExpression": ["JSX", "Expression"],
"JSXNamespacedName": ["JSX"],
"JSXOpeningElement": ["JSX", "Immutable"],
"JSXSpreadAttribute": ["JSX"]

View File

@@ -15,16 +15,28 @@ export function createUnionTypeAnnotation(types) {
}
}
/**
* Description
*/
export function removeTypeDuplicates(nodes) {
var generics = {};
var bases = {};
// store union type groups to circular references
var typeGroups = [];
var types = [];
for (var i = 0; i < nodes.length; i++) {
var node = nodes[i];
if (!node) continue;
// detect duplicates
if (types.indexOf(node) >= 0) {
continue;
}
// this type matches anything
if (t.isAnyTypeAnnotation(node)) {
return [node];
@@ -38,7 +50,10 @@ export function removeTypeDuplicates(nodes) {
//
if (t.isUnionTypeAnnotation(node)) {
nodes = nodes.concat(node.types);
if (typeGroups.indexOf(node.types) < 0) {
nodes = nodes.concat(node.types);
typeGroups.push(node.types);
}
continue;
}
@@ -79,3 +94,23 @@ export function removeTypeDuplicates(nodes) {
return types;
}
/**
* Description
*/
export function createTypeAnnotationBasedOnTypeof(type) {
if (type === "string") {
return t.stringTypeAnnotation();
} else if (type === "number") {
return t.numberTypeAnnotation();
} else if (type === "undefined") {
return t.voidTypeAnnotation();
} else if (type === "boolean") {
return t.booleanTypeAnnotation();
} else if (type === "function") {
return t.genericTypeAnnotation(t.identifier("Function"));
} else if (type === "object") {
return t.genericTypeAnnotation(t.identifier("Object"));
}
}

View File

@@ -29,8 +29,10 @@ export const FLATTENABLE_KEYS = ["body", "expressions"];
export const FOR_INIT_KEYS = ["left", "init"];
export const COMMENT_KEYS = ["leadingComments", "trailingComments"];
export const BOOLEAN_BINARY_OPERATORS = ["==", "===", "!=", "!==", ">", "<", ">=", "<=", "in", "instanceof"];
export const NUMBER_BINARY_OPERATORS = ["-", "/", "*", "**", "&", "|", ">>", ">>>", "<<", "^"];
export const BOOLEAN_NUMBER_BINARY_OPERATORS = [">", "<", ">=", "<="];
export const COMPARISON_BINARY_OPERATORS = ["==", "===", "!=", "!==", "in", "instanceof"];
export const BOOLEAN_BINARY_OPERATORS = [].concat(COMPARISON_BINARY_OPERATORS, BOOLEAN_NUMBER_BINARY_OPERATORS);
export const NUMBER_BINARY_OPERATORS = ["-", "/", "*", "**", "&", "|", ">>", ">>>", "<<", "^"];
export const BOOLEAN_UNARY_OPERATORS = ["delete", "!"];
export const NUMBER_UNARY_OPERATORS = ["+", "-", "++", "--", "~"];

View File

@@ -102,7 +102,7 @@ export function arrayify(val: any, mapFn?: Function): Array {
return [val];
}
export function booleanify(val: any): boolean {
export function booleanify(val: any) {
if (val === "true") return true;
if (val === "false") return false;
return val;
@@ -111,7 +111,7 @@ export function booleanify(val: any): boolean {
export function shouldIgnore(filename, ignore, only) {
filename = slash(filename);
if (only.length) {
if (only) {
for (let pattern of (only: Array)) {
if (pattern.test(filename)) return false;
}

View File

@@ -620,6 +620,63 @@ testFail("function foo(promise) { await promise; }", "Unexpected token (1:30)",
features: { "es7.asyncFunctions": true }
});
testFail("var x = async\n(x) => x + 1;", "Unexpected token (2:4)", {
ecmaVersion: 7,
features: { "es7.asyncFunctions": true }
});
test("async\nfunction foo() {}", {
type: "Program",
body: [
{
type: "ExpressionStatement",
expression: {
type: "Identifier",
name: "async",
loc: {
start: {line: 1, column: 0},
end: {line: 1, column: 5}
}
},
loc: {
start: {line: 1, column: 0},
end: {line: 1, column: 5}
}
},
{
type: "FunctionDeclaration",
id: {
type: "Identifier",
name: "foo",
loc: {
start: {line: 2, column: 9},
end: {line: 2, column: 12}
}
},
params: [],
body: {
type: "BlockStatement",
body: [],
loc: {
start: {line: 2, column: 15},
end: {line: 2, column: 17}
}
},
generator: false,
expression: false,
async: false,
loc: {
start: {line: 2, column: 0},
end: {line: 2, column: 17}
}
}
]
}, {
ecmaVersion: 7,
features: { "es7.asyncFunctions": true },
locations: true
});
test('async function foo(promise) { await promise; }', {
type: "Program",
body: [{

View File

@@ -18,13 +18,23 @@ suite("api", function () {
assert.ok(!result.ast);
});
test("auxiliaryComment option", function () {
test("auxiliaryCommentBefore option", function () {
assert.ok(transform("class Foo {}", {
auxiliaryComment: "foobar"
auxiliaryCommentBefore: "foobar"
}).code.indexOf("foobar") >= 0);
assert.ok(transform("for (let i in bar) { foo(function () { i; }); break; continue; }", {
auxiliaryComment: "foobar"
auxiliaryCommentBefore: "foobar"
}).code.indexOf("foobar") >= 0);
});
test("auxiliaryCommentAfter option", function () {
assert.ok(transform("class Foo {}", {
auxiliaryCommentAfter: "foobar"
}).code.indexOf("foobar") >= 0);
assert.ok(transform("for (let i in bar) { foo(function () { i; }); break; continue; }", {
auxiliaryCommentAfter: "foobar"
}).code.indexOf("foobar") >= 0);
});
@@ -49,22 +59,40 @@ suite("api", function () {
});
assert.deepEqual(transform('import localName3 from "external";').metadata.modules.imports[0], {
source: 'external',
imported: ['default'],
source: "external",
imported: ["default"],
specifiers: [{
kind: 'named',
imported: 'default',
local: 'localName3'
kind: "named",
imported: "default",
local: "localName3"
}]
});
assert.deepEqual(transform('import localName from "./array";', {
resolveModuleSource: function() {
return 'override-source';
}
}).metadata.modules.imports, [
{
source: "override-source",
imported: ["default"],
specifiers: [
{
"kind": "named",
"imported": "default",
"local": "localName"
}
]
}
]);
assert.deepEqual(transform('export * as externalName1 from "external";', {
stage: 0
}).metadata.modules.exports, {
exported: ['externalName1'],
specifiers: [{
kind: 'external-namespace',
exported: 'externalName1',
kind: "external-namespace",
exported: "externalName1",
source: "external",
}]
});

View File

@@ -11,17 +11,10 @@ require("./_transformation-helper")({
// weird environmental issue make these hard to test
"Modules",
// these are the responsibility of regenerator
"AsyncFunctions",
"Yield",
// these are the responsibility of core-js
"StringExtras",
"ArrayExtras",
"Collections",
// not supported
"ProperTailCalls",
// uses the old async generator proposal
"AsyncGenerators",
// these are all internal traceur tests or non-standard features
@@ -38,8 +31,30 @@ require("./_transformation-helper")({
],
ignoreTasks: [
// non-standard
"ObjectMixin",
// TODO
"Syntax/StrictKeywordsInPattern",
"Yield/GeneratorSend",
"Yield/BreakForOf",
"Yield/GeneratorThrow",
"Yield/ObjectModel",
"Yield/ReturnGenerator",
// TODO: core-js fails these
"Collections/Map",
"Collections/Set",
"ArrayExtras/From",
"ArrayExtras/FindIndex",
"ArrayExtras/Find",
"StringExtras/Includes",
"StringExtras/EndsWith",
// this tests pollutes Object.prototype which messes things up
"StringExtras/StartsWith",
// TODO
"Syntax/IsValidSimpleAssignmentTarget",
// babel has no way to check these :( TODO: add to caveats
"TemplateLiterals/TemplateObjectCaching.module",
@@ -52,11 +67,8 @@ require("./_transformation-helper")({
"Classes/ExtendStrange",
// these are the responsibility of core-js
"Symbol/GetOwnPropertySymbols",
"Spread/Type",
"Symbol/ObjectModel",
"Symbol/Inherited",
"Symbol/Object",
"Spread/NoIterator",
"Destructuring/Rest",
"Destructuring/Empty",
@@ -64,16 +76,8 @@ require("./_transformation-helper")({
// babel doesn't like non-closing comments :)
"Syntax/NoNewLineHereEndOfFile",
// traceur uses an old version of regexpu
"RegularExpression/Simple",
// class methods are still enumerable in traceur...
// TODO
"Classes/PrototypeDescriptor",
"NumericLiteral/Simple",
"Classes/Method",
// Object.mixin didn't make it into ES6
"ObjectMixin",
// Babel assumes that all code transformed is a module so this isn't necessary
"Strict",
@@ -87,6 +91,7 @@ require("./_transformation-helper")({
"GeneratorComprehension/Simple",
// yield has been added as a keyword in ES6
"Syntax/StrictKeywordsInPattern",
"Yield/YieldIdentifier",
"Syntax/StrictKeywords"
]

2
vendor/traceur vendored