
The `Logger` interface and its related classes are general purpose and could be used by other tooling. Moving it into ngtsc is a more suitable place from which to share it - similar to the FileSystem stuff. PR Close #37114
787 lines
34 KiB
TypeScript
787 lines
34 KiB
TypeScript
/**
|
|
* @license
|
|
* Copyright Google LLC 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, AbsoluteFsPath, FileSystem, getFileSystem, join, relative} from '../../../src/ngtsc/file_system';
|
|
import {runInEachFileSystem} from '../../../src/ngtsc/file_system/testing';
|
|
import {MockLogger} from '../../../src/ngtsc/logging/testing';
|
|
import {loadTestFiles} from '../../../test/helpers';
|
|
import {NgccConfiguration, ProcessedNgccPackageConfig} from '../../src/packages/configuration';
|
|
import {EntryPoint, EntryPointJsonProperty, getEntryPointFormat, getEntryPointInfo, IGNORED_ENTRY_POINT, INCOMPATIBLE_ENTRY_POINT, isEntryPoint, NO_ENTRY_POINT, SUPPORTED_FORMAT_PROPERTIES} from '../../src/packages/entry_point';
|
|
|
|
runInEachFileSystem(() => {
|
|
describe('getEntryPointInfo()', () => {
|
|
let SOME_PACKAGE: AbsoluteFsPath;
|
|
let _: typeof absoluteFrom;
|
|
let fs: FileSystem;
|
|
|
|
beforeEach(() => {
|
|
_ = absoluteFrom;
|
|
SOME_PACKAGE = _('/project/node_modules/some_package');
|
|
fs = getFileSystem();
|
|
});
|
|
|
|
it('should return an object containing absolute paths to the formats of the specified entry-point',
|
|
() => {
|
|
loadTestFiles([
|
|
{
|
|
name: _('/project/node_modules/some_package/valid_entry_point/package.json'),
|
|
contents: createPackageJson('valid_entry_point')
|
|
},
|
|
{
|
|
name: _(
|
|
'/project/node_modules/some_package/valid_entry_point/valid_entry_point.metadata.json'),
|
|
contents: 'some meta data'
|
|
},
|
|
]);
|
|
const config = new NgccConfiguration(fs, _('/project'));
|
|
const entryPoint = getEntryPointInfo(
|
|
fs, config, new MockLogger(), SOME_PACKAGE,
|
|
_('/project/node_modules/some_package/valid_entry_point'));
|
|
expect(entryPoint).toEqual({
|
|
name: 'some_package/valid_entry_point',
|
|
path: _('/project/node_modules/some_package/valid_entry_point'),
|
|
packageName: 'some_package',
|
|
packagePath: SOME_PACKAGE,
|
|
packageJson: loadPackageJson(fs, '/project/node_modules/some_package/valid_entry_point'),
|
|
typings:
|
|
_(`/project/node_modules/some_package/valid_entry_point/valid_entry_point.d.ts`),
|
|
compiledByAngular: true,
|
|
ignoreMissingDependencies: false,
|
|
generateDeepReexports: false,
|
|
});
|
|
});
|
|
|
|
it('should return `IGNORED_ENTRY_POINT` if configured to ignore the specified entry-point', () => {
|
|
loadTestFiles([
|
|
{
|
|
name: _('/project/node_modules/some_package/valid_entry_point/package.json'),
|
|
contents: createPackageJson('valid_entry_point'),
|
|
},
|
|
{
|
|
name: _(
|
|
'/project/node_modules/some_package/valid_entry_point/valid_entry_point.metadata.json'),
|
|
contents: 'some meta data',
|
|
},
|
|
]);
|
|
const config = new NgccConfiguration(fs, _('/project'));
|
|
spyOn(config, 'getPackageConfig')
|
|
.and.returnValue(new ProcessedNgccPackageConfig(
|
|
_('/project/node_modules/some_package'),
|
|
{entryPoints: {'./valid_entry_point': {ignore: true}}}));
|
|
const entryPoint = getEntryPointInfo(
|
|
fs, config, new MockLogger(), SOME_PACKAGE,
|
|
_('/project/node_modules/some_package/valid_entry_point'));
|
|
expect(entryPoint).toBe(IGNORED_ENTRY_POINT);
|
|
});
|
|
|
|
it('should retrieve the entry-point\'s version from the package\'s `package.json`', () => {
|
|
const entryPointPath = join(SOME_PACKAGE, 'valid_entry_point');
|
|
|
|
loadTestFiles([
|
|
{
|
|
name: _('/project/ngcc.config.js'),
|
|
contents: `
|
|
module.exports = {
|
|
packages: {
|
|
'some_package@3': {
|
|
entryPoints: {valid_entry_point: {override: {packageVersion: '3'}}},
|
|
},
|
|
'some_package@2': {
|
|
entryPoints: {valid_entry_point: {override: {packageVersion: '2'}}},
|
|
},
|
|
'some_package@1': {
|
|
entryPoints: {valid_entry_point: {override: {packageVersion: '1'}}},
|
|
},
|
|
},
|
|
};
|
|
`,
|
|
},
|
|
{
|
|
name: join(SOME_PACKAGE, 'package.json'),
|
|
contents: createPackageJson('', {version: '1.0.0'}),
|
|
},
|
|
{
|
|
name: join(entryPointPath, 'package.json'),
|
|
contents: createPackageJson('valid_entry_point', {version: '2.0.0'}),
|
|
},
|
|
{
|
|
name: join(entryPointPath, 'valid_entry_point.metadata.json'),
|
|
contents: 'some meta data',
|
|
},
|
|
]);
|
|
|
|
const config = new NgccConfiguration(fs, _('/project'));
|
|
const info: EntryPoint =
|
|
getEntryPointInfo(fs, config, new MockLogger(), SOME_PACKAGE, entryPointPath) as any;
|
|
|
|
expect(info.packageJson).toEqual(jasmine.objectContaining({packageVersion: '1'}));
|
|
});
|
|
|
|
it('should use `null` for version if it cannot be retrieved from a `package.json`', () => {
|
|
const entryPointPath = join(SOME_PACKAGE, 'valid_entry_point');
|
|
|
|
loadTestFiles([
|
|
{
|
|
name: _('/project/ngcc.config.js'),
|
|
contents: `
|
|
module.exports = {
|
|
packages: {
|
|
'some_package@3': {
|
|
entryPoints: {valid_entry_point: {override: {packageVersion: '3'}}},
|
|
},
|
|
'some_package@2': {
|
|
entryPoints: {valid_entry_point: {override: {packageVersion: '2'}}},
|
|
},
|
|
'some_package@1': {
|
|
entryPoints: {valid_entry_point: {override: {packageVersion: '1'}}},
|
|
},
|
|
},
|
|
};
|
|
`,
|
|
},
|
|
{
|
|
name: join(SOME_PACKAGE, 'package.json'),
|
|
contents: createPackageJson(''),
|
|
},
|
|
{
|
|
name: join(entryPointPath, 'package.json'),
|
|
contents: createPackageJson('valid_entry_point'),
|
|
},
|
|
{
|
|
name: join(entryPointPath, 'valid_entry_point.metadata.json'),
|
|
contents: 'some meta data',
|
|
},
|
|
]);
|
|
|
|
const config = new NgccConfiguration(fs, _('/project'));
|
|
const info: EntryPoint =
|
|
getEntryPointInfo(fs, config, new MockLogger(), SOME_PACKAGE, entryPointPath) as any;
|
|
|
|
expect(info.packageJson).toEqual(jasmine.objectContaining({packageVersion: '3'}));
|
|
});
|
|
|
|
it('should override the properties on package.json if the entry-point is configured', () => {
|
|
loadTestFiles([
|
|
{
|
|
name: _('/project/node_modules/some_package/valid_entry_point/package.json'),
|
|
contents: createPackageJson('valid_entry_point'),
|
|
},
|
|
{
|
|
name: _(
|
|
'/project/node_modules/some_package/valid_entry_point/valid_entry_point.metadata.json'),
|
|
contents: 'some meta data',
|
|
},
|
|
]);
|
|
const config = new NgccConfiguration(fs, _('/project'));
|
|
const override = {
|
|
typings: './some_other.d.ts',
|
|
esm2015: './some_other.js',
|
|
};
|
|
spyOn(config, 'getPackageConfig')
|
|
.and.returnValue(new ProcessedNgccPackageConfig(
|
|
_('/project/node_modules/some_package'),
|
|
{entryPoints: {'./valid_entry_point': {override}}}));
|
|
const entryPoint = getEntryPointInfo(
|
|
fs, config, new MockLogger(), SOME_PACKAGE,
|
|
_('/project/node_modules/some_package/valid_entry_point'));
|
|
const overriddenPackageJson = {
|
|
...loadPackageJson(fs, '/project/node_modules/some_package/valid_entry_point'),
|
|
...override
|
|
};
|
|
expect(entryPoint).toEqual({
|
|
name: 'some_package/valid_entry_point',
|
|
path: _('/project/node_modules/some_package/valid_entry_point'),
|
|
packageName: 'some_package',
|
|
packagePath: SOME_PACKAGE,
|
|
packageJson: overriddenPackageJson,
|
|
typings: _('/project/node_modules/some_package/valid_entry_point/some_other.d.ts'),
|
|
compiledByAngular: true,
|
|
ignoreMissingDependencies: false,
|
|
generateDeepReexports: false,
|
|
});
|
|
});
|
|
|
|
it('should return `NO_ENTRY_POINT` if there is no package.json at the entry-point path', () => {
|
|
loadTestFiles([
|
|
{
|
|
name: _(
|
|
'/project/node_modules/some_package/missing_package_json/missing_package_json.metadata.json'),
|
|
contents: 'some meta data'
|
|
},
|
|
]);
|
|
const config = new NgccConfiguration(fs, _('/project'));
|
|
const entryPoint = getEntryPointInfo(
|
|
fs, config, new MockLogger(), SOME_PACKAGE,
|
|
_('/project/node_modules/some_package/missing_package_json'));
|
|
expect(entryPoint).toBe(NO_ENTRY_POINT);
|
|
});
|
|
|
|
it('should return a configured entry-point if there is no package.json at the entry-point path',
|
|
() => {
|
|
loadTestFiles([
|
|
// no package.json!
|
|
{
|
|
name: _(
|
|
'/project/node_modules/some_package/missing_package_json/missing_package_json.metadata.json'),
|
|
contents: 'some meta data',
|
|
},
|
|
]);
|
|
const config = new NgccConfiguration(fs, _('/project'));
|
|
const override =
|
|
JSON.parse(createPackageJson('missing_package_json', {excludes: ['name']}));
|
|
spyOn(config, 'getPackageConfig')
|
|
.and.returnValue(new ProcessedNgccPackageConfig(
|
|
_('/project/node_modules/some_package/'),
|
|
{entryPoints: {'./missing_package_json': {override}}}));
|
|
const entryPoint = getEntryPointInfo(
|
|
fs, config, new MockLogger(), SOME_PACKAGE,
|
|
_('/project/node_modules/some_package/missing_package_json'));
|
|
expect(entryPoint).toEqual({
|
|
name: 'some_package/missing_package_json',
|
|
path: _('/project/node_modules/some_package/missing_package_json'),
|
|
packageName: 'some_package',
|
|
packagePath: SOME_PACKAGE,
|
|
packageJson: {name: 'some_package/missing_package_json', ...override},
|
|
typings: _(
|
|
'/project/node_modules/some_package/missing_package_json/missing_package_json.d.ts'),
|
|
compiledByAngular: true,
|
|
ignoreMissingDependencies: false,
|
|
generateDeepReexports: false,
|
|
});
|
|
});
|
|
|
|
[false, true].forEach(isScoped => {
|
|
const nameWithScope = (baseName: string) => `${isScoped ? '@some-scope/' : ''}${baseName}`;
|
|
const getPackageName = (packagePath: AbsoluteFsPath, entryPointPath: AbsoluteFsPath) => {
|
|
const config = new NgccConfiguration(fs, _('/project'));
|
|
const logger = new MockLogger();
|
|
const entryPoint = getEntryPointInfo(fs, config, logger, packagePath, entryPointPath);
|
|
|
|
if (!isEntryPoint(entryPoint)) {
|
|
return fail(`Expected an entry point but got ${entryPoint}`);
|
|
}
|
|
|
|
return entryPoint.packageName;
|
|
};
|
|
const setUpPackageWithEntryPointPackageJson =
|
|
(entryPointName: string, entryPointPath: AbsoluteFsPath) => {
|
|
// Ensure a `package.json` exists for the entry-point (containing `entryPointName`).
|
|
loadTestFiles([
|
|
{
|
|
name: join(entryPointPath, 'package.json'),
|
|
contents: JSON.stringify({name: entryPointName, typings: './index.d.ts'}),
|
|
},
|
|
]);
|
|
};
|
|
const setUpPackageWithoutEntryPointPackageJson =
|
|
(packagePath: AbsoluteFsPath, entryPointPath: AbsoluteFsPath) => {
|
|
// Ensure there is an ngcc config for the entry-point providing a `typings` field to
|
|
// avoid returning `INCOMPATIBLE_ENTRY_POINT` (since there is no `package.json`).
|
|
loadTestFiles([
|
|
{
|
|
name: join(packagePath, 'ngcc.config.js'),
|
|
contents: `
|
|
module.exports = {
|
|
entryPoints: {
|
|
'${relative(packagePath, entryPointPath)}': {
|
|
override: {typings: './index.d.ts'},
|
|
},
|
|
},
|
|
};
|
|
`,
|
|
},
|
|
]);
|
|
};
|
|
|
|
describe(`should compute the containing ${isScoped ? 'scoped ' : ''}package's name`, () => {
|
|
it('for a primary entry-point with a `package.json`', () => {
|
|
const packagePath = _(`/project/node_modules/${nameWithScope('on-disk-package-name')}`);
|
|
const entryPointPath = packagePath;
|
|
const expectedPackageName = nameWithScope('package-json-package-name');
|
|
|
|
setUpPackageWithEntryPointPackageJson(expectedPackageName, entryPointPath);
|
|
|
|
expect(getPackageName(packagePath, entryPointPath)).toBe(expectedPackageName);
|
|
});
|
|
|
|
it('for a primary entry-point without a `package.json`', () => {
|
|
const packagePath = _(`/project/node_modules/${nameWithScope('on-disk-package-name')}`);
|
|
const entryPointPath = packagePath;
|
|
const expectedPackageName = nameWithScope('on-disk-package-name');
|
|
|
|
setUpPackageWithoutEntryPointPackageJson(packagePath, entryPointPath);
|
|
|
|
expect(getPackageName(packagePath, entryPointPath)).toBe(expectedPackageName);
|
|
});
|
|
|
|
it('for a secondary entry-point with a `package.json`', () => {
|
|
const packagePath = _(`/project/node_modules/${nameWithScope('on-disk-package-name')}`);
|
|
const entryPointPath = join(packagePath, 'some-entry-point');
|
|
const expectedPackageName = nameWithScope('package-json-package-name');
|
|
|
|
setUpPackageWithEntryPointPackageJson(
|
|
`${expectedPackageName}/some-entry-point`, entryPointPath);
|
|
|
|
expect(getPackageName(packagePath, entryPointPath)).toBe(expectedPackageName);
|
|
});
|
|
|
|
it('for a secondary entry-point without a `package.json`', () => {
|
|
const packagePath = _(`/project/node_modules/${nameWithScope('on-disk-package-name')}`);
|
|
const entryPointPath = join(packagePath, 'some-entry-point');
|
|
const expectedPackageName = nameWithScope('on-disk-package-name');
|
|
|
|
setUpPackageWithoutEntryPointPackageJson(packagePath, entryPointPath);
|
|
|
|
expect(getPackageName(packagePath, entryPointPath)).toBe(expectedPackageName);
|
|
});
|
|
|
|
it('for a primary entry-point without a `package.json` in nested `node_modules/`', () => {
|
|
const packagePath = _(`/project/node_modules/other-package/node_modules/${
|
|
nameWithScope('on-disk-package-name')}`);
|
|
const entryPointPath = packagePath;
|
|
const expectedPackageName = nameWithScope('on-disk-package-name');
|
|
|
|
setUpPackageWithoutEntryPointPackageJson(packagePath, entryPointPath);
|
|
|
|
expect(getPackageName(packagePath, entryPointPath)).toBe(expectedPackageName);
|
|
});
|
|
|
|
it('for a secondary entry-point without a `package.json` in nested `node_modules/`', () => {
|
|
const packagePath = _(`/project/node_modules/other-package/node_modules/${
|
|
nameWithScope('on-disk-package-name')}`);
|
|
const entryPointPath = join(packagePath, 'some-entry-point');
|
|
const expectedPackageName = nameWithScope('on-disk-package-name');
|
|
|
|
setUpPackageWithoutEntryPointPackageJson(packagePath, entryPointPath);
|
|
|
|
expect(getPackageName(packagePath, entryPointPath)).toBe(expectedPackageName);
|
|
});
|
|
|
|
it('for a primary entry-point with a `package.json` outside `node_modules/`', () => {
|
|
const packagePath = _(`/project/libs/${nameWithScope('on-disk-package-name')}`);
|
|
const entryPointPath = packagePath;
|
|
const expectedPackageName = nameWithScope('package-json-package-name');
|
|
|
|
setUpPackageWithEntryPointPackageJson(expectedPackageName, entryPointPath);
|
|
|
|
expect(getPackageName(packagePath, entryPointPath)).toBe(expectedPackageName);
|
|
});
|
|
|
|
it('for a primary entry-point without a `package.json` outside `node_modules/`', () => {
|
|
const packagePath = _(`/project/libs/${nameWithScope('on-disk-package-name')}`);
|
|
const entryPointPath = packagePath;
|
|
const expectedPackageName = nameWithScope('on-disk-package-name');
|
|
|
|
setUpPackageWithoutEntryPointPackageJson(packagePath, entryPointPath);
|
|
|
|
expect(getPackageName(packagePath, entryPointPath)).toBe(expectedPackageName);
|
|
});
|
|
|
|
it('for a secondary entry-point with a `package.json` outside `node_modules/`', () => {
|
|
const packagePath = _(`/project/libs/${nameWithScope('on-disk-package-name')}`);
|
|
const entryPointPath = join(packagePath, 'some-entry-point');
|
|
const expectedPackageName = nameWithScope('package-json-package-name');
|
|
|
|
setUpPackageWithEntryPointPackageJson(expectedPackageName, entryPointPath);
|
|
|
|
expect(getPackageName(packagePath, entryPointPath)).toBe(expectedPackageName);
|
|
});
|
|
|
|
it('for a secondary entry-point without a `package.json` outside `node_modules/`', () => {
|
|
const packagePath = _(`/project/libs/${nameWithScope('on-disk-package-name')}`);
|
|
const entryPointPath = join(packagePath, 'some-entry-point');
|
|
const expectedPackageName = nameWithScope('on-disk-package-name');
|
|
|
|
setUpPackageWithoutEntryPointPackageJson(packagePath, entryPointPath);
|
|
|
|
expect(getPackageName(packagePath, entryPointPath)).toBe(expectedPackageName);
|
|
});
|
|
});
|
|
});
|
|
|
|
it('should return `INCOMPATIBLE_ENTRY_POINT` if there is no typings or types field in the package.json',
|
|
() => {
|
|
loadTestFiles([
|
|
{
|
|
name: _('/project/node_modules/some_package/missing_typings/package.json'),
|
|
contents: createPackageJson('missing_typings', {excludes: ['typings']})
|
|
},
|
|
{
|
|
name: _(
|
|
'/project/node_modules/some_package/missing_typings/missing_typings.metadata.json'),
|
|
contents: 'some meta data'
|
|
},
|
|
]);
|
|
const config = new NgccConfiguration(fs, _('/project'));
|
|
const entryPoint = getEntryPointInfo(
|
|
fs, config, new MockLogger(), SOME_PACKAGE,
|
|
_('/project/node_modules/some_package/missing_typings'));
|
|
expect(entryPoint).toBe(INCOMPATIBLE_ENTRY_POINT);
|
|
});
|
|
|
|
it('should return `INCOMPATIBLE_ENTRY_POINT` if the typings or types field is not a string in the package.json',
|
|
() => {
|
|
loadTestFiles([
|
|
{
|
|
name: _('/project/node_modules/some_package/typings_array/package.json'),
|
|
contents: createPackageJson('typings_array', {typingsIsArray: true})
|
|
},
|
|
{
|
|
name: _(
|
|
'/project/node_modules/some_package/typings_array/missing_typings.metadata.json'),
|
|
contents: 'some meta data'
|
|
},
|
|
]);
|
|
const config = new NgccConfiguration(fs, _('/project'));
|
|
const entryPoint = getEntryPointInfo(
|
|
fs, config, new MockLogger(), SOME_PACKAGE,
|
|
_('/project/node_modules/some_package/typings_array'));
|
|
expect(entryPoint).toBe(INCOMPATIBLE_ENTRY_POINT);
|
|
});
|
|
|
|
for (let prop of SUPPORTED_FORMAT_PROPERTIES) {
|
|
// Ignore the UMD format
|
|
if (prop === 'main' || prop === 'browser') continue;
|
|
// Let's give 'module' a specific path, otherwise compute it based on the property.
|
|
const typingsPath = prop === 'module' ? 'index' : `${prop}/missing_typings`;
|
|
|
|
it(`should return an object if it can guess the typings path from the "${prop}" field`,
|
|
() => {
|
|
loadTestFiles([
|
|
{
|
|
name: _('/project/node_modules/some_package/missing_typings/package.json'),
|
|
contents: createPackageJson('missing_typings', {excludes: ['typings']}),
|
|
},
|
|
{
|
|
name: _(`/project/node_modules/some_package/missing_typings/${
|
|
typingsPath}.metadata.json`),
|
|
contents: 'some meta data',
|
|
},
|
|
{
|
|
name: _(`/project/node_modules/some_package/missing_typings/${typingsPath}.d.ts`),
|
|
contents: '// some typings file',
|
|
},
|
|
]);
|
|
const config = new NgccConfiguration(fs, _('/project'));
|
|
const entryPoint = getEntryPointInfo(
|
|
fs, config, new MockLogger(), SOME_PACKAGE,
|
|
_('/project/node_modules/some_package/missing_typings'));
|
|
expect(entryPoint).toEqual({
|
|
name: 'some_package/missing_typings',
|
|
path: _('/project/node_modules/some_package/missing_typings'),
|
|
packageName: 'some_package',
|
|
packagePath: SOME_PACKAGE,
|
|
packageJson: loadPackageJson(fs, '/project/node_modules/some_package/missing_typings'),
|
|
typings: _(`/project/node_modules/some_package/missing_typings/${typingsPath}.d.ts`),
|
|
compiledByAngular: true,
|
|
ignoreMissingDependencies: false,
|
|
generateDeepReexports: false,
|
|
});
|
|
});
|
|
}
|
|
|
|
it('should return an object with `compiledByAngular` set to false if there is no metadata.json file next to the typing file',
|
|
() => {
|
|
loadTestFiles([
|
|
{
|
|
name: _('/project/node_modules/some_package/missing_metadata/package.json'),
|
|
contents: createPackageJson('missing_metadata')
|
|
},
|
|
]);
|
|
const config = new NgccConfiguration(fs, _('/project'));
|
|
const entryPoint = getEntryPointInfo(
|
|
fs, config, new MockLogger(), SOME_PACKAGE,
|
|
_('/project/node_modules/some_package/missing_metadata'));
|
|
expect(entryPoint).toEqual({
|
|
name: 'some_package/missing_metadata',
|
|
path: _('/project/node_modules/some_package/missing_metadata'),
|
|
packageName: 'some_package',
|
|
packagePath: SOME_PACKAGE,
|
|
packageJson: loadPackageJson(fs, '/project/node_modules/some_package/missing_metadata'),
|
|
typings: _(`/project/node_modules/some_package/missing_metadata/missing_metadata.d.ts`),
|
|
compiledByAngular: false,
|
|
ignoreMissingDependencies: false,
|
|
generateDeepReexports: false,
|
|
});
|
|
});
|
|
|
|
it('should return an object with `compiledByAngular` set to true if there is no metadata.json file but the entry-point has a configuration',
|
|
() => {
|
|
loadTestFiles([
|
|
{
|
|
name: _('/project/node_modules/some_package/missing_metadata/package.json'),
|
|
contents: createPackageJson('missing_metadata'),
|
|
},
|
|
// no metadata.json!
|
|
]);
|
|
const config = new NgccConfiguration(fs, _('/project'));
|
|
spyOn(config, 'getPackageConfig')
|
|
.and.returnValue(new ProcessedNgccPackageConfig(
|
|
_('/project/node_modules/some_package'),
|
|
{entryPoints: {'./missing_metadata': {}}}));
|
|
const entryPoint = getEntryPointInfo(
|
|
fs, config, new MockLogger(), SOME_PACKAGE,
|
|
_('/project/node_modules/some_package/missing_metadata'));
|
|
expect(entryPoint).toEqual({
|
|
name: 'some_package/missing_metadata',
|
|
path: _('/project/node_modules/some_package/missing_metadata'),
|
|
packageName: 'some_package',
|
|
packagePath: SOME_PACKAGE,
|
|
packageJson: loadPackageJson(fs, '/project/node_modules/some_package/missing_metadata'),
|
|
typings: _('/project/node_modules/some_package/missing_metadata/missing_metadata.d.ts'),
|
|
compiledByAngular: true,
|
|
ignoreMissingDependencies: false,
|
|
generateDeepReexports: false,
|
|
});
|
|
});
|
|
|
|
it('should work if the typings field is named `types', () => {
|
|
loadTestFiles([
|
|
{
|
|
name: _('/project/node_modules/some_package/types_rather_than_typings/package.json'),
|
|
contents: createPackageJson('types_rather_than_typings', {typingsProp: 'types'})
|
|
},
|
|
{
|
|
name: _(
|
|
'/project/node_modules/some_package/types_rather_than_typings/types_rather_than_typings.metadata.json'),
|
|
contents: 'some meta data'
|
|
},
|
|
]);
|
|
const config = new NgccConfiguration(fs, _('/project'));
|
|
const entryPoint = getEntryPointInfo(
|
|
fs, config, new MockLogger(), SOME_PACKAGE,
|
|
_('/project/node_modules/some_package/types_rather_than_typings'));
|
|
expect(entryPoint).toEqual({
|
|
name: 'some_package/types_rather_than_typings',
|
|
path: _('/project/node_modules/some_package/types_rather_than_typings'),
|
|
packageName: 'some_package',
|
|
packagePath: SOME_PACKAGE,
|
|
packageJson:
|
|
loadPackageJson(fs, '/project/node_modules/some_package/types_rather_than_typings'),
|
|
typings: _(
|
|
`/project/node_modules/some_package/types_rather_than_typings/types_rather_than_typings.d.ts`),
|
|
compiledByAngular: true,
|
|
ignoreMissingDependencies: false,
|
|
generateDeepReexports: false,
|
|
});
|
|
});
|
|
|
|
it('should work with Angular Material style package.json', () => {
|
|
loadTestFiles([
|
|
{
|
|
name: _('/project/node_modules/some_package/material_style/package.json'),
|
|
contents: `{
|
|
"name": "some_package/material_style",
|
|
"typings": "./material_style.d.ts",
|
|
"main": "./bundles/material_style.umd.js",
|
|
"module": "./esm5/material_style.es5.js",
|
|
"es2015": "./esm2015/material_style.js"
|
|
}`
|
|
},
|
|
{
|
|
name: _('/project/node_modules/some_package/material_style/material_style.metadata.json'),
|
|
contents: 'some meta data'
|
|
},
|
|
]);
|
|
const config = new NgccConfiguration(fs, _('/project'));
|
|
const entryPoint = getEntryPointInfo(
|
|
fs, config, new MockLogger(), SOME_PACKAGE,
|
|
_('/project/node_modules/some_package/material_style'));
|
|
expect(entryPoint).toEqual({
|
|
name: 'some_package/material_style',
|
|
path: _('/project/node_modules/some_package/material_style'),
|
|
packageName: 'some_package',
|
|
packagePath: SOME_PACKAGE,
|
|
packageJson: loadPackageJson(fs, '/project/node_modules/some_package/material_style'),
|
|
typings: _(`/project/node_modules/some_package/material_style/material_style.d.ts`),
|
|
compiledByAngular: true,
|
|
ignoreMissingDependencies: false,
|
|
generateDeepReexports: false,
|
|
});
|
|
});
|
|
|
|
it('should return `INCOMPATIBLE_ENTRY_POINT` if the package.json is not valid JSON', () => {
|
|
loadTestFiles([
|
|
// package.json might not be a valid JSON
|
|
// for example, @schematics/angular contains a package.json blueprint
|
|
// with unexpected symbols
|
|
{
|
|
name: _('/project/node_modules/some_package/unexpected_symbols/package.json'),
|
|
contents: '{"devDependencies": {<% if (!minimal) { %>"@types/jasmine": "~2.8.8" <% } %>}}'
|
|
},
|
|
]);
|
|
const config = new NgccConfiguration(fs, _('/project'));
|
|
const entryPoint = getEntryPointInfo(
|
|
fs, config, new MockLogger(), SOME_PACKAGE,
|
|
_('/project/node_modules/some_package/unexpected_symbols'));
|
|
expect(entryPoint).toBe(INCOMPATIBLE_ENTRY_POINT);
|
|
});
|
|
});
|
|
|
|
describe('getEntryPointFormat()', () => {
|
|
let SOME_PACKAGE: AbsoluteFsPath;
|
|
let _: typeof absoluteFrom;
|
|
let fs: FileSystem;
|
|
let entryPoint: EntryPoint;
|
|
|
|
beforeEach(() => {
|
|
_ = absoluteFrom;
|
|
SOME_PACKAGE = _('/project/node_modules/some_package');
|
|
fs = getFileSystem();
|
|
loadTestFiles([{
|
|
name: _('/project/node_modules/some_package/valid_entry_point/package.json'),
|
|
contents: createPackageJson('valid_entry_point')
|
|
}]);
|
|
const config = new NgccConfiguration(fs, _('/project'));
|
|
const result = getEntryPointInfo(
|
|
fs, config, new MockLogger(), SOME_PACKAGE,
|
|
_('/project/node_modules/some_package/valid_entry_point'));
|
|
if (!isEntryPoint(result)) {
|
|
return fail(`Expected an entry point but got ${result}`);
|
|
}
|
|
entryPoint = result;
|
|
});
|
|
|
|
it('should return `esm2015` format for `fesm2015` property', () => {
|
|
expect(getEntryPointFormat(fs, entryPoint, 'fesm2015')).toBe('esm2015');
|
|
});
|
|
|
|
it('should return `esm5` format for `fesm5` property', () => {
|
|
expect(getEntryPointFormat(fs, entryPoint, 'fesm5')).toBe('esm5');
|
|
});
|
|
|
|
it('should return `esm2015` format for `es2015` property', () => {
|
|
expect(getEntryPointFormat(fs, entryPoint, 'es2015')).toBe('esm2015');
|
|
});
|
|
|
|
it('should return `esm2015` format for `esm2015` property', () => {
|
|
expect(getEntryPointFormat(fs, entryPoint, 'esm2015')).toBe('esm2015');
|
|
});
|
|
|
|
it('should return `esm5` format for `esm5` property', () => {
|
|
expect(getEntryPointFormat(fs, entryPoint, 'esm5')).toBe('esm5');
|
|
});
|
|
|
|
it('should return `esm5` format for `module` property', () => {
|
|
expect(getEntryPointFormat(fs, entryPoint, 'module')).toBe('esm5');
|
|
});
|
|
|
|
it('should return `esm2015` format for `module` property if it points to esm2015 output',
|
|
() => {
|
|
entryPoint.packageJson['module'] = '../fesm2015/valid-entry-point.js';
|
|
expect(getEntryPointFormat(fs, entryPoint, 'module')).toBe('esm2015');
|
|
});
|
|
|
|
(['browser', 'main'] as EntryPointJsonProperty[]).forEach(browserOrMain => {
|
|
it('should return `esm5` for `' + browserOrMain +
|
|
'` if the file contains import or export statements',
|
|
() => {
|
|
const name = _(
|
|
'/project/node_modules/some_package/valid_entry_point/bundles/valid_entry_point/index.js');
|
|
loadTestFiles([{name, contents: `import * as core from '@angular/core;`}]);
|
|
expect(getEntryPointFormat(fs, entryPoint, browserOrMain)).toBe('esm5');
|
|
|
|
loadTestFiles([{name, contents: `import {Component} from '@angular/core;`}]);
|
|
expect(getEntryPointFormat(fs, entryPoint, browserOrMain)).toBe('esm5');
|
|
|
|
loadTestFiles([{name, contents: `export function foo() {}`}]);
|
|
expect(getEntryPointFormat(fs, entryPoint, browserOrMain)).toBe('esm5');
|
|
|
|
loadTestFiles([{name, contents: `export * from 'abc';`}]);
|
|
expect(getEntryPointFormat(fs, entryPoint, browserOrMain)).toBe('esm5');
|
|
});
|
|
|
|
it('should return `umd` for `' + browserOrMain +
|
|
'` if the file contains a UMD wrapper function',
|
|
() => {
|
|
loadTestFiles([{
|
|
name: _(
|
|
'/project/node_modules/some_package/valid_entry_point/bundles/valid_entry_point/index.js'),
|
|
contents: `
|
|
(function (global, factory) {
|
|
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('@angular/core')) :
|
|
typeof define === 'function' && define.amd ? define('@angular/common', ['exports', '@angular/core'], factory) :
|
|
(global = global || self, factory((global.ng = global.ng || {}, global.ng.common = {}), global.ng.core));
|
|
}(this, function (exports, core) { 'use strict'; }));
|
|
`
|
|
}]);
|
|
expect(getEntryPointFormat(fs, entryPoint, browserOrMain)).toBe('umd');
|
|
});
|
|
|
|
it('should return `commonjs` for `' + browserOrMain +
|
|
'` if the file does not contain a UMD wrapper function',
|
|
() => {
|
|
loadTestFiles([{
|
|
name: _(
|
|
'/project/node_modules/some_package/valid_entry_point/bundles/valid_entry_point/index.js'),
|
|
contents: `
|
|
const core = require('@angular/core);
|
|
module.exports = {};
|
|
`
|
|
}]);
|
|
expect(getEntryPointFormat(fs, entryPoint, browserOrMain)).toBe('commonjs');
|
|
});
|
|
|
|
it('should resolve the format path with suitable postfixes', () => {
|
|
loadTestFiles([{
|
|
name: _(
|
|
'/project/node_modules/some_package/valid_entry_point/bundles/valid_entry_point/index.js'),
|
|
contents: `
|
|
(function (global, factory) {
|
|
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('@angular/core')) :
|
|
typeof define === 'function' && define.amd ? define('@angular/common', ['exports', '@angular/core'], factory) :
|
|
(global = global || self, factory((global.ng = global.ng || {}, global.ng.common = {}), global.ng.core));
|
|
}(this, function (exports, core) { 'use strict'; }));
|
|
`
|
|
}]);
|
|
|
|
entryPoint.packageJson.main = './bundles/valid_entry_point/index';
|
|
expect(getEntryPointFormat(fs, entryPoint, browserOrMain)).toBe('umd');
|
|
|
|
entryPoint.packageJson.main = './bundles/valid_entry_point';
|
|
expect(getEntryPointFormat(fs, entryPoint, browserOrMain)).toBe('umd');
|
|
});
|
|
});
|
|
|
|
it('should return `undefined` if the `browser` property is not a string', () => {
|
|
entryPoint.packageJson.browser = {} as any;
|
|
expect(getEntryPointFormat(fs, entryPoint, 'browser')).toBeUndefined();
|
|
});
|
|
});
|
|
});
|
|
|
|
export function createPackageJson(
|
|
entryPointName: string, {excludes, typingsProp = 'typings', typingsIsArray, version}: {
|
|
excludes?: string[],
|
|
typingsProp?: string,
|
|
typingsIsArray?: boolean,
|
|
version?: string
|
|
} = {}): string {
|
|
const packageJson: any = {
|
|
name: (entryPointName === '') ? 'some_package' : `some_package/${entryPointName}`,
|
|
version,
|
|
[typingsProp]: typingsIsArray ? [`./${entryPointName}.d.ts`] : `./${entryPointName}.d.ts`,
|
|
fesm2015: `./fesm2015/${entryPointName}.js`,
|
|
esm2015: `./esm2015/${entryPointName}.js`,
|
|
es2015: `./es2015/${entryPointName}.js`,
|
|
fesm5: `./fesm5/${entryPointName}.js`,
|
|
esm5: `./esm5/${entryPointName}.js`,
|
|
main: `./bundles/${entryPointName}/index.js`,
|
|
browser: `./bundles/${entryPointName}/index.js`,
|
|
module: './index.js',
|
|
};
|
|
if (excludes) {
|
|
excludes.forEach(exclude => delete packageJson[exclude]);
|
|
}
|
|
return JSON.stringify(packageJson);
|
|
}
|
|
|
|
export function loadPackageJson(fs: FileSystem, packagePath: string) {
|
|
return JSON.parse(fs.readFile(fs.resolve(packagePath + '/package.json')));
|
|
}
|