@jdeighan/coffee-utils 8.0.4 → 8.0.7
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 +21 -12
- package/src/Section.js +22 -12
- package/src/SectionMap.coffee +117 -120
- package/src/SectionMap.js +143 -143
- package/src/block_utils.coffee +17 -5
- package/src/block_utils.js +17 -5
- package/src/coffee_utils.coffee +12 -0
- package/src/coffee_utils.js +10 -0
- package/src/indent_utils.coffee +7 -0
- package/src/indent_utils.js +6 -0
package/package.json
CHANGED
package/src/Section.coffee
CHANGED
|
@@ -10,36 +10,36 @@ import {indented} from '@jdeighan/coffee-utils/indent'
|
|
|
10
10
|
|
|
11
11
|
export class Section
|
|
12
12
|
|
|
13
|
-
constructor: () ->
|
|
13
|
+
constructor: (@name) ->
|
|
14
14
|
|
|
15
|
-
@
|
|
15
|
+
@lParts = []
|
|
16
16
|
|
|
17
17
|
# ..........................................................
|
|
18
18
|
|
|
19
19
|
length: () ->
|
|
20
20
|
|
|
21
|
-
return @
|
|
21
|
+
return @lParts.length
|
|
22
22
|
|
|
23
23
|
# ..........................................................
|
|
24
24
|
|
|
25
25
|
indent: (level=1) ->
|
|
26
26
|
|
|
27
|
-
lNewLines = for line in @
|
|
27
|
+
lNewLines = for line in @lParts
|
|
28
28
|
indented(line, level)
|
|
29
|
-
@
|
|
29
|
+
@lParts = lNewLines
|
|
30
30
|
return
|
|
31
31
|
|
|
32
32
|
# ..........................................................
|
|
33
33
|
|
|
34
34
|
isEmpty: () ->
|
|
35
35
|
|
|
36
|
-
return (@
|
|
36
|
+
return (@lParts.length == 0)
|
|
37
37
|
|
|
38
38
|
# ..........................................................
|
|
39
39
|
|
|
40
40
|
nonEmpty: () ->
|
|
41
41
|
|
|
42
|
-
return (@
|
|
42
|
+
return (@lParts.length > 0)
|
|
43
43
|
|
|
44
44
|
# ..........................................................
|
|
45
45
|
|
|
@@ -47,9 +47,9 @@ export class Section
|
|
|
47
47
|
|
|
48
48
|
if isArray(data)
|
|
49
49
|
for line in data
|
|
50
|
-
@
|
|
50
|
+
@lParts.push line
|
|
51
51
|
else
|
|
52
|
-
@
|
|
52
|
+
@lParts.push data
|
|
53
53
|
return
|
|
54
54
|
|
|
55
55
|
# ..........................................................
|
|
@@ -57,13 +57,22 @@ export class Section
|
|
|
57
57
|
prepend: (data) ->
|
|
58
58
|
|
|
59
59
|
if isArray(data)
|
|
60
|
-
@
|
|
60
|
+
@lParts = [data..., @lParts...]
|
|
61
61
|
else
|
|
62
|
-
@
|
|
62
|
+
@lParts = [data, @lParts...]
|
|
63
63
|
return
|
|
64
64
|
|
|
65
65
|
# ..........................................................
|
|
66
66
|
|
|
67
|
+
getParts: () ->
|
|
68
|
+
|
|
69
|
+
return @lParts
|
|
70
|
+
|
|
71
|
+
# ..........................................................
|
|
72
|
+
|
|
67
73
|
getBlock: () ->
|
|
68
74
|
|
|
69
|
-
|
|
75
|
+
if (@lParts.length == 0)
|
|
76
|
+
return undef
|
|
77
|
+
else
|
|
78
|
+
return arrayToBlock(@lParts)
|
package/src/Section.js
CHANGED
|
@@ -19,13 +19,14 @@ import {
|
|
|
19
19
|
|
|
20
20
|
// ---------------------------------------------------------------------------
|
|
21
21
|
export var Section = class Section {
|
|
22
|
-
constructor() {
|
|
23
|
-
this.
|
|
22
|
+
constructor(name) {
|
|
23
|
+
this.name = name;
|
|
24
|
+
this.lParts = [];
|
|
24
25
|
}
|
|
25
26
|
|
|
26
27
|
// ..........................................................
|
|
27
28
|
length() {
|
|
28
|
-
return this.
|
|
29
|
+
return this.lParts.length;
|
|
29
30
|
}
|
|
30
31
|
|
|
31
32
|
// ..........................................................
|
|
@@ -33,7 +34,7 @@ export var Section = class Section {
|
|
|
33
34
|
var lNewLines, line;
|
|
34
35
|
lNewLines = (function() {
|
|
35
36
|
var i, len, ref, results;
|
|
36
|
-
ref = this.
|
|
37
|
+
ref = this.lParts;
|
|
37
38
|
results = [];
|
|
38
39
|
for (i = 0, len = ref.length; i < len; i++) {
|
|
39
40
|
line = ref[i];
|
|
@@ -41,17 +42,17 @@ export var Section = class Section {
|
|
|
41
42
|
}
|
|
42
43
|
return results;
|
|
43
44
|
}).call(this);
|
|
44
|
-
this.
|
|
45
|
+
this.lParts = lNewLines;
|
|
45
46
|
}
|
|
46
47
|
|
|
47
48
|
// ..........................................................
|
|
48
49
|
isEmpty() {
|
|
49
|
-
return this.
|
|
50
|
+
return this.lParts.length === 0;
|
|
50
51
|
}
|
|
51
52
|
|
|
52
53
|
// ..........................................................
|
|
53
54
|
nonEmpty() {
|
|
54
|
-
return this.
|
|
55
|
+
return this.lParts.length > 0;
|
|
55
56
|
}
|
|
56
57
|
|
|
57
58
|
// ..........................................................
|
|
@@ -60,25 +61,34 @@ export var Section = class Section {
|
|
|
60
61
|
if (isArray(data)) {
|
|
61
62
|
for (i = 0, len = data.length; i < len; i++) {
|
|
62
63
|
line = data[i];
|
|
63
|
-
this.
|
|
64
|
+
this.lParts.push(line);
|
|
64
65
|
}
|
|
65
66
|
} else {
|
|
66
|
-
this.
|
|
67
|
+
this.lParts.push(data);
|
|
67
68
|
}
|
|
68
69
|
}
|
|
69
70
|
|
|
70
71
|
// ..........................................................
|
|
71
72
|
prepend(data) {
|
|
72
73
|
if (isArray(data)) {
|
|
73
|
-
this.
|
|
74
|
+
this.lParts = [...data, ...this.lParts];
|
|
74
75
|
} else {
|
|
75
|
-
this.
|
|
76
|
+
this.lParts = [data, ...this.lParts];
|
|
76
77
|
}
|
|
77
78
|
}
|
|
78
79
|
|
|
80
|
+
// ..........................................................
|
|
81
|
+
getParts() {
|
|
82
|
+
return this.lParts;
|
|
83
|
+
}
|
|
84
|
+
|
|
79
85
|
// ..........................................................
|
|
80
86
|
getBlock() {
|
|
81
|
-
|
|
87
|
+
if (this.lParts.length === 0) {
|
|
88
|
+
return undef;
|
|
89
|
+
} else {
|
|
90
|
+
return arrayToBlock(this.lParts);
|
|
91
|
+
}
|
|
82
92
|
}
|
|
83
93
|
|
|
84
94
|
};
|
package/src/SectionMap.coffee
CHANGED
|
@@ -3,8 +3,10 @@
|
|
|
3
3
|
import {
|
|
4
4
|
assert, pass, undef, defined, croak, OL, isEmpty, nonEmpty,
|
|
5
5
|
isString, isHash, isArray, isUniqueTree, isNonEmptyString,
|
|
6
|
+
isNonEmptyArray,
|
|
6
7
|
} from '@jdeighan/coffee-utils'
|
|
7
8
|
import {arrayToBlock} from '@jdeighan/coffee-utils/block'
|
|
9
|
+
import {indented} from '@jdeighan/coffee-utils/indent'
|
|
8
10
|
import {debug} from '@jdeighan/coffee-utils/debug'
|
|
9
11
|
import {Section} from '@jdeighan/coffee-utils/section'
|
|
10
12
|
|
|
@@ -12,110 +14,148 @@ import {Section} from '@jdeighan/coffee-utils/section'
|
|
|
12
14
|
|
|
13
15
|
isSectionName = (name) ->
|
|
14
16
|
|
|
15
|
-
|
|
16
|
-
return name.match(/^[a-z][a-z0-9]*/)
|
|
17
|
+
return isString(name) && name.match(/^[a-z][a-z0-9]*/)
|
|
17
18
|
|
|
18
19
|
# ---------------------------------------------------------------------------
|
|
19
20
|
|
|
20
21
|
isSetName = (name) ->
|
|
21
22
|
|
|
22
|
-
|
|
23
|
-
return name.match(/^[A-Z][a-z0-9]*/)
|
|
23
|
+
return isString(name) && name.match(/^[A-Z][a-z0-9]*/)
|
|
24
24
|
|
|
25
25
|
# ---------------------------------------------------------------------------
|
|
26
26
|
|
|
27
27
|
export class SectionMap
|
|
28
28
|
|
|
29
|
-
constructor: (
|
|
30
|
-
# ---
|
|
29
|
+
constructor: (lSectionTree) ->
|
|
30
|
+
# --- lSectionTree is a tree of section names
|
|
31
31
|
|
|
32
|
-
debug "enter SectionMap()",
|
|
33
|
-
@
|
|
32
|
+
debug "enter SectionMap()", lSectionTree
|
|
33
|
+
@lSectionTree = lSectionTree # a tree of section names
|
|
34
34
|
@hSets = {}
|
|
35
35
|
@hSections = {}
|
|
36
|
-
@addSections
|
|
36
|
+
@addSections lSectionTree
|
|
37
37
|
debug "return from SectionMap()", @hSections
|
|
38
38
|
|
|
39
39
|
# ..........................................................
|
|
40
40
|
|
|
41
|
-
# --- TODO: Allow array to start with a set name ---
|
|
42
|
-
|
|
43
41
|
addSections: (desc) ->
|
|
42
|
+
# --- returns a flat array of sections that were added
|
|
44
43
|
|
|
45
44
|
if isString(desc)
|
|
46
45
|
assert nonEmpty(desc), "empty section name"
|
|
47
|
-
assert desc
|
|
46
|
+
assert isSectionName(desc), "bad section name #{OL(desc)}"
|
|
48
47
|
assert (@hSections[desc] == undef), "duplicate section #{OL(desc)}"
|
|
49
|
-
@hSections[desc] = new Section()
|
|
48
|
+
@hSections[desc] = new Section(desc)
|
|
49
|
+
return [desc]
|
|
50
50
|
else
|
|
51
51
|
assert isArray(desc), "not an array or string #{OL(desc)}"
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
# --- a generator - yield order is not guaranteed
|
|
58
|
-
|
|
59
|
-
allSections: (desc) ->
|
|
60
|
-
|
|
61
|
-
debug "enter allSections()"
|
|
62
|
-
if (desc == undef)
|
|
63
|
-
# --- We want to return all sections
|
|
64
|
-
debug "yield all sections"
|
|
65
|
-
for _,sect of @hSections
|
|
66
|
-
yield sect
|
|
67
|
-
else if isString(desc)
|
|
68
|
-
if isSectionName(desc)
|
|
69
|
-
debug "yield section #{OL(desc)}"
|
|
70
|
-
yield @section(desc)
|
|
71
|
-
else if isSetName(desc)
|
|
72
|
-
debug "expand set #{OL(desc)}"
|
|
73
|
-
debug 'hSets', @hSets
|
|
74
|
-
lNames = @hSets[desc]
|
|
75
|
-
assert defined(lNames), "no set named #{OL(desc)}"
|
|
76
|
-
debug "set #{desc}", lNames
|
|
77
|
-
for name in lNames
|
|
78
|
-
debug "yield section #{OL(desc)}"
|
|
79
|
-
yield @section(name)
|
|
80
|
-
else
|
|
81
|
-
croak "bad name #{OL(desc)}"
|
|
82
|
-
else
|
|
83
|
-
assert isArray(desc), "not an array"
|
|
84
|
-
for name in desc
|
|
85
|
-
debug "yield section #{OL(name)}"
|
|
86
|
-
assert isString(name), "not a string #{OL(name)}"
|
|
87
|
-
if isSectionName(name)
|
|
88
|
-
yield @section(name)
|
|
89
|
-
else if isSetName(name)
|
|
90
|
-
for _,sect of @hSets[name]
|
|
91
|
-
yield sect
|
|
52
|
+
name = undef
|
|
53
|
+
lParts = []
|
|
54
|
+
for item,i in desc
|
|
55
|
+
if (i==0) && isSetName(item)
|
|
56
|
+
name = item
|
|
92
57
|
else
|
|
93
|
-
|
|
94
|
-
|
|
58
|
+
lAdded = @addSections item
|
|
59
|
+
for item in lAdded
|
|
60
|
+
lParts.push item
|
|
61
|
+
if defined(name)
|
|
62
|
+
@addSet name, lParts
|
|
63
|
+
return lParts
|
|
95
64
|
return
|
|
96
65
|
|
|
97
66
|
# ..........................................................
|
|
98
67
|
|
|
99
|
-
addSet: (name,
|
|
68
|
+
addSet: (name, lSectionTree) ->
|
|
100
69
|
|
|
101
|
-
debug "enter addSet()", name,
|
|
70
|
+
debug "enter addSet()", name, lSectionTree
|
|
102
71
|
|
|
103
72
|
# --- check the name
|
|
104
73
|
assert isSetName(name), "not a valid set name #{OL(name)}"
|
|
105
74
|
|
|
106
|
-
# --- check
|
|
107
|
-
assert isArray(
|
|
108
|
-
for secName in
|
|
75
|
+
# --- check lSectionTree
|
|
76
|
+
assert isArray(lSectionTree), "arg 2 not an array"
|
|
77
|
+
for secName in lSectionTree
|
|
109
78
|
assert isNonEmptyString(secName),
|
|
110
79
|
"not a non-empty string #{OL(secName)}"
|
|
111
80
|
assert defined(@hSections[secName]),
|
|
112
81
|
"not a section name #{OL(secName)}"
|
|
113
82
|
|
|
114
|
-
@hSets[name] =
|
|
83
|
+
@hSets[name] = lSectionTree
|
|
115
84
|
debug 'hSets', @hSets
|
|
116
85
|
debug "return from addSet()"
|
|
117
86
|
return
|
|
118
87
|
|
|
88
|
+
# ..........................................................
|
|
89
|
+
# --- sections returned in depth-first order from section tree
|
|
90
|
+
# Set names are simply skipped
|
|
91
|
+
# yields: [<level>, <section>]
|
|
92
|
+
|
|
93
|
+
allSections: (desc=undef, level=0) ->
|
|
94
|
+
|
|
95
|
+
debug "enter allSections()", desc, level
|
|
96
|
+
if (desc == undef)
|
|
97
|
+
desc = @lSectionTree
|
|
98
|
+
if isArray(desc)
|
|
99
|
+
for item in desc
|
|
100
|
+
if isSectionName(item)
|
|
101
|
+
result = [level, @section(item)]
|
|
102
|
+
debug 'yield', result
|
|
103
|
+
yield result
|
|
104
|
+
else if isSetName(item)
|
|
105
|
+
pass
|
|
106
|
+
else
|
|
107
|
+
assert isArray(item), "not an array #{OL(item)}"
|
|
108
|
+
yield from @allSections(item, level+1)
|
|
109
|
+
else if isSectionName(desc)
|
|
110
|
+
result = [level, @section(desc)]
|
|
111
|
+
debug 'yield', result
|
|
112
|
+
yield result
|
|
113
|
+
else if isSetName(desc)
|
|
114
|
+
lTree = @hSets[desc]
|
|
115
|
+
assert defined(lTree), "Not a Set: #{OL(desc)}"
|
|
116
|
+
yield from @allSections(lTree, level)
|
|
117
|
+
else
|
|
118
|
+
croak "Bad item: #{OL(desc)}"
|
|
119
|
+
debug "return from allSections()"
|
|
120
|
+
return
|
|
121
|
+
|
|
122
|
+
# ..........................................................
|
|
123
|
+
# --- procFunc should be (name, block) ->
|
|
124
|
+
# return processed block
|
|
125
|
+
|
|
126
|
+
getBlock: (procFunc=undef, lTree=undef) ->
|
|
127
|
+
|
|
128
|
+
debug "enter getBlock()"
|
|
129
|
+
if (lTree == undef)
|
|
130
|
+
lTree = @lSectionTree
|
|
131
|
+
else
|
|
132
|
+
assert isArray(lTree), "not an array #{OL(lTree)}"
|
|
133
|
+
|
|
134
|
+
lParts = []
|
|
135
|
+
for part in lTree
|
|
136
|
+
if isString(part)
|
|
137
|
+
text = @section(part).getBlock()
|
|
138
|
+
if nonEmpty(text) && defined(procFunc)
|
|
139
|
+
text = procFunc(part, text)
|
|
140
|
+
else if isNonEmptyArray(part)
|
|
141
|
+
if isSectionName(part[0])
|
|
142
|
+
text = @getBlock(procFunc, part)
|
|
143
|
+
else if isSetName(part[0])
|
|
144
|
+
text = @getBlock(procFunc, part.slice(1))
|
|
145
|
+
if nonEmpty(text) && defined(procFunc)
|
|
146
|
+
text = procFunc(part[0], text)
|
|
147
|
+
else
|
|
148
|
+
croak "Bad part: #{OL(part)}"
|
|
149
|
+
else
|
|
150
|
+
croak "Bad part: #{OL(part)}"
|
|
151
|
+
if defined(text)
|
|
152
|
+
lParts.push text
|
|
153
|
+
|
|
154
|
+
debug 'lParts', lParts
|
|
155
|
+
result = arrayToBlock(lParts)
|
|
156
|
+
debug "return from getBlock()", result
|
|
157
|
+
return result
|
|
158
|
+
|
|
119
159
|
# ..........................................................
|
|
120
160
|
|
|
121
161
|
section: (name) ->
|
|
@@ -129,27 +169,27 @@ export class SectionMap
|
|
|
129
169
|
firstSection: (name) ->
|
|
130
170
|
|
|
131
171
|
assert isSetName(name), "bad set name #{OL(name)}"
|
|
132
|
-
|
|
133
|
-
assert defined(
|
|
134
|
-
assert nonEmpty(
|
|
135
|
-
return @section(
|
|
172
|
+
lSectionTree = @hSets[name]
|
|
173
|
+
assert defined(lSectionTree), "no such set #{OL(name)}"
|
|
174
|
+
assert nonEmpty(lSectionTree), "empty section #{OL(name)}"
|
|
175
|
+
return @section(lSectionTree[0])
|
|
136
176
|
|
|
137
177
|
# ..........................................................
|
|
138
178
|
|
|
139
179
|
lastSection: (name) ->
|
|
140
180
|
|
|
141
181
|
assert isSetName(name), "bad set name #{OL(name)}"
|
|
142
|
-
|
|
143
|
-
assert defined(
|
|
144
|
-
assert nonEmpty(
|
|
145
|
-
return @section(
|
|
182
|
+
lSectionTree = @hSets[name]
|
|
183
|
+
assert defined(lSectionTree), "no such set #{OL(name)}"
|
|
184
|
+
assert nonEmpty(lSectionTree), "empty section #{OL(name)}"
|
|
185
|
+
return @section(lSectionTree[lSectionTree.length - 1])
|
|
146
186
|
|
|
147
187
|
# ..........................................................
|
|
148
188
|
|
|
149
189
|
length: (desc=undef) ->
|
|
150
190
|
|
|
151
191
|
result = 0
|
|
152
|
-
for sect from @allSections(desc)
|
|
192
|
+
for [_, sect] from @allSections(desc)
|
|
153
193
|
result += sect.length()
|
|
154
194
|
return result
|
|
155
195
|
|
|
@@ -167,55 +207,12 @@ export class SectionMap
|
|
|
167
207
|
|
|
168
208
|
# ..........................................................
|
|
169
209
|
|
|
170
|
-
|
|
210
|
+
getShape: () ->
|
|
171
211
|
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
enclose: (name, pre, post) ->
|
|
179
|
-
|
|
180
|
-
if isSectionName(name)
|
|
181
|
-
sect = @section(name)
|
|
182
|
-
if sect.nonEmpty()
|
|
183
|
-
sect.indent()
|
|
184
|
-
sect.prepend(pre)
|
|
185
|
-
sect.add(post)
|
|
186
|
-
else if isSetName(name)
|
|
187
|
-
if @nonEmpty(name)
|
|
188
|
-
@indent(name)
|
|
189
|
-
@firstSection(name).prepend(pre)
|
|
190
|
-
@lastSection(name).add(post)
|
|
191
|
-
else
|
|
192
|
-
croak "Bad name param #{OL(name)}"
|
|
193
|
-
return
|
|
194
|
-
|
|
195
|
-
# ..........................................................
|
|
196
|
-
|
|
197
|
-
getBlock: () ->
|
|
198
|
-
|
|
199
|
-
debug "enter getBlock()"
|
|
200
|
-
@lAllBlocks = []
|
|
201
|
-
debug 'lSections', @lSections
|
|
202
|
-
@accumBlock @lSections
|
|
203
|
-
debug 'lAllBlocks', @lAllBlocks
|
|
204
|
-
result = arrayToBlock(@lAllBlocks)
|
|
205
|
-
debug "return from getBlock()", result
|
|
212
|
+
debug "enter getShape()"
|
|
213
|
+
lParts = []
|
|
214
|
+
for [level, sect] from @allSections()
|
|
215
|
+
lParts.push indented(sect.name, level)
|
|
216
|
+
result = arrayToBlock(lParts)
|
|
217
|
+
debug "return from getShape()", result
|
|
206
218
|
return result
|
|
207
|
-
|
|
208
|
-
# ..........................................................
|
|
209
|
-
|
|
210
|
-
accumBlock: (tree) ->
|
|
211
|
-
|
|
212
|
-
if isString(tree)
|
|
213
|
-
debug "accumBlock #{OL(tree)}"
|
|
214
|
-
block = @section(tree).getBlock()
|
|
215
|
-
if nonEmpty(block)
|
|
216
|
-
@lAllBlocks.push block
|
|
217
|
-
else
|
|
218
|
-
assert isArray(tree), "not an array"
|
|
219
|
-
for subtree in tree
|
|
220
|
-
@accumBlock subtree
|
|
221
|
-
return
|
package/src/SectionMap.js
CHANGED
|
@@ -15,13 +15,18 @@ import {
|
|
|
15
15
|
isHash,
|
|
16
16
|
isArray,
|
|
17
17
|
isUniqueTree,
|
|
18
|
-
isNonEmptyString
|
|
18
|
+
isNonEmptyString,
|
|
19
|
+
isNonEmptyArray
|
|
19
20
|
} from '@jdeighan/coffee-utils';
|
|
20
21
|
|
|
21
22
|
import {
|
|
22
23
|
arrayToBlock
|
|
23
24
|
} from '@jdeighan/coffee-utils/block';
|
|
24
25
|
|
|
26
|
+
import {
|
|
27
|
+
indented
|
|
28
|
+
} from '@jdeighan/coffee-utils/indent';
|
|
29
|
+
|
|
25
30
|
import {
|
|
26
31
|
debug
|
|
27
32
|
} from '@jdeighan/coffee-utils/debug';
|
|
@@ -32,116 +37,156 @@ import {
|
|
|
32
37
|
|
|
33
38
|
// ---------------------------------------------------------------------------
|
|
34
39
|
isSectionName = function(name) {
|
|
35
|
-
|
|
36
|
-
return name.match(/^[a-z][a-z0-9]*/);
|
|
40
|
+
return isString(name) && name.match(/^[a-z][a-z0-9]*/);
|
|
37
41
|
};
|
|
38
42
|
|
|
39
43
|
// ---------------------------------------------------------------------------
|
|
40
44
|
isSetName = function(name) {
|
|
41
|
-
|
|
42
|
-
return name.match(/^[A-Z][a-z0-9]*/);
|
|
45
|
+
return isString(name) && name.match(/^[A-Z][a-z0-9]*/);
|
|
43
46
|
};
|
|
44
47
|
|
|
45
48
|
// ---------------------------------------------------------------------------
|
|
46
49
|
export var SectionMap = class SectionMap {
|
|
47
|
-
constructor(
|
|
48
|
-
// ---
|
|
49
|
-
debug("enter SectionMap()",
|
|
50
|
-
this.
|
|
50
|
+
constructor(lSectionTree) {
|
|
51
|
+
// --- lSectionTree is a tree of section names
|
|
52
|
+
debug("enter SectionMap()", lSectionTree);
|
|
53
|
+
this.lSectionTree = lSectionTree; // a tree of section names
|
|
51
54
|
this.hSets = {};
|
|
52
55
|
this.hSections = {};
|
|
53
|
-
this.addSections(
|
|
56
|
+
this.addSections(lSectionTree);
|
|
54
57
|
debug("return from SectionMap()", this.hSections);
|
|
55
58
|
}
|
|
56
59
|
|
|
57
60
|
// ..........................................................
|
|
58
|
-
|
|
59
|
-
// --- TODO: Allow array to start with a set name ---
|
|
60
61
|
addSections(desc) {
|
|
61
|
-
var i, item, len;
|
|
62
|
+
var i, item, j, k, lAdded, lParts, len, len1, name;
|
|
63
|
+
// --- returns a flat array of sections that were added
|
|
62
64
|
if (isString(desc)) {
|
|
63
65
|
assert(nonEmpty(desc), "empty section name");
|
|
64
|
-
assert(desc
|
|
66
|
+
assert(isSectionName(desc), `bad section name ${OL(desc)}`);
|
|
65
67
|
assert(this.hSections[desc] === undef, `duplicate section ${OL(desc)}`);
|
|
66
|
-
this.hSections[desc] = new Section();
|
|
68
|
+
this.hSections[desc] = new Section(desc);
|
|
69
|
+
return [desc];
|
|
67
70
|
} else {
|
|
68
71
|
assert(isArray(desc), `not an array or string ${OL(desc)}`);
|
|
69
|
-
|
|
72
|
+
name = undef;
|
|
73
|
+
lParts = [];
|
|
74
|
+
for (i = j = 0, len = desc.length; j < len; i = ++j) {
|
|
70
75
|
item = desc[i];
|
|
71
|
-
|
|
76
|
+
if ((i === 0) && isSetName(item)) {
|
|
77
|
+
name = item;
|
|
78
|
+
} else {
|
|
79
|
+
lAdded = this.addSections(item);
|
|
80
|
+
for (k = 0, len1 = lAdded.length; k < len1; k++) {
|
|
81
|
+
item = lAdded[k];
|
|
82
|
+
lParts.push(item);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
72
85
|
}
|
|
86
|
+
if (defined(name)) {
|
|
87
|
+
this.addSet(name, lParts);
|
|
88
|
+
}
|
|
89
|
+
return lParts;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// ..........................................................
|
|
94
|
+
addSet(name, lSectionTree) {
|
|
95
|
+
var j, len, secName;
|
|
96
|
+
debug("enter addSet()", name, lSectionTree);
|
|
97
|
+
// --- check the name
|
|
98
|
+
assert(isSetName(name), `not a valid set name ${OL(name)}`);
|
|
99
|
+
// --- check lSectionTree
|
|
100
|
+
assert(isArray(lSectionTree), "arg 2 not an array");
|
|
101
|
+
for (j = 0, len = lSectionTree.length; j < len; j++) {
|
|
102
|
+
secName = lSectionTree[j];
|
|
103
|
+
assert(isNonEmptyString(secName), `not a non-empty string ${OL(secName)}`);
|
|
104
|
+
assert(defined(this.hSections[secName]), `not a section name ${OL(secName)}`);
|
|
73
105
|
}
|
|
106
|
+
this.hSets[name] = lSectionTree;
|
|
107
|
+
debug('hSets', this.hSets);
|
|
108
|
+
debug("return from addSet()");
|
|
74
109
|
}
|
|
75
110
|
|
|
76
111
|
// ..........................................................
|
|
77
|
-
// ---
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
112
|
+
// --- sections returned in depth-first order from section tree
|
|
113
|
+
// Set names are simply skipped
|
|
114
|
+
// yields: [<level>, <section>]
|
|
115
|
+
* allSections(desc = undef, level = 0) {
|
|
116
|
+
var item, j, lTree, len, result;
|
|
117
|
+
debug("enter allSections()", desc, level);
|
|
81
118
|
if (desc === undef) {
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
for (
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
} else if (isSetName(desc)) {
|
|
94
|
-
debug(`expand set ${OL(desc)}`);
|
|
95
|
-
debug('hSets', this.hSets);
|
|
96
|
-
lNames = this.hSets[desc];
|
|
97
|
-
assert(defined(lNames), `no set named ${OL(desc)}`);
|
|
98
|
-
debug(`set ${desc}`, lNames);
|
|
99
|
-
for (i = 0, len = lNames.length; i < len; i++) {
|
|
100
|
-
name = lNames[i];
|
|
101
|
-
debug(`yield section ${OL(desc)}`);
|
|
102
|
-
yield this.section(name);
|
|
103
|
-
}
|
|
104
|
-
} else {
|
|
105
|
-
croak(`bad name ${OL(desc)}`);
|
|
106
|
-
}
|
|
107
|
-
} else {
|
|
108
|
-
assert(isArray(desc), "not an array");
|
|
109
|
-
for (j = 0, len1 = desc.length; j < len1; j++) {
|
|
110
|
-
name = desc[j];
|
|
111
|
-
debug(`yield section ${OL(name)}`);
|
|
112
|
-
assert(isString(name), `not a string ${OL(name)}`);
|
|
113
|
-
if (isSectionName(name)) {
|
|
114
|
-
yield this.section(name);
|
|
115
|
-
} else if (isSetName(name)) {
|
|
116
|
-
ref1 = this.hSets[name];
|
|
117
|
-
for (_ in ref1) {
|
|
118
|
-
sect = ref1[_];
|
|
119
|
-
yield sect;
|
|
120
|
-
}
|
|
119
|
+
desc = this.lSectionTree;
|
|
120
|
+
}
|
|
121
|
+
if (isArray(desc)) {
|
|
122
|
+
for (j = 0, len = desc.length; j < len; j++) {
|
|
123
|
+
item = desc[j];
|
|
124
|
+
if (isSectionName(item)) {
|
|
125
|
+
result = [level, this.section(item)];
|
|
126
|
+
debug('yield', result);
|
|
127
|
+
yield result;
|
|
128
|
+
} else if (isSetName(item)) {
|
|
129
|
+
pass;
|
|
121
130
|
} else {
|
|
122
|
-
|
|
131
|
+
assert(isArray(item), `not an array ${OL(item)}`);
|
|
132
|
+
yield* this.allSections(item, level + 1);
|
|
123
133
|
}
|
|
124
134
|
}
|
|
135
|
+
} else if (isSectionName(desc)) {
|
|
136
|
+
result = [level, this.section(desc)];
|
|
137
|
+
debug('yield', result);
|
|
138
|
+
yield result;
|
|
139
|
+
} else if (isSetName(desc)) {
|
|
140
|
+
lTree = this.hSets[desc];
|
|
141
|
+
assert(defined(lTree), `Not a Set: ${OL(desc)}`);
|
|
142
|
+
yield* this.allSections(lTree, level);
|
|
143
|
+
} else {
|
|
144
|
+
croak(`Bad item: ${OL(desc)}`);
|
|
125
145
|
}
|
|
126
146
|
debug("return from allSections()");
|
|
127
147
|
}
|
|
128
148
|
|
|
129
149
|
// ..........................................................
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
assert(isNonEmptyString(secName), `not a non-empty string ${OL(secName)}`);
|
|
140
|
-
assert(defined(this.hSections[secName]), `not a section name ${OL(secName)}`);
|
|
150
|
+
// --- procFunc should be (name, block) ->
|
|
151
|
+
// return processed block
|
|
152
|
+
getBlock(procFunc = undef, lTree = undef) {
|
|
153
|
+
var j, lParts, len, part, result, text;
|
|
154
|
+
debug("enter getBlock()");
|
|
155
|
+
if (lTree === undef) {
|
|
156
|
+
lTree = this.lSectionTree;
|
|
157
|
+
} else {
|
|
158
|
+
assert(isArray(lTree), `not an array ${OL(lTree)}`);
|
|
141
159
|
}
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
160
|
+
lParts = [];
|
|
161
|
+
for (j = 0, len = lTree.length; j < len; j++) {
|
|
162
|
+
part = lTree[j];
|
|
163
|
+
if (isString(part)) {
|
|
164
|
+
text = this.section(part).getBlock();
|
|
165
|
+
if (nonEmpty(text) && defined(procFunc)) {
|
|
166
|
+
text = procFunc(part, text);
|
|
167
|
+
}
|
|
168
|
+
} else if (isNonEmptyArray(part)) {
|
|
169
|
+
if (isSectionName(part[0])) {
|
|
170
|
+
text = this.getBlock(procFunc, part);
|
|
171
|
+
} else if (isSetName(part[0])) {
|
|
172
|
+
text = this.getBlock(procFunc, part.slice(1));
|
|
173
|
+
if (nonEmpty(text) && defined(procFunc)) {
|
|
174
|
+
text = procFunc(part[0], text);
|
|
175
|
+
}
|
|
176
|
+
} else {
|
|
177
|
+
croak(`Bad part: ${OL(part)}`);
|
|
178
|
+
}
|
|
179
|
+
} else {
|
|
180
|
+
croak(`Bad part: ${OL(part)}`);
|
|
181
|
+
}
|
|
182
|
+
if (defined(text)) {
|
|
183
|
+
lParts.push(text);
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
debug('lParts', lParts);
|
|
187
|
+
result = arrayToBlock(lParts);
|
|
188
|
+
debug("return from getBlock()", result);
|
|
189
|
+
return result;
|
|
145
190
|
}
|
|
146
191
|
|
|
147
192
|
// ..........................................................
|
|
@@ -154,30 +199,31 @@ export var SectionMap = class SectionMap {
|
|
|
154
199
|
|
|
155
200
|
// ..........................................................
|
|
156
201
|
firstSection(name) {
|
|
157
|
-
var
|
|
202
|
+
var lSectionTree;
|
|
158
203
|
assert(isSetName(name), `bad set name ${OL(name)}`);
|
|
159
|
-
|
|
160
|
-
assert(defined(
|
|
161
|
-
assert(nonEmpty(
|
|
162
|
-
return this.section(
|
|
204
|
+
lSectionTree = this.hSets[name];
|
|
205
|
+
assert(defined(lSectionTree), `no such set ${OL(name)}`);
|
|
206
|
+
assert(nonEmpty(lSectionTree), `empty section ${OL(name)}`);
|
|
207
|
+
return this.section(lSectionTree[0]);
|
|
163
208
|
}
|
|
164
209
|
|
|
165
210
|
// ..........................................................
|
|
166
211
|
lastSection(name) {
|
|
167
|
-
var
|
|
212
|
+
var lSectionTree;
|
|
168
213
|
assert(isSetName(name), `bad set name ${OL(name)}`);
|
|
169
|
-
|
|
170
|
-
assert(defined(
|
|
171
|
-
assert(nonEmpty(
|
|
172
|
-
return this.section(
|
|
214
|
+
lSectionTree = this.hSets[name];
|
|
215
|
+
assert(defined(lSectionTree), `no such set ${OL(name)}`);
|
|
216
|
+
assert(nonEmpty(lSectionTree), `empty section ${OL(name)}`);
|
|
217
|
+
return this.section(lSectionTree[lSectionTree.length - 1]);
|
|
173
218
|
}
|
|
174
219
|
|
|
175
220
|
// ..........................................................
|
|
176
221
|
length(desc = undef) {
|
|
177
|
-
var ref, result, sect;
|
|
222
|
+
var _, ref, result, sect, x;
|
|
178
223
|
result = 0;
|
|
179
224
|
ref = this.allSections(desc);
|
|
180
|
-
for (
|
|
225
|
+
for (x of ref) {
|
|
226
|
+
[_, sect] = x;
|
|
181
227
|
result += sect.length();
|
|
182
228
|
}
|
|
183
229
|
return result;
|
|
@@ -194,64 +240,18 @@ export var SectionMap = class SectionMap {
|
|
|
194
240
|
}
|
|
195
241
|
|
|
196
242
|
// ..........................................................
|
|
197
|
-
|
|
198
|
-
var ref, sect;
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
// ..........................................................
|
|
206
|
-
enclose(name, pre, post) {
|
|
207
|
-
var sect;
|
|
208
|
-
if (isSectionName(name)) {
|
|
209
|
-
sect = this.section(name);
|
|
210
|
-
if (sect.nonEmpty()) {
|
|
211
|
-
sect.indent();
|
|
212
|
-
sect.prepend(pre);
|
|
213
|
-
sect.add(post);
|
|
214
|
-
}
|
|
215
|
-
} else if (isSetName(name)) {
|
|
216
|
-
if (this.nonEmpty(name)) {
|
|
217
|
-
this.indent(name);
|
|
218
|
-
this.firstSection(name).prepend(pre);
|
|
219
|
-
this.lastSection(name).add(post);
|
|
220
|
-
}
|
|
221
|
-
} else {
|
|
222
|
-
croak(`Bad name param ${OL(name)}`);
|
|
243
|
+
getShape() {
|
|
244
|
+
var lParts, level, ref, result, sect, x;
|
|
245
|
+
debug("enter getShape()");
|
|
246
|
+
lParts = [];
|
|
247
|
+
ref = this.allSections();
|
|
248
|
+
for (x of ref) {
|
|
249
|
+
[level, sect] = x;
|
|
250
|
+
lParts.push(indented(sect.name, level));
|
|
223
251
|
}
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
// ..........................................................
|
|
227
|
-
getBlock() {
|
|
228
|
-
var result;
|
|
229
|
-
debug("enter getBlock()");
|
|
230
|
-
this.lAllBlocks = [];
|
|
231
|
-
debug('lSections', this.lSections);
|
|
232
|
-
this.accumBlock(this.lSections);
|
|
233
|
-
debug('lAllBlocks', this.lAllBlocks);
|
|
234
|
-
result = arrayToBlock(this.lAllBlocks);
|
|
235
|
-
debug("return from getBlock()", result);
|
|
252
|
+
result = arrayToBlock(lParts);
|
|
253
|
+
debug("return from getShape()", result);
|
|
236
254
|
return result;
|
|
237
255
|
}
|
|
238
256
|
|
|
239
|
-
// ..........................................................
|
|
240
|
-
accumBlock(tree) {
|
|
241
|
-
var block, i, len, subtree;
|
|
242
|
-
if (isString(tree)) {
|
|
243
|
-
debug(`accumBlock ${OL(tree)}`);
|
|
244
|
-
block = this.section(tree).getBlock();
|
|
245
|
-
if (nonEmpty(block)) {
|
|
246
|
-
this.lAllBlocks.push(block);
|
|
247
|
-
}
|
|
248
|
-
} else {
|
|
249
|
-
assert(isArray(tree), "not an array");
|
|
250
|
-
for (i = 0, len = tree.length; i < len; i++) {
|
|
251
|
-
subtree = tree[i];
|
|
252
|
-
this.accumBlock(subtree);
|
|
253
|
-
}
|
|
254
|
-
}
|
|
255
|
-
}
|
|
256
|
-
|
|
257
257
|
};
|
package/src/block_utils.coffee
CHANGED
|
@@ -30,19 +30,31 @@ export blockToArray = (block) ->
|
|
|
30
30
|
export arrayToBlock = (lLines) ->
|
|
31
31
|
|
|
32
32
|
if (lLines == undef)
|
|
33
|
-
return
|
|
33
|
+
return undef
|
|
34
34
|
assert isArray(lLines), "lLines is not an array"
|
|
35
35
|
lLines = lLines.filter((line) => defined(line));
|
|
36
36
|
if lLines.length == 0
|
|
37
|
-
return
|
|
37
|
+
return undef
|
|
38
38
|
else
|
|
39
39
|
return rtrim(lLines.join('\n'))
|
|
40
40
|
|
|
41
41
|
# ---------------------------------------------------------------------------
|
|
42
42
|
|
|
43
|
+
export splitBlock = (block) ->
|
|
44
|
+
|
|
45
|
+
assert isString(block), "not a string"
|
|
46
|
+
pos = block.indexOf('\n')
|
|
47
|
+
if (pos == -1)
|
|
48
|
+
return [block, undef]
|
|
49
|
+
else
|
|
50
|
+
return [block.substring(0, pos), block.substring(pos+1)]
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
# ---------------------------------------------------------------------------
|
|
54
|
+
|
|
43
55
|
export firstLine = (block) ->
|
|
44
56
|
|
|
45
|
-
assert isString(block), "
|
|
57
|
+
assert isString(block), "not a string"
|
|
46
58
|
pos = block.indexOf('\n')
|
|
47
59
|
if (pos == -1)
|
|
48
60
|
return block
|
|
@@ -53,10 +65,10 @@ export firstLine = (block) ->
|
|
|
53
65
|
|
|
54
66
|
export remainingLines = (block) ->
|
|
55
67
|
|
|
56
|
-
assert isString(block), "
|
|
68
|
+
assert isString(block), "not a string"
|
|
57
69
|
pos = block.indexOf('\n')
|
|
58
70
|
if (pos == -1)
|
|
59
|
-
return
|
|
71
|
+
return undef
|
|
60
72
|
else
|
|
61
73
|
return block.substring(pos+1)
|
|
62
74
|
|
package/src/block_utils.js
CHANGED
|
@@ -38,23 +38,35 @@ export var blockToArray = function(block) {
|
|
|
38
38
|
// arrayToBlock - block will have no trailing whitespace
|
|
39
39
|
export var arrayToBlock = function(lLines) {
|
|
40
40
|
if (lLines === undef) {
|
|
41
|
-
return
|
|
41
|
+
return undef;
|
|
42
42
|
}
|
|
43
43
|
assert(isArray(lLines), "lLines is not an array");
|
|
44
44
|
lLines = lLines.filter((line) => {
|
|
45
45
|
return defined(line);
|
|
46
46
|
});
|
|
47
47
|
if (lLines.length === 0) {
|
|
48
|
-
return
|
|
48
|
+
return undef;
|
|
49
49
|
} else {
|
|
50
50
|
return rtrim(lLines.join('\n'));
|
|
51
51
|
}
|
|
52
52
|
};
|
|
53
53
|
|
|
54
|
+
// ---------------------------------------------------------------------------
|
|
55
|
+
export var splitBlock = function(block) {
|
|
56
|
+
var pos;
|
|
57
|
+
assert(isString(block), "not a string");
|
|
58
|
+
pos = block.indexOf('\n');
|
|
59
|
+
if (pos === -1) {
|
|
60
|
+
return [block, undef];
|
|
61
|
+
} else {
|
|
62
|
+
return [block.substring(0, pos), block.substring(pos + 1)];
|
|
63
|
+
}
|
|
64
|
+
};
|
|
65
|
+
|
|
54
66
|
// ---------------------------------------------------------------------------
|
|
55
67
|
export var firstLine = function(block) {
|
|
56
68
|
var pos;
|
|
57
|
-
assert(isString(block), "
|
|
69
|
+
assert(isString(block), "not a string");
|
|
58
70
|
pos = block.indexOf('\n');
|
|
59
71
|
if (pos === -1) {
|
|
60
72
|
return block;
|
|
@@ -66,10 +78,10 @@ export var firstLine = function(block) {
|
|
|
66
78
|
// ---------------------------------------------------------------------------
|
|
67
79
|
export var remainingLines = function(block) {
|
|
68
80
|
var pos;
|
|
69
|
-
assert(isString(block), "
|
|
81
|
+
assert(isString(block), "not a string");
|
|
70
82
|
pos = block.indexOf('\n');
|
|
71
83
|
if (pos === -1) {
|
|
72
|
-
return
|
|
84
|
+
return undef;
|
|
73
85
|
} else {
|
|
74
86
|
return block.substring(pos + 1);
|
|
75
87
|
}
|
package/src/coffee_utils.coffee
CHANGED
|
@@ -173,6 +173,12 @@ export isArray = (x) ->
|
|
|
173
173
|
|
|
174
174
|
# ---------------------------------------------------------------------------
|
|
175
175
|
|
|
176
|
+
export isNonEmptyArray = (x) ->
|
|
177
|
+
|
|
178
|
+
return isArray(x) && (x.length > 0)
|
|
179
|
+
|
|
180
|
+
# ---------------------------------------------------------------------------
|
|
181
|
+
|
|
176
182
|
export isHash = (x, lKeys) ->
|
|
177
183
|
|
|
178
184
|
if ! x || (getClassName(x) != 'Object')
|
|
@@ -186,6 +192,12 @@ export isHash = (x, lKeys) ->
|
|
|
186
192
|
|
|
187
193
|
# ---------------------------------------------------------------------------
|
|
188
194
|
|
|
195
|
+
export isNonEmptyHash = (x) ->
|
|
196
|
+
|
|
197
|
+
return isHash(x) && (Object.keys(x).length > 0)
|
|
198
|
+
|
|
199
|
+
# ---------------------------------------------------------------------------
|
|
200
|
+
|
|
189
201
|
export hashHasKey = (x, key) ->
|
|
190
202
|
|
|
191
203
|
assert isHash(x), "hashHasKey(): not a hash"
|
package/src/coffee_utils.js
CHANGED
|
@@ -159,6 +159,11 @@ export var isArray = function(x) {
|
|
|
159
159
|
return Array.isArray(x);
|
|
160
160
|
};
|
|
161
161
|
|
|
162
|
+
// ---------------------------------------------------------------------------
|
|
163
|
+
export var isNonEmptyArray = function(x) {
|
|
164
|
+
return isArray(x) && (x.length > 0);
|
|
165
|
+
};
|
|
166
|
+
|
|
162
167
|
// ---------------------------------------------------------------------------
|
|
163
168
|
export var isHash = function(x, lKeys) {
|
|
164
169
|
var i, key, len;
|
|
@@ -177,6 +182,11 @@ export var isHash = function(x, lKeys) {
|
|
|
177
182
|
return true;
|
|
178
183
|
};
|
|
179
184
|
|
|
185
|
+
// ---------------------------------------------------------------------------
|
|
186
|
+
export var isNonEmptyHash = function(x) {
|
|
187
|
+
return isHash(x) && (Object.keys(x).length > 0);
|
|
188
|
+
};
|
|
189
|
+
|
|
180
190
|
// ---------------------------------------------------------------------------
|
|
181
191
|
export var hashHasKey = function(x, key) {
|
|
182
192
|
assert(isHash(x), "hashHasKey(): not a hash");
|
package/src/indent_utils.coffee
CHANGED
|
@@ -146,3 +146,10 @@ export tabify = (str, numSpaces=undef) ->
|
|
|
146
146
|
export untabify = (str, numSpaces=3) ->
|
|
147
147
|
|
|
148
148
|
return str.replace(/\t/g, ' '.repeat(numSpaces))
|
|
149
|
+
|
|
150
|
+
# ---------------------------------------------------------------------------
|
|
151
|
+
# enclose - indent text, surround with pre and post
|
|
152
|
+
|
|
153
|
+
export enclose = (text, pre, post) ->
|
|
154
|
+
|
|
155
|
+
return pre + "\n" + indented(text) + "\n" + post
|
package/src/indent_utils.js
CHANGED
|
@@ -175,3 +175,9 @@ export var tabify = function(str, numSpaces = undef) {
|
|
|
175
175
|
export var untabify = function(str, numSpaces = 3) {
|
|
176
176
|
return str.replace(/\t/g, ' '.repeat(numSpaces));
|
|
177
177
|
};
|
|
178
|
+
|
|
179
|
+
// ---------------------------------------------------------------------------
|
|
180
|
+
// enclose - indent text, surround with pre and post
|
|
181
|
+
export var enclose = function(text, pre, post) {
|
|
182
|
+
return pre + "\n" + indented(text) + "\n" + post;
|
|
183
|
+
};
|