From 2cfd8fb5180d35eddbe5aa8319f587e21abf8139 Mon Sep 17 00:00:00 2001 From: Zhongliang Wang Date: Tue, 29 Oct 2019 00:53:57 +0800 Subject: [PATCH] =?UTF-8?q?Support=20TypeScript=203.7=20(and=20drop=20Node?= =?UTF-8?q?=206=20support=20for=20direct=20inst=E2=80=A6=20(#6657)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * WIP: Support TypeScript 3.7 * Add support for `asserts` keyword; Update snapshots * Update typescript-estree to v2.5.0 to remove the dependency on chokidar * Update TypeScript * Update CHANGELOG.unreleased.md * Add examples for TypeScript 3.7 * Update TypeScript 3.7 to latest dev version * Correct wording * Support `declare` keyword on class members (TypeScript 3.7 feature) * Update Changelog and downgrade TypeScript from 3.8.0-dev to 3.7.1-rc * Add a note regarding to dropping Node 6 support for direct installation * tweak build config to repair build * update CHANGELOG.unreleased.md * TSTypePredicate microrefactoring * fix formatting * clean up tests * fix parens for optional chaining inside computed properties * update CHANGELOG.unreleased.md * unify output across parsers for template literals * enable more tests with optional chaining * fix unneeded parens inside computed key of OptionalMemberExpression * fix paren issues for OptionalCallExpression * more fixes for OptionalCallExpression * @typescript-eslint/typescript-estree 2.5.1-alpha.4 * fix lint * revert build hacks * fix one more parens issue * @typescript-eslint/typescript-estree 2.5.1-alpha.5, remove loggerFn override * drop node 6 for direct installing from github * fix another parens issue, disable some tests for flow * workaround for flow bug * fix issues with comments Co-authored-by: Georgii Dolzhykov --- CHANGELOG.unreleased.md | 104 ++++++++++++++++ package.json | 6 +- src/common/util.js | 2 + src/language-js/comments.js | 4 +- src/language-js/needs-parens.js | 115 ++++++++++-------- src/language-js/parser-typescript.js | 5 +- src/language-js/printer-estree.js | 35 ++++-- src/language-js/utils.js | 28 +++-- .../comments/__snapshots__/jsfmt.spec.js.snap | 13 ++ tests/comments/call_comment.js | 5 + tests/comments/dangling.js | 1 + tests/jsx/__snapshots__/jsfmt.spec.js.snap | 32 +++++ tests/jsx/parens.js | 4 + .../__snapshots__/jsfmt.spec.js.snap | 2 +- tests/nullish_coalescing/jsfmt.spec.js | 2 +- .../__snapshots__/jsfmt.spec.js.snap | 102 +++++++++++++++- tests/optional_chaining/chaining.js | 47 +++++++ tests/optional_chaining/jsfmt.spec.js | 2 +- .../__snapshots__/jsfmt.spec.js.snap | 22 ++-- tests/template_literals/expressions.js | 6 +- tests/template_literals/jsfmt.spec.js | 2 +- .../__snapshots__/jsfmt.spec.js.snap | 68 +++++++++++ tests/typescript_assert/index.ts | 28 +++++ tests/typescript_assert/jsfmt.spec.js | 1 + .../__snapshots__/jsfmt.spec.js.snap | 20 +++ .../declare_class_fields.ts | 2 + yarn.lock | 30 ++--- 27 files changed, 572 insertions(+), 116 deletions(-) create mode 100644 tests/typescript_assert/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/typescript_assert/index.ts create mode 100644 tests/typescript_assert/jsfmt.spec.js create mode 100644 tests/typescript_declare/declare_class_fields.ts diff --git a/CHANGELOG.unreleased.md b/CHANGELOG.unreleased.md index 10b564ae..94da1ddc 100644 --- a/CHANGELOG.unreleased.md +++ b/CHANGELOG.unreleased.md @@ -44,6 +44,107 @@ const link = http://example.com; --> +#### TypeScript: Support for TypeScript 3.7 ([#6657] by [@cryrivers]) + +Prettier 1.19 adds support for the features of the upcoming TypeScript 3.7 that introduce new syntax: + +- [Optional chaining](https://devblogs.microsoft.com/typescript/announcing-typescript-3-7-rc/#optional-chaining) +- [Nullish coalescing](https://devblogs.microsoft.com/typescript/announcing-typescript-3-7-rc/#nullish-coalescing) +- [Assertion functions](https://devblogs.microsoft.com/typescript/announcing-typescript-3-7-rc/#assertion-functions) +- [`declare` modifier on class fields](https://github.com/microsoft/TypeScript/pull/33509) + +**NOTE:** A dependency upgrade for TypeScript 3.7 led to dropping Node 6 support for direct installation from GitHub. Prettier installed from NPM stays compatible with Node 4. + +##### Optional Chaining + + +```ts +// Input +const longChain = obj?.a?.b?.c?.d?.e?.f?.g; +const longChainCallExpression = obj.a?.(a,b,c).b?.(a,b,c).c?.(a,b,c).d?.(a,b,c).e?.(a,b,c).f?.(a,b,c) + +// Output (Prettier master) +const longChain = obj?.a?.b?.c?.d?.e?.f?.g; +const longChainCallExpression = obj + .a?.(a, b, c) + .b?.(a, b, c) + .c?.(a, b, c) + .d?.(a, b, c) + .e?.(a, b, c) + .f?.(a, b, c); +``` + +##### Nullish Coalescing + + +```ts +// Input +const cond = null; +const result = cond??'a'; +const longChain = cond??cond??cond??'b'; + +// Output (Prettier master) +const cond = null; +const result = cond ?? "a"; +const longChain = cond ?? cond ?? cond ?? "b"; +``` + +##### Assertion Functions + + +```ts +// Input +function assertsString(x: any): asserts x {console.assert(typeof x === 'string');} +function assertsStringWithGuard(x: any): asserts x is string {console.assert(typeof x === 'string');} + +// Output (Prettier master) +function assertsString(x: any): asserts x { + console.assert(typeof x === "string"); +} +function assertsStringWithGuard(x: any): asserts x is string { + console.assert(typeof x === "string"); +} +``` + +##### `declare` Modifier on Class Fields + + +```ts +// Input +class B {p: number;} +class C extends B {declare p: 256 | 1000;} + +// Output (Prettier master) +class B { + p: number; +} +class C extends B { + declare p: 256 | 1000; +} +``` + +#### TypeScript: Prettier removed `?` from optional computed class fields ([#6657] by [@cryrivers]) + +Still happens if the field key is a complex expression, but has been fixed in this case: + + +```ts +// Input +class Foo { + [bar]?: number; +} + +// Output (Prettier stable) +class Foo { + [bar]: number; +} + +// Output (Prettier master) +class Foo { + [bar]?: number; +} +``` + #### API: Add `resolveConfig` option to `getFileInfo()` ([#6666] by [@kaicataldo]) Add a `resolveConfig: boolean` option to `prettier.getFileInfo()` that, when set to `true`, will resolve the configuration for the given file path. This allows consumers to take any overridden parsers into account. @@ -52,6 +153,7 @@ Add a `resolveConfig: boolean` option to `prettier.getFileInfo()` that, when set ```js +// Input const addOne = add(1, ?); // apply from the left addOne(2); // 3 @@ -1168,6 +1270,7 @@ new Map([ ``` [#5682]: https://github.com/prettier/prettier/pull/5682 +[#6657]: https://github.com/prettier/prettier/pull/6657 [#5910]: https://github.com/prettier/prettier/pull/5910 [#6033]: https://github.com/prettier/prettier/pull/6033 [#6186]: https://github.com/prettier/prettier/pull/6186 @@ -1224,4 +1327,5 @@ new Map([ [@selvazhagan]: https://github.com/selvazhagan [@chadian]: https://github.com/chadian [@kaicataldo]: https://github.com/kaicataldo +[@cryrivers]: https://github.com/Cryrivers [@voithos]: https://github.com/voithos diff --git a/package.json b/package.json index 851474d8..3114cb47 100644 --- a/package.json +++ b/package.json @@ -11,7 +11,7 @@ "license": "MIT", "main": "./index.js", "engines": { - "node": ">=6" + "node": ">=8" }, "dependencies": { "@angular/compiler": "8.2.7", @@ -19,7 +19,7 @@ "@babel/parser": "7.6.3", "@glimmer/syntax": "0.41.0", "@iarna/toml": "2.2.3", - "@typescript-eslint/typescript-estree": "1.13.0", + "@typescript-eslint/typescript-estree": "2.5.1-alpha.5", "angular-estree-parser": "1.1.5", "angular-html-parser": "1.2.0", "camelcase": "5.3.1", @@ -67,7 +67,7 @@ "resolve": "1.12.0", "semver": "6.3.0", "string-width": "3.1.0", - "typescript": "3.6.4", + "typescript": "3.7.1-rc", "unicode-regex": "3.0.0", "unified": "6.1.6", "vnopts": "1.0.2", diff --git a/src/common/util.js b/src/common/util.js index 5db0e0ad..582f76ee 100644 --- a/src/common/util.js +++ b/src/common/util.js @@ -342,6 +342,7 @@ function startsWithNoLookaheadToken(node, forbidFunctionClassAndDoExpr) { case "ObjectExpression": return true; case "MemberExpression": + case "OptionalMemberExpression": return startsWithNoLookaheadToken( node.object, forbidFunctionClassAndDoExpr @@ -353,6 +354,7 @@ function startsWithNoLookaheadToken(node, forbidFunctionClassAndDoExpr) { } return startsWithNoLookaheadToken(node.tag, forbidFunctionClassAndDoExpr); case "CallExpression": + case "OptionalCallExpression": if (node.callee.type === "FunctionExpression") { // IIFEs are always already parenthesized return false; diff --git a/src/language-js/comments.js b/src/language-js/comments.js index cf264945..6f339594 100644 --- a/src/language-js/comments.js +++ b/src/language-js/comments.js @@ -564,6 +564,7 @@ function handleCommentInEmptyParens(text, enclosingNode, comment, options) { enclosingNode.type === "ObjectMethod") && enclosingNode.params.length === 0) || ((enclosingNode.type === "CallExpression" || + enclosingNode.type === "OptionalCallExpression" || enclosingNode.type === "NewExpression") && enclosingNode.arguments.length === 0)) ) { @@ -686,7 +687,8 @@ function handleBreakAndContinueStatementComments(enclosingNode, comment) { function handleCallExpressionComments(precedingNode, enclosingNode, comment) { if ( enclosingNode && - enclosingNode.type === "CallExpression" && + (enclosingNode.type === "CallExpression" || + enclosingNode.type === "OptionalCallExpression") && precedingNode && enclosingNode.callee === precedingNode && enclosingNode.arguments.length > 0 diff --git a/src/language-js/needs-parens.js b/src/language-js/needs-parens.js index c8596ecf..d8201676 100644 --- a/src/language-js/needs-parens.js +++ b/src/language-js/needs-parens.js @@ -254,14 +254,16 @@ function needsParens(path, options) { return true; case "MemberExpression": - return name === "object" && parent.object === node; + case "OptionalMemberExpression": + return name === "object"; case "TaggedTemplateExpression": return true; case "NewExpression": case "CallExpression": - return name === "callee" && parent.callee === node; + case "OptionalCallExpression": + return name === "callee"; case "BinaryExpression": return parent.operator === "**" && name === "left"; @@ -306,7 +308,8 @@ function needsParens(path, options) { case "CallExpression": case "NewExpression": - return name === "callee" && parent.callee === node; + case "OptionalCallExpression": + return name === "callee"; case "ClassExpression": case "ClassDeclaration": @@ -327,7 +330,7 @@ function needsParens(path, options) { case "MemberExpression": case "OptionalMemberExpression": - return name === "object" && parent.object === node; + return name === "object"; case "AssignmentExpression": return ( @@ -427,15 +430,16 @@ function needsParens(path, options) { case "TSAsExpression": case "TSNonNullExpression": case "BindExpression": - case "OptionalMemberExpression": return true; case "MemberExpression": - return parent.object === node; + case "OptionalMemberExpression": + return name === "object"; case "NewExpression": case "CallExpression": - return parent.callee === node; + case "OptionalCallExpression": + return name === "callee"; case "ConditionalExpression": return parent.test === node; @@ -591,18 +595,19 @@ function needsParens(path, options) { case "TypeCastExpression": case "TSAsExpression": case "TSNonNullExpression": - case "OptionalMemberExpression": return true; case "NewExpression": case "CallExpression": - return name === "callee" && parent.callee === node; + case "OptionalCallExpression": + return name === "callee"; case "ConditionalExpression": return name === "test" && parent.test === node; case "MemberExpression": - return name === "object" && parent.object === node; + case "OptionalMemberExpression": + return name === "object"; default: return false; @@ -612,7 +617,10 @@ function needsParens(path, options) { switch (parent.type) { case "NewExpression": case "CallExpression": - return name === "callee"; // Not strictly necessary, but it's clearer to the reader if IIFEs are wrapped in parentheses. + case "OptionalCallExpression": + // Not always necessary, but it's clearer to the reader if IIFEs are wrapped in parentheses. + // Is necessary if it is `expression` of `ExpressionStatement`. + return name === "callee"; case "TaggedTemplateExpression": return true; // This is basically a kind of IIFE. default: @@ -621,13 +629,13 @@ function needsParens(path, options) { case "ArrowFunctionExpression": switch (parent.type) { - case "CallExpression": - return name === "callee"; - case "NewExpression": + case "CallExpression": + case "OptionalCallExpression": return name === "callee"; case "MemberExpression": + case "OptionalMemberExpression": return name === "object"; case "TSAsExpression": @@ -656,23 +664,32 @@ function needsParens(path, options) { } case "OptionalMemberExpression": - return parent.type === "MemberExpression"; - + case "OptionalCallExpression": + if ( + ((parent.type === "MemberExpression" && name === "object") || + (parent.type === "CallExpression" && name === "callee")) && + // workaround for https://github.com/facebook/flow/issues/8159 + !(options.parser === "flow" && parent.range[0] === node.range[0]) + ) { + return true; + } + // fallthrough case "CallExpression": case "MemberExpression": case "TaggedTemplateExpression": case "TSNonNullExpression": if ( (parent.type === "BindExpression" || parent.type === "NewExpression") && - name === "callee" && - parent.callee === node + name === "callee" ) { let object = node; while (object) { switch (object.type) { case "CallExpression": + case "OptionalCallExpression": return true; case "MemberExpression": + case "OptionalMemberExpression": case "BindExpression": object = object.object; break; @@ -692,20 +709,14 @@ function needsParens(path, options) { return false; case "BindExpression": - if ( - (parent.type === "BindExpression" && - name === "callee" && - parent.callee === node) || - (parent.type === "MemberExpression" && - name === "object" && - parent.object === node) || - (parent.type === "NewExpression" && - name === "callee" && - parent.callee === node) - ) { - return true; - } - return false; + return ( + ((parent.type === "BindExpression" || + parent.type === "NewExpression") && + name === "callee") || + ((parent.type === "MemberExpression" || + parent.type === "OptionalMemberExpression") && + name === "object") + ); case "NGPipeExpression": if ( parent.type === "NGRoot" || @@ -725,25 +736,27 @@ function needsParens(path, options) { case "JSXFragment": case "JSXElement": return ( - parent.type !== "ArrayExpression" && - parent.type !== "ArrowFunctionExpression" && - parent.type !== "AssignmentExpression" && - parent.type !== "AssignmentPattern" && - parent.type !== "BinaryExpression" && - parent.type !== "CallExpression" && - parent.type !== "ConditionalExpression" && - parent.type !== "ExpressionStatement" && - parent.type !== "JsExpressionRoot" && - parent.type !== "JSXAttribute" && - parent.type !== "JSXElement" && - parent.type !== "JSXExpressionContainer" && - parent.type !== "JSXFragment" && - parent.type !== "LogicalExpression" && - parent.type !== "ObjectProperty" && - parent.type !== "Property" && - parent.type !== "ReturnStatement" && - parent.type !== "TypeCastExpression" && - parent.type !== "VariableDeclarator" + name === "callee" || + (parent.type !== "ArrayExpression" && + parent.type !== "ArrowFunctionExpression" && + parent.type !== "AssignmentExpression" && + parent.type !== "AssignmentPattern" && + parent.type !== "BinaryExpression" && + parent.type !== "CallExpression" && + parent.type !== "ConditionalExpression" && + parent.type !== "ExpressionStatement" && + parent.type !== "JsExpressionRoot" && + parent.type !== "JSXAttribute" && + parent.type !== "JSXElement" && + parent.type !== "JSXExpressionContainer" && + parent.type !== "JSXFragment" && + parent.type !== "LogicalExpression" && + parent.type !== "ObjectProperty" && + parent.type !== "OptionalCallExpression" && + parent.type !== "Property" && + parent.type !== "ReturnStatement" && + parent.type !== "TypeCastExpression" && + parent.type !== "VariableDeclarator") ); } diff --git a/src/language-js/parser-typescript.js b/src/language-js/parser-typescript.js index 8f99112f..35401525 100644 --- a/src/language-js/parser-typescript.js +++ b/src/language-js/parser-typescript.js @@ -43,10 +43,7 @@ function tryParseTypeScript(text, jsx) { tokens: true, comment: true, useJSXTextNode: true, - jsx, - // Override logger function with noop, - // to avoid unsupported version errors being logged - loggerFn: () => {} + jsx }); } diff --git a/src/language-js/printer-estree.js b/src/language-js/printer-estree.js index 0696c55c..4bbb9193 100644 --- a/src/language-js/printer-estree.js +++ b/src/language-js/printer-estree.js @@ -570,7 +570,9 @@ function printPathNoParens(path, options, print, args) { // c // ).call() if ( - (parent.type === "CallExpression" && parent.callee === n) || + ((parent.type === "CallExpression" || + parent.type === "OptionalCallExpression") && + parent.callee === n) || parent.type === "UnaryExpression" || ((parent.type === "MemberExpression" || parent.type === "OptionalMemberExpression") && @@ -596,7 +598,8 @@ function printPathNoParens(path, options, print, args) { (n !== parent.body && parent.type === "ForStatement") || (parent.type === "ConditionalExpression" && (parentParent.type !== "ReturnStatement" && - parentParent.type !== "CallExpression")); + parentParent.type !== "CallExpression" && + parentParent.type !== "OptionalCallExpression")); const shouldIndentIfInlining = parent.type === "AssignmentExpression" || @@ -2350,6 +2353,9 @@ function printPathNoParens(path, options, print, args) { if (n.accessibility) { parts.push(n.accessibility + " "); } + if (n.declare) { + parts.push("declare "); + } if (n.static) { parts.push("static "); } @@ -3177,9 +3183,11 @@ function printPathNoParens(path, options, print, args) { } case "TSTypePredicate": return concat([ + n.asserts ? "asserts " : "", path.call(print, "parameterName"), - " is ", - path.call(print, "typeAnnotation") + n.typeAnnotation + ? concat([" is ", path.call(print, "typeAnnotation")]) + : "" ]); case "TSNonNullExpression": return concat([path.call(print, "expression"), "!"]); @@ -5447,11 +5455,17 @@ function maybeWrapJSXElementInParens(path, elem, options) { return elem; } - const shouldBreak = matchAncestorTypes(path, [ - "ArrowFunctionExpression", - "CallExpression", - "JSXExpressionContainer" - ]); + const shouldBreak = + matchAncestorTypes(path, [ + "ArrowFunctionExpression", + "CallExpression", + "JSXExpressionContainer" + ]) || + matchAncestorTypes(path, [ + "ArrowFunctionExpression", + "OptionalCallExpression", + "JSXExpressionContainer" + ]); const needsParens = pathNeedsParens(path, options); @@ -5816,7 +5830,8 @@ function willPrintOwnComments(path /*, options */) { (isJSXNode(node) || hasFlowShorthandAnnotationComment(node) || (parent && - parent.type === "CallExpression" && + (parent.type === "CallExpression" || + parent.type === "OptionalCallExpression") && (hasFlowAnnotationComment(node.leadingComments) || hasFlowAnnotationComment(node.trailingComments))))) || (parent && diff --git a/src/language-js/utils.js b/src/language-js/utils.js index cd60e378..8666b6eb 100644 --- a/src/language-js/utils.js +++ b/src/language-js/utils.js @@ -425,25 +425,29 @@ function isSimpleTemplateLiteral(node) { // Allow `a.b.c`, `a.b[c]`, and `this.x.y` if ( - (expr.type === "MemberExpression" || - expr.type === "OptionalMemberExpression") && - (expr.property.type === "Identifier" || expr.property.type === "Literal") + expr.type === "MemberExpression" || + expr.type === "OptionalMemberExpression" ) { - let ancestor = expr; + let head = expr; while ( - ancestor.type === "MemberExpression" || - ancestor.type === "OptionalMemberExpression" + head.type === "MemberExpression" || + head.type === "OptionalMemberExpression" ) { - ancestor = ancestor.object; - if (ancestor.comments) { + if ( + head.property.type !== "Identifier" && + head.property.type !== "Literal" && + head.property.type !== "StringLiteral" && + head.property.type !== "NumericLiteral" + ) { + return false; + } + head = head.object; + if (head.comments) { return false; } } - if ( - ancestor.type === "Identifier" || - ancestor.type === "ThisExpression" - ) { + if (head.type === "Identifier" || head.type === "ThisExpression") { return true; } diff --git a/tests/comments/__snapshots__/jsfmt.spec.js.snap b/tests/comments/__snapshots__/jsfmt.spec.js.snap index 87824618..34cf5455 100644 --- a/tests/comments/__snapshots__/jsfmt.spec.js.snap +++ b/tests/comments/__snapshots__/jsfmt.spec.js.snap @@ -325,6 +325,11 @@ React.render( // Warm any cache container ); +render?.( // Warm any cache + , + container +); + =====================================output===================================== render( // Warm any cache @@ -338,6 +343,12 @@ React.render( container ); +render?.( + // Warm any cache + , + container +); + ================================================================================ `; @@ -357,6 +368,7 @@ function d() { } new Thing(/* dangling */); Thing(/* dangling */); +Thing?.(/* dangling */); declare class Foo extends Qux {/* dangling */} export /* dangling */{}; @@ -375,6 +387,7 @@ function d() { } new Thing(/* dangling */); Thing(/* dangling */); +Thing?.(/* dangling */); declare class Foo extends Qux { /* dangling */ } diff --git a/tests/comments/call_comment.js b/tests/comments/call_comment.js index ff2ea0ea..ac4af413 100644 --- a/tests/comments/call_comment.js +++ b/tests/comments/call_comment.js @@ -7,3 +7,8 @@ React.render( // Warm any cache , container ); + +render?.( // Warm any cache + , + container +); diff --git a/tests/comments/dangling.js b/tests/comments/dangling.js index 25939492..30ae9272 100644 --- a/tests/comments/dangling.js +++ b/tests/comments/dangling.js @@ -8,5 +8,6 @@ function d() { } new Thing(/* dangling */); Thing(/* dangling */); +Thing?.(/* dangling */); declare class Foo extends Qux {/* dangling */} export /* dangling */{}; diff --git a/tests/jsx/__snapshots__/jsfmt.spec.js.snap b/tests/jsx/__snapshots__/jsfmt.spec.js.snap index c07256ba..31cb9d86 100644 --- a/tests/jsx/__snapshots__/jsfmt.spec.js.snap +++ b/tests/jsx/__snapshots__/jsfmt.spec.js.snap @@ -4093,6 +4093,10 @@ a = [
+f?.(
); +(
)(); +(
)?.(); + =====================================output===================================== a = [ ; +f?.(
); +(
)(); +(
)?.(); + ================================================================================ `; @@ -4131,6 +4139,10 @@ a = [
+f?.(
); +(
)(); +(
)?.(); + =====================================output===================================== a = [ ; +f?.(
); +(
)(); +(
)?.(); + ================================================================================ `; @@ -4169,6 +4185,10 @@ a = [
+f?.(
); +(
)(); +(
)?.(); + =====================================output===================================== a = [ ; +f?.(
); +(
)(); +(
)?.(); + ================================================================================ `; @@ -4207,6 +4231,10 @@ a = [
+f?.(
); +(
)(); +(
)?.(); + =====================================output===================================== a = [ ; +f?.(
); +(
)(); +(
)?.(); + ================================================================================ `; diff --git a/tests/jsx/parens.js b/tests/jsx/parens.js index 3a31f7c1..aacd7379 100644 --- a/tests/jsx/parens.js +++ b/tests/jsx/parens.js @@ -10,3 +10,7 @@ a = [ ];
+ +f?.(
); +(
)(); +(
)?.(); diff --git a/tests/nullish_coalescing/__snapshots__/jsfmt.spec.js.snap b/tests/nullish_coalescing/__snapshots__/jsfmt.spec.js.snap index a85951d9..57a8c76a 100644 --- a/tests/nullish_coalescing/__snapshots__/jsfmt.spec.js.snap +++ b/tests/nullish_coalescing/__snapshots__/jsfmt.spec.js.snap @@ -2,7 +2,7 @@ exports[`nullish_coalesing_operator.js 1`] = ` ====================================options===================================== -parsers: ["babel", "flow"] +parsers: ["babel", "flow", "typescript"] printWidth: 80 | printWidth =====================================input====================================== diff --git a/tests/nullish_coalescing/jsfmt.spec.js b/tests/nullish_coalescing/jsfmt.spec.js index e3b2b302..eb85eda6 100644 --- a/tests/nullish_coalescing/jsfmt.spec.js +++ b/tests/nullish_coalescing/jsfmt.spec.js @@ -1 +1 @@ -run_spec(__dirname, ["babel", "flow"]); +run_spec(__dirname, ["babel", "flow", "typescript"]); diff --git a/tests/optional_chaining/__snapshots__/jsfmt.spec.js.snap b/tests/optional_chaining/__snapshots__/jsfmt.spec.js.snap index 72697a72..d317b7b4 100644 --- a/tests/optional_chaining/__snapshots__/jsfmt.spec.js.snap +++ b/tests/optional_chaining/__snapshots__/jsfmt.spec.js.snap @@ -2,7 +2,7 @@ exports[`chaining.js 1`] = ` ====================================options===================================== -parsers: ["babel", "flow"] +parsers: ["babel", "flow", "typescript"] printWidth: 80 | printWidth =====================================input====================================== @@ -35,8 +35,55 @@ a?.b[3].c?.(x).d.e?.f[3].g?.(y).h; async function HelloWorld() { var x = (await foo.bar.blah)?.hi; + a?.[await b]; + (await x)?.(); } +a[b?.c].d(); +a?.[b?.c].d(); +a[b?.c]?.d(); +a?.[b?.c]?.d(); + +(one?.fn()); +(one?.two).fn(); +(one.two?.fn()); +(one.two?.three).fn(); +(one.two?.three?.fn()); + +(one?.()); +(one?.())(); +(one?.())?.(); + +(one?.()).two; + +a?.[b ? c : d]; + +(-1)?.toFixed(); +(void fn)?.(); +(a && b)?.(); +(a ? b : c)?.(); +(function(){})?.(); +(() => f)?.(); +(()=>f)?.x; +(a?.(x)).x; +(aaaaaaaaaaaaaaaaaaaaaaaa&&aaaaaaaaaaaaaaaaaaaaaaaa&&aaaaaaaaaaaaaaaaaaaaaaaa)?.(); + +let f = () => ({}?.()); +let g = () => ({}?.b); +a = () => ({}?.() && a); +a = () => ({}?.()() && a); +a = () => ({}?.().b && a); +a = () => ({}?.b && a); +a = () => ({}?.b() && a); +(a) => ({}?.()?.b && 0); +(a) => ({}?.b?.b && 0); +(x) => ({}?.()()); +(x) => ({}?.().b); +(x) => ({}?.b()); +(x) => ({}?.b.b); +({}?.a().b()); +({ a: 1 }?.entries()); + =====================================output===================================== var street = user.address?.street; var fooValue = myForm.querySelector("input[name=foo]")?.value; @@ -67,14 +114,65 @@ a?.b?.c.d?.e; async function HelloWorld() { var x = (await foo.bar.blah)?.hi; + a?.[await b]; + (await x)?.(); } +a[b?.c].d(); +a?.[b?.c].d(); +a[b?.c]?.d(); +a?.[b?.c]?.d(); + +one?.fn(); +(one?.two).fn(); +one.two?.fn(); +(one.two?.three).fn(); +one.two?.three?.fn(); + +one?.(); +(one?.())(); +one?.()?.(); + +(one?.()).two; + +a?.[b ? c : d]; + +(-1)?.toFixed(); +(void fn)?.(); +(a && b)?.(); +(a ? b : c)?.(); +(function() {})?.(); +(() => f)?.(); +(() => f)?.x; +(a?.(x)).x; +( + aaaaaaaaaaaaaaaaaaaaaaaa && + aaaaaaaaaaaaaaaaaaaaaaaa && + aaaaaaaaaaaaaaaaaaaaaaaa +)?.(); + +let f = () => ({}?.()); +let g = () => ({}?.b); +a = () => ({}?.() && a); +a = () => ({}?.()() && a); +a = () => ({}?.().b && a); +a = () => ({}?.b && a); +a = () => ({}?.b() && a); +a => ({}?.()?.b && 0); +a => ({}?.b?.b && 0); +x => ({}?.()()); +x => ({}?.().b); +x => ({}?.b()); +x => ({}?.b.b); +({}?.a().b()); +({ a: 1 }?.entries()); + ================================================================================ `; exports[`comments.js 1`] = ` ====================================options===================================== -parsers: ["babel", "flow"] +parsers: ["babel", "flow", "typescript"] printWidth: 80 | printWidth =====================================input====================================== diff --git a/tests/optional_chaining/chaining.js b/tests/optional_chaining/chaining.js index eb30e566..a169179b 100644 --- a/tests/optional_chaining/chaining.js +++ b/tests/optional_chaining/chaining.js @@ -27,4 +27,51 @@ a?.b[3].c?.(x).d.e?.f[3].g?.(y).h; async function HelloWorld() { var x = (await foo.bar.blah)?.hi; + a?.[await b]; + (await x)?.(); } + +a[b?.c].d(); +a?.[b?.c].d(); +a[b?.c]?.d(); +a?.[b?.c]?.d(); + +(one?.fn()); +(one?.two).fn(); +(one.two?.fn()); +(one.two?.three).fn(); +(one.two?.three?.fn()); + +(one?.()); +(one?.())(); +(one?.())?.(); + +(one?.()).two; + +a?.[b ? c : d]; + +(-1)?.toFixed(); +(void fn)?.(); +(a && b)?.(); +(a ? b : c)?.(); +(function(){})?.(); +(() => f)?.(); +(()=>f)?.x; +(a?.(x)).x; +(aaaaaaaaaaaaaaaaaaaaaaaa&&aaaaaaaaaaaaaaaaaaaaaaaa&&aaaaaaaaaaaaaaaaaaaaaaaa)?.(); + +let f = () => ({}?.()); +let g = () => ({}?.b); +a = () => ({}?.() && a); +a = () => ({}?.()() && a); +a = () => ({}?.().b && a); +a = () => ({}?.b && a); +a = () => ({}?.b() && a); +(a) => ({}?.()?.b && 0); +(a) => ({}?.b?.b && 0); +(x) => ({}?.()()); +(x) => ({}?.().b); +(x) => ({}?.b()); +(x) => ({}?.b.b); +({}?.a().b()); +({ a: 1 }?.entries()); diff --git a/tests/optional_chaining/jsfmt.spec.js b/tests/optional_chaining/jsfmt.spec.js index e3b2b302..eb85eda6 100644 --- a/tests/optional_chaining/jsfmt.spec.js +++ b/tests/optional_chaining/jsfmt.spec.js @@ -1 +1 @@ -run_spec(__dirname, ["babel", "flow"]); +run_spec(__dirname, ["babel", "flow", "typescript"]); diff --git a/tests/template_literals/__snapshots__/jsfmt.spec.js.snap b/tests/template_literals/__snapshots__/jsfmt.spec.js.snap index 3457abfa..4768cc0d 100644 --- a/tests/template_literals/__snapshots__/jsfmt.spec.js.snap +++ b/tests/template_literals/__snapshots__/jsfmt.spec.js.snap @@ -2,7 +2,7 @@ exports[`css-prop.js 1`] = ` ====================================options===================================== -parsers: ["flow"] +parsers: ["babel", "flow", "typescript"] printWidth: 80 | printWidth =====================================input====================================== @@ -73,15 +73,15 @@ const TestComponent = ({ children, ...props }) => ( exports[`expressions.js 1`] = ` ====================================options===================================== -parsers: ["flow"] +parsers: ["babel", "flow", "typescript"] printWidth: 80 | printWidth =====================================input====================================== -const long = \`long \${a//comment +const long1 = \`long \${a//comment .b} long longlong \${a.b.c.d.e} long longlong \${a.b.c.d.e} long longlong \${a.b.c.d.e} long long\`; -const long = \`long \${a.b.c.d.e} long longlong \${loooooooooooooooooong} long longlong \${loooooooooooooooooong} long longlong \${loooooooooooooooooong} long long\`; +const long2 = \`long \${a.b.c.d.e} long longlong \${loooooooooooooooooong} long longlong \${loooooooooooooooooong} long longlong \${loooooooooooooooooong} long long\`; -const long = \`long long long long long long long long long long long \${a.b.c.d.e} long long long long long long long long long long long long long\`; +const long3 = \`long long long long long long long long long long long \${a.b.c.d.e} long long long long long long long long long long long long long\`; const description = \`The value of the \${cssName} css of the \${this._name} element\`; @@ -125,14 +125,14 @@ descirbe('something', () => { throw new Error(\`pretty-format: Option "theme" has a key "\${key}" whose value "\${value}" is undefined in ansi-styles.\`,) =====================================output===================================== -const long = \`long \${ +const long1 = \`long \${ a.b //comment } long longlong \${a.b.c.d.e} long longlong \${a.b.c.d.e} long longlong \${ a.b.c.d.e } long long\`; -const long = \`long \${a.b.c.d.e} long longlong \${loooooooooooooooooong} long longlong \${loooooooooooooooooong} long longlong \${loooooooooooooooooong} long long\`; +const long2 = \`long \${a.b.c.d.e} long longlong \${loooooooooooooooooong} long longlong \${loooooooooooooooooong} long longlong \${loooooooooooooooooong} long long\`; -const long = \`long long long long long long long long long long long \${a.b.c.d.e} long long long long long long long long long long long long long\`; +const long3 = \`long long long long long long long long long long long \${a.b.c.d.e} long long long long long long long long long long long long long\`; const description = \`The value of the \${cssName} css of the \${this._name} element\`; @@ -193,7 +193,7 @@ throw new Error( exports[`styled-components-with-expressions.js 1`] = ` ====================================options===================================== -parsers: ["flow"] +parsers: ["babel", "flow", "typescript"] printWidth: 80 | printWidth =====================================input====================================== @@ -294,7 +294,7 @@ const header = css\` exports[`styled-jsx.js 1`] = ` ====================================options===================================== -parsers: ["flow"] +parsers: ["babel", "flow", "typescript"] printWidth: 80 | printWidth =====================================input====================================== @@ -484,7 +484,7 @@ const headerGlobal = css.global\` exports[`styled-jsx-with-expressions.js 1`] = ` ====================================options===================================== -parsers: ["flow"] +parsers: ["babel", "flow", "typescript"] printWidth: 80 | printWidth =====================================input====================================== diff --git a/tests/template_literals/expressions.js b/tests/template_literals/expressions.js index c6e3febd..c68f1176 100644 --- a/tests/template_literals/expressions.js +++ b/tests/template_literals/expressions.js @@ -1,8 +1,8 @@ -const long = `long ${a//comment +const long1 = `long ${a//comment .b} long longlong ${a.b.c.d.e} long longlong ${a.b.c.d.e} long longlong ${a.b.c.d.e} long long`; -const long = `long ${a.b.c.d.e} long longlong ${loooooooooooooooooong} long longlong ${loooooooooooooooooong} long longlong ${loooooooooooooooooong} long long`; +const long2 = `long ${a.b.c.d.e} long longlong ${loooooooooooooooooong} long longlong ${loooooooooooooooooong} long longlong ${loooooooooooooooooong} long long`; -const long = `long long long long long long long long long long long ${a.b.c.d.e} long long long long long long long long long long long long long`; +const long3 = `long long long long long long long long long long long ${a.b.c.d.e} long long long long long long long long long long long long long`; const description = `The value of the ${cssName} css of the ${this._name} element`; diff --git a/tests/template_literals/jsfmt.spec.js b/tests/template_literals/jsfmt.spec.js index b9a90898..eb85eda6 100644 --- a/tests/template_literals/jsfmt.spec.js +++ b/tests/template_literals/jsfmt.spec.js @@ -1 +1 @@ -run_spec(__dirname, ["flow"]); +run_spec(__dirname, ["babel", "flow", "typescript"]); diff --git a/tests/typescript_assert/__snapshots__/jsfmt.spec.js.snap b/tests/typescript_assert/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 00000000..aa33a20c --- /dev/null +++ b/tests/typescript_assert/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,68 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`index.ts 1`] = ` +====================================options===================================== +parsers: ["typescript"] +printWidth: 80 + | printWidth +=====================================input====================================== +const assertString = (x: any): asserts x => { + console.assert(typeof x === 'string'); +} + +function assertsString(x: any): asserts x { + console.assert(typeof x === 'string'); +} + +const assertStringWithGuard = (x: any): asserts x is string => { + console.assert(typeof x === 'string'); +} + +function assertsStringWithGuard(x: any): asserts x is string { + console.assert(typeof x === 'string'); +} + +interface AssertFoo { + isString(node: any): asserts node; +} + +class AssertsFoo { + isBar(): asserts this { + return; + } + isBaz = (): asserts this => { + return; + } +} +=====================================output===================================== +const assertString = (x: any): asserts x => { + console.assert(typeof x === "string"); +}; + +function assertsString(x: any): asserts x { + console.assert(typeof x === "string"); +} + +const assertStringWithGuard = (x: any): asserts x is string => { + console.assert(typeof x === "string"); +}; + +function assertsStringWithGuard(x: any): asserts x is string { + console.assert(typeof x === "string"); +} + +interface AssertFoo { + isString(node: any): asserts node; +} + +class AssertsFoo { + isBar(): asserts this { + return; + } + isBaz = (): asserts this => { + return; + }; +} + +================================================================================ +`; diff --git a/tests/typescript_assert/index.ts b/tests/typescript_assert/index.ts new file mode 100644 index 00000000..e09ee8ea --- /dev/null +++ b/tests/typescript_assert/index.ts @@ -0,0 +1,28 @@ +const assertString = (x: any): asserts x => { + console.assert(typeof x === 'string'); +} + +function assertsString(x: any): asserts x { + console.assert(typeof x === 'string'); +} + +const assertStringWithGuard = (x: any): asserts x is string => { + console.assert(typeof x === 'string'); +} + +function assertsStringWithGuard(x: any): asserts x is string { + console.assert(typeof x === 'string'); +} + +interface AssertFoo { + isString(node: any): asserts node; +} + +class AssertsFoo { + isBar(): asserts this { + return; + } + isBaz = (): asserts this => { + return; + } +} \ No newline at end of file diff --git a/tests/typescript_assert/jsfmt.spec.js b/tests/typescript_assert/jsfmt.spec.js new file mode 100644 index 00000000..2ea3bb6e --- /dev/null +++ b/tests/typescript_assert/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname, ["typescript"]); diff --git a/tests/typescript_declare/__snapshots__/jsfmt.spec.js.snap b/tests/typescript_declare/__snapshots__/jsfmt.spec.js.snap index 44fb4d59..2e79f1b0 100644 --- a/tests/typescript_declare/__snapshots__/jsfmt.spec.js.snap +++ b/tests/typescript_declare/__snapshots__/jsfmt.spec.js.snap @@ -1,5 +1,25 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP +exports[`declare_class_fields.ts 1`] = ` +====================================options===================================== +parsers: ["typescript"] +printWidth: 80 + | printWidth +=====================================input====================================== +class B {p: number;} +class C extends B {declare p: 256 | 1000;} + +=====================================output===================================== +class B { + p: number; +} +class C extends B { + declare p: 256 | 1000; +} + +================================================================================ +`; + exports[`declare_enum.ts 1`] = ` ====================================options===================================== parsers: ["typescript"] diff --git a/tests/typescript_declare/declare_class_fields.ts b/tests/typescript_declare/declare_class_fields.ts new file mode 100644 index 00000000..447d7a37 --- /dev/null +++ b/tests/typescript_declare/declare_class_fields.ts @@ -0,0 +1,2 @@ +class B {p: number;} +class C extends B {declare p: 256 | 1000;} diff --git a/yarn.lock b/yarn.lock index 8c91d834..e22dc9ab 100644 --- a/yarn.lock +++ b/yarn.lock @@ -975,13 +975,16 @@ dependencies: "@types/yargs-parser" "*" -"@typescript-eslint/typescript-estree@1.13.0": - version "1.13.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-1.13.0.tgz#8140f17d0f60c03619798f1d628b8434913dc32e" - integrity sha512-b5rCmd2e6DCC6tCTN9GSUAuxdYwCM/k/2wdjHGrIRGPSJotWMCe/dGpi66u42bhuh8q3QBzqM4TMA1GUUCJvdw== +"@typescript-eslint/typescript-estree@2.5.1-alpha.5": + version "2.5.1-alpha.5" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-2.5.1-alpha.5.tgz#7dc6a29bc55a89640378948894039933c9c370ea" + integrity sha512-R0bXoqvgLw2epTtCRjZZUo+vwGFqRqcQ54kd8Dcm+lVY7Mxp5Wf9CDunojkB2EGwwG0olbihJIRQI1GZaewBtg== dependencies: + debug "^4.1.1" + glob "^7.1.4" + is-glob "^4.0.1" lodash.unescape "4.0.1" - semver "5.5.0" + semver "^6.3.0" "@webassemblyjs/ast@1.8.5": version "1.8.5" @@ -2351,7 +2354,7 @@ debug@^3.1.0: dependencies: ms "2.0.0" -debug@^4.0.1: +debug@^4.0.1, debug@^4.1.1: version "4.1.1" resolved "https://registry.yarnpkg.com/debug/-/debug-4.1.1.tgz#3b72260255109c6b589cee050f1d516139664791" integrity sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw== @@ -5254,6 +5257,7 @@ normalize-package-data@^2.3.2, normalize-package-data@^2.3.4: normalize-path@3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" + integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== normalize-path@^2.0.1, normalize-path@^2.1.1: version "2.1.1" @@ -6477,11 +6481,7 @@ schema-utils@^2.4.1: version "5.6.0" resolved "https://registry.yarnpkg.com/semver/-/semver-5.6.0.tgz#7e74256fbaa49c75aa7c7a205cc22799cac80004" -semver@5.5.0: - version "5.5.0" - resolved "https://registry.yarnpkg.com/semver/-/semver-5.5.0.tgz#dc4bbc7a6ca9d916dee5d43516f0092b58f7b8ab" - -semver@6.3.0, semver@^6.0.0, semver@^6.1.2: +semver@6.3.0, semver@^6.0.0, semver@^6.1.2, semver@^6.3.0: version "6.3.0" resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== @@ -7161,10 +7161,10 @@ typedarray@^0.0.6: version "0.0.6" resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" -typescript@3.6.4: - version "3.6.4" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.6.4.tgz#b18752bb3792bc1a0281335f7f6ebf1bbfc5b91d" - integrity sha512-unoCll1+l+YK4i4F8f22TaNVPRHcD9PA3yCuZ8g5e0qGqlVlJ/8FSateOLLSagn+Yg5+ZwuPkL8LFUc0Jcvksg== +typescript@3.7.1-rc: + version "3.7.1-rc" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.7.1-rc.tgz#2054b872d67f8dc732e36c1df397f9327f37ada0" + integrity sha512-2rMtWppLsaPvmpXsoIAXWDBQVnJMw1ITGGSnidMuayLj9iCmMRT69ncKZw/Mk5rXfJkilApKucWQZxproALoRw== uglify-js@^3.1.4: version "3.6.0"