chore(transform): move transform module to modules_dart

The build/pure-packages.dart gulp task has also been updated to move the files into the angular2 tree.
Closes #3729
This commit is contained in:
Jeff Cross
2015-08-19 10:36:52 -07:00
parent 92da5430e7
commit 88a5b8da0f
245 changed files with 16 additions and 3 deletions

View File

@ -1,497 +0,0 @@
library angular2.transform.template_compiler.change_detector_codegen;
import 'package:angular2/src/change_detection/change_detection_util.dart';
import 'package:angular2/src/change_detection/codegen_facade.dart';
import 'package:angular2/src/change_detection/codegen_logic_util.dart';
import 'package:angular2/src/change_detection/codegen_name_util.dart';
import 'package:angular2/src/change_detection/directive_record.dart';
import 'package:angular2/src/change_detection/interfaces.dart';
import 'package:angular2/src/change_detection/proto_change_detector.dart';
import 'package:angular2/src/change_detection/proto_record.dart';
import 'package:angular2/src/change_detection/event_binding.dart';
import 'package:angular2/src/change_detection/binding_record.dart';
import 'package:angular2/src/change_detection/codegen_facade.dart' show codify;
import 'package:angular2/src/facade/lang.dart' show BaseException;
/// Responsible for generating change detector classes for Angular 2.
///
/// This code should be kept in sync with the `ChangeDetectorJITGenerator`
/// class. If you make updates here, please make equivalent changes there.
class Codegen {
/// Stores the generated class definitions.
final StringBuffer _buf = new StringBuffer();
/// Stores all generated initialization code.
final StringBuffer _initBuf = new StringBuffer();
/// The names of already generated classes.
final Set<String> _names = new Set<String>();
/// Generates a change detector class with name `changeDetectorTypeName`,
/// which must not conflict with other generated classes in the same
/// `.ng_deps.dart` file. The change detector is used to detect changes in
/// Objects of type `typeName`.
void generate(String typeName, String changeDetectorTypeName,
ChangeDetectorDefinition def) {
if (_names.contains(changeDetectorTypeName)) {
throw new BaseException(
'Change detector named "${changeDetectorTypeName}" for ${typeName} '
'conflicts with an earlier generated change detector class.');
}
_names.add(changeDetectorTypeName);
new _CodegenState(typeName, changeDetectorTypeName, def)
.._writeToBuf(_buf)
.._writeInitToBuf(_initBuf);
}
/// Gets all imports necessary for the generated code.
String get imports {
return _buf.isEmpty
? ''
: '''import '$_PREGEN_PROTO_CHANGE_DETECTOR_IMPORT' as $_GEN_PREFIX;''';
}
bool get isEmpty => _buf.isEmpty;
/// Gets the initilization code that registers the generated classes with
/// the Angular 2 change detection system.
String get initialize => '$_initBuf';
@override
String toString() => '$_buf';
}
/// The state needed to generate a change detector for a single `Component`.
class _CodegenState {
/// The `id` of the `ChangeDetectorDefinition` we are generating this class
/// for.
final String _changeDetectorDefId;
/// The name of the `Type` this change detector is generated for. For example,
/// this is `MyComponent` if the generated class will detect changes in
/// `MyComponent` objects.
final String _contextTypeName;
/// The name of the generated change detector class. This is an implementation
/// detail and should not be visible to users.
final String _changeDetectorTypeName;
final String _changeDetectionStrategy;
final List<DirectiveRecord> _directiveRecords;
final List<ProtoRecord> _records;
final List<EventBinding> _eventBindings;
final CodegenLogicUtil _logic;
final CodegenNameUtil _names;
final ChangeDetectorGenConfig _genConfig;
final List<BindingTarget> _propertyBindingTargets;
_CodegenState._(
this._changeDetectorDefId,
this._contextTypeName,
this._changeDetectorTypeName,
this._changeDetectionStrategy,
this._records,
this._propertyBindingTargets,
this._eventBindings,
this._directiveRecords,
this._logic,
this._names,
this._genConfig);
factory _CodegenState(String typeName, String changeDetectorTypeName,
ChangeDetectorDefinition def) {
var protoRecords = createPropertyRecords(def);
var eventBindings = createEventRecords(def);
var propertyBindingTargets = def.bindingRecords.map((b) => b.target).toList();
var names = new CodegenNameUtil(protoRecords, eventBindings, def.directiveRecords, _UTIL);
var logic = new CodegenLogicUtil(names, _UTIL, def.strategy);
return new _CodegenState._(
def.id,
typeName,
changeDetectorTypeName,
def.strategy,
protoRecords,
propertyBindingTargets,
eventBindings,
def.directiveRecords,
logic,
names,
def.genConfig);
}
void _writeToBuf(StringBuffer buf) {
buf.write('''\n
class $_changeDetectorTypeName extends $_BASE_CLASS<$_contextTypeName> {
${_genDeclareFields()}
$_changeDetectorTypeName(dispatcher)
: super(${codify(_changeDetectorDefId)},
dispatcher, ${_records.length},
${_changeDetectorTypeName}.gen_propertyBindingTargets,
${_changeDetectorTypeName}.gen_directiveIndices,
${codify(_changeDetectionStrategy)}) {
dehydrateDirectives(false);
}
void detectChangesInRecordsInternal(throwOnChange) {
${_names.genInitLocals()}
var $_IS_CHANGED_LOCAL = false;
var $_CHANGES_LOCAL = null;
${_records.map(_genRecord).join('')}
${_names.getAlreadyCheckedName()} = true;
}
${_maybeGenHandleEventInternal()}
${_genCheckNoChanges()}
${_maybeGenCallOnAllChangesDone()}
${_maybeGenHydrateDirectives()}
${_maybeGenDehydrateDirectives()}
${_genPropertyBindingTargets()};
${_genDirectiveIndices()};
static $_GEN_PREFIX.ProtoChangeDetector
$PROTO_CHANGE_DETECTOR_FACTORY_METHOD(
$_GEN_PREFIX.ChangeDetectorDefinition def) {
return new $_GEN_PREFIX.PregenProtoChangeDetector(
(a) => new $_changeDetectorTypeName(a),
def);
}
}
''');
}
String _genPropertyBindingTargets() {
var targets = _logic.genPropertyBindingTargets(_propertyBindingTargets, this._genConfig.genDebugInfo);
return "static var gen_propertyBindingTargets = ${targets}";
}
String _genDirectiveIndices() {
var indices = _logic.genDirectiveIndices(_directiveRecords);
return "static var gen_directiveIndices = ${indices}";
}
String _maybeGenHandleEventInternal() {
if (_eventBindings.length > 0) {
var handlers = _eventBindings.map((eb) => _genEventBinding(eb)).join("\n");
return '''
handleEventInternal(eventName, elIndex, locals) {
var ${this._names.getPreventDefaultAccesor()} = false;
${this._names.genInitEventLocals()}
${handlers}
return ${this._names.getPreventDefaultAccesor()};
}
''';
} else {
return '';
}
}
String _genEventBinding(EventBinding eb) {
var recs = eb.records.map((r) => _genEventBindingEval(eb, r)).join("\n");
return '''
if (eventName == "${eb.eventName}" && elIndex == ${eb.elIndex}) {
${recs}
}''';
}
String _genEventBindingEval(EventBinding eb, ProtoRecord r){
if (r.lastInBinding) {
var evalRecord = _logic.genEventBindingEvalValue(eb, r);
var markPath = _genMarkPathToRootAsCheckOnce(r);
var prevDefault = _genUpdatePreventDefault(eb, r);
return "${evalRecord}\n${markPath}\n${prevDefault}";
} else {
return _logic.genEventBindingEvalValue(eb, r);
}
}
String _genMarkPathToRootAsCheckOnce(ProtoRecord r) {
var br = r.bindingRecord;
if (!br.isDefaultChangeDetection()) {
return "${_names.getDetectorName(br.directiveRecord.directiveIndex)}.markPathToRootAsCheckOnce();";
} else {
return "";
}
}
String _genUpdatePreventDefault(EventBinding eb, ProtoRecord r) {
var local = this._names.getEventLocalName(eb, r.selfIndex);
return """if (${local} == false) { ${_names.getPreventDefaultAccesor()} = true; }""";
}
void _writeInitToBuf(StringBuffer buf) {
buf.write('''
$_GEN_PREFIX.preGeneratedProtoDetectors['$_changeDetectorDefId'] =
$_changeDetectorTypeName.newProtoChangeDetector;
''');
}
String _maybeGenDehydrateDirectives() {
var destroyPipesParamName = 'destroyPipes';
var destroyPipesCode = _names.genPipeOnDestroy();
if (destroyPipesCode.isNotEmpty) {
destroyPipesCode = 'if (${destroyPipesParamName}) {${destroyPipesCode}}';
}
var dehydrateFieldsCode = _names.genDehydrateFields();
if (destroyPipesCode.isEmpty && dehydrateFieldsCode.isEmpty) return '';
return 'void dehydrateDirectives(${destroyPipesParamName}) '
'{ ${destroyPipesCode} ${dehydrateFieldsCode} }';
}
String _maybeGenHydrateDirectives() {
var hydrateDirectivesCode = _logic.genHydrateDirectives(_directiveRecords);
var hydrateDetectorsCode = _logic.genHydrateDetectors(_directiveRecords);
if (hydrateDirectivesCode.isEmpty && hydrateDetectorsCode.isEmpty) {
return '';
}
return 'void hydrateDirectives(directives) '
'{ $hydrateDirectivesCode $hydrateDetectorsCode }';
}
/// Generates calls to `onAllChangesDone` for all `Directive`s that request
/// them.
String _maybeGenCallOnAllChangesDone() {
// NOTE(kegluneq): Order is important!
var directiveNotifications = _directiveRecords.reversed
.where((rec) => rec.callOnAllChangesDone)
.map((rec) =>
'${_names.getDirectiveName(rec.directiveIndex)}.onAllChangesDone();');
if (directiveNotifications.isNotEmpty) {
return '''
void callOnAllChangesDone() {
${_names.getDispatcherName()}.notifyOnAllChangesDone();
${directiveNotifications.join('')}
}
''';
} else {
return '';
}
}
String _genDeclareFields() {
var fields = _names.getAllFieldNames();
// If there's only one field, it's `context`, declared in the superclass.
if (fields.length == 1) return '';
fields.removeAt(CONTEXT_INDEX);
var toRemove = 'this.';
var declareNames = fields
.map((f) => f.startsWith(toRemove) ? f.substring(toRemove.length) : f);
return 'var ${declareNames.join(', ')};';
}
String _genRecord(ProtoRecord r) {
var rec = null;
if (r.isLifeCycleRecord()) {
rec = _genDirectiveLifecycle(r);
} else if (r.isPipeRecord()) {
rec = _genPipeCheck(r);
} else {
rec = _genReferenceCheck(r);
}
return '''
${this._maybeFirstInBinding(r)}
${rec}
${this._maybeGenLastInDirective(r)}
''';
}
String _genDirectiveLifecycle(ProtoRecord r) {
if (r.name == 'onCheck') {
return _genOnCheck(r);
} else if (r.name == 'onInit') {
return _genOnInit(r);
} else if (r.name == 'onChange') {
return _genOnChange(r);
} else {
throw new BaseException("Unknown lifecycle event '${r.name}'");
}
}
String _genPipeCheck(ProtoRecord r) {
var context = _names.getLocalName(r.contextIndex);
var argString = r.args.map((arg) => _names.getLocalName(arg)).join(", ");
var oldValue = _names.getFieldName(r.selfIndex);
var newValue = _names.getLocalName(r.selfIndex);
var pipe = _names.getPipeName(r.selfIndex);
var pipeType = r.name;
var read = '''
if ($_IDENTICAL_CHECK_FN($pipe, $_UTIL.uninitialized)) {
$pipe = ${_names.getPipesAccessorName()}.get('$pipeType');
}
$newValue = $pipe.transform($context, [$argString]);
''';
var check = '''
if ($_NOT_IDENTICAL_CHECK_FN($oldValue, $newValue)) {
$newValue = $_UTIL.unwrapValue($newValue);
${_genChangeMarker(r)}
${_genUpdateDirectiveOrElement(r)}
${_genAddToChanges(r)}
$oldValue = $newValue;
}
''';
return r.shouldBeChecked() ? "${read}${check}" : read;
}
String _genReferenceCheck(ProtoRecord r) {
var oldValue = _names.getFieldName(r.selfIndex);
var newValue = _names.getLocalName(r.selfIndex);
var read = '''
${_logic.genPropertyBindingEvalValue(r)}
''';
var check = '''
if ($_NOT_IDENTICAL_CHECK_FN($newValue, $oldValue)) {
${_genChangeMarker(r)}
${_genUpdateDirectiveOrElement(r)}
${_genAddToChanges(r)}
$oldValue = $newValue;
}
''';
var genCode = r.shouldBeChecked() ? "${read}${check}" : read;
if (r.isPureFunction()) {
// Add an "if changed guard"
var condition = r.args.map((a) => _names.getChangeName(a)).join(' || ');
if (r.isUsedByOtherRecord()) {
return 'if ($condition) { $genCode } else { $newValue = $oldValue; }';
} else {
return 'if ($condition) { $genCode }';
}
} else {
return genCode;
}
}
String _genChangeMarker(ProtoRecord r) {
return r.argumentToPureFunction
? "${this._names.getChangeName(r.selfIndex)} = true;"
: "";
}
String _genUpdateDirectiveOrElement(ProtoRecord r) {
if (!r.lastInBinding) return '';
var newValue = _names.getLocalName(r.selfIndex);
var oldValue = _names.getFieldName(r.selfIndex);
var notifyDebug = _genConfig.logBindingUpdate ? "this.logBindingUpdate(${newValue});" : "";
var br = r.bindingRecord;
if (br.target.isDirective()) {
var directiveProperty =
'${_names.getDirectiveName(br.directiveRecord.directiveIndex)}.${br.target.name}';
return '''
${_genThrowOnChangeCheck(oldValue, newValue)}
$directiveProperty = $newValue;
${notifyDebug}
$_IS_CHANGED_LOCAL = true;
''';
} else {
return '''
${_genThrowOnChangeCheck(oldValue, newValue)}
this.notifyDispatcher(${newValue});
${notifyDebug}
''';
}
}
String _genThrowOnChangeCheck(String oldValue, String newValue) {
if (this._genConfig.genCheckNoChanges) {
return '''
if(throwOnChange) {
this.throwOnChangeError(${oldValue}, ${newValue});
}
''';
} else {
return "";
}
}
String _genCheckNoChanges() {
if (this._genConfig.genCheckNoChanges) {
return 'void checkNoChanges() { runDetectChanges(true); }';
} else {
return '';
}
}
String _maybeFirstInBinding(ProtoRecord r) {
var prev = ChangeDetectionUtil.protoByIndex(_records, r.selfIndex - 1);
var firstInBindng = prev == null || prev.bindingRecord != r.bindingRecord;
return firstInBindng && !r.bindingRecord.isDirectiveLifecycle()
? "${_names.getPropertyBindingIndex()} = ${r.propertyBindingIndex};"
: '';
}
String _genAddToChanges(ProtoRecord r) {
var newValue = _names.getLocalName(r.selfIndex);
var oldValue = _names.getFieldName(r.selfIndex);
if (!r.bindingRecord.callOnChange()) return '';
return "$_CHANGES_LOCAL = addChange($_CHANGES_LOCAL, $oldValue, $newValue);";
}
String _maybeGenLastInDirective(ProtoRecord r) {
if (!r.lastInDirective) return '';
return '''
$_CHANGES_LOCAL = null;
${_genNotifyOnPushDetectors(r)}
$_IS_CHANGED_LOCAL = false;
''';
}
String _genOnCheck(ProtoRecord r) {
var br = r.bindingRecord;
return 'if (!throwOnChange) '
'${_names.getDirectiveName(br.directiveRecord.directiveIndex)}.onCheck();';
}
String _genOnInit(ProtoRecord r) {
var br = r.bindingRecord;
return 'if (!throwOnChange && !${_names.getAlreadyCheckedName()}) '
'${_names.getDirectiveName(br.directiveRecord.directiveIndex)}.onInit();';
}
String _genOnChange(ProtoRecord r) {
var br = r.bindingRecord;
return 'if (!throwOnChange && $_CHANGES_LOCAL != null) '
'${_names.getDirectiveName(br.directiveRecord.directiveIndex)}'
'.onChange($_CHANGES_LOCAL);';
}
String _genNotifyOnPushDetectors(ProtoRecord r) {
var br = r.bindingRecord;
if (!r.lastInDirective || br.isDefaultChangeDetection()) return '';
return '''
if($_IS_CHANGED_LOCAL) {
${_names.getDetectorName(br.directiveRecord.directiveIndex)}.markAsCheckOnce();
}
''';
}
}
const PROTO_CHANGE_DETECTOR_FACTORY_METHOD = 'newProtoChangeDetector';
const _BASE_CLASS = '$_GEN_PREFIX.AbstractChangeDetector';
const _CHANGES_LOCAL = 'changes';
const _GEN_PREFIX = '_gen';
const _GEN_RECORDS_METHOD_NAME = '_createRecords';
const _IDENTICAL_CHECK_FN = '$_GEN_PREFIX.looseIdentical';
const _NOT_IDENTICAL_CHECK_FN = '$_GEN_PREFIX.looseNotIdentical';
const _IS_CHANGED_LOCAL = 'isChanged';
const _PREGEN_PROTO_CHANGE_DETECTOR_IMPORT =
'package:angular2/src/change_detection/pregen_proto_change_detector.dart';
const _UTIL = '$_GEN_PREFIX.ChangeDetectionUtil';

