@o3co/ts.hocon 1.14.1 → 1.14.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/dist/zod.d.ts CHANGED
@@ -4,10 +4,12 @@ import { C as Config, D as DurationUnit, B as ByteUnit, b as Period, a as ParseO
4
4
  /**
5
5
  * The whole config, validated against `schema`. HOCON strings are coerced
6
6
  * where the schema expects a number or a boolean (`"8080"` → 8080), through
7
- * objects, arrays, records, tuples, unions, pipes (by their input schema), lazy
8
- * schemas and optional / nullable / default / prefault / nonoptional / catch /
9
- * readonly wrappers; a union coerces by the option that takes the value (see
10
- * the README). Unit values go through the {@link hocon} markers.
7
+ * objects (and their catchall), arrays, records, tuples, unions,
8
+ * intersections, pipes (by their input schema), lazy schemas, numeric literals
9
+ * and enums, and optional / nullable / default / prefault / nonoptional /
10
+ * success / catch / readonly wrappers; a union coerces by the option that
11
+ * takes the value (see the README). Unit values go through the {@link hocon}
12
+ * markers.
11
13
  *
12
14
  * An object key named `__proto__`, `constructor` or `prototype` anywhere in
13
15
  * the value is refused with a `ZodError` issue at the object that holds it
@@ -34,6 +36,18 @@ declare function validate<T>(config: Config, schema: ZodType<T>): T;
34
36
  * @throws `ZodError` when the value does not match the schema.
35
37
  */
36
38
  declare function getValidated<T>(config: Config, path: string, schema: ZodType<T>): T;
39
+ /**
40
+ * Options for the {@link hocon} unit markers.
41
+ */
42
+ interface UnitMarkerOptions {
43
+ /**
44
+ * Refuse a value that does not name its unit: a number (`ttl = 30`) or a
45
+ * string of the number alone (`"30"`, what an environment variable gives),
46
+ * which would otherwise read in the default unit (milliseconds, bytes, days).
47
+ * `30s`, `"30 s"`, `64KiB`, `2w` read as before. Default `false` (#233).
48
+ */
49
+ readonly requireUnit?: boolean;
50
+ }
37
51
  /**
38
52
  * Zod schema markers for HOCON unit values. Each reads the forms the matching
39
53
  * Config getter reads and gives what the getter gives (a number in the
@@ -54,23 +68,26 @@ declare const hocon: {
54
68
  * significant digits than a double holds can read differently: the getter
55
69
  * reads its text, the marker its JS value (`1.0000000000000001` in `us`:
56
70
  * 1000.0000000000001 through the getter, 1000 here).
71
+ * `options.requireUnit` refuses a value that does not name its unit (#233).
57
72
  */
58
- duration(unit?: DurationUnit): ZodTransform<number, unknown>;
73
+ duration(unit?: DurationUnit, options?: UnitMarkerOptions): ZodTransform<number, unknown>;
59
74
  /**
60
75
  * A byte size, read as {@link Config.getBytes} reads it (default unit `B`),
61
76
  * exponent forms included, except that a number literal with more
62
77
  * significant digits than a double holds can read differently: the getter
63
78
  * reads its text, the marker its JS value (`1.99999999999999999`: 1 through
64
79
  * the getter, 2 here).
80
+ * `options.requireUnit` refuses a value that does not name its unit (#233).
65
81
  */
66
- bytes(unit?: ByteUnit): ZodTransform<number, unknown>;
82
+ bytes(unit?: ByteUnit, options?: UnitMarkerOptions): ZodTransform<number, unknown>;
67
83
  /**
68
84
  * A calendar period, read as {@link Config.getPeriod} reads it (a bare
69
85
  * integer is days), except that a number literal with a decimal point or in
70
86
  * exponent form (`7.0`, `1e2`) can read differently: the getter refuses it,
71
87
  * the marker reads the JS number.
88
+ * `options.requireUnit` refuses a value that does not name its unit (#233).
72
89
  */
73
- period(): ZodTransform<Period, unknown>;
90
+ period(options?: UnitMarkerOptions): ZodTransform<Period, unknown>;
74
91
  };
