Source code
Revision control
Copy as Markdown
Other Tools
"""
This script parses mozilla-central's WebIDL bindings and writes a JSON-formatted
subset of the function bindings to several files:
- "devtools/server/actors/webconsole/webidl-pure-allowlist.js" (for eager evaluation processing)
- "devtools/server/actors/webconsole/webidl-unsafe-getters-names.js" (for preventing automatically call getters that could emit warnings)
Run this script via
> ./mach python devtools/shared/webconsole/GenerateDataFromWebIdls.py
with a mozconfig that references a built non-artifact build.
"""
from os import path, remove, system
import json
import WebIDL
import buildconfig
# This is an explicit list of interfaces to load [Pure] and [Constant]
# annotation for. There are a bunch of things that are pure in other interfaces
# that we don't care about in the context of the devtools.
PURE_INTERFACE_ALLOWLIST = set(
[
"Document",
"Node",
"DOMTokenList",
"Element",
"Performance",
"URLSearchParams",
"FormData",
"Headers",
]
)
# This is an explicit list of interfaces to exclude.
DEPRECATED_INTERFACE__EXCLUDE_LIST = set(
[
"External",
"TestExampleInterface",
"TestInterface",
"TestJSImplInterface",
"TestingDeprecatedInterface",
]
)
FILE_TEMPLATE = """\
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
// This file is automatically generated by the GenerateDataFromWebIdls.py
// script. Do not modify it manually.
"use strict";
module.exports = %(data)s;
"""
pure_output_file = path.join(
buildconfig.topsrcdir, "devtools/server/actors/webconsole/webidl-pure-allowlist.js"
)
unsafe_getters_names_file = path.join(
buildconfig.topsrcdir,
"devtools/server/actors/webconsole/webidl-unsafe-getters-names.js",
)
input_file = path.join(buildconfig.topobjdir, "dom/bindings/file-lists.json")
if not path.isfile(input_file):
raise Exception(
"Script must be run with a mozconfig referencing a non-artifact OBJDIR"
)
file_list = json.load(open(input_file))
parser = WebIDL.Parser()
for filepath in file_list["webidls"]:
with open(filepath, "r", encoding="utf8") as f:
parser.parse(f.read(), filepath)
results = parser.finish()
pure_output = {
"Document": {
"prototype": [
"getSelection",
"hasStorageAccess",
],
},
"Range": {
"prototype": [
"isPointInRange",
"comparePoint",
"intersectsNode",
# These two functions aren't pure because they do trigger
# layout when they are called, but in the context of eager
# evaluation, that should be a totally fine thing to do.
"getClientRects",
"getBoundingClientRect",
],
},
"Selection": {
"prototype": ["getRangeAt", "containsNode"],
},
}
unsafe_getters_names = []
for result in results:
if isinstance(result, WebIDL.IDLInterface):
iface = result.identifier.name
is_global = result.getExtendedAttribute("Global")
for member in result.members:
name = member.identifier.name
if member.isMethod() and member.affects == "Nothing":
if (
PURE_INTERFACE_ALLOWLIST and not iface in PURE_INTERFACE_ALLOWLIST
) or name.startswith("_"):
continue
if is_global:
raise Exception(
"Global methods and accessors are not supported: " + iface
)
if iface not in pure_output:
pure_output[iface] = {}
if member.isStatic():
owner_type = "static"
else:
owner_type = "prototype"
if owner_type not in pure_output[iface]:
pure_output[iface][owner_type] = []
# All DOM getters are considered eagerly-evaluate-able.
# Collect methods only.
#
# NOTE: We still need to calculate unsafe_getters_names for
# object preview.
if member.isMethod():
pure_output[iface][owner_type].append(name)
if (
not iface in DEPRECATED_INTERFACE__EXCLUDE_LIST
and not name in unsafe_getters_names
and member.isAttr()
and (
member.getExtendedAttribute("Deprecated")
or member.getExtendedAttribute("LegacyLenientThis")
)
):
unsafe_getters_names.append(name)
with open(pure_output_file, "w") as f:
f.write(FILE_TEMPLATE % {"data": json.dumps(pure_output, indent=2, sort_keys=True)})
print("Successfully generated", pure_output_file)
unsafe_getters_names.sort()
with open(unsafe_getters_names_file, "w") as f:
f.write(
FILE_TEMPLATE
% {"data": json.dumps(unsafe_getters_names, indent=2, sort_keys=True)}
)
print("Successfully generated", unsafe_getters_names_file)
print("Formatting files...")
system("./mach eslint --fix " + pure_output_file + " " + unsafe_getters_names_file)
print("Files are now properly formatted")
# Parsing the idls generate a parser.out file that we don't have any use of.
if path.exists("parser.out"):
remove("parser.out")
print("DONE")