@jdeighan/coffee-utils 8.0.1 → 8.0.4
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 +4 -2
- package/src/Section.coffee +69 -0
- package/src/Section.js +84 -0
- package/src/SectionMap.coffee +221 -0
- package/src/SectionMap.js +257 -0
- package/src/coffee_utils.coffee +20 -0
- package/src/coffee_utils.js +28 -0
package/package.json
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
{
|
2
2
|
"name": "@jdeighan/coffee-utils",
|
3
3
|
"type": "module",
|
4
|
-
"version": "8.0.
|
4
|
+
"version": "8.0.4",
|
5
5
|
"description": "A set of utility functions for CoffeeScript",
|
6
6
|
"main": "coffee_utils.js",
|
7
7
|
"exports": {
|
@@ -19,6 +19,8 @@
|
|
19
19
|
"./store": "./src/DataStores.js",
|
20
20
|
"./taml": "./src/taml.js",
|
21
21
|
"./placeholders": "./src/placeholders.js",
|
22
|
+
"./section": "./src/Section.js",
|
23
|
+
"./sectionmap": "./src/SectionMap.js",
|
22
24
|
"./package.json": "./package.json"
|
23
25
|
},
|
24
26
|
"engines": {
|
@@ -53,6 +55,6 @@
|
|
53
55
|
"svelte": "^3.48.0"
|
54
56
|
},
|
55
57
|
"devDependencies": {
|
56
|
-
"@jdeighan/unit-tester": "^2.0.
|
58
|
+
"@jdeighan/unit-tester": "^2.0.9"
|
57
59
|
}
|
58
60
|
}
|
@@ -0,0 +1,69 @@
|
|
1
|
+
# Section.coffee
|
2
|
+
|
3
|
+
import {
|
4
|
+
assert, pass, undef, defined, croak, isArray,
|
5
|
+
} from '@jdeighan/coffee-utils'
|
6
|
+
import {arrayToBlock} from '@jdeighan/coffee-utils/block'
|
7
|
+
import {indented} from '@jdeighan/coffee-utils/indent'
|
8
|
+
|
9
|
+
# ---------------------------------------------------------------------------
|
10
|
+
|
11
|
+
export class Section
|
12
|
+
|
13
|
+
constructor: () ->
|
14
|
+
|
15
|
+
@lLines = []
|
16
|
+
|
17
|
+
# ..........................................................
|
18
|
+
|
19
|
+
length: () ->
|
20
|
+
|
21
|
+
return @lLines.length
|
22
|
+
|
23
|
+
# ..........................................................
|
24
|
+
|
25
|
+
indent: (level=1) ->
|
26
|
+
|
27
|
+
lNewLines = for line in @lLines
|
28
|
+
indented(line, level)
|
29
|
+
@lLines = lNewLines
|
30
|
+
return
|
31
|
+
|
32
|
+
# ..........................................................
|
33
|
+
|
34
|
+
isEmpty: () ->
|
35
|
+
|
36
|
+
return (@lLines.length == 0)
|
37
|
+
|
38
|
+
# ..........................................................
|
39
|
+
|
40
|
+
nonEmpty: () ->
|
41
|
+
|
42
|
+
return (@lLines.length > 0)
|
43
|
+
|
44
|
+
# ..........................................................
|
45
|
+
|
46
|
+
add: (data) ->
|
47
|
+
|
48
|
+
if isArray(data)
|
49
|
+
for line in data
|
50
|
+
@lLines.push line
|
51
|
+
else
|
52
|
+
@lLines.push data
|
53
|
+
return
|
54
|
+
|
55
|
+
# ..........................................................
|
56
|
+
|
57
|
+
prepend: (data) ->
|
58
|
+
|
59
|
+
if isArray(data)
|
60
|
+
@lLines = [data..., @lLines...]
|
61
|
+
else
|
62
|
+
@lLines = [data, @lLines...]
|
63
|
+
return
|
64
|
+
|
65
|
+
# ..........................................................
|
66
|
+
|
67
|
+
getBlock: () ->
|
68
|
+
|
69
|
+
return arrayToBlock(@lLines)
|
package/src/Section.js
ADDED
@@ -0,0 +1,84 @@
|
|
1
|
+
// Generated by CoffeeScript 2.7.0
|
2
|
+
// Section.coffee
|
3
|
+
import {
|
4
|
+
assert,
|
5
|
+
pass,
|
6
|
+
undef,
|
7
|
+
defined,
|
8
|
+
croak,
|
9
|
+
isArray
|
10
|
+
} from '@jdeighan/coffee-utils';
|
11
|
+
|
12
|
+
import {
|
13
|
+
arrayToBlock
|
14
|
+
} from '@jdeighan/coffee-utils/block';
|
15
|
+
|
16
|
+
import {
|
17
|
+
indented
|
18
|
+
} from '@jdeighan/coffee-utils/indent';
|
19
|
+
|
20
|
+
// ---------------------------------------------------------------------------
|
21
|
+
export var Section = class Section {
|
22
|
+
constructor() {
|
23
|
+
this.lLines = [];
|
24
|
+
}
|
25
|
+
|
26
|
+
// ..........................................................
|
27
|
+
length() {
|
28
|
+
return this.lLines.length;
|
29
|
+
}
|
30
|
+
|
31
|
+
// ..........................................................
|
32
|
+
indent(level = 1) {
|
33
|
+
var lNewLines, line;
|
34
|
+
lNewLines = (function() {
|
35
|
+
var i, len, ref, results;
|
36
|
+
ref = this.lLines;
|
37
|
+
results = [];
|
38
|
+
for (i = 0, len = ref.length; i < len; i++) {
|
39
|
+
line = ref[i];
|
40
|
+
results.push(indented(line, level));
|
41
|
+
}
|
42
|
+
return results;
|
43
|
+
}).call(this);
|
44
|
+
this.lLines = lNewLines;
|
45
|
+
}
|
46
|
+
|
47
|
+
// ..........................................................
|
48
|
+
isEmpty() {
|
49
|
+
return this.lLines.length === 0;
|
50
|
+
}
|
51
|
+
|
52
|
+
// ..........................................................
|
53
|
+
nonEmpty() {
|
54
|
+
return this.lLines.length > 0;
|
55
|
+
}
|
56
|
+
|
57
|
+
// ..........................................................
|
58
|
+
add(data) {
|
59
|
+
var i, len, line;
|
60
|
+
if (isArray(data)) {
|
61
|
+
for (i = 0, len = data.length; i < len; i++) {
|
62
|
+
line = data[i];
|
63
|
+
this.lLines.push(line);
|
64
|
+
}
|
65
|
+
} else {
|
66
|
+
this.lLines.push(data);
|
67
|
+
}
|
68
|
+
}
|
69
|
+
|
70
|
+
// ..........................................................
|
71
|
+
prepend(data) {
|
72
|
+
if (isArray(data)) {
|
73
|
+
this.lLines = [...data, ...this.lLines];
|
74
|
+
} else {
|
75
|
+
this.lLines = [data, ...this.lLines];
|
76
|
+
}
|
77
|
+
}
|
78
|
+
|
79
|
+
// ..........................................................
|
80
|
+
getBlock() {
|
81
|
+
return arrayToBlock(this.lLines);
|
82
|
+
}
|
83
|
+
|
84
|
+
};
|
@@ -0,0 +1,221 @@
|
|
1
|
+
# SectionMap.coffee
|
2
|
+
|
3
|
+
import {
|
4
|
+
assert, pass, undef, defined, croak, OL, isEmpty, nonEmpty,
|
5
|
+
isString, isHash, isArray, isUniqueTree, isNonEmptyString,
|
6
|
+
} from '@jdeighan/coffee-utils'
|
7
|
+
import {arrayToBlock} from '@jdeighan/coffee-utils/block'
|
8
|
+
import {debug} from '@jdeighan/coffee-utils/debug'
|
9
|
+
import {Section} from '@jdeighan/coffee-utils/section'
|
10
|
+
|
11
|
+
# ---------------------------------------------------------------------------
|
12
|
+
|
13
|
+
isSectionName = (name) ->
|
14
|
+
|
15
|
+
assert isString(name), "not a string"
|
16
|
+
return name.match(/^[a-z][a-z0-9]*/)
|
17
|
+
|
18
|
+
# ---------------------------------------------------------------------------
|
19
|
+
|
20
|
+
isSetName = (name) ->
|
21
|
+
|
22
|
+
assert isString(name), "not a string"
|
23
|
+
return name.match(/^[A-Z][a-z0-9]*/)
|
24
|
+
|
25
|
+
# ---------------------------------------------------------------------------
|
26
|
+
|
27
|
+
export class SectionMap
|
28
|
+
|
29
|
+
constructor: (lSections) ->
|
30
|
+
# --- lSections is a tree of section names
|
31
|
+
|
32
|
+
debug "enter SectionMap()", lSections
|
33
|
+
@lSections = lSections # a tree of section names
|
34
|
+
@hSets = {}
|
35
|
+
@hSections = {}
|
36
|
+
@addSections lSections
|
37
|
+
debug "return from SectionMap()", @hSections
|
38
|
+
|
39
|
+
# ..........................................................
|
40
|
+
|
41
|
+
# --- TODO: Allow array to start with a set name ---
|
42
|
+
|
43
|
+
addSections: (desc) ->
|
44
|
+
|
45
|
+
if isString(desc)
|
46
|
+
assert nonEmpty(desc), "empty section name"
|
47
|
+
assert desc.match(/^[a-z][a-z0-9]*$/), "bad section name #{OL(desc)}"
|
48
|
+
assert (@hSections[desc] == undef), "duplicate section #{OL(desc)}"
|
49
|
+
@hSections[desc] = new Section()
|
50
|
+
else
|
51
|
+
assert isArray(desc), "not an array or string #{OL(desc)}"
|
52
|
+
for item in desc
|
53
|
+
@addSections item
|
54
|
+
return
|
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
|
92
|
+
else
|
93
|
+
croak "bad name #{OL(name)}"
|
94
|
+
debug "return from allSections()"
|
95
|
+
return
|
96
|
+
|
97
|
+
# ..........................................................
|
98
|
+
|
99
|
+
addSet: (name, lSections) ->
|
100
|
+
|
101
|
+
debug "enter addSet()", name, lSections
|
102
|
+
|
103
|
+
# --- check the name
|
104
|
+
assert isSetName(name), "not a valid set name #{OL(name)}"
|
105
|
+
|
106
|
+
# --- check lSections
|
107
|
+
assert isArray(lSections), "arg 2 not an array"
|
108
|
+
for secName in lSections
|
109
|
+
assert isNonEmptyString(secName),
|
110
|
+
"not a non-empty string #{OL(secName)}"
|
111
|
+
assert defined(@hSections[secName]),
|
112
|
+
"not a section name #{OL(secName)}"
|
113
|
+
|
114
|
+
@hSets[name] = lSections
|
115
|
+
debug 'hSets', @hSets
|
116
|
+
debug "return from addSet()"
|
117
|
+
return
|
118
|
+
|
119
|
+
# ..........................................................
|
120
|
+
|
121
|
+
section: (name) ->
|
122
|
+
|
123
|
+
sect = @hSections[name]
|
124
|
+
assert defined(sect), "No section named #{OL(name)}"
|
125
|
+
return sect
|
126
|
+
|
127
|
+
# ..........................................................
|
128
|
+
|
129
|
+
firstSection: (name) ->
|
130
|
+
|
131
|
+
assert isSetName(name), "bad set name #{OL(name)}"
|
132
|
+
lSections = @hSets[name]
|
133
|
+
assert defined(lSections), "no such set #{OL(name)}"
|
134
|
+
assert nonEmpty(lSections), "empty section #{OL(name)}"
|
135
|
+
return @section(lSections[0])
|
136
|
+
|
137
|
+
# ..........................................................
|
138
|
+
|
139
|
+
lastSection: (name) ->
|
140
|
+
|
141
|
+
assert isSetName(name), "bad set name #{OL(name)}"
|
142
|
+
lSections = @hSets[name]
|
143
|
+
assert defined(lSections), "no such set #{OL(name)}"
|
144
|
+
assert nonEmpty(lSections), "empty section #{OL(name)}"
|
145
|
+
return @section(lSections[lSections.length - 1])
|
146
|
+
|
147
|
+
# ..........................................................
|
148
|
+
|
149
|
+
length: (desc=undef) ->
|
150
|
+
|
151
|
+
result = 0
|
152
|
+
for sect from @allSections(desc)
|
153
|
+
result += sect.length()
|
154
|
+
return result
|
155
|
+
|
156
|
+
# ..........................................................
|
157
|
+
|
158
|
+
isEmpty: (desc=undef) ->
|
159
|
+
|
160
|
+
return (@length(desc) == 0)
|
161
|
+
|
162
|
+
# ..........................................................
|
163
|
+
|
164
|
+
nonEmpty: (desc=undef) ->
|
165
|
+
|
166
|
+
return (@length(desc) > 0)
|
167
|
+
|
168
|
+
# ..........................................................
|
169
|
+
|
170
|
+
indent: (desc=undef, level=1) ->
|
171
|
+
|
172
|
+
for sect from @allSections(desc)
|
173
|
+
sect.indent(level)
|
174
|
+
return
|
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
|
206
|
+
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
|
@@ -0,0 +1,257 @@
|
|
1
|
+
// Generated by CoffeeScript 2.7.0
|
2
|
+
// SectionMap.coffee
|
3
|
+
var isSectionName, isSetName;
|
4
|
+
|
5
|
+
import {
|
6
|
+
assert,
|
7
|
+
pass,
|
8
|
+
undef,
|
9
|
+
defined,
|
10
|
+
croak,
|
11
|
+
OL,
|
12
|
+
isEmpty,
|
13
|
+
nonEmpty,
|
14
|
+
isString,
|
15
|
+
isHash,
|
16
|
+
isArray,
|
17
|
+
isUniqueTree,
|
18
|
+
isNonEmptyString
|
19
|
+
} from '@jdeighan/coffee-utils';
|
20
|
+
|
21
|
+
import {
|
22
|
+
arrayToBlock
|
23
|
+
} from '@jdeighan/coffee-utils/block';
|
24
|
+
|
25
|
+
import {
|
26
|
+
debug
|
27
|
+
} from '@jdeighan/coffee-utils/debug';
|
28
|
+
|
29
|
+
import {
|
30
|
+
Section
|
31
|
+
} from '@jdeighan/coffee-utils/section';
|
32
|
+
|
33
|
+
// ---------------------------------------------------------------------------
|
34
|
+
isSectionName = function(name) {
|
35
|
+
assert(isString(name), "not a string");
|
36
|
+
return name.match(/^[a-z][a-z0-9]*/);
|
37
|
+
};
|
38
|
+
|
39
|
+
// ---------------------------------------------------------------------------
|
40
|
+
isSetName = function(name) {
|
41
|
+
assert(isString(name), "not a string");
|
42
|
+
return name.match(/^[A-Z][a-z0-9]*/);
|
43
|
+
};
|
44
|
+
|
45
|
+
// ---------------------------------------------------------------------------
|
46
|
+
export var SectionMap = class SectionMap {
|
47
|
+
constructor(lSections) {
|
48
|
+
// --- lSections is a tree of section names
|
49
|
+
debug("enter SectionMap()", lSections);
|
50
|
+
this.lSections = lSections; // a tree of section names
|
51
|
+
this.hSets = {};
|
52
|
+
this.hSections = {};
|
53
|
+
this.addSections(lSections);
|
54
|
+
debug("return from SectionMap()", this.hSections);
|
55
|
+
}
|
56
|
+
|
57
|
+
// ..........................................................
|
58
|
+
|
59
|
+
// --- TODO: Allow array to start with a set name ---
|
60
|
+
addSections(desc) {
|
61
|
+
var i, item, len;
|
62
|
+
if (isString(desc)) {
|
63
|
+
assert(nonEmpty(desc), "empty section name");
|
64
|
+
assert(desc.match(/^[a-z][a-z0-9]*$/), `bad section name ${OL(desc)}`);
|
65
|
+
assert(this.hSections[desc] === undef, `duplicate section ${OL(desc)}`);
|
66
|
+
this.hSections[desc] = new Section();
|
67
|
+
} else {
|
68
|
+
assert(isArray(desc), `not an array or string ${OL(desc)}`);
|
69
|
+
for (i = 0, len = desc.length; i < len; i++) {
|
70
|
+
item = desc[i];
|
71
|
+
this.addSections(item);
|
72
|
+
}
|
73
|
+
}
|
74
|
+
}
|
75
|
+
|
76
|
+
// ..........................................................
|
77
|
+
// --- a generator - yield order is not guaranteed
|
78
|
+
* allSections(desc) {
|
79
|
+
var _, i, j, lNames, len, len1, name, ref, ref1, sect;
|
80
|
+
debug("enter allSections()");
|
81
|
+
if (desc === undef) {
|
82
|
+
// --- We want to return all sections
|
83
|
+
debug("yield all sections");
|
84
|
+
ref = this.hSections;
|
85
|
+
for (_ in ref) {
|
86
|
+
sect = ref[_];
|
87
|
+
yield sect;
|
88
|
+
}
|
89
|
+
} else if (isString(desc)) {
|
90
|
+
if (isSectionName(desc)) {
|
91
|
+
debug(`yield section ${OL(desc)}`);
|
92
|
+
yield this.section(desc);
|
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
|
+
}
|
121
|
+
} else {
|
122
|
+
croak(`bad name ${OL(name)}`);
|
123
|
+
}
|
124
|
+
}
|
125
|
+
}
|
126
|
+
debug("return from allSections()");
|
127
|
+
}
|
128
|
+
|
129
|
+
// ..........................................................
|
130
|
+
addSet(name, lSections) {
|
131
|
+
var i, len, secName;
|
132
|
+
debug("enter addSet()", name, lSections);
|
133
|
+
// --- check the name
|
134
|
+
assert(isSetName(name), `not a valid set name ${OL(name)}`);
|
135
|
+
// --- check lSections
|
136
|
+
assert(isArray(lSections), "arg 2 not an array");
|
137
|
+
for (i = 0, len = lSections.length; i < len; i++) {
|
138
|
+
secName = lSections[i];
|
139
|
+
assert(isNonEmptyString(secName), `not a non-empty string ${OL(secName)}`);
|
140
|
+
assert(defined(this.hSections[secName]), `not a section name ${OL(secName)}`);
|
141
|
+
}
|
142
|
+
this.hSets[name] = lSections;
|
143
|
+
debug('hSets', this.hSets);
|
144
|
+
debug("return from addSet()");
|
145
|
+
}
|
146
|
+
|
147
|
+
// ..........................................................
|
148
|
+
section(name) {
|
149
|
+
var sect;
|
150
|
+
sect = this.hSections[name];
|
151
|
+
assert(defined(sect), `No section named ${OL(name)}`);
|
152
|
+
return sect;
|
153
|
+
}
|
154
|
+
|
155
|
+
// ..........................................................
|
156
|
+
firstSection(name) {
|
157
|
+
var lSections;
|
158
|
+
assert(isSetName(name), `bad set name ${OL(name)}`);
|
159
|
+
lSections = this.hSets[name];
|
160
|
+
assert(defined(lSections), `no such set ${OL(name)}`);
|
161
|
+
assert(nonEmpty(lSections), `empty section ${OL(name)}`);
|
162
|
+
return this.section(lSections[0]);
|
163
|
+
}
|
164
|
+
|
165
|
+
// ..........................................................
|
166
|
+
lastSection(name) {
|
167
|
+
var lSections;
|
168
|
+
assert(isSetName(name), `bad set name ${OL(name)}`);
|
169
|
+
lSections = this.hSets[name];
|
170
|
+
assert(defined(lSections), `no such set ${OL(name)}`);
|
171
|
+
assert(nonEmpty(lSections), `empty section ${OL(name)}`);
|
172
|
+
return this.section(lSections[lSections.length - 1]);
|
173
|
+
}
|
174
|
+
|
175
|
+
// ..........................................................
|
176
|
+
length(desc = undef) {
|
177
|
+
var ref, result, sect;
|
178
|
+
result = 0;
|
179
|
+
ref = this.allSections(desc);
|
180
|
+
for (sect of ref) {
|
181
|
+
result += sect.length();
|
182
|
+
}
|
183
|
+
return result;
|
184
|
+
}
|
185
|
+
|
186
|
+
// ..........................................................
|
187
|
+
isEmpty(desc = undef) {
|
188
|
+
return this.length(desc) === 0;
|
189
|
+
}
|
190
|
+
|
191
|
+
// ..........................................................
|
192
|
+
nonEmpty(desc = undef) {
|
193
|
+
return this.length(desc) > 0;
|
194
|
+
}
|
195
|
+
|
196
|
+
// ..........................................................
|
197
|
+
indent(desc = undef, level = 1) {
|
198
|
+
var ref, sect;
|
199
|
+
ref = this.allSections(desc);
|
200
|
+
for (sect of ref) {
|
201
|
+
sect.indent(level);
|
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)}`);
|
223
|
+
}
|
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);
|
236
|
+
return result;
|
237
|
+
}
|
238
|
+
|
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
|
+
};
|
package/src/coffee_utils.coffee
CHANGED
@@ -296,6 +296,26 @@ export isUniqueList = (lItems, func=undef) ->
|
|
296
296
|
|
297
297
|
# ---------------------------------------------------------------------------
|
298
298
|
|
299
|
+
export isUniqueTree = (lItems, func=undef, hFound={}) ->
|
300
|
+
|
301
|
+
if isEmpty(lItems)
|
302
|
+
return true # empty list is unique
|
303
|
+
if defined(func)
|
304
|
+
assert isFunction(func), "Not a function: #{OL(func)}"
|
305
|
+
for item in lItems
|
306
|
+
if isArray(item)
|
307
|
+
if ! isUniqueTree(item, func, hFound)
|
308
|
+
return false
|
309
|
+
else
|
310
|
+
if defined(func) && !func(item)
|
311
|
+
return false
|
312
|
+
if defined(hFound[item])
|
313
|
+
return false
|
314
|
+
hFound[item] = 1
|
315
|
+
return true
|
316
|
+
|
317
|
+
# ---------------------------------------------------------------------------
|
318
|
+
|
299
319
|
export uniq = (lItems) ->
|
300
320
|
|
301
321
|
return [...new Set(lItems)]
|
package/src/coffee_utils.js
CHANGED
@@ -303,6 +303,34 @@ export var isUniqueList = function(lItems, func = undef) {
|
|
303
303
|
return true;
|
304
304
|
};
|
305
305
|
|
306
|
+
// ---------------------------------------------------------------------------
|
307
|
+
export var isUniqueTree = function(lItems, func = undef, hFound = {}) {
|
308
|
+
var i, item, len;
|
309
|
+
if (isEmpty(lItems)) {
|
310
|
+
return true; // empty list is unique
|
311
|
+
}
|
312
|
+
if (defined(func)) {
|
313
|
+
assert(isFunction(func), `Not a function: ${OL(func)}`);
|
314
|
+
}
|
315
|
+
for (i = 0, len = lItems.length; i < len; i++) {
|
316
|
+
item = lItems[i];
|
317
|
+
if (isArray(item)) {
|
318
|
+
if (!isUniqueTree(item, func, hFound)) {
|
319
|
+
return false;
|
320
|
+
}
|
321
|
+
} else {
|
322
|
+
if (defined(func) && !func(item)) {
|
323
|
+
return false;
|
324
|
+
}
|
325
|
+
if (defined(hFound[item])) {
|
326
|
+
return false;
|
327
|
+
}
|
328
|
+
hFound[item] = 1;
|
329
|
+
}
|
330
|
+
}
|
331
|
+
return true;
|
332
|
+
};
|
333
|
+
|
306
334
|
// ---------------------------------------------------------------------------
|
307
335
|
export var uniq = function(lItems) {
|
308
336
|
return [...new Set(lItems)];
|