refactor(dart/transform): Generate `inputs` setters in `TemplateCompiler` step
Move generation of setters for `inputs` from `BindGenerator` into `TemplateCompiler`.
This commit is contained in:
parent
c94f239536
commit
fcc6f2c561
|
@ -8,8 +8,6 @@ import 'package:angular2/src/transform/common/ng_deps.dart';
|
||||||
import 'package:angular2/src/transform/common/property_utils.dart' as prop;
|
import 'package:angular2/src/transform/common/property_utils.dart' as prop;
|
||||||
import 'package:barback/barback.dart';
|
import 'package:barback/barback.dart';
|
||||||
|
|
||||||
import 'visitor.dart';
|
|
||||||
|
|
||||||
class _ExtractQueryFieldsFromAnnotation extends Object
|
class _ExtractQueryFieldsFromAnnotation extends Object
|
||||||
with RecursiveAstVisitor<Object> {
|
with RecursiveAstVisitor<Object> {
|
||||||
final ConstantEvaluator _evaluator = new ConstantEvaluator();
|
final ConstantEvaluator _evaluator = new ConstantEvaluator();
|
||||||
|
@ -73,7 +71,7 @@ Future<String> createNgSettersAndGetters(
|
||||||
NgDeps ngDeps = await NgDeps.parse(reader, entryPoint);
|
NgDeps ngDeps = await NgDeps.parse(reader, entryPoint);
|
||||||
|
|
||||||
String code = ngDeps.code;
|
String code = ngDeps.code;
|
||||||
var setters = _generateSetters(_createInputPropertiesMap(ngDeps));
|
var setters = [];
|
||||||
|
|
||||||
ngDeps.registeredTypes.forEach((t) {
|
ngDeps.registeredTypes.forEach((t) {
|
||||||
final fromAnnotation = new _ExtractQueryFieldsFromAnnotation();
|
final fromAnnotation = new _ExtractQueryFieldsFromAnnotation();
|
||||||
|
@ -116,32 +114,3 @@ List<String> _generateSetters(Map<String, String> bindMap) {
|
||||||
});
|
});
|
||||||
return setters;
|
return setters;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Collapses all `inputs` in {@link ngDeps} into a map where the keys are
|
|
||||||
/// the bind inputs and the values are either the one and only type
|
|
||||||
/// binding to that property or the empty string.
|
|
||||||
Map<String, String> _createInputPropertiesMap(NgDeps ngDeps) {
|
|
||||||
var visitor = new ExtractNamedExpressionVisitor('inputs');
|
|
||||||
var bindMap = {};
|
|
||||||
ngDeps.registeredTypes.forEach((RegisteredType t) {
|
|
||||||
visitor.bindConfig.clear();
|
|
||||||
t.annotations.accept(visitor);
|
|
||||||
visitor.bindConfig.forEach((String config) {
|
|
||||||
// See comments for `Directive` in annotations_impl/annotations.ts for
|
|
||||||
// details on how `inputs` is specified.
|
|
||||||
var prop;
|
|
||||||
var idx = config.indexOf(':');
|
|
||||||
if (idx > 0) {
|
|
||||||
prop = config.substring(0, idx).trim();
|
|
||||||
} else {
|
|
||||||
prop = config;
|
|
||||||
}
|
|
||||||
if (bindMap.containsKey(prop)) {
|
|
||||||
bindMap[prop] = '';
|
|
||||||
} else {
|
|
||||||
bindMap[prop] = '${t.typeName}';
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
return bindMap;
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,30 +0,0 @@
|
||||||
library angular2.transform.bind_generator.visitor;
|
|
||||||
|
|
||||||
import 'package:analyzer/analyzer.dart';
|
|
||||||
import 'package:angular2/src/transform/common/logging.dart';
|
|
||||||
|
|
||||||
/// Visitor responsible for crawling the "annotations" value in a
|
|
||||||
/// `registerType` call and pulling out the properties of any "bind"
|
|
||||||
/// values found.
|
|
||||||
class ExtractNamedExpressionVisitor extends Object
|
|
||||||
with RecursiveAstVisitor<Object> {
|
|
||||||
final ConstantEvaluator _evaluator = new ConstantEvaluator();
|
|
||||||
final List<String> bindConfig = [];
|
|
||||||
final String nameToExtract;
|
|
||||||
|
|
||||||
ExtractNamedExpressionVisitor(this.nameToExtract);
|
|
||||||
|
|
||||||
@override
|
|
||||||
Object visitNamedExpression(NamedExpression node) {
|
|
||||||
if ('${node.name.label}' == nameToExtract) {
|
|
||||||
var evaluated = node.expression.accept(_evaluator);
|
|
||||||
if (evaluated is List) {
|
|
||||||
bindConfig.addAll(evaluated);
|
|
||||||
} else {
|
|
||||||
logger.error('`$nameToExtract` currently only supports List values');
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return super.visitNamedExpression(node);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -15,8 +15,15 @@ class Processor implements CodegenModel {
|
||||||
final Set<ReflectiveAccessor> methodNames = new Set<ReflectiveAccessor>();
|
final Set<ReflectiveAccessor> methodNames = new Set<ReflectiveAccessor>();
|
||||||
|
|
||||||
void process(CompileDirectiveMetadata meta) {
|
void process(CompileDirectiveMetadata meta) {
|
||||||
meta.outputs.keys.forEach((eventName) {
|
if (meta.outputs != null) {
|
||||||
getterNames.add(new ReflectiveAccessor(eventName));
|
meta.outputs.keys.forEach((eventName) {
|
||||||
});
|
getterNames.add(new ReflectiveAccessor(eventName));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (meta.inputs != null) {
|
||||||
|
meta.inputs.keys.forEach((inputName) {
|
||||||
|
setterNames.add(new ReflectiveAccessor(inputName));
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,28 +14,6 @@ main() => allTests();
|
||||||
void allTests() {
|
void allTests() {
|
||||||
var reader = new TestAssetReader();
|
var reader = new TestAssetReader();
|
||||||
|
|
||||||
it('should generate a setter for an `inputs` property in an annotation.',
|
|
||||||
() async {
|
|
||||||
var inputPath = 'basic_bind_files/bar.ng_deps.dart';
|
|
||||||
var expected = _readFile('basic_bind_files/expected/bar.ng_deps.dart');
|
|
||||||
|
|
||||||
var output = formatter
|
|
||||||
.format(await createNgSettersAndGetters(reader, _assetId(inputPath)));
|
|
||||||
expect(output).toEqual(expected);
|
|
||||||
});
|
|
||||||
|
|
||||||
it(
|
|
||||||
'should generate a single setter when multiple annotations bind to the '
|
|
||||||
'same `inputs` property.', () async {
|
|
||||||
var inputPath = 'duplicate_bind_name_files/soup.ng_deps.dart';
|
|
||||||
var expected =
|
|
||||||
_readFile('duplicate_bind_name_files/expected/soup.ng_deps.dart');
|
|
||||||
|
|
||||||
var output = formatter
|
|
||||||
.format(await createNgSettersAndGetters(reader, _assetId(inputPath)));
|
|
||||||
expect(output).toEqual(expected);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should generate setters for queries defined in the class annotation.',
|
it('should generate setters for queries defined in the class annotation.',
|
||||||
() async {
|
() async {
|
||||||
var inputPath = 'queries_class_annotation_files/bar.ng_deps.dart';
|
var inputPath = 'queries_class_annotation_files/bar.ng_deps.dart';
|
||||||
|
|
|
@ -159,7 +159,7 @@ void noChangeDetectorTests() {
|
||||||
_formatThenExpectEquals(output, expected);
|
_formatThenExpectEquals(output, expected);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should generate getters for Component#events.', () async {
|
it('should generate getters for Component#outputs.', () async {
|
||||||
var inputPath = 'template_compiler/event_files/hello.ng_deps.dart';
|
var inputPath = 'template_compiler/event_files/hello.ng_deps.dart';
|
||||||
var expected =
|
var expected =
|
||||||
readFile('template_compiler/event_files/expected/hello.ng_deps.dart');
|
readFile('template_compiler/event_files/expected/hello.ng_deps.dart');
|
||||||
|
@ -169,7 +169,7 @@ void noChangeDetectorTests() {
|
||||||
_formatThenExpectEquals(output, expected);
|
_formatThenExpectEquals(output, expected);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should generate getters for Directive#events.', () async {
|
it('should generate getters for Directive#outputs.', () async {
|
||||||
var inputPath =
|
var inputPath =
|
||||||
'template_compiler/directive_event_files/hello.ng_deps.dart';
|
'template_compiler/directive_event_files/hello.ng_deps.dart';
|
||||||
var expected = readFile(
|
var expected = readFile(
|
||||||
|
@ -180,6 +180,39 @@ void noChangeDetectorTests() {
|
||||||
_formatThenExpectEquals(output, expected);
|
_formatThenExpectEquals(output, expected);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should generate setters for Component#inputs.', () async {
|
||||||
|
var inputPath = 'template_compiler/component_inputs_files/bar.ng_deps.dart';
|
||||||
|
var expected = readFile(
|
||||||
|
'template_compiler/component_inputs_files/expected/bar.ng_deps.dart');
|
||||||
|
var output = await process(new AssetId('a', inputPath));
|
||||||
|
_formatThenExpectEquals(output, expected);
|
||||||
|
output = await process(new AssetId('a', inputPath));
|
||||||
|
_formatThenExpectEquals(output, expected);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should generate setters for Directive#inputs.', () async {
|
||||||
|
var inputPath = 'template_compiler/directive_inputs_files/bar.ng_deps.dart';
|
||||||
|
var expected = readFile(
|
||||||
|
'template_compiler/directive_inputs_files/expected/bar.ng_deps.dart');
|
||||||
|
var output = await process(new AssetId('a', inputPath));
|
||||||
|
_formatThenExpectEquals(output, expected);
|
||||||
|
output = await process(new AssetId('a', inputPath));
|
||||||
|
_formatThenExpectEquals(output, expected);
|
||||||
|
});
|
||||||
|
|
||||||
|
it(
|
||||||
|
'should generate a single setter for two `Directive`s '
|
||||||
|
'with the same inputs.', () async {
|
||||||
|
var inputPath =
|
||||||
|
'template_compiler/duplicate_input_name_files/soup.ng_deps.dart';
|
||||||
|
var expected = readFile(
|
||||||
|
'template_compiler/duplicate_input_name_files/expected/soup.ng_deps.dart');
|
||||||
|
var output = await process(new AssetId('a', inputPath));
|
||||||
|
_formatThenExpectEquals(output, expected);
|
||||||
|
output = await process(new AssetId('a', inputPath));
|
||||||
|
_formatThenExpectEquals(output, expected);
|
||||||
|
});
|
||||||
|
|
||||||
// TODO(kegluenq): Before committing, should this test be removed or just
|
// TODO(kegluenq): Before committing, should this test be removed or just
|
||||||
// modified to check something different, maybe the created template code?
|
// modified to check something different, maybe the created template code?
|
||||||
xit('should generate all expected getters, setters, & methods.', () async {
|
xit('should generate all expected getters, setters, & methods.', () async {
|
||||||
|
|
|
@ -0,0 +1,18 @@
|
||||||
|
library bar.ng_deps.dart;
|
||||||
|
|
||||||
|
import 'bar.dart';
|
||||||
|
import 'package:angular2/src/core/metadata.dart';
|
||||||
|
|
||||||
|
var _visited = false;
|
||||||
|
void initReflector(reflector) {
|
||||||
|
if (_visited) return;
|
||||||
|
_visited = true;
|
||||||
|
reflector
|
||||||
|
..registerType(
|
||||||
|
ToolTip,
|
||||||
|
new ReflectionInfo(const [
|
||||||
|
const Component(
|
||||||
|
selector: '[tool-tip]', inputs: const ['text: tool-tip']),
|
||||||
|
const View(template: '<div>Tooltip</div>')
|
||||||
|
], const [], () => new ToolTip()));
|
||||||
|
}
|
|
@ -0,0 +1,32 @@
|
||||||
|
{
|
||||||
|
"ToolTip":
|
||||||
|
{
|
||||||
|
"kind": "type",
|
||||||
|
"value": {
|
||||||
|
"isComponent": true,
|
||||||
|
"dynamicLoadable": true,
|
||||||
|
"selector":"[tool-tip]",
|
||||||
|
"exportAs": null,
|
||||||
|
"type": {
|
||||||
|
"id": 1,
|
||||||
|
"name": "ToolTip",
|
||||||
|
"moduleUrl": "asset:template_compiler/lib/basic_inputs_files/bar.dart"
|
||||||
|
},
|
||||||
|
"changeDetection": 5,
|
||||||
|
"inputs": {"text": "tool-tip"},
|
||||||
|
"outputs": {},
|
||||||
|
"hostListeners": {},
|
||||||
|
"hostProperties": {},
|
||||||
|
"hostAttributes": {},
|
||||||
|
"lifecycleHooks": [],
|
||||||
|
"template": {
|
||||||
|
"encapsulation": 0,
|
||||||
|
"template": "<div>Tooltip</div>",
|
||||||
|
"templateUrl": null,
|
||||||
|
"styles": null,
|
||||||
|
"styleUrls": null,
|
||||||
|
"ngContentSelectors": null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,22 @@
|
||||||
|
library bar.ng_deps.dart;
|
||||||
|
|
||||||
|
import 'bar.template.dart' as _templates;
|
||||||
|
|
||||||
|
import 'bar.dart';
|
||||||
|
import 'package:angular2/src/core/metadata.dart';
|
||||||
|
|
||||||
|
var _visited = false;
|
||||||
|
void initReflector(reflector) {
|
||||||
|
if (_visited) return;
|
||||||
|
_visited = true;
|
||||||
|
reflector
|
||||||
|
..registerType(
|
||||||
|
ToolTip,
|
||||||
|
new ReflectionInfo(const [
|
||||||
|
const Component(
|
||||||
|
selector: '[tool-tip]', inputs: const ['text: tool-tip']),
|
||||||
|
const View(template: '<div>Tooltip</div>'),
|
||||||
|
_templates.HostToolTipTemplate
|
||||||
|
], const [], () => new ToolTip()))
|
||||||
|
..registerSetters({'text': (o, v) => o.text = v});
|
||||||
|
}
|
|
@ -0,0 +1,25 @@
|
||||||
|
{
|
||||||
|
"ToolTip":
|
||||||
|
{
|
||||||
|
"kind": "type",
|
||||||
|
"value": {
|
||||||
|
"isComponent": false,
|
||||||
|
"dynamicLoadable": true,
|
||||||
|
"selector":"[tool-tip]",
|
||||||
|
"exportAs": null,
|
||||||
|
"type": {
|
||||||
|
"id": 1,
|
||||||
|
"name": "ToolTip",
|
||||||
|
"moduleUrl": "asset:template_compiler/lib/basic_inputs_files/bar.dart"
|
||||||
|
},
|
||||||
|
"changeDetection": 5,
|
||||||
|
"inputs": {"text": "tool-tip"},
|
||||||
|
"outputs": {},
|
||||||
|
"hostListeners": {},
|
||||||
|
"hostProperties": {},
|
||||||
|
"hostAttributes": {},
|
||||||
|
"lifecycleHooks": [],
|
||||||
|
"template": null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -9,16 +9,17 @@ void initReflector(reflector) {
|
||||||
_visited = true;
|
_visited = true;
|
||||||
reflector
|
reflector
|
||||||
..registerType(
|
..registerType(
|
||||||
SoupComponent,
|
SoupDirective,
|
||||||
new ReflectionInfo(const [
|
new ReflectionInfo(const [
|
||||||
const Component(
|
const Directive(
|
||||||
componentServices: const [SaladComponent],
|
selector: 'soup',
|
||||||
|
componentServices: const [SaladDirective],
|
||||||
inputs: const ['menu'])
|
inputs: const ['menu'])
|
||||||
], const [], () => new SoupComponent()))
|
], const [], () => new SoupDirective()))
|
||||||
..registerType(
|
..registerType(
|
||||||
SaladComponent,
|
SaladDirective,
|
||||||
new ReflectionInfo(const [
|
new ReflectionInfo(const [
|
||||||
const Component(inputs: const ['menu'])
|
const Directive(selector: 'salad', inputs: const ['menu'])
|
||||||
], const [], () => new SaladComponent()))
|
], const [], () => new SaladDirective()))
|
||||||
..registerSetters({'menu': (o, v) => o.menu = v});
|
..registerSetters({'menu': (o, v) => o.menu = v});
|
||||||
}
|
}
|
|
@ -9,15 +9,16 @@ void initReflector(reflector) {
|
||||||
_visited = true;
|
_visited = true;
|
||||||
reflector
|
reflector
|
||||||
..registerType(
|
..registerType(
|
||||||
SoupComponent,
|
SoupDirective,
|
||||||
new ReflectionInfo(const [
|
new ReflectionInfo(const [
|
||||||
const Component(
|
const Directive(
|
||||||
componentServices: const [SaladComponent],
|
selector: 'soup',
|
||||||
|
componentServices: const [SaladDirective],
|
||||||
inputs: const ['menu'])
|
inputs: const ['menu'])
|
||||||
], const [], () => new SoupComponent()))
|
], const [], () => new SoupDirective()))
|
||||||
..registerType(
|
..registerType(
|
||||||
SaladComponent,
|
SaladDirective,
|
||||||
new ReflectionInfo(const [
|
new ReflectionInfo(const [
|
||||||
const Component(inputs: const ['menu'])
|
const Directive(selector: 'salad', inputs: const ['menu'])
|
||||||
], const [], () => new SaladComponent()));
|
], const [], () => new SaladDirective()));
|
||||||
}
|
}
|
|
@ -0,0 +1,48 @@
|
||||||
|
{
|
||||||
|
"SoupDirective":
|
||||||
|
{
|
||||||
|
"kind": "type",
|
||||||
|
"value": {
|
||||||
|
"isComponent": false,
|
||||||
|
"dynamicLoadable": true,
|
||||||
|
"selector":"soup",
|
||||||
|
"exportAs": null,
|
||||||
|
"type": {
|
||||||
|
"id": 1,
|
||||||
|
"name": "SoupDirective",
|
||||||
|
"moduleUrl": "asset:template_compiler/test/duplicate_input_name_files/soup.dart"
|
||||||
|
},
|
||||||
|
"changeDetection": 5,
|
||||||
|
"inputs": {"menu": "menu"},
|
||||||
|
"outputs": {},
|
||||||
|
"hostListeners": {},
|
||||||
|
"hostProperties": {},
|
||||||
|
"hostAttributes": {},
|
||||||
|
"lifecycleHooks": [],
|
||||||
|
"template": null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"SaladDirective":
|
||||||
|
{
|
||||||
|
"kind": "type",
|
||||||
|
"value": {
|
||||||
|
"isComponent": false,
|
||||||
|
"dynamicLoadable": true,
|
||||||
|
"selector":"salad",
|
||||||
|
"exportAs": null,
|
||||||
|
"type": {
|
||||||
|
"id": 1,
|
||||||
|
"name": "SaladDirective",
|
||||||
|
"moduleUrl": "asset:template_compiler/test/duplicate_input_name_files/soup.dart"
|
||||||
|
},
|
||||||
|
"changeDetection": 5,
|
||||||
|
"inputs": {"menu": "menu"},
|
||||||
|
"outputs": {},
|
||||||
|
"hostListeners": {},
|
||||||
|
"hostProperties": {},
|
||||||
|
"hostAttributes": {},
|
||||||
|
"lifecycleHooks": [],
|
||||||
|
"template": null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue