refactor: modularize validator and type declaration logic
This commit is contained in:
@@ -0,0 +1,111 @@
|
||||
import type {
|
||||
Schema,
|
||||
ReferenceSchema,
|
||||
ReverseReferenceSchema,
|
||||
UnionSchema,
|
||||
} from "./types";
|
||||
|
||||
export function schemaToTypeString(
|
||||
schema: Schema,
|
||||
resourceNames?: Map<string, string>,
|
||||
): string {
|
||||
switch (schema.type) {
|
||||
case "string":
|
||||
return "string";
|
||||
case "number":
|
||||
case "int":
|
||||
case "float":
|
||||
return "number";
|
||||
case "boolean":
|
||||
return "boolean";
|
||||
case "stringLiteral":
|
||||
return `"${schema.value}"`;
|
||||
case "union":
|
||||
return schema.members
|
||||
.map((m) => schemaToTypeString(m, resourceNames))
|
||||
.join(" | ");
|
||||
case "reference": {
|
||||
const typeName =
|
||||
resourceNames?.get(schema.tableName) ||
|
||||
schema.tableName.charAt(0).toUpperCase() + schema.tableName.slice(1);
|
||||
const baseType = schema.isArray ? `${typeName}[]` : typeName;
|
||||
return schema.isOptional ? `${baseType} | null` : baseType;
|
||||
}
|
||||
case "reverseReference": {
|
||||
const typeName =
|
||||
resourceNames?.get(schema.tableName) ||
|
||||
schema.tableName.charAt(0).toUpperCase() + schema.tableName.slice(1);
|
||||
const baseType = `${typeName}[]`;
|
||||
return schema.isOptional ? `${baseType} | null` : baseType;
|
||||
}
|
||||
case "array":
|
||||
if (schema.element.type === "tuple") {
|
||||
const tupleElements = schema.element.elements.map((el) => {
|
||||
const typeStr = schemaToTypeString(el.schema, resourceNames);
|
||||
return el.name ? `${el.name}: ${typeStr}` : typeStr;
|
||||
});
|
||||
return `[${tupleElements.join(", ")}][]`;
|
||||
}
|
||||
const elementType = schemaToTypeString(schema.element, resourceNames);
|
||||
if (schema.element.type === "union") {
|
||||
return `(${elementType})[]`;
|
||||
}
|
||||
return `${elementType}[]`;
|
||||
case "tuple":
|
||||
const tupleElements = schema.elements.map((el) => {
|
||||
const typeStr = schemaToTypeString(el.schema, resourceNames);
|
||||
return el.name ? `${el.name}: ${typeStr}` : typeStr;
|
||||
});
|
||||
return `[${tupleElements.join(", ")}]`;
|
||||
default:
|
||||
return "unknown";
|
||||
}
|
||||
}
|
||||
|
||||
export function createValidator(schema: Schema): (value: unknown) => boolean {
|
||||
return function validate(value: unknown): boolean {
|
||||
switch (schema.type) {
|
||||
case "string":
|
||||
return typeof value === "string";
|
||||
case "number":
|
||||
return typeof value === "number" && !isNaN(value);
|
||||
case "int":
|
||||
return (
|
||||
typeof value === "number" && !isNaN(value) && Number.isInteger(value)
|
||||
);
|
||||
case "float":
|
||||
return typeof value === "number" && !isNaN(value);
|
||||
case "boolean":
|
||||
return typeof value === "boolean";
|
||||
case "stringLiteral":
|
||||
return typeof value === "string" && value === schema.value;
|
||||
case "union":
|
||||
return schema.members.some((member) => createValidator(member)(value));
|
||||
case "tuple":
|
||||
if (!Array.isArray(value)) return false;
|
||||
if (value.length !== schema.elements.length) return false;
|
||||
return schema.elements.every((elementSchema, index) =>
|
||||
createValidator(elementSchema.schema)(value[index]),
|
||||
);
|
||||
case "array":
|
||||
if (!Array.isArray(value)) return false;
|
||||
return value.every((item) => createValidator(schema.element)(item));
|
||||
case "reference":
|
||||
if (schema.isOptional && value === null) return true;
|
||||
if (schema.isArray) {
|
||||
return (
|
||||
Array.isArray(value) && value.every((id) => typeof id === "string")
|
||||
);
|
||||
}
|
||||
return (
|
||||
typeof value === "string" ||
|
||||
(Array.isArray(value) && value.every((id) => typeof id === "string"))
|
||||
);
|
||||
case "reverseReference":
|
||||
if (schema.isOptional && value === null) return true;
|
||||
return Array.isArray(value);
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user