From 66239b9d091ac39a63465396e17ab3c354a446be Mon Sep 17 00:00:00 2001 From: Pete Bacon Darwin Date: Wed, 20 Mar 2019 13:47:58 +0000 Subject: [PATCH] refactor(ivy): expose ngcc programmatically (#29092) The `mainNgcc()` function has been refactored to make it easier to call ngcc from JavaScript, rather than via the command line. For example, the `yargs` argument parsing and the exception handling/logging have moved to the `main-ngcc.ts` file so that it is only used for the command line version. FW-1118 PR Close #29092 --- packages/compiler-cli/ngcc/main-ngcc.ts | 35 +++++- packages/compiler-cli/ngcc/src/main.ts | 105 ++++++++---------- .../ngcc/test/integration/ngcc_spec.ts | 12 +- 3 files changed, 84 insertions(+), 68 deletions(-) diff --git a/packages/compiler-cli/ngcc/main-ngcc.ts b/packages/compiler-cli/ngcc/main-ngcc.ts index 08524a6afa..1d71d0ffee 100644 --- a/packages/compiler-cli/ngcc/main-ngcc.ts +++ b/packages/compiler-cli/ngcc/main-ngcc.ts @@ -6,11 +6,44 @@ * 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 * as path from 'canonical-path'; +import * as yargs from 'yargs'; import {mainNgcc} from './src/main'; +import {EntryPointFormat} from './src/packages/entry_point'; // CLI entry point if (require.main === module) { const args = process.argv.slice(2); - process.exitCode = mainNgcc(args); + const options = + yargs + .option('s', { + alias: 'source', + describe: 'A path to the root folder to compile.', + default: './node_modules' + }) + .option('f', { + alias: 'formats', + array: true, + describe: 'An array of formats to compile.', + default: ['fesm2015', 'esm2015', 'fesm5', 'esm5'] + }) + .option('t', { + alias: 'target', + describe: 'A path to a root folder where the compiled files will be written.', + defaultDescription: 'The `source` folder.' + }) + .help() + .parse(args); + + const baseSourcePath: string = path.resolve(options['s']); + const formats: EntryPointFormat[] = options['f']; + const baseTargetPath: string = options['t']; + try { + mainNgcc({baseSourcePath, formats, baseTargetPath}); + process.exitCode = 0; + } catch (e) { + console.error(e.stack || e.message); + process.exitCode = 1; + } } diff --git a/packages/compiler-cli/ngcc/src/main.ts b/packages/compiler-cli/ngcc/src/main.ts index a339919b01..1bde0dddd9 100644 --- a/packages/compiler-cli/ngcc/src/main.ts +++ b/packages/compiler-cli/ngcc/src/main.ts @@ -5,8 +5,6 @@ * 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 * as path from 'canonical-path'; -import * as yargs from 'yargs'; import {checkMarkerFile, writeMarkerFile} from './packages/build_marker'; import {DependencyHost} from './packages/dependency_host'; @@ -16,72 +14,61 @@ import {makeEntryPointBundle} from './packages/entry_point_bundle'; import {EntryPointFinder} from './packages/entry_point_finder'; import {Transformer} from './packages/transformer'; -export function mainNgcc(args: string[]): number { - const options = - yargs - .option('s', { - alias: 'source', - describe: 'A path to the root folder to compile.', - default: './node_modules' - }) - .option('f', { - alias: 'formats', - array: true, - describe: 'An array of formats to compile.', - default: ['fesm2015', 'esm2015', 'fesm5', 'esm5'] - }) - .option('t', { - alias: 'target', - describe: 'A path to a root folder where the compiled files will be written.', - defaultDescription: 'The `source` folder.' - }) - .help() - .parse(args); +/** + * The options to configure the ngcc compiler. + */ +export interface NgccOptions { + /** The path to the node_modules folder that contains the packages to compile. */ + baseSourcePath: string; + /** A list of JavaScript bundle formats that should be compiled. */ + formats: EntryPointFormat[]; + /** The path to the node_modules folder where modified files should be written. */ + baseTargetPath?: string; +} - const sourcePath: string = path.resolve(options['s']); - const formats: EntryPointFormat[] = options['f']; - const targetPath: string = options['t'] || sourcePath; - - const transformer = new Transformer(sourcePath, targetPath); +/** + * This is the main entry-point into ngcc (aNGular Compatibility Compiler). + * + * You can call this function to process one or more npm packages, to ensure + * that they are compatible with the ivy compiler (ngtsc). + * + * @param options The options telling ngcc what to compile and how. + */ +export function mainNgcc({baseSourcePath, formats, baseTargetPath = baseSourcePath}: NgccOptions): + void { + const transformer = new Transformer(baseSourcePath, baseTargetPath); const host = new DependencyHost(); const resolver = new DependencyResolver(host); const finder = new EntryPointFinder(resolver); - try { - const {entryPoints} = finder.findEntryPoints(sourcePath); - entryPoints.forEach(entryPoint => { + const {entryPoints} = finder.findEntryPoints(baseSourcePath); + entryPoints.forEach(entryPoint => { - // Are we compiling the Angular core? - const isCore = entryPoint.name === '@angular/core'; + // Are we compiling the Angular core? + const isCore = entryPoint.name === '@angular/core'; - // We transform the d.ts typings files while transforming one of the formats. - // This variable decides with which of the available formats to do this transform. - // It is marginally faster to process via the flat file if available. - const dtsTransformFormat: EntryPointFormat = entryPoint.fesm2015 ? 'fesm2015' : 'esm2015'; + // We transform the d.ts typings files while transforming one of the formats. + // This variable decides with which of the available formats to do this transform. + // It is marginally faster to process via the flat file if available. + const dtsTransformFormat: EntryPointFormat = entryPoint.fesm2015 ? 'fesm2015' : 'esm2015'; - formats.forEach(format => { - if (checkMarkerFile(entryPoint, format)) { - console.warn(`Skipping ${entryPoint.name} : ${format} (already built).`); - return; - } + formats.forEach(format => { + if (checkMarkerFile(entryPoint, format)) { + console.warn(`Skipping ${entryPoint.name} : ${format} (already built).`); + return; + } - const bundle = - makeEntryPointBundle(entryPoint, isCore, format, format === dtsTransformFormat); - if (bundle === null) { - console.warn( - `Skipping ${entryPoint.name} : ${format} (no entry point file for this format).`); - } else { - transformer.transform(entryPoint, isCore, bundle); - } + const bundle = + makeEntryPointBundle(entryPoint, isCore, format, format === dtsTransformFormat); + if (bundle === null) { + console.warn( + `Skipping ${entryPoint.name} : ${format} (no entry point file for this format).`); + } else { + transformer.transform(entryPoint, isCore, bundle); + } - // Write the built-with-ngcc marker - writeMarkerFile(entryPoint, format); - }); + // Write the built-with-ngcc marker + writeMarkerFile(entryPoint, format); }); - } catch (e) { - console.error(e.stack || e.message); - return 1; - } - - return 0; + }); } diff --git a/packages/compiler-cli/ngcc/test/integration/ngcc_spec.ts b/packages/compiler-cli/ngcc/test/integration/ngcc_spec.ts index 0f33444a12..e5a8d401cd 100644 --- a/packages/compiler-cli/ngcc/test/integration/ngcc_spec.ts +++ b/packages/compiler-cli/ngcc/test/integration/ngcc_spec.ts @@ -19,23 +19,19 @@ describe('ngcc main()', () => { afterEach(restoreRealFileSystem); it('should run ngcc without errors for fesm2015', () => { - const format = 'fesm2015'; - expect(mainNgcc(['-f', format, '-s', '/node_modules'])).toBe(0); + expect(() => mainNgcc({baseSourcePath: '/node_modules', formats: ['fesm2015']})).not.toThrow(); }); it('should run ngcc without errors for fesm5', () => { - const format = 'fesm5'; - expect(mainNgcc(['-f', format, '-s', '/node_modules'])).toBe(0); + expect(() => mainNgcc({baseSourcePath: '/node_modules', formats: ['fesm5']})).not.toThrow(); }); it('should run ngcc without errors for esm2015', () => { - const format = 'esm2015'; - expect(mainNgcc(['-f', format, '-s', '/node_modules'])).toBe(0); + expect(() => mainNgcc({baseSourcePath: '/node_modules', formats: ['esm2015']})).not.toThrow(); }); it('should run ngcc without errors for esm5', () => { - const format = 'esm5'; - expect(mainNgcc(['-f', format, '-s', '/node_modules'])).toBe(0); + expect(() => mainNgcc({baseSourcePath: '/node_modules', formats: ['esm5']})).not.toThrow(); }); });