Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions packages/compiler-cli/src/ngtsc/tsc_plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ export class NgTscPlugin implements TscPlugin {
if (this.host === null || this.options === null) {
throw new Error('Lifecycle error: setupCompilation() before wrapHost().');
}
this.host.postProgramCreationCleanup();
const typeCheckStrategy = new ReusedProgramStrategy(
program, this.host, this.options, this.host.shimExtensionPrefixes);
this._compiler = new NgCompiler(
Expand Down
69 changes: 65 additions & 4 deletions packages/compiler-cli/test/ngtsc/env.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,20 @@
* found in the LICENSE file at https://angular.io/license
*/

import {CustomTransformers, defaultGatherDiagnostics, Program} from '@angular/compiler-cli';
import {CustomTransformers, defaultGatherDiagnostics, NgTscPlugin, Program, readConfiguration} from '@angular/compiler-cli';
import * as api from '@angular/compiler-cli/src/transformers/api';
import * as ts from 'typescript';

import {createCompilerHost, createProgram} from '../../index';
import {main, mainDiagnosticsForTest, readNgcCommandLineAndConfiguration} from '../../src/main';
import {absoluteFrom, AbsoluteFsPath, FileSystem, getFileSystem, NgtscCompilerHost} from '../../src/ngtsc/file_system';
import {absoluteFrom, AbsoluteFsPath, FileSystem, getFileSystem, NgtscCompilerHost, setFileSystem} from '../../src/ngtsc/file_system';
import {Folder, MockFileSystem} from '../../src/ngtsc/file_system/testing';
import {IndexedComponent} from '../../src/ngtsc/indexer';
import {NgtscProgram} from '../../src/ngtsc/program';
import {LazyRoute} from '../../src/ngtsc/routing';
import {setWrapHostForTest} from '../../src/transformers/compiler_host';

let wrapHost!: (host: ts.CompilerHost) => ts.CompilerHost;

/**
* Manages a temporary testing directory structure and environment for testing ngtsc by feeding it
Expand All @@ -27,6 +28,7 @@ import {setWrapHostForTest} from '../../src/transformers/compiler_host';
export class NgtscTestEnvironment {
private multiCompileHostExt: MultiCompileHostExt|null = null;
private oldProgram: Program|null = null;
private oldPluginProgram: ts.Program|null = null;
private changedResources: Set<string>|null = null;

private constructor(
Expand All @@ -43,7 +45,8 @@ export class NgtscTestEnvironment {
}

const host = new AugmentedCompilerHost(fs);
setWrapHostForTest(makeWrapHost(host));
wrapHost = makeWrapHost(host);
setWrapHostForTest(wrapHost);

const env = new NgtscTestEnvironment(fs, fs.resolve('/built'), workingDir);
fs.chdir(workingDir);
Expand Down Expand Up @@ -101,7 +104,8 @@ export class NgtscTestEnvironment {
enableMultipleCompilations(): void {
this.changedResources = new Set();
this.multiCompileHostExt = new MultiCompileHostExt(this.fs);
setWrapHostForTest(makeWrapHost(this.multiCompileHostExt));
wrapHost = makeWrapHost(this.multiCompileHostExt);
setWrapHostForTest(wrapHost);
}

/**
Expand Down Expand Up @@ -210,6 +214,63 @@ export class NgtscTestEnvironment {
}
}

drivePluginDiagnostics(): ts.Diagnostic[] {
const oldProgram = this.oldPluginProgram ?? undefined;

const config = readConfiguration(this.basePath);
const options = config.options;

// Creating the NgTscPlugin installs a real NodeJSFileSystem. Save the current testing fs and
// restore it after creation.
const fs = getFileSystem();
const plugin = new NgTscPlugin(options);
setFileSystem(fs);

const nativeHost = wrapHost(ts.createCompilerHost(options));
const host = plugin.wrapHost(nativeHost as any, config.rootNames, options);
const program = ts.createProgram({
host,
options,
rootNames: config.rootNames,
oldProgram,
});
const {ignoreForDiagnostics, ignoreForEmit} = plugin.setupCompilation(program, oldProgram);

const diagnostics: ts.Diagnostic[] = [
...program.getOptionsDiagnostics(),
...program.getGlobalDiagnostics(),
...plugin.getOptionDiagnostics(),
];
if (diagnostics.length > 0) {
return diagnostics;
}

for (const sf of program.getSourceFiles()) {
if (sf.isDeclarationFile || ignoreForDiagnostics.has(sf)) {
continue;
}

diagnostics.push(...program.getSyntacticDiagnostics(sf));
diagnostics.push(...program.getSemanticDiagnostics(sf));
diagnostics.push(...plugin.getDiagnostics(sf));
}

if (diagnostics.length > 0) {
return diagnostics;
}

const transformers = plugin.createTransformers();
for (const sf of program.getSourceFiles()) {
if (sf.isDeclarationFile || ignoreForEmit.has(sf)) {
continue;
}
program.emit(sf, undefined, undefined, undefined, transformers);
}

this.oldPluginProgram = plugin.getNextProgram();
return [];
}

/**
* Run the compiler to completion, and return any `ts.Diagnostic` errors that may have occurred.
*/
Expand Down
41 changes: 41 additions & 0 deletions packages/compiler-cli/test/ngtsc/plugin_spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
/**
* @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
*/

import {runInEachFileSystem} from '../../src/ngtsc/file_system/testing';
import {loadStandardTestFiles} from '../helpers/src/mock_file_loading';

import {NgtscTestEnvironment} from './env';


const testFiles = loadStandardTestFiles();

runInEachFileSystem(() => {
describe('NgTscPlugin', () => {
let env!: NgtscTestEnvironment;

beforeEach(() => {
env = NgtscTestEnvironment.setup(testFiles);
env.tsconfig();
});

it('should not leave triple-slash references to typecheck files in output .d.ts', () => {
env.write('main.ts', `
import {Injectable} from '@angular/core';

@Injectable()
export class FooService {}
`);
const diags = env.drivePluginDiagnostics();
expect(diags).toEqual([]);

const dtsContents = env.getContents('main.d.ts');
expect(dtsContents).not.toContain('<reference');
expect(dtsContents).not.toContain('ngtypecheck');
});
});
});