@jdeighan/coffee-utils 9.0.5 → 10.0.2

Sign up to get free protection for your applications and to get access to all the features.
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
  };