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
* /
2019-06-06 15:22:32 -04:00
import { AbsoluteFsPath , FileSystem , absoluteFrom , getFileSystem , join } from '../../../src/ngtsc/file_system' ;
import { Folder , MockFileSystem , runInEachFileSystem } from '../../../src/ngtsc/file_system/testing' ;
import { loadStandardTestFiles , loadTestFiles } from '../../../test/helpers' ;
2019-04-06 10:35:13 -04:00
import { mainNgcc } from '../../src/main' ;
2019-04-06 10:35:40 -04:00
import { markAsProcessed } from '../../src/packages/build_marker' ;
import { EntryPointJsonProperty , EntryPointPackageJson , SUPPORTED_FORMAT_PROPERTIES } from '../../src/packages/entry_point' ;
2019-04-06 10:35:13 -04:00
import { MockLogger } from '../helpers/mock_logger' ;
2018-07-16 03:49:56 -04:00
2019-06-06 15:22:32 -04:00
const testFiles = loadStandardTestFiles ( { fakeCore : false , rxjs : true } ) ;
2018-07-25 06:06:32 -04:00
2019-06-06 15:22:32 -04:00
runInEachFileSystem ( ( ) = > {
describe ( 'ngcc main()' , ( ) = > {
let _ : typeof absoluteFrom ;
let fs : FileSystem ;
2019-03-20 09:47:58 -04:00
2019-06-06 15:22:32 -04:00
beforeEach ( ( ) = > {
_ = absoluteFrom ;
fs = getFileSystem ( ) ;
initMockFileSystem ( fs , testFiles ) ;
2019-06-10 08:52:11 -04:00
} ) ;
2019-06-06 15:22:32 -04:00
it ( 'should run ngcc without errors for esm2015' , ( ) = > {
expect ( ( ) = > mainNgcc ( { basePath : '/node_modules' , propertiesToConsider : [ 'esm2015' ] } ) )
. not . toThrow ( ) ;
2019-06-10 08:52:11 -04:00
} ) ;
2019-06-06 15:22:32 -04:00
it ( 'should run ngcc without errors for esm5' , ( ) = > {
expect ( ( ) = > mainNgcc ( {
basePath : '/node_modules' ,
propertiesToConsider : [ 'esm5' ] ,
logger : new MockLogger ( ) ,
} ) )
. not . toThrow ( ) ;
2019-03-20 09:47:59 -04:00
} ) ;
2019-06-06 15:22:32 -04:00
it ( 'should run ngcc without errors when "main" property is not present' , ( ) = > {
mainNgcc ( {
basePath : '/dist' ,
propertiesToConsider : [ 'main' , 'es2015' ] ,
logger : new MockLogger ( ) ,
} ) ;
2019-03-20 09:47:59 -04:00
2019-06-06 15:22:32 -04:00
expect ( loadPackage ( 'local-package' , _ ( '/dist' ) ) . __processed_by_ivy_ngcc__ ) . toEqual ( {
2019-03-20 09:47:59 -04:00
es2015 : '0.0.0-PLACEHOLDER' ,
2019-06-06 15:22:32 -04:00
typings : '0.0.0-PLACEHOLDER' ,
2019-03-20 09:47:59 -04:00
} ) ;
2019-03-20 09:47:58 -04:00
} ) ;
2019-03-20 09:47:58 -04:00
2019-06-06 15:22:32 -04:00
describe ( 'with targetEntryPointPath' , ( ) = > {
it ( 'should only compile the given package entry-point (and its dependencies).' , ( ) = > {
const STANDARD_MARKERS = {
main : '0.0.0-PLACEHOLDER' ,
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' ,
typings : '0.0.0-PLACEHOLDER' ,
} ;
mainNgcc ( { basePath : '/node_modules' , targetEntryPointPath : '@angular/common/http/testing' } ) ;
expect ( loadPackage ( '@angular/common/http/testing' ) . __processed_by_ivy_ngcc__ )
. toEqual ( STANDARD_MARKERS ) ;
// * `common/http` is a dependency of `common/http/testing`, so is compiled.
expect ( loadPackage ( '@angular/common/http' ) . __processed_by_ivy_ngcc__ )
. toEqual ( STANDARD_MARKERS ) ;
// * `core` is a dependency of `common/http`, so is compiled.
expect ( loadPackage ( '@angular/core' ) . __processed_by_ivy_ngcc__ ) . toEqual ( STANDARD_MARKERS ) ;
// * `common` is a private (only in .js not .d.ts) dependency so is compiled.
expect ( loadPackage ( '@angular/common' ) . __processed_by_ivy_ngcc__ ) . toEqual ( STANDARD_MARKERS ) ;
// * `common/testing` is not a dependency so is not compiled.
expect ( loadPackage ( '@angular/common/testing' ) . __processed_by_ivy_ngcc__ ) . toBeUndefined ( ) ;
2019-04-06 10:35:40 -04:00
} ) ;
2019-06-06 15:22:32 -04:00
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' ,
2019-08-04 10:51:37 -04:00
esm2015 : '0.0.0-PLACEHOLDER' ,
esm5 : '0.0.0-PLACEHOLDER' ,
fesm2015 : '0.0.0-PLACEHOLDER' ,
fesm5 : '0.0.0-PLACEHOLDER' ,
main : '0.0.0-PLACEHOLDER' ,
module : '0.0.0-PLACEHOLDER' ,
2019-04-06 10:35:40 -04:00
} ) ;
2019-06-06 15:22:32 -04:00
// * `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-04-06 10:35:40 -04:00
} ) ;
2019-07-31 07:54:12 -04:00
it ( 'should report an error if a dependency of the target does not exist' , ( ) = > {
expect ( ( ) = > {
mainNgcc ( { basePath : '/node_modules' , targetEntryPointPath : 'invalid-package' } ) ;
} )
. toThrowError (
'The target entry-point "invalid-package" has missing dependencies:\n - @angular/missing\n' ) ;
} ) ;
2019-04-06 10:35:40 -04:00
} ) ;
2019-06-06 15:22:32 -04:00
describe ( 'early skipping of target entry-point' , ( ) = > {
describe ( '[compileAllFormats === true]' , ( ) = > {
it ( 'should skip all processing if all the properties are marked as processed' , ( ) = > {
const logger = new MockLogger ( ) ;
markPropertiesAsProcessed ( '@angular/common/http/testing' , SUPPORTED_FORMAT_PROPERTIES ) ;
mainNgcc ( {
basePath : '/node_modules' ,
targetEntryPointPath : '@angular/common/http/testing' , logger ,
} ) ;
expect ( logger . logs . debug ) . toContain ( [
'The target entry-point has already been processed'
] ) ;
} ) ;
2019-04-06 10:35:40 -04:00
2019-06-06 15:22:32 -04:00
it ( 'should process the target if any `propertyToConsider` is not marked as processed' ,
( ) = > {
const logger = new MockLogger ( ) ;
markPropertiesAsProcessed ( '@angular/common/http/testing' , [ 'esm2015' , 'fesm2015' ] ) ;
mainNgcc ( {
basePath : '/node_modules' ,
targetEntryPointPath : '@angular/common/http/testing' ,
propertiesToConsider : [ 'fesm2015' , 'esm5' , 'esm2015' ] , logger ,
} ) ;
expect ( logger . logs . debug ) . not . toContain ( [
'The target entry-point has already been processed'
] ) ;
} ) ;
} ) ;
2019-04-06 10:35:40 -04:00
2019-06-06 15:22:32 -04:00
describe ( '[compileAllFormats === false]' , ( ) = > {
it ( 'should process the target if the first matching `propertyToConsider` is not marked as processed' ,
( ) = > {
const logger = new MockLogger ( ) ;
markPropertiesAsProcessed ( '@angular/common/http/testing' , [ 'esm2015' ] ) ;
mainNgcc ( {
basePath : '/node_modules' ,
targetEntryPointPath : '@angular/common/http/testing' ,
propertiesToConsider : [ 'esm5' , 'esm2015' ] ,
compileAllFormats : false , logger ,
} ) ;
expect ( logger . logs . debug ) . not . toContain ( [
'The target entry-point has already been processed'
] ) ;
2019-04-06 10:35:40 -04:00
} ) ;
2019-06-06 15:22:32 -04:00
it ( 'should skip all processing if the first matching `propertyToConsider` is marked as processed' ,
( ) = > {
const logger = new MockLogger ( ) ;
markPropertiesAsProcessed ( '@angular/common/http/testing' , [ 'esm2015' ] ) ;
mainNgcc ( {
basePath : '/node_modules' ,
targetEntryPointPath : '@angular/common/http/testing' ,
// Simulate a property that does not exist on the package.json and will be ignored.
propertiesToConsider : [ 'missing' , 'esm2015' , 'esm5' ] ,
compileAllFormats : false , logger ,
} ) ;
expect ( logger . logs . debug ) . toContain ( [
'The target entry-point has already been processed'
] ) ;
} ) ;
} ) ;
2019-08-05 06:36:51 -04:00
it ( 'should skip all processing if the first matching `propertyToConsider` is marked as processed' ,
( ) = > {
const logger = new MockLogger ( ) ;
markPropertiesAsProcessed ( '@angular/common/http/testing' , [ 'esm2015' ] ) ;
mainNgcc ( {
basePath : '/node_modules' ,
targetEntryPointPath : '@angular/common/http/testing' ,
// Simulate a property that does not exist on the package.json and will be ignored.
propertiesToConsider : [ 'missing' , 'esm2015' , 'esm5' ] ,
compileAllFormats : false , logger ,
} ) ;
expect ( logger . logs . debug ) . toContain ( [
'The target entry-point has already been processed'
] ) ;
} ) ;
2019-04-06 10:35:40 -04:00
} ) ;
2019-06-06 15:22:32 -04:00
function markPropertiesAsProcessed ( packagePath : string , properties : EntryPointJsonProperty [ ] ) {
const basePath = _ ( '/node_modules' ) ;
const targetPackageJsonPath = join ( basePath , packagePath , 'package.json' ) ;
const targetPackage = loadPackage ( packagePath ) ;
2019-08-04 10:51:37 -04:00
markAsProcessed ( fs , targetPackage , targetPackageJsonPath , [ 'typings' , . . . properties ] ) ;
2019-06-06 15:22:32 -04:00
}
2019-04-06 10:35:40 -04:00
2019-06-06 15:22:32 -04:00
describe ( 'with propertiesToConsider' , ( ) = > {
2019-08-05 17:53:38 -04:00
it ( 'should complain if none of the properties in the `propertiesToConsider` list is supported' ,
( ) = > {
const propertiesToConsider = [ 'es1337' , 'fesm42' ] ;
const errorMessage =
'No supported format property to consider among [es1337, fesm42]. Supported ' +
'properties: fesm2015, fesm5, es2015, esm2015, esm5, main, module' ;
expect ( ( ) = > mainNgcc ( { basePath : '/node_modules' , propertiesToConsider } ) )
. toThrowError ( errorMessage ) ;
} ) ;
2019-06-06 15:22:32 -04:00
it ( 'should only compile the entry-point formats given in the `propertiesToConsider` list' ,
( ) = > {
mainNgcc ( {
basePath : '/node_modules' ,
propertiesToConsider : [ 'main' , 'esm5' , 'module' , 'fesm5' ] ,
logger : new MockLogger ( ) ,
2019-04-06 10:35:13 -04:00
2019-06-06 15:22:32 -04:00
} ) ;
2019-03-20 09:47:58 -04:00
2019-06-06 15:22:32 -04:00
// The ES2015 formats are not compiled as they are not in `propertiesToConsider`.
expect ( loadPackage ( '@angular/core' ) . __processed_by_ivy_ngcc__ ) . toEqual ( {
esm5 : '0.0.0-PLACEHOLDER' ,
main : '0.0.0-PLACEHOLDER' ,
module : '0.0.0-PLACEHOLDER' ,
fesm5 : '0.0.0-PLACEHOLDER' ,
typings : '0.0.0-PLACEHOLDER' ,
} ) ;
expect ( loadPackage ( '@angular/common' ) . __processed_by_ivy_ngcc__ ) . toEqual ( {
esm5 : '0.0.0-PLACEHOLDER' ,
main : '0.0.0-PLACEHOLDER' ,
module : '0.0.0-PLACEHOLDER' ,
fesm5 : '0.0.0-PLACEHOLDER' ,
typings : '0.0.0-PLACEHOLDER' ,
} ) ;
expect ( loadPackage ( '@angular/common/testing' ) . __processed_by_ivy_ngcc__ ) . toEqual ( {
esm5 : '0.0.0-PLACEHOLDER' ,
main : '0.0.0-PLACEHOLDER' ,
module : '0.0.0-PLACEHOLDER' ,
fesm5 : '0.0.0-PLACEHOLDER' ,
typings : '0.0.0-PLACEHOLDER' ,
} ) ;
expect ( loadPackage ( '@angular/common/http' ) . __processed_by_ivy_ngcc__ ) . toEqual ( {
esm5 : '0.0.0-PLACEHOLDER' ,
main : '0.0.0-PLACEHOLDER' ,
module : '0.0.0-PLACEHOLDER' ,
fesm5 : '0.0.0-PLACEHOLDER' ,
typings : '0.0.0-PLACEHOLDER' ,
} ) ;
2019-03-20 09:47:58 -04:00
} ) ;
2019-08-05 06:36:51 -04:00
it ( 'should mark all matching properties as processed in order not to compile them on a subsequent run' ,
( ) = > {
const logger = new MockLogger ( ) ;
const logs = logger . logs . debug ;
// `fesm2015` and `es2015` map to the same file: `./fesm2015/common.js`
mainNgcc ( {
basePath : '/node_modules/@angular/common' ,
propertiesToConsider : [ 'fesm2015' ] , logger ,
} ) ;
expect ( logs ) . not . toContain ( [ 'Skipping @angular/common : es2015 (already compiled).' ] ) ;
expect ( loadPackage ( '@angular/common' ) . __processed_by_ivy_ngcc__ ) . toEqual ( {
es2015 : '0.0.0-PLACEHOLDER' ,
fesm2015 : '0.0.0-PLACEHOLDER' ,
typings : '0.0.0-PLACEHOLDER' ,
} ) ;
// Now, compiling `es2015` should be a no-op.
mainNgcc ( {
basePath : '/node_modules/@angular/common' ,
propertiesToConsider : [ 'es2015' ] , logger ,
} ) ;
expect ( logs ) . toContain ( [ 'Skipping @angular/common : es2015 (already compiled).' ] ) ;
} ) ;
2019-06-06 15:22:32 -04:00
} ) ;
2019-03-20 09:47:58 -04:00
2019-06-06 15:22:32 -04:00
describe ( 'with compileAllFormats set to false' , ( ) = > {
it ( 'should only compile the first matching format' , ( ) = > {
mainNgcc ( {
basePath : '/node_modules' ,
propertiesToConsider : [ 'module' , 'fesm5' , 'esm5' ] ,
compileAllFormats : false ,
logger : new MockLogger ( ) ,
2019-04-06 10:35:13 -04:00
2019-06-06 15:22:32 -04:00
} ) ;
// * 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.
expect ( loadPackage ( '@angular/core' ) . __processed_by_ivy_ngcc__ ) . toEqual ( {
fesm5 : '0.0.0-PLACEHOLDER' ,
module : '0.0.0-PLACEHOLDER' ,
typings : '0.0.0-PLACEHOLDER' ,
} ) ;
expect ( loadPackage ( '@angular/common' ) . __processed_by_ivy_ngcc__ ) . toEqual ( {
fesm5 : '0.0.0-PLACEHOLDER' ,
module : '0.0.0-PLACEHOLDER' ,
typings : '0.0.0-PLACEHOLDER' ,
} ) ;
expect ( loadPackage ( '@angular/common/testing' ) . __processed_by_ivy_ngcc__ ) . toEqual ( {
fesm5 : '0.0.0-PLACEHOLDER' ,
module : '0.0.0-PLACEHOLDER' ,
typings : '0.0.0-PLACEHOLDER' ,
} ) ;
expect ( loadPackage ( '@angular/common/http' ) . __processed_by_ivy_ngcc__ ) . toEqual ( {
fesm5 : '0.0.0-PLACEHOLDER' ,
module : '0.0.0-PLACEHOLDER' ,
typings : '0.0.0-PLACEHOLDER' ,
} ) ;
2019-03-20 09:47:58 -04:00
} ) ;
2019-04-02 06:51:39 -04:00
2019-06-06 15:22:32 -04:00
it ( 'should cope with compiling the same entry-point multiple times with different formats' ,
( ) = > {
mainNgcc ( {
basePath : '/node_modules' ,
propertiesToConsider : [ 'module' ] ,
compileAllFormats : false ,
logger : new MockLogger ( ) ,
2019-04-06 10:35:13 -04:00
2019-06-06 15:22:32 -04:00
} ) ;
expect ( loadPackage ( '@angular/core' ) . __processed_by_ivy_ngcc__ ) . toEqual ( {
2019-08-05 06:36:51 -04:00
fesm5 : '0.0.0-PLACEHOLDER' ,
2019-06-06 15:22:32 -04:00
module : '0.0.0-PLACEHOLDER' ,
typings : '0.0.0-PLACEHOLDER' ,
} ) ;
// If ngcc tries to write out the typings files again, this will throw an exception.
mainNgcc ( {
basePath : '/node_modules' ,
propertiesToConsider : [ 'esm5' ] ,
compileAllFormats : false ,
logger : new MockLogger ( ) ,
} ) ;
expect ( loadPackage ( '@angular/core' ) . __processed_by_ivy_ngcc__ ) . toEqual ( {
esm5 : '0.0.0-PLACEHOLDER' ,
2019-08-05 06:36:51 -04:00
fesm5 : '0.0.0-PLACEHOLDER' ,
2019-06-06 15:22:32 -04:00
module : '0.0.0-PLACEHOLDER' ,
typings : '0.0.0-PLACEHOLDER' ,
} ) ;
2019-04-02 06:51:39 -04:00
} ) ;
2019-06-06 15:22:32 -04:00
} ) ;
2019-03-20 09:47:59 -04:00
2019-06-06 15:22:32 -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' ] ,
logger : new MockLogger ( ) ,
2019-04-06 10:35:13 -04:00
2019-06-06 15:22:32 -04:00
} ) ;
2019-03-20 09:47:59 -04:00
2019-06-06 15:22:32 -04:00
// 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 ( fs . readFile ( _ ( ` /node_modules/@angular/common/esm5/src/common_module.js ` ) ) )
. not . toMatch ( ANGULAR_CORE_IMPORT_REGEX ) ;
// Or create a backup of the original
expect (
fs . exists ( _ ( ` /node_modules/@angular/common/esm5/src/common_module.js.__ivy_ngcc_bak ` ) ) )
. toBe ( false ) ;
// Creates new files
expect (
fs . readFile ( _ ( ` /node_modules/@angular/common/__ivy_ngcc__/esm5/src/common_module.js ` ) ) )
. toMatch ( ANGULAR_CORE_IMPORT_REGEX ) ;
// Copies over files (unchanged) that did not need compiling
expect ( fs . exists ( _ ( ` /node_modules/@angular/common/__ivy_ngcc__/esm5/src/version.js ` ) ) ) ;
expect ( fs . readFile ( _ ( ` /node_modules/@angular/common/__ivy_ngcc__/esm5/src/version.js ` ) ) )
. toEqual ( fs . readFile ( _ ( ` /node_modules/@angular/common/esm5/src/version.js ` ) ) ) ;
// Overwrites .d.ts files (as usual)
expect ( fs . readFile ( _ ( ` /node_modules/@angular/common/common.d.ts ` ) ) )
. toMatch ( ANGULAR_CORE_IMPORT_REGEX ) ;
expect ( fs . exists ( _ ( ` /node_modules/@angular/common/common.d.ts.__ivy_ngcc_bak ` ) ) ) . toBe ( true ) ;
} ) ;
2019-08-07 20:23:46 -04:00
it ( 'should update `package.json` for all matching format properties' , ( ) = > {
mainNgcc ( {
basePath : '/node_modules/@angular/core' ,
createNewEntryPointFormats : true ,
propertiesToConsider : [ 'fesm2015' , 'fesm5' ] ,
} ) ;
const pkg : any = loadPackage ( '@angular/core' ) ;
// `es2015` is an alias of `fesm2015`.
expect ( pkg . fesm2015 ) . toEqual ( './fesm2015/core.js' ) ;
expect ( pkg . es2015 ) . toEqual ( './fesm2015/core.js' ) ;
expect ( pkg . fesm2015_ivy_ngcc ) . toEqual ( '__ivy_ngcc__/fesm2015/core.js' ) ;
expect ( pkg . es2015_ivy_ngcc ) . toEqual ( '__ivy_ngcc__/fesm2015/core.js' ) ;
// `module` is an alias of `fesm5`.
expect ( pkg . fesm5 ) . toEqual ( './fesm5/core.js' ) ;
expect ( pkg . module ) . toEqual ( './fesm5/core.js' ) ;
expect ( pkg . fesm5_ivy_ngcc ) . toEqual ( '__ivy_ngcc__/fesm5/core.js' ) ;
expect ( pkg . module _ivy_ngcc ) . toEqual ( '__ivy_ngcc__/fesm5/core.js' ) ;
} ) ;
2019-03-20 09:47:59 -04:00
} ) ;
2019-03-29 06:13:14 -04:00
2019-08-04 13:20:38 -04:00
describe ( 'diagnostics' , ( ) = > {
it ( 'should fail with formatted diagnostics when an error diagnostic is produced' , ( ) = > {
loadTestFiles ( [
{
name : _ ( '/node_modules/fatal-error/package.json' ) ,
contents : '{"name": "fatal-error", "es2015": "./index.js", "typings": "./index.d.ts"}' ,
} ,
{ name : _ ( '/node_modules/fatal-error/index.metadata.json' ) , contents : 'DUMMY DATA' } ,
{
name : _ ( '/node_modules/fatal-error/index.js' ) ,
contents : `
import { Component } from '@angular/core' ;
export class FatalError { }
FatalError . decorators = [
{ type : Component , args : [ { selector : 'fatal-error' } ] }
] ;
` ,
} ,
{
name : _ ( '/node_modules/fatal-error/index.d.ts' ) ,
contents : `
export declare class FatalError { }
` ,
} ,
] ) ;
expect ( ( ) = > mainNgcc ( {
basePath : '/node_modules' ,
targetEntryPointPath : 'fatal-error' ,
propertiesToConsider : [ 'es2015' ]
} ) )
. toThrowError (
/^Failed to compile entry-point fatal-error due to compilation errors:\nnode_modules\/fatal-error\/index\.js\(5,17\): error TS-992001: component is missing a template\r?\n$/ ) ;
} ) ;
} ) ;
2019-06-06 15:22:32 -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' ) ;
} ) ;
2019-03-29 06:13:14 -04:00
2019-06-06 15:22:32 -04:00
it ( 'should use a custom logger if provided' , ( ) = > {
const logger = new MockLogger ( ) ;
mainNgcc ( {
basePath : '/node_modules' ,
propertiesToConsider : [ 'esm2015' ] , logger ,
} ) ;
expect ( logger . logs . info ) . toContain ( [ 'Compiling @angular/common/http : esm2015 as esm2015' ] ) ;
2019-04-06 10:35:13 -04:00
} ) ;
2019-03-29 06:13:14 -04:00
} ) ;
2019-04-28 15:47:57 -04:00
2019-06-06 15:22:32 -04:00
describe ( 'with pathMappings' , ( ) = > {
it ( 'should find and compile packages accessible via the pathMappings' , ( ) = > {
mainNgcc ( {
basePath : '/node_modules' ,
propertiesToConsider : [ 'es2015' ] ,
pathMappings : { paths : { '*' : [ 'dist/*' ] } , baseUrl : '/' } ,
} ) ;
expect ( loadPackage ( '@angular/core' ) . __processed_by_ivy_ngcc__ ) . toEqual ( {
es2015 : '0.0.0-PLACEHOLDER' ,
2019-08-05 06:36:51 -04:00
fesm2015 : '0.0.0-PLACEHOLDER' ,
2019-06-06 15:22:32 -04:00
typings : '0.0.0-PLACEHOLDER' ,
} ) ;
expect ( loadPackage ( 'local-package' , _ ( '/dist' ) ) . __processed_by_ivy_ngcc__ ) . toEqual ( {
2019-05-21 10:23:24 -04:00
es2015 : '0.0.0-PLACEHOLDER' ,
typings : '0.0.0-PLACEHOLDER' ,
} ) ;
} ) ;
} ) ;
describe ( 'with configuration files' , ( ) = > {
it ( 'should process a configured deep-import as an entry-point' , ( ) = > {
loadTestFiles ( [
{
name : _ ( '/ngcc.config.js' ) ,
contents : ` module.exports = { packages: {
'deep_import' : {
entryPoints : {
'./entry_point' : { override : { typings : '../entry_point.d.ts' , es2015 : '../entry_point.js' } }
}
}
} } ; ` ,
} ,
{
name : _ ( '/node_modules/deep_import/package.json' ) ,
contents : '{"name": "deep-import", "es2015": "./index.js", "typings": "./index.d.ts"}' ,
} ,
{
name : _ ( '/node_modules/deep_import/entry_point.js' ) ,
contents : `
import { Component } from '@angular/core' ;
@Component ( { selector : 'entry-point' } )
export class EntryPoint { }
` ,
} ,
{
name : _ ( '/node_modules/deep_import/entry_point.d.ts' ) ,
contents : `
import { Component } from '@angular/core' ;
@Component ( { selector : 'entry-point' } )
export class EntryPoint { }
` ,
} ,
] ) ;
mainNgcc ( {
basePath : '/node_modules' ,
targetEntryPointPath : 'deep_import/entry_point' ,
propertiesToConsider : [ 'es2015' ]
} ) ;
// The containing package is not processed
expect ( loadPackage ( 'deep_import' ) . __processed_by_ivy_ngcc__ ) . toBeUndefined ( ) ;
// But the configured entry-point and its dependency (@angular/core) are processed.
expect ( loadPackage ( 'deep_import/entry_point' ) . __processed_by_ivy_ngcc__ ) . toEqual ( {
es2015 : '0.0.0-PLACEHOLDER' ,
typings : '0.0.0-PLACEHOLDER' ,
} ) ;
expect ( loadPackage ( '@angular/core' ) . __processed_by_ivy_ngcc__ ) . toEqual ( {
es2015 : '0.0.0-PLACEHOLDER' ,
2019-08-05 06:36:51 -04:00
fesm2015 : '0.0.0-PLACEHOLDER' ,
2019-05-21 10:23:24 -04:00
typings : '0.0.0-PLACEHOLDER' ,
} ) ;
} ) ;
it ( 'should not process ignored entry-points' , ( ) = > {
loadTestFiles ( [
{
name : _ ( '/ngcc.config.js' ) ,
contents : ` module.exports = { packages: {
'@angular/core' : {
entryPoints : {
'./testing' : { ignore : true }
} ,
} ,
'@angular/common' : {
entryPoints : {
'.' : { ignore : true }
} ,
}
} } ; ` ,
} ,
] ) ;
mainNgcc ( { basePath : '/node_modules' , propertiesToConsider : [ 'es2015' ] } ) ;
// We process core but not core/testing.
expect ( loadPackage ( '@angular/core' ) . __processed_by_ivy_ngcc__ ) . toEqual ( {
es2015 : '0.0.0-PLACEHOLDER' ,
2019-08-05 06:36:51 -04:00
fesm2015 : '0.0.0-PLACEHOLDER' ,
2019-05-21 10:23:24 -04:00
typings : '0.0.0-PLACEHOLDER' ,
} ) ;
expect ( loadPackage ( '@angular/core/testing' ) . __processed_by_ivy_ngcc__ ) . toBeUndefined ( ) ;
// We do not compile common but we do compile its sub-entry-points.
expect ( loadPackage ( '@angular/common' ) . __processed_by_ivy_ngcc__ ) . toBeUndefined ( ) ;
expect ( loadPackage ( ' @angular / common / http ' ) . __processed_by_ivy_ngcc__ ) . toEqual ( {
2019-06-06 15:22:32 -04:00
es2015 : '0.0.0-PLACEHOLDER' ,
2019-08-05 06:36:51 -04:00
fesm2015 : '0.0.0-PLACEHOLDER' ,
2019-06-06 15:22:32 -04:00
typings : '0.0.0-PLACEHOLDER' ,
} ) ;
2019-04-28 15:47:57 -04:00
} ) ;
fix(ngcc): ignore format properties that exist but are undefined (#32205)
Previously, `ngcc` assumed that if a format property was defined in
`package.json` it would point to a valid format-path (i.e. a file that
is an entry-point for a specific format). This is generally the case,
except if a format property is set to a non-string value (such as
`package.json`) - either directly in the `package.json` (which is unusual)
or in ngcc.config.js (which is a valid usecase, when one wants a
format property to be ignored by `ngcc`).
For example, the following config file would cause `ngcc` to throw:
```
module.exports = {
packages: {
'test-package': {
entryPoints: {
'.': {
override: {
fesm2015: undefined,
},
},
},
},
},
};
```
This commit fixes it by ensuring that only format properties whose value
is a string are considered by `ngcc`.
For reference, this regression was introduced in #32052.
Fixes #32188
PR Close #32205
2019-08-20 03:43:08 -04:00
it ( 'should support removing a format property by setting it to `undefined`' , ( ) = > {
loadTestFiles ( [
{
name : _ ( '/ngcc.config.js' ) ,
contents : `
module .exports = {
packages : {
'test-package' : {
entryPoints : {
'.' : {
override : {
fesm2015 : undefined ,
} ,
} ,
} ,
} ,
} ,
} ;
` ,
} ,
{
name : _ ( '/node_modules/test-package/package.json' ) ,
contents : `
{
"name" : "test-package" ,
"fesm2015" : "./index.es2015.js" ,
"fesm5" : "./index.es5.js" ,
"typings" : "./index.d.ts"
}
` ,
} ,
{
name : _ ( '/node_modules/test-package/index.es5.js' ) ,
contents : `
var TestService = ( function ( ) {
function TestService() {
}
return TestService ;
} ( ) ) ;
` ,
} ,
{
name : _ ( '/node_modules/test-package/index.d.js' ) ,
contents : `
export declare class TestService { }
` ,
} ,
] ) ;
mainNgcc ( {
basePath : '/node_modules' ,
targetEntryPointPath : 'test-package' ,
propertiesToConsider : [ 'fesm2015' , 'fesm5' ] ,
} ) ;
expect ( loadPackage ( 'test-package' ) . __processed_by_ivy_ngcc__ ) . toEqual ( {
fesm5 : '0.0.0-PLACEHOLDER' ,
typings : '0.0.0-PLACEHOLDER' ,
} ) ;
} ) ;
2019-04-28 15:47:57 -04:00
} ) ;
2019-01-25 13:48:27 -05:00
2019-06-06 15:22:32 -04:00
function loadPackage (
packageName : string , basePath : AbsoluteFsPath = _ ( '/node_modules' ) ) : EntryPointPackageJson {
return JSON . parse ( fs . readFile ( fs . resolve ( basePath , packageName , 'package.json' ) ) ) ;
}
2018-08-28 06:32:01 -04:00
2019-06-06 15:22:32 -04:00
function initMockFileSystem ( fs : FileSystem , testFiles : Folder ) {
if ( fs instanceof MockFileSystem ) {
fs . init ( testFiles ) ;
}
// a random test package that no metadata.json file so not compiled by Angular.
loadTestFiles ( [
{
name : _ ( '/node_modules/test-package/package.json' ) ,
contents : '{"name": "test-package", "es2015": "./index.js", "typings": "./index.d.ts"}'
} ,
{
name : _ ( '/node_modules/test-package/index.js' ) ,
contents :
'import {AppModule} from "@angular/common"; export class MyApp extends AppModule {};'
} ,
{
name : _ ( '/node_modules/test-package/index.d.ts' ) ,
contents :
'import {AppModule} from "@angular/common"; export declare class MyApp extends AppModule;'
} ,
] ) ;
// An Angular package that has been built locally and stored in the `dist` directory.
loadTestFiles ( [
{
name : _ ( '/dist/local-package/package.json' ) ,
contents : '{"name": "local-package", "es2015": "./index.js", "typings": "./index.d.ts"}'
} ,
{ name : _ ( '/dist/local-package/index.metadata.json' ) , contents : 'DUMMY DATA' } ,
{
name : _ ( '/dist/local-package/index.js' ) ,
contents :
` import {Component} from '@angular/core'; \ nexport class AppComponent {}; \ nAppComponent.decorators = [ \ n{ type: Component, args: [{selector: 'app', template: '<h2>Hello</h2>'}] } \ n]; `
} ,
{
name : _ ( '/dist/local-package/index.d.ts' ) ,
contents : ` export declare class AppComponent {}; `
} ,
] ) ;
2019-07-31 07:54:12 -04:00
// An Angular package that has a missing dependency
loadTestFiles ( [
{
name : _ ( '/node_modules/invalid-package/package.json' ) ,
contents : '{"name": "invalid-package", "es2015": "./index.js", "typings": "./index.d.ts"}'
} ,
{
name : _ ( '/node_modules/invalid-package/index.js' ) ,
contents : `
import { AppModule } from "@angular/missing" ;
import { Component } from '@angular/core' ;
export class AppComponent { } ;
AppComponent . decorators = [
{ type : Component , args : [ { selector : 'app' , template : '<h2>Hello</h2>' } ] }
] ;
`
} ,
{
name : _ ( '/node_modules/invalid-package/index.d.ts' ) ,
contents : ` export declare class AppComponent {} `
} ,
{ name : _ ( '/node_modules/invalid-package/index.metadata.json' ) , contents : 'DUMMY DATA' } ,
] ) ;
2018-08-28 06:32:01 -04:00
}
} ) ;
2019-06-06 15:22:32 -04:00
} ) ;