@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/SchemaAST.ts
ADDED
|
@@ -0,0 +1,3043 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @since 3.10.0
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import * as Arr from "./Array.js"
|
|
6
|
+
import type { Effect } from "./Effect.js"
|
|
7
|
+
import type { Equivalence } from "./Equivalence.js"
|
|
8
|
+
import { dual, identity } from "./Function.js"
|
|
9
|
+
import { globalValue } from "./GlobalValue.js"
|
|
10
|
+
import * as Inspectable from "./Inspectable.js"
|
|
11
|
+
import * as errors_ from "./internal/schema/errors.js"
|
|
12
|
+
import * as util_ from "./internal/schema/util.js"
|
|
13
|
+
import * as Number from "./Number.js"
|
|
14
|
+
import * as Option from "./Option.js"
|
|
15
|
+
import * as Order from "./Order.js"
|
|
16
|
+
import type { ParseIssue } from "./ParseResult.js"
|
|
17
|
+
import * as Predicate from "./Predicate.js"
|
|
18
|
+
import * as regexp from "./RegExp.js"
|
|
19
|
+
import type { Concurrency } from "./Types.js"
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* @category model
|
|
23
|
+
* @since 3.10.0
|
|
24
|
+
*/
|
|
25
|
+
export type AST =
|
|
26
|
+
| Declaration
|
|
27
|
+
| Literal
|
|
28
|
+
| UniqueSymbol
|
|
29
|
+
| UndefinedKeyword
|
|
30
|
+
| VoidKeyword
|
|
31
|
+
| NeverKeyword
|
|
32
|
+
| UnknownKeyword
|
|
33
|
+
| AnyKeyword
|
|
34
|
+
| StringKeyword
|
|
35
|
+
| NumberKeyword
|
|
36
|
+
| BooleanKeyword
|
|
37
|
+
| BigIntKeyword
|
|
38
|
+
| SymbolKeyword
|
|
39
|
+
| ObjectKeyword
|
|
40
|
+
| Enums
|
|
41
|
+
| TemplateLiteral
|
|
42
|
+
// possible transformations
|
|
43
|
+
| Refinement
|
|
44
|
+
| TupleType
|
|
45
|
+
| TypeLiteral
|
|
46
|
+
| Union
|
|
47
|
+
| Suspend
|
|
48
|
+
// transformations
|
|
49
|
+
| Transformation
|
|
50
|
+
|
|
51
|
+
// -------------------------------------------------------------------------------------
|
|
52
|
+
// annotations
|
|
53
|
+
// -------------------------------------------------------------------------------------
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* @category annotations
|
|
57
|
+
* @since 3.19.0
|
|
58
|
+
* @experimental
|
|
59
|
+
*/
|
|
60
|
+
export type TypeConstructorAnnotation = {
|
|
61
|
+
readonly _tag: string
|
|
62
|
+
[key: PropertyKey]: unknown
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* @category annotations
|
|
67
|
+
* @since 3.19.0
|
|
68
|
+
* @experimental
|
|
69
|
+
*/
|
|
70
|
+
export const TypeConstructorAnnotationId: unique symbol = Symbol.for("effect/annotation/TypeConstructor")
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* @category annotations
|
|
74
|
+
* @since 3.10.0
|
|
75
|
+
*/
|
|
76
|
+
export type BrandAnnotation = Arr.NonEmptyReadonlyArray<string | symbol>
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* @category annotations
|
|
80
|
+
* @since 3.10.0
|
|
81
|
+
*/
|
|
82
|
+
export const BrandAnnotationId: unique symbol = Symbol.for("effect/annotation/Brand")
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* @category annotations
|
|
86
|
+
* @since 3.10.0
|
|
87
|
+
*/
|
|
88
|
+
export type SchemaIdAnnotation = string | symbol
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* @category annotations
|
|
92
|
+
* @since 3.10.0
|
|
93
|
+
*/
|
|
94
|
+
export const SchemaIdAnnotationId: unique symbol = Symbol.for("effect/annotation/SchemaId")
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* @category annotations
|
|
98
|
+
* @since 3.10.0
|
|
99
|
+
*/
|
|
100
|
+
export type MessageAnnotation = (issue: ParseIssue) => string | Effect<string> | {
|
|
101
|
+
readonly message: string | Effect<string>
|
|
102
|
+
readonly override: boolean
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* @category annotations
|
|
107
|
+
* @since 3.10.0
|
|
108
|
+
*/
|
|
109
|
+
export const MessageAnnotationId: unique symbol = Symbol.for("effect/annotation/Message")
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* @category annotations
|
|
113
|
+
* @since 3.10.0
|
|
114
|
+
*/
|
|
115
|
+
export type MissingMessageAnnotation = () => string | Effect<string>
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* @category annotations
|
|
119
|
+
* @since 3.10.0
|
|
120
|
+
*/
|
|
121
|
+
export const MissingMessageAnnotationId: unique symbol = Symbol.for("effect/annotation/MissingMessage")
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* @category annotations
|
|
125
|
+
* @since 3.10.0
|
|
126
|
+
*/
|
|
127
|
+
export type IdentifierAnnotation = string
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* @category annotations
|
|
131
|
+
* @since 3.10.0
|
|
132
|
+
*/
|
|
133
|
+
export const IdentifierAnnotationId: unique symbol = Symbol.for("effect/annotation/Identifier")
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* @category annotations
|
|
137
|
+
* @since 3.10.0
|
|
138
|
+
*/
|
|
139
|
+
export type TitleAnnotation = string
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* @category annotations
|
|
143
|
+
* @since 3.10.0
|
|
144
|
+
*/
|
|
145
|
+
export const TitleAnnotationId: unique symbol = Symbol.for("effect/annotation/Title")
|
|
146
|
+
|
|
147
|
+
/** @internal */
|
|
148
|
+
export const AutoTitleAnnotationId: unique symbol = Symbol.for("effect/annotation/AutoTitle")
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* @category annotations
|
|
152
|
+
* @since 3.10.0
|
|
153
|
+
*/
|
|
154
|
+
export type DescriptionAnnotation = string
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* @category annotations
|
|
158
|
+
* @since 3.10.0
|
|
159
|
+
*/
|
|
160
|
+
export const DescriptionAnnotationId: unique symbol = Symbol.for("effect/annotation/Description")
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* @category annotations
|
|
164
|
+
* @since 3.10.0
|
|
165
|
+
*/
|
|
166
|
+
export type ExamplesAnnotation<A> = Arr.NonEmptyReadonlyArray<A>
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
* @category annotations
|
|
170
|
+
* @since 3.10.0
|
|
171
|
+
*/
|
|
172
|
+
export const ExamplesAnnotationId: unique symbol = Symbol.for("effect/annotation/Examples")
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* @category annotations
|
|
176
|
+
* @since 3.10.0
|
|
177
|
+
*/
|
|
178
|
+
export type DefaultAnnotation<A> = A
|
|
179
|
+
|
|
180
|
+
/**
|
|
181
|
+
* @category annotations
|
|
182
|
+
* @since 3.10.0
|
|
183
|
+
*/
|
|
184
|
+
export const DefaultAnnotationId: unique symbol = Symbol.for("effect/annotation/Default")
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
* @category annotations
|
|
188
|
+
* @since 3.10.0
|
|
189
|
+
*/
|
|
190
|
+
export type JSONSchemaAnnotation = object
|
|
191
|
+
|
|
192
|
+
/**
|
|
193
|
+
* @category annotations
|
|
194
|
+
* @since 3.10.0
|
|
195
|
+
*/
|
|
196
|
+
export const JSONSchemaAnnotationId: unique symbol = Symbol.for("effect/annotation/JSONSchema")
|
|
197
|
+
|
|
198
|
+
/**
|
|
199
|
+
* @category annotations
|
|
200
|
+
* @since 3.10.0
|
|
201
|
+
*/
|
|
202
|
+
export const ArbitraryAnnotationId: unique symbol = Symbol.for("effect/annotation/Arbitrary")
|
|
203
|
+
|
|
204
|
+
/**
|
|
205
|
+
* @category annotations
|
|
206
|
+
* @since 3.10.0
|
|
207
|
+
*/
|
|
208
|
+
export const PrettyAnnotationId: unique symbol = Symbol.for("effect/annotation/Pretty")
|
|
209
|
+
|
|
210
|
+
/**
|
|
211
|
+
* @category annotations
|
|
212
|
+
* @since 3.10.0
|
|
213
|
+
*/
|
|
214
|
+
export type EquivalenceAnnotation<A, TypeParameters extends ReadonlyArray<any> = readonly []> = (
|
|
215
|
+
...equivalences: { readonly [K in keyof TypeParameters]: Equivalence<TypeParameters[K]> }
|
|
216
|
+
) => Equivalence<A>
|
|
217
|
+
|
|
218
|
+
/**
|
|
219
|
+
* @category annotations
|
|
220
|
+
* @since 3.10.0
|
|
221
|
+
*/
|
|
222
|
+
export const EquivalenceAnnotationId: unique symbol = Symbol.for("effect/annotation/Equivalence")
|
|
223
|
+
|
|
224
|
+
/**
|
|
225
|
+
* @category annotations
|
|
226
|
+
* @since 3.10.0
|
|
227
|
+
*/
|
|
228
|
+
export type DocumentationAnnotation = string
|
|
229
|
+
|
|
230
|
+
/**
|
|
231
|
+
* @category annotations
|
|
232
|
+
* @since 3.10.0
|
|
233
|
+
*/
|
|
234
|
+
export const DocumentationAnnotationId: unique symbol = Symbol.for("effect/annotation/Documentation")
|
|
235
|
+
|
|
236
|
+
/**
|
|
237
|
+
* @category annotations
|
|
238
|
+
* @since 3.10.0
|
|
239
|
+
*/
|
|
240
|
+
export type ConcurrencyAnnotation = Concurrency | undefined
|
|
241
|
+
|
|
242
|
+
/**
|
|
243
|
+
* @category annotations
|
|
244
|
+
* @since 3.10.0
|
|
245
|
+
*/
|
|
246
|
+
export const ConcurrencyAnnotationId: unique symbol = Symbol.for("effect/annotation/Concurrency")
|
|
247
|
+
|
|
248
|
+
/**
|
|
249
|
+
* @category annotations
|
|
250
|
+
* @since 3.10.0
|
|
251
|
+
*/
|
|
252
|
+
export type BatchingAnnotation = boolean | "inherit" | undefined
|
|
253
|
+
|
|
254
|
+
/**
|
|
255
|
+
* @category annotations
|
|
256
|
+
* @since 3.10.0
|
|
257
|
+
*/
|
|
258
|
+
export const BatchingAnnotationId: unique symbol = Symbol.for("effect/annotation/Batching")
|
|
259
|
+
|
|
260
|
+
/**
|
|
261
|
+
* @category annotations
|
|
262
|
+
* @since 3.10.0
|
|
263
|
+
*/
|
|
264
|
+
export type ParseIssueTitleAnnotation = (issue: ParseIssue) => string | undefined
|
|
265
|
+
|
|
266
|
+
/**
|
|
267
|
+
* @category annotations
|
|
268
|
+
* @since 3.10.0
|
|
269
|
+
*/
|
|
270
|
+
export const ParseIssueTitleAnnotationId: unique symbol = Symbol.for("effect/annotation/ParseIssueTitle")
|
|
271
|
+
|
|
272
|
+
/**
|
|
273
|
+
* @category annotations
|
|
274
|
+
* @since 3.10.0
|
|
275
|
+
*/
|
|
276
|
+
export const ParseOptionsAnnotationId: unique symbol = Symbol.for("effect/annotation/ParseOptions")
|
|
277
|
+
|
|
278
|
+
/**
|
|
279
|
+
* @category annotations
|
|
280
|
+
* @since 3.10.0
|
|
281
|
+
*/
|
|
282
|
+
export type DecodingFallbackAnnotation<A> = (issue: ParseIssue) => Effect<A, ParseIssue>
|
|
283
|
+
|
|
284
|
+
/**
|
|
285
|
+
* @category annotations
|
|
286
|
+
* @since 3.10.0
|
|
287
|
+
*/
|
|
288
|
+
export const DecodingFallbackAnnotationId: unique symbol = Symbol.for("effect/annotation/DecodingFallback")
|
|
289
|
+
|
|
290
|
+
/**
|
|
291
|
+
* @category annotations
|
|
292
|
+
* @since 3.10.0
|
|
293
|
+
*/
|
|
294
|
+
export const SurrogateAnnotationId: unique symbol = Symbol.for("effect/annotation/Surrogate")
|
|
295
|
+
|
|
296
|
+
/**
|
|
297
|
+
* @category annotations
|
|
298
|
+
* @since 3.10.0
|
|
299
|
+
*/
|
|
300
|
+
export type SurrogateAnnotation = AST
|
|
301
|
+
|
|
302
|
+
/** @internal */
|
|
303
|
+
export const StableFilterAnnotationId: unique symbol = Symbol.for("effect/annotation/StableFilter")
|
|
304
|
+
|
|
305
|
+
/**
|
|
306
|
+
* A stable filter consistently applies fixed validation rules, such as
|
|
307
|
+
* 'minItems', 'maxItems', and 'itemsCount', to ensure array length complies
|
|
308
|
+
* with set criteria regardless of the input data's content.
|
|
309
|
+
*
|
|
310
|
+
* @internal
|
|
311
|
+
*/
|
|
312
|
+
export type StableFilterAnnotation = boolean
|
|
313
|
+
|
|
314
|
+
/**
|
|
315
|
+
* @category annotations
|
|
316
|
+
* @since 3.10.0
|
|
317
|
+
*/
|
|
318
|
+
export interface Annotations {
|
|
319
|
+
readonly [_: string]: unknown
|
|
320
|
+
readonly [_: symbol]: unknown
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
/**
|
|
324
|
+
* @category annotations
|
|
325
|
+
* @since 3.10.0
|
|
326
|
+
*/
|
|
327
|
+
export interface Annotated {
|
|
328
|
+
readonly annotations: Annotations
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
/**
|
|
332
|
+
* @category annotations
|
|
333
|
+
* @since 3.10.0
|
|
334
|
+
*/
|
|
335
|
+
export const getAnnotation: {
|
|
336
|
+
<A>(key: symbol): (annotated: Annotated) => Option.Option<A>
|
|
337
|
+
<A>(annotated: Annotated, key: symbol): Option.Option<A>
|
|
338
|
+
} = dual(
|
|
339
|
+
2,
|
|
340
|
+
<A>(annotated: Annotated, key: symbol): Option.Option<A> =>
|
|
341
|
+
Object.prototype.hasOwnProperty.call(annotated.annotations, key) ?
|
|
342
|
+
Option.some(annotated.annotations[key] as any) :
|
|
343
|
+
Option.none()
|
|
344
|
+
)
|
|
345
|
+
|
|
346
|
+
/**
|
|
347
|
+
* @category annotations
|
|
348
|
+
* @since 3.19.0
|
|
349
|
+
* @experimental
|
|
350
|
+
*/
|
|
351
|
+
export const getTypeConstructorAnnotation = getAnnotation<TypeConstructorAnnotation>(TypeConstructorAnnotationId)
|
|
352
|
+
|
|
353
|
+
/**
|
|
354
|
+
* @category annotations
|
|
355
|
+
* @since 3.10.0
|
|
356
|
+
*/
|
|
357
|
+
export const getBrandAnnotation = getAnnotation<BrandAnnotation>(BrandAnnotationId)
|
|
358
|
+
|
|
359
|
+
/**
|
|
360
|
+
* @category annotations
|
|
361
|
+
* @since 3.14.2
|
|
362
|
+
*/
|
|
363
|
+
export const getSchemaIdAnnotation = getAnnotation<SchemaIdAnnotation>(SchemaIdAnnotationId)
|
|
364
|
+
|
|
365
|
+
/**
|
|
366
|
+
* @category annotations
|
|
367
|
+
* @since 3.10.0
|
|
368
|
+
*/
|
|
369
|
+
export const getMessageAnnotation = getAnnotation<MessageAnnotation>(MessageAnnotationId)
|
|
370
|
+
|
|
371
|
+
/**
|
|
372
|
+
* @category annotations
|
|
373
|
+
* @since 3.10.0
|
|
374
|
+
*/
|
|
375
|
+
export const getMissingMessageAnnotation = getAnnotation<MissingMessageAnnotation>(MissingMessageAnnotationId)
|
|
376
|
+
|
|
377
|
+
/**
|
|
378
|
+
* @category annotations
|
|
379
|
+
* @since 3.10.0
|
|
380
|
+
*/
|
|
381
|
+
export const getTitleAnnotation = getAnnotation<TitleAnnotation>(TitleAnnotationId)
|
|
382
|
+
|
|
383
|
+
/** @internal */
|
|
384
|
+
export const getAutoTitleAnnotation = getAnnotation<TitleAnnotation>(AutoTitleAnnotationId)
|
|
385
|
+
|
|
386
|
+
/**
|
|
387
|
+
* @category annotations
|
|
388
|
+
* @since 3.10.0
|
|
389
|
+
*/
|
|
390
|
+
export const getIdentifierAnnotation = getAnnotation<IdentifierAnnotation>(IdentifierAnnotationId)
|
|
391
|
+
|
|
392
|
+
/**
|
|
393
|
+
* @category annotations
|
|
394
|
+
* @since 3.10.0
|
|
395
|
+
*/
|
|
396
|
+
export const getDescriptionAnnotation = getAnnotation<DescriptionAnnotation>(DescriptionAnnotationId)
|
|
397
|
+
|
|
398
|
+
/**
|
|
399
|
+
* @category annotations
|
|
400
|
+
* @since 3.10.0
|
|
401
|
+
*/
|
|
402
|
+
export const getExamplesAnnotation = getAnnotation<ExamplesAnnotation<unknown>>(ExamplesAnnotationId)
|
|
403
|
+
|
|
404
|
+
/**
|
|
405
|
+
* @category annotations
|
|
406
|
+
* @since 3.10.0
|
|
407
|
+
*/
|
|
408
|
+
export const getDefaultAnnotation = getAnnotation<DefaultAnnotation<unknown>>(DefaultAnnotationId)
|
|
409
|
+
|
|
410
|
+
/**
|
|
411
|
+
* @category annotations
|
|
412
|
+
* @since 3.10.0
|
|
413
|
+
*/
|
|
414
|
+
export const getJSONSchemaAnnotation = getAnnotation<JSONSchemaAnnotation>(JSONSchemaAnnotationId)
|
|
415
|
+
|
|
416
|
+
/**
|
|
417
|
+
* @category annotations
|
|
418
|
+
* @since 3.10.0
|
|
419
|
+
*/
|
|
420
|
+
export const getDocumentationAnnotation = getAnnotation<DocumentationAnnotation>(DocumentationAnnotationId)
|
|
421
|
+
|
|
422
|
+
/**
|
|
423
|
+
* @category annotations
|
|
424
|
+
* @since 3.10.0
|
|
425
|
+
*/
|
|
426
|
+
export const getConcurrencyAnnotation = getAnnotation<ConcurrencyAnnotation>(ConcurrencyAnnotationId)
|
|
427
|
+
|
|
428
|
+
/**
|
|
429
|
+
* @category annotations
|
|
430
|
+
* @since 3.10.0
|
|
431
|
+
*/
|
|
432
|
+
export const getBatchingAnnotation = getAnnotation<BatchingAnnotation>(BatchingAnnotationId)
|
|
433
|
+
|
|
434
|
+
/**
|
|
435
|
+
* @category annotations
|
|
436
|
+
* @since 3.10.0
|
|
437
|
+
*/
|
|
438
|
+
export const getParseIssueTitleAnnotation = getAnnotation<ParseIssueTitleAnnotation>(ParseIssueTitleAnnotationId)
|
|
439
|
+
|
|
440
|
+
/**
|
|
441
|
+
* @category annotations
|
|
442
|
+
* @since 3.10.0
|
|
443
|
+
*/
|
|
444
|
+
export const getParseOptionsAnnotation = getAnnotation<ParseOptions>(ParseOptionsAnnotationId)
|
|
445
|
+
|
|
446
|
+
/**
|
|
447
|
+
* @category annotations
|
|
448
|
+
* @since 3.10.0
|
|
449
|
+
*/
|
|
450
|
+
export const getDecodingFallbackAnnotation = getAnnotation<DecodingFallbackAnnotation<unknown>>(
|
|
451
|
+
DecodingFallbackAnnotationId
|
|
452
|
+
)
|
|
453
|
+
|
|
454
|
+
/**
|
|
455
|
+
* @category annotations
|
|
456
|
+
* @since 3.10.0
|
|
457
|
+
*/
|
|
458
|
+
export const getSurrogateAnnotation = getAnnotation<SurrogateAnnotation>(SurrogateAnnotationId)
|
|
459
|
+
|
|
460
|
+
const getStableFilterAnnotation = getAnnotation<StableFilterAnnotation>(StableFilterAnnotationId)
|
|
461
|
+
|
|
462
|
+
/** @internal */
|
|
463
|
+
export const hasStableFilter = (annotated: Annotated) =>
|
|
464
|
+
Option.exists(getStableFilterAnnotation(annotated), (b) => b === true)
|
|
465
|
+
|
|
466
|
+
/**
|
|
467
|
+
* @category annotations
|
|
468
|
+
* @since 3.10.0
|
|
469
|
+
*/
|
|
470
|
+
export const JSONIdentifierAnnotationId: unique symbol = Symbol.for("effect/annotation/JSONIdentifier")
|
|
471
|
+
|
|
472
|
+
/**
|
|
473
|
+
* @category annotations
|
|
474
|
+
* @since 3.10.0
|
|
475
|
+
*/
|
|
476
|
+
export const getJSONIdentifierAnnotation = getAnnotation<IdentifierAnnotation>(JSONIdentifierAnnotationId)
|
|
477
|
+
|
|
478
|
+
/**
|
|
479
|
+
* @category annotations
|
|
480
|
+
* @since 3.10.0
|
|
481
|
+
*/
|
|
482
|
+
export const getJSONIdentifier = (annotated: Annotated) =>
|
|
483
|
+
Option.orElse(getJSONIdentifierAnnotation(annotated), () => getIdentifierAnnotation(annotated))
|
|
484
|
+
|
|
485
|
+
// -------------------------------------------------------------------------------------
|
|
486
|
+
// schema ids
|
|
487
|
+
// -------------------------------------------------------------------------------------
|
|
488
|
+
|
|
489
|
+
/**
|
|
490
|
+
* @category schema id
|
|
491
|
+
* @since 3.10.0
|
|
492
|
+
*/
|
|
493
|
+
export const ParseJsonSchemaId: unique symbol = Symbol.for("effect/schema/ParseJson")
|
|
494
|
+
|
|
495
|
+
/**
|
|
496
|
+
* @category model
|
|
497
|
+
* @since 3.10.0
|
|
498
|
+
*/
|
|
499
|
+
export class Declaration implements Annotated {
|
|
500
|
+
/**
|
|
501
|
+
* @since 3.10.0
|
|
502
|
+
*/
|
|
503
|
+
readonly _tag = "Declaration"
|
|
504
|
+
constructor(
|
|
505
|
+
readonly typeParameters: ReadonlyArray<AST>,
|
|
506
|
+
readonly decodeUnknown: (
|
|
507
|
+
...typeParameters: ReadonlyArray<AST>
|
|
508
|
+
) => (input: unknown, options: ParseOptions, self: Declaration) => Effect<any, ParseIssue, any>,
|
|
509
|
+
readonly encodeUnknown: (
|
|
510
|
+
...typeParameters: ReadonlyArray<AST>
|
|
511
|
+
) => (input: unknown, options: ParseOptions, self: Declaration) => Effect<any, ParseIssue, any>,
|
|
512
|
+
readonly annotations: Annotations = {}
|
|
513
|
+
) {}
|
|
514
|
+
/**
|
|
515
|
+
* @since 3.10.0
|
|
516
|
+
*/
|
|
517
|
+
toString() {
|
|
518
|
+
return Option.getOrElse(getExpected(this), () => "<declaration schema>")
|
|
519
|
+
}
|
|
520
|
+
/**
|
|
521
|
+
* @since 3.10.0
|
|
522
|
+
*/
|
|
523
|
+
toJSON(): object {
|
|
524
|
+
return {
|
|
525
|
+
_tag: this._tag,
|
|
526
|
+
typeParameters: this.typeParameters.map((ast) => ast.toJSON()),
|
|
527
|
+
annotations: toJSONAnnotations(this.annotations)
|
|
528
|
+
}
|
|
529
|
+
}
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
const createASTGuard = <T extends AST["_tag"]>(tag: T) => (ast: AST): ast is Extract<AST, { _tag: T }> =>
|
|
533
|
+
ast._tag === tag
|
|
534
|
+
|
|
535
|
+
/**
|
|
536
|
+
* @category guards
|
|
537
|
+
* @since 3.10.0
|
|
538
|
+
*/
|
|
539
|
+
export const isDeclaration: (ast: AST) => ast is Declaration = createASTGuard("Declaration")
|
|
540
|
+
|
|
541
|
+
/**
|
|
542
|
+
* @category model
|
|
543
|
+
* @since 3.10.0
|
|
544
|
+
*/
|
|
545
|
+
export type LiteralValue = string | number | boolean | null | bigint
|
|
546
|
+
|
|
547
|
+
/**
|
|
548
|
+
* @category model
|
|
549
|
+
* @since 3.10.0
|
|
550
|
+
*/
|
|
551
|
+
export class Literal implements Annotated {
|
|
552
|
+
/**
|
|
553
|
+
* @since 3.10.0
|
|
554
|
+
*/
|
|
555
|
+
readonly _tag = "Literal"
|
|
556
|
+
constructor(readonly literal: LiteralValue, readonly annotations: Annotations = {}) {}
|
|
557
|
+
/**
|
|
558
|
+
* @since 3.10.0
|
|
559
|
+
*/
|
|
560
|
+
toString() {
|
|
561
|
+
return Option.getOrElse(getExpected(this), () => Inspectable.formatUnknown(this.literal))
|
|
562
|
+
}
|
|
563
|
+
/**
|
|
564
|
+
* @since 3.10.0
|
|
565
|
+
*/
|
|
566
|
+
toJSON(): object {
|
|
567
|
+
return {
|
|
568
|
+
_tag: this._tag,
|
|
569
|
+
literal: Predicate.isBigInt(this.literal) ? String(this.literal) : this.literal,
|
|
570
|
+
annotations: toJSONAnnotations(this.annotations)
|
|
571
|
+
}
|
|
572
|
+
}
|
|
573
|
+
}
|
|
574
|
+
|
|
575
|
+
/**
|
|
576
|
+
* @category guards
|
|
577
|
+
* @since 3.10.0
|
|
578
|
+
*/
|
|
579
|
+
export const isLiteral: (ast: AST) => ast is Literal = createASTGuard("Literal")
|
|
580
|
+
|
|
581
|
+
const $null = new Literal(null)
|
|
582
|
+
|
|
583
|
+
export {
|
|
584
|
+
/**
|
|
585
|
+
* @category constructors
|
|
586
|
+
* @since 3.10.0
|
|
587
|
+
*/
|
|
588
|
+
$null as null
|
|
589
|
+
}
|
|
590
|
+
|
|
591
|
+
/**
|
|
592
|
+
* @category model
|
|
593
|
+
* @since 3.10.0
|
|
594
|
+
*/
|
|
595
|
+
export class UniqueSymbol implements Annotated {
|
|
596
|
+
/**
|
|
597
|
+
* @since 3.10.0
|
|
598
|
+
*/
|
|
599
|
+
readonly _tag = "UniqueSymbol"
|
|
600
|
+
constructor(readonly symbol: symbol, readonly annotations: Annotations = {}) {}
|
|
601
|
+
/**
|
|
602
|
+
* @since 3.10.0
|
|
603
|
+
*/
|
|
604
|
+
toString() {
|
|
605
|
+
return Option.getOrElse(getExpected(this), () => Inspectable.formatUnknown(this.symbol))
|
|
606
|
+
}
|
|
607
|
+
/**
|
|
608
|
+
* @since 3.10.0
|
|
609
|
+
*/
|
|
610
|
+
toJSON(): object {
|
|
611
|
+
return {
|
|
612
|
+
_tag: this._tag,
|
|
613
|
+
symbol: String(this.symbol),
|
|
614
|
+
annotations: toJSONAnnotations(this.annotations)
|
|
615
|
+
}
|
|
616
|
+
}
|
|
617
|
+
}
|
|
618
|
+
|
|
619
|
+
/**
|
|
620
|
+
* @category guards
|
|
621
|
+
* @since 3.10.0
|
|
622
|
+
*/
|
|
623
|
+
export const isUniqueSymbol: (ast: AST) => ast is UniqueSymbol = createASTGuard("UniqueSymbol")
|
|
624
|
+
|
|
625
|
+
/**
|
|
626
|
+
* @category model
|
|
627
|
+
* @since 3.10.0
|
|
628
|
+
*/
|
|
629
|
+
export class UndefinedKeyword implements Annotated {
|
|
630
|
+
/**
|
|
631
|
+
* @since 3.10.0
|
|
632
|
+
*/
|
|
633
|
+
readonly _tag = "UndefinedKeyword"
|
|
634
|
+
constructor(readonly annotations: Annotations = {}) {}
|
|
635
|
+
/**
|
|
636
|
+
* @since 3.10.0
|
|
637
|
+
*/
|
|
638
|
+
toString() {
|
|
639
|
+
return formatKeyword(this)
|
|
640
|
+
}
|
|
641
|
+
/**
|
|
642
|
+
* @since 3.10.0
|
|
643
|
+
*/
|
|
644
|
+
toJSON(): object {
|
|
645
|
+
return {
|
|
646
|
+
_tag: this._tag,
|
|
647
|
+
annotations: toJSONAnnotations(this.annotations)
|
|
648
|
+
}
|
|
649
|
+
}
|
|
650
|
+
}
|
|
651
|
+
|
|
652
|
+
/**
|
|
653
|
+
* @category constructors
|
|
654
|
+
* @since 3.10.0
|
|
655
|
+
*/
|
|
656
|
+
export const undefinedKeyword: UndefinedKeyword = new UndefinedKeyword({
|
|
657
|
+
[TitleAnnotationId]: "undefined"
|
|
658
|
+
})
|
|
659
|
+
|
|
660
|
+
/**
|
|
661
|
+
* @category guards
|
|
662
|
+
* @since 3.10.0
|
|
663
|
+
*/
|
|
664
|
+
export const isUndefinedKeyword: (ast: AST) => ast is UndefinedKeyword = createASTGuard("UndefinedKeyword")
|
|
665
|
+
|
|
666
|
+
/**
|
|
667
|
+
* @category model
|
|
668
|
+
* @since 3.10.0
|
|
669
|
+
*/
|
|
670
|
+
export class VoidKeyword implements Annotated {
|
|
671
|
+
/**
|
|
672
|
+
* @since 3.10.0
|
|
673
|
+
*/
|
|
674
|
+
readonly _tag = "VoidKeyword"
|
|
675
|
+
constructor(readonly annotations: Annotations = {}) {}
|
|
676
|
+
/**
|
|
677
|
+
* @since 3.10.0
|
|
678
|
+
*/
|
|
679
|
+
toString() {
|
|
680
|
+
return formatKeyword(this)
|
|
681
|
+
}
|
|
682
|
+
/**
|
|
683
|
+
* @since 3.10.0
|
|
684
|
+
*/
|
|
685
|
+
toJSON(): object {
|
|
686
|
+
return {
|
|
687
|
+
_tag: this._tag,
|
|
688
|
+
annotations: toJSONAnnotations(this.annotations)
|
|
689
|
+
}
|
|
690
|
+
}
|
|
691
|
+
}
|
|
692
|
+
|
|
693
|
+
/**
|
|
694
|
+
* @category constructors
|
|
695
|
+
* @since 3.10.0
|
|
696
|
+
*/
|
|
697
|
+
export const voidKeyword: VoidKeyword = new VoidKeyword({
|
|
698
|
+
[TitleAnnotationId]: "void"
|
|
699
|
+
})
|
|
700
|
+
|
|
701
|
+
/**
|
|
702
|
+
* @category guards
|
|
703
|
+
* @since 3.10.0
|
|
704
|
+
*/
|
|
705
|
+
export const isVoidKeyword: (ast: AST) => ast is VoidKeyword = createASTGuard("VoidKeyword")
|
|
706
|
+
|
|
707
|
+
/**
|
|
708
|
+
* @category model
|
|
709
|
+
* @since 3.10.0
|
|
710
|
+
*/
|
|
711
|
+
export class NeverKeyword implements Annotated {
|
|
712
|
+
/**
|
|
713
|
+
* @since 3.10.0
|
|
714
|
+
*/
|
|
715
|
+
readonly _tag = "NeverKeyword"
|
|
716
|
+
constructor(readonly annotations: Annotations = {}) {}
|
|
717
|
+
/**
|
|
718
|
+
* @since 3.10.0
|
|
719
|
+
*/
|
|
720
|
+
toString() {
|
|
721
|
+
return formatKeyword(this)
|
|
722
|
+
}
|
|
723
|
+
/**
|
|
724
|
+
* @since 3.10.0
|
|
725
|
+
*/
|
|
726
|
+
toJSON(): object {
|
|
727
|
+
return {
|
|
728
|
+
_tag: this._tag,
|
|
729
|
+
annotations: toJSONAnnotations(this.annotations)
|
|
730
|
+
}
|
|
731
|
+
}
|
|
732
|
+
}
|
|
733
|
+
|
|
734
|
+
/**
|
|
735
|
+
* @category constructors
|
|
736
|
+
* @since 3.10.0
|
|
737
|
+
*/
|
|
738
|
+
export const neverKeyword: NeverKeyword = new NeverKeyword({
|
|
739
|
+
[TitleAnnotationId]: "never"
|
|
740
|
+
})
|
|
741
|
+
|
|
742
|
+
/**
|
|
743
|
+
* @category guards
|
|
744
|
+
* @since 3.10.0
|
|
745
|
+
*/
|
|
746
|
+
export const isNeverKeyword: (ast: AST) => ast is NeverKeyword = createASTGuard("NeverKeyword")
|
|
747
|
+
|
|
748
|
+
/**
|
|
749
|
+
* @category model
|
|
750
|
+
* @since 3.10.0
|
|
751
|
+
*/
|
|
752
|
+
export class UnknownKeyword implements Annotated {
|
|
753
|
+
/**
|
|
754
|
+
* @since 3.10.0
|
|
755
|
+
*/
|
|
756
|
+
readonly _tag = "UnknownKeyword"
|
|
757
|
+
constructor(readonly annotations: Annotations = {}) {}
|
|
758
|
+
/**
|
|
759
|
+
* @since 3.10.0
|
|
760
|
+
*/
|
|
761
|
+
toString() {
|
|
762
|
+
return formatKeyword(this)
|
|
763
|
+
}
|
|
764
|
+
/**
|
|
765
|
+
* @since 3.10.0
|
|
766
|
+
*/
|
|
767
|
+
toJSON(): object {
|
|
768
|
+
return {
|
|
769
|
+
_tag: this._tag,
|
|
770
|
+
annotations: toJSONAnnotations(this.annotations)
|
|
771
|
+
}
|
|
772
|
+
}
|
|
773
|
+
}
|
|
774
|
+
|
|
775
|
+
/**
|
|
776
|
+
* @category constructors
|
|
777
|
+
* @since 3.10.0
|
|
778
|
+
*/
|
|
779
|
+
export const unknownKeyword: UnknownKeyword = new UnknownKeyword({
|
|
780
|
+
[TitleAnnotationId]: "unknown"
|
|
781
|
+
})
|
|
782
|
+
|
|
783
|
+
/**
|
|
784
|
+
* @category guards
|
|
785
|
+
* @since 3.10.0
|
|
786
|
+
*/
|
|
787
|
+
export const isUnknownKeyword: (ast: AST) => ast is UnknownKeyword = createASTGuard("UnknownKeyword")
|
|
788
|
+
|
|
789
|
+
/**
|
|
790
|
+
* @category model
|
|
791
|
+
* @since 3.10.0
|
|
792
|
+
*/
|
|
793
|
+
export class AnyKeyword implements Annotated {
|
|
794
|
+
/**
|
|
795
|
+
* @since 3.10.0
|
|
796
|
+
*/
|
|
797
|
+
readonly _tag = "AnyKeyword"
|
|
798
|
+
constructor(readonly annotations: Annotations = {}) {}
|
|
799
|
+
/**
|
|
800
|
+
* @since 3.10.0
|
|
801
|
+
*/
|
|
802
|
+
toString() {
|
|
803
|
+
return formatKeyword(this)
|
|
804
|
+
}
|
|
805
|
+
/**
|
|
806
|
+
* @since 3.10.0
|
|
807
|
+
*/
|
|
808
|
+
toJSON(): object {
|
|
809
|
+
return {
|
|
810
|
+
_tag: this._tag,
|
|
811
|
+
annotations: toJSONAnnotations(this.annotations)
|
|
812
|
+
}
|
|
813
|
+
}
|
|
814
|
+
}
|
|
815
|
+
|
|
816
|
+
/**
|
|
817
|
+
* @category constructors
|
|
818
|
+
* @since 3.10.0
|
|
819
|
+
*/
|
|
820
|
+
export const anyKeyword: AnyKeyword = new AnyKeyword({
|
|
821
|
+
[TitleAnnotationId]: "any"
|
|
822
|
+
})
|
|
823
|
+
|
|
824
|
+
/**
|
|
825
|
+
* @category guards
|
|
826
|
+
* @since 3.10.0
|
|
827
|
+
*/
|
|
828
|
+
export const isAnyKeyword: (ast: AST) => ast is AnyKeyword = createASTGuard("AnyKeyword")
|
|
829
|
+
|
|
830
|
+
/**
|
|
831
|
+
* @category model
|
|
832
|
+
* @since 3.10.0
|
|
833
|
+
*/
|
|
834
|
+
export class StringKeyword implements Annotated {
|
|
835
|
+
/**
|
|
836
|
+
* @since 3.10.0
|
|
837
|
+
*/
|
|
838
|
+
readonly _tag = "StringKeyword"
|
|
839
|
+
constructor(readonly annotations: Annotations = {}) {}
|
|
840
|
+
/**
|
|
841
|
+
* @since 3.10.0
|
|
842
|
+
*/
|
|
843
|
+
toString() {
|
|
844
|
+
return formatKeyword(this)
|
|
845
|
+
}
|
|
846
|
+
/**
|
|
847
|
+
* @since 3.10.0
|
|
848
|
+
*/
|
|
849
|
+
toJSON(): object {
|
|
850
|
+
return {
|
|
851
|
+
_tag: this._tag,
|
|
852
|
+
annotations: toJSONAnnotations(this.annotations)
|
|
853
|
+
}
|
|
854
|
+
}
|
|
855
|
+
}
|
|
856
|
+
|
|
857
|
+
/**
|
|
858
|
+
* @category constructors
|
|
859
|
+
* @since 3.10.0
|
|
860
|
+
*/
|
|
861
|
+
export const stringKeyword: StringKeyword = new StringKeyword({
|
|
862
|
+
[TitleAnnotationId]: "string",
|
|
863
|
+
[DescriptionAnnotationId]: "a string"
|
|
864
|
+
})
|
|
865
|
+
|
|
866
|
+
/**
|
|
867
|
+
* @category guards
|
|
868
|
+
* @since 3.10.0
|
|
869
|
+
*/
|
|
870
|
+
export const isStringKeyword: (ast: AST) => ast is StringKeyword = createASTGuard("StringKeyword")
|
|
871
|
+
|
|
872
|
+
/**
|
|
873
|
+
* @category model
|
|
874
|
+
* @since 3.10.0
|
|
875
|
+
*/
|
|
876
|
+
export class NumberKeyword implements Annotated {
|
|
877
|
+
/**
|
|
878
|
+
* @since 3.10.0
|
|
879
|
+
*/
|
|
880
|
+
readonly _tag = "NumberKeyword"
|
|
881
|
+
constructor(readonly annotations: Annotations = {}) {}
|
|
882
|
+
/**
|
|
883
|
+
* @since 3.10.0
|
|
884
|
+
*/
|
|
885
|
+
toString() {
|
|
886
|
+
return formatKeyword(this)
|
|
887
|
+
}
|
|
888
|
+
/**
|
|
889
|
+
* @since 3.10.0
|
|
890
|
+
*/
|
|
891
|
+
toJSON(): object {
|
|
892
|
+
return {
|
|
893
|
+
_tag: this._tag,
|
|
894
|
+
annotations: toJSONAnnotations(this.annotations)
|
|
895
|
+
}
|
|
896
|
+
}
|
|
897
|
+
}
|
|
898
|
+
|
|
899
|
+
/**
|
|
900
|
+
* @category constructors
|
|
901
|
+
* @since 3.10.0
|
|
902
|
+
*/
|
|
903
|
+
export const numberKeyword: NumberKeyword = new NumberKeyword({
|
|
904
|
+
[TitleAnnotationId]: "number",
|
|
905
|
+
[DescriptionAnnotationId]: "a number"
|
|
906
|
+
})
|
|
907
|
+
|
|
908
|
+
/**
|
|
909
|
+
* @category guards
|
|
910
|
+
* @since 3.10.0
|
|
911
|
+
*/
|
|
912
|
+
export const isNumberKeyword: (ast: AST) => ast is NumberKeyword = createASTGuard("NumberKeyword")
|
|
913
|
+
|
|
914
|
+
/**
|
|
915
|
+
* @category model
|
|
916
|
+
* @since 3.10.0
|
|
917
|
+
*/
|
|
918
|
+
export class BooleanKeyword implements Annotated {
|
|
919
|
+
/**
|
|
920
|
+
* @since 3.10.0
|
|
921
|
+
*/
|
|
922
|
+
readonly _tag = "BooleanKeyword"
|
|
923
|
+
constructor(readonly annotations: Annotations = {}) {}
|
|
924
|
+
/**
|
|
925
|
+
* @since 3.10.0
|
|
926
|
+
*/
|
|
927
|
+
toString() {
|
|
928
|
+
return formatKeyword(this)
|
|
929
|
+
}
|
|
930
|
+
/**
|
|
931
|
+
* @since 3.10.0
|
|
932
|
+
*/
|
|
933
|
+
toJSON(): object {
|
|
934
|
+
return {
|
|
935
|
+
_tag: this._tag,
|
|
936
|
+
annotations: toJSONAnnotations(this.annotations)
|
|
937
|
+
}
|
|
938
|
+
}
|
|
939
|
+
}
|
|
940
|
+
|
|
941
|
+
/**
|
|
942
|
+
* @category constructors
|
|
943
|
+
* @since 3.10.0
|
|
944
|
+
*/
|
|
945
|
+
export const booleanKeyword: BooleanKeyword = new BooleanKeyword({
|
|
946
|
+
[TitleAnnotationId]: "boolean",
|
|
947
|
+
[DescriptionAnnotationId]: "a boolean"
|
|
948
|
+
})
|
|
949
|
+
|
|
950
|
+
/**
|
|
951
|
+
* @category guards
|
|
952
|
+
* @since 3.10.0
|
|
953
|
+
*/
|
|
954
|
+
export const isBooleanKeyword: (ast: AST) => ast is BooleanKeyword = createASTGuard("BooleanKeyword")
|
|
955
|
+
|
|
956
|
+
/**
|
|
957
|
+
* @category model
|
|
958
|
+
* @since 3.10.0
|
|
959
|
+
*/
|
|
960
|
+
export class BigIntKeyword implements Annotated {
|
|
961
|
+
/**
|
|
962
|
+
* @since 3.10.0
|
|
963
|
+
*/
|
|
964
|
+
readonly _tag = "BigIntKeyword"
|
|
965
|
+
constructor(readonly annotations: Annotations = {}) {}
|
|
966
|
+
/**
|
|
967
|
+
* @since 3.10.0
|
|
968
|
+
*/
|
|
969
|
+
toString() {
|
|
970
|
+
return formatKeyword(this)
|
|
971
|
+
}
|
|
972
|
+
/**
|
|
973
|
+
* @since 3.10.0
|
|
974
|
+
*/
|
|
975
|
+
toJSON(): object {
|
|
976
|
+
return {
|
|
977
|
+
_tag: this._tag,
|
|
978
|
+
annotations: toJSONAnnotations(this.annotations)
|
|
979
|
+
}
|
|
980
|
+
}
|
|
981
|
+
}
|
|
982
|
+
|
|
983
|
+
/**
|
|
984
|
+
* @category constructors
|
|
985
|
+
* @since 3.10.0
|
|
986
|
+
*/
|
|
987
|
+
export const bigIntKeyword: BigIntKeyword = new BigIntKeyword({
|
|
988
|
+
[TitleAnnotationId]: "bigint",
|
|
989
|
+
[DescriptionAnnotationId]: "a bigint"
|
|
990
|
+
})
|
|
991
|
+
|
|
992
|
+
/**
|
|
993
|
+
* @category guards
|
|
994
|
+
* @since 3.10.0
|
|
995
|
+
*/
|
|
996
|
+
export const isBigIntKeyword: (ast: AST) => ast is BigIntKeyword = createASTGuard("BigIntKeyword")
|
|
997
|
+
|
|
998
|
+
/**
|
|
999
|
+
* @category model
|
|
1000
|
+
* @since 3.10.0
|
|
1001
|
+
*/
|
|
1002
|
+
export class SymbolKeyword implements Annotated {
|
|
1003
|
+
/**
|
|
1004
|
+
* @since 3.10.0
|
|
1005
|
+
*/
|
|
1006
|
+
readonly _tag = "SymbolKeyword"
|
|
1007
|
+
constructor(readonly annotations: Annotations = {}) {}
|
|
1008
|
+
/**
|
|
1009
|
+
* @since 3.10.0
|
|
1010
|
+
*/
|
|
1011
|
+
toString() {
|
|
1012
|
+
return formatKeyword(this)
|
|
1013
|
+
}
|
|
1014
|
+
/**
|
|
1015
|
+
* @since 3.10.0
|
|
1016
|
+
*/
|
|
1017
|
+
toJSON(): object {
|
|
1018
|
+
return {
|
|
1019
|
+
_tag: this._tag,
|
|
1020
|
+
annotations: toJSONAnnotations(this.annotations)
|
|
1021
|
+
}
|
|
1022
|
+
}
|
|
1023
|
+
}
|
|
1024
|
+
|
|
1025
|
+
/**
|
|
1026
|
+
* @category constructors
|
|
1027
|
+
* @since 3.10.0
|
|
1028
|
+
*/
|
|
1029
|
+
export const symbolKeyword: SymbolKeyword = new SymbolKeyword({
|
|
1030
|
+
[TitleAnnotationId]: "symbol",
|
|
1031
|
+
[DescriptionAnnotationId]: "a symbol"
|
|
1032
|
+
})
|
|
1033
|
+
|
|
1034
|
+
/**
|
|
1035
|
+
* @category guards
|
|
1036
|
+
* @since 3.10.0
|
|
1037
|
+
*/
|
|
1038
|
+
export const isSymbolKeyword: (ast: AST) => ast is SymbolKeyword = createASTGuard("SymbolKeyword")
|
|
1039
|
+
|
|
1040
|
+
/**
|
|
1041
|
+
* @category model
|
|
1042
|
+
* @since 3.10.0
|
|
1043
|
+
*/
|
|
1044
|
+
export class ObjectKeyword implements Annotated {
|
|
1045
|
+
/**
|
|
1046
|
+
* @since 3.10.0
|
|
1047
|
+
*/
|
|
1048
|
+
readonly _tag = "ObjectKeyword"
|
|
1049
|
+
constructor(readonly annotations: Annotations = {}) {}
|
|
1050
|
+
/**
|
|
1051
|
+
* @since 3.10.0
|
|
1052
|
+
*/
|
|
1053
|
+
toString() {
|
|
1054
|
+
return formatKeyword(this)
|
|
1055
|
+
}
|
|
1056
|
+
/**
|
|
1057
|
+
* @since 3.10.0
|
|
1058
|
+
*/
|
|
1059
|
+
toJSON(): object {
|
|
1060
|
+
return {
|
|
1061
|
+
_tag: this._tag,
|
|
1062
|
+
annotations: toJSONAnnotations(this.annotations)
|
|
1063
|
+
}
|
|
1064
|
+
}
|
|
1065
|
+
}
|
|
1066
|
+
|
|
1067
|
+
/**
|
|
1068
|
+
* @category constructors
|
|
1069
|
+
* @since 3.10.0
|
|
1070
|
+
*/
|
|
1071
|
+
export const objectKeyword: ObjectKeyword = new ObjectKeyword({
|
|
1072
|
+
[TitleAnnotationId]: "object",
|
|
1073
|
+
[DescriptionAnnotationId]: "an object in the TypeScript meaning, i.e. the `object` type"
|
|
1074
|
+
})
|
|
1075
|
+
|
|
1076
|
+
/**
|
|
1077
|
+
* @category guards
|
|
1078
|
+
* @since 3.10.0
|
|
1079
|
+
*/
|
|
1080
|
+
export const isObjectKeyword: (ast: AST) => ast is ObjectKeyword = createASTGuard("ObjectKeyword")
|
|
1081
|
+
|
|
1082
|
+
/**
|
|
1083
|
+
* @category model
|
|
1084
|
+
* @since 3.10.0
|
|
1085
|
+
*/
|
|
1086
|
+
export class Enums implements Annotated {
|
|
1087
|
+
/**
|
|
1088
|
+
* @since 3.10.0
|
|
1089
|
+
*/
|
|
1090
|
+
readonly _tag = "Enums"
|
|
1091
|
+
constructor(
|
|
1092
|
+
readonly enums: ReadonlyArray<readonly [string, string | number]>,
|
|
1093
|
+
readonly annotations: Annotations = {}
|
|
1094
|
+
) {}
|
|
1095
|
+
/**
|
|
1096
|
+
* @since 3.10.0
|
|
1097
|
+
*/
|
|
1098
|
+
toString() {
|
|
1099
|
+
return Option.getOrElse(
|
|
1100
|
+
getExpected(this),
|
|
1101
|
+
() => `<enum ${this.enums.length} value(s): ${this.enums.map(([_, value]) => JSON.stringify(value)).join(" | ")}>`
|
|
1102
|
+
)
|
|
1103
|
+
}
|
|
1104
|
+
/**
|
|
1105
|
+
* @since 3.10.0
|
|
1106
|
+
*/
|
|
1107
|
+
toJSON(): object {
|
|
1108
|
+
return {
|
|
1109
|
+
_tag: this._tag,
|
|
1110
|
+
enums: this.enums,
|
|
1111
|
+
annotations: toJSONAnnotations(this.annotations)
|
|
1112
|
+
}
|
|
1113
|
+
}
|
|
1114
|
+
}
|
|
1115
|
+
|
|
1116
|
+
/**
|
|
1117
|
+
* @category guards
|
|
1118
|
+
* @since 3.10.0
|
|
1119
|
+
*/
|
|
1120
|
+
export const isEnums: (ast: AST) => ast is Enums = createASTGuard("Enums")
|
|
1121
|
+
|
|
1122
|
+
type TemplateLiteralSpanBaseType = StringKeyword | NumberKeyword | Literal | TemplateLiteral
|
|
1123
|
+
|
|
1124
|
+
type TemplateLiteralSpanType = TemplateLiteralSpanBaseType | Union<TemplateLiteralSpanType>
|
|
1125
|
+
|
|
1126
|
+
const isTemplateLiteralSpanType = (ast: AST): ast is TemplateLiteralSpanType => {
|
|
1127
|
+
switch (ast._tag) {
|
|
1128
|
+
case "Literal":
|
|
1129
|
+
case "NumberKeyword":
|
|
1130
|
+
case "StringKeyword":
|
|
1131
|
+
case "TemplateLiteral":
|
|
1132
|
+
return true
|
|
1133
|
+
case "Union":
|
|
1134
|
+
return ast.types.every(isTemplateLiteralSpanType)
|
|
1135
|
+
}
|
|
1136
|
+
return false
|
|
1137
|
+
}
|
|
1138
|
+
|
|
1139
|
+
const templateLiteralSpanUnionTypeToString = (type: TemplateLiteralSpanType): string => {
|
|
1140
|
+
switch (type._tag) {
|
|
1141
|
+
case "Literal":
|
|
1142
|
+
return JSON.stringify(String(type.literal))
|
|
1143
|
+
case "StringKeyword":
|
|
1144
|
+
return "string"
|
|
1145
|
+
case "NumberKeyword":
|
|
1146
|
+
return "number"
|
|
1147
|
+
case "TemplateLiteral":
|
|
1148
|
+
return String(type)
|
|
1149
|
+
case "Union":
|
|
1150
|
+
return type.types.map(templateLiteralSpanUnionTypeToString).join(" | ")
|
|
1151
|
+
}
|
|
1152
|
+
}
|
|
1153
|
+
|
|
1154
|
+
const templateLiteralSpanTypeToString = (type: TemplateLiteralSpanType): string => {
|
|
1155
|
+
switch (type._tag) {
|
|
1156
|
+
case "Literal":
|
|
1157
|
+
return String(type.literal)
|
|
1158
|
+
case "StringKeyword":
|
|
1159
|
+
return "${string}"
|
|
1160
|
+
case "NumberKeyword":
|
|
1161
|
+
return "${number}"
|
|
1162
|
+
case "TemplateLiteral":
|
|
1163
|
+
return "${" + String(type) + "}"
|
|
1164
|
+
case "Union":
|
|
1165
|
+
return "${" + type.types.map(templateLiteralSpanUnionTypeToString).join(" | ") + "}"
|
|
1166
|
+
}
|
|
1167
|
+
}
|
|
1168
|
+
|
|
1169
|
+
/**
|
|
1170
|
+
* @category model
|
|
1171
|
+
* @since 3.10.0
|
|
1172
|
+
*/
|
|
1173
|
+
export class TemplateLiteralSpan {
|
|
1174
|
+
/**
|
|
1175
|
+
* @since 3.10.0
|
|
1176
|
+
*/
|
|
1177
|
+
readonly type: TemplateLiteralSpanType
|
|
1178
|
+
constructor(type: AST, readonly literal: string) {
|
|
1179
|
+
if (isTemplateLiteralSpanType(type)) {
|
|
1180
|
+
this.type = type
|
|
1181
|
+
} else {
|
|
1182
|
+
throw new Error(errors_.getSchemaUnsupportedLiteralSpanErrorMessage(type))
|
|
1183
|
+
}
|
|
1184
|
+
}
|
|
1185
|
+
/**
|
|
1186
|
+
* @since 3.10.0
|
|
1187
|
+
*/
|
|
1188
|
+
toString() {
|
|
1189
|
+
return templateLiteralSpanTypeToString(this.type) + this.literal
|
|
1190
|
+
}
|
|
1191
|
+
/**
|
|
1192
|
+
* @since 3.10.0
|
|
1193
|
+
*/
|
|
1194
|
+
toJSON(): object {
|
|
1195
|
+
return {
|
|
1196
|
+
type: this.type.toJSON(),
|
|
1197
|
+
literal: this.literal
|
|
1198
|
+
}
|
|
1199
|
+
}
|
|
1200
|
+
}
|
|
1201
|
+
|
|
1202
|
+
/**
|
|
1203
|
+
* @category model
|
|
1204
|
+
* @since 3.10.0
|
|
1205
|
+
*/
|
|
1206
|
+
export class TemplateLiteral implements Annotated {
|
|
1207
|
+
/**
|
|
1208
|
+
* @since 3.10.0
|
|
1209
|
+
*/
|
|
1210
|
+
readonly _tag = "TemplateLiteral"
|
|
1211
|
+
constructor(
|
|
1212
|
+
readonly head: string,
|
|
1213
|
+
readonly spans: Arr.NonEmptyReadonlyArray<TemplateLiteralSpan>,
|
|
1214
|
+
readonly annotations: Annotations = {}
|
|
1215
|
+
) {}
|
|
1216
|
+
/**
|
|
1217
|
+
* @since 3.10.0
|
|
1218
|
+
*/
|
|
1219
|
+
toString() {
|
|
1220
|
+
return Option.getOrElse(getExpected(this), () => formatTemplateLiteral(this))
|
|
1221
|
+
}
|
|
1222
|
+
/**
|
|
1223
|
+
* @since 3.10.0
|
|
1224
|
+
*/
|
|
1225
|
+
toJSON(): object {
|
|
1226
|
+
return {
|
|
1227
|
+
_tag: this._tag,
|
|
1228
|
+
head: this.head,
|
|
1229
|
+
spans: this.spans.map((span) => span.toJSON()),
|
|
1230
|
+
annotations: toJSONAnnotations(this.annotations)
|
|
1231
|
+
}
|
|
1232
|
+
}
|
|
1233
|
+
}
|
|
1234
|
+
|
|
1235
|
+
const formatTemplateLiteral = (ast: TemplateLiteral): string =>
|
|
1236
|
+
"`" + ast.head + ast.spans.map(String).join("") +
|
|
1237
|
+
"`"
|
|
1238
|
+
|
|
1239
|
+
/**
|
|
1240
|
+
* @category guards
|
|
1241
|
+
* @since 3.10.0
|
|
1242
|
+
*/
|
|
1243
|
+
export const isTemplateLiteral: (ast: AST) => ast is TemplateLiteral = createASTGuard("TemplateLiteral")
|
|
1244
|
+
|
|
1245
|
+
/**
|
|
1246
|
+
* @category model
|
|
1247
|
+
* @since 3.10.0
|
|
1248
|
+
*/
|
|
1249
|
+
export class Type implements Annotated {
|
|
1250
|
+
constructor(
|
|
1251
|
+
readonly type: AST,
|
|
1252
|
+
readonly annotations: Annotations = {}
|
|
1253
|
+
) {}
|
|
1254
|
+
/**
|
|
1255
|
+
* @since 3.10.0
|
|
1256
|
+
*/
|
|
1257
|
+
toJSON(): object {
|
|
1258
|
+
return {
|
|
1259
|
+
type: this.type.toJSON(),
|
|
1260
|
+
annotations: toJSONAnnotations(this.annotations)
|
|
1261
|
+
}
|
|
1262
|
+
}
|
|
1263
|
+
/**
|
|
1264
|
+
* @since 3.10.0
|
|
1265
|
+
*/
|
|
1266
|
+
toString() {
|
|
1267
|
+
return String(this.type)
|
|
1268
|
+
}
|
|
1269
|
+
}
|
|
1270
|
+
|
|
1271
|
+
/**
|
|
1272
|
+
* @category model
|
|
1273
|
+
* @since 3.10.0
|
|
1274
|
+
*/
|
|
1275
|
+
export class OptionalType extends Type {
|
|
1276
|
+
constructor(
|
|
1277
|
+
type: AST,
|
|
1278
|
+
readonly isOptional: boolean,
|
|
1279
|
+
annotations: Annotations = {}
|
|
1280
|
+
) {
|
|
1281
|
+
super(type, annotations)
|
|
1282
|
+
}
|
|
1283
|
+
/**
|
|
1284
|
+
* @since 3.10.0
|
|
1285
|
+
*/
|
|
1286
|
+
toJSON(): object {
|
|
1287
|
+
return {
|
|
1288
|
+
type: this.type.toJSON(),
|
|
1289
|
+
isOptional: this.isOptional,
|
|
1290
|
+
annotations: toJSONAnnotations(this.annotations)
|
|
1291
|
+
}
|
|
1292
|
+
}
|
|
1293
|
+
/**
|
|
1294
|
+
* @since 3.10.0
|
|
1295
|
+
*/
|
|
1296
|
+
toString() {
|
|
1297
|
+
return String(this.type) + (this.isOptional ? "?" : "")
|
|
1298
|
+
}
|
|
1299
|
+
}
|
|
1300
|
+
|
|
1301
|
+
const getRestASTs = (rest: ReadonlyArray<Type>): ReadonlyArray<AST> => rest.map((annotatedAST) => annotatedAST.type)
|
|
1302
|
+
|
|
1303
|
+
/**
|
|
1304
|
+
* @category model
|
|
1305
|
+
* @since 3.10.0
|
|
1306
|
+
*/
|
|
1307
|
+
export class TupleType implements Annotated {
|
|
1308
|
+
/**
|
|
1309
|
+
* @since 3.10.0
|
|
1310
|
+
*/
|
|
1311
|
+
readonly _tag = "TupleType"
|
|
1312
|
+
constructor(
|
|
1313
|
+
readonly elements: ReadonlyArray<OptionalType>,
|
|
1314
|
+
readonly rest: ReadonlyArray<Type>,
|
|
1315
|
+
readonly isReadonly: boolean,
|
|
1316
|
+
readonly annotations: Annotations = {}
|
|
1317
|
+
) {
|
|
1318
|
+
let hasOptionalElement = false
|
|
1319
|
+
let hasIllegalRequiredElement = false
|
|
1320
|
+
for (const e of elements) {
|
|
1321
|
+
if (e.isOptional) {
|
|
1322
|
+
hasOptionalElement = true
|
|
1323
|
+
} else if (hasOptionalElement) {
|
|
1324
|
+
hasIllegalRequiredElement = true
|
|
1325
|
+
break
|
|
1326
|
+
}
|
|
1327
|
+
}
|
|
1328
|
+
if (hasIllegalRequiredElement || (hasOptionalElement && rest.length > 1)) {
|
|
1329
|
+
throw new Error(errors_.getASTRequiredElementFollowinAnOptionalElementErrorMessage)
|
|
1330
|
+
}
|
|
1331
|
+
}
|
|
1332
|
+
/**
|
|
1333
|
+
* @since 3.10.0
|
|
1334
|
+
*/
|
|
1335
|
+
toString() {
|
|
1336
|
+
return Option.getOrElse(getExpected(this), () => formatTuple(this))
|
|
1337
|
+
}
|
|
1338
|
+
/**
|
|
1339
|
+
* @since 3.10.0
|
|
1340
|
+
*/
|
|
1341
|
+
toJSON(): object {
|
|
1342
|
+
return {
|
|
1343
|
+
_tag: this._tag,
|
|
1344
|
+
elements: this.elements.map((e) => e.toJSON()),
|
|
1345
|
+
rest: this.rest.map((ast) => ast.toJSON()),
|
|
1346
|
+
isReadonly: this.isReadonly,
|
|
1347
|
+
annotations: toJSONAnnotations(this.annotations)
|
|
1348
|
+
}
|
|
1349
|
+
}
|
|
1350
|
+
}
|
|
1351
|
+
|
|
1352
|
+
const formatTuple = (ast: TupleType): string => {
|
|
1353
|
+
const formattedElements = ast.elements.map(String)
|
|
1354
|
+
.join(", ")
|
|
1355
|
+
return Arr.matchLeft(ast.rest, {
|
|
1356
|
+
onEmpty: () => `readonly [${formattedElements}]`,
|
|
1357
|
+
onNonEmpty: (head, tail) => {
|
|
1358
|
+
const formattedHead = String(head)
|
|
1359
|
+
const wrappedHead = formattedHead.includes(" | ") ? `(${formattedHead})` : formattedHead
|
|
1360
|
+
|
|
1361
|
+
if (tail.length > 0) {
|
|
1362
|
+
const formattedTail = tail.map(String).join(", ")
|
|
1363
|
+
if (ast.elements.length > 0) {
|
|
1364
|
+
return `readonly [${formattedElements}, ...${wrappedHead}[], ${formattedTail}]`
|
|
1365
|
+
} else {
|
|
1366
|
+
return `readonly [...${wrappedHead}[], ${formattedTail}]`
|
|
1367
|
+
}
|
|
1368
|
+
} else {
|
|
1369
|
+
if (ast.elements.length > 0) {
|
|
1370
|
+
return `readonly [${formattedElements}, ...${wrappedHead}[]]`
|
|
1371
|
+
} else {
|
|
1372
|
+
return `ReadonlyArray<${formattedHead}>`
|
|
1373
|
+
}
|
|
1374
|
+
}
|
|
1375
|
+
}
|
|
1376
|
+
})
|
|
1377
|
+
}
|
|
1378
|
+
|
|
1379
|
+
/**
|
|
1380
|
+
* @category guards
|
|
1381
|
+
* @since 3.10.0
|
|
1382
|
+
*/
|
|
1383
|
+
export const isTupleType: (ast: AST) => ast is TupleType = createASTGuard("TupleType")
|
|
1384
|
+
|
|
1385
|
+
/**
|
|
1386
|
+
* @category model
|
|
1387
|
+
* @since 3.10.0
|
|
1388
|
+
*/
|
|
1389
|
+
export class PropertySignature extends OptionalType {
|
|
1390
|
+
constructor(
|
|
1391
|
+
readonly name: PropertyKey,
|
|
1392
|
+
type: AST,
|
|
1393
|
+
isOptional: boolean,
|
|
1394
|
+
readonly isReadonly: boolean,
|
|
1395
|
+
annotations?: Annotations
|
|
1396
|
+
) {
|
|
1397
|
+
super(type, isOptional, annotations)
|
|
1398
|
+
}
|
|
1399
|
+
/**
|
|
1400
|
+
* @since 3.10.0
|
|
1401
|
+
*/
|
|
1402
|
+
toString(): string {
|
|
1403
|
+
return (this.isReadonly ? "readonly " : "") + String(this.name) + (this.isOptional ? "?" : "") + ": " +
|
|
1404
|
+
this.type
|
|
1405
|
+
}
|
|
1406
|
+
/**
|
|
1407
|
+
* @since 3.10.0
|
|
1408
|
+
*/
|
|
1409
|
+
toJSON(): object {
|
|
1410
|
+
return {
|
|
1411
|
+
name: String(this.name),
|
|
1412
|
+
type: this.type.toJSON(),
|
|
1413
|
+
isOptional: this.isOptional,
|
|
1414
|
+
isReadonly: this.isReadonly,
|
|
1415
|
+
annotations: toJSONAnnotations(this.annotations)
|
|
1416
|
+
}
|
|
1417
|
+
}
|
|
1418
|
+
}
|
|
1419
|
+
|
|
1420
|
+
/**
|
|
1421
|
+
* @since 3.10.0
|
|
1422
|
+
*/
|
|
1423
|
+
export type Parameter = StringKeyword | SymbolKeyword | TemplateLiteral | Refinement<Parameter>
|
|
1424
|
+
|
|
1425
|
+
/**
|
|
1426
|
+
* @since 3.10.0
|
|
1427
|
+
*/
|
|
1428
|
+
export const isParameter = (ast: AST): ast is Parameter => {
|
|
1429
|
+
switch (ast._tag) {
|
|
1430
|
+
case "StringKeyword":
|
|
1431
|
+
case "SymbolKeyword":
|
|
1432
|
+
case "TemplateLiteral":
|
|
1433
|
+
return true
|
|
1434
|
+
case "Refinement":
|
|
1435
|
+
return isParameter(ast.from)
|
|
1436
|
+
}
|
|
1437
|
+
return false
|
|
1438
|
+
}
|
|
1439
|
+
|
|
1440
|
+
/**
|
|
1441
|
+
* @category model
|
|
1442
|
+
* @since 3.10.0
|
|
1443
|
+
*/
|
|
1444
|
+
export class IndexSignature {
|
|
1445
|
+
/**
|
|
1446
|
+
* @since 3.10.0
|
|
1447
|
+
*/
|
|
1448
|
+
readonly parameter: Parameter
|
|
1449
|
+
constructor(
|
|
1450
|
+
parameter: AST,
|
|
1451
|
+
readonly type: AST,
|
|
1452
|
+
readonly isReadonly: boolean
|
|
1453
|
+
) {
|
|
1454
|
+
if (isParameter(parameter)) {
|
|
1455
|
+
this.parameter = parameter
|
|
1456
|
+
} else {
|
|
1457
|
+
throw new Error(errors_.getASTIndexSignatureParameterErrorMessage)
|
|
1458
|
+
}
|
|
1459
|
+
}
|
|
1460
|
+
/**
|
|
1461
|
+
* @since 3.10.0
|
|
1462
|
+
*/
|
|
1463
|
+
toString(): string {
|
|
1464
|
+
return (this.isReadonly ? "readonly " : "") + `[x: ${this.parameter}]: ${this.type}`
|
|
1465
|
+
}
|
|
1466
|
+
/**
|
|
1467
|
+
* @since 3.10.0
|
|
1468
|
+
*/
|
|
1469
|
+
toJSON(): object {
|
|
1470
|
+
return {
|
|
1471
|
+
parameter: this.parameter.toJSON(),
|
|
1472
|
+
type: this.type.toJSON(),
|
|
1473
|
+
isReadonly: this.isReadonly
|
|
1474
|
+
}
|
|
1475
|
+
}
|
|
1476
|
+
}
|
|
1477
|
+
|
|
1478
|
+
/**
|
|
1479
|
+
* @category model
|
|
1480
|
+
* @since 3.10.0
|
|
1481
|
+
*/
|
|
1482
|
+
export class TypeLiteral implements Annotated {
|
|
1483
|
+
/**
|
|
1484
|
+
* @since 3.10.0
|
|
1485
|
+
*/
|
|
1486
|
+
readonly _tag = "TypeLiteral"
|
|
1487
|
+
/**
|
|
1488
|
+
* @since 3.10.0
|
|
1489
|
+
*/
|
|
1490
|
+
readonly propertySignatures: ReadonlyArray<PropertySignature>
|
|
1491
|
+
/**
|
|
1492
|
+
* @since 3.10.0
|
|
1493
|
+
*/
|
|
1494
|
+
readonly indexSignatures: ReadonlyArray<IndexSignature>
|
|
1495
|
+
constructor(
|
|
1496
|
+
propertySignatures: ReadonlyArray<PropertySignature>,
|
|
1497
|
+
indexSignatures: ReadonlyArray<IndexSignature>,
|
|
1498
|
+
readonly annotations: Annotations = {}
|
|
1499
|
+
) {
|
|
1500
|
+
// check for duplicate property signatures
|
|
1501
|
+
const keys: Record<PropertyKey, null> = {}
|
|
1502
|
+
for (let i = 0; i < propertySignatures.length; i++) {
|
|
1503
|
+
const name = propertySignatures[i].name
|
|
1504
|
+
if (Object.prototype.hasOwnProperty.call(keys, name)) {
|
|
1505
|
+
throw new Error(errors_.getASTDuplicatePropertySignatureErrorMessage(name))
|
|
1506
|
+
}
|
|
1507
|
+
keys[name] = null
|
|
1508
|
+
}
|
|
1509
|
+
// check for duplicate index signatures
|
|
1510
|
+
const parameters = {
|
|
1511
|
+
string: false,
|
|
1512
|
+
symbol: false
|
|
1513
|
+
}
|
|
1514
|
+
for (let i = 0; i < indexSignatures.length; i++) {
|
|
1515
|
+
const encodedParameter = getEncodedParameter(indexSignatures[i].parameter)
|
|
1516
|
+
if (isStringKeyword(encodedParameter)) {
|
|
1517
|
+
if (parameters.string) {
|
|
1518
|
+
throw new Error(errors_.getASTDuplicateIndexSignatureErrorMessage("string"))
|
|
1519
|
+
}
|
|
1520
|
+
parameters.string = true
|
|
1521
|
+
} else if (isSymbolKeyword(encodedParameter)) {
|
|
1522
|
+
if (parameters.symbol) {
|
|
1523
|
+
throw new Error(errors_.getASTDuplicateIndexSignatureErrorMessage("symbol"))
|
|
1524
|
+
}
|
|
1525
|
+
parameters.symbol = true
|
|
1526
|
+
}
|
|
1527
|
+
}
|
|
1528
|
+
|
|
1529
|
+
this.propertySignatures = propertySignatures
|
|
1530
|
+
this.indexSignatures = indexSignatures
|
|
1531
|
+
}
|
|
1532
|
+
/**
|
|
1533
|
+
* @since 3.10.0
|
|
1534
|
+
*/
|
|
1535
|
+
toString() {
|
|
1536
|
+
return Option.getOrElse(getExpected(this), () => formatTypeLiteral(this))
|
|
1537
|
+
}
|
|
1538
|
+
/**
|
|
1539
|
+
* @since 3.10.0
|
|
1540
|
+
*/
|
|
1541
|
+
toJSON(): object {
|
|
1542
|
+
return {
|
|
1543
|
+
_tag: this._tag,
|
|
1544
|
+
propertySignatures: this.propertySignatures.map((ps) => ps.toJSON()),
|
|
1545
|
+
indexSignatures: this.indexSignatures.map((ps) => ps.toJSON()),
|
|
1546
|
+
annotations: toJSONAnnotations(this.annotations)
|
|
1547
|
+
}
|
|
1548
|
+
}
|
|
1549
|
+
}
|
|
1550
|
+
|
|
1551
|
+
const formatIndexSignatures = (iss: ReadonlyArray<IndexSignature>): string => iss.map(String).join("; ")
|
|
1552
|
+
|
|
1553
|
+
const formatTypeLiteral = (ast: TypeLiteral): string => {
|
|
1554
|
+
if (ast.propertySignatures.length > 0) {
|
|
1555
|
+
const pss = ast.propertySignatures.map(String).join("; ")
|
|
1556
|
+
if (ast.indexSignatures.length > 0) {
|
|
1557
|
+
return `{ ${pss}; ${formatIndexSignatures(ast.indexSignatures)} }`
|
|
1558
|
+
} else {
|
|
1559
|
+
return `{ ${pss} }`
|
|
1560
|
+
}
|
|
1561
|
+
} else {
|
|
1562
|
+
if (ast.indexSignatures.length > 0) {
|
|
1563
|
+
return `{ ${formatIndexSignatures(ast.indexSignatures)} }`
|
|
1564
|
+
} else {
|
|
1565
|
+
return "{}"
|
|
1566
|
+
}
|
|
1567
|
+
}
|
|
1568
|
+
}
|
|
1569
|
+
|
|
1570
|
+
/**
|
|
1571
|
+
* @category guards
|
|
1572
|
+
* @since 3.10.0
|
|
1573
|
+
*/
|
|
1574
|
+
export const isTypeLiteral: (ast: AST) => ast is TypeLiteral = createASTGuard("TypeLiteral")
|
|
1575
|
+
|
|
1576
|
+
/**
|
|
1577
|
+
* @since 3.10.0
|
|
1578
|
+
*/
|
|
1579
|
+
export type Members<A> = readonly [A, A, ...Array<A>]
|
|
1580
|
+
|
|
1581
|
+
const sortCandidates = Arr.sort(
|
|
1582
|
+
Order.mapInput(Number.Order, (ast: AST) => {
|
|
1583
|
+
switch (ast._tag) {
|
|
1584
|
+
case "AnyKeyword":
|
|
1585
|
+
return 0
|
|
1586
|
+
case "UnknownKeyword":
|
|
1587
|
+
return 1
|
|
1588
|
+
case "ObjectKeyword":
|
|
1589
|
+
return 2
|
|
1590
|
+
case "StringKeyword":
|
|
1591
|
+
case "NumberKeyword":
|
|
1592
|
+
case "BooleanKeyword":
|
|
1593
|
+
case "BigIntKeyword":
|
|
1594
|
+
case "SymbolKeyword":
|
|
1595
|
+
return 3
|
|
1596
|
+
}
|
|
1597
|
+
return 4
|
|
1598
|
+
})
|
|
1599
|
+
)
|
|
1600
|
+
|
|
1601
|
+
const literalMap = {
|
|
1602
|
+
string: "StringKeyword",
|
|
1603
|
+
number: "NumberKeyword",
|
|
1604
|
+
boolean: "BooleanKeyword",
|
|
1605
|
+
bigint: "BigIntKeyword"
|
|
1606
|
+
} as const
|
|
1607
|
+
|
|
1608
|
+
/** @internal */
|
|
1609
|
+
export const flatten = (candidates: ReadonlyArray<AST>): Array<AST> =>
|
|
1610
|
+
Arr.flatMap(candidates, (ast) => isUnion(ast) ? flatten(ast.types) : [ast])
|
|
1611
|
+
|
|
1612
|
+
/** @internal */
|
|
1613
|
+
export const unify = (candidates: ReadonlyArray<AST>): Array<AST> => {
|
|
1614
|
+
const cs = sortCandidates(candidates)
|
|
1615
|
+
const out: Array<AST> = []
|
|
1616
|
+
const uniques: { [K in AST["_tag"] | "{}"]?: AST } = {}
|
|
1617
|
+
const literals: Array<LiteralValue | symbol> = []
|
|
1618
|
+
for (const ast of cs) {
|
|
1619
|
+
switch (ast._tag) {
|
|
1620
|
+
case "NeverKeyword":
|
|
1621
|
+
break
|
|
1622
|
+
case "AnyKeyword":
|
|
1623
|
+
return [anyKeyword]
|
|
1624
|
+
case "UnknownKeyword":
|
|
1625
|
+
return [unknownKeyword]
|
|
1626
|
+
// uniques
|
|
1627
|
+
case "ObjectKeyword":
|
|
1628
|
+
case "UndefinedKeyword":
|
|
1629
|
+
case "VoidKeyword":
|
|
1630
|
+
case "StringKeyword":
|
|
1631
|
+
case "NumberKeyword":
|
|
1632
|
+
case "BooleanKeyword":
|
|
1633
|
+
case "BigIntKeyword":
|
|
1634
|
+
case "SymbolKeyword": {
|
|
1635
|
+
if (!uniques[ast._tag]) {
|
|
1636
|
+
uniques[ast._tag] = ast
|
|
1637
|
+
out.push(ast)
|
|
1638
|
+
}
|
|
1639
|
+
break
|
|
1640
|
+
}
|
|
1641
|
+
case "Literal": {
|
|
1642
|
+
const type = typeof ast.literal
|
|
1643
|
+
switch (type) {
|
|
1644
|
+
case "string":
|
|
1645
|
+
case "number":
|
|
1646
|
+
case "bigint":
|
|
1647
|
+
case "boolean": {
|
|
1648
|
+
const _tag = literalMap[type]
|
|
1649
|
+
if (!uniques[_tag] && !literals.includes(ast.literal)) {
|
|
1650
|
+
literals.push(ast.literal)
|
|
1651
|
+
out.push(ast)
|
|
1652
|
+
}
|
|
1653
|
+
break
|
|
1654
|
+
}
|
|
1655
|
+
// null
|
|
1656
|
+
case "object": {
|
|
1657
|
+
if (!literals.includes(ast.literal)) {
|
|
1658
|
+
literals.push(ast.literal)
|
|
1659
|
+
out.push(ast)
|
|
1660
|
+
}
|
|
1661
|
+
break
|
|
1662
|
+
}
|
|
1663
|
+
}
|
|
1664
|
+
break
|
|
1665
|
+
}
|
|
1666
|
+
case "UniqueSymbol": {
|
|
1667
|
+
if (!uniques["SymbolKeyword"] && !literals.includes(ast.symbol)) {
|
|
1668
|
+
literals.push(ast.symbol)
|
|
1669
|
+
out.push(ast)
|
|
1670
|
+
}
|
|
1671
|
+
break
|
|
1672
|
+
}
|
|
1673
|
+
case "TupleType": {
|
|
1674
|
+
if (!uniques["ObjectKeyword"]) {
|
|
1675
|
+
out.push(ast)
|
|
1676
|
+
}
|
|
1677
|
+
break
|
|
1678
|
+
}
|
|
1679
|
+
case "TypeLiteral": {
|
|
1680
|
+
if (ast.propertySignatures.length === 0 && ast.indexSignatures.length === 0) {
|
|
1681
|
+
if (!uniques["{}"]) {
|
|
1682
|
+
uniques["{}"] = ast
|
|
1683
|
+
out.push(ast)
|
|
1684
|
+
}
|
|
1685
|
+
} else if (!uniques["ObjectKeyword"]) {
|
|
1686
|
+
out.push(ast)
|
|
1687
|
+
}
|
|
1688
|
+
break
|
|
1689
|
+
}
|
|
1690
|
+
default:
|
|
1691
|
+
out.push(ast)
|
|
1692
|
+
}
|
|
1693
|
+
}
|
|
1694
|
+
return out
|
|
1695
|
+
}
|
|
1696
|
+
|
|
1697
|
+
/**
|
|
1698
|
+
* @category model
|
|
1699
|
+
* @since 3.10.0
|
|
1700
|
+
*/
|
|
1701
|
+
export class Union<M extends AST = AST> implements Annotated {
|
|
1702
|
+
static make = (types: ReadonlyArray<AST>, annotations?: Annotations): AST => {
|
|
1703
|
+
return isMembers(types) ? new Union(types, annotations) : types.length === 1 ? types[0] : neverKeyword
|
|
1704
|
+
}
|
|
1705
|
+
/** @internal */
|
|
1706
|
+
static unify = (candidates: ReadonlyArray<AST>, annotations?: Annotations): AST => {
|
|
1707
|
+
return Union.make(unify(flatten(candidates)), annotations)
|
|
1708
|
+
}
|
|
1709
|
+
/**
|
|
1710
|
+
* @since 3.10.0
|
|
1711
|
+
*/
|
|
1712
|
+
readonly _tag = "Union"
|
|
1713
|
+
private constructor(readonly types: Members<M>, readonly annotations: Annotations = {}) {}
|
|
1714
|
+
/**
|
|
1715
|
+
* @since 3.10.0
|
|
1716
|
+
*/
|
|
1717
|
+
toString() {
|
|
1718
|
+
return Option.getOrElse(getExpected(this), () => this.types.map(String).join(" | "))
|
|
1719
|
+
}
|
|
1720
|
+
/**
|
|
1721
|
+
* @since 3.10.0
|
|
1722
|
+
*/
|
|
1723
|
+
toJSON(): object {
|
|
1724
|
+
return {
|
|
1725
|
+
_tag: this._tag,
|
|
1726
|
+
types: this.types.map((ast) => ast.toJSON()),
|
|
1727
|
+
annotations: toJSONAnnotations(this.annotations)
|
|
1728
|
+
}
|
|
1729
|
+
}
|
|
1730
|
+
}
|
|
1731
|
+
|
|
1732
|
+
/** @internal */
|
|
1733
|
+
export const mapMembers = <A, B>(members: Members<A>, f: (a: A) => B): Members<B> => members.map(f) as any
|
|
1734
|
+
|
|
1735
|
+
/** @internal */
|
|
1736
|
+
export const isMembers = <A>(as: ReadonlyArray<A>): as is Members<A> => as.length > 1
|
|
1737
|
+
|
|
1738
|
+
/**
|
|
1739
|
+
* @category guards
|
|
1740
|
+
* @since 3.10.0
|
|
1741
|
+
*/
|
|
1742
|
+
export const isUnion: (ast: AST) => ast is Union = createASTGuard("Union")
|
|
1743
|
+
|
|
1744
|
+
const toJSONMemoMap = globalValue(
|
|
1745
|
+
Symbol.for("effect/Schema/AST/toJSONMemoMap"),
|
|
1746
|
+
() => new WeakMap<AST, object>()
|
|
1747
|
+
)
|
|
1748
|
+
|
|
1749
|
+
/**
|
|
1750
|
+
* @category model
|
|
1751
|
+
* @since 3.10.0
|
|
1752
|
+
*/
|
|
1753
|
+
export class Suspend implements Annotated {
|
|
1754
|
+
/**
|
|
1755
|
+
* @since 3.10.0
|
|
1756
|
+
*/
|
|
1757
|
+
readonly _tag = "Suspend"
|
|
1758
|
+
constructor(readonly f: () => AST, readonly annotations: Annotations = {}) {
|
|
1759
|
+
this.f = util_.memoizeThunk(f)
|
|
1760
|
+
}
|
|
1761
|
+
/**
|
|
1762
|
+
* @since 3.10.0
|
|
1763
|
+
*/
|
|
1764
|
+
toString() {
|
|
1765
|
+
return getExpected(this).pipe(
|
|
1766
|
+
Option.orElse(() =>
|
|
1767
|
+
Option.flatMap(
|
|
1768
|
+
Option.liftThrowable(this.f)(),
|
|
1769
|
+
(ast) => getExpected(ast)
|
|
1770
|
+
)
|
|
1771
|
+
),
|
|
1772
|
+
Option.getOrElse(() => "<suspended schema>")
|
|
1773
|
+
)
|
|
1774
|
+
}
|
|
1775
|
+
/**
|
|
1776
|
+
* @since 3.10.0
|
|
1777
|
+
*/
|
|
1778
|
+
toJSON(): object {
|
|
1779
|
+
const ast = this.f()
|
|
1780
|
+
let out = toJSONMemoMap.get(ast)
|
|
1781
|
+
if (out) {
|
|
1782
|
+
return out
|
|
1783
|
+
}
|
|
1784
|
+
toJSONMemoMap.set(ast, { _tag: this._tag })
|
|
1785
|
+
out = {
|
|
1786
|
+
_tag: this._tag,
|
|
1787
|
+
ast: ast.toJSON(),
|
|
1788
|
+
annotations: toJSONAnnotations(this.annotations)
|
|
1789
|
+
}
|
|
1790
|
+
toJSONMemoMap.set(ast, out)
|
|
1791
|
+
return out
|
|
1792
|
+
}
|
|
1793
|
+
}
|
|
1794
|
+
|
|
1795
|
+
/**
|
|
1796
|
+
* @category guards
|
|
1797
|
+
* @since 3.10.0
|
|
1798
|
+
*/
|
|
1799
|
+
export const isSuspend: (ast: AST) => ast is Suspend = createASTGuard("Suspend")
|
|
1800
|
+
|
|
1801
|
+
/**
|
|
1802
|
+
* @category model
|
|
1803
|
+
* @since 3.10.0
|
|
1804
|
+
*/
|
|
1805
|
+
export class Refinement<From extends AST = AST> implements Annotated {
|
|
1806
|
+
/**
|
|
1807
|
+
* @since 3.10.0
|
|
1808
|
+
*/
|
|
1809
|
+
readonly _tag = "Refinement"
|
|
1810
|
+
constructor(
|
|
1811
|
+
readonly from: From,
|
|
1812
|
+
readonly filter: (
|
|
1813
|
+
input: any,
|
|
1814
|
+
options: ParseOptions,
|
|
1815
|
+
self: Refinement
|
|
1816
|
+
) => Option.Option<ParseIssue>,
|
|
1817
|
+
readonly annotations: Annotations = {}
|
|
1818
|
+
) {}
|
|
1819
|
+
/**
|
|
1820
|
+
* @since 3.10.0
|
|
1821
|
+
*/
|
|
1822
|
+
toString() {
|
|
1823
|
+
return getIdentifierAnnotation(this).pipe(Option.getOrElse(() =>
|
|
1824
|
+
Option.match(getOrElseExpected(this), {
|
|
1825
|
+
onNone: () => `{ ${this.from} | filter }`,
|
|
1826
|
+
onSome: (expected) => isRefinement(this.from) ? String(this.from) + " & " + expected : expected
|
|
1827
|
+
})
|
|
1828
|
+
))
|
|
1829
|
+
}
|
|
1830
|
+
/**
|
|
1831
|
+
* @since 3.10.0
|
|
1832
|
+
*/
|
|
1833
|
+
toJSON(): object {
|
|
1834
|
+
return {
|
|
1835
|
+
_tag: this._tag,
|
|
1836
|
+
from: this.from.toJSON(),
|
|
1837
|
+
annotations: toJSONAnnotations(this.annotations)
|
|
1838
|
+
}
|
|
1839
|
+
}
|
|
1840
|
+
}
|
|
1841
|
+
|
|
1842
|
+
/**
|
|
1843
|
+
* @category guards
|
|
1844
|
+
* @since 3.10.0
|
|
1845
|
+
*/
|
|
1846
|
+
export const isRefinement: (ast: AST) => ast is Refinement<AST> = createASTGuard("Refinement")
|
|
1847
|
+
|
|
1848
|
+
/**
|
|
1849
|
+
* @category model
|
|
1850
|
+
* @since 3.10.0
|
|
1851
|
+
*/
|
|
1852
|
+
export interface ParseOptions {
|
|
1853
|
+
/**
|
|
1854
|
+
* The `errors` option allows you to receive all parsing errors when
|
|
1855
|
+
* attempting to parse a value using a schema. By default only the first error
|
|
1856
|
+
* is returned, but by setting the `errors` option to `"all"`, you can receive
|
|
1857
|
+
* all errors that occurred during the parsing process. This can be useful for
|
|
1858
|
+
* debugging or for providing more comprehensive error messages to the user.
|
|
1859
|
+
*
|
|
1860
|
+
* default: "first"
|
|
1861
|
+
*
|
|
1862
|
+
* @since 3.10.0
|
|
1863
|
+
*/
|
|
1864
|
+
readonly errors?: "first" | "all" | undefined
|
|
1865
|
+
/**
|
|
1866
|
+
* When using a `Schema` to parse a value, by default any properties that are
|
|
1867
|
+
* not specified in the `Schema` will be stripped out from the output. This is
|
|
1868
|
+
* because the `Schema` is expecting a specific shape for the parsed value,
|
|
1869
|
+
* and any excess properties do not conform to that shape.
|
|
1870
|
+
*
|
|
1871
|
+
* However, you can use the `onExcessProperty` option (default value:
|
|
1872
|
+
* `"ignore"`) to trigger a parsing error. This can be particularly useful in
|
|
1873
|
+
* cases where you need to detect and handle potential errors or unexpected
|
|
1874
|
+
* values.
|
|
1875
|
+
*
|
|
1876
|
+
* If you want to allow excess properties to remain, you can use
|
|
1877
|
+
* `onExcessProperty` set to `"preserve"`.
|
|
1878
|
+
*
|
|
1879
|
+
* default: "ignore"
|
|
1880
|
+
*
|
|
1881
|
+
* @since 3.10.0
|
|
1882
|
+
*/
|
|
1883
|
+
readonly onExcessProperty?: "ignore" | "error" | "preserve" | undefined
|
|
1884
|
+
/**
|
|
1885
|
+
* The `propertyOrder` option provides control over the order of object fields
|
|
1886
|
+
* in the output. This feature is particularly useful when the sequence of
|
|
1887
|
+
* keys is important for the consuming processes or when maintaining the input
|
|
1888
|
+
* order enhances readability and usability.
|
|
1889
|
+
*
|
|
1890
|
+
* By default, the `propertyOrder` option is set to `"none"`. This means that
|
|
1891
|
+
* the internal system decides the order of keys to optimize parsing speed.
|
|
1892
|
+
* The order of keys in this mode should not be considered stable, and it's
|
|
1893
|
+
* recommended not to rely on key ordering as it may change in future updates
|
|
1894
|
+
* without notice.
|
|
1895
|
+
*
|
|
1896
|
+
* Setting `propertyOrder` to `"original"` ensures that the keys are ordered
|
|
1897
|
+
* as they appear in the input during the decoding/encoding process.
|
|
1898
|
+
*
|
|
1899
|
+
* default: "none"
|
|
1900
|
+
*
|
|
1901
|
+
* @since 3.10.0
|
|
1902
|
+
*/
|
|
1903
|
+
readonly propertyOrder?: "none" | "original" | undefined
|
|
1904
|
+
/**
|
|
1905
|
+
* Handles missing properties in data structures. By default, missing
|
|
1906
|
+
* properties are treated as if present with an `undefined` value. To treat
|
|
1907
|
+
* missing properties as errors, set the `exact` option to `true`. This
|
|
1908
|
+
* setting is already enabled by default for `is` and `asserts` functions,
|
|
1909
|
+
* treating absent properties strictly unless overridden.
|
|
1910
|
+
*
|
|
1911
|
+
* default: false
|
|
1912
|
+
*
|
|
1913
|
+
* @since 3.10.0
|
|
1914
|
+
*/
|
|
1915
|
+
readonly exact?: boolean | undefined
|
|
1916
|
+
}
|
|
1917
|
+
|
|
1918
|
+
/**
|
|
1919
|
+
* @since 3.10.0
|
|
1920
|
+
*/
|
|
1921
|
+
export const defaultParseOption: ParseOptions = {}
|
|
1922
|
+
|
|
1923
|
+
/**
|
|
1924
|
+
* @category model
|
|
1925
|
+
* @since 3.10.0
|
|
1926
|
+
*/
|
|
1927
|
+
export class Transformation implements Annotated {
|
|
1928
|
+
/**
|
|
1929
|
+
* @since 3.10.0
|
|
1930
|
+
*/
|
|
1931
|
+
readonly _tag = "Transformation"
|
|
1932
|
+
constructor(
|
|
1933
|
+
readonly from: AST,
|
|
1934
|
+
readonly to: AST,
|
|
1935
|
+
readonly transformation: TransformationKind,
|
|
1936
|
+
readonly annotations: Annotations = {}
|
|
1937
|
+
) {}
|
|
1938
|
+
/**
|
|
1939
|
+
* @since 3.10.0
|
|
1940
|
+
*/
|
|
1941
|
+
toString() {
|
|
1942
|
+
return Option.getOrElse(
|
|
1943
|
+
getExpected(this),
|
|
1944
|
+
() => `(${String(this.from)} <-> ${String(this.to)})`
|
|
1945
|
+
)
|
|
1946
|
+
}
|
|
1947
|
+
/**
|
|
1948
|
+
* @since 3.10.0
|
|
1949
|
+
*/
|
|
1950
|
+
toJSON(): object {
|
|
1951
|
+
return {
|
|
1952
|
+
_tag: this._tag,
|
|
1953
|
+
from: this.from.toJSON(),
|
|
1954
|
+
to: this.to.toJSON(),
|
|
1955
|
+
annotations: toJSONAnnotations(this.annotations)
|
|
1956
|
+
}
|
|
1957
|
+
}
|
|
1958
|
+
}
|
|
1959
|
+
|
|
1960
|
+
/**
|
|
1961
|
+
* @category guards
|
|
1962
|
+
* @since 3.10.0
|
|
1963
|
+
*/
|
|
1964
|
+
export const isTransformation: (ast: AST) => ast is Transformation = createASTGuard("Transformation")
|
|
1965
|
+
|
|
1966
|
+
/**
|
|
1967
|
+
* @category model
|
|
1968
|
+
* @since 3.10.0
|
|
1969
|
+
*/
|
|
1970
|
+
export type TransformationKind =
|
|
1971
|
+
| FinalTransformation
|
|
1972
|
+
| ComposeTransformation
|
|
1973
|
+
| TypeLiteralTransformation
|
|
1974
|
+
|
|
1975
|
+
/**
|
|
1976
|
+
* @category model
|
|
1977
|
+
* @since 3.10.0
|
|
1978
|
+
*/
|
|
1979
|
+
export class FinalTransformation {
|
|
1980
|
+
/**
|
|
1981
|
+
* @since 3.10.0
|
|
1982
|
+
*/
|
|
1983
|
+
readonly _tag = "FinalTransformation"
|
|
1984
|
+
constructor(
|
|
1985
|
+
readonly decode: (
|
|
1986
|
+
fromA: any,
|
|
1987
|
+
options: ParseOptions,
|
|
1988
|
+
self: Transformation,
|
|
1989
|
+
fromI: any
|
|
1990
|
+
) => Effect<any, ParseIssue, any>,
|
|
1991
|
+
readonly encode: (toI: any, options: ParseOptions, self: Transformation, toA: any) => Effect<any, ParseIssue, any>
|
|
1992
|
+
) {}
|
|
1993
|
+
}
|
|
1994
|
+
|
|
1995
|
+
const createTransformationGuard =
|
|
1996
|
+
<T extends TransformationKind["_tag"]>(tag: T) =>
|
|
1997
|
+
(ast: TransformationKind): ast is Extract<TransformationKind, { _tag: T }> => ast._tag === tag
|
|
1998
|
+
|
|
1999
|
+
/**
|
|
2000
|
+
* @category guards
|
|
2001
|
+
* @since 3.10.0
|
|
2002
|
+
*/
|
|
2003
|
+
export const isFinalTransformation: (ast: TransformationKind) => ast is FinalTransformation = createTransformationGuard(
|
|
2004
|
+
"FinalTransformation"
|
|
2005
|
+
)
|
|
2006
|
+
|
|
2007
|
+
/**
|
|
2008
|
+
* @category model
|
|
2009
|
+
* @since 3.10.0
|
|
2010
|
+
*/
|
|
2011
|
+
export class ComposeTransformation {
|
|
2012
|
+
/**
|
|
2013
|
+
* @since 3.10.0
|
|
2014
|
+
*/
|
|
2015
|
+
readonly _tag = "ComposeTransformation"
|
|
2016
|
+
}
|
|
2017
|
+
|
|
2018
|
+
/**
|
|
2019
|
+
* @category constructors
|
|
2020
|
+
* @since 3.10.0
|
|
2021
|
+
*/
|
|
2022
|
+
export const composeTransformation: ComposeTransformation = new ComposeTransformation()
|
|
2023
|
+
|
|
2024
|
+
/**
|
|
2025
|
+
* @category guards
|
|
2026
|
+
* @since 3.10.0
|
|
2027
|
+
*/
|
|
2028
|
+
export const isComposeTransformation: (ast: TransformationKind) => ast is ComposeTransformation =
|
|
2029
|
+
createTransformationGuard(
|
|
2030
|
+
"ComposeTransformation"
|
|
2031
|
+
)
|
|
2032
|
+
|
|
2033
|
+
/**
|
|
2034
|
+
* Represents a `PropertySignature -> PropertySignature` transformation
|
|
2035
|
+
*
|
|
2036
|
+
* The semantic of `decode` is:
|
|
2037
|
+
* - `none()` represents the absence of the key/value pair
|
|
2038
|
+
* - `some(value)` represents the presence of the key/value pair
|
|
2039
|
+
*
|
|
2040
|
+
* The semantic of `encode` is:
|
|
2041
|
+
* - `none()` you don't want to output the key/value pair
|
|
2042
|
+
* - `some(value)` you want to output the key/value pair
|
|
2043
|
+
*
|
|
2044
|
+
* @category model
|
|
2045
|
+
* @since 3.10.0
|
|
2046
|
+
*/
|
|
2047
|
+
export class PropertySignatureTransformation {
|
|
2048
|
+
constructor(
|
|
2049
|
+
readonly from: PropertyKey,
|
|
2050
|
+
readonly to: PropertyKey,
|
|
2051
|
+
readonly decode: (o: Option.Option<any>) => Option.Option<any>,
|
|
2052
|
+
readonly encode: (o: Option.Option<any>) => Option.Option<any>
|
|
2053
|
+
) {}
|
|
2054
|
+
}
|
|
2055
|
+
|
|
2056
|
+
const isRenamingPropertySignatureTransformation = (t: PropertySignatureTransformation) =>
|
|
2057
|
+
t.decode === identity && t.encode === identity
|
|
2058
|
+
|
|
2059
|
+
/**
|
|
2060
|
+
* @category model
|
|
2061
|
+
* @since 3.10.0
|
|
2062
|
+
*/
|
|
2063
|
+
export class TypeLiteralTransformation {
|
|
2064
|
+
/**
|
|
2065
|
+
* @since 3.10.0
|
|
2066
|
+
*/
|
|
2067
|
+
readonly _tag = "TypeLiteralTransformation"
|
|
2068
|
+
constructor(
|
|
2069
|
+
readonly propertySignatureTransformations: ReadonlyArray<
|
|
2070
|
+
PropertySignatureTransformation
|
|
2071
|
+
>
|
|
2072
|
+
) {
|
|
2073
|
+
// check for duplicate property signature transformations
|
|
2074
|
+
const fromKeys: Record<PropertyKey, true> = {}
|
|
2075
|
+
const toKeys: Record<PropertyKey, true> = {}
|
|
2076
|
+
for (const pst of propertySignatureTransformations) {
|
|
2077
|
+
const from = pst.from
|
|
2078
|
+
if (fromKeys[from]) {
|
|
2079
|
+
throw new Error(errors_.getASTDuplicatePropertySignatureTransformationErrorMessage(from))
|
|
2080
|
+
}
|
|
2081
|
+
fromKeys[from] = true
|
|
2082
|
+
const to = pst.to
|
|
2083
|
+
if (toKeys[to]) {
|
|
2084
|
+
throw new Error(errors_.getASTDuplicatePropertySignatureTransformationErrorMessage(to))
|
|
2085
|
+
}
|
|
2086
|
+
toKeys[to] = true
|
|
2087
|
+
}
|
|
2088
|
+
}
|
|
2089
|
+
}
|
|
2090
|
+
|
|
2091
|
+
/**
|
|
2092
|
+
* @category guards
|
|
2093
|
+
* @since 3.10.0
|
|
2094
|
+
*/
|
|
2095
|
+
export const isTypeLiteralTransformation: (ast: TransformationKind) => ast is TypeLiteralTransformation =
|
|
2096
|
+
createTransformationGuard("TypeLiteralTransformation")
|
|
2097
|
+
|
|
2098
|
+
// -------------------------------------------------------------------------------------
|
|
2099
|
+
// API
|
|
2100
|
+
// -------------------------------------------------------------------------------------
|
|
2101
|
+
|
|
2102
|
+
/**
|
|
2103
|
+
* Merges a set of new annotations with existing ones, potentially overwriting
|
|
2104
|
+
* any duplicates.
|
|
2105
|
+
*
|
|
2106
|
+
* Any previously existing identifier annotations are deleted.
|
|
2107
|
+
*
|
|
2108
|
+
* @since 3.10.0
|
|
2109
|
+
*/
|
|
2110
|
+
export const annotations = (ast: AST, overrides: Annotations): AST => {
|
|
2111
|
+
const d = Object.getOwnPropertyDescriptors(ast)
|
|
2112
|
+
const base: any = { ...ast.annotations }
|
|
2113
|
+
delete base[IdentifierAnnotationId]
|
|
2114
|
+
const value = { ...base, ...overrides }
|
|
2115
|
+
const surrogate = getSurrogateAnnotation(ast)
|
|
2116
|
+
if (Option.isSome(surrogate)) {
|
|
2117
|
+
value[SurrogateAnnotationId] = annotations(surrogate.value, overrides)
|
|
2118
|
+
}
|
|
2119
|
+
d.annotations.value = value
|
|
2120
|
+
return Object.create(Object.getPrototypeOf(ast), d)
|
|
2121
|
+
}
|
|
2122
|
+
|
|
2123
|
+
/**
|
|
2124
|
+
* Equivalent at runtime to the TypeScript type-level `keyof` operator.
|
|
2125
|
+
*
|
|
2126
|
+
* @since 3.10.0
|
|
2127
|
+
*/
|
|
2128
|
+
export const keyof = (ast: AST): AST => Union.unify(_keyof(ast))
|
|
2129
|
+
|
|
2130
|
+
const STRING_KEYWORD_PATTERN = "[\\s\\S]*?" // any string, including newlines
|
|
2131
|
+
const NUMBER_KEYWORD_PATTERN = "[+-]?\\d*\\.?\\d+(?:[Ee][+-]?\\d+)?"
|
|
2132
|
+
|
|
2133
|
+
const getTemplateLiteralSpanTypePattern = (type: TemplateLiteralSpanType, capture: boolean): string => {
|
|
2134
|
+
switch (type._tag) {
|
|
2135
|
+
case "Literal":
|
|
2136
|
+
return regexp.escape(String(type.literal))
|
|
2137
|
+
case "StringKeyword":
|
|
2138
|
+
return STRING_KEYWORD_PATTERN
|
|
2139
|
+
case "NumberKeyword":
|
|
2140
|
+
return NUMBER_KEYWORD_PATTERN
|
|
2141
|
+
case "TemplateLiteral":
|
|
2142
|
+
return getTemplateLiteralPattern(type, capture, false)
|
|
2143
|
+
case "Union":
|
|
2144
|
+
return type.types.map((type) => getTemplateLiteralSpanTypePattern(type, capture)).join("|")
|
|
2145
|
+
}
|
|
2146
|
+
}
|
|
2147
|
+
|
|
2148
|
+
const handleTemplateLiteralSpanTypeParens = (
|
|
2149
|
+
type: TemplateLiteralSpanType,
|
|
2150
|
+
s: string,
|
|
2151
|
+
capture: boolean,
|
|
2152
|
+
top: boolean
|
|
2153
|
+
) => {
|
|
2154
|
+
if (isUnion(type)) {
|
|
2155
|
+
if (capture && !top) {
|
|
2156
|
+
return `(?:${s})`
|
|
2157
|
+
}
|
|
2158
|
+
} else if (!capture || !top) {
|
|
2159
|
+
return s
|
|
2160
|
+
}
|
|
2161
|
+
return `(${s})`
|
|
2162
|
+
}
|
|
2163
|
+
|
|
2164
|
+
const getTemplateLiteralPattern = (ast: TemplateLiteral, capture: boolean, top: boolean): string => {
|
|
2165
|
+
let pattern = ``
|
|
2166
|
+
if (ast.head !== "") {
|
|
2167
|
+
const head = regexp.escape(ast.head)
|
|
2168
|
+
pattern += capture && top ? `(${head})` : head
|
|
2169
|
+
}
|
|
2170
|
+
|
|
2171
|
+
for (const span of ast.spans) {
|
|
2172
|
+
const spanPattern = getTemplateLiteralSpanTypePattern(span.type, capture)
|
|
2173
|
+
pattern += handleTemplateLiteralSpanTypeParens(span.type, spanPattern, capture, top)
|
|
2174
|
+
if (span.literal !== "") {
|
|
2175
|
+
const literal = regexp.escape(span.literal)
|
|
2176
|
+
pattern += capture && top ? `(${literal})` : literal
|
|
2177
|
+
}
|
|
2178
|
+
}
|
|
2179
|
+
|
|
2180
|
+
return pattern
|
|
2181
|
+
}
|
|
2182
|
+
|
|
2183
|
+
/**
|
|
2184
|
+
* Generates a regular expression from a `TemplateLiteral` AST node.
|
|
2185
|
+
*
|
|
2186
|
+
* @see {@link getTemplateLiteralCapturingRegExp} for a variant that captures the pattern.
|
|
2187
|
+
*
|
|
2188
|
+
* @since 3.10.0
|
|
2189
|
+
*/
|
|
2190
|
+
export const getTemplateLiteralRegExp = (ast: TemplateLiteral): RegExp =>
|
|
2191
|
+
new RegExp(`^${getTemplateLiteralPattern(ast, false, true)}$`)
|
|
2192
|
+
|
|
2193
|
+
/**
|
|
2194
|
+
* Generates a regular expression that captures the pattern defined by the given `TemplateLiteral` AST.
|
|
2195
|
+
*
|
|
2196
|
+
* @see {@link getTemplateLiteralRegExp} for a variant that does not capture the pattern.
|
|
2197
|
+
*
|
|
2198
|
+
* @since 3.10.0
|
|
2199
|
+
*/
|
|
2200
|
+
export const getTemplateLiteralCapturingRegExp = (ast: TemplateLiteral): RegExp =>
|
|
2201
|
+
new RegExp(`^${getTemplateLiteralPattern(ast, true, true)}$`)
|
|
2202
|
+
|
|
2203
|
+
/**
|
|
2204
|
+
* @since 3.10.0
|
|
2205
|
+
*/
|
|
2206
|
+
export const getPropertySignatures = (ast: AST): Array<PropertySignature> => {
|
|
2207
|
+
const annotation = getSurrogateAnnotation(ast)
|
|
2208
|
+
if (Option.isSome(annotation)) {
|
|
2209
|
+
return getPropertySignatures(annotation.value)
|
|
2210
|
+
}
|
|
2211
|
+
switch (ast._tag) {
|
|
2212
|
+
case "TypeLiteral":
|
|
2213
|
+
return ast.propertySignatures.slice()
|
|
2214
|
+
case "Suspend":
|
|
2215
|
+
return getPropertySignatures(ast.f())
|
|
2216
|
+
case "Refinement":
|
|
2217
|
+
return getPropertySignatures(ast.from)
|
|
2218
|
+
}
|
|
2219
|
+
return getPropertyKeys(ast).map((name) => getPropertyKeyIndexedAccess(ast, name))
|
|
2220
|
+
}
|
|
2221
|
+
|
|
2222
|
+
const getIndexSignatures = (ast: AST): Array<IndexSignature> => {
|
|
2223
|
+
const annotation = getSurrogateAnnotation(ast)
|
|
2224
|
+
if (Option.isSome(annotation)) {
|
|
2225
|
+
return getIndexSignatures(annotation.value)
|
|
2226
|
+
}
|
|
2227
|
+
switch (ast._tag) {
|
|
2228
|
+
case "TypeLiteral":
|
|
2229
|
+
return ast.indexSignatures.slice()
|
|
2230
|
+
case "Suspend":
|
|
2231
|
+
return getIndexSignatures(ast.f())
|
|
2232
|
+
case "Refinement":
|
|
2233
|
+
return getIndexSignatures(ast.from)
|
|
2234
|
+
}
|
|
2235
|
+
return []
|
|
2236
|
+
}
|
|
2237
|
+
|
|
2238
|
+
/** @internal */
|
|
2239
|
+
export const getNumberIndexedAccess = (ast: AST): AST => {
|
|
2240
|
+
switch (ast._tag) {
|
|
2241
|
+
case "TupleType": {
|
|
2242
|
+
let hasOptional = false
|
|
2243
|
+
let out: Array<AST> = []
|
|
2244
|
+
for (const e of ast.elements) {
|
|
2245
|
+
if (e.isOptional) {
|
|
2246
|
+
hasOptional = true
|
|
2247
|
+
}
|
|
2248
|
+
out.push(e.type)
|
|
2249
|
+
}
|
|
2250
|
+
if (hasOptional) {
|
|
2251
|
+
out.push(undefinedKeyword)
|
|
2252
|
+
}
|
|
2253
|
+
out = out.concat(getRestASTs(ast.rest))
|
|
2254
|
+
return Union.make(out)
|
|
2255
|
+
}
|
|
2256
|
+
case "Refinement":
|
|
2257
|
+
return getNumberIndexedAccess(ast.from)
|
|
2258
|
+
case "Union":
|
|
2259
|
+
return Union.make(ast.types.map(getNumberIndexedAccess))
|
|
2260
|
+
case "Suspend":
|
|
2261
|
+
return getNumberIndexedAccess(ast.f())
|
|
2262
|
+
}
|
|
2263
|
+
throw new Error(errors_.getASTUnsupportedSchemaErrorMessage(ast))
|
|
2264
|
+
}
|
|
2265
|
+
|
|
2266
|
+
const getTypeLiteralPropertySignature = (ast: TypeLiteral, name: PropertyKey): PropertySignature | undefined => {
|
|
2267
|
+
// from property signatures...
|
|
2268
|
+
const ops = Arr.findFirst(ast.propertySignatures, (ps) => ps.name === name)
|
|
2269
|
+
if (Option.isSome(ops)) {
|
|
2270
|
+
return ops.value
|
|
2271
|
+
}
|
|
2272
|
+
|
|
2273
|
+
// from index signatures...
|
|
2274
|
+
if (Predicate.isString(name)) {
|
|
2275
|
+
let out: PropertySignature | undefined = undefined
|
|
2276
|
+
for (const is of ast.indexSignatures) {
|
|
2277
|
+
const encodedParameter = getEncodedParameter(is.parameter)
|
|
2278
|
+
switch (encodedParameter._tag) {
|
|
2279
|
+
case "TemplateLiteral": {
|
|
2280
|
+
const regex = getTemplateLiteralRegExp(encodedParameter)
|
|
2281
|
+
if (regex.test(name)) {
|
|
2282
|
+
return new PropertySignature(name, is.type, false, true)
|
|
2283
|
+
}
|
|
2284
|
+
break
|
|
2285
|
+
}
|
|
2286
|
+
case "StringKeyword": {
|
|
2287
|
+
if (out === undefined) {
|
|
2288
|
+
out = new PropertySignature(name, is.type, false, true)
|
|
2289
|
+
}
|
|
2290
|
+
}
|
|
2291
|
+
}
|
|
2292
|
+
}
|
|
2293
|
+
if (out) {
|
|
2294
|
+
return out
|
|
2295
|
+
}
|
|
2296
|
+
} else if (Predicate.isSymbol(name)) {
|
|
2297
|
+
for (const is of ast.indexSignatures) {
|
|
2298
|
+
const encodedParameter = getEncodedParameter(is.parameter)
|
|
2299
|
+
if (isSymbolKeyword(encodedParameter)) {
|
|
2300
|
+
return new PropertySignature(name, is.type, false, true)
|
|
2301
|
+
}
|
|
2302
|
+
}
|
|
2303
|
+
}
|
|
2304
|
+
}
|
|
2305
|
+
|
|
2306
|
+
/** @internal */
|
|
2307
|
+
export const getPropertyKeyIndexedAccess = (ast: AST, name: PropertyKey): PropertySignature => {
|
|
2308
|
+
const annotation = getSurrogateAnnotation(ast)
|
|
2309
|
+
if (Option.isSome(annotation)) {
|
|
2310
|
+
return getPropertyKeyIndexedAccess(annotation.value, name)
|
|
2311
|
+
}
|
|
2312
|
+
switch (ast._tag) {
|
|
2313
|
+
case "TypeLiteral": {
|
|
2314
|
+
const ps = getTypeLiteralPropertySignature(ast, name)
|
|
2315
|
+
if (ps) {
|
|
2316
|
+
return ps
|
|
2317
|
+
}
|
|
2318
|
+
break
|
|
2319
|
+
}
|
|
2320
|
+
case "Union":
|
|
2321
|
+
return new PropertySignature(
|
|
2322
|
+
name,
|
|
2323
|
+
Union.make(ast.types.map((ast) => getPropertyKeyIndexedAccess(ast, name).type)),
|
|
2324
|
+
false,
|
|
2325
|
+
true
|
|
2326
|
+
)
|
|
2327
|
+
case "Suspend":
|
|
2328
|
+
return getPropertyKeyIndexedAccess(ast.f(), name)
|
|
2329
|
+
case "Refinement":
|
|
2330
|
+
return getPropertyKeyIndexedAccess(ast.from, name)
|
|
2331
|
+
}
|
|
2332
|
+
throw new Error(errors_.getASTUnsupportedSchemaErrorMessage(ast))
|
|
2333
|
+
}
|
|
2334
|
+
|
|
2335
|
+
const getPropertyKeys = (ast: AST): Array<PropertyKey> => {
|
|
2336
|
+
const annotation = getSurrogateAnnotation(ast)
|
|
2337
|
+
if (Option.isSome(annotation)) {
|
|
2338
|
+
return getPropertyKeys(annotation.value)
|
|
2339
|
+
}
|
|
2340
|
+
switch (ast._tag) {
|
|
2341
|
+
case "TypeLiteral":
|
|
2342
|
+
return ast.propertySignatures.map((ps) => ps.name)
|
|
2343
|
+
case "Union":
|
|
2344
|
+
return ast.types.slice(1).reduce(
|
|
2345
|
+
(out: Array<PropertyKey>, ast) => Arr.intersection(out, getPropertyKeys(ast)),
|
|
2346
|
+
getPropertyKeys(ast.types[0])
|
|
2347
|
+
)
|
|
2348
|
+
case "Suspend":
|
|
2349
|
+
return getPropertyKeys(ast.f())
|
|
2350
|
+
case "Refinement":
|
|
2351
|
+
return getPropertyKeys(ast.from)
|
|
2352
|
+
case "Transformation":
|
|
2353
|
+
return getPropertyKeys(ast.to)
|
|
2354
|
+
}
|
|
2355
|
+
return []
|
|
2356
|
+
}
|
|
2357
|
+
|
|
2358
|
+
/** @internal */
|
|
2359
|
+
export const record = (key: AST, value: AST): {
|
|
2360
|
+
propertySignatures: Array<PropertySignature>
|
|
2361
|
+
indexSignatures: Array<IndexSignature>
|
|
2362
|
+
} => {
|
|
2363
|
+
const propertySignatures: Array<PropertySignature> = []
|
|
2364
|
+
const indexSignatures: Array<IndexSignature> = []
|
|
2365
|
+
const go = (key: AST): void => {
|
|
2366
|
+
switch (key._tag) {
|
|
2367
|
+
case "NeverKeyword":
|
|
2368
|
+
break
|
|
2369
|
+
case "StringKeyword":
|
|
2370
|
+
case "SymbolKeyword":
|
|
2371
|
+
case "TemplateLiteral":
|
|
2372
|
+
case "Refinement":
|
|
2373
|
+
indexSignatures.push(new IndexSignature(key, value, true))
|
|
2374
|
+
break
|
|
2375
|
+
case "Literal":
|
|
2376
|
+
if (Predicate.isString(key.literal) || Predicate.isNumber(key.literal)) {
|
|
2377
|
+
propertySignatures.push(new PropertySignature(key.literal, value, false, true))
|
|
2378
|
+
} else {
|
|
2379
|
+
throw new Error(errors_.getASTUnsupportedLiteralErrorMessage(key.literal))
|
|
2380
|
+
}
|
|
2381
|
+
break
|
|
2382
|
+
case "Enums": {
|
|
2383
|
+
for (const [_, name] of key.enums) {
|
|
2384
|
+
propertySignatures.push(new PropertySignature(name, value, false, true))
|
|
2385
|
+
}
|
|
2386
|
+
break
|
|
2387
|
+
}
|
|
2388
|
+
case "UniqueSymbol":
|
|
2389
|
+
propertySignatures.push(new PropertySignature(key.symbol, value, false, true))
|
|
2390
|
+
break
|
|
2391
|
+
case "Union":
|
|
2392
|
+
key.types.forEach(go)
|
|
2393
|
+
break
|
|
2394
|
+
default:
|
|
2395
|
+
throw new Error(errors_.getASTUnsupportedKeySchemaErrorMessage(key))
|
|
2396
|
+
}
|
|
2397
|
+
}
|
|
2398
|
+
go(key)
|
|
2399
|
+
return { propertySignatures, indexSignatures }
|
|
2400
|
+
}
|
|
2401
|
+
|
|
2402
|
+
/**
|
|
2403
|
+
* Equivalent at runtime to the built-in TypeScript utility type `Pick`.
|
|
2404
|
+
*
|
|
2405
|
+
* @since 3.10.0
|
|
2406
|
+
*/
|
|
2407
|
+
export const pick = (ast: AST, keys: ReadonlyArray<PropertyKey>): TypeLiteral | Transformation => {
|
|
2408
|
+
const annotation = getSurrogateAnnotation(ast)
|
|
2409
|
+
if (Option.isSome(annotation)) {
|
|
2410
|
+
return pick(annotation.value, keys)
|
|
2411
|
+
}
|
|
2412
|
+
switch (ast._tag) {
|
|
2413
|
+
case "TypeLiteral": {
|
|
2414
|
+
const pss: Array<PropertySignature> = []
|
|
2415
|
+
const names: Record<PropertyKey, null> = {}
|
|
2416
|
+
for (const ps of ast.propertySignatures) {
|
|
2417
|
+
names[ps.name] = null
|
|
2418
|
+
if (keys.includes(ps.name)) {
|
|
2419
|
+
pss.push(ps)
|
|
2420
|
+
}
|
|
2421
|
+
}
|
|
2422
|
+
for (const key of keys) {
|
|
2423
|
+
if (!(key in names)) {
|
|
2424
|
+
const ps = getTypeLiteralPropertySignature(ast, key)
|
|
2425
|
+
if (ps) {
|
|
2426
|
+
pss.push(ps)
|
|
2427
|
+
}
|
|
2428
|
+
}
|
|
2429
|
+
}
|
|
2430
|
+
return new TypeLiteral(pss, [])
|
|
2431
|
+
}
|
|
2432
|
+
case "Union":
|
|
2433
|
+
return new TypeLiteral(keys.map((name) => getPropertyKeyIndexedAccess(ast, name)), [])
|
|
2434
|
+
case "Suspend":
|
|
2435
|
+
return pick(ast.f(), keys)
|
|
2436
|
+
case "Refinement":
|
|
2437
|
+
return pick(ast.from, keys)
|
|
2438
|
+
case "Transformation": {
|
|
2439
|
+
switch (ast.transformation._tag) {
|
|
2440
|
+
case "ComposeTransformation":
|
|
2441
|
+
return new Transformation(
|
|
2442
|
+
pick(ast.from, keys),
|
|
2443
|
+
pick(ast.to, keys),
|
|
2444
|
+
composeTransformation
|
|
2445
|
+
)
|
|
2446
|
+
case "TypeLiteralTransformation": {
|
|
2447
|
+
const ts: Array<PropertySignatureTransformation> = []
|
|
2448
|
+
const fromKeys: Array<PropertyKey> = []
|
|
2449
|
+
for (const k of keys) {
|
|
2450
|
+
const t = ast.transformation.propertySignatureTransformations.find((t) => t.to === k)
|
|
2451
|
+
if (t) {
|
|
2452
|
+
ts.push(t)
|
|
2453
|
+
fromKeys.push(t.from)
|
|
2454
|
+
} else {
|
|
2455
|
+
fromKeys.push(k)
|
|
2456
|
+
}
|
|
2457
|
+
}
|
|
2458
|
+
return Arr.isNonEmptyReadonlyArray(ts) ?
|
|
2459
|
+
new Transformation(
|
|
2460
|
+
pick(ast.from, fromKeys),
|
|
2461
|
+
pick(ast.to, keys),
|
|
2462
|
+
new TypeLiteralTransformation(ts)
|
|
2463
|
+
) :
|
|
2464
|
+
pick(ast.from, fromKeys)
|
|
2465
|
+
}
|
|
2466
|
+
}
|
|
2467
|
+
}
|
|
2468
|
+
}
|
|
2469
|
+
throw new Error(errors_.getASTUnsupportedSchemaErrorMessage(ast))
|
|
2470
|
+
}
|
|
2471
|
+
|
|
2472
|
+
/**
|
|
2473
|
+
* Equivalent at runtime to the built-in TypeScript utility type `Omit`.
|
|
2474
|
+
*
|
|
2475
|
+
* @since 3.10.0
|
|
2476
|
+
*/
|
|
2477
|
+
export const omit = (ast: AST, keys: ReadonlyArray<PropertyKey>): TypeLiteral | Transformation => {
|
|
2478
|
+
let indexSignatures = getIndexSignatures(ast)
|
|
2479
|
+
if (indexSignatures.length > 0) {
|
|
2480
|
+
if (indexSignatures.some((is) => isStringKeyword(getEncodedParameter(is.parameter)))) {
|
|
2481
|
+
indexSignatures = indexSignatures.filter((is) => !isTemplateLiteral(getEncodedParameter(is.parameter)))
|
|
2482
|
+
}
|
|
2483
|
+
return new TypeLiteral([], indexSignatures)
|
|
2484
|
+
}
|
|
2485
|
+
return pick(ast, getPropertyKeys(ast).filter((name) => !keys.includes(name)))
|
|
2486
|
+
}
|
|
2487
|
+
|
|
2488
|
+
/** @internal */
|
|
2489
|
+
export const orUndefined = (ast: AST): AST => Union.make([ast, undefinedKeyword])
|
|
2490
|
+
|
|
2491
|
+
/**
|
|
2492
|
+
* Equivalent at runtime to the built-in TypeScript utility type `Partial`.
|
|
2493
|
+
*
|
|
2494
|
+
* @since 3.10.0
|
|
2495
|
+
*/
|
|
2496
|
+
export const partial = (ast: AST, options?: { readonly exact: true }): AST => {
|
|
2497
|
+
const exact = options?.exact === true
|
|
2498
|
+
switch (ast._tag) {
|
|
2499
|
+
case "TupleType":
|
|
2500
|
+
return new TupleType(
|
|
2501
|
+
ast.elements.map((e) => new OptionalType(exact ? e.type : orUndefined(e.type), true)),
|
|
2502
|
+
Arr.match(ast.rest, {
|
|
2503
|
+
onEmpty: () => ast.rest,
|
|
2504
|
+
onNonEmpty: (rest) => [new Type(Union.make([...getRestASTs(rest), undefinedKeyword]))]
|
|
2505
|
+
}),
|
|
2506
|
+
ast.isReadonly
|
|
2507
|
+
)
|
|
2508
|
+
case "TypeLiteral":
|
|
2509
|
+
return new TypeLiteral(
|
|
2510
|
+
ast.propertySignatures.map((ps) =>
|
|
2511
|
+
new PropertySignature(ps.name, exact ? ps.type : orUndefined(ps.type), true, ps.isReadonly, ps.annotations)
|
|
2512
|
+
),
|
|
2513
|
+
ast.indexSignatures.map((is) => new IndexSignature(is.parameter, orUndefined(is.type), is.isReadonly))
|
|
2514
|
+
)
|
|
2515
|
+
case "Union":
|
|
2516
|
+
return Union.make(ast.types.map((member) => partial(member, options)))
|
|
2517
|
+
case "Suspend":
|
|
2518
|
+
return new Suspend(() => partial(ast.f(), options))
|
|
2519
|
+
case "Declaration":
|
|
2520
|
+
case "Refinement":
|
|
2521
|
+
throw new Error(errors_.getASTUnsupportedSchemaErrorMessage(ast))
|
|
2522
|
+
case "Transformation": {
|
|
2523
|
+
if (
|
|
2524
|
+
isTypeLiteralTransformation(ast.transformation) &&
|
|
2525
|
+
ast.transformation.propertySignatureTransformations.every(isRenamingPropertySignatureTransformation)
|
|
2526
|
+
) {
|
|
2527
|
+
return new Transformation(partial(ast.from, options), partial(ast.to, options), ast.transformation)
|
|
2528
|
+
}
|
|
2529
|
+
throw new Error(errors_.getASTUnsupportedSchemaErrorMessage(ast))
|
|
2530
|
+
}
|
|
2531
|
+
}
|
|
2532
|
+
return ast
|
|
2533
|
+
}
|
|
2534
|
+
|
|
2535
|
+
/**
|
|
2536
|
+
* Equivalent at runtime to the built-in TypeScript utility type `Required`.
|
|
2537
|
+
*
|
|
2538
|
+
* @since 3.10.0
|
|
2539
|
+
*/
|
|
2540
|
+
export const required = (ast: AST): AST => {
|
|
2541
|
+
switch (ast._tag) {
|
|
2542
|
+
case "TupleType":
|
|
2543
|
+
return new TupleType(
|
|
2544
|
+
ast.elements.map((e) => new OptionalType(e.type, false)),
|
|
2545
|
+
ast.rest,
|
|
2546
|
+
ast.isReadonly
|
|
2547
|
+
)
|
|
2548
|
+
case "TypeLiteral":
|
|
2549
|
+
return new TypeLiteral(
|
|
2550
|
+
ast.propertySignatures.map((f) => new PropertySignature(f.name, f.type, false, f.isReadonly, f.annotations)),
|
|
2551
|
+
ast.indexSignatures
|
|
2552
|
+
)
|
|
2553
|
+
case "Union":
|
|
2554
|
+
return Union.make(ast.types.map((member) => required(member)))
|
|
2555
|
+
case "Suspend":
|
|
2556
|
+
return new Suspend(() => required(ast.f()))
|
|
2557
|
+
case "Declaration":
|
|
2558
|
+
case "Refinement":
|
|
2559
|
+
throw new Error(errors_.getASTUnsupportedSchemaErrorMessage(ast))
|
|
2560
|
+
case "Transformation": {
|
|
2561
|
+
if (
|
|
2562
|
+
isTypeLiteralTransformation(ast.transformation) &&
|
|
2563
|
+
ast.transformation.propertySignatureTransformations.every(isRenamingPropertySignatureTransformation)
|
|
2564
|
+
) {
|
|
2565
|
+
return new Transformation(required(ast.from), required(ast.to), ast.transformation)
|
|
2566
|
+
}
|
|
2567
|
+
throw new Error(errors_.getASTUnsupportedSchemaErrorMessage(ast))
|
|
2568
|
+
}
|
|
2569
|
+
}
|
|
2570
|
+
return ast
|
|
2571
|
+
}
|
|
2572
|
+
|
|
2573
|
+
/**
|
|
2574
|
+
* Creates a new AST with shallow mutability applied to its properties.
|
|
2575
|
+
*
|
|
2576
|
+
* @since 3.10.0
|
|
2577
|
+
*/
|
|
2578
|
+
export const mutable = (ast: AST): AST => {
|
|
2579
|
+
switch (ast._tag) {
|
|
2580
|
+
case "TupleType":
|
|
2581
|
+
return ast.isReadonly === false ? ast : new TupleType(ast.elements, ast.rest, false, ast.annotations)
|
|
2582
|
+
case "TypeLiteral": {
|
|
2583
|
+
const propertySignatures = changeMap(
|
|
2584
|
+
ast.propertySignatures,
|
|
2585
|
+
(ps) =>
|
|
2586
|
+
ps.isReadonly === false ? ps : new PropertySignature(ps.name, ps.type, ps.isOptional, false, ps.annotations)
|
|
2587
|
+
)
|
|
2588
|
+
const indexSignatures = changeMap(
|
|
2589
|
+
ast.indexSignatures,
|
|
2590
|
+
(is) => is.isReadonly === false ? is : new IndexSignature(is.parameter, is.type, false)
|
|
2591
|
+
)
|
|
2592
|
+
return propertySignatures === ast.propertySignatures && indexSignatures === ast.indexSignatures ?
|
|
2593
|
+
ast :
|
|
2594
|
+
new TypeLiteral(propertySignatures, indexSignatures, ast.annotations)
|
|
2595
|
+
}
|
|
2596
|
+
case "Union": {
|
|
2597
|
+
const types = changeMap(ast.types, mutable)
|
|
2598
|
+
return types === ast.types ? ast : Union.make(types, ast.annotations)
|
|
2599
|
+
}
|
|
2600
|
+
case "Suspend":
|
|
2601
|
+
return new Suspend(() => mutable(ast.f()), ast.annotations)
|
|
2602
|
+
case "Refinement": {
|
|
2603
|
+
const from = mutable(ast.from)
|
|
2604
|
+
return from === ast.from ? ast : new Refinement(from, ast.filter, ast.annotations)
|
|
2605
|
+
}
|
|
2606
|
+
case "Transformation": {
|
|
2607
|
+
const from = mutable(ast.from)
|
|
2608
|
+
const to = mutable(ast.to)
|
|
2609
|
+
return from === ast.from && to === ast.to ?
|
|
2610
|
+
ast :
|
|
2611
|
+
new Transformation(from, to, ast.transformation, ast.annotations)
|
|
2612
|
+
}
|
|
2613
|
+
}
|
|
2614
|
+
return ast
|
|
2615
|
+
}
|
|
2616
|
+
|
|
2617
|
+
// -------------------------------------------------------------------------------------
|
|
2618
|
+
// compiler harness
|
|
2619
|
+
// -------------------------------------------------------------------------------------
|
|
2620
|
+
|
|
2621
|
+
/**
|
|
2622
|
+
* @since 3.10.0
|
|
2623
|
+
*/
|
|
2624
|
+
export type Compiler<A> = (ast: AST, path: ReadonlyArray<PropertyKey>) => A
|
|
2625
|
+
|
|
2626
|
+
/**
|
|
2627
|
+
* @since 3.10.0
|
|
2628
|
+
*/
|
|
2629
|
+
export type Match<A> = {
|
|
2630
|
+
[K in AST["_tag"]]: (ast: Extract<AST, { _tag: K }>, compile: Compiler<A>, path: ReadonlyArray<PropertyKey>) => A
|
|
2631
|
+
}
|
|
2632
|
+
|
|
2633
|
+
/**
|
|
2634
|
+
* @since 3.10.0
|
|
2635
|
+
*/
|
|
2636
|
+
export const getCompiler = <A>(match: Match<A>): Compiler<A> => {
|
|
2637
|
+
const compile = (ast: AST, path: ReadonlyArray<PropertyKey>): A => match[ast._tag](ast as any, compile, path)
|
|
2638
|
+
return compile
|
|
2639
|
+
}
|
|
2640
|
+
|
|
2641
|
+
/** @internal */
|
|
2642
|
+
export const pickAnnotations =
|
|
2643
|
+
(annotationIds: ReadonlyArray<symbol>) => (annotated: Annotated): Annotations | undefined => {
|
|
2644
|
+
let out: { [_: symbol]: unknown } | undefined = undefined
|
|
2645
|
+
for (const id of annotationIds) {
|
|
2646
|
+
if (Object.prototype.hasOwnProperty.call(annotated.annotations, id)) {
|
|
2647
|
+
if (out === undefined) {
|
|
2648
|
+
out = {}
|
|
2649
|
+
}
|
|
2650
|
+
out[id] = annotated.annotations[id]
|
|
2651
|
+
}
|
|
2652
|
+
}
|
|
2653
|
+
return out
|
|
2654
|
+
}
|
|
2655
|
+
|
|
2656
|
+
/** @internal */
|
|
2657
|
+
export const omitAnnotations =
|
|
2658
|
+
(annotationIds: ReadonlyArray<symbol>) => (annotated: Annotated): Annotations | undefined => {
|
|
2659
|
+
const out = { ...annotated.annotations }
|
|
2660
|
+
for (const id of annotationIds) {
|
|
2661
|
+
delete out[id]
|
|
2662
|
+
}
|
|
2663
|
+
return out
|
|
2664
|
+
}
|
|
2665
|
+
|
|
2666
|
+
const preserveTransformationAnnotations = pickAnnotations([
|
|
2667
|
+
ExamplesAnnotationId,
|
|
2668
|
+
DefaultAnnotationId,
|
|
2669
|
+
JSONSchemaAnnotationId,
|
|
2670
|
+
ArbitraryAnnotationId,
|
|
2671
|
+
PrettyAnnotationId,
|
|
2672
|
+
EquivalenceAnnotationId
|
|
2673
|
+
])
|
|
2674
|
+
|
|
2675
|
+
/**
|
|
2676
|
+
* @since 3.10.0
|
|
2677
|
+
*/
|
|
2678
|
+
export const typeAST = (ast: AST): AST => {
|
|
2679
|
+
switch (ast._tag) {
|
|
2680
|
+
case "Declaration": {
|
|
2681
|
+
const typeParameters = changeMap(ast.typeParameters, typeAST)
|
|
2682
|
+
return typeParameters === ast.typeParameters ?
|
|
2683
|
+
ast :
|
|
2684
|
+
new Declaration(typeParameters, ast.decodeUnknown, ast.encodeUnknown, ast.annotations)
|
|
2685
|
+
}
|
|
2686
|
+
case "TupleType": {
|
|
2687
|
+
const elements = changeMap(ast.elements, (e) => {
|
|
2688
|
+
const type = typeAST(e.type)
|
|
2689
|
+
return type === e.type ? e : new OptionalType(type, e.isOptional)
|
|
2690
|
+
})
|
|
2691
|
+
const restASTs = getRestASTs(ast.rest)
|
|
2692
|
+
const rest = changeMap(restASTs, typeAST)
|
|
2693
|
+
return elements === ast.elements && rest === restASTs ?
|
|
2694
|
+
ast :
|
|
2695
|
+
new TupleType(elements, rest.map((type) => new Type(type)), ast.isReadonly, ast.annotations)
|
|
2696
|
+
}
|
|
2697
|
+
case "TypeLiteral": {
|
|
2698
|
+
const propertySignatures = changeMap(ast.propertySignatures, (p) => {
|
|
2699
|
+
const type = typeAST(p.type)
|
|
2700
|
+
return type === p.type ? p : new PropertySignature(p.name, type, p.isOptional, p.isReadonly)
|
|
2701
|
+
})
|
|
2702
|
+
const indexSignatures = changeMap(ast.indexSignatures, (is) => {
|
|
2703
|
+
const type = typeAST(is.type)
|
|
2704
|
+
return type === is.type ? is : new IndexSignature(is.parameter, type, is.isReadonly)
|
|
2705
|
+
})
|
|
2706
|
+
return propertySignatures === ast.propertySignatures && indexSignatures === ast.indexSignatures ?
|
|
2707
|
+
ast :
|
|
2708
|
+
new TypeLiteral(propertySignatures, indexSignatures, ast.annotations)
|
|
2709
|
+
}
|
|
2710
|
+
case "Union": {
|
|
2711
|
+
const types = changeMap(ast.types, typeAST)
|
|
2712
|
+
return types === ast.types ? ast : Union.make(types, ast.annotations)
|
|
2713
|
+
}
|
|
2714
|
+
case "Suspend":
|
|
2715
|
+
return new Suspend(() => typeAST(ast.f()), ast.annotations)
|
|
2716
|
+
case "Refinement": {
|
|
2717
|
+
const from = typeAST(ast.from)
|
|
2718
|
+
return from === ast.from ?
|
|
2719
|
+
ast :
|
|
2720
|
+
new Refinement(from, ast.filter, ast.annotations)
|
|
2721
|
+
}
|
|
2722
|
+
case "Transformation": {
|
|
2723
|
+
const preserve = preserveTransformationAnnotations(ast)
|
|
2724
|
+
return typeAST(
|
|
2725
|
+
preserve !== undefined ?
|
|
2726
|
+
annotations(ast.to, preserve) :
|
|
2727
|
+
ast.to
|
|
2728
|
+
)
|
|
2729
|
+
}
|
|
2730
|
+
}
|
|
2731
|
+
return ast
|
|
2732
|
+
}
|
|
2733
|
+
|
|
2734
|
+
function changeMap<A>(
|
|
2735
|
+
as: Arr.NonEmptyReadonlyArray<A>,
|
|
2736
|
+
f: (a: A) => A
|
|
2737
|
+
): Arr.NonEmptyReadonlyArray<A>
|
|
2738
|
+
function changeMap<A>(as: ReadonlyArray<A>, f: (a: A) => A): ReadonlyArray<A>
|
|
2739
|
+
function changeMap<A>(as: ReadonlyArray<A>, f: (a: A) => A): ReadonlyArray<A> {
|
|
2740
|
+
let changed = false
|
|
2741
|
+
const out = Arr.allocate(as.length) as Array<A>
|
|
2742
|
+
for (let i = 0; i < as.length; i++) {
|
|
2743
|
+
const a = as[i]
|
|
2744
|
+
const fa = f(a)
|
|
2745
|
+
if (fa !== a) {
|
|
2746
|
+
changed = true
|
|
2747
|
+
}
|
|
2748
|
+
out[i] = fa
|
|
2749
|
+
}
|
|
2750
|
+
return changed ? out : as
|
|
2751
|
+
}
|
|
2752
|
+
|
|
2753
|
+
/**
|
|
2754
|
+
* Returns the from part of a transformation if it exists
|
|
2755
|
+
*
|
|
2756
|
+
* @internal
|
|
2757
|
+
*/
|
|
2758
|
+
export const getTransformationFrom = (ast: AST): AST | undefined => {
|
|
2759
|
+
switch (ast._tag) {
|
|
2760
|
+
case "Transformation":
|
|
2761
|
+
return ast.from
|
|
2762
|
+
case "Refinement":
|
|
2763
|
+
return getTransformationFrom(ast.from)
|
|
2764
|
+
case "Suspend":
|
|
2765
|
+
return getTransformationFrom(ast.f())
|
|
2766
|
+
}
|
|
2767
|
+
}
|
|
2768
|
+
|
|
2769
|
+
const encodedAST_ = (ast: AST, isBound: boolean): AST => {
|
|
2770
|
+
switch (ast._tag) {
|
|
2771
|
+
case "Declaration": {
|
|
2772
|
+
const typeParameters = changeMap(ast.typeParameters, (ast) => encodedAST_(ast, isBound))
|
|
2773
|
+
return typeParameters === ast.typeParameters ?
|
|
2774
|
+
ast :
|
|
2775
|
+
new Declaration(typeParameters, ast.decodeUnknown, ast.encodeUnknown)
|
|
2776
|
+
}
|
|
2777
|
+
case "TupleType": {
|
|
2778
|
+
const elements = changeMap(ast.elements, (e) => {
|
|
2779
|
+
const type = encodedAST_(e.type, isBound)
|
|
2780
|
+
return type === e.type ? e : new OptionalType(type, e.isOptional)
|
|
2781
|
+
})
|
|
2782
|
+
const restASTs = getRestASTs(ast.rest)
|
|
2783
|
+
const rest = changeMap(restASTs, (ast) => encodedAST_(ast, isBound))
|
|
2784
|
+
return elements === ast.elements && rest === restASTs ?
|
|
2785
|
+
ast :
|
|
2786
|
+
new TupleType(elements, rest.map((ast) => new Type(ast)), ast.isReadonly)
|
|
2787
|
+
}
|
|
2788
|
+
case "TypeLiteral": {
|
|
2789
|
+
const propertySignatures = changeMap(ast.propertySignatures, (ps) => {
|
|
2790
|
+
const type = encodedAST_(ps.type, isBound)
|
|
2791
|
+
return type === ps.type
|
|
2792
|
+
? ps
|
|
2793
|
+
: new PropertySignature(ps.name, type, ps.isOptional, ps.isReadonly)
|
|
2794
|
+
})
|
|
2795
|
+
const indexSignatures = changeMap(ast.indexSignatures, (is) => {
|
|
2796
|
+
const type = encodedAST_(is.type, isBound)
|
|
2797
|
+
return type === is.type ? is : new IndexSignature(is.parameter, type, is.isReadonly)
|
|
2798
|
+
})
|
|
2799
|
+
return propertySignatures === ast.propertySignatures && indexSignatures === ast.indexSignatures ?
|
|
2800
|
+
ast :
|
|
2801
|
+
new TypeLiteral(propertySignatures, indexSignatures)
|
|
2802
|
+
}
|
|
2803
|
+
case "Union": {
|
|
2804
|
+
const types = changeMap(ast.types, (ast) => encodedAST_(ast, isBound))
|
|
2805
|
+
return types === ast.types ? ast : Union.make(types)
|
|
2806
|
+
}
|
|
2807
|
+
case "Suspend": {
|
|
2808
|
+
let borrowedAnnotations = undefined
|
|
2809
|
+
const identifier = getJSONIdentifier(ast)
|
|
2810
|
+
if (Option.isSome(identifier)) {
|
|
2811
|
+
const suffix = isBound ? "Bound" : ""
|
|
2812
|
+
borrowedAnnotations = { [JSONIdentifierAnnotationId]: `${identifier.value}Encoded${suffix}` }
|
|
2813
|
+
}
|
|
2814
|
+
return new Suspend(() => encodedAST_(ast.f(), isBound), borrowedAnnotations)
|
|
2815
|
+
}
|
|
2816
|
+
case "Refinement": {
|
|
2817
|
+
const from = encodedAST_(ast.from, isBound)
|
|
2818
|
+
if (isBound) {
|
|
2819
|
+
if (from === ast.from) return ast
|
|
2820
|
+
if (getTransformationFrom(ast.from) === undefined && hasStableFilter(ast)) {
|
|
2821
|
+
return new Refinement(from, ast.filter, ast.annotations)
|
|
2822
|
+
}
|
|
2823
|
+
return from
|
|
2824
|
+
} else {
|
|
2825
|
+
return from
|
|
2826
|
+
}
|
|
2827
|
+
}
|
|
2828
|
+
case "Transformation":
|
|
2829
|
+
return encodedAST_(ast.from, isBound)
|
|
2830
|
+
}
|
|
2831
|
+
return ast
|
|
2832
|
+
}
|
|
2833
|
+
|
|
2834
|
+
/**
|
|
2835
|
+
* @since 3.10.0
|
|
2836
|
+
*/
|
|
2837
|
+
export const encodedAST = (ast: AST): AST => encodedAST_(ast, false)
|
|
2838
|
+
|
|
2839
|
+
/**
|
|
2840
|
+
* @since 3.10.0
|
|
2841
|
+
*/
|
|
2842
|
+
export const encodedBoundAST = (ast: AST): AST => encodedAST_(ast, true)
|
|
2843
|
+
|
|
2844
|
+
const toJSONAnnotations = (annotations: Annotations): object => {
|
|
2845
|
+
const out: Record<string, unknown> = {}
|
|
2846
|
+
for (const k of Object.getOwnPropertySymbols(annotations)) {
|
|
2847
|
+
out[String(k)] = annotations[k]
|
|
2848
|
+
}
|
|
2849
|
+
return out
|
|
2850
|
+
}
|
|
2851
|
+
|
|
2852
|
+
/** @internal */
|
|
2853
|
+
export const getEncodedParameter = (
|
|
2854
|
+
ast: Parameter
|
|
2855
|
+
): StringKeyword | SymbolKeyword | TemplateLiteral => {
|
|
2856
|
+
switch (ast._tag) {
|
|
2857
|
+
case "StringKeyword":
|
|
2858
|
+
case "SymbolKeyword":
|
|
2859
|
+
case "TemplateLiteral":
|
|
2860
|
+
return ast
|
|
2861
|
+
case "Refinement":
|
|
2862
|
+
return getEncodedParameter(ast.from)
|
|
2863
|
+
}
|
|
2864
|
+
}
|
|
2865
|
+
|
|
2866
|
+
/** @internal */
|
|
2867
|
+
export const equals = (self: AST, that: AST): boolean => {
|
|
2868
|
+
switch (self._tag) {
|
|
2869
|
+
case "Literal":
|
|
2870
|
+
return isLiteral(that) && that.literal === self.literal
|
|
2871
|
+
case "UniqueSymbol":
|
|
2872
|
+
return isUniqueSymbol(that) && that.symbol === self.symbol
|
|
2873
|
+
case "UndefinedKeyword":
|
|
2874
|
+
case "VoidKeyword":
|
|
2875
|
+
case "NeverKeyword":
|
|
2876
|
+
case "UnknownKeyword":
|
|
2877
|
+
case "AnyKeyword":
|
|
2878
|
+
case "StringKeyword":
|
|
2879
|
+
case "NumberKeyword":
|
|
2880
|
+
case "BooleanKeyword":
|
|
2881
|
+
case "BigIntKeyword":
|
|
2882
|
+
case "SymbolKeyword":
|
|
2883
|
+
case "ObjectKeyword":
|
|
2884
|
+
return that._tag === self._tag
|
|
2885
|
+
case "TemplateLiteral":
|
|
2886
|
+
return isTemplateLiteral(that) && that.head === self.head && equalsTemplateLiteralSpan(that.spans, self.spans)
|
|
2887
|
+
case "Enums":
|
|
2888
|
+
return isEnums(that) && equalsEnums(that.enums, self.enums)
|
|
2889
|
+
case "Union":
|
|
2890
|
+
return isUnion(that) && equalsUnion(self.types, that.types)
|
|
2891
|
+
case "Refinement":
|
|
2892
|
+
case "TupleType":
|
|
2893
|
+
case "TypeLiteral":
|
|
2894
|
+
case "Suspend":
|
|
2895
|
+
case "Transformation":
|
|
2896
|
+
case "Declaration":
|
|
2897
|
+
return self === that
|
|
2898
|
+
}
|
|
2899
|
+
}
|
|
2900
|
+
|
|
2901
|
+
const equalsTemplateLiteralSpan = Arr.getEquivalence<TemplateLiteralSpan>((self, that): boolean => {
|
|
2902
|
+
return self.literal === that.literal && equals(self.type, that.type)
|
|
2903
|
+
})
|
|
2904
|
+
|
|
2905
|
+
const equalsEnums = Arr.getEquivalence<readonly [string, string | number]>((self, that) =>
|
|
2906
|
+
that[0] === self[0] && that[1] === self[1]
|
|
2907
|
+
)
|
|
2908
|
+
|
|
2909
|
+
const equalsUnion = Arr.getEquivalence<AST>(equals)
|
|
2910
|
+
|
|
2911
|
+
const intersection = Arr.intersectionWith(equals)
|
|
2912
|
+
|
|
2913
|
+
const _keyof = (ast: AST): Array<AST> => {
|
|
2914
|
+
switch (ast._tag) {
|
|
2915
|
+
case "Declaration": {
|
|
2916
|
+
const annotation = getSurrogateAnnotation(ast)
|
|
2917
|
+
if (Option.isSome(annotation)) {
|
|
2918
|
+
return _keyof(annotation.value)
|
|
2919
|
+
}
|
|
2920
|
+
break
|
|
2921
|
+
}
|
|
2922
|
+
case "TypeLiteral":
|
|
2923
|
+
return ast.propertySignatures.map((p): AST =>
|
|
2924
|
+
Predicate.isSymbol(p.name) ? new UniqueSymbol(p.name) : new Literal(p.name)
|
|
2925
|
+
).concat(ast.indexSignatures.map((is) => getEncodedParameter(is.parameter)))
|
|
2926
|
+
case "Suspend":
|
|
2927
|
+
return _keyof(ast.f())
|
|
2928
|
+
case "Union":
|
|
2929
|
+
return ast.types.slice(1).reduce(
|
|
2930
|
+
(out: Array<AST>, ast) => intersection(out, _keyof(ast)),
|
|
2931
|
+
_keyof(ast.types[0])
|
|
2932
|
+
)
|
|
2933
|
+
case "Transformation":
|
|
2934
|
+
return _keyof(ast.to)
|
|
2935
|
+
}
|
|
2936
|
+
throw new Error(errors_.getASTUnsupportedSchemaErrorMessage(ast))
|
|
2937
|
+
}
|
|
2938
|
+
|
|
2939
|
+
/** @internal */
|
|
2940
|
+
export const compose = (ab: AST, cd: AST): AST => new Transformation(ab, cd, composeTransformation)
|
|
2941
|
+
|
|
2942
|
+
/** @internal */
|
|
2943
|
+
export const rename = (ast: AST, mapping: { readonly [K in PropertyKey]?: PropertyKey }): AST => {
|
|
2944
|
+
switch (ast._tag) {
|
|
2945
|
+
case "TypeLiteral": {
|
|
2946
|
+
const propertySignatureTransformations: Array<PropertySignatureTransformation> = []
|
|
2947
|
+
for (const key of Reflect.ownKeys(mapping)) {
|
|
2948
|
+
const name = mapping[key]
|
|
2949
|
+
if (name !== undefined) {
|
|
2950
|
+
propertySignatureTransformations.push(
|
|
2951
|
+
new PropertySignatureTransformation(
|
|
2952
|
+
key,
|
|
2953
|
+
name,
|
|
2954
|
+
identity,
|
|
2955
|
+
identity
|
|
2956
|
+
)
|
|
2957
|
+
)
|
|
2958
|
+
}
|
|
2959
|
+
}
|
|
2960
|
+
if (propertySignatureTransformations.length === 0) {
|
|
2961
|
+
return ast
|
|
2962
|
+
}
|
|
2963
|
+
return new Transformation(
|
|
2964
|
+
ast,
|
|
2965
|
+
new TypeLiteral(
|
|
2966
|
+
ast.propertySignatures.map((ps) => {
|
|
2967
|
+
const name = mapping[ps.name]
|
|
2968
|
+
return new PropertySignature(
|
|
2969
|
+
name === undefined ? ps.name : name,
|
|
2970
|
+
typeAST(ps.type),
|
|
2971
|
+
ps.isOptional,
|
|
2972
|
+
ps.isReadonly,
|
|
2973
|
+
ps.annotations
|
|
2974
|
+
)
|
|
2975
|
+
}),
|
|
2976
|
+
ast.indexSignatures
|
|
2977
|
+
),
|
|
2978
|
+
new TypeLiteralTransformation(propertySignatureTransformations)
|
|
2979
|
+
)
|
|
2980
|
+
}
|
|
2981
|
+
case "Union":
|
|
2982
|
+
return Union.make(ast.types.map((ast) => rename(ast, mapping)))
|
|
2983
|
+
case "Suspend":
|
|
2984
|
+
return new Suspend(() => rename(ast.f(), mapping))
|
|
2985
|
+
case "Transformation":
|
|
2986
|
+
return compose(ast, rename(typeAST(ast), mapping))
|
|
2987
|
+
}
|
|
2988
|
+
throw new Error(errors_.getASTUnsupportedRenameSchemaErrorMessage(ast))
|
|
2989
|
+
}
|
|
2990
|
+
|
|
2991
|
+
const formatKeyword = (ast: AST): string => Option.getOrElse(getExpected(ast), () => ast._tag)
|
|
2992
|
+
|
|
2993
|
+
function getBrands(ast: Annotated): string {
|
|
2994
|
+
return Option.match(getBrandAnnotation(ast), {
|
|
2995
|
+
onNone: () => "",
|
|
2996
|
+
onSome: (brands) => brands.map((brand) => ` & Brand<${Inspectable.formatUnknown(brand)}>`).join("")
|
|
2997
|
+
})
|
|
2998
|
+
}
|
|
2999
|
+
|
|
3000
|
+
const getOrElseExpected = (ast: Annotated): Option.Option<string> =>
|
|
3001
|
+
getTitleAnnotation(ast).pipe(
|
|
3002
|
+
Option.orElse(() => getDescriptionAnnotation(ast)),
|
|
3003
|
+
Option.orElse(() => getAutoTitleAnnotation(ast)),
|
|
3004
|
+
Option.map((s) => s + getBrands(ast))
|
|
3005
|
+
)
|
|
3006
|
+
|
|
3007
|
+
const getExpected = (ast: Annotated): Option.Option<string> =>
|
|
3008
|
+
Option.orElse(getIdentifierAnnotation(ast), () => getOrElseExpected(ast))
|
|
3009
|
+
|
|
3010
|
+
/** @internal */
|
|
3011
|
+
export const pruneUndefined = (
|
|
3012
|
+
ast: AST,
|
|
3013
|
+
self: (ast: AST) => AST | undefined,
|
|
3014
|
+
onTransformation: (ast: Transformation) => AST | undefined
|
|
3015
|
+
): AST | undefined => {
|
|
3016
|
+
switch (ast._tag) {
|
|
3017
|
+
case "UndefinedKeyword":
|
|
3018
|
+
return neverKeyword
|
|
3019
|
+
case "Union": {
|
|
3020
|
+
const types: Array<AST> = []
|
|
3021
|
+
let hasUndefined = false
|
|
3022
|
+
for (const type of ast.types) {
|
|
3023
|
+
const pruned = self(type)
|
|
3024
|
+
if (pruned) {
|
|
3025
|
+
hasUndefined = true
|
|
3026
|
+
if (!isNeverKeyword(pruned)) {
|
|
3027
|
+
types.push(pruned)
|
|
3028
|
+
}
|
|
3029
|
+
} else {
|
|
3030
|
+
types.push(type)
|
|
3031
|
+
}
|
|
3032
|
+
}
|
|
3033
|
+
if (hasUndefined) {
|
|
3034
|
+
return Union.make(types)
|
|
3035
|
+
}
|
|
3036
|
+
break
|
|
3037
|
+
}
|
|
3038
|
+
case "Suspend":
|
|
3039
|
+
return self(ast.f())
|
|
3040
|
+
case "Transformation":
|
|
3041
|
+
return onTransformation(ast)
|
|
3042
|
+
}
|
|
3043
|
+
}
|