@jdeighan/coffee-utils 9.0.5 → 10.0.0
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 +91 -148
- package/src/SectionMap.js +108 -160
- package/src/coffee_utils.coffee +11 -0
- package/src/coffee_utils.js +12 -0
- package/src/indent_utils.coffee +17 -2
- package/src/indent_utils.js +8 -2
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,126 @@ 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
|
|
88
|
-
|
|
89
|
-
# ..........................................................
|
|
90
|
-
# --- sections returned in depth-first order from section tree
|
|
91
|
-
# Set names are simply skipped
|
|
92
|
-
# yields: [<level>, <section>]
|
|
86
|
+
getBlock: (desc=undef, hProcs={}) ->
|
|
93
87
|
|
|
94
|
-
|
|
88
|
+
debug "enter SectionMap.getBlock()", desc, hProcs
|
|
95
89
|
|
|
96
|
-
|
|
97
|
-
if (desc == undef)
|
|
90
|
+
if notdefined(desc)
|
|
98
91
|
desc = @lSectionTree
|
|
92
|
+
|
|
99
93
|
if isArray(desc)
|
|
94
|
+
lBlocks = []
|
|
95
|
+
setName = undef
|
|
100
96
|
for item in desc
|
|
101
|
-
if isSectionName(item)
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
97
|
+
if isArray(item) || isSectionName(item)
|
|
98
|
+
# --- arrayToBlock() will skip undef items
|
|
99
|
+
# so, no need to check for undef block
|
|
100
|
+
lBlocks.push @getBlock(item, hProcs)
|
|
105
101
|
else if isSetName(item)
|
|
106
|
-
|
|
102
|
+
setName = item
|
|
103
|
+
else if isString(item)
|
|
104
|
+
lBlocks.push item # a literal string
|
|
107
105
|
else
|
|
108
|
-
|
|
109
|
-
|
|
106
|
+
croak "Bad item: #{OL(item)}"
|
|
107
|
+
block = arrayToBlock(lBlocks)
|
|
110
108
|
else if isSectionName(desc)
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
109
|
+
block = @section(desc).getBlock()
|
|
110
|
+
if defined(proc = hProcs[desc])
|
|
111
|
+
block = proc(block)
|
|
114
112
|
else if isSetName(desc)
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
113
|
+
# --- pass array to getBlock()
|
|
114
|
+
block = @getBlock(@hSets[desc], hProcs)
|
|
115
|
+
if defined(proc = hProcs[desc])
|
|
116
|
+
block = proc(block)
|
|
118
117
|
else
|
|
119
|
-
croak "Bad
|
|
120
|
-
debug "return from
|
|
121
|
-
return
|
|
118
|
+
croak "Bad 1st arg: #{OL(desc)}"
|
|
119
|
+
debug "return from SectionMap.getBlock()", block
|
|
120
|
+
return block
|
|
122
121
|
|
|
123
122
|
# ..........................................................
|
|
124
|
-
# --- hProc should be <name> -> <function>
|
|
125
|
-
# <function> should be <block> -> <block>
|
|
126
|
-
# --- lTree allows you to get just a section
|
|
127
123
|
|
|
128
|
-
|
|
124
|
+
isEmpty: () ->
|
|
129
125
|
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
lParts = []
|
|
137
|
-
for part in lTree
|
|
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
|
|
126
|
+
for name,sect of @hSections
|
|
127
|
+
if sect.nonEmpty()
|
|
128
|
+
return false
|
|
129
|
+
return true
|
|
130
|
+
|
|
131
|
+
# ..........................................................
|
|
156
132
|
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
133
|
+
nonEmpty: () ->
|
|
134
|
+
|
|
135
|
+
for name,sect of @hSections
|
|
136
|
+
if sect.nonEmpty()
|
|
137
|
+
return true
|
|
138
|
+
return false
|
|
161
139
|
|
|
162
140
|
# ..........................................................
|
|
163
141
|
|
|
@@ -172,50 +150,15 @@ export class SectionMap
|
|
|
172
150
|
firstSection: (name) ->
|
|
173
151
|
|
|
174
152
|
assert isSetName(name), "bad set name #{OL(name)}"
|
|
175
|
-
|
|
176
|
-
assert defined(
|
|
177
|
-
|
|
178
|
-
return @section(lSectionTree[0])
|
|
153
|
+
lSubTree = @hSets[name]
|
|
154
|
+
assert defined(lSubTree), "no such set #{OL(name)}"
|
|
155
|
+
return @section(lSubTree[1])
|
|
179
156
|
|
|
180
157
|
# ..........................................................
|
|
181
158
|
|
|
182
159
|
lastSection: (name) ->
|
|
183
160
|
|
|
184
161
|
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
|
|
162
|
+
lSubTree = @hSets[name]
|
|
163
|
+
assert defined(lSubTree), "no such set #{OL(name)}"
|
|
164
|
+
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,140 @@ 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
104
|
}
|
|
105
|
+
debug("return from build()", this.hSections, this.hSets);
|
|
95
106
|
}
|
|
96
107
|
|
|
97
108
|
// ..........................................................
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
this.hSets[name] = lSectionTree;
|
|
111
|
-
debug('hSets', this.hSets);
|
|
112
|
-
debug("return from addSet()");
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
// ..........................................................
|
|
116
|
-
// --- sections returned in depth-first order from section tree
|
|
117
|
-
// Set names are simply skipped
|
|
118
|
-
// yields: [<level>, <section>]
|
|
119
|
-
* allSections(desc = undef, level = 0) {
|
|
120
|
-
var item, j, lTree, len, result;
|
|
121
|
-
debug("enter allSections()", desc, level);
|
|
122
|
-
if (desc === undef) {
|
|
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, hProcs = {}) {
|
|
118
|
+
var block, i, item, lBlocks, len, proc, setName;
|
|
119
|
+
debug("enter SectionMap.getBlock()", desc, hProcs);
|
|
120
|
+
if (notdefined(desc)) {
|
|
123
121
|
desc = this.lSectionTree;
|
|
124
122
|
}
|
|
125
123
|
if (isArray(desc)) {
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
124
|
+
lBlocks = [];
|
|
125
|
+
setName = undef;
|
|
126
|
+
for (i = 0, len = desc.length; i < len; i++) {
|
|
127
|
+
item = desc[i];
|
|
128
|
+
if (isArray(item) || isSectionName(item)) {
|
|
129
|
+
// --- arrayToBlock() will skip undef items
|
|
130
|
+
// so, no need to check for undef block
|
|
131
|
+
lBlocks.push(this.getBlock(item, hProcs));
|
|
132
132
|
} else if (isSetName(item)) {
|
|
133
|
-
|
|
133
|
+
setName = item;
|
|
134
|
+
} else if (isString(item)) {
|
|
135
|
+
lBlocks.push(item); // a literal string
|
|
134
136
|
} else {
|
|
135
|
-
|
|
136
|
-
yield* this.allSections(item, level + 1);
|
|
137
|
+
croak(`Bad item: ${OL(item)}`);
|
|
137
138
|
}
|
|
138
139
|
}
|
|
140
|
+
block = arrayToBlock(lBlocks);
|
|
139
141
|
} else if (isSectionName(desc)) {
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
142
|
+
block = this.section(desc).getBlock();
|
|
143
|
+
if (defined(proc = hProcs[desc])) {
|
|
144
|
+
block = proc(block);
|
|
145
|
+
}
|
|
143
146
|
} else if (isSetName(desc)) {
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
+
// --- pass array to getBlock()
|
|
148
|
+
block = this.getBlock(this.hSets[desc], hProcs);
|
|
149
|
+
if (defined(proc = hProcs[desc])) {
|
|
150
|
+
block = proc(block);
|
|
151
|
+
}
|
|
147
152
|
} else {
|
|
148
|
-
croak(`Bad
|
|
153
|
+
croak(`Bad 1st arg: ${OL(desc)}`);
|
|
149
154
|
}
|
|
150
|
-
debug("return from
|
|
155
|
+
debug("return from SectionMap.getBlock()", block);
|
|
156
|
+
return block;
|
|
151
157
|
}
|
|
152
158
|
|
|
153
159
|
// ..........................................................
|
|
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)}`);
|
|
160
|
+
isEmpty() {
|
|
161
|
+
var name, ref, sect;
|
|
162
|
+
ref = this.hSections;
|
|
163
|
+
for (name in ref) {
|
|
164
|
+
sect = ref[name];
|
|
165
|
+
if (sect.nonEmpty()) {
|
|
166
|
+
return false;
|
|
187
167
|
}
|
|
188
|
-
|
|
189
|
-
|
|
168
|
+
}
|
|
169
|
+
return true;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
// ..........................................................
|
|
173
|
+
nonEmpty() {
|
|
174
|
+
var name, ref, sect;
|
|
175
|
+
ref = this.hSections;
|
|
176
|
+
for (name in ref) {
|
|
177
|
+
sect = ref[name];
|
|
178
|
+
if (sect.nonEmpty()) {
|
|
179
|
+
return true;
|
|
190
180
|
}
|
|
191
181
|
}
|
|
192
|
-
|
|
193
|
-
result = arrayToBlock(lParts);
|
|
194
|
-
debug("return from getBlock()", result);
|
|
195
|
-
return result;
|
|
182
|
+
return false;
|
|
196
183
|
}
|
|
197
184
|
|
|
198
185
|
// ..........................................................
|
|
@@ -205,59 +192,20 @@ export var SectionMap = class SectionMap {
|
|
|
205
192
|
|
|
206
193
|
// ..........................................................
|
|
207
194
|
firstSection(name) {
|
|
208
|
-
var
|
|
195
|
+
var lSubTree;
|
|
209
196
|
assert(isSetName(name), `bad set name ${OL(name)}`);
|
|
210
|
-
|
|
211
|
-
assert(defined(
|
|
212
|
-
|
|
213
|
-
return this.section(lSectionTree[0]);
|
|
197
|
+
lSubTree = this.hSets[name];
|
|
198
|
+
assert(defined(lSubTree), `no such set ${OL(name)}`);
|
|
199
|
+
return this.section(lSubTree[1]);
|
|
214
200
|
}
|
|
215
201
|
|
|
216
202
|
// ..........................................................
|
|
217
203
|
lastSection(name) {
|
|
218
|
-
var
|
|
204
|
+
var lSubTree;
|
|
219
205
|
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;
|
|
206
|
+
lSubTree = this.hSets[name];
|
|
207
|
+
assert(defined(lSubTree), `no such set ${OL(name)}`);
|
|
208
|
+
return this.section(lSubTree[lSubTree.length - 1]);
|
|
261
209
|
}
|
|
262
210
|
|
|
263
211
|
};
|
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
|
@@ -157,6 +157,21 @@ export untabify = (str, numSpaces=3) ->
|
|
|
157
157
|
# ---------------------------------------------------------------------------
|
|
158
158
|
# enclose - indent text, surround with pre and post
|
|
159
159
|
|
|
160
|
-
export enclose = (text, pre, post) ->
|
|
160
|
+
export enclose = (text, pre, post, oneIndent="\t") ->
|
|
161
161
|
|
|
162
|
-
return
|
|
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") ->
|
|
172
|
+
|
|
173
|
+
return arrayToBlock([
|
|
174
|
+
"<#{tag}>"
|
|
175
|
+
indented(text, 1, oneIndent)
|
|
176
|
+
"</#{tag}>"
|
|
177
|
+
])
|
package/src/indent_utils.js
CHANGED
|
@@ -184,6 +184,12 @@ export var untabify = function(str, numSpaces = 3) {
|
|
|
184
184
|
|
|
185
185
|
// ---------------------------------------------------------------------------
|
|
186
186
|
// enclose - indent text, surround with pre and post
|
|
187
|
-
export var enclose = function(text, pre, post) {
|
|
188
|
-
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}>`]);
|
|
189
195
|
};
|