From c1937cb1b8717d8fe2247de99e7031bd7fd7bab3 Mon Sep 17 00:00:00 2001 From: JounQin Date: Wed, 29 Jan 2020 20:11:16 +0800 Subject: [PATCH] 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 --- changelog_unreleased/typescript/pr-6400.md | 3 + docs/options.md | 5 +- src/common/internal-plugins.js | 5 + src/language-js/clean.js | 1 + src/language-js/comments.js | 56 ++++++++++-- src/language-js/embed.js | 4 +- src/language-js/index.js | 4 +- src/language-js/loc.js | 29 +++--- src/language-js/parser-babylon.js | 46 ++++++++-- src/language-js/postprocess.js | 16 ++++ src/language-js/printer-estree.js | 91 ++++++++++++------- src/language-js/utils.js | 7 +- src/main/comments.js | 38 ++++---- src/main/core-options.js | 1 + src/main/range-util.js | 2 + src/main/support.js | 4 +- .../__snapshots__/jsfmt.spec.js.snap | 3 +- tests/empty/__snapshots__/jsfmt.spec.js.snap | 8 +- tests/typescript/compiler/jsfmt.spec.js | 8 +- .../classAbstractKeyword/jsfmt.spec.js | 4 +- .../constructorParameters/jsfmt.spec.js | 4 +- .../ecmascript5/Statements/jsfmt.spec.js | 2 +- .../types/abstractKeyword/jsfmt.spec.js | 2 +- .../conformance/types/decorator/jsfmt.spec.js | 2 +- .../conformance/types/functions/jsfmt.spec.js | 4 +- .../typescript/custom/abstract/jsfmt.spec.js | 2 +- tests/typescript_class/jsfmt.spec.js | 4 +- tests/typescript_decorators/jsfmt.spec.js | 2 +- tests/typescript_error_recovery/jsfmt.spec.js | 14 ++- .../__snapshots__/jsfmt.spec.js.snap | 21 +++++ .../single-parameter.ts | 2 + tests/typescript_interface/jsfmt.spec.js | 7 +- tests/typescript_keywords/jsfmt.spec.js | 2 +- tests_config/run_spec.js | 22 ++++- .../__snapshots__/early-exit.js.snap | 7 +- .../__snapshots__/help-options.js.snap | 3 +- .../__tests__/__snapshots__/schema.js.snap | 6 ++ .../__snapshots__/support-info.js.snap | 75 +++++++++------ website/playground/codeSamples.js | 1 + website/playground/markdown.js | 1 + website/static/worker.js | 4 + 41 files changed, 375 insertions(+), 147 deletions(-) create mode 100644 changelog_unreleased/typescript/pr-6400.md create mode 100644 tests/typescript_function_type/single-parameter.ts diff --git a/changelog_unreleased/typescript/pr-6400.md b/changelog_unreleased/typescript/pr-6400.md new file mode 100644 index 000000000..76210e694 --- /dev/null +++ b/changelog_unreleased/typescript/pr-6400.md @@ -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. diff --git a/docs/options.md b/docs/options.md index 1f81cfb65..521f2cf18 100644 --- a/docs/options.md +++ b/docs/options.md @@ -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_ diff --git a/src/common/internal-plugins.js b/src/common/internal-plugins.js index 188c3833b..85bd20a20 100644 --- a/src/common/internal-plugins.js +++ b/src/common/internal-plugins.js @@ -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; }, diff --git a/src/language-js/clean.js b/src/language-js/clean.js index 2801323f8..147d5f197 100644 --- a/src/language-js/clean.js +++ b/src/language-js/clean.js @@ -7,6 +7,7 @@ function clean(ast, newObj, parent) { "comments", "leadingComments", "trailingComments", + "innerComments", "extra", "start", "end", diff --git a/src/language-js/comments.js b/src/language-js/comments.js index c14c45f39..2b63db2dd 100644 --- a/src/language-js/comments.js +++ b/src/language-js/comments.js @@ -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 }; diff --git a/src/language-js/embed.js b/src/language-js/embed.js index 5e3d553bd..286006075 100644 --- a/src/language-js/embed.js +++ b/src/language-js/embed.js @@ -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", diff --git a/src/language-js/index.js b/src/language-js/index.js index db1aa0710..7286afa22 100644 --- a/src/language-js/index.js +++ b/src/language-js/index.js @@ -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 => ({ diff --git a/src/language-js/loc.js b/src/language-js/loc.js index 214de144c..98df29f90 100644 --- a/src/language-js/loc.js +++ b/src/language-js/loc.js @@ -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 = { diff --git a/src/language-js/parser-babylon.js b/src/language-js/parser-babylon.js index d866a0bd3..e52801fb3 100644 --- a/src/language-js/parser-babylon.js +++ b/src/language-js/parser-babylon.js @@ -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: { diff --git a/src/language-js/postprocess.js b/src/language-js/postprocess.js index 0456bf4ca..fe82fba30 100644 --- a/src/language-js/postprocess.js +++ b/src/language-js/postprocess.js @@ -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; } }); diff --git a/src/language-js/printer-estree.js b/src/language-js/printer-estree.js index 88b10a31e..39f6de7dd 100644 --- a/src/language-js/printer-estree.js +++ b/src/language-js/printer-estree.js @@ -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 }; diff --git a/src/language-js/utils.js b/src/language-js/utils.js index f1e797ff4..6ded49ca5 100644 --- a/src/language-js/utils.js +++ b/src/language-js/utils.js @@ -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" + ) ); } diff --git a/src/main/comments.js b/src/main/comments.js index 63ab1fc5e..60fbe5a8d 100644 --- a/src/main/comments.js +++ b/src/main/comments.js @@ -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 diff --git a/src/main/core-options.js b/src/main/core-options.js index 426f7502d..885a5e925 100644 --- a/src/main/core-options.js +++ b/src/main/core-options.js @@ -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" }, { diff --git a/src/main/range-util.js b/src/main/range-util.js index 06138b8a2..5fccdf18c 100644 --- a/src/main/range-util.js +++ b/src/main/range-util.js @@ -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": diff --git a/src/main/support.js b/src/main/support.js index 71d86fd11..2f45a4464 100644 --- a/src/main/support.js +++ b/src/main/support.js @@ -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 => diff --git a/tests/class_comment/__snapshots__/jsfmt.spec.js.snap b/tests/class_comment/__snapshots__/jsfmt.spec.js.snap index ae3ee690d..6a23750c8 100644 --- a/tests/class_comment/__snapshots__/jsfmt.spec.js.snap +++ b/tests/class_comment/__snapshots__/jsfmt.spec.js.snap @@ -87,8 +87,7 @@ class A4 /* a */ extends B {} (class A9 /* a */ extends B {}); class x { - focus() // do nothing - { + focus() { // do nothing // do nothing } } diff --git a/tests/empty/__snapshots__/jsfmt.spec.js.snap b/tests/empty/__snapshots__/jsfmt.spec.js.snap index fc67ad249..3e9d8b988 100644 --- a/tests/empty/__snapshots__/jsfmt.spec.js.snap +++ b/tests/empty/__snapshots__/jsfmt.spec.js.snap @@ -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====================================== diff --git a/tests/typescript/compiler/jsfmt.spec.js b/tests/typescript/compiler/jsfmt.spec.js index 2ea3bb6eb..e018c7184 100644 --- a/tests/typescript/compiler/jsfmt.spec.js +++ b/tests/typescript/compiler/jsfmt.spec.js @@ -1 +1,7 @@ -run_spec(__dirname, ["typescript"]); +run_spec(__dirname, ["typescript"], { + disableBabelTS: [ + "downlevelLetConst1.ts", + "errorOnInitializerInInterfaceProperty.ts", + "modifiersOnInterfaceIndexSignature1.ts" + ] +}); diff --git a/tests/typescript/conformance/classes/classDeclarations/classAbstractKeyword/jsfmt.spec.js b/tests/typescript/conformance/classes/classDeclarations/classAbstractKeyword/jsfmt.spec.js index 2ea3bb6eb..900677c6a 100644 --- a/tests/typescript/conformance/classes/classDeclarations/classAbstractKeyword/jsfmt.spec.js +++ b/tests/typescript/conformance/classes/classDeclarations/classAbstractKeyword/jsfmt.spec.js @@ -1 +1,3 @@ -run_spec(__dirname, ["typescript"]); +run_spec(__dirname, ["typescript"], { + disableBabelTS: ["classAbstractMixedWithModifiers.ts"] +}); diff --git a/tests/typescript/conformance/classes/constructorDeclarations/constructorParameters/jsfmt.spec.js b/tests/typescript/conformance/classes/constructorDeclarations/constructorParameters/jsfmt.spec.js index 2ea3bb6eb..b8a739b47 100644 --- a/tests/typescript/conformance/classes/constructorDeclarations/constructorParameters/jsfmt.spec.js +++ b/tests/typescript/conformance/classes/constructorDeclarations/constructorParameters/jsfmt.spec.js @@ -1 +1,3 @@ -run_spec(__dirname, ["typescript"]); +run_spec(__dirname, ["typescript"], { + disableBabelTS: ["readonlyInConstructorParameters.ts", "readonlyReadonly.ts"] +}); diff --git a/tests/typescript/conformance/parser/ecmascript5/Statements/jsfmt.spec.js b/tests/typescript/conformance/parser/ecmascript5/Statements/jsfmt.spec.js index 2ea3bb6eb..58101833a 100644 --- a/tests/typescript/conformance/parser/ecmascript5/Statements/jsfmt.spec.js +++ b/tests/typescript/conformance/parser/ecmascript5/Statements/jsfmt.spec.js @@ -1 +1 @@ -run_spec(__dirname, ["typescript"]); +run_spec(__dirname, ["typescript"], { disableBabelTS: true }); diff --git a/tests/typescript/conformance/types/abstractKeyword/jsfmt.spec.js b/tests/typescript/conformance/types/abstractKeyword/jsfmt.spec.js index 2ea3bb6eb..58101833a 100644 --- a/tests/typescript/conformance/types/abstractKeyword/jsfmt.spec.js +++ b/tests/typescript/conformance/types/abstractKeyword/jsfmt.spec.js @@ -1 +1 @@ -run_spec(__dirname, ["typescript"]); +run_spec(__dirname, ["typescript"], { disableBabelTS: true }); diff --git a/tests/typescript/conformance/types/decorator/jsfmt.spec.js b/tests/typescript/conformance/types/decorator/jsfmt.spec.js index 2ea3bb6eb..58101833a 100644 --- a/tests/typescript/conformance/types/decorator/jsfmt.spec.js +++ b/tests/typescript/conformance/types/decorator/jsfmt.spec.js @@ -1 +1 @@ -run_spec(__dirname, ["typescript"]); +run_spec(__dirname, ["typescript"], { disableBabelTS: true }); diff --git a/tests/typescript/conformance/types/functions/jsfmt.spec.js b/tests/typescript/conformance/types/functions/jsfmt.spec.js index 2ea3bb6eb..c5547c764 100644 --- a/tests/typescript/conformance/types/functions/jsfmt.spec.js +++ b/tests/typescript/conformance/types/functions/jsfmt.spec.js @@ -1 +1,3 @@ -run_spec(__dirname, ["typescript"]); +run_spec(__dirname, ["typescript"], { + disableBabelTS: ["functionOverloadErrorsSyntax.ts"] +}); diff --git a/tests/typescript/custom/abstract/jsfmt.spec.js b/tests/typescript/custom/abstract/jsfmt.spec.js index 2ea3bb6eb..58101833a 100644 --- a/tests/typescript/custom/abstract/jsfmt.spec.js +++ b/tests/typescript/custom/abstract/jsfmt.spec.js @@ -1 +1 @@ -run_spec(__dirname, ["typescript"]); +run_spec(__dirname, ["typescript"], { disableBabelTS: true }); diff --git a/tests/typescript_class/jsfmt.spec.js b/tests/typescript_class/jsfmt.spec.js index 2ea3bb6eb..ca20c03e0 100644 --- a/tests/typescript_class/jsfmt.spec.js +++ b/tests/typescript_class/jsfmt.spec.js @@ -1 +1,3 @@ -run_spec(__dirname, ["typescript"]); +run_spec(__dirname, ["typescript"], { + disableBabelTS: ["constructor.ts", "generics.ts", "methods.ts"] +}); diff --git a/tests/typescript_decorators/jsfmt.spec.js b/tests/typescript_decorators/jsfmt.spec.js index 2ea3bb6eb..7822a8e17 100644 --- a/tests/typescript_decorators/jsfmt.spec.js +++ b/tests/typescript_decorators/jsfmt.spec.js @@ -1 +1 @@ -run_spec(__dirname, ["typescript"]); +run_spec(__dirname, ["typescript"], { disableBabelTS: ["interface.ts"] }); diff --git a/tests/typescript_error_recovery/jsfmt.spec.js b/tests/typescript_error_recovery/jsfmt.spec.js index 9ae5dd616..e097bb78e 100644 --- a/tests/typescript_error_recovery/jsfmt.spec.js +++ b/tests/typescript_error_recovery/jsfmt.spec.js @@ -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"] +}); diff --git a/tests/typescript_function_type/__snapshots__/jsfmt.spec.js.snap b/tests/typescript_function_type/__snapshots__/jsfmt.spec.js.snap index f03a65c29..7f0bb8671 100644 --- a/tests/typescript_function_type/__snapshots__/jsfmt.spec.js.snap +++ b/tests/typescript_function_type/__snapshots__/jsfmt.spec.js.snap @@ -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"] diff --git a/tests/typescript_function_type/single-parameter.ts b/tests/typescript_function_type/single-parameter.ts new file mode 100644 index 000000000..07342bd78 --- /dev/null +++ b/tests/typescript_function_type/single-parameter.ts @@ -0,0 +1,2 @@ +type X = (options:{ a: string; b: AbstractCompositeThingamabobberFactoryProvider}) => {}; +type Y = new (options:{ a: string; b: AbstractCompositeThingamabobberFactoryProvider}) => {}; \ No newline at end of file diff --git a/tests/typescript_interface/jsfmt.spec.js b/tests/typescript_interface/jsfmt.spec.js index ba52aeb62..1336a726c 100644 --- a/tests/typescript_interface/jsfmt.spec.js +++ b/tests/typescript_interface/jsfmt.spec.js @@ -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"] +}); diff --git a/tests/typescript_keywords/jsfmt.spec.js b/tests/typescript_keywords/jsfmt.spec.js index 2ea3bb6eb..58101833a 100644 --- a/tests/typescript_keywords/jsfmt.spec.js +++ b/tests/typescript_keywords/jsfmt.spec.js @@ -1 +1 @@ -run_spec(__dirname, ["typescript"]); +run_spec(__dirname, ["typescript"], { disableBabelTS: true }); diff --git a/tests_config/run_spec.js b/tests_config/run_spec.js index 56d40e4db..4f88832cc 100644 --- a/tests_config/run_spec.js +++ b/tests_config/run_spec.js @@ -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, diff --git a/tests_integration/__tests__/__snapshots__/early-exit.js.snap b/tests_integration/__tests__/__snapshots__/early-exit.js.snap index b34e4a7df..ddc5ef0d2 100644 --- a/tests_integration/__tests__/__snapshots__/early-exit.js.snap +++ b/tests_integration/__tests__/__snapshots__/early-exit.js.snap @@ -72,7 +72,7 @@ Format options: Defaults to false. --jsx-single-quote Use single quotes in JSX. Defaults to false. - --parser + --parser Which parser to use. --print-width 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 +"--parser 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 + --parser Which parser to use. --print-width The line length where Prettier will try wrap. Defaults to 80. diff --git a/tests_integration/__tests__/__snapshots__/help-options.js.snap b/tests_integration/__tests__/__snapshots__/help-options.js.snap index 0efcbedaf..27c849c32 100644 --- a/tests_integration/__tests__/__snapshots__/help-options.js.snap +++ b/tests_integration/__tests__/__snapshots__/help-options.js.snap @@ -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 +"--parser 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 diff --git a/tests_integration/__tests__/__snapshots__/schema.js.snap b/tests_integration/__tests__/__snapshots__/schema.js.snap index 06ee0a419..bd6f7cb44 100644 --- a/tests_integration/__tests__/__snapshots__/schema.js.snap +++ b/tests_integration/__tests__/__snapshots__/schema.js.snap @@ -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 [ diff --git a/tests_integration/__tests__/__snapshots__/support-info.js.snap b/tests_integration/__tests__/__snapshots__/support-info.js.snap index a86d19913..a3bbc7a91 100644 --- a/tests_integration/__tests__/__snapshots__/support-info.js.snap +++ b/tests_integration/__tests__/__snapshots__/support-info.js.snap @@ -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\\", diff --git a/website/playground/codeSamples.js b/website/playground/codeSamples.js index 783573bcb..dc1cd9521 100644 --- a/website/playground/codeSamples.js +++ b/website/playground/codeSamples.js @@ -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,", diff --git a/website/playground/markdown.js b/website/playground/markdown.js index e894eef29..ab367d71f 100644 --- a/website/playground/markdown.js +++ b/website/playground/markdown.js @@ -40,6 +40,7 @@ function getMarkdownSyntax(options) { case "babel-flow": case "flow": return "jsx"; + case "babel-ts": case "typescript": return "tsx"; case "json": diff --git a/website/static/worker.js b/website/static/worker.js index b8c4c28a2..d33f636c6 100644 --- a/website/static/worker.js +++ b/website/static/worker.js @@ -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");