refactor(change_detection): introduce enum ChangeDetectionStrategy

BREAKING CHANGE

Closes #2497

- change detection strategy type changes from string to ChangeDetectionStrategy
- CHECK_ONCE => ChangeDetectionStrategy.CheckOnce
- CHECKED => ChangeDetectionStrategy.Checked
- CHECK_ALWAYS => ChangeDetectionStrategy.CheckAlways
- DETACHED => ChangeDetectionStrategy.Detached
- ON_PUSH => ChangeDetectionStrategy.OnPush
- DEFAULT => ChangeDetectionStrategy.Default
- ON_PUSH_OBSERVE => ChangeDetectionStrategy.OnPushObserve
This commit is contained in:
Misko Hevery
2015-08-26 11:44:59 -07:00
parent e41d7451bf
commit 69926dd002
35 changed files with 388 additions and 365 deletions

View File

@ -0,0 +1,71 @@
library angular2.transform.common.convert;
import "package:angular2/src/core/facade/collection.dart"
show ListWrapper, MapWrapper;
import "package:angular2/src/core/facade/lang.dart" show isPresent, isArray;
import "package:angular2/src/core/render/api.dart" show RenderDirectiveMetadata;
import "package:angular2/src/core/change_detection/change_detection.dart"
show ChangeDetectionStrategy;
/**
* Converts a [DirectiveMetadata] to a map representation. This creates a copy,
* that is, subsequent changes to `meta` will not be mirrored in the map.
*/
Map<String, dynamic> directiveMetadataToMap(RenderDirectiveMetadata meta) {
return MapWrapper.createFromPairs([
["id", meta.id],
["selector", meta.selector],
["compileChildren", meta.compileChildren],
["hostProperties", _cloneIfPresent(meta.hostProperties)],
["hostListeners", _cloneIfPresent(meta.hostListeners)],
["hostAttributes", _cloneIfPresent(meta.hostAttributes)],
["properties", _cloneIfPresent(meta.properties)],
["readAttributes", _cloneIfPresent(meta.readAttributes)],
["type", meta.type],
["exportAs", meta.exportAs],
["callOnDestroy", meta.callOnDestroy],
["callOnCheck", meta.callOnCheck],
["callOnInit", meta.callOnInit],
["callOnChange", meta.callOnChange],
["callOnAllChangesDone", meta.callOnAllChangesDone],
["events", meta.events],
["changeDetection", meta.changeDetection == null ? null : meta.changeDetection.index],
["version", 1]
]);
}
/**
* Converts a map representation of [DirectiveMetadata] into a
* [DirectiveMetadata] object. This creates a copy, that is, subsequent changes
* to `map` will not be mirrored in the [DirectiveMetadata] object.
*/
RenderDirectiveMetadata directiveMetadataFromMap(Map<String, dynamic> map) {
return new RenderDirectiveMetadata(
id: (map["id"] as String),
selector: (map["selector"] as String),
compileChildren: (map["compileChildren"] as bool),
hostProperties: (_cloneIfPresent(
map["hostProperties"]) as Map<String, String>),
hostListeners: (_cloneIfPresent(
map["hostListeners"]) as Map<String, String>),
hostAttributes: (_cloneIfPresent(
map["hostAttributes"]) as Map<String, String>),
properties: (_cloneIfPresent(map["properties"]) as List<String>),
readAttributes: (_cloneIfPresent(map["readAttributes"]) as List<String>),
type: (map["type"] as num),
exportAs: (map["exportAs"] as String),
callOnDestroy: (map["callOnDestroy"] as bool),
callOnCheck: (map["callOnCheck"] as bool),
callOnChange: (map["callOnChange"] as bool),
callOnInit: (map["callOnInit"] as bool),
callOnAllChangesDone: (map["callOnAllChangesDone"] as bool),
events: (_cloneIfPresent(map["events"]) as List<String>),
changeDetection: map["changeDetection"] == null ? null
: ChangeDetectionStrategy.values[map["changeDetection"] as int]);
}
/**
* Clones the [List] or [Map] `o` if it is present.
*/
dynamic _cloneIfPresent(o) {
if (!isPresent(o)) return null;
return isArray(o) ? ListWrapper.clone(o) : MapWrapper.clone(o);
}

View File

