Skip to content

Commit

Permalink
fixup! WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
ezzatron committed Mar 24, 2024
1 parent c136dbf commit acd6423
Show file tree
Hide file tree
Showing 2 changed files with 91 additions and 5 deletions.
21 changes: 17 additions & 4 deletions src/declaration/enumeration.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
import type {
Constraint,
DeclarationConstraintOptions,
} from "../constraint.js";
import {
Declaration,
Options as DeclarationOptions,
Expand All @@ -22,7 +26,9 @@ export type Member<T> = {
readonly description: string;
};

export type Options<T> = DeclarationOptions<T> & DeclarationExampleOptions<T>;
export type Options<T> = DeclarationOptions<T> &
DeclarationConstraintOptions<T> &
DeclarationExampleOptions<T>;

export function enumeration<T, O extends Options<T>>(
name: string,
Expand All @@ -33,7 +39,7 @@ export function enumeration<T, O extends Options<T>>(
const { examples, isSensitive = false } = options;

const def = defaultFromOptions(options);
const schema = createSchema(name, members);
const schema = createSchema(name, members, options);

const v = registerVariable({
name,
Expand All @@ -56,7 +62,11 @@ export function enumeration<T, O extends Options<T>>(
};
}

function createSchema<T>(name: string, members: Members<T>): EnumSchema<T> {
function createSchema<T>(
name: string,
members: Members<T>,
options: Options<T>,
): EnumSchema<T> {
const entries = Object.entries(members);

if (entries.length < 2) throw new InsufficientMembersError(name);
Expand All @@ -81,7 +91,10 @@ function createSchema<T>(name: string, members: Members<T>): EnumSchema<T> {
throw new InvalidEnumError(members);
}

return createEnum(schemaMembers, marshal, unmarshal, []);
const { constraints: explicitConstraints = [] } = options;
const constraints: Constraint<T>[] = [...explicitConstraints];

return createEnum(schemaMembers, marshal, unmarshal, constraints);
}

function buildExamples<T>(members: Members<T>): Example<T>[] {
Expand Down
75 changes: 74 additions & 1 deletion test/suite/declaration/enumeration.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ describe("Enumeration declarations", () => {
},
} as const;

let declaration: Declaration<number, Options<number>>;
let declaration: Declaration<0 | 1 | 2, Options<0 | 1 | 2>>;

describe("when no options are supplied", () => {
beforeEach(() => {
Expand Down Expand Up @@ -268,4 +268,77 @@ describe("Enumeration declarations", () => {
);
});
});

describe("when the declaration has constraints", () => {
beforeEach(() => {
declaration = enumeration(
"AUSTENITE_ENUMERATION",
"<description>",
members,
{
constraints: [
{
description: "<constraint A>",
constrain: (v) => [0, 1].includes(v) || "value must be 0 or 1",
},
{
description: "<constraint B>",
constrain: (v) => [1, 2].includes(v) || "value must be 1 or 2",
},
],
examples: [{ value: 1, label: "example" }],
},
);
});

describe("when the value satisfies the constraints", () => {
beforeEach(() => {
process.env.AUSTENITE_ENUMERATION = "<member-1>";

initialize({ onInvalid: noop });
});

describe(".value()", () => {
it("returns the value", () => {
expect(declaration.value()).toBe(1);
});
});
});

describe("when the value violates the first constraint", () => {
beforeEach(() => {
process.env.AUSTENITE_ENUMERATION = "<member-2>";

initialize({ onInvalid: noop });
});

describe(".value()", () => {
it("throws", () => {
expect(() => {
declaration.value();
}).toThrow(
"value of AUSTENITE_ENUMERATION ('<member-2>') is invalid: value must be 0 or 1",
);
});
});
});

describe("when the value violates the second constraint", () => {
beforeEach(() => {
process.env.AUSTENITE_ENUMERATION = "<member-0>";

initialize({ onInvalid: noop });
});

describe(".value()", () => {
it("throws", () => {
expect(() => {
declaration.value();
}).toThrow(
"value of AUSTENITE_ENUMERATION ('<member-0>') is invalid: value must be 1 or 2",
);
});
});
});
});
});

0 comments on commit acd6423

Please sign in to comment.