185 lines
6.6 KiB
Python
185 lines
6.6 KiB
Python
# 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
|
|
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
|
|
import os
|
|
import shutil
|
|
import sys
|
|
|
|
import mozpack.path as mozpath
|
|
from mach.decorators import Command, CommandArgument, SubCommand
|
|
|
|
targets = ["dom", "nsresult", "services", "xpcom"]
|
|
|
|
|
|
@Command("ts", category="misc", description="Run TypeScript and related commands.")
|
|
def ts(ctx):
|
|
"""
|
|
TypeScript related commands to build/update typelibs and type-check js.
|
|
|
|
Example:
|
|
# Use tsc to check types in extensions framework code:
|
|
$ ./mach ts check toolkit/components/extensions
|
|
"""
|
|
ctx._sub_mach(["help", "ts"])
|
|
return 1
|
|
|
|
|
|
@SubCommand("ts", "build", description="Build typelibs.")
|
|
@CommandArgument("lib", choices=targets, nargs="?")
|
|
def build(ctx, lib):
|
|
"""Command to build the target typelibs."""
|
|
|
|
if lib is None:
|
|
for t in targets:
|
|
if rv := build(ctx, t):
|
|
return rv
|
|
return 0
|
|
|
|
types_dir = mozpath.join(ctx.distdir, "@types")
|
|
lib_dts = mozpath.join(types_dir, f"lib.gecko.{lib}.d.ts")
|
|
if not os.path.exists(types_dir):
|
|
os.makedirs(types_dir)
|
|
|
|
if lib == "nsresult":
|
|
xpc_msg = mozpath.join(ctx.topsrcdir, "js/xpconnect/src/xpc.msg")
|
|
errors_json = mozpath.join(ctx.topsrcdir, "tools/ts/config/error_list.json")
|
|
return node(ctx, "build_nsresult", lib_dts, xpc_msg, errors_json)
|
|
|
|
if lib == "services":
|
|
services_json = mozpath.join(ctx.topobjdir, "xpcom/components/services.json")
|
|
if not os.path.isfile(services_json):
|
|
return build_required(lib, services_json)
|
|
return node(ctx, "build_services", lib_dts, services_json)
|
|
|
|
if lib == "xpcom":
|
|
# When we hook this up to be part of the build, we'll have
|
|
# an explicit list of files. For now, just get all of them.
|
|
dir = mozpath.join(ctx.topobjdir, "config/makefiles/xpidl")
|
|
if not os.path.isdir(dir):
|
|
return build_required(lib, dir)
|
|
|
|
files = [f for f in os.listdir(dir) if f.endswith(".d.json")]
|
|
if not files:
|
|
return build_required(lib, f"*.d.json files in {dir}")
|
|
|
|
return node(ctx, "build_xpcom", lib_dts, dir, *files)
|
|
|
|
if lib == "dom":
|
|
# Same as above, get all *.webidl files for now.
|
|
dir = mozpath.join(ctx.topsrcdir, "dom")
|
|
files = []
|
|
for subdir in ["webidl", "chrome-webidl"]:
|
|
for file in os.listdir(mozpath.join(dir, subdir)):
|
|
if file.endswith(".webidl"):
|
|
files.append(subdir + "/" + file)
|
|
|
|
return node(ctx, "build_dom", lib_dts, dir, *files)
|
|
|
|
raise ValueError(f"Unknown typelib: {lib}")
|
|
|
|
|
|
@SubCommand("ts", "check", description="Check types in a project using tsc.")
|
|
@CommandArgument("paths", nargs="+", help="Path to a (dir with) tsconfig.json.")
|
|
def check(ctx, paths):
|
|
for p in paths:
|
|
rv = node(ctx, "node_modules/typescript/bin/tsc", "--project", p)
|
|
if rv:
|
|
return rv
|
|
return 0
|
|
|
|
|
|
@SubCommand("ts", "setup", description="Install TypeScript and other dependencies.")
|
|
def setup(ctx):
|
|
# Install locally under tools/ts/node_modules, to avoid any conflicts for now.
|
|
os.chdir(mozpath.dirname(__file__))
|
|
return ctx._sub_mach(["npm", "ci"])
|
|
|
|
|
|
@SubCommand("ts", "update", description="Update tools/@types libraries.")
|
|
def update(ctx):
|
|
typelib_dir = mozpath.join(ctx.topsrcdir, "tools/@types/generated")
|
|
platforms = ["darwin", "linux", "win32"]
|
|
|
|
for lib in targets + platforms:
|
|
file = f"lib.gecko.{lib}.d.ts"
|
|
path = mozpath.join(ctx.distdir, "@types", file)
|
|
if not os.path.exists(path):
|
|
if lib in platforms:
|
|
continue
|
|
print(f"[ERROR] {path} not found. Did you run `mach ts build`?")
|
|
return 1
|
|
|
|
# This command inherently goes in a confusing direction, we're copying:
|
|
# from `<topobjdir>/dist/@types` files generated with `mach ts build`,
|
|
# into `<topsrcdir>/tools/@types` typelib dir back in your source tree.
|
|
print(f"[INFO] Updating {typelib_dir}/{file}")
|
|
shutil.copy(path, typelib_dir)
|
|
|
|
print("[WARNING] Your source tree was updated, you should commit the changes.")
|
|
|
|
|
|
@SubCommand("ts", "glean", description="Build Glean bindings.")
|
|
def glean(ctx):
|
|
sys.path.append(mozpath.join(ctx.topsrcdir, "toolkit/components/glean/"))
|
|
from metrics_index import metrics_yamls, pings_yamls
|
|
|
|
typelib_dir = mozpath.join(ctx.topsrcdir, "tools/@types/generated")
|
|
|
|
maybe_setup(ctx)
|
|
return node(
|
|
ctx, "build_glean", ctx.topsrcdir, typelib_dir, *metrics_yamls, *pings_yamls
|
|
)
|
|
|
|
|
|
@SubCommand("ts", "paths", description="Build module path mapping.")
|
|
def paths(ctx):
|
|
maybe_setup(ctx)
|
|
lib = mozpath.join(ctx.topsrcdir, "tools/@types/generated/tspaths.json")
|
|
lazy = mozpath.join(ctx.topsrcdir, "tools/@types/generated/lib.gecko.modules.d.ts")
|
|
return node(ctx, "build_paths", ctx.topsrcdir, lib, lazy)
|
|
|
|
|
|
@SubCommand("ts", "subs", description="Emit substitution .d.ts for processed sources.")
|
|
def subs(ctx):
|
|
maybe_setup(ctx)
|
|
processed = [
|
|
# AppConstants.sys.mjs has a (better) manually created declaration file.
|
|
"dist/bin/browser/modules/policies/schema.sys.mjs",
|
|
"dist/bin/modules/Readerable.sys.mjs",
|
|
"toolkit/components/nimbus/FeatureManifest.sys.mjs",
|
|
"toolkit/components/promiseworker/worker/PromiseWorker.js",
|
|
"toolkit/components/promiseworker/worker/PromiseWorker.mjs",
|
|
"toolkit/components/resistfingerprinting/RFPTargetConstants.sys.mjs",
|
|
]
|
|
args = ["--declaration", "--emitDeclarationOnly", "--allowJs", "--outDir"]
|
|
subs_dir = mozpath.join(ctx.topsrcdir, "tools/@types/subs")
|
|
|
|
for file in processed:
|
|
path = mozpath.join(ctx.topobjdir, file)
|
|
print(f"[INFO] {path} -> {subs_dir}/{mozpath.basename(path)}")
|
|
node(ctx, "node_modules/typescript/bin/tsc", *args, subs_dir, path)
|
|
|
|
|
|
def node(ctx, script, *args):
|
|
maybe_setup(ctx)
|
|
path = mozpath.join(mozpath.dirname(__file__), script)
|
|
return ctx._sub_mach(["node", path, *args])
|
|
|
|
|
|
def maybe_setup(ctx):
|
|
sys.path.append(mozpath.join(ctx.topsrcdir, "tools", "lint", "eslint"))
|
|
import setup_helper
|
|
|
|
if not setup_helper.check_node_executables_valid():
|
|
return 1
|
|
|
|
"""Check if npm modules are installed, and run setup if needed."""
|
|
dir = mozpath.dirname(__file__)
|
|
setup_helper.eslint_maybe_setup(dir, "TypeScript")
|
|
|
|
|
|
def build_required(lib, item):
|
|
print(f"Missing {item}.")
|
|
print(f"Building {lib} typelib requires a full Firefox build.")
|
|
return 1
|