• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

NaturalIntelligence / fast-xml-parser / 4156981534

pending completion
4156981534

push

github

amit kumar gupta
Update package detail

692 of 741 branches covered (93.39%)

3 of 3 new or added lines in 2 files covered. (100.0%)

2376 of 2418 relevant lines covered (98.26%)

196233.44 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

96.47
/src/xmlparser/OrderedObjParser.js
1
'use strict';
2
///@ts-check
3

4
const util = require('../util');
1✔
5
const xmlNode = require('./xmlNode');
1✔
6
const readDocType = require("./DocTypeReader");
1✔
7
const toNumber = require("strnum");
1✔
8

9
const regx =
10
  '<((!\\[CDATA\\[([\\s\\S]*?)(]]>))|((NAME:)?(NAME))([^>]*)>|((\\/)(NAME)\\s*>))([^<]*)'
1✔
11
  .replace(/NAME/g, util.nameRegexp);
12

13
//const tagsRegx = new RegExp("<(\\/?[\\w:\\-\._]+)([^>]*)>(\\s*"+cdataRegx+")*([^<]+)?","g");
14
//const tagsRegx = new RegExp("<(\\/?)((\\w*:)?([\\w:\\-\._]+))([^>]*)>([^<]*)("+cdataRegx+"([^<]*))*([^<]+)?","g");
15

