@jdeighan/coffee-utils 14.0.32 → 14.0.33
Sign up to get free protection for your applications and to get access to all the features.
- package/package.json +1 -1
- package/src/html.coffee +57 -1
- package/src/html.js +60 -1
package/package.json
CHANGED
package/src/html.coffee
CHANGED
@@ -2,8 +2,9 @@
|
|
2
2
|
|
3
3
|
import {assert, croak} from '@jdeighan/base-utils/exceptions'
|
4
4
|
import {
|
5
|
-
undef, pass, words, isEmpty, nonEmpty, toBlock,
|
5
|
+
undef, pass, words, isEmpty, nonEmpty, toBlock, OL, getOptions,
|
6
6
|
} from '@jdeighan/base-utils'
|
7
|
+
import {dbgEnter, dbgReturn, dbg} from '@jdeighan/base-utils/debug'
|
7
8
|
import {indented} from '@jdeighan/coffee-utils/indent'
|
8
9
|
|
9
10
|
hNoEnd = {}
|
@@ -211,3 +212,58 @@ export elem = (tagName, hAttr=undef, text=undef, oneIndent="\t") =>
|
|
211
212
|
indented(text, 1, oneIndent)
|
212
213
|
tag2str(hToken, 'end')
|
213
214
|
])
|
215
|
+
|
216
|
+
# ---------------------------------------------------------------------------
|
217
|
+
|
218
|
+
export formatHTML = (html, hOptions={}) =>
|
219
|
+
|
220
|
+
dbgEnter 'formatHTML', html, hOptions
|
221
|
+
{oneIndent} = getOptions(hOptions, {
|
222
|
+
oneIndent: ' '
|
223
|
+
})
|
224
|
+
|
225
|
+
html = html.trim() # remove any leading/trailing whitespace
|
226
|
+
assert html.charAt(0) == '<', "Bad HTML, no < at start"
|
227
|
+
assert html.charAt(html.length-1) == '>', "Bad HTML, no > at end"
|
228
|
+
|
229
|
+
# --- Remove leading '<' and trailing '>'
|
230
|
+
html = html.substring(1, html.length-1)
|
231
|
+
|
232
|
+
hNoEndTag = {}
|
233
|
+
for tag in words("""
|
234
|
+
br hr img input link base
|
235
|
+
meta param area embed
|
236
|
+
col track source
|
237
|
+
""")
|
238
|
+
hNoEndTag[tag] = true
|
239
|
+
|
240
|
+
lParts = []
|
241
|
+
level = 0
|
242
|
+
|
243
|
+
for elem in html.split(/>\s*</)
|
244
|
+
dbg "ELEM: #{OL(elem)}"
|
245
|
+
[_, endMarker, tagName, rest] = elem.match(///^
|
246
|
+
(\/)? # possible end tag
|
247
|
+
([A-Za-z][A-Za-z0-9-]*) # tag name
|
248
|
+
(.*) # everything else
|
249
|
+
$///)
|
250
|
+
if endMarker
|
251
|
+
dbg " TAG: #{OL(tagName)} - END MARKER"
|
252
|
+
else
|
253
|
+
dbg " TAG: #{OL(tagName)} - NO END MARKER"
|
254
|
+
|
255
|
+
if endMarker && (level > 0)
|
256
|
+
# --- If end tag, reduce level
|
257
|
+
dbg " reduce level #{level} to #{level-1}"
|
258
|
+
level -= 1
|
259
|
+
|
260
|
+
dbg " ADD #{OL(elem)} at level #{level}"
|
261
|
+
lParts.push oneIndent.repeat(level), "<#{elem}>\n"
|
262
|
+
|
263
|
+
if ! endMarker && ! hNoEndTag[tagName] && !rest.endsWith('/'+tagName)
|
264
|
+
dbg " inc level #{level} to #{level+1}"
|
265
|
+
level += 1
|
266
|
+
|
267
|
+
result = lParts.join('').trim()
|
268
|
+
dbgReturn 'formatHTML', result
|
269
|
+
return result
|
package/src/html.js
CHANGED
@@ -13,9 +13,17 @@ import {
|
|
13
13
|
words,
|
14
14
|
isEmpty,
|
15
15
|
nonEmpty,
|
16
|
-
toBlock
|
16
|
+
toBlock,
|
17
|
+
OL,
|
18
|
+
getOptions
|
17
19
|
} from '@jdeighan/base-utils';
|
18
20
|
|
21
|
+
import {
|
22
|
+
dbgEnter,
|
23
|
+
dbgReturn,
|
24
|
+
dbg
|
25
|
+
} from '@jdeighan/base-utils/debug';
|
26
|
+
|
19
27
|
import {
|
20
28
|
indented
|
21
29
|
} from '@jdeighan/coffee-utils/indent';
|
@@ -214,3 +222,54 @@ export var elem = (tagName, hAttr = undef, text = undef, oneIndent = "\t") => {
|
|
214
222
|
return toBlock([tag2str(hToken, 'begin'), indented(text, 1, oneIndent), tag2str(hToken, 'end')]);
|
215
223
|
}
|
216
224
|
};
|
225
|
+
|
226
|
+
// ---------------------------------------------------------------------------
|
227
|
+
export var formatHTML = (html, hOptions = {}) => {
|
228
|
+
var _, endMarker, hNoEndTag, j, k, lParts, len1, len2, level, oneIndent, ref1, ref2, rest, result, tag;
|
229
|
+
dbgEnter('formatHTML', html, hOptions);
|
230
|
+
({oneIndent} = getOptions(hOptions, {
|
231
|
+
oneIndent: ' '
|
232
|
+
}));
|
233
|
+
html = html.trim(); // remove any leading/trailing whitespace
|
234
|
+
assert(html.charAt(0) === '<', "Bad HTML, no < at start");
|
235
|
+
assert(html.charAt(html.length - 1) === '>', "Bad HTML, no > at end");
|
236
|
+
// --- Remove leading '<' and trailing '>'
|
237
|
+
html = html.substring(1, html.length - 1);
|
238
|
+
hNoEndTag = {};
|
239
|
+
ref1 = words(`br hr img input link base
|
240
|
+
meta param area embed
|
241
|
+
col track source`);
|
242
|
+
for (j = 0, len1 = ref1.length; j < len1; j++) {
|
243
|
+
tag = ref1[j];
|
244
|
+
hNoEndTag[tag] = true;
|
245
|
+
}
|
246
|
+
lParts = [];
|
247
|
+
level = 0;
|
248
|
+
ref2 = html.split(/>\s*</);
|
249
|
+
for (k = 0, len2 = ref2.length; k < len2; k++) {
|
250
|
+
elem = ref2[k];
|
251
|
+
dbg(`ELEM: ${OL(elem)}`);
|
252
|
+
[_, endMarker, tagName, rest] = elem.match(/^(\/)?([A-Za-z][A-Za-z0-9-]*)(.*)$/); // possible end tag
|
253
|
+
// tag name
|
254
|
+
// everything else
|
255
|
+
if (endMarker) {
|
256
|
+
dbg(` TAG: ${OL(tagName)} - END MARKER`);
|
257
|
+
} else {
|
258
|
+
dbg(` TAG: ${OL(tagName)} - NO END MARKER`);
|
259
|
+
}
|
260
|
+
if (endMarker && (level > 0)) {
|
261
|
+
// --- If end tag, reduce level
|
262
|
+
dbg(` reduce level ${level} to ${level - 1}`);
|
263
|
+
level -= 1;
|
264
|
+
}
|
265
|
+
dbg(` ADD ${OL(elem)} at level ${level}`);
|
266
|
+
lParts.push(oneIndent.repeat(level), `<${elem}>\n`);
|
267
|
+
if (!endMarker && !hNoEndTag[tagName] && !rest.endsWith('/' + tagName)) {
|
268
|
+
dbg(` inc level ${level} to ${level + 1}`);
|
269
|
+
level += 1;
|
270
|
+
}
|
271
|
+
}
|
272
|
+
result = lParts.join('').trim();
|
273
|
+
dbgReturn('formatHTML', result);
|
274
|
+
return result;
|
275
|
+
};
|