| 
									
										
										
										
											2020-01-06 23:12:19 +01:00
										 |  |  | /** | 
					
						
							|  |  |  |  * @license | 
					
						
							| 
									
										
										
										
											2020-05-19 12:08:49 -07:00
										 |  |  |  * Copyright Google LLC All Rights Reserved. | 
					
						
							| 
									
										
										
										
											2020-01-06 23:12:19 +01:00
										 |  |  |  * | 
					
						
							|  |  |  |  * 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 {ErrorCode, makeDiagnostic, ngErrorCode} from '../../../src/ngtsc/diagnostics'; | 
					
						
							|  |  |  | import {absoluteFrom} from '../../../src/ngtsc/file_system'; | 
					
						
							|  |  |  | import {runInEachFileSystem} from '../../../src/ngtsc/file_system/testing'; | 
					
						
							| 
									
										
										
										
											2020-05-14 20:06:12 +01:00
										 |  |  | import {MockLogger} from '../../../src/ngtsc/logging/testing'; | 
					
						
							| 
									
										
										
										
											2020-01-06 23:12:19 +01:00
										 |  |  | import {ClassDeclaration, Decorator, isNamedClassDeclaration} from '../../../src/ngtsc/reflection'; | 
					
						
							|  |  |  | import {getDeclaration} from '../../../src/ngtsc/testing'; | 
					
						
							|  |  |  | import {AnalysisOutput, CompileResult, DecoratorHandler, DetectResult, HandlerPrecedence, TraitState} from '../../../src/ngtsc/transform'; | 
					
						
							|  |  |  | import {loadTestFiles} from '../../../test/helpers'; | 
					
						
							|  |  |  | import {NgccTraitCompiler} from '../../src/analysis/ngcc_trait_compiler'; | 
					
						
							|  |  |  | import {Esm2015ReflectionHost} from '../../src/host/esm2015_host'; | 
					
						
							|  |  |  | import {createComponentDecorator} from '../../src/migrations/utils'; | 
					
						
							|  |  |  | import {EntryPointBundle} from '../../src/packages/entry_point_bundle'; | 
					
						
							|  |  |  | import {makeTestEntryPointBundle} from '../helpers/utils'; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | runInEachFileSystem(() => { | 
					
						
							|  |  |  |   describe('NgccTraitCompiler', () => { | 
					
						
							|  |  |  |     let _: typeof absoluteFrom; | 
					
						
							|  |  |  |     let mockClazz: any; | 
					
						
							|  |  |  |     let injectedDecorator: any = {name: 'InjectedDecorator'}; | 
					
						
							|  |  |  |     beforeEach(() => { | 
					
						
							|  |  |  |       _ = absoluteFrom; | 
					
						
							|  |  |  |       const mockSourceFile: any = { | 
					
						
							|  |  |  |         fileName: _('/node_modules/some-package/entry-point/test-file.js'), | 
					
						
							|  |  |  |       }; | 
					
						
							|  |  |  |       mockClazz = { | 
					
						
							|  |  |  |         name: {text: 'MockClazz'}, | 
					
						
							|  |  |  |         getSourceFile: () => mockSourceFile, | 
					
						
							|  |  |  |         getStart: () => 0, | 
					
						
							|  |  |  |         getWidth: () => 0, | 
					
						
							|  |  |  |       }; | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     function createCompiler({entryPoint, handlers}: { | 
					
						
							|  |  |  |       entryPoint: EntryPointBundle; handlers: DecoratorHandler<unknown, unknown, unknown>[] | 
					
						
							|  |  |  |     }) { | 
					
						
							|  |  |  |       const reflectionHost = new Esm2015ReflectionHost(new MockLogger(), false, entryPoint.src); | 
					
						
							|  |  |  |       return new NgccTraitCompiler(handlers, reflectionHost); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     describe('injectSyntheticDecorator()', () => { | 
					
						
							|  |  |  |       it('should call `detect()` on each of the provided handlers', () => { | 
					
						
							|  |  |  |         const log: string[] = []; | 
					
						
							|  |  |  |         const handler1 = new TestHandler('handler1', log); | 
					
						
							|  |  |  |         const handler2 = new TestHandler('handler2', log); | 
					
						
							|  |  |  |         loadTestFiles([{name: _('/node_modules/test/index.js'), contents: ``}]); | 
					
						
							|  |  |  |         const entryPoint = | 
					
						
							|  |  |  |             makeTestEntryPointBundle('test', 'esm2015', false, [_('/node_modules/test/index.js')]); | 
					
						
							|  |  |  |         const compiler = createCompiler({entryPoint, handlers: [handler1, handler2]}); | 
					
						
							|  |  |  |         compiler.injectSyntheticDecorator(mockClazz, injectedDecorator); | 
					
						
							|  |  |  |         expect(log).toEqual([ | 
					
						
							|  |  |  |           `handler1:detect:MockClazz:InjectedDecorator`, | 
					
						
							|  |  |  |           `handler2:detect:MockClazz:InjectedDecorator`, | 
					
						
							|  |  |  |         ]); | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       it('should call `analyze()` on each of the provided handlers whose `detect()` call returns a result', | 
					
						
							|  |  |  |          () => { | 
					
						
							|  |  |  |            const log: string[] = []; | 
					
						
							|  |  |  |            const handler1 = new TestHandler('handler1', log); | 
					
						
							|  |  |  |            const handler2 = new AlwaysDetectHandler('handler2', log); | 
					
						
							|  |  |  |            const handler3 = new TestHandler('handler3', log); | 
					
						
							|  |  |  |            loadTestFiles([{name: _('/node_modules/test/index.js'), contents: ``}]); | 
					
						
							|  |  |  |            const entryPoint = makeTestEntryPointBundle( | 
					
						
							|  |  |  |                'test', 'esm2015', false, [_('/node_modules/test/index.js')]); | 
					
						
							|  |  |  |            const compiler = createCompiler({entryPoint, handlers: [handler1, handler2, handler3]}); | 
					
						
							|  |  |  |            compiler.injectSyntheticDecorator(mockClazz, injectedDecorator); | 
					
						
							|  |  |  |            expect(log).toEqual([ | 
					
						
							|  |  |  |              `handler1:detect:MockClazz:InjectedDecorator`, | 
					
						
							|  |  |  |              `handler2:detect:MockClazz:InjectedDecorator`, | 
					
						
							|  |  |  |              `handler3:detect:MockClazz:InjectedDecorator`, | 
					
						
							|  |  |  |              'handler2:analyze:MockClazz', | 
					
						
							|  |  |  |            ]); | 
					
						
							|  |  |  |          }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       it('should inject a new class record into the compilation', () => { | 
					
						
							|  |  |  |         const injectedHandler = | 
					
						
							|  |  |  |             new DetectDecoratorHandler('InjectedDecorator', HandlerPrecedence.WEAK); | 
					
						
							|  |  |  |         loadTestFiles([{name: _('/node_modules/test/index.js'), contents: ``}]); | 
					
						
							|  |  |  |         const entryPoint = | 
					
						
							|  |  |  |             makeTestEntryPointBundle('test', 'esm2015', false, [_('/node_modules/test/index.js')]); | 
					
						
							|  |  |  |         const compiler = createCompiler({entryPoint, handlers: [injectedHandler]}); | 
					
						
							|  |  |  |         compiler.injectSyntheticDecorator(mockClazz, injectedDecorator); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         const record = compiler.recordFor(mockClazz); | 
					
						
							|  |  |  |         expect(record).toBeDefined(); | 
					
						
							| 
									
										
										
										
											2020-04-06 08:30:08 +01:00
										 |  |  |         expect(record!.traits.length).toBe(1); | 
					
						
							| 
									
										
										
										
											2020-01-06 23:12:19 +01:00
										 |  |  |       }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       it('should add a new trait to an existing class record', () => { | 
					
						
							|  |  |  |         const directiveHandler = new DetectDecoratorHandler('Directive', HandlerPrecedence.WEAK); | 
					
						
							|  |  |  |         const injectedHandler = | 
					
						
							|  |  |  |             new DetectDecoratorHandler('InjectedDecorator', HandlerPrecedence.WEAK); | 
					
						
							|  |  |  |         loadTestFiles([{ | 
					
						
							|  |  |  |           name: _('/node_modules/test/index.js'), | 
					
						
							|  |  |  |           contents: `
 | 
					
						
							|  |  |  |               import {Directive} from '@angular/core'; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |               export class MyClass {}; | 
					
						
							|  |  |  |               MyClass.decorators = [{ type: Directive }]; | 
					
						
							|  |  |  |             `
 | 
					
						
							|  |  |  |         }]); | 
					
						
							|  |  |  |         const entryPoint = | 
					
						
							|  |  |  |             makeTestEntryPointBundle('test', 'esm2015', false, [_('/node_modules/test/index.js')]); | 
					
						
							|  |  |  |         const compiler = | 
					
						
							|  |  |  |             createCompiler({entryPoint, handlers: [directiveHandler, injectedHandler]}); | 
					
						
							|  |  |  |         const myClass = getDeclaration( | 
					
						
							|  |  |  |             entryPoint.src.program, _('/node_modules/test/index.js'), 'MyClass', | 
					
						
							|  |  |  |             isNamedClassDeclaration); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         compiler.analyzeFile(entryPoint.src.file); | 
					
						
							|  |  |  |         compiler.injectSyntheticDecorator(myClass, injectedDecorator); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-06 08:30:08 +01:00
										 |  |  |         const record = compiler.recordFor(myClass)!; | 
					
						
							| 
									
										
										
										
											2020-01-06 23:12:19 +01:00
										 |  |  |         expect(record).toBeDefined(); | 
					
						
							|  |  |  |         expect(record.traits.length).toBe(2); | 
					
						
							| 
									
										
										
										
											2020-04-06 08:30:08 +01:00
										 |  |  |         expect(record.traits[0].detected.decorator!.name).toBe('Directive'); | 
					
						
							|  |  |  |         expect(record.traits[1].detected.decorator!.name).toBe('InjectedDecorator'); | 
					
						
							| 
									
										
										
										
											2020-01-06 23:12:19 +01:00
										 |  |  |       }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       it('should not add a weak handler when a primary handler already exists', () => { | 
					
						
							|  |  |  |         const directiveHandler = new DetectDecoratorHandler('Directive', HandlerPrecedence.PRIMARY); | 
					
						
							|  |  |  |         const injectedHandler = | 
					
						
							|  |  |  |             new DetectDecoratorHandler('InjectedDecorator', HandlerPrecedence.WEAK); | 
					
						
							|  |  |  |         loadTestFiles([{ | 
					
						
							|  |  |  |           name: _('/node_modules/test/index.js'), | 
					
						
							|  |  |  |           contents: `
 | 
					
						
							|  |  |  |               import {Directive} from '@angular/core'; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |               export class MyClass {}; | 
					
						
							|  |  |  |               MyClass.decorators = [{ type: Directive }]; | 
					
						
							|  |  |  |             `
 | 
					
						
							|  |  |  |         }]); | 
					
						
							|  |  |  |         const entryPoint = | 
					
						
							|  |  |  |             makeTestEntryPointBundle('test', 'esm2015', false, [_('/node_modules/test/index.js')]); | 
					
						
							|  |  |  |         const compiler = | 
					
						
							|  |  |  |             createCompiler({entryPoint, handlers: [directiveHandler, injectedHandler]}); | 
					
						
							|  |  |  |         const myClass = getDeclaration( | 
					
						
							|  |  |  |             entryPoint.src.program, _('/node_modules/test/index.js'), 'MyClass', | 
					
						
							|  |  |  |             isNamedClassDeclaration); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         compiler.analyzeFile(entryPoint.src.file); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         compiler.injectSyntheticDecorator(myClass, injectedDecorator); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-06 08:30:08 +01:00
										 |  |  |         const record = compiler.recordFor(myClass)!; | 
					
						
							| 
									
										
										
										
											2020-01-06 23:12:19 +01:00
										 |  |  |         expect(record).toBeDefined(); | 
					
						
							|  |  |  |         expect(record.traits.length).toBe(1); | 
					
						
							| 
									
										
										
										
											2020-04-06 08:30:08 +01:00
										 |  |  |         expect(record.traits[0].detected.decorator!.name).toBe('Directive'); | 
					
						
							| 
									
										
										
										
											2020-01-06 23:12:19 +01:00
										 |  |  |       }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       it('should replace an existing weak handler when injecting a primary handler', () => { | 
					
						
							|  |  |  |         const directiveHandler = new DetectDecoratorHandler('Directive', HandlerPrecedence.WEAK); | 
					
						
							|  |  |  |         const injectedHandler = | 
					
						
							|  |  |  |             new DetectDecoratorHandler('InjectedDecorator', HandlerPrecedence.PRIMARY); | 
					
						
							|  |  |  |         loadTestFiles([{ | 
					
						
							|  |  |  |           name: _('/node_modules/test/index.js'), | 
					
						
							|  |  |  |           contents: `
 | 
					
						
							|  |  |  |               import {Directive} from '@angular/core'; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |               export class MyClass {}; | 
					
						
							|  |  |  |               MyClass.decorators = [{ type: Directive }]; | 
					
						
							|  |  |  |             `
 | 
					
						
							|  |  |  |         }]); | 
					
						
							|  |  |  |         const entryPoint = | 
					
						
							|  |  |  |             makeTestEntryPointBundle('test', 'esm2015', false, [_('/node_modules/test/index.js')]); | 
					
						
							|  |  |  |         const compiler = | 
					
						
							|  |  |  |             createCompiler({entryPoint, handlers: [directiveHandler, injectedHandler]}); | 
					
						
							|  |  |  |         const myClass = getDeclaration( | 
					
						
							|  |  |  |             entryPoint.src.program, _('/node_modules/test/index.js'), 'MyClass', | 
					
						
							|  |  |  |             isNamedClassDeclaration); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         compiler.analyzeFile(entryPoint.src.file); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         compiler.injectSyntheticDecorator(myClass, injectedDecorator); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-06 08:30:08 +01:00
										 |  |  |         const record = compiler.recordFor(myClass)!; | 
					
						
							| 
									
										
										
										
											2020-01-06 23:12:19 +01:00
										 |  |  |         expect(record).toBeDefined(); | 
					
						
							|  |  |  |         expect(record.traits.length).toBe(1); | 
					
						
							| 
									
										
										
										
											2020-04-06 08:30:08 +01:00
										 |  |  |         expect(record.traits[0].detected.decorator!.name).toBe('InjectedDecorator'); | 
					
						
							| 
									
										
										
										
											2020-01-06 23:12:19 +01:00
										 |  |  |       }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       it('should produce an error when a primary handler is added when a primary handler is already present', | 
					
						
							|  |  |  |          () => { | 
					
						
							|  |  |  |            const directiveHandler = | 
					
						
							|  |  |  |                new DetectDecoratorHandler('Directive', HandlerPrecedence.PRIMARY); | 
					
						
							|  |  |  |            const injectedHandler = | 
					
						
							|  |  |  |                new DetectDecoratorHandler('InjectedDecorator', HandlerPrecedence.PRIMARY); | 
					
						
							|  |  |  |            loadTestFiles([{ | 
					
						
							|  |  |  |              name: _('/node_modules/test/index.js'), | 
					
						
							|  |  |  |              contents: `
 | 
					
						
							|  |  |  |               import {Directive} from '@angular/core'; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |               export class MyClass {}; | 
					
						
							|  |  |  |               MyClass.decorators = [{ type: Directive }]; | 
					
						
							|  |  |  |             `
 | 
					
						
							|  |  |  |            }]); | 
					
						
							|  |  |  |            const entryPoint = makeTestEntryPointBundle( | 
					
						
							|  |  |  |                'test', 'esm2015', false, [_('/node_modules/test/index.js')]); | 
					
						
							|  |  |  |            const compiler = | 
					
						
							|  |  |  |                createCompiler({entryPoint, handlers: [directiveHandler, injectedHandler]}); | 
					
						
							|  |  |  |            const myClass = getDeclaration( | 
					
						
							|  |  |  |                entryPoint.src.program, _('/node_modules/test/index.js'), 'MyClass', | 
					
						
							|  |  |  |                isNamedClassDeclaration); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            compiler.analyzeFile(entryPoint.src.file); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            compiler.injectSyntheticDecorator(myClass, injectedDecorator); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-06 08:30:08 +01:00
										 |  |  |            const record = compiler.recordFor(myClass)!; | 
					
						
							| 
									
										
										
										
											2020-01-06 23:12:19 +01:00
										 |  |  |            expect(record).toBeDefined(); | 
					
						
							|  |  |  |            expect(record.metaDiagnostics).toBeDefined(); | 
					
						
							| 
									
										
										
										
											2020-04-06 08:30:08 +01:00
										 |  |  |            expect(record.metaDiagnostics!.length).toBe(1); | 
					
						
							|  |  |  |            expect(record.metaDiagnostics![0].code).toBe(ngErrorCode(ErrorCode.DECORATOR_COLLISION)); | 
					
						
							| 
									
										
										
										
											2020-01-06 23:12:19 +01:00
										 |  |  |            expect(record.traits.length).toBe(0); | 
					
						
							|  |  |  |          }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       it('should report diagnostics from handlers', () => { | 
					
						
							|  |  |  |         const log: string[] = []; | 
					
						
							|  |  |  |         const handler = new DiagnosticProducingHandler('handler', log); | 
					
						
							|  |  |  |         loadTestFiles([{name: _('/node_modules/test/index.js'), contents: ``}]); | 
					
						
							|  |  |  |         const entryPoint = | 
					
						
							|  |  |  |             makeTestEntryPointBundle('test', 'esm2015', false, [_('/node_modules/test/index.js')]); | 
					
						
							|  |  |  |         const compiler = createCompiler({entryPoint, handlers: [handler]}); | 
					
						
							|  |  |  |         const decorator = createComponentDecorator(mockClazz, {selector: 'comp', exportAs: null}); | 
					
						
							|  |  |  |         compiler.injectSyntheticDecorator(mockClazz, decorator); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-06 08:30:08 +01:00
										 |  |  |         const record = compiler.recordFor(mockClazz)!; | 
					
						
							| 
									
										
										
										
											2020-01-06 23:12:19 +01:00
										 |  |  |         const migratedTrait = record.traits[0]; | 
					
						
							|  |  |  |         if (migratedTrait.state !== TraitState.ERRORED) { | 
					
						
							|  |  |  |           return fail('Expected migrated class trait to be in an error state'); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         expect(migratedTrait.diagnostics.length).toBe(1); | 
					
						
							|  |  |  |         expect(migratedTrait.diagnostics[0].messageText).toEqual(`test diagnostic`); | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     describe('getAllDecorators', () => { | 
					
						
							|  |  |  |       it('should be null for classes without decorators', () => { | 
					
						
							|  |  |  |         loadTestFiles( | 
					
						
							|  |  |  |             [{name: _('/node_modules/test/index.js'), contents: `export class MyClass {};`}]); | 
					
						
							|  |  |  |         const entryPoint = | 
					
						
							|  |  |  |             makeTestEntryPointBundle('test', 'esm2015', false, [_('/node_modules/test/index.js')]); | 
					
						
							|  |  |  |         const compiler = createCompiler({entryPoint, handlers: []}); | 
					
						
							|  |  |  |         const myClass = getDeclaration( | 
					
						
							|  |  |  |             entryPoint.src.program, _('/node_modules/test/index.js'), 'MyClass', | 
					
						
							|  |  |  |             isNamedClassDeclaration); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         const decorators = compiler.getAllDecorators(myClass); | 
					
						
							|  |  |  |         expect(decorators).toBeNull(); | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       it('should include injected decorators', () => { | 
					
						
							|  |  |  |         const directiveHandler = new DetectDecoratorHandler('Directive', HandlerPrecedence.WEAK); | 
					
						
							|  |  |  |         const injectedHandler = | 
					
						
							|  |  |  |             new DetectDecoratorHandler('InjectedDecorator', HandlerPrecedence.WEAK); | 
					
						
							|  |  |  |         loadTestFiles([{ | 
					
						
							|  |  |  |           name: _('/node_modules/test/index.js'), | 
					
						
							|  |  |  |           contents: `
 | 
					
						
							|  |  |  |             import {Directive} from '@angular/core'; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             export class MyClass {}; | 
					
						
							|  |  |  |             MyClass.decorators = [{ type: Directive }]; | 
					
						
							|  |  |  |           `
 | 
					
						
							|  |  |  |         }]); | 
					
						
							|  |  |  |         const entryPoint = | 
					
						
							|  |  |  |             makeTestEntryPointBundle('test', 'esm2015', false, [_('/node_modules/test/index.js')]); | 
					
						
							|  |  |  |         const compiler = | 
					
						
							|  |  |  |             createCompiler({entryPoint, handlers: [directiveHandler, injectedHandler]}); | 
					
						
							|  |  |  |         const myClass = getDeclaration( | 
					
						
							|  |  |  |             entryPoint.src.program, _('/node_modules/test/index.js'), 'MyClass', | 
					
						
							|  |  |  |             isNamedClassDeclaration); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         compiler.analyzeFile(entryPoint.src.file); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         compiler.injectSyntheticDecorator(myClass, injectedDecorator); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-06 08:30:08 +01:00
										 |  |  |         const decorators = compiler.getAllDecorators(myClass)!; | 
					
						
							| 
									
										
										
										
											2020-01-06 23:12:19 +01:00
										 |  |  |         expect(decorators.length).toBe(2); | 
					
						
							|  |  |  |         expect(decorators[0].name).toBe('Directive'); | 
					
						
							|  |  |  |         expect(decorators[1].name).toBe('InjectedDecorator'); | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class TestHandler implements DecoratorHandler<unknown, unknown, unknown> { | 
					
						
							|  |  |  |   constructor(readonly name: string, protected log: string[]) {} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   precedence = HandlerPrecedence.PRIMARY; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   detect(node: ClassDeclaration, decorators: Decorator[]|null): DetectResult<unknown>|undefined { | 
					
						
							| 
									
										
										
										
											2020-04-06 08:30:08 +01:00
										 |  |  |     this.log.push(`${this.name}:detect:${node.name.text}:${decorators!.map(d => d.name)}`); | 
					
						
							| 
									
										
										
										
											2020-01-06 23:12:19 +01:00
										 |  |  |     return undefined; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   analyze(node: ClassDeclaration): AnalysisOutput<unknown> { | 
					
						
							|  |  |  |     this.log.push(this.name + ':analyze:' + node.name.text); | 
					
						
							|  |  |  |     return {}; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-09 21:32:56 +02:00
										 |  |  |   compileFull(node: ClassDeclaration): CompileResult|CompileResult[] { | 
					
						
							| 
									
										
										
										
											2020-01-06 23:12:19 +01:00
										 |  |  |     this.log.push(this.name + ':compile:' + node.name.text); | 
					
						
							|  |  |  |     return []; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class AlwaysDetectHandler extends TestHandler { | 
					
						
							|  |  |  |   detect(node: ClassDeclaration, decorators: Decorator[]|null): DetectResult<unknown>|undefined { | 
					
						
							|  |  |  |     super.detect(node, decorators); | 
					
						
							|  |  |  |     const decorator = decorators !== null ? decorators[0] : null; | 
					
						
							|  |  |  |     return {trigger: node, decorator, metadata: {}}; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class DetectDecoratorHandler extends TestHandler { | 
					
						
							|  |  |  |   constructor(private decorator: string, readonly precedence: HandlerPrecedence) { | 
					
						
							|  |  |  |     super(decorator, []); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   detect(node: ClassDeclaration, decorators: Decorator[]|null): DetectResult<unknown>|undefined { | 
					
						
							|  |  |  |     super.detect(node, decorators); | 
					
						
							|  |  |  |     if (decorators === null) { | 
					
						
							|  |  |  |       return undefined; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     const decorator = decorators.find(decorator => decorator.name === this.decorator); | 
					
						
							|  |  |  |     if (decorator === undefined) { | 
					
						
							|  |  |  |       return undefined; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return {trigger: node, decorator, metadata: {}}; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class DiagnosticProducingHandler extends AlwaysDetectHandler { | 
					
						
							|  |  |  |   analyze(node: ClassDeclaration): AnalysisOutput<any> { | 
					
						
							|  |  |  |     super.analyze(node); | 
					
						
							|  |  |  |     return {diagnostics: [makeDiagnostic(9999, node, 'test diagnostic')]}; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | } |