diff --git a/packages/compiler-cli/ngcc/src/analysis/module_with_providers_analyzer.ts b/packages/compiler-cli/ngcc/src/analysis/module_with_providers_analyzer.ts index 8be4952c74..fc9f6a7cac 100644 --- a/packages/compiler-cli/ngcc/src/analysis/module_with_providers_analyzer.ts +++ b/packages/compiler-cli/ngcc/src/analysis/module_with_providers_analyzer.ts @@ -30,7 +30,9 @@ export type ModuleWithProvidersAnalyses = Map { new MockLogger(), false, program.getTypeChecker(), dtsProgram); referencesRegistry = new NgccReferencesRegistry(host); - const analyzer = new ModuleWithProvidersAnalyzer(host, referencesRegistry); + const processDts = true; + const analyzer = new ModuleWithProvidersAnalyzer(host, referencesRegistry, processDts); analyses = analyzer.analyzeProgram(program); }); @@ -427,21 +428,19 @@ runInEachFileSystem(() => { describe('tracking references when generic types already present', () => { let _: typeof absoluteFrom; - let analyses: ModuleWithProvidersAnalyses; - let program: ts.Program; - let dtsProgram: BundleProgram; - let referencesRegistry: NgccReferencesRegistry; + let TEST_DTS_PROGRAM: TestFile[]; + let TEST_PROGRAM: TestFile[]; beforeEach(() => { _ = absoluteFrom; - const TEST_PROGRAM: TestFile[] = [ + TEST_PROGRAM = [ { name: _('/node_modules/test-package/src/entry-point.js'), contents: ` export * from './explicit'; export * from './module'; - ` + `, }, { name: _('/node_modules/test-package/src/explicit.js'), @@ -469,26 +468,26 @@ runInEachFileSystem(() => { }; } } - ` + `, }, { name: _('/node_modules/test-package/src/module.js'), contents: ` export class ExternalModule {} - ` + `, }, { name: _('/node_modules/some-library/index.d.ts'), - contents: 'export declare class LibraryModule {}' + contents: 'export declare class LibraryModule {}', }, ]; - const TEST_DTS_PROGRAM: TestFile[] = [ + TEST_DTS_PROGRAM = [ { name: _('/node_modules/test-package/typings/entry-point.d.ts'), contents: ` export * from './explicit'; export * from './module'; - ` + `, }, { name: _('/node_modules/test-package/typings/explicit.d.ts'), @@ -502,13 +501,13 @@ runInEachFileSystem(() => { static explicitExternalMethod(): ModuleWithProviders; static explicitLibraryMethod(): ModuleWithProviders; } - ` + `, }, { name: _('/node_modules/test-package/typings/module.d.ts'), contents: ` export declare class ExternalModule {} - ` + `, }, { name: _('/node_modules/test-package/typings/core.d.ts'), @@ -522,29 +521,31 @@ runInEachFileSystem(() => { ngModule: Type providers?: Provider[] } - ` + `, }, { name: _('/node_modules/some-library/index.d.ts'), - contents: 'export declare class LibraryModule {}' + contents: 'export declare class LibraryModule {}', }, ]; loadTestFiles(TEST_PROGRAM); loadTestFiles(TEST_DTS_PROGRAM); - const bundle = makeTestEntryPointBundle( - 'test-package', 'esm2015', false, getRootFiles(TEST_PROGRAM), - getRootFiles(TEST_DTS_PROGRAM)); - program = bundle.src.program; - dtsProgram = bundle.dts !; - const host = - new Esm2015ReflectionHost(new MockLogger(), false, program.getTypeChecker(), dtsProgram); - referencesRegistry = new NgccReferencesRegistry(host); - - const analyzer = new ModuleWithProvidersAnalyzer(host, referencesRegistry); - analyses = analyzer.analyzeProgram(program); }); it('should track references even when nothing needs to be updated', () => { + const bundle = makeTestEntryPointBundle( + 'test-package', 'esm2015', false, getRootFiles(TEST_PROGRAM), + getRootFiles(TEST_DTS_PROGRAM)); + const program = bundle.src.program; + const dtsProgram = bundle.dts !; + const host = + new Esm2015ReflectionHost(new MockLogger(), false, program.getTypeChecker(), dtsProgram); + const referencesRegistry = new NgccReferencesRegistry(host); + + const processDts = true; + const analyzer = new ModuleWithProvidersAnalyzer(host, referencesRegistry, processDts); + const analyses = analyzer.analyzeProgram(program); + const file = getSourceFileOrError( dtsProgram.program, _('/node_modules/test-package/typings/explicit.d.ts')); expect(analyses.has(file)).toBe(false); @@ -563,5 +564,34 @@ runInEachFileSystem(() => { expect(declarations.has(externalModuleDeclaration.name !)).toBe(true); expect(declarations.has(libraryModuleDeclaration.name !)).toBe(false); }); + + it('should track references even when typings have already been processed', () => { + const bundle = + makeTestEntryPointBundle('test-package', 'esm2015', false, getRootFiles(TEST_PROGRAM)); + const program = bundle.src.program; + const host = + new Esm2015ReflectionHost(new MockLogger(), false, program.getTypeChecker(), null); + const referencesRegistry = new NgccReferencesRegistry(host); + + const processDts = false; // Emulate the scenario where typings have already been processed + const analyzer = new ModuleWithProvidersAnalyzer(host, referencesRegistry, processDts); + const analyses = analyzer.analyzeProgram(program); + + expect(analyses.size).toBe(0); + + const declarations = referencesRegistry.getDeclarationMap(); + const explicitInternalModuleDeclaration = getDeclaration( + program, absoluteFrom('/node_modules/test-package/src/explicit.js'), + 'ExplicitInternalModule', ts.isClassDeclaration); + const externalModuleDeclaration = getDeclaration( + program, absoluteFrom('/node_modules/test-package/src/module.js'), 'ExternalModule', + ts.isClassDeclaration); + const libraryModuleDeclaration = getDeclaration( + program, absoluteFrom('/node_modules/some-library/index.d.ts'), 'LibraryModule', + ts.isClassDeclaration); + expect(declarations.has(explicitInternalModuleDeclaration.name !)).toBe(true); + expect(declarations.has(externalModuleDeclaration.name !)).toBe(true); + expect(declarations.has(libraryModuleDeclaration.name !)).toBe(false); + }); }); }); diff --git a/packages/compiler-cli/ngcc/test/integration/ngcc_spec.ts b/packages/compiler-cli/ngcc/test/integration/ngcc_spec.ts index 959c0bbd97..a3fdc4de45 100644 --- a/packages/compiler-cli/ngcc/test/integration/ngcc_spec.ts +++ b/packages/compiler-cli/ngcc/test/integration/ngcc_spec.ts @@ -175,6 +175,54 @@ runInEachFileSystem(() => { expect(jsContents).toMatch(/\bvar _c0 =/); }); + it('should add generic type for ModuleWithProviders and generate exports for private modules', + () => { + compileIntoApf('test-package', { + '/index.ts': ` + import {ModuleWithProviders} from '@angular/core'; + import {InternalFooModule} from './internal'; + + export class FooModule { + static forRoot(): ModuleWithProviders { + return { + ngModule: InternalFooModule, + }; + } + } + `, + '/internal.ts': ` + import {NgModule} from '@angular/core'; + + @NgModule() + export class InternalFooModule {} + `, + }); + + mainNgcc({ + basePath: '/node_modules', + targetEntryPointPath: 'test-package', + propertiesToConsider: ['esm2015', 'esm5', 'module'], + }); + + // The .d.ts where FooModule is declared should have a generic type added + const dtsContents = fs.readFile(_(`/node_modules/test-package/src/index.d.ts`)); + expect(dtsContents).toContain(`import * as ɵngcc0 from './internal';`); + expect(dtsContents) + .toContain(`static forRoot(): ModuleWithProviders<ɵngcc0.InternalFooModule>`); + + // The public facing .d.ts should export the InternalFooModule + const entryDtsContents = fs.readFile(_(`/node_modules/test-package/index.d.ts`)); + expect(entryDtsContents).toContain(`export {InternalFooModule} from './src/internal';`); + + // The esm2015 index source should export the InternalFooModule + const esm2015Contents = fs.readFile(_(`/node_modules/test-package/esm2015/index.js`)); + expect(esm2015Contents).toContain(`export {InternalFooModule} from './src/internal';`); + + // The esm5 index source should also export the InternalFooModule + const esm5Contents = fs.readFile(_(`/node_modules/test-package/esm5/index.js`)); + expect(esm5Contents).toContain(`export {InternalFooModule} from './src/internal';`); + }); + describe('in async mode', () => { it('should run ngcc without errors for fesm2015', async() => { const promise = mainNgcc({ diff --git a/packages/compiler-cli/ngcc/test/rendering/dts_renderer_spec.ts b/packages/compiler-cli/ngcc/test/rendering/dts_renderer_spec.ts index 626e8f9264..ab1f198611 100644 --- a/packages/compiler-cli/ngcc/test/rendering/dts_renderer_spec.ts +++ b/packages/compiler-cli/ngcc/test/rendering/dts_renderer_spec.ts @@ -76,7 +76,8 @@ function createTestRenderer( const decorationAnalyses = new DecorationAnalyzer(fs, bundle, host, referencesRegistry).analyzeProgram(); const moduleWithProvidersAnalyses = - new ModuleWithProvidersAnalyzer(host, referencesRegistry).analyzeProgram(bundle.src.program); + new ModuleWithProvidersAnalyzer(host, referencesRegistry, true) + .analyzeProgram(bundle.src.program); const privateDeclarationsAnalyses = new PrivateDeclarationsAnalyzer(host, referencesRegistry).analyzeProgram(bundle.src.program); const testFormatter = new TestRenderingFormatter(); diff --git a/packages/compiler-cli/ngcc/test/rendering/esm_rendering_formatter_spec.ts b/packages/compiler-cli/ngcc/test/rendering/esm_rendering_formatter_spec.ts index e1e200e8e1..640dd3fa58 100644 --- a/packages/compiler-cli/ngcc/test/rendering/esm_rendering_formatter_spec.ts +++ b/packages/compiler-cli/ngcc/test/rendering/esm_rendering_formatter_spec.ts @@ -574,7 +574,7 @@ export { D }; const referencesRegistry = new NgccReferencesRegistry(host); const moduleWithProvidersAnalyses = - new ModuleWithProvidersAnalyzer(host, referencesRegistry) + new ModuleWithProvidersAnalyzer(host, referencesRegistry, true) .analyzeProgram(bundle.src.program); const typingsFile = getSourceFileOrError(bundle.dts !.program, _('/typings/index.d.ts')); const moduleWithProvidersInfo = moduleWithProvidersAnalyses.get(typingsFile) !; @@ -610,7 +610,7 @@ export { D }; const referencesRegistry = new NgccReferencesRegistry(host); const moduleWithProvidersAnalyses = - new ModuleWithProvidersAnalyzer(host, referencesRegistry) + new ModuleWithProvidersAnalyzer(host, referencesRegistry, true) .analyzeProgram(bundle.src.program); const typingsFile = getSourceFileOrError(bundle.dts !.program, _('/typings/module.d.ts'));