effect 2.0.0-next.60 → 2.0.0-next.61

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 (41) hide show
  1. package/dist/cjs/BigDecimal.js +19 -5
  2. package/dist/cjs/BigDecimal.js.map +1 -1
  3. package/dist/cjs/ConfigProvider.js +8 -1
  4. package/dist/cjs/ConfigProvider.js.map +1 -1
  5. package/dist/cjs/ReadonlyRecord.js +28 -1
  6. package/dist/cjs/ReadonlyRecord.js.map +1 -1
  7. package/dist/cjs/internal/configProvider.js +103 -32
  8. package/dist/cjs/internal/configProvider.js.map +1 -1
  9. package/dist/cjs/internal/fiberRuntime.js +4 -4
  10. package/dist/cjs/internal/fiberRuntime.js.map +1 -1
  11. package/dist/cjs/internal/metric.js +2 -2
  12. package/dist/cjs/internal/metric.js.map +1 -1
  13. package/dist/cjs/internal/version.js +1 -1
  14. package/dist/dts/BigDecimal.d.ts +2 -2
  15. package/dist/dts/BigDecimal.d.ts.map +1 -1
  16. package/dist/dts/ConfigProvider.d.ts +28 -0
  17. package/dist/dts/ConfigProvider.d.ts.map +1 -1
  18. package/dist/dts/ReadonlyRecord.d.ts +26 -0
  19. package/dist/dts/ReadonlyRecord.d.ts.map +1 -1
  20. package/dist/dts/internal/version.d.ts +1 -1
  21. package/dist/esm/BigDecimal.js +17 -4
  22. package/dist/esm/BigDecimal.js.map +1 -1
  23. package/dist/esm/ConfigProvider.js +7 -0
  24. package/dist/esm/ConfigProvider.js.map +1 -1
  25. package/dist/esm/ReadonlyRecord.js +26 -0
  26. package/dist/esm/ReadonlyRecord.js.map +1 -1
  27. package/dist/esm/internal/configProvider.js +101 -31
  28. package/dist/esm/internal/configProvider.js.map +1 -1
  29. package/dist/esm/internal/fiberRuntime.js +4 -4
  30. package/dist/esm/internal/fiberRuntime.js.map +1 -1
  31. package/dist/esm/internal/metric.js +2 -2
  32. package/dist/esm/internal/metric.js.map +1 -1
  33. package/dist/esm/internal/version.js +1 -1
  34. package/package.json +1 -1
  35. package/src/BigDecimal.ts +19 -4
  36. package/src/ConfigProvider.ts +32 -0
  37. package/src/ReadonlyRecord.ts +28 -0
  38. package/src/internal/configProvider.ts +133 -33
  39. package/src/internal/fiberRuntime.ts +4 -4
  40. package/src/internal/metric.ts +2 -2
  41. package/src/internal/version.ts +1 -1
@@ -104,6 +104,30 @@ export declare namespace ConfigProvider {
104
104
  readonly pathDelim: string
105
105
  readonly seqDelim: string
106
106
  }
107
+
108
+ /**
109
+ * @since 1.0.0
110
+ * @category models
111
+ */
112
+ export type KeyComponent = KeyName | KeyIndex
113
+
114
+ /**
115
+ * @since 1.0.0
116
+ * @category models
117
+ */
118
+ export interface KeyName {
119
+ readonly _tag: "KeyName"
120
+ readonly name: string
121
+ }
122
+
123
+ /**
124
+ * @since 1.0.0
125
+ * @category models
126
+ */
127
+ export interface KeyIndex {
128
+ readonly _tag: "KeyIndex"
129
+ readonly index: number
130
+ }
107
131
  }
108
132
 
109
133
  /**
@@ -163,6 +187,14 @@ export const fromEnv: (config?: ConfigProvider.FromEnvConfig) => ConfigProvider
163
187
  */
164
188
  export const fromFlat: (flat: ConfigProvider.Flat) => ConfigProvider = internal.fromFlat
165
189
 
