fix(compiler): fix bazel integration and make `perform-compile` more flexible
Needed to allow custom checking for diagnostics.
This commit is contained in:
parent
b1055a5edb
commit
a69172f6ce
|
@ -15,7 +15,8 @@
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@angular/bazel": "file:../../dist/packages-dist/bazel",
|
"@angular/bazel": "file:../../dist/packages-dist/bazel",
|
||||||
"@angular/compiler-cli": "file:../../dist/packages-dist/compiler-cli",
|
"@angular/compiler-cli": "file:../../dist/packages-dist/compiler-cli",
|
||||||
"typescript": "~2.3.1"
|
"typescript": "~2.3.1",
|
||||||
|
"@types/source-map": "0.5.1"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"postinstall": "ngc -p angular.tsconfig.json",
|
"postinstall": "ngc -p angular.tsconfig.json",
|
||||||
|
|
|
@ -4,8 +4,8 @@ load("@angular//:index.bzl", "ng_module")
|
||||||
exports_files(["tsconfig.json"])
|
exports_files(["tsconfig.json"])
|
||||||
|
|
||||||
ng_module(
|
ng_module(
|
||||||
name = "app",
|
name = "src",
|
||||||
srcs = ["app.module.ts"],
|
srcs = glob(["*.ts"]),
|
||||||
deps = ["//src/hello-world"],
|
deps = ["//src/hello-world"],
|
||||||
tsconfig = ":tsconfig.json",
|
tsconfig = ":tsconfig.json",
|
||||||
)
|
)
|
||||||
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
import {platformBrowser} from '@angular/platform-browser';
|
||||||
|
import {AppModuleNgFactory} from './app.module.ngfactory';
|
||||||
|
|
||||||
|
platformBrowser().bootstrapModuleFactory(AppModuleNgFactory);
|
|
@ -106,13 +106,14 @@ def _compile_action(ctx, inputs, outputs, config_file_path):
|
||||||
if hasattr(ctx.attr, "tsconfig") and ctx.file.tsconfig:
|
if hasattr(ctx.attr, "tsconfig") and ctx.file.tsconfig:
|
||||||
action_inputs += [ctx.file.tsconfig]
|
action_inputs += [ctx.file.tsconfig]
|
||||||
|
|
||||||
|
arguments = ["--node_options=--expose-gc"]
|
||||||
# One at-sign makes this a params-file, enabling the worker strategy.
|
# One at-sign makes this a params-file, enabling the worker strategy.
|
||||||
# Two at-signs escapes the argument so it's passed through to ngc
|
# Two at-signs escapes the argument so it's passed through to ngc
|
||||||
# rather than the contents getting expanded.
|
# rather than the contents getting expanded.
|
||||||
if ctx.attr._supports_workers:
|
if ctx.attr._supports_workers:
|
||||||
arguments = ["@@" + config_file_path]
|
arguments += ["@@" + config_file_path]
|
||||||
else:
|
else:
|
||||||
arguments = ["-p", config_file_path]
|
arguments += ["-p", config_file_path]
|
||||||
|
|
||||||
ctx.action(
|
ctx.action(
|
||||||
progress_message = "Compiling Angular templates (ngc) %s" % ctx.label,
|
progress_message = "Compiling Angular templates (ngc) %s" % ctx.label,
|
||||||
|
|
|
@ -22,7 +22,6 @@ nodejs_binary(
|
||||||
# Entry point assumes the user is outside this WORKSPACE,
|
# Entry point assumes the user is outside this WORKSPACE,
|
||||||
# and references our rules with @angular//src/ngc-wrapped
|
# and references our rules with @angular//src/ngc-wrapped
|
||||||
entry_point = "angular/src/ngc-wrapped/index.js",
|
entry_point = "angular/src/ngc-wrapped/index.js",
|
||||||
args = ["--node_options=--expose-gc"],
|
|
||||||
data = [
|
data = [
|
||||||
":ngc_lib",
|
":ngc_lib",
|
||||||
"@build_bazel_rules_typescript//internal:worker_protocol.proto"
|
"@build_bazel_rules_typescript//internal:worker_protocol.proto"
|
||||||
|
|
|
@ -6,18 +6,17 @@
|
||||||
* found in the LICENSE file at https://angular.io/license
|
* found in the LICENSE file at https://angular.io/license
|
||||||
*/
|
*/
|
||||||
import * as ng from '@angular/compiler-cli';
|
import * as ng from '@angular/compiler-cli';
|
||||||
import {CachedFileLoader, CompilerHost, FileCache, FileLoader, UncachedFileLoader, constructManifest, debug, parseTsconfig, runAsWorker, runWorkerLoop} from '@bazel/typescript';
|
import {BazelOptions, CachedFileLoader, CompilerHost, FileCache, FileLoader, UncachedFileLoader, constructManifest, debug, parseTsconfig, runAsWorker, runWorkerLoop} from '@bazel/typescript';
|
||||||
import * as fs from 'fs';
|
import * as fs from 'fs';
|
||||||
import * as path from 'path';
|
import * as path from 'path';
|
||||||
import * as tsickle from 'tsickle';
|
import * as tsickle from 'tsickle';
|
||||||
import * as ts from 'typescript';
|
import * as ts from 'typescript';
|
||||||
|
|
||||||
const EXT = /(\.ts|\.d\.ts|\.js|\.jsx|\.tsx)$/;
|
const EXT = /(\.ts|\.d\.ts|\.js|\.jsx|\.tsx)$/;
|
||||||
|
const NGC_GEN_FILES = /^(.*?)\.(ngfactory|ngsummary|ngstyle|shim\.ngstyle)(.*)$/;
|
||||||
// FIXME: we should be able to add the assets to the tsconfig so FileLoader
|
// FIXME: we should be able to add the assets to the tsconfig so FileLoader
|
||||||
// knows about them
|
// knows about them
|
||||||
const NGC_NON_TS_INPUTS =
|
const NGC_ASSETS = /\.(css|html|ngsummary\.json)$/;
|
||||||
/(\.(ngsummary|ngstyle|ngfactory)(\.d)?\.ts|\.ngsummary\.json|\.css|\.html)$/;
|
|
||||||
// FIXME should need only summary, css, html
|
|
||||||
|
|
||||||
// TODO(alexeagle): probably not needed, see
|
// TODO(alexeagle): probably not needed, see
|
||||||
// https://github.com/bazelbuild/rules_typescript/issues/28
|
// https://github.com/bazelbuild/rules_typescript/issues/28
|
||||||
|
@ -42,54 +41,72 @@ function runOneBuild(args: string[], inputs?: {[path: string]: string}): boolean
|
||||||
let fileLoader: FileLoader;
|
let fileLoader: FileLoader;
|
||||||
if (inputs) {
|
if (inputs) {
|
||||||
fileLoader = new CachedFileLoader(fileCache, ALLOW_NON_HERMETIC_READS);
|
fileLoader = new CachedFileLoader(fileCache, ALLOW_NON_HERMETIC_READS);
|
||||||
fileCache.updateCache(inputs);
|
// Resolve the inputs to absolute paths to match TypeScript internals
|
||||||
|
const resolvedInputs: {[path: string]: string} = {};
|
||||||
|
for (const key of Object.keys(inputs)) {
|
||||||
|
resolvedInputs[path.resolve(key)] = inputs[key];
|
||||||
|
}
|
||||||
|
fileCache.updateCache(resolvedInputs);
|
||||||
} else {
|
} else {
|
||||||
fileLoader = new UncachedFileLoader();
|
fileLoader = new UncachedFileLoader();
|
||||||
}
|
}
|
||||||
const [{options: tsOptions, bazelOpts, files, config}] = parseTsconfig(project);
|
const [{options: tsOptions, bazelOpts, files, config}] = parseTsconfig(project);
|
||||||
|
const expectedOuts = config['angularCompilerOptions']['expectedOut'];
|
||||||
|
|
||||||
const {basePath} = ng.calcProjectFileAndBasePath(project);
|
const {basePath} = ng.calcProjectFileAndBasePath(project);
|
||||||
const ngOptions = ng.createNgCompilerOptions(basePath, config, tsOptions);
|
const compilerOpts = ng.createNgCompilerOptions(basePath, config, tsOptions);
|
||||||
|
const {diagnostics} = compile({fileLoader, compilerOpts, bazelOpts, files, expectedOuts});
|
||||||
|
return diagnostics.every(d => d.category !== ts.DiagnosticCategory.Error);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function relativeToRootDirs(filePath: string, rootDirs: string[]): string {
|
||||||
|
if (!filePath) return filePath;
|
||||||
|
// NB: the rootDirs should have been sorted longest-first
|
||||||
|
for (const dir of rootDirs || []) {
|
||||||
|
const rel = path.relative(dir, filePath);
|
||||||
|
if (rel.indexOf('.') != 0) return rel;
|
||||||
|
}
|
||||||
|
return filePath;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function compile(
|
||||||
|
{fileLoader, compilerOpts, bazelOpts, files, expectedOuts, gatherDiagnostics}: {
|
||||||
|
fileLoader: FileLoader,
|
||||||
|
compilerOpts: ng.CompilerOptions,
|
||||||
|
bazelOpts: BazelOptions,
|
||||||
|
files: string[],
|
||||||
|
expectedOuts: string[], gatherDiagnostics?: (program: ng.Program) => ng.Diagnostics
|
||||||
|
}): {diagnostics: ng.Diagnostics, program: ng.Program} {
|
||||||
if (!bazelOpts.es5Mode) {
|
if (!bazelOpts.es5Mode) {
|
||||||
ngOptions.annotateForClosureCompiler = true;
|
compilerOpts.annotateForClosureCompiler = true;
|
||||||
ngOptions.annotationsAs = 'static fields';
|
compilerOpts.annotationsAs = 'static fields';
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!tsOptions.rootDirs) {
|
if (!compilerOpts.rootDirs) {
|
||||||
throw new Error('rootDirs is not set!');
|
throw new Error('rootDirs is not set!');
|
||||||
}
|
}
|
||||||
|
|
||||||
function relativeToRootDirs(filePath: string, rootDirs: string[]): string {
|
const writtenExpectedOuts = [...expectedOuts];
|
||||||
if (!filePath) return filePath;
|
const tsHost = ts.createCompilerHost(compilerOpts, true);
|
||||||
// NB: the rootDirs should have been sorted longest-first
|
|
||||||
for (const dir of rootDirs || []) {
|
|
||||||
const rel = path.relative(dir, filePath);
|
|
||||||
if (rel.indexOf('.') !== 0) return rel;
|
|
||||||
}
|
|
||||||
return filePath;
|
|
||||||
}
|
|
||||||
const expectedOuts = [...config['angularCompilerOptions']['expectedOut']];
|
|
||||||
const tsHost = ts.createCompilerHost(tsOptions, true);
|
|
||||||
|
|
||||||
const originalWriteFile = tsHost.writeFile.bind(tsHost);
|
const originalWriteFile = tsHost.writeFile.bind(tsHost);
|
||||||
tsHost.writeFile =
|
tsHost.writeFile =
|
||||||
(fileName: string, content: string, writeByteOrderMark: boolean,
|
(fileName: string, content: string, writeByteOrderMark: boolean,
|
||||||
onError?: (message: string) => void, sourceFiles?: ts.SourceFile[]) => {
|
onError?: (message: string) => void, sourceFiles?: ts.SourceFile[]) => {
|
||||||
const relative = relativeToRootDirs(fileName, [tsOptions.rootDir]);
|
const relative = relativeToRootDirs(fileName, [compilerOpts.rootDir]);
|
||||||
const expectedIdx = expectedOuts.findIndex(o => o === relative);
|
const expectedIdx = writtenExpectedOuts.findIndex(o => o === relative);
|
||||||
if (expectedIdx >= 0) {
|
if (expectedIdx >= 0) {
|
||||||
expectedOuts.splice(expectedIdx, 1);
|
writtenExpectedOuts.splice(expectedIdx, 1);
|
||||||
originalWriteFile(fileName, content, writeByteOrderMark, onError, sourceFiles);
|
originalWriteFile(fileName, content, writeByteOrderMark, onError, sourceFiles);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
// Patch fileExists when resolving modules, so that ngc can ask TypeScript to
|
// Patch fileExists when resolving modules, so that ngc can ask TypeScript to
|
||||||
// resolve non-existing generated files that don't exist on disk, but are
|
// resolve non-existing generated files that don't exist on disk, but are
|
||||||
// synthetic and added to the `programWithStubs` based on real inputs.
|
// synthetic and added to the `programWithStubs` based on real inputs.
|
||||||
const generatedFileModuleResolverHost = Object.create(tsHost);
|
const generatedFileModuleResolverHost = Object.create(tsHost);
|
||||||
generatedFileModuleResolverHost.fileExists = (fileName: string) => {
|
generatedFileModuleResolverHost.fileExists = (fileName: string) => {
|
||||||
const match = /^(.*?)\.(ngfactory|ngsummary|ngstyle|shim\.ngstyle)(.*)$/.exec(fileName);
|
const match = NGC_GEN_FILES.exec(fileName);
|
||||||
if (match) {
|
if (match) {
|
||||||
const [, file, suffix, ext] = match;
|
const [, file, suffix, ext] = match;
|
||||||
// Performance: skip looking for files other than .d.ts or .ts
|
// Performance: skip looking for files other than .d.ts or .ts
|
||||||
|
@ -112,22 +129,29 @@ function runOneBuild(args: string[], inputs?: {[path: string]: string}): boolean
|
||||||
moduleName, containingFile, compilerOptions, generatedFileModuleResolverHost);
|
moduleName, containingFile, compilerOptions, generatedFileModuleResolverHost);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO(alexeagle): does this also work in third_party?
|
||||||
|
const allowNonHermeticRead = false;
|
||||||
const bazelHost = new CompilerHost(
|
const bazelHost = new CompilerHost(
|
||||||
files, tsOptions, bazelOpts, tsHost, fileLoader, ALLOW_NON_HERMETIC_READS,
|
files, compilerOpts, bazelOpts, tsHost, fileLoader, ALLOW_NON_HERMETIC_READS,
|
||||||
generatedFileModuleResolver);
|
generatedFileModuleResolver);
|
||||||
// The file cache is populated by Bazel with workspace-relative filenames
|
const origBazelHostFileExist = bazelHost.fileExists;
|
||||||
// so we must relativize paths before looking them up in the cache.
|
bazelHost.fileExists = (fileName: string) => {
|
||||||
const originalGetSourceFile = bazelHost.getSourceFile.bind(bazelHost);
|
if (NGC_ASSETS.test(fileName)) {
|
||||||
bazelHost.getSourceFile = (fileName: string, languageVersion: ts.ScriptTarget) => {
|
return tsHost.fileExists(fileName);
|
||||||
return originalGetSourceFile(relativeToRootDirs(fileName, [tsOptions.rootDir]));
|
}
|
||||||
|
return origBazelHostFileExist.call(bazelHost, fileName);
|
||||||
};
|
};
|
||||||
|
// TODO(tbosch): fix tsickle to still run regular transformers even
|
||||||
|
// if tsickle is not processing a file, and then remove this override,
|
||||||
|
// as this is only required to keep the ng transformer running,
|
||||||
|
// but produces e.g. too many externs.
|
||||||
bazelHost.shouldSkipTsickleProcessing = (fileName: string): boolean =>
|
bazelHost.shouldSkipTsickleProcessing = (fileName: string): boolean =>
|
||||||
bazelOpts.compilationTargetSrc.indexOf(fileName) === -1 && !NGC_NON_TS_INPUTS.test(fileName);
|
bazelOpts.compilationTargetSrc.indexOf(fileName) === -1 && !NGC_GEN_FILES.test(fileName);
|
||||||
|
|
||||||
const ngHost = ng.createCompilerHost({options: ngOptions, tsHost: bazelHost});
|
const ngHost = ng.createCompilerHost({options: compilerOpts, tsHost: bazelHost});
|
||||||
|
|
||||||
ngHost.fileNameToModuleName = (importedFilePath: string, containingFilePath: string) =>
|
ngHost.fileNameToModuleName = (importedFilePath: string, containingFilePath: string) =>
|
||||||
relativeToRootDirs(importedFilePath, tsOptions.rootDirs).replace(EXT, '');
|
relativeToRootDirs(importedFilePath, compilerOpts.rootDirs).replace(EXT, '');
|
||||||
ngHost.toSummaryFileName = (fileName: string, referringSrcFileName: string) =>
|
ngHost.toSummaryFileName = (fileName: string, referringSrcFileName: string) =>
|
||||||
ngHost.fileNameToModuleName(fileName, referringSrcFileName);
|
ngHost.fileNameToModuleName(fileName, referringSrcFileName);
|
||||||
|
|
||||||
|
@ -149,18 +173,18 @@ function runOneBuild(args: string[], inputs?: {[path: string]: string}): boolean
|
||||||
customTransformers = {},
|
customTransformers = {},
|
||||||
}) =>
|
}) =>
|
||||||
tsickle.emitWithTsickle(
|
tsickle.emitWithTsickle(
|
||||||
program, bazelHost, tsickleOpts, bazelHost, ngOptions, targetSourceFile, writeFile,
|
program, bazelHost, tsickleOpts, bazelHost, compilerOpts, targetSourceFile, writeFile,
|
||||||
cancellationToken, emitOnlyDtsFiles, {
|
cancellationToken, emitOnlyDtsFiles, {
|
||||||
beforeTs: customTransformers.before,
|
beforeTs: customTransformers.before,
|
||||||
afterTs: customTransformers.after,
|
afterTs: customTransformers.after,
|
||||||
});
|
});
|
||||||
|
|
||||||
const {diagnostics, emitResult} =
|
const {diagnostics, emitResult, program} = ng.performCompilation(
|
||||||
ng.performCompilation({rootNames: files, options: ngOptions, host: ngHost, emitCallback});
|
{rootNames: files, options: compilerOpts, host: ngHost, emitCallback, gatherDiagnostics});
|
||||||
const tsickleEmitResult = emitResult as tsickle.EmitResult;
|
const tsickleEmitResult = emitResult as tsickle.EmitResult;
|
||||||
let externs = '/** @externs */\n';
|
let externs = '/** @externs */\n';
|
||||||
if (diagnostics.length) {
|
if (diagnostics.length) {
|
||||||
console.error(ng.formatDiagnostics(ngOptions, diagnostics));
|
console.error(ng.formatDiagnostics(compilerOpts, diagnostics));
|
||||||
} else {
|
} else {
|
||||||
if (bazelOpts.tsickleGenerateExterns) {
|
if (bazelOpts.tsickleGenerateExterns) {
|
||||||
externs += tsickle.getGeneratedExterns(tsickleEmitResult.externs);
|
externs += tsickle.getGeneratedExterns(tsickleEmitResult.externs);
|
||||||
|
@ -178,11 +202,11 @@ function runOneBuild(args: string[], inputs?: {[path: string]: string}): boolean
|
||||||
fs.writeFileSync(bazelOpts.tsickleExternsPath, externs);
|
fs.writeFileSync(bazelOpts.tsickleExternsPath, externs);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const missing of expectedOuts) {
|
for (const missing of writtenExpectedOuts) {
|
||||||
originalWriteFile(missing, '', false);
|
originalWriteFile(missing, '', false);
|
||||||
}
|
}
|
||||||
|
|
||||||
return diagnostics.every(d => d.category !== ts.DiagnosticCategory.Error);
|
return {program, diagnostics};
|
||||||
}
|
}
|
||||||
|
|
||||||
if (require.main === module) {
|
if (require.main === module) {
|
||||||
|
|
|
@ -20,7 +20,7 @@ export {BuiltinType, DeclarationKind, Definition, PipeInfo, Pipes, Signature, Sp
|
||||||
export * from './src/transformers/api';
|
export * from './src/transformers/api';
|
||||||
export * from './src/transformers/entry_points';
|
export * from './src/transformers/entry_points';
|
||||||
|
|
||||||
export {performCompilation, readConfiguration, formatDiagnostics, calcProjectFileAndBasePath, createNgCompilerOptions} from './src/perform_compile';
|
export * from './src/perform_compile';
|
||||||
|
|
||||||
// TODO(hansl): moving to Angular 4 need to update this API.
|
// TODO(hansl): moving to Angular 4 need to update this API.
|
||||||
export {NgTools_InternalApi_NG_2 as __NGTOOLS_PRIVATE_API_2} from './src/ngtools_api';
|
export {NgTools_InternalApi_NG_2 as __NGTOOLS_PRIVATE_API_2} from './src/ngtools_api';
|
||||||
|
|
|
@ -129,33 +129,26 @@ export function exitCodeFromResult(result: PerformCompilationResult | undefined)
|
||||||
1;
|
1;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function performCompilation(
|
export function performCompilation({rootNames, options, host, oldProgram, emitCallback,
|
||||||
{rootNames, options, host, oldProgram, emitCallback, customTransformers}: {
|
gatherDiagnostics = defaultGatherDiagnostics,
|
||||||
rootNames: string[],
|
customTransformers}: {
|
||||||
options: api.CompilerOptions,
|
rootNames: string[],
|
||||||
host?: api.CompilerHost,
|
options: api.CompilerOptions,
|
||||||
oldProgram?: api.Program,
|
host?: api.CompilerHost,
|
||||||
emitCallback?: api.TsEmitCallback,
|
oldProgram?: api.Program,
|
||||||
customTransformers?: api.CustomTransformers
|
emitCallback?: api.TsEmitCallback,
|
||||||
}): PerformCompilationResult {
|
gatherDiagnostics?: (program: api.Program) => Diagnostics,
|
||||||
|
customTransformers?: api.CustomTransformers
|
||||||
|
}): PerformCompilationResult {
|
||||||
const [major, minor] = ts.version.split('.');
|
const [major, minor] = ts.version.split('.');
|
||||||
|
|
||||||
if (Number(major) < 2 || (Number(major) === 2 && Number(minor) < 3)) {
|
if (Number(major) < 2 || (Number(major) === 2 && Number(minor) < 3)) {
|
||||||
throw new Error('Must use TypeScript > 2.3 to have transformer support');
|
throw new Error('Must use TypeScript > 2.3 to have transformer support');
|
||||||
}
|
}
|
||||||
|
|
||||||
const allDiagnostics: Diagnostics = [];
|
|
||||||
|
|
||||||
function checkDiagnostics(diags: Diagnostics | undefined) {
|
|
||||||
if (diags) {
|
|
||||||
allDiagnostics.push(...diags);
|
|
||||||
return diags.every(d => d.category !== ts.DiagnosticCategory.Error);
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
let program: api.Program|undefined;
|
let program: api.Program|undefined;
|
||||||
let emitResult: ts.EmitResult|undefined;
|
let emitResult: ts.EmitResult|undefined;
|
||||||
|
let allDiagnostics: Diagnostics = [];
|
||||||
try {
|
try {
|
||||||
if (!host) {
|
if (!host) {
|
||||||
host = ng.createCompilerHost({options});
|
host = ng.createCompilerHost({options});
|
||||||
|
@ -163,25 +156,9 @@ export function performCompilation(
|
||||||
|
|
||||||
program = ng.createProgram({rootNames, host, options, oldProgram});
|
program = ng.createProgram({rootNames, host, options, oldProgram});
|
||||||
|
|
||||||
let shouldEmit = true;
|
allDiagnostics.push(...gatherDiagnostics(program !));
|
||||||
// Check parameter diagnostics
|
|
||||||
shouldEmit = shouldEmit && checkDiagnostics([
|
|
||||||
...program !.getTsOptionDiagnostics(), ...program !.getNgOptionDiagnostics()
|
|
||||||
]);
|
|
||||||
|
|
||||||
// Check syntactic diagnostics
|
if (!hasErrors(allDiagnostics)) {
|
||||||
shouldEmit = shouldEmit && checkDiagnostics(program !.getTsSyntacticDiagnostics());
|
|
||||||
|
|
||||||
// Check TypeScript semantic and Angular structure diagnostics
|
|
||||||
shouldEmit =
|
|
||||||
shouldEmit &&
|
|
||||||
checkDiagnostics(
|
|
||||||
[...program !.getTsSemanticDiagnostics(), ...program !.getNgStructuralDiagnostics()]);
|
|
||||||
|
|
||||||
// Check Angular semantic diagnostics
|
|
||||||
shouldEmit = shouldEmit && checkDiagnostics(program !.getNgSemanticDiagnostics());
|
|
||||||
|
|
||||||
if (shouldEmit) {
|
|
||||||
emitResult = program !.emit({
|
emitResult = program !.emit({
|
||||||
emitCallback,
|
emitCallback,
|
||||||
customTransformers,
|
customTransformers,
|
||||||
|
@ -209,4 +186,41 @@ export function performCompilation(
|
||||||
{category: ts.DiagnosticCategory.Error, messageText: errMsg, code, source: api.SOURCE});
|
{category: ts.DiagnosticCategory.Error, messageText: errMsg, code, source: api.SOURCE});
|
||||||
return {diagnostics: allDiagnostics, program};
|
return {diagnostics: allDiagnostics, program};
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function defaultGatherDiagnostics(program: api.Program): Diagnostics {
|
||||||
|
const allDiagnostics: Diagnostics = [];
|
||||||
|
|
||||||
|
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());
|
||||||
|
|
||||||
|
// Check TypeScript semantic and Angular structure diagnostics
|
||||||
|
checkOtherDiagnostics =
|
||||||
|
checkOtherDiagnostics &&
|
||||||
|
checkDiagnostics(
|
||||||
|
[...program.getTsSemanticDiagnostics(), ...program.getNgStructuralDiagnostics()]);
|
||||||
|
|
||||||
|
// Check Angular semantic diagnostics
|
||||||
|
checkOtherDiagnostics =
|
||||||
|
checkOtherDiagnostics && checkDiagnostics(program.getNgSemanticDiagnostics());
|
||||||
|
|
||||||
|
return allDiagnostics;
|
||||||
|
}
|
||||||
|
|
||||||
|
function hasErrors(diags: Diagnostics) {
|
||||||
|
return diags.some(d => d.category === ts.DiagnosticCategory.Error);
|
||||||
}
|
}
|
Loading…
Reference in New Issue