effect 4.0.0-rc.113 → 4.0.0-rc.115

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 (76) hide show
  1. package/dist/Effect.d.ts +268 -7
  2. package/dist/Effect.d.ts.map +1 -1
  3. package/dist/Effect.js +33 -2
  4. package/dist/Effect.js.map +1 -1
  5. package/dist/Effectable.d.ts +1 -2
  6. package/dist/Effectable.d.ts.map +1 -1
  7. package/dist/Effectable.js.map +1 -1
  8. package/dist/FileSystem.d.ts +3 -4
  9. package/dist/FileSystem.d.ts.map +1 -1
  10. package/dist/FileSystem.js.map +1 -1
  11. package/dist/Match.d.ts +1 -14
  12. package/dist/Match.d.ts.map +1 -1
  13. package/dist/Schema.d.ts +4 -4
  14. package/dist/Schema.d.ts.map +1 -1
  15. package/dist/SchemaAST.d.ts.map +1 -1
  16. package/dist/SchemaAST.js +43 -23
  17. package/dist/SchemaAST.js.map +1 -1
  18. package/dist/SchemaParser.d.ts.map +1 -1
  19. package/dist/SchemaParser.js +3 -2
  20. package/dist/SchemaParser.js.map +1 -1
  21. package/dist/SchemaRepresentation.d.ts +39 -24
  22. package/dist/SchemaRepresentation.d.ts.map +1 -1
  23. package/dist/SchemaRepresentation.js +37 -23
  24. package/dist/SchemaRepresentation.js.map +1 -1
  25. package/dist/internal/arbitrary/schema.js.map +1 -1
  26. package/dist/internal/effect.js +16 -8
  27. package/dist/internal/effect.js.map +1 -1
  28. package/dist/internal/schema/fromJsonSchemaDocument.js +221 -230
  29. package/dist/internal/schema/fromJsonSchemaDocument.js.map +1 -1
  30. package/dist/internal/schema/make.js +8 -3
  31. package/dist/internal/schema/make.js.map +1 -1
  32. package/dist/internal/schema/toCodeDocument.js +4 -4
  33. package/dist/internal/schema/toCodeDocument.js.map +1 -1
  34. package/dist/internal/schema/toEquivalence.js +2 -2
  35. package/dist/internal/schema/toEquivalence.js.map +1 -1
  36. package/dist/internal/schema/toFormatter.js +2 -2
  37. package/dist/internal/schema/toFormatter.js.map +1 -1
  38. package/dist/unstable/cli/Prompt.d.ts +6 -2
  39. package/dist/unstable/cli/Prompt.d.ts.map +1 -1
  40. package/dist/unstable/cli/Prompt.js +8 -7
  41. package/dist/unstable/cli/Prompt.js.map +1 -1
  42. package/dist/unstable/cli/internal/command.d.ts +1 -6
  43. package/dist/unstable/cli/internal/command.d.ts.map +1 -1
  44. package/dist/unstable/cli/internal/command.js +2 -0
  45. package/dist/unstable/cli/internal/command.js.map +1 -1
  46. package/dist/unstable/http/HttpEffect.d.ts.map +1 -1
  47. package/dist/unstable/http/HttpEffect.js +6 -2
  48. package/dist/unstable/http/HttpEffect.js.map +1 -1
  49. package/dist/unstable/http/HttpServerResponse.d.ts +13 -2
  50. package/dist/unstable/http/HttpServerResponse.d.ts.map +1 -1
  51. package/dist/unstable/http/HttpServerResponse.js +19 -5
  52. package/dist/unstable/http/HttpServerResponse.js.map +1 -1
  53. package/dist/unstable/persistence/Persistence.d.ts.map +1 -1
  54. package/dist/unstable/persistence/Persistence.js +2 -10
  55. package/dist/unstable/persistence/Persistence.js.map +1 -1
  56. package/package.json +2 -2
  57. package/src/Effect.ts +271 -7
  58. package/src/Effectable.ts +2 -2
  59. package/src/FileSystem.ts +3 -4
  60. package/src/Match.ts +1 -1
  61. package/src/Schema.ts +4 -7
  62. package/src/SchemaAST.ts +48 -25
  63. package/src/SchemaParser.ts +3 -2
  64. package/src/SchemaRepresentation.ts +39 -24
  65. package/src/internal/arbitrary/schema.ts +16 -16
  66. package/src/internal/effect.ts +34 -11
  67. package/src/internal/schema/fromJsonSchemaDocument.ts +294 -268
  68. package/src/internal/schema/make.ts +9 -4
  69. package/src/internal/schema/toCodeDocument.ts +4 -4
  70. package/src/internal/schema/toEquivalence.ts +2 -2
  71. package/src/internal/schema/toFormatter.ts +2 -2
  72. package/src/unstable/cli/Prompt.ts +22 -11
  73. package/src/unstable/cli/internal/command.ts +2 -0
  74. package/src/unstable/http/HttpEffect.ts +5 -2
  75. package/src/unstable/http/HttpServerResponse.ts +21 -5
  76. package/src/unstable/persistence/Persistence.ts +6 -16
