@fuzdev/fuz_util 0.46.0 → 0.48.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/args.d.ts ADDED
@@ -0,0 +1,138 @@
1
+ import { z } from 'zod';
2
+ /**
3
+ * CLI arguments container.
4
+ * Positional arguments stored in `_`, named flags/options as string keys.
5
+ * Produced by `argv_parse` or external parsers (mri, minimist, etc.).
6
+ */
7
+ export interface Args {
8
+ _?: Array<string>;
9
+ [key: string]: ArgValue;
10
+ }
11
+ /**
12
+ * Parsed CLI arguments with guaranteed positionals array.
13
+ * Returned by `argv_parse` which always initializes `_`.
14
+ */
15
+ export interface ParsedArgs extends Args {
16
+ _: Array<string>;
17
+ }
18
+ /**
19
+ * Value types supported in CLI arguments.
20
+ */
21
+ export type ArgValue = string | number | boolean | undefined | Array<string | number | boolean>;
22
+ /**
23
+ * Schema description for help text generation.
24
+ * Not used by args_parse/args_serialize directly - provided for consumers
25
+ * building CLI help output.
26
+ */
27
+ export interface ArgSchema {
28
+ type: string;
29
+ default: ArgValue;
30
+ description: string;
31
+ }
32
+ /**
33
+ * Result of alias extraction from a schema.
34
+ * Includes canonical keys for downstream conflict detection.
35
+ */
36
+ export interface ArgsAliasesResult {
37
+ aliases: Map<string, string>;
38
+ canonical_keys: Set<string>;
39
+ }
40
+ /**
41
+ * Validates a zod schema for CLI arg usage.
42
+ *
43
+ * Checks for:
44
+ * - Alias conflicts with canonical keys
45
+ * - Duplicate aliases across different keys
46
+ *
47
+ * Results are cached per schema (WeakMap). Safe to call multiple times.
48
+ *
49
+ * @param schema Zod object schema with optional alias metadata
50
+ * @returns Validation result with success flag and optional error
51
+ */
52
+ export declare const args_validate_schema: (schema: z.ZodType) => {
53
+ success: true;
54
+ } | {
55
+ success: false;
56
+ error: z.ZodError;
57
+ };
58
+ /**
59
+ * Validates parsed CLI args against a zod schema.
60
+ *
61
+ * Handles CLI-specific concerns before validation:
62
+ * 1. Validates schema (cached) - returns error if alias conflicts exist
63
+ * 2. Expands aliases defined in schema `.meta({aliases: ['v']})`
64
+ * 3. Strips alias keys (required for strictObject schemas)
65
+ * 4. Validates with zod
66
+ * 5. After validation, syncs `no-` prefixed boolean flags with their base keys
67
+ *
68
+ * Schema analysis is cached per schema (WeakMap) for performance.
69
+ *
70
+ * @param unparsed_args Args object from CLI parser (mri, minimist, etc.)
71
+ * @param schema Zod object schema with optional alias metadata
72
+ * @returns Zod SafeParseResult with expanded/synced data on success
73
+ */
74
+ export declare const args_parse: <TOutput extends Record<string, ArgValue> = Args>(unparsed_args: Args, schema: z.ZodType<TOutput>) => z.ZodSafeParseResult<TOutput>;
75
+ /**
76
+ * Serializes Args to CLI string array for subprocess forwarding.
77
+ *
78
+ * Handles CLI conventions:
79
+ * - Positionals first, then flags
80
+ * - Single-char keys get single dash, multi-char get double dash
81
+ * - Boolean `true` becomes bare flag, `false` is skipped
82
+ * - `undefined` values are skipped
83
+ * - `no-` prefixed keys skipped when base key is truthy (avoid contradiction)
84
+ * - When schema provided, extracts aliases and prefers shortest form
85
+ *
86
+ * Schema analysis is cached per schema (WeakMap) for performance.
87
+ *
88
+ * @param args Args object to serialize
89
+ * @param schema Optional zod schema to extract aliases for short form preference
90
+ * @returns Array of CLI argument strings
91
+ */
92
+ export declare const args_serialize: (args: Args, schema?: z.ZodType) => Array<string>;
93
+ /**
94
+ * Extracts alias mappings and canonical keys from a zod schema's metadata.
95
+ *
96
+ * Useful for consumers building custom tooling (help generators, conflict detection, etc.).
97
+ * Results are cached per schema (WeakMap).
98
+ *
99
+ * Note: Returns copies of the cached data to prevent mutation of internal cache.
100
+ *
101
+ * @param schema Zod object schema with optional `.meta({aliases})` on fields
102
+ * @returns Object with aliases map and canonical_keys set
103
+ */
104
+ export declare const args_extract_aliases: (schema: z.ZodType) => ArgsAliasesResult;
105
+ /**
106
+ * Parses raw CLI argv array into an Args object.
107
+ *
108
+ * A lightweight, dependency-free alternative to mri/minimist with compatible behavior.
109
+ *
110
+ * Features:
111
+ * - `--flag` → `{flag: true}`
112
+ * - `--flag value` → `{flag: 'value'}` or `{flag: 123}` (numeric coercion)
113
+ * - `--flag=value` → equals syntax
114
+ * - `--flag=` → `{flag: ''}` (empty string, differs from mri which returns true)
115
+ * - `-f` → `{f: true}` (short flag)
116
+ * - `-f value` → `{f: 'value'}`
117
+ * - `-abc` → `{a: true, b: true, c: true}` (combined short flags)
118
+ * - `-abc value` → `{a: true, b: true, c: 'value'}` (last flag gets value)
119
+ * - `--no-flag` → `{flag: false}` (negation prefix)
120
+ * - `--` → stops flag parsing, rest become positionals
121
+ * - Positionals collected in `_` array
122
+ * - Repeated flags become arrays
123
+ *
124
+ * Intentional differences from mri:
125
+ * - `--flag=` returns `''` (mri returns `true`)
126
+ * - `--flag= next` returns `{flag: '', _: ['next']}` (mri takes `next` as the value)
127
+ * - `---flag` returns `{'-flag': true}` (mri strips all dashes)
128
+ * - `['--flag', '']` preserves `''` (mri coerces to `0`)
129
+ * - `--__proto__` works as a normal key (mri silently fails)
130
+ *
131
+ * The returned object uses `Object.create(null)` to prevent prototype pollution
132
+ * and allow any key name including `__proto__` and `constructor`.
133
+ *
134
+ * @param argv Raw argument array (typically process.argv.slice(2))
135
+ * @returns Parsed Args object with guaranteed `_` array (null prototype)
136
+ */
137
+ export declare const argv_parse: (argv: Array<string>) => ParsedArgs;
138
+ //# sourceMappingURL=args.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"args.d.ts","sourceRoot":"../src/lib/","sources":["../src/lib/args.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,CAAC,EAAC,MAAM,KAAK,CAAC;AAEtB;;;;GAIG;AACH,MAAM,WAAW,IAAI;IACpB,CAAC,CAAC,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;IAClB,CAAC,GAAG,EAAE,MAAM,GAAG,QAAQ,CAAC;CACxB;AAED;;;GAGG;AACH,MAAM,WAAW,UAAW,SAAQ,IAAI;IACvC,CAAC,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;CACjB;AAED;;GAEG;AACH,MAAM,MAAM,QAAQ,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,SAAS,GAAG,KAAK,CAAC,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC,CAAC;AAEhG;;;;GAIG;AACH,MAAM,WAAW,SAAS;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,QAAQ,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;CACpB;AAED;;;GAGG;AACH,MAAM,WAAW,iBAAiB;IACjC,OAAO,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC7B,cAAc,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;CAC5B;AAsID;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,oBAAoB,GAChC,QAAQ,CAAC,CAAC,OAAO,KACf;IAAC,OAAO,EAAE,IAAI,CAAA;CAAC,GAAG;IAAC,OAAO,EAAE,KAAK,CAAC;IAAC,KAAK,EAAE,CAAC,CAAC,QAAQ,CAAA;CAMtD,CAAC;AAEF;;;;;;;;;;;;;;;GAeG;AACH,eAAO,MAAM,UAAU,GAAI,OAAO,SAAS,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAC,GAAG,IAAI,EACzE,eAAe,IAAI,EACnB,QAAQ,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,KACxB,CAAC,CAAC,kBAAkB,CAAC,OAAO,CA6C9B,CAAC;AAEF;;;;;;;;;;;;;;;;GAgBG;AACH,eAAO,MAAM,cAAc,GAAI,MAAM,IAAI,EAAE,SAAS,CAAC,CAAC,OAAO,KAAG,KAAK,CAAC,MAAM,CA2D3E,CAAC;AAEF;;;;;;;;;;GAUG;AACH,eAAO,MAAM,oBAAoB,GAAI,QAAQ,CAAC,CAAC,OAAO,KAAG,iBAMxD,CAAC;AAgCF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,eAAO,MAAM,UAAU,GAAI,MAAM,KAAK,CAAC,MAAM,CAAC,KAAG,UAyHhD,CAAC"}
package/dist/args.js ADDED
@@ -0,0 +1,447 @@
1
+ import { z } from 'zod';
2
+ // WeakMap cache for schema analysis - avoids redundant reflection
3
+ const schema_cache = new WeakMap();
4
+ // Internal: Unwrap nested schema types (Optional, Default, Transform, Pipe)
5
+ const unwrap_schema = (def) => {
6
+ if ('innerType' in def)
7
+ return def.innerType; // Optional, Nullable
8
+ if ('in' in def)
9
+ return def.in; // Pipe
10
+ if ('schema' in def)
11
+ return def.schema; // Default, Transform
12
+ return undefined;
13
+ };
14
+ // Internal: Check if schema type is boolean (recursing through wrappers)
15
+ const is_boolean_field = (schema) => {
16
+ const def = schema._zod.def;
17
+ if (def.type === 'boolean')
18
+ return true;
19
+ const inner = unwrap_schema(def);
20
+ if (inner)
21
+ return is_boolean_field(inner);
22
+ return false;
23
+ };
24
+ // Internal: Analyze schema for aliases, canonical keys, boolean keys, and conflicts
25
+ const analyze_schema = (schema) => {
26
+ const aliases = new Map();
27
+ const canonical_keys = new Set();
28
+ const boolean_keys = new Set();
29
+ const errors = [];
30
+ const def = schema._zod.def;
31
+ // Unwrap to get object def (handle wrapped types like optional, default, etc.)
32
+ let obj_def = def;
33
+ while (!('shape' in obj_def)) {
34
+ const inner = unwrap_schema(obj_def);
35
+ if (!inner)
36
+ return { aliases, canonical_keys, boolean_keys, errors };
37
+ obj_def = inner._zod.def;
38
+ }
39
+ const shape = obj_def.shape;
40
+ // First pass: collect all canonical keys
41
+ for (const key of Object.keys(shape)) {
42
+ canonical_keys.add(key);
43
+ }
44
+ // Second pass: process fields for aliases and booleans
45
+ for (const [key, field] of Object.entries(shape)) {
46
+ const field_schema = field;
47
+ // Track boolean fields for no- prefix sync
48
+ if (is_boolean_field(field_schema)) {
49
+ boolean_keys.add(key);
50
+ }
51
+ const meta = field_schema.meta();
52
+ if (meta?.aliases) {
53
+ for (const alias of meta.aliases) {
54
+ // Check for alias-canonical conflict
55
+ if (canonical_keys.has(alias)) {
56
+ errors.push({
57
+ type: 'alias_canonical_conflict',
58
+ alias,
59
+ canonical: key,
60
+ conflict_with: alias,
61
+ });
62
+ }
63
+ // Check for duplicate alias
64
+ else if (aliases.has(alias)) {
65
+ errors.push({
66
+ type: 'duplicate_alias',
67
+ alias,
68
+ canonical: key,
69
+ conflict_with: aliases.get(alias),
70
+ });
71
+ }
72
+ else {
73
+ aliases.set(alias, key);
74
+ }
75
+ }
76
+ }
77
+ }
78
+ return { aliases, canonical_keys, boolean_keys, errors };
79
+ };
80
+ // Internal: Convert analysis errors to ZodError for consistent API
81
+ const to_conflict_error = (errors) => {
82
+ return new z.ZodError(errors.map((err) => ({
83
+ code: 'custom',
84
+ path: [err.alias],
85
+ message: err.type === 'alias_canonical_conflict'
86
+ ? `Alias '${err.alias}' for '${err.canonical}' conflicts with canonical key '${err.conflict_with}'`
87
+ : `Alias '${err.alias}' is used by both '${err.canonical}' and '${err.conflict_with}'`,
88
+ })));
89
+ };
90
+ // Internal: Get or create cache entry for schema
91
+ const get_schema_cache = (schema) => {
92
+ let entry = schema_cache.get(schema);
93
+ if (!entry) {
94
+ const analysis = analyze_schema(schema);
95
+ entry = {
96
+ aliases: analysis.aliases,
97
+ canonical_keys: analysis.canonical_keys,
98
+ boolean_keys: analysis.boolean_keys,
99
+ conflict_error: analysis.errors.length > 0 ? to_conflict_error(analysis.errors) : null,
100
+ };
101
+ schema_cache.set(schema, entry);
102
+ }
103
+ return entry;
104
+ };
105
+ /**
106
+ * Validates a zod schema for CLI arg usage.
107
+ *
108
+ * Checks for:
109
+ * - Alias conflicts with canonical keys
110
+ * - Duplicate aliases across different keys
111
+ *
112
+ * Results are cached per schema (WeakMap). Safe to call multiple times.
113
+ *
114
+ * @param schema Zod object schema with optional alias metadata
115
+ * @returns Validation result with success flag and optional error
116
+ */
117
+ export const args_validate_schema = (schema) => {
118
+ const cache = get_schema_cache(schema);
119
+ if (cache.conflict_error) {
120
+ return { success: false, error: cache.conflict_error };
121
+ }
122
+ return { success: true };
123
+ };
124
+ /**
125
+ * Validates parsed CLI args against a zod schema.
126
+ *
127
+ * Handles CLI-specific concerns before validation:
128
+ * 1. Validates schema (cached) - returns error if alias conflicts exist
129
+ * 2. Expands aliases defined in schema `.meta({aliases: ['v']})`
130
+ * 3. Strips alias keys (required for strictObject schemas)
131
+ * 4. Validates with zod
132
+ * 5. After validation, syncs `no-` prefixed boolean flags with their base keys
133
+ *
134
+ * Schema analysis is cached per schema (WeakMap) for performance.
135
+ *
136
+ * @param unparsed_args Args object from CLI parser (mri, minimist, etc.)
137
+ * @param schema Zod object schema with optional alias metadata
138
+ * @returns Zod SafeParseResult with expanded/synced data on success
139
+ */
140
+ export const args_parse = (unparsed_args, schema) => {
141
+ const cache = get_schema_cache(schema);
142
+ // Return conflict error if schema has issues
143
+ if (cache.conflict_error) {
144
+ return { success: false, error: cache.conflict_error };
145
+ }
146
+ // Build expanded args - copy canonical, expand aliases, strip alias keys
147
+ const expanded = {};
148
+ for (const [key, value] of Object.entries(unparsed_args)) {
149
+ if (cache.aliases.has(key)) {
150
+ const canonical = cache.aliases.get(key);
151
+ // Only expand if canonical not already present (canonical takes precedence)
152
+ if (!(canonical in expanded) && !(canonical in unparsed_args)) {
153
+ expanded[canonical] = value;
154
+ }
155
+ // Don't copy alias key (strip it)
156
+ }
157
+ else {
158
+ expanded[key] = value;
159
+ }
160
+ }
161
+ // Validate with zod
162
+ const parsed = schema.safeParse(expanded);
163
+ if (parsed.success) {
164
+ // Mutate data with the correct source of truth for no- prefixed args
165
+ const data = parsed.data;
166
+ for (const key in data) {
167
+ if (key.startsWith('no-')) {
168
+ const base_key = key.substring(3);
169
+ // Only sync if both keys are booleans in the schema
170
+ if (cache.boolean_keys.has(key) && cache.boolean_keys.has(base_key)) {
171
+ if (!(key in unparsed_args) && !(key in expanded)) {
172
+ data[key] = !data[base_key];
173
+ }
174
+ else if (!(base_key in unparsed_args) && !(base_key in expanded)) {
175
+ data[base_key] = !data[key];
176
+ }
177
+ }
178
+ }
179
+ }
180
+ }
181
+ return parsed;
182
+ };
183
+ /**
184
+ * Serializes Args to CLI string array for subprocess forwarding.
185
+ *
186
+ * Handles CLI conventions:
187
+ * - Positionals first, then flags
188
+ * - Single-char keys get single dash, multi-char get double dash
189
+ * - Boolean `true` becomes bare flag, `false` is skipped
190
+ * - `undefined` values are skipped
191
+ * - `no-` prefixed keys skipped when base key is truthy (avoid contradiction)
192
+ * - When schema provided, extracts aliases and prefers shortest form
193
+ *
194
+ * Schema analysis is cached per schema (WeakMap) for performance.
195
+ *
196
+ * @param args Args object to serialize
197
+ * @param schema Optional zod schema to extract aliases for short form preference
198
+ * @returns Array of CLI argument strings
199
+ */
200
+ export const args_serialize = (args, schema) => {
201
+ const result = [];
202
+ // Build reverse map (canonical → shortest alias) if schema provided
203
+ let shortest_names;
204
+ if (schema) {
205
+ const cache = get_schema_cache(schema);
206
+ shortest_names = new Map();
207
+ // Group aliases by canonical key
208
+ const aliases_by_canonical = new Map();
209
+ for (const [alias, canonical] of cache.aliases) {
210
+ if (!aliases_by_canonical.has(canonical)) {
211
+ aliases_by_canonical.set(canonical, []);
212
+ }
213
+ aliases_by_canonical.get(canonical).push(alias);
214
+ }
215
+ // Find shortest for each canonical
216
+ for (const [canonical, aliases] of aliases_by_canonical) {
217
+ const all_names = [canonical, ...aliases];
218
+ const shortest = all_names.reduce((a, b) => (a.length <= b.length ? a : b));
219
+ shortest_names.set(canonical, shortest);
220
+ }
221
+ }
222
+ const add_value = (name, value) => {
223
+ if (value === undefined)
224
+ return;
225
+ if (value === false)
226
+ return; // Can't represent false as bare flag
227
+ result.push(name);
228
+ if (typeof value !== 'boolean') {
229
+ result.push(value + '');
230
+ }
231
+ };
232
+ let positionals = null;
233
+ for (const [key, value] of Object.entries(args)) {
234
+ if (key === '_') {
235
+ positionals = value ? value.map((v) => v + '') : [];
236
+ }
237
+ else {
238
+ // Skip no-X if X exists and is truthy
239
+ if (key.startsWith('no-')) {
240
+ const base = key.substring(3);
241
+ if (base in args && args[base]) {
242
+ continue; // Skip redundant no- flag
243
+ }
244
+ }
245
+ // Determine the name to use (prefer shortest if schema provided)
246
+ const use_key = shortest_names?.get(key) ?? key;
247
+ const name = `${use_key.length === 1 ? '-' : '--'}${use_key}`;
248
+ if (Array.isArray(value)) {
249
+ for (const v of value)
250
+ add_value(name, v);
251
+ }
252
+ else {
253
+ add_value(name, value);
254
+ }
255
+ }
256
+ }
257
+ return positionals ? [...positionals, ...result] : result;
258
+ };
259
+ /**
260
+ * Extracts alias mappings and canonical keys from a zod schema's metadata.
261
+ *
262
+ * Useful for consumers building custom tooling (help generators, conflict detection, etc.).
263
+ * Results are cached per schema (WeakMap).
264
+ *
265
+ * Note: Returns copies of the cached data to prevent mutation of internal cache.
266
+ *
267
+ * @param schema Zod object schema with optional `.meta({aliases})` on fields
268
+ * @returns Object with aliases map and canonical_keys set
269
+ */
270
+ export const args_extract_aliases = (schema) => {
271
+ const cache = get_schema_cache(schema);
272
+ return {
273
+ aliases: new Map(cache.aliases),
274
+ canonical_keys: new Set(cache.canonical_keys),
275
+ };
276
+ };
277
+ // Internal: Try to coerce a string value to number if it looks numeric
278
+ const coerce_value = (value) => {
279
+ // Handle empty string
280
+ if (value === '')
281
+ return value;
282
+ // Try to parse as number
283
+ const num = Number(value);
284
+ // Return number if valid and finite, otherwise keep as string
285
+ // This matches mri behavior: "123" -> 123, "12.5" -> 12.5, "1e5" -> 100000
286
+ // But "123abc" -> "123abc", "NaN" -> "NaN", "Infinity" -> "Infinity"
287
+ if (!Number.isNaN(num) && Number.isFinite(num) && value.trim() !== '') {
288
+ return num;
289
+ }
290
+ return value;
291
+ };
292
+ // Internal: Set a value on args, handling arrays for repeated flags
293
+ const set_arg = (args, key, value) => {
294
+ if (key in args) {
295
+ // Convert to array or push to existing array
296
+ const existing = args[key];
297
+ if (Array.isArray(existing)) {
298
+ existing.push(value);
299
+ }
300
+ else {
301
+ args[key] = [existing, value];
302
+ }
303
+ }
304
+ else {
305
+ args[key] = value;
306
+ }
307
+ };
308
+ /**
309
+ * Parses raw CLI argv array into an Args object.
310
+ *
311
+ * A lightweight, dependency-free alternative to mri/minimist with compatible behavior.
312
+ *
313
+ * Features:
314
+ * - `--flag` → `{flag: true}`
315
+ * - `--flag value` → `{flag: 'value'}` or `{flag: 123}` (numeric coercion)
316
+ * - `--flag=value` → equals syntax
317
+ * - `--flag=` → `{flag: ''}` (empty string, differs from mri which returns true)
318
+ * - `-f` → `{f: true}` (short flag)
319
+ * - `-f value` → `{f: 'value'}`
320
+ * - `-abc` → `{a: true, b: true, c: true}` (combined short flags)
321
+ * - `-abc value` → `{a: true, b: true, c: 'value'}` (last flag gets value)
322
+ * - `--no-flag` → `{flag: false}` (negation prefix)
323
+ * - `--` → stops flag parsing, rest become positionals
324
+ * - Positionals collected in `_` array
325
+ * - Repeated flags become arrays
326
+ *
327
+ * Intentional differences from mri:
328
+ * - `--flag=` returns `''` (mri returns `true`)
329
+ * - `--flag= next` returns `{flag: '', _: ['next']}` (mri takes `next` as the value)
330
+ * - `---flag` returns `{'-flag': true}` (mri strips all dashes)
331
+ * - `['--flag', '']` preserves `''` (mri coerces to `0`)
332
+ * - `--__proto__` works as a normal key (mri silently fails)
333
+ *
334
+ * The returned object uses `Object.create(null)` to prevent prototype pollution
335
+ * and allow any key name including `__proto__` and `constructor`.
336
+ *
337
+ * @param argv Raw argument array (typically process.argv.slice(2))
338
+ * @returns Parsed Args object with guaranteed `_` array (null prototype)
339
+ */
340
+ export const argv_parse = (argv) => {
341
+ // Use Object.create(null) to allow __proto__ as a normal key
342
+ // This prevents prototype pollution and makes all key names work
343
+ const args = Object.create(null);
344
+ args._ = [];
345
+ const positionals = args._;
346
+ let i = 0;
347
+ let flags_done = false; // Set to true after seeing --
348
+ while (i < argv.length) {
349
+ const arg = argv[i];
350
+ // After --, everything is a positional
351
+ if (flags_done) {
352
+ positionals.push(arg);
353
+ i++;
354
+ continue;
355
+ }
356
+ // -- stops flag parsing
357
+ if (arg === '--') {
358
+ flags_done = true;
359
+ i++;
360
+ continue;
361
+ }
362
+ // Long flag: --flag or --flag=value or --no-flag
363
+ if (arg.startsWith('--')) {
364
+ const rest = arg.slice(2);
365
+ // Handle --flag=value
366
+ const equals_index = rest.indexOf('=');
367
+ if (equals_index !== -1) {
368
+ const key = rest.slice(0, equals_index);
369
+ const value = rest.slice(equals_index + 1);
370
+ // Empty value after = becomes empty string (explicit value assignment)
371
+ // This differs from mri which treats it as boolean true
372
+ set_arg(args, key, coerce_value(value));
373
+ i++;
374
+ continue;
375
+ }
376
+ // Handle --no-flag (negation) - includes --no- which sets '' to false
377
+ if (rest.startsWith('no-')) {
378
+ const key = rest.slice(3); // May be empty string for --no-
379
+ args[key] = false;
380
+ i++;
381
+ continue;
382
+ }
383
+ // Handle --flag or --flag value
384
+ const key = rest;
385
+ const next = argv[i + 1];
386
+ // If next arg exists and doesn't look like a flag, it's the value
387
+ if (next !== undefined && !next.startsWith('-')) {
388
+ set_arg(args, key, coerce_value(next));
389
+ i += 2;
390
+ }
391
+ else {
392
+ // Boolean flag
393
+ args[key] = true;
394
+ i++;
395
+ }
396
+ continue;
397
+ }
398
+ // Single dash is ignored (matches mri)
399
+ if (arg === '-') {
400
+ i++;
401
+ continue;
402
+ }
403
+ // Short flag(s): -f or -abc or -f value
404
+ if (arg.startsWith('-') && arg.length > 1) {
405
+ const chars = arg.slice(1);
406
+ // Handle -f=value (short flag with equals)
407
+ const equals_index = chars.indexOf('=');
408
+ if (equals_index !== -1) {
409
+ const key = chars.slice(0, equals_index);
410
+ const value = chars.slice(equals_index + 1);
411
+ // For -abc=value, set a and b to true, c gets value
412
+ for (let j = 0; j < key.length - 1; j++) {
413
+ args[key[j]] = true;
414
+ }
415
+ if (key.length > 0) {
416
+ set_arg(args, key[key.length - 1], coerce_value(value));
417
+ }
418
+ i++;
419
+ continue;
420
+ }
421
+ // Handle combined flags: -abc means -a -b -c
422
+ // Last flag can take a value if next arg isn't a flag
423
+ const next = argv[i + 1];
424
+ const has_value = next !== undefined && !next.startsWith('-');
425
+ for (let j = 0; j < chars.length; j++) {
426
+ const char = chars[j];
427
+ const is_last = j === chars.length - 1;
428
+ if (is_last && has_value) {
429
+ // Last char gets the value
430
+ set_arg(args, char, coerce_value(next));
431
+ i += 2;
432
+ }
433
+ else {
434
+ // Boolean flag
435
+ args[char] = true;
436
+ if (is_last)
437
+ i++;
438
+ }
439
+ }
440
+ continue;
441
+ }
442
+ // Positional argument
443
+ positionals.push(arg);
444
+ i++;
445
+ }
446
+ return args;
447
+ };
package/dist/process.d.ts CHANGED
@@ -8,6 +8,8 @@ export interface SpawnResultError {
8
8
  ok: false;
9
9
  child: ChildProcess;
10
10
  error: Error;
11
+ code: null;
12
+ signal: null;
11
13
  }
