def testProperties(self): schema = idl_schema.Load('test/idl_properties.idl')[0] self.assertEquals( OrderedDict([ ('first', OrderedDict([ ('description', 'Integer property.'), ('jsexterns', None), ('type', 'integer'), ('value', 42), ])), ('second', OrderedDict([ ('description', 'Double property.'), ('jsexterns', None), ('type', 'number'), ('value', 42.1), ])), ('third', OrderedDict([ ('description', 'String property.'), ('jsexterns', None), ('type', 'string'), ('value', 'hello world'), ])), ('fourth', OrderedDict([ ('description', 'Unvalued property.'), ('jsexterns', None), ('type', 'integer'), ])), ]), schema.get('properties'))
def process(self, callbacks): properties = self.additional_properties result = properties if self.parent.GetProperty('OPTIONAL', False): properties['optional'] = True # The IDL parser denotes array types by adding a child 'Array' node onto # the Param node in the Callspec. for sibling in self.parent.GetChildren(): if sibling.cls == 'Array' and sibling.GetName( ) == self.parent.GetName(): properties['type'] = 'array' properties['items'] = OrderedDict() properties = properties['items'] break if self.typeref == 'DOMString': properties['type'] = 'string' elif self.typeref == 'boolean': properties['type'] = 'boolean' elif self.typeref == 'double': properties['type'] = 'number' elif self.typeref == 'long': properties['type'] = 'integer' elif self.typeref == 'any': properties['type'] = 'any' elif self.typeref == 'object': properties['type'] = 'object' if 'additionalProperties' not in properties: properties['additionalProperties'] = OrderedDict() properties['additionalProperties']['type'] = 'any' instance_of = self.parent.GetProperty('instanceOf') if instance_of: properties['isInstanceOf'] = instance_of elif self.typeref == 'ArrayBuffer': properties['type'] = 'binary' properties['isInstanceOf'] = 'ArrayBuffer' elif self.typeref == 'FileEntry': properties['type'] = 'object' properties['isInstanceOf'] = 'FileEntry' if 'additionalProperties' not in properties: properties['additionalProperties'] = OrderedDict() properties['additionalProperties']['type'] = 'any' elif self.typeref is None: properties['type'] = 'function' else: if self.typeref in callbacks: # Do not override name and description if they are already specified. name = properties.get('name', None) description = properties.get('description', None) properties.update(callbacks[self.typeref]) if description is not None: properties['description'] = description if name is not None: properties['name'] = name else: properties['$ref'] = self.typeref return result
def testManifestKeys(self): schema = self.idl_basics self.assertEquals( OrderedDict([('key_str', OrderedDict([('description', 'String manifest key.'), ('jsexterns', None), ('name', 'key_str'), ('type', 'string')])), ('key_ref', OrderedDict([('name', 'key_ref'), ('$ref', 'MyType2')]))]), schema.get('manifest_keys'))
def _AddEvents(model, json, namespace): """Adds Function objects to |model| contained in the 'events' field of |json|. """ model.events = OrderedDict() for event_json in json.get('events', []): event = Function(model, event_json, namespace, from_client=True) model.events[event.name] = event
def _NamespaceTypeDependencies(self): """Returns a dict ordered by namespace name containing a mapping of model.Namespace to every _TypeDependency for |self._default_namespace|, sorted by the type's name. """ dependencies = set() for function in self._default_namespace.functions.values(): for param in function.params: dependencies |= self._TypeDependencies(param.type_, hard=not param.optional) if function.callback: for param in function.callback.params: dependencies |= self._TypeDependencies( param.type_, hard=not param.optional) for type_ in self._default_namespace.types.values(): for prop in type_.properties.values(): dependencies |= self._TypeDependencies(prop.type_, hard=not prop.optional) for event in self._default_namespace.events.values(): for param in event.params: dependencies |= self._TypeDependencies(param.type_, hard=not param.optional) # Make sure that the dependencies are returned in alphabetical order. dependency_namespaces = OrderedDict() for dependency in sorted(dependencies, key=_TypeDependency.GetSortKey): namespace = dependency.type_.namespace if namespace is self._default_namespace: continue if namespace not in dependency_namespaces: dependency_namespaces[namespace] = [] dependency_namespaces[namespace].append(dependency) return dependency_namespaces
def _AddTypes(model, json, namespace): """Adds Type objects to |model| contained in the 'types' field of |json|. """ model.types = OrderedDict() for type_json in json.get('types', []): type_ = Type(model, type_json['id'], type_json, namespace) model.types[type_.name] = type_
def _GetProperties(parent, json, namespace, origin): """Generates Property objects extracted from |json|. """ properties = OrderedDict() for name, property_json in json.get('properties', {}).items(): properties[name] = Property(parent, name, property_json, namespace, origin) return properties
def process(self, callbacks): properties = OrderedDict() name = self.node.GetName() if self.node.GetProperty('deprecated'): properties['deprecated'] = self.node.GetProperty('deprecated') if self.node.GetProperty('allowAmbiguousOptionalArguments'): properties['allowAmbiguousOptionalArguments'] = True for property_name in ('OPTIONAL', 'nodoc', 'nocompile', 'nodart'): if self.node.GetProperty(property_name): properties[property_name.lower()] = True for option_name, sanitizer in [ ('maxListeners', int), ('supportsFilters', lambda s: s == 'true'), ('supportsListeners', lambda s: s == 'true'), ('supportsRules', lambda s: s == 'true')]: if self.node.GetProperty(option_name): if 'options' not in properties: properties['options'] = {} properties['options'][option_name] = sanitizer(self.node.GetProperty( option_name)) is_function = False parameter_comments = OrderedDict() for node in self.node.GetChildren(): if node.cls == 'Comment': (parent_comment, parameter_comments) = ProcessComment(node.GetName()) properties['description'] = parent_comment elif node.cls == 'Callspec': is_function = True name, parameters, return_type = (Callspec(node, parameter_comments) .process(callbacks)) properties['parameters'] = parameters if return_type is not None: properties['returns'] = return_type properties['name'] = name if is_function: properties['type'] = 'function' else: properties = Typeref(self.node.GetProperty('TYPEREF'), self.node, properties).process(callbacks) enum_values = self.node.GetProperty('legalValues') if enum_values: if properties['type'] == 'integer': enum_values = map(int, enum_values) elif properties['type'] == 'double': enum_values = map(float, enum_values) properties['enum'] = enum_values return name, properties
def _GetTypes(parent, json, namespace, origin): """Creates Type objects extracted from |json|. """ types = OrderedDict() for type_json in json.get('types', []): type_ = Type(parent, type_json['id'], type_json, namespace, origin) types[type_.name] = type_ return types
def _AddFunctions(model, json, namespace): """Adds Function objects to |model| contained in the 'functions' field of |json|. """ model.functions = OrderedDict() for function_json in json.get('functions', []): function = Function(model, function_json, namespace, from_json=True) model.functions[function.name] = function
def _GetEvents(parent, json, namespace): """Creates Function objects generated from the events in |json|. """ events = OrderedDict() for event_json in json.get('events', []): event = Function(parent, event_json['name'], event_json, namespace, Origin(from_client=True)) events[event.name] = event return events
def __init__(self, namespace_node, description, nodoc=False, internal=False): self.namespace = namespace_node self.nodoc = nodoc self.internal = internal self.events = [] self.functions = [] self.types = [] self.callbacks = OrderedDict() self.description = description
def _GetFunctions(parent, json, namespace): """Creates Function objects extracted from |json|. """ functions = OrderedDict() for function_json in json.get('functions', []): function = Function(parent, function_json['name'], function_json, namespace, Origin(from_json=True)) functions[function.name] = function return functions
def ProcessComment(comment): ''' Convert a comment into a parent comment and a list of parameter comments. Function comments are of the form: Function documentation. May contain HTML and multiple lines. |arg1_name|: Description of arg1. Use <var>argument</var> to refer to other arguments. |arg2_name|: Description of arg2... Newlines are removed, and leading and trailing whitespace is stripped. Args: comment: The string from a Comment node. Returns: A tuple that looks like: ( "The processed comment, minus all |parameter| mentions.", { 'parameter_name_1': "The comment that followed |parameter_name_1|:", ... } ) ''' def add_paragraphs(content): paragraphs = content.split('\n\n') if len(paragraphs) < 2: return content return '<p>' + '</p><p>'.join(p.strip() for p in paragraphs) + '</p>' # Find all the parameter comments of the form '|name|: comment'. parameter_starts = list(re.finditer(r' *\|([^|]*)\| *: *', comment)) # Get the parent comment (everything before the first parameter comment. first_parameter_location = (parameter_starts[0].start() if parameter_starts else len(comment)) parent_comment = (add_paragraphs( comment[:first_parameter_location].strip()).replace('\n', '')) params = OrderedDict() for (cur_param, next_param) in itertools.izip_longest(parameter_starts, parameter_starts[1:]): param_name = cur_param.group(1) # A parameter's comment goes from the end of its introduction to the # beginning of the next parameter's introduction. param_comment_start = cur_param.end() param_comment_end = next_param.start() if next_param else len(comment) params[param_name] = (add_paragraphs( comment[param_comment_start:param_comment_end].strip()).replace( '\n', '')) return (parent_comment, params)
def _GetTypes(parent, json, namespace, origin): """Creates Type objects extracted from |json|. """ assert hasattr(namespace, 'manifest_keys'), \ 'Types should be parsed after parsing manifest keys.' types = OrderedDict() for type_json in json.get('types', []): type_ = Type(parent, type_json['id'], type_json, namespace, origin) types[type_.name] = type_ return types
def _AddProperties(model, json, namespace, from_json=False, from_client=False): """Adds model.Property objects to |model| contained in the 'properties' field of |json|. """ model.properties = OrderedDict() for name, property_json in json.get('properties', {}).items(): model.properties[name] = Property(model, name, property_json, namespace, from_json=from_json, from_client=from_client)
def __init__(self, namespace_node, description, nodoc=False, internal=False, platforms=None, compiler_options=None, deprecated=None, documentation_options=None): self.namespace = namespace_node self.nodoc = nodoc self.internal = internal self.platforms = platforms self.compiler_options = compiler_options self.events = [] self.functions = [] self.properties = OrderedDict() self.types = [] self.callbacks = OrderedDict() self.description = description self.deprecated = deprecated self.documentation_options = documentation_options
def __init__(self, namespace_node, nodoc=False, permissions=None, internal=False): self.namespace = namespace_node self.nodoc = nodoc self.internal = internal self.events = [] self.functions = [] self.types = [] self.callbacks = OrderedDict() self.permissions = permissions or []
def testFunctionWithPromise(self): schema = idl_schema.Load('test/idl_function_types.idl')[0] promise_function = getFunction(schema, 'promise_supporting') expected = OrderedDict([ ('parameters', []), ('returns_async', { 'name': 'callback', 'parameters': [{'name': 'x', 'type': 'integer'}] }), ('name', 'promise_supporting'), ('type', 'function') ]) self.assertEquals(expected, promise_function)
def process(self, callbacks): properties = OrderedDict() for node in self.node.children: if node.cls == 'Member': k, v = Member(node).process(callbacks) properties[k] = v result = {'id': self.node.GetName(), 'properties': properties, 'type': 'object'} if self.node.GetProperty('inline_doc'): result['inline_doc'] = True elif self.node.GetProperty('noinline_doc'): result['noinline_doc'] = True return result
def process(self, callbacks, functions_are_properties=False): properties = OrderedDict() name = self.node.GetName() if self.node.GetProperty('deprecated'): properties['deprecated'] = self.node.GetProperty('deprecated') for property_name in [ 'allowAmbiguousOptionalArguments', 'nodoc', 'nocompile', 'nodart', 'serializableFunction' ]: if self.node.GetProperty(property_name): properties[property_name] = True if self.node.GetProperty('OPTIONAL'): properties['optional'] = True for option_name, sanitizer in [ ('maxListeners', int), ('supportsFilters', lambda s: s == 'true'), ('supportsListeners', lambda s: s == 'true'), ('supportsRules', lambda s: s == 'true') ]: if self.node.GetProperty(option_name): if 'options' not in properties: properties['options'] = {} properties['options'][option_name] = sanitizer( self.node.GetProperty(option_name)) type_override = None parameter_comments = OrderedDict() for node in self.node.GetChildren(): if node.cls == 'Comment': (parent_comment, jsexterns, parameter_comments) = ProcessComment(node.GetName()) properties['description'] = parent_comment properties['jsexterns'] = jsexterns elif node.cls == 'Callspec': name, parameters, return_type, returns_async = (Callspec( node, parameter_comments).process(callbacks)) if functions_are_properties: # If functions are treated as properties (which will happen if the # interface is named Properties) then this isn't a function, it's a # property which is encoded as a function with no arguments. The # property type is the return type. This is an egregious hack in lieu # of the IDL parser supporting 'const'. assert parameters == [], ( 'Property "%s" must be no-argument functions ' 'with a non-void return type' % name) assert return_type is not None, ( 'Property "%s" must be no-argument functions ' 'with a non-void return type' % name) assert 'type' in return_type, ( 'Property return type "%s" from "%s" must specify a ' 'fundamental IDL type.' % (pprint.pformat(return_type), name)) type_override = return_type['type'] else: type_override = 'function' properties['parameters'] = parameters if return_type is not None: properties['returns'] = return_type if returns_async is not None: assert return_type is None, ( 'Function "%s" cannot support promises and also have a ' 'return value.' % name) properties['returns_async'] = returns_async properties['name'] = name if type_override is not None: properties['type'] = type_override else: properties = Typeref(self.node.GetProperty('TYPEREF'), self.node, properties).process(callbacks) value = self.node.GetProperty('value') if value is not None: # IDL always returns values as strings, so cast to their real type. properties['value'] = self.cast_from_json_type( properties['type'], value) enum_values = self.node.GetProperty('legalValues') if enum_values: # IDL always returns enum values as strings, so cast to their real type. properties['enum'] = [ self.cast_from_json_type(properties['type'], enum) for enum in enum_values ] return name, properties
def __init__(self, typeref, parent, additional_properties=OrderedDict()): self.typeref = typeref self.parent = parent self.additional_properties = additional_properties
def __init__(self, parent, name, json, namespace, is_additional_properties=False, from_json=False, from_client=False): self.name = name self.simple_name = _StripNamespace(self.name, namespace) self._unix_name = UnixName(self.name) self._unix_name_used = False self.optional = json.get('optional', False) self.functions = OrderedDict() self.has_value = False self.description = json.get('description') self.parent = parent self.from_json = from_json self.from_client = from_client self.instance_of = json.get('isInstanceOf', None) self.params = [] self.returns = None _AddProperties(self, json, namespace) if is_additional_properties: self.type_ = PropertyType.ADDITIONAL_PROPERTIES elif '$ref' in json: self.ref_type = json['$ref'] self.type_ = PropertyType.REF elif 'enum' in json and json.get('type') == 'string': # Non-string enums (as in the case of [legalValues=(1,2)]) should fall # through to the next elif. self.enum_values = [] for value in json['enum']: self.enum_values.append(value) self.type_ = PropertyType.ENUM elif 'type' in json: self.type_ = self._JsonTypeToPropertyType(json['type']) if self.type_ == PropertyType.ARRAY: self.item_type = Property(self, name + "Element", json['items'], namespace, from_json=from_json, from_client=from_client) elif self.type_ == PropertyType.OBJECT: # These members are read when this OBJECT Property is used as a Type type_ = Type(self, self.name, json, namespace) # self.properties will already have some value from |_AddProperties|. self.properties.update(type_.properties) self.functions = type_.functions elif self.type_ == PropertyType.FUNCTION: for p in json.get('parameters', []): self.params.append( Property(self, p['name'], p, namespace, from_json=from_json, from_client=from_client)) if 'returns' in json: self.returns = Property(self, 'return', json['returns'], namespace) elif 'choices' in json: if not json['choices'] or len(json['choices']) == 0: raise ParseException(self, 'Choices has no choices') self.choices = {} self.type_ = PropertyType.CHOICES self.compiled_type = self.type_ for choice_json in json['choices']: choice = Property(self, self.name, choice_json, namespace, from_json=from_json, from_client=from_client) choice.unix_name = UnixName(self.name + choice.type_.name) # The existence of any single choice is optional choice.optional = True self.choices[choice.type_] = choice elif 'value' in json: self.has_value = True self.value = json['value'] if type(self.value) == int: self.type_ = PropertyType.INTEGER self.compiled_type = self.type_ else: # TODO(kalman): support more types as necessary. raise ParseException( self, '"%s" is not a supported type' % type(self.value)) else: raise ParseException( self, 'Property has no type, $ref, choices, or value') if 'compiled_type' in json: if 'type' in json: self.compiled_type = self._JsonTypeToPropertyType( json['compiled_type']) else: raise ParseException(self, 'Property has compiled_type but no type') else: self.compiled_type = self.type_