@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 CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@jdeighan/coffee-utils",
3
3
  "type": "module",
4
- "version": "14.0.32",
4
+ "version": "14.0.34",
5
5
  "description": "A set of utility functions for CoffeeScript",
6
6
  "main": "coffee_utils.js",
7
7
  "exports": {
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, pass, words, isEmpty, nonEmpty, toBlock,
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
- pass,
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
+ };