Skip to content

Commit

Permalink
feat(unique): add validator for unique item
Browse files Browse the repository at this point in the history
  • Loading branch information
TomokiMiyauci committed May 23, 2023
1 parent de6059a commit 0d34889
Show file tree
Hide file tree
Showing 3 changed files with 49 additions and 0 deletions.
2 changes: 2 additions & 0 deletions combinator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { PatternValidator } from "./validators/string/pattern.ts";
import { CountValidator } from "./validators/iterable/count.ts";
import { EmptyValidator } from "./validators/iterable/empty.ts";
import { ItemValidator } from "./validators/iterable/item.ts";
import { UniqueValidator } from "./validators/iterable/unique.ts";
import { MaxCountValidator } from "./validators/iterable/max_count.ts";
import { MinCountValidator } from "./validators/iterable/min_count.ts";
import { NonEmptyValidator } from "./validators/iterable/non_empty.ts";
Expand Down Expand Up @@ -43,6 +44,7 @@ export const item = /* @__PURE__ */ lazy(ItemValidator);
export const maxCount = /* @__PURE__ */ lazy(MaxCountValidator);
export const minCount = /* @__PURE__ */ lazy(MinCountValidator);
export const nonEmpty = /* @__PURE__ */ new NonEmptyValidator();
export const unique = /* @__PURE__ */ new UniqueValidator();

// number
export const int = /* @__PURE__ */ new IntegerValidator();
Expand Down
1 change: 1 addition & 0 deletions mod.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,5 +24,6 @@ export {
positive,
string,
type,
unique,
validDate,
} from "./combinator.ts";
46 changes: 46 additions & 0 deletions validators/iterable/unique.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
// Copyright 2023-latest Tomoki Miyauchi. All rights reserved. MIT license.
// This module is browser compatible.

import { enumerate } from "../../iter_utils.ts";
import { display, interpolate } from "../../utils.ts";
import { Reporter, ValidationError, Validator } from "../../types.ts";
import error from "../error.json" assert { type: "json" };

interface Context {
input: Iterable<unknown>;
index: number;
item: unknown;
}

@display("unique")
export class UniqueValidator extends Reporter<Context>
implements Validator<Iterable<unknown>> {
constructor() {
super();
super.expect(({ item }) => interpolate(error.unique, [item]));
}
*validate(input: Iterable<unknown>): Iterable<ValidationError> {
for (const [index, item] of duplicates(input)) {
yield new ValidationError(
this.report({ input, item, index }),
{
instancePath: [index.toString()],
},
);
}
}
}

function* duplicates<T>(
iterable: Iterable<T>,
): Iterable<[index: number, item: T]> {
const seen = new Set<T>();

for (const [i, item] of enumerate(iterable)) {
if (seen.has(item)) {
yield [i, item];
} else {
seen.add(item);
}
}
}

0 comments on commit 0d34889

Please sign in to comment.