@jdeighan/coffee-utils 9.0.5 → 10.0.2

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@jdeighan/coffee-utils",
3
3
  "type": "module",
4
- "version": "9.0.5",
4
+ "version": "10.0.2",
5
5
  "description": "A set of utility functions for CoffeeScript",
6
6
  "main": "coffee_utils.js",
7
7
  "exports": {
@@ -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
- return arrayToBlock(@lParts)
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
- return arrayToBlock(this.lParts);
106
+ result = arrayToBlock(this.lParts);
107
+ debug("return from Section.getBlock()", result);
108
+ return result;
95
109
  }
96
110
  }
97
111
 
@@ -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-9]*/)
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-9]*/)
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 = lSectionTree # a tree of section names
35
- @hSets = {}
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
- @addSections lSectionTree
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
- addSections: (desc) ->
43
- # --- returns a flat array of sections that were added
44
-
45
- if isString(desc)
46
- assert nonEmpty(desc), "empty section name"
47
- assert isSectionName(desc), "bad section name #{OL(desc)}"
48
- assert (@hSections[desc] == undef), "duplicate section #{OL(desc)}"
49
- @hSections[desc] = new Section(desc)
50
- return [desc]
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
- assert isArray(desc), "not an array or string #{OL(desc)}"
53
- name = undef
54
- lParts = []
55
- for item,i in desc
56
- if (i==0) && isSetName(item)
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
- lAdded = @addSections item
60
- for item in lAdded
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
- addSet: (name, lSectionTree) ->
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
- allSections: (desc=undef, level=0) ->
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
- debug "enter allSections()", desc, level
97
- if (desc == undef)
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
- if isSectionName(item)
102
- result = [level, @section(item)]
103
- debug 'yield', result
104
- yield result
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
- pass
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
- assert isArray(item), "not an array #{OL(item)}"
109
- yield from @allSections(item, level+1)
125
+ debug "NO REPLACER for #{setName}"
110
126
  else if isSectionName(desc)
111
- result = [level, @section(desc)]
112
- debug 'yield', result
113
- yield result
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
- lTree = @hSets[desc]
116
- assert defined(lTree), "Not a Set: #{OL(desc)}"
117
- yield from @allSections(lTree, level)
134
+ # --- pass array to getBlock()
135
+ block = @getBlock(@hSets[desc], hReplacers)
118
136
  else
119
- croak "Bad item: #{OL(desc)}"
120
- debug "return from allSections()"
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
- getBlock: (hProc={}, lTree=undef) ->
143
+ isEmpty: () ->
129
144
 
130
- debug "enter getBlock()"
131
- if (lTree == undef)
132
- lTree = @lSectionTree
133
- else
134
- assert isArray(lTree), "not an array #{OL(lTree)}"
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
145
+ for name,sect of @hSections
146
+ if sect.nonEmpty()
147
+ return false
148
+ return true
149
+
150
+ # ..........................................................
151
+
152
+ nonEmpty: () ->
156
153
 
