Skip to content

Commit

Permalink
refactor(compiler-cli): fixup!
Browse files Browse the repository at this point in the history
  • Loading branch information
vicb committed Aug 3, 2017
1 parent 61ab10e commit 4519541
Show file tree
Hide file tree
Showing 9 changed files with 97 additions and 70 deletions.
2 changes: 1 addition & 1 deletion packages/compiler-cli/package.json
Expand Up @@ -5,7 +5,7 @@
"main": "index.js",
"typings": "index.d.ts",
"bin": {
"ngc": "./src/main2.js",
"ngc": "./src/main.js",
"ng-xi18n": "./src/extract_i18n.js"
},
"dependencies": {
Expand Down
21 changes: 19 additions & 2 deletions packages/compiler-cli/src/main.ts
Expand Up @@ -13,8 +13,12 @@ import 'reflect-metadata';

import * as ts from 'typescript';
import * as tsc from '@angular/tsc-wrapped';
import * as fs from 'fs';
import * as path from 'path';
import {isSyntaxError} from '@angular/compiler';

import {main as mainUsingTransformer, readConfiguration} from './ngc';

import {CodeGenerator} from './codegen';

function codegen(
Expand Down Expand Up @@ -46,6 +50,19 @@ export function main(

// CLI entry point
if (require.main === module) {
const args = require('minimist')(process.argv.slice(2));
main(args).then((exitCode: number) => process.exit(exitCode));
const args = process.argv.slice(2);
const parsedArgs = require('minimist')(args);
const project = parsedArgs.p || parsedArgs.project || '.';

const projectDir = fs.lstatSync(project).isFile() ? path.dirname(project) : project;

// file names in tsconfig are resolved relative to this absolute path
const basePath = path.resolve(process.cwd(), projectDir);
const {ngOptions} = readConfiguration(project, basePath);

if (ngOptions.disableTransformerPipeline) {
main(parsedArgs).then((exitCode: number) => process.exit(exitCode));
} else {
process.exit(mainUsingTransformer(args, s => console.error(s)));
}
}
15 changes: 0 additions & 15 deletions packages/compiler-cli/src/main2.ts

This file was deleted.

103 changes: 63 additions & 40 deletions packages/compiler-cli/src/ngc.ts
Expand Up @@ -13,7 +13,6 @@ import {isSyntaxError, syntaxError} from '@angular/compiler';
import {MetadataBundler, createBundleIndexHost} from '@angular/tsc-wrapped';
import * as fs from 'fs';
import * as path from 'path';
import * as tsickle from 'tsickle';
import * as ts from 'typescript';
import * as api from './transformers/api';
import * as ng from './transformers/entry_points';
Expand Down Expand Up @@ -96,54 +95,74 @@ export function readConfiguration(
return {parsed, ngOptions};
}

/**
* Returns an object with two properties:
* - `errorCode` is 0 when the compilation was successful,
* - `result` is an `EmitResult` when the errorCode is 0, `undefined` otherwise.
*/
export function performCompilation(
basePath: string, files: string[], options: ts.CompilerOptions, ngOptions: any,
consoleError: (s: string) => void = console.error,
checkFunc: (cwd: string, ...args: any[]) => void = check,
tsCompilerHost?: ts.CompilerHost): tsickle.EmitResult {
ngOptions.basePath = basePath;
ngOptions.genDir = basePath;

let host = tsCompilerHost || ts.createCompilerHost(options, true);
host.realpath = p => p;
tsCompilerHost?: ts.CompilerHost): {errorCode: number, result?: api.EmitResult} {
try {
ngOptions.basePath = basePath;
ngOptions.genDir = basePath;

let host = tsCompilerHost || ts.createCompilerHost(options, true);
host.realpath = p => p;

const rootFileNames = files.map(f => path.normalize(f));

const addGeneratedFileName = (fileName: string) => {
if (fileName.startsWith(basePath) && TS_EXT.exec(fileName)) {
rootFileNames.push(fileName);
}
};

if (ngOptions.flatModuleOutFile && !ngOptions.skipMetadataEmit) {
const {host: bundleHost, indexName, errors} =
createBundleIndexHost(ngOptions, rootFileNames, host);
if (errors) checkFunc(basePath, errors);
if (indexName) addGeneratedFileName(indexName);
host = bundleHost;
}

const rootFileNames = files.map(f => path.normalize(f));
const ngHostOptions = {...options, ...ngOptions};
const ngHost = ng.createHost({tsHost: host, options: ngHostOptions});

const addGeneratedFileName = (fileName: string) => {
if (fileName.startsWith(basePath) && TS_EXT.exec(fileName)) {
rootFileNames.push(fileName);
}
};
const ngProgram =
ng.createProgram({rootNames: rootFileNames, host: ngHost, options: ngHostOptions});

if (ngOptions.flatModuleOutFile && !ngOptions.skipMetadataEmit) {
const {host: bundleHost, indexName, errors} =
createBundleIndexHost(ngOptions, rootFileNames, host);
if (errors) checkFunc(basePath, errors);
if (indexName) addGeneratedFileName(indexName);
host = bundleHost;
}
// Check parameter diagnostics
checkFunc(basePath, ngProgram.getTsOptionDiagnostics(), ngProgram.getNgOptionDiagnostics());

const ngHostOptions = {...options, ...ngOptions};
const ngHost = ng.createHost({tsHost: host, options: ngHostOptions});
// Check syntactic diagnostics
checkFunc(basePath, ngProgram.getTsSyntacticDiagnostics());

const ngProgram =
ng.createProgram({rootNames: rootFileNames, host: ngHost, options: ngHostOptions});
// Check TypeScript semantic and Angular structure diagnostics
checkFunc(
basePath, ngProgram.getTsSemanticDiagnostics(), ngProgram.getNgStructuralDiagnostics());

// Check parameter diagnostics
checkFunc(basePath, ngProgram.getTsOptionDiagnostics(), ngProgram.getNgOptionDiagnostics());
// Check Angular semantic diagnostics
checkFunc(basePath, ngProgram.getNgSemanticDiagnostics());

// Check syntactic diagnostics
checkFunc(basePath, ngProgram.getTsSyntacticDiagnostics());
const result = ngProgram.emit({
emitFlags: api.EmitFlags.Default |
((ngOptions.skipMetadataEmit || ngOptions.flatModuleOutFile) ? 0 : api.EmitFlags.Metadata)
});

// Check TypeScript semantic and Angular structure diagnostics
checkFunc(basePath, ngProgram.getTsSemanticDiagnostics(), ngProgram.getNgStructuralDiagnostics());
checkFunc(basePath, result.diagnostics);

// Check Angular semantic diagnostics
checkFunc(basePath, ngProgram.getNgSemanticDiagnostics());
return {errorCode: 0, result};
} catch (e) {
if (isSyntaxError(e)) {
consoleError(e.message);
return {errorCode: 1};
}

return ngProgram.emit({
emitFlags: api.EmitFlags.Default |
((ngOptions.skipMetadataEmit || ngOptions.flatModuleOutFile) ? 0 : api.EmitFlags.Metadata)
});
throw e;
}
}

export function main(
Expand All @@ -159,11 +178,10 @@ export function main(
const basePath = path.resolve(process.cwd(), projectDir);
const {parsed, ngOptions} = readConfiguration(project, basePath, checkFunc);

const result =
performCompilation(basePath, parsed.fileNames, parsed.options, ngOptions, checkFunc);

return result.diagnostics.length === 0 ? 0 : 1;
const res = performCompilation(
basePath, parsed.fileNames, parsed.options, ngOptions, consoleError, checkFunc);

return res.errorCode;
} catch (e) {
if (isSyntaxError(e)) {
consoleError(e.message);
Expand All @@ -175,3 +193,8 @@ export function main(
return 2;
}
}

// CLI entry point
if (require.main === module) {
process.exit(main(process.argv.slice(2), s => console.error(s)));
}
14 changes: 9 additions & 5 deletions packages/compiler-cli/src/transformers/api.ts
Expand Up @@ -7,7 +7,6 @@
*/

import {ParseSourceSpan} from '@angular/compiler';
import * as tsickle from 'tsickle';
import * as ts from 'typescript';

export enum DiagnosticCategory {
Expand Down Expand Up @@ -147,6 +146,11 @@ export enum EmitFlags {
// afterTs?: ts.TransformerFactory<ts.SourceFile>[];
// }

export interface EmitResult extends ts.EmitResult {
modulesManifest: {modules: string[]; fileNames: string[];};
externs: {[fileName: string]: string;};
}

export interface Program {
/**
* Retrieve the TypeScript program used to produce semantic diagnostics and emit the sources.
Expand All @@ -156,7 +160,7 @@ export interface Program {
getTsProgram(): ts.Program;

/**
* Retreive options diagnostics for the TypeScript options used to create the program. This is
* Retrieve options diagnostics for the TypeScript options used to create the program. This is
* faster than calling `getTsProgram().getOptionsDiagnostics()` since it does not need to
* collect Angular structural information to produce the errors.
*/
Expand All @@ -168,7 +172,7 @@ export interface Program {
getNgOptionDiagnostics(cancellationToken?: ts.CancellationToken): Diagnostic[];

/**
* Retrive the syntax diagnostics from TypeScript. This is faster than calling
* Retrieve the syntax diagnostics from TypeScript. This is faster than calling
* `getTsProgram().getSyntacticDiagnostics()` since it does not need to collect Angular structural
* information to produce the errors.
*/
Expand All @@ -189,7 +193,7 @@ export interface Program {
getNgStructuralDiagnostics(cancellationToken?: ts.CancellationToken): Diagnostic[];

/**
* Retreive the semantic diagnostics from TypeScript. This is equivilent to calling
* Retrieve the semantic diagnostics from TypeScript. This is equivilent to calling
* `getTsProgram().getSemanticDiagnostics()` directly and is included for completeness.
*/
getTsSemanticDiagnostics(sourceFile?: ts.SourceFile, cancellationToken?: ts.CancellationToken):
Expand Down Expand Up @@ -228,5 +232,5 @@ export interface Program {
emitFlags: EmitFlags,
// transformers?: CustomTransformers, // See TODO above
cancellationToken?: ts.CancellationToken,
}): tsickle.EmitResult;
}): EmitResult;
}
3 changes: 1 addition & 2 deletions packages/compiler-cli/src/transformers/program.ts
Expand Up @@ -7,13 +7,12 @@
*/

import {AotCompiler, GeneratedFile, NgAnalyzedModules, createAotCompiler, getParseErrors, isSyntaxError, toTypeScript} from '@angular/compiler';
import {MetadataCollector, ModuleMetadata} from '@angular/tsc-wrapped';
import {writeFileSync} from 'fs';
import * as path from 'path';
import * as tsickle from 'tsickle';
import * as ts from 'typescript';

import {CompilerHost as AotCompilerHost, CompilerHostContext} from '../compiler_host';
import {CompilerHost as AotCompilerHost} from '../compiler_host';
import {TypeChecker} from '../diagnostics/check_types';

import {CompilerHost, CompilerOptions, Diagnostic, DiagnosticCategory, EmitFlags, Program} from './api';
Expand Down
2 changes: 1 addition & 1 deletion packages/compiler-cli/test/ngc_spec.ts
Expand Up @@ -641,7 +641,7 @@ describe('ngc command-line', () => {
});


expect(emitResult.diagnostics.length).toEqual(0);
expect(emitResult.errorCode).toEqual(0);
shouldExist('index.js');
shouldExist('index.metadata.json');
});
Expand Down
1 change: 0 additions & 1 deletion packages/compiler-cli/tsconfig-build.json
Expand Up @@ -32,7 +32,6 @@
"files": [
"index.ts",
"src/main.ts",
"src/main2.ts",
"src/ngc.ts",
"src/extract_i18n.ts",
"../../node_modules/@types/node/index.d.ts",
Expand Down
6 changes: 3 additions & 3 deletions tools/ngc-wrapped/index.ts
Expand Up @@ -6,7 +6,7 @@
* found in the LICENSE file at https://angular.io/license
*/

// TODO(chuckj): Remove the requirment for a fake 'reflect` implementation from
// TODO(chuckj): Remove the requirement for a fake 'reflect` implementation from
// the compiler
import 'reflect-metadata';
import {performCompilation} from '@angular/compiler-cli';
Expand All @@ -28,7 +28,7 @@ function main(args: string[]) {
const basePath = path.resolve(process.cwd(), projectDir);
const result = performCompilation(basePath, files, options, ngOptions, undefined);

if (result === 0) {
if (result.errorCode === 0) {
// Ensure that expected output files exist.
if (ngOptions && ngOptions.expectedOut) {
for (const out of ngOptions.expectedOut) {
Expand All @@ -37,7 +37,7 @@ function main(args: string[]) {
}
}

return result;
return result.errorCode;
}

if (require.main === module) {
Expand Down

0 comments on commit 4519541

Please sign in to comment.