old version placed

This commit is contained in:
2024-12-31 12:22:36 +03:00
parent 08b7ad5c00
commit 00acc8c320
93 changed files with 7481 additions and 1 deletions

View File

@@ -0,0 +1,78 @@
"use client";
import * as z from "zod";
import { ZodDecimal } from "./zodDecimal";
function convertApiValidationToZodValidation(apiValidation: any) {
let zodValidation: any = {};
Object.entries(apiValidation).forEach(([key, value]: any) => {
const fieldType: String = value.fieldType || "string";
const required = value.required || false;
if (fieldType === "string") {
zodValidation[key] = required
? z
.string()
.min(1)
.refine((val) => val !== "" || val !== null)
: z
.string()
.min(1)
.optional()
.refine((val) => val !== "" || val !== null);
} else if (fieldType === "integer") {
zodValidation[key] = required
? z.preprocess((value) => {
try {
const parsedValue = Number(value);
return isNaN(parsedValue) ? undefined : parsedValue;
} catch (error) {
return undefined;
}
}, z.number().min(1))
: z.preprocess((value) => {
try {
const parsedValue = Number(value);
return isNaN(parsedValue) ? undefined : parsedValue;
} catch (error) {
return undefined;
}
}, z.number().min(1).optional());
} else if (fieldType === "boolean") {
zodValidation[key] = required ? z.boolean() : z.boolean().optional();
} else if (fieldType === "datetime") {
zodValidation[key] = required ? z.date() : z.date().optional();
} else if (fieldType === "float") {
zodValidation[key] = required
? ZodDecimal.create({ coerce: true })
: ZodDecimal.create({ coerce: true }).optional();
}
});
const validSchemaZod = z.object({
...zodValidation,
});
return {
validSchemaZod: validSchemaZod,
zodValidation: zodValidation,
apiValidation: apiValidation,
};
}
function retrieveDataWhichHaveValidation(data: any, apiValidation: any) {
const apiValidated = apiValidation?.validated || {};
Object.entries(apiValidated).forEach(([key, value]: any) => {
const fieldType: String = value.fieldType || "string";
const required = value.required || false;
if (fieldType === "string") {
data[key] = required ? data[key] : data[key] || "";
} else if (fieldType === "integer") {
data[key] = required ? data[key] : data[key] || 0;
} else if (fieldType === "boolean") {
data[key] = required ? data[key] : data[key] || false;
} else if (fieldType === "datetime") {
data[key] = required ? data[key] : new Date(data[key]) || "";
} else if (fieldType === "float") {
data[key] = required ? data[key] : data[key] || 0.0;
}
});
}
export { convertApiValidationToZodValidation, retrieveDataWhichHaveValidation };

6
src/lib/utils.ts Normal file
View File

@@ -0,0 +1,6 @@
import { clsx, type ClassValue } from "clsx"
import { twMerge } from "tailwind-merge"
export function cn(...inputs: ClassValue[]) {
return twMerge(clsx(inputs))
}

306
src/lib/zodDecimal.ts Normal file
View File

