diff --git a/modules/angular2/manual_typings/globals-es6.d.ts b/modules/angular2/manual_typings/globals-es6.d.ts
index c6e348aa79..703f7de009 100644
--- a/modules/angular2/manual_typings/globals-es6.d.ts
+++ b/modules/angular2/manual_typings/globals-es6.d.ts
@@ -6,8 +6,6 @@
///
///
-///
-///
// TODO: ideally the node.d.ts reference should be scoped only for files that need and not to all
// the code including client code
diff --git a/modules/angular2/src/common/directives/ng_switch.ts b/modules/angular2/src/common/directives/ng_switch.ts
index a25cb70a08..469a9dbca2 100644
--- a/modules/angular2/src/common/directives/ng_switch.ts
+++ b/modules/angular2/src/common/directives/ng_switch.ts
@@ -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); }
diff --git a/tools/broccoli/broccoli-typescript.ts b/tools/broccoli/broccoli-typescript.ts
index ff57205306..1913d02c50 100644
--- a/tools/broccoli/broccoli-typescript.ts
+++ b/tools/broccoli/broccoli-typescript.ts
@@ -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 = (ts).emitFiles;
+
+(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.
@@ -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'];
@@ -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 ((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 === '') {
@@ -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);
@@ -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))
@@ -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 = [];
@@ -293,5 +355,16 @@ class CustomLanguageServiceHost implements ts.LanguageServiceHost {
}
}
-
export default wrapDiffingPlugin(DiffingTSCompiler);
+
+function clone(object: T): T {
+ const result: any = {};
+ for (const id in object) {
+ result[id] = (object)[id];
+ }
+ return result;
+}
+
+function endsWith(str: string, substring: string): boolean {
+ return str.indexOf(substring, str.length - substring.length) !== -1;
+}
diff --git a/tools/broccoli/trees/node_tree.ts b/tools/broccoli/trees/node_tree.ts
index 50fd5fb37e..9b5c40e5d1 100644
--- a/tools/broccoli/trees/node_tree.ts
+++ b/tools/broccoli/trees/node_tree.ts
@@ -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');
@@ -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/**',
@@ -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, {
@@ -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}});
+}