2018-08-09 10:59:10 -04:00
|
|
|
/**
|
|
|
|
* @license
|
2020-05-19 15:08:49 -04:00
|
|
|
* Copyright Google LLC All Rights Reserved.
|
2018-08-09 10:59:10 -04:00
|
|
|
*
|
|
|
|
* 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
|
|
|
|
*/
|
2019-08-29 11:47:54 -04:00
|
|
|
|
|
|
|
import {DepGraph} from 'dependency-graph';
|
|
|
|
|
2020-04-06 03:30:08 -04:00
|
|
|
import {absoluteFrom, AbsoluteFsPath, FileSystem, getFileSystem, relativeFrom} from '../../../src/ngtsc/file_system';
|
2019-06-06 15:22:32 -04:00
|
|
|
import {runInEachFileSystem} from '../../../src/ngtsc/file_system/testing';
|
2020-04-07 12:47:46 -04:00
|
|
|
import {DependencyInfo, EntryPointWithDependencies} from '../../src/dependencies/dependency_host';
|
2019-04-28 15:47:57 -04:00
|
|
|
import {DependencyResolver, SortedEntryPointsInfo} from '../../src/dependencies/dependency_resolver';
|
2020-01-08 12:10:25 -05:00
|
|
|
import {DtsDependencyHost} from '../../src/dependencies/dts_dependency_host';
|
2019-04-28 15:47:57 -04:00
|
|
|
import {EsmDependencyHost} from '../../src/dependencies/esm_dependency_host';
|
|
|
|
import {ModuleResolver} from '../../src/dependencies/module_resolver';
|
2020-02-25 10:51:54 -05:00
|
|
|
import {NgccConfiguration} from '../../src/packages/configuration';
|
2018-08-09 10:59:10 -04:00
|
|
|
import {EntryPoint} from '../../src/packages/entry_point';
|
2019-03-29 06:13:14 -04:00
|
|
|
import {MockLogger} from '../helpers/mock_logger';
|
2018-08-09 10:59:10 -04:00
|
|
|
|
2019-08-29 11:47:54 -04:00
|
|
|
|
2019-06-06 15:22:32 -04:00
|
|
|
interface DepMap {
|
2020-02-25 10:51:54 -05:00
|
|
|
[path: string]: {resolved: string[], missing: string[], deepImports?: AbsoluteFsPath[]};
|
2019-06-06 15:22:32 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
runInEachFileSystem(() => {
|
|
|
|
describe('DependencyResolver', () => {
|
|
|
|
let _: typeof absoluteFrom;
|
|
|
|
let host: EsmDependencyHost;
|
2019-12-19 17:43:13 -05:00
|
|
|
let dtsHost: EsmDependencyHost;
|
2019-06-06 15:22:32 -04:00
|
|
|
let resolver: DependencyResolver;
|
|
|
|
let fs: FileSystem;
|
2020-02-25 10:51:54 -05:00
|
|
|
let config: NgccConfiguration;
|
|
|
|
let logger: MockLogger;
|
2019-06-06 15:22:32 -04:00
|
|
|
let moduleResolver: ModuleResolver;
|
|
|
|
|
|
|
|
beforeEach(() => {
|
|
|
|
_ = absoluteFrom;
|
|
|
|
fs = getFileSystem();
|
2020-02-25 10:51:54 -05:00
|
|
|
config = new NgccConfiguration(fs, _('/'));
|
|
|
|
logger = new MockLogger();
|
2019-06-06 15:22:32 -04:00
|
|
|
moduleResolver = new ModuleResolver(fs);
|
|
|
|
host = new EsmDependencyHost(fs, moduleResolver);
|
2020-01-08 12:10:25 -05:00
|
|
|
dtsHost = new DtsDependencyHost(fs);
|
2020-02-25 10:51:54 -05:00
|
|
|
resolver = new DependencyResolver(fs, logger, config, {esm5: host, esm2015: host}, dtsHost);
|
2019-03-20 09:47:58 -04:00
|
|
|
});
|
|
|
|
|
2019-06-06 15:22:32 -04:00
|
|
|
describe('sortEntryPointsByDependency()', () => {
|
|
|
|
let first: EntryPoint;
|
|
|
|
let second: EntryPoint;
|
|
|
|
let third: EntryPoint;
|
|
|
|
let fourth: EntryPoint;
|
|
|
|
let fifth: EntryPoint;
|
2019-10-02 03:32:57 -04:00
|
|
|
let sixthIgnoreMissing: EntryPoint;
|
2019-06-06 15:22:32 -04:00
|
|
|
let dependencies: DepMap;
|
2019-12-19 17:43:13 -05:00
|
|
|
let dtsDependencies: DepMap;
|
2019-06-06 15:22:32 -04:00
|
|
|
|
|
|
|
beforeEach(() => {
|
|
|
|
first = {
|
2020-02-25 10:51:54 -05:00
|
|
|
name: 'first',
|
2019-06-06 15:22:32 -04:00
|
|
|
path: _('/first'),
|
2020-06-08 15:04:35 -04:00
|
|
|
packageName: 'first',
|
2020-06-08 15:04:28 -04:00
|
|
|
packagePath: _('/first'),
|
2019-06-06 15:22:32 -04:00
|
|
|
packageJson: {esm5: './index.js'},
|
2020-06-08 15:04:28 -04:00
|
|
|
typings: _('/first/index.d.ts'),
|
2019-10-02 03:32:57 -04:00
|
|
|
compiledByAngular: true,
|
|
|
|
ignoreMissingDependencies: false,
|
2019-06-06 15:22:32 -04:00
|
|
|
} as EntryPoint;
|
|
|
|
second = {
|
2020-06-08 15:04:35 -04:00
|
|
|
name: 'second',
|
2019-06-06 15:22:32 -04:00
|
|
|
path: _('/second'),
|
2020-06-08 15:04:35 -04:00
|
|
|
packageName: 'second',
|
2020-06-08 15:04:28 -04:00
|
|
|
packagePath: _('/second'),
|
2019-06-06 15:22:32 -04:00
|
|
|
packageJson: {esm2015: './sub/index.js'},
|
2020-06-08 15:04:28 -04:00
|
|
|
typings: _('/second/sub/index.d.ts'),
|
2019-10-02 03:32:57 -04:00
|
|
|
compiledByAngular: true,
|
|
|
|
ignoreMissingDependencies: false,
|
2019-06-06 15:22:32 -04:00
|
|
|
} as EntryPoint;
|
|
|
|
third = {
|
2020-06-08 15:04:35 -04:00
|
|
|
name: 'third',
|
2019-06-06 15:22:32 -04:00
|
|
|
path: _('/third'),
|
2020-06-08 15:04:35 -04:00
|
|
|
packageName: 'third',
|
2020-06-08 15:04:28 -04:00
|
|
|
packagePath: _('/third'),
|
2019-06-06 15:22:32 -04:00
|
|
|
packageJson: {fesm5: './index.js'},
|
2020-06-08 15:04:28 -04:00
|
|
|
typings: _('/third/index.d.ts'),
|
2019-10-02 03:32:57 -04:00
|
|
|
compiledByAngular: true,
|
|
|
|
ignoreMissingDependencies: false,
|
2019-06-06 15:22:32 -04:00
|
|
|
} as EntryPoint;
|
|
|
|
fourth = {
|
2020-06-08 15:04:35 -04:00
|
|
|
name: 'fourth',
|
2019-06-06 15:22:32 -04:00
|
|
|
path: _('/fourth'),
|
2020-06-08 15:04:35 -04:00
|
|
|
packageName: 'fourth',
|
2020-06-08 15:04:28 -04:00
|
|
|
packagePath: _('/fourth'),
|
2019-06-06 15:22:32 -04:00
|
|
|
packageJson: {fesm2015: './sub2/index.js'},
|
2020-06-08 15:04:28 -04:00
|
|
|
typings: _('/fourth/sub2/index.d.ts'),
|
2019-10-02 03:32:57 -04:00
|
|
|
compiledByAngular: true,
|
|
|
|
ignoreMissingDependencies: false,
|
2019-06-06 15:22:32 -04:00
|
|
|
} as EntryPoint;
|
|
|
|
fifth = {
|
2020-06-08 15:04:35 -04:00
|
|
|
name: 'fifth',
|
2019-06-06 15:22:32 -04:00
|
|
|
path: _('/fifth'),
|
2020-06-08 15:04:35 -04:00
|
|
|
packageName: 'fifth',
|
2020-06-08 15:04:28 -04:00
|
|
|
packagePath: _('/fifth'),
|
2019-06-06 15:22:32 -04:00
|
|
|
packageJson: {module: './index.js'},
|
2020-06-08 15:04:28 -04:00
|
|
|
typings: _('/fifth/index.d.ts'),
|
2019-10-02 03:32:57 -04:00
|
|
|
compiledByAngular: true,
|
|
|
|
ignoreMissingDependencies: false,
|
|
|
|
} as EntryPoint;
|
|
|
|
|
|
|
|
sixthIgnoreMissing = {
|
2020-06-08 15:04:35 -04:00
|
|
|
name: 'sixth',
|
2019-10-02 03:32:57 -04:00
|
|
|
path: _('/sixth'),
|
2020-06-08 15:04:35 -04:00
|
|
|
packageName: 'sixth',
|
2020-06-08 15:04:28 -04:00
|
|
|
packagePath: _('/sixth'),
|
2019-10-02 03:32:57 -04:00
|
|
|
packageJson: {module: './index.js'},
|
2020-06-08 15:04:28 -04:00
|
|
|
typings: _('/sixth/index.d.ts'),
|
2019-10-02 03:32:57 -04:00
|
|
|
compiledByAngular: true,
|
|
|
|
ignoreMissingDependencies: true,
|
2019-06-06 15:22:32 -04:00
|
|
|
} as EntryPoint;
|
|
|
|
|
|
|
|
dependencies = {
|
2019-12-19 17:43:12 -05:00
|
|
|
[_('/first/index.js')]:
|
|
|
|
{resolved: [second.path, third.path, _('/ignored-1')], missing: []},
|
2019-06-06 15:22:32 -04:00
|
|
|
[_('/second/sub/index.js')]: {resolved: [third.path, fifth.path], missing: []},
|
2019-12-19 17:43:12 -05:00
|
|
|
[_('/third/index.js')]: {resolved: [fourth.path, _('/ignored-2')], missing: []},
|
2019-06-06 15:22:32 -04:00
|
|
|
[_('/fourth/sub2/index.js')]: {resolved: [fifth.path], missing: []},
|
|
|
|
[_('/fifth/index.js')]: {resolved: [], missing: []},
|
|
|
|
};
|
2019-12-19 17:43:13 -05:00
|
|
|
dtsDependencies = {
|
|
|
|
[_('/first/index.d.ts')]:
|
|
|
|
{resolved: [second.path, third.path, _('/ignored-1')], missing: []},
|
|
|
|
[_('/second/sub/index.d.ts')]: {resolved: [third.path, fifth.path], missing: []},
|
|
|
|
[_('/third/index.d.ts')]: {resolved: [fourth.path, _('/ignored-2')], missing: []},
|
|
|
|
[_('/fourth/sub2/index.d.ts')]: {resolved: [fifth.path], missing: []},
|
|
|
|
[_('/fifth/index.d.ts')]: {resolved: [], missing: []},
|
|
|
|
};
|
2019-06-06 15:22:32 -04:00
|
|
|
});
|
|
|
|
|
|
|
|
it('should order the entry points by their dependency on each other', () => {
|
2019-12-19 17:43:12 -05:00
|
|
|
spyOn(host, 'collectDependencies')
|
|
|
|
.and.callFake(createFakeComputeDependencies(dependencies));
|
2019-12-19 17:43:13 -05:00
|
|
|
spyOn(dtsHost, 'collectDependencies')
|
|
|
|
.and.callFake(createFakeComputeDependencies(dtsDependencies));
|
2020-04-07 12:47:46 -04:00
|
|
|
const result = resolver.sortEntryPointsByDependency(
|
|
|
|
getEntryPointsWithDeps(resolver, [fifth, first, fourth, second, third]));
|
2019-06-06 15:22:32 -04:00
|
|
|
expect(result.entryPoints).toEqual([fifth, fourth, third, second, first]);
|
|
|
|
});
|
|
|
|
|
|
|
|
it('should remove entry-points that have missing direct dependencies', () => {
|
2019-12-19 17:43:12 -05:00
|
|
|
spyOn(host, 'collectDependencies').and.callFake(createFakeComputeDependencies({
|
|
|
|
[_('/first/index.js')]: {resolved: [], missing: [_('/missing')]},
|
2019-06-06 15:22:32 -04:00
|
|
|
[_('/second/sub/index.js')]: {resolved: [], missing: []},
|
|
|
|
}));
|
2019-12-19 17:43:13 -05:00
|
|
|
spyOn(dtsHost, 'collectDependencies').and.callFake(createFakeComputeDependencies({
|
|
|
|
[_('/first/index.d.ts')]: {resolved: [], missing: [_('/missing')]},
|
|
|
|
[_('/second/sub/index.d.ts')]: {resolved: [], missing: []},
|
|
|
|
}));
|
2020-04-07 12:47:46 -04:00
|
|
|
const result =
|
|
|
|
resolver.sortEntryPointsByDependency(getEntryPointsWithDeps(resolver, [first, second]));
|
2019-06-06 15:22:32 -04:00
|
|
|
expect(result.entryPoints).toEqual([second]);
|
|
|
|
expect(result.invalidEntryPoints).toEqual([
|
2019-12-19 17:43:12 -05:00
|
|
|
{entryPoint: first, missingDependencies: [_('/missing')]},
|
2019-06-06 15:22:32 -04:00
|
|
|
]);
|
|
|
|
});
|
|
|
|
|
|
|
|
it('should remove entry points that depended upon an invalid entry-point', () => {
|
2019-12-19 17:43:12 -05:00
|
|
|
spyOn(host, 'collectDependencies').and.callFake(createFakeComputeDependencies({
|
2019-06-06 15:22:32 -04:00
|
|
|
[_('/first/index.js')]: {resolved: [second.path, third.path], missing: []},
|
2019-12-19 17:43:12 -05:00
|
|
|
[_('/second/sub/index.js')]: {resolved: [], missing: [_('/missing')]},
|
2019-06-06 15:22:32 -04:00
|
|
|
[_('/third/index.js')]: {resolved: [], missing: []},
|
|
|
|
}));
|
2019-12-19 17:43:13 -05:00
|
|
|
spyOn(dtsHost, 'collectDependencies').and.callFake(createFakeComputeDependencies({
|
|
|
|
[_('/first/index.d.ts')]: {resolved: [second.path, third.path], missing: []},
|
|
|
|
[_('/second/sub/index.d.ts')]: {resolved: [], missing: [_('/missing')]},
|
|
|
|
[_('/third/index.d.ts')]: {resolved: [], missing: []},
|
|
|
|
}));
|
2019-06-06 15:22:32 -04:00
|
|
|
// Note that we will process `first` before `second`, which has the missing dependency.
|
2020-04-07 12:47:46 -04:00
|
|
|
const result = resolver.sortEntryPointsByDependency(
|
|
|
|
getEntryPointsWithDeps(resolver, [first, second, third]));
|
2019-06-06 15:22:32 -04:00
|
|
|
expect(result.entryPoints).toEqual([third]);
|
|
|
|
expect(result.invalidEntryPoints).toEqual([
|
2019-12-19 17:43:12 -05:00
|
|
|
{entryPoint: second, missingDependencies: [_('/missing')]},
|
|
|
|
{entryPoint: first, missingDependencies: [_('/missing')]},
|
2019-06-06 15:22:32 -04:00
|
|
|
]);
|
|
|
|
});
|
|
|
|
|
|
|
|
it('should remove entry points that will depend upon an invalid entry-point', () => {
|
2019-12-19 17:43:12 -05:00
|
|
|
spyOn(host, 'collectDependencies').and.callFake(createFakeComputeDependencies({
|
2019-06-06 15:22:32 -04:00
|
|
|
[_('/first/index.js')]: {resolved: [second.path, third.path], missing: []},
|
2019-12-19 17:43:12 -05:00
|
|
|
[_('/second/sub/index.js')]: {resolved: [], missing: [_('/missing')]},
|
2019-06-06 15:22:32 -04:00
|
|
|
[_('/third/index.js')]: {resolved: [], missing: []},
|
|
|
|
}));
|
2019-12-19 17:43:13 -05:00
|
|
|
spyOn(dtsHost, 'collectDependencies').and.callFake(createFakeComputeDependencies({
|
|
|
|
[_('/first/index.d.ts')]: {resolved: [second.path, third.path], missing: []},
|
|
|
|
[_('/second/sub/index.d.ts')]: {resolved: [], missing: [_('/missing')]},
|
|
|
|
[_('/third/index.d.ts')]: {resolved: [], missing: []},
|
|
|
|
}));
|
2019-06-06 15:22:32 -04:00
|
|
|
// Note that we will process `first` after `second`, which has the missing dependency.
|
2020-04-07 12:47:46 -04:00
|
|
|
const result = resolver.sortEntryPointsByDependency(
|
|
|
|
getEntryPointsWithDeps(resolver, [second, first, third]));
|
2019-06-06 15:22:32 -04:00
|
|
|
expect(result.entryPoints).toEqual([third]);
|
|
|
|
expect(result.invalidEntryPoints).toEqual([
|
2019-12-19 17:43:12 -05:00
|
|
|
{entryPoint: second, missingDependencies: [_('/missing')]},
|
2019-06-06 15:22:32 -04:00
|
|
|
{entryPoint: first, missingDependencies: [second.path]},
|
|
|
|
]);
|
|
|
|
});
|
|
|
|
|
2019-10-02 03:32:57 -04:00
|
|
|
it('should cope with entry points that will depend upon an invalid entry-point, when told to ignore missing dependencies',
|
|
|
|
() => {
|
2019-12-19 17:43:12 -05:00
|
|
|
spyOn(host, 'collectDependencies').and.callFake(createFakeComputeDependencies({
|
2019-10-02 03:32:57 -04:00
|
|
|
[_('/first/index.js')]: {resolved: [sixthIgnoreMissing.path], missing: []},
|
2019-12-19 17:43:12 -05:00
|
|
|
[_('/sixth/index.js')]: {resolved: [], missing: [_('/missing')]},
|
2019-10-02 03:32:57 -04:00
|
|
|
}));
|
2019-12-19 17:43:13 -05:00
|
|
|
spyOn(dtsHost, 'collectDependencies').and.callFake(createFakeComputeDependencies({
|
|
|
|
[_('/first/index.d.ts')]: {resolved: [sixthIgnoreMissing.path], missing: []},
|
|
|
|
[_('/sixth/index.d.ts')]: {resolved: [], missing: [_('/missing')]},
|
|
|
|
}));
|
2019-10-02 03:32:57 -04:00
|
|
|
// Note that we will process `first` after `second`, which has the missing dependency.
|
2020-04-07 12:47:46 -04:00
|
|
|
const result = resolver.sortEntryPointsByDependency(
|
|
|
|
getEntryPointsWithDeps(resolver, [sixthIgnoreMissing, first]));
|
2019-10-02 03:32:57 -04:00
|
|
|
expect(result.entryPoints).toEqual([sixthIgnoreMissing, first]);
|
|
|
|
expect(result.invalidEntryPoints).toEqual([]);
|
|
|
|
});
|
|
|
|
|
|
|
|
it('should not transitively ignore missing dependencies', () => {
|
2019-12-19 17:43:12 -05:00
|
|
|
spyOn(host, 'collectDependencies').and.callFake(createFakeComputeDependencies({
|
|
|
|
[_('/first/index.js')]: {resolved: [], missing: [_('/missing')]},
|
2019-10-02 03:32:57 -04:00
|
|
|
[_('/second/sub/index.js')]: {resolved: [first.path], missing: []},
|
|
|
|
[_('/sixth/index.js')]: {resolved: [second.path], missing: []},
|
|
|
|
}));
|
2019-12-19 17:43:13 -05:00
|
|
|
spyOn(dtsHost, 'collectDependencies').and.callFake(createFakeComputeDependencies({
|
|
|
|
[_('/first/index.d.ts')]: {resolved: [], missing: [_('/missing')]},
|
|
|
|
[_('/second/sub/index.d.ts')]: {resolved: [first.path], missing: []},
|
|
|
|
[_('/sixth/index.d.ts')]: {resolved: [second.path], missing: []},
|
|
|
|
}));
|
2020-04-07 12:47:46 -04:00
|
|
|
const result = resolver.sortEntryPointsByDependency(
|
|
|
|
getEntryPointsWithDeps(resolver, [first, second, sixthIgnoreMissing]));
|
2019-10-02 03:32:57 -04:00
|
|
|
// sixth has no missing dependencies, but it has _invalid_ dependencies, so it's not
|
|
|
|
// compiled.
|
|
|
|
expect(result.entryPoints).toEqual([]);
|
|
|
|
});
|
|
|
|
|
2019-06-26 04:16:15 -04:00
|
|
|
it('should cope with entry points having multiple indirect missing dependencies', () => {
|
2019-12-19 17:43:12 -05:00
|
|
|
spyOn(host, 'collectDependencies').and.callFake(createFakeComputeDependencies({
|
|
|
|
[_('/first/index.js')]: {resolved: [], missing: [_('/missing1')]},
|
|
|
|
[_('/second/sub/index.js')]: {resolved: [], missing: [_('/missing2')]},
|
2019-06-26 04:16:15 -04:00
|
|
|
[_('/third/index.js')]: {resolved: [first.path, second.path], missing: []},
|
|
|
|
}));
|
2019-12-19 17:43:13 -05:00
|
|
|
spyOn(dtsHost, 'collectDependencies').and.callFake(createFakeComputeDependencies({
|
|
|
|
[_('/first/index.d.ts')]: {resolved: [], missing: [_('/missing1')]},
|
|
|
|
[_('/second/sub/index.d.ts')]: {resolved: [], missing: [_('/missing2')]},
|
|
|
|
[_('/third/index.d.ts')]: {resolved: [first.path, second.path], missing: []},
|
|
|
|
}));
|
2020-04-07 12:47:46 -04:00
|
|
|
const result = resolver.sortEntryPointsByDependency(
|
|
|
|
getEntryPointsWithDeps(resolver, [first, second, third]));
|
2019-06-26 04:16:15 -04:00
|
|
|
expect(result.entryPoints).toEqual([]);
|
|
|
|
expect(result.invalidEntryPoints).toEqual([
|
2019-12-19 17:43:12 -05:00
|
|
|
{entryPoint: first, missingDependencies: [_('/missing1')]},
|
|
|
|
{entryPoint: second, missingDependencies: [_('/missing2')]},
|
2019-06-26 04:16:15 -04:00
|
|
|
{entryPoint: third, missingDependencies: [first.path]},
|
|
|
|
]);
|
|
|
|
});
|
|
|
|
|
2020-02-25 10:51:54 -05:00
|
|
|
it('should log a warning for deep imports', () => {
|
|
|
|
spyOn(host, 'collectDependencies').and.callFake(createFakeComputeDependencies({
|
|
|
|
[_('/first/index.js')]: {resolved: [], missing: [], deepImports: [_('/deep/one')]},
|
|
|
|
}));
|
|
|
|
spyOn(dtsHost, 'collectDependencies').and.callFake(createFakeComputeDependencies({
|
|
|
|
[_('/first/index.d.ts')]: {resolved: [], missing: []},
|
|
|
|
}));
|
2020-04-07 12:47:46 -04:00
|
|
|
const result =
|
|
|
|
resolver.sortEntryPointsByDependency(getEntryPointsWithDeps(resolver, [first]));
|
2020-02-25 10:51:54 -05:00
|
|
|
expect(result.entryPoints).toEqual([first]);
|
|
|
|
expect(logger.logs.warn).toEqual([[
|
2020-04-06 03:30:08 -04:00
|
|
|
`Entry point 'first' contains deep imports into '${
|
|
|
|
_('/deep/one')}'. This is probably not a problem, but may cause the compilation of entry points to be out of order.`
|
2020-02-25 10:51:54 -05:00
|
|
|
]]);
|
|
|
|
});
|
|
|
|
|
|
|
|
it('should not log a warning for ignored deep imports', () => {
|
|
|
|
spyOn(host, 'collectDependencies').and.callFake(createFakeComputeDependencies({
|
2020-06-08 15:04:38 -04:00
|
|
|
[_('/project/node_modules/test-package/test-entry-point/index.js')]: {
|
2020-02-25 10:51:54 -05:00
|
|
|
resolved: [],
|
|
|
|
missing: [],
|
|
|
|
deepImports: [
|
|
|
|
_('/project/node_modules/deep/one'), _('/project/node_modules/deep/two'),
|
|
|
|
_('/project/node_modules/deeper/one'), _('/project/node_modules/deeper/two')
|
|
|
|
]
|
|
|
|
},
|
|
|
|
}));
|
|
|
|
spyOn(dtsHost, 'collectDependencies').and.callFake(createFakeComputeDependencies({
|
2020-06-08 15:04:38 -04:00
|
|
|
[_('/project/node_modules/test-package/test-entry-point/index.d.ts')]: {
|
|
|
|
resolved: [],
|
|
|
|
missing: [],
|
|
|
|
},
|
2020-02-25 10:51:54 -05:00
|
|
|
}));
|
|
|
|
// Setup the configuration to ignore deep imports that contain either "deep/" or "two".
|
|
|
|
fs.ensureDir(_('/project'));
|
|
|
|
fs.writeFile(
|
|
|
|
_('/project/ngcc.config.js'),
|
|
|
|
`module.exports = { packages: { 'test-package': { ignorableDeepImportMatchers: [/deep\\//, /two/] } } };`);
|
|
|
|
config = new NgccConfiguration(fs, _('/project'));
|
|
|
|
resolver = new DependencyResolver(fs, logger, config, {esm5: host, esm2015: host}, dtsHost);
|
|
|
|
const testEntryPoint = {
|
2020-06-08 15:04:38 -04:00
|
|
|
name: 'test-package/test-entry-point',
|
|
|
|
path: _('/project/node_modules/test-package/test-entry-point'),
|
2020-06-08 15:04:35 -04:00
|
|
|
packageName: 'test-package',
|
2020-06-08 15:04:28 -04:00
|
|
|
packagePath: _('/project/node_modules/test-package'),
|
2020-02-25 10:51:54 -05:00
|
|
|
packageJson: {esm5: './index.js'},
|
2020-06-08 15:04:38 -04:00
|
|
|
typings: _('/project/node_modules/test-package/test-entry-point/index.d.ts'),
|
2020-02-25 10:51:54 -05:00
|
|
|
compiledByAngular: true,
|
|
|
|
ignoreMissingDependencies: false,
|
|
|
|
} as EntryPoint;
|
|
|
|
|
2020-04-07 12:47:46 -04:00
|
|
|
const result = resolver.sortEntryPointsByDependency(
|
|
|
|
getEntryPointsWithDeps(resolver, [testEntryPoint]));
|
2020-02-25 10:51:54 -05:00
|
|
|
expect(result.entryPoints).toEqual([testEntryPoint]);
|
|
|
|
expect(logger.logs.warn).toEqual([[
|
2020-06-08 15:04:38 -04:00
|
|
|
`Entry point 'test-package/test-entry-point' contains deep imports into '${
|
2020-04-06 03:30:08 -04:00
|
|
|
_('/project/node_modules/deeper/one')}'. This is probably not a problem, but may cause the compilation of entry points to be out of order.`
|
2020-02-25 10:51:54 -05:00
|
|
|
]]);
|
|
|
|
});
|
|
|
|
|
2019-06-06 15:22:32 -04:00
|
|
|
it('should error if the entry point does not have a suitable format', () => {
|
2020-04-07 12:47:46 -04:00
|
|
|
expect(() => resolver.sortEntryPointsByDependency(getEntryPointsWithDeps(resolver, [
|
2020-04-06 03:30:08 -04:00
|
|
|
{path: '/first', packageJson: {}, compiledByAngular: true} as EntryPoint
|
2020-04-07 12:47:46 -04:00
|
|
|
]))).toThrowError(`There is no appropriate source code format in '/first' entry-point.`);
|
2019-06-06 15:22:32 -04:00
|
|
|
});
|
|
|
|
|
|
|
|
it('should error if there is no appropriate DependencyHost for the given formats', () => {
|
2020-02-25 10:51:54 -05:00
|
|
|
resolver = new DependencyResolver(fs, new MockLogger(), config, {esm2015: host}, host);
|
2020-04-07 12:47:46 -04:00
|
|
|
expect(
|
|
|
|
() => resolver.sortEntryPointsByDependency(getEntryPointsWithDeps(resolver, [first])))
|
2019-06-06 15:22:32 -04:00
|
|
|
.toThrowError(
|
2020-04-06 03:30:08 -04:00
|
|
|
`Could not find a suitable format for computing dependencies of entry-point: '${
|
|
|
|
first.path}'.`);
|
2019-06-06 15:22:32 -04:00
|
|
|
});
|
|
|
|
|
|
|
|
it('should capture any dependencies that were ignored', () => {
|
2019-12-19 17:43:12 -05:00
|
|
|
spyOn(host, 'collectDependencies')
|
|
|
|
.and.callFake(createFakeComputeDependencies(dependencies));
|
2019-12-19 17:43:13 -05:00
|
|
|
spyOn(dtsHost, 'collectDependencies')
|
|
|
|
.and.callFake(createFakeComputeDependencies(dtsDependencies));
|
2020-04-07 12:47:46 -04:00
|
|
|
const result = resolver.sortEntryPointsByDependency(
|
|
|
|
getEntryPointsWithDeps(resolver, [fifth, first, fourth, second, third]));
|
2019-06-06 15:22:32 -04:00
|
|
|
expect(result.ignoredDependencies).toEqual([
|
2019-12-19 17:43:12 -05:00
|
|
|
{entryPoint: first, dependencyPath: _('/ignored-1')},
|
|
|
|
{entryPoint: third, dependencyPath: _('/ignored-2')},
|
2019-06-06 15:22:32 -04:00
|
|
|
]);
|
|
|
|
});
|
|
|
|
|
2019-08-29 11:47:54 -04:00
|
|
|
it('should return the computed dependency graph', () => {
|
2019-12-19 17:43:12 -05:00
|
|
|
spyOn(host, 'collectDependencies')
|
|
|
|
.and.callFake(createFakeComputeDependencies(dependencies));
|
2019-12-19 17:43:13 -05:00
|
|
|
spyOn(dtsHost, 'collectDependencies')
|
|
|
|
.and.callFake(createFakeComputeDependencies(dtsDependencies));
|
2020-04-07 12:47:46 -04:00
|
|
|
const result = resolver.sortEntryPointsByDependency(
|
|
|
|
getEntryPointsWithDeps(resolver, [fifth, first, fourth, second, third]));
|
2019-08-29 11:47:54 -04:00
|
|
|
|
|
|
|
expect(result.graph).toEqual(jasmine.any(DepGraph));
|
|
|
|
expect(result.graph.size()).toBe(5);
|
|
|
|
expect(result.graph.dependenciesOf(third.path)).toEqual([fifth.path, fourth.path]);
|
|
|
|
});
|
|
|
|
|
2019-06-06 15:22:32 -04:00
|
|
|
it('should only return dependencies of the target, if provided', () => {
|
2019-12-19 17:43:12 -05:00
|
|
|
spyOn(host, 'collectDependencies')
|
|
|
|
.and.callFake(createFakeComputeDependencies(dependencies));
|
2019-12-19 17:43:13 -05:00
|
|
|
spyOn(dtsHost, 'collectDependencies')
|
|
|
|
.and.callFake(createFakeComputeDependencies(dtsDependencies));
|
2020-04-07 12:47:46 -04:00
|
|
|
const entryPoints = getEntryPointsWithDeps(resolver, [fifth, first, fourth, second, third]);
|
2019-06-06 15:22:32 -04:00
|
|
|
let sorted: SortedEntryPointsInfo;
|
|
|
|
|
|
|
|
sorted = resolver.sortEntryPointsByDependency(entryPoints, first);
|
|
|
|
expect(sorted.entryPoints).toEqual([fifth, fourth, third, second, first]);
|
|
|
|
sorted = resolver.sortEntryPointsByDependency(entryPoints, second);
|
|
|
|
expect(sorted.entryPoints).toEqual([fifth, fourth, third, second]);
|
|
|
|
sorted = resolver.sortEntryPointsByDependency(entryPoints, third);
|
|
|
|
expect(sorted.entryPoints).toEqual([fifth, fourth, third]);
|
|
|
|
sorted = resolver.sortEntryPointsByDependency(entryPoints, fourth);
|
|
|
|
expect(sorted.entryPoints).toEqual([fifth, fourth]);
|
|
|
|
sorted = resolver.sortEntryPointsByDependency(entryPoints, fifth);
|
|
|
|
expect(sorted.entryPoints).toEqual([fifth]);
|
|
|
|
});
|
|
|
|
|
2019-07-27 15:02:04 -04:00
|
|
|
it('should not process the provided target if it has missing dependencies', () => {
|
2019-12-19 17:43:12 -05:00
|
|
|
spyOn(host, 'collectDependencies').and.callFake(createFakeComputeDependencies({
|
|
|
|
[_('/first/index.js')]: {resolved: [], missing: [_('/missing')]},
|
2019-07-27 15:02:04 -04:00
|
|
|
}));
|
2019-12-19 17:43:13 -05:00
|
|
|
spyOn(dtsHost, 'collectDependencies').and.callFake(createFakeComputeDependencies({
|
|
|
|
[_('/first/index.d.ts')]: {resolved: [], missing: [_('/missing')]},
|
|
|
|
}));
|
2020-04-07 12:47:46 -04:00
|
|
|
const entryPoints = getEntryPointsWithDeps(resolver, [first]);
|
2019-07-27 15:02:04 -04:00
|
|
|
let sorted: SortedEntryPointsInfo;
|
|
|
|
|
|
|
|
sorted = resolver.sortEntryPointsByDependency(entryPoints, first);
|
|
|
|
expect(sorted.entryPoints).toEqual([]);
|
|
|
|
expect(sorted.invalidEntryPoints[0].entryPoint).toEqual(first);
|
2019-12-19 17:43:12 -05:00
|
|
|
expect(sorted.invalidEntryPoints[0].missingDependencies).toEqual([_('/missing')]);
|
2019-07-27 15:02:04 -04:00
|
|
|
});
|
|
|
|
|
2019-07-27 15:37:04 -04:00
|
|
|
it('should not consider builtin NodeJS modules as missing dependency', () => {
|
2019-12-19 17:43:12 -05:00
|
|
|
spyOn(host, 'collectDependencies').and.callFake(createFakeComputeDependencies({
|
2019-07-27 15:37:04 -04:00
|
|
|
[_('/first/index.js')]: {resolved: [], missing: ['fs']},
|
|
|
|
}));
|
2019-12-19 17:43:13 -05:00
|
|
|
spyOn(dtsHost, 'collectDependencies').and.callFake(createFakeComputeDependencies({
|
|
|
|
[_('/first/index.d.ts')]: {resolved: [], missing: ['fs']},
|
|
|
|
}));
|
2020-04-07 12:47:46 -04:00
|
|
|
const entryPoints = getEntryPointsWithDeps(resolver, [first]);
|
2019-07-27 15:37:04 -04:00
|
|
|
let sorted: SortedEntryPointsInfo;
|
|
|
|
|
|
|
|
sorted = resolver.sortEntryPointsByDependency(entryPoints, first);
|
|
|
|
expect(sorted.entryPoints).toEqual([first]);
|
|
|
|
expect(sorted.invalidEntryPoints).toEqual([]);
|
|
|
|
expect(sorted.ignoredDependencies).toEqual([]);
|
|
|
|
});
|
|
|
|
|
2019-06-06 15:22:32 -04:00
|
|
|
it('should use the appropriate DependencyHost for each entry-point', () => {
|
|
|
|
const esm5Host = new EsmDependencyHost(fs, moduleResolver);
|
|
|
|
const esm2015Host = new EsmDependencyHost(fs, moduleResolver);
|
2020-01-08 12:10:25 -05:00
|
|
|
const dtsHost = new DtsDependencyHost(fs);
|
2019-12-19 17:43:13 -05:00
|
|
|
resolver = new DependencyResolver(
|
2020-02-25 10:51:54 -05:00
|
|
|
fs, new MockLogger(), config, {esm5: esm5Host, esm2015: esm2015Host}, dtsHost);
|
2019-12-19 17:43:12 -05:00
|
|
|
spyOn(esm5Host, 'collectDependencies')
|
2019-06-06 15:22:32 -04:00
|
|
|
.and.callFake(createFakeComputeDependencies(dependencies));
|
2019-12-19 17:43:12 -05:00
|
|
|
spyOn(esm2015Host, 'collectDependencies')
|
2019-06-06 15:22:32 -04:00
|
|
|
.and.callFake(createFakeComputeDependencies(dependencies));
|
2019-12-19 17:43:13 -05:00
|
|
|
spyOn(dtsHost, 'collectDependencies')
|
|
|
|
.and.callFake(createFakeComputeDependencies(dtsDependencies));
|
2020-04-07 12:47:46 -04:00
|
|
|
const result = resolver.sortEntryPointsByDependency(
|
|
|
|
getEntryPointsWithDeps(resolver, [fifth, first, fourth, second, third]));
|
2019-06-06 15:22:32 -04:00
|
|
|
expect(result.entryPoints).toEqual([fifth, fourth, third, second, first]);
|
|
|
|
|
2019-12-19 17:43:12 -05:00
|
|
|
expect(esm5Host.collectDependencies)
|
|
|
|
.toHaveBeenCalledWith(fs.resolve(first.path, 'index.js'), jasmine.any(Object));
|
|
|
|
expect(esm5Host.collectDependencies)
|
|
|
|
.not.toHaveBeenCalledWith(fs.resolve(second.path, 'sub/index.js'), jasmine.any(Object));
|
|
|
|
expect(esm5Host.collectDependencies)
|
|
|
|
.toHaveBeenCalledWith(fs.resolve(third.path, 'index.js'), jasmine.any(Object));
|
|
|
|
expect(esm5Host.collectDependencies)
|
|
|
|
.not.toHaveBeenCalledWith(
|
|
|
|
fs.resolve(fourth.path, 'sub2/index.js'), jasmine.any(Object));
|
|
|
|
expect(esm5Host.collectDependencies)
|
|
|
|
.toHaveBeenCalledWith(fs.resolve(fifth.path, 'index.js'), jasmine.any(Object));
|
|
|
|
|
|
|
|
expect(esm2015Host.collectDependencies)
|
|
|
|
.not.toHaveBeenCalledWith(fs.resolve(first.path, 'index.js'), jasmine.any(Object));
|
|
|
|
expect(esm2015Host.collectDependencies)
|
|
|
|
.toHaveBeenCalledWith(fs.resolve(second.path, 'sub/index.js'), jasmine.any(Object));
|
|
|
|
expect(esm2015Host.collectDependencies)
|
|
|
|
.not.toHaveBeenCalledWith(fs.resolve(third.path, 'index.js'), jasmine.any(Object));
|
|
|
|
expect(esm2015Host.collectDependencies)
|
|
|
|
.toHaveBeenCalledWith(fs.resolve(fourth.path, 'sub2/index.js'), jasmine.any(Object));
|
|
|
|
expect(esm2015Host.collectDependencies)
|
|
|
|
.not.toHaveBeenCalledWith(fs.resolve(fifth.path, 'index.js'), jasmine.any(Object));
|
2019-12-19 17:43:13 -05:00
|
|
|
|
|
|
|
expect(dtsHost.collectDependencies)
|
|
|
|
.toHaveBeenCalledWith(fs.resolve(first.path, 'index.d.ts'), jasmine.any(Object));
|
|
|
|
expect(dtsHost.collectDependencies)
|
|
|
|
.toHaveBeenCalledWith(fs.resolve(second.path, 'sub/index.d.ts'), jasmine.any(Object));
|
|
|
|
expect(dtsHost.collectDependencies)
|
|
|
|
.toHaveBeenCalledWith(fs.resolve(third.path, 'index.d.ts'), jasmine.any(Object));
|
|
|
|
expect(dtsHost.collectDependencies)
|
|
|
|
.toHaveBeenCalledWith(fs.resolve(fourth.path, 'sub2/index.d.ts'), jasmine.any(Object));
|
|
|
|
expect(dtsHost.collectDependencies)
|
|
|
|
.toHaveBeenCalledWith(fs.resolve(fifth.path, 'index.d.ts'), jasmine.any(Object));
|
|
|
|
});
|
|
|
|
|
|
|
|
it('should merge "typings-only" dependencies with source dependencies', () => {
|
|
|
|
spyOn(host, 'collectDependencies').and.callFake(createFakeComputeDependencies({
|
|
|
|
[_('/first/index.js')]: {resolved: [], missing: []},
|
|
|
|
[_('/second/sub/index.js')]: {resolved: [], missing: [_('/missing1')]},
|
|
|
|
[_('/third/index.js')]: {resolved: [first.path], missing: []},
|
|
|
|
}));
|
|
|
|
spyOn(dtsHost, 'collectDependencies').and.callFake(createFakeComputeDependencies({
|
|
|
|
[_('/first/index.d.ts')]: {resolved: [], missing: []},
|
|
|
|
[_('/second/sub/index.d.ts')]: {resolved: [], missing: [_('/missing2')]},
|
|
|
|
[_('/third/index.d.ts')]: {resolved: [second.path], missing: []},
|
|
|
|
}));
|
2020-04-07 12:47:46 -04:00
|
|
|
const entryPoints = getEntryPointsWithDeps(resolver, [first, second, third]);
|
2019-12-19 17:43:13 -05:00
|
|
|
const sorted = resolver.sortEntryPointsByDependency(entryPoints);
|
|
|
|
expect(sorted.entryPoints).toEqual([first]);
|
|
|
|
expect(sorted.invalidEntryPoints).toEqual([
|
|
|
|
{entryPoint: second, missingDependencies: [_('/missing1'), _('/missing2')]},
|
|
|
|
{entryPoint: third, missingDependencies: [_('/second')]},
|
|
|
|
]);
|
2019-06-06 15:22:32 -04:00
|
|
|
});
|
|
|
|
|
|
|
|
function createFakeComputeDependencies(deps: DepMap) {
|
2019-12-19 17:43:12 -05:00
|
|
|
return (entryPointPath: string, {dependencies, missing, deepImports}: DependencyInfo) => {
|
|
|
|
deps[entryPointPath].resolved.forEach(dep => dependencies.add(absoluteFrom(dep)));
|
|
|
|
deps[entryPointPath].missing.forEach(
|
|
|
|
dep => missing.add(fs.isRooted(dep) ? absoluteFrom(dep) : relativeFrom(dep)));
|
2020-02-25 10:51:54 -05:00
|
|
|
if (deps[entryPointPath].deepImports) {
|
2020-04-06 03:30:08 -04:00
|
|
|
deps[entryPointPath].deepImports!.forEach(dep => deepImports.add(dep));
|
2020-02-25 10:51:54 -05:00
|
|
|
}
|
2019-06-06 15:22:32 -04:00
|
|
|
return {dependencies, missing, deepImports};
|
|
|
|
};
|
|
|
|
}
|
2020-04-07 12:47:46 -04:00
|
|
|
|
|
|
|
function getEntryPointsWithDeps(
|
|
|
|
resolver: DependencyResolver, entryPoints: EntryPoint[]): EntryPointWithDependencies[] {
|
|
|
|
return entryPoints.map(entryPoint => resolver.getEntryPointWithDependencies(entryPoint));
|
|
|
|
}
|
2019-04-28 15:48:35 -04:00
|
|
|
});
|
2018-08-09 10:59:10 -04:00
|
|
|
});
|
|
|
|
});
|