@@ -25,10 +25,15 @@ const SchemaProto = {
25
25
  /** @internal */
26
26
  export function make<S extends Schema.Constraint>(ast: S["ast"], options?: object): S {
27
27
  function Schema() {}
28
- const self = Object.defineProperties(
29
- Object.setPrototypeOf(Schema, SchemaProto),
30
- Object.getOwnPropertyDescriptors({ ...options })
31
- )
28
+ const self = Object.setPrototypeOf(Schema, SchemaProto)
29
+ if (
30
+ options &&
31
+ (Object.hasOwn(options, "name") || Object.hasOwn(options, "length") || Object.hasOwn(options, "__proto__"))
32
+ ) {
33
+ Object.defineProperties(self, Object.getOwnPropertyDescriptors({ ...options }))
34
+ } else {
35
+ Object.assign(self, options)
36
+ }
32
37
  self.ast = ast
33
38
  self.rebuild = (ast: SchemaAST.AST) => make(ast, options)
34
39
  self.makeEffect = SchemaParser.makeEffect(self)
@@ -484,7 +484,7 @@ export function toCodeDocument(
484
484
  `${element.isOptional ? "Schema.optionalKey(" : ""}${type.runtime}${element.isOptional ? ")" : ""}${
485
485
  runtimeAnnotate(element.annotations, "annotateKey")
486
486
  }`,
487
- `${type.Type}${element.isOptional ? "?" : ""}`
487
+ element.isOptional ? `(${type.Type})?` : type.Type
488
488
  )
489
489
  })
490
490
  const rest = representation.rest.map((item, index) => recur(item, [...path, "rest", index]))
@@ -516,15 +516,15 @@ export function toCodeDocument(
516
516
  const properties = representation.propertySignatures.map((property, index) => {
517
517
  const isSymbol = typeof property.name === "symbol"
518
518
  const name = isSymbol
519
- ? addSymbol(property.name)
519
+ ? `[${addSymbol(property.name)}]`
520
520
  : formatPropertyKey(property.name)
521
521
  const type = recur(property.type, [...path, "propertySignatures", index, "type"])
522
522
  let runtime = type.runtime
523
523
  if (property.isMutable) runtime = `Schema.mutableKey(${runtime})`
524
524
  if (property.isOptional) runtime = `Schema.optionalKey(${runtime})`
525
525
  runtime += runtimeAnnotate(property.annotations, "annotateKey")
526
- const runtimeName = isSymbol ? `[${name}]` : name
527
- const typeName = `${property.isMutable ? "" : "readonly "}${runtimeName}${property.isOptional ? "?" : ""}`
526
+ const runtimeName = property.name === "__proto__" ? `[${name}]` : name
527
+ const typeName = `${property.isMutable ? "" : "readonly "}${name}${property.isOptional ? "?" : ""}`
528
528
  return {
529
529
  code: makeCode(`${runtimeName}: ${runtime}`, `${typeName}: ${type.Type}`)
530
530
  }
@@ -153,8 +153,8 @@ function recur(ast: SchemaAST.AST, path: ReadonlyArray<PropertyKey>): Equivalenc
153
153
  })
154
154
  }
