Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 0 additions & 2 deletions modules/angular2/manual_typings/globals-es6.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,6 @@

/// <reference path="../typings/zone/zone.d.ts"/>
/// <reference path="../typings/hammerjs/hammerjs.d.ts"/>
/// <reference path="../typings/jasmine/jasmine.d.ts"/>
/// <reference path="../typings/angular-protractor/angular-protractor.d.ts"/>

// TODO: ideally the node.d.ts reference should be scoped only for files that need and not to all
// the code including client code
Expand Down
3 changes: 2 additions & 1 deletion modules/angular2/src/common/directives/ng_switch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ import {ListWrapper, Map} from 'angular2/src/facade/collection';

const _WHEN_DEFAULT = CONST_EXPR(new Object());

class SwitchView {
/** @internal */
export class SwitchView {
constructor(private _viewContainerRef: ViewContainerRef, private _templateRef: TemplateRef) {}

create(): void { this._viewContainerRef.createEmbeddedView(this._templateRef); }
Expand Down
79 changes: 76 additions & 3 deletions tools/broccoli/broccoli-typescript.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,26 @@ const FS_OPTS = {
encoding: 'utf-8'
};

// Sub-directory where the @internal typing files (.d.ts) are stored
export const INTERNAL_TYPINGS_PATH: string = 'internal_typings';

// Monkey patch the TS compiler to be able to re-emit files with @internal symbols
let tsEmitInternal: boolean = false;

const originalEmitFiles: Function = (<any>ts).emitFiles;

(<any>ts).emitFiles = function(resolver: any, host: any, targetSourceFile: any): any {
if (tsEmitInternal) {
const orignalgetCompilerOptions = host.getCompilerOptions;
host.getCompilerOptions = () => {
let options = clone(orignalgetCompilerOptions.call(host));
options.stripInternal = false;
options.outDir = `${options.outDir}/${INTERNAL_TYPINGS_PATH}`;
return options;
}
}
return originalEmitFiles(resolver, host, targetSourceFile);
};

/**
* Broccoli plugin that implements incremental Typescript compiler.
Expand All @@ -32,6 +52,9 @@ class DiffingTSCompiler implements DiffingBroccoliPlugin {
private tsService: ts.LanguageService;
private firstRun: boolean = true;
private previousRunFailed: boolean = false;
// Whether to generate the @internal typing files (they are only generated when `stripInternal` is
// true)
private genInternalTypings: boolean = false;

static includeExtensions = ['.ts'];
static excludeExtensions = ['.d.ts'];
Expand All @@ -44,11 +67,21 @@ class DiffingTSCompiler implements DiffingBroccoliPlugin {
this.rootFilePaths = [];
}

if (options.internalTypings) {
this.genInternalTypings = true;
delete options.internalTypings;
}

// the conversion is a bit awkward, see https://github.com/Microsoft/TypeScript/issues/5276
// in 1.8 use convertCompilerOptionsFromJson
this.tsOpts =
ts.parseJsonConfigFileContent({compilerOptions: options, files: []}, null, null).options;

if ((<any>this.tsOpts).stripInternal === false) {
// @internal are included in the generated .d.ts, do not generate them separately
this.genInternalTypings = false;
}

// TODO: the above turns rootDir set to './' into an empty string - looks like a tsc bug
// check back when we upgrade to 1.7.x
if (this.tsOpts.rootDir === '') {
Expand Down Expand Up @@ -91,6 +124,7 @@ class DiffingTSCompiler implements DiffingBroccoliPlugin {
this.firstRun = false;
this.doFullBuild();
} else {
tsEmitInternal = false;
pathsToEmit.forEach((tsFilePath) => {
let output = this.tsService.getEmitOutput(tsFilePath);

Expand All @@ -117,11 +151,26 @@ class DiffingTSCompiler implements DiffingBroccoliPlugin {
throw error;
} else if (this.previousRunFailed) {
this.doFullBuild();
} else if (this.genInternalTypings) {
// serialize the .d.ts files containing @internal symbols
tsEmitInternal = true;
pathsToEmit.forEach((tsFilePath) => {
let output = this.tsService.getEmitOutput(tsFilePath);
if (!output.emitSkipped) {
output.outputFiles.forEach(o => {
if (endsWith(o.name, '.d.ts')) {
let destDirPath = path.dirname(o.name);
fse.mkdirsSync(destDirPath);
fs.writeFileSync(o.name, this.fixSourceMapSources(o.text), FS_OPTS);
}
});
}
});
tsEmitInternal = false;
}
}
}


private collectErrors(tsFilePath): String {
let allDiagnostics = this.tsService.getCompilerOptionsDiagnostics()
.concat(this.tsService.getSyntacticDiagnostics(tsFilePath))
Expand All @@ -143,14 +192,27 @@ class DiffingTSCompiler implements DiffingBroccoliPlugin {
}
}


private doFullBuild() {
let program = this.tsService.getProgram();

tsEmitInternal = false;
let emitResult = program.emit(undefined, (absoluteFilePath, fileContent) => {
fse.mkdirsSync(path.dirname(absoluteFilePath));
fs.writeFileSync(absoluteFilePath, this.fixSourceMapSources(fileContent), FS_OPTS);
});

if (this.genInternalTypings) {
// serialize the .d.ts files containing @internal symbols
tsEmitInternal = true;
program.emit(undefined, (absoluteFilePath, fileContent) => {
if (endsWith(absoluteFilePath, '.d.ts')) {
fse.mkdirsSync(path.dirname(absoluteFilePath));
fs.writeFileSync(absoluteFilePath, fileContent, FS_OPTS);
}
});
tsEmitInternal = false;
}

if (emitResult.emitSkipped) {
let allDiagnostics = ts.getPreEmitDiagnostics(program).concat(emitResult.diagnostics);
let errorMessages = [];
Expand Down Expand Up @@ -293,5 +355,16 @@ class CustomLanguageServiceHost implements ts.LanguageServiceHost {
}
}


export default wrapDiffingPlugin(DiffingTSCompiler);

function clone<T>(object: T): T {
const result: any = {};
for (const id in object) {
result[id] = (<any>object)[id];
}
return <T>result;
}

function endsWith(str: string, substring: string): boolean {
return str.indexOf(substring, str.length - substring.length) !== -1;
}
148 changes: 108 additions & 40 deletions tools/broccoli/trees/node_tree.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
'use strict';

import destCopy from '../broccoli-dest-copy';
import compileWithTypescript from '../broccoli-typescript';
import compileWithTypescript, { INTERNAL_TYPINGS_PATH }
from '../broccoli-typescript';
var Funnel = require('broccoli-funnel');
import mergeTrees from '../broccoli-merge-trees';
var path = require('path');
Expand All @@ -11,13 +12,47 @@ var stew = require('broccoli-stew');

var projectRootDir = path.normalize(path.join(__dirname, '..', '..', '..', '..'));


module.exports = function makeNodeTree(projects, destinationPath) {
// list of npm packages that this build will create
var outputPackages = ['angular2', 'benchpress'];

var modulesTree = new Funnel('modules', {
include: ['angular2/**', 'benchpress/**', '**/e2e_test/**'],
let srcTree = new Funnel('modules', {
include: ['angular2/**'],
exclude: [
'**/e2e_test/**',
'angular2/test/**',
'angular2/examples/**',

'angular2/src/testing/**',
'angular2/testing.ts',
'angular2/testing_internal.ts',
'angular2/src/upgrade/**',
'angular2/upgrade.ts',
'angular2/platform/testing/**',
]
});

// Compile the sources and generate the @internal .d.ts
let compiledSrcTreeWithInternals =
compileTree(srcTree, true, ['angular2/manual_typings/globals.d.ts']);

var testTree = new Funnel('modules', {
include: [
'angular2/manual_typings/**',
'angular2/typings/**',

'angular2/test/**',
'benchpress/**',
'**/e2e_test/**',
'angular2/examples/**/*_spec.ts',

'angular2/src/testing/**',
'angular2/testing.ts',
'angular2/testing_internal.ts',
'angular2/src/upgrade/**',
'angular2/upgrade.ts',
'angular2/platform/testing/**',
],
exclude: [
// the following code and tests are not compatible with CJS/node environment
'angular2/test/animate/**',
Expand All @@ -41,58 +76,48 @@ module.exports = function makeNodeTree(projects, destinationPath) {
'angular2/test/upgrade/**/*.ts',

'angular1_router/**',
'angular2/examples/**/!(*_spec.ts)',
]
});

