just-bash-util 0.1.6 → 0.1.8

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/README.md CHANGED
@@ -64,9 +64,10 @@ await serve.invoke({ port: 8080, entry: "app.ts" }, ctx);
64
64
  - `omitInherited` to exclude parent options from specific subcommands
65
65
  - `--help` / `-h` auto-generated at every level
66
66
  - `--no-<flag>` negation, `-abc` combined short flags, `--key=value` syntax, counted flags (`-vvv` → 3)
67
- - `--` end-of-options separator (remaining tokens become positional args and are available via `meta.passthrough`)
67
+ - `--` end-of-options separator (remaining tokens go to `meta.passthrough` without consuming positional args)
68
68
  - Environment variable fallbacks for options
69
69
  - Levenshtein-based "did you mean?" suggestions for typos
70
+ - `transformArgs` callback to rewrite tokens before parsing — support non-standard shorthand syntax like `-5` → `-n 5`
70
71
  - Automatic error handling — thrown errors in handlers are caught and returned as clean `ExecResult` with `exitCode: 1`
71
72
 
72
73
  #### Options and flags
@@ -113,16 +114,43 @@ args: [
113
114
 
114
115
  #### The `--` separator
115
116
 
116
- The `--` token signals end-of-options. Tokens after `--` are treated as positional arguments (not parsed as flags) and are also available in `meta.passthrough`:
117
+ The `--` token stops all parsing. Tokens after `--` go exclusively into `meta.passthrough` — they are **not** consumed as positional args or parsed as flags. Positional args must appear before `--`:
117
118
 
118
119
  ```ts
120
+ // mycli checkout main -- README.md
121
+ handler: (args, ctx, meta) => {
122
+ args.target; // "main" (positional arg before --)
123
+ meta.passthrough; // ["README.md"] (tokens after --)
124
+ }
125
+
119
126
  // mycli checkout -- README.md
120
127
  handler: (args, ctx, meta) => {
121
- args.target; // "README.md" (assigned to positional arg)
122
- meta.passthrough; // ["README.md"] (raw tokens after --)
128
+ args.target; // undefined (no positional before --)
129
+ meta.passthrough; // ["README.md"]
123
130
  }
124
131
  ```
125
132
 
133
+ #### Token rewriting with `transformArgs`
134
+
135
+ Commands can define a `transformArgs` callback to rewrite the raw token array before it reaches the parser. This is useful for supporting non-standard shorthand syntax that the parser wouldn't otherwise understand:
136
+
137
+ ```ts
138
+ cli.command("log", {
139
+ description: "Show commit log",
140
+ transformArgs: (tokens) =>
141
+ tokens.map((t) => (/^-(\d+)$/.test(t) ? `-n${t.slice(1)}` : t)),
142
+ options: {
143
+ maxCount: o.number().alias("n").describe("Limit output to n commits"),
144
+ },
145
+ handler: (args) => {
146
+ // git log -5 → tokens rewritten to -n5 → args.maxCount === 5
147
+ return { stdout: `showing ${args.maxCount} commits`, stderr: "", exitCode: 0 };
148
+ },
149
+ });
150
+ ```
151
+
152
+ The callback receives a mutable copy of the tokens and returns the rewritten array. It runs only in `execute()` (token-based invocation) — `invoke()` takes typed args directly, so there's nothing to transform.
153
+
126
154
  ### `just-bash-util/config` — Config file discovery
127
155
 
128
156
  Cosmiconfig-style config search that walks up the directory tree, trying conventional filenames at each level. Comments and trailing commas are supported out of the box.
@@ -217,7 +217,6 @@ function parseArgs(options, argDefs, tokens, env) {
217
217
  if (token === "--") {
218
218
  i++;
219
219
  while (i < tokens.length) {
220
- positionals.push(tokens[i]);
221
220
  passthrough.push(tokens[i]);
222
221
  i++;
223
222
  }
@@ -550,10 +549,11 @@ var Command = class _Command {
550
549
  examples;
551
550
  omitInherited;
552
551
  handler;
552
+ transformArgs;
553
553
  children = /* @__PURE__ */ new Map();
554
554
  parent;
555
555
  /** @internal */
556
- constructor(name, description, options, args, examples, omitInherited, handler) {
556
+ constructor(name, description, options, args, examples, omitInherited, handler, transformArgs) {
557
557
  this.name = name;
558
558
  this.description = description;
559
559
  this.options = options;
@@ -561,6 +561,7 @@ var Command = class _Command {
561
561
  this.examples = examples;
562
562
  this.omitInherited = omitInherited;
563
563
  this.handler = handler;
564
+ this.transformArgs = transformArgs;
564
565
  }
565
566
  // --------------------------------------------------------------------------
566
567
  // Tree building
@@ -575,7 +576,8 @@ var Command = class _Command {
575
576
  resolveArgsInput(config.args),
576
577
  config.examples ?? [],
577
578
  omitSet,
578
- config.handler
579
+ config.handler,
580
+ config.transformArgs
579
581
  );
580
582
  child.parent = this;
581
583
  this.children.set(name, child);
@@ -763,7 +765,8 @@ var Command = class _Command {
763
765
  return { stdout: generateHelp(this), stderr: "", exitCode: 0 };
764
766
  }
765
767
  if (this.handler) {
766
- const parsed = parseArgs(this.allOptions, this.args, [...tokens], env);
768
+ const effective = this.transformArgs ? this.transformArgs([...tokens]) : [...tokens];
769
+ const parsed = parseArgs(this.allOptions, this.args, effective, env);
767
770
  if (!parsed.ok) {
768
771
  return { stdout: "", stderr: formatErrors(parsed.errors), exitCode: 1 };
769
772
  }
@@ -797,7 +800,8 @@ function command(name, config) {
797
800
  resolveArgsInput(config.args),
798
801
  config.examples ?? [],
799
802
  /* @__PURE__ */ new Set(),
800
- config.handler
803
+ config.handler,
804
+ config.transformArgs
801
805
  );
802
806
  }
803
807
  function hasHelpFlag(tokens) {
@@ -177,6 +177,7 @@ declare class Command<THandlerArgs extends object = {}, TInvokeArgs extends obje
177
177
  readonly examples: readonly string[];
178
178
  readonly omitInherited: ReadonlySet<string>;
179
179
  readonly handler?: Handler<any>;
180
+ readonly transformArgs?: (tokens: string[]) => string[];
180
181
  readonly children: Map<string, Command<any, any>>;
181
182
  parent?: Command<any, any>;
182
183
  /** @internal — phantom type carrying the resolved handler args */
@@ -184,7 +185,7 @@ declare class Command<THandlerArgs extends object = {}, TInvokeArgs extends obje
184
185
  /** @internal — phantom type carrying the resolved invoke args */
185
186
  readonly _invokeArgs: TInvokeArgs;
186
187
  /** @internal */
187
- constructor(name: string, description: string, options: OptionsSchema, args: ArgsSchema, examples: readonly string[], omitInherited: ReadonlySet<string>, handler: Handler<any> | undefined);
188
+ constructor(name: string, description: string, options: OptionsSchema, args: ArgsSchema, examples: readonly string[], omitInherited: ReadonlySet<string>, handler: Handler<any> | undefined, transformArgs?: (tokens: string[]) => string[]);
188
189
  /** Add a subcommand. Returns the child command for further nesting. */
189
190
  command<TOpts extends OptionsInput = {}, const TArgs extends ArgsInput = [], const TOmit extends string[] = []>(name: string, config: {
190
191
  readonly description: string;
@@ -192,6 +193,7 @@ declare class Command<THandlerArgs extends object = {}, TInvokeArgs extends obje
192
193
  readonly args?: TArgs;
193
194
  readonly examples?: readonly string[];
194
195
  readonly omitInherited?: TOmit;
196
+ readonly transformArgs?: (tokens: string[]) => string[];
195
197
  readonly handler?: Handler<Prettify<Omit<THandlerArgs, TOmit[number]> & InferOptionsFromInput<TOpts> & InferArgsFromInput<TArgs>>>;
196
198
  }): Command<Prettify<Omit<THandlerArgs, TOmit[number]> & InferOptionsFromInput<TOpts> & InferArgsFromInput<TArgs>>, Prettify<Omit<TInvokeArgs, TOmit[number]> & InferInvokeOptions<TOpts> & InferInvokeArgs<TArgs>>>;
197
199
  /** Full path from root (e.g. "mycli db migrate") */
@@ -258,6 +260,7 @@ declare function command<TOpts extends OptionsInput = {}, const TArgs extends Ar
258
260
  readonly options?: TOpts;
259
261
  readonly args?: TArgs;
260
262
  readonly examples?: readonly string[];
263
+ readonly transformArgs?: (tokens: string[]) => string[];
261
264
  readonly handler?: Handler<Prettify<InferOptionsFromInput<TOpts> & InferArgsFromInput<TArgs>>>;
262
265
  }): Command<Prettify<InferOptionsFromInput<TOpts> & InferArgsFromInput<TArgs>>, Prettify<InferInvokeOptions<TOpts> & InferInvokeArgs<TArgs>>>;
263
266
  /**
@@ -8,7 +8,7 @@ import {
8
8
  generateHelp,
9
9
  o,
10
10
  parseArgs
11
- } from "../chunk-4J5EECVQ.js";
11
+ } from "../chunk-4EGDYWA4.js";
12
12
  export {
13
13
  Command,
14
14
  a,
package/dist/index.js CHANGED
@@ -8,7 +8,7 @@ import {
8
8
  generateHelp,
9
9
  o,
10
10
  parseArgs
11
- } from "./chunk-4J5EECVQ.js";
11
+ } from "./chunk-4EGDYWA4.js";
12
12
  import {
13
13
  findUp,
14
14
  loadConfig,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "just-bash-util",
3
- "version": "0.1.6",
3
+ "version": "0.1.8",
4
4
  "description": "CLI command framework, config file discovery, and path utilities for just-bash",
5
5
  "type": "module",
6
6
  "license": "MIT",