commit 06226be0a8a79e31181ad5ad592865d675b9eb1e Author: upstream Date: Thu Oct 15 00:35:14 2026 +0200 Upstream NaturalIntelligence/fast-xml-parser state of the touched files before 606d90c9d9 diff --git a/lib/fxp.d.cts b/lib/fxp.d.cts new file mode 100644 index 0000000..eabd37d --- /dev/null +++ b/lib/fxp.d.cts @@ -0,0 +1,772 @@ +/** + * Types copied from path-expression-matcher + * @version + * @updated + * + * Update this file when path-expression-matcher releases a new version. + * Source: https://github.com/NaturalIntelligence/path-expression-matcher + */ + +/** + * Options for creating an Expression + */ +interface ExpressionOptions { + /** + * Path separator character + * @default '.' + */ + separator?: string; +} + +/** + * Parsed segment from an expression pattern + */ +interface Segment { + type: 'tag' | 'deep-wildcard'; + tag?: string; + namespace?: string; + attrName?: string; + attrValue?: string; + position?: 'first' | 'last' | 'odd' | 'even' | 'nth'; + positionValue?: number; +} + +/** + * Expression - Parses and stores a tag pattern expression. + * Patterns are parsed once and stored in an optimized structure for fast matching. + * + * @example + * ```typescript + * const expr = new Expression("root.users.user"); + * const expr2 = new Expression("..user[id]:first"); + * const expr3 = new Expression("root/users/user", { separator: '/' }); + * ``` + * + * Pattern Syntax: + * - `root.users.user` — Match exact path + * - `..user` — Match "user" at any depth (deep wildcard) + * - `user[id]` — Match user tag with "id" attribute + * - `user[id=123]` — Match user tag where id="123" + * - `user:first` — Match first occurrence of user tag + * - `ns::user` — Match user tag with namespace "ns" + * - `ns::user[id]:first` — Combine namespace, attribute, and position + */ +declare class Expression { + readonly pattern: string; + readonly separator: string; + readonly segments: Segment[]; + + constructor(pattern: string, options?: ExpressionOptions); + + get length(): number; + hasDeepWildcard(): boolean; + hasAttributeCondition(): boolean; + hasPositionSelector(): boolean; + toString(): string; +} + +// --------------------------------------------------------------------------- +// MatcherView +// --------------------------------------------------------------------------- + +/** + * A lightweight, live read-only view of a Matcher instance. + * + * Returned by `Matcher.readOnly()`. The same instance is reused across every + * callback invocation — no allocation overhead per call. Reads directly from + * the parent Matcher's internal state so it always reflects the current parser + * position with no copying or freezing. + * + * Mutation methods (`push`, `pop`, `reset`, `updateCurrent`, `restore`) are + * simply absent — misuse is caught at compile time by TypeScript. + * + * This is the type received by all FXP user callbacks when `jPath: false`. + */ +interface MatcherView { + readonly separator: string; + + /** Check if current path matches an Expression. */ + matches(expression: Expression): boolean; + + /** Get current tag name, or `undefined` if path is empty. */ + getCurrentTag(): string | undefined; + + /** Get current namespace, or `undefined` if not present. */ + getCurrentNamespace(): string | undefined; + + /** Get attribute value of the current node. */ + getAttrValue(attrName: string): any; + + /** Check if the current node has a given attribute. */ + hasAttr(attrName: string): boolean; + + /** Sibling position of the current node (child index in parent). */ + getPosition(): number; + + /** Occurrence counter of the current tag name at this level. */ + getCounter(): number; + + /** Number of nodes in the current path. */ + getDepth(): number; + + /** Current path as a string (e.g. `"root.users.user"`). */ + toString(separator?: string, includeNamespace?: boolean): string; + + /** Current path as an array of tag names. */ + toArray(): string[]; + + /** + * Create a snapshot of the current state. + * The snapshot can be passed to the real Matcher.restore() if needed. + */ + snapshot(): MatcherSnapshot; +} + +/** + * @deprecated Use {@link MatcherView} instead. + * Alias kept for backward compatibility. + */ +type ReadonlyMatcher = MatcherView; + +/** Internal node structure — exposed via snapshot only. */ +interface PathNode { + tag: string; + namespace?: string; + position: number; + counter: number; + values?: Record; +} + +/** Snapshot of matcher state returned by `snapshot()` and `readOnly().snapshot()`. */ +interface MatcherSnapshot { + path: PathNode[]; + siblingStacks: Map[]; +} + +/********************************************************************** + * + * END of path-expression-matcher relevant typings + * + **********************************************************************/ + + + +// jPath: true → string +// jPath: false → MatcherView +type JPathOrMatcher = string | MatcherView; +type JPathOrExpression = string | Expression; + +type ProcessEntitiesOptions = { + /** + * Whether to enable entity processing + * + * Defaults to `true` + */ + enabled?: boolean; + + /** + * Maximum size in characters for a single entity definition + * + * Defaults to `10000` + */ + maxEntitySize?: number; + + /** + * Maximum depth for nested entity references (reserved for future use) + * + * Defaults to `10` + */ + maxExpansionDepth?: number; + + /** + * Maximum total number of entity expansions allowed + * + * Defaults to `1000` + */ + maxTotalExpansions?: number; + + /** + * Maximum total expanded content length in characters + * + * Defaults to `100000` + */ + maxExpandedLength?: number; + + /** + * Maximum number of entities allowed in the XML + * + * Defaults to `100` + */ + maxEntityCount?: number; + + /** + * Array of tag names where entity replacement is allowed. + * If null, entities are replaced in all tags. + * + * Defaults to `null` + */ + allowedTags?: string[] | null; + + /** + * Custom filter function to determine if entities should be replaced in a tag + * + * @param tagName - The name of the current tag + * @param jPathOrMatcher - The jPath string (if jPath: true) or Matcher instance (if jPath: false) + * @returns `true` to allow entity replacement, `false` to skip + * + * Defaults to `null` + */ + tagFilter?: ((tagName: string, jPathOrMatcher: JPathOrMatcher) => boolean) | null; +}; + +type EntityDecoderOptions = { + setExternalEntities: (entities: Record) => void; + addInputEntities: (entities: Record) => void; + reset: () => void; + decode: (text: string) => string; + setXmlVersion: (version: number) => void; +} + +type X2jOptions = { + /** + * Preserve the order of tags in resulting JS object + * + * Defaults to `false` + */ + preserveOrder?: boolean; + + /** + * Give a prefix to the attribute name in the resulting JS object + * + * Defaults to '@_' + */ + attributeNamePrefix?: string; + + /** + * A name to group all attributes of a tag under, or `false` to disable + * + * Defaults to `false` + */ + attributesGroupName?: false | string; + + /** + * The name of the next node in the resulting JS + * + * Defaults to `#text` + */ + textNodeName?: string; + + /** + * Whether to ignore attributes when parsing + * + * When `true` - ignores all the attributes + * + * When `false` - parses all the attributes + * + * When `Array` - filters out attributes that match provided patterns + * + * When `Function` - calls the function for each attribute and filters out those for which the function returned `true` + * + * Defaults to `true` + */ + ignoreAttributes?: boolean | (string | RegExp)[] | ((attrName: string, jPathOrMatcher: JPathOrMatcher) => boolean); + + /** + * Whether to remove namespace string from tag and attribute names + * + * Defaults to `false` + */ + removeNSPrefix?: boolean; + + /** + * Whether to allow attributes without value + * + * Defaults to `false` + */ + allowBooleanAttributes?: boolean; + + /** + * Whether to parse tag value with `strnum` package + * + * Defaults to `true` + */ + parseTagValue?: boolean; + + /** + * Whether to parse attribute value with `strnum` package + * + * Defaults to `false` + */ + parseAttributeValue?: boolean; + + /** + * Whether to remove surrounding whitespace from tag or attribute value + * + * Defaults to `true` + */ + trimValues?: boolean; + + /** + * Give a property name to set CDATA values to instead of merging to tag's text value + * + * Defaults to `false` + */ + cdataPropName?: false | string; + + /** + * If set, parse comments and set as this property + * + * Defaults to `false` + */ + commentPropName?: false | string; + + /** + * Control how tag value should be parsed. Called only if tag value is not empty + * + * @param tagName - The name of the tag + * @param tagValue - The value of the tag + * @param jPathOrMatcher - The jPath string (if jPath: true) or Matcher instance (if jPath: false) + * @param hasAttributes - Whether the tag has attributes + * @param isLeafNode - Whether the tag is a leaf node + * @returns {undefined|null} `undefined` or `null` to set original value. + * @returns {unknown} + * + * 1. Different value or value with different data type to set new value. + * 2. Same value to set parsed value if `parseTagValue: true`. + * + * Defaults to `(tagName, val, jPathOrMatcher, hasAttributes, isLeafNode) => val` + */ + tagValueProcessor?: (tagName: string, tagValue: string, jPathOrMatcher: JPathOrMatcher, hasAttributes: boolean, isLeafNode: boolean) => unknown; + + /** + * Control how attribute value should be parsed + * + * @param attrName - The name of the attribute + * @param attrValue - The value of the attribute + * @param jPathOrMatcher - The jPath string (if jPath: true) or Matcher instance (if jPath: false) + * @returns {undefined|null} `undefined` or `null` to set original value + * @returns {unknown} + * + * Defaults to `(attrName, val, jPathOrMatcher) => val` + */ + attributeValueProcessor?: (attrName: string, attrValue: string, jPathOrMatcher: JPathOrMatcher) => unknown; + + /** + * Options to pass to `strnum` for parsing numbers + * + * Defaults to `{ hex: true, leadingZeros: true, eNotation: true }` + */ + numberParseOptions?: strnumOptions; + + /** + * Nodes to stop parsing at + * + * Accepts string patterns or Expression objects from path-expression-matcher + * + * String patterns starting with "*." are automatically converted to ".." for backward compatibility + * + * Defaults to `[]` + */ + stopNodes?: JPathOrExpression[]; + + /** + * List of tags without closing tags + * + * Defaults to `[]` + */ + unpairedTags?: string[]; + + /** + * Whether to always create a text node + * + * Defaults to `false` + */ + alwaysCreateTextNode?: boolean; + + /** + * Determine whether a tag should be parsed as an array + * + * @param tagName - The name of the tag + * @param jPathOrMatcher - The jPath string (if jPath: true) or Matcher instance (if jPath: false) + * @param isLeafNode - Whether the tag is a leaf node + * @param isAttribute - Whether this is an attribute + * @returns {boolean} + * + * Defaults to `() => false` + */ + isArray?: (tagName: string, jPathOrMatcher: JPathOrMatcher, isLeafNode: boolean, isAttribute: boolean) => boolean; + + /** + * Whether to process default and DOCTYPE entities + * + * When `true` - enables entity processing with default limits + * + * When `false` - disables all entity processing + * + * When `ProcessEntitiesOptions` - enables entity processing with custom configuration + * + * Defaults to `true` + */ + processEntities?: boolean | ProcessEntitiesOptions; + + /** + * Whether to process HTML entities + * + * Defaults to `false` + * @deprecated Use `entityDecoder` instead + */ + htmlEntities?: boolean; + + /** + * Custom entity decoder + */ + entityDecoder?: EntityDecoderOptions; + /** + * Whether to ignore the declaration tag from output + * + * Defaults to `false` + */ + ignoreDeclaration?: boolean; + + /** + * Whether to ignore Pi tags + * + * Defaults to `false` + */ + ignorePiTags?: boolean; + + /** + * Transform tag names + * + * Defaults to `false` + */ + transformTagName?: ((tagName: string) => string) | false; + + /** + * Transform attribute names + * + * Defaults to `false` + */ + transformAttributeName?: ((attributeName: string) => string) | false; + + /** + * Change the tag name when a different name is returned. Skip the tag from parsed result when false is returned. + * Modify `attrs` object to control attributes for the given tag. + * + * @param tagName - The name of the tag + * @param jPathOrMatcher - The jPath string (if jPath: true) or Matcher instance (if jPath: false) + * @param attrs - The attributes object + * @returns {string} new tag name. + * @returns false to skip the tag + * + * Defaults to `(tagName, jPathOrMatcher, attrs) => tagName` + */ + updateTag?: (tagName: string, jPathOrMatcher: JPathOrMatcher, attrs: { [k: string]: string }) => string | boolean; + + /** + * If true, adds a Symbol to all object nodes, accessible by {@link XMLParser.getMetaDataSymbol} with + * metadata about each the node in the XML file. + */ + captureMetaData?: boolean; + + /** + * Maximum number of nested tags + * + * Defaults to `100` + */ + maxNestedTags?: number; + + /** + * Whether to strictly validate tag names + * + * Defaults to `true` + */ + strictReservedNames?: boolean; + + /** + * Controls whether callbacks receive jPath as string or Matcher instance + * + * When `true` - callbacks receive jPath as string (backward compatible) + * + * When `false` - callbacks receive Matcher instance for advanced pattern matching + * + * Defaults to `true` + */ + jPath?: boolean; + + /** + * Function to sanitize dangerous property names + * + * @param name - The name of the property + * @returns {string} The sanitized name + * + * Defaults to `(name) => __name` + */ + onDangerousProperty?: (name: string) => string; +}; + +type strnumOptions = { + hex: boolean; + leadingZeros: boolean, + skipLike?: RegExp, + eNotation?: boolean, + infinity?: string, + unicode?: boolean +} + +type validationOptions = { + /** + * Whether to allow attributes without value + * + * Defaults to `false` + */ + allowBooleanAttributes?: boolean; + + /** + * List of tags without closing tags + * + * Defaults to `[]` + */ + unpairedTags?: string[]; +}; + +type XmlBuilderOptions = { + /** + * Give a prefix to the attribute name in the resulting JS object + * + * Defaults to '@_' + */ + attributeNamePrefix?: string; + + /** + * A name to group all attributes of a tag under, or `false` to disable + * + * Defaults to `false` + */ + attributesGroupName?: false | string; + + /** + * The name of the next node in the resulting JS + * + * Defaults to `#text` + */ + textNodeName?: string; + + /** + * Whether to ignore attributes when building + * + * When `true` - ignores all the attributes + * + * When `false` - builds all the attributes + * + * When `Array` - filters out attributes that match provided patterns + * + * When `Function` - calls the function for each attribute and filters out those for which the function returned `true` + * + * Defaults to `true` + */ + ignoreAttributes?: boolean | (string | RegExp)[] | ((attrName: string, jPath: string) => boolean); + + /** + * Give a property name to set CDATA values to instead of merging to tag's text value + * + * Defaults to `false` + */ + cdataPropName?: false | string; + + /** + * If set, parse comments and set as this property + * + * Defaults to `false` + */ + commentPropName?: false | string; + + /** + * Whether to make output pretty instead of single line + * + * Defaults to `false` + */ + format?: boolean; + + + /** + * If `format` is set to `true`, sets the indent string + * + * Defaults to ` ` + */ + indentBy?: string; + + /** + * Give a name to a top-level array + * + * Defaults to `undefined` + */ + arrayNodeName?: string; + + /** + * Create empty tags for tags with no text value + * + * Defaults to `false` + */ + suppressEmptyNode?: boolean; + + /** + * Suppress an unpaired tag + * + * Defaults to `true` + */ + suppressUnpairedNode?: boolean; + + /** + * Don't put a value for boolean attributes + * + * Defaults to `true` + */ + suppressBooleanAttributes?: boolean; + + /** + * Preserve the order of tags in resulting JS object + * + * Defaults to `false` + */ + preserveOrder?: boolean; + + /** + * List of tags without closing tags + * + * Defaults to `[]` + */ + unpairedTags?: string[]; + + /** + * Nodes to stop parsing at + * + * Accepts string patterns or Expression objects from path-expression-matcher + * + * Defaults to `[]` + */ + stopNodes?: JPathOrExpression[]; + + /** + * Control how tag value should be parsed. Called only if tag value is not empty + * + * @returns {undefined|null} `undefined` or `null` to set original value. + * @returns {unknown} + * + * 1. Different value or value with different data type to set new value. + * 2. Same value to set parsed value if `parseTagValue: true`. + * + * Defaults to `(tagName, val, jPath, hasAttributes, isLeafNode) => val` + */ + tagValueProcessor?: (name: string, value: unknown) => unknown; + + /** + * Control how attribute value should be parsed + * + * @param attrName + * @param attrValue + * @param jPath + * @returns {undefined|null} `undefined` or `null` to set original value + * @returns {unknown} + * + * Defaults to `(attrName, val, jPath) => val` + */ + attributeValueProcessor?: (name: string, value: unknown) => unknown; + + /** + * Whether to process default and DOCTYPE entities + * + * Defaults to `true` + */ + processEntities?: boolean; + + + oneListGroup?: boolean; + + /** + * Maximum number of nested tags + * + * Defaults to `100` + */ + maxNestedTags?: number; +}; + +type ESchema = string | object | Array; + +type ValidationError = { + err: { + code: string; + msg: string, + line: number, + col: number + }; +}; + +declare class XMLParser { + constructor(options?: X2jOptions); + parse(xmlData: string | Uint8Array, validationOptions?: validationOptions | boolean): any; + /** + * Add Entity which is not by default supported by this library + * @param entityIdentifier {string} Eg: 'ent' for &ent; + * @param entityValue {string} Eg: '\r' + * @deprecated Use `entityDecoder` instead + */ + addEntity(entityIdentifier: string, entityValue: string): void; + + /** + * Returns a Symbol that can be used to access the {@link XMLMetaData} + * property on a node. + * + * If Symbol is not available in the environment, an ordinary property is used + * and the name of the property is here returned. + * + * The XMLMetaData property is only present when {@link X2jOptions.captureMetaData} + * is true in the options. + */ + static getMetaDataSymbol(): Symbol; +} + +declare class XMLValidator { + static validate(xmlData: string, options?: validationOptions): true | ValidationError; +} +/** + * @deprecated Use npm package 'fast-xml-builder' instead + */ +declare class XMLBuilder { + constructor(options?: XmlBuilderOptions); + build(jObj: any): string; +} + + +/** + * This object is available on nodes via the symbol {@link XMLParser.getMetaDataSymbol} + * when {@link X2jOptions.captureMetaData} is true. + */ +declare interface XMLMetaData { + /** The index, if available, of the character where the XML node began in the input stream. */ + startIndex?: number; +} + +declare namespace fxp { + export { + XMLParser, + XMLValidator, + XMLBuilder, + XMLMetaData, + XmlBuilderOptions, + X2jOptions, + ESchema, + ValidationError, + strnumOptions, + validationOptions, + ProcessEntitiesOptions, + Expression, + ReadonlyMatcher, + MatcherView, + JPathOrMatcher, + JPathOrExpression, + EntityDecoderOptions + } +} + +export = fxp; \ No newline at end of file diff --git a/spec/typings/typings-test.ts b/spec/typings/typings-test.ts new file mode 100644 index 0000000..43175b2 --- /dev/null +++ b/spec/typings/typings-test.ts @@ -0,0 +1,67 @@ +import { + XMLParser, + XMLBuilder, + XMLValidator, + type EntityDecoderOptions, + type X2jOptions, + type XmlBuilderOptions, + type validationOptions, +} from '../../src/fxp.js'; + +const parseOpts: X2jOptions = {}; + +// The parser hands `setXmlVersion` the number it read off ``. +const entityDecoder: EntityDecoderOptions = { + setExternalEntities: () => {}, + addInputEntities: () => {}, + reset: () => {}, + decode: (text: string) => text, + setXmlVersion: (version: number) => { + console.log(version.toFixed(1)); + }, +}; + +console.log(!!new XMLParser({ entityDecoder })); + +// A decoder typed for a string version would compare it against "1.1", which never matches the number it receives. +type StringVersionAccepted = ((version: string) => void) extends EntityDecoderOptions['setXmlVersion'] ? true : false; +const stringVersionAccepted: StringVersionAccepted = false; + +console.log(stringVersionAccepted); + +const XML = ` + + + + +`; + +const parser = new XMLParser(parseOpts); +const parsed = parser.parse(XML); + +console.log(!!parsed); + +const buildOpts: XmlBuilderOptions = {}; + +const builder = new XMLBuilder(buildOpts); + +const built = builder.build({ + any_name: { + person: { + phone: [ + 15555551313, + 15555551212 + ] + } + } +}); + +console.log(!!built); + +const validateOpts: validationOptions = {}; + +const isValid = XMLValidator.validate(built, validateOpts); + +console.log(!!isValid); + + diff --git a/src/fxp.d.ts b/src/fxp.d.ts new file mode 100644 index 0000000..5ba0938 --- /dev/null +++ b/src/fxp.d.ts @@ -0,0 +1,754 @@ +/** + * Types copied from path-expression-matcher + * @version + * @updated + * + * Update this file when path-expression-matcher releases a new version. + * Source: https://github.com/NaturalIntelligence/path-expression-matcher + */ + +/** + * Options for creating an Expression + */ +export interface ExpressionOptions { + /** + * Path separator character + * @default '.' + */ + separator?: string; +} + +/** + * Parsed segment from an expression pattern + */ +export interface Segment { + type: 'tag' | 'deep-wildcard'; + tag?: string; + namespace?: string; + attrName?: string; + attrValue?: string; + position?: 'first' | 'last' | 'odd' | 'even' | 'nth'; + positionValue?: number; +} + +/** + * Expression - Parses and stores a tag pattern expression. + * Patterns are parsed once and stored in an optimized structure for fast matching. + * + * @example + * ```typescript + * const expr = new Expression("root.users.user"); + * const expr2 = new Expression("..user[id]:first"); + * const expr3 = new Expression("root/users/user", { separator: '/' }); + * ``` + * + * Pattern Syntax: + * - `root.users.user` — Match exact path + * - `..user` — Match "user" at any depth (deep wildcard) + * - `user[id]` — Match user tag with "id" attribute + * - `user[id=123]` — Match user tag where id="123" + * - `user:first` — Match first occurrence of user tag + * - `ns::user` — Match user tag with namespace "ns" + * - `ns::user[id]:first` — Combine namespace, attribute, and position + */ +export class Expression { + readonly pattern: string; + readonly separator: string; + readonly segments: Segment[]; + + constructor(pattern: string, options?: ExpressionOptions); + + get length(): number; + hasDeepWildcard(): boolean; + hasAttributeCondition(): boolean; + hasPositionSelector(): boolean; + toString(): string; +} + +// --------------------------------------------------------------------------- +// MatcherView +// --------------------------------------------------------------------------- + +/** + * A lightweight, live read-only view of a Matcher instance. + * + * Returned by `Matcher.readOnly()`. The same instance is reused across every + * callback invocation — no allocation overhead per call. Reads directly from + * the parent Matcher's internal state so it always reflects the current parser + * position with no copying or freezing. + * + * Mutation methods (`push`, `pop`, `reset`, `updateCurrent`, `restore`) are + * simply absent — misuse is caught at compile time by TypeScript. + * + * This is the type received by all FXP user callbacks when `jPath: false`. + */ +export class MatcherView { + readonly separator: string; + + /** Check if current path matches an Expression. */ + matches(expression: Expression): boolean; + + /** Get current tag name, or `undefined` if path is empty. */ + getCurrentTag(): string | undefined; + + /** Get current namespace, or `undefined` if not present. */ + getCurrentNamespace(): string | undefined; + + /** Get attribute value of the current node. */ + getAttrValue(attrName: string): any; + + /** Check if the current node has a given attribute. */ + hasAttr(attrName: string): boolean; + + /** Sibling position of the current node (child index in parent). */ + getPosition(): number; + + /** Occurrence counter of the current tag name at this level. */ + getCounter(): number; + + /** Number of nodes in the current path. */ + getDepth(): number; + + /** Current path as a string (e.g. `"root.users.user"`). */ + toString(separator?: string, includeNamespace?: boolean): string; + + /** Current path as an array of tag names. */ + toArray(): string[]; +} + +/** + * @deprecated Use {@link MatcherView} instead. + * Alias kept for backward compatibility. + */ +export type ReadonlyMatcher = MatcherView; + +/** Internal node structure — exposed via snapshot only. */ +export interface PathNode { + tag: string; + namespace?: string; + position: number; + counter: number; + values?: Record; +} + +/** Snapshot of matcher state returned by `snapshot()` and `readOnly().snapshot()`. */ +export interface MatcherSnapshot { + path: PathNode[]; + siblingStacks: Map[]; +} + +/********************************************************************** + * + * END of path-expression-matcher relevant typings + * + **********************************************************************/ + +// jPath: true → string +// jPath: false → MatcherView +type JPathOrMatcher = string | MatcherView; +type JPathOrExpression = string | Expression; + +export type ProcessEntitiesOptions = { + /** + * Whether to enable entity processing + * + * Defaults to `true` + */ + enabled?: boolean; + + /** + * Maximum size in characters for a single entity definition + * + * Defaults to `10000` + */ + maxEntitySize?: number; + + /** + * Maximum depth for nested entity references (reserved for future use) + * + * Defaults to `10` + */ + maxExpansionDepth?: number; + + /** + * Maximum total number of entity expansions allowed + * + * Defaults to `1000` + */ + maxTotalExpansions?: number; + + /** + * Maximum total expanded content length in characters + * + * Defaults to `100000` + */ + maxExpandedLength?: number; + + /** + * Maximum number of entities allowed in the XML + * + * Defaults to `100` + */ + maxEntityCount?: number; + + /** + * Array of tag names where entity replacement is allowed. + * If null, entities are replaced in all tags. + * + * Defaults to `null` + */ + allowedTags?: string[] | null; + + /** + * Custom filter function to determine if entities should be replaced in a tag + * + * @param tagName - The name of the current tag + * @param jPathOrMatcher - The jPath string (if jPath: true) or Matcher instance (if jPath: false) + * @returns `true` to allow entity replacement, `false` to skip + * + * Defaults to `null` + */ + tagFilter?: ((tagName: string, jPathOrMatcher: JPathOrMatcher) => boolean) | null; +}; + +export type EntityDecoderOptions = { + setExternalEntities: (entities: Record) => void; + addInputEntities: (entities: Record) => void; + reset: () => void; + decode: (text: string) => string; + setXmlVersion: (version: number) => void; +} + +export type X2jOptions = { + /** + * Preserve the order of tags in resulting JS object + * + * Defaults to `false` + */ + preserveOrder?: boolean; + + /** + * Give a prefix to the attribute name in the resulting JS object + * + * Defaults to '@_' + */ + attributeNamePrefix?: string; + + /** + * A name to group all attributes of a tag under, or `false` to disable + * + * Defaults to `false` + */ + attributesGroupName?: false | string; + + /** + * The name of the next node in the resulting JS + * + * Defaults to `#text` + */ + textNodeName?: string; + + /** + * Whether to ignore attributes when parsing + * + * When `true` - ignores all the attributes + * + * When `false` - parses all the attributes + * + * When `Array` - filters out attributes that match provided patterns + * + * When `Function` - calls the function for each attribute and filters out those for which the function returned `true` + * + * Defaults to `true` + */ + ignoreAttributes?: boolean | (string | RegExp)[] | ((attrName: string, jPathOrMatcher: JPathOrMatcher) => boolean); + + /** + * Whether to remove namespace string from tag and attribute names + * + * Defaults to `false` + */ + removeNSPrefix?: boolean; + + /** + * Whether to allow attributes without value + * + * Defaults to `false` + */ + allowBooleanAttributes?: boolean; + + /** + * Whether to parse tag value with `strnum` package + * + * Defaults to `true` + */ + parseTagValue?: boolean; + + /** + * Whether to parse attribute value with `strnum` package + * + * Defaults to `false` + */ + parseAttributeValue?: boolean; + + /** + * Whether to remove surrounding whitespace from tag or attribute value + * + * Defaults to `true` + */ + trimValues?: boolean; + + /** + * Give a property name to set CDATA values to instead of merging to tag's text value + * + * Defaults to `false` + */ + cdataPropName?: false | string; + + /** + * If set, parse comments and set as this property + * + * Defaults to `false` + */ + commentPropName?: false | string; + + /** + * Control how tag value should be parsed. Called only if tag value is not empty + * + * @param tagName - The name of the tag + * @param tagValue - The value of the tag + * @param jPathOrMatcher - The jPath string (if jPath: true) or Matcher instance (if jPath: false) + * @param hasAttributes - Whether the tag has attributes + * @param isLeafNode - Whether the tag is a leaf node + * @returns {undefined|null} `undefined` or `null` to set original value. + * @returns {unknown} + * + * 1. Different value or value with different data type to set new value. + * 2. Same value to set parsed value if `parseTagValue: true`. + * + * Defaults to `(tagName, val, jPathOrMatcher, hasAttributes, isLeafNode) => val` + */ + tagValueProcessor?: (tagName: string, tagValue: string, jPathOrMatcher: JPathOrMatcher, hasAttributes: boolean, isLeafNode: boolean) => unknown; + + /** + * Control how attribute value should be parsed + * + * @param attrName - The name of the attribute + * @param attrValue - The value of the attribute + * @param jPathOrMatcher - The jPath string (if jPath: true) or Matcher instance (if jPath: false) + * @returns {undefined|null} `undefined` or `null` to set original value + * @returns {unknown} + * + * Defaults to `(attrName, val, jPathOrMatcher) => val` + */ + attributeValueProcessor?: (attrName: string, attrValue: string, jPathOrMatcher: JPathOrMatcher) => unknown; + + /** + * Options to pass to `strnum` for parsing numbers + * + * Defaults to `{ hex: true, leadingZeros: true, eNotation: true }` + */ + numberParseOptions?: strnumOptions; + + /** + * Nodes to stop parsing at + * + * Accepts string patterns or Expression objects from path-expression-matcher + * + * String patterns starting with "*." are automatically converted to ".." for backward compatibility + * + * Defaults to `[]` + */ + stopNodes?: JPathOrExpression[]; + + /** + * List of tags without closing tags + * + * Defaults to `[]` + */ + unpairedTags?: string[]; + + /** + * Whether to always create a text node + * + * Defaults to `false` + */ + alwaysCreateTextNode?: boolean; + + /** + * Determine whether a tag should be parsed as an array + * + * @param tagName - The name of the tag + * @param jPathOrMatcher - The jPath string (if jPath: true) or Matcher instance (if jPath: false) + * @param isLeafNode - Whether the tag is a leaf node + * @param isAttribute - Whether this is an attribute + * @returns {boolean} + * + * Defaults to `() => false` + */ + isArray?: (tagName: string, jPathOrMatcher: JPathOrMatcher, isLeafNode: boolean, isAttribute: boolean) => boolean; + + /** + * Whether to process default and DOCTYPE entities + * + * When `true` - enables entity processing with default limits + * + * When `false` - disables all entity processing + * + * When `ProcessEntitiesOptions` - enables entity processing with custom configuration + * + * Defaults to `true` + */ + processEntities?: boolean | ProcessEntitiesOptions; + + /** + * Whether to process HTML entities + * + * Defaults to `false` + * @deprecated Use `entityDecoder` instead + */ + htmlEntities?: boolean; + + /** + * Custom entity decoder + */ + entityDecoder?: EntityDecoderOptions; + /** + * Whether to ignore the declaration tag from output + * + * Defaults to `false` + */ + ignoreDeclaration?: boolean; + + /** + * Whether to ignore Pi tags + * + * Defaults to `false` + */ + ignorePiTags?: boolean; + + /** + * Transform tag names + * + * Defaults to `false` + */ + transformTagName?: ((tagName: string) => string) | false; + + /** + * Transform attribute names + * + * Defaults to `false` + */ + transformAttributeName?: ((attributeName: string) => string) | false; + + /** + * Change the tag name when a different name is returned. Skip the tag from parsed result when false is returned. + * Modify `attrs` object to control attributes for the given tag. + * + * @param tagName - The name of the tag + * @param jPathOrMatcher - The jPath string (if jPath: true) or Matcher instance (if jPath: false) + * @param attrs - The attributes object + * @returns {string} new tag name. + * @returns false to skip the tag + * + * Defaults to `(tagName, jPathOrMatcher, attrs) => tagName` + */ + updateTag?: (tagName: string, jPathOrMatcher: JPathOrMatcher, attrs: { [k: string]: string }) => string | boolean; + + /** + * If true, adds a Symbol to all object nodes, accessible by {@link XMLParser.getMetaDataSymbol} with + * metadata about each the node in the XML file. + */ + captureMetaData?: boolean; + + /** + * Maximum number of nested tags + * + * Defaults to `100` + */ + maxNestedTags?: number; + + /** + * Whether to strictly validate tag names + * + * Defaults to `true` + */ + strictReservedNames?: boolean; + + /** + * Controls whether callbacks receive jPath as string or Matcher instance + * + * When `true` - callbacks receive jPath as string (backward compatible) + * + * When `false` - callbacks receive Matcher instance for advanced pattern matching + * + * Defaults to `true` + */ + jPath?: boolean; + + /** + * Function to sanitize dangerous property names + * + * @param name - The name of the property + * @returns {string} The sanitized name + * + * Defaults to `(name) => __name` + */ + onDangerousProperty?: (name: string) => string; +}; + + + +export type strnumOptions = { + hex: boolean; + leadingZeros: boolean, + skipLike?: RegExp, + eNotation?: boolean, + infinity?: string, + unicode?: boolean +} + +export type validationOptions = { + /** + * Whether to allow attributes without value + * + * Defaults to `false` + */ + allowBooleanAttributes?: boolean; + + /** + * List of tags without closing tags + * + * Defaults to `[]` + */ + unpairedTags?: string[]; +}; + +export type XmlBuilderOptions = { + /** + * Give a prefix to the attribute name in the resulting JS object + * + * Defaults to '@_' + */ + attributeNamePrefix?: string; + + /** + * A name to group all attributes of a tag under, or `false` to disable + * + * Defaults to `false` + */ + attributesGroupName?: false | string; + + /** + * The name of the next node in the resulting JS + * + * Defaults to `#text` + */ + textNodeName?: string; + + /** + * Whether to ignore attributes when building + * + * When `true` - ignores all the attributes + * + * When `false` - builds all the attributes + * + * When `Array` - filters out attributes that match provided patterns + * + * When `Function` - calls the function for each attribute and filters out those for which the function returned `true` + * + * Defaults to `true` + */ + ignoreAttributes?: boolean | (string | RegExp)[] | ((attrName: string, jPath: string) => boolean); + + /** + * Give a property name to set CDATA values to instead of merging to tag's text value + * + * Defaults to `false` + */ + cdataPropName?: false | string; + + /** + * If set, parse comments and set as this property + * + * Defaults to `false` + */ + commentPropName?: false | string; + + /** + * Whether to make output pretty instead of single line + * + * Defaults to `false` + */ + format?: boolean; + + + /** + * If `format` is set to `true`, sets the indent string + * + * Defaults to ` ` + */ + indentBy?: string; + + /** + * Give a name to a top-level array + * + * Defaults to `undefined` + */ + arrayNodeName?: string; + + /** + * Create empty tags for tags with no text value + * + * Defaults to `false` + */ + suppressEmptyNode?: boolean; + + /** + * Suppress an unpaired tag + * + * Defaults to `true` + */ + suppressUnpairedNode?: boolean; + + /** + * Don't put a value for boolean attributes + * + * Defaults to `true` + */ + suppressBooleanAttributes?: boolean; + + /** + * Preserve the order of tags in resulting JS object + * + * Defaults to `false` + */ + preserveOrder?: boolean; + + /** + * List of tags without closing tags + * + * Defaults to `[]` + */ + unpairedTags?: string[]; + + /** + * Nodes to stop parsing at + * + * Accepts string patterns or Expression objects from path-expression-matcher + * + * Defaults to `[]` + */ + stopNodes?: JPathOrExpression[]; + + /** + * Control how tag value should be parsed. Called only if tag value is not empty + * + * @returns {undefined|null} `undefined` or `null` to set original value. + * @returns {unknown} + * + * 1. Different value or value with different data type to set new value. + * 2. Same value to set parsed value if `parseTagValue: true`. + * + * Defaults to `(tagName, val, jPath, hasAttributes, isLeafNode) => val` + */ + tagValueProcessor?: (name: string, value: unknown) => unknown; + + /** + * Control how attribute value should be parsed + * + * @param attrName + * @param attrValue + * @param jPath + * @returns {undefined|null} `undefined` or `null` to set original value + * @returns {unknown} + * + * Defaults to `(attrName, val, jPath) => val` + */ + attributeValueProcessor?: (name: string, value: unknown) => unknown; + + /** + * Whether to process default and DOCTYPE entities + * + * Defaults to `true` + */ + processEntities?: boolean; + + + oneListGroup?: boolean; + + /** + * Maximum number of nested tags + * + * Defaults to `100` + */ + maxNestedTags?: number; +}; + +type ESchema = string | object | Array; + +export type ValidationError = { + err: { + code: string; + msg: string, + line: number, + col: number + }; +}; + +export class XMLParser { + constructor(options?: X2jOptions); + + parse(xmlData: string | Uint8Array): any; + /** + * @deprecated The `validationOptions` parameter is deprecated. + * Use the `fast-xml-validator` package instead for XML validation. + * @see https://www.npmjs.com/package/fast-xml-validator + */ + parse(xmlData: string | Uint8Array, validationOptions: validationOptions | boolean): any; + /** + * Add Entity which is not by default supported by this library + * @param entityIdentifier {string} Eg: 'ent' for &ent; + * @param entityValue {string} Eg: '\r' + * @deprecated Use `entityDecoder` instead + */ + addEntity(entityIdentifier: string, entityValue: string): void; + + /** + * Returns a Symbol that can be used to access the {@link XMLMetaData} + * property on a node. + * + * If Symbol is not available in the environment, an ordinary property is used + * and the name of the property is here returned. + * + * The XMLMetaData property is only present when {@link X2jOptions.captureMetaData} + * is true in the options. + */ + static getMetaDataSymbol(): Symbol; +} + +/** + * @deprecated Use fast-xml-validator instead + * @see https://www.npmjs.com/package/fast-xml-validator + */ +export class XMLValidator { + static validate(xmlData: string, options?: validationOptions): true | ValidationError; +} +/** + * @deprecated Use npm package 'fast-xml-builder' instead + */ +export class XMLBuilder { + constructor(options?: XmlBuilderOptions); + build(jObj: any): string; +} + +/** + * This object is available on nodes via the symbol {@link XMLParser.getMetaDataSymbol} + * when {@link X2jOptions.captureMetaData} is true. + */ +export interface XMLMetaData { + /** The index, if available, of the character where the XML node began in the input stream. */ + startIndex?: number; + /** The index, if available, of the character where the XML node ended in the input stream. */ + endIndex?: number; +} \ No newline at end of file