feat(ngcc): support version ranges in project/default configurations (#33008)
By appending a version range to the package name, it is now possible to target configuration to specific versions of a package. PR Close #33008
This commit is contained in:
parent
916762440c
commit
90007e97ca
|
@ -61,6 +61,7 @@
|
|||
"@types/minimist": "^1.2.0",
|
||||
"@types/node": "^10.9.4",
|
||||
"@types/selenium-webdriver": "3.0.7",
|
||||
"@types/semver": "^6.0.2",
|
||||
"@types/shelljs": "^0.7.8",
|
||||
"@types/systemjs": "0.19.32",
|
||||
"@types/yargs": "^11.1.1",
|
||||
|
@ -159,7 +160,7 @@
|
|||
"mutation-observer": "^1.0.3",
|
||||
"rewire": "2.5.2",
|
||||
"sauce-connect": "https://saucelabs.com/downloads/sc-4.5.1-linux.tar.gz",
|
||||
"semver": "5.4.1",
|
||||
"semver": "^6.3.0",
|
||||
"tslint-eslint-rules": "4.1.1",
|
||||
"tslint-no-toplevel-property-access": "0.0.2",
|
||||
"tsutils": "2.27.2",
|
||||
|
|
|
@ -27,10 +27,12 @@ ts_library(
|
|||
"//packages/compiler-cli/src/ngtsc/util",
|
||||
"@npm//@types/convert-source-map",
|
||||
"@npm//@types/node",
|
||||
"@npm//@types/semver",
|
||||
"@npm//@types/yargs",
|
||||
"@npm//canonical-path",
|
||||
"@npm//dependency-graph",
|
||||
"@npm//magic-string",
|
||||
"@npm//semver",
|
||||
"@npm//source-map",
|
||||
"@npm//typescript",
|
||||
],
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
* 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 {satisfies} from 'semver';
|
||||
import * as vm from 'vm';
|
||||
import {AbsoluteFsPath, FileSystem, dirname, join, resolve} from '../../../src/ngtsc/file_system';
|
||||
import {PackageJsonFormatPropertiesMap} from './entry_point';
|
||||
|
@ -12,7 +13,7 @@ import {PackageJsonFormatPropertiesMap} from './entry_point';
|
|||
/**
|
||||
* The format of a project level configuration file.
|
||||
*/
|
||||
export interface NgccProjectConfig { packages: {[packagePath: string]: NgccPackageConfig}; }
|
||||
export interface NgccProjectConfig<T = NgccPackageConfig> { packages: {[packagePath: string]: T}; }
|
||||
|
||||
/**
|
||||
* The format of a package level configuration file.
|
||||
|
@ -80,47 +81,96 @@ export const DEFAULT_NGCC_CONFIG: NgccProjectConfig = {
|
|||
}
|
||||
};
|
||||
|
||||
interface VersionedPackageConfig extends NgccPackageConfig {
|
||||
versionRange: string;
|
||||
}
|
||||
|
||||
const NGCC_CONFIG_FILENAME = 'ngcc.config.js';
|
||||
|
||||
/**
|
||||
* Ngcc has a hierarchical configuration system that lets us "fix up" packages that do not
|
||||
* work with ngcc out of the box.
|
||||
*
|
||||
* There are three levels at which configuration can be declared:
|
||||
*
|
||||
* * Default level - ngcc comes with built-in configuration for well known cases.
|
||||
* * Package level - a library author publishes a configuration with their package to fix known
|
||||
* issues.
|
||||
* * Project level - the application developer provides a configuration that fixes issues specific
|
||||
* to the libraries used in their application.
|
||||
*
|
||||
* Ngcc will match configuration based on the package name but also on its version. This allows
|
||||
* configuration to provide different fixes to different version ranges of a package.
|
||||
*
|
||||
* * Package level configuration is specific to the package version where the configuration is
|
||||
* found.
|
||||
* * Default and project level configuration should provide version ranges to ensure that the
|
||||
* configuration is only applied to the appropriate versions of a package.
|
||||
*
|
||||
* When getting a configuration for a package (via `getConfig()`) the caller should provide the
|
||||
* version of the package in question, if available. If it is not provided then the first available
|
||||
* configuration for a package is returned.
|
||||
*/
|
||||
export class NgccConfiguration {
|
||||
private defaultConfig: NgccProjectConfig;
|
||||
private cache = new Map<string, NgccPackageConfig>();
|
||||
private defaultConfig: NgccProjectConfig<VersionedPackageConfig[]>;
|
||||
private projectConfig: NgccProjectConfig<VersionedPackageConfig[]>;
|
||||
private cache = new Map<string, VersionedPackageConfig>();
|
||||
|
||||
constructor(private fs: FileSystem, baseDir: AbsoluteFsPath) {
|
||||
this.defaultConfig = this.processDefaultConfig(baseDir);
|
||||
const projectConfig = this.loadProjectConfig(baseDir);
|
||||
for (const packagePath in projectConfig.packages) {
|
||||
const absPackagePath = resolve(baseDir, 'node_modules', packagePath);
|
||||
const packageConfig = projectConfig.packages[packagePath];
|
||||
packageConfig.entryPoints =
|
||||
this.processEntryPoints(absPackagePath, packageConfig.entryPoints);
|
||||
this.cache.set(absPackagePath, packageConfig);
|
||||
}
|
||||
this.defaultConfig = this.processProjectConfig(baseDir, DEFAULT_NGCC_CONFIG);
|
||||
this.projectConfig = this.processProjectConfig(baseDir, this.loadProjectConfig(baseDir));
|
||||
}
|
||||
|
||||
getConfig(packagePath: AbsoluteFsPath): NgccPackageConfig {
|
||||
if (this.cache.has(packagePath)) {
|
||||
return this.cache.get(packagePath) !;
|
||||
/**
|
||||
* Get a configuration for the given `version` of a package at `packagePath`.
|
||||
*
|
||||
* @param packagePath The path to the package whose config we want.
|
||||
* @param version The version of the package whose config we want, or `null` if the package's
|
||||
* package.json did not exist or was invalid.
|
||||
*/
|
||||
getConfig(packagePath: AbsoluteFsPath, version: string|null): VersionedPackageConfig {
|
||||
const cacheKey = packagePath + (version !== null ? `@${version}` : '');
|
||||
if (this.cache.has(cacheKey)) {
|
||||
return this.cache.get(cacheKey) !;
|
||||
}
|
||||
|
||||
const packageConfig = this.loadPackageConfig(packagePath) ||
|
||||
this.defaultConfig.packages[packagePath] || {entryPoints: {}};
|
||||
this.cache.set(packagePath, packageConfig);
|
||||
return packageConfig;
|
||||
const projectLevelConfig =
|
||||
findSatisfactoryVersion(this.projectConfig.packages[packagePath], version);
|
||||
if (projectLevelConfig !== null) {
|
||||
this.cache.set(cacheKey, projectLevelConfig);
|
||||
return projectLevelConfig;
|
||||
}
|
||||
|
||||
const packageLevelConfig = this.loadPackageConfig(packagePath, version);
|
||||
if (packageLevelConfig !== null) {
|
||||
this.cache.set(cacheKey, packageLevelConfig);
|
||||
return packageLevelConfig;
|
||||
}
|
||||
|
||||
const defaultLevelConfig =
|
||||
findSatisfactoryVersion(this.defaultConfig.packages[packagePath], version);
|
||||
if (defaultLevelConfig !== null) {
|
||||
this.cache.set(cacheKey, defaultLevelConfig);
|
||||
return defaultLevelConfig;
|
||||
}
|
||||
|
||||
return {versionRange: '*', entryPoints: {}};
|
||||
}
|
||||
|
||||
private processDefaultConfig(baseDir: AbsoluteFsPath): NgccProjectConfig {
|
||||
const defaultConfig: NgccProjectConfig = {packages: {}};
|
||||
for (const packagePath in DEFAULT_NGCC_CONFIG.packages) {
|
||||
const absPackagePath = resolve(baseDir, 'node_modules', packagePath);
|
||||
const packageConfig = DEFAULT_NGCC_CONFIG.packages[packagePath];
|
||||
private processProjectConfig(baseDir: AbsoluteFsPath, projectConfig: NgccProjectConfig):
|
||||
NgccProjectConfig<VersionedPackageConfig[]> {
|
||||
const processedConfig: NgccProjectConfig<VersionedPackageConfig[]> = {packages: {}};
|
||||
for (const packagePathAndVersion in projectConfig.packages) {
|
||||
const packageConfig = projectConfig.packages[packagePathAndVersion];
|
||||
if (packageConfig) {
|
||||
packageConfig.entryPoints =
|
||||
this.processEntryPoints(absPackagePath, packageConfig.entryPoints);
|
||||
defaultConfig.packages[absPackagePath] = packageConfig;
|
||||
const [packagePath, versionRange = '*'] = this.splitPathAndVersion(packagePathAndVersion);
|
||||
const absPackagePath = resolve(baseDir, 'node_modules', packagePath);
|
||||
const entryPoints = this.processEntryPoints(absPackagePath, packageConfig);
|
||||
processedConfig.packages[absPackagePath] = processedConfig.packages[absPackagePath] || [];
|
||||
processedConfig.packages[absPackagePath].push({versionRange, entryPoints});
|
||||
}
|
||||
}
|
||||
return defaultConfig;
|
||||
return processedConfig;
|
||||
}
|
||||
|
||||
private loadProjectConfig(baseDir: AbsoluteFsPath): NgccProjectConfig {
|
||||
|
@ -136,13 +186,15 @@ export class NgccConfiguration {
|
|||
}
|
||||
}
|
||||
|
||||
private loadPackageConfig(packagePath: AbsoluteFsPath): NgccPackageConfig|null {
|
||||
private loadPackageConfig(packagePath: AbsoluteFsPath, version: string|null):
|
||||
VersionedPackageConfig|null {
|
||||
const configFilePath = join(packagePath, NGCC_CONFIG_FILENAME);
|
||||
if (this.fs.exists(configFilePath)) {
|
||||
try {
|
||||
const packageConfig = this.evalSrcFile(configFilePath);
|
||||
packageConfig.entryPoints = this.processEntryPoints(packagePath, packageConfig.entryPoints);
|
||||
return packageConfig;
|
||||
return {
|
||||
versionRange: version || '*',
|
||||
entryPoints: this.processEntryPoints(packagePath, this.evalSrcFile(configFilePath)),
|
||||
};
|
||||
} catch (e) {
|
||||
throw new Error(`Invalid package configuration file at "${configFilePath}": ` + e.message);
|
||||
}
|
||||
|
@ -164,14 +216,41 @@ export class NgccConfiguration {
|
|||
return sandbox.module.exports;
|
||||
}
|
||||
|
||||
private processEntryPoints(
|
||||
packagePath: AbsoluteFsPath, entryPoints: {[entryPointPath: string]: NgccEntryPointConfig;}):
|
||||
private processEntryPoints(packagePath: AbsoluteFsPath, packageConfig: NgccPackageConfig):
|
||||
{[entryPointPath: string]: NgccEntryPointConfig;} {
|
||||
const processedEntryPoints: {[entryPointPath: string]: NgccEntryPointConfig;} = {};
|
||||
for (const entryPointPath in entryPoints) {
|
||||
for (const entryPointPath in packageConfig.entryPoints) {
|
||||
// Change the keys to be absolute paths
|
||||
processedEntryPoints[resolve(packagePath, entryPointPath)] = entryPoints[entryPointPath];
|
||||
processedEntryPoints[resolve(packagePath, entryPointPath)] =
|
||||
packageConfig.entryPoints[entryPointPath];
|
||||
}
|
||||
return processedEntryPoints;
|
||||
}
|
||||
|
||||
private splitPathAndVersion(packagePathAndVersion: string): [string, string|undefined] {
|
||||
const versionIndex = packagePathAndVersion.lastIndexOf('@');
|
||||
// Note that > 0 is because we don't want to match @ at the start of the line
|
||||
// which is what you would have with a namespaced package, e.g. `@angular/common`.
|
||||
return versionIndex > 0 ?
|
||||
[
|
||||
packagePathAndVersion.substring(0, versionIndex),
|
||||
packagePathAndVersion.substring(versionIndex + 1)
|
||||
] :
|
||||
[packagePathAndVersion, undefined];
|
||||
}
|
||||
}
|
||||
|
||||
function findSatisfactoryVersion(
|
||||
configs: VersionedPackageConfig[] | undefined, version: string | null): VersionedPackageConfig|
|
||||
null {
|
||||
if (configs === undefined) {
|
||||
return null;
|
||||
}
|
||||
if (version === null) {
|
||||
// The package has no version (!) - perhaps the entry-point was from a deep import, which made
|
||||
// it impossible to find the package.json.
|
||||
// So just return the first config that matches the package name.
|
||||
return configs[0];
|
||||
}
|
||||
return configs.find(config => satisfies(version, config.versionRange)) || null;
|
||||
}
|
||||
|
|
|
@ -82,7 +82,9 @@ export function getEntryPointInfo(
|
|||
fs: FileSystem, config: NgccConfiguration, logger: Logger, packagePath: AbsoluteFsPath,
|
||||
entryPointPath: AbsoluteFsPath): EntryPoint|null {
|
||||
const packageJsonPath = resolve(entryPointPath, 'package.json');
|
||||
const entryPointConfig = config.getConfig(packagePath).entryPoints[entryPointPath];
|
||||
const packageVersion = getPackageVersion(fs, packageJsonPath);
|
||||
const entryPointConfig =
|
||||
config.getConfig(packagePath, packageVersion).entryPoints[entryPointPath];
|
||||
if (entryPointConfig === undefined && !fs.exists(packageJsonPath)) {
|
||||
return null;
|
||||
}
|
||||
|
@ -224,3 +226,20 @@ function guessTypingsFromPackageJson(
|
|||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the version of the package at `packageJsonPath`.
|
||||
*
|
||||
* @returns the version string or `null` if the package.json does not exist or is invalid.
|
||||
*/
|
||||
function getPackageVersion(fs: FileSystem, packageJsonPath: AbsoluteFsPath): string|null {
|
||||
try {
|
||||
if (fs.exists(packageJsonPath)) {
|
||||
const packageJson = JSON.parse(fs.readFile(packageJsonPath));
|
||||
return packageJson['version'] || null;
|
||||
}
|
||||
} catch {
|
||||
// Do nothing
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
|
|
@ -32,49 +32,47 @@ runInEachFileSystem(() => {
|
|||
|
||||
describe('getConfig()', () => {
|
||||
describe('at the package level', () => {
|
||||
it('should return configuration for a package found in a package level file', () => {
|
||||
loadTestFiles([{
|
||||
name: _Abs('/project-1/node_modules/package-1/ngcc.config.js'),
|
||||
contents: `module.exports = {entryPoints: { './entry-point-1': {}}}`
|
||||
}]);
|
||||
const readFileSpy = spyOn(fs, 'readFile').and.callThrough();
|
||||
const configuration = new NgccConfiguration(fs, _Abs('/project-1'));
|
||||
const config = configuration.getConfig(_Abs('/project-1/node_modules/package-1'));
|
||||
it('should return configuration for a package found in a package level file, with a matching version',
|
||||
() => {
|
||||
loadTestFiles(packageWithConfigFiles('package-1', 'entry-point-1', '1.0.0'));
|
||||
const readFileSpy = spyOn(fs, 'readFile').and.callThrough();
|
||||
const configuration = new NgccConfiguration(fs, _Abs('/project-1'));
|
||||
const config =
|
||||
configuration.getConfig(_Abs('/project-1/node_modules/package-1'), '1.0.0');
|
||||
|
||||
expect(config).toEqual(
|
||||
{entryPoints: {[_Abs('/project-1/node_modules/package-1/entry-point-1')]: {}}});
|
||||
expect(readFileSpy)
|
||||
.toHaveBeenCalledWith(_Abs('/project-1/node_modules/package-1/ngcc.config.js'));
|
||||
});
|
||||
expect(config).toEqual({
|
||||
versionRange: '1.0.0',
|
||||
entryPoints: {[_Abs('/project-1/node_modules/package-1/entry-point-1')]: {}}
|
||||
});
|
||||
expect(readFileSpy)
|
||||
.toHaveBeenCalledWith(_Abs('/project-1/node_modules/package-1/ngcc.config.js'));
|
||||
});
|
||||
|
||||
it('should used cached configuration for a package if available', () => {
|
||||
loadTestFiles([{
|
||||
name: _Abs('/project-1/node_modules/package-1/ngcc.config.js'),
|
||||
contents: `
|
||||
module.exports = {
|
||||
entryPoints: {
|
||||
'./entry-point-1': {}
|
||||
},
|
||||
};`
|
||||
}]);
|
||||
loadTestFiles(packageWithConfigFiles('package-1', 'entry-point-1', '1.0.0'));
|
||||
const configuration = new NgccConfiguration(fs, _Abs('/project-1'));
|
||||
|
||||
// Populate the cache
|
||||
configuration.getConfig(_Abs('/project-1/node_modules/package-1'));
|
||||
configuration.getConfig(_Abs('/project-1/node_modules/package-1'), '1.0.0');
|
||||
|
||||
const readFileSpy = spyOn(fs, 'readFile').and.callThrough();
|
||||
const config = configuration.getConfig(_Abs('/project-1/node_modules/package-1'));
|
||||
const config =
|
||||
configuration.getConfig(_Abs('/project-1/node_modules/package-1'), '1.0.0');
|
||||
|
||||
expect(config).toEqual(
|
||||
{entryPoints: {[_Abs('/project-1/node_modules/package-1/entry-point-1')]: {}}});
|
||||
expect(config).toEqual({
|
||||
versionRange: '1.0.0',
|
||||
entryPoints: {[_Abs('/project-1/node_modules/package-1/entry-point-1')]: {}}
|
||||
});
|
||||
expect(readFileSpy).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should return an empty configuration object if there is no matching configuration for the package',
|
||||
() => {
|
||||
loadTestFiles(packageWithConfigFiles('package-2', 'entry-point-1', '1.0.0'));
|
||||
const configuration = new NgccConfiguration(fs, _Abs('/project-1'));
|
||||
const config = configuration.getConfig(_Abs('/project-1/node_modules/package-1'));
|
||||
expect(config).toEqual({entryPoints: {}});
|
||||
const config =
|
||||
configuration.getConfig(_Abs('/project-1/node_modules/package-1'), '1.0.0');
|
||||
expect(config).toEqual({versionRange: '*', entryPoints: {}});
|
||||
});
|
||||
|
||||
it('should error if a package level config file is badly formatted', () => {
|
||||
|
@ -83,7 +81,7 @@ runInEachFileSystem(() => {
|
|||
contents: `bad js code`
|
||||
}]);
|
||||
const configuration = new NgccConfiguration(fs, _Abs('/project-1'));
|
||||
expect(() => configuration.getConfig(_Abs('/project-1/node_modules/package-1')))
|
||||
expect(() => configuration.getConfig(_Abs('/project-1/node_modules/package-1'), '1.0.0'))
|
||||
.toThrowError(
|
||||
`Invalid package configuration file at "${_Abs('/project-1/node_modules/package-1/ngcc.config.js')}": Unexpected identifier`);
|
||||
});
|
||||
|
@ -94,65 +92,125 @@ runInEachFileSystem(() => {
|
|||
loadTestFiles([{
|
||||
name: _Abs('/project-1/ngcc.config.js'),
|
||||
contents: `
|
||||
module.exports = {
|
||||
packages: {
|
||||
'package-1': {
|
||||
entryPoints: {
|
||||
'./entry-point-1': {}
|
||||
module.exports = {
|
||||
packages: {
|
||||
'package-1': {
|
||||
entryPoints: {
|
||||
'./entry-point-1': {}
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
};`
|
||||
};`
|
||||
}]);
|
||||
const readFileSpy = spyOn(fs, 'readFile').and.callThrough();
|
||||
const configuration = new NgccConfiguration(fs, _Abs('/project-1'));
|
||||
expect(readFileSpy).toHaveBeenCalledWith(_Abs('/project-1/ngcc.config.js'));
|
||||
|
||||
const config = configuration.getConfig(_Abs('/project-1/node_modules/package-1'));
|
||||
expect(config).toEqual(
|
||||
{entryPoints: {[_Abs('/project-1/node_modules/package-1/entry-point-1')]: {}}});
|
||||
const config =
|
||||
configuration.getConfig(_Abs('/project-1/node_modules/package-1'), '1.0.0');
|
||||
expect(config).toEqual({
|
||||
versionRange: '*',
|
||||
entryPoints: {[_Abs('/project-1/node_modules/package-1/entry-point-1')]: {}}
|
||||
});
|
||||
});
|
||||
|
||||
it('should return configuration for the correct version of a package found in a project level file',
|
||||
() => {
|
||||
loadTestFiles([{
|
||||
name: _Abs('/project-1/ngcc.config.js'),
|
||||
contents: `
|
||||
module.exports = {
|
||||
packages: {
|
||||
'package-1@1.0.0': {
|
||||
entryPoints: {
|
||||
'./entry-point-1': {}
|
||||
},
|
||||
},
|
||||
'package-1@2.*': {
|
||||
entryPoints: {
|
||||
'./entry-point-2': {}
|
||||
},
|
||||
},
|
||||
'package-1@^3.2.0': {
|
||||
entryPoints: {
|
||||
'./entry-point-3': {}
|
||||
},
|
||||
},
|
||||
},
|
||||
};`
|
||||
}]);
|
||||
const configuration = new NgccConfiguration(fs, _Abs('/project-1'));
|
||||
|
||||
expect(configuration.getConfig(_Abs('/project-1/node_modules/package-1'), '1.0.0'))
|
||||
.toEqual({
|
||||
versionRange: '1.0.0',
|
||||
entryPoints: {[_Abs('/project-1/node_modules/package-1/entry-point-1')]: {}}
|
||||
});
|
||||
expect(configuration.getConfig(_Abs('/project-1/node_modules/package-1'), '2.5.0'))
|
||||
.toEqual({
|
||||
versionRange: '2.*',
|
||||
entryPoints: {[_Abs('/project-1/node_modules/package-1/entry-point-2')]: {}}
|
||||
});
|
||||
expect(configuration.getConfig(_Abs('/project-1/node_modules/package-1'), '3.2.5'))
|
||||
.toEqual({
|
||||
versionRange: '^3.2.0',
|
||||
entryPoints: {[_Abs('/project-1/node_modules/package-1/entry-point-3')]: {}}
|
||||
});
|
||||
expect(configuration.getConfig(_Abs('/project-1/node_modules/package-1'), '4.0.0'))
|
||||
.toEqual({versionRange: '*', entryPoints: {}});
|
||||
});
|
||||
|
||||
it('should not get confused by the @ in namespaced packages', () => {
|
||||
loadTestFiles([{
|
||||
name: _Abs('/project-1/ngcc.config.js'),
|
||||
contents: `
|
||||
module.exports = {
|
||||
packages: {
|
||||
'@angular/common': {
|
||||
entryPoints: {
|
||||
'.': {}
|
||||
},
|
||||
},
|
||||
},
|
||||
};`
|
||||
}]);
|
||||
const configuration = new NgccConfiguration(fs, _Abs('/project-1'));
|
||||
|
||||
expect(configuration.getConfig(_Abs('/project-1/node_modules/@angular/common'), '1.0.0'))
|
||||
.toEqual({
|
||||
versionRange: '*',
|
||||
entryPoints: {[_Abs('/project-1/node_modules/@angular/common')]: {}}
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
it('should override package level config with project level config per package', () => {
|
||||
loadTestFiles([
|
||||
{
|
||||
name: _Abs('/project-1/ngcc.config.js'),
|
||||
contents: `
|
||||
module.exports = {
|
||||
packages: {
|
||||
'package-2': {
|
||||
entryPoints: {
|
||||
'./project-setting-entry-point': {}
|
||||
loadTestFiles([{
|
||||
name: _Abs('/project-1/ngcc.config.js'),
|
||||
contents: `
|
||||
module.exports = {
|
||||
packages: {
|
||||
'package-2': {
|
||||
entryPoints: {
|
||||
'./project-setting-entry-point': {}
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
};`,
|
||||
},
|
||||
{
|
||||
name: _Abs('/project-1/node_modules/package-1/ngcc.config.js'),
|
||||
contents: `
|
||||
module.exports = {
|
||||
entryPoints: {
|
||||
'./package-setting-entry-point': {}
|
||||
},
|
||||
};`,
|
||||
},
|
||||
{
|
||||
name: _Abs('/project-1/node_modules/package-2/ngcc.config.js'),
|
||||
contents: `
|
||||
module.exports = {
|
||||
entryPoints: {
|
||||
'./package-setting-entry-point': {}
|
||||
},
|
||||
};`,
|
||||
}
|
||||
]);
|
||||
};`,
|
||||
}]);
|
||||
loadTestFiles(
|
||||
packageWithConfigFiles('package-1', 'package-setting-entry-point', '1.0.0'));
|
||||
loadTestFiles(
|
||||
packageWithConfigFiles('package-2', 'package-setting-entry-point', '1.0.0'));
|
||||
|
||||
const readFileSpy = spyOn(fs, 'readFile').and.callThrough();
|
||||
const configuration = new NgccConfiguration(fs, _Abs('/project-1'));
|
||||
expect(readFileSpy).toHaveBeenCalledWith(_Abs('/project-1/ngcc.config.js'));
|
||||
|
||||
const package1Config = configuration.getConfig(_Abs('/project-1/node_modules/package-1'));
|
||||
const package1Config =
|
||||
configuration.getConfig(_Abs('/project-1/node_modules/package-1'), '1.0.0');
|
||||
expect(package1Config).toEqual({
|
||||
versionRange: '1.0.0',
|
||||
entryPoints:
|
||||
{[_Abs('/project-1/node_modules/package-1/package-setting-entry-point')]: {}}
|
||||
});
|
||||
|
@ -162,8 +220,10 @@ runInEachFileSystem(() => {
|
|||
// Note that for `package-2` only the project level entry-point is left.
|
||||
// This is because overriding happens for packages as a whole and there is no attempt to
|
||||
// merge entry-points.
|
||||
const package2Config = configuration.getConfig(_Abs('/project-1/node_modules/package-2'));
|
||||
const package2Config =
|
||||
configuration.getConfig(_Abs('/project-1/node_modules/package-2'), '1.0.0');
|
||||
expect(package2Config).toEqual({
|
||||
versionRange: '*',
|
||||
entryPoints:
|
||||
{[_Abs('/project-1/node_modules/package-2/project-setting-entry-point')]: {}}
|
||||
});
|
||||
|
@ -182,38 +242,36 @@ runInEachFileSystem(() => {
|
|||
afterEach(() => { DEFAULT_NGCC_CONFIG.packages['package-1'] = originalDefaultConfig; });
|
||||
|
||||
it('should return configuration for a package found in the default config', () => {
|
||||
|
||||
const readFileSpy = spyOn(fs, 'readFile').and.callThrough();
|
||||
const configuration = new NgccConfiguration(fs, _Abs('/project-1'));
|
||||
expect(readFileSpy).not.toHaveBeenCalled();
|
||||
|
||||
const config = configuration.getConfig(_Abs('/project-1/node_modules/package-1'));
|
||||
const config =
|
||||
configuration.getConfig(_Abs('/project-1/node_modules/package-1'), '1.0.0');
|
||||
expect(config).toEqual({
|
||||
versionRange: '*',
|
||||
entryPoints:
|
||||
{[_Abs('/project-1/node_modules/package-1/default-level-entry-point')]: {}}
|
||||
});
|
||||
});
|
||||
|
||||
it('should override default level config with package level config, if provided', () => {
|
||||
loadTestFiles([{
|
||||
name: _Abs('/project-1/node_modules/package-1/ngcc.config.js'),
|
||||
contents: `
|
||||
module.exports = {
|
||||
entryPoints: {'./package-level-entry-point': {}},
|
||||
};`,
|
||||
}]);
|
||||
loadTestFiles(packageWithConfigFiles('package-1', 'package-level-entry-point', '1.0.0'));
|
||||
const configuration = new NgccConfiguration(fs, _Abs('/project-1'));
|
||||
const config = configuration.getConfig(_Abs('/project-1/node_modules/package-1'));
|
||||
const config =
|
||||
configuration.getConfig(_Abs('/project-1/node_modules/package-1'), '1.0.0');
|
||||
// Note that only the package-level-entry-point is left.
|
||||
// This is because overriding happens for packages as a whole and there is no attempt to
|
||||
// merge entry-points.
|
||||
expect(config).toEqual({
|
||||
versionRange: '1.0.0',
|
||||
entryPoints:
|
||||
{[_Abs('/project-1/node_modules/package-1/package-level-entry-point')]: {}}
|
||||
});
|
||||
});
|
||||
|
||||
it('should override default level config with project level config, if provided', () => {
|
||||
loadTestFiles(packageWithConfigFiles('package-1', 'package-level-entry-point', '1.0.0'));
|
||||
loadTestFiles([
|
||||
{
|
||||
name: _Abs('/project-1/node_modules/package-1/ngcc.config.js'),
|
||||
|
@ -238,11 +296,13 @@ runInEachFileSystem(() => {
|
|||
]);
|
||||
|
||||
const configuration = new NgccConfiguration(fs, _Abs('/project-1'));
|
||||
const config = configuration.getConfig(_Abs('/project-1/node_modules/package-1'));
|
||||
const config =
|
||||
configuration.getConfig(_Abs('/project-1/node_modules/package-1'), '1.0.0');
|
||||
// Note that only the project-level-entry-point is left.
|
||||
// This is because overriding happens for packages as a whole and there is no attempt to
|
||||
// merge entry-points.
|
||||
expect(config).toEqual({
|
||||
versionRange: '*',
|
||||
entryPoints:
|
||||
{[_Abs('/project-1/node_modules/package-1/project-level-entry-point')]: {}}
|
||||
});
|
||||
|
@ -250,4 +310,17 @@ runInEachFileSystem(() => {
|
|||
});
|
||||
});
|
||||
});
|
||||
|
||||
function packageWithConfigFiles(packageName: string, entryPointName: string, version: string) {
|
||||
return [
|
||||
{
|
||||
name: _Abs(`/project-1/node_modules/${packageName}/ngcc.config.js`),
|
||||
contents: `module.exports = {entryPoints: { './${entryPointName}': {}}}`
|
||||
},
|
||||
{
|
||||
name: _Abs(`/project-1/node_modules/${packageName}/package.json`),
|
||||
contents: `{ "version": "${version}" }`
|
||||
}
|
||||
];
|
||||
}
|
||||
});
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
"convert-source-map": "^1.5.1",
|
||||
"dependency-graph": "^0.7.2",
|
||||
"magic-string": "^0.25.0",
|
||||
"semver": "^6.3.0",
|
||||
"source-map": "^0.6.1",
|
||||
"tslib": "^1.9.0",
|
||||
"yargs": "13.1.0"
|
||||
|
|
15
yarn.lock
15
yarn.lock
|
@ -877,6 +877,11 @@
|
|||
resolved "https://registry.yarnpkg.com/@types/selenium-webdriver/-/selenium-webdriver-3.0.14.tgz#0b20a2370e6b1b8322c9c3dfcaa409e6c7c0c0a9"
|
||||
integrity sha512-4GbNCDs98uHCT/OMv40qQC/OpoPbYn9XdXeTiFwHBBFO6eJhYEPUu2zDKirXSbHlvDV8oZ9l8EQ+HrEx/YS9DQ==
|
||||
|
||||
"@types/semver@^6.0.2":
|
||||
version "6.0.2"
|
||||
resolved "https://registry.yarnpkg.com/@types/semver/-/semver-6.0.2.tgz#5e8b09f0e4af53034b1d0fb9977a277847836205"
|
||||
integrity sha512-G1Ggy7/9Nsa1Jt2yiBR2riEuyK2DFNnqow6R7cromXPMNynackRY1vqFTLz/gwnef1LHokbXThcPhqMRjUbkpQ==
|
||||
|
||||
"@types/shelljs@^0.7.8":
|
||||
version "0.7.9"
|
||||
resolved "https://registry.yarnpkg.com/@types/shelljs/-/shelljs-0.7.9.tgz#3abecb72d9cad9cd4b0e7cb86ed10a97d93ba602"
|
||||
|
@ -10057,11 +10062,6 @@ semver@5.1.0:
|
|||
resolved "https://registry.yarnpkg.com/semver/-/semver-5.1.0.tgz#85f2cf8550465c4df000cf7d86f6b054106ab9e5"
|
||||
integrity sha1-hfLPhVBGXE3wAM99hvawVBBqueU=
|
||||
|
||||
semver@5.4.1:
|
||||
version "5.4.1"
|
||||
resolved "https://registry.yarnpkg.com/semver/-/semver-5.4.1.tgz#e059c09d8571f0540823733433505d3a2f00b18e"
|
||||
integrity sha512-WfG/X9+oATh81XtllIo/I8gOiY9EXRdv1cQdyykeXK17YcUW3EXUAi2To4pcH6nZtJPr7ZOpM5OMyWJZm+8Rsg==
|
||||
|
||||
semver@5.5.0:
|
||||
version "5.5.0"
|
||||
resolved "https://registry.yarnpkg.com/semver/-/semver-5.5.0.tgz#dc4bbc7a6ca9d916dee5d43516f0092b58f7b8ab"
|
||||
|
@ -10072,6 +10072,11 @@ semver@6.0.0:
|
|||
resolved "https://registry.yarnpkg.com/semver/-/semver-6.0.0.tgz#05e359ee571e5ad7ed641a6eec1e547ba52dea65"
|
||||
integrity sha512-0UewU+9rFapKFnlbirLi3byoOuhrSsli/z/ihNnvM24vgF+8sNBiI1LZPBSH9wJKUwaUbw+s3hToDLCXkrghrQ==
|
||||
|
||||
semver@^6.3.0:
|
||||
version "6.3.0"
|
||||
resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d"
|
||||
integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==
|
||||
|
||||
semver@~5.0.1:
|
||||
version "5.0.3"
|
||||
resolved "https://registry.yarnpkg.com/semver/-/semver-5.0.3.tgz#77466de589cd5d3c95f138aa78bc569a3cb5d27a"
|
||||
|
|
Loading…
Reference in New Issue