xml-formatter
Advanced tools
Comparing version 1.2.1 to 2.0.0
require=(function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u="function"==typeof require&&require,i=0;i<t.length;i++)o(t[i]);return o}return r})()({1:[function(require,module,exports){ | ||
},{}],2:[function(require,module,exports){ | ||
module.exports = function() { | ||
return function debug() { | ||
// empty mock of debug module for browser usage | ||
}; | ||
}; | ||
},{}],3:[function(require,module,exports){ | ||
/** | ||
* Module dependencies. | ||
* @typedef {Object} ParsingOptions | ||
* @property {function(node)} filter Returns false to exclude a node. Default is true. | ||
*/ | ||
var debug = require('debug')('xml-parser'); | ||
/** | ||
* Expose `parse`. | ||
*/ | ||
module.exports = parse; | ||
/** | ||
* Parse the given string of `xml`. | ||
* Parse the given XML string into an object. | ||
* | ||
* @param {String} xml | ||
* @param {Object} [options] | ||
* @config {Boolean} [trim=true] | ||
* @config {Boolean} [stripComments=true] | ||
* @param {ParsingOptions} [options] | ||
* @return {Object} | ||
* @api public | ||
*/ | ||
function parse(xml, options = {}) { | ||
function parse(xml, options) { | ||
options.filter = options.filter || (() => true); | ||
// trim content | ||
if (!options || options.trim) { | ||
xml = xml.trim(); | ||
} | ||
function nextChild() { | ||
return tag() || content() || comment() || cdata(); | ||
} | ||
// strip comments | ||
if (!options || options.stripComments) { | ||
xml = xml.replace(/<!--[\s\S]*?-->/g, ''); | ||
} | ||
function nextRootChild() { | ||
match(/\s*/); | ||
return tag(true) || comment() || doctype() || processingInstruction(false); | ||
} | ||
return document(); | ||
function document() { | ||
const decl = declaration(); | ||
const children = []; | ||
let documentRootNode; | ||
let child = nextRootChild(); | ||
/** | ||
* XML document. | ||
*/ | ||
while (child) { | ||
if (child.node.type === 'Element') { | ||
if (documentRootNode) { | ||
throw new Error('Found multiple root nodes'); | ||
} | ||
documentRootNode = child.node; | ||
} | ||
function document() { | ||
if (!child.excluded) { | ||
children.push(child.node); | ||
} | ||
var decl = declaration(); | ||
var child; | ||
var children = []; | ||
var documentRootNode; | ||
child = nextRootChild(); | ||
} | ||
while (child = nextRootChild()) { | ||
if (child.name !== '#comment') { | ||
if (documentRootNode) { | ||
throw new Error('Found multiple root nodes'); | ||
if (!documentRootNode) { | ||
throw new Error('Failed to parse XML'); | ||
} | ||
documentRootNode = child; | ||
} | ||
children.push(child); | ||
return { | ||
declaration: decl ? decl.node : null, | ||
root: documentRootNode, | ||
children | ||
}; | ||
} | ||
return { | ||
declaration: decl, | ||
root: documentRootNode, | ||
children: children | ||
}; | ||
} | ||
function declaration() { | ||
return processingInstruction(true); | ||
} | ||
/** | ||
* Declaration. | ||
*/ | ||
function processingInstruction(matchDeclaration) { | ||
const m = matchDeclaration ? match(/^<\?(xml)\s*/) : match(/^<\?([\w-:.]+)\s*/); | ||
if (!m) return; | ||
function declaration() { | ||
var m = match(/^<\?xml\s*/); | ||
if (!m) return; | ||
// tag | ||
const node = { | ||
name: m[1], | ||
type: 'ProcessingInstruction', | ||
attributes: {} | ||
}; | ||
// tag | ||
var node = { | ||
attributes: {} | ||
}; | ||
// attributes | ||
while (!(eos() || is('?>'))) { | ||
const attr = attribute(); | ||
if (!attr) return node; | ||
node.attributes[attr.name] = attr.value; | ||
} | ||
// attributes | ||
while (!(eos() || is('?>'))) { | ||
var attr = attribute(); | ||
if (!attr) return node; | ||
node.attributes[attr.name] = attr.value; | ||
match(/\?>/); | ||
return { | ||
excluded: matchDeclaration ? false : options.filter(node) === false, | ||
node | ||
}; | ||
} | ||
match(/\?>\s*/); | ||
function tag(matchRoot) { | ||
const m = match(/^<([\w-:.]+)\s*/); | ||
if (!m) return; | ||
return node; | ||
} | ||
// name | ||
const node = { | ||
type: 'Element', | ||
name: m[1], | ||
attributes: {}, | ||
children: [] | ||
}; | ||
/** | ||
* Tag. | ||
*/ | ||
// attributes | ||
while (!(eos() || is('>') || is('?>') || is('/>'))) { | ||
const attr = attribute(); | ||
if (!attr) return node; | ||
node.attributes[attr.name] = attr.value; | ||
} | ||
function tag() { | ||
debug('tag %j', xml); | ||
var m = match(/^<([\w-:.]+)\s*/); | ||
if (!m) return; | ||
const excluded = matchRoot ? false : options.filter(node) === false; | ||
// name | ||
var node = { | ||
name: m[1], | ||
attributes: {}, | ||
children: [] | ||
}; | ||
// self closing tag | ||
if (match(/^\s*\/>/)) { | ||
node.children = null; | ||
return { | ||
excluded, | ||
node | ||
}; | ||
} | ||
// attributes | ||
while (!(eos() || is('>') || is('?>') || is('/>'))) { | ||
var attr = attribute(); | ||
if (!attr) return node; | ||
node.attributes[attr.name] = attr.value; | ||
} | ||
match(/\??>/); | ||
// self closing tag | ||
if (match(/^\s*\/>/)) { | ||
node.children = null; | ||
return node; | ||
} | ||
if (!excluded) { | ||
// children | ||
let child = nextChild(); | ||
while (child) { | ||
if (!child.excluded) { | ||
node.children.push(child.node); | ||
} | ||
child = nextChild(); | ||
} | ||
} | ||
match(/\??>/); | ||
// closing | ||
match(/^<\/[\w-:.]+>/); | ||
// children | ||
var child; | ||
while (child = nextChild()) { | ||
node.children.push(child); | ||
return { | ||
excluded, | ||
node | ||
}; | ||
} | ||
// closing | ||
match(/^<\/[\w-:.]+>/); | ||
function doctype() { | ||
const m = match(/^<!DOCTYPE\s+[^>]*>/); | ||
if (m) { | ||
const node = { | ||
type: 'DocumentType', | ||
content: m[0] | ||
}; | ||
return { | ||
excluded: options.filter(node) === false, | ||
node | ||
}; | ||
} | ||
} | ||
return node; | ||
} | ||
function cdata() { | ||
const m = match(/^<!\[CDATA\[[^\]\]>]*]]>/); | ||
if (m) { | ||
const node = { | ||
type: 'CDATA', | ||
content: m[0] | ||
}; | ||
return { | ||
excluded: options.filter(node) === false, | ||
node | ||
}; | ||
} | ||
} | ||
function nextChild() { | ||
return tag() || content() || comment(); | ||
} | ||
function comment() { | ||
const m = match(/^<!--[\s\S]*?-->/); | ||
if (m) { | ||
const node = { | ||
type: 'Comment', | ||
content: m[0] | ||
}; | ||
return { | ||
excluded: options.filter(node) === false, | ||
node | ||
}; | ||
} | ||
} | ||
function nextRootChild() { | ||
return tag() || comment(); | ||
} | ||
function content() { | ||
const m = match(/^([^<]+)/); | ||
if (m) { | ||
const node = { | ||
type: 'Text', | ||
content: m[1] | ||
}; | ||
return { | ||
excluded: options.filter(node) === false, | ||
node | ||
}; | ||
} | ||
} | ||
function comment() { | ||
var m = match(/^<!--[\s\S]*?-->/); | ||
if (m) { | ||
return { | ||
name: '#comment', | ||
content: m[0] | ||
}; | ||
function attribute() { | ||
const m = match(/([\w:-]+)\s*=\s*("[^"]*"|'[^']*'|\w+)\s*/); | ||
if (!m) return; | ||
return {name: m[1], value: strip(m[2])} | ||
} | ||
} | ||
/** | ||
* Text content. | ||
*/ | ||
/** | ||
* Strip quotes from `val`. | ||
*/ | ||
function strip(val) { | ||
return val.replace(/^['"]|['"]$/g, ''); | ||
} | ||
function content() { | ||
debug('content %j', xml); | ||
var m = match(/^([^<]+)/); | ||
if (m) { | ||
return { | ||
name: '#text', | ||
content: m[1] | ||
}; | ||
/** | ||
* Match `re` and advance the string. | ||
*/ | ||
function match(re) { | ||
const m = xml.match(re); | ||
if (!m) return; | ||
xml = xml.slice(m[0].length); | ||
return m; | ||
} | ||
} | ||
/** | ||
* Attribute. | ||
*/ | ||
/** | ||
* End-of-source. | ||
*/ | ||
function eos() { | ||
return 0 === xml.length; | ||
} | ||
function attribute() { | ||
debug('attribute %j', xml); | ||
var m = match(/([\w:-]+)\s*=\s*("[^"]*"|'[^']*'|\w+)\s*/); | ||
if (!m) return; | ||
return { name: m[1], value: strip(m[2]) } | ||
} | ||
/** | ||
* Check for `prefix`. | ||
*/ | ||
function is(prefix) { | ||
return 0 === xml.indexOf(prefix); | ||
} | ||
/** | ||
* Strip quotes from `val`. | ||
*/ | ||
xml = xml.trim(); | ||
function strip(val) { | ||
return val.replace(/^['"]|['"]$/g, ''); | ||
} | ||
return document(); | ||
} | ||
/** | ||
* Match `re` and advance the string. | ||
*/ | ||
module.exports = parse; | ||
function match(re) { | ||
var m = xml.match(re); | ||
if (!m) return; | ||
xml = xml.slice(m[0].length); | ||
return m; | ||
} | ||
/** | ||
* End-of-source. | ||
*/ | ||
function eos() { | ||
return 0 == xml.length; | ||
} | ||
/** | ||
* Check for `prefix`. | ||
*/ | ||
function is(prefix) { | ||
return 0 == xml.indexOf(prefix); | ||
} | ||
} | ||
},{"debug":2}],"xml-formatter":[function(require,module,exports){ | ||
},{}],"xml-formatter":[function(require,module,exports){ | ||
function newLine(output) { | ||
output.content += output.options.lineSeparator; | ||
var i; | ||
let i; | ||
for (i = 0; i < output.level; i++) { | ||
@@ -238,7 +256,10 @@ output.content += output.options.indentation; | ||
function processNode(node, output, preserveSpace) { | ||
if (node.name === '#text' || node.name === '#comment') { | ||
if (typeof node.content === 'string') { | ||
processContentNode(node, output, preserveSpace); | ||
} else if (node.type === 'Element') { | ||
processElement(node, output, preserveSpace); | ||
} else if (node.type === 'ProcessingInstruction') { | ||
processProcessingIntruction(node, output, preserveSpace); | ||
} else { | ||
// Assuming that we only have 3 types of node (#text, #comment and element) | ||
processElement(node, output, preserveSpace); | ||
throw new Error('Unknown node type: ' + node.type); | ||
} | ||
@@ -265,2 +286,5 @@ } | ||
appendContent(output, '/>'); | ||
} else if (node.children.length === 0) { | ||
// empty node | ||
appendContent(output, '></' + node.name + '>'); | ||
} else { | ||
@@ -272,8 +296,8 @@ | ||
var nodePreserveSpace = node.attributes['xml:space'] === 'preserve'; | ||
let nodePreserveSpace = node.attributes['xml:space'] === 'preserve'; | ||
if (!nodePreserveSpace && output.options.collapseContent) { | ||
var containsTextNodes = node.children.some(function(child) { | ||
return child.name === '#text'; | ||
const containsTextNodes = node.children.some(function(child) { | ||
return child.type === 'Text'; | ||
}); | ||
@@ -305,8 +329,9 @@ | ||
function processDeclaration(declaration, output) { | ||
if (declaration) { | ||
appendContent(output, '<?xml'); | ||
processAttributes(output, declaration.attributes); | ||
appendContent(output, '?>'); | ||
function processProcessingIntruction(node, output) { | ||
if (output.content.length > 0) { | ||
newLine(output); | ||
} | ||
appendContent(output, '<?' + node.name); | ||
processAttributes(output, node.attributes); | ||
appendContent(output, '?>'); | ||
} | ||
@@ -320,5 +345,4 @@ | ||
* @param {Object} options | ||
* @config {Boolean} [debug=false] displays a tree of the parsed XML before formatting | ||
* @config {String} [indentation=' '] The value used for indentation | ||
* @config {Boolean} [stripComments=false] True to strip the comments | ||
* @config {function(node)} [filter] Return false to exclude the node. | ||
* @config {Boolean} [collapseContent=false] True to keep content in the same line as the element. Only works if element contains at least one text node | ||
@@ -328,23 +352,17 @@ * @config {String} [lineSeparator='\r\n'] The line separator to use | ||
*/ | ||
function format(xml, options) { | ||
function format(xml, options = {}) { | ||
options = options || {}; | ||
options.debug = options.debug === true; | ||
options.indentation = options.indentation || ' '; | ||
options.stripComments = options.stripComments === true; | ||
options.collapseContent = options.collapseContent === true; | ||
options.lineSeparator = options.lineSeparator || '\r\n'; | ||
var parse = require('xml-parser-xo'); | ||
var parsedXml = parse(xml, {stripComments: options.stripComments}); | ||
const parse = require('xml-parser-xo'); | ||
const parsedXml = parse(xml, {filter: options.filter}); | ||
const output = {content: '', level: 0, options: options}; | ||
if (options.debug) { | ||
var inspect = require('util').inspect; | ||
console.log(inspect(parsedXml, { colors: true, depth: Infinity })); | ||
if (parsedXml.declaration) { | ||
processProcessingIntruction(parsedXml.declaration, output); | ||
} | ||
var output = {content: '', level: 0, options: options}; | ||
processDeclaration(parsedXml.declaration, output); | ||
parsedXml.children.forEach(function(child) { | ||
@@ -360,2 +378,2 @@ processNode(child, output, false); | ||
},{"util":1,"xml-parser-xo":3}]},{},[]); | ||
},{"xml-parser-xo":1}]},{},[]); |
52
index.js
function newLine(output) { | ||
output.content += output.options.lineSeparator; | ||
var i; | ||
let i; | ||
for (i = 0; i < output.level; i++) { | ||
@@ -14,7 +14,10 @@ output.content += output.options.indentation; | ||
function processNode(node, output, preserveSpace) { | ||
if (node.name === '#text' || node.name === '#comment') { | ||
if (typeof node.content === 'string') { | ||
processContentNode(node, output, preserveSpace); | ||
} else if (node.type === 'Element') { | ||
processElement(node, output, preserveSpace); | ||
} else if (node.type === 'ProcessingInstruction') { | ||
processProcessingIntruction(node, output, preserveSpace); | ||
} else { | ||
// Assuming that we only have 3 types of node (#text, #comment and element) | ||
processElement(node, output, preserveSpace); | ||
throw new Error('Unknown node type: ' + node.type); | ||
} | ||
@@ -41,2 +44,5 @@ } | ||
appendContent(output, '/>'); | ||
} else if (node.children.length === 0) { | ||
// empty node | ||
appendContent(output, '></' + node.name + '>'); | ||
} else { | ||
@@ -48,8 +54,8 @@ | ||
var nodePreserveSpace = node.attributes['xml:space'] === 'preserve'; | ||
let nodePreserveSpace = node.attributes['xml:space'] === 'preserve'; | ||
if (!nodePreserveSpace && output.options.collapseContent) { | ||
var containsTextNodes = node.children.some(function(child) { | ||
return child.name === '#text'; | ||
const containsTextNodes = node.children.some(function(child) { | ||
return child.type === 'Text'; | ||
}); | ||
@@ -81,8 +87,9 @@ | ||
function processDeclaration(declaration, output) { | ||
if (declaration) { | ||
appendContent(output, '<?xml'); | ||
processAttributes(output, declaration.attributes); | ||
appendContent(output, '?>'); | ||
function processProcessingIntruction(node, output) { | ||
if (output.content.length > 0) { | ||
newLine(output); | ||
} | ||
appendContent(output, '<?' + node.name); | ||
processAttributes(output, node.attributes); | ||
appendContent(output, '?>'); | ||
} | ||
@@ -96,5 +103,4 @@ | ||
* @param {Object} options | ||
* @config {Boolean} [debug=false] displays a tree of the parsed XML before formatting | ||
* @config {String} [indentation=' '] The value used for indentation | ||
* @config {Boolean} [stripComments=false] True to strip the comments | ||
* @config {function(node)} [filter] Return false to exclude the node. | ||
* @config {Boolean} [collapseContent=false] True to keep content in the same line as the element. Only works if element contains at least one text node | ||
@@ -104,23 +110,17 @@ * @config {String} [lineSeparator='\r\n'] The line separator to use | ||
*/ | ||
function format(xml, options) { | ||
function format(xml, options = {}) { | ||
options = options || {}; | ||
options.debug = options.debug === true; | ||
options.indentation = options.indentation || ' '; | ||
options.stripComments = options.stripComments === true; | ||
options.collapseContent = options.collapseContent === true; | ||
options.lineSeparator = options.lineSeparator || '\r\n'; | ||
var parse = require('xml-parser-xo'); | ||
var parsedXml = parse(xml, {stripComments: options.stripComments}); | ||
const parse = require('xml-parser-xo'); | ||
const parsedXml = parse(xml, {filter: options.filter}); | ||
const output = {content: '', level: 0, options: options}; | ||
if (options.debug) { | ||
var inspect = require('util').inspect; | ||
console.log(inspect(parsedXml, { colors: true, depth: Infinity })); | ||
if (parsedXml.declaration) { | ||
processProcessingIntruction(parsedXml.declaration, output); | ||
} | ||
var output = {content: '', level: 0, options: options}; | ||
processDeclaration(parsedXml.declaration, output); | ||
parsedXml.children.forEach(function(child) { | ||
@@ -127,0 +127,0 @@ processNode(child, output, false); |
{ | ||
"name": "xml-formatter", | ||
"version": "1.2.1", | ||
"repository": "chrisbottin/xml-formatter", | ||
"description": "Converts XML into a human readable format (pretty print) while respecting the xml:space attribute", | ||
"version": "2.0.0", | ||
"repository": "github:chrisbottin/xml-formatter", | ||
"bugs": { | ||
"url": "https://github.com/chrisbottin/xml-formatter/issues" | ||
}, | ||
"homepage": "https://github.com/chrisbottin/xml-formatter#readme", | ||
"description": "Converts a XML string into a human readable format (pretty print) while respecting the xml:space attribute", | ||
"author": "Chris Bottin <chrisbottin@gmail.com>", | ||
"license": "MIT", | ||
"main": "index.js", | ||
"scripts": { | ||
"test": "node_modules/.bin/mocha", | ||
"prepublishOnly": "npm test && npm run dist:prepare && npm run dist:build", | ||
"test": "mocha", | ||
"prepublishOnly": "eslint . && npm test && npm run dist:prepare && npm run dist:build", | ||
"dist:prepare": "rm -rf ./dist && mkdir -p ./dist/browser", | ||
"dist:build": "node_modules/.bin/browserify -r ./index.js:xml-formatter -o ./dist/browser/xml-formatter.js" | ||
"dist:build": "browserify -r ./index.js:xml-formatter -o ./dist/browser/xml-formatter.js" | ||
}, | ||
@@ -18,2 +24,4 @@ "engines": { | ||
"xml", | ||
"pretty", | ||
"print", | ||
"pretty-print", | ||
@@ -26,17 +34,12 @@ "indent", | ||
], | ||
"author": "Chris Bottin", | ||
"license": "MIT", | ||
"dependencies": { | ||
"xml-parser-xo": "^2.1.1" | ||
"xml-parser-xo": "^3.0.0" | ||
}, | ||
"devDependencies": { | ||
"browserify": "^13.1.1", | ||
"chai": "^3.5.0", | ||
"gulp": "^4.0.2", | ||
"mocha": "^6.2.1", | ||
"stream-assert": "^2.0.3" | ||
}, | ||
"browser": { | ||
"util": false | ||
"chai": "^4.2.0", | ||
"eslint": "^6.8.0", | ||
"glob": "^7.1.6", | ||
"mocha": "^6.2.1" | ||
} | ||
} |
@@ -48,4 +48,8 @@ | ||
var options = {indentation: ' ', stripComments: true, collapseContent: true, lineSeparator: '\n'}; | ||
var formattedXml = format(xml, options); | ||
var formattedXml = format(xml, { | ||
indentation: ' ', | ||
filter: (node) => node.type !== 'Comment', | ||
collapseContent: true, | ||
lineSeparator: '\n' | ||
}); | ||
@@ -65,5 +69,4 @@ console.log(formattedXml); | ||
- `stripComments` (Boolean, default=`true`) True to strip the comments. | ||
- `filter` (function(node)) Function to filter out unwanted nodes by returning false. | ||
- `indentation` (String, default=`' '`) The value used for indentation. | ||
- `debug` (Boolean, default=`false`) Displays a tree of the parsed XML before formatting. | ||
- `collapseContent` (Boolean, default=`false`] True to keep content in the same line as the element. Only works if element contains at least one text node | ||
@@ -70,0 +73,0 @@ - `lineSeparator` (String, default=`\r\n`) Specify the line separator to use |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
No repository
Supply chain riskPackage does not have a linked source code repository. Without this field, a package will have no reference to the location of the source code use to generate the package.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
No bug tracker
MaintenancePackage does not have a linked bug tracker in package.json.
Found 1 instance in 1 package
No repository
Supply chain riskPackage does not have a linked source code repository. Without this field, a package will have no reference to the location of the source code use to generate the package.
Found 1 instance in 1 package
No website
QualityPackage does not have a website.
Found 1 instance in 1 package
170219
18
426
0
0
105
0
+ Addedxml-parser-xo@3.2.0(transitive)
- Removeddebug@4.3.7(transitive)
- Removedms@2.1.3(transitive)
- Removedxml-parser-xo@2.2.1(transitive)
Updatedxml-parser-xo@^3.0.0