@jdeighan/coffee-utils 7.0.50 → 7.0.53

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.
@@ -2,7 +2,7 @@
2
2
 
3
3
  import {
4
4
  assert, undef, error, croak, warn, defined,
5
- isString, isFunction, isBoolean,
5
+ isString, isFunction, isBoolean, sep_dash,
6
6
  OL, escapeStr, isNumber, isArray, words, pass,
7
7
  } from '@jdeighan/coffee-utils'
8
8
  import {blockToArray} from '@jdeighan/coffee-utils/block'
@@ -10,17 +10,134 @@ import {untabify} from '@jdeighan/coffee-utils/indent'
10
10
  import {slurp} from '@jdeighan/coffee-utils/fs'
11
11
  import {CallStack} from '@jdeighan/coffee-utils/stack'
12
12
  import {
13
- log, logItem, LOG, setStringifier, orderedStringify,
13
+ getPrefix, addArrow, removeLastVbar,
14
+ } from '@jdeighan/coffee-utils/arrow'
15
+ import {
16
+ log, logItem, LOG, shortEnough,
14
17
  } from '@jdeighan/coffee-utils/log'
15
18
 
16
- # --- These are saved/restored on the call stack
17
- export debugging = false
18
- shouldLogFunc = (func) -> return debugging
19
- shouldLogString = (str) -> return debugging
20
-
21
- stack = new CallStack()
19
+ callStack = new CallStack()
22
20
  doDebugDebug = false
23
21
 
22
+ export shouldLog = undef # set in resetDebugging() and setDebugging()
23
+ export lFuncList = []
24
+
25
+ # ---------------------------------------------------------------------------
26
+
27
+ export debug = (label, lObjects...) ->
28
+
29
+ assert isString(label), "1st arg #{OL(label)} should be a string"
30
+
31
+ # --- We want to allow objects to be undef. Therefore, we need to
32
+ # distinguish between 1 arg sent vs. 2 or more args sent
33
+ nObjects = lObjects.length
34
+
35
+ # --- funcName is only set for types 'enter' and 'return'
36
+ [type, funcName] = getType(label, nObjects)
37
+ if doDebugDebug
38
+ LOG "debug(): type = #{OL(type)}"
39
+ LOG "debug(): funcName = #{OL(funcName)}"
40
+
41
+ switch type
42
+ when 'enter'
43
+ callStack.enter funcName
44
+ label = shouldLog(label, type, funcName, callStack)
45
+ when 'return'
46
+ label = shouldLog(label, type, funcName, callStack)
47
+ when 'string'
48
+ label = shouldLog(label, type, undef, callStack)
49
+ assert (nObjects == 0),
50
+ "multiple objects only not allowed for #{OL(type)}"
51
+ when 'objects'
52
+ label = shouldLog(label, type, undef, callStack)
53
+ assert (nObjects > 0),
54
+ "multiple objects only not allowed for #{OL(type)}"
55
+ doLog = defined(label)
56
+
57
+ if doDebugDebug
58
+ if nObjects == 0
59
+ LOG "debug(#{OL(label)}) - 1 arg"
60
+ else
61
+ LOG "debug(#{OL(label)}), #{nObjects} args"
62
+ LOG "doLog = #{OL(doLog)}"
63
+
64
+ if doLog
65
+ level = callStack.getLevel()
66
+ prefix = getPrefix(level)
67
+
68
+ if doDebugDebug
69
+ LOG "callStack", callStack
70
+ LOG "level = #{OL(level)}"
71
+ LOG "prefix = #{OL(prefix)}"
72
+
73
+ switch type
74
+ when 'enter'
75
+ log label, {prefix}
76
+ for obj,i in lObjects
77
+ if (i > 0)
78
+ log sep_dash, {prefix: removeLastVbar(prefix)}
79
+ logItem undef, obj, {prefix: removeLastVbar(prefix)}
80
+ when 'return'
81
+ log label, {prefix: addArrow(prefix)}
82
+ for obj,i in lObjects
83
+ if (i > 0)
84
+ log sep_dash, {prefix: removeLastVbar(prefix)}
85
+ logItem undef, obj, {prefix: removeLastVbar(prefix)}
86
+ when 'string'
87
+ log label, {prefix}
88
+ when 'objects'
89
+ if (nObjects==1) && shortEnough(label, lObjects[0])
90
+ logItem label, lObjects[0], {prefix}
91
+ else
92
+ if (label.indexOf(':') != label.length - 1)
93
+ label += ':'
94
+ log label, {prefix}
95
+ for obj in lObjects
96
+ logItem undef, obj, {prefix}
97
+
98
+ if (type == 'enter') && doLog
99
+ callStack.logCurFunc()
100
+ else if (type == 'return')
101
+ callStack.returnFrom funcName
102
+
103
+ return true # allow use in boolean expressions
104
+
105
+ # ---------------------------------------------------------------------------
106
+
107
+ export stdShouldLog = (label, type, funcName, stack) ->
108
+ # --- if type is 'enter', then funcName won't be on the stack yet
109
+ # returns the (possibly modified) label to log
110
+
111
+ # --- If we're logging now,
112
+ # but we won't be logging when funcName is activated
113
+ # then change 'enter' to 'call'
114
+
115
+ assert isString(label), "label #{OL(label)} not a string"
116
+ assert isString(type), "type #{OL(type)} not a string"
117
+ if (type == 'enter') || (type == 'return')
118
+ assert isString(funcName), "func name #{OL(funcName)} not a string"
119
+ else
120
+ assert funcName == undef, "func name #{OL(funcName)} not undef"
121
+ assert stack instanceof CallStack, "not a call stack object"
122
+ if doDebugDebug
123
+ LOG "stdShouldLog(#{OL(label)}, #{OL(type)}, #{OL(funcName)}, stack)"
124
+ LOG "stack", stack
125
+ LOG "lFuncList", lFuncList
126
+ switch type
127
+ when 'enter'
128
+ if funcMatch(stack, lFuncList)
129
+ return label
130
+
131
+ # --- As a special case, if we enter a function where we will not
132
+ # be logging, but we were logging in the calling function,
133
+ # we'll log out the call itself
134
+ else if stack.isLoggingPrev()
135
+ return label.replace('enter', 'call')
136
+ else
137
+ if funcMatch(stack, lFuncList)
138
+ return label
139
+ return undef
140
+
24
141
  # ---------------------------------------------------------------------------
