@jdeighan/coffee-utils 8.0.4 → 8.0.7

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": "8.0.4",
4
+ "version": "8.0.7",
5
5
  "description": "A set of utility functions for CoffeeScript",
6
6
  "main": "coffee_utils.js",
7
7
  "exports": {
@@ -10,36 +10,36 @@ import {indented} from '@jdeighan/coffee-utils/indent'
10
10
 
11
11
  export class Section
12
12
 
13
- constructor: () ->
13
+ constructor: (@name) ->
14
14
 
15
- @lLines = []
15
+ @lParts = []
16
16
 
17
17
  # ..........................................................
18
18
 
19
19
  length: () ->
20
20
 
21
- return @lLines.length
21
+ return @lParts.length
22
22
 
23
23
  # ..........................................................
24
24
 
25
25
  indent: (level=1) ->
26
26
 
27
- lNewLines = for line in @lLines
27
+ lNewLines = for line in @lParts
28
28
  indented(line, level)
29
- @lLines = lNewLines
29
+ @lParts = lNewLines
30
30
  return
31
31
 
32
32
  # ..........................................................
33
33
 
34
34
  isEmpty: () ->
35
35
 
36
- return (@lLines.length == 0)
36
+ return (@lParts.length == 0)
37
37
 
38
38
  # ..........................................................
39
39
 
40
40
  nonEmpty: () ->
41
41
 
42
- return (@lLines.length > 0)
42
+ return (@lParts.length > 0)
43
43
 
44
44
  # ..........................................................
45
45
 
@@ -47,9 +47,9 @@ export class Section
47
47
 
48
48
  if isArray(data)
49
49
  for line in data
50
- @lLines.push line
50
+ @lParts.push line
51
51
  else
52
- @lLines.push data
52
+ @lParts.push data
53
53
  return
54
54
 
55
55
  # ..........................................................
@@ -57,13 +57,22 @@ export class Section
57
57
  prepend: (data) ->
58
58
 
59
59
  if isArray(data)
60
- @lLines = [data..., @lLines...]
60
+ @lParts = [data..., @lParts...]
61
61
  else
62
- @lLines = [data, @lLines...]
62
+ @lParts = [data, @lParts...]
63
63
  return
64
64
 
65
65
  # ..........................................................
66
66
 
67
+ getParts: () ->
68
+
69
+ return @lParts
70
+
71
+ # ..........................................................
72
+
67
73
  getBlock: () ->
68
74
 
69
- return arrayToBlock(@lLines)
75
+ if (@lParts.length == 0)
76
+ return undef
77
+ else
78
+ return arrayToBlock(@lParts)
package/src/Section.js CHANGED
@@ -19,13 +19,14 @@ import {
19
19
 
20
20
  // ---------------------------------------------------------------------------
21
21
  export var Section = class Section {
22
- constructor() {
23
- this.lLines = [];
22
+ constructor(name) {
23
+ this.name = name;
24
+ this.lParts = [];
24
25
  }
25
26
 
26
27
  // ..........................................................
27
28
  length() {
28
- return this.lLines.length;
29
+ return this.lParts.length;
29
30
  }
30
31
 
31
32
  // ..........................................................
@@ -33,7 +34,7 @@ export var Section = class Section {
33
34
  var lNewLines, line;
34
35
  lNewLines = (function() {
35
36
  var i, len, ref, results;
36
- ref = this.lLines;
37
+ ref = this.lParts;
37
38
  results = [];
38
39
  for (i = 0, len = ref.length; i < len; i++) {
39
40
  line = ref[i];
@@ -41,17 +42,17 @@ export var Section = class Section {
41
42
  }
42
43
  return results;
43
44
  }).call(this);
44
- this.lLines = lNewLines;
45
+ this.lParts = lNewLines;
45
46
  }
46
47
 
47
48
  // ..........................................................
48
49
  isEmpty() {
49
- return this.lLines.length === 0;
50
+ return this.lParts.length === 0;
50
51
  }
51
52
 
52
53
  // ..........................................................
53
54
  nonEmpty() {
54
- return this.lLines.length > 0;
55
+ return this.lParts.length > 0;
55
56
  }
56
57
 
57
58
  // ..........................................................
@@ -60,25 +61,34 @@ export var Section = class Section {
60
61
  if (isArray(data)) {
61
62
  for (i = 0, len = data.length; i < len; i++) {
62
63
  line = data[i];
63
- this.lLines.push(line);
64
+ this.lParts.push(line);
64
65
  }
65
66
  } else {
66
- this.lLines.push(data);
67
+ this.lParts.push(data);
67
68
  }
68
69
  }
69
70
 
70
71
  // ..........................................................
71
72
  prepend(data) {
72
73
  if (isArray(data)) {
73
- this.lLines = [...data, ...this.lLines];
74
+ this.lParts = [...data, ...this.lParts];
74
75
  } else {
75
- this.lLines = [data, ...this.lLines];
76
+ this.lParts = [data, ...this.lParts];
76
77
  }
77
78
  }
78
79
 
80
+ // ..........................................................
81
+ getParts() {
82
+ return this.lParts;
83
+ }
84
+
79
85
  // ..........................................................
80
86
  getBlock() {
81
- return arrayToBlock(this.lLines);
87
+ if (this.lParts.length === 0) {
88
+ return undef;
89
+ } else {
90
+ return arrayToBlock(this.lParts);
91
+ }
82
92
  }
83
93
 
84
94
  };
@@ -3,8 +3,10 @@
3
3
  import {
4
4
  assert, pass, undef, defined, croak, OL, isEmpty, nonEmpty,
5
5
  isString, isHash, isArray, isUniqueTree, isNonEmptyString,
6
+ isNonEmptyArray,
6
7
  } from '@jdeighan/coffee-utils'
7
8
  import {arrayToBlock} from '@jdeighan/coffee-utils/block'
9
+ import {indented} from '@jdeighan/coffee-utils/indent'
8
10
  import {debug} from '@jdeighan/coffee-utils/debug'
9
11
  import {Section} from '@jdeighan/coffee-utils/section'
10
12
 
@@ -12,110 +14,148 @@ import {Section} from '@jdeighan/coffee-utils/section'
12
14
 
13
15
  isSectionName = (name) ->
14
16
 
15
- assert isString(name), "not a string"
16
- return name.match(/^[a-z][a-z0-9]*/)
17
+ return isString(name) && name.match(/^[a-z][a-z0-9]*/)
17
18
 
18
19
  # ---------------------------------------------------------------------------
19
20
 
20
21
  isSetName = (name) ->
21
22
 
22
- assert isString(name), "not a string"
23
- return name.match(/^[A-Z][a-z0-9]*/)
23
+ return isString(name) && name.match(/^[A-Z][a-z0-9]*/)
24
24
 
25
25
  # ---------------------------------------------------------------------------
26
26
 
27
27
  export class SectionMap
28
28
 
29
- constructor: (lSections) ->
30
- # --- lSections is a tree of section names
29
+ constructor: (lSectionTree) ->
30
+ # --- lSectionTree is a tree of section names
31
31
 
32
- debug "enter SectionMap()", lSections
33
- @lSections = lSections # a tree of section names
32
+ debug "enter SectionMap()", lSectionTree
33
+ @lSectionTree = lSectionTree # a tree of section names
34
34
  @hSets = {}
35
35
  @hSections = {}
36
- @addSections lSections
36
+ @addSections lSectionTree
37
37
  debug "return from SectionMap()", @hSections
38
38
 
39
39
  # ..........................................................
40
40
 
41
- # --- TODO: Allow array to start with a set name ---
42
-
43
41
  addSections: (desc) ->
42
+ # --- returns a flat array of sections that were added
44
43
 
45
44
  if isString(desc)
46
45
  assert nonEmpty(desc), "empty section name"
47
- assert desc.match(/^[a-z][a-z0-9]*$/), "bad section name #{OL(desc)}"
46
+ assert isSectionName(desc), "bad section name #{OL(desc)}"
48
47
  assert (@hSections[desc] == undef), "duplicate section #{OL(desc)}"
49
- @hSections[desc] = new Section()
48
+ @hSections[desc] = new Section(desc)
49
+ return [desc]
50
50
  else
51
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
52
+ name = undef
53
+ lParts = []
54
+ for item,i in desc
55
+ if (i==0) && isSetName(item)
56
+ name = item
92
57
  else
93
- croak "bad name #{OL(name)}"
94
- debug "return from allSections()"
58
+ lAdded = @addSections item
59
+ for item in lAdded
60
+ lParts.push item
61
+ if defined(name)
62
+ @addSet name, lParts
63
+ return lParts
95
64
  return
96
65
 
97
66
  # ..........................................................
98
67
 
99
- addSet: (name, lSections) ->
68
+ addSet: (name, lSectionTree) ->
100
69
 
101
- debug "enter addSet()", name, lSections
70
+ debug "enter addSet()", name, lSectionTree
102
71
 
103
72
  # --- check the name
104
73
  assert isSetName(name), "not a valid set name #{OL(name)}"
105
74
 
106
- # --- check lSections
107
- assert isArray(lSections), "arg 2 not an array"
108
- for secName in lSections
75
+ # --- check lSectionTree
76
+ assert isArray(lSectionTree), "arg 2 not an array"
77
+ for secName in lSectionTree
109
78
  assert isNonEmptyString(secName),
110
79
  "not a non-empty string #{OL(secName)}"
111
80
  assert defined(@hSections[secName]),
112
81
  "not a section name #{OL(secName)}"
113
82
 
114
- @hSets[name] = lSections
83
+ @hSets[name] = lSectionTree
115
84
  debug 'hSets', @hSets
116
85
  debug "return from addSet()"
117
86
  return
118
87
 
88
+ # ..........................................................
89
+ # --- sections returned in depth-first order from section tree
90
+ # Set names are simply skipped
91
+ # yields: [<level>, <section>]
92
+
93
+ allSections: (desc=undef, level=0) ->
94
+
95
+ debug "enter allSections()", desc, level
96
+ if (desc == undef)
97
+ desc = @lSectionTree
98
+ if isArray(desc)
99
+ for item in desc
100
+ if isSectionName(item)
101
+ result = [level, @section(item)]
102
+ debug 'yield', result
103
+ yield result
104
+ else if isSetName(item)
105
+ pass
106
+ else
107
+ assert isArray(item), "not an array #{OL(item)}"
108
+ yield from @allSections(item, level+1)
109
+ else if isSectionName(desc)
110
+ result = [level, @section(desc)]
111
+ debug 'yield', result
112
+ yield result
113
+ else if isSetName(desc)
114
+ lTree = @hSets[desc]
115
+ assert defined(lTree), "Not a Set: #{OL(desc)}"
116
+ yield from @allSections(lTree, level)
117
+ else
118
+ croak "Bad item: #{OL(desc)}"
119
+ debug "return from allSections()"
120
+ return
121
+
122
+ # ..........................................................
123
+ # --- procFunc should be (name, block) ->
124
+ # return processed block
125
+
126
+ getBlock: (procFunc=undef, lTree=undef) ->
127
+
128
+ debug "enter getBlock()"
129
+ if (lTree == undef)
130
+ lTree = @lSectionTree
131
+ else
132
+ assert isArray(lTree), "not an array #{OL(lTree)}"
133
+
134
+ lParts = []
135
+ for part in lTree
136
+ if isString(part)
137
+ text = @section(part).getBlock()
138
+ if nonEmpty(text) && defined(procFunc)
139
+ text = procFunc(part, text)
140
+ else if isNonEmptyArray(part)
141
+ if isSectionName(part[0])
142
+ text = @getBlock(procFunc, part)
143
+ else if isSetName(part[0])
144
+ text = @getBlock(procFunc, part.slice(1))
145
+ if nonEmpty(text) && defined(procFunc)
146
+ text = procFunc(part[0], text)
147
+ else
148
+ croak "Bad part: #{OL(part)}"
149
+ else
150
+ croak "Bad part: #{OL(part)}"
151
+ if defined(text)
152
+ lParts.push text
153
+
154
+ debug 'lParts', lParts
155
+ result = arrayToBlock(lParts)
156
+ debug "return from getBlock()", result
157
+ return result
158
+
119
159
  # ..........................................................
120
160
 
121
161
  section: (name) ->
@@ -129,27 +169,27 @@ export class SectionMap
129
169
  firstSection: (name) ->
130
170
 
131
171
  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])
172
+ lSectionTree = @hSets[name]
173
+ assert defined(lSectionTree), "no such set #{OL(name)}"
174
+ assert nonEmpty(lSectionTree), "empty section #{OL(name)}"
175
+ return @section(lSectionTree[0])
136
176
 
137
177
  # ..........................................................
138
178
 
139
179
  lastSection: (name) ->
140
180
 
141
181
  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])
