effect-app 4.0.0-beta.18 → 4.0.0-beta.180
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 +760 -0
- package/dist/Array.d.ts +1 -1
- package/dist/Chunk.d.ts +1 -1
- package/dist/Chunk.d.ts.map +1 -1
- package/dist/Config/SecretURL.d.ts +1 -1
- package/dist/Config/SecretURL.d.ts.map +1 -1
- package/dist/Config/SecretURL.js +2 -2
- package/dist/Config/internal/configSecretURL.d.ts +1 -1
- package/dist/Config/internal/configSecretURL.d.ts.map +1 -1
- package/dist/Config.d.ts +7 -0
- package/dist/Config.d.ts.map +1 -0
- package/dist/Config.js +6 -0
- package/dist/ConfigProvider.d.ts +39 -0
- package/dist/ConfigProvider.d.ts.map +1 -0
- package/dist/ConfigProvider.js +42 -0
- package/dist/Context.d.ts +40 -0
- package/dist/Context.d.ts.map +1 -0
- package/dist/Context.js +67 -0
- package/dist/Effect.d.ts +9 -10
- package/dist/Effect.d.ts.map +1 -1
- package/dist/Effect.js +3 -6
- package/dist/Function.d.ts +1 -1
- package/dist/Function.d.ts.map +1 -1
- package/dist/Inputify.type.d.ts +1 -1
- package/dist/Layer.d.ts +6 -5
- package/dist/Layer.d.ts.map +1 -1
- package/dist/Layer.js +1 -1
- package/dist/NonEmptySet.d.ts +1 -1
- package/dist/NonEmptySet.d.ts.map +1 -1
- package/dist/Operations.d.ts +369 -47
- package/dist/Operations.d.ts.map +1 -1
- package/dist/Operations.js +10 -10
- package/dist/Option.d.ts +1 -1
- package/dist/Option.d.ts.map +1 -1
- package/dist/Pure.d.ts +5 -5
- package/dist/Pure.d.ts.map +1 -1
- package/dist/Pure.js +13 -13
- package/dist/Schema/Class.d.ts +69 -20
- package/dist/Schema/Class.d.ts.map +1 -1
- package/dist/Schema/Class.js +190 -22
- package/dist/Schema/FastCheck.d.ts +1 -1
- package/dist/Schema/FastCheck.d.ts.map +1 -1
- package/dist/Schema/Methods.d.ts +1 -1
- package/dist/Schema/SchemaParser.d.ts +5 -0
- package/dist/Schema/SchemaParser.d.ts.map +1 -0
- package/dist/Schema/SchemaParser.js +6 -0
- package/dist/Schema/SpecialJsonSchema.d.ts +33 -0
- package/dist/Schema/SpecialJsonSchema.d.ts.map +1 -0
- package/dist/Schema/SpecialJsonSchema.js +122 -0
- package/dist/Schema/SpecialOpenApi.d.ts +32 -0
- package/dist/Schema/SpecialOpenApi.d.ts.map +1 -0
- package/dist/Schema/SpecialOpenApi.js +123 -0
- package/dist/Schema/brand.d.ts +7 -2
- package/dist/Schema/brand.d.ts.map +1 -1
- package/dist/Schema/brand.js +1 -1
- package/dist/Schema/email.d.ts +1 -1
- package/dist/Schema/email.d.ts.map +1 -1
- package/dist/Schema/email.js +7 -4
- package/dist/Schema/ext.d.ts +118 -45
- package/dist/Schema/ext.d.ts.map +1 -1
- package/dist/Schema/ext.js +129 -53
- package/dist/Schema/moreStrings.d.ts +111 -11
- package/dist/Schema/moreStrings.d.ts.map +1 -1
- package/dist/Schema/moreStrings.js +14 -15
- package/dist/Schema/numbers.d.ts +127 -15
- package/dist/Schema/numbers.d.ts.map +1 -1
- package/dist/Schema/numbers.js +10 -12
- package/dist/Schema/phoneNumber.d.ts +1 -1
- package/dist/Schema/phoneNumber.d.ts.map +1 -1
- package/dist/Schema/phoneNumber.js +6 -3
- package/dist/Schema/schema.d.ts +1 -1
- package/dist/Schema/strings.d.ts +37 -5
- package/dist/Schema/strings.d.ts.map +1 -1
- package/dist/Schema/strings.js +1 -5
- package/dist/Schema.d.ts +102 -56
- package/dist/Schema.d.ts.map +1 -1
- package/dist/Schema.js +128 -64
- package/dist/Set.d.ts +1 -1
- package/dist/Set.d.ts.map +1 -1
- package/dist/TypeTest.d.ts +1 -1
- package/dist/Types.d.ts +1 -1
- package/dist/Widen.type.d.ts +1 -1
- package/dist/_ext/Array.d.ts +1 -1
- package/dist/_ext/Array.d.ts.map +1 -1
- package/dist/_ext/date.d.ts +1 -1
- package/dist/_ext/misc.d.ts +1 -1
- package/dist/_ext/ord.ext.d.ts +1 -1
- package/dist/_ext/ord.ext.d.ts.map +1 -1
- package/dist/builtin.d.ts +1 -1
- package/dist/builtin.d.ts.map +1 -1
- package/dist/client/InvalidationKeys.d.ts +29 -0
- package/dist/client/InvalidationKeys.d.ts.map +1 -0
- package/dist/client/InvalidationKeys.js +33 -0
- package/dist/client/apiClientFactory.d.ts +17 -31
- package/dist/client/apiClientFactory.d.ts.map +1 -1
- package/dist/client/apiClientFactory.js +81 -26
- package/dist/client/clientFor.d.ts +63 -10
- package/dist/client/clientFor.d.ts.map +1 -1
- package/dist/client/clientFor.js +9 -1
- package/dist/client/errors.d.ts +49 -25
- package/dist/client/errors.d.ts.map +1 -1
- package/dist/client/errors.js +43 -17
- package/dist/client/makeClient.d.ts +360 -30
- package/dist/client/makeClient.d.ts.map +1 -1
- package/dist/client/makeClient.js +63 -23
- package/dist/client.d.ts +2 -1
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +2 -1
- package/dist/faker.d.ts +1 -1
- package/dist/faker.d.ts.map +1 -1
- package/dist/http/Request.d.ts +2 -2
- package/dist/http/Request.d.ts.map +1 -1
- package/dist/http/Request.js +5 -5
- package/dist/http/internal/lib.d.ts +1 -1
- package/dist/http.d.ts +1 -1
- package/dist/ids.d.ts +3 -3
- package/dist/ids.d.ts.map +1 -1
- package/dist/ids.js +3 -2
- package/dist/index.d.ts +5 -8
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -8
- package/dist/logger.d.ts +1 -1
- package/dist/middleware.d.ts +16 -9
- package/dist/middleware.d.ts.map +1 -1
- package/dist/middleware.js +13 -9
- package/dist/rpc/Invalidation.d.ts +490 -0
- package/dist/rpc/Invalidation.d.ts.map +1 -0
- package/dist/rpc/Invalidation.js +129 -0
- package/dist/rpc/MiddlewareMaker.d.ts +5 -4
- package/dist/rpc/MiddlewareMaker.d.ts.map +1 -1
- package/dist/rpc/MiddlewareMaker.js +26 -27
- package/dist/rpc/RpcContextMap.d.ts +3 -3
- package/dist/rpc/RpcContextMap.d.ts.map +1 -1
- package/dist/rpc/RpcContextMap.js +4 -4
- package/dist/rpc/RpcMiddleware.d.ts +5 -4
- package/dist/rpc/RpcMiddleware.d.ts.map +1 -1
- package/dist/rpc/RpcMiddleware.js +1 -1
- package/dist/rpc.d.ts +2 -2
- package/dist/rpc.d.ts.map +1 -1
- package/dist/rpc.js +2 -2
- package/dist/transform.d.ts +1 -1
- package/dist/transform.d.ts.map +1 -1
- package/dist/transform.js +3 -3
- package/dist/utils/effectify.d.ts +1 -1
- package/dist/utils/extend.d.ts +1 -1
- package/dist/utils/extend.d.ts.map +1 -1
- package/dist/utils/gen.d.ts +2 -2
- package/dist/utils/gen.d.ts.map +1 -1
- package/dist/utils/logLevel.d.ts +2 -2
- package/dist/utils/logLevel.d.ts.map +1 -1
- package/dist/utils/logger.d.ts +3 -3
- package/dist/utils/logger.d.ts.map +1 -1
- package/dist/utils/logger.js +3 -3
- package/dist/utils.d.ts +30 -10
- package/dist/utils.d.ts.map +1 -1
- package/dist/utils.js +10 -4
- package/dist/validation/validators.d.ts +1 -1
- package/dist/validation/validators.d.ts.map +1 -1
- package/dist/validation.d.ts +1 -1
- package/dist/validation.d.ts.map +1 -1
- package/eslint.config.mjs +2 -2
- package/package.json +47 -19
- package/src/Config/SecretURL.ts +2 -1
- package/src/Config.ts +14 -0
- package/src/ConfigProvider.ts +48 -0
- package/src/{ServiceMap.ts → Context.ts} +52 -59
- package/src/Effect.ts +12 -14
- package/src/Layer.ts +5 -4
- package/src/Operations.ts +14 -14
- package/src/Pure.ts +17 -18
- package/src/Schema/Class.ts +279 -62
- package/src/Schema/SchemaParser.ts +12 -0
- package/src/Schema/SpecialJsonSchema.ts +137 -0
- package/src/Schema/SpecialOpenApi.ts +130 -0
- package/src/Schema/brand.ts +9 -1
- package/src/Schema/email.ts +7 -2
- package/src/Schema/ext.ts +210 -80
- package/src/Schema/moreStrings.ts +22 -20
- package/src/Schema/numbers.ts +14 -16
- package/src/Schema/phoneNumber.ts +5 -1
- package/src/Schema/strings.ts +4 -8
- package/src/Schema.ts +265 -105
- package/src/client/InvalidationKeys.ts +50 -0
- package/src/client/apiClientFactory.ts +203 -119
- package/src/client/clientFor.ts +112 -23
- package/src/client/errors.ts +52 -26
- package/src/client/makeClient.ts +339 -63
- package/src/client.ts +1 -0
- package/src/http/Request.ts +7 -4
- package/src/ids.ts +2 -1
- package/src/index.ts +5 -10
- package/src/middleware.ts +12 -10
- package/src/rpc/Invalidation.ts +174 -0
- package/src/rpc/MiddlewareMaker.ts +36 -47
- package/src/rpc/README.md +2 -2
- package/src/rpc/RpcContextMap.ts +6 -5
- package/src/rpc/RpcMiddleware.ts +5 -4
- package/src/rpc.ts +1 -1
- package/src/transform.ts +2 -2
- package/src/utils/gen.ts +1 -1
- package/src/utils/logger.ts +2 -2
- package/src/utils.ts +47 -11
- package/test/dist/rpc.test.d.ts.map +1 -1
- package/test/dist/secretURL.test.d.ts.map +1 -0
- package/test/dist/special.test.d.ts.map +1 -0
- package/test/rpc.test.ts +38 -6
- package/test/schema.test.ts +591 -17
- package/test/secretURL.test.ts +157 -0
- package/test/special.test.ts +1023 -0
- package/test/utils.test.ts +6 -6
- package/tsconfig.base.json +3 -4
- package/tsconfig.json +0 -1
- package/tsconfig.json.bak +2 -2
- package/tsconfig.src.json +29 -29
- package/tsconfig.test.json +2 -2
- package/dist/ServiceMap.d.ts +0 -44
- package/dist/ServiceMap.d.ts.map +0 -1
- package/dist/ServiceMap.js +0 -91
package/src/Schema/email.ts
CHANGED
|
@@ -12,11 +12,16 @@ export type Email = string & EmailBrand
|
|
|
12
12
|
export const Email = S
|
|
13
13
|
.String
|
|
14
14
|
.pipe(
|
|
15
|
+
S.annotate({
|
|
16
|
+
title: "Email",
|
|
17
|
+
description: "an email according to RFC 5322",
|
|
18
|
+
format: "email"
|
|
19
|
+
}),
|
|
20
|
+
S.check(S.isMinLength(3), /* a@b */ S.isMaxLength(998)),
|
|
15
21
|
S.refine(isValidEmail as Refinement<string, Email>, {
|
|
16
22
|
identifier: "Email",
|
|
17
|
-
title: "Email",
|
|
18
23
|
description: "an email according to RFC 5322",
|
|
19
|
-
jsonSchema: { format: "email", minLength: 3,
|
|
24
|
+
jsonSchema: { format: "email", minLength: 3, maxLength: 998 }
|
|
20
25
|
}),
|
|
21
26
|
S.annotate({
|
|
22
27
|
toArbitrary: () => (fc) => fc.emailAddress().map((_) => _ as Email)
|
package/src/Schema/ext.ts
CHANGED
|
@@ -1,56 +1,115 @@
|
|
|
1
1
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
2
2
|
/* eslint-disable @typescript-eslint/no-unsafe-return */
|
|
3
|
-
import { Effect, Option, pipe,
|
|
3
|
+
import { Effect, Function, Option, pipe, type SchemaAST, SchemaIssue, SchemaTransformation } from "effect"
|
|
4
4
|
import * as S from "effect/Schema"
|
|
5
|
+
import { isDateValid } from "effect/Schema"
|
|
5
6
|
import { type NonEmptyReadonlyArray } from "../Array.js"
|
|
7
|
+
import * as Context from "../Context.js"
|
|
6
8
|
import { extendM, typedKeysOf } from "../utils.js"
|
|
7
9
|
import { type AST } from "./schema.js"
|
|
8
10
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
11
|
+
type ProvidedCodec<Self extends S.Top, R> = S.Codec<
|
|
12
|
+
Self["Type"],
|
|
13
|
+
Self["Encoded"],
|
|
14
|
+
Exclude<Self["DecodingServices"], R>,
|
|
15
|
+
Exclude<Self["EncodingServices"], R>
|
|
16
|
+
>
|
|
17
|
+
|
|
18
|
+
export const DefaultParseOptions: SchemaAST.ParseOptions = { concurrency: "unbounded" }
|
|
19
|
+
/**
|
|
20
|
+
* Parse-options annotation used on schema constructors for decode paths where callers
|
|
21
|
+
* cannot currently pass parse options (notably some RPC / HttpApi integration paths).
|
|
22
|
+
*
|
|
23
|
+
* Keep this annotation in place so those framework-managed decodes still run with
|
|
24
|
+
* unbounded concurrency by default.
|
|
25
|
+
*/
|
|
26
|
+
export const concurrencyUnbounded = { parseOptions: DefaultParseOptions } as const
|
|
27
|
+
|
|
28
|
+
type DecodeLike = (schema: any) => (input: any, options?: SchemaAST.ParseOptions) => any
|
|
29
|
+
|
|
30
|
+
export const withDefaultParseOptions = <Decode extends DecodeLike>(
|
|
31
|
+
decode: Decode,
|
|
32
|
+
defaultParseOptions: SchemaAST.ParseOptions = DefaultParseOptions
|
|
33
|
+
): Decode =>
|
|
34
|
+
((schema: any) => {
|
|
35
|
+
const run = decode(schema)
|
|
36
|
+
return (input: any, options?: SchemaAST.ParseOptions) => run(input, { ...defaultParseOptions, ...options })
|
|
37
|
+
}) as Decode
|
|
22
38
|
|
|
23
39
|
// TODO: v4 migration - Date is no longer by default encoded to string.
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
)
|
|
40
|
+
|
|
41
|
+
const DateString = S.String.annotate({
|
|
42
|
+
identifier: "Date",
|
|
43
|
+
description: "a string in ISO 8601 format that will be decoded as a Date",
|
|
44
|
+
format: "date-time"
|
|
45
|
+
})
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Schema type for {@link DateFromString}.
|
|
49
|
+
*
|
|
50
|
+
* @category Schemas
|
|
51
|
+
* @since 4.0.0
|
|
52
|
+
*/
|
|
53
|
+
export interface DateFromString extends S.decodeTo<S.Date, S.String> {}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* A transformation schema that parses an ISO 8601 string into a `Date`.
|
|
57
|
+
*
|
|
58
|
+
* Decoding:
|
|
59
|
+
* - A `string` is decoded as a `Date`.
|
|
60
|
+
*
|
|
61
|
+
* Encoding:
|
|
62
|
+
* - A `Date` is encoded as a `string`.
|
|
63
|
+
*
|
|
64
|
+
* @since 4.0.0
|
|
65
|
+
*/
|
|
66
|
+
export const DateFromString: DateFromString = DateString.pipe(S.decodeTo(S.Date, SchemaTransformation.dateFromString))
|
|
30
67
|
|
|
31
68
|
/**
|
|
32
69
|
* Like the default Schema `Date` but from String with `withDefault` => now
|
|
33
70
|
*/
|
|
34
71
|
export const Date = Object.assign(DateFromString, {
|
|
35
|
-
withDefault: DateFromString.pipe(
|
|
72
|
+
withDefault: DateFromString.pipe(S.withConstructorDefault(Effect.sync(() => new global.Date()))),
|
|
73
|
+
withDecodingDefaultType: DateFromString.pipe(S.withDecodingDefaultType(Effect.sync(() => new global.Date())))
|
|
74
|
+
})
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Like the default Schema `DateValid` but from String with `withDefault` => now
|
|
78
|
+
*/
|
|
79
|
+
export const DateValid = Object.assign(Date.check(isDateValid()), {
|
|
80
|
+
withDefault: DateFromString.pipe(S.withConstructorDefault(Effect.sync(() => new global.Date()))),
|
|
81
|
+
withDecodingDefaultType: DateFromString.pipe(S.withDecodingDefaultType(Effect.sync(() => new global.Date())))
|
|
36
82
|
})
|
|
37
83
|
|
|
38
84
|
/**
|
|
39
85
|
* Like the default Schema `Boolean` but with `withDefault` => false
|
|
40
86
|
*/
|
|
41
87
|
export const Boolean = Object.assign(S.Boolean, {
|
|
42
|
-
withDefault: S.Boolean.pipe(
|
|
88
|
+
withDefault: S.Boolean.pipe(S.withConstructorDefault(Effect.succeed(false))),
|
|
89
|
+
withDecodingDefaultType: S.Boolean.pipe(S.withDecodingDefaultType(Effect.succeed(false)))
|
|
43
90
|
})
|
|
44
91
|
|
|
45
92
|
/**
|
|
93
|
+
* You probably want to use `Finite` instead of this.
|
|
46
94
|
* Like the default Schema `Number` but with `withDefault` => 0
|
|
47
95
|
*/
|
|
48
|
-
export const Number = Object.assign(S.Number, {
|
|
96
|
+
export const Number = Object.assign(S.Number, {
|
|
97
|
+
withDefault: S.Number.pipe(S.withConstructorDefault(Effect.succeed(0))),
|
|
98
|
+
withDecodingDefaultType: S.Number.pipe(S.withDecodingDefaultType(Effect.succeed(0)))
|
|
99
|
+
})
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Like the default Schema `Finite` but with `withDefault` => 0
|
|
103
|
+
*/
|
|
104
|
+
export const Finite = Object.assign(S.Finite, {
|
|
105
|
+
withDefault: S.Finite.pipe(S.withConstructorDefault(Effect.succeed(0))),
|
|
106
|
+
withDecodingDefaultType: S.Finite.pipe(S.withDecodingDefaultType(Effect.succeed(0)))
|
|
107
|
+
})
|
|
49
108
|
|
|
50
109
|
/**
|
|
51
|
-
* Like the default Schema `
|
|
110
|
+
* Like the default Schema `Literals` but with `withDefault` => literals[0]
|
|
52
111
|
*/
|
|
53
|
-
export const
|
|
112
|
+
export const Literals = <const Literals extends NonEmptyReadonlyArray<AST.LiteralValue>>(literals: Literals) =>
|
|
54
113
|
pipe(
|
|
55
114
|
S.Literals(literals),
|
|
56
115
|
(s) =>
|
|
@@ -58,11 +117,14 @@ export const Literal = <Literals extends NonEmptyReadonlyArray<AST.LiteralValue>
|
|
|
58
117
|
changeDefault: <A extends Literals[number]>(a: A) => {
|
|
59
118
|
return Object.assign(S.Literals(literals), {
|
|
60
119
|
Default: a,
|
|
61
|
-
withDefault: s.pipe(
|
|
120
|
+
withDefault: s.pipe(S.withConstructorDefault(Effect.succeed(a))),
|
|
121
|
+
withDecodingDefaultType: s.pipe(S.withDecodingDefaultType(Effect.succeed(a)))
|
|
62
122
|
}) // todo: copy annotations from original?
|
|
63
123
|
},
|
|
64
|
-
|
|
65
|
-
|
|
124
|
+
// eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion -- load-bearing: Object.assign widens the field type without it, breaking `expectTypeOf(l.Default).toEqualTypeOf<"a">()` in tests
|
|
125
|
+
Default: literals[0] as Literals[0],
|
|
126
|
+
withDefault: s.pipe(S.withConstructorDefault(Effect.succeed(literals[0]))),
|
|
127
|
+
withDecodingDefaultType: s.pipe(S.withDecodingDefaultType(Effect.succeed(literals[0])))
|
|
66
128
|
})
|
|
67
129
|
)
|
|
68
130
|
|
|
@@ -71,43 +133,96 @@ export const Literal = <Literals extends NonEmptyReadonlyArray<AST.LiteralValue>
|
|
|
71
133
|
*/
|
|
72
134
|
export function Array<ValueSchema extends S.Top>(value: ValueSchema) {
|
|
73
135
|
return pipe(
|
|
74
|
-
S.Array(value),
|
|
75
|
-
(s) =>
|
|
136
|
+
S.Array(value).annotate(concurrencyUnbounded),
|
|
137
|
+
(s) =>
|
|
138
|
+
Object.assign(s, {
|
|
139
|
+
withDefault: s.pipe(S.withConstructorDefault(Effect.sync(() => []))),
|
|
140
|
+
withDecodingDefaultType: s.pipe(S.withDecodingDefaultType(Effect.sync(() => [])))
|
|
141
|
+
})
|
|
76
142
|
)
|
|
77
143
|
}
|
|
78
144
|
|
|
79
145
|
/**
|
|
80
|
-
*
|
|
146
|
+
* An annotated `S.Array` of unique items that decodes to a `ReadonlySet`.
|
|
81
147
|
*/
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
(
|
|
148
|
+
export const ReadonlySetFromArray = <ValueSchema extends S.Top>(value: ValueSchema) => {
|
|
149
|
+
const from = S
|
|
150
|
+
.Array(value)
|
|
151
|
+
.annotate({ ...concurrencyUnbounded, expected: "an array of unique items that will be decoded as a ReadonlySet" })
|
|
152
|
+
const to = S.instanceOf(Set) as S.instanceOf<ReadonlySet<S.Schema.Type<ValueSchema>>>
|
|
153
|
+
const schema = from.pipe(
|
|
154
|
+
S.decodeTo(
|
|
155
|
+
to,
|
|
156
|
+
SchemaTransformation.transform({
|
|
157
|
+
decode: (arr) => new Set(arr) as ReadonlySet<S.Schema.Type<ValueSchema>>,
|
|
158
|
+
encode: (set) => [...set]
|
|
159
|
+
})
|
|
160
|
+
)
|
|
86
161
|
)
|
|
162
|
+
return schema
|
|
87
163
|
}
|
|
88
164
|
|
|
89
|
-
|
|
165
|
+
/**
|
|
166
|
+
* An annotated `S.Array` of key-value tuples that decodes to a `ReadonlyMap`.
|
|
167
|
+
*/
|
|
168
|
+
export const ReadonlyMapFromArray = <KeySchema extends S.Top, ValueSchema extends S.Top>(pair: {
|
|
169
|
+
readonly key: KeySchema
|
|
170
|
+
readonly value: ValueSchema
|
|
171
|
+
}) => {
|
|
172
|
+
const from = S
|
|
173
|
+
.Array(S.Tuple([pair.key, pair.value]))
|
|
174
|
+
.annotate({
|
|
175
|
+
...concurrencyUnbounded,
|
|
176
|
+
expected: "an array of key-value tuples that will be decoded as a ReadonlyMap"
|
|
177
|
+
})
|
|
178
|
+
const to = S.instanceOf(Map) as S.instanceOf<
|
|
179
|
+
ReadonlyMap<S.Schema.Type<KeySchema>, S.Schema.Type<ValueSchema>>
|
|
180
|
+
>
|
|
181
|
+
const schema = from.pipe(
|
|
182
|
+
S.decodeTo(
|
|
183
|
+
to,
|
|
184
|
+
SchemaTransformation.transform({
|
|
185
|
+
decode: (
|
|
186
|
+
arr
|
|
187
|
+
) => new Map(arr) as ReadonlyMap<S.Schema.Type<KeySchema>, S.Schema.Type<ValueSchema>>,
|
|
188
|
+
encode: (
|
|
189
|
+
map
|
|
190
|
+
) => [...map.entries()] as any // fu
|
|
191
|
+
})
|
|
192
|
+
)
|
|
193
|
+
)
|
|
194
|
+
return schema
|
|
195
|
+
}
|
|
90
196
|
|
|
91
197
|
/**
|
|
92
|
-
* Like the default Schema `ReadonlySet` but with `withDefault` => new Set()
|
|
198
|
+
* Like the default Schema `ReadonlySet` but from Array with `withDefault` => new Set()
|
|
93
199
|
*/
|
|
94
200
|
export const ReadonlySet = <ValueSchema extends S.Top>(value: ValueSchema) =>
|
|
95
201
|
pipe(
|
|
96
|
-
|
|
202
|
+
ReadonlySetFromArray(value),
|
|
97
203
|
(s) =>
|
|
98
|
-
Object.assign(s, {
|
|
204
|
+
Object.assign(s, {
|
|
205
|
+
withDefault: s.pipe(S.withConstructorDefault(Effect.sync(() => new Set<S.Schema.Type<ValueSchema>>()))),
|
|
206
|
+
withDecodingDefaultType: s.pipe(
|
|
207
|
+
S.withDecodingDefaultType(Effect.sync(() => new Set<S.Schema.Type<ValueSchema>>()))
|
|
208
|
+
)
|
|
209
|
+
})
|
|
99
210
|
)
|
|
100
211
|
|
|
101
212
|
/**
|
|
102
|
-
* Like the default Schema `ReadonlyMap` but with `withDefault` => new Map()
|
|
213
|
+
* Like the default Schema `ReadonlyMap` but from Array with `withDefault` => new Map()
|
|
103
214
|
*/
|
|
104
215
|
export const ReadonlyMap = <KeySchema extends S.Top, ValueSchema extends S.Top>(pair: {
|
|
105
216
|
readonly key: KeySchema
|
|
106
217
|
readonly value: ValueSchema
|
|
107
218
|
}) =>
|
|
108
219
|
pipe(
|
|
109
|
-
|
|
110
|
-
(s) =>
|
|
220
|
+
ReadonlyMapFromArray(pair),
|
|
221
|
+
(s) =>
|
|
222
|
+
Object.assign(s, {
|
|
223
|
+
withDefault: s.pipe(S.withConstructorDefault(Effect.sync(() => new Map()))),
|
|
224
|
+
withDecodingDefaultType: s.pipe(S.withDecodingDefaultType(Effect.sync(() => new Map())))
|
|
225
|
+
})
|
|
111
226
|
)
|
|
112
227
|
|
|
113
228
|
/**
|
|
@@ -116,21 +231,30 @@ export const ReadonlyMap = <KeySchema extends S.Top, ValueSchema extends S.Top>(
|
|
|
116
231
|
export const NullOr = <Schema extends S.Top>(self: Schema) =>
|
|
117
232
|
pipe(
|
|
118
233
|
S.NullOr(self),
|
|
119
|
-
(s) =>
|
|
234
|
+
(s) =>
|
|
235
|
+
Object.assign(s, {
|
|
236
|
+
withDefault: s.pipe(S.withConstructorDefault(Effect.succeed(null))),
|
|
237
|
+
withDecodingDefaultType: s.pipe(S.withDecodingDefaultType(Effect.succeed(null)))
|
|
238
|
+
})
|
|
120
239
|
)
|
|
121
240
|
|
|
122
|
-
export const defaultDate = <Schema extends S.Top>(schema: Schema) =>
|
|
123
|
-
schema.pipe(
|
|
241
|
+
export const defaultDate = <Schema extends S.Top & S.WithoutConstructorDefault>(schema: Schema) =>
|
|
242
|
+
schema.pipe(S.withConstructorDefault(Effect.sync(() => new global.Date())))
|
|
124
243
|
|
|
125
|
-
export const defaultBool = <Schema extends S.Top>(schema: Schema) =>
|
|
244
|
+
export const defaultBool = <Schema extends S.Top & S.WithoutConstructorDefault>(schema: Schema) =>
|
|
245
|
+
schema.pipe(S.withConstructorDefault(Effect.succeed(false)))
|
|
126
246
|
|
|
127
|
-
export const defaultNullable = <Schema extends S.Top>(schema: Schema) =>
|
|
247
|
+
export const defaultNullable = <Schema extends S.Top & S.WithoutConstructorDefault>(schema: Schema) =>
|
|
248
|
+
schema.pipe(S.withConstructorDefault(Effect.succeed(null)))
|
|
128
249
|
|
|
129
|
-
export const defaultArray = <Schema extends S.Top>(schema: Schema) =>
|
|
250
|
+
export const defaultArray = <Schema extends S.Top & S.WithoutConstructorDefault>(schema: Schema) =>
|
|
251
|
+
schema.pipe(S.withConstructorDefault(Effect.sync(() => [])))
|
|
130
252
|
|
|
131
|
-
export const defaultMap = <Schema extends S.Top>(schema: Schema) =>
|
|
253
|
+
export const defaultMap = <Schema extends S.Top & S.WithoutConstructorDefault>(schema: Schema) =>
|
|
254
|
+
schema.pipe(S.withConstructorDefault(Effect.sync(() => new Map())))
|
|
132
255
|
|
|
133
|
-
export const defaultSet = <Schema extends S.Top>(schema: Schema) =>
|
|
256
|
+
export const defaultSet = <Schema extends S.Top & S.WithoutConstructorDefault>(schema: Schema) =>
|
|
257
|
+
schema.pipe(S.withConstructorDefault(Effect.sync(() => new Set())))
|
|
134
258
|
|
|
135
259
|
export const withDefaultMake = <Self extends S.Top>(s: Self) => {
|
|
136
260
|
const a = Object.assign(S.decodeSync(s as any) as WithDefaults<Self>, s)
|
|
@@ -160,8 +284,11 @@ export type WithDefaults<Self extends S.Top> = (
|
|
|
160
284
|
// : never
|
|
161
285
|
|
|
162
286
|
export const inputDate = extendM(
|
|
163
|
-
S.Union([S.DateValid,
|
|
164
|
-
(s) => ({
|
|
287
|
+
S.Union([S.DateValid, Date]),
|
|
288
|
+
(s) => ({
|
|
289
|
+
withDefault: s.pipe(S.withConstructorDefault(Effect.sync(() => new globalThis.Date()))),
|
|
290
|
+
withDecodingDefaultType: s.pipe(S.withDecodingDefaultType(Effect.sync(() => new globalThis.Date())))
|
|
291
|
+
})
|
|
165
292
|
)
|
|
166
293
|
|
|
167
294
|
export interface UnionBrand {}
|
|
@@ -211,7 +338,7 @@ export const transformTo = <To extends S.Top, From extends S.Top>(
|
|
|
211
338
|
{ message: "One way schema transformation, encoding is not allowed" }
|
|
212
339
|
)
|
|
213
340
|
)
|
|
214
|
-
})
|
|
341
|
+
})
|
|
215
342
|
)
|
|
216
343
|
)
|
|
217
344
|
|
|
@@ -228,7 +355,7 @@ export const transformToOrFail = <To extends S.Top, From extends S.Top, RD>(
|
|
|
228
355
|
S.decodeTo(
|
|
229
356
|
to,
|
|
230
357
|
SchemaTransformation.transformOrFail({
|
|
231
|
-
decode
|
|
358
|
+
decode,
|
|
232
359
|
encode: (i: any) =>
|
|
233
360
|
Effect.fail(
|
|
234
361
|
new SchemaIssue.Forbidden(
|
|
@@ -236,33 +363,36 @@ export const transformToOrFail = <To extends S.Top, From extends S.Top, RD>(
|
|
|
236
363
|
{ message: "One way schema transformation, encoding is not allowed" }
|
|
237
364
|
)
|
|
238
365
|
)
|
|
239
|
-
})
|
|
366
|
+
})
|
|
240
367
|
)
|
|
241
368
|
)
|
|
242
369
|
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
context: ServiceMap.ServiceMap<R>
|
|
248
|
-
): any => {
|
|
370
|
+
export const provide: {
|
|
371
|
+
<R>(context: Context.Context<R>): <Self extends S.Top>(self: Self) => ProvidedCodec<Self, R>
|
|
372
|
+
<Self extends S.Top, R>(self: Self, context: Context.Context<R>): ProvidedCodec<Self, R>
|
|
373
|
+
} = Function.dual(2, <Self extends S.Top, R>(self: Self, context: Context.Context<R>): ProvidedCodec<Self, R> => {
|
|
249
374
|
const prov = Effect.provide(context)
|
|
250
|
-
return
|
|
251
|
-
.
|
|
252
|
-
.
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
)
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
375
|
+
return self.pipe(
|
|
376
|
+
S.middlewareDecoding((effect) => prov(effect)),
|
|
377
|
+
S.middlewareEncoding((effect) => prov(effect))
|
|
378
|
+
)
|
|
379
|
+
})
|
|
380
|
+
export const contextFromServices = Effect.fnUntraced(function*<
|
|
381
|
+
Self extends S.Top,
|
|
382
|
+
Tags extends ReadonlyArray<Context.Key<any, any>>
|
|
383
|
+
>(self: Self, ...services: Tags) {
|
|
384
|
+
const context: Context.Context<Context.Service.Identifier<Tags[number]>> = Context.pick(...services)(
|
|
385
|
+
yield* Effect.context<Context.Service.Identifier<Tags[number]>>()
|
|
386
|
+
)
|
|
387
|
+
return provide(self, context)
|
|
388
|
+
}) as <
|
|
389
|
+
Self extends S.Top,
|
|
390
|
+
Tags extends ReadonlyArray<Context.Key<any, any>>
|
|
391
|
+
>(
|
|
392
|
+
self: Self,
|
|
393
|
+
...services: Tags
|
|
394
|
+
) => Effect.Effect<
|
|
395
|
+
ProvidedCodec<Self, Context.Service.Identifier<Tags[number]>>,
|
|
396
|
+
never,
|
|
397
|
+
Context.Service.Identifier<Tags[number]>
|
|
398
|
+
>
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { pipe } from "effect"
|
|
1
|
+
import { Effect, pipe } from "effect"
|
|
2
2
|
import type { Refinement } from "effect-app/Function"
|
|
3
3
|
import { extendM } from "effect-app/utils"
|
|
4
4
|
import * as S from "effect/Schema"
|
|
@@ -6,7 +6,7 @@ import type { Simplify } from "effect/Types"
|
|
|
6
6
|
import { customRandom, nanoid, urlAlphabet } from "nanoid"
|
|
7
7
|
import validator from "validator"
|
|
8
8
|
import { fromBrand, nominal } from "./brand.js"
|
|
9
|
-
import {
|
|
9
|
+
import { withDefaultMake, type WithDefaults } from "./ext.js"
|
|
10
10
|
import { type B } from "./schema.js"
|
|
11
11
|
import type { NonEmptyString255Brand, NonEmptyStringBrand } from "./strings.js"
|
|
12
12
|
|
|
@@ -27,9 +27,8 @@ export type NonEmptyString50 = string & NonEmptyString50Brand
|
|
|
27
27
|
*/
|
|
28
28
|
export const NonEmptyString50 = nonEmptyString.pipe(
|
|
29
29
|
S.check(S.isMaxLength(50)),
|
|
30
|
-
fromBrand(nominal<NonEmptyString50>(), {
|
|
30
|
+
fromBrand<NonEmptyString50>(nominal<NonEmptyString50>(), {
|
|
31
31
|
identifier: "NonEmptyString50",
|
|
32
|
-
title: "NonEmptyString50",
|
|
33
32
|
jsonSchema: {}
|
|
34
33
|
}),
|
|
35
34
|
withDefaultMake
|
|
@@ -50,9 +49,8 @@ export type NonEmptyString64 = string & NonEmptyString64Brand
|
|
|
50
49
|
*/
|
|
51
50
|
export const NonEmptyString64 = nonEmptyString.pipe(
|
|
52
51
|
S.check(S.isMaxLength(64)),
|
|
53
|
-
fromBrand(nominal<NonEmptyString64>(), {
|
|
52
|
+
fromBrand<NonEmptyString64>(nominal<NonEmptyString64>(), {
|
|
54
53
|
identifier: "NonEmptyString64",
|
|
55
|
-
title: "NonEmptyString64",
|
|
56
54
|
jsonSchema: {}
|
|
57
55
|
}),
|
|
58
56
|
withDefaultMake
|
|
@@ -74,9 +72,8 @@ export type NonEmptyString80 = string & NonEmptyString80Brand
|
|
|
74
72
|
|
|
75
73
|
export const NonEmptyString80 = nonEmptyString.pipe(
|
|
76
74
|
S.check(S.isMaxLength(80)),
|
|
77
|
-
fromBrand(nominal<NonEmptyString80>(), {
|
|
75
|
+
fromBrand<NonEmptyString80>(nominal<NonEmptyString80>(), {
|
|
78
76
|
identifier: "NonEmptyString80",
|
|
79
|
-
title: "NonEmptyString80",
|
|
80
77
|
jsonSchema: {}
|
|
81
78
|
}),
|
|
82
79
|
withDefaultMake
|
|
@@ -97,9 +94,8 @@ export type NonEmptyString100 = string & NonEmptyString100Brand
|
|
|
97
94
|
*/
|
|
98
95
|
export const NonEmptyString100 = nonEmptyString.pipe(
|
|
99
96
|
S.check(S.isMaxLength(100)),
|
|
100
|
-
fromBrand(nominal<NonEmptyString100>(), {
|
|
97
|
+
fromBrand<NonEmptyString100>(nominal<NonEmptyString100>(), {
|
|
101
98
|
identifier: "NonEmptyString100",
|
|
102
|
-
title: "NonEmptyString100",
|
|
103
99
|
jsonSchema: {}
|
|
104
100
|
}),
|
|
105
101
|
withDefaultMake
|
|
@@ -121,7 +117,10 @@ export type Min3String255 = string & Min3String255Brand
|
|
|
121
117
|
export const Min3String255 = pipe(
|
|
122
118
|
S.String,
|
|
123
119
|
S.check(S.isMinLength(3), S.isMaxLength(255)),
|
|
124
|
-
fromBrand(nominal<Min3String255>(), {
|
|
120
|
+
fromBrand<Min3String255>(nominal<Min3String255>(), {
|
|
121
|
+
identifier: "Min3String255",
|
|
122
|
+
jsonSchema: {}
|
|
123
|
+
}),
|
|
125
124
|
withDefaultMake
|
|
126
125
|
)
|
|
127
126
|
|
|
@@ -151,16 +150,15 @@ export const StringId = extendM(
|
|
|
151
150
|
pipe(
|
|
152
151
|
S.String,
|
|
153
152
|
S.check(S.isMinLength(minLength), S.isMaxLength(maxLength)),
|
|
154
|
-
fromBrand(nominal<StringId>(), {
|
|
153
|
+
fromBrand<StringId>(nominal<StringId>(), {
|
|
155
154
|
identifier: "StringId",
|
|
156
|
-
title: "StringId",
|
|
157
155
|
toArbitrary: () => (fc) => StringIdArb()(fc),
|
|
158
156
|
jsonSchema: {}
|
|
159
157
|
})
|
|
160
158
|
),
|
|
161
159
|
(s) => ({
|
|
162
160
|
make: makeStringId,
|
|
163
|
-
withDefault: s.pipe(
|
|
161
|
+
withDefault: s.pipe(S.withConstructorDefault(Effect.sync(makeStringId)))
|
|
164
162
|
})
|
|
165
163
|
)
|
|
166
164
|
.pipe(withDefaultMake)
|
|
@@ -182,16 +180,15 @@ export function prefixedStringId<Brand extends StringId>() {
|
|
|
182
180
|
(x) => (pref + x.substring(0, 50 - pref.length)) as Brand
|
|
183
181
|
)
|
|
184
182
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
|
185
|
-
const s
|
|
183
|
+
const s = StringId
|
|
186
184
|
.pipe(
|
|
187
185
|
S.refine((x: string): x is string & Brand => x.startsWith(pref), {
|
|
188
|
-
identifier: name
|
|
189
|
-
title: name
|
|
186
|
+
identifier: name
|
|
190
187
|
}),
|
|
191
188
|
S.annotate({
|
|
192
189
|
toArbitrary: () => (fc) => arb()(fc)
|
|
193
190
|
})
|
|
194
|
-
)
|
|
191
|
+
)
|
|
195
192
|
const schema = s.pipe(withDefaultMake)
|
|
196
193
|
const make = () => (pref + StringId.make().substring(0, 50 - pref.length)) as Brand
|
|
197
194
|
|
|
@@ -208,7 +205,9 @@ export function prefixedStringId<Brand extends StringId>() {
|
|
|
208
205
|
*/
|
|
209
206
|
prefixSafe: <REST extends string>(str: `${Prefix}${Separator}${REST}`) => ex(str),
|
|
210
207
|
prefix,
|
|
211
|
-
withDefault: schema.pipe(
|
|
208
|
+
withDefault: schema.pipe(S.withConstructorDefault<S.Codec<Brand, string> & S.WithoutConstructorDefault>(
|
|
209
|
+
Effect.sync(make)
|
|
210
|
+
))
|
|
212
211
|
})
|
|
213
212
|
)
|
|
214
213
|
}
|
|
@@ -247,9 +246,12 @@ const isUrl: Refinement<string, Url> = (s: string): s is Url => {
|
|
|
247
246
|
export const Url = S
|
|
248
247
|
.String
|
|
249
248
|
.pipe(
|
|
249
|
+
S.annotate({
|
|
250
|
+
title: "Url",
|
|
251
|
+
format: "uri"
|
|
252
|
+
}),
|
|
250
253
|
S.refine(isUrl, {
|
|
251
254
|
identifier: "Url",
|
|
252
|
-
title: "Url",
|
|
253
255
|
jsonSchema: { format: "uri" }
|
|
254
256
|
}),
|
|
255
257
|
S.annotate({
|
package/src/Schema/numbers.ts
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
|
+
import { Effect } from "effect"
|
|
1
2
|
import { extendM } from "effect-app/utils"
|
|
2
3
|
import * as S from "effect/Schema"
|
|
3
4
|
import type { Simplify } from "effect/Types"
|
|
4
5
|
import { fromBrand, nominal } from "./brand.js"
|
|
5
|
-
import {
|
|
6
|
+
import { withDefaultMake } from "./ext.js"
|
|
6
7
|
import { type B } from "./schema.js"
|
|
7
8
|
|
|
8
9
|
export interface PositiveIntBrand
|
|
@@ -11,10 +12,10 @@ export interface PositiveIntBrand
|
|
|
11
12
|
export const PositiveInt = extendM(
|
|
12
13
|
S.Int.pipe(
|
|
13
14
|
S.check(S.isGreaterThan(0)),
|
|
14
|
-
fromBrand(nominal<PositiveInt>(), { identifier: "PositiveInt",
|
|
15
|
+
fromBrand<PositiveInt>(nominal<PositiveInt>(), { identifier: "PositiveInt", jsonSchema: {} }),
|
|
15
16
|
withDefaultMake
|
|
16
17
|
),
|
|
17
|
-
(s) => ({ withDefault: s.pipe(
|
|
18
|
+
(s) => ({ withDefault: s.pipe(S.withConstructorDefault(Effect.sync(() => s(1)))) })
|
|
18
19
|
)
|
|
19
20
|
export type PositiveInt = number & PositiveIntBrand
|
|
20
21
|
|
|
@@ -22,53 +23,50 @@ export interface NonNegativeIntBrand extends Simplify<B.Brand<"NonNegativeInt">
|
|
|
22
23
|
export const NonNegativeInt = extendM(
|
|
23
24
|
S.Int.pipe(
|
|
24
25
|
S.check(S.isGreaterThanOrEqualTo(0)),
|
|
25
|
-
fromBrand(nominal<NonNegativeInt>(), {
|
|
26
|
+
fromBrand<NonNegativeInt>(nominal<NonNegativeInt>(), {
|
|
26
27
|
identifier: "NonNegativeInt",
|
|
27
|
-
title: "NonNegativeInt",
|
|
28
28
|
jsonSchema: {}
|
|
29
29
|
}),
|
|
30
30
|
withDefaultMake
|
|
31
31
|
),
|
|
32
|
-
(s) => ({ withDefault: s.pipe(
|
|
32
|
+
(s) => ({ withDefault: s.pipe(S.withConstructorDefault(Effect.sync(() => s(0)))) })
|
|
33
33
|
)
|
|
34
34
|
export type NonNegativeInt = number & NonNegativeIntBrand
|
|
35
35
|
|
|
36
36
|
export interface IntBrand extends Simplify<B.Brand<"Int">> {}
|
|
37
37
|
export const Int = extendM(
|
|
38
|
-
S.Int.pipe(fromBrand(nominal<Int>(), { identifier: "Int",
|
|
39
|
-
(s) => ({ withDefault: s.pipe(
|
|
38
|
+
S.Int.pipe(fromBrand<Int>(nominal<Int>(), { identifier: "Int", jsonSchema: {} }), withDefaultMake),
|
|
39
|
+
(s) => ({ withDefault: s.pipe(S.withConstructorDefault(Effect.sync(() => s(0)))) })
|
|
40
40
|
)
|
|
41
41
|
export type Int = number & IntBrand
|
|
42
42
|
|
|
43
43
|
export interface PositiveNumberBrand extends Simplify<B.Brand<"PositiveNumber"> & NonNegativeNumberBrand> {}
|
|
44
44
|
export const PositiveNumber = extendM(
|
|
45
|
-
S.
|
|
45
|
+
S.Finite.pipe(
|
|
46
46
|
S.check(S.isGreaterThan(0)),
|
|
47
|
-
fromBrand(nominal<PositiveNumber>(), {
|
|
47
|
+
fromBrand<PositiveNumber>(nominal<PositiveNumber>(), {
|
|
48
48
|
identifier: "PositiveNumber",
|
|
49
|
-
title: "PositiveNumber",
|
|
50
49
|
jsonSchema: {}
|
|
51
50
|
}),
|
|
52
51
|
withDefaultMake
|
|
53
52
|
),
|
|
54
|
-
(s) => ({ withDefault: s.pipe(
|
|
53
|
+
(s) => ({ withDefault: s.pipe(S.withConstructorDefault(Effect.sync(() => s(1)))) })
|
|
55
54
|
)
|
|
56
55
|
export type PositiveNumber = number & PositiveNumberBrand
|
|
57
56
|
|
|
58
57
|
export interface NonNegativeNumberBrand extends Simplify<B.Brand<"NonNegativeNumber">> {}
|
|
59
58
|
export const NonNegativeNumber = extendM(
|
|
60
59
|
S
|
|
61
|
-
.
|
|
60
|
+
.Finite
|
|
62
61
|
.pipe(
|
|
63
62
|
S.check(S.isGreaterThanOrEqualTo(0)),
|
|
64
|
-
fromBrand(nominal<NonNegativeNumber>(), {
|
|
63
|
+
fromBrand<NonNegativeNumber>(nominal<NonNegativeNumber>(), {
|
|
65
64
|
identifier: "NonNegativeNumber",
|
|
66
|
-
title: "NonNegativeNumber",
|
|
67
65
|
jsonSchema: {}
|
|
68
66
|
}),
|
|
69
67
|
withDefaultMake
|
|
70
68
|
),
|
|
71
|
-
(s) => ({ withDefault: s.pipe(
|
|
69
|
+
(s) => ({ withDefault: s.pipe(S.withConstructorDefault(Effect.sync(() => s(0)))) })
|
|
72
70
|
)
|
|
73
71
|
export type NonNegativeNumber = number & NonNegativeNumberBrand
|
|
74
72
|
|
|
@@ -13,9 +13,13 @@ export type PhoneNumber = string & PhoneNumberBrand
|
|
|
13
13
|
export const PhoneNumber = S
|
|
14
14
|
.String
|
|
15
15
|
.pipe(
|
|
16
|
+
S.annotate({
|
|
17
|
+
title: "PhoneNumber",
|
|
18
|
+
description: "a phone number with at least 7 digits",
|
|
19
|
+
format: "phone"
|
|
20
|
+
}),
|
|
16
21
|
S.refine(isValidPhone as Refinement<string, PhoneNumber>, {
|
|
17
22
|
identifier: "PhoneNumber",
|
|
18
|
-
title: "PhoneNumber",
|
|
19
23
|
description: "a phone number with at least 7 digits",
|
|
20
24
|
jsonSchema: { format: "phone" }
|
|
21
25
|
}),
|