diff --git a/packages/compiler-cli/ngcc/src/analysis/decoration_analyzer.ts b/packages/compiler-cli/ngcc/src/analysis/decoration_analyzer.ts index 232506d3a7..f87c448561 100644 --- a/packages/compiler-cli/ngcc/src/analysis/decoration_analyzer.ts +++ b/packages/compiler-cli/ngcc/src/analysis/decoration_analyzer.ts @@ -10,7 +10,7 @@ import * as ts from 'typescript'; import {BaseDefDecoratorHandler, ComponentDecoratorHandler, DirectiveDecoratorHandler, InjectableDecoratorHandler, NgModuleDecoratorHandler, PipeDecoratorHandler, ReferencesRegistry, ResourceLoader} from '../../../src/ngtsc/annotations'; import {CycleAnalyzer, ImportGraph} from '../../../src/ngtsc/cycles'; -import {AbsoluteFsPath, FileSystem, LogicalFileSystem, absoluteFrom, dirname, resolve} from '../../../src/ngtsc/file_system'; +import {FileSystem, LogicalFileSystem, absoluteFrom, dirname, resolve} from '../../../src/ngtsc/file_system'; import {AbsoluteModuleStrategy, LocalIdentifierStrategy, LogicalProjectStrategy, ModuleResolver, NOOP_DEFAULT_IMPORT_RECORDER, ReferenceEmitter} from '../../../src/ngtsc/imports'; import {CompoundMetadataReader, CompoundMetadataRegistry, DtsMetadataReader, LocalMetadataRegistry} from '../../../src/ngtsc/metadata'; import {PartialEvaluator} from '../../../src/ngtsc/partial_evaluator'; @@ -20,6 +20,7 @@ import {CompileResult, DecoratorHandler, DetectResult, HandlerPrecedence} from ' import {NgccReflectionHost} from '../host/ngcc_host'; import {EntryPointBundle} from '../packages/entry_point_bundle'; import {isDefined} from '../utils'; +import {isWithinPackage} from './util'; export interface AnalyzedFile { sourceFile: ts.SourceFile; @@ -72,6 +73,7 @@ export class DecorationAnalyzer { private host = this.bundle.src.host; private typeChecker = this.bundle.src.program.getTypeChecker(); private rootDirs = this.bundle.rootDirs; + private packagePath = this.bundle.entryPoint.package; private isCore = this.bundle.isCore; resourceManager = new NgccResourceLoader(this.fs); metaRegistry = new LocalMetadataRegistry(); @@ -130,6 +132,7 @@ export class DecorationAnalyzer { analyzeProgram(): DecorationAnalyses { const decorationAnalyses = new DecorationAnalyses(); const analysedFiles = this.program.getSourceFiles() + .filter(sourceFile => isWithinPackage(this.packagePath, sourceFile)) .map(sourceFile => this.analyzeFile(sourceFile)) .filter(isDefined); analysedFiles.forEach(analysedFile => this.resolveFile(analysedFile)); diff --git a/packages/compiler-cli/ngcc/src/analysis/switch_marker_analyzer.ts b/packages/compiler-cli/ngcc/src/analysis/switch_marker_analyzer.ts index 394cab1797..fc8b3a0fa6 100644 --- a/packages/compiler-cli/ngcc/src/analysis/switch_marker_analyzer.ts +++ b/packages/compiler-cli/ngcc/src/analysis/switch_marker_analyzer.ts @@ -6,7 +6,9 @@ * found in the LICENSE file at https://angular.io/license */ import * as ts from 'typescript'; +import {AbsoluteFsPath} from '../../../src/ngtsc/file_system'; import {NgccReflectionHost, SwitchableVariableDeclaration} from '../host/ngcc_host'; +import {isWithinPackage} from './util'; export interface SwitchMarkerAnalysis { sourceFile: ts.SourceFile; @@ -21,7 +23,7 @@ export const SwitchMarkerAnalyses = Map; * that will be replaced. */ export class SwitchMarkerAnalyzer { - constructor(private host: NgccReflectionHost) {} + constructor(private host: NgccReflectionHost, private packagePath: AbsoluteFsPath) {} /** * Analyze the files in the program to identify declarations that contain R3 * switch markers. @@ -32,12 +34,14 @@ export class SwitchMarkerAnalyzer { */ analyzeProgram(program: ts.Program): SwitchMarkerAnalyses { const analyzedFiles = new SwitchMarkerAnalyses(); - program.getSourceFiles().forEach(sourceFile => { - const declarations = this.host.getSwitchableDeclarations(sourceFile); - if (declarations.length) { - analyzedFiles.set(sourceFile, {sourceFile, declarations}); - } - }); + program.getSourceFiles() + .filter(sourceFile => isWithinPackage(this.packagePath, sourceFile)) + .forEach(sourceFile => { + const declarations = this.host.getSwitchableDeclarations(sourceFile); + if (declarations.length) { + analyzedFiles.set(sourceFile, {sourceFile, declarations}); + } + }); return analyzedFiles; } } diff --git a/packages/compiler-cli/ngcc/src/analysis/util.ts b/packages/compiler-cli/ngcc/src/analysis/util.ts new file mode 100644 index 0000000000..b4117ad913 --- /dev/null +++ b/packages/compiler-cli/ngcc/src/analysis/util.ts @@ -0,0 +1,13 @@ +/** + * @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'; +import {AbsoluteFsPath, absoluteFromSourceFile, relative} from '../../../src/ngtsc/file_system'; + +export function isWithinPackage(packagePath: AbsoluteFsPath, sourceFile: ts.SourceFile): boolean { + return !relative(packagePath, absoluteFromSourceFile(sourceFile)).startsWith('..'); +} diff --git a/packages/compiler-cli/ngcc/src/packages/transformer.ts b/packages/compiler-cli/ngcc/src/packages/transformer.ts index 23b6d76bba..99549ce9aa 100644 --- a/packages/compiler-cli/ngcc/src/packages/transformer.ts +++ b/packages/compiler-cli/ngcc/src/packages/transformer.ts @@ -122,7 +122,8 @@ export class Transformer { analyzeProgram(reflectionHost: NgccReflectionHost, bundle: EntryPointBundle): ProgramAnalyses { const referencesRegistry = new NgccReferencesRegistry(reflectionHost); - const switchMarkerAnalyzer = new SwitchMarkerAnalyzer(reflectionHost); + const switchMarkerAnalyzer = + new SwitchMarkerAnalyzer(reflectionHost, bundle.entryPoint.package); const switchMarkerAnalyses = switchMarkerAnalyzer.analyzeProgram(bundle.src.program); const decorationAnalyzer = diff --git a/packages/compiler-cli/ngcc/test/analysis/decoration_analyzer_spec.ts b/packages/compiler-cli/ngcc/test/analysis/decoration_analyzer_spec.ts index bcd31c248f..f5e462864e 100644 --- a/packages/compiler-cli/ngcc/test/analysis/decoration_analyzer_spec.ts +++ b/packages/compiler-cli/ngcc/test/analysis/decoration_analyzer_spec.ts @@ -109,17 +109,19 @@ runInEachFileSystem(() => { beforeEach(() => { const TEST_PROGRAM = [ { - name: _('/index.js'), + name: _('/node_modules/test-package/index.js'), contents: ` import * as test from './test'; import * as other from './other'; `, }, { - name: _('/test.js'), + name: _('/node_modules/test-package/test.js'), contents: ` import {Component, Directive, Injectable} from '@angular/core'; + export class NoDecorators {} + export class MyComponent {} MyComponent.decorators = [{type: Component}]; @@ -128,10 +130,11 @@ runInEachFileSystem(() => { export class MyService {} MyService.decorators = [{type: Injectable}]; + `, }, { - name: _('/other.js'), + name: _('/node_modules/test-package/other.js'), contents: ` import {Component} from '@angular/core'; @@ -144,22 +147,16 @@ runInEachFileSystem(() => { }); it('should return an object containing a reference to the original source file', () => { - const testFile = getSourceFileOrError(program, _('/test.js')); + const testFile = getSourceFileOrError(program, _('/node_modules/test-package/test.js')); expect(result.get(testFile) !.sourceFile).toBe(testFile); - const otherFile = getSourceFileOrError(program, _('/other.js')); + const otherFile = getSourceFileOrError(program, _('/node_modules/test-package/other.js')); expect(result.get(otherFile) !.sourceFile).toBe(otherFile); }); it('should call detect on the decorator handlers with each class from the parsed file', () => { - expect(testHandler.detect).toHaveBeenCalledTimes(11); + expect(testHandler.detect).toHaveBeenCalledTimes(5); expect(testHandler.detect.calls.allArgs().map(args => args[1])).toEqual([ - null, - null, - null, - null, - null, - null, null, jasmine.arrayContaining([jasmine.objectContaining({name: 'Component'})]), jasmine.arrayContaining([jasmine.objectContaining({name: 'Directive'})]), @@ -169,7 +166,7 @@ runInEachFileSystem(() => { }); it('should return an object containing the classes that were analyzed', () => { - const file1 = getSourceFileOrError(program, _('/test.js')); + const file1 = getSourceFileOrError(program, _('/node_modules/test-package/test.js')); const compiledFile1 = result.get(file1) !; expect(compiledFile1.compiledClasses.length).toEqual(2); expect(compiledFile1.compiledClasses[0]).toEqual(jasmine.objectContaining({ @@ -179,7 +176,7 @@ runInEachFileSystem(() => { name: 'MyDirective', compilation: ['@Directive (compiled)'], } as unknown as CompiledClass)); - const file2 = getSourceFileOrError(program, _('/other.js')); + const file2 = getSourceFileOrError(program, _('/node_modules/test-package/other.js')); const compiledFile2 = result.get(file2) !; expect(compiledFile2.compiledClasses.length).toEqual(1); expect(compiledFile2.compiledClasses[0]).toEqual(jasmine.objectContaining({ @@ -190,13 +187,7 @@ runInEachFileSystem(() => { it('should analyze, resolve and compile the classes that are detected', () => { expect(logs).toEqual([ // Classes without decorators should also be detected. - 'detect: ChangeDetectorRef (no decorators)', - 'detect: ElementRef (no decorators)', - 'detect: Injector (no decorators)', - 'detect: TemplateRef (no decorators)', - 'detect: ViewContainerRef (no decorators)', - 'detect: Renderer2 (no decorators)', - 'detect: ɵNgModuleFactory (no decorators)', + 'detect: NoDecorators (no decorators)', // First detect and (potentially) analyze. 'detect: MyComponent@Component', 'analyze: MyComponent@Component', @@ -221,7 +212,7 @@ runInEachFileSystem(() => { beforeEach(() => { const INTERNAL_COMPONENT_PROGRAM = [ { - name: _('/entrypoint.js'), + name: _('/node_modules/test-package/entrypoint.js'), contents: ` import {Component, NgModule} from '@angular/core'; import {ImportedComponent} from './component'; @@ -237,7 +228,7 @@ runInEachFileSystem(() => { ` }, { - name: _('/component.js'), + name: _('/node_modules/test-package/component.js'), contents: ` import {Component} from '@angular/core'; export class ImportedComponent {} @@ -253,7 +244,8 @@ runInEachFileSystem(() => { // files is not yet solved. it('should analyze an internally imported component, which is not publicly exported from the entry-point', () => { - const file = getSourceFileOrError(program, _('/component.js')); + const file = + getSourceFileOrError(program, _('/node_modules/test-package/component.js')); const analysis = result.get(file) !; expect(analysis).toBeDefined(); const ImportedComponent = @@ -262,13 +254,58 @@ runInEachFileSystem(() => { }); it('should analyze an internally defined component, which is not exported at all', () => { - const file = getSourceFileOrError(program, _('/entrypoint.js')); + const file = getSourceFileOrError(program, _('/node_modules/test-package/entrypoint.js')); const analysis = result.get(file) !; expect(analysis).toBeDefined(); const LocalComponent = analysis.compiledClasses.find(f => f.name === 'LocalComponent') !; expect(LocalComponent).toBeDefined(); }); }); + + describe('external components', () => { + beforeEach(() => { + const EXTERNAL_COMPONENT_PROGRAM: TestFile[] = [ + { + name: _('/node_modules/test-package/entrypoint.js'), + contents: ` + import {Component, NgModule} from '@angular/core'; + import {ImportedComponent} from 'other/component'; + + export class LocalComponent {} + LocalComponent.decorators = [{type: Component}]; + + export class MyModule {} + MyModule.decorators = [{type: NgModule, args: [{ + declarations: [ImportedComponent, LocalComponent], + exports: [ImportedComponent, LocalComponent], + },] }]; + ` + }, + { + name: _('/node_modules/other/component.js'), + contents: ` + import {Component} from '@angular/core'; + export class ImportedComponent {} + ImportedComponent.decorators = [{type: Component}]; + `, + isRoot: false, + }, + { + name: _('/node_modules/other/component.d.ts'), + contents: ` + import {Component} from '@angular/core'; + export class ImportedComponent {}` + }, + ]; + + setUpAndAnalyzeProgram(EXTERNAL_COMPONENT_PROGRAM); + }); + + it('should ignore classes from an externally imported file', () => { + const file = program.getSourceFile(_('/node_modules/other/component.js')) !; + expect(result.has(file)).toBe(false); + }); + }); }); }); -}); +}); \ No newline at end of file diff --git a/packages/compiler-cli/ngcc/test/analysis/module_with_providers_analyzer_spec.ts b/packages/compiler-cli/ngcc/test/analysis/module_with_providers_analyzer_spec.ts index e50396ae77..4b8b4a17d4 100644 --- a/packages/compiler-cli/ngcc/test/analysis/module_with_providers_analyzer_spec.ts +++ b/packages/compiler-cli/ngcc/test/analysis/module_with_providers_analyzer_spec.ts @@ -32,7 +32,7 @@ runInEachFileSystem(() => { const TEST_PROGRAM: TestFile[] = [ { - name: _('/src/entry-point.js'), + name: _('/node_modules/test-package/src/entry-point.js'), contents: ` export * from './explicit'; export * from './any'; @@ -42,7 +42,7 @@ runInEachFileSystem(() => { ` }, { - name: _('/src/explicit.js'), + name: _('/node_modules/test-package/src/explicit.js'), contents: ` import {ExternalModule} from './module'; import {LibraryModule} from 'some-library'; @@ -88,7 +88,7 @@ runInEachFileSystem(() => { ` }, { - name: _('/src/any.js'), + name: _('/node_modules/test-package/src/any.js'), contents: ` import {ExternalModule} from './module'; import {LibraryModule} from 'some-library'; @@ -134,7 +134,7 @@ runInEachFileSystem(() => { ` }, { - name: _('/src/implicit.js'), + name: _('/node_modules/test-package/src/implicit.js'), contents: ` import {ExternalModule} from './module'; import {LibraryModule} from 'some-library'; @@ -180,7 +180,7 @@ runInEachFileSystem(() => { ` }, { - name: _('/src/no-providers.js'), + name: _('/node_modules/test-package/src/no-providers.js'), contents: ` import {ExternalModule} from './module'; import {LibraryModule} from 'some-library'; @@ -215,7 +215,7 @@ runInEachFileSystem(() => { ` }, { - name: _('/src/module.js'), + name: _('/node_modules/test-package/src/module.js'), contents: ` export class ExternalModule {} ` @@ -227,7 +227,7 @@ runInEachFileSystem(() => { ]; const TEST_DTS_PROGRAM: TestFile[] = [ { - name: _('/typings/entry-point.d.ts'), + name: _('/node_modules/test-package/typings/entry-point.d.ts'), contents: ` export * from './explicit'; export * from './any'; @@ -237,7 +237,7 @@ runInEachFileSystem(() => { ` }, { - name: _('/typings/explicit.d.ts'), + name: _('/node_modules/test-package/typings/explicit.d.ts'), contents: ` import {ModuleWithProviders} from './core'; import {ExternalModule} from './module'; @@ -254,7 +254,7 @@ runInEachFileSystem(() => { ` }, { - name: _('/typings/any.d.ts'), + name: _('/node_modules/test-package/typings/any.d.ts'), contents: ` import {ModuleWithProviders} from './core'; export declare class AnyInternalModule {} @@ -269,7 +269,7 @@ runInEachFileSystem(() => { ` }, { - name: _('/typings/implicit.d.ts'), + name: _('/node_modules/test-package/typings/implicit.d.ts'), contents: ` import {ExternalModule} from './module'; import {LibraryModule} from 'some-library'; @@ -285,7 +285,7 @@ runInEachFileSystem(() => { ` }, { - name: _('/typings/no-providers.d.ts'), + name: _('/node_modules/test-package/typings/no-providers.d.ts'), contents: ` import {ModuleWithProviders} from './core'; import {ExternalModule} from './module'; @@ -303,13 +303,13 @@ runInEachFileSystem(() => { ` }, { - name: _('/typings/module.d.ts'), + name: _('/node_modules/test-package/typings/module.d.ts'), contents: ` export declare class ExternalModule {} ` }, { - name: _('/typings/core.d.ts'), + name: _('/node_modules/test-package/typings/core.d.ts'), contents: ` export declare interface Type { @@ -343,11 +343,14 @@ runInEachFileSystem(() => { }); it('should ignore declarations that already have explicit NgModule type params', () => { - expect(getAnalysisDescription(analyses, _('/typings/explicit.d.ts'))).toEqual([]); + expect( + getAnalysisDescription(analyses, _('/node_modules/test-package/typings/explicit.d.ts'))) + .toEqual([]); }); it('should find declarations that use `any` for the NgModule type param', () => { - const anyAnalysis = getAnalysisDescription(analyses, _('/typings/any.d.ts')); + const anyAnalysis = + getAnalysisDescription(analyses, _('/node_modules/test-package/typings/any.d.ts')); expect(anyAnalysis).toContain(['anyInternalFunction', 'AnyInternalModule', null]); expect(anyAnalysis).toContain(['anyExternalFunction', 'ExternalModule', null]); expect(anyAnalysis).toContain(['anyLibraryFunction', 'LibraryModule', 'some-library']); @@ -359,7 +362,8 @@ runInEachFileSystem(() => { it('should track internal module references in the references registry', () => { const declarations = referencesRegistry.getDeclarationMap(); const externalModuleDeclaration = getDeclaration( - program, absoluteFrom('/src/module.js'), 'ExternalModule', ts.isClassDeclaration); + 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); @@ -368,7 +372,8 @@ runInEachFileSystem(() => { }); it('should find declarations that have implicit return types', () => { - const anyAnalysis = getAnalysisDescription(analyses, _('/typings/implicit.d.ts')); + const anyAnalysis = + getAnalysisDescription(analyses, _('/node_modules/test-package/typings/implicit.d.ts')); expect(anyAnalysis).toContain(['implicitInternalFunction', 'ImplicitInternalModule', null]); expect(anyAnalysis).toContain(['implicitExternalFunction', 'ExternalModule', null]); expect(anyAnalysis).toContain(['implicitLibraryFunction', 'LibraryModule', 'some-library']); @@ -379,7 +384,8 @@ runInEachFileSystem(() => { it('should find declarations that do not specify a `providers` property in the return type', () => { - const anyAnalysis = getAnalysisDescription(analyses, _('/typings/no-providers.d.ts')); + const anyAnalysis = getAnalysisDescription( + analyses, _('/node_modules/test-package/typings/no-providers.d.ts')); expect(anyAnalysis).not.toContain([ 'noProvExplicitInternalFunction', 'NoProvidersInternalModule' ]); diff --git a/packages/compiler-cli/ngcc/test/analysis/private_declarations_analyzer_spec.ts b/packages/compiler-cli/ngcc/test/analysis/private_declarations_analyzer_spec.ts index 599110dca7..8a41159601 100644 --- a/packages/compiler-cli/ngcc/test/analysis/private_declarations_analyzer_spec.ts +++ b/packages/compiler-cli/ngcc/test/analysis/private_declarations_analyzer_spec.ts @@ -27,7 +27,7 @@ runInEachFileSystem(() => { const TEST_PROGRAM: TestFile[] = [ { - name: _('/src/entry_point.js'), + name: _('/node_modules/test-package/src/entry_point.js'), isRoot: true, contents: ` export {PublicComponent} from './a'; @@ -36,7 +36,7 @@ runInEachFileSystem(() => { ` }, { - name: _('/src/a.js'), + name: _('/node_modules/test-package/src/a.js'), isRoot: false, contents: ` import {Component} from '@angular/core'; @@ -47,7 +47,7 @@ runInEachFileSystem(() => { ` }, { - name: _('/src/b.js'), + name: _('/node_modules/test-package/src/b.js'), isRoot: false, contents: ` import {Component, NgModule} from '@angular/core'; @@ -66,7 +66,7 @@ runInEachFileSystem(() => { ` }, { - name: _('/src/c.js'), + name: _('/node_modules/test-package/src/c.js'), isRoot: false, contents: ` import {Component} from '@angular/core'; @@ -81,7 +81,7 @@ runInEachFileSystem(() => { ` }, { - name: _('/src/mod.js'), + name: _('/node_modules/test-package/src/mod.js'), isRoot: false, contents: ` import {Component, NgModule} from '@angular/core'; @@ -100,7 +100,7 @@ runInEachFileSystem(() => { ]; const TEST_DTS_PROGRAM = [ { - name: _('/typings/entry_point.d.ts'), + name: _('/node_modules/test-package/typings/entry_point.d.ts'), isRoot: true, contents: ` export {PublicComponent} from './a'; @@ -109,28 +109,28 @@ runInEachFileSystem(() => { ` }, { - name: _('/typings/a.d.ts'), + name: _('/node_modules/test-package/typings/a.d.ts'), isRoot: false, contents: ` export declare class PublicComponent {} ` }, { - name: _('/typings/b.d.ts'), + name: _('/node_modules/test-package/typings/b.d.ts'), isRoot: false, contents: ` export declare class ModuleB {} ` }, { - name: _('/typings/c.d.ts'), + name: _('/node_modules/test-package/typings/c.d.ts'), isRoot: false, contents: ` export declare class InternalComponent1 {} ` }, { - name: _('/typings/mod.d.ts'), + name: _('/node_modules/test-package/typings/mod.d.ts'), isRoot: false, contents: ` import {PublicComponent} from './a'; @@ -142,22 +142,31 @@ runInEachFileSystem(() => { ]; const {program, referencesRegistry, analyzer} = setup(TEST_PROGRAM, TEST_DTS_PROGRAM); - addToReferencesRegistry(program, referencesRegistry, _('/src/a.js'), 'PublicComponent'); addToReferencesRegistry( - program, referencesRegistry, _('/src/b.js'), 'PrivateComponent1'); + program, referencesRegistry, _('/node_modules/test-package/src/a.js'), + 'PublicComponent'); addToReferencesRegistry( - program, referencesRegistry, _('/src/c.js'), 'InternalComponent1'); + program, referencesRegistry, _('/node_modules/test-package/src/b.js'), + 'PrivateComponent1'); + addToReferencesRegistry( + program, referencesRegistry, _('/node_modules/test-package/src/c.js'), + 'InternalComponent1'); 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([ - {identifier: 'PrivateComponent1', from: _('/src/b.js'), dtsFrom: null, alias: null}, + { + identifier: 'PrivateComponent1', + from: _('/node_modules/test-package/src/b.js'), + dtsFrom: null, + alias: null + }, { identifier: 'InternalComponent1', - from: _('/src/c.js'), - dtsFrom: _('/typings/c.d.ts'), + from: _('/node_modules/test-package/src/c.js'), + dtsFrom: _('/node_modules/test-package/typings/c.d.ts'), alias: null }, ]); @@ -167,7 +176,7 @@ runInEachFileSystem(() => { const _ = absoluteFrom; const ALIASED_EXPORTS_PROGRAM = [ { - name: _('/src/entry_point.js'), + name: _('/node_modules/test-package/src/entry_point.js'), isRoot: true, contents: ` // This component is only exported as an alias. @@ -177,7 +186,7 @@ runInEachFileSystem(() => { ` }, { - name: _('/src/a.js'), + name: _('/node_modules/test-package/src/a.js'), isRoot: false, contents: ` import {Component} from '@angular/core'; @@ -195,7 +204,7 @@ runInEachFileSystem(() => { ]; const ALIASED_EXPORTS_DTS_PROGRAM = [ { - name: _('/typings/entry_point.d.ts'), + name: _('/node_modules/test-package/typings/entry_point.d.ts'), isRoot: true, contents: ` export declare class aliasedComponentOne {} @@ -207,13 +216,15 @@ runInEachFileSystem(() => { const {program, referencesRegistry, analyzer} = setup(ALIASED_EXPORTS_PROGRAM, ALIASED_EXPORTS_DTS_PROGRAM); - addToReferencesRegistry(program, referencesRegistry, _('/src/a.js'), 'ComponentOne'); - addToReferencesRegistry(program, referencesRegistry, _('/src/a.js'), 'ComponentTwo'); + addToReferencesRegistry( + program, referencesRegistry, _('/node_modules/test-package/src/a.js'), 'ComponentOne'); + addToReferencesRegistry( + program, referencesRegistry, _('/node_modules/test-package/src/a.js'), 'ComponentTwo'); const analyses = analyzer.analyzeProgram(program); expect(analyses).toEqual([{ identifier: 'ComponentOne', - from: _('/src/a.js'), + from: _('/node_modules/test-package/src/a.js'), dtsFrom: null, alias: 'aliasedComponentOne', }]); diff --git a/packages/compiler-cli/ngcc/test/analysis/switch_marker_analyzer_spec.ts b/packages/compiler-cli/ngcc/test/analysis/switch_marker_analyzer_spec.ts index dd60ee315f..3459406275 100644 --- a/packages/compiler-cli/ngcc/test/analysis/switch_marker_analyzer_spec.ts +++ b/packages/compiler-cli/ngcc/test/analysis/switch_marker_analyzer_spec.ts @@ -11,54 +11,77 @@ import {loadTestFiles} from '../../../test/helpers'; import {SwitchMarkerAnalyzer} from '../../src/analysis/switch_marker_analyzer'; import {Esm2015ReflectionHost} from '../../src/host/esm2015_host'; import {MockLogger} from '../helpers/mock_logger'; -import {getRootFiles, makeTestBundleProgram} from '../helpers/utils'; +import {makeTestEntryPointBundle} from '../helpers/utils'; runInEachFileSystem(() => { describe('SwitchMarkerAnalyzer', () => { + + let _: typeof absoluteFrom; + let TEST_PROGRAM: TestFile[]; + + beforeEach(() => { + _ = absoluteFrom; + TEST_PROGRAM = [ + { + name: _('/node_modules/test/entrypoint.js'), + contents: ` + import {a} from './a'; + import {b} from './b'; + import {x} from '../other/x'; + ` + }, + { + name: _('/node_modules/test/a.js'), + contents: ` + import {c} from './c'; + export const a = 1; + ` + }, + { + name: _('/node_modules/test/b.js'), + contents: ` + export const b = 42; + var factoryB = factory__PRE_R3__; + ` + }, + { + name: _('/node_modules/test/c.js'), + contents: ` + export const c = 'So long, and thanks for all the fish!'; + var factoryC = factory__PRE_R3__; + var factoryD = factory__PRE_R3__; + ` + }, + { + name: _('/node_modules/other/x.js'), + contents: ` + export const x = 3.142; + var factoryX = factory__PRE_R3__; + ` + }, + { + name: _('/node_modules/other/x.d.ts'), + contents: ` + export const x: number; + ` + }, + ]; + }); + describe('analyzeProgram()', () => { it('should check for switchable markers in all the files of the program', () => { - const _ = absoluteFrom; - const TEST_PROGRAM: TestFile[] = [ - { - name: _('/entrypoint.js'), - contents: ` - import {a} from './a'; - import {b} from './b'; - ` - }, - { - name: _('/a.js'), - contents: ` - import {c} from './c'; - export const a = 1; - ` - }, - { - name: _('/b.js'), - contents: ` - export const b = 42; - var factoryB = factory__PRE_R3__; - ` - }, - { - name: _('/c.js'), - contents: ` - export const c = 'So long, and thanks for all the fish!'; - var factoryC = factory__PRE_R3__; - var factoryD = factory__PRE_R3__; - ` - }, - ]; loadTestFiles(TEST_PROGRAM); - const {program} = makeTestBundleProgram(getRootFiles(TEST_PROGRAM)[0]); + const bundle = makeTestEntryPointBundle( + 'test', 'esm2015', 'esm2015', false, [_('/node_modules/test/entrypoint.js')]); + const program = bundle.src.program; const host = new Esm2015ReflectionHost(new MockLogger(), false, program.getTypeChecker()); - const analyzer = new SwitchMarkerAnalyzer(host); + const analyzer = new SwitchMarkerAnalyzer(host, bundle.entryPoint.package); const analysis = analyzer.analyzeProgram(program); - const entrypoint = getSourceFileOrError(program, _('/entrypoint.js')); - const a = getSourceFileOrError(program, _('/a.js')); - const b = getSourceFileOrError(program, _('/b.js')); - const c = getSourceFileOrError(program, _('/c.js')); + const entrypoint = getSourceFileOrError(program, _('/node_modules/test/entrypoint.js')); + const a = getSourceFileOrError(program, _('/node_modules/test/a.js')); + const b = getSourceFileOrError(program, _('/node_modules/test/b.js')); + const c = getSourceFileOrError(program, _('/node_modules/test/c.js')); expect(analysis.size).toEqual(2); expect(analysis.has(entrypoint)).toBe(false); @@ -76,6 +99,19 @@ runInEachFileSystem(() => { 'factoryD = factory__PRE_R3__', ]); }); + + it('should ignore files that are outside the package', () => { + loadTestFiles(TEST_PROGRAM); + const bundle = makeTestEntryPointBundle( + 'test', 'esm2015', 'esm2015', false, [_('/node_modules/test/entrypoint.js')]); + const program = bundle.src.program; + const host = new Esm2015ReflectionHost(new MockLogger(), false, program.getTypeChecker()); + const analyzer = new SwitchMarkerAnalyzer(host, bundle.entryPoint.package); + const analysis = analyzer.analyzeProgram(program); + + const x = getSourceFileOrError(program, _('/node_modules/other/x.js')); + expect(analysis.has(x)).toBe(false); + }); }); }); -}); +}); \ No newline at end of file diff --git a/packages/compiler-cli/ngcc/test/analysis/util_spec.ts b/packages/compiler-cli/ngcc/test/analysis/util_spec.ts new file mode 100644 index 0000000000..fd6ee82409 --- /dev/null +++ b/packages/compiler-cli/ngcc/test/analysis/util_spec.ts @@ -0,0 +1,31 @@ +/** + * @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'; +import {absoluteFrom} from '../../../src/ngtsc/file_system'; +import {runInEachFileSystem} from '../../../src/ngtsc/file_system/testing'; +import {isWithinPackage} from '../../src/analysis/util'; + +runInEachFileSystem(() => { + describe('isWithinPackage', () => { + it('should return true if the source-file is contained in the package', () => { + const _ = absoluteFrom; + const file = + ts.createSourceFile(_('/node_modules/test/src/index.js'), '', ts.ScriptTarget.ES2015); + const packagePath = _('/node_modules/test'); + expect(isWithinPackage(packagePath, file)).toBe(true); + }); + + it('should return false if the source-file is not contained in the package', () => { + const _ = absoluteFrom; + const file = + ts.createSourceFile(_('/node_modules/other/src/index.js'), '', ts.ScriptTarget.ES2015); + const packagePath = _('/node_modules/test'); + expect(isWithinPackage(packagePath, file)).toBe(false); + }); + }); +}); diff --git a/packages/compiler-cli/ngcc/test/helpers/utils.ts b/packages/compiler-cli/ngcc/test/helpers/utils.ts index 0c34fa6169..3b6bd99dd0 100644 --- a/packages/compiler-cli/ngcc/test/helpers/utils.ts +++ b/packages/compiler-cli/ngcc/test/helpers/utils.ts @@ -5,6 +5,7 @@ * 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'; import {AbsoluteFsPath, NgtscCompilerHost, absoluteFrom, getFileSystem} from '../../../src/ngtsc/file_system'; import {TestFile} from '../../../src/ngtsc/file_system/testing'; import {BundleProgram, makeBundleProgram} from '../../src/packages/bundle_program'; @@ -49,8 +50,10 @@ export function makeTestEntryPointBundle( export function makeTestBundleProgram( path: AbsoluteFsPath, isCore: boolean = false): BundleProgram { const fs = getFileSystem(); - const options = {allowJs: true, checkJs: false}; const entryPointPath = fs.dirname(path); + const rootDir = fs.dirname(entryPointPath); + const options: ts.CompilerOptions = + {allowJs: true, maxNodeModuleJsDepth: Infinity, checkJs: false, rootDir, rootDirs: [rootDir]}; const host = new NgccSourcesCompilerHost(fs, options, entryPointPath); return makeBundleProgram(fs, isCore, path, 'r3_symbols.js', options, host); } diff --git a/packages/compiler-cli/ngcc/test/rendering/commonjs_rendering_formatter_spec.ts b/packages/compiler-cli/ngcc/test/rendering/commonjs_rendering_formatter_spec.ts index 567a1e5ff9..8f8b4354ed 100644 --- a/packages/compiler-cli/ngcc/test/rendering/commonjs_rendering_formatter_spec.ts +++ b/packages/compiler-cli/ngcc/test/rendering/commonjs_rendering_formatter_spec.ts @@ -30,7 +30,7 @@ runInEachFileSystem(() => { beforeEach(() => { _ = absoluteFrom; PROGRAM = { - name: _('/some/file.js'), + name: _('/node_modules/test-package/some/file.js'), contents: ` /* A copyright notice */ require('some-side-effect'); @@ -94,7 +94,7 @@ exports.BadIife = BadIife;` }; PROGRAM_DECORATE_HELPER = { - name: _('/some/file.js'), + name: _('/node_modules/test-package/some/file.js'), contents: ` var tslib_1 = require("tslib"); /* A copyright notice */ @@ -156,8 +156,8 @@ exports.D = D; const referencesRegistry = new NgccReferencesRegistry(host); const decorationAnalyses = new DecorationAnalyzer(fs, bundle, host, referencesRegistry).analyzeProgram(); - const switchMarkerAnalyses = - new SwitchMarkerAnalyzer(host).analyzeProgram(bundle.src.program); + const switchMarkerAnalyses = new SwitchMarkerAnalyzer(host, bundle.entryPoint.package) + .analyzeProgram(bundle.src.program); const renderer = new CommonJsRenderingFormatter(host, false); const importManager = new ImportManager(new NoopImportRewriter(), 'i'); return { @@ -197,9 +197,21 @@ var i1 = require('@angular/common');`); renderer.addExports( output, _(PROGRAM.name.replace(/\.js$/, '')), [ - {from: _('/some/a.js'), dtsFrom: _('/some/a.d.ts'), identifier: 'ComponentA1'}, - {from: _('/some/a.js'), dtsFrom: _('/some/a.d.ts'), identifier: 'ComponentA2'}, - {from: _('/some/foo/b.js'), dtsFrom: _('/some/foo/b.d.ts'), identifier: 'ComponentB'}, + { + from: _('/node_modules/test-package/some/a.js'), + dtsFrom: _('/node_modules/test-package/some/a.d.ts'), + identifier: 'ComponentA1' + }, + { + from: _('/node_modules/test-package/some/a.js'), + dtsFrom: _('/node_modules/test-package/some/a.d.ts'), + identifier: 'ComponentA2' + }, + { + from: _('/node_modules/test-package/some/foo/b.js'), + dtsFrom: _('/node_modules/test-package/some/foo/b.d.ts'), + identifier: 'ComponentB' + }, {from: PROGRAM.name, dtsFrom: PROGRAM.name, identifier: 'TopLevelComponent'}, ], importManager, sourceFile); @@ -222,9 +234,21 @@ exports.TopLevelComponent = TopLevelComponent;`); renderer.addExports( output, _(PROGRAM.name.replace(/\.js$/, '')), [ - {from: _('/some/a.js'), alias: 'eComponentA1', identifier: 'ComponentA1'}, - {from: _('/some/a.js'), alias: 'eComponentA2', identifier: 'ComponentA2'}, - {from: _('/some/foo/b.js'), alias: 'eComponentB', identifier: 'ComponentB'}, + { + from: _('/node_modules/test-package/some/a.js'), + alias: 'eComponentA1', + identifier: 'ComponentA1' + }, + { + from: _('/node_modules/test-package/some/a.js'), + alias: 'eComponentA2', + identifier: 'ComponentA2' + }, + { + from: _('/node_modules/test-package/some/foo/b.js'), + alias: 'eComponentB', + identifier: 'ComponentB' + }, {from: PROGRAM.name, alias: 'eTopLevelComponent', identifier: 'TopLevelComponent'}, ], importManager, sourceFile); @@ -238,7 +262,7 @@ exports.TopLevelComponent = TopLevelComponent;`); describe('addConstants', () => { it('should insert the given constants after imports in the source file', () => { const {renderer, program} = setup(PROGRAM); - const file = getSourceFileOrError(program, _('/some/file.js')); + const file = getSourceFileOrError(program, _('/node_modules/test-package/some/file.js')); const output = new MagicString(PROGRAM.contents); renderer.addConstants(output, 'var x = 3;', file); expect(output.toString()).toContain(` @@ -250,7 +274,7 @@ var A = (function() {`); it('should insert constants after inserted imports', () => { const {renderer, program} = setup(PROGRAM); - const file = getSourceFileOrError(program, _('/some/file.js')); + const file = getSourceFileOrError(program, _('/node_modules/test-package/some/file.js')); const output = new MagicString(PROGRAM.contents); renderer.addConstants(output, 'var x = 3;', file); renderer.addImports(output, [{specifier: '@angular/core', qualifier: 'i0'}], file); @@ -266,7 +290,7 @@ var A = (function() {`); describe('rewriteSwitchableDeclarations', () => { it('should switch marked declaration initializers', () => { const {renderer, program, sourceFile, switchMarkerAnalyses} = setup(PROGRAM); - const file = getSourceFileOrError(program, _('/some/file.js')); + const file = getSourceFileOrError(program, _('/node_modules/test-package/some/file.js')); const output = new MagicString(PROGRAM.contents); renderer.rewriteSwitchableDeclarations( output, file, switchMarkerAnalyses.get(sourceFile) !.declarations); @@ -311,14 +335,14 @@ SOME DEFINITION TEXT const mockNoIifeClass: any = {declaration: noIifeDeclaration, name: 'NoIife'}; expect(() => renderer.addDefinitions(output, mockNoIifeClass, 'SOME DEFINITION TEXT')) .toThrowError( - `Compiled class declaration is not inside an IIFE: NoIife in ${_('/some/file.js')}`); + `Compiled class declaration is not inside an IIFE: NoIife in ${_('/node_modules/test-package/some/file.js')}`); const badIifeDeclaration = getDeclaration( program, absoluteFromSourceFile(sourceFile), 'BadIife', ts.isVariableDeclaration); const mockBadIifeClass: any = {declaration: badIifeDeclaration, name: 'BadIife'}; expect(() => renderer.addDefinitions(output, mockBadIifeClass, 'SOME DEFINITION TEXT')) .toThrowError( - `Compiled class wrapper IIFE does not have a return statement: BadIife in ${_('/some/file.js')}`); + `Compiled class wrapper IIFE does not have a return statement: BadIife in ${_('/node_modules/test-package/some/file.js')}`); }); }); 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 2caf9cf0be..e4651655c8 100644 --- a/packages/compiler-cli/ngcc/test/rendering/dts_renderer_spec.ts +++ b/packages/compiler-cli/ngcc/test/rendering/dts_renderer_spec.ts @@ -99,7 +99,7 @@ runInEachFileSystem(() => { beforeEach(() => { _ = absoluteFrom; INPUT_PROGRAM = { - name: _('/src/file.js'), + name: _('/node_modules/test-package/src/file.js'), contents: `import { Directive } from '@angular/core';\nexport class A {\n foo(x) {\n return x;\n }\n}\nA.decorators = [\n { type: Directive, args: [{ selector: '[a]' }] }\n];\n` }; @@ -139,8 +139,11 @@ runInEachFileSystem(() => { createTestRenderer('test-package', [INPUT_PROGRAM], [INPUT_DTS_PROGRAM]); // Add a mock export to trigger export rendering - privateDeclarationsAnalyses.push( - {identifier: 'ComponentB', from: _('/src/file.js'), dtsFrom: _('/typings/b.d.ts')}); + privateDeclarationsAnalyses.push({ + identifier: 'ComponentB', + from: _('/node_modules/test-package/src/file.js'), + dtsFrom: _('/typings/b.d.ts') + }); const result = renderer.renderProgram( decorationAnalyses, privateDeclarationsAnalyses, moduleWithProvidersAnalyses); diff --git a/packages/compiler-cli/ngcc/test/rendering/esm5_rendering_formatter_spec.ts b/packages/compiler-cli/ngcc/test/rendering/esm5_rendering_formatter_spec.ts index c92974ad69..4d3a24e5d5 100644 --- a/packages/compiler-cli/ngcc/test/rendering/esm5_rendering_formatter_spec.ts +++ b/packages/compiler-cli/ngcc/test/rendering/esm5_rendering_formatter_spec.ts @@ -32,7 +32,8 @@ function setup(file: {name: AbsoluteFsPath, contents: string}) { const referencesRegistry = new NgccReferencesRegistry(host); const decorationAnalyses = new DecorationAnalyzer(fs, bundle, host, referencesRegistry).analyzeProgram(); - const switchMarkerAnalyses = new SwitchMarkerAnalyzer(host).analyzeProgram(bundle.src.program); + const switchMarkerAnalyses = + new SwitchMarkerAnalyzer(host, bundle.entryPoint.package).analyzeProgram(bundle.src.program); const renderer = new Esm5RenderingFormatter(host, false); const importManager = new ImportManager(new NoopImportRewriter(), IMPORT_PREFIX); return { @@ -52,7 +53,7 @@ runInEachFileSystem(() => { beforeEach(() => { _ = absoluteFrom; PROGRAM = { - name: _('/some/file.js'), + name: _('/node_modules/test-package/some/file.js'), contents: ` /* A copyright notice */ import 'some-side-effect'; @@ -112,7 +113,7 @@ export {A, B, C, NoIife, BadIife};` }; PROGRAM_DECORATE_HELPER = { - name: _('/some/file.js'), + name: _('/node_modules/test-package/some/file.js'), contents: ` import * as tslib_1 from "tslib"; /* A copyright notice */ @@ -189,9 +190,21 @@ import * as i1 from '@angular/common';`); renderer.addExports( output, _(PROGRAM.name.replace(/\.js$/, '')), [ - {from: _('/some/a.js'), dtsFrom: _('/some/a.d.ts'), identifier: 'ComponentA1'}, - {from: _('/some/a.js'), dtsFrom: _('/some/a.d.ts'), identifier: 'ComponentA2'}, - {from: _('/some/foo/b.js'), dtsFrom: _('/some/foo/b.d.ts'), identifier: 'ComponentB'}, + { + from: _('/node_modules/test-package/some/a.js'), + dtsFrom: _('/node_modules/test-package/some/a.d.ts'), + identifier: 'ComponentA1' + }, + { + from: _('/node_modules/test-package/some/a.js'), + dtsFrom: _('/node_modules/test-package/some/a.d.ts'), + identifier: 'ComponentA2' + }, + { + from: _('/node_modules/test-package/some/foo/b.js'), + dtsFrom: _('/node_modules/test-package/some/foo/b.d.ts'), + identifier: 'ComponentB' + }, {from: PROGRAM.name, dtsFrom: PROGRAM.name, identifier: 'TopLevelComponent'}, ], importManager, sourceFile); @@ -209,9 +222,21 @@ export {TopLevelComponent};`); renderer.addExports( output, _(PROGRAM.name.replace(/\.js$/, '')), [ - {from: _('/some/a.js'), alias: 'eComponentA1', identifier: 'ComponentA1'}, - {from: _('/some/a.js'), alias: 'eComponentA2', identifier: 'ComponentA2'}, - {from: _('/some/foo/b.js'), alias: 'eComponentB', identifier: 'ComponentB'}, + { + from: _('/node_modules/test-package/some/a.js'), + alias: 'eComponentA1', + identifier: 'ComponentA1' + }, + { + from: _('/node_modules/test-package/some/a.js'), + alias: 'eComponentA2', + identifier: 'ComponentA2' + }, + { + from: _('/node_modules/test-package/some/foo/b.js'), + alias: 'eComponentB', + identifier: 'ComponentB' + }, {from: PROGRAM.name, alias: 'eTopLevelComponent', identifier: 'TopLevelComponent'}, ], importManager, sourceFile); @@ -225,7 +250,7 @@ export {TopLevelComponent};`); describe('addConstants', () => { it('should insert the given constants after imports in the source file', () => { const {renderer, program} = setup(PROGRAM); - const file = getSourceFileOrError(program, _('/some/file.js')); + const file = getSourceFileOrError(program, _('/node_modules/test-package/some/file.js')); const output = new MagicString(PROGRAM.contents); renderer.addConstants(output, 'var x = 3;', file); expect(output.toString()).toContain(` @@ -237,7 +262,7 @@ var A = (function() {`); it('should insert constants after inserted imports', () => { const {renderer, program} = setup(PROGRAM); - const file = getSourceFileOrError(program, _('/some/file.js')); + const file = getSourceFileOrError(program, _('/node_modules/test-package/some/file.js')); const output = new MagicString(PROGRAM.contents); renderer.addConstants(output, 'var x = 3;', file); renderer.addImports(output, [{specifier: '@angular/core', qualifier: 'i0'}], file); @@ -253,7 +278,7 @@ var A = (function() {`); describe('rewriteSwitchableDeclarations', () => { it('should switch marked declaration initializers', () => { const {renderer, program, sourceFile, switchMarkerAnalyses} = setup(PROGRAM); - const file = getSourceFileOrError(program, _('/some/file.js')); + const file = getSourceFileOrError(program, _('/node_modules/test-package/some/file.js')); const output = new MagicString(PROGRAM.contents); renderer.rewriteSwitchableDeclarations( output, file, switchMarkerAnalyses.get(sourceFile) !.declarations); @@ -298,14 +323,14 @@ SOME DEFINITION TEXT const mockNoIifeClass: any = {declaration: noIifeDeclaration, name: 'NoIife'}; expect(() => renderer.addDefinitions(output, mockNoIifeClass, 'SOME DEFINITION TEXT')) .toThrowError( - `Compiled class declaration is not inside an IIFE: NoIife in ${_('/some/file.js')}`); + `Compiled class declaration is not inside an IIFE: NoIife in ${_('/node_modules/test-package/some/file.js')}`); const badIifeDeclaration = getDeclaration( program, absoluteFromSourceFile(sourceFile), 'BadIife', ts.isVariableDeclaration); const mockBadIifeClass: any = {declaration: badIifeDeclaration, name: 'BadIife'}; expect(() => renderer.addDefinitions(output, mockBadIifeClass, 'SOME DEFINITION TEXT')) .toThrowError( - `Compiled class wrapper IIFE does not have a return statement: BadIife in ${_('/some/file.js')}`); + `Compiled class wrapper IIFE does not have a return statement: BadIife in ${_('/node_modules/test-package/some/file.js')}`); }); }); 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 2c52e002ea..5bd6bcaac8 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 @@ -9,7 +9,7 @@ import MagicString from 'magic-string'; import * as ts from 'typescript'; import {NoopImportRewriter} from '../../../src/ngtsc/imports'; import {absoluteFrom, getFileSystem, getSourceFileOrError} from '../../../src/ngtsc/file_system'; -import {loadTestFiles} from '../../../test/helpers'; +import {loadTestFiles, loadFakeCore} from '../../../test/helpers'; import {TestFile, runInEachFileSystem} from '../../../src/ngtsc/file_system/testing'; import {ImportManager} from '../../../src/ngtsc/translator'; import {DecorationAnalyzer} from '../../src/analysis/decoration_analyzer'; @@ -23,11 +23,12 @@ import {MockLogger} from '../helpers/mock_logger'; import {ModuleWithProvidersAnalyzer} from '../../src/analysis/module_with_providers_analyzer'; function setup(files: TestFile[], dtsFiles?: TestFile[]) { + const fs = getFileSystem(); + loadFakeCore(fs); loadTestFiles(files); if (dtsFiles) { loadTestFiles(dtsFiles); } - const fs = getFileSystem(); const logger = new MockLogger(); const bundle = makeTestEntryPointBundle( 'test-package', 'es2015', 'esm2015', false, getRootFiles(files), @@ -37,7 +38,8 @@ function setup(files: TestFile[], dtsFiles?: TestFile[]) { const referencesRegistry = new NgccReferencesRegistry(host); const decorationAnalyses = new DecorationAnalyzer(fs, bundle, host, referencesRegistry).analyzeProgram(); - const switchMarkerAnalyses = new SwitchMarkerAnalyzer(host).analyzeProgram(bundle.src.program); + const switchMarkerAnalyses = + new SwitchMarkerAnalyzer(host, bundle.entryPoint.package).analyzeProgram(bundle.src.program); const renderer = new EsmRenderingFormatter(host, false); const importManager = new ImportManager(new NoopImportRewriter(), IMPORT_PREFIX); return { @@ -58,7 +60,7 @@ runInEachFileSystem(() => { _ = absoluteFrom; PROGRAM = { - name: _('/some/file.js'), + name: _('/node_modules/test-package/some/file.js'), contents: ` /* A copyright notice */ import 'some-side-effect'; @@ -120,9 +122,21 @@ import * as i1 from '@angular/common';`); renderer.addExports( output, _(PROGRAM.name.replace(/\.js$/, '')), [ - {from: _('/some/a.js'), dtsFrom: _('/some/a.d.ts'), identifier: 'ComponentA1'}, - {from: _('/some/a.js'), dtsFrom: _('/some/a.d.ts'), identifier: 'ComponentA2'}, - {from: _('/some/foo/b.js'), dtsFrom: _('/some/foo/b.d.ts'), identifier: 'ComponentB'}, + { + from: _('/node_modules/test-package/some/a.js'), + dtsFrom: _('/node_modules/test-package/some/a.d.ts'), + identifier: 'ComponentA1' + }, + { + from: _('/node_modules/test-package/some/a.js'), + dtsFrom: _('/node_modules/test-package/some/a.d.ts'), + identifier: 'ComponentA2' + }, + { + from: _('/node_modules/test-package/some/foo/b.js'), + dtsFrom: _('/node_modules/test-package/some/foo/b.d.ts'), + identifier: 'ComponentB' + }, {from: PROGRAM.name, dtsFrom: PROGRAM.name, identifier: 'TopLevelComponent'}, ], importManager, sourceFile); @@ -140,9 +154,21 @@ export {TopLevelComponent};`); renderer.addExports( output, _(PROGRAM.name.replace(/\.js$/, '')), [ - {from: _('/some/a.js'), alias: 'eComponentA1', identifier: 'ComponentA1'}, - {from: _('/some/a.js'), alias: 'eComponentA2', identifier: 'ComponentA2'}, - {from: _('/some/foo/b.js'), alias: 'eComponentB', identifier: 'ComponentB'}, + { + from: _('/node_modules/test-package/some/a.js'), + alias: 'eComponentA1', + identifier: 'ComponentA1' + }, + { + from: _('/node_modules/test-package/some/a.js'), + alias: 'eComponentA2', + identifier: 'ComponentA2' + }, + { + from: _('/node_modules/test-package/some/foo/b.js'), + alias: 'eComponentB', + identifier: 'ComponentB' + }, {from: PROGRAM.name, alias: 'eTopLevelComponent', identifier: 'TopLevelComponent'}, ], importManager, sourceFile); @@ -156,7 +182,7 @@ export {TopLevelComponent};`); describe('addConstants', () => { it('should insert the given constants after imports in the source file', () => { const {renderer, program} = setup([PROGRAM]); - const file = getSourceFileOrError(program, _('/some/file.js')); + const file = getSourceFileOrError(program, _('/node_modules/test-package/some/file.js')); const output = new MagicString(PROGRAM.contents); renderer.addConstants(output, 'const x = 3;', file); expect(output.toString()).toContain(` @@ -168,7 +194,7 @@ export class A {}`); it('should insert constants after inserted imports', () => { const {renderer, program} = setup([PROGRAM]); - const file = getSourceFileOrError(program, _('/some/file.js')); + const file = getSourceFileOrError(program, _('/node_modules/test-package/some/file.js')); const output = new MagicString(PROGRAM.contents); renderer.addConstants(output, 'const x = 3;', file); renderer.addImports(output, [{specifier: '@angular/core', qualifier: 'i0'}], file); @@ -184,7 +210,7 @@ export class A {`); describe('rewriteSwitchableDeclarations', () => { it('should switch marked declaration initializers', () => { const {renderer, program, switchMarkerAnalyses, sourceFile} = setup([PROGRAM]); - const file = getSourceFileOrError(program, _('/some/file.js')); + const file = getSourceFileOrError(program, _('/node_modules/test-package/some/file.js')); const output = new MagicString(PROGRAM.contents); renderer.rewriteSwitchableDeclarations( output, file, switchMarkerAnalyses.get(sourceFile) !.declarations); @@ -292,7 +318,7 @@ A.decorators = [ beforeEach(() => { PROGRAM_DECORATE_HELPER = { - name: _('/some/file.js'), + name: _('/node_modules/test-package/some/file.js'), contents: ` import * as tslib_1 from "tslib"; var D_1; diff --git a/packages/compiler-cli/ngcc/test/rendering/renderer_spec.ts b/packages/compiler-cli/ngcc/test/rendering/renderer_spec.ts index be77626357..adf8b57d0f 100644 --- a/packages/compiler-cli/ngcc/test/rendering/renderer_spec.ts +++ b/packages/compiler-cli/ngcc/test/rendering/renderer_spec.ts @@ -69,7 +69,8 @@ function createTestRenderer( const referencesRegistry = new NgccReferencesRegistry(host); const decorationAnalyses = new DecorationAnalyzer(fs, bundle, host, referencesRegistry).analyzeProgram(); - const switchMarkerAnalyses = new SwitchMarkerAnalyzer(host).analyzeProgram(bundle.src.program); + const switchMarkerAnalyses = + new SwitchMarkerAnalyzer(host, bundle.entryPoint.package).analyzeProgram(bundle.src.program); const privateDeclarationsAnalyses = new PrivateDeclarationsAnalyzer(host, referencesRegistry).analyzeProgram(bundle.src.program); const testFormatter = new TestRenderingFormatter(); @@ -105,22 +106,22 @@ runInEachFileSystem(() => { _ = absoluteFrom; INPUT_PROGRAM = { - name: _('/src/file.js'), + name: _('/node_modules/test-package/src/file.js'), contents: `import { Directive } from '@angular/core';\nexport class A {\n foo(x) {\n return x;\n }\n}\nA.decorators = [\n { type: Directive, args: [{ selector: '[a]' }] }\n];\n` }; COMPONENT_PROGRAM = { - name: _('/src/component.js'), + name: _('/node_modules/test-package/src/component.js'), contents: `import { Component } from '@angular/core';\nexport class A {}\nA.decorators = [\n { type: Component, args: [{ selector: 'a', template: '{{ person!.name }}' }] }\n];\n` }; INPUT_PROGRAM_MAP = fromObject({ 'version': 3, - 'file': _('/src/file.js'), + 'file': _('/node_modules/test-package/src/file.js'), 'sourceRoot': '', - 'sources': [_('/src/file.ts')], + 'sources': [_('/node_modules/test-package/src/file.ts')], 'names': [], 'mappings': 'AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAC1C,MAAM;IACF,GAAG,CAAC,CAAS;QACT,OAAO,CAAC,CAAC;IACb,CAAC;;AACM,YAAU,GAAG;IAChB,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC,EAAE;CACnD,CAAC', @@ -142,7 +143,7 @@ runInEachFileSystem(() => { OUTPUT_PROGRAM_MAP = fromObject({ 'version': 3, 'file': 'file.js', - 'sources': [_('/src/file.js')], + 'sources': [_('/node_modules/test-package/src/file.js')], 'sourcesContent': [INPUT_PROGRAM.contents], 'names': [], 'mappings': ';;;;;;;;;;AAAA;;;;;;;;;' @@ -150,7 +151,7 @@ runInEachFileSystem(() => { MERGED_OUTPUT_PROGRAM_MAP = fromObject({ 'version': 3, - 'sources': [_('/src/file.ts')], + 'sources': [_('/node_modules/test-package/src/file.ts')], 'names': [], 'mappings': ';;;;;;;;;;AAAA', 'file': 'file.js', @@ -165,10 +166,10 @@ runInEachFileSystem(() => { createTestRenderer('test-package', [INPUT_PROGRAM]); const result = renderer.renderProgram( decorationAnalyses, switchMarkerAnalyses, privateDeclarationsAnalyses); - expect(result[0].path).toEqual(_('/src/file.js')); + expect(result[0].path).toEqual(_('/node_modules/test-package/src/file.js')); expect(result[0].contents) .toEqual(RENDERED_CONTENTS + '\n' + generateMapFileComment('file.js.map')); - expect(result[1].path).toEqual(_('/src/file.js.map')); + expect(result[1].path).toEqual(_('/node_modules/test-package/src/file.js.map')); expect(result[1].contents).toEqual(OUTPUT_PROGRAM_MAP.toJSON()); }); @@ -254,9 +255,10 @@ runInEachFileSystem(() => { it('should render classes without decorators if handler matches', () => { const {renderer, decorationAnalyses, switchMarkerAnalyses, privateDeclarationsAnalyses, - testFormatter} = createTestRenderer('test-package', [{ - name: _('/src/file.js'), - contents: ` + testFormatter} = + createTestRenderer('test-package', [{ + name: _('/node_modules/test-package/src/file.js'), + contents: ` import { Directive, ViewChild } from '@angular/core'; export class UndecoratedBase { test = null; } @@ -268,7 +270,7 @@ runInEachFileSystem(() => { }], }; ` - }]); + }]); renderer.renderProgram( decorationAnalyses, switchMarkerAnalyses, privateDeclarationsAnalyses); @@ -312,7 +314,7 @@ runInEachFileSystem(() => { }]); const result = renderer.renderProgram( decorationAnalyses, switchMarkerAnalyses, privateDeclarationsAnalyses); - expect(result[0].path).toEqual(_('/src/file.js')); + expect(result[0].path).toEqual(_('/node_modules/test-package/src/file.js')); expect(result[0].contents) .toEqual(RENDERED_CONTENTS + '\n' + MERGED_OUTPUT_PROGRAM_MAP.toComment()); expect(result[1]).toBeUndefined(); @@ -331,10 +333,10 @@ runInEachFileSystem(() => { createTestRenderer('test-package', sourceFiles, undefined, mappingFiles); const result = renderer.renderProgram( decorationAnalyses, switchMarkerAnalyses, privateDeclarationsAnalyses); - expect(result[0].path).toEqual(_('/src/file.js')); + expect(result[0].path).toEqual(_('/node_modules/test-package/src/file.js')); expect(result[0].contents) .toEqual(RENDERED_CONTENTS + '\n' + generateMapFileComment('file.js.map')); - expect(result[1].path).toEqual(_('/src/file.js.map')); + expect(result[1].path).toEqual(_('/node_modules/test-package/src/file.js.map')); expect(JSON.parse(result[1].contents)).toEqual(MERGED_OUTPUT_PROGRAM_MAP.toObject()); }); }); @@ -342,14 +344,14 @@ runInEachFileSystem(() => { describe('@angular/core support', () => { it('should render relative imports in ESM bundles', () => { const CORE_FILE: TestFile = { - name: _('/src/core.js'), + name: _('/node_modules/test-package/src/core.js'), contents: `import { NgModule } from './ng_module';\nexport class MyModule {}\nMyModule.decorators = [\n { type: NgModule, args: [] }\n];\n` }; const R3_SYMBOLS_FILE: TestFile = { // r3_symbols in the file name indicates that this is the path to rewrite core imports // to - name: _('/src/r3_symbols.js'), + name: _('/node_modules/test-package/src/r3_symbols.js'), contents: `export const NgModule = () => null;` }; // The package name of `@angular/core` indicates that we are compiling the core library. @@ -368,7 +370,7 @@ runInEachFileSystem(() => { it('should render no imports in FESM bundles', () => { const CORE_FILE: TestFile = { - name: _('/src/core.js'), + name: _('/node_modules/test-package/src/core.js'), contents: `export const NgModule = () => null; export class MyModule {}\nMyModule.decorators = [\n { type: NgModule, args: [] }\n];\n` }; diff --git a/packages/compiler-cli/ngcc/test/rendering/umd_rendering_formatter_spec.ts b/packages/compiler-cli/ngcc/test/rendering/umd_rendering_formatter_spec.ts index 1286f9a081..a6065b229c 100644 --- a/packages/compiler-cli/ngcc/test/rendering/umd_rendering_formatter_spec.ts +++ b/packages/compiler-cli/ngcc/test/rendering/umd_rendering_formatter_spec.ts @@ -31,7 +31,8 @@ function setup(file: TestFile) { const referencesRegistry = new NgccReferencesRegistry(host); const decorationAnalyses = new DecorationAnalyzer(fs, bundle, host, referencesRegistry).analyzeProgram(); - const switchMarkerAnalyses = new SwitchMarkerAnalyzer(host).analyzeProgram(src.program); + const switchMarkerAnalyses = + new SwitchMarkerAnalyzer(host, bundle.entryPoint.package).analyzeProgram(src.program); const renderer = new UmdRenderingFormatter(host, false); const importManager = new ImportManager(new NoopImportRewriter(), 'i'); return { @@ -54,7 +55,7 @@ runInEachFileSystem(() => { _ = absoluteFrom; PROGRAM = { - name: _('/some/file.js'), + name: _('/node_modules/test-package/some/file.js'), contents: ` /* A copyright notice */ (function (global, factory) { @@ -123,7 +124,7 @@ exports.BadIife = BadIife; PROGRAM_DECORATE_HELPER = { - name: _('/some/file.js'), + name: _('/node_modules/test-package/some/file.js'), contents: ` /* A copyright notice */ (function (global, factory) { @@ -181,7 +182,7 @@ typeof define === 'function' && define.amd ? define('file', ['exports','/tslib', describe('addImports', () => { it('should append the given imports into the CommonJS factory call', () => { const {renderer, program} = setup(PROGRAM); - const file = getSourceFileOrError(program, _('/some/file.js')); + const file = getSourceFileOrError(program, _('/node_modules/test-package/some/file.js')); const output = new MagicString(PROGRAM.contents); renderer.addImports( output, @@ -197,7 +198,7 @@ typeof define === 'function' && define.amd ? define('file', ['exports','/tslib', it('should append the given imports into the AMD initialization', () => { const {renderer, program} = setup(PROGRAM); - const file = getSourceFileOrError(program, _('/some/file.js')); + const file = getSourceFileOrError(program, _('/node_modules/test-package/some/file.js')); const output = new MagicString(PROGRAM.contents); renderer.addImports( output, @@ -213,7 +214,7 @@ typeof define === 'function' && define.amd ? define('file', ['exports','/tslib', it('should append the given imports into the global initialization', () => { const {renderer, program} = setup(PROGRAM); - const file = getSourceFileOrError(program, _('/some/file.js')); + const file = getSourceFileOrError(program, _('/node_modules/test-package/some/file.js')); const output = new MagicString(PROGRAM.contents); renderer.addImports( output, @@ -230,7 +231,7 @@ typeof define === 'function' && define.amd ? define('file', ['exports','/tslib', it('should append the given imports as parameters into the factory function definition', () => { const {renderer, program} = setup(PROGRAM); - const file = getSourceFileOrError(program, _('/some/file.js')); + const file = getSourceFileOrError(program, _('/node_modules/test-package/some/file.js')); const output = new MagicString(PROGRAM.contents); renderer.addImports( output, @@ -253,9 +254,9 @@ typeof define === 'function' && define.amd ? define('file', ['exports','/tslib', renderer.addExports( output, PROGRAM.name.replace(/\.js$/, ''), [ - {from: _('/some/a.js'), identifier: 'ComponentA1'}, - {from: _('/some/a.js'), identifier: 'ComponentA2'}, - {from: _('/some/foo/b.js'), identifier: 'ComponentB'}, + {from: _('/node_modules/test-package/some/a.js'), identifier: 'ComponentA1'}, + {from: _('/node_modules/test-package/some/a.js'), identifier: 'ComponentA2'}, + {from: _('/node_modules/test-package/some/foo/b.js'), identifier: 'ComponentB'}, {from: PROGRAM.name, identifier: 'TopLevelComponent'}, ], importManager, sourceFile); @@ -283,9 +284,21 @@ exports.TopLevelComponent = TopLevelComponent; renderer.addExports( output, PROGRAM.name.replace(/\.js$/, ''), [ - {from: _('/some/a.js'), alias: 'eComponentA1', identifier: 'ComponentA1'}, - {from: _('/some/a.js'), alias: 'eComponentA2', identifier: 'ComponentA2'}, - {from: _('/some/foo/b.js'), alias: 'eComponentB', identifier: 'ComponentB'}, + { + from: _('/node_modules/test-package/some/a.js'), + alias: 'eComponentA1', + identifier: 'ComponentA1' + }, + { + from: _('/node_modules/test-package/some/a.js'), + alias: 'eComponentA2', + identifier: 'ComponentA2' + }, + { + from: _('/node_modules/test-package/some/foo/b.js'), + alias: 'eComponentB', + identifier: 'ComponentB' + }, {from: PROGRAM.name, alias: 'eTopLevelComponent', identifier: 'TopLevelComponent'}, ], importManager, sourceFile); @@ -299,7 +312,7 @@ exports.TopLevelComponent = TopLevelComponent; describe('addConstants', () => { it('should insert the given constants after imports in the source file', () => { const {renderer, program} = setup(PROGRAM); - const file = getSourceFileOrError(program, _('/some/file.js')); + const file = getSourceFileOrError(program, _('/node_modules/test-package/some/file.js')); const output = new MagicString(PROGRAM.contents); renderer.addConstants(output, 'var x = 3;', file); expect(output.toString()).toContain(` @@ -319,7 +332,7 @@ var A = (function() {`); describe('rewriteSwitchableDeclarations', () => { it('should switch marked declaration initializers', () => { const {renderer, program, sourceFile, switchMarkerAnalyses} = setup(PROGRAM); - const file = getSourceFileOrError(program, _('/some/file.js')); + const file = getSourceFileOrError(program, _('/node_modules/test-package/some/file.js')); const output = new MagicString(PROGRAM.contents); renderer.rewriteSwitchableDeclarations( output, file, switchMarkerAnalyses.get(sourceFile) !.declarations); @@ -364,14 +377,14 @@ SOME DEFINITION TEXT const mockNoIifeClass: any = {declaration: noIifeDeclaration, name: 'NoIife'}; expect(() => renderer.addDefinitions(output, mockNoIifeClass, 'SOME DEFINITION TEXT')) .toThrowError( - `Compiled class declaration is not inside an IIFE: NoIife in ${_('/some/file.js')}`); + `Compiled class declaration is not inside an IIFE: NoIife in ${_('/node_modules/test-package/some/file.js')}`); const badIifeDeclaration = getDeclaration( program, absoluteFromSourceFile(sourceFile), 'BadIife', ts.isVariableDeclaration); const mockBadIifeClass: any = {declaration: badIifeDeclaration, name: 'BadIife'}; expect(() => renderer.addDefinitions(output, mockBadIifeClass, 'SOME DEFINITION TEXT')) .toThrowError( - `Compiled class wrapper IIFE does not have a return statement: BadIife in ${_('/some/file.js')}`); + `Compiled class wrapper IIFE does not have a return statement: BadIife in ${_('/node_modules/test-package/some/file.js')}`); }); });