182
+ lSectionTree = @hSets[name]
183
+ assert defined(lSectionTree), "no such set #{OL(name)}"
184
+ assert nonEmpty(lSectionTree), "empty section #{OL(name)}"
185
+ return @section(lSectionTree[lSectionTree.length - 1])
146
186
 
147
187
  # ..........................................................
148
188
 
149
189
  length: (desc=undef) ->
150
190
 
151
191
  result = 0
152
- for sect from @allSections(desc)
192
+ for [_, sect] from @allSections(desc)
153
193
  result += sect.length()
154
194
  return result
155
195
 
@@ -167,55 +207,12 @@ export class SectionMap
167
207
 
168
208
  # ..........................................................
169
209
 
170
- indent: (desc=undef, level=1) ->
210
+ getShape: () ->
171
211
 
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
212
+ debug "enter getShape()"
213
+ lParts = []
214
+ for [level, sect] from @allSections()
215
+ lParts.push indented(sect.name, level)
216
+ result = arrayToBlock(lParts)
217
+ debug "return from getShape()", result
206
218
  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
package/src/SectionMap.js CHANGED
@@ -15,13 +15,18 @@ import {
15
15
  isHash,
16
16
  isArray,
17
17
  isUniqueTree,
18
- isNonEmptyString
18
+ isNonEmptyString,
19
+ isNonEmptyArray
19
20
  } from '@jdeighan/coffee-utils';