@@ -0,0 +1,306 @@
import {
INVALID,
ParseContext,
ParseInput,
ParseReturnType,
ParseStatus,
RawCreateParams,
ZodIssueCode,
ZodParsedType,
ZodType,
ZodTypeDef,
addIssueToContext,
} from "zod";
export type ZodDecimalCheck =
| { kind: "precision"; value: number; message?: string }
| { kind: "wholeNumber"; value: number; message?: string }
| { kind: "min"; value: number; inclusive: boolean; message?: string }
| { kind: "max"; value: number; inclusive: boolean; message?: string }
| { kind: "finite"; message?: string };
const zodDecimalKind = "ZodDecimal";
export interface ZodDecimalDef extends ZodTypeDef {
checks: ZodDecimalCheck[];
typeName: typeof zodDecimalKind;
coerce: boolean;
}
const precisionRegex = /(?:\.(\d+))?(?:[eE]([+-]?\d+))?$/;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
export class ZodDecimal extends ZodType<number, ZodDecimalDef, any> {
// eslint-disable-next-line @typescript-eslint/naming-convention
_parse(input: ParseInput): ParseReturnType<number> {
// detect decimal js object
if (
input.data !== null &&
typeof input.data === "object" &&
"toNumber" in input.data
) {
input.data = input.data.toNumber();
}
if (this._def.coerce) {
input.data = Number(input.data);
}
const parsedType = this._getType(input);
if (parsedType !== ZodParsedType.number) {
const ctx = this._getOrReturnCtx(input);
addIssueToContext(ctx, {
code: ZodIssueCode.invalid_type,
expected: ZodParsedType.number,
received: ctx.parsedType,
});
return INVALID;
}
let ctx: undefined | ParseContext = undefined;
const status = new ParseStatus();
for (const check of this._def.checks) {
if (check.kind === "precision") {
const parts = input.data.toString().match(precisionRegex);
const decimals = Math.max(
(parts[1] ? parts[1].length : 0) -
(parts[2] ? parseInt(parts[2], 10) : 0),
0
);
if (decimals > check.value) {
ctx = this._getOrReturnCtx(input, ctx);
addIssueToContext(ctx, {
code: ZodIssueCode.custom,
message: check.message,
params: {
precision: check.value,
},
});
status.dirty();
}
} else if (check.kind === "wholeNumber") {
const wholeNumber = input.data.toString().split(".")[0];
const tooLong = wholeNumber.length > check.value;
if (tooLong) {
ctx = this._getOrReturnCtx(input, ctx);
addIssueToContext(ctx, {
code: ZodIssueCode.custom,
message: check.message,
params: {
wholeNumber: check.value,
},
});
status.dirty();
}
} else if (check.kind === "min") {
const tooSmall = check.inclusive
? input.data < check.value
: input.data <= check.value;
if (tooSmall) {
ctx = this._getOrReturnCtx(input, ctx);
addIssueToContext(ctx, {
code: ZodIssueCode.too_small,
minimum: check.value,
type: "number",
inclusive: check.inclusive,
exact: false,
message: check.message,
});
status.dirty();
}
} else if (check.kind === "max") {
const tooBig = check.inclusive
? input.data > check.value
: input.data >= check.value;
if (tooBig) {
ctx = this._getOrReturnCtx(input, ctx);
addIssueToContext(ctx, {
code: ZodIssueCode.too_big,
maximum: check.value,
type: "number",
inclusive: check.inclusive,
exact: false,
message: check.message,
});
status.dirty();
}
} else if (check.kind === "finite") {
if (!Number.isFinite(input.data)) {
ctx = this._getOrReturnCtx(input, ctx);
addIssueToContext(ctx, {
code: ZodIssueCode.not_finite,
message: check.message,
});
status.dirty();
}
}
}
return { status: status.value, value: input.data };
}
static create = (
params?: RawCreateParams & { coerce?: true }
): ZodDecimal => {
return new ZodDecimal({
checks: [],
typeName: zodDecimalKind,
coerce: params?.coerce ?? false,
});
};
protected setLimit(
kind: "min" | "max",
value: number,
inclusive: boolean,
message?: string
): ZodDecimal {
return new ZodDecimal({
...this._def,
checks: [
...this._def.checks,
{
kind,
value,
inclusive,
message,
},
],
});
}
_addCheck(check: ZodDecimalCheck): ZodDecimal {
return new ZodDecimal({
...this._def,
checks: [...this._def.checks, check],
});
}
lte(value: number, message?: string): ZodDecimal {
return this.setLimit("max", value, true, message);
}
lt(value: number, message?: string): ZodDecimal {
return this.setLimit("max", value, false, message);
}
max = this.lte;
gt(value: number, message?: string): ZodDecimal {
return this.setLimit("min", value, false, message);
}
gte(value: number, message?: string): ZodDecimal {
return this.setLimit("min", value, true, message);
}
min = this.gte;
precision(value: number, message?: string): ZodDecimal {
return this._addCheck({
kind: "precision",
value,
message,
});
}
wholeNumber(value: number, message?: string): ZodDecimal {
return this._addCheck({
kind: "wholeNumber",
value,
message,
});
}
get minValue() {
let min: number | null = null;
for (const ch of this._def.checks) {
if (ch.kind === "min") {
if (min === null || ch.value > min) min = ch.value;
}
}
return min;
}
get maxValue() {
let max: number | null = null;
for (const ch of this._def.checks) {
if (ch.kind === "max") {
if (max === null || ch.value < max) max = ch.value;
}
}
return max;
}
positive(message?: string) {
return this._addCheck({
kind: "min",
value: 0,
inclusive: false,
message,
});
}
negative(message?: string) {
return this._addCheck({
kind: "max",
value: 0,
inclusive: false,
message,
});
}
nonpositive(message?: string) {
return this._addCheck({
kind: "max",
value: 0,
inclusive: true,
message,
});
}
nonnegative(message?: string) {
return this._addCheck({
kind: "min",
value: 0,
inclusive: true,
message,
});
}
finite(message?: string) {
return this._addCheck({
kind: "finite",
message,
});
}
safe(message?: string) {
return this._addCheck({
kind: "min",
inclusive: true,
value: Number.MIN_SAFE_INTEGER,
message,
})._addCheck({
kind: "max",
inclusive: true,
value: Number.MAX_SAFE_INTEGER,
message,
});
}
get isFinite() {
let max: number | null = null,
min: number | null = null;
for (const ch of this._def.checks) {
if (ch.kind === "finite") {
return true;
} else if (ch.kind === "min") {
if (min === null || ch.value > min) min = ch.value;
} else if (ch.kind === "max") {
if (max === null || ch.value < max) max = ch.value;
}
}
return Number.isFinite(min) && Number.isFinite(max);
}
}
// eslint-disable-next-line @typescript-eslint/naming-convention
export const zodDecimal = ZodDecimal.create;