25
142
 
26
143
  export debugDebug = (flag=true) ->
@@ -34,183 +151,124 @@ export debugDebug = (flag=true) ->
34
151
 
35
152
  resetDebugging = () ->
36
153
 
37
- debugging = false
38
154
  if doDebugDebug
39
- LOG "resetDebugging() - debugging = false"
40
- stack.reset()
41
- shouldLogFunc = (func) -> return debugging
42
- shouldLogString = (str) -> return debugging
155
+ LOG "resetDebugging()"
156
+ callStack.reset()
157
+ shouldLog = (label, type, funcName, stack) -> undef
43
158
  return
44
159
 
45
160
  # ---------------------------------------------------------------------------
46
161
 
47
- export setDebugging = (funcDoDebug=undef, funcDoLog=undef) ->
162
+ export setDebugging = (option) ->
48
163
 
49
164
  resetDebugging()
50
- if isBoolean(funcDoDebug)
51
- debugging = funcDoDebug
165
+ if isBoolean(option)
166
+ if option
167
+ shouldLog = (label, type, funcName, stack) -> label
168
+ else
169
+ shouldLog = (label, type, funcName, stack) -> undef
52
170
  if doDebugDebug
53
- LOG "setDebugging(): debugging = #{funcDoDebug}"
54
- else if isString(funcDoDebug)
55
- debugging = false
56
- lFuncNames = words(funcDoDebug)
57
- assert isArray(lFuncNames), "words('#{funcDoDebug}') returned non-array"
58
- shouldLogFunc = (funcName) ->
59
- funcMatch(funcName, lFuncNames)
171
+ LOG "setDebugging = #{option}"
172
+ else if isString(option)
173
+ lFuncList = getFuncList(option)
174
+ shouldLog = stdShouldLog
60
175
  if doDebugDebug