20
21
 
21
22
  import {
22
23
  arrayToBlock
23
24
  } from '@jdeighan/coffee-utils/block';
24
25
 
26
+ import {
27
+ indented
28
+ } from '@jdeighan/coffee-utils/indent';
29
+
25
30
  import {
26
31
  debug
27
32
  } from '@jdeighan/coffee-utils/debug';
@@ -32,116 +37,156 @@ import {
32
37
 
33
38
  // ---------------------------------------------------------------------------
34
39
  isSectionName = function(name) {
35
- assert(isString(name), "not a string");
36
- return name.match(/^[a-z][a-z0-9]*/);
40
+ return isString(name) && name.match(/^[a-z][a-z0-9]*/);
37
41
  };
38
42
 
39
43
  // ---------------------------------------------------------------------------
40
44
  isSetName = function(name) {
41
- assert(isString(name), "not a string");
42
- return name.match(/^[A-Z][a-z0-9]*/);
45
+ return isString(name) && name.match(/^[A-Z][a-z0-9]*/);
43
46
  };
44
47
 
45
48
  // ---------------------------------------------------------------------------
46
49
  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
50
+ constructor(lSectionTree) {
51
+ // --- lSectionTree is a tree of section names
52
+ debug("enter SectionMap()", lSectionTree);
53
+ this.lSectionTree = lSectionTree; // a tree of section names
51
54
  this.hSets = {};
52
55
  this.hSections = {};
53
- this.addSections(lSections);
56
+ this.addSections(lSectionTree);
54
57
  debug("return from SectionMap()", this.hSections);
55
58
  }
56
59
 
57
60
  // ..........................................................
58
-
59
- // --- TODO: Allow array to start with a set name ---
60
61
  addSections(desc) {
61
- var i, item, len;
62
+ var i, item, j, k, lAdded, lParts, len, len1, name;
63
+ // --- returns a flat array of sections that were added
62
64
  if (isString(desc)) {
63
65
  assert(nonEmpty(desc), "empty section name");
64
- assert(desc.match(/^[a-z][a-z0-9]*$/), `bad section name ${OL(desc)}`);
66
+ assert(isSectionName(desc), `bad section name ${OL(desc)}`);
65
67
  assert(this.hSections[desc] === undef, `duplicate section ${OL(desc)}`);
66
- this.hSections[desc] = new Section();
68
+ this.hSections[desc] = new Section(desc);
69
+ return [desc];
67
70
  } else {
68
71
  assert(isArray(desc), `not an array or string ${OL(desc)}`);
69
- for (i = 0, len = desc.length; i < len; i++) {
72
+ name = undef;
73
+ lParts = [];
74
+ for (i = j = 0, len = desc.length; j < len; i = ++j) {
70
75
  item = desc[i];
71
- this.addSections(item);
76
+ if ((i === 0) && isSetName(item)) {
77
+ name = item;
78
+ } else {
79
+ lAdded = this.addSections(item);
80
+ for (k = 0, len1 = lAdded.length; k < len1; k++) {
81
+ item = lAdded[k];
82
+ lParts.push(item);
83
+ }
84
+ }
72
85
  }
86
+ if (defined(name)) {
87
+ this.addSet(name, lParts);
88
+ }
89
+ return lParts;
90
+ }
91
+ }
92
+
93
+ // ..........................................................
94
+ addSet(name, lSectionTree) {
95
+ var j, len, secName;
96
+ debug("enter addSet()", name, lSectionTree);
97
+ // --- check the name
98
+ assert(isSetName(name), `not a valid set name ${OL(name)}`);
99
+ // --- check lSectionTree
100
+ assert(isArray(lSectionTree), "arg 2 not an array");
101
+ for (j = 0, len = lSectionTree.length; j < len; j++) {
102
+ secName = lSectionTree[j];
103
+ assert(isNonEmptyString(secName), `not a non-empty string ${OL(secName)}`);
104
+ assert(defined(this.hSections[secName]), `not a section name ${OL(secName)}`);
73
105
  }
106
+ this.hSets[name] = lSectionTree;
107
+ debug('hSets', this.hSets);
108
+ debug("return from addSet()");
74
109
  }
75
110
 
76
111
  // ..........................................................
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()");
112
+ // --- sections returned in depth-first order from section tree
113
+ // Set names are simply skipped
114
+ // yields: [<level>, <section>]
115
+ * allSections(desc = undef, level = 0) {
116
+ var item, j, lTree, len, result;
117
+ debug("enter allSections()", desc, level);
81
118
  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
- }
119
+ desc = this.lSectionTree;
120
+ }
121
+ if (isArray(desc)) {
122
+ for (j = 0, len = desc.length; j < len; j++) {
123
+ item = desc[j];
124
+ if (isSectionName(item)) {
125
+ result = [level, this.section(item)];
126
+ debug('yield', result);
127
+ yield result;
128
+ } else if (isSetName(item)) {
129
+ pass;
121
130
  } else {
122
- croak(`bad name ${OL(name)}`);
131
+ assert(isArray(item), `not an array ${OL(item)}`);
132
+ yield* this.allSections(item, level + 1);
123
133
  }
124
134
  }
135
+ } else if (isSectionName(desc)) {
136
+ result = [level, this.section(desc)];
137
+ debug('yield', result);
138
+ yield result;
139
+ } else if (isSetName(desc)) {
140
+ lTree = this.hSets[desc];
141
+ assert(defined(lTree), `Not a Set: ${OL(desc)}`);
142
+ yield* this.allSections(lTree, level);
143
+ } else {
144
+ croak(`Bad item: ${OL(desc)}`);
125
145
  }
126
146
  debug("return from allSections()");
127
147
  }
