From 90642fa8c57fc2b37e59e997c1e525663a1c5067 Mon Sep 17 00:00:00 2001 From: Evgenii Korolevskii Date: Thu, 29 Sep 2022 18:23:42 +0200 Subject: [PATCH] update parser to v4 --- dist/index.js | 2313 +++++++++++++++++++++++++++------------------ package-lock.json | 33 +- package.json | 2 +- src/authutil.ts | 9 +- 4 files changed, 1427 insertions(+), 930 deletions(-) diff --git a/dist/index.js b/dist/index.js index 5b10e8d..a799d59 100644 --- a/dist/index.js +++ b/dist/index.js @@ -32,7 +32,7 @@ const path = __importStar(__nccwpck_require__(1017)); const core = __importStar(__nccwpck_require__(2186)); const github = __importStar(__nccwpck_require__(5438)); const xmlbuilder = __importStar(__nccwpck_require__(2958)); -const xmlParser = __importStar(__nccwpck_require__(7448)); +const fast_xml_parser_1 = __nccwpck_require__(2603); function configAuthentication(feedUrl, existingFileLocation = '', processRoot = process.cwd()) { const existingNuGetConfig = path.resolve(processRoot, existingFileLocation === '' ? getExistingNugetConfig(processRoot) @@ -70,7 +70,11 @@ function writeFeedToFile(feedUrl, existingFileLocation, tempFileLocation) { if (fs.existsSync(existingFileLocation)) { // get key from existing NuGet.config so NuGet/dotnet can match credentials const curContents = fs.readFileSync(existingFileLocation, 'utf8'); - const json = xmlParser.parse(curContents, { ignoreAttributes: false }); + const parserOptions = { + ignoreAttributes: false + }; + const parser = new fast_xml_parser_1.XMLParser(parserOptions); + const json = parser.parse(curContents); if (typeof json.configuration === 'undefined') { throw new Error(`The provided NuGet.config seems invalid.`); } @@ -8274,636 +8278,20 @@ module.exports = opts => { /***/ }), -/***/ 5152: +/***/ 2603: /***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { "use strict"; -//parse Empty Node as self closing node -const buildOptions = (__nccwpck_require__(8280).buildOptions); -const defaultOptions = { - attributeNamePrefix: '@_', - attrNodeName: false, - textNodeName: '#text', - ignoreAttributes: true, - cdataTagName: false, - cdataPositionChar: '\\c', - format: false, - indentBy: ' ', - supressEmptyNode: false, - tagValueProcessor: function(a) { - return a; - }, - attrValueProcessor: function(a) { - return a; - }, -}; - -const props = [ - 'attributeNamePrefix', - 'attrNodeName', - 'textNodeName', - 'ignoreAttributes', - 'cdataTagName', - 'cdataPositionChar', - 'format', - 'indentBy', - 'supressEmptyNode', - 'tagValueProcessor', - 'attrValueProcessor', -]; - -function Parser(options) { - this.options = buildOptions(options, defaultOptions, props); - if (this.options.ignoreAttributes || this.options.attrNodeName) { - this.isAttribute = function(/*a*/) { - return false; - }; - } else { - this.attrPrefixLen = this.options.attributeNamePrefix.length; - this.isAttribute = isAttribute; - } - if (this.options.cdataTagName) { - this.isCDATA = isCDATA; - } else { - this.isCDATA = function(/*a*/) { - return false; - }; - } - this.replaceCDATAstr = replaceCDATAstr; - this.replaceCDATAarr = replaceCDATAarr; - - if (this.options.format) { - this.indentate = indentate; - this.tagEndChar = '>\n'; - this.newLine = '\n'; - } else { - this.indentate = function() { - return ''; - }; - this.tagEndChar = '>'; - this.newLine = ''; - } - - if (this.options.supressEmptyNode) { - this.buildTextNode = buildEmptyTextNode; - this.buildObjNode = buildEmptyObjNode; - } else { - this.buildTextNode = buildTextValNode; - this.buildObjNode = buildObjectNode; - } - - this.buildTextValNode = buildTextValNode; - this.buildObjectNode = buildObjectNode; -} - -Parser.prototype.parse = function(jObj) { - return this.j2x(jObj, 0).val; -}; - -Parser.prototype.j2x = function(jObj, level) { - let attrStr = ''; - let val = ''; - const keys = Object.keys(jObj); - const len = keys.length; - for (let i = 0; i < len; i++) { - const key = keys[i]; - if (typeof jObj[key] === 'undefined') { - // supress undefined node - } else if (jObj[key] === null) { - val += this.indentate(level) + '<' + key + '/' + this.tagEndChar; - } else if (jObj[key] instanceof Date) { - val += this.buildTextNode(jObj[key], key, '', level); - } else if (typeof jObj[key] !== 'object') { - //premitive type - const attr = this.isAttribute(key); - if (attr) { - attrStr += ' ' + attr + '="' + this.options.attrValueProcessor('' + jObj[key]) + '"'; - } else if (this.isCDATA(key)) { - if (jObj[this.options.textNodeName]) { - val += this.replaceCDATAstr(jObj[this.options.textNodeName], jObj[key]); - } else { - val += this.replaceCDATAstr('', jObj[key]); - } - } else { - //tag value - if (key === this.options.textNodeName) { - if (jObj[this.options.cdataTagName]) { - //value will added while processing cdata - } else { - val += this.options.tagValueProcessor('' + jObj[key]); - } - } else { - val += this.buildTextNode(jObj[key], key, '', level); - } - } - } else if (Array.isArray(jObj[key])) { - //repeated nodes - if (this.isCDATA(key)) { - val += this.indentate(level); - if (jObj[this.options.textNodeName]) { - val += this.replaceCDATAarr(jObj[this.options.textNodeName], jObj[key]); - } else { - val += this.replaceCDATAarr('', jObj[key]); - } - } else { - //nested nodes - const arrLen = jObj[key].length; - for (let j = 0; j < arrLen; j++) { - const item = jObj[key][j]; - if (typeof item === 'undefined') { - // supress undefined node - } else if (item === null) { - val += this.indentate(level) + '<' + key + '/' + this.tagEndChar; - } else if (typeof item === 'object') { - const result = this.j2x(item, level + 1); - val += this.buildObjNode(result.val, key, result.attrStr, level); - } else { - val += this.buildTextNode(item, key, '', level); - } - } - } - } else { - //nested node - if (this.options.attrNodeName && key === this.options.attrNodeName) { - const Ks = Object.keys(jObj[key]); - const L = Ks.length; - for (let j = 0; j < L; j++) { - attrStr += ' ' + Ks[j] + '="' + this.options.attrValueProcessor('' + jObj[key][Ks[j]]) + '"'; - } - } else { - const result = this.j2x(jObj[key], level + 1); - val += this.buildObjNode(result.val, key, result.attrStr, level); - } - } - } - return {attrStr: attrStr, val: val}; -}; - -function replaceCDATAstr(str, cdata) { - str = this.options.tagValueProcessor('' + str); - if (this.options.cdataPositionChar === '' || str === '') { - return str + ''); - } - return str + this.newLine; - } -} - -function buildObjectNode(val, key, attrStr, level) { - if (attrStr && !val.includes('<')) { - return ( - this.indentate(level) + - '<' + - key + - attrStr + - '>' + - val + - //+ this.newLine - // + this.indentate(level) - '' + - this.options.tagValueProcessor(val) + - ' { - -"use strict"; - -const char = function(a) { - return String.fromCharCode(a); -}; - -const chars = { - nilChar: char(176), - missingChar: char(201), - nilPremitive: char(175), - missingPremitive: char(200), - - emptyChar: char(178), - emptyValue: char(177), //empty Premitive - - boundryChar: char(179), - - objStart: char(198), - arrStart: char(204), - arrayEnd: char(185), -}; - -const charsArr = [ - chars.nilChar, - chars.nilPremitive, - chars.missingChar, - chars.missingPremitive, - chars.boundryChar, - chars.emptyChar, - chars.emptyValue, - chars.arrayEnd, - chars.objStart, - chars.arrStart, -]; - -const _e = function(node, e_schema, options) { - if (typeof e_schema === 'string') { - //premitive - if (node && node[0] && node[0].val !== undefined) { - return getValue(node[0].val, e_schema); - } else { - return getValue(node, e_schema); - } - } else { - const hasValidData = hasData(node); - if (hasValidData === true) { - let str = ''; - if (Array.isArray(e_schema)) { - //attributes can't be repeated. hence check in children tags only - str += chars.arrStart; - const itemSchema = e_schema[0]; - //var itemSchemaType = itemSchema; - const arr_len = node.length; - - if (typeof itemSchema === 'string') { - for (let arr_i = 0; arr_i < arr_len; arr_i++) { - const r = getValue(node[arr_i].val, itemSchema); - str = processValue(str, r); - } - } else { - for (let arr_i = 0; arr_i < arr_len; arr_i++) { - const r = _e(node[arr_i], itemSchema, options); - str = processValue(str, r); - } - } - str += chars.arrayEnd; //indicates that next item is not array item - } else { - //object - str += chars.objStart; - const keys = Object.keys(e_schema); - if (Array.isArray(node)) { - node = node[0]; - } - for (let i in keys) { - const key = keys[i]; - //a property defined in schema can be present either in attrsMap or children tags - //options.textNodeName will not present in both maps, take it's value from val - //options.attrNodeName will be present in attrsMap - let r; - if (!options.ignoreAttributes && node.attrsMap && node.attrsMap[key]) { - r = _e(node.attrsMap[key], e_schema[key], options); - } else if (key === options.textNodeName) { - r = _e(node.val, e_schema[key], options); - } else { - r = _e(node.child[key], e_schema[key], options); - } - str = processValue(str, r); - } - } - return str; - } else { - return hasValidData; - } - } -}; - -const getValue = function(a /*, type*/) { - switch (a) { - case undefined: - return chars.missingPremitive; - case null: - return chars.nilPremitive; - case '': - return chars.emptyValue; - default: - return a; - } -}; - -const processValue = function(str, r) { - if (!isAppChar(r[0]) && !isAppChar(str[str.length - 1])) { - str += chars.boundryChar; - } - return str + r; -}; - -const isAppChar = function(ch) { - return charsArr.indexOf(ch) !== -1; -}; - -function hasData(jObj) { - if (jObj === undefined) { - return chars.missingChar; - } else if (jObj === null) { - return chars.nilChar; - } else if ( - jObj.child && - Object.keys(jObj.child).length === 0 && - (!jObj.attrsMap || Object.keys(jObj.attrsMap).length === 0) - ) { - return chars.emptyChar; - } else { - return true; - } -} - -const x2j = __nccwpck_require__(6712); -const buildOptions = (__nccwpck_require__(8280).buildOptions); - -const convert2nimn = function(node, e_schema, options) { - options = buildOptions(options, x2j.defaultOptions, x2j.props); - return _e(node, e_schema, options); -}; - -exports.convert2nimn = convert2nimn; - - -/***/ }), - -/***/ 8270: -/***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { - -"use strict"; - - -const util = __nccwpck_require__(8280); - -const convertToJson = function(node, options) { - const jObj = {}; - - //when no child node or attr is present - if ((!node.child || util.isEmptyObject(node.child)) && (!node.attrsMap || util.isEmptyObject(node.attrsMap))) { - return util.isExist(node.val) ? node.val : ''; - } else { - //otherwise create a textnode if node has some text - if (util.isExist(node.val)) { - if (!(typeof node.val === 'string' && (node.val === '' || node.val === options.cdataPositionChar))) { - if(options.arrayMode === "strict"){ - jObj[options.textNodeName] = [ node.val ]; - }else{ - jObj[options.textNodeName] = node.val; - } - } - } - } - - util.merge(jObj, node.attrsMap, options.arrayMode); - - const keys = Object.keys(node.child); - for (let index = 0; index < keys.length; index++) { - var tagname = keys[index]; - if (node.child[tagname] && node.child[tagname].length > 1) { - jObj[tagname] = []; - for (var tag in node.child[tagname]) { - jObj[tagname].push(convertToJson(node.child[tagname][tag], options)); - } - } else { - if(options.arrayMode === true){ - const result = convertToJson(node.child[tagname][0], options) - if(typeof result === 'object') - jObj[tagname] = [ result ]; - else - jObj[tagname] = result; - }else if(options.arrayMode === "strict"){ - jObj[tagname] = [convertToJson(node.child[tagname][0], options) ]; - }else{ - jObj[tagname] = convertToJson(node.child[tagname][0], options); - } - } - } - - //add value - return jObj; -}; - -exports.convertToJson = convertToJson; - - -/***/ }), - -/***/ 6014: -/***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { - -"use strict"; - - -const util = __nccwpck_require__(8280); -const buildOptions = (__nccwpck_require__(8280).buildOptions); -const x2j = __nccwpck_require__(6712); - -//TODO: do it later -const convertToJsonString = function(node, options) { - options = buildOptions(options, x2j.defaultOptions, x2j.props); - - options.indentBy = options.indentBy || ''; - return _cToJsonStr(node, options, 0); -}; - -const _cToJsonStr = function(node, options, level) { - let jObj = '{'; - - //traver through all the children - const keys = Object.keys(node.child); - - for (let index = 0; index < keys.length; index++) { - var tagname = keys[index]; - if (node.child[tagname] && node.child[tagname].length > 1) { - jObj += '"' + tagname + '" : [ '; - for (var tag in node.child[tagname]) { - jObj += _cToJsonStr(node.child[tagname][tag], options) + ' , '; - } - jObj = jObj.substr(0, jObj.length - 1) + ' ] '; //remove extra comma in last - } else { - jObj += '"' + tagname + '" : ' + _cToJsonStr(node.child[tagname][0], options) + ' ,'; - } - } - util.merge(jObj, node.attrsMap); - //add attrsMap as new children - if (util.isEmptyObject(jObj)) { - return util.isExist(node.val) ? node.val : ''; - } else { - if (util.isExist(node.val)) { - if (!(typeof node.val === 'string' && (node.val === '' || node.val === options.cdataPositionChar))) { - jObj += '"' + options.textNodeName + '" : ' + stringval(node.val); - } - } - } - //add value - if (jObj[jObj.length - 1] === ',') { - jObj = jObj.substr(0, jObj.length - 2); - } - return jObj + '}'; -}; - -function stringval(v) { - if (v === true || v === false || !isNaN(v)) { - return v; - } else { - return '"' + v + '"'; - } -} - -function indentate(options, level) { - return options.indentBy.repeat(level); -} - -exports.convertToJsonString = convertToJsonString; - - -/***/ }), - -/***/ 7448: -/***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { - -"use strict"; - - -const nodeToJson = __nccwpck_require__(8270); -const xmlToNodeobj = __nccwpck_require__(6712); -const x2xmlnode = __nccwpck_require__(6712); -const buildOptions = (__nccwpck_require__(8280).buildOptions); const validator = __nccwpck_require__(1739); +const XMLParser = __nccwpck_require__(2380); +const XMLBuilder = __nccwpck_require__(660); -exports.parse = function(xmlData, options, validationOption) { - if( validationOption){ - if(validationOption === true) validationOption = {} - - const result = validator.validate(xmlData, validationOption); - if (result !== true) { - throw Error( result.err.msg) - } - } - options = buildOptions(options, x2xmlnode.defaultOptions, x2xmlnode.props); - const traversableObj = xmlToNodeobj.getTraversalObj(xmlData, options) - //print(traversableObj, " "); - return nodeToJson.convertToJson(traversableObj, options); -}; -exports.convertTonimn = __nccwpck_require__(1901).convert2nimn; -exports.getTraversalObj = xmlToNodeobj.getTraversalObj; -exports.convertToJson = nodeToJson.convertToJson; -exports.convertToJsonString = __nccwpck_require__(6014).convertToJsonString; -exports.validate = validator.validate; -exports.j2xParser = __nccwpck_require__(5152); -exports.parseToNimn = function(xmlData, schema, options) { - return exports.convertTonimn(exports.getTraversalObj(xmlData, options), schema, options); -}; - - -function print(xmlNode, indentation){ - if(xmlNode){ - console.log(indentation + "{") - console.log(indentation + " \"tagName\": \"" + xmlNode.tagname + "\", "); - if(xmlNode.parent){ - console.log(indentation + " \"parent\": \"" + xmlNode.parent.tagname + "\", "); - } - console.log(indentation + " \"val\": \"" + xmlNode.val + "\", "); - console.log(indentation + " \"attrs\": " + JSON.stringify(xmlNode.attrsMap,null,4) + ", "); - - if(xmlNode.child){ - console.log(indentation + "\"child\": {") - const indentation2 = indentation + indentation; - Object.keys(xmlNode.child).forEach( function(key) { - const node = xmlNode.child[key]; - - if(Array.isArray(node)){ - console.log(indentation + "\""+key+"\" :[") - node.forEach( function(item,index) { - //console.log(indentation + " \""+index+"\" : [") - print(item, indentation2); - }) - console.log(indentation + "],") - }else{ - console.log(indentation + " \""+key+"\" : {") - print(node, indentation2); - console.log(indentation + "},") - } - }); - console.log(indentation + "},") - } - console.log(indentation + "},") - } +module.exports = { + XMLParser: XMLParser, + XMLValidator: validator, + XMLBuilder: XMLBuilder } /***/ }), @@ -8924,6 +8312,7 @@ const getAllMatches = function(string, regex) { let match = regex.exec(string); while (match) { const allmatches = []; + allmatches.startIndex = regex.lastIndex - match[0].length; const len = match.length; for (let index = 0; index < len; index++) { allmatches.push(match[index]); @@ -8957,9 +8346,9 @@ exports.merge = function(target, a, arrayMode) { const keys = Object.keys(a); // will return an array of own properties const len = keys.length; //don't make it inline for (let i = 0; i < len; i++) { - if(arrayMode === 'strict'){ + if (arrayMode === 'strict') { target[keys[i]] = [ a[keys[i]] ]; - }else{ + } else { target[keys[i]] = a[keys[i]]; } } @@ -8980,22 +8369,6 @@ exports.getValue = function(v) { // const fakeCall = function(a) {return a;}; // const fakeCallNoReturn = function() {}; -exports.buildOptions = function(options, defaultOptions, props) { - var newOptions = {}; - if (!options) { - return defaultOptions; //if there are not options - } - - for (let i = 0; i < props.length; i++) { - if (options[props[i]] !== undefined) { - newOptions[props[i]] = options[props[i]]; - } else { - newOptions[props[i]] = defaultOptions[props[i]]; - } - } - return newOptions; -}; - exports.isName = isName; exports.getAllMatches = getAllMatches; exports.nameRegexp = nameRegexp; @@ -9013,13 +8386,12 @@ const util = __nccwpck_require__(8280); const defaultOptions = { allowBooleanAttributes: false, //A tag can have attributes without any value + unpairedTags: [] }; -const props = ['allowBooleanAttributes']; - //const tagsPattern = new RegExp("<\\/?([\\w:\\-_\.]+)\\s*\/?>","g"); exports.validate = function (xmlData, options) { - options = util.buildOptions(options, defaultOptions, props); + options = Object.assign({}, defaultOptions, options); //xmlData = xmlData.replace(/(\r\n|\n|\r)/gm,"");//make it single line //xmlData = xmlData.replace(/(^\s*<\?xml.*?\?>)/g,"");//Remove XML starting tag @@ -9034,19 +8406,20 @@ exports.validate = function (xmlData, options) { // check for byte order mark (BOM) xmlData = xmlData.substr(1); } - + for (let i = 0; i < xmlData.length; i++) { - if (xmlData[i] === '<') { + + if (xmlData[i] === '<' && xmlData[i+1] === '?') { + i+=2; + i = readPI(xmlData,i); + if (i.err) return i; + }else if (xmlData[i] === '<') { //starting of tag //read until you reach to '>' avoiding any '>' in attribute value - + let tagStartPos = i; i++; - if (xmlData[i] === '?') { - i = readPI(xmlData, ++i); - if (i.err) { - return i; - } - } else if (xmlData[i] === '!') { + + if (xmlData[i] === '!') { i = readCommentAndCDATA(xmlData, i); continue; } else { @@ -9079,7 +8452,7 @@ exports.validate = function (xmlData, options) { if (!validateTagName(tagName)) { let msg; if (tagName.trim().length === 0) { - msg = "There is an unnecessary space between tag name and backward slash ' 0) { - return getErrorObject('InvalidTag', "Closing tag '"+tagName+"' can't have attributes or invalid starting.", getLineNumberForPosition(xmlData, i)); + return getErrorObject('InvalidTag', "Closing tag '"+tagName+"' can't have attributes or invalid starting.", getLineNumberForPosition(xmlData, tagStartPos)); } else { const otg = tags.pop(); - if (tagName !== otg) { - return getErrorObject('InvalidTag', "Closing tag '"+otg+"' is expected inplace of '"+tagName+"'.", getLineNumberForPosition(xmlData, i)); + if (tagName !== otg.tagName) { + let openPos = getLineNumberForPosition(xmlData, otg.tagStartPos); + return getErrorObject('InvalidTag', + "Expected closing tag '"+otg.tagName+"' (opened in line "+openPos.line+", col "+openPos.col+") instead of closing tag '"+tagName+"'.", + getLineNumberForPosition(xmlData, tagStartPos)); } //when there are no more tags, we reached the root level. @@ -9134,8 +8511,10 @@ exports.validate = function (xmlData, options) { //if the root level has been reached before ... if (reachedRoot === true) { return getErrorObject('InvalidXml', 'Multiple possible root nodes found.', getLineNumberForPosition(xmlData, i)); + } else if(options.unpairedTags.indexOf(tagName) !== -1){ + //don't push into stack } else { - tags.push(tagName); + tags.push({tagName, tagStartPos}); } tagFound = true; } @@ -9149,7 +8528,10 @@ exports.validate = function (xmlData, options) { i++; i = readCommentAndCDATA(xmlData, i); continue; - } else { + } else if (xmlData[i+1] === '?') { + i = readPI(xmlData, ++i); + if (i.err) return i; + } else{ break; } } else if (xmlData[i] === '&') { @@ -9157,6 +8539,10 @@ exports.validate = function (xmlData, options) { if (afterAmp == -1) return getErrorObject('InvalidChar', "char '&' is not expected.", getLineNumberForPosition(xmlData, i)); i = afterAmp; + }else{ + if (reachedRoot === true && !isWhiteSpace(xmlData[i])) { + return getErrorObject('InvalidXml', "Extra text at the end", getLineNumberForPosition(xmlData, i)); + } } } //end of reading tag text value if (xmlData[i] === '<') { @@ -9164,7 +8550,7 @@ exports.validate = function (xmlData, options) { } } } else { - if (xmlData[i] === ' ' || xmlData[i] === '\t' || xmlData[i] === '\n' || xmlData[i] === '\r') { + if ( isWhiteSpace(xmlData[i])) { continue; } return getErrorObject('InvalidChar', "char '"+xmlData[i]+"' is not expected.", getLineNumberForPosition(xmlData, i)); @@ -9173,24 +8559,31 @@ exports.validate = function (xmlData, options) { if (!tagFound) { return getErrorObject('InvalidXml', 'Start tag expected.', 1); - } else if (tags.length > 0) { - return getErrorObject('InvalidXml', "Invalid '"+JSON.stringify(tags, null, 4).replace(/\r?\n/g, '')+"' found.", 1); + }else if (tags.length == 1) { + return getErrorObject('InvalidTag', "Unclosed tag '"+tags[0].tagName+"'.", getLineNumberForPosition(xmlData, tags[0].tagStartPos)); + }else if (tags.length > 0) { + return getErrorObject('InvalidXml', "Invalid '"+ + JSON.stringify(tags.map(t => t.tagName), null, 4).replace(/\r?\n/g, '')+ + "' found.", {line: 1, col: 1}); } return true; }; +function isWhiteSpace(char){ + return char === ' ' || char === '\t' || char === '\n' || char === '\r'; +} /** * Read Processing insstructions and skip * @param {*} xmlData * @param {*} i */ function readPI(xmlData, i) { - var start = i; + const start = i; for (; i < xmlData.length; i++) { if (xmlData[i] == '?' || xmlData[i] == ' ') { //tagname - var tagname = xmlData.substr(start, i - start); + const tagname = xmlData.substr(start, i - start); if (i > 5 && tagname === 'xml') { return getErrorObject('InvalidXml', 'XML declaration allowed only at the start of the document.', getLineNumberForPosition(xmlData, i)); } else if (xmlData[i] == '?' && xmlData[i + 1] == '>') { @@ -9256,8 +8649,8 @@ function readCommentAndCDATA(xmlData, i) { return i; } -var doubleQuote = '"'; -var singleQuote = "'"; +const doubleQuote = '"'; +const singleQuote = "'"; /** * Keep reading xmlData until '<' is found outside the attribute value. @@ -9274,7 +8667,6 @@ function readAttributeStr(xmlData, i) { startChar = xmlData[i]; } else if (startChar !== xmlData[i]) { //if vaue is enclosed with double quote then single quotes are allowed inside the value and vice versa - continue; } else { startChar = ''; } @@ -9315,23 +8707,25 @@ function validateAttributeString(attrStr, options) { for (let i = 0; i < matches.length; i++) { if (matches[i][1].length === 0) { //nospace before attribute name: a="sd"b="saf" - return getErrorObject('InvalidAttr', "Attribute '"+matches[i][2]+"' has no space in starting.", getPositionFromMatch(attrStr, matches[i][0])) + return getErrorObject('InvalidAttr', "Attribute '"+matches[i][2]+"' has no space in starting.", getPositionFromMatch(matches[i])) + } else if (matches[i][3] !== undefined && matches[i][4] === undefined) { + return getErrorObject('InvalidAttr', "Attribute '"+matches[i][2]+"' is without value.", getPositionFromMatch(matches[i])); } else if (matches[i][3] === undefined && !options.allowBooleanAttributes) { //independent attribute: ab - return getErrorObject('InvalidAttr', "boolean attribute '"+matches[i][2]+"' is not allowed.", getPositionFromMatch(attrStr, matches[i][0])); + return getErrorObject('InvalidAttr', "boolean attribute '"+matches[i][2]+"' is not allowed.", getPositionFromMatch(matches[i])); } /* else if(matches[i][6] === undefined){//attribute without value: ab= return { err: { code:"InvalidAttr",msg:"attribute " + matches[i][2] + " has no value assigned."}}; } */ const attrName = matches[i][2]; if (!validateAttrName(attrName)) { - return getErrorObject('InvalidAttr', "Attribute '"+attrName+"' is an invalid name.", getPositionFromMatch(attrStr, matches[i][0])); + return getErrorObject('InvalidAttr', "Attribute '"+attrName+"' is an invalid name.", getPositionFromMatch(matches[i])); } if (!attrNames.hasOwnProperty(attrName)) { //check for duplicate attribute. attrNames[attrName] = 1; } else { - return getErrorObject('InvalidAttr', "Attribute '"+attrName+"' is repeated.", getPositionFromMatch(attrStr, matches[i][0])); + return getErrorObject('InvalidAttr', "Attribute '"+attrName+"' is repeated.", getPositionFromMatch(matches[i])); } } @@ -9378,7 +8772,8 @@ function getErrorObject(code, message, lineNumber) { err: { code: code, msg: message, - line: lineNumber, + line: lineNumber.line || lineNumber, + col: lineNumber.col, }, }; } @@ -9395,52 +8790,587 @@ function validateTagName(tagname) { //this function returns the line number for the character at the given index function getLineNumberForPosition(xmlData, index) { - var lines = xmlData.substring(0, index).split(/\r?\n/); - return lines.length; + const lines = xmlData.substring(0, index).split(/\r?\n/); + return { + line: lines.length, + + // column number is last line's length + 1, because column numbering starts at 1: + col: lines[lines.length - 1].length + 1 + }; } -//this function returns the position of the last character of match within attrStr -function getPositionFromMatch(attrStr, match) { - return attrStr.indexOf(match) + match.length; +//this function returns the position of the first character of match within attrStr +function getPositionFromMatch(match) { + return match.startIndex + match[1].length; } /***/ }), -/***/ 9539: -/***/ ((module) => { +/***/ 660: +/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { "use strict"; +//parse Empty Node as self closing node +const buildFromOrderedJs = __nccwpck_require__(2462); -module.exports = function(tagname, parent, val) { - this.tagname = tagname; - this.parent = parent; - this.child = {}; //child tags - this.attrsMap = {}; //attributes map - this.val = val; //text only - this.addChild = function(child) { - if (Array.isArray(this.child[child.tagname])) { - //already presents - this.child[child.tagname].push(child); - } else { - this.child[child.tagname] = [child]; - } - }; +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, }; +function Builder(options) { + this.options = Object.assign({}, defaultOptions, options); + if (this.options.ignoreAttributes || this.options.attributesGroupName) { + this.isAttribute = function(/*a*/) { + return false; + }; + } else { + 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 = ''; + } + + if (this.options.suppressEmptyNode) { + this.buildTextNode = buildEmptyTextNode; + this.buildObjNode = buildEmptyObjNode; + } else { + this.buildTextNode = buildTextValNode; + this.buildObjNode = buildObjectNode; + } + + this.buildTextValNode = buildTextValNode; + this.buildObjectNode = buildObjectNode; + + this.replaceEntitiesValue = replaceEntitiesValue; + this.buildAttrPairStr = buildAttrPairStr; +} + +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 + } + } + return this.j2x(jObj, 0).val; + } +}; + +Builder.prototype.j2x = function(jObj, level) { + let attrStr = ''; + let val = ''; + for (let key in jObj) { + if (typeof jObj[key] === 'undefined') { + // supress undefined node + } else if (jObj[key] === 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 (jObj[key] instanceof Date) { + val += this.buildTextNode(jObj[key], key, '', level); + } else if (typeof jObj[key] !== 'object') { + //premitive type + const attr = this.isAttribute(key); + if (attr) { + attrStr += this.buildAttrPairStr(attr, '' + jObj[key]); + }else { + //tag value + if (key === this.options.textNodeName) { + let newval = this.options.tagValueProcessor(key, '' + jObj[key]); + val += this.replaceEntitiesValue(newval); + } else { + val += this.buildTextNode(jObj[key], key, '', level); + } + } + } else if (Array.isArray(jObj[key])) { + //repeated nodes + const arrLen = jObj[key].length; + 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') { + val += this.processTextOrObjNode(item, key, level) + } else { + val += this.buildTextNode(item, key, '', level); + } + } + } 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]]); + } + } else { + val += this.processTextOrObjNode(jObj[key], key, level) + } + } + } + return {attrStr: attrStr, val: val}; +}; + +function buildAttrPairStr(attrName, val){ + 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) { + const result = this.j2x(object, level + 1); + if (object[this.options.textNodeName] !== undefined && Object.keys(object).length === 1) { + return this.buildTextNode(object[this.options.textNodeName], key, result.attrStr, level); + } else { + return this.buildObjNode(result.val, key, result.attrStr, level); + } +} + +function buildObjectNode(val, key, attrStr, level) { + let tagEndExp = '' + val + tagEndExp ); + } else if (this.options.commentPropName !== false && key === this.options.commentPropName && piClosingChar.length === 0) { + return this.indentate(level) + `` + this.newLine; + }else { + return ( + this.indentate(level) + '<' + key + attrStr + piClosingChar + this.tagEndChar + + val + + this.indentate(level) + tagEndExp ); + } +} + +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; + } +} + +function buildTextValNode(val, key, attrStr, level) { + if (this.options.cdataPropName !== false && key === this.options.cdataPropName) { + return this.indentate(level) + `` + this.newLine; + }else if (this.options.commentPropName !== false && key === this.options.commentPropName) { + return this.indentate(level) + `` + this.newLine; + }else{ + let textValue = this.options.tagValueProcessor(key, val); + textValue = this.replaceEntitiesValue(textValue); + + if( textValue === '' && this.options.unpairedTags.indexOf(key) !== -1){ //unpaired + if(this.options.suppressUnpairedNode){ + return this.indentate(level) + '<' + key + this.tagEndChar; + }else{ + return this.indentate(level) + '<' + key + "/" + this.tagEndChar; + } + } else{ + return ( + this.indentate(level) + '<' + key + attrStr + '>' + + textValue + + ' 0 && this.options.processEntities){ + for (let i=0; i { +/***/ 2462: +/***/ ((module) => { + +const EOL = "\n"; + +/** + * + * @param {array} jArray + * @param {any} options + * @returns + */ +function toXml(jArray, options){ + return arrToStr( jArray, options, "", 0); +} + +function arrToStr(arr, options, jPath, level){ + let xmlStr = ""; + + let indentation = ""; + if(options.format && options.indentBy.length > 0){//TODO: this logic can be avoided for each call + indentation = EOL + "" + options.indentBy.repeat(level); + } + + for (let i = 0; i < arr.length; i++) { + const tagObj = arr[i]; + const tagName = propName(tagObj); + let newJPath = ""; + if(jPath.length === 0) newJPath = tagName + else newJPath = `${jPath}.${tagName}`; + + if(tagName === options.textNodeName){ + let tagText = tagObj[tagName]; + if(!isStopNode(newJPath, options)){ + tagText = options.tagValueProcessor( tagName, tagText); + tagText = replaceEntitiesValue(tagText, options); + } + xmlStr += indentation + tagText; + continue; + }else if( tagName === options.cdataPropName){ + xmlStr += indentation + ``; + continue; + }else if( tagName === options.commentPropName){ + xmlStr += indentation + ``; + continue; + }else if( tagName[0] === "?"){ + const attStr = attr_to_str(tagObj[":@"], options); + 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}?>`; + continue; + } + const attStr = attr_to_str(tagObj[":@"], options); + let tagStart = indentation + `<${tagName}${attStr}`; + let tagValue = arrToStr(tagObj[tagName], options, newJPath, level + 1); + 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{ + //TODO: node with only text value should not parse the text value in next line + xmlStr += tagStart + `>${tagValue}${indentation}` ; + } + } + + return xmlStr; +} + +function propName(obj){ + const keys = Object.keys(obj); + for (let i = 0; i < keys.length; i++) { + const key = keys[i]; + if(key !== ":@") return key; + } + } + +function attr_to_str(attrMap, options){ + let attrStr = ""; + if(attrMap && !options.ignoreAttributes){ + for (let attr in attrMap){ + let 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 isStopNode(jPath, options){ + jPath = jPath.substr(0,jPath.length - options.textNodeName.length - 1); + let tagName = jPath.substr(jPath.lastIndexOf(".") + 1); + for(let index in options.stopNodes){ + if(options.stopNodes[index] === jPath || options.stopNodes[index] === "*."+tagName) 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; + } +module.exports = toXml; + +/***/ }), + +/***/ 6072: +/***/ ((module) => { + +//TODO: handle comments +function readDocType(xmlData, i){ + + const entities = {}; + if( xmlData[i + 3] === 'O' && + xmlData[i + 4] === 'C' && + xmlData[i + 5] === 'T' && + xmlData[i + 6] === 'Y' && + xmlData[i + 7] === 'P' && + xmlData[i + 8] === 'E') + { + i = i+9; + let angleBracketsCount = 1; + let hasBody = false, entity = false, comment = false; + let exp = ""; + for(;i') { + if(comment){ + if( xmlData[i - 1] === "-" && xmlData[i - 2] === "-"){ + comment = false; + }else{ + throw new Error(`Invalid XML comment in DOCTYPE`); + } + }else if(entity){ + parseEntityExp(exp, entities); + entity = false; + } + angleBracketsCount--; + if (angleBracketsCount === 0) { + break; + } + }else if( xmlData[i] === '['){ + hasBody = true; + }else{ + exp += xmlData[i]; + } + } + if(angleBracketsCount !== 0){ + throw new Error(`Unclosed DOCTYPE`); + } + }else{ + throw new Error(`Invalid Tag instead of DOCTYPE`); + } + return {entities, i}; +} + +const entityRegex = RegExp("^\\s([a-zA-z0-0]+)[ \t](['\"])([^&]+)\\2"); +function parseEntityExp(exp, entities){ + const match = entityRegex.exec(exp); + if(match){ + entities[ match[1] ] = { + regx : RegExp( `&${match[1]};`,"g"), + val: match[3] + }; + } +} +module.exports = readDocType; + +/***/ }), + +/***/ 6993: +/***/ ((__unused_webpack_module, exports) => { + + +const defaultOptions = { + preserveOrder: false, + attributeNamePrefix: '@_', + attributesGroupName: false, + textNodeName: '#text', + ignoreAttributes: true, + removeNSPrefix: false, // remove NS from tag name or attribute name if true + allowBooleanAttributes: false, //a tag can have attributes without any value + //ignoreRootElement : false, + parseTagValue: true, + parseAttributeValue: false, + trimValues: true, //Trim string values of tag and attributes + cdataPropName: false, + numberParseOptions: { + hex: true, + leadingZeros: true + }, + tagValueProcessor: function(tagName, val) { + return val; + }, + attributeValueProcessor: function(attrName, val) { + return val; + }, + stopNodes: [], //nested tags will not be parsed even for errors + alwaysCreateTextNode: false, + isArray: () => false, + commentPropName: false, + unpairedTags: [], + processEntities: true, + htmlEntities: false, + ignoreDeclaration: false, + ignorePiTags: false, + transformTagName: false, +}; + +const buildOptions = function(options) { + return Object.assign({}, defaultOptions, options); +}; + +exports.buildOptions = buildOptions; +exports.defaultOptions = defaultOptions; + +/***/ }), + +/***/ 5832: +/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { "use strict"; +///@ts-check const util = __nccwpck_require__(8280); -const buildOptions = (__nccwpck_require__(8280).buildOptions); -const xmlNode = __nccwpck_require__(9539); +const xmlNode = __nccwpck_require__(7462); +const readDocType = __nccwpck_require__(6072); +const toNumber = __nccwpck_require__(4526); + const regx = '<((!\\[CDATA\\[([\\s\\S]*?)(]]>))|((NAME:)?(NAME))([^>]*)>|((\\/)(NAME)\\s*>))([^<]*)' .replace(/NAME/g, util.nameRegexp); @@ -9448,80 +9378,98 @@ const regx = //const tagsRegx = new RegExp("<(\\/?[\\w:\\-\._]+)([^>]*)>(\\s*"+cdataRegx+")*([^<]+)?","g"); //const tagsRegx = new RegExp("<(\\/?)((\\w*:)?([\\w:\\-\._]+))([^>]*)>([^<]*)("+cdataRegx+"([^<]*))*([^<]+)?","g"); -//polyfill -if (!Number.parseInt && window.parseInt) { - Number.parseInt = window.parseInt; -} -if (!Number.parseFloat && window.parseFloat) { - Number.parseFloat = window.parseFloat; -} - -const defaultOptions = { - attributeNamePrefix: '@_', - attrNodeName: false, - textNodeName: '#text', - ignoreAttributes: true, - ignoreNameSpace: false, - allowBooleanAttributes: false, //a tag can have attributes without any value - //ignoreRootElement : false, - parseNodeValue: true, - parseAttributeValue: false, - arrayMode: false, - trimValues: true, //Trim string values of tag and attributes - cdataTagName: false, - cdataPositionChar: '\\c', - tagValueProcessor: function(a, tagName) { - return a; - }, - attrValueProcessor: function(a, attrName) { - return a; - }, - stopNodes: [] - //decodeStrict: false, -}; - -exports.defaultOptions = defaultOptions; - -const props = [ - 'attributeNamePrefix', - 'attrNodeName', - 'textNodeName', - 'ignoreAttributes', - 'ignoreNameSpace', - 'allowBooleanAttributes', - 'parseNodeValue', - 'parseAttributeValue', - 'arrayMode', - 'trimValues', - 'cdataTagName', - 'cdataPositionChar', - 'tagValueProcessor', - 'attrValueProcessor', - 'parseTrueNumberOnly', - 'stopNodes' -]; -exports.props = props; - -/** - * Trim -> valueProcessor -> parse value - * @param {string} tagName - * @param {string} val - * @param {object} options - */ -function processTagValue(tagName, val, options) { - if (val) { - if (options.trimValues) { - val = val.trim(); - } - val = options.tagValueProcessor(val, tagName); - val = parseValue(val, options.parseNodeValue, options.parseTrueNumberOnly); +class OrderedObjParser{ + constructor(options){ + this.options = options; + this.currentNode = null; + this.tagsNodeStack = []; + this.docTypeEntities = {}; + this.lastEntities = { + "amp" : { regex: /&(amp|#38|#x26);/g, val : "&"}, + "apos" : { regex: /&(apos|#39|#x27);/g, val : "'"}, + "gt" : { regex: /&(gt|#62|#x3E);/g, val : ">"}, + "lt" : { regex: /&(lt|#60|#x3C);/g, val : "<"}, + "quot" : { regex: /&(quot|#34|#x22);/g, val : "\""}, + }; + this.htmlEntities = { + "space": { regex: /&(nbsp|#160);/g, val: " " }, + // "lt" : { regex: /&(lt|#60);/g, val: "<" }, + // "gt" : { regex: /&(gt|#62);/g, val: ">" }, + // "amp" : { regex: /&(amp|#38);/g, val: "&" }, + // "quot" : { regex: /&(quot|#34);/g, val: "\"" }, + // "apos" : { regex: /&(apos|#39);/g, val: "'" }, + "cent" : { regex: /&(cent|#162);/g, val: "¢" }, + "pound" : { regex: /&(pound|#163);/g, val: "£" }, + "yen" : { regex: /&(yen|#165);/g, val: "¥" }, + "euro" : { regex: /&(euro|#8364);/g, val: "€" }, + "copyright" : { regex: /&(copy|#169);/g, val: "©" }, + "reg" : { regex: /&(reg|#174);/g, val: "®" }, + "inr" : { regex: /&(inr|#8377);/g, val: "₹" }, + }; + this.addExternalEntities = addExternalEntities; + this.parseXml = parseXml; + this.parseTextData = parseTextData; + this.resolveNameSpace = resolveNameSpace; + this.buildAttributesMap = buildAttributesMap; + this.isItStopNode = isItStopNode; + this.replaceEntitiesValue = replaceEntitiesValue; + this.readStopNodeData = readStopNodeData; + this.saveTextToParentTag = saveTextToParentTag; } - return val; } -function resolveNameSpace(tagname, options) { - if (options.ignoreNameSpace) { +function addExternalEntities(externalEntities){ + const entKeys = Object.keys(externalEntities); + for (let i = 0; i < entKeys.length; i++) { + const ent = entKeys[i]; + this.lastEntities[ent] = { + regex: new RegExp("&"+ent+";","g"), + val : externalEntities[ent] + } + } +} + +/** + * @param {string} val + * @param {string} tagName + * @param {string} jPath + * @param {boolean} dontTrim + * @param {boolean} hasAttributes + * @param {boolean} isLeafNode + * @param {boolean} escapeEntities + */ +function parseTextData(val, tagName, jPath, dontTrim, hasAttributes, isLeafNode, escapeEntities) { + if (val !== undefined) { + if (this.options.trimValues && !dontTrim) { + val = val.trim(); + } + if(val.length > 0){ + if(!escapeEntities) val = this.replaceEntitiesValue(val); + + const newval = this.options.tagValueProcessor(tagName, val, jPath, hasAttributes, isLeafNode); + if(newval === null || newval === undefined){ + //don't parse + return val; + }else if(typeof newval !== typeof val || newval !== val){ + //overwrite + return newval; + }else if(this.options.trimValues){ + return parseValue(val, this.options.parseTagValue, this.options.numberParseOptions); + }else{ + const trimmedVal = val.trim(); + if(trimmedVal === val){ + return parseValue(val, this.options.parseTagValue, this.options.numberParseOptions); + }else{ + return val; + } + } + } + } +} + +function resolveNameSpace(tagname) { + if (this.options.removeNSPrefix) { const tags = tagname.split(':'); const prefix = tagname.charAt(0) === '/' ? '/' : ''; if (tags[0] === 'xmlns') { @@ -9534,232 +9482,334 @@ function resolveNameSpace(tagname, options) { return tagname; } -function parseValue(val, shouldParse, parseTrueNumberOnly) { - if (shouldParse && typeof val === 'string') { - let parsed; - if (val.trim() === '' || isNaN(val)) { - parsed = val === 'true' ? true : val === 'false' ? false : val; - } else { - if (val.indexOf('0x') !== -1) { - //support hexa decimal - parsed = Number.parseInt(val, 16); - } else if (val.indexOf('.') !== -1) { - parsed = Number.parseFloat(val); - val = val.replace(/\.?0+$/, ""); - } else { - parsed = Number.parseInt(val, 10); - } - if (parseTrueNumberOnly) { - parsed = String(parsed) === val ? parsed : val; - } - } - return parsed; - } else { - if (util.isExist(val)) { - return val; - } else { - return ''; - } - } -} - //TODO: change regex to capture NS //const attrsRegx = new RegExp("([\\w\\-\\.\\:]+)\\s*=\\s*(['\"])((.|\n)*?)\\2","gm"); -const attrsRegx = new RegExp('([^\\s=]+)\\s*(=\\s*([\'"])(.*?)\\3)?', 'g'); +const attrsRegx = new RegExp('([^\\s=]+)\\s*(=\\s*([\'"])([\\s\\S]*?)\\3)?', 'gm'); -function buildAttributesMap(attrStr, options) { - if (!options.ignoreAttributes && typeof attrStr === 'string') { - attrStr = attrStr.replace(/\r?\n/g, ' '); +function buildAttributesMap(attrStr, jPath) { + if (!this.options.ignoreAttributes && typeof attrStr === 'string') { + // attrStr = attrStr.replace(/\r?\n/g, ' '); //attrStr = attrStr || attrStr.trim(); const matches = util.getAllMatches(attrStr, attrsRegx); const len = matches.length; //don't make it inline const attrs = {}; for (let i = 0; i < len; i++) { - const attrName = resolveNameSpace(matches[i][1], options); + const attrName = this.resolveNameSpace(matches[i][1]); + let oldVal = matches[i][4]; + const aName = this.options.attributeNamePrefix + attrName; if (attrName.length) { - if (matches[i][4] !== undefined) { - if (options.trimValues) { - matches[i][4] = matches[i][4].trim(); + if (oldVal !== undefined) { + if (this.options.trimValues) { + oldVal = oldVal.trim(); } - matches[i][4] = options.attrValueProcessor(matches[i][4], attrName); - attrs[options.attributeNamePrefix + attrName] = parseValue( - matches[i][4], - options.parseAttributeValue, - options.parseTrueNumberOnly - ); - } else if (options.allowBooleanAttributes) { - attrs[options.attributeNamePrefix + attrName] = true; + oldVal = this.replaceEntitiesValue(oldVal); + const newVal = this.options.attributeValueProcessor(attrName, oldVal, jPath); + if(newVal === null || newVal === undefined){ + //don't parse + attrs[aName] = oldVal; + }else if(typeof newVal !== typeof oldVal || newVal !== oldVal){ + //overwrite + attrs[aName] = newVal; + }else{ + //parse + attrs[aName] = parseValue( + oldVal, + this.options.parseAttributeValue, + this.options.numberParseOptions + ); + } + } else if (this.options.allowBooleanAttributes) { + attrs[aName] = true; } } } if (!Object.keys(attrs).length) { return; } - if (options.attrNodeName) { + if (this.options.attributesGroupName) { const attrCollection = {}; - attrCollection[options.attrNodeName] = attrs; + attrCollection[this.options.attributesGroupName] = attrs; return attrCollection; } return attrs; } } -const getTraversalObj = function(xmlData, options) { - xmlData = xmlData.replace(/(\r\n)|\n/, " "); - options = buildOptions(options, defaultOptions, props); +const parseXml = function(xmlData) { + xmlData = xmlData.replace(/\r\n?/g, "\n"); //TODO: remove this line const xmlObj = new xmlNode('!xml'); let currentNode = xmlObj; let textData = ""; - -//function match(xmlData){ - for(let i=0; i< xmlData.length; i++){ + let jPath = ""; + for(let i=0; i< xmlData.length; i++){//for each char in XML data const ch = xmlData[i]; if(ch === '<'){ + // const nextIndex = i+1; + // const _2ndChar = xmlData[nextIndex]; if( xmlData[i+1] === '/') {//Closing Tag const closeIndex = findClosingIndex(xmlData, ">", i, "Closing Tag is not closed.") let tagName = xmlData.substring(i+2,closeIndex).trim(); - if(options.ignoreNameSpace){ + if(this.options.removeNSPrefix){ const colonIndex = tagName.indexOf(":"); if(colonIndex !== -1){ tagName = tagName.substr(colonIndex+1); } } - /* if (currentNode.parent) { - currentNode.parent.val = util.getValue(currentNode.parent.val) + '' + processTagValue2(tagName, textData , options); - } */ - if(currentNode){ - if(currentNode.val){ - currentNode.val = util.getValue(currentNode.val) + '' + processTagValue(tagName, textData , options); - }else{ - currentNode.val = processTagValue(tagName, textData , options); - } + if(this.options.transformTagName) { + tagName = this.options.transformTagName(tagName); } - if (options.stopNodes.length && options.stopNodes.includes(currentNode.tagname)) { - currentNode.child = [] - if (currentNode.attrsMap == undefined) { currentNode.attrsMap = {}} - currentNode.val = xmlData.substr(currentNode.startIndex + 1, i - currentNode.startIndex - 1) + if(currentNode){ + textData = this.saveTextToParentTag(textData, currentNode, jPath); } - currentNode = currentNode.parent; + + jPath = jPath.substr(0, jPath.lastIndexOf(".")); + + currentNode = this.tagsNodeStack.pop();//avoid recurssion, set the parent tag scope textData = ""; i = closeIndex; } else if( xmlData[i+1] === '?') { - i = findClosingIndex(xmlData, "?>", i, "Pi Tag is not closed.") - } else if(xmlData.substr(i + 1, 3) === '!--') { - i = findClosingIndex(xmlData, "-->", i, "Comment is not closed.") - } else if( xmlData.substr(i + 1, 2) === '!D') { - const closeIndex = findClosingIndex(xmlData, ">", i, "DOCTYPE is not closed.") - const tagExp = xmlData.substring(i, closeIndex); - if(tagExp.indexOf("[") >= 0){ - i = xmlData.indexOf("]>", i) + 1; + + let tagData = readTagExp(xmlData,i, false, "?>"); + if(!tagData) throw new Error("Pi Tag is not closed."); + + textData = this.saveTextToParentTag(textData, currentNode, jPath); + if( (this.options.ignoreDeclaration && tagData.tagName === "?xml") || this.options.ignorePiTags){ + }else{ - i = closeIndex; + + const childNode = new xmlNode(tagData.tagName); + childNode.add(this.options.textNodeName, ""); + + if(tagData.tagName !== tagData.tagExp && tagData.attrExpPresent){ + childNode[":@"] = this.buildAttributesMap(tagData.tagExp, jPath); + } + currentNode.addChild(childNode); + } + + + i = tagData.closeIndex + 1; + } else if(xmlData.substr(i + 1, 3) === '!--') { + const endIndex = findClosingIndex(xmlData, "-->", i+4, "Comment is not closed.") + if(this.options.commentPropName){ + const comment = xmlData.substring(i + 4, endIndex - 2); + + textData = this.saveTextToParentTag(textData, currentNode, jPath); + + currentNode.add(this.options.commentPropName, [ { [this.options.textNodeName] : comment } ]); + } + i = endIndex; + } else if( xmlData.substr(i + 1, 2) === '!D') { + const result = readDocType(xmlData, i); + this.docTypeEntities = result.entities; + i = result.i; }else if(xmlData.substr(i + 1, 2) === '![') { - const closeIndex = findClosingIndex(xmlData, "]]>", i, "CDATA is not closed.") - 2 + const closeIndex = findClosingIndex(xmlData, "]]>", i, "CDATA is not closed.") - 2; const tagExp = xmlData.substring(i + 9,closeIndex); - //considerations - //1. CDATA will always have parent node - //2. A tag with CDATA is not a leaf node so it's value would be string type. - if(textData){ - currentNode.val = util.getValue(currentNode.val) + '' + processTagValue(currentNode.tagname, textData , options); - textData = ""; - } + textData = this.saveTextToParentTag(textData, currentNode, jPath); - if (options.cdataTagName) { - //add cdata node - const childNode = new xmlNode(options.cdataTagName, currentNode, tagExp); - currentNode.addChild(childNode); - //for backtracking - currentNode.val = util.getValue(currentNode.val) + options.cdataPositionChar; - //add rest value to parent node - if (tagExp) { - childNode.val = tagExp; - } - } else { - currentNode.val = (currentNode.val || '') + (tagExp || ''); + //cdata should be set even if it is 0 length string + if(this.options.cdataPropName){ + // let val = this.parseTextData(tagExp, this.options.cdataPropName, jPath + "." + this.options.cdataPropName, true, false, true); + // if(!val) val = ""; + currentNode.add(this.options.cdataPropName, [ { [this.options.textNodeName] : tagExp } ]); + }else{ + let val = this.parseTextData(tagExp, currentNode.tagname, jPath, true, false, true); + if(val == undefined) val = ""; + currentNode.add(this.options.textNodeName, val); } - + i = closeIndex + 2; }else {//Opening tag - const result = closingIndexForOpeningTag(xmlData, i+1) - let tagExp = result.data; - const closeIndex = result.index; - const separatorIndex = tagExp.indexOf(" "); - let tagName = tagExp; - if(separatorIndex !== -1){ - tagName = tagExp.substr(0, separatorIndex).trimRight(); - tagExp = tagExp.substr(separatorIndex + 1); - } + let result = readTagExp(xmlData,i, this. options.removeNSPrefix); + let tagName= result.tagName; + let tagExp = result.tagExp; + let attrExpPresent = result.attrExpPresent; + let closeIndex = result.closeIndex; - if(options.ignoreNameSpace){ - const colonIndex = tagName.indexOf(":"); - if(colonIndex !== -1){ - tagName = tagName.substr(colonIndex+1); - } + if (this.options.transformTagName) { + tagName = this.options.transformTagName(tagName); } - - //save text to parent node + + //save text as child node if (currentNode && textData) { if(currentNode.tagname !== '!xml'){ - currentNode.val = util.getValue(currentNode.val) + '' + processTagValue( currentNode.tagname, textData, options); + //when nested tag is found + textData = this.saveTextToParentTag(textData, currentNode, jPath, false); } } - if(tagExp.length > 0 && tagExp.lastIndexOf("/") === tagExp.length - 1){//selfClosing tag - - if(tagName[tagName.length - 1] === "/"){ //remove trailing '/' - tagName = tagName.substr(0, tagName.length - 1); - tagExp = tagName; - }else{ - tagExp = tagExp.substr(0, tagExp.length - 1); - } - - const childNode = new xmlNode(tagName, currentNode, ''); - if(tagName !== tagExp){ - childNode.attrsMap = buildAttributesMap(tagExp, options); - } - currentNode.addChild(childNode); - }else{//opening tag - - const childNode = new xmlNode( tagName, currentNode ); - if (options.stopNodes.length && options.stopNodes.includes(childNode.tagname)) { - childNode.startIndex=closeIndex; - } - if(tagName !== tagExp){ - childNode.attrsMap = buildAttributesMap(tagExp, options); - } - currentNode.addChild(childNode); - currentNode = childNode; + if(tagName !== xmlObj.tagname){ + jPath += jPath ? "." + tagName : tagName; + } + + //check if last tag was unpaired tag + const lastTag = currentNode; + if(lastTag && this.options.unpairedTags.indexOf(lastTag.tagname) !== -1 ){ + currentNode = this.tagsNodeStack.pop(); + } + + if (this.isItStopNode(this.options.stopNodes, jPath, tagName)) { //TODO: namespace + let tagContent = ""; + //self-closing tag + if(tagExp.length > 0 && tagExp.lastIndexOf("/") === tagExp.length - 1){ + i = result.closeIndex; + } + //boolean tag + else if(this.options.unpairedTags.indexOf(tagName) !== -1){ + i = result.closeIndex; + } + //normal tag + else{ + //read until closing tag is found + const result = this.readStopNodeData(xmlData, tagName, closeIndex + 1); + if(!result) throw new Error(`Unexpected end of ${tagName}`); + i = result.i; + tagContent = result.tagContent; + } + + const childNode = new xmlNode(tagName); + if(tagName !== tagExp && attrExpPresent){ + childNode[":@"] = this.buildAttributesMap(tagExp, jPath); + } + if(tagContent) { + tagContent = this.parseTextData(tagContent, tagName, jPath, true, attrExpPresent, true, true); + } + + jPath = jPath.substr(0, jPath.lastIndexOf(".")); + childNode.add(this.options.textNodeName, tagContent); + + currentNode.addChild(childNode); + }else{ + //selfClosing tag + if(tagExp.length > 0 && tagExp.lastIndexOf("/") === tagExp.length - 1){ + if(tagName[tagName.length - 1] === "/"){ //remove trailing '/' + tagName = tagName.substr(0, tagName.length - 1); + tagExp = tagName; + }else{ + tagExp = tagExp.substr(0, tagExp.length - 1); + } + + if(this.options.transformTagName) { + tagName = this.options.transformTagName(tagName); + } + + const childNode = new xmlNode(tagName); + if(tagName !== tagExp && attrExpPresent){ + childNode[":@"] = this.buildAttributesMap(tagExp, jPath); + } + jPath = jPath.substr(0, jPath.lastIndexOf(".")); + currentNode.addChild(childNode); + } + //opening tag + else{ + const childNode = new xmlNode( tagName); + this.tagsNodeStack.push(currentNode); + + if(tagName !== tagExp && attrExpPresent){ + childNode[":@"] = this.buildAttributesMap(tagExp, jPath); + } + currentNode.addChild(childNode); + currentNode = childNode; + } + textData = ""; + i = closeIndex; } - textData = ""; - i = closeIndex; } }else{ textData += xmlData[i]; } } - return xmlObj; + return xmlObj.child; } -function closingIndexForOpeningTag(data, i){ +const replaceEntitiesValue = function(val){ + if(this.options.processEntities){ + for(let entityName in this.docTypeEntities){ + const entity = this.docTypeEntities[entityName]; + val = val.replace( entity.regx, entity.val); + } + for(let entityName in this.lastEntities){ + const entity = this.lastEntities[entityName]; + val = val.replace( entity.regex, entity.val); + } + if(this.options.htmlEntities){ + for(let entityName in this.htmlEntities){ + const entity = this.htmlEntities[entityName]; + val = val.replace( entity.regex, entity.val); + } + } + } + return val; +} +function saveTextToParentTag(textData, currentNode, jPath, isLeafNode) { + if (textData) { //store previously collected data as textNode + if(isLeafNode === undefined) isLeafNode = Object.keys(currentNode.child).length === 0 + + textData = this.parseTextData(textData, + currentNode.tagname, + jPath, + false, + currentNode[":@"] ? Object.keys(currentNode[":@"]).length !== 0 : false, + isLeafNode); + + if (textData !== undefined && textData !== "") + currentNode.add(this.options.textNodeName, textData); + textData = ""; + } + return textData; +} + +//TODO: use jPath to simplify the logic +/** + * + * @param {string[]} stopNodes + * @param {string} jPath + * @param {string} currentTagName + */ +function isItStopNode(stopNodes, jPath, currentTagName){ + const allNodesExp = "*." + currentTagName; + for (const stopNodePath in stopNodes) { + const stopNodeExp = stopNodes[stopNodePath]; + if( allNodesExp === stopNodeExp || jPath === stopNodeExp ) return true; + } + return false; +} + +/** + * Returns the tag Expression and where it is ending handling single-dobule quotes situation + * @param {string} xmlData + * @param {number} i starting index + * @returns + */ +function tagExpWithClosingIndex(xmlData, i, closingChar = ">"){ let attrBoundary; let tagExp = ""; - for (let index = i; index < data.length; index++) { - let ch = data[index]; + for (let index = i; index < xmlData.length; index++) { + let ch = xmlData[index]; if (attrBoundary) { if (ch === attrBoundary) attrBoundary = "";//reset } else if (ch === '"' || ch === "'") { attrBoundary = ch; - } else if (ch === '>') { + } else if (ch === closingChar[0]) { + if(closingChar[1]){ + if(xmlData[index + 1] === closingChar[1]){ + return { + data: tagExp, + index: index + } + } + }else{ return { data: tagExp, index: index } + } } else if (ch === '\t') { ch = " " } @@ -9776,8 +9826,304 @@ function findClosingIndex(xmlData, str, i, errMsg){ } } -exports.getTraversalObj = getTraversalObj; +function readTagExp(xmlData,i, removeNSPrefix, closingChar = ">"){ + const result = tagExpWithClosingIndex(xmlData, i+1, closingChar); + if(!result) return; + let tagExp = result.data; + const closeIndex = result.index; + const separatorIndex = tagExp.search(/\s/); + let tagName = tagExp; + let attrExpPresent = true; + if(separatorIndex !== -1){//separate tag name and attributes expression + tagName = tagExp.substr(0, separatorIndex).replace(/\s\s*$/, ''); + tagExp = tagExp.substr(separatorIndex + 1); + } + if(removeNSPrefix){ + const colonIndex = tagName.indexOf(":"); + if(colonIndex !== -1){ + tagName = tagName.substr(colonIndex+1); + attrExpPresent = tagName !== result.data.substr(colonIndex + 1); + } + } + + return { + tagName: tagName, + tagExp: tagExp, + closeIndex: closeIndex, + attrExpPresent: attrExpPresent, + } +} +/** + * find paired tag for a stop node + * @param {string} xmlData + * @param {string} tagName + * @param {number} i + */ +function readStopNodeData(xmlData, tagName, i){ + const startIndex = i; + // Starting at 1 since we already have an open tag + let openTagCount = 1; + + for (; i < xmlData.length; i++) { + if( xmlData[i] === "<"){ + if (xmlData[i+1] === "/") {//close tag + const closeIndex = findClosingIndex(xmlData, ">", i, `${tagName} is not closed`); + let closeTagName = xmlData.substring(i+2,closeIndex).trim(); + if(closeTagName === tagName){ + openTagCount--; + if (openTagCount === 0) { + return { + tagContent: xmlData.substring(startIndex, i), + i : closeIndex + } + } + } + i=closeIndex; + } else if(xmlData[i+1] === '?') { + const closeIndex = findClosingIndex(xmlData, "?>", i+1, "StopNode is not closed.") + i=closeIndex; + } else if(xmlData.substr(i + 1, 3) === '!--') { + const closeIndex = findClosingIndex(xmlData, "-->", i+3, "StopNode is not closed.") + i=closeIndex; + } else if(xmlData.substr(i + 1, 2) === '![') { + const closeIndex = findClosingIndex(xmlData, "]]>", i, "StopNode is not closed.") - 2; + i=closeIndex; + } else { + const tagData = readTagExp(xmlData, i, '>') + + if (tagData) { + const openTagName = tagData && tagData.tagName; + if (openTagName === tagName && tagData.tagExp[tagData.tagExp.length-1] !== "/") { + openTagCount++; + } + i=tagData.closeIndex; + } + } + } + }//end for loop +} + +function parseValue(val, shouldParse, options) { + if (shouldParse && typeof val === 'string') { + //console.log(options) + const newval = val.trim(); + if(newval === 'true' ) return true; + else if(newval === 'false' ) return false; + else return toNumber(val, options); + } else { + if (util.isExist(val)) { + return val; + } else { + return ''; + } + } +} + + +module.exports = OrderedObjParser; + + +/***/ }), + +/***/ 2380: +/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { + +const { buildOptions} = __nccwpck_require__(6993); +const OrderedObjParser = __nccwpck_require__(5832); +const { prettify} = __nccwpck_require__(2882); +const validator = __nccwpck_require__(1739); + +class XMLParser{ + + constructor(options){ + this.externalEntities = {}; + this.options = buildOptions(options); + + } + /** + * Parse XML dats to JS object + * @param {string|Buffer} xmlData + * @param {boolean|Object} validationOption + */ + parse(xmlData,validationOption){ + if(typeof xmlData === "string"){ + }else if( xmlData.toString){ + xmlData = xmlData.toString(); + }else{ + throw new Error("XML data is accepted in String or Bytes[] form.") + } + if( validationOption){ + if(validationOption === true) validationOption = {}; //validate with default options + + const result = validator.validate(xmlData, validationOption); + if (result !== true) { + throw Error( `${result.err.msg}:${result.err.line}:${result.err.col}` ) + } + } + const orderedObjParser = new OrderedObjParser(this.options); + orderedObjParser.addExternalEntities(this.externalEntities); + const orderedResult = orderedObjParser.parseXml(xmlData); + if(this.options.preserveOrder || orderedResult === undefined) return orderedResult; + else return prettify(orderedResult, this.options); + } + + /** + * Add Entity which is not by default supported by this library + * @param {string} key + * @param {string} value + */ + addEntity(key, value){ + if(value.indexOf("&") !== -1){ + throw new Error("Entity value can't have '&'") + }else if(key.indexOf("&") !== -1 || key.indexOf(";") !== -1){ + throw new Error("An entity must be set without '&' and ';'. Eg. use '#xD' for ' '") + }else{ + this.externalEntities[key] = value; + } + } +} + +module.exports = XMLParser; + +/***/ }), + +/***/ 2882: +/***/ ((__unused_webpack_module, exports) => { + +"use strict"; + + +/** + * + * @param {array} node + * @param {any} options + * @returns + */ +function prettify(node, options){ + return compress( node, options); +} + +/** + * + * @param {array} arr + * @param {object} options + * @param {string} jPath + * @returns object + */ +function compress(arr, options, jPath){ + let text; + const compressedObj = {}; + for (let i = 0; i < arr.length; i++) { + const tagObj = arr[i]; + const property = propName(tagObj); + let newJpath = ""; + if(jPath === undefined) newJpath = property; + else newJpath = jPath + "." + property; + + if(property === options.textNodeName){ + if(text === undefined) text = tagObj[property]; + else text += "" + tagObj[property]; + }else if(property === undefined){ + continue; + }else if(tagObj[property]){ + + let val = compress(tagObj[property], options, newJpath); + const isLeaf = isLeafTag(val, options); + + if(tagObj[":@"]){ + assignAttributes( val, tagObj[":@"], newJpath, options); + }else if(Object.keys(val).length === 1 && val[options.textNodeName] !== undefined && !options.alwaysCreateTextNode){ + val = val[options.textNodeName]; + }else if(Object.keys(val).length === 0){ + if(options.alwaysCreateTextNode) val[options.textNodeName] = ""; + else val = ""; + } + + if(compressedObj[property] !== undefined && compressedObj.hasOwnProperty(property)) { + if(!Array.isArray(compressedObj[property])) { + compressedObj[property] = [ compressedObj[property] ]; + } + compressedObj[property].push(val); + }else{ + //TODO: if a node is not an array, then check if it should be an array + //also determine if it is a leaf node + if (options.isArray(property, newJpath, isLeaf )) { + compressedObj[property] = [val]; + }else{ + compressedObj[property] = val; + } + } + } + + } + // if(text && text.length > 0) compressedObj[options.textNodeName] = text; + if(typeof text === "string"){ + if(text.length > 0) compressedObj[options.textNodeName] = text; + }else if(text !== undefined) compressedObj[options.textNodeName] = text; + return compressedObj; +} + +function propName(obj){ + const keys = Object.keys(obj); + for (let i = 0; i < keys.length; i++) { + const key = keys[i]; + if(key !== ":@") return key; + } +} + +function assignAttributes(obj, attrMap, jpath, options){ + if (attrMap) { + const keys = Object.keys(attrMap); + const len = keys.length; //don't make it inline + for (let i = 0; i < len; i++) { + const atrrName = keys[i]; + if (options.isArray(atrrName, jpath + "." + atrrName, true, true)) { + obj[atrrName] = [ attrMap[atrrName] ]; + } else { + obj[atrrName] = attrMap[atrrName]; + } + } + } +} + +function isLeafTag(obj, options){ + const propCount = Object.keys(obj).length; + if( propCount === 0 || (propCount === 1 && obj[options.textNodeName]) ) return true; + return false; +} +exports.prettify = prettify; + + +/***/ }), + +/***/ 7462: +/***/ ((module) => { + +"use strict"; + + +class XmlNode{ + constructor(tagname) { + this.tagname = tagname; + this.child = []; //nested tags, text, cdata, comments in order + this[":@"] = {}; //attributes map + } + add(key,val){ + // this.child.push( {name : key, val: val, isCdata: isCdata }); + this.child.push( {[key]: val }); + } + addChild(node) { + if(node[":@"] && Object.keys(node[":@"]).length > 0){ + this.child.push( { [node.tagname]: node.child, [":@"]: node[":@"] }); + }else{ + this.child.push( { [node.tagname]: node.child }); + } + }; +}; + + +module.exports = XmlNode; /***/ }), @@ -19267,6 +19613,137 @@ module.exports = function (x) { }; +/***/ }), + +/***/ 4526: +/***/ ((module) => { + +const hexRegex = /^[-+]?0x[a-fA-F0-9]+$/; +const numRegex = /^([\-\+])?(0*)(\.[0-9]+([eE]\-?[0-9]+)?|[0-9]+(\.[0-9]+([eE]\-?[0-9]+)?)?)$/; +// const octRegex = /0x[a-z0-9]+/; +// const binRegex = /0x[a-z0-9]+/; + + +//polyfill +if (!Number.parseInt && window.parseInt) { + Number.parseInt = window.parseInt; +} +if (!Number.parseFloat && window.parseFloat) { + Number.parseFloat = window.parseFloat; +} + + +const consider = { + hex : true, + leadingZeros: true, + decimalPoint: "\.", + eNotation: true + //skipLike: /regex/ +}; + +function toNumber(str, options = {}){ + // const options = Object.assign({}, consider); + // if(opt.leadingZeros === false){ + // options.leadingZeros = false; + // }else if(opt.hex === false){ + // options.hex = false; + // } + + options = Object.assign({}, consider, options ); + if(!str || typeof str !== "string" ) return str; + + let trimmedStr = str.trim(); + // if(trimmedStr === "0.0") return 0; + // else if(trimmedStr === "+0.0") return 0; + // else if(trimmedStr === "-0.0") return -0; + + if(options.skipLike !== undefined && options.skipLike.test(trimmedStr)) return str; + else if (options.hex && hexRegex.test(trimmedStr)) { + return Number.parseInt(trimmedStr, 16); + // } else if (options.parseOct && octRegex.test(str)) { + // return Number.parseInt(val, 8); + // }else if (options.parseBin && binRegex.test(str)) { + // return Number.parseInt(val, 2); + }else{ + //separate negative sign, leading zeros, and rest number + const match = numRegex.exec(trimmedStr); + if(match){ + const sign = match[1]; + const leadingZeros = match[2]; + let numTrimmedByZeros = trimZeros(match[3]); //complete num without leading zeros + //trim ending zeros for floating number + + const eNotation = match[4] || match[6]; + if(!options.leadingZeros && leadingZeros.length > 0 && sign && trimmedStr[2] !== ".") return str; //-0123 + else if(!options.leadingZeros && leadingZeros.length > 0 && !sign && trimmedStr[1] !== ".") return str; //0123 + else{//no leading zeros or leading zeros are allowed + const num = Number(trimmedStr); + const numStr = "" + num; + if(numStr.search(/[eE]/) !== -1){ //given number is long and parsed to eNotation + if(options.eNotation) return num; + else return str; + }else if(eNotation){ //given number has enotation + if(options.eNotation) return num; + else return str; + }else if(trimmedStr.indexOf(".") !== -1){ //floating number + // const decimalPart = match[5].substr(1); + // const intPart = trimmedStr.substr(0,trimmedStr.indexOf(".")); + + + // const p = numStr.indexOf("."); + // const givenIntPart = numStr.substr(0,p); + // const givenDecPart = numStr.substr(p+1); + if(numStr === "0" && (numTrimmedByZeros === "") ) return num; //0.0 + else if(numStr === numTrimmedByZeros) return num; //0.456. 0.79000 + else if( sign && numStr === "-"+numTrimmedByZeros) return num; + else return str; + } + + if(leadingZeros){ + // if(numTrimmedByZeros === numStr){ + // if(options.leadingZeros) return num; + // else return str; + // }else return str; + if(numTrimmedByZeros === numStr) return num; + else if(sign+numTrimmedByZeros === numStr) return num; + else return str; + } + + if(trimmedStr === numStr) return num; + else if(trimmedStr === sign+numStr) return num; + // else{ + // //number with +/- sign + // trimmedStr.test(/[-+][0-9]); + + // } + return str; + } + // else if(!eNotation && trimmedStr && trimmedStr !== Number(trimmedStr) ) return str; + + }else{ //non-numeric string + return str; + } + } +} + +/** + * + * @param {string} numStr without leading zeros + * @returns + */ +function trimZeros(numStr){ + if(numStr && numStr.indexOf(".") !== -1){//float + numStr = numStr.replace(/0+$/, ""); //remove ending zeros + if(numStr === ".") numStr = "0"; + else if(numStr[0] === ".") numStr = "0"+numStr; + else if(numStr[numStr.length-1] === ".") numStr = numStr.substr(0,numStr.length-1); + return numStr; + } + return numStr; +} +module.exports = toNumber + + /***/ }), /***/ 4294: diff --git a/package-lock.json b/package-lock.json index 98bc5c5..368beb2 100644 --- a/package-lock.json +++ b/package-lock.json @@ -14,7 +14,7 @@ "@actions/github": "^1.1.0", "@actions/http-client": "^2.0.1", "@actions/io": "^1.0.2", - "fast-xml-parser": "^3.15.1", + "fast-xml-parser": "^4.0.10", "semver": "^6.3.0", "xmlbuilder": "^13.0.2" }, @@ -1992,12 +1992,14 @@ "dev": true }, "node_modules/fast-xml-parser": { - "version": "3.17.4", - "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-3.17.4.tgz", - "integrity": "sha512-qudnQuyYBgnvzf5Lj/yxMcf4L9NcVWihXJg7CiU1L+oUCq8MUnFEfH2/nXR/W5uq+yvUN1h7z6s7vs2v1WkL1A==", - "hasInstallScript": true, + "version": "4.0.10", + "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-4.0.10.tgz", + "integrity": "sha512-mYMMIk7Ho1QOiedyvafdyPamn1Vlda+5n95lcn0g79UiCQoLQ2xfPQ8m3pcxBMpVaftYXtoIE2wrNTjmLQnnkg==", + "dependencies": { + "strnum": "^1.0.5" + }, "bin": { - "xml2js": "cli.js" + "fxparser": "src/cli/cli.js" }, "funding": { "type": "paypal", @@ -4204,6 +4206,11 @@ "node": ">=6" } }, + "node_modules/strnum": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/strnum/-/strnum-1.0.5.tgz", + "integrity": "sha512-J8bbNyKKXl5qYcR36TIO8W3mVGVHrmmxsd5PAItGkmyzwJvybiw2IVq5nqd0i4LSNSkB/sx9VHllbfFdr9k1JA==" + }, "node_modules/supports-color": { "version": "7.1.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz", @@ -6293,9 +6300,12 @@ "dev": true }, "fast-xml-parser": { - "version": "3.17.4", - "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-3.17.4.tgz", - "integrity": "sha512-qudnQuyYBgnvzf5Lj/yxMcf4L9NcVWihXJg7CiU1L+oUCq8MUnFEfH2/nXR/W5uq+yvUN1h7z6s7vs2v1WkL1A==" + "version": "4.0.10", + "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-4.0.10.tgz", + "integrity": "sha512-mYMMIk7Ho1QOiedyvafdyPamn1Vlda+5n95lcn0g79UiCQoLQ2xfPQ8m3pcxBMpVaftYXtoIE2wrNTjmLQnnkg==", + "requires": { + "strnum": "^1.0.5" + } }, "fb-watchman": { "version": "2.0.1", @@ -7967,6 +7977,11 @@ "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", "dev": true }, + "strnum": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/strnum/-/strnum-1.0.5.tgz", + "integrity": "sha512-J8bbNyKKXl5qYcR36TIO8W3mVGVHrmmxsd5PAItGkmyzwJvybiw2IVq5nqd0i4LSNSkB/sx9VHllbfFdr9k1JA==" + }, "supports-color": { "version": "7.1.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz", diff --git a/package.json b/package.json index 5838e4d..512bc02 100644 --- a/package.json +++ b/package.json @@ -29,7 +29,7 @@ "@actions/github": "^1.1.0", "@actions/http-client": "^2.0.1", "@actions/io": "^1.0.2", - "fast-xml-parser": "^3.15.1", + "fast-xml-parser": "^4.0.10", "semver": "^6.3.0", "xmlbuilder": "^13.0.2" }, diff --git a/src/authutil.ts b/src/authutil.ts index b9c0e15..3c48c5d 100644 --- a/src/authutil.ts +++ b/src/authutil.ts @@ -3,7 +3,7 @@ import * as path from 'path'; import * as core from '@actions/core'; import * as github from '@actions/github'; import * as xmlbuilder from 'xmlbuilder'; -import * as xmlParser from 'fast-xml-parser'; +import {XMLParser} from 'fast-xml-parser'; export function configAuthentication( feedUrl: string, @@ -66,7 +66,12 @@ function writeFeedToFile( if (fs.existsSync(existingFileLocation)) { // get key from existing NuGet.config so NuGet/dotnet can match credentials const curContents: string = fs.readFileSync(existingFileLocation, 'utf8'); - const json = xmlParser.parse(curContents, {ignoreAttributes: false}); + + const parserOptions = { + ignoreAttributes: false + }; + const parser = new XMLParser(parserOptions); + const json = parser.parse(curContents); if (typeof json.configuration === 'undefined') { throw new Error(`The provided NuGet.config seems invalid.`);