effect-app 0.152.0

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.
Files changed (169) hide show
  1. package/.eslintrc.cjs +11 -0
  2. package/.prettierignore +6 -0
  3. package/CHANGELOG.md +4106 -0
  4. package/_cjs/Config/SecretURL.cjs +58 -0
  5. package/_cjs/Config/SecretURL.cjs.map +1 -0
  6. package/_cjs/Config/internal/configSecretURL.cjs +88 -0
  7. package/_cjs/Config/internal/configSecretURL.cjs.map +1 -0
  8. package/_cjs/Inputify.type.cjs +6 -0
  9. package/_cjs/Inputify.type.cjs.map +1 -0
  10. package/_cjs/Operations.cjs +76 -0
  11. package/_cjs/Operations.cjs.map +1 -0
  12. package/_cjs/Pure.cjs +201 -0
  13. package/_cjs/Pure.cjs.map +1 -0
  14. package/_cjs/Request.cjs +76 -0
  15. package/_cjs/Request.cjs.map +1 -0
  16. package/_cjs/Widen.type.cjs +6 -0
  17. package/_cjs/Widen.type.cjs.map +1 -0
  18. package/_cjs/_ext/date.cjs +64 -0
  19. package/_cjs/_ext/date.cjs.map +1 -0
  20. package/_cjs/_ext/misc.cjs +121 -0
  21. package/_cjs/_ext/misc.cjs.map +1 -0
  22. package/_cjs/_global.cjs +24 -0
  23. package/_cjs/_global.cjs.map +1 -0
  24. package/_cjs/_global.ext.cjs +5 -0
  25. package/_cjs/_global.ext.cjs.map +1 -0
  26. package/_cjs/_global.schema.cjs +4 -0
  27. package/_cjs/_global.schema.cjs.map +1 -0
  28. package/_cjs/client/QueryResult.cjs +116 -0
  29. package/_cjs/client/QueryResult.cjs.map +1 -0
  30. package/_cjs/client/clientFor.cjs +159 -0
  31. package/_cjs/client/clientFor.cjs.map +1 -0
  32. package/_cjs/client/config.cjs +21 -0
  33. package/_cjs/client/config.cjs.map +1 -0
  34. package/_cjs/client/errors.cjs +116 -0
  35. package/_cjs/client/errors.cjs.map +1 -0
  36. package/_cjs/client/fetch.cjs +178 -0
  37. package/_cjs/client/fetch.cjs.map +1 -0
  38. package/_cjs/client.cjs +61 -0
  39. package/_cjs/client.cjs.map +1 -0
  40. package/_cjs/faker.cjs +31 -0
  41. package/_cjs/faker.cjs.map +1 -0
  42. package/_cjs/ids.cjs +24 -0
  43. package/_cjs/ids.cjs.map +1 -0
  44. package/_cjs/index.cjs +27 -0
  45. package/_cjs/index.cjs.map +1 -0
  46. package/_cjs/refinements.cjs +97 -0
  47. package/_cjs/refinements.cjs.map +1 -0
  48. package/_cjs/schema.cjs +50 -0
  49. package/_cjs/schema.cjs.map +1 -0
  50. package/_cjs/schema.test.cjs +9 -0
  51. package/_cjs/schema.test.cjs.map +1 -0
  52. package/_cjs/service.cjs +97 -0
  53. package/_cjs/service.cjs.map +1 -0
  54. package/_cjs/utils.cjs +17 -0
  55. package/_cjs/utils.cjs.map +1 -0
  56. package/_src/Config/SecretURL.ts +103 -0
  57. package/_src/Config/internal/configSecretURL.ts +85 -0
  58. package/_src/Inputify.type.ts +13 -0
  59. package/_src/Operations.ts +70 -0
  60. package/_src/Pure.ts +525 -0
  61. package/_src/Request.ts +106 -0
  62. package/_src/Widen.type.ts +28 -0
  63. package/_src/_ext/date.ts +84 -0
  64. package/_src/_ext/misc.ts +161 -0
  65. package/_src/_global/stm.ts.bak +35 -0
  66. package/_src/_global.ext.ts +3 -0
  67. package/_src/_global.schema.ts +106 -0
  68. package/_src/_global.ts +119 -0
  69. package/_src/client/QueryResult.ts +120 -0
  70. package/_src/client/clientFor.ts +260 -0
  71. package/_src/client/config.ts +13 -0
  72. package/_src/client/errors.ts +129 -0
  73. package/_src/client/fetch.ts +253 -0
  74. package/_src/client.ts +7 -0
  75. package/_src/faker.ts +32 -0
  76. package/_src/ids.ts +35 -0
  77. package/_src/index.ts +4 -0
  78. package/_src/refinements.ts +92 -0
  79. package/_src/schema/_schema.ts.bak +208 -0
  80. package/_src/schema/api/date.ts.bak +78 -0
  81. package/_src/schema/api.ts.bak +20 -0
  82. package/_src/schema/overrides.ts.bak +76 -0
  83. package/_src/schema/shared.ts.bak +334 -0
  84. package/_src/schema.test.ts +3 -0
  85. package/_src/schema.ts +37 -0
  86. package/_src/service.ts +119 -0
  87. package/_src/utils.ts +1 -0
  88. package/dist/Config/SecretURL.d.ts +82 -0
  89. package/dist/Config/SecretURL.d.ts.map +1 -0
  90. package/dist/Config/SecretURL.js +49 -0
  91. package/dist/Config/internal/configSecretURL.d.ts +24 -0
  92. package/dist/Config/internal/configSecretURL.d.ts.map +1 -0
  93. package/dist/Config/internal/configSecretURL.js +75 -0
  94. package/dist/Inputify.type.d.ts +10 -0
  95. package/dist/Inputify.type.d.ts.map +1 -0
  96. package/dist/Inputify.type.js +2 -0
  97. package/dist/Operations.d.ts +170 -0
  98. package/dist/Operations.d.ts.map +1 -0
  99. package/dist/Operations.js +87 -0
  100. package/dist/Pure.d.ts +169 -0
  101. package/dist/Pure.d.ts.map +1 -0
  102. package/dist/Pure.js +167 -0
  103. package/dist/Request.d.ts +49 -0
  104. package/dist/Request.d.ts.map +1 -0
  105. package/dist/Request.js +58 -0
  106. package/dist/Widen.type.d.ts +19 -0
  107. package/dist/Widen.type.d.ts.map +1 -0
  108. package/dist/Widen.type.js +2 -0
  109. package/dist/_ext/date.d.ts +71 -0
  110. package/dist/_ext/date.d.ts.map +1 -0
  111. package/dist/_ext/date.js +58 -0
  112. package/dist/_ext/misc.d.ts +77 -0
  113. package/dist/_ext/misc.d.ts.map +1 -0
  114. package/dist/_ext/misc.js +98 -0
  115. package/dist/_global.d.ts +70 -0
  116. package/dist/_global.d.ts.map +1 -0
  117. package/dist/_global.ext.d.ts +3 -0
  118. package/dist/_global.ext.d.ts.map +1 -0
  119. package/dist/_global.ext.js +4 -0
  120. package/dist/_global.js +76 -0
  121. package/dist/_global.schema.d.ts +6 -0
  122. package/dist/_global.schema.d.ts.map +1 -0
  123. package/dist/_global.schema.js +6 -0
  124. package/dist/client/QueryResult.d.ts +85 -0
  125. package/dist/client/QueryResult.d.ts.map +1 -0
  126. package/dist/client/QueryResult.js +85 -0
  127. package/dist/client/clientFor.d.ts +44 -0
  128. package/dist/client/clientFor.d.ts.map +1 -0
  129. package/dist/client/clientFor.js +144 -0
  130. package/dist/client/config.d.ts +14 -0
  131. package/dist/client/config.d.ts.map +1 -0
  132. package/dist/client/config.js +11 -0
  133. package/dist/client/errors.d.ts +206 -0
  134. package/dist/client/errors.d.ts.map +1 -0
  135. package/dist/client/errors.js +130 -0
  136. package/dist/client/fetch.d.ts +61 -0
  137. package/dist/client/fetch.d.ts.map +1 -0
  138. package/dist/client/fetch.js +127 -0
  139. package/dist/client.d.ts +6 -0
  140. package/dist/client.d.ts.map +1 -0
  141. package/dist/client.js +7 -0
  142. package/dist/faker.d.ts +7 -0
  143. package/dist/faker.d.ts.map +1 -0
  144. package/dist/faker.js +24 -0
  145. package/dist/ids.d.ts +32 -0
  146. package/dist/ids.d.ts.map +1 -0
  147. package/dist/ids.js +17 -0
  148. package/dist/index.d.ts +4 -0
  149. package/dist/index.d.ts.map +1 -0
  150. package/dist/index.js +4 -0
  151. package/dist/refinements.d.ts +57 -0
  152. package/dist/refinements.d.ts.map +1 -0
  153. package/dist/refinements.js +85 -0
  154. package/dist/schema.d.ts +7 -0
  155. package/dist/schema.d.ts.map +1 -0
  156. package/dist/schema.js +22 -0
  157. package/dist/schema.test.d.ts.map +1 -0
  158. package/dist/service.d.ts +47 -0
  159. package/dist/service.d.ts.map +1 -0
  160. package/dist/service.js +83 -0
  161. package/dist/utils.d.ts +2 -0
  162. package/dist/utils.d.ts.map +1 -0
  163. package/dist/utils.js +2 -0
  164. package/package.json +315 -0
  165. package/tsconfig.json +114 -0
  166. package/tsconfig.json.bak +47 -0
  167. package/tsplus.config.json +7 -0
  168. package/vitest.config.ts +5 -0
  169. package/wallaby.cjs +1 -0
