From 120513402d3216eb2302af40f3efc4092b00ecaa Mon Sep 17 00:00:00 2001
From: "bryeung@chromium.org"
 <bryeung@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>
Date: Thu, 10 May 2012 14:38:07 +0000
Subject: Make all extension api types fully qualified.

BUG=123073
TEST= (unit_tests --gtest_filter=ExtensionAPI) && (browser_tests --gtest_filter=ExtensionApiTest)

Review URL: https://chromiumcodereview.appspot.com/10367002

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@136296 0039d316-1c4b-4281-b951-d872f2087c98
---
 tools/json_schema_compiler/cc_generator.py         |  9 +--
 tools/json_schema_compiler/cpp_type_generator.py   | 44 ++++++--------
 .../cpp_type_generator_test.py                     | 23 ++++----
 tools/json_schema_compiler/h_generator.py          |  3 +-
 tools/json_schema_compiler/idl_schema.py           |  5 +-
 tools/json_schema_compiler/idl_schema_test.py      |  4 +-
 tools/json_schema_compiler/json_schema.py          |  6 +-
 tools/json_schema_compiler/model_test.py           | 17 +++---
 tools/json_schema_compiler/schema_util.py          | 37 ++++++++++++
 tools/json_schema_compiler/schema_util_test.py     | 67 ++++++++++++++++++++++
 tools/json_schema_compiler/test/crossref.json      |  8 +--
 .../test/dependencyTester.json                     |  4 +-
 tools/json_schema_compiler/test/windows.json       |  2 +-
 13 files changed, 164 insertions(+), 65 deletions(-)
 create mode 100644 tools/json_schema_compiler/schema_util.py
 create mode 100755 tools/json_schema_compiler/schema_util_test.py

(limited to 'tools/json_schema_compiler')

diff --git a/tools/json_schema_compiler/cc_generator.py b/tools/json_schema_compiler/cc_generator.py
index 3efad84..508e0f2 100644
--- a/tools/json_schema_compiler/cc_generator.py
+++ b/tools/json_schema_compiler/cc_generator.py
@@ -7,6 +7,7 @@ from model import PropertyType
 import any_helper
 import cpp_util
 import model
+import schema_util
 import sys
 import util_cc_helper
 
@@ -71,8 +72,8 @@ class CCGenerator(object):
         .Append()
       )
     for type_ in self._namespace.types.values():
-      (c.Concat(self._GenerateType(type_.name, type_))
-        .Append()
+      (c.Concat(self._GenerateType(
+        schema_util.StripSchemaNamespace(type_.name), type_)).Append()
       )
     if self._namespace.functions:
       (c.Append('//')
@@ -95,7 +96,7 @@ class CCGenerator(object):
   def _GenerateType(self, cpp_namespace, type_):
     """Generates the function definitions for a type.
     """
-    classname = cpp_util.Classname(type_.name)
+    classname = cpp_util.Classname(schema_util.StripSchemaNamespace(type_.name))
     c = Code()
 
     if type_.functions:
@@ -174,7 +175,7 @@ class CCGenerator(object):
 
     E.g for type "Foo", generates Foo::Populate()
     """
-    classname = cpp_util.Classname(type_.name)
+    classname = cpp_util.Classname(schema_util.StripSchemaNamespace(type_.name))
     c = Code()
     (c.Append('// static')
       .Sblock('bool %(namespace)s::Populate'
diff --git a/tools/json_schema_compiler/cpp_type_generator.py b/tools/json_schema_compiler/cpp_type_generator.py
index 5afc915..1d3ac303 100644
--- a/tools/json_schema_compiler/cpp_type_generator.py
+++ b/tools/json_schema_compiler/cpp_type_generator.py
@@ -6,6 +6,8 @@ from code import Code
 from model import PropertyType
 import any_helper
 import cpp_util
+import schema_util
+import string
 
 class CppTypeGenerator(object):
   """Manages the types of properties and provides utilities for getting the
@@ -28,12 +30,10 @@ class CppTypeGenerator(object):
     beneath the root namespace.
     """
     for type_ in namespace.types:
-      qualified_name = self._QualifyName(namespace, type_)
-      if qualified_name in self._type_namespaces:
+      if type_ in self._type_namespaces:
         raise ValueError('Type %s is declared in both %s and %s' %
-            (qualified_name, namespace.name,
-             self._type_namespaces[qualified_name].name))
-      self._type_namespaces[qualified_name] = namespace
+            (type_, namespace.name, self._type_namespaces[type_].name))
+      self._type_namespaces[type_] = namespace
     self._cpp_namespaces[namespace] = cpp_namespace
 
   def GetExpandedChoicesInParams(self, params):
@@ -125,9 +125,9 @@ class CppTypeGenerator(object):
         raise KeyError('Cannot find referenced type: %s' % prop.ref_type)
       if self._namespace != dependency_namespace:
         cpp_type = '%s::%s' % (self._cpp_namespaces[dependency_namespace],
-                               prop.ref_type)
+            schema_util.StripSchemaNamespace(prop.ref_type))
       else:
-        cpp_type = prop.ref_type
+        cpp_type = schema_util.StripSchemaNamespace(prop.ref_type)
     elif prop.type_ == PropertyType.BOOLEAN:
       cpp_type = 'bool'
     elif prop.type_ == PropertyType.INTEGER:
@@ -175,20 +175,21 @@ class CppTypeGenerator(object):
     for namespace, types in sorted(self._NamespaceTypeDependencies().items()):
       c.Append('namespace %s {' % namespace.name)
       for type_ in types:
+        type_name = schema_util.StripSchemaNamespace(type_)
         if namespace.types[type_].type_ == PropertyType.STRING:
-          c.Append('typedef std::string %s;' % type_)
+          c.Append('typedef std::string %s;' % type_name)
         elif namespace.types[type_].type_ == PropertyType.ARRAY:
           c.Append('typedef std::vector<%(item_type)s> %(name)s;')
-          c.Substitute({'name': type_, 'item_type':
+          c.Substitute({'name': type_name, 'item_type':
               self.GetType(namespace.types[type_].item_type,
                            wrap_optional=True)})
         else:
-          c.Append('struct %s;' % type_)
+          c.Append('struct %s;' % type_name)
       c.Append('}')
     c.Concat(self.GetNamespaceStart())
     for (name, type_) in self._namespace.types.items():
       if not type_.functions and type_.type_ == PropertyType.OBJECT:
-        c.Append('struct %s;' % name)
+        c.Append('struct %s;' % schema_util.StripSchemaNamespace(name))
     c.Concat(self.GetNamespaceEnd())
     return c
 
@@ -203,23 +204,13 @@ class CppTypeGenerator(object):
     return c
 
   def _ResolveTypeNamespace(self, ref_type):
-    """Resolves a type name to its enclosing namespace.
-
-    Searches for the ref_type first as an explicitly qualified name, then within
-    the enclosing namespace, then within other namespaces that the current
-    namespace depends upon.
+    """Resolves a type, which must be explicitly qualified, to its enclosing
+    namespace.
     """
     if ref_type in self._type_namespaces:
       return self._type_namespaces[ref_type]
-
-    qualified_name = self._QualifyName(self._namespace, ref_type)
-    if qualified_name in self._type_namespaces:
-      return self._type_namespaces[qualified_name]
-
-    for (type_name, namespace) in self._type_namespaces.items():
-      if type_name == self._QualifyName(namespace, ref_type):
-        return namespace
-
+    raise KeyError(('Cannot resolve type: %s.' % ref_type) +
+        'Maybe it needs a namespace prefix if it comes from another namespace?')
     return None
 
   def GetReferencedProperty(self, prop):
@@ -233,9 +224,6 @@ class CppTypeGenerator(object):
     return self._ResolveTypeNamespace(prop.ref_type).types.get(prop.ref_type,
         None)
 
-  def _QualifyName(self, namespace, name):
-    return '.'.join([namespace.name, name])
-
   def _NamespaceTypeDependencies(self):
     """Returns a dict containing a mapping of model.Namespace to the C++ type
     of type dependencies for self._namespace.
diff --git a/tools/json_schema_compiler/cpp_type_generator_test.py b/tools/json_schema_compiler/cpp_type_generator_test.py
index 708bd46..46b10a2 100755
--- a/tools/json_schema_compiler/cpp_type_generator_test.py
+++ b/tools/json_schema_compiler/cpp_type_generator_test.py
@@ -119,27 +119,27 @@ class CppTypeGeneratorTest(unittest.TestCase):
     manager = CppTypeGenerator('', self.tabs, self.tabs.unix_name)
     self.assertEquals('int',
         manager.GetType(
-        self.tabs.types['Tab'].properties['id']))
+        self.tabs.types['tabs.Tab'].properties['id']))
     self.assertEquals('std::string',
         manager.GetType(
-        self.tabs.types['Tab'].properties['status']))
+        self.tabs.types['tabs.Tab'].properties['status']))
     self.assertEquals('bool',
         manager.GetType(
-        self.tabs.types['Tab'].properties['selected']))
+        self.tabs.types['tabs.Tab'].properties['selected']))
 
   def testStringAsType(self):
     manager = CppTypeGenerator('', self.font_settings,
                                self.font_settings.unix_name)
     self.assertEquals('std::string',
         manager.GetType(
-        self.font_settings.types['ScriptCode']))
+        self.font_settings.types['fontSettings.ScriptCode']))
 
   def testArrayAsType(self):
     manager = CppTypeGenerator('', self.browser_action,
                                self.browser_action.unix_name)
     self.assertEquals('std::vector<int>',
         manager.GetType(
-        self.browser_action.types['ColorArray']))
+        self.browser_action.types['browserAction.ColorArray']))
 
   def testGetTypeArray(self):
     manager = CppTypeGenerator('', self.windows, self.windows.unix_name)
@@ -147,9 +147,8 @@ class CppTypeGeneratorTest(unittest.TestCase):
         manager.GetType(
         self.windows.functions['getAll'].callback.params[0]))
     manager = CppTypeGenerator('', self.permissions, self.permissions.unix_name)
-    self.assertEquals('std::vector<std::string>',
-        manager.GetType(
-        self.permissions.types['Permissions'].properties['origins']))
+    self.assertEquals('std::vector<std::string>', manager.GetType(
+      self.permissions.types['permissions.Permissions'].properties['origins']))
 
   def testGetTypeLocalRef(self):
     manager = CppTypeGenerator('', self.tabs, self.tabs.unix_name)
@@ -162,16 +161,16 @@ class CppTypeGeneratorTest(unittest.TestCase):
     manager.AddNamespace(self.tabs, self.tabs.unix_name)
     self.assertEquals('std::vector<linked_ptr<tabs::Tab> >',
         manager.GetType(
-        self.windows.types['Window'].properties['tabs']))
+        self.windows.types['windows.Window'].properties['tabs']))
 
   def testGetTypeNotfound(self):
-    prop = self.windows.types['Window'].properties['tabs'].item_type
+    prop = self.windows.types['windows.Window'].properties['tabs'].item_type
     prop.ref_type = 'Something'
     manager = CppTypeGenerator('', self.windows, self.windows.unix_name)
     self.assertRaises(KeyError, manager.GetType, prop)
 
   def testGetTypeNotimplemented(self):
-    prop = self.windows.types['Window'].properties['tabs'].item_type
+    prop = self.windows.types['windows.Window'].properties['tabs'].item_type
     prop.type_ = 10
     manager = CppTypeGenerator('', self.windows, self.windows.unix_name)
     self.assertRaises(NotImplementedError, manager.GetType, prop)
@@ -180,7 +179,7 @@ class CppTypeGeneratorTest(unittest.TestCase):
     manager = CppTypeGenerator('', self.permissions, self.permissions.unix_name)
     self.assertEquals('std::vector<std::string> ',
         manager.GetType(
-        self.permissions.types['Permissions'].properties['origins'],
+        self.permissions.types['permissions.Permissions'].properties['origins'],
         pad_for_generics=True))
     self.assertEquals('bool',
         manager.GetType(
diff --git a/tools/json_schema_compiler/h_generator.py b/tools/json_schema_compiler/h_generator.py
index 9ce2868..a028813 100644
--- a/tools/json_schema_compiler/h_generator.py
+++ b/tools/json_schema_compiler/h_generator.py
@@ -7,6 +7,7 @@ from model import PropertyType
 import cpp_util
 import model
 import os
+import schema_util
 
 class HGenerator(object):
   """A .h generator for a namespace.
@@ -156,7 +157,7 @@ class HGenerator(object):
   def _GenerateType(self, type_):
     """Generates a struct for a type.
     """
-    classname = cpp_util.Classname(type_.name)
+    classname = cpp_util.Classname(schema_util.StripSchemaNamespace(type_.name))
     c = Code()
 
     if type_.functions:
diff --git a/tools/json_schema_compiler/idl_schema.py b/tools/json_schema_compiler/idl_schema.py
index 087b2f4..bdaa2ca 100644
--- a/tools/json_schema_compiler/idl_schema.py
+++ b/tools/json_schema_compiler/idl_schema.py
@@ -5,8 +5,10 @@
 
 import json
 import os.path
-import sys
 import re
+import sys
+
+import schema_util
 
 # This file is a peer to json_schema.py. Each of these files understands a
 # certain format describing APIs (either JSON or IDL), reads files written
@@ -256,6 +258,7 @@ class IDLSchema(object):
           continue
       else:
         sys.exit("Did not process %s %s" % (node.cls, node))
+    schema_util.PrefixSchemasWithNamespace(namespaces)
     return namespaces
 
 def Load(filename):
diff --git a/tools/json_schema_compiler/idl_schema_test.py b/tools/json_schema_compiler/idl_schema_test.py
index d045f62..024f408 100755
--- a/tools/json_schema_compiler/idl_schema_test.py
+++ b/tools/json_schema_compiler/idl_schema_test.py
@@ -33,14 +33,14 @@ class IdlSchemaTest(unittest.TestCase):
     self.assertEquals(expected, getParams(schema, 'function5'))
 
     expected = [{'type':'function', 'name':'Callback3',
-                 'parameters':[{'name':'arg', '$ref':'MyType1'}]}]
+                 'parameters':[{'name':'arg', '$ref':'idl_basics.MyType1'}]}]
     self.assertEquals(expected, getParams(schema, 'function6'))
 
   def testCallbackWithArrayArgument(self):
     schema = self.idl_basics
     expected = [{'type':'function', 'name':'Callback4',
                  'parameters':[{'name':'arg', 'type':'array',
-                                'items':{'$ref':'MyType2'}}]}]
+                                'items':{'$ref':'idl_basics.MyType2'}}]}]
     self.assertEquals(expected, getParams(schema, 'function12'))
 
 
diff --git a/tools/json_schema_compiler/json_schema.py b/tools/json_schema_compiler/json_schema.py
index f51cece..636f837 100644
--- a/tools/json_schema_compiler/json_schema.py
+++ b/tools/json_schema_compiler/json_schema.py
@@ -10,6 +10,7 @@ import sys
 _script_path = os.path.realpath(__file__)
 sys.path.insert(0, os.path.normpath(_script_path + "/../../"))
 import json_comment_eater
+import schema_util
 
 def DeleteNocompileNodes(item):
   def HasNocompile(thing):
@@ -32,9 +33,10 @@ def DeleteNocompileNodes(item):
 
 def Load(filename):
   with open(filename, 'r') as handle:
-    return DeleteNocompileNodes(
+    schemas = DeleteNocompileNodes(
         json.loads(json_comment_eater.Nom(handle.read())))
-
+  schema_util.PrefixSchemasWithNamespace(schemas)
+  return schemas
 
 # A dictionary mapping |filename| to the object resulting from loading the JSON
 # at |filename|.
diff --git a/tools/json_schema_compiler/model_test.py b/tools/json_schema_compiler/model_test.py
index 577b3ca..0a15187 100755
--- a/tools/json_schema_compiler/model_test.py
+++ b/tools/json_schema_compiler/model_test.py
@@ -32,25 +32,26 @@ class ModelTest(unittest.TestCase):
         sorted(self.permissions.functions.keys()))
 
   def testHasTypes(self):
-    self.assertEquals(['Tab'], self.tabs.types.keys())
-    self.assertEquals(['Permissions'], self.permissions.types.keys())
-    self.assertEquals(['Window'], self.windows.types.keys())
+    self.assertEquals(['tabs.Tab'], self.tabs.types.keys())
+    self.assertEquals(['permissions.Permissions'],
+        self.permissions.types.keys())
+    self.assertEquals(['windows.Window'], self.windows.types.keys())
 
   def testHasProperties(self):
     self.assertEquals(["active", "favIconUrl", "highlighted", "id",
         "incognito", "index", "pinned", "selected", "status", "title", "url",
         "windowId"],
-        sorted(self.tabs.types['Tab'].properties.keys()))
+        sorted(self.tabs.types['tabs.Tab'].properties.keys()))
 
   def testProperties(self):
-    string_prop = self.tabs.types['Tab'].properties['status']
+    string_prop = self.tabs.types['tabs.Tab'].properties['status']
     self.assertEquals(model.PropertyType.STRING, string_prop.type_)
-    integer_prop = self.tabs.types['Tab'].properties['id']
+    integer_prop = self.tabs.types['tabs.Tab'].properties['id']
     self.assertEquals(model.PropertyType.INTEGER, integer_prop.type_)
-    array_prop = self.windows.types['Window'].properties['tabs']
+    array_prop = self.windows.types['windows.Window'].properties['tabs']
     self.assertEquals(model.PropertyType.ARRAY, array_prop.type_)
     self.assertEquals(model.PropertyType.REF, array_prop.item_type.type_)
-    self.assertEquals('Tab', array_prop.item_type.ref_type)
+    self.assertEquals('tabs.Tab', array_prop.item_type.ref_type)
     object_prop = self.tabs.functions['query'].params[0]
     self.assertEquals(model.PropertyType.OBJECT, object_prop.type_)
     self.assertEquals(
diff --git a/tools/json_schema_compiler/schema_util.py b/tools/json_schema_compiler/schema_util.py
new file mode 100644
index 0000000..289d24d
--- /dev/null
+++ b/tools/json_schema_compiler/schema_util.py
@@ -0,0 +1,37 @@
+# Copyright (c) 2012 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+"""Utilies for the processing of schema python structures.
+"""
+
+def StripSchemaNamespace(s):
+  last_dot = s.rfind('.')
+  if not last_dot == -1:
+    return s[last_dot + 1:]
+  return s
+
+def PrefixSchemasWithNamespace(schemas):
+  for s in schemas:
+    _PrefixWithNamespace(s.get("namespace"), s)
+
+def _MaybePrefixFieldWithNamespace(namespace, schema, key):
+  if type(schema) == dict and key in schema:
+    old_value = schema[key]
+    if not "." in old_value:
+      schema[key] = namespace + "." + old_value
+
+def _PrefixTypesWithNamespace(namespace, types):
+  for t in types:
+    _MaybePrefixFieldWithNamespace(namespace, t, "id")
+    _MaybePrefixFieldWithNamespace(namespace, t, "customBindings")
+
+def _PrefixWithNamespace(namespace, schema):
+  if type(schema) == dict:
+    if "types" in schema:
+      _PrefixTypesWithNamespace(namespace, schema.get("types"))
+    _MaybePrefixFieldWithNamespace(namespace, schema, "$ref")
+    for s in schema:
+      _PrefixWithNamespace(namespace, schema[s])
+  elif type(schema) == list:
+    for s in schema:
+      _PrefixWithNamespace(namespace, s)
diff --git a/tools/json_schema_compiler/schema_util_test.py b/tools/json_schema_compiler/schema_util_test.py
new file mode 100755
index 0000000..ecdd17c
--- /dev/null
+++ b/tools/json_schema_compiler/schema_util_test.py
@@ -0,0 +1,67 @@
+#!/usr/bin/env python
+# Copyright (c) 2012 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import schema_util
+import unittest
+
+class SchemaUtilTest(unittest.TestCase):
+  def testStripSchemaNamespace(self):
+    self.assertEquals('Bar', schema_util.StripSchemaNamespace('foo.Bar'))
+    self.assertEquals('Baz', schema_util.StripSchemaNamespace('Baz'))
+
+  def testPrefixSchemasWithNamespace(self):
+    schemas = [
+        { 'namespace': 'n1',
+          'types': [
+            {
+              'id': 'T1',
+              'customBindings': 'T1',
+              'properties': {
+                'p1': {'$ref': 'T1'},
+                'p2': {'$ref': 'fully.qualified.T'},
+              }
+            }
+          ],
+          'functions': [
+            {
+              'parameters': [
+                { '$ref': 'T1' },
+                { '$ref': 'fully.qualified.T' },
+              ],
+              'returns': { '$ref': 'T1' }
+            },
+          ],
+          'events': [
+            {
+              'parameters': [
+                { '$ref': 'T1' },
+                { '$ref': 'fully.qualified.T' },
+              ],
+            },
+          ],
+        },
+      ]
+    schema_util.PrefixSchemasWithNamespace(schemas)
+    self.assertEquals('n1.T1', schemas[0]['types'][0]['id'])
+    self.assertEquals('n1.T1', schemas[0]['types'][0]['customBindings'])
+    self.assertEquals('n1.T1',
+        schemas[0]['types'][0]['properties']['p1']['$ref'])
+    self.assertEquals('fully.qualified.T',
+        schemas[0]['types'][0]['properties']['p2']['$ref'])
+
+    self.assertEquals('n1.T1',
+        schemas[0]['functions'][0]['parameters'][0]['$ref'])
+    self.assertEquals('fully.qualified.T',
+        schemas[0]['functions'][0]['parameters'][1]['$ref'])
+    self.assertEquals('n1.T1',
+        schemas[0]['functions'][0]['returns']['$ref'])
+
+    self.assertEquals('n1.T1',
+        schemas[0]['events'][0]['parameters'][0]['$ref'])
+    self.assertEquals('fully.qualified.T',
+        schemas[0]['events'][0]['parameters'][1]['$ref'])
+
+if __name__ == '__main__':
+  unittest.main()
diff --git a/tools/json_schema_compiler/test/crossref.json b/tools/json_schema_compiler/test/crossref.json
index 02e5c94..9d3f905 100644
--- a/tools/json_schema_compiler/test/crossref.json
+++ b/tools/json_schema_compiler/test/crossref.json
@@ -8,7 +8,7 @@
         "type": "object",
         "properties": {
           "testType": {
-            "$ref": "TestType",
+            "$ref": "simple_api.TestType",
             "optional": true
           }
         }
@@ -22,7 +22,7 @@
         "parameters": [
           {
             "name": "testType",
-            "$ref": "TestType",
+            "$ref": "simple_api.TestType",
             "optional": true
           },
           {
@@ -43,7 +43,7 @@
             "parameters": [
               {
                 "name": "result",
-                "$ref": "TestType",
+                "$ref": "simple_api.TestType",
                 "description": "A TestType."
               }
             ]
@@ -59,7 +59,7 @@
             "name": "paramObject",
             "type": "object",
             "properties": {
-              "testType": {"$ref": "TestType", "optional": true},
+              "testType": {"$ref": "simple_api.TestType", "optional": true},
               "boolean": {"type": "boolean"}
             }
           },
diff --git a/tools/json_schema_compiler/test/dependencyTester.json b/tools/json_schema_compiler/test/dependencyTester.json
index 43b145a..aec4c15 100644
--- a/tools/json_schema_compiler/test/dependencyTester.json
+++ b/tools/json_schema_compiler/test/dependencyTester.json
@@ -18,10 +18,10 @@
             "type": "object",
             "properties": {
               "color": {
-                "$ref": "ColorArray"
+                "$ref": "browserAction.ColorArray"
               },
               "scriptCode": {
-                "$ref": "ScriptCode"
+                "$ref": "fontSettings.ScriptCode"
               }
             }
           }
diff --git a/tools/json_schema_compiler/test/windows.json b/tools/json_schema_compiler/test/windows.json
index 52fc683d..f6062d4 100644
--- a/tools/json_schema_compiler/test/windows.json
+++ b/tools/json_schema_compiler/test/windows.json
@@ -12,7 +12,7 @@
           "left": {"type": "integer", "description": "The offset of the window from the left edge of the screen in pixels."},
           "width": {"type": "integer", "description": "The width of the window in pixels."},
           "height": {"type": "integer", "description": "The height of the window in pixels."},
-          "tabs": {"type": "array", "items": { "$ref": "Tab" }, "optional": true, "description": "Array of $ref:Tab objects representing the current tabs in the window."},
+          "tabs": {"type": "array", "items": { "$ref": "tabs.Tab" }, "optional": true, "description": "Array of $ref:Tab objects representing the current tabs in the window."},
           "incognito": {"type": "boolean", "description": "Whether the window is incognito."},
           "type": {
             "type": "string",
-- 
cgit v1.1