Skip to content

Commit

Permalink
chore(ngc): refactor out tsc-wrapped
Browse files Browse the repository at this point in the history
This allows angular's build to depend on some extensions, but not on code generation, and breaks a cycle in the angular build
We now merge ts-metadata-collector into tsc-wrapped and stop publishing the former.
  • Loading branch information
alexeagle committed May 25, 2016
1 parent e26e4f9 commit 4c26397
Show file tree
Hide file tree
Showing 31 changed files with 230 additions and 193 deletions.
18 changes: 6 additions & 12 deletions build.sh
Original file line number Diff line number Diff line change
Expand Up @@ -35,14 +35,8 @@ cd -
TSCONFIG=./modules/tsconfig.json
echo "====== (all)COMPILING: \$(npm bin)/tsc -p ${TSCONFIG} ====="
# compile ts code
# TODO: Right now we have a cycle in that the compiler_cli depends on Angular
# but we need it to compile Angular.
# The solution right now is to do 2 compilation runs.
# Fix this by separating the metadata extraction into a separate binary that does
# not depend on Angular.
$(npm bin)/tsc -p ${TSCONFIG}
NG_TC="node dist/all/@angular/compiler_cli/src/main"
$NG_TC -p modules/tsconfig.json
TSC="node dist/tools/tsc-wrapped/src/main"
$TSC -p modules/tsconfig.json

rm -rf ./dist/packages-dist

Expand All @@ -68,8 +62,8 @@ do
echo "====== COMPILING: \$(npm bin)/tsc -p ${SRCDIR}/tsconfig-es5.json ====="
$(npm bin)/tsc -p ${SRCDIR}/tsconfig-es5.json
else
echo "====== COMPILING: ${NG_TC} -p ${SRCDIR}/tsconfig-es5.json ====="
$NG_TC -p ${SRCDIR}/tsconfig-es5.json
echo "====== COMPILING: ${TSC} -p ${SRCDIR}/tsconfig-es5.json ====="
$TSC -p ${SRCDIR}/tsconfig-es5.json
fi

cp ${SRCDIR}/package.json ${DESTDIR}/
Expand All @@ -91,8 +85,8 @@ do
echo "====== (esm)COMPILING: \$(npm bin)/tsc -p ${SRCDIR}/tsconfig-es2015.json ====="
$(npm bin)/tsc -p ${SRCDIR}/tsconfig-es2015.json
else
echo "====== (esm)COMPILING: $NG_TC -p ${SRCDIR}/tsconfig-es2015.json ====="
$NG_TC -p ${SRCDIR}/tsconfig-es2015.json
echo "====== (esm)COMPILING: $TSC -p ${SRCDIR}/tsconfig-es2015.json ====="
$TSC -p ${SRCDIR}/tsconfig-es2015.json
fi

echo "====== BUNDLING: ${SRCDIR} ====="
Expand Down
2 changes: 1 addition & 1 deletion modules/@angular/compiler_cli/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ with the one already used in the plugin for TypeScript typechecking and emit.

## Design
At a high level, this program
- collects static metadata about the sources using the `ts-metadata-collector` package in angular2
- collects static metadata about the sources using the `tsc-wrapped` package in angular2
- uses the `OfflineCompiler` from `angular2/src/compiler/compiler` to codegen additional `.ts` files
- these `.ts` files are written to the `genDir` path, then compiled together with the application.

Expand Down
2 changes: 1 addition & 1 deletion modules/@angular/compiler_cli/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
export {CodeGenerator} from './src/codegen';
export {NodeReflectorHost} from './src/reflector_host';
export {TsickleHost, MetadataWriterHost} from './src/compiler_host';
export * from 'tsc-wrapped';
3 changes: 1 addition & 2 deletions modules/@angular/compiler_cli/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,7 @@
"ngc": "./src/main.js"
},
"dependencies": {
"ts-metadata-collector": "^0.1.0",
"tsickle": "^0.1.2",
"tsc-wrapped": "^0.1.0",
"reflect-metadata": "^0.1.2",
"parse5": "1.3.2"
},
Expand Down
38 changes: 8 additions & 30 deletions modules/@angular/compiler_cli/src/codegen.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
*/
import * as ts from 'typescript';
import * as path from 'path';
import {AngularCompilerOptions} from 'tsc-wrapped';

