Skip to content

Commit f6e9d1f

Browse files
author
Tim Blasi
committed
feat(dart/transform): Fix handling of Dart keywords
Use `package:analyzer`'s list of Dart keywords to ensure we are properly reporting usages of Dart keywords as runtime errors.
1 parent 2cab7c7 commit f6e9d1f

6 files changed

Lines changed: 75 additions & 14 deletions

File tree

modules/angular2/src/transform/bind_generator/generator.dart

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import 'dart:async';
44

55
import 'package:angular2/src/transform/common/asset_reader.dart';
66
import 'package:angular2/src/transform/common/parser.dart';
7+
import 'package:angular2/src/transform/common/property_utils.dart' as prop;
78
import 'package:barback/barback.dart';
89

910
import 'visitor.dart';
@@ -22,12 +23,20 @@ Future<String> createNgSetters(AssetReader reader, AssetId entryPoint) async {
2223
'${code.substring(codeInjectIdx)}';
2324
}
2425

26+
// TODO(kegluneq): De-dupe from template_compiler/generator.dart.
27+
2528
/// Consumes the map generated by [_createBindMap] to codegen setters.
2629
List<String> _generateSetters(Map<String, String> bindMap) {
2730
var setters = [];
2831
// TODO(kegluneq): Include types for receivers. See #886.
29-
bindMap.forEach((prop, type) {
30-
setters.add(''''$prop': (o, String v) => o.$prop = v''');
32+
bindMap.forEach((setterName, type) {
33+
if (!prop.isValid(setterName)) {
34+
// TODO(kegluenq): Eagerly throw here once #1295 is addressed.
35+
setters.add(prop.lazyInvalidSetter(setterName));
36+
} else {
37+
setters.add(''' '${prop.sanitize(setterName)}': '''
38+
''' (o, v) => o.$setterName = v ''');
39+
}
3140
});
3241
return setters;
3342
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
library angular2.transform.common.property_utils;
2+
3+
import 'package:analyzer/src/generated/scanner.dart' show Keyword;
4+
5+
/// Whether `name` is a valid property name.
6+
bool isValid(String name) => !Keyword.keywords.containsKey(name);
7+
8+
/// Prepares [name] to be emitted inside a string.
9+
String sanitize(String name) => name.replaceAll('\$', '\\\$');
10+
11+
/// Get a string usable as a lazy invalid setter, that is, one which will
12+
/// `throw` immediately upon use.
13+
String lazyInvalidSetter(String setterName) {
14+
var sName = sanitize(setterName);
15+
return ''' '$sName': (o, v) => '''
16+
''' throw 'Invalid setter name "$sName" is a Dart keyword.' ''';
17+
}
18+
19+
/// Get a string usable as a lazy invalid getter, that is, one which will
20+
/// `throw` immediately upon use.
21+
String lazyInvalidGetter(String getterName) {
22+
var sName = sanitize(getterName);
23+
return ''' '$sName': (o) => '''
24+
''' throw 'Invalid getter name "$sName" is a Dart keyword.' ''';
25+
}
26+
27+
/// Get a string usable as a lazy invalid method, that is, one which will
28+
/// `throw` immediately upon use.
29+
String lazyInvalidMethod(String methodName) {
30+
var sName = sanitize(methodName);
31+
return ''' '$sName': (o, args) => '''
32+
''' throw 'Invalid method name "$sName" is a Dart keyword.' ''';
33+
}

modules/angular2/src/transform/directive_processor/rewriter.dart

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -200,6 +200,7 @@ class _Tester {
200200
return metaName == 'Component' ||
201201
metaName == 'Decorator' ||
202202
metaName == 'Injectable' ||
203-
metaName == 'View';
203+
metaName == 'View' ||
204+
metaName == 'Viewport';
204205
}
205206
}

modules/angular2/src/transform/template_compiler/generator.dart

Lines changed: 27 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import 'package:angular2/src/transform/common/asset_reader.dart';
1616
import 'package:angular2/src/transform/common/logging.dart';
1717
import 'package:angular2/src/transform/common/names.dart';
1818
import 'package:angular2/src/transform/common/parser.dart';
19+
import 'package:angular2/src/transform/common/property_utils.dart' as prop;
1920
import 'package:barback/barback.dart';
2021
import 'package:code_transformers/assets.dart';
2122

@@ -63,21 +64,38 @@ Future<String> processTemplates(AssetReader reader, AssetId entryPoint) async {
6364

6465
Iterable<String> _generateGetters(String typeName, List<String> getterNames) {
6566
// TODO(kegluneq): Include `typeName` where possible.
66-
return getterNames.map((prop) => '''
67-
'$prop': (o) => o.$prop
68-
''');
67+
return getterNames.map((getterName) {
68+
if (!prop.isValid(getterName)) {
69+
// TODO(kegluenq): Eagerly throw here once #1295 is addressed.
70+
return prop.lazyInvalidGetter(getterName);
71+
} else {
72+
return ''' '${prop.sanitize(getterName)}': (o) => o.$getterName''';
73+
}
74+
});
6975
}
7076

7177
Iterable<String> _generateSetters(String typeName, List<String> setterName) {
72-
return setterName.map((prop) => '''
73-
'$prop': (o, v) => o.$prop = v
74-
''');
78+
return setterName.map((setterName) {
79+
if (!prop.isValid(setterName)) {
80+
// TODO(kegluenq): Eagerly throw here once #1295 is addressed.
81+
return prop.lazyInvalidSetter(setterName);
82+
} else {
83+
return ''' '${prop.sanitize(setterName)}': '''
84+
''' (o, v) => o.$setterName = v ''';
85+
}
86+
});
7587
}
7688

7789
Iterable<String> _generateMethods(String typeName, List<String> methodNames) {
78-
return methodNames.map((methodName) => '''
79-
'$methodName': (o, List args) => Function.apply(o.$methodName, args)
80-
''');
90+
return methodNames.map((methodName) {
91+
if (!prop.isValid(methodName)) {
92+
// TODO(kegluenq): Eagerly throw here once #1295 is addressed.
93+
return prop.lazyInvalidMethod(methodName);
94+
} else {
95+
return ''' '${prop.sanitize(methodName)}': '''
96+
'(o, List args) => Function.apply(o.$methodName, args) ';
97+
}
98+
});
8199
}
82100

83101
/// Extracts `template` and `url` values from `View` annotations, reads

modules/angular2/test/transform/bind_generator/basic_bind_files/expected/bar.ng_deps.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,5 +16,5 @@ void initReflector(reflector) {
1616
selector: '[tool-tip]', properties: const {'text': 'tool-tip'})
1717
]
1818
})
19-
..registerSetters({'text': (o, String v) => o.text = v});
19+
..registerSetters({'text': (o, v) => o.text = v});
2020
}

modules/angular2/test/transform/bind_generator/duplicate_bind_name_files/expected/soup.ng_deps.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,5 +22,5 @@ void initReflector(reflector) {
2222
'parameters': const [],
2323
'annotations': const [const Component(properties: const {'menu': 'menu'})]
2424
})
25-
..registerSetters({'menu': (o, String v) => o.menu = v});
25+
..registerSetters({'menu': (o, v) => o.menu = v});
2626
}

0 commit comments

Comments
 (0)