@jdeighan/coffee-utils 9.0.4 → 10.0.1
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 +1 -1
- package/src/Section.coffee +11 -3
- package/src/Section.js +17 -3
- package/src/SectionMap.coffee +109 -147
- package/src/SectionMap.js +128 -160
- package/src/block_utils.coffee +32 -0
- package/src/block_utils.js +41 -0
- package/src/coffee_utils.coffee +11 -0
- package/src/coffee_utils.js +12 -0
- package/src/indent_utils.coffee +31 -26
- package/src/indent_utils.js +23 -32
package/package.json
CHANGED
package/src/Section.coffee
CHANGED
|
@@ -2,18 +2,22 @@
|
|
|
2
2
|
|
|
3
3
|
import {assert, error, croak} from '@jdeighan/unit-tester/utils'
|
|
4
4
|
import {
|
|
5
|
-
pass, undef, defined, isArray,
|
|
5
|
+
pass, undef, defined, isArray, isEmpty,
|
|
6
6
|
} from '@jdeighan/coffee-utils'
|
|
7
7
|
import {arrayToBlock} from '@jdeighan/coffee-utils/block'
|
|
8
8
|
import {indented} from '@jdeighan/coffee-utils/indent'
|
|
9
|
+
import {debug} from '@jdeighan/coffee-utils/debug'
|
|
9
10
|
|
|
10
11
|
# ---------------------------------------------------------------------------
|
|
11
12
|
|
|
12
13
|
export class Section
|
|
13
14
|
|
|
14
|
-
constructor: (@name) ->
|
|
15
|
+
constructor: (@name, content=undef) ->
|
|
16
|
+
# --- name can be undef or empty
|
|
15
17
|
|
|
16
18
|
@lParts = []
|
|
19
|
+
if defined(content)
|
|
20
|
+
@lParts.push content
|
|
17
21
|
|
|
18
22
|
# ..........................................................
|
|
19
23
|
|
|
@@ -73,7 +77,11 @@ export class Section
|
|
|
73
77
|
|
|
74
78
|
getBlock: () ->
|
|
75
79
|
|
|
80
|
+
debug "enter Section.getBlock()"
|
|
76
81
|
if (@lParts.length == 0)
|
|
82
|
+
debug "return undef from Section.getBlock()"
|
|
77
83
|
return undef
|
|
78
84
|
else
|
|
79
|
-
|
|
85
|
+
result = arrayToBlock(@lParts)
|
|
86
|
+
debug "return from Section.getBlock()", result
|
|
87
|
+
return result
|
package/src/Section.js
CHANGED
|
@@ -10,7 +10,8 @@ import {
|
|
|
10
10
|
pass,
|
|
11
11
|
undef,
|
|
12
12
|
defined,
|
|
13
|
-
isArray
|
|
13
|
+
isArray,
|
|
14
|
+
isEmpty
|
|
14
15
|
} from '@jdeighan/coffee-utils';
|
|
15
16
|
|
|
16
17
|
import {
|
|
@@ -21,11 +22,19 @@ import {
|
|
|
21
22
|
indented
|
|
22
23
|
} from '@jdeighan/coffee-utils/indent';
|
|
23
24
|
|
|
25
|
+
import {
|
|
26
|
+
debug
|
|
27
|
+
} from '@jdeighan/coffee-utils/debug';
|
|
28
|
+
|
|
24
29
|
// ---------------------------------------------------------------------------
|
|
25
30
|
export var Section = class Section {
|
|
26
|
-
constructor(name) {
|
|
31
|
+
constructor(name, content = undef) {
|
|
27
32
|
this.name = name;
|
|
33
|
+
// --- name can be undef or empty
|
|
28
34
|
this.lParts = [];
|
|
35
|
+
if (defined(content)) {
|
|
36
|
+
this.lParts.push(content);
|
|
37
|
+
}
|
|
29
38
|
}
|
|
30
39
|
|
|
31
40
|
// ..........................................................
|
|
@@ -88,10 +97,15 @@ export var Section = class Section {
|
|
|
88
97
|
|
|
89
98
|
// ..........................................................
|
|
90
99
|
getBlock() {
|
|
100
|
+
var result;
|
|
101
|
+
debug("enter Section.getBlock()");
|
|
91
102
|
if (this.lParts.length === 0) {
|
|
103
|
+
debug("return undef from Section.getBlock()");
|
|
92
104
|
return undef;
|
|
93
105
|
} else {
|
|
94
|
-
|
|
106
|
+
result = arrayToBlock(this.lParts);
|
|
107
|
+
debug("return from Section.getBlock()", result);
|
|
108
|
+
return result;
|
|
95
109
|
}
|
|
96
110
|
}
|
|
97
111
|
|
package/src/SectionMap.coffee
CHANGED
|
@@ -2,12 +2,13 @@
|
|
|
2
2
|
|
|
3
3
|
import {assert, error, croak} from '@jdeighan/unit-tester/utils'
|
|
4
4
|
import {
|
|
5
|
-
pass, undef, defined, OL, isEmpty, nonEmpty,
|
|
5
|
+
pass, undef, defined, notdefined, OL, isEmpty, nonEmpty,
|
|
6
6
|
isString, isHash, isArray, isUniqueTree, isNonEmptyString,
|
|
7
7
|
isNonEmptyArray,
|
|
8
8
|
} from '@jdeighan/coffee-utils'
|
|
9
9
|
import {arrayToBlock} from '@jdeighan/coffee-utils/block'
|
|
10
10
|
import {indented} from '@jdeighan/coffee-utils/indent'
|
|
11
|
+
import {LOG} from '@jdeighan/coffee-utils/log'
|
|
11
12
|
import {debug} from '@jdeighan/coffee-utils/debug'
|
|
12
13
|
import {Section} from '@jdeighan/coffee-utils/section'
|
|
13
14
|
|
|
@@ -15,149 +16,145 @@ import {Section} from '@jdeighan/coffee-utils/section'
|
|
|
15
16
|
|
|
16
17
|
isSectionName = (name) ->
|
|
17
18
|
|
|
18
|
-
return isString(name) && name.match(/^[a-z][a-z0-
|
|
19
|
+
return isString(name) && name.match(/^[a-z][a-z0-9_]*/)
|
|
19
20
|
|
|
20
21
|
# ---------------------------------------------------------------------------
|
|
21
22
|
|
|
22
23
|
isSetName = (name) ->
|
|
23
24
|
|
|
24
|
-
return isString(name) && name.match(/^[A-Z][a-z0-
|
|
25
|
+
return isString(name) && name.match(/^[A-Z][a-z0-9_]*/)
|
|
25
26
|
|
|
26
27
|
# ---------------------------------------------------------------------------
|
|
27
28
|
|
|
28
29
|
export class SectionMap
|
|
29
30
|
|
|
30
|
-
constructor: (lSectionTree) ->
|
|
31
|
-
# --- lSectionTree is a tree of section names
|
|
31
|
+
constructor: (@lSectionTree) ->
|
|
32
|
+
# --- lSectionTree is a tree of section/set names
|
|
32
33
|
|
|
33
|
-
debug "enter SectionMap()", lSectionTree
|
|
34
|
-
@lSectionTree
|
|
35
|
-
|
|
34
|
+
debug "enter SectionMap()", @lSectionTree
|
|
35
|
+
assert isArray(@lSectionTree), "not an array"
|
|
36
|
+
|
|
37
|
+
# --- keys are section names, values are Section objects
|
|
36
38
|
@hSections = {}
|
|
37
|
-
|
|
39
|
+
|
|
40
|
+
# --- keys are set names, values are subtrees of lSectionTree
|
|
41
|
+
@hSets = {}
|
|
42
|
+
|
|
43
|
+
@build @lSectionTree
|
|
38
44
|
debug "return from SectionMap()", @hSections
|
|
39
45
|
|
|
40
46
|
# ..........................................................
|
|
41
47
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
48
|
+
build: (lTree) ->
|
|
49
|
+
|
|
50
|
+
debug "enter build()", lTree
|
|
51
|
+
assert isArray(lTree), "not an array"
|
|
52
|
+
assert nonEmpty(lTree), "empty array"
|
|
53
|
+
|
|
54
|
+
firstItem = lTree[0]
|
|
55
|
+
if isSetName(firstItem)
|
|
56
|
+
assert (lTree.length >= 2), "set without sections"
|
|
57
|
+
@hSets[firstItem] = lTree
|
|
58
|
+
for item in lTree.slice(1)
|
|
59
|
+
if isArray(item)
|
|
60
|
+
@build item
|
|
61
|
+
else if isSectionName(item)
|
|
62
|
+
@hSections[item] = new Section(item)
|
|
63
|
+
else if ! isString(item) # string would be literal
|
|
64
|
+
croak "Bad section tree: #{OL(@lSectionTree)}"
|
|
51
65
|
else
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
name = item
|
|
66
|
+
for item in lTree
|
|
67
|
+
if isArray(item)
|
|
68
|
+
@build item
|
|
69
|
+
else if isSectionName(item)
|
|
70
|
+
@hSections[item] = new Section(item)
|
|
58
71
|
else
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
lParts.push item
|
|
62
|
-
if defined(name)
|
|
63
|
-
@addSet name, lParts
|
|
64
|
-
return lParts
|
|
72
|
+
croak "Bad section tree: #{OL(@lSectionTree)}"
|
|
73
|
+
debug "return from build()", @hSections, @hSets
|
|
65
74
|
return
|
|
66
75
|
|
|
67
76
|
# ..........................................................
|
|
77
|
+
# --- hProc should be <name> -> <function>
|
|
78
|
+
# <name> can be a section name or a set name
|
|
79
|
+
# <function> should be <block> -> <block>
|
|
80
|
+
# --- desc can be:
|
|
81
|
+
# an array, which may begin with a set name
|
|
82
|
+
# a section name
|
|
83
|
+
# a set name
|
|
84
|
+
# undef (equivalent to being set to @SectionTree)
|
|
68
85
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
debug "enter addSet()", name, lSectionTree
|
|
72
|
-
|
|
73
|
-
# --- check the name
|
|
74
|
-
assert isSetName(name), "not a valid set name #{OL(name)}"
|
|
75
|
-
|
|
76
|
-
# --- check lSectionTree
|
|
77
|
-
assert isArray(lSectionTree), "arg 2 not an array"
|
|
78
|
-
for secName in lSectionTree
|
|
79
|
-
assert isNonEmptyString(secName),
|
|
80
|
-
"not a non-empty string #{OL(secName)}"
|
|
81
|
-
assert defined(@hSections[secName]),
|
|
82
|
-
"not a section name #{OL(secName)}"
|
|
83
|
-
|
|
84
|
-
@hSets[name] = lSectionTree
|
|
85
|
-
debug 'hSets', @hSets
|
|
86
|
-
debug "return from addSet()"
|
|
87
|
-
return
|
|
86
|
+
getBlock: (desc=undef, hReplacers={}) ->
|
|
88
87
|
|
|
89
|
-
|
|
90
|
-
# --- sections returned in depth-first order from section tree
|
|
91
|
-
# Set names are simply skipped
|
|
92
|
-
# yields: [<level>, <section>]
|
|
88
|
+
debug "enter SectionMap.getBlock()", desc, hReplacers
|
|
93
89
|
|
|
94
|
-
|
|
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
|
|
95
93
|
|
|
96
|
-
|
|
97
|
-
|
|
94
|
+
if isHash(desc)
|
|
95
|
+
debug "arg 1 is hReplacers, no desc"
|
|
96
|
+
assert isEmpty(hReplacers), "invalid parms"
|
|
97
|
+
hReplacers = desc
|
|
98
98
|
desc = @lSectionTree
|
|
99
|
+
else if notdefined(desc)
|
|
100
|
+
desc = @lSectionTree
|
|
101
|
+
|
|
99
102
|
if isArray(desc)
|
|
103
|
+
lBlocks = []
|
|
104
|
+
setName = undef
|
|
100
105
|
for item in desc
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
106
|
+
subBlock = undef
|
|
107
|
+
if isArray(item)
|
|
108
|
+
subBlock = @getBlock(item, hReplacers)
|
|
109
|
+
else if isSectionName(item)
|
|
110
|
+
subBlock = @getBlock(item, hReplacers)
|
|
105
111
|
else if isSetName(item)
|
|
106
|
-
|
|
112
|
+
setName = item
|
|
113
|
+
else if isString(item)
|
|
114
|
+
subBlock = item # a literal string
|
|
115
|
+
else
|
|
116
|
+
croak "Bad item: #{OL(item)}"
|
|
117
|
+
if defined(subBlock)
|
|
118
|
+
lBlocks.push subBlock
|
|
119
|
+
block = arrayToBlock(lBlocks)
|
|
120
|
+
if defined(setName)
|
|
121
|
+
if defined(proc = hReplacers[setName])
|
|
122
|
+
debug "REPLACE #{setName}"
|
|
123
|
+
block = proc(block)
|
|
107
124
|
else
|
|
108
|
-
|
|
109
|
-
yield from @allSections(item, level+1)
|
|
125
|
+
debug "NO REPLACER for #{setName}"
|
|
110
126
|
else if isSectionName(desc)
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
127
|
+
block = @section(desc).getBlock()
|
|
128
|
+
if defined(proc = hReplacers[desc])
|
|
129
|
+
debug "REPLACE #{desc}"
|
|
130
|
+
block = proc(block)
|
|
131
|
+
else
|
|
132
|
+
debug "NO REPLACER for #{desc}"
|
|
114
133
|
else if isSetName(desc)
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
yield from @allSections(lTree, level)
|
|
134
|
+
# --- pass array to getBlock()
|
|
135
|
+
block = @getBlock(@hSets[desc], hReplacers)
|
|
118
136
|
else
|
|
119
|
-
croak "Bad
|
|
120
|
-
debug "return from
|
|
121
|
-
return
|
|
137
|
+
croak "Bad 1st arg: #{OL(desc)}"
|
|
138
|
+
debug "return from SectionMap.getBlock()", block
|
|
139
|
+
return block
|
|
122
140
|
|
|
123
141
|
# ..........................................................
|
|
124
|
-
# --- hProc should be <name> -> <function>
|
|
125
|
-
# <function> should be <block> -> <block>
|
|
126
|
-
# --- lTree allows you to get just a section
|
|
127
142
|
|
|
128
|
-
|
|
143
|
+
isEmpty: () ->
|
|
129
144
|
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
if isString(part)
|
|
139
|
-
block = @section(part).getBlock()
|
|
140
|
-
if defined(hProc[part])
|
|
141
|
-
# --- called even if block is empty
|
|
142
|
-
block = hProc[part](block)
|
|
143
|
-
else if isNonEmptyArray(part)
|
|
144
|
-
if isSectionName(part[0])
|
|
145
|
-
block = @getBlock(hProc, part)
|
|
146
|
-
else if isSetName(part[0])
|
|
147
|
-
block = @getBlock(hProc, part.slice(1))
|
|
148
|
-
if defined(hProc[part[0]])
|
|
149
|
-
block = hProc[part[0]](block)
|
|
150
|
-
else
|
|
151
|
-
croak "Bad part: #{OL(part)}"
|
|
152
|
-
else
|
|
153
|
-
croak "Bad part: #{OL(part)}"
|
|
154
|
-
if defined(block)
|
|
155
|
-
lParts.push block
|
|
145
|
+
for name,sect of @hSections
|
|
146
|
+
if sect.nonEmpty()
|
|
147
|
+
return false
|
|
148
|
+
return true
|
|
149
|
+
|
|
150
|
+
# ..........................................................
|
|
151
|
+
|
|
152
|
+
nonEmpty: () ->
|
|
156
153
|
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
return
|
|
154
|
+
for name,sect of @hSections
|
|
155
|
+
if sect.nonEmpty()
|
|
156
|
+
return true
|
|
157
|
+
return false
|
|
161
158
|
|
|
162
159
|
# ..........................................................
|
|
163
160
|
|
|
@@ -172,50 +169,15 @@ export class SectionMap
|
|
|
172
169
|
firstSection: (name) ->
|
|
173
170
|
|
|
174
171
|
assert isSetName(name), "bad set name #{OL(name)}"
|
|
175
|
-
|
|
176
|
-
assert defined(
|
|
177
|
-
|
|
178
|
-
return @section(lSectionTree[0])
|
|
172
|
+
lSubTree = @hSets[name]
|
|
173
|
+
assert defined(lSubTree), "no such set #{OL(name)}"
|
|
174
|
+
return @section(lSubTree[1])
|
|
179
175
|
|
|
180
176
|
# ..........................................................
|
|
181
177
|
|
|
182
178
|
lastSection: (name) ->
|
|
183
179
|
|
|
184
180
|
assert isSetName(name), "bad set name #{OL(name)}"
|
|
185
|
-
|
|
186
|
-
assert defined(
|
|
187
|
-
|
|
188
|
-
return @section(lSectionTree[lSectionTree.length - 1])
|
|
189
|
-
|
|
190
|
-
# ..........................................................
|
|
191
|
-
|
|
192
|
-
length: (desc=undef) ->
|
|
193
|
-
|
|
194
|
-
result = 0
|
|
195
|
-
for [_, sect] from @allSections(desc)
|
|
196
|
-
result += sect.length()
|
|
197
|
-
return result
|
|
198
|
-
|
|
199
|
-
# ..........................................................
|
|
200
|
-
|
|
201
|
-
isEmpty: (desc=undef) ->
|
|
202
|
-
|
|
203
|
-
return (@length(desc) == 0)
|
|
204
|
-
|
|
205
|
-
# ..........................................................
|
|
206
|
-
|
|
207
|
-
nonEmpty: (desc=undef) ->
|
|
208
|
-
|
|
209
|
-
return (@length(desc) > 0)
|
|
210
|
-
|
|
211
|
-
# ..........................................................
|
|
212
|
-
|
|
213
|
-
getShape: () ->
|
|
214
|
-
|
|
215
|
-
debug "enter getShape()"
|
|
216
|
-
lParts = []
|
|
217
|
-
for [level, sect] from @allSections()
|
|
218
|
-
lParts.push indented(sect.name, level)
|
|
219
|
-
result = arrayToBlock(lParts)
|
|
220
|
-
debug "return from getShape()", result
|
|
221
|
-
return result
|
|
181
|
+
lSubTree = @hSets[name]
|
|
182
|
+
assert defined(lSubTree), "no such set #{OL(name)}"
|
|
183
|
+
return @section(lSubTree[lSubTree.length - 1])
|
package/src/SectionMap.js
CHANGED
|
@@ -12,6 +12,7 @@ import {
|
|
|
12
12
|
pass,
|
|
13
13
|
undef,
|
|
14
14
|
defined,
|
|
15
|
+
notdefined,
|
|
15
16
|
OL,
|
|
16
17
|
isEmpty,
|
|
17
18
|
nonEmpty,
|
|
@@ -31,6 +32,10 @@ import {
|
|
|
31
32
|
indented
|
|
32
33
|
} from '@jdeighan/coffee-utils/indent';
|
|
33
34
|
|
|
35
|
+
import {
|
|
36
|
+
LOG
|
|
37
|
+
} from '@jdeighan/coffee-utils/log';
|
|
38
|
+
|
|
34
39
|
import {
|
|
35
40
|
debug
|
|
36
41
|
} from '@jdeighan/coffee-utils/debug';
|
|
@@ -41,158 +46,160 @@ import {
|
|
|
41
46
|
|
|
42
47
|
// ---------------------------------------------------------------------------
|
|
43
48
|
isSectionName = function(name) {
|
|
44
|
-
return isString(name) && name.match(/^[a-z][a-z0-
|
|
49
|
+
return isString(name) && name.match(/^[a-z][a-z0-9_]*/);
|
|
45
50
|
};
|
|
46
51
|
|
|
47
52
|
// ---------------------------------------------------------------------------
|
|
48
53
|
isSetName = function(name) {
|
|
49
|
-
return isString(name) && name.match(/^[A-Z][a-z0-
|
|
54
|
+
return isString(name) && name.match(/^[A-Z][a-z0-9_]*/);
|
|
50
55
|
};
|
|
51
56
|
|
|
52
57
|
// ---------------------------------------------------------------------------
|
|
53
58
|
export var SectionMap = class SectionMap {
|
|
54
59
|
constructor(lSectionTree) {
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
this.lSectionTree
|
|
58
|
-
this.
|
|
60
|
+
this.lSectionTree = lSectionTree;
|
|
61
|
+
// --- lSectionTree is a tree of section/set names
|
|
62
|
+
debug("enter SectionMap()", this.lSectionTree);
|
|
63
|
+
assert(isArray(this.lSectionTree), "not an array");
|
|
64
|
+
// --- keys are section names, values are Section objects
|
|
59
65
|
this.hSections = {};
|
|
60
|
-
|
|
66
|
+
// --- keys are set names, values are subtrees of lSectionTree
|
|
67
|
+
this.hSets = {};
|
|
68
|
+
this.build(this.lSectionTree);
|
|
61
69
|
debug("return from SectionMap()", this.hSections);
|
|
62
70
|
}
|
|
63
71
|
|
|
64
72
|
// ..........................................................
|
|
65
|
-
|
|
66
|
-
var i, item, j,
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
73
|
+
build(lTree) {
|
|
74
|
+
var firstItem, i, item, j, len, len1, ref;
|
|
75
|
+
debug("enter build()", lTree);
|
|
76
|
+
assert(isArray(lTree), "not an array");
|
|
77
|
+
assert(nonEmpty(lTree), "empty array");
|
|
78
|
+
firstItem = lTree[0];
|
|
79
|
+
if (isSetName(firstItem)) {
|
|
80
|
+
assert(lTree.length >= 2, "set without sections");
|
|
81
|
+
this.hSets[firstItem] = lTree;
|
|
82
|
+
ref = lTree.slice(1);
|
|
83
|
+
for (i = 0, len = ref.length; i < len; i++) {
|
|
84
|
+
item = ref[i];
|
|
85
|
+
if (isArray(item)) {
|
|
86
|
+
this.build(item);
|
|
87
|
+
} else if (isSectionName(item)) {
|
|
88
|
+
this.hSections[item] = new Section(item);
|
|
89
|
+
} else if (!isString(item)) { // string would be literal
|
|
90
|
+
croak(`Bad section tree: ${OL(this.lSectionTree)}`);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
74
93
|
} else {
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
item
|
|
80
|
-
|
|
81
|
-
name = item;
|
|
94
|
+
for (j = 0, len1 = lTree.length; j < len1; j++) {
|
|
95
|
+
item = lTree[j];
|
|
96
|
+
if (isArray(item)) {
|
|
97
|
+
this.build(item);
|
|
98
|
+
} else if (isSectionName(item)) {
|
|
99
|
+
this.hSections[item] = new Section(item);
|
|
82
100
|
} else {
|
|
83
|
-
|
|
84
|
-
for (k = 0, len1 = lAdded.length; k < len1; k++) {
|
|
85
|
-
item = lAdded[k];
|
|
86
|
-
lParts.push(item);
|
|
87
|
-
}
|
|
101
|
+
croak(`Bad section tree: ${OL(this.lSectionTree)}`);
|
|
88
102
|
}
|
|
89
103
|
}
|
|
90
|
-
if (defined(name)) {
|
|
91
|
-
this.addSet(name, lParts);
|
|
92
|
-
}
|
|
93
|
-
return lParts;
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
// ..........................................................
|
|
98
|
-
addSet(name, lSectionTree) {
|
|
99
|
-
var j, len, secName;
|
|
100
|
-
debug("enter addSet()", name, lSectionTree);
|
|
101
|
-
// --- check the name
|
|
102
|
-
assert(isSetName(name), `not a valid set name ${OL(name)}`);
|
|
103
|
-
// --- check lSectionTree
|
|
104
|
-
assert(isArray(lSectionTree), "arg 2 not an array");
|
|
105
|
-
for (j = 0, len = lSectionTree.length; j < len; j++) {
|
|
106
|
-
secName = lSectionTree[j];
|
|
107
|
-
assert(isNonEmptyString(secName), `not a non-empty string ${OL(secName)}`);
|
|
108
|
-
assert(defined(this.hSections[secName]), `not a section name ${OL(secName)}`);
|
|
109
104
|
}
|
|
110
|
-
this.hSets
|
|
111
|
-
debug('hSets', this.hSets);
|
|
112
|
-
debug("return from addSet()");
|
|
105
|
+
debug("return from build()", this.hSections, this.hSets);
|
|
113
106
|
}
|
|
114
107
|
|
|
115
108
|
// ..........................................................
|
|
116
|
-
// ---
|
|
117
|
-
//
|
|
118
|
-
//
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
109
|
+
// --- hProc should be <name> -> <function>
|
|
110
|
+
// <name> can be a section name or a set name
|
|
111
|
+
// <function> should be <block> -> <block>
|
|
112
|
+
// --- desc can be:
|
|
113
|
+
// an array, which may begin with a set name
|
|
114
|
+
// a section name
|
|
115
|
+
// a set name
|
|
116
|
+
// undef (equivalent to being set to @SectionTree)
|
|
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)) {
|
|
123
129
|
desc = this.lSectionTree;
|
|
124
130
|
}
|
|
125
131
|
if (isArray(desc)) {
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
+
lBlocks = [];
|
|
133
|
+
setName = undef;
|
|
134
|
+
for (i = 0, len = desc.length; i < len; i++) {
|
|
135
|
+
item = desc[i];
|
|
136
|
+
subBlock = undef;
|
|
137
|
+
if (isArray(item)) {
|
|
138
|
+
subBlock = this.getBlock(item, hReplacers);
|
|
139
|
+
} else if (isSectionName(item)) {
|
|
140
|
+
subBlock = this.getBlock(item, hReplacers);
|
|
132
141
|
} else if (isSetName(item)) {
|
|
133
|
-
|
|
142
|
+
setName = item;
|
|
143
|
+
} else if (isString(item)) {
|
|
144
|
+
subBlock = item; // a literal string
|
|
145
|
+
} else {
|
|
146
|
+
croak(`Bad item: ${OL(item)}`);
|
|
147
|
+
}
|
|
148
|
+
if (defined(subBlock)) {
|
|
149
|
+
lBlocks.push(subBlock);
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
block = arrayToBlock(lBlocks);
|
|
153
|
+
if (defined(setName)) {
|
|
154
|
+
if (defined(proc = hReplacers[setName])) {
|
|
155
|
+
debug(`REPLACE ${setName}`);
|
|
156
|
+
block = proc(block);
|
|
134
157
|
} else {
|
|
135
|
-
|
|
136
|
-
yield* this.allSections(item, level + 1);
|
|
158
|
+
debug(`NO REPLACER for ${setName}`);
|
|
137
159
|
}
|
|
138
160
|
}
|
|
139
161
|
} else if (isSectionName(desc)) {
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
162
|
+
block = this.section(desc).getBlock();
|
|
163
|
+
if (defined(proc = hReplacers[desc])) {
|
|
164
|
+
debug(`REPLACE ${desc}`);
|
|
165
|
+
block = proc(block);
|
|
166
|
+
} else {
|
|
167
|
+
debug(`NO REPLACER for ${desc}`);
|
|
168
|
+
}
|
|
143
169
|
} else if (isSetName(desc)) {
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
yield* this.allSections(lTree, level);
|
|
170
|
+
// --- pass array to getBlock()
|
|
171
|
+
block = this.getBlock(this.hSets[desc], hReplacers);
|
|
147
172
|
} else {
|
|
148
|
-
croak(`Bad
|
|
173
|
+
croak(`Bad 1st arg: ${OL(desc)}`);
|
|
149
174
|
}
|
|
150
|
-
debug("return from
|
|
175
|
+
debug("return from SectionMap.getBlock()", block);
|
|
176
|
+
return block;
|
|
151
177
|
}
|
|
152
178
|
|
|
153
179
|
// ..........................................................
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
lTree = this.lSectionTree;
|
|
162
|
-
} else {
|
|
163
|
-
assert(isArray(lTree), `not an array ${OL(lTree)}`);
|
|
164
|
-
}
|
|
165
|
-
lParts = [];
|
|
166
|
-
for (j = 0, len = lTree.length; j < len; j++) {
|
|
167
|
-
part = lTree[j];
|
|
168
|
-
if (isString(part)) {
|
|
169
|
-
block = this.section(part).getBlock();
|
|
170
|
-
if (defined(hProc[part])) {
|
|
171
|
-
// --- called even if block is empty
|
|
172
|
-
block = hProc[part](block);
|
|
173
|
-
}
|
|
174
|
-
} else if (isNonEmptyArray(part)) {
|
|
175
|
-
if (isSectionName(part[0])) {
|
|
176
|
-
block = this.getBlock(hProc, part);
|
|
177
|
-
} else if (isSetName(part[0])) {
|
|
178
|
-
block = this.getBlock(hProc, part.slice(1));
|
|
179
|
-
if (defined(hProc[part[0]])) {
|
|
180
|
-
block = hProc[part[0]](block);
|
|
181
|
-
}
|
|
182
|
-
} else {
|
|
183
|
-
croak(`Bad part: ${OL(part)}`);
|
|
184
|
-
}
|
|
185
|
-
} else {
|
|
186
|
-
croak(`Bad part: ${OL(part)}`);
|
|
180
|
+
isEmpty() {
|
|
181
|
+
var name, ref, sect;
|
|
182
|
+
ref = this.hSections;
|
|
183
|
+
for (name in ref) {
|
|
184
|
+
sect = ref[name];
|
|
185
|
+
if (sect.nonEmpty()) {
|
|
186
|
+
return false;
|
|
187
187
|
}
|
|
188
|
-
|
|
189
|
-
|
|
188
|
+
}
|
|
189
|
+
return true;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
// ..........................................................
|
|
193
|
+
nonEmpty() {
|
|
194
|
+
var name, ref, sect;
|
|
195
|
+
ref = this.hSections;
|
|
196
|
+
for (name in ref) {
|
|
197
|
+
sect = ref[name];
|
|
198
|
+
if (sect.nonEmpty()) {
|
|
199
|
+
return true;
|
|
190
200
|
}
|
|
191
201
|
}
|
|
192
|
-
|
|
193
|
-
result = arrayToBlock(lParts);
|
|
194
|
-
debug("return from getBlock()", result);
|
|
195
|
-
return result;
|
|
202
|
+
return false;
|
|
196
203
|
}
|
|
197
204
|
|
|
198
205
|
// ..........................................................
|
|
@@ -205,59 +212,20 @@ export var SectionMap = class SectionMap {
|
|
|
205
212
|
|
|
206
213
|
// ..........................................................
|
|
207
214
|
firstSection(name) {
|
|
208
|
-
var
|
|
215
|
+
var lSubTree;
|
|
209
216
|
assert(isSetName(name), `bad set name ${OL(name)}`);
|
|
210
|
-
|
|
211
|
-
assert(defined(
|
|
212
|
-
|
|
213
|
-
return this.section(lSectionTree[0]);
|
|
217
|
+
lSubTree = this.hSets[name];
|
|
218
|
+
assert(defined(lSubTree), `no such set ${OL(name)}`);
|
|
219
|
+
return this.section(lSubTree[1]);
|
|
214
220
|
}
|
|
215
221
|
|
|
216
222
|
// ..........................................................
|
|
217
223
|
lastSection(name) {
|
|
218
|
-
var
|
|
224
|
+
var lSubTree;
|
|
219
225
|
assert(isSetName(name), `bad set name ${OL(name)}`);
|
|
220
|
-
|
|
221
|
-
assert(defined(
|
|
222
|
-
|
|
223
|
-
return this.section(lSectionTree[lSectionTree.length - 1]);
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
// ..........................................................
|
|
227
|
-
length(desc = undef) {
|
|
228
|
-
var _, ref, result, sect, x;
|
|
229
|
-
result = 0;
|
|
230
|
-
ref = this.allSections(desc);
|
|
231
|
-
for (x of ref) {
|
|
232
|
-
[_, sect] = x;
|
|
233
|
-
result += sect.length();
|
|
234
|
-
}
|
|
235
|
-
return result;
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
// ..........................................................
|
|
239
|
-
isEmpty(desc = undef) {
|
|
240
|
-
return this.length(desc) === 0;
|
|
241
|
-
}
|
|
242
|
-
|
|
243
|
-
// ..........................................................
|
|
244
|
-
nonEmpty(desc = undef) {
|
|
245
|
-
return this.length(desc) > 0;
|
|
246
|
-
}
|
|
247
|
-
|
|
248
|
-
// ..........................................................
|
|
249
|
-
getShape() {
|
|
250
|
-
var lParts, level, ref, result, sect, x;
|
|
251
|
-
debug("enter getShape()");
|
|
252
|
-
lParts = [];
|
|
253
|
-
ref = this.allSections();
|
|
254
|
-
for (x of ref) {
|
|
255
|
-
[level, sect] = x;
|
|
256
|
-
lParts.push(indented(sect.name, level));
|
|
257
|
-
}
|
|
258
|
-
result = arrayToBlock(lParts);
|
|
259
|
-
debug("return from getShape()", result);
|
|
260
|
-
return result;
|
|
226
|
+
lSubTree = this.hSets[name];
|
|
227
|
+
assert(defined(lSubTree), `no such set ${OL(name)}`);
|
|
228
|
+
return this.section(lSubTree[lSubTree.length - 1]);
|
|
261
229
|
}
|
|
262
230
|
|
|
263
231
|
};
|
package/src/block_utils.coffee
CHANGED
|
@@ -25,6 +25,23 @@ export blockToArray = (block) ->
|
|
|
25
25
|
len -= 1
|
|
26
26
|
return lLines
|
|
27
27
|
|
|
28
|
+
# ---------------------------------------------------------------------------
|
|
29
|
+
# toArray - split a block or array into lines w/o newlines
|
|
30
|
+
|
|
31
|
+
export toArray = (item) ->
|
|
32
|
+
|
|
33
|
+
if isString(item)
|
|
34
|
+
return item.split(/\r?\n/)
|
|
35
|
+
else if isArray(item)
|
|
36
|
+
# --- We still need to ensure that no strings contain newlines
|
|
37
|
+
lLines = []
|
|
38
|
+
for str in item
|
|
39
|
+
for substr in toArray(str)
|
|
40
|
+
lLines.push substr
|
|
41
|
+
return lLines
|
|
42
|
+
else
|
|
43
|
+
croak "Not a string or array"
|
|
44
|
+
|
|
28
45
|
# ---------------------------------------------------------------------------
|
|
29
46
|
# arrayToBlock - block will have no trailing whitespace
|
|
30
47
|
|
|
@@ -39,6 +56,21 @@ export arrayToBlock = (lLines) ->
|
|
|
39
56
|
else
|
|
40
57
|
return rtrim(lLines.join('\n'))
|
|
41
58
|
|
|
59
|
+
# ---------------------------------------------------------------------------
|
|
60
|
+
# toBlock - block may have trailing whitespace
|
|
61
|
+
# but undef items are ignored
|
|
62
|
+
|
|
63
|
+
export toBlock = (lLines) ->
|
|
64
|
+
|
|
65
|
+
if (lLines == undef)
|
|
66
|
+
return undef
|
|
67
|
+
assert isArray(lLines), "lLines is not an array"
|
|
68
|
+
lLines = lLines.filter((line) => defined(line));
|
|
69
|
+
if lLines.length == 0
|
|
70
|
+
return undef
|
|
71
|
+
else
|
|
72
|
+
return lLines.join('\n')
|
|
73
|
+
|
|
42
74
|
# ---------------------------------------------------------------------------
|
|
43
75
|
|
|
44
76
|
export splitBlock = (block) ->
|
package/src/block_utils.js
CHANGED
|
@@ -37,6 +37,29 @@ export var blockToArray = function(block) {
|
|
|
37
37
|
}
|
|
38
38
|
};
|
|
39
39
|
|
|
40
|
+
// ---------------------------------------------------------------------------
|
|
41
|
+
// toArray - split a block or array into lines w/o newlines
|
|
42
|
+
export var toArray = function(item) {
|
|
43
|
+
var i, j, lLines, len1, len2, ref, str, substr;
|
|
44
|
+
if (isString(item)) {
|
|
45
|
+
return item.split(/\r?\n/);
|
|
46
|
+
} else if (isArray(item)) {
|
|
47
|
+
// --- We still need to ensure that no strings contain newlines
|
|
48
|
+
lLines = [];
|
|
49
|
+
for (i = 0, len1 = item.length; i < len1; i++) {
|
|
50
|
+
str = item[i];
|
|
51
|
+
ref = toArray(str);
|
|
52
|
+
for (j = 0, len2 = ref.length; j < len2; j++) {
|
|
53
|
+
substr = ref[j];
|
|
54
|
+
lLines.push(substr);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
return lLines;
|
|
58
|
+
} else {
|
|
59
|
+
return croak("Not a string or array");
|
|
60
|
+
}
|
|
61
|
+
};
|
|
62
|
+
|
|
40
63
|
// ---------------------------------------------------------------------------
|
|
41
64
|
// arrayToBlock - block will have no trailing whitespace
|
|
42
65
|
export var arrayToBlock = function(lLines) {
|
|
@@ -54,6 +77,24 @@ export var arrayToBlock = function(lLines) {
|
|
|
54
77
|
}
|
|
55
78
|
};
|
|
56
79
|
|
|
80
|
+
// ---------------------------------------------------------------------------
|
|
81
|
+
// toBlock - block may have trailing whitespace
|
|
82
|
+
// but undef items are ignored
|
|
83
|
+
export var toBlock = function(lLines) {
|
|
84
|
+
if (lLines === undef) {
|
|
85
|
+
return undef;
|
|
86
|
+
}
|
|
87
|
+
assert(isArray(lLines), "lLines is not an array");
|
|
88
|
+
lLines = lLines.filter((line) => {
|
|
89
|
+
return defined(line);
|
|
90
|
+
});
|
|
91
|
+
if (lLines.length === 0) {
|
|
92
|
+
return undef;
|
|
93
|
+
} else {
|
|
94
|
+
return lLines.join('\n');
|
|
95
|
+
}
|
|
96
|
+
};
|
|
97
|
+
|
|
57
98
|
// ---------------------------------------------------------------------------
|
|
58
99
|
export var splitBlock = function(block) {
|
|
59
100
|
var pos;
|
package/src/coffee_utils.coffee
CHANGED
|
@@ -51,6 +51,17 @@ export patchStr = (bigstr, pos, str) ->
|
|
|
51
51
|
|
|
52
52
|
# ---------------------------------------------------------------------------
|
|
53
53
|
|
|
54
|
+
export charCount = (str, ch) ->
|
|
55
|
+
|
|
56
|
+
count = 0
|
|
57
|
+
pos = str.indexOf(ch, 0)
|
|
58
|
+
while (pos >= 0)
|
|
59
|
+
count += 1
|
|
60
|
+
pos = str.indexOf(ch, pos+1)
|
|
61
|
+
return count
|
|
62
|
+
|
|
63
|
+
# ---------------------------------------------------------------------------
|
|
64
|
+
|
|
54
65
|
export isString = (x) ->
|
|
55
66
|
|
|
56
67
|
return (typeof x == 'string') || (x instanceof String)
|
package/src/coffee_utils.js
CHANGED
|
@@ -56,6 +56,18 @@ export var patchStr = function(bigstr, pos, str) {
|
|
|
56
56
|
}
|
|
57
57
|
};
|
|
58
58
|
|
|
59
|
+
// ---------------------------------------------------------------------------
|
|
60
|
+
export var charCount = function(str, ch) {
|
|
61
|
+
var count, pos;
|
|
62
|
+
count = 0;
|
|
63
|
+
pos = str.indexOf(ch, 0);
|
|
64
|
+
while (pos >= 0) {
|
|
65
|
+
count += 1;
|
|
66
|
+
pos = str.indexOf(ch, pos + 1);
|
|
67
|
+
}
|
|
68
|
+
return count;
|
|
69
|
+
};
|
|
70
|
+
|
|
59
71
|
// ---------------------------------------------------------------------------
|
|
60
72
|
export var isString = function(x) {
|
|
61
73
|
return (typeof x === 'string') || (x instanceof String);
|
package/src/indent_utils.coffee
CHANGED
|
@@ -5,7 +5,9 @@ import {
|
|
|
5
5
|
undef, escapeStr, defined,
|
|
6
6
|
OL, isInteger, isString, isArray, isEmpty, rtrim,
|
|
7
7
|
} from '@jdeighan/coffee-utils'
|
|
8
|
-
import {
|
|
8
|
+
import {
|
|
9
|
+
arrayToBlock, blockToArray, toArray, toBlock,
|
|
10
|
+
} from '@jdeighan/coffee-utils/block'
|
|
9
11
|
|
|
10
12
|
# ---------------------------------------------------------------------------
|
|
11
13
|
|
|
@@ -71,14 +73,11 @@ export isUndented = (line) ->
|
|
|
71
73
|
export indented = (input, level=1, oneIndent="\t") ->
|
|
72
74
|
|
|
73
75
|
assert (level >= 0), "indented(): negative level"
|
|
74
|
-
if level == 0
|
|
76
|
+
if (level == 0)
|
|
75
77
|
return input
|
|
76
78
|
|
|
77
79
|
toAdd = indentation(level, oneIndent)
|
|
78
|
-
|
|
79
|
-
lInputLines = input
|
|
80
|
-
else
|
|
81
|
-
lInputLines = blockToArray(input)
|
|
80
|
+
lInputLines = toArray(input)
|
|
82
81
|
|
|
83
82
|
lLines = for line in lInputLines
|
|
84
83
|
if isEmpty(line)
|
|
@@ -93,27 +92,18 @@ export indented = (input, level=1, oneIndent="\t") ->
|
|
|
93
92
|
# indentation is removed
|
|
94
93
|
# - returns same type as text, i.e. either string or array
|
|
95
94
|
|
|
96
|
-
export undented = (
|
|
95
|
+
export undented = (input, level=undef, oneIndent="\t") ->
|
|
97
96
|
|
|
98
97
|
if defined(level) && (level==0)
|
|
99
|
-
return
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
return ''
|
|
105
|
-
else if isArray(text)
|
|
106
|
-
lLines = text
|
|
107
|
-
for line in lLines
|
|
108
|
-
assert isString(line), "undented(): array not all strings"
|
|
109
|
-
if (lLines.length == 0)
|
|
110
|
-
return []
|
|
111
|
-
else
|
|
112
|
-
error "undented(): Not an array or string: #{OL(text)}"
|
|
98
|
+
return input
|
|
99
|
+
|
|
100
|
+
lLines = toArray(input)
|
|
101
|
+
if (lLines.length == 0)
|
|
102
|
+
return ''
|
|
113
103
|
|
|
114
104
|
# --- determine what to remove from beginning of each line
|
|
115
105
|
if defined(level)
|
|
116
|
-
assert isInteger(level), "
|
|
106
|
+
assert isInteger(level), "level must be an integer"
|
|
117
107
|
toRemove = indentation(level, oneIndent)
|
|
118
108
|
else
|
|
119
109
|
lMatches = lLines[0].match(/^\s*/)
|
|
@@ -129,8 +119,8 @@ export undented = (text, level=undef, oneIndent="\t") ->
|
|
|
129
119
|
throw new Error("remove #{OL(toRemove)} from #{OL(text)}")
|
|
130
120
|
lNewLines.push(line.substr(nToRemove))
|
|
131
121
|
|
|
132
|
-
if isString(
|
|
133
|
-
return
|
|
122
|
+
if isString(input)
|
|
123
|
+
return toBlock(lNewLines)
|
|
134
124
|
else
|
|
135
125
|
return lNewLines
|
|
136
126
|
|
|
@@ -167,6 +157,21 @@ export untabify = (str, numSpaces=3) ->
|
|
|
167
157
|
# ---------------------------------------------------------------------------
|
|
168
158
|
# enclose - indent text, surround with pre and post
|
|
169
159
|
|
|
170
|
-
export enclose = (text, pre, post) ->
|
|
160
|
+
export enclose = (text, pre, post, oneIndent="\t") ->
|
|
161
|
+
|
|
162
|
+
return arrayToBlock([
|
|
163
|
+
pre
|
|
164
|
+
indented(text, 1, oneIndent)
|
|
165
|
+
post
|
|
166
|
+
])
|
|
167
|
+
|
|
168
|
+
# ---------------------------------------------------------------------------
|
|
169
|
+
# elem - indent text, surround with HTML tags
|
|
170
|
+
|
|
171
|
+
export elem = (text, tag, oneIndent="\t") ->
|
|
171
172
|
|
|
172
|
-
return
|
|
173
|
+
return arrayToBlock([
|
|
174
|
+
"<#{tag}>"
|
|
175
|
+
indented(text, 1, oneIndent)
|
|
176
|
+
"</#{tag}>"
|
|
177
|
+
])
|
package/src/indent_utils.js
CHANGED
|
@@ -19,7 +19,9 @@ import {
|
|
|
19
19
|
|
|
20
20
|
import {
|
|
21
21
|
arrayToBlock,
|
|
22
|
-
blockToArray
|
|
22
|
+
blockToArray,
|
|
23
|
+
toArray,
|
|
24
|
+
toBlock
|
|
23
25
|
} from '@jdeighan/coffee-utils/block';
|
|
24
26
|
|
|
25
27
|
// ---------------------------------------------------------------------------
|
|
@@ -87,11 +89,7 @@ export var indented = function(input, level = 1, oneIndent = "\t") {
|
|
|
87
89
|
return input;
|
|
88
90
|
}
|
|
89
91
|
toAdd = indentation(level, oneIndent);
|
|
90
|
-
|
|
91
|
-
lInputLines = input;
|
|
92
|
-
} else {
|
|
93
|
-
lInputLines = blockToArray(input);
|
|
94
|
-
}
|
|
92
|
+
lInputLines = toArray(input);
|
|
95
93
|
lLines = (function() {
|
|
96
94
|
var i, len1, results;
|
|
97
95
|
results = [];
|
|
@@ -113,31 +111,18 @@ export var indented = function(input, level = 1, oneIndent = "\t") {
|
|
|
113
111
|
// - unless level is set, in which case exactly that
|
|
114
112
|
// indentation is removed
|
|
115
113
|
// - returns same type as text, i.e. either string or array
|
|
116
|
-
export var undented = function(
|
|
117
|
-
var i,
|
|
114
|
+
export var undented = function(input, level = undef, oneIndent = "\t") {
|
|
115
|
+
var i, lLines, lMatches, lNewLines, len1, line, nToRemove, toRemove;
|
|
118
116
|
if (defined(level) && (level === 0)) {
|
|
119
|
-
return
|
|
117
|
+
return input;
|
|
120
118
|
}
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
return '';
|
|
125
|
-
}
|
|
126
|
-
} else if (isArray(text)) {
|
|
127
|
-
lLines = text;
|
|
128
|
-
for (i = 0, len1 = lLines.length; i < len1; i++) {
|
|
129
|
-
line = lLines[i];
|
|
130
|
-
assert(isString(line), "undented(): array not all strings");
|
|
131
|
-
}
|
|
132
|
-
if (lLines.length === 0) {
|
|
133
|
-
return [];
|
|
134
|
-
}
|
|
135
|
-
} else {
|
|
136
|
-
error(`undented(): Not an array or string: ${OL(text)}`);
|
|
119
|
+
lLines = toArray(input);
|
|
120
|
+
if (lLines.length === 0) {
|
|
121
|
+
return '';
|
|
137
122
|
}
|
|
138
123
|
// --- determine what to remove from beginning of each line
|
|
139
124
|
if (defined(level)) {
|
|
140
|
-
assert(isInteger(level), "
|
|
125
|
+
assert(isInteger(level), "level must be an integer");
|
|
141
126
|
toRemove = indentation(level, oneIndent);
|
|
142
127
|
} else {
|
|
143
128
|
lMatches = lLines[0].match(/^\s*/);
|
|
@@ -145,8 +130,8 @@ export var undented = function(text, level = undef, oneIndent = "\t") {
|
|
|
145
130
|
}
|
|
146
131
|
nToRemove = indentLevel(toRemove);
|
|
147
132
|
lNewLines = [];
|
|
148
|
-
for (
|
|
149
|
-
line = lLines[
|
|
133
|
+
for (i = 0, len1 = lLines.length; i < len1; i++) {
|
|
134
|
+
line = lLines[i];
|
|
150
135
|
if (isEmpty(line)) {
|
|
151
136
|
lNewLines.push('');
|
|
152
137
|
} else {
|
|
@@ -156,8 +141,8 @@ export var undented = function(text, level = undef, oneIndent = "\t") {
|
|
|
156
141
|
lNewLines.push(line.substr(nToRemove));
|
|
157
142
|
}
|
|
158
143
|
}
|
|
159
|
-
if (isString(
|
|
160
|
-
return
|
|
144
|
+
if (isString(input)) {
|
|
145
|
+
return toBlock(lNewLines);
|
|
161
146
|
} else {
|
|
162
147
|
return lNewLines;
|
|
163
148
|
}
|
|
@@ -199,6 +184,12 @@ export var untabify = function(str, numSpaces = 3) {
|
|
|
199
184
|
|
|
200
185
|
// ---------------------------------------------------------------------------
|
|
201
186
|
// enclose - indent text, surround with pre and post
|
|
202
|
-
export var enclose = function(text, pre, post) {
|
|
203
|
-
return pre
|
|
187
|
+
export var enclose = function(text, pre, post, oneIndent = "\t") {
|
|
188
|
+
return arrayToBlock([pre, indented(text, 1, oneIndent), post]);
|
|
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}>`]);
|
|
204
195
|
};
|