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'))
Example #3
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
Example #4
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_
Example #5
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
Example #6
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
Example #7
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
Example #8
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
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)
Example #10
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
Example #11
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)
Example #12
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
Example #13
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 []
Example #14
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
Example #15
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)
 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
class Namespace(object):
  '''
  Given an IDLNode representing an IDL namespace, converts into a Python
  dictionary that the JSON schema compiler expects to see.
  '''

  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 process(self):
    for node in self.namespace.GetChildren():
      if node.cls == 'Dictionary':
        self.types.append(Dictionary(node).process(self.callbacks))
      elif node.cls == 'Callback':
        k, v = Member(node).process(self.callbacks)
        self.callbacks[k] = v
      elif node.cls == 'Interface' and node.GetName() == 'Functions':
        self.functions = self.process_interface(node)
      elif node.cls == 'Interface' and node.GetName() == 'Events':
        self.events = self.process_interface(node)
      elif node.cls == 'Interface' and node.GetName() == 'Properties':
        properties_as_list = self.process_interface(
            node, functions_are_properties=True)
        for prop in properties_as_list:
          # Properties are given as key-value pairs, but IDL will parse
          # it as a list. Convert back to key-value pairs.
          prop_name = prop.pop('name')
          assert not self.properties.has_key(prop_name), (
                 'Property "%s" cannot be specified more than once.' %
                 prop_name)
          self.properties[prop_name] = prop
      elif node.cls == 'Enum':
        self.types.append(Enum(node).process())
      else:
        sys.exit('Did not process %s %s' % (node.cls, node))
    compiler_options = self.compiler_options or {}
    documentation_options = self.documentation_options or {}
    return {'namespace': self.namespace.GetName(),
            'description': self.description,
            'nodoc': self.nodoc,
            'types': self.types,
            'functions': self.functions,
            'properties': self.properties,
            'internal': self.internal,
            'events': self.events,
            'platforms': self.platforms,
            'compiler_options': compiler_options,
            'deprecated': self.deprecated,
            'documentation_options': documentation_options}

  def process_interface(self, node, functions_are_properties=False):
    members = []
    for member in node.GetChildren():
      if member.cls == 'Member':
        _, properties = Member(member).process(
            self.callbacks,
            functions_are_properties=functions_are_properties)
        members.append(properties)
    return members
Example #18
0
 def __init__(self, typeref, parent, additional_properties=OrderedDict()):
   self.typeref = typeref
   self.parent = parent
   self.additional_properties = additional_properties
Example #19
0
class Namespace(object):
  '''
  Given an IDLNode representing an IDL namespace, converts into a Python
  dictionary that the JSON schema compiler expects to see.
  '''

  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 process(self):
    for node in self.namespace.GetChildren():
      if node.cls == 'Dictionary':
        self.types.append(Dictionary(node).process(self.callbacks))
      elif node.cls == 'Callback':
        k, v = Member(node).process(self.callbacks)
        self.callbacks[k] = v
      elif node.cls == 'Interface' and node.GetName() == 'Functions':
        self.functions = self.process_interface(node)
      elif node.cls == 'Interface' and node.GetName() == 'Events':
        self.events = self.process_interface(node)
      elif node.cls == 'Interface' and node.GetName() == 'Properties':
        properties_as_list = self.process_interface(
            node, functions_are_properties=True)
        for prop in properties_as_list:
          # Properties are given as key-value pairs, but IDL will parse
          # it as a list. Convert back to key-value pairs.
          prop_name = prop.pop('name')
          assert not self.properties.has_key(prop_name), (
                 'Property "%s" cannot be specified more than once.' %
                 prop_name)
          self.properties[prop_name] = prop
      elif node.cls == 'Enum':
        self.types.append(Enum(node).process())
      else:
        sys.exit('Did not process %s %s' % (node.cls, node))
    compiler_options = self.compiler_options or {}
    documentation_options = self.documentation_options or {}
    return {'namespace': self.namespace.GetName(),
            'description': self.description,
            'nodoc': self.nodoc,
            'types': self.types,
            'functions': self.functions,
            'properties': self.properties,
            'internal': self.internal,
            'events': self.events,
            'platforms': self.platforms,
            'compiler_options': compiler_options,
            'deprecated': self.deprecated,
            'documentation_options': documentation_options}

  def process_interface(self, node, functions_are_properties=False):
    members = []
    for member in node.GetChildren():
      if member.cls == 'Member':
        _, properties = Member(member).process(
            self.callbacks,
            functions_are_properties=functions_are_properties)
        members.append(properties)
    return members
Example #20
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_