@naturalcycles/nodejs-lib 15.113.0 → 15.115.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.
@@ -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 } = _yargs().options({
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
- }).argv;
17
+ });
18
18
  const buildInfo = generateBuildInfo({
19
19
  overrideTimestamp: overrideTimestamp,
20
20
  });
@@ -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 { argv } = _yargs()
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 } = _yargs()
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
- descr: 'Move files instead of copy',
29
+ desc: 'Move files instead of copy',
32
30
  },
33
- }).argv;
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: 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 } = _yargs().options({
10
+ let { dir, file, encKey, encKeyVar, del, jsonMode } = _parseArgs({
11
11
  dir: {
12
- type: 'array',
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
- }).argv;
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
- // `as any` because @types/yargs can't handle string[] type properly
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 } = _yargs().options({
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
- }).argv;
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
- // `as any` because @types/yargs can't handle string[] type properly
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 } = _yargs().option('sizeBytes', {
7
- type: 'number',
8
- default: 256,
9
- }).argv;
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');
@@ -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, } = _yargs().options({
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
- }).argv;
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,149 @@
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
+ /**
11
+ * Value type. Defaults to `'string'` when omitted.
12
+ */
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
+ * Transform the raw string value into the final value. The output type is
44
+ * inferred from the function's return type, so this is the way to produce
45
+ * branded types (e.g. `IsoDate`) or richer values (parsed numbers, JSON, ...).
46
+ *
47
+ * Applied per-element for `array` options. Receives the raw string token, so
48
+ * it fully owns conversion - built-in `number` coercion is not applied on top.
49
+ * NOT applied to `default` values: a `default` is taken to be in final form.
50
+ *
51
+ * @example transform: s => s as IsoDate
52
+ */
53
+ transform?: (value: string) => unknown;
54
+ }
55
+ export type CliOptions = Record<string, CliOption>;
56
+ /**
57
+ * Element value type of a single option, derived from `transform` (if present,
58
+ * its return type wins), then `choices`, then `type`. Defaults to `string` when
59
+ * none narrow it (so `type` is optional).
60
+ */
61
+ type ElemType<O extends CliOption> = O extends {
62
+ transform: (...args: any[]) => infer R;
63
+ } ? R : O extends {
64
+ choices: readonly (infer C)[];
65
+ } ? C : O extends {
66
+ type: 'number';
67
+ } ? number : O extends {
68
+ type: 'boolean';
69
+ } ? boolean : string;
70
+ /**
71
+ * Full value type of a single option, applying `array` on top of the element
72
+ * type.
73
+ */
74
+ type ValueType<O extends CliOption> = O extends {
75
+ array: true;
76
+ } ? ElemType<O>[] : ElemType<O>;
77
+ /**
78
+ * An option is "required" (non-optional in the output) when it is `demandOption`
79
+ * or has a non-`undefined` `default`. `NonNullable<unknown>` matches any
80
+ * non-null/undefined value, so `default: false | 0 | ''` correctly counts as
81
+ * present, while `default: process.env.X` (which may be `undefined`) stays optional.
82
+ */
83
+ type IsRequired<O extends CliOption> = O extends {
84
+ demandOption: true;
85
+ } ? true : O extends {
86
+ default: NonNullable<unknown>;
87
+ } ? true : false;
88
+ /**
89
+ * Flattens an intersection into a single object type for nicer hovers.
90
+ */
91
+ type Simplify<T> = {
92
+ [K in keyof T]: T[K];
93
+ } & {};
94
+ /**
95
+ * Output type inferred from the options config - the clean `@types/yargs@16`
96
+ * shape: exactly the declared keys with correct optionality, plus `_` for
97
+ * positionals. No `[x: string]: unknown` index signature, no camelCase/kebab
98
+ * key duplication (the `@types/yargs@17` noise).
99
+ */
100
+ export type InferCliArgs<O extends CliOptions> = Simplify<{
101
+ [K in keyof O as IsRequired<O[K]> extends true ? K : never]: ValueType<O[K]>;
102
+ } & {
103
+ [K in keyof O as IsRequired<O[K]> extends true ? never : K]?: ValueType<O[K]>;
104
+ } & {
105
+ /** Positional arguments (yargs `_`). */
106
+ _: string[];
107
+ }>;
108
+ export interface ParseArgsOptions {
109
+ /**
110
+ * Args to parse. Defaults to `process.argv.slice(2)` (no `hideBin` needed).
111
+ */
112
+ args?: string[];
113
+ /**
114
+ * Require at least this many positional args. Replaces yargs `.demandCommand`.
115
+ */
116
+ minPositionals?: number;
117
+ /**
118
+ * Usage line shown at the top of `--help`.
119
+ */
120
+ usage?: string;
121
+ /**
122
+ * When `true`, unknown options throw a {@link ParseArgsError}.
123
+ * When `false` (default), unknown options are silently ignored - matching
124
+ * yargs' default lenient behavior. Important when several parsers read the
125
+ * same `process.argv` and each only knows about its own subset of options.
126
+ */
127
+ strict?: boolean;
128
+ }
129
+ /**
130
+ * Thrown by {@link _parseArgs} on invalid input (missing/invalid option,
131
+ * too few positionals). Unknown options are ignored, not rejected.
132
+ */
133
+ export declare class ParseArgsError extends Error {
134
+ name: string;
135
+ }
136
+ /**
137
+ * In-house, type-inferred replacement for `yargs().options(...).argv`, built on
138
+ * top of node's `util.parseArgs`.
139
+ *
140
+ * @example
141
+ * const { dir, limit, date } = _parseArgs({
142
+ * dir: { desc: 'Output directory' }, // type defaults to 'string'
143
+ * limit: { type: 'number', default: 100 },
144
+ * date: { transform: s => s as IsoDate }, // inferred + converted via transform
145
+ * })
146
+ * // dir?: string limit: number date?: IsoDate _: string[]
147
+ */
148
+ export declare function _parseArgs<const O extends CliOptions>(options: O, opt?: ParseArgsOptions): InferCliArgs<O>;
149
+ export {};
@@ -0,0 +1,130 @@
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, date } = _parseArgs({
15
+ * dir: { desc: 'Output directory' }, // type defaults to 'string'
16
+ * limit: { type: 'number', default: 100 },
17
+ * date: { transform: s => s as IsoDate }, // inferred + converted via transform
18
+ * })
19
+ * // dir?: string limit: number date?: IsoDate _: string[]
20
+ */
21
+ export function _parseArgs(options, opt = {}) {
22
+ const { args, minPositionals = 0, usage, strict = false } = opt;
23
+ // node's parseArgs only supports string|boolean, so `number` is parsed as a
24
+ // string and coerced afterwards. We also never forward `default` (parseArgs
25
+ // rejects e.g. a numeric default on a string-typed option) - defaults are
26
+ // applied by us below.
27
+ const nodeOptions = options['help'] ? {} : { help: { type: 'boolean', short: 'h' } };
28
+ for (const [name, def] of Object.entries(options)) {
29
+ // parseArgs rejects `undefined` for `short`/`multiple`, so only set when present
30
+ const nodeOption = {
31
+ type: def.type === 'boolean' ? 'boolean' : 'string',
32
+ };
33
+ if (def.array)
34
+ nodeOption.multiple = true;
35
+ if (def.short)
36
+ nodeOption.short = def.short;
37
+ nodeOptions[name] = nodeOption;
38
+ }
39
+ const parsed = (() => {
40
+ try {
41
+ return parseArgs({
42
+ args,
43
+ options: nodeOptions,
44
+ allowPositionals: true,
45
+ allowNegative: true, // native `--no-flag` support for booleans
46
+ // In non-strict mode, unknown options are collected into `values` but
47
+ // ignored below, since we only read declared options. See `strict` docs.
48
+ strict,
49
+ });
50
+ }
51
+ catch (err) {
52
+ throw new ParseArgsError(err.message);
53
+ }
54
+ })();
55
+ const values = parsed.values;
56
+ if (!options['help'] && values['help']) {
57
+ process.stdout.write(buildHelp(options, usage));
58
+ process.exit(0);
59
+ }
60
+ const result = { _: parsed.positionals };
61
+ for (const [name, def] of Object.entries(options)) {
62
+ let v = values[name];
63
+ // `transform` is only applied to arg-sourced values; a `default` is taken
64
+ // to be in final form (see CliOption.transform docs).
65
+ const fromArgs = v !== undefined;
66
+ if (v === undefined) {
67
+ if (def.default !== undefined) {
68
+ v = def.default;
69
+ }
70
+ else if (def.demandOption) {
71
+ throw new ParseArgsError(`Missing required option: --${name}`);
72
+ }
73
+ else {
74
+ continue; // leave absent
75
+ }
76
+ }
77
+ // normalize to array (e.g. a scalar default on an `array` option)
78
+ if (def.array) {
79
+ v = Array.isArray(v) ? v : [v];
80
+ }
81
+ // `transform` owns conversion, so built-in number coercion is skipped for it
82
+ if (def.type === 'number' && !def.transform) {
83
+ v = Array.isArray(v) ? v.map(x => toNumber(x, name)) : toNumber(v, name);
84
+ }
85
+ if (def.choices) {
86
+ const list = Array.isArray(v) ? v : [v];
87
+ for (const x of list) {
88
+ if (!def.choices.includes(x)) {
89
+ throw new ParseArgsError(`Invalid value for --${name}: "${x}". Choices: ${def.choices.join(', ')}`);
90
+ }
91
+ }
92
+ }
93
+ if (def.transform && fromArgs) {
94
+ const { transform } = def;
95
+ v = Array.isArray(v) ? v.map(x => transform(x)) : transform(v);
96
+ }
97
+ result[name] = v;
98
+ }
99
+ if (parsed.positionals.length < minPositionals) {
100
+ throw new ParseArgsError(`Expected at least ${minPositionals} positional argument(s), got ${parsed.positionals.length}`);
101
+ }
102
+ return result;
103
+ }
104
+ function toNumber(raw, name) {
105
+ const n = Number(raw);
106
+ if (Number.isNaN(n)) {
107
+ throw new ParseArgsError(`Invalid number for --${name}: "${raw}"`);
108
+ }
109
+ return n;
110
+ }
111
+ function buildHelp(options, usage) {
112
+ const lines = [];
113
+ if (usage)
114
+ lines.push(usage, '');
115
+ lines.push('Options:');
116
+ for (const [name, def] of Object.entries(options)) {
117
+ const flag = def.short ? `-${def.short}, --${name}` : `--${name}`;
118
+ const type = def.type ?? 'string';
119
+ const meta = [`[${def.array ? `${type}[]` : type}]`];
120
+ if (def.demandOption)
121
+ meta.push('[required]');
122
+ if (def.default !== undefined)
123
+ meta.push(`[default: ${JSON.stringify(def.default)}]`);
124
+ if (def.choices)
125
+ meta.push(`[choices: ${def.choices.join(', ')}]`);
126
+ lines.push(` ${flag} ${meta.join(' ')}${def.desc ? ` ${def.desc}` : ''}`);
127
+ }
128
+ lines.push(' -h, --help Show help');
129
+ return `${lines.join('\n')}\n`;
130
+ }
@@ -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<OUT_1, Opt_1>(itemSchema: JSchema<OUT_1, Opt_1>): JSet2Builder<OUT_1, Opt_1>;
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<B_1 extends readonly JSchema<any, boolean>[]>(items: [...B_1]): JBuilder<BuilderOutUnion<B_1>, false>;
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<B_2 extends readonly JSchema<any, boolean>[]>(items: [...B_2]): JBuilder<BuilderOutUnion<B_2>, false>;
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<OUT_2>(schema: JsonSchema<OUT_2>, cfg?: {
126
+ fromSchema<OUT>(schema: JsonSchema<OUT>, cfg?: {
127
127
  ajv?: Ajv;
128
128
  inputName?: string;
129
- }): JSchema<OUT_2, false>;
129
+ }): JSchema<OUT, false>;
130
130
  };
