@naturalcycles/nodejs-lib 15.112.0 → 15.114.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/bin/generate-build-info.js +3 -3
- package/dist/bin/json2env.js +4 -4
- package/dist/bin/kpy.js +5 -7
- package/dist/bin/secrets-decrypt.js +6 -6
- package/dist/bin/secrets-encrypt.js +4 -5
- package/dist/bin/secrets-gen-key.js +7 -5
- package/dist/bin/slack-this.js +3 -3
- package/dist/cli/parseArgs.d.ts +126 -0
- package/dist/cli/parseArgs.js +120 -0
- package/dist/exec2/exec2.d.ts +11 -1
- package/dist/exec2/exec2.js +13 -2
- package/dist/validation/ajv/jSchema.d.ts +5 -5
- package/dist/zip/zipReader.d.ts +5 -0
- package/dist/zip/zipWriter.d.ts +7 -0
- package/package.json +5 -7
- package/src/bin/generate-build-info.ts +3 -3
- package/src/bin/json2env.ts +9 -6
- package/src/bin/kpy.ts +10 -9
- package/src/bin/secrets-decrypt.ts +6 -6
- package/src/bin/secrets-encrypt.ts +4 -5
- package/src/bin/secrets-gen-key.ts +7 -5
- package/src/bin/slack-this.ts +3 -3
- package/src/cli/parseArgs.ts +257 -0
- package/src/exec2/exec2.ts +27 -2
- package/src/stream/pipeline.ts +4 -4
- package/src/validation/ajv/from-data/generateJsonSchemaFromData.ts +6 -6
- package/dist/yargs/yargs.util.d.ts +0 -6
- package/dist/yargs/yargs.util.js +0 -11
- package/src/yargs/yargs.util.ts +0 -12
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import fs from 'node:fs';
|
|
2
2
|
import path from 'node:path';
|
|
3
|
+
import { _parseArgs } from '../cli/parseArgs.js';
|
|
3
4
|
import { appendToBashEnv, appendToGithubEnv, appendToGithubOutput } from '../fs/json2env.js';
|
|
4
5
|
import { runScript } from '../script/runScript.js';
|
|
5
6
|
import { generateBuildInfo } from '../util/buildInfo.util.js';
|
|
6
|
-
import { _yargs } from '../yargs/yargs.util.js';
|
|
7
7
|
runScript(async () => {
|
|
8
|
-
const { dir, overrideTimestamp } =
|
|
8
|
+
const { dir, overrideTimestamp } = _parseArgs({
|
|
9
9
|
dir: {
|
|
10
10
|
type: 'string',
|
|
11
11
|
desc: 'Output directory',
|
|
@@ -14,7 +14,7 @@ runScript(async () => {
|
|
|
14
14
|
type: 'number',
|
|
15
15
|
desc: 'This unix timestamp will be used instead of "current time"',
|
|
16
16
|
},
|
|
17
|
-
})
|
|
17
|
+
});
|
|
18
18
|
const buildInfo = generateBuildInfo({
|
|
19
19
|
overrideTimestamp: overrideTimestamp,
|
|
20
20
|
});
|
package/dist/bin/json2env.js
CHANGED
|
@@ -1,10 +1,8 @@
|
|
|
1
|
+
import { _parseArgs } from '../cli/parseArgs.js';
|
|
1
2
|
import { json2env } from '../fs/json2env.js';
|
|
2
3
|
import { runScript } from '../script/runScript.js';
|
|
3
|
-
import { _yargs } from '../yargs/yargs.util.js';
|
|
4
4
|
runScript(() => {
|
|
5
|
-
const
|
|
6
|
-
.demandCommand(1)
|
|
7
|
-
.options({
|
|
5
|
+
const argv = _parseArgs({
|
|
8
6
|
prefix: {
|
|
9
7
|
type: 'string',
|
|
10
8
|
},
|
|
@@ -34,6 +32,8 @@ runScript(() => {
|
|
|
34
32
|
silent: {
|
|
35
33
|
type: 'boolean',
|
|
36
34
|
},
|
|
35
|
+
}, {
|
|
36
|
+
minPositionals: 1,
|
|
37
37
|
});
|
|
38
38
|
const { _: args, prefix, saveEnvFile, bashEnv, githubEnv, fail, debug, silent } = argv;
|
|
39
39
|
if (debug)
|
package/dist/bin/kpy.js
CHANGED
|
@@ -1,10 +1,8 @@
|
|
|
1
|
+
import { _parseArgs } from '../cli/parseArgs.js';
|
|
1
2
|
import { kpySync } from '../fs/kpy.js';
|
|
2
3
|
import { runScript } from '../script/runScript.js';
|
|
3
|
-
import { _yargs } from '../yargs/yargs.util.js';
|
|
4
4
|
runScript(() => {
|
|
5
|
-
const { _: [baseDir, ...inputPatterns], ...opt } =
|
|
6
|
-
.demandCommand(2)
|
|
7
|
-
.options({
|
|
5
|
+
const { _: [baseDir, ...inputPatterns], ...opt } = _parseArgs({
|
|
8
6
|
silent: {
|
|
9
7
|
type: 'boolean',
|
|
10
8
|
desc: 'Suppress all text output',
|
|
@@ -28,9 +26,9 @@ runScript(() => {
|
|
|
28
26
|
},
|
|
29
27
|
move: {
|
|
30
28
|
type: 'boolean',
|
|
31
|
-
|
|
29
|
+
desc: 'Move files instead of copy',
|
|
32
30
|
},
|
|
33
|
-
})
|
|
31
|
+
}, { minPositionals: 2 });
|
|
34
32
|
const outputDir = inputPatterns.pop();
|
|
35
33
|
/*
|
|
36
34
|
console.log({
|
|
@@ -43,7 +41,7 @@ runScript(() => {
|
|
|
43
41
|
})*/
|
|
44
42
|
const kpyOpt = {
|
|
45
43
|
baseDir: baseDir,
|
|
46
|
-
inputPatterns
|
|
44
|
+
inputPatterns,
|
|
47
45
|
outputDir,
|
|
48
46
|
...opt,
|
|
49
47
|
noOverwrite: !opt.overwrite,
|
|
@@ -1,15 +1,16 @@
|
|
|
1
|
+
import { _parseArgs } from '../cli/parseArgs.js';
|
|
1
2
|
import { dimGrey } from '../colors/colors.js';
|
|
2
3
|
import { runScript } from '../script/runScript.js';
|
|
3
4
|
import { secretsDecrypt } from '../secret/secrets-decrypt.util.js';
|
|
4
|
-
import { _yargs } from '../yargs/yargs.util.js';
|
|
5
5
|
runScript(() => {
|
|
6
6
|
const { dir, file, encKeyBuffer, del, jsonMode } = getDecryptCLIOptions();
|
|
7
7
|
secretsDecrypt(dir, file, encKeyBuffer, del, jsonMode);
|
|
8
8
|
});
|
|
9
9
|
function getDecryptCLIOptions() {
|
|
10
|
-
let { dir, file, encKey, encKeyVar, del, jsonMode } =
|
|
10
|
+
let { dir, file, encKey, encKeyVar, del, jsonMode } = _parseArgs({
|
|
11
11
|
dir: {
|
|
12
|
-
type: '
|
|
12
|
+
type: 'string',
|
|
13
|
+
array: true,
|
|
13
14
|
desc: 'Directory with secrets. Can be many',
|
|
14
15
|
// demandOption: true,
|
|
15
16
|
default: './secret',
|
|
@@ -42,7 +43,7 @@ function getDecryptCLIOptions() {
|
|
|
42
43
|
desc: 'JSON mode. Encrypts only json values, not the whole file',
|
|
43
44
|
default: false,
|
|
44
45
|
},
|
|
45
|
-
})
|
|
46
|
+
});
|
|
46
47
|
if (!encKey) {
|
|
47
48
|
encKey = process.env[encKeyVar];
|
|
48
49
|
if (encKey) {
|
|
@@ -53,6 +54,5 @@ function getDecryptCLIOptions() {
|
|
|
53
54
|
}
|
|
54
55
|
}
|
|
55
56
|
const encKeyBuffer = Buffer.from(encKey, 'base64');
|
|
56
|
-
|
|
57
|
-
return { dir: dir, file, encKeyBuffer, del, jsonMode };
|
|
57
|
+
return { dir, file, encKeyBuffer, del, jsonMode };
|
|
58
58
|
}
|
|
@@ -1,13 +1,13 @@
|
|
|
1
|
+
import { _parseArgs } from '../cli/parseArgs.js';
|
|
1
2
|
import { dimGrey } from '../colors/colors.js';
|
|
2
3
|
import { runScript } from '../script/runScript.js';
|
|
3
4
|
import { secretsEncrypt } from '../secret/secrets-encrypt.util.js';
|
|
4
|
-
import { _yargs } from '../yargs/yargs.util.js';
|
|
5
5
|
runScript(() => {
|
|
6
6
|
const { pattern, file, encKeyBuffer, del, jsonMode } = getEncryptCLIOptions();
|
|
7
7
|
secretsEncrypt(pattern, file, encKeyBuffer, del, jsonMode);
|
|
8
8
|
});
|
|
9
9
|
function getEncryptCLIOptions() {
|
|
10
|
-
let { pattern, file, encKey, encKeyVar, del, jsonMode } =
|
|
10
|
+
let { pattern, file, encKey, encKeyVar, del, jsonMode } = _parseArgs({
|
|
11
11
|
pattern: {
|
|
12
12
|
type: 'string',
|
|
13
13
|
array: true,
|
|
@@ -44,7 +44,7 @@ function getEncryptCLIOptions() {
|
|
|
44
44
|
desc: 'JSON mode. Encrypts only json values, not the whole file',
|
|
45
45
|
default: false,
|
|
46
46
|
},
|
|
47
|
-
})
|
|
47
|
+
});
|
|
48
48
|
if (!encKey) {
|
|
49
49
|
encKey = process.env[encKeyVar];
|
|
50
50
|
if (encKey) {
|
|
@@ -55,6 +55,5 @@ function getEncryptCLIOptions() {
|
|
|
55
55
|
}
|
|
56
56
|
}
|
|
57
57
|
const encKeyBuffer = Buffer.from(encKey, 'base64');
|
|
58
|
-
|
|
59
|
-
return { pattern: pattern, file, encKeyBuffer, del, jsonMode };
|
|
58
|
+
return { pattern, file, encKeyBuffer, del, jsonMode };
|
|
60
59
|
}
|
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
import { randomBytes } from 'node:crypto';
|
|
2
|
+
import { _parseArgs } from '../cli/parseArgs.js';
|
|
2
3
|
import { dimGrey } from '../colors/colors.js';
|
|
3
4
|
import { runScript } from '../script/runScript.js';
|
|
4
|
-
import { _yargs } from '../yargs/yargs.util.js';
|
|
5
5
|
runScript(() => {
|
|
6
|
-
const { sizeBytes } =
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
6
|
+
const { sizeBytes } = _parseArgs({
|
|
7
|
+
sizeBytes: {
|
|
8
|
+
type: 'number',
|
|
9
|
+
default: 256,
|
|
10
|
+
},
|
|
11
|
+
});
|
|
10
12
|
const key = randomBytes(sizeBytes).toString('base64');
|
|
11
13
|
console.log(dimGrey('\nSECRET_ENCRYPTION_KEY:\n'));
|
|
12
14
|
console.log(key, '\n');
|
package/dist/bin/slack-this.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
+
import { _parseArgs } from '../cli/parseArgs.js';
|
|
1
2
|
import { runScript } from '../script/runScript.js';
|
|
2
3
|
import { SlackService } from '../slack/index.js';
|
|
3
|
-
import { _yargs } from '../yargs/yargs.util.js';
|
|
4
4
|
runScript(async () => {
|
|
5
|
-
const { channel, msg, username, emoji, webhook: webhookUrl, } =
|
|
5
|
+
const { channel, msg, username, emoji, webhook: webhookUrl, } = _parseArgs({
|
|
6
6
|
channel: {
|
|
7
7
|
type: 'string',
|
|
8
8
|
demandOption: true,
|
|
@@ -23,7 +23,7 @@ runScript(async () => {
|
|
|
23
23
|
type: 'string',
|
|
24
24
|
default: process.env.SLACK_WEBHOOK_URL,
|
|
25
25
|
},
|
|
26
|
-
})
|
|
26
|
+
});
|
|
27
27
|
if (!webhookUrl) {
|
|
28
28
|
console.log(`Slack webhook is required, either via env.SLACK_WEBHOOK_URL or --webhook`);
|
|
29
29
|
process.exit(1);
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Allowed CLI option value types.
|
|
3
|
+
*/
|
|
4
|
+
export type CliOptionType = 'string' | 'number' | 'boolean';
|
|
5
|
+
/**
|
|
6
|
+
* Declarative definition of a single CLI option, modeled after the subset of
|
|
7
|
+
* yargs `.options()` that we actually use.
|
|
8
|
+
*/
|
|
9
|
+
export interface CliOption {
|
|
10
|
+
type: CliOptionType;
|
|
11
|
+
/**
|
|
12
|
+
* Accept the flag multiple times, collecting values into an array.
|
|
13
|
+
* `--id a --id b` => `['a', 'b']`. Replaces yargs `type: 'array'`.
|
|
14
|
+
*/
|
|
15
|
+
array?: boolean;
|
|
16
|
+
/**
|
|
17
|
+
* Default value, applied when the flag is not provided.
|
|
18
|
+
* Providing a non-`undefined` default makes the output field non-optional.
|
|
19
|
+
*/
|
|
20
|
+
default?: string | number | boolean | readonly (string | number)[];
|
|
21
|
+
/**
|
|
22
|
+
* Mark the option as required. Throws/exits if not provided.
|
|
23
|
+
* Makes the output field non-optional.
|
|
24
|
+
*/
|
|
25
|
+
demandOption?: boolean;
|
|
26
|
+
/**
|
|
27
|
+
* Restrict the value to a set of allowed values. With a `const` call (the
|
|
28
|
+
* default here) the output type is narrowed to the union of the literals.
|
|
29
|
+
*/
|
|
30
|
+
choices?: readonly (string | number)[];
|
|
31
|
+
/**
|
|
32
|
+
* Help text, shown in `--help` output.
|
|
33
|
+
*/
|
|
34
|
+
desc?: string;
|
|
35
|
+
/**
|
|
36
|
+
* Single-character alias, e.g. `short: 'v'` enables `-v`.
|
|
37
|
+
*/
|
|
38
|
+
short?: string;
|
|
39
|
+
}
|
|
40
|
+
export type CliOptions = Record<string, CliOption>;
|
|
41
|
+
/**
|
|
42
|
+
* Element value type of a single option, derived from `choices` (if present)
|
|
43
|
+
* or `type`.
|
|
44
|
+
*/
|
|
45
|
+
type ElemType<O extends CliOption> = O extends {
|
|
46
|
+
choices: readonly (infer C)[];
|
|
47
|
+
} ? C : O['type'] extends 'string' ? string : O['type'] extends 'number' ? number : O['type'] extends 'boolean' ? boolean : never;
|
|
48
|
+
/**
|
|
49
|
+
* Full value type of a single option, applying `array` on top of the element
|
|
50
|
+
* type.
|
|
51
|
+
*/
|
|
52
|
+
type ValueType<O extends CliOption> = O extends {
|
|
53
|
+
array: true;
|
|
54
|
+
} ? ElemType<O>[] : ElemType<O>;
|
|
55
|
+
/**
|
|
56
|
+
* An option is "required" (non-optional in the output) when it is `demandOption`
|
|
57
|
+
* or has a non-`undefined` `default`. `NonNullable<unknown>` matches any
|
|
58
|
+
* non-null/undefined value, so `default: false | 0 | ''` correctly counts as
|
|
59
|
+
* present, while `default: process.env.X` (which may be `undefined`) stays optional.
|
|
60
|
+
*/
|
|
61
|
+
type IsRequired<O extends CliOption> = O extends {
|
|
62
|
+
demandOption: true;
|
|
63
|
+
} ? true : O extends {
|
|
64
|
+
default: NonNullable<unknown>;
|
|
65
|
+
} ? true : false;
|
|
66
|
+
/**
|
|
67
|
+
* Flattens an intersection into a single object type for nicer hovers.
|
|
68
|
+
*/
|
|
69
|
+
type Simplify<T> = {
|
|
70
|
+
[K in keyof T]: T[K];
|
|
71
|
+
} & {};
|
|
72
|
+
/**
|
|
73
|
+
* Output type inferred from the options config - the clean `@types/yargs@16`
|
|
74
|
+
* shape: exactly the declared keys with correct optionality, plus `_` for
|
|
75
|
+
* positionals. No `[x: string]: unknown` index signature, no camelCase/kebab
|
|
76
|
+
* key duplication (the `@types/yargs@17` noise).
|
|
77
|
+
*/
|
|
78
|
+
export type InferCliArgs<O extends CliOptions> = Simplify<{
|
|
79
|
+
[K in keyof O as IsRequired<O[K]> extends true ? K : never]: ValueType<O[K]>;
|
|
80
|
+
} & {
|
|
81
|
+
[K in keyof O as IsRequired<O[K]> extends true ? never : K]?: ValueType<O[K]>;
|
|
82
|
+
} & {
|
|
83
|
+
/** Positional arguments (yargs `_`). */
|
|
84
|
+
_: string[];
|
|
85
|
+
}>;
|
|
86
|
+
export interface ParseArgsOptions {
|
|
87
|
+
/**
|
|
88
|
+
* Args to parse. Defaults to `process.argv.slice(2)` (no `hideBin` needed).
|
|
89
|
+
*/
|
|
90
|
+
args?: string[];
|
|
91
|
+
/**
|
|
92
|
+
* Require at least this many positional args. Replaces yargs `.demandCommand`.
|
|
93
|
+
*/
|
|
94
|
+
minPositionals?: number;
|
|
95
|
+
/**
|
|
96
|
+
* Usage line shown at the top of `--help`.
|
|
97
|
+
*/
|
|
98
|
+
usage?: string;
|
|
99
|
+
/**
|
|
100
|
+
* When `true`, unknown options throw a {@link ParseArgsError}.
|
|
101
|
+
* When `false` (default), unknown options are silently ignored - matching
|
|
102
|
+
* yargs' default lenient behavior. Important when several parsers read the
|
|
103
|
+
* same `process.argv` and each only knows about its own subset of options.
|
|
104
|
+
*/
|
|
105
|
+
strict?: boolean;
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Thrown by {@link _parseArgs} on invalid input (missing/invalid option,
|
|
109
|
+
* too few positionals). Unknown options are ignored, not rejected.
|
|
110
|
+
*/
|
|
111
|
+
export declare class ParseArgsError extends Error {
|
|
112
|
+
name: string;
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* In-house, type-inferred replacement for `yargs().options(...).argv`, built on
|
|
116
|
+
* top of node's `util.parseArgs`.
|
|
117
|
+
*
|
|
118
|
+
* @example
|
|
119
|
+
* const { dir, limit } = _parseArgs({
|
|
120
|
+
* dir: { type: 'string', desc: 'Output directory' },
|
|
121
|
+
* limit: { type: 'number', default: 100 },
|
|
122
|
+
* })
|
|
123
|
+
* // dir?: string limit: number _: string[]
|
|
124
|
+
*/
|
|
125
|
+
export declare function _parseArgs<const O extends CliOptions>(options: O, opt?: ParseArgsOptions): InferCliArgs<O>;
|
|
126
|
+
export {};
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import { parseArgs } from 'node:util';
|
|
2
|
+
/**
|
|
3
|
+
* Thrown by {@link _parseArgs} on invalid input (missing/invalid option,
|
|
4
|
+
* too few positionals). Unknown options are ignored, not rejected.
|
|
5
|
+
*/
|
|
6
|
+
export class ParseArgsError extends Error {
|
|
7
|
+
name = 'ParseArgsError';
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* In-house, type-inferred replacement for `yargs().options(...).argv`, built on
|
|
11
|
+
* top of node's `util.parseArgs`.
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* const { dir, limit } = _parseArgs({
|
|
15
|
+
* dir: { type: 'string', desc: 'Output directory' },
|
|
16
|
+
* limit: { type: 'number', default: 100 },
|
|
17
|
+
* })
|
|
18
|
+
* // dir?: string limit: number _: string[]
|
|
19
|
+
*/
|
|
20
|
+
export function _parseArgs(options, opt = {}) {
|
|
21
|
+
const { args, minPositionals = 0, usage, strict = false } = opt;
|
|
22
|
+
// node's parseArgs only supports string|boolean, so `number` is parsed as a
|
|
23
|
+
// string and coerced afterwards. We also never forward `default` (parseArgs
|
|
24
|
+
// rejects e.g. a numeric default on a string-typed option) - defaults are
|
|
25
|
+
// applied by us below.
|
|
26
|
+
const nodeOptions = options['help'] ? {} : { help: { type: 'boolean', short: 'h' } };
|
|
27
|
+
for (const [name, def] of Object.entries(options)) {
|
|
28
|
+
// parseArgs rejects `undefined` for `short`/`multiple`, so only set when present
|
|
29
|
+
const nodeOption = {
|
|
30
|
+
type: def.type === 'boolean' ? 'boolean' : 'string',
|
|
31
|
+
};
|
|
32
|
+
if (def.array)
|
|
33
|
+
nodeOption.multiple = true;
|
|
34
|
+
if (def.short)
|
|
35
|
+
nodeOption.short = def.short;
|
|
36
|
+
nodeOptions[name] = nodeOption;
|
|
37
|
+
}
|
|
38
|
+
const parsed = (() => {
|
|
39
|
+
try {
|
|
40
|
+
return parseArgs({
|
|
41
|
+
args,
|
|
42
|
+
options: nodeOptions,
|
|
43
|
+
allowPositionals: true,
|
|
44
|
+
allowNegative: true, // native `--no-flag` support for booleans
|
|
45
|
+
// In non-strict mode, unknown options are collected into `values` but
|
|
46
|
+
// ignored below, since we only read declared options. See `strict` docs.
|
|
47
|
+
strict,
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
catch (err) {
|
|
51
|
+
throw new ParseArgsError(err.message);
|
|
52
|
+
}
|
|
53
|
+
})();
|
|
54
|
+
const values = parsed.values;
|
|
55
|
+
if (!options['help'] && values['help']) {
|
|
56
|
+
process.stdout.write(buildHelp(options, usage));
|
|
57
|
+
process.exit(0);
|
|
58
|
+
}
|
|
59
|
+
const result = { _: parsed.positionals };
|
|
60
|
+
for (const [name, def] of Object.entries(options)) {
|
|
61
|
+
let v = values[name];
|
|
62
|
+
if (v === undefined) {
|
|
63
|
+
if (def.default !== undefined) {
|
|
64
|
+
v = def.default;
|
|
65
|
+
}
|
|
66
|
+
else if (def.demandOption) {
|
|
67
|
+
throw new ParseArgsError(`Missing required option: --${name}`);
|
|
68
|
+
}
|
|
69
|
+
else {
|
|
70
|
+
continue; // leave absent
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
// normalize to array (e.g. a scalar default on an `array` option)
|
|
74
|
+
if (def.array) {
|
|
75
|
+
v = Array.isArray(v) ? v : [v];
|
|
76
|
+
}
|
|
77
|
+
if (def.type === 'number') {
|
|
78
|
+
v = Array.isArray(v) ? v.map(x => toNumber(x, name)) : toNumber(v, name);
|
|
79
|
+
}
|
|
80
|
+
if (def.choices) {
|
|
81
|
+
const list = Array.isArray(v) ? v : [v];
|
|
82
|
+
for (const x of list) {
|
|
83
|
+
if (!def.choices.includes(x)) {
|
|
84
|
+
throw new ParseArgsError(`Invalid value for --${name}: "${x}". Choices: ${def.choices.join(', ')}`);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
result[name] = v;
|
|
89
|
+
}
|
|
90
|
+
if (parsed.positionals.length < minPositionals) {
|
|
91
|
+
throw new ParseArgsError(`Expected at least ${minPositionals} positional argument(s), got ${parsed.positionals.length}`);
|
|
92
|
+
}
|
|
93
|
+
return result;
|
|
94
|
+
}
|
|
95
|
+
function toNumber(raw, name) {
|
|
96
|
+
const n = Number(raw);
|
|
97
|
+
if (Number.isNaN(n)) {
|
|
98
|
+
throw new ParseArgsError(`Invalid number for --${name}: "${raw}"`);
|
|
99
|
+
}
|
|
100
|
+
return n;
|
|
101
|
+
}
|
|
102
|
+
function buildHelp(options, usage) {
|
|
103
|
+
const lines = [];
|
|
104
|
+
if (usage)
|
|
105
|
+
lines.push(usage, '');
|
|
106
|
+
lines.push('Options:');
|
|
107
|
+
for (const [name, def] of Object.entries(options)) {
|
|
108
|
+
const flag = def.short ? `-${def.short}, --${name}` : `--${name}`;
|
|
109
|
+
const meta = [`[${def.array ? `${def.type}[]` : def.type}]`];
|
|
110
|
+
if (def.demandOption)
|
|
111
|
+
meta.push('[required]');
|
|
112
|
+
if (def.default !== undefined)
|
|
113
|
+
meta.push(`[default: ${JSON.stringify(def.default)}]`);
|
|
114
|
+
if (def.choices)
|
|
115
|
+
meta.push(`[choices: ${def.choices.join(', ')}]`);
|
|
116
|
+
lines.push(` ${flag} ${meta.join(' ')}${def.desc ? ` ${def.desc}` : ''}`);
|
|
117
|
+
}
|
|
118
|
+
lines.push(' -h, --help Show help');
|
|
119
|
+
return `${lines.join('\n')}\n`;
|
|
120
|
+
}
|
package/dist/exec2/exec2.d.ts
CHANGED
|
@@ -37,7 +37,7 @@ declare class Exec2 {
|
|
|
37
37
|
* shell: true
|
|
38
38
|
* log: true
|
|
39
39
|
*/
|
|
40
|
-
spawn(cmd: string, opt?:
|
|
40
|
+
spawn(cmd: string, opt?: SpawnSyncOptions): void;
|
|
41
41
|
/**
|
|
42
42
|
* Reasons to use it:
|
|
43
43
|
*
|
|
@@ -105,6 +105,12 @@ export interface SpawnOutput {
|
|
|
105
105
|
stdout: string;
|
|
106
106
|
stderr: string;
|
|
107
107
|
}
|
|
108
|
+
export interface SpawnSyncOptions extends SpawnOptions {
|
|
109
|
+
/**
|
|
110
|
+
* Defaults to 10 MiB (higher than Node's own default of 1 MiB).
|
|
111
|
+
*/
|
|
112
|
+
maxBuffer?: number;
|
|
113
|
+
}
|
|
108
114
|
export interface SpawnAsyncOptions extends SpawnOptions {
|
|
109
115
|
/**
|
|
110
116
|
* Defaults to true.
|
|
@@ -202,5 +208,9 @@ export interface ExecOptions {
|
|
|
202
208
|
* beware that stdio: 'inherit', means we don't get the output returned.
|
|
203
209
|
*/
|
|
204
210
|
stdio?: StdioOptions;
|
|
211
|
+
/**
|
|
212
|
+
* Defaults to 10 MiB (higher than Node's own default of 1 MiB).
|
|
213
|
+
*/
|
|
214
|
+
maxBuffer?: number;
|
|
205
215
|
}
|
|
206
216
|
export {};
|
package/dist/exec2/exec2.js
CHANGED
|
@@ -3,6 +3,15 @@ import { _since } from '@naturalcycles/js-lib/datetime/time.util.js';
|
|
|
3
3
|
import { AppError } from '@naturalcycles/js-lib/error/error.util.js';
|
|
4
4
|
import { _substringAfterLast } from '@naturalcycles/js-lib/string/string.util.js';
|
|
5
5
|
import { dimGrey, dimRed, hasColors, white } from '../colors/colors.js';
|
|
6
|
+
/**
|
|
7
|
+
* Default `maxBuffer` (in bytes) for the synchronous `exec`/`spawn`.
|
|
8
|
+
* Set to 10 MiB, which is higher than Node's own default of 1 MiB.
|
|
9
|
+
* Node's 1 MiB is too low for common large outputs (e.g. `git log`, `git diff`,
|
|
10
|
+
* `tsc`/`eslint` reports), while 10 MiB still bounds runaway processes to a
|
|
11
|
+
* memory level that won't OOM constrained deploy/CI environments.
|
|
12
|
+
* Can be overridden per-call via the `maxBuffer` option.
|
|
13
|
+
*/
|
|
14
|
+
const defaultMaxBuffer = 10 * 1024 * 1024;
|
|
6
15
|
/**
|
|
7
16
|
* Set of utility functions to work with Spawn / Exec.
|
|
8
17
|
*
|
|
@@ -40,7 +49,7 @@ class Exec2 {
|
|
|
40
49
|
* log: true
|
|
41
50
|
*/
|
|
42
51
|
spawn(cmd, opt = {}) {
|
|
43
|
-
const { shell = true, cwd, env, passProcessEnv = true, forceColor = hasColors, stdio = 'inherit', } = opt;
|
|
52
|
+
const { shell = true, cwd, env, passProcessEnv = true, forceColor = hasColors, stdio = 'inherit', maxBuffer = defaultMaxBuffer, } = opt;
|
|
44
53
|
opt.log ??= true; // by default log should be true, as we are printing the output
|
|
45
54
|
opt.logStart ??= opt.log;
|
|
46
55
|
opt.logFinish ??= opt.log;
|
|
@@ -51,6 +60,7 @@ class Exec2 {
|
|
|
51
60
|
stdio,
|
|
52
61
|
shell,
|
|
53
62
|
cwd,
|
|
63
|
+
maxBuffer,
|
|
54
64
|
env: {
|
|
55
65
|
...(passProcessEnv ? process.env : {}),
|
|
56
66
|
...(forceColor ? { FORCE_COLOR: '1' } : {}),
|
|
@@ -81,7 +91,7 @@ class Exec2 {
|
|
|
81
91
|
* log: false
|
|
82
92
|
*/
|
|
83
93
|
exec(cmd, opt = {}) {
|
|
84
|
-
const { cwd, env, passProcessEnv = true, timeout, stdio } = opt;
|
|
94
|
+
const { cwd, env, passProcessEnv = true, timeout, stdio, maxBuffer = defaultMaxBuffer } = opt;
|
|
85
95
|
opt.logStart ??= opt.log ?? false;
|
|
86
96
|
opt.logFinish ??= opt.log ?? false;
|
|
87
97
|
const started = Date.now();
|
|
@@ -93,6 +103,7 @@ class Exec2 {
|
|
|
93
103
|
// shell: undefined,
|
|
94
104
|
cwd,
|
|
95
105
|
timeout,
|
|
106
|
+
maxBuffer,
|
|
96
107
|
env: {
|
|
97
108
|
...(passProcessEnv ? process.env : {}),
|
|
98
109
|
...env,
|
|
@@ -64,7 +64,7 @@ export declare const j: {
|
|
|
64
64
|
};
|
|
65
65
|
array<OUT, Opt>(itemSchema: JSchema<OUT, Opt>): JArray<OUT, Opt>;
|
|
66
66
|
tuple<const S extends JSchema<any, any>[]>(items: S): JTuple<S>;
|
|
67
|
-
set<
|
|
67
|
+
set<OUT, Opt>(itemSchema: JSchema<OUT, Opt>): JSet2Builder<OUT, Opt>;
|
|
68
68
|
buffer(): JBuilder<Buffer, false>;
|
|
69
69
|
enum<const T extends readonly (string | number | boolean | null)[] | StringEnum | NumberEnum>(input: T, opt?: JsonBuilderRuleOpt): JEnum<T extends readonly (infer U)[] ? U : T extends StringEnum ? T[keyof T] : T extends NumberEnum ? T[keyof T] : never>;
|
|
70
70
|
/**
|
|
@@ -90,7 +90,7 @@ export declare const j: {
|
|
|
90
90
|
* Use `anyOf` when schemas may overlap (e.g., AccountId | PartnerId with same format).
|
|
91
91
|
* Use `oneOf` when schemas are mutually exclusive.
|
|
92
92
|
*/
|
|
93
|
-
anyOf<
|
|
93
|
+
anyOf<B extends readonly JSchema<any, boolean>[]>(items: [...B]): JBuilder<BuilderOutUnion<B>, false>;
|
|
94
94
|
/**
|
|
95
95
|
* Pick validation schema for an object based on the value of a specific property.
|
|
96
96
|
*
|
|
@@ -112,7 +112,7 @@ export declare const j: {
|
|
|
112
112
|
* const schema = j.anyOfThese([successSchema, errorSchema])
|
|
113
113
|
* ```
|
|
114
114
|
*/
|
|
115
|
-
anyOfThese<
|
|
115
|
+
anyOfThese<B extends readonly JSchema<any, boolean>[]>(items: [...B]): JBuilder<BuilderOutUnion<B>, false>;
|
|
116
116
|
and(): {
|
|
117
117
|
silentBob: () => never;
|
|
118
118
|
};
|
|
@@ -123,10 +123,10 @@ export declare const j: {
|
|
|
123
123
|
*
|
|
124
124
|
* Optionally accepts a custom Ajv instance and/or inputName for error messages.
|
|
125
125
|
*/
|
|
126
|
-
fromSchema<
|
|
126
|
+
fromSchema<OUT>(schema: JsonSchema<OUT>, cfg?: {
|
|
127
127
|
ajv?: Ajv;
|
|
128
128
|
inputName?: string;
|
|
129
|
-
}): JSchema<
|
|
129
|
+
}): JSchema<OUT, false>;
|
|
130
130
|
};
|
|
131
131
|
export declare const HIDDEN_AJV_SCHEMA: unique symbol;
|
|
132
132
|
export type WithCachedAjvSchema<Base, OUT> = Base & {
|
package/dist/zip/zipReader.d.ts
CHANGED
|
@@ -77,6 +77,11 @@ export declare class ZipReader implements AsyncDisposable {
|
|
|
77
77
|
*/
|
|
78
78
|
[Symbol.asyncDispose](): Promise<void>;
|
|
79
79
|
private assertReadable;
|
|
80
|
+
/**
|
|
81
|
+
* Read the local file header to locate the start of the entry's data.
|
|
82
|
+
* The local header's name/extra-field lengths can differ from the central
|
|
83
|
+
* directory's, so this must be read per entry.
|
|
84
|
+
*/
|
|
80
85
|
private findFileDataStart;
|
|
81
86
|
}
|
|
82
87
|
/**
|
package/dist/zip/zipWriter.d.ts
CHANGED
|
@@ -98,9 +98,16 @@ export declare class ZipWriter implements AsyncDisposable {
|
|
|
98
98
|
private assertWritable;
|
|
99
99
|
/** Build the in-memory representation of an entry from its name and options. */
|
|
100
100
|
private createEntry;
|
|
101
|
+
/** Write an entry whose CRC and sizes are already known: header, name, data, no descriptor. */
|
|
101
102
|
private writeKnownEntry;
|
|
103
|
+
/** Write a streamed entry: header with bit 3 set, streamed data, then a data descriptor. */
|
|
102
104
|
private pumpEntry;
|
|
105
|
+
/**
|
|
106
|
+
* Pipe `source` to the output, computing the CRC-32 and uncompressed size on
|
|
107
|
+
* the way in, optionally deflating, and counting the compressed bytes written.
|
|
108
|
+
*/
|
|
103
109
|
private pumpData;
|
|
110
|
+
/** Write a buffer to the output, tracking the byte offset and respecting backpressure. */
|
|
104
111
|
private write;
|
|
105
112
|
private waitDrain;
|
|
106
113
|
private finishStream;
|
package/package.json
CHANGED
|
@@ -1,27 +1,26 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@naturalcycles/nodejs-lib",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "15.
|
|
4
|
+
"version": "15.114.0",
|
|
5
5
|
"dependencies": {
|
|
6
6
|
"@naturalcycles/js-lib": "^15",
|
|
7
7
|
"@standard-schema/spec": "^1",
|
|
8
8
|
"@types/jsonwebtoken": "^9",
|
|
9
|
-
"@types/yargs": "^16",
|
|
10
9
|
"ajv": "^8",
|
|
11
10
|
"ansis": "^4",
|
|
12
11
|
"jsonwebtoken": "^9",
|
|
13
12
|
"lru-cache": "^11",
|
|
14
13
|
"tinyglobby": "^0.2",
|
|
15
14
|
"tslib": "^2",
|
|
16
|
-
"yaml": "^2"
|
|
17
|
-
"yargs": "^18"
|
|
15
|
+
"yaml": "^2"
|
|
18
16
|
},
|
|
19
17
|
"devDependencies": {
|
|
20
|
-
"
|
|
21
|
-
"@naturalcycles/dev-lib": "
|
|
18
|
+
"typescript": "rc",
|
|
19
|
+
"@naturalcycles/dev-lib": "20.50.0"
|
|
22
20
|
},
|
|
23
21
|
"exports": {
|
|
24
22
|
".": "./dist/index.js",
|
|
23
|
+
"./args": "./dist/cli/parseArgs.js",
|
|
25
24
|
"./lruMemoCache": "./dist/cache/lruMemoCache.js",
|
|
26
25
|
"./colors": "./dist/colors/colors.js",
|
|
27
26
|
"./csv": "./dist/csv/index.js",
|
|
@@ -36,7 +35,6 @@
|
|
|
36
35
|
"./slack": "./dist/slack/index.js",
|
|
37
36
|
"./stream": "./dist/stream/index.js",
|
|
38
37
|
"./stream/*.js": "./dist/stream/*.js",
|
|
39
|
-
"./yargs": "./dist/yargs/yargs.util.js",
|
|
40
38
|
"./ajv": "./dist/validation/ajv/index.js",
|
|
41
39
|
"./zip": "./dist/zip/index.js"
|
|
42
40
|
},
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import fs from 'node:fs'
|
|
2
2
|
import path from 'node:path'
|
|
3
3
|
import type { UnixTimestamp } from '@naturalcycles/js-lib/types'
|
|
4
|
+
import { _parseArgs } from '../cli/parseArgs.js'
|
|
4
5
|
import { appendToBashEnv, appendToGithubEnv, appendToGithubOutput } from '../fs/json2env.js'
|
|
5
6
|
import { runScript } from '../script/runScript.js'
|
|
6
7
|
import { generateBuildInfo } from '../util/buildInfo.util.js'
|
|
7
|
-
import { _yargs } from '../yargs/yargs.util.js'
|
|
8
8
|
|
|
9
9
|
runScript(async () => {
|
|
10
|
-
const { dir, overrideTimestamp } =
|
|
10
|
+
const { dir, overrideTimestamp } = _parseArgs({
|
|
11
11
|
dir: {
|
|
12
12
|
type: 'string',
|
|
13
13
|
desc: 'Output directory',
|
|
@@ -16,7 +16,7 @@ runScript(async () => {
|
|
|
16
16
|
type: 'number',
|
|
17
17
|
desc: 'This unix timestamp will be used instead of "current time"',
|
|
18
18
|
},
|
|
19
|
-
})
|
|
19
|
+
})
|
|
20
20
|
|
|
21
21
|
const buildInfo = generateBuildInfo({
|
|
22
22
|
overrideTimestamp: overrideTimestamp as UnixTimestamp,
|
package/src/bin/json2env.ts
CHANGED
|
@@ -1,11 +1,10 @@
|
|
|
1
|
+
import { _parseArgs } from '../cli/parseArgs.js'
|
|
1
2
|
import { json2env } from '../fs/json2env.js'
|
|
2
3
|
import { runScript } from '../script/runScript.js'
|
|
3
|
-
import { _yargs } from '../yargs/yargs.util.js'
|
|
4
4
|
|
|
5
5
|
runScript(() => {
|
|
6
|
-
const
|
|
7
|
-
|
|
8
|
-
.options({
|
|
6
|
+
const argv = _parseArgs(
|
|
7
|
+
{
|
|
9
8
|
prefix: {
|
|
10
9
|
type: 'string',
|
|
11
10
|
},
|
|
@@ -35,12 +34,16 @@ runScript(() => {
|
|
|
35
34
|
silent: {
|
|
36
35
|
type: 'boolean',
|
|
37
36
|
},
|
|
38
|
-
}
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
minPositionals: 1,
|
|
40
|
+
},
|
|
41
|
+
)
|
|
39
42
|
|
|
40
43
|
const { _: args, prefix, saveEnvFile, bashEnv, githubEnv, fail, debug, silent } = argv
|
|
41
44
|
if (debug) console.log({ argv })
|
|
42
45
|
|
|
43
|
-
const jsonPath = args[0]
|
|
46
|
+
const jsonPath = args[0]!
|
|
44
47
|
|
|
45
48
|
json2env({
|
|
46
49
|
jsonPath,
|
package/src/bin/kpy.ts
CHANGED
|
@@ -1,14 +1,13 @@
|
|
|
1
|
+
import { _parseArgs } from '../cli/parseArgs.js'
|
|
1
2
|
import { kpySync } from '../fs/kpy.js'
|
|
2
3
|
import { runScript } from '../script/runScript.js'
|
|
3
|
-
import { _yargs } from '../yargs/yargs.util.js'
|
|
4
4
|
|
|
5
5
|
runScript(() => {
|
|
6
6
|
const {
|
|
7
7
|
_: [baseDir, ...inputPatterns],
|
|
8
8
|
...opt
|
|
9
|
-
} =
|
|
10
|
-
|
|
11
|
-
.options({
|
|
9
|
+
} = _parseArgs(
|
|
10
|
+
{
|
|
12
11
|
silent: {
|
|
13
12
|
type: 'boolean',
|
|
14
13
|
desc: 'Suppress all text output',
|
|
@@ -32,11 +31,13 @@ runScript(() => {
|
|
|
32
31
|
},
|
|
33
32
|
move: {
|
|
34
33
|
type: 'boolean',
|
|
35
|
-
|
|
34
|
+
desc: 'Move files instead of copy',
|
|
36
35
|
},
|
|
37
|
-
}
|
|
36
|
+
},
|
|
37
|
+
{ minPositionals: 2 },
|
|
38
|
+
)
|
|
38
39
|
|
|
39
|
-
const outputDir = inputPatterns.pop()
|
|
40
|
+
const outputDir = inputPatterns.pop()!
|
|
40
41
|
|
|
41
42
|
/*
|
|
42
43
|
console.log({
|
|
@@ -49,8 +50,8 @@ runScript(() => {
|
|
|
49
50
|
})*/
|
|
50
51
|
|
|
51
52
|
const kpyOpt = {
|
|
52
|
-
baseDir: baseDir
|
|
53
|
-
inputPatterns
|
|
53
|
+
baseDir: baseDir!,
|
|
54
|
+
inputPatterns,
|
|
54
55
|
outputDir,
|
|
55
56
|
...opt,
|
|
56
57
|
noOverwrite: !opt.overwrite,
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
+
import { _parseArgs } from '../cli/parseArgs.js'
|
|
1
2
|
import { dimGrey } from '../colors/colors.js'
|
|
2
3
|
import { runScript } from '../script/runScript.js'
|
|
3
4
|
import type { DecryptCLIOptions } from '../secret/secrets-decrypt.util.js'
|
|
4
5
|
import { secretsDecrypt } from '../secret/secrets-decrypt.util.js'
|
|
5
|
-
import { _yargs } from '../yargs/yargs.util.js'
|
|
6
6
|
|
|
7
7
|
runScript(() => {
|
|
8
8
|
const { dir, file, encKeyBuffer, del, jsonMode } = getDecryptCLIOptions()
|
|
@@ -11,9 +11,10 @@ runScript(() => {
|
|
|
11
11
|
})
|
|
12
12
|
|
|
13
13
|
function getDecryptCLIOptions(): DecryptCLIOptions {
|
|
14
|
-
let { dir, file, encKey, encKeyVar, del, jsonMode } =
|
|
14
|
+
let { dir, file, encKey, encKeyVar, del, jsonMode } = _parseArgs({
|
|
15
15
|
dir: {
|
|
16
|
-
type: '
|
|
16
|
+
type: 'string',
|
|
17
|
+
array: true,
|
|
17
18
|
desc: 'Directory with secrets. Can be many',
|
|
18
19
|
// demandOption: true,
|
|
19
20
|
default: './secret',
|
|
@@ -46,7 +47,7 @@ function getDecryptCLIOptions(): DecryptCLIOptions {
|
|
|
46
47
|
desc: 'JSON mode. Encrypts only json values, not the whole file',
|
|
47
48
|
default: false,
|
|
48
49
|
},
|
|
49
|
-
})
|
|
50
|
+
})
|
|
50
51
|
|
|
51
52
|
if (!encKey) {
|
|
52
53
|
encKey = process.env[encKeyVar]
|
|
@@ -62,6 +63,5 @@ function getDecryptCLIOptions(): DecryptCLIOptions {
|
|
|
62
63
|
|
|
63
64
|
const encKeyBuffer = Buffer.from(encKey, 'base64')
|
|
64
65
|
|
|
65
|
-
|
|
66
|
-
return { dir: dir as any, file, encKeyBuffer, del, jsonMode }
|
|
66
|
+
return { dir, file, encKeyBuffer, del, jsonMode }
|
|
67
67
|
}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
+
import { _parseArgs } from '../cli/parseArgs.js'
|
|
1
2
|
import { dimGrey } from '../colors/colors.js'
|
|
2
3
|
import { runScript } from '../script/runScript.js'
|
|
3
4
|
import type { EncryptCLIOptions } from '../secret/secrets-encrypt.util.js'
|
|
4
5
|
import { secretsEncrypt } from '../secret/secrets-encrypt.util.js'
|
|
5
|
-
import { _yargs } from '../yargs/yargs.util.js'
|
|
6
6
|
|
|
7
7
|
runScript(() => {
|
|
8
8
|
const { pattern, file, encKeyBuffer, del, jsonMode } = getEncryptCLIOptions()
|
|
@@ -11,7 +11,7 @@ runScript(() => {
|
|
|
11
11
|
})
|
|
12
12
|
|
|
13
13
|
function getEncryptCLIOptions(): EncryptCLIOptions {
|
|
14
|
-
let { pattern, file, encKey, encKeyVar, del, jsonMode } =
|
|
14
|
+
let { pattern, file, encKey, encKeyVar, del, jsonMode } = _parseArgs({
|
|
15
15
|
pattern: {
|
|
16
16
|
type: 'string',
|
|
17
17
|
array: true,
|
|
@@ -48,7 +48,7 @@ function getEncryptCLIOptions(): EncryptCLIOptions {
|
|
|
48
48
|
desc: 'JSON mode. Encrypts only json values, not the whole file',
|
|
49
49
|
default: false,
|
|
50
50
|
},
|
|
51
|
-
})
|
|
51
|
+
})
|
|
52
52
|
|
|
53
53
|
if (!encKey) {
|
|
54
54
|
encKey = process.env[encKeyVar]
|
|
@@ -64,6 +64,5 @@ function getEncryptCLIOptions(): EncryptCLIOptions {
|
|
|
64
64
|
|
|
65
65
|
const encKeyBuffer = Buffer.from(encKey, 'base64')
|
|
66
66
|
|
|
67
|
-
|
|
68
|
-
return { pattern: pattern as any, file, encKeyBuffer, del, jsonMode }
|
|
67
|
+
return { pattern, file, encKeyBuffer, del, jsonMode }
|
|
69
68
|
}
|
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
import { randomBytes } from 'node:crypto'
|
|
2
|
+
import { _parseArgs } from '../cli/parseArgs.js'
|
|
2
3
|
import { dimGrey } from '../colors/colors.js'
|
|
3
4
|
import { runScript } from '../script/runScript.js'
|
|
4
|
-
import { _yargs } from '../yargs/yargs.util.js'
|
|
5
5
|
|
|
6
6
|
runScript(() => {
|
|
7
|
-
const { sizeBytes } =
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
7
|
+
const { sizeBytes } = _parseArgs({
|
|
8
|
+
sizeBytes: {
|
|
9
|
+
type: 'number',
|
|
10
|
+
default: 256,
|
|
11
|
+
},
|
|
12
|
+
})
|
|
11
13
|
|
|
12
14
|
const key = randomBytes(sizeBytes).toString('base64')
|
|
13
15
|
|
package/src/bin/slack-this.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
+
import { _parseArgs } from '../cli/parseArgs.js'
|
|
1
2
|
import { runScript } from '../script/runScript.js'
|
|
2
3
|
import { SlackService } from '../slack/index.js'
|
|
3
|
-
import { _yargs } from '../yargs/yargs.util.js'
|
|
4
4
|
|
|
5
5
|
runScript(async () => {
|
|
6
6
|
const {
|
|
@@ -9,7 +9,7 @@ runScript(async () => {
|
|
|
9
9
|
username,
|
|
10
10
|
emoji,
|
|
11
11
|
webhook: webhookUrl,
|
|
12
|
-
} =
|
|
12
|
+
} = _parseArgs({
|
|
13
13
|
channel: {
|
|
14
14
|
type: 'string',
|
|
15
15
|
demandOption: true,
|
|
@@ -30,7 +30,7 @@ runScript(async () => {
|
|
|
30
30
|
type: 'string',
|
|
31
31
|
default: process.env.SLACK_WEBHOOK_URL,
|
|
32
32
|
},
|
|
33
|
-
})
|
|
33
|
+
})
|
|
34
34
|
|
|
35
35
|
if (!webhookUrl) {
|
|
36
36
|
console.log(`Slack webhook is required, either via env.SLACK_WEBHOOK_URL or --webhook`)
|
|
@@ -0,0 +1,257 @@
|
|
|
1
|
+
import { parseArgs } from 'node:util'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Allowed CLI option value types.
|
|
5
|
+
*/
|
|
6
|
+
export type CliOptionType = 'string' | 'number' | 'boolean'
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Declarative definition of a single CLI option, modeled after the subset of
|
|
10
|
+
* yargs `.options()` that we actually use.
|
|
11
|
+
*/
|
|
12
|
+
export interface CliOption {
|
|
13
|
+
type: CliOptionType
|
|
14
|
+
/**
|
|
15
|
+
* Accept the flag multiple times, collecting values into an array.
|
|
16
|
+
* `--id a --id b` => `['a', 'b']`. Replaces yargs `type: 'array'`.
|
|
17
|
+
*/
|
|
18
|
+
array?: boolean
|
|
19
|
+
/**
|
|
20
|
+
* Default value, applied when the flag is not provided.
|
|
21
|
+
* Providing a non-`undefined` default makes the output field non-optional.
|
|
22
|
+
*/
|
|
23
|
+
default?: string | number | boolean | readonly (string | number)[]
|
|
24
|
+
/**
|
|
25
|
+
* Mark the option as required. Throws/exits if not provided.
|
|
26
|
+
* Makes the output field non-optional.
|
|
27
|
+
*/
|
|
28
|
+
demandOption?: boolean
|
|
29
|
+
/**
|
|
30
|
+
* Restrict the value to a set of allowed values. With a `const` call (the
|
|
31
|
+
* default here) the output type is narrowed to the union of the literals.
|
|
32
|
+
*/
|
|
33
|
+
choices?: readonly (string | number)[]
|
|
34
|
+
/**
|
|
35
|
+
* Help text, shown in `--help` output.
|
|
36
|
+
*/
|
|
37
|
+
desc?: string
|
|
38
|
+
/**
|
|
39
|
+
* Single-character alias, e.g. `short: 'v'` enables `-v`.
|
|
40
|
+
*/
|
|
41
|
+
short?: string
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export type CliOptions = Record<string, CliOption>
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Element value type of a single option, derived from `choices` (if present)
|
|
48
|
+
* or `type`.
|
|
49
|
+
*/
|
|
50
|
+
type ElemType<O extends CliOption> = O extends { choices: readonly (infer C)[] }
|
|
51
|
+
? C
|
|
52
|
+
: O['type'] extends 'string'
|
|
53
|
+
? string
|
|
54
|
+
: O['type'] extends 'number'
|
|
55
|
+
? number
|
|
56
|
+
: O['type'] extends 'boolean'
|
|
57
|
+
? boolean
|
|
58
|
+
: never
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Full value type of a single option, applying `array` on top of the element
|
|
62
|
+
* type.
|
|
63
|
+
*/
|
|
64
|
+
type ValueType<O extends CliOption> = O extends { array: true } ? ElemType<O>[] : ElemType<O>
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* An option is "required" (non-optional in the output) when it is `demandOption`
|
|
68
|
+
* or has a non-`undefined` `default`. `NonNullable<unknown>` matches any
|
|
69
|
+
* non-null/undefined value, so `default: false | 0 | ''` correctly counts as
|
|
70
|
+
* present, while `default: process.env.X` (which may be `undefined`) stays optional.
|
|
71
|
+
*/
|
|
72
|
+
type IsRequired<O extends CliOption> = O extends { demandOption: true }
|
|
73
|
+
? true
|
|
74
|
+
: O extends { default: NonNullable<unknown> }
|
|
75
|
+
? true
|
|
76
|
+
: false
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Flattens an intersection into a single object type for nicer hovers.
|
|
80
|
+
*/
|
|
81
|
+
type Simplify<T> = { [K in keyof T]: T[K] } & {}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Output type inferred from the options config - the clean `@types/yargs@16`
|
|
85
|
+
* shape: exactly the declared keys with correct optionality, plus `_` for
|
|
86
|
+
* positionals. No `[x: string]: unknown` index signature, no camelCase/kebab
|
|
87
|
+
* key duplication (the `@types/yargs@17` noise).
|
|
88
|
+
*/
|
|
89
|
+
export type InferCliArgs<O extends CliOptions> = Simplify<
|
|
90
|
+
{
|
|
91
|
+
[K in keyof O as IsRequired<O[K]> extends true ? K : never]: ValueType<O[K]>
|
|
92
|
+
} & {
|
|
93
|
+
[K in keyof O as IsRequired<O[K]> extends true ? never : K]?: ValueType<O[K]>
|
|
94
|
+
} & {
|
|
95
|
+
/** Positional arguments (yargs `_`). */
|
|
96
|
+
_: string[]
|
|
97
|
+
}
|
|
98
|
+
>
|
|
99
|
+
|
|
100
|
+
export interface ParseArgsOptions {
|
|
101
|
+
/**
|
|
102
|
+
* Args to parse. Defaults to `process.argv.slice(2)` (no `hideBin` needed).
|
|
103
|
+
*/
|
|
104
|
+
args?: string[]
|
|
105
|
+
/**
|
|
106
|
+
* Require at least this many positional args. Replaces yargs `.demandCommand`.
|
|
107
|
+
*/
|
|
108
|
+
minPositionals?: number
|
|
109
|
+
/**
|
|
110
|
+
* Usage line shown at the top of `--help`.
|
|
111
|
+
*/
|
|
112
|
+
usage?: string
|
|
113
|
+
/**
|
|
114
|
+
* When `true`, unknown options throw a {@link ParseArgsError}.
|
|
115
|
+
* When `false` (default), unknown options are silently ignored - matching
|
|
116
|
+
* yargs' default lenient behavior. Important when several parsers read the
|
|
117
|
+
* same `process.argv` and each only knows about its own subset of options.
|
|
118
|
+
*/
|
|
119
|
+
strict?: boolean
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* Thrown by {@link _parseArgs} on invalid input (missing/invalid option,
|
|
124
|
+
* too few positionals). Unknown options are ignored, not rejected.
|
|
125
|
+
*/
|
|
126
|
+
export class ParseArgsError extends Error {
|
|
127
|
+
override name = 'ParseArgsError'
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* In-house, type-inferred replacement for `yargs().options(...).argv`, built on
|
|
132
|
+
* top of node's `util.parseArgs`.
|
|
133
|
+
*
|
|
134
|
+
* @example
|
|
135
|
+
* const { dir, limit } = _parseArgs({
|
|
136
|
+
* dir: { type: 'string', desc: 'Output directory' },
|
|
137
|
+
* limit: { type: 'number', default: 100 },
|
|
138
|
+
* })
|
|
139
|
+
* // dir?: string limit: number _: string[]
|
|
140
|
+
*/
|
|
141
|
+
export function _parseArgs<const O extends CliOptions>(
|
|
142
|
+
options: O,
|
|
143
|
+
opt: ParseArgsOptions = {},
|
|
144
|
+
): InferCliArgs<O> {
|
|
145
|
+
const { args, minPositionals = 0, usage, strict = false } = opt
|
|
146
|
+
|
|
147
|
+
// node's parseArgs only supports string|boolean, so `number` is parsed as a
|
|
148
|
+
// string and coerced afterwards. We also never forward `default` (parseArgs
|
|
149
|
+
// rejects e.g. a numeric default on a string-typed option) - defaults are
|
|
150
|
+
// applied by us below.
|
|
151
|
+
const nodeOptions: Record<
|
|
152
|
+
string,
|
|
153
|
+
{ type: 'string' | 'boolean'; multiple?: boolean; short?: string }
|
|
154
|
+
> = options['help'] ? {} : { help: { type: 'boolean', short: 'h' } }
|
|
155
|
+
for (const [name, def] of Object.entries(options)) {
|
|
156
|
+
// parseArgs rejects `undefined` for `short`/`multiple`, so only set when present
|
|
157
|
+
const nodeOption: { type: 'string' | 'boolean'; multiple?: boolean; short?: string } = {
|
|
158
|
+
type: def.type === 'boolean' ? 'boolean' : 'string',
|
|
159
|
+
}
|
|
160
|
+
if (def.array) nodeOption.multiple = true
|
|
161
|
+
if (def.short) nodeOption.short = def.short
|
|
162
|
+
nodeOptions[name] = nodeOption
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
const parsed = (() => {
|
|
166
|
+
try {
|
|
167
|
+
return parseArgs({
|
|
168
|
+
args,
|
|
169
|
+
options: nodeOptions,
|
|
170
|
+
allowPositionals: true,
|
|
171
|
+
allowNegative: true, // native `--no-flag` support for booleans
|
|
172
|
+
// In non-strict mode, unknown options are collected into `values` but
|
|
173
|
+
// ignored below, since we only read declared options. See `strict` docs.
|
|
174
|
+
strict,
|
|
175
|
+
})
|
|
176
|
+
} catch (err) {
|
|
177
|
+
throw new ParseArgsError((err as Error).message)
|
|
178
|
+
}
|
|
179
|
+
})()
|
|
180
|
+
|
|
181
|
+
const values = parsed.values as Record<string, unknown>
|
|
182
|
+
|
|
183
|
+
if (!options['help'] && values['help']) {
|
|
184
|
+
process.stdout.write(buildHelp(options, usage))
|
|
185
|
+
process.exit(0)
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
const result: Record<string, unknown> = { _: parsed.positionals }
|
|
189
|
+
|
|
190
|
+
for (const [name, def] of Object.entries(options)) {
|
|
191
|
+
let v = values[name]
|
|
192
|
+
|
|
193
|
+
if (v === undefined) {
|
|
194
|
+
if (def.default !== undefined) {
|
|
195
|
+
v = def.default
|
|
196
|
+
} else if (def.demandOption) {
|
|
197
|
+
throw new ParseArgsError(`Missing required option: --${name}`)
|
|
198
|
+
} else {
|
|
199
|
+
continue // leave absent
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
// normalize to array (e.g. a scalar default on an `array` option)
|
|
204
|
+
if (def.array) {
|
|
205
|
+
v = Array.isArray(v) ? v : [v]
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
if (def.type === 'number') {
|
|
209
|
+
v = Array.isArray(v) ? v.map(x => toNumber(x, name)) : toNumber(v, name)
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
if (def.choices) {
|
|
213
|
+
const list = Array.isArray(v) ? v : [v]
|
|
214
|
+
for (const x of list) {
|
|
215
|
+
if (!def.choices.includes(x as string | number)) {
|
|
216
|
+
throw new ParseArgsError(
|
|
217
|
+
`Invalid value for --${name}: "${x}". Choices: ${def.choices.join(', ')}`,
|
|
218
|
+
)
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
result[name] = v
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
if (parsed.positionals.length < minPositionals) {
|
|
227
|
+
throw new ParseArgsError(
|
|
228
|
+
`Expected at least ${minPositionals} positional argument(s), got ${parsed.positionals.length}`,
|
|
229
|
+
)
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
return result as InferCliArgs<O>
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
function toNumber(raw: unknown, name: string): number {
|
|
236
|
+
const n = Number(raw)
|
|
237
|
+
if (Number.isNaN(n)) {
|
|
238
|
+
throw new ParseArgsError(`Invalid number for --${name}: "${raw}"`)
|
|
239
|
+
}
|
|
240
|
+
return n
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
function buildHelp(options: CliOptions, usage?: string): string {
|
|
244
|
+
const lines: string[] = []
|
|
245
|
+
if (usage) lines.push(usage, '')
|
|
246
|
+
lines.push('Options:')
|
|
247
|
+
for (const [name, def] of Object.entries(options)) {
|
|
248
|
+
const flag = def.short ? `-${def.short}, --${name}` : `--${name}`
|
|
249
|
+
const meta = [`[${def.array ? `${def.type}[]` : def.type}]`]
|
|
250
|
+
if (def.demandOption) meta.push('[required]')
|
|
251
|
+
if (def.default !== undefined) meta.push(`[default: ${JSON.stringify(def.default)}]`)
|
|
252
|
+
if (def.choices) meta.push(`[choices: ${def.choices.join(', ')}]`)
|
|
253
|
+
lines.push(` ${flag} ${meta.join(' ')}${def.desc ? ` ${def.desc}` : ''}`)
|
|
254
|
+
}
|
|
255
|
+
lines.push(' -h, --help Show help')
|
|
256
|
+
return `${lines.join('\n')}\n`
|
|
257
|
+
}
|
package/src/exec2/exec2.ts
CHANGED
|
@@ -10,6 +10,16 @@ import type {
|
|
|
10
10
|
} from '@naturalcycles/js-lib/types'
|
|
11
11
|
import { dimGrey, dimRed, hasColors, white } from '../colors/colors.js'
|
|
12
12
|
|
|
13
|
+
/**
|
|
14
|
+
* Default `maxBuffer` (in bytes) for the synchronous `exec`/`spawn`.
|
|
15
|
+
* Set to 10 MiB, which is higher than Node's own default of 1 MiB.
|
|
16
|
+
* Node's 1 MiB is too low for common large outputs (e.g. `git log`, `git diff`,
|
|
17
|
+
* `tsc`/`eslint` reports), while 10 MiB still bounds runaway processes to a
|
|
18
|
+
* memory level that won't OOM constrained deploy/CI environments.
|
|
19
|
+
* Can be overridden per-call via the `maxBuffer` option.
|
|
20
|
+
*/
|
|
21
|
+
const defaultMaxBuffer = 10 * 1024 * 1024
|
|
22
|
+
|
|
13
23
|
/**
|
|
14
24
|
* Set of utility functions to work with Spawn / Exec.
|
|
15
25
|
*
|
|
@@ -46,7 +56,7 @@ class Exec2 {
|
|
|
46
56
|
* shell: true
|
|
47
57
|
* log: true
|
|
48
58
|
*/
|
|
49
|
-
spawn(cmd: string, opt:
|
|
59
|
+
spawn(cmd: string, opt: SpawnSyncOptions = {}): void {
|
|
50
60
|
const {
|
|
51
61
|
shell = true,
|
|
52
62
|
cwd,
|
|
@@ -54,6 +64,7 @@ class Exec2 {
|
|
|
54
64
|
passProcessEnv = true,
|
|
55
65
|
forceColor = hasColors,
|
|
56
66
|
stdio = 'inherit',
|
|
67
|
+
maxBuffer = defaultMaxBuffer,
|
|
57
68
|
} = opt
|
|
58
69
|
opt.log ??= true // by default log should be true, as we are printing the output
|
|
59
70
|
opt.logStart ??= opt.log
|
|
@@ -66,6 +77,7 @@ class Exec2 {
|
|
|
66
77
|
stdio,
|
|
67
78
|
shell,
|
|
68
79
|
cwd,
|
|
80
|
+
maxBuffer,
|
|
69
81
|
env: {
|
|
70
82
|
...(passProcessEnv ? process.env : {}),
|
|
71
83
|
...(forceColor ? { FORCE_COLOR: '1' } : {}),
|
|
@@ -99,7 +111,7 @@ class Exec2 {
|
|
|
99
111
|
* log: false
|
|
100
112
|
*/
|
|
101
113
|
exec(cmd: string, opt: ExecOptions = {}): string {
|
|
102
|
-
const { cwd, env, passProcessEnv = true, timeout, stdio } = opt
|
|
114
|
+
const { cwd, env, passProcessEnv = true, timeout, stdio, maxBuffer = defaultMaxBuffer } = opt
|
|
103
115
|
opt.logStart ??= opt.log ?? false
|
|
104
116
|
opt.logFinish ??= opt.log ?? false
|
|
105
117
|
const started = Date.now() as UnixTimestampMillis
|
|
@@ -112,6 +124,7 @@ class Exec2 {
|
|
|
112
124
|
// shell: undefined,
|
|
113
125
|
cwd,
|
|
114
126
|
timeout,
|
|
127
|
+
maxBuffer,
|
|
115
128
|
env: {
|
|
116
129
|
...(passProcessEnv ? process.env : {}),
|
|
117
130
|
...env,
|
|
@@ -355,6 +368,13 @@ export interface SpawnOutput {
|
|
|
355
368
|
stderr: string
|
|
356
369
|
}
|
|
357
370
|
|
|
371
|
+
export interface SpawnSyncOptions extends SpawnOptions {
|
|
372
|
+
/**
|
|
373
|
+
* Defaults to 10 MiB (higher than Node's own default of 1 MiB).
|
|
374
|
+
*/
|
|
375
|
+
maxBuffer?: number
|
|
376
|
+
}
|
|
377
|
+
|
|
358
378
|
export interface SpawnAsyncOptions extends SpawnOptions {
|
|
359
379
|
/**
|
|
360
380
|
* Defaults to true.
|
|
@@ -462,4 +482,9 @@ export interface ExecOptions {
|
|
|
462
482
|
* beware that stdio: 'inherit', means we don't get the output returned.
|
|
463
483
|
*/
|
|
464
484
|
stdio?: StdioOptions
|
|
485
|
+
|
|
486
|
+
/**
|
|
487
|
+
* Defaults to 10 MiB (higher than Node's own default of 1 MiB).
|
|
488
|
+
*/
|
|
489
|
+
maxBuffer?: number
|
|
465
490
|
}
|
package/src/stream/pipeline.ts
CHANGED
|
@@ -341,7 +341,7 @@ export class Pipeline<T = unknown> {
|
|
|
341
341
|
}),
|
|
342
342
|
)
|
|
343
343
|
this.objectMode = false
|
|
344
|
-
return this
|
|
344
|
+
return this
|
|
345
345
|
}
|
|
346
346
|
|
|
347
347
|
gunzip(this: Pipeline<Uint8Array>, opt?: ZlibOptions): Pipeline<Uint8Array> {
|
|
@@ -352,7 +352,7 @@ export class Pipeline<T = unknown> {
|
|
|
352
352
|
}),
|
|
353
353
|
)
|
|
354
354
|
this.objectMode = false
|
|
355
|
-
return this
|
|
355
|
+
return this
|
|
356
356
|
}
|
|
357
357
|
|
|
358
358
|
zstdCompress(
|
|
@@ -362,7 +362,7 @@ export class Pipeline<T = unknown> {
|
|
|
362
362
|
): Pipeline<Uint8Array> {
|
|
363
363
|
this.transforms.push(createZstdCompress(zip2.zstdLevelToOptions(level, opt)))
|
|
364
364
|
this.objectMode = false
|
|
365
|
-
return this
|
|
365
|
+
return this
|
|
366
366
|
}
|
|
367
367
|
|
|
368
368
|
zstdDecompress(this: Pipeline<Uint8Array>, opt?: ZstdOptions): Pipeline<Uint8Array> {
|
|
@@ -373,7 +373,7 @@ export class Pipeline<T = unknown> {
|
|
|
373
373
|
}),
|
|
374
374
|
)
|
|
375
375
|
this.objectMode = false
|
|
376
|
-
return this
|
|
376
|
+
return this
|
|
377
377
|
}
|
|
378
378
|
|
|
379
379
|
async toArray(opt?: TransformOptions): Promise<T[]> {
|
|
@@ -14,7 +14,7 @@ type Type = PrimitiveType | 'array' | 'object'
|
|
|
14
14
|
export function generateJsonSchemaFromData<T extends AnyObject = AnyObject>(
|
|
15
15
|
rows: AnyObject[],
|
|
16
16
|
): JsonSchema<T> {
|
|
17
|
-
return objectToJsonSchema<T>(rows
|
|
17
|
+
return objectToJsonSchema<T>(rows)
|
|
18
18
|
}
|
|
19
19
|
|
|
20
20
|
function objectToJsonSchema<T extends AnyObject>(rows: AnyObject[]): JsonSchema<T> {
|
|
@@ -68,25 +68,25 @@ function mergeTypes(types: Type[], samples: any[]): JsonSchema | undefined {
|
|
|
68
68
|
if (type === 'null') {
|
|
69
69
|
return {
|
|
70
70
|
type: 'null',
|
|
71
|
-
}
|
|
71
|
+
}
|
|
72
72
|
}
|
|
73
73
|
|
|
74
74
|
if (type === 'boolean') {
|
|
75
75
|
return {
|
|
76
76
|
type: 'boolean',
|
|
77
|
-
}
|
|
77
|
+
}
|
|
78
78
|
}
|
|
79
79
|
|
|
80
80
|
if (type === 'string') {
|
|
81
81
|
return {
|
|
82
82
|
type: 'string',
|
|
83
|
-
}
|
|
83
|
+
}
|
|
84
84
|
}
|
|
85
85
|
|
|
86
86
|
if (type === 'number') {
|
|
87
87
|
return {
|
|
88
88
|
type: 'number',
|
|
89
|
-
}
|
|
89
|
+
}
|
|
90
90
|
}
|
|
91
91
|
|
|
92
92
|
if (type === 'object') {
|
|
@@ -102,7 +102,7 @@ function mergeTypes(types: Type[], samples: any[]): JsonSchema | undefined {
|
|
|
102
102
|
return {
|
|
103
103
|
type: 'array',
|
|
104
104
|
items: mergeTypes(itemTypes, items),
|
|
105
|
-
}
|
|
105
|
+
}
|
|
106
106
|
}
|
|
107
107
|
}
|
|
108
108
|
|
package/dist/yargs/yargs.util.js
DELETED
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
import yargs from 'yargs';
|
|
2
|
-
// @ts-expect-error yargs types disagree with runtime
|
|
3
|
-
import { hideBin } from 'yargs/helpers';
|
|
4
|
-
/**
|
|
5
|
-
* Quick yargs helper to make it work in esm.
|
|
6
|
-
* It also allows to not have yargs and `@types/yargs` to be declared as dependencies.
|
|
7
|
-
*/
|
|
8
|
-
// oxlint-disable-next-line @typescript-eslint/explicit-function-return-type
|
|
9
|
-
export function _yargs() {
|
|
10
|
-
return yargs(hideBin(process.argv));
|
|
11
|
-
}
|
package/src/yargs/yargs.util.ts
DELETED
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
import yargs from 'yargs'
|
|
2
|
-
// @ts-expect-error yargs types disagree with runtime
|
|
3
|
-
import { hideBin } from 'yargs/helpers'
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* Quick yargs helper to make it work in esm.
|
|
7
|
-
* It also allows to not have yargs and `@types/yargs` to be declared as dependencies.
|
|
8
|
-
*/
|
|
9
|
-
// oxlint-disable-next-line @typescript-eslint/explicit-function-return-type
|
|
10
|
-
export function _yargs() {
|
|
11
|
-
return yargs(hideBin(process.argv))
|
|
12
|
-
}
|