angular-cn/packages/compiler-cli/ngcc/test/integration/ngcc_spec.ts

2076 lines
81 KiB
TypeScript
Raw Normal View History

/**
* @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
*/
/// <reference types="node" />
import * as os from 'os';
import {absoluteFrom, AbsoluteFsPath, FileSystem, getFileSystem, join} from '../../../src/ngtsc/file_system';
import {Folder, MockFileSystem, runInEachFileSystem, TestFile} from '../../../src/ngtsc/file_system/testing';
refactor(ivy): implement a virtual file-system layer in ngtsc + ngcc (#30921) To improve cross platform support, all file access (and path manipulation) is now done through a well known interface (`FileSystem`). For testing a number of `MockFileSystem` implementations are provided. These provide an in-memory file-system which emulates operating systems like OS/X, Unix and Windows. The current file system is always available via the static method, `FileSystem.getFileSystem()`. This is also used by a number of static methods on `AbsoluteFsPath` and `PathSegment`, to avoid having to pass `FileSystem` objects around all the time. The result of this is that one must be careful to ensure that the file-system has been initialized before using any of these static methods. To prevent this happening accidentally the current file system always starts out as an instance of `InvalidFileSystem`, which will throw an error if any of its methods are called. You can set the current file-system by calling `FileSystem.setFileSystem()`. During testing you can call the helper function `initMockFileSystem(os)` which takes a string name of the OS to emulate, and will also monkey-patch aspects of the TypeScript library to ensure that TS is also using the current file-system. Finally there is the `NgtscCompilerHost` to be used for any TypeScript compilation, which uses a given file-system. All tests that interact with the file-system should be tested against each of the mock file-systems. A series of helpers have been provided to support such tests: * `runInEachFileSystem()` - wrap your tests in this helper to run all the wrapped tests in each of the mock file-systems. * `addTestFilesToFileSystem()` - use this to add files and their contents to the mock file system for testing. * `loadTestFilesFromDisk()` - use this to load a mirror image of files on disk into the in-memory mock file-system. * `loadFakeCore()` - use this to load a fake version of `@angular/core` into the mock file-system. All ngcc and ngtsc source and tests now use this virtual file-system setup. PR Close #30921
2019-06-06 15:22:32 -04:00
import {loadStandardTestFiles, loadTestFiles} from '../../../test/helpers';
import {getLockFilePath} from '../../src/locking/lock_file';
import {mainNgcc} from '../../src/main';
import {hasBeenProcessed, markAsProcessed} from '../../src/packages/build_marker';
import {EntryPointJsonProperty, EntryPointPackageJson, SUPPORTED_FORMAT_PROPERTIES} from '../../src/packages/entry_point';
import {EntryPointManifestFile} from '../../src/packages/entry_point_manifest';
import {Transformer} from '../../src/packages/transformer';
import {DirectPackageJsonUpdater, PackageJsonUpdater} from '../../src/writing/package_json_updater';
import {MockLogger} from '../helpers/mock_logger';
import {compileIntoApf, compileIntoFlatEs5Package} from './util';
refactor(ivy): implement a virtual file-system layer in ngtsc + ngcc (#30921) To improve cross platform support, all file access (and path manipulation) is now done through a well known interface (`FileSystem`). For testing a number of `MockFileSystem` implementations are provided. These provide an in-memory file-system which emulates operating systems like OS/X, Unix and Windows. The current file system is always available via the static method, `FileSystem.getFileSystem()`. This is also used by a number of static methods on `AbsoluteFsPath` and `PathSegment`, to avoid having to pass `FileSystem` objects around all the time. The result of this is that one must be careful to ensure that the file-system has been initialized before using any of these static methods. To prevent this happening accidentally the current file system always starts out as an instance of `InvalidFileSystem`, which will throw an error if any of its methods are called. You can set the current file-system by calling `FileSystem.setFileSystem()`. During testing you can call the helper function `initMockFileSystem(os)` which takes a string name of the OS to emulate, and will also monkey-patch aspects of the TypeScript library to ensure that TS is also using the current file-system. Finally there is the `NgtscCompilerHost` to be used for any TypeScript compilation, which uses a given file-system. All tests that interact with the file-system should be tested against each of the mock file-systems. A series of helpers have been provided to support such tests: * `runInEachFileSystem()` - wrap your tests in this helper to run all the wrapped tests in each of the mock file-systems. * `addTestFilesToFileSystem()` - use this to add files and their contents to the mock file system for testing. * `loadTestFilesFromDisk()` - use this to load a mirror image of files on disk into the in-memory mock file-system. * `loadFakeCore()` - use this to load a fake version of `@angular/core` into the mock file-system. All ngcc and ngtsc source and tests now use this virtual file-system setup. PR Close #30921
2019-06-06 15:22:32 -04:00
const testFiles = loadStandardTestFiles({fakeCore: false, rxjs: true});
refactor(ivy): implement a virtual file-system layer in ngtsc + ngcc (#30921) To improve cross platform support, all file access (and path manipulation) is now done through a well known interface (`FileSystem`). For testing a number of `MockFileSystem` implementations are provided. These provide an in-memory file-system which emulates operating systems like OS/X, Unix and Windows. The current file system is always available via the static method, `FileSystem.getFileSystem()`. This is also used by a number of static methods on `AbsoluteFsPath` and `PathSegment`, to avoid having to pass `FileSystem` objects around all the time. The result of this is that one must be careful to ensure that the file-system has been initialized before using any of these static methods. To prevent this happening accidentally the current file system always starts out as an instance of `InvalidFileSystem`, which will throw an error if any of its methods are called. You can set the current file-system by calling `FileSystem.setFileSystem()`. During testing you can call the helper function `initMockFileSystem(os)` which takes a string name of the OS to emulate, and will also monkey-patch aspects of the TypeScript library to ensure that TS is also using the current file-system. Finally there is the `NgtscCompilerHost` to be used for any TypeScript compilation, which uses a given file-system. All tests that interact with the file-system should be tested against each of the mock file-systems. A series of helpers have been provided to support such tests: * `runInEachFileSystem()` - wrap your tests in this helper to run all the wrapped tests in each of the mock file-systems. * `addTestFilesToFileSystem()` - use this to add files and their contents to the mock file system for testing. * `loadTestFilesFromDisk()` - use this to load a mirror image of files on disk into the in-memory mock file-system. * `loadFakeCore()` - use this to load a fake version of `@angular/core` into the mock file-system. All ngcc and ngtsc source and tests now use this virtual file-system setup. PR Close #30921
2019-06-06 15:22:32 -04:00
runInEachFileSystem(() => {
describe('ngcc main()', () => {
let _: typeof absoluteFrom;
let fs: FileSystem;
let pkgJsonUpdater: PackageJsonUpdater;
refactor(ivy): implement a virtual file-system layer in ngtsc + ngcc (#30921) To improve cross platform support, all file access (and path manipulation) is now done through a well known interface (`FileSystem`). For testing a number of `MockFileSystem` implementations are provided. These provide an in-memory file-system which emulates operating systems like OS/X, Unix and Windows. The current file system is always available via the static method, `FileSystem.getFileSystem()`. This is also used by a number of static methods on `AbsoluteFsPath` and `PathSegment`, to avoid having to pass `FileSystem` objects around all the time. The result of this is that one must be careful to ensure that the file-system has been initialized before using any of these static methods. To prevent this happening accidentally the current file system always starts out as an instance of `InvalidFileSystem`, which will throw an error if any of its methods are called. You can set the current file-system by calling `FileSystem.setFileSystem()`. During testing you can call the helper function `initMockFileSystem(os)` which takes a string name of the OS to emulate, and will also monkey-patch aspects of the TypeScript library to ensure that TS is also using the current file-system. Finally there is the `NgtscCompilerHost` to be used for any TypeScript compilation, which uses a given file-system. All tests that interact with the file-system should be tested against each of the mock file-systems. A series of helpers have been provided to support such tests: * `runInEachFileSystem()` - wrap your tests in this helper to run all the wrapped tests in each of the mock file-systems. * `addTestFilesToFileSystem()` - use this to add files and their contents to the mock file system for testing. * `loadTestFilesFromDisk()` - use this to load a mirror image of files on disk into the in-memory mock file-system. * `loadFakeCore()` - use this to load a fake version of `@angular/core` into the mock file-system. All ngcc and ngtsc source and tests now use this virtual file-system setup. PR Close #30921
2019-06-06 15:22:32 -04:00
beforeEach(() => {
_ = absoluteFrom;
fs = getFileSystem();
pkgJsonUpdater = new DirectPackageJsonUpdater(fs);
refactor(ivy): implement a virtual file-system layer in ngtsc + ngcc (#30921) To improve cross platform support, all file access (and path manipulation) is now done through a well known interface (`FileSystem`). For testing a number of `MockFileSystem` implementations are provided. These provide an in-memory file-system which emulates operating systems like OS/X, Unix and Windows. The current file system is always available via the static method, `FileSystem.getFileSystem()`. This is also used by a number of static methods on `AbsoluteFsPath` and `PathSegment`, to avoid having to pass `FileSystem` objects around all the time. The result of this is that one must be careful to ensure that the file-system has been initialized before using any of these static methods. To prevent this happening accidentally the current file system always starts out as an instance of `InvalidFileSystem`, which will throw an error if any of its methods are called. You can set the current file-system by calling `FileSystem.setFileSystem()`. During testing you can call the helper function `initMockFileSystem(os)` which takes a string name of the OS to emulate, and will also monkey-patch aspects of the TypeScript library to ensure that TS is also using the current file-system. Finally there is the `NgtscCompilerHost` to be used for any TypeScript compilation, which uses a given file-system. All tests that interact with the file-system should be tested against each of the mock file-systems. A series of helpers have been provided to support such tests: * `runInEachFileSystem()` - wrap your tests in this helper to run all the wrapped tests in each of the mock file-systems. * `addTestFilesToFileSystem()` - use this to add files and their contents to the mock file system for testing. * `loadTestFilesFromDisk()` - use this to load a mirror image of files on disk into the in-memory mock file-system. * `loadFakeCore()` - use this to load a fake version of `@angular/core` into the mock file-system. All ngcc and ngtsc source and tests now use this virtual file-system setup. PR Close #30921
2019-06-06 15:22:32 -04:00
initMockFileSystem(fs, testFiles);
// Force single-process execution in unit tests by mocking available CPUs to 1.
spyOn(os, 'cpus').and.returnValue([{model: 'Mock CPU'} as any]);
});
refactor(ivy): implement a virtual file-system layer in ngtsc + ngcc (#30921) To improve cross platform support, all file access (and path manipulation) is now done through a well known interface (`FileSystem`). For testing a number of `MockFileSystem` implementations are provided. These provide an in-memory file-system which emulates operating systems like OS/X, Unix and Windows. The current file system is always available via the static method, `FileSystem.getFileSystem()`. This is also used by a number of static methods on `AbsoluteFsPath` and `PathSegment`, to avoid having to pass `FileSystem` objects around all the time. The result of this is that one must be careful to ensure that the file-system has been initialized before using any of these static methods. To prevent this happening accidentally the current file system always starts out as an instance of `InvalidFileSystem`, which will throw an error if any of its methods are called. You can set the current file-system by calling `FileSystem.setFileSystem()`. During testing you can call the helper function `initMockFileSystem(os)` which takes a string name of the OS to emulate, and will also monkey-patch aspects of the TypeScript library to ensure that TS is also using the current file-system. Finally there is the `NgtscCompilerHost` to be used for any TypeScript compilation, which uses a given file-system. All tests that interact with the file-system should be tested against each of the mock file-systems. A series of helpers have been provided to support such tests: * `runInEachFileSystem()` - wrap your tests in this helper to run all the wrapped tests in each of the mock file-systems. * `addTestFilesToFileSystem()` - use this to add files and their contents to the mock file system for testing. * `loadTestFilesFromDisk()` - use this to load a mirror image of files on disk into the in-memory mock file-system. * `loadFakeCore()` - use this to load a fake version of `@angular/core` into the mock file-system. All ngcc and ngtsc source and tests now use this virtual file-system setup. PR Close #30921
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();
});
refactor(ivy): implement a virtual file-system layer in ngtsc + ngcc (#30921) To improve cross platform support, all file access (and path manipulation) is now done through a well known interface (`FileSystem`). For testing a number of `MockFileSystem` implementations are provided. These provide an in-memory file-system which emulates operating systems like OS/X, Unix and Windows. The current file system is always available via the static method, `FileSystem.getFileSystem()`. This is also used by a number of static methods on `AbsoluteFsPath` and `PathSegment`, to avoid having to pass `FileSystem` objects around all the time. The result of this is that one must be careful to ensure that the file-system has been initialized before using any of these static methods. To prevent this happening accidentally the current file system always starts out as an instance of `InvalidFileSystem`, which will throw an error if any of its methods are called. You can set the current file-system by calling `FileSystem.setFileSystem()`. During testing you can call the helper function `initMockFileSystem(os)` which takes a string name of the OS to emulate, and will also monkey-patch aspects of the TypeScript library to ensure that TS is also using the current file-system. Finally there is the `NgtscCompilerHost` to be used for any TypeScript compilation, which uses a given file-system. All tests that interact with the file-system should be tested against each of the mock file-systems. A series of helpers have been provided to support such tests: * `runInEachFileSystem()` - wrap your tests in this helper to run all the wrapped tests in each of the mock file-systems. * `addTestFilesToFileSystem()` - use this to add files and their contents to the mock file system for testing. * `loadTestFilesFromDisk()` - use this to load a mirror image of files on disk into the in-memory mock file-system. * `loadFakeCore()` - use this to load a fake version of `@angular/core` into the mock file-system. All ngcc and ngtsc source and tests now use this virtual file-system setup. PR Close #30921
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();
});
refactor(ivy): implement a virtual file-system layer in ngtsc + ngcc (#30921) To improve cross platform support, all file access (and path manipulation) is now done through a well known interface (`FileSystem`). For testing a number of `MockFileSystem` implementations are provided. These provide an in-memory file-system which emulates operating systems like OS/X, Unix and Windows. The current file system is always available via the static method, `FileSystem.getFileSystem()`. This is also used by a number of static methods on `AbsoluteFsPath` and `PathSegment`, to avoid having to pass `FileSystem` objects around all the time. The result of this is that one must be careful to ensure that the file-system has been initialized before using any of these static methods. To prevent this happening accidentally the current file system always starts out as an instance of `InvalidFileSystem`, which will throw an error if any of its methods are called. You can set the current file-system by calling `FileSystem.setFileSystem()`. During testing you can call the helper function `initMockFileSystem(os)` which takes a string name of the OS to emulate, and will also monkey-patch aspects of the TypeScript library to ensure that TS is also using the current file-system. Finally there is the `NgtscCompilerHost` to be used for any TypeScript compilation, which uses a given file-system. All tests that interact with the file-system should be tested against each of the mock file-systems. A series of helpers have been provided to support such tests: * `runInEachFileSystem()` - wrap your tests in this helper to run all the wrapped tests in each of the mock file-systems. * `addTestFilesToFileSystem()` - use this to add files and their contents to the mock file system for testing. * `loadTestFilesFromDisk()` - use this to load a mirror image of files on disk into the in-memory mock file-system. * `loadFakeCore()` - use this to load a fake version of `@angular/core` into the mock file-system. All ngcc and ngtsc source and tests now use this virtual file-system setup. PR Close #30921
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(),
});
refactor(ivy): implement a virtual file-system layer in ngtsc + ngcc (#30921) To improve cross platform support, all file access (and path manipulation) is now done through a well known interface (`FileSystem`). For testing a number of `MockFileSystem` implementations are provided. These provide an in-memory file-system which emulates operating systems like OS/X, Unix and Windows. The current file system is always available via the static method, `FileSystem.getFileSystem()`. This is also used by a number of static methods on `AbsoluteFsPath` and `PathSegment`, to avoid having to pass `FileSystem` objects around all the time. The result of this is that one must be careful to ensure that the file-system has been initialized before using any of these static methods. To prevent this happening accidentally the current file system always starts out as an instance of `InvalidFileSystem`, which will throw an error if any of its methods are called. You can set the current file-system by calling `FileSystem.setFileSystem()`. During testing you can call the helper function `initMockFileSystem(os)` which takes a string name of the OS to emulate, and will also monkey-patch aspects of the TypeScript library to ensure that TS is also using the current file-system. Finally there is the `NgtscCompilerHost` to be used for any TypeScript compilation, which uses a given file-system. All tests that interact with the file-system should be tested against each of the mock file-systems. A series of helpers have been provided to support such tests: * `runInEachFileSystem()` - wrap your tests in this helper to run all the wrapped tests in each of the mock file-systems. * `addTestFilesToFileSystem()` - use this to add files and their contents to the mock file system for testing. * `loadTestFilesFromDisk()` - use this to load a mirror image of files on disk into the in-memory mock file-system. * `loadFakeCore()` - use this to load a fake version of `@angular/core` into the mock file-system. All ngcc and ngtsc source and tests now use this virtual file-system setup. PR Close #30921
2019-06-06 15:22:32 -04:00
expect(loadPackage('local-package', _('/dist')).__processed_by_ivy_ngcc__).toEqual({
es2015: '0.0.0-PLACEHOLDER',
refactor(ivy): implement a virtual file-system layer in ngtsc + ngcc (#30921) To improve cross platform support, all file access (and path manipulation) is now done through a well known interface (`FileSystem`). For testing a number of `MockFileSystem` implementations are provided. These provide an in-memory file-system which emulates operating systems like OS/X, Unix and Windows. The current file system is always available via the static method, `FileSystem.getFileSystem()`. This is also used by a number of static methods on `AbsoluteFsPath` and `PathSegment`, to avoid having to pass `FileSystem` objects around all the time. The result of this is that one must be careful to ensure that the file-system has been initialized before using any of these static methods. To prevent this happening accidentally the current file system always starts out as an instance of `InvalidFileSystem`, which will throw an error if any of its methods are called. You can set the current file-system by calling `FileSystem.setFileSystem()`. During testing you can call the helper function `initMockFileSystem(os)` which takes a string name of the OS to emulate, and will also monkey-patch aspects of the TypeScript library to ensure that TS is also using the current file-system. Finally there is the `NgtscCompilerHost` to be used for any TypeScript compilation, which uses a given file-system. All tests that interact with the file-system should be tested against each of the mock file-systems. A series of helpers have been provided to support such tests: * `runInEachFileSystem()` - wrap your tests in this helper to run all the wrapped tests in each of the mock file-systems. * `addTestFilesToFileSystem()` - use this to add files and their contents to the mock file system for testing. * `loadTestFilesFromDisk()` - use this to load a mirror image of files on disk into the in-memory mock file-system. * `loadFakeCore()` - use this to load a fake version of `@angular/core` into the mock file-system. All ngcc and ngtsc source and tests now use this virtual file-system setup. PR Close #30921
2019-06-06 15:22:32 -04:00
typings: '0.0.0-PLACEHOLDER',
});
});
refactor(ngcc): take advantage of early knowledge about format property processability (#32427) In the past, a task's processability didn't use to be known in advance. It was possible that a task would be created and added to the queue during the analysis phase and then later (during the compilation phase) it would be found out that the task (i.e. the associated format property) was not processable. As a result, certain checks had to be delayed, until a task's processing had started or even until all tasks had been processed. Examples of checks that had to be delayed are: - Whether a task can be skipped due to `compileAllFormats: false`. - Whether there were entry-points for which no format at all was successfully processed. It turns out that (as made clear by the refactoring in 9537b2ff8), once a task starts being processed it is expected to either complete successfully (with the associated format being processed) or throw an error (in which case the process will exit). In other words, a task's processability is known in advance. This commit takes advantage of this fact by moving certain checks earlier in the process (e.g. in the analysis phase instead of the compilation phase), which in turn allows avoiding some unnecessary work. More specifically: - When `compileAllFormats` is `false`, tasks are created _only_ for the first suitable format property for each entry-point, since the rest of the tasks would have been skipped during the compilation phase anyway. This has the following advantages: 1. It avoids the slight overhead of generating extraneous tasks and then starting to process them (before realizing they should be skipped). 2. In a potential future parallel execution mode, unnecessary tasks might start being processed at the same time as the first (useful) task, even if their output would be later discarded, wasting resources. Alternatively, extra logic would have to be added to prevent this from happening. The change in this commit avoids these issues. - When an entry-point is not processable, an error will be thrown upfront without having to wait for other tasks to be processed before failing. PR Close #32427
2019-08-28 18:33:15 -04:00
it('should throw, if some of the entry-points are unprocessable', () => {
const createEntryPoint = (name: string, prop: EntryPointJsonProperty): TestFile[] => {
return [
{
name: _(`/dist/${name}/package.json`),
contents: `{"name": "${name}", "typings": "./index.d.ts", "${prop}": "./index.js"}`,
},
{name: _(`/dist/${name}/index.js`), contents: 'var DUMMY_DATA = true;'},
{name: _(`/dist/${name}/index.d.ts`), contents: 'export type DummyData = boolean;'},
{name: _(`/dist/${name}/index.metadata.json`), contents: 'DUMMY DATA'},
];
};
loadTestFiles([
...createEntryPoint('processable-1', 'es2015'),
...createEntryPoint('unprocessable-2', 'main'),
...createEntryPoint('unprocessable-3', 'main'),
]);
expect(() => mainNgcc({
basePath: '/dist',
propertiesToConsider: ['es2015', 'fesm5', 'module'],
logger: new MockLogger(),
}))
.toThrowError(
'Unable to process any formats for the following entry-points (tried es2015, fesm5, module): \n' +
` - ${_('/dist/unprocessable-2')}\n` +
` - ${_('/dist/unprocessable-3')}`);
});
it('should throw, if an error happens during processing', () => {
spyOn(Transformer.prototype, 'transform').and.throwError('Test error.');
expect(() => mainNgcc({
basePath: '/dist',
targetEntryPointPath: 'local-package',
propertiesToConsider: ['main', 'es2015'],
logger: new MockLogger(),
}))
.toThrowError(`Test error.`);
expect(loadPackage('@angular/core').__processed_by_ivy_ngcc__).toBeUndefined();
expect(loadPackage('local-package', _('/dist')).__processed_by_ivy_ngcc__).toBeUndefined();
});
it('should generate correct metadata for decorated getter/setter properties', () => {
compileIntoFlatEs5Package('test-package', {
'/index.ts': `
import {Directive, Input, NgModule} from '@angular/core';
@Directive({selector: '[foo]'})
export class FooDirective {
@Input() get bar() { return 'bar'; }
set bar(value: string) {}
}
@NgModule({
declarations: [FooDirective],
})
export class FooModule {}
`,
});
mainNgcc({
basePath: '/node_modules',
targetEntryPointPath: 'test-package',
propertiesToConsider: ['module'],
});
const jsContents = fs.readFile(_(`/node_modules/test-package/index.js`)).replace(/\s+/g, ' ');
expect(jsContents)
.toContain(
'/*@__PURE__*/ (function () { ɵngcc0.ɵsetClassMetadata(FooDirective, ' +
'[{ type: Directive, args: [{ selector: \'[foo]\' }] }], ' +
'function () { return []; }, ' +
'{ bar: [{ type: Input }] }); })();');
});
['esm5', 'esm2015'].forEach(target => {
it(`should be able to process spread operator inside objects for ${
target} format (imported helpers)`,
fix(ngcc): correctly detect emitted TS helpers in ES5 (#35191) In ES5 code, TypeScript requires certain helpers (such as `__spreadArrays()`) to be able to support ES2015+ features. These helpers can be either imported from `tslib` (by setting the `importHelpers` TS compiler option to `true`) or emitted inline (by setting the `importHelpers` and `noEmitHelpers` TS compiler options to `false`, which is the default value for both). Ngtsc's `StaticInterpreter` (which is also used during ngcc processing) is able to statically evaluate some of these helpers (currently `__assign()`, `__spread()` and `__spreadArrays()`), as long as `ReflectionHost#getDefinitionOfFunction()` correctly detects the declaration of the helper. For this to happen, the left-hand side of the corresponding call expression (i.e. `__spread(...)` or `tslib.__spread(...)`) must be evaluated as a function declaration for `getDefinitionOfFunction()` to be called with. In the case of imported helpers, the `tslib.__someHelper` expression was resolved to a function declaration of the form `export declare function __someHelper(...args: any[][]): any[];`, which allows `getDefinitionOfFunction()` to correctly map it to a TS helper. In contrast, in the case of emitted helpers (and regardless of the module format: `CommonJS`, `ESNext`, `UMD`, etc.)), the `__someHelper` identifier was resolved to a variable declaration of the form `var __someHelper = (this && this.__someHelper) || function () { ... }`, which upon further evaluation was categorized as a `DynamicValue` (prohibiting further evaluation by the `getDefinitionOfFunction()`). As a result of the above, emitted TypeScript helpers were not evaluated in ES5 code. --- This commit changes the detection of TS helpers to leverage the existing `KnownFn` feature (previously only used for built-in functions). `Esm5ReflectionHost` is changed to always return `KnownDeclaration`s for TS helpers, both imported (`getExportsOfModule()`) as well as emitted (`getDeclarationOfIdentifier()`). Similar changes are made to `CommonJsReflectionHost` and `UmdReflectionHost`. The `KnownDeclaration`s are then mapped to `KnownFn`s in `StaticInterpreter`, allowing it to statically evaluate call expressions involving any kind of TS helpers. Jira issue: https://angular-team.atlassian.net/browse/FW-1689 PR Close #35191
2020-02-06 11:44:49 -05:00
() => {
compileIntoApf(
'test-package', {
'/index.ts': `
import {Directive, Input, NgModule} from '@angular/core';
const a = { '[class.a]': 'true' };
const b = { '[class.b]': 'true' };
@Directive({
selector: '[foo]',
host: {...a, ...b, '[class.c]': 'false'}
})
export class FooDirective {}
@NgModule({
declarations: [FooDirective],
})
export class FooModule {}
`,
},
{importHelpers: true, noEmitHelpers: true});
fs.writeFile(
_('/node_modules/tslib/index.d.ts'),
`export declare function __assign(...args: object[]): object;`);
mainNgcc({
basePath: '/node_modules',
targetEntryPointPath: 'test-package',
propertiesToConsider: [target],
});
const jsContents = fs.readFile(_(`/node_modules/test-package/${target}/src/index.js`))
.replace(/\s+/g, ' ');
expect(jsContents).toContain('ngcc0.ɵɵclassProp("a", true)("b", true)("c", false)');
});
it(`should be able to process emitted spread operator inside objects for ${
target} format (emitted helpers)`,
fix(ngcc): correctly detect emitted TS helpers in ES5 (#35191) In ES5 code, TypeScript requires certain helpers (such as `__spreadArrays()`) to be able to support ES2015+ features. These helpers can be either imported from `tslib` (by setting the `importHelpers` TS compiler option to `true`) or emitted inline (by setting the `importHelpers` and `noEmitHelpers` TS compiler options to `false`, which is the default value for both). Ngtsc's `StaticInterpreter` (which is also used during ngcc processing) is able to statically evaluate some of these helpers (currently `__assign()`, `__spread()` and `__spreadArrays()`), as long as `ReflectionHost#getDefinitionOfFunction()` correctly detects the declaration of the helper. For this to happen, the left-hand side of the corresponding call expression (i.e. `__spread(...)` or `tslib.__spread(...)`) must be evaluated as a function declaration for `getDefinitionOfFunction()` to be called with. In the case of imported helpers, the `tslib.__someHelper` expression was resolved to a function declaration of the form `export declare function __someHelper(...args: any[][]): any[];`, which allows `getDefinitionOfFunction()` to correctly map it to a TS helper. In contrast, in the case of emitted helpers (and regardless of the module format: `CommonJS`, `ESNext`, `UMD`, etc.)), the `__someHelper` identifier was resolved to a variable declaration of the form `var __someHelper = (this && this.__someHelper) || function () { ... }`, which upon further evaluation was categorized as a `DynamicValue` (prohibiting further evaluation by the `getDefinitionOfFunction()`). As a result of the above, emitted TypeScript helpers were not evaluated in ES5 code. --- This commit changes the detection of TS helpers to leverage the existing `KnownFn` feature (previously only used for built-in functions). `Esm5ReflectionHost` is changed to always return `KnownDeclaration`s for TS helpers, both imported (`getExportsOfModule()`) as well as emitted (`getDeclarationOfIdentifier()`). Similar changes are made to `CommonJsReflectionHost` and `UmdReflectionHost`. The `KnownDeclaration`s are then mapped to `KnownFn`s in `StaticInterpreter`, allowing it to statically evaluate call expressions involving any kind of TS helpers. Jira issue: https://angular-team.atlassian.net/browse/FW-1689 PR Close #35191
2020-02-06 11:44:49 -05:00
() => {
compileIntoApf(
'test-package', {
'/index.ts': `
import {Directive, Input, NgModule} from '@angular/core';
const a = { '[class.a]': 'true' };
const b = { '[class.b]': 'true' };
@Directive({
selector: '[foo]',
host: {...a, ...b, '[class.c]': 'false'}
})
export class FooDirective {}
@NgModule({
declarations: [FooDirective],
})
export class FooModule {}
`,
},
{importHelpers: false, noEmitHelpers: false});
mainNgcc({
basePath: '/node_modules',
targetEntryPointPath: 'test-package',
propertiesToConsider: [target],
});
const jsContents = fs.readFile(_(`/node_modules/test-package/${target}/src/index.js`))
.replace(/\s+/g, ' ');
expect(jsContents).toContain('ngcc0.ɵɵclassProp("a", true)("b", true)("c", false)');
});
});
it('should not add `const` in ES5 generated code', () => {
compileIntoFlatEs5Package('test-package', {
'/index.ts': `
import {Directive, Input, NgModule} from '@angular/core';
@Directive({
selector: '[foo]',
host: {bar: ''},
})
export class FooDirective {
}
@NgModule({
declarations: [FooDirective],
})
export class FooModule {}
`,
});
mainNgcc({
basePath: '/node_modules',
targetEntryPointPath: 'test-package',
propertiesToConsider: ['module'],
});
const jsContents = fs.readFile(_(`/node_modules/test-package/index.js`));
expect(jsContents).not.toMatch(/\bconst \w+\s*=/);
});
fix(ngcc): consistently delegate to TypeScript host for typing files (#36089) When ngcc is compiling an entry-point, it uses a `ReflectionHost` that is specific to its format, e.g. ES2015, ES5, UMD or CommonJS. During the compilation of that entry-point however, the reflector may be used to reflect into external libraries using their declaration files. Up until now this was achieved by letting all `ReflectionHost` classes consider their parent class for reflector queries, thereby ending up in the `TypeScriptReflectionHost` that is a common base class for all reflector hosts. This approach has proven to be prone to bugs, as failing to call into the base class would cause incompatibilities with reading from declaration files. The observation can be made that there's only two distinct kinds of reflection host queries: 1. the reflector query is about code that is part of the entry-point that is being compiled, or 2. the reflector query is for an external library that the entry-point depends on, in which case the information is reflected from the declaration files. The `ReflectionHost` that was chosen for the entry-point should serve only reflector queries for the first case, whereas a regular `TypeScriptReflectionHost` should be used for the second case. This avoids the problem where a format-specific `ReflectionHost` fails to handle the second case correctly, as it isn't even considered for such reflector queries. This commit introduces a `ReflectionHost` that delegates to the `TypeScriptReflectionHost` for AST nodes within declaration files, otherwise delegating to the format-specific `ReflectionHost`. Fixes #35078 Resolves FW-1859 PR Close #36089
2020-02-04 16:15:06 -05:00
it('should be able to reflect into external libraries', () => {
compileIntoApf('lib', {
'/index.ts': `
export * from './constants';
export * from './module';
`,
'/constants.ts': `
export const selectorA = '[selector-a]';
export class Selectors {
static readonly B = '[selector-b]';
}
`,
'/module.ts': `
import {NgModule, ModuleWithProviders} from '@angular/core';
@NgModule()
export class MyOtherModule {}
export class MyModule {
static forRoot(): ModuleWithProviders<MyOtherModule> {
return {ngModule: MyOtherModule};
}
}
`
});
compileIntoFlatEs5Package('test-package', {
'/index.ts': `
import {Directive, Input, NgModule} from '@angular/core';
import * as lib from 'lib';
@Directive({
selector: lib.selectorA,
})
export class DirectiveA {
}
@Directive({
selector: lib.Selectors.B,
})
export class DirectiveB {
}
@NgModule({
imports: [lib.MyModule.forRoot()],
declarations: [DirectiveA, DirectiveB],
})
export class FooModule {}
`,
});
mainNgcc({
basePath: '/node_modules',
targetEntryPointPath: 'test-package',
propertiesToConsider: ['module'],
});
const jsContents = fs.readFile(_(`/node_modules/test-package/index.js`));
expect(jsContents).toContain('"selector-a"');
expect(jsContents).toContain('"selector-b"');
expect(jsContents).toContain('imports: [ɵngcc1.MyOtherModule]');
});
it('should be able to resolve enum values', () => {
compileIntoApf('test-package', {
'/index.ts': `
import {Component, NgModule} from '@angular/core';
export enum StringEnum {
ValueA = "a",
ValueB = "b",
}
export enum NumericEnum {
Value3 = 3,
Value4,
}
@Component({
template: \`\${StringEnum.ValueA} - \${StringEnum.ValueB} - \${NumericEnum.Value3} - \${NumericEnum.Value4}\`,
})
export class FooCmp {}
@NgModule({
declarations: [FooCmp],
})
export class FooModule {}
`,
});
mainNgcc({
basePath: '/node_modules',
targetEntryPointPath: 'test-package',
propertiesToConsider: ['esm2015', 'esm5'],
});
const es2015Contents = fs.readFile(_(`/node_modules/test-package/esm2015/src/index.js`));
expect(es2015Contents).toContain('ɵngcc0.ɵɵtext(0, "a - b - 3 - 4")');
const es5Contents = fs.readFile(_(`/node_modules/test-package/esm5/src/index.js`));
expect(es5Contents).toContain('ɵngcc0.ɵɵtext(0, "a - b - 3 - 4")');
});
it('should add ɵfac but not duplicate ɵprov properties on injectables', () => {
compileIntoFlatEs5Package('test-package', {
'/index.ts': `
import {Injectable, ɵɵdefineInjectable} from '@angular/core';
export const TestClassToken = 'TestClassToken';
@Injectable({providedIn: 'module'})
export class TestClass {
static ɵprov = ɵɵdefineInjectable({ factory: () => {}, token: TestClassToken, providedIn: "module" });
}
`,
});
const before = fs.readFile(_(`/node_modules/test-package/index.js`));
const originalProp = /ɵprov[^;]+/.exec(before)![0];
mainNgcc({
basePath: '/node_modules',
targetEntryPointPath: 'test-package',
propertiesToConsider: ['module'],
});
const after = fs.readFile(_(`/node_modules/test-package/index.js`));
expect(before).toContain(originalProp);
expect(countOccurrences(before, 'ɵprov')).toEqual(1);
expect(countOccurrences(before, 'ɵfac')).toEqual(0);
expect(after).toContain(originalProp);
expect(countOccurrences(after, 'ɵprov')).toEqual(1);
expect(countOccurrences(after, 'ɵfac')).toEqual(1);
});
// This is necessary to ensure XPipeDef.fac is defined when delegated from injectable def
it('should always generate factory def (fac) before injectable def (prov)', () => {
compileIntoFlatEs5Package('test-package', {
'/index.ts': `
import {Injectable, Pipe, PipeTransform} from '@angular/core';
@Injectable()
@Pipe({
name: 'myTestPipe'
})
export class TestClass implements PipeTransform {
transform(value: any) { return value; }
}
`,
});
mainNgcc({
basePath: '/node_modules',
targetEntryPointPath: 'test-package',
propertiesToConsider: ['module'],
});
const jsContents = fs.readFile(_(`/node_modules/test-package/index.js`));
expect(jsContents)
.toContain(
`TestClass.ɵfac = function TestClass_Factory(t) { return new (t || TestClass)(); };\n` +
`TestClass.ɵpipe = ɵngcc0.ɵɵdefinePipe({ name: "myTestPipe", type: TestClass, pure: true });\n` +
`TestClass.ɵprov = ɵngcc0.ɵɵdefineInjectable({`);
});
it('should use the correct type name in typings files when an export has a different name in source files',
() => {
// We need to make sure that changes to the typings files use the correct name
// static ɵprov: ɵngcc0.ɵɵInjectableDef<ɵangular_packages_common_common_a>;
mainNgcc({
basePath: '/node_modules',
targetEntryPointPath: '@angular/common',
propertiesToConsider: ['esm2015']
});
// In `@angular/common` the `BrowserPlatformLocation` class gets exported as something like
// `ɵangular_packages_common_common_a`.
const jsContents = fs.readFile(_(`/node_modules/@angular/common/fesm2015/common.js`));
const exportedNameMatch =
jsContents.match(/export.* BrowserPlatformLocation as ([^ ,}]+)/);
if (exportedNameMatch === null) {
return fail(
'Expected `/node_modules/@angular/common/fesm2015/common.js` to export `BrowserPlatformLocation` via an alias');
}
const exportedName = exportedNameMatch[1];
// We need to make sure that the flat typings file exports this directly
const dtsContents = fs.readFile(_('/node_modules/@angular/common/common.d.ts'));
expect(dtsContents)
.toContain(`export declare class ${exportedName} extends PlatformLocation`);
// And that ngcc's modifications to that class use the correct (exported) name
feat(compiler): add dependency info and ng-content selectors to metadata (#35695) This commit augments the `FactoryDef` declaration of Angular decorated classes to contain information about the parameter decorators used in the constructor. If no constructor is present, or none of the parameters have any Angular decorators, then this will be represented using the `null` type. Otherwise, a tuple type is used where the entry at index `i` corresponds with parameter `i`. Each tuple entry can be one of two types: 1. If the associated parameter does not have any Angular decorators, the tuple entry will be the `null` type. 2. Otherwise, a type literal is used that may declare at least one of the following properties: - "attribute": if `@Attribute` is present. The injected attribute's name is used as string literal type, or the `unknown` type if the attribute name is not a string literal. - "self": if `@Self` is present, always of type `true`. - "skipSelf": if `@SkipSelf` is present, always of type `true`. - "host": if `@Host` is present, always of type `true`. - "optional": if `@Optional` is present, always of type `true`. A property is only present if the corresponding decorator is used. Note that the `@Inject` decorator is currently not included, as it's non-trivial to properly convert the token's value expression to a type that is valid in a declaration file. Additionally, the `ComponentDefWithMeta` declaration that is created for Angular components has been extended to include all selectors on `ng-content` elements within the component's template. This additional metadata is useful for tooling such as the Angular Language Service, as it provides the ability to offer suggestions for directives/components defined in libraries. At the moment, such tooling extracts the necessary information from the _metadata.json_ manifest file as generated by ngc, however this metadata representation is being replaced by the information emitted into the declaration files. Resolves FW-1870 PR Close #35695
2020-02-26 16:05:44 -05:00
expect(dtsContents).toContain(`static ɵfac: ɵngcc0.ɵɵFactoryDef<${exportedName}, never>`);
});
feat(compiler): add dependency info and ng-content selectors to metadata (#35695) This commit augments the `FactoryDef` declaration of Angular decorated classes to contain information about the parameter decorators used in the constructor. If no constructor is present, or none of the parameters have any Angular decorators, then this will be represented using the `null` type. Otherwise, a tuple type is used where the entry at index `i` corresponds with parameter `i`. Each tuple entry can be one of two types: 1. If the associated parameter does not have any Angular decorators, the tuple entry will be the `null` type. 2. Otherwise, a type literal is used that may declare at least one of the following properties: - "attribute": if `@Attribute` is present. The injected attribute's name is used as string literal type, or the `unknown` type if the attribute name is not a string literal. - "self": if `@Self` is present, always of type `true`. - "skipSelf": if `@SkipSelf` is present, always of type `true`. - "host": if `@Host` is present, always of type `true`. - "optional": if `@Optional` is present, always of type `true`. A property is only present if the corresponding decorator is used. Note that the `@Inject` decorator is currently not included, as it's non-trivial to properly convert the token's value expression to a type that is valid in a declaration file. Additionally, the `ComponentDefWithMeta` declaration that is created for Angular components has been extended to include all selectors on `ng-content` elements within the component's template. This additional metadata is useful for tooling such as the Angular Language Service, as it provides the ability to offer suggestions for directives/components defined in libraries. At the moment, such tooling extracts the necessary information from the _metadata.json_ manifest file as generated by ngc, however this metadata representation is being replaced by the information emitted into the declaration files. Resolves FW-1870 PR Close #35695
2020-02-26 16:05:44 -05:00
it('should include constructor metadata in factory definitions', () => {
mainNgcc({
basePath: '/node_modules',
targetEntryPointPath: '@angular/common',
propertiesToConsider: ['esm2015']
});
const dtsContents = fs.readFile(_('/node_modules/@angular/common/common.d.ts'));
expect(dtsContents)
.toContain(
`static ɵfac: ɵngcc0.ɵɵFactoryDef<NgPluralCase, [{ attribute: "ngPluralCase"; }, null, null, { host: true; }]>`);
});
it('should add generic type for ModuleWithProviders and generate exports for private modules',
() => {
compileIntoApf('test-package', {
'/index.ts': `
import {ModuleWithProviders} from '@angular/core';
import {InternalFooModule} from './internal';
export class FooModule {
static forRoot(): ModuleWithProviders {
return {
ngModule: InternalFooModule,
};
}
}
`,
'/internal.ts': `
import {NgModule} from '@angular/core';
@NgModule()
export class InternalFooModule {}
`,
});
mainNgcc({
basePath: '/node_modules',
targetEntryPointPath: 'test-package',
propertiesToConsider: ['esm2015', 'esm5', 'module'],
});
// The .d.ts where FooModule is declared should have a generic type added
const dtsContents = fs.readFile(_(`/node_modules/test-package/src/index.d.ts`));
expect(dtsContents).toContain(`import * as ɵngcc0 from './internal';`);
expect(dtsContents)
.toContain(`static forRoot(): ModuleWithProviders<ɵngcc0.InternalFooModule>`);
// The public facing .d.ts should export the InternalFooModule
const entryDtsContents = fs.readFile(_(`/node_modules/test-package/index.d.ts`));
expect(entryDtsContents).toContain(`export {InternalFooModule} from './src/internal';`);
// The esm2015 index source should export the InternalFooModule
const esm2015Contents = fs.readFile(_(`/node_modules/test-package/esm2015/index.js`));
expect(esm2015Contents).toContain(`export {InternalFooModule} from './src/internal';`);
// The esm5 index source should also export the InternalFooModule
const esm5Contents = fs.readFile(_(`/node_modules/test-package/esm5/index.js`));
expect(esm5Contents).toContain(`export {InternalFooModule} from './src/internal';`);
});
it('should use `$localize` calls rather than tagged templates in ES5 generated code', () => {
compileIntoFlatEs5Package('test-package', {
'/index.ts': `
import {Component, Input, NgModule} from '@angular/core';
@Component({
selector: '[foo]',
template: '<div i18n="some:\`description\`">A message</div>'
})
export class FooComponent {
}
@NgModule({
declarations: [FooComponent],
})
export class FooModule {}
`,
});
mainNgcc({
basePath: '/node_modules',
targetEntryPointPath: 'test-package',
propertiesToConsider: ['module'],
});
const jsContents = fs.readFile(_(`/node_modules/test-package/index.js`));
expect(jsContents).not.toMatch(/\$localize\s*`/);
expect(jsContents)
.toMatch(
/\$localize\(ɵngcc\d+\.__makeTemplateObject\(\[":some:`description`\\u241Fefc92f285b3c24b083a8a594f62c7fccf3118766\\u241F3806630072763809030:A message"], \[":some\\\\:\\\\`description\\\\`\\u241Fefc92f285b3c24b083a8a594f62c7fccf3118766\\u241F3806630072763809030:A message"]\)\);/);
});
describe('in async mode', () => {
it('should run ngcc without errors for fesm2015', async () => {
const promise = mainNgcc({
basePath: '/node_modules',
propertiesToConsider: ['fesm2015'],
async: true,
});
expect(promise).toEqual(jasmine.any(Promise));
await promise;
});
it('should reject, if some of the entry-points are unprocessable', async () => {
refactor(ngcc): take advantage of early knowledge about format property processability (#32427) In the past, a task's processability didn't use to be known in advance. It was possible that a task would be created and added to the queue during the analysis phase and then later (during the compilation phase) it would be found out that the task (i.e. the associated format property) was not processable. As a result, certain checks had to be delayed, until a task's processing had started or even until all tasks had been processed. Examples of checks that had to be delayed are: - Whether a task can be skipped due to `compileAllFormats: false`. - Whether there were entry-points for which no format at all was successfully processed. It turns out that (as made clear by the refactoring in 9537b2ff8), once a task starts being processed it is expected to either complete successfully (with the associated format being processed) or throw an error (in which case the process will exit). In other words, a task's processability is known in advance. This commit takes advantage of this fact by moving certain checks earlier in the process (e.g. in the analysis phase instead of the compilation phase), which in turn allows avoiding some unnecessary work. More specifically: - When `compileAllFormats` is `false`, tasks are created _only_ for the first suitable format property for each entry-point, since the rest of the tasks would have been skipped during the compilation phase anyway. This has the following advantages: 1. It avoids the slight overhead of generating extraneous tasks and then starting to process them (before realizing they should be skipped). 2. In a potential future parallel execution mode, unnecessary tasks might start being processed at the same time as the first (useful) task, even if their output would be later discarded, wasting resources. Alternatively, extra logic would have to be added to prevent this from happening. The change in this commit avoids these issues. - When an entry-point is not processable, an error will be thrown upfront without having to wait for other tasks to be processed before failing. PR Close #32427
2019-08-28 18:33:15 -04:00
const createEntryPoint = (name: string, prop: EntryPointJsonProperty): TestFile[] => {
return [
{
name: _(`/dist/${name}/package.json`),
contents: `{"name": "${name}", "typings": "./index.d.ts", "${prop}": "./index.js"}`,
},
{name: _(`/dist/${name}/index.js`), contents: 'var DUMMY_DATA = true;'},
{name: _(`/dist/${name}/index.d.ts`), contents: 'export type DummyData = boolean;'},
{name: _(`/dist/${name}/index.metadata.json`), contents: 'DUMMY DATA'},
];
};
loadTestFiles([
...createEntryPoint('processable-1', 'es2015'),
...createEntryPoint('unprocessable-2', 'main'),
...createEntryPoint('unprocessable-3', 'main'),
]);
const promise = mainNgcc({
basePath: '/dist',
propertiesToConsider: ['es2015', 'fesm5', 'module'],
logger: new MockLogger(),
async: true,
});
await promise.then(
() => Promise.reject('Expected promise to be rejected.'),
err => expect(err).toEqual(new Error(
'Unable to process any formats for the following entry-points (tried es2015, fesm5, module): \n' +
` - ${_('/dist/unprocessable-2')}\n` +
` - ${_('/dist/unprocessable-3')}`)));
});
it('should reject, if an error happens during processing', async () => {
spyOn(Transformer.prototype, 'transform').and.throwError('Test error.');
const promise = mainNgcc({
basePath: '/dist',
targetEntryPointPath: 'local-package',
propertiesToConsider: ['main', 'es2015'],
logger: new MockLogger(),
async: true,
});
await promise.then(
() => Promise.reject('Expected promise to be rejected.'),
err => expect(err).toEqual(new Error('Test error.')));
expect(loadPackage('@angular/core').__processed_by_ivy_ngcc__).toBeUndefined();
expect(loadPackage('local-package', _('/dist')).__processed_by_ivy_ngcc__).toBeUndefined();
});
});
refactor(ivy): implement a virtual file-system layer in ngtsc + ngcc (#30921) To improve cross platform support, all file access (and path manipulation) is now done through a well known interface (`FileSystem`). For testing a number of `MockFileSystem` implementations are provided. These provide an in-memory file-system which emulates operating systems like OS/X, Unix and Windows. The current file system is always available via the static method, `FileSystem.getFileSystem()`. This is also used by a number of static methods on `AbsoluteFsPath` and `PathSegment`, to avoid having to pass `FileSystem` objects around all the time. The result of this is that one must be careful to ensure that the file-system has been initialized before using any of these static methods. To prevent this happening accidentally the current file system always starts out as an instance of `InvalidFileSystem`, which will throw an error if any of its methods are called. You can set the current file-system by calling `FileSystem.setFileSystem()`. During testing you can call the helper function `initMockFileSystem(os)` which takes a string name of the OS to emulate, and will also monkey-patch aspects of the TypeScript library to ensure that TS is also using the current file-system. Finally there is the `NgtscCompilerHost` to be used for any TypeScript compilation, which uses a given file-system. All tests that interact with the file-system should be tested against each of the mock file-systems. A series of helpers have been provided to support such tests: * `runInEachFileSystem()` - wrap your tests in this helper to run all the wrapped tests in each of the mock file-systems. * `addTestFilesToFileSystem()` - use this to add files and their contents to the mock file system for testing. * `loadTestFilesFromDisk()` - use this to load a mirror image of files on disk into the in-memory mock file-system. * `loadFakeCore()` - use this to load a fake version of `@angular/core` into the mock file-system. All ngcc and ngtsc source and tests now use this virtual file-system setup. PR Close #30921
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();
});
it('should not mark a non-Angular package as processed if it is the target', () => {
refactor(ivy): implement a virtual file-system layer in ngtsc + ngcc (#30921) To improve cross platform support, all file access (and path manipulation) is now done through a well known interface (`FileSystem`). For testing a number of `MockFileSystem` implementations are provided. These provide an in-memory file-system which emulates operating systems like OS/X, Unix and Windows. The current file system is always available via the static method, `FileSystem.getFileSystem()`. This is also used by a number of static methods on `AbsoluteFsPath` and `PathSegment`, to avoid having to pass `FileSystem` objects around all the time. The result of this is that one must be careful to ensure that the file-system has been initialized before using any of these static methods. To prevent this happening accidentally the current file system always starts out as an instance of `InvalidFileSystem`, which will throw an error if any of its methods are called. You can set the current file-system by calling `FileSystem.setFileSystem()`. During testing you can call the helper function `initMockFileSystem(os)` which takes a string name of the OS to emulate, and will also monkey-patch aspects of the TypeScript library to ensure that TS is also using the current file-system. Finally there is the `NgtscCompilerHost` to be used for any TypeScript compilation, which uses a given file-system. All tests that interact with the file-system should be tested against each of the mock file-systems. A series of helpers have been provided to support such tests: * `runInEachFileSystem()` - wrap your tests in this helper to run all the wrapped tests in each of the mock file-systems. * `addTestFilesToFileSystem()` - use this to add files and their contents to the mock file system for testing. * `loadTestFilesFromDisk()` - use this to load a mirror image of files on disk into the in-memory mock file-system. * `loadFakeCore()` - use this to load a fake version of `@angular/core` into the mock file-system. All ngcc and ngtsc source and tests now use this virtual file-system setup. PR Close #30921
2019-06-06 15:22:32 -04:00
mainNgcc({basePath: '/node_modules', targetEntryPointPath: 'test-package'});
// * `test-package` has no Angular and is not marked as processed.
expect(loadPackage('test-package').__processed_by_ivy_ngcc__).toBeUndefined();
// * `core` is a dependency of `test-package`, but it is also not processed, since
// `test-package` was not processed.
expect(loadPackage('@angular/core').__processed_by_ivy_ngcc__).toBeUndefined();
});
it('should not mark a non-Angular package as processed if it is a dependency', () => {
// `test-package-user` is a valid Angular package that depends upon `test-package`.
loadTestFiles([
{
name: _('/node_modules/test-package-user/package.json'),
contents:
'{"name": "test-package-user", "es2015": "./index.js", "typings": "./index.d.ts"}'
},
{
name: _('/node_modules/test-package-user/index.js'),
contents: 'import * as x from \'test-package\';'
},
{
name: _('/node_modules/test-package-user/index.d.ts'),
contents: 'import * as x from \'test-package\';'
},
{name: _('/node_modules/test-package-user/index.metadata.json'), contents: 'DUMMY DATA'},
]);
mainNgcc({basePath: '/node_modules', targetEntryPointPath: 'test-package-user'});
// * `test-package-user` is processed because it is compiled by Angular
expect(loadPackage('test-package-user').__processed_by_ivy_ngcc__).toEqual({
refactor(ivy): implement a virtual file-system layer in ngtsc + ngcc (#30921) To improve cross platform support, all file access (and path manipulation) is now done through a well known interface (`FileSystem`). For testing a number of `MockFileSystem` implementations are provided. These provide an in-memory file-system which emulates operating systems like OS/X, Unix and Windows. The current file system is always available via the static method, `FileSystem.getFileSystem()`. This is also used by a number of static methods on `AbsoluteFsPath` and `PathSegment`, to avoid having to pass `FileSystem` objects around all the time. The result of this is that one must be careful to ensure that the file-system has been initialized before using any of these static methods. To prevent this happening accidentally the current file system always starts out as an instance of `InvalidFileSystem`, which will throw an error if any of its methods are called. You can set the current file-system by calling `FileSystem.setFileSystem()`. During testing you can call the helper function `initMockFileSystem(os)` which takes a string name of the OS to emulate, and will also monkey-patch aspects of the TypeScript library to ensure that TS is also using the current file-system. Finally there is the `NgtscCompilerHost` to be used for any TypeScript compilation, which uses a given file-system. All tests that interact with the file-system should be tested against each of the mock file-systems. A series of helpers have been provided to support such tests: * `runInEachFileSystem()` - wrap your tests in this helper to run all the wrapped tests in each of the mock file-systems. * `addTestFilesToFileSystem()` - use this to add files and their contents to the mock file system for testing. * `loadTestFilesFromDisk()` - use this to load a mirror image of files on disk into the in-memory mock file-system. * `loadFakeCore()` - use this to load a fake version of `@angular/core` into the mock file-system. All ngcc and ngtsc source and tests now use this virtual file-system setup. PR Close #30921
2019-06-06 15:22:32 -04:00
es2015: '0.0.0-PLACEHOLDER',
typings: '0.0.0-PLACEHOLDER',
});
refactor(ivy): implement a virtual file-system layer in ngtsc + ngcc (#30921) To improve cross platform support, all file access (and path manipulation) is now done through a well known interface (`FileSystem`). For testing a number of `MockFileSystem` implementations are provided. These provide an in-memory file-system which emulates operating systems like OS/X, Unix and Windows. The current file system is always available via the static method, `FileSystem.getFileSystem()`. This is also used by a number of static methods on `AbsoluteFsPath` and `PathSegment`, to avoid having to pass `FileSystem` objects around all the time. The result of this is that one must be careful to ensure that the file-system has been initialized before using any of these static methods. To prevent this happening accidentally the current file system always starts out as an instance of `InvalidFileSystem`, which will throw an error if any of its methods are called. You can set the current file-system by calling `FileSystem.setFileSystem()`. During testing you can call the helper function `initMockFileSystem(os)` which takes a string name of the OS to emulate, and will also monkey-patch aspects of the TypeScript library to ensure that TS is also using the current file-system. Finally there is the `NgtscCompilerHost` to be used for any TypeScript compilation, which uses a given file-system. All tests that interact with the file-system should be tested against each of the mock file-systems. A series of helpers have been provided to support such tests: * `runInEachFileSystem()` - wrap your tests in this helper to run all the wrapped tests in each of the mock file-systems. * `addTestFilesToFileSystem()` - use this to add files and their contents to the mock file system for testing. * `loadTestFilesFromDisk()` - use this to load a mirror image of files on disk into the in-memory mock file-system. * `loadFakeCore()` - use this to load a fake version of `@angular/core` into the mock file-system. All ngcc and ngtsc source and tests now use this virtual file-system setup. PR Close #30921
2019-06-06 15:22:32 -04:00
// * `test-package` is a dependency of `test-package-user` but has not been compiled by
// Angular, and so is not marked as processed
expect(loadPackage('test-package').__processed_by_ivy_ngcc__).toBeUndefined();
// * `core` is a dependency of `test-package`, but it is not processed, because
// `test-package` was not processed.
refactor(ivy): implement a virtual file-system layer in ngtsc + ngcc (#30921) To improve cross platform support, all file access (and path manipulation) is now done through a well known interface (`FileSystem`). For testing a number of `MockFileSystem` implementations are provided. These provide an in-memory file-system which emulates operating systems like OS/X, Unix and Windows. The current file system is always available via the static method, `FileSystem.getFileSystem()`. This is also used by a number of static methods on `AbsoluteFsPath` and `PathSegment`, to avoid having to pass `FileSystem` objects around all the time. The result of this is that one must be careful to ensure that the file-system has been initialized before using any of these static methods. To prevent this happening accidentally the current file system always starts out as an instance of `InvalidFileSystem`, which will throw an error if any of its methods are called. You can set the current file-system by calling `FileSystem.setFileSystem()`. During testing you can call the helper function `initMockFileSystem(os)` which takes a string name of the OS to emulate, and will also monkey-patch aspects of the TypeScript library to ensure that TS is also using the current file-system. Finally there is the `NgtscCompilerHost` to be used for any TypeScript compilation, which uses a given file-system. All tests that interact with the file-system should be tested against each of the mock file-systems. A series of helpers have been provided to support such tests: * `runInEachFileSystem()` - wrap your tests in this helper to run all the wrapped tests in each of the mock file-systems. * `addTestFilesToFileSystem()` - use this to add files and their contents to the mock file system for testing. * `loadTestFilesFromDisk()` - use this to load a mirror image of files on disk into the in-memory mock file-system. * `loadFakeCore()` - use this to load a fake version of `@angular/core` into the mock file-system. All ngcc and ngtsc source and tests now use this virtual file-system setup. PR Close #30921
2019-06-06 15:22:32 -04:00
expect(loadPackage('@angular/core').__processed_by_ivy_ngcc__).toBeUndefined();
});
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');
});
});
refactor(ivy): implement a virtual file-system layer in ngtsc + ngcc (#30921) To improve cross platform support, all file access (and path manipulation) is now done through a well known interface (`FileSystem`). For testing a number of `MockFileSystem` implementations are provided. These provide an in-memory file-system which emulates operating systems like OS/X, Unix and Windows. The current file system is always available via the static method, `FileSystem.getFileSystem()`. This is also used by a number of static methods on `AbsoluteFsPath` and `PathSegment`, to avoid having to pass `FileSystem` objects around all the time. The result of this is that one must be careful to ensure that the file-system has been initialized before using any of these static methods. To prevent this happening accidentally the current file system always starts out as an instance of `InvalidFileSystem`, which will throw an error if any of its methods are called. You can set the current file-system by calling `FileSystem.setFileSystem()`. During testing you can call the helper function `initMockFileSystem(os)` which takes a string name of the OS to emulate, and will also monkey-patch aspects of the TypeScript library to ensure that TS is also using the current file-system. Finally there is the `NgtscCompilerHost` to be used for any TypeScript compilation, which uses a given file-system. All tests that interact with the file-system should be tested against each of the mock file-systems. A series of helpers have been provided to support such tests: * `runInEachFileSystem()` - wrap your tests in this helper to run all the wrapped tests in each of the mock file-systems. * `addTestFilesToFileSystem()` - use this to add files and their contents to the mock file system for testing. * `loadTestFilesFromDisk()` - use this to load a mirror image of files on disk into the in-memory mock file-system. * `loadFakeCore()` - use this to load a fake version of `@angular/core` into the mock file-system. All ngcc and ngtsc source and tests now use this virtual file-system setup. PR Close #30921
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,
refactor(ivy): implement a virtual file-system layer in ngtsc + ngcc (#30921) To improve cross platform support, all file access (and path manipulation) is now done through a well known interface (`FileSystem`). For testing a number of `MockFileSystem` implementations are provided. These provide an in-memory file-system which emulates operating systems like OS/X, Unix and Windows. The current file system is always available via the static method, `FileSystem.getFileSystem()`. This is also used by a number of static methods on `AbsoluteFsPath` and `PathSegment`, to avoid having to pass `FileSystem` objects around all the time. The result of this is that one must be careful to ensure that the file-system has been initialized before using any of these static methods. To prevent this happening accidentally the current file system always starts out as an instance of `InvalidFileSystem`, which will throw an error if any of its methods are called. You can set the current file-system by calling `FileSystem.setFileSystem()`. During testing you can call the helper function `initMockFileSystem(os)` which takes a string name of the OS to emulate, and will also monkey-patch aspects of the TypeScript library to ensure that TS is also using the current file-system. Finally there is the `NgtscCompilerHost` to be used for any TypeScript compilation, which uses a given file-system. All tests that interact with the file-system should be tested against each of the mock file-systems. A series of helpers have been provided to support such tests: * `runInEachFileSystem()` - wrap your tests in this helper to run all the wrapped tests in each of the mock file-systems. * `addTestFilesToFileSystem()` - use this to add files and their contents to the mock file system for testing. * `loadTestFilesFromDisk()` - use this to load a mirror image of files on disk into the in-memory mock file-system. * `loadFakeCore()` - use this to load a fake version of `@angular/core` into the mock file-system. All ngcc and ngtsc source and tests now use this virtual file-system setup. PR Close #30921
2019-06-06 15:22:32 -04:00
});
expect(logger.logs.debug).toContain([
'The target entry-point has already been processed'
]);
});
refactor(ivy): implement a virtual file-system layer in ngtsc + ngcc (#30921) To improve cross platform support, all file access (and path manipulation) is now done through a well known interface (`FileSystem`). For testing a number of `MockFileSystem` implementations are provided. These provide an in-memory file-system which emulates operating systems like OS/X, Unix and Windows. The current file system is always available via the static method, `FileSystem.getFileSystem()`. This is also used by a number of static methods on `AbsoluteFsPath` and `PathSegment`, to avoid having to pass `FileSystem` objects around all the time. The result of this is that one must be careful to ensure that the file-system has been initialized before using any of these static methods. To prevent this happening accidentally the current file system always starts out as an instance of `InvalidFileSystem`, which will throw an error if any of its methods are called. You can set the current file-system by calling `FileSystem.setFileSystem()`. During testing you can call the helper function `initMockFileSystem(os)` which takes a string name of the OS to emulate, and will also monkey-patch aspects of the TypeScript library to ensure that TS is also using the current file-system. Finally there is the `NgtscCompilerHost` to be used for any TypeScript compilation, which uses a given file-system. All tests that interact with the file-system should be tested against each of the mock file-systems. A series of helpers have been provided to support such tests: * `runInEachFileSystem()` - wrap your tests in this helper to run all the wrapped tests in each of the mock file-systems. * `addTestFilesToFileSystem()` - use this to add files and their contents to the mock file system for testing. * `loadTestFilesFromDisk()` - use this to load a mirror image of files on disk into the in-memory mock file-system. * `loadFakeCore()` - use this to load a fake version of `@angular/core` into the mock file-system. All ngcc and ngtsc source and tests now use this virtual file-system setup. PR Close #30921
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,
refactor(ivy): implement a virtual file-system layer in ngtsc + ngcc (#30921) To improve cross platform support, all file access (and path manipulation) is now done through a well known interface (`FileSystem`). For testing a number of `MockFileSystem` implementations are provided. These provide an in-memory file-system which emulates operating systems like OS/X, Unix and Windows. The current file system is always available via the static method, `FileSystem.getFileSystem()`. This is also used by a number of static methods on `AbsoluteFsPath` and `PathSegment`, to avoid having to pass `FileSystem` objects around all the time. The result of this is that one must be careful to ensure that the file-system has been initialized before using any of these static methods. To prevent this happening accidentally the current file system always starts out as an instance of `InvalidFileSystem`, which will throw an error if any of its methods are called. You can set the current file-system by calling `FileSystem.setFileSystem()`. During testing you can call the helper function `initMockFileSystem(os)` which takes a string name of the OS to emulate, and will also monkey-patch aspects of the TypeScript library to ensure that TS is also using the current file-system. Finally there is the `NgtscCompilerHost` to be used for any TypeScript compilation, which uses a given file-system. All tests that interact with the file-system should be tested against each of the mock file-systems. A series of helpers have been provided to support such tests: * `runInEachFileSystem()` - wrap your tests in this helper to run all the wrapped tests in each of the mock file-systems. * `addTestFilesToFileSystem()` - use this to add files and their contents to the mock file system for testing. * `loadTestFilesFromDisk()` - use this to load a mirror image of files on disk into the in-memory mock file-system. * `loadFakeCore()` - use this to load a fake version of `@angular/core` into the mock file-system. All ngcc and ngtsc source and tests now use this virtual file-system setup. PR Close #30921
2019-06-06 15:22:32 -04:00
});
expect(logger.logs.debug).not.toContain([
'The target entry-point has already been processed'
]);
});
});
refactor(ivy): implement a virtual file-system layer in ngtsc + ngcc (#30921) To improve cross platform support, all file access (and path manipulation) is now done through a well known interface (`FileSystem`). For testing a number of `MockFileSystem` implementations are provided. These provide an in-memory file-system which emulates operating systems like OS/X, Unix and Windows. The current file system is always available via the static method, `FileSystem.getFileSystem()`. This is also used by a number of static methods on `AbsoluteFsPath` and `PathSegment`, to avoid having to pass `FileSystem` objects around all the time. The result of this is that one must be careful to ensure that the file-system has been initialized before using any of these static methods. To prevent this happening accidentally the current file system always starts out as an instance of `InvalidFileSystem`, which will throw an error if any of its methods are called. You can set the current file-system by calling `FileSystem.setFileSystem()`. During testing you can call the helper function `initMockFileSystem(os)` which takes a string name of the OS to emulate, and will also monkey-patch aspects of the TypeScript library to ensure that TS is also using the current file-system. Finally there is the `NgtscCompilerHost` to be used for any TypeScript compilation, which uses a given file-system. All tests that interact with the file-system should be tested against each of the mock file-systems. A series of helpers have been provided to support such tests: * `runInEachFileSystem()` - wrap your tests in this helper to run all the wrapped tests in each of the mock file-systems. * `addTestFilesToFileSystem()` - use this to add files and their contents to the mock file system for testing. * `loadTestFilesFromDisk()` - use this to load a mirror image of files on disk into the in-memory mock file-system. * `loadFakeCore()` - use this to load a fake version of `@angular/core` into the mock file-system. All ngcc and ngtsc source and tests now use this virtual file-system setup. PR Close #30921
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,
refactor(ivy): implement a virtual file-system layer in ngtsc + ngcc (#30921) To improve cross platform support, all file access (and path manipulation) is now done through a well known interface (`FileSystem`). For testing a number of `MockFileSystem` implementations are provided. These provide an in-memory file-system which emulates operating systems like OS/X, Unix and Windows. The current file system is always available via the static method, `FileSystem.getFileSystem()`. This is also used by a number of static methods on `AbsoluteFsPath` and `PathSegment`, to avoid having to pass `FileSystem` objects around all the time. The result of this is that one must be careful to ensure that the file-system has been initialized before using any of these static methods. To prevent this happening accidentally the current file system always starts out as an instance of `InvalidFileSystem`, which will throw an error if any of its methods are called. You can set the current file-system by calling `FileSystem.setFileSystem()`. During testing you can call the helper function `initMockFileSystem(os)` which takes a string name of the OS to emulate, and will also monkey-patch aspects of the TypeScript library to ensure that TS is also using the current file-system. Finally there is the `NgtscCompilerHost` to be used for any TypeScript compilation, which uses a given file-system. All tests that interact with the file-system should be tested against each of the mock file-systems. A series of helpers have been provided to support such tests: * `runInEachFileSystem()` - wrap your tests in this helper to run all the wrapped tests in each of the mock file-systems. * `addTestFilesToFileSystem()` - use this to add files and their contents to the mock file system for testing. * `loadTestFilesFromDisk()` - use this to load a mirror image of files on disk into the in-memory mock file-system. * `loadFakeCore()` - use this to load a fake version of `@angular/core` into the mock file-system. All ngcc and ngtsc source and tests now use this virtual file-system setup. PR Close #30921
2019-06-06 15:22:32 -04:00
});
expect(logger.logs.debug).not.toContain([
'The target entry-point has already been processed'
]);
});
refactor(ivy): implement a virtual file-system layer in ngtsc + ngcc (#30921) To improve cross platform support, all file access (and path manipulation) is now done through a well known interface (`FileSystem`). For testing a number of `MockFileSystem` implementations are provided. These provide an in-memory file-system which emulates operating systems like OS/X, Unix and Windows. The current file system is always available via the static method, `FileSystem.getFileSystem()`. This is also used by a number of static methods on `AbsoluteFsPath` and `PathSegment`, to avoid having to pass `FileSystem` objects around all the time. The result of this is that one must be careful to ensure that the file-system has been initialized before using any of these static methods. To prevent this happening accidentally the current file system always starts out as an instance of `InvalidFileSystem`, which will throw an error if any of its methods are called. You can set the current file-system by calling `FileSystem.setFileSystem()`. During testing you can call the helper function `initMockFileSystem(os)` which takes a string name of the OS to emulate, and will also monkey-patch aspects of the TypeScript library to ensure that TS is also using the current file-system. Finally there is the `NgtscCompilerHost` to be used for any TypeScript compilation, which uses a given file-system. All tests that interact with the file-system should be tested against each of the mock file-systems. A series of helpers have been provided to support such tests: * `runInEachFileSystem()` - wrap your tests in this helper to run all the wrapped tests in each of the mock file-systems. * `addTestFilesToFileSystem()` - use this to add files and their contents to the mock file system for testing. * `loadTestFilesFromDisk()` - use this to load a mirror image of files on disk into the in-memory mock file-system. * `loadFakeCore()` - use this to load a fake version of `@angular/core` into the mock file-system. All ngcc and ngtsc source and tests now use this virtual file-system setup. PR Close #30921
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,
refactor(ivy): implement a virtual file-system layer in ngtsc + ngcc (#30921) To improve cross platform support, all file access (and path manipulation) is now done through a well known interface (`FileSystem`). For testing a number of `MockFileSystem` implementations are provided. These provide an in-memory file-system which emulates operating systems like OS/X, Unix and Windows. The current file system is always available via the static method, `FileSystem.getFileSystem()`. This is also used by a number of static methods on `AbsoluteFsPath` and `PathSegment`, to avoid having to pass `FileSystem` objects around all the time. The result of this is that one must be careful to ensure that the file-system has been initialized before using any of these static methods. To prevent this happening accidentally the current file system always starts out as an instance of `InvalidFileSystem`, which will throw an error if any of its methods are called. You can set the current file-system by calling `FileSystem.setFileSystem()`. During testing you can call the helper function `initMockFileSystem(os)` which takes a string name of the OS to emulate, and will also monkey-patch aspects of the TypeScript library to ensure that TS is also using the current file-system. Finally there is the `NgtscCompilerHost` to be used for any TypeScript compilation, which uses a given file-system. All tests that interact with the file-system should be tested against each of the mock file-systems. A series of helpers have been provided to support such tests: * `runInEachFileSystem()` - wrap your tests in this helper to run all the wrapped tests in each of the mock file-systems. * `addTestFilesToFileSystem()` - use this to add files and their contents to the mock file system for testing. * `loadTestFilesFromDisk()` - use this to load a mirror image of files on disk into the in-memory mock file-system. * `loadFakeCore()` - use this to load a fake version of `@angular/core` into the mock file-system. All ngcc and ngtsc source and tests now use this virtual file-system setup. PR Close #30921
2019-06-06 15:22:32 -04:00
});
expect(logger.logs.debug).toContain([
'The target entry-point has already been processed'
]);
});
});
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'
]);
});
});
refactor(ivy): implement a virtual file-system layer in ngtsc + ngcc (#30921) To improve cross platform support, all file access (and path manipulation) is now done through a well known interface (`FileSystem`). For testing a number of `MockFileSystem` implementations are provided. These provide an in-memory file-system which emulates operating systems like OS/X, Unix and Windows. The current file system is always available via the static method, `FileSystem.getFileSystem()`. This is also used by a number of static methods on `AbsoluteFsPath` and `PathSegment`, to avoid having to pass `FileSystem` objects around all the time. The result of this is that one must be careful to ensure that the file-system has been initialized before using any of these static methods. To prevent this happening accidentally the current file system always starts out as an instance of `InvalidFileSystem`, which will throw an error if any of its methods are called. You can set the current file-system by calling `FileSystem.setFileSystem()`. During testing you can call the helper function `initMockFileSystem(os)` which takes a string name of the OS to emulate, and will also monkey-patch aspects of the TypeScript library to ensure that TS is also using the current file-system. Finally there is the `NgtscCompilerHost` to be used for any TypeScript compilation, which uses a given file-system. All tests that interact with the file-system should be tested against each of the mock file-systems. A series of helpers have been provided to support such tests: * `runInEachFileSystem()` - wrap your tests in this helper to run all the wrapped tests in each of the mock file-systems. * `addTestFilesToFileSystem()` - use this to add files and their contents to the mock file system for testing. * `loadTestFilesFromDisk()` - use this to load a mirror image of files on disk into the in-memory mock file-system. * `loadFakeCore()` - use this to load a fake version of `@angular/core` into the mock file-system. All ngcc and ngtsc source and tests now use this virtual file-system setup. PR Close #30921
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);
markAsProcessed(
pkgJsonUpdater, targetPackage, targetPackageJsonPath, ['typings', ...properties]);
refactor(ivy): implement a virtual file-system layer in ngtsc + ngcc (#30921) To improve cross platform support, all file access (and path manipulation) is now done through a well known interface (`FileSystem`). For testing a number of `MockFileSystem` implementations are provided. These provide an in-memory file-system which emulates operating systems like OS/X, Unix and Windows. The current file system is always available via the static method, `FileSystem.getFileSystem()`. This is also used by a number of static methods on `AbsoluteFsPath` and `PathSegment`, to avoid having to pass `FileSystem` objects around all the time. The result of this is that one must be careful to ensure that the file-system has been initialized before using any of these static methods. To prevent this happening accidentally the current file system always starts out as an instance of `InvalidFileSystem`, which will throw an error if any of its methods are called. You can set the current file-system by calling `FileSystem.setFileSystem()`. During testing you can call the helper function `initMockFileSystem(os)` which takes a string name of the OS to emulate, and will also monkey-patch aspects of the TypeScript library to ensure that TS is also using the current file-system. Finally there is the `NgtscCompilerHost` to be used for any TypeScript compilation, which uses a given file-system. All tests that interact with the file-system should be tested against each of the mock file-systems. A series of helpers have been provided to support such tests: * `runInEachFileSystem()` - wrap your tests in this helper to run all the wrapped tests in each of the mock file-systems. * `addTestFilesToFileSystem()` - use this to add files and their contents to the mock file system for testing. * `loadTestFilesFromDisk()` - use this to load a mirror image of files on disk into the in-memory mock file-system. * `loadFakeCore()` - use this to load a fake version of `@angular/core` into the mock file-system. All ngcc and ngtsc source and tests now use this virtual file-system setup. PR Close #30921
2019-06-06 15:22:32 -04:00
}
it('should clean up outdated artifacts', () => {
compileIntoFlatEs5Package('test-package', {
'index.ts': `
import {Directive} from '@angular/core';
@Directive({selector: '[foo]'})
export class FooDirective {
}
`,
});
mainNgcc({
basePath: '/node_modules',
propertiesToConsider: ['module'],
logger: new MockLogger(),
});
// Now hack the files to look like it was processed by an outdated version of ngcc
const packageJson = loadPackage('test-package', _('/node_modules'));
packageJson.__processed_by_ivy_ngcc__!.typings = '8.0.0';
packageJson.main_ivy_ngcc = '__ivy_ngcc__/main.js';
fs.writeFile(_('/node_modules/test-package/package.json'), JSON.stringify(packageJson));
fs.writeFile(_('/node_modules/test-package/x.js'), 'processed content');
fs.writeFile(_('/node_modules/test-package/x.js.__ivy_ngcc_bak'), 'original content');
fs.ensureDir(_('/node_modules/test-package/__ivy_ngcc__/foo'));
// Now run ngcc again to see that it cleans out the outdated artifacts
mainNgcc({
basePath: '/node_modules',
propertiesToConsider: ['module'],
logger: new MockLogger(),
});
const newPackageJson = loadPackage('test-package', _('/node_modules'));
expect(newPackageJson.__processed_by_ivy_ngcc__).toEqual({
module: '0.0.0-PLACEHOLDER',
typings: '0.0.0-PLACEHOLDER',
});
expect(newPackageJson.module_ivy_ngcc).toBeUndefined();
expect(fs.exists(_('/node_modules/test-package/x.js'))).toBe(true);
expect(fs.exists(_('/node_modules/test-package/x.js.__ivy_ngcc_bak'))).toBe(false);
expect(fs.readFile(_('/node_modules/test-package/x.js'))).toEqual('original content');
expect(fs.exists(_('/node_modules/test-package/__ivy_ngcc__'))).toBe(false);
});
refactor(ivy): implement a virtual file-system layer in ngtsc + ngcc (#30921) To improve cross platform support, all file access (and path manipulation) is now done through a well known interface (`FileSystem`). For testing a number of `MockFileSystem` implementations are provided. These provide an in-memory file-system which emulates operating systems like OS/X, Unix and Windows. The current file system is always available via the static method, `FileSystem.getFileSystem()`. This is also used by a number of static methods on `AbsoluteFsPath` and `PathSegment`, to avoid having to pass `FileSystem` objects around all the time. The result of this is that one must be careful to ensure that the file-system has been initialized before using any of these static methods. To prevent this happening accidentally the current file system always starts out as an instance of `InvalidFileSystem`, which will throw an error if any of its methods are called. You can set the current file-system by calling `FileSystem.setFileSystem()`. During testing you can call the helper function `initMockFileSystem(os)` which takes a string name of the OS to emulate, and will also monkey-patch aspects of the TypeScript library to ensure that TS is also using the current file-system. Finally there is the `NgtscCompilerHost` to be used for any TypeScript compilation, which uses a given file-system. All tests that interact with the file-system should be tested against each of the mock file-systems. A series of helpers have been provided to support such tests: * `runInEachFileSystem()` - wrap your tests in this helper to run all the wrapped tests in each of the mock file-systems. * `addTestFilesToFileSystem()` - use this to add files and their contents to the mock file system for testing. * `loadTestFilesFromDisk()` - use this to load a mirror image of files on disk into the in-memory mock file-system. * `loadFakeCore()` - use this to load a fake version of `@angular/core` into the mock file-system. All ngcc and ngtsc source and tests now use this virtual file-system setup. PR Close #30921
2019-06-06 15:22:32 -04:00
describe('with propertiesToConsider', () => {
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, browser';
expect(() => mainNgcc({basePath: '/node_modules', propertiesToConsider}))
.toThrowError(errorMessage);
});
refactor(ivy): implement a virtual file-system layer in ngtsc + ngcc (#30921) To improve cross platform support, all file access (and path manipulation) is now done through a well known interface (`FileSystem`). For testing a number of `MockFileSystem` implementations are provided. These provide an in-memory file-system which emulates operating systems like OS/X, Unix and Windows. The current file system is always available via the static method, `FileSystem.getFileSystem()`. This is also used by a number of static methods on `AbsoluteFsPath` and `PathSegment`, to avoid having to pass `FileSystem` objects around all the time. The result of this is that one must be careful to ensure that the file-system has been initialized before using any of these static methods. To prevent this happening accidentally the current file system always starts out as an instance of `InvalidFileSystem`, which will throw an error if any of its methods are called. You can set the current file-system by calling `FileSystem.setFileSystem()`. During testing you can call the helper function `initMockFileSystem(os)` which takes a string name of the OS to emulate, and will also monkey-patch aspects of the TypeScript library to ensure that TS is also using the current file-system. Finally there is the `NgtscCompilerHost` to be used for any TypeScript compilation, which uses a given file-system. All tests that interact with the file-system should be tested against each of the mock file-systems. A series of helpers have been provided to support such tests: * `runInEachFileSystem()` - wrap your tests in this helper to run all the wrapped tests in each of the mock file-systems. * `addTestFilesToFileSystem()` - use this to add files and their contents to the mock file system for testing. * `loadTestFilesFromDisk()` - use this to load a mirror image of files on disk into the in-memory mock file-system. * `loadFakeCore()` - use this to load a fake version of `@angular/core` into the mock file-system. All ngcc and ngtsc source and tests now use this virtual file-system setup. PR Close #30921
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(),
refactor(ivy): implement a virtual file-system layer in ngtsc + ngcc (#30921) To improve cross platform support, all file access (and path manipulation) is now done through a well known interface (`FileSystem`). For testing a number of `MockFileSystem` implementations are provided. These provide an in-memory file-system which emulates operating systems like OS/X, Unix and Windows. The current file system is always available via the static method, `FileSystem.getFileSystem()`. This is also used by a number of static methods on `AbsoluteFsPath` and `PathSegment`, to avoid having to pass `FileSystem` objects around all the time. The result of this is that one must be careful to ensure that the file-system has been initialized before using any of these static methods. To prevent this happening accidentally the current file system always starts out as an instance of `InvalidFileSystem`, which will throw an error if any of its methods are called. You can set the current file-system by calling `FileSystem.setFileSystem()`. During testing you can call the helper function `initMockFileSystem(os)` which takes a string name of the OS to emulate, and will also monkey-patch aspects of the TypeScript library to ensure that TS is also using the current file-system. Finally there is the `NgtscCompilerHost` to be used for any TypeScript compilation, which uses a given file-system. All tests that interact with the file-system should be tested against each of the mock file-systems. A series of helpers have been provided to support such tests: * `runInEachFileSystem()` - wrap your tests in this helper to run all the wrapped tests in each of the mock file-systems. * `addTestFilesToFileSystem()` - use this to add files and their contents to the mock file system for testing. * `loadTestFilesFromDisk()` - use this to load a mirror image of files on disk into the in-memory mock file-system. * `loadFakeCore()` - use this to load a fake version of `@angular/core` into the mock file-system. All ngcc and ngtsc source and tests now use this virtual file-system setup. PR Close #30921
2019-06-06 15:22:32 -04:00
});
refactor(ivy): implement a virtual file-system layer in ngtsc + ngcc (#30921) To improve cross platform support, all file access (and path manipulation) is now done through a well known interface (`FileSystem`). For testing a number of `MockFileSystem` implementations are provided. These provide an in-memory file-system which emulates operating systems like OS/X, Unix and Windows. The current file system is always available via the static method, `FileSystem.getFileSystem()`. This is also used by a number of static methods on `AbsoluteFsPath` and `PathSegment`, to avoid having to pass `FileSystem` objects around all the time. The result of this is that one must be careful to ensure that the file-system has been initialized before using any of these static methods. To prevent this happening accidentally the current file system always starts out as an instance of `InvalidFileSystem`, which will throw an error if any of its methods are called. You can set the current file-system by calling `FileSystem.setFileSystem()`. During testing you can call the helper function `initMockFileSystem(os)` which takes a string name of the OS to emulate, and will also monkey-patch aspects of the TypeScript library to ensure that TS is also using the current file-system. Finally there is the `NgtscCompilerHost` to be used for any TypeScript compilation, which uses a given file-system. All tests that interact with the file-system should be tested against each of the mock file-systems. A series of helpers have been provided to support such tests: * `runInEachFileSystem()` - wrap your tests in this helper to run all the wrapped tests in each of the mock file-systems. * `addTestFilesToFileSystem()` - use this to add files and their contents to the mock file system for testing. * `loadTestFilesFromDisk()` - use this to load a mirror image of files on disk into the in-memory mock file-system. * `loadFakeCore()` - use this to load a fake version of `@angular/core` into the mock file-system. All ngcc and ngtsc source and tests now use this virtual file-system setup. PR Close #30921
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',
});
});
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).']);
});
refactor(ivy): implement a virtual file-system layer in ngtsc + ngcc (#30921) To improve cross platform support, all file access (and path manipulation) is now done through a well known interface (`FileSystem`). For testing a number of `MockFileSystem` implementations are provided. These provide an in-memory file-system which emulates operating systems like OS/X, Unix and Windows. The current file system is always available via the static method, `FileSystem.getFileSystem()`. This is also used by a number of static methods on `AbsoluteFsPath` and `PathSegment`, to avoid having to pass `FileSystem` objects around all the time. The result of this is that one must be careful to ensure that the file-system has been initialized before using any of these static methods. To prevent this happening accidentally the current file system always starts out as an instance of `InvalidFileSystem`, which will throw an error if any of its methods are called. You can set the current file-system by calling `FileSystem.setFileSystem()`. During testing you can call the helper function `initMockFileSystem(os)` which takes a string name of the OS to emulate, and will also monkey-patch aspects of the TypeScript library to ensure that TS is also using the current file-system. Finally there is the `NgtscCompilerHost` to be used for any TypeScript compilation, which uses a given file-system. All tests that interact with the file-system should be tested against each of the mock file-systems. A series of helpers have been provided to support such tests: * `runInEachFileSystem()` - wrap your tests in this helper to run all the wrapped tests in each of the mock file-systems. * `addTestFilesToFileSystem()` - use this to add files and their contents to the mock file system for testing. * `loadTestFilesFromDisk()` - use this to load a mirror image of files on disk into the in-memory mock file-system. * `loadFakeCore()` - use this to load a fake version of `@angular/core` into the mock file-system. All ngcc and ngtsc source and tests now use this virtual file-system setup. PR Close #30921
2019-06-06 15:22:32 -04:00
});
refactor(ivy): implement a virtual file-system layer in ngtsc + ngcc (#30921) To improve cross platform support, all file access (and path manipulation) is now done through a well known interface (`FileSystem`). For testing a number of `MockFileSystem` implementations are provided. These provide an in-memory file-system which emulates operating systems like OS/X, Unix and Windows. The current file system is always available via the static method, `FileSystem.getFileSystem()`. This is also used by a number of static methods on `AbsoluteFsPath` and `PathSegment`, to avoid having to pass `FileSystem` objects around all the time. The result of this is that one must be careful to ensure that the file-system has been initialized before using any of these static methods. To prevent this happening accidentally the current file system always starts out as an instance of `InvalidFileSystem`, which will throw an error if any of its methods are called. You can set the current file-system by calling `FileSystem.setFileSystem()`. During testing you can call the helper function `initMockFileSystem(os)` which takes a string name of the OS to emulate, and will also monkey-patch aspects of the TypeScript library to ensure that TS is also using the current file-system. Finally there is the `NgtscCompilerHost` to be used for any TypeScript compilation, which uses a given file-system. All tests that interact with the file-system should be tested against each of the mock file-systems. A series of helpers have been provided to support such tests: * `runInEachFileSystem()` - wrap your tests in this helper to run all the wrapped tests in each of the mock file-systems. * `addTestFilesToFileSystem()` - use this to add files and their contents to the mock file system for testing. * `loadTestFilesFromDisk()` - use this to load a mirror image of files on disk into the in-memory mock file-system. * `loadFakeCore()` - use this to load a fake version of `@angular/core` into the mock file-system. All ngcc and ngtsc source and tests now use this virtual file-system setup. PR Close #30921
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(),
});
// * 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',
});
});
refactor(ivy): implement a virtual file-system layer in ngtsc + ngcc (#30921) To improve cross platform support, all file access (and path manipulation) is now done through a well known interface (`FileSystem`). For testing a number of `MockFileSystem` implementations are provided. These provide an in-memory file-system which emulates operating systems like OS/X, Unix and Windows. The current file system is always available via the static method, `FileSystem.getFileSystem()`. This is also used by a number of static methods on `AbsoluteFsPath` and `PathSegment`, to avoid having to pass `FileSystem` objects around all the time. The result of this is that one must be careful to ensure that the file-system has been initialized before using any of these static methods. To prevent this happening accidentally the current file system always starts out as an instance of `InvalidFileSystem`, which will throw an error if any of its methods are called. You can set the current file-system by calling `FileSystem.setFileSystem()`. During testing you can call the helper function `initMockFileSystem(os)` which takes a string name of the OS to emulate, and will also monkey-patch aspects of the TypeScript library to ensure that TS is also using the current file-system. Finally there is the `NgtscCompilerHost` to be used for any TypeScript compilation, which uses a given file-system. All tests that interact with the file-system should be tested against each of the mock file-systems. A series of helpers have been provided to support such tests: * `runInEachFileSystem()` - wrap your tests in this helper to run all the wrapped tests in each of the mock file-systems. * `addTestFilesToFileSystem()` - use this to add files and their contents to the mock file system for testing. * `loadTestFilesFromDisk()` - use this to load a mirror image of files on disk into the in-memory mock file-system. * `loadFakeCore()` - use this to load a fake version of `@angular/core` into the mock file-system. All ngcc and ngtsc source and tests now use this virtual file-system setup. PR Close #30921
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(),
refactor(ivy): implement a virtual file-system layer in ngtsc + ngcc (#30921) To improve cross platform support, all file access (and path manipulation) is now done through a well known interface (`FileSystem`). For testing a number of `MockFileSystem` implementations are provided. These provide an in-memory file-system which emulates operating systems like OS/X, Unix and Windows. The current file system is always available via the static method, `FileSystem.getFileSystem()`. This is also used by a number of static methods on `AbsoluteFsPath` and `PathSegment`, to avoid having to pass `FileSystem` objects around all the time. The result of this is that one must be careful to ensure that the file-system has been initialized before using any of these static methods. To prevent this happening accidentally the current file system always starts out as an instance of `InvalidFileSystem`, which will throw an error if any of its methods are called. You can set the current file-system by calling `FileSystem.setFileSystem()`. During testing you can call the helper function `initMockFileSystem(os)` which takes a string name of the OS to emulate, and will also monkey-patch aspects of the TypeScript library to ensure that TS is also using the current file-system. Finally there is the `NgtscCompilerHost` to be used for any TypeScript compilation, which uses a given file-system. All tests that interact with the file-system should be tested against each of the mock file-systems. A series of helpers have been provided to support such tests: * `runInEachFileSystem()` - wrap your tests in this helper to run all the wrapped tests in each of the mock file-systems. * `addTestFilesToFileSystem()` - use this to add files and their contents to the mock file system for testing. * `loadTestFilesFromDisk()` - use this to load a mirror image of files on disk into the in-memory mock file-system. * `loadFakeCore()` - use this to load a fake version of `@angular/core` into the mock file-system. All ngcc and ngtsc source and tests now use this virtual file-system setup. PR Close #30921
2019-06-06 15:22:32 -04:00
});
expect(loadPackage('@angular/core').__processed_by_ivy_ngcc__).toEqual({
fesm5: '0.0.0-PLACEHOLDER',
refactor(ivy): implement a virtual file-system layer in ngtsc + ngcc (#30921) To improve cross platform support, all file access (and path manipulation) is now done through a well known interface (`FileSystem`). For testing a number of `MockFileSystem` implementations are provided. These provide an in-memory file-system which emulates operating systems like OS/X, Unix and Windows. The current file system is always available via the static method, `FileSystem.getFileSystem()`. This is also used by a number of static methods on `AbsoluteFsPath` and `PathSegment`, to avoid having to pass `FileSystem` objects around all the time. The result of this is that one must be careful to ensure that the file-system has been initialized before using any of these static methods. To prevent this happening accidentally the current file system always starts out as an instance of `InvalidFileSystem`, which will throw an error if any of its methods are called. You can set the current file-system by calling `FileSystem.setFileSystem()`. During testing you can call the helper function `initMockFileSystem(os)` which takes a string name of the OS to emulate, and will also monkey-patch aspects of the TypeScript library to ensure that TS is also using the current file-system. Finally there is the `NgtscCompilerHost` to be used for any TypeScript compilation, which uses a given file-system. All tests that interact with the file-system should be tested against each of the mock file-systems. A series of helpers have been provided to support such tests: * `runInEachFileSystem()` - wrap your tests in this helper to run all the wrapped tests in each of the mock file-systems. * `addTestFilesToFileSystem()` - use this to add files and their contents to the mock file system for testing. * `loadTestFilesFromDisk()` - use this to load a mirror image of files on disk into the in-memory mock file-system. * `loadFakeCore()` - use this to load a fake version of `@angular/core` into the mock file-system. All ngcc and ngtsc source and tests now use this virtual file-system setup. PR Close #30921
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',
fesm5: '0.0.0-PLACEHOLDER',
refactor(ivy): implement a virtual file-system layer in ngtsc + ngcc (#30921) To improve cross platform support, all file access (and path manipulation) is now done through a well known interface (`FileSystem`). For testing a number of `MockFileSystem` implementations are provided. These provide an in-memory file-system which emulates operating systems like OS/X, Unix and Windows. The current file system is always available via the static method, `FileSystem.getFileSystem()`. This is also used by a number of static methods on `AbsoluteFsPath` and `PathSegment`, to avoid having to pass `FileSystem` objects around all the time. The result of this is that one must be careful to ensure that the file-system has been initialized before using any of these static methods. To prevent this happening accidentally the current file system always starts out as an instance of `InvalidFileSystem`, which will throw an error if any of its methods are called. You can set the current file-system by calling `FileSystem.setFileSystem()`. During testing you can call the helper function `initMockFileSystem(os)` which takes a string name of the OS to emulate, and will also monkey-patch aspects of the TypeScript library to ensure that TS is also using the current file-system. Finally there is the `NgtscCompilerHost` to be used for any TypeScript compilation, which uses a given file-system. All tests that interact with the file-system should be tested against each of the mock file-systems. A series of helpers have been provided to support such tests: * `runInEachFileSystem()` - wrap your tests in this helper to run all the wrapped tests in each of the mock file-systems. * `addTestFilesToFileSystem()` - use this to add files and their contents to the mock file system for testing. * `loadTestFilesFromDisk()` - use this to load a mirror image of files on disk into the in-memory mock file-system. * `loadFakeCore()` - use this to load a fake version of `@angular/core` into the mock file-system. All ngcc and ngtsc source and tests now use this virtual file-system setup. PR Close #30921
2019-06-06 15:22:32 -04:00
module: '0.0.0-PLACEHOLDER',
typings: '0.0.0-PLACEHOLDER',
});
});
refactor(ivy): implement a virtual file-system layer in ngtsc + ngcc (#30921) To improve cross platform support, all file access (and path manipulation) is now done through a well known interface (`FileSystem`). For testing a number of `MockFileSystem` implementations are provided. These provide an in-memory file-system which emulates operating systems like OS/X, Unix and Windows. The current file system is always available via the static method, `FileSystem.getFileSystem()`. This is also used by a number of static methods on `AbsoluteFsPath` and `PathSegment`, to avoid having to pass `FileSystem` objects around all the time. The result of this is that one must be careful to ensure that the file-system has been initialized before using any of these static methods. To prevent this happening accidentally the current file system always starts out as an instance of `InvalidFileSystem`, which will throw an error if any of its methods are called. You can set the current file-system by calling `FileSystem.setFileSystem()`. During testing you can call the helper function `initMockFileSystem(os)` which takes a string name of the OS to emulate, and will also monkey-patch aspects of the TypeScript library to ensure that TS is also using the current file-system. Finally there is the `NgtscCompilerHost` to be used for any TypeScript compilation, which uses a given file-system. All tests that interact with the file-system should be tested against each of the mock file-systems. A series of helpers have been provided to support such tests: * `runInEachFileSystem()` - wrap your tests in this helper to run all the wrapped tests in each of the mock file-systems. * `addTestFilesToFileSystem()` - use this to add files and their contents to the mock file system for testing. * `loadTestFilesFromDisk()` - use this to load a mirror image of files on disk into the in-memory mock file-system. * `loadFakeCore()` - use this to load a fake version of `@angular/core` into the mock file-system. All ngcc and ngtsc source and tests now use this virtual file-system setup. PR Close #30921
2019-06-06 15:22:32 -04:00
});
refactor(ivy): implement a virtual file-system layer in ngtsc + ngcc (#30921) To improve cross platform support, all file access (and path manipulation) is now done through a well known interface (`FileSystem`). For testing a number of `MockFileSystem` implementations are provided. These provide an in-memory file-system which emulates operating systems like OS/X, Unix and Windows. The current file system is always available via the static method, `FileSystem.getFileSystem()`. This is also used by a number of static methods on `AbsoluteFsPath` and `PathSegment`, to avoid having to pass `FileSystem` objects around all the time. The result of this is that one must be careful to ensure that the file-system has been initialized before using any of these static methods. To prevent this happening accidentally the current file system always starts out as an instance of `InvalidFileSystem`, which will throw an error if any of its methods are called. You can set the current file-system by calling `FileSystem.setFileSystem()`. During testing you can call the helper function `initMockFileSystem(os)` which takes a string name of the OS to emulate, and will also monkey-patch aspects of the TypeScript library to ensure that TS is also using the current file-system. Finally there is the `NgtscCompilerHost` to be used for any TypeScript compilation, which uses a given file-system. All tests that interact with the file-system should be tested against each of the mock file-systems. A series of helpers have been provided to support such tests: * `runInEachFileSystem()` - wrap your tests in this helper to run all the wrapped tests in each of the mock file-systems. * `addTestFilesToFileSystem()` - use this to add files and their contents to the mock file system for testing. * `loadTestFilesFromDisk()` - use this to load a mirror image of files on disk into the in-memory mock file-system. * `loadFakeCore()` - use this to load a fake version of `@angular/core` into the mock file-system. All ngcc and ngtsc source and tests now use this virtual file-system setup. PR Close #30921
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(),
refactor(ivy): implement a virtual file-system layer in ngtsc + ngcc (#30921) To improve cross platform support, all file access (and path manipulation) is now done through a well known interface (`FileSystem`). For testing a number of `MockFileSystem` implementations are provided. These provide an in-memory file-system which emulates operating systems like OS/X, Unix and Windows. The current file system is always available via the static method, `FileSystem.getFileSystem()`. This is also used by a number of static methods on `AbsoluteFsPath` and `PathSegment`, to avoid having to pass `FileSystem` objects around all the time. The result of this is that one must be careful to ensure that the file-system has been initialized before using any of these static methods. To prevent this happening accidentally the current file system always starts out as an instance of `InvalidFileSystem`, which will throw an error if any of its methods are called. You can set the current file-system by calling `FileSystem.setFileSystem()`. During testing you can call the helper function `initMockFileSystem(os)` which takes a string name of the OS to emulate, and will also monkey-patch aspects of the TypeScript library to ensure that TS is also using the current file-system. Finally there is the `NgtscCompilerHost` to be used for any TypeScript compilation, which uses a given file-system. All tests that interact with the file-system should be tested against each of the mock file-systems. A series of helpers have been provided to support such tests: * `runInEachFileSystem()` - wrap your tests in this helper to run all the wrapped tests in each of the mock file-systems. * `addTestFilesToFileSystem()` - use this to add files and their contents to the mock file system for testing. * `loadTestFilesFromDisk()` - use this to load a mirror image of files on disk into the in-memory mock file-system. * `loadFakeCore()` - use this to load a fake version of `@angular/core` into the mock file-system. All ngcc and ngtsc source and tests now use this virtual file-system setup. PR Close #30921
2019-06-06 15:22:32 -04:00
});
refactor(ivy): implement a virtual file-system layer in ngtsc + ngcc (#30921) To improve cross platform support, all file access (and path manipulation) is now done through a well known interface (`FileSystem`). For testing a number of `MockFileSystem` implementations are provided. These provide an in-memory file-system which emulates operating systems like OS/X, Unix and Windows. The current file system is always available via the static method, `FileSystem.getFileSystem()`. This is also used by a number of static methods on `AbsoluteFsPath` and `PathSegment`, to avoid having to pass `FileSystem` objects around all the time. The result of this is that one must be careful to ensure that the file-system has been initialized before using any of these static methods. To prevent this happening accidentally the current file system always starts out as an instance of `InvalidFileSystem`, which will throw an error if any of its methods are called. You can set the current file-system by calling `FileSystem.setFileSystem()`. During testing you can call the helper function `initMockFileSystem(os)` which takes a string name of the OS to emulate, and will also monkey-patch aspects of the TypeScript library to ensure that TS is also using the current file-system. Finally there is the `NgtscCompilerHost` to be used for any TypeScript compilation, which uses a given file-system. All tests that interact with the file-system should be tested against each of the mock file-systems. A series of helpers have been provided to support such tests: * `runInEachFileSystem()` - wrap your tests in this helper to run all the wrapped tests in each of the mock file-systems. * `addTestFilesToFileSystem()` - use this to add files and their contents to the mock file system for testing. * `loadTestFilesFromDisk()` - use this to load a mirror image of files on disk into the in-memory mock file-system. * `loadFakeCore()` - use this to load a fake version of `@angular/core` into the mock file-system. All ngcc and ngtsc source and tests now use this virtual file-system setup. PR Close #30921
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`)))
.toBeTrue();
refactor(ivy): implement a virtual file-system layer in ngtsc + ngcc (#30921) To improve cross platform support, all file access (and path manipulation) is now done through a well known interface (`FileSystem`). For testing a number of `MockFileSystem` implementations are provided. These provide an in-memory file-system which emulates operating systems like OS/X, Unix and Windows. The current file system is always available via the static method, `FileSystem.getFileSystem()`. This is also used by a number of static methods on `AbsoluteFsPath` and `PathSegment`, to avoid having to pass `FileSystem` objects around all the time. The result of this is that one must be careful to ensure that the file-system has been initialized before using any of these static methods. To prevent this happening accidentally the current file system always starts out as an instance of `InvalidFileSystem`, which will throw an error if any of its methods are called. You can set the current file-system by calling `FileSystem.setFileSystem()`. During testing you can call the helper function `initMockFileSystem(os)` which takes a string name of the OS to emulate, and will also monkey-patch aspects of the TypeScript library to ensure that TS is also using the current file-system. Finally there is the `NgtscCompilerHost` to be used for any TypeScript compilation, which uses a given file-system. All tests that interact with the file-system should be tested against each of the mock file-systems. A series of helpers have been provided to support such tests: * `runInEachFileSystem()` - wrap your tests in this helper to run all the wrapped tests in each of the mock file-systems. * `addTestFilesToFileSystem()` - use this to add files and their contents to the mock file system for testing. * `loadTestFilesFromDisk()` - use this to load a mirror image of files on disk into the in-memory mock file-system. * `loadFakeCore()` - use this to load a fake version of `@angular/core` into the mock file-system. All ngcc and ngtsc source and tests now use this virtual file-system setup. PR Close #30921
2019-06-06 15:22:32 -04:00
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);
});
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');
});
it('should update `package.json` deterministically (regardless of entry-point processing order)',
() => {
// Ensure formats are not marked as processed in `package.json` at the beginning.
let pkg = loadPackage('@angular/core');
expectNotToHaveProp(pkg, 'esm5_ivy_ngcc');
expectNotToHaveProp(pkg, 'fesm2015_ivy_ngcc');
expectNotToHaveProp(pkg, 'fesm5_ivy_ngcc');
expectNotToHaveProp(pkg, '__processed_by_ivy_ngcc__');
// Process `fesm2015` and update `package.json`.
pkg = processFormatAndUpdatePackageJson('fesm2015');
expectNotToHaveProp(pkg, 'esm5_ivy_ngcc');
expectToHaveProp(pkg, 'fesm2015_ivy_ngcc');
expectNotToHaveProp(pkg, 'fesm5_ivy_ngcc');
expectToHaveProp(pkg.__processed_by_ivy_ngcc__!, 'fesm2015');
// Process `fesm5` and update `package.json`.
pkg = processFormatAndUpdatePackageJson('fesm5');
expectNotToHaveProp(pkg, 'esm5_ivy_ngcc');
expectToHaveProp(pkg, 'fesm2015_ivy_ngcc');
expectToHaveProp(pkg, 'fesm5_ivy_ngcc');
expectToHaveProp(pkg.__processed_by_ivy_ngcc__!, 'fesm5');
// Process `esm5` and update `package.json`.
pkg = processFormatAndUpdatePackageJson('esm5');
expectToHaveProp(pkg, 'esm5_ivy_ngcc');
expectToHaveProp(pkg, 'fesm2015_ivy_ngcc');
expectToHaveProp(pkg, 'fesm5_ivy_ngcc');
expectToHaveProp(pkg.__processed_by_ivy_ngcc__!, 'esm5');
// Ensure the properties are in deterministic order (regardless of processing order).
const pkgKeys = stringifyKeys(pkg);
expect(pkgKeys).toContain('|esm5_ivy_ngcc|esm5|');
expect(pkgKeys).toContain('|fesm2015_ivy_ngcc|fesm2015|');
expect(pkgKeys).toContain('|fesm5_ivy_ngcc|fesm5|');
// NOTE:
// Along with the first format that is processed, the typings are processed as well.
// Also, once a property has been processed, alias properties as also marked as
// processed. Aliases properties are properties that point to the same entry-point file.
// For example:
// - `fesm2015` <=> `es2015`
// - `fesm5` <=> `module`
expect(stringifyKeys(pkg.__processed_by_ivy_ngcc__!))
.toBe('|es2015|esm5|fesm2015|fesm5|module|typings|');
// Helpers
function expectNotToHaveProp(obj: object, prop: string) {
expect(obj.hasOwnProperty(prop))
.toBe(
false,
`Expected object not to have property '${prop}': ${
JSON.stringify(obj, null, 2)}`);
}
function expectToHaveProp(obj: object, prop: string) {
expect(obj.hasOwnProperty(prop))
.toBe(
true,
`Expected object to have property '${prop}': ${JSON.stringify(obj, null, 2)}`);
}
function processFormatAndUpdatePackageJson(formatProp: string) {
mainNgcc({
basePath: '/node_modules/@angular/core',
createNewEntryPointFormats: true,
propertiesToConsider: [formatProp],
});
return loadPackage('@angular/core');
}
function stringifyKeys(obj: object) {
return `|${Object.keys(obj).join('|')}|`;
}
});
});
describe('with ignoreEntryPointManifest', () => {
it('should not read the entry-point manifest file', () => {
// Ensure there is a lock-file. Otherwise the manifest will not be written
fs.writeFile(_('/yarn.lock'), 'DUMMY YARN LOCK FILE');
// Populate the manifest file
mainNgcc(
{basePath: '/node_modules', propertiesToConsider: ['esm5'], logger: new MockLogger()});
// Check that common/testing ES5 was processed
let commonTesting =
JSON.parse(fs.readFile(_('/node_modules/@angular/common/testing/package.json')));
expect(hasBeenProcessed(commonTesting, 'esm5')).toBe(true);
expect(hasBeenProcessed(commonTesting, 'esm2015')).toBe(false);
// Modify the manifest to test that is has no effect
let manifest: EntryPointManifestFile =
JSON.parse(fs.readFile(_('/node_modules/__ngcc_entry_points__.json')));
manifest.entryPointPaths =
manifest.entryPointPaths.filter(paths => paths[1] !== '@angular/common/testing');
fs.writeFile(_('/node_modules/__ngcc_entry_points__.json'), JSON.stringify(manifest));
// Now run ngcc again ignoring this manifest but trying to process ES2015, which are not yet
// processed.
mainNgcc({
basePath: '/node_modules',
propertiesToConsider: ['esm2015'],
logger: new MockLogger(),
invalidateEntryPointManifest: true,
});
// Check that common/testing ES2015 is now processed, despite the manifest not listing it
commonTesting =
JSON.parse(fs.readFile(_('/node_modules/@angular/common/testing/package.json')));
expect(hasBeenProcessed(commonTesting, 'esm5')).toBe(true);
expect(hasBeenProcessed(commonTesting, 'esm2015')).toBe(true);
// Check that the newly computed manifest has written to disk, containing the path that we
// had removed earlier.
manifest = JSON.parse(fs.readFile(_('/node_modules/__ngcc_entry_points__.json')));
expect(manifest.entryPointPaths).toContain([
'@angular/common',
'@angular/common/testing',
[
_('/node_modules/@angular/core'), _('/node_modules/@angular/common'),
_('/node_modules/rxjs')
],
]);
});
});
describe('diagnostics', () => {
it('should fail with formatted diagnostics when an error diagnostic is produced, if targetEntryPointPath is provided',
() => {
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 {}
`,
},
]);
try {
mainNgcc({
basePath: '/node_modules',
targetEntryPointPath: 'fatal-error',
propertiesToConsider: ['es2015']
});
fail('should have thrown');
} catch (e) {
expect(e.message).toContain(
'Failed to compile entry-point fatal-error (es2015 as esm2015) due to compilation errors:');
expect(e.message).toContain('NG2001');
expect(e.message).toContain('component is missing a template');
}
});
it('should not fail but log an error with formatted diagnostics when an error diagnostic is produced, if targetEntryPoint is not provided and errorOnFailedEntryPoint is false',
() => {
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 {}`,
},
{
name: _('/node_modules/dependent/package.json'),
contents: '{"name": "dependent", "es2015": "./index.js", "typings": "./index.d.ts"}',
},
{name: _('/node_modules/dependent/index.metadata.json'), contents: 'DUMMY DATA'},
{
name: _('/node_modules/dependent/index.js'),
contents: `
import {Component} from '@angular/core';
import {FatalError} from 'fatal-error';
export class Dependent {}
Dependent.decorators = [
{type: Component, args: [{selector: 'dependent', template: ''}]}
];`,
},
{
name: _('/node_modules/dependent/index.d.ts'),
contents: `export declare class Dependent {}`,
},
{
name: _('/node_modules/independent/package.json'),
contents:
'{"name": "independent", "es2015": "./index.js", "typings": "./index.d.ts"}',
},
{name: _('/node_modules/independent/index.metadata.json'), contents: 'DUMMY DATA'},
{
name: _('/node_modules/independent/index.js'),
contents: `
import {Component} from '@angular/core';
export class Independent {}
Independent.decorators = [
{type: Component, args: [{selector: 'independent', template: ''}]}
];`,
},
{
name: _('/node_modules/independent/index.d.ts'),
contents: `export declare class Independent {}`,
},
]);
const logger = new MockLogger();
mainNgcc({
basePath: '/node_modules',
propertiesToConsider: ['es2015'],
errorOnFailedEntryPoint: false,
logger,
});
expect(logger.logs.error.length).toEqual(1);
const message = logger.logs.error[0][0];
expect(message).toContain(
'Failed to compile entry-point fatal-error (es2015 as esm2015) due to compilation errors:');
expect(message).toContain('NG2001');
expect(message).toContain('component is missing a template');
expect(hasBeenProcessed(loadPackage('fatal-error', _('/node_modules')), 'es2015'))
.toBe(false);
expect(hasBeenProcessed(loadPackage('dependent', _('/node_modules')), 'es2015'))
.toBe(false);
expect(hasBeenProcessed(loadPackage('independent', _('/node_modules')), 'es2015'))
.toBe(true);
});
});
refactor(ivy): implement a virtual file-system layer in ngtsc + ngcc (#30921) To improve cross platform support, all file access (and path manipulation) is now done through a well known interface (`FileSystem`). For testing a number of `MockFileSystem` implementations are provided. These provide an in-memory file-system which emulates operating systems like OS/X, Unix and Windows. The current file system is always available via the static method, `FileSystem.getFileSystem()`. This is also used by a number of static methods on `AbsoluteFsPath` and `PathSegment`, to avoid having to pass `FileSystem` objects around all the time. The result of this is that one must be careful to ensure that the file-system has been initialized before using any of these static methods. To prevent this happening accidentally the current file system always starts out as an instance of `InvalidFileSystem`, which will throw an error if any of its methods are called. You can set the current file-system by calling `FileSystem.setFileSystem()`. During testing you can call the helper function `initMockFileSystem(os)` which takes a string name of the OS to emulate, and will also monkey-patch aspects of the TypeScript library to ensure that TS is also using the current file-system. Finally there is the `NgtscCompilerHost` to be used for any TypeScript compilation, which uses a given file-system. All tests that interact with the file-system should be tested against each of the mock file-systems. A series of helpers have been provided to support such tests: * `runInEachFileSystem()` - wrap your tests in this helper to run all the wrapped tests in each of the mock file-systems. * `addTestFilesToFileSystem()` - use this to add files and their contents to the mock file system for testing. * `loadTestFilesFromDisk()` - use this to load a mirror image of files on disk into the in-memory mock file-system. * `loadFakeCore()` - use this to load a fake version of `@angular/core` into the mock file-system. All ngcc and ngtsc source and tests now use this virtual file-system setup. PR Close #30921
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');
});
refactor(ivy): implement a virtual file-system layer in ngtsc + ngcc (#30921) To improve cross platform support, all file access (and path manipulation) is now done through a well known interface (`FileSystem`). For testing a number of `MockFileSystem` implementations are provided. These provide an in-memory file-system which emulates operating systems like OS/X, Unix and Windows. The current file system is always available via the static method, `FileSystem.getFileSystem()`. This is also used by a number of static methods on `AbsoluteFsPath` and `PathSegment`, to avoid having to pass `FileSystem` objects around all the time. The result of this is that one must be careful to ensure that the file-system has been initialized before using any of these static methods. To prevent this happening accidentally the current file system always starts out as an instance of `InvalidFileSystem`, which will throw an error if any of its methods are called. You can set the current file-system by calling `FileSystem.setFileSystem()`. During testing you can call the helper function `initMockFileSystem(os)` which takes a string name of the OS to emulate, and will also monkey-patch aspects of the TypeScript library to ensure that TS is also using the current file-system. Finally there is the `NgtscCompilerHost` to be used for any TypeScript compilation, which uses a given file-system. All tests that interact with the file-system should be tested against each of the mock file-systems. A series of helpers have been provided to support such tests: * `runInEachFileSystem()` - wrap your tests in this helper to run all the wrapped tests in each of the mock file-systems. * `addTestFilesToFileSystem()` - use this to add files and their contents to the mock file system for testing. * `loadTestFilesFromDisk()` - use this to load a mirror image of files on disk into the in-memory mock file-system. * `loadFakeCore()` - use this to load a fake version of `@angular/core` into the mock file-system. All ngcc and ngtsc source and tests now use this virtual file-system setup. PR Close #30921
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,
refactor(ivy): implement a virtual file-system layer in ngtsc + ngcc (#30921) To improve cross platform support, all file access (and path manipulation) is now done through a well known interface (`FileSystem`). For testing a number of `MockFileSystem` implementations are provided. These provide an in-memory file-system which emulates operating systems like OS/X, Unix and Windows. The current file system is always available via the static method, `FileSystem.getFileSystem()`. This is also used by a number of static methods on `AbsoluteFsPath` and `PathSegment`, to avoid having to pass `FileSystem` objects around all the time. The result of this is that one must be careful to ensure that the file-system has been initialized before using any of these static methods. To prevent this happening accidentally the current file system always starts out as an instance of `InvalidFileSystem`, which will throw an error if any of its methods are called. You can set the current file-system by calling `FileSystem.setFileSystem()`. During testing you can call the helper function `initMockFileSystem(os)` which takes a string name of the OS to emulate, and will also monkey-patch aspects of the TypeScript library to ensure that TS is also using the current file-system. Finally there is the `NgtscCompilerHost` to be used for any TypeScript compilation, which uses a given file-system. All tests that interact with the file-system should be tested against each of the mock file-systems. A series of helpers have been provided to support such tests: * `runInEachFileSystem()` - wrap your tests in this helper to run all the wrapped tests in each of the mock file-systems. * `addTestFilesToFileSystem()` - use this to add files and their contents to the mock file system for testing. * `loadTestFilesFromDisk()` - use this to load a mirror image of files on disk into the in-memory mock file-system. * `loadFakeCore()` - use this to load a fake version of `@angular/core` into the mock file-system. All ngcc and ngtsc source and tests now use this virtual file-system setup. PR Close #30921
2019-06-06 15:22:32 -04:00
});
expect(logger.logs.info).toContain(['Compiling @angular/common/http : esm2015 as esm2015']);
});
});
refactor(ivy): implement a virtual file-system layer in ngtsc + ngcc (#30921) To improve cross platform support, all file access (and path manipulation) is now done through a well known interface (`FileSystem`). For testing a number of `MockFileSystem` implementations are provided. These provide an in-memory file-system which emulates operating systems like OS/X, Unix and Windows. The current file system is always available via the static method, `FileSystem.getFileSystem()`. This is also used by a number of static methods on `AbsoluteFsPath` and `PathSegment`, to avoid having to pass `FileSystem` objects around all the time. The result of this is that one must be careful to ensure that the file-system has been initialized before using any of these static methods. To prevent this happening accidentally the current file system always starts out as an instance of `InvalidFileSystem`, which will throw an error if any of its methods are called. You can set the current file-system by calling `FileSystem.setFileSystem()`. During testing you can call the helper function `initMockFileSystem(os)` which takes a string name of the OS to emulate, and will also monkey-patch aspects of the TypeScript library to ensure that TS is also using the current file-system. Finally there is the `NgtscCompilerHost` to be used for any TypeScript compilation, which uses a given file-system. All tests that interact with the file-system should be tested against each of the mock file-systems. A series of helpers have been provided to support such tests: * `runInEachFileSystem()` - wrap your tests in this helper to run all the wrapped tests in each of the mock file-systems. * `addTestFilesToFileSystem()` - use this to add files and their contents to the mock file system for testing. * `loadTestFilesFromDisk()` - use this to load a mirror image of files on disk into the in-memory mock file-system. * `loadFakeCore()` - use this to load a fake version of `@angular/core` into the mock file-system. All ngcc and ngtsc source and tests now use this virtual file-system setup. PR Close #30921
2019-06-06 15:22:32 -04:00
describe('with pathMappings', () => {
it('should infer the @app pathMapping from a local tsconfig.json path', () => {
fs.writeFile(
_('/tsconfig.json'),
JSON.stringify({compilerOptions: {paths: {'@app/*': ['dist/*']}, baseUrl: './'}}));
const logger = new MockLogger();
mainNgcc({basePath: '/dist', propertiesToConsider: ['es2015'], logger});
expect(loadPackage('local-package', _('/dist')).__processed_by_ivy_ngcc__).toEqual({
es2015: '0.0.0-PLACEHOLDER',
typings: '0.0.0-PLACEHOLDER',
});
expect(loadPackage('local-package-2', _('/dist')).__processed_by_ivy_ngcc__).toEqual({
es2015: '0.0.0-PLACEHOLDER',
typings: '0.0.0-PLACEHOLDER',
});
// The local-package-3 and local-package-4 will not be processed because there is no path
// mappings for `@x` and plain local imports.
expect(loadPackage('local-package-3', _('/dist')).__processed_by_ivy_ngcc__)
.toBeUndefined();
expect(logger.logs.debug).toContain([
`Invalid entry-point ${_('/dist/local-package-3')}.`,
'It is missing required dependencies:\n - @x/local-package'
]);
expect(loadPackage('local-package-4', _('/dist')).__processed_by_ivy_ngcc__)
.toBeUndefined();
expect(logger.logs.debug).toContain([
`Invalid entry-point ${_('/dist/local-package-4')}.`,
'It is missing required dependencies:\n - local-package'
]);
});
it('should read the @x pathMapping from a specified tsconfig.json path', () => {
fs.writeFile(
_('/tsconfig.app.json'),
JSON.stringify({compilerOptions: {paths: {'@x/*': ['dist/*']}, baseUrl: './'}}));
const logger = new MockLogger();
refactor(ivy): implement a virtual file-system layer in ngtsc + ngcc (#30921) To improve cross platform support, all file access (and path manipulation) is now done through a well known interface (`FileSystem`). For testing a number of `MockFileSystem` implementations are provided. These provide an in-memory file-system which emulates operating systems like OS/X, Unix and Windows. The current file system is always available via the static method, `FileSystem.getFileSystem()`. This is also used by a number of static methods on `AbsoluteFsPath` and `PathSegment`, to avoid having to pass `FileSystem` objects around all the time. The result of this is that one must be careful to ensure that the file-system has been initialized before using any of these static methods. To prevent this happening accidentally the current file system always starts out as an instance of `InvalidFileSystem`, which will throw an error if any of its methods are called. You can set the current file-system by calling `FileSystem.setFileSystem()`. During testing you can call the helper function `initMockFileSystem(os)` which takes a string name of the OS to emulate, and will also monkey-patch aspects of the TypeScript library to ensure that TS is also using the current file-system. Finally there is the `NgtscCompilerHost` to be used for any TypeScript compilation, which uses a given file-system. All tests that interact with the file-system should be tested against each of the mock file-systems. A series of helpers have been provided to support such tests: * `runInEachFileSystem()` - wrap your tests in this helper to run all the wrapped tests in each of the mock file-systems. * `addTestFilesToFileSystem()` - use this to add files and their contents to the mock file system for testing. * `loadTestFilesFromDisk()` - use this to load a mirror image of files on disk into the in-memory mock file-system. * `loadFakeCore()` - use this to load a fake version of `@angular/core` into the mock file-system. All ngcc and ngtsc source and tests now use this virtual file-system setup. PR Close #30921
2019-06-06 15:22:32 -04:00
mainNgcc({
basePath: '/dist',
refactor(ivy): implement a virtual file-system layer in ngtsc + ngcc (#30921) To improve cross platform support, all file access (and path manipulation) is now done through a well known interface (`FileSystem`). For testing a number of `MockFileSystem` implementations are provided. These provide an in-memory file-system which emulates operating systems like OS/X, Unix and Windows. The current file system is always available via the static method, `FileSystem.getFileSystem()`. This is also used by a number of static methods on `AbsoluteFsPath` and `PathSegment`, to avoid having to pass `FileSystem` objects around all the time. The result of this is that one must be careful to ensure that the file-system has been initialized before using any of these static methods. To prevent this happening accidentally the current file system always starts out as an instance of `InvalidFileSystem`, which will throw an error if any of its methods are called. You can set the current file-system by calling `FileSystem.setFileSystem()`. During testing you can call the helper function `initMockFileSystem(os)` which takes a string name of the OS to emulate, and will also monkey-patch aspects of the TypeScript library to ensure that TS is also using the current file-system. Finally there is the `NgtscCompilerHost` to be used for any TypeScript compilation, which uses a given file-system. All tests that interact with the file-system should be tested against each of the mock file-systems. A series of helpers have been provided to support such tests: * `runInEachFileSystem()` - wrap your tests in this helper to run all the wrapped tests in each of the mock file-systems. * `addTestFilesToFileSystem()` - use this to add files and their contents to the mock file system for testing. * `loadTestFilesFromDisk()` - use this to load a mirror image of files on disk into the in-memory mock file-system. * `loadFakeCore()` - use this to load a fake version of `@angular/core` into the mock file-system. All ngcc and ngtsc source and tests now use this virtual file-system setup. PR Close #30921
2019-06-06 15:22:32 -04:00
propertiesToConsider: ['es2015'],
tsConfigPath: _('/tsconfig.app.json'),
logger
refactor(ivy): implement a virtual file-system layer in ngtsc + ngcc (#30921) To improve cross platform support, all file access (and path manipulation) is now done through a well known interface (`FileSystem`). For testing a number of `MockFileSystem` implementations are provided. These provide an in-memory file-system which emulates operating systems like OS/X, Unix and Windows. The current file system is always available via the static method, `FileSystem.getFileSystem()`. This is also used by a number of static methods on `AbsoluteFsPath` and `PathSegment`, to avoid having to pass `FileSystem` objects around all the time. The result of this is that one must be careful to ensure that the file-system has been initialized before using any of these static methods. To prevent this happening accidentally the current file system always starts out as an instance of `InvalidFileSystem`, which will throw an error if any of its methods are called. You can set the current file-system by calling `FileSystem.setFileSystem()`. During testing you can call the helper function `initMockFileSystem(os)` which takes a string name of the OS to emulate, and will also monkey-patch aspects of the TypeScript library to ensure that TS is also using the current file-system. Finally there is the `NgtscCompilerHost` to be used for any TypeScript compilation, which uses a given file-system. All tests that interact with the file-system should be tested against each of the mock file-systems. A series of helpers have been provided to support such tests: * `runInEachFileSystem()` - wrap your tests in this helper to run all the wrapped tests in each of the mock file-systems. * `addTestFilesToFileSystem()` - use this to add files and their contents to the mock file system for testing. * `loadTestFilesFromDisk()` - use this to load a mirror image of files on disk into the in-memory mock file-system. * `loadFakeCore()` - use this to load a fake version of `@angular/core` into the mock file-system. All ngcc and ngtsc source and tests now use this virtual file-system setup. PR Close #30921
2019-06-06 15:22:32 -04:00
});
expect(loadPackage('local-package', _('/dist')).__processed_by_ivy_ngcc__).toEqual({
refactor(ivy): implement a virtual file-system layer in ngtsc + ngcc (#30921) To improve cross platform support, all file access (and path manipulation) is now done through a well known interface (`FileSystem`). For testing a number of `MockFileSystem` implementations are provided. These provide an in-memory file-system which emulates operating systems like OS/X, Unix and Windows. The current file system is always available via the static method, `FileSystem.getFileSystem()`. This is also used by a number of static methods on `AbsoluteFsPath` and `PathSegment`, to avoid having to pass `FileSystem` objects around all the time. The result of this is that one must be careful to ensure that the file-system has been initialized before using any of these static methods. To prevent this happening accidentally the current file system always starts out as an instance of `InvalidFileSystem`, which will throw an error if any of its methods are called. You can set the current file-system by calling `FileSystem.setFileSystem()`. During testing you can call the helper function `initMockFileSystem(os)` which takes a string name of the OS to emulate, and will also monkey-patch aspects of the TypeScript library to ensure that TS is also using the current file-system. Finally there is the `NgtscCompilerHost` to be used for any TypeScript compilation, which uses a given file-system. All tests that interact with the file-system should be tested against each of the mock file-systems. A series of helpers have been provided to support such tests: * `runInEachFileSystem()` - wrap your tests in this helper to run all the wrapped tests in each of the mock file-systems. * `addTestFilesToFileSystem()` - use this to add files and their contents to the mock file system for testing. * `loadTestFilesFromDisk()` - use this to load a mirror image of files on disk into the in-memory mock file-system. * `loadFakeCore()` - use this to load a fake version of `@angular/core` into the mock file-system. All ngcc and ngtsc source and tests now use this virtual file-system setup. PR Close #30921
2019-06-06 15:22:32 -04:00
es2015: '0.0.0-PLACEHOLDER',
typings: '0.0.0-PLACEHOLDER',
});
expect(loadPackage('local-package-3', _('/dist')).__processed_by_ivy_ngcc__).toEqual({
es2015: '0.0.0-PLACEHOLDER',
typings: '0.0.0-PLACEHOLDER',
});
// The local-package-2 and local-package-4 will not be processed because there is no path
// mappings for `@app` and plain local imports.
expect(loadPackage('local-package-2', _('/dist')).__processed_by_ivy_ngcc__)
.toBeUndefined();
expect(logger.logs.debug).toContain([
`Invalid entry-point ${_('/dist/local-package-2')}.`,
'It is missing required dependencies:\n - @app/local-package'
]);
expect(loadPackage('local-package-4', _('/dist')).__processed_by_ivy_ngcc__)
.toBeUndefined();
expect(logger.logs.debug).toContain([
`Invalid entry-point ${_('/dist/local-package-4')}.`,
'It is missing required dependencies:\n - local-package'
]);
});
it('should use the explicit `pathMappings`, ignoring the local tsconfig.json settings',
() => {
const logger = new MockLogger();
fs.writeFile(
_('/tsconfig.json'),
JSON.stringify({compilerOptions: {paths: {'@app/*': ['dist/*']}, baseUrl: './'}}));
mainNgcc({
basePath: '/node_modules',
propertiesToConsider: ['es2015'],
pathMappings: {paths: {'*': ['dist/*']}, baseUrl: '/'},
logger
});
expect(loadPackage('@angular/core').__processed_by_ivy_ngcc__).toEqual({
es2015: '0.0.0-PLACEHOLDER',
fesm2015: '0.0.0-PLACEHOLDER',
typings: '0.0.0-PLACEHOLDER',
});
expect(loadPackage('local-package', _('/dist')).__processed_by_ivy_ngcc__).toEqual({
es2015: '0.0.0-PLACEHOLDER',
typings: '0.0.0-PLACEHOLDER',
});
expect(loadPackage('local-package-4', _('/dist')).__processed_by_ivy_ngcc__).toEqual({
es2015: '0.0.0-PLACEHOLDER',
typings: '0.0.0-PLACEHOLDER',
});
// The local-package-2 and local-package-3 will not be processed because there is no path
// mappings for `@app` and `@x` local imports.
expect(loadPackage('local-package-2', _('/dist')).__processed_by_ivy_ngcc__)
.toBeUndefined();
expect(logger.logs.debug).toContain([
`Invalid entry-point ${_('/dist/local-package-2')}.`,
'It is missing required dependencies:\n - @app/local-package'
]);
expect(loadPackage('local-package-3', _('/dist')).__processed_by_ivy_ngcc__)
.toBeUndefined();
expect(logger.logs.debug).toContain([
`Invalid entry-point ${_('/dist/local-package-3')}.`,
'It is missing required dependencies:\n - @x/local-package'
]);
});
it('should not use pathMappings from a local tsconfig.json path if tsConfigPath is null',
() => {
const logger = new MockLogger();
fs.writeFile(
_('/tsconfig.json'),
JSON.stringify({compilerOptions: {paths: {'@app/*': ['dist/*']}, baseUrl: './'}}));
mainNgcc({
basePath: '/dist',
propertiesToConsider: ['es2015'],
tsConfigPath: null,
logger,
});
expect(loadPackage('local-package', _('/dist')).__processed_by_ivy_ngcc__).toEqual({
es2015: '0.0.0-PLACEHOLDER',
typings: '0.0.0-PLACEHOLDER',
});
// Since the tsconfig is not loaded, the `@app/local-package` import in `local-package-2`
// is not path-mapped correctly, and so it fails to be processed.
expect(loadPackage('local-package-2', _('/dist')).__processed_by_ivy_ngcc__)
.toBeUndefined();
expect(logger.logs.debug).toContain([
`Invalid entry-point ${_('/dist/local-package-2')}.`,
'It is missing required dependencies:\n - @app/local-package'
]);
});
});
describe('whitespace preservation', () => {
it('should default not to preserve whitespace', () => {
mainNgcc({basePath: '/dist', propertiesToConsider: ['es2015']});
expect(loadPackage('local-package', _('/dist')).__processed_by_ivy_ngcc__).toEqual({
es2015: '0.0.0-PLACEHOLDER',
typings: '0.0.0-PLACEHOLDER',
});
expect(fs.readFile(_('/dist/local-package/index.js')))
.toMatch(/ɵɵtext\(\d+, " Hello\\n"\);/);
});
it('should preserve whitespace if set in a loaded tsconfig.json', () => {
fs.writeFile(
_('/tsconfig.json'),
JSON.stringify({angularCompilerOptions: {preserveWhitespaces: true}}));
mainNgcc({basePath: '/dist', propertiesToConsider: ['es2015']});
expect(loadPackage('local-package', _('/dist')).__processed_by_ivy_ngcc__).toEqual({
es2015: '0.0.0-PLACEHOLDER',
typings: '0.0.0-PLACEHOLDER',
});
expect(fs.readFile(_('/dist/local-package/index.js')))
.toMatch(/ɵɵtext\(\d+, "\\n Hello\\n"\);/);
});
it('should not preserve whitespace if set to false in a loaded tsconfig.json', () => {
fs.writeFile(
_('/tsconfig.json'),
JSON.stringify({angularCompilerOptions: {preserveWhitespaces: false}}));
mainNgcc({basePath: '/dist', propertiesToConsider: ['es2015']});
expect(loadPackage('local-package', _('/dist')).__processed_by_ivy_ngcc__).toEqual({
es2015: '0.0.0-PLACEHOLDER',
typings: '0.0.0-PLACEHOLDER',
});
expect(fs.readFile(_('/dist/local-package/index.js')))
.toMatch(/ɵɵtext\(\d+, " Hello\\n"\);/);
});
});
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',
fesm2015: '0.0.0-PLACEHOLDER',
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',
fesm2015: '0.0.0-PLACEHOLDER',
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({
refactor(ivy): implement a virtual file-system layer in ngtsc + ngcc (#30921) To improve cross platform support, all file access (and path manipulation) is now done through a well known interface (`FileSystem`). For testing a number of `MockFileSystem` implementations are provided. These provide an in-memory file-system which emulates operating systems like OS/X, Unix and Windows. The current file system is always available via the static method, `FileSystem.getFileSystem()`. This is also used by a number of static methods on `AbsoluteFsPath` and `PathSegment`, to avoid having to pass `FileSystem` objects around all the time. The result of this is that one must be careful to ensure that the file-system has been initialized before using any of these static methods. To prevent this happening accidentally the current file system always starts out as an instance of `InvalidFileSystem`, which will throw an error if any of its methods are called. You can set the current file-system by calling `FileSystem.setFileSystem()`. During testing you can call the helper function `initMockFileSystem(os)` which takes a string name of the OS to emulate, and will also monkey-patch aspects of the TypeScript library to ensure that TS is also using the current file-system. Finally there is the `NgtscCompilerHost` to be used for any TypeScript compilation, which uses a given file-system. All tests that interact with the file-system should be tested against each of the mock file-systems. A series of helpers have been provided to support such tests: * `runInEachFileSystem()` - wrap your tests in this helper to run all the wrapped tests in each of the mock file-systems. * `addTestFilesToFileSystem()` - use this to add files and their contents to the mock file system for testing. * `loadTestFilesFromDisk()` - use this to load a mirror image of files on disk into the in-memory mock file-system. * `loadFakeCore()` - use this to load a fake version of `@angular/core` into the mock file-system. All ngcc and ngtsc source and tests now use this virtual file-system setup. PR Close #30921
2019-06-06 15:22:32 -04:00
es2015: '0.0.0-PLACEHOLDER',
fesm2015: '0.0.0-PLACEHOLDER',
refactor(ivy): implement a virtual file-system layer in ngtsc + ngcc (#30921) To improve cross platform support, all file access (and path manipulation) is now done through a well known interface (`FileSystem`). For testing a number of `MockFileSystem` implementations are provided. These provide an in-memory file-system which emulates operating systems like OS/X, Unix and Windows. The current file system is always available via the static method, `FileSystem.getFileSystem()`. This is also used by a number of static methods on `AbsoluteFsPath` and `PathSegment`, to avoid having to pass `FileSystem` objects around all the time. The result of this is that one must be careful to ensure that the file-system has been initialized before using any of these static methods. To prevent this happening accidentally the current file system always starts out as an instance of `InvalidFileSystem`, which will throw an error if any of its methods are called. You can set the current file-system by calling `FileSystem.setFileSystem()`. During testing you can call the helper function `initMockFileSystem(os)` which takes a string name of the OS to emulate, and will also monkey-patch aspects of the TypeScript library to ensure that TS is also using the current file-system. Finally there is the `NgtscCompilerHost` to be used for any TypeScript compilation, which uses a given file-system. All tests that interact with the file-system should be tested against each of the mock file-systems. A series of helpers have been provided to support such tests: * `runInEachFileSystem()` - wrap your tests in this helper to run all the wrapped tests in each of the mock file-systems. * `addTestFilesToFileSystem()` - use this to add files and their contents to the mock file system for testing. * `loadTestFilesFromDisk()` - use this to load a mirror image of files on disk into the in-memory mock file-system. * `loadFakeCore()` - use this to load a fake version of `@angular/core` into the mock file-system. All ngcc and ngtsc source and tests now use this virtual file-system setup. PR Close #30921
2019-06-06 15:22:32 -04:00
typings: '0.0.0-PLACEHOLDER',
});
});
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',
});
});
});
feat(ngcc): add a migration for undecorated child classes (#33362) In Angular View Engine, there are two kinds of decorator inheritance: 1) both the parent and child classes have decorators This case is supported by InheritDefinitionFeature, which merges some fields of the definitions (such as the inputs or queries). 2) only the parent class has a decorator If the child class is missing a decorator, the compiler effectively behaves as if the parent class' decorator is applied to the child class as well. This is the "undecorated child" scenario, and this commit adds a migration to ngcc to support this pattern in Ivy. This migration has 2 phases. First, the NgModules of the application are scanned for classes in 'declarations' which are missing decorators, but whose base classes do have decorators. These classes are the undecorated children. This scan is performed recursively, so even if a declared class has a base class that itself inherits a decorator, this case is handled. Next, a synthetic decorator (either @Component or @Directive) is created on the child class. This decorator copies some critical information such as 'selector' and 'exportAs', as well as supports any decorated fields (@Input, etc). A flag is passed to the decorator compiler which causes a special feature `CopyDefinitionFeature` to be included on the compiled definition. This feature copies at runtime the remaining aspects of the parent definition which `InheritDefinitionFeature` does not handle, completing the "full" inheritance of the child class' decorator from its parent class. PR Close #33362
2019-10-23 15:00:49 -04:00
describe('undecorated child class migration', () => {
it('should generate a directive definition with CopyDefinitionFeature for an undecorated child directive',
() => {
compileIntoFlatEs5Package('test-package', {
'/index.ts': `
feat(ngcc): add a migration for undecorated child classes (#33362) In Angular View Engine, there are two kinds of decorator inheritance: 1) both the parent and child classes have decorators This case is supported by InheritDefinitionFeature, which merges some fields of the definitions (such as the inputs or queries). 2) only the parent class has a decorator If the child class is missing a decorator, the compiler effectively behaves as if the parent class' decorator is applied to the child class as well. This is the "undecorated child" scenario, and this commit adds a migration to ngcc to support this pattern in Ivy. This migration has 2 phases. First, the NgModules of the application are scanned for classes in 'declarations' which are missing decorators, but whose base classes do have decorators. These classes are the undecorated children. This scan is performed recursively, so even if a declared class has a base class that itself inherits a decorator, this case is handled. Next, a synthetic decorator (either @Component or @Directive) is created on the child class. This decorator copies some critical information such as 'selector' and 'exportAs', as well as supports any decorated fields (@Input, etc). A flag is passed to the decorator compiler which causes a special feature `CopyDefinitionFeature` to be included on the compiled definition. This feature copies at runtime the remaining aspects of the parent definition which `InheritDefinitionFeature` does not handle, completing the "full" inheritance of the child class' decorator from its parent class. PR Close #33362
2019-10-23 15:00:49 -04:00
import {Directive, NgModule} from '@angular/core';
@Directive({
selector: '[base]',
exportAs: 'base1, base2',
feat(ngcc): add a migration for undecorated child classes (#33362) In Angular View Engine, there are two kinds of decorator inheritance: 1) both the parent and child classes have decorators This case is supported by InheritDefinitionFeature, which merges some fields of the definitions (such as the inputs or queries). 2) only the parent class has a decorator If the child class is missing a decorator, the compiler effectively behaves as if the parent class' decorator is applied to the child class as well. This is the "undecorated child" scenario, and this commit adds a migration to ngcc to support this pattern in Ivy. This migration has 2 phases. First, the NgModules of the application are scanned for classes in 'declarations' which are missing decorators, but whose base classes do have decorators. These classes are the undecorated children. This scan is performed recursively, so even if a declared class has a base class that itself inherits a decorator, this case is handled. Next, a synthetic decorator (either @Component or @Directive) is created on the child class. This decorator copies some critical information such as 'selector' and 'exportAs', as well as supports any decorated fields (@Input, etc). A flag is passed to the decorator compiler which causes a special feature `CopyDefinitionFeature` to be included on the compiled definition. This feature copies at runtime the remaining aspects of the parent definition which `InheritDefinitionFeature` does not handle, completing the "full" inheritance of the child class' decorator from its parent class. PR Close #33362
2019-10-23 15:00:49 -04:00
})
export class BaseDir {}
export class DerivedDir extends BaseDir {}
@NgModule({
declarations: [DerivedDir],
})
export class Module {}
`,
});
mainNgcc({
basePath: '/node_modules',
targetEntryPointPath: 'test-package',
propertiesToConsider: ['module'],
feat(ngcc): add a migration for undecorated child classes (#33362) In Angular View Engine, there are two kinds of decorator inheritance: 1) both the parent and child classes have decorators This case is supported by InheritDefinitionFeature, which merges some fields of the definitions (such as the inputs or queries). 2) only the parent class has a decorator If the child class is missing a decorator, the compiler effectively behaves as if the parent class' decorator is applied to the child class as well. This is the "undecorated child" scenario, and this commit adds a migration to ngcc to support this pattern in Ivy. This migration has 2 phases. First, the NgModules of the application are scanned for classes in 'declarations' which are missing decorators, but whose base classes do have decorators. These classes are the undecorated children. This scan is performed recursively, so even if a declared class has a base class that itself inherits a decorator, this case is handled. Next, a synthetic decorator (either @Component or @Directive) is created on the child class. This decorator copies some critical information such as 'selector' and 'exportAs', as well as supports any decorated fields (@Input, etc). A flag is passed to the decorator compiler which causes a special feature `CopyDefinitionFeature` to be included on the compiled definition. This feature copies at runtime the remaining aspects of the parent definition which `InheritDefinitionFeature` does not handle, completing the "full" inheritance of the child class' decorator from its parent class. PR Close #33362
2019-10-23 15:00:49 -04:00
});
const jsContents = fs.readFile(_(`/node_modules/test-package/index.js`));
expect(jsContents)
.toContain(
'DerivedDir.ɵdir = ɵngcc0.ɵɵdefineDirective({ type: DerivedDir, ' +
'selectors: [["", "base", ""]], exportAs: ["base1", "base2"], ' +
feat(ngcc): add a migration for undecorated child classes (#33362) In Angular View Engine, there are two kinds of decorator inheritance: 1) both the parent and child classes have decorators This case is supported by InheritDefinitionFeature, which merges some fields of the definitions (such as the inputs or queries). 2) only the parent class has a decorator If the child class is missing a decorator, the compiler effectively behaves as if the parent class' decorator is applied to the child class as well. This is the "undecorated child" scenario, and this commit adds a migration to ngcc to support this pattern in Ivy. This migration has 2 phases. First, the NgModules of the application are scanned for classes in 'declarations' which are missing decorators, but whose base classes do have decorators. These classes are the undecorated children. This scan is performed recursively, so even if a declared class has a base class that itself inherits a decorator, this case is handled. Next, a synthetic decorator (either @Component or @Directive) is created on the child class. This decorator copies some critical information such as 'selector' and 'exportAs', as well as supports any decorated fields (@Input, etc). A flag is passed to the decorator compiler which causes a special feature `CopyDefinitionFeature` to be included on the compiled definition. This feature copies at runtime the remaining aspects of the parent definition which `InheritDefinitionFeature` does not handle, completing the "full" inheritance of the child class' decorator from its parent class. PR Close #33362
2019-10-23 15:00:49 -04:00
'features: [ɵngcc0.ɵɵInheritDefinitionFeature, ɵngcc0.ɵɵCopyDefinitionFeature] });');
const dtsContents = fs.readFile(_(`/node_modules/test-package/index.d.ts`));
expect(dtsContents)
.toContain(
'static ɵdir: ɵngcc0.ɵɵDirectiveDefWithMeta<DerivedDir, "[base]", ["base1", "base2"], {}, {}, never>;');
feat(ngcc): add a migration for undecorated child classes (#33362) In Angular View Engine, there are two kinds of decorator inheritance: 1) both the parent and child classes have decorators This case is supported by InheritDefinitionFeature, which merges some fields of the definitions (such as the inputs or queries). 2) only the parent class has a decorator If the child class is missing a decorator, the compiler effectively behaves as if the parent class' decorator is applied to the child class as well. This is the "undecorated child" scenario, and this commit adds a migration to ngcc to support this pattern in Ivy. This migration has 2 phases. First, the NgModules of the application are scanned for classes in 'declarations' which are missing decorators, but whose base classes do have decorators. These classes are the undecorated children. This scan is performed recursively, so even if a declared class has a base class that itself inherits a decorator, this case is handled. Next, a synthetic decorator (either @Component or @Directive) is created on the child class. This decorator copies some critical information such as 'selector' and 'exportAs', as well as supports any decorated fields (@Input, etc). A flag is passed to the decorator compiler which causes a special feature `CopyDefinitionFeature` to be included on the compiled definition. This feature copies at runtime the remaining aspects of the parent definition which `InheritDefinitionFeature` does not handle, completing the "full" inheritance of the child class' decorator from its parent class. PR Close #33362
2019-10-23 15:00:49 -04:00
});
it('should generate a component definition with CopyDefinitionFeature for an undecorated child component',
() => {
compileIntoFlatEs5Package('test-package', {
'/index.ts': `
feat(ngcc): add a migration for undecorated child classes (#33362) In Angular View Engine, there are two kinds of decorator inheritance: 1) both the parent and child classes have decorators This case is supported by InheritDefinitionFeature, which merges some fields of the definitions (such as the inputs or queries). 2) only the parent class has a decorator If the child class is missing a decorator, the compiler effectively behaves as if the parent class' decorator is applied to the child class as well. This is the "undecorated child" scenario, and this commit adds a migration to ngcc to support this pattern in Ivy. This migration has 2 phases. First, the NgModules of the application are scanned for classes in 'declarations' which are missing decorators, but whose base classes do have decorators. These classes are the undecorated children. This scan is performed recursively, so even if a declared class has a base class that itself inherits a decorator, this case is handled. Next, a synthetic decorator (either @Component or @Directive) is created on the child class. This decorator copies some critical information such as 'selector' and 'exportAs', as well as supports any decorated fields (@Input, etc). A flag is passed to the decorator compiler which causes a special feature `CopyDefinitionFeature` to be included on the compiled definition. This feature copies at runtime the remaining aspects of the parent definition which `InheritDefinitionFeature` does not handle, completing the "full" inheritance of the child class' decorator from its parent class. PR Close #33362
2019-10-23 15:00:49 -04:00
import {Component, NgModule} from '@angular/core';
@Component({
selector: '[base]',
template: '<span>This is the base template</span>',
})
export class BaseCmp {}
export class DerivedCmp extends BaseCmp {}
@NgModule({
declarations: [DerivedCmp],
})
export class Module {}
`,
});
mainNgcc({
basePath: '/node_modules',
targetEntryPointPath: 'test-package',
propertiesToConsider: ['module'],
feat(ngcc): add a migration for undecorated child classes (#33362) In Angular View Engine, there are two kinds of decorator inheritance: 1) both the parent and child classes have decorators This case is supported by InheritDefinitionFeature, which merges some fields of the definitions (such as the inputs or queries). 2) only the parent class has a decorator If the child class is missing a decorator, the compiler effectively behaves as if the parent class' decorator is applied to the child class as well. This is the "undecorated child" scenario, and this commit adds a migration to ngcc to support this pattern in Ivy. This migration has 2 phases. First, the NgModules of the application are scanned for classes in 'declarations' which are missing decorators, but whose base classes do have decorators. These classes are the undecorated children. This scan is performed recursively, so even if a declared class has a base class that itself inherits a decorator, this case is handled. Next, a synthetic decorator (either @Component or @Directive) is created on the child class. This decorator copies some critical information such as 'selector' and 'exportAs', as well as supports any decorated fields (@Input, etc). A flag is passed to the decorator compiler which causes a special feature `CopyDefinitionFeature` to be included on the compiled definition. This feature copies at runtime the remaining aspects of the parent definition which `InheritDefinitionFeature` does not handle, completing the "full" inheritance of the child class' decorator from its parent class. PR Close #33362
2019-10-23 15:00:49 -04:00
});
const jsContents = fs.readFile(_(`/node_modules/test-package/index.js`));
expect(jsContents).toContain('DerivedCmp.ɵcmp = ɵngcc0.ɵɵdefineComponent');
expect(jsContents)
.toContain(
'features: [ɵngcc0.ɵɵInheritDefinitionFeature, ɵngcc0.ɵɵCopyDefinitionFeature]');
const dtsContents = fs.readFile(_(`/node_modules/test-package/index.d.ts`));
expect(dtsContents)
.toContain(
feat(compiler): add dependency info and ng-content selectors to metadata (#35695) This commit augments the `FactoryDef` declaration of Angular decorated classes to contain information about the parameter decorators used in the constructor. If no constructor is present, or none of the parameters have any Angular decorators, then this will be represented using the `null` type. Otherwise, a tuple type is used where the entry at index `i` corresponds with parameter `i`. Each tuple entry can be one of two types: 1. If the associated parameter does not have any Angular decorators, the tuple entry will be the `null` type. 2. Otherwise, a type literal is used that may declare at least one of the following properties: - "attribute": if `@Attribute` is present. The injected attribute's name is used as string literal type, or the `unknown` type if the attribute name is not a string literal. - "self": if `@Self` is present, always of type `true`. - "skipSelf": if `@SkipSelf` is present, always of type `true`. - "host": if `@Host` is present, always of type `true`. - "optional": if `@Optional` is present, always of type `true`. A property is only present if the corresponding decorator is used. Note that the `@Inject` decorator is currently not included, as it's non-trivial to properly convert the token's value expression to a type that is valid in a declaration file. Additionally, the `ComponentDefWithMeta` declaration that is created for Angular components has been extended to include all selectors on `ng-content` elements within the component's template. This additional metadata is useful for tooling such as the Angular Language Service, as it provides the ability to offer suggestions for directives/components defined in libraries. At the moment, such tooling extracts the necessary information from the _metadata.json_ manifest file as generated by ngc, however this metadata representation is being replaced by the information emitted into the declaration files. Resolves FW-1870 PR Close #35695
2020-02-26 16:05:44 -05:00
'static ɵcmp: ɵngcc0.ɵɵComponentDefWithMeta<DerivedCmp, "[base]", never, {}, {}, never, never>;');
feat(ngcc): add a migration for undecorated child classes (#33362) In Angular View Engine, there are two kinds of decorator inheritance: 1) both the parent and child classes have decorators This case is supported by InheritDefinitionFeature, which merges some fields of the definitions (such as the inputs or queries). 2) only the parent class has a decorator If the child class is missing a decorator, the compiler effectively behaves as if the parent class' decorator is applied to the child class as well. This is the "undecorated child" scenario, and this commit adds a migration to ngcc to support this pattern in Ivy. This migration has 2 phases. First, the NgModules of the application are scanned for classes in 'declarations' which are missing decorators, but whose base classes do have decorators. These classes are the undecorated children. This scan is performed recursively, so even if a declared class has a base class that itself inherits a decorator, this case is handled. Next, a synthetic decorator (either @Component or @Directive) is created on the child class. This decorator copies some critical information such as 'selector' and 'exportAs', as well as supports any decorated fields (@Input, etc). A flag is passed to the decorator compiler which causes a special feature `CopyDefinitionFeature` to be included on the compiled definition. This feature copies at runtime the remaining aspects of the parent definition which `InheritDefinitionFeature` does not handle, completing the "full" inheritance of the child class' decorator from its parent class. PR Close #33362
2019-10-23 15:00:49 -04:00
});
it('should generate directive definitions with CopyDefinitionFeature for undecorated child directives in a long inheritance chain',
() => {
compileIntoFlatEs5Package('test-package', {
'/index.ts': `
feat(ngcc): add a migration for undecorated child classes (#33362) In Angular View Engine, there are two kinds of decorator inheritance: 1) both the parent and child classes have decorators This case is supported by InheritDefinitionFeature, which merges some fields of the definitions (such as the inputs or queries). 2) only the parent class has a decorator If the child class is missing a decorator, the compiler effectively behaves as if the parent class' decorator is applied to the child class as well. This is the "undecorated child" scenario, and this commit adds a migration to ngcc to support this pattern in Ivy. This migration has 2 phases. First, the NgModules of the application are scanned for classes in 'declarations' which are missing decorators, but whose base classes do have decorators. These classes are the undecorated children. This scan is performed recursively, so even if a declared class has a base class that itself inherits a decorator, this case is handled. Next, a synthetic decorator (either @Component or @Directive) is created on the child class. This decorator copies some critical information such as 'selector' and 'exportAs', as well as supports any decorated fields (@Input, etc). A flag is passed to the decorator compiler which causes a special feature `CopyDefinitionFeature` to be included on the compiled definition. This feature copies at runtime the remaining aspects of the parent definition which `InheritDefinitionFeature` does not handle, completing the "full" inheritance of the child class' decorator from its parent class. PR Close #33362
2019-10-23 15:00:49 -04:00
import {Directive, NgModule} from '@angular/core';
@Directive({
selector: '[base]',
})
export class BaseDir {}
export class DerivedDir1 extends BaseDir {}
export class DerivedDir2 extends DerivedDir1 {}
export class DerivedDir3 extends DerivedDir2 {}
@NgModule({
declarations: [DerivedDir3],
})
export class Module {}
`,
});
mainNgcc({
basePath: '/node_modules',
targetEntryPointPath: 'test-package',
propertiesToConsider: ['module'],
feat(ngcc): add a migration for undecorated child classes (#33362) In Angular View Engine, there are two kinds of decorator inheritance: 1) both the parent and child classes have decorators This case is supported by InheritDefinitionFeature, which merges some fields of the definitions (such as the inputs or queries). 2) only the parent class has a decorator If the child class is missing a decorator, the compiler effectively behaves as if the parent class' decorator is applied to the child class as well. This is the "undecorated child" scenario, and this commit adds a migration to ngcc to support this pattern in Ivy. This migration has 2 phases. First, the NgModules of the application are scanned for classes in 'declarations' which are missing decorators, but whose base classes do have decorators. These classes are the undecorated children. This scan is performed recursively, so even if a declared class has a base class that itself inherits a decorator, this case is handled. Next, a synthetic decorator (either @Component or @Directive) is created on the child class. This decorator copies some critical information such as 'selector' and 'exportAs', as well as supports any decorated fields (@Input, etc). A flag is passed to the decorator compiler which causes a special feature `CopyDefinitionFeature` to be included on the compiled definition. This feature copies at runtime the remaining aspects of the parent definition which `InheritDefinitionFeature` does not handle, completing the "full" inheritance of the child class' decorator from its parent class. PR Close #33362
2019-10-23 15:00:49 -04:00
});
const dtsContents = fs.readFile(_(`/node_modules/test-package/index.d.ts`));
expect(dtsContents)
.toContain(
'static ɵdir: ɵngcc0.ɵɵDirectiveDefWithMeta<DerivedDir1, "[base]", never, {}, {}, never>;');
expect(dtsContents)
.toContain(
'static ɵdir: ɵngcc0.ɵɵDirectiveDefWithMeta<DerivedDir2, "[base]", never, {}, {}, never>;');
expect(dtsContents)
.toContain(
'static ɵdir: ɵngcc0.ɵɵDirectiveDefWithMeta<DerivedDir3, "[base]", never, {}, {}, never>;');
});
});
describe('aliasing re-exports in commonjs', () => {
it('should add re-exports to commonjs files', () => {
loadTestFiles([
{
name: _('/node_modules/test-package/package.json'),
contents: `
{
"name": "test-package",
"main": "./index.js",
"typings": "./index.d.ts"
}
`,
},
{
name: _('/node_modules/test-package/index.js'),
contents: `
var __export = null;
__export(require("./module"));
`,
},
{
name: _('/node_modules/test-package/index.d.ts'),
contents: `
export * from "./module";
`,
},
{
name: _('/node_modules/test-package/index.metadata.json'),
contents: '{}',
},
{
name: _('/node_modules/test-package/module.js'),
contents: `
var __decorate = null;
var core_1 = require("@angular/core");
var directive_1 = require("./directive");
var LocalDir = /** @class */ (function () {
function LocalDir() {
}
LocalDir = __decorate([
core_1.Directive({
selector: '[local]',
})
], LocalDir);
return LocalDir;
}());
var FooModule = /** @class */ (function () {
function FooModule() {
}
FooModule = __decorate([
core_1.NgModule({
declarations: [directive_1.Foo, LocalDir],
exports: [directive_1.Foo, LocalDir],
})
], FooModule);
return FooModule;
}());
exports.LocalDir = LocalDir;
exports.FooModule = FooModule;
`,
},
{
name: _('/node_modules/test-package/module.d.ts'),
contents: `
export declare class LocalDir {}
export declare class FooModule {}
`,
},
{
name: _('/node_modules/test-package/module.metadata.json'),
contents: '{}',
},
{
name: _('/node_modules/test-package/directive.js'),
contents: `
var __decorate = null;
var core_1 = require("@angular/core");
var Foo = /** @class */ (function () {
function Foo() {
}
Foo = __decorate([
core_1.Directive({
selector: '[foo]',
})
], Foo);
return Foo;
}());
exports.Foo = Foo;
`,
},
{
name: _('/node_modules/test-package/directive.d.ts'),
contents: `
export declare class Foo {}
`,
},
{
name: _('/node_modules/test-package/directive.metadata.json'),
contents: '{}',
},
{
name: _('/ngcc.config.js'),
contents: `
module.exports = {
packages: {
'test-package': {
entryPoints: {
'.': {
generateDeepReexports: true
},
},
},
},
};
`,
}
]);
mainNgcc({
basePath: '/node_modules',
targetEntryPointPath: 'test-package',
propertiesToConsider: ['main'],
});
expect(loadPackage('test-package').__processed_by_ivy_ngcc__).toEqual({
main: '0.0.0-PLACEHOLDER',
typings: '0.0.0-PLACEHOLDER',
});
const jsContents = fs.readFile(_(`/node_modules/test-package/module.js`));
const dtsContents = fs.readFile(_(`/node_modules/test-package/module.d.ts`));
expect(jsContents).toContain(`var ɵngcc1 = require('./directive');`);
expect(jsContents).toContain('exports.ɵngExportɵFooModuleɵFoo = ɵngcc1.Foo;');
expect(dtsContents)
.toContain(`export {Foo as ɵngExportɵFooModuleɵFoo} from './directive';`);
expect(dtsContents.match(/ɵngExportɵFooModuleɵFoo/g)!.length).toBe(1);
expect(dtsContents).not.toContain(`ɵngExportɵFooModuleɵLocalDir`);
});
});
describe('legacy message ids', () => {
it('should render legacy message ids when compiling i18n tags in component templates', () => {
compileIntoApf('test-package', {
'/index.ts': `
import {Component} from '@angular/core';
@Component({
selector: '[base]',
template: '<div i18n>Some message</div>'
})
export class AppComponent {}
`,
});
mainNgcc({
basePath: '/node_modules',
targetEntryPointPath: 'test-package',
propertiesToConsider: ['esm2015'],
});
const jsContents = fs.readFile(_(`/node_modules/test-package/esm2015/src/index.js`));
expect(jsContents)
.toContain(
'$localize `:␟888aea0e46f7e9dddbd95fc1ef380a3ff70ada9d␟1812794354835616626:Some message');
});
it('should not render legacy message ids when compiling i18n tags in component templates if `enableI18nLegacyMessageIdFormat` is false',
() => {
compileIntoApf('test-package', {
'/index.ts': `
import {Component} from '@angular/core';
@Component({
selector: '[base]',
template: '<div i18n>Some message</div>'
})
export class AppComponent {}
`,
});
mainNgcc({
basePath: '/node_modules',
targetEntryPointPath: 'test-package',
propertiesToConsider: ['esm2015'],
enableI18nLegacyMessageIdFormat: false,
});
const jsContents = fs.readFile(_(`/node_modules/test-package/esm2015/src/index.js`));
expect(jsContents).not.toContain('␟888aea0e46f7e9dddbd95fc1ef380a3ff70ada9d');
expect(jsContents).not.toContain('␟1812794354835616626');
expect(jsContents).not.toContain('␟');
});
});
refactor(ivy): implement a virtual file-system layer in ngtsc + ngcc (#30921) To improve cross platform support, all file access (and path manipulation) is now done through a well known interface (`FileSystem`). For testing a number of `MockFileSystem` implementations are provided. These provide an in-memory file-system which emulates operating systems like OS/X, Unix and Windows. The current file system is always available via the static method, `FileSystem.getFileSystem()`. This is also used by a number of static methods on `AbsoluteFsPath` and `PathSegment`, to avoid having to pass `FileSystem` objects around all the time. The result of this is that one must be careful to ensure that the file-system has been initialized before using any of these static methods. To prevent this happening accidentally the current file system always starts out as an instance of `InvalidFileSystem`, which will throw an error if any of its methods are called. You can set the current file-system by calling `FileSystem.setFileSystem()`. During testing you can call the helper function `initMockFileSystem(os)` which takes a string name of the OS to emulate, and will also monkey-patch aspects of the TypeScript library to ensure that TS is also using the current file-system. Finally there is the `NgtscCompilerHost` to be used for any TypeScript compilation, which uses a given file-system. All tests that interact with the file-system should be tested against each of the mock file-systems. A series of helpers have been provided to support such tests: * `runInEachFileSystem()` - wrap your tests in this helper to run all the wrapped tests in each of the mock file-systems. * `addTestFilesToFileSystem()` - use this to add files and their contents to the mock file system for testing. * `loadTestFilesFromDisk()` - use this to load a mirror image of files on disk into the in-memory mock file-system. * `loadFakeCore()` - use this to load a fake version of `@angular/core` into the mock file-system. All ngcc and ngtsc source and tests now use this virtual file-system setup. PR Close #30921
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')));
}
refactor(ivy): implement a virtual file-system layer in ngtsc + ngcc (#30921) To improve cross platform support, all file access (and path manipulation) is now done through a well known interface (`FileSystem`). For testing a number of `MockFileSystem` implementations are provided. These provide an in-memory file-system which emulates operating systems like OS/X, Unix and Windows. The current file system is always available via the static method, `FileSystem.getFileSystem()`. This is also used by a number of static methods on `AbsoluteFsPath` and `PathSegment`, to avoid having to pass `FileSystem` objects around all the time. The result of this is that one must be careful to ensure that the file-system has been initialized before using any of these static methods. To prevent this happening accidentally the current file system always starts out as an instance of `InvalidFileSystem`, which will throw an error if any of its methods are called. You can set the current file-system by calling `FileSystem.setFileSystem()`. During testing you can call the helper function `initMockFileSystem(os)` which takes a string name of the OS to emulate, and will also monkey-patch aspects of the TypeScript library to ensure that TS is also using the current file-system. Finally there is the `NgtscCompilerHost` to be used for any TypeScript compilation, which uses a given file-system. All tests that interact with the file-system should be tested against each of the mock file-systems. A series of helpers have been provided to support such tests: * `runInEachFileSystem()` - wrap your tests in this helper to run all the wrapped tests in each of the mock file-systems. * `addTestFilesToFileSystem()` - use this to add files and their contents to the mock file system for testing. * `loadTestFilesFromDisk()` - use this to load a mirror image of files on disk into the in-memory mock file-system. * `loadFakeCore()` - use this to load a fake version of `@angular/core` into the mock file-system. All ngcc and ngtsc source and tests now use this virtual file-system setup. PR Close #30921
2019-06-06 15:22:32 -04:00
function initMockFileSystem(fs: FileSystem, testFiles: Folder) {
if (fs instanceof MockFileSystem) {
fs.init(testFiles);
fs.ensureDir(fs.dirname(getLockFilePath(fs)));
refactor(ivy): implement a virtual file-system layer in ngtsc + ngcc (#30921) To improve cross platform support, all file access (and path manipulation) is now done through a well known interface (`FileSystem`). For testing a number of `MockFileSystem` implementations are provided. These provide an in-memory file-system which emulates operating systems like OS/X, Unix and Windows. The current file system is always available via the static method, `FileSystem.getFileSystem()`. This is also used by a number of static methods on `AbsoluteFsPath` and `PathSegment`, to avoid having to pass `FileSystem` objects around all the time. The result of this is that one must be careful to ensure that the file-system has been initialized before using any of these static methods. To prevent this happening accidentally the current file system always starts out as an instance of `InvalidFileSystem`, which will throw an error if any of its methods are called. You can set the current file-system by calling `FileSystem.setFileSystem()`. During testing you can call the helper function `initMockFileSystem(os)` which takes a string name of the OS to emulate, and will also monkey-patch aspects of the TypeScript library to ensure that TS is also using the current file-system. Finally there is the `NgtscCompilerHost` to be used for any TypeScript compilation, which uses a given file-system. All tests that interact with the file-system should be tested against each of the mock file-systems. A series of helpers have been provided to support such tests: * `runInEachFileSystem()` - wrap your tests in this helper to run all the wrapped tests in each of the mock file-systems. * `addTestFilesToFileSystem()` - use this to add files and their contents to the mock file system for testing. * `loadTestFilesFromDisk()` - use this to load a mirror image of files on disk into the in-memory mock file-system. * `loadFakeCore()` - use this to load a fake version of `@angular/core` into the mock file-system. All ngcc and ngtsc source and tests now use this virtual file-system setup. PR Close #30921
2019-06-06 15:22:32 -04:00
}
// 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;'
},
]);
// Angular packages that have been built locally and stored in the `dist` directory.
refactor(ivy): implement a virtual file-system layer in ngtsc + ngcc (#30921) To improve cross platform support, all file access (and path manipulation) is now done through a well known interface (`FileSystem`). For testing a number of `MockFileSystem` implementations are provided. These provide an in-memory file-system which emulates operating systems like OS/X, Unix and Windows. The current file system is always available via the static method, `FileSystem.getFileSystem()`. This is also used by a number of static methods on `AbsoluteFsPath` and `PathSegment`, to avoid having to pass `FileSystem` objects around all the time. The result of this is that one must be careful to ensure that the file-system has been initialized before using any of these static methods. To prevent this happening accidentally the current file system always starts out as an instance of `InvalidFileSystem`, which will throw an error if any of its methods are called. You can set the current file-system by calling `FileSystem.setFileSystem()`. During testing you can call the helper function `initMockFileSystem(os)` which takes a string name of the OS to emulate, and will also monkey-patch aspects of the TypeScript library to ensure that TS is also using the current file-system. Finally there is the `NgtscCompilerHost` to be used for any TypeScript compilation, which uses a given file-system. All tests that interact with the file-system should be tested against each of the mock file-systems. A series of helpers have been provided to support such tests: * `runInEachFileSystem()` - wrap your tests in this helper to run all the wrapped tests in each of the mock file-systems. * `addTestFilesToFileSystem()` - use this to add files and their contents to the mock file system for testing. * `loadTestFilesFromDisk()` - use this to load a mirror image of files on disk into the in-memory mock file-system. * `loadFakeCore()` - use this to load a fake version of `@angular/core` into the mock file-system. All ngcc and ngtsc source and tests now use this virtual file-system setup. PR Close #30921
2019-06-06 15:22:32 -04:00
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>\\n Hello\\n</h2>'}] }\n];`
refactor(ivy): implement a virtual file-system layer in ngtsc + ngcc (#30921) To improve cross platform support, all file access (and path manipulation) is now done through a well known interface (`FileSystem`). For testing a number of `MockFileSystem` implementations are provided. These provide an in-memory file-system which emulates operating systems like OS/X, Unix and Windows. The current file system is always available via the static method, `FileSystem.getFileSystem()`. This is also used by a number of static methods on `AbsoluteFsPath` and `PathSegment`, to avoid having to pass `FileSystem` objects around all the time. The result of this is that one must be careful to ensure that the file-system has been initialized before using any of these static methods. To prevent this happening accidentally the current file system always starts out as an instance of `InvalidFileSystem`, which will throw an error if any of its methods are called. You can set the current file-system by calling `FileSystem.setFileSystem()`. During testing you can call the helper function `initMockFileSystem(os)` which takes a string name of the OS to emulate, and will also monkey-patch aspects of the TypeScript library to ensure that TS is also using the current file-system. Finally there is the `NgtscCompilerHost` to be used for any TypeScript compilation, which uses a given file-system. All tests that interact with the file-system should be tested against each of the mock file-systems. A series of helpers have been provided to support such tests: * `runInEachFileSystem()` - wrap your tests in this helper to run all the wrapped tests in each of the mock file-systems. * `addTestFilesToFileSystem()` - use this to add files and their contents to the mock file system for testing. * `loadTestFilesFromDisk()` - use this to load a mirror image of files on disk into the in-memory mock file-system. * `loadFakeCore()` - use this to load a fake version of `@angular/core` into the mock file-system. All ngcc and ngtsc source and tests now use this virtual file-system setup. PR Close #30921
2019-06-06 15:22:32 -04:00
},
{
name: _('/dist/local-package/index.d.ts'),
contents: `export declare class AppComponent {};`
},
// local-package-2 depends upon local-package, via an `@app` aliased import.
{
name: _('/dist/local-package-2/package.json'),
contents: '{"name": "local-package-2", "es2015": "./index.js", "typings": "./index.d.ts"}'
},
{name: _('/dist/local-package-2/index.metadata.json'), contents: 'DUMMY DATA'},
{
name: _('/dist/local-package-2/index.js'),
contents:
`import {Component} from '@angular/core';\nexport {AppComponent} from '@app/local-package';`
},
{
name: _('/dist/local-package-2/index.d.ts'),
contents:
`import {Component} from '@angular/core';\nexport {AppComponent} from '@app/local-package';`
},
// local-package-3 depends upon local-package, via an `@x` aliased import.
{
name: _('/dist/local-package-3/package.json'),
contents: '{"name": "local-package-3", "es2015": "./index.js", "typings": "./index.d.ts"}'
},
{name: _('/dist/local-package-3/index.metadata.json'), contents: 'DUMMY DATA'},
{
name: _('/dist/local-package-3/index.js'),
contents:
`import {Component} from '@angular/core';\nexport {AppComponent} from '@x/local-package';`
},
{
name: _('/dist/local-package-3/index.d.ts'),
contents:
`import {Component} from '@angular/core';\nexport {AppComponent} from '@x/local-package';`
},
// local-package-4 depends upon local-package, via a plain import.
{
name: _('/dist/local-package-4/package.json'),
contents: '{"name": "local-package-", "es2015": "./index.js", "typings": "./index.d.ts"}'
},
{name: _('/dist/local-package-4/index.metadata.json'), contents: 'DUMMY DATA'},
{
name: _('/dist/local-package-4/index.js'),
contents:
`import {Component} from '@angular/core';\nexport {AppComponent} from 'local-package';`
},
{
name: _('/dist/local-package-4/index.d.ts'),
contents:
`import {Component} from '@angular/core';\nexport {AppComponent} from 'local-package';`
},
refactor(ivy): implement a virtual file-system layer in ngtsc + ngcc (#30921) To improve cross platform support, all file access (and path manipulation) is now done through a well known interface (`FileSystem`). For testing a number of `MockFileSystem` implementations are provided. These provide an in-memory file-system which emulates operating systems like OS/X, Unix and Windows. The current file system is always available via the static method, `FileSystem.getFileSystem()`. This is also used by a number of static methods on `AbsoluteFsPath` and `PathSegment`, to avoid having to pass `FileSystem` objects around all the time. The result of this is that one must be careful to ensure that the file-system has been initialized before using any of these static methods. To prevent this happening accidentally the current file system always starts out as an instance of `InvalidFileSystem`, which will throw an error if any of its methods are called. You can set the current file-system by calling `FileSystem.setFileSystem()`. During testing you can call the helper function `initMockFileSystem(os)` which takes a string name of the OS to emulate, and will also monkey-patch aspects of the TypeScript library to ensure that TS is also using the current file-system. Finally there is the `NgtscCompilerHost` to be used for any TypeScript compilation, which uses a given file-system. All tests that interact with the file-system should be tested against each of the mock file-systems. A series of helpers have been provided to support such tests: * `runInEachFileSystem()` - wrap your tests in this helper to run all the wrapped tests in each of the mock file-systems. * `addTestFilesToFileSystem()` - use this to add files and their contents to the mock file system for testing. * `loadTestFilesFromDisk()` - use this to load a mirror image of files on disk into the in-memory mock file-system. * `loadFakeCore()` - use this to load a fake version of `@angular/core` into the mock file-system. All ngcc and ngtsc source and tests now use this virtual file-system setup. PR Close #30921
2019-06-06 15:22:32 -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'},
]);
}
});
refactor(ivy): implement a virtual file-system layer in ngtsc + ngcc (#30921) To improve cross platform support, all file access (and path manipulation) is now done through a well known interface (`FileSystem`). For testing a number of `MockFileSystem` implementations are provided. These provide an in-memory file-system which emulates operating systems like OS/X, Unix and Windows. The current file system is always available via the static method, `FileSystem.getFileSystem()`. This is also used by a number of static methods on `AbsoluteFsPath` and `PathSegment`, to avoid having to pass `FileSystem` objects around all the time. The result of this is that one must be careful to ensure that the file-system has been initialized before using any of these static methods. To prevent this happening accidentally the current file system always starts out as an instance of `InvalidFileSystem`, which will throw an error if any of its methods are called. You can set the current file-system by calling `FileSystem.setFileSystem()`. During testing you can call the helper function `initMockFileSystem(os)` which takes a string name of the OS to emulate, and will also monkey-patch aspects of the TypeScript library to ensure that TS is also using the current file-system. Finally there is the `NgtscCompilerHost` to be used for any TypeScript compilation, which uses a given file-system. All tests that interact with the file-system should be tested against each of the mock file-systems. A series of helpers have been provided to support such tests: * `runInEachFileSystem()` - wrap your tests in this helper to run all the wrapped tests in each of the mock file-systems. * `addTestFilesToFileSystem()` - use this to add files and their contents to the mock file system for testing. * `loadTestFilesFromDisk()` - use this to load a mirror image of files on disk into the in-memory mock file-system. * `loadFakeCore()` - use this to load a fake version of `@angular/core` into the mock file-system. All ngcc and ngtsc source and tests now use this virtual file-system setup. PR Close #30921
2019-06-06 15:22:32 -04:00
});
function countOccurrences(haystack: string, needle: string): number {
const matches = haystack.match(new RegExp(needle, 'g'));
return matches !== null ? matches.length : 0;
}