From 0c7726dd74b8c5a6fe6e3482ecb3bc05b525ad61 Mon Sep 17 00:00:00 2001 From: jolly-roger Date: Tue, 24 Jan 2017 22:51:14 +0200 Subject: [PATCH] feat(tsc-wrapped): Support of vinyl like config file was added (#13987) This feature was implemented in order to provide easier way of use in gulp --- tools/@angular/tsc-wrapped/src/main.ts | 10 +++++-- tools/@angular/tsc-wrapped/src/tsc.ts | 20 +++++++++++--- tools/@angular/tsc-wrapped/src/vinyl_file.ts | 19 +++++++++++++ tools/@angular/tsc-wrapped/test/main.spec.ts | 29 ++++++++++++++++++++ tools/@angular/tsc-wrapped/test/tsc.spec.ts | 24 ++++++++++++---- 5 files changed, 91 insertions(+), 11 deletions(-) create mode 100644 tools/@angular/tsc-wrapped/src/vinyl_file.ts diff --git a/tools/@angular/tsc-wrapped/src/main.ts b/tools/@angular/tsc-wrapped/src/main.ts index 723696ed11..d85f26f1d9 100644 --- a/tools/@angular/tsc-wrapped/src/main.ts +++ b/tools/@angular/tsc-wrapped/src/main.ts @@ -15,6 +15,7 @@ import {check, tsc} from './tsc'; import NgOptions from './options'; import {MetadataWriterHost, DecoratorDownlevelCompilerHost, TsickleCompilerHost} from './compiler_host'; import {CliOptions} from './cli_options'; +import {VinylFile, isVinylFile} from './vinyl_file'; export {UserError} from './tsc'; @@ -23,11 +24,16 @@ export type CodegenExtension = Promise; export function main( - project: string, cliOptions: CliOptions, codegen?: CodegenExtension, + project: string | VinylFile, cliOptions: CliOptions, codegen?: CodegenExtension, options?: ts.CompilerOptions): Promise { try { let projectDir = project; - if (fs.lstatSync(project).isFile()) { + // project is vinyl like file object + if (isVinylFile(project)) { + projectDir = path.dirname(project.path); + } + // project is path to project file + else if (fs.lstatSync(project).isFile()) { projectDir = path.dirname(project); } diff --git a/tools/@angular/tsc-wrapped/src/tsc.ts b/tools/@angular/tsc-wrapped/src/tsc.ts index e2e4e2df83..9e606aa783 100644 --- a/tools/@angular/tsc-wrapped/src/tsc.ts +++ b/tools/@angular/tsc-wrapped/src/tsc.ts @@ -11,6 +11,7 @@ import * as path from 'path'; import * as ts from 'typescript'; import AngularCompilerOptions from './options'; +import {VinylFile, isVinylFile} from './vinyl_file'; /** * Our interface to the TypeScript standard compiler. @@ -18,7 +19,8 @@ import AngularCompilerOptions from './options'; * you should implement a similar interface. */ export interface CompilerInterface { - readConfiguration(project: string, basePath: string, existingOptions?: ts.CompilerOptions): + readConfiguration( + project: string|VinylFile, basePath: string, existingOptions?: ts.CompilerOptions): {parsed: ts.ParsedCommandLine, ngOptions: AngularCompilerOptions}; typeCheck(compilerHost: ts.CompilerHost, program: ts.Program): void; emit(program: ts.Program): number; @@ -97,20 +99,30 @@ export class Tsc implements CompilerInterface { constructor(private readFile = ts.sys.readFile, private readDirectory = ts.sys.readDirectory) {} - readConfiguration(project: string, basePath: string, existingOptions?: ts.CompilerOptions) { + readConfiguration( + project: string|VinylFile, basePath: string, existingOptions?: ts.CompilerOptions) { this.basePath = basePath; // Allow a directory containing tsconfig.json as the project value // Note, TS@next returns an empty array, while earlier versions throw try { - if (this.readDirectory(project).length > 0) { + if (!isVinylFile(project) && this.readDirectory(project).length > 0) { project = path.join(project, 'tsconfig.json'); } } catch (e) { // Was not a directory, continue on assuming it's a file } - const {config, error} = ts.readConfigFile(project, this.readFile); + let {config, error} = (() => { + // project is vinyl like file object + if (isVinylFile(project)) { + return {config: JSON.parse(project.contents.toString()), error: null}; + } + // project is path to project file + else { + return ts.readConfigFile(project, this.readFile); + } + })(); check([error]); // Do not inline `host` into `parseJsonConfigFileContent` until after diff --git a/tools/@angular/tsc-wrapped/src/vinyl_file.ts b/tools/@angular/tsc-wrapped/src/vinyl_file.ts new file mode 100644 index 0000000000..41b619d48c --- /dev/null +++ b/tools/@angular/tsc-wrapped/src/vinyl_file.ts @@ -0,0 +1,19 @@ +/** + * @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 + */ +export interface VinylFile extends Object { + // Absolute path to the virtual file + path: string; + + // Content of the virtual file + contents: Buffer; +} +; + +export function isVinylFile(obj: any): obj is VinylFile { + return (typeof obj === 'object') && ('path' in obj) && ('contents' in obj); +}; \ No newline at end of file diff --git a/tools/@angular/tsc-wrapped/test/main.spec.ts b/tools/@angular/tsc-wrapped/test/main.spec.ts index 0a47a813ab..0e0bece04c 100644 --- a/tools/@angular/tsc-wrapped/test/main.spec.ts +++ b/tools/@angular/tsc-wrapped/test/main.spec.ts @@ -91,6 +91,35 @@ describe('tsc-wrapped', () => { .catch(e => done.fail(e)); }); + it('should pre-process sources using config from vinyl like object', (done) => { + const config = { + path: basePath + '/tsconfig.json', + contents: new Buffer(JSON.stringify({ + compilerOptions: { + experimentalDecorators: true, + types: [], + outDir: 'built', + declaration: true, + moduleResolution: 'node', + target: 'es2015' + }, + angularCompilerOptions: {annotateForClosureCompiler: true}, + files: ['test.ts'] + })) + }; + + main(config, {basePath}) + .then(() => { + const out = readOut('js'); + // Expand `export *` and fix index import + expect(out).toContain(`export { A, B } from './dep/index'`); + // Annotated for Closure compiler + expect(out).toContain('* @param {?} x'); + done(); + }) + .catch(e => done.fail(e)); + }); + it('should allow all options disabled', (done) => { write('tsconfig.json', `{ "compilerOptions": { diff --git a/tools/@angular/tsc-wrapped/test/tsc.spec.ts b/tools/@angular/tsc-wrapped/test/tsc.spec.ts index 9eafe33fb7..8b694c46bd 100644 --- a/tools/@angular/tsc-wrapped/test/tsc.spec.ts +++ b/tools/@angular/tsc-wrapped/test/tsc.spec.ts @@ -7,12 +7,12 @@ */ import * as ts from 'typescript'; -import {Tsc} from '../src/tsc'; +import {Tsc, tsc as pureTsc} from '../src/tsc'; +import {VinylFile} from '../src/vinyl_file'; describe('options parsing', () => { - const tsc = new Tsc( - () => ` + const configData = ` { "angularCompilerOptions": { "googleClosureOutput": true @@ -21,8 +21,10 @@ describe('options parsing', () => { "module": "commonjs", "outDir": "built" } -}`, - () => ['tsconfig.json']); +}`; + + const tsc = new Tsc(() => configData, () => ['tsconfig.json']); + const config = {path: 'basePath/tsconfig.json', contents: new Buffer(configData)}; it('should combine all options into ngOptions', () => { const {parsed, ngOptions} = @@ -37,4 +39,16 @@ describe('options parsing', () => { target: ts.ScriptTarget.ES2015 }); }); + + it('should combine all options into ngOptions from vinyl like object', () => { + const {parsed, ngOptions} = pureTsc.readConfiguration(config as VinylFile, 'basePath'); + + expect(ngOptions).toEqual({ + genDir: 'basePath', + googleClosureOutput: true, + module: ts.ModuleKind.CommonJS, + outDir: 'basePath/built', + configFilePath: undefined + }); + }); });