ec4381dd40
This commit switches the default value of the enableIvy flag to true. Applications that run ngc will now by default receive an Ivy build! This does not affect the way Bazel builds in the Angular repo work, since those are still switched based on the value of the --define=compile flag. Additionally, projects using @angular/bazel still use View Engine builds by default. Since most of the Angular repo tests are still written against View Engine (particularly because we still publish VE packages to NPM), this switch also requires lots of `enableIvy: false` flags in tsconfigs throughout the repo. Congrats to the team for reaching this milestone! PR Close #32219
174 lines
5.9 KiB
TypeScript
174 lines
5.9 KiB
TypeScript
/**
|
|
* @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
|
|
*/
|
|
/// <reference types="node" />
|
|
import * as fs from 'fs';
|
|
import * as path from 'path';
|
|
import * as ts from 'typescript';
|
|
|
|
import * as ng from '../index';
|
|
import {NodeJSFileSystem, setFileSystem} from '../src/ngtsc/file_system';
|
|
import {getAngularPackagesFromRunfiles, resolveNpmTreeArtifact} from '../test/helpers';
|
|
|
|
// TEST_TMPDIR is always set by Bazel.
|
|
const tmpdir = process.env.TEST_TMPDIR !;
|
|
|
|
export function makeTempDir(): string {
|
|
let dir: string;
|
|
while (true) {
|
|
const id = (Math.random() * 1000000).toFixed(0);
|
|
dir = path.posix.join(tmpdir, `tmp.${id}`);
|
|
if (!fs.existsSync(dir)) break;
|
|
}
|
|
fs.mkdirSync(dir);
|
|
return dir;
|
|
}
|
|
|
|
export interface TestSupport {
|
|
basePath: string;
|
|
write(fileName: string, content: string): void;
|
|
writeFiles(...mockDirs: {[fileName: string]: string}[]): void;
|
|
createCompilerOptions(overrideOptions?: ng.CompilerOptions): ng.CompilerOptions;
|
|
shouldExist(fileName: string): void;
|
|
shouldNotExist(fileName: string): void;
|
|
}
|
|
|
|
function createTestSupportFor(basePath: string) {
|
|
// Typescript uses identity comparison on `paths` and other arrays in order to determine
|
|
// if program structure can be reused for incremental compilation, so we reuse the default
|
|
// values unless overriden, and freeze them so that they can't be accidentaly changed somewhere
|
|
// in tests.
|
|
const defaultCompilerOptions = {
|
|
basePath,
|
|
'experimentalDecorators': true,
|
|
'skipLibCheck': true,
|
|
'strict': true,
|
|
'strictPropertyInitialization': false,
|
|
'types': Object.freeze<string>([]) as string[],
|
|
'outDir': path.resolve(basePath, 'built'),
|
|
'rootDir': basePath,
|
|
'baseUrl': basePath,
|
|
'declaration': true,
|
|
'target': ts.ScriptTarget.ES5,
|
|
'newLine': ts.NewLineKind.LineFeed,
|
|
'module': ts.ModuleKind.ES2015,
|
|
'moduleResolution': ts.ModuleResolutionKind.NodeJs,
|
|
'enableIvy': false,
|
|
'lib': Object.freeze([
|
|
path.resolve(basePath, 'node_modules/typescript/lib/lib.es6.d.ts'),
|
|
]) as string[],
|
|
// clang-format off
|
|
'paths': Object.freeze({'@angular/*': ['./node_modules/@angular/*']}) as {[index: string]: string[]}
|
|
// clang-format on
|
|
};
|
|
|
|
|
|
return {
|
|
// We normalize the basePath into a posix path, so that multiple assertions which compare
|
|
// paths don't need to normalize the path separators each time.
|
|
basePath: normalizeSeparators(basePath),
|
|
write,
|
|
writeFiles,
|
|
createCompilerOptions,
|
|
shouldExist,
|
|
shouldNotExist
|
|
};
|
|
|
|
function ensureDirExists(absolutePathToDir: string) {
|
|
if (fs.existsSync(absolutePathToDir)) {
|
|
if (!fs.statSync(absolutePathToDir).isDirectory()) {
|
|
throw new Error(`'${absolutePathToDir}' exists and is not a directory.`);
|
|
}
|
|
} else {
|
|
const parentDir = path.dirname(absolutePathToDir);
|
|
ensureDirExists(parentDir);
|
|
fs.mkdirSync(absolutePathToDir);
|
|
}
|
|
}
|
|
|
|
function write(fileName: string, content: string) {
|
|
const absolutePathToFile = path.resolve(basePath, fileName);
|
|
ensureDirExists(path.dirname(absolutePathToFile));
|
|
fs.writeFileSync(absolutePathToFile, content);
|
|
}
|
|
|
|
function writeFiles(...mockDirs: {[fileName: string]: string}[]) {
|
|
mockDirs.forEach(
|
|
(dir) => { Object.keys(dir).forEach((fileName) => { write(fileName, dir[fileName]); }); });
|
|
}
|
|
|
|
function createCompilerOptions(overrideOptions: ng.CompilerOptions = {}): ng.CompilerOptions {
|
|
return {...defaultCompilerOptions, ...overrideOptions};
|
|
}
|
|
|
|
function shouldExist(fileName: string) {
|
|
if (!fs.existsSync(path.resolve(basePath, fileName))) {
|
|
throw new Error(`Expected ${fileName} to be emitted (basePath: ${basePath})`);
|
|
}
|
|
}
|
|
|
|
function shouldNotExist(fileName: string) {
|
|
if (fs.existsSync(path.resolve(basePath, fileName))) {
|
|
throw new Error(`Did not expect ${fileName} to be emitted (basePath: ${basePath})`);
|
|
}
|
|
}
|
|
}
|
|
|
|
export function setupBazelTo(tmpDirPath: string) {
|
|
const nodeModulesPath = path.join(tmpDirPath, 'node_modules');
|
|
const angularDirectory = path.join(nodeModulesPath, '@angular');
|
|
|
|
fs.mkdirSync(nodeModulesPath);
|
|
fs.mkdirSync(angularDirectory);
|
|
|
|
getAngularPackagesFromRunfiles().forEach(({pkgPath, name}) => {
|
|
fs.symlinkSync(pkgPath, path.join(angularDirectory, name), 'junction');
|
|
});
|
|
|
|
// Link typescript
|
|
const typeScriptSource = resolveNpmTreeArtifact('npm/node_modules/typescript');
|
|
const typescriptDest = path.join(nodeModulesPath, 'typescript');
|
|
fs.symlinkSync(typeScriptSource, typescriptDest, 'junction');
|
|
|
|
// Link "rxjs" if it has been set up as a runfile. "rxjs" is linked optionally because
|
|
// not all compiler-cli tests need "rxjs" set up.
|
|
try {
|
|
const rxjsSource = resolveNpmTreeArtifact('rxjs', 'index.js');
|
|
const rxjsDest = path.join(nodeModulesPath, 'rxjs');
|
|
fs.symlinkSync(rxjsSource, rxjsDest, 'junction');
|
|
} catch (e) {
|
|
if (e.code !== 'MODULE_NOT_FOUND') throw e;
|
|
}
|
|
}
|
|
|
|
export function setup(): TestSupport {
|
|
// // `TestSupport` provides its own file-system abstraction so we just use
|
|
// // the native `NodeJSFileSystem` under the hood.
|
|
setFileSystem(new NodeJSFileSystem());
|
|
const tmpDirPath = makeTempDir();
|
|
setupBazelTo(tmpDirPath);
|
|
return createTestSupportFor(tmpDirPath);
|
|
}
|
|
|
|
export function expectNoDiagnostics(options: ng.CompilerOptions, diags: ng.Diagnostics) {
|
|
const errorDiags = diags.filter(d => d.category !== ts.DiagnosticCategory.Message);
|
|
if (errorDiags.length) {
|
|
throw new Error(`Expected no diagnostics: ${ng.formatDiagnostics(errorDiags)}`);
|
|
}
|
|
}
|
|
|
|
export function expectNoDiagnosticsInProgram(options: ng.CompilerOptions, p: ng.Program) {
|
|
expectNoDiagnostics(options, [
|
|
...p.getNgStructuralDiagnostics(), ...p.getTsSemanticDiagnostics(),
|
|
...p.getNgSemanticDiagnostics()
|
|
]);
|
|
}
|
|
|
|
export function normalizeSeparators(path: string): string {
|
|
return path.replace(/\\/g, '/');
|
|
}
|