package/_src/ids.ts ADDED
@@ -0,0 +1,35 @@
1
+ import { brandedStringId, withDefaults } from "effect-app/schema"
2
+ import type { StringIdBrand } from "effect-app/schema"
3
+ import type { B } from "@effect-app/schema/schema"
4
+ import type { Simplify } from "effect/Types"
5
+ import { extendM } from "./utils.js"
6
+
7
+ export interface RequestIdBrand extends StringIdBrand {
8
+ readonly RequestId: unique symbol
9
+ }
10
+
11
+ /**
12
+ * @tsplus type RequestId
13
+ */
14
+ export type RequestId = NonEmptyString255
15
+ // a request id may be made from a span id, which does not comply with StringId schema.
16
+ export const RequestId = extendM(
17
+ Object
18
+ // eslint-disable-next-line @typescript-eslint/ban-types
19
+ .assign(Object.create(NonEmptyString255) as {}, NonEmptyString255 as Schema<NonEmptyString255, string>),
20
+ (s) => {
21
+ const make = StringId.make as () => NonEmptyString255
22
+ return ({
23
+ make,
24
+ withDefault: S.withDefaultConstructor(s, make)
25
+ })
26
+ }
27
+ )
28
+ .pipe(withDefaults)
29
+
30
+ export interface UserProfileIdBrand extends Simplify<B.Brand<"UserProfileId"> & StringIdBrand> {}
31
+ /**
32
+ * @tsplus type UserProfileId
33
+ */
34
+ export type UserProfileId = StringId & UserProfileIdBrand
35
+ export const UserProfileId = brandedStringId<UserProfileIdBrand>()
package/_src/index.ts ADDED
@@ -0,0 +1,4 @@
1
+ import "@effect-app/fluent-extensions"
2
+
3
+ export * from "@effect-app/core"
4
+ export * as S from "effect-app/schema"
@@ -0,0 +1,92 @@
1
+ import type { Clone } from "@fp-ts/optic"
2
+ import { InvalidStateError } from "./client.js"
3
+ import { clone, copy } from "./utils.js"
4
+
5
+ /**
6
+ * @tsplus getter function asCollectable
7
+ */
8
+ export function asCollectable<T, T2 extends T>(refinement: Refinement<T, T2>) {
9
+ return Option.liftPredicate(refinement)
10
+ }
11
+
12
+ /**
13
+ * @tsplus fluent function as
14
+ */
15
+ export function as<T, T2 extends T>(refinement: Refinement<T, T2>, name: string) {
16
+ return flow(
17
+ asCollectable(refinement),
18
+ (_) => _.encaseInEither(() => new InvalidStateError(`Cannot be ${name}`))
19
+ )
20
+ }
21
+
22
+ /**
23
+ * @tsplus fluent function refinements
24
+ */
25
+ export function makeAwesome<T, T2 extends T>(refinement: Refinement<T, T2>, name: string) {
26
+ const as = refinement.as(name)
27
+ const validate = {
28
+ is: refinement,
29
+ collect: refinement.asCollectable,
30
+ as,
31
+ lens: Optic.id<T2>()
32
+ }
33
+ function validatei(item: T) {
34
+ return {
35
+ get collect() {
36
+ return validate.collect(item)
37
+ },
38
+ get as() {
39
+ return validate.as(item)
40
+ }
41
+ }
42
+ }
43
+ return {
44
+ ...validate,
45
+ $item: validatei
46
+ }
47
+ }
48
+
49
+ // The idea is that such refinements are dynamic
50
+ export interface Collect<A, B extends A> {
51
+ (a: A): Option<B>
52
+ }
53
+
54
+ /**
55
+ * @tsplus fluent function as
56
+ */
57
+ export function asOption<T, T2 extends T>(collect: Collect<T, T2>, name: string) {
58
+ return flow(collect, (_) => _.encaseInEither(() => new InvalidStateError({ message: `Cannot be ${name}` })))
59
+ }
60
+
61
+ /**
62
+ * @tsplus fluent function refinements
63
+ */
64
+ export function makeAwesomeCollect<T extends Object, T2 extends T>(collect: Collect<T, T2>, name: string) {
65
+ const as = collect.as(name)
66
+ function is(item: T): item is T2 {
67
+ return collect(item).isSome()
68
+ }
69
+ const validate = {
70
+ collect,
71
+ is,
72
+ as,
73
+ lens: Optic.id<T2>(),
74
+ copy: (item: T2, _copy: Partial<Omit<T2, keyof Clone | keyof Equal>>) => copy(item, _copy),
75
+ clone: (item: T, cloned: T) => clone(item, cloned)
76
+ }
77
+ function validatei(item: T) {
78
+ return {
79
+ get collect() {
80
+ return validate.collect(item)
81
+ },
82
+ get as() {
83
+ return validate.as(item)
84
+ }
85
+ }
86
+ }
87
+ return {
88
+ ...validate,
89
+ $item: validatei
90
+ }
91
+ }
92
+ export type GetCollectedType<T> = T extends { collect: Collect<any, infer U> } ? U : never
@@ -0,0 +1,208 @@
1
+ /* eslint-disable @typescript-eslint/no-unsafe-return */
2
+ /* eslint-disable @typescript-eslint/no-explicit-any */
3
+ /* eslint-disable @typescript-eslint/ban-types */
4
+
5
+ import { identity } from "@effect-app/core/Function"
6
+ import type { AnyError, Parser } from "effect-app/schema"
7
+ import {
8
+ Guard,
9
+ maxLengthIdentifier,
10
+ minLengthIdentifier,
11
+ NonEmptyString255,
12
+ NonEmptyString2k,
13
+ nullableIdentifier
14
+ } from "effect-app/schema"
15
+ import * as S from "effect-app/schema"
16
+ import type { Faker } from "@faker-js/faker"
17
+ import { fakerToArb, getFaker } from "../faker.js"
18
+
19
+ export { matchTag } from "@effect-app/core/utils"
20
+
21
+ /**
22
+ * A little helper to allow writing `interface X extends Identity<typeof Y>`
23
+ * so you don't need an intermediate type for `typeof Y`
24
+ */
25
+ export type Identity<T> = T
26
+
27
+ export function fitIntoNonEmptyString255(str: string) {
28
+ if (Guard.is(NonEmptyString255)(str)) {
29
+ return str
30
+ }
31
+
32
+ return NonEmptyString255(str.substring(0, 255 - 3) + "...")
33
+ }
34
+
35
+ export function fitIntoNonEmptyString2k(str: string) {
36
+ if (Guard.is(NonEmptyString2k)(str)) {
37
+ return str
38
+ }
39
+
40
+ return NonEmptyString2k(str.substring(0, 2047 - 3) + "...")
41
+ }
42
+
43
+ export const fakerArb = (
44
+ gen: (fake: Faker) => () => string
45
+ ): (a: any) => S.Arbitrary.Arbitrary<string> => fakerToArb(gen(getFaker()))
46
+
47
+ export function tryParse<X, A>(self: Parser.Parser<X, AnyError, A>) {
48
+ return (a: X, env?: Parser.ParserEnv) => {
49
+ const res = self(a, env).effect
50
+ if (res._tag === "Left") {
51
+ return Option.none()
52
+ }
53
+ const warn = res.right[1]
54
+ if (warn._tag === "Some") {
55
+ return Option.none()
56
+ }
57
+ return Option.some(res.right[0])
58
+ }
59
+ }
60
+
61
+ export function isSchema(
62
+ p: Schema<any, any> | S.AnyField
63
+ ): p is Schema<any, any> {
64
+ return !!(p as any)[S.SchemaSym]
65
+ }
66
+
67
+ export function getMetadataFromSchemaOrProp(p: Schema<any, any> | S.AnyField) {
68
+ if (isSchema(p)) {
69
+ return getMetadataFromSchema(p)
70
+ }
71
+ return getMetadataFromProp(p)
72
+ }
73
+
74
+ // 1. get metadata from properties, use it to constrain fields
75
+ // 2. use the metadata for custom validation error messges?
76
+ // 3. or leverage the actual validation errors that come from parsing the fields.
77
+ // function getMetadataFromProp_<Field extends S.AnyField>(p: Field) {
78
+ // return {
79
+ // required: p._optional === "required",
80
+ // }
81
+ // }
82
+ export function getMetadataFromProp<Field extends S.AnyField>(p: Field) {
83
+ const schemaMetadata = getMetadataFromSchema(p._schema)
84
+ // const propMetadata = getMetadataFromProp_(p)
85
+
86
+ return schemaMetadata
87
+ // return {
88
+ // ...schemaMetadata,
89
+ // required: propMetadata.required && schemaMetadata.required,
90
+ // }
91
+ }
92
+
93
+ const numberIds = [
94
+ S.numberIdentifier
95
+ // S.stringNumberFromStringIdentifier, actually input is string
96
+ ]
97
+ const intIds = [
98
+ S.intIdentifier,
99
+ S.intFromNumberIdentifier
100
+ ]
101
+ const rangeNumberIds = [
102
+ S.rangeIdentifier,
103
+ S.minIdentifier,
104
+ S.maxIdentifier
105
+ ]
106
+
107
+ export function getMetadataFromSchema<Self extends Schema<any, any>>(self: Self) {
108
+ const nullable = S.findAnnotation(self, nullableIdentifier)
109
+ const realSelf = nullable?.self ?? self
110
+ const minLength = S.findAnnotation(realSelf, minLengthIdentifier)
111
+ const maxLength = S.findAnnotation(realSelf, maxLengthIdentifier)
112
+
113
+ const min = S.findAnnotation(realSelf, S.minIdentifier)
114
+ const max = S.findAnnotation(realSelf, S.maxIdentifier)
115
+ const range = S.findAnnotation(realSelf, S.rangeIdentifier)
116
+
117
+ const isNumber = numberIds.some((_) => S.findAnnotation(realSelf, _))
118
+ const isInt = intIds.some((_) => S.findAnnotation(realSelf, _))
119
+ const asMin = min || range
120
+ const asMax = max || range
121
+ const typeN = asMin || asMax
122
+ return {
123
+ type: typeN ? typeN.type : isInt ? "int" as const : isNumber ? "float" as const : "text" as const,
124
+ minimum: asMin?.minimum,
125
+ minimumExclusive: asMin?.minimumExclusive,
126
+ maximum: asMax?.maximum,
127
+ maximumExclusive: asMax?.maximumExclusive,
128
+ minLength: minLength?.minLength,
129
+ maxLength: maxLength?.maxLength,
130
+ required: !nullable
131
+ }
132
+ }
133
+
134
+ export function getRegisterFromSchemaOrProp(p: Schema<any, any> | S.AnyField) {
135
+ if (isSchema(p)) {
136
+ return getRegisterFromSchema(p)
137
+ }
138
+ return getRegisterFromProp(p)
139
+ }
140
+
141
+ // 1. get metadata from properties, use it to constrain fields
142
+ // 2. use the metadata for custom validation error messges?
143
+ // 3. or leverage the actual validation errors that come from parsing the fields.
144
+
145
+ export function getRegisterFromProp<Field extends S.AnyField>(p: Field) {
146
+ const schemaMetadata = getRegisterFromSchema(p._schema)
147
+ // const metadata = getMetadataFromProp_(p)
148
+
149
+ return {
150
+ ...schemaMetadata
151
+ // optional fields should not translate values to undefined, as empty value is not absence
152
+ // ...(!metadata.required
153
+ // ? {
154
+ // transform: {
155
+ // output: (value: any) => (value ? value : undefined),
156
+ // input: (value: any) => (!value ? "" : value),
157
+ // },
158
+ // }
159
+ // : {}),
160
+ }
161
+ }
162
+
163
+ export function getRegisterFromSchema<Self extends Schema<any, any>>(self: Self) {
164
+ // or take from openapi = number type?
165
+ const metadata = getMetadataFromSchema(self)
166
+ const nullable = S.findAnnotation(self, nullableIdentifier)
167
+
168
+ const mapType = numberIds.concat(rangeNumberIds).some((x) => S.findAnnotation(nullable?.self ?? self, x))
169
+ ? ("asNumber" as const)
170
+ : ("normal" as const)
171
+ const map = mapValueType(mapType)
172
+
173
+ return {
174
+ ...(!metadata.required
175
+ ? {
176
+ transform: {
177
+ output: (value: any) => map(value === "" ? null : value),
178
+ // for date fields we should not undo null..
179
+ // actually for string fields they appropriately convert to empty string probably anyway, so lets remove
180
+ // input: (value: any) => (value === null || value === undefined ? "" : value),
181
+ input: identity
182
+ }
183
+ }
184
+ : { transform: { output: map, input: identity } })
185
+ }
186
+ }
187
+
188
+ function asNumber(value: any) {
189
+ return value === null || value === undefined
190
+ ? value
191
+ : value === ""
192
+ ? NaN
193
+ : typeof value === "string"
194
+ ? +value.replace(",", ".")
195
+ : +value
196
+ }
197
+
198
+ function asDate(value: any) {
199
+ return value === null || value === undefined ? value : new Date(value)
200
+ }
201
+
202
+ function mapValueType(type: "asNumber" | "asDate" | "normal") {
203
+ return type === "asNumber" ? asNumber : type === "asDate" ? asDate : identity
204
+ }
205
+
206
+ export * from "effect-app/schema"
207
+ export * from "./overrides.js"
208
+ export { array, nonEmptyArray, set } from "./overrides.js"
@@ -0,0 +1,78 @@
1
+ /* eslint-disable @typescript-eslint/no-explicit-any */
2
+ /* eslint-disable @typescript-eslint/ban-types */
3
+ import { pipe } from "@effect-app/core/Function"
4
+ import { arbitrary, date, encoder, leafE, parseDateE, Parser, parser } from "effect-app/schema"
5
+ import * as Th from "@effect-app/schema/custom/These"
6
+
7
+ import { todayAtUTCNoon } from "../../utils.js"
8
+
9
+ export { matchTag } from "@effect-app/core/utils"
10
+
11
+ // workaround for strange date extension issue.
12
+ const subNow = (amount: number): Date => todayAtUTCNoon().subDays(amount)
13
+ const addNow = (amount: number): Date => todayAtUTCNoon().addDays(amount)
14
+
15
+ const dateParser = Parser.for(date)
16
+
17
+ function isProbablyADate(u: unknown): u is Date {
18
+ return (u instanceof Object && "toISOString" in u && "getTime" in u)
19
+ }
20
+
21
+ /**
22
+ * As we want to use actual Date Objects in inputs,
23
+ * and instead of leveraging the parser as a decoder from JSON, we wish to use it as a validator from Inputs.
24
+ * This won't work with JSON because a Date is represented as an ISO string inside JSON, and when JSON is parsed, it remains a string.
25
+ */
26
+ export const inputDate = pipe(
27
+ date,
28
+ parser((u, env) =>
29
+ // if it quacks like a ... Date..
30
+ u instanceof Date || isProbablyADate(u)
31
+ ? Number.isNaN(u.getTime())
32
+ ? Th.fail(leafE(parseDateE(u)))
33
+ : Th.succeed(u)
34
+ : dateParser(u, env)
35
+ ),
36
+ encoder((i): Date => i.toISOString() as unknown as Date /* sue me*/),
37
+ arbitrary((FC) =>
38
+ FC.date({
39
+ min: subNow(350),
40
+ max: addNow(350)
41
+ })
42
+ )
43
+ )
44
+
45
+ export type inputDate = Date
46
+ export type InputDate = inputDate
47
+
48
+ export const reasonablePastDate = date.pipe(
49
+ arbitrary((FC) =>
50
+ FC.date({
51
+ min: subNow(350),
52
+ max: subNow(1)
53
+ })
54
+ )
55
+ )
56
+ export type reasonablePastDate = Date
57
+ export type ReasonablePastDate = reasonablePastDate
58
+
59
+ export const reasonableFutureDate = date.pipe(
60
+ arbitrary((FC) =>
61
+ FC.date({
62
+ min: addNow(350),
63
+ max: addNow(1)
64
+ })
65
+ )
66
+ )
67
+ export type ReasonableFutureDate = Date
68
+
69
+ export const reasonableDate = date.pipe(
70
+ arbitrary((FC) =>
71
+ FC.date({
72
+ min: subNow(350),
73
+ max: addNow(350)
74
+ })
75
+ )
76
+ )
77
+ export type reasonableDate = Date
78
+ export type ReasonableDate = reasonableDate
@@ -0,0 +1,20 @@
1
+ import { brand } from "./_schema.js"
2
+ import { PositiveNumber } from "./overrides.js"
3
+
4
+ // codegen:start {preset: barrel, include: ./api/*.ts}
5
+ export * from "./api/date.js"
6
+ // codegen:end
7
+
8
+ // TODO: true decimal
9
+ /**
10
+ * @deprecated - implement true decimal!
11
+ */
12
+ export const PositiveDecimal = PositiveNumber.pipe(brand<PositiveDecimal>())
13
+ /**
14
+ * @deprecated - implement true decimal!
15
+ */
16
+ export type PositiveDecimal = PositiveNumber & DecimalBrand
17
+
18
+ export interface DecimalBrand {
19
+ readonly Decimal: unique symbol
20
+ }
@@ -0,0 +1,76 @@
1
+ /* eslint-disable @typescript-eslint/no-explicit-any */
2
+ /* eslint-disable @typescript-eslint/ban-types */
3
+
4
+ import { ReadonlySet } from "@effect-app/core/Prelude"
5
+ import { arbitrary, type PositiveBrand, positiveExcludeZero, type PositiveExcludeZeroBrand } from "effect-app/schema"
6
+ import { brand, positive } from "effect-app/schema"
7
+ import { number } from "effect/Equivalence"
8
+ import { Arbitrary } from "fast-check"
9
+
10
+ export const PositiveNumber = positive("float")(number).pipe(brand<PositiveNumber>())
11
+ export type PositiveNumber = number & PositiveBrand
12
+
13
+ export const PositiveNumberZeroExclusive = positiveExcludeZero("float")(number).pipe(brand<PositiveNumber>())
14
+ export type PositiveNumberZeroExclusive = number & PositiveExcludeZeroBrand
15
+
16
+ export interface CentimeterBrand extends PositiveBrand {
17
+ readonly CentimeterBrand: unique symbol
18
+ }
19
+
20
+ export type Centimeter = number & CentimeterBrand
21
+
22
+ export const Centimeter = positive("float")(number).pipe(brand<Centimeter>())
23
+
24
+ export interface KilogramBrand extends PositiveBrand {
25
+ readonly KilogramBrand: unique symbol
26
+ }
27
+
28
+ export type Kilogram = number & KilogramBrand
29
+
30
+ export const Kilogram = positive("float")(number).pipe(brand<Kilogram>())
31
+
32
+ // Limit arbitrary collections to generate a max of 6 entries
33
+ // TODO: dictionary, map
34
+ const MAX_LENGTH = 6
35
+
36
+ export function nonEmptyArray<To, ConstructorInput, From, Api>(
37
+ self: Schema<unknown, To, ConstructorInput, From, Api>
38
+ ) {
39
+ const arbitrarySelf = Arbitrary.for(self)
40
+
41
+ return nonEmptyArrayOriginal(self).pipe(
42
+ arbitrary(
43
+ (_) =>
44
+ _.array(arbitrarySelf(_), {
45
+ minLength: 1,
46
+ maxLength: MAX_LENGTH
47
+ }) as any as Arbitrary.Arbitrary<NonEmptyReadonlyArray<To>>
48
+ )
49
+ )
50
+ }
51
+
52
+ export function array<To, ConstructorInput, From, Api>(
53
+ self: Schema<unknown, To, ConstructorInput, From, Api>
54
+ ) {
55
+ const arbitrarySelf = Arbitrary.for(self)
56
+
57
+ return arrayOriginal(self).pipe(
58
+ arbitrary(
59
+ (_) =>
60
+ _.array(arbitrarySelf(_), {
61
+ maxLength: MAX_LENGTH
62
+ }) as any as Arbitrary.Arbitrary<Array<To>>
63
+ )
64
+ )
65
+ }
66
+
67
+ export function set<To, ConstructorInput, From, Api>(
68
+ self: Schema<unknown, To, ConstructorInput, From, Api>,
69
+ ord: Order<To>,
70
+ eq: Equivalence<To>
71
+ ) {
72
+ const arbitrarySelf = Arbitrary.for(self)
73
+ return setOriginal(self, ord, eq).pipe(
74
+ arbitrary((_) => _.uniqueArray(arbitrarySelf(_), { maxLength: MAX_LENGTH }).map(ReadonlySet.fromArray(eq)))
75
+ )
76
+ }