1 | 'use strict';
|
2 |
|
3 |
|
4 |
|
5 |
|
6 |
|
7 | const lang = require('zero-lang');
|
8 | const repeatString = require('./repeat-string');
|
9 |
|
10 | const splitOnTags = str => str.split(/(<[^<]+"\s*>)|(<\/?[^>]+>)/g).filter(line => line && lang.trim(line) !== '');
|
11 | const isTag = str => /<[^>]+>/.test(str);
|
12 | const isClosingTag = str => /<\/+[^>]+>/.test(str);
|
13 | const isSelfClosingTag = str => /<[^>]+\/>/.test(str);
|
14 | const isComment = str => /<![ \r\n\t]*(--([^-]|[\r\n]|-[^-])*--[ \r\n\t]*)>/.test(str);
|
15 | const isProcessingInstruction = str => /<\?(.*)\?>/.test(str);
|
16 | const isOpeningTag = str => (
|
17 | isTag(str) && !isClosingTag(str) && !isSelfClosingTag(str) && !isComment(str) && !isProcessingInstruction(str)
|
18 | );
|
19 |
|
20 | const formatter = {
|
21 | beautify(xml, indent) {
|
22 | let depth = 0;
|
23 | indent = indent || ' ';
|
24 |
|
25 | xml = xml
|
26 | .replace(/<[^<]+"\s*>/g, matched => {
|
27 |
|
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, '><')
|
42 | .replace(/>[\s]*/g, '>')
|
43 | .replace(/[\s]*</g, '<');
|
44 | },
|
45 | };
|
46 |
|
47 | module.exports = formatter;
|