190
+ /**
191
+ * Constructs a new `ConfigProvider` from a JSON object.
192
+ *
193
+ * @since 2.0.0
194
+ * @category constructors
195
+ */
196
+ export const fromJson: (json: unknown) => ConfigProvider = internal.fromJson
197
+
166
198
  /**
167
199
  * Constructs a ConfigProvider using a map and the specified delimiter string,
168
200
  * which determines how to split the keys in the map into path segments.
@@ -117,6 +117,34 @@ export const fromIterable: <V>(entries: Iterable<readonly [string, V]>) => Recor
117
117
  identity
118
118
  )
119
119
 
120
+ /**
121
+ * Creates a new record from an iterable, utilizing the provided function to determine the key for each element.
122
+ *
123
+ * @param items - An iterable containing elements.
124
+ * @param f - A function that extracts the key for each element.
125
+ *
126
+ * @example
127
+ * import { fromIterableBy } from "effect/ReadonlyRecord"
128
+ *
129
+ * const users = [
130
+ * { id: "2", name: "name2" },
131
+ * { id: "1", name: "name1" }
132
+ * ]
133
+ *
134
+ * assert.deepStrictEqual(
135
+ * fromIterableBy(users, user => user.id),
136
+ * {
137
+ * "2": { id: "2", name: "name2" },
138
+ * "1": { id: "1", name: "name1" }
139
+ * }
140
+ * )
141
+ *
142
+ * @category constructors
143
+ * @since 2.0.0
144
+ */
145
+ export const fromIterableBy = <A>(items: Iterable<A>, f: (a: A) => string): Record<string, A> =>
146
+ fromIterableWith(items, (a) => [f(a), a])
147
+
120
148
  /**
121
149
  * Builds a record from an iterable of key-value pairs.
122
150
  *
@@ -12,7 +12,7 @@ import * as HashSet from "../HashSet.js"
12
12
  import * as number from "../Number.js"
13
13
  import * as Option from "../Option.js"
14
14
  import { pipeArguments } from "../Pipeable.js"
15
- import * as RA from "../ReadonlyArray.js"
15
+ import * as ReadonlyArray from "../ReadonlyArray.js"
16
16
  import type * as _config from "./config.js"
17
17
  import * as configError from "./configError.js"
18
18
  import * as pathPatch from "./configProvider/pathPatch.js"
@@ -20,6 +20,8 @@ import * as core from "./core.js"
20
20
  import * as OpCodes from "./opCodes/config.js"
21
21
  import * as StringUtils from "./string-utils.js"
22
22
 
23
+ type KeyComponent = ConfigProvider.ConfigProvider.KeyComponent
24
+
23
25
  const concat = <A, B>(l: ReadonlyArray<A>, r: ReadonlyArray<B>): ReadonlyArray<A | B> => [...l, ...r]
24
26
 
25
27
  /** @internal */
