初始化环境文件
This commit is contained in:
16
node_modules/fast-xml-builder/CHANGELOG.md
generated
vendored
Normal file
16
node_modules/fast-xml-builder/CHANGELOG.md
generated
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
**1.1.4** (2026-03-16)
|
||||
- support maxNestedTags option
|
||||
|
||||
**1.1.3** (2026-03-13)
|
||||
- declare Matcher & Expression as unknown so user is not forced to install path-expression-matcher
|
||||
|
||||
**1.1.2** (2026-03-11)
|
||||
- fix typings
|
||||
|
||||
**1.1.1** (2026-03-11)
|
||||
- upgrade path-expression-matcher to 1.1.3
|
||||
|
||||
**1.1.0** (2026-03-10)
|
||||
|
||||
- Integrate [path-expression-matcher](https://github.com/NaturalIntelligence/path-expression-matcher)
|
||||
|
||||
21
node_modules/fast-xml-builder/LICENSE
generated
vendored
Normal file
21
node_modules/fast-xml-builder/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2026 Natural Intelligence
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
23
node_modules/fast-xml-builder/README.md
generated
vendored
Normal file
23
node_modules/fast-xml-builder/README.md
generated
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
# fast-xml-builder
|
||||
Build XML from JSON
|
||||
|
||||
|
||||
XML Builder was the part of [fast-xml-parser](https://github.com/NaturalIntelligence/fast-xml-parser) for years. But considering that any bug in parser may false-alarm the users who are only using builder, we have decided to split it into a separate package.
|
||||
|
||||
## Installation
|
||||
|
||||
```bash
|
||||
npm install fast-xml-builder
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
```javascript
|
||||
import XMLBuilder from 'fast-xml-builder';
|
||||
|
||||
const builder = new XMLBuilder();
|
||||
const xml = builder.build({ name: 'value' });
|
||||
```
|
||||
|
||||
fast-xml-builder fully support the response generated by fast-xml-parser. So you can use the maximum options as you are using for fast-xml-parser like `preserveOrder`, `ignoreAttributes`, `attributeNamePrefix`, `textNodeName`, `cdataTagName`, `cdataPositionChar`, `format`, `indentBy`, `suppressEmptyNode` and many more. Any change in parser will reflect here time to time.
|
||||
|
||||
1
node_modules/fast-xml-builder/lib/fxb.cjs
generated
vendored
Normal file
1
node_modules/fast-xml-builder/lib/fxb.cjs
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
180
node_modules/fast-xml-builder/lib/fxb.d.cts
generated
vendored
Normal file
180
node_modules/fast-xml-builder/lib/fxb.d.cts
generated
vendored
Normal file
@@ -0,0 +1,180 @@
|
||||
// const { Expression } = require('path-expression-matcher');
|
||||
|
||||
type Matcher = unknown;
|
||||
type Expression = unknown;
|
||||
|
||||
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<string | RegExp>` - 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
|
||||
*
|
||||
* String patterns starting with "*." are automatically converted to ".." for backward compatibility
|
||||
*
|
||||
* Defaults to `[]`
|
||||
*/
|
||||
stopNodes?: (string | Expression)[];
|
||||
|
||||
/**
|
||||
* 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;
|
||||
};
|
||||
|
||||
interface XMLBuilder {
|
||||
build(jObj: any): string;
|
||||
}
|
||||
|
||||
interface XMLBuilderConstructor {
|
||||
new(options?: XmlBuilderOptions): XMLBuilder;
|
||||
(options?: XmlBuilderOptions): XMLBuilder;
|
||||
}
|
||||
|
||||
declare const Builder: XMLBuilderConstructor;
|
||||
|
||||
export = Builder;
|
||||
2
node_modules/fast-xml-builder/lib/fxb.min.js
generated
vendored
Normal file
2
node_modules/fast-xml-builder/lib/fxb.min.js
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
1
node_modules/fast-xml-builder/lib/fxb.min.js.map
generated
vendored
Normal file
1
node_modules/fast-xml-builder/lib/fxb.min.js.map
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
80
node_modules/fast-xml-builder/package.json
generated
vendored
Normal file
80
node_modules/fast-xml-builder/package.json
generated
vendored
Normal file
@@ -0,0 +1,80 @@
|
||||
{
|
||||
"name": "fast-xml-builder",
|
||||
"version": "1.1.4",
|
||||
"description": "Build XML from JSON without C/C++ based libraries",
|
||||
"main": "./lib/fxb.cjs",
|
||||
"type": "module",
|
||||
"sideEffects": false,
|
||||
"module": "./src/fxb.js",
|
||||
"types": "./src/fxb.d.ts",
|
||||
"exports": {
|
||||
".": {
|
||||
"import": {
|
||||
"types": "./src/fxb.d.ts",
|
||||
"default": "./src/fxb.js"
|
||||
},
|
||||
"require": {
|
||||
"types": "./lib/fxb.d.cts",
|
||||
"default": "./lib/fxb.cjs"
|
||||
}
|
||||
}
|
||||
},
|
||||
"scripts": {
|
||||
"test": "c8 --reporter=lcov --reporter=text jasmine spec/*spec.js",
|
||||
"test-types": "tsc --noEmit spec/typings/typings-test.ts",
|
||||
"unit": "jasmine",
|
||||
"lint": "eslint src/**/*.js spec/**/*.js benchmark/**/*.js",
|
||||
"bundle": "webpack --config webpack.cjs.config.js",
|
||||
"prettier": "prettier --write src/**/*.js",
|
||||
"checkReadiness": "publish-please --dry-run",
|
||||
"publish-please": "publish-please",
|
||||
"prepublishOnly": "publish-please guard"
|
||||
},
|
||||
"files": [
|
||||
"lib",
|
||||
"src",
|
||||
"CHANGELOG.md"
|
||||
],
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/NaturalIntelligence/fast-xml-builder.git"
|
||||
},
|
||||
"keywords": [
|
||||
"xml",
|
||||
"json",
|
||||
"fast",
|
||||
"builder",
|
||||
"parser",
|
||||
"js2xml",
|
||||
"json2xml"
|
||||
],
|
||||
"author": "Amit Gupta (https://solothought.com)",
|
||||
"license": "MIT",
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.13.10",
|
||||
"@babel/plugin-transform-runtime": "^7.13.10",
|
||||
"@babel/preset-env": "^7.13.10",
|
||||
"@babel/register": "^7.13.8",
|
||||
"@types/node": "20",
|
||||
"babel-loader": "^8.2.2",
|
||||
"c8": "^10.1.3",
|
||||
"eslint": "^8.3.0",
|
||||
"fast-xml-parser": "^5.3.9",
|
||||
"he": "^1.2.0",
|
||||
"jasmine": "^5.6.0",
|
||||
"prettier": "^3.5.1",
|
||||
"publish-please": "^5.5.2",
|
||||
"typescript": "5",
|
||||
"webpack": "^5.64.4",
|
||||
"webpack-cli": "^4.9.1"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/NaturalIntelligence"
|
||||
}
|
||||
],
|
||||
"dependencies": {
|
||||
"path-expression-matcher": "^1.1.3"
|
||||
}
|
||||
}
|
||||
180
node_modules/fast-xml-builder/src/fxb.d.ts
generated
vendored
Normal file
180
node_modules/fast-xml-builder/src/fxb.d.ts
generated
vendored
Normal file
@@ -0,0 +1,180 @@
|
||||
// import { Expression } from 'path-expression-matcher';
|
||||
|
||||
type Matcher = unknown;
|
||||
type Expression = unknown;
|
||||
|
||||
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<string | RegExp>` - 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
|
||||
*
|
||||
* String patterns starting with "*." are automatically converted to ".." for backward compatibility
|
||||
*
|
||||
* Defaults to `[]`
|
||||
*/
|
||||
stopNodes?: (string | Expression)[];
|
||||
|
||||
/**
|
||||
* 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;
|
||||
};
|
||||
|
||||
export interface XMLBuilder {
|
||||
build(jObj: any): string;
|
||||
}
|
||||
|
||||
export interface XMLBuilderConstructor {
|
||||
new(options?: XmlBuilderOptions): XMLBuilder;
|
||||
(options?: XmlBuilderOptions): XMLBuilder;
|
||||
}
|
||||
|
||||
declare const Builder: XMLBuilderConstructor;
|
||||
|
||||
export default Builder;
|
||||
529
node_modules/fast-xml-builder/src/fxb.js
generated
vendored
Normal file
529
node_modules/fast-xml-builder/src/fxb.js
generated
vendored
Normal file
@@ -0,0 +1,529 @@
|
||||
'use strict';
|
||||
//parse Empty Node as self closing node
|
||||
import buildFromOrderedJs from './orderedJs2Xml.js';
|
||||
import getIgnoreAttributesFn from "./ignoreAttributes.js";
|
||||
import { Expression, Matcher } from 'path-expression-matcher';
|
||||
|
||||
const defaultOptions = {
|
||||
attributeNamePrefix: '@_',
|
||||
attributesGroupName: false,
|
||||
textNodeName: '#text',
|
||||
ignoreAttributes: true,
|
||||
cdataPropName: false,
|
||||
format: false,
|
||||
indentBy: ' ',
|
||||
suppressEmptyNode: false,
|
||||
suppressUnpairedNode: true,
|
||||
suppressBooleanAttributes: true,
|
||||
tagValueProcessor: function (key, a) {
|
||||
return a;
|
||||
},
|
||||
attributeValueProcessor: function (attrName, a) {
|
||||
return a;
|
||||
},
|
||||
preserveOrder: false,
|
||||
commentPropName: false,
|
||||
unpairedTags: [],
|
||||
entities: [
|
||||
{ regex: new RegExp("&", "g"), val: "&" },//it must be on top
|
||||
{ regex: new RegExp(">", "g"), val: ">" },
|
||||
{ regex: new RegExp("<", "g"), val: "<" },
|
||||
{ regex: new RegExp("\'", "g"), val: "'" },
|
||||
{ regex: new RegExp("\"", "g"), val: """ }
|
||||
],
|
||||
processEntities: true,
|
||||
stopNodes: [],
|
||||
// transformTagName: false,
|
||||
// transformAttributeName: false,
|
||||
oneListGroup: false,
|
||||
maxNestedTags: 100,
|
||||
jPath: true // When true, callbacks receive string jPath; when false, receive Matcher instance
|
||||
};
|
||||
|
||||
export default function Builder(options) {
|
||||
this.options = Object.assign({}, defaultOptions, options);
|
||||
|
||||
// Convert old-style stopNodes for backward compatibility
|
||||
// Old syntax: "*.tag" meant "tag anywhere in tree"
|
||||
// New syntax: "..tag" means "tag anywhere in tree"
|
||||
if (this.options.stopNodes && Array.isArray(this.options.stopNodes)) {
|
||||
this.options.stopNodes = this.options.stopNodes.map(node => {
|
||||
if (typeof node === 'string' && node.startsWith('*.')) {
|
||||
// Convert old wildcard syntax to deep wildcard
|
||||
return '..' + node.substring(2);
|
||||
}
|
||||
return node;
|
||||
});
|
||||
}
|
||||
|
||||
// Pre-compile stopNode expressions for pattern matching
|
||||
this.stopNodeExpressions = [];
|
||||
if (this.options.stopNodes && Array.isArray(this.options.stopNodes)) {
|
||||
for (let i = 0; i < this.options.stopNodes.length; i++) {
|
||||
const node = this.options.stopNodes[i];
|
||||
if (typeof node === 'string') {
|
||||
this.stopNodeExpressions.push(new Expression(node));
|
||||
} else if (node instanceof Expression) {
|
||||
this.stopNodeExpressions.push(node);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (this.options.ignoreAttributes === true || this.options.attributesGroupName) {
|
||||
this.isAttribute = function (/*a*/) {
|
||||
return false;
|
||||
};
|
||||
} else {
|
||||
this.ignoreAttributesFn = getIgnoreAttributesFn(this.options.ignoreAttributes)
|
||||
this.attrPrefixLen = this.options.attributeNamePrefix.length;
|
||||
this.isAttribute = isAttribute;
|
||||
}
|
||||
|
||||
this.processTextOrObjNode = processTextOrObjNode
|
||||
|
||||
if (this.options.format) {
|
||||
this.indentate = indentate;
|
||||
this.tagEndChar = '>\n';
|
||||
this.newLine = '\n';
|
||||
} else {
|
||||
this.indentate = function () {
|
||||
return '';
|
||||
};
|
||||
this.tagEndChar = '>';
|
||||
this.newLine = '';
|
||||
}
|
||||
}
|
||||
|
||||
Builder.prototype.build = function (jObj) {
|
||||
if (this.options.preserveOrder) {
|
||||
return buildFromOrderedJs(jObj, this.options);
|
||||
} else {
|
||||
if (Array.isArray(jObj) && this.options.arrayNodeName && this.options.arrayNodeName.length > 1) {
|
||||
jObj = {
|
||||
[this.options.arrayNodeName]: jObj
|
||||
}
|
||||
}
|
||||
// Initialize matcher for path tracking
|
||||
const matcher = new Matcher();
|
||||
return this.j2x(jObj, 0, matcher).val;
|
||||
}
|
||||
};
|
||||
|
||||
Builder.prototype.j2x = function (jObj, level, matcher) {
|
||||
let attrStr = '';
|
||||
let val = '';
|
||||
if (this.options.maxNestedTags && matcher.getDepth() >= this.options.maxNestedTags) {
|
||||
throw new Error("Maximum nested tags exceeded");
|
||||
}
|
||||
// Get jPath based on option: string for backward compatibility, or Matcher for new features
|
||||
const jPath = this.options.jPath ? matcher.toString() : matcher;
|
||||
|
||||
// Check if current node is a stopNode (will be used for attribute encoding)
|
||||
const isCurrentStopNode = this.checkStopNode(matcher);
|
||||
|
||||
for (let key in jObj) {
|
||||
if (!Object.prototype.hasOwnProperty.call(jObj, key)) continue;
|
||||
if (typeof jObj[key] === 'undefined') {
|
||||
// supress undefined node only if it is not an attribute
|
||||
if (this.isAttribute(key)) {
|
||||
val += '';
|
||||
}
|
||||
} else if (jObj[key] === null) {
|
||||
// null attribute should be ignored by the attribute list, but should not cause the tag closing
|
||||
if (this.isAttribute(key)) {
|
||||
val += '';
|
||||
} else if (key === this.options.cdataPropName) {
|
||||
val += '';
|
||||
} else if (key[0] === '?') {
|
||||
val += this.indentate(level) + '<' + key + '?' + this.tagEndChar;
|
||||
} else {
|
||||
val += this.indentate(level) + '<' + key + '/' + this.tagEndChar;
|
||||
}
|
||||
// val += this.indentate(level) + '<' + key + '/' + this.tagEndChar;
|
||||
} else if (jObj[key] instanceof Date) {
|
||||
val += this.buildTextValNode(jObj[key], key, '', level, matcher);
|
||||
} else if (typeof jObj[key] !== 'object') {
|
||||
//premitive type
|
||||
const attr = this.isAttribute(key);
|
||||
if (attr && !this.ignoreAttributesFn(attr, jPath)) {
|
||||
attrStr += this.buildAttrPairStr(attr, '' + jObj[key], isCurrentStopNode);
|
||||
} else if (!attr) {
|
||||
//tag value
|
||||
if (key === this.options.textNodeName) {
|
||||
let newval = this.options.tagValueProcessor(key, '' + jObj[key]);
|
||||
val += this.replaceEntitiesValue(newval);
|
||||
} else {
|
||||
// Check if this is a stopNode before building
|
||||
matcher.push(key);
|
||||
const isStopNode = this.checkStopNode(matcher);
|
||||
matcher.pop();
|
||||
|
||||
if (isStopNode) {
|
||||
// Build as raw content without encoding
|
||||
const textValue = '' + jObj[key];
|
||||
if (textValue === '') {
|
||||
val += this.indentate(level) + '<' + key + this.closeTag(key) + this.tagEndChar;
|
||||
} else {
|
||||
val += this.indentate(level) + '<' + key + '>' + textValue + '</' + key + this.tagEndChar;
|
||||
}
|
||||
} else {
|
||||
val += this.buildTextValNode(jObj[key], key, '', level, matcher);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (Array.isArray(jObj[key])) {
|
||||
//repeated nodes
|
||||
const arrLen = jObj[key].length;
|
||||
let listTagVal = "";
|
||||
let listTagAttr = "";
|
||||
for (let j = 0; j < arrLen; j++) {
|
||||
const item = jObj[key][j];
|
||||
if (typeof item === 'undefined') {
|
||||
// supress undefined node
|
||||
} else if (item === null) {
|
||||
if (key[0] === "?") val += this.indentate(level) + '<' + key + '?' + this.tagEndChar;
|
||||
else val += this.indentate(level) + '<' + key + '/' + this.tagEndChar;
|
||||
// val += this.indentate(level) + '<' + key + '/' + this.tagEndChar;
|
||||
} else if (typeof item === 'object') {
|
||||
if (this.options.oneListGroup) {
|
||||
// Push tag to matcher before recursive call
|
||||
matcher.push(key);
|
||||
const result = this.j2x(item, level + 1, matcher);
|
||||
// Pop tag from matcher after recursive call
|
||||
matcher.pop();
|
||||
|
||||
listTagVal += result.val;
|
||||
if (this.options.attributesGroupName && item.hasOwnProperty(this.options.attributesGroupName)) {
|
||||
listTagAttr += result.attrStr
|
||||
}
|
||||
} else {
|
||||
listTagVal += this.processTextOrObjNode(item, key, level, matcher)
|
||||
}
|
||||
} else {
|
||||
if (this.options.oneListGroup) {
|
||||
let textValue = this.options.tagValueProcessor(key, item);
|
||||
textValue = this.replaceEntitiesValue(textValue);
|
||||
listTagVal += textValue;
|
||||
} else {
|
||||
// Check if this is a stopNode before building
|
||||
matcher.push(key);
|
||||
const isStopNode = this.checkStopNode(matcher);
|
||||
matcher.pop();
|
||||
|
||||
if (isStopNode) {
|
||||
// Build as raw content without encoding
|
||||
const textValue = '' + item;
|
||||
if (textValue === '') {
|
||||
listTagVal += this.indentate(level) + '<' + key + this.closeTag(key) + this.tagEndChar;
|
||||
} else {
|
||||
listTagVal += this.indentate(level) + '<' + key + '>' + textValue + '</' + key + this.tagEndChar;
|
||||
}
|
||||
} else {
|
||||
listTagVal += this.buildTextValNode(item, key, '', level, matcher);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (this.options.oneListGroup) {
|
||||
listTagVal = this.buildObjectNode(listTagVal, key, listTagAttr, level);
|
||||
}
|
||||
val += listTagVal;
|
||||
} else {
|
||||
//nested node
|
||||
if (this.options.attributesGroupName && key === this.options.attributesGroupName) {
|
||||
const Ks = Object.keys(jObj[key]);
|
||||
const L = Ks.length;
|
||||
for (let j = 0; j < L; j++) {
|
||||
attrStr += this.buildAttrPairStr(Ks[j], '' + jObj[key][Ks[j]], isCurrentStopNode);
|
||||
}
|
||||
} else {
|
||||
val += this.processTextOrObjNode(jObj[key], key, level, matcher)
|
||||
}
|
||||
}
|
||||
}
|
||||
return { attrStr: attrStr, val: val };
|
||||
};
|
||||
|
||||
Builder.prototype.buildAttrPairStr = function (attrName, val, isStopNode) {
|
||||
if (!isStopNode) {
|
||||
val = this.options.attributeValueProcessor(attrName, '' + val);
|
||||
val = this.replaceEntitiesValue(val);
|
||||
}
|
||||
if (this.options.suppressBooleanAttributes && val === "true") {
|
||||
return ' ' + attrName;
|
||||
} else return ' ' + attrName + '="' + val + '"';
|
||||
}
|
||||
|
||||
function processTextOrObjNode(object, key, level, matcher) {
|
||||
// Extract attributes to pass to matcher
|
||||
const attrValues = this.extractAttributes(object);
|
||||
|
||||
// Push tag to matcher before recursion WITH attributes
|
||||
matcher.push(key, attrValues);
|
||||
|
||||
// Check if this entire node is a stopNode
|
||||
const isStopNode = this.checkStopNode(matcher);
|
||||
|
||||
if (isStopNode) {
|
||||
// For stopNodes, build raw content without entity encoding
|
||||
const rawContent = this.buildRawContent(object);
|
||||
const attrStr = this.buildAttributesForStopNode(object);
|
||||
matcher.pop();
|
||||
return this.buildObjectNode(rawContent, key, attrStr, level);
|
||||
}
|
||||
|
||||
const result = this.j2x(object, level + 1, matcher);
|
||||
// Pop tag from matcher after recursion
|
||||
matcher.pop();
|
||||
|
||||
if (object[this.options.textNodeName] !== undefined && Object.keys(object).length === 1) {
|
||||
return this.buildTextValNode(object[this.options.textNodeName], key, result.attrStr, level, matcher);
|
||||
} else {
|
||||
return this.buildObjectNode(result.val, key, result.attrStr, level);
|
||||
}
|
||||
}
|
||||
|
||||
// Helper method to extract attributes from an object
|
||||
Builder.prototype.extractAttributes = function (obj) {
|
||||
if (!obj || typeof obj !== 'object') return null;
|
||||
|
||||
const attrValues = {};
|
||||
let hasAttrs = false;
|
||||
|
||||
// Check for attributesGroupName (when attributes are grouped)
|
||||
if (this.options.attributesGroupName && obj[this.options.attributesGroupName]) {
|
||||
const attrGroup = obj[this.options.attributesGroupName];
|
||||
for (let attrKey in attrGroup) {
|
||||
if (!Object.prototype.hasOwnProperty.call(attrGroup, attrKey)) continue;
|
||||
// Remove attribute prefix if present
|
||||
const cleanKey = attrKey.startsWith(this.options.attributeNamePrefix)
|
||||
? attrKey.substring(this.options.attributeNamePrefix.length)
|
||||
: attrKey;
|
||||
attrValues[cleanKey] = attrGroup[attrKey];
|
||||
hasAttrs = true;
|
||||
}
|
||||
} else {
|
||||
// Look for individual attributes (prefixed with attributeNamePrefix)
|
||||
for (let key in obj) {
|
||||
if (!Object.prototype.hasOwnProperty.call(obj, key)) continue;
|
||||
const attr = this.isAttribute(key);
|
||||
if (attr) {
|
||||
attrValues[attr] = obj[key];
|
||||
hasAttrs = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return hasAttrs ? attrValues : null;
|
||||
};
|
||||
|
||||
// Build raw content for stopNode without entity encoding
|
||||
Builder.prototype.buildRawContent = function (obj) {
|
||||
if (typeof obj === 'string') {
|
||||
return obj; // Already a string, return as-is
|
||||
}
|
||||
|
||||
if (typeof obj !== 'object' || obj === null) {
|
||||
return String(obj);
|
||||
}
|
||||
|
||||
// Check if this is a stopNode data from parser: { "#text": "raw xml", "@_attr": "val" }
|
||||
if (obj[this.options.textNodeName] !== undefined) {
|
||||
return obj[this.options.textNodeName]; // Return raw text without encoding
|
||||
}
|
||||
|
||||
// Build raw XML from nested structure
|
||||
let content = '';
|
||||
|
||||
for (let key in obj) {
|
||||
if (!Object.prototype.hasOwnProperty.call(obj, key)) continue;
|
||||
|
||||
// Skip attributes
|
||||
if (this.isAttribute(key)) continue;
|
||||
if (this.options.attributesGroupName && key === this.options.attributesGroupName) continue;
|
||||
|
||||
const value = obj[key];
|
||||
|
||||
if (key === this.options.textNodeName) {
|
||||
content += value; // Raw text
|
||||
} else if (Array.isArray(value)) {
|
||||
// Array of same tag
|
||||
for (let item of value) {
|
||||
if (typeof item === 'string' || typeof item === 'number') {
|
||||
content += `<${key}>${item}</${key}>`;
|
||||
} else if (typeof item === 'object' && item !== null) {
|
||||
const nestedContent = this.buildRawContent(item);
|
||||
const nestedAttrs = this.buildAttributesForStopNode(item);
|
||||
if (nestedContent === '') {
|
||||
content += `<${key}${nestedAttrs}/>`;
|
||||
} else {
|
||||
content += `<${key}${nestedAttrs}>${nestedContent}</${key}>`;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (typeof value === 'object' && value !== null) {
|
||||
// Nested object
|
||||
const nestedContent = this.buildRawContent(value);
|
||||
const nestedAttrs = this.buildAttributesForStopNode(value);
|
||||
if (nestedContent === '') {
|
||||
content += `<${key}${nestedAttrs}/>`;
|
||||
} else {
|
||||
content += `<${key}${nestedAttrs}>${nestedContent}</${key}>`;
|
||||
}
|
||||
} else {
|
||||
// Primitive value
|
||||
content += `<${key}>${value}</${key}>`;
|
||||
}
|
||||
}
|
||||
|
||||
return content;
|
||||
};
|
||||
|
||||
// Build attribute string for stopNode (no entity encoding)
|
||||
Builder.prototype.buildAttributesForStopNode = function (obj) {
|
||||
if (!obj || typeof obj !== 'object') return '';
|
||||
|
||||
let attrStr = '';
|
||||
|
||||
// Check for attributesGroupName (when attributes are grouped)
|
||||
if (this.options.attributesGroupName && obj[this.options.attributesGroupName]) {
|
||||
const attrGroup = obj[this.options.attributesGroupName];
|
||||
for (let attrKey in attrGroup) {
|
||||
if (!Object.prototype.hasOwnProperty.call(attrGroup, attrKey)) continue;
|
||||
const cleanKey = attrKey.startsWith(this.options.attributeNamePrefix)
|
||||
? attrKey.substring(this.options.attributeNamePrefix.length)
|
||||
: attrKey;
|
||||
const val = attrGroup[attrKey];
|
||||
if (val === true && this.options.suppressBooleanAttributes) {
|
||||
attrStr += ' ' + cleanKey;
|
||||
} else {
|
||||
attrStr += ' ' + cleanKey + '="' + val + '"'; // No encoding for stopNode
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Look for individual attributes
|
||||
for (let key in obj) {
|
||||
if (!Object.prototype.hasOwnProperty.call(obj, key)) continue;
|
||||
const attr = this.isAttribute(key);
|
||||
if (attr) {
|
||||
const val = obj[key];
|
||||
if (val === true && this.options.suppressBooleanAttributes) {
|
||||
attrStr += ' ' + attr;
|
||||
} else {
|
||||
attrStr += ' ' + attr + '="' + val + '"'; // No encoding for stopNode
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return attrStr;
|
||||
};
|
||||
|
||||
Builder.prototype.buildObjectNode = function (val, key, attrStr, level) {
|
||||
if (val === "") {
|
||||
if (key[0] === "?") return this.indentate(level) + '<' + key + attrStr + '?' + this.tagEndChar;
|
||||
else {
|
||||
return this.indentate(level) + '<' + key + attrStr + this.closeTag(key) + this.tagEndChar;
|
||||
}
|
||||
} else {
|
||||
|
||||
let tagEndExp = '</' + key + this.tagEndChar;
|
||||
let piClosingChar = "";
|
||||
|
||||
if (key[0] === "?") {
|
||||
piClosingChar = "?";
|
||||
tagEndExp = "";
|
||||
}
|
||||
|
||||
// attrStr is an empty string in case the attribute came as undefined or null
|
||||
if ((attrStr || attrStr === '') && val.indexOf('<') === -1) {
|
||||
return (this.indentate(level) + '<' + key + attrStr + piClosingChar + '>' + val + tagEndExp);
|
||||
} else if (this.options.commentPropName !== false && key === this.options.commentPropName && piClosingChar.length === 0) {
|
||||
return this.indentate(level) + `<!--${val}-->` + this.newLine;
|
||||
} else {
|
||||
return (
|
||||
this.indentate(level) + '<' + key + attrStr + piClosingChar + this.tagEndChar +
|
||||
val +
|
||||
this.indentate(level) + tagEndExp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Builder.prototype.closeTag = function (key) {
|
||||
let closeTag = "";
|
||||
if (this.options.unpairedTags.indexOf(key) !== -1) { //unpaired
|
||||
if (!this.options.suppressUnpairedNode) closeTag = "/"
|
||||
} else if (this.options.suppressEmptyNode) { //empty
|
||||
closeTag = "/";
|
||||
} else {
|
||||
closeTag = `></${key}`
|
||||
}
|
||||
return closeTag;
|
||||
}
|
||||
|
||||
Builder.prototype.checkStopNode = function (matcher) {
|
||||
if (!this.stopNodeExpressions || this.stopNodeExpressions.length === 0) return false;
|
||||
|
||||
for (let i = 0; i < this.stopNodeExpressions.length; i++) {
|
||||
if (matcher.matches(this.stopNodeExpressions[i])) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function buildEmptyObjNode(val, key, attrStr, level) {
|
||||
if (val !== '') {
|
||||
return this.buildObjectNode(val, key, attrStr, level);
|
||||
} else {
|
||||
if (key[0] === "?") return this.indentate(level) + '<' + key + attrStr + '?' + this.tagEndChar;
|
||||
else {
|
||||
return this.indentate(level) + '<' + key + attrStr + '/' + this.tagEndChar;
|
||||
// return this.buildTagStr(level,key, attrStr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Builder.prototype.buildTextValNode = function (val, key, attrStr, level, matcher) {
|
||||
if (this.options.cdataPropName !== false && key === this.options.cdataPropName) {
|
||||
return this.indentate(level) + `<![CDATA[${val}]]>` + this.newLine;
|
||||
} else if (this.options.commentPropName !== false && key === this.options.commentPropName) {
|
||||
return this.indentate(level) + `<!--${val}-->` + this.newLine;
|
||||
} else if (key[0] === "?") {//PI tag
|
||||
return this.indentate(level) + '<' + key + attrStr + '?' + this.tagEndChar;
|
||||
} else {
|
||||
// Normal processing: apply tagValueProcessor and entity replacement
|
||||
let textValue = this.options.tagValueProcessor(key, val);
|
||||
textValue = this.replaceEntitiesValue(textValue);
|
||||
|
||||
if (textValue === '') {
|
||||
return this.indentate(level) + '<' + key + attrStr + this.closeTag(key) + this.tagEndChar;
|
||||
} else {
|
||||
return this.indentate(level) + '<' + key + attrStr + '>' +
|
||||
textValue +
|
||||
'</' + key + this.tagEndChar;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Builder.prototype.replaceEntitiesValue = function (textValue) {
|
||||
if (textValue && textValue.length > 0 && this.options.processEntities) {
|
||||
for (let i = 0; i < this.options.entities.length; i++) {
|
||||
const entity = this.options.entities[i];
|
||||
textValue = textValue.replace(entity.regex, entity.val);
|
||||
}
|
||||
}
|
||||
return textValue;
|
||||
}
|
||||
|
||||
function indentate(level) {
|
||||
return this.options.indentBy.repeat(level);
|
||||
}
|
||||
|
||||
function isAttribute(name /*, options*/) {
|
||||
if (name.startsWith(this.options.attributeNamePrefix) && name !== this.options.textNodeName) {
|
||||
return name.substr(this.attrPrefixLen);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
18
node_modules/fast-xml-builder/src/ignoreAttributes.js
generated
vendored
Normal file
18
node_modules/fast-xml-builder/src/ignoreAttributes.js
generated
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
export default function getIgnoreAttributesFn(ignoreAttributes) {
|
||||
if (typeof ignoreAttributes === 'function') {
|
||||
return ignoreAttributes
|
||||
}
|
||||
if (Array.isArray(ignoreAttributes)) {
|
||||
return (attrName) => {
|
||||
for (const pattern of ignoreAttributes) {
|
||||
if (typeof pattern === 'string' && attrName === pattern) {
|
||||
return true
|
||||
}
|
||||
if (pattern instanceof RegExp && pattern.test(attrName)) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return () => false
|
||||
}
|
||||
292
node_modules/fast-xml-builder/src/orderedJs2Xml.js
generated
vendored
Normal file
292
node_modules/fast-xml-builder/src/orderedJs2Xml.js
generated
vendored
Normal file
@@ -0,0 +1,292 @@
|
||||
import { Expression, Matcher } from 'path-expression-matcher';
|
||||
|
||||
const EOL = "\n";
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {array} jArray
|
||||
* @param {any} options
|
||||
* @returns
|
||||
*/
|
||||
export default function toXml(jArray, options) {
|
||||
let indentation = "";
|
||||
if (options.format && options.indentBy.length > 0) {
|
||||
indentation = EOL;
|
||||
}
|
||||
|
||||
// Pre-compile stopNode expressions for pattern matching
|
||||
const stopNodeExpressions = [];
|
||||
if (options.stopNodes && Array.isArray(options.stopNodes)) {
|
||||
for (let i = 0; i < options.stopNodes.length; i++) {
|
||||
const node = options.stopNodes[i];
|
||||
if (typeof node === 'string') {
|
||||
stopNodeExpressions.push(new Expression(node));
|
||||
} else if (node instanceof Expression) {
|
||||
stopNodeExpressions.push(node);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize matcher for path tracking
|
||||
const matcher = new Matcher();
|
||||
|
||||
return arrToStr(jArray, options, indentation, matcher, stopNodeExpressions);
|
||||
}
|
||||
|
||||
function arrToStr(arr, options, indentation, matcher, stopNodeExpressions) {
|
||||
let xmlStr = "";
|
||||
let isPreviousElementTag = false;
|
||||
|
||||
if (options.maxNestedTags && matcher.getDepth() > options.maxNestedTags) {
|
||||
throw new Error("Maximum nested tags exceeded");
|
||||
}
|
||||
|
||||
if (!Array.isArray(arr)) {
|
||||
// Non-array values (e.g. string tag values) should be treated as text content
|
||||
if (arr !== undefined && arr !== null) {
|
||||
let text = arr.toString();
|
||||
text = replaceEntitiesValue(text, options);
|
||||
return text;
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
for (let i = 0; i < arr.length; i++) {
|
||||
const tagObj = arr[i];
|
||||
const tagName = propName(tagObj);
|
||||
if (tagName === undefined) continue;
|
||||
|
||||
// Extract attributes from ":@" property
|
||||
const attrValues = extractAttributeValues(tagObj[":@"], options);
|
||||
|
||||
// Push tag to matcher WITH attributes
|
||||
matcher.push(tagName, attrValues);
|
||||
|
||||
// Check if this is a stop node using Expression matching
|
||||
const isStopNode = checkStopNode(matcher, stopNodeExpressions);
|
||||
|
||||
if (tagName === options.textNodeName) {
|
||||
let tagText = tagObj[tagName];
|
||||
if (!isStopNode) {
|
||||
tagText = options.tagValueProcessor(tagName, tagText);
|
||||
tagText = replaceEntitiesValue(tagText, options);
|
||||
}
|
||||
if (isPreviousElementTag) {
|
||||
xmlStr += indentation;
|
||||
}
|
||||
xmlStr += tagText;
|
||||
isPreviousElementTag = false;
|
||||
matcher.pop();
|
||||
continue;
|
||||
} else if (tagName === options.cdataPropName) {
|
||||
if (isPreviousElementTag) {
|
||||
xmlStr += indentation;
|
||||
}
|
||||
xmlStr += `<![CDATA[${tagObj[tagName][0][options.textNodeName]}]]>`;
|
||||
isPreviousElementTag = false;
|
||||
matcher.pop();
|
||||
continue;
|
||||
} else if (tagName === options.commentPropName) {
|
||||
xmlStr += indentation + `<!--${tagObj[tagName][0][options.textNodeName]}-->`;
|
||||
isPreviousElementTag = true;
|
||||
matcher.pop();
|
||||
continue;
|
||||
} else if (tagName[0] === "?") {
|
||||
const attStr = attr_to_str(tagObj[":@"], options, isStopNode);
|
||||
const tempInd = tagName === "?xml" ? "" : indentation;
|
||||
let piTextNodeName = tagObj[tagName][0][options.textNodeName];
|
||||
piTextNodeName = piTextNodeName.length !== 0 ? " " + piTextNodeName : ""; //remove extra spacing
|
||||
xmlStr += tempInd + `<${tagName}${piTextNodeName}${attStr}?>`;
|
||||
isPreviousElementTag = true;
|
||||
matcher.pop();
|
||||
continue;
|
||||
}
|
||||
|
||||
let newIdentation = indentation;
|
||||
if (newIdentation !== "") {
|
||||
newIdentation += options.indentBy;
|
||||
}
|
||||
|
||||
// Pass isStopNode to attr_to_str so attributes are also not processed for stopNodes
|
||||
const attStr = attr_to_str(tagObj[":@"], options, isStopNode);
|
||||
const tagStart = indentation + `<${tagName}${attStr}`;
|
||||
|
||||
// If this is a stopNode, get raw content without processing
|
||||
let tagValue;
|
||||
if (isStopNode) {
|
||||
tagValue = getRawContent(tagObj[tagName], options);
|
||||
} else {
|
||||
|
||||
tagValue = arrToStr(tagObj[tagName], options, newIdentation, matcher, stopNodeExpressions);
|
||||
}
|
||||
|
||||
if (options.unpairedTags.indexOf(tagName) !== -1) {
|
||||
if (options.suppressUnpairedNode) xmlStr += tagStart + ">";
|
||||
else xmlStr += tagStart + "/>";
|
||||
} else if ((!tagValue || tagValue.length === 0) && options.suppressEmptyNode) {
|
||||
xmlStr += tagStart + "/>";
|
||||
} else if (tagValue && tagValue.endsWith(">")) {
|
||||
xmlStr += tagStart + `>${tagValue}${indentation}</${tagName}>`;
|
||||
} else {
|
||||
xmlStr += tagStart + ">";
|
||||
if (tagValue && indentation !== "" && (tagValue.includes("/>") || tagValue.includes("</"))) {
|
||||
xmlStr += indentation + options.indentBy + tagValue + indentation;
|
||||
} else {
|
||||
xmlStr += tagValue;
|
||||
}
|
||||
xmlStr += `</${tagName}>`;
|
||||
}
|
||||
isPreviousElementTag = true;
|
||||
|
||||
// Pop tag from matcher
|
||||
matcher.pop();
|
||||
}
|
||||
|
||||
return xmlStr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract attribute values from the ":@" object and return as plain object
|
||||
* for passing to matcher.push()
|
||||
*/
|
||||
function extractAttributeValues(attrMap, options) {
|
||||
if (!attrMap || options.ignoreAttributes) return null;
|
||||
|
||||
const attrValues = {};
|
||||
let hasAttrs = false;
|
||||
|
||||
for (let attr in attrMap) {
|
||||
if (!Object.prototype.hasOwnProperty.call(attrMap, attr)) continue;
|
||||
// Remove the attribute prefix to get clean attribute name
|
||||
const cleanAttrName = attr.startsWith(options.attributeNamePrefix)
|
||||
? attr.substr(options.attributeNamePrefix.length)
|
||||
: attr;
|
||||
attrValues[cleanAttrName] = attrMap[attr];
|
||||
hasAttrs = true;
|
||||
}
|
||||
|
||||
return hasAttrs ? attrValues : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract raw content from a stopNode without any processing
|
||||
* This preserves the content exactly as-is, including special characters
|
||||
*/
|
||||
function getRawContent(arr, options) {
|
||||
if (!Array.isArray(arr)) {
|
||||
// Non-array values return as-is
|
||||
if (arr !== undefined && arr !== null) {
|
||||
return arr.toString();
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
let content = "";
|
||||
for (let i = 0; i < arr.length; i++) {
|
||||
const item = arr[i];
|
||||
const tagName = propName(item);
|
||||
|
||||
if (tagName === options.textNodeName) {
|
||||
// Raw text content - NO processing, NO entity replacement
|
||||
content += item[tagName];
|
||||
} else if (tagName === options.cdataPropName) {
|
||||
// CDATA content
|
||||
content += item[tagName][0][options.textNodeName];
|
||||
} else if (tagName === options.commentPropName) {
|
||||
// Comment content
|
||||
content += item[tagName][0][options.textNodeName];
|
||||
} else if (tagName && tagName[0] === "?") {
|
||||
// Processing instruction - skip for stopNodes
|
||||
continue;
|
||||
} else if (tagName) {
|
||||
// Nested tags within stopNode
|
||||
// Recursively get raw content and reconstruct the tag
|
||||
// For stopNodes, we don't process attributes either
|
||||
const attStr = attr_to_str_raw(item[":@"], options);
|
||||
const nestedContent = getRawContent(item[tagName], options);
|
||||
|
||||
if (!nestedContent || nestedContent.length === 0) {
|
||||
content += `<${tagName}${attStr}/>`;
|
||||
} else {
|
||||
content += `<${tagName}${attStr}>${nestedContent}</${tagName}>`;
|
||||
}
|
||||
}
|
||||
}
|
||||
return content;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build attribute string for stopNodes - NO entity replacement
|
||||
*/
|
||||
function attr_to_str_raw(attrMap, options) {
|
||||
let attrStr = "";
|
||||
if (attrMap && !options.ignoreAttributes) {
|
||||
for (let attr in attrMap) {
|
||||
if (!Object.prototype.hasOwnProperty.call(attrMap, attr)) continue;
|
||||
// For stopNodes, use raw value without processing
|
||||
let attrVal = attrMap[attr];
|
||||
if (attrVal === true && options.suppressBooleanAttributes) {
|
||||
attrStr += ` ${attr.substr(options.attributeNamePrefix.length)}`;
|
||||
} else {
|
||||
attrStr += ` ${attr.substr(options.attributeNamePrefix.length)}="${attrVal}"`;
|
||||
}
|
||||
}
|
||||
}
|
||||
return attrStr;
|
||||
}
|
||||
|
||||
function propName(obj) {
|
||||
const keys = Object.keys(obj);
|
||||
for (let i = 0; i < keys.length; i++) {
|
||||
const key = keys[i];
|
||||
if (!Object.prototype.hasOwnProperty.call(obj, key)) continue;
|
||||
if (key !== ":@") return key;
|
||||
}
|
||||
}
|
||||
|
||||
function attr_to_str(attrMap, options, isStopNode) {
|
||||
let attrStr = "";
|
||||
if (attrMap && !options.ignoreAttributes) {
|
||||
for (let attr in attrMap) {
|
||||
if (!Object.prototype.hasOwnProperty.call(attrMap, attr)) continue;
|
||||
let attrVal;
|
||||
|
||||
if (isStopNode) {
|
||||
// For stopNodes, use raw value without any processing
|
||||
attrVal = attrMap[attr];
|
||||
} else {
|
||||
// Normal processing: apply attributeValueProcessor and entity replacement
|
||||
attrVal = options.attributeValueProcessor(attr, attrMap[attr]);
|
||||
attrVal = replaceEntitiesValue(attrVal, options);
|
||||
}
|
||||
|
||||
if (attrVal === true && options.suppressBooleanAttributes) {
|
||||
attrStr += ` ${attr.substr(options.attributeNamePrefix.length)}`;
|
||||
} else {
|
||||
attrStr += ` ${attr.substr(options.attributeNamePrefix.length)}="${attrVal}"`;
|
||||
}
|
||||
}
|
||||
}
|
||||
return attrStr;
|
||||
}
|
||||
|
||||
function checkStopNode(matcher, stopNodeExpressions) {
|
||||
if (!stopNodeExpressions || stopNodeExpressions.length === 0) return false;
|
||||
|
||||
for (let i = 0; i < stopNodeExpressions.length; i++) {
|
||||
if (matcher.matches(stopNodeExpressions[i])) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function replaceEntitiesValue(textValue, options) {
|
||||
if (textValue && textValue.length > 0 && options.processEntities) {
|
||||
for (let i = 0; i < options.entities.length; i++) {
|
||||
const entity = options.entities[i];
|
||||
textValue = textValue.replace(entity.regex, entity.val);
|
||||
}
|
||||
}
|
||||
return textValue;
|
||||
}
|
||||
0
node_modules/fast-xml-builder/src/prettifyJs2Xml.js
generated
vendored
Normal file
0
node_modules/fast-xml-builder/src/prettifyJs2Xml.js
generated
vendored
Normal file
Reference in New Issue
Block a user