Don't default parser to babylon (#4528)

* Don't default parser to babylon

* Different default values according to version

* Fix error logging

* Add tests specifically for parser inference

* Add another test case

* Add API test
This commit is contained in:
Lucas Duailibe authored and GitHub committed 2018-05-23 16:55:06 -03:00
1 parent 9db668702c
commit 5c6e0802af
23 files changed
+338 -81

No files matched your search

+2 -6
View File
@@ -42,12 +42,8 @@ module.exports = {
}, },
check: function(text, opts) { check: function(text, opts) {
try { const formatted = formatWithCursor(text, opts).formatted;
const formatted = formatWithCursor(text, opts).formatted; return formatted === text;
return formatted === text;
} catch (e) {
return false;
}
}, },
doc, doc,
+45 -23
View File
@@ -52,6 +52,23 @@ function diff(a, b) {
} }
function handleError(context, filename, error) { function handleError(context, filename, error) {
if (error instanceof errors.UndefinedParserError) {
if (context.argv["write"] && process.stdout.isTTY) {
readline.clearLine(process.stdout, 0);
readline.cursorTo(process.stdout, 0, null);
}
if (!context.argv["list-different"]) {
process.exitCode = 2;
}
context.logger.error(error.message);
return;
}
if (context.argv["write"]) {
// Add newline to split errors from filename line.
process.stdout.write("\n");
}
const isParseError = Boolean(error && error.loc); const isParseError = Boolean(error && error.loc);
const isValidationError = /Validation Error/.test(error && error.message); const isValidationError = /Validation Error/.test(error && error.message);
@@ -119,13 +136,15 @@ function listDifferent(context, input, options, filename) {
return; return;
} }
options = Object.assign({}, options, { filepath: filename }); try {
if (!prettier.check(input, options)) {
if (!prettier.check(input, options)) { if (!context.argv["write"]) {
if (!context.argv["write"]) { context.logger.log(filename);
context.logger.log(filename); }
process.exitCode = 1;
} }
process.exitCode = 1; } catch (error) {
context.logger.error(error.message);
} }
return true; return true;
@@ -286,11 +305,11 @@ function formatStdin(context) {
const options = getOptionsForFile(context, filepath); const options = getOptionsForFile(context, filepath);
if (listDifferent(context, input, options, "(stdin)")) {
return;
}
try { try {
if (listDifferent(context, input, options, "(stdin)")) {
return;
}
writeOutput(format(context, input, options), options); writeOutput(format(context, input, options), options);
} catch (error) { } catch (error) {
handleError(context, "stdin", error); handleError(context, "stdin", error);
@@ -329,7 +348,12 @@ function eachFilename(context, patterns, callback) {
return; return;
} }
filePaths.forEach(filePath => filePaths.forEach(filePath =>
callback(filePath, getOptionsForFile(context, filePath)) callback(
filePath,
Object.assign(getOptionsForFile(context, filePath), {
filepath: filePath
})
)
); );
} catch (error) { } catch (error) {
context.logger.error( context.logger.error(
@@ -381,8 +405,6 @@ function formatFiles(context) {
return; return;
} }
listDifferent(context, input, options, filename);
const start = Date.now(); const start = Date.now();
let result; let result;
@@ -396,13 +418,17 @@ function formatFiles(context) {
); );
output = result.formatted; output = result.formatted;
} catch (error) { } catch (error) {
// Add newline to split errors from filename line.
process.stdout.write("\n");
handleError(context, filename, error); handleError(context, filename, error);
return; return;
} }
const isDifferent = output !== input;
if (context.argv["list-different"] && isDifferent) {
context.logger.log(filename);
process.exitCode = 1;
}
if (context.argv["write"]) { if (context.argv["write"]) {
if (process.stdout.isTTY) { if (process.stdout.isTTY) {
// Remove previously printed filename to log it with duration. // Remove previously printed filename to log it with duration.
@@ -412,14 +438,8 @@ function formatFiles(context) {
// Don't write the file if it won't change in order not to invalidate // Don't write the file if it won't change in order not to invalidate
// mtime based caches. // mtime based caches.
if (output === input) { if (isDifferent) {
if (!context.argv["list-different"]) { if (!context.argv["list-different"]) {
context.logger.log(`${chalk.grey(filename)} ${Date.now() - start}ms`);
}
} else {
if (context.argv["list-different"]) {
context.logger.log(filename);
} else {
context.logger.log(`${filename} ${Date.now() - start}ms`); context.logger.log(`${filename} ${Date.now() - start}ms`);
} }
@@ -432,6 +452,8 @@ function formatFiles(context) {
// Don't exit the process if one file failed // Don't exit the process if one file failed
process.exitCode = 2; process.exitCode = 2;
} }
} else if (!context.argv["list-different"]) {
context.logger.log(`${chalk.grey(filename)} ${Date.now() - start}ms`);
} }
} else if (context.argv["debug-check"]) { } else if (context.argv["debug-check"]) {
if (output) { if (output) {
+3 -1
View File
@@ -2,8 +2,10 @@
class ConfigError extends Error {} class ConfigError extends Error {}
class DebugError extends Error {} class DebugError extends Error {}
class UndefinedParserError extends Error {}
module.exports = { module.exports = {
ConfigError, ConfigError,
DebugError DebugError,
UndefinedParserError
}; };
+4 -1
View File
@@ -85,7 +85,10 @@ const options = {
since: "0.0.10", since: "0.0.10",
category: CATEGORY_GLOBAL, category: CATEGORY_GLOBAL,
type: "choice", type: "choice",
default: "babylon", default: [
{ since: "0.0.10", value: "babylon" },
{ since: "1.13.0", value: undefined }
],
description: "Which parser to use.", description: "Which parser to use.",
exception: value => exception: value =>
typeof value === "string" || typeof value === "function", typeof value === "string" || typeof value === "function",
+2 -1
View File
@@ -255,6 +255,7 @@ function format(text, opts) {
module.exports = { module.exports = {
formatWithCursor(text, opts) { formatWithCursor(text, opts) {
opts = normalizeOptions(opts);
return format(text, normalizeOptions(opts)); return format(text, normalizeOptions(opts));
}, },
@@ -275,8 +276,8 @@ module.exports = {
// Doesn't handle shebang for now // Doesn't handle shebang for now
formatDoc(doc, opts) { formatDoc(doc, opts) {
opts = normalizeOptions(opts);
const debug = printDocToDebug(doc); const debug = printDocToDebug(doc);
opts = normalizeOptions(Object.assign({}, opts, { parser: "babylon" }));
return format(debug, opts).formatted; return format(debug, opts).formatted;
}, },
+1 -1
View File
@@ -21,7 +21,7 @@ function textToDoc(text, partialNextOptions, parentOptions) {
parentParser: parentOptions.parser, parentParser: parentOptions.parser,
originalText: text originalText: text
}), }),
{ passThrough: true, inferParser: false } { passThrough: true }
); );
const result = require("./parser").parse(text, nextOptions); const result = require("./parser").parse(text, nextOptions);
+17 -19
View File
@@ -1,6 +1,7 @@
"use strict"; "use strict";
const path = require("path"); const path = require("path");
const UndefinedParserError = require("../common/errors").UndefinedParserError;
const getSupportInfo = require("../main/support").getSupportInfo; const getSupportInfo = require("../main/support").getSupportInfo;
const normalizer = require("./options-normalizer"); const normalizer = require("./options-normalizer");
const resolveParser = require("./parser").resolveParser; const resolveParser = require("./parser").resolveParser;
@@ -29,30 +30,27 @@ function normalize(options, opts) {
Object.assign({}, hiddenDefaults) Object.assign({}, hiddenDefaults)
); );
if (opts.inferParser !== false) { if (!rawOptions.parser) {
if ( if (!rawOptions.filepath) {
rawOptions.filepath && throw new UndefinedParserError(
(!rawOptions.parser || rawOptions.parser === defaults.parser) "No parser and no file path given, couldn't infer a parser."
) { );
const inferredParser = inferParser( }
rawOptions.filepath,
rawOptions.plugins rawOptions.parser = inferParser(rawOptions.filepath, rawOptions.plugins);
if (!rawOptions.parser) {
throw new UndefinedParserError(
`No parser could be inferred for file: ${rawOptions.filepath}`
); );
if (inferredParser) {
rawOptions.parser = inferredParser;
}
} }
} }
const parser = resolveParser( const parser = resolveParser(
!rawOptions.parser normalizer.normalizeApiOptions(
? rawOptions rawOptions,
: // handle deprecated parsers [supportOptions.find(x => x.name === "parser")],
normalizer.normalizeApiOptions( { passThrough: true, logger: false }
rawOptions, )
[supportOptions.find(x => x.name === "parser")],
{ passThrough: true, logger: false }
)
); );
rawOptions.astFormat = parser.astFormat; rawOptions.astFormat = parser.astFormat;
rawOptions.locEnd = parser.locEnd; rawOptions.locEnd = parser.locEnd;
-2
View File
@@ -43,8 +43,6 @@ function resolveParser(opts, parsers) {
throw new ConfigError(`Couldn't resolve parser "${opts.parser}"`); throw new ConfigError(`Couldn't resolve parser "${opts.parser}"`);
} }
} }
/* istanbul ignore next */
return parsers.babylon;
} }
function parse(text, opts) { function parse(text, opts) {
+12 -4
View File
@@ -3,7 +3,9 @@ run_spec(__dirname, ["babylon", "typescript", "flow"]);
const prettier = require("../../tests_config/require_prettier"); const prettier = require("../../tests_config/require_prettier");
test("translates cursor correctly in basic case", () => { test("translates cursor correctly in basic case", () => {
expect(prettier.formatWithCursor(" 1", { cursorOffset: 2 })).toEqual({ expect(
prettier.formatWithCursor(" 1", { parser: "babylon", cursorOffset: 2 })
).toEqual({
formatted: "1;\n", formatted: "1;\n",
cursorOffset: 1 cursorOffset: 1
}); });
@@ -11,7 +13,9 @@ test("translates cursor correctly in basic case", () => {
test("positions cursor relative to closest node, not SourceElement", () => { test("positions cursor relative to closest node, not SourceElement", () => {
const code = "return 15"; const code = "return 15";
expect(prettier.formatWithCursor(code, { cursorOffset: 15 })).toEqual({ expect(
prettier.formatWithCursor(code, { parser: "babylon", cursorOffset: 15 })
).toEqual({
formatted: "return 15;\n", formatted: "return 15;\n",
cursorOffset: 7 cursorOffset: 7
}); });
@@ -19,7 +23,9 @@ test("positions cursor relative to closest node, not SourceElement", () => {
test("keeps cursor inside formatted node", () => { test("keeps cursor inside formatted node", () => {
const code = "return 15"; const code = "return 15";
expect(prettier.formatWithCursor(code, { cursorOffset: 14 })).toEqual({ expect(
prettier.formatWithCursor(code, { parser: "babylon", cursorOffset: 14 })
).toEqual({
formatted: "return 15;\n", formatted: "return 15;\n",
cursorOffset: 7 cursorOffset: 7
}); });
@@ -30,7 +36,9 @@ test("doesn't insert second placeholder for nonexistent TypeAnnotation", () => {
foo('bar', cb => { foo('bar', cb => {
console.log('stuff') console.log('stuff')
})`; })`;
expect(prettier.formatWithCursor(code, { cursorOffset: 24 })).toEqual({ expect(
prettier.formatWithCursor(code, { parser: "babylon", cursorOffset: 24 })
).toEqual({
formatted: `foo("bar", cb => { formatted: `foo("bar", cb => {
console.log("stuff"); console.log("stuff");
}); });
@@ -30,10 +30,6 @@ exports[`show diff for 2+ error files with --debug-check (stderr) 1`] = `
" "
`; `;
exports[`show diff for 2+ error files with --debug-check (stdout) 1`] = ` exports[`show diff for 2+ error files with --debug-check (stdout) 1`] = `""`;
"
"
`;
exports[`show diff for 2+ error files with --debug-check (write) 1`] = `Array []`; exports[`show diff for 2+ error files with --debug-check (write) 1`] = `Array []`;
@@ -296,8 +296,6 @@ Valid options:
graphql GraphQL graphql GraphQL
markdown Markdown markdown Markdown
vue Vue vue Vue
Default: babylon
" "
`; `;
@@ -597,7 +595,6 @@ Format options:
Defaults to false. Defaults to false.
--parser <flow|babylon|typescript|css|less|scss|json|json5|json-stringify|graphql|markdown|vue> --parser <flow|babylon|typescript|css|less|scss|json|json5|json-stringify|graphql|markdown|vue>
Which parser to use. Which parser to use.
Defaults to babylon.
--print-width <int> The line length where Prettier will try wrap. --print-width <int> The line length where Prettier will try wrap.
Defaults to 80. Defaults to 80.
--prose-wrap <always|never|preserve> --prose-wrap <always|never|preserve>
@@ -717,8 +714,6 @@ Valid options:
graphql GraphQL graphql GraphQL
markdown Markdown markdown Markdown
vue Vue vue Vue
Default: babylon
" "
`; `;
@@ -749,7 +744,6 @@ Format options:
Defaults to false. Defaults to false.
--parser <flow|babylon|typescript|css|less|scss|json|json5|json-stringify|graphql|markdown|vue> --parser <flow|babylon|typescript|css|less|scss|json|json5|json-stringify|graphql|markdown|vue>
Which parser to use. Which parser to use.
Defaults to babylon.
--print-width <int> The line length where Prettier will try wrap. --print-width <int> The line length where Prettier will try wrap.
Defaults to 80. Defaults to 80.
--prose-wrap <always|never|preserve> --prose-wrap <always|never|preserve>
@@ -0,0 +1,98 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[` 1`] = `"No parser and no file path given, couldn't infer a parser."`;
exports[`--list-different with unknown path and no parser multiple files (stderr) 1`] = `
"[error] No parser could be inferred for file: FOO
"
`;
exports[`--list-different with unknown path and no parser specific file (stderr) 1`] = `
"[error] No parser could be inferred for file: FOO
"
`;
exports[`--write and --list-different with unknown path and no parser multiple files (stderr) 1`] = `
"[error] No parser could be inferred for file: FOO
"
`;
exports[`--write and --list-different with unknown path and no parser multiple files (stdout) 1`] = `
"foo.js
"
`;
exports[`--write and --list-different with unknown path and no parser multiple files (write) 1`] = `
Array [
Object {
"content": "foo();
",
"filename": "foo.js",
},
]
`;
exports[`--write and --list-different with unknown path and no parser specific file (stderr) 1`] = `
"[error] No parser could be inferred for file: FOO
"
`;
exports[`--write with unknown path and no parser multiple files (stderr) 1`] = `
"[error] No parser could be inferred for file: FOO
"
`;
exports[`--write with unknown path and no parser multiple files (stdout) 1`] = `
"foo.js 0ms
"
`;
exports[`--write with unknown path and no parser multiple files (write) 1`] = `
Array [
Object {
"content": "foo();
",
"filename": "foo.js",
},
]
`;
exports[`--write with unknown path and no parser specific file (stderr) 1`] = `
"[error] No parser could be inferred for file: FOO
"
`;
exports[`stdin no path and no parser --list-different logs error but exits with 0 (stderr) 1`] = `
"[error] No parser and no file path given, couldn't infer a parser.
"
`;
exports[`stdin no path and no parser logs error and exits with 2 (stderr) 1`] = `
"[error] No parser and no file path given, couldn't infer a parser.
"
`;
exports[`stdin with unknown path and no parser --list-different logs error but exits with 0 (stderr) 1`] = `
"[error] No parser could be inferred for file: foo
"
`;
exports[`stdin with unknown path and no parser logs error and exits with 2 (stderr) 1`] = `
"[error] No parser could be inferred for file: foo
"
`;
exports[`unknown path and no parser multiple files (stderr) 1`] = `
"[error] No parser could be inferred for file: FOO
"
`;
exports[`unknown path and no parser multiple files (stdout) 1`] = `
"foo();
"
`;
exports[`unknown path and no parser specific file (stderr) 1`] = `
"[error] No parser could be inferred for file: FOO
"
`;
@@ -17,7 +17,7 @@ exports[` 1`] = `
Defaults to false. Defaults to false.
--parser <flow|babylon|typescript|css|less|scss|json|json5|json-stringify|graphql|markdown|vue> --parser <flow|babylon|typescript|css|less|scss|json|json5|json-stringify|graphql|markdown|vue>
Which parser to use. Which parser to use.
Defaults to babylon." --print-width <int> The line length where Prettier will try wrap."
`; `;
exports[`show detailed external option with \`--help foo-option\` (stderr) 1`] = `""`; exports[`show detailed external option with \`--help foo-option\` (stderr) 1`] = `""`;
+14 -2
View File
@@ -40,14 +40,26 @@ describe("throw error with invalid config precedence option (configPrecedence)",
}); });
}); });
// Tests below require --parser to prevent an error (no parser/filepath specified)
describe("show warning with unknown option", () => { describe("show warning with unknown option", () => {
runPrettier("cli/config/invalid", ["--config", "option/unknown"]).test({ runPrettier("cli/config/invalid", [
"--config",
"option/unknown",
"--parser",
"babylon"
]).test({
status: 0 status: 0
}); });
}); });
describe("show warning with kebab-case option key", () => { describe("show warning with kebab-case option key", () => {
runPrettier("cli/config/invalid", ["--config", "option/kebab-case"]).test({ runPrettier("cli/config/invalid", [
"--config",
"option/kebab-case",
"--parser",
"babylon"
]).test({
status: 0 status: 0
}); });
}); });
+4 -2
View File
@@ -3,13 +3,15 @@
const runPrettier = require("../runPrettier"); const runPrettier = require("../runPrettier");
describe("write cursorOffset to stderr with --cursor-offset <int>", () => { describe("write cursorOffset to stderr with --cursor-offset <int>", () => {
runPrettier("cli", ["--cursor-offset", "2"], { input: " 1" }).test({ runPrettier("cli", ["--cursor-offset", "2", "--parser", "babylon"], {
input: " 1"
}).test({
status: 0 status: 0
}); });
}); });
describe("cursorOffset should not be affected by full-width character", () => { describe("cursorOffset should not be affected by full-width character", () => {
runPrettier("cli", ["--cursor-offset", "21"], { runPrettier("cli", ["--cursor-offset", "21", "--parser", "babylon"], {
input: `const x = ["中文", "中文", "中文", "中文", "中文", "中文", "中文", "中文", "中文", "中文", "中文"];` input: `const x = ["中文", "中文", "中文", "中文", "中文", "中文", "中文", "中文", "中文", "中文", "中文"];`
// ^ offset = 21 ^ width = 80 // ^ offset = 21 ^ width = 80
}).test({ }).test({
+1 -1
View File
@@ -11,7 +11,7 @@ describe("doesn't crash when --debug-check is passed", () => {
}); });
describe("checks stdin with --debug-check", () => { describe("checks stdin with --debug-check", () => {
runPrettier("cli/with-shebang", ["--debug-check"], { runPrettier("cli/with-shebang", ["--debug-check", "--parser", "babylon"], {
input: "0" input: "0"
}).test({ }).test({
stdout: "(stdin)\n", stdout: "(stdin)\n",
@@ -3,9 +3,11 @@
const runPrettier = require("../runPrettier"); const runPrettier = require("../runPrettier");
describe("prints doc with --debug-print-doc", () => { describe("prints doc with --debug-print-doc", () => {
runPrettier("cli/with-shebang", ["--debug-print-doc"], { runPrettier(
input: "0" "cli/with-shebang",
}).test({ ["--debug-print-doc", "--parser", "babylon"],
{ input: "0" }
).test({
stdout: '["0", ";", hardline, breakParent];\n', stdout: '["0", ";", hardline, breakParent];\n',
stderr: "", stderr: "",
status: 0 status: 0
+123
View File
@@ -0,0 +1,123 @@
"use strict";
const runPrettier = require("../runPrettier");
const prettier = require("../../tests_config/require_prettier");
describe("stdin no path and no parser", () => {
describe("logs error and exits with 2", () => {
runPrettier("cli/infer-parser/", ["--stdin"], { input: "foo" }).test({
status: 2,
stdout: "",
write: []
});
});
describe("--list-different logs error but exits with 0", () => {
runPrettier("cli/infer-parser/", ["--list-different", "--stdin"], {
input: "foo"
}).test({
status: 0,
stdout: "",
write: []
});
});
});
describe("stdin with unknown path and no parser", () => {
describe("logs error and exits with 2", () => {
runPrettier("cli/infer-parser/", ["--stdin", "--stdin-filepath", "foo"], {
input: "foo"
}).test({
status: 2,
stdout: "",
write: []
});
});
describe("--list-different logs error but exits with 0", () => {
runPrettier(
"cli/infer-parser/",
["--list-different", "--stdin", "--stdin-filepath", "foo"],
{ input: "foo" }
).test({
status: 0,
stdout: "",
write: []
});
});
});
describe("unknown path and no parser", () => {
describe("specific file", () => {
runPrettier("cli/infer-parser/", ["FOO"]).test({
status: 2,
stdout: "",
write: []
});
});
describe("multiple files", () => {
runPrettier("cli/infer-parser/", ["*"]).test({
status: 2,
write: []
});
});
});
describe("--list-different with unknown path and no parser", () => {
describe("specific file", () => {
runPrettier("cli/infer-parser/", ["--list-different", "FOO"]).test({
status: 0,
stdout: "",
write: []
});
});
describe("multiple files", () => {
runPrettier("cli/infer-parser/", ["--list-different", "*"]).test({
status: 1,
stdout: "foo.js\n",
write: []
});
});
});
describe("--write with unknown path and no parser", () => {
describe("specific file", () => {
runPrettier("cli/infer-parser/", ["--write", "FOO"]).test({
status: 2,
stdout: "",
write: []
});
});
describe("multiple files", () => {
runPrettier("cli/infer-parser/", ["--write", "*"]).test({
status: 2
});
});
});
describe("--write and --list-different with unknown path and no parser", () => {
describe("specific file", () => {
runPrettier("cli/infer-parser/", [
"--list-different",
"--write",
"FOO"
]).test({
status: 0,
stdout: "",
write: []
});
});
describe("multiple files", () => {
runPrettier("cli/infer-parser/", ["--list-different", "--write", "*"]).test(
{ status: 1 }
);
});
});
describe("API with no path and no parser", () => {
expect(() => prettier.format("foo")).toThrowErrorMatchingSnapshot();
});
@@ -3,7 +3,7 @@
const runPrettier = require("../runPrettier"); const runPrettier = require("../runPrettier");
describe("checks stdin with --list-different", () => { describe("checks stdin with --list-different", () => {
runPrettier("cli/with-shebang", ["--list-different"], { runPrettier("cli/with-shebang", ["--list-different", "--parser", "babylon"], {
input: "0" input: "0"
}).test({ }).test({
stdout: "(stdin)\n", stdout: "(stdin)\n",
@@ -64,7 +64,8 @@ describe("multiple patterns by with ignore pattern, doesn't ignore node_modules
}); });
describe("no errors on empty patterns", () => { describe("no errors on empty patterns", () => {
runPrettier("cli/multiple-patterns").test({ // --parser is mandatory if no filepath is passed
runPrettier("cli/multiple-patterns", ["--parser", "babylon"]).test({
status: 0 status: 0
}); });
}); });
+1 -1
View File
@@ -3,7 +3,7 @@
const runPrettier = require("../runPrettier"); const runPrettier = require("../runPrettier");
describe("exits with non-zero code when input has a syntax error", () => { describe("exits with non-zero code when input has a syntax error", () => {
runPrettier("cli/with-shebang", ["--stdin"], { runPrettier("cli/with-shebang", ["--stdin", "--parser", "babylon"], {
input: "a.2" input: "a.2"
}).test({ }).test({
status: 2 status: 2
Whitespace-only changes.
@@ -0,0 +1 @@
foo ( )