refactor(dart/transform): Use render Compiler concepts

Update `TemplateCompiler` transform step to use abstractions used by the
render `Compiler`. For example, template code is now loaded via an
instance of `TemplateLoader` and external resources are fetched via an
instance of `XHR`.
This commit is contained in:
Tim Blasi 2015-05-01 17:29:58 -07:00
parent abc3de7efe
commit 169e4e862d
5 changed files with 111 additions and 76 deletions

View File

@ -296,7 +296,9 @@ class BrowserDomAdapter extends GenericBrowserDomAdapter {
}
String getEventKey(KeyboardEvent event) {
int keyCode = event.keyCode;
return _keyCodeToKeyMap.containsKey(keyCode) ? _keyCodeToKeyMap[keyCode] : 'Unidentified';
return _keyCodeToKeyMap.containsKey(keyCode)
? _keyCodeToKeyMap[keyCode]
: 'Unidentified';
}
getGlobalEventTarget(String target) {
if (target == "window") {

View File

@ -168,9 +168,8 @@ class Html5LibDomAdapter implements DomAdapter {
getHost(el) {
throw 'not implemented';
}
clone(node) {
throw 'not implemented';
}
clone(node) => node.clone(true);
hasProperty(element, String name) {
throw 'not implemented';
}

View File

@ -0,0 +1,26 @@
library angular2.transform.template_compiler.compile_step_factory;
import 'dart:async';
import 'package:angular2/src/change_detection/parser/parser.dart' as ng;
import 'package:angular2/src/render/api.dart';
import 'package:angular2/src/render/dom/compiler/compile_step.dart';
import 'package:angular2/src/render/dom/compiler/compile_step_factory.dart'
as base;
import 'package:angular2/src/render/dom/compiler/property_binding_parser.dart';
import 'package:angular2/src/render/dom/compiler/text_interpolation_parser.dart';
import 'package:angular2/src/render/dom/compiler/view_splitter.dart';
class CompileStepFactory implements base.CompileStepFactory {
final ng.Parser _parser;
CompileStepFactory(this._parser);
List<CompileStep> createSteps(
ViewDefinition template, List<Future> subTaskPromises) {
// TODO(kegluneq): Add other compile steps from default_steps.dart.
return [
new ViewSplitter(_parser),
new PropertyBindingParser(_parser),
new TextInterpolationParser(_parser)
];
}
}

View File

@ -5,22 +5,22 @@ import 'dart:async';
import 'package:analyzer/analyzer.dart';
import 'package:angular2/src/change_detection/parser/lexer.dart' as ng;
import 'package:angular2/src/change_detection/parser/parser.dart' as ng;
import 'package:angular2/src/render/api.dart';
import 'package:angular2/src/render/dom/compiler/compile_pipeline.dart';
import 'package:angular2/src/render/dom/compiler/compile_step.dart';
import 'package:angular2/src/render/dom/compiler/property_binding_parser.dart';
import 'package:angular2/src/render/dom/compiler/text_interpolation_parser.dart';
import 'package:angular2/src/render/dom/compiler/view_splitter.dart';
import 'package:angular2/src/dom/dom_adapter.dart';
import 'package:angular2/src/render/dom/compiler/template_loader.dart';
import "package:angular2/src/services/xhr.dart" show XHR;
import 'package:angular2/src/reflection/reflection.dart';
import 'package:angular2/src/services/url_resolver.dart';
import 'package:angular2/src/transform/common/asset_reader.dart';
import 'package:angular2/src/transform/common/logging.dart';
import 'package:angular2/src/transform/common/names.dart';
import 'package:angular2/src/transform/common/parser.dart';
import 'package:angular2/src/transform/common/property_utils.dart' as prop;
import 'package:barback/barback.dart';
import 'package:code_transformers/assets.dart';
import 'compile_step_factory.dart';
import 'recording_reflection_capabilities.dart';
import 'xhr_impl.dart';
/// Reads the `.ng_deps.dart` file represented by `entryPoint` and parses any
/// Angular 2 `View` annotations it declares to generate `getter`s,
@ -30,28 +30,27 @@ import 'recording_reflection_capabilities.dart';
Future<String> processTemplates(AssetReader reader, AssetId entryPoint) async {
var parser = new Parser(reader);
NgDeps ngDeps = await parser.parse(entryPoint);
var extractor = new _TemplateExtractor(reader, entryPoint);
var extractor = new _TemplateExtractor(new XhrImpl(reader, entryPoint));
var registrations = new StringBuffer();
for (var rType in ngDeps.registeredTypes) {
(await extractor.extractTemplates(rType))
.forEach((RecordingReflectionCapabilities values) {
var calls = _generateGetters('${rType.typeName}', values.getterNames);
if (calls.isNotEmpty) {
registrations.write('..${REGISTER_GETTERS_METHOD_NAME}'
'({${calls.join(', ')}})');
}
calls = _generateSetters('${rType.typeName}', values.setterNames);
if (calls.isNotEmpty) {
registrations.write('..${REGISTER_SETTERS_METHOD_NAME}'
'({${calls.join(', ')}})');
}
calls = _generateMethods('${rType.typeName}', values.methodNames);
if (calls.isNotEmpty) {
registrations.write('..${REGISTER_METHODS_METHOD_NAME}'
'({${calls.join(', ')}})');
}
});
var values = await extractor.extractTemplates(rType);
if (values == null) continue;
var calls = _generateGetters('${rType.typeName}', values.getterNames);
if (calls.isNotEmpty) {
registrations.write('..${REGISTER_GETTERS_METHOD_NAME}'
'({${calls.join(', ')}})');
}
calls = _generateSetters('${rType.typeName}', values.setterNames);
if (calls.isNotEmpty) {
registrations.write('..${REGISTER_SETTERS_METHOD_NAME}'
'({${calls.join(', ')}})');
}
calls = _generateMethods('${rType.typeName}', values.methodNames);
if (calls.isNotEmpty) {
registrations.write('..${REGISTER_METHODS_METHOD_NAME}'
'({${calls.join(', ')}})');
}
}
var code = ngDeps.code;
@ -105,75 +104,52 @@ Iterable<String> _generateMethods(
/// template code if necessary, and determines what values will be
/// reflectively accessed from that template.
class _TemplateExtractor {
final AssetReader _reader;
final AssetId _entryPoint;
final CompilePipeline _pipeline;
final CompileStepFactory _factory;
final _TemplateExtractVisitor _visitor = new _TemplateExtractVisitor();
final TemplateLoader _loader;
_TemplateExtractor(this._reader, this._entryPoint)
: _pipeline = new CompilePipeline(_createCompileSteps());
_TemplateExtractor(XHR xhr)
: _loader = new TemplateLoader(xhr, new UrlResolver()),
_factory = new CompileStepFactory(new ng.Parser(new ng.Lexer()));
static List<CompileStep> _createCompileSteps() {
var parser = new ng.Parser(new ng.Lexer());
// TODO(kegluneq): Add other compile steps from default_steps.dart.
return [
new ViewSplitter(parser),
new PropertyBindingParser(parser),
new TextInterpolationParser(parser)
];
Future<RecordingReflectionCapabilities> extractTemplates(RegisteredType t) {
return _processTemplate(_processRegisteredType(t));
}
Future<List<RecordingReflectionCapabilities>> extractTemplates(
RegisteredType t) async {
return (await _processRegisteredType(t)).map(_processTemplate).toList();
}
Future<RecordingReflectionCapabilities> _processTemplate(
ViewDefinition viewDef) async {
// Check for "imperative views".
if (viewDef.template == null && viewDef.absUrl == null) return null;
RecordingReflectionCapabilities _processTemplate(String templateCode) {
var recordingCapabilities = new RecordingReflectionCapabilities();
var savedReflectionCapabilities = reflector.reflectionCapabilities;
reflector.reflectionCapabilities = recordingCapabilities;
_pipeline.process(DOM.createTemplate(templateCode), templateCode);
// TODO(kegluneq): Rewrite url to inline `template` where possible.
// See [https://github.com/angular/angular/issues/1035].
var domNode = await _loader.load(viewDef);
new CompilePipeline(_factory.createSteps(viewDef, [])).process(
domNode, '$domNode');
reflector.reflectionCapabilities = savedReflectionCapabilities;
return recordingCapabilities;
}
Future<List<String>> _processRegisteredType(RegisteredType t) async {
ViewDefinition _processRegisteredType(RegisteredType t) {
_visitor.reset();
t.annotations.accept(_visitor);
var toReturn = _visitor.inlineValues;
for (var url in _visitor.urlValues) {
var templateText = await _readUrlTemplate(url);
if (templateText != null) {
toReturn.add(templateText);
}
}
return toReturn;
}
// TODO(kegluneq): Rewrite these to `template` where possible.
// See [https://github.com/angular/angular/issues/1035].
Future<String> _readUrlTemplate(String url) async {
var assetId = uriToAssetId(_entryPoint, url, logger, null);
var templateExists = await _reader.hasInput(assetId);
if (!templateExists) {
logger.error('Could not read template at uri $url from $_entryPoint');
return null;
}
return await _reader.readAsString(assetId);
return _visitor.viewDef;
}
}
/// Visitor responsible for processing the `annotations` property of a
/// {@link RegisterType} object and pulling out template text.
/// {@link RegisterType} object and pulling out template information.
class _TemplateExtractVisitor extends Object with RecursiveAstVisitor<Object> {
final List<String> inlineValues = [];
final List<String> urlValues = [];
ViewDefinition viewDef = new ViewDefinition();
void reset() {
inlineValues.clear();
urlValues.clear();
viewDef = new ViewDefinition();
}
@override
@ -195,9 +171,16 @@ class _TemplateExtractVisitor extends Object with RecursiveAstVisitor<Object> {
}
var valueString = stringLiteralToString(node.expression);
if (keyString == 'templateUrl') {
urlValues.add(valueString);
if (viewDef.absUrl != null) {
logger.error(
'Found multiple values for "templateUrl". Source: ${node}');
}
viewDef.absUrl = valueString;
} else {
inlineValues.add(valueString);
if (viewDef.template != null) {
logger.error('Found multiple values for "template". Source: ${node}');
}
viewDef.template = valueString;
}
}
return null;

View File

@ -0,0 +1,25 @@
library angular2.transform.template_compiler.xhr_impl;
import 'dart:async';
import 'package:angular2/src/services/xhr.dart' show XHR;
import 'package:angular2/src/transform/common/asset_reader.dart';
import 'package:angular2/src/transform/common/logging.dart';
import 'package:barback/barback.dart';
import 'package:code_transformers/assets.dart';
class XhrImpl implements XHR {
final AssetReader _reader;
final AssetId _entryPoint;
XhrImpl(this._reader, this._entryPoint);
Future<String> get(String url) async {
var assetId = uriToAssetId(_entryPoint, url, logger, null);
var templateExists = await _reader.hasInput(assetId);
if (!templateExists) {
logger.error('Could not read template at uri $url from $_entryPoint');
return null;
}
return await _reader.readAsString(assetId);
}
}