diff --git a/package.json b/package.json index 02d22a26c..b075541a9 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@snapshot-labs/snapshot.js", - "version": "0.9.9", + "version": "0.10.0", "repository": "snapshot-labs/snapshot.js", "license": "MIT", "main": "dist/snapshot.cjs.js", diff --git a/src/schemas/space.json b/src/schemas/space.json index 9721b7957..c96bf9e90 100644 --- a/src/schemas/space.json +++ b/src/schemas/space.json @@ -103,7 +103,11 @@ "strategies": { "type": "array", "minItems": 1, - "maxItems": 8, + "maxItemsWithSpaceType": { + "default": 8, + "turbo": 10 + }, + "uniqueItems": true, "items": { "type": "object", "properties": { diff --git a/src/utils.ts b/src/utils.ts index 5f142d86f..e4002df77 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -113,6 +113,28 @@ ajv.addKeyword({ errors: true }); +ajv.addKeyword({ + keyword: 'maxItemsWithSpaceType', + validate: function validate(schema, data) { + // @ts-ignore + const spaceType = this.spaceType || 'default'; + const isValid = data.length <= schema[spaceType]; + if (!isValid) { + // @ts-ignore + validate.errors = [ + { + keyword: 'maxItemsWithSpaceType', + message: `must NOT have more than ${schema[spaceType]} items`, + params: { limit: schema[spaceType] } + } + ]; + } + return isValid; + }, + errors: true +}); + + // Custom URL format to allow empty string values // https://github.com/snapshot-labs/snapshot.js/pull/541/files ajv.addFormat('customUrl', { diff --git a/test/examples/space-maxItemsWithSpaceType-error.json b/test/examples/space-maxItemsWithSpaceType-error.json new file mode 100644 index 000000000..9c1307668 --- /dev/null +++ b/test/examples/space-maxItemsWithSpaceType-error.json @@ -0,0 +1,11 @@ +[ + { + "instancePath": "/strategies", + "keyword": "maxItemsWithSpaceType", + "message": "must NOT have more than 8 items", + "params": { + "limit": 8 + }, + "schemaPath": "#/properties/strategies/maxItemsWithSpaceType" + } +] diff --git a/test/examples/space-turbo.json b/test/examples/space-turbo.json new file mode 100644 index 000000000..425ad9e46 --- /dev/null +++ b/test/examples/space-turbo.json @@ -0,0 +1,95 @@ +{ + "name": "Loot Owners", + "skin": "indexed", + "about": "", + "admins": [ + "0xF296178d553C8Ec21A2fBD2c5dDa8CA9ac905A00" + ], + "avatar": "https://pbs.twimg.com/profile_images/1431587138202701826/lpgblc4h_400x400.jpg", + "github": "lootproject", + "symbol": "LOOT", + "filters": { + "minScore": 1, + "onlyMembers": false + }, + "members": [], + "network": "1", + "plugins": {}, + "twitter": "lootproject", + "strategies": [ + { + "name": "erc721", + "params": { + "symbol": "LOOT", + "address": "0xff9c1b15b16263c61d017ee9f65c50e4ae0113d7" + } + }, + { + "name": "erc721", + "params": { + "symbol": "LOOT", + "address": "0x0e42acBD23FAee03249DAFF896b78d7e79fBD58E" + } + }, + { + "name": "erc721", + "params": { + "symbol": "LOOT", + "address": "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48" + } + }, + { + "name": "erc721", + "params": { + "symbol": "LOOT", + "address": "0x6c3f90f043a72fa612cbac8115ee7e52bde6e490" + } + }, + { + "name": "erc721", + "params": { + "symbol": "LOOT", + "address": "0x1f9840a85d5af5bf1d1762f925bdaddc4201f984" + } + }, + { + "name": "erc721", + "params": { + "symbol": "LOOT", + "address": "0x7fc66500c84a76ad7e9c93437bfc5ac33e2ddae9" + } + }, + { + "name": "erc721", + "params": { + "symbol": "LOOT", + "address": "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2" + } + }, + { + "name": "erc721", + "params": { + "symbol": "LOOT", + "address": "0x2260fac5e5542a773aa44fbcfedf7c193bc2c599" + } + }, + { + "name": "erc721", + "params": { + "symbol": "LOOT", + "address": "0xbbbbca6a901c926f240b89eacb641d8aec7aeafd" + } + }, + { + "name": "erc721", + "params": { + "symbol": "LOOT", + "address": "0xc011a73ee8576fb46f5e1c5751ca3b9fe0af2a6f" + } + } + ], + "validation": { + "name": "basic", + "params": {} + } +} diff --git a/test/schema.spec.ts b/test/schema.spec.ts index 10e76de15..5abd6a0e5 100644 --- a/test/schema.spec.ts +++ b/test/schema.spec.ts @@ -2,6 +2,7 @@ import { test, expect, describe } from 'vitest'; import { validateSchema } from '../src/utils'; import space from './examples/space.json'; import proposal from './examples/proposal.json'; +import spaceTurbo from './examples/space-turbo.json'; import proposalTurbo from './examples/proposal-turbo.json'; import vote from './examples/vote.json'; import profile from './examples/profile.json'; @@ -9,6 +10,8 @@ import statement from './examples/statement.json'; import alias from './examples/alias.json'; import schemas from '../src/schemas'; import proposalMaxLengthWithSpaceTypeError from './examples/proposal-maxLengthWithSpaceType-error.json'; +import spaceMaxItemsWithSpaceTypeError from './examples/space-maxItemsWithSpaceType-error.json'; + describe.each([ { schemaType: 'space', schema: schemas.space, example: space }, @@ -30,7 +33,7 @@ describe.each([ // Tests for turbo spaces describe.each([ - { schemaType: 'space', schema: schemas.space, example: space }, + { schemaType: 'space', schema: schemas.space, example: spaceTurbo }, { schemaType: 'proposal', schema: schemas.proposal, example: proposalTurbo } ])(`Run validate for turbo spaces`, ({ schemaType, schema, example }) => { test(`validating schema ${schemaType} should return true`, () => { @@ -43,7 +46,12 @@ describe.each([ }); describe.each([ - // { schemaType: 'space', schema: schemas.space, example: space }, + { + schemaType: 'space', + schema: schemas.space, + example: spaceTurbo, + error: spaceMaxItemsWithSpaceTypeError + }, { schemaType: 'proposal', schema: schemas.proposal,