| 
									
										
										
										
											2017-09-13 16:55:42 -07: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
 | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import * as fs from 'fs'; | 
					
						
							|  |  |  | import * as ts from 'typescript'; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import {Evaluator} from '../../src/metadata/evaluator'; | 
					
						
							|  |  |  | import {Symbols} from '../../src/metadata/symbols'; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import {Directory, Host, expectNoDiagnostics, findVar, findVarInitializer} from './typescript.mocks'; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | describe('Evaluator', () => { | 
					
						
							|  |  |  |   const documentRegistry = ts.createDocumentRegistry(); | 
					
						
							|  |  |  |   let host: ts.LanguageServiceHost; | 
					
						
							|  |  |  |   let service: ts.LanguageService; | 
					
						
							|  |  |  |   let program: ts.Program; | 
					
						
							|  |  |  |   let typeChecker: ts.TypeChecker; | 
					
						
							|  |  |  |   let symbols: Symbols; | 
					
						
							|  |  |  |   let evaluator: Evaluator; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   beforeEach(() => { | 
					
						
							|  |  |  |     host = new Host(FILES, [ | 
					
						
							|  |  |  |       'expressions.ts', 'consts.ts', 'const_expr.ts', 'forwardRef.ts', 'classes.ts', | 
					
						
							|  |  |  |       'newExpression.ts', 'errors.ts', 'declared.ts' | 
					
						
							|  |  |  |     ]); | 
					
						
							|  |  |  |     service = ts.createLanguageService(host, documentRegistry); | 
					
						
							| 
									
										
										
										
											2018-08-05 17:31:27 +02:00
										 |  |  |     program = service.getProgram() !; | 
					
						
							| 
									
										
										
										
											2017-09-13 16:55:42 -07:00
										 |  |  |     typeChecker = program.getTypeChecker(); | 
					
						
							|  |  |  |     symbols = new Symbols(null as any as ts.SourceFile); | 
					
						
							|  |  |  |     evaluator = new Evaluator(symbols, new Map()); | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   it('should not have typescript errors in test data', () => { | 
					
						
							|  |  |  |     expectNoDiagnostics(service.getCompilerOptionsDiagnostics()); | 
					
						
							|  |  |  |     for (const sourceFile of program.getSourceFiles()) { | 
					
						
							|  |  |  |       expectNoDiagnostics(service.getSyntacticDiagnostics(sourceFile.fileName)); | 
					
						
							|  |  |  |       if (sourceFile.fileName != 'errors.ts') { | 
					
						
							|  |  |  |         // Skip errors.ts because we it has intentional semantic errors that we are testing for.
 | 
					
						
							|  |  |  |         expectNoDiagnostics(service.getSemanticDiagnostics(sourceFile.fileName)); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   it('should be able to fold literal expressions', () => { | 
					
						
							| 
									
										
										
										
											2018-02-08 08:59:25 -08:00
										 |  |  |     const consts = program.getSourceFile('consts.ts') !; | 
					
						
							| 
									
										
										
										
											2017-09-13 16:55:42 -07:00
										 |  |  |     expect(evaluator.isFoldable(findVarInitializer(consts, 'someName'))).toBeTruthy(); | 
					
						
							|  |  |  |     expect(evaluator.isFoldable(findVarInitializer(consts, 'someBool'))).toBeTruthy(); | 
					
						
							|  |  |  |     expect(evaluator.isFoldable(findVarInitializer(consts, 'one'))).toBeTruthy(); | 
					
						
							|  |  |  |     expect(evaluator.isFoldable(findVarInitializer(consts, 'two'))).toBeTruthy(); | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   it('should be able to fold expressions with foldable references', () => { | 
					
						
							| 
									
										
										
										
											2018-02-08 08:59:25 -08:00
										 |  |  |     const expressions = program.getSourceFile('expressions.ts') !; | 
					
						
							| 
									
										
										
										
											2017-09-13 16:55:42 -07:00
										 |  |  |     symbols.define('someName', 'some-name'); | 
					
						
							|  |  |  |     symbols.define('someBool', true); | 
					
						
							|  |  |  |     symbols.define('one', 1); | 
					
						
							|  |  |  |     symbols.define('two', 2); | 
					
						
							|  |  |  |     expect(evaluator.isFoldable(findVarInitializer(expressions, 'three'))).toBeTruthy(); | 
					
						
							|  |  |  |     expect(evaluator.isFoldable(findVarInitializer(expressions, 'four'))).toBeTruthy(); | 
					
						
							|  |  |  |     symbols.define('three', 3); | 
					
						
							|  |  |  |     symbols.define('four', 4); | 
					
						
							|  |  |  |     expect(evaluator.isFoldable(findVarInitializer(expressions, 'obj'))).toBeTruthy(); | 
					
						
							|  |  |  |     expect(evaluator.isFoldable(findVarInitializer(expressions, 'arr'))).toBeTruthy(); | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   it('should be able to evaluate literal expressions', () => { | 
					
						
							| 
									
										
										
										
											2018-02-08 08:59:25 -08:00
										 |  |  |     const consts = program.getSourceFile('consts.ts') !; | 
					
						
							| 
									
										
										
										
											2017-09-13 16:55:42 -07:00
										 |  |  |     expect(evaluator.evaluateNode(findVarInitializer(consts, 'someName'))).toBe('some-name'); | 
					
						
							|  |  |  |     expect(evaluator.evaluateNode(findVarInitializer(consts, 'someBool'))).toBe(true); | 
					
						
							|  |  |  |     expect(evaluator.evaluateNode(findVarInitializer(consts, 'one'))).toBe(1); | 
					
						
							|  |  |  |     expect(evaluator.evaluateNode(findVarInitializer(consts, 'two'))).toBe(2); | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   it('should be able to evaluate expressions', () => { | 
					
						
							| 
									
										
										
										
											2018-02-08 08:59:25 -08:00
										 |  |  |     const expressions = program.getSourceFile('expressions.ts') !; | 
					
						
							| 
									
										
										
										
											2017-09-13 16:55:42 -07:00
										 |  |  |     symbols.define('someName', 'some-name'); | 
					
						
							|  |  |  |     symbols.define('someBool', true); | 
					
						
							|  |  |  |     symbols.define('one', 1); | 
					
						
							|  |  |  |     symbols.define('two', 2); | 
					
						
							|  |  |  |     expect(evaluator.evaluateNode(findVarInitializer(expressions, 'three'))).toBe(3); | 
					
						
							|  |  |  |     symbols.define('three', 3); | 
					
						
							|  |  |  |     expect(evaluator.evaluateNode(findVarInitializer(expressions, 'four'))).toBe(4); | 
					
						
							|  |  |  |     symbols.define('four', 4); | 
					
						
							|  |  |  |     expect(evaluator.evaluateNode(findVarInitializer(expressions, 'obj'))) | 
					
						
							|  |  |  |         .toEqual({one: 1, two: 2, three: 3, four: 4}); | 
					
						
							|  |  |  |     expect(evaluator.evaluateNode(findVarInitializer(expressions, 'arr'))).toEqual([1, 2, 3, 4]); | 
					
						
							|  |  |  |     expect(evaluator.evaluateNode(findVarInitializer(expressions, 'bTrue'))).toEqual(true); | 
					
						
							|  |  |  |     expect(evaluator.evaluateNode(findVarInitializer(expressions, 'bFalse'))).toEqual(false); | 
					
						
							|  |  |  |     expect(evaluator.evaluateNode(findVarInitializer(expressions, 'bAnd'))).toEqual(true); | 
					
						
							|  |  |  |     expect(evaluator.evaluateNode(findVarInitializer(expressions, 'bOr'))).toEqual(true); | 
					
						
							|  |  |  |     expect(evaluator.evaluateNode(findVarInitializer(expressions, 'nDiv'))).toEqual(2); | 
					
						
							|  |  |  |     expect(evaluator.evaluateNode(findVarInitializer(expressions, 'nMod'))).toEqual(1); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     expect(evaluator.evaluateNode(findVarInitializer(expressions, 'bLOr'))).toEqual(false || true); | 
					
						
							|  |  |  |     expect(evaluator.evaluateNode(findVarInitializer(expressions, 'bLAnd'))).toEqual(true && true); | 
					
						
							|  |  |  |     expect(evaluator.evaluateNode(findVarInitializer(expressions, 'bBOr'))).toEqual(0x11 | 0x22); | 
					
						
							|  |  |  |     expect(evaluator.evaluateNode(findVarInitializer(expressions, 'bBAnd'))).toEqual(0x11 & 0x03); | 
					
						
							|  |  |  |     expect(evaluator.evaluateNode(findVarInitializer(expressions, 'bXor'))).toEqual(0x11 ^ 0x21); | 
					
						
							|  |  |  |     expect(evaluator.evaluateNode(findVarInitializer(expressions, 'bEqual'))) | 
					
						
							|  |  |  |         .toEqual(1 == <any>'1'); | 
					
						
							|  |  |  |     expect(evaluator.evaluateNode(findVarInitializer(expressions, 'bNotEqual'))) | 
					
						
							|  |  |  |         .toEqual(1 != <any>'1'); | 
					
						
							|  |  |  |     expect(evaluator.evaluateNode(findVarInitializer(expressions, 'bIdentical'))) | 
					
						
							|  |  |  |         .toEqual(1 === <any>'1'); | 
					
						
							|  |  |  |     expect(evaluator.evaluateNode(findVarInitializer(expressions, 'bNotIdentical'))) | 
					
						
							|  |  |  |         .toEqual(1 !== <any>'1'); | 
					
						
							|  |  |  |     expect(evaluator.evaluateNode(findVarInitializer(expressions, 'bLessThan'))).toEqual(1 < 2); | 
					
						
							|  |  |  |     expect(evaluator.evaluateNode(findVarInitializer(expressions, 'bGreaterThan'))).toEqual(1 > 2); | 
					
						
							|  |  |  |     expect(evaluator.evaluateNode(findVarInitializer(expressions, 'bLessThanEqual'))) | 
					
						
							|  |  |  |         .toEqual(1 <= 2); | 
					
						
							|  |  |  |     expect(evaluator.evaluateNode(findVarInitializer(expressions, 'bGreaterThanEqual'))) | 
					
						
							|  |  |  |         .toEqual(1 >= 2); | 
					
						
							|  |  |  |     expect(evaluator.evaluateNode(findVarInitializer(expressions, 'bShiftLeft'))).toEqual(1 << 2); | 
					
						
							|  |  |  |     expect(evaluator.evaluateNode(findVarInitializer(expressions, 'bShiftRight'))).toEqual(-1 >> 2); | 
					
						
							|  |  |  |     expect(evaluator.evaluateNode(findVarInitializer(expressions, 'bShiftRightU'))) | 
					
						
							|  |  |  |         .toEqual(-1 >>> 2); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   it('should report recursive references as symbolic', () => { | 
					
						
							| 
									
										
										
										
											2018-02-08 08:59:25 -08:00
										 |  |  |     const expressions = program.getSourceFile('expressions.ts') !; | 
					
						
							| 
									
										
										
										
											2017-09-13 16:55:42 -07:00
										 |  |  |     expect(evaluator.evaluateNode(findVarInitializer(expressions, 'recursiveA'))) | 
					
						
							|  |  |  |         .toEqual({__symbolic: 'reference', name: 'recursiveB'}); | 
					
						
							|  |  |  |     expect(evaluator.evaluateNode(findVarInitializer(expressions, 'recursiveB'))) | 
					
						
							|  |  |  |         .toEqual({__symbolic: 'reference', name: 'recursiveA'}); | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   it('should correctly handle special cases for CONST_EXPR', () => { | 
					
						
							| 
									
										
										
										
											2018-02-08 08:59:25 -08:00
										 |  |  |     const const_expr = program.getSourceFile('const_expr.ts') !; | 
					
						
							| 
									
										
										
										
											2017-09-13 16:55:42 -07:00
										 |  |  |     expect(evaluator.evaluateNode(findVarInitializer(const_expr, 'bTrue'))).toEqual(true); | 
					
						
							|  |  |  |     expect(evaluator.evaluateNode(findVarInitializer(const_expr, 'bFalse'))).toEqual(false); | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   it('should resolve a forwardRef', () => { | 
					
						
							| 
									
										
										
										
											2018-02-08 08:59:25 -08:00
										 |  |  |     const forwardRef = program.getSourceFile('forwardRef.ts') !; | 
					
						
							| 
									
										
										
										
											2017-09-13 16:55:42 -07:00
										 |  |  |     expect(evaluator.evaluateNode(findVarInitializer(forwardRef, 'bTrue'))).toEqual(true); | 
					
						
							|  |  |  |     expect(evaluator.evaluateNode(findVarInitializer(forwardRef, 'bFalse'))).toEqual(false); | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   it('should return new expressions', () => { | 
					
						
							|  |  |  |     symbols.define('Value', {__symbolic: 'reference', module: './classes', name: 'Value'}); | 
					
						
							|  |  |  |     evaluator = new Evaluator(symbols, new Map()); | 
					
						
							| 
									
										
										
										
											2018-02-08 08:59:25 -08:00
										 |  |  |     const newExpression = program.getSourceFile('newExpression.ts') !; | 
					
						
							| 
									
										
										
										
											2017-09-13 16:55:42 -07:00
										 |  |  |     expect(evaluator.evaluateNode(findVarInitializer(newExpression, 'someValue'))).toEqual({ | 
					
						
							|  |  |  |       __symbolic: 'new', | 
					
						
							| 
									
										
										
										
											2017-11-14 17:49:47 -08:00
										 |  |  |       expression: | 
					
						
							|  |  |  |           {__symbolic: 'reference', name: 'Value', module: './classes', line: 4, character: 33}, | 
					
						
							| 
									
										
										
										
											2017-09-13 16:55:42 -07:00
										 |  |  |       arguments: ['name', 12] | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  |     expect(evaluator.evaluateNode(findVarInitializer(newExpression, 'complex'))).toEqual({ | 
					
						
							|  |  |  |       __symbolic: 'new', | 
					
						
							| 
									
										
										
										
											2017-11-14 17:49:47 -08:00
										 |  |  |       expression: | 
					
						
							|  |  |  |           {__symbolic: 'reference', name: 'Value', module: './classes', line: 5, character: 42}, | 
					
						
							| 
									
										
										
										
											2017-09-13 16:55:42 -07:00
										 |  |  |       arguments: ['name', 12] | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   it('should support referene to a declared module type', () => { | 
					
						
							| 
									
										
										
										
											2018-02-08 08:59:25 -08:00
										 |  |  |     const declared = program.getSourceFile('declared.ts') !; | 
					
						
							| 
									
										
										
										
											2017-09-13 16:55:42 -07:00
										 |  |  |     const aDecl = findVar(declared, 'a') !; | 
					
						
							|  |  |  |     expect(evaluator.evaluateNode(aDecl.type !)).toEqual({ | 
					
						
							|  |  |  |       __symbolic: 'select', | 
					
						
							|  |  |  |       expression: {__symbolic: 'reference', name: 'Foo'}, | 
					
						
							|  |  |  |       member: 'A' | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   it('should return errors for unsupported expressions', () => { | 
					
						
							| 
									
										
										
										
											2018-02-08 08:59:25 -08:00
										 |  |  |     const errors = program.getSourceFile('errors.ts') !; | 
					
						
							| 
									
										
										
										
											2017-09-13 16:55:42 -07:00
										 |  |  |     const fDecl = findVar(errors, 'f') !; | 
					
						
							|  |  |  |     expect(evaluator.evaluateNode(fDecl.initializer !)) | 
					
						
							| 
									
										
										
										
											2017-11-14 17:49:47 -08:00
										 |  |  |         .toEqual({__symbolic: 'error', message: 'Lambda not supported', line: 1, character: 12}); | 
					
						
							| 
									
										
										
										
											2017-09-13 16:55:42 -07:00
										 |  |  |     const eDecl = findVar(errors, 'e') !; | 
					
						
							|  |  |  |     expect(evaluator.evaluateNode(eDecl.type !)).toEqual({ | 
					
						
							|  |  |  |       __symbolic: 'error', | 
					
						
							|  |  |  |       message: 'Could not resolve type', | 
					
						
							|  |  |  |       line: 2, | 
					
						
							|  |  |  |       character: 11, | 
					
						
							|  |  |  |       context: {typeName: 'NotFound'} | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  |     const sDecl = findVar(errors, 's') !; | 
					
						
							|  |  |  |     expect(evaluator.evaluateNode(sDecl.initializer !)).toEqual({ | 
					
						
							|  |  |  |       __symbolic: 'error', | 
					
						
							|  |  |  |       message: 'Name expected', | 
					
						
							|  |  |  |       line: 3, | 
					
						
							|  |  |  |       character: 14, | 
					
						
							|  |  |  |       context: {received: '1'} | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  |     const tDecl = findVar(errors, 't') !; | 
					
						
							|  |  |  |     expect(evaluator.evaluateNode(tDecl.initializer !)).toEqual({ | 
					
						
							|  |  |  |       __symbolic: 'error', | 
					
						
							|  |  |  |       message: 'Expression form not supported', | 
					
						
							|  |  |  |       line: 4, | 
					
						
							|  |  |  |       character: 12 | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   it('should be able to fold an array spread', () => { | 
					
						
							| 
									
										
										
										
											2018-02-08 08:59:25 -08:00
										 |  |  |     const expressions = program.getSourceFile('expressions.ts') !; | 
					
						
							| 
									
										
										
										
											2017-09-13 16:55:42 -07:00
										 |  |  |     symbols.define('arr', [1, 2, 3, 4]); | 
					
						
							|  |  |  |     const arrSpread = findVar(expressions, 'arrSpread') !; | 
					
						
							|  |  |  |     expect(evaluator.evaluateNode(arrSpread.initializer !)).toEqual([0, 1, 2, 3, 4, 5]); | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   it('should be able to produce a spread expression', () => { | 
					
						
							| 
									
										
										
										
											2018-02-08 08:59:25 -08:00
										 |  |  |     const expressions = program.getSourceFile('expressions.ts') !; | 
					
						
							| 
									
										
										
										
											2017-09-13 16:55:42 -07:00
										 |  |  |     const arrSpreadRef = findVar(expressions, 'arrSpreadRef') !; | 
					
						
							|  |  |  |     expect(evaluator.evaluateNode(arrSpreadRef.initializer !)).toEqual([ | 
					
						
							|  |  |  |       0, {__symbolic: 'spread', expression: {__symbolic: 'reference', name: 'arrImport'}}, 5 | 
					
						
							|  |  |  |     ]); | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   it('should be able to handle a new expression with no arguments', () => { | 
					
						
							|  |  |  |     const source = sourceFileOf(`
 | 
					
						
							|  |  |  |       export var a = new f; | 
					
						
							|  |  |  |     `);
 | 
					
						
							|  |  |  |     const expr = findVar(source, 'a') !; | 
					
						
							|  |  |  |     expect(evaluator.evaluateNode(expr.initializer !)) | 
					
						
							|  |  |  |         .toEqual({__symbolic: 'new', expression: {__symbolic: 'reference', name: 'f'}}); | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   describe('with substitution', () => { | 
					
						
							|  |  |  |     let evaluator: Evaluator; | 
					
						
							|  |  |  |     const lambdaTemp = 'lambdaTemp'; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     beforeEach(() => { | 
					
						
							|  |  |  |       evaluator = new Evaluator(symbols, new Map(), { | 
					
						
							|  |  |  |         substituteExpression: (value, node) => { | 
					
						
							|  |  |  |           if (node.kind == ts.SyntaxKind.ArrowFunction) { | 
					
						
							|  |  |  |             return {__symbolic: 'reference', name: lambdaTemp}; | 
					
						
							|  |  |  |           } | 
					
						
							|  |  |  |           return value; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     it('should be able to substitute a lambda with a reference', () => { | 
					
						
							|  |  |  |       const source = sourceFileOf(`
 | 
					
						
							|  |  |  |         var b = 1; | 
					
						
							|  |  |  |         export var a = () => b; | 
					
						
							|  |  |  |       `);
 | 
					
						
							|  |  |  |       const expr = findVar(source, 'a'); | 
					
						
							|  |  |  |       expect(evaluator.evaluateNode(expr !.initializer !)) | 
					
						
							|  |  |  |           .toEqual({__symbolic: 'reference', name: lambdaTemp}); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     it('should be able to substitute a lambda in an expression', () => { | 
					
						
							|  |  |  |       const source = sourceFileOf(`
 | 
					
						
							|  |  |  |         var b = 1; | 
					
						
							|  |  |  |         export var a = [ | 
					
						
							|  |  |  |           { provide: 'someValue': useFactory: () => b } | 
					
						
							|  |  |  |         ]; | 
					
						
							|  |  |  |       `);
 | 
					
						
							|  |  |  |       const expr = findVar(source, 'a'); | 
					
						
							|  |  |  |       expect(evaluator.evaluateNode(expr !.initializer !)).toEqual([ | 
					
						
							|  |  |  |         {provide: 'someValue', useFactory: {__symbolic: 'reference', name: lambdaTemp}} | 
					
						
							|  |  |  |       ]); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | function sourceFileOf(text: string): ts.SourceFile { | 
					
						
							|  |  |  |   return ts.createSourceFile('test.ts', text, ts.ScriptTarget.Latest, true); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const FILES: Directory = { | 
					
						
							|  |  |  |   'directives.ts': `
 | 
					
						
							|  |  |  |     export function Pipe(options: { name?: string, pure?: boolean}) { | 
					
						
							|  |  |  |       return function(fn: Function) { } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     `,
 | 
					
						
							|  |  |  |   'classes.ts': `
 | 
					
						
							|  |  |  |     export class Value { | 
					
						
							|  |  |  |       constructor(public name: string, public value: any) {} | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   `,
 | 
					
						
							|  |  |  |   'consts.ts': `
 | 
					
						
							|  |  |  |     export var someName = 'some-name'; | 
					
						
							|  |  |  |     export var someBool = true; | 
					
						
							|  |  |  |     export var one = 1; | 
					
						
							|  |  |  |     export var two = 2; | 
					
						
							|  |  |  |     export var arrImport = [1, 2, 3, 4]; | 
					
						
							|  |  |  |   `,
 | 
					
						
							|  |  |  |   'expressions.ts': `
 | 
					
						
							|  |  |  |     import {arrImport} from './consts'; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     export var someName = 'some-name'; | 
					
						
							|  |  |  |     export var someBool = true; | 
					
						
							|  |  |  |     export var one = 1; | 
					
						
							|  |  |  |     export var two = 2; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     export var three = one + two; | 
					
						
							|  |  |  |     export var four = two * two; | 
					
						
							|  |  |  |     export var obj = { one: one, two: two, three: three, four: four }; | 
					
						
							|  |  |  |     export var arr = [one, two, three, four]; | 
					
						
							|  |  |  |     export var bTrue = someBool; | 
					
						
							|  |  |  |     export var bFalse = !someBool; | 
					
						
							|  |  |  |     export var bAnd = someBool && someBool; | 
					
						
							|  |  |  |     export var bOr = someBool || someBool; | 
					
						
							|  |  |  |     export var nDiv = four / two; | 
					
						
							|  |  |  |     export var nMod = (four + one) % two; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     export var bLOr = false || true;             // true
 | 
					
						
							|  |  |  |     export var bLAnd = true && true;             // true
 | 
					
						
							|  |  |  |     export var bBOr = 0x11 | 0x22;               // 0x33
 | 
					
						
							|  |  |  |     export var bBAnd = 0x11 & 0x03;              // 0x01
 | 
					
						
							|  |  |  |     export var bXor = 0x11 ^ 0x21;               // 0x20
 | 
					
						
							|  |  |  |     export var bEqual = 1 == <any>"1";           // true
 | 
					
						
							|  |  |  |     export var bNotEqual = 1 != <any>"1";        // false
 | 
					
						
							|  |  |  |     export var bIdentical = 1 === <any>"1";      // false
 | 
					
						
							|  |  |  |     export var bNotIdentical = 1 !== <any>"1";   // true
 | 
					
						
							|  |  |  |     export var bLessThan = 1 < 2;                // true
 | 
					
						
							|  |  |  |     export var bGreaterThan = 1 > 2;             // false
 | 
					
						
							|  |  |  |     export var bLessThanEqual = 1 <= 2;          // true
 | 
					
						
							|  |  |  |     export var bGreaterThanEqual = 1 >= 2;       // false
 | 
					
						
							|  |  |  |     export var bShiftLeft = 1 << 2;              // 0x04
 | 
					
						
							|  |  |  |     export var bShiftRight = -1 >> 2;            // -1
 | 
					
						
							|  |  |  |     export var bShiftRightU = -1 >>> 2;          // 0x3fffffff
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     export var arrSpread = [0, ...arr, 5]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     export var arrSpreadRef = [0, ...arrImport, 5]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     export var recursiveA = recursiveB; | 
					
						
							|  |  |  |     export var recursiveB = recursiveA; | 
					
						
							|  |  |  |   `,
 | 
					
						
							|  |  |  |   'A.ts': `
 | 
					
						
							|  |  |  |     import {Pipe} from './directives'; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     @Pipe({name: 'A', pure: false}) | 
					
						
							|  |  |  |     export class A {}`,
 | 
					
						
							|  |  |  |   'B.ts': `
 | 
					
						
							|  |  |  |     import {Pipe} from './directives'; | 
					
						
							|  |  |  |     import {someName, someBool} from './consts'; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     @Pipe({name: someName, pure: someBool}) | 
					
						
							|  |  |  |     export class B {}`,
 | 
					
						
							|  |  |  |   'const_expr.ts': `
 | 
					
						
							|  |  |  |     function CONST_EXPR(value: any) { return value; } | 
					
						
							|  |  |  |     export var bTrue = CONST_EXPR(true); | 
					
						
							|  |  |  |     export var bFalse = CONST_EXPR(false); | 
					
						
							|  |  |  |   `,
 | 
					
						
							|  |  |  |   'forwardRef.ts': `
 | 
					
						
							|  |  |  |     function forwardRef(value: any) { return value; } | 
					
						
							|  |  |  |     export var bTrue = forwardRef(() => true); | 
					
						
							|  |  |  |     export var bFalse = forwardRef(() => false); | 
					
						
							|  |  |  |   `,
 | 
					
						
							|  |  |  |   'newExpression.ts': `
 | 
					
						
							|  |  |  |     import {Value} from './classes'; | 
					
						
							|  |  |  |     function CONST_EXPR(value: any) { return value; } | 
					
						
							|  |  |  |     function forwardRef(value: any) { return value; } | 
					
						
							|  |  |  |     export const someValue = new Value("name", 12); | 
					
						
							|  |  |  |     export const complex = CONST_EXPR(new Value("name", forwardRef(() => 12))); | 
					
						
							|  |  |  |   `,
 | 
					
						
							|  |  |  |   'errors.ts': `
 | 
					
						
							|  |  |  |     let f = () => 1; | 
					
						
							|  |  |  |     let e: NotFound; | 
					
						
							|  |  |  |     let s = { 1: 1, 2: 2 }; | 
					
						
							|  |  |  |     let t = typeof 12; | 
					
						
							|  |  |  |   `,
 | 
					
						
							|  |  |  |   'declared.ts': `
 | 
					
						
							|  |  |  |     declare namespace Foo { | 
					
						
							|  |  |  |       type A = string; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     let a: Foo.A = 'some value'; | 
					
						
							|  |  |  |   `
 | 
					
						
							|  |  |  | }; |