61
- LOG "setDebugging FUNCS: #{lFuncNames.join(',')}, debugging = false"
62
- else if isFunction(funcDoDebug)
63
- shouldLogFunc = funcDoDebug
176
+ LOG "setDebugging FUNCS: #{option}"
177
+ LOG 'lFuncList', lFuncList
178
+ else if isFunction(option)
179
+ shouldLog = option
64
180
  if doDebugDebug
65
181
  LOG "setDebugging to custom func"
66
182
  else
67
- croak "setDebugging(): bad parameter #{OL(funcDoDebug)}"
68
-
69
- if isFunction(funcDoLog)
70
- assert isFunction(funcDoLog), "setDebugging: arg 2 not a function"
71
- shouldLogString = funcDoLog
183
+ croak "bad parameter #{OL(option)}"
72
184
  return
73
185
 
74
186
  # ---------------------------------------------------------------------------
75
187
  # --- export only to allow unit tests
76
188
 
77
- export funcMatch = (curFunc, lFuncNames) ->
189
+ export getFuncList = (str) ->
190
+
191
+ lFuncList = []
192
+ for word in words(str)
193
+ if lMatches = word.match(///^
194
+ ([A-Za-z_][A-Za-z0-9_]*)
195
+ (?:
196
+ \.
197
+ ([A-Za-z_][A-Za-z0-9_]*)
198
+ )?
199
+ (\+)?
200
+ $///)
201
+ [_, ident1, ident2, plus] = lMatches
202
+ if ident2
203
+ lFuncList.push {
204
+ name: ident2
205
+ object: ident1
206
+ plus: (plus == '+')
207
+ }
208
+ else
209
+ lFuncList.push {
210
+ name: ident1
211
+ plus: (plus == '+')
212
+ }
213
+ else
214
+ croak "Bad word in func list: #{OL(word)}"
215
+ return lFuncList
78
216
 
79
- assert isString(curFunc), "funcMatch(): not a string"
80
- assert isArray(lFuncNames), "funcMatch(): bad array #{lFuncNames}"
81
- if lFuncNames.includes(curFunc)
82
- return true
83
- else if (lMatches = curFunc.match(reMethod)) \
84
- && ([_, cls, meth] = lMatches) \
85
- && lFuncNames.includes(meth)
86
- return true
87
- else
88
- return false
217
+ # ---------------------------------------------------------------------------
218
+ # --- export only to allow unit tests
219
+
220
+ export funcMatch = (stack, lFuncList) ->
221
+
222
+ assert isArray(lFuncList), "not an array #{OL(lFuncList)}"
223
+
224
+ curFunc = stack.curFunc()
225
+ if doDebugDebug
226
+ LOG "funcMatch(): curFunc = #{OL(curFunc)}"
227
+ stack.dump(' ')
228
+ LOG 'lFuncList', lFuncList
229
+ for h in lFuncList
230
+ {name, object, plus} = h
231
+ if (name == curFunc)
232
+ if doDebugDebug
233
+ LOG " curFunc in lFuncList - match successful"
234
+ return true
235
+ if plus && stack.isActive(name)
236
+ if doDebugDebug
237
+ LOG " func #{OL(name)} is active - match successful"
238
+ return true
239
+ if doDebugDebug
240
+ LOG " - no match"
241
+ return false
89
242
 
90
243
  # ---------------------------------------------------------------------------
91
- # 1. adjust call stack on 'enter' or 'return from'
92
- # 2. adjust debugging flag
93
- # 3. return [mainPrefix, auxPrefix, hEnv, type] - hEnv can be undef
94
- # 4. disable logging by setting type to undef
244
+ # --- type is one of: 'enter', 'return', 'string', 'object'
95
245
 
96
- adjustStack = (str) ->
246
+ export getType = (str, nObjects) ->
97
247
 
98
- if (lMatches = str.match(///^
248
+ if lMatches = str.match(///^
99
249
  \s*
100
250
  enter
101
251
  \s+
102
252
  ([A-Za-z_][A-Za-z0-9_\.]*)
103
- ///))
253
+ ///)
104
254
 
105
255
  # --- We are entering function curFunc
106
- curFunc = lMatches[1]
107
-
108
- hEnv = {
109
- debugging
110
- shouldLogFunc
111
- shouldLogString
112
- }
256
+ return ['enter', lMatches[1]]
113
257
 
114
- debugging = shouldLogFunc(curFunc)
115
- if doDebugDebug
116
- trans = "#{hEnv.debugging} => #{debugging}"
117
- LOG " ENTER #{curFunc}, debugging: #{trans}"
118
- [mainPre, auxPre] = stack.doCall(curFunc, hEnv, debugging)
119
- return [
120
- mainPre
121
- auxPre
122
- undef
123
- if shouldLogFunc(curFunc) then 'enter' else undef
124
- ]
125
- else if (lMatches = str.match(///^
258
+ else if lMatches = str.match(///^
126
259
  \s*
127
260
  return
128
261
  .+
129
262
  from
130
263
  \s+
131
264
  ([A-Za-z_][A-Za-z0-9_\.]*)
132
- ///))
133
- curFunc = lMatches[1]
134
- [mainPre, auxPre, hEnv] = stack.returnFrom(curFunc)
135
- if doDebugDebug
136
- LOG " RETURN FROM #{curFunc}"
137
- return [
138
- mainPre
139
- auxPre
140
- hEnv
141
- if shouldLogFunc(curFunc) then 'return' else undef
142
- ]
143
- else
144
- [mainPre, auxPre, _] = stack.logStr()
145
- return [
146
- mainPre
147
- auxPre
148
- undef
149
- if shouldLogString(str) then 'string' else undef
150
- ]
151
-
152
- # ---------------------------------------------------------------------------
153
-
154
- export debug = (lArgs...) ->
155
-
156
- # --- We want to allow item to be undef. Therefore, we need to
157
- # distinguish between 1 arg sent vs. 2 args sent
158
- nArgs = lArgs.length
159
- assert (nArgs==1) || (nArgs==2), "debug(): #{nArgs} args"
265
+ ///)
266
+ return ['return', lMatches[1]]
160
267
 
161
- # --- label must always be there, and be a string
162
- # item is optional
163
- [label, item] = lArgs
164
- assert isString(label),
165
- "debug(): 1st arg #{OL(label)} should be a string"
166
-
167
- if doDebugDebug
168
- if nArgs==1
169
- LOG "debug('#{escapeStr(label)}') - 1 arg"
170
- else
171
- LOG "debug('#{escapeStr(label)}', #{typeof item}) - 2 args"
172
- LOG "debugging flag = #{OL(debugging)}"
173
-
174
- # --- We always need to manipulate the stack when we encounter
175
- # either "enter X" or "return from X", so we can't short-circuit
176
- # when debugging is off
177
-
178
- lResult = adjustStack(label)
179
- if doDebugDebug
180
- LOG 'lResult', lResult
181
- [mainPre, auxPre, hEnv, type] = lResult
182
- if doDebugDebug && (type == undef)
183
- LOG "type is undef - NOT LOGGING"
184
-
185
- hOptions = {
186
- prefix: mainPre
187
- itemPrefix: auxPre
188
- }
189
-
190
- switch type
191
- when 'enter'
192
- log label, hOptions
193
- if (nArgs==2)
194
- # --- don't repeat the label
195
- logItem undef, item, hOptions
196
- when 'return'
197
- log label, hOptions
198
- if (nArgs==2)
199
- # --- don't repeat the label
200
- logItem undef, item, hOptions
201
- when 'string'
202
- if (nArgs==2)
203
- logItem label, item, hOptions
204
- else
205
- log label, hOptions
206
-
207
- if hEnv
208
- orgDebugging = debugging
209
- {debugging, shouldLogFunc, shouldLogString} = hEnv
210
- if doDebugDebug
211
- trans = "#{orgDebugging} => #{debugging}"
212
- LOG " Restore hEnv: debugging: #{trans}"
213
- return true # allow use in boolean expressions
268
+ else if (nObjects > 0)
269
+ return ['objects', undef]
270
+ else
271
+ return ['string', undef]
214
272
 
215
273
  # ---------------------------------------------------------------------------
216
274