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.
This commit is contained in:
@ -4,6 +4,7 @@ import 'dart:async';
|
|||||||
|
|
||||||
import 'package:angular2/src/transform/common/asset_reader.dart';
|
import 'package:angular2/src/transform/common/asset_reader.dart';
|
||||||
import 'package:angular2/src/transform/common/parser.dart';
|
import 'package:angular2/src/transform/common/parser.dart';
|
||||||
|
import 'package:angular2/src/transform/common/property_utils.dart' as prop;
|
||||||
import 'package:barback/barback.dart';
|
import 'package:barback/barback.dart';
|
||||||
|
|
||||||
import 'visitor.dart';
|
import 'visitor.dart';
|
||||||
@ -22,12 +23,20 @@ Future<String> createNgSetters(AssetReader reader, AssetId entryPoint) async {
|
|||||||
'${code.substring(codeInjectIdx)}';
|
'${code.substring(codeInjectIdx)}';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO(kegluneq): De-dupe from template_compiler/generator.dart.
|
||||||
|
|
||||||
/// Consumes the map generated by [_createBindMap] to codegen setters.
|
/// Consumes the map generated by [_createBindMap] to codegen setters.
|
||||||
List<String> _generateSetters(Map<String, String> bindMap) {
|
List<String> _generateSetters(Map<String, String> bindMap) {
|
||||||
var setters = [];
|
var setters = [];
|
||||||
// TODO(kegluneq): Include types for receivers. See #886.
|
// TODO(kegluneq): Include types for receivers. See #886.
|
||||||
bindMap.forEach((prop, type) {
|
bindMap.forEach((setterName, type) {
|
||||||
setters.add(''''$prop': (o, String v) => o.$prop = v''');
|
if (!prop.isValid(setterName)) {
|
||||||
|
// TODO(kegluenq): Eagerly throw here once #1295 is addressed.
|
||||||
|
setters.add(prop.lazyInvalidSetter(setterName));
|
||||||
|
} else {
|
||||||
|
setters.add(''' '${prop.sanitize(setterName)}': '''
|
||||||
|
''' (o, v) => o.$setterName = v ''');
|
||||||
|
}
|
||||||
});
|
});
|
||||||
return setters;
|
return setters;
|
||||||
}
|
}
|
||||||
|
33
modules/angular2/src/transform/common/property_utils.dart
Normal file
33
modules/angular2/src/transform/common/property_utils.dart
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
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);
|
||||||
|
|
||||||
|
/// Prepares [name] to be emitted inside a string.
|
||||||
|
String sanitize(String name) => name.replaceAll('\$', '\\\$');
|
||||||
|
|
||||||
|
/// Get a string usable as a lazy invalid setter, that is, one which will
|
||||||
|
/// `throw` immediately upon use.
|
||||||
|
String lazyInvalidSetter(String setterName) {
|
||||||
|
var sName = sanitize(setterName);
|
||||||
|
return ''' '$sName': (o, v) => '''
|
||||||
|
''' throw 'Invalid setter name "$sName" is a Dart keyword.' ''';
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get a string usable as a lazy invalid getter, that is, one which will
|
||||||
|
/// `throw` immediately upon use.
|
||||||
|
String lazyInvalidGetter(String getterName) {
|
||||||
|
var sName = sanitize(getterName);
|
||||||
|
return ''' '$sName': (o) => '''
|
||||||
|
''' throw 'Invalid getter name "$sName" is a Dart keyword.' ''';
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get a string usable as a lazy invalid method, that is, one which will
|
||||||
|
/// `throw` immediately upon use.
|
||||||
|
String lazyInvalidMethod(String methodName) {
|
||||||
|
var sName = sanitize(methodName);
|
||||||
|
return ''' '$sName': (o, args) => '''
|
||||||
|
''' throw 'Invalid method name "$sName" is a Dart keyword.' ''';
|
||||||
|
}
|
@ -200,6 +200,7 @@ class _Tester {
|
|||||||
return metaName == 'Component' ||
|
return metaName == 'Component' ||
|
||||||
metaName == 'Decorator' ||
|
metaName == 'Decorator' ||
|
||||||
metaName == 'Injectable' ||
|
metaName == 'Injectable' ||
|
||||||
metaName == 'View';
|
metaName == 'View' ||
|
||||||
|
metaName == 'Viewport';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -16,6 +16,7 @@ import 'package:angular2/src/transform/common/asset_reader.dart';
|
|||||||
import 'package:angular2/src/transform/common/logging.dart';
|
import 'package:angular2/src/transform/common/logging.dart';
|
||||||
import 'package:angular2/src/transform/common/names.dart';
|
import 'package:angular2/src/transform/common/names.dart';
|
||||||
import 'package:angular2/src/transform/common/parser.dart';
|
import 'package:angular2/src/transform/common/parser.dart';
|
||||||
|
import 'package:angular2/src/transform/common/property_utils.dart' as prop;
|
||||||
import 'package:barback/barback.dart';
|
import 'package:barback/barback.dart';
|
||||||
import 'package:code_transformers/assets.dart';
|
import 'package:code_transformers/assets.dart';
|
||||||
|
|
||||||
@ -63,21 +64,38 @@ Future<String> processTemplates(AssetReader reader, AssetId entryPoint) async {
|
|||||||
|
|
||||||
Iterable<String> _generateGetters(String typeName, List<String> getterNames) {
|
Iterable<String> _generateGetters(String typeName, List<String> getterNames) {
|
||||||
// TODO(kegluneq): Include `typeName` where possible.
|
// TODO(kegluneq): Include `typeName` where possible.
|
||||||
return getterNames.map((prop) => '''
|
return getterNames.map((getterName) {
|
||||||
'$prop': (o) => o.$prop
|
if (!prop.isValid(getterName)) {
|
||||||
''');
|
// TODO(kegluenq): Eagerly throw here once #1295 is addressed.
|
||||||
|
return prop.lazyInvalidGetter(getterName);
|
||||||
|
} else {
|
||||||
|
return ''' '${prop.sanitize(getterName)}': (o) => o.$getterName''';
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
Iterable<String> _generateSetters(String typeName, List<String> setterName) {
|
Iterable<String> _generateSetters(String typeName, List<String> setterName) {
|
||||||
return setterName.map((prop) => '''
|
return setterName.map((setterName) {
|
||||||
'$prop': (o, v) => o.$prop = v
|
if (!prop.isValid(setterName)) {
|
||||||
''');
|
// TODO(kegluenq): Eagerly throw here once #1295 is addressed.
|
||||||
|
return prop.lazyInvalidSetter(setterName);
|
||||||
|
} else {
|
||||||
|
return ''' '${prop.sanitize(setterName)}': '''
|
||||||
|
''' (o, v) => o.$setterName = v ''';
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
Iterable<String> _generateMethods(String typeName, List<String> methodNames) {
|
Iterable<String> _generateMethods(String typeName, List<String> methodNames) {
|
||||||
return methodNames.map((methodName) => '''
|
return methodNames.map((methodName) {
|
||||||
'$methodName': (o, List args) => Function.apply(o.$methodName, args)
|
if (!prop.isValid(methodName)) {
|
||||||
''');
|
// TODO(kegluenq): Eagerly throw here once #1295 is addressed.
|
||||||
|
return prop.lazyInvalidMethod(methodName);
|
||||||
|
} else {
|
||||||
|
return ''' '${prop.sanitize(methodName)}': '''
|
||||||
|
'(o, List args) => Function.apply(o.$methodName, args) ';
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Extracts `template` and `url` values from `View` annotations, reads
|
/// Extracts `template` and `url` values from `View` annotations, reads
|
||||||
|
@ -16,5 +16,5 @@ void initReflector(reflector) {
|
|||||||
selector: '[tool-tip]', properties: const {'text': 'tool-tip'})
|
selector: '[tool-tip]', properties: const {'text': 'tool-tip'})
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
..registerSetters({'text': (o, String v) => o.text = v});
|
..registerSetters({'text': (o, v) => o.text = v});
|
||||||
}
|
}
|
||||||
|
@ -22,5 +22,5 @@ void initReflector(reflector) {
|
|||||||
'parameters': const [],
|
'parameters': const [],
|
||||||
'annotations': const [const Component(properties: const {'menu': 'menu'})]
|
'annotations': const [const Component(properties: const {'menu': 'menu'})]
|
||||||
})
|
})
|
||||||
..registerSetters({'menu': (o, String v) => o.menu = v});
|
..registerSetters({'menu': (o, v) => o.menu = v});
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user