@jdeighan/coffee-utils 8.0.4 → 8.0.5

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