View File

@ -1,25 +0,0 @@
library angular2.transform.template_compiler.compile_step_factory;
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/directive_parser.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';
class CompileStepFactory implements base.CompileStepFactory {
final ng.Parser _parser;
CompileStepFactory(this._parser);
List<CompileStep> createSteps(ViewDefinition template) {
return [
new ViewSplitter(_parser),
new PropertyBindingParser(_parser),
new DirectiveParser(_parser, template.directives),
new TextInterpolationParser(_parser)
];
}
}

View File

@ -1,139 +0,0 @@
library angular2.transform.template_compiler.generator;
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;
import 'package:angular2/src/change_detection/interfaces.dart';
import 'package:angular2/src/core/compiler/proto_view_factory.dart';
import 'package:angular2/src/dom/dom_adapter.dart';
import 'package:angular2/src/render/api.dart';
import 'package:angular2/src/render/dom/compiler/compile_pipeline.dart';
import 'package:angular2/src/render/dom/compiler/style_inliner.dart';
import 'package:angular2/src/render/dom/compiler/style_url_resolver.dart';
import 'package:angular2/src/render/dom/compiler/view_loader.dart';
import 'package:angular2/src/render/dom/schema/element_schema_registry.dart';
import 'package:angular2/src/render/dom/schema/dom_element_schema_registry.dart';
import 'package:angular2/src/render/dom/template_cloner.dart';
import 'package:angular2/src/render/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/xhr_impl.dart';
import 'package:angular2/src/facade/lang.dart';
import 'package:barback/barback.dart';
import 'change_detector_codegen.dart' as change;
import 'compile_step_factory.dart';
import 'reflection/codegen.dart' as reg;
import 'reflection/processor.dart' as reg;
import 'reflection/reflection_capabilities.dart';
import 'view_definition_creator.dart';
/// Reads the `.ng_deps.dart` file represented by `entryPoint` and parses any
/// Angular 2 `View` annotations it declares to generate `getter`s,
/// `setter`s, and `method`s that would otherwise be reflectively accessed.
///
/// This method assumes a {@link DomAdapter} has been registered.
Future<String> processTemplates(AssetReader reader, AssetId entryPoint,
{bool generateRegistrations: true,
bool generateChangeDetectors: true, bool reflectPropertiesAsAttributes: false}) async {
var viewDefResults = await createViewDefinitions(reader, entryPoint);
// Note: TemplateCloner(-1) never serializes Nodes into strings.
// we might want to change this to TemplateCloner(0) to force the serialization
// later when the transformer also stores the proto view template.
var extractor = new _TemplateExtractor(new DomElementSchemaRegistry(),
new TemplateCloner(-1), new XhrImpl(reader, entryPoint));
final processor = new reg.Processor();
var changeDetectorClasses = new change.Codegen();
for (var rType in viewDefResults.viewDefinitions.keys) {
var viewDefEntry = viewDefResults.viewDefinitions[rType];
var protoView = await extractor.extractTemplates(viewDefEntry.viewDef);
if (protoView == null) continue;
if (generateRegistrations) {
processor.process(viewDefEntry, protoView);
}
if (generateChangeDetectors) {
var saved = reflector.reflectionCapabilities;
var genConfig = new ChangeDetectorGenConfig(assertionsEnabled(), assertionsEnabled(), reflectPropertiesAsAttributes);
reflector.reflectionCapabilities = const NullReflectionCapabilities();
var defs = getChangeDetectorDefinitions(viewDefEntry.hostMetadata,
protoView, viewDefEntry.viewDef.directives, genConfig);
for (var i = 0; i < defs.length; ++i) {
changeDetectorClasses.generate('${rType.typeName}',
'_${rType.typeName}_ChangeDetector$i', defs[i]);
}
reflector.reflectionCapabilities = saved;
}
}
// TODO(kegluneq): Do not hard-code `false` here once i/3436 is fixed.
final registrations = new reg.Codegen(generateChangeDetectors: false);
registrations.generate(processor);
var code = viewDefResults.ngDeps.code;
if (registrations.isEmpty && changeDetectorClasses.isEmpty) return code;
var importInjectIdx =
viewDefResults.ngDeps.lib != null ? viewDefResults.ngDeps.lib.end : 0;
var codeInjectIdx =
viewDefResults.ngDeps.registeredTypes.last.registerMethod.end;
var initInjectIdx = viewDefResults.ngDeps.setupMethod.end - 1;
return '${code.substring(0, importInjectIdx)}'
'${changeDetectorClasses.imports}'
'${code.substring(importInjectIdx, codeInjectIdx)}'
'${registrations}'
'${code.substring(codeInjectIdx, initInjectIdx)}'
'${changeDetectorClasses.initialize}'
'${code.substring(initInjectIdx)}'
'$changeDetectorClasses';
}
/// Extracts `template` and `url` values from `View` annotations, reads
/// template code if necessary, and determines what values will be
/// reflectively accessed from that template.
class _TemplateExtractor {
final CompileStepFactory _factory;
ViewLoader _loader;
ElementSchemaRegistry _schemaRegistry;
TemplateCloner _templateCloner;
_TemplateExtractor(this._schemaRegistry, this._templateCloner, XHR xhr)
: _factory = new CompileStepFactory(new ng.Parser(new ng.Lexer())) {
var urlResolver = new UrlResolver();
var styleUrlResolver = new StyleUrlResolver(urlResolver);
var styleInliner = new StyleInliner(xhr, styleUrlResolver, urlResolver);
_loader = new ViewLoader(xhr, styleInliner, styleUrlResolver);
}
Future<ProtoViewDto> extractTemplates(ViewDefinition viewDef) async {
// Check for "imperative views".
if (viewDef.template == null && viewDef.templateAbsUrl == null) return null;
var templateAndStyles = await _loader.load(viewDef);
// NOTE(kegluneq): Since this is a global, we must not have any async
// operations between saving and restoring it, otherwise we can get into
// a bad state. See issue #2359 for additional context.
var savedReflectionCapabilities = reflector.reflectionCapabilities;
reflector.reflectionCapabilities = const NullReflectionCapabilities();
var pipeline = new CompilePipeline(_factory.createSteps(viewDef));
var compileElements = pipeline.processElements(
DOM.createTemplate(templateAndStyles.template),
ViewType.COMPONENT,
viewDef);
var protoViewDto = compileElements[0]
.inheritedProtoView
.build(_schemaRegistry, _templateCloner);
reflector.reflectionCapabilities = savedReflectionCapabilities;
return protoViewDto;
}
}

