diff --git a/packages/compiler-cli/ngcc/src/entry_point_finder/targeted_entry_point_finder.ts b/packages/compiler-cli/ngcc/src/entry_point_finder/targeted_entry_point_finder.ts index 58b698bc04..5cbf40ed3b 100644 --- a/packages/compiler-cli/ngcc/src/entry_point_finder/targeted_entry_point_finder.ts +++ b/packages/compiler-cli/ngcc/src/entry_point_finder/targeted_entry_point_finder.ts @@ -8,8 +8,9 @@ import {AbsoluteFsPath, FileSystem, PathSegment, join, relative, relativeFrom} from '../../../src/ngtsc/file_system'; import {DependencyResolver, SortedEntryPointsInfo} from '../dependencies/dependency_resolver'; import {Logger} from '../logging/logger'; +import {hasBeenProcessed} from '../packages/build_marker'; import {NgccConfiguration} from '../packages/configuration'; -import {EntryPoint, getEntryPointInfo} from '../packages/entry_point'; +import {EntryPoint, EntryPointJsonProperty, getEntryPointInfo} from '../packages/entry_point'; import {PathMappings} from '../utils'; import {EntryPointFinder} from './interface'; import {getBasePaths} from './utils'; @@ -37,8 +38,41 @@ export class TargetedEntryPointFinder implements EntryPointFinder { this.processNextPath(); } const targetEntryPoint = this.unsortedEntryPoints.get(this.targetPath); - return this.resolver.sortEntryPointsByDependency( + const entryPoints = this.resolver.sortEntryPointsByDependency( Array.from(this.unsortedEntryPoints.values()), targetEntryPoint); + + const invalidTarget = + entryPoints.invalidEntryPoints.find(i => i.entryPoint.path === this.targetPath); + if (invalidTarget !== undefined) { + throw new Error( + `The target entry-point "${invalidTarget.entryPoint.name}" has missing dependencies:\n` + + invalidTarget.missingDependencies.map(dep => ` - ${dep}\n`).join('')); + } + return entryPoints; + } + + targetNeedsProcessingOrCleaning( + propertiesToConsider: EntryPointJsonProperty[], compileAllFormats: boolean): boolean { + const entryPoint = this.getEntryPoint(this.targetPath); + if (entryPoint === null || !entryPoint.compiledByAngular) { + return false; + } + + for (const property of propertiesToConsider) { + if (entryPoint.packageJson[property]) { + // Here is a property that should be processed. + if (!hasBeenProcessed(entryPoint.packageJson, property)) { + return true; + } + if (!compileAllFormats) { + // This property has been processed, and we only need one. + return false; + } + } + } + // All `propertiesToConsider` that appear in this entry-point have been processed. + // In other words, there were no properties that need processing. + return false; } private processNextPath(): void { diff --git a/packages/compiler-cli/ngcc/src/main.ts b/packages/compiler-cli/ngcc/src/main.ts index 4abaf878f7..d64f972f6d 100644 --- a/packages/compiler-cli/ngcc/src/main.ts +++ b/packages/compiler-cli/ngcc/src/main.ts @@ -16,12 +16,13 @@ import {replaceTsWithNgInErrors} from '../../src/ngtsc/diagnostics'; import {AbsoluteFsPath, FileSystem, absoluteFrom, dirname, getFileSystem, resolve} from '../../src/ngtsc/file_system'; import {CommonJsDependencyHost} from './dependencies/commonjs_dependency_host'; -import {DependencyResolver, InvalidEntryPoint, PartiallyOrderedEntryPoints, SortedEntryPointsInfo} from './dependencies/dependency_resolver'; +import {DependencyResolver, InvalidEntryPoint} from './dependencies/dependency_resolver'; import {DtsDependencyHost} from './dependencies/dts_dependency_host'; import {EsmDependencyHost} from './dependencies/esm_dependency_host'; import {ModuleResolver} from './dependencies/module_resolver'; import {UmdDependencyHost} from './dependencies/umd_dependency_host'; import {DirectoryWalkerEntryPointFinder} from './entry_point_finder/directory_walker_entry_point_finder'; +import {EntryPointFinder} from './entry_point_finder/interface'; import {TargetedEntryPointFinder} from './entry_point_finder/targeted_entry_point_finder'; import {AnalyzeEntryPointsFn, CreateCompileFn, Executor, PartiallyOrderedTasks, Task, TaskProcessingOutcome, TaskQueue} from './execution/api'; import {ClusterExecutor} from './execution/cluster/executor'; @@ -147,16 +148,19 @@ export function mainNgcc( // NOTE: Avoid eagerly instantiating anything that might not be used when running sync/async or in // master/worker process. const fileSystem = getFileSystem(); - + const absBasePath = absoluteFrom(basePath); + const config = new NgccConfiguration(fileSystem, dirname(absBasePath)); + const dependencyResolver = getDependencyResolver(fileSystem, logger, pathMappings); // Bail out early if the work is already done. const supportedPropertiesToConsider = ensureSupportedProperties(propertiesToConsider); const absoluteTargetEntryPointPath = - targetEntryPointPath !== undefined ? resolve(basePath, targetEntryPointPath) : undefined; - if (absoluteTargetEntryPointPath !== undefined && - hasProcessedTargetEntryPoint( - fileSystem, absoluteTargetEntryPointPath, supportedPropertiesToConsider, - compileAllFormats)) { + targetEntryPointPath !== undefined ? resolve(basePath, targetEntryPointPath) : null; + const finder = getEntryPointFinder( + fileSystem, logger, dependencyResolver, config, absBasePath, absoluteTargetEntryPointPath, + pathMappings); + if (finder instanceof TargetedEntryPointFinder && + !finder.targetNeedsProcessingOrCleaning(supportedPropertiesToConsider, compileAllFormats)) { logger.debug('The target entry-point has already been processed'); return; } @@ -172,34 +176,15 @@ export function mainNgcc( logger.debug('Analyzing entry-points...'); const startTime = Date.now(); - const moduleResolver = new ModuleResolver(fileSystem, pathMappings); - const esmDependencyHost = new EsmDependencyHost(fileSystem, moduleResolver); - const umdDependencyHost = new UmdDependencyHost(fileSystem, moduleResolver); - const commonJsDependencyHost = new CommonJsDependencyHost(fileSystem, moduleResolver); - const dtsDependencyHost = new DtsDependencyHost(fileSystem, pathMappings); - const dependencyResolver = new DependencyResolver( - fileSystem, logger, { - esm5: esmDependencyHost, - esm2015: esmDependencyHost, - umd: umdDependencyHost, - commonjs: commonJsDependencyHost - }, - dtsDependencyHost); - - const absBasePath = absoluteFrom(basePath); - const config = new NgccConfiguration(fileSystem, dirname(absBasePath)); - let entryPointInfo = getEntryPoints( - fileSystem, pkgJsonUpdater, logger, dependencyResolver, config, absBasePath, - absoluteTargetEntryPointPath, pathMappings); - + let entryPointInfo = finder.findEntryPoints(); const cleaned = cleanOutdatedPackages(fileSystem, entryPointInfo.entryPoints); if (cleaned) { // If we had to clean up one or more packages then we must read in the entry-points again. - entryPointInfo = getEntryPoints( - fileSystem, pkgJsonUpdater, logger, dependencyResolver, config, absBasePath, - absoluteTargetEntryPointPath, pathMappings); + entryPointInfo = finder.findEntryPoints(); } - const {entryPoints, graph} = entryPointInfo; + + const {entryPoints, invalidEntryPoints, graph} = entryPointInfo; + logInvalidEntryPoints(logger, invalidEntryPoints); const unprocessableEntryPointPaths: string[] = []; // The tasks are partially ordered by virtue of the entry-points being partially ordered too. @@ -364,77 +349,35 @@ function getExecutor( } } -function getEntryPoints( - fs: FileSystem, pkgJsonUpdater: PackageJsonUpdater, logger: Logger, - resolver: DependencyResolver, config: NgccConfiguration, basePath: AbsoluteFsPath, - targetEntryPointPath: AbsoluteFsPath | undefined, pathMappings: PathMappings | - undefined): {entryPoints: PartiallyOrderedEntryPoints, graph: DepGraph} { - const {entryPoints, invalidEntryPoints, graph} = (targetEntryPointPath !== undefined) ? - getTargetedEntryPoints( - fs, pkgJsonUpdater, logger, resolver, config, basePath, targetEntryPointPath, - pathMappings) : - getAllEntryPoints(fs, config, logger, resolver, basePath, pathMappings); - logInvalidEntryPoints(logger, invalidEntryPoints); - return {entryPoints, graph}; +function getDependencyResolver( + fileSystem: FileSystem, logger: Logger, + pathMappings: PathMappings | undefined): DependencyResolver { + const moduleResolver = new ModuleResolver(fileSystem, pathMappings); + const esmDependencyHost = new EsmDependencyHost(fileSystem, moduleResolver); + const umdDependencyHost = new UmdDependencyHost(fileSystem, moduleResolver); + const commonJsDependencyHost = new CommonJsDependencyHost(fileSystem, moduleResolver); + const dtsDependencyHost = new DtsDependencyHost(fileSystem, pathMappings); + return new DependencyResolver( + fileSystem, logger, { + esm5: esmDependencyHost, + esm2015: esmDependencyHost, + umd: umdDependencyHost, + commonjs: commonJsDependencyHost + }, + dtsDependencyHost); } -function getTargetedEntryPoints( - fs: FileSystem, pkgJsonUpdater: PackageJsonUpdater, logger: Logger, - resolver: DependencyResolver, config: NgccConfiguration, basePath: AbsoluteFsPath, - absoluteTargetEntryPointPath: AbsoluteFsPath, - pathMappings: PathMappings | undefined): SortedEntryPointsInfo { - const finder = new TargetedEntryPointFinder( - fs, config, logger, resolver, basePath, absoluteTargetEntryPointPath, pathMappings); - const entryPointInfo = finder.findEntryPoints(); - const invalidTarget = entryPointInfo.invalidEntryPoints.find( - i => i.entryPoint.path === absoluteTargetEntryPointPath); - if (invalidTarget !== undefined) { - throw new Error( - `The target entry-point "${invalidTarget.entryPoint.name}" has missing dependencies:\n` + - invalidTarget.missingDependencies.map(dep => ` - ${dep}\n`).join('')); +function getEntryPointFinder( + fs: FileSystem, logger: Logger, resolver: DependencyResolver, config: NgccConfiguration, + basePath: AbsoluteFsPath, absoluteTargetEntryPointPath: AbsoluteFsPath | null, + pathMappings: PathMappings | undefined): EntryPointFinder { + if (absoluteTargetEntryPointPath !== null) { + return new TargetedEntryPointFinder( + fs, config, logger, resolver, basePath, absoluteTargetEntryPointPath, pathMappings); + } else { + return new DirectoryWalkerEntryPointFinder( + fs, config, logger, resolver, basePath, pathMappings); } - if (entryPointInfo.entryPoints.length === 0) { - markNonAngularPackageAsProcessed(fs, pkgJsonUpdater, absoluteTargetEntryPointPath); - } - return entryPointInfo; -} - -function getAllEntryPoints( - fs: FileSystem, config: NgccConfiguration, logger: Logger, resolver: DependencyResolver, - basePath: AbsoluteFsPath, pathMappings: PathMappings | undefined): SortedEntryPointsInfo { - const finder = - new DirectoryWalkerEntryPointFinder(fs, config, logger, resolver, basePath, pathMappings); - return finder.findEntryPoints(); -} - -function hasProcessedTargetEntryPoint( - fs: FileSystem, targetPath: AbsoluteFsPath, propertiesToConsider: string[], - compileAllFormats: boolean) { - const packageJsonPath = resolve(targetPath, 'package.json'); - // It might be that this target is configured in which case its package.json might not exist. - if (!fs.exists(packageJsonPath)) { - return false; - } - const packageJson = JSON.parse(fs.readFile(packageJsonPath)); - - for (const property of propertiesToConsider) { - if (packageJson[property]) { - // Here is a property that should be processed - if (hasBeenProcessed(packageJson, property as EntryPointJsonProperty)) { - if (!compileAllFormats) { - // It has been processed and we only need one, so we are done. - return true; - } - } else { - // It has not been processed but we need all of them, so we are done. - return false; - } - } - } - // Either all formats need to be compiled and there were none that were unprocessed, - // Or only the one matching format needs to be compiled but there was at least one matching - // property before the first processed format that was unprocessed. - return true; } /** diff --git a/packages/compiler-cli/ngcc/test/entry_point_finder/targeted_entry_point_finder_spec.ts b/packages/compiler-cli/ngcc/test/entry_point_finder/targeted_entry_point_finder_spec.ts index 521748d5a1..647a4dca63 100644 --- a/packages/compiler-cli/ngcc/test/entry_point_finder/targeted_entry_point_finder_spec.ts +++ b/packages/compiler-cli/ngcc/test/entry_point_finder/targeted_entry_point_finder_spec.ts @@ -13,6 +13,7 @@ import {DtsDependencyHost} from '../../src/dependencies/dts_dependency_host'; import {EsmDependencyHost} from '../../src/dependencies/esm_dependency_host'; import {ModuleResolver} from '../../src/dependencies/module_resolver'; import {TargetedEntryPointFinder} from '../../src/entry_point_finder/targeted_entry_point_finder'; +import {NGCC_VERSION} from '../../src/packages/build_marker'; import {NgccConfiguration} from '../../src/packages/configuration'; import {EntryPoint} from '../../src/packages/entry_point'; import {PathMappings} from '../../src/utils'; @@ -227,32 +228,252 @@ runInEachFileSystem(() => { ]); }); - function createPackage( - basePath: AbsoluteFsPath, packageName: string, deps: string[] = []): TestFile[] { - return [ - { - name: _Abs(`${basePath}/${packageName}/package.json`), - contents: JSON.stringify({ - typings: `./${packageName}.d.ts`, - fesm2015: `./fesm2015/${packageName}.js`, - }) - }, - { - name: _Abs(`${basePath}/${packageName}/${packageName}.metadata.json`), - contents: 'metadata info' - }, - { - name: _Abs(`${basePath}/${packageName}/fesm2015/${packageName}.js`), - contents: deps.map((dep, i) => `import * as i${i} from '${dep}';`).join('\n'), - }, - ]; - } - function dumpEntryPointPaths( basePath: AbsoluteFsPath, entryPoints: EntryPoint[]): [string, string][] { return entryPoints.map(x => [relative(basePath, x.package), relative(basePath, x.path)]); } }); + + describe('targetNeedsProcessingOrCleaning()', () => { + it('should return false if there is no entry-point', () => { + const targetPath = _Abs('/no_packages/node_modules/should_not_be_found'); + fs.ensureDir(targetPath); + const finder = new TargetedEntryPointFinder( + fs, config, logger, resolver, _Abs('/no_packages/node_modules'), targetPath, undefined); + expect(finder.targetNeedsProcessingOrCleaning(['fesm2015'], true)).toBe(false); + }); + + it('should return false if the target path is not a valid entry-point', () => { + const targetPath = _Abs('/no_valid_entry_points/node_modules/some_package'); + loadTestFiles([ + { + name: _Abs('/no_valid_entry_points/node_modules/some_package/package.json'), + contents: '{}' + }, + ]); + const finder = new TargetedEntryPointFinder( + fs, config, logger, resolver, _Abs('/no_valid_entry_points/node_modules'), targetPath, + undefined); + expect(finder.targetNeedsProcessingOrCleaning(['fesm2015'], true)).toBe(false); + }); + + it('should false if the target path has no typings', () => { + const targetPath = _Abs('/no_valid_entry_points/node_modules/some_package'); + loadTestFiles([ + { + name: _Abs('/no_valid_entry_points/node_modules/some_package/package.json'), + contents: '{"fesm2015": "./index.js"}' + }, + { + name: + _Abs('/no_valid_entry_points/node_modules/some_package/some_package.metadata.json'), + contents: 'metadata info' + }, + { + name: _Abs('/no_valid_entry_points/node_modules/some_package/index.js'), + contents: 'export class MyClass {}' + }, + ]); + const finder = new TargetedEntryPointFinder( + fs, config, logger, resolver, _Abs('/no_valid_entry_points/node_modules'), targetPath, + undefined); + expect(finder.targetNeedsProcessingOrCleaning(['fesm2015'], true)).toBe(false); + }); + + it('should false if the target path is not compiled by Angular - i.e has no metadata file', + () => { + const targetPath = _Abs('/no_valid_entry_points/node_modules/some_package'); + loadTestFiles([ + { + name: _Abs('/no_valid_entry_points/node_modules/some_package/package.json'), + contents: '{"typings": "./index.d.ts", "fesm2015": "./index.js"}' + }, + { + name: _Abs('/no_valid_entry_points/node_modules/some_package/index.d.ts'), + contents: 'export declare class MyClass {}' + }, + { + name: _Abs('/no_valid_entry_points/node_modules/some_package/index.js'), + contents: 'export class MyClass {}' + }, + ]); + const finder = new TargetedEntryPointFinder( + fs, config, logger, resolver, _Abs('/no_valid_entry_points/node_modules'), + targetPath, undefined); + expect(finder.targetNeedsProcessingOrCleaning(['fesm2015'], true)).toBe(false); + }); + + describe('[compileAllFormats: true]', () => { + it('should return true if none of the properties to consider have been processed', () => { + const basePath = _Abs('/sub_entry_points/node_modules'); + const targetPath = _Abs('/sub_entry_points/node_modules/common/http/testing'); + loadTestFiles([ + ...createPackage(fs.resolve(basePath, ''), 'common'), + ...createPackage(fs.resolve(basePath, 'common'), 'http', ['common']), + ...createPackage( + fs.resolve(basePath, 'common/http'), 'testing', ['common/http', 'common/testing']), + ...createPackage(fs.resolve(basePath, 'common'), 'testing', ['common']), + ]); + const finder = new TargetedEntryPointFinder( + fs, config, logger, resolver, basePath, targetPath, undefined); + expect(finder.targetNeedsProcessingOrCleaning(['fesm2015', 'esm5'], true)).toBe(true); + }); + + it('should return true if at least one of the properties to consider has not been processed', + () => { + const basePath = _Abs('/sub_entry_points/node_modules'); + const targetPath = _Abs('/sub_entry_points/node_modules/common/http/testing'); + loadTestFiles([ + ...createPackage(fs.resolve(basePath, ''), 'common'), + ...createPackage(fs.resolve(basePath, 'common'), 'http', ['common']), + ...createPackage( + fs.resolve(basePath, 'common/http'), 'testing', + ['common/http', 'common/testing']), + ...createPackage(fs.resolve(basePath, 'common'), 'testing', ['common']), + ]); + + // Add a build marker to the package.json + const packageJsonPath = _Abs(`${targetPath}/package.json`); + const packageJson = JSON.parse(fs.readFile(packageJsonPath)); + packageJson.__processed_by_ivy_ngcc__ = { + esm5: NGCC_VERSION, + }; + fs.writeFile(packageJsonPath, JSON.stringify(packageJson)); + + const finder = new TargetedEntryPointFinder( + fs, config, logger, resolver, basePath, targetPath, undefined); + expect(finder.targetNeedsProcessingOrCleaning(['fesm2015', 'esm5'], true)).toBe(true); + }); + + it('should return false if all of the properties to consider have been processed', () => { + const basePath = _Abs('/sub_entry_points/node_modules'); + const targetPath = _Abs('/sub_entry_points/node_modules/common/http/testing'); + loadTestFiles([ + ...createPackage(fs.resolve(basePath, ''), 'common'), + ...createPackage(fs.resolve(basePath, 'common'), 'http', ['common']), + ...createPackage( + fs.resolve(basePath, 'common/http'), 'testing', ['common/http', 'common/testing']), + ...createPackage(fs.resolve(basePath, 'common'), 'testing', ['common']), + ]); + + // Add build markers to the package.json + const packageJsonPath = _Abs(`${targetPath}/package.json`); + const packageJson = JSON.parse(fs.readFile(packageJsonPath)); + packageJson.__processed_by_ivy_ngcc__ = { + fesm2015: NGCC_VERSION, + esm5: NGCC_VERSION, + main: NGCC_VERSION, + }; + fs.writeFile(packageJsonPath, JSON.stringify(packageJson)); + + const finder = new TargetedEntryPointFinder( + fs, config, logger, resolver, basePath, targetPath, undefined); + expect(finder.targetNeedsProcessingOrCleaning(['fesm2015', 'esm5'], true)).toBe(false); + }); + }); + + describe('[compileAllFormats: false]', () => { + it('should return true if none of the properties to consider have been processed', () => { + const basePath = _Abs('/sub_entry_points/node_modules'); + const targetPath = _Abs('/sub_entry_points/node_modules/common/http/testing'); + loadTestFiles([ + ...createPackage(fs.resolve(basePath, ''), 'common'), + ...createPackage(fs.resolve(basePath, 'common'), 'http', ['common']), + ...createPackage( + fs.resolve(basePath, 'common/http'), 'testing', ['common/http', 'common/testing']), + ...createPackage(fs.resolve(basePath, 'common'), 'testing', ['common']), + ]); + + const finder = new TargetedEntryPointFinder( + fs, config, logger, resolver, basePath, targetPath, undefined); + expect(finder.targetNeedsProcessingOrCleaning(['fesm2015', 'esm5'], false)).toBe(true); + }); + + it('should return true if the first of the properties to consider that is in the package.json has not been processed', + () => { + const basePath = _Abs('/sub_entry_points/node_modules'); + const targetPath = _Abs('/sub_entry_points/node_modules/common/http/testing'); + loadTestFiles([ + ...createPackage(fs.resolve(basePath, ''), 'common'), + ...createPackage(fs.resolve(basePath, 'common'), 'http', ['common']), + ...createPackage( + fs.resolve(basePath, 'common/http'), 'testing', + ['common/http', 'common/testing']), + ...createPackage(fs.resolve(basePath, 'common'), 'testing', ['common']), + ]); + + // Add build markers to the package.json + const packageJsonPath = _Abs(`${targetPath}/package.json`); + const packageJson = JSON.parse(fs.readFile(packageJsonPath)); + packageJson.__processed_by_ivy_ngcc__ = { + esm5: NGCC_VERSION, + }; + fs.writeFile(packageJsonPath, JSON.stringify(packageJson)); + + const finder = new TargetedEntryPointFinder( + fs, config, logger, resolver, basePath, targetPath, undefined); + expect(finder.targetNeedsProcessingOrCleaning(['fesm2015', 'esm5'], false)).toBe(true); + }); + + it('should return false if the first of the properties to consider (that actually appear in the package.json) has been processed', + () => { + const basePath = _Abs('/sub_entry_points/node_modules'); + const targetPath = _Abs('/sub_entry_points/node_modules/common/http/testing'); + loadTestFiles([ + ...createPackage(fs.resolve(basePath, ''), 'common'), + ...createPackage(fs.resolve(basePath, 'common'), 'http', ['common']), + ...createPackage( + fs.resolve(basePath, 'common/http'), 'testing', + ['common/http', 'common/testing']), + ...createPackage(fs.resolve(basePath, 'common'), 'testing', ['common']), + ]); + + // Add build markers to the package.json + const packageJsonPath = _Abs(`${targetPath}/package.json`); + const packageJson = JSON.parse(fs.readFile(packageJsonPath)); + packageJson.__processed_by_ivy_ngcc__ = { + fesm2015: NGCC_VERSION, + }; + fs.writeFile(packageJsonPath, JSON.stringify(packageJson)); + + const finder = new TargetedEntryPointFinder( + fs, config, logger, resolver, basePath, targetPath, undefined); + expect(finder.targetNeedsProcessingOrCleaning(['fesm2015', 'esm5'], false)) + .toBe(false); + }); + }); + }); + + function createPackage( + basePath: AbsoluteFsPath, packageName: string, deps: string[] = []): TestFile[] { + return [ + { + name: _Abs(`${basePath}/${packageName}/package.json`), + contents: JSON.stringify({ + typings: `./${packageName}.d.ts`, + fesm2015: `./fesm2015/${packageName}.js`, + esm5: `./esm5/${packageName}.js`, + main: `./common/${packageName}.js`, + }) + }, + { + name: _Abs(`${basePath}/${packageName}/${packageName}.metadata.json`), + contents: 'metadata info' + }, + { + name: _Abs(`${basePath}/${packageName}/fesm2015/${packageName}.js`), + contents: deps.map((dep, i) => `import * as i${i} from '${dep}';`).join('\n'), + }, + { + name: _Abs(`${basePath}/${packageName}/esm5/${packageName}.js`), + contents: deps.map((dep, i) => `import * as i${i} from '${dep}';`).join('\n'), + }, + { + name: _Abs(`${basePath}/${packageName}/commonjs/${packageName}.js`), + contents: deps.map((dep, i) => `var i${i} = require('${dep}');`).join('\n'), + }, + ]; + } }); }); diff --git a/packages/compiler-cli/ngcc/test/integration/ngcc_spec.ts b/packages/compiler-cli/ngcc/test/integration/ngcc_spec.ts index c2ca59d889..56bd9064b5 100644 --- a/packages/compiler-cli/ngcc/test/integration/ngcc_spec.ts +++ b/packages/compiler-cli/ngcc/test/integration/ngcc_spec.ts @@ -480,22 +480,50 @@ runInEachFileSystem(() => { expect(loadPackage('@angular/common/testing').__processed_by_ivy_ngcc__).toBeUndefined(); }); - it('should mark a non-Angular package target as processed', () => { + it('should not mark a non-Angular package as processed if it is the target', () => { mainNgcc({basePath: '/node_modules', targetEntryPointPath: 'test-package'}); - // `test-package` has no Angular but is marked as processed. - expect(loadPackage('test-package').__processed_by_ivy_ngcc__).toEqual({ + // * `test-package` has no Angular and is not marked as processed. + expect(loadPackage('test-package').__processed_by_ivy_ngcc__).toBeUndefined(); + + // * `core` is a dependency of `test-package`, but it is also not processed, since + // `test-package` was not processed. + expect(loadPackage('@angular/core').__processed_by_ivy_ngcc__).toBeUndefined(); + }); + + it('should not mark a non-Angular package as processed if it is a dependency', () => { + // `test-package-user` is a valid Angular package that depends upon `test-package`. + loadTestFiles([ + { + name: _('/node_modules/test-package-user/package.json'), + contents: + '{"name": "test-package-user", "es2015": "./index.js", "typings": "./index.d.ts"}' + }, + { + name: _('/node_modules/test-package-user/index.js'), + contents: 'import * as x from \'test-package\';' + }, + { + name: _('/node_modules/test-package-user/index.d.ts'), + contents: 'import * as x from \'test-package\';' + }, + {name: _('/node_modules/test-package-user/index.metadata.json'), contents: 'DUMMY DATA'}, + ]); + + mainNgcc({basePath: '/node_modules', targetEntryPointPath: 'test-package-user'}); + + // * `test-package-user` is processed because it is compiled by Angular + expect(loadPackage('test-package-user').__processed_by_ivy_ngcc__).toEqual({ es2015: '0.0.0-PLACEHOLDER', - esm2015: '0.0.0-PLACEHOLDER', - esm5: '0.0.0-PLACEHOLDER', - fesm2015: '0.0.0-PLACEHOLDER', - fesm5: '0.0.0-PLACEHOLDER', - main: '0.0.0-PLACEHOLDER', - module: '0.0.0-PLACEHOLDER', + typings: '0.0.0-PLACEHOLDER', }); - // * `core` is a dependency of `test-package`, but it is not processed, since test-package - // was not processed. + // * `test-package` is a dependency of `test-package-user` but has not been compiled by + // Angular, and so is not marked as processed + expect(loadPackage('test-package').__processed_by_ivy_ngcc__).toBeUndefined(); + + // * `core` is a dependency of `test-package`, but it is not processed, because + // `test-package` was not processed. expect(loadPackage('@angular/core').__processed_by_ivy_ngcc__).toBeUndefined(); });