@optique/config 1.4.0-dev.2600 → 1.4.0-dev.2603

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/index.cjs CHANGED
@@ -22,6 +22,7 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
22
22
 
23
23
  //#endregion
24
24
  const node_fs = __toESM(require("node:fs"));
25
+ const node_os = __toESM(require("node:os"));
25
26
  const node_path = __toESM(require("node:path"));
26
27
  const __optique_core_annotations = __toESM(require("@optique/core/annotations"));
27
28
  const __optique_core_extension = __toESM(require("@optique/core/extension"));
@@ -66,6 +67,19 @@ function isStandardSchema(value) {
66
67
  if (standard == null || typeof standard !== "object" && typeof standard !== "function") return false;
67
68
  return typeof standard.validate === "function";
68
69
  }
70
+ /**
71
+ * Expands a leading `~` in a config file path to the home directory. Only
72
+ * a bare `~` and `~/` (or `~\` on Windows) prefixes are expanded; any other
73
+ * path is returned unchanged.
74
+ * @throws {Error} If the home directory cannot be determined.
75
+ */
76
+ function expandHomeDirectory(path) {
77
+ const hasHomePrefix = path === "~" || path.startsWith("~/") || node_path.sep === "\\" && path.startsWith("~\\");
78
+ if (!hasHomePrefix) return path;
79
+ const home = (0, node_os.homedir)();
80
+ if (!home) throw new Error("Cannot expand ~ in config path: the home directory could not be determined.");
81
+ return path === "~" ? home : (0, node_path.join)(home, path.slice(2));
82
+ }
69
83
  function isErrnoException(error) {
70
84
  return typeof error === "object" && error !== null && "code" in error;
71
85
  }
