fix(compiler-cli): ensure ngcc can handle wildcard base-paths (#41033)
Ngcc uses the `paths` property to compute the potential base-paths for packages that are being processed. If the `paths` contain a wildcard `*` within a path segment, ngcc was not finding the base-path correctly. Now when a wildcard is found, there is an additional search to look for paths that might match the wildcard. Fixes #41014 PR Close #41033
This commit is contained in:
parent
e12d9dec64
commit
0b69fabcf5
|
@ -5,7 +5,7 @@
|
||||||
* Use of this source code is governed by an MIT-style license that can be
|
* 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
|
* found in the LICENSE file at https://angular.io/license
|
||||||
*/
|
*/
|
||||||
import {AbsoluteFsPath, getFileSystem, PathManipulation} from '../../../src/ngtsc/file_system';
|
import {AbsoluteFsPath, getFileSystem, PathManipulation, ReadonlyFileSystem} from '../../../src/ngtsc/file_system';
|
||||||
import {Logger} from '../../../src/ngtsc/logging';
|
import {Logger} from '../../../src/ngtsc/logging';
|
||||||
import {PathMappings} from '../path_mappings';
|
import {PathMappings} from '../path_mappings';
|
||||||
|
|
||||||
|
@ -41,21 +41,52 @@ export function getBasePaths(
|
||||||
`This is likely to mess up how ngcc finds entry-points and is probably not correct.\n` +
|
`This is likely to mess up how ngcc finds entry-points and is probably not correct.\n` +
|
||||||
`Please check your path mappings configuration such as in the tsconfig.json file.`);
|
`Please check your path mappings configuration such as in the tsconfig.json file.`);
|
||||||
}
|
}
|
||||||
Object.values(pathMappings.paths).forEach(paths => paths.forEach(path => {
|
for (const paths of Object.values(pathMappings.paths)) {
|
||||||
// We only want base paths that exist and are not files
|
for (const path of paths) {
|
||||||
let basePath = fs.resolve(baseUrl, extractPathPrefix(path));
|
let foundMatch = false;
|
||||||
if (fs.exists(basePath) && fs.stat(basePath).isFile()) {
|
|
||||||
basePath = fs.dirname(basePath);
|
// We only want base paths that exist and are not files
|
||||||
|
const {prefix, hasWildcard} = extractPathPrefix(path);
|
||||||
|
let basePath = fs.resolve(baseUrl, prefix);
|
||||||
|
if (fs.exists(basePath) && fs.stat(basePath).isFile()) {
|
||||||
|
basePath = fs.dirname(basePath);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fs.exists(basePath)) {
|
||||||
|
// The `basePath` is itself a directory
|
||||||
|
basePaths.push(basePath);
|
||||||
|
foundMatch = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hasWildcard) {
|
||||||
|
// The path contains a wildcard (`*`) so also try searching for directories that start
|
||||||
|
// with the wildcard prefix path segment.
|
||||||
|
const wildcardContainer = fs.dirname(basePath);
|
||||||
|
const wildcardPrefix = fs.basename(basePath);
|
||||||
|
if (isExistingDirectory(fs, wildcardContainer)) {
|
||||||
|
const candidates = fs.readdir(wildcardContainer);
|
||||||
|
for (const candidate of candidates) {
|
||||||
|
if (candidate.startsWith(wildcardPrefix)) {
|
||||||
|
const candidatePath = fs.resolve(wildcardContainer, candidate);
|
||||||
|
if (isExistingDirectory(fs, candidatePath)) {
|
||||||
|
foundMatch = true;
|
||||||
|
basePaths.push(candidatePath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!foundMatch) {
|
||||||
|
// We neither found a direct match (i.e. `basePath` is an existing directory) nor a
|
||||||
|
// directory that starts with a wildcard prefix.
|
||||||
|
logger.debug(
|
||||||
|
`The basePath "${basePath}" computed from baseUrl "${baseUrl}" and path mapping "${
|
||||||
|
path}" does not exist in the file-system.\n` +
|
||||||
|
`It will not be scanned for entry-points.`);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (fs.exists(basePath)) {
|
}
|
||||||
basePaths.push(basePath);
|
|
||||||
} else {
|
|
||||||
logger.debug(
|
|
||||||
`The basePath "${basePath}" computed from baseUrl "${baseUrl}" and path mapping "${
|
|
||||||
path}" does not exist in the file-system.\n` +
|
|
||||||
`It will not be scanned for entry-points.`);
|
|
||||||
}
|
|
||||||
}));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const dedupedBasePaths = dedupePaths(fs, basePaths);
|
const dedupedBasePaths = dedupePaths(fs, basePaths);
|
||||||
|
@ -70,13 +101,18 @@ export function getBasePaths(
|
||||||
return dedupedBasePaths;
|
return dedupedBasePaths;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function isExistingDirectory(fs: ReadonlyFileSystem, path: AbsoluteFsPath): boolean {
|
||||||
|
return fs.exists(path) && fs.stat(path).isDirectory();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Extract everything in the `path` up to the first `*`.
|
* Extract everything in the `path` up to the first `*`.
|
||||||
* @param path The path to parse.
|
* @param path The path to parse.
|
||||||
* @returns The extracted prefix.
|
* @returns The extracted prefix and a flag to indicate whether there was a wildcard `*`.
|
||||||
*/
|
*/
|
||||||
function extractPathPrefix(path: string) {
|
function extractPathPrefix(path: string): {prefix: string, hasWildcard: boolean} {
|
||||||
return path.split('*', 1)[0];
|
const [prefix, rest] = path.split('*', 2);
|
||||||
|
return {prefix, hasWildcard: rest !== undefined};
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -48,6 +48,24 @@ runInEachFileSystem(() => {
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should find base-paths that start with a wildcard prefix', () => {
|
||||||
|
const projectDirectory = _('/path/to/project');
|
||||||
|
const fs = getFileSystem();
|
||||||
|
fs.ensureDir(fs.resolve(projectDirectory, 'dist'));
|
||||||
|
fs.ensureDir(fs.resolve(projectDirectory, 'dist-a'));
|
||||||
|
fs.ensureDir(fs.resolve(projectDirectory, 'dist-b'));
|
||||||
|
|
||||||
|
const sourceDirectory = _('/path/to/project/node_modules');
|
||||||
|
const pathMappings = {baseUrl: projectDirectory, paths: {'@dist*': ['dist*']}};
|
||||||
|
const basePaths = getBasePaths(logger, sourceDirectory, pathMappings);
|
||||||
|
expect(basePaths).toEqual([
|
||||||
|
sourceDirectory,
|
||||||
|
fs.resolve(projectDirectory, 'dist'),
|
||||||
|
fs.resolve(projectDirectory, 'dist-a'),
|
||||||
|
fs.resolve(projectDirectory, 'dist-b'),
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
it('should not be confused by folders that have the same starting string', () => {
|
it('should not be confused by folders that have the same starting string', () => {
|
||||||
const projectDirectory = _('/path/to/project');
|
const projectDirectory = _('/path/to/project');
|
||||||
const fs = getFileSystem();
|
const fs = getFileSystem();
|
||||||
|
|
Loading…
Reference in New Issue