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'))
Exemple #4
0
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
Exemple #6
0
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_
Exemple #7
0
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
Exemple #8
0
 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
Exemple #10
0
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
Exemple #11
0
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
Exemple #12
0
 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
Exemple #13
0
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)
Exemple #15
0
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
Exemple #16
0
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)
Exemple #17
0
 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
Exemple #18
0
 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 []
Exemple #19
0
  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)
Exemple #20
0
 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
Exemple #21
0
    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
Exemple #22
0
 def __init__(self, typeref, parent, additional_properties=OrderedDict()):
   self.typeref = typeref
   self.parent = parent
   self.additional_properties = additional_properties
Exemple #23
0
 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_