128 lines
3.2 KiB
Python
128 lines
3.2 KiB
Python
|
from __future__ import absolute_import, division, print_function, unicode_literals
|
||
|
|
||
|
import json
|
||
|
import six
|
||
|
|
||
|
from stone.ir import (
|
||
|
Boolean,
|
||
|
Bytes,
|
||
|
Float32,
|
||
|
Float64,
|
||
|
Int32,
|
||
|
Int64,
|
||
|
List,
|
||
|
String,
|
||
|
Timestamp,
|
||
|
UInt32,
|
||
|
UInt64,
|
||
|
Void,
|
||
|
is_list_type,
|
||
|
is_struct_type,
|
||
|
is_user_defined_type,
|
||
|
)
|
||
|
from stone.backends.helpers import (
|
||
|
fmt_camel,
|
||
|
fmt_pascal,
|
||
|
)
|
||
|
|
||
|
_base_type_table = {
|
||
|
Boolean: 'boolean',
|
||
|
Bytes: 'string',
|
||
|
Float32: 'number',
|
||
|
Float64: 'number',
|
||
|
Int32: 'number',
|
||
|
Int64: 'number',
|
||
|
List: 'Array',
|
||
|
String: 'string',
|
||
|
UInt32: 'number',
|
||
|
UInt64: 'number',
|
||
|
Timestamp: 'Timestamp',
|
||
|
Void: 'void',
|
||
|
}
|
||
|
|
||
|
|
||
|
def fmt_obj(o):
|
||
|
if isinstance(o, six.text_type):
|
||
|
# Prioritize single-quoted strings per JS style guides.
|
||
|
return repr(o).lstrip('u')
|
||
|
else:
|
||
|
return json.dumps(o, indent=2)
|
||
|
|
||
|
|
||
|
def fmt_error_type(data_type):
|
||
|
"""
|
||
|
Converts the error type into a JSDoc type.
|
||
|
"""
|
||
|
return 'Error.<%s>' % fmt_type(data_type)
|
||
|
|
||
|
|
||
|
def fmt_type_name(data_type):
|
||
|
"""
|
||
|
Returns the JSDoc name for the given data type.
|
||
|
(Does not attempt to enumerate subtypes.)
|
||
|
"""
|
||
|
if is_user_defined_type(data_type):
|
||
|
return fmt_pascal('%s%s' % (data_type.namespace.name, data_type.name))
|
||
|
else:
|
||
|
fmted_type = _base_type_table.get(data_type.__class__, 'Object')
|
||
|
if is_list_type(data_type):
|
||
|
fmted_type += '.<' + fmt_type(data_type.data_type) + '>'
|
||
|
return fmted_type
|
||
|
|
||
|
|
||
|
def fmt_type(data_type):
|
||
|
"""
|
||
|
Returns a JSDoc annotation for a data type.
|
||
|
May contain a union of enumerated subtypes.
|
||
|
"""
|
||
|
if is_struct_type(data_type) and data_type.has_enumerated_subtypes():
|
||
|
possible_types = []
|
||
|
possible_subtypes = data_type.get_all_subtypes_with_tags()
|
||
|
for _, subtype in possible_subtypes:
|
||
|
possible_types.append(fmt_type_name(subtype))
|
||
|
if data_type.is_catch_all():
|
||
|
possible_types.append(fmt_type_name(data_type))
|
||
|
return fmt_jsdoc_union(possible_types)
|
||
|
else:
|
||
|
return fmt_type_name(data_type)
|
||
|
|
||
|
|
||
|
def fmt_jsdoc_union(type_strings):
|
||
|
"""
|
||
|
Returns a JSDoc union of the given type strings.
|
||
|
"""
|
||
|
return '(' + '|'.join(type_strings) + ')' if len(type_strings) > 1 else type_strings[0]
|
||
|
|
||
|
|
||
|
def fmt_func(name, version):
|
||
|
if version == 1:
|
||
|
return fmt_camel(name)
|
||
|
return fmt_camel(name) + 'V{}'.format(version)
|
||
|
|
||
|
|
||
|
def fmt_url(namespace_name, route_name, route_version):
|
||
|
if route_version != 1:
|
||
|
return '{}/{}_v{}'.format(namespace_name, route_name, route_version)
|
||
|
else:
|
||
|
return '{}/{}'.format(namespace_name, route_name)
|
||
|
|
||
|
|
||
|
def fmt_var(name):
|
||
|
return fmt_camel(name)
|
||
|
|
||
|
|
||
|
def check_route_name_conflict(namespace):
|
||
|
"""
|
||
|
Check name conflicts among generated route definitions. Raise a runtime exception when a
|
||
|
conflict is encountered.
|
||
|
"""
|
||
|
|
||
|
route_by_name = {}
|
||
|
for route in namespace.routes:
|
||
|
route_name = fmt_func(route.name, version=route.version)
|
||
|
if route_name in route_by_name:
|
||
|
other_route = route_by_name[route_name]
|
||
|
raise RuntimeError(
|
||
|
'There is a name conflict between {!r} and {!r}'.format(other_route, route))
|
||
|
route_by_name[route_name] = route
|