def _generate_struct_class(self, namespace, data_type): if data_type.doc: doc = self.process_doc(data_type.doc, self._docf) else: doc = 'The {} struct'.format(fmt_class(data_type.name)) self.emit_wrapped_text(doc, prefix='/// ', width=120) protocols = [] if not data_type.parent_type: protocols.append('CustomStringConvertible') with self.class_block(data_type, protocols=protocols): for field in data_type.fields: fdoc = self.process_doc(field.doc, self._docf) if field.doc else undocumented self.emit_wrapped_text(fdoc, prefix='/// ', width=120) self.emit('public let {}: {}'.format( fmt_var(field.name), fmt_type(field.data_type), )) self._generate_struct_init(namespace, data_type) decl = 'public var' if not data_type.parent_type else 'public override var' with self.block('{} description: String'.format(decl)): cls = fmt_class(data_type.name)+'Serializer' self.emit('return "\(SerializeUtil.prepareJSONForSerialization' + '({}().serialize(self)))"'.format(cls)) self._generate_struct_class_serializer(namespace, data_type)
def _generate_union_type(self, namespace, data_type): if data_type.doc: doc = self.process_doc(data_type.doc, self._docf) else: doc = 'The {} union'.format(fmt_class(data_type.name)) self.emit_wrapped_text(doc, prefix='/// ', width=120) class_type = fmt_class(data_type.name) with self.block( 'public enum {}: CustomStringConvertible'.format(class_type)): for field in data_type.all_fields: typ = self._format_tag_type(namespace, field.data_type) fdoc = self.process_doc( field.doc, self._docf) if field.doc else 'An unspecified error.' self.emit_wrapped_text(fdoc, prefix='/// ', width=120) self.emit('case {}{}'.format(fmt_var(field.name), typ)) self.emit() with self.block('public var description: String'): cls = class_type + 'Serializer' self.emit( 'return "\\(SerializeUtil.prepareJSONForSerialization' + '({}().serialize(self)))"'.format(cls)) self._generate_union_serializer(data_type)
def _generate_struct_class(self, namespace, data_type): if data_type.doc: doc = self.process_doc(data_type.doc, self._docf) else: doc = 'The {} struct'.format(fmt_class(data_type.name)) self.emit_wrapped_text(doc, prefix='/// ', width=120) protocols = [] if not data_type.parent_type: protocols.append('CustomStringConvertible') with self.class_block(data_type, protocols=protocols): for field in data_type.fields: fdoc = self.process_doc( field.doc, self._docf) if field.doc else undocumented self.emit_wrapped_text(fdoc, prefix='/// ', width=120) self.emit('open let {}: {}'.format( fmt_var(field.name), fmt_type(field.data_type), )) self._generate_struct_init(namespace, data_type) decl = 'open var' if not data_type.parent_type else 'open override var' with self.block('{} description: String'.format(decl)): cls = fmt_class(data_type.name) + 'Serializer' self.emit( 'return "\\(SerializeUtil.prepareJSONForSerialization' + '({}().serialize(self)))"'.format(cls)) self._generate_struct_class_serializer(namespace, data_type)
def _emit_route(self, namespace, route, req_obj_name, extra_args=None, extra_docs=None): arg_list, doc_list = self._get_route_args(namespace, route) extra_args = extra_args or [] extra_docs = extra_docs or [] arg_type = fmt_type(route.arg_data_type) func_name = fmt_func(route.name) if route.doc: route_doc = self.process_doc(route.doc, self._docf) else: route_doc = 'The {} route'.format(func_name) self.emit_wrapped_text(route_doc, prefix='/// ', width=120) self.emit('///') for name, doc in doc_list + extra_docs: param_doc = '- parameter {}: {}'.format(name, doc if doc is not None else undocumented) self.emit_wrapped_text(param_doc, prefix='/// ', width=120) self.emit('///') output = (' - returns: Through the response callback, the caller will ' + 'receive a `{}` object on success or a `{}` object on failure.') output = output.format(fmt_type(route.result_data_type), fmt_type(route.error_data_type)) self.emit_wrapped_text(output, prefix='/// ', width=120) func_args = [ ('route', '{}.{}'.format(fmt_class(namespace.name), func_name)), ] client_args = [] return_args = [('route', 'route')] for name, value, typ in extra_args: arg_list.append((name, typ)) func_args.append((name, value)) client_args.append((name, value)) rtype = fmt_serial_type(route.result_data_type) etype = fmt_serial_type(route.error_data_type) self._maybe_generate_deprecation_warning(route) with self.function_block('public func {}'.format(func_name), args=self._func_args(arg_list, force_first=True), return_type='{}<{}, {}>'.format(req_obj_name, rtype, etype)): self.emit('let route = {}.{}'.format(fmt_class(namespace.name), func_name)) if is_struct_type(route.arg_data_type): args = [(name, name) for name, _ in self._struct_init_args(route.arg_data_type)] func_args += [('serverArgs', '{}({})'.format(arg_type, self._func_args(args)))] self.emit('let serverArgs = {}({})'.format(arg_type, self._func_args(args))) elif is_union_type(route.arg_data_type): self.emit('let serverArgs = {}'.format(fmt_var(route.arg_data_type.name))) if not is_void_type(route.arg_data_type): return_args += [('serverArgs', 'serverArgs')] return_args += client_args self.emit('return client.request({})'.format(self._func_args(return_args, not_init=True))) self.emit()
def fmt_serial_type(data_type): data_type, nullable = unwrap_nullable(data_type) if is_user_defined_type(data_type): result = '{}.{}Serializer' result = result.format(fmt_class(data_type.namespace.name), fmt_class(data_type.name)) else: result = _serial_type_table.get(data_type.__class__, fmt_class(data_type.name)) if is_list_type(data_type): result = result + '<{}>'.format(fmt_serial_type(data_type.data_type)) return result if not nullable else 'NullableSerializer'
def _generate_union_type(self, namespace, data_type): self.emit('/**') if data_type.doc: doc = self.process_doc(data_type.doc, self._docf) else: doc = 'The {} union'.format(self.class_data_type(data_type)) self.emit_wrapped_text(doc, prefix=' ', width=120) self.emit('*/') class_type = self.class_data_type(data_type) with self.block('public enum {}: CustomStringConvertible'.format(class_type)): all_fields = self._populate_all_fields(data_type) for field in all_fields: typ = self._format_tag_type(namespace, field.data_type) if field.doc: self.emit('/**') self.emit_wrapped_text(self.process_doc(field.doc, self._docf), prefix=' ', width=120) self.emit('*/') self.emit('case {}{}'.format(fmt_class(field.name), typ)) with self.block('public var description : String'): cls = class_type+'Serializer' self.emit( 'return "\(prepareJSONForSerialization({}().serialize(self)))"'.format(cls) ) self._generate_union_serializer(data_type)
def _generate_client(self, api): self.emit_raw(base) self.emit('import Alamofire') self.emit() with self.block('open class {}'.format(self.args.class_name)): namespace_fields = [] for namespace in api.namespaces.values(): if namespace.routes: namespace_fields.append( (namespace.name, fmt_class(namespace.name))) for var, typ in namespace_fields: self.emit('/// Routes within the {} namespace. ' 'See {}Routes for details.'.format(var, typ)) self.emit('open var {}: {}Routes!'.format(var, typ)) self.emit() with self.function_block('public init', args=self._func_args([ ('client', '{}'.format( self.args.transport_client_name)) ])): for var, typ in namespace_fields: self.emit('self.{} = {}Routes(client: client)'.format( var, typ))
def _generate_bound_client(self, api, raw_client): self.emit_raw(base) self.emit('import Alamofire') self.emit('/// The client for the API. Call routes using' 'the namespaces inside this object.') with self.block('public class DropboxClient : StoneClient'): self.emit_raw(raw_client.read()) namespace_fields = [] for namespace in api.namespaces.values(): if len(namespace.routes) > 0: namespace_fields.append((namespace.name, fmt_class(namespace.name))) my_props = [('accessToken', 'DropboxAccessToken')] super_props = [('manager', 'Manager'), ('backgroundManager', 'Manager'), ('baseHosts', '[String : String]')] for var, typ in namespace_fields: self.emit('/// Routes within the {} namespace.' 'See {}Routes for details.'.format(var, typ)) self.emit('public var {} : {}Routes!'.format(var, typ)) with self.function_block('public init', self._func_args(my_props + super_props)): for var, typ in my_props: self.emit('self.{} = {}'.format(var, var)) self.emit('super.init({})'.format(self._func_args((name,name) for name, _ in super_props))) for var, typ in namespace_fields: self.emit('self.{} = {}Routes(client: self)'.format(var, typ))
def generate(self, api): rsrc_folder = os.path.join(os.path.dirname(__file__), 'swift_rsrc') self.logger.info('Copying StoneValidators.swift to output folder') shutil.copy(os.path.join(rsrc_folder, 'StoneValidators.swift'), self.target_folder_path) self.logger.info('Copying StoneSerializers.swift to output folder') shutil.copy(os.path.join(rsrc_folder, 'StoneSerializers.swift'), self.target_folder_path) self.logger.info('Copying StoneBase.swift to output folder') shutil.copy(os.path.join(rsrc_folder, 'StoneBase.swift'), self.target_folder_path) jazzy_cfg_path = os.path.join(rsrc_folder, 'jazzy.json') with open(jazzy_cfg_path) as jazzy_file: jazzy_cfg = json.load(jazzy_file) for namespace in api.namespaces.values(): ns_class = fmt_class(namespace.name) with self.output_to_relative_path('{}.swift'.format(ns_class)): self._generate_base_namespace_module(api, namespace) jazzy_cfg['custom_categories'][1]['children'].append(ns_class) if namespace.routes: jazzy_cfg['custom_categories'][0]['children'].append(ns_class + 'Routes') with self.output_to_relative_path('../.jazzy.json'): self.emit_raw(json.dumps(jazzy_cfg, indent=2)+'\n')
def serializer_func(self, data_type): with self.function_block('open func serialize', args=self._func_args([ ('_ value', fmt_class(data_type.name)) ]), return_type='JSON'): yield
def generate(self, api): rsrc_folder = os.path.join(os.path.dirname(__file__), 'swift_rsrc') self.logger.info('Copying StoneValidators.swift to output folder') shutil.copy(os.path.join(rsrc_folder, 'StoneValidators.swift'), self.target_folder_path) self.logger.info('Copying StoneSerializers.swift to output folder') shutil.copy(os.path.join(rsrc_folder, 'StoneSerializers.swift'), self.target_folder_path) self.logger.info('Copying StoneBase.swift to output folder') shutil.copy(os.path.join(rsrc_folder, 'StoneBase.swift'), self.target_folder_path) jazzy_cfg_path = os.path.join('../Format', 'jazzy.json') with open(jazzy_cfg_path) as jazzy_file: jazzy_cfg = json.load(jazzy_file) for namespace in api.namespaces.values(): ns_class = fmt_class(namespace.name) with self.output_to_relative_path('{}.swift'.format(ns_class)): self._generate_base_namespace_module(api, namespace) jazzy_cfg['custom_categories'][1]['children'].append(ns_class) if namespace.routes: jazzy_cfg['custom_categories'][0]['children'].append(ns_class + 'Routes') with self.output_to_relative_path('../../../../.jazzy.json'): self.emit_raw(json.dumps(jazzy_cfg, indent=2) + '\n')
def _generate_union_serializer(self, data_type): with self.serializer_block(data_type): with self.serializer_func(data_type), self.block('switch value'): for field in data_type.all_fields: field_type = field.data_type case = '.{}{}'.format(fmt_class(field.name), '' if is_void_type(field_type) else '(let arg)') self.emit('case {}:'.format(case)) with self.indent(): if is_void_type(field_type): self.emit('var d = [String: JSON]()') elif (is_struct_type(field_type) and not field_type.has_enumerated_subtypes()): self.emit('var d = Serialization.getFields({}.serialize(arg))'.format( fmt_serial_obj(field_type))) else: self.emit('var d = ["{}": {}.serialize(arg)]'.format( field.name, fmt_serial_obj(field_type))) self.emit('d[".tag"] = .Str("{}")'.format(field.name)) self.emit('return .Dictionary(d)') with self.deserializer_func(data_type): with self.block("switch json"): self.emit("case .Dictionary(let d):") with self.indent(): self.emit('let tag = Serialization.getTag(d)') with self.block('switch tag'): for field in data_type.all_fields: field_type = field.data_type self.emit('case "{}":'.format(field.name)) tag_type = self._tag_type(data_type, field) with self.indent(): if is_void_type(field_type): self.emit('return {}'.format(tag_type)) else: if (is_struct_type(field_type) and not field_type.has_enumerated_subtypes()): subdict = 'json' else: subdict = 'd["{}"] ?? .Null'.format(field.name) self.emit('let v = {}.deserialize({})'.format( fmt_serial_obj(field_type), subdict )) self.emit('return {}(v)'.format(tag_type)) self.emit('default:') with self.indent(): if data_type.catch_all_field: self.emit('return {}'.format( self._tag_type(data_type, data_type.catch_all_field) )) else: self.emit('fatalError("Unknown tag \(tag)")') self.emit("default:") with self.indent(): self.emit('fatalError("Failed to deserialize")')
def generate(self, api): for namespace in api.namespaces.values(): ns_class = fmt_class(namespace.name) if namespace.routes: with self.output_to_relative_path('{}Routes.swift'.format(ns_class)): self._generate_routes(namespace) with self.output_to_relative_path('{}.swift'.format(self.args.module_name)): self._generate_client(api)
def _get_route_args(self, namespace, route): data_type = route.arg_data_type arg_type = fmt_type(data_type) if is_struct_type(data_type): arg_list = self._struct_init_args(data_type, namespace=namespace) doc_list = [(fmt_var(f.name), self.process_doc(f.doc, self._docf) if f.doc else undocumented) for f in data_type.fields if f.doc] elif is_union_type(data_type): arg_list = [(fmt_var(data_type.name), '{}.{}'.format( fmt_class(namespace.name), fmt_class(data_type.name)))] doc_list = [(fmt_var(data_type.name), self.process_doc(data_type.doc, self._docf) if data_type.doc else 'The {} union'.format(fmt_class(data_type.name)))] else: arg_list = [] if is_void_type(data_type) else [('request', arg_type)] doc_list = [] return arg_list, doc_list
def fmt_serial_obj(data_type): data_type, nullable = unwrap_nullable(data_type) if is_user_defined_type(data_type): result = '{}.{}Serializer()' result = result.format(fmt_class(data_type.namespace.name), fmt_class(data_type.name)) else: result = _serial_type_table.get(data_type.__class__, fmt_class(data_type.name)) if is_list_type(data_type): result = result + '({})'.format(fmt_serial_obj(data_type.data_type)) elif is_timestamp_type(data_type): result = result + '("{}")'.format(data_type.format) else: result = 'Serialization._{}'.format(result) return result if not nullable else 'NullableSerializer({})'.format(result)
def generate(self, api): rsrc_folder = os.path.join(os.path.dirname(__file__), 'swift_rsrc') for namespace in api.namespaces.values(): ns_class = fmt_class(namespace.name) if namespace.routes: with self.output_to_relative_path('{}Routes.swift'.format(ns_class)): self._generate_routes(namespace) with self.output_to_relative_path('{}.swift'.format(self.args.module_name)): self._generate_client(api)
def generate(self, api): for namespace in api.namespaces.values(): ns_class = fmt_class(namespace.name) if namespace.routes: with self.output_to_relative_path( '{}Routes.swift'.format(ns_class)): self._generate_routes(namespace) with self.output_to_relative_path('{}.swift'.format( self.args.module_name)): self._generate_client(api)
def _generate_routes(self, namespace): ns_class = fmt_class(namespace.name) self.emit('/// Routes for the {} namespace'.format(namespace.name)) with self.block('public class {}Routes'.format(ns_class)): self.emit('public let client : StoneClient') args = [('client', 'StoneClient')] with self.function_block('init', self._func_args(args)): self.emit('self.client = client') for route in namespace.routes: self._generate_route(namespace, route)
def _generate_base_namespace_module(self, namespace): self.emit_raw(base) self.emit('/**') self.emit(' Datatypes and serializers for the {} namespace'.format(namespace.name)) self.emit('*/') with self.block('public class {}'.format(fmt_class(namespace.name))): for data_type in namespace.linearize_data_types(): if is_struct_type(data_type): self._generate_struct_class(namespace, data_type) elif is_union_type(data_type): self._generate_union_type(namespace, data_type)
def generate(self, api): rsrc_folder = os.path.join(os.path.dirname(__file__), 'swift_rsrc') for namespace in api.namespaces.values(): ns_class = fmt_class(namespace.name) if namespace.routes: with self.output_to_relative_path( '{}Routes.swift'.format(ns_class)): self._generate_routes(namespace) with self.output_to_relative_path('{}.swift'.format( self.args.module_name)): self._generate_client(api)
def _generate_struct_base_class_deserializer(self, namespace, data_type): args = [] for field in data_type.all_fields: var = fmt_var(field.name) value = 'dict["{}"]'.format(field.name) self.emit('let {} = {}.deserialize({} ?? {})'.format( var, fmt_serial_obj(field.data_type), value, fmt_default_value(namespace, field) if field.has_default else '.null')) args.append((var, var)) self.emit('return {}({})'.format(fmt_class(data_type.name), self._func_args(args)))
def _generate_struct_base_class_deserializer(self, namespace, data_type): args = [] for field in data_type.all_fields: var = fmt_var(field.name) self.emit('let {} = {}.deserialize(dict["{}"] ?? .Null)'.format( var, fmt_serial_obj(field.data_type), field.name, )) args.append((var, var)) self.emit('return {}({})'.format(fmt_class(data_type.name), self._func_args(args)))
def _get_route_args(self, namespace, route): data_type = route.arg_data_type arg_type = fmt_type(data_type) if is_struct_type(data_type): arg_list = self._struct_init_args(data_type, namespace=namespace) doc_list = [(fmt_var(f.name), self.process_doc(f.doc, self._docf) if f.doc else undocumented) for f in data_type.fields if f.doc] elif is_union_type(data_type): arg_list = [(fmt_var(data_type.name), '{}.{}'.format(fmt_class(namespace.name), fmt_class(data_type.name)))] doc_list = [ (fmt_var(data_type.name), self.process_doc(data_type.doc, self._docf) if data_type.doc else 'The {} union'.format(fmt_class(data_type.name))) ] else: arg_list = [] if is_void_type(data_type) else [('request', arg_type)] doc_list = [] return arg_list, doc_list
def _generate_union_type(self, namespace, data_type): if data_type.doc: doc = self.process_doc(data_type.doc, self._docf) else: doc = 'The {} union'.format(fmt_class(data_type.name)) self.emit_wrapped_text(doc, prefix='/// ', width=120) class_type = fmt_class(data_type.name) with self.block('public enum {}: CustomStringConvertible'.format(class_type)): for field in data_type.all_fields: typ = self._format_tag_type(namespace, field.data_type) fdoc = self.process_doc(field.doc, self._docf) if field.doc else 'An unspecified error.' self.emit_wrapped_text(fdoc, prefix='/// ', width=120) self.emit('case {}{}'.format(fmt_var(field.name), typ)) self.emit() with self.block('public var description: String'): cls = class_type + 'Serializer' self.emit('return "\\(SerializeUtil.prepareJSONForSerialization' + '({}().serialize(self)))"'.format(cls)) self._generate_union_serializer(data_type)
def _generate_struct_base_class_deserializer(self, namespace, data_type): args = [] for field in data_type.all_fields: var = fmt_var(field.name) self.emit('let {} = {}.deserialize(dict["{}"] ?? .Null)'.format( var, fmt_serial_obj(field.data_type), field.name, )) args.append((var, var)) self.emit('return {}({})'.format( fmt_class(data_type.name), self._func_args(args) ))
def _docf(self, tag, val): if tag == 'route': return fmt_func(val) elif tag == 'field': if '.' in val: cls, field = val.split('.') return ('{} in {}'.format(fmt_var(field), fmt_class(cls))) else: return fmt_var(val) elif tag in ('type', 'val', 'link'): return val else: import pdb pdb.set_trace() return val
def class_block(self, thing, protocols=None): protocols = protocols or [] extensions = [] if isinstance(thing, DataType): name = fmt_class(thing.name) if thing.parent_type: extensions.append(fmt_type(thing.parent_type)) else: name = thing extensions.extend(protocols) extend_suffix = ': {}'.format(', '.join(extensions)) if extensions else '' with self.block('open class {}{}'.format(name, extend_suffix)): yield
def _generate_routes(self, namespace): ns_class = fmt_class(namespace.name) self.emit_raw(stone_warning) self.emit('/// Routes for the {} namespace'.format(namespace.name)) with self.block('open class {}Routes'.format(ns_class)): self.emit('open let client: {}'.format(self.args.transport_client_name)) args = [('client', '{}'.format(self.args.transport_client_name))] with self.function_block('init', self._func_args(args)): self.emit('self.client = client') self.emit() for route in namespace.routes: self._generate_route(namespace, route)
def _generate_base_namespace_module(self, api, namespace): self.emit_raw(base) routes_base = 'Datatypes and serializers for the {} namespace'.format(namespace.name) self.emit_wrapped_text(routes_base, prefix='/// ', width=120) with self.block('public class {}'.format(fmt_class(namespace.name))): for data_type in namespace.linearize_data_types(): if is_struct_type(data_type): self._generate_struct_class(namespace, data_type) self.emit() elif is_union_type(data_type): self._generate_union_type(namespace, data_type) self.emit() if namespace.routes: self._generate_route_objects(api.route_schema, namespace)
def class_block(self, thing, protocols=None): protocols = protocols or [] extensions = [] if isinstance(thing, DataType): name = fmt_class(thing.name) if thing.parent_type: extensions.append(fmt_type(thing.parent_type)) else: name = thing extensions.extend(protocols) extend_suffix = ': {}'.format(', '.join(extensions)) if extensions else '' with self.block('public class {}{}'.format(name, extend_suffix)): yield
def _generate_base_namespace_module(self, api, namespace): self.emit_raw(base) routes_base = 'Datatypes and serializers for the {} namespace'.format(namespace.name) self.emit_wrapped_text(routes_base, prefix='/// ', width=120) with self.block('open class {}'.format(fmt_class(namespace.name))): for data_type in namespace.linearize_data_types(): if is_struct_type(data_type): self._generate_struct_class(namespace, data_type) self.emit() elif is_union_type(data_type): self._generate_union_type(namespace, data_type) self.emit() if namespace.routes: self._generate_route_objects(api.route_schema, namespace)
def _generate_routes(self, namespace): ns_class = fmt_class(namespace.name) self.emit_raw(stone_warning) self.emit('/// Routes for the {} namespace'.format(namespace.name)) with self.block('open class {}Routes'.format(ns_class)): self.emit('open let client: {}'.format( self.args.transport_client_name)) args = [('client', '{}'.format(self.args.transport_client_name))] with self.function_block('init', self._func_args(args)): self.emit('self.client = client') self.emit() for route in namespace.routes: self._generate_route(namespace, route)
def _swift_type_mapping(self, data_type, serializer=False): suffix = 'Serializer' if serializer else '' if is_nullable_type(data_type): data_type = data_type.data_type nullable = True else: nullable = False if is_list_type(data_type): ret = 'Array{}<{}>'.format( suffix, self._swift_type_mapping(data_type.data_type, serializer) ) suffix = '' elif is_string_type(data_type): ret = 'String' elif is_timestamp_type(data_type): ret = 'NSDate' elif is_boolean_type(data_type): ret = 'Bool' elif is_bytes_type(data_type): ret = 'NSData' elif is_void_type(data_type): ret = 'Void' elif isinstance(data_type, Int32): ret = 'Int32' elif isinstance(data_type, Int64): ret = 'Int64' elif isinstance(data_type, UInt32): ret = 'UInt32' elif isinstance(data_type, UInt64): ret = 'UInt64' elif isinstance(data_type, Float32): ret = 'Float' elif isinstance(data_type, Float64): ret = 'Double' elif is_user_defined_type(data_type): ret = '{}.{}'.format(fmt_class(data_type.namespace.name), self.class_data_type(data_type)) ret += suffix if nullable: if serializer: ret = 'NullableSerializer<{}>'.format(ret) else: ret += '?' return ret
def _generate_struct_base_class_deserializer(self, namespace, data_type): args = [] for field in data_type.all_fields: var = fmt_var(field.name) value = 'dict["{}"]'.format(field.name) self.emit('let {} = {}.deserialize({} ?? {})'.format( var, fmt_serial_obj(field.data_type), value, fmt_default_value(namespace, field) if field.has_default else '.null' )) args.append((var, var)) self.emit('return {}({})'.format( fmt_class(data_type.name), self._func_args(args) ))
def _struct_init_args(self, data_type, namespace=None): args = [] for field in data_type.all_fields: name = fmt_var(field.name) value = fmt_type(field.data_type) data_type, nullable = unwrap_nullable(field.data_type) if field.has_default: if is_union_type(data_type): default = '.{}'.format(fmt_class(field.default.tag_name)) else: default = fmt_obj(field.default) value += ' = {}'.format(default) elif nullable: value += ' = nil' arg = (name, value) args.append(arg) return args
def _generate_client(self, api): self.emit_raw(base) self.emit('import Alamofire') self.emit() with self.block('open class {}'.format(self.args.class_name)): namespace_fields = [] for namespace in api.namespaces.values(): if namespace.routes: namespace_fields.append((namespace.name, fmt_class(namespace.name))) for var, typ in namespace_fields: self.emit('/// Routes within the {} namespace. ' 'See {}Routes for details.'.format(var, typ)) self.emit('open var {}: {}Routes!'.format(var, typ)) self.emit() with self.function_block('public init', args=self._func_args( [('client', '{}'.format(self.args.transport_client_name))])): for var, typ in namespace_fields: self.emit('self.{} = {}Routes(client: client)'.format(var, typ))
def generate(self, api): rsrc_folder = os.path.join(os.path.dirname(__file__), 'swift_rsrc') self.logger.info('Copying StoneSerializers.swift to output folder') shutil.copy(os.path.join(rsrc_folder, 'StoneSerializers.swift'), os.path.join(self.target_folder_path, 'Source')) self.logger.info('Copying StoneValidators.swift to output folder') shutil.copy(os.path.join(rsrc_folder, 'StoneValidators.swift'), os.path.join(self.target_folder_path, 'Source')) self.logger.info('Copying Client.swift to output folder') shutil.copy(os.path.join(rsrc_folder, 'Client.swift'), os.path.join(self.target_folder_path, 'Source')) jazzy_cfg_path = os.path.join(rsrc_folder, 'jazzy.json') with open(jazzy_cfg_path) as jazzy_file: jazzy_cfg = json.load(jazzy_file) for namespace in api.namespaces.values(): ns_class = fmt_class(namespace.name) path = os.path.join('Source', '{}.swift'.format(ns_class)) with self.output_to_relative_path(path): self._generate_base_namespace_module(namespace) jazzy_cfg['custom_categories'][1]['children'].append(ns_class) if len(namespace.routes) > 0: path = os.path.join('Source', '{}Routes.swift'.format(ns_class)) with self.output_to_relative_path(path): self._generate_routes(namespace) jazzy_cfg['custom_categories'][0]['children'].append(ns_class + 'Routes') with self.output_to_relative_path('.jazzy.json'): self.emit_raw(json.dumps(jazzy_cfg, indent=2)+'\n') client_path = os.path.join('Source', 'DropboxClient.swift') dropbox_raw_path = os.path.join(rsrc_folder, 'DropboxClient-raw.swift') with open(dropbox_raw_path) as raw_client, self.output_to_relative_path(client_path): self._generate_bound_client(api, raw_client)
def _serializer_obj(self, data_type): if is_nullable_type(data_type): data_type = data_type.data_type nullable = True else: nullable = False if is_list_type(data_type): ret = 'ArraySerializer({})'.format( self._serializer_obj(data_type.data_type)) elif is_string_type(data_type): ret = 'Serialization._StringSerializer' elif is_timestamp_type(data_type): ret = 'NSDateSerializer("{}")'.format(data_type.format) elif is_boolean_type(data_type): ret = 'Serialization._BoolSerializer' elif is_bytes_type(data_type): ret = 'Serialization._NSDataSerializer' elif is_void_type(data_type): ret = 'Serialization._VoidSerializer' elif isinstance(data_type, Int32): ret = 'Serialization._Int32Serializer' elif isinstance(data_type, Int64): ret = 'Serialization._Int64Serializer' elif isinstance(data_type, UInt32): ret = 'Serialization._UInt32Serializer' elif isinstance(data_type, UInt64): ret = 'Serialization._UInt64Serializer' elif isinstance(data_type, Float32): ret = 'Serialization._FloatSerializer' elif isinstance(data_type, Float64): ret = 'Serialization._DoubleSerializer' elif is_user_defined_type(data_type): ret = "{}.{}Serializer()".format(fmt_class(data_type.namespace.name), self.class_data_type(data_type)) if nullable: ret = 'NullableSerializer({})'.format(ret) return ret
def _struct_init_args(self, data_type, namespace=None): args = [] for field in data_type.all_fields: name = fmt_var(field.name) value = self._swift_type_mapping(field.data_type) field_type = field.data_type if is_nullable_type(field_type): field_type = field_type.data_type nullable = True else: nullable = False if field.has_default: if is_union_type(field_type): default = '.{}'.format(fmt_class(field.default.tag_name)) else: default = fmt_obj(field.default) value += ' = {}'.format(default) elif nullable: value += ' = nil' arg = (name, value) args.append(arg) return args
def deserializer_func(self, data_type): with self.function_block('public func deserialize', args=self._func_args([('json', 'JSON')]), return_type=fmt_class(data_type.name)): yield
def serializer_func(self, data_type): with self.function_block('public func serialize', args=self._func_args([('value', fmt_class(data_type.name))]), return_type='JSON'): yield
def serializer_block(self, data_type): with self.class_block(fmt_class(data_type.name)+'Serializer', protocols=['JSONSerializer']): self.emit("public init() { }") yield
def _tag_type(self, data_type, field): return "{}.{}".format( fmt_class(data_type.name), fmt_class(field.name) )
def _tag_type(self, data_type, field): return "{}.{}".format(fmt_class(data_type.name), fmt_var(field.name))
def serializer_block(self, data_type): with self.class_block(fmt_class(data_type.name) + 'Serializer', protocols=['JSONSerializer']): self.emit("public init() { }") yield
def _generate_union_serializer(self, data_type): with self.serializer_block(data_type): with self.serializer_func(data_type), self.block('switch value'): for field in data_type.all_fields: field_type = field.data_type case = '.{}{}'.format( fmt_class(field.name), '' if is_void_type(field_type) else '(let arg)') self.emit('case {}:'.format(case)) with self.indent(): if is_void_type(field_type): self.emit('var d = [String: JSON]()') elif (is_struct_type(field_type) and not field_type.has_enumerated_subtypes()): self.emit( 'var d = Serialization.getFields({}.serialize(arg))' .format(fmt_serial_obj(field_type))) else: self.emit( 'var d = ["{}": {}.serialize(arg)]'.format( field.name, fmt_serial_obj(field_type))) self.emit('d[".tag"] = .Str("{}")'.format(field.name)) self.emit('return .Dictionary(d)') with self.deserializer_func(data_type): with self.block("switch json"): self.emit("case .Dictionary(let d):") with self.indent(): self.emit('let tag = Serialization.getTag(d)') with self.block('switch tag'): for field in data_type.all_fields: field_type = field.data_type self.emit('case "{}":'.format(field.name)) tag_type = self._tag_type(data_type, field) with self.indent(): if is_void_type(field_type): self.emit('return {}'.format(tag_type)) else: if (is_struct_type(field_type) and not field_type. has_enumerated_subtypes()): subdict = 'json' else: subdict = 'd["{}"] ?? .Null'.format( field.name) self.emit( 'let v = {}.deserialize({})'. format(fmt_serial_obj(field_type), subdict)) self.emit( 'return {}(v)'.format(tag_type)) self.emit('default:') with self.indent(): if data_type.catch_all_field: self.emit('return {}'.format( self._tag_type( data_type, data_type.catch_all_field))) else: self.emit( 'fatalError("Unknown tag \(tag)")') self.emit("default:") with self.indent(): self.emit('fatalError("Failed to deserialize")')
def deserializer_func(self, data_type): with self.function_block('open func deserialize', args=self._func_args([('_ json', 'JSON')]), return_type=fmt_class(data_type.name)): yield
def _emit_route(self, namespace, route, req_obj_name, extra_args=None, extra_docs=None): arg_list, doc_list = self._get_route_args(namespace, route) extra_args = extra_args or [] extra_docs = extra_docs or [] arg_type = fmt_type(route.arg_data_type) func_name = fmt_func(route.name) if route.doc: route_doc = self.process_doc(route.doc, self._docf) else: route_doc = 'The {} route'.format(func_name) self.emit_wrapped_text(route_doc, prefix='/// ', width=120) self.emit('///') for name, doc in doc_list + extra_docs: param_doc = '- parameter {}: {}'.format( name, doc if doc is not None else undocumented) self.emit_wrapped_text(param_doc, prefix='/// ', width=120) self.emit('///') output = ( ' - returns: Through the response callback, the caller will ' + 'receive a `{}` object on success or a `{}` object on failure.') output = output.format(fmt_type(route.result_data_type), fmt_type(route.error_data_type)) self.emit_wrapped_text(output, prefix='/// ', width=120) func_args = [ ('route', '{}.{}'.format(fmt_class(namespace.name), func_name)), ] client_args = [] return_args = [('route', 'route')] for name, value, typ in extra_args: arg_list.append((name, typ)) func_args.append((name, value)) client_args.append((name, value)) rtype = fmt_serial_type(route.result_data_type) etype = fmt_serial_type(route.error_data_type) self._maybe_generate_deprecation_warning(route) with self.function_block( '@discardableResult open func {}'.format(func_name), args=self._func_args(arg_list, force_first=False), return_type='{}<{}, {}>'.format(req_obj_name, rtype, etype)): self.emit('let route = {}.{}'.format(fmt_class(namespace.name), func_name)) if is_struct_type(route.arg_data_type): args = [ (name, name) for name, _ in self._struct_init_args(route.arg_data_type) ] func_args += [ ('serverArgs', '{}({})'.format(arg_type, self._func_args(args))) ] self.emit('let serverArgs = {}({})'.format( arg_type, self._func_args(args))) elif is_union_type(route.arg_data_type): self.emit('let serverArgs = {}'.format( fmt_var(route.arg_data_type.name))) if not is_void_type(route.arg_data_type): return_args += [('serverArgs', 'serverArgs')] return_args += client_args self.emit('return client.request({})'.format( self._func_args(return_args, not_init=True))) self.emit()