View File

@ -1,85 +0,0 @@
library angular2.transform.template_compiler.reflection.codegen;
import 'package:angular2/src/transform/common/names.dart';
import 'package:angular2/src/transform/common/property_utils.dart' as prop;
import 'model.dart';
class Codegen {
final StringBuffer _buf = new StringBuffer();
/// Whether we are pre-generating change detectors.
/// If we have pre-generated change detectors, we need
final bool generateChangeDetectors;
Codegen({this.generateChangeDetectors});
void generate(CodegenModel model) {
if (model != null) {
var calls = _generateGetters(_extractNames(model.getterNames));
if (calls.isNotEmpty) {
_buf.write('..${REGISTER_GETTERS_METHOD_NAME}'
'({${calls.join(', ')}})');
}
calls = _generateSetters(_extractNames(model.setterNames));
if (calls.isNotEmpty) {
_buf.write('..${REGISTER_SETTERS_METHOD_NAME}'
'({${calls.join(', ')}})');
}
calls = _generateMethods(_extractNames(model.methodNames));
if (calls.isNotEmpty) {
_buf.write('..${REGISTER_METHODS_METHOD_NAME}'
'({${calls.join(', ')}})');
}
}
}
Iterable<String> _extractNames(Iterable<ReflectiveAccessor> accessors) {
var names = accessors.where((accessor) {
return accessor.isStaticallyNecessary || !generateChangeDetectors;
}).map((accessor) => accessor.sanitizedName);
var nameList = names.toList();
nameList.sort();
return nameList;
}
bool get isEmpty => _buf.isEmpty;
@override
String toString() => '$_buf';
}
Iterable<String> _generateGetters(Iterable<String> getterNames) {
return getterNames.map((getterName) {
if (!prop.isValid(getterName)) {
// TODO(kegluenq): Eagerly throw here once #1295 is addressed.
return prop.lazyInvalidGetter(getterName);
} else {
return ''' '${prop.sanitize(getterName)}': (o) => o.$getterName''';
}
});
}
Iterable<String> _generateSetters(Iterable<String> setterName) {
return setterName.map((setterName) {
if (!prop.isValid(setterName)) {
// TODO(kegluenq): Eagerly throw here once #1295 is addressed.
return prop.lazyInvalidSetter(setterName);
} else {
return ''' '${prop.sanitize(setterName)}': '''
''' (o, v) => o.$setterName = v ''';
}
});
}
Iterable<String> _generateMethods(Iterable<String> methodNames) {
return methodNames.map((methodName) {
if (!prop.isValid(methodName)) {
// TODO(kegluenq): Eagerly throw here once #1295 is addressed.
return prop.lazyInvalidMethod(methodName);
} else {
return ''' '${prop.sanitize(methodName)}': '''
'(o, List args) => Function.apply(o.$methodName, args) ';
}
});
}

