Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@
"ts-adt": "^2.1.2",
"winston": "^3.11.0",
"yaml": "^2.3.4",
"yargs": "^17.7.2"
"yargs": "^17.7.2",
"zod": "^3.25.67"
}
}
11 changes: 11 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 7 additions & 0 deletions src/resources/schema/url.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { z } from "zod";
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of hard-coding the schemas using Zod, I'd suggest we leave it as JSON Schema and convert it at build/test time to the respective library.

For example, you should be able to use this for Zod.
https://www.npmjs.com/package/json-schema-to-zod

In the future, we may also want to do something similar to Python Pydantic
https://github.com/richard-gyiko/json-schema-to-pydantic


export const urlSchema = z.object({
url: z.string().url(),
});

export type URL = z.infer<typeof urlSchema>;
41 changes: 39 additions & 2 deletions src/validator/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,18 @@ import Ajv from "ajv";
import addFormats from "ajv-formats";
import projectSchema from "../resources/schema/project.json" with { type: "json" };
import collectionSchema from "../resources/schema/collection.json" with { type: "json" };
import urlSchema from "../resources/schema/url.json" with { type: "json" };
//import urlSchema from "../resources/schema/url.json" with { type: "json" };
import socialProfileSchema from "../resources/schema/social-profile.json" with { type: "json" };
import blockchainAddressSchema from "../resources/schema/blockchain-address.json" with { type: "json" };
import { Project } from "../types/project.js";
import { Collection } from "../types/collection.js";
import { URL } from "../types/url.js";
//import { URL } from "../types/url.js";
import { URL, urlSchema } from "../resources/schema/url.js";
import { SocialProfile } from "../types/social-profile.js";
import { BlockchainAddress } from "../types/blockchain-address.js";
import { DEFAULT_FORMAT, FileFormat } from "../types/files.js";
import { readFileParse } from "../utils/files.js";
import { z } from "zod";

// Initialize Ajv
type Schema =
Expand All @@ -20,6 +22,11 @@ type Schema =
| "url.json"
| "social-profile.json"
| "blockchain-address.json";
type SchemaZod = "url.json";
const schemaMap = {
"url.json": urlSchema,
} as const;
type SchemaMap = typeof schemaMap;
const PROJECT_SCHEMA: Schema = "project.json";
const COLLECTION_SCHEMA: Schema = "collection.json";
const URL_SCHEMA: Schema = "url.json";
Expand Down Expand Up @@ -69,6 +76,36 @@ function validateObject<T>(obj: any, schemaName: Schema): ValidationResult {
return { valid: true, errors: {} };
}

function validateObjectZod<T extends SchemaZod>(
obj: unknown,
schemaName: T,
): ValidationResult {
const schema = schemaMap[schemaName];

if (!schema) {
return { valid: false, errors: { schema: "Schema not found" } };
}

const result = schema.safeParse(obj);

if (result.success) {
return { valid: true, errors: {} };
}

const errors: Record<string, string> = {};
const formatted = result.error.format();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks like formatted errors are deprecated?
https://zod.dev/error-formatting?id=zformaterror

I also don't think this is necessary
You can just get a list of issues
https://zod.dev/basics?id=handling-errors

for (const [key, value] of Object.entries(formatted)) {
if (key === "_errors") continue;

if (value && typeof value === "object" && "_errors" in value) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This still looks wrong, I don't think we should be unsafely casting as a ZodFormattedError and directly accessing _errors. Can you check the Zod documentation and please use the typed accessors?

const fieldErrors = (value as z.ZodFormattedError<any, string>)._errors;
errors[key] = fieldErrors.join(", ");
}
}

return { valid: false, errors };
}

function safeCastObject<T>(obj: any, schemaName: Schema): T {
const result = validateObject<T>(obj, schemaName);
if (!result.valid) {
Expand Down