From 6b47fef1b59b7d38982ecc3de719409ff09cdfad Mon Sep 17 00:00:00 2001 From: user Date: Mon, 20 Jul 2026 13:23:10 -0300 Subject: [PATCH] feat: add CJS module name mapping - extracted modules now use descriptive paths instead of numeric IDs --- src/update/shared.ts | 1 + src/update/tasks/code.ts | 68 ++++++++++++++++++++++++++++++++--- src/update/tasks/decompile.ts | 10 +++++- 3 files changed, 73 insertions(+), 6 deletions(-) diff --git a/src/update/shared.ts b/src/update/shared.ts index 6d4c3028c1e..deb016731d6 100644 --- a/src/update/shared.ts +++ b/src/update/shared.ts @@ -7,6 +7,7 @@ export const workFolder = "tmp"; export const apksFolder = join(workFolder, "apks"); export const codePath = join(workFolder, "code.js"); export const modulesPath = join(workFolder, "modules"); +export const moduleMapPath = join(workFolder, "module-map.json"); export const apkSplits = ["base", "config.hdpi", "config.xxhdpi"] as const; export const oprevFiles = ["source.jsonl"] as const; diff --git a/src/update/tasks/code.ts b/src/update/tasks/code.ts index fbfc0f9e5e4..816af122155 100644 --- a/src/update/tasks/code.ts +++ b/src/update/tasks/code.ts @@ -2,9 +2,20 @@ import { mkdir, rm, readdir, stat } from "node:fs/promises"; import { join as pathJoin } from "node:path"; import { commit } from "../git"; import type { Progress } from "../progress"; -import { commitAnyway, cuteVersion, modulesPath } from "../shared"; +import { commitAnyway, cuteVersion, moduleMapPath, modulesPath } from "../shared"; import { join, sortEntries } from "../utils"; +const moduleIdRegex = /^module_(\d+)\.js$/; + +interface CjsModule { + id: number; + name: string; +} + +function sanitizePath(name: string): string { + return name.replace(/[<>:"|?*]/g, "_").replace(/\.\./g, "__"); +} + export default async function code(progress: Progress, _code: string[]) { progress.start("code_getting"); @@ -12,6 +23,24 @@ export default async function code(progress: Progress, _code: string[]) { throw new Error(`Modules directory not found at ${modulesPath}`); } + const moduleMap = new Map(); + try { + const mapRaw = await Bun.file(moduleMapPath).json(); + if (Array.isArray(mapRaw)) { + for (const entry of mapRaw as CjsModule[]) { + if (entry.name?.trim()) moduleMap.set(entry.id, entry.name); + } + } else if (mapRaw && typeof mapRaw === "object") { + for (const [key, value] of Object.entries(mapRaw)) { + const id = Number(key); + if (!Number.isNaN(id) && typeof value === "string" && value.trim()) { + moduleMap.set(id, value); + } + } + } + } catch {} + console.log(`Loaded ${moduleMap.size} module name mappings`); + async function scanDir(dir: string, basePath: string): Promise> { const files = new Map(); const entries = await readdir(dir, { withFileTypes: true }); @@ -29,7 +58,24 @@ export default async function code(progress: Progress, _code: string[]) { return files; } - const files = await scanDir(modulesPath, modulesPath); + const rawFiles = await scanDir(modulesPath, modulesPath); + const files = new Map(); + + for (const [relativePath, fileSize] of rawFiles) { + const match = relativePath.match(moduleIdRegex); + if (match) { + const id = Number.parseInt(match[1], 10); + const mappedName = moduleMap.get(id); + if (mappedName) { + const newPath = sanitizePath(mappedName) + ".js"; + files.set(newPath, fileSize); + } else { + files.set(relativePath, fileSize); + } + } else { + files.set(relativePath, fileSize); + } + } await Bun.write( "../data/source.jsonl", @@ -47,10 +93,22 @@ export default async function code(progress: Progress, _code: string[]) { await rm(filePrefix, { recursive: true, force: true }); await Promise.all( - [...files.keys()].map(async (file) => { - const dest = join(filePrefix, file); + [...rawFiles.entries()].map(async ([relativePath]) => { + const match = relativePath.match(moduleIdRegex); + let dest: string; + if (match) { + const id = Number.parseInt(match[1], 10); + const mappedName = moduleMap.get(id); + if (mappedName) { + dest = join(filePrefix, sanitizePath(mappedName) + ".js"); + } else { + dest = join(filePrefix, relativePath); + } + } else { + dest = join(filePrefix, relativePath); + } await mkdir(pathJoin(dest, ".."), { recursive: true }); - await Bun.write(dest, Bun.file(join(modulesPath, file))); + await Bun.write(dest, Bun.file(join(modulesPath, relativePath))); }), ); diff --git a/src/update/tasks/decompile.ts b/src/update/tasks/decompile.ts index c8d4048c0d6..c1e8f2917fc 100644 --- a/src/update/tasks/decompile.ts +++ b/src/update/tasks/decompile.ts @@ -1,7 +1,7 @@ import { exists } from "node:fs/promises"; import { commit } from "../git"; import type { Progress } from "../progress"; -import { codePath, commitAnyway, cuteVersion, modulesPath, workFolder } from "../shared"; +import { codePath, commitAnyway, cuteVersion, moduleMapPath, modulesPath, workFolder } from "../shared"; import { handleShellErr, join } from "../utils"; const gzipWorkerURL = new URL("decompile-gzip.ts", import.meta.url).href; @@ -45,6 +45,14 @@ export default async function decompile(progress: Progress, pathToBundle: string .then(handleShellErr); } + if (!(await Bun.file(moduleMapPath).exists())) { + await Bun.$`${decompilerBin} dump ${pathToBundle} --kind cjs-modules --json` + .quiet() + .nothrow() + .then(handleShellErr) + .then((out) => Bun.write(moduleMapPath, out.stdout)); + } + progress.update("decompile_decompiling", true); if (process.env.NODE_ENV !== "test" && !commitAnyway) {