View File

@ -1,49 +0,0 @@
library angular2.transform.template_compiler.reflection.model;
import 'package:angular2/src/render/dom/util.dart';
/// Defines the names of getters, setters, and methods which need to be
/// available to Angular 2 via the `reflector` at runtime.
/// See [angular2.src.reflection.reflector] for details.
abstract class CodegenModel {
Iterable<ReflectiveAccessor> get getterNames;
Iterable<ReflectiveAccessor> get methodNames;
Iterable<ReflectiveAccessor> get setterNames;
}
/// Wraps a getter, setter, or method that we may need to access reflectively in
/// an Angular2 app.
/// This is essentially a wrapper for `sanitizedName`, which is the name of the
/// actual getter, setter, or method that will be registered. Note that
/// `operator==` and `hashCode` basically forward to `sanitizedName`.
class ReflectiveAccessor {
/// The value in the Ast determining that we need this accessor. This is the
/// value that is actually present in the template, which may not directly
/// correspond to the model on the `Component`.
final String astValue;
/// The sanitized name of this accessor. This is the name of the getter,
/// setter, or method on the `Component`.
final String sanitizedName;
/// Whether this getter, setter, or method is still necessary when we have
/// pre-generated change detectors.
final bool isStaticallyNecessary;
ReflectiveAccessor(String astValue, {this.isStaticallyNecessary})
: this.astValue = astValue,
this.sanitizedName = sanitizePropertyName(astValue);
@override
bool operator ==(other) {
if (other is! ReflectiveAccessor) return false;
return sanitizedName == other.sanitizedName;
}
@override
int get hashCode => sanitizedName.hashCode;
}
String sanitizePropertyName(String name) {
return dashCaseToCamelCase(EventConfig.parse(name).fieldName);
}