12
14
  /**
13
15
  * Process ran and exited with a code.
@@ -16,6 +18,7 @@ export interface SpawnResultError {
16
18
  export interface SpawnResultExited {
17
19
  ok: boolean;
18
20
  child: ChildProcess;
21
+ error: null;
19
22
  code: number;
20
23
  signal: null;
21
24
  }
@@ -25,6 +28,7 @@ export interface SpawnResultExited {
25
28
  export interface SpawnResultSignaled {
26
29
  ok: false;
27
30
  child: ChildProcess;
31
+ error: null;
28
32
  code: null;
29
33
  signal: NodeJS.Signals;
30
34
  }
@@ -1 +1 @@
1
- {"version":3,"file":"process.d.ts","sourceRoot":"../src/lib/","sources":["../src/lib/process.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"process.d.ts","sourceRoot":"../src/lib/","sources":["../src/lib/process.ts"],"names":[],"mappings":"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"}
package/dist/process.js CHANGED
@@ -10,15 +10,15 @@ const log = new Logger('process');
10
10
  /**
11
11
  * Type guard for spawn errors (process failed to start).
12
12
  */
13
- export const spawn_result_is_error = (result) => 'error' in result;
13
+ export const spawn_result_is_error = (result) => result.error !== null;
14
14
  /**
15
15
  * Type guard for signal termination.
16
16
  */
