effect-app 4.0.0-beta.320 → 4.0.0-beta.322
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 +23 -0
- package/dist/Config/SecretURL.js +1 -1
- package/dist/Model/query/new-kid-interpreter.d.ts.map +1 -1
- package/dist/Model/query/new-kid-interpreter.js +51 -42
- package/dist/Schema/brand.d.ts +2 -4
- package/dist/Schema/brand.d.ts.map +1 -1
- package/dist/Schema/brand.js +1 -1
- package/dist/Schema/email.d.ts.map +1 -1
- package/dist/Schema/email.js +1 -3
- package/dist/Schema/ext.d.ts +1 -1
- package/dist/Schema/ext.js +5 -5
- package/dist/Schema/moreStrings.d.ts.map +1 -1
- package/dist/Schema/moreStrings.js +2 -13
- package/dist/Schema/phoneNumber.d.ts.map +1 -1
- package/dist/Schema/phoneNumber.js +1 -4
- package/dist/Schema.d.ts +5 -1
- package/dist/Schema.d.ts.map +1 -1
- package/dist/Schema.js +3 -15
- package/dist/client/apiClientFactory.d.ts.map +1 -1
- package/dist/client/apiClientFactory.js +3 -5
- package/dist/runtime.d.ts.map +1 -1
- package/dist/runtime.js +2 -2
- package/package.json +2 -2
- package/src/Config/SecretURL.ts +1 -1
- package/src/Model/query/new-kid-interpreter.ts +197 -191
- package/src/Schema/brand.ts +2 -7
- package/src/Schema/email.ts +0 -3
- package/src/Schema/ext.ts +5 -5
- package/src/Schema/moreStrings.ts +1 -18
- package/src/Schema/phoneNumber.ts +0 -4
- package/src/Schema.ts +7 -21
- package/src/client/apiClientFactory.ts +2 -7
- package/src/runtime.ts +3 -2
- package/test/moreStrings.test.ts +6 -8
- package/test/special.test.ts +4 -0
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
2
2
|
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
|
|
3
|
-
import { identity
|
|
4
|
-
import * as Match from "effect/Match"
|
|
3
|
+
import { identity } from "effect/Function"
|
|
5
4
|
import * as Array from "../../Array.ts"
|
|
6
5
|
import { toNonEmptyArray } from "../../Array.ts"
|
|
7
6
|
import * as Option from "../../Option.ts"
|
|
@@ -192,197 +191,204 @@ const interpret = <
|
|
|
192
191
|
? { ..._, path: `${path}.-1.${_.path}` }
|
|
193
192
|
: { ..._, result: _.result.map(applyPath(path)) }
|
|
194
193
|
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
}
|
|
298
|
-
})
|
|
299
|
-
)
|
|
300
|
-
return
|
|
301
|
-
}
|
|
302
|
-
if (v.computed && v.mode === "transform") {
|
|
303
|
-
throw new Error("Computed projections require mode 'project' or 'collect', not 'transform'")
|
|
304
|
-
}
|
|
305
|
-
data.schema = v.schema
|
|
306
|
-
data.mode = v.computed
|
|
307
|
-
? v.mode === "collect" ? "collect" : "project"
|
|
308
|
-
: v.mode
|
|
309
|
-
data.computed = v.computed
|
|
310
|
-
? Object.fromEntries(
|
|
311
|
-
Object.entries(v.computed).map(([key, expression]) => {
|
|
312
|
-
const e = expression
|
|
313
|
-
const op = "operation" in e ? e.operation : undefined
|
|
314
|
-
const filter = op ? interpret(op(make())).filter.map(applyPath(e.path)) : []
|
|
315
|
-
switch (e._tag) {
|
|
316
|
-
case "relation-count":
|
|
317
|
-
case "relation-any":
|
|
318
|
-
case "relation-every":
|
|
319
|
-
return [key, { _tag: e._tag, path: e.path, filter }]
|
|
320
|
-
case "relation-distinct-count":
|
|
321
|
-
case "relation-sum":
|
|
322
|
-
return [
|
|
323
|
-
key,
|
|
324
|
-
{ _tag: e._tag, path: e.path, field: e.field, filter }
|
|
325
|
-
]
|
|
326
|
-
case "relation-sum-expr":
|
|
327
|
-
return [
|
|
328
|
-
key,
|
|
329
|
-
{ _tag: e._tag, path: e.path, expression: e.expression, filter }
|
|
330
|
-
]
|
|
331
|
-
case "relation-sum-expr-by":
|
|
332
|
-
return [
|
|
333
|
-
key,
|
|
334
|
-
{
|
|
335
|
-
_tag: e._tag,
|
|
336
|
-
path: e.path,
|
|
337
|
-
expression: e.expression,
|
|
338
|
-
unit: e.unit,
|
|
339
|
-
filter
|
|
340
|
-
}
|
|
341
|
-
]
|
|
342
|
-
case "relation-sum-expr-normalized":
|
|
343
|
-
return [
|
|
344
|
-
key,
|
|
345
|
-
{
|
|
346
|
-
_tag: e._tag,
|
|
347
|
-
path: e.path,
|
|
348
|
-
expression: e.expression,
|
|
349
|
-
unit: e.unit,
|
|
350
|
-
toBase: e.toBase,
|
|
351
|
-
factors: e.factors,
|
|
352
|
-
filter
|
|
353
|
-
}
|
|
354
|
-
]
|
|
355
|
-
case "relation-collect":
|
|
356
|
-
return [
|
|
357
|
-
key,
|
|
358
|
-
{
|
|
359
|
-
_tag: e._tag,
|
|
360
|
-
path: e.path,
|
|
361
|
-
field: e.field,
|
|
362
|
-
distinct: e.distinct,
|
|
363
|
-
filter
|
|
364
|
-
}
|
|
365
|
-
]
|
|
366
|
-
case "relation-collect-fields":
|
|
367
|
-
return [
|
|
368
|
-
key,
|
|
369
|
-
{
|
|
370
|
-
_tag: e._tag,
|
|
371
|
-
path: e.path,
|
|
372
|
-
fields: e.fields,
|
|
373
|
-
distinct: e.distinct,
|
|
374
|
-
filter
|
|
375
|
-
}
|
|
376
|
-
]
|
|
377
|
-
case "relation-length":
|
|
378
|
-
return [key, { _tag: e._tag, path: e.path }]
|
|
194
|
+
switch (a._tag) {
|
|
195
|
+
case "value":
|
|
196
|
+
break
|
|
197
|
+
case "where": {
|
|
198
|
+
const { current, operation, relation, subPath } = a
|
|
199
|
+
upd(interpret(current))
|
|
200
|
+
if (typeof operation === "function") {
|
|
201
|
+
data.filter.push(
|
|
202
|
+
{
|
|
203
|
+
t: "where-scope",
|
|
204
|
+
result: interpret(operation(make())).filter.map(subPath ? applyPath(subPath) : identity),
|
|
205
|
+
relation
|
|
206
|
+
}
|
|
207
|
+
)
|
|
208
|
+
} else {
|
|
209
|
+
data.filter.push(
|
|
210
|
+
{
|
|
211
|
+
t: "where",
|
|
212
|
+
path: operation[0],
|
|
213
|
+
op: operation.length === 2 ? "eq" : operation[1],
|
|
214
|
+
value: operation.length === 2 ? operation[1] : operation[2]
|
|
215
|
+
}
|
|
216
|
+
)
|
|
217
|
+
}
|
|
218
|
+
break
|
|
219
|
+
}
|
|
220
|
+
case "and": {
|
|
221
|
+
const { current, operation, relation } = a
|
|
222
|
+
upd(interpret(current))
|
|
223
|
+
if (typeof operation === "function") {
|
|
224
|
+
data.filter.push(
|
|
225
|
+
{ t: "and-scope", result: interpret(operation(make())).filter, relation }
|
|
226
|
+
)
|
|
227
|
+
} else {
|
|
228
|
+
data.filter.push(
|
|
229
|
+
{
|
|
230
|
+
t: "and",
|
|
231
|
+
path: operation[0],
|
|
232
|
+
op: operation.length === 2 ? "eq" : operation[1],
|
|
233
|
+
value: operation.length === 2 ? operation[1] : operation[2]
|
|
234
|
+
}
|
|
235
|
+
)
|
|
236
|
+
}
|
|
237
|
+
break
|
|
238
|
+
}
|
|
239
|
+
case "or": {
|
|
240
|
+
const { current, operation, relation } = a
|
|
241
|
+
upd(interpret(current))
|
|
242
|
+
if (typeof operation === "function") {
|
|
243
|
+
data.filter.push(
|
|
244
|
+
{ t: "or-scope", result: interpret(operation(make())).filter, relation }
|
|
245
|
+
)
|
|
246
|
+
} else {
|
|
247
|
+
data.filter.push(
|
|
248
|
+
{
|
|
249
|
+
t: "or",
|
|
250
|
+
path: operation[0],
|
|
251
|
+
op: operation.length === 2 ? "eq" : operation[1],
|
|
252
|
+
value: operation.length === 2 ? operation[1] : operation[2]
|
|
253
|
+
}
|
|
254
|
+
)
|
|
255
|
+
}
|
|
256
|
+
break
|
|
257
|
+
}
|
|
258
|
+
case "one": {
|
|
259
|
+
upd(interpret(a.current))
|
|
260
|
+
data.limit = 1
|
|
261
|
+
data.ttype = "one"
|
|
262
|
+
break
|
|
263
|
+
}
|
|
264
|
+
case "count": {
|
|
265
|
+
upd(interpret(a.current))
|
|
266
|
+
data.ttype = "count"
|
|
267
|
+
data.schema = S.Struct({ id: S.String }) as any
|
|
268
|
+
break
|
|
269
|
+
}
|
|
270
|
+
case "order": {
|
|
271
|
+
upd(interpret(a.current))
|
|
272
|
+
data.order.push({ key: a.field, direction: a.direction })
|
|
273
|
+
break
|
|
274
|
+
}
|
|
275
|
+
case "page": {
|
|
276
|
+
upd(interpret(a.current))
|
|
277
|
+
data.limit = a.take
|
|
278
|
+
data.skip = a.skip
|
|
279
|
+
break
|
|
280
|
+
}
|
|
281
|
+
case "project": {
|
|
282
|
+
upd(interpret(a.current))
|
|
283
|
+
if (a.mode === "aggregate" && a.aggregateMap) {
|
|
284
|
+
data.schema = a.schema
|
|
285
|
+
data.mode = "aggregate"
|
|
286
|
+
data.aggregateMap = Object.fromEntries(
|
|
287
|
+
Object.entries(a.aggregateMap).map(([key, expression]) => {
|
|
288
|
+
switch (expression._tag) {
|
|
289
|
+
case "agg-field":
|
|
290
|
+
return [key, { _tag: "agg-field" as const, path: expression.path }]
|
|
291
|
+
case "agg-count":
|
|
292
|
+
return [key, { _tag: "agg-count" as const }]
|
|
293
|
+
case "agg-count-when": {
|
|
294
|
+
const filter = interpret(expression.operation(make())).filter
|
|
295
|
+
return [key, { _tag: "agg-count-when" as const, filter }]
|
|
379
296
|
}
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
297
|
+
case "agg-sum":
|
|
298
|
+
return [key, { _tag: "agg-sum" as const, field: expression.field }]
|
|
299
|
+
case "agg-min":
|
|
300
|
+
return [key, { _tag: "agg-min" as const, field: expression.field }]
|
|
301
|
+
case "agg-max":
|
|
302
|
+
return [key, { _tag: "agg-max" as const, field: expression.field }]
|
|
303
|
+
}
|
|
304
|
+
})
|
|
305
|
+
)
|
|
306
|
+
break
|
|
383
307
|
}
|
|
384
|
-
|
|
385
|
-
|
|
308
|
+
if (a.computed && a.mode === "transform") {
|
|
309
|
+
throw new Error("Computed projections require mode 'project' or 'collect', not 'transform'")
|
|
310
|
+
}
|
|
311
|
+
data.schema = a.schema
|
|
312
|
+
data.mode = a.computed
|
|
313
|
+
? a.mode === "collect" ? "collect" : "project"
|
|
314
|
+
: a.mode
|
|
315
|
+
data.computed = a.computed
|
|
316
|
+
? Object.fromEntries(
|
|
317
|
+
Object.entries(a.computed).map(([key, expression]) => {
|
|
318
|
+
const e = expression
|
|
319
|
+
const op = "operation" in e ? e.operation : undefined
|
|
320
|
+
const filter = op ? interpret(op(make())).filter.map(applyPath(e.path)) : []
|
|
321
|
+
switch (e._tag) {
|
|
322
|
+
case "relation-count":
|
|
323
|
+
case "relation-any":
|
|
324
|
+
case "relation-every":
|
|
325
|
+
return [key, { _tag: e._tag, path: e.path, filter }]
|
|
326
|
+
case "relation-distinct-count":
|
|
327
|
+
case "relation-sum":
|
|
328
|
+
return [
|
|
329
|
+
key,
|
|
330
|
+
{ _tag: e._tag, path: e.path, field: e.field, filter }
|
|
331
|
+
]
|
|
332
|
+
case "relation-sum-expr":
|
|
333
|
+
return [
|
|
334
|
+
key,
|
|
335
|
+
{ _tag: e._tag, path: e.path, expression: e.expression, filter }
|
|
336
|
+
]
|
|
337
|
+
case "relation-sum-expr-by":
|
|
338
|
+
return [
|
|
339
|
+
key,
|
|
340
|
+
{
|
|
341
|
+
_tag: e._tag,
|
|
342
|
+
path: e.path,
|
|
343
|
+
expression: e.expression,
|
|
344
|
+
unit: e.unit,
|
|
345
|
+
filter
|
|
346
|
+
}
|
|
347
|
+
]
|
|
348
|
+
case "relation-sum-expr-normalized":
|
|
349
|
+
return [
|
|
350
|
+
key,
|
|
351
|
+
{
|
|
352
|
+
_tag: e._tag,
|
|
353
|
+
path: e.path,
|
|
354
|
+
expression: e.expression,
|
|
355
|
+
unit: e.unit,
|
|
356
|
+
toBase: e.toBase,
|
|
357
|
+
factors: e.factors,
|
|
358
|
+
filter
|
|
359
|
+
}
|
|
360
|
+
]
|
|
361
|
+
case "relation-collect":
|
|
362
|
+
return [
|
|
363
|
+
key,
|
|
364
|
+
{
|
|
365
|
+
_tag: e._tag,
|
|
366
|
+
path: e.path,
|
|
367
|
+
field: e.field,
|
|
368
|
+
distinct: e.distinct,
|
|
369
|
+
filter
|
|
370
|
+
}
|
|
371
|
+
]
|
|
372
|
+
case "relation-collect-fields":
|
|
373
|
+
return [
|
|
374
|
+
key,
|
|
375
|
+
{
|
|
376
|
+
_tag: e._tag,
|
|
377
|
+
path: e.path,
|
|
378
|
+
fields: e.fields,
|
|
379
|
+
distinct: e.distinct,
|
|
380
|
+
filter
|
|
381
|
+
}
|
|
382
|
+
]
|
|
383
|
+
case "relation-length":
|
|
384
|
+
return [key, { _tag: e._tag, path: e.path }]
|
|
385
|
+
}
|
|
386
|
+
})
|
|
387
|
+
)
|
|
388
|
+
: undefined
|
|
389
|
+
break
|
|
390
|
+
}
|
|
391
|
+
}
|
|
386
392
|
|
|
387
393
|
return data
|
|
388
394
|
}
|
package/src/Schema/brand.ts
CHANGED
|
@@ -28,12 +28,7 @@ export interface Constructor<in out A extends B.Brand<any>> {
|
|
|
28
28
|
is(a: Unbranded<A>): a is Unbranded<A> & A
|
|
29
29
|
}
|
|
30
30
|
|
|
31
|
-
type BrandAnnotations
|
|
32
|
-
& S.Annotations.Filter
|
|
33
|
-
& (
|
|
34
|
-
C extends string ? { readonly toArbitrary?: S.Annotations.ToArbitrary.Declaration<C, readonly []> }
|
|
35
|
-
: {}
|
|
36
|
-
)
|
|
31
|
+
type BrandAnnotations = S.Annotations.Filter
|
|
37
32
|
|
|
38
33
|
export interface BrandedSchema<S extends S.Top, C extends B.Brand<any>> extends
|
|
39
34
|
S.Bottom<
|
|
@@ -57,7 +52,7 @@ export interface BrandedSchema<S extends S.Top, C extends B.Brand<any>> extends
|
|
|
57
52
|
|
|
58
53
|
export const fromBrand = <C extends B.Brand<any>>(
|
|
59
54
|
constructor: Constructor<C>,
|
|
60
|
-
options?: BrandAnnotations
|
|
55
|
+
options?: BrandAnnotations
|
|
61
56
|
) =>
|
|
62
57
|
<Self extends S.Top>(self: Self): BrandedSchema<Self, C> => {
|
|
63
58
|
const branded = S.fromBrand(options?.identifier ?? "Brand", constructor as any)(self as any)
|
package/src/Schema/email.ts
CHANGED
|
@@ -22,8 +22,5 @@ export const Email = S
|
|
|
22
22
|
identifier: "Email",
|
|
23
23
|
description: "an email according to RFC 5322",
|
|
24
24
|
jsonSchema: { format: "email", minLength: 3, maxLength: 998 }
|
|
25
|
-
}),
|
|
26
|
-
S.annotate({
|
|
27
|
-
toArbitrary: () => (fc) => fc.emailAddress().map((_) => _ as Email)
|
|
28
25
|
})
|
|
29
26
|
)
|
package/src/Schema/ext.ts
CHANGED
|
@@ -54,8 +54,8 @@ type ProvidedCodec<Self extends S.Top, R> = S.Codec<
|
|
|
54
54
|
|
|
55
55
|
const concurrencySetting = Effect.runSync(
|
|
56
56
|
Config
|
|
57
|
-
.
|
|
58
|
-
.pipe(Config.orElse(() => Config.
|
|
57
|
+
.Literal("unbounded", "SCHEMA_CONCURRENCY")
|
|
58
|
+
.pipe(Config.orElse(() => Config.Number("SCHEMA_CONCURRENCY")), Config.option)
|
|
59
59
|
)
|
|
60
60
|
|
|
61
61
|
export const DefaultParseOptions: SchemaAST.ParseOptions = {
|
|
@@ -611,7 +611,7 @@ export const transformTo = <To extends S.Top, From extends S.Top>(
|
|
|
611
611
|
from.pipe(
|
|
612
612
|
S.decodeTo(
|
|
613
613
|
to,
|
|
614
|
-
SchemaTransformation.
|
|
614
|
+
SchemaTransformation.transformEffect({
|
|
615
615
|
decode: (input: any, options: any) => Effect.sync(() => decode(input, options)),
|
|
616
616
|
encode: (i: any) =>
|
|
617
617
|
Effect.fail(
|
|
@@ -624,7 +624,7 @@ export const transformTo = <To extends S.Top, From extends S.Top>(
|
|
|
624
624
|
)
|
|
625
625
|
)
|
|
626
626
|
|
|
627
|
-
/** A version of
|
|
627
|
+
/** A version of transformEffect which is only a one way mapping of From->To */
|
|
628
628
|
export const transformToOrFail = <To extends S.Top, From extends S.Top, RD>(
|
|
629
629
|
from: From,
|
|
630
630
|
to: To,
|
|
@@ -636,7 +636,7 @@ export const transformToOrFail = <To extends S.Top, From extends S.Top, RD>(
|
|
|
636
636
|
from.pipe(
|
|
637
637
|
S.decodeTo(
|
|
638
638
|
to,
|
|
639
|
-
SchemaTransformation.
|
|
639
|
+
SchemaTransformation.transformEffect({
|
|
640
640
|
decode,
|
|
641
641
|
encode: (i: any) =>
|
|
642
642
|
Effect.fail(
|
|
@@ -15,7 +15,7 @@ import * as Effect from "effect/Effect"
|
|
|
15
15
|
import { pipe } from "effect/Function"
|
|
16
16
|
import * as S from "effect/Schema"
|
|
17
17
|
import type { Simplify } from "effect/Types"
|
|
18
|
-
import {
|
|
18
|
+
import { nanoid } from "nanoid"
|
|
19
19
|
import validator from "validator"
|
|
20
20
|
import type * as SchemaAST from "../SchemaAST.ts"
|
|
21
21
|
import { type BrandedSchema, fromBrand, nominal } from "./brand.ts"
|
|
@@ -164,23 +164,16 @@ export type StringId = string & StringIdBrand
|
|
|
164
164
|
|
|
165
165
|
const minLength = 6
|
|
166
166
|
const maxLength = 50
|
|
167
|
-
const size = 21
|
|
168
|
-
const length = 10 * size
|
|
169
167
|
const StringIdSchemaBase = pipe(
|
|
170
168
|
S.String,
|
|
171
169
|
S.check(S.isMinLength(minLength), S.isMaxLength(maxLength)),
|
|
172
170
|
fromBrand<StringId>(nominal<StringId>(), {
|
|
173
171
|
identifier: "StringId",
|
|
174
|
-
toArbitrary: () => (fc) => StringIdArb()(fc),
|
|
175
172
|
jsonSchema: {}
|
|
176
173
|
})
|
|
177
174
|
)
|
|
178
175
|
const makeStringId = (s?: string): StringId =>
|
|
179
176
|
s !== undefined ? S.decodeSync(StringIdSchemaBase)(s) : nanoid() as unknown as StringId
|
|
180
|
-
const StringIdArb = (): S.Arbitrary<StringId> => (fc) =>
|
|
181
|
-
fc
|
|
182
|
-
.uint8Array({ minLength: length, maxLength: length })
|
|
183
|
-
.map((_) => customRandom(urlAlphabet, size, (size) => _.subarray(0, size))() as StringId)
|
|
184
177
|
/**
|
|
185
178
|
* A string that is at least 6 characters long and a maximum of 50.
|
|
186
179
|
*
|
|
@@ -226,18 +219,11 @@ export function prefixedStringId<Type extends StringId>() {
|
|
|
226
219
|
) => {
|
|
227
220
|
type FullPrefix = `${Prefix}${Separator}`
|
|
228
221
|
const pref = `${prefix}${separator ?? "-"}` as FullPrefix
|
|
229
|
-
const arb = (): S.Arbitrary<Type> => (fc) =>
|
|
230
|
-
StringIdArb()(fc).map(
|
|
231
|
-
(x) => (pref + x.substring(0, 50 - pref.length)) as Type
|
|
232
|
-
)
|
|
233
222
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
|
234
223
|
const s = StringIdSchemaBase
|
|
235
224
|
.pipe(
|
|
236
225
|
S.refine((x: string): x is Type => x.startsWith(pref), {
|
|
237
226
|
identifier: name
|
|
238
|
-
}),
|
|
239
|
-
S.annotate({
|
|
240
|
-
toArbitrary: () => (fc) => arb()(fc)
|
|
241
227
|
})
|
|
242
228
|
)
|
|
243
229
|
const schema = s.pipe(withDefaultMake)
|
|
@@ -331,8 +317,5 @@ export const Url: UrlSchema = S
|
|
|
331
317
|
identifier: "Url",
|
|
332
318
|
jsonSchema: { format: "uri" }
|
|
333
319
|
}),
|
|
334
|
-
S.annotate({
|
|
335
|
-
toArbitrary: () => (fc) => fc.webUrl().map((_) => _ as Url)
|
|
336
|
-
}),
|
|
337
320
|
withDefaultMake
|
|
338
321
|
)
|
|
@@ -3,7 +3,6 @@ import { isValidPhone } from "effect-app/validation"
|
|
|
3
3
|
import * as S from "effect/Schema"
|
|
4
4
|
import type { Simplify } from "effect/Types"
|
|
5
5
|
import { withDefaultMake } from "./ext.ts"
|
|
6
|
-
import { Numbers } from "./FastCheck.ts"
|
|
7
6
|
import type { B } from "./schema.ts"
|
|
8
7
|
import type { NonEmptyStringBrand } from "./strings.ts"
|
|
9
8
|
|
|
@@ -23,8 +22,5 @@ export const PhoneNumber = S
|
|
|
23
22
|
description: "a phone number with at least 7 digits",
|
|
24
23
|
jsonSchema: { format: "phone" }
|
|
25
24
|
}),
|
|
26
|
-
S.annotate({
|
|
27
|
-
toArbitrary: () => (fc) => Numbers(7, 10)(fc).map((_) => _ as PhoneNumber)
|
|
28
|
-
}),
|
|
29
25
|
withDefaultMake
|
|
30
26
|
)
|
package/src/Schema.ts
CHANGED
|
@@ -2,10 +2,11 @@ import * as S from "effect/Schema"
|
|
|
2
2
|
import { type Simplify } from "effect/Struct"
|
|
3
3
|
import type * as Tracer from "effect/Tracer"
|
|
4
4
|
import type { RequiredKeys } from "effect/Types"
|
|
5
|
+
import type { Arbitrary as FastCheckArbitrary } from "fast-check"
|
|
5
6
|
import type { NonEmptyReadonlyArray } from "./Array.ts"
|
|
6
|
-
import { fakerArb } from "./faker.ts"
|
|
7
7
|
import { Email as EmailT, type Email as EmailType } from "./Schema/email.ts"
|
|
8
8
|
import { concurrencyUnbounded, withDefaultMake, withDefaultParseOptions } from "./Schema/ext.ts"
|
|
9
|
+
import type { FC } from "./Schema/FastCheck.ts"
|
|
9
10
|
import { PhoneNumber as PhoneNumberT, type PhoneNumber as PhoneNumberType } from "./Schema/phoneNumber.ts"
|
|
10
11
|
import { type AST } from "./Schema/schema.ts"
|
|
11
12
|
import * as SchemaAST from "./SchemaAST.ts"
|
|
@@ -129,6 +130,9 @@ export { NonEmptyString } from "./Schema/strings.ts"
|
|
|
129
130
|
|
|
130
131
|
export * as SchemaIssue from "effect/SchemaIssue"
|
|
131
132
|
|
|
133
|
+
/** Fast-check generator factory previously exported as `Schema.Arbitrary`. */
|
|
134
|
+
export type Arbitrary<T> = (fc: FC) => FastCheckArbitrary<T>
|
|
135
|
+
|
|
132
136
|
export const decodeEffectConcurrently: typeof S.decodeEffect = withDefaultParseOptions(S.decodeEffect)
|
|
133
137
|
export const decodeUnknownEffectConcurrently: typeof S.decodeUnknownEffect = withDefaultParseOptions(
|
|
134
138
|
S.decodeUnknownEffect
|
|
@@ -347,29 +351,11 @@ export interface WithOptionalSpan {
|
|
|
347
351
|
[SpanId]?: Tracer.Span
|
|
348
352
|
}
|
|
349
353
|
|
|
350
|
-
const
|
|
351
|
-
const makePhoneNumber = S.decodeSync(PhoneNumberT as any) as (value: string) => PhoneNumberType
|
|
352
|
-
|
|
353
|
-
export const Email = EmailT
|
|
354
|
-
.pipe(
|
|
355
|
-
S.annotate({
|
|
356
|
-
// eslint-disable-next-line @typescript-eslint/unbound-method
|
|
357
|
-
toArbitrary: () => (fc) => fakerArb((faker) => faker.internet.exampleEmail)(fc).map(makeEmail)
|
|
358
|
-
}),
|
|
359
|
-
withDefaultMake
|
|
360
|
-
)
|
|
354
|
+
export const Email = EmailT.pipe(withDefaultMake)
|
|
361
355
|
|
|
362
356
|
export type Email = EmailType
|
|
363
357
|
|
|
364
|
-
export const PhoneNumber = PhoneNumberT
|
|
365
|
-
.pipe(
|
|
366
|
-
S.annotate({
|
|
367
|
-
toArbitrary: () => (fc) =>
|
|
368
|
-
// eslint-disable-next-line @typescript-eslint/unbound-method
|
|
369
|
-
fakerArb((faker) => faker.phone.number)(fc).map(makePhoneNumber)
|
|
370
|
-
}),
|
|
371
|
-
withDefaultMake
|
|
372
|
-
)
|
|
358
|
+
export const PhoneNumber = PhoneNumberT.pipe(withDefaultMake)
|
|
373
359
|
|
|
374
360
|
export type PhoneNumber = PhoneNumberType
|
|
375
361
|
|
|
@@ -25,13 +25,8 @@ export interface ApiConfig {
|
|
|
25
25
|
}
|
|
26
26
|
|
|
27
27
|
export const DefaultApiConfig = Config.all({
|
|
28
|
-
url: Config.
|
|
29
|
-
headers: Config
|
|
30
|
-
.schema(
|
|
31
|
-
Config.Record(Schema.String, Schema.String),
|
|
32
|
-
"headers"
|
|
33
|
-
)
|
|
34
|
-
.pipe(Config.option)
|
|
28
|
+
url: Config.String("apiUrl").pipe(Config.withDefault("/api")),
|
|
29
|
+
headers: Config.Record(Schema.String, Schema.String, "headers").pipe(Config.option)
|
|
35
30
|
})
|
|
36
31
|
|
|
37
32
|
export type Req = S.Top & {
|
package/src/runtime.ts
CHANGED
|
@@ -9,8 +9,9 @@ import * as Layer from "./Layer.ts"
|
|
|
9
9
|
|
|
10
10
|
export const makeAppRuntime = Effect.fnUntraced(function*<A, E>(layer: Layer.Layer<A, E>) {
|
|
11
11
|
const l = layer.pipe(
|
|
12
|
-
Layer.provide(Logger.layer([Logger.consolePretty()]))
|
|
13
|
-
|
|
12
|
+
Layer.provide(Logger.layer([Logger.consolePretty()])),
|
|
13
|
+
Layer.orDie
|
|
14
|
+
)
|
|
14
15
|
const mrt = ManagedRuntime.make(l)
|
|
15
16
|
yield* mrt.contextEffect
|
|
16
17
|
return Object.assign(mrt, {
|
package/test/moreStrings.test.ts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import * as S from "effect-app/Schema"
|
|
2
|
-
import * as fc from "fast-check"
|
|
3
2
|
import { urlAlphabet } from "nanoid"
|
|
4
3
|
import { test } from "vitest"
|
|
5
4
|
|
|
@@ -7,11 +6,10 @@ const nanoidAlphabet = new Set(urlAlphabet)
|
|
|
7
6
|
|
|
8
7
|
const isNanoId = (value: string) => value.length === 21 && Array.from(value).every((char) => nanoidAlphabet.has(char))
|
|
9
8
|
|
|
10
|
-
test("StringId
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
)
|
|
9
|
+
test("StringId make generates nanoid-shaped values", () => {
|
|
10
|
+
for (let i = 0; i < 20; i++) {
|
|
11
|
+
const value = S.StringId.make()
|
|
12
|
+
expect(isNanoId(value)).toBe(true)
|
|
13
|
+
expect(S.is(S.StringId)(value)).toBe(true)
|
|
14
|
+
}
|
|
17
15
|
})
|