effect 4.0.4 → 4.0.6
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/ai-docs/package.json +1 -1
- package/ai-docs/src/06_schedule/10_schedules.ts +5 -4
- package/ai-docs/src/52_graphql/10_basics.ts +19 -13
- package/ai-docs/src/52_graphql/30_batching.ts +6 -4
- package/ai-docs/src/52_graphql/40_aliased-batching.ts +6 -4
- package/ai-docs/tsconfig.json +3 -1
- package/dist/Array.d.ts +207 -58
- package/dist/Array.d.ts.map +1 -1
- package/dist/Array.js +45 -22
- package/dist/Array.js.map +1 -1
- package/dist/Bytes.d.ts +79 -0
- package/dist/Bytes.d.ts.map +1 -0
- package/dist/Bytes.js +109 -0
- package/dist/Bytes.js.map +1 -0
- package/dist/Channel.d.ts +187 -14
- package/dist/Channel.d.ts.map +1 -1
- package/dist/Channel.js +142 -33
- package/dist/Channel.js.map +1 -1
- package/dist/ChannelSchema.d.ts.map +1 -1
- package/dist/ChannelSchema.js.map +1 -1
- package/dist/Chunk.d.ts +39 -21
- package/dist/Chunk.d.ts.map +1 -1
- package/dist/Chunk.js +26 -17
- package/dist/Chunk.js.map +1 -1
- package/dist/Config.d.ts.map +1 -1
- package/dist/Config.js +8 -3
- package/dist/Config.js.map +1 -1
- package/dist/ConfigProvider.d.ts.map +1 -1
- package/dist/ConfigProvider.js +34 -32
- package/dist/ConfigProvider.js.map +1 -1
- package/dist/Cron.d.ts +2 -2
- package/dist/Cron.d.ts.map +1 -1
- package/dist/Cron.js +6 -3
- package/dist/Cron.js.map +1 -1
- package/dist/Duration.d.ts.map +1 -1
- package/dist/Duration.js +58 -21
- package/dist/Duration.js.map +1 -1
- package/dist/Effect.d.ts +548 -182
- package/dist/Effect.d.ts.map +1 -1
- package/dist/Effect.js +261 -76
- package/dist/Effect.js.map +1 -1
- package/dist/Equivalence.d.ts +2 -1
- package/dist/Equivalence.d.ts.map +1 -1
- package/dist/Equivalence.js +12 -8
- package/dist/Equivalence.js.map +1 -1
- package/dist/Exit.d.ts +24 -9
- package/dist/Exit.d.ts.map +1 -1
- package/dist/Exit.js +8 -3
- package/dist/Exit.js.map +1 -1
- package/dist/FiberHandle.d.ts +2 -0
- package/dist/FiberHandle.d.ts.map +1 -1
- package/dist/FiberHandle.js +9 -4
- package/dist/FiberHandle.js.map +1 -1
- package/dist/FiberMap.d.ts +2 -0
- package/dist/FiberMap.d.ts.map +1 -1
- package/dist/FiberMap.js +5 -2
- package/dist/FiberMap.js.map +1 -1
- package/dist/FileSystem.d.ts +28 -9
- package/dist/FileSystem.d.ts.map +1 -1
- package/dist/FileSystem.js +3 -0
- package/dist/FileSystem.js.map +1 -1
- package/dist/Graph.d.ts.map +1 -1
- package/dist/Graph.js.map +1 -1
- package/dist/HashSet.d.ts.map +1 -1
- package/dist/HashSet.js.map +1 -1
- package/dist/Iterable.d.ts.map +1 -1
- package/dist/Iterable.js +18 -17
- package/dist/Iterable.js.map +1 -1
- package/dist/JsonSchema.d.ts +9 -3
- package/dist/JsonSchema.d.ts.map +1 -1
- package/dist/JsonSchema.js +19 -3
- package/dist/JsonSchema.js.map +1 -1
- package/dist/Layer.d.ts.map +1 -1
- package/dist/Layer.js +2 -2
- package/dist/Layer.js.map +1 -1
- package/dist/ManagedRuntime.d.ts +19 -1
- package/dist/ManagedRuntime.d.ts.map +1 -1
- package/dist/ManagedRuntime.js +62 -6
- package/dist/ManagedRuntime.js.map +1 -1
- package/dist/Match.d.ts +20 -6
- package/dist/Match.d.ts.map +1 -1
- package/dist/Match.js +2 -2
- package/dist/Match.js.map +1 -1
- package/dist/Metric.d.ts +132 -0
- package/dist/Metric.d.ts.map +1 -1
- package/dist/Metric.js +197 -25
- package/dist/Metric.js.map +1 -1
- package/dist/MutableHashMap.d.ts.map +1 -1
- package/dist/MutableHashMap.js.map +1 -1
- package/dist/Number.js +2 -2
- package/dist/Number.js.map +1 -1
- package/dist/Optic.d.ts.map +1 -1
- package/dist/Optic.js.map +1 -1
- package/dist/Path.d.ts +37 -5
- package/dist/Path.d.ts.map +1 -1
- package/dist/Path.js +44 -6
- package/dist/Path.js.map +1 -1
- package/dist/PubSub.d.ts.map +1 -1
- package/dist/PubSub.js +12 -7
- package/dist/PubSub.js.map +1 -1
- package/dist/Queue.d.ts +4 -1
- package/dist/Queue.d.ts.map +1 -1
- package/dist/Queue.js +4 -1
- package/dist/Queue.js.map +1 -1
- package/dist/Random.d.ts.map +1 -1
- package/dist/Random.js +1 -1
- package/dist/Random.js.map +1 -1
- package/dist/RcMap.d.ts +12 -7
- package/dist/RcMap.d.ts.map +1 -1
- package/dist/RcMap.js +9 -6
- package/dist/RcMap.js.map +1 -1
- package/dist/Record.d.ts +51 -0
- package/dist/Record.d.ts.map +1 -1
- package/dist/Record.js +17 -0
- package/dist/Record.js.map +1 -1
- package/dist/Ref.d.ts.map +1 -1
- package/dist/Ref.js.map +1 -1
- package/dist/References.d.ts +5 -4
- package/dist/References.d.ts.map +1 -1
- package/dist/References.js +5 -4
- package/dist/References.js.map +1 -1
- package/dist/RequestResolver.d.ts +31 -1
- package/dist/RequestResolver.d.ts.map +1 -1
- package/dist/RequestResolver.js +39 -4
- package/dist/RequestResolver.js.map +1 -1
- package/dist/Resource.js +1 -1
- package/dist/Resource.js.map +1 -1
- package/dist/Runtime.d.ts +3 -3
- package/dist/Runtime.d.ts.map +1 -1
- package/dist/Runtime.js +18 -15
- package/dist/Runtime.js.map +1 -1
- package/dist/Schedule.d.ts.map +1 -1
- package/dist/Schedule.js.map +1 -1
- package/dist/Schema.d.ts +383 -326
- package/dist/Schema.d.ts.map +1 -1
- package/dist/Schema.js +338 -17
- package/dist/Schema.js.map +1 -1
- package/dist/SchemaAST.d.ts +5 -5
- package/dist/SchemaAST.d.ts.map +1 -1
- package/dist/SchemaAST.js +24 -8
- package/dist/SchemaAST.js.map +1 -1
- package/dist/SchemaGetter.d.ts +8 -3
- package/dist/SchemaGetter.d.ts.map +1 -1
- package/dist/SchemaGetter.js +15 -5
- package/dist/SchemaGetter.js.map +1 -1
- package/dist/SchemaIssue.d.ts +4 -4
- package/dist/SchemaIssue.d.ts.map +1 -1
- package/dist/SchemaIssue.js +29 -51
- package/dist/SchemaIssue.js.map +1 -1
- package/dist/SchemaRepresentation.d.ts +56 -1
- package/dist/SchemaRepresentation.d.ts.map +1 -1
- package/dist/SchemaRepresentation.js +18 -0
- package/dist/SchemaRepresentation.js.map +1 -1
- package/dist/SchemaTransformation.d.ts +1 -1
- package/dist/SchemaTransformation.js +1 -1
- package/dist/Scope.d.ts +12 -2
- package/dist/Scope.d.ts.map +1 -1
- package/dist/Scope.js +5 -0
- package/dist/Scope.js.map +1 -1
- package/dist/ScopedCache.d.ts +10 -7
- package/dist/ScopedCache.d.ts.map +1 -1
- package/dist/ScopedCache.js +9 -5
- package/dist/ScopedCache.js.map +1 -1
- package/dist/SemVer.d.ts +1196 -0
- package/dist/SemVer.d.ts.map +1 -0
- package/dist/SemVer.js +756 -0
- package/dist/SemVer.js.map +1 -0
- package/dist/SemVerRange.d.ts +559 -0
- package/dist/SemVerRange.d.ts.map +1 -0
- package/dist/SemVerRange.js +551 -0
- package/dist/SemVerRange.js.map +1 -0
- package/dist/Sink.d.ts.map +1 -1
- package/dist/Sink.js +6 -2
- package/dist/Sink.js.map +1 -1
- package/dist/Stream.d.ts +235 -8
- package/dist/Stream.d.ts.map +1 -1
- package/dist/Stream.js +145 -60
- package/dist/Stream.js.map +1 -1
- package/dist/String.d.ts +16 -2
- package/dist/String.d.ts.map +1 -1
- package/dist/String.js +25 -10
- package/dist/String.js.map +1 -1
- package/dist/TextDiff.d.ts +399 -0
- package/dist/TextDiff.d.ts.map +1 -0
- package/dist/TextDiff.js +634 -0
- package/dist/TextDiff.js.map +1 -0
- package/dist/TxHashMap.d.ts.map +1 -1
- package/dist/TxHashMap.js.map +1 -1
- package/dist/TxHashSet.d.ts.map +1 -1
- package/dist/TxHashSet.js.map +1 -1
- package/dist/TxRef.d.ts.map +1 -1
- package/dist/TxRef.js +3 -2
- package/dist/TxRef.js.map +1 -1
- package/dist/ai/AiError.d.ts +78 -14
- package/dist/ai/AiError.d.ts.map +1 -1
- package/dist/ai/AiError.js +51 -3
- package/dist/ai/AiError.js.map +1 -1
- package/dist/ai/Chat.d.ts +1 -2
- package/dist/ai/Chat.d.ts.map +1 -1
- package/dist/ai/Chat.js +6 -3
- package/dist/ai/Chat.js.map +1 -1
- package/dist/ai/Decision.d.ts +116 -20
- package/dist/ai/Decision.d.ts.map +1 -1
- package/dist/ai/Decision.js +37 -3
- package/dist/ai/Decision.js.map +1 -1
- package/dist/ai/DecisionModel.d.ts +129 -11
- package/dist/ai/DecisionModel.d.ts.map +1 -1
- package/dist/ai/DecisionModel.js +183 -95
- package/dist/ai/DecisionModel.js.map +1 -1
- package/dist/ai/EmbeddingModel.d.ts +10 -0
- package/dist/ai/EmbeddingModel.d.ts.map +1 -1
- package/dist/ai/EmbeddingModel.js +21 -7
- package/dist/ai/EmbeddingModel.js.map +1 -1
- package/dist/ai/LanguageModel.d.ts.map +1 -1
- package/dist/ai/LanguageModel.js +47 -35
- package/dist/ai/LanguageModel.js.map +1 -1
- package/dist/ai/McpClient.d.ts +289 -0
- package/dist/ai/McpClient.d.ts.map +1 -0
- package/dist/ai/McpClient.js +819 -0
- package/dist/ai/McpClient.js.map +1 -0
- package/dist/ai/McpClientError.d.ts +254 -0
- package/dist/ai/McpClientError.d.ts.map +1 -0
- package/dist/ai/McpClientError.js +260 -0
- package/dist/ai/McpClientError.js.map +1 -0
- package/dist/ai/McpProtocol.d.ts +2 -2
- package/dist/ai/McpProtocol.d.ts.map +1 -1
- package/dist/ai/McpSchema.d.ts +368 -235
- package/dist/ai/McpSchema.d.ts.map +1 -1
- package/dist/ai/McpSchema.js +94 -24
- package/dist/ai/McpSchema.js.map +1 -1
- package/dist/ai/McpServer.d.ts +6 -52
- package/dist/ai/McpServer.d.ts.map +1 -1
- package/dist/ai/McpServer.js +27 -50
- package/dist/ai/McpServer.js.map +1 -1
- package/dist/ai/Prompt.d.ts +22 -20
- package/dist/ai/Prompt.d.ts.map +1 -1
- package/dist/ai/Prompt.js +23 -1
- package/dist/ai/Prompt.js.map +1 -1
- package/dist/ai/Response.d.ts +148 -4
- package/dist/ai/Response.d.ts.map +1 -1
- package/dist/ai/Response.js +35 -37
- package/dist/ai/Response.js.map +1 -1
- package/dist/ai/Tool.d.ts +12 -4
- package/dist/ai/Tool.d.ts.map +1 -1
- package/dist/ai/Tool.js.map +1 -1
- package/dist/ai/Toolkit.d.ts +48 -1
- package/dist/ai/Toolkit.d.ts.map +1 -1
- package/dist/ai/Toolkit.js +65 -12
- package/dist/ai/Toolkit.js.map +1 -1
- package/dist/ai/index.d.ts +10 -0
- package/dist/ai/index.d.ts.map +1 -1
- package/dist/ai/index.js +10 -0
- package/dist/ai/index.js.map +1 -1
- package/dist/ai/internal/mcpCore.js.map +1 -1
- package/dist/ai/internal/mcpProtocol/v2024_11_05.js +1 -1
- package/dist/ai/internal/mcpProtocol/v2024_11_05.js.map +1 -1
- package/dist/ai/internal/mcpProtocol/v2025_03_26.js +1 -1
- package/dist/ai/internal/mcpProtocol/v2025_03_26.js.map +1 -1
- package/dist/ai/internal/mcpProtocol/v2025_06_18.js +2 -2
- package/dist/ai/internal/mcpProtocol/v2025_06_18.js.map +1 -1
- package/dist/ai/internal/mcpProtocol/v2025_11_25.js +2 -2
- package/dist/ai/internal/mcpProtocol/v2025_11_25.js.map +1 -1
- package/dist/ai/internal/mcpProtocol/v2026_07_28.js +4 -7
- package/dist/ai/internal/mcpProtocol/v2026_07_28.js.map +1 -1
- package/dist/ai/internal/mcpProtocol.js +16 -2
- package/dist/ai/internal/mcpProtocol.js.map +1 -1
- package/dist/ai/internal/mcpRuntime.js +3 -4
- package/dist/ai/internal/mcpRuntime.js.map +1 -1
- package/dist/ai/internal/mcpSchema/v2024_11_05.js +19 -13
- package/dist/ai/internal/mcpSchema/v2024_11_05.js.map +1 -1
- package/dist/ai/internal/mcpSchema/v2025_03_26.js +3 -2
- package/dist/ai/internal/mcpSchema/v2025_03_26.js.map +1 -1
- package/dist/ai/internal/mcpSchema/v2025_06_18.js +7 -7
- package/dist/ai/internal/mcpSchema/v2025_06_18.js.map +1 -1
- package/dist/ai/internal/mcpSchema/v2025_11_25.js +8 -8
- package/dist/ai/internal/mcpSchema/v2025_11_25.js.map +1 -1
- package/dist/ai/internal/mcpSchema/v2026_07_28.js +43 -42
- package/dist/ai/internal/mcpSchema/v2026_07_28.js.map +1 -1
- package/dist/cli/CliError.d.ts +42 -2
- package/dist/cli/CliError.d.ts.map +1 -1
- package/dist/cli/CliError.js +44 -5
- package/dist/cli/CliError.js.map +1 -1
- package/dist/cli/Command.d.ts +286 -2
- package/dist/cli/Command.d.ts.map +1 -1
- package/dist/cli/Command.js +107 -6
- package/dist/cli/Command.js.map +1 -1
- package/dist/cli/Completions.d.ts +10 -0
- package/dist/cli/Completions.d.ts.map +1 -1
- package/dist/cli/Completions.js.map +1 -1
- package/dist/cli/Flag.d.ts +215 -0
- package/dist/cli/Flag.d.ts.map +1 -1
- package/dist/cli/Flag.js +89 -0
- package/dist/cli/Flag.js.map +1 -1
- package/dist/cli/GlobalFlag.d.ts.map +1 -1
- package/dist/cli/GlobalFlag.js +3 -3
- package/dist/cli/GlobalFlag.js.map +1 -1
- package/dist/cli/Param.d.ts +194 -0
- package/dist/cli/Param.d.ts.map +1 -1
- package/dist/cli/Param.js +86 -0
- package/dist/cli/Param.js.map +1 -1
- package/dist/cli/TerminalCapabilities.d.ts +84 -0
- package/dist/cli/TerminalCapabilities.d.ts.map +1 -0
- package/dist/cli/TerminalCapabilities.js +122 -0
- package/dist/cli/TerminalCapabilities.js.map +1 -0
- package/dist/cli/index.d.ts +5 -0
- package/dist/cli/index.d.ts.map +1 -1
- package/dist/cli/index.js +5 -0
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/internal/command.d.ts +2 -1
- package/dist/cli/internal/command.d.ts.map +1 -1
- package/dist/cli/internal/command.js +7 -3
- package/dist/cli/internal/command.js.map +1 -1
- package/dist/cli/internal/completions/bash.js +7 -5
- package/dist/cli/internal/completions/bash.js.map +1 -1
- package/dist/cli/internal/completions/descriptor.js +16 -1
- package/dist/cli/internal/completions/descriptor.js.map +1 -1
- package/dist/cli/internal/completions/fish.js +12 -10
- package/dist/cli/internal/completions/fish.js.map +1 -1
- package/dist/cli/internal/completions/powershell.js +20 -10
- package/dist/cli/internal/completions/powershell.js.map +1 -1
- package/dist/cli/internal/completions/zsh.js +15 -8
- package/dist/cli/internal/completions/zsh.js.map +1 -1
- package/dist/cli/internal/formatter.d.ts +2 -0
- package/dist/cli/internal/formatter.d.ts.map +1 -0
- package/dist/cli/internal/formatter.js +15 -0
- package/dist/cli/internal/formatter.js.map +1 -0
- package/dist/cli/internal/lexer.js +24 -10
- package/dist/cli/internal/lexer.js.map +1 -1
- package/dist/cli/internal/parser.js +35 -15
- package/dist/cli/internal/parser.js.map +1 -1
- package/dist/cli/internal/wizard.d.ts.map +1 -1
- package/dist/cli/internal/wizard.js +2 -1
- package/dist/cli/internal/wizard.js.map +1 -1
- package/dist/cluster/ClusterCron.d.ts +29 -1
- package/dist/cluster/ClusterCron.d.ts.map +1 -1
- package/dist/cluster/ClusterCron.js +64 -32
- package/dist/cluster/ClusterCron.js.map +1 -1
- package/dist/cluster/ClusterMetrics.d.ts +143 -7
- package/dist/cluster/ClusterMetrics.d.ts.map +1 -1
- package/dist/cluster/ClusterMetrics.js +151 -7
- package/dist/cluster/ClusterMetrics.js.map +1 -1
- package/dist/cluster/ClusterWorkflowEngine.d.ts +2 -1
- package/dist/cluster/ClusterWorkflowEngine.d.ts.map +1 -1
- package/dist/cluster/ClusterWorkflowEngine.js +98 -18
- package/dist/cluster/ClusterWorkflowEngine.js.map +1 -1
- package/dist/cluster/Entity.d.ts +2 -0
- package/dist/cluster/Entity.d.ts.map +1 -1
- package/dist/cluster/Entity.js.map +1 -1
- package/dist/cluster/MessageStorage.d.ts +21 -0
- package/dist/cluster/MessageStorage.d.ts.map +1 -1
- package/dist/cluster/MessageStorage.js +20 -12
- package/dist/cluster/MessageStorage.js.map +1 -1
- package/dist/cluster/Runners.d.ts.map +1 -1
- package/dist/cluster/Runners.js +96 -37
- package/dist/cluster/Runners.js.map +1 -1
- package/dist/cluster/Sharding.d.ts +1 -0
- package/dist/cluster/Sharding.d.ts.map +1 -1
- package/dist/cluster/Sharding.js +95 -32
- package/dist/cluster/Sharding.js.map +1 -1
- package/dist/cluster/ShardingConfig.d.ts +20 -0
- package/dist/cluster/ShardingConfig.d.ts.map +1 -1
- package/dist/cluster/ShardingConfig.js +4 -0
- package/dist/cluster/ShardingConfig.js.map +1 -1
- package/dist/cluster/SqlMessageStorage.d.ts.map +1 -1
- package/dist/cluster/SqlMessageStorage.js +40 -50
- package/dist/cluster/SqlMessageStorage.js.map +1 -1
- package/dist/cluster/SqlRunnerStorage.d.ts +2 -2
- package/dist/cluster/SqlRunnerStorage.d.ts.map +1 -1
- package/dist/cluster/SqlRunnerStorage.js +10 -4
- package/dist/cluster/SqlRunnerStorage.js.map +1 -1
- package/dist/cluster/internal/entityManager.js +66 -9
- package/dist/cluster/internal/entityManager.js.map +1 -1
- package/dist/devtools/DevTools.d.ts +3 -2
- package/dist/devtools/DevTools.d.ts.map +1 -1
- package/dist/devtools/DevTools.js +3 -2
- package/dist/devtools/DevTools.js.map +1 -1
- package/dist/devtools/DevToolsClient.d.ts +11 -0
- package/dist/devtools/DevToolsClient.d.ts.map +1 -1
- package/dist/devtools/DevToolsClient.js +31 -4
- package/dist/devtools/DevToolsClient.js.map +1 -1
- package/dist/encoding/Base64Url.d.ts +29 -0
- package/dist/encoding/Base64Url.d.ts.map +1 -1
- package/dist/encoding/Base64Url.js +29 -0
- package/dist/encoding/Base64Url.js.map +1 -1
- package/dist/encoding/Ini.d.ts.map +1 -1
- package/dist/encoding/Ini.js +3 -0
- package/dist/encoding/Ini.js.map +1 -1
- package/dist/encoding/JsonArray.d.ts +270 -0
- package/dist/encoding/JsonArray.d.ts.map +1 -0
- package/dist/encoding/JsonArray.js +691 -0
- package/dist/encoding/JsonArray.js.map +1 -0
- package/dist/encoding/Ndjson.d.ts +43 -4
- package/dist/encoding/Ndjson.d.ts.map +1 -1
- package/dist/encoding/Ndjson.js +169 -18
- package/dist/encoding/Ndjson.js.map +1 -1
- package/dist/encoding/SchemaBinary.d.ts +9 -1
- package/dist/encoding/SchemaBinary.d.ts.map +1 -1
- package/dist/encoding/SchemaBinary.js +12 -19
- package/dist/encoding/SchemaBinary.js.map +1 -1
- package/dist/encoding/Sse.js +1 -1
- package/dist/encoding/Sse.js.map +1 -1
- package/dist/encoding/Tar.d.ts +309 -0
- package/dist/encoding/Tar.d.ts.map +1 -0
- package/dist/encoding/Tar.js +1182 -0
- package/dist/encoding/Tar.js.map +1 -0
- package/dist/encoding/Toml.js +3 -3
- package/dist/encoding/Toml.js.map +1 -1
- package/dist/encoding/Xml.d.ts +464 -0
- package/dist/encoding/Xml.d.ts.map +1 -0
- package/dist/encoding/Xml.js +1619 -0
- package/dist/encoding/Xml.js.map +1 -0
- package/dist/encoding/Yaml.d.ts +6 -2
- package/dist/encoding/Yaml.d.ts.map +1 -1
- package/dist/encoding/Yaml.js +97 -34
- package/dist/encoding/Yaml.js.map +1 -1
- package/dist/encoding/Zip.d.ts +413 -0
- package/dist/encoding/Zip.d.ts.map +1 -0
- package/dist/encoding/Zip.js +1255 -0
- package/dist/encoding/Zip.js.map +1 -0
- package/dist/encoding/index.d.ts +20 -0
- package/dist/encoding/index.d.ts.map +1 -1
- package/dist/encoding/index.js +20 -0
- package/dist/encoding/index.js.map +1 -1
- package/dist/eventlog/EventJournal.d.ts +90 -5
- package/dist/eventlog/EventJournal.d.ts.map +1 -1
- package/dist/eventlog/EventJournal.js +488 -228
- package/dist/eventlog/EventJournal.js.map +1 -1
- package/dist/eventlog/EventLog.d.ts +180 -12
- package/dist/eventlog/EventLog.d.ts.map +1 -1
- package/dist/eventlog/EventLog.js +394 -146
- package/dist/eventlog/EventLog.js.map +1 -1
- package/dist/eventlog/EventLogEncryption.d.ts +36 -30
- package/dist/eventlog/EventLogEncryption.d.ts.map +1 -1
- package/dist/eventlog/EventLogEncryption.js +97 -38
- package/dist/eventlog/EventLogEncryption.js.map +1 -1
- package/dist/eventlog/EventLogMessage.d.ts +74 -34
- package/dist/eventlog/EventLogMessage.d.ts.map +1 -1
- package/dist/eventlog/EventLogMessage.js +45 -11
- package/dist/eventlog/EventLogMessage.js.map +1 -1
- package/dist/eventlog/EventLogRemote.d.ts +45 -8
- package/dist/eventlog/EventLogRemote.d.ts.map +1 -1
- package/dist/eventlog/EventLogRemote.js +51 -14
- package/dist/eventlog/EventLogRemote.js.map +1 -1
- package/dist/eventlog/EventLogServer.d.ts +46 -3
- package/dist/eventlog/EventLogServer.d.ts.map +1 -1
- package/dist/eventlog/EventLogServer.js +119 -19
- package/dist/eventlog/EventLogServer.js.map +1 -1
- package/dist/eventlog/EventLogServerEncrypted.d.ts +23 -33
- package/dist/eventlog/EventLogServerEncrypted.d.ts.map +1 -1
- package/dist/eventlog/EventLogServerEncrypted.js +97 -70
- package/dist/eventlog/EventLogServerEncrypted.js.map +1 -1
- package/dist/eventlog/EventLogServerUnencrypted.d.ts +39 -5
- package/dist/eventlog/EventLogServerUnencrypted.d.ts.map +1 -1
- package/dist/eventlog/EventLogServerUnencrypted.js +151 -69
- package/dist/eventlog/EventLogServerUnencrypted.js.map +1 -1
- package/dist/eventlog/EventRow.d.ts +288 -0
- package/dist/eventlog/EventRow.d.ts.map +1 -0
- package/dist/eventlog/EventRow.js +435 -0
- package/dist/eventlog/EventRow.js.map +1 -0
- package/dist/eventlog/SqlEventJournal.d.ts +18 -18
- package/dist/eventlog/SqlEventJournal.d.ts.map +1 -1
- package/dist/eventlog/SqlEventJournal.js +387 -159
- package/dist/eventlog/SqlEventJournal.js.map +1 -1
- package/dist/eventlog/SqlEventLogServerEncrypted.d.ts +10 -18
- package/dist/eventlog/SqlEventLogServerEncrypted.d.ts.map +1 -1
- package/dist/eventlog/SqlEventLogServerEncrypted.js +179 -69
- package/dist/eventlog/SqlEventLogServerEncrypted.js.map +1 -1
- package/dist/eventlog/SqlEventLogServerUnencrypted.d.ts +23 -3
- package/dist/eventlog/SqlEventLogServerUnencrypted.d.ts.map +1 -1
- package/dist/eventlog/SqlEventLogServerUnencrypted.js +102 -51
- package/dist/eventlog/SqlEventLogServerUnencrypted.js.map +1 -1
- package/dist/eventlog/index.d.ts +5 -0
- package/dist/eventlog/index.d.ts.map +1 -1
- package/dist/eventlog/index.js +5 -0
- package/dist/eventlog/index.js.map +1 -1
- package/dist/eventlog/internal/conflicts.d.ts +47 -0
- package/dist/eventlog/internal/conflicts.d.ts.map +1 -0
- package/dist/eventlog/internal/conflicts.js +92 -0
- package/dist/eventlog/internal/conflicts.js.map +1 -0
- package/dist/graphql/GraphQLClient.d.ts.map +1 -1
- package/dist/graphql/GraphQLClient.js +12 -5
- package/dist/graphql/GraphQLClient.js.map +1 -1
- package/dist/graphql/GraphQLClientError.d.ts +2 -2
- package/dist/graphql/GraphQLClientError.d.ts.map +1 -1
- package/dist/graphql/GraphQLClientError.js +4 -18
- package/dist/graphql/GraphQLClientError.js.map +1 -1
- package/dist/graphql/GraphQLProtocol.d.ts +252 -11
- package/dist/graphql/GraphQLProtocol.d.ts.map +1 -1
- package/dist/graphql/GraphQLProtocol.js +99 -8
- package/dist/graphql/GraphQLProtocol.js.map +1 -1
- package/dist/graphql/GraphQLResolver.d.ts +3 -1
- package/dist/graphql/GraphQLResolver.d.ts.map +1 -1
- package/dist/graphql/GraphQLResolver.js +91 -19
- package/dist/graphql/GraphQLResolver.js.map +1 -1
- package/dist/http/FetchHttpClient.d.ts +13 -3
- package/dist/http/FetchHttpClient.d.ts.map +1 -1
- package/dist/http/FetchHttpClient.js +56 -6
- package/dist/http/FetchHttpClient.js.map +1 -1
- package/dist/http/FindMyWay/internal/router.js +12 -1
- package/dist/http/FindMyWay/internal/router.js.map +1 -1
- package/dist/http/Headers.d.ts +230 -3
- package/dist/http/Headers.d.ts.map +1 -1
- package/dist/http/Headers.js +267 -5
- package/dist/http/Headers.js.map +1 -1
- package/dist/http/HttpClient.d.ts +105 -0
- package/dist/http/HttpClient.d.ts.map +1 -1
- package/dist/http/HttpClient.js +69 -17
- package/dist/http/HttpClient.js.map +1 -1
- package/dist/http/HttpClientError.d.ts.map +1 -1
- package/dist/http/HttpClientError.js +8 -6
- package/dist/http/HttpClientError.js.map +1 -1
- package/dist/http/HttpClientRequest.d.ts +274 -7
- package/dist/http/HttpClientRequest.d.ts.map +1 -1
- package/dist/http/HttpClientRequest.js +91 -3
- package/dist/http/HttpClientRequest.js.map +1 -1
- package/dist/http/HttpClientResponse.d.ts +53 -0
- package/dist/http/HttpClientResponse.d.ts.map +1 -1
- package/dist/http/HttpClientResponse.js +47 -0
- package/dist/http/HttpClientResponse.js.map +1 -1
- package/dist/http/HttpEffect.d.ts +6 -2
- package/dist/http/HttpEffect.d.ts.map +1 -1
- package/dist/http/HttpEffect.js +21 -17
- package/dist/http/HttpEffect.js.map +1 -1
- package/dist/http/HttpIncomingMessage.d.ts +2 -1
- package/dist/http/HttpIncomingMessage.d.ts.map +1 -1
- package/dist/http/HttpIncomingMessage.js +3 -23
- package/dist/http/HttpIncomingMessage.js.map +1 -1
- package/dist/http/HttpMiddleware.d.ts +179 -2
- package/dist/http/HttpMiddleware.d.ts.map +1 -1
- package/dist/http/HttpMiddleware.js +226 -18
- package/dist/http/HttpMiddleware.js.map +1 -1
- package/dist/http/HttpRouter.d.ts.map +1 -1
- package/dist/http/HttpRouter.js +58 -14
- package/dist/http/HttpRouter.js.map +1 -1
- package/dist/http/HttpServerError.d.ts +5 -2
- package/dist/http/HttpServerError.d.ts.map +1 -1
- package/dist/http/HttpServerError.js +11 -7
- package/dist/http/HttpServerError.js.map +1 -1
- package/dist/http/HttpServerRequest.d.ts +25 -5
- package/dist/http/HttpServerRequest.d.ts.map +1 -1
- package/dist/http/HttpServerRequest.js +38 -12
- package/dist/http/HttpServerRequest.js.map +1 -1
- package/dist/http/HttpServerResponse.d.ts +17 -8
- package/dist/http/HttpServerResponse.d.ts.map +1 -1
- package/dist/http/HttpServerResponse.js +37 -21
- package/dist/http/HttpServerResponse.js.map +1 -1
- package/dist/http/HttpStaticServer.d.ts +0 -12
- package/dist/http/HttpStaticServer.d.ts.map +1 -1
- package/dist/http/HttpStaticServer.js +25 -17
- package/dist/http/HttpStaticServer.js.map +1 -1
- package/dist/http/HttpTraceContext.js +1 -1
- package/dist/http/HttpTraceContext.js.map +1 -1
- package/dist/http/MultipartParser/internal/contentType.d.ts +15 -1
- package/dist/http/MultipartParser/internal/contentType.d.ts.map +1 -1
- package/dist/http/MultipartParser/internal/contentType.js +87 -5
- package/dist/http/MultipartParser/internal/contentType.js.map +1 -1
- package/dist/http/MultipartParser/internal/headers.d.ts.map +1 -1
- package/dist/http/MultipartParser/internal/headers.js +4 -12
- package/dist/http/MultipartParser/internal/headers.js.map +1 -1
- package/dist/http/MultipartParser/internal/multipart.d.ts.map +1 -1
- package/dist/http/MultipartParser/internal/multipart.js +6 -27
- package/dist/http/MultipartParser/internal/multipart.js.map +1 -1
- package/dist/http/Url.d.ts.map +1 -1
- package/dist/http/Url.js +8 -2
- package/dist/http/Url.js.map +1 -1
- package/dist/http/UrlParams.d.ts +112 -8
- package/dist/http/UrlParams.d.ts.map +1 -1
- package/dist/http/UrlParams.js +141 -14
- package/dist/http/UrlParams.js.map +1 -1
- package/dist/http/internal/compression.d.ts +1 -1
- package/dist/http/internal/compression.d.ts.map +1 -1
- package/dist/http/internal/compression.js +2 -10
- package/dist/http/internal/compression.js.map +1 -1
- package/dist/http/internal/compressionBody.d.ts +2 -0
- package/dist/http/internal/compressionBody.d.ts.map +1 -0
- package/dist/http/internal/compressionBody.js +36 -0
- package/dist/http/internal/compressionBody.js.map +1 -0
- package/dist/http/internal/decompression.d.ts +2 -0
- package/dist/http/internal/decompression.d.ts.map +1 -0
- package/dist/http/internal/decompression.js +168 -0
- package/dist/http/internal/decompression.js.map +1 -0
- package/dist/http/internal/lazyStream.d.ts +2 -0
- package/dist/http/internal/lazyStream.d.ts.map +1 -0
- package/dist/http/internal/lazyStream.js +18 -0
- package/dist/http/internal/lazyStream.js.map +1 -0
- package/dist/http/internal/requestState.d.ts +2 -0
- package/dist/http/internal/requestState.d.ts.map +1 -0
- package/dist/http/internal/requestState.js +28 -0
- package/dist/http/internal/requestState.js.map +1 -0
- package/dist/http/internal/tracing.js +14 -4
- package/dist/http/internal/tracing.js.map +1 -1
- package/dist/http/internal/urlParams.d.ts +2 -0
- package/dist/http/internal/urlParams.d.ts.map +1 -0
- package/dist/http/internal/urlParams.js +4 -0
- package/dist/http/internal/urlParams.js.map +1 -0
- package/dist/http/internal/webResponse.d.ts +2 -0
- package/dist/http/internal/webResponse.d.ts.map +1 -0
- package/dist/http/internal/webResponse.js +12 -0
- package/dist/http/internal/webResponse.js.map +1 -0
- package/dist/http-api/HttpApi.js +1 -1
- package/dist/http-api/HttpApi.js.map +1 -1
- package/dist/http-api/HttpApiBuilder.d.ts.map +1 -1
- package/dist/http-api/HttpApiBuilder.js +121 -18
- package/dist/http-api/HttpApiBuilder.js.map +1 -1
- package/dist/http-api/HttpApiClient.d.ts +29 -4
- package/dist/http-api/HttpApiClient.d.ts.map +1 -1
- package/dist/http-api/HttpApiClient.js +85 -24
- package/dist/http-api/HttpApiClient.js.map +1 -1
- package/dist/http-api/HttpApiEndpoint.d.ts +55 -29
- package/dist/http-api/HttpApiEndpoint.d.ts.map +1 -1
- package/dist/http-api/HttpApiEndpoint.js +49 -5
- package/dist/http-api/HttpApiEndpoint.js.map +1 -1
- package/dist/http-api/HttpApiError.d.ts +58 -0
- package/dist/http-api/HttpApiError.d.ts.map +1 -1
- package/dist/http-api/HttpApiError.js +38 -12
- package/dist/http-api/HttpApiError.js.map +1 -1
- package/dist/http-api/HttpApiScalar.d.ts +2 -1
- package/dist/http-api/HttpApiScalar.d.ts.map +1 -1
- package/dist/http-api/HttpApiScalar.js +6 -3
- package/dist/http-api/HttpApiScalar.js.map +1 -1
- package/dist/http-api/HttpApiSchema.d.ts +191 -9
- package/dist/http-api/HttpApiSchema.d.ts.map +1 -1
- package/dist/http-api/HttpApiSchema.js +137 -4
- package/dist/http-api/HttpApiSchema.js.map +1 -1
- package/dist/http-api/HttpApiSwagger.d.ts +5 -0
- package/dist/http-api/HttpApiSwagger.d.ts.map +1 -1
- package/dist/http-api/HttpApiSwagger.js +14 -4
- package/dist/http-api/HttpApiSwagger.js.map +1 -1
- package/dist/http-api/HttpApiTest.d.ts +13 -2
- package/dist/http-api/HttpApiTest.d.ts.map +1 -1
- package/dist/http-api/HttpApiTest.js +30 -9
- package/dist/http-api/HttpApiTest.js.map +1 -1
- package/dist/http-api/OpenApi.d.ts +17 -3
- package/dist/http-api/OpenApi.d.ts.map +1 -1
- package/dist/http-api/OpenApi.js +57 -32
- package/dist/http-api/OpenApi.js.map +1 -1
- package/dist/http-api/internal/path.js +35 -10
- package/dist/http-api/internal/path.js.map +1 -1
- package/dist/index.d.ts +20 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +20 -0
- package/dist/index.js.map +1 -1
- package/dist/internal/core.js +18 -2
- package/dist/internal/core.js.map +1 -1
- package/dist/internal/dateTime.js +19 -7
- package/dist/internal/dateTime.js.map +1 -1
- package/dist/internal/effect.js +89 -76
- package/dist/internal/effect.js.map +1 -1
- package/dist/internal/graphql.js +12 -2
- package/dist/internal/graphql.js.map +1 -1
- package/dist/internal/hashMap.js +2 -2
- package/dist/internal/hashMap.js.map +1 -1
- package/dist/internal/hydration.d.ts +2 -0
- package/dist/internal/hydration.d.ts.map +1 -0
- package/dist/internal/hydration.js +15 -0
- package/dist/internal/hydration.js.map +1 -0
- package/dist/internal/inflate.d.ts +2 -0
- package/dist/internal/inflate.d.ts.map +1 -0
- package/dist/internal/inflate.js +680 -0
- package/dist/internal/inflate.js.map +1 -0
- package/dist/internal/record.js +6 -0
- package/dist/internal/record.js.map +1 -1
- package/dist/internal/request.js +20 -7
- package/dist/internal/request.js.map +1 -1
- package/dist/internal/schedule.js +17 -22
- package/dist/internal/schedule.js.map +1 -1
- package/dist/internal/schema/fromJsonSchemaDocument.js +136 -126
- package/dist/internal/schema/fromJsonSchemaDocument.js.map +1 -1
- package/dist/internal/schema/interpreter.js +51 -36
- package/dist/internal/schema/interpreter.js.map +1 -1
- package/dist/internal/schema/standardSchema.js +34 -33
- package/dist/internal/schema/standardSchema.js.map +1 -1
- package/dist/internal/schema/toCodeDocument.js +7 -2
- package/dist/internal/schema/toCodeDocument.js.map +1 -1
- package/dist/internal/schema/toCodec.js +86 -1
- package/dist/internal/schema/toCodec.js.map +1 -1
- package/dist/internal/schema/toFormatter.js +5 -5
- package/dist/internal/schema/toFormatter.js.map +1 -1
- package/dist/internal/schema/toJsonSchemaDocument.js +60 -38
- package/dist/internal/schema/toJsonSchemaDocument.js.map +1 -1
- package/dist/internal/trie.js +1 -3
- package/dist/internal/trie.js.map +1 -1
- package/dist/internal/uuid.js +7 -3
- package/dist/internal/uuid.js.map +1 -1
- package/dist/internal/version.js +1 -1
- package/dist/net/NetAddress.d.ts.map +1 -1
- package/dist/net/NetAddress.js +2 -8
- package/dist/net/NetAddress.js.map +1 -1
- package/dist/observability/Otlp.d.ts +15 -0
- package/dist/observability/Otlp.d.ts.map +1 -1
- package/dist/observability/Otlp.js +3 -0
- package/dist/observability/Otlp.js.map +1 -1
- package/dist/observability/OtlpExporter.d.ts +8 -0
- package/dist/observability/OtlpExporter.d.ts.map +1 -1
- package/dist/observability/OtlpExporter.js +15 -13
- package/dist/observability/OtlpExporter.js.map +1 -1
- package/dist/observability/OtlpLogger.d.ts +17 -0
- package/dist/observability/OtlpLogger.d.ts.map +1 -1
- package/dist/observability/OtlpLogger.js +14 -1
- package/dist/observability/OtlpLogger.js.map +1 -1
- package/dist/observability/OtlpMetrics.d.ts +17 -0
- package/dist/observability/OtlpMetrics.d.ts.map +1 -1
- package/dist/observability/OtlpMetrics.js +18 -3
- package/dist/observability/OtlpMetrics.js.map +1 -1
- package/dist/observability/OtlpResource.d.ts +3 -1
- package/dist/observability/OtlpResource.d.ts.map +1 -1
- package/dist/observability/OtlpResource.js +11 -4
- package/dist/observability/OtlpResource.js.map +1 -1
- package/dist/observability/OtlpSerialization.d.ts +5 -0
- package/dist/observability/OtlpSerialization.d.ts.map +1 -1
- package/dist/observability/OtlpSerialization.js +14 -3
- package/dist/observability/OtlpSerialization.js.map +1 -1
- package/dist/observability/OtlpTracer.d.ts +17 -0
- package/dist/observability/OtlpTracer.d.ts.map +1 -1
- package/dist/observability/OtlpTracer.js +15 -2
- package/dist/observability/OtlpTracer.js.map +1 -1
- package/dist/observability/internal/protobuf.d.ts +0 -9
- package/dist/observability/internal/protobuf.d.ts.map +1 -1
- package/dist/observability/internal/protobuf.js +2 -10
- package/dist/observability/internal/protobuf.js.map +1 -1
- package/dist/persistence/PersistedCache.d.ts.map +1 -1
- package/dist/persistence/PersistedCache.js +1 -1
- package/dist/persistence/PersistedCache.js.map +1 -1
- package/dist/persistence/PersistedQueue.d.ts +6 -2
- package/dist/persistence/PersistedQueue.d.ts.map +1 -1
- package/dist/persistence/PersistedQueue.js +162 -84
- package/dist/persistence/PersistedQueue.js.map +1 -1
- package/dist/persistence/Persistence.d.ts +28 -0
- package/dist/persistence/Persistence.d.ts.map +1 -1
- package/dist/persistence/Persistence.js +36 -8
- package/dist/persistence/Persistence.js.map +1 -1
- package/dist/persistence/RateLimiter.d.ts.map +1 -1
- package/dist/persistence/RateLimiter.js +8 -12
- package/dist/persistence/RateLimiter.js.map +1 -1
- package/dist/persistence/UserDirectories.d.ts +129 -0
- package/dist/persistence/UserDirectories.d.ts.map +1 -0
- package/dist/persistence/UserDirectories.js +178 -0
- package/dist/persistence/UserDirectories.js.map +1 -0
- package/dist/persistence/index.d.ts +5 -0
- package/dist/persistence/index.d.ts.map +1 -1
- package/dist/persistence/index.js +5 -0
- package/dist/persistence/index.js.map +1 -1
- package/dist/process/ChildProcess.d.ts +2 -1
- package/dist/process/ChildProcess.d.ts.map +1 -1
- package/dist/process/ChildProcess.js.map +1 -1
- package/dist/reactivity/AsyncResult.d.ts +6 -0
- package/dist/reactivity/AsyncResult.d.ts.map +1 -1
- package/dist/reactivity/AsyncResult.js +28 -1
- package/dist/reactivity/AsyncResult.js.map +1 -1
- package/dist/reactivity/Atom.d.ts +69 -30
- package/dist/reactivity/Atom.d.ts.map +1 -1
- package/dist/reactivity/Atom.js +40 -15
- package/dist/reactivity/Atom.js.map +1 -1
- package/dist/reactivity/AtomHttpApi.d.ts +5 -5
- package/dist/reactivity/AtomHttpApi.d.ts.map +1 -1
- package/dist/reactivity/AtomHttpApi.js +1 -1
- package/dist/reactivity/AtomHttpApi.js.map +1 -1
- package/dist/reactivity/AtomRegistry.d.ts +2 -2
- package/dist/reactivity/AtomRegistry.d.ts.map +1 -1
- package/dist/reactivity/AtomRegistry.js +47 -10
- package/dist/reactivity/AtomRegistry.js.map +1 -1
- package/dist/reactivity/AtomRpc.d.ts +3 -3
- package/dist/reactivity/AtomRpc.d.ts.map +1 -1
- package/dist/reactivity/AtomRpc.js +1 -1
- package/dist/reactivity/AtomRpc.js.map +1 -1
- package/dist/reactivity/Hydration.d.ts.map +1 -1
- package/dist/reactivity/Hydration.js +46 -12
- package/dist/reactivity/Hydration.js.map +1 -1
- package/dist/reactivity/Reactivity.d.ts +71 -7
- package/dist/reactivity/Reactivity.d.ts.map +1 -1
- package/dist/reactivity/Reactivity.js +21 -12
- package/dist/reactivity/Reactivity.js.map +1 -1
- package/dist/rpc/Rpc.d.ts +18 -0
- package/dist/rpc/Rpc.d.ts.map +1 -1
- package/dist/rpc/Rpc.js +20 -0
- package/dist/rpc/Rpc.js.map +1 -1
- package/dist/rpc/RpcClient.d.ts +26 -2
- package/dist/rpc/RpcClient.d.ts.map +1 -1
- package/dist/rpc/RpcClient.js +202 -61
- package/dist/rpc/RpcClient.js.map +1 -1
- package/dist/rpc/RpcSerialization.d.ts +15 -0
- package/dist/rpc/RpcSerialization.d.ts.map +1 -1
- package/dist/rpc/RpcSerialization.js +21 -5
- package/dist/rpc/RpcSerialization.js.map +1 -1
- package/dist/rpc/RpcServer.d.ts.map +1 -1
- package/dist/rpc/RpcServer.js +9 -18
- package/dist/rpc/RpcServer.js.map +1 -1
- package/dist/schema/Model.d.ts +1 -1
- package/dist/schema/VariantSchema.d.ts +22 -3
- package/dist/schema/VariantSchema.d.ts.map +1 -1
- package/dist/schema/VariantSchema.js +32 -18
- package/dist/schema/VariantSchema.js.map +1 -1
- package/dist/socket/Socket.d.ts +23 -1
- package/dist/socket/Socket.d.ts.map +1 -1
- package/dist/socket/Socket.js +36 -3
- package/dist/socket/Socket.js.map +1 -1
- package/dist/sql/Migrator.d.ts.map +1 -1
- package/dist/sql/Migrator.js +15 -3
- package/dist/sql/Migrator.js.map +1 -1
- package/dist/sql/SqlClient.d.ts +151 -12
- package/dist/sql/SqlClient.d.ts.map +1 -1
- package/dist/sql/SqlClient.js +156 -34
- package/dist/sql/SqlClient.js.map +1 -1
- package/dist/sql/SqlResolver.d.ts +9 -0
- package/dist/sql/SqlResolver.d.ts.map +1 -1
- package/dist/sql/SqlResolver.js +9 -0
- package/dist/sql/SqlResolver.js.map +1 -1
- package/dist/sql/Statement.d.ts +3 -1
- package/dist/sql/Statement.d.ts.map +1 -1
- package/dist/sql/Statement.js +24 -5
- package/dist/sql/Statement.js.map +1 -1
- package/dist/testing/TestClock.d.ts +16 -3
- package/dist/testing/TestClock.d.ts.map +1 -1
- package/dist/testing/TestClock.js +115 -23
- package/dist/testing/TestClock.js.map +1 -1
- package/dist/testing/TestSchema.d.ts +7 -1
- package/dist/testing/TestSchema.d.ts.map +1 -1
- package/dist/testing/TestSchema.js +9 -3
- package/dist/testing/TestSchema.js.map +1 -1
- package/dist/workflow/Activity.js +1 -0
- package/dist/workflow/Activity.js.map +1 -1
- package/dist/workflow/Workflow.d.ts +22 -0
- package/dist/workflow/Workflow.d.ts.map +1 -1
- package/dist/workflow/Workflow.js +15 -3
- package/dist/workflow/Workflow.js.map +1 -1
- package/dist/workflow/WorkflowEngine.d.ts +20 -1
- package/dist/workflow/WorkflowEngine.d.ts.map +1 -1
- package/dist/workflow/WorkflowEngine.js +52 -24
- package/dist/workflow/WorkflowEngine.js.map +1 -1
- package/package.json +13 -3
- package/src/Array.ts +223 -61
- package/src/Bytes.ts +111 -0
- package/src/Channel.ts +287 -439
- package/src/ChannelSchema.ts +1 -49
- package/src/Chunk.ts +55 -61
- package/src/Config.ts +12 -86
- package/src/ConfigProvider.ts +41 -44
- package/src/Cron.ts +6 -3
- package/src/Duration.ts +70 -21
- package/src/Effect.ts +642 -220
- package/src/Equivalence.ts +7 -4
- package/src/Exit.ts +24 -9
- package/src/FiberHandle.ts +10 -9
- package/src/FiberMap.ts +13 -66
- package/src/FileSystem.ts +33 -9
- package/src/Graph.ts +171 -1263
- package/src/HashSet.ts +0 -60
- package/src/Iterable.ts +15 -14
- package/src/JsonSchema.ts +28 -3
- package/src/Layer.ts +2 -2
- package/src/ManagedRuntime.ts +72 -6
- package/src/Match.ts +65 -12
- package/src/Metric.ts +249 -507
- package/src/MutableHashMap.ts +4 -473
- package/src/Number.ts +2 -2
- package/src/Optic.ts +17 -332
- package/src/Path.ts +61 -8
- package/src/PubSub.ts +12 -7
- package/src/Queue.ts +5 -37
- package/src/Random.ts +1 -1
- package/src/RcMap.ts +14 -8
- package/src/Record.ts +51 -0
- package/src/Ref.ts +7 -104
- package/src/References.ts +5 -4
- package/src/RequestResolver.ts +46 -87
- package/src/Resource.ts +1 -1
- package/src/Runtime.ts +19 -18
- package/src/Schedule.ts +2 -94
- package/src/Schema.ts +596 -348
- package/src/SchemaAST.ts +20 -9
- package/src/SchemaGetter.ts +22 -5
- package/src/SchemaIssue.ts +44 -53
- package/src/SchemaRepresentation.ts +64 -1
- package/src/SchemaTransformation.ts +1 -1
- package/src/Scope.ts +12 -2
- package/src/ScopedCache.ts +17 -142
- package/src/SemVer.ts +1528 -0
- package/src/SemVerRange.ts +883 -0
- package/src/Sink.ts +6 -2
- package/src/Stream.ts +334 -1011
- package/src/String.ts +25 -12
- package/src/TextDiff.ts +766 -0
- package/src/TxHashMap.ts +1 -103
- package/src/TxHashSet.ts +48 -753
- package/src/TxRef.ts +4 -2
- package/src/ai/AiError.ts +69 -5
- package/src/ai/Chat.ts +10 -5
- package/src/ai/Decision.ts +119 -22
- package/src/ai/DecisionModel.ts +265 -109
- package/src/ai/EmbeddingModel.ts +25 -13
- package/src/ai/LanguageModel.ts +57 -51
- package/src/ai/McpClient.ts +1211 -0
- package/src/ai/McpClientError.ts +329 -0
- package/src/ai/McpProtocol.ts +2 -2
- package/src/ai/McpSchema.ts +153 -35
- package/src/ai/McpServer.ts +232 -275
- package/src/ai/Prompt.ts +49 -35
- package/src/ai/Response.ts +195 -65
- package/src/ai/Tool.ts +12 -4
- package/src/ai/Toolkit.ts +78 -10
- package/src/ai/index.ts +12 -0
- package/src/ai/internal/mcpCore.ts +13 -14
- package/src/ai/internal/mcpProtocol/v2024_11_05.ts +1 -1
- package/src/ai/internal/mcpProtocol/v2025_03_26.ts +1 -1
- package/src/ai/internal/mcpProtocol/v2025_06_18.ts +3 -3
- package/src/ai/internal/mcpProtocol/v2025_11_25.ts +3 -3
- package/src/ai/internal/mcpProtocol/v2026_07_28.ts +12 -14
- package/src/ai/internal/mcpProtocol.ts +22 -2
- package/src/ai/internal/mcpRuntime.ts +3 -4
- package/src/ai/internal/mcpSchema/v2024_11_05.ts +20 -13
- package/src/ai/internal/mcpSchema/v2025_03_26.ts +4 -2
- package/src/ai/internal/mcpSchema/v2025_06_18.ts +7 -7
- package/src/ai/internal/mcpSchema/v2025_11_25.ts +8 -8
- package/src/ai/internal/mcpSchema/v2026_07_28.ts +44 -42
- package/src/cli/CliError.ts +49 -4
- package/src/cli/Command.ts +316 -9
- package/src/cli/Completions.ts +10 -0
- package/src/cli/Flag.ts +218 -0
- package/src/cli/GlobalFlag.ts +3 -3
- package/src/cli/Param.ts +218 -0
- package/src/cli/TerminalCapabilities.ts +156 -0
- package/src/cli/index.ts +6 -0
- package/src/cli/internal/command.ts +10 -4
- package/src/cli/internal/completions/bash.ts +7 -5
- package/src/cli/internal/completions/descriptor.ts +20 -1
- package/src/cli/internal/completions/fish.ts +12 -10
- package/src/cli/internal/completions/powershell.ts +25 -13
- package/src/cli/internal/completions/zsh.ts +15 -8
- package/src/cli/internal/formatter.ts +18 -0
- package/src/cli/internal/lexer.ts +12 -5
- package/src/cli/internal/parser.ts +43 -14
- package/src/cli/internal/wizard.ts +2 -1
- package/src/cluster/ClusterCron.ts +94 -35
- package/src/cluster/ClusterMetrics.ts +149 -7
- package/src/cluster/ClusterWorkflowEngine.ts +164 -53
- package/src/cluster/Entity.ts +4 -0
- package/src/cluster/MessageStorage.ts +21 -3
- package/src/cluster/Runners.ts +145 -72
- package/src/cluster/Sharding.ts +118 -38
- package/src/cluster/ShardingConfig.ts +15 -0
- package/src/cluster/SqlMessageStorage.ts +58 -55
- package/src/cluster/SqlRunnerStorage.ts +10 -4
- package/src/cluster/internal/entityManager.ts +81 -11
- package/src/devtools/DevTools.ts +3 -2
- package/src/devtools/DevToolsClient.ts +27 -10
- package/src/encoding/Base64Url.ts +31 -0
- package/src/encoding/Ini.ts +3 -0
- package/src/encoding/JsonArray.ts +849 -0
- package/src/encoding/Ndjson.ts +211 -20
- package/src/encoding/SchemaBinary.ts +14 -48
- package/src/encoding/Sse.ts +1 -1
- package/src/encoding/Tar.ts +1417 -0
- package/src/encoding/Toml.ts +3 -3
- package/src/encoding/Xml.ts +2037 -0
- package/src/encoding/Yaml.ts +108 -36
- package/src/encoding/Zip.ts +1558 -0
- package/src/encoding/index.ts +24 -0
- package/src/eventlog/EventJournal.ts +611 -227
- package/src/eventlog/EventLog.ts +496 -196
- package/src/eventlog/EventLogEncryption.ts +128 -43
- package/src/eventlog/EventLogMessage.ts +62 -11
- package/src/eventlog/EventLogRemote.ts +77 -21
- package/src/eventlog/EventLogServer.ts +162 -20
- package/src/eventlog/EventLogServerEncrypted.ts +121 -80
- package/src/eventlog/EventLogServerUnencrypted.ts +180 -77
- package/src/eventlog/EventRow.ts +706 -0
- package/src/eventlog/SqlEventJournal.ts +453 -173
- package/src/eventlog/SqlEventLogServerEncrypted.ts +212 -83
- package/src/eventlog/SqlEventLogServerUnencrypted.ts +141 -62
- package/src/eventlog/index.ts +6 -0
- package/src/eventlog/internal/conflicts.ts +123 -0
- package/src/graphql/GraphQLClient.ts +17 -5
- package/src/graphql/GraphQLClientError.ts +5 -12
- package/src/graphql/GraphQLProtocol.ts +277 -20
- package/src/graphql/GraphQLResolver.ts +109 -230
- package/src/http/FetchHttpClient.ts +61 -8
- package/src/http/FindMyWay/internal/router.ts +13 -1
- package/src/http/Headers.ts +343 -163
- package/src/http/HttpClient.ts +144 -136
- package/src/http/HttpClientError.ts +10 -6
- package/src/http/HttpClientRequest.ts +315 -11
- package/src/http/HttpClientResponse.ts +71 -0
- package/src/http/HttpEffect.ts +25 -33
- package/src/http/HttpIncomingMessage.ts +3 -23
- package/src/http/HttpMiddleware.ts +265 -28
- package/src/http/HttpRouter.ts +67 -14
- package/src/http/HttpServerError.ts +14 -7
- package/src/http/HttpServerRequest.ts +73 -14
- package/src/http/HttpServerResponse.ts +49 -23
- package/src/http/HttpStaticServer.ts +29 -19
- package/src/http/HttpTraceContext.ts +1 -1
- package/src/http/MultipartParser/internal/contentType.ts +107 -6
- package/src/http/MultipartParser/internal/headers.ts +4 -16
- package/src/http/MultipartParser/internal/multipart.ts +10 -32
- package/src/http/Url.ts +8 -2
- package/src/http/UrlParams.ts +225 -26
- package/src/http/internal/compression.ts +3 -17
- package/src/http/internal/compressionBody.ts +56 -0
- package/src/http/internal/decompression.ts +235 -0
- package/src/http/internal/lazyStream.ts +25 -0
- package/src/http/internal/requestState.ts +33 -0
- package/src/http/internal/tracing.ts +21 -4
- package/src/http/internal/urlParams.ts +5 -0
- package/src/http/internal/webResponse.ts +20 -0
- package/src/http-api/HttpApi.ts +1 -1
- package/src/http-api/HttpApiBuilder.ts +151 -23
- package/src/http-api/HttpApiClient.ts +160 -31
- package/src/http-api/HttpApiEndpoint.ts +144 -33
- package/src/http-api/HttpApiError.ts +55 -0
- package/src/http-api/HttpApiScalar.ts +4 -3
- package/src/http-api/HttpApiSchema.ts +275 -13
- package/src/http-api/HttpApiSwagger.ts +11 -4
- package/src/http-api/HttpApiTest.ts +33 -9
- package/src/http-api/OpenApi.ts +84 -42
- package/src/http-api/internal/path.ts +40 -12
- package/src/index.ts +24 -0
- package/src/internal/core.ts +22 -2
- package/src/internal/dateTime.ts +20 -7
- package/src/internal/effect.ts +125 -88
- package/src/internal/graphql.ts +30 -7
- package/src/internal/hashMap.ts +2 -2
- package/src/internal/hydration.ts +15 -0
- package/src/internal/inflate.ts +710 -0
- package/src/internal/record.ts +6 -0
- package/src/internal/request.ts +21 -6
- package/src/internal/schedule.ts +20 -39
- package/src/internal/schema/fromJsonSchemaDocument.ts +262 -193
- package/src/internal/schema/interpreter.ts +58 -45
- package/src/internal/schema/standardSchema.ts +32 -30
- package/src/internal/schema/toCodeDocument.ts +8 -3
- package/src/internal/schema/toCodec.ts +116 -1
- package/src/internal/schema/toFormatter.ts +6 -6
- package/src/internal/schema/toJsonSchemaDocument.ts +69 -39
- package/src/internal/trie.ts +1 -3
- package/src/internal/uuid.ts +15 -10
- package/src/internal/version.ts +1 -1
- package/src/net/NetAddress.ts +2 -9
- package/src/observability/Otlp.ts +18 -0
- package/src/observability/OtlpExporter.ts +19 -15
- package/src/observability/OtlpLogger.ts +31 -2
- package/src/observability/OtlpMetrics.ts +35 -4
- package/src/observability/OtlpResource.ts +16 -6
- package/src/observability/OtlpSerialization.ts +17 -3
- package/src/observability/OtlpTracer.ts +32 -3
- package/src/observability/internal/protobuf.ts +2 -10
- package/src/persistence/PersistedCache.ts +3 -1
- package/src/persistence/PersistedQueue.ts +223 -153
- package/src/persistence/Persistence.ts +64 -30
- package/src/persistence/RateLimiter.ts +18 -21
- package/src/persistence/UserDirectories.ts +273 -0
- package/src/persistence/index.ts +6 -0
- package/src/process/ChildProcess.ts +2 -1
- package/src/reactivity/AsyncResult.ts +35 -38
- package/src/reactivity/Atom.ts +134 -166
- package/src/reactivity/AtomHttpApi.ts +10 -16
- package/src/reactivity/AtomRegistry.ts +53 -30
- package/src/reactivity/AtomRpc.ts +6 -22
- package/src/reactivity/Hydration.ts +53 -12
- package/src/reactivity/Reactivity.ts +97 -39
- package/src/rpc/Rpc.ts +21 -0
- package/src/rpc/RpcClient.ts +285 -104
- package/src/rpc/RpcSerialization.ts +21 -5
- package/src/rpc/RpcServer.ts +11 -20
- package/src/schema/VariantSchema.ts +86 -22
- package/src/socket/Socket.ts +45 -20
- package/src/sql/Migrator.ts +19 -9
- package/src/sql/SqlClient.ts +275 -36
- package/src/sql/SqlResolver.ts +9 -0
- package/src/sql/Statement.ts +35 -8
- package/src/testing/TestClock.ts +147 -29
- package/src/testing/TestSchema.ts +9 -3
- package/src/workflow/Activity.ts +1 -0
- package/src/workflow/Workflow.ts +31 -5
- package/src/workflow/WorkflowEngine.ts +93 -31
- package/dist/http/internal/preResponseHandler.d.ts +0 -2
- package/dist/http/internal/preResponseHandler.d.ts.map +0 -1
- package/dist/http/internal/preResponseHandler.js +0 -14
- package/dist/http/internal/preResponseHandler.js.map +0 -1
- package/src/http/internal/preResponseHandler.ts +0 -19
|
@@ -0,0 +1,2037 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Decodes and encodes XML 1.0 documents as streams of events in Effect
|
|
3
|
+
* channels.
|
|
4
|
+
*
|
|
5
|
+
* `decode` and `decodeString` turn UTF-8 bytes or text into events, and
|
|
6
|
+
* `encode` and `encodeString` write events back as XML. `elements` collects
|
|
7
|
+
* repeated elements, such as the items of a feed, into small trees, so that a
|
|
8
|
+
* large document can be processed one record at a time.
|
|
9
|
+
*
|
|
10
|
+
* The decoder checks that documents are well-formed. It never reads external
|
|
11
|
+
* resources and never expands entities declared in a DOCTYPE, so external
|
|
12
|
+
* entity (XXE) and entity expansion attacks do not apply. It does not validate
|
|
13
|
+
* documents against a DTD or schema, and reports names as written, without
|
|
14
|
+
* resolving namespaces.
|
|
15
|
+
*
|
|
16
|
+
* @stability experimental
|
|
17
|
+
* @since 4.0.6
|
|
18
|
+
*/
|
|
19
|
+
import * as Arr from "../Array.ts"
|
|
20
|
+
import * as Cause from "../Cause.ts"
|
|
21
|
+
import * as Channel from "../Channel.ts"
|
|
22
|
+
import * as Data from "../Data.ts"
|
|
23
|
+
import * as Effect from "../Effect.ts"
|
|
24
|
+
import * as Predicate from "../Predicate.ts"
|
|
25
|
+
import * as Pull from "../Pull.ts"
|
|
26
|
+
|
|
27
|
+
const XmlErrorTypeId = "~effect/encoding/Xml/XmlError"
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Error raised when XML cannot be decoded or encoded.
|
|
31
|
+
*
|
|
32
|
+
* **Details**
|
|
33
|
+
*
|
|
34
|
+
* The `kind` field identifies the failure:
|
|
35
|
+
*
|
|
36
|
+
* - `Syntax`: the input is not well-formed XML or not valid UTF-8.
|
|
37
|
+
* - `Unsupported`: the input uses a feature this module does not process, such
|
|
38
|
+
* as an entity declared in a DOCTYPE or a byte encoding other than UTF-8.
|
|
39
|
+
* - `Limit`: the input exceeds `maxTokenSize`, `maxDepth` or `maxElementSize`.
|
|
40
|
+
* - `InvalidEvent`: the events do not form a well-formed document, such as an
|
|
41
|
+
* end tag that does not match its start tag.
|
|
42
|
+
*
|
|
43
|
+
* Errors from `decode` and `decodeString` carry the one-based `line` and
|
|
44
|
+
* `column` where the problem was found, also appended to `message`. Columns
|
|
45
|
+
* count UTF-16 code units, and lines end at LF, CR or CRLF.
|
|
46
|
+
*
|
|
47
|
+
* @stability experimental
|
|
48
|
+
* @category errors
|
|
49
|
+
* @since 4.0.6
|
|
50
|
+
*/
|
|
51
|
+
export class XmlError extends Data.TaggedError("XmlError")<{
|
|
52
|
+
readonly kind: "Syntax" | "Unsupported" | "Limit" | "InvalidEvent"
|
|
53
|
+
readonly message: string
|
|
54
|
+
readonly line?: number | undefined
|
|
55
|
+
readonly column?: number | undefined
|
|
56
|
+
}> {
|
|
57
|
+
/**
|
|
58
|
+
* Marks this value as an XML error for runtime guards.
|
|
59
|
+
*
|
|
60
|
+
* @stability experimental
|
|
61
|
+
* @since 4.0.6
|
|
62
|
+
*/
|
|
63
|
+
readonly [XmlErrorTypeId] = XmlErrorTypeId
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Checks whether a value is an `XmlError`.
|
|
68
|
+
*
|
|
69
|
+
* @stability experimental
|
|
70
|
+
* @category guards
|
|
71
|
+
* @since 4.0.6
|
|
72
|
+
*/
|
|
73
|
+
export const isXmlError = (u: unknown): u is XmlError => Predicate.hasProperty(u, XmlErrorTypeId)
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Event for the XML declaration at the start of a document, such as
|
|
77
|
+
* `<?xml version="1.0" encoding="UTF-8"?>`.
|
|
78
|
+
*
|
|
79
|
+
* **Details**
|
|
80
|
+
*
|
|
81
|
+
* `encoding` and `standalone` are present only when the declaration sets them.
|
|
82
|
+
*
|
|
83
|
+
* @stability experimental
|
|
84
|
+
* @category models
|
|
85
|
+
* @since 4.0.6
|
|
86
|
+
*/
|
|
87
|
+
export interface Declaration {
|
|
88
|
+
readonly _tag: "Declaration"
|
|
89
|
+
readonly version: string
|
|
90
|
+
readonly encoding?: string | undefined
|
|
91
|
+
readonly standalone?: boolean | undefined
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Event for a document type declaration, such as `<!DOCTYPE html>`.
|
|
96
|
+
*
|
|
97
|
+
* **Details**
|
|
98
|
+
*
|
|
99
|
+
* `publicId` and `systemId` are present only when the declaration names an
|
|
100
|
+
* external DTD; the DTD is never read. Whitespace in `publicId` is collapsed
|
|
101
|
+
* to single spaces and trimmed. The internal subset is not reported.
|
|
102
|
+
*
|
|
103
|
+
* @stability experimental
|
|
104
|
+
* @category models
|
|
105
|
+
* @since 4.0.6
|
|
106
|
+
*/
|
|
107
|
+
export interface Doctype {
|
|
108
|
+
readonly _tag: "Doctype"
|
|
109
|
+
readonly name: string
|
|
110
|
+
readonly publicId?: string | undefined
|
|
111
|
+
readonly systemId?: string | undefined
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Event for a start tag, with its attributes in document order.
|
|
116
|
+
*
|
|
117
|
+
* **Details**
|
|
118
|
+
*
|
|
119
|
+
* `name` is the qualified name as written and is the only element-name field
|
|
120
|
+
* the encoder reads.
|
|
121
|
+
*
|
|
122
|
+
* Attribute values have their references replaced and whitespace normalized as
|
|
123
|
+
* XML requires. Decoded attributes inherit nothing, so only the attributes of
|
|
124
|
+
* the tag are present and `__proto__` is an ordinary key. Their key order is
|
|
125
|
+
* document order, as XML names are never integer-like. A `structuredClone` of
|
|
126
|
+
* a decoded map gets `Object.prototype` back. A self-closing tag such as
|
|
127
|
+
* `<br/>` is decoded as a `StartElement` followed by an `EndElement`.
|
|
128
|
+
*
|
|
129
|
+
* @stability experimental
|
|
130
|
+
* @category models
|
|
131
|
+
* @since 4.0.6
|
|
132
|
+
*/
|
|
133
|
+
export interface StartElement {
|
|
134
|
+
readonly _tag: "StartElement"
|
|
135
|
+
readonly name: string
|
|
136
|
+
readonly attributes: Readonly<Record<string, string>>
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* Event for an end tag.
|
|
141
|
+
*
|
|
142
|
+
* @stability experimental
|
|
143
|
+
* @category models
|
|
144
|
+
* @since 4.0.6
|
|
145
|
+
*/
|
|
146
|
+
export interface EndElement {
|
|
147
|
+
readonly _tag: "EndElement"
|
|
148
|
+
readonly name: string
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Event for character data inside the root element.
|
|
153
|
+
*
|
|
154
|
+
* **Details**
|
|
155
|
+
*
|
|
156
|
+
* Adjacent text, references and CDATA sections are decoded into one `Text`
|
|
157
|
+
* event that ends at the next tag, comment or processing instruction, however
|
|
158
|
+
* the input is chunked. Line endings are normalized to `\n`.
|
|
159
|
+
*
|
|
160
|
+
* @stability experimental
|
|
161
|
+
* @category models
|
|
162
|
+
* @since 4.0.6
|
|
163
|
+
*/
|
|
164
|
+
export interface Text {
|
|
165
|
+
readonly _tag: "Text"
|
|
166
|
+
readonly text: string
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
/**
|
|
170
|
+
* Event for a comment, holding the text between `<!--` and `-->`.
|
|
171
|
+
*
|
|
172
|
+
* @stability experimental
|
|
173
|
+
* @category models
|
|
174
|
+
* @since 4.0.6
|
|
175
|
+
*/
|
|
176
|
+
export interface Comment {
|
|
177
|
+
readonly _tag: "Comment"
|
|
178
|
+
readonly text: string
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* Event for a processing instruction, such as
|
|
183
|
+
* `<?xml-stylesheet href="style.xsl"?>`.
|
|
184
|
+
*
|
|
185
|
+
* **Details**
|
|
186
|
+
*
|
|
187
|
+
* `data` is the text after the target, without leading whitespace.
|
|
188
|
+
*
|
|
189
|
+
* @stability experimental
|
|
190
|
+
* @category models
|
|
191
|
+
* @since 4.0.6
|
|
192
|
+
*/
|
|
193
|
+
export interface ProcessingInstruction {
|
|
194
|
+
readonly _tag: "ProcessingInstruction"
|
|
195
|
+
readonly target: string
|
|
196
|
+
readonly data: string
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
/**
|
|
200
|
+
* Event produced by the decoders and consumed by the encoders.
|
|
201
|
+
*
|
|
202
|
+
* @stability experimental
|
|
203
|
+
* @category models
|
|
204
|
+
* @since 4.0.6
|
|
205
|
+
*/
|
|
206
|
+
export type Event =
|
|
207
|
+
| Declaration
|
|
208
|
+
| Doctype
|
|
209
|
+
| StartElement
|
|
210
|
+
| EndElement
|
|
211
|
+
| Text
|
|
212
|
+
| Comment
|
|
213
|
+
| ProcessingInstruction
|
|
214
|
+
|
|
215
|
+
/**
|
|
216
|
+
* Element collected by `elements`, with its attributes and children.
|
|
217
|
+
*
|
|
218
|
+
* **Details**
|
|
219
|
+
*
|
|
220
|
+
* Children are elements and strings of character data, in document order.
|
|
221
|
+
* Adjacent text is merged into one string; comments and processing
|
|
222
|
+
* instructions are dropped.
|
|
223
|
+
*
|
|
224
|
+
* @stability experimental
|
|
225
|
+
* @category models
|
|
226
|
+
* @since 4.0.6
|
|
227
|
+
*/
|
|
228
|
+
export interface Element {
|
|
229
|
+
readonly name: string
|
|
230
|
+
readonly attributes: Readonly<Record<string, string>>
|
|
231
|
+
readonly children: ReadonlyArray<Element | string>
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
/**
|
|
235
|
+
* Options for the XML decoders.
|
|
236
|
+
*
|
|
237
|
+
* **Details**
|
|
238
|
+
*
|
|
239
|
+
* - `maxTokenSize`: the maximum length of a single token in UTF-16 code units,
|
|
240
|
+
* as written in the input: a tag with its attributes, a comment, a processing
|
|
241
|
+
* instruction, a DOCTYPE, or a text node including its references and CDATA
|
|
242
|
+
* sections. Defaults to 10 MiB; `Infinity` disables the limit.
|
|
243
|
+
* - `maxDepth`: the maximum number of nested elements. Defaults to 1024;
|
|
244
|
+
* `Infinity` disables the limit.
|
|
245
|
+
*
|
|
246
|
+
* Memory per token and for open element names is bounded by `maxTokenSize`.
|
|
247
|
+
* Invalid options throw when the channel is created.
|
|
248
|
+
*
|
|
249
|
+
* @stability experimental
|
|
250
|
+
* @category configuration
|
|
251
|
+
* @since 4.0.6
|
|
252
|
+
*/
|
|
253
|
+
export interface DecodeOptions {
|
|
254
|
+
readonly maxTokenSize?: number | undefined
|
|
255
|
+
readonly maxDepth?: number | undefined
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
/**
|
|
259
|
+
* Options for `elements`.
|
|
260
|
+
*
|
|
261
|
+
* **Details**
|
|
262
|
+
*
|
|
263
|
+
* `maxElementSize` is the maximum size of one collected element, counted as
|
|
264
|
+
* the UTF-16 code units of its names, attribute names and values, and text.
|
|
265
|
+
* Defaults to 16 MiB; `Infinity` disables the limit. Invalid options throw when
|
|
266
|
+
* the channel is created.
|
|
267
|
+
*
|
|
268
|
+
* @stability experimental
|
|
269
|
+
* @category configuration
|
|
270
|
+
* @since 4.0.6
|
|
271
|
+
*/
|
|
272
|
+
export interface ElementsOptions {
|
|
273
|
+
readonly maxElementSize?: number | undefined
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
/**
|
|
277
|
+
* Creates a channel that decodes XML text chunks into events.
|
|
278
|
+
*
|
|
279
|
+
* **Details**
|
|
280
|
+
*
|
|
281
|
+
* - Tokens can be split anywhere between chunks. Each output chunk holds the
|
|
282
|
+
* events completed by one input chunk.
|
|
283
|
+
* - The document must have one root element. Whitespace outside it is not
|
|
284
|
+
* reported.
|
|
285
|
+
* - A leading byte order mark is skipped, and the encoding named by the XML
|
|
286
|
+
* declaration is ignored.
|
|
287
|
+
* - Events completed before an error are emitted before the channel fails.
|
|
288
|
+
*
|
|
289
|
+
* **Gotchas**
|
|
290
|
+
*
|
|
291
|
+
* - End of input inside the root fails with a `Syntax` error ("unclosed
|
|
292
|
+
* element"); interruption ends the stream without this check.
|
|
293
|
+
* - A DOCTYPE is reported as a `Doctype` event, and its internal subset is
|
|
294
|
+
* skipped without checking its declarations. They are not applied, so
|
|
295
|
+
* default attribute values are not added, and parameter entities are not
|
|
296
|
+
* expanded.
|
|
297
|
+
* - References to entities other than `<`, `>`, `&`, `'` and
|
|
298
|
+
* `"` fail with an `Unsupported` `XmlError` when the document has a
|
|
299
|
+
* DOCTYPE, and with a `Syntax` `XmlError` otherwise. Character references
|
|
300
|
+
* such as `é` are always decoded.
|
|
301
|
+
* - Names are reported as written, including namespace prefixes, and `xmlns`
|
|
302
|
+
* declarations are ordinary attributes.
|
|
303
|
+
* - Tokens or aggregate open element names longer than `maxTokenSize`, and
|
|
304
|
+
* elements nested deeper than `maxDepth`, fail with a `Limit` `XmlError`. A
|
|
305
|
+
* long token can instead fail with an error found in its first
|
|
306
|
+
* `maxTokenSize + 1` characters.
|
|
307
|
+
* - Strings in events can share memory with their input chunk, so keeping a
|
|
308
|
+
* short string, such as an id from each record, can keep the whole chunk in
|
|
309
|
+
* memory. Copy strings that are kept long, for example with
|
|
310
|
+
* `structuredClone`.
|
|
311
|
+
*
|
|
312
|
+
* **Example** (Decoding events)
|
|
313
|
+
*
|
|
314
|
+
* ```ts import.meta.vitest
|
|
315
|
+
* import { Effect, Stream } from "effect"
|
|
316
|
+
* import { Xml } from "effect/encoding"
|
|
317
|
+
*
|
|
318
|
+
* const events = Stream.make("<note id=\"1\">Hi & bye<br/></note>").pipe(
|
|
319
|
+
* Stream.pipeThroughChannel(Xml.decodeString()),
|
|
320
|
+
* Stream.map((event) => event._tag),
|
|
321
|
+
* Stream.runCollect
|
|
322
|
+
* )
|
|
323
|
+
* await Effect.runPromise(events) // => ["StartElement", "Text", "StartElement", "EndElement", "EndElement"]
|
|
324
|
+
* ```
|
|
325
|
+
*
|
|
326
|
+
* @see {@link decode} for UTF-8 byte input
|
|
327
|
+
* @see {@link elements} for collecting repeated elements into trees
|
|
328
|
+
* @see {@link encodeString} for the inverse operation
|
|
329
|
+
*
|
|
330
|
+
* @stability experimental
|
|
331
|
+
* @category decoding
|
|
332
|
+
* @since 4.0.6
|
|
333
|
+
*/
|
|
334
|
+
export const decodeString = <IE = never, Done = unknown>(options?: DecodeOptions): Channel.Channel<
|
|
335
|
+
Arr.NonEmptyReadonlyArray<Event>,
|
|
336
|
+
XmlError | IE,
|
|
337
|
+
Done,
|
|
338
|
+
Arr.NonEmptyReadonlyArray<string>,
|
|
339
|
+
IE,
|
|
340
|
+
Done
|
|
341
|
+
> => {
|
|
342
|
+
const parser = makeParser(options, false)
|
|
343
|
+
return makeChannel<string, Event, IE, Done>(() => new TextInput(parser()))
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
/**
|
|
347
|
+
* Creates a channel that decodes UTF-8 XML bytes into events.
|
|
348
|
+
*
|
|
349
|
+
* **Details**
|
|
350
|
+
*
|
|
351
|
+
* Works like `decodeString` after decoding the bytes as UTF-8. Multi-byte
|
|
352
|
+
* characters can be split between chunks, and a leading byte order mark is
|
|
353
|
+
* skipped.
|
|
354
|
+
*
|
|
355
|
+
* **Gotchas**
|
|
356
|
+
*
|
|
357
|
+
* - Invalid or truncated UTF-8 fails with a `Syntax` `XmlError`.
|
|
358
|
+
* - An initial UTF-16 byte order mark or an XML declaration naming an encoding
|
|
359
|
+
* other than UTF-8 or US-ASCII fails with an `Unsupported` `XmlError`.
|
|
360
|
+
* Decode such bytes with a `TextDecoder` for that encoding and use `decodeString`.
|
|
361
|
+
*
|
|
362
|
+
* @see {@link decodeString} for text input and the shared gotchas
|
|
363
|
+
*
|
|
364
|
+
* @stability experimental
|
|
365
|
+
* @category decoding
|
|
366
|
+
* @since 4.0.6
|
|
367
|
+
*/
|
|
368
|
+
export const decode = <IE = never, Done = unknown>(options?: DecodeOptions): Channel.Channel<
|
|
369
|
+
Arr.NonEmptyReadonlyArray<Event>,
|
|
370
|
+
XmlError | IE,
|
|
371
|
+
Done,
|
|
372
|
+
Arr.NonEmptyReadonlyArray<Uint8Array>,
|
|
373
|
+
IE,
|
|
374
|
+
Done
|
|
375
|
+
> => {
|
|
376
|
+
const parser = makeParser(options, true)
|
|
377
|
+
return makeChannel<Uint8Array, Event, IE, Done>(() => new Utf8Input(parser()))
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
/**
|
|
381
|
+
* Creates a channel that collects the elements at a path into trees.
|
|
382
|
+
*
|
|
383
|
+
* **When to use**
|
|
384
|
+
*
|
|
385
|
+
* Use to process large documents such as feeds, sitemaps or exports one record
|
|
386
|
+
* at a time, without holding the whole document in memory.
|
|
387
|
+
*
|
|
388
|
+
* **Details**
|
|
389
|
+
*
|
|
390
|
+
* `path` lists element names from the root, and `"*"` matches any name. Each
|
|
391
|
+
* element whose ancestors and own name match the path is emitted once its end
|
|
392
|
+
* tag arrives, with all of its descendants; everything outside the matched
|
|
393
|
+
* elements is skipped. Because paths start at the root, an element nested in a
|
|
394
|
+
* matched element is part of its tree and is not emitted separately.
|
|
395
|
+
*
|
|
396
|
+
* **Gotchas**
|
|
397
|
+
*
|
|
398
|
+
* - A path that does not start at the root element matches nothing.
|
|
399
|
+
* - Whitespace between child elements, such as indentation, is kept as string
|
|
400
|
+
* children.
|
|
401
|
+
* - A collected element larger than `maxElementSize` fails with a `Limit`
|
|
402
|
+
* `XmlError`. The size counts characters, not memory: an element with many
|
|
403
|
+
* small children can take many times its size in memory, so use a lower
|
|
404
|
+
* limit for untrusted input.
|
|
405
|
+
* - Events that end inside an element, or end an element that was never
|
|
406
|
+
* started, fail with an `InvalidEvent` `XmlError`.
|
|
407
|
+
* - A path that is empty or contains an invalid name throws when the channel is
|
|
408
|
+
* created.
|
|
409
|
+
*
|
|
410
|
+
* **Example** (Reading feed items)
|
|
411
|
+
*
|
|
412
|
+
* ```ts import.meta.vitest
|
|
413
|
+
* import { Effect, Stream } from "effect"
|
|
414
|
+
* import { Xml } from "effect/encoding"
|
|
415
|
+
*
|
|
416
|
+
* const feed = `<rss><channel><title>News</title>
|
|
417
|
+
* <item><title>First</title></item>
|
|
418
|
+
* <item><title>Second</title></item>
|
|
419
|
+
* </channel></rss>`
|
|
420
|
+
*
|
|
421
|
+
* const items = await Effect.runPromise(
|
|
422
|
+
* Stream.make(feed).pipe(
|
|
423
|
+
* Stream.pipeThroughChannel(Xml.decodeString()),
|
|
424
|
+
* Stream.pipeThroughChannel(Xml.elements(["rss", "channel", "item"])),
|
|
425
|
+
* Stream.runCollect
|
|
426
|
+
* )
|
|
427
|
+
* )
|
|
428
|
+
* items.length // => 2
|
|
429
|
+
* items[1] // => { name: "item", attributes: {}, children: [{ name: "title", attributes: {}, children: ["Second"] }] }
|
|
430
|
+
* ```
|
|
431
|
+
*
|
|
432
|
+
* @see {@link decode} for producing events from bytes
|
|
433
|
+
*
|
|
434
|
+
* @stability experimental
|
|
435
|
+
* @category decoding
|
|
436
|
+
* @since 4.0.6
|
|
437
|
+
*/
|
|
438
|
+
export const elements = <IE = never, Done = unknown>(
|
|
439
|
+
path: ReadonlyArray<string>,
|
|
440
|
+
options?: ElementsOptions
|
|
441
|
+
): Channel.Channel<
|
|
442
|
+
Arr.NonEmptyReadonlyArray<Element>,
|
|
443
|
+
XmlError | IE,
|
|
444
|
+
Done,
|
|
445
|
+
Arr.NonEmptyReadonlyArray<Event>,
|
|
446
|
+
IE,
|
|
447
|
+
Done
|
|
448
|
+
> => {
|
|
449
|
+
if (path.length === 0) {
|
|
450
|
+
throw new Error("Xml: elements path must not be empty")
|
|
451
|
+
}
|
|
452
|
+
for (const name of path) {
|
|
453
|
+
if (name !== "*" && !isName(name)) {
|
|
454
|
+
throw new Error(`Xml: invalid element name in path: ${JSON.stringify(name)}`)
|
|
455
|
+
}
|
|
456
|
+
}
|
|
457
|
+
const maxElementSize = checkLimit("maxElementSize", options?.maxElementSize, defaultMaxElementSize)
|
|
458
|
+
const segments = Array.from(path)
|
|
459
|
+
return makeChannel<Event, Element, IE, Done>(() => new Collector(segments, maxElementSize))
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
/**
|
|
463
|
+
* Creates a channel that writes events as XML text.
|
|
464
|
+
*
|
|
465
|
+
* **Details**
|
|
466
|
+
*
|
|
467
|
+
* - Each input chunk is written as one string.
|
|
468
|
+
* - Text escapes `&`, `<` and `>`. Attribute values are double-quoted and
|
|
469
|
+
* escape `&`, `<`, `"`, tabs and line breaks. Carriage returns are written
|
|
470
|
+
* as ` ` so that they survive decoding.
|
|
471
|
+
* - Start tags are written completely on their event. Empty elements use
|
|
472
|
+
* explicit closing tags, such as `<br></br>`, never self-closing tags.
|
|
473
|
+
* - Nothing is added between events, so whitespace comes only from `Text`
|
|
474
|
+
* events.
|
|
475
|
+
*
|
|
476
|
+
* **Gotchas**
|
|
477
|
+
*
|
|
478
|
+
* Events that do not form one well-formed document fail with an
|
|
479
|
+
* `InvalidEvent` `XmlError`, such as an end tag that does not match the open
|
|
480
|
+
* element, a second root element, non-whitespace text outside the root
|
|
481
|
+
* element, invalid names or characters, `--` in a comment, `?>` in processing
|
|
482
|
+
* instruction data, or a declaration that is not the first event. The stream
|
|
483
|
+
* must end with the root element closed.
|
|
484
|
+
*
|
|
485
|
+
* **Example** (Writing a document)
|
|
486
|
+
*
|
|
487
|
+
* ```ts import.meta.vitest
|
|
488
|
+
* import { Effect, Stream } from "effect"
|
|
489
|
+
* import { Xml } from "effect/encoding"
|
|
490
|
+
*
|
|
491
|
+
* const events: ReadonlyArray<Xml.Event> = [
|
|
492
|
+
* { _tag: "StartElement", name: "a", attributes: { href: "x?a=1&b=2" } },
|
|
493
|
+
* { _tag: "Text", text: "1 < 2" },
|
|
494
|
+
* { _tag: "EndElement", name: "a" }
|
|
495
|
+
* ]
|
|
496
|
+
*
|
|
497
|
+
* const xml = Stream.fromIterable(events).pipe(
|
|
498
|
+
* Stream.pipeThroughChannel(Xml.encodeString()),
|
|
499
|
+
* Stream.mkString
|
|
500
|
+
* )
|
|
501
|
+
* await Effect.runPromise(xml) // => '<a href="x?a=1&b=2">1 < 2</a>'
|
|
502
|
+
* ```
|
|
503
|
+
*
|
|
504
|
+
* @see {@link encode} for UTF-8 byte output
|
|
505
|
+
* @see {@link decodeString} for the inverse operation
|
|
506
|
+
*
|
|
507
|
+
* @stability experimental
|
|
508
|
+
* @category encoding
|
|
509
|
+
* @since 4.0.6
|
|
510
|
+
*/
|
|
511
|
+
export const encodeString = <IE = never, Done = unknown>(): Channel.Channel<
|
|
512
|
+
Arr.NonEmptyReadonlyArray<string>,
|
|
513
|
+
XmlError | IE,
|
|
514
|
+
Done,
|
|
515
|
+
Arr.NonEmptyReadonlyArray<Event>,
|
|
516
|
+
IE,
|
|
517
|
+
Done
|
|
518
|
+
> => makeChannel<Event, string, IE, Done>(() => new Writer(false))
|
|
519
|
+
|
|
520
|
+
/**
|
|
521
|
+
* Creates a channel that writes events as UTF-8 XML bytes.
|
|
522
|
+
*
|
|
523
|
+
* **Details**
|
|
524
|
+
*
|
|
525
|
+
* Works like `encodeString`, with one byte array per input chunk.
|
|
526
|
+
*
|
|
527
|
+
* **Gotchas**
|
|
528
|
+
*
|
|
529
|
+
* A `Declaration` event naming an encoding other than UTF-8 fails
|
|
530
|
+
* with an `InvalidEvent` `XmlError`.
|
|
531
|
+
*
|
|
532
|
+
* @see {@link encodeString} for text output and the shared gotchas
|
|
533
|
+
*
|
|
534
|
+
* @stability experimental
|
|
535
|
+
* @category encoding
|
|
536
|
+
* @since 4.0.6
|
|
537
|
+
*/
|
|
538
|
+
export const encode = <IE = never, Done = unknown>(): Channel.Channel<
|
|
539
|
+
Arr.NonEmptyReadonlyArray<Uint8Array>,
|
|
540
|
+
XmlError | IE,
|
|
541
|
+
Done,
|
|
542
|
+
Arr.NonEmptyReadonlyArray<Event>,
|
|
543
|
+
IE,
|
|
544
|
+
Done
|
|
545
|
+
> =>
|
|
546
|
+
Channel.map(makeChannel<Event, string, IE, Done>(() => new Writer(true)), Arr.map((text) => textEncoder.encode(text)))
|
|
547
|
+
|
|
548
|
+
const defaultMaxTokenSize = 10 * 1024 * 1024
|
|
549
|
+
const defaultMaxDepth = 1024
|
|
550
|
+
const defaultMaxElementSize = 16 * 1024 * 1024
|
|
551
|
+
|
|
552
|
+
const checkLimit = (name: string, value: number | undefined, defaultValue: number): number => {
|
|
553
|
+
const limit = value ?? defaultValue
|
|
554
|
+
if (!(limit > 0)) {
|
|
555
|
+
throw new Error(`Xml: ${name} must be positive, got ${limit}`)
|
|
556
|
+
}
|
|
557
|
+
return limit
|
|
558
|
+
}
|
|
559
|
+
|
|
560
|
+
// The per-run state of a channel. `push` and `end` add output to `out`, and
|
|
561
|
+
// throw `XmlError`s.
|
|
562
|
+
interface Machine<In, Out> {
|
|
563
|
+
out: Array<Out>
|
|
564
|
+
push(input: In): void
|
|
565
|
+
end(): void
|
|
566
|
+
}
|
|
567
|
+
|
|
568
|
+
const makeChannel = <In, Out, IE, Done>(
|
|
569
|
+
make: () => Machine<In, Out>
|
|
570
|
+
): Channel.Channel<
|
|
571
|
+
Arr.NonEmptyReadonlyArray<Out>,
|
|
572
|
+
XmlError | IE,
|
|
573
|
+
Done,
|
|
574
|
+
Arr.NonEmptyReadonlyArray<In>,
|
|
575
|
+
IE,
|
|
576
|
+
Done
|
|
577
|
+
> =>
|
|
578
|
+
Channel.fromTransform((upstream: Pull.Pull<Arr.NonEmptyReadonlyArray<In>, IE, Done>, _scope) =>
|
|
579
|
+
Effect.sync(() => {
|
|
580
|
+
const machine = make()
|
|
581
|
+
let done: Pull.Pull<never, never, Done> | undefined
|
|
582
|
+
let failure: XmlError | undefined
|
|
583
|
+
|
|
584
|
+
// Output completed before an error is emitted before the failure
|
|
585
|
+
const emit = (
|
|
586
|
+
inputs: ReadonlyArray<In> | undefined
|
|
587
|
+
): Pull.Pull<Arr.NonEmptyReadonlyArray<Out>, XmlError | IE, Done> => {
|
|
588
|
+
try {
|
|
589
|
+
if (inputs === undefined) machine.end()
|
|
590
|
+
else for (let i = 0; i < inputs.length; i++) machine.push(inputs[i])
|
|
591
|
+
} catch (error) {
|
|
592
|
+
if (!isXmlError(error)) throw error
|
|
593
|
+
failure = error
|
|
594
|
+
}
|
|
595
|
+
const out = machine.out
|
|
596
|
+
if (Arr.isArrayNonEmpty(out)) {
|
|
597
|
+
machine.out = []
|
|
598
|
+
return Effect.succeed(out)
|
|
599
|
+
}
|
|
600
|
+
return pull
|
|
601
|
+
}
|
|
602
|
+
|
|
603
|
+
const step = Pull.matchEffect(upstream, {
|
|
604
|
+
onSuccess: emit,
|
|
605
|
+
onFailure: Effect.failCause,
|
|
606
|
+
onDone: (value) => {
|
|
607
|
+
done = Cause.done(value)
|
|
608
|
+
return emit(undefined)
|
|
609
|
+
}
|
|
610
|
+
})
|
|
611
|
+
const pull: Pull.Pull<Arr.NonEmptyReadonlyArray<Out>, XmlError | IE, Done> = Effect.suspend(() =>
|
|
612
|
+
failure !== undefined ? Effect.fail(failure) : done ?? step
|
|
613
|
+
)
|
|
614
|
+
return pull
|
|
615
|
+
})
|
|
616
|
+
)
|
|
617
|
+
|
|
618
|
+
const makeParser = (options: DecodeOptions | undefined, bytes: boolean): () => Parser => {
|
|
619
|
+
const maxTokenSize = checkLimit("maxTokenSize", options?.maxTokenSize, defaultMaxTokenSize)
|
|
620
|
+
const maxDepth = checkLimit("maxDepth", options?.maxDepth, defaultMaxDepth)
|
|
621
|
+
return () => new Parser(maxTokenSize, maxDepth, bytes)
|
|
622
|
+
}
|
|
623
|
+
|
|
624
|
+
const textEncoder = new TextEncoder()
|
|
625
|
+
|
|
626
|
+
const TAB = 9
|
|
627
|
+
const LF = 10
|
|
628
|
+
const CR = 13
|
|
629
|
+
const SPACE = 32
|
|
630
|
+
const BANG = 33
|
|
631
|
+
const DQUOTE = 34
|
|
632
|
+
const HASH = 35
|
|
633
|
+
const AMPERSAND = 38
|
|
634
|
+
const SQUOTE = 39
|
|
635
|
+
const DASH = 45
|
|
636
|
+
const SLASH = 47
|
|
637
|
+
const LT = 60
|
|
638
|
+
const EQUALS = 61
|
|
639
|
+
const GT = 62
|
|
640
|
+
const QUESTION = 63
|
|
641
|
+
const LBRACKET = 91
|
|
642
|
+
const RBRACKET = 93
|
|
643
|
+
const LOWER_X = 120
|
|
644
|
+
|
|
645
|
+
const isSpace = (c: number): boolean => c === SPACE || c === LF || c === TAB || c === CR
|
|
646
|
+
|
|
647
|
+
// Characters outside the XML `Char` production, including unpaired surrogates
|
|
648
|
+
// oxlint-disable-next-line no-control-regex
|
|
649
|
+
const invalidChar = /[\0-\x08\x0B\x0C\x0E-\x1F\uFFFE\uFFFF\uD800-\uDFFF]/u
|
|
650
|
+
|
|
651
|
+
// Decoded UTF-8 has no unpaired surrogates, and without the `u` flag the
|
|
652
|
+
// search runs several times faster on non-ASCII text
|
|
653
|
+
// oxlint-disable-next-line no-control-regex
|
|
654
|
+
const invalidDecodedChar = /[\0-\x08\x0B\x0C\x0E-\x1F\uFFFE\uFFFF]/
|
|
655
|
+
|
|
656
|
+
// `isWellFormed` (ES2024) finds unpaired surrogates much faster than a `u`
|
|
657
|
+
// regex, which is slow on non-ASCII text
|
|
658
|
+
const isWellFormed: ((s: string) => boolean) | undefined =
|
|
659
|
+
typeof (String.prototype as { isWellFormed?: unknown }).isWellFormed === "function" ?
|
|
660
|
+
(s) => (s as unknown as { isWellFormed(): boolean }).isWellFormed() :
|
|
661
|
+
undefined
|
|
662
|
+
|
|
663
|
+
// Returns the index of the first character outside the XML `Char` production,
|
|
664
|
+
// or -1
|
|
665
|
+
const searchInvalid = (s: string): number =>
|
|
666
|
+
isWellFormed !== undefined && s.search(invalidDecodedChar) === -1 && isWellFormed(s) ? -1 : s.search(invalidChar)
|
|
667
|
+
|
|
668
|
+
const isChar = (c: number): boolean =>
|
|
669
|
+
c === TAB || c === LF || c === CR || (c >= 0x20 && c <= 0xD7FF) || (c >= 0xE000 && c <= 0xFFFD) ||
|
|
670
|
+
(c >= 0x10000 && c <= 0x10FFFF)
|
|
671
|
+
|
|
672
|
+
const NAME_START = 1
|
|
673
|
+
const NAME_CHAR = 2
|
|
674
|
+
const asciiName = new Uint8Array(128)
|
|
675
|
+
for (let c = 0; c < 128; c++) {
|
|
676
|
+
if ((c >= 65 && c <= 90) || (c >= 97 && c <= 122) || c === 95 || c === 58) asciiName[c] = NAME_START | NAME_CHAR
|
|
677
|
+
else if ((c >= 48 && c <= 57) || c === DASH || c === 46) asciiName[c] = NAME_CHAR
|
|
678
|
+
}
|
|
679
|
+
|
|
680
|
+
// Name characters of XML 1.0 fifth edition. Supplementary characters are
|
|
681
|
+
// accepted by their surrogates, which are paired once input is validated.
|
|
682
|
+
const isNameStartCode = (c: number): boolean =>
|
|
683
|
+
c < 128 ?
|
|
684
|
+
(asciiName[c] & NAME_START) !== 0 :
|
|
685
|
+
(c >= 0xC0 && c <= 0xD6) || (c >= 0xD8 && c <= 0xF6) || (c >= 0xF8 && c <= 0x2FF) ||
|
|
686
|
+
(c >= 0x370 && c <= 0x37D) || (c >= 0x37F && c <= 0x1FFF) || (c >= 0x200C && c <= 0x200D) ||
|
|
687
|
+
(c >= 0x2070 && c <= 0x218F) || (c >= 0x2C00 && c <= 0x2FEF) || (c >= 0x3001 && c <= 0xD7FF) ||
|
|
688
|
+
(c >= 0xF900 && c <= 0xFDCF) || (c >= 0xFDF0 && c <= 0xFFFD) || (c >= 0xD800 && c <= 0xDB7F)
|
|
689
|
+
|
|
690
|
+
const isNameCode = (c: number): boolean =>
|
|
691
|
+
c < 128 ?
|
|
692
|
+
(asciiName[c] & NAME_CHAR) !== 0 :
|
|
693
|
+
isNameStartCode(c) || c === 0xB7 || (c >= 0x300 && c <= 0x36F) || (c >= 0x203F && c <= 0x2040) ||
|
|
694
|
+
(c >= 0xDC00 && c <= 0xDFFF)
|
|
695
|
+
|
|
696
|
+
// Returns the end of the name starting at `i`, or `i` when there is none
|
|
697
|
+
const scanName = (s: string, i: number, end: number): number => {
|
|
698
|
+
if (i >= end || !isNameStartCode(s.charCodeAt(i))) return i
|
|
699
|
+
i++
|
|
700
|
+
while (i < end && isNameCode(s.charCodeAt(i))) i++
|
|
701
|
+
return i
|
|
702
|
+
}
|
|
703
|
+
|
|
704
|
+
// Name characters exclude every invalid character but unpaired surrogates
|
|
705
|
+
const isName = (s: string): boolean =>
|
|
706
|
+
s.length > 0 && scanName(s, 0, s.length) === s.length &&
|
|
707
|
+
(isWellFormed !== undefined ? isWellFormed(s) : !invalidChar.test(s))
|
|
708
|
+
|
|
709
|
+
const skipSpace = (s: string, i: number, end: number): number => {
|
|
710
|
+
while (i < end && isSpace(s.charCodeAt(i))) i++
|
|
711
|
+
return i
|
|
712
|
+
}
|
|
713
|
+
|
|
714
|
+
const lineEndings = /\r\n?/g
|
|
715
|
+
const attributeWhitespace = /\r\n|[\t\n\r]/g
|
|
716
|
+
// Characters of an attribute value that need decoding, or are not allowed
|
|
717
|
+
const attributeSpecial = /[&<\t\n\r]/
|
|
718
|
+
const attributeWhitespaceChar = /[\t\n\r]/
|
|
719
|
+
// Attribute values shorter than this are scanned with a loop
|
|
720
|
+
const shortValue = 24
|
|
721
|
+
const publicIdWhitespace = /[ \r\n]+/g
|
|
722
|
+
const decimalDigits = /^[0-9]+$/
|
|
723
|
+
const hexDigits = /^[0-9a-fA-F]+$/
|
|
724
|
+
const versionPattern = /^1\.[0-9]+$/
|
|
725
|
+
const encodingPattern = /^[A-Za-z][A-Za-z0-9._-]*$/
|
|
726
|
+
|
|
727
|
+
const normalizeLines = (s: string): string => s.indexOf("\r") === -1 ? s : s.replace(lineEndings, "\n")
|
|
728
|
+
|
|
729
|
+
// Normalizes the line endings and whitespace of a literal attribute value part
|
|
730
|
+
const normalizeAttribute = (s: string): string => s.replace(attributeWhitespace, " ")
|
|
731
|
+
|
|
732
|
+
const isReservedTarget = (target: string): boolean => target.length === 3 && target.toLowerCase() === "xml"
|
|
733
|
+
|
|
734
|
+
const isUtf8 = (encoding: string): boolean => {
|
|
735
|
+
const lower = encoding.toLowerCase()
|
|
736
|
+
return lower === "utf-8" || lower === "us-ascii"
|
|
737
|
+
}
|
|
738
|
+
|
|
739
|
+
const declarationPattern =
|
|
740
|
+
/^[ \t\r\n]+version[ \t\r\n]*=[ \t\r\n]*(?:"(1\.[0-9]+)"|'(1\.[0-9]+)')(?:[ \t\r\n]+encoding[ \t\r\n]*=[ \t\r\n]*(?:"([A-Za-z][A-Za-z0-9._-]*)"|'([A-Za-z][A-Za-z0-9._-]*)'))?(?:[ \t\r\n]+standalone[ \t\r\n]*=[ \t\r\n]*(?:"(yes|no)"|'(yes|no)'))?[ \t\r\n]*$/
|
|
741
|
+
|
|
742
|
+
const pubidPattern = /^[ \r\na-zA-Z0-9\-'()+,./:=?;!*#@$_%]*$/
|
|
743
|
+
|
|
744
|
+
// States of `Scanner`, which finds where a token split between chunks ends
|
|
745
|
+
const S_START = 0
|
|
746
|
+
const S_TEXT = 1
|
|
747
|
+
const S_LT = 2 // after "<"
|
|
748
|
+
const S_BANG = 3 // after "<!"
|
|
749
|
+
const S_KEYWORD = 4 // matching the rest of "<!--", "<![CDATA[" or "<!DOCTYPE"
|
|
750
|
+
const S_COMMENT = 5
|
|
751
|
+
const S_CDATA = 6
|
|
752
|
+
const S_PI = 7
|
|
753
|
+
const S_TAG = 8
|
|
754
|
+
const S_DOCTYPE = 9 // a DOCTYPE before its internal subset
|
|
755
|
+
const S_SUBSET = 10
|
|
756
|
+
const S_SUBSET_LT = 11
|
|
757
|
+
const S_SUBSET_BANG = 12
|
|
758
|
+
const S_SUBSET_BANG_DASH = 13
|
|
759
|
+
const S_SUBSET_COMMENT = 14
|
|
760
|
+
const S_SUBSET_PI = 15
|
|
761
|
+
const S_DECLARATION = 16 // a markup declaration in the internal subset
|
|
762
|
+
const S_AFTER_SUBSET = 17
|
|
763
|
+
|
|
764
|
+
// Scans a token one character at a time, so that the scan can resume in the
|
|
765
|
+
// next chunk. A token "ends" where it is complete or where it is known to be
|
|
766
|
+
// malformed; the parser then reads the complete token from a single string.
|
|
767
|
+
class Scanner {
|
|
768
|
+
state = S_START
|
|
769
|
+
// A count of matched keyword characters or trailing "-", "]" or "?"
|
|
770
|
+
// characters, or an open quote
|
|
771
|
+
aux = 0
|
|
772
|
+
keyword = ""
|
|
773
|
+
|
|
774
|
+
reset(state: number): void {
|
|
775
|
+
this.state = state
|
|
776
|
+
this.aux = 0
|
|
777
|
+
}
|
|
778
|
+
|
|
779
|
+
// Returns an index of `s` at which the token has ended, or -1
|
|
780
|
+
scan(s: string, i: number): number {
|
|
781
|
+
const n = s.length
|
|
782
|
+
while (i < n) {
|
|
783
|
+
const c = s.charCodeAt(i)
|
|
784
|
+
switch (this.state) {
|
|
785
|
+
case S_START: {
|
|
786
|
+
this.state = c === LT ? S_LT : S_TEXT
|
|
787
|
+
if (c !== LT) continue
|
|
788
|
+
break
|
|
789
|
+
}
|
|
790
|
+
case S_TEXT: {
|
|
791
|
+
return s.indexOf("<", i)
|
|
792
|
+
}
|
|
793
|
+
case S_LT: {
|
|
794
|
+
if (c === BANG) {
|
|
795
|
+
this.state = S_BANG
|
|
796
|
+
} else if (c === QUESTION) {
|
|
797
|
+
this.reset(S_PI)
|
|
798
|
+
} else {
|
|
799
|
+
this.reset(S_TAG)
|
|
800
|
+
continue
|
|
801
|
+
}
|
|
802
|
+
break
|
|
803
|
+
}
|
|
804
|
+
case S_BANG: {
|
|
805
|
+
if (c === DASH) this.keyword = "--"
|
|
806
|
+
else if (c === LBRACKET) this.keyword = "[CDATA["
|
|
807
|
+
else if (c === 68) this.keyword = "DOCTYPE"
|
|
808
|
+
else return i
|
|
809
|
+
this.state = S_KEYWORD
|
|
810
|
+
this.aux = 1
|
|
811
|
+
break
|
|
812
|
+
}
|
|
813
|
+
case S_KEYWORD: {
|
|
814
|
+
if (c !== this.keyword.charCodeAt(this.aux)) return i
|
|
815
|
+
if (++this.aux === this.keyword.length) {
|
|
816
|
+
this.reset(this.keyword === "--" ? S_COMMENT : this.keyword === "DOCTYPE" ? S_DOCTYPE : S_CDATA)
|
|
817
|
+
}
|
|
818
|
+
break
|
|
819
|
+
}
|
|
820
|
+
case S_COMMENT:
|
|
821
|
+
case S_SUBSET_COMMENT: {
|
|
822
|
+
if (c === DASH) {
|
|
823
|
+
this.aux++
|
|
824
|
+
} else if (c === GT && this.aux >= 2) {
|
|
825
|
+
if (this.state === S_COMMENT) return i + 1
|
|
826
|
+
this.reset(S_SUBSET)
|
|
827
|
+
} else {
|
|
828
|
+
this.aux = 0
|
|
829
|
+
}
|
|
830
|
+
break
|
|
831
|
+
}
|
|
832
|
+
case S_CDATA: {
|
|
833
|
+
if (c === RBRACKET) this.aux++
|
|
834
|
+
else if (c === GT && this.aux >= 2) return i + 1
|
|
835
|
+
else this.aux = 0
|
|
836
|
+
break
|
|
837
|
+
}
|
|
838
|
+
case S_PI:
|
|
839
|
+
case S_SUBSET_PI: {
|
|
840
|
+
if (c === GT && this.aux === 1) {
|
|
841
|
+
if (this.state === S_PI) return i + 1
|
|
842
|
+
this.reset(S_SUBSET)
|
|
843
|
+
} else {
|
|
844
|
+
this.aux = c === QUESTION ? 1 : 0
|
|
845
|
+
}
|
|
846
|
+
break
|
|
847
|
+
}
|
|
848
|
+
case S_TAG: {
|
|
849
|
+
// Attribute values cannot contain "<"
|
|
850
|
+
if (c === LT) return i
|
|
851
|
+
if (this.aux === 0) {
|
|
852
|
+
if (c === GT) return i + 1
|
|
853
|
+
if (c === DQUOTE || c === SQUOTE) this.aux = c
|
|
854
|
+
} else if (c === this.aux) {
|
|
855
|
+
this.aux = 0
|
|
856
|
+
}
|
|
857
|
+
break
|
|
858
|
+
}
|
|
859
|
+
case S_DOCTYPE:
|
|
860
|
+
case S_DECLARATION: {
|
|
861
|
+
if (this.aux === 0) {
|
|
862
|
+
if (c === LT) return i
|
|
863
|
+
if (c === GT) {
|
|
864
|
+
if (this.state === S_DOCTYPE) return i + 1
|
|
865
|
+
this.reset(S_SUBSET)
|
|
866
|
+
} else if (c === LBRACKET && this.state === S_DOCTYPE) {
|
|
867
|
+
this.reset(S_SUBSET)
|
|
868
|
+
} else if (c === DQUOTE || c === SQUOTE) {
|
|
869
|
+
this.aux = c
|
|
870
|
+
}
|
|
871
|
+
} else if (c === this.aux) {
|
|
872
|
+
this.aux = 0
|
|
873
|
+
}
|
|
874
|
+
break
|
|
875
|
+
}
|
|
876
|
+
case S_SUBSET: {
|
|
877
|
+
if (c === RBRACKET) this.state = S_AFTER_SUBSET
|
|
878
|
+
else if (c === LT) this.state = S_SUBSET_LT
|
|
879
|
+
else if (c === DQUOTE || c === SQUOTE || c === GT) return i
|
|
880
|
+
break
|
|
881
|
+
}
|
|
882
|
+
case S_SUBSET_LT: {
|
|
883
|
+
if (c === BANG) this.state = S_SUBSET_BANG
|
|
884
|
+
else if (c === QUESTION) this.reset(S_SUBSET_PI)
|
|
885
|
+
else return i
|
|
886
|
+
break
|
|
887
|
+
}
|
|
888
|
+
case S_SUBSET_BANG: {
|
|
889
|
+
if (c === DASH) {
|
|
890
|
+
this.state = S_SUBSET_BANG_DASH
|
|
891
|
+
} else {
|
|
892
|
+
this.reset(S_DECLARATION)
|
|
893
|
+
continue
|
|
894
|
+
}
|
|
895
|
+
break
|
|
896
|
+
}
|
|
897
|
+
case S_SUBSET_BANG_DASH: {
|
|
898
|
+
if (c !== DASH) return i
|
|
899
|
+
this.reset(S_SUBSET_COMMENT)
|
|
900
|
+
break
|
|
901
|
+
}
|
|
902
|
+
case S_AFTER_SUBSET: {
|
|
903
|
+
if (c === GT) return i + 1
|
|
904
|
+
if (!isSpace(c)) return i
|
|
905
|
+
break
|
|
906
|
+
}
|
|
907
|
+
}
|
|
908
|
+
i++
|
|
909
|
+
}
|
|
910
|
+
return -1
|
|
911
|
+
}
|
|
912
|
+
}
|
|
913
|
+
|
|
914
|
+
const PROLOG = 0
|
|
915
|
+
const CONTENT = 1
|
|
916
|
+
const EPILOG = 2
|
|
917
|
+
|
|
918
|
+
const describeToken = (s: string, i: number): string =>
|
|
919
|
+
s.startsWith("<!--", i) ?
|
|
920
|
+
"comment" :
|
|
921
|
+
s.startsWith("<![CDATA[", i) ?
|
|
922
|
+
"CDATA section" :
|
|
923
|
+
s.startsWith("<!DOCTYPE", i) ?
|
|
924
|
+
"DOCTYPE" :
|
|
925
|
+
s.startsWith("<?", i) ?
|
|
926
|
+
"processing instruction" :
|
|
927
|
+
s.startsWith("</", i) ?
|
|
928
|
+
"end tag" :
|
|
929
|
+
"start tag"
|
|
930
|
+
|
|
931
|
+
// Attribute maps inherit nothing, so "__proto__" is an ordinary key and no
|
|
932
|
+
// attribute is inherited. Instances of a constructor are fast-mode objects in
|
|
933
|
+
// V8, several times faster to fill and iterate than the dictionary-mode
|
|
934
|
+
// objects that `Object.create(null)` makes, but V8 makes a hidden class for
|
|
935
|
+
// every distinct key sequence, so `Parser.shapes` decides which tags get one.
|
|
936
|
+
const Attributes = function(this: Record<string, string>) {} as unknown as new() => Record<string, string>
|
|
937
|
+
Attributes.prototype = Object.freeze(Object.create(null))
|
|
938
|
+
|
|
939
|
+
const emptyAttributes: Readonly<Record<string, string>> = Object.freeze(new Attributes())
|
|
940
|
+
|
|
941
|
+
// The number of element names whose attribute order is tracked, and the
|
|
942
|
+
// number of attributes beyond which V8 would turn a fast-mode map into a
|
|
943
|
+
// dictionary anyway
|
|
944
|
+
const maxShapes = 256
|
|
945
|
+
const maxFastAttributes = 16
|
|
946
|
+
|
|
947
|
+
const pendingRun = 256
|
|
948
|
+
|
|
949
|
+
class Parser {
|
|
950
|
+
out: Array<Event> = []
|
|
951
|
+
|
|
952
|
+
// The text being parsed, which starts at document offset `base`
|
|
953
|
+
private buf = ""
|
|
954
|
+
private base = 0
|
|
955
|
+
// Number of characters received, excluding a byte order mark
|
|
956
|
+
received = 0
|
|
957
|
+
private started = false
|
|
958
|
+
|
|
959
|
+
// A token that continues in the next chunk
|
|
960
|
+
private pending: Array<string> | undefined
|
|
961
|
+
private pendingStart = 0
|
|
962
|
+
private pendingLength = 0
|
|
963
|
+
// Number of chunks added to `pending` since its last chunks were joined
|
|
964
|
+
private pendingAdded = 0
|
|
965
|
+
private readonly scanner = new Scanner()
|
|
966
|
+
|
|
967
|
+
// Line and column of document offset `counted`
|
|
968
|
+
private line = 1
|
|
969
|
+
private lineStart = 0
|
|
970
|
+
private counted = 0
|
|
971
|
+
|
|
972
|
+
private state = PROLOG
|
|
973
|
+
private readonly stack: Array<string> = []
|
|
974
|
+
private openNameSize = 0
|
|
975
|
+
// The attribute names of each element name, in the order they were first
|
|
976
|
+
// seen. A tag whose attributes follow that order, or extend it, gets a
|
|
977
|
+
// fast-mode map; one that diverges marks the element `null`, so that later
|
|
978
|
+
// tags get dictionary-mode maps and V8 does not get a hidden class per tag.
|
|
979
|
+
private readonly shapes = new Map<string, Array<string> | null>()
|
|
980
|
+
private doctype = false
|
|
981
|
+
private literalEnd = 0
|
|
982
|
+
// Character data that has not been emitted yet, and its size in the input
|
|
983
|
+
private text = ""
|
|
984
|
+
private textSize = 0
|
|
985
|
+
|
|
986
|
+
private readonly maxTokenSize: number
|
|
987
|
+
private readonly maxDepth: number
|
|
988
|
+
private readonly bytes: boolean
|
|
989
|
+
private ascii = false
|
|
990
|
+
|
|
991
|
+
constructor(maxTokenSize: number, maxDepth: number, bytes: boolean) {
|
|
992
|
+
this.maxTokenSize = maxTokenSize
|
|
993
|
+
this.maxDepth = maxDepth
|
|
994
|
+
this.bytes = bytes
|
|
995
|
+
}
|
|
996
|
+
|
|
997
|
+
// `force` parses a pending token without waiting for its end, so that an
|
|
998
|
+
// error found before invalid input is reported however the input is chunked
|
|
999
|
+
feed(chunk: string, force = false): void {
|
|
1000
|
+
if (chunk.length === 0 && !force) return
|
|
1001
|
+
if (!this.started) {
|
|
1002
|
+
this.started = true
|
|
1003
|
+
if (chunk.charCodeAt(0) === 0xFEFF) chunk = chunk.slice(1)
|
|
1004
|
+
}
|
|
1005
|
+
if (this.bytes) {
|
|
1006
|
+
const nonAscii = chunk.search(/[\u0080-\uFFFF]/)
|
|
1007
|
+
if (nonAscii !== -1) {
|
|
1008
|
+
// The prefix may contain the declaration that selects US-ASCII.
|
|
1009
|
+
this.feed(chunk.slice(0, nonAscii), true)
|
|
1010
|
+
if (this.ascii) throw this.error("Syntax", "invalid US-ASCII byte", this.received)
|
|
1011
|
+
chunk = chunk.slice(nonAscii)
|
|
1012
|
+
}
|
|
1013
|
+
}
|
|
1014
|
+
const invalid = this.bytes ? chunk.search(invalidDecodedChar) : searchInvalid(chunk)
|
|
1015
|
+
if (invalid !== -1) {
|
|
1016
|
+
// Parse up to the invalid character first, so that earlier errors are
|
|
1017
|
+
// reported first however the input is chunked
|
|
1018
|
+
this.consume(chunk.slice(0, invalid), true)
|
|
1019
|
+
const code = chunk.codePointAt(invalid)!.toString(16).toUpperCase().padStart(4, "0")
|
|
1020
|
+
throw this.error("Syntax", `invalid character U+${code}`, this.received)
|
|
1021
|
+
}
|
|
1022
|
+
this.consume(chunk, force)
|
|
1023
|
+
}
|
|
1024
|
+
|
|
1025
|
+
end(): void {
|
|
1026
|
+
if (this.pending !== undefined) {
|
|
1027
|
+
this.load(this.pending.join(""), this.pendingStart)
|
|
1028
|
+
this.pending = undefined
|
|
1029
|
+
}
|
|
1030
|
+
this.parse(true)
|
|
1031
|
+
if (this.state === PROLOG) throw this.error("Syntax", "no root element", this.received)
|
|
1032
|
+
if (this.state === CONTENT) {
|
|
1033
|
+
throw this.error("Syntax", `unclosed element <${this.stack[this.stack.length - 1]}>`, this.received)
|
|
1034
|
+
}
|
|
1035
|
+
}
|
|
1036
|
+
|
|
1037
|
+
error(kind: XmlError["kind"], message: string, at: number): XmlError {
|
|
1038
|
+
if (at > this.counted) {
|
|
1039
|
+
if (this.pending !== undefined) this.count(this.pending.join(""), this.pendingStart, at - this.pendingStart)
|
|
1040
|
+
else this.count(this.buf, this.base, at - this.base)
|
|
1041
|
+
}
|
|
1042
|
+
const line = this.line
|
|
1043
|
+
const column = at - this.lineStart + 1
|
|
1044
|
+
return new XmlError({ kind, message: `${message} at line ${line}, column ${column}`, line, column })
|
|
1045
|
+
}
|
|
1046
|
+
|
|
1047
|
+
// Advances the line count from `counted` to `to`, an index of `s`, which
|
|
1048
|
+
// starts at document offset `base`. Counting resumes only where parsing
|
|
1049
|
+
// stopped, which is never between a CR and an LF.
|
|
1050
|
+
private count(s: string, base: number, to: number): void {
|
|
1051
|
+
const i = this.counted - base
|
|
1052
|
+
if (i >= to) return
|
|
1053
|
+
let cr = s.indexOf("\r", i)
|
|
1054
|
+
let lf = s.indexOf("\n", i)
|
|
1055
|
+
while (true) {
|
|
1056
|
+
if (cr !== -1 && cr < to && (lf === -1 || cr < lf)) {
|
|
1057
|
+
this.line++
|
|
1058
|
+
this.lineStart = base + cr + 1
|
|
1059
|
+
cr = s.indexOf("\r", cr + 1)
|
|
1060
|
+
} else if (lf !== -1 && lf < to) {
|
|
1061
|
+
// The LF of a CRLF does not start a new line
|
|
1062
|
+
if (!(lf > 0 && s.charCodeAt(lf - 1) === CR)) this.line++
|
|
1063
|
+
this.lineStart = base + lf + 1
|
|
1064
|
+
lf = s.indexOf("\n", lf + 1)
|
|
1065
|
+
} else {
|
|
1066
|
+
break
|
|
1067
|
+
}
|
|
1068
|
+
}
|
|
1069
|
+
this.counted = base + to
|
|
1070
|
+
}
|
|
1071
|
+
|
|
1072
|
+
private syntax(message: string, i: number): XmlError {
|
|
1073
|
+
return this.error("Syntax", message, this.base + i)
|
|
1074
|
+
}
|
|
1075
|
+
|
|
1076
|
+
private tokenLimit(at: number): XmlError {
|
|
1077
|
+
return this.error("Limit", `token exceeds maxTokenSize of ${this.maxTokenSize}`, at)
|
|
1078
|
+
}
|
|
1079
|
+
|
|
1080
|
+
private consume(chunk: string, force = false): void {
|
|
1081
|
+
this.received += chunk.length
|
|
1082
|
+
if (this.pending !== undefined) {
|
|
1083
|
+
if (!force && this.scanner.scan(chunk, 0) === -1) {
|
|
1084
|
+
this.pending.push(chunk)
|
|
1085
|
+
this.pendingLength += chunk.length
|
|
1086
|
+
// Joins runs of chunks, so that a token split into many tiny chunks
|
|
1087
|
+
// does not take an array slot for each
|
|
1088
|
+
if (++this.pendingAdded === pendingRun) {
|
|
1089
|
+
this.pending.push(this.pending.splice(-pendingRun).join(""))
|
|
1090
|
+
this.pendingAdded = 0
|
|
1091
|
+
}
|
|
1092
|
+
this.checkPending()
|
|
1093
|
+
return
|
|
1094
|
+
}
|
|
1095
|
+
// Joining makes a flat string, which V8 reads faster than the rope that
|
|
1096
|
+
// concatenation makes
|
|
1097
|
+
this.pending.push(chunk)
|
|
1098
|
+
this.load(this.pending.join(""), this.pendingStart)
|
|
1099
|
+
this.pending = undefined
|
|
1100
|
+
} else {
|
|
1101
|
+
this.load(chunk, this.received - chunk.length)
|
|
1102
|
+
}
|
|
1103
|
+
this.parse(false)
|
|
1104
|
+
}
|
|
1105
|
+
|
|
1106
|
+
private load(buf: string, base: number): void {
|
|
1107
|
+
this.buf = buf
|
|
1108
|
+
this.base = base
|
|
1109
|
+
}
|
|
1110
|
+
|
|
1111
|
+
// Fails an incomplete token over maxTokenSize, preferring an error in the
|
|
1112
|
+
// first maxTokenSize + 1 characters of markup, as `parse` does
|
|
1113
|
+
private checkPending(): void {
|
|
1114
|
+
const text = this.scanner.state === S_TEXT
|
|
1115
|
+
if (this.pendingLength + (text ? this.textSize : 0) <= this.maxTokenSize) return
|
|
1116
|
+
if (!text) {
|
|
1117
|
+
this.load(this.pending!.join("").slice(0, this.maxTokenSize + 1), this.pendingStart)
|
|
1118
|
+
this.markup(this.buf, 0)
|
|
1119
|
+
}
|
|
1120
|
+
throw this.tokenLimit(this.pendingStart)
|
|
1121
|
+
}
|
|
1122
|
+
|
|
1123
|
+
private parse(final: boolean): void {
|
|
1124
|
+
const s = this.buf
|
|
1125
|
+
const n = s.length
|
|
1126
|
+
// Positions of the next "&", CR and "]]>", so that text runs are checked
|
|
1127
|
+
// without searching past them repeatedly
|
|
1128
|
+
let nextAmp = -1
|
|
1129
|
+
let nextCR = -1
|
|
1130
|
+
let nextCdataEnd = -1
|
|
1131
|
+
let i = 0
|
|
1132
|
+
while (i < n) {
|
|
1133
|
+
if (s.charCodeAt(i) !== LT) {
|
|
1134
|
+
let j = s.indexOf("<", i)
|
|
1135
|
+
if (j === -1) {
|
|
1136
|
+
if (!final) break
|
|
1137
|
+
j = n
|
|
1138
|
+
}
|
|
1139
|
+
if (this.state !== CONTENT) {
|
|
1140
|
+
this.checkSize(i, j)
|
|
1141
|
+
this.whitespace(s, i, j)
|
|
1142
|
+
} else {
|
|
1143
|
+
this.addText(i, j - i)
|
|
1144
|
+
if (nextCdataEnd < i) nextCdataEnd = indexOrEnd(s, "]]>", i)
|
|
1145
|
+
if (nextCdataEnd < j) throw this.syntax("\"]]>\" is not allowed in text", nextCdataEnd)
|
|
1146
|
+
if (nextAmp < i) nextAmp = indexOrEnd(s, "&", i)
|
|
1147
|
+
if (nextCR < i) nextCR = indexOrEnd(s, "\r", i)
|
|
1148
|
+
const raw = s.slice(i, j)
|
|
1149
|
+
this.text += nextAmp >= j
|
|
1150
|
+
? (nextCR >= j ? raw : normalizeLines(raw))
|
|
1151
|
+
: this.decodeText(raw, i, false, nextCR < j)
|
|
1152
|
+
}
|
|
1153
|
+
i = j
|
|
1154
|
+
continue
|
|
1155
|
+
}
|
|
1156
|
+
// Markup is parsed from at most maxTokenSize + 1 characters, so that its
|
|
1157
|
+
// errors do not depend on how the input is chunked
|
|
1158
|
+
const long = n - i > this.maxTokenSize
|
|
1159
|
+
const end = this.markup(long ? s.slice(0, i + this.maxTokenSize + 1) : s, i)
|
|
1160
|
+
if (end === -1) {
|
|
1161
|
+
if (long) throw this.tokenLimit(this.base + i)
|
|
1162
|
+
if (final) throw this.syntax(`unterminated ${describeToken(s, i)}`, i)
|
|
1163
|
+
break
|
|
1164
|
+
}
|
|
1165
|
+
i = end
|
|
1166
|
+
}
|
|
1167
|
+
this.count(s, this.base, i)
|
|
1168
|
+
this.buf = ""
|
|
1169
|
+
if (i < n) {
|
|
1170
|
+
const rest = i === 0 ? s : s.slice(i)
|
|
1171
|
+
this.pending = [rest]
|
|
1172
|
+
this.pendingStart = this.base + i
|
|
1173
|
+
this.pendingLength = rest.length
|
|
1174
|
+
this.pendingAdded = 0
|
|
1175
|
+
// Brings the scanner to the end of the incomplete token
|
|
1176
|
+
this.scanner.reset(S_START)
|
|
1177
|
+
this.scanner.scan(rest, 0)
|
|
1178
|
+
this.checkPending()
|
|
1179
|
+
}
|
|
1180
|
+
}
|
|
1181
|
+
|
|
1182
|
+
private flushText(): void {
|
|
1183
|
+
if (this.text.length > 0) {
|
|
1184
|
+
this.out.push({ _tag: "Text", text: this.text })
|
|
1185
|
+
this.text = ""
|
|
1186
|
+
}
|
|
1187
|
+
this.textSize = 0
|
|
1188
|
+
}
|
|
1189
|
+
|
|
1190
|
+
// Adds the size of the text run or CDATA section at `i`. Exceeding the limit
|
|
1191
|
+
// is reported there, rather than at the start of the text.
|
|
1192
|
+
private addText(i: number, size: number): void {
|
|
1193
|
+
this.textSize += size
|
|
1194
|
+
if (this.textSize > this.maxTokenSize) {
|
|
1195
|
+
throw this.tokenLimit(this.base + i)
|
|
1196
|
+
}
|
|
1197
|
+
}
|
|
1198
|
+
|
|
1199
|
+
// Checks that the text run `s[i, j)` outside the root element is whitespace
|
|
1200
|
+
private whitespace(s: string, i: number, j: number): void {
|
|
1201
|
+
for (let k = i; k < j; k++) {
|
|
1202
|
+
if (!isSpace(s.charCodeAt(k))) {
|
|
1203
|
+
throw this.syntax(this.state === PROLOG ? "text before the root element" : "text after the root element", k)
|
|
1204
|
+
}
|
|
1205
|
+
}
|
|
1206
|
+
}
|
|
1207
|
+
|
|
1208
|
+
// Replaces references and normalizes line endings, or attribute whitespace.
|
|
1209
|
+
// `whitespace` is false when `raw` has nothing to normalize.
|
|
1210
|
+
private decodeText(raw: string, offset: number, attribute: boolean, whitespace: boolean): string {
|
|
1211
|
+
let out = ""
|
|
1212
|
+
let k = 0
|
|
1213
|
+
while (true) {
|
|
1214
|
+
const amp = raw.indexOf("&", k)
|
|
1215
|
+
const literal = raw.slice(k, amp === -1 ? raw.length : amp)
|
|
1216
|
+
out += !whitespace ? literal : attribute ? normalizeAttribute(literal) : normalizeLines(literal)
|
|
1217
|
+
if (amp === -1) return out
|
|
1218
|
+
const semicolon = raw.indexOf(";", amp + 1)
|
|
1219
|
+
if (semicolon === -1) throw this.syntax("unterminated reference", offset + amp)
|
|
1220
|
+
out += this.reference(raw, amp, semicolon, offset)
|
|
1221
|
+
k = semicolon + 1
|
|
1222
|
+
}
|
|
1223
|
+
}
|
|
1224
|
+
|
|
1225
|
+
// Decodes the reference `raw[amp, semicolon]`
|
|
1226
|
+
private reference(raw: string, amp: number, semicolon: number, offset: number): string {
|
|
1227
|
+
const c = raw.charCodeAt(amp + 1)
|
|
1228
|
+
// The predefined entities, without slicing their names
|
|
1229
|
+
if (c === 97) {
|
|
1230
|
+
if (raw.startsWith("amp;", amp + 1)) return "&"
|
|
1231
|
+
if (raw.startsWith("apos;", amp + 1)) return "'"
|
|
1232
|
+
} else if (c === 108) {
|
|
1233
|
+
if (raw.startsWith("lt;", amp + 1)) return "<"
|
|
1234
|
+
} else if (c === 103) {
|
|
1235
|
+
if (raw.startsWith("gt;", amp + 1)) return ">"
|
|
1236
|
+
} else if (c === 113) {
|
|
1237
|
+
if (raw.startsWith("quot;", amp + 1)) return "\""
|
|
1238
|
+
}
|
|
1239
|
+
if (c === HASH) {
|
|
1240
|
+
const hex = raw.charCodeAt(amp + 2) === LOWER_X
|
|
1241
|
+
const digits = raw.slice(amp + (hex ? 3 : 2), semicolon)
|
|
1242
|
+
const code = (hex ? hexDigits : decimalDigits).test(digits) ? parseInt(digits, hex ? 16 : 10) : -1
|
|
1243
|
+
if (!isChar(code)) throw this.syntax("invalid character reference", offset + amp)
|
|
1244
|
+
return String.fromCodePoint(code)
|
|
1245
|
+
}
|
|
1246
|
+
const name = raw.slice(amp + 1, semicolon)
|
|
1247
|
+
if (!isName(name)) throw this.syntax("invalid reference", offset + amp)
|
|
1248
|
+
if (this.doctype) {
|
|
1249
|
+
throw this.error(
|
|
1250
|
+
"Unsupported",
|
|
1251
|
+
`entity references other than the predefined entities are not supported: &${name};`,
|
|
1252
|
+
this.base + offset + amp
|
|
1253
|
+
)
|
|
1254
|
+
}
|
|
1255
|
+
throw this.syntax(`undefined entity &${name};`, offset + amp)
|
|
1256
|
+
}
|
|
1257
|
+
|
|
1258
|
+
// Parses the markup at `i`, and returns its end or -1 when it is incomplete
|
|
1259
|
+
private markup(s: string, i: number): number {
|
|
1260
|
+
const n = s.length
|
|
1261
|
+
if (i + 1 >= n) return -1
|
|
1262
|
+
const c = s.charCodeAt(i + 1)
|
|
1263
|
+
if (c === SLASH) return this.endTag(s, i)
|
|
1264
|
+
if (c === QUESTION) return this.processingInstruction(s, i)
|
|
1265
|
+
if (c !== BANG) return this.startTag(s, i)
|
|
1266
|
+
if (i + 2 >= n) return -1
|
|
1267
|
+
const keyword = s.charCodeAt(i + 2) === DASH ? "<!--" : s.charCodeAt(i + 2) === LBRACKET ? "<![CDATA[" : "<!DOCTYPE"
|
|
1268
|
+
if (!s.startsWith(keyword, i)) {
|
|
1269
|
+
if (n - i < keyword.length && keyword.startsWith(s.slice(i))) return -1
|
|
1270
|
+
throw this.syntax("invalid markup", i)
|
|
1271
|
+
}
|
|
1272
|
+
return keyword === "<!--"
|
|
1273
|
+
? this.comment(s, i)
|
|
1274
|
+
: keyword === "<!DOCTYPE"
|
|
1275
|
+
? this.doctypeDeclaration(s, i)
|
|
1276
|
+
: this.cdata(s, i)
|
|
1277
|
+
}
|
|
1278
|
+
|
|
1279
|
+
private checkSize(i: number, end: number): void {
|
|
1280
|
+
if (end - i > this.maxTokenSize) {
|
|
1281
|
+
throw this.tokenLimit(this.base + i)
|
|
1282
|
+
}
|
|
1283
|
+
}
|
|
1284
|
+
|
|
1285
|
+
private startTag(s: string, i: number): number {
|
|
1286
|
+
const n = s.length
|
|
1287
|
+
if (this.state === EPILOG) throw this.syntax("content after the root element", i)
|
|
1288
|
+
let j = scanName(s, i + 1, n)
|
|
1289
|
+
if (j === i + 1) throw this.syntax("invalid element name", i + 1)
|
|
1290
|
+
if (j >= n) return -1
|
|
1291
|
+
// In V8, a slice of 13 or more characters keeps its whole input chunk
|
|
1292
|
+
// alive, and the name of an open element is held until its end tag, so
|
|
1293
|
+
// long names are copied
|
|
1294
|
+
const name = j - i - 1 < 13 ? s.slice(i + 1, j) : (" " + s.slice(i + 1, j)).slice(1)
|
|
1295
|
+
let attributes: Record<string, string> | undefined
|
|
1296
|
+
let shape: Array<string> | null | undefined
|
|
1297
|
+
let index = 0
|
|
1298
|
+
let selfClosing = false
|
|
1299
|
+
while (true) {
|
|
1300
|
+
let c = s.charCodeAt(j)
|
|
1301
|
+
const space = isSpace(c)
|
|
1302
|
+
if (space) {
|
|
1303
|
+
j = skipSpace(s, j, n)
|
|
1304
|
+
if (j >= n) return -1
|
|
1305
|
+
c = s.charCodeAt(j)
|
|
1306
|
+
}
|
|
1307
|
+
if (c === GT) {
|
|
1308
|
+
j++
|
|
1309
|
+
break
|
|
1310
|
+
}
|
|
1311
|
+
if (c === SLASH) {
|
|
1312
|
+
if (j + 1 >= n) return -1
|
|
1313
|
+
if (s.charCodeAt(j + 1) !== GT) throw this.syntax("expected \">\"", j + 1)
|
|
1314
|
+
j += 2
|
|
1315
|
+
selfClosing = true
|
|
1316
|
+
break
|
|
1317
|
+
}
|
|
1318
|
+
if (!space) throw this.syntax("expected whitespace, \">\" or \"/>\"", j)
|
|
1319
|
+
const nameStart = j
|
|
1320
|
+
j = scanName(s, j, n)
|
|
1321
|
+
if (j === nameStart) throw this.syntax("invalid attribute name", j)
|
|
1322
|
+
if (j >= n) return -1
|
|
1323
|
+
const attribute = s.slice(nameStart, j)
|
|
1324
|
+
j = skipSpace(s, j, n)
|
|
1325
|
+
if (j >= n) return -1
|
|
1326
|
+
if (s.charCodeAt(j) !== EQUALS) throw this.syntax("expected \"=\"", j)
|
|
1327
|
+
j = skipSpace(s, j + 1, n)
|
|
1328
|
+
if (j >= n) return -1
|
|
1329
|
+
const quote = s.charCodeAt(j)
|
|
1330
|
+
if (quote !== DQUOTE && quote !== SQUOTE) throw this.syntax("expected a quoted attribute value", j)
|
|
1331
|
+
const close = s.indexOf(quote === DQUOTE ? "\"" : "'", j + 1)
|
|
1332
|
+
if (close === -1) {
|
|
1333
|
+
const lt = s.indexOf("<", j + 1)
|
|
1334
|
+
if (lt !== -1) throw this.syntax("\"<\" is not allowed in attribute values", lt)
|
|
1335
|
+
return -1
|
|
1336
|
+
}
|
|
1337
|
+
const value = this.attributeValue(s, j + 1, close)
|
|
1338
|
+
if (attributes === undefined) {
|
|
1339
|
+
shape = this.shapes.get(name)
|
|
1340
|
+
if (shape === undefined && this.shapes.size < maxShapes) {
|
|
1341
|
+
shape = []
|
|
1342
|
+
this.shapes.set(name, shape)
|
|
1343
|
+
}
|
|
1344
|
+
attributes = shape === undefined || shape === null || shape.length > maxFastAttributes ?
|
|
1345
|
+
Object.create(null) as Record<string, string> :
|
|
1346
|
+
new Attributes()
|
|
1347
|
+
} else if (attributes[attribute] !== undefined) {
|
|
1348
|
+
throw this.syntax(`duplicate attribute ${attribute}`, nameStart)
|
|
1349
|
+
}
|
|
1350
|
+
if (shape !== undefined && shape !== null && shape.length <= maxFastAttributes) {
|
|
1351
|
+
// Stored names are copied, as they outlive the chunk
|
|
1352
|
+
if (index === shape.length) shape.push((" " + attribute).slice(1))
|
|
1353
|
+
else if (shape[index] !== attribute) {
|
|
1354
|
+
this.shapes.set(name, null)
|
|
1355
|
+
shape = null
|
|
1356
|
+
}
|
|
1357
|
+
}
|
|
1358
|
+
index++
|
|
1359
|
+
attributes[attribute] = value
|
|
1360
|
+
j = close + 1
|
|
1361
|
+
if (j >= n) return -1
|
|
1362
|
+
}
|
|
1363
|
+
this.checkSize(i, j)
|
|
1364
|
+
if (this.stack.length >= this.maxDepth) {
|
|
1365
|
+
throw this.error("Limit", `element nesting exceeds maxDepth of ${this.maxDepth}`, this.base + i)
|
|
1366
|
+
}
|
|
1367
|
+
if (!selfClosing && this.openNameSize + name.length > this.maxTokenSize) {
|
|
1368
|
+
throw this.error("Limit", `open element names exceed maxTokenSize of ${this.maxTokenSize}`, this.base + i)
|
|
1369
|
+
}
|
|
1370
|
+
this.flushText()
|
|
1371
|
+
this.out.push({ _tag: "StartElement", name, attributes: attributes ?? emptyAttributes })
|
|
1372
|
+
if (selfClosing) {
|
|
1373
|
+
this.out.push({ _tag: "EndElement", name })
|
|
1374
|
+
if (this.stack.length === 0) this.state = EPILOG
|
|
1375
|
+
} else {
|
|
1376
|
+
this.stack.push(name)
|
|
1377
|
+
this.openNameSize += name.length
|
|
1378
|
+
this.state = CONTENT
|
|
1379
|
+
}
|
|
1380
|
+
return j
|
|
1381
|
+
}
|
|
1382
|
+
|
|
1383
|
+
private attributeValue(s: string, i: number, j: number): string {
|
|
1384
|
+
let reference = false
|
|
1385
|
+
let whitespace = false
|
|
1386
|
+
if (j - i < shortValue) {
|
|
1387
|
+
for (let k = i; k < j; k++) {
|
|
1388
|
+
const c = s.charCodeAt(k)
|
|
1389
|
+
if (c === LT) throw this.syntax("\"<\" is not allowed in attribute values", k)
|
|
1390
|
+
if (c === AMPERSAND) reference = true
|
|
1391
|
+
else if (c === TAB || c === LF || c === CR) whitespace = true
|
|
1392
|
+
}
|
|
1393
|
+
if (!reference && !whitespace) return s.slice(i, j)
|
|
1394
|
+
} else {
|
|
1395
|
+
// A regex search beats the loop above on long values
|
|
1396
|
+
const value = s.slice(i, j)
|
|
1397
|
+
const special = value.search(attributeSpecial)
|
|
1398
|
+
if (special === -1) return value
|
|
1399
|
+
const lt = value.indexOf("<", special)
|
|
1400
|
+
if (lt !== -1) throw this.syntax("\"<\" is not allowed in attribute values", i + lt)
|
|
1401
|
+
reference = value.indexOf("&", special) !== -1
|
|
1402
|
+
whitespace = !reference || attributeWhitespaceChar.test(value)
|
|
1403
|
+
}
|
|
1404
|
+
const raw = s.slice(i, j)
|
|
1405
|
+
return reference ? this.decodeText(raw, i, true, whitespace) : normalizeAttribute(raw)
|
|
1406
|
+
}
|
|
1407
|
+
|
|
1408
|
+
private endTag(s: string, i: number): number {
|
|
1409
|
+
const n = s.length
|
|
1410
|
+
const j = scanName(s, i + 2, n)
|
|
1411
|
+
if (j === i + 2) {
|
|
1412
|
+
if (j >= n) return -1
|
|
1413
|
+
throw this.syntax("invalid element name", j)
|
|
1414
|
+
}
|
|
1415
|
+
const k = skipSpace(s, j, n)
|
|
1416
|
+
if (k >= n) return -1
|
|
1417
|
+
if (s.charCodeAt(k) !== GT) throw this.syntax("expected \">\"", k)
|
|
1418
|
+
const open = this.stack.length > 0 ? this.stack[this.stack.length - 1] : undefined
|
|
1419
|
+
if (open === undefined) throw this.syntax("end tag without a start tag", i)
|
|
1420
|
+
if (j - i - 2 !== open.length || !s.startsWith(open, i + 2)) {
|
|
1421
|
+
throw this.syntax(`end tag </${s.slice(i + 2, j)}> does not match <${open}>`, i)
|
|
1422
|
+
}
|
|
1423
|
+
this.checkSize(i, k + 1)
|
|
1424
|
+
this.flushText()
|
|
1425
|
+
this.stack.pop()
|
|
1426
|
+
this.openNameSize -= open.length
|
|
1427
|
+
this.out.push({ _tag: "EndElement", name: open })
|
|
1428
|
+
if (this.stack.length === 0) this.state = EPILOG
|
|
1429
|
+
return k + 1
|
|
1430
|
+
}
|
|
1431
|
+
|
|
1432
|
+
private comment(s: string, i: number): number {
|
|
1433
|
+
const end = s.indexOf("-->", i + 4)
|
|
1434
|
+
if (end === -1) return -1
|
|
1435
|
+
const dashes = s.indexOf("--", i + 4)
|
|
1436
|
+
if (dashes < end) throw this.syntax("\"--\" is not allowed in comments", dashes)
|
|
1437
|
+
this.checkSize(i, end + 3)
|
|
1438
|
+
this.flushText()
|
|
1439
|
+
this.out.push({ _tag: "Comment", text: normalizeLines(s.slice(i + 4, end)) })
|
|
1440
|
+
return end + 3
|
|
1441
|
+
}
|
|
1442
|
+
|
|
1443
|
+
private processingInstruction(s: string, i: number): number {
|
|
1444
|
+
const end = s.indexOf("?>", i + 2)
|
|
1445
|
+
if (end === -1) return -1
|
|
1446
|
+
const t = scanName(s, i + 2, end)
|
|
1447
|
+
if (t === i + 2) throw this.syntax("invalid processing instruction target", i + 2)
|
|
1448
|
+
const target = s.slice(i + 2, t)
|
|
1449
|
+
if (isReservedTarget(target)) {
|
|
1450
|
+
if (target === "xml" && this.base + i === 0) return this.declaration(s, i, t, end)
|
|
1451
|
+
throw this.syntax(
|
|
1452
|
+
target === "xml" ?
|
|
1453
|
+
"the XML declaration is only allowed at the start of the document" :
|
|
1454
|
+
`processing instruction target ${target} is reserved`,
|
|
1455
|
+
i
|
|
1456
|
+
)
|
|
1457
|
+
}
|
|
1458
|
+
let data = ""
|
|
1459
|
+
if (t < end) {
|
|
1460
|
+
if (!isSpace(s.charCodeAt(t))) throw this.syntax("expected whitespace after the target", t)
|
|
1461
|
+
data = normalizeLines(s.slice(skipSpace(s, t, end), end))
|
|
1462
|
+
}
|
|
1463
|
+
this.checkSize(i, end + 2)
|
|
1464
|
+
this.flushText()
|
|
1465
|
+
this.out.push({ _tag: "ProcessingInstruction", target, data })
|
|
1466
|
+
return end + 2
|
|
1467
|
+
}
|
|
1468
|
+
|
|
1469
|
+
private declaration(s: string, i: number, t: number, end: number): number {
|
|
1470
|
+
this.checkSize(i, end + 2)
|
|
1471
|
+
const match = declarationPattern.exec(s.slice(t, end))
|
|
1472
|
+
if (match === null) throw this.syntax("invalid XML declaration", i)
|
|
1473
|
+
const encoding = match[3] ?? match[4]
|
|
1474
|
+
const standalone = match[5] ?? match[6]
|
|
1475
|
+
if (this.bytes && encoding !== undefined && !isUtf8(encoding)) {
|
|
1476
|
+
throw this.error(
|
|
1477
|
+
"Unsupported",
|
|
1478
|
+
`encoding ${encoding} is not supported for byte input, decode the bytes to text first`,
|
|
1479
|
+
this.base + i
|
|
1480
|
+
)
|
|
1481
|
+
}
|
|
1482
|
+
this.ascii = this.bytes && encoding?.toLowerCase() === "us-ascii"
|
|
1483
|
+
const event: { -readonly [K in keyof Declaration]: Declaration[K] } = {
|
|
1484
|
+
_tag: "Declaration",
|
|
1485
|
+
version: match[1] ?? match[2]
|
|
1486
|
+
}
|
|
1487
|
+
if (encoding !== undefined) event.encoding = encoding
|
|
1488
|
+
if (standalone !== undefined) event.standalone = standalone === "yes"
|
|
1489
|
+
this.out.push(event)
|
|
1490
|
+
return end + 2
|
|
1491
|
+
}
|
|
1492
|
+
|
|
1493
|
+
private cdata(s: string, i: number): number {
|
|
1494
|
+
const end = s.indexOf("]]>", i + 9)
|
|
1495
|
+
if (end === -1) return -1
|
|
1496
|
+
if (this.state !== CONTENT) throw this.syntax("CDATA sections are only allowed inside the root element", i)
|
|
1497
|
+
this.addText(i, end + 3 - i)
|
|
1498
|
+
this.text += normalizeLines(s.slice(i + 9, end))
|
|
1499
|
+
return end + 3
|
|
1500
|
+
}
|
|
1501
|
+
|
|
1502
|
+
private doctypeDeclaration(s: string, i: number): number {
|
|
1503
|
+
if (this.state !== PROLOG || this.doctype) {
|
|
1504
|
+
throw this.syntax("a DOCTYPE is only allowed once, before the root element", i)
|
|
1505
|
+
}
|
|
1506
|
+
const scanner = new Scanner()
|
|
1507
|
+
scanner.reset(S_DOCTYPE)
|
|
1508
|
+
const end = scanner.scan(s, i + 9)
|
|
1509
|
+
if (end === -1) return -1
|
|
1510
|
+
this.checkSize(i, end)
|
|
1511
|
+
this.doctype = true
|
|
1512
|
+
let j = this.space(s, i + 9, end)
|
|
1513
|
+
const nameEnd = this.name(s, j, end)
|
|
1514
|
+
const event: { -readonly [K in keyof Doctype]: Doctype[K] } = { _tag: "Doctype", name: s.slice(j, nameEnd) }
|
|
1515
|
+
j = skipSpace(s, nameEnd, end)
|
|
1516
|
+
if (j > nameEnd && (s.startsWith("PUBLIC", j) || s.startsWith("SYSTEM", j))) {
|
|
1517
|
+
if (s.charCodeAt(j) === 80) {
|
|
1518
|
+
// Whitespace in public identifiers is normalized for matching
|
|
1519
|
+
event.publicId = this.publicLiteral(s, this.space(s, j + 6, end), end).replace(publicIdWhitespace, " ").trim()
|
|
1520
|
+
j = this.literalEnd
|
|
1521
|
+
}
|
|
1522
|
+
event.systemId = normalizeLines(
|
|
1523
|
+
this.literal(s, this.space(s, j + (event.publicId === undefined ? 6 : 0), end), end)
|
|
1524
|
+
)
|
|
1525
|
+
j = skipSpace(s, this.literalEnd, end)
|
|
1526
|
+
}
|
|
1527
|
+
if (s.charCodeAt(j) === LBRACKET) {
|
|
1528
|
+
// The scanner skips the internal subset, whose declarations are not
|
|
1529
|
+
// checked, and ends the token early only at malformed markup
|
|
1530
|
+
if (scanner.state !== S_AFTER_SUBSET) throw this.syntax("invalid markup in the internal subset", end)
|
|
1531
|
+
j = skipSpace(s, s.lastIndexOf("]", end - 1) + 1, end)
|
|
1532
|
+
}
|
|
1533
|
+
if (j !== end - 1 || s.charCodeAt(j) !== GT) throw this.syntax("invalid DOCTYPE", j)
|
|
1534
|
+
this.out.push(event)
|
|
1535
|
+
return end
|
|
1536
|
+
}
|
|
1537
|
+
|
|
1538
|
+
// Skips the whitespace that is required at `i`
|
|
1539
|
+
private space(s: string, i: number, end: number): number {
|
|
1540
|
+
if (i >= end || !isSpace(s.charCodeAt(i))) throw this.syntax("expected whitespace", i)
|
|
1541
|
+
return skipSpace(s, i, end)
|
|
1542
|
+
}
|
|
1543
|
+
|
|
1544
|
+
// Returns the end of the name that is required at `i`
|
|
1545
|
+
private name(s: string, i: number, end: number): number {
|
|
1546
|
+
const nameEnd = scanName(s, i, end)
|
|
1547
|
+
if (nameEnd === i) throw this.syntax("expected a name", i)
|
|
1548
|
+
return nameEnd
|
|
1549
|
+
}
|
|
1550
|
+
|
|
1551
|
+
// Reads the quoted literal at `i`, and sets `literalEnd` to the index after it
|
|
1552
|
+
private literal(s: string, i: number, end: number): string {
|
|
1553
|
+
const quote = s.charCodeAt(i)
|
|
1554
|
+
if (quote !== DQUOTE && quote !== SQUOTE) throw this.syntax("expected a quoted literal", i)
|
|
1555
|
+
const close = s.indexOf(quote === DQUOTE ? "\"" : "'", i + 1)
|
|
1556
|
+
// Unreachable while the scanner ends a DOCTYPE only after its literals close
|
|
1557
|
+
if (close === -1 || close >= end) throw this.syntax("unterminated literal", i)
|
|
1558
|
+
this.literalEnd = close + 1
|
|
1559
|
+
return s.slice(i + 1, close)
|
|
1560
|
+
}
|
|
1561
|
+
|
|
1562
|
+
private publicLiteral(s: string, i: number, end: number): string {
|
|
1563
|
+
const literal = this.literal(s, i, end)
|
|
1564
|
+
if (!pubidPattern.test(literal)) throw this.syntax("invalid public identifier", i)
|
|
1565
|
+
return literal
|
|
1566
|
+
}
|
|
1567
|
+
}
|
|
1568
|
+
|
|
1569
|
+
const indexOrEnd = (s: string, search: string, from: number): number => {
|
|
1570
|
+
const i = s.indexOf(search, from)
|
|
1571
|
+
return i === -1 ? s.length : i
|
|
1572
|
+
}
|
|
1573
|
+
|
|
1574
|
+
class TextInput implements Machine<string, Event> {
|
|
1575
|
+
private readonly parser: Parser
|
|
1576
|
+
// A high surrogate at the end of a chunk, which pairs with the next chunk
|
|
1577
|
+
private surrogate = ""
|
|
1578
|
+
|
|
1579
|
+
constructor(parser: Parser) {
|
|
1580
|
+
this.parser = parser
|
|
1581
|
+
}
|
|
1582
|
+
|
|
1583
|
+
get out(): Array<Event> {
|
|
1584
|
+
return this.parser.out
|
|
1585
|
+
}
|
|
1586
|
+
set out(out: Array<Event>) {
|
|
1587
|
+
this.parser.out = out
|
|
1588
|
+
}
|
|
1589
|
+
|
|
1590
|
+
push(chunk: string): void {
|
|
1591
|
+
if (this.surrogate !== "") {
|
|
1592
|
+
chunk = this.surrogate + chunk
|
|
1593
|
+
this.surrogate = ""
|
|
1594
|
+
}
|
|
1595
|
+
const last = chunk.charCodeAt(chunk.length - 1)
|
|
1596
|
+
if (last >= 0xD800 && last <= 0xDBFF) {
|
|
1597
|
+
this.surrogate = chunk.slice(-1)
|
|
1598
|
+
chunk = chunk.slice(0, -1)
|
|
1599
|
+
}
|
|
1600
|
+
this.parser.feed(chunk)
|
|
1601
|
+
}
|
|
1602
|
+
|
|
1603
|
+
end(): void {
|
|
1604
|
+
// An unpaired high surrogate fails as an invalid character
|
|
1605
|
+
this.parser.feed(this.surrogate)
|
|
1606
|
+
this.parser.end()
|
|
1607
|
+
}
|
|
1608
|
+
}
|
|
1609
|
+
|
|
1610
|
+
const utf8Length = (lead: number): number => lead >= 0xF0 ? 4 : lead >= 0xE0 ? 3 : lead >= 0xC0 ? 2 : 1
|
|
1611
|
+
|
|
1612
|
+
// Returns the length of the valid UTF-8 prefix of `bytes`
|
|
1613
|
+
const validUtf8 = (bytes: Uint8Array): number => {
|
|
1614
|
+
let i = 0
|
|
1615
|
+
while (i < bytes.length) {
|
|
1616
|
+
const lead = bytes[i]
|
|
1617
|
+
if (lead < 0x80) {
|
|
1618
|
+
i++
|
|
1619
|
+
continue
|
|
1620
|
+
}
|
|
1621
|
+
const length = lead >= 0xC2 && lead <= 0xF4 ? utf8Length(lead) : 0
|
|
1622
|
+
if (length === 0 || i + length > bytes.length) return i
|
|
1623
|
+
let code = lead & (0xFF >> (length + 1))
|
|
1624
|
+
for (let k = 1; k < length; k++) {
|
|
1625
|
+
const c = bytes[i + k]
|
|
1626
|
+
if ((c & 0xC0) !== 0x80) return i
|
|
1627
|
+
code = (code << 6) | (c & 0x3F)
|
|
1628
|
+
}
|
|
1629
|
+
const min = length === 2 ? 0x80 : length === 3 ? 0x800 : 0x10000
|
|
1630
|
+
if (code < min || code > 0x10FFFF || (code >= 0xD800 && code <= 0xDFFF)) return i
|
|
1631
|
+
i += length
|
|
1632
|
+
}
|
|
1633
|
+
return i
|
|
1634
|
+
}
|
|
1635
|
+
|
|
1636
|
+
const utf8Decoder = new TextDecoder("utf-8", { fatal: true, ignoreBOM: true })
|
|
1637
|
+
|
|
1638
|
+
// Decodes UTF-8 without streaming state, so that the position of invalid bytes
|
|
1639
|
+
// is known: an incomplete sequence at the end of a chunk is carried over.
|
|
1640
|
+
class Utf8Input implements Machine<Uint8Array, Event> {
|
|
1641
|
+
private readonly parser: Parser
|
|
1642
|
+
private carry: Uint8Array | undefined
|
|
1643
|
+
private started = false
|
|
1644
|
+
|
|
1645
|
+
constructor(parser: Parser) {
|
|
1646
|
+
this.parser = parser
|
|
1647
|
+
}
|
|
1648
|
+
|
|
1649
|
+
get out(): Array<Event> {
|
|
1650
|
+
return this.parser.out
|
|
1651
|
+
}
|
|
1652
|
+
set out(out: Array<Event>) {
|
|
1653
|
+
this.parser.out = out
|
|
1654
|
+
}
|
|
1655
|
+
|
|
1656
|
+
push(chunk: Uint8Array): void {
|
|
1657
|
+
if (!this.started && chunk.length > 0) {
|
|
1658
|
+
const first = this.carry === undefined ? chunk[0] : this.carry[0]
|
|
1659
|
+
const second = this.carry === undefined ? chunk[1] : chunk[0]
|
|
1660
|
+
if ((first === 0xFE && second === 0xFF) || (first === 0xFF && second === 0xFE)) {
|
|
1661
|
+
throw this.parser.error(
|
|
1662
|
+
"Unsupported",
|
|
1663
|
+
"UTF-16 is not supported for byte input, decode the bytes to text first",
|
|
1664
|
+
0
|
|
1665
|
+
)
|
|
1666
|
+
}
|
|
1667
|
+
// Keep a lone BOM prefix pending in the UTF-8 carry below
|
|
1668
|
+
this.started = second !== undefined || (first !== 0xFE && first !== 0xFF)
|
|
1669
|
+
}
|
|
1670
|
+
let start = 0
|
|
1671
|
+
if (this.carry !== undefined) {
|
|
1672
|
+
const need = utf8Length(this.carry[0]) - this.carry.length
|
|
1673
|
+
const head = new Uint8Array(this.carry.length + Math.min(need, chunk.length))
|
|
1674
|
+
head.set(this.carry)
|
|
1675
|
+
head.set(chunk.subarray(0, need), this.carry.length)
|
|
1676
|
+
if (chunk.length < need) {
|
|
1677
|
+
this.carry = head
|
|
1678
|
+
return
|
|
1679
|
+
}
|
|
1680
|
+
this.carry = undefined
|
|
1681
|
+
this.decode(head)
|
|
1682
|
+
start = need
|
|
1683
|
+
}
|
|
1684
|
+
const n = chunk.length
|
|
1685
|
+
let end = n
|
|
1686
|
+
for (let k = 1; k <= 3 && n - k >= start; k++) {
|
|
1687
|
+
const b = chunk[n - k]
|
|
1688
|
+
if ((b & 0xC0) === 0x80) continue
|
|
1689
|
+
if (b >= 0xC0 && k < utf8Length(b)) end = n - k
|
|
1690
|
+
break
|
|
1691
|
+
}
|
|
1692
|
+
if (end < n) this.carry = chunk.slice(end)
|
|
1693
|
+
if (end > start) this.decode(start === 0 && end === n ? chunk : chunk.subarray(start, end))
|
|
1694
|
+
}
|
|
1695
|
+
|
|
1696
|
+
end(): void {
|
|
1697
|
+
// The carried bytes may also be an invalid sequence, such as a single 0xFF
|
|
1698
|
+
if (this.carry !== undefined) {
|
|
1699
|
+
this.parser.feed("", true)
|
|
1700
|
+
throw this.parser.error("Syntax", "invalid UTF-8", this.parser.received)
|
|
1701
|
+
}
|
|
1702
|
+
this.parser.end()
|
|
1703
|
+
}
|
|
1704
|
+
|
|
1705
|
+
private decode(bytes: Uint8Array): void {
|
|
1706
|
+
let text: string
|
|
1707
|
+
try {
|
|
1708
|
+
text = utf8Decoder.decode(bytes)
|
|
1709
|
+
} catch {
|
|
1710
|
+
this.parser.feed(utf8Decoder.decode(bytes.subarray(0, validUtf8(bytes))), true)
|
|
1711
|
+
throw this.parser.error("Syntax", "invalid UTF-8", this.parser.received)
|
|
1712
|
+
}
|
|
1713
|
+
this.parser.feed(text)
|
|
1714
|
+
}
|
|
1715
|
+
}
|
|
1716
|
+
|
|
1717
|
+
interface MutableElement {
|
|
1718
|
+
readonly name: string
|
|
1719
|
+
readonly attributes: Readonly<Record<string, string>>
|
|
1720
|
+
readonly children: Array<MutableElement | string>
|
|
1721
|
+
}
|
|
1722
|
+
|
|
1723
|
+
class Collector implements Machine<Event, Element> {
|
|
1724
|
+
out: Array<Element> = []
|
|
1725
|
+
private depth = 0
|
|
1726
|
+
// Number of open elements, from the root, that match the path
|
|
1727
|
+
private matched = 0
|
|
1728
|
+
// The element being collected and its open descendants
|
|
1729
|
+
private readonly stack: Array<MutableElement> = []
|
|
1730
|
+
private size = 0
|
|
1731
|
+
private readonly path: ReadonlyArray<string>
|
|
1732
|
+
private readonly maxElementSize: number
|
|
1733
|
+
|
|
1734
|
+
constructor(path: ReadonlyArray<string>, maxElementSize: number) {
|
|
1735
|
+
this.path = path
|
|
1736
|
+
this.maxElementSize = maxElementSize
|
|
1737
|
+
}
|
|
1738
|
+
|
|
1739
|
+
push(event: Event): void {
|
|
1740
|
+
switch (event._tag) {
|
|
1741
|
+
case "StartElement": {
|
|
1742
|
+
const depth = this.depth++
|
|
1743
|
+
if (this.stack.length === 0) {
|
|
1744
|
+
const segment = this.path[depth]
|
|
1745
|
+
if (this.matched !== depth || (segment !== "*" && segment !== event.name)) return
|
|
1746
|
+
if (++this.matched < this.path.length) return
|
|
1747
|
+
this.size = 0
|
|
1748
|
+
}
|
|
1749
|
+
const element: MutableElement = { name: event.name, attributes: event.attributes, children: [] }
|
|
1750
|
+
if (this.stack.length > 0) this.stack[this.stack.length - 1].children.push(element)
|
|
1751
|
+
this.stack.push(element)
|
|
1752
|
+
let size = event.name.length
|
|
1753
|
+
for (const key in event.attributes) size += key.length + event.attributes[key].length
|
|
1754
|
+
this.grow(size)
|
|
1755
|
+
return
|
|
1756
|
+
}
|
|
1757
|
+
case "EndElement": {
|
|
1758
|
+
if (this.depth === 0) throw invalidEvent(`end tag </${event.name}> without a start tag`)
|
|
1759
|
+
if (this.stack.length > 0) {
|
|
1760
|
+
const element = this.stack.pop()!
|
|
1761
|
+
if (this.stack.length === 0) this.out.push(element)
|
|
1762
|
+
}
|
|
1763
|
+
if (this.matched === this.depth) this.matched--
|
|
1764
|
+
this.depth--
|
|
1765
|
+
return
|
|
1766
|
+
}
|
|
1767
|
+
case "Text": {
|
|
1768
|
+
if (this.stack.length === 0 || event.text.length === 0) return
|
|
1769
|
+
this.grow(event.text.length)
|
|
1770
|
+
const children = this.stack[this.stack.length - 1].children
|
|
1771
|
+
const last = children.length - 1
|
|
1772
|
+
if (last >= 0 && typeof children[last] === "string") children[last] += event.text
|
|
1773
|
+
else children.push(event.text)
|
|
1774
|
+
return
|
|
1775
|
+
}
|
|
1776
|
+
}
|
|
1777
|
+
}
|
|
1778
|
+
|
|
1779
|
+
end(): void {
|
|
1780
|
+
if (this.depth > 0) throw invalidEvent("events ended inside an element")
|
|
1781
|
+
}
|
|
1782
|
+
|
|
1783
|
+
private grow(size: number): void {
|
|
1784
|
+
this.size += size
|
|
1785
|
+
if (this.size > this.maxElementSize) {
|
|
1786
|
+
throw positionless("Limit", `element <${this.stack[0].name}> exceeds maxElementSize of ${this.maxElementSize}`)
|
|
1787
|
+
}
|
|
1788
|
+
}
|
|
1789
|
+
}
|
|
1790
|
+
|
|
1791
|
+
// JavaScriptCore gives every Error its own source `line` and `column`, which
|
|
1792
|
+
// would pass for an XML position, so errors without one set both to undefined
|
|
1793
|
+
const positionless = (kind: XmlError["kind"], message: string) =>
|
|
1794
|
+
new XmlError({ kind, message, line: undefined, column: undefined })
|
|
1795
|
+
|
|
1796
|
+
const invalidEvent = (message: string) => positionless("InvalidEvent", message)
|
|
1797
|
+
|
|
1798
|
+
const textSpecial = /[&<>\r]/
|
|
1799
|
+
const attributeSpecials = /[&<"\t\n\r]/
|
|
1800
|
+
|
|
1801
|
+
// The regex finds the first special character, which is fast when there is
|
|
1802
|
+
// none; the rest is copied in runs between escapes. Invalid characters are
|
|
1803
|
+
// kept, so that the writer can check them in the output.
|
|
1804
|
+
const escapeText = (s: string): string => {
|
|
1805
|
+
const first = s.search(textSpecial)
|
|
1806
|
+
if (first === -1) return s
|
|
1807
|
+
let out = ""
|
|
1808
|
+
let last = 0
|
|
1809
|
+
for (let i = first; i < s.length; i++) {
|
|
1810
|
+
const c = s.charCodeAt(i)
|
|
1811
|
+
const escaped = c === AMPERSAND ? "&" : c === LT ? "<" : c === GT ? ">" : c === CR ? " " : undefined
|
|
1812
|
+
if (escaped !== undefined) {
|
|
1813
|
+
out += s.slice(last, i) + escaped
|
|
1814
|
+
last = i + 1
|
|
1815
|
+
}
|
|
1816
|
+
}
|
|
1817
|
+
return out + s.slice(last)
|
|
1818
|
+
}
|
|
1819
|
+
|
|
1820
|
+
const escapeAttribute = (s: string): string => {
|
|
1821
|
+
const first = s.search(attributeSpecials)
|
|
1822
|
+
if (first === -1) return s
|
|
1823
|
+
let out = ""
|
|
1824
|
+
let last = 0
|
|
1825
|
+
for (let i = first; i < s.length; i++) {
|
|
1826
|
+
const c = s.charCodeAt(i)
|
|
1827
|
+
const escaped = c === AMPERSAND ?
|
|
1828
|
+
"&" :
|
|
1829
|
+
c === LT ?
|
|
1830
|
+
"<" :
|
|
1831
|
+
c === DQUOTE ?
|
|
1832
|
+
""" :
|
|
1833
|
+
c === TAB ?
|
|
1834
|
+
"	" :
|
|
1835
|
+
c === LF ?
|
|
1836
|
+
" " :
|
|
1837
|
+
c === CR ?
|
|
1838
|
+
" " :
|
|
1839
|
+
undefined
|
|
1840
|
+
if (escaped !== undefined) {
|
|
1841
|
+
out += s.slice(last, i) + escaped
|
|
1842
|
+
last = i + 1
|
|
1843
|
+
}
|
|
1844
|
+
}
|
|
1845
|
+
return out + s.slice(last)
|
|
1846
|
+
}
|
|
1847
|
+
|
|
1848
|
+
const checkChars = (what: string, s: string): void => {
|
|
1849
|
+
const invalid = searchInvalid(s)
|
|
1850
|
+
if (invalid !== -1) {
|
|
1851
|
+
const code = s.codePointAt(invalid)!.toString(16).toUpperCase().padStart(4, "0")
|
|
1852
|
+
throw invalidEvent(`${what} contains the invalid character U+${code}`)
|
|
1853
|
+
}
|
|
1854
|
+
}
|
|
1855
|
+
|
|
1856
|
+
const checkName = (what: string, name: string): void => {
|
|
1857
|
+
if (typeof name !== "string" || !isName(name)) throw invalidEvent(`invalid ${what} ${JSON.stringify(name)}`)
|
|
1858
|
+
}
|
|
1859
|
+
|
|
1860
|
+
const isWhitespace = (s: string): boolean => {
|
|
1861
|
+
for (let i = 0; i < s.length; i++) {
|
|
1862
|
+
if (!isSpace(s.charCodeAt(i))) return false
|
|
1863
|
+
}
|
|
1864
|
+
return true
|
|
1865
|
+
}
|
|
1866
|
+
|
|
1867
|
+
const NOTHING_WRITTEN = 3
|
|
1868
|
+
|
|
1869
|
+
class Writer implements Machine<Event, string> {
|
|
1870
|
+
out: Array<string> = []
|
|
1871
|
+
private readonly stack: Array<string> = []
|
|
1872
|
+
private state = NOTHING_WRITTEN
|
|
1873
|
+
private doctype = false
|
|
1874
|
+
private readonly bytes: boolean
|
|
1875
|
+
// Element and attribute names already checked, which repeat in most
|
|
1876
|
+
// documents. Cleared when full, so that it stays small.
|
|
1877
|
+
private readonly names = new Set<string>()
|
|
1878
|
+
|
|
1879
|
+
constructor(bytes: boolean) {
|
|
1880
|
+
this.bytes = bytes
|
|
1881
|
+
}
|
|
1882
|
+
|
|
1883
|
+
private checkName(what: string, name: string): void {
|
|
1884
|
+
if (!this.isName(name)) checkName(what, name)
|
|
1885
|
+
}
|
|
1886
|
+
|
|
1887
|
+
private isName(name: string): boolean {
|
|
1888
|
+
if (this.names.has(name)) return true
|
|
1889
|
+
if (typeof name !== "string" || !isName(name)) return false
|
|
1890
|
+
if (this.names.size >= 1024) this.names.clear()
|
|
1891
|
+
this.names.add(name)
|
|
1892
|
+
return true
|
|
1893
|
+
}
|
|
1894
|
+
|
|
1895
|
+
// Checks attributes one by one, in order, after a batched check has failed
|
|
1896
|
+
private checkAttributes(attributes: Readonly<Record<string, string>>): void {
|
|
1897
|
+
for (const name in attributes) {
|
|
1898
|
+
if (!Object.hasOwn(attributes, name)) continue
|
|
1899
|
+
const value = attributes[name]
|
|
1900
|
+
this.checkName("attribute name", name)
|
|
1901
|
+
if (typeof value !== "string") throw invalidEvent(`attribute ${name} must be a string`)
|
|
1902
|
+
checkChars(`attribute ${name}`, value)
|
|
1903
|
+
}
|
|
1904
|
+
}
|
|
1905
|
+
|
|
1906
|
+
push(event: Event): void {
|
|
1907
|
+
const text = this.write(event)
|
|
1908
|
+
if (text.length > 0) {
|
|
1909
|
+
const out = this.out
|
|
1910
|
+
if (out.length > 0) out[0] += text
|
|
1911
|
+
else out.push(text)
|
|
1912
|
+
}
|
|
1913
|
+
}
|
|
1914
|
+
|
|
1915
|
+
end(): void {
|
|
1916
|
+
if (this.stack.length > 0) throw invalidEvent(`unclosed element <${this.stack[this.stack.length - 1]}>`)
|
|
1917
|
+
if (this.state !== EPILOG) throw invalidEvent("no root element")
|
|
1918
|
+
}
|
|
1919
|
+
|
|
1920
|
+
private write(event: Event): string {
|
|
1921
|
+
if (event._tag === "EndElement") {
|
|
1922
|
+
const open = this.stack.length > 0 ? this.stack[this.stack.length - 1] : undefined
|
|
1923
|
+
if (open === undefined || event.name !== open) {
|
|
1924
|
+
// Only valid names are written into messages
|
|
1925
|
+
checkName("element name", event.name)
|
|
1926
|
+
throw invalidEvent(
|
|
1927
|
+
open === undefined
|
|
1928
|
+
? `end tag </${event.name}> without a start tag`
|
|
1929
|
+
: `end tag </${event.name}> does not match <${open}>`
|
|
1930
|
+
)
|
|
1931
|
+
}
|
|
1932
|
+
this.stack.pop()
|
|
1933
|
+
if (this.stack.length === 0) this.state = EPILOG
|
|
1934
|
+
return `</${open}>`
|
|
1935
|
+
}
|
|
1936
|
+
switch (event._tag) {
|
|
1937
|
+
case "StartElement": {
|
|
1938
|
+
this.checkName("element name", event.name)
|
|
1939
|
+
if (this.state === EPILOG) throw invalidEvent(`second root element <${event.name}>`)
|
|
1940
|
+
let tag = "<" + event.name
|
|
1941
|
+
let valid = true
|
|
1942
|
+
for (const name in event.attributes) {
|
|
1943
|
+
if (!Object.hasOwn(event.attributes, name)) continue
|
|
1944
|
+
const value = event.attributes[name]
|
|
1945
|
+
if (typeof value !== "string" || !this.isName(name)) {
|
|
1946
|
+
valid = false
|
|
1947
|
+
break
|
|
1948
|
+
}
|
|
1949
|
+
tag += ` ${name}="${escapeAttribute(value)}"`
|
|
1950
|
+
}
|
|
1951
|
+
// Escaping keeps invalid characters, so one search of the tag checks
|
|
1952
|
+
// every value; the first error is then found in attribute order
|
|
1953
|
+
if (!valid || (tag.length > event.name.length + 1 && searchInvalid(tag) !== -1)) {
|
|
1954
|
+
this.checkAttributes(event.attributes)
|
|
1955
|
+
}
|
|
1956
|
+
this.stack.push(event.name)
|
|
1957
|
+
this.state = CONTENT
|
|
1958
|
+
return tag + ">"
|
|
1959
|
+
}
|
|
1960
|
+
case "Text": {
|
|
1961
|
+
if (this.state !== CONTENT) {
|
|
1962
|
+
checkChars("text", event.text)
|
|
1963
|
+
if (!isWhitespace(event.text)) throw invalidEvent("text outside the root element must be whitespace")
|
|
1964
|
+
if (this.state === NOTHING_WRITTEN && event.text.length > 0) this.state = PROLOG
|
|
1965
|
+
return event.text
|
|
1966
|
+
}
|
|
1967
|
+
checkChars("text", event.text)
|
|
1968
|
+
return escapeText(event.text)
|
|
1969
|
+
}
|
|
1970
|
+
case "Comment": {
|
|
1971
|
+
checkChars("comment", event.text)
|
|
1972
|
+
if (event.text.includes("--") || event.text.endsWith("-")) {
|
|
1973
|
+
throw invalidEvent("comments cannot contain \"--\" or end with \"-\"")
|
|
1974
|
+
}
|
|
1975
|
+
if (this.state === NOTHING_WRITTEN) this.state = PROLOG
|
|
1976
|
+
return `<!--${event.text}-->`
|
|
1977
|
+
}
|
|
1978
|
+
case "ProcessingInstruction": {
|
|
1979
|
+
checkName("processing instruction target", event.target)
|
|
1980
|
+
if (isReservedTarget(event.target)) {
|
|
1981
|
+
throw invalidEvent(`processing instruction target ${event.target} is reserved`)
|
|
1982
|
+
}
|
|
1983
|
+
checkChars("processing instruction", event.data)
|
|
1984
|
+
if (event.data.includes("?>")) throw invalidEvent("processing instruction data cannot contain \"?>\"")
|
|
1985
|
+
if (this.state === NOTHING_WRITTEN) this.state = PROLOG
|
|
1986
|
+
return `<?${event.target}${event.data === "" ? "" : " " + event.data}?>`
|
|
1987
|
+
}
|
|
1988
|
+
case "Declaration": {
|
|
1989
|
+
if (this.state !== NOTHING_WRITTEN) throw invalidEvent("the XML declaration must be the first event")
|
|
1990
|
+
if (!versionPattern.test(event.version)) {
|
|
1991
|
+
throw invalidEvent(`invalid XML version ${JSON.stringify(event.version)}`)
|
|
1992
|
+
}
|
|
1993
|
+
let declaration = `<?xml version="${event.version}"`
|
|
1994
|
+
if (event.encoding !== undefined) {
|
|
1995
|
+
if (!encodingPattern.test(event.encoding)) {
|
|
1996
|
+
throw invalidEvent(`invalid encoding name ${JSON.stringify(event.encoding)}`)
|
|
1997
|
+
}
|
|
1998
|
+
if (this.bytes && event.encoding.toLowerCase() !== "utf-8") {
|
|
1999
|
+
throw invalidEvent(`encoding ${event.encoding} cannot be declared for UTF-8 output`)
|
|
2000
|
+
}
|
|
2001
|
+
declaration += ` encoding="${event.encoding}"`
|
|
2002
|
+
}
|
|
2003
|
+
if (event.standalone !== undefined) declaration += ` standalone="${event.standalone ? "yes" : "no"}"`
|
|
2004
|
+
this.state = PROLOG
|
|
2005
|
+
return declaration + "?>"
|
|
2006
|
+
}
|
|
2007
|
+
case "Doctype": {
|
|
2008
|
+
if (this.state === CONTENT || this.state === EPILOG || this.doctype) {
|
|
2009
|
+
throw invalidEvent("a DOCTYPE must appear once, before the root element")
|
|
2010
|
+
}
|
|
2011
|
+
checkName("DOCTYPE name", event.name)
|
|
2012
|
+
let doctype = `<!DOCTYPE ${event.name}`
|
|
2013
|
+
if (event.publicId !== undefined) {
|
|
2014
|
+
if (event.systemId === undefined) {
|
|
2015
|
+
throw invalidEvent("a DOCTYPE with a public identifier needs a system identifier")
|
|
2016
|
+
}
|
|
2017
|
+
if (!pubidPattern.test(event.publicId)) {
|
|
2018
|
+
throw invalidEvent(`invalid public identifier ${JSON.stringify(event.publicId)}`)
|
|
2019
|
+
}
|
|
2020
|
+
doctype += ` PUBLIC "${event.publicId}"`
|
|
2021
|
+
}
|
|
2022
|
+
if (event.systemId !== undefined) {
|
|
2023
|
+
checkChars("system identifier", event.systemId)
|
|
2024
|
+
const hasDouble = event.systemId.includes("\"")
|
|
2025
|
+
if (hasDouble && event.systemId.includes("'")) {
|
|
2026
|
+
throw invalidEvent("a system identifier cannot contain both quote characters")
|
|
2027
|
+
}
|
|
2028
|
+
if (event.publicId === undefined) doctype += " SYSTEM"
|
|
2029
|
+
doctype += hasDouble ? ` '${event.systemId}'` : ` "${event.systemId}"`
|
|
2030
|
+
}
|
|
2031
|
+
this.doctype = true
|
|
2032
|
+
this.state = PROLOG
|
|
2033
|
+
return doctype + ">"
|
|
2034
|
+
}
|
|
2035
|
+
}
|
|
2036
|
+
}
|
|
2037
|
+
}
|