UNPKG

1.84 kBJavaScriptView Raw
1'use strict';
2/**
3 * xml-format module
4 * @module xml-format
5 * @see module:index
6 */
7const lang = require('zero-lang');
8const repeatString = require('./repeat-string');
9
10const splitOnTags = str => str.split(/(<[^<]+"\s*>)|(<\/?[^>]+>)/g).filter(line => line && lang.trim(line) !== '');
11const isTag = str => /<[^>]+>/.test(str);
12const isClosingTag = str => /<\/+[^>]+>/.test(str);
13const isSelfClosingTag = str => /<[^>]+\/>/.test(str);
14const isComment = str => /<![ \r\n\t]*(--([^-]|[\r\n]|-[^-])*--[ \r\n\t]*)>/.test(str);
15const isProcessingInstruction = str => /<\?(.*)\?>/.test(str);
16const isOpeningTag = str => (
17 isTag(str) && !isClosingTag(str) && !isSelfClosingTag(str) && !isComment(str) && !isProcessingInstruction(str)
18);
19
20const formatter = {
21 beautify(xml, indent) {
22 let depth = 0;
23 indent = indent || ' ';
24
25 xml = xml
26 .replace(/<[^<]+"\s*>/g, matched => {
27 // flatten attributes
28 if (/\/>$/.test(matched)) return matched;
29 return lang.filter(lang.map(matched.split(/[\n|\r]+/), part => lang.trim(part)), str => str.length).join(' ');
30 });
31 xml = lang.map(splitOnTags(xml), item => {
32 if (isClosingTag(item)) depth--;
33 const line = repeatString(indent, depth) + item;
34 if (isOpeningTag(item)) depth++;
35 return line;
36 }).join('\n');
37 return lang.filter(xml.split(/[\r\n]/), line => !(/^\s*$/.test(line) || lang.trim(line) === '')).join('\n');
38 },
39 uglify(xml, preserveComments) {
40 const str = preserveComments ? xml : xml.replace(/<![ \r\n\t]*(--([^-]|[\r\n]|-[^-])*--[ \r\n\t]*)>/g, '');
41 return formatter.beautify(str).replace(/>[\s]*</g, '><') // before uglify it, you have to beautify it first
42 .replace(/>[\s]*/g, '>')
43 .replace(/[\s]*</g, '<');
44 },
45};
46
47module.exports = formatter;