155
155
  case "Suspend": {
156
- const get = SchemaAST.memoizeThunk(() => recur(ast.thunk(), path))
157
- return Equivalence.make((a, b) => get()(a, b))
156
+ let equivalence: Equivalence.Equivalence<any>
157
+ return Equivalence.make((a, b) => (equivalence ??= recur(ast.thunk(), path))(a, b))
158
158
  }
159
159
  }
160
160
  }
@@ -222,8 +222,8 @@ export function toFormatter<T>(ast: SchemaAST.AST, options?: {
222
222
  }
223
223
  }
224
224
  case "Suspend": {
225
- const get = SchemaAST.memoizeThunk(() => recur(ast.thunk()))
226
- return (value) => get()(value)
225
+ let formatter: Formatter<any>
226
+ return (value) => (formatter ??= recur(ast.thunk()))(value)
227
227
  }
228
228
  }
229
229
  }
@@ -447,9 +447,9 @@ export interface FileOptions extends ThemeOptions {
447
447
  */
448
448
  export interface SelectOptions<A> extends ThemeOptions {
449
449
  /**
450
- * The message to display in the prompt.
450
+ * The prompt message. Omit to display only the choices.
451
451
  */
452
- readonly message: string
452
+ readonly message?: string | undefined
453
453
  /**
454
454
  * The choices to display to the user.
455
455
  */
@@ -468,6 +468,10 @@ export interface SelectOptions<A> extends ThemeOptions {
468
468
  * @since 4.0.0
469
469
  */
470
470
  export interface AutoCompleteOptions<A> extends SelectOptions<A> {
471
+ /**
472
+ * The required prompt message.
473
+ */
474
+ readonly message: string
471
475
  /**
472
476
  * The label used for the filter display (defaults to "filter").
473
477
  */
@@ -2699,7 +2703,9 @@ const handleFileProcess = (options: FileOptionsReq) => {
2699
2703
  })
2700
2704
  }
2701
2705
 
2702
- interface SelectOptionsReq<A> extends OptionsReq<SelectOptions<A>> {}
2706
+ interface SelectOptionsReq<A> extends SelectOptions<A> {
2707
+ readonly maxPerPage: number
2708
+ }
2703
2709
  interface MultiSelectOptionsReq extends MultiSelectOptions {}
2704
2710
 
2705
2711
  type MultiSelectState = {
@@ -2826,7 +2832,7 @@ const renderMultiSelectNextFrame = Effect.fnUntraced(
2826
2832
  const trailingSymbol = annotateSymbol(figures.pointerSmall, figures.mutedColor)
2827
2833
  const promptMsg = renderSelectOutput(leadingSymbol, trailingSymbol, options)
2828
2834
  const error = renderMultiSelectError(state, figures.pointer, figures)
2829
- return Ansi.cursorHide + promptMsg + "\n" + choices + error
2835
+ return Ansi.cursorHide + withSelectHeader(promptMsg, choices) + error
2830
2836
  }
2831
2837
  )
2832
2838
 
@@ -2839,7 +2845,7 @@ const renderMultiSelectSubmission = Effect.fnUntraced(
2839
2845
  const selectedText = selectedChoices.join(", ")
2840
2846
  const leadingSymbol = annotateSymbol(figures.tick, figures.successColor)
2841
2847
  const trailingSymbol = annotateSymbol(figures.ellipsis, figures.mutedColor)
2842
- const promptMsg = renderSelectOutput(leadingSymbol, trailingSymbol, options)
2848
+ const promptMsg = renderSelectOutput(leadingSymbol, trailingSymbol, options) ?? leadingSymbol
2843
2849
  return promptMsg + " " + Ansi.annotate(selectedText, figures.submittedColor) + "\n"
2844
2850
  }
2845
2851
  )
@@ -2901,7 +2907,7 @@ const handleMultiSelectClear = <A>(options: SelectOptionsReq<A>) =>
2901
2907
  const promptText = renderSelectOutput(figures.prefix, figures.pointerSmall, options, { plain: true })
2902
2908
  const choicesText = renderMultiSelectChoices(state, options, figures, { plain: true })
2903
2909
  const errorText = renderMultiSelectError(state, figures.pointer, figures, { plain: true })
2904
- const clearOutput = clearOutputWithError(`${promptText}\n${choicesText}`, columns, errorText)
2910
+ const clearOutput = clearOutputWithError(withSelectHeader(promptText, choicesText), columns, errorText)
2905
2911
  return clearOutput + clearPrompt
2906
2912
  })
