Skip to content
This repository has been archived by the owner on Dec 14, 2017. It is now read-only.

Commit

Permalink
fix conversion of API names to Dart identifiers
Browse files Browse the repository at this point in the history
  • Loading branch information
yjbanov committed Aug 22, 2014
1 parent 3eaea4d commit d947a00
Show file tree
Hide file tree
Showing 4 changed files with 108 additions and 45 deletions.
84 changes: 51 additions & 33 deletions lib/generator/emitter.dart
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,7 @@ class Emitter {

List<DartClass> processRoot(Api api, String resourcePrefix, String dispatchPrefix) {
// Create the resource mixin class.
var resourceMixin = new DartClass('${toProperIdentifier(api.name)}ResourcesMixin');
var resourceMixin = new DartClass('${_makeClassName(api.name)}ResourcesMixin');
if (api.description != null) {
resourceMixin.comments.addAll(splitStringAcrossLines(api.description));
}
Expand All @@ -180,10 +180,9 @@ class Emitter {
var getterTemplate = _template('lazy_resource_getter');
api.resources.forEach((name, resource) {
// Backing field.
var resName = toProperIdentifier(resource.name);
var lcResName = toProperIdentifier(resource.name, firstLetter: false);
var lcResName = _makePropertyName(resource.name);
var fieldName = '_$lcResName';
var type = new DartType('${resName}Resource',
var type = new DartType('${_makeClassName(resource.name)}Resource',
resourcePrefix, const []);
var field = new DartSimpleField(fieldName, type);
resourceMixin.fields.add(field);
Expand All @@ -200,8 +199,8 @@ class Emitter {
}
final marshallerType = new DartType('Marshaller', dispatchPrefix, const []);
var mixinType = new DartType.from(resourceMixin);
var txClassName = toProperIdentifier('${api.name}Transaction');
var root = new DartClass(toProperIdentifier(api.name), baseClass: baseType)
var txClassName = _makeClassName('${api.name}Transaction');
var root = new DartClass(_makeClassName(api.name), baseClass: baseType)
..mixins.add(mixinType)
..fields.add(new DartSimpleField('marshaller', marshallerType, isFinal: true))
..fields.add(new DartSimpleField('requestHandler', streamyImport('RequestHandler'), isFinal: true))
Expand Down Expand Up @@ -272,8 +271,7 @@ class Emitter {

DartClass processResource(Resource resource, String requestPrefix,
String objectPrefix) {
var name = toProperIdentifier(resource.name);
var clazz = new DartClass('${toProperIdentifier(resource.name)}Resource');
var clazz = new DartClass('${_makeClassName(resource.name)}Resource');
var requestMethodTemplate = _template('request_method');

// Set up a _root field for the implementation RequestHandler, and a
Expand Down Expand Up @@ -315,10 +313,10 @@ class Emitter {
}

var requestType = new DartType(
'${toProperIdentifier(resource.name)}${toProperIdentifier(method.name)}Request',
'${_makeClassName(resource.name)}${_makeClassName(method.name)}Request',
requestPrefix, const []);

var m = new DartMethod(toProperIdentifier(method.name, firstLetter: false), requestType,
var m = new DartMethod(_makeMethodName(method.name), requestType,
new DartTemplateBody(requestMethodTemplate, {
'requestType': requestType,
'parameters': pnames
Expand All @@ -344,15 +342,17 @@ class Emitter {
.expand((resource) => resource
.methods
.values
.map((method) => processRequest(api, toProperIdentifier(resource.name), method, objectPrefix, dispatchPrefix))
.map((method) => processRequest(api, _makeClassName(resource.name),
method, objectPrefix, dispatchPrefix))
)
.toList(growable: false);

DartClass processRequest(Api api, String resourceName, Method method, String objectPrefix, String dispatchPrefix) {

DartClass processRequest(Api api, String resourceClassName, Method method,
String objectPrefix, String dispatchPrefix) {
var paramGetter = _template('request_param_getter');
var paramSetter = _template('request_param_setter');
var methodName = toProperIdentifier(method.name);
var clazz = new DartClass('$resourceName${methodName}Request',
var methodName = _makeClassName(method.name);
var clazz = new DartClass('$resourceClassName${methodName}Request',
baseClass: streamyImport('HttpRequest'));

// Determine payload type.
Expand Down Expand Up @@ -395,10 +395,10 @@ class Emitter {
method.parameters.forEach((name, param) {
var type = toDartType(param.typeRef, objectPrefix);
clazz.fields.add(
new DartComplexField(toProperIdentifier(name, firstLetter: false), type,
new DartComplexField(_makePropertyName(name), type,
new DartTemplateBody(paramGetter, {'name': name}),
new DartTemplateBody(paramSetter, {'name': name})));
clazz.methods.add(new DartMethod(toProperIdentifier('remove_$name', firstLetter: false), type,
clazz.methods.add(new DartMethod(_makeRemoverName(name), type,
new DartTemplateBody(_template('request_remove'), {'name': name})));
});

Expand Down Expand Up @@ -470,15 +470,15 @@ class Emitter {
if (responseType != null && api.httpConfig != null) {
clazz.methods.add(new DartMethod('unmarshalResponse', responseType,
new DartTemplateBody(_template('request_unmarshal_response'), {
'name': toProperIdentifier(method.responseType.schemaClass)
'name': _makeClassName((method.responseType as SchemaTypeRef).schemaClass)
}))
..parameters.add(new DartParameter('data', new DartType('Map', null, const []))));
}

if (method.payloadType != null) {
clazz.methods.add(new DartMethod('marshalPayload', new DartType('Map'),
new DartTemplateBody(_template('request_marshal_payload'), {
'name': toProperIdentifier(method.payloadType.schemaClass)
'name': _makeClassName((method.payloadType as SchemaTypeRef).schemaClass)
})));
}
}
Expand Down Expand Up @@ -546,7 +546,7 @@ class Emitter {

SchemaDefinition processSchema(Schema schema) {
var base = new DartType(config.baseClass, BASE_PREFIX, const []);
var clazz = new DartClass(toProperIdentifier(schema.name), baseClass: base);
var clazz = new DartClass(_makeClassName(schema.name), baseClass: base);
clazz.mixins.addAll(schema.mixins.map((mixin) => toDartType(mixin, '')));

var globalFnDef = null;
Expand Down Expand Up @@ -593,15 +593,15 @@ class Emitter {

schema.properties.forEach((_, field) {
// Add getter and setter, delegating to map access.
var name = toProperIdentifier(field.name, firstLetter: false);
var name = _makePropertyName(field.name);
var type = toDartType(field.typeRef, null);
if (config.mapBackedFields) {
var f = new DartComplexField(name, type,
new DartTemplateBody(getter, {'name': field.name}),
new DartTemplateBody(setter, {'name': field.name}));
clazz.fields.add(f);
if (config.removers) {
var r = new DartMethod('remove${toProperIdentifier(field.name)}', type,
var r = new DartMethod(_makeRemoverName(field.name), type,
new DartTemplateBody(remove, {'name': field.name}));
clazz.methods.add(r);
}
Expand Down Expand Up @@ -639,16 +639,17 @@ class Emitter {
doubleFields.add(name);
break;
case 'schema':
entityFields[name] = typeRef.schemaClass;
entityFields[name] = (typeRef as SchemaTypeRef).schemaClass;
break;
case 'list':
_accumulateMarshallingTypes(name, typeRef.subType, int64Fields, doubleFields, entityFields);
_accumulateMarshallingTypes(name, (typeRef as ListTypeRef).subType,
int64Fields, doubleFields, entityFields);
break;
}
}

void processSchemaForMarshaller(DartClass clazz, Schema schema, String objectPrefix) {
var name = toProperIdentifier(schema.name);
var name = _makeClassName(schema.name);
var type = new DartType(name, objectPrefix, const []);
var rt = new DartType.map(const DartType.string(), const DartType.dynamic());
var data = {
Expand All @@ -665,17 +666,25 @@ class Emitter {
schema
.properties
.forEach((_, field) {
_accumulateMarshallingTypes(field.name, field.typeRef, int64Fields, doubleFields, entityFields);
allFields.add({'key': field.name, 'identifier': toProperIdentifier(field.name, firstLetter: false)});
_accumulateMarshallingTypes(field.name, field.typeRef, int64Fields,
doubleFields, entityFields);
allFields.add({
'key': field.name,
'identifier': _makePropertyName(field.name),
});
});

var stringList = new DartType.list(const DartType.string());
var serialMap = new DartType('Map');
if (int64Fields.isNotEmpty) {
clazz.fields.add(new DartSimpleField('_int64s$name', stringList, isStatic: true, isFinal: true, initializer: stringListBody(int64Fields)));
clazz.fields.add(new DartSimpleField('_int64s$name', stringList,
isStatic: true, isFinal: true,
initializer: stringListBody(int64Fields)));
}
if (doubleFields.isNotEmpty) {
clazz.fields.add(new DartSimpleField('_doubles$name', stringList, isStatic: true, isFinal: true, initializer: stringListBody(doubleFields)));
clazz.fields.add(new DartSimpleField('_doubles$name', stringList,
isStatic: true, isFinal: true,
initializer: stringListBody(doubleFields)));
}

var fieldMapping = {};
Expand All @@ -695,10 +704,17 @@ class Emitter {
if (entityFields.isNotEmpty) {
var data = [];
entityFields.forEach((name, schema) {
data.add({'key': name, 'value': '_handle${toProperIdentifier(schema)}'});
data.add({
'key': name,
'value': _makeHandlerName(schema),
});
});
clazz.fields.add(new DartComplexField.getterOnly('_entities$name', rt,
new DartTemplateBody(_template('map'), {'pairs': data, 'getter': true, 'const': false})));
new DartTemplateBody(_template('map'), {
'pairs': data,
'getter': true,
'const': false,
})));
}
var serializerConfig = {
'entity': type,
Expand Down Expand Up @@ -764,7 +780,7 @@ class Emitter {
if (ref is ListTypeRef) {
return new DartType.list(toDartType(ref.subType, objectPrefix));
} else if (ref is SchemaTypeRef) {
return new DartType(toProperIdentifier(ref.schemaClass), objectPrefix, const []);
return new DartType(_makeClassName(ref.schemaClass), objectPrefix, const []);
} else {
switch (ref.base) {
case 'int64':
Expand All @@ -782,7 +798,9 @@ class Emitter {
case 'number':
return const DartType.double();
case 'external':
return new DartType(ref.type, ref.importedFrom, const []);
ExternalTypeRef externalTypeRef = ref;
return new DartType(externalTypeRef.type,
externalTypeRef.importedFrom, const []);
default:
throw new Exception('Unhandled API type: $ref');
}
Expand Down
2 changes: 1 addition & 1 deletion lib/generator/service.dart
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ void _parseService(Api api, String importPath, analyzer.ClassDeclaration clazz)
var method = new Method(m.name.name, new Path('/'), '', null, ref);
res.methods[method.name] = method;
// Need a request class for the method.
var name = '${res.name}${toProperIdentifier(m.name.name)}Request';
var name = '${res.name}${_makeClassName(m.name.name)}Request';
m
.parameters
.parameters
Expand Down
63 changes: 55 additions & 8 deletions lib/generator/util.dart
Original file line number Diff line number Diff line change
@@ -1,8 +1,47 @@
part of streamy.generator;

String toProperIdentifier(String identifier, {firstLetter: true}) {
var first = !firstLetter;
var name = identifier
String _makePropertyName(String name) {
name = _fixIllegalChars(name);
if (_ILLEGAL_PROPERTY_NAMES.contains(name)) {
name = '\$${name}';
}
return name;
}

String _makeMethodName(String name) {
name = _fixIllegalChars(name);
if (_ILLEGAL_METHOD_NAMES.contains(name)) {
name = '\$${name}';
}
return name;
}

String _makeRemoverName(String name) {
name = _capitalize(_fixIllegalChars(name));
return 'remove${name}';
}

String _makeHandlerName(String name) {
name = _capitalize(_fixIllegalChars(name));
return '_handle${name}';
}

String _makeClassName(String name) {
name = _capitalize(_fixIllegalChars(name));
if (_ILLEGAL_CLASS_NAMES.contains(name)) {
name = '\$${name}';
}
return name;
}

String _fixIllegalChars(String name) {
if (name.length == 0) {
throw new StateError('Empty property, schema, resource or method name');
}

// Make names like foo_bar_baz look like fooBarBaz
var first = true;
name = name
.split('_')
.map((piece) {
if (first) {
Expand All @@ -16,22 +55,30 @@ String toProperIdentifier(String identifier, {firstLetter: true}) {
}
})
.join();
if (name.length == 0) {
throw new StateError('Empty property, schema, resource or method name');
}


// Replace bad starting character with dollar sign (it has to be public)
if (!name.startsWith(IDENTIFIER_START)) {
if(!name.startsWith(IDENTIFIER_START)) {
name = '\$${name.substring(1)}';
}

// Replace bad characters in the middle with underscore
name = name.replaceAll(NON_IDENTIFIER_CHAR_MATCHER, '_');
if (name.startsWith('_')) {
name = 'clean${name}';
}

return name;
}


/// Turns the first letter in a string to a capital letter.
String _capitalize(String str) {
if (str == null || str.length == 0) {
return str;
}
return str[0].toUpperCase() + str.substring(1);
}

List<String> splitStringAcrossLines(String src, [int maxLen = 80]) {
var lines = [];
var words = src.split(' ');
Expand Down
4 changes: 1 addition & 3 deletions test/generated/method_get_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -42,13 +42,11 @@ main() {
expect(MethodGetTest.API_TYPE, 'MethodGetTest');
expect(new MethodGetTest(null).apiType, 'MethodGetTest');
});
/* TODO: fix test
test('of MethodGetTestTransaction', () {
expect(MethodGetTestTransaction.API_TYPE, 'MethodGetTestTransaction');
expect(new MethodGetTestTransaction(null, null).apiType,
expect(new MethodGetTestTransaction(null, null, null).apiType,
'MethodGetTestTransaction');
});
*/
test('of Foo', () {
expect(Foo.API_TYPE, 'Foo');
expect(new Foo().apiType, 'Foo');
Expand Down

0 comments on commit d947a00

Please sign in to comment.