embed acorn

This commit is contained in:
Sebastian McKenzie 2015-03-17 02:44:05 +11:00
parent 976e8c1cfd
commit ec526f9224
30 changed files with 92334 additions and 59 deletions

2
.gitignore vendored
View File

@ -14,4 +14,4 @@ dist
packages/babel-runtime/*.js
packages/babel-runtime/helpers/*.js
packages/babel-runtime/regenerator/*.js
lib
lib/babel

32
lib/acorn/AUTHORS Normal file
View File

@ -0,0 +1,32 @@
List of Acorn contributors. Updated before every release.
Alistair Braidwood
Aparajita Fishman
Arian Stolwijk
Artem Govorov
Brandon Mills
Charles Hughes
Conrad Irwin
David Bonnet
impinball
Ingvar Stepanyan
Jiaxing Wang
Johannes Herr
Jürg Lehni
keeyipchan
krator
Marijn Haverbeke
Martin Carlberg
Mathias Bynens
Mathieu 'p01' Henri
Max Schaefer
Mihai Bazon
Mike Rennie
Oskar Schöldström
Paul Harper
Peter Rust
PlNG
r-e-d
Rich Harris
Sebastian McKenzie
zsjforcn

19
lib/acorn/LICENSE Normal file
View File

@ -0,0 +1,19 @@
Copyright (C) 2012-2014 by various contributors (see AUTHORS)
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

4
lib/acorn/README.md Normal file
View File

@ -0,0 +1,4 @@
# Acorn
Embedded version with Babel-specific modifications of the excellent
[acorn](https://github.com/marijnh/acorn) parser.

2934
lib/acorn/acorn.js Normal file

File diff suppressed because it is too large Load Diff

23
lib/acorn/package.json Normal file
View File

@ -0,0 +1,23 @@
{
"name": "acorn",
"description": "ECMAScript parser",
"homepage": "http://marijnhaverbeke.nl/acorn/",
"main": "acorn.js",
"version": "0.12.1",
"engines": {"node": ">=0.4.0"},
"browser": "acorn_csp.js",
"maintainers": [{"name": "Marijn Haverbeke",
"email": "marijnh@gmail.com",
"web": "http://marijnhaverbeke.nl"}],
"repository": {"type": "git",
"url": "http://marijnhaverbeke.nl/git/acorn"},
"licenses": [{"type": "MIT",
"url": "http://marijnhaverbeke.nl/acorn/LICENSE"}],
"scripts": {
"test": "node test/run.js",
"prepublish": "node bin/without_eval > acorn_csp.js"
},
"bin": {"acorn": "./bin/acorn"},
"devDependencies": {"regenerate": "~0.6.2",
"unicode-7.0.0": "~0.1.5"}
}

96
lib/acorn/test/bench.html Normal file
View File

@ -0,0 +1,96 @@
<!doctype html>
<head>
<meta charset="utf-8">
<title>Acorn benchmark</title>
<script src="../acorn.js"></script>
<script src="compare/esprima.js"></script>
<script src="compare/traceur.js"></script>
<script src="jquery-string.js"></script>
<script src="codemirror-string.js"></script>
<style>
td { text-align: right; padding-right: 20px; }
th { text-align: left; padding-right: 40px; }
body { max-width: 50em; padding: 1em 2em; }
h1 { font-size: 150%; }
</style>
</head>
<h1>Acorn/Esprima/Traceur speed comparison</h1>
<p>This will run each of the three ES6 parsers on the source code of
jQuery 1.11.1 and CodeMirror 3.0b1 for five seconds, and show a table
indicating the number of lines parsed per second. Note that Traceur
always stores location data, and is thus not fairly compared by the
benchmark <em>without</em> location data.<p>
<p>Also note that having the developer tools open in Chrome, or
Firebug in Firefox <em>heavily</em> influences the numbers you get. In
Chrome, the effect even lingers (in the tab) after you close the
developer tools. Load in a fresh tab to get (halfway) stable
numbers.</p>
<button onclick="run(false)">Compare <strong>without</strong> location data</button>
<button onclick="run(true)">Compare <strong>with</strong> location data</button>
<button onclick="run(false, true)">Run only Acorn</button>
<span id="running"></span>
<script>
var sourceFileName = 'source.js';
function runAcorn(code, locations) {
acorn.parse(code, {ecmaVersion: 6, locations: locations, sourceFile: sourceFileName});
}
function runEsprima(code, locations) {
esprima.parse(code, {loc: locations, source: sourceFileName});
}
function runTraceur(code) {
var file = new traceur.syntax.SourceFile(sourceFileName, code);
var parser = new traceur.syntax.Parser(file);
parser.parseScript();
}
var totalLines = codemirror30.split("\n").length + jquery111.split("\n").length;
var nowHost = (typeof performance === 'object' && 'now' in performance) ? performance : Date;
function benchmark(runner, locations) {
// Give it a chance to warm up (first runs are usually outliers)
runner(jquery111, locations);
runner(codemirror30, locations);
var t0 = nowHost.now(), t1, lines = 0;
for (;;) {
runner(jquery111, locations);
runner(codemirror30, locations);
lines += totalLines;
t1 = nowHost.now();
if (t1 - t0 > 5000) break;
}
return lines / ((t1 - t0) / 1000);
}
function showOutput(values) {
var html = "<hr><table>";
for (var i = 0; i < values.length; ++i)
html += "<tr><th>" + values[i].name + "</td><td>" + Math.round(values[i].score) + " lines per second</td><td>" +
Math.round(values[i].score * 100 / values[0].score) + "%</td></tr>";
document.body.appendChild(document.createElement("div")).innerHTML = html;
}
function run(locations, acornOnly) {
var running = document.getElementById("running");
running.innerHTML = "Running benchmark...";
var data = [{name: "Acorn", runner: runAcorn},
{name: "Esprima", runner: runEsprima},
{name: "Traceur", runner: runTraceur}];
if (acornOnly) data.length = 1;
var pos = 0;
function next() {
data[pos].score = benchmark(data[pos].runner, locations);
if (++pos == data.length) {
running.innerHTML = "";
showOutput(data);
} else setTimeout(next, 100);
}
setTimeout(next, 50);
}
</script>

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

113
lib/acorn/test/driver.js Normal file
View File

@ -0,0 +1,113 @@
(function(exports) {
var tests = [];
exports.test = function(code, ast, options) {
tests.push({code: code, ast: ast, options: options});
};
exports.testFail = function(code, message, options) {
tests.push({code: code, error: message, options: options});
};
exports.testAssert = function(code, assert, options) {
tests.push({code: code, assert: assert, options: options});
};
exports.runTests = function(config, callback) {
var parse = config.parse;
for (var i = 0; i < tests.length; ++i) {
var test = tests[i];
if (config.filter && !config.filter(test)) continue;
var testOpts = test.options || {locations: true};
var expected = {};
if (expected.onComment = testOpts.onComment)
testOpts.onComment = []
if (expected.onToken = testOpts.onToken)
testOpts.onToken = [];
try {
var ast = parse(test.code, testOpts);
} catch(e) {
if (!(e instanceof SyntaxError)) throw e;
if (test.error) {
if (e.message == test.error) callback("ok", test.code);
else callback("fail", test.code,
"Expected error message: " + test.error + "\nGot error message: " + e.message);
} else {
callback("error", test.code, e.message || e.toString());
}
continue
}
if (test.error) {
if (config.loose) callback("ok", test.code);
else callback("fail", test.code, "Expected error message: " + test.error + "\nBut parsing succeeded.");
} else if (test.assert) {
var error = test.assert(ast);
if (error) callback("fail", test.code, "\n Assertion failed:\n " + error);
else callback("ok", test.code);
} else {
var mis = misMatch(test.ast, ast);
for (var name in expected) {
if (mis) break;
if (expected[name]) {
mis = misMatch(expected[name], testOpts[name]);
testOpts[name] = expected[name];
}
}
if (mis) callback("fail", test.code, mis);
else callback("ok", test.code);
}
}
};
function ppJSON(v) { return v instanceof RegExp ? v.toString() : JSON.stringify(v, null, 2); }
function addPath(str, pt) {
if (str.charAt(str.length-1) == ")")
return str.slice(0, str.length-1) + "/" + pt + ")";
return str + " (" + pt + ")";
}
var misMatch = exports.misMatch = function(exp, act) {
if (!exp || !act || (typeof exp != "object") || (typeof act != "object")) {
if (exp !== act) return ppJSON(exp) + " !== " + ppJSON(act);
} else if (exp instanceof RegExp || act instanceof RegExp) {
var left = ppJSON(exp), right = ppJSON(act);
if (left !== right) return left + " !== " + right;
} else if (exp.splice) {
if (!act.slice) return ppJSON(exp) + " != " + ppJSON(act);
if (act.length != exp.length) return "array length mismatch " + exp.length + " != " + act.length;
for (var i = 0; i < act.length; ++i) {
var mis = misMatch(exp[i], act[i]);
if (mis) return addPath(mis, i);
}
} else {
for (var prop in exp) {
var mis = misMatch(exp[prop], act[prop]);
if (mis) return addPath(mis, prop);
}
}
};
function mangle(ast) {
if (typeof ast != "object" || !ast) return;
if (ast.slice) {
for (var i = 0; i < ast.length; ++i) mangle(ast[i]);
} else {
var loc = ast.start && ast.end && {start: ast.start, end: ast.end};
if (loc) { delete ast.start; delete ast.end; }
for (var name in ast) if (ast.hasOwnProperty(name)) mangle(ast[name]);
if (loc) ast.loc = loc;
}
}
exports.printTests = function() {
var out = "";
for (var i = 0; i < tests.length; ++i) {
if (tests[i].error) continue;
mangle(tests[i].ast);
out += "test(" + JSON.stringify(tests[i].code) + ", " + JSON.stringify(tests[i].ast, null, 2) + ");\n\n";
}
document.body.innerHTML = "";
document.body.appendChild(document.createElement("pre")).appendChild(document.createTextNode(out));
};
})(typeof exports == "undefined" ? window : exports);

14
lib/acorn/test/index.html Normal file
View File

@ -0,0 +1,14 @@
<!doctype html>
<head>
<meta charset="utf-8">
<title>Acorn test suite</title>
<script src="../acorn.js"></script>
<script src="../acorn_loose.js"></script>
<script src="driver.js"></script>
<script src="tests.js" charset="utf-8"></script>
<script src="tests-harmony.js" charset="utf-8"></script>
</head>
<body>
<ul id="log"></ul>
<script src="run.js"></script>
</body>

10315
lib/acorn/test/jquery-string.js vendored Normal file

File diff suppressed because it is too large Load Diff

109
lib/acorn/test/run.js Normal file
View File

@ -0,0 +1,109 @@
(function() {
var driver;
if (typeof require !== "undefined") {
driver = require("./driver.js");
require("./tests.js");
require("./tests-harmony.js");
} else {
driver = window;
}
var htmlLog = typeof document === "object" && document.getElementById('log');
var htmlGroup = htmlLog;
function group(name) {
if (htmlGroup) {
var parentGroup = htmlGroup;
htmlGroup = document.createElement("ul");
var item = document.createElement("li");
item.textContent = name;
item.appendChild(htmlGroup);
parentGroup.appendChild(item);
}
if (typeof console === "object" && console.group) {
console.group(name);
}
}
function groupEnd() {
if (htmlGroup) {
htmlGroup = htmlGroup.parentElement.parentElement;
}
if (typeof console === "object" && console.groupEnd) {
console.groupEnd(name);
}
}
function log(title, message) {
if (htmlGroup) {
var elem = document.createElement("li");
elem.innerHTML = "<b>" + title + "</b> " + message;
htmlGroup.appendChild(elem);
}
if (typeof console === "object") console.log(title, message);
}
var stats, modes = {
Normal: {
config: {
parse: (typeof require === "undefined" ? window.acorn : require("../acorn.js")).parse
}
},
Loose: {
config: {
parse: (typeof require === "undefined" ? window.acorn : require("../acorn_loose")).parse_dammit,
loose: true,
filter: function (test) {
var opts = test.options || {};
if (opts.loose === false) return false;
return (opts.ecmaVersion || 5) <= 6;
}
}
}
};
function report(state, code, message) {
if (state != "ok") {++stats.failed; log(code, message);}
++stats.testsRun;
}
group("Errors");
for (var name in modes) {
group(name);
var mode = modes[name];
stats = mode.stats = {testsRun: 0, failed: 0};
var t0 = +new Date;
driver.runTests(mode.config, report);
mode.stats.duration = +new Date - t0;
groupEnd();
}
groupEnd();
function outputStats(name, stats) {
log(name + ":", stats.testsRun + " tests run in " + stats.duration + "ms; " +
(stats.failed ? stats.failed + " failures." : "all passed."));
}
var total = {testsRun: 0, failed: 0, duration: 0};
group("Stats");
for (var name in modes) {
var stats = modes[name].stats;
outputStats(name + " parser", stats);
for (var key in stats) total[key] += stats[key];
}
outputStats("Total", total);
groupEnd();
if (total.failed && typeof process === "object") {
process.stdout.write("", function() {
process.exit(1);
});
}
})();

File diff suppressed because it is too large Load Diff

28967
lib/acorn/test/tests.js Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,47 @@
// Note: run `npm install unicode-7.0.0` first.
// Which Unicode version should be used?
var version = '7.0.0';
var start = require('unicode-' + version + '/properties/ID_Start/code-points')
.filter(function(ch) { return ch > 127; });
var cont = [0x200c, 0x200d].concat(require('unicode-' + version + '/properties/ID_Continue/code-points')
.filter(function(ch) { return ch > 127 && start.indexOf(ch) == -1; }));
function pad(str, width) {
while (str.length < width) str = "0" + str;
return str;
}
function esc(code) {
var hex = code.toString(16);
if (hex.length <= 2) return "\\x" + pad(hex, 2);
else return "\\u" + pad(hex, 4);
}
function generate(chars) {
var astral = [], re = "";
for (var i = 0, at = 0x10000; i < chars.length; i++) {
var from = chars[i], to = from;
while (i < chars.length - 1 && chars[i + 1] == to + 1) {
i++;
to++;
}
if (to <= 0xffff) {
if (from == to) re += esc(from);
else if (from + 1 == to) re += esc(from) + esc(to);
else re += esc(from) + "-" + esc(to);
} else {
astral.push(from - at, to - from);
at = to;
}
}
return {nonASCII: re, astral: astral};
}
var startData = generate(start), contData = generate(cont);
console.log(" var nonASCIIidentifierStartChars = \"" + startData.nonASCII + "\";");
console.log(" var nonASCIIidentifierChars = \"" + contData.nonASCII + "\";");
console.log(" var astralIdentifierStartCodes = " + JSON.stringify(startData.astral) + ";");
console.log(" var astralIdentifierCodes = " + JSON.stringify(contData.astral) + ";");

View File

@ -36,7 +36,6 @@
"test": "make test"
},
"dependencies": {
"acorn-babel": "0.11.1-38",
"ast-types": "~0.7.0",
"chalk": "^1.0.0",
"chokidar": "^0.12.6",

View File

@ -6,7 +6,7 @@ import fs from "fs";
export { util };
export { canCompile } from "../util";
export { default as acorn } from "acorn-babel";
export { default as acorn } from "../../acorn";
export { default as Transformer } from "../transformation/transformer";
export { default as transform } from "../transformation";
export { default as traverse } from "../traversal";

View File

@ -10,26 +10,32 @@ export function ImportSpecifier(node, print) {
}
export function ExportSpecifier(node, print) {
print(node.id);
if (node.name) {
print(node.local);
if (node.exported && node.local !== node.exported) {
this.push(" as ");
print(node.name);
print(node.exported);
}
}
export function ExportBatchSpecifier() {
this.push("*");
export function ExportAllDeclaration(node, source) {
this.push("export * from");
print(node.source);
this.semicolon();
}
export function ExportDeclaration(node, print) {
export function ExportNamedDeclaration(node, print) {
this.push("export ");
var specifiers = node.specifiers;
if (node.default) {
this.push("default ");
ExportDeclaration.call(this, node, print);
}
export function ExportDefaultDeclaration(node, print) {
this.push("export default ");
ExportDeclaration.call(this, node, print);
}
function ExportDeclaration(node, print) {
var specifiers = node.specifiers;
if (node.declaration) {
print(node.declaration);
if (t.isStatement(node.declaration)) return;

View File

@ -1,7 +1,7 @@
import normalizeAst from "./normalize-ast";
import estraverse from "estraverse";
import codeFrame from "./code-frame";
import acorn from "acorn-babel";
import acorn from "../../acorn";
export default function (opts, code, callback) {
try {
@ -11,11 +11,12 @@ export default function (opts, code, callback) {
var ast = acorn.parse(code, {
allowImportExportEverywhere: opts.looseModules,
allowReturnOutsideFunction: opts.looseModules,
transformers: opts.transformers,
transformers: opts.transformers || {},
ecmaVersion: 6,
strictMode: opts.strictMode,
onComment: comments,
locations: true,
plugins: opts.plugins || [],
onToken: tokens,
ranges: true
});

728
src/babel/parser/flow.js Normal file
View File

@ -0,0 +1,728 @@
import acorn from "../../acorn";
var pp = acorn.Parser.prototype;
var tt = acorn.tokTypes;
pp.isRelational = function (op) {
return this.type === tt.relational && this.value === op;
};
pp.expectRelational = function (op) {
if (this.isRelational(op)) {
this.next();
} else {
this.unexpected();
}
};
pp.flow_parseDeclareClass = function (node) {
this.next();
this.flow_parseInterfaceish(node, true);
return this.finishNode(node, "DeclareClass");
};
pp.flow_parseDeclareFunction = function (node) {
this.next();
var id = node.id = this.parseIdent();
var typeNode = this.startNode();
var typeContainer = this.startNode();
if (this.isRelational("<")) {
typeNode.typeParameters = this.flow_parseTypeParameterDeclaration();
} else {
typeNode.typeParameters = null;
}
this.expect(tt.parenL);
var tmp = this.flow_parseFunctionTypeParams();
typeNode.params = tmp.params;
typeNode.rest = tmp.rest;
this.expect(tt.parenR);
this.expect(tt.colon);
typeNode.returnType = this.flow_parseType();
typeContainer.typeAnnotation = this.finishNode(typeNode, "FunctionTypeAnnotation");
id.typeAnnotation = this.finishNode(typeContainer, "TypeAnnotation");
this.finishNode(id, id.type);
this.semicolon();
return this.finishNode(node, "DeclareFunction");
};
pp.flow_parseDeclare = function (node) {
if (this.type === tt._class) {
return this.flow_parseDeclareClass(node);
} else if (this.type === tt._function) {
return this.flow_parseDeclareFunction(node);
} else if (this.type === tt._var) {
return this.flow_parseDeclareVariable(node);
} else if (this.isContextual("module")) {
return this.flow_parseDeclareModule(node);
} else {
this.unexpected();
}
};
pp.flow_parseDeclareVariable = function (node) {
this.next();
node.id = this.flow_parseTypeAnnotatableIdentifier();
this.semicolon();
return this.finishNode(node, "DeclareVariable");
};
pp.flow_parseDeclareModule = function (node) {
this.next();
if (this.type === tt.string) {
node.id = this.parseExprAtom();
} else {
node.id = this.parseIdent();
}
var bodyNode = node.body = this.startNode();
var body = bodyNode.body = [];
this.expect(tt.braceL);
while (this.type !== tt.braceR) {
var node2 = this.startNode();
// todo: declare check
this.next();
body.push(this.flow_parseDeclare(node2));
}
this.expect(tt.braceR);
this.finishNode(bodyNode, "BlockStatement");
return this.finishNode(node, "DeclareModule");
};
// Interfaces
pp.flow_parseInterfaceish = function (node, allowStatic) {
node.id = this.parseIdent();
if (this.isRelational("<")) {
node.typeParameters = this.flow_parseTypeParameterDeclaration();
} else {
node.typeParameters = null;
}
node.extends = [];
if (this.eat(tt._extends)) {
do {
node.extends.push(this.flow_parseInterfaceExtends());
} while(this.eat(tt.comma));
}
node.body = this.flow_parseObjectType(allowStatic);
};
pp.flow_parseInterfaceExtends = function () {
var node = this.startNode();
node.id = this.parseIdent();
if (this.isRelational("<")) {
node.typeParameters = this.flow_parseTypeParameterInstantiation();
} else {
node.typeParameters = null;
}
return this.finishNode(node, "InterfaceExtends");
};
pp.flow_parseInterface = function (node) {
this.flow_parseInterfaceish(node, false);
return this.finishNode(node, "InterfaceDeclaration");
};
// Type aliases
pp.flow_parseTypeAlias = function (node) {
node.id = this.parseIdent();
if (this.isRelational("<")) {
node.typeParameters = this.flow_parseTypeParameterDeclaration();
} else {
node.typeParameters = null;
}
this.expect(tt.eq);
node.right = this.flow_parseType();
this.semicolon();
return this.finishNode(node, "TypeAlias");
};
// Type annotations
pp.flow_parseTypeParameterDeclaration = function () {
var node = this.startNode();
node.params = [];
this.expectRelational("<");
while (!this.isRelational(">")) {
node.params.push(this.flow_parseTypeAnnotatableIdentifier());
if (!this.isRelational(">")) {
this.expect(tt.comma);
}
}
this.expectRelational(">");
return this.finishNode(node, "TypeParameterDeclaration");
};
pp.flow_parseTypeParameterInstantiation = function () {
var node = this.startNode(), oldInType = this.inType;
node.params = [];
this.inType = true;
this.expectRelational("<");
while (!this.isRelational(">")) {
node.params.push(this.flow_parseType());
if (!this.isRelational(">")) {
this.expect(tt.comma);
}
}
this.expectRelational(">");
this.inType = oldInType;
return this.finishNode(node, "TypeParameterInstantiation");
};
pp.flow_parseObjectPropertyKey = function () {
return (this.type === tt.num || this.type === tt.string) ? this.parseExprAtom() : this.parseIdent(true);
};
pp.flow_parseObjectTypeIndexer = function (node, isStatic) {
node.static = isStatic;
this.expect(tt.bracketL);
node.id = this.flow_parseObjectPropertyKey();
this.expect(tt.colon);
node.key = this.flow_parseType();
this.expect(tt.bracketR);
this.expect(tt.colon);
node.value = this.flow_parseType();
return this.finishNode(node, "ObjectTypeIndexer");
};
pp.flow_parseObjectTypeMethodish = function (node) {
node.params = [];
node.rest = null;
node.typeParameters = null;
if (this.isRelational("<")) {
node.typeParameters = this.flow_parseTypeParameterDeclaration();
}
this.expect(tt.parenL);
while (this.type === tt.name) {
node.params.push(this.flow_parseFunctionTypeParam());
if (this.type !== tt.parenR) {
this.expect(tt.comma);
}
}
if (this.eat(tt.ellipsis)) {
node.rest = this.flow_parseFunctionTypeParam();
}
this.expect(tt.parenR);
this.expect(tt.colon);
node.returnType = this.flow_parseType();
return this.finishNode(node, "FunctionTypeAnnotation");
};
pp.flow_parseObjectTypeMethod = function (start, isStatic, key) {
var node = this.startNodeAt(start);
node.value = this.flow_parseObjectTypeMethodish(this.startNodeAt(start));
node.static = isStatic;
node.key = key;
node.optional = false;
return this.finishNode(node, "ObjectTypeProperty");
};
pp.flow_parseObjectTypeCallProperty = function (node, isStatic) {
var valueNode = this.startNode();
node.static = isStatic;
node.value = this.flow_parseObjectTypeMethodish(valueNode);
return this.finishNode(node, "ObjectTypeCallProperty");
};
pp.flow_parseObjectType = function (allowStatic) {
var nodeStart = this.startNode();
var node;
var optional = false;
var property;
var propertyKey;
var propertyTypeAnnotation;
var token;
var isStatic;
nodeStart.callProperties = [];
nodeStart.properties = [];
nodeStart.indexers = [];
this.expect(tt.braceL);
while (this.type !== tt.braceR) {
var start = this.currentPos();
node = this.startNode();
if (allowStatic && this.isContextual("static")) {
this.next();
isStatic = true;
}
if (this.type === tt.bracketL) {
nodeStart.indexers.push(this.flow_parseObjectTypeIndexer(node, isStatic));
} else if (this.type === tt.parenL || this.isRelational("<")) {
nodeStart.callProperties.push(this.flow_parseObjectTypeCallProperty(node, allowStatic));
} else {
if (isStatic && this.type === tt.colon) {
propertyKey = this.parseIdent();
} else {
propertyKey = this.flow_parseObjectPropertyKey();
}
if (this.isRelational("<") || this.type === tt.parenL) {
// This is a method property
nodeStart.properties.push(this.flow_parseObjectTypeMethod(start, isStatic, propertyKey));
} else {
if (this.eat(tt.question)) {
optional = true;
}
this.expect(tt.colon);
node.key = propertyKey;
node.value = this.flow_parseType();
node.optional = optional;
node.static = isStatic;
nodeStart.properties.push(this.finishNode(node, "ObjectTypeProperty"));
}
}
if (!this.eat(tt.semi) && this.type !== tt.braceR) {
this.unexpected();
}
}
this.expect(tt.braceR);
return this.finishNode(nodeStart, "ObjectTypeAnnotation")
};
pp.flow_parseGenericType = function (start, id) {
var node = this.startNodeAt(start);
node.typeParameters = null;
node.id = id;
while (this.eat(tt.dot)) {
var node2 = this.startNodeAt(start);
node2.qualification = node.id;
node2.id = this.parseIdent();
node.id = this.finishNode(node2, "QualifiedTypeIdentifier");
}
if (this.isRelational("<")) {
node.typeParameters = this.flow_parseTypeParameterInstantiation();
}
return this.finishNode(node, "GenericTypeAnnotation");
};
pp.flow_parseVoidType = function () {
var node = this.startNode();
this.expect(tt._void);
return this.finishNode(node, "VoidTypeAnnotation");
};
pp.flow_parseTypeofType = function () {
var node = this.startNode();
this.expect(tt._typeof);
node.argument = this.flow_parsePrimaryType();
return this.finishNode(node, "TypeofTypeAnnotation");
};
pp.flow_parseTupleType = function () {
var node = this.startNode();
node.types = [];
this.expect(tt.bracketL);
// We allow trailing commas
while (this.pos < this.input.length && this.type !== tt.bracketR) {
node.types.push(this.flow_parseType());
if (this.type === tt.bracketR) break;
this.expect(tt.comma);
}
this.expect(tt.bracketR);
return this.finishNode(node, "TupleTypeAnnotation");
};
pp.flow_parseFunctionTypeParam = function () {
var optional = false;
var node = this.startNode();
node.name = this.parseIdent();
if (this.eat(tt.question)) {
optional = true;
}
this.expect(tt.colon);
node.optional = optional;
node.typeAnnotation = this.flow_parseType();
return this.finishNode(node, "FunctionTypeParam");
};
pp.flow_parseFunctionTypeParams = function () {
var ret = { params: [], rest: null };
while (this.type === tt.name) {
ret.params.push(this.flow_parseFunctionTypeParam());
if (this.type !== tt.parenR) {
this.expect(tt.comma);
}
}
if (this.eat(tt.ellipsis)) {
ret.rest = this.flow_parseFunctionTypeParam();
}
return ret;
};
pp.flow_identToTypeAnnotation = function (start, node, id) {
switch (id.name) {
case "any":
return this.finishNode(node, "AnyTypeAnnotation");
case "bool":
case "boolean":
return this.finishNode(node, "BooleanTypeAnnotation");
case "number":
return this.finishNode(node, "NumberTypeAnnotation");
case "string":
return this.finishNode(node, "StringTypeAnnotation");
default:
return this.flow_parseGenericType(start, id);
}
};
// The parsing of types roughly parallels the parsing of expressions, and
// primary types are kind of like primary expressions...they're the
// primitives with which other types are constructed.
pp.flow_parsePrimaryType = function () {
var typeIdentifier = null;
var params = null;
var returnType = null;
var start = this.currentPos();
var node = this.startNode();
var rest = null;
var tmp;
var typeParameters;
var token;
var type;
var isGroupedType = false;
switch (this.type) {
case tt.name:
return this.flow_identToTypeAnnotation(start, node, this.parseIdent());
case tt.braceL:
return this.flow_parseObjectType();
case tt.bracketL:
return this.flow_parseTupleType();
case tt.relational:
if (this.value === "<") {
node.typeParameters = this.flow_parseTypeParameterDeclaration();
this.expect(tt.parenL);
tmp = this.flow_parseFunctionTypeParams();
node.params = tmp.params;
node.rest = tmp.rest;
this.expect(tt.parenR);
this.expect(tt.arrow);
node.returnType = this.flow_parseType();
return this.finishNode(node, "FunctionTypeAnnotation");
}
case tt.parenL:
this.next();
var tmpId;
// Check to see if this is actually a grouped type
if (this.type !== tt.parenR && this.type !== tt.ellipsis) {
if (this.type === tt.name) {
//raise(tokStart, "Grouped types are currently the only flow feature not supported, request it?");
//tmpId = identToTypeAnnotation(start, node, parseIdent());
//next();
//isGroupedType = this.type !== tt.question && this.type !== tt.colon;
} else {
isGroupedType = true;
}
}
if (isGroupedType) {
if (tmpId && tt.parenR) {
type = tmpId;
} else {
type = this.flow_parseType();
this.expect(tt.parenR);
}
// If we see a => next then someone was probably confused about
// function types, so we can provide a better error message
if (this.eat(tt.arrow)) {
this.raise(node,
"Unexpected token =>. It looks like " +
"you are trying to write a function type, but you ended up " +
"writing a grouped type followed by an =>, which is a syntax " +
"error. Remember, function type parameters are named so function " +
"types look like (name1: type1, name2: type2) => returnType. You " +
"probably wrote (type1) => returnType"
);
}
return type;
}
tmp = this.flow_parseFunctionTypeParams();
node.params = tmp.params;
node.rest = tmp.rest;
this.expect(tt.parenR);
this.expect(tt.arrow);
node.returnType = this.flow_parseType();
node.typeParameters = null;
return this.finishNode(node, "FunctionTypeAnnotation");
case tt.string:
node.value = this.value;
node.raw = this.input.slice(this.start, this.end);
this.next();
return this.finishNode(node, "StringLiteralTypeAnnotation");
default:
if (this.type.keyword) {
switch (this.type.keyword) {
case "void":
return this.flow_parseVoidType();
case "typeof":
return this.flow_parseTypeofType();
}
}
}
this.unexpected();
};
pp.flow_parsePostfixType = function () {
var node = this.startNode();
var type = node.elementType = this.flow_parsePrimaryType();
if (this.type === tt.bracketL) {
this.expect(tt.bracketL);
this.expect(tt.bracketR);
return this.finishNode(node, "ArrayTypeAnnotation");
}
return type;
};
pp.flow_parsePrefixType = function () {
var node = this.startNode();
if (this.eat(tt.question)) {
node.typeAnnotation = this.flow_parsePrefixType();
return this.finishNode(node, "NullableTypeAnnotation");
}
return this.flow_parsePostfixType();
};
pp.flow_parseIntersectionType = function () {
var node = this.startNode();
var type = this.flow_parsePrefixType();
node.types = [type];
while (this.eat(tt.bitwiseAND)) {
node.types.push(this.flow_parsePrefixType());
}
return node.types.length === 1 ? type : this.finishNode(node, "IntersectionTypeAnnotation");
};
pp.flow_parseUnionType = function () {
var node = this.startNode();
var type = this.flow_parseIntersectionType();
node.types = [type];
while (this.eat(tt.bitwiseOR)) {
node.types.push(this.flow_parseIntersectionType());
}
return node.types.length === 1 ? type : this.finishNode(node, "UnionTypeAnnotation");
};
pp.flow_parseType = function () {
var oldInType = this.inType;
this.inType = true;
var type = this.flow_parseUnionType();
this.inType = oldInType;
return type;
};
pp.flow_parseTypeAnnotation = function () {
var node = this.startNode();
var oldInType = this.inType;
this.inType = true;
this.expect(tt.colon);
node.typeAnnotation = this.flow_parseType();
this.inType = oldInType;
return this.finishNode(node, "TypeAnnotation");
};
pp.flow_parseTypeAnnotatableIdentifier = function (requireTypeAnnotation, canBeOptionalParam) {
var node = this.startNode();
var ident = this.parseIdent();
var isOptionalParam = false;
if (canBeOptionalParam && this.eat(tt.question)) {
this.expect(tt.question);
isOptionalParam = true;
}
if (requireTypeAnnotation || this.type === tt.colon) {
ident.typeAnnotation = this.flow_parseTypeAnnotation();
this.finishNode(ident, ident.type);
}
if (isOptionalParam) {
ident.optional = true;
this.finishNode(ident, ident.type);
}
return ident;
};
acorn.plugins.flow = function (instance) {
// function name(): string {}
instance.extend("parseFunctionBody", function (inner) {
return function (node, allowExpression) {
if (this.type === tt.colon) {
node.returnType = this.flow_parseTypeAnnotation();
}
return inner.call(this, node, allowExpression);
};
});
instance.extend("parseExpressionStatement", function (inner) {
return function (node, expr) {
if (expr.type === "Identifier") {
if (expr.name === "declare") {
if (this.type === tt._class || this.type === tt.name || this.type === tt._function || this.type === tt._var) {
return this.flow_parseDeclare(node);
}
} else if (this.type === tt.name) {
if (expr.name === "interface") {
return this.flow_parseInterface(node);
} else if (expr.name === "type") {
return this.flow_parseTypeAlias(node);
}
}
}
return inner.call(this, node, expr);
};
});
instance.extend("parseParenItem", function (inner) {
return function (node, start) {
if (this.type === tt.colon) {
var typeCastNode = this.startNodeAt(start);
typeCastNode.expression = node;
typeCastNode.typeAnnotation = this.flow_parseTypeAnnotation();
return this.finishNode(typeCastNode, "TypeCastExpression");
} else {
return node;
}
};
});
instance.extend("parseClassId", function (inner) {
return function (node, isStatement) {
inner.call(this, node, isStatement);
if (this.isRelational("<")) {
node.typeParameters = this.flow_parseTypeParameterDeclaration();
}
};
});
instance.extend("parseClassSuper", function (inner) {
return function (node, isStatement) {
inner.call(this, node, isStatement);
if (node.superClass && this.isRelational("<")) {
node.superTypeParameters = this.flow_parseTypeParameterInstantiation();
}
if (this.isContextual("implements")) {
this.next();
var implemented = node.implements = [];
do {
var node = this.startNode();
node.id = this.parseIdent();
if (this.isRelational("<")) {
node.typeParameters = this.flow_parseTypeParameterInstantiation();
} else {
node.typeParameters = null;
}
implemented.push(this.finishNode(node, "ClassImplements"));
} while(this.eat(tt.comma));
}
};
});
instance.extend("parseAssignableListItemTypes", function (inner) {
return function (param) {
if (this.eat(tt.question)) {
param.optional = true;
}
if (this.type === tt.colon) {
param.typeAnnotation = this.flow_parseTypeAnnotation();
}
this.finishNode(param, param.type);
return param;
};
});
// function foo<T>() {}
instance.extend("parseFunctionParams", function (inner) {
return function (node) {
if (this.isRelational("<")) {
node.typeParameters = this.flow_parseTypeParameterDeclaration();
}
inner.call(this, node);
};
});
// var foo: string = bar;
instance.extend("parseVarHead", function (inner) {
return function (decl) {
inner.call(this, decl);
if (this.type === tt.colon) {
decl.id.typeAnnotation = this.flow_parseTypeAnnotation();
this.finishNode(decl.id, decl.id.type);
}
};
});
}

658
src/babel/parser/jsx.js Normal file
View File

@ -0,0 +1,658 @@
import acorn from "../../acorn";
var tt = acorn.tokTypes;
var tc = acorn.tokContexts;
tc.j_oTag = new acorn.TokContext("<tag", false);
tc.j_cTag = new acorn.TokContext("</tag", false);
tc.j_expr = new acorn.TokContext("<tag>...</tag>", true, true);
tt.jsxName = new acorn.TokenType("jsxName");
tt.jsxText = new acorn.TokenType("jsxText", {beforeExpr: true});
tt.jsxTagStart = new acorn.TokenType("jsxTagStart");
tt.jsxTagEnd = new acorn.TokenType("jsxTagEnd");
tt.jsxTagStart.updateContext = function() {
this.context.push(tc.j_expr); // treat as beginning of JSX expression
this.context.push(tc.j_oTag); // start opening tag context
this.exprAllowed = false;
};
tt.jsxTagEnd.updateContext = function(prevType) {
var out = this.context.pop();
if (out === tc.j_oTag && prevType === tt.slash || out === tc.j_cTag) {
this.context.pop();
this.exprAllowed = this.curContext() === tc.j_expr;
} else {
this.exprAllowed = true;
}
};
var pp = acorn.Parser.prototype;
// Reads inline JSX contents token.
pp.jsx_readToken = function() {
var out = "", chunkStart = this.pos;
for (;;) {
if (this.pos >= this.input.length)
this.raise(this.start, "Unterminated JSX contents");
var ch = this.input.charCodeAt(this.pos);
switch (ch) {
case 60: // '<'
case 123: // '{'
if (this.pos === this.start) {
if (ch === 60 && this.exprAllowed) {
++this.pos;
return this.finishToken(tt.jsxTagStart);
}
return this.getTokenFromCode(ch);
}
out += this.input.slice(chunkStart, this.pos);
return this.finishToken(tt.jsxText, out);
case 38: // '&'
out += this.input.slice(chunkStart, this.pos);
out += this.jsx_readEntity();
chunkStart = this.pos;
break;
default:
if (acorn.isNewLine(ch)) {
out += this.input.slice(chunkStart, this.pos);
++this.pos;
if (ch === 13 && this.input.charCodeAt(this.pos) === 10) {
++this.pos;
out += "\n";
} else {
out += String.fromCharCode(ch);
}
if (this.options.locations) {
++this.curLine;
this.lineStart = this.pos;
}
chunkStart = this.pos;
} else {
++this.pos;
}
}
}
};
pp.jsx_readString = function(quote) {
var out = "", chunkStart = ++this.pos;
for (;;) {
if (this.pos >= this.input.length)
this.raise(this.start, "Unterminated string constant");
var ch = this.input.charCodeAt(this.pos);
if (ch === quote) break;
if (ch === 38) { // '&'
out += this.input.slice(chunkStart, this.pos);
out += this.jsx_readEntity();
chunkStart = this.pos;
} else {
++this.pos;
}
}
out += this.input.slice(chunkStart, this.pos++);
return this.finishToken(tt.string, out);
};
var XHTMLEntities = {
quot: '\u0022',
amp: '&',
apos: '\u0027',
lt: '<',
gt: '>',
nbsp: '\u00A0',
iexcl: '\u00A1',
cent: '\u00A2',
pound: '\u00A3',
curren: '\u00A4',
yen: '\u00A5',
brvbar: '\u00A6',
sect: '\u00A7',
uml: '\u00A8',
copy: '\u00A9',
ordf: '\u00AA',
laquo: '\u00AB',
not: '\u00AC',
shy: '\u00AD',
reg: '\u00AE',
macr: '\u00AF',
deg: '\u00B0',
plusmn: '\u00B1',
sup2: '\u00B2',
sup3: '\u00B3',
acute: '\u00B4',
micro: '\u00B5',
para: '\u00B6',
middot: '\u00B7',
cedil: '\u00B8',
sup1: '\u00B9',
ordm: '\u00BA',
raquo: '\u00BB',
frac14: '\u00BC',
frac12: '\u00BD',
frac34: '\u00BE',
iquest: '\u00BF',
Agrave: '\u00C0',
Aacute: '\u00C1',
Acirc: '\u00C2',
Atilde: '\u00C3',
Auml: '\u00C4',
Aring: '\u00C5',
AElig: '\u00C6',
Ccedil: '\u00C7',
Egrave: '\u00C8',
Eacute: '\u00C9',
Ecirc: '\u00CA',
Euml: '\u00CB',
Igrave: '\u00CC',
Iacute: '\u00CD',
Icirc: '\u00CE',
Iuml: '\u00CF',
ETH: '\u00D0',
Ntilde: '\u00D1',
Ograve: '\u00D2',
Oacute: '\u00D3',
Ocirc: '\u00D4',
Otilde: '\u00D5',
Ouml: '\u00D6',
times: '\u00D7',
Oslash: '\u00D8',
Ugrave: '\u00D9',
Uacute: '\u00DA',
Ucirc: '\u00DB',
Uuml: '\u00DC',
Yacute: '\u00DD',
THORN: '\u00DE',
szlig: '\u00DF',
agrave: '\u00E0',
aacute: '\u00E1',
acirc: '\u00E2',
atilde: '\u00E3',
auml: '\u00E4',
aring: '\u00E5',
aelig: '\u00E6',
ccedil: '\u00E7',
egrave: '\u00E8',
eacute: '\u00E9',
ecirc: '\u00EA',
euml: '\u00EB',
igrave: '\u00EC',
iacute: '\u00ED',
icirc: '\u00EE',
iuml: '\u00EF',
eth: '\u00F0',
ntilde: '\u00F1',
ograve: '\u00F2',
oacute: '\u00F3',
ocirc: '\u00F4',
otilde: '\u00F5',
ouml: '\u00F6',
divide: '\u00F7',
oslash: '\u00F8',
ugrave: '\u00F9',
uacute: '\u00FA',
ucirc: '\u00FB',
uuml: '\u00FC',
yacute: '\u00FD',
thorn: '\u00FE',
yuml: '\u00FF',
OElig: '\u0152',
oelig: '\u0153',
Scaron: '\u0160',
scaron: '\u0161',
Yuml: '\u0178',
fnof: '\u0192',
circ: '\u02C6',
tilde: '\u02DC',
Alpha: '\u0391',
Beta: '\u0392',
Gamma: '\u0393',
Delta: '\u0394',
Epsilon: '\u0395',
Zeta: '\u0396',
Eta: '\u0397',
Theta: '\u0398',
Iota: '\u0399',
Kappa: '\u039A',
Lambda: '\u039B',
Mu: '\u039C',
Nu: '\u039D',
Xi: '\u039E',
Omicron: '\u039F',
Pi: '\u03A0',
Rho: '\u03A1',
Sigma: '\u03A3',
Tau: '\u03A4',
Upsilon: '\u03A5',
Phi: '\u03A6',
Chi: '\u03A7',
Psi: '\u03A8',
Omega: '\u03A9',
alpha: '\u03B1',
beta: '\u03B2',
gamma: '\u03B3',
delta: '\u03B4',
epsilon: '\u03B5',
zeta: '\u03B6',
eta: '\u03B7',
theta: '\u03B8',
iota: '\u03B9',
kappa: '\u03BA',
lambda: '\u03BB',
mu: '\u03BC',
nu: '\u03BD',
xi: '\u03BE',
omicron: '\u03BF',
pi: '\u03C0',
rho: '\u03C1',
sigmaf: '\u03C2',
sigma: '\u03C3',
tau: '\u03C4',
upsilon: '\u03C5',
phi: '\u03C6',
chi: '\u03C7',
psi: '\u03C8',
omega: '\u03C9',
thetasym: '\u03D1',
upsih: '\u03D2',
piv: '\u03D6',
ensp: '\u2002',
emsp: '\u2003',
thinsp: '\u2009',
zwnj: '\u200C',
zwj: '\u200D',
lrm: '\u200E',
rlm: '\u200F',
ndash: '\u2013',
mdash: '\u2014',
lsquo: '\u2018',
rsquo: '\u2019',
sbquo: '\u201A',
ldquo: '\u201C',
rdquo: '\u201D',
bdquo: '\u201E',
dagger: '\u2020',
Dagger: '\u2021',
bull: '\u2022',
hellip: '\u2026',
permil: '\u2030',
prime: '\u2032',
Prime: '\u2033',
lsaquo: '\u2039',
rsaquo: '\u203A',
oline: '\u203E',
frasl: '\u2044',
euro: '\u20AC',
image: '\u2111',
weierp: '\u2118',
real: '\u211C',
trade: '\u2122',
alefsym: '\u2135',
larr: '\u2190',
uarr: '\u2191',
rarr: '\u2192',
darr: '\u2193',
harr: '\u2194',
crarr: '\u21B5',
lArr: '\u21D0',
uArr: '\u21D1',
rArr: '\u21D2',
dArr: '\u21D3',
hArr: '\u21D4',
forall: '\u2200',
part: '\u2202',
exist: '\u2203',
empty: '\u2205',
nabla: '\u2207',
isin: '\u2208',
notin: '\u2209',
ni: '\u220B',
prod: '\u220F',
sum: '\u2211',
minus: '\u2212',
lowast: '\u2217',
radic: '\u221A',
prop: '\u221D',
infin: '\u221E',
ang: '\u2220',
and: '\u2227',
or: '\u2228',
cap: '\u2229',
cup: '\u222A',
'int': '\u222B',
there4: '\u2234',
sim: '\u223C',
cong: '\u2245',
asymp: '\u2248',
ne: '\u2260',
equiv: '\u2261',
le: '\u2264',
ge: '\u2265',
sub: '\u2282',
sup: '\u2283',
nsub: '\u2284',
sube: '\u2286',
supe: '\u2287',
oplus: '\u2295',
otimes: '\u2297',
perp: '\u22A5',
sdot: '\u22C5',
lceil: '\u2308',
rceil: '\u2309',
lfloor: '\u230A',
rfloor: '\u230B',
lang: '\u2329',
rang: '\u232A',
loz: '\u25CA',
spades: '\u2660',
clubs: '\u2663',
hearts: '\u2665',
diams: '\u2666'
};
var hexNumber = /^[\da-fA-F]+$/;
var decimalNumber = /^\d+$/;
pp.jsx_readEntity = function() {
var str = "", count = 0, entity;
var ch = this.input[this.pos];
if (ch !== "&")
this.raise(this.pos, "Entity must start with an ampersand");
var startPos = ++this.pos;
while (this.pos < this.input.length && count++ < 10) {
ch = this.input[this.pos++];
if (ch === ";") {
if (str[0] === "#") {
if (str[1] === "x") {
str = str.substr(2);
if (hexNumber.test(str))
entity = String.fromCharCode(parseInt(str, 16));
} else {
str = str.substr(1);
if (decimalNumber.test(str))
entity = String.fromCharCode(parseInt(str, 10));
}
} else {
entity = XHTMLEntities[str];
}
break;
}
str += ch;
}
if (!entity) {
this.pos = startPos;
return "&";
}
return entity;
};
// Read a JSX identifier (valid tag or attribute name).
//
// Optimized version since JSX identifiers can't contain
// escape characters and so can be read as single slice.
// Also assumes that first character was already checked
// by isIdentifierStart in readToken.
pp.jsx_readWord = function() {
var ch, start = this.pos;
do {
ch = this.input.charCodeAt(++this.pos);
} while (acorn.isIdentifierChar(ch) || ch === 45); // '-'
return this.finishToken(tt.jsxName, this.input.slice(start, this.pos));
};
// Transforms JSX element name to string.
function getQualifiedJSXName(object) {
if (object.type === "JSXIdentifier")
return object.name;
if (object.type === "JSXNamespacedName")
return object.namespace.name + ':' + object.name.name;
if (object.type === "JSXMemberExpression")
return getQualifiedJSXName(object.object) + '.' +
getQualifiedJSXName(object.property);
}
// Parse next token as JSX identifier
pp.jsx_parseIdentifier = function() {
var node = this.startNode();
if (this.type === tt.jsxName)
node.name = this.value;
else if (this.type.keyword)
node.name = this.type.keyword;
else
this.unexpected();
this.next();
return this.finishNode(node, "JSXIdentifier");
};
// Parse namespaced identifier.
pp.jsx_parseNamespacedName = function() {
var start = this.currentPos();
var name = this.jsx_parseIdentifier();
if (!this.eat(tt.colon)) return name;
var node = this.startNodeAt(start);
node.namespace = name;
node.name = this.jsx_parseIdentifier();
return this.finishNode(node, "JSXNamespacedName");
};
// Parses element name in any form - namespaced, member
// or single identifier.
pp.jsx_parseElementName = function() {
var start = this.currentPos();
var node = this.jsx_parseNamespacedName();
while (this.eat(tt.dot)) {
var newNode = this.startNodeAt(start);
newNode.object = node;
newNode.property = this.jsx_parseIdentifier();
node = this.finishNode(newNode, "JSXMemberExpression");
}
return node;
};
// Parses any type of JSX attribute value.
pp.jsx_parseAttributeValue = function() {
switch (this.type) {
case tt.braceL:
var node = this.jsx_parseExpressionContainer();
if (node.expression.type === "JSXEmptyExpression")
this.raise(node.start, "JSX attributes must only be assigned a non-empty expression");
return node;
case tt.jsxTagStart:
case tt.string:
return this.parseExprAtom();
default:
this.raise(this.start, "JSX value should be either an expression or a quoted JSX text");
}
};
// JSXEmptyExpression is unique type since it doesn't actually parse anything,
// and so it should start at the end of last read token (left brace) and finish
// at the beginning of the next one (right brace).
pp.jsx_parseEmptyExpression = function() {
var tmp = this.start;
this.start = this.lastTokEnd;
this.lastTokEnd = tmp;
tmp = this.startLoc;
this.startLoc = this.lastTokEndLoc;
this.lastTokEndLoc = tmp;
return this.finishNode(this.startNode(), "JSXEmptyExpression");
};
// Parses JSX expression enclosed into curly brackets.
pp.jsx_parseExpressionContainer = function() {
var node = this.startNode();
this.next();
node.expression = this.type === tt.braceR
? this.jsx_parseEmptyExpression()
: this.parseExpression();
this.expect(tt.braceR);
return this.finishNode(node, "JSXExpressionContainer");
};
// Parses following JSX attribute name-value pair.
pp.jsx_parseAttribute = function() {
var node = this.startNode();
if (this.eat(tt.braceL)) {
this.expect(tt.ellipsis);
node.argument = this.parseMaybeAssign();
this.expect(tt.braceR);
return this.finishNode(node, "JSXSpreadAttribute");
}
node.name = this.jsx_parseNamespacedName();
node.value = this.eat(tt.eq) ? this.jsx_parseAttributeValue() : null;
return this.finishNode(node, "JSXAttribute");
};
// Parses JSX opening tag starting after '<'.
pp.jsx_parseOpeningElementAt = function(start) {
var node = this.startNodeAt(start);
node.attributes = [];
node.name = this.jsx_parseElementName();
while (this.type !== tt.slash && this.type !== tt.jsxTagEnd)
node.attributes.push(this.jsx_parseAttribute());
node.selfClosing = this.eat(tt.slash);
this.expect(tt.jsxTagEnd);
return this.finishNode(node, "JSXOpeningElement");
};
// Parses JSX closing tag starting after '</'.
pp.jsx_parseClosingElementAt = function(start) {
var node = this.startNodeAt(start);
node.name = this.jsx_parseElementName();
this.expect(tt.jsxTagEnd);
return this.finishNode(node, "JSXClosingElement");
};
// Parses entire JSX element, including it's opening tag
// (starting after '<'), attributes, contents and closing tag.
pp.jsx_parseElementAt = function(start) {
var node = this.startNodeAt(start);
var children = [];
var openingElement = this.jsx_parseOpeningElementAt(start);
var closingElement = null;
if (!openingElement.selfClosing) {
contents: for (;;) {
switch (this.type) {
case tt.jsxTagStart:
start = this.currentPos();
this.next();
if (this.eat(tt.slash)) {
closingElement = this.jsx_parseClosingElementAt(start);
break contents;
}
children.push(this.jsx_parseElementAt(start));
break;
case tt.jsxText:
children.push(this.parseExprAtom());
break;
case tt.braceL:
children.push(this.jsx_parseExpressionContainer());
break;
default:
this.unexpected();
}
}
if (getQualifiedJSXName(closingElement.name) !== getQualifiedJSXName(openingElement.name))
this.raise(
closingElement.start,
"Expected corresponding JSX closing tag for <" + getQualifiedJSXName(openingElement.name) + ">");
}
node.openingElement = openingElement;
node.closingElement = closingElement;
node.children = children;
return this.finishNode(node, "JSXElement");
};
// Parses entire JSX element from current position.
pp.jsx_parseElement = function() {
var start = this.currentPos();
this.next();
return this.jsx_parseElementAt(start);
};
acorn.plugins.jsx = function(instance) {
instance.extend("parseExprAtom", function(inner) {
return function(refShortHandDefaultPos) {
if (this.type === tt.jsxText)
return this.parseLiteral(this.value);
else if (this.type === tt.jsxTagStart)
return this.jsx_parseElement();
else
return inner.call(this, refShortHandDefaultPos);
};
});
instance.extend("readToken", function(inner) {
return function(code) {
var context = this.curContext();
if (context === tc.j_expr) return this.jsx_readToken();
if (context === tc.j_oTag || context === tc.j_cTag) {
if (acorn.isIdentifierStart(code)) return this.jsx_readWord();
if (code == 62) {
++this.pos;
return this.finishToken(tt.jsxTagEnd);
}
if ((code === 34 || code === 39) && context == tc.j_oTag)
return this.jsx_readString(code);
}
if (code === 60 && this.exprAllowed) {
++this.pos;
return this.finishToken(tt.jsxTagStart);
}
return inner.call(this, code);
};
});
instance.extend("updateContext", function(inner) {
return function(prevType) {
if (this.type == tt.braceL) {
var curContext = this.curContext();
if (curContext == tc.j_oTag) this.context.push(tc.b_expr);
else if (curContext == tc.j_expr) this.context.push(tc.b_tmpl);
else inner.call(this, prevType);
this.exprAllowed = true;
} else if (this.type === tt.slash && prevType === tt.jsxTagStart) {
this.context.length -= 2; // do not consider JSX expr -> JSX open tag -> ... anymore
this.context.push(tc.j_cTag); // reconsider as closing tag context
this.exprAllowed = false;
} else {
return inner.call(this, prevType);
}
};
});
}

View File

@ -21,6 +21,9 @@ import path from "path";
import each from "lodash/collection/each";
import * as t from "../../types";
import "../../parser/jsx";
import "../../parser/flow";
var checkTransformerVisitor = {
enter(node, parent, scope, state) {
checkNode(state.stack, node, scope);
@ -35,7 +38,7 @@ function checkNode(stack, node, scope) {
}
export default class File {
constructor(opts) {
constructor(opts = {}) {
this.dynamicImportedNoDefault = [];
this.dynamicImportIds = {};
this.dynamicImported = [];
@ -46,8 +49,8 @@ export default class File {
this.data = {};
this.lastStatements = [];
this.log = new Logger(this, opts.filename || "unknown");
this.opts = this.normalizeOptions(opts);
this.log = new Logger(this);
this.ast = {};
this.buildTransformers();
@ -98,7 +101,7 @@ export default class File {
if (key[0] === "_") continue;
let option = File.options[key];
if (!option) throw new ReferenceError(`Unknown option: ${key}`);
if (!option) this.log.error(`Unknown option: ${key}`, ReferenceError);
}
for (let key in File.options) {
@ -181,7 +184,7 @@ export default class File {
each(transform.transformers, function (transformer, key) {
var pass = transformers[key] = transformer.buildPass(file);
if (pass.canRun) {
if (pass.canTransform) {
stack.push(pass);
if (transformer.metadata.secondPass) {
@ -274,7 +277,7 @@ export default class File {
this.dynamicImported.push(declar);
if (noDefault) this.dynamicImportedNoDefault.push(declar);
if (this.transformers["es6.modules"].canRun) {
if (this.transformers["es6.modules"].canTransform) {
this.moduleFormatter.importSpecifier(specifiers[0], declar, this.dynamicImports);
} else {
this.dynamicImports.push(declar);
@ -382,19 +385,27 @@ export default class File {
//
var parseOpts = {};
var parseOpts = {
filename: opts.filename,
plugins: {}
};
var transformers = parseOpts.transformers = {};
for (var key in this.transformers) {
transformers[key] = this.transformers[key].canRun;
transformers[key] = this.transformers[key].canParse;
}
parseOpts.looseModules = this.isLoose("es6.modules");
parseOpts.strictMode = this.transformers.strict.canRun;
parseOpts.strictMode = transformers.strict;
if (!opts.standardOnly) {
parseOpts.plugins.jsx = true;
parseOpts.plugins.flow = true;
}
//
return parse(opts, code, (tree) => {
return parse(parseOpts, code, (tree) => {
this.transform(tree);
return this.generate();
});
@ -424,7 +435,7 @@ export default class File {
this.lastStatements = t.getLastStatements(ast.program);
var modFormatter = this.moduleFormatter = this.getModuleFormatter(this.opts.modules);
if (modFormatter.init && this.transformers["es6.modules"].canRun) {
if (modFormatter.init && this.transformers["es6.modules"].canTransform) {
modFormatter.init();
}

View File

@ -1,8 +1,8 @@
import * as util from "../../util";
export default class Logger {
constructor(file: File) {
this.filename = file.opts.filename;
constructor(file: File, filename: string) {
this.filename = filename;
this.file = file;
}
@ -12,6 +12,10 @@ export default class Logger {
return parts;
}
error(msg: string, Constructor = Error) {
throw new Constructor(this._buildMessage(msg));
}
deprecate(msg) {
if (!this.file.opts.suppressDeprecationMessages) {
console.error(msg);

View File

@ -228,14 +228,14 @@ export default class DefaultFormatter {
// export { foo } from "test";
nodes.push(this.buildExportsAssignment(
t.getSpecifierName(specifier),
node.local,
ref,
node
));
}
} else {
// export { foo };
nodes.push(this.buildExportsAssignment(t.getSpecifierName(specifier), specifier.id, node));
nodes.push(this.buildExportsAssignment(specifier.local, specifier.exported, node));
}
}

View File

@ -69,7 +69,6 @@ export default class AMDFormatter extends DefaultFormatter {
}
importSpecifier(specifier, node, nodes) {
var key = t.getSpecifierName(specifier);
var ref = this.getExternalReference(node);
if (includes(this.file.dynamicImportedNoDefault, node)) {
@ -86,7 +85,7 @@ export default class AMDFormatter extends DefaultFormatter {
}
nodes.push(t.variableDeclaration("var", [
t.variableDeclarator(key, ref)
t.variableDeclarator(node.local, ref)
]));
}

View File

@ -14,7 +14,9 @@
"EmptyStatement": ["Statement"],
"LabeledStatement": ["Statement"],
"VariableDeclaration": ["Statement", "Declaration"],
"ExportDeclaration": ["Statement", "Declaration", "ModuleDeclaration"],
"ExportAllDeclaration": ["Statement", "Declaration", "ModuleDeclaration", "ExportDeclaration"],
"ExportDefaultDeclaration": ["Statement", "Declaration", "ModuleDeclaration", "ExportDeclaration"],
"ExportNamedDeclaration": ["Statement", "Declaration", "ModuleDeclaration", "ExportDeclaration"],
"ImportDeclaration": ["Statement", "Declaration", "ModuleDeclaration"],
"PrivateDeclaration": ["Statement", "Declaration"],

View File

@ -18,8 +18,6 @@ export function getBindingIdentifiers(node: Object): Object {
if (t.isIdentifier(id)) {
ids[id.name] = id;
} else if (t.isImportSpecifier(id)) {
search.push(id.name || id.id);
} else if (t.isExportDeclaration(id)) {
if (t.isDeclaration(node.declaration)) {
search.push(node.declaration);
@ -38,7 +36,8 @@ export function getBindingIdentifiers(node: Object): Object {
getBindingIdentifiers.keys = {
UnaryExpression: ["argument"],
AssignmentExpression: ["left"],
ImportBatchSpecifier: ["name"],
ImportSpecifier: ["local"],
ImportNamespaceSpecifier: ["local"],
VariableDeclarator: ["id"],
FunctionDeclaration: ["id"],
FunctionExpression: ["id"],
@ -83,23 +82,3 @@ export function getLastStatements(node: Object): Array<Object> {
return nodes;
}
/**
* Description
*/
export function getSpecifierName(specifier: Object): Object {
return specifier.name || specifier.id;
}
/**
* Description
*/
export function getSpecifierId(specifier: Object): Object {
if (specifier.default) {
return t.identifier("default");
} else {
return specifier.id;
}
}

View File

@ -23,8 +23,10 @@
"DoWhileStatement": ["body", "test"],
"EmptyStatement": [],
"ExportBatchSpecifier": [],
"ExportDeclaration": ["declaration", "specifiers", "source"],
"ExportSpecifier": ["id", "name"],
"ExportAllDeclaration": ["source"],
"ExportDefaultDeclaration": ["declaration"],
"ExportNamedDeclaration": ["declaration", "specifiers", "source"],
"ExportSpecifier": ["local", "exported"],
"ExpressionStatement": ["expression"],
"File": ["program"],
"ForInStatement": ["left", "right", "body"],
@ -34,9 +36,9 @@
"FunctionExpression": ["id", "params", "defaults", "rest", "body", "returnType", "typeParameters"],
"Identifier": ["typeAnnotation"],
"IfStatement": ["test", "consequent", "alternate"],
"ImportBatchSpecifier": ["id"],
"ImportNamespaceSpecifier": ["local"],
"ImportDeclaration": ["specifiers", "source"],
"ImportSpecifier": ["id", "name"],
"ImportSpecifier": ["imported", "local"],
"LabeledStatement": ["label", "body"],
"Literal": [],
"LogicalExpression": ["left", "right"],