effect-app 4.0.0-beta.2 → 4.0.0-beta.200
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 +960 -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 +7 -6
- 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/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 +66 -20
- package/dist/Schema/Class.d.ts.map +1 -1
- package/dist/Schema/Class.js +189 -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 +14 -6
- 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 +9 -5
- package/dist/Schema/ext.d.ts +121 -48
- package/dist/Schema/ext.d.ts.map +1 -1
- package/dist/Schema/ext.js +134 -52
- package/dist/Schema/moreStrings.d.ts +117 -17
- package/dist/Schema/moreStrings.d.ts.map +1 -1
- package/dist/Schema/moreStrings.js +19 -18
- 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 +8 -4
- 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 +159 -58
- package/dist/Schema.d.ts.map +1 -1
- package/dist/Schema.js +136 -68
- 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 +18 -32
- package/dist/client/apiClientFactory.d.ts.map +1 -1
- package/dist/client/apiClientFactory.js +98 -36
- package/dist/client/clientFor.d.ts +51 -17
- 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 +468 -32
- package/dist/client/makeClient.d.ts.map +1 -1
- package/dist/client/makeClient.js +61 -34
- 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 +9 -9
- package/dist/ids.d.ts.map +1 -1
- package/dist/ids.js +3 -2
- package/dist/index.d.ts +5 -9
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -9
- 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 +397 -0
- package/dist/rpc/Invalidation.d.ts.map +1 -0
- package/dist/rpc/Invalidation.js +150 -0
- package/dist/rpc/MiddlewareMaker.d.ts +6 -5
- package/dist/rpc/MiddlewareMaker.d.ts.map +1 -1
- package/dist/rpc/MiddlewareMaker.js +51 -28
- 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 +6 -5
- 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 +48 -10
- package/dist/utils.d.ts.map +1 -1
- package/dist/utils.js +33 -8
- 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/package.json +46 -28
- 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} +58 -64
- package/src/Effect.ts +12 -14
- package/src/Layer.ts +6 -5
- package/src/Pure.ts +17 -18
- package/src/Schema/Class.ts +268 -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 +21 -7
- package/src/Schema/email.ts +10 -3
- package/src/Schema/ext.ts +226 -86
- package/src/Schema/moreStrings.ts +37 -32
- package/src/Schema/numbers.ts +14 -16
- package/src/Schema/phoneNumber.ts +8 -2
- package/src/Schema/strings.ts +4 -8
- package/src/Schema.ts +350 -107
- package/src/client/InvalidationKeys.ts +50 -0
- package/src/client/apiClientFactory.ts +227 -136
- package/src/client/clientFor.ts +86 -29
- package/src/client/errors.ts +61 -26
- package/src/client/makeClient.ts +530 -80
- package/src/client.ts +1 -0
- package/src/http/Request.ts +7 -4
- package/src/ids.ts +3 -2
- package/src/index.ts +5 -11
- package/src/middleware.ts +12 -10
- package/src/rpc/Invalidation.ts +221 -0
- package/src/rpc/MiddlewareMaker.ts +61 -51
- package/src/rpc/README.md +2 -2
- package/src/rpc/RpcContextMap.ts +6 -5
- package/src/rpc/RpcMiddleware.ts +6 -5
- 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 +73 -15
- package/test/dist/moreStrings.test.d.ts.map +1 -0
- 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/moreStrings.test.ts +17 -0
- package/test/rpc.test.ts +38 -6
- package/test/schema.test.ts +609 -4
- 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/Operations.d.ts +0 -87
- package/dist/Operations.d.ts.map +0 -1
- package/dist/Operations.js +0 -29
- package/dist/ServiceMap.d.ts +0 -44
- package/dist/ServiceMap.d.ts.map +0 -1
- package/dist/ServiceMap.js +0 -91
- package/dist/Struct.d.ts +0 -44
- package/dist/Struct.d.ts.map +0 -1
- package/dist/Struct.js +0 -29
- package/eslint.config.mjs +0 -26
- package/src/Operations.ts +0 -55
- package/src/Struct.ts +0 -54
package/src/Schema/brand.ts
CHANGED
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
/* eslint-disable @typescript-eslint/no-unsafe-return */
|
|
3
3
|
import type { Option } from "effect"
|
|
4
4
|
import * as B from "effect/Brand"
|
|
5
|
-
import type * as Brand from "effect/Brand"
|
|
6
5
|
import type * as Result from "effect/Result"
|
|
7
6
|
import * as S from "effect/Schema"
|
|
8
7
|
|
|
@@ -21,7 +20,7 @@ export interface Constructor<in out A extends B.Brand<any>> {
|
|
|
21
20
|
* Constructs a branded type from a value of type `A`, returning `Result.succeed`
|
|
22
21
|
* if the provided `A` is valid, `Result.fail` otherwise.
|
|
23
22
|
*/
|
|
24
|
-
result(args: Unbranded<A>): Result.Result<A,
|
|
23
|
+
result(args: Unbranded<A>): Result.Result<A, B.BrandError>
|
|
25
24
|
/**
|
|
26
25
|
* Attempts to refine the provided value of type `A`, returning `true` if
|
|
27
26
|
* the provided `A` is valid, `false` otherwise.
|
|
@@ -29,19 +28,34 @@ export interface Constructor<in out A extends B.Brand<any>> {
|
|
|
29
28
|
is(a: Unbranded<A>): a is Unbranded<A> & A
|
|
30
29
|
}
|
|
31
30
|
|
|
32
|
-
|
|
31
|
+
type BrandAnnotations<C extends B.Brand<any>> =
|
|
32
|
+
& S.Annotations.Filter
|
|
33
|
+
& (
|
|
34
|
+
C extends string ? { readonly toArbitrary?: S.Annotations.ToArbitrary.Declaration<C, readonly []> }
|
|
35
|
+
: {}
|
|
36
|
+
)
|
|
37
|
+
|
|
38
|
+
type BrandedSchema<Self extends S.Top, C extends B.Brand<any>> =
|
|
39
|
+
& Omit<S.brand<Self["Rebuild"], B.Brand.Keys<C>>, "Type" | "Iso" | "~type.make">
|
|
40
|
+
& {
|
|
41
|
+
readonly Type: C
|
|
42
|
+
readonly Iso: C
|
|
43
|
+
readonly "~type.make": C
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export const fromBrand = <C extends B.Brand<any>>(
|
|
33
47
|
constructor: Constructor<C>,
|
|
34
|
-
options?:
|
|
48
|
+
options?: BrandAnnotations<C>
|
|
35
49
|
) =>
|
|
36
|
-
<Self extends S.Top>(self: Self):
|
|
50
|
+
<Self extends S.Top>(self: Self): BrandedSchema<Self, C> => {
|
|
37
51
|
const branded = S.fromBrand(options?.identifier ?? "Brand", constructor as any)(self as any)
|
|
38
52
|
return options ? (branded as any).pipe(S.annotate(options)) : branded as any
|
|
39
53
|
}
|
|
40
54
|
|
|
41
|
-
export type Brands<P> = P extends B.Brand<any> ?
|
|
55
|
+
export type Brands<P> = P extends B.Brand<any> ? B.Brand.Brands<P>
|
|
42
56
|
: never
|
|
43
57
|
|
|
44
|
-
export type Unbranded<P> = P extends B.Brand<any> ?
|
|
58
|
+
export type Unbranded<P> = P extends B.Brand<any> ? B.Brand.Unbranded<P> : P
|
|
45
59
|
|
|
46
60
|
export const nominal: <A extends B.Brand<any>>() => Constructor<A> = <
|
|
47
61
|
A extends B.Brand<any>
|
package/src/Schema/email.ts
CHANGED
|
@@ -12,11 +12,18 @@ 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,
|
|
20
|
-
|
|
24
|
+
jsonSchema: { format: "email", minLength: 3, maxLength: 998 }
|
|
25
|
+
}),
|
|
26
|
+
S.annotate({
|
|
27
|
+
toArbitrary: () => (fc) => fc.emailAddress().map((_) => _ as Email)
|
|
21
28
|
})
|
|
22
29
|
)
|
package/src/Schema/ext.ts
CHANGED
|
@@ -1,56 +1,125 @@
|
|
|
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 { Config, 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
|
-
|
|
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
|
+
const concurrencySetting = Effect.runSync(
|
|
19
|
+
Config
|
|
20
|
+
.literal("unbounded", "SCHEMA_CONCURRENCY")
|
|
21
|
+
.pipe(Config.orElse(() => Config.number("SCHEMA_CONCURRENCY")), Config.option)
|
|
22
|
+
.asEffect()
|
|
23
|
+
)
|
|
24
|
+
|
|
25
|
+
export const DefaultParseOptions: SchemaAST.ParseOptions = {
|
|
26
|
+
concurrency: Option.getOrElse(concurrencySetting, () => "unbounded" as const)
|
|
21
27
|
}
|
|
22
28
|
|
|
29
|
+
/**
|
|
30
|
+
* Parse-options annotation used on schema constructors for decode paths where callers
|
|
31
|
+
* cannot currently pass parse options (notably some RPC / HttpApi integration paths).
|
|
32
|
+
*
|
|
33
|
+
* Keep this annotation in place so those framework-managed decodes still run with
|
|
34
|
+
* unbounded concurrency by default.
|
|
35
|
+
*/
|
|
36
|
+
export const concurrencyUnbounded = { parseOptions: DefaultParseOptions } as const
|
|
37
|
+
|
|
38
|
+
type DecodeLike = (schema: any) => (input: any, options?: SchemaAST.ParseOptions) => any
|
|
39
|
+
|
|
40
|
+
export const withDefaultParseOptions = <Decode extends DecodeLike>(
|
|
41
|
+
decode: Decode,
|
|
42
|
+
defaultParseOptions: SchemaAST.ParseOptions = DefaultParseOptions
|
|
43
|
+
): Decode =>
|
|
44
|
+
((schema: any) => {
|
|
45
|
+
const run = decode(schema)
|
|
46
|
+
return (input: any, options?: SchemaAST.ParseOptions) => run(input, { ...defaultParseOptions, ...options })
|
|
47
|
+
}) as Decode
|
|
48
|
+
|
|
23
49
|
// TODO: v4 migration - Date is no longer by default encoded to string.
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
)
|
|
50
|
+
|
|
51
|
+
const DateString = S.String.annotate({
|
|
52
|
+
identifier: "Date",
|
|
53
|
+
description: "a string in ISO 8601 format that will be decoded as a Date",
|
|
54
|
+
format: "date-time"
|
|
55
|
+
})
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Schema type for {@link DateFromString}.
|
|
59
|
+
*
|
|
60
|
+
* @category Schemas
|
|
61
|
+
* @since 4.0.0
|
|
62
|
+
*/
|
|
63
|
+
export interface DateFromString extends S.decodeTo<S.Date, S.String> {}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* A transformation schema that parses an ISO 8601 string into a `Date`.
|
|
67
|
+
*
|
|
68
|
+
* Decoding:
|
|
69
|
+
* - A `string` is decoded as a `Date`.
|
|
70
|
+
*
|
|
71
|
+
* Encoding:
|
|
72
|
+
* - A `Date` is encoded as a `string`.
|
|
73
|
+
*
|
|
74
|
+
* @since 4.0.0
|
|
75
|
+
*/
|
|
76
|
+
export const DateFromString: DateFromString = DateString.pipe(S.decodeTo(S.Date, SchemaTransformation.dateFromString))
|
|
30
77
|
|
|
31
78
|
/**
|
|
32
79
|
* Like the default Schema `Date` but from String with `withDefault` => now
|
|
33
80
|
*/
|
|
34
81
|
export const Date = Object.assign(DateFromString, {
|
|
35
|
-
withDefault: DateFromString.pipe(
|
|
82
|
+
withDefault: DateFromString.pipe(S.withConstructorDefault(Effect.sync(() => new global.Date()))),
|
|
83
|
+
withDecodingDefaultType: DateFromString.pipe(S.withDecodingDefaultType(Effect.sync(() => new global.Date())))
|
|
84
|
+
})
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Like the default Schema `DateValid` but from String with `withDefault` => now
|
|
88
|
+
*/
|
|
89
|
+
export const DateValid = Object.assign(Date.check(isDateValid()), {
|
|
90
|
+
withDefault: DateFromString.pipe(S.withConstructorDefault(Effect.sync(() => new global.Date()))),
|
|
91
|
+
withDecodingDefaultType: DateFromString.pipe(S.withDecodingDefaultType(Effect.sync(() => new global.Date())))
|
|
36
92
|
})
|
|
37
93
|
|
|
38
94
|
/**
|
|
39
95
|
* Like the default Schema `Boolean` but with `withDefault` => false
|
|
40
96
|
*/
|
|
41
97
|
export const Boolean = Object.assign(S.Boolean, {
|
|
42
|
-
withDefault: S.Boolean.pipe(
|
|
98
|
+
withDefault: S.Boolean.pipe(S.withConstructorDefault(Effect.succeed(false))),
|
|
99
|
+
withDecodingDefaultType: S.Boolean.pipe(S.withDecodingDefaultType(Effect.succeed(false)))
|
|
43
100
|
})
|
|
44
101
|
|
|
45
102
|
/**
|
|
103
|
+
* You probably want to use `Finite` instead of this.
|
|
46
104
|
* Like the default Schema `Number` but with `withDefault` => 0
|
|
47
105
|
*/
|
|
48
|
-
export const Number = Object.assign(S.Number, {
|
|
106
|
+
export const Number = Object.assign(S.Number, {
|
|
107
|
+
withDefault: S.Number.pipe(S.withConstructorDefault(Effect.succeed(0))),
|
|
108
|
+
withDecodingDefaultType: S.Number.pipe(S.withDecodingDefaultType(Effect.succeed(0)))
|
|
109
|
+
})
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Like the default Schema `Finite` but with `withDefault` => 0
|
|
113
|
+
*/
|
|
114
|
+
export const Finite = Object.assign(S.Finite, {
|
|
115
|
+
withDefault: S.Finite.pipe(S.withConstructorDefault(Effect.succeed(0))),
|
|
116
|
+
withDecodingDefaultType: S.Finite.pipe(S.withDecodingDefaultType(Effect.succeed(0)))
|
|
117
|
+
})
|
|
49
118
|
|
|
50
119
|
/**
|
|
51
|
-
* Like the default Schema `
|
|
120
|
+
* Like the default Schema `Literals` but with `withDefault` => literals[0]
|
|
52
121
|
*/
|
|
53
|
-
export const
|
|
122
|
+
export const Literals = <const Literals extends NonEmptyReadonlyArray<AST.LiteralValue>>(literals: Literals) =>
|
|
54
123
|
pipe(
|
|
55
124
|
S.Literals(literals),
|
|
56
125
|
(s) =>
|
|
@@ -58,79 +127,144 @@ export const Literal = <Literals extends NonEmptyReadonlyArray<AST.LiteralValue>
|
|
|
58
127
|
changeDefault: <A extends Literals[number]>(a: A) => {
|
|
59
128
|
return Object.assign(S.Literals(literals), {
|
|
60
129
|
Default: a,
|
|
61
|
-
withDefault: s.pipe(
|
|
130
|
+
withDefault: s.pipe(S.withConstructorDefault(Effect.succeed(a))),
|
|
131
|
+
withDecodingDefaultType: s.pipe(S.withDecodingDefaultType(Effect.succeed(a)))
|
|
62
132
|
}) // todo: copy annotations from original?
|
|
63
133
|
},
|
|
64
|
-
|
|
65
|
-
|
|
134
|
+
// 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
|
|
135
|
+
Default: literals[0] as Literals[0],
|
|
136
|
+
withDefault: s.pipe(S.withConstructorDefault(Effect.succeed(literals[0]))),
|
|
137
|
+
withDecodingDefaultType: s.pipe(S.withDecodingDefaultType(Effect.succeed(literals[0])))
|
|
66
138
|
})
|
|
67
139
|
)
|
|
68
140
|
|
|
69
141
|
/**
|
|
70
142
|
* Like the default Schema `Array` but with `withDefault` => []
|
|
71
143
|
*/
|
|
72
|
-
export function Array<
|
|
144
|
+
export function Array<ValueSchema extends S.Top>(value: ValueSchema) {
|
|
73
145
|
return pipe(
|
|
74
|
-
S.Array(value),
|
|
75
|
-
(s) =>
|
|
146
|
+
S.Array(value).annotate(concurrencyUnbounded),
|
|
147
|
+
(s) =>
|
|
148
|
+
Object.assign(s, {
|
|
149
|
+
withDefault: s.pipe(S.withConstructorDefault(Effect.sync(() => []))),
|
|
150
|
+
withDecodingDefaultType: s.pipe(S.withDecodingDefaultType(Effect.sync(() => [])))
|
|
151
|
+
})
|
|
76
152
|
)
|
|
77
153
|
}
|
|
78
154
|
|
|
79
155
|
/**
|
|
80
|
-
*
|
|
156
|
+
* An annotated `S.Array` of unique items that decodes to a `ReadonlySet`.
|
|
81
157
|
*/
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
(
|
|
158
|
+
export const ReadonlySetFromArray = <ValueSchema extends S.Top>(value: ValueSchema) => {
|
|
159
|
+
const from = S
|
|
160
|
+
.Array(value)
|
|
161
|
+
.annotate({ ...concurrencyUnbounded, expected: "an array of unique items that will be decoded as a ReadonlySet" })
|
|
162
|
+
const to = S.instanceOf(Set) as S.instanceOf<ReadonlySet<S.Schema.Type<ValueSchema>>>
|
|
163
|
+
const schema = from.pipe(
|
|
164
|
+
S.decodeTo(
|
|
165
|
+
to,
|
|
166
|
+
SchemaTransformation.transform({
|
|
167
|
+
decode: (arr) => new Set(arr) as ReadonlySet<S.Schema.Type<ValueSchema>>,
|
|
168
|
+
encode: (set) => [...set]
|
|
169
|
+
})
|
|
170
|
+
)
|
|
86
171
|
)
|
|
172
|
+
return schema
|
|
87
173
|
}
|
|
88
174
|
|
|
89
|
-
|
|
175
|
+
/**
|
|
176
|
+
* An annotated `S.Array` of key-value tuples that decodes to a `ReadonlyMap`.
|
|
177
|
+
*/
|
|
178
|
+
export const ReadonlyMapFromArray = <KeySchema extends S.Top, ValueSchema extends S.Top>(pair: {
|
|
179
|
+
readonly key: KeySchema
|
|
180
|
+
readonly value: ValueSchema
|
|
181
|
+
}) => {
|
|
182
|
+
const from = S
|
|
183
|
+
.Array(S.Tuple([pair.key, pair.value]))
|
|
184
|
+
.annotate({
|
|
185
|
+
...concurrencyUnbounded,
|
|
186
|
+
expected: "an array of key-value tuples that will be decoded as a ReadonlyMap"
|
|
187
|
+
})
|
|
188
|
+
const to = S.instanceOf(Map) as S.instanceOf<
|
|
189
|
+
ReadonlyMap<S.Schema.Type<KeySchema>, S.Schema.Type<ValueSchema>>
|
|
190
|
+
>
|
|
191
|
+
const schema = from.pipe(
|
|
192
|
+
S.decodeTo(
|
|
193
|
+
to,
|
|
194
|
+
SchemaTransformation.transform({
|
|
195
|
+
decode: (
|
|
196
|
+
arr
|
|
197
|
+
) => new Map(arr) as ReadonlyMap<S.Schema.Type<KeySchema>, S.Schema.Type<ValueSchema>>,
|
|
198
|
+
encode: (
|
|
199
|
+
map
|
|
200
|
+
) => [...map.entries()] as any // fu
|
|
201
|
+
})
|
|
202
|
+
)
|
|
203
|
+
)
|
|
204
|
+
return schema
|
|
205
|
+
}
|
|
90
206
|
|
|
91
207
|
/**
|
|
92
|
-
* Like the default Schema `ReadonlySet` but with `withDefault` => new Set()
|
|
208
|
+
* Like the default Schema `ReadonlySet` but from Array with `withDefault` => new Set()
|
|
93
209
|
*/
|
|
94
|
-
export const ReadonlySet = <
|
|
210
|
+
export const ReadonlySet = <ValueSchema extends S.Top>(value: ValueSchema) =>
|
|
95
211
|
pipe(
|
|
96
|
-
|
|
97
|
-
(s) =>
|
|
212
|
+
ReadonlySetFromArray(value),
|
|
213
|
+
(s) =>
|
|
214
|
+
Object.assign(s, {
|
|
215
|
+
withDefault: s.pipe(S.withConstructorDefault(Effect.sync(() => new Set<S.Schema.Type<ValueSchema>>()))),
|
|
216
|
+
withDecodingDefaultType: s.pipe(
|
|
217
|
+
S.withDecodingDefaultType(Effect.sync(() => new Set<S.Schema.Type<ValueSchema>>()))
|
|
218
|
+
)
|
|
219
|
+
})
|
|
98
220
|
)
|
|
99
221
|
|
|
100
222
|
/**
|
|
101
|
-
* Like the default Schema `ReadonlyMap` but with `withDefault` => new Map()
|
|
223
|
+
* Like the default Schema `ReadonlyMap` but from Array with `withDefault` => new Map()
|
|
102
224
|
*/
|
|
103
|
-
export const ReadonlyMap = <
|
|
104
|
-
readonly key:
|
|
105
|
-
readonly value:
|
|
225
|
+
export const ReadonlyMap = <KeySchema extends S.Top, ValueSchema extends S.Top>(pair: {
|
|
226
|
+
readonly key: KeySchema
|
|
227
|
+
readonly value: ValueSchema
|
|
106
228
|
}) =>
|
|
107
229
|
pipe(
|
|
108
|
-
|
|
109
|
-
(s) =>
|
|
230
|
+
ReadonlyMapFromArray(pair),
|
|
231
|
+
(s) =>
|
|
232
|
+
Object.assign(s, {
|
|
233
|
+
withDefault: s.pipe(S.withConstructorDefault(Effect.sync(() => new Map()))),
|
|
234
|
+
withDecodingDefaultType: s.pipe(S.withDecodingDefaultType(Effect.sync(() => new Map())))
|
|
235
|
+
})
|
|
110
236
|
)
|
|
111
237
|
|
|
112
238
|
/**
|
|
113
239
|
* Like the default Schema `NullOr` but with `withDefault` => null
|
|
114
240
|
*/
|
|
115
|
-
export const NullOr = <
|
|
241
|
+
export const NullOr = <Schema extends S.Top>(self: Schema) =>
|
|
116
242
|
pipe(
|
|
117
243
|
S.NullOr(self),
|
|
118
|
-
(s) =>
|
|
244
|
+
(s) =>
|
|
245
|
+
Object.assign(s, {
|
|
246
|
+
withDefault: s.pipe(S.withConstructorDefault(Effect.succeed(null))),
|
|
247
|
+
withDecodingDefaultType: s.pipe(S.withDecodingDefaultType(Effect.succeed(null)))
|
|
248
|
+
})
|
|
119
249
|
)
|
|
120
250
|
|
|
121
|
-
export const defaultDate =
|
|
251
|
+
export const defaultDate = <Schema extends S.Top & S.WithoutConstructorDefault>(schema: Schema) =>
|
|
252
|
+
schema.pipe(S.withConstructorDefault(Effect.sync(() => new global.Date())))
|
|
122
253
|
|
|
123
|
-
export const defaultBool =
|
|
254
|
+
export const defaultBool = <Schema extends S.Top & S.WithoutConstructorDefault>(schema: Schema) =>
|
|
255
|
+
schema.pipe(S.withConstructorDefault(Effect.succeed(false)))
|
|
124
256
|
|
|
125
|
-
export const defaultNullable = (
|
|
126
|
-
|
|
127
|
-
) => s.pipe(withDefaultConstructor(() => null))
|
|
257
|
+
export const defaultNullable = <Schema extends S.Top & S.WithoutConstructorDefault>(schema: Schema) =>
|
|
258
|
+
schema.pipe(S.withConstructorDefault(Effect.succeed(null)))
|
|
128
259
|
|
|
129
|
-
export const defaultArray =
|
|
260
|
+
export const defaultArray = <Schema extends S.Top & S.WithoutConstructorDefault>(schema: Schema) =>
|
|
261
|
+
schema.pipe(S.withConstructorDefault(Effect.sync(() => [])))
|
|
130
262
|
|
|
131
|
-
export const defaultMap =
|
|
263
|
+
export const defaultMap = <Schema extends S.Top & S.WithoutConstructorDefault>(schema: Schema) =>
|
|
264
|
+
schema.pipe(S.withConstructorDefault(Effect.sync(() => new Map())))
|
|
132
265
|
|
|
133
|
-
export const defaultSet =
|
|
266
|
+
export const defaultSet = <Schema extends S.Top & S.WithoutConstructorDefault>(schema: Schema) =>
|
|
267
|
+
schema.pipe(S.withConstructorDefault(Effect.sync(() => new Set())))
|
|
134
268
|
|
|
135
269
|
export const withDefaultMake = <Self extends S.Top>(s: Self) => {
|
|
136
270
|
const a = Object.assign(S.decodeSync(s as any) as WithDefaults<Self>, s)
|
|
@@ -160,8 +294,11 @@ export type WithDefaults<Self extends S.Top> = (
|
|
|
160
294
|
// : never
|
|
161
295
|
|
|
162
296
|
export const inputDate = extendM(
|
|
163
|
-
S.Union([S.DateValid,
|
|
164
|
-
(s) => ({
|
|
297
|
+
S.Union([S.DateValid, Date]),
|
|
298
|
+
(s) => ({
|
|
299
|
+
withDefault: s.pipe(S.withConstructorDefault(Effect.sync(() => new globalThis.Date()))),
|
|
300
|
+
withDecodingDefaultType: s.pipe(S.withDecodingDefaultType(Effect.sync(() => new globalThis.Date())))
|
|
301
|
+
})
|
|
165
302
|
)
|
|
166
303
|
|
|
167
304
|
export interface UnionBrand {}
|
|
@@ -211,7 +348,7 @@ export const transformTo = <To extends S.Top, From extends S.Top>(
|
|
|
211
348
|
{ message: "One way schema transformation, encoding is not allowed" }
|
|
212
349
|
)
|
|
213
350
|
)
|
|
214
|
-
})
|
|
351
|
+
})
|
|
215
352
|
)
|
|
216
353
|
)
|
|
217
354
|
|
|
@@ -228,7 +365,7 @@ export const transformToOrFail = <To extends S.Top, From extends S.Top, RD>(
|
|
|
228
365
|
S.decodeTo(
|
|
229
366
|
to,
|
|
230
367
|
SchemaTransformation.transformOrFail({
|
|
231
|
-
decode
|
|
368
|
+
decode,
|
|
232
369
|
encode: (i: any) =>
|
|
233
370
|
Effect.fail(
|
|
234
371
|
new SchemaIssue.Forbidden(
|
|
@@ -236,33 +373,36 @@ export const transformToOrFail = <To extends S.Top, From extends S.Top, RD>(
|
|
|
236
373
|
{ message: "One way schema transformation, encoding is not allowed" }
|
|
237
374
|
)
|
|
238
375
|
)
|
|
239
|
-
})
|
|
376
|
+
})
|
|
240
377
|
)
|
|
241
378
|
)
|
|
242
379
|
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
context: ServiceMap.ServiceMap<R>
|
|
248
|
-
): any => {
|
|
380
|
+
export const provide: {
|
|
381
|
+
<R>(context: Context.Context<R>): <Self extends S.Top>(self: Self) => ProvidedCodec<Self, R>
|
|
382
|
+
<Self extends S.Top, R>(self: Self, context: Context.Context<R>): ProvidedCodec<Self, R>
|
|
383
|
+
} = Function.dual(2, <Self extends S.Top, R>(self: Self, context: Context.Context<R>): ProvidedCodec<Self, R> => {
|
|
249
384
|
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
|
-
|
|
385
|
+
return self.pipe(
|
|
386
|
+
S.middlewareDecoding((effect) => prov(effect)),
|
|
387
|
+
S.middlewareEncoding((effect) => prov(effect))
|
|
388
|
+
)
|
|
389
|
+
})
|
|
390
|
+
export const contextFromServices = Effect.fnUntraced(function*<
|
|
391
|
+
Self extends S.Top,
|
|
392
|
+
Tags extends ReadonlyArray<Context.Key<any, any>>
|
|
393
|
+
>(self: Self, ...services: Tags) {
|
|
394
|
+
const context: Context.Context<Context.Service.Identifier<Tags[number]>> = Context.pick(...services)(
|
|
395
|
+
yield* Effect.context<Context.Service.Identifier<Tags[number]>>()
|
|
396
|
+
)
|
|
397
|
+
return provide(self, context)
|
|
398
|
+
}) as <
|
|
399
|
+
Self extends S.Top,
|
|
400
|
+
Tags extends ReadonlyArray<Context.Key<any, any>>
|
|
401
|
+
>(
|
|
402
|
+
self: Self,
|
|
403
|
+
...services: Tags
|
|
404
|
+
) => Effect.Effect<
|
|
405
|
+
ProvidedCodec<Self, Context.Service.Identifier<Tags[number]>>,
|
|
406
|
+
never,
|
|
407
|
+
Context.Service.Identifier<Tags[number]>
|
|
408
|
+
>
|