128
148
 
129
149
  // ..........................................................
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)}`);
150
+ // --- procFunc should be (name, block) ->
151
+ // return processed block
152
+ getBlock(procFunc = undef, lTree = undef) {
153
+ var j, lParts, len, part, result, text;
154
+ debug("enter getBlock()");
155
+ if (lTree === undef) {
156
+ lTree = this.lSectionTree;
157
+ } else {
158
+ assert(isArray(lTree), `not an array ${OL(lTree)}`);
141
159
  }
142
- this.hSets[name] = lSections;
143
- debug('hSets', this.hSets);
144
- debug("return from addSet()");
160
+ lParts = [];
161
+ for (j = 0, len = lTree.length; j < len; j++) {
162
+ part = lTree[j];
163
+ if (isString(part)) {
164
+ text = this.section(part).getBlock();
165
+ if (nonEmpty(text) && defined(procFunc)) {
166
+ text = procFunc(part, text);
167
+ }
168
+ } else if (isNonEmptyArray(part)) {
169
+ if (isSectionName(part[0])) {
170
+ text = this.getBlock(procFunc, part);
171
+ } else if (isSetName(part[0])) {
172
+ text = this.getBlock(procFunc, part.slice(1));
173
+ if (nonEmpty(text) && defined(procFunc)) {
174
+ text = procFunc(part[0], text);
175
+ }
176
+ } else {
177
+ croak(`Bad part: ${OL(part)}`);
178
+ }
179
+ } else {
180
+ croak(`Bad part: ${OL(part)}`);
181
+ }
182
+ if (defined(text)) {
183
+ lParts.push(text);
184
+ }
185
+ }
186
+ debug('lParts', lParts);
187
+ result = arrayToBlock(lParts);
188
+ debug("return from getBlock()", result);
189
+ return result;
145
190
  }
146
191
 
147
192
  // ..........................................................
@@ -154,30 +199,31 @@ export var SectionMap = class SectionMap {
154
199
 
155
200
  // ..........................................................
156
201
  firstSection(name) {
157
- var lSections;
202
+ var lSectionTree;
158
203
  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]);
204
+ lSectionTree = this.hSets[name];
205
+ assert(defined(lSectionTree), `no such set ${OL(name)}`);
206
+ assert(nonEmpty(lSectionTree), `empty section ${OL(name)}`);
207
+ return this.section(lSectionTree[0]);
163
208
  }
164
209
 
165
210
  // ..........................................................
166
211
  lastSection(name) {
167
- var lSections;
212
+ var lSectionTree;
168
213
  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]);
214
+ lSectionTree = this.hSets[name];
215
+ assert(defined(lSectionTree), `no such set ${OL(name)}`);
216
+ assert(nonEmpty(lSectionTree), `empty section ${OL(name)}`);
217
+ return this.section(lSectionTree[lSectionTree.length - 1]);
173
218
  }
174
219
 
175
220
  // ..........................................................
176
221
  length(desc = undef) {
177
- var ref, result, sect;
222
+ var _, ref, result, sect, x;
178
223
  result = 0;
179
224
  ref = this.allSections(desc);
180
- for (sect of ref) {
225
+ for (x of ref) {
226
+ [_, sect] = x;
181
227
  result += sect.length();
182
228
  }
183
229
  return result;
@@ -194,64 +240,18 @@ export var SectionMap = class SectionMap {
194
240
  }
195
241
 
196
242
  // ..........................................................
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)}`);
243
+ getShape() {
244
+ var lParts, level, ref, result, sect, x;
245
+ debug("enter getShape()");
246
+ lParts = [];
247
+ ref = this.allSections();
248
+ for (x of ref) {
249
+ [level, sect] = x;
250
+ lParts.push(indented(sect.name, level));
223
251
  }
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);
252
+ result = arrayToBlock(lParts);
253
+ debug("return from getShape()", result);
236
254
  return result;
