angular/packages/compiler-cli/ngcc/src/entry_point_finder/utils.ts
Pete Bacon Darwin 207f9b6017 fix(ivy): ngcc - handle pathMappings to files rather then directories (#30525)
Paths can be mapped directly to files, which was not being taken
into account when computing `basePaths` for the `EntryPointFinder`s.

Now if a `pathMapping` pattern does not exist or is a file, then we try
the containing folder instead.

Fixes #31424

PR Close #30525
2019-07-09 09:40:46 -07:00

71 lines
2.5 KiB
TypeScript

/**
* @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, getFileSystem, 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 fs = getFileSystem();
let basePaths = [sourceDirectory];
if (pathMappings) {
const baseUrl = resolve(pathMappings.baseUrl);
Object.values(pathMappings.paths).forEach(paths => paths.forEach(path => {
// We only want base paths that exist and are not files
let basePath = join(baseUrl, extractPathPrefix(path));
while (basePath !== baseUrl && (!fs.exists(basePath) || fs.stat(basePath).isFile())) {
basePath = fs.dirname(basePath);
}
basePaths.push(basePath);
}));
}
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;
}