/** * @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 */ import * as fs from 'fs'; import * as os from 'os'; import * as path from 'path'; import * as ts from 'typescript'; import * as ng from '../index'; // TEST_TMPDIR is set by bazel. const tmpdir = process.env.TEST_TMPDIR || os.tmpdir(); function getNgRootDir() { const moduleFilename = module.filename.replace(/\\/g, '/'); const distIndex = moduleFilename.indexOf('/dist/all'); return moduleFilename.substr(0, distIndex); } export function writeTempFile(name: string, contents: string): string { const id = (Math.random() * 1000000).toFixed(0); const fn = path.join(tmpdir, `tmp.${id}.${name}`); fs.writeFileSync(fn, contents); return fn; } export function makeTempDir(): string { let dir: string; while (true) { const id = (Math.random() * 1000000).toFixed(0); dir = path.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) { return {basePath, write, writeFiles, createCompilerOptions, shouldExist, shouldNotExist}; function write(fileName: string, content: string) { const dir = path.dirname(fileName); if (dir != '.') { const newDir = path.resolve(basePath, dir); if (!fs.existsSync(newDir)) fs.mkdirSync(newDir); } fs.writeFileSync(path.resolve(basePath, fileName), content, {encoding: 'utf-8'}); } 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 { basePath, 'experimentalDecorators': true, 'skipLibCheck': true, 'strict': true, 'strictPropertyInitialization': false, 'types': [], 'outDir': path.resolve(basePath, 'built'), 'rootDir': basePath, 'baseUrl': basePath, 'declaration': true, 'target': ts.ScriptTarget.ES5, 'module': ts.ModuleKind.ES2015, 'moduleResolution': ts.ModuleResolutionKind.NodeJs, 'lib': [ path.resolve(basePath, 'node_modules/typescript/lib/lib.es6.d.ts'), ], 'paths': {'@angular/*': ['./node_modules/@angular/*']}, ...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(basePath: string) { const sources = process.env.TEST_SRCDIR; const packages = path.join(sources, 'angular/packages'); const nodeModulesPath = path.join(basePath, 'node_modules'); const angularDirectory = path.join(nodeModulesPath, '@angular'); fs.mkdirSync(nodeModulesPath); // Link the built angular packages fs.mkdirSync(angularDirectory); const packageNames = fs.readdirSync(packages).filter( name => fs.statSync(path.join(packages, name)).isDirectory() && fs.existsSync(path.join(packages, name, 'npm_package'))); for (const pkg of packageNames) { fs.symlinkSync(path.join(packages, `${pkg}/npm_package`), path.join(angularDirectory, pkg)); } // Link rxjs const rxjsSource = path.join(sources, 'rxjs'); const rxjsDest = path.join(nodeModulesPath, 'rxjs'); if (fs.existsSync(rxjsSource)) { fs.symlinkSync(rxjsSource, rxjsDest); } // Link typescript const typescriptSource = path.join(sources, 'angular/external/angular_deps/node_modules/typescript'); const typescriptDest = path.join(nodeModulesPath, 'typescript'); if (fs.existsSync(typescriptSource)) { fs.symlinkSync(typescriptSource, typescriptDest); } } function setupBazel(): TestSupport { const basePath = makeTempDir(); setupBazelTo(basePath); return createTestSupportFor(basePath); } function setupTestSh(): TestSupport { const basePath = makeTempDir(); const ngRootDir = getNgRootDir(); const nodeModulesPath = path.resolve(basePath, 'node_modules'); fs.mkdirSync(nodeModulesPath); fs.symlinkSync( path.resolve(ngRootDir, 'dist', 'all', '@angular'), path.resolve(nodeModulesPath, '@angular')); fs.symlinkSync( path.resolve(ngRootDir, 'node_modules', 'rxjs'), path.resolve(nodeModulesPath, 'rxjs')); fs.symlinkSync( path.resolve(ngRootDir, 'node_modules', 'typescript'), path.resolve(nodeModulesPath, 'typescript')); return createTestSupportFor(basePath); } export function isInBazel() { return process.env.TEST_SRCDIR != null; } export function setup(): TestSupport { return isInBazel() ? setupBazel() : setupTestSh(); } 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() ]); }