GenerateDataFromWebIdls.py (5635B)
1 """ 2 This script parses mozilla-central's WebIDL bindings and writes a JSON-formatted 3 subset of the function bindings to several files: 4 - "devtools/server/actors/webconsole/webidl-pure-allowlist.js" (for eager evaluation processing) 5 - "devtools/server/actors/webconsole/webidl-unsafe-getters-names.js" (for preventing automatically call getters that could emit warnings) 6 7 Run this script via 8 9 > ./mach python devtools/shared/webconsole/GenerateDataFromWebIdls.py 10 11 with a mozconfig that references a built non-artifact build. 12 """ 13 14 from os import path, remove, system 15 import json 16 import WebIDL 17 import buildconfig 18 19 # This is an explicit list of interfaces to load [Pure] and [Constant] 20 # annotation for. There are a bunch of things that are pure in other interfaces 21 # that we don't care about in the context of the devtools. 22 PURE_INTERFACE_ALLOWLIST = set( 23 [ 24 "Document", 25 "Node", 26 "DOMTokenList", 27 "Element", 28 "Performance", 29 "URLSearchParams", 30 "FormData", 31 "Headers", 32 ] 33 ) 34 35 # This is an explicit list of interfaces to exclude. 36 DEPRECATED_INTERFACE__EXCLUDE_LIST = set( 37 [ 38 "External", 39 "TestExampleInterface", 40 "TestInterface", 41 "TestJSImplInterface", 42 "TestingDeprecatedInterface", 43 ] 44 ) 45 46 FILE_TEMPLATE = """\ 47 /* This Source Code Form is subject to the terms of the Mozilla Public 48 * License, v. 2.0. If a copy of the MPL was not distributed with this 49 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 50 51 // This file is automatically generated by the GenerateDataFromWebIdls.py 52 // script. Do not modify it manually. 53 "use strict"; 54 55 module.exports = %(data)s; 56 """ 57 58 pure_output_file = path.join( 59 buildconfig.topsrcdir, "devtools/server/actors/webconsole/webidl-pure-allowlist.js" 60 ) 61 unsafe_getters_names_file = path.join( 62 buildconfig.topsrcdir, 63 "devtools/server/actors/webconsole/webidl-unsafe-getters-names.js", 64 ) 65 66 input_file = path.join(buildconfig.topobjdir, "dom/bindings/file-lists.json") 67 68 if not path.isfile(input_file): 69 raise Exception( 70 "Script must be run with a mozconfig referencing a non-artifact OBJDIR" 71 ) 72 73 file_list = json.load(open(input_file)) 74 75 parser = WebIDL.Parser() 76 for filepath in file_list["webidls"]: 77 with open(filepath, "r", encoding="utf8") as f: 78 parser.parse(f.read(), filepath) 79 results = parser.finish() 80 81 # TODO: Bug 1616013 - Move more of these to be part of the pure list. 82 pure_output = { 83 "Document": { 84 "prototype": [ 85 "getSelection", 86 "hasStorageAccess", 87 ], 88 }, 89 "Range": { 90 "prototype": [ 91 "isPointInRange", 92 "comparePoint", 93 "intersectsNode", 94 # These two functions aren't pure because they do trigger 95 # layout when they are called, but in the context of eager 96 # evaluation, that should be a totally fine thing to do. 97 "getClientRects", 98 "getBoundingClientRect", 99 ], 100 }, 101 "Selection": { 102 "prototype": ["getRangeAt", "containsNode"], 103 }, 104 } 105 unsafe_getters_names = [] 106 for result in results: 107 if isinstance(result, WebIDL.IDLInterface): 108 iface = result.identifier.name 109 110 is_global = result.getExtendedAttribute("Global") 111 112 for member in result.members: 113 name = member.identifier.name 114 115 if member.isMethod() and member.affects == "Nothing": 116 if ( 117 PURE_INTERFACE_ALLOWLIST and not iface in PURE_INTERFACE_ALLOWLIST 118 ) or name.startswith("_"): 119 continue 120 121 if is_global: 122 raise Exception( 123 "Global methods and accessors are not supported: " + iface 124 ) 125 126 if iface not in pure_output: 127 pure_output[iface] = {} 128 129 if member.isStatic(): 130 owner_type = "static" 131 else: 132 owner_type = "prototype" 133 134 if owner_type not in pure_output[iface]: 135 pure_output[iface][owner_type] = [] 136 137 # All DOM getters are considered eagerly-evaluate-able. 138 # Collect methods only. 139 # 140 # NOTE: We still need to calculate unsafe_getters_names for 141 # object preview. 142 if member.isMethod(): 143 pure_output[iface][owner_type].append(name) 144 145 if ( 146 not iface in DEPRECATED_INTERFACE__EXCLUDE_LIST 147 and not name in unsafe_getters_names 148 and member.isAttr() 149 and ( 150 member.getExtendedAttribute("Deprecated") 151 or member.getExtendedAttribute("LegacyLenientThis") 152 ) 153 ): 154 unsafe_getters_names.append(name) 155 156 157 with open(pure_output_file, "w") as f: 158 f.write(FILE_TEMPLATE % {"data": json.dumps(pure_output, indent=2, sort_keys=True)}) 159 print("Successfully generated", pure_output_file) 160 161 unsafe_getters_names.sort() 162 with open(unsafe_getters_names_file, "w") as f: 163 f.write( 164 FILE_TEMPLATE 165 % {"data": json.dumps(unsafe_getters_names, indent=2, sort_keys=True)} 166 ) 167 print("Successfully generated", unsafe_getters_names_file) 168 169 print("Formatting files...") 170 system("./mach eslint --fix " + pure_output_file + " " + unsafe_getters_names_file) 171 print("Files are now properly formatted") 172 173 # Parsing the idls generate a parser.out file that we don't have any use of. 174 if path.exists("parser.out"): 175 remove("parser.out") 176 print("DONE")