Skip to content

Commit 7fcbef5

Browse files
authored
feat: add nonEmptyRecord refiner (#3288)
This PR adds a new struct refiner to validate that a record is not empty.
1 parent e90f300 commit 7fcbef5

File tree

5 files changed

+53
-3
lines changed

5 files changed

+53
-3
lines changed

packages/examples/packages/browserify-plugin/snap.manifest.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
"url": "https://github.com/MetaMask/snaps.git"
88
},
99
"source": {
10-
"shasum": "2WLcpc3RXg2Up0zeSMxWS/2rsVI1bC1iHCHAhzc3DOA=",
10+
"shasum": "2XIZ9NDtR8XhO4hsAxS89GtjVkpwj/iTuHUv2P0TKYk=",
1111
"location": {
1212
"npm": {
1313
"filePath": "dist/bundle.js",

packages/examples/packages/browserify/snap.manifest.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
"url": "https://github.com/MetaMask/snaps.git"
88
},
99
"source": {
10-
"shasum": "LQYiFCEu2fQXCuzfYHVpFfqffCbzzUjaqH7kPwgBfNc=",
10+
"shasum": "4U6ZsKhhX3XQp20W7rLNWpaExEasUgcSU/+Q/UQQNns=",
1111
"location": {
1212
"npm": {
1313
"filePath": "dist/bundle.js",

packages/snaps-sdk/src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ export {
1111
enumValue,
1212
typedUnion,
1313
selectiveUnion,
14+
nonEmptyRecord,
1415
} from './internals';
1516

1617
// Re-exported from `@metamask/utils` for convenience.

packages/snaps-sdk/src/internals/structs.test.ts

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,16 @@ import {
55
object,
66
string,
77
validate,
8+
any,
89
} from '@metamask/superstruct';
910

10-
import { enumValue, literal, typedUnion, union } from './structs';
11+
import {
12+
enumValue,
13+
literal,
14+
typedUnion,
15+
union,
16+
nonEmptyRecord,
17+
} from './structs';
1118
import type { BoxElement } from '../jsx';
1219
import { Footer, Icon, Text, Button, Box } from '../jsx';
1320
import {
@@ -145,3 +152,27 @@ describe('typedUnion', () => {
145152
]);
146153
});
147154
});
155+
156+
describe('nonEmptyRecord', () => {
157+
it.each([
158+
{ foo: 'bar' },
159+
{
160+
a: {
161+
b: 'c',
162+
},
163+
},
164+
])('validates "%p"', (value) => {
165+
const struct = nonEmptyRecord(string(), any());
166+
167+
expect(is(value, struct)).toBe(true);
168+
});
169+
170+
it.each(['foo', 42, null, undefined, [], {}, [1, 2, 3]])(
171+
'does not validate "%p"',
172+
(value) => {
173+
const struct = nonEmptyRecord(string(), any());
174+
175+
expect(is(value, struct)).toBe(false);
176+
},
177+
);
178+
});

packages/snaps-sdk/src/internals/structs.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ import type { AnyStruct, Infer, InferStructTuple } from '@metamask/superstruct';
22
import {
33
Struct,
44
define,
5+
record,
6+
refine,
57
literal as superstructLiteral,
68
union as superstructUnion,
79
} from '@metamask/superstruct';
@@ -217,3 +219,19 @@ export function selectiveUnion<Selector extends (value: any) => AnyStruct>(
217219
},
218220
});
219221
}
222+
223+
/**
224+
* Refine a struct to be a non-empty record and disallows usage of arrays.
225+
*
226+
* @param Key - The struct for the record key.
227+
* @param Value - The struct for the record value.
228+
* @returns The refined struct.
229+
*/
230+
export function nonEmptyRecord<Key extends string, Value>(
231+
Key: Struct<Key>,
232+
Value: Struct<Value>,
233+
) {
234+
return refine(record(Key, Value), 'Non-empty record', (value) => {
235+
return !Array.isArray(value) && Object.keys(value).length > 0;
236+
});
237+
}

0 commit comments

Comments
 (0)