157
- debug 'lParts', lParts
158
- result = arrayToBlock(lParts)
159
- debug "return from getBlock()", result
160
- return result
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
- lSectionTree = @hSets[name]
176
- assert defined(lSectionTree), "no such set #{OL(name)}"
177
- assert nonEmpty(lSectionTree), "empty section #{OL(name)}"
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
- lSectionTree = @hSets[name]
186
- assert defined(lSectionTree), "no such set #{OL(name)}"
187
- assert nonEmpty(lSectionTree), "empty section #{OL(name)}"
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-9]*/);
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-9]*/);
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
- // --- lSectionTree is a tree of section names
56
- debug("enter SectionMap()", lSectionTree);
57
- this.lSectionTree = lSectionTree; // a tree of section names
58
- this.hSets = {};
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
- this.addSections(lSectionTree);
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
- addSections(desc) {
66
- var i, item, j, k, lAdded, lParts, len, len1, name;
67
- // --- returns a flat array of sections that were added
68
- if (isString(desc)) {
69
- assert(nonEmpty(desc), "empty section name");
70
- assert(isSectionName(desc), `bad section name ${OL(desc)}`);
71
- assert(this.hSections[desc] === undef, `duplicate section ${OL(desc)}`);
72
- this.hSections[desc] = new Section(desc);
73
- return [desc];
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
- assert(isArray(desc), `not an array or string ${OL(desc)}`);
76
- name = undef;
77
- lParts = [];
78
- for (i = j = 0, len = desc.length; j < len; i = ++j) {
79
- item = desc[i];
80
- if ((i === 0) && isSetName(item)) {
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
- lAdded = this.addSections(item);
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[name] = lSectionTree;
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
- // --- 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, 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
- for (j = 0, len = desc.length; j < len; j++) {
127
- item = desc[j];
128
- if (isSectionName(item)) {
129
- result = [level, this.section(item)];
130
- debug('yield', result);
131
- yield result;
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
- pass;
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
- assert(isArray(item), `not an array ${OL(item)}`);
136
- yield* this.allSections(item, level + 1);
158
+ debug(`NO REPLACER for ${setName}`);
137
159
  }
138
160
  }
139
161
  } else if (isSectionName(desc)) {
140
- result = [level, this.section(desc)];
141
- debug('yield', result);
142
- yield result;
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
- lTree = this.hSets[desc];
145
- assert(defined(lTree), `Not a Set: ${OL(desc)}`);
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 item: ${OL(desc)}`);
173
+ croak(`Bad 1st arg: ${OL(desc)}`);
149
174
  }
150
- debug("return from allSections()");
175
+ debug("return from SectionMap.getBlock()", block);
176
+ return block;
151
177
  }
152
178
 
153
179
  // ..........................................................
154
- // --- hProc should be <name> -> <function>
155
- // <function> should be <block> -> <block>
156
- // --- lTree allows you to get just a section
157
- getBlock(hProc = {}, lTree = undef) {
158
- var block, j, lParts, len, part, result;
159
- debug("enter getBlock()");
160
- if (lTree === undef) {
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
- if (defined(block)) {
189
- lParts.push(block);
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
- debug('lParts', lParts);
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 lSectionTree;
215
+ var lSubTree;
209
216
  assert(isSetName(name), `bad set name ${OL(name)}`);
210
- lSectionTree = this.hSets[name];
211
- assert(defined(lSectionTree), `no such set ${OL(name)}`);
212
- assert(nonEmpty(lSectionTree), `empty section ${OL(name)}`);
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 lSectionTree;
224
+ var lSubTree;
219
225
  assert(isSetName(name), `bad set name ${OL(name)}`);
220
- lSectionTree = this.hSets[name];
221
- assert(defined(lSectionTree), `no such set ${OL(name)}`);
222
- assert(nonEmpty(lSectionTree), `empty section ${OL(name)}`);
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
  };
@@ -3,7 +3,7 @@
3
3
  import fs from 'fs'
4
4
  import readline from 'readline'
5
5
 
6
- import {assert, error} from '@jdeighan/unit-tester/utils'
6
+ import {assert, error, croak} from '@jdeighan/unit-tester/utils'
7
7
  import {
8
8
  undef, defined, isEmpty, isString, isArray, nonEmpty, rtrim,
9
9
  } from '@jdeighan/coffee-utils'
@@ -6,7 +6,8 @@ import readline from 'readline';
6
6
 
7
7
  import {
8
8
  assert,
9
- error
9
+ error,
10
+ croak
10
11
  } from '@jdeighan/unit-tester/utils';
11
12
 
12
13
  import {
@@ -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)
@@ -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);
@@ -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 pre + "\n" + indented(text) + "\n" + post
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
+ ])
@@ -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 + "\n" + indented(text) + "\n" + post;
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
  };