View File

@ -1,124 +0,0 @@
library angular2.transform.template_compiler.reflection.processor;
import 'package:angular2/src/change_detection/parser/ast.dart';
import 'package:angular2/src/render/api.dart';
import 'package:angular2/src/transform/template_compiler/view_definition_creator.dart';
import 'model.dart';
class Processor implements CodegenModel {
/// The names of all requested `getter`s.
final Set<ReflectiveAccessor> getterNames = new Set<ReflectiveAccessor>();
/// The names of all requested `setter`s.
final Set<ReflectiveAccessor> setterNames = new Set<ReflectiveAccessor>();
/// The names of all requested `method`s.
final Set<ReflectiveAccessor> methodNames = new Set<ReflectiveAccessor>();
_NgAstVisitor _visitor;
Processor() {
_visitor = new _NgAstVisitor(this);
}
void process(ViewDefinitionEntry viewDefEntry, ProtoViewDto protoViewDto) {
_processViewDefinition(viewDefEntry);
_processProtoViewDto(protoViewDto);
}
/// Extracts the names of necessary getters from the events in host and
/// dependent [DirectiveMetadata].
void _processViewDefinition(ViewDefinitionEntry viewDefEntry) {
// These are necessary even with generated change detectors.
if (viewDefEntry.hostMetadata != null &&
viewDefEntry.hostMetadata.events != null) {
viewDefEntry.hostMetadata.events.forEach((eventName) {
getterNames.add(
new ReflectiveAccessor(eventName, isStaticallyNecessary: true));
});
}
}
void _processProtoViewDto(ProtoViewDto protoViewDto) {
_visitor.isStaticallyNecessary = false;
protoViewDto.textBindings.forEach((ast) => ast.visit(_visitor));
protoViewDto.elementBinders.forEach((binder) {
binder.propertyBindings.forEach((binding) {
binding.astWithSource.visit(_visitor);
setterNames.add(new ReflectiveAccessor(binding.property,
isStaticallyNecessary: false));
});
binder.directives.forEach((directiveBinding) {
directiveBinding.propertyBindings.values
.forEach((propBinding) => propBinding.visit(_visitor));
directiveBinding.propertyBindings.keys.forEach((bindingName) {
setterNames.add(new ReflectiveAccessor(bindingName,
isStaticallyNecessary: false));
});
directiveBinding.hostPropertyBindings.forEach((elementBinding) {
elementBinding.astWithSource.visit(_visitor);
setterNames.add(new ReflectiveAccessor(elementBinding.property,
isStaticallyNecessary: false));
});
});
binder.eventBindings
.forEach((eventBinding) => eventBinding.source.visit(_visitor));
binder.directives.forEach((directiveBinding) {
directiveBinding.eventBindings
.forEach((eventBinding) => eventBinding.source.visit(_visitor));
});
if (binder.nestedProtoView != null) {
_processProtoViewDto(binder.nestedProtoView);
}
});
}
}
class _NgAstVisitor extends RecursiveAstVisitor {
final Processor _result;
/// Whether any getters or setters recorded are necessary when running
/// statically. A getter or setter that is necessary only for change detection
/// is not necessary when running statically because all accesses are handled
/// by the dedicated change detector classes.
bool isStaticallyNecessary = false;
_NgAstVisitor(this._result);
visitMethodCall(MethodCall ast) {
_result.methodNames
.add(new ReflectiveAccessor(ast.name, isStaticallyNecessary: true));
super.visitMethodCall(ast);
}
visitPropertyRead(PropertyRead ast) {
_result.getterNames.add(new ReflectiveAccessor(ast.name,
isStaticallyNecessary: isStaticallyNecessary));
super.visitPropertyRead(ast);
}
visitPropertyWrite(PropertyWrite ast) {
_result.setterNames.add(new ReflectiveAccessor(ast.name,
isStaticallyNecessary: isStaticallyNecessary));
super.visitPropertyWrite(ast);
}
visitSafeMethodCall(SafeMethodCall ast) {
_result.methodNames
.add(new ReflectiveAccessor(ast.name, isStaticallyNecessary: true));
super.visitSafeMethodCall(ast);
}
visitSafePropertyRead(SafePropertyRead ast) {
_result.getterNames.add(new ReflectiveAccessor(ast.name,
isStaticallyNecessary: isStaticallyNecessary));
super.visitSafePropertyRead(ast);
}
}

