@clayroach/effect 3.19.14-source-capture.8 → 3.19.14-source-trace.2
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/SourceLocation/package.json +6 -0
- package/dist/cjs/Effect.js +2 -28
- package/dist/cjs/Effect.js.map +1 -1
- package/dist/cjs/FiberRef.js +12 -1
- package/dist/cjs/FiberRef.js.map +1 -1
- package/dist/cjs/Layer.js +2 -24
- package/dist/cjs/Layer.js.map +1 -1
- package/dist/cjs/RuntimeFlags.js +1 -29
- package/dist/cjs/RuntimeFlags.js.map +1 -1
- package/dist/cjs/SourceLocation.js +60 -0
- package/dist/cjs/SourceLocation.js.map +1 -0
- package/dist/cjs/Tracer.js +1 -15
- package/dist/cjs/Tracer.js.map +1 -1
- package/dist/cjs/Utils.js +1 -1
- package/dist/cjs/Utils.js.map +1 -1
- package/dist/cjs/index.js +3 -1
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/internal/clock.js +1 -1
- package/dist/cjs/internal/clock.js.map +1 -1
- package/dist/cjs/internal/core.js +17 -50
- package/dist/cjs/internal/core.js.map +1 -1
- package/dist/cjs/internal/effect/circular.js +18 -30
- package/dist/cjs/internal/effect/circular.js.map +1 -1
- package/dist/cjs/internal/fiberRuntime.js +16 -65
- package/dist/cjs/internal/fiberRuntime.js.map +1 -1
- package/dist/cjs/internal/layer/circular.js +1 -5
- package/dist/cjs/internal/layer/circular.js.map +1 -1
- package/dist/cjs/internal/layer.js +1 -3
- package/dist/cjs/internal/layer.js.map +1 -1
- package/dist/cjs/internal/logger.js +25 -2
- package/dist/cjs/internal/logger.js.map +1 -1
- package/dist/cjs/internal/runtimeFlags.js +2 -11
- package/dist/cjs/internal/runtimeFlags.js.map +1 -1
- package/dist/cjs/internal/tracer.js +1 -114
- package/dist/cjs/internal/tracer.js.map +1 -1
- package/dist/dts/Config.d.ts +2 -2
- package/dist/dts/Config.d.ts.map +1 -1
- package/dist/dts/Effect.d.ts +8 -29
- package/dist/dts/Effect.d.ts.map +1 -1
- package/dist/dts/FiberRef.d.ts +12 -0
- package/dist/dts/FiberRef.d.ts.map +1 -1
- package/dist/dts/Layer.d.ts +0 -22
- package/dist/dts/Layer.d.ts.map +1 -1
- package/dist/dts/RuntimeFlags.d.ts +0 -28
- package/dist/dts/RuntimeFlags.d.ts.map +1 -1
- package/dist/dts/SourceLocation.d.ts +88 -0
- package/dist/dts/SourceLocation.d.ts.map +1 -0
- package/dist/dts/Tracer.d.ts +0 -15
- package/dist/dts/Tracer.d.ts.map +1 -1
- package/dist/dts/index.d.ts +6 -0
- package/dist/dts/index.d.ts.map +1 -1
- package/dist/dts/internal/core.d.ts.map +1 -1
- package/dist/dts/internal/layer.d.ts.map +1 -1
- package/dist/dts/internal/runtimeFlags.d.ts.map +1 -1
- package/dist/esm/Effect.js +0 -26
- package/dist/esm/Effect.js.map +1 -1
- package/dist/esm/FiberRef.js +11 -0
- package/dist/esm/FiberRef.js.map +1 -1
- package/dist/esm/Layer.js +0 -22
- package/dist/esm/Layer.js.map +1 -1
- package/dist/esm/RuntimeFlags.js +0 -28
- package/dist/esm/RuntimeFlags.js.map +1 -1
- package/dist/esm/SourceLocation.js +51 -0
- package/dist/esm/SourceLocation.js.map +1 -0
- package/dist/esm/Tracer.js +0 -14
- package/dist/esm/Tracer.js.map +1 -1
- package/dist/esm/Utils.js +1 -1
- package/dist/esm/Utils.js.map +1 -1
- package/dist/esm/index.js +6 -0
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/internal/clock.js +1 -1
- package/dist/esm/internal/clock.js.map +1 -1
- package/dist/esm/internal/core.js +12 -45
- package/dist/esm/internal/core.js.map +1 -1
- package/dist/esm/internal/effect/circular.js +18 -30
- package/dist/esm/internal/effect/circular.js.map +1 -1
- package/dist/esm/internal/fiberRuntime.js +13 -60
- package/dist/esm/internal/fiberRuntime.js.map +1 -1
- package/dist/esm/internal/layer/circular.js +0 -4
- package/dist/esm/internal/layer/circular.js.map +1 -1
- package/dist/esm/internal/layer.js +0 -2
- package/dist/esm/internal/layer.js.map +1 -1
- package/dist/esm/internal/logger.js +25 -2
- package/dist/esm/internal/logger.js.map +1 -1
- package/dist/esm/internal/runtimeFlags.js +1 -9
- package/dist/esm/internal/runtimeFlags.js.map +1 -1
- package/dist/esm/internal/tracer.js +0 -111
- package/dist/esm/internal/tracer.js.map +1 -1
- package/package.json +12 -1
- package/src/Arbitrary.ts +1101 -0
- package/src/Array.ts +3589 -0
- package/src/BigDecimal.ts +1349 -0
- package/src/BigInt.ts +643 -0
- package/src/Boolean.ts +287 -0
- package/src/Brand.ts +360 -0
- package/src/Cache.ts +281 -0
- package/src/Cause.ts +1555 -0
- package/src/Channel.ts +2355 -0
- package/src/ChildExecutorDecision.ts +146 -0
- package/src/Chunk.ts +1495 -0
- package/src/Clock.ts +111 -0
- package/src/Config.ts +542 -0
- package/src/ConfigError.ts +270 -0
- package/src/ConfigProvider.ts +333 -0
- package/src/ConfigProviderPathPatch.ts +100 -0
- package/src/Console.ts +226 -0
- package/src/Context.ts +585 -0
- package/src/Cron.ts +706 -0
- package/src/Data.ts +596 -0
- package/src/DateTime.ts +1686 -0
- package/src/DefaultServices.ts +34 -0
- package/src/Deferred.ts +301 -0
- package/src/Differ.ts +450 -0
- package/src/Duration.ts +1000 -0
- package/src/Effect.ts +14817 -0
- package/src/Effectable.ts +107 -0
- package/src/Either.ts +1040 -0
- package/src/Encoding.ts +195 -0
- package/src/Equal.ts +98 -0
- package/src/Equivalence.ts +235 -0
- package/src/ExecutionPlan.ts +308 -0
- package/src/ExecutionStrategy.ts +119 -0
- package/src/Exit.ts +467 -0
- package/src/FastCheck.ts +9 -0
- package/src/Fiber.ts +744 -0
- package/src/FiberHandle.ts +540 -0
- package/src/FiberId.ts +195 -0
- package/src/FiberMap.ts +656 -0
- package/src/FiberRef.ts +444 -0
- package/src/FiberRefs.ts +204 -0
- package/src/FiberRefsPatch.ts +105 -0
- package/src/FiberSet.ts +491 -0
- package/src/FiberStatus.ts +108 -0
- package/src/Function.ts +1222 -0
- package/src/GlobalValue.ts +53 -0
- package/src/Graph.ts +3732 -0
- package/src/GroupBy.ts +103 -0
- package/src/HKT.ts +45 -0
- package/src/Hash.ts +195 -0
- package/src/HashMap.ts +519 -0
- package/src/HashRing.ts +317 -0
- package/src/HashSet.ts +2346 -0
- package/src/Inspectable.ts +287 -0
- package/src/Iterable.ts +1119 -0
- package/src/JSONSchema.ts +1044 -0
- package/src/KeyedPool.ts +167 -0
- package/src/Layer.ts +1228 -0
- package/src/LayerMap.ts +436 -0
- package/src/List.ts +977 -0
- package/src/LogLevel.ts +285 -0
- package/src/LogSpan.ts +25 -0
- package/src/Logger.ts +702 -0
- package/src/Mailbox.ts +268 -0
- package/src/ManagedRuntime.ts +180 -0
- package/src/Match.ts +1477 -0
- package/src/MergeDecision.ts +95 -0
- package/src/MergeState.ts +172 -0
- package/src/MergeStrategy.ts +107 -0
- package/src/Metric.ts +780 -0
- package/src/MetricBoundaries.ts +69 -0
- package/src/MetricHook.ts +151 -0
- package/src/MetricKey.ts +224 -0
- package/src/MetricKeyType.ts +262 -0
- package/src/MetricLabel.ts +47 -0
- package/src/MetricPair.ts +71 -0
- package/src/MetricPolling.ts +148 -0
- package/src/MetricRegistry.ts +48 -0
- package/src/MetricState.ts +257 -0
- package/src/Micro.ts +4405 -0
- package/src/ModuleVersion.ts +18 -0
- package/src/MutableHashMap.ts +411 -0
- package/src/MutableHashSet.ts +706 -0
- package/src/MutableList.ts +297 -0
- package/src/MutableQueue.ts +227 -0
- package/src/MutableRef.ts +202 -0
- package/src/NonEmptyIterable.ts +32 -0
- package/src/Number.ts +1071 -0
- package/src/Option.ts +2170 -0
- package/src/Order.ts +373 -0
- package/src/Ordering.ts +111 -0
- package/src/ParseResult.ts +2031 -0
- package/src/PartitionedSemaphore.ts +200 -0
- package/src/Pipeable.ts +566 -0
- package/src/Pool.ts +204 -0
- package/src/Predicate.ts +1405 -0
- package/src/Pretty.ts +205 -0
- package/src/PrimaryKey.ts +23 -0
- package/src/PubSub.ts +182 -0
- package/src/Queue.ts +644 -0
- package/src/Random.ts +204 -0
- package/src/RateLimiter.ts +138 -0
- package/src/RcMap.ts +141 -0
- package/src/RcRef.ts +122 -0
- package/src/Readable.ts +93 -0
- package/src/Record.ts +1274 -0
- package/src/RedBlackTree.ts +421 -0
- package/src/Redacted.ts +144 -0
- package/src/Ref.ts +180 -0
- package/src/RegExp.ts +38 -0
- package/src/Reloadable.ts +127 -0
- package/src/Request.ts +347 -0
- package/src/RequestBlock.ts +118 -0
- package/src/RequestResolver.ts +366 -0
- package/src/Resource.ts +119 -0
- package/src/Runtime.ts +383 -0
- package/src/RuntimeFlags.ts +336 -0
- package/src/RuntimeFlagsPatch.ts +183 -0
- package/src/STM.ts +2045 -0
- package/src/Schedule.ts +2219 -0
- package/src/ScheduleDecision.ts +62 -0
- package/src/ScheduleInterval.ts +151 -0
- package/src/ScheduleIntervals.ts +122 -0
- package/src/Scheduler.ts +353 -0
- package/src/Schema.ts +10914 -0
- package/src/SchemaAST.ts +3043 -0
- package/src/Scope.ts +204 -0
- package/src/ScopedCache.ts +151 -0
- package/src/ScopedRef.ts +117 -0
- package/src/Secret.ts +88 -0
- package/src/SingleProducerAsyncInput.ts +67 -0
- package/src/Sink.ts +1461 -0
- package/src/SortedMap.ts +287 -0
- package/src/SortedSet.ts +390 -0
- package/src/SourceLocation.ts +108 -0
- package/src/Stream.ts +6468 -0
- package/src/StreamEmit.ts +136 -0
- package/src/StreamHaltStrategy.ts +123 -0
- package/src/Streamable.ts +45 -0
- package/src/String.ts +778 -0
- package/src/Struct.ts +243 -0
- package/src/Subscribable.ts +100 -0
- package/src/SubscriptionRef.ts +298 -0
- package/src/Supervisor.ts +240 -0
- package/src/Symbol.ts +29 -0
- package/src/SynchronizedRef.ts +270 -0
- package/src/TArray.ts +495 -0
- package/src/TDeferred.ts +100 -0
- package/src/TMap.ts +515 -0
- package/src/TPriorityQueue.ts +223 -0
- package/src/TPubSub.ts +200 -0
- package/src/TQueue.ts +432 -0
- package/src/TRandom.ts +129 -0
- package/src/TReentrantLock.ts +224 -0
- package/src/TRef.ts +178 -0
- package/src/TSemaphore.ts +129 -0
- package/src/TSet.ts +365 -0
- package/src/TSubscriptionRef.ts +192 -0
- package/src/Take.ts +258 -0
- package/src/TestAnnotation.ts +158 -0
- package/src/TestAnnotationMap.ts +119 -0
- package/src/TestAnnotations.ts +117 -0
- package/src/TestClock.ts +556 -0
- package/src/TestConfig.ts +47 -0
- package/src/TestContext.ts +36 -0
- package/src/TestLive.ts +53 -0
- package/src/TestServices.ts +390 -0
- package/src/TestSized.ts +55 -0
- package/src/Tracer.ts +182 -0
- package/src/Trie.ts +840 -0
- package/src/Tuple.ts +305 -0
- package/src/Types.ts +353 -0
- package/src/Unify.ts +113 -0
- package/src/UpstreamPullRequest.ts +117 -0
- package/src/UpstreamPullStrategy.ts +121 -0
- package/src/Utils.ts +809 -0
- package/src/index.ts +1568 -0
- package/src/internal/array.ts +8 -0
- package/src/internal/blockedRequests.ts +520 -0
- package/src/internal/cache.ts +733 -0
- package/src/internal/cause.ts +1050 -0
- package/src/internal/channel/channelExecutor.ts +1200 -0
- package/src/internal/channel/channelState.ts +134 -0
- package/src/internal/channel/childExecutorDecision.ts +96 -0
- package/src/internal/channel/continuation.ts +200 -0
- package/src/internal/channel/mergeDecision.ts +113 -0
- package/src/internal/channel/mergeState.ts +120 -0
- package/src/internal/channel/mergeStrategy.ts +72 -0
- package/src/internal/channel/singleProducerAsyncInput.ts +259 -0
- package/src/internal/channel/subexecutor.ts +229 -0
- package/src/internal/channel/upstreamPullRequest.ts +84 -0
- package/src/internal/channel/upstreamPullStrategy.ts +87 -0
- package/src/internal/channel.ts +2603 -0
- package/src/internal/clock.ts +95 -0
- package/src/internal/completedRequestMap.ts +9 -0
- package/src/internal/concurrency.ts +54 -0
- package/src/internal/config.ts +716 -0
- package/src/internal/configError.ts +304 -0
- package/src/internal/configProvider/pathPatch.ts +97 -0
- package/src/internal/configProvider.ts +799 -0
- package/src/internal/console.ts +153 -0
- package/src/internal/context.ts +337 -0
- package/src/internal/core-effect.ts +2293 -0
- package/src/internal/core-stream.ts +998 -0
- package/src/internal/core.ts +3189 -0
- package/src/internal/data.ts +36 -0
- package/src/internal/dataSource.ts +327 -0
- package/src/internal/dateTime.ts +1277 -0
- package/src/internal/defaultServices/console.ts +100 -0
- package/src/internal/defaultServices.ts +163 -0
- package/src/internal/deferred.ts +46 -0
- package/src/internal/differ/chunkPatch.ts +211 -0
- package/src/internal/differ/contextPatch.ts +232 -0
- package/src/internal/differ/hashMapPatch.ts +220 -0
- package/src/internal/differ/hashSetPatch.ts +176 -0
- package/src/internal/differ/orPatch.ts +311 -0
- package/src/internal/differ/readonlyArrayPatch.ts +210 -0
- package/src/internal/differ.ts +200 -0
- package/src/internal/doNotation.ts +80 -0
- package/src/internal/effect/circular.ts +895 -0
- package/src/internal/effectable.ts +131 -0
- package/src/internal/either.ts +110 -0
- package/src/internal/encoding/base64.ts +286 -0
- package/src/internal/encoding/base64Url.ts +29 -0
- package/src/internal/encoding/common.ts +51 -0
- package/src/internal/encoding/hex.ts +315 -0
- package/src/internal/errors.ts +7 -0
- package/src/internal/executionPlan.ts +114 -0
- package/src/internal/executionStrategy.ts +74 -0
- package/src/internal/fiber.ts +388 -0
- package/src/internal/fiberId.ts +267 -0
- package/src/internal/fiberMessage.ts +82 -0
- package/src/internal/fiberRefs/patch.ts +144 -0
- package/src/internal/fiberRefs.ts +297 -0
- package/src/internal/fiberRuntime.ts +3842 -0
- package/src/internal/fiberScope.ts +71 -0
- package/src/internal/fiberStatus.ts +119 -0
- package/src/internal/groupBy.ts +530 -0
- package/src/internal/hashMap/array.ts +49 -0
- package/src/internal/hashMap/bitwise.ts +32 -0
- package/src/internal/hashMap/config.ts +14 -0
- package/src/internal/hashMap/keySet.ts +8 -0
- package/src/internal/hashMap/node.ts +391 -0
- package/src/internal/hashMap.ts +586 -0
- package/src/internal/hashSet.ts +323 -0
- package/src/internal/keyedPool.ts +244 -0
- package/src/internal/layer/circular.ts +214 -0
- package/src/internal/layer.ts +1483 -0
- package/src/internal/logSpan.ts +20 -0
- package/src/internal/logger-circular.ts +24 -0
- package/src/internal/logger.ts +522 -0
- package/src/internal/mailbox.ts +561 -0
- package/src/internal/managedRuntime/circular.ts +6 -0
- package/src/internal/managedRuntime.ts +134 -0
- package/src/internal/matcher.ts +652 -0
- package/src/internal/metric/boundaries.ts +75 -0
- package/src/internal/metric/hook.ts +483 -0
- package/src/internal/metric/key.ts +167 -0
- package/src/internal/metric/keyType.ts +238 -0
- package/src/internal/metric/label.ts +41 -0
- package/src/internal/metric/pair.ts +48 -0
- package/src/internal/metric/polling.ts +149 -0
- package/src/internal/metric/registry.ts +187 -0
- package/src/internal/metric/state.ts +290 -0
- package/src/internal/metric.ts +577 -0
- package/src/internal/opCodes/cause.ts +35 -0
- package/src/internal/opCodes/channel.ts +83 -0
- package/src/internal/opCodes/channelChildExecutorDecision.ts +17 -0
- package/src/internal/opCodes/channelMergeDecision.ts +11 -0
- package/src/internal/opCodes/channelMergeState.ts +17 -0
- package/src/internal/opCodes/channelMergeStrategy.ts +11 -0
- package/src/internal/opCodes/channelState.ts +23 -0
- package/src/internal/opCodes/channelUpstreamPullRequest.ts +11 -0
- package/src/internal/opCodes/channelUpstreamPullStrategy.ts +11 -0
- package/src/internal/opCodes/config.ts +65 -0
- package/src/internal/opCodes/configError.ts +35 -0
- package/src/internal/opCodes/continuation.ts +11 -0
- package/src/internal/opCodes/deferred.ts +11 -0
- package/src/internal/opCodes/effect.ts +89 -0
- package/src/internal/opCodes/layer.ts +59 -0
- package/src/internal/opCodes/streamHaltStrategy.ts +23 -0
- package/src/internal/option.ts +80 -0
- package/src/internal/pool.ts +432 -0
- package/src/internal/pubsub.ts +1762 -0
- package/src/internal/query.ts +204 -0
- package/src/internal/queue.ts +766 -0
- package/src/internal/random.ts +161 -0
- package/src/internal/rateLimiter.ts +93 -0
- package/src/internal/rcMap.ts +285 -0
- package/src/internal/rcRef.ts +192 -0
- package/src/internal/redBlackTree/iterator.ts +200 -0
- package/src/internal/redBlackTree/node.ts +68 -0
- package/src/internal/redBlackTree.ts +1245 -0
- package/src/internal/redacted.ts +73 -0
- package/src/internal/ref.ts +171 -0
- package/src/internal/reloadable.ts +140 -0
- package/src/internal/request.ts +177 -0
- package/src/internal/resource.ts +76 -0
- package/src/internal/ringBuffer.ts +68 -0
- package/src/internal/runtime.ts +558 -0
- package/src/internal/runtimeFlags.ts +178 -0
- package/src/internal/runtimeFlagsPatch.ts +103 -0
- package/src/internal/schedule/decision.ts +47 -0
- package/src/internal/schedule/interval.ts +101 -0
- package/src/internal/schedule/intervals.ts +180 -0
- package/src/internal/schedule.ts +2199 -0
- package/src/internal/schema/errors.ts +191 -0
- package/src/internal/schema/schemaId.ts +106 -0
- package/src/internal/schema/util.ts +50 -0
- package/src/internal/scopedCache.ts +644 -0
- package/src/internal/scopedRef.ts +118 -0
- package/src/internal/secret.ts +89 -0
- package/src/internal/singleShotGen.ts +35 -0
- package/src/internal/sink.ts +2120 -0
- package/src/internal/stack.ts +10 -0
- package/src/internal/stm/core.ts +817 -0
- package/src/internal/stm/entry.ts +59 -0
- package/src/internal/stm/journal.ts +123 -0
- package/src/internal/stm/opCodes/stm.ts +71 -0
- package/src/internal/stm/opCodes/stmState.ts +17 -0
- package/src/internal/stm/opCodes/strategy.ts +17 -0
- package/src/internal/stm/opCodes/tExit.ts +29 -0
- package/src/internal/stm/opCodes/tryCommit.ts +11 -0
- package/src/internal/stm/stm.ts +1453 -0
- package/src/internal/stm/stmState.ts +136 -0
- package/src/internal/stm/tArray.ts +550 -0
- package/src/internal/stm/tDeferred.ts +81 -0
- package/src/internal/stm/tExit.ts +190 -0
- package/src/internal/stm/tMap.ts +824 -0
- package/src/internal/stm/tPriorityQueue.ts +267 -0
- package/src/internal/stm/tPubSub.ts +551 -0
- package/src/internal/stm/tQueue.ts +393 -0
- package/src/internal/stm/tRandom.ts +140 -0
- package/src/internal/stm/tReentrantLock.ts +352 -0
- package/src/internal/stm/tRef.ts +195 -0
- package/src/internal/stm/tSemaphore.ts +113 -0
- package/src/internal/stm/tSet.ts +259 -0
- package/src/internal/stm/tSubscriptionRef.ts +286 -0
- package/src/internal/stm/tryCommit.ts +34 -0
- package/src/internal/stm/txnId.ts +14 -0
- package/src/internal/stm/versioned.ts +4 -0
- package/src/internal/stream/debounceState.ts +57 -0
- package/src/internal/stream/emit.ts +123 -0
- package/src/internal/stream/haltStrategy.ts +94 -0
- package/src/internal/stream/handoff.ts +187 -0
- package/src/internal/stream/handoffSignal.ts +59 -0
- package/src/internal/stream/pull.ts +34 -0
- package/src/internal/stream/sinkEndReason.ts +30 -0
- package/src/internal/stream/zipAllState.ts +88 -0
- package/src/internal/stream/zipChunksState.ts +56 -0
- package/src/internal/stream.ts +8801 -0
- package/src/internal/string-utils.ts +107 -0
- package/src/internal/subscriptionRef.ts +138 -0
- package/src/internal/supervisor/patch.ts +190 -0
- package/src/internal/supervisor.ts +303 -0
- package/src/internal/synchronizedRef.ts +114 -0
- package/src/internal/take.ts +199 -0
- package/src/internal/testing/sleep.ts +27 -0
- package/src/internal/testing/suspendedWarningData.ts +85 -0
- package/src/internal/testing/warningData.ts +94 -0
- package/src/internal/tracer.ts +150 -0
- package/src/internal/trie.ts +722 -0
- package/src/internal/version.ts +7 -0
package/src/Match.ts
ADDED
|
@@ -0,0 +1,1477 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The `effect/match` module provides a type-safe pattern matching system for
|
|
3
|
+
* TypeScript. Inspired by functional programming, it simplifies conditional
|
|
4
|
+
* logic by replacing verbose if/else or switch statements with a structured and
|
|
5
|
+
* expressive API.
|
|
6
|
+
*
|
|
7
|
+
* This module supports matching against types, values, and discriminated unions
|
|
8
|
+
* while enforcing exhaustiveness checking to ensure all cases are handled.
|
|
9
|
+
*
|
|
10
|
+
* Although pattern matching is not yet a native JavaScript feature,
|
|
11
|
+
* `effect/match` offers a reliable implementation that is available today.
|
|
12
|
+
*
|
|
13
|
+
* **How Pattern Matching Works**
|
|
14
|
+
*
|
|
15
|
+
* Pattern matching follows a structured process:
|
|
16
|
+
*
|
|
17
|
+
* - **Creating a matcher**: Define a `Matcher` that operates on either a
|
|
18
|
+
* specific `Match.type` or `Match.value`.
|
|
19
|
+
*
|
|
20
|
+
* - **Defining patterns**: Use combinators such as `Match.when`, `Match.not`,
|
|
21
|
+
* and `Match.tag` to specify matching conditions.
|
|
22
|
+
*
|
|
23
|
+
* - **Completing the match**: Apply a finalizer such as `Match.exhaustive`,
|
|
24
|
+
* `Match.orElse`, or `Match.option` to determine how unmatched cases should
|
|
25
|
+
* be handled.
|
|
26
|
+
*
|
|
27
|
+
* @since 1.0.0
|
|
28
|
+
*/
|
|
29
|
+
import type * as Either from "./Either.js"
|
|
30
|
+
import * as internal from "./internal/matcher.js"
|
|
31
|
+
import type * as Option from "./Option.js"
|
|
32
|
+
import type { Pipeable } from "./Pipeable.js"
|
|
33
|
+
import * as Predicate from "./Predicate.js"
|
|
34
|
+
import type * as T from "./Types.js"
|
|
35
|
+
import type { Unify } from "./Unify.js"
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* @category Symbols
|
|
39
|
+
* @since 1.0.0
|
|
40
|
+
*/
|
|
41
|
+
export const MatcherTypeId: unique symbol = internal.TypeId
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* @category Symbols
|
|
45
|
+
* @since 1.0.0
|
|
46
|
+
*/
|
|
47
|
+
export type MatcherTypeId = typeof MatcherTypeId
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Pattern matching follows a structured process:
|
|
51
|
+
*
|
|
52
|
+
* - **Creating a matcher**: Define a `Matcher` that operates on either a
|
|
53
|
+
* specific `Match.type` or `Match.value`.
|
|
54
|
+
*
|
|
55
|
+
* - **Defining patterns**: Use combinators such as `Match.when`, `Match.not`,
|
|
56
|
+
* and `Match.tag` to specify matching conditions.
|
|
57
|
+
*
|
|
58
|
+
* - **Completing the match**: Apply a finalizer such as `Match.exhaustive`,
|
|
59
|
+
* `Match.orElse`, or `Match.option` to determine how unmatched cases should
|
|
60
|
+
* be handled.
|
|
61
|
+
*
|
|
62
|
+
* @example
|
|
63
|
+
* ```ts
|
|
64
|
+
* import { Match } from "effect"
|
|
65
|
+
*
|
|
66
|
+
* // Simulated dynamic input that can be a string or a number
|
|
67
|
+
* const input: string | number = "some input"
|
|
68
|
+
*
|
|
69
|
+
* // ┌─── string
|
|
70
|
+
* // ▼
|
|
71
|
+
* const result = Match.value(input).pipe(
|
|
72
|
+
* // Match if the value is a number
|
|
73
|
+
* Match.when(Match.number, (n) => `number: ${n}`),
|
|
74
|
+
* // Match if the value is a string
|
|
75
|
+
* Match.when(Match.string, (s) => `string: ${s}`),
|
|
76
|
+
* // Ensure all possible cases are covered
|
|
77
|
+
* Match.exhaustive
|
|
78
|
+
* )
|
|
79
|
+
*
|
|
80
|
+
* console.log(result)
|
|
81
|
+
* // Output: "string: some input"
|
|
82
|
+
* ```
|
|
83
|
+
*
|
|
84
|
+
* @category Model
|
|
85
|
+
* @since 1.0.0
|
|
86
|
+
*/
|
|
87
|
+
export type Matcher<Input, Filters, RemainingApplied, Result, Provided, Return = any> =
|
|
88
|
+
| TypeMatcher<Input, Filters, RemainingApplied, Result, Return>
|
|
89
|
+
| ValueMatcher<Input, Filters, RemainingApplied, Result, Provided, Return>
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* @category Model
|
|
93
|
+
* @since 1.0.0
|
|
94
|
+
*/
|
|
95
|
+
export interface TypeMatcher<in Input, out Filters, out Remaining, out Result, out Return = any> extends Pipeable {
|
|
96
|
+
readonly _tag: "TypeMatcher"
|
|
97
|
+
readonly [MatcherTypeId]: {
|
|
98
|
+
readonly _input: T.Contravariant<Input>
|
|
99
|
+
readonly _filters: T.Covariant<Filters>
|
|
100
|
+
readonly _remaining: T.Covariant<Remaining>
|
|
101
|
+
readonly _result: T.Covariant<Result>
|
|
102
|
+
readonly _return: T.Covariant<Return>
|
|
103
|
+
}
|
|
104
|
+
readonly cases: ReadonlyArray<Case>
|
|
105
|
+
add<I, R, RA, A>(_case: Case): TypeMatcher<I, R, RA, A>
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* @category Model
|
|
110
|
+
* @since 1.0.0
|
|
111
|
+
*/
|
|
112
|
+
export interface ValueMatcher<in Input, out Filters, out Remaining, out Result, out Provided, out Return = any>
|
|
113
|
+
extends Pipeable
|
|
114
|
+
{
|
|
115
|
+
readonly _tag: "ValueMatcher"
|
|
116
|
+
readonly [MatcherTypeId]: {
|
|
117
|
+
readonly _input: T.Contravariant<Input>
|
|
118
|
+
readonly _filters: T.Covariant<Filters>
|
|
119
|
+
readonly _remaining: T.Covariant<Remaining>
|
|
120
|
+
readonly _result: T.Covariant<Result>
|
|
121
|
+
readonly _provided: T.Covariant<Result>
|
|
122
|
+
readonly _return: T.Covariant<Return>
|
|
123
|
+
}
|
|
124
|
+
readonly provided: Provided
|
|
125
|
+
readonly value: Either.Either<Provided, Remaining>
|
|
126
|
+
add<I, R, RA, A, Pr>(_case: Case): ValueMatcher<I, R, RA, A, Pr>
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* @category Model
|
|
131
|
+
* @since 1.0.0
|
|
132
|
+
*/
|
|
133
|
+
export type Case = When | Not
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* @category Model
|
|
137
|
+
* @since 1.0.0
|
|
138
|
+
*/
|
|
139
|
+
export interface When {
|
|
140
|
+
readonly _tag: "When"
|
|
141
|
+
guard(u: unknown): boolean
|
|
142
|
+
evaluate(input: unknown): any
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* @category Model
|
|
147
|
+
* @since 1.0.0
|
|
148
|
+
*/
|
|
149
|
+
export interface Not {
|
|
150
|
+
readonly _tag: "Not"
|
|
151
|
+
guard(u: unknown): boolean
|
|
152
|
+
evaluate(input: unknown): any
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* Creates a matcher for a specific type.
|
|
157
|
+
*
|
|
158
|
+
* **Details**
|
|
159
|
+
*
|
|
160
|
+
* This function defines a `Matcher` that operates on a given type, allowing you
|
|
161
|
+
* to specify conditions for handling different cases. Once the matcher is
|
|
162
|
+
* created, you can use pattern-matching functions like {@link when} to define
|
|
163
|
+
* how different values should be processed.
|
|
164
|
+
*
|
|
165
|
+
* **Example** (Matching Numbers and Strings)
|
|
166
|
+
*
|
|
167
|
+
* ```ts
|
|
168
|
+
* import { Match } from "effect"
|
|
169
|
+
*
|
|
170
|
+
* // Create a matcher for values that are either strings or numbers
|
|
171
|
+
* //
|
|
172
|
+
* // ┌─── (u: string | number) => string
|
|
173
|
+
* // ▼
|
|
174
|
+
* const match = Match.type<string | number>().pipe(
|
|
175
|
+
* // Match when the value is a number
|
|
176
|
+
* Match.when(Match.number, (n) => `number: ${n}`),
|
|
177
|
+
* // Match when the value is a string
|
|
178
|
+
* Match.when(Match.string, (s) => `string: ${s}`),
|
|
179
|
+
* // Ensure all possible cases are handled
|
|
180
|
+
* Match.exhaustive
|
|
181
|
+
* )
|
|
182
|
+
*
|
|
183
|
+
* console.log(match(0))
|
|
184
|
+
* // Output: "number: 0"
|
|
185
|
+
*
|
|
186
|
+
* console.log(match("hello"))
|
|
187
|
+
* // Output: "string: hello"
|
|
188
|
+
* ```
|
|
189
|
+
*
|
|
190
|
+
* @see {@link value} for creating a matcher from a specific value.
|
|
191
|
+
*
|
|
192
|
+
* @category Creating a matcher
|
|
193
|
+
* @since 1.0.0
|
|
194
|
+
*/
|
|
195
|
+
export const type: <I>() => Matcher<I, Types.Without<never>, I, never, never> = internal.type
|
|
196
|
+
|
|
197
|
+
/**
|
|
198
|
+
* Creates a matcher from a specific value.
|
|
199
|
+
*
|
|
200
|
+
* **Details**
|
|
201
|
+
*
|
|
202
|
+
* This function allows you to define a `Matcher` directly from a given value,
|
|
203
|
+
* rather than from a type. This is useful when working with known values,
|
|
204
|
+
* enabling structured pattern matching on objects, primitives, or any data
|
|
205
|
+
* structure.
|
|
206
|
+
*
|
|
207
|
+
* Once the matcher is created, you can use pattern-matching functions like
|
|
208
|
+
* {@link when} to define how different cases should be handled.
|
|
209
|
+
*
|
|
210
|
+
* **Example** (Matching an Object by Property)
|
|
211
|
+
*
|
|
212
|
+
* ```ts
|
|
213
|
+
* import { Match } from "effect"
|
|
214
|
+
*
|
|
215
|
+
* const input = { name: "John", age: 30 }
|
|
216
|
+
*
|
|
217
|
+
* // Create a matcher for the specific object
|
|
218
|
+
* const result = Match.value(input).pipe(
|
|
219
|
+
* // Match when the 'name' property is "John"
|
|
220
|
+
* Match.when(
|
|
221
|
+
* { name: "John" },
|
|
222
|
+
* (user) => `${user.name} is ${user.age} years old`
|
|
223
|
+
* ),
|
|
224
|
+
* // Provide a fallback if no match is found
|
|
225
|
+
* Match.orElse(() => "Oh, not John")
|
|
226
|
+
* )
|
|
227
|
+
*
|
|
228
|
+
* console.log(result)
|
|
229
|
+
* // Output: "John is 30 years old"
|
|
230
|
+
* ```
|
|
231
|
+
*
|
|
232
|
+
* @see {@link type} for creating a matcher from a specific type.
|
|
233
|
+
*
|
|
234
|
+
* @category Creating a matcher
|
|
235
|
+
* @since 1.0.0
|
|
236
|
+
*/
|
|
237
|
+
export const value: <const I>(
|
|
238
|
+
i: I
|
|
239
|
+
) => Matcher<I, Types.Without<never>, I, never, I> = internal.value
|
|
240
|
+
|
|
241
|
+
/**
|
|
242
|
+
* @category Creating a matcher
|
|
243
|
+
* @since 1.0.0
|
|
244
|
+
*/
|
|
245
|
+
export const valueTags: {
|
|
246
|
+
<
|
|
247
|
+
const I,
|
|
248
|
+
P extends
|
|
249
|
+
& { readonly [Tag in Types.Tags<"_tag", I> & string]: (_: Extract<I, { readonly _tag: Tag }>) => any }
|
|
250
|
+
& { readonly [Tag in Exclude<keyof P, Types.Tags<"_tag", I>>]: never }
|
|
251
|
+
>(fields: P): (input: I) => Unify<ReturnType<P[keyof P]>>
|
|
252
|
+
<
|
|
253
|
+
const I,
|
|
254
|
+
P extends
|
|
255
|
+
& { readonly [Tag in Types.Tags<"_tag", I> & string]: (_: Extract<I, { readonly _tag: Tag }>) => any }
|
|
256
|
+
& { readonly [Tag in Exclude<keyof P, Types.Tags<"_tag", I>>]: never }
|
|
257
|
+
>(input: I, fields: P): Unify<ReturnType<P[keyof P]>>
|
|
258
|
+
} = internal.valueTags
|
|
259
|
+
|
|
260
|
+
/**
|
|
261
|
+
* @category Creating a matcher
|
|
262
|
+
* @since 1.0.0
|
|
263
|
+
*/
|
|
264
|
+
export const typeTags: {
|
|
265
|
+
<I, Ret>(): <
|
|
266
|
+
P extends
|
|
267
|
+
& {
|
|
268
|
+
readonly [Tag in Types.Tags<"_tag", I> & string]: (
|
|
269
|
+
_: Extract<I, { readonly _tag: Tag }>
|
|
270
|
+
) => Ret
|
|
271
|
+
}
|
|
272
|
+
& { readonly [Tag in Exclude<keyof P, Types.Tags<"_tag", I>>]: never }
|
|
273
|
+
>(fields: P) => (input: I) => Ret
|
|
274
|
+
<I>(): <
|
|
275
|
+
P extends
|
|
276
|
+
& {
|
|
277
|
+
readonly [Tag in Types.Tags<"_tag", I> & string]: (
|
|
278
|
+
_: Extract<I, { readonly _tag: Tag }>
|
|
279
|
+
) => any
|
|
280
|
+
}
|
|
281
|
+
& { readonly [Tag in Exclude<keyof P, Types.Tags<"_tag", I>>]: never }
|
|
282
|
+
>(fields: P) => (input: I) => Unify<ReturnType<P[keyof P]>>
|
|
283
|
+
} = internal.typeTags
|
|
284
|
+
|
|
285
|
+
/**
|
|
286
|
+
* Ensures that all branches of a matcher return a specific type.
|
|
287
|
+
*
|
|
288
|
+
* **Details**
|
|
289
|
+
*
|
|
290
|
+
* This function enforces a consistent return type across all pattern-matching
|
|
291
|
+
* branches. By specifying a return type, TypeScript will check that every
|
|
292
|
+
* matching condition produces a value of the expected type.
|
|
293
|
+
*
|
|
294
|
+
* **Important:** This function must be the first step in the matcher pipeline.
|
|
295
|
+
* If used later, TypeScript will not enforce type consistency correctly.
|
|
296
|
+
*
|
|
297
|
+
* **Example** (Validating Return Type Consistency)
|
|
298
|
+
*
|
|
299
|
+
* ```ts
|
|
300
|
+
* import { Match } from "effect"
|
|
301
|
+
*
|
|
302
|
+
* const match = Match.type<{ a: number } | { b: string }>().pipe(
|
|
303
|
+
* // Ensure all branches return a string
|
|
304
|
+
* Match.withReturnType<string>(),
|
|
305
|
+
* // ❌ Type error: 'number' is not assignable to type 'string'
|
|
306
|
+
* // @ts-expect-error
|
|
307
|
+
* Match.when({ a: Match.number }, (_) => _.a),
|
|
308
|
+
* // ✅ Correct: returns a string
|
|
309
|
+
* Match.when({ b: Match.string }, (_) => _.b),
|
|
310
|
+
* Match.exhaustive
|
|
311
|
+
* )
|
|
312
|
+
* ```
|
|
313
|
+
*
|
|
314
|
+
* @since 1.0.0
|
|
315
|
+
*/
|
|
316
|
+
export const withReturnType: <Ret>() => <I, F, R, A, Pr, _>(
|
|
317
|
+
self: Matcher<I, F, R, A, Pr, _>
|
|
318
|
+
) => [Ret] extends [[A] extends [never] ? any : A] ? Matcher<I, F, R, A, Pr, Ret>
|
|
319
|
+
: "withReturnType constraint does not extend Result type" = internal.withReturnType
|
|
320
|
+
|
|
321
|
+
/**
|
|
322
|
+
* Defines a condition for matching values.
|
|
323
|
+
*
|
|
324
|
+
* **Details**
|
|
325
|
+
*
|
|
326
|
+
* This function enables pattern matching by checking whether a given value
|
|
327
|
+
* satisfies a condition. It supports both direct value comparisons and
|
|
328
|
+
* predicate functions. If the condition is met, the associated function is
|
|
329
|
+
* executed.
|
|
330
|
+
*
|
|
331
|
+
* This function is useful when defining matchers that need to check for
|
|
332
|
+
* specific values or apply logical conditions to determine a match. It works
|
|
333
|
+
* well with structured objects and primitive types.
|
|
334
|
+
*
|
|
335
|
+
* **Example** (Matching with Values and Predicates)
|
|
336
|
+
*
|
|
337
|
+
* ```ts
|
|
338
|
+
* import { Match } from "effect"
|
|
339
|
+
*
|
|
340
|
+
* // Create a matcher for objects with an "age" property
|
|
341
|
+
* const match = Match.type<{ age: number }>().pipe(
|
|
342
|
+
* // Match when age is greater than 18
|
|
343
|
+
* Match.when({ age: (age) => age > 18 }, (user) => `Age: ${user.age}`),
|
|
344
|
+
* // Match when age is exactly 18
|
|
345
|
+
* Match.when({ age: 18 }, () => "You can vote"),
|
|
346
|
+
* // Fallback case for all other ages
|
|
347
|
+
* Match.orElse((user) => `${user.age} is too young`)
|
|
348
|
+
* )
|
|
349
|
+
*
|
|
350
|
+
* console.log(match({ age: 20 }))
|
|
351
|
+
* // Output: "Age: 20"
|
|
352
|
+
*
|
|
353
|
+
* console.log(match({ age: 18 }))
|
|
354
|
+
* // Output: "You can vote"
|
|
355
|
+
*
|
|
356
|
+
* console.log(match({ age: 4 }))
|
|
357
|
+
* // Output: "4 is too young"
|
|
358
|
+
* ```
|
|
359
|
+
*
|
|
360
|
+
* @see {@link whenOr} Use this when multiple patterns should match in a single
|
|
361
|
+
* condition.
|
|
362
|
+
* @see {@link whenAnd} Use this when a value must match all provided patterns.
|
|
363
|
+
* @see {@link orElse} Provides a fallback when no patterns match.
|
|
364
|
+
*
|
|
365
|
+
* @category Defining patterns
|
|
366
|
+
* @since 1.0.0
|
|
367
|
+
*/
|
|
368
|
+
export const when: <
|
|
369
|
+
R,
|
|
370
|
+
const P extends Types.PatternPrimitive<R> | Types.PatternBase<R>,
|
|
371
|
+
Ret,
|
|
372
|
+
Fn extends (_: Types.WhenMatch<R, P>) => Ret
|
|
373
|
+
>(
|
|
374
|
+
pattern: P,
|
|
375
|
+
f: Fn
|
|
376
|
+
) => <I, F, A, Pr>(
|
|
377
|
+
self: Matcher<I, F, R, A, Pr, Ret>
|
|
378
|
+
) => Matcher<
|
|
379
|
+
I,
|
|
380
|
+
Types.AddWithout<F, Types.PForExclude<P>>,
|
|
381
|
+
Types.ApplyFilters<I, Types.AddWithout<F, Types.PForExclude<P>>>,
|
|
382
|
+
A | ReturnType<Fn>,
|
|
383
|
+
Pr,
|
|
384
|
+
Ret
|
|
385
|
+
> = internal.when
|
|
386
|
+
|
|
387
|
+
/**
|
|
388
|
+
* Matches one of multiple patterns in a single condition.
|
|
389
|
+
*
|
|
390
|
+
* **Details**
|
|
391
|
+
*
|
|
392
|
+
* This function allows defining a condition where a value matches any of the
|
|
393
|
+
* provided patterns. If a match is found, the associated function is executed.
|
|
394
|
+
* It simplifies cases where multiple patterns share the same handling logic.
|
|
395
|
+
*
|
|
396
|
+
* Unlike {@link when}, which requires separate conditions for each pattern,
|
|
397
|
+
* this function enables combining them into a single statement, making the
|
|
398
|
+
* matcher more concise.
|
|
399
|
+
*
|
|
400
|
+
* @example
|
|
401
|
+
* ```ts
|
|
402
|
+
* import { Match } from "effect"
|
|
403
|
+
*
|
|
404
|
+
* type ErrorType =
|
|
405
|
+
* | { readonly _tag: "NetworkError"; readonly message: string }
|
|
406
|
+
* | { readonly _tag: "TimeoutError"; readonly duration: number }
|
|
407
|
+
* | { readonly _tag: "ValidationError"; readonly field: string }
|
|
408
|
+
*
|
|
409
|
+
* const handleError = Match.type<ErrorType>().pipe(
|
|
410
|
+
* Match.whenOr(
|
|
411
|
+
* { _tag: "NetworkError" },
|
|
412
|
+
* { _tag: "TimeoutError" },
|
|
413
|
+
* () => "Retry the request"
|
|
414
|
+
* ),
|
|
415
|
+
* Match.when({ _tag: "ValidationError" }, (_) => `Invalid field: ${_.field}`),
|
|
416
|
+
* Match.exhaustive
|
|
417
|
+
* )
|
|
418
|
+
*
|
|
419
|
+
* console.log(handleError({ _tag: "NetworkError", message: "No connection" }))
|
|
420
|
+
* // Output: "Retry the request"
|
|
421
|
+
*
|
|
422
|
+
* console.log(handleError({ _tag: "ValidationError", field: "email" }))
|
|
423
|
+
* // Output: "Invalid field: email"
|
|
424
|
+
* ```
|
|
425
|
+
*
|
|
426
|
+
* @category Defining patterns
|
|
427
|
+
* @since 1.0.0
|
|
428
|
+
*/
|
|
429
|
+
export const whenOr: <
|
|
430
|
+
R,
|
|
431
|
+
const P extends ReadonlyArray<Types.PatternPrimitive<R> | Types.PatternBase<R>>,
|
|
432
|
+
Ret,
|
|
433
|
+
Fn extends (_: Types.WhenMatch<R, P[number]>) => Ret
|
|
434
|
+
>(
|
|
435
|
+
...args: [...patterns: P, f: Fn]
|
|
436
|
+
) => <I, F, A, Pr>(
|
|
437
|
+
self: Matcher<I, F, R, A, Pr, Ret>
|
|
438
|
+
) => Matcher<
|
|
439
|
+
I,
|
|
440
|
+
Types.AddWithout<F, Types.PForExclude<P[number]>>,
|
|
441
|
+
Types.ApplyFilters<I, Types.AddWithout<F, Types.PForExclude<P[number]>>>,
|
|
442
|
+
A | ReturnType<Fn>,
|
|
443
|
+
Pr,
|
|
444
|
+
Ret
|
|
445
|
+
> = internal.whenOr
|
|
446
|
+
|
|
447
|
+
/**
|
|
448
|
+
* Matches a value that satisfies all provided patterns.
|
|
449
|
+
*
|
|
450
|
+
* **Details**
|
|
451
|
+
*
|
|
452
|
+
* This function allows defining a condition where a value must match all the
|
|
453
|
+
* given patterns simultaneously. If the value satisfies every pattern, the
|
|
454
|
+
* associated function is executed.
|
|
455
|
+
*
|
|
456
|
+
* Unlike {@link when}, which matches a single pattern at a time, this function
|
|
457
|
+
* ensures that multiple conditions are met before executing the callback. It is
|
|
458
|
+
* useful when checking for values that need to fulfill multiple criteria at
|
|
459
|
+
* once.
|
|
460
|
+
*
|
|
461
|
+
* @example
|
|
462
|
+
* ```ts
|
|
463
|
+
* import { Match } from "effect"
|
|
464
|
+
*
|
|
465
|
+
* type User = { readonly age: number; readonly role: "admin" | "user" }
|
|
466
|
+
*
|
|
467
|
+
* const checkUser = Match.type<User>().pipe(
|
|
468
|
+
* Match.whenAnd(
|
|
469
|
+
* { age: (n) => n >= 18 },
|
|
470
|
+
* { role: "admin" },
|
|
471
|
+
* () => "Admin access granted"
|
|
472
|
+
* ),
|
|
473
|
+
* Match.orElse(() => "Access denied")
|
|
474
|
+
* )
|
|
475
|
+
*
|
|
476
|
+
* console.log(checkUser({ age: 20, role: "admin" }))
|
|
477
|
+
* // Output: "Admin access granted"
|
|
478
|
+
*
|
|
479
|
+
* console.log(checkUser({ age: 20, role: "user" }))
|
|
480
|
+
* // Output: "Access denied"
|
|
481
|
+
* ```
|
|
482
|
+
*
|
|
483
|
+
* @category Defining patterns
|
|
484
|
+
* @since 1.0.0
|
|
485
|
+
*/
|
|
486
|
+
export const whenAnd: <
|
|
487
|
+
R,
|
|
488
|
+
const P extends ReadonlyArray<Types.PatternPrimitive<R> | Types.PatternBase<R>>,
|
|
489
|
+
Ret,
|
|
490
|
+
Fn extends (_: Types.WhenMatch<R, T.UnionToIntersection<P[number]>>) => Ret
|
|
491
|
+
>(
|
|
492
|
+
...args: [...patterns: P, f: Fn]
|
|
493
|
+
) => <I, F, A, Pr>(
|
|
494
|
+
self: Matcher<I, F, R, A, Pr, Ret>
|
|
495
|
+
) => Matcher<
|
|
496
|
+
I,
|
|
497
|
+
Types.AddWithout<F, Types.PForExclude<T.UnionToIntersection<P[number]>>>,
|
|
498
|
+
Types.ApplyFilters<I, Types.AddWithout<F, Types.PForExclude<T.UnionToIntersection<P[number]>>>>,
|
|
499
|
+
A | ReturnType<Fn>,
|
|
500
|
+
Pr
|
|
501
|
+
> = internal.whenAnd
|
|
502
|
+
|
|
503
|
+
/**
|
|
504
|
+
* Matches values based on a specified discriminant field.
|
|
505
|
+
*
|
|
506
|
+
* **Details**
|
|
507
|
+
*
|
|
508
|
+
* This function is used to define pattern matching on objects that follow a
|
|
509
|
+
* **discriminated union** structure, where a specific field (e.g., `type`,
|
|
510
|
+
* `kind`, `_tag`) determines the variant of the object. It allows matching
|
|
511
|
+
* multiple values of the discriminant and provides a function to handle the
|
|
512
|
+
* matched cases.
|
|
513
|
+
*
|
|
514
|
+
* @example
|
|
515
|
+
* ```ts
|
|
516
|
+
* import { Match, pipe } from "effect"
|
|
517
|
+
*
|
|
518
|
+
* const match = pipe(
|
|
519
|
+
* Match.type<{ type: "A"; a: string } | { type: "B"; b: number } | { type: "C"; c: boolean }>(),
|
|
520
|
+
* Match.discriminator("type")("A", "B", (_) => `A or B: ${_.type}`),
|
|
521
|
+
* Match.discriminator("type")("C", (_) => `C(${_.c})`),
|
|
522
|
+
* Match.exhaustive
|
|
523
|
+
* )
|
|
524
|
+
* ```
|
|
525
|
+
*
|
|
526
|
+
* @category Defining patterns
|
|
527
|
+
* @since 1.0.0
|
|
528
|
+
*/
|
|
529
|
+
export const discriminator: <D extends string>(
|
|
530
|
+
field: D
|
|
531
|
+
) => <R, P extends Types.Tags<D, R> & string, Ret, Fn extends (_: Extract<R, Record<D, P>>) => Ret>(
|
|
532
|
+
...pattern: [first: P, ...values: Array<P>, f: Fn]
|
|
533
|
+
) => <I, F, A, Pr>(
|
|
534
|
+
self: Matcher<I, F, R, A, Pr, Ret>
|
|
535
|
+
) => Matcher<
|
|
536
|
+
I,
|
|
537
|
+
Types.AddWithout<F, Extract<R, Record<D, P>>>,
|
|
538
|
+
Types.ApplyFilters<I, Types.AddWithout<F, Extract<R, Record<D, P>>>>,
|
|
539
|
+
A | ReturnType<Fn>,
|
|
540
|
+
Pr,
|
|
541
|
+
Ret
|
|
542
|
+
> = internal.discriminator
|
|
543
|
+
|
|
544
|
+
/**
|
|
545
|
+
* Matches values where a specified field starts with a given prefix.
|
|
546
|
+
*
|
|
547
|
+
* **Details**
|
|
548
|
+
*
|
|
549
|
+
* This function is useful for working with discriminated unions where the
|
|
550
|
+
* discriminant field follows a hierarchical or namespaced structure. It allows
|
|
551
|
+
* you to match values based on whether the specified field starts with a given
|
|
552
|
+
* prefix, making it easier to handle grouped cases.
|
|
553
|
+
*
|
|
554
|
+
* Instead of checking for exact matches, this function lets you match values
|
|
555
|
+
* that share a common prefix. For example, if your discriminant field contains
|
|
556
|
+
* hierarchical names like `"A"`, `"A.A"`, and `"B"`, you can match all values
|
|
557
|
+
* starting with `"A"` using a single rule.
|
|
558
|
+
*
|
|
559
|
+
* @example
|
|
560
|
+
* ```ts
|
|
561
|
+
* import { Match, pipe } from "effect"
|
|
562
|
+
*
|
|
563
|
+
* const match = pipe(
|
|
564
|
+
* Match.type<{ type: "A" } | { type: "B" } | { type: "A.A" } | {}>(),
|
|
565
|
+
* Match.discriminatorStartsWith("type")("A", (_) => 1 as const),
|
|
566
|
+
* Match.discriminatorStartsWith("type")("B", (_) => 2 as const),
|
|
567
|
+
* Match.orElse((_) => 3 as const)
|
|
568
|
+
* )
|
|
569
|
+
*
|
|
570
|
+
* console.log(match({ type: "A" })) // 1
|
|
571
|
+
* console.log(match({ type: "B" })) // 2
|
|
572
|
+
* console.log(match({ type: "A.A" })) // 1
|
|
573
|
+
* ```
|
|
574
|
+
*
|
|
575
|
+
* @category Defining patterns
|
|
576
|
+
* @since 1.0.0
|
|
577
|
+
*/
|
|
578
|
+
export const discriminatorStartsWith: <D extends string>(
|
|
579
|
+
field: D
|
|
580
|
+
) => <R, P extends string, Ret, Fn extends (_: Extract<R, Record<D, `${P}${string}`>>) => Ret>(
|
|
581
|
+
pattern: P,
|
|
582
|
+
f: Fn
|
|
583
|
+
) => <I, F, A, Pr>(
|
|
584
|
+
self: Matcher<I, F, R, A, Pr, Ret>
|
|
585
|
+
) => Matcher<
|
|
586
|
+
I,
|
|
587
|
+
Types.AddWithout<F, Extract<R, Record<D, `${P}${string}`>>>,
|
|
588
|
+
Types.ApplyFilters<I, Types.AddWithout<F, Extract<R, Record<D, `${P}${string}`>>>>,
|
|
589
|
+
A | ReturnType<Fn>,
|
|
590
|
+
Pr,
|
|
591
|
+
Ret
|
|
592
|
+
> = internal.discriminatorStartsWith
|
|
593
|
+
|
|
594
|
+
/**
|
|
595
|
+
* Matches values based on a field that serves as a discriminator, mapping each
|
|
596
|
+
* possible value to a corresponding handler.
|
|
597
|
+
*
|
|
598
|
+
* **Details**
|
|
599
|
+
*
|
|
600
|
+
* This function simplifies working with discriminated unions by letting you
|
|
601
|
+
* define a set of handlers for each possible value of a given field. Instead of
|
|
602
|
+
* chaining multiple calls to {@link discriminator}, this function allows
|
|
603
|
+
* defining all possible cases at once using an object where the keys are the
|
|
604
|
+
* possible values of the field, and the values are the corresponding handler
|
|
605
|
+
* functions.
|
|
606
|
+
*
|
|
607
|
+
* @example
|
|
608
|
+
* ```ts
|
|
609
|
+
* import { Match, pipe } from "effect"
|
|
610
|
+
*
|
|
611
|
+
* const match = pipe(
|
|
612
|
+
* Match.type<{ type: "A"; a: string } | { type: "B"; b: number } | { type: "C"; c: boolean }>(),
|
|
613
|
+
* Match.discriminators("type")({
|
|
614
|
+
* A: (a) => a.a,
|
|
615
|
+
* B: (b) => b.b,
|
|
616
|
+
* C: (c) => c.c
|
|
617
|
+
* }),
|
|
618
|
+
* Match.exhaustive
|
|
619
|
+
* )
|
|
620
|
+
* ```
|
|
621
|
+
*
|
|
622
|
+
* @category Defining patterns
|
|
623
|
+
* @since 1.0.0
|
|
624
|
+
*/
|
|
625
|
+
export const discriminators: <D extends string>(
|
|
626
|
+
field: D
|
|
627
|
+
) => <
|
|
628
|
+
R,
|
|
629
|
+
Ret,
|
|
630
|
+
P extends
|
|
631
|
+
& { readonly [Tag in Types.Tags<D, R> & string]?: ((_: Extract<R, Record<D, Tag>>) => Ret) | undefined }
|
|
632
|
+
& { readonly [Tag in Exclude<keyof P, Types.Tags<D, R>>]: never }
|
|
633
|
+
>(
|
|
634
|
+
fields: P
|
|
635
|
+
) => <I, F, A, Pr>(
|
|
636
|
+
self: Matcher<I, F, R, A, Pr, Ret>
|
|
637
|
+
) => Matcher<
|
|
638
|
+
I,
|
|
639
|
+
Types.AddWithout<F, Extract<R, Record<D, keyof P>>>,
|
|
640
|
+
Types.ApplyFilters<I, Types.AddWithout<F, Extract<R, Record<D, keyof P>>>>,
|
|
641
|
+
A | ReturnType<P[keyof P] & {}>,
|
|
642
|
+
Pr,
|
|
643
|
+
Ret
|
|
644
|
+
> = internal.discriminators
|
|
645
|
+
|
|
646
|
+
/**
|
|
647
|
+
* Matches values based on a discriminator field and **ensures all cases are
|
|
648
|
+
* handled**.
|
|
649
|
+
*
|
|
650
|
+
* **Details*+
|
|
651
|
+
*
|
|
652
|
+
* This function is similar to {@link discriminators}, but **requires that all
|
|
653
|
+
* possible cases** are explicitly handled. It is useful when working with
|
|
654
|
+
* discriminated unions, where a specific field (e.g., `"type"`) determines the
|
|
655
|
+
* shape of an object. Each possible value of the field must have a
|
|
656
|
+
* corresponding handler, ensuring **exhaustiveness checking** at compile time.
|
|
657
|
+
*
|
|
658
|
+
* This function **does not require** `Match.exhaustive` at the end of the
|
|
659
|
+
* pipeline because it enforces exhaustiveness by design.
|
|
660
|
+
*
|
|
661
|
+
* @example
|
|
662
|
+
* ```ts
|
|
663
|
+
* import { Match, pipe } from "effect"
|
|
664
|
+
*
|
|
665
|
+
* const match = pipe(
|
|
666
|
+
* Match.type<{ type: "A"; a: string } | { type: "B"; b: number } | { type: "C"; c: boolean }>(),
|
|
667
|
+
* Match.discriminatorsExhaustive("type")({
|
|
668
|
+
* A: (a) => a.a,
|
|
669
|
+
* B: (b) => b.b,
|
|
670
|
+
* C: (c) => c.c
|
|
671
|
+
* })
|
|
672
|
+
* )
|
|
673
|
+
* ```
|
|
674
|
+
*
|
|
675
|
+
* @category Defining patterns
|
|
676
|
+
* @since 1.0.0
|
|
677
|
+
*/
|
|
678
|
+
export const discriminatorsExhaustive: <D extends string>(
|
|
679
|
+
field: D
|
|
680
|
+
) => <
|
|
681
|
+
R,
|
|
682
|
+
Ret,
|
|
683
|
+
P extends
|
|
684
|
+
& { readonly [Tag in Types.Tags<D, R> & string]: (_: Extract<R, Record<D, Tag>>) => Ret }
|
|
685
|
+
& { readonly [Tag in Exclude<keyof P, Types.Tags<D, R>>]: never }
|
|
686
|
+
>(
|
|
687
|
+
fields: P
|
|
688
|
+
) => <I, F, A, Pr>(
|
|
689
|
+
self: Matcher<I, F, R, A, Pr, Ret>
|
|
690
|
+
) => [Pr] extends [never] ? (u: I) => Unify<A | ReturnType<P[keyof P]>> : Unify<A | ReturnType<P[keyof P]>> =
|
|
691
|
+
internal.discriminatorsExhaustive
|
|
692
|
+
|
|
693
|
+
/**
|
|
694
|
+
* The `Match.tag` function allows pattern matching based on the `_tag` field in
|
|
695
|
+
* a [Discriminated Union](https://www.typescriptlang.org/docs/handbook/typescript-in-5-minutes-func.html#discriminated-unions).
|
|
696
|
+
* You can specify multiple tags to match within a single pattern.
|
|
697
|
+
*
|
|
698
|
+
* **Note**
|
|
699
|
+
*
|
|
700
|
+
* The `Match.tag` function relies on the convention within the Effect ecosystem
|
|
701
|
+
* of naming the tag field as `"_tag"`. Ensure that your discriminated unions
|
|
702
|
+
* follow this naming convention for proper functionality.
|
|
703
|
+
*
|
|
704
|
+
* **Example** (Matching a Discriminated Union by Tag)
|
|
705
|
+
*
|
|
706
|
+
* ```ts
|
|
707
|
+
* import { Match } from "effect"
|
|
708
|
+
*
|
|
709
|
+
* type Event =
|
|
710
|
+
* | { readonly _tag: "fetch" }
|
|
711
|
+
* | { readonly _tag: "success"; readonly data: string }
|
|
712
|
+
* | { readonly _tag: "error"; readonly error: Error }
|
|
713
|
+
* | { readonly _tag: "cancel" }
|
|
714
|
+
*
|
|
715
|
+
* // Create a Matcher for Either<number, string>
|
|
716
|
+
* const match = Match.type<Event>().pipe(
|
|
717
|
+
* // Match either "fetch" or "success"
|
|
718
|
+
* Match.tag("fetch", "success", () => `Ok!`),
|
|
719
|
+
* // Match "error" and extract the error message
|
|
720
|
+
* Match.tag("error", (event) => `Error: ${event.error.message}`),
|
|
721
|
+
* // Match "cancel"
|
|
722
|
+
* Match.tag("cancel", () => "Cancelled"),
|
|
723
|
+
* Match.exhaustive
|
|
724
|
+
* )
|
|
725
|
+
*
|
|
726
|
+
* console.log(match({ _tag: "success", data: "Hello" }))
|
|
727
|
+
* // Output: "Ok!"
|
|
728
|
+
*
|
|
729
|
+
* console.log(match({ _tag: "error", error: new Error("Oops!") }))
|
|
730
|
+
* // Output: "Error: Oops!"
|
|
731
|
+
* ```
|
|
732
|
+
*
|
|
733
|
+
* @category Defining patterns
|
|
734
|
+
* @since 1.0.0
|
|
735
|
+
*/
|
|
736
|
+
export const tag: <
|
|
737
|
+
R,
|
|
738
|
+
P extends Types.Tags<"_tag", R> & string,
|
|
739
|
+
Ret,
|
|
740
|
+
Fn extends (_: Extract<R, Record<"_tag", P>>) => Ret
|
|
741
|
+
>(
|
|
742
|
+
...pattern: [first: P, ...values: Array<P>, f: Fn]
|
|
743
|
+
) => <I, F, A, Pr>(
|
|
744
|
+
self: Matcher<I, F, R, A, Pr, Ret>
|
|
745
|
+
) => Matcher<
|
|
746
|
+
I,
|
|
747
|
+
Types.AddWithout<F, Extract<R, Record<"_tag", P>>>,
|
|
748
|
+
Types.ApplyFilters<I, Types.AddWithout<F, Extract<R, Record<"_tag", P>>>>,
|
|
749
|
+
ReturnType<Fn> | A,
|
|
750
|
+
Pr,
|
|
751
|
+
Ret
|
|
752
|
+
> = internal.tag
|
|
753
|
+
|
|
754
|
+
/**
|
|
755
|
+
* Matches values where the `_tag` field starts with a given prefix.
|
|
756
|
+
*
|
|
757
|
+
* **Details**
|
|
758
|
+
*
|
|
759
|
+
* This function allows you to match on values in a **discriminated union**
|
|
760
|
+
* based on whether the `_tag` field starts with a specified prefix. It is
|
|
761
|
+
* useful for handling hierarchical or namespaced tags, where multiple related
|
|
762
|
+
* cases share a common prefix.
|
|
763
|
+
*
|
|
764
|
+
* @example
|
|
765
|
+
* ```ts
|
|
766
|
+
* import { Match, pipe } from "effect"
|
|
767
|
+
*
|
|
768
|
+
* const match = pipe(
|
|
769
|
+
* Match.type<{ _tag: "A" } | { _tag: "B" } | { _tag: "A.A" } | {}>(),
|
|
770
|
+
* Match.tagStartsWith("A", (_) => 1 as const),
|
|
771
|
+
* Match.tagStartsWith("B", (_) => 2 as const),
|
|
772
|
+
* Match.orElse((_) => 3 as const)
|
|
773
|
+
* )
|
|
774
|
+
*
|
|
775
|
+
* console.log(match({ _tag: "A" })) // 1
|
|
776
|
+
* console.log(match({ _tag: "B" })) // 2
|
|
777
|
+
* console.log(match({ _tag: "A.A" })) // 1
|
|
778
|
+
* ```
|
|
779
|
+
*
|
|
780
|
+
* @category Defining patterns
|
|
781
|
+
* @since 1.0.0
|
|
782
|
+
*/
|
|
783
|
+
export const tagStartsWith: <
|
|
784
|
+
R,
|
|
785
|
+
P extends string,
|
|
786
|
+
Ret,
|
|
787
|
+
Fn extends (_: Extract<R, Record<"_tag", `${P}${string}`>>) => Ret
|
|
788
|
+
>(
|
|
789
|
+
pattern: P,
|
|
790
|
+
f: Fn
|
|
791
|
+
) => <I, F, A, Pr>(
|
|
792
|
+
self: Matcher<I, F, R, A, Pr, Ret>
|
|
793
|
+
) => Matcher<
|
|
794
|
+
I,
|
|
795
|
+
Types.AddWithout<F, Extract<R, Record<"_tag", `${P}${string}`>>>,
|
|
796
|
+
Types.ApplyFilters<I, Types.AddWithout<F, Extract<R, Record<"_tag", `${P}${string}`>>>>,
|
|
797
|
+
ReturnType<Fn> | A,
|
|
798
|
+
Pr,
|
|
799
|
+
Ret
|
|
800
|
+
> = internal.tagStartsWith
|
|
801
|
+
|
|
802
|
+
/**
|
|
803
|
+
* Matches values based on their `_tag` field, mapping each tag to a
|
|
804
|
+
* corresponding handler.
|
|
805
|
+
*
|
|
806
|
+
* **Details**
|
|
807
|
+
*
|
|
808
|
+
* This function provides a way to handle discriminated unions by mapping `_tag`
|
|
809
|
+
* values to specific functions. Each handler receives the matched value and
|
|
810
|
+
* returns a transformed result. If all possible tags are handled, you can
|
|
811
|
+
* enforce exhaustiveness using `Match.exhaustive` to ensure no case is missed.
|
|
812
|
+
*
|
|
813
|
+
* @example
|
|
814
|
+
* ```ts
|
|
815
|
+
* import { Match, pipe } from "effect"
|
|
816
|
+
*
|
|
817
|
+
* const match = pipe(
|
|
818
|
+
* Match.type<{ _tag: "A"; a: string } | { _tag: "B"; b: number } | { _tag: "C"; c: boolean }>(),
|
|
819
|
+
* Match.tags({
|
|
820
|
+
* A: (a) => a.a,
|
|
821
|
+
* B: (b) => b.b,
|
|
822
|
+
* C: (c) => c.c
|
|
823
|
+
* }),
|
|
824
|
+
* Match.exhaustive
|
|
825
|
+
* )
|
|
826
|
+
* ```
|
|
827
|
+
*
|
|
828
|
+
* @category Defining patterns
|
|
829
|
+
* @since 1.0.0
|
|
830
|
+
*/
|
|
831
|
+
export const tags: <
|
|
832
|
+
R,
|
|
833
|
+
Ret,
|
|
834
|
+
P extends
|
|
835
|
+
& { readonly [Tag in Types.Tags<"_tag", R> & string]?: ((_: Extract<R, Record<"_tag", Tag>>) => Ret) | undefined }
|
|
836
|
+
& { readonly [Tag in Exclude<keyof P, Types.Tags<"_tag", R>>]: never }
|
|
837
|
+
>(
|
|
838
|
+
fields: P
|
|
839
|
+
) => <I, F, A, Pr>(
|
|
840
|
+
self: Matcher<I, F, R, A, Pr, Ret>
|
|
841
|
+
) => Matcher<
|
|
842
|
+
I,
|
|
843
|
+
Types.AddWithout<F, Extract<R, Record<"_tag", keyof P>>>,
|
|
844
|
+
Types.ApplyFilters<I, Types.AddWithout<F, Extract<R, Record<"_tag", keyof P>>>>,
|
|
845
|
+
A | ReturnType<P[keyof P] & {}>,
|
|
846
|
+
Pr,
|
|
847
|
+
Ret
|
|
848
|
+
> = internal.tags
|
|
849
|
+
|
|
850
|
+
/**
|
|
851
|
+
* Matches values based on their `_tag` field and requires handling of all
|
|
852
|
+
* possible cases.
|
|
853
|
+
*
|
|
854
|
+
* **Details**
|
|
855
|
+
*
|
|
856
|
+
* This function is designed for **discriminated unions** where every possible
|
|
857
|
+
* `_tag` value must have a corresponding handler. Unlike {@link tags}, this
|
|
858
|
+
* function ensures **exhaustiveness**, meaning all cases must be explicitly
|
|
859
|
+
* handled. If a `_tag` value is missing from the mapping, TypeScript will
|
|
860
|
+
* report an error.
|
|
861
|
+
*
|
|
862
|
+
* @example
|
|
863
|
+
* ```ts
|
|
864
|
+
* import { Match, pipe } from "effect"
|
|
865
|
+
*
|
|
866
|
+
* const match = pipe(
|
|
867
|
+
* Match.type<{ _tag: "A"; a: string } | { _tag: "B"; b: number } | { _tag: "C"; c: boolean }>(),
|
|
868
|
+
* Match.tagsExhaustive({
|
|
869
|
+
* A: (a) => a.a,
|
|
870
|
+
* B: (b) => b.b,
|
|
871
|
+
* C: (c) => c.c
|
|
872
|
+
* })
|
|
873
|
+
* )
|
|
874
|
+
* ```
|
|
875
|
+
*
|
|
876
|
+
* @category Defining patterns
|
|
877
|
+
* @since 1.0.0
|
|
878
|
+
*/
|
|
879
|
+
export const tagsExhaustive: <
|
|
880
|
+
R,
|
|
881
|
+
Ret,
|
|
882
|
+
P extends
|
|
883
|
+
& { readonly [Tag in Types.Tags<"_tag", R> & string]: (_: Extract<R, Record<"_tag", Tag>>) => Ret }
|
|
884
|
+
& { readonly [Tag in Exclude<keyof P, Types.Tags<"_tag", R>>]: never }
|
|
885
|
+
>(
|
|
886
|
+
fields: P
|
|
887
|
+
) => <I, F, A, Pr>(
|
|
888
|
+
self: Matcher<I, F, R, A, Pr, Ret>
|
|
889
|
+
) => [Pr] extends [never] ? (u: I) => Unify<A | ReturnType<P[keyof P]>> : Unify<A | ReturnType<P[keyof P]>> =
|
|
890
|
+
internal.tagsExhaustive
|
|
891
|
+
|
|
892
|
+
/**
|
|
893
|
+
* Excludes a specific value from matching while allowing all others.
|
|
894
|
+
*
|
|
895
|
+
* **Details**
|
|
896
|
+
*
|
|
897
|
+
* This function is useful when you need to **handle all values except one or
|
|
898
|
+
* more specific cases**. Instead of listing all possible matches manually, this
|
|
899
|
+
* function simplifies the logic by allowing you to specify values to exclude.
|
|
900
|
+
* Any excluded value will bypass the provided function and continue matching
|
|
901
|
+
* through other cases.
|
|
902
|
+
*
|
|
903
|
+
* **Example** (Ignoring a Specific Value)
|
|
904
|
+
*
|
|
905
|
+
* ```ts
|
|
906
|
+
* import { Match } from "effect"
|
|
907
|
+
*
|
|
908
|
+
* // Create a matcher for string or number values
|
|
909
|
+
* const match = Match.type<string | number>().pipe(
|
|
910
|
+
* // Match any value except "hi", returning "ok"
|
|
911
|
+
* Match.not("hi", () => "ok"),
|
|
912
|
+
* // Fallback case for when the value is "hi"
|
|
913
|
+
* Match.orElse(() => "fallback")
|
|
914
|
+
* )
|
|
915
|
+
*
|
|
916
|
+
* console.log(match("hello"))
|
|
917
|
+
* // Output: "ok"
|
|
918
|
+
*
|
|
919
|
+
* console.log(match("hi"))
|
|
920
|
+
* // Output: "fallback"
|
|
921
|
+
* ```
|
|
922
|
+
*
|
|
923
|
+
* @category Defining patterns
|
|
924
|
+
* @since 1.0.0
|
|
925
|
+
*/
|
|
926
|
+
export const not: <
|
|
927
|
+
R,
|
|
928
|
+
const P extends Types.PatternPrimitive<R> | Types.PatternBase<R>,
|
|
929
|
+
Ret,
|
|
930
|
+
Fn extends (_: Types.NotMatch<R, P>) => Ret
|
|
931
|
+
>(
|
|
932
|
+
pattern: P,
|
|
933
|
+
f: Fn
|
|
934
|
+
) => <I, F, A, Pr>(
|
|
935
|
+
self: Matcher<I, F, R, A, Pr, Ret>
|
|
936
|
+
) => Matcher<
|
|
937
|
+
I,
|
|
938
|
+
Types.AddOnly<F, Types.WhenMatch<R, P>>,
|
|
939
|
+
Types.ApplyFilters<I, Types.AddOnly<F, Types.WhenMatch<R, P>>>,
|
|
940
|
+
A | ReturnType<Fn>,
|
|
941
|
+
Pr,
|
|
942
|
+
Ret
|
|
943
|
+
> = internal.not
|
|
944
|
+
|
|
945
|
+
/**
|
|
946
|
+
* Matches non-empty strings.
|
|
947
|
+
*
|
|
948
|
+
* @category Predicates
|
|
949
|
+
* @since 1.0.0
|
|
950
|
+
*/
|
|
951
|
+
export const nonEmptyString: SafeRefinement<string, never> = internal.nonEmptyString
|
|
952
|
+
|
|
953
|
+
/**
|
|
954
|
+
* Matches a specific set of literal values (e.g., `Match.is("a", 42, true)`).
|
|
955
|
+
*
|
|
956
|
+
* @category Predicates
|
|
957
|
+
* @since 1.0.0
|
|
958
|
+
*/
|
|
959
|
+
export const is: <
|
|
960
|
+
Literals extends ReadonlyArray<string | number | bigint | boolean | null>
|
|
961
|
+
>(...literals: Literals) => SafeRefinement<Literals[number]> = internal.is
|
|
962
|
+
|
|
963
|
+
/**
|
|
964
|
+
* Matches values of type `string`.
|
|
965
|
+
*
|
|
966
|
+
* @category Predicates
|
|
967
|
+
* @since 1.0.0
|
|
968
|
+
*/
|
|
969
|
+
export const string: Predicate.Refinement<unknown, string> = Predicate.isString
|
|
970
|
+
|
|
971
|
+
/**
|
|
972
|
+
* Matches values of type `number`.
|
|
973
|
+
*
|
|
974
|
+
* @category Predicates
|
|
975
|
+
* @since 1.0.0
|
|
976
|
+
*/
|
|
977
|
+
export const number: Predicate.Refinement<unknown, number> = Predicate.isNumber
|
|
978
|
+
|
|
979
|
+
/**
|
|
980
|
+
* Matches any value without restrictions.
|
|
981
|
+
*
|
|
982
|
+
* @category Predicates
|
|
983
|
+
* @since 1.0.0
|
|
984
|
+
*/
|
|
985
|
+
export const any: SafeRefinement<unknown, any> = internal.any
|
|
986
|
+
|
|
987
|
+
/**
|
|
988
|
+
* Matches any defined (non-null and non-undefined) value.
|
|
989
|
+
*
|
|
990
|
+
* @category Predicates
|
|
991
|
+
* @since 1.0.0
|
|
992
|
+
*/
|
|
993
|
+
export const defined: <A>(u: A) => u is A & {} = internal.defined
|
|
994
|
+
|
|
995
|
+
/**
|
|
996
|
+
* Matches values of type `boolean`.
|
|
997
|
+
*
|
|
998
|
+
* @category Predicates
|
|
999
|
+
* @since 1.0.0
|
|
1000
|
+
*/
|
|
1001
|
+
export const boolean: Predicate.Refinement<unknown, boolean> = Predicate.isBoolean
|
|
1002
|
+
|
|
1003
|
+
const _undefined: Predicate.Refinement<unknown, undefined> = Predicate.isUndefined
|
|
1004
|
+
export {
|
|
1005
|
+
/**
|
|
1006
|
+
* Matches the value `undefined`.
|
|
1007
|
+
*
|
|
1008
|
+
* @category Predicates
|
|
1009
|
+
* @since 1.0.0
|
|
1010
|
+
*/
|
|
1011
|
+
_undefined as undefined
|
|
1012
|
+
}
|
|
1013
|
+
|
|
1014
|
+
const _null: Predicate.Refinement<unknown, null> = Predicate.isNull
|
|
1015
|
+
export {
|
|
1016
|
+
/**
|
|
1017
|
+
* Matches the value `null`.
|
|
1018
|
+
*
|
|
1019
|
+
* @category Predicates
|
|
1020
|
+
* @since 1.0.0
|
|
1021
|
+
*/
|
|
1022
|
+
_null as null
|
|
1023
|
+
}
|
|
1024
|
+
|
|
1025
|
+
/**
|
|
1026
|
+
* Matches values of type `bigint`.
|
|
1027
|
+
*
|
|
1028
|
+
* @category Predicates
|
|
1029
|
+
* @since 1.0.0
|
|
1030
|
+
*/
|
|
1031
|
+
export const bigint: Predicate.Refinement<unknown, bigint> = Predicate.isBigInt
|
|
1032
|
+
|
|
1033
|
+
/**
|
|
1034
|
+
* Matches values of type `symbol`.
|
|
1035
|
+
*
|
|
1036
|
+
* @category Predicates
|
|
1037
|
+
* @since 1.0.0
|
|
1038
|
+
*/
|
|
1039
|
+
export const symbol: Predicate.Refinement<unknown, symbol> = Predicate.isSymbol
|
|
1040
|
+
|
|
1041
|
+
/**
|
|
1042
|
+
* Matches values that are instances of `Date`.
|
|
1043
|
+
*
|
|
1044
|
+
* @category Predicates
|
|
1045
|
+
* @since 1.0.0
|
|
1046
|
+
*/
|
|
1047
|
+
export const date: Predicate.Refinement<unknown, Date> = Predicate.isDate
|
|
1048
|
+
|
|
1049
|
+
/**
|
|
1050
|
+
* Matches objects where keys are `string` or `symbol` and values are `unknown`.
|
|
1051
|
+
*
|
|
1052
|
+
* @category Predicates
|
|
1053
|
+
* @since 1.0.0
|
|
1054
|
+
*/
|
|
1055
|
+
export const record: Predicate.Refinement<unknown, { [x: string | symbol]: unknown }> = Predicate.isRecord
|
|
1056
|
+
|
|
1057
|
+
/**
|
|
1058
|
+
* Matches instances of a given class.
|
|
1059
|
+
*
|
|
1060
|
+
* @category Predicates
|
|
1061
|
+
* @since 1.0.0
|
|
1062
|
+
*/
|
|
1063
|
+
export const instanceOf: <A extends abstract new(...args: any) => any>(
|
|
1064
|
+
constructor: A
|
|
1065
|
+
) => SafeRefinement<InstanceType<A>, never> = internal.instanceOf
|
|
1066
|
+
|
|
1067
|
+
/**
|
|
1068
|
+
* @category Predicates
|
|
1069
|
+
* @since 1.0.0
|
|
1070
|
+
*/
|
|
1071
|
+
export const instanceOfUnsafe: <A extends abstract new(...args: any) => any>(
|
|
1072
|
+
constructor: A
|
|
1073
|
+
) => SafeRefinement<InstanceType<A>, InstanceType<A>> = internal.instanceOf
|
|
1074
|
+
|
|
1075
|
+
/**
|
|
1076
|
+
* Provides a fallback value when no patterns match.
|
|
1077
|
+
*
|
|
1078
|
+
* **Details**
|
|
1079
|
+
*
|
|
1080
|
+
* This function ensures that a matcher always returns a valid result, even if
|
|
1081
|
+
* no defined patterns match. It acts as a default case, similar to the
|
|
1082
|
+
* `default` clause in a `switch` statement or the final `else` in an `if-else`
|
|
1083
|
+
* chain.
|
|
1084
|
+
*
|
|
1085
|
+
* **Example** (Providing a Default Value When No Patterns Match)
|
|
1086
|
+
*
|
|
1087
|
+
* ```ts
|
|
1088
|
+
* import { Match } from "effect"
|
|
1089
|
+
*
|
|
1090
|
+
* // Create a matcher for string or number values
|
|
1091
|
+
* const match = Match.type<string | number>().pipe(
|
|
1092
|
+
* // Match when the value is "a"
|
|
1093
|
+
* Match.when("a", () => "ok"),
|
|
1094
|
+
* // Fallback when no patterns match
|
|
1095
|
+
* Match.orElse(() => "fallback")
|
|
1096
|
+
* )
|
|
1097
|
+
*
|
|
1098
|
+
* console.log(match("a"))
|
|
1099
|
+
* // Output: "ok"
|
|
1100
|
+
*
|
|
1101
|
+
* console.log(match("b"))
|
|
1102
|
+
* // Output: "fallback"
|
|
1103
|
+
* ```
|
|
1104
|
+
*
|
|
1105
|
+
* @category Completion
|
|
1106
|
+
* @since 1.0.0
|
|
1107
|
+
*/
|
|
1108
|
+
export const orElse: <RA, Ret, F extends (_: RA) => Ret>(
|
|
1109
|
+
f: F
|
|
1110
|
+
) => <I, R, A, Pr>(
|
|
1111
|
+
self: Matcher<I, R, RA, A, Pr, Ret>
|
|
1112
|
+
) => [Pr] extends [never] ? (input: I) => Unify<ReturnType<F> | A> : Unify<ReturnType<F> | A> = internal.orElse
|
|
1113
|
+
|
|
1114
|
+
// TODO(4.0): Rename to "orThrow"? Like Either.getOrThrow
|
|
1115
|
+
/**
|
|
1116
|
+
* Throws an error if no pattern matches.
|
|
1117
|
+
*
|
|
1118
|
+
* **Details**
|
|
1119
|
+
*
|
|
1120
|
+
* This function finalizes a matcher by ensuring that if no patterns match, an
|
|
1121
|
+
* error is thrown. It is useful when all cases should be covered, and any
|
|
1122
|
+
* unexpected input should trigger an error instead of returning a default
|
|
1123
|
+
* value.
|
|
1124
|
+
*
|
|
1125
|
+
* When used, this function removes the need for an explicit fallback case and
|
|
1126
|
+
* ensures that an unmatched value is never silently ignored.
|
|
1127
|
+
*
|
|
1128
|
+
* @category Completion
|
|
1129
|
+
* @since 1.0.0
|
|
1130
|
+
*/
|
|
1131
|
+
export const orElseAbsurd: <I, R, RA, A, Pr, Ret>(
|
|
1132
|
+
self: Matcher<I, R, RA, A, Pr, Ret>
|
|
1133
|
+
) => [Pr] extends [never] ? (input: I) => Unify<A> : Unify<A> = internal.orElseAbsurd
|
|
1134
|
+
|
|
1135
|
+
/**
|
|
1136
|
+
* Wraps the match result in an `Either`, distinguishing matched and unmatched
|
|
1137
|
+
* cases.
|
|
1138
|
+
*
|
|
1139
|
+
* **Details**
|
|
1140
|
+
*
|
|
1141
|
+
* This function ensures that the result of a matcher is always wrapped in an
|
|
1142
|
+
* `Either`, allowing clear differentiation between successful matches
|
|
1143
|
+
* (`Right(value)`) and cases where no pattern matched (`Left(unmatched
|
|
1144
|
+
* value)`).
|
|
1145
|
+
*
|
|
1146
|
+
* This approach is particularly useful when handling optional values or when an
|
|
1147
|
+
* unmatched case should be explicitly handled rather than returning a default
|
|
1148
|
+
* value or throwing an error.
|
|
1149
|
+
*
|
|
1150
|
+
* **Example** (Extracting a User Role with `Match.either`)
|
|
1151
|
+
*
|
|
1152
|
+
* ```ts
|
|
1153
|
+
* import { Match } from "effect"
|
|
1154
|
+
*
|
|
1155
|
+
* type User = { readonly role: "admin" | "editor" | "viewer" }
|
|
1156
|
+
*
|
|
1157
|
+
* // Create a matcher to extract user roles
|
|
1158
|
+
* const getRole = Match.type<User>().pipe(
|
|
1159
|
+
* Match.when({ role: "admin" }, () => "Has full access"),
|
|
1160
|
+
* Match.when({ role: "editor" }, () => "Can edit content"),
|
|
1161
|
+
* Match.either // Wrap the result in an Either
|
|
1162
|
+
* )
|
|
1163
|
+
*
|
|
1164
|
+
* console.log(getRole({ role: "admin" }))
|
|
1165
|
+
* // Output: { _id: 'Either', _tag: 'Right', right: 'Has full access' }
|
|
1166
|
+
*
|
|
1167
|
+
* console.log(getRole({ role: "viewer" }))
|
|
1168
|
+
* // Output: { _id: 'Either', _tag: 'Left', left: { role: 'viewer' } }
|
|
1169
|
+
* ```
|
|
1170
|
+
*
|
|
1171
|
+
* @category Completion
|
|
1172
|
+
* @since 1.0.0
|
|
1173
|
+
*/
|
|
1174
|
+
export const either: <I, F, R, A, Pr, Ret>(
|
|
1175
|
+
self: Matcher<I, F, R, A, Pr, Ret>
|
|
1176
|
+
) => [Pr] extends [never] ? (input: I) => Either.Either<Unify<A>, R> : Either.Either<Unify<A>, R> = internal.either
|
|
1177
|
+
|
|
1178
|
+
/**
|
|
1179
|
+
* Wraps the match result in an `Option`, representing an optional match.
|
|
1180
|
+
*
|
|
1181
|
+
* **Details**
|
|
1182
|
+
*
|
|
1183
|
+
* This function ensures that the result of a matcher is wrapped in an `Option`,
|
|
1184
|
+
* making it easy to handle cases where no pattern matches. If a match is found,
|
|
1185
|
+
* it returns `Some(value)`, otherwise, it returns `None`.
|
|
1186
|
+
*
|
|
1187
|
+
* This is useful in cases where a missing match is expected and should be
|
|
1188
|
+
* handled explicitly rather than throwing an error or returning a default
|
|
1189
|
+
* value.
|
|
1190
|
+
*
|
|
1191
|
+
* **Example** (Extracting a User Role with `Match.option`)
|
|
1192
|
+
*
|
|
1193
|
+
* ```ts
|
|
1194
|
+
* import { Match } from "effect"
|
|
1195
|
+
*
|
|
1196
|
+
* type User = { readonly role: "admin" | "editor" | "viewer" }
|
|
1197
|
+
*
|
|
1198
|
+
* // Create a matcher to extract user roles
|
|
1199
|
+
* const getRole = Match.type<User>().pipe(
|
|
1200
|
+
* Match.when({ role: "admin" }, () => "Has full access"),
|
|
1201
|
+
* Match.when({ role: "editor" }, () => "Can edit content"),
|
|
1202
|
+
* Match.option // Wrap the result in an Option
|
|
1203
|
+
* )
|
|
1204
|
+
*
|
|
1205
|
+
* console.log(getRole({ role: "admin" }))
|
|
1206
|
+
* // Output: { _id: 'Option', _tag: 'Some', value: 'Has full access' }
|
|
1207
|
+
*
|
|
1208
|
+
* console.log(getRole({ role: "viewer" }))
|
|
1209
|
+
* // Output: { _id: 'Option', _tag: 'None' }
|
|
1210
|
+
* ```
|
|
1211
|
+
*
|
|
1212
|
+
* @category Completion
|
|
1213
|
+
* @since 1.0.0
|
|
1214
|
+
*/
|
|
1215
|
+
export const option: <I, F, R, A, Pr, Ret>(
|
|
1216
|
+
self: Matcher<I, F, R, A, Pr, Ret>
|
|
1217
|
+
) => [Pr] extends [never] ? (input: I) => Option.Option<Unify<A>> : Option.Option<Unify<A>> = internal.option
|
|
1218
|
+
|
|
1219
|
+
/**
|
|
1220
|
+
* The `Match.exhaustive` method finalizes the pattern matching process by
|
|
1221
|
+
* ensuring that all possible cases are accounted for. If any case is missing,
|
|
1222
|
+
* TypeScript will produce a type error. This is particularly useful when
|
|
1223
|
+
* working with unions, as it helps prevent unintended gaps in pattern matching.
|
|
1224
|
+
*
|
|
1225
|
+
* **Example** (Ensuring All Cases Are Covered)
|
|
1226
|
+
*
|
|
1227
|
+
* ```ts
|
|
1228
|
+
* import { Match } from "effect"
|
|
1229
|
+
*
|
|
1230
|
+
* // Create a matcher for string or number values
|
|
1231
|
+
* const match = Match.type<string | number>().pipe(
|
|
1232
|
+
* // Match when the value is a number
|
|
1233
|
+
* Match.when(Match.number, (n) => `number: ${n}`),
|
|
1234
|
+
* // Mark the match as exhaustive, ensuring all cases are handled
|
|
1235
|
+
* // TypeScript will throw an error if any case is missing
|
|
1236
|
+
* // @ts-expect-error Type 'string' is not assignable to type 'never'
|
|
1237
|
+
* Match.exhaustive
|
|
1238
|
+
* )
|
|
1239
|
+
* ```
|
|
1240
|
+
*
|
|
1241
|
+
* @category Completion
|
|
1242
|
+
* @since 1.0.0
|
|
1243
|
+
*/
|
|
1244
|
+
export const exhaustive: <I, F, A, Pr, Ret>(
|
|
1245
|
+
self: Matcher<I, F, never, A, Pr, Ret>
|
|
1246
|
+
) => [Pr] extends [never] ? (u: I) => Unify<A> : Unify<A> = internal.exhaustive
|
|
1247
|
+
|
|
1248
|
+
/**
|
|
1249
|
+
* @since 1.0.0
|
|
1250
|
+
* @category Symbols
|
|
1251
|
+
*/
|
|
1252
|
+
export const SafeRefinementId = Symbol.for("effect/SafeRefinement")
|
|
1253
|
+
|
|
1254
|
+
/**
|
|
1255
|
+
* @since 1.0.0
|
|
1256
|
+
* @category Symbols
|
|
1257
|
+
*/
|
|
1258
|
+
export type SafeRefinementId = typeof SafeRefinementId
|
|
1259
|
+
|
|
1260
|
+
/**
|
|
1261
|
+
* @category Model
|
|
1262
|
+
* @since 1.0.0
|
|
1263
|
+
*/
|
|
1264
|
+
export interface SafeRefinement<in A, out R = A> {
|
|
1265
|
+
readonly [SafeRefinementId]: (a: A) => R
|
|
1266
|
+
}
|
|
1267
|
+
|
|
1268
|
+
const Fail = Symbol.for("effect/Fail")
|
|
1269
|
+
type Fail = typeof Fail
|
|
1270
|
+
|
|
1271
|
+
/**
|
|
1272
|
+
* @since 1.0.0
|
|
1273
|
+
*/
|
|
1274
|
+
export declare namespace Types {
|
|
1275
|
+
/**
|
|
1276
|
+
* @since 1.0.0
|
|
1277
|
+
*/
|
|
1278
|
+
export type WhenMatch<R, P> =
|
|
1279
|
+
// check for any
|
|
1280
|
+
[0] extends [1 & R] ? ResolvePred<P> :
|
|
1281
|
+
P extends SafeRefinement<infer SP, never> ? SP
|
|
1282
|
+
: P extends Predicate.Refinement<infer _R, infer RP>
|
|
1283
|
+
// try to narrow refinement
|
|
1284
|
+
? [Extract<R, RP>] extends [infer X] ? [X] extends [never]
|
|
1285
|
+
// fallback to original refinement
|
|
1286
|
+
? RP
|
|
1287
|
+
: X
|
|
1288
|
+
: never
|
|
1289
|
+
: P extends PredicateA<infer PP> ? PP
|
|
1290
|
+
: ExtractMatch<R, P>
|
|
1291
|
+
|
|
1292
|
+
/**
|
|
1293
|
+
* @since 1.0.0
|
|
1294
|
+
*/
|
|
1295
|
+
export type NotMatch<R, P> = Exclude<R, ExtractMatch<R, PForNotMatch<P>>>
|
|
1296
|
+
|
|
1297
|
+
type PForNotMatch<P> = [ToInvertedRefinement<P>] extends [infer X] ? X
|
|
1298
|
+
: never
|
|
1299
|
+
|
|
1300
|
+
/**
|
|
1301
|
+
* @since 1.0.0
|
|
1302
|
+
*/
|
|
1303
|
+
export type PForMatch<P> = [ResolvePred<P>] extends [infer X] ? X
|
|
1304
|
+
: never
|
|
1305
|
+
|
|
1306
|
+
/**
|
|
1307
|
+
* @since 1.0.0
|
|
1308
|
+
*/
|
|
1309
|
+
export type PForExclude<P> = [SafeRefinementR<ToSafeRefinement<P>>] extends [infer X] ? X
|
|
1310
|
+
: never
|
|
1311
|
+
|
|
1312
|
+
// utilities
|
|
1313
|
+
type PredicateA<A> = Predicate.Predicate<A> | Predicate.Refinement<A, A>
|
|
1314
|
+
|
|
1315
|
+
type SafeRefinementR<A> = A extends never ? never
|
|
1316
|
+
: A extends SafeRefinement<infer _, infer R> ? R
|
|
1317
|
+
: A extends Function ? A
|
|
1318
|
+
: A extends Record<string, any> ? { [K in keyof A]: SafeRefinementR<A[K]> }
|
|
1319
|
+
: A
|
|
1320
|
+
|
|
1321
|
+
type ResolvePred<A, Input = any> = A extends never ? never
|
|
1322
|
+
: A extends SafeRefinement<infer _A, infer _R> ? _A
|
|
1323
|
+
: A extends Predicate.Refinement<Input, infer P> ? P
|
|
1324
|
+
: A extends Predicate.Predicate<infer P> ? P
|
|
1325
|
+
: A extends Record<string, any> ? { [K in keyof A]: ResolvePred<A[K]> }
|
|
1326
|
+
: A
|
|
1327
|
+
|
|
1328
|
+
type ToSafeRefinement<A> = A extends never ? never
|
|
1329
|
+
: A extends Predicate.Refinement<any, infer P> ? SafeRefinement<P, P>
|
|
1330
|
+
: A extends Predicate.Predicate<infer P> ? SafeRefinement<P, never>
|
|
1331
|
+
: A extends SafeRefinement<any> ? A
|
|
1332
|
+
: A extends Record<string, any> ? { [K in keyof A]: ToSafeRefinement<A[K]> }
|
|
1333
|
+
: NonLiteralsTo<A, never>
|
|
1334
|
+
|
|
1335
|
+
type ToInvertedRefinement<A> = A extends never ? never
|
|
1336
|
+
: A extends Predicate.Refinement<any, infer P> ? SafeRefinement<P>
|
|
1337
|
+
: A extends Predicate.Predicate<infer _P> ? SafeRefinement<never>
|
|
1338
|
+
: A extends SafeRefinement<infer _A, infer _R> ? SafeRefinement<_R>
|
|
1339
|
+
: A extends Record<string, any> ? { [K in keyof A]: ToInvertedRefinement<A[K]> }
|
|
1340
|
+
: NonLiteralsTo<A, never>
|
|
1341
|
+
|
|
1342
|
+
type NonLiteralsTo<A, T> = [A] extends [string | number | boolean | bigint] ? [string] extends [A] ? T
|
|
1343
|
+
: [number] extends [A] ? T
|
|
1344
|
+
: [boolean] extends [A] ? T
|
|
1345
|
+
: [bigint] extends [A] ? T
|
|
1346
|
+
: A
|
|
1347
|
+
: A
|
|
1348
|
+
|
|
1349
|
+
/**
|
|
1350
|
+
* @since 1.0.0
|
|
1351
|
+
*/
|
|
1352
|
+
export type PatternBase<A> = A extends ReadonlyArray<infer _T> ? ReadonlyArray<any> | PatternPrimitive<A>
|
|
1353
|
+
: A extends Record<string, any> ? Partial<
|
|
1354
|
+
{ [K in keyof A]: PatternPrimitive<A[K] & {}> | PatternBase<A[K] & {}> }
|
|
1355
|
+
>
|
|
1356
|
+
: never
|
|
1357
|
+
|
|
1358
|
+
/**
|
|
1359
|
+
* @since 1.0.0
|
|
1360
|
+
*/
|
|
1361
|
+
export type PatternPrimitive<A> = PredicateA<A> | A | SafeRefinement<any>
|
|
1362
|
+
|
|
1363
|
+
/**
|
|
1364
|
+
* @since 1.0.0
|
|
1365
|
+
*/
|
|
1366
|
+
export interface Without<out X> {
|
|
1367
|
+
readonly _tag: "Without"
|
|
1368
|
+
readonly _X: X
|
|
1369
|
+
}
|
|
1370
|
+
|
|
1371
|
+
/**
|
|
1372
|
+
* @since 1.0.0
|
|
1373
|
+
*/
|
|
1374
|
+
export interface Only<out X> {
|
|
1375
|
+
readonly _tag: "Only"
|
|
1376
|
+
readonly _X: X
|
|
1377
|
+
}
|
|
1378
|
+
|
|
1379
|
+
/**
|
|
1380
|
+
* @since 1.0.0
|
|
1381
|
+
*/
|
|
1382
|
+
export type AddWithout<A, X> = [A] extends [Without<infer WX>] ? Without<X | WX>
|
|
1383
|
+
: [A] extends [Only<infer OX>] ? Only<Exclude<OX, X>>
|
|
1384
|
+
: never
|
|
1385
|
+
|
|
1386
|
+
/**
|
|
1387
|
+
* @since 1.0.0
|
|
1388
|
+
*/
|
|
1389
|
+
export type AddOnly<A, X> = [A] extends [Without<infer WX>] ? [X] extends [WX] ? never
|
|
1390
|
+
: Only<X>
|
|
1391
|
+
: [A] extends [Only<infer OX>] ? [X] extends [OX] ? Only<X>
|
|
1392
|
+
: never
|
|
1393
|
+
: never
|
|
1394
|
+
|
|
1395
|
+
/**
|
|
1396
|
+
* @since 1.0.0
|
|
1397
|
+
*/
|
|
1398
|
+
export type ApplyFilters<I, A> = A extends Only<infer X> ? X
|
|
1399
|
+
: A extends Without<infer X> ? Exclude<I, X>
|
|
1400
|
+
: never
|
|
1401
|
+
|
|
1402
|
+
/**
|
|
1403
|
+
* @since 1.0.0
|
|
1404
|
+
*/
|
|
1405
|
+
export type Tags<D extends string, P> = P extends Record<D, infer X> ? X : never
|
|
1406
|
+
|
|
1407
|
+
/**
|
|
1408
|
+
* @since 1.0.0
|
|
1409
|
+
*/
|
|
1410
|
+
export type ArrayToIntersection<A extends ReadonlyArray<any>> = T.UnionToIntersection<
|
|
1411
|
+
A[number]
|
|
1412
|
+
>
|
|
1413
|
+
|
|
1414
|
+
/**
|
|
1415
|
+
* @since 1.0.0
|
|
1416
|
+
*/
|
|
1417
|
+
export type ExtractMatch<I, P> = [ExtractAndNarrow<I, P>] extends [infer EI] ? EI
|
|
1418
|
+
: never
|
|
1419
|
+
|
|
1420
|
+
type Replace<A, B> = A extends Function ? A
|
|
1421
|
+
: A extends Record<string | number, any> ? { [K in keyof A]: K extends keyof B ? Replace<A[K], B[K]> : A[K] }
|
|
1422
|
+
: [B] extends [A] ? B
|
|
1423
|
+
: A
|
|
1424
|
+
|
|
1425
|
+
type MaybeReplace<I, P> = [P] extends [I] ? P
|
|
1426
|
+
: [I] extends [P] ? Replace<I, P>
|
|
1427
|
+
: Fail
|
|
1428
|
+
|
|
1429
|
+
type BuiltInObjects =
|
|
1430
|
+
| Function
|
|
1431
|
+
| Date
|
|
1432
|
+
| RegExp
|
|
1433
|
+
| Generator
|
|
1434
|
+
| { readonly [Symbol.toStringTag]: string }
|
|
1435
|
+
|
|
1436
|
+
type IsPlainObject<T> = T extends BuiltInObjects ? false
|
|
1437
|
+
: T extends Record<string, any> ? true
|
|
1438
|
+
: false
|
|
1439
|
+
|
|
1440
|
+
type Simplify<A> = { [K in keyof A]: A[K] } & {}
|
|
1441
|
+
|
|
1442
|
+
type ExtractAndNarrow<Input, P> = P extends Predicate.Refinement<infer _In, infer _Out> ?
|
|
1443
|
+
_Out extends Input ? Extract<_Out, Input>
|
|
1444
|
+
: Extract<Input, _Out> :
|
|
1445
|
+
P extends SafeRefinement<infer _In, infer _R> ? [0] extends [1 & _R] ? Input
|
|
1446
|
+
: _In extends Input ? Extract<_In, Input>
|
|
1447
|
+
: Extract<Input, _In>
|
|
1448
|
+
: P extends Predicate.Predicate<infer _In> ? Extract<Input, _In>
|
|
1449
|
+
: Input extends infer I ? Exclude<
|
|
1450
|
+
I extends ReadonlyArray<any> ? P extends ReadonlyArray<any> ? {
|
|
1451
|
+
readonly [K in keyof I]: K extends keyof P ? ExtractAndNarrow<I[K], P[K]>
|
|
1452
|
+
: I[K]
|
|
1453
|
+
} extends infer R ? Fail extends R[keyof R] ? never
|
|
1454
|
+
: R
|
|
1455
|
+
: never
|
|
1456
|
+
: never
|
|
1457
|
+
: IsPlainObject<I> extends true ? string extends keyof I ? I extends P ? I
|
|
1458
|
+
: never
|
|
1459
|
+
: symbol extends keyof I ? I extends P ? I
|
|
1460
|
+
: never
|
|
1461
|
+
: Simplify<
|
|
1462
|
+
& { [RK in Extract<keyof I, keyof P>]-?: ExtractAndNarrow<I[RK], P[RK]> }
|
|
1463
|
+
& Omit<I, keyof P>
|
|
1464
|
+
> extends infer R ? keyof P extends NonFailKeys<R> ? R
|
|
1465
|
+
: never
|
|
1466
|
+
: never
|
|
1467
|
+
: MaybeReplace<I, P> extends infer R ? [I] extends [R] ? I
|
|
1468
|
+
: R
|
|
1469
|
+
: never,
|
|
1470
|
+
Fail
|
|
1471
|
+
> :
|
|
1472
|
+
never
|
|
1473
|
+
|
|
1474
|
+
type NonFailKeys<A> = keyof A & {} extends infer K ? K extends keyof A ? A[K] extends Fail ? never : K
|
|
1475
|
+
: never :
|
|
1476
|
+
never
|
|
1477
|
+
}
|