@jdeighan/coffee-utils 11.0.30 → 11.0.32

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": "11.0.30",
4
+ "version": "11.0.32",
5
5
  "description": "A set of utility functions for CoffeeScript",
6
6
  "main": "coffee_utils.js",
7
7
  "exports": {
@@ -19,7 +19,6 @@
19
19
  "./svelte": "./src/svelte.js",
20
20
  "./store": "./src/DataStores.js",
21
21
  "./taml": "./src/taml.js",
22
- "./placeholders": "./src/placeholders.js",
23
22
  "./section": "./src/Section.js",
24
23
  "./sectionmap": "./src/SectionMap.js",
25
24
  "./fsa": "./src/fsa.js",
@@ -32,8 +31,7 @@
32
31
  "verbose": false
33
32
  },
34
33
  "scripts": {
35
- "build": "cls && rm -f ./*.js && coffee -c .",
36
- "pretest": "cls && cielo -qfc ./test && coffee -c .",
34
+ "build": "cls && coffee -c .",
37
35
  "test": "npm run build && ava ./test/*.test.js && git status"
38
36
  },
39
37
  "repository": {
@@ -50,7 +48,7 @@
50
48
  },
51
49
  "homepage": "https://github.com/johndeighan/coffee-utils#readme",
52
50
  "dependencies": {
53
- "@jdeighan/exceptions": "^1.0.24",
51
+ "@jdeighan/exceptions": "^1.0.26",
54
52
  "cross-env": "^7.0.3",
55
53
  "js-yaml": "^4.1.0",
56
54
  "n-readlines": "^1.0.1",
@@ -58,6 +56,6 @@
58
56
  "svelte": "^3.52.0"
59
57
  },
60
58
  "devDependencies": {
61
- "@jdeighan/unit-tester": "^2.0.49"
59
+ "@jdeighan/unit-tester": "^2.0.52"
62
60
  }
63
61
  }
@@ -3,36 +3,20 @@
3
3
  import {assert, croak} from '@jdeighan/exceptions'
4
4
  import {debug} from '@jdeighan/exceptions/debug'
5
5
  import {
6
- pass, undef, defined, isArray, isEmpty,
6
+ pass, undef, defined, isArray, isEmpty, isFunction,
7
7
  } from '@jdeighan/coffee-utils'
8
- import {arrayToBlock} from '@jdeighan/coffee-utils/block'
9
- import {indented} from '@jdeighan/coffee-utils/indent'
8
+ import {toBlock} from '@jdeighan/coffee-utils/block'
10
9
 
11
10
  # ---------------------------------------------------------------------------
12
11
 
13
12
  export class Section
14
13
 
15
- constructor: (@name, content=undef) ->
14
+ constructor: (@name, @replacer=undef) ->
16
15
  # --- name can be undef or empty
17
16
 
18
17
  @lParts = []
19
- if defined(content)
20
- @lParts.push content
21
-
22
- # ..........................................................
23
-
24
- length: () ->
25
-
26
- return @lParts.length
27
-
28
- # ..........................................................
29
-
30
- indent: (level=1, oneIndent="\t") ->
31
-
32
- lNewLines = for line in @lParts
33
- indented(line, level, oneIndent)
34
- @lParts = lNewLines
35
- return
18
+ if defined(@replacer)
19
+ assert isFunction(@replacer), "bad replacer"
36
20
 
37
21
  # ..........................................................
38
22
 
@@ -81,7 +65,8 @@ export class Section
81
65
  if (@lParts.length == 0)
82
66
  debug "return undef from Section.getBlock()"
83
67
  return undef
84
- else
85
- result = arrayToBlock(@lParts)
86
- debug "return from Section.getBlock()", result
87
- return result
68
+ block = toBlock(@lParts)
69
+ if defined(@replacer)
70
+ block = @replacer block
71
+ debug "return from Section.getBlock()", block
72
+ return block
package/src/Section.js CHANGED
@@ -14,49 +14,26 @@ import {
14
14
  undef,
15
15
  defined,
16
16
  isArray,
17
- isEmpty
17
+ isEmpty,
18
+ isFunction
18
19
  } from '@jdeighan/coffee-utils';
19
20
 
20
21
  import {
21
- arrayToBlock
22
+ toBlock
22
23
  } from '@jdeighan/coffee-utils/block';
23
24
 
24
- import {
25
- indented
26
- } from '@jdeighan/coffee-utils/indent';
27
-
28
25
  // ---------------------------------------------------------------------------