2907
2913
 
@@ -3265,7 +3271,6 @@ type AutoCompleteState = {
3265
3271
  readonly filtered: ReadonlyArray<number>
3266
3272
  }
3267
3273
 
3268
- interface SelectOptionsReq<A> extends OptionsReq<SelectOptions<A>> {}
3269
3274
  interface AutoCompleteOptionsReq<A> extends OptionsReq<AutoCompleteOptions<A>> {}
3270
3275
 
3271
3276
  const filterAutoCompleteChoices = <A>(choices: ReadonlyArray<SelectChoice<A>>, query: string) => {
@@ -3302,7 +3307,13 @@ const renderSelectOutput = <A>(
3302
3307
  trailingSymbol: string,
3303
3308
  options: SelectOptionsReq<A>,
3304
3309
  renderOptions?: RenderOptions | undefined
3305
- ) => renderPrompt("", options.message, leadingSymbol, trailingSymbol, renderOptions)
3310
+ ): string | undefined =>
3311
+ options.message === undefined
3312
+ ? undefined
3313
+ : renderPrompt("", options.message, leadingSymbol, trailingSymbol, renderOptions)
3314
+
3315
+ const withSelectHeader = (header: string | undefined, body: string): string =>
3316
+ header === undefined ? body : header + "\n" + body
3306
3317
 
