@warlock.js/seal 4.9.0 → 4.9.2

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/CHANGELOG.md CHANGED
@@ -4,6 +4,15 @@ All notable changes to `@warlock.js/seal` are documented in this file.
4
4
 
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/). `@warlock.js/*` packages are released in lockstep — every package shares the same version number, so a version below may list only the changes that affected this package.
6
6
 
7
+ ## 4.9.2
8
+
9
+ ### Fixed
10
+
11
+ - `v.literal("")` could never pass. Every validator is required by default and `required` rejects anything the empty-value check calls empty — which includes `""` — so a schema demanding an exact empty string reported "is required" for a field that was present. A literal set containing an empty value now uses `present` (the key must exist) instead of `required`, leaving the literal set to judge the value. Only the empty string was affected; `v.literal(0)` and `v.literal(false)` always worked
12
+ - `v.literal("").optional()` silently disabled the literal check rather than fixing it, accepting `""`, `null` **and** a missing key alike. The literal rule now runs on empty values (`requiresValue: false`) while treating absence as the required/present rule's question, so `.optional()` means optional again and a present value must still match
13
+ - a **failed** validation no longer returns the input it rejected. `object` returned the raw input — including the unknown keys it had just complained about — while `discriminatedUnion` returned `undefined`; the same call shape had two contracts. Validating an outbound DTO to keep internal fields out of a response, then reading `data` without branching on `isValid`, shipped every field the schema existed to exclude. `data` is now `undefined` whenever `isValid` is `false`
14
+ - `v.number().toFixed(n)` could never produce a valid result — the mutator returned `Number(value).toFixed(n)`, a *string*, which the validator's own `number` type rule then rejected. It now yields a number (`3.14159` → `3.14`), so the method works where it lives. No working code can have depended on the old output, since every such validation failed; for a fixed-point *string*, format at the presentation edge rather than asking a number schema to emit one
15
+
7
16
  ## 4.2.11
8
17
 
9
18
  ### Changed
package/cjs/index.cjs CHANGED
@@ -170,7 +170,12 @@ const validate = async (schema, data, { context: extendedContext, ...configurati
170
170
  },
171
171
  configurations
172
172
  };
173
- return await schema.validate(data, context);
173
+ const result = await schema.validate(data, context);
174
+ if (!result.isValid) return {
175
+ ...result,
176
+ data: void 0
177
+ };
178
+ return result;
174
179
  };
175
180
 
176
181
  //#endregion
@@ -1267,10 +1272,18 @@ const roundMutator = async (value, context) => {
1267
1272
  if (decimals === 0) return Math.round(Number(value));
1268
1273
  return (0, _mongez_reinforcements.round)(Number(value), decimals);
1269
1274
  };
1270
- /** To fixed mutator */
1275
+ /**
1276
+ * To fixed mutator — rounds to a fixed number of decimal places, as a number.
1277
+ *
1278
+ * `Number.prototype.toFixed` returns a *string*, which the number validator's
1279
+ * own type rule then rejected: `v.number().toFixed(2)` could never produce a
1280
+ * valid result. Coercing back to a number keeps the method usable where it
1281
+ * lives. For the fixed-point string form, format at the edge instead of asking
1282
+ * a number schema to output a string.
1283
+ */
1271
1284
  const toFixedMutator = async (value, context) => {
1272
1285
  const decimals = context?.options?.decimals ?? 2;
1273
- return Number(value).toFixed(decimals);
1286
+ return Number(Number(value).toFixed(decimals));
1274
1287
  };
1275
1288
 
1276
1289
  //#endregion
@@ -4205,8 +4218,10 @@ const instanceofRule = {
4205
4218
  */
4206
4219
  const literalRule = {
4207
4220
  name: "literal",
4221
+ requiresValue: false,
4208
4222
  defaultErrorMessage: "The :input must be one of the following values: :values",
4209
4223
  async validate(value, context) {
4224
+ if (value === void 0) return VALID_RULE;
4210
4225
  if (this.context.options.values.includes(value)) return VALID_RULE;
4211
4226
  this.context.translationParams.values = this.context.options.values.map((v) => resolveTranslation({
4212
4227
  key: String(v),
@@ -6509,6 +6524,7 @@ var LiteralValidator = class extends BaseValidator {
6509
6524
  super();
6510
6525
  this.values = values;
6511
6526
  this.addMutableRule(literalRule, errorMessage, { values });
6527
+ if (values.some((value) => isEmptyValue(value))) this.requiredRule = this.createRule(presentRule);
6512
6528
  }
6513
6529
  /**
6514
6530
  * Check if value is one of the configured literals
@@ -6901,7 +6917,14 @@ var NumberValidator = class extends PrimitiveValidator {
6901
6917
  return this.addMutator(roundMutator, { decimals });
6902
6918
  }
6903
6919
  /**
6904
- * Format number using fixed-point notation
6920
+ * Round to a fixed number of decimal places, keeping the value a **number**.
6921
+ *
6922
+ * `v.number().toFixed(2)` on `3.14159` yields `3.14`, not `"3.14"` — a number
6923
+ * schema has to output a number, or its own type rule rejects the result.
6924
+ * Format to a fixed-point *string* at the presentation edge instead.
6925
+ *
6926
+ * @example
6927
+ * v.number().toFixed(2) // 3.14159 → 3.14
6905
6928
  */
6906
6929
  toFixed(decimals = 2) {
6907
6930
  return this.addMutator(toFixedMutator, { decimals });