import * as compiler from '@angular/compiler';
import {ViewEncapsulation} from '@angular/core';
Expand All @@ -23,7 +24,6 @@ import {

import {Parse5DomAdapter} from '@angular/platform-server';

import {MetadataCollector} from 'ts-metadata-collector';
import {NodeReflectorHost} from './reflector_host';
import {StaticAndDynamicReflectionCapabilities} from './static_reflection_capabilities';

Expand All @@ -35,30 +35,8 @@ const PREAMBLE = `/**
*/
`;

// TODO(alexeagle): we end up passing options and ngOptions everywhere.
// Maybe this should extend ts.CompilerOptions so we only need this one.
export interface AngularCompilerOptions {
// Absolute path to a directory where generated file structure is written
genDir: string;

// Path to the directory containing the tsconfig.json file.
basePath: string;

// Don't do the template code generation
skipTemplateCodegen: boolean;

// Don't produce .metadata.json files (they don't work for bundled emit with --out)
skipMetadataEmit: boolean;

// Lookup angular's symbols using the old angular2/... npm namespace.
legacyPackageLayout: boolean;

// Print extra information while running the compiler
trace: boolean;
}

export class CodeGenerator {
constructor(private options: ts.CompilerOptions, private ngOptions: AngularCompilerOptions,
constructor(private options: AngularCompilerOptions,
private program: ts.Program, public host: ts.CompilerHost,
private staticReflector: StaticReflector, private resolver: CompileMetadataResolver,
private compiler: compiler.OfflineCompiler,
Expand Down Expand Up @@ -107,17 +85,17 @@ export class CodeGenerator {

// Write codegen in a directory structure matching the sources.
private calculateEmitPath(filePath: string) {
let root = this.ngOptions.basePath;
let root = this.options.basePath;
for (let eachRootDir of this.options.rootDirs || []) {
if (this.ngOptions.trace) {
if (this.options.trace) {
console.log(`Check if ${filePath} is under rootDirs element ${eachRootDir}`);
}
if (path.relative(eachRootDir, filePath).indexOf('.') !== 0) {
root = eachRootDir;
}
}

return path.join(this.ngOptions.genDir, path.relative(root, filePath));
return path.join(this.options.genDir, path.relative(root, filePath));
}

// TODO(tbosch): add a cache for shared css files
Expand Down Expand Up @@ -170,11 +148,11 @@ export class CodeGenerator {
return Promise.all(stylesheetPromises.concat(compPromises));
}

static create(ngOptions: AngularCompilerOptions, program: ts.Program, options: ts.CompilerOptions,
static create(options: AngularCompilerOptions, program: ts.Program,
compilerHost: ts.CompilerHost): CodeGenerator {
const xhr: compiler.XHR = {get: (s: string) => Promise.resolve(compilerHost.readFile(s))};
const urlResolver: compiler.UrlResolver = compiler.createOfflineCompileUrlResolver();
const reflectorHost = new NodeReflectorHost(program, compilerHost, options, ngOptions);
const reflectorHost = new NodeReflectorHost(program, compilerHost, options);
const staticReflector = new StaticReflector(reflectorHost);
StaticAndDynamicReflectionCapabilities.install(staticReflector);
const htmlParser = new HtmlParser();
Expand All @@ -190,7 +168,7 @@ export class CodeGenerator {
new compiler.DirectiveResolver(staticReflector), new compiler.PipeResolver(staticReflector),
new compiler.ViewResolver(staticReflector), null, null, staticReflector);

return new CodeGenerator(options, ngOptions, program, compilerHost, staticReflector, resolver,
return new CodeGenerator(options, program, compilerHost, staticReflector, resolver,
offlineCompiler, reflectorHost);
}
}
63 changes: 5 additions & 58 deletions modules/@angular/compiler_cli/src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,72 +3,19 @@
// Must be imported first, because angular2 decorators throws on load.
import 'reflect-metadata';

import * as fs from 'fs';
import * as path from 'path';
import * as ts from 'typescript';
import {tsc, check} from './tsc';
import {MetadataWriterHost, TsickleHost} from './compiler_host';
import {NodeReflectorHost} from './reflector_host';
import {CodeGenerator} from './codegen';
import {MetadataCollector, ModuleMetadata} from 'ts-metadata-collector';

const DEBUG = false;

function debug(msg: string, ...o: any[]) {
if (DEBUG) console.log(msg, ...o);
}

export function main(project: string, basePath?: string): Promise<any> {
try {
let projectDir = project;
if (fs.lstatSync(project).isFile()) {
projectDir = path.dirname(project);
}
// file names in tsconfig are resolved relative to this absolute path
basePath = path.join(process.cwd(), basePath || projectDir);

// read the configuration options from wherever you store them
const {parsed, ngOptions} = tsc.readConfiguration(project, basePath);
ngOptions.basePath = basePath;
import * as tsc from 'tsc-wrapped';

const host = ts.createCompilerHost(parsed.options, true);

let codegenStep: Promise<any>;

const program = ts.createProgram(parsed.fileNames, parsed.options, host);
const errors = program.getOptionsDiagnostics();
check(errors);

const doCodegen = ngOptions.skipTemplateCodegen ?
Promise.resolve(null) :
CodeGenerator.create(ngOptions, program, parsed.options, host).codegen();

return doCodegen.then(() => {
tsc.typeCheck(host, program);

// Emit *.js with Decorators lowered to Annotations, and also *.js.map
const tsicklePreProcessor = new TsickleHost(host, parsed.options);
tsc.emit(tsicklePreProcessor, program);
import {CodeGenerator} from './codegen';

if (!ngOptions.skipMetadataEmit) {
// Emit *.metadata.json and *.d.ts
// Not in the same emit pass with above, because tsickle erases
// decorators which we want to read or document.
// Do this emit second since TypeScript will create missing directories for us
// in the standard emit.
const metadataWriter = new MetadataWriterHost(host, program, parsed.options, ngOptions);
tsc.emit(metadataWriter, program);
}
});
} catch (e) {
return Promise.reject(e);
}
function codegen(ngOptions: tsc.AngularCompilerOptions, program: ts.Program, host: ts.CompilerHost) {
return CodeGenerator.create(ngOptions, program, host).codegen();
}

// CLI entry point
if (require.main === module) {
const args = require('minimist')(process.argv.slice(2));
main(args.p || args.project || '.', args.basePath)
tsc.main(args.p || args.project || '.', args.basePath, codegen)
.then(exitCode => process.exit(exitCode))
.catch(e => {
console.error(e.stack);
Expand Down
47 changes: 12 additions & 35 deletions modules/@angular/compiler_cli/src/reflector_host.ts
Original file line number Diff line number Diff line change
@@ -1,35 +1,26 @@
import {StaticReflectorHost, StaticSymbol} from './static_reflector';
import * as ts from 'typescript';
import {MetadataCollector, ModuleMetadata} from 'ts-metadata-collector';
import {AngularCompilerOptions, MetadataCollector, ModuleMetadata} from 'tsc-wrapped';
import * as fs from 'fs';
import * as path from 'path';
import {AngularCompilerOptions} from './codegen';
import {ImportGenerator, AssetUrl} from './compiler_private';
import {ImportGenerator, AssetUrl} from './compiler_private'


const EXT = /(\.ts|\.d\.ts|\.js|\.jsx|\.tsx)$/;
const DTS = /\.d\.ts$/;

export class NodeReflectorHost implements StaticReflectorHost, ImportGenerator {
private metadataCollector = new MetadataCollector();
constructor(private program: ts.Program, private compilerHost: ts.CompilerHost,
private options: ts.CompilerOptions, private ngOptions: AngularCompilerOptions) {}
private options: AngularCompilerOptions) {}

angularImportLocations() {
if (this.ngOptions.legacyPackageLayout) {
return {
coreDecorators: 'angular2/src/core/metadata',
diDecorators: 'angular2/src/core/di/decorators',
diMetadata: 'angular2/src/core/di/metadata',
provider: 'angular2/src/core/di/provider'
};
} else {
return {
coreDecorators: '@angular/core/src/metadata',
diDecorators: '@angular/core/src/di/decorators',
diMetadata: '@angular/core/src/di/metadata',
provider: '@angular/core/src/di/provider'
};
}
return {
coreDecorators: '@angular/core/src/metadata',
diDecorators: '@angular/core/src/di/decorators',
diMetadata: '@angular/core/src/di/metadata',
provider: '@angular/core/src/di/provider'
};
}
private resolve(m: string, containingFile: string) {
const resolved =
Expand Down Expand Up @@ -63,7 +54,7 @@ export class NodeReflectorHost implements StaticReflectorHost, ImportGenerator {
// TODO(tbosch): if a file does not yet exist (because we compile it later),
// we still need to create it so that the `resolve` method works!
if (!this.compilerHost.fileExists(importedFile)) {
if (this.ngOptions.trace) {
if (this.options.trace) {
console.log(`Generating empty file ${importedFile} to allow resolution of import`);
}
this.compilerHost.writeFile(importedFile, '', false);
Expand Down Expand Up @@ -92,7 +83,7 @@ export class NodeReflectorHost implements StaticReflectorHost, ImportGenerator {
throw new Error("Resolution of relative paths requires a containing file.");
}
// Any containing file gives the same result for absolute imports
containingFile = path.join(this.ngOptions.basePath, 'index.ts');
containingFile = path.join(this.options.basePath, 'index.ts');
}

try {
Expand Down Expand Up @@ -175,18 +166,4 @@ export class NodeReflectorHost implements StaticReflectorHost, ImportGenerator {
throw e;
}
}

writeMetadata(emitFilePath: string, sourceFile: ts.SourceFile) {
// TODO: replace with DTS filePath when https://github.com/Microsoft/TypeScript/pull/8412 is
// released
if (/*DTS*/ /\.js$/.test(emitFilePath)) {
const path = emitFilePath.replace(/*DTS*/ /\.js$/, '.metadata.json');
const metadata =
this.metadataCollector.getMetadata(sourceFile, this.program.getTypeChecker());
if (metadata && metadata.metadata) {
const metadataText = JSON.stringify(metadata);
fs.writeFileSync(path, metadataText, {encoding: 'utf-8'});
}
}
}
}
2 changes: 1 addition & 1 deletion modules/@angular/compiler_cli/tsconfig-es5.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
"@angular/compiler": ["../../../dist/packages-dist/compiler"],
"@angular/platform-server": ["../../../dist/packages-dist/platform-server"],
"@angular/platform-browser": ["../../../dist/packages-dist/platform-browser"],
"ts-metadata-collector": ["../../../dist/tools/ts-metadata-collector"]
"tsc-wrapped": ["../../../dist/tools/tsc-wrapped"]
},
"experimentalDecorators": true,
"rootDir": ".",
Expand Down
2 changes: 1 addition & 1 deletion modules/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
"selenium-webdriver": ["./@angular/typings/selenium-webdriver/selenium-webdriver.d.ts"],
"rxjs/*": ["../node_modules/rxjs/*"],
"@angular/*": ["./@angular/*"],
"ts-metadata-collector": ["../dist/tools/ts-metadata-collector"]
"tsc-wrapped": ["../dist/tools/tsc-wrapped"]
},
"rootDir": ".",
"inlineSourceMap": true,
Expand Down
8 changes: 1 addition & 7 deletions scripts/ci-lite/build.sh
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,7 @@ cd ../..

$(npm bin)/tsc -p ./tools/tsconfig.json

# TODO: Right now we have a cycle in that the compiler_cli depends on Angular
# but we need it to compile Angular.
# The solution right now is to do 2 compilation runs.
# Fix this by separating the metadata extraction into a separate binary that does
# not depend on Angular.
$(npm bin)/tsc -p ./modules/tsconfig.json
node dist/all/@angular/compiler_cli/src/main -p modules/tsconfig.json
node dist/tools/tsc-wrapped/src/main -p modules/tsconfig.json

# Compile the compiler_cli integration tests
node dist/all/@angular/compiler_cli/src/main -p modules/@angular/compiler_cli/integrationtest
Expand Down
2 changes: 1 addition & 1 deletion tools/broccoli/broccoli-typescript.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import fse = require('fs-extra');
import path = require('path');
import * as ts from 'typescript';
import {wrapDiffingPlugin, DiffingBroccoliPlugin, DiffResult} from './diffing-broccoli-plugin';
import {MetadataCollector} from '../ts-metadata-collector';
import {MetadataCollector} from '../tsc-wrapped';

type FileRegistry = ts.Map<{version: number}>;

Expand Down
2 changes: 1 addition & 1 deletion tools/build/linknodemodules.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ module.exports = function(gulp, plugins, config) {
symlink(relativeFolder, linkDir);
});
// Also symlink tools we release independently to NPM, so tests can require metadata, etc.
symlink('../../tools/metadata', path.join(nodeModulesDir, 'ts-metadata-collector'));
symlink('../../tools/metadata', path.join(nodeModulesDir, 'tsc-wrapped'));
};
};

Expand Down
15 changes: 0 additions & 15 deletions tools/ts-metadata-collector/README.md

This file was deleted.

2 changes: 0 additions & 2 deletions tools/ts-metadata-collector/index.ts

This file was deleted.

3 changes: 1 addition & 2 deletions tools/tsc-watch/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -93,8 +93,7 @@ if (platform == 'node') {
error: 'error',
complete: 'Compilation complete. Watching for file changes.',
onChangeCmds: [
['node', 'dist/tools/cjs-jasmine/index-tools', '--', 'ts-metadata-collector/**/*{_,.}spec.js'],
['node', 'dist/tools/cjs-jasmine/index-tools', '--', 'public_api_guard/**/*{_,.}spec.js']
['node', 'dist/tools/cjs-jasmine/index-tools', '--', '{public_api_guard,tsc-wrapped}/**/*{_,.}spec.js']
]
});
}
Expand Down
Loading

0 comments on commit 4c26397

Please sign in to comment.