feat(typescript): add TSTypeAssertionExpression and naive TSX detection (#1545)

master
Lucas Azzola 2017-05-08 01:09:52 +10:00 committed by Christopher Chedeau
parent 3471ce4584
commit fa27e5838c
14 changed files with 361 additions and 1 deletions

View File

@ -313,6 +313,7 @@ FPp.needsParens = function() {
return true;
}
// else fall through
case "TSTypeAssertionExpression":
case "TSAsExpression":
case "LogicalExpression":
switch (parent.type) {
@ -320,6 +321,7 @@ FPp.needsParens = function() {
case "NewExpression":
return name === "callee" && parent.callee === node;
case "TSTypeAssertionExpression":
case "TaggedTemplateExpression":
case "UnaryExpression":
case "SpreadElement":

View File

@ -64,7 +64,7 @@ function parseWithTypeScript(text) {
tokens: true,
attachComment: true,
ecmaFeatures: {
jsx: true
jsx: isJsx(text)
}
});
} catch(e) {
@ -76,4 +76,16 @@ function parseWithTypeScript(text) {
}
}
/**
* Use a naive regular expression until we address
* https://github.com/prettier/prettier/issues/1538
*/
function isJsx(text) {
return new RegExp([
"(</)", // Contains "</"
"|",
"(^[^/]{2}.*\/>)" // Contains "/>" on line not starting with "//"
].join(""), "m").test(text);
}
module.exports = { parseWithFlow, parseWithBabylon, parseWithTypeScript };

View File

@ -257,6 +257,13 @@ function genericPrintNoParens(path, options, print, args) {
" = ",
path.call(print, "right")
]);
case "TSTypeAssertionExpression":
return concat([
"<",
path.call(print, "typeAnnotation"),
">",
path.call(print, "expression")
]);
case "MemberExpression": {
const parent = path.getParentNode();
let firstNonMemberParent;

View File

@ -180,4 +180,10 @@ module.exports = function(fork) {
def("TSTypeParameter").build("name").field("name", def("Identifier"));
def("TSParameterProperty").build("accessibility", "isReadonly", "parameters");
def("TSTypeAssertionExpression")
.build("expression", "typeAnnotation")
.field("expression", def("Identifier"))
.field("typeAnnotation", def("TSType"))
.bases("Expression");
};

View File

@ -20,6 +20,119 @@ var results = number[];
`;
exports[`castOfAwait.ts 1`] = `
// @target: es6
async function f() {
<number> await 0;
typeof await 0;
void await 0;
await void <string> typeof <number> void await 0;
await await 0;
}
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// @target: es6
async function f() {
<number>await 0;
typeof await 0;
void await 0;
await void (<string>typeof (<number>void await 0));
await await 0;
}
`;
exports[`castParentheses.ts 1`] = `
class a {
static b: any;
}
var b = (<any>a);
var b = (<any>a).b;
var b = (<any>a.b).c;
var b = (<any>a.b()).c;
var b = (<any>new a);
var b = (<any>new a.b);
var b = (<any>new a).b
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
class a {
static b: any;
}
var b = <any>a;
var b = (<any>a).b;
var b = (<any>a.b).c;
var b = (<any>a.b()).c;
var b = <any>new a();
var b = <any>new a.b();
var b = (<any>new a()).b;
`;
exports[`castTest.ts 1`] = `
var x : any = 0;
var z = <number> x;
var y = x + z;
var a = <any>0;
var b = <boolean>true;
var s = <string>"";
var ar = <any[]>null;
var f = <(res : number) => void>null;
declare class Point
{
x: number;
y: number;
add(dx: number, dy: number): Point;
mult(p: Point): Point;
constructor(x: number, y: number);
}
var p_cast = <Point> ({
x: 0,
y: 0,
add: function(dx, dy) {
return new Point(this.x + dx, this.y + dy);
},
mult: function(p) { return p; }
})
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
var x: any = 0;
var z = <number>x;
var y = x + z;
var a = <any>0;
var b = <boolean>true;
var s = <string>"";
var ar = <any[]>null;
var f = <(res: number) => void>null;
declare class Point {
x: number;
y: number;
add(dx: number, dy: number): Point;
mult(p: Point): Point;
constructor(x: number, y: number);
}
var p_cast = <Point>{
x: 0,
y: 0,
add: function(dx, dy) {
return new Point(this.x + dx, this.y + dy);
},
mult: function(p) {
return p;
}
};
`;
exports[`checkInfiniteExpansionTermination.ts 1`] = `
// Regression test for #1002
// Before fix this code would cause infinite loop

View File

@ -0,0 +1,8 @@
// @target: es6
async function f() {
<number> await 0;
typeof await 0;
void await 0;
await void <string> typeof <number> void await 0;
await await 0;
}

View File

@ -0,0 +1,11 @@
class a {
static b: any;
}
var b = (<any>a);
var b = (<any>a).b;
var b = (<any>a.b).c;
var b = (<any>a.b()).c;
var b = (<any>new a);
var b = (<any>new a.b);
var b = (<any>new a).b

View File

@ -0,0 +1,30 @@
var x : any = 0;
var z = <number> x;
var y = x + z;
var a = <any>0;
var b = <boolean>true;
var s = <string>"";
var ar = <any[]>null;
var f = <(res : number) => void>null;
declare class Point
{
x: number;
y: number;
add(dx: number, dy: number): Point;
mult(p: Point): Point;
constructor(x: number, y: number);
}
var p_cast = <Point> ({
x: 0,
y: 0,
add: function(dx, dy) {
return new Point(this.x + dx, this.y + dy);
},
mult: function(p) { return p; }
})

View File

@ -0,0 +1,10 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`templateStringWithEmbeddedTypeAssertionOnAdditionES6.ts 1`] = `
// @target: ES6
var x = \`abc\${ <any>(10 + 10) }def\`;
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// @target: ES6
var x = \`abc\${<any>(10 + 10)}def\`;
`;