View File

@ -1,34 +0,0 @@
library angular2.transform.template_compiler.reflection.reflection_capabilities;
import 'package:angular2/src/reflection/reflection_capabilities.dart';
import 'package:angular2/src/reflection/types.dart';
/// ReflectionCapabilities object that responds to all requests for `getter`s,
/// `setter`s, and `method`s with `null`.
class NullReflectionCapabilities implements ReflectionCapabilities {
const NullReflectionCapabilities();
_notImplemented(String name) => throw 'Not implemented: $name';
bool isReflectionEnabled() {
return false;
}
Function factory(Type type) => _notImplemented("factory");
List<List> parameters(typeOrFunc) => _notImplemented('parameters');
List<List> interfaces(typeOrFunc) => _notImplemented('interfaces');
List annotations(typeOrFunc) => _notImplemented('annotations');
GetterFn getter(String name) => _nullGetter;
SetterFn setter(String name) => _nullSetter;
MethodFn method(String name) => _nullMethod;
}
_nullGetter(Object p) => null;
_nullSetter(Object p, v) => null;
_nullMethod(Object p, List a) => null;

View File

@ -1,41 +0,0 @@
library angular2.transform.template_compiler.transformer;
import 'dart:async';
import 'package:angular2/src/dom/html_adapter.dart';
import 'package:angular2/src/transform/common/asset_reader.dart';
import 'package:angular2/src/transform/common/formatter.dart';
import 'package:angular2/src/transform/common/logging.dart' as log;
import 'package:angular2/src/transform/common/names.dart';
import 'package:angular2/src/transform/common/options.dart';
import 'package:barback/barback.dart';
import 'generator.dart';
/// {@link Transformer} responsible for detecting and processing Angular 2 templates.
///
/// {@link TemplateCompiler} uses the Angular 2 `Compiler` to process the templates,
/// extracting information about what reflection is necessary to render and
/// use that template. It then generates code in place of those reflective
/// accesses.
class TemplateCompiler extends Transformer {
final TransformerOptions options;
TemplateCompiler(this.options);
@override
bool isPrimary(AssetId id) => id.path.endsWith(DEPS_EXTENSION);
@override
Future apply(Transform transform) async {
await log.initZoned(transform, () async {
Html5LibDomAdapter.makeCurrent();
var id = transform.primaryInput.id;
var reader = new AssetReader.fromTransform(transform);
var transformedCode = formatter.format(await processTemplates(reader, id,
generateChangeDetectors: options.generateChangeDetectors,
reflectPropertiesAsAttributes: options.reflectPropertiesAsAttributes));
transform.addOutput(new Asset.fromString(id, transformedCode));
});
}
}