3307
3318
  const renderAutoCompleteFilter = <A>(
3308
3319
  state: AutoCompleteState,
@@ -3464,7 +3475,7 @@ const renderSelectNextFrame = Effect.fnUntraced(function*<A>(state: SelectState,
3464
3475
  const leadingSymbol = annotateSymbol(figures.prefix, figures.primaryColor)
3465
3476
  const trailingSymbol = annotateSymbol(figures.pointerSmall, figures.mutedColor)
3466
3477
  const promptMsg = renderSelectOutput(leadingSymbol, trailingSymbol, options)
3467
- return Ansi.cursorHide + promptMsg + "\n" + choices
3478
+ return Ansi.cursorHide + withSelectHeader(promptMsg, choices)
3468
3479
  })
3469
3480
 
3470
3481
  const renderAutoCompleteNextFrame = Effect.fnUntraced(function*<A>(
@@ -3484,7 +3495,7 @@ const renderSelectSubmission = Effect.fnUntraced(function*<A>(state: SelectState
3484
3495
  const selected = options.choices[state].title
3485
3496
  const leadingSymbol = annotateSymbol(figures.tick, figures.successColor)
3486
3497
  const trailingSymbol = annotateSymbol(figures.ellipsis, figures.mutedColor)
3487
- const promptMsg = renderSelectOutput(leadingSymbol, trailingSymbol, options)
3498
+ const promptMsg = renderSelectOutput(leadingSymbol, trailingSymbol, options) ?? leadingSymbol
3488
3499
  return promptMsg + " " + Ansi.annotate(selected, figures.submittedColor) + "\n"
3489
3500
  })
3490
3501
 
@@ -3585,7 +3596,7 @@ const handleSelectClear = <A>(options: SelectOptionsReq<A>) =>
3585
3596
  const clearPrompt = Ansi.eraseLine + Ansi.cursorLeft
3586
3597
  const promptText = renderSelectOutput(figures.prefix, figures.pointerSmall, options, { plain: true })
3587
3598
  const choicesText = renderSelectChoices(state, options, figures, { plain: true })
3588
- const clearOutput = eraseText(`${promptText}\n${choicesText}`, columns)
3599
+ const clearOutput = eraseText(withSelectHeader(promptText, choicesText), columns)
3589
3600
  return clearOutput + clearPrompt
3590
3601
  })
3591
3602
 
@@ -234,6 +234,8 @@ export const makeCommand = <const Name extends string, Input, E, R, ContextInput
234
234
 
235
235
  /**
236
236
  * Converts a single flag param into a FlagDoc for help display.
237
+ *
238
+ * @internal
237
239
  */
238
240
  export const toFlagDoc = (
239
241
  single: Param.Single<typeof Param.flagKind, unknown>,
@@ -317,9 +317,12 @@ export const toWebHandlerWith = <Provided, R = never, ReqR = Exclude<R, Provided
317
317
  {
318
318
  const resolveSymbol = Symbol.for("@effect/platform/HttpApp/resolve")
319
319
  const httpApp = toHandled(self, (request, response) => {
320
- if (request.method !== "HEAD") response = scopeTransferToStream(response)
320
+ const withoutBody = request.method === "HEAD"
321
+ if (!Response.omitsBody(response, withoutBody)) {
322
+ response = scopeTransferToStream(response)
323
+ }
321
324
  ;(request as any)[resolveSymbol](
322
- Response.toWeb(response, { withoutBody: request.method === "HEAD", context })
325
+ Response.toWeb(response, { withoutBody, context })
323
326
  )
324
327
  return Effect.void
325
328
  }, middleware)
@@ -14,7 +14,7 @@ import type * as ByteSize from "../../ByteSize.ts"
14
14
  import * as Context from "../../Context.ts"
15
15
  import * as Effect from "../../Effect.ts"
16
16
  import * as ErrorReporter from "../../ErrorReporter.ts"
17
- import { dual } from "../../Function.ts"
17
+ import { constVoid, dual } from "../../Function.ts"
18
18
  import * as Inspectable from "../../Inspectable.ts"
19
19
  import { PipeInspectableProto } from "../../internal/core.ts"
20
20
  import * as Option from "../../Option.ts"
@@ -1251,14 +1251,27 @@ export const setStatus: {
1251
1251
  })
1252
1252
  )
1253
1253
 
1254
+ /**
1255
+ * Returns whether a response must omit its body because its status is 204, 205,
1256
+ * or 304, or `withoutBody` is true.
1257
+ *
1258
+ * @category predicates
1259
+ * @since 4.0.0
1260
+ */
1261
+ export const omitsBody = (response: HttpServerResponse, withoutBody = false): boolean =>
1262
+ withoutBody || response.status === 204 || response.status === 205 || response.status === 304
1263
+
1254
1264
  /**
1255
1265
  * Converts an `HttpServerResponse` to a Web `Response`.
1256
1266
  *
1257
1267
  * **Details**
1258
1268
  *
1259
1269
  * Cookies are appended as `Set-Cookie` headers. Stream bodies are converted using
1260
- * the supplied context, and `withoutBody` can be used for responses such as HEAD
1261
- * responses.
1270
+ * the supplied context.
1271
+ *
1272
+ * Bodies are omitted for statuses 204, 205, and 304, or when `withoutBody` is true
1273
+ * (for example, for HEAD responses). Omitted raw `ReadableStream` bodies are
1274
+ * cancelled without awaiting completion, and cancellation errors are ignored.
1262
1275
  *
1263
1276
  * @category converting
1264
1277
  * @since 4.0.0
@@ -1277,14 +1290,17 @@ export const toWeb = (
1277
1290
  headers.append("set-cookie", header)
1278
1291
  }
1279
1292
  }
1280
- if (options?.withoutBody) {
1293
+ const body = response.body
1294
+ if (omitsBody(response, options?.withoutBody)) {
1295
+ if (body._tag === "Raw" && isReadableStream(body.body)) {
1296
+ body.body.cancel().catch(constVoid)
1297
+ }
1281
1298
  return new Response(undefined, {
1282
1299
  status: response.status,
1283
1300
  statusText: response.statusText as string,
1284
1301
  headers
1285
1302
  })
1286
1303
  }
1287
- const body = response.body
1288
1304
  switch (body._tag) {
1289
1305
  case "Empty": {
1290
1306
  return new Response(undefined, {
@@ -385,11 +385,6 @@ export const layerBackingSqlMultiTable: Layer.Layer<
385
385
  `.unprepared
386
386
  })
387
387
 
388
- const wrapString = sql.onDialectOrElse({
389
- mssql: () => (s: string) => `N'${s}'`,
390
- orElse: () => (s: string) => `'${s}'`
391
- })
392
-
393
388
  return identity<BackingPersistenceStore>({
394
389
  get: (key) =>
395
390
  sql<
@@ -419,9 +414,9 @@ export const layerBackingSqlMultiTable: Layer.Layer<
419
414
  })
420
415
  ),
421
416
  getMany: (keys) =>
422
- sql<{ id: string; value: string }>`SELECT id, value FROM ${table} WHERE id IN (${
423
- sql.literal(keys.map(wrapString).join(", "))
424
- }) AND (expires IS NULL OR expires > ${clock.currentTimeMillisUnsafe()})`.unprepared.pipe(
417
+ sql<{ id: string; value: string }>`SELECT id, value FROM ${table} WHERE ${
418
+ sql.in("id", keys)
419
+ } AND (expires IS NULL OR expires > ${clock.currentTimeMillisUnsafe()})`.unprepared.pipe(
425
420
  Effect.mapError((cause) =>
426
421
  new PersistenceError({
427
422
  message: `Failed to getMany from backing store`,
@@ -726,11 +721,6 @@ export const layerBackingSql: Layer.Layer<
726
721
  `.unprepared
727
722
  })
728
723
 
729
- const wrapString = sql.onDialectOrElse({
730
- mssql: () => (s: string) => `N'${s}'`,
731
- orElse: () => (s: string) => `'${s}'`
732
- })
733
-
734
724
  return BackingPersistence.of({
735
725
  make: Effect.fnUntraced(function*(storeId) {
736
726
  const clock = yield* Clock.Clock
@@ -764,9 +754,9 @@ export const layerBackingSql: Layer.Layer<
764
754
  })
765
755
  ),
766
756
  getMany: (keys) =>
767
- sql<{ id: string; value: string }>`SELECT id, value FROM ${table} WHERE store_id = ${storeId} AND id IN (${
768
- sql.literal(keys.map(wrapString).join(", "))
769
- }) AND (expires IS NULL OR expires > ${clock.currentTimeMillisUnsafe()})`.unprepared.pipe(
757
+ sql<{ id: string; value: string }>`SELECT id, value FROM ${table} WHERE store_id = ${storeId} AND ${
758
+ sql.in("id", keys)
759
+ } AND (expires IS NULL OR expires > ${clock.currentTimeMillisUnsafe()})`.unprepared.pipe(
770
760
  Effect.mapError((cause) =>
771
761
  new PersistenceError({
772
762
  message: `Failed to getMany from backing store`,