237
255
  }
238
256
 
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
257
  };
@@ -30,19 +30,31 @@ export blockToArray = (block) ->
30
30
  export arrayToBlock = (lLines) ->
31
31
 
32
32
  if (lLines == undef)
33
- return ''
33
+ return undef
34
34
  assert isArray(lLines), "lLines is not an array"
35
35
  lLines = lLines.filter((line) => defined(line));
36
36
  if lLines.length == 0
37
- return ''
37
+ return undef
38
38
  else
39
39
  return rtrim(lLines.join('\n'))
40
40
 
41
41
  # ---------------------------------------------------------------------------
42
42
 
43
+ export splitBlock = (block) ->
44
+
45
+ assert isString(block), "not a string"
46
+ pos = block.indexOf('\n')
47
+ if (pos == -1)
48
+ return [block, undef]
49
+ else
50
+ return [block.substring(0, pos), block.substring(pos+1)]
51
+
52
+
53
+ # ---------------------------------------------------------------------------
54
+
43
55
  export firstLine = (block) ->
44
56
 
45
- assert isString(block), "firstLine(): string expected"
57
+ assert isString(block), "not a string"
46
58
  pos = block.indexOf('\n')
47
59
  if (pos == -1)
48
60
  return block
@@ -53,10 +65,10 @@ export firstLine = (block) ->
53
65
 
