2015-03-20 15:37:09 -07:00
|
|
|
library angular2.transform.template_compiler.generator;
|
2015-03-13 13:24:56 -07:00
|
|
|
|
|
|
|
import 'dart:async';
|
|
|
|
|
|
|
|
import 'package:angular2/src/change_detection/parser/lexer.dart' as ng;
|
|
|
|
import 'package:angular2/src/change_detection/parser/parser.dart' as ng;
|
2015-05-14 13:14:45 -07:00
|
|
|
import 'package:angular2/src/core/compiler/proto_view_factory.dart';
|
2015-05-01 17:29:58 -07:00
|
|
|
import 'package:angular2/src/render/api.dart';
|
2015-05-05 10:31:21 -07:00
|
|
|
import 'package:angular2/src/render/dom/compiler/compiler.dart';
|
2015-05-01 17:29:58 -07:00
|
|
|
import 'package:angular2/src/render/dom/compiler/template_loader.dart';
|
2015-05-08 17:29:21 -07:00
|
|
|
import 'package:angular2/src/services/xhr.dart' show XHR;
|
2015-03-13 13:24:56 -07:00
|
|
|
import 'package:angular2/src/reflection/reflection.dart';
|
2015-05-01 17:29:58 -07:00
|
|
|
import 'package:angular2/src/services/url_resolver.dart';
|
2015-03-13 13:24:56 -07:00
|
|
|
import 'package:angular2/src/transform/common/asset_reader.dart';
|
2015-05-08 17:29:21 -07:00
|
|
|
import 'package:angular2/src/transform/common/xhr_impl.dart';
|
2015-03-13 13:24:56 -07:00
|
|
|
import 'package:barback/barback.dart';
|
|
|
|
|
2015-05-14 13:14:45 -07:00
|
|
|
import 'change_detector_codegen.dart' as change;
|
2015-05-01 17:29:58 -07:00
|
|
|
import 'compile_step_factory.dart';
|
2015-03-13 13:24:56 -07:00
|
|
|
import 'recording_reflection_capabilities.dart';
|
2015-05-14 13:14:45 -07:00
|
|
|
import 'reflector_register_codegen.dart' as reg;
|
2015-05-05 10:31:21 -07:00
|
|
|
import 'view_definition_creator.dart';
|
2015-03-13 13:24:56 -07:00
|
|
|
|
2015-03-13 13:55:49 -07:00
|
|
|
/// Reads the `.ng_deps.dart` file represented by `entryPoint` and parses any
|
2015-04-09 21:20:11 +02:00
|
|
|
/// Angular 2 `View` annotations it declares to generate `getter`s,
|
2015-03-13 13:55:49 -07:00
|
|
|
/// `setter`s, and `method`s that would otherwise be reflectively accessed.
|
|
|
|
///
|
2015-04-17 13:01:07 -07:00
|
|
|
/// This method assumes a {@link DomAdapter} has been registered.
|
2015-05-14 13:14:45 -07:00
|
|
|
Future<String> processTemplates(AssetReader reader, AssetId entryPoint,
|
|
|
|
{bool generateRegistrations: true,
|
|
|
|
bool generateChangeDetectors: true}) async {
|
2015-05-05 10:31:21 -07:00
|
|
|
var viewDefResults = await createViewDefinitions(reader, entryPoint);
|
2015-05-01 17:29:58 -07:00
|
|
|
var extractor = new _TemplateExtractor(new XhrImpl(reader, entryPoint));
|
2015-03-13 13:24:56 -07:00
|
|
|
|
2015-05-14 13:14:45 -07:00
|
|
|
var registrations = new reg.Codegen();
|
|
|
|
var changeDetectorClasses = new change.Codegen();
|
|
|
|
for (var rType in viewDefResults.viewDefinitions.keys) {
|
|
|
|
var viewDefEntry = viewDefResults.viewDefinitions[rType];
|
|
|
|
var result = await extractor.extractTemplates(viewDefEntry.viewDef);
|
|
|
|
if (result == null) continue;
|
|
|
|
|
|
|
|
registrations.generate(result.recording);
|
|
|
|
if (result.protoView != null && generateChangeDetectors) {
|
|
|
|
var savedReflectionCapabilities = reflector.reflectionCapabilities;
|
|
|
|
var recordingCapabilities = new RecordingReflectionCapabilities();
|
|
|
|
reflector.reflectionCapabilities = recordingCapabilities;
|
|
|
|
|
|
|
|
var defs = getChangeDetectorDefinitions(viewDefEntry.hostMetadata,
|
|
|
|
result.protoView, viewDefEntry.viewDef.directives);
|
|
|
|
for (var i = 0; i < defs.length; ++i) {
|
|
|
|
changeDetectorClasses.generate(
|
|
|
|
'_${rType.typeName}_ChangeDetector$i', defs[i]);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Check that getters, setters, methods are the same as above.
|
|
|
|
assert(recordingCapabilities.getterNames
|
|
|
|
.containsAll(result.recording.getterNames));
|
|
|
|
assert(result.recording.getterNames
|
|
|
|
.containsAll(recordingCapabilities.getterNames));
|
|
|
|
assert(recordingCapabilities.setterNames
|
|
|
|
.containsAll(result.recording.setterNames));
|
|
|
|
assert(result.recording.setterNames
|
|
|
|
.containsAll(recordingCapabilities.setterNames));
|
|
|
|
assert(recordingCapabilities.methodNames
|
|
|
|
.containsAll(result.recording.methodNames));
|
|
|
|
assert(result.recording.methodNames
|
|
|
|
.containsAll(recordingCapabilities.methodNames));
|
|
|
|
|
|
|
|
reflector.reflectionCapabilities = savedReflectionCapabilities;
|
2015-05-01 17:29:58 -07:00
|
|
|
}
|
2015-03-19 09:16:01 -07:00
|
|
|
}
|
2015-03-13 13:24:56 -07:00
|
|
|
|
2015-05-05 10:31:21 -07:00
|
|
|
var code = viewDefResults.ngDeps.code;
|
2015-05-14 13:14:45 -07:00
|
|
|
if (registrations.isEmpty && changeDetectorClasses.isEmpty) return code;
|
|
|
|
var importInjectIdx =
|
|
|
|
viewDefResults.ngDeps.lib != null ? viewDefResults.ngDeps.lib.end : 0;
|
2015-05-05 10:31:21 -07:00
|
|
|
var codeInjectIdx =
|
|
|
|
viewDefResults.ngDeps.registeredTypes.last.registerMethod.end;
|
2015-05-14 13:14:45 -07:00
|
|
|
return '${code.substring(0, importInjectIdx)}'
|
|
|
|
'${changeDetectorClasses.imports}'
|
|
|
|
'${code.substring(importInjectIdx, codeInjectIdx)}'
|
2015-03-13 13:24:56 -07:00
|
|
|
'${registrations}'
|
2015-05-14 13:14:45 -07:00
|
|
|
'${code.substring(codeInjectIdx)}'
|
|
|
|
'$changeDetectorClasses';
|
2015-03-13 13:55:49 -07:00
|
|
|
}
|
|
|
|
|
2015-04-09 21:20:11 +02:00
|
|
|
/// Extracts `template` and `url` values from `View` annotations, reads
|
2015-03-19 09:16:01 -07:00
|
|
|
/// template code if necessary, and determines what values will be
|
|
|
|
/// reflectively accessed from that template.
|
|
|
|
class _TemplateExtractor {
|
2015-05-05 10:31:21 -07:00
|
|
|
final RenderCompiler _compiler;
|
2015-03-19 09:16:01 -07:00
|
|
|
|
2015-05-05 10:31:21 -07:00
|
|
|
_TemplateExtractor(XHR xhr) : _compiler = new DomCompiler(
|
|
|
|
new CompileStepFactory(new ng.Parser(new ng.Lexer())),
|
|
|
|
new TemplateLoader(xhr, new UrlResolver()));
|
2015-03-13 13:24:56 -07:00
|
|
|
|
2015-05-14 13:14:45 -07:00
|
|
|
Future<_ExtractResult> extractTemplates(ViewDefinition viewDef) async {
|
2015-05-01 17:29:58 -07:00
|
|
|
// Check for "imperative views".
|
|
|
|
if (viewDef.template == null && viewDef.absUrl == null) return null;
|
|
|
|
|
2015-03-19 09:16:01 -07:00
|
|
|
var savedReflectionCapabilities = reflector.reflectionCapabilities;
|
2015-05-05 10:31:21 -07:00
|
|
|
var recordingCapabilities = new RecordingReflectionCapabilities();
|
2015-03-19 09:16:01 -07:00
|
|
|
reflector.reflectionCapabilities = recordingCapabilities;
|
2015-03-13 13:24:56 -07:00
|
|
|
|
2015-05-01 17:29:58 -07:00
|
|
|
// TODO(kegluneq): Rewrite url to inline `template` where possible.
|
2015-05-14 13:14:45 -07:00
|
|
|
var protoViewDto = await _compiler.compile(viewDef);
|
2015-03-19 09:16:01 -07:00
|
|
|
|
|
|
|
reflector.reflectionCapabilities = savedReflectionCapabilities;
|
2015-05-14 13:14:45 -07:00
|
|
|
return new _ExtractResult(recordingCapabilities, protoViewDto);
|
2015-03-19 09:16:01 -07:00
|
|
|
}
|
2015-03-13 13:24:56 -07:00
|
|
|
}
|
2015-05-14 13:14:45 -07:00
|
|
|
|
|
|
|
class _ExtractResult {
|
|
|
|
final RecordingReflectionCapabilities recording;
|
|
|
|
final ProtoViewDto protoView;
|
|
|
|
|
|
|
|
_ExtractResult(this.recording, this.protoView);
|
|
|
|
}
|