16
class OrderedObjParser{
17
  constructor(options){
18
    this.options = options;
142✔
19
    this.currentNode = null;
142✔
20
    this.tagsNodeStack = [];
142✔
21
    this.docTypeEntities = {};
142✔
22
    this.lastEntities = {
142✔
23
      "apos" : { regex: /&(apos|#39|#x27);/g, val : "'"},
24
      "gt" : { regex: /&(gt|#62|#x3E);/g, val : ">"},
25
      "lt" : { regex: /&(lt|#60|#x3C);/g, val : "<"},
26
      "quot" : { regex: /&(quot|#34|#x22);/g, val : "\""},
27
    };
28
    this.ampEntity = { regex: /&(amp|#38|#x26);/g, val : "&"};
142✔
29
    this.htmlEntities = {
142✔
30
      "space": { regex: /&(nbsp|#160);/g, val: " " },
31
      // "lt" : { regex: /&(lt|#60);/g, val: "<" },
32
      // "gt" : { regex: /&(gt|#62);/g, val: ">" },
33
      // "amp" : { regex: /&(amp|#38);/g, val: "&" },
34
      // "quot" : { regex: /&(quot|#34);/g, val: "\"" },
35
      // "apos" : { regex: /&(apos|#39);/g, val: "'" },
36
      "cent" : { regex: /&(cent|#162);/g, val: "¢" },
37
      "pound" : { regex: /&(pound|#163);/g, val: "£" },
38
      "yen" : { regex: /&(yen|#165);/g, val: "Â¥" },
39
      "euro" : { regex: /&(euro|#8364);/g, val: "€" },
40
      "copyright" : { regex: /&(copy|#169);/g, val: "©" },
41
      "reg" : { regex: /&(reg|#174);/g, val: "®" },
42
      "inr" : { regex: /&(inr|#8377);/g, val: "₹" },
43
    };
44
    this.addExternalEntities = addExternalEntities;
142✔
45
    this.parseXml = parseXml;
142✔
46
    this.parseTextData = parseTextData;
142✔
47
    this.resolveNameSpace = resolveNameSpace;
142✔
48
    this.buildAttributesMap = buildAttributesMap;
142✔
49
    this.isItStopNode = isItStopNode;
142✔
50
    this.replaceEntitiesValue = replaceEntitiesValue;
142✔
51
    this.readStopNodeData = readStopNodeData;
142✔
52
    this.saveTextToParentTag = saveTextToParentTag;
142✔
53
  }
54

55
}
56

57
function addExternalEntities(externalEntities){
58
  const entKeys = Object.keys(externalEntities);
142✔
59
  for (let i = 0; i < entKeys.length; i++) {
142✔
60
    const ent = entKeys[i];
3✔
61
    this.lastEntities[ent] = {
3✔
62
       regex: new RegExp("&"+ent+";","g"),
63
       val : externalEntities[ent]
64
    }
65
  }
66
}
67

68
/**
69
 * @param {string} val
70
 * @param {string} tagName
71
 * @param {string} jPath
72
 * @param {boolean} dontTrim
73
 * @param {boolean} hasAttributes
74
 * @param {boolean} isLeafNode
75
 * @param {boolean} escapeEntities
76
 */
77
function parseTextData(val, tagName, jPath, dontTrim, hasAttributes, isLeafNode, escapeEntities) {
78
  if (val !== undefined) {
951!
79
    if (this.options.trimValues && !dontTrim) {
951✔
80
      val = val.trim();
887✔
81
    }
82
    if(val.length > 0){
951✔
83
      if(!escapeEntities) val = this.replaceEntitiesValue(val);
377✔
84
      
85
      const newval = this.options.tagValueProcessor(tagName, val, jPath, hasAttributes, isLeafNode);
377✔
86
      if(newval === null || newval === undefined){
377✔
87
        //don't parse
88
        return val;
10✔
89
      }else if(typeof newval !== typeof val || newval !== val){
367✔
90
        //overwrite
91
        return newval;
4✔
92
      }else if(this.options.trimValues){
363✔
93
        return parseValue(val, this.options.parseTagValue, this.options.numberParseOptions);
351✔
94
      }else{
95
        const trimmedVal = val.trim();
12✔
96
        if(trimmedVal === val){
12✔
97
          return parseValue(val, this.options.parseTagValue, this.options.numberParseOptions);
3✔
98
        }else{
99
          return val;
9✔
100
        }
101
      }
102
    }
103
  }
104
}
105

106
function resolveNameSpace(tagname) {
107
  if (this.options.removeNSPrefix) {
214✔
108
    const tags = tagname.split(':');
22✔
109
    const prefix = tagname.charAt(0) === '/' ? '/' : '';
22!
110
    if (tags[0] === 'xmlns') {
22✔
111
      return '';
7✔
112
    }
113
    if (tags.length === 2) {
15✔
114
      tagname = prefix + tags[1];
6✔
115
    }
116
  }
117
  return tagname;
207✔
118
}
119

120
//TODO: change regex to capture NS
121
//const attrsRegx = new RegExp("([\\w\\-\\.\\:]+)\\s*=\\s*(['\"])((.|\n)*?)\\2","gm");
122
const attrsRegx = new RegExp('([^\\s=]+)\\s*(=\\s*([\'"])([\\s\\S]*?)\\3)?', 'gm');
1✔
123

124
function buildAttributesMap(attrStr, jPath) {
125
  if (!this.options.ignoreAttributes && typeof attrStr === 'string') {
182✔
126
    // attrStr = attrStr.replace(/\r?\n/g, ' ');
127
    //attrStr = attrStr || attrStr.trim();
128

129
    const matches = util.getAllMatches(attrStr, attrsRegx);
149✔
130
    const len = matches.length; //don't make it inline
149✔
131
    const attrs = {};
149✔
132
    for (let i = 0; i < len; i++) {
149✔
133
      const attrName = this.resolveNameSpace(matches[i][1]);
214✔
134
      let oldVal = matches[i][4];
214✔
135
      let aName = this.options.attributeNamePrefix + attrName;
214✔
136
      if (attrName.length) {
214✔
137
        if (this.options.transformAttributeName) {
207✔
138
          aName = this.options.transformAttributeName(aName);
4✔
139
        }
140
        if(aName === "__proto__") aName  = "#__proto__";
207!
141
        if (oldVal !== undefined) {
207✔
142
          if (this.options.trimValues) {
190✔
143
            oldVal = oldVal.trim();
185✔
144
          }
145
          oldVal = this.replaceEntitiesValue(oldVal);
190✔
146
          const newVal = this.options.attributeValueProcessor(attrName, oldVal, jPath);
190✔
147
          if(newVal === null || newVal === undefined){
190!
148
            //don't parse
149
            attrs[aName] = oldVal;
×
150
          }else if(typeof newVal !== typeof oldVal || newVal !== oldVal){
190!
151
            //overwrite
152
            attrs[aName] = newVal;
×
153
          }else{
154
            //parse
155
            attrs[aName] = parseValue(
190✔
156
              oldVal,
157
              this.options.parseAttributeValue,
158
              this.options.numberParseOptions
159
            );
160
          }
161
        } else if (this.options.allowBooleanAttributes) {
17✔
162
          attrs[aName] = true;
15✔
163
        }
164
      }
165
    }
166
    if (!Object.keys(attrs).length) {
149✔
167
      return;
14✔
168
    }
169
    if (this.options.attributesGroupName) {
135✔
170
      const attrCollection = {};
12✔
171
      attrCollection[this.options.attributesGroupName] = attrs;
12✔
172
      return attrCollection;
12✔
173
    }
174
    return attrs;
123✔
175
  }
176
}
177

178
const parseXml = function(xmlData) {
1✔
179
  xmlData = xmlData.replace(/\r\n?/g, "\n"); //TODO: remove this line
142✔
180
  const xmlObj = new xmlNode('!xml');
142✔
181
  let currentNode = xmlObj;
142✔
182
  let textData = "";
142✔
183
  let jPath = "";
142✔
184
  for(let i=0; i< xmlData.length; i++){//for each char in XML data
142✔
185
    const ch = xmlData[i];
10,995✔
186
    if(ch === '<'){
10,995✔
187
      // const nextIndex = i+1;
188
      // const _2ndChar = xmlData[nextIndex];
189
      if( xmlData[i+1] === '/') {//Closing Tag
1,214✔
190
        const closeIndex = findClosingIndex(xmlData, ">", i, "Closing Tag is not closed.")
508✔
191
        let tagName = xmlData.substring(i+2,closeIndex).trim();
507✔
192

193
        if(this.options.removeNSPrefix){
507✔
194
          const colonIndex = tagName.indexOf(":");
21✔
195
          if(colonIndex !== -1){
21✔
196
            tagName = tagName.substr(colonIndex+1);
10✔
197
          }
198
        }
199

200
        if(this.options.transformTagName) {
507✔
201
          tagName = this.options.transformTagName(tagName);
10✔
202
        }
203

204
        if(currentNode){
507!
205
          textData = this.saveTextToParentTag(textData, currentNode, jPath);
507✔
206
        }
207

208
        jPath = jPath.substr(0, jPath.lastIndexOf("."));
507✔
209
        
210
        currentNode = this.tagsNodeStack.pop();//avoid recurssion, set the parent tag scope
507✔
211
        textData = "";
507✔
212
        i = closeIndex;
507✔
213
      } else if( xmlData[i+1] === '?') {
706✔
214

215
        let tagData = readTagExp(xmlData,i, false, "?>");
43✔
216
        if(!tagData) throw new Error("Pi Tag is not closed.");
43✔
217

218
        textData = this.saveTextToParentTag(textData, currentNode, jPath);
41✔
219
        if( (this.options.ignoreDeclaration && tagData.tagName === "?xml") || this.options.ignorePiTags){
41✔
220

221
        }else{
222
  
223
          const childNode = new xmlNode(tagData.tagName);
36✔
224
          childNode.add(this.options.textNodeName, "");
36✔
225
          
226
          if(tagData.tagName !== tagData.tagExp && tagData.attrExpPresent){
36✔
227
            childNode[":@"] = this.buildAttributesMap(tagData.tagExp, jPath);
34✔
228
          }
229
          currentNode.addChild(childNode);
36✔
230

231
        }
232

233

234
        i = tagData.closeIndex + 1;
41✔
235
      } else if(xmlData.substr(i + 1, 3) === '!--') {
663✔
236
        const endIndex = findClosingIndex(xmlData, "-->", i+4, "Comment is not closed.")
12✔
237
        if(this.options.commentPropName){
11✔
238
          const comment = xmlData.substring(i + 4, endIndex - 2);
5✔
239

240
          textData = this.saveTextToParentTag(textData, currentNode, jPath);
5✔
241

242
          currentNode.add(this.options.commentPropName, [ { [this.options.textNodeName] : comment } ]);
5✔
243
        }
244
        i = endIndex;
11✔
245
      } else if( xmlData.substr(i + 1, 2) === '!D') {
651✔
246
        const result = readDocType(xmlData, i);
10✔
247
        this.docTypeEntities = result.entities;
9✔
248
        i = result.i;
9✔
249
      }else if(xmlData.substr(i + 1, 2) === '![') {
641✔
250
        const closeIndex = findClosingIndex(xmlData, "]]>", i, "CDATA is not closed.") - 2;
50✔
251
        const tagExp = xmlData.substring(i + 9,closeIndex);
49✔
252

253
        textData = this.saveTextToParentTag(textData, currentNode, jPath);
49✔
254

255
        //cdata should be set even if it is 0 length string
256
        if(this.options.cdataPropName){
49✔
257
          // let val = this.parseTextData(tagExp, this.options.cdataPropName, jPath + "." + this.options.cdataPropName, true, false, true);
258
          // if(!val) val = "";
259
          currentNode.add(this.options.cdataPropName, [ { [this.options.textNodeName] : tagExp } ]);
13✔
260
        }else{
261
          let val = this.parseTextData(tagExp, currentNode.tagname, jPath, true, false, true);
36✔
262
          if(val == undefined) val = "";
36✔
263
          currentNode.add(this.options.textNodeName, val);
36✔
264
        }
265
        
266
        i = closeIndex + 2;
49✔
267
      }else {//Opening tag
268
        let result = readTagExp(xmlData,i, this.options.removeNSPrefix);
591✔
269
        let tagName= result.tagName;
591✔
270
        let tagExp = result.tagExp;
591✔
271
        let attrExpPresent = result.attrExpPresent;
591✔
272
        let closeIndex = result.closeIndex;
591✔
273

274
        if (this.options.transformTagName) {
591✔
275
          tagName = this.options.transformTagName(tagName);
10✔
276
        }
277
        
278
        //save text as child node
279
        if (currentNode && textData) {
591✔
280
          if(currentNode.tagname !== '!xml'){
439✔
281
            //when nested tag is found
282
            textData = this.saveTextToParentTag(textData, currentNode, jPath, false);
401✔
283
          }
284
        }
285

286
        if(tagName !== xmlObj.tagname){
591!
287
          jPath += jPath ? "." + tagName : tagName;
591✔
288
        }
289

290
        //check if last tag was unpaired tag
291
        const lastTag = currentNode;
591✔
292
        if(lastTag && this.options.unpairedTags.indexOf(lastTag.tagname) !== -1 ){
591✔
293
          currentNode = this.tagsNodeStack.pop();
14✔
294
        }
295

296
        if (this.isItStopNode(this.options.stopNodes, jPath, tagName)) { //TODO: namespace
591✔
297
          let tagContent = "";
22✔
298
          //self-closing tag
299
          if(tagExp.length > 0 && tagExp.lastIndexOf("/") === tagExp.length - 1){
22✔
300
            i = result.closeIndex;
1✔
301
          }
302
          //boolean tag
303
          else if(this.options.unpairedTags.indexOf(tagName) !== -1){
21✔
304
            i = result.closeIndex;
1✔
305
          }
306
          //normal tag
307
          else{
308
            //read until closing tag is found
309
            const result = this.readStopNodeData(xmlData, tagName, closeIndex + 1);
20✔
310
            if(!result) throw new Error(`Unexpected end of ${tagName}`);
20!
311
            i = result.i;
20✔
312
            tagContent = result.tagContent;
20✔
313
          }
314

315
          const childNode = new xmlNode(tagName);
22✔
316
          if(tagName !== tagExp && attrExpPresent){
22✔
317
            childNode[":@"] = this.buildAttributesMap(tagExp, jPath);
8✔
318
          }
319
          if(tagContent) {
22✔
320
            tagContent = this.parseTextData(tagContent, tagName, jPath, true, attrExpPresent, true, true);
16✔
321
          }
322
          
323
          jPath = jPath.substr(0, jPath.lastIndexOf("."));
22✔
324
          childNode.add(this.options.textNodeName, tagContent);
22✔
325
          
326
          currentNode.addChild(childNode);
22✔
327
        }else{
328
  //selfClosing tag
329
          if(tagExp.length > 0 && tagExp.lastIndexOf("/") === tagExp.length - 1){
569✔
330
            if(tagName[tagName.length - 1] === "/"){ //remove trailing '/'
36✔
331
              tagName = tagName.substr(0, tagName.length - 1);
9✔
332
              tagExp = tagName;
9✔
333
            }else{
334
              tagExp = tagExp.substr(0, tagExp.length - 1);
27✔
335
            }
336
            
337
            if(this.options.transformTagName) {
36!
338
              tagName = this.options.transformTagName(tagName);
×
339
            }
340

341
            const childNode = new xmlNode(tagName);
36✔
342
            if(tagName !== tagExp && attrExpPresent){
36✔
343
              childNode[":@"] = this.buildAttributesMap(tagExp, jPath);
27✔
344
            }
345
            jPath = jPath.substr(0, jPath.lastIndexOf("."));
36✔
346
            currentNode.addChild(childNode);
36✔
347
          }
348
    //opening tag
349
          else{
350
            const childNode = new xmlNode( tagName);
533✔
351
            this.tagsNodeStack.push(currentNode);
533✔
352
            
353
            if(tagName !== tagExp && attrExpPresent){
533✔
354
              childNode[":@"] = this.buildAttributesMap(tagExp, jPath);
113✔
355
            }
356
            currentNode.addChild(childNode);
533✔
357
            currentNode = childNode;
533✔
358
          }
359
          textData = "";
569✔
360
          i = closeIndex;
569✔
361
        }
362
      }
363
    }else{
364
      textData += xmlData[i];
9,781✔
365
    }
366
  }
367
  return xmlObj.child;
136✔
368
}
369

370
const replaceEntitiesValue = function(val){
1✔
371

372
  if(this.options.processEntities){
551✔
373
    for(let entityName in this.docTypeEntities){
538✔
374
      const entity = this.docTypeEntities[entityName];
36✔
375
      val = val.replace( entity.regx, entity.val);
36✔
376
    }
377
    for(let entityName in this.lastEntities){
538✔
378
      const entity = this.lastEntities[entityName];
2,153✔
379
      val = val.replace( entity.regex, entity.val);
2,153✔
380
    }
381
    if(this.options.htmlEntities){
538✔
382
      for(let entityName in this.htmlEntities){
24✔
383
        const entity = this.htmlEntities[entityName];
192✔
384
        val = val.replace( entity.regex, entity.val);
192✔
385
      }
386
    }
387
    val = val.replace( this.ampEntity.regex, this.ampEntity.val);
538✔
388
  }
389
  return val;
551✔
390
}
391
function saveTextToParentTag(textData, currentNode, jPath, isLeafNode) {
392
  if (textData) { //store previously collected data as textNode
1,003✔
393
    if(isLeafNode === undefined) isLeafNode = Object.keys(currentNode.child).length === 0
899✔
394
    
395
    textData = this.parseTextData(textData,
899✔
396
      currentNode.tagname,
397
      jPath,
398
      false,
399
      currentNode[":@"] ? Object.keys(currentNode[":@"]).length !== 0 : false,
899✔
400
      isLeafNode);
401

402
    if (textData !== undefined && textData !== "")
899✔
403
      currentNode.add(this.options.textNodeName, textData);
327✔
404
    textData = "";
899✔
405
  }
406
  return textData;
1,003✔
407
}
408

409
//TODO: use jPath to simplify the logic
410
/**
411
 * 
412
 * @param {string[]} stopNodes 
413
 * @param {string} jPath
414
 * @param {string} currentTagName 
415
 */
416
function isItStopNode(stopNodes, jPath, currentTagName){
417
  const allNodesExp = "*." + currentTagName;
591✔
418
  for (const stopNodePath in stopNodes) {
591✔
419
    const stopNodeExp = stopNodes[stopNodePath];
97✔
420
    if( allNodesExp === stopNodeExp || jPath === stopNodeExp  ) return true;
97✔
421
  }
422
  return false;
569✔
423
}
424

425
/**
426
 * Returns the tag Expression and where it is ending handling single-dobule quotes situation
427
 * @param {string} xmlData 
428
 * @param {number} i starting index
429
 * @returns 
430
 */
431
function tagExpWithClosingIndex(xmlData, i, closingChar = ">"){
×
432
  let attrBoundary;
433
  let tagExp = "";
660✔
434
  for (let index = i; index < xmlData.length; index++) {
660✔
435
    let ch = xmlData[index];
8,821✔
436
    if (attrBoundary) {
8,821✔
437
        if (ch === attrBoundary) attrBoundary = "";//reset
2,294✔
438
    } else if (ch === '"' || ch === "'") {
6,527✔
439
        attrBoundary = ch;
238✔
440
    } else if (ch === closingChar[0]) {
6,289✔
441
      if(closingChar[1]){
700✔
442
        if(xmlData[index + 1] === closingChar[1]){
84✔
443
          return {
41✔
444
            data: tagExp,
445
            index: index
446
          }
447
        }
448
      }else{
449
        return {
616✔
450
          data: tagExp,
451
          index: index
452
        }
453
      }
454
    } else if (ch === '\t') {
5,589✔
455
      ch = " "
4✔
456
    }
457
    tagExp += ch;
8,164✔
458
  }
459
}
460

461
function findClosingIndex(xmlData, str, i, errMsg){
462
  const closingIndex = xmlData.indexOf(str, i);
616✔
463
  if(closingIndex === -1){
616✔
464
    throw new Error(errMsg)
3✔
465
  }else{
466
    return closingIndex + str.length - 1;
613✔
467
  }
468
}
469

470
function readTagExp(xmlData,i, removeNSPrefix, closingChar = ">"){
617✔
471
  const result = tagExpWithClosingIndex(xmlData, i+1, closingChar);
660✔
472
  if(!result) return;
660✔
473
  let tagExp = result.data;
657✔
474
  const closeIndex = result.index;
657✔
475
  const separatorIndex = tagExp.search(/\s/);
657✔
476
  let tagName = tagExp;
657✔
477
  let attrExpPresent = true;
657✔
478
  if(separatorIndex !== -1){//separate tag name and attributes expression
657✔
479
    tagName = tagExp.substr(0, separatorIndex).replace(/\s\s*$/, '');
194✔
480
    tagExp = tagExp.substr(separatorIndex + 1);
194✔
481
  }
482

483
  if(removeNSPrefix){
657✔
484
    const colonIndex = tagName.indexOf(":");
48✔
485
    if(colonIndex !== -1){
48✔
486
      tagName = tagName.substr(colonIndex+1);
12✔
487
      attrExpPresent = tagName !== result.data.substr(colonIndex + 1);
12✔
488
    }
489
  }
490

491
  return {
657✔
492
    tagName: tagName,
493
    tagExp: tagExp,
494
    closeIndex: closeIndex,
495
    attrExpPresent: attrExpPresent,
496
  }
497
}
498
/**
499
 * find paired tag for a stop node
500
 * @param {string} xmlData 
501
 * @param {string} tagName 
502
 * @param {number} i 
503
 */
504
function readStopNodeData(xmlData, tagName, i){
505
  const startIndex = i;
20✔
506
  // Starting at 1 since we already have an open tag
507
  let openTagCount = 1;
20✔
508

509
  for (; i < xmlData.length; i++) {
20✔
510
    if( xmlData[i] === "<"){ 
896✔
511
      if (xmlData[i+1] === "/") {//close tag
72✔
512
          const closeIndex = findClosingIndex(xmlData, ">", i, `${tagName} is not closed`);
44✔
513
          let closeTagName = xmlData.substring(i+2,closeIndex).trim();
44✔
514
          if(closeTagName === tagName){
44✔
515
            openTagCount--;
21✔
516
            if (openTagCount === 0) {
21✔
517
              return {
20✔
518
                tagContent: xmlData.substring(startIndex, i),
519
                i : closeIndex
520
              }
521
            }
522
          }
523
          i=closeIndex;
24✔
524
        } else if(xmlData[i+1] === '?') { 
28!
525
          const closeIndex = findClosingIndex(xmlData, "?>", i+1, "StopNode is not closed.")
×
526
          i=closeIndex;
×
527
        } else if(xmlData.substr(i + 1, 3) === '!--') { 
28✔
528
          const closeIndex = findClosingIndex(xmlData, "-->", i+3, "StopNode is not closed.")
1✔
529
          i=closeIndex;
1✔
530
        } else if(xmlData.substr(i + 1, 2) === '![') { 
27✔
531
          const closeIndex = findClosingIndex(xmlData, "]]>", i, "StopNode is not closed.") - 2;
1✔
532
          i=closeIndex;
1✔
533
        } else {
534
          const tagData = readTagExp(xmlData, i, '>')
26✔
535

536
          if (tagData) {
26✔
537
            const openTagName = tagData && tagData.tagName;
25✔
538
            if (openTagName === tagName && tagData.tagExp[tagData.tagExp.length-1] !== "/") {
25✔
539
              openTagCount++;
1✔
540
            }
541
            i=tagData.closeIndex;
25✔
542
          }
543
        }
544
      }
545
  }//end for loop
546
}
547

548
function parseValue(val, shouldParse, options) {
549
  if (shouldParse && typeof val === 'string') {
544✔
550
    //console.log(options)
551
    const newval = val.trim();
378✔
552
    if(newval === 'true' ) return true;
378✔
553
    else if(newval === 'false' ) return false;
372✔
554
    else return toNumber(val, options);
370✔
555
  } else {
556
    if (util.isExist(val)) {
166!
557
      return val;
166✔
558
    } else {
559
      return '';
×
560
    }
561
  }
562
}
563

564

565
module.exports = OrderedObjParser;
1✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc