Web Inspector: expose Audit and Recording versions to the frontend
[WebKit-https.git] / Source / JavaScriptCore / inspector / scripts / codegen / models.py
1 #!/usr/bin/env python
2 #
3 # Copyright (c) 2014 Apple Inc. All rights reserved.
4 # Copyright (c) 2014 University of Washington. All rights reserved.
5 #
6 # Redistribution and use in source and binary forms, with or without
7 # modification, are permitted provided that the following conditions
8 # are met:
9 # 1. Redistributions of source code must retain the above copyright
10 #    notice, this list of conditions and the following disclaimer.
11 # 2. Redistributions in binary form must reproduce the above copyright
12 #    notice, this list of conditions and the following disclaimer in the
13 #    documentation and/or other materials provided with the distribution.
14 #
15 # THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
16 # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
17 # THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
18 # PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
19 # BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
20 # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
21 # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22 # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
23 # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
24 # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
25 # THE POSSIBILITY OF SUCH DAMAGE.
26
27 import logging
28 import collections
29
30 log = logging.getLogger('global')
31
32
33 def ucfirst(str):
34     return str[:1].upper() + str[1:]
35
36
37 def find_duplicates(l):
38     return [key for key, count in list(collections.Counter(l).items()) if count > 1]
39
40
41 _FRAMEWORK_CONFIG_MAP = {
42     "Global": {
43     },
44     "JavaScriptCore": {
45         "cpp_protocol_group": "Inspector",
46         "export_macro": "JS_EXPORT_PRIVATE",
47         "alternate_dispatchers": True,
48     },
49     "WebKit": {
50         "cpp_protocol_group": "Automation",
51         "objc_protocol_group": "WD",
52         "objc_prefix": "WD",
53     },
54     "WebInspector": {
55         "objc_protocol_group": "RWI",
56         "objc_prefix": "RWI",
57     },
58     "WebInspectorUI": {
59     },
60     # Used for code generator tests.
61     "Test": {
62         "alternate_dispatchers": True,
63         "cpp_protocol_group": "Test",
64         "objc_protocol_group": "Test",
65         "objc_prefix": "Test",
66     }
67 }
68
69
70 class ParseException(Exception):
71     pass
72
73
74 class TypecheckException(Exception):
75     pass
76
77
78 class Framework:
79     def __init__(self, name):
80         self._settings = _FRAMEWORK_CONFIG_MAP[name]
81         self.name = name
82
83     def setting(self, key, default=''):
84         return self._settings.get(key, default)
85
86     @staticmethod
87     def fromString(frameworkString):
88         if frameworkString == "Global":
89             return Frameworks.Global
90
91         if frameworkString == "JavaScriptCore":
92             return Frameworks.JavaScriptCore
93
94         if frameworkString == "WebKit":
95             return Frameworks.WebKit
96
97         if frameworkString == "WebInspector":
98             return Frameworks.WebInspector
99
100         if frameworkString == "WebInspectorUI":
101             return Frameworks.WebInspectorUI
102
103         if frameworkString == "Test":
104             return Frameworks.Test
105
106         raise ParseException("Unknown framework: %s" % frameworkString)
107
108
109 class Frameworks:
110     Global = Framework("Global")
111     JavaScriptCore = Framework("JavaScriptCore")
112     WebKit = Framework("WebKit")
113     WebInspector = Framework("WebInspector")
114     WebInspectorUI = Framework("WebInspectorUI")
115     Test = Framework("Test")
116
117
118 class Platform:
119     def __init__(self, name):
120         self.name = name
121
122     @staticmethod
123     def fromString(platformString):
124         platformString = platformString.lower()
125         if platformString == "ios":
126             return Platforms.iOS
127
128         if platformString == "macos":
129             return Platforms.macOS
130
131         if platformString == "all":
132             return Platforms.All
133
134         if platformString == "generic" or not platformString:
135             return Platforms.Generic
136
137         raise ParseException("Unknown platform: %s" % platformString)
138
139
140 class Platforms:
141     All = Platform("all")
142     Generic = Platform("generic")
143     iOS = Platform("ios")
144     macOS = Platform("macos")
145
146     # Allow iteration over all platforms. See <http://stackoverflow.com/questions/5434400/>.
147     class __metaclass__(type):
148         def __iter__(self):
149             for attr in dir(Platforms):
150                 if not attr.startswith("__"):
151                     yield getattr(Platforms, attr)
152
153 class TypeReference:
154     def __init__(self, type_kind, referenced_type_name, enum_values, array_items):
155         self.type_kind = type_kind
156         self.referenced_type_name = referenced_type_name
157         self.enum_values = enum_values
158         if array_items is None:
159             self.array_type_ref = None
160         else:
161             self.array_type_ref = TypeReference(array_items.get('type'), array_items.get('$ref'), array_items.get('enum'), array_items.get('items'))
162
163         if type_kind is not None and referenced_type_name is not None:
164             raise ParseException("Type reference cannot have both 'type' and '$ref' keys.")
165
166         all_primitive_types = ["integer", "number", "string", "boolean", "enum", "object", "array", "any"]
167         if type_kind is not None and type_kind not in all_primitive_types:
168             raise ParseException("Type reference '%s' is not a primitive type. Allowed values: %s" % (type_kind, ', '.join(all_primitive_types)))
169
170         if type_kind == "array" and array_items is None:
171             raise ParseException("Type reference with type 'array' must have key 'items' to define array element type.")
172
173         if enum_values is not None and len(enum_values) == 0:
174             raise ParseException("Type reference with enum values must have at least one enum value.")
175
176     def referenced_name(self):
177         if self.referenced_type_name is not None:
178             return self.referenced_type_name
179         else:
180             return self.type_kind  # one of all_primitive_types
181
182
183 class Type:
184     def __init__(self):
185         pass
186
187     def __eq__(self, other):
188         return self.qualified_name() == other.qualified_name()
189
190     def __hash__(self):
191         return self.qualified_name().__hash__()
192
193     def raw_name(self):
194         return self._name
195
196     # These methods should be overridden by subclasses.
197     def is_enum(self):
198         return False
199
200     def type_domain(self):
201         pass
202
203     def qualified_name(self):
204         pass
205
206     # This is used to resolve nested types after instances are created.
207     def resolve_type_references(self, protocol):
208         pass
209
210
211 class PrimitiveType(Type):
212     def __init__(self, name):
213         self._name = name
214
215     def __repr__(self):
216         return 'PrimitiveType[%s]' % self.qualified_name()
217
218     def type_domain(self):
219         return None
220
221     def qualified_name(self):
222         return self.raw_name()
223
224
225 class AliasedType(Type):
226     def __init__(self, declaration, domain, aliased_type_ref):
227         self._name = declaration.type_name
228         self._declaration = declaration
229         self._domain = domain
230         self._aliased_type_ref = aliased_type_ref
231         self.aliased_type = None
232
233     def __repr__(self):
234         if self.aliased_type is not None:
235             return 'AliasedType[%s -> %r]' % (self.qualified_name(), self.aliased_type)
236         else:
237             return 'AliasedType[%s -> (unresolved)]' % self.qualified_name()
238
239     def is_enum(self):
240         return self.aliased_type.is_enum()
241
242     def type_domain(self):
243         return self._domain
244
245     def qualified_name(self):
246         return  ".".join([self.type_domain().domain_name, self.raw_name()])
247
248     def resolve_type_references(self, protocol):
249         if self.aliased_type is not None:
250             return
251
252         self.aliased_type = protocol.lookup_type_reference(self._aliased_type_ref, self.type_domain())
253         log.debug("< Resolved type reference for aliased type in %s: %s" % (self.qualified_name(), self.aliased_type.qualified_name()))
254
255
256 class EnumType(Type):
257     def __init__(self, declaration, domain, values, primitive_type_ref, is_anonymous=False):
258         self._name = "(anonymous)" if declaration is None else declaration.type_name
259         self._declaration = declaration
260         self._domain = domain
261         self._values = values
262         self._primitive_type_ref = primitive_type_ref
263         self.primitive_type = None
264         self.is_anonymous = is_anonymous
265
266     def __repr__(self):
267         return 'EnumType[primitive_type=%s; enum_values=%s]' % (self.qualified_name(), ', '.join(map(str, self.enum_values())))
268
269     def is_enum(self):
270         return True
271
272     def enum_values(self):
273         return self._values
274
275     def type_domain(self):
276         return self._domain
277
278     def declaration(self):
279         return self._declaration
280
281     def qualified_name(self):
282         return  ".".join([self.type_domain().domain_name, self.raw_name()])
283
284     def resolve_type_references(self, protocol):
285         if self.primitive_type is not None:
286             return
287
288         self.primitive_type = protocol.lookup_type_reference(self._primitive_type_ref, Domains.GLOBAL)
289         log.debug("< Resolved type reference for enum type in %s: %s" % (self.qualified_name(), self.primitive_type.qualified_name()))
290         log.debug("<< enum values: %s" % self.enum_values())
291
292
293 class ArrayType(Type):
294     def __init__(self, declaration, element_type_ref, domain):
295         self._name = None if declaration is None else declaration.type_name
296         self._declaration = declaration
297         self._domain = domain
298         self._element_type_ref = element_type_ref
299         self.element_type = None
300
301     def __repr__(self):
302         if self.element_type is not None:
303             return 'ArrayType[element_type=%r]' % self.element_type
304         else:
305             return 'ArrayType[element_type=(unresolved)]'
306
307     def declaration(self):
308         return self._declaration
309
310     def type_domain(self):
311         return self._domain
312
313     def qualified_name(self):
314         return  ".".join(["array", self.element_type.qualified_name()])
315
316     def resolve_type_references(self, protocol):
317         if self.element_type is not None:
318             return
319
320         self.element_type = protocol.lookup_type_reference(self._element_type_ref, self.type_domain())
321         log.debug("< Resolved type reference for element type in %s: %s" % (self.qualified_name(), self.element_type.qualified_name()))
322
323
324 class ObjectType(Type):
325     def __init__(self, declaration, domain):
326         self._name = declaration.type_name
327         self._declaration = declaration
328         self._domain = domain
329         self.members = declaration.type_members
330
331     def __repr__(self):
332         return 'ObjectType[%s]' % self.qualified_name()
333
334     def declaration(self):
335         return self._declaration
336
337     def type_domain(self):
338         return self._domain
339
340     def qualified_name(self):
341         return  ".".join([self.type_domain().domain_name, self.raw_name()])
342
343
344 def check_for_required_properties(props, obj, what):
345     for prop in props:
346         if prop not in obj:
347             raise ParseException("When parsing %s, required property missing: %s" % (what, prop))
348
349
350 class Protocol:
351     def __init__(self, framework_name):
352         self.domains = []
353         self.types_by_name = {}
354         self.framework = Framework.fromString(framework_name)
355
356     def parse_specification(self, json, isSupplemental):
357         log.debug("parse toplevel")
358
359         if isinstance(json, dict) and 'domains' in json:
360             json = json['domains']
361         if not isinstance(json, list):
362             json = [json]
363
364         for domain in json:
365             self.parse_domain(domain, isSupplemental)
366
367     def parse_domain(self, json, isSupplemental):
368         check_for_required_properties(['domain'], json, "domain")
369         log.debug("parse domain " + json['domain'])
370
371         version = None
372         types = []
373         commands = []
374         events = []
375
376         if 'version' in json:
377             if not isinstance(json['version'], int):
378                 raise ParseException("Malformed domain specification: version is not a number or string")
379             version = json['version']
380
381         if 'types' in json:
382             if not isinstance(json['types'], list):
383                 raise ParseException("Malformed domain specification: types is not an array")
384             types.extend([self.parse_type_declaration(declaration) for declaration in json['types']])
385
386         if 'commands' in json:
387             if not isinstance(json['commands'], list):
388                 raise ParseException("Malformed domain specification: commands is not an array")
389             commands.extend([self.parse_command(command) for command in json['commands']])
390
391         if 'events' in json:
392             if not isinstance(json['events'], list):
393                 raise ParseException("Malformed domain specification: events is not an array")
394             events.extend([self.parse_event(event) for event in json['events']])
395
396         if 'availability' in json:
397             if not isinstance(json['availability'], list):
398                 raise ParseException("Malformed domain specification: availability is not an array")
399             allowed_activation_strings = set(['javascript', 'web', 'worker', 'service-worker'])
400             for availability_type in json['availability']:
401                 if availability_type not in allowed_activation_strings:
402                     raise ParseException('Malformed domain specification: availability is an unsupported string. Was: "%s", Allowed values: %s' % (json['availability'], ', '.join(allowed_activation_strings)))
403
404         self.domains.append(Domain(json['domain'], json.get('description', ''), json.get('featureGuard'), json.get('availability'), isSupplemental, version, types, commands, events))
405
406     def parse_type_declaration(self, json):
407         check_for_required_properties(['id', 'type'], json, "type")
408         log.debug("parse type %s" % json['id'])
409
410         type_members = []
411
412         if 'properties' in json:
413             if not isinstance(json['properties'], list):
414                 raise ParseException("Malformed type specification: properties is not an array")
415             type_members.extend([self.parse_type_member(member) for member in json['properties']])
416
417         duplicate_names = find_duplicates([member.member_name for member in type_members])
418         if len(duplicate_names) > 0:
419             raise ParseException("Malformed domain specification: type declaration for %s has duplicate member names" % json['id'])
420
421         type_ref = TypeReference(json['type'], json.get('$ref'), json.get('enum'), json.get('items'))
422         platform = Platform.fromString(json.get('platform', 'generic'))
423         return TypeDeclaration(json['id'], type_ref, json.get("description", ""), platform, type_members)
424
425     def parse_type_member(self, json):
426         check_for_required_properties(['name'], json, "type member")
427         log.debug("parse type member %s" % json['name'])
428
429         type_ref = TypeReference(json.get('type'), json.get('$ref'), json.get('enum'), json.get('items'))
430         return TypeMember(json['name'], type_ref, json.get('optional', False), json.get('description', ""))
431
432     def parse_command(self, json):
433         check_for_required_properties(['name'], json, "command")
434         log.debug("parse command %s" % json['name'])
435
436         call_parameters = []
437         return_parameters = []
438
439         if 'parameters' in json:
440             if not isinstance(json['parameters'], list):
441                 raise ParseException("Malformed command specification: parameters is not an array")
442             call_parameters.extend([self.parse_call_or_return_parameter(parameter) for parameter in json['parameters']])
443
444             duplicate_names = find_duplicates([param.parameter_name for param in call_parameters])
445             if len(duplicate_names) > 0:
446                 raise ParseException("Malformed domain specification: call parameter list for command %s has duplicate parameter names" % json['name'])
447
448         if 'returns' in json:
449             if not isinstance(json['returns'], list):
450                 raise ParseException("Malformed command specification: returns is not an array")
451             return_parameters.extend([self.parse_call_or_return_parameter(parameter) for parameter in json['returns']])
452
453             duplicate_names = find_duplicates([param.parameter_name for param in return_parameters])
454             if len(duplicate_names) > 0:
455                 raise ParseException("Malformed domain specification: return parameter list for command %s has duplicate parameter names" % json['name'])
456
457         platform = Platform.fromString(json.get('platform', 'generic'))
458         return Command(json['name'], call_parameters, return_parameters, json.get('description', ""), platform, json.get('async', False))
459
460     def parse_event(self, json):
461         check_for_required_properties(['name'], json, "event")
462         log.debug("parse event %s" % json['name'])
463
464         event_parameters = []
465
466         if 'parameters' in json:
467             if not isinstance(json['parameters'], list):
468                 raise ParseException("Malformed event specification: parameters is not an array")
469             event_parameters.extend([self.parse_call_or_return_parameter(parameter) for parameter in json['parameters']])
470
471             duplicate_names = find_duplicates([param.parameter_name for param in event_parameters])
472             if len(duplicate_names) > 0:
473                 raise ParseException("Malformed domain specification: parameter list for event %s has duplicate parameter names" % json['name'])
474
475         platform = Platform.fromString(json.get('platform', 'generic'))
476         return Event(json['name'], event_parameters, json.get('description', ""), platform)
477
478     def parse_call_or_return_parameter(self, json):
479         check_for_required_properties(['name'], json, "parameter")
480         log.debug("parse parameter %s" % json['name'])
481
482         type_ref = TypeReference(json.get('type'), json.get('$ref'), json.get('enum'), json.get('items'))
483         return Parameter(json['name'], type_ref, json.get('optional', False), json.get('description', ""))
484
485     def resolve_types(self):
486         qualified_declared_type_names = set(['boolean', 'string', 'integer', 'number', 'enum', 'array', 'object', 'any'])
487
488         self.types_by_name['string'] = PrimitiveType('string')
489         for _primitive_type in ['boolean', 'integer', 'number']:
490             self.types_by_name[_primitive_type] = PrimitiveType(_primitive_type)
491         for _object_type in ['any', 'object']:
492             self.types_by_name[_object_type] = PrimitiveType(_object_type)
493
494         # Gather qualified type names from type declarations in each domain.
495         for domain in self.domains:
496             for declaration in domain.all_type_declarations():
497                 # Basic sanity checking.
498                 if declaration.type_ref.referenced_type_name is not None:
499                     raise TypecheckException("Type declarations must name a base type, not a type reference.")
500
501                 # Find duplicate qualified type names.
502                 qualified_type_name = ".".join([domain.domain_name, declaration.type_name])
503                 if qualified_type_name in qualified_declared_type_names:
504                     raise TypecheckException("Duplicate type declaration: %s" % qualified_type_name)
505
506                 qualified_declared_type_names.add(qualified_type_name)
507
508                 type_instance = None
509
510                 kind = declaration.type_ref.type_kind
511                 if declaration.type_ref.enum_values is not None:
512                     primitive_type_ref = TypeReference(declaration.type_ref.type_kind, None, None, None)
513                     type_instance = EnumType(declaration, domain, declaration.type_ref.enum_values, primitive_type_ref)
514                 elif kind == "array":
515                     type_instance = ArrayType(declaration, declaration.type_ref.array_type_ref, domain)
516                 elif kind == "object":
517                     type_instance = ObjectType(declaration, domain)
518                 else:
519                     type_instance = AliasedType(declaration, domain, declaration.type_ref)
520
521                 log.debug("< Created fresh type %r for declaration %s" % (type_instance, qualified_type_name))
522                 self.types_by_name[qualified_type_name] = type_instance
523
524         # Resolve all type references recursively.
525         for domain in self.domains:
526             domain.resolve_type_references(self)
527
528     def lookup_type_for_declaration(self, declaration, domain):
529         # This will only match a type defined in the same domain, where prefixes aren't required.
530         qualified_name = ".".join([domain.domain_name, declaration.type_name])
531         if qualified_name in self.types_by_name:
532             found_type = self.types_by_name[qualified_name]
533             found_type.resolve_type_references(self)
534             return found_type
535
536         raise TypecheckException("Lookup failed for type declaration: %s (referenced from domain: %s)" % (declaration.type_name, domain.domain_name))
537
538     def lookup_type_reference(self, type_ref, domain):
539         # If reference is to an anonymous array type, create a fresh instance.
540         if type_ref.type_kind == "array":
541             type_instance = ArrayType(None, type_ref.array_type_ref, domain)
542             type_instance.resolve_type_references(self)
543             log.debug("< Created fresh type instance for anonymous array type: %s" % type_instance.qualified_name())
544             return type_instance
545
546         # If reference is to an anonymous enum type, create a fresh instance.
547         if type_ref.enum_values is not None:
548             # We need to create a type reference without enum values as the enum's nested type.
549             primitive_type_ref = TypeReference(type_ref.type_kind, None, None, None)
550             type_instance = EnumType(None, domain, type_ref.enum_values, primitive_type_ref, True)
551             type_instance.resolve_type_references(self)
552             log.debug("< Created fresh type instance for anonymous enum type: %s" % type_instance.qualified_name())
553             return type_instance
554
555         # This will match when referencing a type defined in the same domain, where prefixes aren't required.
556         qualified_name = ".".join([domain.domain_name, type_ref.referenced_name()])
557         if qualified_name in self.types_by_name:
558             found_type = self.types_by_name[qualified_name]
559             found_type.resolve_type_references(self)
560             log.debug("< Lookup succeeded for unqualified type: %s" % found_type.qualified_name())
561             return found_type
562
563         # This will match primitive types and fully-qualified types from a different domain.
564         if type_ref.referenced_name() in self.types_by_name:
565             found_type = self.types_by_name[type_ref.referenced_name()]
566             found_type.resolve_type_references(self)
567             log.debug("< Lookup succeeded for primitive or qualified type: %s" % found_type.qualified_name())
568             return found_type
569
570         raise TypecheckException("Lookup failed for type reference: %s (referenced from domain: %s)" % (type_ref.referenced_name(), domain.domain_name))
571
572
573 class Domain:
574     def __init__(self, domain_name, description, feature_guard, availability, isSupplemental, version, type_declarations, commands, events):
575         self.domain_name = domain_name
576         self.description = description
577         self.feature_guard = feature_guard
578         self.availability = availability
579         self.is_supplemental = isSupplemental
580         self._version = version
581         self._type_declarations = type_declarations
582         self._commands = commands
583         self._events = events
584
585     def version(self):
586         return self._version
587
588     def all_type_declarations(self):
589         return self._type_declarations
590
591     def all_commands(self):
592         return self._commands
593
594     def all_events(self):
595         return self._events
596
597     def resolve_type_references(self, protocol):
598         log.debug("> Resolving type declarations for domain: %s" % self.domain_name)
599         for declaration in self._type_declarations:
600             declaration.resolve_type_references(protocol, self)
601
602         log.debug("> Resolving types in commands for domain: %s" % self.domain_name)
603         for command in self._commands:
604             command.resolve_type_references(protocol, self)
605
606         log.debug("> Resolving types in events for domain: %s" % self.domain_name)
607         for event in self._events:
608             event.resolve_type_references(protocol, self)
609
610
611 class Domains:
612     GLOBAL = Domain("", "The global domain, in which primitive types are implicitly declared.", None, None, False, None, [], [], [])
613
614
615 class TypeDeclaration:
616     def __init__(self, type_name, type_ref, description, platform, type_members):
617         self.type_name = type_name
618         self.type_ref = type_ref
619         self.description = description
620         self.platform = platform
621         self.type_members = type_members
622
623         if self.type_name != ucfirst(self.type_name):
624             raise ParseException("Types must begin with an uppercase character.")
625
626     def resolve_type_references(self, protocol, domain):
627         log.debug(">> Resolving type references for type declaration: %s" % self.type_name)
628         self.type = protocol.lookup_type_for_declaration(self, domain)
629         for member in self.type_members:
630             member.resolve_type_references(protocol, domain)
631
632
633 class TypeMember:
634     def __init__(self, member_name, type_ref, is_optional, description):
635         self.member_name = member_name
636         self.type_ref = type_ref
637         self.is_optional = is_optional
638         self.description = description
639
640         if not isinstance(self.is_optional, bool):
641             raise ParseException("The 'optional' flag for a type member must be a boolean literal.")
642
643     def resolve_type_references(self, protocol, domain):
644         log.debug(">>> Resolving type references for type member: %s" % self.member_name)
645         self.type = protocol.lookup_type_reference(self.type_ref, domain)
646
647
648 class Parameter:
649     def __init__(self, parameter_name, type_ref, is_optional, description):
650         self.parameter_name = parameter_name
651         self.type_ref = type_ref
652         self.is_optional = is_optional
653         self.description = description
654
655         if not isinstance(self.is_optional, bool):
656             raise ParseException("The 'optional' flag for a parameter must be a boolean literal.")
657
658     def resolve_type_references(self, protocol, domain):
659         log.debug(">>> Resolving type references for parameter: %s" % self.parameter_name)
660         self.type = protocol.lookup_type_reference(self.type_ref, domain)
661
662
663 class Command:
664     def __init__(self, command_name, call_parameters, return_parameters, description, platform, is_async):
665         self.command_name = command_name
666         self.call_parameters = call_parameters
667         self.return_parameters = return_parameters
668         self.description = description
669         self.platform = platform
670         self.is_async = is_async
671
672     def resolve_type_references(self, protocol, domain):
673         log.debug(">> Resolving type references for call parameters in command: %s" % self.command_name)
674         for parameter in self.call_parameters:
675             parameter.resolve_type_references(protocol, domain)
676
677         log.debug(">> Resolving type references for return parameters in command: %s" % self.command_name)
678         for parameter in self.return_parameters:
679             parameter.resolve_type_references(protocol, domain)
680
681
682 class Event:
683     def __init__(self, event_name, event_parameters, description, platform):
684         self.event_name = event_name
685         self.event_parameters = event_parameters
686         self.description = description
687         self.platform = platform
688
689     def resolve_type_references(self, protocol, domain):
690         log.debug(">> Resolving type references for parameters in event: %s" % self.event_name)
691         for parameter in self.event_parameters:
692             parameter.resolve_type_references(protocol, domain)