From 0c3bb6a731ec2e235a8734877cd831e02077b1fe Mon Sep 17 00:00:00 2001 From: Pete Bacon Darwin Date: Thu, 13 Jun 2019 12:20:02 +0100 Subject: [PATCH] fix(ivy): ngcc - capture entry-points in top-level path-mapped folders (#31027) The `EntryPointFinder` computes the base paths to consider when searching for entry-points. When there are `pathMappings` provided it works out the best top level base-paths that cover all the potential mappings. If this computed basePath happens to coincide with an entry-point path itself then we were missing it. Now we check for an entry-point even at the base-path itself. Related to https://github.com/angular/angular-cli/pull/14755 PR Close #31027 --- .../ngcc/src/packages/entry_point_finder.ts | 30 +++++++++------- .../test/packages/entry_point_finder_spec.ts | 35 +++++++++++++++++++ 2 files changed, 52 insertions(+), 13 deletions(-) diff --git a/packages/compiler-cli/ngcc/src/packages/entry_point_finder.ts b/packages/compiler-cli/ngcc/src/packages/entry_point_finder.ts index d1546a7466..b3972bb530 100644 --- a/packages/compiler-cli/ngcc/src/packages/entry_point_finder.ts +++ b/packages/compiler-cli/ngcc/src/packages/entry_point_finder.ts @@ -70,7 +70,12 @@ export class EntryPointFinder { * @param sourceDirectory An absolute path to the root directory where searching begins. */ private walkDirectoryForEntryPoints(sourceDirectory: AbsoluteFsPath): EntryPoint[] { - const entryPoints: EntryPoint[] = []; + const entryPoints = this.getEntryPointsForPackage(sourceDirectory); + if (entryPoints.length > 0) { + // The `sourceDirectory` is an entry-point itself so no need to search its sub-directories. + return entryPoints; + } + this.fs .readdir(sourceDirectory) // Not interested in hidden files @@ -86,16 +91,12 @@ export class EntryPointFinder { // Either the directory is a potential package or a namespace containing packages (e.g // `@angular`). const packagePath = AbsoluteFsPath.join(sourceDirectory, p); - if (p.startsWith('@')) { - entryPoints.push(...this.walkDirectoryForEntryPoints(packagePath)); - } else { - entryPoints.push(...this.getEntryPointsForPackage(packagePath)); + entryPoints.push(...this.walkDirectoryForEntryPoints(packagePath)); - // Also check for any nested node_modules in this package - const nestedNodeModulesPath = AbsoluteFsPath.join(packagePath, 'node_modules'); - if (this.fs.exists(nestedNodeModulesPath)) { - entryPoints.push(...this.walkDirectoryForEntryPoints(nestedNodeModulesPath)); - } + // Also check for any nested node_modules in this package + const nestedNodeModulesPath = AbsoluteFsPath.join(packagePath, 'node_modules'); + if (this.fs.exists(nestedNodeModulesPath)) { + entryPoints.push(...this.walkDirectoryForEntryPoints(nestedNodeModulesPath)); } }); return entryPoints; @@ -111,11 +112,14 @@ export class EntryPointFinder { // Try to get an entry point from the top level package directory const topLevelEntryPoint = getEntryPointInfo(this.fs, this.logger, packagePath, packagePath); - if (topLevelEntryPoint !== null) { - entryPoints.push(topLevelEntryPoint); + + // If there is no primary entry-point then exit + if (topLevelEntryPoint === null) { + return []; } - // Now search all the directories of this package for possible entry points + // Otherwise store it and search for secondary entry-points + entryPoints.push(topLevelEntryPoint); this.walkDirectory(packagePath, subdir => { const subEntryPoint = getEntryPointInfo(this.fs, this.logger, packagePath, subdir); if (subEntryPoint !== null) { diff --git a/packages/compiler-cli/ngcc/test/packages/entry_point_finder_spec.ts b/packages/compiler-cli/ngcc/test/packages/entry_point_finder_spec.ts index 5f7dc3ae74..bb524f9bfc 100644 --- a/packages/compiler-cli/ngcc/test/packages/entry_point_finder_spec.ts +++ b/packages/compiler-cli/ngcc/test/packages/entry_point_finder_spec.ts @@ -52,6 +52,21 @@ describe('findEntryPoints()', () => { ]); }); + it('should find entry-points via `pathMappings', () => { + const {entryPoints} = finder.findEntryPoints( + _('/pathMappings/node_modules'), undefined, + {baseUrl: _('/pathMappings'), paths: {'my-lib': ['dist/my-lib']}}); + const entryPointPaths = entryPoints.map(x => [x.package, x.path]); + expect(entryPointPaths).toEqual([ + [_('/pathMappings/dist/my-lib'), _('/pathMappings/dist/my-lib')], + [_('/pathMappings/dist/my-lib'), _('/pathMappings/dist/my-lib/sub-lib')], + [ + _('/pathMappings/node_modules/@angular/common'), + _('/pathMappings/node_modules/@angular/common') + ], + ]); + }); + it('should return an empty array if there are no packages', () => { const {entryPoints} = finder.findEntryPoints(_('/no_packages')); expect(entryPoints).toEqual([]); @@ -105,6 +120,26 @@ describe('findEntryPoints()', () => { }, }, }, + '/pathMappings': { + 'dist': { + 'my-lib': { + 'package.json': createPackageJson('my-lib'), + 'my-lib.metadata.json': 'metadata info', + 'sub-lib': { + 'package.json': createPackageJson('sub-lib'), + 'sub-lib.metadata.json': 'metadata info', + }, + }, + }, + 'node_modules': { + '@angular': { + 'common': { + 'package.json': createPackageJson('common'), + 'common.metadata.json': 'metadata info', + }, + }, + } + }, '/namespaced': { '@angular': { 'common': {