effect-app 4.0.0-beta.101 → 4.0.0-beta.103
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +10 -0
- package/dist/Operations.d.ts +31 -11
- package/dist/Operations.d.ts.map +1 -1
- package/dist/Schema.d.ts +15 -0
- package/dist/Schema.d.ts.map +1 -1
- package/dist/Schema.js +15 -2
- package/package.json +1 -1
- package/src/Schema.ts +40 -1
- package/test/schema.test.ts +73 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,15 @@
|
|
|
1
1
|
# @effect-app/prelude
|
|
2
2
|
|
|
3
|
+
## 4.0.0-beta.103
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- 7119320: Add `generateGuards` to `TaggedUnion` / `ExtendTaggedUnion` for generating property-scoped type guards.
|
|
8
|
+
|
|
9
|
+
Usage: `MyUnion.generateGuards<MyType>()("propertyKey")` returns `{ is{Tag}, isAnyOf }` guards that narrow the container type by its tagged union property.
|
|
10
|
+
|
|
11
|
+
## 4.0.0-beta.102
|
|
12
|
+
|
|
3
13
|
## 4.0.0-beta.101
|
|
4
14
|
|
|
5
15
|
## 4.0.0-beta.100
|
package/dist/Operations.d.ts
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import * as S from "./Schema.js";
|
|
2
2
|
export type OperationId = S.StringId;
|
|
3
|
-
export declare const OperationId: S.WithDefaults<S.brand<S.String, "NonEmptyString" | "
|
|
3
|
+
export declare const OperationId: S.WithDefaults<S.brand<S.String, "NonEmptyString" | "StringId" | "NonEmptyString50" | "NonEmptyString64" | "NonEmptyString80" | "NonEmptyString100" | "NonEmptyString255" | "NonEmptyString2k" | "NonEmptyString64k"> & {
|
|
4
4
|
make: () => S.StringId;
|
|
5
|
-
withDefault: S.withConstructorDefault<S.brand<S.String, "NonEmptyString" | "
|
|
6
|
-
}> & S.brand<S.String, "NonEmptyString" | "
|
|
5
|
+
withDefault: S.withConstructorDefault<S.brand<S.String, "NonEmptyString" | "StringId" | "NonEmptyString50" | "NonEmptyString64" | "NonEmptyString80" | "NonEmptyString100" | "NonEmptyString255" | "NonEmptyString2k" | "NonEmptyString64k">>;
|
|
6
|
+
}> & S.brand<S.String, "NonEmptyString" | "StringId" | "NonEmptyString50" | "NonEmptyString64" | "NonEmptyString80" | "NonEmptyString100" | "NonEmptyString255" | "NonEmptyString2k" | "NonEmptyString64k"> & {
|
|
7
7
|
make: () => S.StringId;
|
|
8
|
-
withDefault: S.withConstructorDefault<S.brand<S.String, "NonEmptyString" | "
|
|
8
|
+
withDefault: S.withConstructorDefault<S.brand<S.String, "NonEmptyString" | "StringId" | "NonEmptyString50" | "NonEmptyString64" | "NonEmptyString80" | "NonEmptyString100" | "NonEmptyString255" | "NonEmptyString2k" | "NonEmptyString64k">>;
|
|
9
9
|
};
|
|
10
10
|
declare const OperationProgress_base: S.EnhancedClass<OperationProgress, S.Struct<{
|
|
11
11
|
completed: S.WithDefaults<S.brand<import("effect/Schema").Int, "NonNegativeInt" | "Int" | "NonNegativeNumber">> & S.brand<import("effect/Schema").Int, "NonNegativeInt" | "Int" | "NonNegativeNumber"> & {
|
|
@@ -20,14 +20,14 @@ export declare class OperationProgress extends OperationProgress_base {
|
|
|
20
20
|
declare const OperationSuccess_base: S.EnhancedTaggedClass<OperationSuccess, "OperationSuccess", {
|
|
21
21
|
readonly _tag: S.tag<"OperationSuccess">;
|
|
22
22
|
} & {
|
|
23
|
-
message: S.withConstructorDefault<import("effect/Schema").NullOr<S.WithDefaults<S.brand<import("effect/Schema").NonEmptyString, "NonEmptyString" | "
|
|
23
|
+
message: S.withConstructorDefault<import("effect/Schema").NullOr<S.WithDefaults<S.brand<import("effect/Schema").NonEmptyString, "NonEmptyString" | "NonEmptyString2k" | "NonEmptyString64k">> & S.brand<import("effect/Schema").NonEmptyString, "NonEmptyString" | "NonEmptyString2k" | "NonEmptyString64k">>>;
|
|
24
24
|
}, OperationSuccess.Encoded>;
|
|
25
25
|
export declare class OperationSuccess extends OperationSuccess_base {
|
|
26
26
|
}
|
|
27
27
|
declare const OperationFailure_base: S.EnhancedTaggedClass<OperationFailure, "OperationFailure", {
|
|
28
28
|
readonly _tag: S.tag<"OperationFailure">;
|
|
29
29
|
} & {
|
|
30
|
-
message: S.withConstructorDefault<import("effect/Schema").NullOr<S.WithDefaults<S.brand<import("effect/Schema").NonEmptyString, "NonEmptyString" | "
|
|
30
|
+
message: S.withConstructorDefault<import("effect/Schema").NullOr<S.WithDefaults<S.brand<import("effect/Schema").NonEmptyString, "NonEmptyString" | "NonEmptyString2k" | "NonEmptyString64k">> & S.brand<import("effect/Schema").NonEmptyString, "NonEmptyString" | "NonEmptyString2k" | "NonEmptyString64k">>>;
|
|
31
31
|
}, OperationFailure.Encoded>;
|
|
32
32
|
export declare class OperationFailure extends OperationFailure_base {
|
|
33
33
|
}
|
|
@@ -57,17 +57,27 @@ export declare const OperationResult: S.Union<[typeof OperationSuccess, typeof O
|
|
|
57
57
|
};
|
|
58
58
|
} & {
|
|
59
59
|
readonly tags: import("effect/Schema").Literals<["OperationSuccess", "OperationFailure"]>;
|
|
60
|
+
readonly generateGuards: <A>() => <K extends { [K_1 in keyof A & string]: A[K_1] extends OperationSuccess | OperationFailure ? K_1 : never; }[keyof A & string]>(property: K) => {
|
|
61
|
+
readonly isOperationSuccess: (target: A) => target is A & { readonly [P in K]: OperationSuccess; };
|
|
62
|
+
readonly isOperationFailure: (target: A) => target is A & { readonly [P in K]: OperationFailure; };
|
|
63
|
+
} & {
|
|
64
|
+
readonly isAnyOf: <const Tags extends readonly ("OperationSuccess" | "OperationFailure")[]>(tags: Tags) => (target: A) => target is A & { readonly [P in K]: Extract<OperationSuccess, {
|
|
65
|
+
readonly _tag: Tags[number];
|
|
66
|
+
}> | Extract<OperationFailure, {
|
|
67
|
+
readonly _tag: Tags[number];
|
|
68
|
+
}>; };
|
|
69
|
+
};
|
|
60
70
|
};
|
|
61
71
|
export type OperationResult = S.Schema.Type<typeof OperationResult>;
|
|
62
72
|
declare const Operation_base: S.EnhancedClass<Operation, S.Struct<{
|
|
63
|
-
id: S.WithDefaults<S.brand<S.String, "NonEmptyString" | "
|
|
73
|
+
id: S.WithDefaults<S.brand<S.String, "NonEmptyString" | "StringId" | "NonEmptyString50" | "NonEmptyString64" | "NonEmptyString80" | "NonEmptyString100" | "NonEmptyString255" | "NonEmptyString2k" | "NonEmptyString64k"> & {
|
|
64
74
|
make: () => S.StringId;
|
|
65
|
-
withDefault: S.withConstructorDefault<S.brand<S.String, "NonEmptyString" | "
|
|
66
|
-
}> & S.brand<S.String, "NonEmptyString" | "
|
|
75
|
+
withDefault: S.withConstructorDefault<S.brand<S.String, "NonEmptyString" | "StringId" | "NonEmptyString50" | "NonEmptyString64" | "NonEmptyString80" | "NonEmptyString100" | "NonEmptyString255" | "NonEmptyString2k" | "NonEmptyString64k">>;
|
|
76
|
+
}> & S.brand<S.String, "NonEmptyString" | "StringId" | "NonEmptyString50" | "NonEmptyString64" | "NonEmptyString80" | "NonEmptyString100" | "NonEmptyString255" | "NonEmptyString2k" | "NonEmptyString64k"> & {
|
|
67
77
|
make: () => S.StringId;
|
|
68
|
-
withDefault: S.withConstructorDefault<S.brand<S.String, "NonEmptyString" | "
|
|
78
|
+
withDefault: S.withConstructorDefault<S.brand<S.String, "NonEmptyString" | "StringId" | "NonEmptyString50" | "NonEmptyString64" | "NonEmptyString80" | "NonEmptyString100" | "NonEmptyString255" | "NonEmptyString2k" | "NonEmptyString64k">>;
|
|
69
79
|
};
|
|
70
|
-
title: S.WithDefaults<S.brand<import("effect/Schema").NonEmptyString, "NonEmptyString" | "
|
|
80
|
+
title: S.WithDefaults<S.brand<import("effect/Schema").NonEmptyString, "NonEmptyString" | "NonEmptyString2k" | "NonEmptyString64k">> & S.brand<import("effect/Schema").NonEmptyString, "NonEmptyString" | "NonEmptyString2k" | "NonEmptyString64k">;
|
|
71
81
|
progress: S.optional<typeof OperationProgress>;
|
|
72
82
|
result: S.optional<S.Union<[typeof OperationSuccess, typeof OperationFailure]> & {
|
|
73
83
|
readonly cases: {
|
|
@@ -95,6 +105,16 @@ declare const Operation_base: S.EnhancedClass<Operation, S.Struct<{
|
|
|
95
105
|
};
|
|
96
106
|
} & {
|
|
97
107
|
readonly tags: import("effect/Schema").Literals<["OperationSuccess", "OperationFailure"]>;
|
|
108
|
+
readonly generateGuards: <A>() => <K extends { [K_1 in keyof A & string]: A[K_1] extends OperationSuccess | OperationFailure ? K_1 : never; }[keyof A & string]>(property: K) => {
|
|
109
|
+
readonly isOperationSuccess: (target: A) => target is A & { readonly [P in K]: OperationSuccess; };
|
|
110
|
+
readonly isOperationFailure: (target: A) => target is A & { readonly [P in K]: OperationFailure; };
|
|
111
|
+
} & {
|
|
112
|
+
readonly isAnyOf: <const Tags extends readonly ("OperationSuccess" | "OperationFailure")[]>(tags: Tags) => (target: A) => target is A & { readonly [P in K]: Extract<OperationSuccess, {
|
|
113
|
+
readonly _tag: Tags[number];
|
|
114
|
+
}> | Extract<OperationFailure, {
|
|
115
|
+
readonly _tag: Tags[number];
|
|
116
|
+
}>; };
|
|
117
|
+
};
|
|
98
118
|
}>;
|
|
99
119
|
createdAt: S.withConstructorDefault<S.DateFromString>;
|
|
100
120
|
updatedAt: S.withConstructorDefault<import("effect/Schema").NullOr<S.DateFromString & {
|
package/dist/Operations.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Operations.d.ts","sourceRoot":"","sources":["../src/Operations.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,CAAC,MAAM,aAAa,CAAA;AAEhC,MAAM,MAAM,WAAW,GAAG,CAAC,CAAC,QAAQ,CAAA;AACpC,eAAO,MAAM,WAAW;;;;;;CAAa,CAAA;;;;;;;;;AAErC,qBAAa,iBAAkB,SAAQ,sBAMrC;CAAG;;;;;;AAEL,qBAAa,gBACX,SAAQ,qBAEN;CACF;;;;;;AAEF,qBAAa,gBACX,SAAQ,qBAEN;CACF;AAEF,eAAO,MAAM,eAAe
|
|
1
|
+
{"version":3,"file":"Operations.d.ts","sourceRoot":"","sources":["../src/Operations.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,CAAC,MAAM,aAAa,CAAA;AAEhC,MAAM,MAAM,WAAW,GAAG,CAAC,CAAC,QAAQ,CAAA;AACpC,eAAO,MAAM,WAAW;;;;;;CAAa,CAAA;;;;;;;;;AAErC,qBAAa,iBAAkB,SAAQ,sBAMrC;CAAG;;;;;;AAEL,qBAAa,gBACX,SAAQ,qBAEN;CACF;;;;;;AAEF,qBAAa,gBACX,SAAQ,qBAEN;CACF;AAEF,eAAO,MAAM,eAAe;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAAoD,CAAA;AAChF,MAAM,MAAM,eAAe,GAAG,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,eAAe,CAAC,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAEnE,qBAAa,SAAU,SAAQ,cAO7B;CAAG;AAKL,yBAAiB,iBAAiB,CAAC;IACjC,UAAiB,OAAQ,SAAQ,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,OAAO,iBAAiB,CAAC,QAAQ,CAAC,CAAC;KAAG;CACzF;AACD,yBAAiB,gBAAgB,CAAC;IAChC,UAAiB,OAAQ,SAAQ,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,OAAO,gBAAgB,CAAC,QAAQ,CAAC,CAAC;KAAG;CACxF;AACD,yBAAiB,gBAAgB,CAAC;IAChC,UAAiB,OAAQ,SAAQ,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,OAAO,gBAAgB,CAAC,QAAQ,CAAC,CAAC;KAAG;CACxF;AACD,yBAAiB,SAAS,CAAC;IACzB,UAAiB,OAAQ,SAAQ,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,OAAO,SAAS,CAAC,QAAQ,CAAC,CAAC;KAAG;CACjF"}
|
package/dist/Schema.d.ts
CHANGED
|
@@ -44,8 +44,23 @@ type TaggedUnionMembers = NonEmptyReadonlyArray<S.Top & {
|
|
|
44
44
|
type TaggedUnionTags<Members extends TaggedUnionMembers> = S.Literals<{
|
|
45
45
|
[Index in keyof Members]: Members[Index]["Type"]["_tag"];
|
|
46
46
|
}>;
|
|
47
|
+
type TaggedPropertyKeys<A, Members extends TaggedUnionMembers> = {
|
|
48
|
+
[K in keyof A & string]: A[K] extends Members[number]["Type"] ? K : never;
|
|
49
|
+
}[keyof A & string];
|
|
50
|
+
type PropertyGuards<Members extends TaggedUnionMembers, K extends string, A> = {
|
|
51
|
+
readonly [M in Members[number] as `is${M["Type"]["_tag"]}`]: (target: A) => target is A & {
|
|
52
|
+
readonly [P in K]: M["Type"];
|
|
53
|
+
};
|
|
54
|
+
} & {
|
|
55
|
+
readonly isAnyOf: <const Tags extends ReadonlyArray<Members[number]["Type"]["_tag"]>>(tags: Tags) => (target: A) => target is A & {
|
|
56
|
+
readonly [P in K]: Extract<Members[number]["Type"], {
|
|
57
|
+
readonly _tag: Tags[number];
|
|
58
|
+
}>;
|
|
59
|
+
};
|
|
60
|
+
};
|
|
47
61
|
type TaggedUnionWithTags<Members extends TaggedUnionMembers> = S.toTaggedUnion<"_tag", Members> & {
|
|
48
62
|
readonly tags: TaggedUnionTags<Members>;
|
|
63
|
+
readonly generateGuards: <A>() => <K extends TaggedPropertyKeys<A, Members>>(property: K) => PropertyGuards<Members, K, A>;
|
|
49
64
|
};
|
|
50
65
|
export declare const ExtendTaggedUnion: <Members extends TaggedUnionMembers>(schema: S.Union<Members>) => TaggedUnionWithTags<Members>;
|
|
51
66
|
export declare const TaggedUnion: <Members extends TaggedUnionMembers>(...a: Members) => TaggedUnionWithTags<Members>;
|
package/dist/Schema.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Schema.d.ts","sourceRoot":"","sources":["../src/Schema.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"Schema.d.ts","sourceRoot":"","sources":["../src/Schema.ts"],"names":[],"mappings":"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"}
|
package/dist/Schema.js
CHANGED
|
@@ -71,7 +71,20 @@ function collectSentinelsFromAST(ast) {
|
|
|
71
71
|
}
|
|
72
72
|
}
|
|
73
73
|
export const tags = (self) => S.Literals(self.map(getTagFromAST));
|
|
74
|
-
const extendTaggedUnionWithTags = (schema) => extendM(schema.pipe(S.toTaggedUnion("_tag")), () => ({
|
|
74
|
+
const extendTaggedUnionWithTags = (schema) => extendM(schema.pipe(S.toTaggedUnion("_tag")), (tagged) => ({
|
|
75
|
+
tags: tags(schema.members),
|
|
76
|
+
generateGuards: () => (property) => {
|
|
77
|
+
const result = {};
|
|
78
|
+
for (const [tag, guard] of Object.entries(tagged.guards)) {
|
|
79
|
+
result[`is${tag}`] = (target) => guard(target[property]);
|
|
80
|
+
}
|
|
81
|
+
result.isAnyOf = (memberTags) => {
|
|
82
|
+
const check = tagged.isAnyOf(memberTags);
|
|
83
|
+
return (target) => check(target[property]);
|
|
84
|
+
};
|
|
85
|
+
return result;
|
|
86
|
+
}
|
|
87
|
+
}));
|
|
75
88
|
export const ExtendTaggedUnion = (schema) => extendTaggedUnionWithTags(schema);
|
|
76
89
|
export const TaggedUnion = (...a) => extendTaggedUnionWithTags(S.Union(a));
|
|
77
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
90
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiU2NoZW1hLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vc3JjL1NjaGVtYS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsU0FBUyxFQUFlLE1BQU0sUUFBUSxDQUFBO0FBQy9DLE9BQU8sS0FBSyxDQUFDLE1BQU0sZUFBZSxDQUFBO0FBRWxDLE9BQU8sRUFBRSxRQUFRLEVBQUUsTUFBTSxZQUFZLENBQUE7QUFDckMsT0FBTyxFQUFFLEtBQUssSUFBSSxNQUFNLEVBQTJCLE1BQU0sbUJBQW1CLENBQUE7QUFDNUUsT0FBTyxFQUFFLGVBQWUsRUFBRSxNQUFNLGlCQUFpQixDQUFBO0FBQ2pELE9BQU8sRUFBRSxXQUFXLElBQUksWUFBWSxFQUF1QyxNQUFNLHlCQUF5QixDQUFBO0FBQzFHLE9BQU8sRUFBRSxPQUFPLEVBQUUsTUFBTSxZQUFZLENBQUE7QUFFcEMsY0FBYyxlQUFlLENBQUE7QUFFN0IsY0FBYyxtQkFBbUIsQ0FBQTtBQUNqQyxPQUFPLEVBQUUsS0FBSyxFQUFFLFdBQVcsRUFBRSxNQUFNLG1CQUFtQixDQUFBO0FBRXRELE9BQU8sRUFBRSxTQUFTLEVBQUUsT0FBTyxFQUFFLE1BQU0sbUJBQW1CLENBQUE7QUFDdEQsT0FBTyxFQUFFLEtBQUssRUFBRSxPQUFPLEVBQUUsSUFBSSxFQUFFLGNBQWMsRUFBRSxTQUFTLEVBQUUsTUFBTSxFQUFFLFFBQVEsRUFBRSxNQUFNLEVBQUUsTUFBTSxFQUFFLFdBQVcsRUFBRSxXQUFXLEVBQUUsTUFBTSxpQkFBaUIsQ0FBQTtBQUM3SSxPQUFPLEVBQUUsR0FBRyxFQUFFLGNBQWMsRUFBRSxNQUFNLHFCQUFxQixDQUFBO0FBRXpELGNBQWMsbUJBQW1CLENBQUE7QUFDakMsY0FBYyxpQkFBaUIsQ0FBQTtBQUMvQixjQUFjLHlCQUF5QixDQUFBO0FBQ3ZDLGNBQWMscUJBQXFCLENBQUE7QUFDbkMsY0FBYyx5QkFBeUIsQ0FBQTtBQUN2QyxjQUFjLG9CQUFvQixDQUFBO0FBQ2xDLGNBQWMsK0JBQStCLENBQUE7QUFDN0MsY0FBYyw0QkFBNEIsQ0FBQTtBQUMxQyxjQUFjLHFCQUFxQixDQUFBO0FBQ25DLE9BQU8sRUFBRSxjQUFjLEVBQUUsTUFBTSxxQkFBcUIsQ0FBQTtBQUVwRCxPQUFPLEtBQUssV0FBVyxNQUFNLG9CQUFvQixDQUFBO0FBQ2pELE9BQU8sS0FBSyxZQUFZLE1BQU0scUJBQXFCLENBQUE7QUFFbkQsT0FBTyxFQUFFLElBQUksSUFBSSxLQUFLLEVBQUUsTUFBTSxlQUFlLENBQUE7QUFFN0MsTUFBTSxDQUFDLE1BQU0sTUFBTSxHQUFHLE1BQU0sRUFBRSxDQUFBO0FBTzlCLE1BQU0sU0FBUyxHQUFHLENBQUMsQ0FBQyxVQUFVLENBQUMsTUFBYSxDQUFpQyxDQUFBO0FBQzdFLE1BQU0sZUFBZSxHQUFHLENBQUMsQ0FBQyxVQUFVLENBQUMsWUFBbUIsQ0FBdUMsQ0FBQTtBQUUvRixNQUFNLENBQUMsTUFBTSxLQUFLLEdBQUcsTUFBTTtLQUN4QixJQUFJLENBQ0gsQ0FBQyxDQUFDLFFBQVEsQ0FBQztJQUNULDZEQUE2RDtJQUM3RCxXQUFXLEVBQUUsR0FBRyxFQUFFLENBQUMsQ0FBQyxFQUFFLEVBQUUsRUFBRSxDQUFDLFFBQVEsQ0FBQyxDQUFDLEtBQUssRUFBRSxFQUFFLENBQUMsS0FBSyxDQUFDLFFBQVEsQ0FBQyxZQUFZLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxHQUFHLENBQUMsU0FBUyxDQUFDO0NBQy9GLENBQUMsRUFDRixlQUFlLENBQ2hCLENBQUE7QUFJSCxNQUFNLENBQUMsTUFBTSxXQUFXLEdBQUcsWUFBWTtLQUNwQyxJQUFJLENBQ0gsQ0FBQyxDQUFDLFFBQVEsQ0FBQztJQUNULFdBQVcsRUFBRSxHQUFHLEVBQUUsQ0FBQyxDQUFDLEVBQUUsRUFBRSxFQUFFO0lBQ3hCLDZEQUE2RDtJQUM3RCxRQUFRLENBQUMsQ0FBQyxLQUFLLEVBQUUsRUFBRSxDQUFDLEtBQUssQ0FBQyxLQUFLLENBQUMsTUFBTSxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsR0FBRyxDQUFDLGVBQWUsQ0FBQztDQUNuRSxDQUFDLEVBQ0YsZUFBZSxDQUNoQixDQUFBO0FBSUgsdUVBQXVFO0FBQ3ZFLDJFQUEyRTtBQUMzRSxNQUFNLGFBQWEsR0FBRyxDQUFDLE1BQWEsRUFBVSxFQUFFO0lBQzlDLE1BQU0sU0FBUyxHQUFHLHVCQUF1QixDQUFDLE1BQU0sQ0FBQyxHQUFHLENBQUMsQ0FBQTtJQUNyRCxNQUFNLFFBQVEsR0FBRyxTQUFTLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxDQUFDLENBQUMsR0FBRyxLQUFLLE1BQU0sQ0FBQyxDQUFBO0lBQ3hELElBQUksUUFBUSxLQUFLLFNBQVMsSUFBSSxPQUFPLFFBQVEsQ0FBQyxPQUFPLEtBQUssUUFBUTtRQUFFLE9BQU8sUUFBUSxDQUFDLE9BQU8sQ0FBQTtJQUMzRixNQUFNLElBQUksS0FBSyxDQUFDLHdDQUF3QyxDQUFDLENBQUE7QUFDM0QsQ0FBQyxDQUFBO0FBRUQsU0FBUyx1QkFBdUIsQ0FDOUIsR0FBa0I7SUFFbEIsUUFBUSxHQUFHLENBQUMsSUFBSSxFQUFFLENBQUM7UUFDakIsS0FBSyxhQUFhLENBQUMsQ0FBQyxDQUFDO1lBQ25CLE1BQU0sQ0FBQyxHQUFHLEdBQUcsQ0FBQyxXQUFXLEVBQUUsQ0FBQyxZQUFZLENBQUMsQ0FBQTtZQUN6QyxPQUFPLEtBQUssQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFBO1FBQ2xDLENBQUM7UUFDRCxLQUFLLFNBQVM7WUFDWixPQUFPLEdBQUcsQ0FBQyxrQkFBa0IsQ0FBQyxPQUFPLENBQ25DLENBQUMsRUFBRSxFQUF5RSxFQUFFO2dCQUM1RSxNQUFNLElBQUksR0FBRyxFQUFFLENBQUMsSUFBSSxDQUFBO2dCQUNwQixJQUFJLENBQUMsU0FBUyxDQUFDLFVBQVUsQ0FBQyxJQUFJLENBQUMsRUFBRSxDQUFDO29CQUNoQyxJQUFJLFNBQVMsQ0FBQyxTQUFTLENBQUMsSUFBSSxDQUFDO3dCQUFFLE9BQU8sQ0FBQyxFQUFFLEdBQUcsRUFBRSxFQUFFLENBQUMsSUFBSSxFQUFFLE9BQU8sRUFBRSxJQUFJLENBQUMsT0FBTyxFQUFFLENBQUMsQ0FBQTtvQkFDL0UsSUFBSSxTQUFTLENBQUMsY0FBYyxDQUFDLElBQUksQ0FBQzt3QkFBRSxPQUFPLENBQUMsRUFBRSxHQUFHLEVBQUUsRUFBRSxDQUFDLElBQUksRUFBRSxPQUFPLEVBQUUsSUFBSSxDQUFDLE1BQU0sRUFBRSxDQUFDLENBQUE7Z0JBQ3JGLENBQUM7Z0JBQ0QsT0FBTyxFQUFFLENBQUE7WUFDWCxDQUFDLENBQ0YsQ0FBQTtRQUNILEtBQUssU0FBUztZQUNaLE9BQU8sdUJBQXVCLENBQUMsR0FBRyxDQUFDLEtBQUssRUFBRSxDQUFDLENBQUE7UUFDN0M7WUFDRSxPQUFPLEVBQUUsQ0FBQTtJQUNiLENBQUM7QUFDSCxDQUFDO0FBRUQsTUFBTSxDQUFDLE1BQU0sSUFBSSxHQUFHLENBR2xCLElBQWEsRUFDYixFQUFFLENBQ0YsQ0FBQyxDQUFDLFFBQVEsQ0FDUixJQUFJLENBQUMsR0FBRyxDQUFDLGFBQWEsQ0FFckIsQ0FLRixDQUFBO0FBeUNILE1BQU0seUJBQXlCLEdBQUcsQ0FDaEMsTUFBd0IsRUFDTSxFQUFFLENBQ2hDLE9BQU8sQ0FBQyxNQUFNLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxhQUFhLENBQUMsTUFBTSxDQUFDLENBQUMsRUFBRSxDQUFDLE1BQU0sRUFBRSxFQUFFLENBQUMsQ0FBQztJQUN6RCxJQUFJLEVBQUUsSUFBSSxDQUFDLE1BQU0sQ0FBQyxPQUFPLENBQUM7SUFDMUIsY0FBYyxFQUFFLEdBQUcsRUFBRSxDQUFDLENBQUMsUUFBZ0IsRUFBRSxFQUFFO1FBQ3pDLE1BQU0sTUFBTSxHQUFRLEVBQUUsQ0FBQTtRQUN0QixLQUFLLE1BQU0sQ0FBQyxHQUFHLEVBQUUsS0FBSyxDQUFDLElBQUksTUFBTSxDQUFDLE9BQU8sQ0FBQyxNQUFNLENBQUMsTUFBTSxDQUE2QyxFQUFFLENBQUM7WUFDckcsTUFBTSxDQUFDLEtBQUssR0FBRyxFQUFFLENBQUMsR0FBRyxDQUFDLE1BQVcsRUFBRSxFQUFFLENBQUMsS0FBSyxDQUFDLE1BQU0sQ0FBQyxRQUFRLENBQUMsQ0FBQyxDQUFBO1FBQy9ELENBQUM7UUFDRCxNQUFNLENBQUMsT0FBTyxHQUFHLENBQUMsVUFBeUIsRUFBRSxFQUFFO1lBQzdDLE1BQU0sS0FBSyxHQUFHLE1BQU0sQ0FBQyxPQUFPLENBQUMsVUFBVSxDQUFDLENBQUE7WUFDeEMsT0FBTyxDQUFDLE1BQVcsRUFBRSxFQUFFLENBQUMsS0FBSyxDQUFDLE1BQU0sQ0FBQyxRQUFRLENBQUMsQ0FBQyxDQUFBO1FBQ2pELENBQUMsQ0FBQTtRQUNELE9BQU8sTUFBTSxDQUFBO0lBQ2YsQ0FBQztDQUNGLENBQUMsQ0FBQyxDQUFBO0FBRUwsTUFBTSxDQUFDLE1BQU0saUJBQWlCLEdBQUcsQ0FDL0IsTUFBd0IsRUFDTSxFQUFFLENBQUMseUJBQXlCLENBQUMsTUFBTSxDQUFDLENBQUE7QUFFcEUsTUFBTSxDQUFDLE1BQU0sV0FBVyxHQUFHLENBRXpCLEdBQUcsQ0FBVSxFQUFnQyxFQUFFLENBQUMseUJBQXlCLENBQUMsQ0FBQyxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFBIn0=
|
package/package.json
CHANGED
package/src/Schema.ts
CHANGED
|
@@ -125,13 +125,52 @@ type TaggedUnionTags<Members extends TaggedUnionMembers> = S.Literals<
|
|
|
125
125
|
}
|
|
126
126
|
>
|
|
127
127
|
|
|
128
|
+
type TaggedPropertyKeys<A, Members extends TaggedUnionMembers> = {
|
|
129
|
+
[K in keyof A & string]: A[K] extends Members[number]["Type"] ? K : never
|
|
130
|
+
}[keyof A & string]
|
|
131
|
+
|
|
132
|
+
type PropertyGuards<
|
|
133
|
+
Members extends TaggedUnionMembers,
|
|
134
|
+
K extends string,
|
|
135
|
+
A
|
|
136
|
+
> =
|
|
137
|
+
& {
|
|
138
|
+
readonly [M in Members[number] as `is${M["Type"]["_tag"]}`]: (
|
|
139
|
+
target: A
|
|
140
|
+
) => target is A & { readonly [P in K]: M["Type"] }
|
|
141
|
+
}
|
|
142
|
+
& {
|
|
143
|
+
readonly isAnyOf: <const Tags extends ReadonlyArray<Members[number]["Type"]["_tag"]>>(
|
|
144
|
+
tags: Tags
|
|
145
|
+
) => (
|
|
146
|
+
target: A
|
|
147
|
+
) => target is A & { readonly [P in K]: Extract<Members[number]["Type"], { readonly _tag: Tags[number] }> }
|
|
148
|
+
}
|
|
149
|
+
|
|
128
150
|
type TaggedUnionWithTags<Members extends TaggedUnionMembers> = S.toTaggedUnion<"_tag", Members> & {
|
|
129
151
|
readonly tags: TaggedUnionTags<Members>
|
|
152
|
+
readonly generateGuards: <A>() => <K extends TaggedPropertyKeys<A, Members>>(
|
|
153
|
+
property: K
|
|
154
|
+
) => PropertyGuards<Members, K, A>
|
|
130
155
|
}
|
|
131
156
|
|
|
132
157
|
const extendTaggedUnionWithTags = <Members extends TaggedUnionMembers>(
|
|
133
158
|
schema: S.Union<Members>
|
|
134
|
-
): TaggedUnionWithTags<Members> =>
|
|
159
|
+
): TaggedUnionWithTags<Members> =>
|
|
160
|
+
extendM(schema.pipe(S.toTaggedUnion("_tag")), (tagged) => ({
|
|
161
|
+
tags: tags(schema.members),
|
|
162
|
+
generateGuards: () => (property: string) => {
|
|
163
|
+
const result: any = {}
|
|
164
|
+
for (const [tag, guard] of Object.entries(tagged.guards) as Array<[string, (u: unknown) => boolean]>) {
|
|
165
|
+
result[`is${tag}`] = (target: any) => guard(target[property])
|
|
166
|
+
}
|
|
167
|
+
result.isAnyOf = (memberTags: Array<string>) => {
|
|
168
|
+
const check = tagged.isAnyOf(memberTags)
|
|
169
|
+
return (target: any) => check(target[property])
|
|
170
|
+
}
|
|
171
|
+
return result
|
|
172
|
+
}
|
|
173
|
+
}))
|
|
135
174
|
|
|
136
175
|
export const ExtendTaggedUnion = <Members extends TaggedUnionMembers>(
|
|
137
176
|
schema: S.Union<Members>
|
package/test/schema.test.ts
CHANGED
|
@@ -416,3 +416,76 @@ describe("JSON Schema", () => {
|
|
|
416
416
|
})
|
|
417
417
|
})
|
|
418
418
|
})
|
|
419
|
+
|
|
420
|
+
describe("generateGuards", () => {
|
|
421
|
+
const StateSchema = S.TaggedUnion(
|
|
422
|
+
S.TaggedStruct("Active", { since: S.String }),
|
|
423
|
+
S.TaggedStruct("Inactive", { reason: S.String }),
|
|
424
|
+
S.TaggedStruct("Pending", { eta: S.Finite })
|
|
425
|
+
)
|
|
426
|
+
|
|
427
|
+
type State = S.Schema.Type<typeof StateSchema>
|
|
428
|
+
type Entity = { readonly state: State; readonly name: string }
|
|
429
|
+
|
|
430
|
+
const { isActive, isAnyOf, isInactive, isPending } = StateSchema.generateGuards<Entity>()("state")
|
|
431
|
+
|
|
432
|
+
test("isActive narrows to Active member", () => {
|
|
433
|
+
const entity: Entity = { state: { _tag: "Active", since: "2024-01-01" }, name: "foo" }
|
|
434
|
+
expect(isActive(entity)).toBe(true)
|
|
435
|
+
if (isActive(entity)) {
|
|
436
|
+
expectTypeOf(entity.state).toEqualTypeOf<{ readonly _tag: "Active"; readonly since: string }>()
|
|
437
|
+
}
|
|
438
|
+
})
|
|
439
|
+
|
|
440
|
+
test("isActive returns false for non-Active", () => {
|
|
441
|
+
const entity: Entity = { state: { _tag: "Inactive", reason: "expired" }, name: "foo" }
|
|
442
|
+
expect(isActive(entity)).toBe(false)
|
|
443
|
+
})
|
|
444
|
+
|
|
445
|
+
test("isInactive narrows to Inactive member", () => {
|
|
446
|
+
const entity: Entity = { state: { _tag: "Inactive", reason: "expired" }, name: "foo" }
|
|
447
|
+
expect(isInactive(entity)).toBe(true)
|
|
448
|
+
})
|
|
449
|
+
|
|
450
|
+
test("isPending narrows to Pending member", () => {
|
|
451
|
+
const entity: Entity = { state: { _tag: "Pending", eta: 42 }, name: "foo" }
|
|
452
|
+
expect(isPending(entity)).toBe(true)
|
|
453
|
+
})
|
|
454
|
+
|
|
455
|
+
test("isAnyOf narrows to union of specified members", () => {
|
|
456
|
+
const isActiveOrPending = isAnyOf(["Active", "Pending"])
|
|
457
|
+
const active: Entity = { state: { _tag: "Active", since: "2024-01-01" }, name: "foo" }
|
|
458
|
+
const pending: Entity = { state: { _tag: "Pending", eta: 5 }, name: "bar" }
|
|
459
|
+
const inactive: Entity = { state: { _tag: "Inactive", reason: "expired" }, name: "baz" }
|
|
460
|
+
|
|
461
|
+
expect(isActiveOrPending(active)).toBe(true)
|
|
462
|
+
expect(isActiveOrPending(pending)).toBe(true)
|
|
463
|
+
expect(isActiveOrPending(inactive)).toBe(false)
|
|
464
|
+
|
|
465
|
+
if (isActiveOrPending(active)) {
|
|
466
|
+
expectTypeOf(active.state).toEqualTypeOf<
|
|
467
|
+
{ readonly _tag: "Active"; readonly since: string } | { readonly _tag: "Pending"; readonly eta: number }
|
|
468
|
+
>()
|
|
469
|
+
}
|
|
470
|
+
})
|
|
471
|
+
|
|
472
|
+
test("guards use schema-based validation (built-in guards)", () => {
|
|
473
|
+
// Built-in guards use Schema.is() — verify they reject structurally invalid values
|
|
474
|
+
expect(StateSchema.guards.Active({ _tag: "Active" })).toBe(false)
|
|
475
|
+
expect(StateSchema.guards.Active({ _tag: "Active", since: "2024-01-01" })).toBe(true)
|
|
476
|
+
})
|
|
477
|
+
|
|
478
|
+
test("ExtendTaggedUnion also exposes generateGuards", () => {
|
|
479
|
+
const union = S.Union([
|
|
480
|
+
S.TaggedStruct("X", { x: S.String }),
|
|
481
|
+
S.TaggedStruct("Y", { y: S.Finite })
|
|
482
|
+
])
|
|
483
|
+
const extended = S.ExtendTaggedUnion(union)
|
|
484
|
+
type Obj = { readonly field: S.Schema.Type<typeof extended> }
|
|
485
|
+
const { isX, isY } = extended.generateGuards<Obj>()("field")
|
|
486
|
+
|
|
487
|
+
expect(isX({ field: { _tag: "X", x: "hi" } })).toBe(true)
|
|
488
|
+
expect(isX({ field: { _tag: "Y", y: 1 } })).toBe(false)
|
|
489
|
+
expect(isY({ field: { _tag: "Y", y: 1 } })).toBe(true)
|
|
490
|
+
})
|
|
491
|
+
})
|