2520 lines
108 KiB
Go
2520 lines
108 KiB
Go
package printer_test
|
|
|
|
import (
|
|
"testing"
|
|
|
|
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/ast"
|
|
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/core"
|
|
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/printer"
|
|
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/testutil/emittestutil"
|
|
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/testutil/parsetestutil"
|
|
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/transformers"
|
|
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/transformers/tstransforms"
|
|
)
|
|
|
|
func TestEmit(t *testing.T) {
|
|
t.Parallel()
|
|
data := []struct {
|
|
title string
|
|
input string
|
|
output string
|
|
jsx bool
|
|
}{
|
|
{title: "StringLiteral#1", input: `;"test"`, output: ";\n\"test\";"},
|
|
{title: "StringLiteral#2", input: `;'test'`, output: ";\n'test';"},
|
|
{title: "NumericLiteral#1", input: `0`, output: `0;`},
|
|
{title: "NumericLiteral#2", input: `10_000`, output: `10_000;`},
|
|
{title: "BigIntLiteral#1", input: `0n`, output: `0n;`},
|
|
{title: "BigIntLiteral#2", input: `10_000n`, output: `10000n;`}, // TODO: Preserve numeric literal separators after Strada migration
|
|
{title: "BooleanLiteral#1", input: `true`, output: `true;`},
|
|
{title: "BooleanLiteral#2", input: `false`, output: `false;`},
|
|
{title: "NoSubstitutionTemplateLiteral", input: "``", output: "``;"},
|
|
{title: "NoSubstitutionTemplateLiteral#2", input: "`\n`", output: "`\n`;"},
|
|
|
|
{title: "RegularExpressionLiteral#1", input: `/a/`, output: `/a/;`},
|
|
{title: "RegularExpressionLiteral#2", input: `/a/g`, output: `/a/g;`},
|
|
{title: "NullLiteral", input: `null`, output: `null;`},
|
|
{title: "ThisExpression", input: `this`, output: `this;`},
|
|
{title: "SuperExpression", input: `super()`, output: `super();`},
|
|
{title: "ImportExpression", input: `import()`, output: `import();`},
|
|
{title: "PropertyAccess#1", input: `a.b`, output: `a.b;`},
|
|
{title: "PropertyAccess#2", input: `a.#b`, output: `a.#b;`},
|
|
{title: "PropertyAccess#3", input: `a?.b`, output: `a?.b;`},
|
|
{title: "PropertyAccess#4", input: `a?.b.c`, output: `a?.b.c;`},
|
|
{title: "PropertyAccess#5", input: `1..b`, output: `1..b;`},
|
|
{title: "PropertyAccess#6", input: `1.0.b`, output: `1.0.b;`},
|
|
{title: "PropertyAccess#7", input: `0x1.b`, output: `0x1.b;`},
|
|
{title: "PropertyAccess#8", input: `0b1.b`, output: `0b1.b;`},
|
|
{title: "PropertyAccess#9", input: `0o1.b`, output: `0o1.b;`},
|
|
{title: "PropertyAccess#10", input: `10e1.b`, output: `10e1.b;`},
|
|
{title: "PropertyAccess#11", input: `10E1.b`, output: `10E1.b;`},
|
|
{title: "PropertyAccess#12", input: `a.b?.c`, output: `a.b?.c;`},
|
|
{title: "PropertyAccess#13", input: "a\n.b", output: "a\n .b;"},
|
|
{title: "PropertyAccess#14", input: "a.\nb", output: "a.\n b;"},
|
|
{title: "ElementAccess#1", input: `a[b]`, output: `a[b];`},
|
|
{title: "ElementAccess#2", input: `a?.[b]`, output: `a?.[b];`},
|
|
{title: "ElementAccess#3", input: `a?.[b].c`, output: `a?.[b].c;`},
|
|
{title: "CallExpression#1", input: `a()`, output: `a();`},
|
|
{title: "CallExpression#2", input: `a<T>()`, output: `a<T>();`},
|
|
{title: "CallExpression#3", input: `a(b)`, output: `a(b);`},
|
|
{title: "CallExpression#4", input: `a<T>(b)`, output: `a<T>(b);`},
|
|
{title: "CallExpression#5", input: `a(b).c`, output: `a(b).c;`},
|
|
{title: "CallExpression#6", input: `a<T>(b).c`, output: `a<T>(b).c;`},
|
|
{title: "CallExpression#7", input: `a?.(b)`, output: `a?.(b);`},
|
|
{title: "CallExpression#8", input: `a?.<T>(b)`, output: `a?.<T>(b);`},
|
|
{title: "CallExpression#9", input: `a?.(b).c`, output: `a?.(b).c;`},
|
|
{title: "CallExpression#10", input: `a?.<T>(b).c`, output: `a?.<T>(b).c;`},
|
|
{title: "CallExpression#11", input: `a<T, U>()`, output: `a<T, U>();`},
|
|
// {title: "CallExpression#12", input: `a<T,>()`, output: `a<T,>();`}, // TODO: preserve trailing comma after Strada migration
|
|
{title: "CallExpression#13", input: `a?.b()`, output: `a?.b();`},
|
|
{title: "NewExpression#1", input: `new a`, output: `new a;`},
|
|
{title: "NewExpression#2", input: `new a.b`, output: `new a.b;`},
|
|
{title: "NewExpression#3", input: `new a()`, output: `new a();`},
|
|
{title: "NewExpression#4", input: `new a.b()`, output: `new a.b();`},
|
|
{title: "NewExpression#5", input: `new a<T>()`, output: `new a<T>();`},
|
|
{title: "NewExpression#6", input: `new a.b<T>()`, output: `new a.b<T>();`},
|
|
{title: "NewExpression#7", input: `new a(b)`, output: `new a(b);`},
|
|
{title: "NewExpression#8", input: `new a.b(c)`, output: `new a.b(c);`},
|
|
{title: "NewExpression#9", input: `new a<T>(b)`, output: `new a<T>(b);`},
|
|
{title: "NewExpression#10", input: `new a.b<T>(c)`, output: `new a.b<T>(c);`},
|
|
{title: "NewExpression#11", input: `new a(b).c`, output: `new a(b).c;`},
|
|
{title: "NewExpression#12", input: `new a<T>(b).c`, output: `new a<T>(b).c;`},
|
|
{title: "TaggedTemplateExpression#1", input: "tag``", output: "tag ``;"},
|
|
{title: "TaggedTemplateExpression#2", input: "tag<T>``", output: "tag<T> ``;"},
|
|
{title: "TypeAssertionExpression#1", input: `<T>a`, output: `<T>a;`},
|
|
{title: "FunctionExpression#1", input: `(function(){})`, output: `(function () { });`},
|
|
{title: "FunctionExpression#2", input: `(function f(){})`, output: `(function f() { });`},
|
|
{title: "FunctionExpression#3", input: `(function*f(){})`, output: `(function* f() { });`},
|
|
{title: "FunctionExpression#4", input: `(async function f(){})`, output: `(async function f() { });`},
|
|
{title: "FunctionExpression#5", input: `(async function*f(){})`, output: `(async function* f() { });`},
|
|
{title: "FunctionExpression#6", input: `(function<T>(){})`, output: `(function <T>() { });`},
|
|
{title: "FunctionExpression#7", input: `(function(a){})`, output: `(function (a) { });`},
|
|
{title: "FunctionExpression#8", input: `(function():T{})`, output: `(function (): T { });`},
|
|
{title: "ArrowFunction#1", input: `a=>{}`, output: `a => { };`},
|
|
{title: "ArrowFunction#2", input: `()=>{}`, output: `() => { };`},
|
|
{title: "ArrowFunction#3", input: `(a)=>{}`, output: `(a) => { };`},
|
|
{title: "ArrowFunction#4", input: `<T>(a)=>{}`, output: `<T>(a) => { };`},
|
|
{title: "ArrowFunction#5", input: `async a=>{}`, output: `async a => { };`},
|
|
{title: "ArrowFunction#6", input: `async()=>{}`, output: `async () => { };`},
|
|
{title: "ArrowFunction#7", input: `async<T>()=>{}`, output: `async <T>() => { };`},
|
|
{title: "ArrowFunction#8", input: `():T=>{}`, output: `(): T => { };`},
|
|
{title: "ArrowFunction#9", input: `()=>a`, output: `() => a;`},
|
|
{title: "DeleteExpression", input: `delete a`, output: `delete a;`},
|
|
{title: "TypeOfExpression", input: `typeof a`, output: `typeof a;`},
|
|
{title: "VoidExpression", input: `void a`, output: `void a;`},
|
|
{title: "AwaitExpression", input: `await a`, output: `await a;`},
|
|
{title: "PrefixUnaryExpression#1", input: `+a`, output: `+a;`},
|
|
{title: "PrefixUnaryExpression#2", input: `++a`, output: `++a;`},
|
|
{title: "PrefixUnaryExpression#3", input: `+ +a`, output: `+ +a;`},
|
|
{title: "PrefixUnaryExpression#4", input: `+ ++a`, output: `+ ++a;`},
|
|
{title: "PrefixUnaryExpression#5", input: `-a`, output: `-a;`},
|
|
{title: "PrefixUnaryExpression#6", input: `--a`, output: `--a;`},
|
|
{title: "PrefixUnaryExpression#7", input: `- -a`, output: `- -a;`},
|
|
{title: "PrefixUnaryExpression#8", input: `- --a`, output: `- --a;`},
|
|
{title: "PrefixUnaryExpression#9", input: `+-a`, output: `+-a;`},
|
|
{title: "PrefixUnaryExpression#10", input: `+--a`, output: `+--a;`},
|
|
{title: "PrefixUnaryExpression#11", input: `-+a`, output: `-+a;`},
|
|
{title: "PrefixUnaryExpression#12", input: `-++a`, output: `-++a;`},
|
|
{title: "PrefixUnaryExpression#13", input: `~a`, output: `~a;`},
|
|
{title: "PrefixUnaryExpression#14", input: `!a`, output: `!a;`},
|
|
{title: "PostfixUnaryExpression#1", input: `a++`, output: `a++;`},
|
|
{title: "PostfixUnaryExpression#2", input: `a--`, output: `a--;`},
|
|
{title: "BinaryExpression#1", input: `a,b`, output: `a, b;`},
|
|
{title: "BinaryExpression#2", input: `a+b`, output: `a + b;`},
|
|
{title: "BinaryExpression#3", input: `a**b`, output: `a ** b;`},
|
|
{title: "BinaryExpression#4", input: `a instanceof b`, output: `a instanceof b;`},
|
|
{title: "BinaryExpression#5", input: `a in b`, output: `a in b;`},
|
|
{title: "BinaryExpression#6", input: "a\n&& b", output: "a\n && b;"},
|
|
{title: "BinaryExpression#7", input: "a &&\nb", output: "a &&\n b;"},
|
|
{title: "ConditionalExpression#1", input: `a?b:c`, output: `a ? b : c;`},
|
|
{title: "ConditionalExpression#2", input: "a\n?b:c", output: "a\n ? b : c;"},
|
|
{title: "ConditionalExpression#3", input: "a?\nb:c", output: "a ?\n b : c;"},
|
|
{title: "ConditionalExpression#4", input: "a?b\n:c", output: "a ? b\n : c;"},
|
|
{title: "ConditionalExpression#5", input: "a?b:\nc", output: "a ? b :\n c;"},
|
|
{title: "TemplateExpression#1", input: "`a${b}c`", output: "`a${b}c`;"},
|
|
{title: "TemplateExpression#2", input: "`a${b}c${d}e`", output: "`a${b}c${d}e`;"},
|
|
{title: "YieldExpression#1", input: `(function*() { yield })`, output: `(function* () { yield; });`},
|
|
{title: "YieldExpression#2", input: `(function*() { yield a })`, output: `(function* () { yield a; });`},
|
|
{title: "YieldExpression#3", input: `(function*() { yield*a })`, output: `(function* () { yield* a; });`},
|
|
{title: "SpreadElement", input: `[...a]`, output: `[...a];`},
|
|
{title: "ClassExpression#1", input: `(class {})`, output: "(class {\n});"},
|
|
{title: "ClassExpression#2", input: `(class a {})`, output: "(class a {\n});"},
|
|
{title: "ClassExpression#3", input: `(class<T>{})`, output: "(class<T> {\n});"},
|
|
{title: "ClassExpression#4", input: `(class a<T>{})`, output: "(class a<T> {\n});"},
|
|
{title: "ClassExpression#5", input: `(class extends b {})`, output: "(class extends b {\n});"},
|
|
{title: "ClassExpression#6", input: `(class a extends b {})`, output: "(class a extends b {\n});"},
|
|
{title: "ClassExpression#7", input: `(class implements b {})`, output: "(class implements b {\n});"},
|
|
{title: "ClassExpression#8", input: `(class a implements b {})`, output: "(class a implements b {\n});"},
|
|
{title: "ClassExpression#9", input: `(class implements b, c {})`, output: "(class implements b, c {\n});"},
|
|
{title: "ClassExpression#10", input: `(class a implements b, c {})`, output: "(class a implements b, c {\n});"},
|
|
{title: "ClassExpression#11", input: `(class extends b implements c, d {})`, output: "(class extends b implements c, d {\n});"},
|
|
{title: "ClassExpression#12", input: `(class a extends b implements c, d {})`, output: "(class a extends b implements c, d {\n});"},
|
|
{title: "ClassExpression#13", input: `(@a class {})`, output: "(\n@a\nclass {\n});"},
|
|
{title: "OmittedExpression", input: `[,]`, output: `[,];`},
|
|
{title: "ExpressionWithTypeArguments", input: `a<T>`, output: `a<T>;`},
|
|
{title: "AsExpression", input: `a as T`, output: `a as T;`},
|
|
{title: "SatisfiesExpression", input: `a satisfies T`, output: `a satisfies T;`},
|
|
{title: "NonNullExpression", input: `a!`, output: `a!;`},
|
|
{title: "MetaProperty#1", input: `new.target`, output: `new.target;`},
|
|
{title: "MetaProperty#2", input: `import.meta`, output: `import.meta;`},
|
|
{title: "ArrayLiteralExpression#1", input: `[]`, output: `[];`},
|
|
{title: "ArrayLiteralExpression#2", input: `[a]`, output: `[a];`},
|
|
{title: "ArrayLiteralExpression#3", input: `[a,]`, output: `[a,];`},
|
|
{title: "ArrayLiteralExpression#4", input: `[,a]`, output: `[, a];`},
|
|
{title: "ArrayLiteralExpression#5", input: `[...a]`, output: `[...a];`},
|
|
{title: "ObjectLiteralExpression#1", input: `({})`, output: `({});`},
|
|
{title: "ObjectLiteralExpression#2", input: `({a,})`, output: `({ a, });`},
|
|
{title: "ShorthandPropertyAssignment", input: `({a})`, output: `({ a });`},
|
|
{title: "PropertyAssignment", input: `({a:b})`, output: `({ a: b });`},
|
|
{title: "SpreadAssignment", input: `({...a})`, output: `({ ...a });`},
|
|
{title: "Block", input: `{}`, output: `{ }`},
|
|
{title: "VariableStatement#1", input: `var a`, output: `var a;`},
|
|
{title: "VariableStatement#2", input: `let a`, output: `let a;`},
|
|
{title: "VariableStatement#3", input: `const a = b`, output: `const a = b;`},
|
|
{title: "VariableStatement#4", input: `using a = b`, output: `using a = b;`},
|
|
{title: "VariableStatement#5", input: `await using a = b`, output: `await using a = b;`},
|
|
{title: "EmptyStatement", input: `;`, output: `;`},
|
|
{title: "IfStatement#1", input: `if(a);`, output: "if (a)\n ;"},
|
|
{title: "IfStatement#2", input: `if(a);else;`, output: "if (a)\n ;\nelse\n ;"},
|
|
{title: "IfStatement#3", input: `if(a);else{}`, output: "if (a)\n ;\nelse { }"},
|
|
{title: "IfStatement#4", input: `if(a);else if(b);`, output: "if (a)\n ;\nelse if (b)\n ;"},
|
|
{title: "IfStatement#5", input: `if(a);else if(b) {}`, output: "if (a)\n ;\nelse if (b) { }"},
|
|
{title: "IfStatement#6", input: `if(a) {}`, output: "if (a) { }"},
|
|
{title: "IfStatement#7", input: `if(a) {} else;`, output: "if (a) { }\nelse\n ;"},
|
|
{title: "IfStatement#8", input: `if(a) {} else {}`, output: "if (a) { }\nelse { }"},
|
|
{title: "IfStatement#9", input: `if(a) {} else if(b);`, output: "if (a) { }\nelse if (b)\n ;"},
|
|
{title: "IfStatement#10", input: `if(a) {} else if(b){}`, output: "if (a) { }\nelse if (b) { }"},
|
|
{title: "DoStatement#1", input: `do;while(a);`, output: "do\n ;\nwhile (a);"},
|
|
{title: "DoStatement#2", input: `do {} while(a);`, output: "do { } while (a);"},
|
|
{title: "WhileStatement#1", input: `while(a);`, output: "while (a)\n ;"},
|
|
{title: "WhileStatement#2", input: `while(a) {}`, output: "while (a) { }"},
|
|
{title: "ForStatement#1", input: `for(;;);`, output: "for (;;)\n ;"},
|
|
{title: "ForStatement#2", input: `for(a;;);`, output: "for (a;;)\n ;"},
|
|
{title: "ForStatement#3", input: `for(var a;;);`, output: "for (var a;;)\n ;"},
|
|
{title: "ForStatement#4", input: `for(;a;);`, output: "for (; a;)\n ;"},
|
|
{title: "ForStatement#5", input: `for(;;a);`, output: "for (;; a)\n ;"},
|
|
{title: "ForStatement#6", input: `for(;;){}`, output: "for (;;) { }"},
|
|
{title: "ForInStatement#1", input: `for(a in b);`, output: "for (a in b)\n ;"},
|
|
{title: "ForInStatement#2", input: `for(var a in b);`, output: "for (var a in b)\n ;"},
|
|
{title: "ForInStatement#3", input: `for(a in b){}`, output: "for (a in b) { }"},
|
|
{title: "ForOfStatement#1", input: `for(a of b);`, output: "for (a of b)\n ;"},
|
|
{title: "ForOfStatement#2", input: `for(var a of b);`, output: "for (var a of b)\n ;"},
|
|
{title: "ForOfStatement#3", input: `for(a of b){}`, output: "for (a of b) { }"},
|
|
{title: "ForOfStatement#4", input: `for await(a of b);`, output: "for await (a of b)\n ;"},
|
|
{title: "ForOfStatement#5", input: `for await(var a of b);`, output: "for await (var a of b)\n ;"},
|
|
{title: "ForOfStatement#6", input: `for await(a of b){}`, output: "for await (a of b) { }"},
|
|
{title: "ContinueStatement#1", input: `continue`, output: "continue;"},
|
|
{title: "ContinueStatement#2", input: `continue a`, output: "continue a;"},
|
|
{title: "BreakStatement#1", input: `break`, output: "break;"},
|
|
{title: "BreakStatement#2", input: `break a`, output: "break a;"},
|
|
{title: "ReturnStatement#1", input: `return`, output: "return;"},
|
|
{title: "ReturnStatement#2", input: `return a`, output: "return a;"},
|
|
{title: "WithStatement#1", input: `with(a);`, output: "with (a)\n ;"},
|
|
{title: "WithStatement#2", input: `with(a){}`, output: "with (a) { }"},
|
|
{title: "SwitchStatement", input: `switch (a) {}`, output: "switch (a) {\n}"},
|
|
{title: "CaseClause#1", input: `switch (a) {case b:}`, output: "switch (a) {\n case b:\n}"},
|
|
{title: "CaseClause#2", input: `switch (a) {case b:;}`, output: "switch (a) {\n case b: ;\n}"},
|
|
{title: "DefaultClause#1", input: `switch (a) {default:}`, output: "switch (a) {\n default:\n}"},
|
|
{title: "DefaultClause#2", input: `switch (a) {default:;}`, output: "switch (a) {\n default: ;\n}"},
|
|
{title: "LabeledStatement", input: `a:;`, output: "a: ;"},
|
|
{title: "ThrowStatement", input: `throw a`, output: "throw a;"},
|
|
{title: "TryStatement#1", input: `try {} catch {}`, output: "try { }\ncatch { }"},
|
|
{title: "TryStatement#2", input: `try {} finally {}`, output: "try { }\nfinally { }"},
|
|
{title: "TryStatement#3", input: `try {} catch {} finally {}`, output: "try { }\ncatch { }\nfinally { }"},
|
|
{title: "DebuggerStatement", input: `debugger`, output: "debugger;"},
|
|
{title: "FunctionDeclaration#1", input: `export default function(){}`, output: `export default function () { }`},
|
|
{title: "FunctionDeclaration#2", input: `function f(){}`, output: `function f() { }`},
|
|
{title: "FunctionDeclaration#3", input: `function*f(){}`, output: `function* f() { }`},
|
|
{title: "FunctionDeclaration#4", input: `async function f(){}`, output: `async function f() { }`},
|
|
{title: "FunctionDeclaration#5", input: `async function*f(){}`, output: `async function* f() { }`},
|
|
{title: "FunctionDeclaration#6", input: `function f<T>(){}`, output: `function f<T>() { }`},
|
|
{title: "FunctionDeclaration#7", input: `function f(a){}`, output: `function f(a) { }`},
|
|
{title: "FunctionDeclaration#8", input: `function f():T{}`, output: `function f(): T { }`},
|
|
{title: "FunctionDeclaration#9", input: `function f();`, output: `function f();`},
|
|
{title: "ClassDeclaration#1", input: `class a {}`, output: "class a {\n}"},
|
|
{title: "ClassDeclaration#2", input: `class a<T>{}`, output: "class a<T> {\n}"},
|
|
{title: "ClassDeclaration#3", input: `class a extends b {}`, output: "class a extends b {\n}"},
|
|
{title: "ClassDeclaration#4", input: `class a implements b {}`, output: "class a implements b {\n}"},
|
|
{title: "ClassDeclaration#5", input: `class a implements b, c {}`, output: "class a implements b, c {\n}"},
|
|
{title: "ClassDeclaration#6", input: `class a extends b implements c, d {}`, output: "class a extends b implements c, d {\n}"},
|
|
{title: "ClassDeclaration#7", input: `export default class {}`, output: "export default class {\n}"},
|
|
{title: "ClassDeclaration#8", input: `export default class<T>{}`, output: "export default class<T> {\n}"},
|
|
{title: "ClassDeclaration#9", input: `export default class extends b {}`, output: "export default class extends b {\n}"},
|
|
{title: "ClassDeclaration#10", input: `export default class implements b {}`, output: "export default class implements b {\n}"},
|
|
{title: "ClassDeclaration#11", input: `export default class implements b, c {}`, output: "export default class implements b, c {\n}"},
|
|
{title: "ClassDeclaration#12", input: `export default class extends b implements c, d {}`, output: "export default class extends b implements c, d {\n}"},
|
|
{title: "ClassDeclaration#13", input: `@a class b {}`, output: "@a\nclass b {\n}"},
|
|
{title: "ClassDeclaration#14", input: `@a export class b {}`, output: "@a\nexport class b {\n}"},
|
|
{title: "ClassDeclaration#15", input: `export @a class b {}`, output: "export \n@a\nclass b {\n}"},
|
|
{title: "InterfaceDeclaration#1", input: `interface a {}`, output: "interface a {\n}"},
|
|
{title: "InterfaceDeclaration#2", input: `interface a<T>{}`, output: "interface a<T> {\n}"},
|
|
{title: "InterfaceDeclaration#3", input: `interface a extends b {}`, output: "interface a extends b {\n}"},
|
|
{title: "InterfaceDeclaration#4", input: `interface a extends b, c {}`, output: "interface a extends b, c {\n}"},
|
|
{title: "TypeAliasDeclaration#1", input: `type a = b`, output: "type a = b;"},
|
|
{title: "TypeAliasDeclaration#2", input: `type a<T> = b`, output: "type a<T> = b;"},
|
|
{title: "EnumDeclaration#1", input: `enum a{}`, output: "enum a {\n}"},
|
|
{title: "EnumDeclaration#2", input: `enum a{b}`, output: "enum a {\n b\n}"},
|
|
{title: "EnumDeclaration#3", input: `enum a{b=c}`, output: "enum a {\n b = c\n}"},
|
|
{title: "ModuleDeclaration#1", input: `module a{}`, output: "module a { }"},
|
|
{title: "ModuleDeclaration#2", input: `module a.b{}`, output: "module a.b { }"},
|
|
{title: "ModuleDeclaration#3", input: `module "a";`, output: "module \"a\";"},
|
|
{title: "ModuleDeclaration#4", input: `module "a"{}`, output: "module \"a\" { }"},
|
|
{title: "ModuleDeclaration#5", input: `namespace a{}`, output: "namespace a { }"},
|
|
{title: "ModuleDeclaration#6", input: `namespace a.b{}`, output: "namespace a.b { }"},
|
|
{title: "ModuleDeclaration#7", input: `global;`, output: "global;"},
|
|
{title: "ModuleDeclaration#8", input: `global{}`, output: "global { }"},
|
|
{title: "ImportEqualsDeclaration#1", input: `import a = b`, output: "import a = b;"},
|
|
{title: "ImportEqualsDeclaration#2", input: `import a = b.c`, output: "import a = b.c;"},
|
|
{title: "ImportEqualsDeclaration#3", input: `import a = require("b")`, output: "import a = require(\"b\");"},
|
|
{title: "ImportEqualsDeclaration#4", input: `export import a = b`, output: "export import a = b;"},
|
|
{title: "ImportEqualsDeclaration#5", input: `export import a = require("b")`, output: "export import a = require(\"b\");"},
|
|
{title: "ImportEqualsDeclaration#6", input: `import type a = b`, output: "import type a = b;"},
|
|
{title: "ImportEqualsDeclaration#7", input: `import type a = b.c`, output: "import type a = b.c;"},
|
|
{title: "ImportEqualsDeclaration#8", input: `import type a = require("b")`, output: "import type a = require(\"b\");"},
|
|
{title: "ImportDeclaration#1", input: `import "a"`, output: "import \"a\";"},
|
|
{title: "ImportDeclaration#2", input: `import a from "b"`, output: "import a from \"b\";"},
|
|
{title: "ImportDeclaration#3", input: `import type a from "b"`, output: "import type a from \"b\";"},
|
|
{title: "ImportDeclaration#4", input: `import * as a from "b"`, output: "import * as a from \"b\";"},
|
|
{title: "ImportDeclaration#5", input: `import type * as a from "b"`, output: "import type * as a from \"b\";"},
|
|
{title: "ImportDeclaration#6", input: `import {} from "b"`, output: "import {} from \"b\";"},
|
|
{title: "ImportDeclaration#7", input: `import type {} from "b"`, output: "import type {} from \"b\";"},
|
|
{title: "ImportDeclaration#8", input: `import { a } from "b"`, output: "import { a } from \"b\";"},
|
|
{title: "ImportDeclaration#9", input: `import type { a } from "b"`, output: "import type { a } from \"b\";"},
|
|
{title: "ImportDeclaration#8", input: `import { a as b } from "c"`, output: "import { a as b } from \"c\";"},
|
|
{title: "ImportDeclaration#9", input: `import type { a as b } from "c"`, output: "import type { a as b } from \"c\";"},
|
|
{title: "ImportDeclaration#10", input: `import { "a" as b } from "c"`, output: "import { \"a\" as b } from \"c\";"},
|
|
{title: "ImportDeclaration#11", input: `import type { "a" as b } from "c"`, output: "import type { \"a\" as b } from \"c\";"},
|
|
{title: "ImportDeclaration#12", input: `import a, {} from "b"`, output: "import a, {} from \"b\";"},
|
|
{title: "ImportDeclaration#13", input: `import a, * as b from "c"`, output: "import a, * as b from \"c\";"},
|
|
{title: "ImportDeclaration#14", input: `import {} from "a" with {}`, output: "import {} from \"a\" with {};"},
|
|
{title: "ImportDeclaration#15", input: `import {} from "a" with { b: "c" }`, output: "import {} from \"a\" with { b: \"c\" };"},
|
|
{title: "ImportDeclaration#16", input: `import {} from "a" with { "b": "c" }`, output: "import {} from \"a\" with { \"b\": \"c\" };"},
|
|
{title: "ExportAssignment#1", input: `export = a`, output: "export = a;"},
|
|
{title: "ExportAssignment#2", input: `export default a`, output: "export default a;"},
|
|
{title: "NamespaceExportDeclaration", input: `export as namespace a`, output: "export as namespace a;"},
|
|
{title: "ExportDeclaration#1", input: `export * from "a"`, output: "export * from \"a\";"},
|
|
{title: "ExportDeclaration#2", input: `export type * from "a"`, output: "export type * from \"a\";"},
|
|
{title: "ExportDeclaration#3", input: `export * as a from "b"`, output: "export * as a from \"b\";"},
|
|
{title: "ExportDeclaration#4", input: `export type * as a from "b"`, output: "export type * as a from \"b\";"},
|
|
{title: "ExportDeclaration#5", input: `export { } from "a"`, output: "export {} from \"a\";"},
|
|
{title: "ExportDeclaration#6", input: `export type { } from "a"`, output: "export type {} from \"a\";"},
|
|
{title: "ExportDeclaration#7", input: `export { a } from "b"`, output: "export { a } from \"b\";"},
|
|
{title: "ExportDeclaration#8", input: `export { type a } from "b"`, output: "export { type a } from \"b\";"},
|
|
{title: "ExportDeclaration#9", input: `export type { a } from "b"`, output: "export type { a } from \"b\";"},
|
|
{title: "ExportDeclaration#10", input: `export { a as b } from "c"`, output: "export { a as b } from \"c\";"},
|
|
{title: "ExportDeclaration#11", input: `export { type a as b } from "c"`, output: "export { type a as b } from \"c\";"},
|
|
{title: "ExportDeclaration#12", input: `export type { a as b } from "c"`, output: "export type { a as b } from \"c\";"},
|
|
{title: "ExportDeclaration#13", input: `export { a as "b" } from "c"`, output: "export { a as \"b\" } from \"c\";"},
|
|
{title: "ExportDeclaration#14", input: `export { type a as "b" } from "c"`, output: "export { type a as \"b\" } from \"c\";"},
|
|
{title: "ExportDeclaration#15", input: `export type { a as "b" } from "c"`, output: "export type { a as \"b\" } from \"c\";"},
|
|
{title: "ExportDeclaration#16", input: `export { "a" } from "b"`, output: "export { \"a\" } from \"b\";"},
|
|
{title: "ExportDeclaration#17", input: `export { type "a" } from "b"`, output: "export { type \"a\" } from \"b\";"},
|
|
{title: "ExportDeclaration#18", input: `export type { "a" } from "b"`, output: "export type { \"a\" } from \"b\";"},
|
|
{title: "ExportDeclaration#19", input: `export { "a" as b } from "c"`, output: "export { \"a\" as b } from \"c\";"},
|
|
{title: "ExportDeclaration#20", input: `export { type "a" as b } from "c"`, output: "export { type \"a\" as b } from \"c\";"},
|
|
{title: "ExportDeclaration#21", input: `export type { "a" as b } from "c"`, output: "export type { \"a\" as b } from \"c\";"},
|
|
{title: "ExportDeclaration#22", input: `export { "a" as "b" } from "c"`, output: "export { \"a\" as \"b\" } from \"c\";"},
|
|
{title: "ExportDeclaration#23", input: `export { type "a" as "b" } from "c"`, output: "export { type \"a\" as \"b\" } from \"c\";"},
|
|
{title: "ExportDeclaration#24", input: `export type { "a" as "b" } from "c"`, output: "export type { \"a\" as \"b\" } from \"c\";"},
|
|
{title: "ExportDeclaration#25", input: `export { }`, output: "export {};"},
|
|
{title: "ExportDeclaration#26", input: `export type { }`, output: "export type {};"},
|
|
{title: "ExportDeclaration#27", input: `export { a }`, output: "export { a };"},
|
|
{title: "ExportDeclaration#28", input: `export { type a }`, output: "export { type a };"},
|
|
{title: "ExportDeclaration#29", input: `export type { a }`, output: "export type { a };"},
|
|
{title: "ExportDeclaration#30", input: `export { a as b }`, output: "export { a as b };"},
|
|
{title: "ExportDeclaration#31", input: `export { type a as b }`, output: "export { type a as b };"},
|
|
{title: "ExportDeclaration#32", input: `export type { a as b }`, output: "export type { a as b };"},
|
|
{title: "ExportDeclaration#33", input: `export { a as "b" }`, output: "export { a as \"b\" };"},
|
|
{title: "ExportDeclaration#34", input: `export { type a as "b" }`, output: "export { type a as \"b\" };"},
|
|
{title: "ExportDeclaration#35", input: `export type { a as "b" }`, output: "export type { a as \"b\" };"},
|
|
{title: "ExportDeclaration#36", input: `export {} from "a" with {}`, output: "export {} from \"a\" with {};"},
|
|
{title: "ExportDeclaration#37", input: `export {} from "a" with { b: "c" }`, output: "export {} from \"a\" with { b: \"c\" };"},
|
|
{title: "ExportDeclaration#38", input: `export {} from "a" with { "b": "c" }`, output: "export {} from \"a\" with { \"b\": \"c\" };"},
|
|
{title: "KeywordTypeNode#1", input: `type T = any`, output: `type T = any;`},
|
|
{title: "KeywordTypeNode#2", input: `type T = unknown`, output: `type T = unknown;`},
|
|
{title: "KeywordTypeNode#3", input: `type T = never`, output: `type T = never;`},
|
|
{title: "KeywordTypeNode#4", input: `type T = void`, output: `type T = void;`},
|
|
{title: "KeywordTypeNode#5", input: `type T = undefined`, output: `type T = undefined;`},
|
|
{title: "KeywordTypeNode#6", input: `type T = null`, output: `type T = null;`},
|
|
{title: "KeywordTypeNode#7", input: `type T = object`, output: `type T = object;`},
|
|
{title: "KeywordTypeNode#8", input: `type T = string`, output: `type T = string;`},
|
|
{title: "KeywordTypeNode#9", input: `type T = symbol`, output: `type T = symbol;`},
|
|
{title: "KeywordTypeNode#10", input: `type T = number`, output: `type T = number;`},
|
|
{title: "KeywordTypeNode#11", input: `type T = bigint`, output: `type T = bigint;`},
|
|
{title: "KeywordTypeNode#12", input: `type T = boolean`, output: `type T = boolean;`},
|
|
{title: "KeywordTypeNode#13", input: `type T = intrinsic`, output: `type T = intrinsic;`},
|
|
{title: "TypePredicateNode#1", input: `function f(): asserts a`, output: `function f(): asserts a;`},
|
|
{title: "TypePredicateNode#2", input: `function f(): asserts a is b`, output: `function f(): asserts a is b;`},
|
|
{title: "TypePredicateNode#3", input: `function f(): asserts this`, output: `function f(): asserts this;`},
|
|
{title: "TypePredicateNode#4", input: `function f(): asserts this is b`, output: `function f(): asserts this is b;`},
|
|
{title: "TypeReferenceNode#1", input: `type T = a`, output: `type T = a;`},
|
|
{title: "TypeReferenceNode#2", input: `type T = a.b`, output: `type T = a.b;`},
|
|
{title: "TypeReferenceNode#3", input: `type T = a<U>`, output: `type T = a<U>;`},
|
|
{title: "TypeReferenceNode#4", input: `type T = a.b<U>`, output: `type T = a.b<U>;`},
|
|
{title: "FunctionTypeNode#1", input: `type T = () => a`, output: `type T = () => a;`},
|
|
{title: "FunctionTypeNode#2", input: `type T = <T>() => a`, output: `type T = <T>() => a;`},
|
|
{title: "FunctionTypeNode#3", input: `type T = (a) => b`, output: `type T = (a) => b;`},
|
|
{title: "ConstructorTypeNode#1", input: `type T = new () => a`, output: `type T = new () => a;`},
|
|
{title: "ConstructorTypeNode#2", input: `type T = new <T>() => a`, output: `type T = new <T>() => a;`},
|
|
{title: "ConstructorTypeNode#3", input: `type T = new (a) => b`, output: `type T = new (a) => b;`},
|
|
{title: "ConstructorTypeNode#4", input: `type T = abstract new () => a`, output: `type T = abstract new () => a;`},
|
|
{title: "TypeQueryNode#1", input: `type T = typeof a`, output: `type T = typeof a;`},
|
|
{title: "TypeQueryNode#2", input: `type T = typeof a.b`, output: `type T = typeof a.b;`},
|
|
{title: "TypeQueryNode#3", input: `type T = typeof a<U>`, output: `type T = typeof a<U>;`},
|
|
{title: "TypeLiteralNode#1", input: `type T = {}`, output: `type T = {};`},
|
|
{title: "TypeLiteralNode#2", input: `type T = {a}`, output: "type T = {\n a;\n};"},
|
|
{title: "ArrayTypeNode", input: `type T = a[]`, output: "type T = a[];"},
|
|
{title: "TupleTypeNode#1", input: `type T = []`, output: "type T = [\n];"},
|
|
{title: "TupleTypeNode#2", input: `type T = [a]`, output: "type T = [\n a\n];"},
|
|
{title: "TupleTypeNode#3", input: `type T = [a,]`, output: "type T = [\n a\n];"},
|
|
{title: "RestTypeNode", input: `type T = [...a]`, output: "type T = [\n ...a\n];"},
|
|
{title: "OptionalTypeNode", input: `type T = [a?]`, output: "type T = [\n a?\n];"},
|
|
{title: "NamedTupleMember#1", input: `type T = [a: b]`, output: "type T = [\n a: b\n];"},
|
|
{title: "NamedTupleMember#2", input: `type T = [a?: b]`, output: "type T = [\n a?: b\n];"},
|
|
{title: "NamedTupleMember#3", input: `type T = [...a: b]`, output: "type T = [\n ...a: b\n];"},
|
|
{title: "UnionTypeNode#1", input: `type T = a | b`, output: "type T = a | b;"},
|
|
{title: "UnionTypeNode#2", input: `type T = a | b | c`, output: "type T = a | b | c;"},
|
|
{title: "UnionTypeNode#3", input: `type T = | a | b`, output: "type T = a | b;"},
|
|
{title: "IntersectionTypeNode#1", input: `type T = a & b`, output: "type T = a & b;"},
|
|
{title: "IntersectionTypeNode#2", input: `type T = a & b & c`, output: "type T = a & b & c;"},
|
|
{title: "IntersectionTypeNode#3", input: `type T = & a & b`, output: "type T = a & b;"},
|
|
{title: "ConditionalTypeNode", input: `type T = a extends b ? c : d`, output: "type T = a extends b ? c : d;"},
|
|
{title: "InferTypeNode#1", input: `type T = a extends infer b ? c : d`, output: "type T = a extends infer b ? c : d;"},
|
|
{title: "InferTypeNode#2", input: `type T = a extends infer b extends c ? d : e`, output: "type T = a extends infer b extends c ? d : e;"},
|
|
{title: "ParenthesizedTypeNode", input: `type T = (U)`, output: "type T = (U);"},
|
|
{title: "ThisTypeNode", input: `type T = this`, output: "type T = this;"},
|
|
{title: "TypeOperatorNode#1", input: `type T = keyof U`, output: "type T = keyof U;"},
|
|
{title: "TypeOperatorNode#2", input: `type T = readonly U[]`, output: "type T = readonly U[];"},
|
|
{title: "TypeOperatorNode#3", input: `type T = unique symbol`, output: "type T = unique symbol;"},
|
|
{title: "IndexedAccessTypeNode", input: `type T = a[b]`, output: "type T = a[b];"},
|
|
{title: "MappedTypeNode#1", input: `type T = { [a in b]: c }`, output: "type T = {\n [a in b]: c;\n};"},
|
|
{title: "MappedTypeNode#2", input: `type T = { [a in b as c]: d }`, output: "type T = {\n [a in b as c]: d;\n};"},
|
|
{title: "MappedTypeNode#3", input: `type T = { readonly [a in b]: c }`, output: "type T = {\n readonly [a in b]: c;\n};"},
|
|
{title: "MappedTypeNode#4", input: `type T = { +readonly [a in b]: c }`, output: "type T = {\n +readonly [a in b]: c;\n};"},
|
|
{title: "MappedTypeNode#5", input: `type T = { -readonly [a in b]: c }`, output: "type T = {\n -readonly [a in b]: c;\n};"},
|
|
{title: "MappedTypeNode#6", input: `type T = { [a in b]?: c }`, output: "type T = {\n [a in b]?: c;\n};"},
|
|
{title: "MappedTypeNode#7", input: `type T = { [a in b]+?: c }`, output: "type T = {\n [a in b]+?: c;\n};"},
|
|
{title: "MappedTypeNode#8", input: `type T = { [a in b]-?: c }`, output: "type T = {\n [a in b]-?: c;\n};"},
|
|
{title: "MappedTypeNode#9", input: `type T = { [a in b]: c; d }`, output: "type T = {\n [a in b]: c;\n d;\n};"},
|
|
{title: "LiteralTypeNode#1", input: `type T = null`, output: "type T = null;"},
|
|
{title: "LiteralTypeNode#2", input: `type T = true`, output: "type T = true;"},
|
|
{title: "LiteralTypeNode#3", input: `type T = false`, output: "type T = false;"},
|
|
{title: "LiteralTypeNode#4", input: `type T = ""`, output: "type T = \"\";"},
|
|
{title: "LiteralTypeNode#5", input: "type T = ''", output: "type T = '';"},
|
|
{title: "LiteralTypeNode#6", input: "type T = ``", output: "type T = ``;"},
|
|
{title: "LiteralTypeNode#7", input: `type T = 0`, output: "type T = 0;"},
|
|
{title: "LiteralTypeNode#8", input: `type T = 0n`, output: "type T = 0n;"},
|
|
{title: "LiteralTypeNode#9", input: `type T = -0`, output: "type T = -0;"},
|
|
{title: "LiteralTypeNode#10", input: `type T = -0n`, output: "type T = -0n;"},
|
|
{title: "TemplateTypeNode#1", input: "type T = `a${b}c`", output: "type T = `a${b}c`;"},
|
|
{title: "TemplateTypeNode#2", input: "type T = `a${b}c${d}e`", output: "type T = `a${b}c${d}e`;"},
|
|
{title: "ImportTypeNode#1", input: `type T = import(a)`, output: "type T = import(a);"},
|
|
{title: "ImportTypeNode#2", input: `type T = import(a).b`, output: "type T = import(a).b;"},
|
|
{title: "ImportTypeNode#3", input: `type T = import(a).b<U>`, output: "type T = import(a).b<U>;"},
|
|
{title: "ImportTypeNode#4", input: `type T = typeof import(a)`, output: "type T = typeof import(a);"},
|
|
{title: "ImportTypeNode#5", input: `type T = typeof import(a).b`, output: "type T = typeof import(a).b;"},
|
|
{title: "ImportTypeNode#6", input: `type T = import(a, { with: { } })`, output: "type T = import(a, { with: {} });"},
|
|
{title: "ImportTypeNode#6", input: `type T = import(a, { with: { b: "c" } })`, output: "type T = import(a, { with: { b: \"c\" } });"},
|
|
{title: "ImportTypeNode#7", input: `type T = import(a, { with: { "b": "c" } })`, output: "type T = import(a, { with: { \"b\": \"c\" } });"},
|
|
{title: "PropertySignature#1", input: "interface I {a}", output: "interface I {\n a;\n}"},
|
|
{title: "PropertySignature#2", input: "interface I {readonly a}", output: "interface I {\n readonly a;\n}"},
|
|
{title: "PropertySignature#3", input: "interface I {\"a\"}", output: "interface I {\n \"a\";\n}"},
|
|
{title: "PropertySignature#4", input: "interface I {'a'}", output: "interface I {\n 'a';\n}"},
|
|
{title: "PropertySignature#5", input: "interface I {0}", output: "interface I {\n 0;\n}"},
|
|
{title: "PropertySignature#6", input: "interface I {0n}", output: "interface I {\n 0n;\n}"},
|
|
{title: "PropertySignature#7", input: "interface I {[a]}", output: "interface I {\n [a];\n}"},
|
|
{title: "PropertySignature#8", input: "interface I {a?}", output: "interface I {\n a?;\n}"},
|
|
{title: "PropertySignature#9", input: "interface I {a: b}", output: "interface I {\n a: b;\n}"},
|
|
{title: "MethodSignature#1", input: "interface I {a()}", output: "interface I {\n a();\n}"},
|
|
{title: "MethodSignature#2", input: "interface I {\"a\"()}", output: "interface I {\n \"a\"();\n}"},
|
|
{title: "MethodSignature#3", input: "interface I {'a'()}", output: "interface I {\n 'a'();\n}"},
|
|
{title: "MethodSignature#4", input: "interface I {0()}", output: "interface I {\n 0();\n}"},
|
|
{title: "MethodSignature#5", input: "interface I {0n()}", output: "interface I {\n 0n();\n}"},
|
|
{title: "MethodSignature#6", input: "interface I {[a]()}", output: "interface I {\n [a]();\n}"},
|
|
{title: "MethodSignature#7", input: "interface I {a?()}", output: "interface I {\n a?();\n}"},
|
|
{title: "MethodSignature#8", input: "interface I {a<T>()}", output: "interface I {\n a<T>();\n}"},
|
|
{title: "MethodSignature#9", input: "interface I {a(): b}", output: "interface I {\n a(): b;\n}"},
|
|
{title: "MethodSignature#10", input: "interface I {a(b): c}", output: "interface I {\n a(b): c;\n}"},
|
|
{title: "CallSignature#1", input: "interface I {()}", output: "interface I {\n ();\n}"},
|
|
{title: "CallSignature#2", input: "interface I {():a}", output: "interface I {\n (): a;\n}"},
|
|
{title: "CallSignature#3", input: "interface I {(p)}", output: "interface I {\n (p);\n}"},
|
|
{title: "CallSignature#4", input: "interface I {<T>()}", output: "interface I {\n <T>();\n}"},
|
|
{title: "ConstructSignature#1", input: "interface I {new ()}", output: "interface I {\n new ();\n}"},
|
|
{title: "ConstructSignature#2", input: "interface I {new ():a}", output: "interface I {\n new (): a;\n}"},
|
|
{title: "ConstructSignature#3", input: "interface I {new (p)}", output: "interface I {\n new (p);\n}"},
|
|
{title: "ConstructSignature#4", input: "interface I {new <T>()}", output: "interface I {\n new <T>();\n}"},
|
|
{title: "IndexSignatureDeclaration#1", input: "interface I {[a]}", output: "interface I {\n [a];\n}"},
|
|
{title: "IndexSignatureDeclaration#2", input: "interface I {[a: b]}", output: "interface I {\n [a: b];\n}"},
|
|
{title: "IndexSignatureDeclaration#3", input: "interface I {[a: b]: c}", output: "interface I {\n [a: b]: c;\n}"},
|
|
{title: "PropertyDeclaration#1", input: "class C {a}", output: "class C {\n a;\n}"},
|
|
{title: "PropertyDeclaration#2", input: "class C {readonly a}", output: "class C {\n readonly a;\n}"},
|
|
{title: "PropertyDeclaration#3", input: "class C {static a}", output: "class C {\n static a;\n}"},
|
|
{title: "PropertyDeclaration#4", input: "class C {accessor a}", output: "class C {\n accessor a;\n}"},
|
|
{title: "PropertyDeclaration#5", input: "class C {\"a\"}", output: "class C {\n \"a\";\n}"},
|
|
{title: "PropertyDeclaration#6", input: "class C {'a'}", output: "class C {\n 'a';\n}"},
|
|
{title: "PropertyDeclaration#7", input: "class C {0}", output: "class C {\n 0;\n}"},
|
|
{title: "PropertyDeclaration#8", input: "class C {0n}", output: "class C {\n 0n;\n}"},
|
|
{title: "PropertyDeclaration#9", input: "class C {[a]}", output: "class C {\n [a];\n}"},
|
|
{title: "PropertyDeclaration#10", input: "class C {#a}", output: "class C {\n #a;\n}"},
|
|
{title: "PropertyDeclaration#11", input: "class C {a?}", output: "class C {\n a?;\n}"},
|
|
{title: "PropertyDeclaration#12", input: "class C {a!}", output: "class C {\n a!;\n}"},
|
|
{title: "PropertyDeclaration#13", input: "class C {a: b}", output: "class C {\n a: b;\n}"},
|
|
{title: "PropertyDeclaration#14", input: "class C {a = b}", output: "class C {\n a = b;\n}"},
|
|
{title: "PropertyDeclaration#15", input: "class C {@a b}", output: "class C {\n @a\n b;\n}"},
|
|
{title: "MethodDeclaration#1", input: "class C {a()}", output: "class C {\n a();\n}"},
|
|
{title: "MethodDeclaration#2", input: "class C {\"a\"()}", output: "class C {\n \"a\"();\n}"},
|
|
{title: "MethodDeclaration#3", input: "class C {'a'()}", output: "class C {\n 'a'();\n}"},
|
|
{title: "MethodDeclaration#4", input: "class C {0()}", output: "class C {\n 0();\n}"},
|
|
{title: "MethodDeclaration#5", input: "class C {0n()}", output: "class C {\n 0n();\n}"},
|
|
{title: "MethodDeclaration#6", input: "class C {[a]()}", output: "class C {\n [a]();\n}"},
|
|
{title: "MethodDeclaration#7", input: "class C {#a()}", output: "class C {\n #a();\n}"},
|
|
{title: "MethodDeclaration#8", input: "class C {a?()}", output: "class C {\n a?();\n}"},
|
|
{title: "MethodDeclaration#9", input: "class C {a<T>()}", output: "class C {\n a<T>();\n}"},
|
|
{title: "MethodDeclaration#10", input: "class C {a(): b}", output: "class C {\n a(): b;\n}"},
|
|
{title: "MethodDeclaration#11", input: "class C {a(b): c}", output: "class C {\n a(b): c;\n}"},
|
|
{title: "MethodDeclaration#12", input: "class C {a() {} }", output: "class C {\n a() { }\n}"},
|
|
{title: "MethodDeclaration#13", input: "class C {@a b() {} }", output: "class C {\n @a\n b() { }\n}"},
|
|
{title: "MethodDeclaration#14", input: "class C {static a() {} }", output: "class C {\n static a() { }\n}"},
|
|
{title: "MethodDeclaration#15", input: "class C {async a() {} }", output: "class C {\n async a() { }\n}"},
|
|
{title: "GetAccessorDeclaration#1", input: "class C {get a()}", output: "class C {\n get a();\n}"},
|
|
{title: "GetAccessorDeclaration#2", input: "class C {get \"a\"()}", output: "class C {\n get \"a\"();\n}"},
|
|
{title: "GetAccessorDeclaration#3", input: "class C {get 'a'()}", output: "class C {\n get 'a'();\n}"},
|
|
{title: "GetAccessorDeclaration#4", input: "class C {get 0()}", output: "class C {\n get 0();\n}"},
|
|
{title: "GetAccessorDeclaration#5", input: "class C {get 0n()}", output: "class C {\n get 0n();\n}"},
|
|
{title: "GetAccessorDeclaration#6", input: "class C {get [a]()}", output: "class C {\n get [a]();\n}"},
|
|
{title: "GetAccessorDeclaration#7", input: "class C {get #a()}", output: "class C {\n get #a();\n}"},
|
|
{title: "GetAccessorDeclaration#8", input: "class C {get a(): b}", output: "class C {\n get a(): b;\n}"},
|
|
{title: "GetAccessorDeclaration#9", input: "class C {get a(b): c}", output: "class C {\n get a(b): c;\n}"},
|
|
{title: "GetAccessorDeclaration#10", input: "class C {get a() {} }", output: "class C {\n get a() { }\n}"},
|
|
{title: "GetAccessorDeclaration#11", input: "class C {@a get b() {} }", output: "class C {\n @a\n get b() { }\n}"},
|
|
{title: "GetAccessorDeclaration#12", input: "class C {static get a() {} }", output: "class C {\n static get a() { }\n}"},
|
|
{title: "SetAccessorDeclaration#1", input: "class C {set a()}", output: "class C {\n set a();\n}"},
|
|
{title: "SetAccessorDeclaration#2", input: "class C {set \"a\"()}", output: "class C {\n set \"a\"();\n}"},
|
|
{title: "SetAccessorDeclaration#3", input: "class C {set 'a'()}", output: "class C {\n set 'a'();\n}"},
|
|
{title: "SetAccessorDeclaration#4", input: "class C {set 0()}", output: "class C {\n set 0();\n}"},
|
|
{title: "SetAccessorDeclaration#5", input: "class C {set 0n()}", output: "class C {\n set 0n();\n}"},
|
|
{title: "SetAccessorDeclaration#6", input: "class C {set [a]()}", output: "class C {\n set [a]();\n}"},
|
|
{title: "SetAccessorDeclaration#7", input: "class C {set #a()}", output: "class C {\n set #a();\n}"},
|
|
{title: "SetAccessorDeclaration#8", input: "class C {set a(): b}", output: "class C {\n set a(): b;\n}"},
|
|
{title: "SetAccessorDeclaration#9", input: "class C {set a(b): c}", output: "class C {\n set a(b): c;\n}"},
|
|
{title: "SetAccessorDeclaration#10", input: "class C {set a() {} }", output: "class C {\n set a() { }\n}"},
|
|
{title: "SetAccessorDeclaration#11", input: "class C {@a set b() {} }", output: "class C {\n @a\n set b() { }\n}"},
|
|
{title: "SetAccessorDeclaration#12", input: "class C {static set a() {} }", output: "class C {\n static set a() { }\n}"},
|
|
{title: "ConstructorDeclaration#1", input: "class C {constructor()}", output: "class C {\n constructor();\n}"},
|
|
{title: "ConstructorDeclaration#2", input: "class C {constructor(): b}", output: "class C {\n constructor(): b;\n}"},
|
|
{title: "ConstructorDeclaration#3", input: "class C {constructor(b): c}", output: "class C {\n constructor(b): c;\n}"},
|
|
{title: "ConstructorDeclaration#4", input: "class C {constructor() {} }", output: "class C {\n constructor() { }\n}"},
|
|
{title: "ConstructorDeclaration#5", input: "class C {@a constructor() {} }", output: "class C {\n constructor() { }\n}"},
|
|
{title: "ConstructorDeclaration#6", input: "class C {private constructor() {} }", output: "class C {\n private constructor() { }\n}"},
|
|
{title: "ClassStaticBlockDeclaration", input: "class C {static { }}", output: "class C {\n static { }\n}"},
|
|
{title: "SemicolonClassElement#1", input: "class C {;}", output: "class C {\n ;\n}"},
|
|
{title: "ParameterDeclaration#1", input: "function f(a)", output: "function f(a);"},
|
|
{title: "ParameterDeclaration#2", input: "function f(a: b)", output: "function f(a: b);"},
|
|
{title: "ParameterDeclaration#3", input: "function f(a = b)", output: "function f(a = b);"},
|
|
{title: "ParameterDeclaration#4", input: "function f(a?)", output: "function f(a?);"},
|
|
{title: "ParameterDeclaration#5", input: "function f(...a)", output: "function f(...a);"},
|
|
{title: "ParameterDeclaration#6", input: "function f(this)", output: "function f(this);"},
|
|
// {title: "ParameterDeclaration#7", input: "function f(a,)", output: "function f(a,);"}, // TODO: preserve trailing comma after Strada migration
|
|
{title: "ObjectBindingPattern#1", input: "function f({})", output: "function f({});"},
|
|
{title: "ObjectBindingPattern#2", input: "function f({a})", output: "function f({ a });"},
|
|
{title: "ObjectBindingPattern#3", input: "function f({a = b})", output: "function f({ a = b });"},
|
|
{title: "ObjectBindingPattern#4", input: "function f({a: b})", output: "function f({ a: b });"},
|
|
{title: "ObjectBindingPattern#5", input: "function f({a: b = c})", output: "function f({ a: b = c });"},
|
|
{title: "ObjectBindingPattern#6", input: "function f({\"a\": b})", output: "function f({ \"a\": b });"},
|
|
{title: "ObjectBindingPattern#7", input: "function f({'a': b})", output: "function f({ 'a': b });"},
|
|
{title: "ObjectBindingPattern#8", input: "function f({0: b})", output: "function f({ 0: b });"},
|
|
{title: "ObjectBindingPattern#9", input: "function f({[a]: b})", output: "function f({ [a]: b });"},
|
|
{title: "ObjectBindingPattern#10", input: "function f({...a})", output: "function f({ ...a });"},
|
|
{title: "ObjectBindingPattern#11", input: "function f({a: {}})", output: "function f({ a: {} });"},
|
|
{title: "ObjectBindingPattern#12", input: "function f({a: []})", output: "function f({ a: [] });"},
|
|
{title: "ArrayBindingPattern#1", input: "function f([])", output: "function f([]);"},
|
|
{title: "ArrayBindingPattern#2", input: "function f([,])", output: "function f([,]);"},
|
|
{title: "ArrayBindingPattern#3", input: "function f([a])", output: "function f([a]);"},
|
|
{title: "ArrayBindingPattern#4", input: "function f([a, b])", output: "function f([a, b]);"},
|
|
{title: "ArrayBindingPattern#5", input: "function f([a, , b])", output: "function f([a, , b]);"},
|
|
{title: "ArrayBindingPattern#6", input: "function f([a = b])", output: "function f([a = b]);"},
|
|
{title: "ArrayBindingPattern#7", input: "function f([...a])", output: "function f([...a]);"},
|
|
{title: "ArrayBindingPattern#8", input: "function f([{}])", output: "function f([{}]);"},
|
|
{title: "ArrayBindingPattern#9", input: "function f([[]])", output: "function f([[]]);"},
|
|
{title: "TypeParameterDeclaration#1", input: "function f<T>();", output: "function f<T>();"},
|
|
{title: "TypeParameterDeclaration#2", input: "function f<in T>();", output: "function f<in T>();"},
|
|
{title: "TypeParameterDeclaration#3", input: "function f<T extends U>();", output: "function f<T extends U>();"},
|
|
{title: "TypeParameterDeclaration#4", input: "function f<T = U>();", output: "function f<T = U>();"},
|
|
{title: "TypeParameterDeclaration#5", input: "function f<T extends U = V>();", output: "function f<T extends U = V>();"},
|
|
{title: "TypeParameterDeclaration#6", input: "function f<T, U>();", output: "function f<T, U>();"},
|
|
// {title: "TypeParameterDeclaration#7", input: "function f<T,>();", output: "function f<T,>();"}, // TODO: preserve trailing comma after Strada migration
|
|
{title: "JsxElement1", input: "<a></a>", output: "<a></a>;", jsx: true},
|
|
{title: "JsxElement2", input: "<this></this>", output: "<this></this>;", jsx: true},
|
|
{title: "JsxElement3", input: "<a:b></a:b>", output: "<a:b></a:b>;", jsx: true},
|
|
{title: "JsxElement4", input: "<a.b></a.b>", output: "<a.b></a.b>;", jsx: true},
|
|
{title: "JsxElement5", input: "<a<b>></a>", output: "<a<b>></a>;", jsx: true},
|
|
{title: "JsxElement6", input: "<a b></a>", output: "<a b></a>;", jsx: true},
|
|
{title: "JsxElement7", input: "<a>b</a>", output: "<a>b</a>;", jsx: true},
|
|
{title: "JsxElement8", input: "<a>{b}</a>", output: "<a>{b}</a>;", jsx: true},
|
|
{title: "JsxElement9", input: "<a><b></b></a>", output: "<a><b></b></a>;", jsx: true},
|
|
{title: "JsxElement10", input: "<a><b /></a>", output: "<a><b /></a>;", jsx: true},
|
|
{title: "JsxElement11", input: "<a><></></a>", output: "<a><></></a>;", jsx: true},
|
|
{title: "JsxSelfClosingElement1", input: "<a />", output: "<a />;", jsx: true},
|
|
{title: "JsxSelfClosingElement2", input: "<this />", output: "<this />;", jsx: true},
|
|
{title: "JsxSelfClosingElement3", input: "<a:b />", output: "<a:b />;", jsx: true},
|
|
{title: "JsxSelfClosingElement4", input: "<a.b />", output: "<a.b />;", jsx: true},
|
|
{title: "JsxSelfClosingElement5", input: "<a<b> />", output: "<a<b> />;", jsx: true},
|
|
{title: "JsxSelfClosingElement6", input: "<a b/>", output: "<a b/>;", jsx: true},
|
|
{title: "JsxFragment1", input: "<></>", output: "<></>;", jsx: true},
|
|
{title: "JsxFragment2", input: "<>b</>", output: "<>b</>;", jsx: true},
|
|
{title: "JsxFragment3", input: "<>{b}</>", output: "<>{b}</>;", jsx: true},
|
|
{title: "JsxFragment4", input: "<><b></b></>", output: "<><b></b></>;", jsx: true},
|
|
{title: "JsxFragment5", input: "<><b /></>", output: "<><b /></>;", jsx: true},
|
|
{title: "JsxFragment6", input: "<><></></>", output: "<><></></>;", jsx: true},
|
|
{title: "JsxAttribute1", input: "<a b/>", output: "<a b/>;", jsx: true},
|
|
{title: "JsxAttribute2", input: "<a b:c/>", output: "<a b:c/>;", jsx: true},
|
|
{title: "JsxAttribute3", input: "<a b=\"c\"/>", output: "<a b=\"c\"/>;", jsx: true},
|
|
{title: "JsxAttribute4", input: "<a b='c'/>", output: "<a b='c'/>;", jsx: true},
|
|
{title: "JsxAttribute5", input: "<a b={c}/>", output: "<a b={c}/>;", jsx: true},
|
|
{title: "JsxAttribute6", input: "<a b=<c></c>/>", output: "<a b=<c></c>/>;", jsx: true},
|
|
{title: "JsxAttribute7", input: "<a b=<c />/>", output: "<a b=<c />/>;", jsx: true},
|
|
{title: "JsxAttribute8", input: "<a b=<></>/>", output: "<a b=<></>/>;", jsx: true},
|
|
{title: "JsxSpreadAttribute", input: "<a {...b}/>", output: "<a {...b}/>;", jsx: true},
|
|
}
|
|
|
|
for _, rec := range data {
|
|
t.Run(rec.title, func(t *testing.T) {
|
|
t.Parallel()
|
|
file := parsetestutil.ParseTypeScript(rec.input, rec.jsx)
|
|
parsetestutil.CheckDiagnostics(t, file)
|
|
emittestutil.CheckEmit(t, nil, file, rec.output)
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestParenthesizeDecorator(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
var factory ast.NodeFactory
|
|
file := factory.NewSourceFile(ast.SourceFileParseOptions{FileName: "/file.ts", Path: "/file.ts"}, "", factory.NewNodeList(
|
|
[]*ast.Node{
|
|
factory.NewClassDeclaration(
|
|
factory.NewModifierList(
|
|
[]*ast.Node{
|
|
factory.NewDecorator(
|
|
factory.NewBinaryExpression(
|
|
nil, /*modifiers*/
|
|
factory.NewIdentifier("a"),
|
|
nil, /*typeNode*/
|
|
factory.NewToken(ast.KindPlusToken),
|
|
factory.NewIdentifier("b"),
|
|
),
|
|
),
|
|
},
|
|
),
|
|
factory.NewIdentifier("C"),
|
|
nil,
|
|
nil,
|
|
factory.NewNodeList([]*ast.Node{}),
|
|
),
|
|
},
|
|
), factory.NewToken(ast.KindEndOfFile))
|
|
|
|
parsetestutil.MarkSyntheticRecursive(file)
|
|
emittestutil.CheckEmit(t, nil, file.AsSourceFile(), "@(a + b)\nclass C {\n}")
|
|
}
|
|
|
|
func TestParenthesizeComputedPropertyName(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
var factory ast.NodeFactory
|
|
file := factory.NewSourceFile(ast.SourceFileParseOptions{FileName: "/file.ts", Path: "/file.ts"}, "", factory.NewNodeList(
|
|
[]*ast.Node{
|
|
factory.NewClassDeclaration(
|
|
nil, /*modifiers*/
|
|
factory.NewIdentifier("C"),
|
|
nil, /*typeParameters*/
|
|
nil, /*heritageClauses*/
|
|
factory.NewNodeList([]*ast.Node{
|
|
factory.NewPropertyDeclaration(
|
|
nil, /*modifiers*/
|
|
factory.NewComputedPropertyName(
|
|
// will be parenthesized on emit:
|
|
factory.NewBinaryExpression(
|
|
nil, /*modifiers*/
|
|
factory.NewIdentifier("a"),
|
|
nil, /*typeNode*/
|
|
factory.NewToken(ast.KindCommaToken),
|
|
factory.NewIdentifier("b"),
|
|
),
|
|
),
|
|
nil, /*postfixToken*/
|
|
nil, /*typeNode*/
|
|
nil, /*initializer*/
|
|
),
|
|
}),
|
|
),
|
|
},
|
|
), factory.NewToken(ast.KindEndOfFile))
|
|
|
|
parsetestutil.MarkSyntheticRecursive(file)
|
|
emittestutil.CheckEmit(t, nil, file.AsSourceFile(), "class C {\n [(a, b)];\n}")
|
|
}
|
|
|
|
func TestParenthesizeArrayLiteral(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
var factory ast.NodeFactory
|
|
file := factory.NewSourceFile(ast.SourceFileParseOptions{FileName: "/file.ts", Path: "/file.ts"}, "", factory.NewNodeList(
|
|
[]*ast.Node{
|
|
factory.NewExpressionStatement(
|
|
factory.NewArrayLiteralExpression(
|
|
factory.NewNodeList(
|
|
[]*ast.Node{
|
|
// will be parenthesized on emit:
|
|
factory.NewBinaryExpression(
|
|
nil, /*modifiers*/
|
|
factory.NewIdentifier("a"),
|
|
nil, /*typeNode*/
|
|
factory.NewToken(ast.KindCommaToken),
|
|
factory.NewIdentifier("b"),
|
|
),
|
|
},
|
|
),
|
|
false, /*multiLine*/
|
|
),
|
|
),
|
|
},
|
|
), factory.NewToken(ast.KindEndOfFile))
|
|
|
|
parsetestutil.MarkSyntheticRecursive(file)
|
|
emittestutil.CheckEmit(t, nil, file.AsSourceFile(), "[(a, b)];")
|
|
}
|
|
|
|
func TestParenthesizePropertyAccess1(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
var factory ast.NodeFactory
|
|
file := factory.NewSourceFile(ast.SourceFileParseOptions{FileName: "/file.ts", Path: "/file.ts"}, "", factory.NewNodeList(
|
|
[]*ast.Node{
|
|
factory.NewExpressionStatement(
|
|
factory.NewPropertyAccessExpression(
|
|
// will be parenthesized on emit:
|
|
factory.NewBinaryExpression(
|
|
nil, /*modifiers*/
|
|
factory.NewIdentifier("a"),
|
|
nil, /*typeNode*/
|
|
factory.NewToken(ast.KindCommaToken),
|
|
factory.NewIdentifier("b"),
|
|
),
|
|
nil, /*questionDotToken*/
|
|
factory.NewIdentifier("c"),
|
|
ast.NodeFlagsNone,
|
|
),
|
|
),
|
|
},
|
|
), factory.NewToken(ast.KindEndOfFile))
|
|
|
|
parsetestutil.MarkSyntheticRecursive(file)
|
|
emittestutil.CheckEmit(t, nil, file.AsSourceFile(), "(a, b).c;")
|
|
}
|
|
|
|
func TestParenthesizePropertyAccess2(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
var factory ast.NodeFactory
|
|
file := factory.NewSourceFile(ast.SourceFileParseOptions{FileName: "/file.ts", Path: "/file.ts"}, "", factory.NewNodeList(
|
|
[]*ast.Node{
|
|
factory.NewExpressionStatement(
|
|
factory.NewPropertyAccessExpression(
|
|
// will be parenthesized on emit:
|
|
factory.NewPropertyAccessExpression(
|
|
factory.NewIdentifier("a"),
|
|
factory.NewToken(ast.KindQuestionDotToken),
|
|
factory.NewIdentifier("b"),
|
|
ast.NodeFlagsOptionalChain,
|
|
),
|
|
nil, /*questionDotToken*/
|
|
factory.NewIdentifier("c"),
|
|
ast.NodeFlagsNone,
|
|
),
|
|
),
|
|
},
|
|
), factory.NewToken(ast.KindEndOfFile))
|
|
|
|
parsetestutil.MarkSyntheticRecursive(file)
|
|
emittestutil.CheckEmit(t, nil, file.AsSourceFile(), "(a?.b).c;")
|
|
}
|
|
|
|
func TestParenthesizePropertyAccess3(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
var factory ast.NodeFactory
|
|
file := factory.NewSourceFile(ast.SourceFileParseOptions{FileName: "/file.ts", Path: "/file.ts"}, "", factory.NewNodeList(
|
|
[]*ast.Node{
|
|
factory.NewExpressionStatement(
|
|
factory.NewPropertyAccessExpression(
|
|
// will be parenthesized on emit:
|
|
factory.NewNewExpression(
|
|
factory.NewIdentifier("a"),
|
|
nil, /*typeArguments*/
|
|
nil, /*arguments*/
|
|
),
|
|
nil, /*questionDotToken*/
|
|
factory.NewIdentifier("b"),
|
|
ast.NodeFlagsNone,
|
|
),
|
|
),
|
|
},
|
|
), factory.NewToken(ast.KindEndOfFile))
|
|
|
|
parsetestutil.MarkSyntheticRecursive(file)
|
|
emittestutil.CheckEmit(t, nil, file.AsSourceFile(), "(new a).b;")
|
|
}
|
|
|
|
func TestParenthesizeElementAccess1(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
var factory ast.NodeFactory
|
|
file := factory.NewSourceFile(ast.SourceFileParseOptions{FileName: "/file.ts", Path: "/file.ts"}, "", factory.NewNodeList(
|
|
[]*ast.Node{
|
|
factory.NewExpressionStatement(
|
|
factory.NewElementAccessExpression(
|
|
// will be parenthesized on emit:
|
|
factory.NewBinaryExpression(
|
|
nil, /*modifiers*/
|
|
factory.NewIdentifier("a"),
|
|
nil, /*typeNode*/
|
|
factory.NewToken(ast.KindCommaToken),
|
|
factory.NewIdentifier("b"),
|
|
),
|
|
nil, /*questionDotToken*/
|
|
factory.NewIdentifier("c"),
|
|
ast.NodeFlagsNone,
|
|
),
|
|
),
|
|
},
|
|
), factory.NewToken(ast.KindEndOfFile))
|
|
|
|
parsetestutil.MarkSyntheticRecursive(file)
|
|
emittestutil.CheckEmit(t, nil, file.AsSourceFile(), "(a, b)[c];")
|
|
}
|
|
|
|
func TestParenthesizeElementAccess2(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
var factory ast.NodeFactory
|
|
file := factory.NewSourceFile(ast.SourceFileParseOptions{FileName: "/file.ts", Path: "/file.ts"}, "", factory.NewNodeList(
|
|
[]*ast.Node{
|
|
factory.NewExpressionStatement(
|
|
factory.NewElementAccessExpression(
|
|
// will be parenthesized on emit:
|
|
factory.NewPropertyAccessExpression(
|
|
factory.NewIdentifier("a"),
|
|
factory.NewToken(ast.KindQuestionDotToken),
|
|
factory.NewIdentifier("b"),
|
|
ast.NodeFlagsOptionalChain,
|
|
),
|
|
nil, /*questionDotToken*/
|
|
factory.NewIdentifier("c"),
|
|
ast.NodeFlagsNone,
|
|
),
|
|
),
|
|
},
|
|
), factory.NewToken(ast.KindEndOfFile))
|
|
|
|
parsetestutil.MarkSyntheticRecursive(file)
|
|
emittestutil.CheckEmit(t, nil, file.AsSourceFile(), "(a?.b)[c];")
|
|
}
|
|
|
|
func TestParenthesizeElementAccess3(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
var factory ast.NodeFactory
|
|
file := factory.NewSourceFile(ast.SourceFileParseOptions{FileName: "/file.ts", Path: "/file.ts"}, "", factory.NewNodeList(
|
|
[]*ast.Node{
|
|
factory.NewExpressionStatement(
|
|
factory.NewElementAccessExpression(
|
|
// will be parenthesized on emit:
|
|
factory.NewNewExpression(
|
|
factory.NewIdentifier("a"),
|
|
nil, /*typeArguments*/
|
|
nil, /*arguments*/
|
|
),
|
|
nil, /*questionDotToken*/
|
|
factory.NewIdentifier("b"),
|
|
ast.NodeFlagsNone,
|
|
),
|
|
),
|
|
},
|
|
), factory.NewToken(ast.KindEndOfFile))
|
|
|
|
parsetestutil.MarkSyntheticRecursive(file)
|
|
emittestutil.CheckEmit(t, nil, file.AsSourceFile(), "(new a)[b];")
|
|
}
|
|
|
|
func TestParenthesizeCall1(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
var factory ast.NodeFactory
|
|
file := factory.NewSourceFile(ast.SourceFileParseOptions{FileName: "/file.ts", Path: "/file.ts"}, "", factory.NewNodeList(
|
|
[]*ast.Node{
|
|
factory.NewExpressionStatement(
|
|
factory.NewCallExpression(
|
|
// will be parenthesized on emit:
|
|
factory.NewBinaryExpression(
|
|
nil, /*modifiers*/
|
|
factory.NewIdentifier("a"),
|
|
nil, /*typeNode*/
|
|
factory.NewToken(ast.KindCommaToken),
|
|
factory.NewIdentifier("b"),
|
|
),
|
|
nil, /*questionDotToken*/
|
|
nil, /*typeArguments*/
|
|
factory.NewNodeList([]*ast.Node{}),
|
|
ast.NodeFlagsNone,
|
|
),
|
|
),
|
|
},
|
|
), factory.NewToken(ast.KindEndOfFile))
|
|
|
|
parsetestutil.MarkSyntheticRecursive(file)
|
|
emittestutil.CheckEmit(t, nil, file.AsSourceFile(), "(a, b)();")
|
|
}
|
|
|
|
func TestParenthesizeCall2(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
var factory ast.NodeFactory
|
|
file := factory.NewSourceFile(ast.SourceFileParseOptions{FileName: "/file.ts", Path: "/file.ts"}, "", factory.NewNodeList(
|
|
[]*ast.Node{
|
|
factory.NewExpressionStatement(
|
|
factory.NewCallExpression(
|
|
// will be parenthesized on emit:
|
|
factory.NewPropertyAccessExpression(
|
|
factory.NewIdentifier("a"),
|
|
factory.NewToken(ast.KindQuestionDotToken),
|
|
factory.NewIdentifier("b"),
|
|
ast.NodeFlagsOptionalChain,
|
|
),
|
|
nil, /*questionDotToken*/
|
|
nil, /*typeArguments*/
|
|
factory.NewNodeList([]*ast.Node{}),
|
|
ast.NodeFlagsNone,
|
|
),
|
|
),
|
|
},
|
|
), factory.NewToken(ast.KindEndOfFile))
|
|
|
|
parsetestutil.MarkSyntheticRecursive(file)
|
|
emittestutil.CheckEmit(t, nil, file.AsSourceFile(), "(a?.b)();")
|
|
}
|
|
|
|
func TestParenthesizeCall3(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
var factory ast.NodeFactory
|
|
file := factory.NewSourceFile(ast.SourceFileParseOptions{FileName: "/file.ts", Path: "/file.ts"}, "", factory.NewNodeList(
|
|
[]*ast.Node{
|
|
factory.NewExpressionStatement(
|
|
factory.NewCallExpression(
|
|
// will be parenthesized on emit:
|
|
factory.NewNewExpression(
|
|
factory.NewIdentifier("C"),
|
|
nil, /*typeArguments*/
|
|
nil, /*arguments*/
|
|
),
|
|
nil, /*questionDotToken*/
|
|
nil, /*typeArguments*/
|
|
factory.NewNodeList([]*ast.Node{}),
|
|
ast.NodeFlagsNone,
|
|
),
|
|
),
|
|
},
|
|
), factory.NewToken(ast.KindEndOfFile))
|
|
|
|
parsetestutil.MarkSyntheticRecursive(file)
|
|
emittestutil.CheckEmit(t, nil, file.AsSourceFile(), "(new C)();")
|
|
}
|
|
|
|
func TestParenthesizeCall4(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
var factory ast.NodeFactory
|
|
file := factory.NewSourceFile(ast.SourceFileParseOptions{FileName: "/file.ts", Path: "/file.ts"}, "", factory.NewNodeList(
|
|
[]*ast.Node{
|
|
factory.NewExpressionStatement(
|
|
factory.NewCallExpression(
|
|
factory.NewIdentifier("a"),
|
|
nil, /*questionDotToken*/
|
|
nil, /*typeArguments*/
|
|
factory.NewNodeList([]*ast.Node{
|
|
factory.NewBinaryExpression(
|
|
nil, /*modifiers*/
|
|
factory.NewIdentifier("b"),
|
|
nil, /*typeNode*/
|
|
factory.NewToken(ast.KindCommaToken),
|
|
factory.NewIdentifier("c"),
|
|
),
|
|
}),
|
|
ast.NodeFlagsNone,
|
|
),
|
|
),
|
|
},
|
|
), factory.NewToken(ast.KindEndOfFile))
|
|
|
|
parsetestutil.MarkSyntheticRecursive(file)
|
|
emittestutil.CheckEmit(t, nil, file.AsSourceFile(), "a((b, c));")
|
|
}
|
|
|
|
func TestParenthesizeNew1(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
var factory ast.NodeFactory
|
|
file := factory.NewSourceFile(ast.SourceFileParseOptions{FileName: "/file.ts", Path: "/file.ts"}, "", factory.NewNodeList(
|
|
[]*ast.Node{
|
|
factory.NewExpressionStatement(
|
|
factory.NewNewExpression(
|
|
// will be parenthesized on emit:
|
|
factory.NewBinaryExpression(
|
|
nil, /*modifiers*/
|
|
factory.NewIdentifier("a"),
|
|
nil, /*typeNode*/
|
|
factory.NewToken(ast.KindCommaToken),
|
|
factory.NewIdentifier("b"),
|
|
),
|
|
nil, /*typeArguments*/
|
|
factory.NewNodeList([]*ast.Node{}),
|
|
),
|
|
),
|
|
},
|
|
), factory.NewToken(ast.KindEndOfFile))
|
|
|
|
parsetestutil.MarkSyntheticRecursive(file)
|
|
emittestutil.CheckEmit(t, nil, file.AsSourceFile(), "new (a, b)();")
|
|
}
|
|
|
|
func TestParenthesizeNew2(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
var factory ast.NodeFactory
|
|
file := factory.NewSourceFile(ast.SourceFileParseOptions{FileName: "/file.ts", Path: "/file.ts"}, "", factory.NewNodeList(
|
|
[]*ast.Node{
|
|
factory.NewExpressionStatement(
|
|
factory.NewNewExpression(
|
|
// will be parenthesized on emit:
|
|
factory.NewCallExpression(
|
|
factory.NewIdentifier("C"),
|
|
nil, /*questionDotToken*/
|
|
nil, /*typeArguments*/
|
|
factory.NewNodeList([]*ast.Node{}),
|
|
ast.NodeFlagsNone,
|
|
),
|
|
nil, /*typeArguments*/
|
|
nil, /*arguments*/
|
|
),
|
|
),
|
|
},
|
|
), factory.NewToken(ast.KindEndOfFile))
|
|
|
|
parsetestutil.MarkSyntheticRecursive(file)
|
|
emittestutil.CheckEmit(t, nil, file.AsSourceFile(), "new (C());")
|
|
}
|
|
|
|
func TestParenthesizeNew3(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
var factory ast.NodeFactory
|
|
file := factory.NewSourceFile(ast.SourceFileParseOptions{FileName: "/file.ts", Path: "/file.ts"}, "", factory.NewNodeList(
|
|
[]*ast.Node{
|
|
factory.NewExpressionStatement(
|
|
factory.NewNewExpression(
|
|
factory.NewIdentifier("C"),
|
|
nil, /*typeArguments*/
|
|
factory.NewNodeList([]*ast.Node{
|
|
factory.NewBinaryExpression(
|
|
nil, /*modifiers*/
|
|
factory.NewIdentifier("a"),
|
|
nil, /*typeNode*/
|
|
factory.NewToken(ast.KindCommaToken),
|
|
factory.NewIdentifier("b"),
|
|
),
|
|
}),
|
|
),
|
|
),
|
|
},
|
|
), factory.NewToken(ast.KindEndOfFile))
|
|
|
|
parsetestutil.MarkSyntheticRecursive(file)
|
|
emittestutil.CheckEmit(t, nil, file.AsSourceFile(), "new C((a, b));")
|
|
}
|
|
|
|
func TestParenthesizeTaggedTemplate1(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
var factory ast.NodeFactory
|
|
file := factory.NewSourceFile(ast.SourceFileParseOptions{FileName: "/file.ts", Path: "/file.ts"}, "", factory.NewNodeList(
|
|
[]*ast.Node{
|
|
factory.NewExpressionStatement(
|
|
factory.NewTaggedTemplateExpression(
|
|
// will be parenthesized on emit:
|
|
factory.NewBinaryExpression(
|
|
nil, /*modifiers*/
|
|
factory.NewIdentifier("a"),
|
|
nil, /*typeNode*/
|
|
factory.NewToken(ast.KindCommaToken),
|
|
factory.NewIdentifier("b"),
|
|
),
|
|
nil, /*questionDotToken*/
|
|
nil, /*typeArguments*/
|
|
factory.NewNoSubstitutionTemplateLiteral(""),
|
|
ast.NodeFlagsNone,
|
|
),
|
|
),
|
|
},
|
|
), factory.NewToken(ast.KindEndOfFile))
|
|
|
|
parsetestutil.MarkSyntheticRecursive(file)
|
|
emittestutil.CheckEmit(t, nil, file.AsSourceFile(), "(a, b) ``;")
|
|
}
|
|
|
|
func TestParenthesizeTaggedTemplate2(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
var factory ast.NodeFactory
|
|
file := factory.NewSourceFile(ast.SourceFileParseOptions{FileName: "/file.ts", Path: "/file.ts"}, "", factory.NewNodeList(
|
|
[]*ast.Node{
|
|
factory.NewExpressionStatement(
|
|
factory.NewTaggedTemplateExpression(
|
|
// will be parenthesized on emit:
|
|
factory.NewPropertyAccessExpression(
|
|
factory.NewIdentifier("a"),
|
|
factory.NewToken(ast.KindQuestionDotToken),
|
|
factory.NewIdentifier("b"),
|
|
ast.NodeFlagsOptionalChain,
|
|
),
|
|
nil, /*questionDotToken*/
|
|
nil, /*typeArguments*/
|
|
factory.NewNoSubstitutionTemplateLiteral(""),
|
|
ast.NodeFlagsNone,
|
|
),
|
|
),
|
|
},
|
|
), factory.NewToken(ast.KindEndOfFile))
|
|
|
|
parsetestutil.MarkSyntheticRecursive(file)
|
|
emittestutil.CheckEmit(t, nil, file.AsSourceFile(), "(a?.b) ``;")
|
|
}
|
|
|
|
func TestParenthesizeTypeAssertion1(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
var factory ast.NodeFactory
|
|
file := factory.NewSourceFile(ast.SourceFileParseOptions{FileName: "/file.ts", Path: "/file.ts"}, "", factory.NewNodeList(
|
|
[]*ast.Node{
|
|
factory.NewExpressionStatement(
|
|
factory.NewTypeAssertion(
|
|
factory.NewTypeReferenceNode(
|
|
factory.NewIdentifier("T"),
|
|
nil, /*typeArguments*/
|
|
),
|
|
// will be parenthesized on emit:
|
|
factory.NewBinaryExpression(
|
|
nil, /*modifiers*/
|
|
factory.NewIdentifier("a"),
|
|
nil, /*typeNode*/
|
|
factory.NewToken(ast.KindPlusToken),
|
|
factory.NewIdentifier("b"),
|
|
),
|
|
),
|
|
),
|
|
},
|
|
), factory.NewToken(ast.KindEndOfFile))
|
|
|
|
parsetestutil.MarkSyntheticRecursive(file)
|
|
emittestutil.CheckEmit(t, nil, file.AsSourceFile(), "<T>(a + b);")
|
|
}
|
|
|
|
func TestParenthesizeArrowFunction1(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
var factory ast.NodeFactory
|
|
file := factory.NewSourceFile(ast.SourceFileParseOptions{FileName: "/file.ts", Path: "/file.ts"}, "", factory.NewNodeList(
|
|
[]*ast.Node{
|
|
factory.NewExpressionStatement(
|
|
factory.NewArrowFunction(
|
|
nil, /*modifiers*/
|
|
nil, /*typeParameters*/
|
|
factory.NewNodeList([]*ast.Node{}),
|
|
nil, /*returnType*/
|
|
nil, /*fullSignature*/
|
|
factory.NewToken(ast.KindEqualsGreaterThanToken),
|
|
// will be parenthesized on emit:
|
|
factory.NewObjectLiteralExpression(
|
|
factory.NewNodeList([]*ast.Node{}),
|
|
false, /*multiLine*/
|
|
),
|
|
),
|
|
),
|
|
},
|
|
), factory.NewToken(ast.KindEndOfFile))
|
|
|
|
parsetestutil.MarkSyntheticRecursive(file)
|
|
emittestutil.CheckEmit(t, nil, file.AsSourceFile(), "() => ({});")
|
|
}
|
|
|
|
func TestParenthesizeArrowFunction2(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
var factory ast.NodeFactory
|
|
file := factory.NewSourceFile(ast.SourceFileParseOptions{FileName: "/file.ts", Path: "/file.ts"}, "", factory.NewNodeList(
|
|
[]*ast.Node{
|
|
factory.NewExpressionStatement(
|
|
factory.NewArrowFunction(
|
|
nil, /*modifiers*/
|
|
nil, /*typeParameters*/
|
|
factory.NewNodeList([]*ast.Node{}),
|
|
nil, /*returnType*/
|
|
nil, /*fullSignature*/
|
|
factory.NewToken(ast.KindEqualsGreaterThanToken),
|
|
// will be parenthesized on emit:
|
|
factory.NewPropertyAccessExpression(
|
|
factory.NewObjectLiteralExpression(
|
|
factory.NewNodeList([]*ast.Node{}),
|
|
false, /*multiLine*/
|
|
),
|
|
nil, /*questionDotToken*/
|
|
factory.NewIdentifier("a"),
|
|
ast.NodeFlagsNone,
|
|
),
|
|
),
|
|
),
|
|
},
|
|
), factory.NewToken(ast.KindEndOfFile))
|
|
|
|
parsetestutil.MarkSyntheticRecursive(file)
|
|
emittestutil.CheckEmit(t, nil, file.AsSourceFile(), "() => ({}.a);")
|
|
}
|
|
|
|
func TestParenthesizeDelete(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
var factory ast.NodeFactory
|
|
file := factory.NewSourceFile(ast.SourceFileParseOptions{FileName: "/file.ts", Path: "/file.ts"}, "", factory.NewNodeList(
|
|
[]*ast.Node{
|
|
factory.NewExpressionStatement(
|
|
factory.NewDeleteExpression(
|
|
// will be parenthesized on emit:
|
|
factory.NewBinaryExpression(
|
|
nil, /*modifiers*/
|
|
factory.NewIdentifier("a"),
|
|
nil, /*typeNode*/
|
|
factory.NewToken(ast.KindPlusToken),
|
|
factory.NewIdentifier("b"),
|
|
),
|
|
),
|
|
),
|
|
},
|
|
), factory.NewToken(ast.KindEndOfFile))
|
|
|
|
parsetestutil.MarkSyntheticRecursive(file)
|
|
emittestutil.CheckEmit(t, nil, file.AsSourceFile(), "delete (a + b);")
|
|
}
|
|
|
|
func TestParenthesizeVoid(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
var factory ast.NodeFactory
|
|
file := factory.NewSourceFile(ast.SourceFileParseOptions{FileName: "/file.ts", Path: "/file.ts"}, "", factory.NewNodeList(
|
|
[]*ast.Node{
|
|
factory.NewExpressionStatement(
|
|
factory.NewVoidExpression(
|
|
// will be parenthesized on emit:
|
|
factory.NewBinaryExpression(
|
|
nil, /*modifiers*/
|
|
factory.NewIdentifier("a"),
|
|
nil, /*typeNode*/
|
|
factory.NewToken(ast.KindPlusToken),
|
|
factory.NewIdentifier("b"),
|
|
),
|
|
),
|
|
),
|
|
},
|
|
), factory.NewToken(ast.KindEndOfFile))
|
|
|
|
parsetestutil.MarkSyntheticRecursive(file)
|
|
emittestutil.CheckEmit(t, nil, file.AsSourceFile(), "void (a + b);")
|
|
}
|
|
|
|
func TestParenthesizeTypeOf(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
var factory ast.NodeFactory
|
|
file := factory.NewSourceFile(ast.SourceFileParseOptions{FileName: "/file.ts", Path: "/file.ts"}, "", factory.NewNodeList(
|
|
[]*ast.Node{
|
|
factory.NewExpressionStatement(
|
|
factory.NewTypeOfExpression(
|
|
// will be parenthesized on emit:
|
|
factory.NewBinaryExpression(
|
|
nil, /*modifiers*/
|
|
factory.NewIdentifier("a"),
|
|
nil, /*typeNode*/
|
|
factory.NewToken(ast.KindPlusToken),
|
|
factory.NewIdentifier("b"),
|
|
),
|
|
),
|
|
),
|
|
},
|
|
), factory.NewToken(ast.KindEndOfFile))
|
|
|
|
parsetestutil.MarkSyntheticRecursive(file)
|
|
emittestutil.CheckEmit(t, nil, file.AsSourceFile(), "typeof (a + b);")
|
|
}
|
|
|
|
func TestParenthesizeAwait(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
var factory ast.NodeFactory
|
|
file := factory.NewSourceFile(ast.SourceFileParseOptions{FileName: "/file.ts", Path: "/file.ts"}, "", factory.NewNodeList(
|
|
[]*ast.Node{
|
|
factory.NewExpressionStatement(
|
|
factory.NewAwaitExpression(
|
|
// will be parenthesized on emit:
|
|
factory.NewBinaryExpression(
|
|
nil, /*modifiers*/
|
|
factory.NewIdentifier("a"),
|
|
nil, /*typeNode*/
|
|
factory.NewToken(ast.KindPlusToken),
|
|
factory.NewIdentifier("b"),
|
|
),
|
|
),
|
|
),
|
|
},
|
|
), factory.NewToken(ast.KindEndOfFile))
|
|
|
|
parsetestutil.MarkSyntheticRecursive(file)
|
|
emittestutil.CheckEmit(t, nil, file.AsSourceFile(), "await (a + b);")
|
|
}
|
|
|
|
func isBinaryOperator(token ast.Kind) bool {
|
|
switch token {
|
|
case ast.KindCommaToken,
|
|
ast.KindLessThanToken,
|
|
ast.KindGreaterThanToken,
|
|
ast.KindLessThanEqualsToken,
|
|
ast.KindGreaterThanEqualsToken,
|
|
ast.KindEqualsEqualsToken,
|
|
ast.KindEqualsEqualsEqualsToken,
|
|
ast.KindExclamationEqualsToken,
|
|
ast.KindExclamationEqualsEqualsToken,
|
|
ast.KindPlusToken,
|
|
ast.KindMinusToken,
|
|
ast.KindAsteriskToken,
|
|
ast.KindAsteriskAsteriskToken,
|
|
ast.KindSlashToken,
|
|
ast.KindPercentToken,
|
|
ast.KindLessThanLessThanToken,
|
|
ast.KindGreaterThanGreaterThanToken,
|
|
ast.KindGreaterThanGreaterThanGreaterThanToken,
|
|
ast.KindAmpersandToken,
|
|
ast.KindBarToken,
|
|
ast.KindCaretToken,
|
|
ast.KindAmpersandAmpersandToken,
|
|
ast.KindBarBarToken,
|
|
ast.KindQuestionQuestionToken,
|
|
ast.KindEqualsToken,
|
|
ast.KindPlusEqualsToken,
|
|
ast.KindMinusEqualsToken,
|
|
ast.KindAsteriskEqualsToken,
|
|
ast.KindAsteriskAsteriskEqualsToken,
|
|
ast.KindSlashEqualsToken,
|
|
ast.KindPercentEqualsToken,
|
|
ast.KindLessThanLessThanEqualsToken,
|
|
ast.KindGreaterThanGreaterThanEqualsToken,
|
|
ast.KindGreaterThanGreaterThanGreaterThanEqualsToken,
|
|
ast.KindAmpersandEqualsToken,
|
|
ast.KindBarEqualsToken,
|
|
ast.KindBarBarEqualsToken,
|
|
ast.KindAmpersandAmpersandEqualsToken,
|
|
ast.KindQuestionQuestionEqualsToken,
|
|
ast.KindCaretEqualsToken,
|
|
ast.KindInKeyword,
|
|
ast.KindInstanceOfKeyword:
|
|
return true
|
|
}
|
|
return false
|
|
}
|
|
|
|
func makeSide(label string, kind ast.Kind, factory *ast.NodeFactory) *ast.Node {
|
|
switch {
|
|
case kind == ast.KindIdentifier || kind == ast.KindUnknown:
|
|
return factory.NewIdentifier(label)
|
|
case kind == ast.KindArrowFunction:
|
|
return factory.NewArrowFunction(
|
|
nil, /*modifiers*/
|
|
nil, /*typeParameters*/
|
|
factory.NewNodeList([]*ast.Node{}),
|
|
nil, /*returnType*/
|
|
nil, /*fullSignature*/
|
|
factory.NewToken(ast.KindEqualsGreaterThanToken),
|
|
factory.NewBlock(factory.NewNodeList([]*ast.Node{}), false /*multiLine*/),
|
|
)
|
|
case isBinaryOperator(kind):
|
|
return factory.NewBinaryExpression(
|
|
nil, /*modifiers*/
|
|
factory.NewIdentifier(label+"l"),
|
|
nil, /*typeNode*/
|
|
factory.NewToken(kind),
|
|
factory.NewIdentifier(label+"r"),
|
|
)
|
|
default:
|
|
panic("unsupported kind")
|
|
}
|
|
}
|
|
|
|
func TestParenthesizeBinary(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
data := []struct {
|
|
left ast.Kind
|
|
operator ast.Kind
|
|
right ast.Kind
|
|
output string
|
|
}{
|
|
{operator: ast.KindCommaToken, output: "l, r"},
|
|
{operator: ast.KindCommaToken, left: ast.KindPlusToken, output: "ll + lr, r"},
|
|
{operator: ast.KindAsteriskToken, left: ast.KindPlusToken, output: "(ll + lr) * r"},
|
|
{operator: ast.KindAsteriskToken, right: ast.KindPlusToken, output: "l * (rl + rr)"},
|
|
{operator: ast.KindPlusToken, left: ast.KindAsteriskToken, output: "ll * lr + r"},
|
|
{operator: ast.KindPlusToken, right: ast.KindAsteriskToken, output: "l + rl * rr"},
|
|
{operator: ast.KindSlashToken, left: ast.KindAsteriskToken, output: "ll * lr / r"},
|
|
{operator: ast.KindSlashToken, left: ast.KindAsteriskAsteriskToken, output: "ll ** lr / r"},
|
|
{operator: ast.KindAsteriskAsteriskToken, left: ast.KindAsteriskToken, output: "(ll * lr) ** r"},
|
|
{operator: ast.KindAsteriskAsteriskToken, left: ast.KindAsteriskAsteriskToken, output: "(ll ** lr) ** r"},
|
|
{operator: ast.KindAsteriskToken, right: ast.KindAsteriskToken, output: "l * rl * rr"},
|
|
{operator: ast.KindBarToken, right: ast.KindBarToken, output: "l | rl | rr"},
|
|
{operator: ast.KindAmpersandToken, right: ast.KindAmpersandToken, output: "l & rl & rr"},
|
|
{operator: ast.KindCaretToken, right: ast.KindCaretToken, output: "l ^ rl ^ rr"},
|
|
{operator: ast.KindAmpersandAmpersandToken, right: ast.KindArrowFunction, output: "l && (() => { })"},
|
|
}
|
|
for _, rec := range data {
|
|
t.Run(rec.output, func(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
var factory ast.NodeFactory
|
|
file := factory.NewSourceFile(ast.SourceFileParseOptions{FileName: "/file.ts", Path: "/file.ts"}, "", factory.NewNodeList(
|
|
[]*ast.Node{
|
|
factory.NewExpressionStatement(
|
|
factory.NewBinaryExpression(
|
|
nil, /*modifiers*/
|
|
makeSide("l", rec.left, &factory),
|
|
nil, /*typeNode*/
|
|
factory.NewToken(rec.operator),
|
|
makeSide("r", rec.right, &factory),
|
|
),
|
|
),
|
|
},
|
|
), factory.NewToken(ast.KindEndOfFile))
|
|
|
|
parsetestutil.MarkSyntheticRecursive(file)
|
|
emittestutil.CheckEmit(t, nil, file.AsSourceFile(), rec.output+";")
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestParenthesizeConditional1(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
var factory ast.NodeFactory
|
|
file := factory.NewSourceFile(ast.SourceFileParseOptions{FileName: "/file.ts", Path: "/file.ts"}, "", factory.NewNodeList(
|
|
[]*ast.Node{
|
|
factory.NewExpressionStatement(
|
|
factory.NewConditionalExpression(
|
|
// will be parenthesized on emit:
|
|
factory.NewBinaryExpression(
|
|
nil, /*modifiers*/
|
|
factory.NewIdentifier("a"),
|
|
nil, /*typeNode*/
|
|
factory.NewToken(ast.KindCommaToken),
|
|
factory.NewIdentifier("b"),
|
|
),
|
|
factory.NewToken(ast.KindQuestionToken),
|
|
factory.NewIdentifier("c"),
|
|
factory.NewToken(ast.KindColonToken),
|
|
factory.NewIdentifier("d"),
|
|
),
|
|
),
|
|
},
|
|
), factory.NewToken(ast.KindEndOfFile))
|
|
|
|
parsetestutil.MarkSyntheticRecursive(file)
|
|
emittestutil.CheckEmit(t, nil, file.AsSourceFile(), "(a, b) ? c : d;")
|
|
}
|
|
|
|
func TestParenthesizeConditional2(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
var factory ast.NodeFactory
|
|
file := factory.NewSourceFile(ast.SourceFileParseOptions{FileName: "/file.ts", Path: "/file.ts"}, "", factory.NewNodeList(
|
|
[]*ast.Node{
|
|
factory.NewExpressionStatement(
|
|
factory.NewConditionalExpression(
|
|
// will be parenthesized on emit:
|
|
factory.NewBinaryExpression(
|
|
nil, /*modifiers*/
|
|
factory.NewIdentifier("a"),
|
|
nil, /*typeNode*/
|
|
factory.NewToken(ast.KindEqualsToken),
|
|
factory.NewIdentifier("b"),
|
|
),
|
|
factory.NewToken(ast.KindQuestionToken),
|
|
factory.NewIdentifier("c"),
|
|
factory.NewToken(ast.KindColonToken),
|
|
factory.NewIdentifier("d"),
|
|
),
|
|
),
|
|
},
|
|
), factory.NewToken(ast.KindEndOfFile))
|
|
|
|
parsetestutil.MarkSyntheticRecursive(file)
|
|
emittestutil.CheckEmit(t, nil, file.AsSourceFile(), "(a = b) ? c : d;")
|
|
}
|
|
|
|
func TestParenthesizeConditional3(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
var factory ast.NodeFactory
|
|
file := factory.NewSourceFile(ast.SourceFileParseOptions{FileName: "/file.ts", Path: "/file.ts"}, "", factory.NewNodeList(
|
|
[]*ast.Node{
|
|
factory.NewExpressionStatement(
|
|
factory.NewConditionalExpression(
|
|
// will be parenthesized on emit:
|
|
factory.NewArrowFunction(
|
|
nil, /*modifiers*/
|
|
nil, /*typeParameters*/
|
|
factory.NewNodeList([]*ast.Node{}),
|
|
nil, /*returnType*/
|
|
nil, /*fullSignature*/
|
|
factory.NewToken(ast.KindEqualsGreaterThanToken),
|
|
factory.NewBlock(
|
|
factory.NewNodeList([]*ast.Node{}),
|
|
false, /*multiLine*/
|
|
),
|
|
),
|
|
factory.NewToken(ast.KindQuestionToken),
|
|
factory.NewIdentifier("a"),
|
|
factory.NewToken(ast.KindColonToken),
|
|
factory.NewIdentifier("b"),
|
|
),
|
|
),
|
|
},
|
|
), factory.NewToken(ast.KindEndOfFile))
|
|
|
|
parsetestutil.MarkSyntheticRecursive(file)
|
|
emittestutil.CheckEmit(t, nil, file.AsSourceFile(), "(() => { }) ? a : b;")
|
|
}
|
|
|
|
func TestParenthesizeConditional4(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
var factory ast.NodeFactory
|
|
file := factory.NewSourceFile(ast.SourceFileParseOptions{FileName: "/file.ts", Path: "/file.ts"}, "", factory.NewNodeList(
|
|
[]*ast.Node{
|
|
factory.NewExpressionStatement(
|
|
factory.NewConditionalExpression(
|
|
// will be parenthesized on emit:
|
|
factory.NewYieldExpression(nil, nil),
|
|
factory.NewToken(ast.KindQuestionToken),
|
|
factory.NewIdentifier("a"),
|
|
factory.NewToken(ast.KindColonToken),
|
|
factory.NewIdentifier("b"),
|
|
),
|
|
),
|
|
},
|
|
), factory.NewToken(ast.KindEndOfFile))
|
|
|
|
parsetestutil.MarkSyntheticRecursive(file)
|
|
emittestutil.CheckEmit(t, nil, file.AsSourceFile(), "(yield) ? a : b;")
|
|
}
|
|
|
|
func TestParenthesizeConditional5(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
var factory ast.NodeFactory
|
|
file := factory.NewSourceFile(ast.SourceFileParseOptions{FileName: "/file.ts", Path: "/file.ts"}, "", factory.NewNodeList(
|
|
[]*ast.Node{
|
|
factory.NewExpressionStatement(
|
|
factory.NewConditionalExpression(
|
|
factory.NewIdentifier("a"),
|
|
factory.NewToken(ast.KindQuestionToken),
|
|
// will be parenthesized on emit:
|
|
factory.NewBinaryExpression(
|
|
nil, /*modifiers*/
|
|
factory.NewIdentifier("b"),
|
|
nil, /*typeNode*/
|
|
factory.NewToken(ast.KindCommaToken),
|
|
factory.NewIdentifier("c"),
|
|
),
|
|
factory.NewToken(ast.KindColonToken),
|
|
factory.NewIdentifier("d"),
|
|
),
|
|
),
|
|
},
|
|
), factory.NewToken(ast.KindEndOfFile))
|
|
|
|
parsetestutil.MarkSyntheticRecursive(file)
|
|
emittestutil.CheckEmit(t, nil, file.AsSourceFile(), "a ? (b, c) : d;")
|
|
}
|
|
|
|
func TestParenthesizeConditional6(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
var factory ast.NodeFactory
|
|
file := factory.NewSourceFile(ast.SourceFileParseOptions{FileName: "/file.ts", Path: "/file.ts"}, "", factory.NewNodeList(
|
|
[]*ast.Node{
|
|
factory.NewExpressionStatement(
|
|
factory.NewConditionalExpression(
|
|
factory.NewIdentifier("a"),
|
|
factory.NewToken(ast.KindQuestionToken),
|
|
factory.NewIdentifier("b"),
|
|
factory.NewToken(ast.KindColonToken),
|
|
// will be parenthesized on emit:
|
|
factory.NewBinaryExpression(
|
|
nil, /*modifiers*/
|
|
factory.NewIdentifier("c"),
|
|
nil, /*typeNode*/
|
|
factory.NewToken(ast.KindCommaToken),
|
|
factory.NewIdentifier("d"),
|
|
),
|
|
),
|
|
),
|
|
},
|
|
), factory.NewToken(ast.KindEndOfFile))
|
|
|
|
parsetestutil.MarkSyntheticRecursive(file)
|
|
emittestutil.CheckEmit(t, nil, file.AsSourceFile(), "a ? b : (c, d);")
|
|
}
|
|
|
|
func TestParenthesizeYield1(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
var factory ast.NodeFactory
|
|
file := factory.NewSourceFile(ast.SourceFileParseOptions{FileName: "/file.ts", Path: "/file.ts"}, "", factory.NewNodeList(
|
|
[]*ast.Node{
|
|
factory.NewExpressionStatement(
|
|
factory.NewYieldExpression(
|
|
nil, /*asteriskToken*/
|
|
// will be parenthesized on emit:
|
|
factory.NewBinaryExpression(
|
|
nil, /*modifiers*/
|
|
factory.NewIdentifier("a"),
|
|
nil, /*typeNode*/
|
|
factory.NewToken(ast.KindCommaToken),
|
|
factory.NewIdentifier("b"),
|
|
),
|
|
),
|
|
),
|
|
},
|
|
), factory.NewToken(ast.KindEndOfFile))
|
|
|
|
parsetestutil.MarkSyntheticRecursive(file)
|
|
emittestutil.CheckEmit(t, nil, file.AsSourceFile(), "yield (a, b);")
|
|
}
|
|
|
|
// !!! test ASI avoidance from emitExpressionNoASI
|
|
////func TestParenthesizeYield2(t *testing.T) {
|
|
////}
|
|
|
|
func TestParenthesizeSpreadElement1(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
var factory ast.NodeFactory
|
|
file := factory.NewSourceFile(ast.SourceFileParseOptions{FileName: "/file.ts", Path: "/file.ts"}, "", factory.NewNodeList(
|
|
[]*ast.Node{
|
|
factory.NewExpressionStatement(
|
|
factory.NewArrayLiteralExpression(
|
|
factory.NewNodeList(
|
|
[]*ast.Node{
|
|
factory.NewSpreadElement(
|
|
// will be parenthesized on emit:
|
|
factory.NewBinaryExpression(
|
|
nil, /*modifiers*/
|
|
factory.NewIdentifier("a"),
|
|
nil, /*typeNode*/
|
|
factory.NewToken(ast.KindCommaToken),
|
|
factory.NewIdentifier("b"),
|
|
),
|
|
),
|
|
},
|
|
),
|
|
false, /*multiLine*/
|
|
),
|
|
),
|
|
},
|
|
), factory.NewToken(ast.KindEndOfFile))
|
|
|
|
parsetestutil.MarkSyntheticRecursive(file)
|
|
emittestutil.CheckEmit(t, nil, file.AsSourceFile(), "[...(a, b)];")
|
|
}
|
|
|
|
func TestParenthesizeSpreadElement2(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
var factory ast.NodeFactory
|
|
file := factory.NewSourceFile(ast.SourceFileParseOptions{FileName: "/file.ts", Path: "/file.ts"}, "", factory.NewNodeList(
|
|
[]*ast.Node{
|
|
factory.NewExpressionStatement(
|
|
factory.NewCallExpression(
|
|
factory.NewIdentifier("a"),
|
|
nil, /*questionDotToken*/
|
|
nil, /*typeArguments*/
|
|
factory.NewNodeList(
|
|
[]*ast.Node{
|
|
factory.NewSpreadElement(
|
|
// will be parenthesized on emit:
|
|
factory.NewBinaryExpression(
|
|
nil, /*modifiers*/
|
|
factory.NewIdentifier("b"),
|
|
nil, /*typeNode*/
|
|
factory.NewToken(ast.KindCommaToken),
|
|
factory.NewIdentifier("c"),
|
|
),
|
|
),
|
|
},
|
|
),
|
|
ast.NodeFlagsNone,
|
|
),
|
|
),
|
|
},
|
|
), factory.NewToken(ast.KindEndOfFile))
|
|
|
|
parsetestutil.MarkSyntheticRecursive(file)
|
|
emittestutil.CheckEmit(t, nil, file.AsSourceFile(), "a(...(b, c));")
|
|
}
|
|
|
|
func TestParenthesizeSpreadElement3(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
var factory ast.NodeFactory
|
|
file := factory.NewSourceFile(ast.SourceFileParseOptions{FileName: "/file.ts", Path: "/file.ts"}, "", factory.NewNodeList(
|
|
[]*ast.Node{
|
|
factory.NewExpressionStatement(
|
|
factory.NewNewExpression(
|
|
factory.NewIdentifier("a"),
|
|
nil, /*typeArguments*/
|
|
factory.NewNodeList(
|
|
[]*ast.Node{
|
|
factory.NewSpreadElement(
|
|
// will be parenthesized on emit:
|
|
factory.NewBinaryExpression(
|
|
nil, /*modifiers*/
|
|
factory.NewIdentifier("b"),
|
|
nil, /*typeNode*/
|
|
factory.NewToken(ast.KindCommaToken),
|
|
factory.NewIdentifier("c"),
|
|
),
|
|
),
|
|
},
|
|
),
|
|
),
|
|
),
|
|
},
|
|
), factory.NewToken(ast.KindEndOfFile))
|
|
|
|
parsetestutil.MarkSyntheticRecursive(file)
|
|
emittestutil.CheckEmit(t, nil, file.AsSourceFile(), "new a(...(b, c));")
|
|
}
|
|
|
|
func TestParenthesizeExpressionWithTypeArguments(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
var factory ast.NodeFactory
|
|
file := factory.NewSourceFile(ast.SourceFileParseOptions{FileName: "/file.ts", Path: "/file.ts"}, "", factory.NewNodeList(
|
|
[]*ast.Node{
|
|
factory.NewExpressionStatement(
|
|
factory.NewExpressionWithTypeArguments(
|
|
// will be parenthesized on emit:
|
|
factory.NewBinaryExpression(
|
|
nil, /*modifiers*/
|
|
factory.NewIdentifier("a"),
|
|
nil, /*typeNode*/
|
|
factory.NewToken(ast.KindCommaToken),
|
|
factory.NewIdentifier("b"),
|
|
),
|
|
factory.NewNodeList(
|
|
[]*ast.Node{
|
|
factory.NewTypeReferenceNode(
|
|
factory.NewIdentifier("c"),
|
|
nil,
|
|
),
|
|
},
|
|
),
|
|
),
|
|
),
|
|
},
|
|
), factory.NewToken(ast.KindEndOfFile))
|
|
|
|
parsetestutil.MarkSyntheticRecursive(file)
|
|
emittestutil.CheckEmit(t, nil, file.AsSourceFile(), "(a, b)<c>;")
|
|
}
|
|
|
|
func TestParenthesizeAsExpression(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
var factory ast.NodeFactory
|
|
file := factory.NewSourceFile(ast.SourceFileParseOptions{FileName: "/file.ts", Path: "/file.ts"}, "", factory.NewNodeList(
|
|
[]*ast.Node{
|
|
factory.NewExpressionStatement(
|
|
factory.NewAsExpression(
|
|
// will be parenthesized on emit:
|
|
factory.NewBinaryExpression(
|
|
nil, /*modifiers*/
|
|
factory.NewIdentifier("a"),
|
|
nil, /*typeNode*/
|
|
factory.NewToken(ast.KindCommaToken),
|
|
factory.NewIdentifier("b"),
|
|
),
|
|
factory.NewTypeReferenceNode(
|
|
factory.NewIdentifier("c"),
|
|
nil,
|
|
),
|
|
),
|
|
),
|
|
},
|
|
), factory.NewToken(ast.KindEndOfFile))
|
|
|
|
parsetestutil.MarkSyntheticRecursive(file)
|
|
emittestutil.CheckEmit(t, nil, file.AsSourceFile(), "(a, b) as c;")
|
|
}
|
|
|
|
func TestParenthesizeSatisfiesExpression(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
var factory ast.NodeFactory
|
|
file := factory.NewSourceFile(ast.SourceFileParseOptions{FileName: "/file.ts", Path: "/file.ts"}, "", factory.NewNodeList(
|
|
[]*ast.Node{
|
|
factory.NewExpressionStatement(
|
|
factory.NewSatisfiesExpression(
|
|
// will be parenthesized on emit:
|
|
factory.NewBinaryExpression(
|
|
nil, /*modifiers*/
|
|
factory.NewIdentifier("a"),
|
|
nil, /*typeNode*/
|
|
factory.NewToken(ast.KindCommaToken),
|
|
factory.NewIdentifier("b"),
|
|
),
|
|
factory.NewTypeReferenceNode(
|
|
factory.NewIdentifier("c"),
|
|
nil,
|
|
),
|
|
),
|
|
),
|
|
},
|
|
), factory.NewToken(ast.KindEndOfFile))
|
|
|
|
parsetestutil.MarkSyntheticRecursive(file)
|
|
emittestutil.CheckEmit(t, nil, file.AsSourceFile(), "(a, b) satisfies c;")
|
|
}
|
|
|
|
func TestParenthesizeNonNullExpression(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
var factory ast.NodeFactory
|
|
file := factory.NewSourceFile(ast.SourceFileParseOptions{FileName: "/file.ts", Path: "/file.ts"}, "", factory.NewNodeList(
|
|
[]*ast.Node{
|
|
factory.NewExpressionStatement(
|
|
factory.NewNonNullExpression(
|
|
// will be parenthesized on emit:
|
|
factory.NewBinaryExpression(
|
|
nil, /*modifiers*/
|
|
factory.NewIdentifier("a"),
|
|
nil, /*typeNode*/
|
|
factory.NewToken(ast.KindCommaToken),
|
|
factory.NewIdentifier("b"),
|
|
),
|
|
ast.NodeFlagsNone,
|
|
),
|
|
),
|
|
},
|
|
), factory.NewToken(ast.KindEndOfFile))
|
|
|
|
parsetestutil.MarkSyntheticRecursive(file)
|
|
emittestutil.CheckEmit(t, nil, file.AsSourceFile(), "(a, b)!;")
|
|
}
|
|
|
|
func TestParenthesizeExpressionStatement1(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
var factory ast.NodeFactory
|
|
file := factory.NewSourceFile(ast.SourceFileParseOptions{FileName: "/file.ts", Path: "/file.ts"}, "", factory.NewNodeList(
|
|
[]*ast.Node{
|
|
factory.NewExpressionStatement(
|
|
factory.NewObjectLiteralExpression(
|
|
factory.NewNodeList(
|
|
[]*ast.Node{},
|
|
),
|
|
false, /*multiLine*/
|
|
),
|
|
),
|
|
},
|
|
), factory.NewToken(ast.KindEndOfFile))
|
|
|
|
parsetestutil.MarkSyntheticRecursive(file)
|
|
emittestutil.CheckEmit(t, nil, file.AsSourceFile(), "({});")
|
|
}
|
|
|
|
func TestParenthesizeExpressionStatement2(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
var factory ast.NodeFactory
|
|
file := factory.NewSourceFile(ast.SourceFileParseOptions{FileName: "/file.ts", Path: "/file.ts"}, "", factory.NewNodeList(
|
|
[]*ast.Node{
|
|
factory.NewExpressionStatement(
|
|
factory.NewFunctionExpression(
|
|
nil, /*modifiers*/
|
|
nil, /*asteriskToken*/
|
|
nil, /*name*/
|
|
nil, /*typeParameters*/
|
|
factory.NewNodeList(
|
|
[]*ast.Node{},
|
|
),
|
|
nil, /*returnType*/
|
|
nil, /*fullSignature*/
|
|
factory.NewBlock(
|
|
factory.NewNodeList([]*ast.Node{}),
|
|
false, /*multiLine*/
|
|
),
|
|
),
|
|
),
|
|
},
|
|
), factory.NewToken(ast.KindEndOfFile))
|
|
|
|
parsetestutil.MarkSyntheticRecursive(file)
|
|
emittestutil.CheckEmit(t, nil, file.AsSourceFile(), "(function () { });")
|
|
}
|
|
|
|
func TestParenthesizeExpressionStatement3(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
var factory ast.NodeFactory
|
|
file := factory.NewSourceFile(ast.SourceFileParseOptions{FileName: "/file.ts", Path: "/file.ts"}, "", factory.NewNodeList(
|
|
[]*ast.Node{
|
|
factory.NewExpressionStatement(
|
|
factory.NewClassExpression(
|
|
nil, /*modifiers*/
|
|
nil, /*name*/
|
|
nil, /*typeParameters*/
|
|
nil, /*heritageClauses*/
|
|
factory.NewNodeList(
|
|
[]*ast.Node{},
|
|
),
|
|
),
|
|
),
|
|
},
|
|
), factory.NewToken(ast.KindEndOfFile))
|
|
|
|
parsetestutil.MarkSyntheticRecursive(file)
|
|
emittestutil.CheckEmit(t, nil, file.AsSourceFile(), "(class {\n});")
|
|
}
|
|
|
|
func TestParenthesizeExpressionDefault1(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
var factory ast.NodeFactory
|
|
file := factory.NewSourceFile(ast.SourceFileParseOptions{FileName: "/file.ts", Path: "/file.ts"}, "", factory.NewNodeList(
|
|
[]*ast.Node{
|
|
factory.NewExportAssignment(
|
|
nil, /*modifiers*/
|
|
false, /*isExportEquals*/
|
|
nil, /*typeNode*/
|
|
// will be parenthesized on emit:
|
|
factory.NewClassExpression(
|
|
nil, /*modifiers*/
|
|
nil, /*name*/
|
|
nil, /*typeParameters*/
|
|
nil, /*heritageClauses*/
|
|
factory.NewNodeList(
|
|
[]*ast.Node{},
|
|
),
|
|
),
|
|
),
|
|
},
|
|
), factory.NewToken(ast.KindEndOfFile))
|
|
|
|
parsetestutil.MarkSyntheticRecursive(file)
|
|
emittestutil.CheckEmit(t, nil, file.AsSourceFile(), "export default (class {\n});")
|
|
}
|
|
|
|
func TestParenthesizeExpressionDefault2(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
var factory ast.NodeFactory
|
|
file := factory.NewSourceFile(ast.SourceFileParseOptions{FileName: "/file.ts", Path: "/file.ts"}, "", factory.NewNodeList(
|
|
[]*ast.Node{
|
|
factory.NewExportAssignment(
|
|
nil, /*modifiers*/
|
|
false, /*isExportEquals*/
|
|
nil, /*typeNode*/
|
|
// will be parenthesized on emit:
|
|
factory.NewFunctionExpression(
|
|
nil, /*modifiers*/
|
|
nil, /*asteriskToken*/
|
|
nil, /*name*/
|
|
nil, /*typeParameters*/
|
|
factory.NewNodeList(
|
|
[]*ast.Node{},
|
|
),
|
|
nil, /*returnType*/
|
|
nil, /*fullSignature*/
|
|
factory.NewBlock(
|
|
factory.NewNodeList(
|
|
[]*ast.Node{},
|
|
),
|
|
false, /*multiLine*/
|
|
),
|
|
),
|
|
),
|
|
},
|
|
), factory.NewToken(ast.KindEndOfFile))
|
|
|
|
parsetestutil.MarkSyntheticRecursive(file)
|
|
emittestutil.CheckEmit(t, nil, file.AsSourceFile(), "export default (function () { });")
|
|
}
|
|
|
|
func TestParenthesizeExpressionDefault3(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
var factory ast.NodeFactory
|
|
file := factory.NewSourceFile(ast.SourceFileParseOptions{FileName: "/file.ts", Path: "/file.ts"}, "", factory.NewNodeList(
|
|
[]*ast.Node{
|
|
factory.NewExportAssignment(
|
|
nil, /*modifiers*/
|
|
false, /*isExportEquals*/
|
|
nil, /*typeNode*/
|
|
// will be parenthesized on emit:
|
|
factory.NewBinaryExpression(
|
|
nil, /*modifiers*/
|
|
factory.NewIdentifier("a"),
|
|
nil, /*typeNode*/
|
|
factory.NewToken(ast.KindCommaToken),
|
|
factory.NewIdentifier("b"),
|
|
),
|
|
),
|
|
},
|
|
), factory.NewToken(ast.KindEndOfFile))
|
|
|
|
parsetestutil.MarkSyntheticRecursive(file)
|
|
emittestutil.CheckEmit(t, nil, file.AsSourceFile(), "export default (a, b);")
|
|
}
|
|
|
|
func TestParenthesizeArrayType(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
var factory ast.NodeFactory
|
|
file := factory.NewSourceFile(ast.SourceFileParseOptions{FileName: "/file.ts", Path: "/file.ts"}, "", factory.NewNodeList(
|
|
[]*ast.Node{
|
|
factory.NewTypeAliasDeclaration(
|
|
nil, /*modifiers*/
|
|
factory.NewIdentifier("_"), /*name*/
|
|
nil, /*typeParameters*/
|
|
factory.NewArrayTypeNode(
|
|
// will be parenthesized on emit:
|
|
factory.NewUnionTypeNode(
|
|
factory.NewNodeList(
|
|
[]*ast.Node{
|
|
factory.NewTypeReferenceNode(factory.NewIdentifier("a"), nil /*typeArguments*/),
|
|
factory.NewTypeReferenceNode(factory.NewIdentifier("b"), nil /*typeArguments*/),
|
|
},
|
|
),
|
|
),
|
|
),
|
|
),
|
|
},
|
|
), factory.NewToken(ast.KindEndOfFile))
|
|
|
|
parsetestutil.MarkSyntheticRecursive(file)
|
|
emittestutil.CheckEmit(t, nil, file.AsSourceFile(), "type _ = (a | b)[];")
|
|
}
|
|
|
|
func TestParenthesizeOptionalType(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
var factory ast.NodeFactory
|
|
file := factory.NewSourceFile(ast.SourceFileParseOptions{FileName: "/file.ts", Path: "/file.ts"}, "", factory.NewNodeList(
|
|
[]*ast.Node{
|
|
factory.NewTypeAliasDeclaration(
|
|
nil, /*modifiers*/
|
|
factory.NewIdentifier("_"), /*name*/
|
|
nil, /*typeParameters*/
|
|
factory.NewTupleTypeNode(
|
|
factory.NewNodeList(
|
|
[]*ast.Node{
|
|
factory.NewOptionalTypeNode(
|
|
// will be parenthesized on emit:
|
|
factory.NewUnionTypeNode(
|
|
factory.NewNodeList(
|
|
[]*ast.Node{
|
|
factory.NewTypeReferenceNode(factory.NewIdentifier("a"), nil /*typeArguments*/),
|
|
factory.NewTypeReferenceNode(factory.NewIdentifier("b"), nil /*typeArguments*/),
|
|
},
|
|
),
|
|
),
|
|
),
|
|
},
|
|
),
|
|
),
|
|
),
|
|
},
|
|
), factory.NewToken(ast.KindEndOfFile))
|
|
|
|
parsetestutil.MarkSyntheticRecursive(file)
|
|
emittestutil.CheckEmit(t, nil, file.AsSourceFile(), "type _ = [\n (a | b)?\n];")
|
|
}
|
|
|
|
func TestParenthesizeUnionType1(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
var factory ast.NodeFactory
|
|
file := factory.NewSourceFile(ast.SourceFileParseOptions{FileName: "/file.ts", Path: "/file.ts"}, "", factory.NewNodeList(
|
|
[]*ast.Node{
|
|
factory.NewTypeAliasDeclaration(
|
|
nil, /*modifiers*/
|
|
factory.NewIdentifier("_"), /*name*/
|
|
nil, /*typeParameters*/
|
|
factory.NewUnionTypeNode(
|
|
factory.NewNodeList(
|
|
[]*ast.Node{
|
|
factory.NewTypeReferenceNode(factory.NewIdentifier("a"), nil /*typeArguments*/),
|
|
// will be parenthesized on emit:
|
|
factory.NewFunctionTypeNode(
|
|
nil, /*typeParameters*/
|
|
factory.NewNodeList(
|
|
[]*ast.Node{},
|
|
),
|
|
factory.NewTypeReferenceNode(factory.NewIdentifier("b"), nil /*typeArguments*/),
|
|
),
|
|
},
|
|
),
|
|
),
|
|
),
|
|
},
|
|
), factory.NewToken(ast.KindEndOfFile))
|
|
|
|
parsetestutil.MarkSyntheticRecursive(file)
|
|
emittestutil.CheckEmit(t, nil, file.AsSourceFile(), "type _ = a | (() => b);")
|
|
}
|
|
|
|
func TestParenthesizeUnionType2(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
var factory ast.NodeFactory
|
|
file := factory.NewSourceFile(ast.SourceFileParseOptions{FileName: "/file.ts", Path: "/file.ts"}, "", factory.NewNodeList(
|
|
[]*ast.Node{
|
|
factory.NewTypeAliasDeclaration(
|
|
nil, /*modifiers*/
|
|
factory.NewIdentifier("_"), /*name*/
|
|
nil, /*typeParameters*/
|
|
factory.NewUnionTypeNode(
|
|
factory.NewNodeList(
|
|
[]*ast.Node{
|
|
// will be parenthesized on emit:
|
|
factory.NewInferTypeNode(
|
|
factory.NewTypeParameterDeclaration(
|
|
nil,
|
|
factory.NewIdentifier("a"),
|
|
factory.NewTypeReferenceNode(factory.NewIdentifier("b"), nil /*typeArguments*/),
|
|
nil, /*defaultType*/
|
|
),
|
|
),
|
|
factory.NewTypeReferenceNode(factory.NewIdentifier("c"), nil /*typeArguments*/),
|
|
},
|
|
),
|
|
),
|
|
),
|
|
},
|
|
), factory.NewToken(ast.KindEndOfFile))
|
|
|
|
parsetestutil.MarkSyntheticRecursive(file)
|
|
emittestutil.CheckEmit(t, nil, file.AsSourceFile(), "type _ = (infer a extends b) | c;")
|
|
}
|
|
|
|
func TestParenthesizeIntersectionType(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
var factory ast.NodeFactory
|
|
file := factory.NewSourceFile(ast.SourceFileParseOptions{FileName: "/file.ts", Path: "/file.ts"}, "", factory.NewNodeList(
|
|
[]*ast.Node{
|
|
factory.NewTypeAliasDeclaration(
|
|
nil, /*modifiers*/
|
|
factory.NewIdentifier("_"), /*name*/
|
|
nil, /*typeParameters*/
|
|
factory.NewIntersectionTypeNode(
|
|
factory.NewNodeList(
|
|
[]*ast.Node{
|
|
factory.NewTypeReferenceNode(factory.NewIdentifier("a"), nil /*typeArguments*/),
|
|
// will be parenthesized on emit:
|
|
factory.NewUnionTypeNode(
|
|
factory.NewNodeList(
|
|
[]*ast.Node{
|
|
factory.NewTypeReferenceNode(factory.NewIdentifier("b"), nil /*typeArguments*/),
|
|
factory.NewTypeReferenceNode(factory.NewIdentifier("c"), nil /*typeArguments*/),
|
|
},
|
|
),
|
|
),
|
|
},
|
|
),
|
|
),
|
|
),
|
|
},
|
|
), factory.NewToken(ast.KindEndOfFile))
|
|
|
|
parsetestutil.MarkSyntheticRecursive(file)
|
|
emittestutil.CheckEmit(t, nil, file.AsSourceFile(), "type _ = a & (b | c);")
|
|
}
|
|
|
|
func TestParenthesizeReadonlyTypeOperator1(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
var factory ast.NodeFactory
|
|
file := factory.NewSourceFile(ast.SourceFileParseOptions{FileName: "/file.ts", Path: "/file.ts"}, "", factory.NewNodeList(
|
|
[]*ast.Node{
|
|
factory.NewTypeAliasDeclaration(
|
|
nil, /*modifiers*/
|
|
factory.NewIdentifier("_"), /*name*/
|
|
nil, /*typeParameters*/
|
|
factory.NewTypeOperatorNode(
|
|
ast.KindReadonlyKeyword,
|
|
// will be parenthesized on emit:
|
|
factory.NewUnionTypeNode(
|
|
factory.NewNodeList(
|
|
[]*ast.Node{
|
|
factory.NewTypeReferenceNode(factory.NewIdentifier("a"), nil /*typeArguments*/),
|
|
factory.NewTypeReferenceNode(factory.NewIdentifier("b"), nil /*typeArguments*/),
|
|
},
|
|
),
|
|
),
|
|
),
|
|
),
|
|
},
|
|
), factory.NewToken(ast.KindEndOfFile))
|
|
|
|
parsetestutil.MarkSyntheticRecursive(file)
|
|
emittestutil.CheckEmit(t, nil, file.AsSourceFile(), "type _ = readonly (a | b);")
|
|
}
|
|
|
|
func TestParenthesizeReadonlyTypeOperator2(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
var factory ast.NodeFactory
|
|
file := factory.NewSourceFile(ast.SourceFileParseOptions{FileName: "/file.ts", Path: "/file.ts"}, "", factory.NewNodeList(
|
|
[]*ast.Node{
|
|
factory.NewTypeAliasDeclaration(
|
|
nil, /*modifiers*/
|
|
factory.NewIdentifier("_"), /*name*/
|
|
nil, /*typeParameters*/
|
|
factory.NewTypeOperatorNode(
|
|
ast.KindReadonlyKeyword,
|
|
// will be parenthesized on emit:
|
|
factory.NewTypeOperatorNode(
|
|
ast.KindKeyOfKeyword,
|
|
factory.NewTypeReferenceNode(factory.NewIdentifier("a"), nil /*typeArguments*/),
|
|
),
|
|
),
|
|
),
|
|
},
|
|
), factory.NewToken(ast.KindEndOfFile))
|
|
|
|
parsetestutil.MarkSyntheticRecursive(file)
|
|
emittestutil.CheckEmit(t, nil, file.AsSourceFile(), "type _ = readonly (keyof a);")
|
|
}
|
|
|
|
func TestParenthesizeKeyofTypeOperator(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
var factory ast.NodeFactory
|
|
file := factory.NewSourceFile(ast.SourceFileParseOptions{FileName: "/file.ts", Path: "/file.ts"}, "", factory.NewNodeList(
|
|
[]*ast.Node{
|
|
factory.NewTypeAliasDeclaration(
|
|
nil, /*modifiers*/
|
|
factory.NewIdentifier("_"), /*name*/
|
|
nil, /*typeParameters*/
|
|
factory.NewTypeOperatorNode(
|
|
ast.KindKeyOfKeyword,
|
|
// will be parenthesized on emit:
|
|
factory.NewUnionTypeNode(
|
|
factory.NewNodeList(
|
|
[]*ast.Node{
|
|
factory.NewTypeReferenceNode(factory.NewIdentifier("a"), nil /*typeArguments*/),
|
|
factory.NewTypeReferenceNode(factory.NewIdentifier("b"), nil /*typeArguments*/),
|
|
},
|
|
),
|
|
),
|
|
),
|
|
),
|
|
},
|
|
), factory.NewToken(ast.KindEndOfFile))
|
|
|
|
parsetestutil.MarkSyntheticRecursive(file)
|
|
emittestutil.CheckEmit(t, nil, file.AsSourceFile(), "type _ = keyof (a | b);")
|
|
}
|
|
|
|
func TestParenthesizeIndexedAccessType(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
var factory ast.NodeFactory
|
|
file := factory.NewSourceFile(ast.SourceFileParseOptions{FileName: "/file.ts", Path: "/file.ts"}, "", factory.NewNodeList(
|
|
[]*ast.Node{
|
|
factory.NewTypeAliasDeclaration(
|
|
nil, /*modifiers*/
|
|
factory.NewIdentifier("_"), /*name*/
|
|
nil, /*typeParameters*/
|
|
factory.NewIndexedAccessTypeNode(
|
|
// will be parenthesized on emit:
|
|
factory.NewUnionTypeNode(
|
|
factory.NewNodeList(
|
|
[]*ast.Node{
|
|
factory.NewTypeReferenceNode(factory.NewIdentifier("a"), nil /*typeArguments*/),
|
|
factory.NewTypeReferenceNode(factory.NewIdentifier("b"), nil /*typeArguments*/),
|
|
},
|
|
),
|
|
),
|
|
factory.NewTypeReferenceNode(factory.NewIdentifier("c"), nil /*typeArguments*/),
|
|
),
|
|
),
|
|
},
|
|
), factory.NewToken(ast.KindEndOfFile))
|
|
|
|
parsetestutil.MarkSyntheticRecursive(file)
|
|
emittestutil.CheckEmit(t, nil, file.AsSourceFile(), "type _ = (a | b)[c];")
|
|
}
|
|
|
|
func TestParenthesizeConditionalType1(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
var factory ast.NodeFactory
|
|
file := factory.NewSourceFile(ast.SourceFileParseOptions{FileName: "/file.ts", Path: "/file.ts"}, "", factory.NewNodeList(
|
|
[]*ast.Node{
|
|
factory.NewTypeAliasDeclaration(
|
|
nil, /*modifiers*/
|
|
factory.NewIdentifier("_"), /*name*/
|
|
nil, /*typeParameters*/
|
|
factory.NewConditionalTypeNode(
|
|
// will be parenthesized on emit:
|
|
factory.NewFunctionTypeNode(
|
|
nil, /*typeParameters*/
|
|
factory.NewNodeList(
|
|
[]*ast.Node{},
|
|
),
|
|
factory.NewTypeReferenceNode(factory.NewIdentifier("a"), nil /*typeArguments*/),
|
|
),
|
|
factory.NewTypeReferenceNode(factory.NewIdentifier("b"), nil /*typeArguments*/),
|
|
factory.NewTypeReferenceNode(factory.NewIdentifier("c"), nil /*typeArguments*/),
|
|
factory.NewTypeReferenceNode(factory.NewIdentifier("d"), nil /*typeArguments*/),
|
|
),
|
|
),
|
|
},
|
|
), factory.NewToken(ast.KindEndOfFile))
|
|
|
|
parsetestutil.MarkSyntheticRecursive(file)
|
|
emittestutil.CheckEmit(t, nil, file.AsSourceFile(), "type _ = (() => a) extends b ? c : d;")
|
|
}
|
|
|
|
func TestParenthesizeConditionalType2(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
var factory ast.NodeFactory
|
|
file := factory.NewSourceFile(ast.SourceFileParseOptions{FileName: "/file.ts", Path: "/file.ts"}, "", factory.NewNodeList(
|
|
[]*ast.Node{
|
|
factory.NewTypeAliasDeclaration(
|
|
nil, /*modifiers*/
|
|
factory.NewIdentifier("_"), /*name*/
|
|
nil, /*typeParameters*/
|
|
factory.NewConditionalTypeNode(
|
|
factory.NewTypeReferenceNode(factory.NewIdentifier("a"), nil /*typeArguments*/),
|
|
// will be parenthesized on emit:
|
|
factory.NewConditionalTypeNode(
|
|
factory.NewTypeReferenceNode(factory.NewIdentifier("b"), nil /*typeArguments*/),
|
|
factory.NewTypeReferenceNode(factory.NewIdentifier("c"), nil /*typeArguments*/),
|
|
factory.NewTypeReferenceNode(factory.NewIdentifier("d"), nil /*typeArguments*/),
|
|
factory.NewTypeReferenceNode(factory.NewIdentifier("e"), nil /*typeArguments*/),
|
|
),
|
|
factory.NewTypeReferenceNode(factory.NewIdentifier("f"), nil /*typeArguments*/),
|
|
factory.NewTypeReferenceNode(factory.NewIdentifier("g"), nil /*typeArguments*/),
|
|
),
|
|
),
|
|
},
|
|
), factory.NewToken(ast.KindEndOfFile))
|
|
|
|
parsetestutil.MarkSyntheticRecursive(file)
|
|
emittestutil.CheckEmit(t, nil, file.AsSourceFile(), "type _ = a extends (b extends c ? d : e) ? f : g;")
|
|
}
|
|
|
|
func TestParenthesizeConditionalType3(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
var factory ast.NodeFactory
|
|
file := factory.NewSourceFile(ast.SourceFileParseOptions{FileName: "/file.ts", Path: "/file.ts"}, "", factory.NewNodeList(
|
|
[]*ast.Node{
|
|
factory.NewTypeAliasDeclaration(
|
|
nil, /*modifiers*/
|
|
factory.NewIdentifier("_"), /*name*/
|
|
nil, /*typeParameters*/
|
|
factory.NewConditionalTypeNode(
|
|
factory.NewTypeReferenceNode(factory.NewIdentifier("a"), nil /*typeArguments*/),
|
|
factory.NewFunctionTypeNode(
|
|
nil, /*typeParameters*/
|
|
factory.NewNodeList(
|
|
[]*ast.Node{},
|
|
),
|
|
// will be parenthesized on emit:
|
|
factory.NewInferTypeNode(
|
|
factory.NewTypeParameterDeclaration(
|
|
nil,
|
|
factory.NewIdentifier("b"),
|
|
factory.NewTypeReferenceNode(factory.NewIdentifier("c"), nil /*typeArguments*/),
|
|
nil, /*defaultType*/
|
|
),
|
|
),
|
|
),
|
|
factory.NewTypeReferenceNode(factory.NewIdentifier("d"), nil /*typeArguments*/),
|
|
factory.NewTypeReferenceNode(factory.NewIdentifier("e"), nil /*typeArguments*/),
|
|
),
|
|
),
|
|
},
|
|
), factory.NewToken(ast.KindEndOfFile))
|
|
|
|
parsetestutil.MarkSyntheticRecursive(file)
|
|
emittestutil.CheckEmit(t, nil, file.AsSourceFile(), "type _ = a extends () => (infer b extends c) ? d : e;")
|
|
}
|
|
|
|
func TestParenthesizeConditionalType4(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
var factory ast.NodeFactory
|
|
file := factory.NewSourceFile(ast.SourceFileParseOptions{FileName: "/file.ts", Path: "/file.ts"}, "", factory.NewNodeList([]*ast.Node{
|
|
factory.NewTypeAliasDeclaration(
|
|
nil, /*modifiers*/
|
|
factory.NewIdentifier("_"), /*name*/
|
|
nil, /*typeParameters*/
|
|
factory.NewConditionalTypeNode(
|
|
factory.NewTypeReferenceNode(factory.NewIdentifier("a"), nil /*typeArguments*/),
|
|
factory.NewFunctionTypeNode(
|
|
nil, /*typeParameters*/
|
|
factory.NewNodeList(
|
|
[]*ast.Node{},
|
|
),
|
|
// will be parenthesized on emit:
|
|
factory.NewUnionTypeNode(
|
|
factory.NewNodeList(
|
|
[]*ast.Node{
|
|
factory.NewInferTypeNode(
|
|
factory.NewTypeParameterDeclaration(
|
|
nil,
|
|
factory.NewIdentifier("b"),
|
|
factory.NewTypeReferenceNode(factory.NewIdentifier("c"), nil /*typeArguments*/),
|
|
nil, /*defaultType*/
|
|
),
|
|
),
|
|
factory.NewTypeReferenceNode(factory.NewIdentifier("d"), nil /*typeArguments*/),
|
|
},
|
|
),
|
|
),
|
|
),
|
|
factory.NewTypeReferenceNode(factory.NewIdentifier("e"), nil /*typeArguments*/),
|
|
factory.NewTypeReferenceNode(factory.NewIdentifier("f"), nil /*typeArguments*/),
|
|
),
|
|
),
|
|
}), factory.NewToken(ast.KindEndOfFile))
|
|
|
|
parsetestutil.MarkSyntheticRecursive(file)
|
|
emittestutil.CheckEmit(t, nil, file.AsSourceFile(), "type _ = a extends () => (infer b extends c) | d ? e : f;")
|
|
}
|
|
|
|
func TestNameGeneration(t *testing.T) {
|
|
t.Parallel()
|
|
ec := printer.NewEmitContext()
|
|
file := ec.Factory.NewSourceFile(ast.SourceFileParseOptions{FileName: "/file.ts", Path: "/file.ts"}, "", ec.Factory.NewNodeList([]*ast.Node{
|
|
ec.Factory.NewVariableStatement(nil, ec.Factory.NewVariableDeclarationList(
|
|
ast.NodeFlagsNone,
|
|
ec.Factory.NewNodeList([]*ast.Node{
|
|
ec.Factory.NewVariableDeclaration(ec.Factory.NewTempVariable(), nil, nil, nil),
|
|
}),
|
|
)),
|
|
ec.Factory.NewFunctionDeclaration(
|
|
nil,
|
|
nil,
|
|
ec.Factory.NewIdentifier("f"),
|
|
nil,
|
|
ec.Factory.NewNodeList([]*ast.Node{}),
|
|
nil,
|
|
nil,
|
|
ec.Factory.NewBlock(ec.Factory.NewNodeList([]*ast.Node{
|
|
ec.Factory.NewVariableStatement(nil, ec.Factory.NewVariableDeclarationList(
|
|
ast.NodeFlagsNone,
|
|
ec.Factory.NewNodeList([]*ast.Node{
|
|
ec.Factory.NewVariableDeclaration(ec.Factory.NewTempVariable(), nil, nil, nil),
|
|
}),
|
|
)),
|
|
}), true),
|
|
),
|
|
}), ec.Factory.NewToken(ast.KindEndOfFile))
|
|
|
|
parsetestutil.MarkSyntheticRecursive(file)
|
|
emittestutil.CheckEmit(t, ec, file.AsSourceFile(), "var _a;\nfunction f() {\n var _a;\n}")
|
|
}
|
|
|
|
func TestNoTrailingCommaAfterTransform(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
file := parsetestutil.ParseTypeScript("[a!]", false /*jsx*/)
|
|
emitContext := printer.NewEmitContext()
|
|
|
|
var visitor *ast.NodeVisitor
|
|
visitor = emitContext.NewNodeVisitor(func(node *ast.Node) *ast.Node {
|
|
switch node.Kind {
|
|
case ast.KindNonNullExpression:
|
|
node = node.AsNonNullExpression().Expression
|
|
default:
|
|
node = node.VisitEachChild(visitor)
|
|
}
|
|
return node
|
|
})
|
|
file = visitor.VisitSourceFile(file)
|
|
|
|
emittestutil.CheckEmit(t, emitContext, file.AsSourceFile(), "[a];")
|
|
}
|
|
|
|
func TestTrailingCommaAfterTransform(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
file := parsetestutil.ParseTypeScript("[a!,]", false /*jsx*/)
|
|
emitContext := printer.NewEmitContext()
|
|
|
|
var visitor *ast.NodeVisitor
|
|
visitor = emitContext.NewNodeVisitor(func(node *ast.Node) *ast.Node {
|
|
switch node.Kind {
|
|
case ast.KindNonNullExpression:
|
|
node = node.AsNonNullExpression().Expression
|
|
default:
|
|
node = node.VisitEachChild(visitor)
|
|
}
|
|
return node
|
|
})
|
|
file = visitor.VisitSourceFile(file)
|
|
|
|
emittestutil.CheckEmit(t, emitContext, file.AsSourceFile(), "[a,];")
|
|
}
|
|
|
|
func TestPartiallyEmittedExpression(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
compilerOptions := &core.CompilerOptions{}
|
|
|
|
file := parsetestutil.ParseTypeScript(`return ((container.parent
|
|
.left as PropertyAccessExpression)
|
|
.expression as PropertyAccessExpression)
|
|
.expression;`, false /*jsx*/)
|
|
|
|
emitContext := printer.NewEmitContext()
|
|
file = tstransforms.NewTypeEraserTransformer(&transformers.TransformOptions{CompilerOptions: compilerOptions, Context: emitContext}).TransformSourceFile(file)
|
|
emittestutil.CheckEmit(t, emitContext, file.AsSourceFile(), `return container.parent
|
|
.left
|
|
.expression
|
|
.expression;`)
|
|
}
|