refactor(ivy): ngcc - clean up the public API and export hasBeenProcessed
helper (#29092)
Now the public API does not contain internal types, such as `AbsoluteFsPath` and `EntryPointJsonProperty`. Instead we just accept strings and then guard them in `mainNgcc` as appropriate. A new public API function (`hasBeenProcessed`) has been exported to allow programmatic checking of the build marker when the package.json contents are already known. PR Close #29092
This commit is contained in:
parent
7ea0d1bd3a
commit
55ea8da6eb
@ -6,4 +6,5 @@
|
|||||||
* found in the LICENSE file at https://angular.io/license
|
* found in the LICENSE file at https://angular.io/license
|
||||||
*/
|
*/
|
||||||
|
|
||||||
export {mainNgcc} from './src/main';
|
export {NgccOptions, mainNgcc as process} from './src/main';
|
||||||
|
export {hasBeenProcessed} from './src/packages/build_marker';
|
||||||
|
@ -9,10 +9,7 @@
|
|||||||
import * as path from 'canonical-path';
|
import * as path from 'canonical-path';
|
||||||
import * as yargs from 'yargs';
|
import * as yargs from 'yargs';
|
||||||
|
|
||||||
import {AbsoluteFsPath} from '../src/ngtsc/path';
|
|
||||||
|
|
||||||
import {mainNgcc} from './src/main';
|
import {mainNgcc} from './src/main';
|
||||||
import {EntryPointJsonProperty} from './src/packages/entry_point';
|
|
||||||
|
|
||||||
// CLI entry point
|
// CLI entry point
|
||||||
if (require.main === module) {
|
if (require.main === module) {
|
||||||
@ -21,7 +18,8 @@ if (require.main === module) {
|
|||||||
yargs
|
yargs
|
||||||
.option('s', {
|
.option('s', {
|
||||||
alias: 'source',
|
alias: 'source',
|
||||||
describe: 'A path to the `node_modules` folder to compile.',
|
describe:
|
||||||
|
'A path (relative to the working directory) of the `node_modules` folder to process.',
|
||||||
default: './node_modules'
|
default: './node_modules'
|
||||||
})
|
})
|
||||||
.option('f', {alias: 'formats', hidden: true, array: true})
|
.option('f', {alias: 'formats', hidden: true, array: true})
|
||||||
@ -29,14 +27,15 @@ if (require.main === module) {
|
|||||||
alias: 'properties',
|
alias: 'properties',
|
||||||
array: true,
|
array: true,
|
||||||
describe:
|
describe:
|
||||||
'An array of names of properties in package.json (e.g. `module` or `es2015`)\n' +
|
'An array of names of properties in package.json to compile (e.g. `module` or `es2015`)\n' +
|
||||||
'These properties should hold a path to a bundle-format to compile.\n' +
|
'Each of these properties should hold the path to a bundle-format.\n' +
|
||||||
'If provided, only the specified properties are considered for processing.\n' +
|
'If provided, only the specified properties are considered for processing.\n' +
|
||||||
'If not provided, all the supported format properties (e.g. fesm2015, fesm5, es2015, esm2015, esm5, main, module) in the package.json are considered.'
|
'If not provided, all the supported format properties (e.g. fesm2015, fesm5, es2015, esm2015, esm5, main, module) in the package.json are considered.'
|
||||||
})
|
})
|
||||||
.option('t', {
|
.option('t', {
|
||||||
alias: 'target',
|
alias: 'target',
|
||||||
describe: 'A path to a single entry-point to compile (plus its dependencies).',
|
describe:
|
||||||
|
'A relative path (from the `source` path) to a single entry-point to process (plus its dependencies).',
|
||||||
})
|
})
|
||||||
.option('first-only', {
|
.option('first-only', {
|
||||||
describe:
|
describe:
|
||||||
@ -51,13 +50,13 @@ if (require.main === module) {
|
|||||||
'The formats option (-f/--formats) has been removed. Consider the properties option (-p/--properties) instead.');
|
'The formats option (-f/--formats) has been removed. Consider the properties option (-p/--properties) instead.');
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
const baseSourcePath = AbsoluteFsPath.from(path.resolve(options['s'] || './node_modules'));
|
const baseSourcePath = path.resolve(options['s'] || './node_modules');
|
||||||
const propertiesToConsider: EntryPointJsonProperty[] = options['p'];
|
const propertiesToConsider: string[] = options['p'];
|
||||||
const targetEntryPointPath =
|
const targetEntryPointPath = options['t'] ? options['t'] : undefined;
|
||||||
options['t'] ? AbsoluteFsPath.from(path.resolve(options['t'])) : undefined;
|
|
||||||
const compileAllFormats = !options['first-only'];
|
const compileAllFormats = !options['first-only'];
|
||||||
try {
|
try {
|
||||||
mainNgcc({baseSourcePath, propertiesToConsider, targetEntryPointPath, compileAllFormats});
|
mainNgcc(
|
||||||
|
{basePath: baseSourcePath, propertiesToConsider, targetEntryPointPath, compileAllFormats});
|
||||||
process.exitCode = 0;
|
process.exitCode = 0;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error(e.stack || e.message);
|
console.error(e.stack || e.message);
|
||||||
|
@ -6,7 +6,9 @@
|
|||||||
* found in the LICENSE file at https://angular.io/license
|
* found in the LICENSE file at https://angular.io/license
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {AbsoluteFsPath} from '../../src/ngtsc/path';
|
import {resolve} from 'canonical-path';
|
||||||
|
|
||||||
|
import {AbsoluteFsPath, PathSegment} from '../../src/ngtsc/path';
|
||||||
|
|
||||||
import {checkMarker, writeMarker} from './packages/build_marker';
|
import {checkMarker, writeMarker} from './packages/build_marker';
|
||||||
import {DependencyHost} from './packages/dependency_host';
|
import {DependencyHost} from './packages/dependency_host';
|
||||||
@ -21,21 +23,23 @@ import {Transformer} from './packages/transformer';
|
|||||||
* The options to configure the ngcc compiler.
|
* The options to configure the ngcc compiler.
|
||||||
*/
|
*/
|
||||||
export interface NgccOptions {
|
export interface NgccOptions {
|
||||||
/** The path to the node_modules folder that contains the packages to compile. */
|
/** The absolute path to the `node_modules` folder that contains the packages to process. */
|
||||||
baseSourcePath: AbsoluteFsPath;
|
basePath: string;
|
||||||
/**
|
/**
|
||||||
* The path, relative to `baseSourcePath` of the primary package to be compiled.
|
* The path, relative to `basePath` to the primary package to be processed.
|
||||||
* All its dependencies will need to be compiled too.
|
*
|
||||||
|
* All its dependencies will need to be processed too.
|
||||||
*/
|
*/
|
||||||
targetEntryPointPath?: AbsoluteFsPath;
|
targetEntryPointPath?: string;
|
||||||
/**
|
/**
|
||||||
* Which entry-point properties in the package.json to consider when compiling.
|
* Which entry-point properties in the package.json to consider when processing an entry-point.
|
||||||
* Each of properties contain a path to particular bundle format for a given entry-point.
|
* Each property should hold a path to the particular bundle format for the entry-point.
|
||||||
|
* Defaults to all the properties in the package.json.
|
||||||
*/
|
*/
|
||||||
propertiesToConsider?: EntryPointJsonProperty[];
|
propertiesToConsider?: string[];
|
||||||
/**
|
/**
|
||||||
* Whether to compile all specified formats or to stop compiling this entry-point at the first
|
* Whether to process all formats specified by (`propertiesToConsider`) or to stop processing
|
||||||
* matching format. Defaults to `true`.
|
* this entry-point at the first matching format. Defaults to `true`.
|
||||||
*/
|
*/
|
||||||
compileAllFormats?: boolean;
|
compileAllFormats?: boolean;
|
||||||
}
|
}
|
||||||
@ -50,15 +54,19 @@ const SUPPORTED_FORMATS: EntryPointFormat[] = ['esm5', 'esm2015'];
|
|||||||
*
|
*
|
||||||
* @param options The options telling ngcc what to compile and how.
|
* @param options The options telling ngcc what to compile and how.
|
||||||
*/
|
*/
|
||||||
export function mainNgcc({baseSourcePath, targetEntryPointPath,
|
export function mainNgcc({basePath, targetEntryPointPath,
|
||||||
propertiesToConsider = SUPPORTED_FORMAT_PROPERTIES,
|
propertiesToConsider = SUPPORTED_FORMAT_PROPERTIES,
|
||||||
compileAllFormats = true}: NgccOptions): void {
|
compileAllFormats = true}: NgccOptions): void {
|
||||||
const transformer = new Transformer(baseSourcePath, baseSourcePath);
|
const transformer = new Transformer(basePath, basePath);
|
||||||
const host = new DependencyHost();
|
const host = new DependencyHost();
|
||||||
const resolver = new DependencyResolver(host);
|
const resolver = new DependencyResolver(host);
|
||||||
const finder = new EntryPointFinder(resolver);
|
const finder = new EntryPointFinder(resolver);
|
||||||
|
|
||||||
const {entryPoints} = finder.findEntryPoints(baseSourcePath, targetEntryPointPath);
|
const absoluteTargetEntryPointPath = targetEntryPointPath ?
|
||||||
|
AbsoluteFsPath.from(resolve(basePath, targetEntryPointPath)) :
|
||||||
|
undefined;
|
||||||
|
const {entryPoints} =
|
||||||
|
finder.findEntryPoints(AbsoluteFsPath.from(basePath), absoluteTargetEntryPointPath);
|
||||||
entryPoints.forEach(entryPoint => {
|
entryPoints.forEach(entryPoint => {
|
||||||
|
|
||||||
// Are we compiling the Angular core?
|
// Are we compiling the Angular core?
|
||||||
@ -67,7 +75,7 @@ export function mainNgcc({baseSourcePath, targetEntryPointPath,
|
|||||||
const compiledFormats = new Set<string>();
|
const compiledFormats = new Set<string>();
|
||||||
|
|
||||||
for (let i = 0; i < propertiesToConsider.length; i++) {
|
for (let i = 0; i < propertiesToConsider.length; i++) {
|
||||||
const property = propertiesToConsider[i];
|
const property = propertiesToConsider[i] as EntryPointJsonProperty;
|
||||||
const formatPath = entryPoint.packageJson[property];
|
const formatPath = entryPoint.packageJson[property];
|
||||||
const format = getEntryPointFormat(property);
|
const format = getEntryPointFormat(property);
|
||||||
|
|
||||||
|
@ -14,17 +14,20 @@ import {EntryPoint, EntryPointJsonProperty} from './entry_point';
|
|||||||
export const NGCC_VERSION = '0.0.0-PLACEHOLDER';
|
export const NGCC_VERSION = '0.0.0-PLACEHOLDER';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check whether there is a build marker for the given entry-point and format property.
|
* Check whether ngcc has already processed a given entry-point format.
|
||||||
* @param entryPoint the entry-point to check for a marker.
|
*
|
||||||
* @param format the property in the package.json of the format for which we are checking for a
|
* The entry-point is defined by the package.json contents provided.
|
||||||
* marker.
|
* The format is defined by the provided property name of the path to the bundle in the package.json
|
||||||
* @returns true if the entry-point and format have already been built with this ngcc version.
|
*
|
||||||
* @throws Error if the entry-point and format have already been built with a different ngcc
|
* @param packageJson The parsed contents of the package.json file for the entry-point.
|
||||||
|
* @param format The entry-point format property in the package.json to check.
|
||||||
|
* @returns true if the entry-point and format have already been processed with this ngcc version.
|
||||||
|
* @throws Error if the entry-point has already been processed with a different ngcc
|
||||||
* version.
|
* version.
|
||||||
*/
|
*/
|
||||||
export function checkMarker(entryPoint: EntryPoint, format: EntryPointJsonProperty): boolean {
|
export function hasBeenProcessed(packageJson: any, format: string): boolean {
|
||||||
const pkg = entryPoint.packageJson;
|
const compiledVersion =
|
||||||
const compiledVersion = pkg.__modified_by_ngcc__ && pkg.__modified_by_ngcc__[format];
|
packageJson && packageJson.__modified_by_ngcc__ && packageJson.__modified_by_ngcc__[format];
|
||||||
if (compiledVersion && compiledVersion !== NGCC_VERSION) {
|
if (compiledVersion && compiledVersion !== NGCC_VERSION) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
'The ngcc compiler has changed since the last ngcc build.\n' +
|
'The ngcc compiler has changed since the last ngcc build.\n' +
|
||||||
@ -33,6 +36,21 @@ export function checkMarker(entryPoint: EntryPoint, format: EntryPointJsonProper
|
|||||||
return !!compiledVersion;
|
return !!compiledVersion;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check whether there is a marker for the given entry-point and format property, indicating that
|
||||||
|
* the given bundle has already been processed.
|
||||||
|
* @param entryPoint the entry-point to check for a marker.
|
||||||
|
* @param format the property in the package.json of the format for which we are checking for a
|
||||||
|
* marker.
|
||||||
|
* @returns true if the entry-point and format have already been processed with this ngcc version.
|
||||||
|
* @throws Error if the entry-point and format have already been processed with a different ngcc
|
||||||
|
* version.
|
||||||
|
*/
|
||||||
|
export function checkMarker(entryPoint: EntryPoint, format: EntryPointJsonProperty): boolean {
|
||||||
|
const pkg = entryPoint.packageJson;
|
||||||
|
return hasBeenProcessed(pkg, format);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Write a build marker for the given entry-point and format property, to indicate that it has
|
* Write a build marker for the given entry-point and format property, to indicate that it has
|
||||||
* been compiled by this version of ngcc.
|
* been compiled by this version of ngcc.
|
||||||
|
@ -13,30 +13,24 @@ const Module = require('module');
|
|||||||
|
|
||||||
import {mainNgcc} from '../../src/main';
|
import {mainNgcc} from '../../src/main';
|
||||||
import {getAngularPackagesFromRunfiles, resolveNpmTreeArtifact} from '../../../test/runfile_helpers';
|
import {getAngularPackagesFromRunfiles, resolveNpmTreeArtifact} from '../../../test/runfile_helpers';
|
||||||
import {AbsoluteFsPath} from '../../../src/ngtsc/path';
|
|
||||||
|
|
||||||
const NODE_MODULES = AbsoluteFsPath.from('/node_modules');
|
|
||||||
|
|
||||||
describe('ngcc main()', () => {
|
describe('ngcc main()', () => {
|
||||||
beforeEach(createMockFileSystem);
|
beforeEach(createMockFileSystem);
|
||||||
afterEach(restoreRealFileSystem);
|
afterEach(restoreRealFileSystem);
|
||||||
|
|
||||||
it('should run ngcc without errors for esm2015', () => {
|
it('should run ngcc without errors for esm2015', () => {
|
||||||
expect(() => mainNgcc({baseSourcePath: NODE_MODULES, propertiesToConsider: ['esm2015']}))
|
expect(() => mainNgcc({basePath: '/node_modules', propertiesToConsider: ['esm2015']}))
|
||||||
.not.toThrow();
|
.not.toThrow();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should run ngcc without errors for esm5', () => {
|
it('should run ngcc without errors for esm5', () => {
|
||||||
expect(() => mainNgcc({baseSourcePath: NODE_MODULES, propertiesToConsider: ['esm5']}))
|
expect(() => mainNgcc({basePath: '/node_modules', propertiesToConsider: ['esm5']}))
|
||||||
.not.toThrow();
|
.not.toThrow();
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('with targetEntryPointPath', () => {
|
describe('with targetEntryPointPath', () => {
|
||||||
it('should only compile the given package entry-point (and its dependencies).', () => {
|
it('should only compile the given package entry-point (and its dependencies).', () => {
|
||||||
mainNgcc({
|
mainNgcc({basePath: '/node_modules', targetEntryPointPath: '@angular/common/http'});
|
||||||
baseSourcePath: NODE_MODULES,
|
|
||||||
targetEntryPointPath: AbsoluteFsPath.from('/node_modules/@angular/common/http')
|
|
||||||
});
|
|
||||||
|
|
||||||
expect(loadPackage('@angular/common/http').__modified_by_ngcc__).toEqual({
|
expect(loadPackage('@angular/common/http').__modified_by_ngcc__).toEqual({
|
||||||
module: '0.0.0-PLACEHOLDER',
|
module: '0.0.0-PLACEHOLDER',
|
||||||
@ -74,7 +68,7 @@ describe('ngcc main()', () => {
|
|||||||
it('should only compile the entry-point formats given in the `propertiesToConsider` list',
|
it('should only compile the entry-point formats given in the `propertiesToConsider` list',
|
||||||
() => {
|
() => {
|
||||||
mainNgcc({
|
mainNgcc({
|
||||||
baseSourcePath: NODE_MODULES,
|
basePath: '/node_modules',
|
||||||
propertiesToConsider: ['main', 'esm5', 'module', 'fesm5']
|
propertiesToConsider: ['main', 'esm5', 'module', 'fesm5']
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -107,7 +101,7 @@ describe('ngcc main()', () => {
|
|||||||
describe('with compileAllFormats set to false', () => {
|
describe('with compileAllFormats set to false', () => {
|
||||||
it('should only compile the first matching format', () => {
|
it('should only compile the first matching format', () => {
|
||||||
mainNgcc({
|
mainNgcc({
|
||||||
baseSourcePath: NODE_MODULES,
|
basePath: '/node_modules',
|
||||||
propertiesToConsider: ['main', 'module', 'fesm5', 'esm5'],
|
propertiesToConsider: ['main', 'module', 'fesm5', 'esm5'],
|
||||||
compileAllFormats: false
|
compileAllFormats: false
|
||||||
});
|
});
|
||||||
|
Loading…
x
Reference in New Issue
Block a user