@@ -153,6 +167,7 @@ function createConfigContext(options) {
153
167
  if (!opts || !opts.getConfigPath && !opts.load) throw new TypeError("Either getConfigPath or load must be provided in the runner options when using ConfigContext.");
154
168
  if (opts.load !== void 0 && typeof opts.load !== "function") throw new TypeError(`Expected load to be a function, but got: ${getTypeName(opts.load)}.`);
155
169
  if (!opts.load && opts.getConfigPath !== void 0 && typeof opts.getConfigPath !== "function") throw new TypeError(`Expected getConfigPath to be a function, but got: ${getTypeName(opts.getConfigPath)}.`);
170
+ if (opts.expandHome !== void 0 && typeof opts.expandHome !== "boolean") throw new TypeError(`Expected expandHome to be a boolean, but got: ${getTypeName(opts.expandHome)}.`);
156
171
  const parsedPlaceholder = request.parsed;
157
172
  const emptyAnnotations = () => ({});
158
173
  const buildAnnotations = (configData, configMeta) => {
@@ -184,7 +199,7 @@ function createConfigContext(options) {
184
199
  const configPath = opts.getConfigPath(parsedPlaceholder);
185
200
  if (configPath !== void 0 && typeof configPath !== "string") throw new TypeError(`Expected getConfigPath() to return a string or undefined, but got: ${getTypeName(configPath)}.`);
186
201
  if (!configPath) return emptyAnnotations();
187
- const absoluteConfigPath = (0, node_path.resolve)(configPath);
202
+ const absoluteConfigPath = (0, node_path.resolve)(opts.expandHome ? expandHomeDirectory(configPath) : configPath);
188
203
  const singleFileMeta = {
189
204
  configDir: (0, node_path.dirname)(absoluteConfigPath),
190
205
  configPath: absoluteConfigPath
package/dist/index.d.cts CHANGED
@@ -103,6 +103,25 @@ interface ConfigContextRequiredOptions<TConfigMeta = ConfigMeta> {
103
103
  * @since 1.0.0
104
104
  */
105
105
  readonly load?: (parsed: ParserValuePlaceholder) => Promise<ConfigLoadResult<TConfigMeta> | undefined | null> | ConfigLoadResult<TConfigMeta> | undefined | null;
106
+ /**
107
+ * Whether to expand a leading `~` in the path returned by `getConfigPath()`
108
+ * to the current user's home directory. Defaults to `false`, so the path
109
+ * is used as is, since `~` is a valid file name character on most
110
+ * platforms.
111
+ *
112
+ * When enabled, only a bare `~` and paths starting with `~/` (or `~\` on
113
+ * Windows) are expanded. Other forms such as `~user/config.json` are left
114
+ * unchanged. The expanded path is also what `ConfigMeta` reports.
115
+ *
116
+ * This option only affects single-file mode. It has no effect when `load`
117
+ * is provided, although it is still validated.
118
+ *
119
+ * On Deno, looking up the home directory requires the
120
+ * `--allow-sys=homedir` permission.
121
+ *
122
+ * @since 1.4.0
123
+ */
124
+ readonly expandHome?: boolean;
106
125
  }
107
126
  /**
108
127
  * A config context that provides configuration data via annotations.
package/dist/index.d.ts CHANGED
@@ -103,6 +103,25 @@ interface ConfigContextRequiredOptions<TConfigMeta = ConfigMeta> {
103
103
  * @since 1.0.0
104
104
  */
105
105
  readonly load?: (parsed: ParserValuePlaceholder) => Promise<ConfigLoadResult<TConfigMeta> | undefined | null> | ConfigLoadResult<TConfigMeta> | undefined | null;
106
+ /**
107
+ * Whether to expand a leading `~` in the path returned by `getConfigPath()`
108
+ * to the current user's home directory. Defaults to `false`, so the path
109
+ * is used as is, since `~` is a valid file name character on most
110
+ * platforms.
111
+ *
112
+ * When enabled, only a bare `~` and paths starting with `~/` (or `~\` on
113
+ * Windows) are expanded. Other forms such as `~user/config.json` are left
114
+ * unchanged. The expanded path is also what `ConfigMeta` reports.
115
+ *
116
+ * This option only affects single-file mode. It has no effect when `load`
117
+ * is provided, although it is still validated.
118
+ *
119
+ * On Deno, looking up the home directory requires the
120
+ * `--allow-sys=homedir` permission.
121
+ *
122
+ * @since 1.4.0
123
+ */
124
+ readonly expandHome?: boolean;
106
125
  }
107
126
  /**
108
127
  * A config context that provides configuration data via annotations.
package/dist/index.js CHANGED
@@ -1,5 +1,6 @@
1
1
  import { readFileSync } from "node:fs";
2
- import { dirname, resolve } from "node:path";
2
+ import { homedir } from "node:os";
3
+ import { dirname, join, resolve, sep } from "node:path";
3
4
  import { getAnnotations } from "@optique/core/annotations";
4
5
  import { defineTraits, delegateSuggestNodes, inheritAnnotations, injectAnnotations, mapModeValue, mapSourceMetadata, withAnnotationView, wrapForMode } from "@optique/core/extension";
5
6
  import { fluent } from "@optique/core/fluent";
@@ -43,6 +44,19 @@ function isStandardSchema(value) {
43
44
  if (standard == null || typeof standard !== "object" && typeof standard !== "function") return false;
44
45
  return typeof standard.validate === "function";
45
46
  }
47
+ /**
48
+ * Expands a leading `~` in a config file path to the home directory. Only
49
+ * a bare `~` and `~/` (or `~\` on Windows) prefixes are expanded; any other
50
+ * path is returned unchanged.
51
+ * @throws {Error} If the home directory cannot be determined.
52
+ */
53
+ function expandHomeDirectory(path) {
54
+ const hasHomePrefix = path === "~" || path.startsWith("~/") || sep === "\\" && path.startsWith("~\\");
55
+ if (!hasHomePrefix) return path;
56
+ const home = homedir();
57
+ if (!home) throw new Error("Cannot expand ~ in config path: the home directory could not be determined.");
58
+ return path === "~" ? home : join(home, path.slice(2));
59
+ }
46
60
  function isErrnoException(error) {
47
61
  return typeof error === "object" && error !== null && "code" in error;
48
62
  }
@@ -130,6 +144,7 @@ function createConfigContext(options) {
130
144
  if (!opts || !opts.getConfigPath && !opts.load) throw new TypeError("Either getConfigPath or load must be provided in the runner options when using ConfigContext.");
131
145
  if (opts.load !== void 0 && typeof opts.load !== "function") throw new TypeError(`Expected load to be a function, but got: ${getTypeName(opts.load)}.`);
132
146
  if (!opts.load && opts.getConfigPath !== void 0 && typeof opts.getConfigPath !== "function") throw new TypeError(`Expected getConfigPath to be a function, but got: ${getTypeName(opts.getConfigPath)}.`);
147
+ if (opts.expandHome !== void 0 && typeof opts.expandHome !== "boolean") throw new TypeError(`Expected expandHome to be a boolean, but got: ${getTypeName(opts.expandHome)}.`);
133
148
  const parsedPlaceholder = request.parsed;
134
149
  const emptyAnnotations = () => ({});
135
150
  const buildAnnotations = (configData, configMeta) => {
@@ -161,7 +176,7 @@ function createConfigContext(options) {
161
176
  const configPath = opts.getConfigPath(parsedPlaceholder);
162
177
  if (configPath !== void 0 && typeof configPath !== "string") throw new TypeError(`Expected getConfigPath() to return a string or undefined, but got: ${getTypeName(configPath)}.`);
163
178
  if (!configPath) return emptyAnnotations();
164
- const absoluteConfigPath = resolve(configPath);
179
+ const absoluteConfigPath = resolve(opts.expandHome ? expandHomeDirectory(configPath) : configPath);
165
180
  const singleFileMeta = {
166
181
  configDir: dirname(absoluteConfigPath),
167
182
  configPath: absoluteConfigPath
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@optique/config",
3
- "version": "1.4.0-dev.2600",
3
+ "version": "1.4.0-dev.2603",
4
4
  "description": "Configuration file support for Optique with Standard Schema validation",
5
5
  "keywords": [
6
6
  "CLI",
@@ -65,10 +65,10 @@
65
65
  "@standard-schema/spec": "^1.1.0"
66
66
  },
67
67
  "dependencies": {
68
- "@optique/core": "1.4.0-dev.2600+6c98c033"
68
+ "@optique/core": "1.4.0-dev.2603+d6d54fca"
69
69
  },
70
70
  "devDependencies": {
71
- "@optique/env": "1.4.0-dev.2600+6c98c033",
71
+ "@optique/env": "1.4.0-dev.2603+d6d54fca",
72
72
  "@standard-schema/spec": "^1.1.0",
73
73
  "@types/node": "^24.0.0",
74
74
  "fast-check": "^4.7.0",