17
- export const spawn_result_is_signaled = (result) => 'signal' in result && result.signal !== null;
17
+ export const spawn_result_is_signaled = (result) => result.signal !== null;
18
18
  /**
19
19
  * Type guard for normal exit with code.
20
20
  */
21
- export const spawn_result_is_exited = (result) => 'code' in result && result.code !== null;
21
+ export const spawn_result_is_exited = (result) => result.code !== null;
22
22
  //
23
23
  // Internal Helpers
24
24
  //
@@ -37,17 +37,17 @@ const create_closed_promise = (child) => {
37
37
  if (resolved)
38
38
  return;
39
39
  resolved = true;
40
- resolve({ ok: false, child, error: err });
40
+ resolve({ ok: false, child, error: err, code: null, signal: null });
41
41
  });
42
42
  child.once('close', (code, signal) => {
43
43
  if (resolved)
44
44
  return;
45
45
  resolved = true;
46
46
  if (signal !== null) {
47
- resolve({ ok: false, child, code: null, signal });
47
+ resolve({ ok: false, child, error: null, code: null, signal });
48
48
  }
49
49
  else {
50
- resolve({ ok: code === 0, child, code: code ?? 0, signal: null });
50
+ resolve({ ok: code === 0, child, error: null, code: code ?? 0, signal: null });
51
51
  }
52
52
  });
53
53
  return closed;
@@ -190,6 +190,7 @@ export class ProcessRegistry {
190
190
  return {
191
191
  ok: child.exitCode === 0,
192
192
  child,
193
+ error: null,
193
194
  code: child.exitCode,
194
195
  signal: null,
195
196
  };
@@ -199,6 +200,7 @@ export class ProcessRegistry {
199
200
  return {
200
201
  ok: false,
201
202
  child,
203
+ error: null,
202
204
  code: null,
203
205
  signal: child.signalCode,
204
206
  };