Pete Bacon Darwin cd449021c1 feat(ivy): ngcc - compile only specified package.json format properties (#29092)
You can now specify a list of properties in the package.json that
should be considered (in order) to find the path to the format to compile.

The build marker system has been updated to store the markers in
the package.json rather than an additional external file.
Also instead of tracking the underlying bundle format that was compiled,
it now tracks the package.json property.

BREAKING CHANGE:

The `proertiesToConsider` option replaces the previous `formats` option,
which specified the final bundle format, rather than the property in the
package.json.
If you were using this option to compile only specific bundle formats,
you must now modify your usage to pass in the properties in the package.json
that map to the format that you wish to compile.

In the CLI, the `--formats` is no longer available. Instead use the
`--properties` option.

FW-1120

PR Close #29092
2019-03-20 14:45:54 -04:00

168 lines
5.2 KiB
TypeScript

/**
* @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
*/
import {existsSync, readFileSync, readdirSync, statSync} from 'fs';
import * as mockFs from 'mock-fs';
import {join} from 'path';
const Module = require('module');
import {mainNgcc} from '../../src/main';
import {getAngularPackagesFromRunfiles, resolveNpmTreeArtifact} from '../../../test/runfile_helpers';
describe('ngcc main()', () => {
beforeEach(createMockFileSystem);
afterEach(restoreRealFileSystem);
it('should run ngcc without errors for fesm2015', () => {
expect(() => mainNgcc({baseSourcePath: '/node_modules', propertiesToConsider: ['fesm2015']}))
.not.toThrow();
});
it('should run ngcc without errors for fesm5', () => {
expect(() => mainNgcc({baseSourcePath: '/node_modules', propertiesToConsider: ['fesm5']}))
.not.toThrow();
});
it('should run ngcc without errors for esm2015', () => {
expect(() => mainNgcc({baseSourcePath: '/node_modules', propertiesToConsider: ['esm2015']}))
.not.toThrow();
});
it('should run ngcc without errors for esm5', () => {
expect(() => mainNgcc({baseSourcePath: '/node_modules', propertiesToConsider: ['esm5']}))
.not.toThrow();
});
it('should only compile the given package entry-point (and its dependencies)', () => {
mainNgcc({baseSourcePath: '/node_modules', targetEntryPointPath: '@angular/common/http'});
expect(loadPackage('@angular/common/http').__modified_by_ngcc__).toEqual({
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'
});
expect(loadPackage('@angular/common').__modified_by_ngcc__).toEqual({
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'
});
expect(loadPackage('@angular/core').__modified_by_ngcc__).toEqual({
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'
});
expect(loadPackage('@angular/common/testing').__modified_by_ngcc__).toBeUndefined();
});
it('should only build the format properties specified for each entry-point', () => {
mainNgcc({baseSourcePath: '/node_modules', propertiesToConsider: ['main', 'esm5', 'module']});
expect(loadPackage('@angular/core').__modified_by_ngcc__).toEqual({
esm5: '0.0.0-PLACEHOLDER',
module: '0.0.0-PLACEHOLDER',
});
expect(loadPackage('@angular/common').__modified_by_ngcc__).toEqual({
esm5: '0.0.0-PLACEHOLDER',
module: '0.0.0-PLACEHOLDER',
});
expect(loadPackage('@angular/common/testing').__modified_by_ngcc__).toEqual({
esm5: '0.0.0-PLACEHOLDER',
module: '0.0.0-PLACEHOLDER',
});
expect(loadPackage('@angular/common/http').__modified_by_ngcc__).toEqual({
esm5: '0.0.0-PLACEHOLDER',
module: '0.0.0-PLACEHOLDER',
});
});
});
function createMockFileSystem() {
mockFs({
'/node_modules/@angular': loadAngularPackages(),
'/node_modules/rxjs': loadDirectory(resolveNpmTreeArtifact('rxjs', 'index.js')),
});
spyOn(Module, '_resolveFilename').and.callFake(mockResolve);
}
function restoreRealFileSystem() {
mockFs.restore();
}
/** Load the built Angular packages into an in-memory structure. */
function loadAngularPackages(): Directory {
const packagesDirectory: Directory = {};
getAngularPackagesFromRunfiles().forEach(
({name, pkgPath}) => { packagesDirectory[name] = loadDirectory(pkgPath); });
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;
}
function mockResolve(request: string): string|null {
if (existsSync(request)) {
const stat = statSync(request);
if (stat.isFile()) {
return request;
} else if (stat.isDirectory()) {
const pIndex = mockResolve(request + '/index');
if (pIndex && existsSync(pIndex)) {
return pIndex;
}
}
}
for (const ext of ['.js', '.d.ts']) {
if (existsSync(request + ext)) {
return request + ext;
}
}
if (request.indexOf('/node_modules') === 0) {
// We already tried adding node_modules so give up.
return null;
} else {
return mockResolve(join('/node_modules', request));
}
}
function loadPackage(packageName: string) {
return JSON.parse(readFileSync(`/node_modules/${packageName}/package.json`, 'utf8'));
}