release: WRNexusJS 0.5.0

This commit is contained in:
2026-07-29 12:51:10 +05:30
parent 76c768099d
commit 6afe32f63f
456 changed files with 40879 additions and 8850 deletions
+36 -6
View File
@@ -20,7 +20,7 @@ export type RuleDescriptor =
| { kind: "integer"; message?: string };
export interface FieldDescriptor {
type: "string" | "number" | "boolean";
type: "string" | "number" | "boolean" | "unknown";
optional?: boolean;
/** Message used when a required field is empty. Defaults to "Required". */
requiredMessage?: string;
@@ -103,6 +103,14 @@ export function checkField(
desc: FieldDescriptor,
raw: unknown,
): { value: unknown; error: string | null } {
if (desc.type === "unknown") {
const empty = raw === undefined || raw === null || raw === "";
return {
value: raw,
error: empty && !desc.optional ? desc.requiredMessage || "Required" : null,
};
}
if (desc.type === "boolean") {
const value = raw === true || raw === "true" || raw === "on";
if (!desc.optional && !value) {
@@ -139,8 +147,8 @@ export function checkField(
/** A server-only refinement (a predicate that can't be serialized to the client). */
type Refinement = { fn: (value: unknown) => boolean | string; message?: string };
abstract class FieldSchema {
abstract readonly type: "string" | "number" | "boolean";
export abstract class FieldSchema {
abstract readonly type: "string" | "number" | "boolean" | "unknown";
protected _optional = false;
protected _requiredMessage?: string;
protected _label?: string;
@@ -206,7 +214,7 @@ abstract class FieldSchema {
}
}
class StringSchema extends FieldSchema {
export class StringSchema extends FieldSchema {
readonly type = "string" as const;
private _trim = false;
email(message?: string): this {
@@ -246,7 +254,7 @@ class StringSchema extends FieldSchema {
}
}
class NumberSchema extends FieldSchema {
export class NumberSchema extends FieldSchema {
readonly type = "number" as const;
integer(message?: string): this {
this.rules.push({ kind: "integer", message });
@@ -262,13 +270,34 @@ class NumberSchema extends FieldSchema {
}
}
class BooleanSchema extends FieldSchema {
export class BooleanSchema extends FieldSchema {
readonly type = "boolean" as const;
}
export class UnknownSchema extends FieldSchema {
readonly type = "unknown" as const;
}
export type AnyFieldSchema = StringSchema | NumberSchema | BooleanSchema | UnknownSchema;
export class ObjectSchema {
constructor(private readonly fields: Record<string, FieldSchema>) {}
/** Return a defensive copy of the schema fields. */
getFields(): Readonly<Record<string, FieldSchema>> {
return { ...this.fields };
}
/** Create a new schema with fields added or replaced. The original is unchanged. */
extend(fields: Record<string, FieldSchema>): ObjectSchema {
return new ObjectSchema({ ...this.fields, ...fields });
}
/** Create a new schema containing fields from both schemas. */
merge(schema: ObjectSchema): ObjectSchema {
return new ObjectSchema({ ...this.fields, ...schema.getFields() });
}
/** Validate an input object; returns coerced values + per-field errors. */
parse(input: unknown): ParseResult {
const source = (input ?? {}) as Record<string, unknown>;
@@ -309,6 +338,7 @@ export const v = {
string: () => new StringSchema(),
number: () => new NumberSchema(),
boolean: () => new BooleanSchema(),
unknown: () => new UnknownSchema(),
object: (fields: Record<string, FieldSchema>) => new ObjectSchema(fields),
};