/**
* Decodes and encodes XML 1.0 documents as streams of events in Effect
* channels.
*
* `decode` and `decodeString` turn UTF-8 bytes or text into events, and
* `encode` and `encodeString` write events back as XML. `elements` collects
* repeated elements, such as the items of a feed, into small trees, so that a
* large document can be processed one record at a time.
*
* The decoder checks that documents are well-formed. It never reads external
* resources and never expands entities declared in a DOCTYPE, so external
* entity (XXE) and entity expansion attacks do not apply. It does not validate
* documents against a DTD or schema, and reports names as written, without
* resolving namespaces.
*
* @stability experimental
* @since 4.0.6
*/
import * as Arr from "../Array.ts";
import * as Cause from "../Cause.ts";
import * as Channel from "../Channel.ts";
declare const XmlErrorTypeId = "~effect/encoding/Xml/XmlError";
declare const XmlError_base: new = {}>(args: import("../Types.ts").VoidIfEmpty<{ readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }>) => Cause.YieldableError & {
readonly _tag: "XmlError";
} & Readonly;
/**
* Error raised when XML cannot be decoded or encoded.
*
* **Details**
*
* The `kind` field identifies the failure:
*
* - `Syntax`: the input is not well-formed XML or not valid UTF-8.
* - `Unsupported`: the input uses a feature this module does not process, such
* as an entity declared in a DOCTYPE or a byte encoding other than UTF-8.
* - `Limit`: the input exceeds `maxTokenSize`, `maxDepth` or `maxElementSize`.
* - `InvalidEvent`: the events do not form a well-formed document, such as an
* end tag that does not match its start tag.
*
* Errors from `decode` and `decodeString` carry the one-based `line` and
* `column` where the problem was found, also appended to `message`. Columns
* count UTF-16 code units, and lines end at LF, CR or CRLF.
*
* @stability experimental
* @category errors
* @since 4.0.6
*/
export declare class XmlError extends XmlError_base<{
readonly kind: "Syntax" | "Unsupported" | "Limit" | "InvalidEvent";
readonly message: string;
readonly line?: number | undefined;
readonly column?: number | undefined;
}> {
/**
* Marks this value as an XML error for runtime guards.
*
* @stability experimental
* @since 4.0.6
*/
readonly [XmlErrorTypeId] = "~effect/encoding/Xml/XmlError";
}
/**
* Checks whether a value is an `XmlError`.
*
* @stability experimental
* @category guards
* @since 4.0.6
*/
export declare const isXmlError: (u: unknown) => u is XmlError;
/**
* Event for the XML declaration at the start of a document, such as
* ``.
*
* **Details**
*
* `encoding` and `standalone` are present only when the declaration sets them.
*
* @stability experimental
* @category models
* @since 4.0.6
*/
export interface Declaration {
readonly _tag: "Declaration";
readonly version: string;
readonly encoding?: string | undefined;
readonly standalone?: boolean | undefined;
}
/**
* Event for a document type declaration, such as ``.
*
* **Details**
*
* `publicId` and `systemId` are present only when the declaration names an
* external DTD; the DTD is never read. Whitespace in `publicId` is collapsed
* to single spaces and trimmed. The internal subset is not reported.
*
* @stability experimental
* @category models
* @since 4.0.6
*/
export interface Doctype {
readonly _tag: "Doctype";
readonly name: string;
readonly publicId?: string | undefined;
readonly systemId?: string | undefined;
}
/**
* Event for a start tag, with its attributes in document order.
*
* **Details**
*
* `name` is the qualified name as written and is the only element-name field
* the encoder reads.
*
* Attribute values have their references replaced and whitespace normalized as
* XML requires. Decoded attributes inherit nothing, so only the attributes of
* the tag are present and `__proto__` is an ordinary key. Their key order is
* document order, as XML names are never integer-like. A `structuredClone` of
* a decoded map gets `Object.prototype` back. A self-closing tag such as
* `
` is decoded as a `StartElement` followed by an `EndElement`.
*
* @stability experimental
* @category models
* @since 4.0.6
*/
export interface StartElement {
readonly _tag: "StartElement";
readonly name: string;
readonly attributes: Readonly>;
}
/**
* Event for an end tag.
*
* @stability experimental
* @category models
* @since 4.0.6
*/
export interface EndElement {
readonly _tag: "EndElement";
readonly name: string;
}
/**
* Event for character data inside the root element.
*
* **Details**
*
* Adjacent text, references and CDATA sections are decoded into one `Text`
* event that ends at the next tag, comment or processing instruction, however
* the input is chunked. Line endings are normalized to `\n`.
*
* @stability experimental
* @category models
* @since 4.0.6
*/
export interface Text {
readonly _tag: "Text";
readonly text: string;
}
/**
* Event for a comment, holding the text between ``.
*
* @stability experimental
* @category models
* @since 4.0.6
*/
export interface Comment {
readonly _tag: "Comment";
readonly text: string;
}
/**
* Event for a processing instruction, such as
* ``.
*
* **Details**
*
* `data` is the text after the target, without leading whitespace.
*
* @stability experimental
* @category models
* @since 4.0.6
*/
export interface ProcessingInstruction {
readonly _tag: "ProcessingInstruction";
readonly target: string;
readonly data: string;
}
/**
* Event produced by the decoders and consumed by the encoders.
*
* @stability experimental
* @category models
* @since 4.0.6
*/
export type Event = Declaration | Doctype | StartElement | EndElement | Text | Comment | ProcessingInstruction;
/**
* Element collected by `elements`, with its attributes and children.
*
* **Details**
*
* Children are elements and strings of character data, in document order.
* Adjacent text is merged into one string; comments and processing
* instructions are dropped.
*
* @stability experimental
* @category models
* @since 4.0.6
*/
export interface Element {
readonly name: string;
readonly attributes: Readonly>;
readonly children: ReadonlyArray;
}
/**
* Options for the XML decoders.
*
* **Details**
*
* - `maxTokenSize`: the maximum length of a single token in UTF-16 code units,
* as written in the input: a tag with its attributes, a comment, a processing
* instruction, a DOCTYPE, or a text node including its references and CDATA
* sections. Defaults to 10 MiB; `Infinity` disables the limit.
* - `maxDepth`: the maximum number of nested elements. Defaults to 1024;
* `Infinity` disables the limit.
*
* Memory per token and for open element names is bounded by `maxTokenSize`.
* Invalid options throw when the channel is created.
*
* @stability experimental
* @category configuration
* @since 4.0.6
*/
export interface DecodeOptions {
readonly maxTokenSize?: number | undefined;
readonly maxDepth?: number | undefined;
}
/**
* Options for `elements`.
*
* **Details**
*
* `maxElementSize` is the maximum size of one collected element, counted as
* the UTF-16 code units of its names, attribute names and values, and text.
* Defaults to 16 MiB; `Infinity` disables the limit. Invalid options throw when
* the channel is created.
*
* @stability experimental
* @category configuration
* @since 4.0.6
*/
export interface ElementsOptions {
readonly maxElementSize?: number | undefined;
}
/**
* Creates a channel that decodes XML text chunks into events.
*
* **Details**
*
* - Tokens can be split anywhere between chunks. Each output chunk holds the
* events completed by one input chunk.
* - The document must have one root element. Whitespace outside it is not
* reported.
* - A leading byte order mark is skipped, and the encoding named by the XML
* declaration is ignored.
* - Events completed before an error are emitted before the channel fails.
*
* **Gotchas**
*
* - End of input inside the root fails with a `Syntax` error ("unclosed
* element"); interruption ends the stream without this check.
* - A DOCTYPE is reported as a `Doctype` event, and its internal subset is
* skipped without checking its declarations. They are not applied, so
* default attribute values are not added, and parameter entities are not
* expanded.
* - References to entities other than `<`, `>`, `&`, `'` and
* `"` fail with an `Unsupported` `XmlError` when the document has a
* DOCTYPE, and with a `Syntax` `XmlError` otherwise. Character references
* such as `é` are always decoded.
* - Names are reported as written, including namespace prefixes, and `xmlns`
* declarations are ordinary attributes.
* - Tokens or aggregate open element names longer than `maxTokenSize`, and
* elements nested deeper than `maxDepth`, fail with a `Limit` `XmlError`. A
* long token can instead fail with an error found in its first
* `maxTokenSize + 1` characters.
* - Strings in events can share memory with their input chunk, so keeping a
* short string, such as an id from each record, can keep the whole chunk in
* memory. Copy strings that are kept long, for example with
* `structuredClone`.
*
* **Example** (Decoding events)
*
* ```ts import.meta.vitest
* import { Effect, Stream } from "effect"
* import { Xml } from "effect/encoding"
*
* const events = Stream.make("Hi & bye
").pipe(
* Stream.pipeThroughChannel(Xml.decodeString()),
* Stream.map((event) => event._tag),
* Stream.runCollect
* )
* await Effect.runPromise(events) // => ["StartElement", "Text", "StartElement", "EndElement", "EndElement"]
* ```
*
* @see {@link decode} for UTF-8 byte input
* @see {@link elements} for collecting repeated elements into trees
* @see {@link encodeString} for the inverse operation
*
* @stability experimental
* @category decoding
* @since 4.0.6
*/
export declare const decodeString: (options?: DecodeOptions) => Channel.Channel, XmlError | IE, Done, Arr.NonEmptyReadonlyArray, IE, Done>;
/**
* Creates a channel that decodes UTF-8 XML bytes into events.
*
* **Details**
*
* Works like `decodeString` after decoding the bytes as UTF-8. Multi-byte
* characters can be split between chunks, and a leading byte order mark is
* skipped.
*
* **Gotchas**
*
* - Invalid or truncated UTF-8 fails with a `Syntax` `XmlError`.
* - An initial UTF-16 byte order mark or an XML declaration naming an encoding
* other than UTF-8 or US-ASCII fails with an `Unsupported` `XmlError`.
* Decode such bytes with a `TextDecoder` for that encoding and use `decodeString`.
*
* @see {@link decodeString} for text input and the shared gotchas
*
* @stability experimental
* @category decoding
* @since 4.0.6
*/
export declare const decode: (options?: DecodeOptions) => Channel.Channel, XmlError | IE, Done, Arr.NonEmptyReadonlyArray, IE, Done>;
/**
* Creates a channel that collects the elements at a path into trees.
*
* **When to use**
*
* Use to process large documents such as feeds, sitemaps or exports one record
* at a time, without holding the whole document in memory.
*
* **Details**
*
* `path` lists element names from the root, and `"*"` matches any name. Each
* element whose ancestors and own name match the path is emitted once its end
* tag arrives, with all of its descendants; everything outside the matched
* elements is skipped. Because paths start at the root, an element nested in a
* matched element is part of its tree and is not emitted separately.
*
* **Gotchas**
*
* - A path that does not start at the root element matches nothing.
* - Whitespace between child elements, such as indentation, is kept as string
* children.
* - A collected element larger than `maxElementSize` fails with a `Limit`
* `XmlError`. The size counts characters, not memory: an element with many
* small children can take many times its size in memory, so use a lower
* limit for untrusted input.
* - Events that end inside an element, or end an element that was never
* started, fail with an `InvalidEvent` `XmlError`.
* - A path that is empty or contains an invalid name throws when the channel is
* created.
*
* **Example** (Reading feed items)
*
* ```ts import.meta.vitest
* import { Effect, Stream } from "effect"
* import { Xml } from "effect/encoding"
*
* const feed = `News
* - First
* - Second
* `
*
* const items = await Effect.runPromise(
* Stream.make(feed).pipe(
* Stream.pipeThroughChannel(Xml.decodeString()),
* Stream.pipeThroughChannel(Xml.elements(["rss", "channel", "item"])),
* Stream.runCollect
* )
* )
* items.length // => 2
* items[1] // => { name: "item", attributes: {}, children: [{ name: "title", attributes: {}, children: ["Second"] }] }
* ```
*
* @see {@link decode} for producing events from bytes
*
* @stability experimental
* @category decoding
* @since 4.0.6
*/
export declare const elements: (path: ReadonlyArray, options?: ElementsOptions) => Channel.Channel, XmlError | IE, Done, Arr.NonEmptyReadonlyArray, IE, Done>;
/**
* Creates a channel that writes events as XML text.
*
* **Details**
*
* - Each input chunk is written as one string.
* - Text escapes `&`, `<` and `>`. Attribute values are double-quoted and
* escape `&`, `<`, `"`, tabs and line breaks. Carriage returns are written
* as `
` so that they survive decoding.
* - Start tags are written completely on their event. Empty elements use
* explicit closing tags, such as `
`, never self-closing tags.
* - Nothing is added between events, so whitespace comes only from `Text`
* events.
*
* **Gotchas**
*
* Events that do not form one well-formed document fail with an
* `InvalidEvent` `XmlError`, such as an end tag that does not match the open
* element, a second root element, non-whitespace text outside the root
* element, invalid names or characters, `--` in a comment, `?>` in processing
* instruction data, or a declaration that is not the first event. The stream
* must end with the root element closed.
*
* **Example** (Writing a document)
*
* ```ts import.meta.vitest
* import { Effect, Stream } from "effect"
* import { Xml } from "effect/encoding"
*
* const events: ReadonlyArray = [
* { _tag: "StartElement", name: "a", attributes: { href: "x?a=1&b=2" } },
* { _tag: "Text", text: "1 < 2" },
* { _tag: "EndElement", name: "a" }
* ]
*
* const xml = Stream.fromIterable(events).pipe(
* Stream.pipeThroughChannel(Xml.encodeString()),
* Stream.mkString
* )
* await Effect.runPromise(xml) // => '1 < 2'
* ```
*
* @see {@link encode} for UTF-8 byte output
* @see {@link decodeString} for the inverse operation
*
* @stability experimental
* @category encoding
* @since 4.0.6
*/
export declare const encodeString: () => Channel.Channel, XmlError | IE, Done, Arr.NonEmptyReadonlyArray, IE, Done>;
/**
* Creates a channel that writes events as UTF-8 XML bytes.
*
* **Details**
*
* Works like `encodeString`, with one byte array per input chunk.
*
* **Gotchas**
*
* A `Declaration` event naming an encoding other than UTF-8 fails
* with an `InvalidEvent` `XmlError`.
*
* @see {@link encodeString} for text output and the shared gotchas
*
* @stability experimental
* @category encoding
* @since 4.0.6
*/
export declare const encode: () => Channel.Channel, XmlError | IE, Done, Arr.NonEmptyReadonlyArray, IE, Done>;
export {};
//# sourceMappingURL=Xml.d.ts.map