embed acorn
This commit is contained in:
parent
976e8c1cfd
commit
ec526f9224
2
.gitignore
vendored
2
.gitignore
vendored
@ -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
32
lib/acorn/AUTHORS
Normal 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
19
lib/acorn/LICENSE
Normal 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
4
lib/acorn/README.md
Normal 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
2934
lib/acorn/acorn.js
Normal file
File diff suppressed because it is too large
Load Diff
23
lib/acorn/package.json
Normal file
23
lib/acorn/package.json
Normal 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
96
lib/acorn/test/bench.html
Normal 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>
|
||||
3995
lib/acorn/test/codemirror-string.js
Normal file
3995
lib/acorn/test/codemirror-string.js
Normal file
File diff suppressed because it is too large
Load Diff
5218
lib/acorn/test/compare/esprima.js
Normal file
5218
lib/acorn/test/compare/esprima.js
Normal file
File diff suppressed because one or more lines are too long
23622
lib/acorn/test/compare/traceur.js
Normal file
23622
lib/acorn/test/compare/traceur.js
Normal file
File diff suppressed because one or more lines are too long
113
lib/acorn/test/driver.js
Normal file
113
lib/acorn/test/driver.js
Normal 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
14
lib/acorn/test/index.html
Normal 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
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
109
lib/acorn/test/run.js
Normal 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);
|
||||
});
|
||||
}
|
||||
})();
|
||||
15378
lib/acorn/test/tests-harmony.js
Normal file
15378
lib/acorn/test/tests-harmony.js
Normal file
File diff suppressed because it is too large
Load Diff
28967
lib/acorn/test/tests.js
Normal file
28967
lib/acorn/test/tests.js
Normal file
File diff suppressed because it is too large
Load Diff
47
lib/acorn/tools/generate-identifier-regex.js
Normal file
47
lib/acorn/tools/generate-identifier-regex.js
Normal 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) + ";");
|
||||
@ -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",
|
||||
|
||||
@ -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";
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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
728
src/babel/parser/flow.js
Normal 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
658
src/babel/parser/jsx.js
Normal 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);
|
||||
}
|
||||
};
|
||||
});
|
||||
}
|
||||
@ -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();
|
||||
}
|
||||
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -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)
|
||||
]));
|
||||
}
|
||||
|
||||
|
||||
@ -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"],
|
||||
|
||||
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@ -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"],
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user