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