From 80b4323949ac112c7e937904112ea7961e3c2d05 Mon Sep 17 00:00:00 2001 From: Rudxain <76864299+Rudxain@users.noreply.github.com> Date: Thu, 3 Jul 2025 22:22:00 -0400 Subject: [PATCH 1/2] Node:assert, TS, Prettier - add some assertions - minor refactor - add JSDoc: comments, type-annotations, and type-casts - `npm i '@types/node@latest' prettier@latest typescript@latest` - strict `jsconfig.json` - add some props to `package.json` --- .gitignore | 3 +++ generate-db.js | 69 ++++++++++++++++++++++++++++++++++++----------- jsconfig.json | 21 +++++++++++++++ package-lock.json | 64 +++++++++++++++++++++++++++++++++++++++++++ package.json | 11 +++++++- 5 files changed, 151 insertions(+), 17 deletions(-) create mode 100644 jsconfig.json create mode 100644 package-lock.json diff --git a/.gitignore b/.gitignore index e3a40b1..07eb8bc 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,6 @@ +# NPM +node_modules/ + # Python __pycache__ diff --git a/generate-db.js b/generate-db.js index f1ff919..caca9f0 100755 --- a/generate-db.js +++ b/generate-db.js @@ -3,6 +3,7 @@ import { glob, readFile, writeFile } from "node:fs/promises"; import { gunzip } from "node:zlib"; import { join } from "node:path"; import { promisify } from "node:util"; +import assert from "node:assert/strict"; const gunzipAsync = promisify(gunzip); @@ -21,9 +22,11 @@ if (!TERMUX_ARCH) { } const binPrefix = TERMUX_PREFIX.substring(1) + "/bin/"; +/**@type {unknown}*/ const repos = JSON.parse( - await readFile(join(TERMUX_SCRIPTDIR, "repo.json")), + await readFile(join(TERMUX_SCRIPTDIR, "repo.json"), "utf8"), ); +assert(typeof repos == "object" && repos); /** * Parses an alternative file and returns an array of alternative entries. @@ -38,6 +41,7 @@ const repos = JSON.parse( * - `priority`: The priority of the alternative. * * Note that both the name and path do not start with TERMUX_PREFIX, but instead start with the relative path from TERMUX_PREFIX. + * @param {string} filePath */ async function parseAlternativeFile(filePath) { const content = await readFile(filePath, "utf8"); @@ -56,7 +60,6 @@ async function parseAlternativeFile(filePath) { let match = line.match(/\s*#.*/); line = line.substring(0, match === null ? line.length : match.index); - if (line.startsWith("Name: ")) { if (parsingDependents) { parsingDependents = false; @@ -138,6 +141,15 @@ async function parseAlternativeFile(filePath) { return alternatives; } +/** +@param {{ + name: string, + url: URL, + distribution: string +}} repo +@param {string} repoPath +@param {string} arch +*/ async function processRepo(repo, repoPath, arch) { // Fetch the Contents.gz file for the given architecture from the apt mirror const url = `${repo.url}/dists/${repo.distribution}/Contents-${arch}.gz`; @@ -157,14 +169,20 @@ async function processRepo(repo, repoPath, arch) { // is the name of the package that provides this file. const lines = data.toString().split("\n"); - // Stores mappings of binary names to package names - // The key is the binary name, and the value is an array of package names - // that provide this binary + /** + * Stores mappings of binary names to package names + * The key is the binary name, and the value is an array of package names + * that provide this binary + * @type {Map} + */ const binMap = new Map(); - // Stores mappings of file paths to package names - // This is needed to resolve the package names for binaries that are setup - // using the alternatives system + /** + * Stores mappings of file paths to package names + * This is needed to resolve the package names for binaries that are setup + * using the alternatives system + * @type {Map} + */ const fileMap = new Map(); // Populate the fileMap lines.forEach((line) => { @@ -185,13 +203,13 @@ async function processRepo(repo, repoPath, arch) { if (!binMap.has(packageName)) { binMap.set(packageName, []); } - binMap.get(packageName).push(binary); + /**@type {string[]}*/ (binMap.get(packageName)).push(binary); }); }); // Now go through all the *.alternatives files in the repository and parse // them to find the alternatives and their dependents - repoPath = join(TERMUX_SCRIPTDIR, repoPath); + repoPath = join(/**@type {string}*/ (TERMUX_SCRIPTDIR), repoPath); for await (const file of glob(`${repoPath}/*/*.alternatives`, { nodir: true, })) { @@ -214,7 +232,7 @@ async function processRepo(repo, repoPath, arch) { if (!binMap.has(packageName)) { binMap.set(packageName, []); } - binMap.get(packageName).push(binary); + /**@type {string[]}*/ (binMap.get(packageName)).push(binary); alternativeEntry.dependents.forEach(({ link, name: _, path }) => { if (link.startsWith("bin/")) { const depPackageName = fileMap.get( @@ -224,7 +242,7 @@ async function processRepo(repo, repoPath, arch) { if (!binMap.has(depPackageName)) { binMap.set(depPackageName, []); } - binMap.get(depPackageName).push(depBinary); + /**@type {string[]}*/ (binMap.get(depPackageName)).push(depBinary); } // Register the link in the fileMap for the package // This is used by vim.alternatives where bin/vim is a link with alternative libexec/vim/vim @@ -233,7 +251,7 @@ async function processRepo(repo, repoPath, arch) { if (!binMap.has(packageName)) { binMap.set(packageName, []); } - binMap.get(packageName).push(binary); + /**@type {string[]}*/ (binMap.get(packageName)).push(binary); }); } // Register the link in the fileMap for the package @@ -250,8 +268,7 @@ async function processRepo(repo, repoPath, arch) { const header = Array.from(binMap.keys()) .sort() .map((packageName) => { - const binaries = binMap - .get(packageName) + const binaries = /**@type {string[]}*/ (binMap.get(packageName)) .sort() .map((bin) => `" ${bin}",`); return `"${packageName}",\n${binaries.join("\n")}`; @@ -261,12 +278,32 @@ async function processRepo(repo, repoPath, arch) { await writeFile(headerFile, header); } +/** +@type {Promise[]} +*/ const promises = []; for (const path in repos) { if (path === "pkg_format") continue; + + //@ts-expect-error const repo = repos[path]; - promises.push(processRepo(repo, path, TERMUX_ARCH)); + assert(typeof repo == "object" && repo); + assert("name" in repo && typeof repo.name == "string"); + assert("url" in repo && typeof repo.url == "string"); + assert("distribution" in repo && typeof repo.distribution == "string"); + + promises.push( + processRepo( + { + name: repo.name, + url: new URL(repo.url), + distribution: repo.distribution, + }, + path, + TERMUX_ARCH, + ), + ); } await Promise.all(promises); diff --git a/jsconfig.json b/jsconfig.json new file mode 100644 index 0000000..35eb6ae --- /dev/null +++ b/jsconfig.json @@ -0,0 +1,21 @@ +/* https://aka.ms/tsconfig */ +{ + "compilerOptions": { + "target": "ESNext", + "module": "ESNext", + "allowJs": true, + "checkJs": true, + "forceConsistentCasingInFileNames": true, + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "exactOptionalPropertyTypes": true, + "noImplicitReturns": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedIndexedAccess": true, + "noImplicitOverride": true, + "noPropertyAccessFromIndexSignature": true, + "allowUnreachableCode": false, + "skipLibCheck": true + } +} diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..34bec49 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,64 @@ +{ + "name": "cmd-not-found-gen-db", + "version": "0.1.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "cmd-not-found-gen-db", + "version": "0.1.0", + "devDependencies": { + "@types/node": "^24.0.10", + "prettier": "^3.6.2", + "typescript": "^5.8.3" + } + }, + "node_modules/@types/node": { + "version": "24.0.10", + "resolved": "https://registry.npmjs.org/@types/node/-/node-24.0.10.tgz", + "integrity": "sha512-ENHwaH+JIRTDIEEbDK6QSQntAYGtbvdDXnMXnZaZ6k13Du1dPMmprkEHIL7ok2Wl2aZevetwTAb5S+7yIF+enA==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~7.8.0" + } + }, + "node_modules/prettier": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.6.2.tgz", + "integrity": "sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ==", + "dev": true, + "license": "MIT", + "bin": { + "prettier": "bin/prettier.cjs" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, + "node_modules/typescript": { + "version": "5.8.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.3.tgz", + "integrity": "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/undici-types": { + "version": "7.8.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.8.0.tgz", + "integrity": "sha512-9UJ2xGDvQ43tYyVMpuHlsgApydB8ZKfVYTsLDhXkFL/6gfkp+U8xTGdh8pMJv1SpZna0zxG1DwsKZsreLbXBxw==", + "dev": true, + "license": "MIT" + } + } +} diff --git a/package.json b/package.json index 094aa89..dc817d3 100644 --- a/package.json +++ b/package.json @@ -1,4 +1,13 @@ { + "name": "cmd-not-found-gen-db", "type": "module", - "private": true + "private": true, + "version": "0.1.0", + "bugs": "https://github.com/termux/command-not-found/issues", + "repository": "github:termux/command-not-found", + "devDependencies": { + "@types/node": "^24.0.10", + "prettier": "^3.6.2", + "typescript": "^5.8.3" + } } From fdabd19e4ed21cf49c2c27ec41d7b0e16f267212 Mon Sep 17 00:00:00 2001 From: Rudxain <76864299+Rudxain@users.noreply.github.com> Date: Fri, 4 Jul 2025 18:46:04 -0400 Subject: [PATCH 2/2] `rm package-lock.json` --- package-lock.json | 64 ----------------------------------------------- 1 file changed, 64 deletions(-) delete mode 100644 package-lock.json diff --git a/package-lock.json b/package-lock.json deleted file mode 100644 index 34bec49..0000000 --- a/package-lock.json +++ /dev/null @@ -1,64 +0,0 @@ -{ - "name": "cmd-not-found-gen-db", - "version": "0.1.0", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "name": "cmd-not-found-gen-db", - "version": "0.1.0", - "devDependencies": { - "@types/node": "^24.0.10", - "prettier": "^3.6.2", - "typescript": "^5.8.3" - } - }, - "node_modules/@types/node": { - "version": "24.0.10", - "resolved": "https://registry.npmjs.org/@types/node/-/node-24.0.10.tgz", - "integrity": "sha512-ENHwaH+JIRTDIEEbDK6QSQntAYGtbvdDXnMXnZaZ6k13Du1dPMmprkEHIL7ok2Wl2aZevetwTAb5S+7yIF+enA==", - "dev": true, - "license": "MIT", - "dependencies": { - "undici-types": "~7.8.0" - } - }, - "node_modules/prettier": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.6.2.tgz", - "integrity": "sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ==", - "dev": true, - "license": "MIT", - "bin": { - "prettier": "bin/prettier.cjs" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/prettier/prettier?sponsor=1" - } - }, - "node_modules/typescript": { - "version": "5.8.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.3.tgz", - "integrity": "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==", - "dev": true, - "license": "Apache-2.0", - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=14.17" - } - }, - "node_modules/undici-types": { - "version": "7.8.0", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.8.0.tgz", - "integrity": "sha512-9UJ2xGDvQ43tYyVMpuHlsgApydB8ZKfVYTsLDhXkFL/6gfkp+U8xTGdh8pMJv1SpZna0zxG1DwsKZsreLbXBxw==", - "dev": true, - "license": "MIT" - } - } -}