/** * A parser that assembles the tokens emitted by the tokenizer into JSON values. * * @example * ```ts * import Tokenizer from "@streamparser/json/tokenizer.js"; * import TokenParser from "@streamparser/json/tokenparser.js"; * * const tokenizer = new Tokenizer(); * const tokenParser = new TokenParser({ paths: ["$.*"] }); * tokenizer.onToken = tokenParser.write.bind(tokenParser); * tokenParser.onValue = ({ value }) => { * // process the value * }; * * tokenizer.write('{ "test": ["a"] }'); * ``` * * @module */ import type { ParsedElementInfo } from "./utils/types/parsedElementInfo.js"; import type { ParsedTokenInfo } from "./utils/types/parsedTokenInfo.js"; /** The options that a {@linkcode TokenParser} can be created with. */ export interface TokenParserOptions { /** * The paths of the values to emit, as a subset of jsonpath: the root selector * (`$`), subproperty selectors (`$.a`, `$.a.b`) and wildcards (`$.*`, * `$.*.b`) are supported. Defaults to `undefined`, which emits every value. */ paths?: string[]; /** * Whether to keep the members of a container that have already been emitted. * Defaults to `true`. Setting it to `false` deletes each value from its parent * as it is emitted, which means the `parent` and `stack` reported to * {@linkcode TokenParser.onValue} no longer show the already-emitted siblings, * but keeps memory flat when streaming a large array or object. */ keepStack?: boolean; /** * The separator between consecutive JSON documents in the stream, for example * `"\n"` for newline-delimited JSON. Defaults to `undefined`, which ends the * parser after the first document. Set it to `""` to accept documents that * follow each other with no delimiter at all. Whitespace between documents is * always ignored. */ separator?: string; /** * Whether to emit values that are still being parsed, as the partial tokens * that make them up arrive. Defaults to `false`. Requires the tokenizer's * `emitPartialTokens` to be enabled too, and partial values are flagged with * `partial: true`. */ emitPartialValues?: boolean; } /** The error thrown when the token parser is misconfigured or gets an unexpected token. */ export declare class TokenParserError extends Error { /** * @param message What went wrong. */ constructor(message: string); } /** * A parser that assembles the tokens emitted by a tokenizer into JSON values. * * Tokens are pushed in with {@linkcode TokenParser.write} and the resulting * values come back through the {@linkcode TokenParser.onValue} callback, which * the user is expected to override. Values are emitted innermost first, as soon * as each one is complete, and can be narrowed down to the ones of interest with * the `paths` option. * * @example * ```ts * import Tokenizer from "@streamparser/json/tokenizer.js"; * import TokenParser from "@streamparser/json/tokenparser.js"; * * const tokenizer = new Tokenizer(); * const tokenParser = new TokenParser(); * tokenizer.onToken = tokenParser.write.bind(tokenParser); * tokenParser.onValue = ({ value, key, parent, stack }) => { * // process the value * }; * * tokenizer.write('{ "test": ["a"] }'); * // onValue is called 3 times: "a", ["a"] and { test: ["a"] } * ``` */ export default class TokenParser { private readonly selectorTrie?; private readonly keepStack; private readonly separator?; private state; private mode; private key; private value; private stack; private memberCount; /** * @param opts What to emit and how. See {@linkcode TokenParserOptions}. * @throws {TokenParserError} If any of the configured `paths` is not a valid selector. */ constructor(opts?: TokenParserOptions); private shouldEmit; private matchesSelector; private push; private pop; private emit; private emitPartial; /** Whether the token parser is ended, and thus no longer accepting tokens. */ get isEnded(): boolean; /** * Pushes the next token into the parser. * * Parsing happens synchronously, so every value that the token completes is * emitted through {@linkcode TokenParser.onValue} before this returns. * * @param parsedTokenInfo The token to process, as emitted by a tokenizer. * @throws {TokenParserError} If the token can't appear at this point of the * JSON document and no {@linkcode TokenParser.onError} callback has been set. */ write({ token, value, partial, }: Omit): void; /** * Puts the token parser in an error state and reports `err` through * {@linkcode TokenParser.onError}. The parser can't be used afterwards. * * @param err What went wrong. */ error(err: Error): void; /** * Signals that there are no more tokens, ending the token parser, which can't * be used afterwards. * * @throws {Error} If the JSON document was left half-parsed and no * {@linkcode TokenParser.onError} callback has been set. */ end(): void; /** * Called with every value that matches the configured `paths`. Override it to * consume them; by default it throws. * * @param parsedElementInfo The value and where it was found. Its `parent` and * `stack` are live references into the parser's in-progress structures, so use * `cloneParsedElementInfo` to snapshot them if they need to outlive the call. */ onValue(parsedElementInfo: ParsedElementInfo): void; /** * Called when the tokens don't add up to valid JSON. Override it to handle * errors asynchronously; by default it throws, so the error surfaces out of the * {@linkcode TokenParser.write} or {@linkcode TokenParser.end} call that caused it. * * @param err What went wrong. */ onError(err: Error): void; /** Called once the token parser has ended. Override it to react to that; by default it does nothing. */ onEnd(): void; } //# sourceMappingURL=tokenparser.d.ts.map