Skip to content

Commit

Permalink
refactor: migrate isCompatibleType to the new rule style (#9)
Browse files Browse the repository at this point in the history
  • Loading branch information
lawvs committed May 7, 2024
1 parent a003d8c commit b40d479
Show file tree
Hide file tree
Showing 7 changed files with 523 additions and 443 deletions.
7 changes: 7 additions & 0 deletions .changeset/smooth-mugs-boil.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
"zod-compare": minor
---

refactor: redesign isCompatibleType with new rule style

The function `createIsSameTypeFn` has been renamed to `createCompareFn`.
47 changes: 37 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Zod Compare
# ⚖️ Zod Compare

[![Build](https://github.com/lawvs/zod-compare/actions/workflows/build.yml/badge.svg)](https://github.com/lawvs/zod-compare/actions/workflows/build.yml)
[![npm](https://img.shields.io/npm/v/zod-compare)](https://www.npmjs.com/package/zod-compare)
Expand Down Expand Up @@ -45,26 +45,27 @@ isCompatibleType(

### Custom Rules

You can use `createIsSameTypeFn` to create a custom comparison function.
You can use `createCompareFn` to create a custom comparison function.

```ts
import {
createIsSameTypeFn,
createCompareFn,
isSameTypePresetRules,
defineCompareRule,
} from "zod-compare";

const customRule = defineCompareRule(
"custom rule",
"compare description",
(a, b, next, recheck, context) => {
// If the schemas are not having the same description, return false
if (a.description !== b.description) {
return false;
}
return next();
},
);

const customIsSameType = createIsSameTypeFn([
const strictIsSameType = createCompareFn([
customRule,
...isSameTypePresetRules,
]);
Expand All @@ -84,6 +85,7 @@ isSameType(
context,
);

// type stacks = { name: string; target: [a: ZodType, b: ZodType]; }[]
console.log(context.stacks);
```

Expand All @@ -100,31 +102,56 @@ If there is a necessity to compare these types, custom rules can be established
Compares two Zod schemas and returns `true` if they are the same.

```ts
const isSameType: (a: ZodType, b: ZodType, context?: CompareContext) => boolean;
import { isSameType } from "zod-compare";

type isSameType: (a: ZodType, b: ZodType, context?: CompareContext) => boolean;
```

### `createIsSameTypeFn`
### `createCompareFn`

Creates a custom comparison function.

```ts
const defineCompareRule: (
import { createCompareFn, defineCompareRule } from "zod-compare";

type defineCompareRule = (
name: string,
rule: CompareFn,
) => {
name: string;
rule: CompareFn;
};

const createIsSameTypeFn: (rules: CompareRule[]) => typeof isSameType;
type createCompareFn = (rules: CompareRule[]) => typeof isSameType;

// Example
const isSameType = createCompareFn(isSameTypePresetRules);
const isCompatibleType = createCompareFn(isCompatibleTypePresetRules);
```

### `isCompatibleType` (Experimental API)

Compares two Zod schemas and returns `true` if they are compatible.

```ts
function isCompatibleType(a: ZodType, b: ZodType): boolean;
import { isCompatibleType } from "zod-compare";
// The `higherType` should be a looser type
// The `lowerType` should be a stricter type
type isCompatibleType: (higherType: ZodType, lowerType: ZodType) => boolean;
```

### Preset Rules

You can use the preset rules `isSameTypePresetRules` and `isCompatibleTypePresetRules` to create custom comparison functions.

```ts
import { isSameTypePresetRules, isCompatibleTypePresetRules } from "zod-compare";

type isSameTypePresetRules: CompareRule[];
type isCompatibleTypePresetRules: CompareRule[];

// Example
const yourIsSameType = createCompareFn([customRule, ...isSameTypePresetRules]);
```

### Types
Expand Down
45 changes: 45 additions & 0 deletions src/create-compare-fn.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import type { ZodType } from "zod";
import { type CompareContext, type CompareRule } from "./types.ts";

export const createCompareFn = (rules: CompareRule[]) => {
const isSameTypeFn = (
a: ZodType,
b: ZodType,
context: CompareContext = {},
): boolean => {
let prevIndex = -1;
const runner = (index: number): boolean => {
if (index === rules.length) {
throw new Error("Failed to compare type! " + a + " " + b);
}
if (index === prevIndex) {
throw new Error("next() called multiple times");
}
prevIndex = index;
const rule = rules[index];

if ("stacks" in context && Array.isArray(context.stacks)) {
context.stacks.push({
name: rule.name,
target: [a, b],
});
}

return rule.compare(
a,
b,
() => runner(index + 1),
(a, b) => isSameTypeFn(a, b, context),
context,
);
};

return runner(0);
};
return isSameTypeFn;
};

/**
* @deprecated Use {@link createCompareFn} instead.
*/
export const createIsSameTypeFn = createCompareFn;
10 changes: 7 additions & 3 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
export { isCompatibleType } from "./is-compatible-type.ts";
export { createIsSameTypeFn, isSameType } from "./is-same-type.ts";
export { defineCompareRule, isSameTypePresetRules } from "./rules.ts";
export { createCompareFn, createIsSameTypeFn } from "./create-compare-fn.ts";
export {
isCompatibleType,
isCompatibleTypePresetRules,
} from "./is-compatible-type.ts";
export { isSameType, isSameTypePresetRules } from "./is-same-type.ts";
export { defineCompareRule } from "./rules.ts";
export type * from "./types.ts";

0 comments on commit b40d479

Please sign in to comment.