@jdeighan/coffee-utils 11.0.31 → 11.0.33

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": "11.0.31",
4
+ "version": "11.0.33",
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/utils.coffee CHANGED
@@ -3,7 +3,7 @@
3
3
  import {assert, croak} from '@jdeighan/exceptions'
4
4
  import {LOG, sep_dash, sep_eq} from '@jdeighan/exceptions/log'
5
5
  import {
6
- undef, pass, defined, notdefined,
6
+ undef, pass, def, defined, notdef, notdefined,
7
7
  deepCopy, escapeStr, unescapeStr, hasChar, quoted, OL,
8
8
  isString, isNumber, isInteger, isHash, isArray, isBoolean,
9
9
  isConstructor, isFunction, isRegExp, isObject, getClassName,
@@ -12,7 +12,7 @@ import {
12
12
  } from '@jdeighan/exceptions/utils'
13
13
 
14
14
  export {
15
- undef, pass, defined, notdefined, LOG, sep_dash, sep_eq,
15
+ undef, pass, def, defined, notdef, notdefined, LOG, sep_dash, sep_eq,
16
16
  deepCopy, escapeStr, unescapeStr, hasChar, quoted, OL,
17
17
  isString, isNumber, isInteger, isHash, isArray, isBoolean,
18
18
  isConstructor, isFunction, isRegExp, isObject, getClassName,
@@ -137,22 +137,24 @@ export pushCond = (lItems, item, doPush=notInArray) ->
137
137
  # ---------------------------------------------------------------------------
138
138
 
139
139
  export isArrayOfHashes = (lItems) ->
140
+ # --- undefined items are allowed
140
141
 
141
142
  if ! isArray(lItems)
142
143
  return false
143
144
  for item in lItems
144
- if ! isHash(item)
145
+ if defined(item) && ! isHash(item)
145
146
  return false
146
147
  return true
147
148
 
148
149
  # ---------------------------------------------------------------------------
149
150
 
150
151
  export isArrayOfStrings = (lItems) ->
152
+ # --- undefined items are allowed
151
153
 
152
154
  if ! isArray(lItems)
153
155
  return false
154
156
  for item in lItems
155
- if ! isString(item)
157
+ if defined(item) && ! isString(item)
156
158
  return false
157
159
  return true
158
160
 
package/src/utils.js CHANGED
@@ -16,7 +16,9 @@ import {
16
16
  import {
17
17
  undef,
18
18
  pass,
19
+ def,
19
20
  defined,
21
+ notdef,
20
22
  notdefined,
21
23
  deepCopy,
22
24
  escapeStr,
@@ -48,7 +50,9 @@ import {
48
50
  export {
49
51
  undef,
50
52
  pass,
53
+ def,
51
54
  defined,
55
+ notdef,
52
56
  notdefined,
53
57
  LOG,
54
58
  sep_dash,
@@ -202,7 +206,7 @@ export var isArrayOfHashes = function(lItems) {
202
206
  }
203
207
  for (i = 0, len = lItems.length; i < len; i++) {
204
208
  item = lItems[i];
205
- if (!isHash(item)) {
209
+ if (defined(item) && !isHash(item)) {
206
210
  return false;
207
211
  }
208
212
  }
@@ -217,7 +221,7 @@ export var isArrayOfStrings = function(lItems) {
217
221
  }
218
222
  for (i = 0, len = lItems.length; i < len; i++) {
219
223
  item = lItems[i];
220
- if (!isString(item)) {
224
+ if (defined(item) && !isString(item)) {
221
225
  return false;
222
226
  }
223
227
  }
@@ -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
- };