242 lines
8.6 KiB
TypeScript
Raw Normal View History

#!/usr/bin/env node
/**
* @license
* Copyright Google LLC 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
*/
// Must be imported first, because Angular decorators throw on load.
import 'reflect-metadata';
import * as ts from 'typescript';
import * as tsickle from 'tsickle';
import {replaceTsWithNgInErrors} from './ngtsc/diagnostics';
import * as api from './transformers/api';
import {GENERATED_FILES} from './transformers/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 20:22:32 +01:00
import {exitCodeFromResult, performCompilation, readConfiguration, formatDiagnostics, Diagnostics, ParsedConfiguration, filterErrorsAndWarnings} from './perform_compile';
import {performWatchCompilation, createPerformWatchHost} from './perform_watch';
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 20:22:32 +01:00
import {NodeJSFileSystem, setFileSystem} from './ngtsc/file_system';
export function main(
args: string[], consoleError: (s: string) => void = console.error,
config?: NgcParsedConfiguration, customTransformers?: api.CustomTransformers, programReuse?: {
program: api.Program|undefined,
},
modifiedResourceFiles?: Set<string>|null): number {
let {project, rootNames, options, errors: configErrors, watch, emitFlags} =
config || readNgcCommandLineAndConfiguration(args);
if (configErrors.length) {
return reportErrorsAndExit(configErrors, /*options*/ undefined, consoleError);
}
if (watch) {
const result = watchMode(project, options, consoleError);
return reportErrorsAndExit(result.firstCompileResult, options, consoleError);
}
let oldProgram: api.Program|undefined;
if (programReuse !== undefined) {
oldProgram = programReuse.program;
}
const {diagnostics: compileDiags, program} = performCompilation({
rootNames,
options,
emitFlags,
oldProgram,
emitCallback: createEmitCallback(options),
customTransformers,
modifiedResourceFiles
});
if (programReuse !== undefined) {
programReuse.program = program;
}
return reportErrorsAndExit(compileDiags, options, consoleError);
}
export function mainDiagnosticsForTest(
args: string[], config?: NgcParsedConfiguration,
programReuse?: {program: api.Program|undefined},
modifiedResourceFiles?: Set<string>|null): ReadonlyArray<ts.Diagnostic|api.Diagnostic> {
let {project, rootNames, options, errors: configErrors, watch, emitFlags} =
config || readNgcCommandLineAndConfiguration(args);
if (configErrors.length) {
return configErrors;
}
let oldProgram: api.Program|undefined;
if (programReuse !== undefined) {
oldProgram = programReuse.program;
}
const {diagnostics: compileDiags, program} = performCompilation({
rootNames,
options,
emitFlags,
oldProgram,
modifiedResourceFiles,
emitCallback: createEmitCallback(options),
});
if (programReuse !== undefined) {
programReuse.program = program;
}
return compileDiags;
}
function createEmitCallback(options: api.CompilerOptions): api.TsEmitCallback|undefined {
fix(compiler-cli): downlevel angular decorators to static properties (#37382) In v7 of Angular we removed `tsickle` from the default `ngc` pipeline. This had the negative potential of breaking ES2015 output and SSR due to a limitation in TypeScript. TypeScript by default preserves type information for decorated constructor parameters when `emitDecoratorMetadata` is enabled. For example, consider this snippet below: ``` @Directive() export class MyDirective { constructor(button: MyButton) {} } export class MyButton {} ``` TypeScript would generate metadata for the `MyDirective` class it has a decorator applied. This metadata would be needed in JIT mode, or for libraries that provide `MyDirective` through NPM. The metadata would look as followed: ``` let MyDirective = class MyDir {} MyDirective = __decorate([ Directive(), __metadata("design:paramtypes", [MyButton]), ], MyDirective); let MyButton = class MyButton {} ``` Notice that TypeScript generated calls to `__decorate` and `__metadata`. These calls are needed so that the Angular compiler is able to determine whether `MyDirective` is actually an directive, and what types are needed for dependency injection. The limitation surfaces in this concrete example because `MyButton` is declared after the `__metadata(..)` call, while `__metadata` actually directly references `MyButton`. This is illegal though because `MyButton` has not been declared at this point. This is due to the so-called temporal dead zone in JavaScript. Errors like followed will be reported at runtime when such file/code evaluates: ``` Uncaught ReferenceError: Cannot access 'MyButton' before initialization ``` As noted, this is a TypeScript limitation because ideally TypeScript shouldn't evaluate `__metadata`/reference `MyButton` immediately. Instead, it should defer the reference until `MyButton` is actually declared. This limitation will not be fixed by the TypeScript team though because it's a limitation as per current design and they will only revisit this once the tc39 decorator proposal is finalized (currently stage-2 at time of writing). Given this wontfix on the TypeScript side, and our heavy reliance on this metadata in libraries (and for JIT mode), we intend to fix this from within the Angular compiler by downleveling decorators to static properties that don't need to evaluate directly. For example: ``` MyDirective.ctorParameters = () => [MyButton]; ``` With this snippet above, `MyButton` is not referenced directly. Only lazily when the Angular runtime needs it. This mitigates the temporal dead zone issue caused by a limitation in TypeScript's decorator metadata output. See: https://github.com/microsoft/TypeScript/issues/27519. In the past (as noted; before version 7), the Angular compiler by default used tsickle that already performed this transformation. We moved the transformation to the CLI for JIT and `ng-packager`, but now we realize that we can move this all to a single place in the compiler so that standalone ngc consumers can benefit too, and that we can disable tsickle in our Bazel `ngc-wrapped` pipeline (that currently still relies on tsickle to perform this decorator processing). This transformation also has another positive side-effect of making Angular application/library code more compatible with server-side rendering. In principle, TypeScript would also preserve type information for decorated class members (similar to how it did that for constructor parameters) at runtime. This becomes an issue when your application relies on native DOM globals for decorated class member types. e.g. ``` @Input() panelElement: HTMLElement; ``` Your application code would then reference `HTMLElement` directly whenever the source file is loaded in NodeJS for SSR. `HTMLElement` does not exist on the server though, so that will become an invalid reference. One could work around this by providing global mocks for these DOM symbols, but that doesn't match up with other places where dependency injection is used for mocking DOM/browser specific symbols. More context in this issue: #30586. The TL;DR here is that the Angular compiler does not care about types for these class members, so it won't ever reference `HTMLElement` at runtime. Fixes #30106. Fixes #30586. Fixes #30141. Resolves FW-2196. Resolves FW-2199. PR Close #37382
2020-06-05 16:26:23 +02:00
if (!options.annotateForClosureCompiler) {
return undefined;
}
const tsickleHost: Pick<
tsickle.TsickleHost,
'shouldSkipTsickleProcessing'|'pathToModuleName'|'shouldIgnoreWarningsForPath'|
'fileNameToModuleId'|'googmodule'|'untyped'|'convertIndexImportShorthand'|
'transformDecorators'|'transformTypesToClosure'> = {
feat(bazel): transform generated shims (in Ivy) with tsickle (#35975) Currently, when Angular code is built with Bazel and with Ivy, generated factory shims (.ngfactory files) are not processed via the majority of tsickle's transforms. This is a subtle effect of the build infrastructure, but it boils down to a TsickleHost method `shouldSkipTsickleProcessing`. For ngc_wrapped builds (Bazel + Angular), this method is defined in the `@bazel/typescript` (aka bazel rules_typescript) implementation of `CompilerHost`. The default behavior is to skip tsickle processing for files which are not present in the original `srcs[]` of the build rule. In Angular's case, this includes all generated shim files. For View Engine factories this is probably desirable as they're quite complex and they've never been tested with tsickle. Ivy factories however are smaller and very straightforward, and it makes sense to treat them like any other output. This commit adjusts two independent implementations of `shouldSkipTsickleProcessing` to enable transformation of Ivy shims: * in `@angular/bazel` aka ngc_wrapped, the upstream `@bazel/typescript` `CompilerHost` is patched to treat .ngfactory files the same as their original source file, with respect to tsickle processing. It is currently not possible to test this change as we don't have any test that inspects tsickle output with bazel. It will be extensively tested in g3. * in `ngc`, Angular's own implementation is adjusted to allow for the processing of shims when compiling with Ivy. This enables a unit test to be written to validate the correct behavior of tsickle when given a host that's appropriately configured to process factory shims. For ngtsc-as-a-plugin, a similar fix will need to be submitted upstream in tsc_wrapped. PR Close #35848 PR Close #35975
2020-03-03 17:02:39 -08:00
shouldSkipTsickleProcessing: (fileName) => /\.d\.ts$/.test(fileName) ||
// View Engine's generated files were never intended to be processed with tsickle.
(!options.enableIvy && GENERATED_FILES.test(fileName)),
pathToModuleName: (context, importPath) => '',
shouldIgnoreWarningsForPath: (filePath) => false,
fileNameToModuleId: (fileName) => fileName,
googmodule: false,
untyped: true,
convertIndexImportShorthand: false,
fix(compiler-cli): downlevel angular decorators to static properties (#37382) In v7 of Angular we removed `tsickle` from the default `ngc` pipeline. This had the negative potential of breaking ES2015 output and SSR due to a limitation in TypeScript. TypeScript by default preserves type information for decorated constructor parameters when `emitDecoratorMetadata` is enabled. For example, consider this snippet below: ``` @Directive() export class MyDirective { constructor(button: MyButton) {} } export class MyButton {} ``` TypeScript would generate metadata for the `MyDirective` class it has a decorator applied. This metadata would be needed in JIT mode, or for libraries that provide `MyDirective` through NPM. The metadata would look as followed: ``` let MyDirective = class MyDir {} MyDirective = __decorate([ Directive(), __metadata("design:paramtypes", [MyButton]), ], MyDirective); let MyButton = class MyButton {} ``` Notice that TypeScript generated calls to `__decorate` and `__metadata`. These calls are needed so that the Angular compiler is able to determine whether `MyDirective` is actually an directive, and what types are needed for dependency injection. The limitation surfaces in this concrete example because `MyButton` is declared after the `__metadata(..)` call, while `__metadata` actually directly references `MyButton`. This is illegal though because `MyButton` has not been declared at this point. This is due to the so-called temporal dead zone in JavaScript. Errors like followed will be reported at runtime when such file/code evaluates: ``` Uncaught ReferenceError: Cannot access 'MyButton' before initialization ``` As noted, this is a TypeScript limitation because ideally TypeScript shouldn't evaluate `__metadata`/reference `MyButton` immediately. Instead, it should defer the reference until `MyButton` is actually declared. This limitation will not be fixed by the TypeScript team though because it's a limitation as per current design and they will only revisit this once the tc39 decorator proposal is finalized (currently stage-2 at time of writing). Given this wontfix on the TypeScript side, and our heavy reliance on this metadata in libraries (and for JIT mode), we intend to fix this from within the Angular compiler by downleveling decorators to static properties that don't need to evaluate directly. For example: ``` MyDirective.ctorParameters = () => [MyButton]; ``` With this snippet above, `MyButton` is not referenced directly. Only lazily when the Angular runtime needs it. This mitigates the temporal dead zone issue caused by a limitation in TypeScript's decorator metadata output. See: https://github.com/microsoft/TypeScript/issues/27519. In the past (as noted; before version 7), the Angular compiler by default used tsickle that already performed this transformation. We moved the transformation to the CLI for JIT and `ng-packager`, but now we realize that we can move this all to a single place in the compiler so that standalone ngc consumers can benefit too, and that we can disable tsickle in our Bazel `ngc-wrapped` pipeline (that currently still relies on tsickle to perform this decorator processing). This transformation also has another positive side-effect of making Angular application/library code more compatible with server-side rendering. In principle, TypeScript would also preserve type information for decorated class members (similar to how it did that for constructor parameters) at runtime. This becomes an issue when your application relies on native DOM globals for decorated class member types. e.g. ``` @Input() panelElement: HTMLElement; ``` Your application code would then reference `HTMLElement` directly whenever the source file is loaded in NodeJS for SSR. `HTMLElement` does not exist on the server though, so that will become an invalid reference. One could work around this by providing global mocks for these DOM symbols, but that doesn't match up with other places where dependency injection is used for mocking DOM/browser specific symbols. More context in this issue: #30586. The TL;DR here is that the Angular compiler does not care about types for these class members, so it won't ever reference `HTMLElement` at runtime. Fixes #30106. Fixes #30586. Fixes #30141. Resolves FW-2196. Resolves FW-2199. PR Close #37382
2020-06-05 16:26:23 +02:00
// Decorators are transformed as part of the Angular compiler programs. To avoid
// conflicts, we disable decorator transformations for tsickle.
transformDecorators: false,
transformTypesToClosure: true,
};
fix(compiler-cli): downlevel angular decorators to static properties (#37382) In v7 of Angular we removed `tsickle` from the default `ngc` pipeline. This had the negative potential of breaking ES2015 output and SSR due to a limitation in TypeScript. TypeScript by default preserves type information for decorated constructor parameters when `emitDecoratorMetadata` is enabled. For example, consider this snippet below: ``` @Directive() export class MyDirective { constructor(button: MyButton) {} } export class MyButton {} ``` TypeScript would generate metadata for the `MyDirective` class it has a decorator applied. This metadata would be needed in JIT mode, or for libraries that provide `MyDirective` through NPM. The metadata would look as followed: ``` let MyDirective = class MyDir {} MyDirective = __decorate([ Directive(), __metadata("design:paramtypes", [MyButton]), ], MyDirective); let MyButton = class MyButton {} ``` Notice that TypeScript generated calls to `__decorate` and `__metadata`. These calls are needed so that the Angular compiler is able to determine whether `MyDirective` is actually an directive, and what types are needed for dependency injection. The limitation surfaces in this concrete example because `MyButton` is declared after the `__metadata(..)` call, while `__metadata` actually directly references `MyButton`. This is illegal though because `MyButton` has not been declared at this point. This is due to the so-called temporal dead zone in JavaScript. Errors like followed will be reported at runtime when such file/code evaluates: ``` Uncaught ReferenceError: Cannot access 'MyButton' before initialization ``` As noted, this is a TypeScript limitation because ideally TypeScript shouldn't evaluate `__metadata`/reference `MyButton` immediately. Instead, it should defer the reference until `MyButton` is actually declared. This limitation will not be fixed by the TypeScript team though because it's a limitation as per current design and they will only revisit this once the tc39 decorator proposal is finalized (currently stage-2 at time of writing). Given this wontfix on the TypeScript side, and our heavy reliance on this metadata in libraries (and for JIT mode), we intend to fix this from within the Angular compiler by downleveling decorators to static properties that don't need to evaluate directly. For example: ``` MyDirective.ctorParameters = () => [MyButton]; ``` With this snippet above, `MyButton` is not referenced directly. Only lazily when the Angular runtime needs it. This mitigates the temporal dead zone issue caused by a limitation in TypeScript's decorator metadata output. See: https://github.com/microsoft/TypeScript/issues/27519. In the past (as noted; before version 7), the Angular compiler by default used tsickle that already performed this transformation. We moved the transformation to the CLI for JIT and `ng-packager`, but now we realize that we can move this all to a single place in the compiler so that standalone ngc consumers can benefit too, and that we can disable tsickle in our Bazel `ngc-wrapped` pipeline (that currently still relies on tsickle to perform this decorator processing). This transformation also has another positive side-effect of making Angular application/library code more compatible with server-side rendering. In principle, TypeScript would also preserve type information for decorated class members (similar to how it did that for constructor parameters) at runtime. This becomes an issue when your application relies on native DOM globals for decorated class member types. e.g. ``` @Input() panelElement: HTMLElement; ``` Your application code would then reference `HTMLElement` directly whenever the source file is loaded in NodeJS for SSR. `HTMLElement` does not exist on the server though, so that will become an invalid reference. One could work around this by providing global mocks for these DOM symbols, but that doesn't match up with other places where dependency injection is used for mocking DOM/browser specific symbols. More context in this issue: #30586. The TL;DR here is that the Angular compiler does not care about types for these class members, so it won't ever reference `HTMLElement` at runtime. Fixes #30106. Fixes #30586. Fixes #30141. Resolves FW-2196. Resolves FW-2199. PR Close #37382
2020-06-05 16:26:23 +02:00
return ({
program,
targetSourceFile,
writeFile,
cancellationToken,
emitOnlyDtsFiles,
customTransformers = {},
host,
options
}) =>
// tslint:disable-next-line:no-require-imports only depend on tsickle if requested
require('tsickle').emitWithTsickle(
program, {...tsickleHost, options, host, moduleResolutionHost: host}, host, options,
targetSourceFile, writeFile, cancellationToken, emitOnlyDtsFiles, {
beforeTs: customTransformers.before,
afterTs: customTransformers.after,
});
}
export interface NgcParsedConfiguration extends ParsedConfiguration {
watch?: boolean;
}
export function readNgcCommandLineAndConfiguration(args: string[]): NgcParsedConfiguration {
const options: api.CompilerOptions = {};
const parsedArgs = require('minimist')(args);
if (parsedArgs.i18nFile) options.i18nInFile = parsedArgs.i18nFile;
if (parsedArgs.i18nFormat) options.i18nInFormat = parsedArgs.i18nFormat;
if (parsedArgs.locale) options.i18nInLocale = parsedArgs.locale;
const mt = parsedArgs.missingTranslation;
if (mt === 'error' || mt === 'warning' || mt === 'ignore') {
options.i18nInMissingTranslations = mt;
}
const config = readCommandLineAndConfiguration(
args, options, ['i18nFile', 'i18nFormat', 'locale', 'missingTranslation', 'watch']);
const watch = parsedArgs.w || parsedArgs.watch;
return {...config, watch};
}
export function readCommandLineAndConfiguration(
args: string[], existingOptions: api.CompilerOptions = {},
ngCmdLineOptions: string[] = []): ParsedConfiguration {
let cmdConfig = ts.parseCommandLine(args);
const project = cmdConfig.options.project || '.';
const cmdErrors = cmdConfig.errors.filter(e => {
if (typeof e.messageText === 'string') {
const msg = e.messageText;
return !ngCmdLineOptions.some(o => msg.indexOf(o) >= 0);
}
return true;
});
if (cmdErrors.length) {
return {
project,
rootNames: [],
options: cmdConfig.options,
errors: cmdErrors,
emitFlags: api.EmitFlags.Default
};
}
const allDiagnostics: Diagnostics = [];
const config = readConfiguration(project, cmdConfig.options);
const options = {...config.options, ...existingOptions};
if (options.locale) {
options.i18nInLocale = options.locale;
}
return {
project,
rootNames: config.rootNames,
options,
errors: config.errors,
emitFlags: config.emitFlags
};
}
function getFormatDiagnosticsHost(options?: api.CompilerOptions): ts.FormatDiagnosticsHost {
const basePath = options ? options.basePath : undefined;
return {
getCurrentDirectory: () => basePath || ts.sys.getCurrentDirectory(),
// We need to normalize the path separators here because by default, TypeScript
// compiler hosts use posix canonical paths. In order to print consistent diagnostics,
// we also normalize the paths.
getCanonicalFileName: fileName => fileName.replace(/\\/g, '/'),
getNewLine: () => {
// Manually determine the proper new line string based on the passed compiler
// options. There is no public TypeScript function that returns the corresponding
// new line string. see: https://github.com/Microsoft/TypeScript/issues/29581
if (options && options.newLine !== undefined) {
return options.newLine === ts.NewLineKind.LineFeed ? '\n' : '\r\n';
}
return ts.sys.newLine;
},
};
}
function reportErrorsAndExit(
allDiagnostics: Diagnostics, options?: api.CompilerOptions,
consoleError: (s: string) => void = console.error): number {
const errorsAndWarnings = filterErrorsAndWarnings(allDiagnostics);
printDiagnostics(errorsAndWarnings, options, consoleError);
return exitCodeFromResult(allDiagnostics);
}
export function watchMode(
project: string, options: api.CompilerOptions, consoleError: (s: string) => void) {
return performWatchCompilation(createPerformWatchHost(project, diagnostics => {
printDiagnostics(diagnostics, options, consoleError);
}, options, options => createEmitCallback(options)));
}
function printDiagnostics(
diagnostics: ReadonlyArray<ts.Diagnostic|api.Diagnostic>,
options: api.CompilerOptions|undefined, consoleError: (s: string) => void): void {
if (diagnostics.length === 0) {
return;
}
const formatHost = getFormatDiagnosticsHost(options);
consoleError(formatDiagnostics(diagnostics, formatHost));
}
// CLI entry point
if (require.main === module) {
const args = process.argv.slice(2);
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 20:22:32 +01:00
// We are running the real compiler so run against the real file-system
setFileSystem(new NodeJSFileSystem());
process.exitCode = main(args);
2016-11-30 16:45:40 -08:00
}