View File

@ -1,274 +0,0 @@
library angular2.transform.template_compiler.view_definition_creator;
import 'dart:async';
import 'dart:convert';
import 'package:analyzer/analyzer.dart';
import 'package:angular2/src/render/api.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/ng_deps.dart';
import 'package:angular2/src/transform/common/ng_meta.dart';
import 'package:barback/barback.dart';
import 'package:code_transformers/assets.dart';
/// Creates [ViewDefinition] objects for all `View` `Directive`s defined in
/// `entryPoint`.
Future<ViewDefinitionResults> createViewDefinitions(
AssetReader reader, AssetId entryPoint) async {
return await new _ViewDefinitionCreator(reader, entryPoint).createViewDefs();
}
class ViewDefinitionResults {
final NgDeps ngDeps;
final Map<RegisteredType, ViewDefinitionEntry> viewDefinitions;
ViewDefinitionResults._(this.ngDeps, this.viewDefinitions);
}
class ViewDefinitionEntry {
final RenderDirectiveMetadata hostMetadata;
final ViewDefinition viewDef;
ViewDefinitionEntry._(this.hostMetadata, this.viewDef);
}
String _getComponentId(AssetId assetId, String className) => '$className';
// TODO(kegluenq): Improve this test.
bool _isViewAnnotation(InstanceCreationExpression node) {
var constructorName = node.constructorName.type.name;
if (constructorName is PrefixedIdentifier) {
constructorName = constructorName.identifier;
}
return constructorName.name == 'View';
}
/// Creates [ViewDefinition] objects for all `View` `Directive`s defined in
/// `entryPoint`.
class _ViewDefinitionCreator {
final AssetReader reader;
final AssetId entryPoint;
final Future<NgDeps> ngDepsFuture;
_ViewDefinitionCreator(AssetReader reader, AssetId entryPoint)
: this.reader = reader,
this.entryPoint = entryPoint,
ngDepsFuture = NgDeps.parse(reader, entryPoint);
Future<ViewDefinitionResults> createViewDefs() async {
var ngDeps = await ngDepsFuture;
var retVal = <RegisteredType, ViewDefinitionEntry>{};
var visitor = new _TemplateExtractVisitor(await _extractNgMeta());
ngDeps.registeredTypes.forEach((rType) {
visitor.reset();
rType.annotations.accept(visitor);
if (visitor.viewDef != null) {
// Note: we use '' because the current file maps to the default prefix.
var ngMeta = visitor._metadataMap[''];
var typeName = '${rType.typeName}';
var hostMetadata = null;
if (ngMeta.types.containsKey(typeName)) {
hostMetadata = ngMeta.types[typeName];
visitor.viewDef.componentId = hostMetadata.id;
} else {
logger.warning('Missing component "$typeName" in metadata map',
asset: entryPoint);
visitor.viewDef.componentId = _getComponentId(entryPoint, typeName);
}
retVal[rType] =
new ViewDefinitionEntry._(hostMetadata, visitor.viewDef);
}
});
return new ViewDefinitionResults._(ngDeps, retVal);
}
/// Creates a map from [AssetId] to import prefix for `.dart` libraries
/// imported by `entryPoint`, excluding any `.ng_deps.dart` files it imports.
/// Unprefixed imports have `null` as their value. `entryPoint` is included
/// in the map with no prefix.
Future<Map<AssetId, String>> _createImportAssetToPrefixMap() async {
// TODO(kegluneq): Support `part` directives.
var ngDeps = await ngDepsFuture;
var importAssetToPrefix = <AssetId, String>{};
// Include the `.ng_meta.json` file associated with `entryPoint`.
importAssetToPrefix[new AssetId(
entryPoint.package, toMetaExtension(entryPoint.path))] = null;
for (ImportDirective node in ngDeps.imports) {
var uri = stringLiteralToString(node.uri);
if (uri.endsWith('.dart') && !uri.endsWith(DEPS_EXTENSION)) {
var prefix = node.prefix != null && node.prefix.name != null
? '${node.prefix.name}'
: null;
importAssetToPrefix[uriToAssetId(
entryPoint, uri, logger, null /* span */,
errorOnAbsolute: false)] = prefix;
}
}
return importAssetToPrefix;
}
/// Reads the `.ng_meta.json` files associated with all of `entryPoint`'s
/// imports and creates a map `Type` name, prefixed if appropriate to the
/// associated [RenderDirectiveMetadata].
///
/// For example, if in `entryPoint` we have:
///
/// ```
/// import 'component.dart' as prefix;
/// ```
///
/// and in 'component.dart' we have:
///
/// ```
/// @Component(...)
/// class MyComponent {...}
/// ```
///
/// This method will look for `component.ng_meta.json`to contain the
/// serialized [RenderDirectiveMetadata] for `MyComponent` and any other
/// `Directive`s declared in `component.dart`. We use this information to
/// build a map:
///
/// ```
/// {
/// "prefix.MyComponent": [RenderDirectiveMetadata for MyComponent],
/// ...<any other entries>...
/// }
/// ```
Future<Map<String, NgMeta>> _extractNgMeta() async {
var importAssetToPrefix = await _createImportAssetToPrefixMap();
var retVal = <String, NgMeta>{};
for (var importAssetId in importAssetToPrefix.keys) {
var prefix = importAssetToPrefix[importAssetId];
if (prefix == null) prefix = '';
var ngMeta = retVal.putIfAbsent(prefix, () => new NgMeta.empty());
var metaAssetId = new AssetId(
importAssetId.package, toMetaExtension(importAssetId.path));
if (await reader.hasInput(metaAssetId)) {
try {
var json = JSON.decode(await reader.readAsString(metaAssetId));
var newMetadata = new NgMeta.fromJson(json);
newMetadata.types.forEach((className, metadata) {
metadata.id = _getComponentId(importAssetId, className);
});
ngMeta.addAll(newMetadata);
} catch (ex, stackTrace) {
logger.warning('Failed to decode: $ex, $stackTrace',
asset: metaAssetId);
}
}
}
return retVal;
}
}
/// Visitor responsible for processing the `annotations` property of a
/// [RegisterType] object and pulling out [ViewDefinition] information.
class _TemplateExtractVisitor extends Object with RecursiveAstVisitor<Object> {
ViewDefinition viewDef = null;
final Map<String, NgMeta> _metadataMap;
final ConstantEvaluator _evaluator = new ConstantEvaluator();
_TemplateExtractVisitor(this._metadataMap);
void reset() {
viewDef = null;
}
/// These correspond to the annotations themselves.
@override
Object visitInstanceCreationExpression(InstanceCreationExpression node) {
if (_isViewAnnotation(node)) {
viewDef = new ViewDefinition(directives: <RenderDirectiveMetadata>[]);
node.visitChildren(this);
}
return null;
}
/// These correspond to the annotation parameters.
@override
Object visitNamedExpression(NamedExpression node) {
// TODO(kegluneq): Remove this limitation.
if (node.name is! Label || node.name.label is! SimpleIdentifier) {
logger.error(
'Angular 2 currently only supports simple identifiers in directives.'
' Source: ${node}');
return null;
}
var keyString = '${node.name.label}';
if (keyString == 'directives') {
_readDirectives(node.expression);
}
if (keyString == 'template' || keyString == 'templateUrl') {
// This could happen in a non-View annotation with a `template` or
// `templateUrl` property.
if (viewDef == null) return null;
var valueString = node.expression.accept(_evaluator);
if (valueString is! String) {
logger.error(
'Angular 2 currently only supports string literals in directives.'
' Source: ${node}');
return null;
}
if (keyString == 'templateUrl') {
if (viewDef.templateAbsUrl != null) {
logger.error(
'Found multiple values for "templateUrl". Source: ${node}');
}
viewDef.templateAbsUrl = valueString;
} else {
// keyString == 'template'
if (viewDef.template != null) {
logger.error('Found multiple values for "template". Source: ${node}');
}
viewDef.template = valueString;
}
}
return null;
}
void _readDirectives(Expression node) {
// This could happen in a non-View annotation with a `directives`
// parameter.
if (viewDef == null) return;
if (node is! ListLiteral) {
logger.error('Angular 2 currently only supports list literals as values '
'for "directives". Source: $node');
return;
}
var directiveList = (node as ListLiteral);
for (var node in directiveList.elements) {
var ngMeta;
var name;
if (node is SimpleIdentifier) {
ngMeta = _metadataMap[''];
name = node.name;
} else if (node is PrefixedIdentifier) {
ngMeta = _metadataMap[node.prefix.name];
name = node.name;
} else {
logger.error(
'Angular 2 currently only supports simple and prefixed identifiers '
'as values for "directives". Source: $node');
return;
}
if (ngMeta.types.containsKey(name)) {
viewDef.directives.add(ngMeta.types[name]);
} else if (ngMeta.aliases.containsKey(name)) {
viewDef.directives.addAll(ngMeta.flatten(name));
} else {
logger.warning('Could not find Directive entry for $node. '
'Please be aware that Dart transformers have limited support for '
'reusable, pre-defined lists of Directives (aka '
'"directive aliases"). See https://goo.gl/d8XPt0 for details.');
}
}
}
}