angular-cn/packages/compiler-cli/src/perform_compile.ts

321 lines
11 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
*/
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 {Position, isSyntaxError} from '@angular/compiler';
import * as ts from 'typescript';
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 {AbsoluteFsPath, absoluteFrom, getFileSystem, relative, resolve} from '../src/ngtsc/file_system';
import * as api from './transformers/api';
import * as ng from './transformers/entry_points';
import {createMessageDiagnostic} from './transformers/util';
export type Diagnostics = ReadonlyArray<ts.Diagnostic|api.Diagnostic>;
export function filterErrorsAndWarnings(diagnostics: Diagnostics): Diagnostics {
return diagnostics.filter(d => d.category !== ts.DiagnosticCategory.Message);
}
const defaultFormatHost: ts.FormatDiagnosticsHost = {
getCurrentDirectory: () => ts.sys.getCurrentDirectory(),
getCanonicalFileName: fileName => fileName,
getNewLine: () => ts.sys.newLine
};
function displayFileName(fileName: string, host: ts.FormatDiagnosticsHost): string {
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
return relative(
resolve(host.getCurrentDirectory()), resolve(host.getCanonicalFileName(fileName)));
}
export function formatDiagnosticPosition(
position: Position, host: ts.FormatDiagnosticsHost = defaultFormatHost): string {
return `${displayFileName(position.fileName, host)}(${position.line + 1},${position.column+1})`;
}
export function flattenDiagnosticMessageChain(
chain: api.DiagnosticMessageChain, host: ts.FormatDiagnosticsHost = defaultFormatHost): string {
let result = chain.messageText;
let indent = 1;
let current = chain.next;
const newLine = host.getNewLine();
while (current) {
result += newLine;
for (let i = 0; i < indent; i++) {
result += ' ';
}
result += current.messageText;
const position = current.position;
if (position) {
result += ` at ${formatDiagnosticPosition(position, host)}`;
}
current = current.next;
indent++;
}
return result;
}
export function formatDiagnostic(
diagnostic: api.Diagnostic, host: ts.FormatDiagnosticsHost = defaultFormatHost) {
let result = '';
const newLine = host.getNewLine();
const span = diagnostic.span;
if (span) {
result += `${formatDiagnosticPosition({
fileName: span.start.file.url,
line: span.start.line,
column: span.start.col
}, host)}: `;
} else if (diagnostic.position) {
result += `${formatDiagnosticPosition(diagnostic.position, host)}: `;
}
if (diagnostic.span && diagnostic.span.details) {
result += `: ${diagnostic.span.details}, ${diagnostic.messageText}${newLine}`;
} else if (diagnostic.chain) {
result += `${flattenDiagnosticMessageChain(diagnostic.chain, host)}.${newLine}`;
} else {
result += `: ${diagnostic.messageText}${newLine}`;
}
return result;
}
export function formatDiagnostics(
diags: Diagnostics, host: ts.FormatDiagnosticsHost = defaultFormatHost): string {
if (diags && diags.length) {
return diags
.map(diagnostic => {
if (api.isTsDiagnostic(diagnostic)) {
return ts.formatDiagnostics([diagnostic], host);
} else {
return formatDiagnostic(diagnostic, host);
}
})
.join('');
} else {
return '';
}
}
export interface ParsedConfiguration {
project: string;
options: api.CompilerOptions;
rootNames: string[];
emitFlags: api.EmitFlags;
errors: Diagnostics;
}
export function calcProjectFileAndBasePath(project: string):
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
{projectFile: AbsoluteFsPath, basePath: AbsoluteFsPath} {
const fs = getFileSystem();
const absProject = fs.resolve(project);
const projectIsDir = fs.lstat(absProject).isDirectory();
const projectFile = projectIsDir ? fs.join(absProject, 'tsconfig.json') : absProject;
const projectDir = projectIsDir ? absProject : fs.dirname(absProject);
const basePath = fs.resolve(projectDir);
return {projectFile, basePath};
}
export function createNgCompilerOptions(
basePath: string, config: any, tsOptions: ts.CompilerOptions): api.CompilerOptions {
// enableIvy `ngtsc` is an alias for `true`.
if (config.angularCompilerOptions && config.angularCompilerOptions.enableIvy === 'ngtsc') {
config.angularCompilerOptions.enableIvy = true;
}
return {...tsOptions, ...config.angularCompilerOptions, genDir: basePath, basePath};
}
export function readConfiguration(
project: string, existingOptions?: ts.CompilerOptions): ParsedConfiguration {
try {
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 fs = getFileSystem();
const {projectFile, basePath} = calcProjectFileAndBasePath(project);
const readExtendedConfigFile =
(configFile: string, existingConfig?: any): {config?: any, error?: ts.Diagnostic} => {
const {config, error} = ts.readConfigFile(configFile, ts.sys.readFile);
if (error) {
return {error};
}
// we are only interested into merging 'angularCompilerOptions' as
// other options like 'compilerOptions' are merged by TS
const baseConfig = existingConfig || config;
if (existingConfig) {
baseConfig.angularCompilerOptions = {...config.angularCompilerOptions,
...baseConfig.angularCompilerOptions};
}
if (config.extends) {
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
let extendedConfigPath = fs.resolve(fs.dirname(configFile), config.extends);
extendedConfigPath = fs.extname(extendedConfigPath) ?
extendedConfigPath :
absoluteFrom(`${extendedConfigPath}.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
if (fs.exists(extendedConfigPath)) {
// Call read config recursively as TypeScript only merges CompilerOptions
return readExtendedConfigFile(extendedConfigPath, baseConfig);
}
}
return {config: baseConfig};
};
const {config, error} = readExtendedConfigFile(projectFile);
if (error) {
return {
project,
errors: [error],
rootNames: [],
options: {},
emitFlags: api.EmitFlags.Default
};
}
const parseConfigHost = {
useCaseSensitiveFileNames: 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
fileExists: fs.exists.bind(fs),
readDirectory: ts.sys.readDirectory,
readFile: ts.sys.readFile
};
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 configFileName = fs.resolve(fs.pwd(), projectFile);
const parsed = ts.parseJsonConfigFileContent(
config, parseConfigHost, basePath, existingOptions, configFileName);
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 rootNames = parsed.fileNames;
const options = createNgCompilerOptions(basePath, config, parsed.options);
let emitFlags = api.EmitFlags.Default;
if (!(options.skipMetadataEmit || options.flatModuleOutFile)) {
emitFlags |= api.EmitFlags.Metadata;
}
if (options.skipTemplateCodegen) {
emitFlags = emitFlags & ~api.EmitFlags.Codegen;
}
return {project: projectFile, rootNames, options, errors: parsed.errors, emitFlags};
} catch (e) {
const errors: Diagnostics = [{
category: ts.DiagnosticCategory.Error,
messageText: e.stack,
source: api.SOURCE,
code: api.UNKNOWN_ERROR_CODE
}];
return {project: '', errors, rootNames: [], options: {}, emitFlags: api.EmitFlags.Default};
}
}
export interface PerformCompilationResult {
diagnostics: Diagnostics;
program?: api.Program;
emitResult?: ts.EmitResult;
}
export function exitCodeFromResult(diags: Diagnostics | undefined): number {
if (!diags || filterErrorsAndWarnings(diags).length === 0) {
// If we have a result and didn't get any errors, we succeeded.
return 0;
}
// Return 2 if any of the errors were unknown.
return diags.some(d => d.source === 'angular' && d.code === api.UNKNOWN_ERROR_CODE) ? 2 : 1;
}
export function performCompilation(
{rootNames, options, host, oldProgram, emitCallback, mergeEmitResultsCallback,
gatherDiagnostics = defaultGatherDiagnostics, customTransformers,
emitFlags = api.EmitFlags.Default, modifiedResourceFiles = null}: {
rootNames: string[],
options: api.CompilerOptions,
host?: api.CompilerHost,
oldProgram?: api.Program,
emitCallback?: api.TsEmitCallback,
mergeEmitResultsCallback?: api.TsMergeEmitResultsCallback,
gatherDiagnostics?: (program: api.Program) => Diagnostics,
customTransformers?: api.CustomTransformers,
emitFlags?: api.EmitFlags,
modifiedResourceFiles?: Set<string>| null,
}): PerformCompilationResult {
let program: api.Program|undefined;
let emitResult: ts.EmitResult|undefined;
let allDiagnostics: Array<ts.Diagnostic|api.Diagnostic> = [];
try {
if (!host) {
host = ng.createCompilerHost({options});
}
if (modifiedResourceFiles) {
host.getModifiedResourceFiles = () => modifiedResourceFiles;
}
program = ng.createProgram({rootNames, host, options, oldProgram});
const beforeDiags = Date.now();
allDiagnostics.push(...gatherDiagnostics(program !));
if (options.diagnostics) {
const afterDiags = Date.now();
allDiagnostics.push(
createMessageDiagnostic(`Time for diagnostics: ${afterDiags - beforeDiags}ms.`));
}
if (!hasErrors(allDiagnostics)) {
emitResult =
program !.emit({emitCallback, mergeEmitResultsCallback, customTransformers, emitFlags});
allDiagnostics.push(...emitResult.diagnostics);
return {diagnostics: allDiagnostics, program, emitResult};
}
return {diagnostics: allDiagnostics, program};
} catch (e) {
let errMsg: string;
let code: number;
if (isSyntaxError(e)) {
// don't report the stack for syntax errors as they are well known errors.
errMsg = e.message;
code = api.DEFAULT_ERROR_CODE;
} else {
errMsg = e.stack;
// It is not a syntax error we might have a program with unknown state, discard it.
program = undefined;
code = api.UNKNOWN_ERROR_CODE;
}
allDiagnostics.push(
{category: ts.DiagnosticCategory.Error, messageText: errMsg, code, source: api.SOURCE});
return {diagnostics: allDiagnostics, program};
}
}
function defaultGatherDiagnostics(program: api.Program): Diagnostics {
const allDiagnostics: Array<ts.Diagnostic|api.Diagnostic> = [];
function checkDiagnostics(diags: Diagnostics | undefined) {
if (diags) {
allDiagnostics.push(...diags);
return !hasErrors(diags);
}
return true;
}
let checkOtherDiagnostics = true;
// Check parameter diagnostics
checkOtherDiagnostics = checkOtherDiagnostics &&
checkDiagnostics([...program.getTsOptionDiagnostics(), ...program.getNgOptionDiagnostics()]);
// Check syntactic diagnostics
checkOtherDiagnostics =
checkOtherDiagnostics && checkDiagnostics(program.getTsSyntacticDiagnostics() as Diagnostics);
// Check TypeScript semantic and Angular structure diagnostics
checkOtherDiagnostics =
checkOtherDiagnostics &&
checkDiagnostics(
[...program.getTsSemanticDiagnostics(), ...program.getNgStructuralDiagnostics()]);
// Check Angular semantic diagnostics
checkOtherDiagnostics =
checkOtherDiagnostics && checkDiagnostics(program.getNgSemanticDiagnostics() as Diagnostics);
return allDiagnostics;
}
function hasErrors(diags: Diagnostics) {
return diags.some(d => d.category === ts.DiagnosticCategory.Error);
}