2018-07-16 03:49:56 -04:00
|
|
|
/**
|
|
|
|
* @license
|
|
|
|
* Copyright Google Inc. All Rights Reserved.
|
|
|
|
*
|
|
|
|
* Use of this source code is governed by an MIT-style license that can be
|
|
|
|
* found in the LICENSE file at https://angular.io/license
|
|
|
|
*/
|
|
|
|
|
2018-08-28 06:32:01 -04:00
|
|
|
import {existsSync, readFileSync, readdirSync, statSync} from 'fs';
|
|
|
|
import * as mockFs from 'mock-fs';
|
2018-07-30 13:06:51 -04:00
|
|
|
import {join} from 'path';
|
2018-08-09 10:59:10 -04:00
|
|
|
const Module = require('module');
|
2018-07-16 03:49:56 -04:00
|
|
|
|
2019-03-20 09:47:58 -04:00
|
|
|
import {mainNgcc} from '../../src/main';
|
|
|
|
import {getAngularPackagesFromRunfiles, resolveNpmTreeArtifact} from '../../../test/runfile_helpers';
|
2019-03-20 09:47:59 -04:00
|
|
|
import {EntryPointPackageJson} from '../../src/packages/entry_point';
|
2019-03-29 06:13:14 -04:00
|
|
|
import {Logger} from '../../src/logging/logger';
|
2018-07-16 03:49:56 -04:00
|
|
|
|
2018-08-28 06:32:01 -04:00
|
|
|
describe('ngcc main()', () => {
|
|
|
|
beforeEach(createMockFileSystem);
|
|
|
|
afterEach(restoreRealFileSystem);
|
2018-07-16 03:49:56 -04:00
|
|
|
|
2018-07-24 09:53:23 -04:00
|
|
|
it('should run ngcc without errors for esm2015', () => {
|
2019-03-20 09:47:59 -04:00
|
|
|
expect(() => mainNgcc({basePath: '/node_modules', propertiesToConsider: ['esm2015']}))
|
2019-03-20 09:47:58 -04:00
|
|
|
.not.toThrow();
|
2018-07-24 09:53:23 -04:00
|
|
|
});
|
2018-07-25 06:06:32 -04:00
|
|
|
|
|
|
|
it('should run ngcc without errors for esm5', () => {
|
2019-03-20 09:47:59 -04:00
|
|
|
expect(() => mainNgcc({basePath: '/node_modules', propertiesToConsider: ['esm5']}))
|
2019-03-20 09:47:58 -04:00
|
|
|
.not.toThrow();
|
2018-08-28 06:32:01 -04:00
|
|
|
});
|
2019-03-20 09:47:58 -04:00
|
|
|
|
2019-03-20 09:47:58 -04:00
|
|
|
describe('with targetEntryPointPath', () => {
|
|
|
|
it('should only compile the given package entry-point (and its dependencies).', () => {
|
2019-03-20 09:47:59 -04:00
|
|
|
mainNgcc({basePath: '/node_modules', targetEntryPointPath: '@angular/common/http'});
|
2019-03-20 09:47:58 -04:00
|
|
|
|
2019-03-20 09:47:59 -04:00
|
|
|
expect(loadPackage('@angular/common/http').__processed_by_ivy_ngcc__).toEqual({
|
2019-03-20 09:47:58 -04:00
|
|
|
module: '0.0.0-PLACEHOLDER',
|
|
|
|
es2015: '0.0.0-PLACEHOLDER',
|
|
|
|
esm5: '0.0.0-PLACEHOLDER',
|
|
|
|
esm2015: '0.0.0-PLACEHOLDER',
|
|
|
|
fesm5: '0.0.0-PLACEHOLDER',
|
|
|
|
fesm2015: '0.0.0-PLACEHOLDER',
|
|
|
|
});
|
|
|
|
// * `common` is a dependency of `common/http`, so is compiled.
|
2019-03-20 09:47:59 -04:00
|
|
|
expect(loadPackage('@angular/common').__processed_by_ivy_ngcc__).toEqual({
|
2019-03-20 09:47:58 -04:00
|
|
|
module: '0.0.0-PLACEHOLDER',
|
|
|
|
es2015: '0.0.0-PLACEHOLDER',
|
|
|
|
esm5: '0.0.0-PLACEHOLDER',
|
|
|
|
esm2015: '0.0.0-PLACEHOLDER',
|
|
|
|
fesm5: '0.0.0-PLACEHOLDER',
|
|
|
|
fesm2015: '0.0.0-PLACEHOLDER',
|
|
|
|
});
|
|
|
|
// * `core` is a dependency of `common`, so is compiled.
|
2019-03-20 09:47:59 -04:00
|
|
|
expect(loadPackage('@angular/core').__processed_by_ivy_ngcc__).toEqual({
|
2019-03-20 09:47:58 -04:00
|
|
|
module: '0.0.0-PLACEHOLDER',
|
|
|
|
es2015: '0.0.0-PLACEHOLDER',
|
|
|
|
esm5: '0.0.0-PLACEHOLDER',
|
|
|
|
esm2015: '0.0.0-PLACEHOLDER',
|
|
|
|
fesm5: '0.0.0-PLACEHOLDER',
|
|
|
|
fesm2015: '0.0.0-PLACEHOLDER',
|
|
|
|
});
|
|
|
|
|
|
|
|
// * `common/testing` is not a dependency of `common/http` so is not compiled.
|
2019-03-20 09:47:59 -04:00
|
|
|
expect(loadPackage('@angular/common/testing').__processed_by_ivy_ngcc__).toBeUndefined();
|
|
|
|
});
|
|
|
|
|
|
|
|
it('should mark a non-Angular package target as processed', () => {
|
|
|
|
mainNgcc({basePath: '/node_modules', targetEntryPointPath: 'test-package'});
|
|
|
|
|
|
|
|
// `test-package` has no Angular but is marked as processed.
|
|
|
|
expect(loadPackage('test-package').__processed_by_ivy_ngcc__).toEqual({
|
|
|
|
es2015: '0.0.0-PLACEHOLDER',
|
|
|
|
});
|
|
|
|
|
|
|
|
// * `core` is a dependency of `test-package`, but it is not processed, since test-package
|
|
|
|
// was not processed.
|
|
|
|
expect(loadPackage('@angular/core').__processed_by_ivy_ngcc__).toBeUndefined();
|
2019-03-20 09:47:58 -04:00
|
|
|
});
|
2019-03-20 09:47:58 -04:00
|
|
|
});
|
|
|
|
|
2019-03-20 09:47:58 -04:00
|
|
|
describe('with propertiesToConsider', () => {
|
|
|
|
it('should only compile the entry-point formats given in the `propertiesToConsider` list',
|
|
|
|
() => {
|
|
|
|
mainNgcc({
|
2019-03-20 09:47:59 -04:00
|
|
|
basePath: '/node_modules',
|
2019-03-20 09:47:58 -04:00
|
|
|
propertiesToConsider: ['main', 'esm5', 'module', 'fesm5']
|
|
|
|
});
|
|
|
|
|
|
|
|
// * the `main` property is UMD, which is not yet supported.
|
|
|
|
// * none of the ES2015 formats are compiled as they are not on the `propertiesToConsider`
|
|
|
|
// list.
|
2019-03-20 09:47:59 -04:00
|
|
|
expect(loadPackage('@angular/core').__processed_by_ivy_ngcc__).toEqual({
|
2019-03-20 09:47:58 -04:00
|
|
|
esm5: '0.0.0-PLACEHOLDER',
|
|
|
|
module: '0.0.0-PLACEHOLDER',
|
|
|
|
fesm5: '0.0.0-PLACEHOLDER',
|
|
|
|
});
|
2019-03-20 09:47:59 -04:00
|
|
|
expect(loadPackage('@angular/common').__processed_by_ivy_ngcc__).toEqual({
|
2019-03-20 09:47:58 -04:00
|
|
|
esm5: '0.0.0-PLACEHOLDER',
|
|
|
|
module: '0.0.0-PLACEHOLDER',
|
|
|
|
fesm5: '0.0.0-PLACEHOLDER',
|
|
|
|
});
|
2019-03-20 09:47:59 -04:00
|
|
|
expect(loadPackage('@angular/common/testing').__processed_by_ivy_ngcc__).toEqual({
|
2019-03-20 09:47:58 -04:00
|
|
|
esm5: '0.0.0-PLACEHOLDER',
|
|
|
|
module: '0.0.0-PLACEHOLDER',
|
|
|
|
fesm5: '0.0.0-PLACEHOLDER',
|
|
|
|
});
|
2019-03-20 09:47:59 -04:00
|
|
|
expect(loadPackage('@angular/common/http').__processed_by_ivy_ngcc__).toEqual({
|
2019-03-20 09:47:58 -04:00
|
|
|
esm5: '0.0.0-PLACEHOLDER',
|
|
|
|
module: '0.0.0-PLACEHOLDER',
|
|
|
|
fesm5: '0.0.0-PLACEHOLDER',
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
2019-03-20 09:47:58 -04:00
|
|
|
|
2019-03-20 09:47:58 -04:00
|
|
|
describe('with compileAllFormats set to false', () => {
|
|
|
|
it('should only compile the first matching format', () => {
|
|
|
|
mainNgcc({
|
2019-03-20 09:47:59 -04:00
|
|
|
basePath: '/node_modules',
|
2019-03-20 09:47:58 -04:00
|
|
|
propertiesToConsider: ['main', 'module', 'fesm5', 'esm5'],
|
|
|
|
compileAllFormats: false
|
|
|
|
});
|
|
|
|
// * The `main` is UMD, which is not yet supported, and so is not compiled.
|
|
|
|
// * In the Angular packages fesm5 and module have the same underlying format,
|
|
|
|
// so both are marked as compiled.
|
|
|
|
// * The `esm5` is not compiled because we stopped after the `fesm5` format.
|
2019-03-20 09:47:59 -04:00
|
|
|
expect(loadPackage('@angular/core').__processed_by_ivy_ngcc__).toEqual({
|
2019-03-20 09:47:58 -04:00
|
|
|
fesm5: '0.0.0-PLACEHOLDER',
|
|
|
|
module: '0.0.0-PLACEHOLDER',
|
|
|
|
});
|
2019-03-20 09:47:59 -04:00
|
|
|
expect(loadPackage('@angular/common').__processed_by_ivy_ngcc__).toEqual({
|
2019-03-20 09:47:58 -04:00
|
|
|
fesm5: '0.0.0-PLACEHOLDER',
|
|
|
|
module: '0.0.0-PLACEHOLDER',
|
|
|
|
});
|
2019-03-20 09:47:59 -04:00
|
|
|
expect(loadPackage('@angular/common/testing').__processed_by_ivy_ngcc__).toEqual({
|
2019-03-20 09:47:58 -04:00
|
|
|
fesm5: '0.0.0-PLACEHOLDER',
|
|
|
|
module: '0.0.0-PLACEHOLDER',
|
|
|
|
});
|
2019-03-20 09:47:59 -04:00
|
|
|
expect(loadPackage('@angular/common/http').__processed_by_ivy_ngcc__).toEqual({
|
2019-03-20 09:47:58 -04:00
|
|
|
fesm5: '0.0.0-PLACEHOLDER',
|
|
|
|
module: '0.0.0-PLACEHOLDER',
|
|
|
|
});
|
2019-03-20 09:47:58 -04:00
|
|
|
});
|
2019-03-20 09:47:58 -04:00
|
|
|
});
|
2019-03-20 09:47:59 -04:00
|
|
|
|
|
|
|
describe('with createNewEntryPointFormats', () => {
|
|
|
|
it('should create new files rather than overwriting the originals', () => {
|
|
|
|
const ANGULAR_CORE_IMPORT_REGEX = /import \* as ɵngcc\d+ from '@angular\/core';/;
|
|
|
|
mainNgcc({
|
|
|
|
basePath: '/node_modules',
|
|
|
|
createNewEntryPointFormats: true,
|
|
|
|
propertiesToConsider: ['esm5']
|
|
|
|
});
|
|
|
|
|
|
|
|
// Updates the package.json
|
|
|
|
expect(loadPackage('@angular/common').esm5).toEqual('./esm5/common.js');
|
|
|
|
expect((loadPackage('@angular/common') as any).esm5_ivy_ngcc)
|
|
|
|
.toEqual('__ivy_ngcc__/esm5/common.js');
|
|
|
|
|
|
|
|
// Doesn't touch original files
|
|
|
|
expect(readFileSync(`/node_modules/@angular/common/esm5/src/common_module.js`, 'utf8'))
|
|
|
|
.not.toMatch(ANGULAR_CORE_IMPORT_REGEX);
|
|
|
|
// Or create a backup of the original
|
|
|
|
expect(existsSync(`/node_modules/@angular/common/esm5/src/common_module.js.__ivy_ngcc_bak`))
|
|
|
|
.toBe(false);
|
|
|
|
|
|
|
|
// Creates new files
|
|
|
|
expect(readFileSync(
|
|
|
|
`/node_modules/@angular/common/__ivy_ngcc__/esm5/src/common_module.js`, 'utf8'))
|
|
|
|
.toMatch(ANGULAR_CORE_IMPORT_REGEX);
|
|
|
|
|
|
|
|
// Copies over files (unchanged) that did not need compiling
|
|
|
|
expect(existsSync(`/node_modules/@angular/common/__ivy_ngcc__/esm5/src/version.js`));
|
|
|
|
expect(readFileSync(`/node_modules/@angular/common/__ivy_ngcc__/esm5/src/version.js`, 'utf8'))
|
|
|
|
.toEqual(readFileSync(`/node_modules/@angular/common/esm5/src/version.js`, 'utf8'));
|
|
|
|
|
|
|
|
// Overwrites .d.ts files (as usual)
|
|
|
|
expect(readFileSync(`/node_modules/@angular/common/common.d.ts`, 'utf8'))
|
|
|
|
.toMatch(ANGULAR_CORE_IMPORT_REGEX);
|
|
|
|
expect(existsSync(`/node_modules/@angular/common/common.d.ts.__ivy_ngcc_bak`)).toBe(true);
|
|
|
|
});
|
|
|
|
});
|
2019-03-29 06:13:14 -04:00
|
|
|
|
|
|
|
describe('logger', () => {
|
|
|
|
it('should log info message to the console by default', () => {
|
|
|
|
const consoleInfoSpy = spyOn(console, 'info');
|
|
|
|
mainNgcc({basePath: '/node_modules', propertiesToConsider: ['esm2015']});
|
|
|
|
expect(consoleInfoSpy)
|
|
|
|
.toHaveBeenCalledWith('Compiling @angular/common/http : esm2015 as esm2015');
|
|
|
|
});
|
|
|
|
|
|
|
|
it('should use a custom logger if provided', () => {
|
|
|
|
const logger: Logger = jasmine.createSpyObj(['debug', 'info', 'warn', 'error']);
|
|
|
|
mainNgcc({basePath: '/node_modules', propertiesToConsider: ['esm2015'], logger});
|
|
|
|
expect(logger.info).toHaveBeenCalled();
|
|
|
|
});
|
|
|
|
});
|
2018-08-28 06:32:01 -04:00
|
|
|
});
|
|
|
|
|
2018-07-25 06:06:32 -04:00
|
|
|
|
2018-08-28 06:32:01 -04:00
|
|
|
function createMockFileSystem() {
|
2019-03-20 09:47:58 -04:00
|
|
|
mockFs({
|
|
|
|
'/node_modules/@angular': loadAngularPackages(),
|
|
|
|
'/node_modules/rxjs': loadDirectory(resolveNpmTreeArtifact('rxjs', 'index.js')),
|
2019-03-20 09:47:58 -04:00
|
|
|
'/node_modules/tslib': loadDirectory(resolveNpmTreeArtifact('tslib', 'tslib.js')),
|
2019-03-20 09:47:59 -04:00
|
|
|
'/node_modules/test-package': {
|
|
|
|
'package.json': '{"name": "test-package", "es2015": "./index.js", "typings": "./index.d.ts"}',
|
|
|
|
'index.js':
|
|
|
|
'import {AppModule} from "@angular/common"; export class MyApp extends AppModule;',
|
|
|
|
'index.d.s':
|
|
|
|
'import {AppModule} from "@angular/common"; export declare class MyApp extends AppModule;',
|
|
|
|
}
|
2019-03-20 09:47:58 -04:00
|
|
|
});
|
2018-08-09 10:59:10 -04:00
|
|
|
spyOn(Module, '_resolveFilename').and.callFake(mockResolve);
|
2018-08-28 06:32:01 -04:00
|
|
|
}
|
2018-07-25 06:06:32 -04:00
|
|
|
|
2018-08-28 06:32:01 -04:00
|
|
|
function restoreRealFileSystem() {
|
|
|
|
mockFs.restore();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2019-01-25 13:48:27 -05:00
|
|
|
/** Load the built Angular packages into an in-memory structure. */
|
|
|
|
function loadAngularPackages(): Directory {
|
2018-08-28 06:32:01 -04:00
|
|
|
const packagesDirectory: Directory = {};
|
2019-01-25 13:48:27 -05:00
|
|
|
|
|
|
|
getAngularPackagesFromRunfiles().forEach(
|
|
|
|
({name, pkgPath}) => { packagesDirectory[name] = loadDirectory(pkgPath); });
|
|
|
|
|
2018-08-28 06:32:01 -04:00
|
|
|
return packagesDirectory;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Load real files from the filesystem into an "in-memory" structure,
|
|
|
|
* which can be used with `mock-fs`.
|
|
|
|
* @param directoryPath the path to the directory we want to load.
|
|
|
|
*/
|
|
|
|
function loadDirectory(directoryPath: string): Directory {
|
|
|
|
const directory: Directory = {};
|
|
|
|
|
|
|
|
readdirSync(directoryPath).forEach(item => {
|
|
|
|
const itemPath = join(directoryPath, item);
|
|
|
|
if (statSync(itemPath).isDirectory()) {
|
|
|
|
directory[item] = loadDirectory(itemPath);
|
|
|
|
} else {
|
|
|
|
directory[item] = readFileSync(itemPath, 'utf-8');
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
return directory;
|
|
|
|
}
|
|
|
|
|
|
|
|
interface Directory {
|
|
|
|
[pathSegment: string]: string|Directory;
|
|
|
|
}
|
|
|
|
|
2019-03-20 09:47:58 -04:00
|
|
|
/**
|
|
|
|
* A mock implementation of the node.js Module._resolveFilename function,
|
|
|
|
* which we are spying on to support mocking out the file-system in these tests.
|
|
|
|
*
|
|
|
|
* @param request the path to a module that needs resolving.
|
|
|
|
*/
|
2019-03-20 09:47:58 -04:00
|
|
|
function mockResolve(request: string): string|null {
|
|
|
|
if (existsSync(request)) {
|
|
|
|
const stat = statSync(request);
|
2018-08-09 10:59:10 -04:00
|
|
|
if (stat.isFile()) {
|
2019-03-20 09:47:58 -04:00
|
|
|
return request;
|
2018-08-09 10:59:10 -04:00
|
|
|
} else if (stat.isDirectory()) {
|
2019-03-20 09:47:58 -04:00
|
|
|
const pIndex = mockResolve(request + '/index');
|
2018-08-09 10:59:10 -04:00
|
|
|
if (pIndex && existsSync(pIndex)) {
|
|
|
|
return pIndex;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
for (const ext of ['.js', '.d.ts']) {
|
2019-03-20 09:47:58 -04:00
|
|
|
if (existsSync(request + ext)) {
|
|
|
|
return request + ext;
|
2018-08-09 10:59:10 -04:00
|
|
|
}
|
|
|
|
}
|
2019-03-20 09:47:58 -04:00
|
|
|
if (request.indexOf('/node_modules') === 0) {
|
|
|
|
// We already tried adding node_modules so give up.
|
|
|
|
return null;
|
|
|
|
} else {
|
|
|
|
return mockResolve(join('/node_modules', request));
|
|
|
|
}
|
2019-01-25 13:44:49 -05:00
|
|
|
}
|
2019-03-20 09:47:58 -04:00
|
|
|
|
2019-03-20 09:47:59 -04:00
|
|
|
function loadPackage(packageName: string): EntryPointPackageJson {
|
2019-03-20 09:47:58 -04:00
|
|
|
return JSON.parse(readFileSync(`/node_modules/${packageName}/package.json`, 'utf8'));
|
2019-03-20 09:47:59 -04:00
|
|
|
}
|