@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 +2 -1
- package/src/SectionMap.coffee +42 -15
- package/src/SectionMap.js +44 -17
- package/src/block_utils.coffee +1 -1
- package/src/block_utils.js +2 -1
- package/src/html_utils.coffee +217 -0
- package/src/html_utils.js +222 -0
- package/src/indent_utils.coffee +0 -11
- package/src/indent_utils.js +0 -6
package/package.json
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
{
|
2
2
|
"name": "@jdeighan/coffee-utils",
|
3
3
|
"type": "module",
|
4
|
-
"version": "10.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",
|
package/src/SectionMap.coffee
CHANGED
@@ -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,
|
86
|
+
getBlock: (desc=undef, hReplacers={}) ->
|
87
87
|
|
88
|
-
debug "enter SectionMap.getBlock()", desc,
|
88
|
+
debug "enter SectionMap.getBlock()", desc, hReplacers
|
89
89
|
|
90
|
-
|
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
|
-
|
98
|
-
|
99
|
-
|
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
|
104
|
-
|
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 =
|
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
|
-
|
114
|
-
block = @getBlock(@hSets[desc],
|
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,
|
118
|
-
var block, i, item, lBlocks, len, proc, setName;
|
119
|
-
debug("enter SectionMap.getBlock()", desc,
|
120
|
-
|
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
|
-
|
129
|
-
|
130
|
-
|
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 (
|
135
|
-
|
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 =
|
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
|
-
|
148
|
-
block = this.getBlock(this.hSets[desc],
|
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
|
}
|
package/src/block_utils.coffee
CHANGED
@@ -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'
|
package/src/block_utils.js
CHANGED
@@ -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
|
+
};
|
package/src/indent_utils.coffee
CHANGED
@@ -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
|
-
])
|
package/src/indent_utils.js
CHANGED
@@ -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
|
-
};
|