Skip to content

Commit

Permalink
refactor: update type export (#25)
Browse files Browse the repository at this point in the history
* chore: update changeset

* refactor: rename `LooseFilterRule` to `SingleFilter`

* chore: export `FilterGroup`

* chore: add type export for filter specs

* chore: add changeset

* chore: update snapshot
  • Loading branch information
lawvs authored Jul 29, 2024
1 parent 336fe84 commit b9d3b0a
Show file tree
Hide file tree
Showing 35 changed files with 239 additions and 237 deletions.
14 changes: 13 additions & 1 deletion .changeset/giant-ties-help.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,18 @@
---
"@fn-sphere/filter": patch
"@fn-sphere/core": patch
---

`getParametersExceptFirst` now returns an array instead of a Zod tuple.

```ts
import { getParametersExceptFirst } from "@fn-sphere/core";

const schema = {
name: "test",
define: z.function().args(z.number(), z.boolean()).returns(z.void()),
implement: () => {},
};

isSameType(z.tuple(getParametersExceptFirst(schema)), z.tuple([z.boolean()]));
// true
```
5 changes: 5 additions & 0 deletions .changeset/tricky-experts-grin.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@fn-sphere/filter": patch
---

chore: add type export for filter specs
53 changes: 53 additions & 0 deletions .changeset/wild-dodos-invite.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
---
"@fn-sphere/filter": patch
"@fn-sphere/core": patch
---

Rename and export `FilterRule`

```ts
interface SingleFilter {
type: "Filter";
/**
* Field path
*
* If it's a empty array, it means the root object.
* If not provided, it means user didn't select a field.
*/
path?: FilterPath;
/**
* Filter name
*
* If not provided, it means user didn't select a filter.
*/
name?: string;
/**
* Arguments for the filter function
*/
args: unknown[];
invert?: boolean;
}

interface SingleFilter extends SingleFilterInput {
/**
* Unique id, used for tracking changes or resorting
*/
id: FilterId;
}

export interface FilterGroupInput {
type: "FilterGroup";
op: "and" | "or";
conditions: (SingleFilter | FilterGroup)[];
invert?: boolean;
}

export interface FilterGroup extends FilterGroupInput {
/**
* Unique id, used for tracking changes or resorting
*/
id: FilterId;
}

export type FilterRule = SingleFilter | FilterGroup;
```
18 changes: 9 additions & 9 deletions packages/core/src/filter.test.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { expect, test } from "vitest";
import { z } from "zod";
import { createFilterSphere } from "./filter/index.js";
import type { LooseFilterGroup } from "./filter/types.js";
import type { FilterGroup } from "./filter/types.js";
import {
genFilterId,
getParametersExceptFirst,
Expand Down Expand Up @@ -64,7 +64,7 @@ test("basic usage", () => {
type: "Filter",
path: firstField.path,
name: firstFilter.name,
arguments: [],
args: [],
});

expect(filterData).toHaveLength(1);
Expand Down Expand Up @@ -115,7 +115,7 @@ test("filter nested obj", () => {
type: "Filter" as const,
name: firstFilterSchema.name,
path: firstField.path,
arguments: [19],
args: [19],
};
expect(rule.name).toEqual("number equal");

Expand Down Expand Up @@ -155,7 +155,7 @@ test("FilterGroup usage", () => {
(i) => i.name === "string equal",
)!;

const filterGroup: LooseFilterGroup = {
const filterGroup: FilterGroup = {
id: genFilterId(),
type: "FilterGroup" as const,
op: "and" as const,
Expand All @@ -165,14 +165,14 @@ test("FilterGroup usage", () => {
type: "Filter" as const,
name: nameFilter.name,
path: nameField.path,
arguments: ["Alice"],
args: ["Alice"],
},
{
id: genFilterId(),
type: "Filter" as const,
name: ageFilter.name,
path: ageField.path,
arguments: [19],
args: [19],
},
],
};
Expand All @@ -198,7 +198,7 @@ test("FilterGroup usage", () => {
expect(filterData[0].name).toEqual("Alice");
expect(filterData[0].age).toEqual(19);

const orGroup: LooseFilterGroup = {
const orGroup: FilterGroup = {
id: genFilterId(),
type: "FilterGroup" as const,
op: "or" as const,
Expand All @@ -208,14 +208,14 @@ test("FilterGroup usage", () => {
type: "Filter" as const,
name: nameFilter.name,
path: nameField.path,
arguments: ["Bob"],
args: ["Bob"],
},
{
id: genFilterId(),
type: "Filter" as const,
name: ageFilter.name,
path: ageField.path,
arguments: [18],
args: [18],
},
],
};
Expand Down
File renamed without changes.
4 changes: 2 additions & 2 deletions packages/core/src/filter/index.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { createFilterSphere } from "./sphere.js";
import type { createFilterSphere } from "./sphere.js";

export { findFilterableFields } from "./field.js";
export { createFilterPredicate } from "./predicate.js";
export { findFilterableFields } from "./pure.js";
export { createFilterSphere } from "./sphere.js";
export { countNumberOfRules } from "./utils.js";
export { isValidRule } from "./validation.js";
Expand Down
12 changes: 5 additions & 7 deletions packages/core/src/filter/predicate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,9 @@ import { z } from "zod";
import type { FnSchema } from "../types.js";
import { unreachable } from "../utils.js";
import type {
LooseFilterGroup,
LooseFilterRule,
FilterRule,
StrictFilterGroup,
StrictFilterRule,
StrictSingleFilter,
} from "./types.js";
import { getValueAtPath } from "./utils.js";
import { getRuleFilterSchema, normalizeFilter } from "./validation.js";
Expand All @@ -19,8 +18,7 @@ type FilterPredicateOptions<T> = {
/**
* The filter rule.
*/
rule?: LooseFilterRule | LooseFilterGroup;
catch?: boolean;
rule?: FilterRule;
};

const trueFn = () => true;
Expand All @@ -30,7 +28,7 @@ const createSingleRulePredicate = <Data>({
schema,
rule,
}: FilterPredicateOptions<Data> & {
rule: StrictFilterRule;
rule: StrictSingleFilter;
}): ((data: Data) => boolean) => {
const filterSchema = getRuleFilterSchema({
rule,
Expand All @@ -50,7 +48,7 @@ const createSingleRulePredicate = <Data>({

return (data: Data): boolean => {
const target = getValueAtPath(data, rule.path);
const result = fnWithImplement(target, ...rule.arguments);
const result = fnWithImplement(target, ...rule.args);
return rule.invert ? !result : result;
};
};
Expand Down
13 changes: 4 additions & 9 deletions packages/core/src/filter/sphere.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import type { ZodType } from "zod";
import type { FnSchema } from "../types.js";
import { findFilterableFields } from "./field.js";
import { createFilterPredicate } from "./predicate.js";
import { findFilterableFields } from "./pure.js";
import type { LooseFilterGroup, LooseFilterRule } from "./types.js";
import type { FilterRule } from "./types.js";

export const createFilterSphere = <Data = unknown>(
dataSchema: ZodType<Data>,
Expand All @@ -19,20 +19,15 @@ export const createFilterSphere = <Data = unknown>(
maxDeep,
});

const getFilterPredicate = (
rule: LooseFilterRule | LooseFilterGroup,
): ((data: Data) => boolean) => {
const getFilterPredicate = (rule: FilterRule): ((data: Data) => boolean) => {
return createFilterPredicate({
schema: dataSchema,
filterList: filterFnList,
rule,
});
};

const filterData = (
data: Data[],
rule: LooseFilterRule | LooseFilterGroup,
): Data[] => {
const filterData = (data: Data[], rule: FilterRule): Data[] => {
const predicate = getFilterPredicate(rule);
return data.filter(predicate);
};
Expand Down
96 changes: 24 additions & 72 deletions packages/core/src/filter/types.ts
Original file line number Diff line number Diff line change
@@ -1,25 +1,11 @@
import type { ZodTuple, ZodType, ZodTypeAny } from "zod";
import type { ZodType } from "zod";
import type { StandardFnSchema } from "../types.js";

export type FilterPath = (string | number)[];

export type FilterRuleWrapper<T = unknown> = {
_state: FilterRule;
type: "Filter";
schema: StandardFnSchema;
/**
* Field path
*/
path: FilterPath;
requiredParameters: ZodTuple;
setInvert: (invert: boolean) => void;
isInvert: () => boolean;
getPlaceholderArguments: () => unknown[];
ready: () => boolean;
input: (...args: unknown[]) => void;
reset: () => void;
turnToGroup: (op: "and" | "or") => FilterGroup<T>;
duplicate: () => FilterRuleWrapper<T>;
export type FilterId = string & {
// Type differentiator only.
__filterId: true;
};

export type FilterField = {
Expand All @@ -31,39 +17,7 @@ export type FilterField = {
filterList: StandardFnSchema[];
};

/**
* @deprecated Use {@link FilterField}
*/
export type FilterableField<T = unknown> = {
/**
* If it's a empty array, it means the root object
*/
path: FilterPath;
fieldSchema: ZodTypeAny;
filterList: FilterRuleWrapper<T>[];
};

export type FilterId = string & { __filterId: true };

/**
* @deprecated
*/
export type FilterGroup<T = unknown> = {
/**
* Unique id, used for tracking changes or resorting
*/
id: FilterId;
type: "FilterGroup";
op: "and" | "or";
conditions: (FilterRuleWrapper<T> | FilterGroup<T>)[];
invert?: boolean;
};

export type LooseFilterRule = {
/**
* Unique id, used for tracking changes or resorting
*/
id: FilterId;
export interface SingleFilterInput {
type: "Filter";
/**
* Field path
Expand All @@ -81,45 +35,43 @@ export type LooseFilterRule = {
/**
* Arguments for the filter function
*/
arguments: unknown[];
args: unknown[];
invert?: boolean;
};
}

export type LooseFilterGroup = {
export interface SingleFilter extends SingleFilterInput {
/**
* Unique id, used for tracking changes or resorting
*/
id: FilterId;
}

export interface FilterGroupInput {
type: "FilterGroup";
op: "and" | "or";
conditions: (LooseFilterRule | LooseFilterGroup)[];
conditions: (SingleFilter | FilterGroup)[];
invert?: boolean;
};

/**
* @deprecated
*/
export type FilterRule = Required<LooseFilterRule>;
}

export type StrictFilterRule = Readonly<FilterRule>;
export type StrictFilterGroup = Readonly<{
export interface FilterGroup extends FilterGroupInput {
/**
* Unique id, used for tracking changes or resorting
*/
id: FilterId;
type: "FilterGroup";
op: "and" | "or";
conditions: (StrictFilterRule | StrictFilterGroup)[];
invert: boolean;
}>;
}

export type SerializedGroup = {
export type FilterRule = SingleFilter | FilterGroup;

export type StrictSingleFilter = Readonly<Required<SingleFilter>>;
export type StrictFilterGroup = Readonly<{
/**
* Unique id, used for tracking changes or resorting
*/
id: FilterId;
type: "FilterGroup";
op: "and" | "or";
conditions: (SerializedGroup | FilterRule)[];
invert?: boolean;
};
conditions: StrictFilterRule[];
invert: boolean;
}>;

export type StrictFilterRule = StrictSingleFilter | StrictFilterGroup;
Loading

0 comments on commit b9d3b0a

Please sign in to comment.