• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1namespace ts {
2    describe("unittests:: PrinterAPI", () => {
3        function makePrintsCorrectly(prefix: string) {
4            return function printsCorrectly(name: string, options: PrinterOptions, printCallback: (printer: Printer) => string) {
5                it(name, () => {
6                    Harness.Baseline.runBaseline(`printerApi/${prefix}.${name}.js`,
7                        printCallback(createPrinter({ newLine: NewLineKind.CarriageReturnLineFeed, ...options })));
8                });
9            };
10        }
11
12        describe("printFile", () => {
13            const printsCorrectly = makePrintsCorrectly("printsFileCorrectly");
14            describe("comment handling", () => {
15                // Avoid eagerly creating the sourceFile so that `createSourceFile` doesn't run unless one of these tests is run.
16                let sourceFile: SourceFile;
17                before(() => {
18                    sourceFile = createSourceFile("source.ts", `
19                        interface A<T> {
20                            // comment1
21                            readonly prop?: T;
22
23                            // comment2
24                            method(): void;
25
26                            // comment3
27                            new <T>(): A<T>;
28
29                            // comment4
30                            <T>(): A<T>;
31                        }
32
33                        // comment5
34                        type B = number | string | object;
35                        type C = A<number> & { x: string; }; // comment6
36
37                        // comment7
38                        enum E1 {
39                            // comment8
40                            first
41                        }
42
43                        const enum E2 {
44                            second
45                        }
46
47                        // comment9
48                        console.log(1 + 2);
49
50                        // comment10
51                        function functionWithDefaultArgValue(argument: string = "defaultValue"): void { }
52                    `, ScriptTarget.ES2015);
53                });
54                printsCorrectly("default", {}, printer => printer.printFile(sourceFile));
55                printsCorrectly("removeComments", { removeComments: true }, printer => printer.printFile(sourceFile));
56            });
57
58            // https://github.com/microsoft/TypeScript/issues/14948
59            // eslint-disable-next-line no-template-curly-in-string
60            printsCorrectly("templateLiteral", {}, printer => printer.printFile(createSourceFile("source.ts", "let greeting = `Hi ${name}, how are you?`;", ScriptTarget.ES2017)));
61
62            // https://github.com/microsoft/TypeScript/issues/18071
63            printsCorrectly("regularExpressionLiteral", {}, printer => printer.printFile(createSourceFile("source.ts", "let regex = /abc/;", ScriptTarget.ES2017)));
64
65            // https://github.com/microsoft/TypeScript/issues/22239
66            printsCorrectly("importStatementRemoveComments", { removeComments: true }, printer => printer.printFile(createSourceFile("source.ts", "import {foo} from 'foo';", ScriptTarget.ESNext)));
67            printsCorrectly("classHeritageClauses", {}, printer => printer.printFile(createSourceFile(
68                "source.ts",
69                `class A extends B implements C implements D {}`,
70                ScriptTarget.ES2017
71            )));
72
73            // https://github.com/microsoft/TypeScript/issues/35093
74            printsCorrectly("definiteAssignmentAssertions", {}, printer => printer.printFile(createSourceFile(
75                "source.ts",
76                `class A {
77                    prop!: string;
78                }
79
80                let x!: string;`,
81                ScriptTarget.ES2017
82            )));
83
84            // https://github.com/microsoft/TypeScript/issues/35054
85            printsCorrectly("jsx attribute escaping", {}, printer => {
86                return printer.printFile(createSourceFile(
87                    "source.ts",
88                    String.raw`<a x='\\"'/>`,
89                    ScriptTarget.ESNext,
90                    /*setParentNodes*/ undefined,
91                    ScriptKind.TSX
92                ));
93            });
94        });
95
96        describe("No duplicate ref directives when emiting .d.ts->.d.ts", () => {
97            it("without statements", () => {
98                const host = new fakes.CompilerHost(new vfs.FileSystem(true, {
99                    files: {
100                        "/test.d.ts": `/// <reference types="node" />\n/// <reference path="./src/test.d.ts />\n`
101                    }
102                }));
103                const program = createProgram(["/test.d.ts"], { }, host);
104                const file = program.getSourceFile("/test.d.ts")!;
105                const printer = createPrinter({ newLine: NewLineKind.CarriageReturnLineFeed });
106                const output = printer.printFile(file);
107                assert.equal(output.split(/\r?\n/g).length, 3);
108            });
109            it("with statements", () => {
110                const host = new fakes.CompilerHost(new vfs.FileSystem(true, {
111                    files: {
112                        "/test.d.ts": `/// <reference types="node" />\n/// <reference path="./src/test.d.ts />\nvar a: number;\n`
113                    }
114                }));
115                const program = createProgram(["/test.d.ts"], { }, host);
116                const file = program.getSourceFile("/test.d.ts")!;
117                const printer = createPrinter({ newLine: NewLineKind.CarriageReturnLineFeed });
118                const output = printer.printFile(file);
119                assert.equal(output.split(/\r?\n/g).length, 4);
120            });
121        });
122
123        describe("printBundle", () => {
124            const printsCorrectly = makePrintsCorrectly("printsBundleCorrectly");
125            let bundle: Bundle;
126            before(() => {
127                bundle = factory.createBundle([
128                    createSourceFile("a.ts", `
129                        /*! [a.ts] */
130
131                        // comment0
132                        const a = 1;
133                    `, ScriptTarget.ES2015),
134                    createSourceFile("b.ts", `
135                        /*! [b.ts] */
136
137                        // comment1
138                        const b = 2;
139                    `, ScriptTarget.ES2015)
140                ]);
141            });
142            printsCorrectly("default", {}, printer => printer.printBundle(bundle));
143            printsCorrectly("removeComments", { removeComments: true }, printer => printer.printBundle(bundle));
144        });
145
146        describe("printNode", () => {
147            const printsCorrectly = makePrintsCorrectly("printsNodeCorrectly");
148            printsCorrectly("class", {}, printer => printer.printNode(
149                EmitHint.Unspecified,
150                factory.createClassDeclaration(
151                    /*modifiers*/ undefined,
152                    /*name*/ factory.createIdentifier("C"),
153                    /*typeParameters*/ undefined,
154                    /*heritageClauses*/ undefined,
155                    [factory.createPropertyDeclaration(
156                        factory.createNodeArray([factory.createToken(SyntaxKind.PublicKeyword)]),
157                        factory.createIdentifier("prop"),
158                        /*questionToken*/ undefined,
159                        /*type*/ undefined,
160                        /*initializer*/ undefined
161                    )]
162                ),
163                createSourceFile("source.ts", "", ScriptTarget.ES2015)
164            ));
165
166            printsCorrectly("namespaceExportDeclaration", {}, printer => printer.printNode(
167                EmitHint.Unspecified,
168                factory.createNamespaceExportDeclaration("B"),
169                createSourceFile("source.ts", "", ScriptTarget.ES2015)
170            ));
171
172            printsCorrectly("newExpressionWithPropertyAccessOnCallExpression", {}, printer => printer.printNode(
173                EmitHint.Unspecified,
174                factory.createNewExpression(
175                    factory.createPropertyAccessExpression(
176                        factory.createCallExpression(factory.createIdentifier("f"), /*typeArguments*/ undefined, /*argumentsArray*/ undefined),
177                        "x"),
178                    /*typeArguments*/ undefined,
179                    /*argumentsArray*/ undefined
180                ),
181                createSourceFile("source.ts", "", ScriptTarget.ESNext))
182            );
183
184            printsCorrectly("newExpressionOnConditionalExpression", {}, printer => printer.printNode(
185                EmitHint.Unspecified,
186                factory.createNewExpression(
187                    factory.createConditionalExpression(
188                        factory.createIdentifier("x"), factory.createToken(SyntaxKind.QuestionToken),
189                        factory.createIdentifier("y"), factory.createToken(SyntaxKind.ColonToken),
190                        factory.createIdentifier("z")),
191                    /*typeArguments*/ undefined,
192                    /*argumentsArray*/ undefined
193                ),
194                createSourceFile("source.ts", "", ScriptTarget.ESNext))
195            );
196
197            printsCorrectly("emptyGlobalAugmentation", {}, printer => printer.printNode(
198                EmitHint.Unspecified,
199                factory.createModuleDeclaration(
200                    /*modifiers*/ [factory.createToken(SyntaxKind.DeclareKeyword)],
201                    factory.createIdentifier("global"),
202                    factory.createModuleBlock(emptyArray),
203                    NodeFlags.GlobalAugmentation),
204                createSourceFile("source.ts", "", ScriptTarget.ES2015)
205            ));
206
207            printsCorrectly("emptyGlobalAugmentationWithNoDeclareKeyword", {}, printer => printer.printNode(
208                EmitHint.Unspecified,
209                factory.createModuleDeclaration(
210                    /*modifiers*/ undefined,
211                    factory.createIdentifier("global"),
212                    factory.createModuleBlock(emptyArray),
213                    NodeFlags.GlobalAugmentation),
214                createSourceFile("source.ts", "", ScriptTarget.ES2015)
215            ));
216
217            // https://github.com/Microsoft/TypeScript/issues/15971
218            printsCorrectly("classWithOptionalMethodAndProperty", {}, printer => printer.printNode(
219                EmitHint.Unspecified,
220                factory.createClassDeclaration(
221                    /*modifiers*/ [factory.createToken(SyntaxKind.DeclareKeyword)],
222                    /*name*/ factory.createIdentifier("X"),
223                    /*typeParameters*/ undefined,
224                    /*heritageClauses*/ undefined,
225                    [
226                        factory.createMethodDeclaration(
227                            /*modifiers*/ undefined,
228                            /*asteriskToken*/ undefined,
229                            /*name*/ factory.createIdentifier("method"),
230                            /*questionToken*/ factory.createToken(SyntaxKind.QuestionToken),
231                            /*typeParameters*/ undefined,
232                            [],
233                            /*type*/ factory.createKeywordTypeNode(SyntaxKind.VoidKeyword),
234                            /*body*/ undefined
235                        ),
236                        factory.createPropertyDeclaration(
237                            /*modifiers*/ undefined,
238                            /*name*/ factory.createIdentifier("property"),
239                            /*questionToken*/ factory.createToken(SyntaxKind.QuestionToken),
240                            /*type*/ factory.createKeywordTypeNode(SyntaxKind.StringKeyword),
241                            /*initializer*/ undefined
242                        ),
243                    ]
244                ),
245                createSourceFile("source.ts", "", ScriptTarget.ES2015)
246            ));
247
248            // https://github.com/Microsoft/TypeScript/issues/15651
249            printsCorrectly("functionTypes", {}, printer => printer.printNode(
250                EmitHint.Unspecified,
251                setEmitFlags(factory.createTupleTypeNode([
252                    factory.createFunctionTypeNode(
253                        /*typeArguments*/ undefined,
254                        [factory.createParameterDeclaration(
255                            /*modifiers*/ undefined,
256                            /*dotDotDotToken*/ undefined,
257                            factory.createIdentifier("args")
258                        )],
259                        factory.createKeywordTypeNode(SyntaxKind.AnyKeyword)
260                    ),
261                    factory.createFunctionTypeNode(
262                        [factory.createTypeParameterDeclaration(/*modifiers*/ undefined, "T")],
263                        [factory.createParameterDeclaration(
264                            /*modifiers*/ undefined,
265                            /*dotDotDotToken*/ undefined,
266                            factory.createIdentifier("args")
267                        )],
268                        factory.createKeywordTypeNode(SyntaxKind.AnyKeyword)
269                    ),
270                    factory.createFunctionTypeNode(
271                        /*typeArguments*/ undefined,
272                        [factory.createParameterDeclaration(
273                            /*modifiers*/ undefined,
274                            factory.createToken(SyntaxKind.DotDotDotToken),
275                            factory.createIdentifier("args")
276                        )],
277                        factory.createKeywordTypeNode(SyntaxKind.AnyKeyword)
278                    ),
279                    factory.createFunctionTypeNode(
280                        /*typeArguments*/ undefined,
281                        [factory.createParameterDeclaration(
282                            /*modifiers*/ undefined,
283                            /*dotDotDotToken*/ undefined,
284                            factory.createIdentifier("args"),
285                            factory.createToken(SyntaxKind.QuestionToken)
286                        )],
287                        factory.createKeywordTypeNode(SyntaxKind.AnyKeyword)
288                    ),
289                    factory.createFunctionTypeNode(
290                        /*typeArguments*/ undefined,
291                        [factory.createParameterDeclaration(
292                            /*modifiers*/ undefined,
293                            /*dotDotDotToken*/ undefined,
294                            factory.createIdentifier("args"),
295                            /*questionToken*/ undefined,
296                            factory.createKeywordTypeNode(SyntaxKind.AnyKeyword)
297                        )],
298                        factory.createKeywordTypeNode(SyntaxKind.AnyKeyword)
299                    ),
300                    factory.createFunctionTypeNode(
301                        /*typeArguments*/ undefined,
302                        [factory.createParameterDeclaration(
303                            /*modifiers*/ undefined,
304                            /*dotDotDotToken*/ undefined,
305                            factory.createObjectBindingPattern([])
306                        )],
307                        factory.createKeywordTypeNode(SyntaxKind.AnyKeyword)
308                    ),
309                ]), EmitFlags.SingleLine),
310                createSourceFile("source.ts", "", ScriptTarget.ES2015)
311            ));
312        });
313    });
314}
315