54
66
  export remainingLines = (block) ->
55
67
 
56
- assert isString(block), "remainingLines(): string expected"
68
+ assert isString(block), "not a string"
57
69
  pos = block.indexOf('\n')
58
70
  if (pos == -1)
59
- return ''
71
+ return undef
60
72
  else
61
73
  return block.substring(pos+1)
62
74
 
@@ -38,23 +38,35 @@ export var blockToArray = function(block) {
38
38
  // arrayToBlock - block will have no trailing whitespace
39
39
  export var arrayToBlock = function(lLines) {
40
40
  if (lLines === undef) {
41
- return '';
41
+ return undef;
42
42
  }
43
43
  assert(isArray(lLines), "lLines is not an array");
44
44
  lLines = lLines.filter((line) => {
45
45
  return defined(line);
46
46
  });
47
47
  if (lLines.length === 0) {
48
- return '';
48
+ return undef;
49
49
  } else {
50
50
  return rtrim(lLines.join('\n'));
51
51
  }
52
52
  };
53
53
 
54
+ // ---------------------------------------------------------------------------
55
+ export var splitBlock = function(block) {
56
+ var pos;
57
+ assert(isString(block), "not a string");
58
+ pos = block.indexOf('\n');
59
+ if (pos === -1) {
60
+ return [block, undef];
61
+ } else {
62
+ return [block.substring(0, pos), block.substring(pos + 1)];
63
+ }
64
+ };
65
+
54
66
  // ---------------------------------------------------------------------------
55
67
  export var firstLine = function(block) {
56
68
  var pos;
57
- assert(isString(block), "firstLine(): string expected");
69
+ assert(isString(block), "not a string");
58
70
  pos = block.indexOf('\n');
59
71
  if (pos === -1) {
60
72
  return block;
@@ -66,10 +78,10 @@ export var firstLine = function(block) {
66
78
  // ---------------------------------------------------------------------------
67
79
  export var remainingLines = function(block) {
68
80
  var pos;
69
- assert(isString(block), "remainingLines(): string expected");
81
+ assert(isString(block), "not a string");
70
82
  pos = block.indexOf('\n');
71
83
  if (pos === -1) {
72
- return '';
84
+ return undef;
73
85
  } else {
74
86
  return block.substring(pos + 1);
75
87
  }
@@ -173,6 +173,12 @@ export isArray = (x) ->
173
173
 
174
174
  # ---------------------------------------------------------------------------
175
175
 
176
+ export isNonEmptyArray = (x) ->
177
+
178
+ return isArray(x) && (x.length > 0)
179
+
180
+ # ---------------------------------------------------------------------------
181
+
176
182
  export isHash = (x, lKeys) ->
177
183
 
178
184
  if ! x || (getClassName(x) != 'Object')
@@ -186,6 +192,12 @@ export isHash = (x, lKeys) ->
186
192
 
187
193
  # ---------------------------------------------------------------------------
188
194
 
195
+ export isNonEmptyHash = (x) ->
196
+
197
+ return isHash(x) && (Object.keys(x).length > 0)
198
+
199
+ # ---------------------------------------------------------------------------
200
+
189
201
  export hashHasKey = (x, key) ->
190
202
 
191
203
  assert isHash(x), "hashHasKey(): not a hash"
@@ -159,6 +159,11 @@ export var isArray = function(x) {
159
159
  return Array.isArray(x);
160
160
  };
161
161
 
162
+ // ---------------------------------------------------------------------------
163
+ export var isNonEmptyArray = function(x) {
164
+ return isArray(x) && (x.length > 0);
165
+ };
166
+
162
167
  // ---------------------------------------------------------------------------
163
168
  export var isHash = function(x, lKeys) {
164
169
  var i, key, len;
@@ -177,6 +182,11 @@ export var isHash = function(x, lKeys) {
177
182
  return true;
178
183
  };
179
184
 
185
+ // ---------------------------------------------------------------------------
186
+ export var isNonEmptyHash = function(x) {
187
+ return isHash(x) && (Object.keys(x).length > 0);
188
+ };
189
+
180
190
  // ---------------------------------------------------------------------------
181
191
  export var hashHasKey = function(x, key) {
182
192
  assert(isHash(x), "hashHasKey(): not a hash");
@@ -146,3 +146,10 @@ export tabify = (str, numSpaces=undef) ->
146
146
  export untabify = (str, numSpaces=3) ->
147
147
 
148
148
  return str.replace(/\t/g, ' '.repeat(numSpaces))
149
+
150
+ # ---------------------------------------------------------------------------
151
+ # enclose - indent text, surround with pre and post
152
+
153
+ export enclose = (text, pre, post) ->
154
+
155
+ return pre + "\n" + indented(text) + "\n" + post
@@ -175,3 +175,9 @@ export var tabify = function(str, numSpaces = undef) {
175
175
  export var untabify = function(str, numSpaces = 3) {
176
176
  return str.replace(/\t/g, ' '.repeat(numSpaces));
177
177
  };
178
+
179
+ // ---------------------------------------------------------------------------
180
+ // enclose - indent text, surround with pre and post
181
+ export var enclose = function(text, pre, post) {
182
+ return pre + "\n" + indented(text) + "\n" + post;
183
+ };