@vlandoss/clibuddy 0.5.1-git-a483516.0 → 0.5.1-git-137024d.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.mts +9 -5
- package/dist/index.mjs +14 -27
- package/package.json +2 -1
- package/src/shell/index.ts +1 -1
- package/src/shell/resolve-package-bin.ts +26 -0
- package/src/shell/resolve-bin.ts +0 -53
package/dist/index.d.mts
CHANGED
|
@@ -75,12 +75,16 @@ declare class ShellService {
|
|
|
75
75
|
declare const cwd: string;
|
|
76
76
|
declare function createShellService(options?: ShellOptions): ShellService;
|
|
77
77
|
//#endregion
|
|
78
|
-
//#region src/shell/resolve-bin.d.ts
|
|
79
|
-
|
|
78
|
+
//#region src/shell/resolve-package-bin.d.ts
|
|
79
|
+
type Options = {
|
|
80
80
|
from: string;
|
|
81
|
-
binPath?: string;
|
|
82
81
|
binName?: string;
|
|
83
|
-
}
|
|
82
|
+
};
|
|
83
|
+
declare function _resolvePackageBin(pkg: string, {
|
|
84
|
+
from,
|
|
85
|
+
binName
|
|
86
|
+
}: Options): Promise<string>;
|
|
87
|
+
declare const resolvePackageBin: typeof _resolvePackageBin;
|
|
84
88
|
//#endregion
|
|
85
89
|
//#region src/shell/utils.d.ts
|
|
86
90
|
declare function isNonZeroExitError(value: unknown): value is NonZeroExitError;
|
|
@@ -91,4 +95,4 @@ declare const text: {
|
|
|
91
95
|
version: (version: string) => string;
|
|
92
96
|
};
|
|
93
97
|
//#endregion
|
|
94
|
-
export { NonZeroExitError, Pkg, type Project, RunOptions, ShellOptions, ShellService, colorize, createPkg, createShellService, cwd, dirnameOf, filenameOf, hasTTY, isCI, isNonZeroExitError, palette,
|
|
98
|
+
export { NonZeroExitError, Pkg, type Project, RunOptions, ShellOptions, ShellService, colorize, createPkg, createShellService, cwd, dirnameOf, filenameOf, hasTTY, isCI, isNonZeroExitError, palette, resolvePackageBin, run, text };
|
package/dist/index.mjs
CHANGED
|
@@ -9,6 +9,7 @@ import { findPackages } from "@pnpm/fs.find-packages";
|
|
|
9
9
|
import { readPackageJSON, resolvePackageJSON, writePackageJSON } from "pkg-types";
|
|
10
10
|
import { parse } from "yaml";
|
|
11
11
|
import { NonZeroExitError, x } from "tinyexec";
|
|
12
|
+
import memoize from "memoize";
|
|
12
13
|
//#region src/colors.ts
|
|
13
14
|
const colorize = (hex) => ansis.hex(hex);
|
|
14
15
|
const palette = {
|
|
@@ -203,34 +204,20 @@ function createShellService(options = {}) {
|
|
|
203
204
|
});
|
|
204
205
|
}
|
|
205
206
|
//#endregion
|
|
206
|
-
//#region src/shell/resolve-bin.ts
|
|
207
|
-
function
|
|
208
|
-
|
|
209
|
-
if (options.binPath) return path.join(pkgRoot, options.binPath);
|
|
210
|
-
const bin = JSON.parse(fs.readFileSync(path.join(pkgRoot, "package.json"), "utf8")).bin;
|
|
211
|
-
if (!bin) throw new Error(`Package ${pkg} has no "bin" field`);
|
|
212
|
-
if (typeof bin === "string") return path.join(pkgRoot, bin);
|
|
213
|
-
const wantName = options.binName ?? pkg.replace(/^@[^/]+\//, "");
|
|
214
|
-
const rel = bin[wantName] ?? Object.values(bin)[0];
|
|
215
|
-
if (!rel) throw new Error(`No bin entry found for ${pkg} (asked for ${wantName})`);
|
|
216
|
-
return path.join(pkgRoot, rel);
|
|
217
|
-
}
|
|
218
|
-
function findPackageRoot(require, pkg) {
|
|
207
|
+
//#region src/shell/resolve-package-bin.ts
|
|
208
|
+
async function _resolvePackageBin(pkg, { from, binName }) {
|
|
209
|
+
let pkgJsonPath;
|
|
219
210
|
try {
|
|
220
|
-
|
|
221
|
-
} catch {
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
const
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
if (JSON.parse(fs.readFileSync(pkgJsonPath, "utf8")).name === pkg) return dir;
|
|
229
|
-
} catch {}
|
|
230
|
-
dir = path.dirname(dir);
|
|
231
|
-
}
|
|
232
|
-
throw new Error(`Could not find package root for ${pkg} from ${mainPath}`);
|
|
211
|
+
pkgJsonPath = await resolvePackageJSON(pkg, { from });
|
|
212
|
+
} catch {
|
|
213
|
+
pkgJsonPath = createRequire(from).resolve(`${pkg}/package.json`);
|
|
214
|
+
}
|
|
215
|
+
const { bin } = await readPackageJSON(pkgJsonPath);
|
|
216
|
+
const rel = typeof bin === "string" ? bin : bin?.[binName ?? pkg.replace(/^@[^/]+\//, "")];
|
|
217
|
+
if (!rel) throw new Error(`No bin "${binName ?? pkg}" in ${pkg}`);
|
|
218
|
+
return path.join(path.dirname(pkgJsonPath), rel);
|
|
233
219
|
}
|
|
220
|
+
const resolvePackageBin = memoize(_resolvePackageBin, { cacheKey: ([pkg, opts]) => `${pkg}|${opts.from}|${opts.binName ?? ""}` });
|
|
234
221
|
//#endregion
|
|
235
222
|
//#region src/text.ts
|
|
236
223
|
const text = {
|
|
@@ -238,4 +225,4 @@ const text = {
|
|
|
238
225
|
version: (version) => palette.muted(`v${version}`)
|
|
239
226
|
};
|
|
240
227
|
//#endregion
|
|
241
|
-
export { NonZeroExitError, Pkg, ShellService, colorize, createPkg, createShellService, cwd, dirnameOf, filenameOf, hasTTY, isCI, isNonZeroExitError, palette,
|
|
228
|
+
export { NonZeroExitError, Pkg, ShellService, colorize, createPkg, createShellService, cwd, dirnameOf, filenameOf, hasTTY, isCI, isNonZeroExitError, palette, resolvePackageBin, run, text };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vlandoss/clibuddy",
|
|
3
|
-
"version": "0.5.1-git-
|
|
3
|
+
"version": "0.5.1-git-137024d.0",
|
|
4
4
|
"description": "A helper library to create CLIs in Variable Land",
|
|
5
5
|
"homepage": "https://github.com/variableland/dx/tree/main/packages/clibuddy#readme",
|
|
6
6
|
"bugs": {
|
|
@@ -30,6 +30,7 @@
|
|
|
30
30
|
"@pnpm/fs.find-packages": "1000.0.24",
|
|
31
31
|
"@pnpm/types": "1001.3.0",
|
|
32
32
|
"ansis": "4.2.0",
|
|
33
|
+
"memoize": "10.2.0",
|
|
33
34
|
"pkg-types": "2.3.0",
|
|
34
35
|
"std-env": "3.9.0",
|
|
35
36
|
"tinyexec": "1.1.2",
|
package/src/shell/index.ts
CHANGED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { createRequire } from "node:module";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import memoize from "memoize";
|
|
4
|
+
import { readPackageJSON, resolvePackageJSON } from "pkg-types";
|
|
5
|
+
|
|
6
|
+
type Options = { from: string; binName?: string };
|
|
7
|
+
|
|
8
|
+
// pkg-types covers any package whose `.` entry is in `exports` (including
|
|
9
|
+
// restrictive ones like oxlint). The fallback handles packages without
|
|
10
|
+
// `main`/`exports` at all (e.g. @biomejs/biome).
|
|
11
|
+
async function _resolvePackageBin(pkg: string, { from, binName }: Options): Promise<string> {
|
|
12
|
+
let pkgJsonPath: string;
|
|
13
|
+
try {
|
|
14
|
+
pkgJsonPath = await resolvePackageJSON(pkg, { from });
|
|
15
|
+
} catch {
|
|
16
|
+
pkgJsonPath = createRequire(from).resolve(`${pkg}/package.json`);
|
|
17
|
+
}
|
|
18
|
+
const { bin } = await readPackageJSON(pkgJsonPath);
|
|
19
|
+
const rel = typeof bin === "string" ? bin : bin?.[binName ?? pkg.replace(/^@[^/]+\//, "")];
|
|
20
|
+
if (!rel) throw new Error(`No bin "${binName ?? pkg}" in ${pkg}`);
|
|
21
|
+
return path.join(path.dirname(pkgJsonPath), rel);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export const resolvePackageBin = memoize(_resolvePackageBin, {
|
|
25
|
+
cacheKey: ([pkg, opts]) => `${pkg}|${opts.from}|${opts.binName ?? ""}`,
|
|
26
|
+
});
|
package/src/shell/resolve-bin.ts
DELETED
|
@@ -1,53 +0,0 @@
|
|
|
1
|
-
import fs from "node:fs";
|
|
2
|
-
import { createRequire } from "node:module";
|
|
3
|
-
import path from "node:path";
|
|
4
|
-
|
|
5
|
-
export function resolveBinPath(pkg: string, options: { from: string; binPath?: string; binName?: string }): string {
|
|
6
|
-
const require = createRequire(options.from);
|
|
7
|
-
const pkgRoot = findPackageRoot(require, pkg);
|
|
8
|
-
|
|
9
|
-
if (options.binPath) {
|
|
10
|
-
return path.join(pkgRoot, options.binPath);
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
const pkgJson = JSON.parse(fs.readFileSync(path.join(pkgRoot, "package.json"), "utf8")) as {
|
|
14
|
-
bin?: string | Record<string, string>;
|
|
15
|
-
};
|
|
16
|
-
const bin = pkgJson.bin;
|
|
17
|
-
if (!bin) throw new Error(`Package ${pkg} has no "bin" field`);
|
|
18
|
-
|
|
19
|
-
if (typeof bin === "string") return path.join(pkgRoot, bin);
|
|
20
|
-
|
|
21
|
-
const wantName = options.binName ?? pkg.replace(/^@[^/]+\//, "");
|
|
22
|
-
const rel = bin[wantName] ?? Object.values(bin)[0];
|
|
23
|
-
if (!rel) throw new Error(`No bin entry found for ${pkg} (asked for ${wantName})`);
|
|
24
|
-
return path.join(pkgRoot, rel);
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
// Two-step lookup tolerates packages that don't expose `./package.json` in
|
|
28
|
-
// their `exports` map (e.g. oxlint) and packages with no `main`/`exports` at
|
|
29
|
-
// all (e.g. @biomejs/biome) — `require.resolve(pkg)` fails for the latter.
|
|
30
|
-
function findPackageRoot(require: NodeJS.Require, pkg: string): string {
|
|
31
|
-
try {
|
|
32
|
-
return path.dirname(require.resolve(`${pkg}/package.json`));
|
|
33
|
-
} catch {
|
|
34
|
-
// fall through to manual walk
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
const mainPath = require.resolve(pkg);
|
|
38
|
-
let dir = path.dirname(mainPath);
|
|
39
|
-
const fsRoot = path.parse(dir).root;
|
|
40
|
-
while (dir !== fsRoot) {
|
|
41
|
-
const pkgJsonPath = path.join(dir, "package.json");
|
|
42
|
-
if (fs.existsSync(pkgJsonPath)) {
|
|
43
|
-
try {
|
|
44
|
-
const data = JSON.parse(fs.readFileSync(pkgJsonPath, "utf8")) as { name?: string };
|
|
45
|
-
if (data.name === pkg) return dir;
|
|
46
|
-
} catch {
|
|
47
|
-
// not a valid package.json — keep walking
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
dir = path.dirname(dir);
|
|
51
|
-
}
|
|
52
|
-
throw new Error(`Could not find package root for ${pkg} from ${mainPath}`);
|
|
53
|
-
}
|