var typescriptTree = compileWithTypescript(modulesTree, {
emitDecoratorMetadata: true,
experimentalDecorators: true,
declaration: true,
stripInternal: true,
module: 'commonjs',
moduleResolution: 'classic',
noEmitOnError: true,
rootDir: '.',
rootFilePaths:
['angular2/manual_typings/globals.d.ts', 'angular2/typings/es6-shim/es6-shim.d.ts'],
inlineSourceMap: true,
inlineSources: true,
target: 'es5'
});
// Compile the tests against the src @internal .d.ts
let srcPrivateDeclarations =
new Funnel(compiledSrcTreeWithInternals, {srcDir: INTERNAL_TYPINGS_PATH});

testTree = mergeTrees([testTree, srcPrivateDeclarations]);

let compiledTestTree = compileTree(testTree, false, [
'angular2/typings/jasmine/jasmine.d.ts',
'angular2/typings/angular-protractor/angular-protractor.d.ts',
'angular2/manual_typings/globals.d.ts'
]);

// Merge the compiled sources and tests
let compiledSrcTree =
new Funnel(compiledSrcTreeWithInternals, {exclude: [`${INTERNAL_TYPINGS_PATH}/**`]});

let compiledTree = mergeTrees([compiledSrcTree, compiledTestTree]);

