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:barback/barback.dart';
|
||||
|
||||
import 'visitor.dart';
|
||||
|
||||
class _ExtractQueryFieldsFromAnnotation extends Object
|
||||
with RecursiveAstVisitor<Object> {
|
||||
final ConstantEvaluator _evaluator = new ConstantEvaluator();
|
||||
|
@ -73,7 +71,7 @@ Future<String> createNgSettersAndGetters(
|
|||
NgDeps ngDeps = await NgDeps.parse(reader, entryPoint);
|
||||
|
||||
String code = ngDeps.code;
|
||||
var setters = _generateSetters(_createInputPropertiesMap(ngDeps));
|
||||
var setters = [];
|
||||
|
||||
ngDeps.registeredTypes.forEach((t) {
|
||||
final fromAnnotation = new _ExtractQueryFieldsFromAnnotation();
|
||||
|
@ -116,32 +114,3 @@ List<String> _generateSetters(Map<String, String> bindMap) {
|
|||
});
|
||||
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>();
|
||||
|
||||
void process(CompileDirectiveMetadata meta) {
|
||||
meta.outputs.keys.forEach((eventName) {
|
||||
getterNames.add(new ReflectiveAccessor(eventName));
|
||||
});
|
||||
if (meta.outputs != null) {
|
||||
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() {
|
||||
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.',
|
||||
() async {
|
||||
var inputPath = 'queries_class_annotation_files/bar.ng_deps.dart';
|
||||
|
|
|
@ -159,7 +159,7 @@ void noChangeDetectorTests() {
|
|||
_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 expected =
|
||||
readFile('template_compiler/event_files/expected/hello.ng_deps.dart');
|
||||
|
@ -169,7 +169,7 @@ void noChangeDetectorTests() {
|
|||
_formatThenExpectEquals(output, expected);
|
||||
});
|
||||
|
||||
it('should generate getters for Directive#events.', () async {
|
||||
it('should generate getters for Directive#outputs.', () async {
|
||||
var inputPath =
|
||||
'template_compiler/directive_event_files/hello.ng_deps.dart';
|
||||
var expected = readFile(
|
||||
|
@ -180,6 +180,39 @@ void noChangeDetectorTests() {
|
|||
_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
|
||||
// modified to check something different, maybe the created template code?
|
||||
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;
|
||||
reflector
|
||||
..registerType(
|
||||
SoupComponent,
|
||||
SoupDirective,
|
||||
new ReflectionInfo(const [
|
||||
const Component(
|
||||
componentServices: const [SaladComponent],
|
||||
const Directive(
|
||||
selector: 'soup',
|
||||
componentServices: const [SaladDirective],
|
||||
inputs: const ['menu'])
|
||||
], const [], () => new SoupComponent()))
|
||||
], const [], () => new SoupDirective()))
|
||||
..registerType(
|
||||
SaladComponent,
|
||||
SaladDirective,
|
||||
new ReflectionInfo(const [
|
||||
const Component(inputs: const ['menu'])
|
||||
], const [], () => new SaladComponent()))
|
||||
const Directive(selector: 'salad', inputs: const ['menu'])
|
||||
], const [], () => new SaladDirective()))
|
||||
..registerSetters({'menu': (o, v) => o.menu = v});
|
||||
}
|
|
@ -9,15 +9,16 @@ void initReflector(reflector) {
|
|||
_visited = true;
|
||||
reflector
|
||||
..registerType(
|
||||
SoupComponent,
|
||||
SoupDirective,
|
||||
new ReflectionInfo(const [
|
||||
const Component(
|
||||
componentServices: const [SaladComponent],
|
||||
const Directive(
|
||||
selector: 'soup',
|
||||
componentServices: const [SaladDirective],
|
||||
inputs: const ['menu'])
|
||||
], const [], () => new SoupComponent()))
|
||||
], const [], () => new SoupDirective()))
|
||||
..registerType(
|
||||
SaladComponent,
|
||||
SaladDirective,
|
||||
new ReflectionInfo(const [
|
||||
const Component(inputs: const ['menu'])
|
||||
], const [], () => new SaladComponent()));
|
||||
const Directive(selector: 'salad', inputs: const ['menu'])
|
||||
], 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