@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 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.33",
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,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
+ };