// Now we add the LICENSE file into all the folders that will become npm packages
outputPackages.forEach(function(destDir) {
var license = new Funnel('.', {files: ['LICENSE'], destDir: destDir});
typescriptTree = mergeTrees([typescriptTree, license]);
// merge the test tree
compiledTree = mergeTrees([compiledTree, license]);
});

// Get all docs and related assets and prepare them for js build
var docs = new Funnel(modulesTree, {include: ['**/*.md', '**/*.png'], exclude: ['**/*.dart.md']});
docs = stew.rename(docs, 'README.js.md', 'README.md');
var srcDocs = extractDocs(srcTree);
var testDocs = extractDocs(testTree);

// Generate shared package.json info
var BASE_PACKAGE_JSON = require(path.join(projectRootDir, 'package.json'));
var COMMON_PACKAGE_JSON = {
version: BASE_PACKAGE_JSON.version,
homepage: BASE_PACKAGE_JSON.homepage,
bugs: BASE_PACKAGE_JSON.bugs,
license: BASE_PACKAGE_JSON.license,
repository: BASE_PACKAGE_JSON.repository,
contributors: BASE_PACKAGE_JSON.contributors,
dependencies: BASE_PACKAGE_JSON.dependencies,
devDependencies: BASE_PACKAGE_JSON.devDependencies,
defaultDevDependencies: {}
};

var packageJsons = new Funnel(modulesTree, {include: ['**/package.json']});
packageJsons =
renderLodashTemplate(packageJsons, {context: {'packageJson': COMMON_PACKAGE_JSON}});
var srcPkgJsons = extractPkgJsons(srcTree, BASE_PACKAGE_JSON);
var testPkgJsons = extractPkgJsons(testTree, BASE_PACKAGE_JSON);

var typingsTree = new Funnel(
'modules',
{include: ['angular2/typings/**/*.d.ts', 'angular2/manual_typings/*.d.ts'], destDir: '/'});
var nodeTree = mergeTrees([typescriptTree, docs, packageJsons, typingsTree]);

var nodeTree =
mergeTrees([compiledTree, srcDocs, testDocs, srcPkgJsons, testPkgJsons, typingsTree]);

// Transform all tests to make them runnable in node
nodeTree = replace(nodeTree, {
Expand Down Expand Up @@ -132,3 +157,46 @@ module.exports = function makeNodeTree(projects, destinationPath) {

return destCopy(nodeTree, destinationPath);
};

function compileTree(tree, genInternalTypings, rootFilePaths: string[] = []) {
return compileWithTypescript(tree, {
// build pipeline options
"rootFilePaths": rootFilePaths,
"internalTypings": genInternalTypings,
// tsc options
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"declaration": true,
"stripInternal": true,
"module": "commonjs",
"moduleResolution": "classic",
"noEmitOnError": true,
"rootDir": ".",
"inlineSourceMap": true,
"inlineSources": true,
"target": "es5"
});
}

function extractDocs(tree) {
var docs = new Funnel(tree, {include: ['**/*.md', '**/*.png'], exclude: ['**/*.dart.md']});
return stew.rename(docs, 'README.js.md', 'README.md');
}

function extractPkgJsons(tree, BASE_PACKAGE_JSON) {
// Generate shared package.json info
var COMMON_PACKAGE_JSON = {
version: BASE_PACKAGE_JSON.version,
homepage: BASE_PACKAGE_JSON.homepage,
bugs: BASE_PACKAGE_JSON.bugs,
license: BASE_PACKAGE_JSON.license,
repository: BASE_PACKAGE_JSON.repository,
contributors: BASE_PACKAGE_JSON.contributors,
dependencies: BASE_PACKAGE_JSON.dependencies,
devDependencies: BASE_PACKAGE_JSON.devDependencies,
defaultDevDependencies: {}
};

var packageJsons = new Funnel(tree, {include: ['**/package.json']});
return renderLodashTemplate(packageJsons, {context: {'packageJson': COMMON_PACKAGE_JSON}});
}