@@ -81,12 +83,12 @@ export const makeFlat = (
81
83
  export const fromFlat = (flat: ConfigProvider.ConfigProvider.Flat): ConfigProvider.ConfigProvider =>
82
84
  make({
83
85
  load: (config) =>
84
- core.flatMap(fromFlatLoop(flat, RA.empty(), config, false), (chunk) =>
85
- Option.match(RA.head(chunk), {
86
+ core.flatMap(fromFlatLoop(flat, ReadonlyArray.empty(), config, false), (chunk) =>
87
+ Option.match(ReadonlyArray.head(chunk), {
86
88
  onNone: () =>
87
89
  core.fail(
88
90
  configError.MissingData(
89
- RA.empty(),
91
+ ReadonlyArray.empty(),
90
92
  `Expected a single value having structure: ${config}`
91
93
  )
92
94
  ),
@@ -100,7 +102,7 @@ export const fromEnv = (
100
102
  config: Partial<ConfigProvider.ConfigProvider.FromEnvConfig> = {}
101
103
  ): ConfigProvider.ConfigProvider => {
102
104
  const { pathDelim, seqDelim } = Object.assign({}, { pathDelim: "_", seqDelim: "," }, config)
103
- const makePathString = (path: ReadonlyArray<string>): string => pipe(path, RA.join(pathDelim))
105
+ const makePathString = (path: ReadonlyArray<string>): string => pipe(path, ReadonlyArray.join(pathDelim))
104
106
  const unmakePathString = (pathString: string): ReadonlyArray<string> => pathString.split(pathDelim)
105
107
 
106
108
  const getEnv = () =>
@@ -130,7 +132,7 @@ export const fromEnv = (
130
132
  const keyPaths = Array.from(keys).map((value) => unmakePathString(value.toUpperCase()))
131
133
  const filteredKeyPaths = keyPaths.filter((keyPath) => {
132
134
  for (let i = 0; i < path.length; i++) {
133
- const pathComponent = pipe(path, RA.unsafeGet(i))
135
+ const pathComponent = pipe(path, ReadonlyArray.unsafeGet(i))
134
136
  const currentElement = keyPath[i]
135
137
  if (currentElement === undefined || pathComponent !== currentElement) {
136
138
  return false
@@ -150,7 +152,7 @@ export const fromMap = (
150
152
  config: Partial<ConfigProvider.ConfigProvider.FromMapConfig> = {}
151
153
  ): ConfigProvider.ConfigProvider => {
152
154
  const { pathDelim, seqDelim } = Object.assign({ seqDelim: ",", pathDelim: "." }, config)
153
- const makePathString = (path: ReadonlyArray<string>): string => pipe(path, RA.join(pathDelim))
155
+ const makePathString = (path: ReadonlyArray<string>): string => pipe(path, ReadonlyArray.join(pathDelim))
154
156
  const unmakePathString = (pathString: string): ReadonlyArray<string> => pathString.split(pathDelim)
155
157
  const mapWithIndexSplit = splitIndexInKeys(
156
158
  map,
@@ -179,7 +181,7 @@ export const fromMap = (
179
181
  const keyPaths = Array.from(mapWithIndexSplit.keys()).map(unmakePathString)
180
182
  const filteredKeyPaths = keyPaths.filter((keyPath) => {
181
183
  for (let i = 0; i < path.length; i++) {
182
- const pathComponent = pipe(path, RA.unsafeGet(i))
184
+ const pathComponent = pipe(path, ReadonlyArray.unsafeGet(i))
183
185
  const currentElement = keyPath[i]
184
186
  if (currentElement === undefined || pathComponent !== currentElement) {
185
187
  return false
@@ -199,14 +201,14 @@ const extend = <A, B>(
199
201
  left: ReadonlyArray<A>,
200
202
  right: ReadonlyArray<B>
201
203
  ): [ReadonlyArray<A>, ReadonlyArray<B>] => {
202
- const leftPad = RA.unfold(
204
+ const leftPad = ReadonlyArray.unfold(
203
205
  left.length,
204
206
  (index) =>
205
207
  index >= right.length ?
206
208
  Option.none() :
207
209
  Option.some([leftDef(index), index + 1])
208
210
  )
209
- const rightPad = RA.unfold(
211
+ const rightPad = ReadonlyArray.unfold(
210
212
  right.length,
211
213
  (index) =>
212
214
  index >= left.length ?
@@ -240,7 +242,7 @@ const fromFlatLoop = <A>(
240
242
  const op = config as _config.ConfigPrimitive
241
243
  switch (op._tag) {
242
244
  case OpCodes.OP_CONSTANT: {
243
- return core.succeed(RA.of(op.value)) as Effect.Effect<
245
+ return core.succeed(ReadonlyArray.of(op.value)) as Effect.Effect<
244
246
  never,
245
247
  ConfigError.ConfigError,
246
248
  ReadonlyArray<A>
@@ -298,7 +300,7 @@ const fromFlatLoop = <A>(
298
300
  return core.suspend(() =>
299
301
  fromFlatLoop(
300
302
  flat,
301
- concat(prefix, RA.of(op.name)),
303
+ concat(prefix, ReadonlyArray.of(op.name)),
302
304
  op.config,
303
305
  split
304
306
  )
@@ -312,7 +314,7 @@ const fromFlatLoop = <A>(
312
314
  flat.load(prefix, op, split),
313
315
  core.flatMap((values) => {
314
316
  if (values.length === 0) {
315
- const name = pipe(RA.last(prefix), Option.getOrElse(() => "<n/a>"))
317
+ const name = pipe(ReadonlyArray.last(prefix), Option.getOrElse(() => "<n/a>"))
316
318
  return core.fail(configError.MissingData([], `Expected ${op.description} with name ${name}`))
317
319
  }
318
320
  return core.succeed(values)
@@ -331,20 +333,20 @@ const fromFlatLoop = <A>(
331
333
  core.flatMap((indices) => {
332
334
  if (indices.length === 0) {
333
335
  return core.suspend(() =>
334
- core.map(fromFlatLoop(flat, patchedPrefix, op.config, true), RA.of)
336
+ core.map(fromFlatLoop(flat, patchedPrefix, op.config, true), ReadonlyArray.of)
335
337
  ) as unknown as Effect.Effect<never, ConfigError.ConfigError, ReadonlyArray<A>>
336
338
  }
337
339
  return pipe(
338
340
  core.forEachSequential(
339
341
  indices,
340
- (index) => fromFlatLoop(flat, RA.append(prefix, `[${index}]`), op.config, true)
342
+ (index) => fromFlatLoop(flat, ReadonlyArray.append(prefix, `[${index}]`), op.config, true)
341
343
  ),
342
344
  core.map((chunkChunk) => {
343
- const flattened = RA.flatten(chunkChunk)
345
+ const flattened = ReadonlyArray.flatten(chunkChunk)
344
346
  if (flattened.length === 0) {
345
- return RA.of(RA.empty<A>())
347
+ return ReadonlyArray.of(ReadonlyArray.empty<A>())
346
348
  }
347
- return RA.of(flattened)
349
+ return ReadonlyArray.of(flattened)
348
350
  })
349
351
  ) as unknown as Effect.Effect<never, ConfigError.ConfigError, ReadonlyArray<A>>
350
352
  })
@@ -365,19 +367,21 @@ const fromFlatLoop = <A>(
365
367
  core.forEachSequential((key) =>
366
368
  fromFlatLoop(
367
369
  flat,
368
- concat(prefix, RA.of(key)),
370
+ concat(prefix, ReadonlyArray.of(key)),
369
371
  op.valueConfig,
370
372
  split
371
373
  )
372
374
  ),
373
375
  core.map((values) => {
374
376
  if (values.length === 0) {
375
- return RA.of(HashMap.empty())
377
+ return ReadonlyArray.of(HashMap.empty())
376
378
  }
377
379
  const matrix = values.map((x) => Array.from(x))
378
380
  return pipe(
379
381
  transpose(matrix),
380
- RA.map((values) => HashMap.fromIterable(RA.zip(RA.fromIterable(keys), values)))
382
+ ReadonlyArray.map((values) =>
383
+ HashMap.fromIterable(ReadonlyArray.zip(ReadonlyArray.fromIterable(keys), values))
384
+ )
381
385
  )
382
386
  })
383
387
  )
@@ -407,17 +411,17 @@ const fromFlatLoop = <A>(
407
411
  return core.fail(right.left)
408
412
  }
409
413
  if (Either.isRight(left) && Either.isRight(right)) {
410
- const path = pipe(prefix, RA.join("."))
414
+ const path = pipe(prefix, ReadonlyArray.join("."))
411
415
  const fail = fromFlatLoopFail(prefix, path)
412
416
  const [lefts, rights] = extend(
413
417
  fail,
414
418
  fail,
415
- pipe(left.right, RA.map(Either.right)),
416
- pipe(right.right, RA.map(Either.right))
419
+ pipe(left.right, ReadonlyArray.map(Either.right)),
420
+ pipe(right.right, ReadonlyArray.map(Either.right))
417
421
  )
418
422
  return pipe(
419
423
  lefts,
420
- RA.zip(rights),
424
+ ReadonlyArray.zip(rights),
421
425
  core.forEachSequential(([left, right]) =>
422
426
  pipe(
423
427
  core.zip(left, right),
@@ -590,8 +594,8 @@ export const within = dual<
590
594
  f: (self: ConfigProvider.ConfigProvider) => ConfigProvider.ConfigProvider
591
595
  ) => ConfigProvider.ConfigProvider
592
596
  >(3, (self, path, f) => {
593
- const unnest = RA.reduce(path, self, (provider, name) => unnested(provider, name))
594
- const nest = RA.reduceRight(path, f(unnest), (provider, name) => nested(provider, name))
597
+ const unnest = ReadonlyArray.reduce(path, self, (provider, name) => unnested(provider, name))
598
+ const nest = ReadonlyArray.reduceRight(path, f(unnest), (provider, name) => nested(provider, name))
595
599
  return orElse(nest, () => self)
596
600
  })
597
601
 
@@ -612,7 +616,7 @@ const parsePrimitive = <A>(
612
616
  primitive.parse(text),
613
617
  core.mapBoth({
614
618
  onFailure: configError.prefixed(path),
615
- onSuccess: RA.of
619
+ onSuccess: ReadonlyArray.of
616
620
  })
617
621
  )
618
622
  }
@@ -635,8 +639,8 @@ const indicesFrom = (quotedIndices: HashSet.HashSet<string>): Effect.Effect<neve
635
639
  pipe(
636
640
  core.forEachSequential(quotedIndices, parseQuotedIndex),
637
641
  core.mapBoth({
638
- onFailure: () => RA.empty<number>(),
639
- onSuccess: RA.sort(number.Order)
642
+ onFailure: () => ReadonlyArray.empty<number>(),
643
+ onSuccess: ReadonlyArray.sort(number.Order)
640
644
  }),
641
645
  core.either,
642
646
  core.map(Either.merge)
@@ -668,10 +672,10 @@ const splitIndexInKeys = (
668
672
  for (const [pathString, value] of map) {
669
673
  const keyWithIndex = pipe(
670
674
  unmakePathString(pathString),
671
- RA.flatMap((key) =>
675
+ ReadonlyArray.flatMap((key) =>
672
676
  Option.match(splitIndexFrom(key), {
673
- onNone: () => RA.of(key),
674
- onSome: ([key, index]) => RA.make(key, `[${index}]`)
677
+ onNone: () => ReadonlyArray.of(key),
678
+ onSome: ([key, index]) => ReadonlyArray.make(key, `[${index}]`)
675
679
  })
676
680
  )
677
681
  )
@@ -705,3 +709,99 @@ const parseInteger = (str: string): Option.Option<number> => {
705
709
  Option.none() :
706
710
  Option.some(parsedIndex)
707
711
  }
712
+
713
+ const keyName = (name: string): KeyComponent => ({
714
+ _tag: "KeyName",
715
+ name
716
+ })
717
+
718
+ const keyIndex = (index: number): KeyComponent => ({
719
+ _tag: "KeyIndex",
720
+ index
721
+ })
722
+
723
+ interface JsonMap {
724
+ [member: string]: string | number | boolean | null | JsonArray | JsonMap
725
+ }
726
+ interface JsonArray extends Array<string | number | boolean | null | JsonArray | JsonMap> {}
727
+
728
+ /** @internal */
729
+ export const fromJson = (json: unknown): ConfigProvider.ConfigProvider => {
730
+ const hiddenDelimiter = "\ufeff"
731
+ const indexedEntries = ReadonlyArray.map(
732
+ getIndexedEntries(json as JsonMap),
733
+ ([key, value]): [string, string] => [configPathToString(key).join(hiddenDelimiter), value]
734
+ )
735
+ return fromMap(new Map(indexedEntries), {
736
+ pathDelim: hiddenDelimiter,
737
+ seqDelim: hiddenDelimiter
738
+ })
739
+ }
740
+
741
+ const configPathToString = (path: ReadonlyArray<KeyComponent>): ReadonlyArray<string> => {
742
+ const output: Array<string> = []
743
+ let i = 0
744
+ while (i < path.length) {
745
+ const component = path[i]
746
+ if (component._tag === "KeyName") {
747
+ if (i + 1 < path.length) {
748
+ const nextComponent = path[i + 1]
749
+ if (nextComponent._tag === "KeyIndex") {
750
+ output.push(`${component.name}[${nextComponent.index}]`)
751
+ i += 2
752
+ } else {
753
+ output.push(component.name)
754
+ i += 1
755
+ }
756
+ } else {
757
+ output.push(component.name)
758
+ i += 1
759
+ }
760
+ }
761
+ }
762
+ return output
763
+ }
764
+
765
+ const getIndexedEntries = (
766
+ config: JsonMap
767
+ ): ReadonlyArray<[path: ReadonlyArray<KeyComponent>, value: string]> => {
768
+ const loopAny = (
769
+ path: ReadonlyArray<KeyComponent>,
770
+ value: string | number | boolean | JsonMap | JsonArray | null
771
+ ): ReadonlyArray<[path: ReadonlyArray<KeyComponent>, value: string]> => {
772
+ if (typeof value === "string") {
773
+ return ReadonlyArray.make([path, value] as [ReadonlyArray<KeyComponent>, string])
774
+ }
775
+ if (typeof value === "number" || typeof value === "boolean") {
776
+ return ReadonlyArray.make([path, String(value)] as [ReadonlyArray<KeyComponent>, string])
777
+ }
778
+ if (Array.isArray(value)) {
779
+ return loopArray(path, value)
780
+ }
781
+ if (typeof value === "object" && value !== null) {
782
+ return loopObject(path, value)
783
+ }
784
+ return ReadonlyArray.empty<[ReadonlyArray<KeyComponent>, string]>()
785
+ }
786
+ const loopArray = (
787
+ path: ReadonlyArray<KeyComponent>,
788
+ values: JsonArray
789
+ ): ReadonlyArray<[path: ReadonlyArray<KeyComponent>, value: string]> =>
790
+ ReadonlyArray.match(values, {
791
+ onEmpty: () => ReadonlyArray.make([path, "<nil>"] as [ReadonlyArray<KeyComponent>, string]),
792
+ onNonEmpty: ReadonlyArray.flatMap((value, index) => loopAny(ReadonlyArray.append(path, keyIndex(index)), value))
793
+ })
794
+ const loopObject = (
795
+ path: ReadonlyArray<KeyComponent>,
796
+ value: JsonMap
797
+ ): ReadonlyArray<[path: ReadonlyArray<KeyComponent>, value: string]> =>
798
+ Object.entries(value).flatMap(([key, value]) => {
799
+ const newPath = ReadonlyArray.append(path, keyName(key))
800
+ const result = loopAny(newPath, value)
801
+ if (ReadonlyArray.isEmptyReadonlyArray(result)) {
802
+ return ReadonlyArray.make([newPath, ""] as [ReadonlyArray<KeyComponent>, string])
803
+ }
804
+ return result
805
+ })
806
+ return loopObject(ReadonlyArray.empty(), config)
807
+ }
@@ -80,9 +80,9 @@ export const fiberLifetimes = metric.tagged(
80
80
  metric.histogram(
81
81
  "effect_fiber_lifetimes",
82
82
  metricBoundaries.exponential({
83
- start: 1.0,
84
- factor: 1.3,
85
- count: 100
83
+ start: 0.5,
84
+ factor: 2,
85
+ count: 35
86
86
  })
87
87
  ),
88
88
  "time_unit",
@@ -2225,7 +2225,7 @@ export const mergeAll = dual<
2225
2225
  readonly batching?: boolean | "inherit" | undefined
2226
2226
  }) => Effect.Effect<R, E, Z>
2227
2227
  >(
2228
- (args) => Predicate.isIterable(args[0]),
2228
+ (args) => Predicate.isFunction(args[2]),
2229
2229
  <R, E, A, Z>(elements: Iterable<Effect.Effect<R, E, A>>, zero: Z, f: (z: Z, a: A, i: number) => Z, options?: {
2230
2230
  readonly concurrency?: Concurrency | undefined
2231
2231
  readonly batching?: boolean | "inherit" | undefined
@@ -308,9 +308,9 @@ export const timer = (name: string, description?: string): Metric.Metric<
308
308
  MetricState.MetricState.Histogram
309
309
  > => {
310
310
  const boundaries = metricBoundaries.exponential({
311
- start: 1,
311
+ start: 0.5,
312
312
  factor: 2,
313
- count: 100
313
+ count: 35
314
314
  })
315
315
  const base = pipe(histogram(name, boundaries, description), tagged("time_unit", "milliseconds"))
316
316
  return mapInput(base, Duration.toMillis)
@@ -1 +1 @@
1
- export const moduleVersion = "2.0.0-next.60"
1
+ export const moduleVersion = "2.0.0-next.61"