@orieljs/validation 0.1.0-alpha.4 → 0.1.0-alpha.6
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/NOTICE +3 -0
- package/dist/index.js +215 -9
- package/dist/index.js.map +1 -1
- package/package.json +4 -4
package/NOTICE
CHANGED
|
@@ -7,3 +7,6 @@ This product includes software developed by the Oriel project
|
|
|
7
7
|
Oriel is licensed under the Apache License, Version 2.0 (see LICENSE).
|
|
8
8
|
The Oriel name and logo are not covered by that license; see TRADEMARKS.md
|
|
9
9
|
(https://github.com/orieljs/framework/blob/main/TRADEMARKS.md).
|
|
10
|
+
|
|
11
|
+
@orieljs/support (and @orieljs/framework, which bundles it) includes transliteration data from
|
|
12
|
+
voku/portable-ascii (https://github.com/voku/portable-ascii), Copyright (C) 2019 Lars Moelleken, MIT License.
|
package/dist/index.js
CHANGED
|
@@ -134,6 +134,9 @@ var DEFAULT_MESSAGES = {
|
|
|
134
134
|
file: "The :attribute field must be a file.",
|
|
135
135
|
image: "The :attribute field must be an image.",
|
|
136
136
|
mimes: "The :attribute field must be a file of type: :values.",
|
|
137
|
+
mimetypes: "The :attribute field must be a file of type: :values.",
|
|
138
|
+
extensions: "The :attribute field must have one of the following extensions: :values.",
|
|
139
|
+
dimensions: "The :attribute field has invalid image dimensions.",
|
|
137
140
|
"max.string": "The :attribute field must not be greater than :max characters.",
|
|
138
141
|
"max.numeric": "The :attribute field must not be greater than :max.",
|
|
139
142
|
"max.array": "The :attribute field must not have more than :max items.",
|
|
@@ -235,6 +238,95 @@ var databaseRules = {
|
|
|
235
238
|
}
|
|
236
239
|
};
|
|
237
240
|
|
|
241
|
+
// rules/file.ts
|
|
242
|
+
import { FileType } from "@orieljs/support";
|
|
243
|
+
|
|
244
|
+
// files/dimensions.ts
|
|
245
|
+
var FRAME_MARKERS = /* @__PURE__ */ new Set([192, 193, 194, 195, 197, 198, 199, 201, 202, 203, 205, 206, 207]);
|
|
246
|
+
var MAX_JPEG_STEPS = 1024;
|
|
247
|
+
var MAX_BOXES = 1024;
|
|
248
|
+
var fourcc = (view, offset) => String.fromCharCode(view.getUint8(offset), view.getUint8(offset + 1), view.getUint8(offset + 2), view.getUint8(offset + 3));
|
|
249
|
+
var u24le = (view, offset) => view.getUint8(offset) | view.getUint8(offset + 1) << 8 | view.getUint8(offset + 2) << 16;
|
|
250
|
+
var READERS = {
|
|
251
|
+
"image/png": (view) => fourcc(view, 12) === "IHDR" ? { width: view.getUint32(16), height: view.getUint32(20) } : void 0,
|
|
252
|
+
"image/gif": (view) => ({ width: view.getUint16(6, true), height: view.getUint16(8, true) }),
|
|
253
|
+
"image/bmp": (view) => view.getUint32(14, true) === 12 ? { width: view.getUint16(18, true), height: view.getUint16(20, true) } : { width: Math.abs(view.getInt32(18, true)), height: Math.abs(view.getInt32(22, true)) },
|
|
254
|
+
"image/jpeg": jpeg,
|
|
255
|
+
"image/webp": webp,
|
|
256
|
+
"image/avif": avif
|
|
257
|
+
};
|
|
258
|
+
function imageDimensions(bytes, mime) {
|
|
259
|
+
const reader = READERS[mime];
|
|
260
|
+
if (!reader) return void 0;
|
|
261
|
+
try {
|
|
262
|
+
const size = reader(new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength));
|
|
263
|
+
return size && size.width > 0 && size.height > 0 ? size : void 0;
|
|
264
|
+
} catch (error) {
|
|
265
|
+
if (error instanceof RangeError) return void 0;
|
|
266
|
+
throw error;
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
function jpeg(view) {
|
|
270
|
+
let offset = 2;
|
|
271
|
+
for (let step = 0; step < MAX_JPEG_STEPS && offset + 4 <= view.byteLength; step++) {
|
|
272
|
+
if (view.getUint8(offset) !== 255) return void 0;
|
|
273
|
+
const marker = view.getUint8(offset + 1);
|
|
274
|
+
if (marker === 255) offset += 1;
|
|
275
|
+
else if (marker === 216 || marker === 1 || marker >= 208 && marker <= 215) offset += 2;
|
|
276
|
+
else if (marker === 217 || marker === 218) return void 0;
|
|
277
|
+
else if (FRAME_MARKERS.has(marker)) return { height: view.getUint16(offset + 5), width: view.getUint16(offset + 7) };
|
|
278
|
+
else offset += 2 + view.getUint16(offset + 2);
|
|
279
|
+
}
|
|
280
|
+
return void 0;
|
|
281
|
+
}
|
|
282
|
+
function webp(view) {
|
|
283
|
+
const chunk = fourcc(view, 12);
|
|
284
|
+
if (chunk === "VP8 ") {
|
|
285
|
+
if (view.getUint8(23) !== 157 || view.getUint8(24) !== 1 || view.getUint8(25) !== 42) return void 0;
|
|
286
|
+
return { width: view.getUint16(26, true) & 16383, height: view.getUint16(28, true) & 16383 };
|
|
287
|
+
}
|
|
288
|
+
if (chunk === "VP8L") {
|
|
289
|
+
if (view.getUint8(20) !== 47) return void 0;
|
|
290
|
+
const bits = view.getUint32(21, true);
|
|
291
|
+
return { width: (bits & 16383) + 1, height: (bits >>> 14 & 16383) + 1 };
|
|
292
|
+
}
|
|
293
|
+
if (chunk === "VP8X") return { width: u24le(view, 24) + 1, height: u24le(view, 27) + 1 };
|
|
294
|
+
return void 0;
|
|
295
|
+
}
|
|
296
|
+
function* boxes(view, start, end) {
|
|
297
|
+
let offset = start;
|
|
298
|
+
for (let count = 0; count < MAX_BOXES && offset + 8 <= end; count++) {
|
|
299
|
+
let size = view.getUint32(offset);
|
|
300
|
+
let header = 8;
|
|
301
|
+
if (size === 1) {
|
|
302
|
+
size = Number(view.getBigUint64(offset + 8));
|
|
303
|
+
header = 16;
|
|
304
|
+
} else if (size === 0) {
|
|
305
|
+
size = end - offset;
|
|
306
|
+
}
|
|
307
|
+
if (size < header || offset + size > end) return;
|
|
308
|
+
yield { type: fourcc(view, offset + 4), start: offset + header, end: offset + size };
|
|
309
|
+
offset += size;
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
var findBox = (view, start, end, type) => {
|
|
313
|
+
for (const box of boxes(view, start, end)) if (box.type === type) return box;
|
|
314
|
+
return void 0;
|
|
315
|
+
};
|
|
316
|
+
function avif(view) {
|
|
317
|
+
const meta = findBox(view, 0, view.byteLength, "meta");
|
|
318
|
+
const iprp = meta && findBox(view, meta.start + 4, meta.end, "iprp");
|
|
319
|
+
const ipco = iprp && findBox(view, iprp.start, iprp.end, "ipco");
|
|
320
|
+
if (!ipco) return void 0;
|
|
321
|
+
let largest;
|
|
322
|
+
for (const box of boxes(view, ipco.start, ipco.end)) {
|
|
323
|
+
if (box.type !== "ispe") continue;
|
|
324
|
+
const size = { width: view.getUint32(box.start + 4), height: view.getUint32(box.start + 8) };
|
|
325
|
+
if (!largest || size.width * size.height > largest.width * largest.height) largest = size;
|
|
326
|
+
}
|
|
327
|
+
return largest;
|
|
328
|
+
}
|
|
329
|
+
|
|
238
330
|
// parse.ts
|
|
239
331
|
import { Arr } from "@orieljs/support";
|
|
240
332
|
function splitParameters(name, raw) {
|
|
@@ -286,25 +378,139 @@ function expandWildcardKeys(pattern, data) {
|
|
|
286
378
|
}
|
|
287
379
|
|
|
288
380
|
// rules/file.ts
|
|
289
|
-
var
|
|
381
|
+
var { BINARY_AND_MARKUP_TYPES, detectFileType, EMPTY, RASTER_IMAGES, SVG, TEXT } = FileType;
|
|
382
|
+
var inspections = /* @__PURE__ */ new WeakMap();
|
|
383
|
+
function inspect(file) {
|
|
384
|
+
let inspection = inspections.get(file);
|
|
385
|
+
if (!inspection) {
|
|
386
|
+
inspection = file.arrayBuffer().then((buffer) => {
|
|
387
|
+
const bytes = new Uint8Array(buffer);
|
|
388
|
+
const type = detectFileType(bytes);
|
|
389
|
+
return { type, dimensions: RASTER_IMAGES.has(type.mime) ? imageDimensions(bytes, type.mime) : void 0 };
|
|
390
|
+
});
|
|
391
|
+
inspections.set(file, inspection);
|
|
392
|
+
}
|
|
393
|
+
return inspection;
|
|
394
|
+
}
|
|
395
|
+
function clientExtension(file) {
|
|
396
|
+
const name = file.clientName.slice(Math.max(file.clientName.lastIndexOf("/"), file.clientName.lastIndexOf("\\")) + 1);
|
|
397
|
+
const dot = name.lastIndexOf(".");
|
|
398
|
+
return dot === -1 ? "" : name.slice(dot + 1).trim().toLowerCase();
|
|
399
|
+
}
|
|
400
|
+
var PHP_EXTENSIONS = /* @__PURE__ */ new Set(["php", "php3", "php4", "php5", "php7", "php8", "phtml", "phar"]);
|
|
401
|
+
var blocksPhp = (file, allowed) => !allowed.includes("php") && PHP_EXTENSIONS.has(clientExtension(file));
|
|
402
|
+
var TEXT_FORMATS = /* @__PURE__ */ new Set(["txt", "text", "csv", "tsv", "json", "md"]);
|
|
403
|
+
var RECOGNISED_EXTENSIONS = new Set(BINARY_AND_MARKUP_TYPES.flatMap(({ extensions }) => extensions));
|
|
404
|
+
var lower = (values) => values.map((value) => value.trim().toLowerCase());
|
|
405
|
+
function meetsMimes(type, extension, allowed) {
|
|
406
|
+
if (type === EMPTY) return false;
|
|
407
|
+
if (type === TEXT && allowed.has("txt")) return true;
|
|
408
|
+
if (type !== TEXT && type.extensions.length > 0) return type.extensions.some((name) => allowed.has(name));
|
|
409
|
+
if (!allowed.has(extension) || RECOGNISED_EXTENSIONS.has(extension)) return false;
|
|
410
|
+
return type === TEXT || !TEXT_FORMATS.has(extension);
|
|
411
|
+
}
|
|
412
|
+
function allowedExtensions(ctx) {
|
|
413
|
+
const allowed = new Set(lower(ctx.parameters));
|
|
414
|
+
if (allowed.has("jpg") || allowed.has("jpeg")) allowed.add("jpg").add("jpeg");
|
|
415
|
+
return allowed;
|
|
416
|
+
}
|
|
417
|
+
var listed = (ctx) => ({ values: ctx.parameters.join(", ") });
|
|
418
|
+
var DIMENSION_KEYS = ["width", "height", "min_width", "min_height", "max_width", "max_height", "ratio"];
|
|
419
|
+
function namedParameter(parameter) {
|
|
420
|
+
const at = parameter.indexOf("=");
|
|
421
|
+
return at === -1 ? [parameter, ""] : [parameter.slice(0, at), parameter.slice(at + 1)];
|
|
422
|
+
}
|
|
423
|
+
function parseRatio(value) {
|
|
424
|
+
const match = /^(\d+(?:\.\d+)?|\.\d+)(?:\/(\d+))?$/.exec(value.trim());
|
|
425
|
+
if (!match) return void 0;
|
|
426
|
+
const ratio = Number(match[1]) / Number(match[2] ?? 1);
|
|
427
|
+
return Number.isFinite(ratio) && ratio > 0 ? ratio : void 0;
|
|
428
|
+
}
|
|
429
|
+
function dimensionConstraints(parameters) {
|
|
430
|
+
if (parameters.length === 0) throw new InvalidRuleParameterError("dimensions", "", `expected one or more of ${DIMENSION_KEYS.join(", ")}`);
|
|
431
|
+
const constraints = {};
|
|
432
|
+
for (const parameter of parameters) {
|
|
433
|
+
const [key, value] = namedParameter(parameter);
|
|
434
|
+
if (!DIMENSION_KEYS.includes(key)) {
|
|
435
|
+
throw new InvalidRuleParameterError("dimensions", parameter, `expected one of ${DIMENSION_KEYS.join(", ")}`);
|
|
436
|
+
}
|
|
437
|
+
const number = key === "ratio" ? parseRatio(value) : /^\d+$/.test(value) ? Number(value) : void 0;
|
|
438
|
+
if (number === void 0) {
|
|
439
|
+
throw new InvalidRuleParameterError("dimensions", parameter, key === "ratio" ? "expected a ratio such as 3/2 or 1.5" : "expected a whole number of pixels");
|
|
440
|
+
}
|
|
441
|
+
constraints[key] = number;
|
|
442
|
+
}
|
|
443
|
+
return constraints;
|
|
444
|
+
}
|
|
445
|
+
function meetsDimensions(constraints, { width, height }) {
|
|
446
|
+
const { width: exactWidth, height: exactHeight, min_width, max_width, min_height, max_height, ratio } = constraints;
|
|
447
|
+
if (exactWidth !== void 0 && width !== exactWidth) return false;
|
|
448
|
+
if (exactHeight !== void 0 && height !== exactHeight) return false;
|
|
449
|
+
if (min_width !== void 0 && width < min_width) return false;
|
|
450
|
+
if (max_width !== void 0 && width > max_width) return false;
|
|
451
|
+
if (min_height !== void 0 && height < min_height) return false;
|
|
452
|
+
if (max_height !== void 0 && height > max_height) return false;
|
|
453
|
+
return ratio === void 0 || Math.abs(ratio - width / height) <= 1 / (Math.max((width + height) / 2, height) + 1);
|
|
454
|
+
}
|
|
290
455
|
var fileRules = {
|
|
291
456
|
file: { validate: (ctx) => isUploadedFileLike(ctx.value), messageKey: () => "file" },
|
|
457
|
+
/** A JPEG, PNG, GIF, WebP, AVIF or BMP by its bytes; SVG only as `image:allow_svg` (Laravel 12). */
|
|
292
458
|
image: {
|
|
293
|
-
validate: (ctx) => {
|
|
294
|
-
if (!isUploadedFileLike(ctx.value)) return false;
|
|
295
|
-
|
|
296
|
-
return
|
|
459
|
+
validate: async (ctx) => {
|
|
460
|
+
if (!isUploadedFileLike(ctx.value) || blocksPhp(ctx.value, [])) return false;
|
|
461
|
+
const { type } = await inspect(ctx.value);
|
|
462
|
+
return RASTER_IMAGES.has(type.mime) || type === SVG && ctx.parameters.includes("allow_svg");
|
|
297
463
|
},
|
|
298
464
|
messageKey: () => "image"
|
|
299
465
|
},
|
|
300
466
|
mimes: {
|
|
301
|
-
validate: (ctx) => {
|
|
467
|
+
validate: async (ctx) => {
|
|
302
468
|
if (!isUploadedFileLike(ctx.value)) return false;
|
|
303
|
-
const allowed = ctx
|
|
304
|
-
|
|
469
|
+
const allowed = allowedExtensions(ctx);
|
|
470
|
+
if (blocksPhp(ctx.value, [...allowed])) return false;
|
|
471
|
+
return meetsMimes((await inspect(ctx.value)).type, clientExtension(ctx.value), allowed);
|
|
305
472
|
},
|
|
306
473
|
messageKey: () => "mimes",
|
|
307
|
-
replacements:
|
|
474
|
+
replacements: listed
|
|
475
|
+
},
|
|
476
|
+
/**
|
|
477
|
+
* The detected MIME type is listed, or its `type/*` wildcard is. `image/*` includes SVG (`image/svg+xml`), as in
|
|
478
|
+
* Laravel: the rule for photos is `image`.
|
|
479
|
+
*/
|
|
480
|
+
mimetypes: {
|
|
481
|
+
validate: async (ctx) => {
|
|
482
|
+
if (!isUploadedFileLike(ctx.value)) return false;
|
|
483
|
+
const allowed = lower(ctx.parameters);
|
|
484
|
+
if (blocksPhp(ctx.value, allowed)) return false;
|
|
485
|
+
const { mime } = (await inspect(ctx.value)).type;
|
|
486
|
+
return allowed.includes(mime) || allowed.includes(`${mime.split("/")[0]}/*`);
|
|
487
|
+
},
|
|
488
|
+
messageKey: () => "mimetypes",
|
|
489
|
+
replacements: listed
|
|
490
|
+
},
|
|
491
|
+
/**
|
|
492
|
+
* The pixel size read from the image's header meets every constraint: width, height, min_width, max_width,
|
|
493
|
+
* min_height, max_height, ratio. SVG and images whose header can't be read fail.
|
|
494
|
+
*/
|
|
495
|
+
dimensions: {
|
|
496
|
+
validate: async (ctx) => {
|
|
497
|
+
const constraints = dimensionConstraints(ctx.parameters);
|
|
498
|
+
if (!isUploadedFileLike(ctx.value)) return false;
|
|
499
|
+
const { dimensions } = await inspect(ctx.value);
|
|
500
|
+
return dimensions !== void 0 && meetsDimensions(constraints, dimensions);
|
|
501
|
+
},
|
|
502
|
+
messageKey: () => "dimensions",
|
|
503
|
+
replacements: (ctx) => Object.fromEntries(ctx.parameters.map(namedParameter))
|
|
504
|
+
},
|
|
505
|
+
/** The client file name's extension is listed (Laravel 11). It checks the name only: pair it with mimes or image. */
|
|
506
|
+
extensions: {
|
|
507
|
+
validate: (ctx) => {
|
|
508
|
+
if (!isUploadedFileLike(ctx.value)) return false;
|
|
509
|
+
const allowed = lower(ctx.parameters);
|
|
510
|
+
return !blocksPhp(ctx.value, allowed) && allowed.includes(clientExtension(ctx.value));
|
|
511
|
+
},
|
|
512
|
+
messageKey: () => "extensions",
|
|
513
|
+
replacements: listed
|
|
308
514
|
}
|
|
309
515
|
};
|
|
310
516
|
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../errors.ts","../FormRequest.ts","../messages.ts","../MessageBag.ts","../rules/auth.ts","../rules/database.ts","../parse.ts","../rules/file.ts","../rules/format.ts","../rules/presence.ts","../rules/type.ts","../rules/size.ts","../registry.ts","../rules/password.ts","../Rule.ts","../Validator.ts","../ValidationFactory.ts","../facade.ts","../ValidationServiceProvider.ts"],"sourcesContent":["import type { OrielError, ValidationError } from '@orieljs/contracts'\n\nexport class ValidationErrorImpl extends Error implements ValidationError {\n readonly kind = 'Validation' as const\n readonly status = 422\n override readonly name = 'ValidationError'\n constructor(\n readonly errors: Record<string, string[]>,\n readonly errorBag = 'default',\n readonly redirectTo?: string,\n ) {\n super('The given data was invalid.')\n }\n}\n\n/**\n * Laravel's ValidationException, for failing a request by hand:\n * `throw ValidationException.withMessages({ email: __('auth.failed') })`. Rendered like any validation error: 422 JSON,\n * or a redirect back with the errors.\n */\nexport class ValidationException extends ValidationErrorImpl {\n /** Messages per field, each a string or a list. */\n static withMessages(messages: Record<string, string | readonly string[]>): ValidationException {\n const errors = Object.fromEntries(Object.entries(messages).map(([field, list]) => [field, typeof list === 'string' ? [list] : [...list]]))\n return new ValidationException(errors)\n }\n\n constructor(errors: Record<string, string[]>, errorBag = 'default', redirectTo?: string) {\n super(errors, errorBag, redirectTo)\n this.message = summarize(errors)\n }\n}\n\n/** \"The first message. (and 2 more errors)\" (Laravel's ValidationException::summarize()). */\nfunction summarize(errors: Record<string, string[]>): string {\n const messages = Object.values(errors).flat()\n if (messages.length === 0) return 'The given data was invalid.'\n const more = messages.length - 1\n return more === 0 ? messages[0]! : `${messages[0]!} (and ${more} more ${more === 1 ? 'error' : 'errors'})`\n}\n\nexport class AuthorizationErrorImpl extends Error implements OrielError {\n readonly kind = 'Authorization' as const\n readonly status = 403\n override readonly name = 'AuthorizationError'\n constructor(message = 'This action is unauthorized.') {\n super(message)\n }\n}\n\nexport class UnknownValidationRuleError extends Error implements OrielError {\n readonly kind = 'Server' as const\n readonly status = 500\n override readonly name = 'UnknownValidationRuleError'\n constructor(name: string) {\n super(`Validation rule \"${name}\" is not registered. Register it with ValidationFactory.extend() first.`)\n }\n}\n\n/** A rule was written with a parameter it can't use (a bad regex, an unparseable date). A developer error, not a user one. */\nexport class InvalidRuleParameterError extends Error implements OrielError {\n readonly kind = 'Server' as const\n readonly status = 500\n override readonly name = 'InvalidRuleParameterError'\n constructor(rule: string, parameter: string, reason: string) {\n super(`Validation rule \"${rule}\" has an invalid parameter \"${parameter}\": ${reason}`)\n }\n}\n","import type { Rules } from '@orieljs/contracts'\nimport { HttpRequest, ValidationFactory } from '@orieljs/contracts'\nimport { inject } from '@orieljs/container'\nimport { AuthorizationErrorImpl } from './errors'\n\n/**\n * Mirrors Illuminate\\Foundation\\Http\\FormRequest, minus dependency injection by type (Oriel resolves the current\n * request and the ValidationFactory through inject(), never through constructor parameters — see spec §3 rule 5).\n * A subclass only has to implement rules(); authorize()/messages()/attributes() default to Laravel's own defaults.\n */\nexport abstract class FormRequest {\n abstract rules(): Rules\n\n authorize(): boolean | Promise<boolean> {\n return true\n }\n\n messages(): Record<string, string> {\n return {}\n }\n\n attributes(): Record<string, string> {\n return {}\n }\n\n /**\n * `const data = await StorePostRequest.validate()` (spec §4.3). Resolves the current request and the\n * ValidationFactory from the active container, runs authorize() first (throwing AuthorizationErrorImpl if it\n * returns false), then validates request.all() against rules()/messages()/attributes() and returns the typed\n * validated data (or throws the 422 ValidationError — see ValidatorImpl.validated()).\n */\n static async validate<T = Record<string, unknown>>(this: new () => FormRequest): Promise<T> {\n const instance = new this()\n if (!(await instance.authorize())) throw new AuthorizationErrorImpl()\n\n const request = inject(HttpRequest)\n const factory = inject(ValidationFactory)\n const validator = factory.make(request.all(), instance.rules(), instance.messages(), instance.attributes())\n return validator.validated<T>()\n }\n}\n","import { Str } from '@orieljs/support'\n\n/** Humanizes a (possibly dotted) attribute key, e.g. \"items.0.product_name\" -> \"items.0.product name\". */\nexport function defaultAttributeName(key: string): string {\n return key\n .split('.')\n .map((segment) => Str.snake(segment).replace(/_/g, ' '))\n .join('.')\n}\n\nexport function applyReplacements(template: string, replacements: Record<string, string>): string {\n return Object.entries(replacements).reduce((message, [key, value]) => message.replaceAll(`:${key}`, value), template)\n}\n\n/** Laravel's English lang/en/validation.php, reproduced as closely as possible (see plan Notes/assumptions). */\nexport const DEFAULT_MESSAGES: Record<string, string> = {\n required: 'The :attribute field is required.',\n required_if: 'The :attribute field is required when :other is :value.',\n required_unless: 'The :attribute field is required unless :other is in :values.',\n required_with: 'The :attribute field is required when :values is present.',\n required_with_all: 'The :attribute field is required when :values are present.',\n required_without: 'The :attribute field is required when :values is not present.',\n required_without_all: 'The :attribute field is required when none of :values are present.',\n string: 'The :attribute field must be a string.',\n integer: 'The :attribute field must be an integer.',\n numeric: 'The :attribute field must be a number.',\n boolean: 'The :attribute field must be true or false.',\n array: 'The :attribute field must be an array.',\n email: 'The :attribute field must be a valid email address.',\n url: 'The :attribute field must be a valid URL.',\n uuid: 'The :attribute field must be a valid UUID.',\n alpha: 'The :attribute field must only contain letters.',\n alpha_num: 'The :attribute field must only contain letters and numbers.',\n alpha_dash: 'The :attribute field must only contain letters, numbers, dashes and underscores.',\n regex: 'The :attribute field format is invalid.',\n lowercase: 'The :attribute field must be lowercase.',\n uppercase: 'The :attribute field must be uppercase.',\n current_password: 'The password is incorrect.',\n 'password.letters': 'The :attribute field must contain at least one letter.',\n 'password.mixed': 'The :attribute field must contain at least one uppercase and one lowercase letter.',\n 'password.numbers': 'The :attribute field must contain at least one number.',\n 'password.symbols': 'The :attribute field must contain at least one symbol.',\n confirmed: 'The :attribute field confirmation does not match.',\n same: 'The :attribute field must match :other.',\n different: 'The :attribute field must be different from :other.',\n accepted: 'The :attribute field must be accepted.',\n digits: 'The :attribute field must be :digits digits.',\n date: 'The :attribute field must be a valid date.',\n before: 'The :attribute field must be a date before :date.',\n after: 'The :attribute field must be a date after :date.',\n in: 'The selected :attribute is invalid.',\n not_in: 'The selected :attribute is invalid.',\n unique: 'The :attribute has already been taken.',\n exists: 'The selected :attribute is invalid.',\n file: 'The :attribute field must be a file.',\n image: 'The :attribute field must be an image.',\n mimes: 'The :attribute field must be a file of type: :values.',\n 'max.string': 'The :attribute field must not be greater than :max characters.',\n 'max.numeric': 'The :attribute field must not be greater than :max.',\n 'max.array': 'The :attribute field must not have more than :max items.',\n 'max.file': 'The :attribute field must not be greater than :max kilobytes.',\n 'min.string': 'The :attribute field must be at least :min characters.',\n 'min.numeric': 'The :attribute field must be at least :min.',\n 'min.array': 'The :attribute field must have at least :min items.',\n 'min.file': 'The :attribute field must be at least :min kilobytes.',\n 'between.string': 'The :attribute field must be between :min and :max characters.',\n 'between.numeric': 'The :attribute field must be between :min and :max.',\n 'between.array': 'The :attribute field must have between :min and :max items.',\n 'between.file': 'The :attribute field must be between :min and :max kilobytes.',\n 'size.string': 'The :attribute field must be :size characters.',\n 'size.numeric': 'The :attribute field must be :size.',\n 'size.array': 'The :attribute field must contain :size items.',\n 'size.file': 'The :attribute field must be :size kilobytes.',\n}\n","import type { MessageBag } from '@orieljs/contracts'\n\nexport class MessageBagImpl implements MessageBag {\n private readonly items: Record<string, string[]> = {}\n\n /** Not part of the MessageBag contract — used internally by ValidatorImpl and by after() hooks. */\n add(key: string, message: string): void {\n ;(this.items[key] ??= []).push(message)\n }\n\n has(key: string): boolean {\n return (this.items[key]?.length ?? 0) > 0\n }\n\n first(key?: string): string | undefined {\n if (key !== undefined) return this.items[key]?.[0]\n for (const messages of Object.values(this.items)) {\n if (messages[0] !== undefined) return messages[0]\n }\n return undefined\n }\n\n get(key: string): string[] {\n return this.items[key] ?? []\n }\n\n all(): string[] {\n return Object.values(this.items).flat()\n }\n\n isEmpty(): boolean {\n return Object.keys(this.items).length === 0\n }\n\n count(): number {\n return this.all().length\n }\n\n toObject(): Record<string, string[]> {\n return structuredClone(this.items)\n }\n}\n","import { AuthFactory, Hasher } from '@orieljs/contracts'\nimport { inject } from '@orieljs/container'\nimport type { BuiltinRule } from '../parse'\n\n/** `current_password` / `current_password:<guard>`: the value is the signed-in user's password (Laravel). */\nexport const authRules: Record<string, BuiltinRule> = {\n current_password: {\n validate: async (ctx) => {\n const guard = inject(AuthFactory).guard(ctx.parameters[0])\n if (await guard.guest()) return false\n const user = await guard.user()\n return user !== undefined && typeof ctx.value === 'string' && inject(Hasher).check(ctx.value, user.getAuthPassword())\n },\n messageKey: () => 'current_password',\n },\n}\n","import { DatabaseManager } from '@orieljs/contracts'\nimport { inject } from '@orieljs/container'\nimport type { BuiltinRule } from '../parse'\n\n/**\n * The column to query when a unique/exists rule doesn't name one: the attribute itself, except for a\n * wildcard-expanded field like \"items.0.email\", which checks the last non-numeric segment (\"email\") rather than a\n * column literally named after the path (Laravel's guessColumnForQuery).\n */\nexport function guessColumn(attribute: string, expandedFromWildcard = false): string {\n if (!expandedFromWildcard) return attribute\n return attribute.split('.').filter((segment) => !/^\\d+$/.test(segment)).at(-1) ?? attribute\n}\n\n/** Laravel's idiom `unique:users,email,NULL,id` (and an empty or null ignore) means \"exclude nothing\". */\nfunction isNoExcept(except: unknown): boolean {\n return except === undefined || except === null || except === '' || except === 'NULL'\n}\n\n/**\n * Shared query shape behind both `unique`/`exists` string rules and `Rule.unique()`/`Rule.exists()` (Review Focus\n * #2): resolve DatabaseManager, filter table/column on value, optionally exclude a record by idColumn/except, and\n * report whether any row matches. Kept in one place so a future fix to this path can't miss one of the two callers.\n */\nexport async function matchingRecordExists(\n table: string,\n column: string,\n value: unknown,\n except?: unknown,\n idColumn = 'id',\n): Promise<boolean> {\n const db = inject(DatabaseManager)\n let query = db.connection().table(table).where(column, value)\n if (!isNoExcept(except)) query = query.where(idColumn, '!=', except)\n return query.exists()\n}\n\nexport const databaseRules: Record<string, BuiltinRule> = {\n unique: {\n validate: async (ctx) => {\n const [table, column, except, idColumn] = ctx.parameters\n return !(await matchingRecordExists(table!, column || guessColumn(ctx.attribute, ctx.expandedFromWildcard), ctx.value, except, idColumn || 'id'))\n },\n messageKey: () => 'unique',\n },\n exists: {\n validate: async (ctx) => {\n const [table, column] = ctx.parameters\n return matchingRecordExists(table!, column || guessColumn(ctx.attribute, ctx.expandedFromWildcard), ctx.value)\n },\n messageKey: () => 'exists',\n },\n}\n","import type { ValidationRule } from '@orieljs/contracts'\nimport { Arr } from '@orieljs/support'\n\n/** Everything a single rule needs to validate one concrete field. */\nexport interface RuleContext {\n /** The concrete, wildcard-expanded field path, e.g. \"items.1.name\". */\n attribute: string\n /** True when `attribute` came from expanding a wildcard pattern such as \"items.*.email\". */\n expandedFromWildcard?: boolean\n value: unknown\n parameters: string[]\n data: Record<string, unknown>\n /** Every named rule attached to this field (for size-type resolution: numeric/array/file/string). */\n ruleNames: string[]\n}\n\nexport interface BuiltinRule {\n validate(ctx: RuleContext): boolean | Promise<boolean>\n /** Which DEFAULT_MESSAGES key to use, e.g. `max.${sizeType}`. Most rules return a constant name. */\n messageKey(ctx: RuleContext): string\n /** Extra :placeholder substitutions beyond :attribute (e.g. :max, :other, :values). */\n replacements?(ctx: RuleContext): Record<string, string>\n /** Used when messageKey() isn't in DEFAULT_MESSAGES (e.g. an extend()ed rule with a custom message). */\n defaultMessage?: string\n /** An extend()ed rule's own message: it wins over the default lines, as Laravel's fallback messages do. */\n message?: string\n /** Runs even when the value is missing, blank, or null under nullable (the required* family, and accepted); a failure stops the field. */\n implicit?: boolean\n}\n\nexport type ParsedRule =\n | { kind: 'named'; name: string; parameters: string[] }\n | { kind: 'object'; rule: ValidationRule }\n\nfunction splitParameters(name: string, raw: string): string[] {\n // regex/not_regex parameters are never comma-split, so a pattern containing a comma survives intact.\n return name === 'regex' || name === 'not_regex' ? [raw] : raw.split(',')\n}\n\nfunction splitOnce(value: string, separator: string): [string, string | undefined] {\n const index = value.indexOf(separator)\n return index === -1 ? [value, undefined] : [value.slice(0, index), value.slice(index + 1)]\n}\n\nexport function parseRuleSpec(spec: string | ReadonlyArray<string | ValidationRule>): ParsedRule[] {\n const items = typeof spec === 'string' ? spec.split('|') : spec\n return items\n .filter((item) => item !== '')\n .map((item): ParsedRule => {\n if (typeof item !== 'string') return { kind: 'object', rule: item }\n const [name, raw] = splitOnce(item, ':')\n return { kind: 'named', name, parameters: raw === undefined ? [] : splitParameters(name, raw) }\n })\n}\n\n/** Laravel's definition of \"empty\" for the required family: null, undefined, '' and []. false and 0 are NOT empty. */\nexport function isEmptyValue(value: unknown): boolean {\n if (value === null || value === undefined) return true\n if (typeof value === 'string') return value === ''\n if (Array.isArray(value)) return value.length === 0\n return false\n}\n\n/** Duck-types Contracts/Http's UploadedFile without importing @orieljs/http. */\nexport function isUploadedFileLike(value: unknown): value is {\n clientName: string\n mimeType: string\n size: number\n extension(): string\n arrayBuffer(): Promise<ArrayBuffer>\n} {\n return (\n typeof value === 'object' &&\n value !== null &&\n typeof (value as Record<string, unknown>).clientName === 'string' &&\n typeof (value as Record<string, unknown>).arrayBuffer === 'function'\n )\n}\n\n/**\n * Keys that must never be followed or written when walking user input: assigning through them reaches\n * Object.prototype (or a constructor) instead of a plain data slot. Mirrors the guard in Arr.set.\n */\nexport const UNSAFE_KEYS: ReadonlySet<string> = new Set(['__proto__', 'prototype', 'constructor'])\n\n/**\n * Expands a `*`-wildcard rule pattern (e.g. \"items.*.name\") into every concrete path present in `data`\n * (e.g. [\"items.0.name\", \"items.1.name\"]). A pattern with no `*` is returned unchanged. A `*` segment whose\n * container is missing, not an array and not a plain object expands to nothing for that branch (Review Focus #4:\n * every reported error is keyed by a concrete path, never the literal pattern). Object keys in UNSAFE_KEYS are\n * treated as absent, so a JSON body like {\"items\":{\"__proto__\":{...}}} never yields a path through the prototype.\n */\nexport function expandWildcardKeys(pattern: string, data: Record<string, unknown>): string[] {\n const segments = pattern.split('.')\n let paths = ['']\n for (const segment of segments) {\n const next: string[] = []\n for (const base of paths) {\n const prefix = base === '' ? '' : `${base}.`\n if (segment !== '*') {\n next.push(`${prefix}${segment}`)\n continue\n }\n const container = Arr.get<unknown>(data, base === '' ? undefined : base)\n if (Array.isArray(container)) {\n container.forEach((_, index) => next.push(`${prefix}${index}`))\n } else if (container !== null && typeof container === 'object') {\n Object.keys(container)\n .filter((key) => !UNSAFE_KEYS.has(key))\n .forEach((key) => next.push(`${prefix}${key}`))\n }\n }\n paths = next\n }\n return paths\n}\n","import type { BuiltinRule } from '../parse'\nimport { isUploadedFileLike } from '../parse'\n\nconst IMAGE_EXTENSIONS = new Set(['jpg', 'jpeg', 'png', 'bmp', 'gif', 'svg', 'webp'])\n\nexport const fileRules: Record<string, BuiltinRule> = {\n file: { validate: (ctx) => isUploadedFileLike(ctx.value), messageKey: () => 'file' },\n image: {\n validate: (ctx) => {\n if (!isUploadedFileLike(ctx.value)) return false\n if (ctx.value.mimeType.startsWith('image/')) return true\n return IMAGE_EXTENSIONS.has(ctx.value.extension().toLowerCase())\n },\n messageKey: () => 'image',\n },\n mimes: {\n validate: (ctx) => {\n if (!isUploadedFileLike(ctx.value)) return false\n const allowed = ctx.parameters.map((p) => p.toLowerCase())\n return allowed.includes(ctx.value.extension().toLowerCase())\n },\n messageKey: () => 'mimes',\n replacements: (ctx) => ({ values: ctx.parameters.join(', ') }),\n },\n}\n","import { Arr } from '@orieljs/support'\nimport type { BuiltinRule, RuleContext } from '../parse'\nimport { InvalidRuleParameterError } from '../errors'\nimport { defaultAttributeName } from '../messages'\n\nconst EMAIL_RE = /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/\nconst UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i\nconst ALPHA_RE = /^[A-Za-z]+$/\nconst ALPHA_NUM_RE = /^[A-Za-z0-9]+$/\nconst ALPHA_DASH_RE = /^[A-Za-z0-9_-]+$/\nconst ACCEPTED_VALUES: unknown[] = ['yes', 'on', 1, '1', true, 'true']\n\nfunction compileRegex(raw: string): RegExp {\n const match = /^\\/(.*)\\/([a-z]*)$/.exec(raw)\n try {\n return match ? new RegExp(match[1]!, match[2]) : new RegExp(raw)\n } catch (error) {\n throw new InvalidRuleParameterError('regex', raw, error instanceof Error ? error.message : String(error))\n }\n}\n\n/**\n * Shapes a string must have before it counts as a date. Date.parse alone is far too lenient (V8 reads \"1\" as the\n * year 2001), so a value needs an ISO date, a slashed/dotted/dashed day-month-year, or a month name with a number.\n */\nconst DATE_SHAPES = [\n /^\\d{4}-\\d{1,2}-\\d{1,2}(?:[T\\s].*)?$/,\n /^\\d{1,2}[/.-]\\d{1,2}[/.-]\\d{2,4}(?:\\s.*)?$/,\n /^(?=.*\\d).*\\b(?:jan|feb|mar|apr|may|jun|jul|aug|sep|oct|nov|dec)[a-z]*\\b/i,\n]\nconst DATE_ONLY_RE = /^(\\d{4})-(\\d{2})-(\\d{2})$/\n\n/**\n * Parses a user-supplied date string to epoch milliseconds, or NaN. A bare YYYY-MM-DD means local midnight, like\n * PHP's strtotime, so it compares sensibly against `today`/`tomorrow`.\n */\nfunction parseDate(value: string): number {\n const trimmed = value.trim()\n if (!DATE_SHAPES.some((shape) => shape.test(trimmed))) return Number.NaN\n const dateOnly = DATE_ONLY_RE.exec(trimmed)\n if (dateOnly) {\n const [, y, m, d] = dateOnly.map(Number) as [number, number, number, number]\n const local = new Date(y, m - 1, d)\n return local.getMonth() === m - 1 && local.getDate() === d ? local.getTime() : Number.NaN\n }\n return Date.parse(trimmed)\n}\n\nfunction startOfDay(offsetDays: number): number {\n const date = new Date()\n date.setHours(0, 0, 0, 0)\n date.setDate(date.getDate() + offsetDays)\n return date.getTime()\n}\n\nconst RELATIVE_RE = /^([+-]\\d+)\\s*(second|minute|hour|day|week|month|year)s?$/i\n\n/** strtotime's keywords (today, tomorrow, yesterday, now) and \"+N unit\"/\"-N unit\" offsets from now, or undefined. */\nfunction relativeDate(param: string): number | undefined {\n switch (param.trim().toLowerCase()) {\n case 'now':\n return Date.now()\n case 'today':\n return startOfDay(0)\n case 'tomorrow':\n return startOfDay(1)\n case 'yesterday':\n return startOfDay(-1)\n }\n const match = RELATIVE_RE.exec(param.trim())\n if (!match) return undefined\n const amount = Number(match[1])\n const date = new Date()\n switch (match[2]!.toLowerCase()) {\n case 'second':\n date.setSeconds(date.getSeconds() + amount)\n break\n case 'minute':\n date.setMinutes(date.getMinutes() + amount)\n break\n case 'hour':\n date.setHours(date.getHours() + amount)\n break\n case 'day':\n date.setDate(date.getDate() + amount)\n break\n case 'week':\n date.setDate(date.getDate() + amount * 7)\n break\n case 'month':\n date.setMonth(date.getMonth() + amount)\n break\n case 'year':\n date.setFullYear(date.getFullYear() + amount)\n break\n }\n return date.getTime()\n}\n\n/** An attribute path such as \"starts_at\" or \"event.starts_at\". */\nconst FIELD_REFERENCE_RE = /^[A-Za-z_][\\w-]*(?:\\.[\\w-]+)*$/\n\n/**\n * Resolves a before/after parameter, in order: another field's date value, a relative keyword/offset, a literal\n * date. A parameter shaped like a field name whose field is missing or not a date gives NaN (the user's value\n * fails). Anything else that can't be parsed is a mistake in the rule itself, so it throws a 'Server' error\n * instead of blaming the user's input.\n */\nfunction resolveDateParam(rule: string, param: string, data: Record<string, unknown>): number {\n const fieldValue = Arr.get<unknown>(data, param)\n if (typeof fieldValue === 'string') {\n const parsed = parseDate(fieldValue)\n if (!Number.isNaN(parsed)) return parsed\n }\n const relative = relativeDate(param)\n if (relative !== undefined) return relative\n const literal = parseDate(param)\n if (!Number.isNaN(literal)) return literal\n if (FIELD_REFERENCE_RE.test(param)) return Number.NaN\n throw new InvalidRuleParameterError(rule, param, 'expected a date, today/tomorrow/yesterday/now, \"+N unit\", or a field name')\n}\n\nfunction compareDate(ctx: RuleContext, rule: 'before' | 'after'): boolean {\n const target = resolveDateParam(rule, ctx.parameters[0] ?? '', ctx.data)\n if (typeof ctx.value !== 'string') return false\n const value = parseDate(ctx.value)\n if (Number.isNaN(value) || Number.isNaN(target)) return false\n return rule === 'before' ? value < target : value > target\n}\n\nexport const formatRules: Record<string, BuiltinRule> = {\n email: { validate: (ctx) => typeof ctx.value === 'string' && EMAIL_RE.test(ctx.value), messageKey: () => 'email' },\n url: {\n validate: (ctx) => {\n if (typeof ctx.value !== 'string') return false\n try {\n new URL(ctx.value)\n return true\n } catch {\n return false\n }\n },\n messageKey: () => 'url',\n },\n uuid: { validate: (ctx) => typeof ctx.value === 'string' && UUID_RE.test(ctx.value), messageKey: () => 'uuid' },\n alpha: { validate: (ctx) => typeof ctx.value === 'string' && ALPHA_RE.test(ctx.value), messageKey: () => 'alpha' },\n alpha_num: {\n validate: (ctx) => typeof ctx.value === 'string' && ALPHA_NUM_RE.test(ctx.value),\n messageKey: () => 'alpha_num',\n },\n alpha_dash: {\n validate: (ctx) => typeof ctx.value === 'string' && ALPHA_DASH_RE.test(ctx.value),\n messageKey: () => 'alpha_dash',\n },\n lowercase: {\n validate: (ctx) => (typeof ctx.value === 'string' || typeof ctx.value === 'number') && String(ctx.value).toLowerCase() === String(ctx.value),\n messageKey: () => 'lowercase',\n },\n uppercase: {\n validate: (ctx) => (typeof ctx.value === 'string' || typeof ctx.value === 'number') && String(ctx.value).toUpperCase() === String(ctx.value),\n messageKey: () => 'uppercase',\n },\n regex: {\n validate: (ctx) => typeof ctx.value === 'string' && compileRegex(ctx.parameters[0] ?? '').test(ctx.value),\n messageKey: () => 'regex',\n },\n confirmed: {\n validate: (ctx: RuleContext) => ctx.value === Arr.get(ctx.data, `${ctx.attribute}_confirmation`),\n messageKey: () => 'confirmed',\n },\n same: {\n validate: (ctx) => ctx.value === Arr.get(ctx.data, ctx.parameters[0] ?? ''),\n messageKey: () => 'same',\n replacements: (ctx) => ({ other: defaultAttributeName(ctx.parameters[0] ?? '') }),\n },\n different: {\n validate: (ctx) => ctx.value !== Arr.get(ctx.data, ctx.parameters[0] ?? ''),\n messageKey: () => 'different',\n replacements: (ctx) => ({ other: defaultAttributeName(ctx.parameters[0] ?? '') }),\n },\n accepted: { implicit: true, validate: (ctx) => ACCEPTED_VALUES.includes(ctx.value), messageKey: () => 'accepted' },\n digits: {\n validate: (ctx) =>\n typeof ctx.value !== 'object' && new RegExp(`^\\\\d{${ctx.parameters[0]}}$`).test(String(ctx.value)),\n messageKey: () => 'digits',\n replacements: (ctx) => ({ digits: ctx.parameters[0] ?? '' }),\n },\n date: {\n validate: (ctx) => typeof ctx.value === 'string' && !Number.isNaN(parseDate(ctx.value)),\n messageKey: () => 'date',\n },\n before: {\n validate: (ctx) => compareDate(ctx, 'before'),\n messageKey: () => 'before',\n replacements: (ctx) => ({ date: ctx.parameters[0] ?? '' }),\n },\n after: {\n validate: (ctx) => compareDate(ctx, 'after'),\n messageKey: () => 'after',\n replacements: (ctx) => ({ date: ctx.parameters[0] ?? '' }),\n },\n}\n","import { Arr } from '@orieljs/support'\nimport type { BuiltinRule, RuleContext } from '../parse'\nimport { isEmptyValue } from '../parse'\n\nfunction isFieldPresent(field: string, data: Record<string, unknown>): boolean {\n return Arr.has(data, field) && !isEmptyValue(Arr.get(data, field))\n}\n\nfunction anyPresent(fields: string[], data: Record<string, unknown>): boolean {\n return fields.some((field) => isFieldPresent(field, data))\n}\n\nfunction allPresent(fields: string[], data: Record<string, unknown>): boolean {\n return fields.every((field) => isFieldPresent(field, data))\n}\n\nexport const presenceRules: Record<string, BuiltinRule> = {\n required: {\n implicit: true,\n validate: (ctx: RuleContext) => !isEmptyValue(ctx.value),\n messageKey: () => 'required',\n },\n required_if: {\n implicit: true,\n validate: (ctx: RuleContext) => {\n const [other, ...values] = ctx.parameters\n const applies = values.includes(String(Arr.get(ctx.data, other)))\n return !applies || !isEmptyValue(ctx.value)\n },\n messageKey: () => 'required_if',\n replacements: (ctx) => ({ other: ctx.parameters[0] ?? '', value: ctx.parameters.slice(1).join(', ') }),\n },\n required_unless: {\n implicit: true,\n validate: (ctx: RuleContext) => {\n const [other, ...values] = ctx.parameters\n const applies = !values.includes(String(Arr.get(ctx.data, other)))\n return !applies || !isEmptyValue(ctx.value)\n },\n messageKey: () => 'required_unless',\n replacements: (ctx) => ({ other: ctx.parameters[0] ?? '', values: ctx.parameters.slice(1).join(', ') }),\n },\n required_with: {\n implicit: true,\n validate: (ctx: RuleContext) => !anyPresent(ctx.parameters, ctx.data) || !isEmptyValue(ctx.value),\n messageKey: () => 'required_with',\n replacements: (ctx) => ({ values: ctx.parameters.join(' / ') }),\n },\n required_with_all: {\n implicit: true,\n validate: (ctx: RuleContext) => !allPresent(ctx.parameters, ctx.data) || !isEmptyValue(ctx.value),\n messageKey: () => 'required_with_all',\n replacements: (ctx) => ({ values: ctx.parameters.join(' / ') }),\n },\n required_without: {\n implicit: true,\n validate: (ctx: RuleContext) => ctx.parameters.every((f) => isFieldPresent(f, ctx.data)) || !isEmptyValue(ctx.value),\n messageKey: () => 'required_without',\n replacements: (ctx) => ({ values: ctx.parameters.join(' / ') }),\n },\n required_without_all: {\n implicit: true,\n validate: (ctx: RuleContext) => anyPresent(ctx.parameters, ctx.data) || !isEmptyValue(ctx.value),\n messageKey: () => 'required_without_all',\n replacements: (ctx) => ({ values: ctx.parameters.join(' / ') }),\n },\n}\n","import type { BuiltinRule } from '../parse'\n\nconst BOOLEAN_VALUES: unknown[] = [true, false, 0, 1, '0', '1']\n\n/** PHP's is_numeric for strings: optional surrounding whitespace and sign, decimal digits, optional exponent. */\nconst NUMERIC_STRING_RE = /^\\s*[+-]?(?:\\d+(?:\\.\\d*)?|\\.\\d+)(?:[eE][+-]?\\d+)?\\s*$/\n\n/**\n * Laravel's `numeric` (PHP is_numeric): a finite number, or a decimal string. Unlike `Number()`, it rejects\n * \"Infinity\", hex/binary/octal literals (\"0x1F\", \"0b101\", \"0o7\") and the empty string.\n */\nexport function isNumeric(value: unknown): boolean {\n if (typeof value === 'number') return Number.isFinite(value)\n return typeof value === 'string' && NUMERIC_STRING_RE.test(value)\n}\n\nexport const typeRules: Record<string, BuiltinRule> = {\n string: { validate: (ctx) => typeof ctx.value === 'string', messageKey: () => 'string' },\n integer: {\n validate: (ctx) => typeof ctx.value !== 'object' && /^-?\\d+$/.test(String(ctx.value).trim()),\n messageKey: () => 'integer',\n },\n numeric: {\n validate: (ctx) => isNumeric(ctx.value),\n messageKey: () => 'numeric',\n },\n boolean: { validate: (ctx) => BOOLEAN_VALUES.includes(ctx.value), messageKey: () => 'boolean' },\n array: { validate: (ctx) => Array.isArray(ctx.value), messageKey: () => 'array' },\n}\n","import type { BuiltinRule, RuleContext } from '../parse'\nimport { isUploadedFileLike } from '../parse'\nimport { isNumeric } from './type'\n\ntype SizeType = 'numeric' | 'array' | 'file' | 'string'\n\nfunction hasAny(ctx: RuleContext, names: string[]): boolean {\n return names.some((name) => ctx.ruleNames.includes(name))\n}\n\n/** A JSON object is a PHP associative array, so it's counted like one. */\nfunction isPlainObject(value: unknown): value is Record<string, unknown> {\n if (typeof value !== 'object' || value === null) return false\n const proto: unknown = Object.getPrototypeOf(value)\n return proto === Object.prototype || proto === null\n}\n\n/**\n * What a size rule measures and which message family it reports, decided in one place so the check and the\n * message always agree (Laravel's getSize + getAttributeType):\n * - numeric/integer rule: the number itself (a non-numeric value falls back to its string length, which the\n * numeric rule rejects anyway);\n * - an array (or plain object): its item count;\n * - an uploaded file: its size in fractional kilobytes;\n * - a file/image rule on something that isn't a file: NaN, so every size comparison fails;\n * - anything else: the length of its string form (a number without a numeric rule counts its digits).\n */\nfunction measure(ctx: RuleContext): { type: SizeType; size: number } {\n const { value } = ctx\n if (hasAny(ctx, ['numeric', 'integer'])) {\n return { type: 'numeric', size: isNumeric(value) ? Number(value) : stringLength(value) }\n }\n if (Array.isArray(value)) return { type: 'array', size: value.length }\n if (isUploadedFileLike(value)) return { type: 'file', size: value.size / 1024 }\n if (hasAny(ctx, ['file', 'image'])) return { type: 'file', size: Number.NaN }\n if (isPlainObject(value)) return { type: 'array', size: Object.keys(value).length }\n if (hasAny(ctx, ['array'])) return { type: 'array', size: stringLength(value) }\n return { type: 'string', size: stringLength(value) }\n}\n\nfunction stringLength(value: unknown): number {\n if (value === null || value === undefined) return 0\n return [...String(value)].length\n}\n\nfunction sizeOf(ctx: RuleContext): number {\n return measure(ctx).size\n}\n\nfunction sizeType(ctx: RuleContext): SizeType {\n return measure(ctx).type\n}\n\nexport const sizeRules: Record<string, BuiltinRule> = {\n max: {\n validate: (ctx) => sizeOf(ctx) <= Number(ctx.parameters[0]),\n messageKey: (ctx) => `max.${sizeType(ctx)}`,\n replacements: (ctx) => ({ max: ctx.parameters[0] ?? '' }),\n },\n min: {\n validate: (ctx) => sizeOf(ctx) >= Number(ctx.parameters[0]),\n messageKey: (ctx) => `min.${sizeType(ctx)}`,\n replacements: (ctx) => ({ min: ctx.parameters[0] ?? '' }),\n },\n between: {\n validate: (ctx) => {\n const size = sizeOf(ctx)\n return size >= Number(ctx.parameters[0]) && size <= Number(ctx.parameters[1])\n },\n messageKey: (ctx) => `between.${sizeType(ctx)}`,\n replacements: (ctx) => ({ min: ctx.parameters[0] ?? '', max: ctx.parameters[1] ?? '' }),\n },\n size: {\n validate: (ctx) => sizeOf(ctx) === Number(ctx.parameters[0]),\n messageKey: (ctx) => `size.${sizeType(ctx)}`,\n replacements: (ctx) => ({ size: ctx.parameters[0] ?? '' }),\n },\n in: { validate: (ctx) => ctx.parameters.includes(String(ctx.value)), messageKey: () => 'in' },\n not_in: { validate: (ctx) => !ctx.parameters.includes(String(ctx.value)), messageKey: () => 'not_in' },\n}\n","import type { BuiltinRule } from './parse'\nimport { authRules } from './rules/auth'\nimport { databaseRules } from './rules/database'\nimport { fileRules } from './rules/file'\nimport { formatRules } from './rules/format'\nimport { presenceRules } from './rules/presence'\nimport { sizeRules } from './rules/size'\nimport { typeRules } from './rules/type'\n\n/** Every built-in rule, merged. Later tasks (database rules) add their own spread here. */\nexport const builtinRules: Record<string, BuiltinRule> = {\n ...presenceRules,\n ...typeRules,\n ...formatRules,\n ...sizeRules,\n ...fileRules,\n ...databaseRules,\n ...authRules,\n}\n","import type { ValidationRule } from '@orieljs/contracts'\nimport { applyReplacements, DEFAULT_MESSAGES, defaultAttributeName } from '../messages'\n\nlet defaultRule: PasswordRule | (() => PasswordRule) | undefined\n\n/**\n * Laravel's Illuminate\\Validation\\Rules\\Password: a string of at least `min` characters (8 by default), plus the\n * checks you add: letters(), mixedCase(), numbers(), symbols(), max(). Every failing check adds its own message.\n * Rule.password() returns the application default (PasswordRule.defaults()). (Laravel's uncompromised() is not\n * ported: it calls an outside service.)\n */\nexport class PasswordRule implements ValidationRule {\n #min: number\n #max: number | undefined\n #letters = false\n #mixedCase = false\n #numbers = false\n #symbols = false\n\n constructor(min = 8) {\n this.#min = Math.max(1, min)\n }\n\n /** A password rule of at least `size` characters: PasswordRule.min(12).mixedCase(). */\n static min(size: number): PasswordRule {\n return new PasswordRule(size)\n }\n\n /**\n * With an argument, sets the default (Laravel's Password::defaults(fn () => ...), in a provider's boot());\n * `null` resets it. Without one, returns a copy of the default: PasswordRule.min(8) unless set.\n */\n static defaults(): PasswordRule\n static defaults(rule: PasswordRule | (() => PasswordRule) | null): void\n static defaults(rule?: PasswordRule | (() => PasswordRule) | null): PasswordRule | void {\n if (rule !== undefined) {\n defaultRule = rule ?? undefined\n return\n }\n const resolved = typeof defaultRule === 'function' ? defaultRule() : defaultRule\n return resolved === undefined ? new PasswordRule(8) : resolved.#copy()\n }\n\n min(size: number): this {\n this.#min = Math.max(1, size)\n return this\n }\n\n max(size: number): this {\n this.#max = size\n return this\n }\n\n /** At least one letter. */\n letters(): this {\n this.#letters = true\n return this\n }\n\n /** At least one uppercase and one lowercase letter. */\n mixedCase(): this {\n this.#mixedCase = true\n return this\n }\n\n /** At least one number. */\n numbers(): this {\n this.#numbers = true\n return this\n }\n\n /** At least one symbol (punctuation, a symbol or a space). */\n symbols(): this {\n this.#symbols = true\n return this\n }\n\n validate(attribute: string, value: unknown, fail: (message: string) => void): void {\n const name = defaultAttributeName(attribute)\n const say = (key: string, replacements: Record<string, string> = {}) =>\n fail(applyReplacements(DEFAULT_MESSAGES[key]!, { attribute: name, ...replacements }))\n if (typeof value !== 'string') return say('string')\n const length = [...value].length\n if (length < this.#min) say('min.string', { min: String(this.#min) })\n if (this.#max !== undefined && length > this.#max) say('max.string', { max: String(this.#max) })\n // Laravel's order and patterns.\n if (this.#mixedCase && !/(\\p{Ll}+.*\\p{Lu})|(\\p{Lu}+.*\\p{Ll})/u.test(value)) say('password.mixed')\n if (this.#letters && !/\\p{L}/u.test(value)) say('password.letters')\n if (this.#symbols && !/\\p{Z}|\\p{S}|\\p{P}/u.test(value)) say('password.symbols')\n if (this.#numbers && !/\\p{N}/u.test(value)) say('password.numbers')\n }\n\n #copy(): PasswordRule {\n const copy = new PasswordRule(this.#min)\n copy.#max = this.#max\n copy.#letters = this.#letters\n copy.#mixedCase = this.#mixedCase\n copy.#numbers = this.#numbers\n copy.#symbols = this.#symbols\n return copy\n }\n}\n","import type { ValidationRule } from '@orieljs/contracts'\nimport { applyReplacements, DEFAULT_MESSAGES, defaultAttributeName } from './messages'\nimport { guessColumn, matchingRecordExists } from './rules/database'\nimport { PasswordRule } from './rules/password'\n\n/**\n * Base for the fluent builders. Each one reports under a built-in rule name (`in`, `unique`, `exists`), so when it\n * runs inside a Validator its failure goes through exactly the same lookup as the string rule: custom messages\n * (\"email.unique\", \"items.*.email.unique\", \"unique\"), custom attributes, then the default text. Called directly\n * as a plain ValidationRule, validate() fails with the default English message.\n */\nexport abstract class BuiltinRuleObject implements ValidationRule {\n abstract readonly ruleName: string\n\n abstract passes(attribute: string, value: unknown, data: Record<string, unknown>, expandedFromWildcard?: boolean): boolean | Promise<boolean>\n\n // Declares all 4 contract parameters so a subclass's inferred type (from `Rule.in(...)` etc.) still accepts a\n // call with the full 4-arg ValidationRule.validate signature, as Rule.test.ts makes.\n async validate(attribute: string, value: unknown, fail: (message: string) => void, data: Record<string, unknown>, expandedFromWildcard = false): Promise<void> {\n if (await this.passes(attribute, value, data, expandedFromWildcard)) return\n fail(applyReplacements(DEFAULT_MESSAGES[this.ruleName]!, { attribute: defaultAttributeName(attribute) }))\n }\n}\n\nclass InRule extends BuiltinRuleObject {\n readonly ruleName = 'in'\n\n constructor(private readonly values: readonly unknown[]) {\n super()\n }\n\n passes(_attribute: string, value: unknown): boolean {\n return this.values.map(String).includes(String(value))\n }\n}\n\n/** Structural shape of Database's Model — duck-typed so this package never imports `@orieljs/database` (B27). */\ninterface ModelInstanceLike {\n getKey(): unknown\n getKeyName(): string\n}\n\nfunction isModelInstance(value: unknown): value is ModelInstanceLike {\n return (\n typeof value === 'object' &&\n value !== null &&\n typeof (value as ModelInstanceLike).getKey === 'function' &&\n typeof (value as ModelInstanceLike).getKeyName === 'function'\n )\n}\n\nclass UniqueRule extends BuiltinRuleObject {\n readonly ruleName = 'unique'\n private exceptId: unknown\n private idColumnName: string | undefined\n\n constructor(\n private readonly table: string,\n private readonly column?: string,\n ) {\n super()\n }\n\n /**\n * Excludes the current record from the uniqueness check. Laravel's `Rule::unique('users')->ignore($user)` accepts\n * a model directly (the common case: \"update your profile without changing your email\"), so a model instance is\n * bound by its key (`getKey()`/`getKeyName()`), not the object itself — the object would reach the query builder\n * as an opaque value and either be rejected by the driver or stringified (B27). A plain id still works as before;\n * null (or \"NULL\") excludes nothing.\n */\n ignore(id: unknown, idColumn?: string): this {\n if (isModelInstance(id)) {\n this.exceptId = id.getKey()\n this.idColumnName = idColumn ?? id.getKeyName()\n } else {\n this.exceptId = id\n this.idColumnName = idColumn ?? 'id'\n }\n return this\n }\n\n async passes(attribute: string, value: unknown, _data?: Record<string, unknown>, expandedFromWildcard = false): Promise<boolean> {\n const column = this.column ?? guessColumn(attribute, expandedFromWildcard)\n return !(await matchingRecordExists(this.table, column, value, this.exceptId, this.idColumnName ?? 'id'))\n }\n}\n\nclass ExistsRule extends BuiltinRuleObject {\n readonly ruleName = 'exists'\n\n constructor(\n private readonly table: string,\n private readonly column?: string,\n ) {\n super()\n }\n\n passes(attribute: string, value: unknown, _data?: Record<string, unknown>, expandedFromWildcard = false): Promise<boolean> {\n return matchingRecordExists(this.table, this.column ?? guessColumn(attribute, expandedFromWildcard), value)\n }\n}\n\n/** Fluent rule-object builders, for when a plain string rule can't express what's needed (e.g. .ignore()). */\nexport const Rule = {\n in: (values: readonly unknown[]): InRule => new InRule(values),\n unique: (table: string, column?: string): UniqueRule => new UniqueRule(table, column),\n exists: (table: string, column?: string): ExistsRule => new ExistsRule(table, column),\n /** Laravel's Password::defaults(): the application's password rule (at least 8 characters unless PasswordRule.defaults() changed it). */\n password: (): PasswordRule => PasswordRule.defaults(),\n}\n","import type { Rules, Validator } from '@orieljs/contracts'\nimport { Arr } from '@orieljs/support'\nimport { UnknownValidationRuleError, ValidationErrorImpl } from './errors'\nimport { MessageBagImpl } from './MessageBag'\nimport { BuiltinRuleObject } from './Rule'\nimport { applyReplacements, DEFAULT_MESSAGES, defaultAttributeName } from './messages'\nimport type { BuiltinRule, ParsedRule, RuleContext } from './parse'\nimport { expandWildcardKeys, parseRuleSpec, UNSAFE_KEYS } from './parse'\n\nconst SKIPPED_MODIFIERS = new Set(['bail', 'nullable', 'sometimes'])\n\n/**\n * Rebuilds a nested structure from flat dot-paths, the way Laravel's validated() does for wildcard fields.\n * `Arr.undot` (from @orieljs/support) always builds plain objects; it can't know \"items.0\"/\"items.1\" should\n * become an array. This walks the same way, then promotes any container it created itself whose keys are exactly\n * \"0\", \"1\", \"2\", … in order into a real array. Leaf values copied from the input (a Date, an uploaded file, an\n * object that happens to have \"0\"/\"1\" keys) are returned untouched, by identity. A path with a segment in\n * UNSAFE_KEYS is dropped, so nothing can be written through to Object.prototype. The input is never mutated.\n */\nfunction buildNested(flat: Record<string, unknown>): Record<string, unknown> {\n const root: Record<string, unknown> = {}\n const created = new Set<object>([root])\n for (const [path, value] of Object.entries(flat)) {\n const parts = path.split('.')\n if (parts.some((part) => UNSAFE_KEYS.has(part))) continue\n let current = root\n for (const part of parts.slice(0, -1)) {\n const existing = Object.hasOwn(current, part) ? current[part] : undefined\n if (typeof existing === 'object' && existing !== null && created.has(existing)) {\n current = existing as Record<string, unknown>\n continue\n }\n const container = cloneContainer(existing)\n created.add(container)\n current[part] = container\n current = container\n }\n current[parts.at(-1)!] = value\n }\n return arrayify(root, created) as Record<string, unknown>\n}\n\nfunction isPlainContainer(value: unknown): value is Record<string, unknown> {\n if (Array.isArray(value)) return true\n if (typeof value !== 'object' || value === null) return false\n const proto: unknown = Object.getPrototypeOf(value)\n return proto === Object.prototype || proto === null\n}\n\n/**\n * A fresh container to write a child path into. When a parent key was already copied from the input (rules on both\n * \"user\" and \"user.name\"), its plain contents are kept (Laravel returns the whole parent) but copied, so the input\n * is never mutated. Anything else (missing, a scalar, a class instance) starts empty.\n */\nfunction cloneContainer(existing: unknown): Record<string, unknown> {\n const container: Record<string, unknown> = {}\n if (!isPlainContainer(existing)) return container\n for (const [key, value] of Object.entries(existing)) {\n if (!UNSAFE_KEYS.has(key)) container[key] = value\n }\n return container\n}\n\nfunction arrayify(node: unknown, created: ReadonlySet<object>): unknown {\n if (node === null || typeof node !== 'object' || !created.has(node)) return node\n const entries = Object.entries(node as Record<string, unknown>).map(([k, v]) => [k, arrayify(v, created)] as const)\n const keys = entries.map(([k]) => k)\n const isArrayLike = keys.length > 0 && keys.every((k, i) => k === String(i))\n return isArrayLike ? entries.map(([, v]) => v) : Object.fromEntries(entries)\n}\n\n/**\n * Runs each field's rules the way Laravel's Validator does:\n * - a missing key, or a string that is blank after trimming, only runs implicit rules (the required* family and\n * accepted); every other rule, including ValidationRule objects, is skipped for it;\n * - an explicit null runs every rule unless the field is `nullable` (then only implicit rules run), so\n * `{ age: null }` still fails `integer`;\n * - `sometimes` skips a missing field entirely;\n * - a field stops validating after its first failure under `bail`, or after any implicit rule fails.\n */\nexport class ValidatorImpl implements Validator {\n private bag: MessageBagImpl | undefined\n private ranPromise: Promise<boolean> | undefined\n private readonly afterCallbacks: Array<(validator: Validator) => void | Promise<void>> = []\n\n constructor(\n private readonly data: Record<string, unknown>,\n private readonly rules: Rules,\n private readonly customMessages: Record<string, string>,\n private readonly customAttributes: Record<string, string>,\n private readonly registry: Record<string, BuiltinRule>,\n private readonly errorBagName = 'default',\n ) {}\n\n after(callback: (validator: Validator) => void | Promise<void>): this {\n this.afterCallbacks.push(callback)\n return this\n }\n\n /** Not part of the Validator contract — lets an after() hook add a failure (MessageBag itself is read-only). */\n fail(field: string, message: string): void {\n this.bag ??= new MessageBagImpl()\n this.bag.add(field, message)\n }\n\n async passes(): Promise<boolean> {\n this.ranPromise ??= this.run()\n return this.ranPromise\n }\n\n async fails(): Promise<boolean> {\n return !(await this.passes())\n }\n\n errors(): MessageBagImpl {\n return this.bag ?? new MessageBagImpl()\n }\n\n async validated<T = Record<string, unknown>>(): Promise<T> {\n if (!(await this.passes())) throw new ValidationErrorImpl(this.bag!.toObject(), this.errorBagName)\n const flat: Record<string, unknown> = {}\n for (const pattern of Object.keys(this.rules)) {\n for (const field of this.fieldsFor(pattern)) {\n if (Arr.has(this.data, field)) flat[field] = Arr.get(this.data, field)\n }\n }\n return buildNested(flat) as T\n }\n\n private fieldsFor(pattern: string): string[] {\n return pattern.includes('*') ? expandWildcardKeys(pattern, this.data) : [pattern]\n }\n\n private async run(): Promise<boolean> {\n this.bag = new MessageBagImpl()\n\n for (const [pattern, spec] of Object.entries(this.rules)) {\n const parsed = parseRuleSpec(spec)\n const names = parsed.filter((r): r is Extract<ParsedRule, { kind: 'named' }> => r.kind === 'named').map((r) => r.name)\n const bail = names.includes('bail')\n const nullable = names.includes('nullable')\n const sometimes = names.includes('sometimes')\n\n for (const field of this.fieldsFor(pattern)) {\n const present = Arr.has(this.data, field)\n if (sometimes && !present) continue\n\n const value = Arr.get(this.data, field)\n const isNull = value === null || value === undefined\n const isBlank = typeof value === 'string' && value.trim() === ''\n\n for (const rule of parsed) {\n if (rule.kind === 'named' && SKIPPED_MODIFIERS.has(rule.name)) continue\n const implicit = rule.kind === 'named' && (this.registry[rule.name]?.implicit ?? false)\n // Laravel's presentOrRuleIsImplicit: a missing key or a blank string only runs implicit rules.\n if (!implicit && (!present || isBlank)) continue\n // Laravel's isNotNullIfMarkedAsNullable: nullable + null only runs implicit rules.\n if (!implicit && nullable && isNull) continue\n\n const messages = await this.runRule(rule, field, pattern, value, names)\n if (messages.length > 0) {\n for (const message of messages) this.bag.add(field, message)\n // Laravel's shouldStopValidating: bail stops at the first failure; a failed implicit rule always stops.\n if (bail || implicit) break\n }\n }\n }\n }\n\n for (const callback of this.afterCallbacks) await callback(this)\n return this.bag.isEmpty()\n }\n\n private async runRule(\n rule: ParsedRule,\n field: string,\n pattern: string,\n value: unknown,\n ruleNames: string[],\n ): Promise<string[]> {\n const expanded = pattern.includes('*')\n if (rule.kind === 'object') {\n if (rule.rule instanceof BuiltinRuleObject) {\n if (await rule.rule.passes(field, value, this.data, expanded)) return []\n const ctx = { attribute: field, expandedFromWildcard: expanded, value, parameters: [], data: this.data, ruleNames }\n return [this.failureMessage(rule.rule.ruleName, this.registry[rule.rule.ruleName], ctx, pattern)]\n }\n // Every fail() call is a message, as with Laravel's invokable rules (Rule.password() reports each failed check).\n const failures: string[] = []\n await rule.rule.validate(field, value, (message) => void failures.push(message), this.data)\n return failures\n }\n\n const builtin = this.registry[rule.name]\n if (!builtin) throw new UnknownValidationRuleError(rule.name)\n\n const ctx = { attribute: field, expandedFromWildcard: expanded, value, parameters: rule.parameters, data: this.data, ruleNames }\n if (await builtin.validate(ctx)) return []\n return [this.failureMessage(rule.name, builtin, ctx, pattern)]\n }\n\n /** Custom message (concrete field, then wildcard pattern, then rule name) or the default, with :attribute filled. */\n private failureMessage(name: string, builtin: BuiltinRule | undefined, ctx: RuleContext, pattern: string): string {\n const field = ctx.attribute\n const template =\n this.customMessages[`${field}.${name}`] ??\n this.customMessages[`${pattern}.${name}`] ??\n this.customMessages[name] ??\n builtin?.message ??\n DEFAULT_MESSAGES[builtin?.messageKey(ctx) ?? name] ??\n builtin?.defaultMessage ??\n 'The :attribute field is invalid.'\n\n const display = this.customAttributes[field] ?? this.customAttributes[pattern] ?? defaultAttributeName(field)\n return applyReplacements(template, { attribute: display, ...(builtin?.replacements?.(ctx) ?? {}) })\n }\n}\n","import type { RuleCallback, Rules, ValidationFactory } from '@orieljs/contracts'\nimport type { BuiltinRule } from './parse'\nimport { builtinRules } from './registry'\nimport { ValidatorImpl } from './Validator'\n\nexport class ValidationFactoryImpl implements ValidationFactory {\n private readonly extended: Record<string, BuiltinRule> = {}\n\n make(\n data: Record<string, unknown>,\n rules: Rules,\n messages: Record<string, string> = {},\n attributes: Record<string, string> = {},\n ): ValidatorImpl {\n return new ValidatorImpl(data, rules, messages, attributes, { ...builtinRules, ...this.extended })\n }\n\n extend(name: string, callback: RuleCallback, message?: string): void {\n this.extended[name] = {\n validate: (ctx) => callback(ctx.attribute, ctx.value, ctx.parameters, ctx.data),\n messageKey: () => name,\n ...(message === undefined ? {} : { message }),\n defaultMessage: message ?? 'The :attribute field is invalid.',\n }\n }\n}\n","import type { ValidationFactory } from '@orieljs/contracts'\nimport { ValidationFactory as ValidationFactoryToken } from '@orieljs/contracts'\nimport { facade } from '@orieljs/support'\n\n/** Laravel's Validator facade: Validator.make(...)/Validator.extend(...), proxied to the resolved ValidationFactory. */\nexport const Validator = facade<ValidationFactory>(ValidationFactoryToken)\n","import { ValidationFactory as ValidationFactoryToken } from '@orieljs/contracts'\nimport { ServiceProvider } from '@orieljs/support'\nimport { ValidationFactoryImpl } from './ValidationFactory'\n\nexport class ValidationServiceProvider extends ServiceProvider {\n override register(): void {\n this.app.singleton(ValidationFactoryToken, () => new ValidationFactoryImpl())\n }\n}\n"],"mappings":"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","names":["inject","inject","Arr","Arr","Arr","Arr","Arr","Arr","ctx","ValidationFactoryToken","ValidationFactoryToken"]}
|
|
1
|
+
{"version":3,"sources":["../errors.ts","../FormRequest.ts","../messages.ts","../MessageBag.ts","../rules/auth.ts","../rules/database.ts","../rules/file.ts","../files/dimensions.ts","../parse.ts","../rules/format.ts","../rules/presence.ts","../rules/type.ts","../rules/size.ts","../registry.ts","../rules/password.ts","../Rule.ts","../Validator.ts","../ValidationFactory.ts","../facade.ts","../ValidationServiceProvider.ts"],"sourcesContent":["import type { OrielError, ValidationError } from '@orieljs/contracts'\n\nexport class ValidationErrorImpl extends Error implements ValidationError {\n readonly kind = 'Validation' as const\n readonly status = 422\n override readonly name = 'ValidationError'\n constructor(\n readonly errors: Record<string, string[]>,\n readonly errorBag = 'default',\n readonly redirectTo?: string,\n ) {\n super('The given data was invalid.')\n }\n}\n\n/**\n * Laravel's ValidationException, for failing a request by hand:\n * `throw ValidationException.withMessages({ email: __('auth.failed') })`. Rendered like any validation error: 422 JSON,\n * or a redirect back with the errors.\n */\nexport class ValidationException extends ValidationErrorImpl {\n /** Messages per field, each a string or a list. */\n static withMessages(messages: Record<string, string | readonly string[]>): ValidationException {\n const errors = Object.fromEntries(Object.entries(messages).map(([field, list]) => [field, typeof list === 'string' ? [list] : [...list]]))\n return new ValidationException(errors)\n }\n\n constructor(errors: Record<string, string[]>, errorBag = 'default', redirectTo?: string) {\n super(errors, errorBag, redirectTo)\n this.message = summarize(errors)\n }\n}\n\n/** \"The first message. (and 2 more errors)\" (Laravel's ValidationException::summarize()). */\nfunction summarize(errors: Record<string, string[]>): string {\n const messages = Object.values(errors).flat()\n if (messages.length === 0) return 'The given data was invalid.'\n const more = messages.length - 1\n return more === 0 ? messages[0]! : `${messages[0]!} (and ${more} more ${more === 1 ? 'error' : 'errors'})`\n}\n\nexport class AuthorizationErrorImpl extends Error implements OrielError {\n readonly kind = 'Authorization' as const\n readonly status = 403\n override readonly name = 'AuthorizationError'\n constructor(message = 'This action is unauthorized.') {\n super(message)\n }\n}\n\nexport class UnknownValidationRuleError extends Error implements OrielError {\n readonly kind = 'Server' as const\n readonly status = 500\n override readonly name = 'UnknownValidationRuleError'\n constructor(name: string) {\n super(`Validation rule \"${name}\" is not registered. Register it with ValidationFactory.extend() first.`)\n }\n}\n\n/** A rule was written with a parameter it can't use (a bad regex, an unparseable date). A developer error, not a user one. */\nexport class InvalidRuleParameterError extends Error implements OrielError {\n readonly kind = 'Server' as const\n readonly status = 500\n override readonly name = 'InvalidRuleParameterError'\n constructor(rule: string, parameter: string, reason: string) {\n super(`Validation rule \"${rule}\" has an invalid parameter \"${parameter}\": ${reason}`)\n }\n}\n","import type { Rules } from '@orieljs/contracts'\nimport { HttpRequest, ValidationFactory } from '@orieljs/contracts'\nimport { inject } from '@orieljs/container'\nimport { AuthorizationErrorImpl } from './errors'\n\n/**\n * Mirrors Illuminate\\Foundation\\Http\\FormRequest, minus dependency injection by type (Oriel resolves the current\n * request and the ValidationFactory through inject(), never through constructor parameters — see spec §3 rule 5).\n * A subclass only has to implement rules(); authorize()/messages()/attributes() default to Laravel's own defaults.\n */\nexport abstract class FormRequest {\n abstract rules(): Rules\n\n authorize(): boolean | Promise<boolean> {\n return true\n }\n\n messages(): Record<string, string> {\n return {}\n }\n\n attributes(): Record<string, string> {\n return {}\n }\n\n /**\n * `const data = await StorePostRequest.validate()` (spec §4.3). Resolves the current request and the\n * ValidationFactory from the active container, runs authorize() first (throwing AuthorizationErrorImpl if it\n * returns false), then validates request.all() against rules()/messages()/attributes() and returns the typed\n * validated data (or throws the 422 ValidationError — see ValidatorImpl.validated()).\n */\n static async validate<T = Record<string, unknown>>(this: new () => FormRequest): Promise<T> {\n const instance = new this()\n if (!(await instance.authorize())) throw new AuthorizationErrorImpl()\n\n const request = inject(HttpRequest)\n const factory = inject(ValidationFactory)\n const validator = factory.make(request.all(), instance.rules(), instance.messages(), instance.attributes())\n return validator.validated<T>()\n }\n}\n","import { Str } from '@orieljs/support'\n\n/** Humanizes a (possibly dotted) attribute key, e.g. \"items.0.product_name\" -> \"items.0.product name\". */\nexport function defaultAttributeName(key: string): string {\n return key\n .split('.')\n .map((segment) => Str.snake(segment).replace(/_/g, ' '))\n .join('.')\n}\n\nexport function applyReplacements(template: string, replacements: Record<string, string>): string {\n return Object.entries(replacements).reduce((message, [key, value]) => message.replaceAll(`:${key}`, value), template)\n}\n\n/** Laravel's English lang/en/validation.php, reproduced as closely as possible (see plan Notes/assumptions). */\nexport const DEFAULT_MESSAGES: Record<string, string> = {\n required: 'The :attribute field is required.',\n required_if: 'The :attribute field is required when :other is :value.',\n required_unless: 'The :attribute field is required unless :other is in :values.',\n required_with: 'The :attribute field is required when :values is present.',\n required_with_all: 'The :attribute field is required when :values are present.',\n required_without: 'The :attribute field is required when :values is not present.',\n required_without_all: 'The :attribute field is required when none of :values are present.',\n string: 'The :attribute field must be a string.',\n integer: 'The :attribute field must be an integer.',\n numeric: 'The :attribute field must be a number.',\n boolean: 'The :attribute field must be true or false.',\n array: 'The :attribute field must be an array.',\n email: 'The :attribute field must be a valid email address.',\n url: 'The :attribute field must be a valid URL.',\n uuid: 'The :attribute field must be a valid UUID.',\n alpha: 'The :attribute field must only contain letters.',\n alpha_num: 'The :attribute field must only contain letters and numbers.',\n alpha_dash: 'The :attribute field must only contain letters, numbers, dashes and underscores.',\n regex: 'The :attribute field format is invalid.',\n lowercase: 'The :attribute field must be lowercase.',\n uppercase: 'The :attribute field must be uppercase.',\n current_password: 'The password is incorrect.',\n 'password.letters': 'The :attribute field must contain at least one letter.',\n 'password.mixed': 'The :attribute field must contain at least one uppercase and one lowercase letter.',\n 'password.numbers': 'The :attribute field must contain at least one number.',\n 'password.symbols': 'The :attribute field must contain at least one symbol.',\n confirmed: 'The :attribute field confirmation does not match.',\n same: 'The :attribute field must match :other.',\n different: 'The :attribute field must be different from :other.',\n accepted: 'The :attribute field must be accepted.',\n digits: 'The :attribute field must be :digits digits.',\n date: 'The :attribute field must be a valid date.',\n before: 'The :attribute field must be a date before :date.',\n after: 'The :attribute field must be a date after :date.',\n in: 'The selected :attribute is invalid.',\n not_in: 'The selected :attribute is invalid.',\n unique: 'The :attribute has already been taken.',\n exists: 'The selected :attribute is invalid.',\n file: 'The :attribute field must be a file.',\n image: 'The :attribute field must be an image.',\n mimes: 'The :attribute field must be a file of type: :values.',\n mimetypes: 'The :attribute field must be a file of type: :values.',\n extensions: 'The :attribute field must have one of the following extensions: :values.',\n dimensions: 'The :attribute field has invalid image dimensions.',\n 'max.string': 'The :attribute field must not be greater than :max characters.',\n 'max.numeric': 'The :attribute field must not be greater than :max.',\n 'max.array': 'The :attribute field must not have more than :max items.',\n 'max.file': 'The :attribute field must not be greater than :max kilobytes.',\n 'min.string': 'The :attribute field must be at least :min characters.',\n 'min.numeric': 'The :attribute field must be at least :min.',\n 'min.array': 'The :attribute field must have at least :min items.',\n 'min.file': 'The :attribute field must be at least :min kilobytes.',\n 'between.string': 'The :attribute field must be between :min and :max characters.',\n 'between.numeric': 'The :attribute field must be between :min and :max.',\n 'between.array': 'The :attribute field must have between :min and :max items.',\n 'between.file': 'The :attribute field must be between :min and :max kilobytes.',\n 'size.string': 'The :attribute field must be :size characters.',\n 'size.numeric': 'The :attribute field must be :size.',\n 'size.array': 'The :attribute field must contain :size items.',\n 'size.file': 'The :attribute field must be :size kilobytes.',\n}\n","import type { MessageBag } from '@orieljs/contracts'\n\nexport class MessageBagImpl implements MessageBag {\n private readonly items: Record<string, string[]> = {}\n\n /** Not part of the MessageBag contract — used internally by ValidatorImpl and by after() hooks. */\n add(key: string, message: string): void {\n ;(this.items[key] ??= []).push(message)\n }\n\n has(key: string): boolean {\n return (this.items[key]?.length ?? 0) > 0\n }\n\n first(key?: string): string | undefined {\n if (key !== undefined) return this.items[key]?.[0]\n for (const messages of Object.values(this.items)) {\n if (messages[0] !== undefined) return messages[0]\n }\n return undefined\n }\n\n get(key: string): string[] {\n return this.items[key] ?? []\n }\n\n all(): string[] {\n return Object.values(this.items).flat()\n }\n\n isEmpty(): boolean {\n return Object.keys(this.items).length === 0\n }\n\n count(): number {\n return this.all().length\n }\n\n toObject(): Record<string, string[]> {\n return structuredClone(this.items)\n }\n}\n","import { AuthFactory, Hasher } from '@orieljs/contracts'\nimport { inject } from '@orieljs/container'\nimport type { BuiltinRule } from '../parse'\n\n/** `current_password` / `current_password:<guard>`: the value is the signed-in user's password (Laravel). */\nexport const authRules: Record<string, BuiltinRule> = {\n current_password: {\n validate: async (ctx) => {\n const guard = inject(AuthFactory).guard(ctx.parameters[0])\n if (await guard.guest()) return false\n const user = await guard.user()\n return user !== undefined && typeof ctx.value === 'string' && inject(Hasher).check(ctx.value, user.getAuthPassword())\n },\n messageKey: () => 'current_password',\n },\n}\n","import { DatabaseManager } from '@orieljs/contracts'\nimport { inject } from '@orieljs/container'\nimport type { BuiltinRule } from '../parse'\n\n/**\n * The column to query when a unique/exists rule doesn't name one: the attribute itself, except for a\n * wildcard-expanded field like \"items.0.email\", which checks the last non-numeric segment (\"email\") rather than a\n * column literally named after the path (Laravel's guessColumnForQuery).\n */\nexport function guessColumn(attribute: string, expandedFromWildcard = false): string {\n if (!expandedFromWildcard) return attribute\n return attribute.split('.').filter((segment) => !/^\\d+$/.test(segment)).at(-1) ?? attribute\n}\n\n/** Laravel's idiom `unique:users,email,NULL,id` (and an empty or null ignore) means \"exclude nothing\". */\nfunction isNoExcept(except: unknown): boolean {\n return except === undefined || except === null || except === '' || except === 'NULL'\n}\n\n/**\n * Shared query shape behind both `unique`/`exists` string rules and `Rule.unique()`/`Rule.exists()` (Review Focus\n * #2): resolve DatabaseManager, filter table/column on value, optionally exclude a record by idColumn/except, and\n * report whether any row matches. Kept in one place so a future fix to this path can't miss one of the two callers.\n */\nexport async function matchingRecordExists(\n table: string,\n column: string,\n value: unknown,\n except?: unknown,\n idColumn = 'id',\n): Promise<boolean> {\n const db = inject(DatabaseManager)\n let query = db.connection().table(table).where(column, value)\n if (!isNoExcept(except)) query = query.where(idColumn, '!=', except)\n return query.exists()\n}\n\nexport const databaseRules: Record<string, BuiltinRule> = {\n unique: {\n validate: async (ctx) => {\n const [table, column, except, idColumn] = ctx.parameters\n return !(await matchingRecordExists(table!, column || guessColumn(ctx.attribute, ctx.expandedFromWildcard), ctx.value, except, idColumn || 'id'))\n },\n messageKey: () => 'unique',\n },\n exists: {\n validate: async (ctx) => {\n const [table, column] = ctx.parameters\n return matchingRecordExists(table!, column || guessColumn(ctx.attribute, ctx.expandedFromWildcard), ctx.value)\n },\n messageKey: () => 'exists',\n },\n}\n","import { FileType } from '@orieljs/support'\nimport { InvalidRuleParameterError } from '../errors'\nimport { imageDimensions, type Dimensions } from '../files/dimensions'\nimport type { BuiltinRule, RuleContext } from '../parse'\nimport { isUploadedFileLike } from '../parse'\n\nconst { BINARY_AND_MARKUP_TYPES, detectFileType, EMPTY, RASTER_IMAGES, SVG, TEXT } = FileType\ntype DetectedType = FileType.DetectedType\n\ninterface Upload {\n clientName: string\n arrayBuffer(): Promise<ArrayBuffer>\n}\n\n/** What an upload's bytes show: its type and, for a raster image, its pixel size. */\ninterface Inspection {\n type: DetectedType\n dimensions: Dimensions | undefined\n}\n\nconst inspections = new WeakMap<object, Promise<Inspection>>()\n\n/** Reads an upload's bytes once per file object, however many file rules look at it. */\nfunction inspect(file: Upload): Promise<Inspection> {\n let inspection = inspections.get(file)\n if (!inspection) {\n inspection = file.arrayBuffer().then((buffer) => {\n const bytes = new Uint8Array(buffer)\n const type = detectFileType(bytes)\n return { type, dimensions: RASTER_IMAGES.has(type.mime) ? imageDimensions(bytes, type.mime) : undefined }\n })\n inspections.set(file, inspection)\n }\n return inspection\n}\n\n/** The extension of the file name the client sent, lower-cased ('' when it has none). */\nfunction clientExtension(file: Upload): string {\n const name = file.clientName.slice(Math.max(file.clientName.lastIndexOf('/'), file.clientName.lastIndexOf('\\\\')) + 1)\n const dot = name.lastIndexOf('.')\n return dot === -1 ? '' : name.slice(dot + 1).trim().toLowerCase()\n}\n\nconst PHP_EXTENSIONS: ReadonlySet<string> = new Set(['php', 'php3', 'php4', 'php5', 'php7', 'php8', 'phtml', 'phar'])\n\n/** Laravel's shouldBlockPhpUpload(): a file named like a PHP script fails the file rules unless the list names php. */\nconst blocksPhp = (file: Upload, allowed: readonly string[]): boolean => !allowed.includes('php') && PHP_EXTENSIONS.has(clientExtension(file))\n\n/** Text formats whose bytes look like any plain text: the client's extension tells them apart, for text bytes only. */\nconst TEXT_FORMATS: ReadonlySet<string> = new Set(['txt', 'text', 'csv', 'tsv', 'json', 'md'])\n\n/** The extensions of the formats recognised by their bytes: a file name alone never earns one. */\nconst RECOGNISED_EXTENSIONS: ReadonlySet<string> = new Set(BINARY_AND_MARKUP_TYPES.flatMap(({ extensions }) => extensions))\n\nconst lower = (values: readonly string[]): string[] => values.map((value) => value.trim().toLowerCase())\n\n/**\n * mimes: the detected type must be one the list names (jpg and jpeg are one, as in Laravel).\n * - A format recognised by its bytes (images, SVG, PDF, HTML, XML) passes only by its own extensions.\n * - Plain text passes `txt`, or the client's extension when that names no recognised format (`csv`, `json`, `yaml`, …).\n * - Bytes no format matches (docx, zip, mp4, …) pass by the client's extension, unless that extension names a\n * recognised format or a text format, which the bytes would have shown.\n * - An empty file fails.\n */\nfunction meetsMimes(type: DetectedType, extension: string, allowed: ReadonlySet<string>): boolean {\n if (type === EMPTY) return false\n if (type === TEXT && allowed.has('txt')) return true\n if (type !== TEXT && type.extensions.length > 0) return type.extensions.some((name) => allowed.has(name))\n if (!allowed.has(extension) || RECOGNISED_EXTENSIONS.has(extension)) return false\n return type === TEXT || !TEXT_FORMATS.has(extension)\n}\n\nfunction allowedExtensions(ctx: RuleContext): Set<string> {\n const allowed = new Set(lower(ctx.parameters))\n if (allowed.has('jpg') || allowed.has('jpeg')) allowed.add('jpg').add('jpeg')\n return allowed\n}\n\nconst listed = (ctx: RuleContext): Record<string, string> => ({ values: ctx.parameters.join(', ') })\n\nconst DIMENSION_KEYS = ['width', 'height', 'min_width', 'min_height', 'max_width', 'max_height', 'ratio'] as const\ntype DimensionKey = (typeof DIMENSION_KEYS)[number]\ntype DimensionConstraints = Partial<Record<DimensionKey, number>>\n\n/** 'min_width=800' → ['min_width', '800']. */\nfunction namedParameter(parameter: string): [string, string] {\n const at = parameter.indexOf('=')\n return at === -1 ? [parameter, ''] : [parameter.slice(0, at), parameter.slice(at + 1)]\n}\n\n/** '3/2' or '1.5' (Laravel reads a ratio as a number, optionally over a whole number). */\nfunction parseRatio(value: string): number | undefined {\n const match = /^(\\d+(?:\\.\\d+)?|\\.\\d+)(?:\\/(\\d+))?$/.exec(value.trim())\n if (!match) return undefined\n const ratio = Number(match[1]) / Number(match[2] ?? 1)\n return Number.isFinite(ratio) && ratio > 0 ? ratio : undefined\n}\n\n/** dimensions' parameters as numbers. A name Oriel doesn't know or a value it can't read is a developer error. */\nfunction dimensionConstraints(parameters: readonly string[]): DimensionConstraints {\n if (parameters.length === 0) throw new InvalidRuleParameterError('dimensions', '', `expected one or more of ${DIMENSION_KEYS.join(', ')}`)\n const constraints: DimensionConstraints = {}\n for (const parameter of parameters) {\n const [key, value] = namedParameter(parameter)\n if (!(DIMENSION_KEYS as readonly string[]).includes(key)) {\n throw new InvalidRuleParameterError('dimensions', parameter, `expected one of ${DIMENSION_KEYS.join(', ')}`)\n }\n const number = key === 'ratio' ? parseRatio(value) : /^\\d+$/.test(value) ? Number(value) : undefined\n if (number === undefined) {\n throw new InvalidRuleParameterError('dimensions', parameter, key === 'ratio' ? 'expected a ratio such as 3/2 or 1.5' : 'expected a whole number of pixels')\n }\n constraints[key as DimensionKey] = number\n }\n return constraints\n}\n\n/** Laravel's failsBasicDimensionChecks() and failsRatioCheck(), inverted. */\nfunction meetsDimensions(constraints: DimensionConstraints, { width, height }: Dimensions): boolean {\n const { width: exactWidth, height: exactHeight, min_width, max_width, min_height, max_height, ratio } = constraints\n if (exactWidth !== undefined && width !== exactWidth) return false\n if (exactHeight !== undefined && height !== exactHeight) return false\n if (min_width !== undefined && width < min_width) return false\n if (max_width !== undefined && width > max_width) return false\n if (min_height !== undefined && height < min_height) return false\n if (max_height !== undefined && height > max_height) return false\n // The tolerance is Laravel's: about one pixel at the image's size.\n return ratio === undefined || Math.abs(ratio - width / height) <= 1 / (Math.max((width + height) / 2, height) + 1)\n}\n\nexport const fileRules: Record<string, BuiltinRule> = {\n file: { validate: (ctx) => isUploadedFileLike(ctx.value), messageKey: () => 'file' },\n\n /** A JPEG, PNG, GIF, WebP, AVIF or BMP by its bytes; SVG only as `image:allow_svg` (Laravel 12). */\n image: {\n validate: async (ctx) => {\n if (!isUploadedFileLike(ctx.value) || blocksPhp(ctx.value, [])) return false\n const { type } = await inspect(ctx.value)\n return RASTER_IMAGES.has(type.mime) || (type === SVG && ctx.parameters.includes('allow_svg'))\n },\n messageKey: () => 'image',\n },\n\n mimes: {\n validate: async (ctx) => {\n if (!isUploadedFileLike(ctx.value)) return false\n const allowed = allowedExtensions(ctx)\n if (blocksPhp(ctx.value, [...allowed])) return false\n return meetsMimes((await inspect(ctx.value)).type, clientExtension(ctx.value), allowed)\n },\n messageKey: () => 'mimes',\n replacements: listed,\n },\n\n /**\n * The detected MIME type is listed, or its `type/*` wildcard is. `image/*` includes SVG (`image/svg+xml`), as in\n * Laravel: the rule for photos is `image`.\n */\n mimetypes: {\n validate: async (ctx) => {\n if (!isUploadedFileLike(ctx.value)) return false\n const allowed = lower(ctx.parameters)\n if (blocksPhp(ctx.value, allowed)) return false\n const { mime } = (await inspect(ctx.value)).type\n return allowed.includes(mime) || allowed.includes(`${mime.split('/')[0]}/*`)\n },\n messageKey: () => 'mimetypes',\n replacements: listed,\n },\n\n /**\n * The pixel size read from the image's header meets every constraint: width, height, min_width, max_width,\n * min_height, max_height, ratio. SVG and images whose header can't be read fail.\n */\n dimensions: {\n validate: async (ctx) => {\n const constraints = dimensionConstraints(ctx.parameters)\n if (!isUploadedFileLike(ctx.value)) return false\n const { dimensions } = await inspect(ctx.value)\n return dimensions !== undefined && meetsDimensions(constraints, dimensions)\n },\n messageKey: () => 'dimensions',\n replacements: (ctx) => Object.fromEntries(ctx.parameters.map(namedParameter)),\n },\n\n /** The client file name's extension is listed (Laravel 11). It checks the name only: pair it with mimes or image. */\n extensions: {\n validate: (ctx) => {\n if (!isUploadedFileLike(ctx.value)) return false\n const allowed = lower(ctx.parameters)\n return !blocksPhp(ctx.value, allowed) && allowed.includes(clientExtension(ctx.value))\n },\n messageKey: () => 'extensions',\n replacements: listed,\n },\n}\n","/** An image's size in pixels, as its header declares it (what PHP's getimagesize() reports for Laravel). */\nexport interface Dimensions {\n readonly width: number\n readonly height: number\n}\n\ntype Reader = (view: DataView) => Dimensions | undefined\n\n/** JPEG frame headers (SOF0–SOF15, without DHT, JPG and DAC), baseline, progressive or lossless. */\nconst FRAME_MARKERS: ReadonlySet<number> = new Set([0xc0, 0xc1, 0xc2, 0xc3, 0xc5, 0xc6, 0xc7, 0xc9, 0xca, 0xcb, 0xcd, 0xce, 0xcf])\n\n/** The steps (a fill byte, a marker or a segment each) a JPEG gets to reach its frame header; real ones need a few dozen. */\nconst MAX_JPEG_STEPS = 1024\n\n/** The boxes one ISO-BMFF walk reads; real images have a handful at each level. */\nconst MAX_BOXES = 1024\n\nconst fourcc = (view: DataView, offset: number): string =>\n String.fromCharCode(view.getUint8(offset), view.getUint8(offset + 1), view.getUint8(offset + 2), view.getUint8(offset + 3))\n\nconst u24le = (view: DataView, offset: number): number =>\n view.getUint8(offset) | (view.getUint8(offset + 1) << 8) | (view.getUint8(offset + 2) << 16)\n\nconst READERS: Record<string, Reader> = {\n 'image/png': (view) => (fourcc(view, 12) === 'IHDR' ? { width: view.getUint32(16), height: view.getUint32(20) } : undefined),\n 'image/gif': (view) => ({ width: view.getUint16(6, true), height: view.getUint16(8, true) }),\n 'image/bmp': (view) =>\n view.getUint32(14, true) === 12\n ? { width: view.getUint16(18, true), height: view.getUint16(20, true) }\n : { width: Math.abs(view.getInt32(18, true)), height: Math.abs(view.getInt32(22, true)) },\n 'image/jpeg': jpeg,\n 'image/webp': webp,\n 'image/avif': avif,\n}\n\n/** The size declared in the header of an image of the given detected type, or undefined when it can't be read. */\nexport function imageDimensions(bytes: Uint8Array, mime: string): Dimensions | undefined {\n const reader = READERS[mime]\n if (!reader) return undefined\n try {\n const size = reader(new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength))\n return size && size.width > 0 && size.height > 0 ? size : undefined\n } catch (error) {\n // A header cut short reads past the end of the bytes: the image has no readable size.\n if (error instanceof RangeError) return undefined\n throw error\n }\n}\n\n/** Walks the marker segments to the first frame header. */\nfunction jpeg(view: DataView): Dimensions | undefined {\n let offset = 2\n for (let step = 0; step < MAX_JPEG_STEPS && offset + 4 <= view.byteLength; step++) {\n if (view.getUint8(offset) !== 0xff) return undefined\n const marker = view.getUint8(offset + 1)\n if (marker === 0xff) offset += 1 // a fill byte\n else if (marker === 0xd8 || marker === 0x01 || (marker >= 0xd0 && marker <= 0xd7)) offset += 2 // no length\n else if (marker === 0xd9 || marker === 0xda) return undefined // the image ends, or its data starts, before any frame header\n else if (FRAME_MARKERS.has(marker)) return { height: view.getUint16(offset + 5), width: view.getUint16(offset + 7) }\n else offset += 2 + view.getUint16(offset + 2)\n }\n return undefined\n}\n\n/** VP8 (lossy), VP8L (lossless) or VP8X (extended) chunks. */\nfunction webp(view: DataView): Dimensions | undefined {\n const chunk = fourcc(view, 12)\n if (chunk === 'VP8 ') {\n if (view.getUint8(23) !== 0x9d || view.getUint8(24) !== 0x01 || view.getUint8(25) !== 0x2a) return undefined\n return { width: view.getUint16(26, true) & 0x3fff, height: view.getUint16(28, true) & 0x3fff }\n }\n if (chunk === 'VP8L') {\n if (view.getUint8(20) !== 0x2f) return undefined\n const bits = view.getUint32(21, true)\n return { width: (bits & 0x3fff) + 1, height: ((bits >>> 14) & 0x3fff) + 1 }\n }\n if (chunk === 'VP8X') return { width: u24le(view, 24) + 1, height: u24le(view, 27) + 1 }\n return undefined\n}\n\ninterface Box {\n type: string\n /** Where the box's content starts. */\n start: number\n end: number\n}\n\n/** The ISO-BMFF boxes between start and end. */\nfunction* boxes(view: DataView, start: number, end: number): Generator<Box> {\n let offset = start\n for (let count = 0; count < MAX_BOXES && offset + 8 <= end; count++) {\n let size = view.getUint32(offset)\n let header = 8\n if (size === 1) {\n size = Number(view.getBigUint64(offset + 8))\n header = 16\n } else if (size === 0) {\n size = end - offset\n }\n if (size < header || offset + size > end) return\n yield { type: fourcc(view, offset + 4), start: offset + header, end: offset + size }\n offset += size\n }\n}\n\nconst findBox = (view: DataView, start: number, end: number, type: string): Box | undefined => {\n for (const box of boxes(view, start, end)) if (box.type === type) return box\n return undefined\n}\n\n/** The largest ispe (image spatial extents) property in meta → iprp → ipco: the primary image, not a thumbnail. */\nfunction avif(view: DataView): Dimensions | undefined {\n const meta = findBox(view, 0, view.byteLength, 'meta')\n // meta is a full box: its version and flags come before its children.\n const iprp = meta && findBox(view, meta.start + 4, meta.end, 'iprp')\n const ipco = iprp && findBox(view, iprp.start, iprp.end, 'ipco')\n if (!ipco) return undefined\n let largest: Dimensions | undefined\n for (const box of boxes(view, ipco.start, ipco.end)) {\n if (box.type !== 'ispe') continue\n const size = { width: view.getUint32(box.start + 4), height: view.getUint32(box.start + 8) }\n if (!largest || size.width * size.height > largest.width * largest.height) largest = size\n }\n return largest\n}\n","import type { ValidationRule } from '@orieljs/contracts'\nimport { Arr } from '@orieljs/support'\n\n/** Everything a single rule needs to validate one concrete field. */\nexport interface RuleContext {\n /** The concrete, wildcard-expanded field path, e.g. \"items.1.name\". */\n attribute: string\n /** True when `attribute` came from expanding a wildcard pattern such as \"items.*.email\". */\n expandedFromWildcard?: boolean\n value: unknown\n parameters: string[]\n data: Record<string, unknown>\n /** Every named rule attached to this field (for size-type resolution: numeric/array/file/string). */\n ruleNames: string[]\n}\n\nexport interface BuiltinRule {\n validate(ctx: RuleContext): boolean | Promise<boolean>\n /** Which DEFAULT_MESSAGES key to use, e.g. `max.${sizeType}`. Most rules return a constant name. */\n messageKey(ctx: RuleContext): string\n /** Extra :placeholder substitutions beyond :attribute (e.g. :max, :other, :values). */\n replacements?(ctx: RuleContext): Record<string, string>\n /** Used when messageKey() isn't in DEFAULT_MESSAGES (e.g. an extend()ed rule with a custom message). */\n defaultMessage?: string\n /** An extend()ed rule's own message: it wins over the default lines, as Laravel's fallback messages do. */\n message?: string\n /** Runs even when the value is missing, blank, or null under nullable (the required* family, and accepted); a failure stops the field. */\n implicit?: boolean\n}\n\nexport type ParsedRule =\n | { kind: 'named'; name: string; parameters: string[] }\n | { kind: 'object'; rule: ValidationRule }\n\nfunction splitParameters(name: string, raw: string): string[] {\n // regex/not_regex parameters are never comma-split, so a pattern containing a comma survives intact.\n return name === 'regex' || name === 'not_regex' ? [raw] : raw.split(',')\n}\n\nfunction splitOnce(value: string, separator: string): [string, string | undefined] {\n const index = value.indexOf(separator)\n return index === -1 ? [value, undefined] : [value.slice(0, index), value.slice(index + 1)]\n}\n\nexport function parseRuleSpec(spec: string | ReadonlyArray<string | ValidationRule>): ParsedRule[] {\n const items = typeof spec === 'string' ? spec.split('|') : spec\n return items\n .filter((item) => item !== '')\n .map((item): ParsedRule => {\n if (typeof item !== 'string') return { kind: 'object', rule: item }\n const [name, raw] = splitOnce(item, ':')\n return { kind: 'named', name, parameters: raw === undefined ? [] : splitParameters(name, raw) }\n })\n}\n\n/** Laravel's definition of \"empty\" for the required family: null, undefined, '' and []. false and 0 are NOT empty. */\nexport function isEmptyValue(value: unknown): boolean {\n if (value === null || value === undefined) return true\n if (typeof value === 'string') return value === ''\n if (Array.isArray(value)) return value.length === 0\n return false\n}\n\n/** Duck-types Contracts/Http's UploadedFile without importing @orieljs/http. */\nexport function isUploadedFileLike(value: unknown): value is {\n clientName: string\n mimeType: string\n size: number\n extension(): string\n arrayBuffer(): Promise<ArrayBuffer>\n} {\n return (\n typeof value === 'object' &&\n value !== null &&\n typeof (value as Record<string, unknown>).clientName === 'string' &&\n typeof (value as Record<string, unknown>).arrayBuffer === 'function'\n )\n}\n\n/**\n * Keys that must never be followed or written when walking user input: assigning through them reaches\n * Object.prototype (or a constructor) instead of a plain data slot. Mirrors the guard in Arr.set.\n */\nexport const UNSAFE_KEYS: ReadonlySet<string> = new Set(['__proto__', 'prototype', 'constructor'])\n\n/**\n * Expands a `*`-wildcard rule pattern (e.g. \"items.*.name\") into every concrete path present in `data`\n * (e.g. [\"items.0.name\", \"items.1.name\"]). A pattern with no `*` is returned unchanged. A `*` segment whose\n * container is missing, not an array and not a plain object expands to nothing for that branch (Review Focus #4:\n * every reported error is keyed by a concrete path, never the literal pattern). Object keys in UNSAFE_KEYS are\n * treated as absent, so a JSON body like {\"items\":{\"__proto__\":{...}}} never yields a path through the prototype.\n */\nexport function expandWildcardKeys(pattern: string, data: Record<string, unknown>): string[] {\n const segments = pattern.split('.')\n let paths = ['']\n for (const segment of segments) {\n const next: string[] = []\n for (const base of paths) {\n const prefix = base === '' ? '' : `${base}.`\n if (segment !== '*') {\n next.push(`${prefix}${segment}`)\n continue\n }\n const container = Arr.get<unknown>(data, base === '' ? undefined : base)\n if (Array.isArray(container)) {\n container.forEach((_, index) => next.push(`${prefix}${index}`))\n } else if (container !== null && typeof container === 'object') {\n Object.keys(container)\n .filter((key) => !UNSAFE_KEYS.has(key))\n .forEach((key) => next.push(`${prefix}${key}`))\n }\n }\n paths = next\n }\n return paths\n}\n","import { Arr } from '@orieljs/support'\nimport type { BuiltinRule, RuleContext } from '../parse'\nimport { InvalidRuleParameterError } from '../errors'\nimport { defaultAttributeName } from '../messages'\n\nconst EMAIL_RE = /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/\nconst UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i\nconst ALPHA_RE = /^[A-Za-z]+$/\nconst ALPHA_NUM_RE = /^[A-Za-z0-9]+$/\nconst ALPHA_DASH_RE = /^[A-Za-z0-9_-]+$/\nconst ACCEPTED_VALUES: unknown[] = ['yes', 'on', 1, '1', true, 'true']\n\nfunction compileRegex(raw: string): RegExp {\n const match = /^\\/(.*)\\/([a-z]*)$/.exec(raw)\n try {\n return match ? new RegExp(match[1]!, match[2]) : new RegExp(raw)\n } catch (error) {\n throw new InvalidRuleParameterError('regex', raw, error instanceof Error ? error.message : String(error))\n }\n}\n\n/**\n * Shapes a string must have before it counts as a date. Date.parse alone is far too lenient (V8 reads \"1\" as the\n * year 2001), so a value needs an ISO date, a slashed/dotted/dashed day-month-year, or a month name with a number.\n */\nconst DATE_SHAPES = [\n /^\\d{4}-\\d{1,2}-\\d{1,2}(?:[T\\s].*)?$/,\n /^\\d{1,2}[/.-]\\d{1,2}[/.-]\\d{2,4}(?:\\s.*)?$/,\n /^(?=.*\\d).*\\b(?:jan|feb|mar|apr|may|jun|jul|aug|sep|oct|nov|dec)[a-z]*\\b/i,\n]\nconst DATE_ONLY_RE = /^(\\d{4})-(\\d{2})-(\\d{2})$/\n\n/**\n * Parses a user-supplied date string to epoch milliseconds, or NaN. A bare YYYY-MM-DD means local midnight, like\n * PHP's strtotime, so it compares sensibly against `today`/`tomorrow`.\n */\nfunction parseDate(value: string): number {\n const trimmed = value.trim()\n if (!DATE_SHAPES.some((shape) => shape.test(trimmed))) return Number.NaN\n const dateOnly = DATE_ONLY_RE.exec(trimmed)\n if (dateOnly) {\n const [, y, m, d] = dateOnly.map(Number) as [number, number, number, number]\n const local = new Date(y, m - 1, d)\n return local.getMonth() === m - 1 && local.getDate() === d ? local.getTime() : Number.NaN\n }\n return Date.parse(trimmed)\n}\n\nfunction startOfDay(offsetDays: number): number {\n const date = new Date()\n date.setHours(0, 0, 0, 0)\n date.setDate(date.getDate() + offsetDays)\n return date.getTime()\n}\n\nconst RELATIVE_RE = /^([+-]\\d+)\\s*(second|minute|hour|day|week|month|year)s?$/i\n\n/** strtotime's keywords (today, tomorrow, yesterday, now) and \"+N unit\"/\"-N unit\" offsets from now, or undefined. */\nfunction relativeDate(param: string): number | undefined {\n switch (param.trim().toLowerCase()) {\n case 'now':\n return Date.now()\n case 'today':\n return startOfDay(0)\n case 'tomorrow':\n return startOfDay(1)\n case 'yesterday':\n return startOfDay(-1)\n }\n const match = RELATIVE_RE.exec(param.trim())\n if (!match) return undefined\n const amount = Number(match[1])\n const date = new Date()\n switch (match[2]!.toLowerCase()) {\n case 'second':\n date.setSeconds(date.getSeconds() + amount)\n break\n case 'minute':\n date.setMinutes(date.getMinutes() + amount)\n break\n case 'hour':\n date.setHours(date.getHours() + amount)\n break\n case 'day':\n date.setDate(date.getDate() + amount)\n break\n case 'week':\n date.setDate(date.getDate() + amount * 7)\n break\n case 'month':\n date.setMonth(date.getMonth() + amount)\n break\n case 'year':\n date.setFullYear(date.getFullYear() + amount)\n break\n }\n return date.getTime()\n}\n\n/** An attribute path such as \"starts_at\" or \"event.starts_at\". */\nconst FIELD_REFERENCE_RE = /^[A-Za-z_][\\w-]*(?:\\.[\\w-]+)*$/\n\n/**\n * Resolves a before/after parameter, in order: another field's date value, a relative keyword/offset, a literal\n * date. A parameter shaped like a field name whose field is missing or not a date gives NaN (the user's value\n * fails). Anything else that can't be parsed is a mistake in the rule itself, so it throws a 'Server' error\n * instead of blaming the user's input.\n */\nfunction resolveDateParam(rule: string, param: string, data: Record<string, unknown>): number {\n const fieldValue = Arr.get<unknown>(data, param)\n if (typeof fieldValue === 'string') {\n const parsed = parseDate(fieldValue)\n if (!Number.isNaN(parsed)) return parsed\n }\n const relative = relativeDate(param)\n if (relative !== undefined) return relative\n const literal = parseDate(param)\n if (!Number.isNaN(literal)) return literal\n if (FIELD_REFERENCE_RE.test(param)) return Number.NaN\n throw new InvalidRuleParameterError(rule, param, 'expected a date, today/tomorrow/yesterday/now, \"+N unit\", or a field name')\n}\n\nfunction compareDate(ctx: RuleContext, rule: 'before' | 'after'): boolean {\n const target = resolveDateParam(rule, ctx.parameters[0] ?? '', ctx.data)\n if (typeof ctx.value !== 'string') return false\n const value = parseDate(ctx.value)\n if (Number.isNaN(value) || Number.isNaN(target)) return false\n return rule === 'before' ? value < target : value > target\n}\n\nexport const formatRules: Record<string, BuiltinRule> = {\n email: { validate: (ctx) => typeof ctx.value === 'string' && EMAIL_RE.test(ctx.value), messageKey: () => 'email' },\n url: {\n validate: (ctx) => {\n if (typeof ctx.value !== 'string') return false\n try {\n new URL(ctx.value)\n return true\n } catch {\n return false\n }\n },\n messageKey: () => 'url',\n },\n uuid: { validate: (ctx) => typeof ctx.value === 'string' && UUID_RE.test(ctx.value), messageKey: () => 'uuid' },\n alpha: { validate: (ctx) => typeof ctx.value === 'string' && ALPHA_RE.test(ctx.value), messageKey: () => 'alpha' },\n alpha_num: {\n validate: (ctx) => typeof ctx.value === 'string' && ALPHA_NUM_RE.test(ctx.value),\n messageKey: () => 'alpha_num',\n },\n alpha_dash: {\n validate: (ctx) => typeof ctx.value === 'string' && ALPHA_DASH_RE.test(ctx.value),\n messageKey: () => 'alpha_dash',\n },\n lowercase: {\n validate: (ctx) => (typeof ctx.value === 'string' || typeof ctx.value === 'number') && String(ctx.value).toLowerCase() === String(ctx.value),\n messageKey: () => 'lowercase',\n },\n uppercase: {\n validate: (ctx) => (typeof ctx.value === 'string' || typeof ctx.value === 'number') && String(ctx.value).toUpperCase() === String(ctx.value),\n messageKey: () => 'uppercase',\n },\n regex: {\n validate: (ctx) => typeof ctx.value === 'string' && compileRegex(ctx.parameters[0] ?? '').test(ctx.value),\n messageKey: () => 'regex',\n },\n confirmed: {\n validate: (ctx: RuleContext) => ctx.value === Arr.get(ctx.data, `${ctx.attribute}_confirmation`),\n messageKey: () => 'confirmed',\n },\n same: {\n validate: (ctx) => ctx.value === Arr.get(ctx.data, ctx.parameters[0] ?? ''),\n messageKey: () => 'same',\n replacements: (ctx) => ({ other: defaultAttributeName(ctx.parameters[0] ?? '') }),\n },\n different: {\n validate: (ctx) => ctx.value !== Arr.get(ctx.data, ctx.parameters[0] ?? ''),\n messageKey: () => 'different',\n replacements: (ctx) => ({ other: defaultAttributeName(ctx.parameters[0] ?? '') }),\n },\n accepted: { implicit: true, validate: (ctx) => ACCEPTED_VALUES.includes(ctx.value), messageKey: () => 'accepted' },\n digits: {\n validate: (ctx) =>\n typeof ctx.value !== 'object' && new RegExp(`^\\\\d{${ctx.parameters[0]}}$`).test(String(ctx.value)),\n messageKey: () => 'digits',\n replacements: (ctx) => ({ digits: ctx.parameters[0] ?? '' }),\n },\n date: {\n validate: (ctx) => typeof ctx.value === 'string' && !Number.isNaN(parseDate(ctx.value)),\n messageKey: () => 'date',\n },\n before: {\n validate: (ctx) => compareDate(ctx, 'before'),\n messageKey: () => 'before',\n replacements: (ctx) => ({ date: ctx.parameters[0] ?? '' }),\n },\n after: {\n validate: (ctx) => compareDate(ctx, 'after'),\n messageKey: () => 'after',\n replacements: (ctx) => ({ date: ctx.parameters[0] ?? '' }),\n },\n}\n","import { Arr } from '@orieljs/support'\nimport type { BuiltinRule, RuleContext } from '../parse'\nimport { isEmptyValue } from '../parse'\n\nfunction isFieldPresent(field: string, data: Record<string, unknown>): boolean {\n return Arr.has(data, field) && !isEmptyValue(Arr.get(data, field))\n}\n\nfunction anyPresent(fields: string[], data: Record<string, unknown>): boolean {\n return fields.some((field) => isFieldPresent(field, data))\n}\n\nfunction allPresent(fields: string[], data: Record<string, unknown>): boolean {\n return fields.every((field) => isFieldPresent(field, data))\n}\n\nexport const presenceRules: Record<string, BuiltinRule> = {\n required: {\n implicit: true,\n validate: (ctx: RuleContext) => !isEmptyValue(ctx.value),\n messageKey: () => 'required',\n },\n required_if: {\n implicit: true,\n validate: (ctx: RuleContext) => {\n const [other, ...values] = ctx.parameters\n const applies = values.includes(String(Arr.get(ctx.data, other)))\n return !applies || !isEmptyValue(ctx.value)\n },\n messageKey: () => 'required_if',\n replacements: (ctx) => ({ other: ctx.parameters[0] ?? '', value: ctx.parameters.slice(1).join(', ') }),\n },\n required_unless: {\n implicit: true,\n validate: (ctx: RuleContext) => {\n const [other, ...values] = ctx.parameters\n const applies = !values.includes(String(Arr.get(ctx.data, other)))\n return !applies || !isEmptyValue(ctx.value)\n },\n messageKey: () => 'required_unless',\n replacements: (ctx) => ({ other: ctx.parameters[0] ?? '', values: ctx.parameters.slice(1).join(', ') }),\n },\n required_with: {\n implicit: true,\n validate: (ctx: RuleContext) => !anyPresent(ctx.parameters, ctx.data) || !isEmptyValue(ctx.value),\n messageKey: () => 'required_with',\n replacements: (ctx) => ({ values: ctx.parameters.join(' / ') }),\n },\n required_with_all: {\n implicit: true,\n validate: (ctx: RuleContext) => !allPresent(ctx.parameters, ctx.data) || !isEmptyValue(ctx.value),\n messageKey: () => 'required_with_all',\n replacements: (ctx) => ({ values: ctx.parameters.join(' / ') }),\n },\n required_without: {\n implicit: true,\n validate: (ctx: RuleContext) => ctx.parameters.every((f) => isFieldPresent(f, ctx.data)) || !isEmptyValue(ctx.value),\n messageKey: () => 'required_without',\n replacements: (ctx) => ({ values: ctx.parameters.join(' / ') }),\n },\n required_without_all: {\n implicit: true,\n validate: (ctx: RuleContext) => anyPresent(ctx.parameters, ctx.data) || !isEmptyValue(ctx.value),\n messageKey: () => 'required_without_all',\n replacements: (ctx) => ({ values: ctx.parameters.join(' / ') }),\n },\n}\n","import type { BuiltinRule } from '../parse'\n\nconst BOOLEAN_VALUES: unknown[] = [true, false, 0, 1, '0', '1']\n\n/** PHP's is_numeric for strings: optional surrounding whitespace and sign, decimal digits, optional exponent. */\nconst NUMERIC_STRING_RE = /^\\s*[+-]?(?:\\d+(?:\\.\\d*)?|\\.\\d+)(?:[eE][+-]?\\d+)?\\s*$/\n\n/**\n * Laravel's `numeric` (PHP is_numeric): a finite number, or a decimal string. Unlike `Number()`, it rejects\n * \"Infinity\", hex/binary/octal literals (\"0x1F\", \"0b101\", \"0o7\") and the empty string.\n */\nexport function isNumeric(value: unknown): boolean {\n if (typeof value === 'number') return Number.isFinite(value)\n return typeof value === 'string' && NUMERIC_STRING_RE.test(value)\n}\n\nexport const typeRules: Record<string, BuiltinRule> = {\n string: { validate: (ctx) => typeof ctx.value === 'string', messageKey: () => 'string' },\n integer: {\n validate: (ctx) => typeof ctx.value !== 'object' && /^-?\\d+$/.test(String(ctx.value).trim()),\n messageKey: () => 'integer',\n },\n numeric: {\n validate: (ctx) => isNumeric(ctx.value),\n messageKey: () => 'numeric',\n },\n boolean: { validate: (ctx) => BOOLEAN_VALUES.includes(ctx.value), messageKey: () => 'boolean' },\n array: { validate: (ctx) => Array.isArray(ctx.value), messageKey: () => 'array' },\n}\n","import type { BuiltinRule, RuleContext } from '../parse'\nimport { isUploadedFileLike } from '../parse'\nimport { isNumeric } from './type'\n\ntype SizeType = 'numeric' | 'array' | 'file' | 'string'\n\nfunction hasAny(ctx: RuleContext, names: string[]): boolean {\n return names.some((name) => ctx.ruleNames.includes(name))\n}\n\n/** A JSON object is a PHP associative array, so it's counted like one. */\nfunction isPlainObject(value: unknown): value is Record<string, unknown> {\n if (typeof value !== 'object' || value === null) return false\n const proto: unknown = Object.getPrototypeOf(value)\n return proto === Object.prototype || proto === null\n}\n\n/**\n * What a size rule measures and which message family it reports, decided in one place so the check and the\n * message always agree (Laravel's getSize + getAttributeType):\n * - numeric/integer rule: the number itself (a non-numeric value falls back to its string length, which the\n * numeric rule rejects anyway);\n * - an array (or plain object): its item count;\n * - an uploaded file: its size in fractional kilobytes;\n * - a file/image rule on something that isn't a file: NaN, so every size comparison fails;\n * - anything else: the length of its string form (a number without a numeric rule counts its digits).\n */\nfunction measure(ctx: RuleContext): { type: SizeType; size: number } {\n const { value } = ctx\n if (hasAny(ctx, ['numeric', 'integer'])) {\n return { type: 'numeric', size: isNumeric(value) ? Number(value) : stringLength(value) }\n }\n if (Array.isArray(value)) return { type: 'array', size: value.length }\n if (isUploadedFileLike(value)) return { type: 'file', size: value.size / 1024 }\n if (hasAny(ctx, ['file', 'image'])) return { type: 'file', size: Number.NaN }\n if (isPlainObject(value)) return { type: 'array', size: Object.keys(value).length }\n if (hasAny(ctx, ['array'])) return { type: 'array', size: stringLength(value) }\n return { type: 'string', size: stringLength(value) }\n}\n\nfunction stringLength(value: unknown): number {\n if (value === null || value === undefined) return 0\n return [...String(value)].length\n}\n\nfunction sizeOf(ctx: RuleContext): number {\n return measure(ctx).size\n}\n\nfunction sizeType(ctx: RuleContext): SizeType {\n return measure(ctx).type\n}\n\nexport const sizeRules: Record<string, BuiltinRule> = {\n max: {\n validate: (ctx) => sizeOf(ctx) <= Number(ctx.parameters[0]),\n messageKey: (ctx) => `max.${sizeType(ctx)}`,\n replacements: (ctx) => ({ max: ctx.parameters[0] ?? '' }),\n },\n min: {\n validate: (ctx) => sizeOf(ctx) >= Number(ctx.parameters[0]),\n messageKey: (ctx) => `min.${sizeType(ctx)}`,\n replacements: (ctx) => ({ min: ctx.parameters[0] ?? '' }),\n },\n between: {\n validate: (ctx) => {\n const size = sizeOf(ctx)\n return size >= Number(ctx.parameters[0]) && size <= Number(ctx.parameters[1])\n },\n messageKey: (ctx) => `between.${sizeType(ctx)}`,\n replacements: (ctx) => ({ min: ctx.parameters[0] ?? '', max: ctx.parameters[1] ?? '' }),\n },\n size: {\n validate: (ctx) => sizeOf(ctx) === Number(ctx.parameters[0]),\n messageKey: (ctx) => `size.${sizeType(ctx)}`,\n replacements: (ctx) => ({ size: ctx.parameters[0] ?? '' }),\n },\n in: { validate: (ctx) => ctx.parameters.includes(String(ctx.value)), messageKey: () => 'in' },\n not_in: { validate: (ctx) => !ctx.parameters.includes(String(ctx.value)), messageKey: () => 'not_in' },\n}\n","import type { BuiltinRule } from './parse'\nimport { authRules } from './rules/auth'\nimport { databaseRules } from './rules/database'\nimport { fileRules } from './rules/file'\nimport { formatRules } from './rules/format'\nimport { presenceRules } from './rules/presence'\nimport { sizeRules } from './rules/size'\nimport { typeRules } from './rules/type'\n\n/** Every built-in rule, merged. Later tasks (database rules) add their own spread here. */\nexport const builtinRules: Record<string, BuiltinRule> = {\n ...presenceRules,\n ...typeRules,\n ...formatRules,\n ...sizeRules,\n ...fileRules,\n ...databaseRules,\n ...authRules,\n}\n","import type { ValidationRule } from '@orieljs/contracts'\nimport { applyReplacements, DEFAULT_MESSAGES, defaultAttributeName } from '../messages'\n\nlet defaultRule: PasswordRule | (() => PasswordRule) | undefined\n\n/**\n * Laravel's Illuminate\\Validation\\Rules\\Password: a string of at least `min` characters (8 by default), plus the\n * checks you add: letters(), mixedCase(), numbers(), symbols(), max(). Every failing check adds its own message.\n * Rule.password() returns the application default (PasswordRule.defaults()). (Laravel's uncompromised() is not\n * ported: it calls an outside service.)\n */\nexport class PasswordRule implements ValidationRule {\n #min: number\n #max: number | undefined\n #letters = false\n #mixedCase = false\n #numbers = false\n #symbols = false\n\n constructor(min = 8) {\n this.#min = Math.max(1, min)\n }\n\n /** A password rule of at least `size` characters: PasswordRule.min(12).mixedCase(). */\n static min(size: number): PasswordRule {\n return new PasswordRule(size)\n }\n\n /**\n * With an argument, sets the default (Laravel's Password::defaults(fn () => ...), in a provider's boot());\n * `null` resets it. Without one, returns a copy of the default: PasswordRule.min(8) unless set.\n */\n static defaults(): PasswordRule\n static defaults(rule: PasswordRule | (() => PasswordRule) | null): void\n static defaults(rule?: PasswordRule | (() => PasswordRule) | null): PasswordRule | void {\n if (rule !== undefined) {\n defaultRule = rule ?? undefined\n return\n }\n const resolved = typeof defaultRule === 'function' ? defaultRule() : defaultRule\n return resolved === undefined ? new PasswordRule(8) : resolved.#copy()\n }\n\n min(size: number): this {\n this.#min = Math.max(1, size)\n return this\n }\n\n max(size: number): this {\n this.#max = size\n return this\n }\n\n /** At least one letter. */\n letters(): this {\n this.#letters = true\n return this\n }\n\n /** At least one uppercase and one lowercase letter. */\n mixedCase(): this {\n this.#mixedCase = true\n return this\n }\n\n /** At least one number. */\n numbers(): this {\n this.#numbers = true\n return this\n }\n\n /** At least one symbol (punctuation, a symbol or a space). */\n symbols(): this {\n this.#symbols = true\n return this\n }\n\n validate(attribute: string, value: unknown, fail: (message: string) => void): void {\n const name = defaultAttributeName(attribute)\n const say = (key: string, replacements: Record<string, string> = {}) =>\n fail(applyReplacements(DEFAULT_MESSAGES[key]!, { attribute: name, ...replacements }))\n if (typeof value !== 'string') return say('string')\n const length = [...value].length\n if (length < this.#min) say('min.string', { min: String(this.#min) })\n if (this.#max !== undefined && length > this.#max) say('max.string', { max: String(this.#max) })\n // Laravel's order and patterns.\n if (this.#mixedCase && !/(\\p{Ll}+.*\\p{Lu})|(\\p{Lu}+.*\\p{Ll})/u.test(value)) say('password.mixed')\n if (this.#letters && !/\\p{L}/u.test(value)) say('password.letters')\n if (this.#symbols && !/\\p{Z}|\\p{S}|\\p{P}/u.test(value)) say('password.symbols')\n if (this.#numbers && !/\\p{N}/u.test(value)) say('password.numbers')\n }\n\n #copy(): PasswordRule {\n const copy = new PasswordRule(this.#min)\n copy.#max = this.#max\n copy.#letters = this.#letters\n copy.#mixedCase = this.#mixedCase\n copy.#numbers = this.#numbers\n copy.#symbols = this.#symbols\n return copy\n }\n}\n","import type { ValidationRule } from '@orieljs/contracts'\nimport { applyReplacements, DEFAULT_MESSAGES, defaultAttributeName } from './messages'\nimport { guessColumn, matchingRecordExists } from './rules/database'\nimport { PasswordRule } from './rules/password'\n\n/**\n * Base for the fluent builders. Each one reports under a built-in rule name (`in`, `unique`, `exists`), so when it\n * runs inside a Validator its failure goes through exactly the same lookup as the string rule: custom messages\n * (\"email.unique\", \"items.*.email.unique\", \"unique\"), custom attributes, then the default text. Called directly\n * as a plain ValidationRule, validate() fails with the default English message.\n */\nexport abstract class BuiltinRuleObject implements ValidationRule {\n abstract readonly ruleName: string\n\n abstract passes(attribute: string, value: unknown, data: Record<string, unknown>, expandedFromWildcard?: boolean): boolean | Promise<boolean>\n\n // Declares all 4 contract parameters so a subclass's inferred type (from `Rule.in(...)` etc.) still accepts a\n // call with the full 4-arg ValidationRule.validate signature, as Rule.test.ts makes.\n async validate(attribute: string, value: unknown, fail: (message: string) => void, data: Record<string, unknown>, expandedFromWildcard = false): Promise<void> {\n if (await this.passes(attribute, value, data, expandedFromWildcard)) return\n fail(applyReplacements(DEFAULT_MESSAGES[this.ruleName]!, { attribute: defaultAttributeName(attribute) }))\n }\n}\n\nclass InRule extends BuiltinRuleObject {\n readonly ruleName = 'in'\n\n constructor(private readonly values: readonly unknown[]) {\n super()\n }\n\n passes(_attribute: string, value: unknown): boolean {\n return this.values.map(String).includes(String(value))\n }\n}\n\n/** Structural shape of Database's Model — duck-typed so this package never imports `@orieljs/database` (B27). */\ninterface ModelInstanceLike {\n getKey(): unknown\n getKeyName(): string\n}\n\nfunction isModelInstance(value: unknown): value is ModelInstanceLike {\n return (\n typeof value === 'object' &&\n value !== null &&\n typeof (value as ModelInstanceLike).getKey === 'function' &&\n typeof (value as ModelInstanceLike).getKeyName === 'function'\n )\n}\n\nclass UniqueRule extends BuiltinRuleObject {\n readonly ruleName = 'unique'\n private exceptId: unknown\n private idColumnName: string | undefined\n\n constructor(\n private readonly table: string,\n private readonly column?: string,\n ) {\n super()\n }\n\n /**\n * Excludes the current record from the uniqueness check. Laravel's `Rule::unique('users')->ignore($user)` accepts\n * a model directly (the common case: \"update your profile without changing your email\"), so a model instance is\n * bound by its key (`getKey()`/`getKeyName()`), not the object itself — the object would reach the query builder\n * as an opaque value and either be rejected by the driver or stringified (B27). A plain id still works as before;\n * null (or \"NULL\") excludes nothing.\n */\n ignore(id: unknown, idColumn?: string): this {\n if (isModelInstance(id)) {\n this.exceptId = id.getKey()\n this.idColumnName = idColumn ?? id.getKeyName()\n } else {\n this.exceptId = id\n this.idColumnName = idColumn ?? 'id'\n }\n return this\n }\n\n async passes(attribute: string, value: unknown, _data?: Record<string, unknown>, expandedFromWildcard = false): Promise<boolean> {\n const column = this.column ?? guessColumn(attribute, expandedFromWildcard)\n return !(await matchingRecordExists(this.table, column, value, this.exceptId, this.idColumnName ?? 'id'))\n }\n}\n\nclass ExistsRule extends BuiltinRuleObject {\n readonly ruleName = 'exists'\n\n constructor(\n private readonly table: string,\n private readonly column?: string,\n ) {\n super()\n }\n\n passes(attribute: string, value: unknown, _data?: Record<string, unknown>, expandedFromWildcard = false): Promise<boolean> {\n return matchingRecordExists(this.table, this.column ?? guessColumn(attribute, expandedFromWildcard), value)\n }\n}\n\n/** Fluent rule-object builders, for when a plain string rule can't express what's needed (e.g. .ignore()). */\nexport const Rule = {\n in: (values: readonly unknown[]): InRule => new InRule(values),\n unique: (table: string, column?: string): UniqueRule => new UniqueRule(table, column),\n exists: (table: string, column?: string): ExistsRule => new ExistsRule(table, column),\n /** Laravel's Password::defaults(): the application's password rule (at least 8 characters unless PasswordRule.defaults() changed it). */\n password: (): PasswordRule => PasswordRule.defaults(),\n}\n","import type { Rules, Validator } from '@orieljs/contracts'\nimport { Arr } from '@orieljs/support'\nimport { UnknownValidationRuleError, ValidationErrorImpl } from './errors'\nimport { MessageBagImpl } from './MessageBag'\nimport { BuiltinRuleObject } from './Rule'\nimport { applyReplacements, DEFAULT_MESSAGES, defaultAttributeName } from './messages'\nimport type { BuiltinRule, ParsedRule, RuleContext } from './parse'\nimport { expandWildcardKeys, parseRuleSpec, UNSAFE_KEYS } from './parse'\n\nconst SKIPPED_MODIFIERS = new Set(['bail', 'nullable', 'sometimes'])\n\n/**\n * Rebuilds a nested structure from flat dot-paths, the way Laravel's validated() does for wildcard fields.\n * `Arr.undot` (from @orieljs/support) always builds plain objects; it can't know \"items.0\"/\"items.1\" should\n * become an array. This walks the same way, then promotes any container it created itself whose keys are exactly\n * \"0\", \"1\", \"2\", … in order into a real array. Leaf values copied from the input (a Date, an uploaded file, an\n * object that happens to have \"0\"/\"1\" keys) are returned untouched, by identity. A path with a segment in\n * UNSAFE_KEYS is dropped, so nothing can be written through to Object.prototype. The input is never mutated.\n */\nfunction buildNested(flat: Record<string, unknown>): Record<string, unknown> {\n const root: Record<string, unknown> = {}\n const created = new Set<object>([root])\n for (const [path, value] of Object.entries(flat)) {\n const parts = path.split('.')\n if (parts.some((part) => UNSAFE_KEYS.has(part))) continue\n let current = root\n for (const part of parts.slice(0, -1)) {\n const existing = Object.hasOwn(current, part) ? current[part] : undefined\n if (typeof existing === 'object' && existing !== null && created.has(existing)) {\n current = existing as Record<string, unknown>\n continue\n }\n const container = cloneContainer(existing)\n created.add(container)\n current[part] = container\n current = container\n }\n current[parts.at(-1)!] = value\n }\n return arrayify(root, created) as Record<string, unknown>\n}\n\nfunction isPlainContainer(value: unknown): value is Record<string, unknown> {\n if (Array.isArray(value)) return true\n if (typeof value !== 'object' || value === null) return false\n const proto: unknown = Object.getPrototypeOf(value)\n return proto === Object.prototype || proto === null\n}\n\n/**\n * A fresh container to write a child path into. When a parent key was already copied from the input (rules on both\n * \"user\" and \"user.name\"), its plain contents are kept (Laravel returns the whole parent) but copied, so the input\n * is never mutated. Anything else (missing, a scalar, a class instance) starts empty.\n */\nfunction cloneContainer(existing: unknown): Record<string, unknown> {\n const container: Record<string, unknown> = {}\n if (!isPlainContainer(existing)) return container\n for (const [key, value] of Object.entries(existing)) {\n if (!UNSAFE_KEYS.has(key)) container[key] = value\n }\n return container\n}\n\nfunction arrayify(node: unknown, created: ReadonlySet<object>): unknown {\n if (node === null || typeof node !== 'object' || !created.has(node)) return node\n const entries = Object.entries(node as Record<string, unknown>).map(([k, v]) => [k, arrayify(v, created)] as const)\n const keys = entries.map(([k]) => k)\n const isArrayLike = keys.length > 0 && keys.every((k, i) => k === String(i))\n return isArrayLike ? entries.map(([, v]) => v) : Object.fromEntries(entries)\n}\n\n/**\n * Runs each field's rules the way Laravel's Validator does:\n * - a missing key, or a string that is blank after trimming, only runs implicit rules (the required* family and\n * accepted); every other rule, including ValidationRule objects, is skipped for it;\n * - an explicit null runs every rule unless the field is `nullable` (then only implicit rules run), so\n * `{ age: null }` still fails `integer`;\n * - `sometimes` skips a missing field entirely;\n * - a field stops validating after its first failure under `bail`, or after any implicit rule fails.\n */\nexport class ValidatorImpl implements Validator {\n private bag: MessageBagImpl | undefined\n private ranPromise: Promise<boolean> | undefined\n private readonly afterCallbacks: Array<(validator: Validator) => void | Promise<void>> = []\n\n constructor(\n private readonly data: Record<string, unknown>,\n private readonly rules: Rules,\n private readonly customMessages: Record<string, string>,\n private readonly customAttributes: Record<string, string>,\n private readonly registry: Record<string, BuiltinRule>,\n private readonly errorBagName = 'default',\n ) {}\n\n after(callback: (validator: Validator) => void | Promise<void>): this {\n this.afterCallbacks.push(callback)\n return this\n }\n\n /** Not part of the Validator contract — lets an after() hook add a failure (MessageBag itself is read-only). */\n fail(field: string, message: string): void {\n this.bag ??= new MessageBagImpl()\n this.bag.add(field, message)\n }\n\n async passes(): Promise<boolean> {\n this.ranPromise ??= this.run()\n return this.ranPromise\n }\n\n async fails(): Promise<boolean> {\n return !(await this.passes())\n }\n\n errors(): MessageBagImpl {\n return this.bag ?? new MessageBagImpl()\n }\n\n async validated<T = Record<string, unknown>>(): Promise<T> {\n if (!(await this.passes())) throw new ValidationErrorImpl(this.bag!.toObject(), this.errorBagName)\n const flat: Record<string, unknown> = {}\n for (const pattern of Object.keys(this.rules)) {\n for (const field of this.fieldsFor(pattern)) {\n if (Arr.has(this.data, field)) flat[field] = Arr.get(this.data, field)\n }\n }\n return buildNested(flat) as T\n }\n\n private fieldsFor(pattern: string): string[] {\n return pattern.includes('*') ? expandWildcardKeys(pattern, this.data) : [pattern]\n }\n\n private async run(): Promise<boolean> {\n this.bag = new MessageBagImpl()\n\n for (const [pattern, spec] of Object.entries(this.rules)) {\n const parsed = parseRuleSpec(spec)\n const names = parsed.filter((r): r is Extract<ParsedRule, { kind: 'named' }> => r.kind === 'named').map((r) => r.name)\n const bail = names.includes('bail')\n const nullable = names.includes('nullable')\n const sometimes = names.includes('sometimes')\n\n for (const field of this.fieldsFor(pattern)) {\n const present = Arr.has(this.data, field)\n if (sometimes && !present) continue\n\n const value = Arr.get(this.data, field)\n const isNull = value === null || value === undefined\n const isBlank = typeof value === 'string' && value.trim() === ''\n\n for (const rule of parsed) {\n if (rule.kind === 'named' && SKIPPED_MODIFIERS.has(rule.name)) continue\n const implicit = rule.kind === 'named' && (this.registry[rule.name]?.implicit ?? false)\n // Laravel's presentOrRuleIsImplicit: a missing key or a blank string only runs implicit rules.\n if (!implicit && (!present || isBlank)) continue\n // Laravel's isNotNullIfMarkedAsNullable: nullable + null only runs implicit rules.\n if (!implicit && nullable && isNull) continue\n\n const messages = await this.runRule(rule, field, pattern, value, names)\n if (messages.length > 0) {\n for (const message of messages) this.bag.add(field, message)\n // Laravel's shouldStopValidating: bail stops at the first failure; a failed implicit rule always stops.\n if (bail || implicit) break\n }\n }\n }\n }\n\n for (const callback of this.afterCallbacks) await callback(this)\n return this.bag.isEmpty()\n }\n\n private async runRule(\n rule: ParsedRule,\n field: string,\n pattern: string,\n value: unknown,\n ruleNames: string[],\n ): Promise<string[]> {\n const expanded = pattern.includes('*')\n if (rule.kind === 'object') {\n if (rule.rule instanceof BuiltinRuleObject) {\n if (await rule.rule.passes(field, value, this.data, expanded)) return []\n const ctx = { attribute: field, expandedFromWildcard: expanded, value, parameters: [], data: this.data, ruleNames }\n return [this.failureMessage(rule.rule.ruleName, this.registry[rule.rule.ruleName], ctx, pattern)]\n }\n // Every fail() call is a message, as with Laravel's invokable rules (Rule.password() reports each failed check).\n const failures: string[] = []\n await rule.rule.validate(field, value, (message) => void failures.push(message), this.data)\n return failures\n }\n\n const builtin = this.registry[rule.name]\n if (!builtin) throw new UnknownValidationRuleError(rule.name)\n\n const ctx = { attribute: field, expandedFromWildcard: expanded, value, parameters: rule.parameters, data: this.data, ruleNames }\n if (await builtin.validate(ctx)) return []\n return [this.failureMessage(rule.name, builtin, ctx, pattern)]\n }\n\n /** Custom message (concrete field, then wildcard pattern, then rule name) or the default, with :attribute filled. */\n private failureMessage(name: string, builtin: BuiltinRule | undefined, ctx: RuleContext, pattern: string): string {\n const field = ctx.attribute\n const template =\n this.customMessages[`${field}.${name}`] ??\n this.customMessages[`${pattern}.${name}`] ??\n this.customMessages[name] ??\n builtin?.message ??\n DEFAULT_MESSAGES[builtin?.messageKey(ctx) ?? name] ??\n builtin?.defaultMessage ??\n 'The :attribute field is invalid.'\n\n const display = this.customAttributes[field] ?? this.customAttributes[pattern] ?? defaultAttributeName(field)\n return applyReplacements(template, { attribute: display, ...(builtin?.replacements?.(ctx) ?? {}) })\n }\n}\n","import type { RuleCallback, Rules, ValidationFactory } from '@orieljs/contracts'\nimport type { BuiltinRule } from './parse'\nimport { builtinRules } from './registry'\nimport { ValidatorImpl } from './Validator'\n\nexport class ValidationFactoryImpl implements ValidationFactory {\n private readonly extended: Record<string, BuiltinRule> = {}\n\n make(\n data: Record<string, unknown>,\n rules: Rules,\n messages: Record<string, string> = {},\n attributes: Record<string, string> = {},\n ): ValidatorImpl {\n return new ValidatorImpl(data, rules, messages, attributes, { ...builtinRules, ...this.extended })\n }\n\n extend(name: string, callback: RuleCallback, message?: string): void {\n this.extended[name] = {\n validate: (ctx) => callback(ctx.attribute, ctx.value, ctx.parameters, ctx.data),\n messageKey: () => name,\n ...(message === undefined ? {} : { message }),\n defaultMessage: message ?? 'The :attribute field is invalid.',\n }\n }\n}\n","import type { ValidationFactory } from '@orieljs/contracts'\nimport { ValidationFactory as ValidationFactoryToken } from '@orieljs/contracts'\nimport { facade } from '@orieljs/support'\n\n/** Laravel's Validator facade: Validator.make(...)/Validator.extend(...), proxied to the resolved ValidationFactory. */\nexport const Validator = facade<ValidationFactory>(ValidationFactoryToken)\n","import { ValidationFactory as ValidationFactoryToken } from '@orieljs/contracts'\nimport { ServiceProvider } from '@orieljs/support'\nimport { ValidationFactoryImpl } from './ValidationFactory'\n\nexport class ValidationServiceProvider extends ServiceProvider {\n override register(): void {\n this.app.singleton(ValidationFactoryToken, () => new ValidationFactoryImpl())\n }\n}\n"],"mappings":"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","names":["inject","inject","Arr","Arr","Arr","Arr","Arr","Arr","ctx","ValidationFactoryToken","ValidationFactoryToken"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@orieljs/validation",
|
|
3
|
-
"version": "0.1.0-alpha.
|
|
3
|
+
"version": "0.1.0-alpha.6",
|
|
4
4
|
"description": "The Oriel Validation component.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -30,9 +30,9 @@
|
|
|
30
30
|
"NOTICE"
|
|
31
31
|
],
|
|
32
32
|
"dependencies": {
|
|
33
|
-
"@orieljs/contracts": "0.1.0-alpha.
|
|
34
|
-
"@orieljs/
|
|
35
|
-
"@orieljs/
|
|
33
|
+
"@orieljs/contracts": "0.1.0-alpha.6",
|
|
34
|
+
"@orieljs/support": "0.1.0-alpha.6",
|
|
35
|
+
"@orieljs/container": "0.1.0-alpha.6"
|
|
36
36
|
},
|
|
37
37
|
"scripts": {
|
|
38
38
|
"build": "tsup && node ../../../scripts/copy-license.mjs"
|