Handling babylon parsing errors in a better way (#6961)

* Handling babylon parsing errors in a better way

* Better error messages + Helpful URLs

* Replaced message from babylon completely

* Add importMeta plugin to the map
This commit is contained in:
Maaz Syed Adeeb
2017-12-19 02:19:34 +05:30
committed by Henry Zhu
parent 56638e1370
commit 17b37b5013
5 changed files with 308 additions and 12 deletions

View File

@@ -6,6 +6,7 @@ import convertSourceMap, { typeof Converter } from "convert-source-map";
import { parse } from "babylon";
import { codeFrameColumns } from "@babel/code-frame";
import File from "./file/file";
import generateMissingPluginMessage from "./util/missing-plugin-helper";
const shebangRegex = /^#!.*/;
@@ -88,21 +89,27 @@ function parser(pluginPasses, options, code) {
}
throw new Error("More than one plugin attempted to override parsing.");
} catch (err) {
const loc = err.loc;
const { loc, missingPlugin } = err;
if (loc) {
err.loc = null;
err.message =
`${options.filename || "unknown"}: ${err.message}\n` +
codeFrameColumns(
code,
{
start: {
line: loc.line,
column: loc.column + 1,
},
const codeFrame = codeFrameColumns(
code,
{
start: {
line: loc.line,
column: loc.column + 1,
},
options,
);
},
options,
);
if (missingPlugin) {
err.message =
`${options.filename || "unknown"}: ` +
generateMissingPluginMessage(missingPlugin[0], loc, codeFrame);
} else {
err.message =
`${options.filename || "unknown"}: ${err.message}\n\n` + codeFrame;
}
}
throw err;
}

View File

@@ -0,0 +1,236 @@
// @flow
const pluginNameMap = {
asyncGenerators: {
syntax: {
name: "@babel/plugin-syntax-async-generators",
url: "https://git.io/vb4SY",
},
transform: {
name: "@babel/plugin-proposal-async-generator-functions",
url: "https://git.io/vb4yp",
},
},
classProperties: {
syntax: {
name: "@babel/plugin-syntax-class-properties",
url: "https://git.io/vb4yQ",
},
transform: {
name: "@babel/plugin-proposal-class-properties",
url: "https://git.io/vb4SL",
},
},
decorators: {
syntax: {
name: "@babel/plugin-syntax-decorators",
url: "https://git.io/vb4y9",
},
transform: {
name: "@babel/plugin-proposal-decorators",
url: "https://git.io/vb4ST",
},
},
doExpressions: {
syntax: {
name: "@babel/plugin-syntax-do-expressions",
url: "https://git.io/vb4yh",
},
transform: {
name: "@babel/plugin-proposal-do-expressions",
url: "https://git.io/vb4S3",
},
},
dynamicImport: {
syntax: {
name: "@babel/plugin-syntax-dynamic-import",
url: "https://git.io/vb4Sv",
},
},
exportDefaultFrom: {
syntax: {
name: "@babel/plugin-syntax-export-default-from",
url: "https://git.io/vb4SO",
},
transform: {
name: "@babel/plugin-proposal-export-default-from",
url: "https://git.io/vb4yH",
},
},
exportNamespaceFrom: {
syntax: {
name: "@babel/plugin-syntax-export-namespace-from",
url: "https://git.io/vb4Sf",
},
transform: {
name: "@babel/plugin-proposal-export-namespace-from",
url: "https://git.io/vb4SG",
},
},
flow: {
syntax: {
name: "@babel/plugin-syntax-flow",
url: "https://git.io/vb4yb",
},
transform: {
name: "@babel/plugin-transform-flow-strip-types",
url: "https://git.io/vb49g",
},
},
functionBind: {
syntax: {
name: "@babel/plugin-syntax-function-bind",
url: "https://git.io/vb4y7",
},
transform: {
name: "@babel/plugin-proposal-function-bind",
url: "https://git.io/vb4St",
},
},
functionSent: {
syntax: {
name: "@babel/plugin-syntax-function-sent",
url: "https://git.io/vb4yN",
},
transform: {
name: "@babel/plugin-proposal-function-sent",
url: "https://git.io/vb4SZ",
},
},
importMeta: {
syntax: {
name: "@babel/plugin-syntax-import-meta",
url: "https://git.io/vbKK6",
},
},
jsx: {
syntax: {
name: "@babel/plugin-syntax-jsx",
url: "https://git.io/vb4yA",
},
transform: {
name: "@babel/plugin-transform-react-jsx",
url: "https://git.io/vb4yd",
},
},
nullishCoalescingOperator: {
syntax: {
name: "@babel/plugin-syntax-nullish-coalescing-operator",
url: "https://git.io/vb4yx",
},
transform: {
name: "@babel/plugin-proposal-nullish-coalescing-operator",
url: "https://git.io/vb4Se",
},
},
numericSeparator: {
syntax: {
name: "@babel/plugin-syntax-numeric-separator",
url: "https://git.io/vb4Sq",
},
transform: {
name: "@babel/plugin-proposal-numeric-separator",
url: "https://git.io/vb4yS",
},
},
objectRestSpread: {
syntax: {
name: "@babel/plugin-syntax-object-rest-spread",
url: "https://git.io/vb4y5",
},
transform: {
name: "@babel/plugin-proposal-object-rest-spread",
url: "https://git.io/vb4Ss",
},
},
optionalCatchBinding: {
syntax: {
name: "@babel/plugin-syntax-optional-catch-binding",
url: "https://git.io/vb4Sn",
},
transform: {
name: "@babel/plugin-proposal-optional-catch-binding",
url: "https://git.io/vb4SI",
},
},
optionalChaining: {
syntax: {
name: "@babel/plugin-syntax-optional-chaining",
url: "https://git.io/vb4Sc",
},
transform: {
name: "@babel/plugin-proposal-optional-chaining",
url: "https://git.io/vb4Sk",
},
},
pipelineOperator: {
syntax: {
name: "@babel/plugin-syntax-pipeline-operator",
url: "https://git.io/vb4yj",
},
transform: {
name: "@babel/plugin-proposal-pipeline-operator",
url: "https://git.io/vb4SU",
},
},
throwExpressions: {
syntax: {
name: "@babel/plugin-syntax-throw-expressions",
url: "https://git.io/vb4SJ",
},
transform: {
name: "@babel/plugin-proposal-throw-expressions",
url: "https://git.io/vb4yF",
},
},
typescript: {
syntax: {
name: "@babel/plugin-syntax-typescript",
url: "https://git.io/vb4SC",
},
transform: {
name: "@babel/plugin-transform-typescript",
url: "https://git.io/vb4Sm",
},
},
};
const getNameURLCombination = ({ name, url }) => `${name} (${url})`;
/*
Returns a string of the format:
Support for the experimental syntax [babylon plugin name] isn't currently enabled ([loc]):
[code frame]
Add [npm package name] ([url]) to the 'plugins' section of your Babel config
to enable [parsing|transformation].
*/
export default function generateMissingPluginMessage(
missingPluginName: string,
loc,
codeFrame,
): string {
let helpMessage =
`Support for the experimental syntax '${missingPluginName}' isn't currently enabled ` +
`(${loc.line}:${loc.column + 1}):\n\n` +
codeFrame;
const pluginInfo = pluginNameMap[missingPluginName];
if (pluginInfo) {
const { syntax: syntaxPlugin, transform: transformPlugin } = pluginInfo;
if (syntaxPlugin) {
if (transformPlugin) {
const transformPluginInfo = getNameURLCombination(transformPlugin);
helpMessage +=
`\n\nAdd ${transformPluginInfo} to the 'plugins' section of your Babel config ` +
`to enable transformation.`;
} else {
const syntaxPluginInfo = getNameURLCombination(syntaxPlugin);
helpMessage +=
`\n\nAdd ${syntaxPluginInfo} to the 'plugins' section of your Babel config ` +
`to enable parsing.`;
}
}
}
return helpMessage;
}

View File

@@ -599,4 +599,52 @@ describe("api", function() {
assert.ok(script.indexOf("typeof") >= 0);
});
});
describe("handle parsing errors", function() {
const options = {
babelrc: false,
};
it("only syntax plugin available", function(done) {
babel.transformFile(
__dirname + "/fixtures/api/parsing-errors/only-syntax/file.js",
options,
function(err) {
assert.ok(
RegExp(
"Support for the experimental syntax 'dynamicImport' isn't currently enabled \\(1:9\\):",
).exec(err.message),
);
assert.ok(
RegExp(
"Add @babel/plugin-syntax-dynamic-import \\(https://git.io/vb4Sv\\) to the " +
"'plugins' section of your Babel config to enable parsing.",
).exec(err.message),
);
done();
},
);
});
it("both syntax and transform plugin available", function(done) {
babel.transformFile(
__dirname + "/fixtures/api/parsing-errors/syntax-and-transform/file.js",
options,
function(err) {
assert.ok(
RegExp(
"Support for the experimental syntax 'asyncGenerators' isn't currently enabled \\(1:15\\):",
).exec(err.message),
);
assert.ok(
RegExp(
"Add @babel/plugin-proposal-async-generator-functions \\(https://git.io/vb4yp\\) to the " +
"'plugins' section of your Babel config to enable transformation.",
).exec(err.message),
);
done();
},
);
});
});
});

View File

@@ -0,0 +1 @@
var $ = import("jquery");

View File

@@ -0,0 +1,4 @@
async function* agf() {
await 1;
yield 2;
}