1
0
Fork 0
firefox/tools/ts/build_paths.js
Daniel Baumann 5e9a113729
Adding upstream version 140.0.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
2025-06-25 09:37:52 +02:00

130 lines
3.9 KiB
JavaScript

/* 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/. */
"use strict";
/**
* Build: <srcdir>/tools/@types/generated/tspaths.json, and
* <srcdir>/tools/@types/generated/lib.gecko.modules.d.ts
*
* from: various import forms in all *.js and *.mjs sources.
*/
const fs = require("fs");
const path = require("path");
const { fixed } = require("./config/fixed_paths.js");
const HEADER = `/**
* NOTE: Do not modify this file by hand.
* Content was generated by running "mach ts paths".
*/
`;
const IGNORE = [/\.git/, /\.hg/, /node_modules/, /^obj.*/, /test262/];
const IMPORT =
/(\bimport |import\(|require\(|\.importESModule\(|\.(defineESModuleGetters?|declareLazy|defineLazy)\()[^;]+/gm;
const URI = /("|')((resource|chrome|moz-src):\/\/[\w\d\/_.-]+\.m?js)\1/gm;
function ignore(filePath) {
return IGNORE.some(re => filePath.match(re));
}
// Scan the root dir for *.js and *.mjs files, recursivelly.
function scan(root, dir, files) {
for (let file of fs.readdirSync(`${root}/${dir}`, { withFileTypes: true })) {
if (file.isDirectory() && !ignore(dir + file.name)) {
scan(root, `${dir}${file.name}/`, files);
} else if (file.name.match(/\.(x?html|m?js)$/)) {
files.push(dir + file.name);
}
}
}
// Emit path mapping for all found module URIs.
function emitPaths(files, uris, modules, relativeBasePath) {
let paths = {};
for (let uri of [...uris].sort()) {
if (uri in fixed) {
continue;
}
let parts = uri.split("/");
let filePath = "";
let matches;
// Check for a substitution .d.ts file from processed/generated sources.
let sub = parts.at(-1).replace(/\.(m)?js$/, ".d.$1ts");
if (fs.existsSync(`${__dirname}/../@types/subs/${sub}`)) {
paths[uri] = [`tools/@types/subs/${sub}`];
continue;
}
// Starting with just the file name, add each path part going backwards.
do {
filePath = "/" + parts.pop() + filePath;
matches = files.filter(f => f.endsWith(filePath));
// While multiple files match, add parts used for filtering.
} while (matches.length > 1 && parts.length);
// Unique match is almost certainy correct.
if (matches.length === 1) {
paths[uri] = [matches[0]];
} else {
// URI matched more than one, or failed to match any file.
console.warn("[WARN]", uri);
modules.delete(uri);
}
}
Object.assign(paths, fixed);
let tspaths = { compilerOptions: { baseUrl: relativeBasePath, paths } };
return JSON.stringify(tspaths, null, 2) + "\n";
}
// Emit type mapping for all modules imported via lazy getters.
function emitLazy(modules) {
let lines = [HEADER];
lines.push("export interface LazyModules {");
for (let uri of [...modules].sort()) {
lines.push(` "${uri}": typeof import("${uri}"),`);
}
lines.push("}\n");
return lines.join("\n");
}
function main(root_dir, paths_json, lib_lazy) {
let files = [];
scan(root_dir, "", files);
let uris = new Set();
let modules = new Set();
for (let file of files) {
let src = fs.readFileSync(`${root_dir}/${file}`, "utf-8");
for (let [exp, , method] of src.matchAll(IMPORT)) {
for (let [, , uri, proto] of exp.matchAll(URI)) {
if (proto !== "moz-src") {
uris.add(uri);
}
if (method?.match(/ModuleGetter|Lazy/)) {
modules.add(uri);
}
}
}
}
let json = emitPaths(
files,
uris,
modules,
path.relative(path.dirname(paths_json), root_dir).replaceAll("\\", "/")
);
console.log(`[INFO] ${paths_json} (${json.length.toLocaleString()} bytes)`);
fs.writeFileSync(paths_json, json);
let lib = emitLazy(modules);
console.log(`[INFO] ${lib_lazy} (${lib.length.toLocaleString()} bytes)`);
fs.writeFileSync(lib_lazy, lib);
}
main(...process.argv.slice(2));