75
92
  /**
76
93
  * Parse a HOCON string and {@link validate} it.
@@ -89,4 +106,4 @@ declare function parseWithSchema<T>(input: string, schema: ZodType<T>, opts?: Pa
89
106
  */
90
107
  declare function parseFileWithSchema<T>(filePath: string, schema: ZodType<T>, opts?: ParseOptions): T;
91
108
 
92
- export { getValidated, hocon, parseFileWithSchema, parseWithSchema, validate };
109
+ export { type UnitMarkerOptions, getValidated, hocon, parseFileWithSchema, parseWithSchema, validate };
package/dist/zod.js CHANGED
@@ -1,14 +1,16 @@
1
1
  import {
2
2
  parse,
3
3
  parseFile
4
- } from "./chunk-JVABBNF5.js";
4
+ } from "./chunk-ITRXT66R.js";
5
5
  import {
6
6
  coerceBoolean,
7
7
  coerceNumber,
8
+ namesMagnitudeUnit,
9
+ namesPeriodUnit,
8
10
  readBytes,
9
11
  readDuration,
10
12
  readPeriod
11
- } from "./chunk-GOXMKYWS.js";
13
+ } from "./chunk-5PV3HO2V.js";
12
14
 
13
15
  // src/zod.ts
14
16
  import { z } from "zod";
@@ -27,8 +29,11 @@ function parseValue(value, schema) {
27
29
  let result;
28
30
  try {
29
31
  result = schema.safeParse(coerced);
30
- } catch {
31
- throw new z.ZodError(refused);
32
+ } catch (err) {
33
+ if (err instanceof z.core.$ZodAsyncError || err?.constructor?.name === "$ZodAsyncError") {
34
+ throw new z.ZodError(refused);
35
+ }
36
+ throw err;
32
37
  }
33
38
  if (result.success) throw new z.ZodError(refused);
34
39
  throw new z.ZodError([...refused, ...withoutPrototypeKeyIssues(result.error.issues)]);
@@ -60,7 +65,7 @@ function dropPrototypeKeys(value, path, issues) {
60
65
  }
61
66
  return kept;
62
67
  }
