just-bash-util 0.1.2 → 0.1.4

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
@@ -28,9 +28,9 @@ const cli = command("mycli", {
28
28
  const serve = cli.command("serve", {
29
29
  description: "Start the dev server",
30
30
  options: {
31
- port: o.number().default(3000).short("p").describe("Port to listen on"),
31
+ port: o.number().default(3000).alias("p").describe("Port to listen on"),
32
32
  host: o.string().describe("Host to bind to"),
33
- open: f().short("o").describe("Open browser"),
33
+ open: f().alias("o").describe("Open browser"),
34
34
  },
35
35
  args: [a.string().name("entry").describe("Entry file")],
36
36
  handler: (args, ctx) => {
@@ -67,6 +67,7 @@ await serve.invoke({ port: 8080, entry: "app.ts" }, ctx);
67
67
  - `--` passthrough separator
68
68
  - Environment variable fallbacks for options
69
69
  - Levenshtein-based "did you mean?" suggestions for typos
70
+ - Automatic error handling — thrown errors in handlers are caught and returned as clean `ExecResult` with `exitCode: 1`
70
71
 
71
72
  ### `just-bash-util/config` — Config file discovery
72
73
 
@@ -75,7 +76,7 @@ Cosmiconfig-style config search that walks up the directory tree, trying convent
75
76
  ```ts
76
77
  import { searchConfig } from "just-bash-util/config";
77
78
 
78
- // Walks up from cwd trying: package.json#myapp, .myapprc, .myapprc.json, myapp.config.json
79
+ // Walks up from cwd trying: .myapprc, .myapprc.json, myapp.config.json
79
80
  const result = await searchConfig(ctx, { name: "myapp" });
80
81
  if (result) {
81
82
  result.config; // parsed config object
@@ -83,11 +84,14 @@ if (result) {
83
84
  result.isEmpty; // true if config is null/undefined/empty object
84
85
  }
85
86
 
86
- // Customize search places, starting directory, or add custom loaders
87
+ // Find nearest package.json and return its full contents
88
+ const pkg = await searchConfig(ctx, { name: "package", searchPlaces: ["package.json"] });
89
+
90
+ // Extract a tool-specific property from package.json
87
91
  const result2 = await searchConfig(ctx, {
88
92
  name: "myapp",
89
- from: "/specific/start/dir",
90
- searchPlaces: [".myapprc.json", "myapp.config.json"],
93
+ searchPlaces: ["package.json", ".myapprc", ".myapprc.json"],
94
+ packageJsonProp: "myapp",
91
95
  });
92
96
  ```
93
97
 
@@ -126,12 +130,16 @@ import {
126
130
  relative,
127
131
  parse,
128
132
  normalize,
133
+ parsePackageSpecifier,
129
134
  } from "just-bash-util/path";
130
135
 
131
136
  join("src", "utils", "index.ts"); // "src/utils/index.ts"
132
137
  dirname("/project/src/index.ts"); // "/project/src"
133
138
  basename("src/index.ts", ".ts"); // "index"
134
139
  relative("/a/b/c", "/a/d"); // "../../d"
140
+
141
+ parsePackageSpecifier("@vue/shared/dist"); // { name: "@vue/shared", subpath: "./dist" }
142
+ parsePackageSpecifier("lodash/merge"); // { name: "lodash", subpath: "./merge" }
135
143
  ```
136
144
 
137
145
  ## Peer dependencies
@@ -9,9 +9,9 @@ var OptionBuilder = class _OptionBuilder {
9
9
  describe(text) {
10
10
  return new _OptionBuilder({ ...this._def, description: text });
11
11
  }
12
- /** Set a short alias (single character) */
13
- short(alias) {
14
- return new _OptionBuilder({ ...this._def, short: alias });
12
+ /** Set a short alias (single character, e.g. "p" for -p) */
13
+ alias(short) {
14
+ return new _OptionBuilder({ ...this._def, short });
15
15
  }
16
16
  /** Set an environment variable fallback */
17
17
  env(name) {
@@ -56,9 +56,9 @@ var FlagBuilder = class _FlagBuilder {
56
56
  describe(text) {
57
57
  return new _FlagBuilder({ ...this._def, description: text });
58
58
  }
59
- /** Set a short alias (single character) */
60
- short(alias) {
61
- return new _FlagBuilder({ ...this._def, short: alias });
59
+ /** Set a short alias (single character, e.g. "v" for -v) */
60
+ alias(short) {
61
+ return new _FlagBuilder({ ...this._def, short });
62
62
  }
63
63
  /** Set a default value */
64
64
  default(value) {
@@ -91,7 +91,9 @@ var ArgBuilder = class _ArgBuilder {
91
91
  required: false
92
92
  });
93
93
  }
94
- /** Mark as variadic — collects all remaining positionals into an array */
94
+ /** Mark as variadic — collects all remaining positionals into an array.
95
+ * If the arg is already optional, element-level undefined is stripped
96
+ * (the optionality means "zero or more", not "elements can be undefined"). */
95
97
  variadic() {
96
98
  return new _ArgBuilder({
97
99
  ...this._def,
@@ -307,6 +309,8 @@ function parseArgs(options, argDefs, tokens, env) {
307
309
  errors.push({ type: "missing_required", name: argName, kind: "arg" });
308
310
  } else if (argDef.default !== void 0) {
309
311
  result[argName] = argDef.default;
312
+ } else {
313
+ result[argName] = [];
310
314
  }
311
315
  posIdx = positionals.length;
312
316
  } else {
@@ -527,12 +531,8 @@ var Command = class _Command {
527
531
  handler;
528
532
  children = /* @__PURE__ */ new Map();
529
533
  parent;
530
- /** @internal — accumulated builder types for generic inference */
531
- _accOpts;
532
- /** @internal — args builder types for generic inference */
533
- _accArgs;
534
534
  /** @internal */
535
- constructor(name, description, options, args, examples, omitInherited, handler, accOpts, accArgs) {
535
+ constructor(name, description, options, args, examples, omitInherited, handler) {
536
536
  this.name = name;
537
537
  this.description = description;
538
538
  this.options = options;
@@ -540,8 +540,6 @@ var Command = class _Command {
540
540
  this.examples = examples;
541
541
  this.omitInherited = omitInherited;
542
542
  this.handler = handler;
543
- this._accOpts = accOpts;
544
- this._accArgs = accArgs;
545
543
  }
546
544
  // --------------------------------------------------------------------------
547
545
  // Tree building
@@ -549,9 +547,6 @@ var Command = class _Command {
549
547
  /** Add a subcommand. Returns the child command for further nesting. */
550
548
  command(name, config) {
551
549
  const omitSet = new Set(config.omitInherited ?? []);
552
- const parentAcc = { ...this._accOpts };
553
- for (const key of omitSet) delete parentAcc[key];
554
- const accOpts = { ...parentAcc, ...config.options ?? {} };
555
550
  const child = new _Command(
556
551
  name,
557
552
  config.description,
@@ -559,9 +554,7 @@ var Command = class _Command {
559
554
  resolveArgsInput(config.args),
560
555
  config.examples ?? [],
561
556
  omitSet,
562
- config.handler,
563
- accOpts,
564
- config.args ?? []
557
+ config.handler
565
558
  );
566
559
  child.parent = this;
567
560
  this.children.set(name, child);
@@ -720,7 +713,12 @@ var Command = class _Command {
720
713
  }
721
714
  }
722
715
  }
723
- return this.handler(resolved, ctx, { passthrough: [] });
716
+ try {
717
+ return await this.handler(resolved, ctx, { passthrough: [] });
718
+ } catch (err) {
719
+ const message = err instanceof Error ? err.message : String(err);
720
+ return { stdout: "", stderr: message, exitCode: 1 };
721
+ }
724
722
  }
725
723
  // --------------------------------------------------------------------------
726
724
  // Execution
@@ -746,7 +744,12 @@ var Command = class _Command {
746
744
  if (!parsed.ok) {
747
745
  return { stdout: "", stderr: formatErrors(parsed.errors), exitCode: 1 };
748
746
  }
749
- return this.handler(parsed.args, ctx, { passthrough: parsed.passthrough });
747
+ try {
748
+ return await this.handler(parsed.args, ctx, { passthrough: parsed.passthrough });
749
+ } catch (err) {
750
+ const message = err instanceof Error ? err.message : String(err);
751
+ return { stdout: "", stderr: message, exitCode: 1 };
752
+ }
750
753
  }
751
754
  if (firstToken && !firstToken.startsWith("-")) {
752
755
  const suggestions = findSuggestions(firstToken, [...this.children.keys()]);
@@ -771,9 +774,7 @@ function command(name, config) {
771
774
  resolveArgsInput(config.args),
772
775
  config.examples ?? [],
773
776
  /* @__PURE__ */ new Set(),
774
- config.handler,
775
- config.options ?? {},
776
- config.args ?? []
777
+ config.handler
777
778
  );
778
779
  }
779
780
  function hasHelpFlag(tokens) {
@@ -3,7 +3,7 @@ import {
3
3
  dirname,
4
4
  extname,
5
5
  join
6
- } from "./chunk-DAO5RF73.js";
6
+ } from "./chunk-HJ3ZU6QO.js";
7
7
 
8
8
  // src/config/find-up.ts
9
9
  async function findUp(ctx, name, options) {
@@ -88,7 +88,6 @@ function deepMerge(base, override) {
88
88
  var defaultLoader = (content) => parseJsonc(content);
89
89
  function defaultSearchPlaces(name) {
90
90
  return [
91
- "package.json",
92
91
  `.${name}rc`,
93
92
  `.${name}rc.json`,
94
93
  `${name}.config.json`
@@ -133,7 +132,7 @@ async function collectAll(ctx, options) {
133
132
  from = ctx.cwd,
134
133
  searchPlaces = defaultSearchPlaces(name),
135
134
  loaders: customLoaders,
136
- packageJsonProp = name,
135
+ packageJsonProp = false,
137
136
  stopAt = "/",
138
137
  stopWhen
139
138
  } = options;
@@ -184,7 +183,7 @@ async function searchConfig(ctx, options) {
184
183
  from = ctx.cwd,
185
184
  searchPlaces = defaultSearchPlaces(name),
186
185
  loaders: customLoaders,
187
- packageJsonProp = name,
186
+ packageJsonProp = false,
188
187
  stopAt = "/"
189
188
  } = options;
190
189
  let dir = from;
@@ -115,6 +115,30 @@ function format(pathObject) {
115
115
  }
116
116
  return `${root}${resolvedBase}`;
117
117
  }
118
+ function parsePackageSpecifier(specifier) {
119
+ if (specifier.startsWith("@")) {
120
+ const firstSlash2 = specifier.indexOf("/");
121
+ if (firstSlash2 === -1) {
122
+ return { name: specifier, subpath: "." };
123
+ }
124
+ const secondSlash = specifier.indexOf("/", firstSlash2 + 1);
125
+ if (secondSlash === -1) {
126
+ return { name: specifier, subpath: "." };
127
+ }
128
+ return {
129
+ name: specifier.slice(0, secondSlash),
130
+ subpath: `.${specifier.slice(secondSlash)}`
131
+ };
132
+ }
133
+ const firstSlash = specifier.indexOf("/");
134
+ if (firstSlash === -1) {
135
+ return { name: specifier, subpath: "." };
136
+ }
137
+ return {
138
+ name: specifier.slice(0, firstSlash),
139
+ subpath: `.${specifier.slice(firstSlash)}`
140
+ };
141
+ }
118
142
  function relative(from, to) {
119
143
  const fromNorm = normalize(from);
120
144
  const toNorm = normalize(to);
@@ -149,5 +173,6 @@ export {
149
173
  extname,
150
174
  parse,
151
175
  format,
176
+ parsePackageSpecifier,
152
177
  relative
153
178
  };
@@ -74,8 +74,8 @@ declare class OptionBuilder<TOut, THasDefault extends boolean = false> {
74
74
  constructor(def: OptionDef<TOut>);
75
75
  /** Add a description */
76
76
  describe(text: string): OptionBuilder<TOut, THasDefault>;
77
- /** Set a short alias (single character) */
78
- short(alias: string): OptionBuilder<TOut, THasDefault>;
77
+ /** Set a short alias (single character, e.g. "p" for -p) */
78
+ alias(short: string): OptionBuilder<TOut, THasDefault>;
79
79
  /** Set an environment variable fallback */
80
80
  env(name: string): OptionBuilder<TOut, THasDefault>;
81
81
  /** Mark as required — removes undefined from TOut */
@@ -94,8 +94,8 @@ declare class FlagBuilder {
94
94
  constructor(def?: FlagDef);
95
95
  /** Add a description */
96
96
  describe(text: string): FlagBuilder;
97
- /** Set a short alias (single character) */
98
- short(alias: string): FlagBuilder;
97
+ /** Set a short alias (single character, e.g. "v" for -v) */
98
+ alias(short: string): FlagBuilder;
99
99
  /** Set a default value */
100
100
  default(value: boolean): FlagBuilder;
101
101
  }
@@ -110,8 +110,10 @@ declare class ArgBuilder<TOut, TName extends string = never, THasDefault extends
110
110
  describe(text: string): ArgBuilder<TOut, TName, THasDefault>;
111
111
  /** Mark as optional — adds undefined to TOut */
112
112
  optional(): ArgBuilder<TOut | undefined, TName, THasDefault>;
113
- /** Mark as variadic — collects all remaining positionals into an array */
114
- variadic(): ArgBuilder<TOut[], TName, THasDefault>;
113
+ /** Mark as variadic — collects all remaining positionals into an array.
114
+ * If the arg is already optional, element-level undefined is stripped
115
+ * (the optionality means "zero or more", not "elements can be undefined"). */
116
+ variadic(): ArgBuilder<NonNullable<TOut>[], TName, THasDefault>;
115
117
  /** Set a default value (also makes the arg optional at parse time) */
116
118
  default(value: TOut): ArgBuilder<TOut, TName, true>;
117
119
  }
@@ -161,7 +163,7 @@ type InferInvokeArgs<T extends ArgsInput> = {
161
163
  } & {
162
164
  [I in keyof T & `${number}` as T[I] extends ArgBuilder<infer _V, infer N extends string, infer D> ? [D] extends [true] ? N : T[I] extends ArgBuilder<infer V, any, any> ? undefined extends V ? N : never : never : never]?: T[I] extends ArgBuilder<infer V, any, any> ? V : never;
163
165
  };
164
- declare class Command<TAccOpts extends OptionsInput = {}, TAccArgs extends ArgsInput = []> {
166
+ declare class Command<THandlerArgs extends object = {}, TInvokeArgs extends object = {}> {
165
167
  readonly name: string;
166
168
  readonly description: string;
167
169
  readonly options: OptionsSchema;
@@ -171,12 +173,12 @@ declare class Command<TAccOpts extends OptionsInput = {}, TAccArgs extends ArgsI
171
173
  readonly handler?: Handler<any>;
172
174
  readonly children: Map<string, Command<any, any>>;
173
175
  parent?: Command<any, any>;
174
- /** @internal — accumulated builder types for generic inference */
175
- readonly _accOpts: TAccOpts;
176
- /** @internal — args builder types for generic inference */
177
- readonly _accArgs: TAccArgs;
176
+ /** @internal — phantom type carrying the resolved handler args */
177
+ readonly _handlerArgs: THandlerArgs;
178
+ /** @internal — phantom type carrying the resolved invoke args */
179
+ readonly _invokeArgs: TInvokeArgs;
178
180
  /** @internal */
179
- constructor(name: string, description: string, options: OptionsSchema, args: ArgsSchema, examples: readonly string[], omitInherited: ReadonlySet<string>, handler: Handler<any> | undefined, accOpts: TAccOpts, accArgs: TAccArgs);
181
+ constructor(name: string, description: string, options: OptionsSchema, args: ArgsSchema, examples: readonly string[], omitInherited: ReadonlySet<string>, handler: Handler<any> | undefined);
180
182
  /** Add a subcommand. Returns the child command for further nesting. */
181
183
  command<TOpts extends OptionsInput = {}, const TArgs extends ArgsInput = [], const TOmit extends string[] = []>(name: string, config: {
182
184
  readonly description: string;
@@ -184,8 +186,8 @@ declare class Command<TAccOpts extends OptionsInput = {}, TAccArgs extends ArgsI
184
186
  readonly args?: TArgs;
185
187
  readonly examples?: readonly string[];
186
188
  readonly omitInherited?: TOmit;
187
- readonly handler?: Handler<Prettify<Omit<InferOptionsFromInput<TAccOpts>, TOmit[number]> & InferOptionsFromInput<TOpts> & InferArgsFromInput<TArgs>>>;
188
- }): Command<Omit<TAccOpts, TOmit[number]> & TOpts, TArgs>;
189
+ readonly handler?: Handler<Prettify<Omit<THandlerArgs, TOmit[number]> & InferOptionsFromInput<TOpts> & InferArgsFromInput<TArgs>>>;
190
+ }): Command<Prettify<Omit<THandlerArgs, TOmit[number]> & InferOptionsFromInput<TOpts> & InferArgsFromInput<TArgs>>, Prettify<Omit<TInvokeArgs, TOmit[number]> & InferInvokeOptions<TOpts> & InferInvokeArgs<TArgs>>>;
189
191
  /** Full path from root (e.g. "mycli db migrate") */
190
192
  get fullPath(): string;
191
193
  /**
@@ -221,7 +223,7 @@ declare class Command<TAccOpts extends OptionsInput = {}, TAccArgs extends ArgsI
221
223
  * await cli.execute(["serve", ...tokens], ctx);
222
224
  * ```
223
225
  */
224
- toTokens(args: Partial<Prettify<InferOptionsFromInput<TAccOpts> & InferArgsFromInput<TAccArgs>>>): string[];
226
+ toTokens(args: Partial<THandlerArgs>): string[];
225
227
  /**
226
228
  * Call this command's handler directly with typed args.
227
229
  *
@@ -234,7 +236,7 @@ declare class Command<TAccOpts extends OptionsInput = {}, TAccArgs extends ArgsI
234
236
  * const result = await serve.invoke({ port: 8080, entry: "app.ts" }, ctx);
235
237
  * ```
236
238
  */
237
- invoke(args: Prettify<InferInvokeOptions<TAccOpts> & InferInvokeArgs<TAccArgs>>, ctx: CommandContext): Promise<ExecResult>;
239
+ invoke(args: TInvokeArgs, ctx: CommandContext): Promise<ExecResult>;
238
240
  /**
239
241
  * Execute this command tree with the given tokens.
240
242
  *
@@ -251,7 +253,7 @@ declare function command<TOpts extends OptionsInput = {}, const TArgs extends Ar
251
253
  readonly args?: TArgs;
252
254
  readonly examples?: readonly string[];
253
255
  readonly handler?: Handler<Prettify<InferOptionsFromInput<TOpts> & InferArgsFromInput<TArgs>>>;
254
- }): Command<TOpts, TArgs>;
256
+ }): Command<Prettify<InferOptionsFromInput<TOpts> & InferArgsFromInput<TArgs>>, Prettify<InferInvokeOptions<TOpts> & InferInvokeArgs<TArgs>>>;
255
257
  /**
256
258
  * Infer the handler args type from a Command instance.
257
259
  *
@@ -270,7 +272,7 @@ declare function command<TOpts extends OptionsInput = {}, const TArgs extends Ar
270
272
  * // ^? { port: number; entry: string }
271
273
  * ```
272
274
  */
273
- type Infer<T extends Command<any, any>> = Prettify<InferOptionsFromInput<T["_accOpts"]> & InferArgsFromInput<T["_accArgs"]>>;
275
+ type Infer<T extends Command<any, any>> = T["_handlerArgs"];
274
276
 
275
277
  type ParseArgsResult = {
276
278
  ok: true;
@@ -8,7 +8,7 @@ import {
8
8
  generateHelp,
9
9
  o,
10
10
  parseArgs
11
- } from "../chunk-OLDCCFR6.js";
11
+ } from "../chunk-35QZZQ4A.js";
12
12
  export {
13
13
  Command,
14
14
  a,
@@ -40,7 +40,6 @@ interface SearchConfigOptions {
40
40
  * Filenames to look for at each directory level, tried in order.
41
41
  *
42
42
  * Defaults:
43
- * - `"package.json"` (extracts the `name` property)
44
43
  * - `".{name}rc"`
45
44
  * - `".{name}rc.json"`
46
45
  * - `"{name}.config.json"`
@@ -54,7 +53,7 @@ interface SearchConfigOptions {
54
53
  /**
55
54
  * Property to extract from `package.json`.
56
55
  * Set to `false` to disable property extraction (load full object).
57
- * Default: the `name` option.
56
+ * Default: `false`.
58
57
  */
59
58
  packageJsonProp?: string | false;
60
59
  /** Directory to stop searching at (default: `"/"`) */
@@ -105,6 +104,16 @@ interface LoadConfigOptions {
105
104
  * const result = await searchConfig(ctx, { name: "myapp" });
106
105
  * if (result) console.log(result.config, result.filepath);
107
106
  *
107
+ * // Find nearest package.json and return its full contents
108
+ * const pkg = await searchConfig(ctx, { name: "package", searchPlaces: ["package.json"] });
109
+ *
110
+ * // Extract a specific property from package.json
111
+ * const result = await searchConfig(ctx, {
112
+ * name: "myapp",
113
+ * searchPlaces: ["package.json", ".myapprc", ".myapprc.json"],
114
+ * packageJsonProp: "myapp",
115
+ * });
116
+ *
108
117
  * // Layered / cascading config
109
118
  * const merged = await searchConfig(ctx, { name: "myapp", merge: true });
110
119
  * ```
@@ -2,8 +2,8 @@ import {
2
2
  findUp,
3
3
  loadConfig,
4
4
  searchConfig
5
- } from "../chunk-DLIJNNDI.js";
6
- import "../chunk-DAO5RF73.js";
5
+ } from "../chunk-FUVD54LW.js";
6
+ import "../chunk-HJ3ZU6QO.js";
7
7
  export {
8
8
  findUp,
9
9
  loadConfig,
package/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
1
  export { Command, Handler, Infer, ParseArgsResult, ParseError, a, command, f, formatError, formatErrors, generateHelp, o, parseArgs } from './command/index.js';
2
2
  export { ConfigResult, FindUpOptions, LoadConfigOptions, Loader, SearchConfigOptions, findUp, loadConfig, searchConfig } from './config/index.js';
3
- export { ParsedPath, basename, delimiter, dirname, extname, format, isAbsolute, join, normalize, parse, relative, resolve, sep } from './path/index.js';
3
+ export { PackageSpecifier, ParsedPath, basename, delimiter, dirname, extname, format, isAbsolute, join, normalize, parse, parsePackageSpecifier, relative, resolve, sep } from './path/index.js';
4
4
  import 'just-bash';
package/dist/index.js CHANGED
@@ -8,12 +8,12 @@ import {
8
8
  generateHelp,
9
9
  o,
10
10
  parseArgs
11
- } from "./chunk-OLDCCFR6.js";
11
+ } from "./chunk-35QZZQ4A.js";
12
12
  import {
13
13
  findUp,
14
14
  loadConfig,
15
15
  searchConfig
16
- } from "./chunk-DLIJNNDI.js";
16
+ } from "./chunk-FUVD54LW.js";
17
17
  import {
18
18
  basename,
19
19
  delimiter,
@@ -24,10 +24,11 @@ import {
24
24
  join,
25
25
  normalize,
26
26
  parse,
27
+ parsePackageSpecifier,
27
28
  relative,
28
29
  resolve,
29
30
  sep
30
- } from "./chunk-DAO5RF73.js";
31
+ } from "./chunk-HJ3ZU6QO.js";
31
32
  export {
32
33
  Command,
33
34
  a,
@@ -49,6 +50,7 @@ export {
49
50
  o,
50
51
  parse,
51
52
  parseArgs,
53
+ parsePackageSpecifier,
52
54
  relative,
53
55
  resolve,
54
56
  searchConfig,
@@ -33,7 +33,26 @@ interface ParsedPath {
33
33
  declare function parse(path: string): ParsedPath;
34
34
  /** Build a path string from components (inverse of `parse`) */
35
35
  declare function format(pathObject: Partial<ParsedPath>): string;
36
+ interface PackageSpecifier {
37
+ /** Package name (e.g. `"pkg"` or `"@scope/pkg"`) */
38
+ name: string;
39
+ /** Subpath within the package (e.g. `"./sub/path"`), or `"."` for the root */
40
+ subpath: string;
41
+ }
42
+ /**
43
+ * Parse a bare package specifier into its package name and subpath.
44
+ *
45
+ * Handles both scoped (`@scope/pkg/sub`) and unscoped (`pkg/sub`) specifiers.
46
+ * The subpath is normalized to start with `"./"` (or `"."` for the root).
47
+ *
48
+ * ```ts
49
+ * parsePackageSpecifier("lodash/merge") // { name: "lodash", subpath: "./merge" }
50
+ * parsePackageSpecifier("@vue/shared/dist") // { name: "@vue/shared", subpath: "./dist" }
51
+ * parsePackageSpecifier("react") // { name: "react", subpath: "." }
52
+ * ```
53
+ */
54
+ declare function parsePackageSpecifier(specifier: string): PackageSpecifier;
36
55
  /** Compute the relative path from `from` to `to` */
37
56
  declare function relative(from: string, to: string): string;
38
57
 
39
- export { type ParsedPath, basename, delimiter, dirname, extname, format, isAbsolute, join, normalize, parse, relative, resolve, sep };
58
+ export { type PackageSpecifier, type ParsedPath, basename, delimiter, dirname, extname, format, isAbsolute, join, normalize, parse, parsePackageSpecifier, relative, resolve, sep };
@@ -8,10 +8,11 @@ import {
8
8
  join,
9
9
  normalize,
10
10
  parse,
11
+ parsePackageSpecifier,
11
12
  relative,
12
13
  resolve,
13
14
  sep
14
- } from "../chunk-DAO5RF73.js";
15
+ } from "../chunk-HJ3ZU6QO.js";
15
16
  export {
16
17
  basename,
17
18
  delimiter,
@@ -22,6 +23,7 @@ export {
22
23
  join,
23
24
  normalize,
24
25
  parse,
26
+ parsePackageSpecifier,
25
27
  relative,
26
28
  resolve,
27
29
  sep
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "just-bash-util",
3
- "version": "0.1.2",
3
+ "version": "0.1.4",
4
4
  "description": "CLI command framework, config file discovery, and path utilities for just-bash",
5
5
  "type": "module",
6
6
  "license": "MIT",