Skip to content

Commit 7e16d00

Browse files
authored
Merge pull request #25 from hypercerts-org/feat/geojson_support_metadata
Support for geoJSON in metadata
2 parents 76367c7 + f205913 commit 7e16d00

20 files changed

+1077
-136
lines changed

Diff for: eslint.config.mjs

+14-11
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
1-
import globals from "globals";
2-
import pluginJs from "@eslint/js";
3-
import tseslint from "typescript-eslint";
4-
5-
6-
export default [
7-
{ files: ["**/*.{js,mjs,cjs,ts}"] },
8-
{ languageOptions: { globals: { ...globals.browser, ...globals.node } } },
9-
pluginJs.configs.recommended,
10-
...tseslint.configs.recommended,
11-
];
1+
export default {
2+
root: true,
3+
env: {
4+
browser: true,
5+
node: true,
6+
},
7+
extends: ["eslint:recommended", "plugin:@typescript-eslint/recommended", "plugin:chai-friendly/recommended"],
8+
parser: "@typescript-eslint/parser",
9+
plugins: ["@typescript-eslint", "chai-friendly"],
10+
rules: {
11+
"no-unused-expressions": "off",
12+
"chai-friendly/no-unused-expressions": "error",
13+
},
14+
};

Diff for: package.json

+2-1
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@
5252
"esbuild": "^0.19.8",
5353
"eslint": "^9.18.0",
5454
"eslint-config-prettier": "^9.1.0",
55+
"eslint-plugin-chai-friendly": "^1.0.1",
5556
"globals": "^15.14.0",
5657
"husky": "^9.1.7",
5758
"json-schema-to-typescript": "^13.1.1",
@@ -83,7 +84,7 @@
8384
"commitlint": "commitlint --config commitlintrc.ts --edit"
8485
},
8586
"lint-staged": {
86-
"*.{js, jsx,ts,tsx}": [
87+
"*.{js,jsx,ts,tsx}": [
8788
"eslint --quiet --fix"
8889
],
8990
"*.{json,js,ts,jsx,tsx,html}": [

Diff for: pnpm-lock.yaml

+13
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Diff for: src/resources/schema/metadata.json

+18-6
Original file line numberDiff line numberDiff line change
@@ -36,14 +36,26 @@
3636
"type": "array",
3737
"items": {
3838
"type": "object",
39-
"properties": {
40-
"trait_type": {
41-
"type": "string"
39+
"oneOf": [
40+
{
41+
"properties": {
42+
"trait_type": { "type": "string" },
43+
"value": { "type": "string" }
44+
},
45+
"required": ["trait_type", "value"],
46+
"additionalProperties": false
4247
},
43-
"value": {
44-
"type": "string"
48+
{
49+
"properties": {
50+
"trait_type": { "type": "string" },
51+
"type": { "type": "string" },
52+
"src": { "type": "string" },
53+
"name": { "type": "string" }
54+
},
55+
"required": ["trait_type", "type", "src", "name"],
56+
"additionalProperties": false
4557
}
46-
}
58+
]
4759
}
4860
},
4961
"hypercert": {

Diff for: src/types/metadata.d.ts

+12-5
Original file line numberDiff line numberDiff line change
@@ -37,11 +37,18 @@ export interface HypercertMetadata {
3737
* A CID pointer to the merke tree proof json on ipfs
3838
*/
3939
allowList?: string;
40-
properties?: {
41-
trait_type?: string;
42-
value?: string;
43-
[k: string]: unknown;
44-
}[];
40+
properties?: (
41+
| {
42+
trait_type: string;
43+
value: string;
44+
}
45+
| {
46+
trait_type: string;
47+
type: string;
48+
src: string;
49+
name: string;
50+
}
51+
)[];
4552
hypercert?: HypercertClaimdata;
4653
}
4754
/**

Diff for: src/validator/ValidatorFactory.ts

+29
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import { HypercertMetadata, HypercertClaimdata, AllowlistEntry } from "src/types";
2+
import { IValidator } from "./interfaces";
3+
import { MerkleProofData, MerkleProofValidator } from "./validators/MerkleProofValidator";
4+
import { MetadataValidator, ClaimDataValidator } from "./validators/MetadataValidator";
5+
import { AllowlistValidator } from "./validators/AllowListValidator";
6+
import { AllowlistValidationParams } from "./validators/AllowListValidator";
7+
import { PropertyValidator, PropertyValue } from "./validators/PropertyValidator";
8+
9+
export class ValidatorFactory {
10+
static createMetadataValidator(): IValidator<HypercertMetadata> {
11+
return new MetadataValidator();
12+
}
13+
14+
static createClaimDataValidator(): IValidator<HypercertClaimdata> {
15+
return new ClaimDataValidator();
16+
}
17+
18+
static createAllowlistValidator(): IValidator<AllowlistEntry[], AllowlistValidationParams> {
19+
return new AllowlistValidator();
20+
}
21+
22+
static createMerkleProofValidator(): IValidator<MerkleProofData> {
23+
return new MerkleProofValidator();
24+
}
25+
26+
static createPropertyValidator(): IValidator<PropertyValue> {
27+
return new PropertyValidator();
28+
}
29+
}

Diff for: src/validator/base/SchemaValidator.ts

+40
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
import Ajv, { Schema, ErrorObject } from "ajv";
2+
import { IValidator, ValidationError, ValidationResult } from "../interfaces";
3+
4+
export abstract class SchemaValidator<T> implements IValidator<T> {
5+
protected ajv: Ajv;
6+
protected schema: Schema;
7+
8+
constructor(schema: Schema, additionalSchemas: Schema[] = []) {
9+
this.ajv = new Ajv({ allErrors: true });
10+
// Add any additional schemas first
11+
additionalSchemas.forEach((schema) => this.ajv.addSchema(schema));
12+
this.schema = schema;
13+
}
14+
15+
validate(data: unknown): ValidationResult<T> {
16+
const validate = this.ajv.compile(this.schema);
17+
18+
if (!validate(data)) {
19+
return {
20+
isValid: false,
21+
errors: this.formatErrors(validate.errors || []),
22+
};
23+
}
24+
25+
return {
26+
isValid: true,
27+
data: data as T,
28+
errors: [],
29+
};
30+
}
31+
32+
protected formatErrors(errors: ErrorObject[]): ValidationError[] {
33+
return errors.map((error) => ({
34+
code: "SCHEMA_VALIDATION_ERROR",
35+
message: error.message || "Unknown validation error",
36+
field: error.instancePath || (error.params.missingProperty as string) || "",
37+
details: error.params,
38+
}));
39+
}
40+
}

0 commit comments

Comments
 (0)