131
131
  export declare const HIDDEN_AJV_SCHEMA: unique symbol;
132
132
  export type WithCachedAjvSchema<Base, OUT> = Base & {
@@ -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
  /**
@@ -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.113.0",
4
+ "version": "15.115.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
- "@typescript/native-preview": "beta",
18
+ "typescript": "rc",
21
19
  "@naturalcycles/dev-lib": "18.4.2"
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 } = _yargs().options({
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
- }).argv
19
+ })
20
20
 
21
21
  const buildInfo = generateBuildInfo({
22
22
  overrideTimestamp: overrideTimestamp as UnixTimestamp,
@@ -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 { argv } = _yargs()
7
- .demandCommand(1)
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] as string
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
- } = _yargs()
10
- .demandCommand(2)
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
- descr: 'Move files instead of copy',
34
+ desc: 'Move files instead of copy',
36
35
  },
37
- }).argv
36
+ },
37
+ { minPositionals: 2 },
38
+ )
38
39
 
39
- const outputDir = inputPatterns.pop() as string
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 as string,
53
- inputPatterns: inputPatterns as string[],
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 } = _yargs().options({
14
+ let { dir, file, encKey, encKeyVar, del, jsonMode } = _parseArgs({
15
15
  dir: {
16
- type: 'array',
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
- }).argv
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
- // `as any` because @types/yargs can't handle string[] type properly
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 } = _yargs().options({
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
- }).argv
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
- // `as any` because @types/yargs can't handle string[] type properly
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 } = _yargs().option('sizeBytes', {
8
- type: 'number',
9
- default: 256,
10
- }).argv
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
 
@@ -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
- } = _yargs().options({
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
- }).argv
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,284 @@
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
+ /**
14
+ * Value type. Defaults to `'string'` when omitted.
15
+ */
16
+ type?: CliOptionType
17
+ /**
18
+ * Accept the flag multiple times, collecting values into an array.
19
+ * `--id a --id b` => `['a', 'b']`. Replaces yargs `type: 'array'`.
20
+ */
21
+ array?: boolean
22
+ /**
23
+ * Default value, applied when the flag is not provided.
24
+ * Providing a non-`undefined` default makes the output field non-optional.
25
+ */
26
+ default?: string | number | boolean | readonly (string | number)[]
27
+ /**
28
+ * Mark the option as required. Throws/exits if not provided.
29
+ * Makes the output field non-optional.
30
+ */
31
+ demandOption?: boolean
32
+ /**
33
+ * Restrict the value to a set of allowed values. With a `const` call (the
34
+ * default here) the output type is narrowed to the union of the literals.
35
+ */
36
+ choices?: readonly (string | number)[]
37
+ /**
38
+ * Help text, shown in `--help` output.
39
+ */
40
+ desc?: string
41
+ /**
42
+ * Single-character alias, e.g. `short: 'v'` enables `-v`.
43
+ */
44
+ short?: string
45
+ /**
46
+ * Transform the raw string value into the final value. The output type is
47
+ * inferred from the function's return type, so this is the way to produce
48
+ * branded types (e.g. `IsoDate`) or richer values (parsed numbers, JSON, ...).
49
+ *
50
+ * Applied per-element for `array` options. Receives the raw string token, so
51
+ * it fully owns conversion - built-in `number` coercion is not applied on top.
52
+ * NOT applied to `default` values: a `default` is taken to be in final form.
53
+ *
54
+ * @example transform: s => s as IsoDate
55
+ */
56
+ transform?: (value: string) => unknown
57
+ }
58
+
59
+ export type CliOptions = Record<string, CliOption>
60
+
61
+ /**
62
+ * Element value type of a single option, derived from `transform` (if present,
63
+ * its return type wins), then `choices`, then `type`. Defaults to `string` when
64
+ * none narrow it (so `type` is optional).
65
+ */
66
+ type ElemType<O extends CliOption> = O extends { transform: (...args: any[]) => infer R }
67
+ ? R
68
+ : O extends { choices: readonly (infer C)[] }
69
+ ? C
70
+ : O extends { type: 'number' }
71
+ ? number
72
+ : O extends { type: 'boolean' }
73
+ ? boolean
74
+ : string
75
+
76
+ /**
77
+ * Full value type of a single option, applying `array` on top of the element
78
+ * type.
79
+ */
80
+ type ValueType<O extends CliOption> = O extends { array: true } ? ElemType<O>[] : ElemType<O>
81
+
82
+ /**
83
+ * An option is "required" (non-optional in the output) when it is `demandOption`
84
+ * or has a non-`undefined` `default`. `NonNullable<unknown>` matches any
85
+ * non-null/undefined value, so `default: false | 0 | ''` correctly counts as
86
+ * present, while `default: process.env.X` (which may be `undefined`) stays optional.
87
+ */
88
+ type IsRequired<O extends CliOption> = O extends { demandOption: true }
89
+ ? true
90
+ : O extends { default: NonNullable<unknown> }
91
+ ? true
92
+ : false
93
+
94
+ /**
95
+ * Flattens an intersection into a single object type for nicer hovers.
96
+ */
97
+ type Simplify<T> = { [K in keyof T]: T[K] } & {}
98
+
99
+ /**
100
+ * Output type inferred from the options config - the clean `@types/yargs@16`
101
+ * shape: exactly the declared keys with correct optionality, plus `_` for
102
+ * positionals. No `[x: string]: unknown` index signature, no camelCase/kebab
103
+ * key duplication (the `@types/yargs@17` noise).
104
+ */
105
+ export type InferCliArgs<O extends CliOptions> = Simplify<
106
+ {
107
+ [K in keyof O as IsRequired<O[K]> extends true ? K : never]: ValueType<O[K]>
108
+ } & {
109
+ [K in keyof O as IsRequired<O[K]> extends true ? never : K]?: ValueType<O[K]>
110
+ } & {
111
+ /** Positional arguments (yargs `_`). */
112
+ _: string[]
113
+ }
114
+ >
115
+
116
+ export interface ParseArgsOptions {
117
+ /**
118
+ * Args to parse. Defaults to `process.argv.slice(2)` (no `hideBin` needed).
119
+ */
120
+ args?: string[]
121
+ /**
122
+ * Require at least this many positional args. Replaces yargs `.demandCommand`.
123
+ */
124
+ minPositionals?: number
125
+ /**
126
+ * Usage line shown at the top of `--help`.
127
+ */
128
+ usage?: string
129
+ /**
130
+ * When `true`, unknown options throw a {@link ParseArgsError}.
131
+ * When `false` (default), unknown options are silently ignored - matching
132
+ * yargs' default lenient behavior. Important when several parsers read the
133
+ * same `process.argv` and each only knows about its own subset of options.
134
+ */
135
+ strict?: boolean
136
+ }
137
+
138
+ /**
139
+ * Thrown by {@link _parseArgs} on invalid input (missing/invalid option,
140
+ * too few positionals). Unknown options are ignored, not rejected.
141
+ */
142
+ export class ParseArgsError extends Error {
143
+ override name = 'ParseArgsError'
144
+ }
145
+
146
+ /**
147
+ * In-house, type-inferred replacement for `yargs().options(...).argv`, built on
148
+ * top of node's `util.parseArgs`.
149
+ *
150
+ * @example
151
+ * const { dir, limit, date } = _parseArgs({
152
+ * dir: { desc: 'Output directory' }, // type defaults to 'string'
153
+ * limit: { type: 'number', default: 100 },
154
+ * date: { transform: s => s as IsoDate }, // inferred + converted via transform
155
+ * })
156
+ * // dir?: string limit: number date?: IsoDate _: string[]
157
+ */
158
+ export function _parseArgs<const O extends CliOptions>(
159
+ options: O,
160
+ opt: ParseArgsOptions = {},
161
+ ): InferCliArgs<O> {
162
+ const { args, minPositionals = 0, usage, strict = false } = opt
163
+
164
+ // node's parseArgs only supports string|boolean, so `number` is parsed as a
165
+ // string and coerced afterwards. We also never forward `default` (parseArgs
166
+ // rejects e.g. a numeric default on a string-typed option) - defaults are
167
+ // applied by us below.
168
+ const nodeOptions: Record<
169
+ string,
170
+ { type: 'string' | 'boolean'; multiple?: boolean; short?: string }
171
+ > = options['help'] ? {} : { help: { type: 'boolean', short: 'h' } }
172
+ for (const [name, def] of Object.entries(options)) {
173
+ // parseArgs rejects `undefined` for `short`/`multiple`, so only set when present
174
+ const nodeOption: { type: 'string' | 'boolean'; multiple?: boolean; short?: string } = {
175
+ type: def.type === 'boolean' ? 'boolean' : 'string',
176
+ }
177
+ if (def.array) nodeOption.multiple = true
178
+ if (def.short) nodeOption.short = def.short
179
+ nodeOptions[name] = nodeOption
180
+ }
181
+
182
+ const parsed = (() => {
183
+ try {
184
+ return parseArgs({
185
+ args,
186
+ options: nodeOptions,
187
+ allowPositionals: true,
188
+ allowNegative: true, // native `--no-flag` support for booleans
189
+ // In non-strict mode, unknown options are collected into `values` but
190
+ // ignored below, since we only read declared options. See `strict` docs.
191
+ strict,
192
+ })
193
+ } catch (err) {
194
+ throw new ParseArgsError((err as Error).message)
195
+ }
196
+ })()
197
+
198
+ const values = parsed.values as Record<string, unknown>
199
+
200
+ if (!options['help'] && values['help']) {
201
+ process.stdout.write(buildHelp(options, usage))
202
+ process.exit(0)
203
+ }
204
+
205
+ const result: Record<string, unknown> = { _: parsed.positionals }
206
+
207
+ for (const [name, def] of Object.entries(options)) {
208
+ let v = values[name]
209
+ // `transform` is only applied to arg-sourced values; a `default` is taken
210
+ // to be in final form (see CliOption.transform docs).
211
+ const fromArgs = v !== undefined
212
+
213
+ if (v === undefined) {
214
+ if (def.default !== undefined) {
215
+ v = def.default
216
+ } else if (def.demandOption) {
217
+ throw new ParseArgsError(`Missing required option: --${name}`)
218
+ } else {
219
+ continue // leave absent
220
+ }
221
+ }
222
+
223
+ // normalize to array (e.g. a scalar default on an `array` option)
224
+ if (def.array) {
225
+ v = Array.isArray(v) ? v : [v]
226
+ }
227
+
228
+ // `transform` owns conversion, so built-in number coercion is skipped for it
229
+ if (def.type === 'number' && !def.transform) {
230
+ v = Array.isArray(v) ? v.map(x => toNumber(x, name)) : toNumber(v, name)
231
+ }
232
+
233
+ if (def.choices) {
234
+ const list = Array.isArray(v) ? v : [v]
235
+ for (const x of list) {
236
+ if (!def.choices.includes(x as string | number)) {
237
+ throw new ParseArgsError(
238
+ `Invalid value for --${name}: "${x}". Choices: ${def.choices.join(', ')}`,
239
+ )
240
+ }
241
+ }
242
+ }
243
+
244
+ if (def.transform && fromArgs) {
245
+ const { transform } = def
246
+ v = Array.isArray(v) ? v.map(x => transform(x as string)) : transform(v as string)
247
+ }
248
+
249
+ result[name] = v
250
+ }
251
+
252
+ if (parsed.positionals.length < minPositionals) {
253
+ throw new ParseArgsError(
254
+ `Expected at least ${minPositionals} positional argument(s), got ${parsed.positionals.length}`,
255
+ )
256
+ }
257
+
258
+ return result as InferCliArgs<O>
259
+ }
260
+
261
+ function toNumber(raw: unknown, name: string): number {
262
+ const n = Number(raw)
263
+ if (Number.isNaN(n)) {
264
+ throw new ParseArgsError(`Invalid number for --${name}: "${raw}"`)
265
+ }
266
+ return n
267
+ }
268
+
269
+ function buildHelp(options: CliOptions, usage?: string): string {
270
+ const lines: string[] = []
271
+ if (usage) lines.push(usage, '')
272
+ lines.push('Options:')
273
+ for (const [name, def] of Object.entries(options)) {
274
+ const flag = def.short ? `-${def.short}, --${name}` : `--${name}`
275
+ const type = def.type ?? 'string'
276
+ const meta = [`[${def.array ? `${type}[]` : type}]`]
277
+ if (def.demandOption) meta.push('[required]')
278
+ if (def.default !== undefined) meta.push(`[default: ${JSON.stringify(def.default)}]`)
279
+ if (def.choices) meta.push(`[choices: ${def.choices.join(', ')}]`)
280
+ lines.push(` ${flag} ${meta.join(' ')}${def.desc ? ` ${def.desc}` : ''}`)
281
+ }
282
+ lines.push(' -h, --help Show help')
283
+ return `${lines.join('\n')}\n`
284
+ }
@@ -341,7 +341,7 @@ export class Pipeline<T = unknown> {
341
341
  }),
342
342
  )
343
343
  this.objectMode = false
344
- return this as any
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 as any
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 as any
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 as any
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 as any)
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
- } as JsonSchema
71
+ }
72
72
  }
73
73
 
74
74
  if (type === 'boolean') {
75
75
  return {
76
76
  type: 'boolean',
77
- } as JsonSchema
77
+ }
78
78
  }
79
79
 
80
80
  if (type === 'string') {
81
81
  return {
82
82
  type: 'string',
83
- } as JsonSchema
83
+ }
84
84
  }
85
85
 
86
86
  if (type === 'number') {
87
87
  return {
88
88
  type: 'number',
89
- } as JsonSchema
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
- } as JsonSchema
105
+ }
106
106
  }
107
107
  }
108
108
 
@@ -1,6 +0,0 @@
1
- import yargs from 'yargs';
2
- /**
3
- * Quick yargs helper to make it work in esm.
4
- * It also allows to not have yargs and `@types/yargs` to be declared as dependencies.
5
- */
6
- export declare function _yargs(): yargs.Argv<{}>;
@@ -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
- }
@@ -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
- }