just-bash-util 0.1.2 → 0.1.3

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
@@ -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
@@ -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
  };
@@ -720,7 +720,12 @@ var Command = class _Command {
720
720
  }
721
721
  }
722
722
  }
723
- return this.handler(resolved, ctx, { passthrough: [] });
723
+ try {
724
+ return await this.handler(resolved, ctx, { passthrough: [] });
725
+ } catch (err) {
726
+ const message = err instanceof Error ? err.message : String(err);
727
+ return { stdout: "", stderr: message, exitCode: 1 };
728
+ }
724
729
  }
725
730
  // --------------------------------------------------------------------------
726
731
  // Execution
@@ -746,7 +751,12 @@ var Command = class _Command {
746
751
  if (!parsed.ok) {
747
752
  return { stdout: "", stderr: formatErrors(parsed.errors), exitCode: 1 };
748
753
  }
749
- return this.handler(parsed.args, ctx, { passthrough: parsed.passthrough });
754
+ try {
755
+ return await this.handler(parsed.args, ctx, { passthrough: parsed.passthrough });
756
+ } catch (err) {
757
+ const message = err instanceof Error ? err.message : String(err);
758
+ return { stdout: "", stderr: message, exitCode: 1 };
759
+ }
750
760
  }
751
761
  if (firstToken && !firstToken.startsWith("-")) {
752
762
  const suggestions = findSuggestions(firstToken, [...this.children.keys()]);
@@ -8,7 +8,7 @@ import {
8
8
  generateHelp,
9
9
  o,
10
10
  parseArgs
11
- } from "../chunk-OLDCCFR6.js";
11
+ } from "../chunk-QKL3AOEA.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-QKL3AOEA.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.3",
4
4
  "description": "CLI command framework, config file discovery, and path utilities for just-bash",
5
5
  "type": "module",
6
6
  "license": "MIT",