@ -3,6 +3,7 @@ library angular2.transform.common.directive_metadata_reader;
import 'package:analyzer/analyzer.dart';
import 'package:analyzer/src/generated/element.dart';
import 'package:angular2/src/core/render/api.dart';
import 'package:angular2/src/core/change_detection/change_detection.dart';
/// Reads [RenderDirectiveMetadata] from the `node`. `node` is expected to be an
/// instance of [Annotation], [NodeList<Annotation>], ListLiteral, or
@ -63,7 +64,7 @@ class _DirectiveMetadataVisitor extends Object
bool _callOnCheck;
bool _callOnInit;
bool _callOnAllChangesDone;
String _changeDetection;
ChangeDetectionStrategy _changeDetection;
List<String> _events;
final ConstantEvaluator _evaluator = new ConstantEvaluator();
@ -283,6 +284,9 @@ class _DirectiveMetadataVisitor extends Object
void _populateChangeDetection(Expression value) {
_checkMeta();
_changeDetection = _expressionToString(value, 'Directive#changeDetection');
_changeDetection = changeDetectionStrategies[value.toSource()];
}
}
final Map<String, ChangeDetectionStrategy> changeDetectionStrategies
= new Map.fromIterable(ChangeDetectionStrategy.values, key: (v) => v.toString());

View File

@ -1,7 +1,7 @@
library angular2.transform.common.ng_meta;
import 'package:angular2/src/core/render/api.dart';
import 'package:angular2/src/core/render/dom/convert.dart';
import 'convert.dart';
import 'logging.dart';
/// Metadata about directives and directive aliases.

View File

