2017-05-29 07:06:09 +03:00
|
|
|
"use strict";
|
|
|
|
|
2017-12-26 04:23:50 +03:00
|
|
|
const createError = require("../common/parser-create-error");
|
2018-05-24 21:30:45 +03:00
|
|
|
const hasPragma = require("./pragma").hasPragma;
|
|
|
|
const locFns = require("./loc");
|
2017-06-01 03:50:55 +03:00
|
|
|
|
2017-07-24 04:43:49 +03:00
|
|
|
function parse(text, parsers, opts) {
|
2017-05-29 07:06:09 +03:00
|
|
|
// Inline the require to avoid loading all the JS if we don't use it
|
2018-05-25 19:27:41 +03:00
|
|
|
const babylon = require("@babel/parser");
|
2017-05-29 07:06:09 +03:00
|
|
|
|
|
|
|
const babylonOptions = {
|
|
|
|
sourceType: "module",
|
2018-07-11 08:18:20 +03:00
|
|
|
allowAwaitOutsideFunction: true,
|
2017-06-21 00:42:58 +03:00
|
|
|
allowImportExportEverywhere: true,
|
2017-05-29 07:06:09 +03:00
|
|
|
allowReturnOutsideFunction: true,
|
2018-07-11 08:18:20 +03:00
|
|
|
allowSuperOutsideMethod: true,
|
2017-05-29 07:06:09 +03:00
|
|
|
plugins: [
|
|
|
|
"jsx",
|
|
|
|
"flow",
|
|
|
|
"doExpressions",
|
|
|
|
"objectRestSpread",
|
2018-05-24 23:06:33 +03:00
|
|
|
"decorators-legacy",
|
2017-05-29 07:06:09 +03:00
|
|
|
"classProperties",
|
2017-12-02 01:39:10 +03:00
|
|
|
"exportDefaultFrom",
|
|
|
|
"exportNamespaceFrom",
|
2017-05-29 07:06:09 +03:00
|
|
|
"asyncGenerators",
|
|
|
|
"functionBind",
|
|
|
|
"functionSent",
|
2017-06-20 18:36:14 +03:00
|
|
|
"dynamicImport",
|
2017-07-16 16:59:49 +03:00
|
|
|
"numericSeparator",
|
2017-07-31 23:40:14 +03:00
|
|
|
"importMeta",
|
2017-08-03 10:38:02 +03:00
|
|
|
"optionalCatchBinding",
|
2017-09-19 22:41:24 +03:00
|
|
|
"optionalChaining",
|
2017-10-16 01:13:25 +03:00
|
|
|
"classPrivateProperties",
|
2018-08-03 06:19:21 +03:00
|
|
|
["pipelineOperator", { proposal: "minimal" }],
|
2018-06-15 03:35:39 +03:00
|
|
|
"nullishCoalescingOperator",
|
2018-06-15 19:20:04 +03:00
|
|
|
"bigInt",
|
2018-06-15 03:35:39 +03:00
|
|
|
"throwExpressions"
|
2017-05-29 07:06:09 +03:00
|
|
|
]
|
|
|
|
};
|
|
|
|
|
2017-07-24 04:43:49 +03:00
|
|
|
const parseMethod =
|
2018-04-25 17:10:22 +03:00
|
|
|
opts && (opts.parser === "json" || opts.parser === "json5")
|
|
|
|
? "parseExpression"
|
|
|
|
: "parse";
|
2017-07-24 04:43:49 +03:00
|
|
|
|
2017-05-29 07:06:09 +03:00
|
|
|
let ast;
|
|
|
|
try {
|
2017-07-24 04:43:49 +03:00
|
|
|
ast = babylon[parseMethod](text, babylonOptions);
|
2017-05-29 07:06:09 +03:00
|
|
|
} catch (originalError) {
|
|
|
|
try {
|
2017-07-24 04:43:49 +03:00
|
|
|
ast = babylon[parseMethod](
|
2017-05-29 07:06:09 +03:00
|
|
|
text,
|
|
|
|
Object.assign({}, babylonOptions, { strictMode: false })
|
|
|
|
);
|
|
|
|
} catch (nonStrictError) {
|
2017-06-01 03:50:55 +03:00
|
|
|
throw createError(
|
|
|
|
// babel error prints (l:c) with cols that are zero indexed
|
|
|
|
// so we need our custom error
|
2017-06-07 04:05:22 +03:00
|
|
|
originalError.message.replace(/ \(.*\)/, ""),
|
2017-06-03 00:11:05 +03:00
|
|
|
{
|
|
|
|
start: {
|
|
|
|
line: originalError.loc.line,
|
|
|
|
column: originalError.loc.column + 1
|
|
|
|
}
|
|
|
|
}
|
2017-06-01 03:50:55 +03:00
|
|
|
);
|
2017-05-29 07:06:09 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
delete ast.tokens;
|
|
|
|
return ast;
|
|
|
|
}
|
|
|
|
|
2018-05-24 21:30:45 +03:00
|
|
|
function parseJson(text, parsers, opts) {
|
|
|
|
const ast = parse(text, parsers, Object.assign({}, opts, { parser: "json" }));
|
|
|
|
|
|
|
|
ast.comments.forEach(assertJsonNode);
|
|
|
|
assertJsonNode(ast);
|
|
|
|
|
|
|
|
return ast;
|
|
|
|
}
|
|
|
|
|
|
|
|
function assertJsonNode(node, parent) {
|
|
|
|
switch (node.type) {
|
|
|
|
case "ArrayExpression":
|
|
|
|
return node.elements.forEach(assertJsonChildNode);
|
|
|
|
case "ObjectExpression":
|
|
|
|
return node.properties.forEach(assertJsonChildNode);
|
|
|
|
case "ObjectProperty":
|
|
|
|
// istanbul ignore if
|
|
|
|
if (node.computed) {
|
|
|
|
throw createJsonError("computed");
|
|
|
|
}
|
|
|
|
// istanbul ignore if
|
|
|
|
if (node.shorthand) {
|
|
|
|
throw createJsonError("shorthand");
|
|
|
|
}
|
|
|
|
return [node.key, node.value].forEach(assertJsonChildNode);
|
|
|
|
case "UnaryExpression":
|
|
|
|
switch (node.operator) {
|
|
|
|
case "+":
|
|
|
|
case "-":
|
|
|
|
return assertJsonChildNode(node.argument);
|
|
|
|
// istanbul ignore next
|
|
|
|
default:
|
|
|
|
throw createJsonError("operator");
|
|
|
|
}
|
|
|
|
case "Identifier":
|
|
|
|
if (parent && parent.type === "ObjectProperty" && parent.key === node) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
throw createJsonError();
|
|
|
|
case "NullLiteral":
|
|
|
|
case "BooleanLiteral":
|
|
|
|
case "NumericLiteral":
|
|
|
|
case "StringLiteral":
|
|
|
|
return;
|
|
|
|
// istanbul ignore next
|
|
|
|
default:
|
|
|
|
throw createJsonError();
|
|
|
|
}
|
|
|
|
|
|
|
|
function assertJsonChildNode(child) {
|
|
|
|
return assertJsonNode(child, node);
|
|
|
|
}
|
|
|
|
|
|
|
|
// istanbul ignore next
|
|
|
|
function createJsonError(attribute) {
|
|
|
|
const name = !attribute
|
|
|
|
? node.type
|
|
|
|
: `${node.type} with ${attribute}=${JSON.stringify(node[attribute])}`;
|
|
|
|
return createError(`${name} is not allowed in JSON.`, {
|
|
|
|
start: {
|
|
|
|
line: node.loc.start.line,
|
|
|
|
column: node.loc.start.column + 1
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
const babylon = Object.assign(
|
|
|
|
{ parse, astFormat: "estree", hasPragma },
|
|
|
|
locFns
|
|
|
|
);
|
|
|
|
|
|
|
|
// Export as a plugin so we can reuse the same bundle for UMD loading
|
|
|
|
module.exports = {
|
|
|
|
parsers: {
|
|
|
|
babylon,
|
|
|
|
json: Object.assign({}, babylon, {
|
|
|
|
hasPragma() {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}),
|
|
|
|
json5: babylon,
|
|
|
|
"json-stringify": Object.assign(
|
|
|
|
{
|
|
|
|
parse: parseJson,
|
|
|
|
astFormat: "estree-json"
|
|
|
|
},
|
|
|
|
locFns
|
|
|
|
)
|
|
|
|
}
|
|
|
|
};
|