@jdeighan/coffee-utils 10.0.0 → 10.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@jdeighan/coffee-utils",
3
3
  "type": "module",
4
- "version": "10.0.0",
4
+ "version": "10.0.3",
5
5
  "description": "A set of utility functions for CoffeeScript",
6
6
  "main": "coffee_utils.js",
7
7
  "exports": {
@@ -12,6 +12,7 @@
12
12
  "./log": "./src/log_utils.js",
13
13
  "./block": "./src/block_utils.js",
14
14
  "./indent": "./src/indent_utils.js",
15
+ "./html": "./src/html_utils.js",
15
16
  "./stack": "./src/call_stack.js",
16
17
  "./debug": "./src/debug_utils.js",
17
18
  "./arrow": "./src/arrow.js",
@@ -83,37 +83,64 @@ export class SectionMap
83
83
  # a set name
84
84
  # undef (equivalent to being set to @SectionTree)
85
85
 
86
- getBlock: (desc=undef, hProcs={}) ->
86
+ getBlock: (desc=undef, hReplacers={}) ->
87
87
 
88
- debug "enter SectionMap.getBlock()", desc, hProcs
88
+ debug "enter SectionMap.getBlock()", desc, hReplacers
89
89
 
90
- if notdefined(desc)
90
+ # --- desc can only be a string or an array
91
+ # so, if it's a hash, then it's really the hReplacers
92
+ # and the real desc is undef
93
+
94
+ if isHash(desc)
95
+ debug "arg 1 is hReplacers, no desc"
96
+ assert isEmpty(hReplacers), "invalid parms"
97
+ hReplacers = desc
98
+ desc = @lSectionTree
99
+ else if notdefined(desc)
100
+ debug "desc is entire tree"
91
101
  desc = @lSectionTree
92
102
 
93
103
  if isArray(desc)
104
+ debug "item is an array"
94
105
  lBlocks = []
95
106
  setName = undef
96
107
  for item in desc
97
- if isArray(item) || isSectionName(item)
98
- # --- arrayToBlock() will skip undef items
99
- # so, no need to check for undef block
100
- lBlocks.push @getBlock(item, hProcs)
101
- else if isSetName(item)
108
+ subBlock = undef
109
+ if isSetName(item)
110
+ debug "set name is #{item}"
102
111
  setName = item
103
- else if isString(item)
104
- lBlocks.push item # a literal string
112
+ else if isSectionName(item) || isArray(item)
113
+ subBlock = @getBlock(item, hReplacers)
114
+ if defined(subBlock)
115
+ debug "add subBlock", subBlock
116
+ lBlocks.push subBlock
117
+ else
118
+ debug "subBlock is undef"
119
+ else if isString(item) && nonEmpty(item)
120
+ debug "add string", item
121
+ lBlocks.push item
105
122
  else
106
123
  croak "Bad item: #{OL(item)}"
124
+
107
125
  block = arrayToBlock(lBlocks)
126
+ debug "block is", block
127
+ if defined(setName)
128
+ if defined(proc = hReplacers[setName])
129
+ block = proc(block)
130
+ debug "REPLACE #{setName} with", block
131
+ else
132
+ debug "NO REPLACER for #{setName}"
108
133
  else if isSectionName(desc)
134
+ debug "item is a section name"
109
135
  block = @section(desc).getBlock()
110
- if defined(proc = hProcs[desc])
136
+ if defined(proc = hReplacers[desc])
137
+ debug "REPLACE #{desc}"
111
138
  block = proc(block)
139
+ else
140
+ debug "NO REPLACER for #{desc}"
112
141
  else if isSetName(desc)
113
- # --- pass array to getBlock()
114
- block = @getBlock(@hSets[desc], hProcs)
115
- if defined(proc = hProcs[desc])
116
- block = proc(block)
142
+ debug "item is a set name"
143
+ block = @getBlock(@hSets[desc], hReplacers)
117
144
  else
118
145
  croak "Bad 1st arg: #{OL(desc)}"
119
146
  debug "return from SectionMap.getBlock()", block
package/src/SectionMap.js CHANGED
@@ -114,41 +114,68 @@ export var SectionMap = class SectionMap {
114
114
  // a section name
115
115
  // a set name
116
116
  // undef (equivalent to being set to @SectionTree)
117
- getBlock(desc = undef, hProcs = {}) {
118
- var block, i, item, lBlocks, len, proc, setName;
119
- debug("enter SectionMap.getBlock()", desc, hProcs);
120
- if (notdefined(desc)) {
117
+ getBlock(desc = undef, hReplacers = {}) {
118
+ var block, i, item, lBlocks, len, proc, setName, subBlock;
119
+ debug("enter SectionMap.getBlock()", desc, hReplacers);
120
+ // --- desc can only be a string or an array
121
+ // so, if it's a hash, then it's really the hReplacers
122
+ // and the real desc is undef
123
+ if (isHash(desc)) {
124
+ debug("arg 1 is hReplacers, no desc");
125
+ assert(isEmpty(hReplacers), "invalid parms");
126
+ hReplacers = desc;
127
+ desc = this.lSectionTree;
128
+ } else if (notdefined(desc)) {
129
+ debug("desc is entire tree");
121
130
  desc = this.lSectionTree;
122
131
  }
123
132
  if (isArray(desc)) {
133
+ debug("item is an array");
124
134
  lBlocks = [];
125
135
  setName = undef;
126
136
  for (i = 0, len = desc.length; i < len; i++) {
127
137
  item = desc[i];
128
- if (isArray(item) || isSectionName(item)) {
129
- // --- arrayToBlock() will skip undef items
130
- // so, no need to check for undef block
131
- lBlocks.push(this.getBlock(item, hProcs));
132
- } else if (isSetName(item)) {
138
+ subBlock = undef;
139
+ if (isSetName(item)) {
140
+ debug(`set name is ${item}`);
133
141
  setName = item;
134
- } else if (isString(item)) {
135
- lBlocks.push(item); // a literal string
142
+ } else if (isSectionName(item) || isArray(item)) {
143
+ subBlock = this.getBlock(item, hReplacers);
144
+ if (defined(subBlock)) {
145
+ debug("add subBlock", subBlock);
146
+ lBlocks.push(subBlock);
147
+ } else {
148
+ debug("subBlock is undef");
149
+ }
150
+ } else if (isString(item) && nonEmpty(item)) {
151
+ debug("add string", item);
152
+ lBlocks.push(item);
136
153
  } else {
137
154
  croak(`Bad item: ${OL(item)}`);
138
155
  }
139
156
  }
140
157
  block = arrayToBlock(lBlocks);
158
+ debug("block is", block);
159
+ if (defined(setName)) {
160
+ if (defined(proc = hReplacers[setName])) {
161
+ block = proc(block);
162
+ debug(`REPLACE ${setName} with`, block);
163
+ } else {
164
+ debug(`NO REPLACER for ${setName}`);
165
+ }
166
+ }
141
167
  } else if (isSectionName(desc)) {
168
+ debug("item is a section name");
142
169
  block = this.section(desc).getBlock();
143
- if (defined(proc = hProcs[desc])) {
170
+ if (defined(proc = hReplacers[desc])) {
171
+ debug(`REPLACE ${desc}`);
144
172
  block = proc(block);
173
+ } else {
174
+ debug(`NO REPLACER for ${desc}`);
145
175
  }
146
176
  } else if (isSetName(desc)) {
147
- // --- pass array to getBlock()
148
- block = this.getBlock(this.hSets[desc], hProcs);
149
- if (defined(proc = hProcs[desc])) {
150
- block = proc(block);
151
- }
177
+ debug("item is a set name");
178
+ block = this.getBlock(this.hSets[desc], hReplacers);
152
179
  } else {
153
180
  croak(`Bad 1st arg: ${OL(desc)}`);
154
181
  }
@@ -3,7 +3,7 @@
3
3
  import fs from 'fs'
4
4
  import readline from 'readline'
5
5
 
6
- import {assert, error} from '@jdeighan/unit-tester/utils'
6
+ import {assert, error, croak} from '@jdeighan/unit-tester/utils'
7
7
  import {
8
8
  undef, defined, isEmpty, isString, isArray, nonEmpty, rtrim,
9
9
  } from '@jdeighan/coffee-utils'
@@ -6,7 +6,8 @@ import readline from 'readline';
6
6
 
7
7
  import {
8
8
  assert,
9
- error
9
+ error,
10
+ croak
10
11
  } from '@jdeighan/unit-tester/utils';
11
12
 
12
13
  import {
@@ -0,0 +1,217 @@
1
+ # html_utils.coffee
2
+
3
+ import {assert, croak} from '@jdeighan/unit-tester/utils'
4
+ import {
5
+ undef, pass, words, isEmpty, nonEmpty,
6
+ } from '@jdeighan/coffee-utils'
7
+ import {indented, enclose} from '@jdeighan/coffee-utils/indent'
8
+ import {arrayToBlock} from '@jdeighan/coffee-utils/block'
9
+ import {debug} from '@jdeighan/coffee-utils/debug'
10
+
11
+ hNoEnd = {}
12
+ for tagName in words('area base br col command embed hr img input' \
13
+ + ' keygen link meta param source track wbr')
14
+ hNoEnd[tagName] = true
15
+
16
+ # ---------------------------------------------------------------------------
17
+
18
+ export parsetag = (line) ->
19
+
20
+ if lMatches = line.match(///^
21
+ (?:
22
+ ([A-Za-z][A-Za-z0-9_]*) # variable name
23
+ \s*
24
+ =
25
+ \s*
26
+ )? # variable is optional
27
+ ([A-Za-z][A-Za-z0-9_]*) # tag name
28
+ (?:
29
+ \:
30
+ ( [a-z]+ )
31
+ )?
32
+ (\S*) # modifiers (class names, etc.)
33
+ \s*
34
+ (.*) # attributes & enclosed text
35
+ $///)
36
+ [_, varName, tagName, subtype, modifiers, rest] = lMatches
37
+ else
38
+ croak "parsetag(): Invalid HTML: '#{line}'"
39
+
40
+ # --- Handle classes - subtypes and added via .<class>
41
+ lClasses = []
42
+ if nonEmpty(subtype) && (tagName != 'svelte')
43
+ lClasses.push subtype
44
+
45
+ if modifiers
46
+ # --- currently, these are only class names
47
+ while lMatches = modifiers.match(///^
48
+ \. ([A-Za-z][A-Za-z0-9_]*)
49
+ ///)
50
+ [all, className] = lMatches
51
+ lClasses.push className
52
+ modifiers = modifiers.substring(all.length)
53
+ if modifiers
54
+ croak "parsetag(): Invalid modifiers in '#{line}'"
55
+
56
+ # --- Handle attributes
57
+ hAttr = {} # { name: { value: <value>, quote: <quote> }, ... }
58
+
59
+ if varName
60
+ hAttr['bind:this'] = {value: varName, quote: '{'}
61
+
62
+ if (tagName == 'script') && (subtype == 'startup')
63
+ hAttr['context'] = {value: 'module', quote: '"'}
64
+
65
+ if rest
66
+ while lMatches = rest.match(///^
67
+ (?:
68
+ (?:
69
+ (?:
70
+ ( bind | on ) # prefix
71
+ :
72
+ )?
73
+ ([A-Za-z][A-Za-z0-9_]*) # attribute name
74
+ )
75
+ =
76
+ (?:
77
+ \{ ([^}]*) \} # attribute value
78
+ | " ([^"]*) "
79
+ | ' ([^']*) '
80
+ | ([^"'\s]+)
81
+ )
82
+ |
83
+ \{
84
+ ([A-Za-z][A-Za-z0-9_]*)
85
+ \}
86
+ ) \s*
87
+ ///)
88
+ [all, prefix, attrName, br_val, dq_val, sq_val, uq_val, ident] = lMatches
89
+ if ident
90
+ hAttr[ident] = { value: ident, shorthand: true }
91
+ else
92
+ if br_val
93
+ value = br_val
94
+ quote = '{'
95
+ else
96
+ assert ! prefix?, "prefix requires use of {...}"
97
+ if dq_val
98
+ value = dq_val
99
+ quote = '"'
100
+ else if sq_val
101
+ value = sq_val
102
+ quote = "'"
103
+ else
104
+ value = uq_val
105
+ quote = ''
106
+
107
+ if prefix
108
+ attrName = "#{prefix}:#{attrName}"
109
+
110
+ if attrName == 'class'
111
+ for className in value.split(/\s+/)
112
+ lClasses.push className
113
+ else
114
+ if hAttr.attrName?
115
+ croak "parsetag(): Multiple attributes named '#{attrName}'"
116
+ hAttr[attrName] = { value, quote }
117
+
118
+ rest = rest.substring(all.length)
119
+
120
+ # --- The rest is contained text
121
+ rest = rest.trim()
122
+ if lMatches = rest.match(///^
123
+ ['"]
124
+ (.*)
125
+ ['"]
126
+ $///)
127
+ rest = lMatches[1]
128
+
129
+ # --- Add class attribute to hAttr if there are classes
130
+ if (lClasses.length > 0)
131
+ hAttr.class = {
132
+ value: lClasses.join(' '),
133
+ quote: '"',
134
+ }
135
+
136
+ # --- Build the return value
137
+ hToken = {
138
+ type: 'tag'
139
+ tagName
140
+ }
141
+
142
+ if subtype
143
+ hToken.subtype = subtype
144
+ hToken.orgtag = "#{tagName}:#{subtype}"
145
+ else
146
+ hToken.orgtag = tagName
147
+
148
+ # --- if tagName == 'svelte', set hToken.tagName to hToken.orgtag
149
+ if (tagName == 'svelte')
150
+ hToken.tagName = hToken.orgtag
151
+
152
+ if nonEmpty(hAttr)
153
+ hToken.hAttr = hAttr
154
+
155
+ # --- Is there contained text?
156
+ if rest
157
+ hToken.text = rest
158
+
159
+ return hToken
160
+
161
+ # ---------------------------------------------------------------------------
162
+ # --- export only for unit testing
163
+
164
+ export attrStr = (hAttr) ->
165
+
166
+ if ! hAttr
167
+ return ''
168
+ str = ''
169
+ for attrName in Object.getOwnPropertyNames(hAttr)
170
+ {value, quote, shorthand} = hAttr[attrName]
171
+ if shorthand
172
+ str += " {#{value}}"
173
+ else
174
+ if quote == '{'
175
+ bquote = '{'
176
+ equote = '}'
177
+ else
178
+ bquote = equote = quote
179
+ str += " #{attrName}=#{bquote}#{value}#{equote}"
180
+ return str
181
+
182
+ # ---------------------------------------------------------------------------
183
+
184
+ export tag2str = (hToken, type='begin') ->
185
+
186
+ {tagName, hAttr} = hToken
187
+ if (type == 'begin')
188
+ str = "<#{tagName}" # build the string bit by bit
189
+ if nonEmpty(hAttr)
190
+ str += attrStr(hAttr)
191
+ str += '>'
192
+ return str
193
+ else if (type == 'end')
194
+ if hNoEnd[tagName]
195
+ return undef
196
+ else
197
+ return "</#{tagName}>"
198
+ else
199
+ croak "type must be 'begin' or 'end'"
200
+
201
+ # ---------------------------------------------------------------------------
202
+ # elem - indent text, surround with HTML tags
203
+
204
+ export elem = (tagName, hAttr=undef, text=undef, oneIndent="\t") ->
205
+
206
+ if isEmpty(text)
207
+ return undef
208
+ hToken = {
209
+ tagName
210
+ hAttr
211
+ text
212
+ }
213
+ return arrayToBlock([
214
+ tag2str(hToken, 'begin')
215
+ indented(text, 1, oneIndent)
216
+ tag2str(hToken, 'end')
217
+ ])
@@ -0,0 +1,222 @@
1
+ // Generated by CoffeeScript 2.7.0
2
+ // html_utils.coffee
3
+ var hNoEnd, i, len, ref, tagName;
4
+
5
+ import {
6
+ assert,
7
+ croak
8
+ } from '@jdeighan/unit-tester/utils';
9
+
10
+ import {
11
+ undef,
12
+ pass,
13
+ words,
14
+ isEmpty,
15
+ nonEmpty
16
+ } from '@jdeighan/coffee-utils';
17
+
18
+ import {
19
+ indented,
20
+ enclose
21
+ } from '@jdeighan/coffee-utils/indent';
22
+
23
+ import {
24
+ arrayToBlock
25
+ } from '@jdeighan/coffee-utils/block';
26
+
27
+ import {
28
+ debug
29
+ } from '@jdeighan/coffee-utils/debug';
30
+
31
+ hNoEnd = {};
32
+
33
+ ref = words('area base br col command embed hr img input' + ' keygen link meta param source track wbr');
34
+ for (i = 0, len = ref.length; i < len; i++) {
35
+ tagName = ref[i];
36
+ hNoEnd[tagName] = true;
37
+ }
38
+
39
+ // ---------------------------------------------------------------------------
40
+ export var parsetag = function(line) {
41
+ var _, all, attrName, br_val, className, dq_val, hAttr, hToken, ident, j, lClasses, lMatches, len1, modifiers, prefix, quote, ref1, rest, sq_val, subtype, uq_val, value, varName;
42
+ if (lMatches = line.match(/^(?:([A-Za-z][A-Za-z0-9_]*)\s*=\s*)?([A-Za-z][A-Za-z0-9_]*)(?:\:([a-z]+))?(\S*)\s*(.*)$/)) { // variable name
43
+ // variable is optional
44
+ // tag name
45
+ // modifiers (class names, etc.)
46
+ // attributes & enclosed text
47
+ [_, varName, tagName, subtype, modifiers, rest] = lMatches;
48
+ } else {
49
+ croak(`parsetag(): Invalid HTML: '${line}'`);
50
+ }
51
+ // --- Handle classes - subtypes and added via .<class>
52
+ lClasses = [];
53
+ if (nonEmpty(subtype) && (tagName !== 'svelte')) {
54
+ lClasses.push(subtype);
55
+ }
56
+ if (modifiers) {
57
+ // --- currently, these are only class names
58
+ while (lMatches = modifiers.match(/^\.([A-Za-z][A-Za-z0-9_]*)/)) {
59
+ [all, className] = lMatches;
60
+ lClasses.push(className);
61
+ modifiers = modifiers.substring(all.length);
62
+ }
63
+ if (modifiers) {
64
+ croak(`parsetag(): Invalid modifiers in '${line}'`);
65
+ }
66
+ }
67
+ // --- Handle attributes
68
+ hAttr = {}; // { name: { value: <value>, quote: <quote> }, ... }
69
+ if (varName) {
70
+ hAttr['bind:this'] = {
71
+ value: varName,
72
+ quote: '{'
73
+ };
74
+ }
75
+ if ((tagName === 'script') && (subtype === 'startup')) {
76
+ hAttr['context'] = {
77
+ value: 'module',
78
+ quote: '"'
79
+ };
80
+ }
81
+ if (rest) {
82
+ while (lMatches = rest.match(/^(?:(?:(?:(bind|on):)?([A-Za-z][A-Za-z0-9_]*))=(?:\{([^}]*)\}|"([^"]*)"|'([^']*)'|([^"'\s]+))|\{([A-Za-z][A-Za-z0-9_]*)\})\s*/)) { // prefix
83
+ // attribute name
84
+ // attribute value
85
+ [all, prefix, attrName, br_val, dq_val, sq_val, uq_val, ident] = lMatches;
86
+ if (ident) {
87
+ hAttr[ident] = {
88
+ value: ident,
89
+ shorthand: true
90
+ };
91
+ } else {
92
+ if (br_val) {
93
+ value = br_val;
94
+ quote = '{';
95
+ } else {
96
+ assert(prefix == null, "prefix requires use of {...}");
97
+ if (dq_val) {
98
+ value = dq_val;
99
+ quote = '"';
100
+ } else if (sq_val) {
101
+ value = sq_val;
102
+ quote = "'";
103
+ } else {
104
+ value = uq_val;
105
+ quote = '';
106
+ }
107
+ }
108
+ if (prefix) {
109
+ attrName = `${prefix}:${attrName}`;
110
+ }
111
+ if (attrName === 'class') {
112
+ ref1 = value.split(/\s+/);
113
+ for (j = 0, len1 = ref1.length; j < len1; j++) {
114
+ className = ref1[j];
115
+ lClasses.push(className);
116
+ }
117
+ } else {
118
+ if (hAttr.attrName != null) {
119
+ croak(`parsetag(): Multiple attributes named '${attrName}'`);
120
+ }
121
+ hAttr[attrName] = {value, quote};
122
+ }
123
+ }
124
+ rest = rest.substring(all.length);
125
+ }
126
+ }
127
+ // --- The rest is contained text
128
+ rest = rest.trim();
129
+ if (lMatches = rest.match(/^['"](.*)['"]$/)) {
130
+ rest = lMatches[1];
131
+ }
132
+ // --- Add class attribute to hAttr if there are classes
133
+ if (lClasses.length > 0) {
134
+ hAttr.class = {
135
+ value: lClasses.join(' '),
136
+ quote: '"'
137
+ };
138
+ }
139
+ // --- Build the return value
140
+ hToken = {
141
+ type: 'tag',
142
+ tagName
143
+ };
144
+ if (subtype) {
145
+ hToken.subtype = subtype;
146
+ hToken.orgtag = `${tagName}:${subtype}`;
147
+ } else {
148
+ hToken.orgtag = tagName;
149
+ }
150
+ // --- if tagName == 'svelte', set hToken.tagName to hToken.orgtag
151
+ if (tagName === 'svelte') {
152
+ hToken.tagName = hToken.orgtag;
153
+ }
154
+ if (nonEmpty(hAttr)) {
155
+ hToken.hAttr = hAttr;
156
+ }
157
+ // --- Is there contained text?
158
+ if (rest) {
159
+ hToken.text = rest;
160
+ }
161
+ return hToken;
162
+ };
163
+
164
+ // ---------------------------------------------------------------------------
165
+ // --- export only for unit testing
166
+ export var attrStr = function(hAttr) {
167
+ var attrName, bquote, equote, j, len1, quote, ref1, shorthand, str, value;
168
+ if (!hAttr) {
169
+ return '';
170
+ }
171
+ str = '';
172
+ ref1 = Object.getOwnPropertyNames(hAttr);
173
+ for (j = 0, len1 = ref1.length; j < len1; j++) {
174
+ attrName = ref1[j];
175
+ ({value, quote, shorthand} = hAttr[attrName]);
176
+ if (shorthand) {
177
+ str += ` {${value}}`;
178
+ } else {
179
+ if (quote === '{') {
180
+ bquote = '{';
181
+ equote = '}';
182
+ } else {
183
+ bquote = equote = quote;
184
+ }
185
+ str += ` ${attrName}=${bquote}${value}${equote}`;
186
+ }
187
+ }
188
+ return str;
189
+ };
190
+
191
+ // ---------------------------------------------------------------------------
192
+ export var tag2str = function(hToken, type = 'begin') {
193
+ var hAttr, str;
194
+ ({tagName, hAttr} = hToken);
195
+ if (type === 'begin') {
196
+ str = `<${tagName}`;
197
+ if (nonEmpty(hAttr)) {
198
+ str += attrStr(hAttr);
199
+ }
200
+ str += '>';
201
+ return str;
202
+ } else if (type === 'end') {
203
+ if (hNoEnd[tagName]) {
204
+ return undef;
205
+ } else {
206
+ return `</${tagName}>`;
207
+ }
208
+ } else {
209
+ return croak("type must be 'begin' or 'end'");
210
+ }
211
+ };
212
+
213
+ // ---------------------------------------------------------------------------
214
+ // elem - indent text, surround with HTML tags
215
+ export var elem = function(tagName, hAttr = undef, text = undef, oneIndent = "\t") {
216
+ var hToken;
217
+ if (isEmpty(text)) {
218
+ return undef;
219
+ }
220
+ hToken = {tagName, hAttr, text};
221
+ return arrayToBlock([tag2str(hToken, 'begin'), indented(text, 1, oneIndent), tag2str(hToken, 'end')]);
222
+ };
@@ -164,14 +164,3 @@ export enclose = (text, pre, post, oneIndent="\t") ->
164
164
  indented(text, 1, oneIndent)
165
165
  post
166
166
  ])
167
-
168
- # ---------------------------------------------------------------------------
169
- # elem - indent text, surround with HTML tags
170
-
171
- export elem = (text, tag, oneIndent="\t") ->
172
-
173
- return arrayToBlock([
174
- "<#{tag}>"
175
- indented(text, 1, oneIndent)
176
- "</#{tag}>"
177
- ])
@@ -187,9 +187,3 @@ export var untabify = function(str, numSpaces = 3) {
187
187
  export var enclose = function(text, pre, post, oneIndent = "\t") {
188
188
  return arrayToBlock([pre, indented(text, 1, oneIndent), post]);
189
189
  };
190
-
191
- // ---------------------------------------------------------------------------
192
- // elem - indent text, surround with HTML tags
193
- export var elem = function(text, tag, oneIndent = "\t") {
194
- return arrayToBlock([`<${tag}>`, indented(text, 1, oneIndent), `</${tag}>`]);
195
- };