@ -1,5 +1,6 @@
library angular2.transform.template_compiler.change_detector_codegen;
import 'package:angular2/src/core/change_detection/change_detection.dart';
import 'package:angular2/src/core/change_detection/change_detection_util.dart';
import 'package:angular2/src/core/change_detection/codegen_facade.dart';
import 'package:angular2/src/core/change_detection/codegen_logic_util.dart';
@ -75,7 +76,7 @@ class _CodegenState {
/// 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 ChangeDetectionStrategy _changeDetectionStrategy;
final List<DirectiveRecord> _directiveRecords;
final List<ProtoRecord> _records;
final List<EventBinding> _eventBindings;
@ -84,6 +85,9 @@ class _CodegenState {
final ChangeDetectorGenConfig _genConfig;
final List<BindingTarget> _propertyBindingTargets;
String get _changeDetectionStrategyAsCode =>
_changeDetectionStrategy == null ? 'null' : '${_GEN_PREFIX}.${_changeDetectionStrategy}';
_CodegenState._(
this._changeDetectorDefId,
this._contextTypeName,
@ -129,7 +133,7 @@ class _CodegenState {
dispatcher, ${_records.length},
${_changeDetectorTypeName}.gen_propertyBindingTargets,
${_changeDetectorTypeName}.gen_directiveIndices,
${codify(_changeDetectionStrategy)}) {
${_changeDetectionStrategyAsCode}) {
dehydrateDirectives(false);
}

View File

@ -0,0 +1,97 @@
library angular2.test.transform.common.convert_spec;
import "package:angular2/src/core/facade/collection.dart" show MapWrapper;
import "package:angular2/src/core/render/api.dart" show RenderDirectiveMetadata;
import "package:angular2/src/transform/common/convert.dart"
show directiveMetadataFromMap, directiveMetadataToMap;
import "package:angular2/test_lib.dart" show ddescribe, describe, expect, it;
import "package:angular2/src/core/change_detection/change_detection.dart"
show ChangeDetectionStrategy;
main() {
describe("convert", () {
it("directiveMetadataToMap", () {
var someComponent = new RenderDirectiveMetadata(
compileChildren: false,
hostListeners: MapWrapper.createFromPairs([["LKey", "LVal"]]),
hostProperties: MapWrapper.createFromPairs([["PKey", "PVal"]]),
hostAttributes: MapWrapper.createFromPairs([["AtKey", "AtVal"]]),
id: "someComponent",
properties: ["propKey: propVal"],
readAttributes: ["read1", "read2"],
selector: "some-comp",
type: RenderDirectiveMetadata.COMPONENT_TYPE,
exportAs: "aaa",
callOnDestroy: true,
callOnChange: true,
callOnCheck: true,
callOnInit: true,
callOnAllChangesDone: true,
events: ["onFoo", "onBar"],
changeDetection: ChangeDetectionStrategy.CheckOnce);
var map = directiveMetadataToMap(someComponent);
expect(map["compileChildren"]).toEqual(false);
expect(map["hostListeners"])
.toEqual(MapWrapper.createFromPairs([["LKey", "LVal"]]));
expect(map["hostProperties"])
.toEqual(MapWrapper.createFromPairs([["PKey", "PVal"]]));
expect(map["hostAttributes"])
.toEqual(MapWrapper.createFromPairs([["AtKey", "AtVal"]]));
expect(map["id"]).toEqual("someComponent");
expect(map["properties"]).toEqual(["propKey: propVal"]);
expect(map["readAttributes"]).toEqual(["read1", "read2"]);
expect(map["selector"]).toEqual("some-comp");
expect(map["type"]).toEqual(RenderDirectiveMetadata.COMPONENT_TYPE);
expect(map["callOnDestroy"]).toEqual(true);
expect(map["callOnCheck"]).toEqual(true);
expect(map["callOnChange"]).toEqual(true);
expect(map["callOnInit"]).toEqual(true);
expect(map["callOnAllChangesDone"]).toEqual(true);
expect(map["exportAs"]).toEqual("aaa");
expect(map["events"]).toEqual(["onFoo", "onBar"]);
expect(map["changeDetection"]).toEqual(ChangeDetectionStrategy.CheckOnce.index);
});
it("mapToDirectiveMetadata", () {
var map = MapWrapper.createFromPairs([
["compileChildren", false],
["hostProperties", MapWrapper.createFromPairs([["PKey", "testVal"]])],
["hostListeners", MapWrapper.createFromPairs([["LKey", "testVal"]])],
["hostAttributes", MapWrapper.createFromPairs([["AtKey", "testVal"]])],
["id", "testId"],
["properties", ["propKey: propVal"]],
["readAttributes", ["readTest1", "readTest2"]],
["selector", "testSelector"],
["type", RenderDirectiveMetadata.DIRECTIVE_TYPE],
["exportAs", "aaa"],
["callOnDestroy", true],
["callOnCheck", true],
["callOnInit", true],
["callOnChange", true],
["callOnAllChangesDone", true],
["events", ["onFoo", "onBar"]],
["changeDetection", ChangeDetectionStrategy.CheckOnce.index]
]);
var meta = directiveMetadataFromMap(map);
expect(meta.compileChildren).toEqual(false);
expect(meta.hostProperties)
.toEqual(MapWrapper.createFromPairs([["PKey", "testVal"]]));
expect(meta.hostListeners)
.toEqual(MapWrapper.createFromPairs([["LKey", "testVal"]]));
expect(meta.hostAttributes)
.toEqual(MapWrapper.createFromPairs([["AtKey", "testVal"]]));
expect(meta.id).toEqual("testId");
expect(meta.properties).toEqual(["propKey: propVal"]);
expect(meta.readAttributes).toEqual(["readTest1", "readTest2"]);
expect(meta.selector).toEqual("testSelector");
expect(meta.type).toEqual(RenderDirectiveMetadata.DIRECTIVE_TYPE);
expect(meta.exportAs).toEqual("aaa");
expect(meta.callOnDestroy).toEqual(true);
expect(meta.callOnCheck).toEqual(true);
expect(meta.callOnInit).toEqual(true);
expect(meta.callOnChange).toEqual(true);
expect(meta.callOnAllChangesDone).toEqual(true);
expect(meta.events).toEqual(["onFoo", "onBar"]);
expect(meta.changeDetection).toEqual(ChangeDetectionStrategy.CheckOnce);
});
});
}

View File

@ -2,7 +2,8 @@ library angular2.test.transform.directive_metadata_extractor.all_tests;
import 'dart:async';
import 'package:angular2/src/core/render/api.dart';
import 'package:angular2/src/core/render/dom/convert.dart';
import 'package:angular2/src/core/change_detection/change_detection.dart';
import 'package:angular2/src/transform/common/convert.dart';
import 'package:angular2/src/transform/common/directive_metadata_reader.dart';
import 'package:angular2/src/transform/common/logging.dart';
import 'package:angular2/src/transform/common/ng_deps.dart';
@ -122,7 +123,7 @@ void allTests() {
it('should parse changeDetection.', () async {
var metadata = await readMetadata('directive_metadata_extractor/'
'directive_metadata_files/changeDetection.ng_deps.dart');
expect(metadata.changeDetection).toEqual('CHECK_ONCE');
expect(metadata.changeDetection).toEqual(ChangeDetectionStrategy.CheckOnce);
});
it('should fail when a class is annotated with multiple Directives.',

View File

@ -2,7 +2,7 @@ library examples.hello_world.index_common_dart.ng_deps.dart;
import 'hello.dart';
import 'package:angular2/angular2.dart'
show Component, Directive, View, NgElement, LifecycleEvent;
show Component, Directive, View, NgElement, LifecycleEvent, ChangeDetectionStrategy;
var _visited = false;
void initReflector(reflector) {
@ -12,7 +12,7 @@ void initReflector(reflector) {
..registerType(
HelloCmp,
new ReflectionInfo(
const [const Component(changeDetection: 'CHECK_ONCE')],
const [const Component(changeDetection: ChangeDetectionStrategy.CheckOnce)],
const [const []],
() => new HelloCmp()));
}