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
This commit is contained in:
parent
4bb0259bc0
commit
cd449021c1
@ -17,7 +17,7 @@
|
|||||||
"build": "yarn ~~build",
|
"build": "yarn ~~build",
|
||||||
"prebuild-local": "yarn setup-local",
|
"prebuild-local": "yarn setup-local",
|
||||||
"build-local": "yarn ~~build",
|
"build-local": "yarn ~~build",
|
||||||
"prebuild-with-ivy": "yarn setup-local && yarn ivy-ngcc --formats fesm2015 fesm5",
|
"prebuild-with-ivy": "yarn setup-local && yarn ivy-ngcc",
|
||||||
"build-with-ivy": "node scripts/build-with-ivy",
|
"build-with-ivy": "node scripts/build-with-ivy",
|
||||||
"extract-cli-command-docs": "node tools/transforms/cli-docs-package/extract-cli-commands.js cafa558cf",
|
"extract-cli-command-docs": "node tools/transforms/cli-docs-package/extract-cli-commands.js cafa558cf",
|
||||||
"lint": "yarn check-env && yarn docs-lint && ng lint && yarn example-lint && yarn tools-lint",
|
"lint": "yarn check-env && yarn docs-lint && ng lint && yarn example-lint && yarn tools-lint",
|
||||||
|
@ -12,80 +12,36 @@ const EXAMPLES_BASE_PATH = path.resolve(__dirname, '../../content/examples');
|
|||||||
|
|
||||||
const BOILERPLATE_PATHS = {
|
const BOILERPLATE_PATHS = {
|
||||||
cli: [
|
cli: [
|
||||||
'src/environments/environment.prod.ts',
|
'src/environments/environment.prod.ts', 'src/environments/environment.ts',
|
||||||
'src/environments/environment.ts',
|
'src/assets/.gitkeep', 'src/browserslist', 'src/favicon.ico', 'src/karma.conf.js',
|
||||||
'src/assets/.gitkeep',
|
'src/polyfills.ts', 'src/test.ts', 'src/tsconfig.app.json', 'src/tsconfig.spec.json',
|
||||||
'src/browserslist',
|
'src/tslint.json', 'e2e/src/app.po.ts', 'e2e/protractor.conf.js', 'e2e/tsconfig.e2e.json',
|
||||||
'src/favicon.ico',
|
'.editorconfig', 'angular.json', 'package.json', 'tsconfig.json', 'tslint.json'
|
||||||
'src/karma.conf.js',
|
|
||||||
'src/polyfills.ts',
|
|
||||||
'src/test.ts',
|
|
||||||
'src/tsconfig.app.json',
|
|
||||||
'src/tsconfig.spec.json',
|
|
||||||
'src/tslint.json',
|
|
||||||
'e2e/src/app.po.ts',
|
|
||||||
'e2e/protractor.conf.js',
|
|
||||||
'e2e/tsconfig.e2e.json',
|
|
||||||
'.editorconfig',
|
|
||||||
'angular.json',
|
|
||||||
'package.json',
|
|
||||||
'tsconfig.json',
|
|
||||||
'tslint.json'
|
|
||||||
],
|
],
|
||||||
systemjs: [
|
systemjs: [
|
||||||
'src/systemjs-angular-loader.js',
|
'src/systemjs-angular-loader.js', 'src/systemjs.config.js', 'src/tsconfig.json',
|
||||||
'src/systemjs.config.js',
|
'bs-config.json', 'bs-config.e2e.json', 'package.json', 'tslint.json'
|
||||||
'src/tsconfig.json',
|
|
||||||
'bs-config.json',
|
|
||||||
'bs-config.e2e.json',
|
|
||||||
'package.json',
|
|
||||||
'tslint.json'
|
|
||||||
],
|
],
|
||||||
common: [
|
common: ['src/styles.css']
|
||||||
'src/styles.css'
|
|
||||||
]
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// All paths in this tool are relative to the current boilerplate folder, i.e boilerplate/i18n
|
// All paths in this tool are relative to the current boilerplate folder, i.e boilerplate/i18n
|
||||||
// This maps the CLI files that exists in a parent folder
|
// This maps the CLI files that exists in a parent folder
|
||||||
const cliRelativePath = BOILERPLATE_PATHS.cli.map(file => `../cli/${file}`);
|
const cliRelativePath = BOILERPLATE_PATHS.cli.map(file => `../cli/${file}`);
|
||||||
|
|
||||||
BOILERPLATE_PATHS.elements = [
|
BOILERPLATE_PATHS.elements = [...cliRelativePath, 'tsconfig.json'];
|
||||||
...cliRelativePath,
|
|
||||||
'tsconfig.json'
|
|
||||||
];
|
|
||||||
|
|
||||||
BOILERPLATE_PATHS.i18n = [
|
BOILERPLATE_PATHS.i18n = [...cliRelativePath, 'angular.json', 'package.json'];
|
||||||
...cliRelativePath,
|
|
||||||
'angular.json',
|
|
||||||
'package.json'
|
|
||||||
];
|
|
||||||
|
|
||||||
BOILERPLATE_PATHS['service-worker'] = [
|
BOILERPLATE_PATHS['service-worker'] = [...cliRelativePath, 'angular.json', 'package.json'];
|
||||||
...cliRelativePath,
|
|
||||||
'angular.json',
|
|
||||||
'package.json'
|
|
||||||
];
|
|
||||||
|
|
||||||
BOILERPLATE_PATHS.testing = [
|
BOILERPLATE_PATHS.testing = [...cliRelativePath, 'angular.json'];
|
||||||
...cliRelativePath,
|
|
||||||
'angular.json'
|
|
||||||
];
|
|
||||||
|
|
||||||
BOILERPLATE_PATHS.universal = [
|
BOILERPLATE_PATHS.universal = [...cliRelativePath, 'angular.json', 'package.json'];
|
||||||
...cliRelativePath,
|
|
||||||
'angular.json',
|
|
||||||
'package.json'
|
|
||||||
];
|
|
||||||
|
|
||||||
BOILERPLATE_PATHS.ivy = {
|
BOILERPLATE_PATHS.ivy = {
|
||||||
systemjs: [
|
systemjs: ['rollup-config.js', 'tsconfig-aot.json'],
|
||||||
'rollup-config.js',
|
cli: ['src/tsconfig.app.json']
|
||||||
'tsconfig-aot.json'
|
|
||||||
],
|
|
||||||
cli: [
|
|
||||||
'src/tsconfig.app.json'
|
|
||||||
]
|
|
||||||
};
|
};
|
||||||
|
|
||||||
BOILERPLATE_PATHS.schematics = [
|
BOILERPLATE_PATHS.schematics = [
|
||||||
@ -101,10 +57,12 @@ class ExampleBoilerPlate {
|
|||||||
*/
|
*/
|
||||||
add(ivy = false) {
|
add(ivy = false) {
|
||||||
// Get all the examples folders, indicated by those that contain a `example-config.json` file
|
// Get all the examples folders, indicated by those that contain a `example-config.json` file
|
||||||
const exampleFolders = this.getFoldersContaining(EXAMPLES_BASE_PATH, EXAMPLE_CONFIG_FILENAME, 'node_modules');
|
const exampleFolders =
|
||||||
|
this.getFoldersContaining(EXAMPLES_BASE_PATH, EXAMPLE_CONFIG_FILENAME, 'node_modules');
|
||||||
|
|
||||||
if (!fs.existsSync(SHARED_NODE_MODULES_PATH)) {
|
if (!fs.existsSync(SHARED_NODE_MODULES_PATH)) {
|
||||||
throw new Error(`The shared node_modules folder for the examples (${SHARED_NODE_MODULES_PATH}) is missing.\n` +
|
throw new Error(
|
||||||
|
`The shared node_modules folder for the examples (${SHARED_NODE_MODULES_PATH}) is missing.\n` +
|
||||||
`Perhaps you need to run "yarn example-use-npm" or "yarn example-use-local" to install the dependencies?`);
|
`Perhaps you need to run "yarn example-use-npm" or "yarn example-use-local" to install the dependencies?`);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -114,7 +72,7 @@ class ExampleBoilerPlate {
|
|||||||
// the module typings if we specified an "es2015" format. This means that
|
// the module typings if we specified an "es2015" format. This means that
|
||||||
// we also need to build with "fesm2015" in order to get updated typings
|
// we also need to build with "fesm2015" in order to get updated typings
|
||||||
// which are needed for compilation.
|
// which are needed for compilation.
|
||||||
shelljs.exec(`yarn --cwd ${SHARED_PATH} ivy-ngcc --formats fesm2015 fesm5`);
|
shelljs.exec(`yarn --cwd ${SHARED_PATH} ivy-ngcc`);
|
||||||
}
|
}
|
||||||
|
|
||||||
exampleFolders.forEach(exampleFolder => {
|
exampleFolders.forEach(exampleFolder => {
|
||||||
@ -128,16 +86,20 @@ class ExampleBoilerPlate {
|
|||||||
const boilerPlateBasePath = path.resolve(BOILERPLATE_BASE_PATH, boilerPlateType);
|
const boilerPlateBasePath = path.resolve(BOILERPLATE_BASE_PATH, boilerPlateType);
|
||||||
|
|
||||||
// Copy the boilerplate specific files
|
// Copy the boilerplate specific files
|
||||||
BOILERPLATE_PATHS[boilerPlateType].forEach(filePath => this.copyFile(boilerPlateBasePath, exampleFolder, filePath));
|
BOILERPLATE_PATHS[boilerPlateType].forEach(
|
||||||
|
filePath => this.copyFile(boilerPlateBasePath, exampleFolder, filePath));
|
||||||
|
|
||||||
// Copy the boilerplate common files
|
// Copy the boilerplate common files
|
||||||
BOILERPLATE_PATHS.common.forEach(filePath => this.copyFile(BOILERPLATE_COMMON_BASE_PATH, exampleFolder, filePath));
|
BOILERPLATE_PATHS.common.forEach(
|
||||||
|
filePath => this.copyFile(BOILERPLATE_COMMON_BASE_PATH, exampleFolder, filePath));
|
||||||
|
|
||||||
// Copy Ivy specific files
|
// Copy Ivy specific files
|
||||||
if (ivy) {
|
if (ivy) {
|
||||||
const ivyBoilerPlateType = boilerPlateType === 'systemjs' ? 'systemjs' : 'cli';
|
const ivyBoilerPlateType = boilerPlateType === 'systemjs' ? 'systemjs' : 'cli';
|
||||||
const ivyBoilerPlateBasePath = path.resolve(BOILERPLATE_BASE_PATH, 'ivy', ivyBoilerPlateType);
|
const ivyBoilerPlateBasePath =
|
||||||
BOILERPLATE_PATHS.ivy[ivyBoilerPlateType].forEach(filePath => this.copyFile(ivyBoilerPlateBasePath, exampleFolder, filePath));
|
path.resolve(BOILERPLATE_BASE_PATH, 'ivy', ivyBoilerPlateType);
|
||||||
|
BOILERPLATE_PATHS.ivy[ivyBoilerPlateType].forEach(
|
||||||
|
filePath => this.copyFile(ivyBoilerPlateBasePath, exampleFolder, filePath));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -145,13 +107,10 @@ class ExampleBoilerPlate {
|
|||||||
/**
|
/**
|
||||||
* Remove all the boilerplate files from all the examples
|
* Remove all the boilerplate files from all the examples
|
||||||
*/
|
*/
|
||||||
remove() {
|
remove() { shelljs.exec('git clean -xdfq', {cwd: EXAMPLES_BASE_PATH}); }
|
||||||
shelljs.exec('git clean -xdfq', { cwd: EXAMPLES_BASE_PATH });
|
|
||||||
}
|
|
||||||
|
|
||||||
main() {
|
main() {
|
||||||
yargs
|
yargs.usage('$0 <cmd> [args]')
|
||||||
.usage('$0 <cmd> [args]')
|
|
||||||
.command('add', 'add the boilerplate to each example', (yrgs) => this.add(yrgs.argv.ivy))
|
.command('add', 'add the boilerplate to each example', (yrgs) => this.add(yrgs.argv.ivy))
|
||||||
.command('remove', 'remove the boilerplate from each example', () => this.remove())
|
.command('remove', 'remove the boilerplate from each example', () => this.remove())
|
||||||
.demandCommand(1, 'Please supply a command from the list above')
|
.demandCommand(1, 'Please supply a command from the list above')
|
||||||
@ -161,7 +120,7 @@ class ExampleBoilerPlate {
|
|||||||
getFoldersContaining(basePath, filename, ignore) {
|
getFoldersContaining(basePath, filename, ignore) {
|
||||||
const pattern = path.resolve(basePath, '**', filename);
|
const pattern = path.resolve(basePath, '**', filename);
|
||||||
const ignorePattern = path.resolve(basePath, '**', ignore, '**');
|
const ignorePattern = path.resolve(basePath, '**', ignore, '**');
|
||||||
return glob.sync(pattern, { ignore: [ignorePattern] }).map(file => path.dirname(file));
|
return glob.sync(pattern, {ignore: [ignorePattern]}).map(file => path.dirname(file));
|
||||||
}
|
}
|
||||||
|
|
||||||
copyFile(sourceFolder, destinationFolder, filePath) {
|
copyFile(sourceFolder, destinationFolder, filePath) {
|
||||||
@ -171,13 +130,11 @@ class ExampleBoilerPlate {
|
|||||||
filePath = this.normalizePath(filePath);
|
filePath = this.normalizePath(filePath);
|
||||||
|
|
||||||
const destinationPath = path.resolve(destinationFolder, filePath);
|
const destinationPath = path.resolve(destinationFolder, filePath);
|
||||||
fs.copySync(sourcePath, destinationPath, { overwrite: true });
|
fs.copySync(sourcePath, destinationPath, {overwrite: true});
|
||||||
fs.chmodSync(destinationPath, 444);
|
fs.chmodSync(destinationPath, 444);
|
||||||
}
|
}
|
||||||
|
|
||||||
loadJsonFile(filePath) {
|
loadJsonFile(filePath) { return fs.readJsonSync(filePath, {throws: false}) || {}; }
|
||||||
return fs.readJsonSync(filePath, { throws: false }) || {};
|
|
||||||
}
|
|
||||||
|
|
||||||
normalizePath(filePath) {
|
normalizePath(filePath) {
|
||||||
// transform for example ../cli/src/tsconfig.app.json to src/tsconfig.app.json
|
// transform for example ../cli/src/tsconfig.app.json to src/tsconfig.app.json
|
||||||
|
@ -10,11 +10,25 @@ ivy-ngcc --help
|
|||||||
ivy-ngcc
|
ivy-ngcc
|
||||||
|
|
||||||
# Did it add the appropriate build markers?
|
# Did it add the appropriate build markers?
|
||||||
# - fesm2015
|
|
||||||
ls node_modules/@angular/common | grep __modified_by_ngcc_for_fesm2015
|
|
||||||
if [[ $? != 0 ]]; then exit 1; fi
|
|
||||||
# - esm2015
|
# - esm2015
|
||||||
ls node_modules/@angular/common | grep __modified_by_ngcc_for_esm2015
|
grep '"__modified_by_ngcc__":[^}]*"esm2015":"' node_modules/@angular/common/package.json
|
||||||
|
if [[ $? != 0 ]]; then exit 1; fi
|
||||||
|
|
||||||
|
# - fesm2015
|
||||||
|
grep '"__modified_by_ngcc__":[^}]*"fesm2015":"' node_modules/@angular/common/package.json
|
||||||
|
if [[ $? != 0 ]]; then exit 1; fi
|
||||||
|
grep '"__modified_by_ngcc__":[^}]*"es2015":"' node_modules/@angular/common/package.json
|
||||||
|
if [[ $? != 0 ]]; then exit 1; fi
|
||||||
|
|
||||||
|
# - esm5
|
||||||
|
grep '"__modified_by_ngcc__":[^}]*"esm5":"' node_modules/@angular/common/package.json
|
||||||
|
if [[ $? != 0 ]]; then exit 1; fi
|
||||||
|
|
||||||
|
# - fesm5
|
||||||
|
grep '"__modified_by_ngcc__":[^}]*"module":"' node_modules/@angular/common/package.json
|
||||||
|
if [[ $? != 0 ]]; then exit 1; fi
|
||||||
|
grep '"__modified_by_ngcc__":[^}]*"fesm5":"' node_modules/@angular/common/package.json
|
||||||
if [[ $? != 0 ]]; then exit 1; fi
|
if [[ $? != 0 ]]; then exit 1; fi
|
||||||
|
|
||||||
# Did it replace the PRE_R3 markers correctly?
|
# Did it replace the PRE_R3 markers correctly?
|
||||||
@ -48,6 +62,9 @@ ivy-ngcc
|
|||||||
# Can it be safely run again (as a noop)?
|
# Can it be safely run again (as a noop)?
|
||||||
ivy-ngcc
|
ivy-ngcc
|
||||||
|
|
||||||
|
# Does running it with --formats fail?
|
||||||
|
ivy-ngcc --formats fesm2015 && exit 1
|
||||||
|
|
||||||
# Now try compiling the app using the ngcc compiled libraries
|
# Now try compiling the app using the ngcc compiled libraries
|
||||||
ngc -p tsconfig-app.json
|
ngc -p tsconfig-app.json
|
||||||
|
|
||||||
|
@ -10,7 +10,7 @@ import * as path from 'canonical-path';
|
|||||||
import * as yargs from 'yargs';
|
import * as yargs from 'yargs';
|
||||||
|
|
||||||
import {mainNgcc} from './src/main';
|
import {mainNgcc} from './src/main';
|
||||||
import {EntryPointFormat} from './src/packages/entry_point';
|
import {EntryPointJsonProperty} from './src/packages/entry_point';
|
||||||
|
|
||||||
// CLI entry point
|
// CLI entry point
|
||||||
if (require.main === module) {
|
if (require.main === module) {
|
||||||
@ -22,11 +22,15 @@ if (require.main === module) {
|
|||||||
describe: 'A path to the root folder to compile.',
|
describe: 'A path to the root folder to compile.',
|
||||||
default: './node_modules'
|
default: './node_modules'
|
||||||
})
|
})
|
||||||
.option('f', {
|
.option('f', {alias: 'formats', hidden: true, array: true})
|
||||||
alias: 'formats',
|
.option('p', {
|
||||||
|
alias: 'properties',
|
||||||
array: true,
|
array: true,
|
||||||
describe: 'An array of formats to compile.',
|
describe:
|
||||||
default: ['fesm2015', 'esm2015', 'fesm5', 'esm5']
|
'An array of names of properties in package.json (e.g. `module` or `es2015`)\n' +
|
||||||
|
'These properties should hold a path to a bundle-format to compile.\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.'
|
||||||
})
|
})
|
||||||
.option('t', {
|
.option('t', {
|
||||||
alias: 'target',
|
alias: 'target',
|
||||||
@ -36,11 +40,16 @@ if (require.main === module) {
|
|||||||
.help()
|
.help()
|
||||||
.parse(args);
|
.parse(args);
|
||||||
|
|
||||||
|
if (options['f'] && options['f'].length) {
|
||||||
|
console.error(
|
||||||
|
'The formats option (-f/--formats) has been removed. Consider the properties option (-p/--properties) instead.');
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
const baseSourcePath: string = path.resolve(options['s']);
|
const baseSourcePath: string = path.resolve(options['s']);
|
||||||
const formats: EntryPointFormat[] = options['f'];
|
const propertiesToConsider: EntryPointJsonProperty[] = options['p'];
|
||||||
const baseTargetPath: string = options['t'];
|
const baseTargetPath: string = options['t'];
|
||||||
try {
|
try {
|
||||||
mainNgcc({baseSourcePath, formats, baseTargetPath});
|
mainNgcc({baseSourcePath, propertiesToConsider, baseTargetPath});
|
||||||
process.exitCode = 0;
|
process.exitCode = 0;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error(e.stack || e.message);
|
console.error(e.stack || e.message);
|
||||||
|
@ -6,10 +6,10 @@
|
|||||||
* found in the LICENSE file at https://angular.io/license
|
* found in the LICENSE file at https://angular.io/license
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {checkMarkerFile, writeMarkerFile} from './packages/build_marker';
|
import {checkMarker, writeMarker} from './packages/build_marker';
|
||||||
import {DependencyHost} from './packages/dependency_host';
|
import {DependencyHost} from './packages/dependency_host';
|
||||||
import {DependencyResolver} from './packages/dependency_resolver';
|
import {DependencyResolver} from './packages/dependency_resolver';
|
||||||
import {EntryPointFormat} from './packages/entry_point';
|
import {EntryPointFormat, EntryPointJsonProperty, getEntryPointFormat} from './packages/entry_point';
|
||||||
import {makeEntryPointBundle} from './packages/entry_point_bundle';
|
import {makeEntryPointBundle} from './packages/entry_point_bundle';
|
||||||
import {EntryPointFinder} from './packages/entry_point_finder';
|
import {EntryPointFinder} from './packages/entry_point_finder';
|
||||||
import {Transformer} from './packages/transformer';
|
import {Transformer} from './packages/transformer';
|
||||||
@ -20,8 +20,6 @@ import {Transformer} from './packages/transformer';
|
|||||||
export interface NgccOptions {
|
export interface NgccOptions {
|
||||||
/** The path to the node_modules folder that contains the packages to compile. */
|
/** The path to the node_modules folder that contains the packages to compile. */
|
||||||
baseSourcePath: string;
|
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. */
|
/** The path to the node_modules folder where modified files should be written. */
|
||||||
baseTargetPath?: string;
|
baseTargetPath?: string;
|
||||||
/**
|
/**
|
||||||
@ -29,8 +27,15 @@ export interface NgccOptions {
|
|||||||
* All its dependencies will need to be compiled too.
|
* All its dependencies will need to be compiled too.
|
||||||
*/
|
*/
|
||||||
targetEntryPointPath?: string;
|
targetEntryPointPath?: string;
|
||||||
|
/**
|
||||||
|
* Which entry-point properties in the package.json to consider when compiling.
|
||||||
|
* Each of properties contain a path to particular bundle format for a given entry-point.
|
||||||
|
*/
|
||||||
|
propertiesToConsider?: EntryPointJsonProperty[];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const SUPPORTED_FORMATS: EntryPointFormat[] = ['esm5', 'esm2015', 'fesm5', 'fesm2015'];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This is the main entry-point into ngcc (aNGular Compatibility Compiler).
|
* This is the main entry-point into ngcc (aNGular Compatibility Compiler).
|
||||||
*
|
*
|
||||||
@ -39,8 +44,8 @@ export interface NgccOptions {
|
|||||||
*
|
*
|
||||||
* @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, formats, baseTargetPath = baseSourcePath,
|
export function mainNgcc({baseSourcePath, baseTargetPath = baseSourcePath, targetEntryPointPath,
|
||||||
targetEntryPointPath}: NgccOptions): void {
|
propertiesToConsider}: NgccOptions): void {
|
||||||
const transformer = new Transformer(baseSourcePath, baseTargetPath);
|
const transformer = new Transformer(baseSourcePath, baseTargetPath);
|
||||||
const host = new DependencyHost();
|
const host = new DependencyHost();
|
||||||
const resolver = new DependencyResolver(host);
|
const resolver = new DependencyResolver(host);
|
||||||
@ -52,28 +57,51 @@ export function mainNgcc({baseSourcePath, formats, baseTargetPath = baseSourcePa
|
|||||||
// Are we compiling the Angular core?
|
// Are we compiling the Angular core?
|
||||||
const isCore = entryPoint.name === '@angular/core';
|
const isCore = entryPoint.name === '@angular/core';
|
||||||
|
|
||||||
// We transform the d.ts typings files while transforming one of the formats.
|
let dtsTransformFormat: EntryPointFormat|undefined;
|
||||||
// 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 => {
|
const propertiesToCompile =
|
||||||
if (checkMarkerFile(entryPoint, format)) {
|
propertiesToConsider || Object.keys(entryPoint.packageJson) as EntryPointJsonProperty[];
|
||||||
console.warn(`Skipping ${entryPoint.name} : ${format} (already built).`);
|
const compiledFormats = new Set<EntryPointFormat>();
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
for (let i = 0; i < propertiesToCompile.length; i++) {
|
||||||
|
const property = propertiesToCompile[i];
|
||||||
|
const format = getEntryPointFormat(entryPoint.packageJson, property);
|
||||||
|
|
||||||
|
// No format then this property is not supposed to be compiled.
|
||||||
|
if (!format || SUPPORTED_FORMATS.indexOf(format) === -1) continue;
|
||||||
|
|
||||||
|
// We don't want to compile a format more than once.
|
||||||
|
// This could happen if there are multiple properties that map to the same format...
|
||||||
|
// E.g. `fesm5` and `module` both can point to the flat ESM5 format.
|
||||||
|
if (!compiledFormats.has(format)) {
|
||||||
|
compiledFormats.add(format);
|
||||||
|
|
||||||
|
// Use the first format found for typings transformation.
|
||||||
|
dtsTransformFormat = dtsTransformFormat || format;
|
||||||
|
|
||||||
|
|
||||||
|
if (checkMarker(entryPoint, property)) {
|
||||||
const bundle =
|
const bundle =
|
||||||
makeEntryPointBundle(entryPoint, isCore, format, format === dtsTransformFormat);
|
makeEntryPointBundle(entryPoint, isCore, format, format === dtsTransformFormat);
|
||||||
if (bundle === null) {
|
if (bundle) {
|
||||||
|
transformer.transform(entryPoint, isCore, bundle);
|
||||||
|
} else {
|
||||||
console.warn(
|
console.warn(
|
||||||
`Skipping ${entryPoint.name} : ${format} (no entry point file for this format).`);
|
`Skipping ${entryPoint.name} : ${format} (no entry point file for this format).`);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
transformer.transform(entryPoint, isCore, bundle);
|
console.warn(`Skipping ${entryPoint.name} : ${property} (already compiled).`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Write the built-with-ngcc marker.
|
||||||
|
writeMarker(entryPoint, property);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Write the built-with-ngcc marker
|
if (!dtsTransformFormat) {
|
||||||
writeMarkerFile(entryPoint, format);
|
throw new Error(
|
||||||
});
|
`Failed to compile any formats for entry-point at (${entryPoint.path}). Tried ${propertiesToCompile}.`);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export {NGCC_VERSION} from './packages/build_marker';
|
@ -7,35 +7,42 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import {resolve} from 'canonical-path';
|
import {resolve} from 'canonical-path';
|
||||||
import {existsSync, readFileSync, writeFileSync} from 'fs';
|
import {writeFileSync} from 'fs';
|
||||||
import {EntryPoint, EntryPointFormat} from './entry_point';
|
|
||||||
|
import {EntryPoint, EntryPointJsonProperty} from './entry_point';
|
||||||
|
|
||||||
export const NGCC_VERSION = '0.0.0-PLACEHOLDER';
|
export const NGCC_VERSION = '0.0.0-PLACEHOLDER';
|
||||||
|
|
||||||
function getMarkerPath(entryPointPath: string, format: EntryPointFormat) {
|
|
||||||
return resolve(entryPointPath, `__modified_by_ngcc_for_${format}__`);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check whether there is a build marker for the given entry point and format.
|
* Check whether there is a build marker for the given entry-point and format property.
|
||||||
* @param entryPoint the entry point to check for a marker.
|
* @param entryPoint the entry-point to check for a marker.
|
||||||
* @param format the format for which we are checking 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 built with this ngcc version.
|
||||||
|
* @throws Error if the entry-point and format have already been built with a different ngcc
|
||||||
|
* version.
|
||||||
*/
|
*/
|
||||||
export function checkMarkerFile(entryPoint: EntryPoint, format: EntryPointFormat): boolean {
|
export function checkMarker(entryPoint: EntryPoint, format: EntryPointJsonProperty): boolean {
|
||||||
const markerPath = getMarkerPath(entryPoint.path, format);
|
const pkg = entryPoint.packageJson;
|
||||||
const markerExists = existsSync(markerPath);
|
const compiledVersion = pkg.__modified_by_ngcc__ && pkg.__modified_by_ngcc__[format];
|
||||||
if (markerExists) {
|
if (compiledVersion && compiledVersion !== NGCC_VERSION) {
|
||||||
const previousVersion = readFileSync(markerPath, 'utf8');
|
|
||||||
if (previousVersion !== 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' +
|
||||||
'Please completely remove `node_modules` and try again.');
|
'Please completely remove `node_modules` and try again.');
|
||||||
}
|
}
|
||||||
}
|
return !!compiledVersion;
|
||||||
return markerExists;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function writeMarkerFile(entryPoint: EntryPoint, format: EntryPointFormat) {
|
/**
|
||||||
const markerPath = getMarkerPath(entryPoint.path, format);
|
* Write a build marker for the given entry-point and format property, to indicate that it has
|
||||||
writeFileSync(markerPath, NGCC_VERSION, 'utf8');
|
* been compiled by this version of ngcc.
|
||||||
|
*
|
||||||
|
* @param entryPoint the entry-point to write a marker.
|
||||||
|
* @param format the property in the package.json of the format for which we are writing the marker.
|
||||||
|
*/
|
||||||
|
export function writeMarker(entryPoint: EntryPoint, format: EntryPointJsonProperty) {
|
||||||
|
const pkg = entryPoint.packageJson;
|
||||||
|
if (!pkg.__modified_by_ngcc__) pkg.__modified_by_ngcc__ = {};
|
||||||
|
pkg.__modified_by_ngcc__[format] = NGCC_VERSION;
|
||||||
|
writeFileSync(resolve(entryPoint.path, 'package.json'), JSON.stringify(pkg), 'utf8');
|
||||||
}
|
}
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
|
|
||||||
import * as path from 'canonical-path';
|
import * as path from 'canonical-path';
|
||||||
import * as fs from 'fs';
|
import * as fs from 'fs';
|
||||||
|
import {isDefined} from '../utils';
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -33,6 +34,8 @@ export type EntryPointFormat = keyof(EntryPointPaths);
|
|||||||
export interface EntryPoint extends EntryPointPaths {
|
export interface EntryPoint extends EntryPointPaths {
|
||||||
/** The name of the package (e.g. `@angular/core`). */
|
/** The name of the package (e.g. `@angular/core`). */
|
||||||
name: string;
|
name: string;
|
||||||
|
/** The parsed package.json file for this entry-point. */
|
||||||
|
packageJson: EntryPointPackageJson;
|
||||||
/** The path to the package that contains this entry-point. */
|
/** The path to the package that contains this entry-point. */
|
||||||
package: string;
|
package: string;
|
||||||
/** The path to this entry point. */
|
/** The path to this entry point. */
|
||||||
@ -41,11 +44,7 @@ export interface EntryPoint extends EntryPointPaths {
|
|||||||
typings: string;
|
typings: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
interface PackageJsonFormatProperties {
|
||||||
* The properties that may be loaded from the `package.json` file.
|
|
||||||
*/
|
|
||||||
interface EntryPointPackageJson {
|
|
||||||
name: string;
|
|
||||||
fesm2015?: string;
|
fesm2015?: string;
|
||||||
fesm5?: string;
|
fesm5?: string;
|
||||||
es2015?: string; // if exists then it is actually FESM2015
|
es2015?: string; // if exists then it is actually FESM2015
|
||||||
@ -57,6 +56,103 @@ interface EntryPointPackageJson {
|
|||||||
typings?: string; // TypeScript .d.ts files
|
typings?: string; // TypeScript .d.ts files
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The properties that may be loaded from the `package.json` file.
|
||||||
|
*/
|
||||||
|
export interface EntryPointPackageJson extends PackageJsonFormatProperties {
|
||||||
|
name: string;
|
||||||
|
__modified_by_ngcc__?: {[key: string]: string};
|
||||||
|
}
|
||||||
|
|
||||||
|
export type EntryPointJsonProperty = keyof(PackageJsonFormatProperties);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Try to create an entry-point from the given paths and properties.
|
||||||
|
*
|
||||||
|
* @param packagePath the absolute path to the containing npm package
|
||||||
|
* @param entryPointPath the absolute path to the potential entry-point.
|
||||||
|
* @returns An entry-point if it is valid, `null` otherwise.
|
||||||
|
*/
|
||||||
|
export function getEntryPointInfo(packagePath: string, entryPointPath: string): EntryPoint|null {
|
||||||
|
const packageJsonPath = path.resolve(entryPointPath, 'package.json');
|
||||||
|
if (!fs.existsSync(packageJsonPath)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const entryPointPackageJson = loadEntryPointPackage(packageJsonPath);
|
||||||
|
if (!entryPointPackageJson) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// We must have a typings property
|
||||||
|
const typings = entryPointPackageJson.typings || entryPointPackageJson.types;
|
||||||
|
if (!typings) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Also there must exist a `metadata.json` file next to the typings entry-point.
|
||||||
|
const metadataPath =
|
||||||
|
path.resolve(entryPointPath, typings.replace(/\.d\.ts$/, '') + '.metadata.json');
|
||||||
|
if (!fs.existsSync(metadataPath)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const formats = Object.keys(entryPointPackageJson)
|
||||||
|
.map((property: EntryPointJsonProperty) => {
|
||||||
|
const format = getEntryPointFormat(entryPointPackageJson, property);
|
||||||
|
return format ? {property, format} : undefined;
|
||||||
|
})
|
||||||
|
.filter(isDefined);
|
||||||
|
|
||||||
|
const entryPointInfo: EntryPoint = {
|
||||||
|
name: entryPointPackageJson.name,
|
||||||
|
packageJson: entryPointPackageJson,
|
||||||
|
package: packagePath,
|
||||||
|
path: entryPointPath,
|
||||||
|
typings: path.resolve(entryPointPath, typings)
|
||||||
|
};
|
||||||
|
|
||||||
|
// Add the formats to the entry-point info object.
|
||||||
|
formats.forEach(
|
||||||
|
item => entryPointInfo[item.format] =
|
||||||
|
path.resolve(entryPointPath, entryPointPackageJson[item.property] !));
|
||||||
|
|
||||||
|
return entryPointInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert a package.json property into an entry-point format.
|
||||||
|
*
|
||||||
|
* The actual format is dependent not only on the property itself but also
|
||||||
|
* on what other properties exist in the package.json.
|
||||||
|
*
|
||||||
|
* @param entryPointProperties The package.json that contains the properties.
|
||||||
|
* @param property The property to convert to a format.
|
||||||
|
* @returns An entry-point format or `undefined` if none match the given property.
|
||||||
|
*/
|
||||||
|
export function getEntryPointFormat(
|
||||||
|
entryPointProperties: EntryPointPackageJson, property: string): EntryPointFormat|undefined {
|
||||||
|
switch (property) {
|
||||||
|
case 'fesm2015':
|
||||||
|
return 'fesm2015';
|
||||||
|
case 'fesm5':
|
||||||
|
return 'fesm5';
|
||||||
|
case 'es2015':
|
||||||
|
return !entryPointProperties.fesm2015 ? 'fesm2015' : 'esm2015';
|
||||||
|
case 'esm2015':
|
||||||
|
return 'esm2015';
|
||||||
|
case 'esm5':
|
||||||
|
return 'esm5';
|
||||||
|
case 'main':
|
||||||
|
return 'umd';
|
||||||
|
case 'module':
|
||||||
|
return !entryPointProperties.fesm5 ? 'fesm5' : 'esm5';
|
||||||
|
default:
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parses the JSON from a package.json file.
|
* Parses the JSON from a package.json file.
|
||||||
* @param packageJsonPath the absolute path to the package.json file.
|
* @param packageJsonPath the absolute path to the package.json file.
|
||||||
@ -71,72 +167,3 @@ function loadEntryPointPackage(packageJsonPath: string): EntryPointPackageJson|n
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Try to get an entry point from the given path.
|
|
||||||
* @param packagePath the absolute path to the containing npm package
|
|
||||||
* @param entryPointPath the absolute path to the potential entry point.
|
|
||||||
* @returns Info about the entry point if it is valid, `null` otherwise.
|
|
||||||
*/
|
|
||||||
export function getEntryPointInfo(packagePath: string, entryPointPath: string): EntryPoint|null {
|
|
||||||
const packageJsonPath = path.resolve(entryPointPath, 'package.json');
|
|
||||||
if (!fs.existsSync(packageJsonPath)) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
const entryPointPackageJson = loadEntryPointPackage(packageJsonPath);
|
|
||||||
if (!entryPointPackageJson) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If there is `esm2015` then `es2015` will be FESM2015, otherwise ESM2015.
|
|
||||||
// If there is `esm5` then `module` will be FESM5, otherwise it will be ESM5.
|
|
||||||
const {
|
|
||||||
name,
|
|
||||||
module: modulePath,
|
|
||||||
types,
|
|
||||||
typings = types, // synonymous
|
|
||||||
es2015,
|
|
||||||
fesm2015 = es2015, // synonymous
|
|
||||||
fesm5 = modulePath, // synonymous
|
|
||||||
esm2015,
|
|
||||||
esm5,
|
|
||||||
main
|
|
||||||
} = entryPointPackageJson;
|
|
||||||
// Minimum requirement is that we have typings and one of esm2015 or fesm2015 formats.
|
|
||||||
if (!typings || !(fesm2015 || esm2015)) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Also there must exist a `metadata.json` file next to the typings entry-point.
|
|
||||||
const metadataPath =
|
|
||||||
path.resolve(entryPointPath, typings.replace(/\.d\.ts$/, '') + '.metadata.json');
|
|
||||||
if (!fs.existsSync(metadataPath)) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
const entryPointInfo: EntryPoint = {
|
|
||||||
name,
|
|
||||||
package: packagePath,
|
|
||||||
path: entryPointPath,
|
|
||||||
typings: path.resolve(entryPointPath, typings),
|
|
||||||
};
|
|
||||||
|
|
||||||
if (esm2015) {
|
|
||||||
entryPointInfo.esm2015 = path.resolve(entryPointPath, esm2015);
|
|
||||||
}
|
|
||||||
if (fesm2015) {
|
|
||||||
entryPointInfo.fesm2015 = path.resolve(entryPointPath, fesm2015);
|
|
||||||
}
|
|
||||||
if (fesm5) {
|
|
||||||
entryPointInfo.fesm5 = path.resolve(entryPointPath, fesm5);
|
|
||||||
}
|
|
||||||
if (esm5) {
|
|
||||||
entryPointInfo.esm5 = path.resolve(entryPointPath, esm5);
|
|
||||||
}
|
|
||||||
if (main) {
|
|
||||||
entryPointInfo.umd = path.resolve(entryPointPath, main);
|
|
||||||
}
|
|
||||||
|
|
||||||
return entryPointInfo;
|
|
||||||
}
|
|
||||||
|
@ -19,38 +19,74 @@ describe('ngcc main()', () => {
|
|||||||
afterEach(restoreRealFileSystem);
|
afterEach(restoreRealFileSystem);
|
||||||
|
|
||||||
it('should run ngcc without errors for fesm2015', () => {
|
it('should run ngcc without errors for fesm2015', () => {
|
||||||
expect(() => mainNgcc({baseSourcePath: '/node_modules', formats: ['fesm2015']})).not.toThrow();
|
expect(() => mainNgcc({baseSourcePath: '/node_modules', propertiesToConsider: ['fesm2015']}))
|
||||||
|
.not.toThrow();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should run ngcc without errors for fesm5', () => {
|
it('should run ngcc without errors for fesm5', () => {
|
||||||
expect(() => mainNgcc({baseSourcePath: '/node_modules', formats: ['fesm5']})).not.toThrow();
|
expect(() => mainNgcc({baseSourcePath: '/node_modules', propertiesToConsider: ['fesm5']}))
|
||||||
|
.not.toThrow();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should run ngcc without errors for esm2015', () => {
|
it('should run ngcc without errors for esm2015', () => {
|
||||||
expect(() => mainNgcc({baseSourcePath: '/node_modules', formats: ['esm2015']})).not.toThrow();
|
expect(() => mainNgcc({baseSourcePath: '/node_modules', propertiesToConsider: ['esm2015']}))
|
||||||
|
.not.toThrow();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should run ngcc without errors for esm5', () => {
|
it('should run ngcc without errors for esm5', () => {
|
||||||
expect(() => mainNgcc({baseSourcePath: '/node_modules', formats: ['esm5']})).not.toThrow();
|
expect(() => mainNgcc({baseSourcePath: '/node_modules', propertiesToConsider: ['esm5']}))
|
||||||
|
.not.toThrow();
|
||||||
});
|
});
|
||||||
|
|
||||||
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({baseSourcePath: '/node_modules', targetEntryPointPath: '@angular/common/http'});
|
||||||
baseSourcePath: '/node_modules',
|
|
||||||
formats: ['esm2015'],
|
|
||||||
targetEntryPointPath: '@angular/common'
|
|
||||||
});
|
|
||||||
|
|
||||||
expect(loadPackage('@angular/common').__modified_by_ngcc__).toEqual({
|
expect(loadPackage('@angular/common/http').__modified_by_ngcc__).toEqual({
|
||||||
esm2015: '0.0.0-PLACEHOLDER',
|
module: '0.0.0-PLACEHOLDER',
|
||||||
es2015: '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({
|
expect(loadPackage('@angular/core').__modified_by_ngcc__).toEqual({
|
||||||
esm2015: '0.0.0-PLACEHOLDER',
|
module: '0.0.0-PLACEHOLDER',
|
||||||
es2015: '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();
|
expect(loadPackage('@angular/common/testing').__modified_by_ngcc__).toBeUndefined();
|
||||||
expect(loadPackage('@angular/common/http').__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',
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -6,10 +6,10 @@
|
|||||||
* found in the LICENSE file at https://angular.io/license
|
* found in the LICENSE file at https://angular.io/license
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {existsSync, readFileSync, writeFileSync} from 'fs';
|
import {readFileSync, writeFileSync} from 'fs';
|
||||||
import * as mockFs from 'mock-fs';
|
import * as mockFs from 'mock-fs';
|
||||||
|
|
||||||
import {checkMarkerFile, writeMarkerFile} from '../../src/packages/build_marker';
|
import {checkMarker, writeMarker} from '../../src/packages/build_marker';
|
||||||
import {EntryPoint} from '../../src/packages/entry_point';
|
import {EntryPoint} from '../../src/packages/entry_point';
|
||||||
|
|
||||||
function createMockFileSystem() {
|
function createMockFileSystem() {
|
||||||
@ -94,58 +94,55 @@ function restoreRealFileSystem() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function createEntryPoint(path: string): EntryPoint {
|
function createEntryPoint(path: string): EntryPoint {
|
||||||
return {name: 'some-package', path, package: '', typings: ''};
|
return {
|
||||||
|
name: 'some-package',
|
||||||
|
path,
|
||||||
|
package: path,
|
||||||
|
typings: '',
|
||||||
|
packageJson: JSON.parse(readFileSync(path + '/package.json', 'utf8'))
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
describe('Marker files', () => {
|
describe('Marker files', () => {
|
||||||
beforeEach(createMockFileSystem);
|
beforeEach(createMockFileSystem);
|
||||||
afterEach(restoreRealFileSystem);
|
afterEach(restoreRealFileSystem);
|
||||||
|
|
||||||
describe('writeMarkerFile', () => {
|
describe('writeMarker', () => {
|
||||||
it('should write a file containing the version placeholder', () => {
|
it('should write a property in the package.json containing the version placeholder', () => {
|
||||||
expect(existsSync('/node_modules/@angular/common/__modified_by_ngcc_for_fesm2015__'))
|
let pkg = JSON.parse(readFileSync('/node_modules/@angular/common/package.json', 'utf8'));
|
||||||
.toBe(false);
|
expect(pkg.__modified_by_ngcc__).toBeUndefined();
|
||||||
expect(existsSync('/node_modules/@angular/common/__modified_by_ngcc_for_esm5__')).toBe(false);
|
expect(pkg.__modified_by_ngcc__).toBeUndefined();
|
||||||
|
|
||||||
writeMarkerFile(createEntryPoint('/node_modules/@angular/common'), 'fesm2015');
|
writeMarker(createEntryPoint('/node_modules/@angular/common'), 'fesm2015');
|
||||||
expect(existsSync('/node_modules/@angular/common/__modified_by_ngcc_for_fesm2015__'))
|
pkg = JSON.parse(readFileSync('/node_modules/@angular/common/package.json', 'utf8'));
|
||||||
.toBe(true);
|
expect(pkg.__modified_by_ngcc__.fesm2015).toEqual('0.0.0-PLACEHOLDER');
|
||||||
expect(existsSync('/node_modules/@angular/common/__modified_by_ngcc_for_esm5__')).toBe(false);
|
expect(pkg.__modified_by_ngcc__.esm5).toBeUndefined();
|
||||||
expect(
|
|
||||||
readFileSync('/node_modules/@angular/common/__modified_by_ngcc_for_fesm2015__', 'utf8'))
|
|
||||||
.toEqual('0.0.0-PLACEHOLDER');
|
|
||||||
|
|
||||||
writeMarkerFile(createEntryPoint('/node_modules/@angular/common'), 'esm5');
|
writeMarker(createEntryPoint('/node_modules/@angular/common'), 'esm5');
|
||||||
expect(existsSync('/node_modules/@angular/common/__modified_by_ngcc_for_fesm2015__'))
|
pkg = JSON.parse(readFileSync('/node_modules/@angular/common/package.json', 'utf8'));
|
||||||
.toBe(true);
|
expect(pkg.__modified_by_ngcc__.fesm2015).toEqual('0.0.0-PLACEHOLDER');
|
||||||
expect(existsSync('/node_modules/@angular/common/__modified_by_ngcc_for_esm5__')).toBe(true);
|
expect(pkg.__modified_by_ngcc__.esm5).toEqual('0.0.0-PLACEHOLDER');
|
||||||
expect(
|
|
||||||
readFileSync('/node_modules/@angular/common/__modified_by_ngcc_for_fesm2015__', 'utf8'))
|
|
||||||
.toEqual('0.0.0-PLACEHOLDER');
|
|
||||||
expect(readFileSync('/node_modules/@angular/common/__modified_by_ngcc_for_esm5__', 'utf8'))
|
|
||||||
.toEqual('0.0.0-PLACEHOLDER');
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('checkMarkerFile', () => {
|
describe('checkMarker', () => {
|
||||||
it('should return false if the marker file does not exist', () => {
|
it('should return false if the marker property does not exist', () => {
|
||||||
expect(checkMarkerFile(createEntryPoint('/node_modules/@angular/common'), 'fesm2015'))
|
expect(checkMarker(createEntryPoint('/node_modules/@angular/common'), 'fesm2015'))
|
||||||
.toBe(false);
|
.toBe(false);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should return true if the marker file exists and contains the correct version', () => {
|
it('should return true if the marker property exists and contains the correct version', () => {
|
||||||
writeFileSync(
|
const pkg = JSON.parse(readFileSync('/node_modules/@angular/common/package.json', 'utf8'));
|
||||||
'/node_modules/@angular/common/__modified_by_ngcc_for_fesm2015__', '0.0.0-PLACEHOLDER',
|
pkg.__modified_by_ngcc__ = {fesm2015: '0.0.0-PLACEHOLDER'};
|
||||||
'utf8');
|
writeFileSync('/node_modules/@angular/common/package.json', JSON.stringify(pkg), 'utf8');
|
||||||
expect(checkMarkerFile(createEntryPoint('/node_modules/@angular/common'), 'fesm2015'))
|
expect(checkMarker(createEntryPoint('/node_modules/@angular/common'), 'fesm2015')).toBe(true);
|
||||||
.toBe(true);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should throw if the marker file exists but contains the wrong version', () => {
|
it('should throw if the marker property exists but contains the wrong version', () => {
|
||||||
writeFileSync(
|
const pkg = JSON.parse(readFileSync('/node_modules/@angular/common/package.json', 'utf8'));
|
||||||
'/node_modules/@angular/common/__modified_by_ngcc_for_fesm2015__', 'WRONG_VERSION',
|
pkg.__modified_by_ngcc__ = {fesm2015: 'WRONG_VERSION'};
|
||||||
'utf8');
|
writeFileSync('/node_modules/@angular/common/package.json', JSON.stringify(pkg), 'utf8');
|
||||||
expect(() => checkMarkerFile(createEntryPoint('/node_modules/@angular/common'), 'fesm2015'))
|
expect(() => checkMarker(createEntryPoint('/node_modules/@angular/common'), 'fesm2015'))
|
||||||
.toThrowError(
|
.toThrowError(
|
||||||
'The ngcc compiler has changed since the last ngcc build.\n' +
|
'The ngcc compiler has changed since the last ngcc build.\n' +
|
||||||
'Please completely remove `node_modules` and try again.');
|
'Please completely remove `node_modules` and try again.');
|
||||||
|
@ -6,10 +6,10 @@
|
|||||||
* found in the LICENSE file at https://angular.io/license
|
* found in the LICENSE file at https://angular.io/license
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import {readFileSync} from 'fs';
|
||||||
import * as mockFs from 'mock-fs';
|
import * as mockFs from 'mock-fs';
|
||||||
import {getEntryPointInfo} from '../../src/packages/entry_point';
|
import {getEntryPointInfo} from '../../src/packages/entry_point';
|
||||||
|
|
||||||
|
|
||||||
describe('getEntryPointInfo()', () => {
|
describe('getEntryPointInfo()', () => {
|
||||||
beforeEach(createMockFileSystem);
|
beforeEach(createMockFileSystem);
|
||||||
afterEach(restoreRealFileSystem);
|
afterEach(restoreRealFileSystem);
|
||||||
@ -27,6 +27,7 @@ describe('getEntryPointInfo()', () => {
|
|||||||
fesm5: `/some_package/valid_entry_point/fesm2015/valid_entry_point.js`,
|
fesm5: `/some_package/valid_entry_point/fesm2015/valid_entry_point.js`,
|
||||||
esm5: `/some_package/valid_entry_point/esm2015/valid_entry_point.js`,
|
esm5: `/some_package/valid_entry_point/esm2015/valid_entry_point.js`,
|
||||||
umd: `/some_package/valid_entry_point/bundles/valid_entry_point.umd.js`,
|
umd: `/some_package/valid_entry_point/bundles/valid_entry_point.umd.js`,
|
||||||
|
packageJson: loadPackageJson('/some_package/valid_entry_point'),
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -63,6 +64,7 @@ describe('getEntryPointInfo()', () => {
|
|||||||
fesm5: `/some_package/types_rather_than_typings/fesm2015/types_rather_than_typings.js`,
|
fesm5: `/some_package/types_rather_than_typings/fesm2015/types_rather_than_typings.js`,
|
||||||
esm5: `/some_package/types_rather_than_typings/esm2015/types_rather_than_typings.js`,
|
esm5: `/some_package/types_rather_than_typings/esm2015/types_rather_than_typings.js`,
|
||||||
umd: `/some_package/types_rather_than_typings/bundles/types_rather_than_typings.umd.js`,
|
umd: `/some_package/types_rather_than_typings/bundles/types_rather_than_typings.umd.js`,
|
||||||
|
packageJson: loadPackageJson('/some_package/types_rather_than_typings'),
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -76,6 +78,7 @@ describe('getEntryPointInfo()', () => {
|
|||||||
fesm2015: `/some_package/material_style/esm2015/material_style.js`,
|
fesm2015: `/some_package/material_style/esm2015/material_style.js`,
|
||||||
fesm5: `/some_package/material_style/esm5/material_style.es5.js`,
|
fesm5: `/some_package/material_style/esm5/material_style.es5.js`,
|
||||||
umd: `/some_package/material_style/bundles/material_style.umd.js`,
|
umd: `/some_package/material_style/bundles/material_style.umd.js`,
|
||||||
|
packageJson: loadPackageJson('/some_package/material_style'),
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -154,3 +157,7 @@ function createPackageJson(
|
|||||||
}
|
}
|
||||||
return JSON.stringify(packageJson);
|
return JSON.stringify(packageJson);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function loadPackageJson(packagePath: string) {
|
||||||
|
return JSON.parse(readFileSync(packagePath + '/package.json', 'utf8'));
|
||||||
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user