fix(compiler): don’t type check templates with `skipTemplateCodegen` (#19909)
This change is needed to prevent users’ builds from breaking. If a user sets `fullTemlateTypeCheck` to true, we will continue to check the templates even when `skipTemplateCodegen` is true as well. Related to #19906 PR Close #19909
This commit is contained in:
parent
b51d57deb8
commit
c92efc15fb
|
@ -426,6 +426,12 @@ export class TsCompilerAotCompilerTypeCheckHostAdapter implements ts.CompilerHos
|
||||||
}
|
}
|
||||||
|
|
||||||
isSourceFile(filePath: string): boolean {
|
isSourceFile(filePath: string): boolean {
|
||||||
|
// Don't generate any files nor typecheck them
|
||||||
|
// if skipTemplateCodegen is set and fullTemplateTypeCheck is not yet set,
|
||||||
|
// for backwards compatibility.
|
||||||
|
if (this.options.skipTemplateCodegen && !this.options.fullTemplateTypeCheck) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
// If we have a summary from a previous compilation,
|
// If we have a summary from a previous compilation,
|
||||||
// treat the file never as a source file.
|
// treat the file never as a source file.
|
||||||
if (this.librarySummaries.has(filePath)) {
|
if (this.librarySummaries.has(filePath)) {
|
||||||
|
|
|
@ -181,11 +181,13 @@ function createVariableStatementForDeclarations(declarations: Declaration[]): ts
|
||||||
/* modifiers */ undefined, ts.createVariableDeclarationList(varDecls, ts.NodeFlags.Const));
|
/* modifiers */ undefined, ts.createVariableDeclarationList(varDecls, ts.NodeFlags.Const));
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getExpressionLoweringTransformFactory(requestsMap: RequestsMap):
|
export function getExpressionLoweringTransformFactory(
|
||||||
(context: ts.TransformationContext) => (sourceFile: ts.SourceFile) => ts.SourceFile {
|
requestsMap: RequestsMap, program: ts.Program): (context: ts.TransformationContext) =>
|
||||||
|
(sourceFile: ts.SourceFile) => ts.SourceFile {
|
||||||
// Return the factory
|
// Return the factory
|
||||||
return (context: ts.TransformationContext) => (sourceFile: ts.SourceFile): ts.SourceFile => {
|
return (context: ts.TransformationContext) => (sourceFile: ts.SourceFile): ts.SourceFile => {
|
||||||
const requests = requestsMap.getRequests(sourceFile);
|
// We need to use the original SourceFile for reading metadata, and not the transformed one.
|
||||||
|
const requests = requestsMap.getRequests(program.getSourceFile(sourceFile.fileName));
|
||||||
if (requests && requests.size) {
|
if (requests && requests.size) {
|
||||||
return transformSourceFile(sourceFile, requests, context);
|
return transformSourceFile(sourceFile, requests, context);
|
||||||
}
|
}
|
||||||
|
|
|
@ -386,7 +386,7 @@ class AngularCompilerProgram implements Program {
|
||||||
customTransformers?: CustomTransformers): ts.CustomTransformers {
|
customTransformers?: CustomTransformers): ts.CustomTransformers {
|
||||||
const beforeTs: ts.TransformerFactory<ts.SourceFile>[] = [];
|
const beforeTs: ts.TransformerFactory<ts.SourceFile>[] = [];
|
||||||
if (!this.options.disableExpressionLowering) {
|
if (!this.options.disableExpressionLowering) {
|
||||||
beforeTs.push(getExpressionLoweringTransformFactory(this.metadataCache));
|
beforeTs.push(getExpressionLoweringTransformFactory(this.metadataCache, this.tsProgram));
|
||||||
}
|
}
|
||||||
beforeTs.push(getAngularEmitterTransformFactory(genFiles));
|
beforeTs.push(getAngularEmitterTransformFactory(genFiles));
|
||||||
if (customTransformers && customTransformers.beforeTs) {
|
if (customTransformers && customTransformers.beforeTs) {
|
||||||
|
@ -754,7 +754,7 @@ export function createSrcToOutPathMapper(
|
||||||
export function i18nExtract(
|
export function i18nExtract(
|
||||||
formatName: string | null, outFile: string | null, host: ts.CompilerHost,
|
formatName: string | null, outFile: string | null, host: ts.CompilerHost,
|
||||||
options: CompilerOptions, bundle: MessageBundle): string[] {
|
options: CompilerOptions, bundle: MessageBundle): string[] {
|
||||||
formatName = formatName || 'null';
|
formatName = formatName || 'xlf';
|
||||||
// Checks the format and returns the extension
|
// Checks the format and returns the extension
|
||||||
const ext = i18nGetExtension(formatName);
|
const ext = i18nGetExtension(formatName);
|
||||||
const content = i18nSerialize(bundle, formatName, options);
|
const content = i18nSerialize(bundle, formatName, options);
|
||||||
|
@ -788,7 +788,7 @@ export function i18nSerialize(
|
||||||
}
|
}
|
||||||
|
|
||||||
export function i18nGetExtension(formatName: string): string {
|
export function i18nGetExtension(formatName: string): string {
|
||||||
const format = (formatName || 'xlf').toLowerCase();
|
const format = formatName.toLowerCase();
|
||||||
|
|
||||||
switch (format) {
|
switch (format) {
|
||||||
case 'xmb':
|
case 'xmb':
|
||||||
|
|
|
@ -181,13 +181,15 @@ function convert(annotatedSource: string) {
|
||||||
[fileName], {module: ts.ModuleKind.CommonJS, target: ts.ScriptTarget.ES2017}, host);
|
[fileName], {module: ts.ModuleKind.CommonJS, target: ts.ScriptTarget.ES2017}, host);
|
||||||
const moduleSourceFile = program.getSourceFile(fileName);
|
const moduleSourceFile = program.getSourceFile(fileName);
|
||||||
const transformers: ts.CustomTransformers = {
|
const transformers: ts.CustomTransformers = {
|
||||||
before: [getExpressionLoweringTransformFactory({
|
before: [getExpressionLoweringTransformFactory(
|
||||||
getRequests(sourceFile: ts.SourceFile): RequestLocationMap{
|
{
|
||||||
if (sourceFile.fileName == moduleSourceFile.fileName) {
|
getRequests(sourceFile: ts.SourceFile): RequestLocationMap{
|
||||||
return requests;
|
if (sourceFile.fileName == moduleSourceFile.fileName) {
|
||||||
} else {return new Map();}
|
return requests;
|
||||||
}
|
} else {return new Map();}
|
||||||
})]
|
}
|
||||||
|
},
|
||||||
|
program)]
|
||||||
};
|
};
|
||||||
let result: string = '';
|
let result: string = '';
|
||||||
const emitResult = program.emit(
|
const emitResult = program.emit(
|
||||||
|
|
|
@ -11,7 +11,7 @@ import * as fs from 'fs';
|
||||||
import * as path from 'path';
|
import * as path from 'path';
|
||||||
import * as ts from 'typescript';
|
import * as ts from 'typescript';
|
||||||
|
|
||||||
import {CompilerHost, LazyRoute} from '../../src/transformers/api';
|
import {CompilerHost, EmitFlags, LazyRoute} from '../../src/transformers/api';
|
||||||
import {createSrcToOutPathMapper} from '../../src/transformers/program';
|
import {createSrcToOutPathMapper} from '../../src/transformers/program';
|
||||||
import {GENERATED_FILES, StructureIsReused, tsStructureIsReused} from '../../src/transformers/util';
|
import {GENERATED_FILES, StructureIsReused, tsStructureIsReused} from '../../src/transformers/util';
|
||||||
import {TestSupport, expectNoDiagnosticsInProgram, setup} from '../test_support';
|
import {TestSupport, expectNoDiagnosticsInProgram, setup} from '../test_support';
|
||||||
|
@ -309,11 +309,35 @@ describe('ng program', () => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should typecheck templates even if skipTemplateCodegen is set', () => {
|
it('should not typecheck templates if skipTemplateCodegen is set but fullTemplateTypeCheck is not',
|
||||||
|
() => {
|
||||||
|
testSupport.writeFiles({
|
||||||
|
'src/main.ts': `
|
||||||
|
import {NgModule} from '@angular/core';
|
||||||
|
|
||||||
|
@NgModule(() => {if (1==1) return null as any;})
|
||||||
|
export class SomeClassWithInvalidMetadata {}
|
||||||
|
`,
|
||||||
|
});
|
||||||
|
const options = testSupport.createCompilerOptions({skipTemplateCodegen: true});
|
||||||
|
const host = ng.createCompilerHost({options});
|
||||||
|
const program = ng.createProgram(
|
||||||
|
{rootNames: [path.resolve(testSupport.basePath, 'src/main.ts')], options, host});
|
||||||
|
expectNoDiagnosticsInProgram(options, program);
|
||||||
|
const emitResult = program.emit({emitFlags: EmitFlags.All});
|
||||||
|
expect(emitResult.diagnostics.length).toBe(0);
|
||||||
|
|
||||||
|
testSupport.shouldExist('built/src/main.metadata.json');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should typecheck templates if skipTemplateCodegen and fullTemplateTypeCheck is set', () => {
|
||||||
testSupport.writeFiles({
|
testSupport.writeFiles({
|
||||||
'src/main.ts': createModuleAndCompSource('main', `{{nonExistent}}`),
|
'src/main.ts': createModuleAndCompSource('main', `{{nonExistent}}`),
|
||||||
});
|
});
|
||||||
const options = testSupport.createCompilerOptions({skipTemplateCodegen: true});
|
const options = testSupport.createCompilerOptions({
|
||||||
|
skipTemplateCodegen: true,
|
||||||
|
fullTemplateTypeCheck: true,
|
||||||
|
});
|
||||||
const host = ng.createCompilerHost({options});
|
const host = ng.createCompilerHost({options});
|
||||||
const program = ng.createProgram(
|
const program = ng.createProgram(
|
||||||
{rootNames: [path.resolve(testSupport.basePath, 'src/main.ts')], options, host});
|
{rootNames: [path.resolve(testSupport.basePath, 'src/main.ts')], options, host});
|
||||||
|
|
Loading…
Reference in New Issue