Add recordOf

This commit is contained in:
Endeavorance 2025-05-22 14:26:11 -04:00
parent fced3e7c65
commit 03b0949d39
3 changed files with 55 additions and 1 deletions

View file

@ -1,6 +1,6 @@
{ {
"name": "@endeavorance/parsec", "name": "@endeavorance/parsec",
"version": "0.6.1", "version": "0.7.0",
"author": "Endeavorance", "author": "Endeavorance",
"type": "module", "type": "module",
"module": "dist/index.js", "module": "dist/index.js",

View file

@ -261,4 +261,38 @@ export const Parse = {
throw MismatchError(shapeName, value); throw MismatchError(shapeName, value);
}; };
}, },
recordOf<K extends string, V>(
keyParser: Parser<K>,
valueParser: Parser<V>,
shapeName = "Record",
) {
return (value: unknown): Record<K, V> => {
if (value === null || typeof value !== "object") {
throw new ParseError("Record value must be an object", shapeName);
}
for (const [key, val] of Object.entries(value)) {
try {
keyParser(key);
} catch (error) {
if (error instanceof ParseError) {
error.path += `${shapeName}["${key}"] (key)`;
}
throw error;
}
try {
valueParser(val);
} catch (error) {
if (error instanceof ParseError) {
error.path += `${shapeName}["${key}"] (value)`;
}
throw error;
}
}
return value as Record<K, V>;
};
},
} as const; } as const;

View file

@ -319,3 +319,23 @@ describe(Parse.oneOf, () => {
} }
}); });
}); });
describe(Parse.recordOf, () => {
test("Parses records of a specific type", () => {
const stringToString = Parse.recordOf(Parse.string, Parse.string);
const rec = {
key: "value",
another: "another",
};
const badRec = {
key: "value",
another: 1,
};
expect(stringToString(rec)).toEqual(rec);
expect(() => stringToString(badRec)).toThrow(ParseError);
});
});