| 
									
										
										
										
											2018-11-21 09:05:27 +00: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 ts from 'typescript'; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-06-06 20:22:32 +01:00
										 |  |  | import {AbsoluteFsPath, absoluteFrom} from '../../../src/ngtsc/file_system'; | 
					
						
							|  |  |  | import {TestFile, runInEachFileSystem} from '../../../src/ngtsc/file_system/testing'; | 
					
						
							| 
									
										
										
										
											2019-03-20 13:47:58 +00:00
										 |  |  | import {Reference} from '../../../src/ngtsc/imports'; | 
					
						
							| 
									
										
										
										
											2019-06-06 20:22:32 +01:00
										 |  |  | import {getDeclaration} from '../../../src/ngtsc/testing'; | 
					
						
							|  |  |  | import {loadTestFiles} from '../../../test/helpers/src/mock_file_loading'; | 
					
						
							| 
									
										
										
										
											2018-11-21 09:05:27 +00:00
										 |  |  | import {NgccReferencesRegistry} from '../../src/analysis/ngcc_references_registry'; | 
					
						
							|  |  |  | import {PrivateDeclarationsAnalyzer} from '../../src/analysis/private_declarations_analyzer'; | 
					
						
							|  |  |  | import {Esm2015ReflectionHost} from '../../src/host/esm2015_host'; | 
					
						
							| 
									
										
										
										
											2019-03-29 10:13:14 +00:00
										 |  |  | import {MockLogger} from '../helpers/mock_logger'; | 
					
						
							| 
									
										
										
										
											2019-06-06 20:22:32 +01:00
										 |  |  | import {getRootFiles, makeTestEntryPointBundle} from '../helpers/utils'; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | runInEachFileSystem(() => { | 
					
						
							|  |  |  |   describe('PrivateDeclarationsAnalyzer', () => { | 
					
						
							|  |  |  |     describe('analyzeProgram()', () => { | 
					
						
							|  |  |  |       it('should find all NgModule declarations that were not publicly exported from the entry-point', | 
					
						
							|  |  |  |          () => { | 
					
						
							|  |  |  |            const _ = absoluteFrom; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            const TEST_PROGRAM: TestFile[] = [ | 
					
						
							|  |  |  |              { | 
					
						
							| 
									
										
										
										
											2019-05-25 21:34:40 +01:00
										 |  |  |                name: _('/node_modules/test-package/src/entry_point.js'), | 
					
						
							| 
									
										
										
										
											2019-06-06 20:22:32 +01:00
										 |  |  |                isRoot: true, | 
					
						
							|  |  |  |                contents: `
 | 
					
						
							|  |  |  |         export {PublicComponent} from './a'; | 
					
						
							|  |  |  |         export {ModuleA} from './mod'; | 
					
						
							|  |  |  |         export {ModuleB} from './b'; | 
					
						
							| 
									
										
										
										
											2019-02-14 18:59:46 +01:00
										 |  |  |       `
 | 
					
						
							| 
									
										
										
										
											2019-06-06 20:22:32 +01:00
										 |  |  |              }, | 
					
						
							|  |  |  |              { | 
					
						
							| 
									
										
										
										
											2019-05-25 21:34:40 +01:00
										 |  |  |                name: _('/node_modules/test-package/src/a.js'), | 
					
						
							| 
									
										
										
										
											2019-06-06 20:22:32 +01:00
										 |  |  |                isRoot: false, | 
					
						
							|  |  |  |                contents: `
 | 
					
						
							|  |  |  |         import {Component} from '@angular/core'; | 
					
						
							|  |  |  |         export class PublicComponent {} | 
					
						
							|  |  |  |         PublicComponent.decorators = [ | 
					
						
							|  |  |  |           {type: Component, args: [{selectors: 'a', template: ''}]} | 
					
						
							|  |  |  |         ]; | 
					
						
							| 
									
										
										
										
											2019-02-14 18:59:46 +01:00
										 |  |  |       `
 | 
					
						
							| 
									
										
										
										
											2019-06-06 20:22:32 +01:00
										 |  |  |              }, | 
					
						
							|  |  |  |              { | 
					
						
							| 
									
										
										
										
											2019-05-25 21:34:40 +01:00
										 |  |  |                name: _('/node_modules/test-package/src/b.js'), | 
					
						
							| 
									
										
										
										
											2019-06-06 20:22:32 +01:00
										 |  |  |                isRoot: false, | 
					
						
							|  |  |  |                contents: `
 | 
					
						
							|  |  |  |         import {Component, NgModule} from '@angular/core'; | 
					
						
							|  |  |  |         class PrivateComponent1 {} | 
					
						
							|  |  |  |         PrivateComponent1.decorators = [ | 
					
						
							|  |  |  |           {type: Component, args: [{selectors: 'b', template: ''}]} | 
					
						
							|  |  |  |         ]; | 
					
						
							|  |  |  |         class PrivateComponent2 {} | 
					
						
							|  |  |  |         PrivateComponent2.decorators = [ | 
					
						
							|  |  |  |           {type: Component, args: [{selectors: 'c', template: ''}]} | 
					
						
							|  |  |  |         ]; | 
					
						
							|  |  |  |         export class ModuleB {} | 
					
						
							|  |  |  |         ModuleB.decorators = [ | 
					
						
							|  |  |  |           {type: NgModule, args: [{declarations: [PrivateComponent1]}]} | 
					
						
							|  |  |  |         ]; | 
					
						
							|  |  |  |       `
 | 
					
						
							|  |  |  |              }, | 
					
						
							|  |  |  |              { | 
					
						
							| 
									
										
										
										
											2019-05-25 21:34:40 +01:00
										 |  |  |                name: _('/node_modules/test-package/src/c.js'), | 
					
						
							| 
									
										
										
										
											2019-06-06 20:22:32 +01:00
										 |  |  |                isRoot: false, | 
					
						
							|  |  |  |                contents: `
 | 
					
						
							|  |  |  |         import {Component} from '@angular/core'; | 
					
						
							|  |  |  |         export class InternalComponent1 {} | 
					
						
							|  |  |  |         InternalComponent1.decorators = [ | 
					
						
							|  |  |  |           {type: Component, args: [{selectors: 'd', template: ''}]} | 
					
						
							|  |  |  |         ]; | 
					
						
							|  |  |  |         export class InternalComponent2 {} | 
					
						
							|  |  |  |         InternalComponent2.decorators = [ | 
					
						
							|  |  |  |           {type: Component, args: [{selectors: 'e', template: ''}]} | 
					
						
							|  |  |  |         ]; | 
					
						
							|  |  |  |       `
 | 
					
						
							|  |  |  |              }, | 
					
						
							|  |  |  |              { | 
					
						
							| 
									
										
										
										
											2019-05-25 21:34:40 +01:00
										 |  |  |                name: _('/node_modules/test-package/src/mod.js'), | 
					
						
							| 
									
										
										
										
											2019-06-06 20:22:32 +01:00
										 |  |  |                isRoot: false, | 
					
						
							|  |  |  |                contents: `
 | 
					
						
							|  |  |  |         import {Component, NgModule} from '@angular/core'; | 
					
						
							|  |  |  |         import {PublicComponent} from './a'; | 
					
						
							|  |  |  |         import {ModuleB} from './b'; | 
					
						
							|  |  |  |         import {InternalComponent1} from './c'; | 
					
						
							|  |  |  |         export class ModuleA {} | 
					
						
							|  |  |  |         ModuleA.decorators = [ | 
					
						
							|  |  |  |           {type: NgModule, args: [{ | 
					
						
							|  |  |  |             declarations: [PublicComponent, InternalComponent1], | 
					
						
							|  |  |  |             imports: [ModuleB] | 
					
						
							|  |  |  |           }]} | 
					
						
							|  |  |  |         ]; | 
					
						
							|  |  |  |       `
 | 
					
						
							|  |  |  |              } | 
					
						
							|  |  |  |            ]; | 
					
						
							|  |  |  |            const TEST_DTS_PROGRAM = [ | 
					
						
							|  |  |  |              { | 
					
						
							| 
									
										
										
										
											2019-05-25 21:34:40 +01:00
										 |  |  |                name: _('/node_modules/test-package/typings/entry_point.d.ts'), | 
					
						
							| 
									
										
										
										
											2019-06-06 20:22:32 +01:00
										 |  |  |                isRoot: true, | 
					
						
							|  |  |  |                contents: `
 | 
					
						
							|  |  |  |         export {PublicComponent} from './a'; | 
					
						
							|  |  |  |         export {ModuleA} from './mod'; | 
					
						
							|  |  |  |         export {ModuleB} from './b'; | 
					
						
							|  |  |  |       `
 | 
					
						
							|  |  |  |              }, | 
					
						
							|  |  |  |              { | 
					
						
							| 
									
										
										
										
											2019-05-25 21:34:40 +01:00
										 |  |  |                name: _('/node_modules/test-package/typings/a.d.ts'), | 
					
						
							| 
									
										
										
										
											2019-06-06 20:22:32 +01:00
										 |  |  |                isRoot: false, | 
					
						
							|  |  |  |                contents: `
 | 
					
						
							|  |  |  |         export declare class PublicComponent {} | 
					
						
							|  |  |  |       `
 | 
					
						
							|  |  |  |              }, | 
					
						
							|  |  |  |              { | 
					
						
							| 
									
										
										
										
											2019-05-25 21:34:40 +01:00
										 |  |  |                name: _('/node_modules/test-package/typings/b.d.ts'), | 
					
						
							| 
									
										
										
										
											2019-06-06 20:22:32 +01:00
										 |  |  |                isRoot: false, | 
					
						
							|  |  |  |                contents: `
 | 
					
						
							|  |  |  |         export declare class ModuleB {} | 
					
						
							|  |  |  |       `
 | 
					
						
							|  |  |  |              }, | 
					
						
							|  |  |  |              { | 
					
						
							| 
									
										
										
										
											2019-05-25 21:34:40 +01:00
										 |  |  |                name: _('/node_modules/test-package/typings/c.d.ts'), | 
					
						
							| 
									
										
										
										
											2019-06-06 20:22:32 +01:00
										 |  |  |                isRoot: false, | 
					
						
							|  |  |  |                contents: `
 | 
					
						
							|  |  |  |         export declare class InternalComponent1 {} | 
					
						
							|  |  |  |       `
 | 
					
						
							|  |  |  |              }, | 
					
						
							|  |  |  |              { | 
					
						
							| 
									
										
										
										
											2019-05-25 21:34:40 +01:00
										 |  |  |                name: _('/node_modules/test-package/typings/mod.d.ts'), | 
					
						
							| 
									
										
										
										
											2019-06-06 20:22:32 +01:00
										 |  |  |                isRoot: false, | 
					
						
							|  |  |  |                contents: `
 | 
					
						
							|  |  |  |         import {PublicComponent} from './a'; | 
					
						
							|  |  |  |         import {ModuleB} from './b'; | 
					
						
							|  |  |  |         import {InternalComponent1} from './c'; | 
					
						
							|  |  |  |         export declare class ModuleA {} | 
					
						
							|  |  |  |       `
 | 
					
						
							|  |  |  |              }, | 
					
						
							|  |  |  |            ]; | 
					
						
							|  |  |  |            const {program, referencesRegistry, analyzer} = setup(TEST_PROGRAM, TEST_DTS_PROGRAM); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            addToReferencesRegistry( | 
					
						
							| 
									
										
										
										
											2019-05-25 21:34:40 +01:00
										 |  |  |                program, referencesRegistry, _('/node_modules/test-package/src/a.js'), | 
					
						
							|  |  |  |                'PublicComponent'); | 
					
						
							| 
									
										
										
										
											2019-06-06 20:22:32 +01:00
										 |  |  |            addToReferencesRegistry( | 
					
						
							| 
									
										
										
										
											2019-05-25 21:34:40 +01:00
										 |  |  |                program, referencesRegistry, _('/node_modules/test-package/src/b.js'), | 
					
						
							|  |  |  |                'PrivateComponent1'); | 
					
						
							|  |  |  |            addToReferencesRegistry( | 
					
						
							|  |  |  |                program, referencesRegistry, _('/node_modules/test-package/src/c.js'), | 
					
						
							|  |  |  |                'InternalComponent1'); | 
					
						
							| 
									
										
										
										
											2019-06-06 20:22:32 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |            const analyses = analyzer.analyzeProgram(program); | 
					
						
							|  |  |  |            // Note that `PrivateComponent2` and `InternalComponent2` are not found because they are
 | 
					
						
							|  |  |  |            // not added to the ReferencesRegistry (i.e. they were not declared in an NgModule).
 | 
					
						
							|  |  |  |            expect(analyses.length).toEqual(2); | 
					
						
							|  |  |  |            expect(analyses).toEqual([ | 
					
						
							| 
									
										
										
										
											2019-05-25 21:34:40 +01:00
										 |  |  |              { | 
					
						
							|  |  |  |                identifier: 'PrivateComponent1', | 
					
						
							|  |  |  |                from: _('/node_modules/test-package/src/b.js'), | 
					
						
							|  |  |  |                dtsFrom: null, | 
					
						
							|  |  |  |              }, | 
					
						
							| 
									
										
										
										
											2019-06-06 20:22:32 +01:00
										 |  |  |              { | 
					
						
							|  |  |  |                identifier: 'InternalComponent1', | 
					
						
							| 
									
										
										
										
											2019-05-25 21:34:40 +01:00
										 |  |  |                from: _('/node_modules/test-package/src/c.js'), | 
					
						
							|  |  |  |                dtsFrom: _('/node_modules/test-package/typings/c.d.ts'), | 
					
						
							| 
									
										
										
										
											2019-06-06 20:22:32 +01:00
										 |  |  |              }, | 
					
						
							|  |  |  |            ]); | 
					
						
							|  |  |  |          }); | 
					
						
							| 
									
										
										
										
											2019-02-14 18:59:46 +01:00
										 |  |  |     }); | 
					
						
							| 
									
										
										
										
											2018-11-21 09:05:27 +00:00
										 |  |  |   }); | 
					
						
							| 
									
										
										
										
											2019-02-14 18:59:46 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-06-06 20:22:32 +01:00
										 |  |  |   function setup(jsProgram: TestFile[], dtsProgram: TestFile[]) { | 
					
						
							|  |  |  |     loadTestFiles(jsProgram); | 
					
						
							|  |  |  |     loadTestFiles(dtsProgram); | 
					
						
							| 
									
										
										
										
											2019-12-18 14:03:04 +00:00
										 |  |  |     const {src, dts} = makeTestEntryPointBundle( | 
					
						
							| 
									
										
										
										
											2019-08-08 02:19:52 +03:00
										 |  |  |         'test-package', 'esm2015', false, getRootFiles(jsProgram), getRootFiles(dtsProgram)); | 
					
						
							| 
									
										
										
										
											2019-12-18 14:03:04 +00:00
										 |  |  |     const host = new Esm2015ReflectionHost(new MockLogger(), false, src, dts); | 
					
						
							| 
									
										
										
										
											2019-06-06 20:22:32 +01:00
										 |  |  |     const referencesRegistry = new NgccReferencesRegistry(host); | 
					
						
							|  |  |  |     const analyzer = new PrivateDeclarationsAnalyzer(host, referencesRegistry); | 
					
						
							| 
									
										
										
										
											2019-12-18 14:03:04 +00:00
										 |  |  |     return {program: src.program, referencesRegistry, analyzer}; | 
					
						
							| 
									
										
										
										
											2019-06-06 20:22:32 +01:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   /** | 
					
						
							|  |  |  |    * Add up the named component to the references registry. | 
					
						
							|  |  |  |    * | 
					
						
							|  |  |  |    * This would normally be done by the decoration handlers in the `DecorationAnalyzer`. | 
					
						
							|  |  |  |    */ | 
					
						
							|  |  |  |   function addToReferencesRegistry( | 
					
						
							|  |  |  |       program: ts.Program, registry: NgccReferencesRegistry, fileName: AbsoluteFsPath, | 
					
						
							|  |  |  |       componentName: string) { | 
					
						
							|  |  |  |     const declaration = getDeclaration(program, fileName, componentName, ts.isClassDeclaration); | 
					
						
							|  |  |  |     registry.add(null !, new Reference(declaration)); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | }); |