effect-app 1.32.0 → 2.0.1

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 (310) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/_cjs/Array.cjs +132 -0
  3. package/_cjs/Array.cjs.map +1 -0
  4. package/_cjs/Chunk.cjs +128 -0
  5. package/_cjs/Chunk.cjs.map +1 -0
  6. package/_cjs/Config/SecretURL.cjs +3 -3
  7. package/_cjs/Config/SecretURL.cjs.map +1 -1
  8. package/_cjs/Config/internal/configSecretURL.cjs +2 -2
  9. package/_cjs/Config/internal/configSecretURL.cjs.map +1 -1
  10. package/_cjs/Context.cjs +243 -0
  11. package/_cjs/Context.cjs.map +1 -0
  12. package/_cjs/Dictionary.cjs +522 -0
  13. package/_cjs/Dictionary.cjs.map +1 -0
  14. package/_cjs/Effect.cjs +202 -0
  15. package/_cjs/Effect.cjs.map +1 -0
  16. package/_cjs/Function.cjs +107 -0
  17. package/_cjs/Function.cjs.map +1 -0
  18. package/_cjs/NonEmptySet.cjs +26 -0
  19. package/_cjs/NonEmptySet.cjs.map +1 -0
  20. package/_cjs/NonEmptySetAspects.cjs +17 -0
  21. package/_cjs/NonEmptySetAspects.cjs.map +1 -0
  22. package/_cjs/NonEmptySetBase.cjs +82 -0
  23. package/_cjs/NonEmptySetBase.cjs.map +1 -0
  24. package/_cjs/Object.cjs +24 -0
  25. package/_cjs/Object.cjs.map +1 -0
  26. package/_cjs/Operations.cjs +1 -1
  27. package/_cjs/Option.cjs +88 -0
  28. package/_cjs/Option.cjs.map +1 -0
  29. package/_cjs/Prelude.cjs +53 -0
  30. package/_cjs/Prelude.cjs.map +1 -0
  31. package/_cjs/Prelude.code.cjs +53 -0
  32. package/_cjs/Prelude.code.cjs.map +1 -0
  33. package/_cjs/Pure.cjs +39 -36
  34. package/_cjs/Pure.cjs.map +1 -1
  35. package/_cjs/Schema/Class.cjs +61 -0
  36. package/_cjs/Schema/Class.cjs.map +1 -0
  37. package/_cjs/Schema/FastCheck.cjs +39 -0
  38. package/_cjs/Schema/FastCheck.cjs.map +1 -0
  39. package/_cjs/Schema/Methods.cjs +6 -0
  40. package/_cjs/Schema/Methods.cjs.map +1 -0
  41. package/_cjs/Schema/brand.cjs +17 -0
  42. package/_cjs/Schema/brand.cjs.map +1 -0
  43. package/_cjs/Schema/email.cjs +20 -0
  44. package/_cjs/Schema/email.cjs.map +1 -0
  45. package/_cjs/Schema/ext.cjs +174 -0
  46. package/_cjs/Schema/ext.cjs.map +1 -0
  47. package/_cjs/Schema/moreStrings.cjs +124 -0
  48. package/_cjs/Schema/moreStrings.cjs.map +1 -0
  49. package/_cjs/Schema/numbers.cjs +52 -0
  50. package/_cjs/Schema/numbers.cjs.map +1 -0
  51. package/_cjs/Schema/phoneNumber.cjs +22 -0
  52. package/_cjs/Schema/phoneNumber.cjs.map +1 -0
  53. package/_cjs/Schema/schema.cjs +15 -0
  54. package/_cjs/Schema/schema.cjs.map +1 -0
  55. package/_cjs/Schema/strings.cjs +32 -0
  56. package/_cjs/Schema/strings.cjs.map +1 -0
  57. package/_cjs/Schema.cjs +334 -0
  58. package/_cjs/Schema.cjs.map +1 -0
  59. package/_cjs/Set.cjs +567 -0
  60. package/_cjs/Set.cjs.map +1 -0
  61. package/_cjs/Struct.cjs +51 -0
  62. package/_cjs/Struct.cjs.map +1 -0
  63. package/_cjs/Tag.cjs +25 -0
  64. package/_cjs/Tag.cjs.map +1 -0
  65. package/_cjs/Unify.cjs +40 -0
  66. package/_cjs/Unify.cjs.map +1 -0
  67. package/_cjs/_ext/misc.cjs +16 -16
  68. package/_cjs/_ext/misc.cjs.map +1 -1
  69. package/_cjs/_ext/ord.ext.cjs +52 -0
  70. package/_cjs/_ext/ord.ext.cjs.map +1 -0
  71. package/_cjs/builtin.cjs +6 -0
  72. package/_cjs/builtin.cjs.map +1 -0
  73. package/_cjs/client/clientFor.cjs +5 -3
  74. package/_cjs/client/clientFor.cjs.map +1 -1
  75. package/_cjs/client/config.cjs +4 -4
  76. package/_cjs/client/config.cjs.map +1 -1
  77. package/_cjs/client/errors.cjs +9 -9
  78. package/_cjs/client/errors.cjs.map +1 -1
  79. package/_cjs/http/http-client.cjs +35 -0
  80. package/_cjs/http/http-client.cjs.map +1 -0
  81. package/_cjs/ids.cjs +5 -5
  82. package/_cjs/ids.cjs.map +1 -1
  83. package/_cjs/index.cjs +1 -1
  84. package/_cjs/lib.cjs +178 -9
  85. package/_cjs/lib.cjs.map +1 -1
  86. package/_cjs/logger.cjs +1 -1
  87. package/_cjs/transform.cjs +45 -0
  88. package/_cjs/transform.cjs.map +1 -0
  89. package/_cjs/utils/effectify.cjs +25 -0
  90. package/_cjs/utils/effectify.cjs.map +1 -0
  91. package/_cjs/utils/extend.cjs +17 -0
  92. package/_cjs/utils/extend.cjs.map +1 -0
  93. package/_cjs/utils/logger.cjs +23 -0
  94. package/_cjs/utils/logger.cjs.map +1 -0
  95. package/_cjs/utils.cjs +431 -4
  96. package/_cjs/utils.cjs.map +1 -1
  97. package/_cjs/validation/validators.cjs +32 -0
  98. package/_cjs/validation/validators.cjs.map +1 -0
  99. package/_cjs/validation.cjs +45 -0
  100. package/_cjs/validation.cjs.map +1 -0
  101. package/dist/Array.d.ts +64 -0
  102. package/dist/Array.d.ts.map +1 -0
  103. package/dist/Array.js +89 -0
  104. package/dist/Chunk.d.ts +68 -0
  105. package/dist/Chunk.d.ts.map +1 -0
  106. package/dist/Chunk.js +93 -0
  107. package/dist/Config/SecretURL.d.ts +3 -3
  108. package/dist/Config/SecretURL.d.ts.map +1 -1
  109. package/dist/Config/SecretURL.js +2 -2
  110. package/dist/Config/internal/configSecretURL.js +2 -2
  111. package/dist/Context.d.ts +55 -0
  112. package/dist/Context.d.ts.map +1 -0
  113. package/dist/Context.js +204 -0
  114. package/dist/Dictionary.d.ts +260 -0
  115. package/dist/Dictionary.d.ts.map +1 -0
  116. package/dist/Dictionary.js +448 -0
  117. package/dist/Effect.d.ts +115 -0
  118. package/dist/Effect.d.ts.map +1 -0
  119. package/dist/Effect.js +153 -0
  120. package/dist/Function.d.ts +72 -0
  121. package/dist/Function.d.ts.map +1 -0
  122. package/dist/Function.js +71 -0
  123. package/dist/Inputify.type.d.ts +1 -1
  124. package/dist/Inputify.type.d.ts.map +1 -1
  125. package/dist/NonEmptySet.d.ts +3 -0
  126. package/dist/NonEmptySet.d.ts.map +1 -0
  127. package/dist/NonEmptySet.js +3 -0
  128. package/dist/NonEmptySetAspects.d.ts +2 -0
  129. package/dist/NonEmptySetAspects.d.ts.map +1 -0
  130. package/dist/NonEmptySetAspects.js +2 -0
  131. package/dist/NonEmptySetBase.d.ts +39 -0
  132. package/dist/NonEmptySetBase.d.ts.map +1 -0
  133. package/dist/NonEmptySetBase.js +63 -0
  134. package/dist/Object.d.ts +7 -0
  135. package/dist/Object.d.ts.map +1 -0
  136. package/dist/Object.js +7 -0
  137. package/dist/Operations.d.ts +2 -2
  138. package/dist/Operations.js +1 -1
  139. package/dist/Option.d.ts +39 -0
  140. package/dist/Option.d.ts.map +1 -0
  141. package/dist/Option.js +55 -0
  142. package/dist/Prelude.code.d.ts +25 -0
  143. package/dist/Prelude.code.d.ts.map +1 -0
  144. package/dist/Prelude.code.js +24 -0
  145. package/dist/Prelude.d.ts +163 -0
  146. package/dist/Prelude.d.ts.map +1 -0
  147. package/dist/Prelude.js +24 -0
  148. package/dist/Pure.d.ts +13 -12
  149. package/dist/Pure.d.ts.map +1 -1
  150. package/dist/Pure.js +18 -17
  151. package/dist/Schema/Class.d.ts +45 -0
  152. package/dist/Schema/Class.d.ts.map +1 -0
  153. package/dist/Schema/Class.js +50 -0
  154. package/dist/Schema/FastCheck.d.ts +10 -0
  155. package/dist/Schema/FastCheck.d.ts.map +1 -0
  156. package/dist/Schema/FastCheck.js +12 -0
  157. package/dist/Schema/Methods.d.ts +6 -0
  158. package/dist/Schema/Methods.d.ts.map +1 -0
  159. package/dist/Schema/Methods.js +2 -0
  160. package/dist/Schema/brand.d.ts +35 -0
  161. package/dist/Schema/brand.d.ts.map +1 -0
  162. package/dist/Schema/brand.js +7 -0
  163. package/dist/Schema/email.d.ts +9 -0
  164. package/dist/Schema/email.d.ts.map +1 -0
  165. package/dist/Schema/email.js +12 -0
  166. package/dist/Schema/ext.d.ts +89 -0
  167. package/dist/Schema/ext.d.ts.map +1 -0
  168. package/dist/Schema/ext.js +111 -0
  169. package/dist/Schema/moreStrings.d.ts +109 -0
  170. package/dist/Schema/moreStrings.d.ts.map +1 -0
  171. package/dist/Schema/moreStrings.js +108 -0
  172. package/dist/Schema/numbers.d.ts +46 -0
  173. package/dist/Schema/numbers.d.ts.map +1 -0
  174. package/dist/Schema/numbers.js +28 -0
  175. package/dist/Schema/phoneNumber.d.ts +9 -0
  176. package/dist/Schema/phoneNumber.d.ts.map +1 -0
  177. package/dist/Schema/phoneNumber.js +14 -0
  178. package/dist/Schema/schema.d.ts +6 -0
  179. package/dist/Schema/schema.d.ts.map +1 -0
  180. package/dist/Schema/schema.js +5 -0
  181. package/dist/Schema/strings.d.ts +19 -0
  182. package/dist/Schema/strings.d.ts.map +1 -0
  183. package/dist/Schema/strings.js +32 -0
  184. package/dist/{schema.d.ts → Schema.d.ts} +25 -9
  185. package/dist/Schema.d.ts.map +1 -0
  186. package/dist/Schema.js +89 -0
  187. package/dist/Set.d.ts +221 -0
  188. package/dist/Set.d.ts.map +1 -0
  189. package/dist/Set.js +516 -0
  190. package/dist/Struct.d.ts +44 -0
  191. package/dist/Struct.d.ts.map +1 -0
  192. package/dist/Struct.js +29 -0
  193. package/dist/Tag.d.ts +9 -0
  194. package/dist/Tag.d.ts.map +1 -0
  195. package/dist/Tag.js +18 -0
  196. package/dist/Unify.d.ts +43 -0
  197. package/dist/Unify.d.ts.map +1 -0
  198. package/dist/Unify.js +31 -0
  199. package/dist/Widen.type.d.ts +1 -1
  200. package/dist/Widen.type.d.ts.map +1 -1
  201. package/dist/_ext/misc.d.ts +11 -11
  202. package/dist/_ext/misc.d.ts.map +1 -1
  203. package/dist/_ext/misc.js +8 -8
  204. package/dist/_ext/ord.ext.d.ts +23 -0
  205. package/dist/_ext/ord.ext.d.ts.map +1 -0
  206. package/dist/_ext/ord.ext.js +44 -0
  207. package/dist/builtin.d.ts +51 -0
  208. package/dist/builtin.d.ts.map +1 -0
  209. package/dist/builtin.js +2 -0
  210. package/dist/client/clientFor.d.ts +1 -1
  211. package/dist/client/clientFor.d.ts.map +1 -1
  212. package/dist/client/clientFor.js +2 -2
  213. package/dist/client/config.d.ts +1 -1
  214. package/dist/client/config.d.ts.map +1 -1
  215. package/dist/client/config.js +2 -2
  216. package/dist/client/errors.js +1 -1
  217. package/dist/http/http-client.d.ts +43 -0
  218. package/dist/http/http-client.d.ts.map +1 -0
  219. package/dist/http/http-client.js +30 -0
  220. package/dist/ids.d.ts +3 -3
  221. package/dist/ids.d.ts.map +1 -1
  222. package/dist/ids.js +2 -2
  223. package/dist/index.d.ts +1 -1
  224. package/dist/index.d.ts.map +1 -1
  225. package/dist/index.js +2 -2
  226. package/dist/lib.d.ts +22 -4
  227. package/dist/lib.d.ts.map +1 -1
  228. package/dist/lib.js +20 -5
  229. package/dist/logger.d.ts.map +1 -1
  230. package/dist/logger.js +2 -2
  231. package/dist/transform.d.ts +12 -0
  232. package/dist/transform.d.ts.map +1 -0
  233. package/dist/transform.js +39 -0
  234. package/dist/utils/effectify.d.ts +210 -0
  235. package/dist/utils/effectify.d.ts.map +1 -0
  236. package/dist/utils/effectify.js +19 -0
  237. package/dist/utils/extend.d.ts +3 -0
  238. package/dist/utils/extend.d.ts.map +1 -0
  239. package/dist/utils/extend.js +9 -0
  240. package/dist/utils/logger.d.ts +12 -0
  241. package/dist/utils/logger.d.ts.map +1 -0
  242. package/dist/utils/logger.js +15 -0
  243. package/dist/utils.d.ts +192 -1
  244. package/dist/utils.d.ts.map +1 -1
  245. package/dist/utils.js +332 -2
  246. package/dist/validation/validators.d.ts +11 -0
  247. package/dist/validation/validators.d.ts.map +1 -0
  248. package/dist/validation/validators.js +26 -0
  249. package/dist/validation.d.ts +13 -0
  250. package/dist/validation.d.ts.map +1 -0
  251. package/dist/validation.js +14 -0
  252. package/package.json +360 -9
  253. package/src/Array.ts +127 -0
  254. package/src/Chunk.ts +112 -0
  255. package/src/Config/SecretURL.ts +3 -3
  256. package/src/Config/internal/configSecretURL.ts +1 -1
  257. package/src/Context.ts +293 -0
  258. package/src/Dictionary.ts +669 -0
  259. package/src/Effect.ts +265 -0
  260. package/src/Function.ts +175 -0
  261. package/src/Inputify.type.ts +1 -1
  262. package/src/NonEmptySet.ts +3 -0
  263. package/src/NonEmptySetAspects.ts +1 -0
  264. package/src/NonEmptySetBase.ts +109 -0
  265. package/src/Object.ts +19 -0
  266. package/src/Operations.ts +1 -1
  267. package/src/Option.ts +82 -0
  268. package/src/Prelude.code.ts +27 -0
  269. package/src/Prelude.ts +220 -0
  270. package/src/Pure.ts +37 -30
  271. package/src/Schema/Class.ts +225 -0
  272. package/src/Schema/FastCheck.ts +23 -0
  273. package/src/Schema/Methods.ts +8 -0
  274. package/src/Schema/brand.ts +50 -0
  275. package/src/Schema/email.ts +22 -0
  276. package/src/Schema/ext.ts +273 -0
  277. package/src/Schema/moreStrings.ts +260 -0
  278. package/src/Schema/numbers.ts +83 -0
  279. package/src/Schema/phoneNumber.ts +24 -0
  280. package/src/Schema/schema.ts +6 -0
  281. package/src/Schema/strings.ts +60 -0
  282. package/src/{schema.ts → Schema.ts} +52 -20
  283. package/src/Set.ts +674 -0
  284. package/src/Struct.ts +54 -0
  285. package/src/Tag.ts +20 -0
  286. package/src/Unify.ts +56 -0
  287. package/src/Widen.type.ts +1 -1
  288. package/src/_ext/misc.ts +22 -22
  289. package/src/_ext/ord.ext.ts +49 -0
  290. package/src/builtin.ts +64 -0
  291. package/src/client/clientFor.ts +1 -1
  292. package/src/client/config.ts +1 -1
  293. package/src/client/errors.ts +1 -1
  294. package/src/http/http-client.ts +73 -0
  295. package/src/ids.ts +3 -3
  296. package/src/index.ts +1 -1
  297. package/src/lib.ts +88 -4
  298. package/src/logger.ts +1 -1
  299. package/src/transform.ts +80 -0
  300. package/src/utils/effectify.ts +259 -0
  301. package/src/utils/extend.ts +9 -0
  302. package/src/utils/logger.ts +24 -0
  303. package/src/utils.ts +805 -1
  304. package/src/validation/validators.ts +32 -0
  305. package/src/validation.ts +18 -0
  306. package/tsconfig.src.json +1 -5
  307. package/_cjs/schema.cjs +0 -110
  308. package/_cjs/schema.cjs.map +0 -1
  309. package/dist/schema.d.ts.map +0 -1
  310. package/dist/schema.js +0 -73
@@ -0,0 +1,23 @@
1
+ import type * as fc from "fast-check"
2
+
3
+ export type { Arbitrary } from "fast-check"
4
+ type FC = typeof fc
5
+
6
+ export type { FC }
7
+
8
+ export const ALPHABET = "abcdefghijklmnopqrstuvwxyz"
9
+ export const ALPHABET_UC = ALPHABET.toUpperCase()
10
+
11
+ // uppercase A-Z
12
+ const UC_char = (fc: Pick<FC, "integer">) => fc.integer({ min: 0x41, max: 0x5a }).map(String.fromCharCode)
13
+ export const UC_alphabet = (min: number, max: number) => (fc: FC) =>
14
+ fc.array(UC_char(fc), { minLength: min, maxLength: max }).map((arr) => arr.join(""))
15
+ // lowercase A-Z
16
+ const LC_char = (fc: Pick<FC, "integer">) => fc.integer({ min: 0x61, max: 0x7a }).map(String.fromCharCode)
17
+ export const LC_alphabet = (min: number, max: number) => (fc: Pick<FC, "array" | "integer">) =>
18
+ fc.array(LC_char(fc), { minLength: min, maxLength: max }).map((arr) => arr.join(""))
19
+
20
+ // numbers 0-9
21
+ const N_char = (fc: Pick<FC, "integer">) => fc.integer({ min: 0x30, max: 0x39 }).map(String.fromCharCode)
22
+ export const Numbers = (min: number, max: number) => (fc: Pick<FC, "array" | "integer">) =>
23
+ fc.array(N_char(fc), { minLength: min, maxLength: max }).map((arr) => arr.join(""))
@@ -0,0 +1,8 @@
1
+ export type ReadMethods = "GET"
2
+ export type WriteMethods = "POST" | "PUT" | "PATCH" | "DELETE"
3
+
4
+ export type Rest = ReadMethods | WriteMethods
5
+
6
+ export type System = "OPTIONS" | "HEAD" | "TRACE"
7
+
8
+ export type All = Rest | System
@@ -0,0 +1,50 @@
1
+ /* eslint-disable @typescript-eslint/no-explicit-any */
2
+ /* eslint-disable @typescript-eslint/no-unsafe-return */
3
+ import type { Option } from "effect"
4
+ import * as B from "effect/Brand"
5
+ import type * as Brand from "effect/Brand"
6
+ import type * as Either from "effect/Either"
7
+ import * as S from "effect/Schema"
8
+
9
+ export interface Constructor<in out A extends B.Brand<any>> {
10
+ readonly [B.RefinedConstructorsTypeId]: B.RefinedConstructorsTypeId
11
+ /**
12
+ * Constructs a branded type from a value of type `A`, throwing an error if
13
+ * the provided `A` is not valid.
14
+ */
15
+ (args: Unbranded<A>): A
16
+ /**
17
+ * Constructs a branded type from a value of type `A`, returning `Some<A>`
18
+ * if the provided `A` is valid, `None` otherwise.
19
+ */
20
+ option(args: Unbranded<A>): Option.Option<A>
21
+ /**
22
+ * Constructs a branded type from a value of type `A`, returning `Right<A>`
23
+ * if the provided `A` is valid, `Left<BrandError>` otherwise.
24
+ */
25
+ either(args: Unbranded<A>): Either.Either<A, Brand.Brand.BrandErrors>
26
+ /**
27
+ * Attempts to refine the provided value of type `A`, returning `true` if
28
+ * the provided `A` is valid, `false` otherwise.
29
+ */
30
+ is(a: Unbranded<A>): a is Unbranded<A> & A
31
+ }
32
+
33
+ export const fromBrand = <C extends Brand.Brand<string | symbol>>(
34
+ constructor: Constructor<C>,
35
+ options?: S.Annotations.Filter<Unbranded<C>>
36
+ ) =>
37
+ <R, I, A extends Unbranded<C>>(self: S.Schema<A, I, R>): S.Schema<A & C, I, R> => {
38
+ return S.fromBrand(constructor as any, options as any)(self as any) as any
39
+ }
40
+
41
+ export type Brands<P> = P extends B.Brand<any> ? { readonly [B.BrandTypeId]: P[B.BrandTypeId] }
42
+ : never
43
+
44
+ export type Unbranded<P> = P extends infer Q & Brands<P> ? Q : P
45
+
46
+ export const nominal: <A extends B.Brand<any>>() => Constructor<A> = <
47
+ A extends B.Brand<any>
48
+ >(): Constructor<
49
+ A
50
+ > => B.nominal<A>() as any
@@ -0,0 +1,22 @@
1
+ import type { Refinement } from "effect-app/Function"
2
+ import { isValidEmail } from "effect-app/validation"
3
+ import * as S from "effect/Schema"
4
+ import type { Simplify } from "effect/Types"
5
+ import type { B } from "./schema.js"
6
+ import type { NonEmptyStringBrand } from "./strings.js"
7
+
8
+ export interface EmailBrand extends Simplify<NonEmptyStringBrand & B.Brand<"Email">> {}
9
+
10
+ export type Email = string & EmailBrand
11
+
12
+ export const Email = S
13
+ .String
14
+ .pipe(
15
+ S.filter(isValidEmail as Refinement<string, Email>, {
16
+ identifier: "Email",
17
+ title: "Email",
18
+ description: "an email according to RFC 5322",
19
+ jsonSchema: { format: "email" },
20
+ arbitrary: () => (fc) => fc.emailAddress().map((_) => _ as Email)
21
+ })
22
+ )
@@ -0,0 +1,273 @@
1
+ /* eslint-disable @typescript-eslint/no-explicit-any */
2
+ /* eslint-disable @typescript-eslint/no-unsafe-return */
3
+ import { Effect, pipe } from "effect"
4
+ import type { ParseResult, SchemaAST } from "effect"
5
+ import type { NonEmptyReadonlyArray } from "effect/Array"
6
+ import type { Schema } from "effect/Schema"
7
+ import * as S from "effect/Schema"
8
+ import { extendM, typedKeysOf } from "../utils.js"
9
+
10
+ export const withDefaultConstructor: <A, I, R>(
11
+ makeDefault: () => NoInfer<A>
12
+ ) => (self: Schema<A, I, R>) => S.PropertySignature<":", A, never, ":", I, true, R> = (makeDefault) => (self) =>
13
+ S.propertySignature(self).pipe(S.withConstructorDefault(makeDefault))
14
+
15
+ export const Date = Object.assign(S.Date, {
16
+ withDefault: S.Date.pipe(withDefaultConstructor(() => new global.Date()))
17
+ })
18
+ export const Boolean = Object.assign(S.Boolean, {
19
+ withDefault: S.Boolean.pipe(withDefaultConstructor(() => false))
20
+ })
21
+ export const Number = Object.assign(S.Number, { withDefault: S.Number.pipe(withDefaultConstructor(() => 0)) })
22
+
23
+ /**
24
+ * Like the default Schema `Struct` but with batching enabled by default
25
+ */
26
+ export function Struct<Fields extends S.Struct.Fields, const Records extends S.IndexSignature.NonEmptyRecords>(
27
+ fields: Fields,
28
+ ...records: Records
29
+ ): S.TypeLiteral<Fields, Records>
30
+ export function Struct<Fields extends S.Struct.Fields>(fields: Fields): S.Struct<Fields>
31
+ export function Struct<Fields extends S.Struct.Fields, const Records extends S.IndexSignature.Records>(
32
+ fields: Fields,
33
+ ...records: Records
34
+ ): S.TypeLiteral<Fields, Records> {
35
+ return S.Struct(fields, ...records as any).pipe(S.annotations({ batching: true }))
36
+ }
37
+
38
+ export declare namespace Struct {
39
+ export type Fields = S.Struct.Fields
40
+ export type Type<F extends Fields> = S.Struct.Type<F>
41
+ export type Encoded<F extends Fields> = S.Struct.Encoded<F>
42
+ export type Context<F extends Fields> = Schema.Context<F[keyof F]>
43
+ }
44
+
45
+ /**
46
+ * Like the default Schema `tuple` but with batching enabled by default
47
+ */
48
+ export function Tuple<
49
+ const Elements extends S.TupleType.Elements,
50
+ Rest extends NonEmptyReadonlyArray<Schema.Any>
51
+ >(elements: Elements, ...rest: Rest): S.TupleType<Elements, Rest>
52
+ export function Tuple<Elements extends S.TupleType.Elements>(...elements: Elements): S.Tuple<Elements>
53
+ export function Tuple(...args: ReadonlyArray<any>): any {
54
+ return S.Tuple(...args).pipe(S.annotations({ batching: true }))
55
+ }
56
+
57
+ /**
58
+ * Like the default Schema `NonEmptyArray` but with batching enabled by default
59
+ */
60
+ export function NonEmptyArray<Value extends Schema.Any>(value: Value): S.NonEmptyArray<Value> {
61
+ return pipe(
62
+ S.NonEmptyArray(value),
63
+ S.annotations({ batching: true })
64
+ )
65
+ }
66
+
67
+ /**
68
+ * Like the default Schema `Array` but with `withDefault` and batching enabled by default
69
+ */
70
+ export function Array<Value extends Schema.Any>(value: Value) {
71
+ return pipe(
72
+ S.Array(value),
73
+ S.annotations({ batching: true }),
74
+ (s) => Object.assign(s, { withDefault: s.pipe(withDefaultConstructor(() => [])) })
75
+ )
76
+ }
77
+
78
+ /**
79
+ * Like the default Schema `ReadonlySet` but with `withDefault` and batching enabled by default
80
+ */
81
+ export const ReadonlySet = <Value extends Schema.Any>(value: Value) =>
82
+ pipe(
83
+ S.ReadonlySet(value),
84
+ S.annotations({ batching: true }),
85
+ (s) => Object.assign(s, { withDefault: s.pipe(withDefaultConstructor(() => new Set<S.Schema.Type<Value>>())) })
86
+ )
87
+
88
+ /**
89
+ * Like the default Schema `ReadonlyMap` but with `withDefault` and batching enabled by default
90
+ */
91
+ export const ReadonlyMap = <K extends Schema.Any, V extends Schema.Any>(pair: {
92
+ readonly key: K
93
+ readonly value: V
94
+ }) =>
95
+ pipe(
96
+ S.ReadonlyMap(pair),
97
+ S.annotations({ batching: true }),
98
+ (s) => Object.assign(s, { withDefault: s.pipe(withDefaultConstructor(() => new Map())) })
99
+ )
100
+
101
+ /**
102
+ * Like the default Schema `NullOr` but with `withDefault`
103
+ */
104
+ export const NullOr = <S extends Schema.Any>(self: S) =>
105
+ pipe(
106
+ S.NullOr(self),
107
+ (s) => Object.assign(s, { withDefault: s.pipe(withDefaultConstructor(() => null)) })
108
+ )
109
+
110
+ export const defaultDate = <I, R>(s: Schema<Date, I, R>) => s.pipe(withDefaultConstructor(() => new global.Date()))
111
+
112
+ export const defaultBool = <I, R>(s: Schema<boolean, I, R>) => s.pipe(withDefaultConstructor(() => false))
113
+
114
+ export const defaultNullable = <A, I, R>(
115
+ s: Schema<A | null, I, R>
116
+ ) => s.pipe(withDefaultConstructor(() => null))
117
+
118
+ export const defaultArray = <A, I, R>(s: Schema<ReadonlyArray<A>, I, R>) => s.pipe(withDefaultConstructor(() => []))
119
+
120
+ export const defaultMap = <A, A2, I, R>(s: Schema<ReadonlyMap<A, A2>, I, R>) =>
121
+ s.pipe(withDefaultConstructor(() => new Map()))
122
+
123
+ export const defaultSet = <A, I, R>(s: Schema<ReadonlySet<A>, I, R>) =>
124
+ s.pipe(withDefaultConstructor(() => new Set<A>()))
125
+
126
+ /**
127
+ * @tsplus getter effect/schema/Schema withDefaultMake
128
+ */
129
+ export const withDefaultMake = <Self extends S.Schema<any, any, never>>(s: Self) => {
130
+ const a = Object.assign(S.decodeSync(s) as WithDefaults<Self>, s)
131
+ Object.setPrototypeOf(a, s)
132
+ return a
133
+
134
+ // return s as Self & WithDefaults<Self>
135
+ }
136
+
137
+ export type WithDefaults<Self extends S.Schema<any, any, never>> = (
138
+ i: S.Schema.Encoded<Self>,
139
+ options?: SchemaAST.ParseOptions
140
+ ) => S.Schema.Type<Self>
141
+
142
+ // type GetKeys<U> = U extends Record<infer K, any> ? K : never
143
+ // type UnionToIntersection2<U extends object> = {
144
+ // readonly [K in GetKeys<U>]: U extends Record<K, infer T> ? T : never
145
+ // }
146
+
147
+ // export type Test<P extends B.Brand<any>> = {
148
+ // [K in keyof P[B.BrandTypeId]]: K extends string | symbol ? {
149
+ // readonly [k in K]: k
150
+ // }
151
+ // : never
152
+ // }[keyof P[B.BrandTypeId]]
153
+ // export type UnionToIntersection3<U> = (U extends any ? (k: U) => void : never) extends ((k: infer I) => void) ? I
154
+ // : never
155
+
156
+ export const inputDate = extendM(
157
+ S.Union(S.ValidDateFromSelf, S.Date),
158
+ (s) => ({ withDefault: s.pipe(withDefaultConstructor(() => new globalThis.Date())) })
159
+ )
160
+
161
+ export interface UnionBrand {}
162
+
163
+ const makeOpt = (self: S.PropertySignature.Any, exact?: boolean) => {
164
+ const ast = self.ast
165
+ switch (ast._tag) {
166
+ case "PropertySignatureDeclaration": {
167
+ return S.makePropertySignature(
168
+ new S.PropertySignatureDeclaration(
169
+ exact ? ast.type : S.UndefinedOr(S.make(ast.type)).ast,
170
+ true,
171
+ ast.isReadonly,
172
+ ast.annotations,
173
+ ast.defaultValue
174
+ )
175
+ )
176
+ }
177
+ case "PropertySignatureTransformation": {
178
+ return S.makePropertySignature(
179
+ new S.PropertySignatureTransformation(
180
+ new S.FromPropertySignature(
181
+ exact ? ast.from.type : S.UndefinedOr(S.make(ast.from.type)).ast,
182
+ true,
183
+ ast.from.isReadonly,
184
+ ast.from.annotations
185
+ ),
186
+ new S.ToPropertySignature(
187
+ exact ? ast.to.type : S.UndefinedOr(S.make(ast.to.type)).ast,
188
+ true,
189
+ ast.to.isReadonly,
190
+ ast.to.annotations,
191
+ ast.to.defaultValue
192
+ ),
193
+ ast.decode,
194
+ ast.encode
195
+ )
196
+ )
197
+ }
198
+ }
199
+ }
200
+
201
+ export function makeOptional<NER extends S.Struct.Fields | S.PropertySignature.Any>(
202
+ t: NER // TODO: enforce non empty
203
+ ): {
204
+ [K in keyof NER]: S.PropertySignature<
205
+ "?:",
206
+ Schema.Type<NER[K]> | undefined,
207
+ never,
208
+ "?:",
209
+ Schema.Encoded<NER[K]> | undefined,
210
+ NER[K] extends S.PropertySignature<any, any, any, any, any, infer Z, any> ? Z : false,
211
+ Schema.Context<NER[K]>
212
+ >
213
+ } {
214
+ return typedKeysOf(t).reduce((prev, cur) => {
215
+ if (S.isSchema(t[cur])) {
216
+ prev[cur] = S.optional(t[cur] as any)
217
+ } else {
218
+ prev[cur] = makeOpt(t[cur] as any)
219
+ }
220
+ return prev
221
+ }, {} as any)
222
+ }
223
+
224
+ export function makeExactOptional<NER extends S.Struct.Fields>(
225
+ t: NER // TODO: enforce non empty
226
+ ): {
227
+ [K in keyof NER]: S.PropertySignature<
228
+ "?:",
229
+ Schema.Type<NER[K]>,
230
+ never,
231
+ "?:",
232
+ Schema.Encoded<NER[K]>,
233
+ NER[K] extends S.PropertySignature<any, any, any, any, any, infer Z, any> ? Z : false,
234
+ Schema.Context<NER[K]>
235
+ >
236
+ } {
237
+ return typedKeysOf(t).reduce((prev, cur) => {
238
+ if (S.isSchema(t[cur])) {
239
+ prev[cur] = S.optionalWith(t[cur] as any, { exact: true })
240
+ } else {
241
+ prev[cur] = makeOpt(t[cur] as any)
242
+ }
243
+ return prev
244
+ }, {} as any)
245
+ }
246
+
247
+ /** A version of transform which is only a one way mapping of From->To */
248
+ export const transformTo = <To extends Schema.Any, From extends Schema.Any>(
249
+ from: From,
250
+ to: To,
251
+ decode: (
252
+ fromA: Schema.Type<From>,
253
+ options: SchemaAST.ParseOptions,
254
+ ast: SchemaAST.Transformation,
255
+ fromI: Schema.Encoded<From>
256
+ ) => Schema.Encoded<To>
257
+ ) =>
258
+ S.transformOrFail<To, From, never, never>(
259
+ from,
260
+ to,
261
+ { decode: (...args) => Effect.sync(() => decode(...args)), encode: () => Effect.die("one way schema") }
262
+ )
263
+
264
+ /** A version of transformOrFail which is only a one way mapping of From->To */
265
+ export const transformToOrFail = <To extends Schema.Any, From extends Schema.Any, RD>(
266
+ from: From,
267
+ to: To,
268
+ decode: (
269
+ fromA: Schema.Type<From>,
270
+ options: SchemaAST.ParseOptions,
271
+ ast: SchemaAST.Transformation
272
+ ) => Effect.Effect<Schema.Encoded<To>, ParseResult.ParseIssue, RD>
273
+ ) => S.transformOrFail<To, From, RD, never>(from, to, { decode, encode: () => Effect.die("one way schema") })
@@ -0,0 +1,260 @@
1
+ import { pipe } from "effect"
2
+ import type { Refinement } from "effect-app/Function"
3
+ import { extendM } from "effect-app/utils"
4
+ import type { LazyArbitrary } from "effect/Arbitrary"
5
+ import * as S from "effect/Schema"
6
+ import type { Simplify } from "effect/Types"
7
+ import { customRandom, nanoid, urlAlphabet } from "nanoid"
8
+ import validator from "validator"
9
+ import { fromBrand, nominal } from "./brand.js"
10
+ import type { WithDefaults } from "./ext.js"
11
+ import { withDefaultConstructor, withDefaultMake } from "./ext.js"
12
+ import { type B } from "./schema.js"
13
+ import type { NonEmptyString255Brand, NonEmptyStringBrand } from "./strings.js"
14
+
15
+ const nonEmptyString = S.String.pipe(S.nonEmptyString())
16
+
17
+ /**
18
+ * A string that is at least 1 character long and a maximum of 50.
19
+ */
20
+ export interface NonEmptyString50Brand extends Simplify<B.Brand<"NonEmptyString50"> & NonEmptyString64Brand> {}
21
+
22
+ /**
23
+ * A string that is at least 1 character long and a maximum of 50.
24
+ */
25
+ export type NonEmptyString50 = string & NonEmptyString50Brand
26
+
27
+ /**
28
+ * A string that is at least 1 character long and a maximum of 50.
29
+ */
30
+ export const NonEmptyString50 = nonEmptyString.pipe(
31
+ S.maxLength(50),
32
+ fromBrand(nominal<NonEmptyString50>(), {
33
+ identifier: "NonEmptyString50",
34
+ title: "NonEmptyString50",
35
+ jsonSchema: {}
36
+ }),
37
+ withDefaultMake
38
+ )
39
+
40
+ /**
41
+ * A string that is at least 1 character long and a maximum of 64.
42
+ */
43
+ export interface NonEmptyString64Brand extends Simplify<B.Brand<"NonEmptyString64"> & NonEmptyString80Brand> {}
44
+
45
+ /**
46
+ * A string that is at least 1 character long and a maximum of 64.
47
+ */
48
+ export type NonEmptyString64 = string & NonEmptyString64Brand
49
+
50
+ /**
51
+ * A string that is at least 1 character long and a maximum of 64.
52
+ */
53
+ export const NonEmptyString64 = nonEmptyString.pipe(
54
+ S.maxLength(64),
55
+ fromBrand(nominal<NonEmptyString64>(), {
56
+ identifier: "NonEmptyString64",
57
+ title: "NonEmptyString64",
58
+ jsonSchema: {}
59
+ }),
60
+ withDefaultMake
61
+ )
62
+
63
+ /**
64
+ * A string that is at least 1 character long and a maximum of 80.
65
+ */
66
+ export interface NonEmptyString80Brand extends Simplify<B.Brand<"NonEmptyString80"> & NonEmptyString100Brand> {}
67
+
68
+ /**
69
+ * A string that is at least 1 character long and a maximum of 80.
70
+ */
71
+ export type NonEmptyString80 = string & NonEmptyString80Brand
72
+
73
+ /**
74
+ * A string that is at least 1 character long and a maximum of 80.
75
+ */
76
+
77
+ export const NonEmptyString80 = nonEmptyString.pipe(
78
+ S.maxLength(80),
79
+ fromBrand(nominal<NonEmptyString80>(), {
80
+ identifier: "NonEmptyString80",
81
+ title: "NonEmptyString80",
82
+ jsonSchema: {}
83
+ }),
84
+ withDefaultMake
85
+ )
86
+
87
+ /**
88
+ * A string that is at least 1 character long and a maximum of 100.
89
+ */
90
+ export interface NonEmptyString100Brand extends Simplify<B.Brand<"NonEmptyString100"> & NonEmptyString255Brand> {}
91
+
92
+ /**
93
+ * A string that is at least 1 character long and a maximum of 100.
94
+ */
95
+ export type NonEmptyString100 = string & NonEmptyString100Brand
96
+
97
+ /**
98
+ * A string that is at least 1 character long and a maximum of 100.
99
+ */
100
+ export const NonEmptyString100 = nonEmptyString.pipe(
101
+ S.maxLength(100),
102
+ fromBrand(nominal<NonEmptyString100>(), {
103
+ identifier: "NonEmptyString100",
104
+ title: "NonEmptyString100",
105
+ jsonSchema: {}
106
+ }),
107
+ withDefaultMake
108
+ )
109
+
110
+ /**
111
+ * A string that is at least 3 character long and a maximum of 255.
112
+ */
113
+ export interface Min3String255Brand extends Simplify<B.Brand<"Min3String255"> & NonEmptyString255Brand> {}
114
+
115
+ /**
116
+ * A string that is at least 3 character long and a maximum of 255.
117
+ */
118
+ export type Min3String255 = string & Min3String255Brand
119
+
120
+ /**
121
+ * A string that is at least 3 character long and a maximum of 255.
122
+ */
123
+ export const Min3String255 = pipe(
124
+ S.String,
125
+ S.minLength(3),
126
+ S.maxLength(255),
127
+ fromBrand(nominal<Min3String255>(), { identifier: "Min3String255", title: "Min3String255", jsonSchema: {} }),
128
+ withDefaultMake
129
+ )
130
+
131
+ /**
132
+ * A string that is at least 6 characters long and a maximum of 50.
133
+ */
134
+ export interface StringIdBrand extends Simplify<B.Brand<"StringId"> & NonEmptyString50Brand> {}
135
+
136
+ /**
137
+ * A string that is at least 6 characters long and a maximum of 50.
138
+ */
139
+ export type StringId = string & StringIdBrand
140
+
141
+ const makeStringId = (): StringId => nanoid() as unknown as StringId
142
+ const minLength = 6
143
+ const maxLength = 50
144
+ const size = 21
145
+ const length = 10 * size
146
+ const StringIdArb = (): LazyArbitrary<string> => (fc) =>
147
+ fc
148
+ .uint8Array({ minLength: length, maxLength: length })
149
+ .map((_) => customRandom(urlAlphabet, size, (size) => _.subarray(0, size))())
150
+
151
+ /**
152
+ * A string that is at least 6 characters long and a maximum of 50.
153
+ */
154
+ export const StringId = extendM(
155
+ pipe(
156
+ S.String,
157
+ S.minLength(minLength),
158
+ S.maxLength(maxLength),
159
+ fromBrand(nominal<StringId>(), {
160
+ identifier: "StringId",
161
+ title: "StringId",
162
+ arbitrary: StringIdArb,
163
+ jsonSchema: {}
164
+ })
165
+ ),
166
+ (s) => ({
167
+ make: makeStringId,
168
+ withDefault: s.pipe(withDefaultConstructor(makeStringId))
169
+ })
170
+ )
171
+ .pipe(withDefaultMake)
172
+
173
+ // const prefixedStringIdUnsafe = (prefix: string) => StringId(prefix + StringId.make())
174
+
175
+ // const prefixedStringIdUnsafeThunk = (prefix: string) => () => prefixedStringIdUnsafe(prefix)
176
+
177
+ export function prefixedStringId<Brand extends StringId>() {
178
+ return <Prefix extends string, Separator extends string = "-">(
179
+ prefix: Prefix,
180
+ name: string,
181
+ separator?: Separator
182
+ ) => {
183
+ type FullPrefix = `${Prefix}${Separator}`
184
+ const pref = `${prefix}${separator ?? "-"}` as FullPrefix
185
+ const arb = (): LazyArbitrary<string & Brand> => (fc) =>
186
+ StringIdArb()(fc).map(
187
+ (x) => (pref + x.substring(0, 50 - pref.length)) as Brand
188
+ )
189
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
190
+ const s: S.Schema<string & Brand, string> = StringId
191
+ .pipe(
192
+ S.filter((x: StringId): x is string & Brand => x.startsWith(pref), {
193
+ arbitrary: arb,
194
+ identifier: name,
195
+ title: name
196
+ })
197
+ )
198
+ const schema = s.pipe(withDefaultMake)
199
+ const make = () => (pref + StringId.make().substring(0, 50 - pref.length)) as Brand
200
+
201
+ return extendM(
202
+ schema,
203
+ (ex): PrefixedStringUtils<Brand, Prefix, Separator> => ({
204
+ make,
205
+ /**
206
+ * Automatically adds the prefix.
207
+ */
208
+ unsafeFrom: (str: string) => ex(pref + str),
209
+ /**
210
+ * Must provide a literal string starting with prefix.
211
+ */
212
+ prefixSafe: <REST extends string>(str: `${Prefix}${Separator}${REST}`) => ex(str),
213
+ prefix,
214
+ withDefault: schema.pipe(withDefaultConstructor(make))
215
+ })
216
+ )
217
+ }
218
+ }
219
+
220
+ export const brandedStringId = <
221
+ Brand extends StringIdBrand
222
+ >() =>
223
+ withDefaultMake(
224
+ Object.assign(Object.create(StringId), StringId) as S.Schema<string & Brand, string> & {
225
+ make: () => string & Brand
226
+ withDefault: S.PropertySignature<":", string & Brand, never, ":", string, true, never>
227
+ } & WithDefaults<S.Schema<string & Brand, string>>
228
+ )
229
+
230
+ export interface PrefixedStringUtils<
231
+ Brand extends StringId,
232
+ Prefix extends string,
233
+ Separator extends string
234
+ > {
235
+ readonly make: () => Brand
236
+ readonly unsafeFrom: (str: string) => Brand
237
+ prefixSafe: <REST extends string>(str: `${Prefix}${Separator}${REST}`) => Brand
238
+ readonly prefix: Prefix
239
+ readonly withDefault: S.PropertySignature<":", Brand, never, ":", string, true, never>
240
+ }
241
+
242
+ export interface UrlBrand extends Simplify<B.Brand<"Url"> & NonEmptyStringBrand> {}
243
+
244
+ export type Url = string & UrlBrand
245
+
246
+ const isUrl: Refinement<string, Url> = (s: string): s is Url => {
247
+ return validator.default.isURL(s, { require_tld: false })
248
+ }
249
+
250
+ export const Url = S
251
+ .String
252
+ .pipe(
253
+ S.filter(isUrl, {
254
+ arbitrary: (): LazyArbitrary<Url> => (fc) => fc.webUrl().map((_) => _ as Url),
255
+ identifier: "Url",
256
+ title: "Url",
257
+ jsonSchema: { format: "uri" }
258
+ }),
259
+ withDefaultMake
260
+ )