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 /*decorators*/ undefined, 152 /*modifiers*/ undefined, 153 /*name*/ factory.createIdentifier("C"), 154 /*typeParameters*/ undefined, 155 /*heritageClauses*/ undefined, 156 [factory.createPropertyDeclaration( 157 /*decorators*/ undefined, 158 factory.createNodeArray([factory.createToken(SyntaxKind.PublicKeyword)]), 159 factory.createIdentifier("prop"), 160 /*questionToken*/ undefined, 161 /*type*/ undefined, 162 /*initializer*/ undefined 163 )] 164 ), 165 createSourceFile("source.ts", "", ScriptTarget.ES2015) 166 )); 167 168 printsCorrectly("namespaceExportDeclaration", {}, printer => printer.printNode( 169 EmitHint.Unspecified, 170 factory.createNamespaceExportDeclaration("B"), 171 createSourceFile("source.ts", "", ScriptTarget.ES2015) 172 )); 173 174 printsCorrectly("newExpressionWithPropertyAccessOnCallExpression", {}, printer => printer.printNode( 175 EmitHint.Unspecified, 176 factory.createNewExpression( 177 factory.createPropertyAccessExpression( 178 factory.createCallExpression(factory.createIdentifier("f"), /*typeArguments*/ undefined, /*argumentsArray*/ undefined), 179 "x"), 180 /*typeArguments*/ undefined, 181 /*argumentsArray*/ undefined 182 ), 183 createSourceFile("source.ts", "", ScriptTarget.ESNext)) 184 ); 185 186 printsCorrectly("newExpressionOnConditionalExpression", {}, printer => printer.printNode( 187 EmitHint.Unspecified, 188 factory.createNewExpression( 189 factory.createConditionalExpression( 190 factory.createIdentifier("x"), factory.createToken(SyntaxKind.QuestionToken), 191 factory.createIdentifier("y"), factory.createToken(SyntaxKind.ColonToken), 192 factory.createIdentifier("z")), 193 /*typeArguments*/ undefined, 194 /*argumentsArray*/ undefined 195 ), 196 createSourceFile("source.ts", "", ScriptTarget.ESNext)) 197 ); 198 199 printsCorrectly("emptyGlobalAugmentation", {}, printer => printer.printNode( 200 EmitHint.Unspecified, 201 factory.createModuleDeclaration( 202 /*decorators*/ undefined, 203 /*modifiers*/ [factory.createToken(SyntaxKind.DeclareKeyword)], 204 factory.createIdentifier("global"), 205 factory.createModuleBlock(emptyArray), 206 NodeFlags.GlobalAugmentation), 207 createSourceFile("source.ts", "", ScriptTarget.ES2015) 208 )); 209 210 printsCorrectly("emptyGlobalAugmentationWithNoDeclareKeyword", {}, printer => printer.printNode( 211 EmitHint.Unspecified, 212 factory.createModuleDeclaration( 213 /*decorators*/ undefined, 214 /*modifiers*/ undefined, 215 factory.createIdentifier("global"), 216 factory.createModuleBlock(emptyArray), 217 NodeFlags.GlobalAugmentation), 218 createSourceFile("source.ts", "", ScriptTarget.ES2015) 219 )); 220 221 // https://github.com/Microsoft/TypeScript/issues/15971 222 printsCorrectly("classWithOptionalMethodAndProperty", {}, printer => printer.printNode( 223 EmitHint.Unspecified, 224 factory.createClassDeclaration( 225 /*decorators*/ undefined, 226 /*modifiers*/ [factory.createToken(SyntaxKind.DeclareKeyword)], 227 /*name*/ factory.createIdentifier("X"), 228 /*typeParameters*/ undefined, 229 /*heritageClauses*/ undefined, 230 [ 231 factory.createMethodDeclaration( 232 /*decorators*/ undefined, 233 /*modifiers*/ undefined, 234 /*asteriskToken*/ undefined, 235 /*name*/ factory.createIdentifier("method"), 236 /*questionToken*/ factory.createToken(SyntaxKind.QuestionToken), 237 /*typeParameters*/ undefined, 238 [], 239 /*type*/ factory.createKeywordTypeNode(SyntaxKind.VoidKeyword), 240 /*body*/ undefined 241 ), 242 factory.createPropertyDeclaration( 243 /*decorators*/ undefined, 244 /*modifiers*/ undefined, 245 /*name*/ factory.createIdentifier("property"), 246 /*questionToken*/ factory.createToken(SyntaxKind.QuestionToken), 247 /*type*/ factory.createKeywordTypeNode(SyntaxKind.StringKeyword), 248 /*initializer*/ undefined 249 ), 250 ] 251 ), 252 createSourceFile("source.ts", "", ScriptTarget.ES2015) 253 )); 254 255 // https://github.com/Microsoft/TypeScript/issues/15651 256 printsCorrectly("functionTypes", {}, printer => printer.printNode( 257 EmitHint.Unspecified, 258 setEmitFlags(factory.createTupleTypeNode([ 259 factory.createFunctionTypeNode( 260 /*typeArguments*/ undefined, 261 [factory.createParameterDeclaration( 262 /*decorators*/ undefined, 263 /*modifiers*/ undefined, 264 /*dotDotDotToken*/ undefined, 265 factory.createIdentifier("args") 266 )], 267 factory.createKeywordTypeNode(SyntaxKind.AnyKeyword) 268 ), 269 factory.createFunctionTypeNode( 270 [factory.createTypeParameterDeclaration("T")], 271 [factory.createParameterDeclaration( 272 /*decorators*/ undefined, 273 /*modifiers*/ undefined, 274 /*dotDotDotToken*/ undefined, 275 factory.createIdentifier("args") 276 )], 277 factory.createKeywordTypeNode(SyntaxKind.AnyKeyword) 278 ), 279 factory.createFunctionTypeNode( 280 /*typeArguments*/ undefined, 281 [factory.createParameterDeclaration( 282 /*decorators*/ undefined, 283 /*modifiers*/ undefined, 284 factory.createToken(SyntaxKind.DotDotDotToken), 285 factory.createIdentifier("args") 286 )], 287 factory.createKeywordTypeNode(SyntaxKind.AnyKeyword) 288 ), 289 factory.createFunctionTypeNode( 290 /*typeArguments*/ undefined, 291 [factory.createParameterDeclaration( 292 /*decorators*/ undefined, 293 /*modifiers*/ undefined, 294 /*dotDotDotToken*/ undefined, 295 factory.createIdentifier("args"), 296 factory.createToken(SyntaxKind.QuestionToken) 297 )], 298 factory.createKeywordTypeNode(SyntaxKind.AnyKeyword) 299 ), 300 factory.createFunctionTypeNode( 301 /*typeArguments*/ undefined, 302 [factory.createParameterDeclaration( 303 /*decorators*/ undefined, 304 /*modifiers*/ undefined, 305 /*dotDotDotToken*/ undefined, 306 factory.createIdentifier("args"), 307 /*questionToken*/ undefined, 308 factory.createKeywordTypeNode(SyntaxKind.AnyKeyword) 309 )], 310 factory.createKeywordTypeNode(SyntaxKind.AnyKeyword) 311 ), 312 factory.createFunctionTypeNode( 313 /*typeArguments*/ undefined, 314 [factory.createParameterDeclaration( 315 /*decorators*/ undefined, 316 /*modifiers*/ undefined, 317 /*dotDotDotToken*/ undefined, 318 factory.createObjectBindingPattern([]) 319 )], 320 factory.createKeywordTypeNode(SyntaxKind.AnyKeyword) 321 ), 322 ]), EmitFlags.SingleLine), 323 createSourceFile("source.ts", "", ScriptTarget.ES2015) 324 )); 325 }); 326 }); 327} 328