mirror of
				https://github.com/mozilla/gecko-dev.git
				synced 2025-10-31 16:28:05 +02:00 
			
		
		
		
	
		
			
				
	
	
		
			180 lines
		
	
	
	
		
			6.4 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			180 lines
		
	
	
	
		
			6.4 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_obj = mozpath.join(ctx.topobjdir, "xpcom/base/error_list.json")
 | |
|         errors_src = mozpath.join(ctx.topsrcdir, "tools/ts/config/error_list.json")
 | |
| 
 | |
|         if os.path.exists(errors_obj):
 | |
|             print(f"[INFO] {errors_obj} -> {errors_src}")
 | |
|             shutil.copy(errors_obj, errors_src)
 | |
| 
 | |
|         return node(ctx, "build_nsresult", lib_dts, xpc_msg, errors_src)
 | |
| 
 | |
|     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"]
 | |
|     retval = 0
 | |
| 
 | |
|     for lib in targets + platforms + ["glean"]:
 | |
|         file = f"lib.gecko.{lib}.d.ts"
 | |
|         path = mozpath.join(ctx.distdir, "@types", file)
 | |
|         if not os.path.exists(path):
 | |
|             if not lib in platforms:
 | |
|                 print(f"[ERROR] {path} not found. Did you run `mach ts build`?")
 | |
|                 retval = 1
 | |
|             continue
 | |
| 
 | |
|         # 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.")
 | |
|     return retval
 | |
| 
 | |
| 
 | |
| @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
 | 