63
- function unitMarker(what, read) {
68
+ function unitMarker(what, read, namesUnit) {
64
69
  return z.transform((input, ctx) => {
65
70
  if (typeof input !== "string" && typeof input !== "number") {
66
71
  ctx.issues.push({ code: "custom", message: `expected ${what}, got ${describeInput(input)}`, input });
@@ -68,16 +73,18 @@ function unitMarker(what, read) {
68
73
  }
69
74
  const text = typeof input === "string" ? input : String(input);
70
75
  const reading = read(text);
76
+ if (reading.ok && namesUnit !== void 0 && (typeof input === "number" || !namesUnit(text))) {
77
+ pushProblem(ctx, what, "missing-unit", input);
78
+ return z.NEVER;
79
+ }
71
80
  if (reading.ok) return reading.value;
72
- ctx.issues.push({
73
- code: "custom",
74
- message: unitProblemMessage(what, reading.problem),
75
- input,
76
- params: { problem: reading.problem }
77
- });
81
+ pushProblem(ctx, what, reading.problem, input);
78
82
  return z.NEVER;
79
83
  });
80
84
  }
85
+ function pushProblem(ctx, what, problem, input) {
86
+ ctx.issues.push({ code: "custom", message: unitProblemMessage(what, problem), input, params: { problem } });
87
+ }
81
88
  function unitProblemMessage(what, problem) {
82
89
  switch (problem) {
83
90
  case "invalid":
@@ -86,6 +93,8 @@ function unitProblemMessage(what, problem) {
86
93
  return `${what} must be non-negative`;
87
94
  case "overflow":
88
95
  return `${what} overflows the representable range`;
96
+ case "missing-unit":
97
+ return `${what} must name its unit`;
89
98
  }
90
99
  }
91
100
  function describeInput(input) {
@@ -100,9 +109,10 @@ var hocon = {
100
109
  * significant digits than a double holds can read differently: the getter
101
110
  * reads its text, the marker its JS value (`1.0000000000000001` in `us`:
102
111
  * 1000.0000000000001 through the getter, 1000 here).
112
+ * `options.requireUnit` refuses a value that does not name its unit (#233).
103
113
  */
104
- duration(unit) {
105
- return unitMarker("duration", (text) => readDuration(text, unit));
114
+ duration(unit, options) {
115
+ return unitMarker("duration", (text) => readDuration(text, unit), requireUnit(options, namesMagnitudeUnit));
106
116
  },
107
117
  /**
108
118
  * A byte size, read as {@link Config.getBytes} reads it (default unit `B`),
@@ -110,20 +120,25 @@ var hocon = {
110
120
  * significant digits than a double holds can read differently: the getter
111
121
  * reads its text, the marker its JS value (`1.99999999999999999`: 1 through
112
122
  * the getter, 2 here).
123
+ * `options.requireUnit` refuses a value that does not name its unit (#233).
113
124
  */
114
- bytes(unit) {
115
- return unitMarker("byte size", (text) => readBytes(text, unit));
125
+ bytes(unit, options) {
126
+ return unitMarker("byte size", (text) => readBytes(text, unit), requireUnit(options, namesMagnitudeUnit));
116
127
  },
117
128
  /**
118
129
  * A calendar period, read as {@link Config.getPeriod} reads it (a bare
119
130
  * integer is days), except that a number literal with a decimal point or in
120
131
  * exponent form (`7.0`, `1e2`) can read differently: the getter refuses it,
121
132
  * the marker reads the JS number.
133
+ * `options.requireUnit` refuses a value that does not name its unit (#233).
122
134
  */
123
- period() {
124
- return unitMarker("period", readPeriod);
135
+ period(options) {
136
+ return unitMarker("period", readPeriod, requireUnit(options, namesPeriodUnit));
125
137
  }
126
138
  };
139
+ function requireUnit(options, namesUnit) {
140
+ return options?.requireUnit === true ? namesUnit : void 0;
141
+ }
127
142
  function getDefType(schema) {
128
143
  const zod = schema._zod;
129
144
  return zod?.def?.type;
@@ -170,6 +185,10 @@ function coerceValue(value, schema) {
170
185
  return coerced !== void 0 ? coerced : value;
171
186
  }
172
187
  return value;
188
+ case "enum": {
189
+ const values = schema._zod.values;
190
+ return coerceToLiteral(value, values);
191
+ }
173
192
  case "literal": {
174
193
  const values = getDef(schema)?.values;
175
194
  return values ? coerceToLiteral(value, new Set(values)) : value;
@@ -185,8 +204,23 @@ function coerceValue(value, schema) {
185
204
  result[key] = coerceValue(obj[key], shape[key]);
186
205
  }
187
206
  }
207
+ const catchall = getDef(schema)?.catchall;
208
+ if (catchall) {
209
+ for (const key of Object.keys(obj)) {
210
+ if (!Object.prototype.hasOwnProperty.call(shape, key)) result[key] = coerceValue(obj[key], catchall);
211
+ }
212
+ }
188
213
  return result;
189
214
  }
215
+ case "intersection": {
216
+ if (accepts(schema, value)) return value;
217
+ const def = getDef(schema);
218
+ const forLeft = coerceValue(value, def.left);
219
+ if (accepts(schema, forLeft)) return forLeft;
220
+ const forRight = coerceValue(value, def.right);
221
+ if (accepts(schema, forRight)) return forRight;
222
+ return coerceValue(forLeft, def.right);
223
+ }
190
224
  case "array": {
191
225
  if (!Array.isArray(value)) return value;
192
226
  const elementSchema = getArrayElement(schema);
@@ -226,6 +260,7 @@ function coerceValue(value, schema) {
226
260
  case "default":
227
261
  case "prefault":
228
262
  case "nonoptional":
263
+ case "success":
229
264
  case "catch":
230
265
  case "readonly": {
231
266
  const inner = getInnerSchema(schema);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@o3co/ts.hocon",
3
- "version": "1.14.1",
3
+ "version": "1.14.3",
4
4
  "description": "Full Lightbend HOCON spec-compliant parser and config library for TypeScript",
5
5
  "keywords": [
6
6
  "hocon",