29
26
  export var Section = class Section {
30
- constructor(name, content = undef) {
27
+ constructor(name, replacer = undef) {
31
28
  this.name = name;
29
+ this.replacer = replacer;
32
30
  // --- name can be undef or empty
33
31
  this.lParts = [];
34
- if (defined(content)) {
35
- this.lParts.push(content);
32
+ if (defined(this.replacer)) {
33
+ assert(isFunction(this.replacer), "bad replacer");
36
34
  }
37
35
  }
38
36
 
39
- // ..........................................................
40
- length() {
41
- return this.lParts.length;
42
- }
43
-
44
- // ..........................................................
45
- indent(level = 1, oneIndent = "\t") {
46
- var lNewLines, line;
47
- lNewLines = (function() {
48
- var i, len, ref, results;
49
- ref = this.lParts;
50
- results = [];
51
- for (i = 0, len = ref.length; i < len; i++) {
52
- line = ref[i];
53
- results.push(indented(line, level, oneIndent));
54
- }
55
- return results;
56
- }).call(this);
57
- this.lParts = lNewLines;
58
- }
59
-
60
37
  // ..........................................................
61
38
  isEmpty() {
62
39
  return this.lParts.length === 0;
@@ -96,16 +73,18 @@ export var Section = class Section {
96
73
 
97
74
  // ..........................................................
98
75
  getBlock() {
99
- var result;
76
+ var block;
100
77
  debug("enter Section.getBlock()");
101
78
  if (this.lParts.length === 0) {
102
79
  debug("return undef from Section.getBlock()");
103
80
  return undef;
104
- } else {
105
- result = arrayToBlock(this.lParts);
106
- debug("return from Section.getBlock()", result);
107
- return result;
108
81
  }
82
+ block = toBlock(this.lParts);
83
+ if (defined(this.replacer)) {
84
+ block = this.replacer(block);
85
+ }
86
+ debug("return from Section.getBlock()", block);
87
+ return block;
109
88
  }
110
89
 
111
90
  };
@@ -1,15 +1,14 @@
1
1
  # SectionMap.coffee
2
2
 
3
- import {assert, croak} from '@jdeighan/exceptions'
4
- import {LOG} from '@jdeighan/exceptions/log'
5
- import {debug} from '@jdeighan/exceptions/debug'
6
3
  import {
7
- pass, undef, defined, notdefined, OL, isEmpty, nonEmpty,
4
+ assert, croak, LOG, LOGVALUE, LOGTAML, debug, isTAML, fromTAML,
5
+ } from '@jdeighan/exceptions'
6
+ import {
7
+ pass, undef, def, notdef, OL, isEmpty, nonEmpty,
8
8
  isString, isHash, isArray, isUniqueTree, isNonEmptyString,
9
- isNonEmptyArray,
9
+ isNonEmptyArray, isFunction, jsType, isArrayOfStrings,
10
10
  } from '@jdeighan/coffee-utils'
11
11
  import {toBlock} from '@jdeighan/coffee-utils/block'
12
- import {isTAML, fromTAML} from '@jdeighan/coffee-utils/taml'
13
12
  import {Section} from '@jdeighan/coffee-utils/section'
14
13
 
15
14
  # ---------------------------------------------------------------------------
@@ -28,142 +27,161 @@ isSetName = (name) ->
28
27
 
29
28
  export class SectionMap
30
29
 
31
- constructor: (@lSectionTree) ->
32
- # --- lSectionTree is a tree of section/set names
33
-
34
- debug "enter SectionMap()", @lSectionTree
30
+ constructor: (tree, @hReplacers={}) ->
31
+ # --- tree is a tree of section/set names
32
+ # or a TAML string that converts to one
33
+ # --- hReplacers are callbacks that are called
34
+ # when a set or section is processed
35
+ # should be <name> -> <function>
36
+ # <name> can be a section name or a set name
37
+ # <function> should be <block> -> <block>
35
38
 
36
- if isTAML(@lSectionTree)
37
- @SectionTree = fromTAML(@lSectionTree)
39
+ debug "enter SectionMap()", tree, @hReplacers
38
40
 
39
- assert isArray(@lSectionTree), "not an array"
41
+ @checkTree tree
42
+ @checkReplacers @hReplacers
40
43
 
41
- # --- keys are section names, values are Section objects
42
- @hSections = {}
44
+ @hSections = {} # --- {section name: Section Object}
45
+ @hSets = {ALL: @lFullTree} # --- {set name: array of parts}
43
46
 
44
- # --- keys are set names, values are subtrees of lSectionTree
45
- @hSets = {}
47
+ @init @lFullTree
46
48
 
47
- @build @lSectionTree
48
- debug "return from SectionMap()", @hSections
49
+ debug 'hSections', @hSections
50
+ debug 'hSets', @hSets
51
+ debug "return from SectionMap()"
49
52
 
50
53
  # ..........................................................
51
54
 
52
- build: (lTree) ->
55
+ init: (lTree) ->
53
56
 
54
- debug "enter build()", lTree
57
+ debug "enter init()", lTree
55
58
  assert isArray(lTree), "not an array"
56
59
  assert nonEmpty(lTree), "empty array"
57
60
 
58
61
  firstItem = lTree[0]
59
62
  if isSetName(firstItem)
60
- assert (lTree.length >= 2), "set without sections"
61
- @hSets[firstItem] = lTree
62
- for item in lTree.slice(1)
63
- if isArray(item)
64
- @build item
65
- else if isSectionName(item)
66
- @hSections[item] = new Section(item)
67
- else if ! isString(item) # string would be literal
68
- croak "Bad section tree: #{OL(@lSectionTree)}"
69
- else
70
- for item in lTree
71
- if isArray(item)
72
- @build item
73
- else if isSectionName(item)
74
- @hSections[item] = new Section(item)
75
- else
76
- croak "Bad section tree: #{OL(@lSectionTree)}"
77
- debug "return from build()", @hSections, @hSets
63
+ debug "found set name #{OL(firstItem)}"
64
+ lTree = lTree.slice(1)
65
+ @mkSet firstItem, lTree
66
+
67
+ for item in lTree
68
+ if isArray(item)
69
+ debug "init subtree"
70
+ @init item
71
+ else if isSectionName(item)
72
+ debug "mkSection #{OL(item)}"
73
+ @mkSection item
74
+ else
75
+ assert isString(item), "Bad item in tree: #{OL(item)}"
76
+ debug "return from init()"
78
77
  return
79
78
 
80
79
  # ..........................................................
81
- # --- hProc should be <name> -> <function>
82
- # <name> can be a section name or a set name
83
- # <function> should be <block> -> <block>
84
- # --- desc can be:
85
- # an array, which may begin with a set name
86
- # a section name
87
- # a set name
88
- # undef (equivalent to being set to @SectionTree)
89
-
90
- getBlock: (desc=undef, hReplacers={}) ->
91
-
92
- debug "enter SectionMap.getBlock()", desc, hReplacers
93
-
94
- # --- desc can only be a string or an array
95
- # so, if it's a hash, then it's really the hReplacers
96
- # and the real desc is undef
97
-
98
- if isHash(desc)
99
- debug "arg 1 is hReplacers, no desc"
100
- assert isEmpty(hReplacers), "invalid parms"
101
- hReplacers = desc
102
- desc = @lSectionTree
103
- else if notdefined(desc)
104
- debug "desc is entire tree"
105
- desc = @lSectionTree
106
-
107
- if isArray(desc)
108
- debug "item is an array"
109
- lBlocks = []
110
- setName = undef
111
- for item in desc
112
- subBlock = undef
113
- if isSetName(item)
114
- debug "set name is #{item}"
115
- setName = item
116
- else if isSectionName(item) || isArray(item)
117
- subBlock = @getBlock(item, hReplacers)
118
- if defined(subBlock)
119
- debug "add subBlock", subBlock
120
- lBlocks.push subBlock
121
- else
122
- debug "subBlock is undef"
123
- else if isString(item) && nonEmpty(item)
124
- debug "add string", item
125
- lBlocks.push item
126
- else
127
- croak "Bad item: #{OL(item)}"
128
80
 
129
- block = toBlock(lBlocks)
130
- debug "block is", block
131
- if defined(setName)
132
- if defined(proc = hReplacers[setName])
133
- block = proc(block)
134
- debug "REPLACE #{setName} with", block
135
- else
136
- debug "NO REPLACER for #{setName}"
137
- else if isSectionName(desc)
81
+ mkSet: (name, lTree) ->
82
+
83
+ assert isArray(lTree), "tree is not an array"
84
+ assert nonEmpty(lTree), "set without sections"
85
+ assert notdef(@hSets[name]), "set #{OL(name)} already exists"
86
+ @hSets[name] = lTree
87
+ return
88
+
89
+ # ..........................................................
90
+
91
+ mkSection: (name) ->
92
+
93
+ assert notdef(@hSections[name]), "duplicate section name"
94
+ @hSections[name] = new Section(name, @hReplacers[name])
95
+ return
96
+
97
+ # ..........................................................
98
+
99
+ getBlock: (desc='ALL') ->
100
+ # ..........................................................
101
+ # --- desc can be:
102
+ # a section name
103
+ # a set name
104
+ # an array of section or set names or literal strings
105
+ # i.e. it should NOT contain sub-arrays
106
+
107
+ if isString(desc)
108
+ debug "enter SectionMap.getBlock(#{OL(desc)})"
109
+ else if isArrayOfStrings(desc)
110
+ debug "enter SectionMap.getBlock()", desc
111
+ else
112
+ croak "Bad desc: #{OL(desc)}"
113
+
114
+ if isSectionName(desc)
138
115
  debug "item is a section name"
116
+ # --- a section's getBlock() applies any replacer
139
117
  block = @section(desc).getBlock()
140
- if defined(proc = hReplacers[desc])
141
- debug "REPLACE #{desc}"
142
- block = proc(block)
143
- else
144
- debug "NO REPLACER for #{desc}"
145
118
  else if isSetName(desc)
146
119
  debug "item is a set name"
147
- block = @getBlock(@hSets[desc], hReplacers)
120
+ lBlocks = for item in @hSets[desc]
121
+ if isArray(item)
122
+ @getBlock item[0]
123
+ else if isString(item)
124
+ @getBlock item
125
+ else
126
+ croak "Item in set #{desc} is not a string or array"
127
+ block = toBlock(lBlocks)
128
+ replacer = @hReplacers[desc]
129
+ debug "replacer for is #{OL(replacer)}"
130
+ if def(replacer)
131
+ block = replacer(block)
132
+ else if isString(desc)
133
+ debug "item is a literal string"
134
+ # --- a literal string
135
+ block = desc
136
+ else if isArray(desc)
137
+ debug "item is an array"
138
+ lBlocks = for item in desc
139
+ @getBlock(item)
140
+ block = toBlock(lBlocks)
148
141
  else
149
- croak "Bad 1st arg: #{OL(desc)}"
142
+ croak "Bad arg: #{OL(desc)}"
143
+
150
144
  debug "return from SectionMap.getBlock()", block
151
145
  return block
152
146
 
147
+ # ..........................................................
148
+ # --- does NOT call any replacers, and skips literal strings
149
+ # so only useful for isEmpty() and nonEmpty()
150
+
151
+ allSections: (desc=undef) ->
152
+
153
+ debug "enter allSections()", desc
154
+ if notdef(desc)
155
+ desc = @lFullTree
156
+
157
+ if isSectionName(desc)
158
+ debug "is section name"
159
+ yield @section(desc)
160
+ else if isSetName(desc)
161
+ debug "is set name"
162
+ for name in @hSets[desc]
163
+ yield from @allSections(name)
164
+ else if isArray(desc)
165
+ debug "is array"
166
+ for item in desc
167
+ yield from @allSections(item)
168
+ debug "return from allSections()"
169
+ return
170
+
153
171
  # ..........................................................
154
172
 
155
- isEmpty: () ->
173
+ isEmpty: (desc=undef) ->
156
174
 
157
- for name,sect of @hSections
175
+ for sect from @allSections(desc)
158
176
  if sect.nonEmpty()
159
177
  return false
160
178
  return true
161
179
 
162
180
  # ..........................................................
163
181
 
164
- nonEmpty: () ->
182
+ nonEmpty: (desc=undef) ->
165
183
 
166
- for name,sect of @hSections
184
+ for sect from @allSections(desc)
167
185
  if sect.nonEmpty()
168
186
  return true
169
187
  return false
@@ -173,7 +191,7 @@ export class SectionMap
173
191
  section: (name) ->
174
192
 
175
193
  sect = @hSections[name]
176
- assert defined(sect), "No section named #{OL(name)}"
194
+ assert def(sect), "No section named #{OL(name)}"
177
195
  return sect
178
196
 
179
197
  # ..........................................................
@@ -182,8 +200,8 @@ export class SectionMap
182
200
 
183
201
  assert isSetName(name), "bad set name #{OL(name)}"
184
202
  lSubTree = @hSets[name]
185
- assert defined(lSubTree), "no such set #{OL(name)}"
186
- return @section(lSubTree[1])
203
+ assert def(lSubTree), "no such set #{OL(name)}"
204
+ return @section(lSubTree[0])
187
205
 
188
206
  # ..........................................................
189
207
 
@@ -191,5 +209,37 @@ export class SectionMap
191
209
 
192
210
  assert isSetName(name), "bad set name #{OL(name)}"
193
211
  lSubTree = @hSets[name]
194
- assert defined(lSubTree), "no such set #{OL(name)}"
212
+ assert def(lSubTree), "no such set #{OL(name)}"
195
213
  return @section(lSubTree[lSubTree.length - 1])
214
+
215
+ # ..........................................................
216
+
217
+ checkTree: (tree) ->
218
+
219
+ debug "enter checkTree()"
220
+ if isString(tree)
221
+ debug "tree is a string"
222
+ assert isTAML(tree), "not TAML"
223
+ @lFullTree = fromTAML(tree)
224
+ else
225
+ @lFullTree = tree
226
+
227
+ assert isArray(@lFullTree), "not an array"
228
+ assert nonEmpty(@lFullTree), "tree is empty"
229
+ if isSetName(@lFullTree[0])
230
+ LOGTAML 'lFullTree', @lFullTree
231
+ croak "tree cannot begin with a set name"
232
+ debug "return from checkTree()"
233
+ return
234
+
235
+ # ..........................................................
236
+
237
+ checkReplacers: (h) ->
238
+
239
+ assert isHash(h), "replacers is not a hash"
240
+ for key,func of h
241
+ assert isSetName(key) || isSectionName(key), "bad replacer key"
242
+ assert isFunction(func),
243
+ "replacer for #{OL(key)} is not a function"
244
+ return
245
+
package/src/SectionMap.js CHANGED
@@ -4,22 +4,20 @@ var isSectionName, isSetName;
4
4
 
5
5
  import {
6
6
  assert,
7
- croak
7
+ croak,
8
+ LOG,
9
+ LOGVALUE,
10
+ LOGTAML,
11
+ debug,
12
+ isTAML,
13
+ fromTAML
8
14
  } from '@jdeighan/exceptions';
9
15
 
10
- import {
11
- LOG
12
- } from '@jdeighan/exceptions/log';
13
-
14
- import {
15
- debug
16
- } from '@jdeighan/exceptions/debug';
17
-
18
16
  import {
19
17
  pass,
20
18
  undef,
21
- defined,
22
- notdefined,
19
+ def,
20
+ notdef,
23
21
  OL,
24
22
  isEmpty,
25
23
  nonEmpty,
@@ -28,18 +26,16 @@ import {
28
26
  isArray,
29
27
  isUniqueTree,
30
28
  isNonEmptyString,
31
- isNonEmptyArray
29
+ isNonEmptyArray,
30
+ isFunction,
31
+ jsType,
32
+ isArrayOfStrings
32
33
  } from '@jdeighan/coffee-utils';
33
34
 
34
35
  import {
35
36
  toBlock
36
37
  } from '@jdeighan/coffee-utils/block';
37
38
 
38
- import {
39
- isTAML,
40
- fromTAML
41
- } from '@jdeighan/coffee-utils/taml';
42
-
43
39
  import {
44
40
  Section
45
41
  } from '@jdeighan/coffee-utils/section';
@@ -56,142 +52,170 @@ isSetName = function(name) {
56
52
 
57
53
  // ---------------------------------------------------------------------------
58
54
  export var SectionMap = class SectionMap {
59
- constructor(lSectionTree) {
60
- this.lSectionTree = lSectionTree;
61
- // --- lSectionTree is a tree of section/set names
62
- debug("enter SectionMap()", this.lSectionTree);
63
- if (isTAML(this.lSectionTree)) {
64
- this.SectionTree = fromTAML(this.lSectionTree);
65
- }
66
- assert(isArray(this.lSectionTree), "not an array");
67
- // --- keys are section names, values are Section objects
68
- this.hSections = {};
69
- // --- keys are set names, values are subtrees of lSectionTree
70
- this.hSets = {};
71
- this.build(this.lSectionTree);
72
- debug("return from SectionMap()", this.hSections);
55
+ constructor(tree, hReplacers = {}) {
56
+ this.hReplacers = hReplacers;
57
+ // --- tree is a tree of section/set names
58
+ // or a TAML string that converts to one
59
+ // --- hReplacers are callbacks that are called
60
+ // when a set or section is processed
61
+ // should be <name> -> <function>
62
+ // <name> can be a section name or a set name
63
+ // <function> should be <block> -> <block>
64
+ debug("enter SectionMap()", tree, this.hReplacers);
65
+ this.checkTree(tree);
66
+ this.checkReplacers(this.hReplacers);
67
+ this.hSections = {}; // --- {section name: Section Object}
68
+ this.hSets = {
69
+ ALL: this.lFullTree // --- {set name: array of parts}
70
+ };
71
+ this.init(this.lFullTree);
72
+ debug('hSections', this.hSections);
73
+ debug('hSets', this.hSets);
74
+ debug("return from SectionMap()");
73
75
  }
74
76
 
75
77
  // ..........................................................
76
- build(lTree) {
77
- var firstItem, i, item, j, len, len1, ref;
78
- debug("enter build()", lTree);
78
+ init(lTree) {
79
+ var firstItem, i, item, len;
80
+ debug("enter init()", lTree);
79
81
  assert(isArray(lTree), "not an array");
80
82
  assert(nonEmpty(lTree), "empty array");
81
83
  firstItem = lTree[0];
82
84
  if (isSetName(firstItem)) {
83
- assert(lTree.length >= 2, "set without sections");
84
- this.hSets[firstItem] = lTree;
85
- ref = lTree.slice(1);
86
- for (i = 0, len = ref.length; i < len; i++) {
87
- item = ref[i];
88
- if (isArray(item)) {
89
- this.build(item);
90
- } else if (isSectionName(item)) {
91
- this.hSections[item] = new Section(item);
92
- } else if (!isString(item)) { // string would be literal
93
- croak(`Bad section tree: ${OL(this.lSectionTree)}`);
94
- }
95
- }
96
- } else {
97
- for (j = 0, len1 = lTree.length; j < len1; j++) {
98
- item = lTree[j];
99
- if (isArray(item)) {
100
- this.build(item);
101
- } else if (isSectionName(item)) {
102
- this.hSections[item] = new Section(item);
103
- } else {
104
- croak(`Bad section tree: ${OL(this.lSectionTree)}`);
105
- }
85
+ debug(`found set name ${OL(firstItem)}`);
86
+ lTree = lTree.slice(1);
87
+ this.mkSet(firstItem, lTree);
88
+ }
89
+ for (i = 0, len = lTree.length; i < len; i++) {
90
+ item = lTree[i];
91
+ if (isArray(item)) {
92
+ debug("init subtree");
93
+ this.init(item);
94
+ } else if (isSectionName(item)) {
95
+ debug(`mkSection ${OL(item)}`);
96
+ this.mkSection(item);
97
+ } else {
98
+ assert(isString(item), `Bad item in tree: ${OL(item)}`);
106
99
  }
107
100
  }
108
- debug("return from build()", this.hSections, this.hSets);
101
+ debug("return from init()");
102
+ }
103
+
104
+ // ..........................................................
105
+ mkSet(name, lTree) {
106
+ assert(isArray(lTree), "tree is not an array");
107
+ assert(nonEmpty(lTree), "set without sections");
108
+ assert(notdef(this.hSets[name]), `set ${OL(name)} already exists`);
109
+ this.hSets[name] = lTree;
109
110
  }
110
111
 
111
112
  // ..........................................................
112
- // --- hProc should be <name> -> <function>
113
- // <name> can be a section name or a set name
114
- // <function> should be <block> -> <block>
115
- // --- desc can be:
116
- // an array, which may begin with a set name
117
- // a section name
118
- // a set name
119
- // undef (equivalent to being set to @SectionTree)
120
- getBlock(desc = undef, hReplacers = {}) {
121
- var block, i, item, lBlocks, len, proc, setName, subBlock;
122
- debug("enter SectionMap.getBlock()", desc, hReplacers);
123
- // --- desc can only be a string or an array
124
- // so, if it's a hash, then it's really the hReplacers
125
- // and the real desc is undef
126
- if (isHash(desc)) {
127
- debug("arg 1 is hReplacers, no desc");
128
- assert(isEmpty(hReplacers), "invalid parms");
129
- hReplacers = desc;
130
- desc = this.lSectionTree;
131
- } else if (notdefined(desc)) {
132
- debug("desc is entire tree");
133
- desc = this.lSectionTree;
113
+ mkSection(name) {
114
+ assert(notdef(this.hSections[name]), "duplicate section name");
115
+ this.hSections[name] = new Section(name, this.hReplacers[name]);
116
+ }
117
+
118
+ // ..........................................................
119
+ getBlock(desc = 'ALL') {
120
+ var block, item, lBlocks, replacer;
121
+ // ..........................................................
122
+ // --- desc can be:
123
+ // a section name
124
+ // a set name
125
+ // an array of section or set names or literal strings
126
+ // i.e. it should NOT contain sub-arrays
127
+ if (isString(desc)) {
128
+ debug(`enter SectionMap.getBlock(${OL(desc)})`);
129
+ } else if (isArrayOfStrings(desc)) {
130
+ debug("enter SectionMap.getBlock()", desc);
131
+ } else {
132
+ croak(`Bad desc: ${OL(desc)}`);
134
133
  }
135
- if (isArray(desc)) {
136
- debug("item is an array");
137
- lBlocks = [];
138
- setName = undef;
139
- for (i = 0, len = desc.length; i < len; i++) {
140
- item = desc[i];
141
- subBlock = undef;
142
- if (isSetName(item)) {
143
- debug(`set name is ${item}`);
144
- setName = item;
145
- } else if (isSectionName(item) || isArray(item)) {
146
- subBlock = this.getBlock(item, hReplacers);
147
- if (defined(subBlock)) {
148
- debug("add subBlock", subBlock);
149
- lBlocks.push(subBlock);
134
+ if (isSectionName(desc)) {
135
+ debug("item is a section name");
136
+ // --- a section's getBlock() applies any replacer
137
+ block = this.section(desc).getBlock();
138
+ } else if (isSetName(desc)) {
139
+ debug("item is a set name");
140
+ lBlocks = (function() {
141
+ var i, len, ref, results;
142
+ ref = this.hSets[desc];
143
+ results = [];
144
+ for (i = 0, len = ref.length; i < len; i++) {
145
+ item = ref[i];
146
+ if (isArray(item)) {
147
+ results.push(this.getBlock(item[0]));
148
+ } else if (isString(item)) {
149
+ results.push(this.getBlock(item));
150
150
  } else {
151
- debug("subBlock is undef");
151
+ results.push(croak(`Item in set ${desc} is not a string or array`));
152
152
  }
153
- } else if (isString(item) && nonEmpty(item)) {
154
- debug("add string", item);
155
- lBlocks.push(item);
156
- } else {
157
- croak(`Bad item: ${OL(item)}`);
158
153
  }
159
- }
154
+ return results;
155
+ }).call(this);
160
156
  block = toBlock(lBlocks);
161
- debug("block is", block);
162
- if (defined(setName)) {
163
- if (defined(proc = hReplacers[setName])) {
164
- block = proc(block);
165
- debug(`REPLACE ${setName} with`, block);
166
- } else {
167
- debug(`NO REPLACER for ${setName}`);
168
- }
169
- }
170
- } else if (isSectionName(desc)) {
171
- debug("item is a section name");
172
- block = this.section(desc).getBlock();
173
- if (defined(proc = hReplacers[desc])) {
174
- debug(`REPLACE ${desc}`);
175
- block = proc(block);
176
- } else {
177
- debug(`NO REPLACER for ${desc}`);
157
+ replacer = this.hReplacers[desc];
158
+ debug(`replacer for is ${OL(replacer)}`);
159
+ if (def(replacer)) {
160
+ block = replacer(block);
178
161
  }
179
- } else if (isSetName(desc)) {
180
- debug("item is a set name");
181
- block = this.getBlock(this.hSets[desc], hReplacers);
162
+ } else if (isString(desc)) {
163
+ debug("item is a literal string");
164
+ // --- a literal string
165
+ block = desc;
166
+ } else if (isArray(desc)) {
167
+ debug("item is an array");
168
+ lBlocks = (function() {
169
+ var i, len, results;
170
+ results = [];
171
+ for (i = 0, len = desc.length; i < len; i++) {
172
+ item = desc[i];
173
+ results.push(this.getBlock(item));
174
+ }
175
+ return results;
176
+ }).call(this);
177
+ block = toBlock(lBlocks);
182
178
  } else {
183
- croak(`Bad 1st arg: ${OL(desc)}`);
179
+ croak(`Bad arg: ${OL(desc)}`);
184
180
  }
185
181
  debug("return from SectionMap.getBlock()", block);
186
182
  return block;
187
183
  }
188
184
 
189
185
  // ..........................................................
190
- isEmpty() {
191
- var name, ref, sect;
192
- ref = this.hSections;
193
- for (name in ref) {
194
- sect = ref[name];
186
+ // --- does NOT call any replacers, and skips literal strings
187
+ // so only useful for isEmpty() and nonEmpty()
188
+ * allSections(desc = undef) {
189
+ var i, item, j, len, len1, name, ref;
190
+ debug("enter allSections()", desc);
191
+ if (notdef(desc)) {
192
+ desc = this.lFullTree;
193
+ }
194
+ if (isSectionName(desc)) {
195
+ debug("is section name");
196
+ yield this.section(desc);
197
+ } else if (isSetName(desc)) {
198
+ debug("is set name");
199
+ ref = this.hSets[desc];
200
+ for (i = 0, len = ref.length; i < len; i++) {
201
+ name = ref[i];
202
+ yield* this.allSections(name);
203
+ }
204
+ } else if (isArray(desc)) {
205
+ debug("is array");
206
+ for (j = 0, len1 = desc.length; j < len1; j++) {
207
+ item = desc[j];
208
+ yield* this.allSections(item);
209
+ }
210
+ }
211
+ debug("return from allSections()");
212
+ }
213
+
214
+ // ..........................................................
215
+ isEmpty(desc = undef) {
216
+ var ref, sect;
217
+ ref = this.allSections(desc);
218
+ for (sect of ref) {
195
219
  if (sect.nonEmpty()) {
196
220
  return false;
197
221
  }
@@ -200,11 +224,10 @@ export var SectionMap = class SectionMap {
200
224
  }
201
225
 
202
226
  // ..........................................................
203
- nonEmpty() {
204
- var name, ref, sect;
205
- ref = this.hSections;
206
- for (name in ref) {
207
- sect = ref[name];
227
+ nonEmpty(desc = undef) {
228
+ var ref, sect;
229
+ ref = this.allSections(desc);
230
+ for (sect of ref) {
208
231
  if (sect.nonEmpty()) {
209
232
  return true;
210
233
  }
@@ -216,7 +239,7 @@ export var SectionMap = class SectionMap {
216
239
  section(name) {
217
240
  var sect;
218
241
  sect = this.hSections[name];
219
- assert(defined(sect), `No section named ${OL(name)}`);
242
+ assert(def(sect), `No section named ${OL(name)}`);
220
243
  return sect;
221
244
  }
222
245
 
@@ -225,8 +248,8 @@ export var SectionMap = class SectionMap {
225
248
  var lSubTree;
226
249
  assert(isSetName(name), `bad set name ${OL(name)}`);
227
250
  lSubTree = this.hSets[name];
228
- assert(defined(lSubTree), `no such set ${OL(name)}`);
229
- return this.section(lSubTree[1]);
251
+ assert(def(lSubTree), `no such set ${OL(name)}`);
252
+ return this.section(lSubTree[0]);
230
253
  }
231
254
 
232
255
  // ..........................................................
@@ -234,8 +257,38 @@ export var SectionMap = class SectionMap {
234
257
  var lSubTree;
235
258
  assert(isSetName(name), `bad set name ${OL(name)}`);
236
259
  lSubTree = this.hSets[name];
237
- assert(defined(lSubTree), `no such set ${OL(name)}`);
260
+ assert(def(lSubTree), `no such set ${OL(name)}`);
238
261
  return this.section(lSubTree[lSubTree.length - 1]);
239
262
  }
240
263
 
264
+ // ..........................................................
265
+ checkTree(tree) {
266
+ debug("enter checkTree()");
267
+ if (isString(tree)) {
268
+ debug("tree is a string");
269
+ assert(isTAML(tree), "not TAML");
270
+ this.lFullTree = fromTAML(tree);
271
+ } else {
272
+ this.lFullTree = tree;
273
+ }
274
+ assert(isArray(this.lFullTree), "not an array");
275
+ assert(nonEmpty(this.lFullTree), "tree is empty");
276
+ if (isSetName(this.lFullTree[0])) {
277
+ LOGTAML('lFullTree', this.lFullTree);
278
+ croak("tree cannot begin with a set name");
279
+ }
280
+ debug("return from checkTree()");
281
+ }
282
+
283
+ // ..........................................................
284
+ checkReplacers(h) {
285
+ var func, key;
286
+ assert(isHash(h), "replacers is not a hash");
287
+ for (key in h) {
288
+ func = h[key];
289
+ assert(isSetName(key) || isSectionName(key), "bad replacer key");
290
+ assert(isFunction(func), `replacer for ${OL(key)} is not a function`);
291
+ }
292
+ }
293
+
241
294
  };
package/src/block.coffee CHANGED
@@ -63,7 +63,8 @@ export toBlock = (lLines) ->
63
63
 
64
64
  if notdefined(lLines)
65
65
  return undef
66
- assert isArrayOfStrings(lLines), "lLines is not an array: #{OL(lLines)}"
66
+ assert isArrayOfStrings(lLines),
67
+ "lLines is not an array of strings: #{OL(lLines)}"
67
68
  lNewLines = []
68
69
  for line in lLines
69
70
  if defined(line)
package/src/block.js CHANGED
@@ -90,7 +90,7 @@ export var toBlock = function(lLines) {
90
90
  if (notdefined(lLines)) {
91
91
  return undef;
92
92
  }
93
- assert(isArrayOfStrings(lLines), `lLines is not an array: ${OL(lLines)}`);
93
+ assert(isArrayOfStrings(lLines), `lLines is not an array of strings: ${OL(lLines)}`);
94
94
  lNewLines = [];
95
95
  for (i = 0, len = lLines.length; i < len; i++) {
96
96
  line = lLines[i];
package/src/fs.coffee CHANGED
@@ -5,7 +5,7 @@ import urllib from 'url'
5
5
  import fs from 'fs'
6
6
  import NReadLines from 'n-readlines'
7
7
 
8
- import {assert, croak, LOG, fromTAML} from '@jdeighan/exceptions'
8
+ import {assert, croak, debug, LOG, fromTAML} from '@jdeighan/exceptions'
9
9
  import {
10
10
  undef, pass, defined, rtrim, isEmpty, nonEmpty, getOptions,
11
11
  isString, isArray, isHash, isRegExp, isFunction, OL,
@@ -377,6 +377,7 @@ export parseSource = (source) ->
377
377
  # }
378
378
  # --- NOTE: source may be a file URL, e.g. import.meta.url
379
379
 
380
+ debug "enter parseSource(#{OL(source)})"
380
381
  assert isString(source),\
381
382
  "parseSource(): source not a string: #{OL(source)}"
382
383
  if source == 'unit test'
@@ -413,6 +414,7 @@ export parseSource = (source) ->
413
414
  ([A-Za-z_]+)
414
415
  $///)
415
416
  hSourceInfo.purpose = lMatches[1]
417
+ debug "return from parseSource()", hSourceInfo
416
418
  return hSourceInfo
417
419
 
418
420
  # ---------------------------------------------------------------------------
package/src/fs.js CHANGED
@@ -13,6 +13,7 @@ import NReadLines from 'n-readlines';
13
13
  import {
14
14
  assert,
15
15
  croak,
16
+ debug,
16
17
  LOG,
17
18
  fromTAML
18
19
  } from '@jdeighan/exceptions';
@@ -446,6 +447,7 @@ export var parseSource = function(source) {
446
447
  // purpose
447
448
  // }
448
449
  // --- NOTE: source may be a file URL, e.g. import.meta.url
450
+ debug(`enter parseSource(${OL(source)})`);
449
451
  assert(isString(source), `parseSource(): source not a string: ${OL(source)}`);
450
452
  if (source === 'unit test') {
451
453
  croak("A source of 'unit test' is deprecated");
@@ -481,6 +483,7 @@ export var parseSource = function(source) {
481
483
  hSourceInfo.purpose = lMatches[1];
482
484
  }
483
485
  }
486
+ debug("return from parseSource()", hSourceInfo);
484
487
  return hSourceInfo;
485
488
  };
486
489
 
package/src/utils.coffee CHANGED
@@ -11,8 +11,11 @@ import {
11
11
  isEmpty, nonEmpty, chomp, rtrim, setCharsAt, words, getOptions,
12
12
  } from '@jdeighan/exceptions/utils'
13
13
 
14
+ def = defined
15
+ notdef = notdefined
16
+
14
17
  export {
15
- undef, pass, defined, notdefined, LOG, sep_dash, sep_eq,
18
+ undef, pass, def, defined, notdef, notdefined, LOG, sep_dash, sep_eq,
16
19
  deepCopy, escapeStr, unescapeStr, hasChar, quoted, OL,
17
20
  isString, isNumber, isInteger, isHash, isArray, isBoolean,
18
21
  isConstructor, isFunction, isRegExp, isObject, getClassName,
@@ -137,22 +140,24 @@ export pushCond = (lItems, item, doPush=notInArray) ->
137
140
  # ---------------------------------------------------------------------------
138
141
 
139
142
  export isArrayOfHashes = (lItems) ->
143
+ # --- undefined items are allowed
140
144
 
141
145
  if ! isArray(lItems)
142
146
  return false
143
147
  for item in lItems
144
- if ! isHash(item)
148
+ if defined(item) && ! isHash(item)
145
149
  return false
146
150
  return true
147
151
 
148
152
  # ---------------------------------------------------------------------------
149
153
 
150
154
  export isArrayOfStrings = (lItems) ->
155
+ # --- undefined items are allowed
151
156
 
152
157
  if ! isArray(lItems)
153
158
  return false
154
159
  for item in lItems
155
- if ! isString(item)
160
+ if defined(item) && ! isString(item)
156
161
  return false
157
162
  return true
158
163
 
package/src/utils.js CHANGED
@@ -1,6 +1,7 @@
1
1
  // Generated by CoffeeScript 2.7.0
2
- // utils.coffee
3
- var hasProp = {}.hasOwnProperty;
2
+ // utils.coffee
3
+ var def, notdef,
4
+ hasProp = {}.hasOwnProperty;
4
5
 
5
6
  import {
6
7
  assert,
@@ -45,10 +46,16 @@ import {
45
46
  getOptions
46
47
  } from '@jdeighan/exceptions/utils';
47
48
 
49
+ def = defined;
50
+
51
+ notdef = notdefined;
52
+
48
53
  export {
49
54
  undef,
50
55
  pass,
56
+ def,
51
57
  defined,
58
+ notdef,
52
59
  notdefined,
53
60
  LOG,
54
61
  sep_dash,
@@ -202,7 +209,7 @@ export var isArrayOfHashes = function(lItems) {
202
209
  }
203
210
  for (i = 0, len = lItems.length; i < len; i++) {
204
211
  item = lItems[i];
205
- if (!isHash(item)) {
212
+ if (defined(item) && !isHash(item)) {
206
213
  return false;
207
214
  }
208
215
  }
@@ -217,7 +224,7 @@ export var isArrayOfStrings = function(lItems) {
217
224
  }
218
225
  for (i = 0, len = lItems.length; i < len; i++) {
219
226
  item = lItems[i];
220
- if (!isString(item)) {
227
+ if (defined(item) && !isString(item)) {
221
228
  return false;
222
229
  }
223
230
  }
@@ -1,26 +0,0 @@
1
- # placeholders.coffee
2
-
3
- import {assert, croak} from '@jdeighan/exceptions'
4
- import {undef, defined} from '@jdeighan/coffee-utils'
5
-
6
- hDefOptions = {
7
- pre: '__'
8
- post: '__'
9
- }
10
-
11
- # ---------------------------------------------------------------------------
12
-
13
- export phStr = (name, hOptions=hDefOptions) ->
14
-
15
- {pre, post} = hOptions
16
- return "#{pre}#{name}#{post}"
17
-
18
- # ---------------------------------------------------------------------------
19
-
20
- export phReplace = (str, hValues, hOptions=hDefOptions) ->
21
-
22
- {pre, post} = hOptions
23
- return str.replace(
24
- /// #{pre} ([A-Za-z_][A-Za-z0-9_]*) #{post} ///g,
25
- (_, name) -> hValues[name]
26
- )
@@ -1,34 +0,0 @@
1
- // Generated by CoffeeScript 2.7.0
2
- // placeholders.coffee
3
- var hDefOptions;
4
-
5
- import {
6
- assert,
7
- croak
8
- } from '@jdeighan/exceptions';
9
-
10
- import {
11
- undef,
12
- defined
13
- } from '@jdeighan/coffee-utils';
14
-
15
- hDefOptions = {
16
- pre: '__',
17
- post: '__'
18
- };
19
-
20
- // ---------------------------------------------------------------------------
21
- export var phStr = function(name, hOptions = hDefOptions) {
22
- var post, pre;
23
- ({pre, post} = hOptions);
24
- return `${pre}${name}${post}`;
25
- };
26
-
27
- // ---------------------------------------------------------------------------
28
- export var phReplace = function(str, hValues, hOptions = hDefOptions) {
29
- var post, pre;
30
- ({pre, post} = hOptions);
31
- return str.replace(RegExp(`${pre}([A-Za-z_][A-Za-z0-9_]*)${post}`, "g"), function(_, name) {
32
- return hValues[name];
33
- });
34
- };