tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

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")