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/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
|
||||
|
|
|
@ -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); }
|
||||
|
|
|
@ -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.
|
||||
|
@ -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 ((<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 === '') {
|
||||
|
@ -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<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';
|
||||
|
||||
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}});
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue