From a581773887eaf872f484e4a6469ad1a6068d8305 Mon Sep 17 00:00:00 2001 From: Pete Bacon Darwin Date: Thu, 16 May 2019 08:53:19 +0100 Subject: [PATCH] perf(ivy): ngcc - only find dependencies when targeting a single entry-point (#30525) Previously, ngcc had to walk the entire `node_modules` tree looking for entry-points, even if it only needed to process a single target entry-point and its dependencies. This added up to a few seconds to each execution of ngcc, which is noticeable when being run via the CLI integration. Now, if an entry-point target is provided, only that target and its entry-points are considered rather than the whole folder tree. PR Close #30525 --- .../src/dependencies/dependency_resolver.ts | 20 +- .../directory_walker_entry_point_finder.ts} | 96 ++------ .../ngcc/src/entry_point_finder/interface.ts | 15 ++ .../targeted_entry_point_finder.ts | 123 ++++++++++ .../ngcc/src/entry_point_finder/utils.ts | 65 ++++++ packages/compiler-cli/ngcc/src/main.ts | 91 +++++--- ...irectory_walker_entry_point_finder_spec.ts | 196 ++++++++++++++++ .../targeted_entry_point_finder_spec.ts | 201 +++++++++++++++++ .../test/packages/entry_point_finder_spec.ts | 212 ------------------ packages/compiler-cli/tsconfig-build.json | 3 +- packages/compiler-cli/tsconfig.json | 3 +- packages/tsconfig.json | 2 +- 12 files changed, 693 insertions(+), 334 deletions(-) rename packages/compiler-cli/ngcc/src/{packages/entry_point_finder.ts => entry_point_finder/directory_walker_entry_point_finder.ts} (61%) create mode 100644 packages/compiler-cli/ngcc/src/entry_point_finder/interface.ts create mode 100644 packages/compiler-cli/ngcc/src/entry_point_finder/targeted_entry_point_finder.ts create mode 100644 packages/compiler-cli/ngcc/src/entry_point_finder/utils.ts create mode 100644 packages/compiler-cli/ngcc/test/entry_point_finder/directory_walker_entry_point_finder_spec.ts create mode 100644 packages/compiler-cli/ngcc/test/entry_point_finder/targeted_entry_point_finder_spec.ts delete mode 100644 packages/compiler-cli/ngcc/test/packages/entry_point_finder_spec.ts diff --git a/packages/compiler-cli/ngcc/src/dependencies/dependency_resolver.ts b/packages/compiler-cli/ngcc/src/dependencies/dependency_resolver.ts index 7db4692260..02d4a26013 100644 --- a/packages/compiler-cli/ngcc/src/dependencies/dependency_resolver.ts +++ b/packages/compiler-cli/ngcc/src/dependencies/dependency_resolver.ts @@ -10,7 +10,7 @@ import {DepGraph} from 'dependency-graph'; import {AbsoluteFsPath, FileSystem, resolve} from '../../../src/ngtsc/file_system'; import {Logger} from '../logging/logger'; import {EntryPoint, EntryPointFormat, EntryPointJsonProperty, getEntryPointFormat} from '../packages/entry_point'; -import {DependencyHost} from './dependency_host'; +import {DependencyHost, DependencyInfo} from './dependency_host'; /** * Holds information about entry points that are removed because @@ -98,6 +98,16 @@ export class DependencyResolver { }; } + getEntryPointDependencies(entryPoint: EntryPoint): DependencyInfo { + const formatInfo = this.getEntryPointFormatInfo(entryPoint); + const host = this.hosts[formatInfo.format]; + if (!host) { + throw new Error( + `Could not find a suitable format for computing dependencies of entry-point: '${entryPoint.path}'.`); + } + return host.findDependencies(formatInfo.path); + } + /** * Computes a dependency graph of the given entry-points. * @@ -116,13 +126,7 @@ export class DependencyResolver { // Now add the dependencies between them angularEntryPoints.forEach(entryPoint => { - const formatInfo = this.getEntryPointFormatInfo(entryPoint); - const host = this.hosts[formatInfo.format]; - if (!host) { - throw new Error( - `Could not find a suitable format for computing dependencies of entry-point: '${entryPoint.path}'.`); - } - const {dependencies, missing, deepImports} = host.findDependencies(formatInfo.path); + const {dependencies, missing, deepImports} = this.getEntryPointDependencies(entryPoint); if (missing.size > 0) { // This entry point has dependencies that are missing diff --git a/packages/compiler-cli/ngcc/src/packages/entry_point_finder.ts b/packages/compiler-cli/ngcc/src/entry_point_finder/directory_walker_entry_point_finder.ts similarity index 61% rename from packages/compiler-cli/ngcc/src/packages/entry_point_finder.ts rename to packages/compiler-cli/ngcc/src/entry_point_finder/directory_walker_entry_point_finder.ts index 9cb618f83b..90470ae843 100644 --- a/packages/compiler-cli/ngcc/src/packages/entry_point_finder.ts +++ b/packages/compiler-cli/ngcc/src/entry_point_finder/directory_walker_entry_point_finder.ts @@ -8,61 +8,31 @@ import {AbsoluteFsPath, FileSystem, join, resolve} from '../../../src/ngtsc/file_system'; import {DependencyResolver, SortedEntryPointsInfo} from '../dependencies/dependency_resolver'; import {Logger} from '../logging/logger'; +import {NgccConfiguration} from '../packages/configuration'; +import {EntryPoint, getEntryPointInfo} from '../packages/entry_point'; import {PathMappings} from '../utils'; -import {NgccConfiguration} from './configuration'; -import {EntryPoint, getEntryPointInfo} from './entry_point'; +import {EntryPointFinder} from './interface'; +import {getBasePaths} from './utils'; -export class EntryPointFinder { +/** + * An EntryPointFinder that searches for all entry-points that can be found given a `basePath` and + * `pathMappings`. + */ +export class DirectoryWalkerEntryPointFinder implements EntryPointFinder { + private basePaths = getBasePaths(this.sourceDirectory, this.pathMappings); constructor( private fs: FileSystem, private config: NgccConfiguration, private logger: Logger, - private resolver: DependencyResolver) {} + private resolver: DependencyResolver, private sourceDirectory: AbsoluteFsPath, + private pathMappings: PathMappings|undefined) {} /** - * Search the given directory, and sub-directories, for Angular package entry points. - * @param sourceDirectory An absolute path to the directory to search for entry points. + * Search the `sourceDirectory`, and sub-directories, using `pathMappings` as necessary, to find + * all package entry-points. */ - findEntryPoints( - sourceDirectory: AbsoluteFsPath, targetEntryPointPath?: AbsoluteFsPath, - pathMappings?: PathMappings): SortedEntryPointsInfo { - const basePaths = this.getBasePaths(sourceDirectory, pathMappings); - const unsortedEntryPoints = basePaths.reduce( + findEntryPoints(): SortedEntryPointsInfo { + const unsortedEntryPoints = this.basePaths.reduce( (entryPoints, basePath) => entryPoints.concat(this.walkDirectoryForEntryPoints(basePath)), []); - const targetEntryPoint = targetEntryPointPath ? - unsortedEntryPoints.find(entryPoint => entryPoint.path === targetEntryPointPath) : - undefined; - return this.resolver.sortEntryPointsByDependency(unsortedEntryPoints, targetEntryPoint); - } - - /** - * Extract all the base-paths that we need to search for entry-points. - * - * This always contains the standard base-path (`sourceDirectory`). - * But it also parses the `paths` mappings object to guess additional base-paths. - * - * For example: - * - * ``` - * getBasePaths('/node_modules', {baseUrl: '/dist', paths: {'*': ['lib/*', 'lib/generated/*']}}) - * > ['/node_modules', '/dist/lib'] - * ``` - * - * Notice that `'/dist'` is not included as there is no `'*'` path, - * and `'/dist/lib/generated'` is not included as it is covered by `'/dist/lib'`. - * - * @param sourceDirectory The standard base-path (e.g. node_modules). - * @param pathMappings Path mapping configuration, from which to extract additional base-paths. - */ - private getBasePaths(sourceDirectory: AbsoluteFsPath, pathMappings?: PathMappings): - AbsoluteFsPath[] { - const basePaths = [sourceDirectory]; - if (pathMappings) { - const baseUrl = resolve(pathMappings.baseUrl); - values(pathMappings.paths).forEach(paths => paths.forEach(path => { - basePaths.push(join(baseUrl, extractPathPrefix(path))); - })); - } - basePaths.sort(); // Get the paths in order with the shorter ones first. - return basePaths.filter(removeDeeperPaths); + return this.resolver.sortEntryPointsByDependency(unsortedEntryPoints); } /** @@ -168,38 +138,6 @@ export class EntryPointFinder { } } -/** - * Extract everything in the `path` up to the first `*`. - * @param path The path to parse. - * @returns The extracted prefix. - */ -function extractPathPrefix(path: string) { - return path.split('*', 1)[0]; -} - -/** - * A filter function that removes paths that are already covered by higher paths. - * - * @param value The current path. - * @param index The index of the current path. - * @param array The array of paths (sorted alphabetically). - * @returns true if this path is not already covered by a previous path. - */ -function removeDeeperPaths(value: AbsoluteFsPath, index: number, array: AbsoluteFsPath[]) { - for (let i = 0; i < index; i++) { - if (value.startsWith(array[i])) return false; - } - return true; -} - -/** - * Extract all the values (not keys) from an object. - * @param obj The object to process. - */ -function values(obj: {[key: string]: T}): T[] { - return Object.keys(obj).map(key => obj[key]); -} - function stripJsExtension(filePath: T): T { return filePath.replace(/\.js$/, '') as T; } diff --git a/packages/compiler-cli/ngcc/src/entry_point_finder/interface.ts b/packages/compiler-cli/ngcc/src/entry_point_finder/interface.ts new file mode 100644 index 0000000000..3887774930 --- /dev/null +++ b/packages/compiler-cli/ngcc/src/entry_point_finder/interface.ts @@ -0,0 +1,15 @@ +/** + * @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 {SortedEntryPointsInfo} from '../dependencies/dependency_resolver'; + +export interface EntryPointFinder { + /** + * Search for Angular package entry-points. + */ + findEntryPoints(): SortedEntryPointsInfo; +} 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 new file mode 100644 index 0000000000..4aaaa150a3 --- /dev/null +++ b/packages/compiler-cli/ngcc/src/entry_point_finder/targeted_entry_point_finder.ts @@ -0,0 +1,123 @@ +/** + * @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 {AbsoluteFsPath, FileSystem, PathSegment, join, relative, relativeFrom} from '../../../src/ngtsc/file_system'; +import {DependencyResolver, SortedEntryPointsInfo} from '../dependencies/dependency_resolver'; +import {Logger} from '../logging/logger'; +import {NgccConfiguration} from '../packages/configuration'; +import {EntryPoint, getEntryPointInfo} from '../packages/entry_point'; +import {PathMappings} from '../utils'; +import {EntryPointFinder} from './interface'; +import {getBasePaths} from './utils'; + +/** + * An EntryPointFinder that starts from a target entry-point and only finds + * entry-points that are dependencies of the target. + * + * This is faster than searching the entire file-system for all the entry-points, + * and is used primarily by the CLI integration. + */ +export class TargetedEntryPointFinder implements EntryPointFinder { + private unprocessedPaths: AbsoluteFsPath[] = []; + private unsortedEntryPoints = new Map(); + private basePaths = getBasePaths(this.basePath, this.pathMappings); + + constructor( + private fs: FileSystem, private config: NgccConfiguration, private logger: Logger, + private resolver: DependencyResolver, private basePath: AbsoluteFsPath, + private targetPath: AbsoluteFsPath, private pathMappings: PathMappings|undefined) {} + + findEntryPoints(): SortedEntryPointsInfo { + this.unprocessedPaths = [this.targetPath]; + while (this.unprocessedPaths.length > 0) { + this.processNextPath(); + } + const targetEntryPoint = this.unsortedEntryPoints.get(this.targetPath); + return this.resolver.sortEntryPointsByDependency( + Array.from(this.unsortedEntryPoints.values()), targetEntryPoint); + } + + private processNextPath(): void { + const path = this.unprocessedPaths.shift() !; + const entryPoint = this.getEntryPoint(path); + if (entryPoint !== null) { + this.unsortedEntryPoints.set(entryPoint.path, entryPoint); + const deps = this.resolver.getEntryPointDependencies(entryPoint); + deps.dependencies.forEach(dep => { + if (!this.unsortedEntryPoints.has(dep)) { + this.unprocessedPaths.push(dep); + } + }); + } + } + + private getEntryPoint(entryPointPath: AbsoluteFsPath): EntryPoint|null { + const packagePath = this.computePackagePath(entryPointPath); + return getEntryPointInfo(this.fs, this.config, this.logger, packagePath, entryPointPath); + } + + /** + * Search down to the `entryPointPath` from each `basePath` for the first `package.json` that we + * come to. This is the path to the entry-point's containing package. For example if `basePath` is + * `/a/b/c` and `entryPointPath` is `/a/b/c/d/e` and there exists `/a/b/c/d/package.json` and + * `/a/b/c/d/e/package.json`, then we will return `/a/b/c/d`. + * + * To account for nested `node_modules` we actually start the search at the last `node_modules` in + * the `entryPointPath` that is below the `basePath`. E.g. if `basePath` is `/a/b/c` and + * `entryPointPath` is `/a/b/c/d/node_modules/x/y/z`, we start the search at + * `/a/b/c/d/node_modules`. + */ + private computePackagePath(entryPointPath: AbsoluteFsPath): AbsoluteFsPath { + for (const basePath of this.basePaths) { + if (entryPointPath.startsWith(basePath)) { + let packagePath = basePath; + const segments = this.splitPath(relative(basePath, entryPointPath)); + + // Start the search at the last nested `node_modules` folder if the relative + // `entryPointPath` contains one or more. + let nodeModulesIndex = segments.lastIndexOf(relativeFrom('node_modules')); + while (nodeModulesIndex >= 0) { + packagePath = join(packagePath, segments.shift() !); + nodeModulesIndex--; + } + + // Note that we skip the first `packagePath` and start looking from the first folder below + // it because that will be the `node_modules` folder. + for (const segment of segments) { + packagePath = join(packagePath, segment); + if (this.fs.exists(join(packagePath, 'package.json'))) { + return packagePath; + } + } + + // If we got here then we couldn't find a `packagePath` for the current `basePath` but since + // `basePath`s are guaranteed not to be a sub-directory each other then no other `basePath` + // will match either. + break; + } + } + // If we get here then none of the `basePaths` matched the `entryPointPath`, which + // is somewhat unexpected and means that this entry-point lives completely outside + // any of the `basePaths`. + // All we can do is assume that his entry-point is a primary entry-point to a package. + return entryPointPath; + } + + + /** + * Split the given `path` into path segments using an FS independent algorithm. + * @param path The path to split. + */ + private splitPath(path: PathSegment) { + const segments = []; + while (path !== '.') { + segments.unshift(this.fs.basename(path)); + path = this.fs.dirname(path); + } + return segments; + } +} diff --git a/packages/compiler-cli/ngcc/src/entry_point_finder/utils.ts b/packages/compiler-cli/ngcc/src/entry_point_finder/utils.ts new file mode 100644 index 0000000000..601d5c7721 --- /dev/null +++ b/packages/compiler-cli/ngcc/src/entry_point_finder/utils.ts @@ -0,0 +1,65 @@ +/** + * @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 {AbsoluteFsPath, join, resolve} from '../../../src/ngtsc/file_system'; +import {PathMappings} from '../utils'; + +/** + * Extract all the base-paths that we need to search for entry-points. + * + * This always contains the standard base-path (`sourceDirectory`). + * But it also parses the `paths` mappings object to guess additional base-paths. + * + * For example: + * + * ``` + * getBasePaths('/node_modules', {baseUrl: '/dist', paths: {'*': ['lib/*', 'lib/generated/*']}}) + * > ['/node_modules', '/dist/lib'] + * ``` + * + * Notice that `'/dist'` is not included as there is no `'*'` path, + * and `'/dist/lib/generated'` is not included as it is covered by `'/dist/lib'`. + * + * @param sourceDirectory The standard base-path (e.g. node_modules). + * @param pathMappings Path mapping configuration, from which to extract additional base-paths. + */ +export function getBasePaths( + sourceDirectory: AbsoluteFsPath, pathMappings: PathMappings | undefined): AbsoluteFsPath[] { + const basePaths = [sourceDirectory]; + if (pathMappings) { + const baseUrl = resolve(pathMappings.baseUrl); + Object.values(pathMappings.paths).forEach(paths => paths.forEach(path => { + basePaths.push(join(baseUrl, extractPathPrefix(path))); + })); + } + basePaths.sort(); // Get the paths in order with the shorter ones first. + return basePaths.filter(removeDeeperPaths); +} + +/** + * Extract everything in the `path` up to the first `*`. + * @param path The path to parse. + * @returns The extracted prefix. + */ +function extractPathPrefix(path: string) { + return path.split('*', 1)[0]; +} + +/** + * A filter function that removes paths that are already covered by higher paths. + * + * @param value The current path. + * @param index The index of the current path. + * @param array The array of paths (sorted alphabetically). + * @returns true if this path is not already covered by a previous path. + */ +function removeDeeperPaths(value: AbsoluteFsPath, index: number, array: AbsoluteFsPath[]) { + for (let i = 0; i < index; i++) { + if (value.startsWith(array[i])) return false; + } + return true; +} diff --git a/packages/compiler-cli/ngcc/src/main.ts b/packages/compiler-cli/ngcc/src/main.ts index 4d0087895c..47130e0dce 100644 --- a/packages/compiler-cli/ngcc/src/main.ts +++ b/packages/compiler-cli/ngcc/src/main.ts @@ -7,17 +7,18 @@ */ import {AbsoluteFsPath, FileSystem, absoluteFrom, dirname, getFileSystem, resolve} from '../../src/ngtsc/file_system'; import {CommonJsDependencyHost} from './dependencies/commonjs_dependency_host'; -import {DependencyResolver} from './dependencies/dependency_resolver'; +import {DependencyResolver, InvalidEntryPoint, SortedEntryPointsInfo} from './dependencies/dependency_resolver'; 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 {TargetedEntryPointFinder} from './entry_point_finder/targeted_entry_point_finder'; import {ConsoleLogger, LogLevel} from './logging/console_logger'; import {Logger} from './logging/logger'; import {hasBeenProcessed, markAsProcessed} from './packages/build_marker'; import {NgccConfiguration} from './packages/configuration'; -import {EntryPointFormat, EntryPointJsonProperty, SUPPORTED_FORMAT_PROPERTIES, getEntryPointFormat} from './packages/entry_point'; +import {EntryPoint, EntryPointFormat, EntryPointJsonProperty, SUPPORTED_FORMAT_PROPERTIES, getEntryPointFormat} from './packages/entry_point'; import {makeEntryPointBundle} from './packages/entry_point_bundle'; -import {EntryPointFinder} from './packages/entry_point_finder'; import {Transformer} from './packages/transformer'; import {PathMappings} from './utils'; import {FileWriter} from './writing/file_writer'; @@ -93,36 +94,12 @@ export function mainNgcc( umd: umdDependencyHost, commonjs: commonJsDependencyHost }); - const config = new NgccConfiguration(fileSystem, dirname(absoluteFrom(basePath))); - const finder = new EntryPointFinder(fileSystem, config, logger, resolver); + const absBasePath = absoluteFrom(basePath); + const config = new NgccConfiguration(fileSystem, dirname(absBasePath)); const fileWriter = getFileWriter(fileSystem, createNewEntryPointFormats); - - const absoluteTargetEntryPointPath = - targetEntryPointPath ? resolve(basePath, targetEntryPointPath) : undefined; - - if (absoluteTargetEntryPointPath && - hasProcessedTargetEntryPoint( - fileSystem, absoluteTargetEntryPointPath, propertiesToConsider, compileAllFormats)) { - logger.debug('The target entry-point has already been processed'); - return; - } - - const {entryPoints, invalidEntryPoints} = - finder.findEntryPoints(absoluteFrom(basePath), absoluteTargetEntryPointPath, pathMappings); - - invalidEntryPoints.forEach(invalidEntryPoint => { - logger.debug( - `Invalid entry-point ${invalidEntryPoint.entryPoint.path}.`, - `It is missing required dependencies:\n` + - invalidEntryPoint.missingDependencies.map(dep => ` - ${dep}`).join('\n')); - }); - - if (absoluteTargetEntryPointPath && entryPoints.length === 0) { - markNonAngularPackageAsProcessed( - fileSystem, absoluteTargetEntryPointPath, propertiesToConsider); - return; - } - + const entryPoints = getEntryPoints( + fileSystem, config, logger, resolver, absBasePath, targetEntryPointPath, pathMappings, + propertiesToConsider, compileAllFormats); for (const entryPoint of entryPoints) { // Are we compiling the Angular core? const isCore = entryPoint.name === '@angular/core'; @@ -188,6 +165,47 @@ function getFileWriter(fs: FileSystem, createNewEntryPointFormats: boolean): Fil return createNewEntryPointFormats ? new NewEntryPointFileWriter(fs) : new InPlaceFileWriter(fs); } +function getEntryPoints( + fs: FileSystem, config: NgccConfiguration, logger: Logger, resolver: DependencyResolver, + basePath: AbsoluteFsPath, targetEntryPointPath: string | undefined, + pathMappings: PathMappings | undefined, propertiesToConsider: string[], + compileAllFormats: boolean): EntryPoint[] { + const {entryPoints, invalidEntryPoints} = (targetEntryPointPath !== undefined) ? + getTargetedEntryPoints( + fs, config, logger, resolver, basePath, targetEntryPointPath, propertiesToConsider, + compileAllFormats, pathMappings) : + getAllEntryPoints(fs, config, logger, resolver, basePath, pathMappings); + logInvalidEntryPoints(logger, invalidEntryPoints); + return entryPoints; +} + +function getTargetedEntryPoints( + fs: FileSystem, config: NgccConfiguration, logger: Logger, resolver: DependencyResolver, + basePath: AbsoluteFsPath, targetEntryPointPath: string, propertiesToConsider: string[], + compileAllFormats: boolean, pathMappings: PathMappings | undefined): SortedEntryPointsInfo { + const absoluteTargetEntryPointPath = resolve(basePath, targetEntryPointPath); + if (hasProcessedTargetEntryPoint( + fs, absoluteTargetEntryPointPath, propertiesToConsider, compileAllFormats)) { + logger.debug('The target entry-point has already been processed'); + return {entryPoints: [], invalidEntryPoints: [], ignoredDependencies: []}; + } + const finder = new TargetedEntryPointFinder( + fs, config, logger, resolver, basePath, absoluteTargetEntryPointPath, pathMappings); + const entryPointInfo = finder.findEntryPoints(); + if (entryPointInfo.entryPoints.length === 0) { + markNonAngularPackageAsProcessed(fs, absoluteTargetEntryPointPath, propertiesToConsider); + } + 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) { @@ -233,3 +251,12 @@ function markNonAngularPackageAsProcessed( markAsProcessed(fs, packageJson, packageJsonPath, formatProperty as EntryPointJsonProperty); }); } + +function logInvalidEntryPoints(logger: Logger, invalidEntryPoints: InvalidEntryPoint[]): void { + invalidEntryPoints.forEach(invalidEntryPoint => { + logger.debug( + `Invalid entry-point ${invalidEntryPoint.entryPoint.path}.`, + `It is missing required dependencies:\n` + + invalidEntryPoint.missingDependencies.map(dep => ` - ${dep}`).join('\n')); + }); +} diff --git a/packages/compiler-cli/ngcc/test/entry_point_finder/directory_walker_entry_point_finder_spec.ts b/packages/compiler-cli/ngcc/test/entry_point_finder/directory_walker_entry_point_finder_spec.ts new file mode 100644 index 0000000000..7e58681923 --- /dev/null +++ b/packages/compiler-cli/ngcc/test/entry_point_finder/directory_walker_entry_point_finder_spec.ts @@ -0,0 +1,196 @@ +/** + * @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 {AbsoluteFsPath, FileSystem, absoluteFrom, getFileSystem, relative} from '../../../src/ngtsc/file_system'; +import {TestFile, runInEachFileSystem} from '../../../src/ngtsc/file_system/testing'; +import {loadTestFiles} from '../../../test/helpers'; +import {DependencyResolver} from '../../src/dependencies/dependency_resolver'; +import {EsmDependencyHost} from '../../src/dependencies/esm_dependency_host'; +import {ModuleResolver} from '../../src/dependencies/module_resolver'; +import {DirectoryWalkerEntryPointFinder} from '../../src/entry_point_finder/directory_walker_entry_point_finder'; +import {NgccConfiguration} from '../../src/packages/configuration'; +import {EntryPoint} from '../../src/packages/entry_point'; +import {PathMappings} from '../../src/utils'; +import {MockLogger} from '../helpers/mock_logger'; + +runInEachFileSystem(() => { + describe('DirectoryWalkerEntryPointFinder', () => { + let fs: FileSystem; + let resolver: DependencyResolver; + let logger: MockLogger; + let config: NgccConfiguration; + let _Abs: typeof absoluteFrom; + + beforeEach(() => { + fs = getFileSystem(); + _Abs = absoluteFrom; + logger = new MockLogger(); + resolver = new DependencyResolver( + fs, logger, {esm2015: new EsmDependencyHost(fs, new ModuleResolver(fs))}); + config = new NgccConfiguration(fs, _Abs('/')); + }); + + describe('findEntryPoints()', () => { + it('should find sub-entry-points within a package', () => { + const basePath = _Abs('/sub_entry_points/node_modules'); + loadTestFiles([ + ...createPackage(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 DirectoryWalkerEntryPointFinder(fs, config, logger, resolver, basePath, undefined); + const {entryPoints} = finder.findEntryPoints(); + expect(dumpEntryPointPaths(basePath, entryPoints)).toEqual([ + ['common', 'common'], + ['common', 'common/http'], + ['common', 'common/testing'], + ['common', 'common/http/testing'], + ]); + }); + + it('should find packages inside a namespace', () => { + const basePath = _Abs('/namespaced/node_modules'); + loadTestFiles([ + ...createPackage(fs.resolve(basePath, '@angular'), 'common'), + ...createPackage(fs.resolve(basePath, '@angular/common'), 'http', ['@angular/common']), + ...createPackage( + fs.resolve(basePath, '@angular/common/http'), 'testing', + ['@angular/common/http', '@angular/common/testing']), + ...createPackage(fs.resolve(basePath, '@angular/common'), 'testing', ['@angular/common']), + ]); + const finder = + new DirectoryWalkerEntryPointFinder(fs, config, logger, resolver, basePath, undefined); + const {entryPoints} = finder.findEntryPoints(); + expect(dumpEntryPointPaths(basePath, entryPoints)).toEqual([ + ['@angular/common', '@angular/common'], + ['@angular/common', '@angular/common/http'], + ['@angular/common', '@angular/common/testing'], + ['@angular/common', '@angular/common/http/testing'], + ]); + }); + + it('should return an empty array if there are no packages', () => { + fs.ensureDir(_Abs('/no_packages/node_modules/should_not_be_found')); + const finder = new DirectoryWalkerEntryPointFinder( + fs, config, logger, resolver, _Abs('/no_packages/node_modules'), undefined); + const {entryPoints} = finder.findEntryPoints(); + expect(entryPoints).toEqual([]); + }); + + it('should return an empty array if there are no valid entry-points', () => { + loadTestFiles([ + { + name: _Abs('/no_valid_entry_points/node_modules/some_package/package.json'), + contents: '{}' + }, + ]); + const finder = new DirectoryWalkerEntryPointFinder( + fs, config, logger, resolver, _Abs('/no_valid_entry_points/node_modules'), undefined); + const {entryPoints} = finder.findEntryPoints(); + expect(entryPoints).toEqual([]); + }); + + it('should ignore folders starting with .', () => { + loadTestFiles([ + ...createPackage(_Abs('/dotted_folders/node_modules/'), '.common'), + ]); + const finder = new DirectoryWalkerEntryPointFinder( + fs, config, logger, resolver, _Abs('/dotted_folders/node_modules'), undefined); + const {entryPoints} = finder.findEntryPoints(); + expect(entryPoints).toEqual([]); + }); + + it('should ignore folders that are symlinked', () => { + fs.ensureDir(_Abs('/symlinked_folders/node_modules')); + fs.symlink( + _Abs('/external/node_modules/common'), _Abs('/symlinked_folders/node_modules/common')); + loadTestFiles(createPackage(_Abs('/external/node_modules'), 'common')); + const finder = new DirectoryWalkerEntryPointFinder( + fs, config, logger, resolver, _Abs('/symlinked_folders/node_modules'), undefined); + const {entryPoints} = finder.findEntryPoints(); + expect(entryPoints).toEqual([]); + }); + + it('should handle nested node_modules folders', () => { + loadTestFiles([ + ...createPackage(_Abs('/nested_node_modules/node_modules'), 'outer', ['inner']), + ...createPackage(_Abs('/nested_node_modules/node_modules/outer/node_modules'), 'inner'), + ]); + const finder = new DirectoryWalkerEntryPointFinder( + fs, config, logger, resolver, _Abs('/nested_node_modules/node_modules'), undefined); + const {entryPoints} = finder.findEntryPoints(); + // Note that the `inner` entry-point is not part of the `outer` package + expect(dumpEntryPointPaths(_Abs('/nested_node_modules/node_modules'), entryPoints)) + .toEqual([ + ['outer/node_modules/inner', 'outer/node_modules/inner'], + ['outer', 'outer'], + ]); + }); + + + it('should handle dependencies via pathMappings', () => { + const basePath = _Abs('/path_mapped/node_modules'); + const pathMappings: PathMappings = { + baseUrl: '/path_mapped/dist', + paths: { + '@x/*': ['*'], + '@y/*/test': ['lib/*/test'], + } + }; + loadTestFiles([ + ...createPackage( + _Abs('/path_mapped/node_modules'), 'test', ['pkg1', '@x/pkg2', '@y/pkg3/test']), + ...createPackage(_Abs('/path_mapped/node_modules'), 'pkg1'), + ...createPackage(_Abs('/path_mapped/dist'), 'pkg2', ['pkg4']), + ...createPackage(_Abs('/path_mapped/dist/pkg2/node_modules'), 'pkg4'), + ...createPackage(_Abs('/path_mapped/dist/lib/pkg3'), 'test'), + ]); + resolver = new DependencyResolver( + fs, logger, {esm2015: new EsmDependencyHost(fs, new ModuleResolver(fs, pathMappings))}); + const finder = new DirectoryWalkerEntryPointFinder( + fs, config, logger, resolver, basePath, pathMappings); + const {entryPoints} = finder.findEntryPoints(); + expect(dumpEntryPointPaths(basePath, entryPoints)).toEqual([ + ['pkg1', 'pkg1'], + ['../dist/pkg2/node_modules/pkg4', '../dist/pkg2/node_modules/pkg4'], + ['../dist/pkg2', '../dist/pkg2'], + ['../dist/lib/pkg3/test', '../dist/lib/pkg3/test'], + ['test', 'test'], + ]); + }); + + 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)]); + } + }); + }); +}); \ No newline at end of file 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 new file mode 100644 index 0000000000..496fae8dc2 --- /dev/null +++ b/packages/compiler-cli/ngcc/test/entry_point_finder/targeted_entry_point_finder_spec.ts @@ -0,0 +1,201 @@ +/** + * @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 {AbsoluteFsPath, FileSystem, absoluteFrom, getFileSystem, relative} from '../../../src/ngtsc/file_system'; +import {TestFile, runInEachFileSystem} from '../../../src/ngtsc/file_system/testing'; +import {loadTestFiles} from '../../../test/helpers'; +import {DependencyResolver} from '../../src/dependencies/dependency_resolver'; +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 {NgccConfiguration} from '../../src/packages/configuration'; +import {EntryPoint} from '../../src/packages/entry_point'; +import {PathMappings} from '../../src/utils'; +import {MockLogger} from '../helpers/mock_logger'; + +runInEachFileSystem(() => { + describe('TargetedEntryPointFinder', () => { + let fs: FileSystem; + let resolver: DependencyResolver; + let logger: MockLogger; + let config: NgccConfiguration; + let _Abs: typeof absoluteFrom; + + beforeEach(() => { + fs = getFileSystem(); + _Abs = absoluteFrom; + logger = new MockLogger(); + resolver = new DependencyResolver( + fs, logger, {esm2015: new EsmDependencyHost(fs, new ModuleResolver(fs))}); + config = new NgccConfiguration(fs, _Abs('/')); + }); + + describe('findEntryPoints()', () => { + it('should find a single entry-point with no dependencies', () => { + const basePath = _Abs('/sub_entry_points/node_modules'); + const targetPath = _Abs('/sub_entry_points/node_modules/common'); + loadTestFiles([ + ...createPackage(fs.resolve(basePath, ''), 'common'), + ...createPackage(fs.resolve(basePath, 'common'), 'http', ['@angular/common']), + ...createPackage( + fs.resolve(basePath, 'common/http'), 'testing', + ['@angular/common/http', '@angular/common/testing']), + ...createPackage(fs.resolve(basePath, 'common'), 'testing', ['@angular/common']), + ]); + const finder = new TargetedEntryPointFinder( + fs, config, logger, resolver, _Abs('/sub_entry_points/node_modules'), targetPath, + undefined); + const {entryPoints} = finder.findEntryPoints(); + expect(dumpEntryPointPaths(basePath, entryPoints)).toEqual([ + ['common', 'common'], + ]); + }); + + it('should find dependencies of secondary entry-points within a package', () => { + 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, _Abs('/sub_entry_points/node_modules'), targetPath, + undefined); + const {entryPoints} = finder.findEntryPoints(); + expect(dumpEntryPointPaths(basePath, entryPoints)).toEqual([ + ['common', 'common'], + ['common', 'common/http'], + ['common', 'common/testing'], + ['common', 'common/http/testing'], + ]); + }); + + it('should find dependencies inside a namespace', () => { + const basePath = _Abs('/namespaced/node_modules'); + const targetPath = _Abs('/namespaced/node_modules/@angular/common/http'); + loadTestFiles([ + ...createPackage(fs.resolve(basePath, '@angular'), 'common'), + ...createPackage(fs.resolve(basePath, '@angular/common'), 'http', ['@angular/common']), + ...createPackage( + fs.resolve(basePath, '@angular/common/http'), 'testing', + ['@angular/common/http', '@angular/common/testing']), + ...createPackage(fs.resolve(basePath, '@angular/common'), 'testing', ['@angular/common']), + ]); + const finder = new TargetedEntryPointFinder( + fs, config, logger, resolver, _Abs('/namespaced/node_modules'), targetPath, undefined); + const {entryPoints} = finder.findEntryPoints(); + expect(dumpEntryPointPaths(basePath, entryPoints)).toEqual([ + ['@angular/common', '@angular/common'], + ['@angular/common', '@angular/common/http'], + ]); + }); + + it('should return an empty array if the target path is not an entry-point', () => { + const targetPath = _Abs('/no_packages/node_modules/should_not_be_found'); + fs.ensureDir(_Abs('/no_packages/node_modules/should_not_be_found')); + const finder = new TargetedEntryPointFinder( + fs, config, logger, resolver, _Abs('/no_packages/node_modules'), targetPath, undefined); + const {entryPoints} = finder.findEntryPoints(); + expect(entryPoints).toEqual([]); + }); + + it('should return an empty array if the target path is not an Angular 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); + const {entryPoints} = finder.findEntryPoints(); + expect(entryPoints).toEqual([]); + }); + + it('should handle nested node_modules folders', () => { + const targetPath = _Abs('/nested_node_modules/node_modules/outer'); + loadTestFiles([ + ...createPackage(_Abs('/nested_node_modules/node_modules'), 'outer', ['inner']), + ...createPackage(_Abs('/nested_node_modules/node_modules/outer/node_modules'), 'inner'), + ]); + const finder = new TargetedEntryPointFinder( + fs, config, logger, resolver, _Abs('/nested_node_modules/node_modules'), targetPath, + undefined); + const {entryPoints} = finder.findEntryPoints(); + expect(dumpEntryPointPaths(_Abs('/nested_node_modules/node_modules'), entryPoints)) + .toEqual([ + ['outer/node_modules/inner', 'outer/node_modules/inner'], + ['outer', 'outer'], + ]); + }); + + it('should handle dependencies via pathMappings', () => { + const basePath = _Abs('/path_mapped/node_modules'); + const targetPath = _Abs('/path_mapped/node_modules/test'); + const pathMappings: PathMappings = { + baseUrl: '/path_mapped/dist', + paths: { + '@x/*': ['*'], + '@y/*/test': ['lib/*/test'], + } + }; + loadTestFiles([ + ...createPackage( + _Abs('/path_mapped/node_modules'), 'test', ['pkg1', '@x/pkg2', '@y/pkg3/test']), + ...createPackage(_Abs('/path_mapped/node_modules'), 'pkg1'), + ...createPackage(_Abs('/path_mapped/dist'), 'pkg2', ['pkg4']), + ...createPackage(_Abs('/path_mapped/dist/pkg2/node_modules'), 'pkg4'), + ...createPackage(_Abs('/path_mapped/dist/lib/pkg3'), 'test'), + ]); + resolver = new DependencyResolver( + fs, logger, {esm2015: new EsmDependencyHost(fs, new ModuleResolver(fs, pathMappings))}); + const finder = new TargetedEntryPointFinder( + fs, config, logger, resolver, basePath, targetPath, pathMappings); + const {entryPoints} = finder.findEntryPoints(); + expect(dumpEntryPointPaths(basePath, entryPoints)).toEqual([ + ['pkg1', 'pkg1'], + ['../dist/pkg2/node_modules/pkg4', '../dist/pkg2/node_modules/pkg4'], + ['../dist/pkg2', '../dist/pkg2'], + ['../dist/lib/pkg3/test', '../dist/lib/pkg3/test'], + ['test', 'test'], + ]); + }); + + 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)]); + } + + }); + }); +}); \ No newline at end of file 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 deleted file mode 100644 index ca86e41d8e..0000000000 --- a/packages/compiler-cli/ngcc/test/packages/entry_point_finder_spec.ts +++ /dev/null @@ -1,212 +0,0 @@ -/** - * @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 {absoluteFrom, getFileSystem} from '../../../src/ngtsc/file_system'; -import {runInEachFileSystem} from '../../../src/ngtsc/file_system/testing'; -import {loadTestFiles} from '../../../test/helpers'; -import {DependencyResolver} from '../../src/dependencies/dependency_resolver'; -import {EsmDependencyHost} from '../../src/dependencies/esm_dependency_host'; -import {ModuleResolver} from '../../src/dependencies/module_resolver'; -import {NgccConfiguration} from '../../src/packages/configuration'; -import {EntryPoint} from '../../src/packages/entry_point'; -import {EntryPointFinder} from '../../src/packages/entry_point_finder'; -import {MockLogger} from '../helpers/mock_logger'; - -runInEachFileSystem(() => { - - describe('findEntryPoints()', () => { - let resolver: DependencyResolver; - let finder: EntryPointFinder; - let _: typeof absoluteFrom; - - beforeEach(() => { - const fs = getFileSystem(); - _ = absoluteFrom; - setupMockFileSystem(); - resolver = new DependencyResolver( - fs, new MockLogger(), {esm2015: new EsmDependencyHost(fs, new ModuleResolver(fs))}); - spyOn(resolver, 'sortEntryPointsByDependency').and.callFake((entryPoints: EntryPoint[]) => { - return {entryPoints, ignoredEntryPoints: [], ignoredDependencies: []}; - }); - finder = - new EntryPointFinder(fs, new NgccConfiguration(fs, _('/')), new MockLogger(), resolver); - }); - - it('should find sub-entry-points within a package', () => { - const {entryPoints} = finder.findEntryPoints(_('/sub_entry_points')); - const entryPointPaths = entryPoints.map(x => [x.package, x.path]); - expect(entryPointPaths).toEqual([ - [_('/sub_entry_points/common'), _('/sub_entry_points/common')], - [_('/sub_entry_points/common'), _('/sub_entry_points/common/http')], - [_('/sub_entry_points/common'), _('/sub_entry_points/common/http/testing')], - [_('/sub_entry_points/common'), _('/sub_entry_points/common/testing')], - ]); - }); - - it('should find packages inside a namespace', () => { - const {entryPoints} = finder.findEntryPoints(_('/namespaced')); - const entryPointPaths = entryPoints.map(x => [x.package, x.path]); - expect(entryPointPaths).toEqual([ - [_('/namespaced/@angular/common'), _('/namespaced/@angular/common')], - [_('/namespaced/@angular/common'), _('/namespaced/@angular/common/http')], - [_('/namespaced/@angular/common'), _('/namespaced/@angular/common/http/testing')], - [_('/namespaced/@angular/common'), _('/namespaced/@angular/common/testing')], - ]); - }); - - 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([]); - }); - - it('should return an empty array if there are no valid entry-points', () => { - const {entryPoints} = finder.findEntryPoints(_('/no_valid_entry_points')); - expect(entryPoints).toEqual([]); - }); - - it('should ignore folders starting with .', () => { - const {entryPoints} = finder.findEntryPoints(_('/dotted_folders')); - expect(entryPoints).toEqual([]); - }); - - it('should ignore folders that are symlinked', () => { - const {entryPoints} = finder.findEntryPoints(_('/symlinked_folders')); - expect(entryPoints).toEqual([]); - }); - - it('should handle nested node_modules folders', () => { - const {entryPoints} = finder.findEntryPoints(_('/nested_node_modules')); - const entryPointPaths = entryPoints.map(x => [x.package, x.path]); - expect(entryPointPaths).toEqual([ - [_('/nested_node_modules/outer'), _('/nested_node_modules/outer')], - // Note that the inner entry point does not get included as part of the outer package - [ - _('/nested_node_modules/outer/node_modules/inner'), - _('/nested_node_modules/outer/node_modules/inner'), - ], - ]); - }); - - function setupMockFileSystem(): void { - loadTestFiles([ - {name: _('/sub_entry_points/common/package.json'), contents: createPackageJson('common')}, - {name: _('/sub_entry_points/common/common.metadata.json'), contents: 'metadata info'}, - { - name: _('/sub_entry_points/common/http/package.json'), - contents: createPackageJson('http') - }, - {name: _('/sub_entry_points/common/http/http.metadata.json'), contents: 'metadata info'}, - { - name: _('/sub_entry_points/common/http/testing/package.json'), - contents: createPackageJson('testing') - }, - { - name: _('/sub_entry_points/common/http/testing/testing.metadata.json'), - contents: 'metadata info' - }, - { - name: _('/sub_entry_points/common/testing/package.json'), - contents: createPackageJson('testing') - }, - { - name: _('/sub_entry_points/common/testing/testing.metadata.json'), - contents: 'metadata info' - }, - {name: _('/pathMappings/dist/my-lib/package.json'), contents: createPackageJson('my-lib')}, - {name: _('/pathMappings/dist/my-lib/my-lib.metadata.json'), contents: 'metadata info'}, - { - name: _('/pathMappings/dist/my-lib/sub-lib/package.json'), - contents: createPackageJson('sub-lib') - }, - { - name: _('/pathMappings/dist/my-lib/sub-lib/sub-lib.metadata.json'), - contents: 'metadata info' - }, - { - name: _('/pathMappings/node_modules/@angular/common/package.json'), - contents: createPackageJson('common') - }, - { - name: _('/pathMappings/node_modules/@angular/common/common.metadata.json'), - contents: 'metadata info' - }, - { - name: _('/namespaced/@angular/common/package.json'), - contents: createPackageJson('common') - }, - {name: _('/namespaced/@angular/common/common.metadata.json'), contents: 'metadata info'}, - { - name: _('/namespaced/@angular/common/http/package.json'), - contents: createPackageJson('http') - }, - {name: _('/namespaced/@angular/common/http/http.metadata.json'), contents: 'metadata info'}, - { - name: _('/namespaced/@angular/common/http/testing/package.json'), - contents: createPackageJson('testing') - }, - { - name: _('/namespaced/@angular/common/http/testing/testing.metadata.json'), - contents: 'metadata info' - }, - { - name: _('/namespaced/@angular/common/testing/package.json'), - contents: createPackageJson('testing') - }, - { - name: _('/namespaced/@angular/common/testing/testing.metadata.json'), - contents: 'metadata info' - }, - {name: _('/no_valid_entry_points/some_package/package.json'), contents: '{}'}, - {name: _('/dotted_folders/.common/package.json'), contents: createPackageJson('common')}, - {name: _('/dotted_folders/.common/common.metadata.json'), contents: 'metadata info'}, - {name: _('/nested_node_modules/outer/package.json'), contents: createPackageJson('outer')}, - {name: _('/nested_node_modules/outer/outer.metadata.json'), contents: 'metadata info'}, - { - name: _('/nested_node_modules/outer/node_modules/inner/package.json'), - contents: createPackageJson('inner') - }, - { - name: _('/nested_node_modules/outer/node_modules/inner/inner.metadata.json'), - contents: 'metadata info' - }, - ]); - const fs = getFileSystem(); - - fs.ensureDir(_('/no_packages/should_not_be_found')); - - fs.ensureDir(_('/symlinked_folders')); - fs.symlink(_('/sub_entry_points/common'), _('/symlinked_folders/common')); - } - }); - - function createPackageJson(packageName: string): string { - const packageJson: any = { - typings: `./${packageName}.d.ts`, - fesm2015: `./fesm2015/${packageName}.js`, - esm2015: `./esm2015/${packageName}.js`, - fesm5: `./fesm2015/${packageName}.js`, - esm5: `./esm2015/${packageName}.js`, - main: `./bundles/${packageName}.umd.js`, - }; - return JSON.stringify(packageJson); - } -}); diff --git a/packages/compiler-cli/tsconfig-build.json b/packages/compiler-cli/tsconfig-build.json index 22956fc745..c213db5f3e 100644 --- a/packages/compiler-cli/tsconfig-build.json +++ b/packages/compiler-cli/tsconfig-build.json @@ -6,7 +6,8 @@ "stripInternal": false, "target": "es2015", "lib": [ - "es2015" + "es2015", + "es2017.object", ], "baseUrl": ".", "rootDir": ".", diff --git a/packages/compiler-cli/tsconfig.json b/packages/compiler-cli/tsconfig.json index 953e52219f..11bddca28b 100644 --- a/packages/compiler-cli/tsconfig.json +++ b/packages/compiler-cli/tsconfig.json @@ -3,7 +3,8 @@ "compilerOptions": { "target": "es2015", "lib": [ - "es2015" + "es2015", + "es2017.object", ], "strict": true, "types": [ diff --git a/packages/tsconfig.json b/packages/tsconfig.json index 367aa9f7e9..516d3ee95a 100644 --- a/packages/tsconfig.json +++ b/packages/tsconfig.json @@ -19,7 +19,7 @@ }, "rootDir": ".", "inlineSourceMap": true, - "lib": ["es5", "dom", "es2015.promise", "es2015.collection", "es2015.iterable", "es2015.core"], + "lib": ["es5", "dom", "es2015.promise", "es2015.collection", "es2015.iterable", "es2015.core", "es2017.object"], "skipDefaultLibCheck": true, "skipLibCheck": true, "target": "es5",