@jdeighan/coffee-utils 8.0.4 → 8.0.5

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.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
  }