refactor(dart/transform): Remove unnecessary getter/setter codegen
Currently the transformer generates all getters and setters even when creating pre-generated change detectors, which remove the need for them. Generate getters and setters via the model provided by `ProtoViewDto`, which contains enough information to allow omitting unnecessary getters and setters from code output. Allow generating getters, setters, and method names which are Dart pseudo keywords. Closes #3489
This commit is contained in:
parent
ba2c077b01
commit
104302a958
|
@ -490,14 +490,11 @@ export class _ParseAST {
|
|||
new MethodCall(receiver, id, fn, args);
|
||||
|
||||
} else {
|
||||
let getter = this.reflector.getter(id);
|
||||
let setter = this.reflector.setter(id);
|
||||
|
||||
if (isSafe) {
|
||||
if (this.optionalOperator("=")) {
|
||||
this.error("The '?.' operator cannot be used in the assignment");
|
||||
} else {
|
||||
return new SafePropertyRead(receiver, id, getter);
|
||||
return new SafePropertyRead(receiver, id, this.reflector.getter(id));
|
||||
}
|
||||
} else {
|
||||
if (this.optionalOperator("=")) {
|
||||
|
@ -506,9 +503,9 @@ export class _ParseAST {
|
|||
}
|
||||
|
||||
let value = this.parseConditional();
|
||||
return new PropertyWrite(receiver, id, setter, value);
|
||||
return new PropertyWrite(receiver, id, this.reflector.setter(id), value);
|
||||
} else {
|
||||
return new PropertyRead(receiver, id, getter);
|
||||
return new PropertyRead(receiver, id, this.reflector.getter(id));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -44,6 +44,7 @@ import {ChangeDetector, ChangeDetectorRef} from 'angular2/src/change_detection/c
|
|||
import {QueryList} from './query_list';
|
||||
import {reflector} from 'angular2/src/reflection/reflection';
|
||||
import {RenderDirectiveMetadata} from 'angular2/src/render/api';
|
||||
import {EventConfig} from 'angular2/src/render/dom/util';
|
||||
import {PipeBinding} from '../pipes/pipe_binding';
|
||||
|
||||
var _staticKeys;
|
||||
|
@ -303,18 +304,8 @@ function _createEventEmitterAccessors(bwv: BindingWithVisibility): EventEmitterA
|
|||
if (!(binding instanceof DirectiveBinding)) return [];
|
||||
var db = <DirectiveBinding>binding;
|
||||
return ListWrapper.map(db.eventEmitters, eventConfig => {
|
||||
let fieldName;
|
||||
let eventName;
|
||||
var colonIdx = eventConfig.indexOf(':');
|
||||
if (colonIdx > -1) {
|
||||
// long format: 'fieldName: eventName'
|
||||
fieldName = StringWrapper.substring(eventConfig, 0, colonIdx).trim();
|
||||
eventName = StringWrapper.substring(eventConfig, colonIdx + 1).trim();
|
||||
} else {
|
||||
// short format: 'name' when fieldName and eventName are the same
|
||||
fieldName = eventName = eventConfig;
|
||||
}
|
||||
return new EventEmitterAccessor(eventName, reflector.getter(fieldName));
|
||||
var parsedEvent = EventConfig.parse(eventConfig);
|
||||
return new EventEmitterAccessor(parsedEvent.eventName, reflector.getter(parsedEvent.fieldName));
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -10,7 +10,7 @@ import {CompileElement} from './compile_element';
|
|||
import {CompileControl} from './compile_control';
|
||||
|
||||
import {RenderDirectiveMetadata} from '../../api';
|
||||
import {dashCaseToCamelCase, camelCaseToDashCase, EVENT_TARGET_SEPARATOR} from '../util';
|
||||
import {EventConfig, dashCaseToCamelCase, camelCaseToDashCase} from '../util';
|
||||
import {DirectiveBuilder, ElementBinderBuilder} from '../view/proto_view_builder';
|
||||
|
||||
/**
|
||||
|
@ -146,12 +146,9 @@ export class DirectiveParser implements CompileStep {
|
|||
|
||||
_bindDirectiveEvent(eventName, action, compileElement, directiveBinderBuilder) {
|
||||
var ast = this._parser.parseAction(action, compileElement.elementDescription);
|
||||
if (StringWrapper.contains(eventName, EVENT_TARGET_SEPARATOR)) {
|
||||
var parts = eventName.split(EVENT_TARGET_SEPARATOR);
|
||||
directiveBinderBuilder.bindEvent(parts[1], ast, parts[0]);
|
||||
} else {
|
||||
directiveBinderBuilder.bindEvent(eventName, ast);
|
||||
}
|
||||
var parsedEvent = EventConfig.parse(eventName);
|
||||
var targetName = parsedEvent.isLongForm ? parsedEvent.fieldName : null;
|
||||
directiveBinderBuilder.bindEvent(parsedEvent.eventName, ast, targetName);
|
||||
}
|
||||
|
||||
_bindHostProperty(hostPropertyName, expression, compileElement, directiveBinderBuilder) {
|
||||
|
|
|
@ -29,6 +29,27 @@ export function dashCaseToCamelCase(input: string): string {
|
|||
(m) => { return m[1].toUpperCase(); });
|
||||
}
|
||||
|
||||
export class EventConfig {
|
||||
constructor(public fieldName: string, public eventName: string, public isLongForm: boolean) {}
|
||||
|
||||
static parse(eventConfig: string): EventConfig {
|
||||
var fieldName = eventConfig, eventName = eventConfig, isLongForm = false;
|
||||
var separatorIdx = eventConfig.indexOf(EVENT_TARGET_SEPARATOR);
|
||||
if (separatorIdx > -1) {
|
||||
// long format: 'fieldName: eventName'
|
||||
fieldName = StringWrapper.substring(eventConfig, 0, separatorIdx).trim();
|
||||
eventName = StringWrapper.substring(eventConfig, separatorIdx + 1).trim();
|
||||
isLongForm = true;
|
||||
}
|
||||
return new EventConfig(fieldName, eventName, isLongForm);
|
||||
}
|
||||
|
||||
getFullName(): string {
|
||||
return this.isLongForm ? `${this.fieldName}${EVENT_TARGET_SEPARATOR}${this.eventName}` :
|
||||
this.eventName;
|
||||
}
|
||||
}
|
||||
|
||||
// Attention: This is on the hot path, so don't use closures or default values!
|
||||
export function queryBoundElements(templateContent: Node, isSingleElementChild: boolean):
|
||||
Element[] {
|
||||
|
|
|
@ -262,7 +262,7 @@ export class DirectiveBuilder {
|
|||
}
|
||||
}
|
||||
|
||||
export class EventBuilder extends AstTransformer {
|
||||
class EventBuilder extends AstTransformer {
|
||||
locals: List<AST> = [];
|
||||
localEvents: List<Event> = [];
|
||||
globalEvents: List<Event> = [];
|
||||
|
|
|
@ -31,7 +31,7 @@ Future<String> createNgSettersAndGetters(
|
|||
return '$out';
|
||||
}
|
||||
|
||||
// TODO(kegluneq): De-dupe from template_compiler/generator.dart.
|
||||
// TODO(kegluneq): De-dupe from template_compiler/generator.dart, #3589.
|
||||
|
||||
/// Consumes the map generated by {@link _createPropertiesMap} to codegen
|
||||
/// setters.
|
||||
|
|
|
@ -3,7 +3,10 @@ library angular2.transform.common.property_utils;
|
|||
import 'package:analyzer/src/generated/scanner.dart' show Keyword;
|
||||
|
||||
/// Whether `name` is a valid property name.
|
||||
bool isValid(String name) => !Keyword.keywords.containsKey(name);
|
||||
bool isValid(String name) {
|
||||
var keyword = Keyword.keywords[name];
|
||||
return keyword == null || keyword.isPseudoKeyword;
|
||||
}
|
||||
|
||||
/// Prepares `name` to be emitted inside a string.
|
||||
String sanitize(String name) => name.replaceAll('\$', '\\\$');
|
||||
|
|
|
@ -23,8 +23,9 @@ import 'package:barback/barback.dart';
|
|||
|
||||
import 'change_detector_codegen.dart' as change;
|
||||
import 'compile_step_factory.dart';
|
||||
import 'reflection_capabilities.dart';
|
||||
import 'reflector_register_codegen.dart' as reg;
|
||||
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
|
||||
|
@ -42,23 +43,22 @@ Future<String> processTemplates(AssetReader reader, AssetId entryPoint,
|
|||
var extractor = new _TemplateExtractor(new DomElementSchemaRegistry(),
|
||||
new TemplateCloner(-1), new XhrImpl(reader, entryPoint));
|
||||
|
||||
var registrations = new reg.Codegen();
|
||||
final processor = new reg.Processor();
|
||||
|
||||
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;
|
||||
var protoView = await extractor.extractTemplates(viewDefEntry.viewDef);
|
||||
if (protoView == null) continue;
|
||||
|
||||
if (generateRegistrations) {
|
||||
// TODO(kegluneq): Generate these getters & setters based on the
|
||||
// `ProtoViewDto` rather than querying the `ReflectionCapabilities`.
|
||||
registrations.generate(result.recording);
|
||||
processor.process(viewDefEntry, protoView);
|
||||
}
|
||||
if (result.protoView != null && generateChangeDetectors) {
|
||||
if (generateChangeDetectors) {
|
||||
var saved = reflector.reflectionCapabilities;
|
||||
reflector.reflectionCapabilities = const NullReflectionCapabilities();
|
||||
var defs = getChangeDetectorDefinitions(viewDefEntry.hostMetadata,
|
||||
result.protoView, viewDefEntry.viewDef.directives);
|
||||
protoView, viewDefEntry.viewDef.directives);
|
||||
for (var i = 0; i < defs.length; ++i) {
|
||||
changeDetectorClasses.generate('${rType.typeName}',
|
||||
'_${rType.typeName}_ChangeDetector$i', defs[i]);
|
||||
|
@ -67,6 +67,10 @@ Future<String> processTemplates(AssetReader reader, AssetId entryPoint,
|
|||
}
|
||||
}
|
||||
|
||||
// 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 =
|
||||
|
@ -93,19 +97,16 @@ class _TemplateExtractor {
|
|||
ElementSchemaRegistry _schemaRegistry;
|
||||
TemplateCloner _templateCloner;
|
||||
|
||||
_TemplateExtractor(ElementSchemaRegistry schemaRegistry,
|
||||
TemplateCloner templateCloner, XHR xhr)
|
||||
_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);
|
||||
_schemaRegistry = schemaRegistry;
|
||||
_templateCloner = templateCloner;
|
||||
}
|
||||
|
||||
Future<_ExtractResult> extractTemplates(ViewDefinition viewDef) async {
|
||||
Future<ProtoViewDto> extractTemplates(ViewDefinition viewDef) async {
|
||||
// Check for "imperative views".
|
||||
if (viewDef.template == null && viewDef.templateAbsUrl == null) return null;
|
||||
|
||||
|
@ -115,8 +116,7 @@ class _TemplateExtractor {
|
|||
// operations between saving and restoring it, otherwise we can get into
|
||||
// a bad state. See issue #2359 for additional context.
|
||||
var savedReflectionCapabilities = reflector.reflectionCapabilities;
|
||||
var recordingCapabilities = new RecordingReflectionCapabilities();
|
||||
reflector.reflectionCapabilities = recordingCapabilities;
|
||||
reflector.reflectionCapabilities = const NullReflectionCapabilities();
|
||||
|
||||
var pipeline = new CompilePipeline(_factory.createSteps(viewDef));
|
||||
|
||||
|
@ -130,13 +130,6 @@ class _TemplateExtractor {
|
|||
|
||||
reflector.reflectionCapabilities = savedReflectionCapabilities;
|
||||
|
||||
return new _ExtractResult(recordingCapabilities, protoViewDto);
|
||||
return protoViewDto;
|
||||
}
|
||||
}
|
||||
|
||||
class _ExtractResult {
|
||||
final RecordingReflectionCapabilities recording;
|
||||
final ProtoViewDto protoView;
|
||||
|
||||
_ExtractResult(this.recording, this.protoView);
|
||||
}
|
||||
|
|
|
@ -1,25 +1,32 @@
|
|||
library angular2.transform.template_compiler.reflector_register_codegen;
|
||||
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 'reflection_capabilities.dart';
|
||||
|
||||
import 'model.dart';
|
||||
|
||||
class Codegen {
|
||||
final StringBuffer _buf = new StringBuffer();
|
||||
|
||||
void generate(RecordingReflectionCapabilities recording) {
|
||||
if (recording != null) {
|
||||
var calls = _generateGetters(recording.getterNames);
|
||||
/// 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(recording.setterNames);
|
||||
calls = _generateSetters(_extractNames(model.setterNames));
|
||||
if (calls.isNotEmpty) {
|
||||
_buf.write('..${REGISTER_SETTERS_METHOD_NAME}'
|
||||
'({${calls.join(', ')}})');
|
||||
}
|
||||
calls = _generateMethods(recording.methodNames);
|
||||
calls = _generateMethods(_extractNames(model.methodNames));
|
||||
if (calls.isNotEmpty) {
|
||||
_buf.write('..${REGISTER_METHODS_METHOD_NAME}'
|
||||
'({${calls.join(', ')}})');
|
||||
|
@ -27,6 +34,15 @@ class Codegen {
|
|||
}
|
||||
}
|
||||
|
||||
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
|
|
@ -0,0 +1,49 @@
|
|||
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);
|
||||
}
|
|
@ -0,0 +1,124 @@
|
|||
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);
|
||||
}
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
library angular2.transform.template_compiler.reflection_capabilities;
|
||||
library angular2.transform.template_compiler.reflection.reflection_capabilities;
|
||||
|
||||
import 'package:angular2/src/reflection/reflection_capabilities.dart';
|
||||
import 'package:angular2/src/reflection/types.dart';
|
||||
|
@ -32,32 +32,3 @@ class NullReflectionCapabilities implements ReflectionCapabilities {
|
|||
_nullGetter(Object p) => null;
|
||||
_nullSetter(Object p, v) => null;
|
||||
_nullMethod(Object p, List a) => null;
|
||||
|
||||
/// ReflectionCapabilities object that records requests for `getter`s,
|
||||
/// `setter`s, and `method`s so these can be code generated rather than
|
||||
/// reflectively accessed at runtime.
|
||||
class RecordingReflectionCapabilities extends NullReflectionCapabilities {
|
||||
/// The names of all requested `getter`s.
|
||||
final Set<String> getterNames = new Set<String>();
|
||||
|
||||
/// The names of all requested `setter`s.
|
||||
final Set<String> setterNames = new Set<String>();
|
||||
|
||||
/// The names of all requested `method`s.
|
||||
final Set<String> methodNames = new Set<String>();
|
||||
|
||||
GetterFn getter(String name) {
|
||||
getterNames.add(name);
|
||||
return super.getter(name);
|
||||
}
|
||||
|
||||
SetterFn setter(String name) {
|
||||
setterNames.add(name);
|
||||
return super.setter(name);
|
||||
}
|
||||
|
||||
MethodFn method(String name) {
|
||||
methodNames.add(name);
|
||||
return super.method(name);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
import {EventConfig} from 'angular2/src/render/dom/util';
|
||||
import {ddescribe, describe, expect, it} from 'angular2/test_lib';
|
||||
|
||||
export function main() {
|
||||
describe('EventConfig', () => {
|
||||
describe('parse', () => {
|
||||
it('should handle short form events', () => {
|
||||
var eventConfig = EventConfig.parse('shortForm');
|
||||
expect(eventConfig.fieldName).toEqual('shortForm');
|
||||
expect(eventConfig.eventName).toEqual('shortForm');
|
||||
expect(eventConfig.isLongForm).toEqual(false);
|
||||
});
|
||||
it('should handle long form events', () => {
|
||||
var eventConfig = EventConfig.parse('fieldName: eventName');
|
||||
expect(eventConfig.fieldName).toEqual('fieldName');
|
||||
expect(eventConfig.eventName).toEqual('eventName');
|
||||
expect(eventConfig.isLongForm).toEqual(true);
|
||||
});
|
||||
});
|
||||
describe('getFullName', () => {
|
||||
it('should handle short form events', () => {
|
||||
var eventConfig = new EventConfig('shortForm', 'shortForm', false);
|
||||
expect(eventConfig.getFullName()).toEqual('shortForm');
|
||||
});
|
||||
it('should handle long form events', () => {
|
||||
var eventConfig = new EventConfig('fieldName', 'eventName', true);
|
||||
expect(eventConfig.getFullName()).toEqual('fieldName:eventName');
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
|
@ -19,8 +19,7 @@ void initReflector() {
|
|||
const Component(selector: '[soup]'),
|
||||
const View(template: 'Salad: {{myNum}} is awesome')
|
||||
], const [], () => new MyComponent()))
|
||||
..registerGetters({'myNum': (o) => o.myNum})
|
||||
..registerSetters({'myNum': (o, v) => o.myNum = v});
|
||||
..registerGetters({'myNum': (o) => o.myNum});
|
||||
_gen.preGeneratedProtoDetectors['MyComponent_comp_0'] =
|
||||
_MyComponent_ChangeDetector0.newProtoChangeDetector;
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@ import 'package:angular2/src/transform/common/asset_reader.dart';
|
|||
import 'package:angular2/src/transform/common/logging.dart';
|
||||
import 'package:angular2/src/transform/template_compiler/generator.dart';
|
||||
import 'package:dart_style/dart_style.dart';
|
||||
import 'package:path/path.dart' as path;
|
||||
import 'package:guinness/guinness.dart';
|
||||
|
||||
import '../common/read_file.dart';
|
||||
|
@ -31,7 +32,7 @@ void changeDetectorTests() {
|
|||
// TODO(tbosch): This is just a temporary test that makes sure that the dart server and
|
||||
// dart browser is in sync. Change this to "not contains notifyBinding"
|
||||
// when https://github.com/angular/angular/issues/3019 is solved.
|
||||
it('shouldn always notifyDispatcher for template variables', () async {
|
||||
it('should not always notifyDispatcher for template variables', () async {
|
||||
var inputPath = 'template_compiler/ng_for_files/hello.ng_deps.dart';
|
||||
var output = await (process(new AssetId('a', inputPath)));
|
||||
expect(output).toContain('notifyDispatcher');
|
||||
|
@ -90,7 +91,7 @@ void noChangeDetectorTests() {
|
|||
_formatThenExpectEquals(output, expected);
|
||||
});
|
||||
|
||||
it('should not generated duplicate getters/setters', () async {
|
||||
it('should not generate duplicate getters/setters', () async {
|
||||
var inputPath = 'template_compiler/duplicate_files/hello.ng_deps.dart';
|
||||
var expected = readFile(
|
||||
'template_compiler/duplicate_files/expected/hello.ng_deps.dart');
|
||||
|
@ -144,6 +145,15 @@ void noChangeDetectorTests() {
|
|||
output = await process(new AssetId('a', inputPath));
|
||||
_formatThenExpectEquals(output, expected);
|
||||
});
|
||||
|
||||
it('should generate all expected getters, setters, & methods.', () async {
|
||||
var base = 'template_compiler/registrations_files';
|
||||
var inputPath = path.join(base, 'registrations.ng_deps.dart');
|
||||
var expected =
|
||||
readFile(path.join(base, 'expected/registrations.ng_deps.dart'));
|
||||
var output = await process(new AssetId('a', inputPath));
|
||||
_formatThenExpectEquals(output, expected);
|
||||
});
|
||||
}
|
||||
|
||||
void _formatThenExpectEquals(String actual, String expected) {
|
||||
|
|
|
@ -17,6 +17,5 @@ void initReflector(reflector) {
|
|||
], const [
|
||||
const []
|
||||
], () => new HelloCmp()))
|
||||
..registerGetters({'greeting': (o) => o.greeting})
|
||||
..registerSetters({'greeting': (o, v) => o.greeting = v});
|
||||
..registerGetters({'greeting': (o) => o.greeting});
|
||||
}
|
||||
|
|
|
@ -18,6 +18,5 @@ void initReflector(reflector) {
|
|||
const []
|
||||
], () => new HelloCmp()))
|
||||
..registerGetters({'b': (o) => o.b, 'greeting': (o) => o.greeting})
|
||||
..registerSetters(
|
||||
{'b': (o, v) => o.b = v, 'greeting': (o, v) => o.greeting = v});
|
||||
..registerSetters({'a': (o, v) => o.a = v});
|
||||
}
|
||||
|
|
|
@ -13,7 +13,7 @@ void initReflector(reflector) {
|
|||
HelloCmp,
|
||||
new ReflectionInfo(const [
|
||||
const Component(selector: 'hello-app'),
|
||||
const View(template: '<button (click)=\"action()\">go</button>')
|
||||
const View(template: '<button (click)="action()">go</button>')
|
||||
], const [
|
||||
const []
|
||||
], () => new HelloCmp()))
|
||||
|
|
|
@ -13,7 +13,7 @@ void initReflector(reflector) {
|
|||
HelloCmp,
|
||||
new ReflectionInfo(const [
|
||||
const Component(selector: 'hello-app'),
|
||||
const View(template: '<button (click)=\"action()\">go</button>')
|
||||
const View(template: '<button (click)="action()">go</button>')
|
||||
], const [
|
||||
const []
|
||||
], () => new HelloCmp()));
|
||||
|
|
|
@ -0,0 +1,98 @@
|
|||
{
|
||||
"DependencyCmp": {
|
||||
"kind": "type",
|
||||
"value": {
|
||||
"id": "DependencyCmp",
|
||||
"selector": "dependency",
|
||||
"compileChildren": true,
|
||||
"hostProperties": {},
|
||||
"hostListeners": {},
|
||||
"hostActions": {},
|
||||
"hostAttributes": {},
|
||||
"properties": null,
|
||||
"readAttributes": null,
|
||||
"type": null,
|
||||
"exportAs": null,
|
||||
"callOnDestroy": null,
|
||||
"callOnCheck": null,
|
||||
"callOnInit": null,
|
||||
"callOnChange": null,
|
||||
"callOnAllChangesDone": null,
|
||||
"events": ["dependencyEventName"],
|
||||
"changeDetection": null,
|
||||
"version": 1
|
||||
}
|
||||
},
|
||||
"DirectiveProps": {
|
||||
"kind": "type",
|
||||
"value": {
|
||||
"id": "DirectiveProps",
|
||||
"selector": "[dir-props]",
|
||||
"compileChildren": true,
|
||||
"hostProperties": {"hprop": "hprop"},
|
||||
"hostListeners": {},
|
||||
"hostActions": {},
|
||||
"hostAttributes": {},
|
||||
"properties": ["prop"],
|
||||
"readAttributes": null,
|
||||
"type": null,
|
||||
"exportAs": null,
|
||||
"callOnDestroy": null,
|
||||
"callOnCheck": null,
|
||||
"callOnInit": null,
|
||||
"callOnChange": null,
|
||||
"callOnAllChangesDone": null,
|
||||
"events": null,
|
||||
"changeDetection": null,
|
||||
"version": 1
|
||||
}
|
||||
},
|
||||
"DirectiveEvents": {
|
||||
"kind": "type",
|
||||
"value": {
|
||||
"id": "DirectiveEvents",
|
||||
"selector": "[dir-events]",
|
||||
"compileChildren": true,
|
||||
"hostProperties": {},
|
||||
"hostListeners": {"subevent": "doAThing()"},
|
||||
"hostActions": {},
|
||||
"hostAttributes": {},
|
||||
"properties": [],
|
||||
"readAttributes": null,
|
||||
"type": null,
|
||||
"exportAs": null,
|
||||
"callOnDestroy": null,
|
||||
"callOnCheck": null,
|
||||
"callOnInit": null,
|
||||
"callOnChange": null,
|
||||
"callOnAllChangesDone": null,
|
||||
"events": null,
|
||||
"changeDetection": null,
|
||||
"version": 1
|
||||
}
|
||||
},
|
||||
"NgFor": {
|
||||
"kind": "type",
|
||||
"value": {
|
||||
"id": "NgFor",
|
||||
"selector": "[ng-for][ng-for-of]",
|
||||
"compileChildren": true,
|
||||
"hostProperties": {},
|
||||
"hostListeners": {},
|
||||
"hostActions": {},
|
||||
"hostAttributes": {},
|
||||
"properties": ["ngForOf"],
|
||||
"readAttributes": null,
|
||||
"type": null,
|
||||
"exportAs": null,
|
||||
"callOnDestroy": null,
|
||||
"callOnCheck": true,
|
||||
"callOnInit": null,
|
||||
"callOnChange": null,
|
||||
"callOnAllChangesDone": null,
|
||||
"events": null,
|
||||
"changeDetection": null,
|
||||
"version": 1
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,108 @@
|
|||
library examples.hello_world.index_common_dart.ng_deps.dart;
|
||||
|
||||
import 'dependency.dart';
|
||||
import 'dependency.ng_deps.dart' as i0;
|
||||
import 'hello.dart';
|
||||
import 'package:angular2/angular2.dart'
|
||||
show Component, Directive, View, NgElement;
|
||||
|
||||
var _visited = false;
|
||||
void initReflector(reflector) {
|
||||
if (_visited) return;
|
||||
_visited = true;
|
||||
reflector
|
||||
..registerType(
|
||||
TextBindingsCmp,
|
||||
new ReflectionInfo(const [
|
||||
const Component(selector: 'text'),
|
||||
const View(template: '{{textBindings}}')
|
||||
], const [
|
||||
const []
|
||||
], () => new TextBindingsCmp()))
|
||||
..registerType(
|
||||
PropertyBindingsCmp,
|
||||
new ReflectionInfo(const [
|
||||
const Component(selector: 'props'),
|
||||
const View(template: '<div [prop-name]="propValue"></div>')
|
||||
], const [
|
||||
const []
|
||||
], () => new PropertyBindingsCmp()))
|
||||
..registerType(
|
||||
EventsCmp,
|
||||
new ReflectionInfo(const [
|
||||
const Component(selector: 'events', events: const ['eventName']),
|
||||
const View(template: 'Hi')
|
||||
], const [
|
||||
const []
|
||||
], () => new EventsCmp()))
|
||||
..registerType(
|
||||
SubEventsCmp,
|
||||
new ReflectionInfo(const [
|
||||
const Component(selector: 'sub-events'),
|
||||
const View(
|
||||
template: '<dependency></dependency>',
|
||||
directives: const [DependencyCmp])
|
||||
], const [
|
||||
const []
|
||||
], () => new SubEventsCmp()))
|
||||
..registerType(
|
||||
TemplateEventsCmp,
|
||||
new ReflectionInfo(const [
|
||||
const Component(selector: 'template-events'),
|
||||
const View(template: '<div (mouseover)="onMouseOver()"></div>')
|
||||
], const [
|
||||
const []
|
||||
], () => new TemplateEventsCmp()))
|
||||
..registerType(
|
||||
DirectivePropsCmp,
|
||||
new ReflectionInfo(const [
|
||||
const Component(selector: 'directive-props-cmp'),
|
||||
const View(
|
||||
template: '<div dir-props prop="somevalue">',
|
||||
directives: const [DirectiveProps])
|
||||
], const [
|
||||
const []
|
||||
], () => new DirectivePropsCmp()))
|
||||
..registerType(
|
||||
DirectiveEventsCmp,
|
||||
new ReflectionInfo(const [
|
||||
const Component(selector: 'directive-events-cmp'),
|
||||
const View(
|
||||
template: '<div dir-events (subevent)="field = 10;">',
|
||||
directives: const [DirectiveEvents])
|
||||
], const [
|
||||
const []
|
||||
], () => new DirectiveEventsCmp()))
|
||||
..registerType(
|
||||
RecursiveCmp,
|
||||
new ReflectionInfo(const [
|
||||
const Component(selector: 'recursive-cmp'),
|
||||
const View(
|
||||
template:
|
||||
'<li *ng-for="#thing of things" [recursive-prop]="thing"><div>test</div></li>',
|
||||
directives: const [NgFor])
|
||||
], const [
|
||||
const []
|
||||
], () => new RecursiveCmp()))
|
||||
..registerGetters({
|
||||
'eventName': (o) => o.eventName,
|
||||
'hprop': (o) => o.hprop,
|
||||
'propValue': (o) => o.propValue,
|
||||
'textBindings': (o) => o.textBindings,
|
||||
'thing': (o) => o.thing,
|
||||
'things': (o) => o.things
|
||||
})
|
||||
..registerSetters({
|
||||
'field': (o, v) => o.field = v,
|
||||
'hprop': (o, v) => o.hprop = v,
|
||||
'ngForOf': (o, v) => o.ngForOf = v,
|
||||
'prop': (o, v) => o.prop = v,
|
||||
'propName': (o, v) => o.propName = v,
|
||||
'recursiveProp': (o, v) => o.recursiveProp = v
|
||||
})
|
||||
..registerMethods({
|
||||
'doAThing': (o, List args) => Function.apply(o.doAThing, args),
|
||||
'onMouseOver': (o, List args) => Function.apply(o.onMouseOver, args)
|
||||
});
|
||||
i0.initReflector();
|
||||
}
|
|
@ -0,0 +1,88 @@
|
|||
library examples.hello_world.index_common_dart.ng_deps.dart;
|
||||
|
||||
import 'dependency.dart';
|
||||
import 'dependency.ng_deps.dart' as i0;
|
||||
import 'hello.dart';
|
||||
import 'package:angular2/angular2.dart'
|
||||
show Component, Directive, View, NgElement;
|
||||
|
||||
var _visited = false;
|
||||
void initReflector(reflector) {
|
||||
if (_visited) return;
|
||||
_visited = true;
|
||||
reflector
|
||||
..registerType(
|
||||
TextBindingsCmp,
|
||||
new ReflectionInfo(const [
|
||||
const Component(selector: 'text'),
|
||||
const View(template: '{{textBindings}}')
|
||||
], const [
|
||||
const []
|
||||
], () => new TextBindingsCmp()))
|
||||
..registerType(
|
||||
PropertyBindingsCmp,
|
||||
new ReflectionInfo(const [
|
||||
const Component(selector: 'props'),
|
||||
const View(template: '<div [prop-name]="propValue"></div>')
|
||||
], const [
|
||||
const []
|
||||
], () => new PropertyBindingsCmp()))
|
||||
..registerType(
|
||||
EventsCmp,
|
||||
new ReflectionInfo(const [
|
||||
const Component(selector: 'events', events: const ['eventName']),
|
||||
const View(template: 'Hi')
|
||||
], const [
|
||||
const []
|
||||
], () => new EventsCmp()))
|
||||
..registerType(
|
||||
SubEventsCmp,
|
||||
new ReflectionInfo(const [
|
||||
const Component(selector: 'sub-events'),
|
||||
const View(
|
||||
template: '<dependency></dependency>',
|
||||
directives: const [DependencyCmp])
|
||||
], const [
|
||||
const []
|
||||
], () => new SubEventsCmp()))
|
||||
..registerType(
|
||||
TemplateEventsCmp,
|
||||
new ReflectionInfo(const [
|
||||
const Component(selector: 'template-events'),
|
||||
const View(template: '<div (mouseover)="onMouseOver()"></div>')
|
||||
], const [
|
||||
const []
|
||||
], () => new TemplateEventsCmp()))
|
||||
..registerType(
|
||||
DirectivePropsCmp,
|
||||
new ReflectionInfo(const [
|
||||
const Component(selector: 'directive-props-cmp'),
|
||||
const View(
|
||||
template: '<div dir-props prop="somevalue">',
|
||||
directives: const [DirectiveProps])
|
||||
], const [
|
||||
const []
|
||||
], () => new DirectivePropsCmp()))
|
||||
..registerType(
|
||||
DirectiveEventsCmp,
|
||||
new ReflectionInfo(const [
|
||||
const Component(selector: 'directive-events-cmp'),
|
||||
const View(
|
||||
template: '<div dir-events (subevent)="field = 10;">',
|
||||
directives: const [DirectiveEvents])
|
||||
], const [
|
||||
const []
|
||||
], () => new DirectiveEventsCmp()))
|
||||
..registerType(
|
||||
RecursiveCmp,
|
||||
new ReflectionInfo(const [
|
||||
const Component(selector: 'recursive-cmp'),
|
||||
const View(
|
||||
template:
|
||||
'<li *ng-for="#thing of things" [recursive-prop]="thing"><div>test</div></li>',
|
||||
directives: const [NgFor])
|
||||
], const [
|
||||
const []
|
||||
], () => new RecursiveCmp()));
|
||||
i0.initReflector();
|
||||
}
|
|
@ -0,0 +1,194 @@
|
|||
{
|
||||
"TextBindingsCmp": {
|
||||
"kind": "type",
|
||||
"value": {
|
||||
"id": "TextBindingsCmp",
|
||||
"selector": "text",
|
||||
"compileChildren": true,
|
||||
"hostProperties": {},
|
||||
"hostListeners": {},
|
||||
"hostActions": {},
|
||||
"hostAttributes": {},
|
||||
"properties": null,
|
||||
"readAttributes": null,
|
||||
"type": null,
|
||||
"exportAs": null,
|
||||
"callOnDestroy": null,
|
||||
"callOnCheck": null,
|
||||
"callOnInit": null,
|
||||
"callOnChange": null,
|
||||
"callOnAllChangesDone": null,
|
||||
"events": null,
|
||||
"changeDetection": null,
|
||||
"version": 1
|
||||
}
|
||||
},
|
||||
"PropertyBindingsCmp": {
|
||||
"kind": "type",
|
||||
"value": {
|
||||
"id": "PropertyBindingsCmp",
|
||||
"selector": "props",
|
||||
"compileChildren": true,
|
||||
"hostProperties": {},
|
||||
"hostListeners": {},
|
||||
"hostActions": {},
|
||||
"hostAttributes": {},
|
||||
"properties": [],
|
||||
"readAttributes": [],
|
||||
"type": 0,
|
||||
"exportAs": null,
|
||||
"callOnDestroy": false,
|
||||
"callOnCheck": false,
|
||||
"callOnInit": false,
|
||||
"callOnChange": false,
|
||||
"callOnAllChangesDone": false,
|
||||
"events": [],
|
||||
"changeDetection": null,
|
||||
"version": 1
|
||||
}
|
||||
},
|
||||
"EventsCmp": {
|
||||
"kind": "type",
|
||||
"value": {
|
||||
"id": "EventsCmp",
|
||||
"selector": "events",
|
||||
"compileChildren": true,
|
||||
"hostProperties": {},
|
||||
"hostListeners": {},
|
||||
"hostActions": {},
|
||||
"hostAttributes": {},
|
||||
"properties": [],
|
||||
"readAttributes": [],
|
||||
"type": 1,
|
||||
"exportAs": null,
|
||||
"callOnDestroy": false,
|
||||
"callOnCheck": false,
|
||||
"callOnInit": false,
|
||||
"callOnChange": false,
|
||||
"callOnAllChangesDone": false,
|
||||
"events": ["eventName"],
|
||||
"changeDetection": null,
|
||||
"version": 1
|
||||
}
|
||||
},
|
||||
"SubEventsCmp": {
|
||||
"kind": "type",
|
||||
"value": {
|
||||
"id": "SubEventsCmp",
|
||||
"selector": "events",
|
||||
"compileChildren": true,
|
||||
"hostProperties": {},
|
||||
"hostListeners": {},
|
||||
"hostActions": {},
|
||||
"hostAttributes": {},
|
||||
"properties": [],
|
||||
"readAttributes": [],
|
||||
"type": 1,
|
||||
"exportAs": null,
|
||||
"callOnDestroy": false,
|
||||
"callOnCheck": false,
|
||||
"callOnInit": false,
|
||||
"callOnChange": false,
|
||||
"callOnAllChangesDone": false,
|
||||
"events": [],
|
||||
"changeDetection": null,
|
||||
"version": 1
|
||||
}
|
||||
},
|
||||
"TemplateEventsCmp": {
|
||||
"kind": "type",
|
||||
"value": {
|
||||
"id": "TemplateEventsCmp",
|
||||
"selector": "template-events",
|
||||
"compileChildren": true,
|
||||
"hostProperties": {},
|
||||
"hostListeners": {},
|
||||
"hostActions": {},
|
||||
"hostAttributes": {},
|
||||
"properties": [],
|
||||
"readAttributes": [],
|
||||
"type": 1,
|
||||
"exportAs": null,
|
||||
"callOnDestroy": false,
|
||||
"callOnCheck": false,
|
||||
"callOnInit": false,
|
||||
"callOnChange": false,
|
||||
"callOnAllChangesDone": false,
|
||||
"events": [],
|
||||
"changeDetection": null,
|
||||
"version": 1
|
||||
}
|
||||
},
|
||||
"DirectivePropsCmp": {
|
||||
"kind": "type",
|
||||
"value": {
|
||||
"id": "DirectivePropsCmp",
|
||||
"selector": "directive-props-cmp",
|
||||
"compileChildren": true,
|
||||
"hostProperties": {},
|
||||
"hostListeners": {},
|
||||
"hostActions": {},
|
||||
"hostAttributes": {},
|
||||
"properties": [],
|
||||
"readAttributes": [],
|
||||
"type": 1,
|
||||
"exportAs": null,
|
||||
"callOnDestroy": false,
|
||||
"callOnCheck": false,
|
||||
"callOnInit": false,
|
||||
"callOnChange": false,
|
||||
"callOnAllChangesDone": false,
|
||||
"events": [],
|
||||
"changeDetection": null,
|
||||
"version": 1
|
||||
}
|
||||
},
|
||||
"DirectiveEventsCmp": {
|
||||
"kind": "type",
|
||||
"value": {
|
||||
"id": "DirectiveEventsCmp",
|
||||
"selector": "directive-events-cmp",
|
||||
"compileChildren": true,
|
||||
"hostProperties": {},
|
||||
"hostListeners": {},
|
||||
"hostActions": {},
|
||||
"hostAttributes": {},
|
||||
"properties": [],
|
||||
"readAttributes": [],
|
||||
"type": 1,
|
||||
"exportAs": null,
|
||||
"callOnDestroy": false,
|
||||
"callOnCheck": false,
|
||||
"callOnInit": false,
|
||||
"callOnChange": false,
|
||||
"callOnAllChangesDone": false,
|
||||
"events": [],
|
||||
"changeDetection": null,
|
||||
"version": 1
|
||||
}
|
||||
},
|
||||
"RecursiveCmp": {
|
||||
"kind": "type",
|
||||
"value": {
|
||||
"id": "RecursiveCmp",
|
||||
"selector": "recursive-cmp",
|
||||
"compileChildren": true,
|
||||
"hostProperties": {},
|
||||
"hostListeners": {},
|
||||
"hostActions": {},
|
||||
"hostAttributes": {},
|
||||
"properties": [],
|
||||
"readAttributes": [],
|
||||
"type": 1,
|
||||
"exportAs": null,
|
||||
"callOnDestroy": false,
|
||||
"callOnCheck": false,
|
||||
"callOnInit": false,
|
||||
"callOnChange": false,
|
||||
"callOnAllChangesDone": false,
|
||||
"events": [],
|
||||
"changeDetection": null,
|
||||
"version": 1
|
||||
}
|
||||
}
|
||||
}
|
|
@ -17,6 +17,5 @@ void initReflector(reflector) {
|
|||
], const [
|
||||
const []
|
||||
], () => new HelloCmp()))
|
||||
..registerGetters({'greeting': (o) => o.greeting})
|
||||
..registerSetters({'greeting': (o, v) => o.greeting = v});
|
||||
..registerGetters({'greeting': (o) => o.greeting});
|
||||
}
|
||||
|
|
|
@ -17,6 +17,5 @@ void initReflector(reflector) {
|
|||
], const [
|
||||
const []
|
||||
], () => new GoodbyeCmp()))
|
||||
..registerGetters({'name': (o) => o.name})
|
||||
..registerSetters({'name': (o, v) => o.name = v});
|
||||
..registerGetters({'name': (o) => o.name});
|
||||
}
|
||||
|
|
|
@ -17,6 +17,5 @@ void initReflector(reflector) {
|
|||
], const [
|
||||
const []
|
||||
], () => new MyApp()))
|
||||
..registerGetters({'name': (o) => o.name})
|
||||
..registerSetters({'name': (o, v) => o.name = v});
|
||||
..registerGetters({'name': (o) => o.name});
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue