refactor(view_compiler): codegen DI and Queries

BREAKING CHANGE:
- Renderer:
  * renderComponent method is removed form `Renderer`, only present on `RootRenderer`
  * Renderer.setDebugInfo is removed. Renderer.createElement / createText / createTemplateAnchor
    now take the DebugInfo directly.
- Query semantics:
  * Queries don't work with dynamically loaded components.
  * e.g. for router-outlet: loaded components can't be queries via @ViewQuery,
    but router-outlet emits an event `activate` now that emits the activated component
- Exception classes and the context inside changed (renamed fields)
- DebugElement.attributes is an Object and not a Map in JS any more
- ChangeDetectorGenConfig was renamed into CompilerConfig
- AppViewManager.createEmbeddedViewInContainer / AppViewManager.createHostViewInContainer
  are removed, use the methods in ViewContainerRef instead
- Change detection order changed:
  * 1. dirty check component inputs
  * 2. dirty check content children
  * 3. update render nodes

Closes #6301
Closes #6567
This commit is contained in:
Tobias Bosch
2016-01-06 14:13:44 -08:00
parent 45f09ba686
commit 2b34c88b69
312 changed files with 14271 additions and 16566 deletions

View File

@ -17,7 +17,8 @@ class CheckImports implements DiffingBroccoliPlugin {
"angular2/src/facade": ["rxjs"],
"angular2/src/common": ["angular2/core", "angular2/src/facade"],
"angular2/src/http": ["angular2/core", "angular2/src/facade", "rxjs"],
"angular2/src/upgrade": ["angular2/core", "angular2/src/facade", "angular2/platform/browser"]
"angular2/src/upgrade":
["angular2/core", "angular2/src/facade", "angular2/platform/browser", "angular2/compiler"]
//"angular2/src/render": [
// "angular2/animate",
// "angular2/core",

View File

@ -0,0 +1,81 @@
import fs = require('fs');
import fse = require('fs-extra');
import path = require('path');
import childProcess = require('child_process');
var glob = require('glob');
import {wrapDiffingPlugin, DiffingBroccoliPlugin, DiffResult} from './diffing-broccoli-plugin';
/**
* Intercepts each changed file and replaces its contents with
* the output of the generator.
*/
class GeneratorForTest implements DiffingBroccoliPlugin {
private seenFiles: {[key: string]: boolean} = {};
constructor(private inputPath, private outputPath, private options) {}
rebuild(treeDiff: DiffResult) {
var matchedFiles = [];
this.options.files.forEach(
(file) => { matchedFiles = matchedFiles.concat(glob.sync(file, {cwd: this.inputPath})); });
return Promise.all(matchedFiles.map((matchedFile) => {
var inputFilePath = path.join(this.inputPath, matchedFile);
var outputFilePath = path.join(this.outputPath, matchedFile);
var outputDirPath = path.dirname(outputFilePath);
if (!fs.existsSync(outputDirPath)) {
fse.mkdirpSync(outputDirPath);
}
return this.invokeGenerator(matchedFile, inputFilePath, outputFilePath)
}))
.then(() => {
var result = new DiffResult();
matchedFiles.forEach((file) => {
if (!this.seenFiles[file]) {
result.addedPaths.push(file);
this.seenFiles[file] = true;
} else {
result.changedPaths.push(file);
}
});
return result;
});
}
private invokeGenerator(file: string, inputFilePath: string,
outputFilePath: string): Promise<any> {
return new Promise((resolve, reject) => {
var args;
var vmPath;
var env;
if (this.options.dartPath) {
vmPath = this.options.dartPath;
args = [`--package-root=${this.inputPath}`, '--checked', inputFilePath, file];
env = {};
} else {
vmPath = process.execPath;
var script = `require('reflect-metadata');require('${inputFilePath}').main(['${file}']);`;
args = ['-e', script];
env = {'NODE_PATH': this.inputPath};
}
var stdoutStream = fs.createWriteStream(outputFilePath);
var proc = childProcess.spawn(
vmPath, args,
{stdio: ['ignore', 'pipe', 'inherit'], env: Object['assign']({}, process.env, env)});
proc.on('error', function(code) {
console.error(code);
reject(new Error('Failed while generating code. Please run manually: ' + vmPath + ' ' +
args.join(' ')));
});
proc.on('close', function() {
stdoutStream.close();
resolve();
});
proc.stdout.pipe(stdoutStream);
});
}
}
export default wrapDiffingPlugin(GeneratorForTest);

View File

@ -12,6 +12,7 @@ import ts2dart from '../broccoli-ts2dart';
import dartfmt from '../broccoli-dartfmt';
import replace from '../broccoli-replace';
import {AngularBuilderOptions} from '../angular_builder';
import generateForTest from '../broccoli-generate-for-test';
var global_excludes = [
'angular2/examples/**/ts/**/*',
@ -61,17 +62,26 @@ function stripModulePrefix(relativePath: string): string {
return relativePath.replace(/^modules\//, '');
}
function getSourceTree() {
function getSourceTree(options: AngularBuilderOptions) {
var tsInputTree = modulesFunnel(['**/*.js', '**/*.ts', '**/*.dart'], ['angular1_router/**/*']);
var transpiled = ts2dart(tsInputTree, {
generateLibraryName: true,
generateSourceMap: false,
translateBuiltins: true,
});
// Native sources, dart only examples, etc.
var dartSrcs = modulesFunnel(
['**/*.dart', '**/*.ng_meta.json', '**/*.aliases.json', '**/css/**', '**/*.css']);
return mergeTrees([transpiled, dartSrcs]);
var compiledTree = mergeTrees([transpiled, dartSrcs]);
// Generate test files
let generatedDartTestFiles = generateForTest(
mergeTrees([compiledTree, new Funnel('packages', {include: ['path/**', 'stack_trace/**']})]),
{files: ['*/test/**/*_codegen_typed.dart'], dartPath: options.dartSDK.VM});
return mergeTrees([compiledTree, generatedDartTestFiles], {overwrite: true});
}
function fixDartFolderLayout(sourceTree) {
@ -169,7 +179,7 @@ function getDocsTree() {
}
module.exports = function makeDartTree(options: AngularBuilderOptions) {
var dartSources = dartfmt(getSourceTree(), {dartSDK: options.dartSDK, logs: options.logs});
var dartSources = dartfmt(getSourceTree(options), {dartSDK: options.dartSDK, logs: options.logs});
var sourceTree = mergeTrees([dartSources, getHtmlSourcesTree(), getExamplesJsonTree()]);
sourceTree = fixDartFolderLayout(sourceTree);

View File

@ -8,6 +8,7 @@ import mergeTrees from '../broccoli-merge-trees';
var path = require('path');
import renderLodashTemplate from '../broccoli-lodash';
import replace from '../broccoli-replace';
import generateForTest from '../broccoli-generate-for-test';
var stew = require('broccoli-stew');
var writeFile = require('broccoli-file-creator');
@ -120,16 +121,41 @@ module.exports = function makeNodeTree(projects, destinationPath) {
let compiledTree = mergeTrees([compiledSrcTree, compiledTestTree]);
// Generate test files
let generatedJsTestFiles =
generateForTest(compiledTree, {files: ['*/test/**/*_codegen_untyped.js']});
let generatedTsTestFiles = stew.rename(
generateForTest(compiledTree, {files: ['*/test/**/*_codegen_typed.js']}), /.js$/, '.ts');
// Compile generated test files against the src @internal .d.ts and the test files
compiledTree = mergeTrees(
[
compiledTree,
generatedJsTestFiles,
compileTree(
new Funnel(
mergeTrees([
packageTypings,
new Funnel('modules',
{include: ['angular2/manual_typings/**', 'angular2/typings/**']}),
generatedTsTestFiles,
srcPrivateDeclarations,
compiledTestTree
]),
{include: ['angular2/**', 'rxjs/**', 'zone.js/**']}),
false, [])
],
{overwrite: true});
// Down-level .d.ts files to be TS 1.8 compatible
// TODO(alexeagle): this can be removed once we drop support for using Angular 2 with TS 1.8
compiledTree = replace(compiledTree, {
files: ['**/*.d.ts'],
patterns: [
{match: /^(\s*(static\s+)?)readonly\s+/mg, replacement: "$1"},
{match: /^(\s*(static\s+|private\s+)*)readonly\s+/mg, replacement: "$1"},
]
});
// 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});