View File

@ -0,0 +1 @@
run_spec(__dirname, { parser: "typescript" });

View File

@ -0,0 +1,2 @@
// @target: ES6
var x = `abc${ <any>(10 + 10) }def`;

View File

@ -0,0 +1,106 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`callWithSpreadES6.ts 1`] = `
// @target: ES6
interface X {
foo(x: number, y: number, ...z: string[]);
}
function foo(x: number, y: number, ...z: string[]) {
}
var a: string[];
var z: number[];
var obj: X;
var xa: X[];
foo(1, 2, "abc");
foo(1, 2, ...a);
foo(1, 2, ...a, "abc");
obj.foo(1, 2, "abc");
obj.foo(1, 2, ...a);
obj.foo(1, 2, ...a, "abc");
(obj.foo)(1, 2, "abc");
(obj.foo)(1, 2, ...a);
(obj.foo)(1, 2, ...a, "abc");
xa[1].foo(1, 2, "abc");
xa[1].foo(1, 2, ...a);
xa[1].foo(1, 2, ...a, "abc");
(<Function>xa[1].foo)(...[1, 2, "abc"]);
class C {
constructor(x: number, y: number, ...z: string[]) {
this.foo(x, y);
this.foo(x, y, ...z);
}
foo(x: number, y: number, ...z: string[]) {
}
}
class D extends C {
constructor() {
super(1, 2);
super(1, 2, ...a);
}
foo() {
super.foo(1, 2);
super.foo(1, 2, ...a);
}
}
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// @target: ES6
interface X {
foo(x: number, y: number, ...z: string[])
}
function foo(x: number, y: number, ...z: string[]) {}
var a: string[];
var z: number[];
var obj: X;
var xa: X[];
foo(1, 2, "abc");
foo(1, 2, ...a);
foo(1, 2, ...a, "abc");
obj.foo(1, 2, "abc");
obj.foo(1, 2, ...a);
obj.foo(1, 2, ...a, "abc");
obj.foo(1, 2, "abc");
obj.foo(1, 2, ...a);
obj.foo(1, 2, ...a, "abc");
xa[1].foo(1, 2, "abc");
xa[1].foo(1, 2, ...a);
xa[1].foo(1, 2, ...a, "abc");
(<Function>xa[1].foo)(...[1, 2, "abc"]);
class C {
constructor(x: number, y: number, ...z: string[]) {
this.foo(x, y);
this.foo(x, y, ...z);
}
foo(x: number, y: number, ...z: string[]) {}
}
class D extends C {
constructor() {
super(1, 2);
super(1, 2, ...a);
}
foo() {
super.foo(1, 2);
super.foo(1, 2, ...a);
}
}
`;

View File

@ -0,0 +1,51 @@
// @target: ES6
interface X {
foo(x: number, y: number, ...z: string[]);
}
function foo(x: number, y: number, ...z: string[]) {
}
var a: string[];
var z: number[];
var obj: X;
var xa: X[];
foo(1, 2, "abc");
foo(1, 2, ...a);
foo(1, 2, ...a, "abc");
obj.foo(1, 2, "abc");
obj.foo(1, 2, ...a);
obj.foo(1, 2, ...a, "abc");
(obj.foo)(1, 2, "abc");
(obj.foo)(1, 2, ...a);
(obj.foo)(1, 2, ...a, "abc");
xa[1].foo(1, 2, "abc");
xa[1].foo(1, 2, ...a);
xa[1].foo(1, 2, ...a, "abc");
(<Function>xa[1].foo)(...[1, 2, "abc"]);
class C {
constructor(x: number, y: number, ...z: string[]) {
this.foo(x, y);
this.foo(x, y, ...z);
}
foo(x: number, y: number, ...z: string[]) {
}
}
class D extends C {
constructor() {
super(1, 2);
super(1, 2, ...a);
}
foo() {
super.foo(1, 2);
super.foo(1, 2, ...a);
}
}

View File

@ -0,0 +1 @@
run_spec(__dirname, { parser: "typescript" });