build(node): split test and src compilation units
This commit is contained in:
parent
c785a1e474
commit
a4b5cb8376
|
@ -6,8 +6,6 @@
|
||||||
|
|
||||||
/// <reference path="../typings/zone/zone.d.ts"/>
|
/// <reference path="../typings/zone/zone.d.ts"/>
|
||||||
/// <reference path="../typings/hammerjs/hammerjs.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
|
// TODO: ideally the node.d.ts reference should be scoped only for files that need and not to all
|
||||||
// the code including client code
|
// the code including client code
|
||||||
|
|
|
@ -4,7 +4,8 @@ import {ListWrapper, Map} from 'angular2/src/facade/collection';
|
||||||
|
|
||||||
const _WHEN_DEFAULT = CONST_EXPR(new Object());
|
const _WHEN_DEFAULT = CONST_EXPR(new Object());
|
||||||
|
|
||||||
class SwitchView {
|
/** @internal */
|
||||||
|
export class SwitchView {
|
||||||
constructor(private _viewContainerRef: ViewContainerRef, private _templateRef: TemplateRef) {}
|
constructor(private _viewContainerRef: ViewContainerRef, private _templateRef: TemplateRef) {}
|
||||||
|
|
||||||
create(): void { this._viewContainerRef.createEmbeddedView(this._templateRef); }
|
create(): void { this._viewContainerRef.createEmbeddedView(this._templateRef); }
|
||||||
|
|
|
@ -13,6 +13,26 @@ const FS_OPTS = {
|
||||||
encoding: 'utf-8'
|
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.
|
* Broccoli plugin that implements incremental Typescript compiler.
|
||||||
|
@ -32,6 +52,9 @@ class DiffingTSCompiler implements DiffingBroccoliPlugin {
|
||||||
private tsService: ts.LanguageService;
|
private tsService: ts.LanguageService;
|
||||||
private firstRun: boolean = true;
|
private firstRun: boolean = true;
|
||||||
private previousRunFailed: boolean = false;
|
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 includeExtensions = ['.ts'];
|
||||||
static excludeExtensions = ['.d.ts'];
|
static excludeExtensions = ['.d.ts'];
|
||||||
|
@ -44,11 +67,21 @@ class DiffingTSCompiler implements DiffingBroccoliPlugin {
|
||||||
this.rootFilePaths = [];
|
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
|
// the conversion is a bit awkward, see https://github.com/Microsoft/TypeScript/issues/5276
|
||||||
// in 1.8 use convertCompilerOptionsFromJson
|
// in 1.8 use convertCompilerOptionsFromJson
|
||||||
this.tsOpts =
|
this.tsOpts =
|
||||||
ts.parseJsonConfigFileContent({compilerOptions: options, files: []}, null, null).options;
|
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
|
// 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
|
// check back when we upgrade to 1.7.x
|
||||||
if (this.tsOpts.rootDir === '') {
|
if (this.tsOpts.rootDir === '') {
|
||||||
|
@ -91,6 +124,7 @@ class DiffingTSCompiler implements DiffingBroccoliPlugin {
|
||||||
this.firstRun = false;
|
this.firstRun = false;
|
||||||
this.doFullBuild();
|
this.doFullBuild();
|
||||||
} else {
|
} else {
|
||||||
|
tsEmitInternal = false;
|
||||||
pathsToEmit.forEach((tsFilePath) => {
|
pathsToEmit.forEach((tsFilePath) => {
|
||||||
let output = this.tsService.getEmitOutput(tsFilePath);
|
let output = this.tsService.getEmitOutput(tsFilePath);
|
||||||
|
|
||||||
|
@ -117,11 +151,26 @@ class DiffingTSCompiler implements DiffingBroccoliPlugin {
|
||||||
throw error;
|
throw error;
|
||||||
} else if (this.previousRunFailed) {
|
} else if (this.previousRunFailed) {
|
||||||
this.doFullBuild();
|
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 {
|
private collectErrors(tsFilePath): String {
|
||||||
let allDiagnostics = this.tsService.getCompilerOptionsDiagnostics()
|
let allDiagnostics = this.tsService.getCompilerOptionsDiagnostics()
|
||||||
.concat(this.tsService.getSyntacticDiagnostics(tsFilePath))
|
.concat(this.tsService.getSyntacticDiagnostics(tsFilePath))
|
||||||
|
@ -143,14 +192,27 @@ class DiffingTSCompiler implements DiffingBroccoliPlugin {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private doFullBuild() {
|
private doFullBuild() {
|
||||||
let program = this.tsService.getProgram();
|
let program = this.tsService.getProgram();
|
||||||
|
|
||||||
|
tsEmitInternal = false;
|
||||||
let emitResult = program.emit(undefined, (absoluteFilePath, fileContent) => {
|
let emitResult = program.emit(undefined, (absoluteFilePath, fileContent) => {
|
||||||
fse.mkdirsSync(path.dirname(absoluteFilePath));
|
fse.mkdirsSync(path.dirname(absoluteFilePath));
|
||||||
fs.writeFileSync(absoluteFilePath, this.fixSourceMapSources(fileContent), FS_OPTS);
|
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) {
|
if (emitResult.emitSkipped) {
|
||||||
let allDiagnostics = ts.getPreEmitDiagnostics(program).concat(emitResult.diagnostics);
|
let allDiagnostics = ts.getPreEmitDiagnostics(program).concat(emitResult.diagnostics);
|
||||||
let errorMessages = [];
|
let errorMessages = [];
|
||||||
|
@ -293,5 +355,16 @@ class CustomLanguageServiceHost implements ts.LanguageServiceHost {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
export default wrapDiffingPlugin(DiffingTSCompiler);
|
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;
|
||||||
|
}
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
import destCopy from '../broccoli-dest-copy';
|
import destCopy from '../broccoli-dest-copy';
|
||||||
import compileWithTypescript from '../broccoli-typescript';
|
import compileWithTypescript, { INTERNAL_TYPINGS_PATH }
|
||||||
|
from '../broccoli-typescript';
|
||||||
var Funnel = require('broccoli-funnel');
|
var Funnel = require('broccoli-funnel');
|
||||||
import mergeTrees from '../broccoli-merge-trees';
|
import mergeTrees from '../broccoli-merge-trees';
|
||||||
var path = require('path');
|
var path = require('path');
|
||||||
|
@ -11,13 +12,47 @@ var stew = require('broccoli-stew');
|
||||||
|
|
||||||
var projectRootDir = path.normalize(path.join(__dirname, '..', '..', '..', '..'));
|
var projectRootDir = path.normalize(path.join(__dirname, '..', '..', '..', '..'));
|
||||||
|
|
||||||
|
|
||||||
module.exports = function makeNodeTree(projects, destinationPath) {
|
module.exports = function makeNodeTree(projects, destinationPath) {
|
||||||
// list of npm packages that this build will create
|
// list of npm packages that this build will create
|
||||||
var outputPackages = ['angular2', 'benchpress'];
|
var outputPackages = ['angular2', 'benchpress'];
|
||||||
|
|
||||||
var modulesTree = new Funnel('modules', {
|
let srcTree = new Funnel('modules', {
|
||||||
include: ['angular2/**', 'benchpress/**', '**/e2e_test/**'],
|
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: [
|
exclude: [
|
||||||
// the following code and tests are not compatible with CJS/node environment
|
// the following code and tests are not compatible with CJS/node environment
|
||||||
'angular2/test/animate/**',
|
'angular2/test/animate/**',
|
||||||
|
@ -41,58 +76,48 @@ module.exports = function makeNodeTree(projects, destinationPath) {
|
||||||
'angular2/test/upgrade/**/*.ts',
|
'angular2/test/upgrade/**/*.ts',
|
||||||
|
|
||||||
'angular1_router/**',
|
'angular1_router/**',
|
||||||
'angular2/examples/**/!(*_spec.ts)',
|
|
||||||
]
|
]
|
||||||
});
|
});
|
||||||
|
|
||||||
var typescriptTree = compileWithTypescript(modulesTree, {
|
// Compile the tests against the src @internal .d.ts
|
||||||
emitDecoratorMetadata: true,
|
let srcPrivateDeclarations =
|
||||||
experimentalDecorators: true,
|
new Funnel(compiledSrcTreeWithInternals, {srcDir: INTERNAL_TYPINGS_PATH});
|
||||||
declaration: true,
|
|
||||||
stripInternal: true,
|
testTree = mergeTrees([testTree, srcPrivateDeclarations]);
|
||||||
module: 'commonjs',
|
|
||||||
moduleResolution: 'classic',
|
let compiledTestTree = compileTree(testTree, false, [
|
||||||
noEmitOnError: true,
|
'angular2/typings/jasmine/jasmine.d.ts',
|
||||||
rootDir: '.',
|
'angular2/typings/angular-protractor/angular-protractor.d.ts',
|
||||||
rootFilePaths:
|
'angular2/manual_typings/globals.d.ts'
|
||||||
['angular2/manual_typings/globals.d.ts', 'angular2/typings/es6-shim/es6-shim.d.ts'],
|
]);
|
||||||
inlineSourceMap: true,
|
|
||||||
inlineSources: true,
|
// Merge the compiled sources and tests
|
||||||
target: 'es5'
|
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
|
// Now we add the LICENSE file into all the folders that will become npm packages
|
||||||
outputPackages.forEach(function(destDir) {
|
outputPackages.forEach(function(destDir) {
|
||||||
var license = new Funnel('.', {files: ['LICENSE'], destDir: 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
|
// Get all docs and related assets and prepare them for js build
|
||||||
var docs = new Funnel(modulesTree, {include: ['**/*.md', '**/*.png'], exclude: ['**/*.dart.md']});
|
var srcDocs = extractDocs(srcTree);
|
||||||
docs = stew.rename(docs, 'README.js.md', 'README.md');
|
var testDocs = extractDocs(testTree);
|
||||||
|
|
||||||
// Generate shared package.json info
|
|
||||||
var BASE_PACKAGE_JSON = require(path.join(projectRootDir, 'package.json'));
|
var BASE_PACKAGE_JSON = require(path.join(projectRootDir, 'package.json'));
|
||||||
var COMMON_PACKAGE_JSON = {
|
var srcPkgJsons = extractPkgJsons(srcTree, BASE_PACKAGE_JSON);
|
||||||
version: BASE_PACKAGE_JSON.version,
|
var testPkgJsons = extractPkgJsons(testTree, BASE_PACKAGE_JSON);
|
||||||
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 typingsTree = new Funnel(
|
var typingsTree = new Funnel(
|
||||||
'modules',
|
'modules',
|
||||||
{include: ['angular2/typings/**/*.d.ts', 'angular2/manual_typings/*.d.ts'], destDir: '/'});
|
{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
|
// Transform all tests to make them runnable in node
|
||||||
nodeTree = replace(nodeTree, {
|
nodeTree = replace(nodeTree, {
|
||||||
|
@ -132,3 +157,46 @@ module.exports = function makeNodeTree(projects, destinationPath) {
|
||||||
|
|
||||||
return destCopy(nodeTree, 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}});
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue