@lovrabet/cli-framework 1.0.1 → 1.0.3
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/lib/framework/output.d.ts +16 -3
- package/lib/framework/output.js +27 -22
- package/lib/index.d.ts +8 -1
- package/lib/index.js +3 -1
- package/lib/utils/apply-jq-filter.d.ts +58 -3
- package/lib/utils/apply-jq-filter.js +105 -27
- package/lib/utils/jq-sidecar.d.ts +11 -0
- package/lib/utils/jq-sidecar.js +28 -0
- package/package.json +7 -6
- package/sidecar/jq/README.md +24 -0
- package/sidecar/jq/darwin-arm64/jq +0 -0
- package/sidecar/jq/darwin-x64/jq +0 -0
- package/sidecar/jq/linux-arm64/jq +0 -0
- package/sidecar/jq/linux-x64/jq +0 -0
- package/sidecar/jq/win32-x64/jq.exe +0 -0
|
@@ -6,10 +6,12 @@
|
|
|
6
6
|
* - `compress` — Single-line JSON envelope (default).
|
|
7
7
|
* - `pretty` — Human-readable plain-text layout.
|
|
8
8
|
*
|
|
9
|
-
* Supports `--jq` post-filtering in `json` / `compress` modes via
|
|
10
|
-
*
|
|
9
|
+
* Supports `--jq` post-filtering in `json` / `compress` modes via a jq binary
|
|
10
|
+
* resolved from `JQ_PATH` or the system `PATH`.
|
|
11
11
|
*/
|
|
12
12
|
import type { CommandResult, OutputFormat, Risk } from "./types.js";
|
|
13
|
+
import { type JqBinaryResolverOptions } from "../utils/apply-jq-filter.js";
|
|
14
|
+
import { type CliErrorsShape } from "../errors.js";
|
|
13
15
|
/** Shared options passed through every internal print function. */
|
|
14
16
|
interface OutputOptions {
|
|
15
17
|
/** Full command label (e.g. `"api list"`). */
|
|
@@ -23,6 +25,15 @@ interface OutputOptions {
|
|
|
23
25
|
/** Optional jq expression for post-filtering (json/compress modes only). */
|
|
24
26
|
jqFilter?: string;
|
|
25
27
|
}
|
|
28
|
+
/**
|
|
29
|
+
* Options for constructing a CLI-specific output formatter.
|
|
30
|
+
*/
|
|
31
|
+
export interface CreateFormatOutputOptions {
|
|
32
|
+
/** Error factory used when jq execution fails. */
|
|
33
|
+
cliErrors?: Pick<CliErrorsShape, "validation">;
|
|
34
|
+
/** jq binary resolution strategy for this concrete CLI. */
|
|
35
|
+
jqBinaryResolverOptions?: JqBinaryResolverOptions;
|
|
36
|
+
}
|
|
26
37
|
/**
|
|
27
38
|
* Central formatting entry point used by the runner adapter.
|
|
28
39
|
*
|
|
@@ -41,5 +52,7 @@ interface OutputOptions {
|
|
|
41
52
|
* formatOutput({ ok: true, data: { id: 1 } }, { command: "app list", risk: "read", format: "compress" });
|
|
42
53
|
* ```
|
|
43
54
|
*/
|
|
44
|
-
export declare function
|
|
55
|
+
export declare function createFormatOutput(options?: CreateFormatOutputOptions): <T>(result: CommandResult<T>, outputOptions: OutputOptions) => void;
|
|
56
|
+
/** Default framework formatter using `JQ_PATH` / `PATH` resolution only. */
|
|
57
|
+
export declare const formatOutput: <T>(result: CommandResult<T>, outputOptions: OutputOptions) => void;
|
|
45
58
|
export {};
|
package/lib/framework/output.js
CHANGED
|
@@ -6,18 +6,18 @@
|
|
|
6
6
|
* - `compress` — Single-line JSON envelope (default).
|
|
7
7
|
* - `pretty` — Human-readable plain-text layout.
|
|
8
8
|
*
|
|
9
|
-
* Supports `--jq` post-filtering in `json` / `compress` modes via
|
|
10
|
-
*
|
|
9
|
+
* Supports `--jq` post-filtering in `json` / `compress` modes via a jq binary
|
|
10
|
+
* resolved from `JQ_PATH` or the system `PATH`.
|
|
11
11
|
*/
|
|
12
12
|
import chalk from "chalk";
|
|
13
13
|
import { createJqFilter } from "../utils/apply-jq-filter.js";
|
|
14
14
|
import { createCliErrors } from "../errors.js";
|
|
15
|
-
const
|
|
15
|
+
const DEFAULT_CLI_ERRORS = createCliErrors({
|
|
16
16
|
cliBinName: "cli",
|
|
17
17
|
authRequiredHint: "",
|
|
18
18
|
configMissingHint: "",
|
|
19
19
|
notInProjectHint: "",
|
|
20
|
-
})
|
|
20
|
+
});
|
|
21
21
|
/**
|
|
22
22
|
* Central formatting entry point used by the runner adapter.
|
|
23
23
|
*
|
|
@@ -36,20 +36,25 @@ const applyJqFilter = createJqFilter(createCliErrors({
|
|
|
36
36
|
* formatOutput({ ok: true, data: { id: 1 } }, { command: "app list", risk: "read", format: "compress" });
|
|
37
37
|
* ```
|
|
38
38
|
*/
|
|
39
|
-
export function
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
39
|
+
export function createFormatOutput(options = {}) {
|
|
40
|
+
const applyJqFilter = createJqFilter(options.cliErrors ?? DEFAULT_CLI_ERRORS, options.jqBinaryResolverOptions);
|
|
41
|
+
return function formatOutput(result, outputOptions) {
|
|
42
|
+
switch (outputOptions.format) {
|
|
43
|
+
case "json":
|
|
44
|
+
printJson(result, outputOptions, applyJqFilter);
|
|
45
|
+
break;
|
|
46
|
+
case "compress":
|
|
47
|
+
printCompress(result, outputOptions, applyJqFilter);
|
|
48
|
+
break;
|
|
49
|
+
case "pretty":
|
|
50
|
+
default:
|
|
51
|
+
printPretty(result, outputOptions);
|
|
52
|
+
break;
|
|
53
|
+
}
|
|
54
|
+
};
|
|
52
55
|
}
|
|
56
|
+
/** Default framework formatter using `JQ_PATH` / `PATH` resolution only. */
|
|
57
|
+
export const formatOutput = createFormatOutput();
|
|
53
58
|
/**
|
|
54
59
|
* Wraps the command result in an {@link OutputEnvelope} by merging the
|
|
55
60
|
* command metadata from `options` and the result data / error.
|
|
@@ -81,8 +86,8 @@ function buildEnvelope(result, options) {
|
|
|
81
86
|
* @param result - The command result to serialize.
|
|
82
87
|
* @param options - Output options including jq filter.
|
|
83
88
|
*/
|
|
84
|
-
function printJson(result, options) {
|
|
85
|
-
writeJsonWithOptionalJq(`${JSON.stringify(buildEnvelope(result, options), null, 2)}\n`, options);
|
|
89
|
+
function printJson(result, options, applyJqFilter) {
|
|
90
|
+
writeJsonWithOptionalJq(`${JSON.stringify(buildEnvelope(result, options), null, 2)}\n`, options, applyJqFilter);
|
|
86
91
|
}
|
|
87
92
|
/**
|
|
88
93
|
* Formats and prints the result as single-line (compact) JSON.
|
|
@@ -91,8 +96,8 @@ function printJson(result, options) {
|
|
|
91
96
|
* @param result - The command result to serialize.
|
|
92
97
|
* @param options - Output options including jq filter.
|
|
93
98
|
*/
|
|
94
|
-
function printCompress(result, options) {
|
|
95
|
-
writeJsonWithOptionalJq(`${JSON.stringify(buildEnvelope(result, options))}\n`, options);
|
|
99
|
+
function printCompress(result, options, applyJqFilter) {
|
|
100
|
+
writeJsonWithOptionalJq(`${JSON.stringify(buildEnvelope(result, options))}\n`, options, applyJqFilter);
|
|
96
101
|
}
|
|
97
102
|
/**
|
|
98
103
|
* Writes a JSON string to stdout, optionally piping it through `jq`.
|
|
@@ -100,7 +105,7 @@ function printCompress(result, options) {
|
|
|
100
105
|
* @param jsonLine - Complete JSON line (must end with `\n`).
|
|
101
106
|
* @param options - Output options carrying the jq expression.
|
|
102
107
|
*/
|
|
103
|
-
function writeJsonWithOptionalJq(jsonLine, options) {
|
|
108
|
+
function writeJsonWithOptionalJq(jsonLine, options, applyJqFilter) {
|
|
104
109
|
const expr = options.jqFilter?.trim();
|
|
105
110
|
if (!expr) {
|
|
106
111
|
process.stdout.write(jsonLine);
|
package/lib/index.d.ts
CHANGED
|
@@ -205,5 +205,12 @@ Paging,
|
|
|
205
205
|
* @description List response wrapper with records and optional paging.
|
|
206
206
|
*/
|
|
207
207
|
ListResponse, } from "./framework/response.js";
|
|
208
|
-
export { formatOutput } from "./framework/output.js";
|
|
208
|
+
export { createFormatOutput, formatOutput } from "./framework/output.js";
|
|
209
|
+
export type {
|
|
210
|
+
/**
|
|
211
|
+
* @see ./framework/output.ts
|
|
212
|
+
* @description Options for constructing a CLI-specific output formatter.
|
|
213
|
+
*/
|
|
214
|
+
CreateFormatOutputOptions, } from "./framework/output.js";
|
|
215
|
+
export { resolveBundledJqPaths } from "./utils/jq-sidecar.js";
|
|
209
216
|
export { createJqFilter } from "./utils/apply-jq-filter.js";
|
package/lib/index.js
CHANGED
|
@@ -47,6 +47,8 @@ extractList,
|
|
|
47
47
|
/** @see ./framework/response.ts */
|
|
48
48
|
extractPaging, } from "./framework/response.js";
|
|
49
49
|
// ─── Output Formatting ─────────────────────────────────────────────────────────
|
|
50
|
-
export { formatOutput } from "./framework/output.js";
|
|
50
|
+
export { createFormatOutput, formatOutput } from "./framework/output.js";
|
|
51
|
+
// ─── Bundled jq Sidecar ────────────────────────────────────────────────────────
|
|
52
|
+
export { resolveBundledJqPaths } from "./utils/jq-sidecar.js";
|
|
51
53
|
// ─── JQ Filter ────────────────────────────────────────────────────────────────
|
|
52
54
|
export { createJqFilter } from "./utils/apply-jq-filter.js";
|
|
@@ -7,12 +7,66 @@
|
|
|
7
7
|
* or `--format compress`.
|
|
8
8
|
*
|
|
9
9
|
* The jq binary is resolved in this order:
|
|
10
|
-
* 1.
|
|
11
|
-
* 2.
|
|
10
|
+
* 1. `JQ_PATH` when explicitly provided.
|
|
11
|
+
* 2. An optional bundled jq candidate path injected by the host CLI.
|
|
12
|
+
* 3. A `jq` executable found on `PATH`.
|
|
12
13
|
*
|
|
13
14
|
* @module apply-jq-filter
|
|
14
15
|
*/
|
|
15
16
|
import type { CliErrorsShape } from "../errors.js";
|
|
17
|
+
/** Source used to resolve the jq binary. */
|
|
18
|
+
export type JqBinarySource = "env" | "bundled" | "path";
|
|
19
|
+
/**
|
|
20
|
+
* Options controlling how a jq executable is discovered.
|
|
21
|
+
*/
|
|
22
|
+
export interface JqBinaryResolverOptions {
|
|
23
|
+
/**
|
|
24
|
+
* Explicit bundled jq candidates supplied by the host CLI.
|
|
25
|
+
*
|
|
26
|
+
* The first existing path wins.
|
|
27
|
+
*/
|
|
28
|
+
bundledJqPaths?: readonly string[];
|
|
29
|
+
/**
|
|
30
|
+
* Environment map used for resolution.
|
|
31
|
+
*
|
|
32
|
+
* Defaults to `process.env`; exposed for tests.
|
|
33
|
+
*/
|
|
34
|
+
env?: NodeJS.ProcessEnv;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Result returned by jq binary resolution.
|
|
38
|
+
*/
|
|
39
|
+
export interface ResolvedJqBinary {
|
|
40
|
+
/** Command or absolute file path passed to `execFileSync`. */
|
|
41
|
+
command: string;
|
|
42
|
+
/** Resolution source used for the command. */
|
|
43
|
+
source: JqBinarySource;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Thrown when `JQ_PATH` is present but does not point to an existing file.
|
|
47
|
+
*/
|
|
48
|
+
export declare class JqBinaryResolutionError extends Error {
|
|
49
|
+
readonly jqPath: string;
|
|
50
|
+
/** Stable machine-readable error code. */
|
|
51
|
+
code: string;
|
|
52
|
+
/**
|
|
53
|
+
* @param jqPath - Invalid path supplied through `JQ_PATH`.
|
|
54
|
+
*/
|
|
55
|
+
constructor(jqPath: string);
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Resolves the jq executable for the current process.
|
|
59
|
+
*
|
|
60
|
+
* Resolution order:
|
|
61
|
+
* 1. `JQ_PATH`
|
|
62
|
+
* 2. injected bundled jq candidates
|
|
63
|
+
* 3. `jq` on `PATH`
|
|
64
|
+
*
|
|
65
|
+
* @param options - Resolution options including env overrides and bundled paths.
|
|
66
|
+
* @returns The command/path to execute and its source.
|
|
67
|
+
* @throws {@link JqBinaryResolutionError} if `JQ_PATH` is set but missing.
|
|
68
|
+
*/
|
|
69
|
+
export declare function resolveJqBinary(options?: JqBinaryResolverOptions): ResolvedJqBinary;
|
|
16
70
|
/**
|
|
17
71
|
* Creates a jq filter function bound to a specific error factory.
|
|
18
72
|
*
|
|
@@ -21,6 +75,7 @@ import type { CliErrorsShape } from "../errors.js";
|
|
|
21
75
|
* throws a typed {@link CliError} with code `"validation_error"`.
|
|
22
76
|
*
|
|
23
77
|
* @param cliErrors - Error factory providing `validation` for error reporting.
|
|
78
|
+
* @param options - Optional jq binary resolution customizations.
|
|
24
79
|
* @returns An `applyJqFilter(jsonInput, expr)` function.
|
|
25
80
|
*
|
|
26
81
|
* @example
|
|
@@ -30,4 +85,4 @@ import type { CliErrorsShape } from "../errors.js";
|
|
|
30
85
|
* // filtered === "1\n"
|
|
31
86
|
* ```
|
|
32
87
|
*/
|
|
33
|
-
export declare function createJqFilter(cliErrors: Pick<CliErrorsShape, "validation"
|
|
88
|
+
export declare function createJqFilter(cliErrors: Pick<CliErrorsShape, "validation">, options?: JqBinaryResolverOptions): (jsonInput: string, expr: string) => string;
|
|
@@ -7,17 +7,62 @@
|
|
|
7
7
|
* or `--format compress`.
|
|
8
8
|
*
|
|
9
9
|
* The jq binary is resolved in this order:
|
|
10
|
-
* 1.
|
|
11
|
-
* 2.
|
|
10
|
+
* 1. `JQ_PATH` when explicitly provided.
|
|
11
|
+
* 2. An optional bundled jq candidate path injected by the host CLI.
|
|
12
|
+
* 3. A `jq` executable found on `PATH`.
|
|
12
13
|
*
|
|
13
14
|
* @module apply-jq-filter
|
|
14
15
|
*/
|
|
15
16
|
import { execFileSync } from "node:child_process";
|
|
16
17
|
import { existsSync } from "node:fs";
|
|
17
|
-
import { createRequire } from "node:module";
|
|
18
|
-
import path from "node:path";
|
|
19
18
|
/** Maximum stdout buffer for the jq process (50 MB). */
|
|
20
19
|
const MAX_BUFFER = 50 * 1024 * 1024;
|
|
20
|
+
/** Error code used when `JQ_PATH` points to a missing executable. */
|
|
21
|
+
const INVALID_JQ_PATH_CODE = "jq_path_invalid";
|
|
22
|
+
/**
|
|
23
|
+
* Thrown when `JQ_PATH` is present but does not point to an existing file.
|
|
24
|
+
*/
|
|
25
|
+
export class JqBinaryResolutionError extends Error {
|
|
26
|
+
jqPath;
|
|
27
|
+
/** Stable machine-readable error code. */
|
|
28
|
+
code = INVALID_JQ_PATH_CODE;
|
|
29
|
+
/**
|
|
30
|
+
* @param jqPath - Invalid path supplied through `JQ_PATH`.
|
|
31
|
+
*/
|
|
32
|
+
constructor(jqPath) {
|
|
33
|
+
super(`JQ_PATH points to a missing jq executable: ${jqPath}`);
|
|
34
|
+
this.jqPath = jqPath;
|
|
35
|
+
this.name = "JqBinaryResolutionError";
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Resolves the jq executable for the current process.
|
|
40
|
+
*
|
|
41
|
+
* Resolution order:
|
|
42
|
+
* 1. `JQ_PATH`
|
|
43
|
+
* 2. injected bundled jq candidates
|
|
44
|
+
* 3. `jq` on `PATH`
|
|
45
|
+
*
|
|
46
|
+
* @param options - Resolution options including env overrides and bundled paths.
|
|
47
|
+
* @returns The command/path to execute and its source.
|
|
48
|
+
* @throws {@link JqBinaryResolutionError} if `JQ_PATH` is set but missing.
|
|
49
|
+
*/
|
|
50
|
+
export function resolveJqBinary(options = {}) {
|
|
51
|
+
const env = options.env ?? process.env;
|
|
52
|
+
const jqPath = readJqPath(env);
|
|
53
|
+
if (jqPath) {
|
|
54
|
+
if (!existsSync(jqPath)) {
|
|
55
|
+
throw new JqBinaryResolutionError(jqPath);
|
|
56
|
+
}
|
|
57
|
+
return { command: jqPath, source: "env" };
|
|
58
|
+
}
|
|
59
|
+
for (const candidate of options.bundledJqPaths ?? []) {
|
|
60
|
+
if (candidate && existsSync(candidate)) {
|
|
61
|
+
return { command: candidate, source: "bundled" };
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
return { command: "jq", source: "path" };
|
|
65
|
+
}
|
|
21
66
|
/**
|
|
22
67
|
* Creates a jq filter function bound to a specific error factory.
|
|
23
68
|
*
|
|
@@ -26,6 +71,7 @@ const MAX_BUFFER = 50 * 1024 * 1024;
|
|
|
26
71
|
* throws a typed {@link CliError} with code `"validation_error"`.
|
|
27
72
|
*
|
|
28
73
|
* @param cliErrors - Error factory providing `validation` for error reporting.
|
|
74
|
+
* @param options - Optional jq binary resolution customizations.
|
|
29
75
|
* @returns An `applyJqFilter(jsonInput, expr)` function.
|
|
30
76
|
*
|
|
31
77
|
* @example
|
|
@@ -35,7 +81,7 @@ const MAX_BUFFER = 50 * 1024 * 1024;
|
|
|
35
81
|
* // filtered === "1\n"
|
|
36
82
|
* ```
|
|
37
83
|
*/
|
|
38
|
-
export function createJqFilter(cliErrors) {
|
|
84
|
+
export function createJqFilter(cliErrors, options = {}) {
|
|
39
85
|
/**
|
|
40
86
|
* Applies a jq expression filter to a JSON input string.
|
|
41
87
|
*
|
|
@@ -48,7 +94,17 @@ export function createJqFilter(cliErrors) {
|
|
|
48
94
|
* - The input is not valid JSON.
|
|
49
95
|
*/
|
|
50
96
|
return function applyJqFilter(jsonInput, expr) {
|
|
51
|
-
const
|
|
97
|
+
const env = options.env ?? process.env;
|
|
98
|
+
let jqCmd = "jq";
|
|
99
|
+
try {
|
|
100
|
+
jqCmd = resolveJqBinary(options).command;
|
|
101
|
+
}
|
|
102
|
+
catch (err) {
|
|
103
|
+
if (err instanceof JqBinaryResolutionError) {
|
|
104
|
+
throw cliErrors.validation(err.message, "Point JQ_PATH to a valid jq executable, unset it, or rely on the bundled/system jq.");
|
|
105
|
+
}
|
|
106
|
+
throw err;
|
|
107
|
+
}
|
|
52
108
|
try {
|
|
53
109
|
return execFileSync(jqCmd, [expr], {
|
|
54
110
|
input: jsonInput,
|
|
@@ -59,11 +115,11 @@ export function createJqFilter(cliErrors) {
|
|
|
59
115
|
}
|
|
60
116
|
catch (err) {
|
|
61
117
|
const e = err;
|
|
62
|
-
// jq binary not found
|
|
63
118
|
if (e.code === "ENOENT") {
|
|
64
|
-
throw cliErrors.validation(
|
|
65
|
-
|
|
66
|
-
|
|
119
|
+
throw cliErrors.validation(`--jq needs a jq binary. Checked ${describeResolutionTargets(env, options.bundledJqPaths)}.`, describeMissingBinaryHint(options.bundledJqPaths));
|
|
120
|
+
}
|
|
121
|
+
if (e.code === "EACCES") {
|
|
122
|
+
throw cliErrors.validation(`jq binary is not executable: ${jqCmd}`, "Fix the file permissions, point JQ_PATH to an executable jq binary, or install jq on PATH.");
|
|
67
123
|
}
|
|
68
124
|
const stderr = e.stderr?.toString?.().trim() ?? "";
|
|
69
125
|
const fallback = (e.message ?? String(err)).trim();
|
|
@@ -74,26 +130,48 @@ export function createJqFilter(cliErrors) {
|
|
|
74
130
|
};
|
|
75
131
|
}
|
|
76
132
|
/**
|
|
77
|
-
*
|
|
133
|
+
* Reads a normalized `JQ_PATH` value from the provided environment.
|
|
78
134
|
*
|
|
79
|
-
*
|
|
80
|
-
*
|
|
81
|
-
|
|
135
|
+
* @param env - Environment variables to inspect.
|
|
136
|
+
* @returns Trimmed `JQ_PATH` when set; otherwise `undefined`.
|
|
137
|
+
*/
|
|
138
|
+
function readJqPath(env) {
|
|
139
|
+
const raw = env.JQ_PATH;
|
|
140
|
+
if (typeof raw !== "string")
|
|
141
|
+
return undefined;
|
|
142
|
+
const trimmed = raw.trim();
|
|
143
|
+
return trimmed.length > 0 ? trimmed : undefined;
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* Builds a user-facing description of the jq binary search order.
|
|
82
147
|
*
|
|
83
|
-
* @
|
|
148
|
+
* @param env - Environment variables used for this resolution.
|
|
149
|
+
* @param bundledJqPaths - Bundled jq candidates supplied by the host CLI.
|
|
150
|
+
* @returns Human-readable search target description.
|
|
84
151
|
*/
|
|
85
|
-
function
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
const binDir = path.join(pkgDir, "bin");
|
|
90
|
-
const name = process.platform === "win32" ? "jq.exe" : "jq";
|
|
91
|
-
const bundled = path.join(binDir, name);
|
|
92
|
-
if (existsSync(bundled))
|
|
93
|
-
return bundled;
|
|
152
|
+
function describeResolutionTargets(env, bundledJqPaths) {
|
|
153
|
+
const targets = ["`jq` on PATH"];
|
|
154
|
+
if ((bundledJqPaths?.length ?? 0) > 0) {
|
|
155
|
+
targets.unshift("the bundled jq shipped with this CLI");
|
|
94
156
|
}
|
|
95
|
-
|
|
96
|
-
|
|
157
|
+
if (!readJqPath(env)) {
|
|
158
|
+
targets.unshift("`JQ_PATH`");
|
|
159
|
+
}
|
|
160
|
+
if (targets.length === 1)
|
|
161
|
+
return targets[0] ?? "`jq` on PATH";
|
|
162
|
+
if (targets.length === 2)
|
|
163
|
+
return `${targets[0]} and ${targets[1]}`;
|
|
164
|
+
return `${targets.slice(0, -1).join(", ")}, and ${targets.at(-1)}`;
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* Builds the remediation hint shown when jq cannot be found.
|
|
168
|
+
*
|
|
169
|
+
* @param bundledJqPaths - Bundled jq candidates supplied by the host CLI.
|
|
170
|
+
* @returns Human-readable remediation hint.
|
|
171
|
+
*/
|
|
172
|
+
function describeMissingBinaryHint(bundledJqPaths) {
|
|
173
|
+
if ((bundledJqPaths?.length ?? 0) > 0) {
|
|
174
|
+
return "Set JQ_PATH to a valid jq executable, reinstall the CLI if its bundled jq is missing, or install jq on PATH.";
|
|
97
175
|
}
|
|
98
|
-
return "jq";
|
|
176
|
+
return "Set JQ_PATH to a valid jq executable or install jq on PATH.";
|
|
99
177
|
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Resolves bundled jq candidate paths for the current runtime platform.
|
|
3
|
+
*
|
|
4
|
+
* The result is ordered from most preferred to least preferred. Callers should
|
|
5
|
+
* test the paths in order and use the first one that exists.
|
|
6
|
+
*
|
|
7
|
+
* @param platform - Node.js platform, defaults to `process.platform`.
|
|
8
|
+
* @param arch - Node.js architecture, defaults to `process.arch`.
|
|
9
|
+
* @returns Candidate absolute paths to bundled jq executables.
|
|
10
|
+
*/
|
|
11
|
+
export declare function resolveBundledJqPaths(platform?: NodeJS.Platform, arch?: NodeJS.Architecture): string[];
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
import { fileURLToPath } from "node:url";
|
|
3
|
+
/** Supported bundled jq targets keyed by `platform:arch`. */
|
|
4
|
+
const JQ_TARGETS = {
|
|
5
|
+
"darwin:arm64": ["darwin-arm64", "darwin-x64"],
|
|
6
|
+
"darwin:x64": ["darwin-x64"],
|
|
7
|
+
"linux:arm64": ["linux-arm64"],
|
|
8
|
+
"linux:x64": ["linux-x64"],
|
|
9
|
+
"win32:arm64": ["win32-x64"],
|
|
10
|
+
"win32:x64": ["win32-x64"],
|
|
11
|
+
};
|
|
12
|
+
const CURRENT_FILE = fileURLToPath(import.meta.url);
|
|
13
|
+
const PACKAGE_ROOT = path.resolve(path.dirname(CURRENT_FILE), "../..");
|
|
14
|
+
const SIDECAR_ROOT = path.join(PACKAGE_ROOT, "sidecar", "jq");
|
|
15
|
+
/**
|
|
16
|
+
* Resolves bundled jq candidate paths for the current runtime platform.
|
|
17
|
+
*
|
|
18
|
+
* The result is ordered from most preferred to least preferred. Callers should
|
|
19
|
+
* test the paths in order and use the first one that exists.
|
|
20
|
+
*
|
|
21
|
+
* @param platform - Node.js platform, defaults to `process.platform`.
|
|
22
|
+
* @param arch - Node.js architecture, defaults to `process.arch`.
|
|
23
|
+
* @returns Candidate absolute paths to bundled jq executables.
|
|
24
|
+
*/
|
|
25
|
+
export function resolveBundledJqPaths(platform = process.platform, arch = process.arch) {
|
|
26
|
+
const targetDirs = JQ_TARGETS[`${platform}:${arch}`] ?? [];
|
|
27
|
+
return targetDirs.map((dir) => path.join(SIDECAR_ROOT, dir, platform === "win32" ? "jq.exe" : "jq"));
|
|
28
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lovrabet/cli-framework",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.3",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "lib/index.js",
|
|
6
6
|
"types": "lib/index.d.ts",
|
|
@@ -11,25 +11,26 @@
|
|
|
11
11
|
}
|
|
12
12
|
},
|
|
13
13
|
"files": [
|
|
14
|
-
"lib"
|
|
14
|
+
"lib",
|
|
15
|
+
"sidecar"
|
|
15
16
|
],
|
|
16
17
|
"publishConfig": {
|
|
17
18
|
"access": "public"
|
|
18
19
|
},
|
|
19
20
|
"scripts": {
|
|
20
21
|
"build": "rm -rf lib && tsc && echo 'cli-framework build done'",
|
|
22
|
+
"update:jq-sidecar": "node scripts/update-jq-sidecar.mjs",
|
|
21
23
|
"beta-release": "sh scripts/update-beta-version.sh && bun run build && git push && git push origin --tag && bun publish --tag beta",
|
|
22
24
|
"release": "sh scripts/update-latest-version.sh && bun run build && git push && git push origin --tag && bun publish",
|
|
23
25
|
"typecheck": "tsc --noEmit",
|
|
24
26
|
"test": "vitest run"
|
|
25
27
|
},
|
|
26
28
|
"dependencies": {
|
|
27
|
-
"chalk": "^5.6.2"
|
|
28
|
-
"node-jq": "^6.3.1"
|
|
29
|
+
"chalk": "^5.6.2"
|
|
29
30
|
},
|
|
30
31
|
"devDependencies": {
|
|
31
32
|
"@types/node": "^24.5.2",
|
|
32
|
-
"typescript": "
|
|
33
|
+
"typescript": "5.9.3",
|
|
33
34
|
"vitest": "^4.1.2"
|
|
34
35
|
}
|
|
35
|
-
}
|
|
36
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
This directory vendors jq binaries that ship with `@lovrabet/cli-framework`.
|
|
2
|
+
|
|
3
|
+
Consumer CLIs such as `@lovrabet/rabetbase-cli` and `@lovrabet/lovrabet-cli`
|
|
4
|
+
resolve these binaries through the framework package.
|
|
5
|
+
|
|
6
|
+
- Upstream project: `jqlang/jq`
|
|
7
|
+
- Version: `jq-1.8.1`
|
|
8
|
+
- License: `MIT`
|
|
9
|
+
- Release source: `https://github.com/jqlang/jq/releases/tag/jq-1.8.1`
|
|
10
|
+
|
|
11
|
+
Bundled targets:
|
|
12
|
+
|
|
13
|
+
- `darwin-arm64/jq`
|
|
14
|
+
- `darwin-x64/jq`
|
|
15
|
+
- `linux-arm64/jq`
|
|
16
|
+
- `linux-x64/jq`
|
|
17
|
+
- `win32-x64/jq.exe`
|
|
18
|
+
|
|
19
|
+
Update policy:
|
|
20
|
+
|
|
21
|
+
1. Download binaries only from the official jq release assets.
|
|
22
|
+
2. Keep file names stable (`jq` / `jq.exe`) so runtime resolution stays simple.
|
|
23
|
+
3. Refresh the sidecar with `npm run update:jq-sidecar -- jq-<version>` when the bundled jq version changes.
|
|
24
|
+
4. Update this README when the bundled jq version changes.
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|