| 
									
										
										
										
											2017-05-30 11:43:13 -06:00
										 |  |  | /** | 
					
						
							|  |  |  |  * @license | 
					
						
							|  |  |  |  * Copyright Google Inc. All Rights Reserved. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Use of this source code is governed by an MIT-style license that can be | 
					
						
							|  |  |  |  * found in the LICENSE file at https://angular.io/license
 | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-26 09:26:18 -07:00
										 |  |  | import {ParseLocation, ParseSourceFile, ParseSourceSpan} from '@angular/compiler'; | 
					
						
							| 
									
										
										
										
											2017-05-30 11:43:13 -06:00
										 |  |  | import * as o from '@angular/compiler/src/output/output_ast'; | 
					
						
							|  |  |  | import * as ts from 'typescript'; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import {TypeScriptNodeEmitter} from '../../src/transformers/node_emitter'; | 
					
						
							|  |  |  | import {Directory, MockAotContext, MockCompilerHost} from '../mocks'; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-06-25 11:22:23 -07:00
										 |  |  | const sourceMap = require('source-map'); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-05-30 11:43:13 -06:00
										 |  |  | const someGenFilePath = '/somePackage/someGenFile'; | 
					
						
							|  |  |  | const someGenFileName = someGenFilePath + '.ts'; | 
					
						
							|  |  |  | const someSourceFilePath = '/somePackage/someSourceFile'; | 
					
						
							|  |  |  | const anotherModuleUrl = '/somePackage/someOtherPath'; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const sameModuleIdentifier = new o.ExternalReference(null, 'someLocalId', null); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const externalModuleIdentifier = new o.ExternalReference(anotherModuleUrl, 'someExternalId', null); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-07-05 14:51:39 -07:00
										 |  |  | describe('TypeScriptNodeEmitter', () => { | 
					
						
							| 
									
										
										
										
											2017-05-30 11:43:13 -06:00
										 |  |  |   let context: MockAotContext; | 
					
						
							|  |  |  |   let host: MockCompilerHost; | 
					
						
							|  |  |  |   let emitter: TypeScriptNodeEmitter; | 
					
						
							|  |  |  |   let someVar: o.ReadVarExpr; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   beforeEach(() => { | 
					
						
							|  |  |  |     context = new MockAotContext('/', FILES); | 
					
						
							|  |  |  |     host = new MockCompilerHost(context); | 
					
						
							|  |  |  |     emitter = new TypeScriptNodeEmitter(); | 
					
						
							|  |  |  |     someVar = o.variable('someVar', null, null); | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-12 15:34:03 +01:00
										 |  |  |   function emitStmt( | 
					
						
							|  |  |  |       stmt: o.Statement | o.Statement[], format: Format = Format.Flat, preamble?: string): string { | 
					
						
							| 
									
										
										
										
											2017-05-30 11:43:13 -06:00
										 |  |  |     const stmts = Array.isArray(stmt) ? stmt : [stmt]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     const program = ts.createProgram( | 
					
						
							|  |  |  |         [someGenFileName], {module: ts.ModuleKind.CommonJS, target: ts.ScriptTarget.ES2017}, host); | 
					
						
							|  |  |  |     const moduleSourceFile = program.getSourceFile(someGenFileName); | 
					
						
							|  |  |  |     const transformers: ts.CustomTransformers = { | 
					
						
							|  |  |  |       before: [context => { | 
					
						
							|  |  |  |         return sourceFile => { | 
					
						
							| 
									
										
										
										
											2017-06-09 14:50:57 -07:00
										 |  |  |           const [newSourceFile] = emitter.updateSourceFile(sourceFile, stmts, preamble); | 
					
						
							| 
									
										
										
										
											2017-05-30 11:43:13 -06:00
										 |  |  |           return newSourceFile; | 
					
						
							|  |  |  |         }; | 
					
						
							|  |  |  |       }] | 
					
						
							|  |  |  |     }; | 
					
						
							|  |  |  |     let result: string = ''; | 
					
						
							|  |  |  |     const emitResult = program.emit( | 
					
						
							|  |  |  |         moduleSourceFile, (fileName, data, writeByteOrderMark, onError, sourceFiles) => { | 
					
						
							|  |  |  |           if (fileName.startsWith(someGenFilePath)) { | 
					
						
							|  |  |  |             result = data; | 
					
						
							|  |  |  |           } | 
					
						
							|  |  |  |         }, undefined, undefined, transformers); | 
					
						
							| 
									
										
										
										
											2018-03-12 15:34:03 +01:00
										 |  |  |     return normalizeResult(result, format); | 
					
						
							| 
									
										
										
										
											2017-05-30 11:43:13 -06:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   it('should declare variables', () => { | 
					
						
							|  |  |  |     expect(emitStmt(someVar.set(o.literal(1)).toDeclStmt())).toEqual(`var someVar = 1;`); | 
					
						
							|  |  |  |     expect(emitStmt(someVar.set(o.literal(1)).toDeclStmt(null, [o.StmtModifier.Final]))) | 
					
						
							|  |  |  |         .toEqual(`var someVar = 1;`); | 
					
						
							|  |  |  |     expect(emitStmt(someVar.set(o.literal(1)).toDeclStmt(null, [o.StmtModifier.Exported]))) | 
					
						
							| 
									
										
										
										
											2017-08-02 11:20:07 -07:00
										 |  |  |         .toEqual(`var someVar = 1; exports.someVar = someVar;`); | 
					
						
							| 
									
										
										
										
											2017-05-30 11:43:13 -06:00
										 |  |  |   }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   describe('declare variables with ExternExpressions as values', () => { | 
					
						
							|  |  |  |     it('should create no reexport if the identifier is in the same module', () => { | 
					
						
							|  |  |  |       // identifier is in the same module -> no reexport
 | 
					
						
							|  |  |  |       expect(emitStmt(someVar.set(o.importExpr(sameModuleIdentifier)).toDeclStmt(null, [ | 
					
						
							|  |  |  |         o.StmtModifier.Exported | 
					
						
							| 
									
										
										
										
											2017-08-02 11:20:07 -07:00
										 |  |  |       ]))).toEqual('var someVar = someLocalId; exports.someVar = someVar;'); | 
					
						
							| 
									
										
										
										
											2017-05-30 11:43:13 -06:00
										 |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     it('should create no reexport if the variable is not exported', () => { | 
					
						
							|  |  |  |       expect(emitStmt(someVar.set(o.importExpr(externalModuleIdentifier)).toDeclStmt())) | 
					
						
							|  |  |  |           .toEqual( | 
					
						
							|  |  |  |               `const i0 = require("/somePackage/someOtherPath"); var someVar = i0.someExternalId;`); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     it('should create no reexport if the variable is typed', () => { | 
					
						
							|  |  |  |       expect(emitStmt(someVar.set(o.importExpr(externalModuleIdentifier)) | 
					
						
							|  |  |  |                           .toDeclStmt(o.DYNAMIC_TYPE, [o.StmtModifier.Exported]))) | 
					
						
							|  |  |  |           .toEqual( | 
					
						
							| 
									
										
										
										
											2017-08-02 11:20:07 -07:00
										 |  |  |               `const i0 = require("/somePackage/someOtherPath"); var someVar = i0.someExternalId; exports.someVar = someVar;`); | 
					
						
							| 
									
										
										
										
											2017-05-30 11:43:13 -06:00
										 |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     it('should create a reexport', () => { | 
					
						
							|  |  |  |       expect(emitStmt(someVar.set(o.importExpr(externalModuleIdentifier)) | 
					
						
							|  |  |  |                           .toDeclStmt(null, [o.StmtModifier.Exported]))) | 
					
						
							|  |  |  |           .toEqual( | 
					
						
							|  |  |  |               `var someOtherPath_1 = require("/somePackage/someOtherPath"); exports.someVar = someOtherPath_1.someExternalId;`); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     it('should create multiple reexports from the same file', () => { | 
					
						
							|  |  |  |       const someVar2 = o.variable('someVar2'); | 
					
						
							|  |  |  |       const externalModuleIdentifier2 = | 
					
						
							|  |  |  |           new o.ExternalReference(anotherModuleUrl, 'someExternalId2', null); | 
					
						
							|  |  |  |       expect(emitStmt([ | 
					
						
							|  |  |  |         someVar.set(o.importExpr(externalModuleIdentifier)) | 
					
						
							|  |  |  |             .toDeclStmt(null, [o.StmtModifier.Exported]), | 
					
						
							|  |  |  |         someVar2.set(o.importExpr(externalModuleIdentifier2)) | 
					
						
							|  |  |  |             .toDeclStmt(null, [o.StmtModifier.Exported]) | 
					
						
							|  |  |  |       ])) | 
					
						
							|  |  |  |           .toEqual( | 
					
						
							|  |  |  |               `var someOtherPath_1 = require("/somePackage/someOtherPath"); exports.someVar = someOtherPath_1.someExternalId; exports.someVar2 = someOtherPath_1.someExternalId2;`); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   it('should read and write variables', () => { | 
					
						
							|  |  |  |     expect(emitStmt(someVar.toStmt())).toEqual(`someVar;`); | 
					
						
							|  |  |  |     expect(emitStmt(someVar.set(o.literal(1)).toStmt())).toEqual(`someVar = 1;`); | 
					
						
							|  |  |  |     expect(emitStmt(someVar.set(o.variable('someOtherVar').set(o.literal(1))).toStmt())) | 
					
						
							|  |  |  |         .toEqual(`someVar = someOtherVar = 1;`); | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   it('should read and write keys', () => { | 
					
						
							|  |  |  |     expect(emitStmt(o.variable('someMap').key(o.variable('someKey')).toStmt())) | 
					
						
							|  |  |  |         .toEqual(`someMap[someKey];`); | 
					
						
							|  |  |  |     expect(emitStmt(o.variable('someMap').key(o.variable('someKey')).set(o.literal(1)).toStmt())) | 
					
						
							|  |  |  |         .toEqual(`someMap[someKey] = 1;`); | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   it('should read and write properties', () => { | 
					
						
							|  |  |  |     expect(emitStmt(o.variable('someObj').prop('someProp').toStmt())).toEqual(`someObj.someProp;`); | 
					
						
							|  |  |  |     expect(emitStmt(o.variable('someObj').prop('someProp').set(o.literal(1)).toStmt())) | 
					
						
							|  |  |  |         .toEqual(`someObj.someProp = 1;`); | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   it('should invoke functions and methods and constructors', () => { | 
					
						
							|  |  |  |     expect(emitStmt(o.variable('someFn').callFn([o.literal(1)]).toStmt())).toEqual('someFn(1);'); | 
					
						
							|  |  |  |     expect(emitStmt(o.variable('someObj').callMethod('someMethod', [o.literal(1)]).toStmt())) | 
					
						
							|  |  |  |         .toEqual('someObj.someMethod(1);'); | 
					
						
							|  |  |  |     expect(emitStmt(o.variable('SomeClass').instantiate([o.literal(1)]).toStmt())) | 
					
						
							|  |  |  |         .toEqual('new SomeClass(1);'); | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   it('should invoke functions and methods and constructors', () => { | 
					
						
							|  |  |  |     expect(emitStmt(o.variable('someFn').callFn([o.literal(1)]).toStmt())).toEqual('someFn(1);'); | 
					
						
							|  |  |  |     expect(emitStmt(o.variable('someObj').callMethod('someMethod', [o.literal(1)]).toStmt())) | 
					
						
							|  |  |  |         .toEqual('someObj.someMethod(1);'); | 
					
						
							|  |  |  |     expect(emitStmt(o.variable('SomeClass').instantiate([o.literal(1)]).toStmt())) | 
					
						
							|  |  |  |         .toEqual('new SomeClass(1);'); | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   it('should support builtin methods', () => { | 
					
						
							|  |  |  |     expect(emitStmt(o.variable('arr1') | 
					
						
							|  |  |  |                         .callMethod(o.BuiltinMethod.ConcatArray, [o.variable('arr2')]) | 
					
						
							|  |  |  |                         .toStmt())) | 
					
						
							|  |  |  |         .toEqual('arr1.concat(arr2);'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     expect(emitStmt(o.variable('observable') | 
					
						
							|  |  |  |                         .callMethod(o.BuiltinMethod.SubscribeObservable, [o.variable('listener')]) | 
					
						
							|  |  |  |                         .toStmt())) | 
					
						
							|  |  |  |         .toEqual('observable.subscribe(listener);'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     expect(emitStmt( | 
					
						
							|  |  |  |                o.variable('fn').callMethod(o.BuiltinMethod.Bind, [o.variable('someObj')]).toStmt())) | 
					
						
							|  |  |  |         .toEqual('fn.bind(someObj);'); | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   it('should support literals', () => { | 
					
						
							|  |  |  |     expect(emitStmt(o.literal(0).toStmt())).toEqual('0;'); | 
					
						
							|  |  |  |     expect(emitStmt(o.literal(true).toStmt())).toEqual('true;'); | 
					
						
							|  |  |  |     expect(emitStmt(o.literal('someStr').toStmt())).toEqual(`"someStr";`); | 
					
						
							|  |  |  |     expect(emitStmt(o.literalArr([o.literal(1)]).toStmt())).toEqual(`[1];`); | 
					
						
							| 
									
										
										
										
											2017-07-05 14:51:39 -07:00
										 |  |  |     expect(emitStmt(o.literalMap([ | 
					
						
							|  |  |  |                        {key: 'someKey', value: o.literal(1), quoted: false}, | 
					
						
							|  |  |  |                        {key: 'a', value: o.literal('a'), quoted: false}, | 
					
						
							| 
									
										
										
										
											2017-08-18 15:02:10 -07:00
										 |  |  |                        {key: 'b', value: o.literal('b'), quoted: true}, | 
					
						
							|  |  |  |                        {key: '*', value: o.literal('star'), quoted: false}, | 
					
						
							| 
									
										
										
										
											2017-07-05 14:51:39 -07:00
										 |  |  |                      ]).toStmt()) | 
					
						
							| 
									
										
										
										
											2017-05-30 11:43:13 -06:00
										 |  |  |                .replace(/\s+/gm, '')) | 
					
						
							| 
									
										
										
										
											2017-08-18 15:02:10 -07:00
										 |  |  |         .toEqual(`({someKey:1,a:"a","b":"b","*":"star"});`); | 
					
						
							| 
									
										
										
										
											2018-03-14 13:31:38 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |     // Regressions #22774
 | 
					
						
							|  |  |  |     expect(emitStmt(o.literal('\\0025BC').toStmt())).toEqual('"\\\\0025BC";'); | 
					
						
							|  |  |  |     expect(emitStmt(o.literal('"some value"').toStmt())).toEqual('"\\"some value\\"";'); | 
					
						
							|  |  |  |     expect(emitStmt(o.literal('"some \\0025BC value"').toStmt())) | 
					
						
							|  |  |  |         .toEqual('"\\"some \\\\0025BC value\\"";'); | 
					
						
							|  |  |  |     expect(emitStmt(o.literal('\n \\0025BC \n ').toStmt())).toEqual('"\\n \\\\0025BC \\n ";'); | 
					
						
							|  |  |  |     expect(emitStmt(o.literal('\r \\0025BC \r ').toStmt())).toEqual('"\\r \\\\0025BC \\r ";'); | 
					
						
							| 
									
										
										
										
											2017-05-30 11:43:13 -06:00
										 |  |  |   }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   it('should support blank literals', () => { | 
					
						
							|  |  |  |     expect(emitStmt(o.literal(null).toStmt())).toEqual('null;'); | 
					
						
							|  |  |  |     expect(emitStmt(o.literal(undefined).toStmt())).toEqual('undefined;'); | 
					
						
							| 
									
										
										
										
											2017-09-23 11:30:51 -07:00
										 |  |  |     expect(emitStmt(o.variable('a', null).isBlank().toStmt())).toEqual('(a == null);'); | 
					
						
							| 
									
										
										
										
											2017-05-30 11:43:13 -06:00
										 |  |  |   }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   it('should support external identifiers', () => { | 
					
						
							|  |  |  |     expect(emitStmt(o.importExpr(sameModuleIdentifier).toStmt())).toEqual('someLocalId;'); | 
					
						
							|  |  |  |     expect(emitStmt(o.importExpr(externalModuleIdentifier).toStmt())) | 
					
						
							|  |  |  |         .toEqual(`const i0 = require("/somePackage/someOtherPath"); i0.someExternalId;`); | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   it('should support operators', () => { | 
					
						
							|  |  |  |     const lhs = o.variable('lhs'); | 
					
						
							|  |  |  |     const rhs = o.variable('rhs'); | 
					
						
							|  |  |  |     expect(emitStmt(someVar.cast(o.INT_TYPE).toStmt())).toEqual('someVar;'); | 
					
						
							|  |  |  |     expect(emitStmt(o.not(someVar).toStmt())).toEqual('!someVar;'); | 
					
						
							|  |  |  |     expect(emitStmt(o.assertNotNull(someVar).toStmt())).toEqual('someVar;'); | 
					
						
							|  |  |  |     expect(emitStmt(someVar.conditional(o.variable('trueCase'), o.variable('falseCase')).toStmt())) | 
					
						
							| 
									
										
										
										
											2017-09-23 11:30:51 -07:00
										 |  |  |         .toEqual('(someVar ? trueCase : falseCase);'); | 
					
						
							|  |  |  |     expect(emitStmt(someVar.conditional(o.variable('trueCase'), o.variable('falseCase')) | 
					
						
							|  |  |  |                         .conditional(o.variable('trueCase'), o.variable('falseCase')) | 
					
						
							|  |  |  |                         .toStmt())) | 
					
						
							|  |  |  |         .toEqual('((someVar ? trueCase : falseCase) ? trueCase : falseCase);'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     expect(emitStmt(lhs.equals(rhs).toStmt())).toEqual('(lhs == rhs);'); | 
					
						
							|  |  |  |     expect(emitStmt(lhs.notEquals(rhs).toStmt())).toEqual('(lhs != rhs);'); | 
					
						
							|  |  |  |     expect(emitStmt(lhs.identical(rhs).toStmt())).toEqual('(lhs === rhs);'); | 
					
						
							|  |  |  |     expect(emitStmt(lhs.notIdentical(rhs).toStmt())).toEqual('(lhs !== rhs);'); | 
					
						
							|  |  |  |     expect(emitStmt(lhs.minus(rhs).toStmt())).toEqual('(lhs - rhs);'); | 
					
						
							|  |  |  |     expect(emitStmt(lhs.plus(rhs).toStmt())).toEqual('(lhs + rhs);'); | 
					
						
							|  |  |  |     expect(emitStmt(lhs.divide(rhs).toStmt())).toEqual('(lhs / rhs);'); | 
					
						
							|  |  |  |     expect(emitStmt(lhs.multiply(rhs).toStmt())).toEqual('(lhs * rhs);'); | 
					
						
							|  |  |  |     expect(emitStmt(lhs.plus(rhs).multiply(rhs).toStmt())).toEqual('((lhs + rhs) * rhs);'); | 
					
						
							|  |  |  |     expect(emitStmt(lhs.modulo(rhs).toStmt())).toEqual('(lhs % rhs);'); | 
					
						
							|  |  |  |     expect(emitStmt(lhs.and(rhs).toStmt())).toEqual('(lhs && rhs);'); | 
					
						
							|  |  |  |     expect(emitStmt(lhs.or(rhs).toStmt())).toEqual('(lhs || rhs);'); | 
					
						
							|  |  |  |     expect(emitStmt(lhs.lower(rhs).toStmt())).toEqual('(lhs < rhs);'); | 
					
						
							|  |  |  |     expect(emitStmt(lhs.lowerEquals(rhs).toStmt())).toEqual('(lhs <= rhs);'); | 
					
						
							|  |  |  |     expect(emitStmt(lhs.bigger(rhs).toStmt())).toEqual('(lhs > rhs);'); | 
					
						
							|  |  |  |     expect(emitStmt(lhs.biggerEquals(rhs).toStmt())).toEqual('(lhs >= rhs);'); | 
					
						
							| 
									
										
										
										
											2017-05-30 11:43:13 -06:00
										 |  |  |   }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   it('should support function expressions', () => { | 
					
						
							|  |  |  |     expect(emitStmt(o.fn([], []).toStmt())).toEqual(`(function () { });`); | 
					
						
							|  |  |  |     expect(emitStmt(o.fn([], [new o.ReturnStatement(o.literal(1))], o.INT_TYPE).toStmt())) | 
					
						
							|  |  |  |         .toEqual(`(function () { return 1; });`); | 
					
						
							|  |  |  |     expect(emitStmt(o.fn([new o.FnParam('param1', o.INT_TYPE)], []).toStmt())) | 
					
						
							|  |  |  |         .toEqual(`(function (param1) { });`); | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   it('should support function statements', () => { | 
					
						
							|  |  |  |     expect(emitStmt(new o.DeclareFunctionStmt('someFn', [], []))).toEqual('function someFn() { }'); | 
					
						
							|  |  |  |     expect(emitStmt(new o.DeclareFunctionStmt('someFn', [], [], null, [o.StmtModifier.Exported]))) | 
					
						
							|  |  |  |         .toEqual(`function someFn() { } exports.someFn = someFn;`); | 
					
						
							|  |  |  |     expect(emitStmt(new o.DeclareFunctionStmt( | 
					
						
							|  |  |  |                'someFn', [], [new o.ReturnStatement(o.literal(1))], o.INT_TYPE))) | 
					
						
							|  |  |  |         .toEqual(`function someFn() { return 1; }`); | 
					
						
							|  |  |  |     expect(emitStmt(new o.DeclareFunctionStmt('someFn', [new o.FnParam('param1', o.INT_TYPE)], [ | 
					
						
							|  |  |  |     ]))).toEqual(`function someFn(param1) { }`); | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-12 15:34:03 +01:00
										 |  |  |   describe('comments', () => { | 
					
						
							|  |  |  |     it('should support a preamble', () => { | 
					
						
							|  |  |  |       expect(emitStmt(o.variable('a').toStmt(), Format.Flat, '/* SomePreamble */')) | 
					
						
							|  |  |  |           .toBe('/* SomePreamble */ a;'); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     it('should support singleline comments', | 
					
						
							|  |  |  |        () => { expect(emitStmt(new o.CommentStmt('Simple comment'))).toBe('// Simple comment'); }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     it('should support multiline comments', () => { | 
					
						
							|  |  |  |       expect(emitStmt(new o.CommentStmt('Multiline comment', true))) | 
					
						
							|  |  |  |           .toBe('/* Multiline comment */'); | 
					
						
							|  |  |  |       expect(emitStmt(new o.CommentStmt(`Multiline\ncomment`, true), Format.Raw)) | 
					
						
							|  |  |  |           .toBe(`/* Multiline\ncomment */`); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     describe('JSDoc comments', () => { | 
					
						
							|  |  |  |       it('should be supported', () => { | 
					
						
							|  |  |  |         expect(emitStmt(new o.JSDocCommentStmt([{text: 'Intro comment'}]), Format.Raw)) | 
					
						
							|  |  |  |             .toBe(`/**\n * Intro comment\n */`); | 
					
						
							|  |  |  |         expect(emitStmt( | 
					
						
							|  |  |  |                    new o.JSDocCommentStmt([{tagName: o.JSDocTagName.Desc, text: 'description'}]), | 
					
						
							|  |  |  |                    Format.Raw)) | 
					
						
							|  |  |  |             .toBe(`/**\n * @desc description\n */`); | 
					
						
							|  |  |  |         expect(emitStmt( | 
					
						
							|  |  |  |                    new o.JSDocCommentStmt([ | 
					
						
							|  |  |  |                      {text: 'Intro comment'}, | 
					
						
							|  |  |  |                      {tagName: o.JSDocTagName.Desc, text: 'description'}, | 
					
						
							|  |  |  |                      {tagName: o.JSDocTagName.Id, text: '{number} identifier 123'}, | 
					
						
							|  |  |  |                    ]), | 
					
						
							|  |  |  |                    Format.Raw)) | 
					
						
							|  |  |  |             .toBe( | 
					
						
							|  |  |  |                 `/**\n * Intro comment\n * @desc description\n * @id {number} identifier 123\n */`); | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       it('should escape @ in the text', () => { | 
					
						
							|  |  |  |         expect(emitStmt(new o.JSDocCommentStmt([{text: 'email@google.com'}]), Format.Raw)) | 
					
						
							|  |  |  |             .toBe(`/**\n * email\\@google.com\n */`); | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       it('should not allow /* and */ in the text', () => { | 
					
						
							|  |  |  |         expect(() => emitStmt(new o.JSDocCommentStmt([{text: 'some text /* */'}]), Format.Raw)) | 
					
						
							|  |  |  |             .toThrowError(`JSDoc text cannot contain "/*" and "*/"`); | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  |   }); | 
					
						
							| 
									
										
										
										
											2017-05-30 11:43:13 -06:00
										 |  |  | 
 | 
					
						
							|  |  |  |   it('should support if stmt', () => { | 
					
						
							|  |  |  |     const trueCase = o.variable('trueCase').callFn([]).toStmt(); | 
					
						
							|  |  |  |     const falseCase = o.variable('falseCase').callFn([]).toStmt(); | 
					
						
							|  |  |  |     expect(emitStmt(new o.IfStmt(o.variable('cond'), [trueCase]))) | 
					
						
							|  |  |  |         .toEqual('if (cond) { trueCase(); }'); | 
					
						
							|  |  |  |     expect(emitStmt(new o.IfStmt(o.variable('cond'), [trueCase], [falseCase]))) | 
					
						
							|  |  |  |         .toEqual('if (cond) { trueCase(); } else { falseCase(); }'); | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   it('should support try/catch', () => { | 
					
						
							|  |  |  |     const bodyStmt = o.variable('body').callFn([]).toStmt(); | 
					
						
							|  |  |  |     const catchStmt = o.variable('catchFn').callFn([o.CATCH_ERROR_VAR, o.CATCH_STACK_VAR]).toStmt(); | 
					
						
							|  |  |  |     expect(emitStmt(new o.TryCatchStmt([bodyStmt], [catchStmt]))) | 
					
						
							|  |  |  |         .toEqual( | 
					
						
							|  |  |  |             `try { body(); } catch (error) { var stack = error.stack; catchFn(error, stack); }`); | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   it('should support support throwing', | 
					
						
							|  |  |  |      () => { expect(emitStmt(new o.ThrowStmt(someVar))).toEqual('throw someVar;'); }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   describe('classes', () => { | 
					
						
							|  |  |  |     let callSomeMethod: o.Statement; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     beforeEach(() => { callSomeMethod = o.THIS_EXPR.callMethod('someMethod', []).toStmt(); }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     it('should support declaring classes', () => { | 
					
						
							|  |  |  |       expect(emitStmt(new o.ClassStmt('SomeClass', null !, [], [], null !, [ | 
					
						
							|  |  |  |       ]))).toEqual('class SomeClass { }'); | 
					
						
							|  |  |  |       expect(emitStmt(new o.ClassStmt('SomeClass', null !, [], [], null !, [], [ | 
					
						
							|  |  |  |         o.StmtModifier.Exported | 
					
						
							|  |  |  |       ]))).toEqual('class SomeClass { } exports.SomeClass = SomeClass;'); | 
					
						
							|  |  |  |       expect(emitStmt(new o.ClassStmt('SomeClass', o.variable('SomeSuperClass'), [], [], null !, [ | 
					
						
							|  |  |  |       ]))).toEqual('class SomeClass extends SomeSuperClass { }'); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     it('should support declaring constructors', () => { | 
					
						
							|  |  |  |       const superCall = o.SUPER_EXPR.callFn([o.variable('someParam')]).toStmt(); | 
					
						
							|  |  |  |       expect(emitStmt(new o.ClassStmt( | 
					
						
							|  |  |  |                  'SomeClass', null !, [], [], new o.ClassMethod(null !, [], []), []))) | 
					
						
							|  |  |  |           .toEqual(`class SomeClass { constructor() { } }`); | 
					
						
							|  |  |  |       expect(emitStmt(new o.ClassStmt( | 
					
						
							|  |  |  |                  'SomeClass', null !, [], [], | 
					
						
							|  |  |  |                  new o.ClassMethod(null !, [new o.FnParam('someParam', o.INT_TYPE)], []), []))) | 
					
						
							|  |  |  |           .toEqual(`class SomeClass { constructor(someParam) { } }`); | 
					
						
							|  |  |  |       expect(emitStmt(new o.ClassStmt( | 
					
						
							|  |  |  |                  'SomeClass', null !, [], [], new o.ClassMethod(null !, [], [superCall]), []))) | 
					
						
							|  |  |  |           .toEqual(`class SomeClass { constructor() { super(someParam); } }`); | 
					
						
							|  |  |  |       expect(emitStmt(new o.ClassStmt( | 
					
						
							|  |  |  |                  'SomeClass', null !, [], [], new o.ClassMethod(null !, [], [callSomeMethod]), []))) | 
					
						
							|  |  |  |           .toEqual(`class SomeClass { constructor() { this.someMethod(); } }`); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     it('should support declaring fields', () => { | 
					
						
							|  |  |  |       expect(emitStmt(new o.ClassStmt( | 
					
						
							|  |  |  |                  'SomeClass', null !, [new o.ClassField('someField')], [], null !, []))) | 
					
						
							|  |  |  |           .toEqual(`class SomeClass { constructor() { this.someField = null; } }`); | 
					
						
							|  |  |  |       expect(emitStmt(new o.ClassStmt( | 
					
						
							|  |  |  |                  'SomeClass', null !, [new o.ClassField('someField', o.INT_TYPE)], [], null !, []))) | 
					
						
							|  |  |  |           .toEqual(`class SomeClass { constructor() { this.someField = null; } }`); | 
					
						
							|  |  |  |       expect(emitStmt(new o.ClassStmt( | 
					
						
							|  |  |  |                  'SomeClass', null !, | 
					
						
							|  |  |  |                  [new o.ClassField('someField', o.INT_TYPE, [o.StmtModifier.Private])], [], null !, | 
					
						
							|  |  |  |                  []))) | 
					
						
							|  |  |  |           .toEqual(`class SomeClass { constructor() { this.someField = null; } }`); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     it('should support declaring getters', () => { | 
					
						
							|  |  |  |       expect(emitStmt(new o.ClassStmt( | 
					
						
							|  |  |  |                  'SomeClass', null !, [], [new o.ClassGetter('someGetter', [])], null !, []))) | 
					
						
							|  |  |  |           .toEqual(`class SomeClass { get someGetter() { } }`); | 
					
						
							|  |  |  |       expect(emitStmt(new o.ClassStmt( | 
					
						
							|  |  |  |                  'SomeClass', null !, [], [new o.ClassGetter('someGetter', [], o.INT_TYPE)], null !, | 
					
						
							|  |  |  |                  []))) | 
					
						
							|  |  |  |           .toEqual(`class SomeClass { get someGetter() { } }`); | 
					
						
							|  |  |  |       expect(emitStmt(new o.ClassStmt( | 
					
						
							|  |  |  |                  'SomeClass', null !, [], [new o.ClassGetter('someGetter', [callSomeMethod])], | 
					
						
							|  |  |  |                  null !, []))) | 
					
						
							|  |  |  |           .toEqual(`class SomeClass { get someGetter() { this.someMethod(); } }`); | 
					
						
							|  |  |  |       expect( | 
					
						
							|  |  |  |           emitStmt(new o.ClassStmt( | 
					
						
							|  |  |  |               'SomeClass', null !, [], | 
					
						
							|  |  |  |               [new o.ClassGetter('someGetter', [], null !, [o.StmtModifier.Private])], null !, []))) | 
					
						
							|  |  |  |           .toEqual(`class SomeClass { get someGetter() { } }`); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     it('should support methods', () => { | 
					
						
							|  |  |  |       expect(emitStmt(new o.ClassStmt('SomeClass', null !, [], [], null !, [ | 
					
						
							|  |  |  |         new o.ClassMethod('someMethod', [], []) | 
					
						
							|  |  |  |       ]))).toEqual(`class SomeClass { someMethod() { } }`); | 
					
						
							|  |  |  |       expect(emitStmt(new o.ClassStmt('SomeClass', null !, [], [], null !, [ | 
					
						
							|  |  |  |         new o.ClassMethod('someMethod', [], [], o.INT_TYPE) | 
					
						
							|  |  |  |       ]))).toEqual(`class SomeClass { someMethod() { } }`); | 
					
						
							|  |  |  |       expect(emitStmt(new o.ClassStmt('SomeClass', null !, [], [], null !, [ | 
					
						
							|  |  |  |         new o.ClassMethod('someMethod', [new o.FnParam('someParam', o.INT_TYPE)], []) | 
					
						
							|  |  |  |       ]))).toEqual(`class SomeClass { someMethod(someParam) { } }`); | 
					
						
							|  |  |  |       expect(emitStmt(new o.ClassStmt('SomeClass', null !, [], [], null !, [ | 
					
						
							|  |  |  |         new o.ClassMethod('someMethod', [], [callSomeMethod]) | 
					
						
							|  |  |  |       ]))).toEqual(`class SomeClass { someMethod() { this.someMethod(); } }`); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   it('should support builtin types', () => { | 
					
						
							|  |  |  |     const writeVarExpr = o.variable('a').set(o.NULL_EXPR); | 
					
						
							|  |  |  |     expect(emitStmt(writeVarExpr.toDeclStmt(o.DYNAMIC_TYPE))).toEqual('var a = null;'); | 
					
						
							|  |  |  |     expect(emitStmt(writeVarExpr.toDeclStmt(o.BOOL_TYPE))).toEqual('var a = null;'); | 
					
						
							|  |  |  |     expect(emitStmt(writeVarExpr.toDeclStmt(o.INT_TYPE))).toEqual('var a = null;'); | 
					
						
							|  |  |  |     expect(emitStmt(writeVarExpr.toDeclStmt(o.NUMBER_TYPE))).toEqual('var a = null;'); | 
					
						
							|  |  |  |     expect(emitStmt(writeVarExpr.toDeclStmt(o.STRING_TYPE))).toEqual('var a = null;'); | 
					
						
							|  |  |  |     expect(emitStmt(writeVarExpr.toDeclStmt(o.FUNCTION_TYPE))).toEqual('var a = null;'); | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   it('should support external types', () => { | 
					
						
							|  |  |  |     const writeVarExpr = o.variable('a').set(o.NULL_EXPR); | 
					
						
							|  |  |  |     expect(emitStmt(writeVarExpr.toDeclStmt(o.importType(sameModuleIdentifier)))) | 
					
						
							|  |  |  |         .toEqual('var a = null;'); | 
					
						
							|  |  |  |     expect(emitStmt(writeVarExpr.toDeclStmt(o.importType(externalModuleIdentifier)))) | 
					
						
							|  |  |  |         .toEqual(`var a = null;`); | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   it('should support expression types', () => { | 
					
						
							|  |  |  |     expect(emitStmt(o.variable('a').set(o.NULL_EXPR).toDeclStmt(o.expressionType(o.variable('b'))))) | 
					
						
							|  |  |  |         .toEqual('var a = null;'); | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   it('should support expressions with type parameters', () => { | 
					
						
							|  |  |  |     expect(emitStmt(o.variable('a') | 
					
						
							|  |  |  |                         .set(o.NULL_EXPR) | 
					
						
							|  |  |  |                         .toDeclStmt(o.importType(externalModuleIdentifier, [o.STRING_TYPE])))) | 
					
						
							|  |  |  |         .toEqual(`var a = null;`); | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   it('should support combined types', () => { | 
					
						
							|  |  |  |     const writeVarExpr = o.variable('a').set(o.NULL_EXPR); | 
					
						
							|  |  |  |     expect(emitStmt(writeVarExpr.toDeclStmt(new o.ArrayType(null !)))).toEqual('var a = null;'); | 
					
						
							|  |  |  |     expect(emitStmt(writeVarExpr.toDeclStmt(new o.ArrayType(o.INT_TYPE)))).toEqual('var a = null;'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     expect(emitStmt(writeVarExpr.toDeclStmt(new o.MapType(null)))).toEqual('var a = null;'); | 
					
						
							|  |  |  |     expect(emitStmt(writeVarExpr.toDeclStmt(new o.MapType(o.INT_TYPE)))).toEqual('var a = null;'); | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-26 09:26:18 -07:00
										 |  |  |   describe('source maps', () => { | 
					
						
							|  |  |  |     function emitStmt(stmt: o.Statement | o.Statement[], preamble?: string): string { | 
					
						
							|  |  |  |       const stmts = Array.isArray(stmt) ? stmt : [stmt]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       const program = ts.createProgram( | 
					
						
							|  |  |  |           [someGenFileName], { | 
					
						
							|  |  |  |             module: ts.ModuleKind.CommonJS, | 
					
						
							|  |  |  |             target: ts.ScriptTarget.ES2017, | 
					
						
							|  |  |  |             sourceMap: true, | 
					
						
							|  |  |  |             inlineSourceMap: true, | 
					
						
							|  |  |  |             inlineSources: true, | 
					
						
							|  |  |  |           }, | 
					
						
							|  |  |  |           host); | 
					
						
							|  |  |  |       const moduleSourceFile = program.getSourceFile(someGenFileName); | 
					
						
							|  |  |  |       const transformers: ts.CustomTransformers = { | 
					
						
							|  |  |  |         before: [context => { | 
					
						
							|  |  |  |           return sourceFile => { | 
					
						
							|  |  |  |             const [newSourceFile] = emitter.updateSourceFile(sourceFile, stmts, preamble); | 
					
						
							|  |  |  |             return newSourceFile; | 
					
						
							|  |  |  |           }; | 
					
						
							|  |  |  |         }] | 
					
						
							|  |  |  |       }; | 
					
						
							|  |  |  |       let result: string = ''; | 
					
						
							|  |  |  |       const emitResult = program.emit( | 
					
						
							|  |  |  |           moduleSourceFile, (fileName, data, writeByteOrderMark, onError, sourceFiles) => { | 
					
						
							|  |  |  |             if (fileName.startsWith(someGenFilePath)) { | 
					
						
							|  |  |  |               result = data; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |           }, undefined, undefined, transformers); | 
					
						
							|  |  |  |       return result; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-06-25 11:22:23 -07:00
										 |  |  |     function mappingItemsOf(text: string) { | 
					
						
							| 
									
										
										
										
											2017-10-05 10:05:57 -07:00
										 |  |  |       // find the source map:
 | 
					
						
							|  |  |  |       const sourceMapMatch = /sourceMappingURL\=data\:application\/json;base64,(.*)$/.exec(text); | 
					
						
							|  |  |  |       const sourceMapBase64 = sourceMapMatch ![1]; | 
					
						
							|  |  |  |       const sourceMapBuffer = Buffer.from(sourceMapBase64, 'base64'); | 
					
						
							|  |  |  |       const sourceMapText = sourceMapBuffer.toString('utf8'); | 
					
						
							| 
									
										
										
										
											2018-06-25 11:22:23 -07:00
										 |  |  |       const sourceMapParsed = JSON.parse(sourceMapText); | 
					
						
							|  |  |  |       const consumer = new sourceMap.SourceMapConsumer(sourceMapParsed); | 
					
						
							|  |  |  |       const mappings: any[] = []; | 
					
						
							|  |  |  |       consumer.eachMapping((mapping: any) => { mappings.push(mapping); }); | 
					
						
							| 
									
										
										
										
											2017-10-05 10:05:57 -07:00
										 |  |  |       return mappings; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-26 09:26:18 -07:00
										 |  |  |     it('should produce a source map that maps back to the source', () => { | 
					
						
							|  |  |  |       const statement = someVar.set(o.literal(1)).toDeclStmt(); | 
					
						
							|  |  |  |       const text = '<my-comp> a = 1 </my-comp>'; | 
					
						
							| 
									
										
										
										
											2017-10-04 13:37:27 -07:00
										 |  |  |       const sourceName = '/some/file.html'; | 
					
						
							|  |  |  |       const sourceUrl = '../some/file.html'; | 
					
						
							| 
									
										
										
										
											2017-09-26 09:26:18 -07:00
										 |  |  |       const file = new ParseSourceFile(text, sourceName); | 
					
						
							|  |  |  |       const start = new ParseLocation(file, 0, 0, 0); | 
					
						
							|  |  |  |       const end = new ParseLocation(file, text.length, 0, text.length); | 
					
						
							|  |  |  |       statement.sourceSpan = new ParseSourceSpan(start, end); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       const result = emitStmt(statement); | 
					
						
							| 
									
										
										
										
											2017-10-05 10:05:57 -07:00
										 |  |  |       const mappings = mappingItemsOf(result); | 
					
						
							| 
									
										
										
										
											2017-09-26 09:26:18 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |       expect(mappings).toEqual([ | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |           source: sourceUrl, | 
					
						
							|  |  |  |           generatedLine: 3, | 
					
						
							|  |  |  |           generatedColumn: 0, | 
					
						
							|  |  |  |           originalLine: 1, | 
					
						
							|  |  |  |           originalColumn: 0, | 
					
						
							| 
									
										
										
										
											2017-10-24 14:54:08 +03:00
										 |  |  |           name: null !  // TODO: Review use of `!` here (#19904)
 | 
					
						
							| 
									
										
										
										
											2017-09-26 09:26:18 -07:00
										 |  |  |         }, | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |           source: sourceUrl, | 
					
						
							|  |  |  |           generatedLine: 3, | 
					
						
							|  |  |  |           generatedColumn: 16, | 
					
						
							|  |  |  |           originalLine: 1, | 
					
						
							|  |  |  |           originalColumn: 26, | 
					
						
							| 
									
										
										
										
											2017-10-24 14:54:08 +03:00
										 |  |  |           name: null !  // TODO: Review use of `!` here (#19904)
 | 
					
						
							| 
									
										
										
										
											2017-09-26 09:26:18 -07:00
										 |  |  |         } | 
					
						
							|  |  |  |       ]); | 
					
						
							|  |  |  |     }); | 
					
						
							| 
									
										
										
										
											2017-10-05 10:05:57 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |     it('should produce a mapping per range instead of a mapping per node', () => { | 
					
						
							|  |  |  |       const text = '<my-comp> a = 1 </my-comp>'; | 
					
						
							|  |  |  |       const sourceName = '/some/file.html'; | 
					
						
							|  |  |  |       const sourceUrl = '../some/file.html'; | 
					
						
							|  |  |  |       const file = new ParseSourceFile(text, sourceName); | 
					
						
							|  |  |  |       const start = new ParseLocation(file, 0, 0, 0); | 
					
						
							|  |  |  |       const end = new ParseLocation(file, text.length, 0, text.length); | 
					
						
							|  |  |  |       const stmt = (loc: number) => { | 
					
						
							|  |  |  |         const start = new ParseLocation(file, loc, 0, loc); | 
					
						
							|  |  |  |         const end = new ParseLocation(file, loc + 1, 0, loc + 1); | 
					
						
							|  |  |  |         const span = new ParseSourceSpan(start, end); | 
					
						
							|  |  |  |         return someVar | 
					
						
							|  |  |  |             .set(new o.BinaryOperatorExpr( | 
					
						
							|  |  |  |                 o.BinaryOperator.Plus, o.literal(loc, null, span), o.literal(loc, null, span), null, | 
					
						
							|  |  |  |                 span)) | 
					
						
							|  |  |  |             .toDeclStmt(); | 
					
						
							|  |  |  |       }; | 
					
						
							|  |  |  |       const stmts = [1, 2, 3, 4, 5, 6].map(stmt); | 
					
						
							|  |  |  |       const result = emitStmt(stmts); | 
					
						
							|  |  |  |       const mappings = mappingItemsOf(result); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       // The span is used in three different nodes but should only be emitted at most twice
 | 
					
						
							|  |  |  |       // (once for the start and once for the end of a span).
 | 
					
						
							|  |  |  |       const maxDup = Math.max( | 
					
						
							|  |  |  |           ...Array.from(countsOfDuplicatesMap(mappings.map(m => m.originalColumn)).values())); | 
					
						
							|  |  |  |       expect(maxDup <= 2).toBeTruthy('A redundant range was emitted'); | 
					
						
							|  |  |  |     }); | 
					
						
							| 
									
										
										
										
											2017-09-26 09:26:18 -07:00
										 |  |  |   }); | 
					
						
							| 
									
										
										
										
											2017-05-30 11:43:13 -06:00
										 |  |  | }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-10-05 10:05:57 -07:00
										 |  |  | function countsOfDuplicatesMap<T>(a: T[]): Map<T, number> { | 
					
						
							|  |  |  |   const result = new Map<T, number>(); | 
					
						
							|  |  |  |   for (const item of a) { | 
					
						
							|  |  |  |     result.set(item, (result.get(item) || 0) + 1); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   return result; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-05-30 11:43:13 -06:00
										 |  |  | const FILES: Directory = { | 
					
						
							|  |  |  |   somePackage: {'someGenFile.ts': `export var a: number;`} | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-12 15:34:03 +01:00
										 |  |  | const enum Format { Raw, Flat } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | function normalizeResult(result: string, format: Format): string { | 
					
						
							| 
									
										
										
										
											2017-05-30 11:43:13 -06:00
										 |  |  |   // Remove TypeScript prefixes
 | 
					
						
							| 
									
										
										
										
											2018-03-12 15:34:03 +01:00
										 |  |  |   let res = result.replace('"use strict";', ' ') | 
					
						
							|  |  |  |                 .replace('exports.__esModule = true;', ' ') | 
					
						
							|  |  |  |                 .replace('Object.defineProperty(exports, "__esModule", { value: true });', ' '); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-05-30 11:43:13 -06:00
										 |  |  |   // Remove new lines
 | 
					
						
							|  |  |  |   // Squish adjacent spaces
 | 
					
						
							| 
									
										
										
										
											2018-03-12 15:34:03 +01:00
										 |  |  |   if (format === Format.Flat) { | 
					
						
							|  |  |  |     return res.replace(/\n/g, ' ').replace(/ +/g, ' ').replace(/^ /g, '').replace(/ $/g, ''); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-05-30 11:43:13 -06:00
										 |  |  |   // Remove prefix and postfix spaces
 | 
					
						
							| 
									
										
										
										
											2018-03-12 15:34:03 +01:00
										 |  |  |   return res.trim(); | 
					
						
							| 
									
										
										
										
											2017-05-30 11:43:13 -06:00
										 |  |  | } |