@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 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.0",
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,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-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
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
- allSections: (desc=undef, level=0) ->
88
+ debug "enter SectionMap.getBlock()", desc, hProcs
95
89
 
96
- debug "enter allSections()", desc, level
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
- result = [level, @section(item)]
103
- debug 'yield', result
104
- yield result
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
- pass
102
+ setName = item
103
+ else if isString(item)
104
+ lBlocks.push item # a literal string
107
105
  else
108
- assert isArray(item), "not an array #{OL(item)}"
109
- yield from @allSections(item, level+1)
106
+ croak "Bad item: #{OL(item)}"
107
+ block = arrayToBlock(lBlocks)
110
108
  else if isSectionName(desc)
111
- result = [level, @section(desc)]
112
- debug 'yield', result
113
- yield result
109
+ block = @section(desc).getBlock()
110
+ if defined(proc = hProcs[desc])
111
+ block = proc(block)
114
112
  else if isSetName(desc)
115
- lTree = @hSets[desc]
116
- assert defined(lTree), "Not a Set: #{OL(desc)}"
117
- yield from @allSections(lTree, level)
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 item: #{OL(desc)}"
120
- debug "return from allSections()"
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
- getBlock: (hProc={}, lTree=undef) ->
124
+ isEmpty: () ->
129
125
 
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
126
+ for name,sect of @hSections
127
+ if sect.nonEmpty()
128
+ return false
129
+ return true
130
+
131
+ # ..........................................................
156
132
 
157
- debug 'lParts', lParts
158
- result = arrayToBlock(lParts)
159
- debug "return from getBlock()", result
160
- return result
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
- 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])
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
- 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
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-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
104
  }
105
+ debug("return from build()", this.hSections, this.hSets);
95
106
  }
96
107
 
97
108
  // ..........................................................
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
- }
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
- 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;
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
- pass;
133
+ setName = item;
134
+ } else if (isString(item)) {
135
+ lBlocks.push(item); // a literal string
134
136
  } else {
135
- assert(isArray(item), `not an array ${OL(item)}`);
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
- result = [level, this.section(desc)];
141
- debug('yield', result);
142
- yield result;
142
+ block = this.section(desc).getBlock();
143
+ if (defined(proc = hProcs[desc])) {
144
+ block = proc(block);
145
+ }
143
146
  } else if (isSetName(desc)) {
144
- lTree = this.hSets[desc];
145
- assert(defined(lTree), `Not a Set: ${OL(desc)}`);
146
- yield* this.allSections(lTree, level);
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 item: ${OL(desc)}`);
153
+ croak(`Bad 1st arg: ${OL(desc)}`);
149
154
  }
150
- debug("return from allSections()");
155
+ debug("return from SectionMap.getBlock()", block);
156
+ return block;
151
157
  }
152
158
 
153
159
  // ..........................................................
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)}`);
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
- if (defined(block)) {
189
- lParts.push(block);
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
- debug('lParts', lParts);
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 lSectionTree;
195
+ var lSubTree;
209
196
  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]);
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 lSectionTree;
204
+ var lSubTree;
219
205
  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;
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
  };
@@ -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
  };