Improve nullable, optional, and shape

This commit is contained in:
Endeavorance 2025-05-21 18:55:16 -04:00
parent 77f0afe6e3
commit fced3e7c65
3 changed files with 64 additions and 3 deletions

View file

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

View file

@ -16,7 +16,10 @@ export class ParseError extends Error {
const MismatchError = (expectedType: string, receivedValue: unknown) => {
return new ParseError(
`Expected: ${expectedType}, Received: ${typeof receivedValue} ${JSON.stringify(receivedValue)}`,
`Type Mismatch
Expected: ${expectedType}
Received: ${typeof receivedValue} (${JSON.stringify(receivedValue)})
`.trim(),
expectedType,
);
};
@ -149,7 +152,7 @@ export const Parse = {
const result = {} as { [K in keyof T]: ReturnType<T[K]> };
for (const key in parsers) {
const value = (val as Record<string, unknown>)[key] ?? undefined;
const value = (val as Record<string, unknown>)[key];
try {
// biome-ignore lint/style/noNonNullAssertion: Logically guaranteed

View file

@ -157,6 +157,56 @@ describe(Parse.shape, () => {
});
});
test("allows nullable entries", () => {
const parseThing = Parse.shape({
name: Parse.string,
another: Parse.nullable(Parse.string),
});
expect(parseThing({ name: "hello", another: null })).toEqual({
name: "hello",
another: null,
});
});
test("nullable entries can accpet undefined when configured as such", () => {
const parseThing = Parse.shape({
name: Parse.string,
another: Parse.nullable(Parse.string, true),
});
const obj = {
name: "hello",
another: undefined,
};
const result = parseThing(obj);
expect(result).toEqual({
name: "hello",
another: null,
});
});
test("optional entries can accpet null when configured as such", () => {
const parseThing = Parse.shape({
name: Parse.string,
another: Parse.optional(Parse.string, true),
});
const obj = {
name: "hello",
another: null,
};
const result = parseThing(obj);
expect(result).toEqual({
name: "hello",
another: undefined,
});
});
test("throws when a required value is missing", () => {
const parseThing = Parse.shape({
name: Parse.string,
@ -195,12 +245,20 @@ describe(Parse.optional, () => {
test("Parses undefined values", () => {
expect(Parse.optional(Parse.string)(undefined)).toBeUndefined();
});
test("Parses null values when configured", () => {
expect(Parse.optional(Parse.string, true)(null)).toBeUndefined();
});
});
describe(Parse.nullable, () => {
test("Parses null values", () => {
expect(Parse.nullable(Parse.string)(null)).toBeNull();
});
test("Parses undefined values when configured", () => {
expect(Parse.nullable(Parse.string, true)(undefined)).toBeNull();
});
});
describe(Parse.defaulted, () => {