feat: add new parser babel-ts to parse TypeScript syntaxes via Babel (#6400)

* feat: add new parser `babel-ts` to parse TypeScript syntaxes via Babel

* docs: document parser babel-ts

* chore: enable babel-ts in markdown and worker.js

* verify all TS tests against babel-ts except disabled by disableBabelTS

* support for TSDeclareMethod; fix abstract properties and methods

* fix embedded angular templates and styles

* fix TSImportType

* simplify babel options combinations

* fix method decorators

* fix ranges

* work around loc inconsistencies for SequenceExpression

* don't print trailing comma in type parameters (unsupported in TS < 3.3)

* preserve quotes for class properties

* align printing of single-parameter functions

* fix comments in degenerate single-element unions and intersections

* fix comments for methods

* fix comments for mapped types

* edit docs, change 'since' to 2.0.0

* add changelog

* fix code sample on playground

* update snapshots after rebase

Co-authored-by: Georgii Dolzhykov <thorn.mailbox@gmail.com>
This commit is contained in:
JounQinandGeorgii Dolzhykov authored and GitHub committed 2020-01-29 14:11:16 +02:00
1 parent 0c51368d33
commit c1937cb1b8
41 files changed
+375 -147

No files matched your search

@@ -0,0 +1,3 @@
#### Babel as an alternative parser for TypeScript ([#6400](https://github.com/prettier/prettier/pull/6400) by [@JounQin](https://github.com/JounQin) & [@thorn0](https://github.com/thorn0))
A new value for the `parser` option has been added: `babel-ts`, which stands for Babel with its TypeScript support enabled. The `babel-ts` parser supports JavaScript features not yet supported by TypeScript (ECMAScript proposals, e.g. [private methods and accessors](https://github.com/tc39/proposal-private-methods)), but it's less permissive when it comes to error recovery and less battle-tested than the `typescript` parser. While Babel's TypeScript plugin is quite mature, ASTs produced by the two parsers aren't 100% compatible. We tried to take the discrepancies into account, but there still must remain cases where code gets formatted differently or even incorrectly. We call upon the community to help us find such cases. If you see them, please raise issues. In the long run, this will help with [unifying the AST format](https://github.com/typescript-eslint/typescript-eslint/tree/master/packages/typescript-estree#ast-alignment-tests) in future versions of the parsers and thus contribute to a better, more solid JavaScript parser ecosystem.
+3 -2
View File
@@ -196,12 +196,13 @@ Specify which parser to use.
Prettier automatically infers the parser from the input file path, so you shouldn't have to change this setting.
Both the `babel` and `flow` parsers support the same set of JavaScript features (including Flow type annotations). They might differ in some edge cases, so if you run into one of those you can try `flow` instead of `babel`.
Both the `babel` and `flow` parsers support the same set of JavaScript features (including Flow type annotations). They might differ in some edge cases, so if you run into one of those you can try `flow` instead of `babel`. Almost the same applies to `typescript` and `babel-ts`. `babel-ts` might support JavaScript features (proposals) not yet supported by TypeScript, but it's less permissive when it comes to invalid code and less battle-tested than the `typescript` parser.
Valid options:
- `"babel"` (via [@babel/parser](https://github.com/babel/babel/tree/master/packages/babel-parser)) _Named `"babylon"` until v1.16.0_
- `"babel-flow"` (Same as `"babel"` but enables Flow parsing explicitly to avoid ambiguity) _First available in v1.16.0_
- `"babel-flow"` (same as `"babel"` but enables Flow parsing explicitly to avoid ambiguity) _First available in v1.16.0_
- `"babel-ts"` (similar to `"typescript"` but uses Babel and its TypeScript plugin) _First available in v2.0.0_
- `"flow"` (via [flow-parser](https://github.com/facebook/flow/tree/master/src/parser))
- `"typescript"` (via [@typescript-eslint/typescript-estree](https://github.com/typescript-eslint/typescript-eslint)) _First available in v1.4.0_
- `"css"` (via [postcss-scss](https://github.com/postcss/postcss-scss) and [postcss-less](https://github.com/shellscape/postcss-less), autodetects which to use) _First available in v1.7.1_
+5
View File
@@ -19,6 +19,11 @@ module.exports = [
"babel-flow"
];
},
get "babel-ts"() {
return eval("require")("../language-js/parser-babylon").parsers[
"babel-ts"
];
},
get babylon() {
return eval("require")("../language-js/parser-babylon").parsers.babel;
},
+1
View File
@@ -7,6 +7,7 @@ function clean(ast, newObj, parent) {
"comments",
"leadingComments",
"trailingComments",
"innerComments",
"extra",
"start",
"end",
+50 -6
View File
@@ -460,8 +460,9 @@ function handleMethodNameComments(
if (
enclosingNode &&
precedingNode &&
// "MethodDefinition" is handled in getCommentChildNodes
(enclosingNode.type === "Property" ||
enclosingNode.type === "MethodDefinition" ||
enclosingNode.type === "TSDeclareMethod" ||
enclosingNode.type === "TSAbstractMethodDefinition") &&
precedingNode.type === "Identifier" &&
enclosingNode.key === precedingNode &&
@@ -487,6 +488,7 @@ function handleMethodNameComments(
enclosingNode.type === "ClassProperty" ||
enclosingNode.type === "TSAbstractClassProperty" ||
enclosingNode.type === "TSAbstractMethodDefinition" ||
enclosingNode.type === "TSDeclareMethod" ||
enclosingNode.type === "MethodDefinition")
) {
addTrailingComment(precedingNode, comment);
@@ -558,7 +560,8 @@ function handleCommentInEmptyParens(text, enclosingNode, comment, options) {
if (
enclosingNode &&
((isRealFunctionLikeNode(enclosingNode) &&
enclosingNode.params.length === 0) ||
// `params` vs `parameters` - see https://github.com/babel/babel/issues/9231
(enclosingNode.params || enclosingNode.parameters).length === 0) ||
((enclosingNode.type === "CallExpression" ||
enclosingNode.type === "OptionalCallExpression" ||
enclosingNode.type === "NewExpression") &&
@@ -623,10 +626,14 @@ function handleLastFunctionArgComments(
followingNode.type === "BlockStatement"
) {
const functionParamRightParenIndex = (() => {
if (enclosingNode.params.length !== 0) {
if ((enclosingNode.params || enclosingNode.parameters).length !== 0) {
return privateUtil.getNextNonSpaceNonCommentCharacterIndexWithStartIndex(
text,
options.locEnd(privateUtil.getLast(enclosingNode.params))
options.locEnd(
privateUtil.getLast(
enclosingNode.params || enclosingNode.parameters
)
)
);
}
const functionParamLeftParenIndex = privateUtil.getNextNonSpaceNonCommentCharacterIndexWithStartIndex(
@@ -899,14 +906,51 @@ function isRealFunctionLikeNode(node) {
node.type === "TSConstructSignatureDeclaration" ||
node.type === "TSMethodSignature" ||
node.type === "TSConstructorType" ||
node.type === "TSFunctionType"
node.type === "TSFunctionType" ||
node.type === "TSDeclareMethod"
);
}
function getGapRegex(enclosingNode) {
if (
enclosingNode &&
enclosingNode.type !== "BinaryExpression" &&
enclosingNode.type !== "LogicalExpression"
) {
// Support degenerate single-element unions and intersections.
// E.g.: `type A = /* 1 */ & B`
return /^[\s(&|]*$/;
}
}
function getCommentChildNodes(node, options) {
// Prevent attaching comments to FunctionExpression in this case:
// class Foo {
// bar() // comment
// {
// baz();
// }
// }
if (
(options.parser === "typescript" || options.parser === "flow") &&
node.type === "MethodDefinition" &&
node.value &&
node.value.type === "FunctionExpression" &&
node.value.params.length === 0 &&
!node.value.returnType &&
(!node.value.typeParameters || node.value.typeParameters.length === 0) &&
node.value.body
) {
return [...(node.decorators || []), node.key, node.value.body];
}
}
module.exports = {
handleOwnLineComment,
handleEndOfLineComment,
handleRemainingComment,
hasLeadingComment,
isBlockComment
isBlockComment,
getGapRegex,
getCommentChildNodes
};
+2 -2
View File
@@ -391,7 +391,7 @@ function isAngularComponentStyles(path) {
node => node.type === "TemplateLiteral",
(node, name) => node.type === "ArrayExpression" && name === "elements",
(node, name) =>
node.type === "Property" &&
(node.type === "Property" || node.type === "ObjectProperty") &&
node.key.type === "Identifier" &&
node.key.name === "styles" &&
name === "value",
@@ -402,7 +402,7 @@ function isAngularComponentTemplate(path) {
return path.match(
node => node.type === "TemplateLiteral",
(node, name) =>
node.type === "Property" &&
(node.type === "Property" || node.type === "ObjectProperty") &&
node.key.type === "Identifier" &&
node.key.name === "template" &&
name === "value",
+2 -2
View File
@@ -32,13 +32,13 @@ const languages = [
createLanguage(require("linguist-languages/data/TypeScript"), data => ({
...data,
since: "1.4.0",
parsers: ["typescript"],
parsers: ["typescript", "babel-ts"],
vscodeLanguageIds: ["typescript"]
})),
createLanguage(require("linguist-languages/data/TSX"), data => ({
...data,
since: "1.4.0",
parsers: ["typescript"],
parsers: ["typescript", "babel-ts"],
vscodeLanguageIds: ["typescriptreact"]
})),
createLanguage(require("linguist-languages/data/JSON"), data => ({
+16 -13
View File
@@ -59,20 +59,23 @@ function locEnd(node) {
return loc;
}
function composeLoc(startNode, endNode = startNode) {
const loc = {};
if (typeof startNode.start === "number") {
loc.start = startNode.start;
loc.end = endNode.end;
}
if (Array.isArray(startNode.range)) {
loc.range = [startNode.range[0], endNode.range[1]];
}
loc.loc = {
start: startNode.loc.start,
end: endNode.loc.end
function composeLoc(startNode, endNodeOrLength = startNode) {
const length = typeof endNodeOrLength === "number" ? endNodeOrLength : -1;
const start = locStart(startNode);
const end = length !== -1 ? start + length : locEnd(endNodeOrLength);
const startLoc = startNode.loc.start;
return {
start,
end,
range: [start, end],
loc: {
start: startLoc,
end:
length !== -1
? { line: startLoc.line, column: startLoc.column + length }
: endNodeOrLength.loc.end
}
};
return loc;
}
module.exports = {
+36 -10
View File
@@ -8,7 +8,7 @@ const { hasPragma } = require("./pragma");
const locFns = require("./loc");
const postprocess = require("./postprocess");
function babelOptions(extraOptions, extraPlugins = []) {
function babelOptions(extraPlugins = []) {
return {
sourceType: "module",
allowAwaitOutsideFunction: true,
@@ -18,7 +18,6 @@ function babelOptions(extraOptions, extraPlugins = []) {
allowUndeclaredExports: true,
errorRecovery: true,
plugins: [
"jsx",
"doExpressions",
"objectRestSpread",
"classProperties",
@@ -41,20 +40,23 @@ function babelOptions(extraOptions, extraPlugins = []) {
"classPrivateMethods",
"v8intrinsic",
"partialApplication",
["decorators", { decoratorsBeforeExport: false }]
].concat(extraPlugins),
...extraOptions
["decorators", { decoratorsBeforeExport: false }],
...extraPlugins
]
};
}
function createParse(parseMethod, extraPlugins) {
function createParse(parseMethod, ...pluginCombinations) {
return (text, parsers, opts) => {
// Inline the require to avoid loading all the JS if we don't use it
const babel = require("@babel/parser");
let ast;
try {
ast = babel[parseMethod](text, babelOptions({}, extraPlugins));
ast = tryCombinations(
options => babel[parseMethod](text, options),
pluginCombinations.map(babelOptions)
);
} catch (error) {
throw createError(
// babel error prints (l:c) with cols that are zero indexed
@@ -73,9 +75,31 @@ function createParse(parseMethod, extraPlugins) {
};
}
const parse = createParse("parse", ["flow"]);
const parseFlow = createParse("parse", [["flow", { all: true, enums: true }]]);
const parseExpression = createParse("parseExpression");
const parse = createParse("parse", ["jsx", "flow"]);
const parseFlow = createParse("parse", [
"jsx",
["flow", { all: true, enums: true }]
]);
const parseTypeScript = createParse(
"parse",
["jsx", "typescript"],
["typescript"]
);
const parseExpression = createParse("parseExpression", ["jsx"]);
function tryCombinations(fn, combinations) {
let error;
for (let i = 0; i < combinations.length; i++) {
try {
return fn(combinations[i]);
} catch (_error) {
if (!error) {
error = _error;
}
}
}
throw error;
}
function parseJson(text, parsers, opts) {
const ast = parseExpression(text, parsers, opts);
@@ -146,6 +170,7 @@ function assertJsonNode(node, parent) {
const babel = { parse, astFormat: "estree", hasPragma, ...locFns };
const babelFlow = { ...babel, parse: parseFlow };
const babelTypeScript = { ...babel, parse: parseTypeScript };
const babelExpression = { ...babel, parse: parseExpression };
// Export as a plugin so we can reuse the same bundle for UMD loading
@@ -153,6 +178,7 @@ module.exports = {
parsers: {
babel,
"babel-flow": babelFlow,
"babel-ts": babelTypeScript,
// aliased to keep backwards compatibility
babylon: babel,
json: {
+16
View File
@@ -32,6 +32,22 @@ function postprocess(ast, options) {
return { ...node.types[0], loc: node.loc, range: node.range };
}
break;
case "TSTypeParameter":
// babel-ts
if (typeof node.name === "string") {
node.name = {
type: "Identifier",
name: node.name,
...composeLoc(node, node.name.length)
};
}
break;
case "SequenceExpression":
// Babel (unlike other parsers) includes spaces and comments in the range. Let's unify this.
if (node.end && node.end > getLast(node.expressions).end) {
node.end = getLast(node.expressions).end;
}
break;
}
});
+57 -34
View File
@@ -167,7 +167,8 @@ function genericPrint(path, options, printPath, args) {
node.type === "TSAbstractClassProperty" ||
node.type === "ClassPrivateProperty" ||
node.type === "MethodDefinition" ||
node.type === "TSAbstractMethodDefinition"
node.type === "TSAbstractMethodDefinition" ||
node.type === "TSDeclareMethod"
) {
// their decorators are handled themselves
} else if (
@@ -1416,14 +1417,18 @@ function printPathNoParens(path, options, print, args) {
path.match(
node => node.type === "ObjectPattern" && !node.decorators,
(node, name, number) =>
shouldHugArguments(node) && name === "params" && number === 0
shouldHugArguments(node) &&
(name === "params" || name === "parameters") &&
number === 0
) ||
path.match(
shouldHugType,
(node, name) => name === "typeAnnotation",
(node, name) => name === "typeAnnotation",
(node, name, number) =>
shouldHugArguments(node) && name === "params" && number === 0
shouldHugArguments(node) &&
(name === "params" || name === "parameters") &&
number === 0
)
) {
return content;
@@ -1458,6 +1463,7 @@ function printPathNoParens(path, options, print, args) {
case "ClassPrivateMethod":
case "MethodDefinition":
case "TSAbstractMethodDefinition":
case "TSDeclareMethod":
if (n.decorators && n.decorators.length !== 0) {
parts.push(printDecorators(path, options, print));
}
@@ -1467,7 +1473,7 @@ function printPathNoParens(path, options, print, args) {
if (n.static) {
parts.push("static ");
}
if (n.type === "TSAbstractMethodDefinition") {
if (n.type === "TSAbstractMethodDefinition" || n.abstract) {
parts.push("abstract ");
}
@@ -2355,7 +2361,7 @@ function printPathNoParens(path, options, print, args) {
if (n.static) {
parts.push("static ");
}
if (n.type === "TSAbstractClassProperty") {
if (n.type === "TSAbstractClassProperty" || n.abstract) {
parts.push("abstract ");
}
if (n.readonly) {
@@ -2394,6 +2400,7 @@ function printPathNoParens(path, options, print, args) {
parts.push(concat(printClass(path, options, print)));
return concat(parts);
case "TSInterfaceHeritage":
case "TSExpressionWithTypeArguments": // Babel AST
parts.push(path.call(print, "expression"));
if (n.typeParameters) {
@@ -3285,7 +3292,7 @@ function printPathNoParens(path, options, print, args) {
return concat([
!n.isTypeOf ? "" : "typeof ",
"import(",
path.call(print, "parameter"),
path.call(print, n.parameter ? "parameter" : "argument"),
")",
!n.qualifier ? "" : concat([".", path.call(print, "qualifier")]),
printTypeParameters(path, options, print, "typeParameters")
@@ -3318,9 +3325,13 @@ function printPathNoParens(path, options, print, args) {
)
);
if (n.returnType) {
if (n.returnType || n.typeAnnotation) {
const isType = n.type === "TSConstructorType";
parts.push(isType ? " => " : ": ", path.call(print, "returnType"));
parts.push(
isType ? " => " : ": ",
path.call(print, "returnType"),
path.call(print, "typeAnnotation")
);
}
return concat(parts);
}
@@ -3380,8 +3391,12 @@ function printPathNoParens(path, options, print, args) {
)
);
if (n.returnType) {
parts.push(": ", path.call(print, "returnType"));
if (n.returnType || n.typeAnnotation) {
parts.push(
": ",
path.call(print, "returnType"),
path.call(print, "typeAnnotation")
);
}
return group(concat(parts));
case "TSNamespaceExportDeclaration":
@@ -4638,7 +4653,9 @@ function printTypeParameters(path, options, print, paramsKey) {
])
),
ifBreak(
options.parser !== "typescript" && shouldPrintComma(options, "all")
options.parser !== "typescript" &&
options.parser !== "babel-ts" &&
shouldPrintComma(options, "all")
? ","
: ""
),
@@ -5892,29 +5909,33 @@ function shouldHugType(node) {
}
function shouldHugArguments(fun) {
if (!fun || fun.rest) {
return false;
}
const params = fun.params || fun.parameters;
if (!params || params.length !== 1) {
return false;
}
const param = params[0];
return (
fun &&
fun.params &&
fun.params.length === 1 &&
!fun.params[0].comments &&
(fun.params[0].type === "ObjectPattern" ||
fun.params[0].type === "ArrayPattern" ||
(fun.params[0].type === "Identifier" &&
fun.params[0].typeAnnotation &&
(fun.params[0].typeAnnotation.type === "TypeAnnotation" ||
fun.params[0].typeAnnotation.type === "TSTypeAnnotation") &&
isObjectType(fun.params[0].typeAnnotation.typeAnnotation)) ||
(fun.params[0].type === "FunctionTypeParam" &&
isObjectType(fun.params[0].typeAnnotation)) ||
(fun.params[0].type === "AssignmentPattern" &&
(fun.params[0].left.type === "ObjectPattern" ||
fun.params[0].left.type === "ArrayPattern") &&
(fun.params[0].right.type === "Identifier" ||
(fun.params[0].right.type === "ObjectExpression" &&
fun.params[0].right.properties.length === 0) ||
(fun.params[0].right.type === "ArrayExpression" &&
fun.params[0].right.elements.length === 0)))) &&
!fun.rest
!param.comments &&
(param.type === "ObjectPattern" ||
param.type === "ArrayPattern" ||
(param.type === "Identifier" &&
param.typeAnnotation &&
(param.typeAnnotation.type === "TypeAnnotation" ||
param.typeAnnotation.type === "TSTypeAnnotation") &&
isObjectType(param.typeAnnotation.typeAnnotation)) ||
(param.type === "FunctionTypeParam" &&
isObjectType(param.typeAnnotation)) ||
(param.type === "AssignmentPattern" &&
(param.left.type === "ObjectPattern" ||
param.left.type === "ArrayPattern") &&
(param.right.type === "Identifier" ||
(param.right.type === "ObjectExpression" &&
param.right.properties.length === 0) ||
(param.right.type === "ArrayExpression" &&
param.right.elements.length === 0))))
);
}
@@ -6118,5 +6139,7 @@ module.exports = {
ownLine: handleComments.handleOwnLineComment,
endOfLine: handleComments.handleEndOfLineComment,
remaining: handleComments.handleRemainingComment
}
},
getGapRegex: handleComments.getGapRegex,
getCommentChildNodes: handleComments.getCommentChildNodes
};
+6 -1
View File
@@ -711,7 +711,12 @@ function isStringPropSafeToCoerceToIdentifier(node, options) {
isStringLiteral(node.key) &&
isIdentifierName(node.key.value) &&
options.parser !== "json" &&
!(options.parser === "typescript" && node.type === "ClassProperty")
// With `--strictPropertyInitialization`, TS treats properties with quoted names differently than unquoted ones.
// See https://github.com/microsoft/TypeScript/pull/20075
!(
(options.parser === "typescript" || options.parser === "babel-ts") &&
node.type === "ClassProperty"
)
);
}
+21 -17
View File
@@ -29,7 +29,7 @@ function getSortedChildNodes(node, options, resultArray) {
const { printer, locStart, locEnd } = options;
if (resultArray) {
if (node && printer.canAttachComment && printer.canAttachComment(node)) {
if (printer.canAttachComment && printer.canAttachComment(node)) {
// This reverse insertion sort almost always takes constant
// time because we almost always (maybe always?) append the
// nodes in order anyway.
@@ -49,20 +49,18 @@ function getSortedChildNodes(node, options, resultArray) {
return node[childNodesCacheKey];
}
let childNodes;
if (printer.getCommentChildNodes) {
childNodes = printer.getCommentChildNodes(node);
} else if (node && typeof node === "object") {
childNodes = Object.keys(node)
.filter(
n =>
n !== "enclosingNode" &&
n !== "precedingNode" &&
n !== "followingNode"
)
.map(n => node[n]);
}
const childNodes =
(printer.getCommentChildNodes &&
printer.getCommentChildNodes(node, options)) ||
(typeof node === "object" &&
Object.keys(node)
.filter(
n =>
n !== "enclosingNode" &&
n !== "precedingNode" &&
n !== "followingNode"
)
.map(n => node[n]));
if (!childNodes) {
return;
@@ -301,7 +299,12 @@ function breakTies(tiesToBreak, text, options) {
if (tieCount === 0) {
return;
}
const { precedingNode, followingNode } = tiesToBreak[0];
const { precedingNode, followingNode, enclosingNode } = tiesToBreak[0];
const gapRegExp =
(options.printer.getGapRegex &&
options.printer.getGapRegex(enclosingNode)) ||
/^[\s(]*$/;
let gapEndPos = options.locStart(followingNode);
@@ -321,7 +324,8 @@ function breakTies(tiesToBreak, text, options) {
assert.strictEqual(comment.followingNode, followingNode);
const gap = text.slice(options.locEnd(comment), gapEndPos);
if (/^[\s(]*$/.test(gap)) {
if (gapRegExp.test(gap)) {
gapEndPos = options.locStart(comment);
} else {
// The gap string contained something other than whitespace or open
+1
View File
@@ -133,6 +133,7 @@ const options = {
},
{ value: "babel", since: "1.16.0", description: "JavaScript" },
{ value: "babel-flow", since: "1.16.0", description: "Flow" },
{ value: "babel-ts", since: "2.0.0", description: "TypeScript" },
{ value: "typescript", since: "1.4.0", description: "TypeScript" },
{ value: "css", since: "1.7.1", description: "CSS" },
{
+2
View File
@@ -137,6 +137,8 @@ function isSourceElement(opts, node) {
switch (opts.parser) {
case "flow":
case "babel":
case "babel-flow":
case "babel-ts":
case "typescript":
return jsSourceElements.includes(node.type);
case "json":
+2 -2
View File
@@ -75,8 +75,8 @@ function getSupportInfo(version, opts) {
.map(language => {
let parsers;
// Prevent breaking changes
if (language.name === "Markdown" || language.name === "TypeScript") {
parsers = [language.name.toLowerCase()];
if (language.name === "Markdown") {
parsers = ["markdown"];
// "babylon" was renamed to "babel" in 1.16.0
} else if (useBabylonParser && language.parsers.includes("babel")) {
parsers = language.parsers.map(parser =>
@@ -87,8 +87,7 @@ class A4 /* a */ extends B {}
(class A9 /* a */ extends B {});
class x {
focus() // do nothing
{
focus() { // do nothing
// do nothing
}
}
+4 -4
View File
@@ -2,7 +2,7 @@
exports[`empty 1`] = `
====================================options=====================================
parsers: ["flow", "babel", "babel-flow", "typescript", "css", "less", "scss", "json", "json5", "json-stringify", "graphql", "markdown", "mdx", "vue", "yaml", "html", "angular", "lwc"]
parsers: ["flow", "babel", "babel-flow", "babel-ts", "typescript", "css", "less", "scss", "json", "json5", "json-stringify", "graphql", "markdown", "mdx", "vue", "yaml", "html", "angular", "lwc"]
printWidth: 80
| printWidth
=====================================input======================================
@@ -14,7 +14,7 @@ printWidth: 80
exports[`newline 1`] = `
====================================options=====================================
parsers: ["flow", "babel", "babel-flow", "typescript", "css", "less", "scss", "json", "json5", "json-stringify", "graphql", "markdown", "mdx", "vue", "yaml", "html", "angular", "lwc"]
parsers: ["flow", "babel", "babel-flow", "babel-ts", "typescript", "css", "less", "scss", "json", "json5", "json-stringify", "graphql", "markdown", "mdx", "vue", "yaml", "html", "angular", "lwc"]
printWidth: 80
| printWidth
=====================================input======================================
@@ -27,7 +27,7 @@ printWidth: 80
exports[`space 1`] = `
====================================options=====================================
parsers: ["flow", "babel", "babel-flow", "typescript", "css", "less", "scss", "json", "json5", "json-stringify", "graphql", "markdown", "mdx", "vue", "yaml", "html", "angular", "lwc"]
parsers: ["flow", "babel", "babel-flow", "babel-ts", "typescript", "css", "less", "scss", "json", "json5", "json-stringify", "graphql", "markdown", "mdx", "vue", "yaml", "html", "angular", "lwc"]
printWidth: 80
| printWidth
=====================================input======================================
@@ -40,7 +40,7 @@ printWidth: 80
exports[`space-newline 1`] = `
====================================options=====================================
parsers: ["flow", "babel", "babel-flow", "typescript", "css", "less", "scss", "json", "json5", "json-stringify", "graphql", "markdown", "mdx", "vue", "yaml", "html", "angular", "lwc"]
parsers: ["flow", "babel", "babel-flow", "babel-ts", "typescript", "css", "less", "scss", "json", "json5", "json-stringify", "graphql", "markdown", "mdx", "vue", "yaml", "html", "angular", "lwc"]
printWidth: 80
| printWidth
=====================================input======================================
+7 -1
View File
@@ -1 +1,7 @@
run_spec(__dirname, ["typescript"]);
run_spec(__dirname, ["typescript"], {
disableBabelTS: [
"downlevelLetConst1.ts",
"errorOnInitializerInInterfaceProperty.ts",
"modifiersOnInterfaceIndexSignature1.ts"
]
});
@@ -1 +1,3 @@
run_spec(__dirname, ["typescript"]);
run_spec(__dirname, ["typescript"], {
disableBabelTS: ["classAbstractMixedWithModifiers.ts"]
});
@@ -1 +1,3 @@
run_spec(__dirname, ["typescript"]);
run_spec(__dirname, ["typescript"], {
disableBabelTS: ["readonlyInConstructorParameters.ts", "readonlyReadonly.ts"]
});
@@ -1 +1 @@
run_spec(__dirname, ["typescript"]);
run_spec(__dirname, ["typescript"], { disableBabelTS: true });
@@ -1 +1 @@
run_spec(__dirname, ["typescript"]);
run_spec(__dirname, ["typescript"], { disableBabelTS: true });
@@ -1 +1 @@
run_spec(__dirname, ["typescript"]);
run_spec(__dirname, ["typescript"], { disableBabelTS: true });
@@ -1 +1,3 @@
run_spec(__dirname, ["typescript"]);
run_spec(__dirname, ["typescript"], {
disableBabelTS: ["functionOverloadErrorsSyntax.ts"]
});
@@ -1 +1 @@
run_spec(__dirname, ["typescript"]);
run_spec(__dirname, ["typescript"], { disableBabelTS: true });
+3 -1
View File
@@ -1 +1,3 @@
run_spec(__dirname, ["typescript"]);
run_spec(__dirname, ["typescript"], {
disableBabelTS: ["constructor.ts", "generics.ts", "methods.ts"]
});
+1 -1
View File
@@ -1 +1 @@
run_spec(__dirname, ["typescript"]);
run_spec(__dirname, ["typescript"], { disableBabelTS: ["interface.ts"] });
+11 -3
View File
@@ -1,3 +1,11 @@
run_spec(__dirname, ["typescript"]);
run_spec(__dirname, ["typescript"], { trailingComma: "es5" });
run_spec(__dirname, ["typescript"], { trailingComma: "all" });
run_spec(__dirname, ["typescript"], {
disableBabelTS: ["jsdoc_only_types.ts", "index-signature.ts"]
});
run_spec(__dirname, ["typescript"], {
trailingComma: "es5",
disableBabelTS: ["jsdoc_only_types.ts", "index-signature.ts"]
});
run_spec(__dirname, ["typescript"], {
trailingComma: "all",
disableBabelTS: ["jsdoc_only_types.ts", "index-signature.ts"]
});
@@ -1,5 +1,26 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`single-parameter.ts 1`] = `
====================================options=====================================
parsers: ["typescript"]
printWidth: 80
| printWidth
=====================================input======================================
type X = (options:{ a: string; b: AbstractCompositeThingamabobberFactoryProvider}) => {};
type Y = new (options:{ a: string; b: AbstractCompositeThingamabobberFactoryProvider}) => {};
=====================================output=====================================
type X = (options: {
a: string;
b: AbstractCompositeThingamabobberFactoryProvider;
}) => {};
type Y = new (options: {
a: string;
b: AbstractCompositeThingamabobberFactoryProvider;
}) => {};
================================================================================
`;
exports[`type-annotation.ts 1`] = `
====================================options=====================================
parsers: ["typescript"]
@@ -0,0 +1,2 @@
type X = (options:{ a: string; b: AbstractCompositeThingamabobberFactoryProvider}) => {};
type Y = new (options:{ a: string; b: AbstractCompositeThingamabobberFactoryProvider}) => {};
+5 -2
View File
@@ -1,2 +1,5 @@
run_spec(__dirname, ["typescript"]);
run_spec(__dirname, ["typescript"], { semi: false });
run_spec(__dirname, ["typescript"], { disableBabelTS: ["abstract.ts"] });
run_spec(__dirname, ["typescript"], {
semi: false,
disableBabelTS: ["abstract.ts"]
});
+1 -1
View File
@@ -1 +1 @@
run_spec(__dirname, ["typescript"]);
run_spec(__dirname, ["typescript"], { disableBabelTS: true });
+20 -2
View File
@@ -90,7 +90,21 @@ global.run_spec = (dirname, parsers, options) => {
).toMatchSnapshot();
});
for (const parser of parsers.slice(1)) {
const parsersToVerify = parsers.slice(1);
if (
parsers.includes("typescript") &&
!parsers.includes("babel-ts") &&
!(
options &&
(options.disableBabelTS === true ||
(Array.isArray(options.disableBabelTS) &&
options.disableBabelTS.includes(basename)))
)
) {
parsersToVerify.push("babel-ts");
}
for (const parser of parsersToVerify) {
const verifyOptions = { ...baseOptions, parser };
test(`${basename} - ${parser}-verify`, () => {
const verifyOutput = format(input, filename, verifyOptions);
@@ -172,7 +186,11 @@ function createSnapshot(input, output, options) {
printOptions(
omit(
options,
k => k === "rangeStart" || k === "rangeEnd" || k === "cursorOffset"
k =>
k === "rangeStart" ||
k === "rangeEnd" ||
k === "cursorOffset" ||
k === "disableBabelTS"
)
),
printWidthIndicator,
@@ -72,7 +72,7 @@ Format options:
Defaults to false.
--jsx-single-quote Use single quotes in JSX.
Defaults to false.
--parser <flow|babel|babel-flow|typescript|css|less|scss|json|json5|json-stringify|graphql|markdown|mdx|vue|yaml|html|angular|lwc>
--parser <flow|babel|babel-flow|babel-ts|typescript|css|less|scss|json|json5|json-stringify|graphql|markdown|mdx|vue|yaml|html|angular|lwc>
Which parser to use.
--print-width <int> The line length where Prettier will try wrap.
Defaults to 80.
@@ -168,7 +168,7 @@ exports[`show warning with --help not-found (typo) (stderr) 1`] = `
`;
exports[`show warning with --help not-found (typo) (stdout) 1`] = `
"--parser <flow|babel|babel-flow|typescript|css|less|scss|json|json5|json-stringify|graphql|markdown|mdx|vue|yaml|html|angular|lwc>
"--parser <flow|babel|babel-flow|babel-ts|typescript|css|less|scss|json|json5|json-stringify|graphql|markdown|mdx|vue|yaml|html|angular|lwc>
Which parser to use.
@@ -177,6 +177,7 @@ Valid options:
flow Flow
babel JavaScript
babel-flow Flow
babel-ts TypeScript
typescript TypeScript
css CSS
less Less
@@ -228,7 +229,7 @@ Format options:
Defaults to false.
--jsx-single-quote Use single quotes in JSX.
Defaults to false.
--parser <flow|babel|babel-flow|typescript|css|less|scss|json|json5|json-stringify|graphql|markdown|mdx|vue|yaml|html|angular|lwc>
--parser <flow|babel|babel-flow|babel-ts|typescript|css|less|scss|json|json5|json-stringify|graphql|markdown|mdx|vue|yaml|html|angular|lwc>
Which parser to use.
--print-width <int> The line length where Prettier will try wrap.
Defaults to 80.
@@ -332,7 +332,7 @@ exports[`show detailed usage with --help no-semi (write) 1`] = `Array []`;
exports[`show detailed usage with --help parser (stderr) 1`] = `""`;
exports[`show detailed usage with --help parser (stdout) 1`] = `
"--parser <flow|babel|babel-flow|typescript|css|less|scss|json|json5|json-stringify|graphql|markdown|mdx|vue|yaml|html|angular|lwc>
"--parser <flow|babel|babel-flow|babel-ts|typescript|css|less|scss|json|json5|json-stringify|graphql|markdown|mdx|vue|yaml|html|angular|lwc>
Which parser to use.
@@ -341,6 +341,7 @@ Valid options:
flow Flow
babel JavaScript
babel-flow Flow
babel-ts TypeScript
typescript TypeScript
css CSS
less Less
@@ -132,6 +132,12 @@ This option cannot be used with --range-start and --range-end.",
"babel-flow",
],
},
Object {
"description": "TypeScript",
"enum": Array [
"babel-ts",
],
},
Object {
"description": "TypeScript",
"enum": Array [
@@ -141,7 +141,7 @@ exports[`API getSupportInfo() with version 1.0.0 -> 1.4.0 1`] = `
\\"flow\\",
],
\\"JSX\\": Array [
@@ -9,31 +12,79 @@
@@ -9,31 +12,81 @@
\\"flow\\",
],
\\"JavaScript\\": Array [
@@ -156,26 +156,28 @@ exports[`API getSupportInfo() with version 1.0.0 -> 1.4.0 1`] = `
+ ],
+ \\"SCSS\\": Array [
+ \\"postcss\\",
],
+ ],
+ \\"TSX\\": Array [
+ \\"typescript\\",
+ \\"babel-ts\\",
+ ],
+ \\"TypeScript\\": Array [
+ \\"typescript\\",
+ ],
+ \\"babel-ts\\",
],
},
\\"options\\": Object {
\\"bracketSpacing\\": Object {
\\"default\\": true,
\\"type\\": \\"boolean\\",
+ },
},
+ \\"cursorOffset\\": Object {
+ \\"default\\": -1,
+ \\"range\\": Object {
+ \\"end\\": Infinity,
+ \\"start\\": -1,
+ \\"step\\": 1,
},
+ },
+ \\"type\\": \\"int\\",
+ },
+ \\"filepath\\": Object {
@@ -248,7 +250,7 @@ exports[`API getSupportInfo() with version 1.4.0 -> 1.5.0 1`] = `
\\"flow\\",
],
\\"JavaScript\\": Array [
@@ -57,10 +66,12 @@
@@ -59,10 +68,12 @@
\\"choices\\": Array [
\\"flow\\",
\\"babylon\\",
@@ -298,9 +300,9 @@ exports[`API getSupportInfo() with version 1.5.0 -> 1.7.1 1`] = `
],
\\"TSX\\": Array [
\\"typescript\\",
\\"babel-ts\\",
],
\\"TypeScript\\": Array [
@@ -65,11 +65,13 @@
@@ -67,11 +67,13 @@
\\"parser\\": Object {
\\"choices\\": Array [
\\"flow\\",
@@ -315,7 +317,7 @@ exports[`API getSupportInfo() with version 1.5.0 -> 1.7.1 1`] = `
],
\\"default\\": \\"babylon\\",
\\"type\\": \\"choice\\",
@@ -98,10 +100,14 @@
@@ -100,10 +102,14 @@
\\"end\\": Infinity,
\\"start\\": 0,
\\"step\\": 1,
@@ -351,7 +353,7 @@ exports[`API getSupportInfo() with version 1.7.1 -> 1.8.0 1`] = `
],
\\"SCSS\\": Array [
\\"scss\\",
@@ -55,10 +58,14 @@
@@ -57,10 +60,14 @@
\\"type\\": \\"int\\",
},
\\"filepath\\": Object {
@@ -366,7 +368,7 @@ exports[`API getSupportInfo() with version 1.7.1 -> 1.8.0 1`] = `
\\"default\\": false,
\\"type\\": \\"boolean\\",
},
@@ -70,10 +77,11 @@
@@ -72,10 +79,11 @@
\\"css\\",
\\"less\\",
\\"scss\\",
@@ -385,7 +387,7 @@ exports[`API getSupportInfo() with version 1.8.0 -> 1.8.2 1`] = `
- First value
+ Second value
@@ -91,10 +91,18 @@
@@ -93,10 +93,18 @@
\\"start\\": 0,
\\"step\\": 1,
},
@@ -463,12 +465,12 @@ exports[`API getSupportInfo() with version 1.8.2 -> 1.16.0 1`] = `
\\"markdown\\",
],
\\"PostCSS\\": Array [
@@ -39,13 +54,27 @@
\\"TSX\\": Array [
\\"typescript\\",
@@ -41,13 +56,27 @@
\\"babel-ts\\",
],
\\"TypeScript\\": Array [
\\"typescript\\",
\\"babel-ts\\",
+ ],
+ \\"Vue\\": Array [
+ \\"vue\\",
@@ -491,7 +493,7 @@ exports[`API getSupportInfo() with version 1.8.2 -> 1.16.0 1`] = `
\\"type\\": \\"boolean\\",
},
\\"cursorOffset\\": Object {
@@ -55,36 +84,75 @@
@@ -57,36 +86,75 @@
\\"start\\": -1,
\\"step\\": 1,
},
@@ -569,7 +571,7 @@ exports[`API getSupportInfo() with version 1.8.2 -> 1.16.0 1`] = `
\\"default\\": 80,
\\"range\\": Object {
\\"end\\": Infinity,
@@ -93,14 +161,15 @@
@@ -95,14 +163,15 @@
},
\\"type\\": \\"int\\",
},
@@ -609,7 +611,7 @@ exports[`API getSupportInfo() with version 1.16.0 -> undefined 1`] = `
],
\\"Markdown\\": Array [
\\"markdown\\",
@@ -68,11 +71,11 @@
@@ -70,11 +73,11 @@
\\"arrowParens\\": Object {
\\"choices\\": Array [
\\"always\\",
@@ -622,7 +624,7 @@ exports[`API getSupportInfo() with version 1.16.0 -> undefined 1`] = `
\\"bracketSpacing\\": Object {
\\"default\\": true,
\\"type\\": \\"boolean\\",
@@ -91,11 +94,11 @@
@@ -93,11 +96,11 @@
\\"lf\\",
\\"crlf\\",
\\"cr\\",
@@ -635,7 +637,19 @@ exports[`API getSupportInfo() with version 1.16.0 -> undefined 1`] = `
\\"filepath\\": Object {
\\"default\\": undefined,
\\"type\\": \\"path\\",
@@ -138,10 +141,11 @@
@@ -126,10 +129,11 @@
\\"parser\\": Object {
\\"choices\\": Array [
\\"flow\\",
\\"babel\\",
\\"babel-flow\\",
+ \\"babel-ts\\",
\\"typescript\\",
\\"css\\",
\\"less\\",
\\"scss\\",
\\"json\\",
@@ -140,10 +144,11 @@
\\"mdx\\",
\\"vue\\",
\\"yaml\\",
@@ -647,12 +661,14 @@ exports[`API getSupportInfo() with version 1.16.0 -> undefined 1`] = `
\\"type\\": \\"choice\\",
},
\\"pluginSearchDirs\\": Object {
@@ -168,10 +172,19 @@
@@ -168,10 +173,19 @@
\\"always\\",
\\"never\\",
\\"preserve\\",
],
\\"default\\": \\"preserve\\",
\\"type\\": \\"choice\\",
},
+ \\"type\\": \\"choice\\",
+ },
+ \\"quoteProps\\": Object {
+ \\"choices\\": Array [
+ \\"as-needed\\",
@@ -660,14 +676,12 @@ exports[`API getSupportInfo() with version 1.16.0 -> undefined 1`] = `
+ \\"preserve\\",
+ ],
+ \\"default\\": \\"as-needed\\",
+ \\"type\\": \\"choice\\",
+ },
\\"type\\": \\"choice\\",
},
\\"rangeEnd\\": Object {
\\"default\\": Infinity,
\\"range\\": Object {
\\"end\\": Infinity,
\\"start\\": 0,
@@ -213,14 +226,18 @@
@@ -215,14 +229,18 @@
\\"choices\\": Array [
\\"es5\\",
\\"none\\",
@@ -783,7 +797,7 @@ exports[`CLI --support-info (stdout) 1`] = `
\\"interpreters\\": [\\"deno\\", \\"ts-node\\"],
\\"linguistLanguageId\\": 378,
\\"name\\": \\"TypeScript\\",
\\"parsers\\": [\\"typescript\\"],
\\"parsers\\": [\\"typescript\\", \\"babel-ts\\"],
\\"since\\": \\"1.4.0\\",
\\"tmScope\\": \\"source.ts\\",
\\"type\\": \\"programming\\",
@@ -797,7 +811,7 @@ exports[`CLI --support-info (stdout) 1`] = `
\\"group\\": \\"TypeScript\\",
\\"linguistLanguageId\\": 94901924,
\\"name\\": \\"TSX\\",
\\"parsers\\": [\\"typescript\\"],
\\"parsers\\": [\\"typescript\\", \\"babel-ts\\"],
\\"since\\": \\"1.4.0\\",
\\"tmScope\\": \\"source.tsx\\",
\\"type\\": \\"programming\\",
@@ -1245,6 +1259,7 @@ exports[`CLI --support-info (stdout) 1`] = `
{ \\"description\\": \\"Flow\\", \\"value\\": \\"flow\\" },
{ \\"description\\": \\"JavaScript\\", \\"since\\": \\"1.16.0\\", \\"value\\": \\"babel\\" },
{ \\"description\\": \\"Flow\\", \\"since\\": \\"1.16.0\\", \\"value\\": \\"babel-flow\\" },
{ \\"description\\": \\"TypeScript\\", \\"since\\": \\"2.0.0\\", \\"value\\": \\"babel-ts\\" },
{
\\"description\\": \\"TypeScript\\",
\\"since\\": \\"1.4.0\\",
+1
View File
@@ -38,6 +38,7 @@ export default function(parser) {
'declare type FetchPolicy = "cache-first" | "cache-and-network" | "network-only" | "cache-only"'
].join("\n");
case "typescript":
case "babel-ts":
return [
"interface MyInterface {",
" foo(): string,",
+1
View File
@@ -40,6 +40,7 @@ function getMarkdownSyntax(options) {
case "babel-flow":
case "flow":
return "jsx";
case "babel-ts":
case "typescript":
return "tsx";
case "json":
+4
View File
@@ -21,6 +21,10 @@ var parsers = {
importScriptOnce("lib/parser-babylon.js");
return prettierPlugins.babylon.parsers["babel-flow"];
},
get "babel-ts"() {
importScriptOnce("lib/parser-babylon.js");
return prettierPlugins.babylon.parsers["babel-ts"];
},
// backward compatibility
get babylon() {
importScriptOnce("lib/parser-babylon.js");