@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.
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@jdeighan/coffee-utils",
3
3
  "type": "module",
4
- "version": "7.0.50",
4
+ "version": "7.0.53",
5
5
  "description": "A set of utility functions for CoffeeScript",
6
6
  "main": "coffee_utils.js",
7
7
  "exports": {
@@ -52,6 +52,6 @@
52
52
  "svelte": "^3.48.0"
53
53
  },
54
54
  "devDependencies": {
55
- "@jdeighan/unit-tester": "^2.0.3"
55
+ "@jdeighan/unit-tester": "^2.0.6"
56
56
  }
57
57
  }
package/src/arrow.coffee CHANGED
@@ -1,5 +1,9 @@
1
1
  # arrow.coffee
2
2
 
3
+ import {undef, OL, setCharsAt} from '@jdeighan/coffee-utils'
4
+
5
+ # --- We use spaces here because Windows Terminal handles TAB chars badly
6
+
3
7
  export vbar = '│' # unicode 2502
4
8
  export hbar = '─' # unicode 2500
5
9
  export corner = '└' # unicode 2514
@@ -8,18 +12,22 @@ export space = ' '
8
12
 
9
13
  export oneIndent = vbar + space + space + space
10
14
  export arrow = corner + hbar + arrowhead + space
11
- export fourSpaces = space + space + space + space
15
+ export clearIndent = space + space + space + space
12
16
 
13
17
  # ---------------------------------------------------------------------------
14
18
 
15
19
  export getPrefix = (level, option='none') ->
16
20
 
17
- if level==0 then return ''
21
+ if level==0
22
+ if (option == 'object')
23
+ return clearIndent
24
+ else
25
+ return ''
18
26
  switch option
19
27
  when 'withArrow'
20
28
  result = oneIndent.repeat(level-1) + arrow
21
- when 'returnVal'
22
- result = oneIndent.repeat(level-1) + fourSpaces
29
+ when 'object'
30
+ result = oneIndent.repeat(level) + clearIndent
23
31
  when 'none'
24
32
  result = oneIndent.repeat(level)
25
33
  else
@@ -27,3 +35,31 @@ export getPrefix = (level, option='none') ->
27
35
  if result.length % 4 != 0
28
36
  throw new Error("getPrefix(): Bad prefix '#{result}'")
29
37
  return result
38
+
39
+ # ---------------------------------------------------------------------------
40
+
41
+ export addArrow = (prefix) ->
42
+
43
+ # console.log "in addArrow(#{OL(prefix)})"
44
+ pos = prefix.lastIndexOf(vbar)
45
+ # console.log "pos = #{pos}"
46
+ if (pos == -1)
47
+ result = prefix
48
+ else
49
+ result = setCharsAt(prefix, pos, arrow)
50
+ # console.log "result = #{OL(result)}"
51
+ return result
52
+
53
+ # ---------------------------------------------------------------------------
54
+
55
+ export removeLastVbar = (prefix) ->
56
+
57
+ # console.log "in removeLastVbar(#{OL(prefix)})"
58
+ pos = prefix.lastIndexOf(vbar)
59
+ # console.log "pos = #{pos}"
60
+ if (pos == -1)
61
+ result = prefix
62
+ else
63
+ result = setCharsAt(prefix, pos, ' ')
64
+ # console.log "result = #{OL(result)}"
65
+ return result
package/src/arrow.js CHANGED
@@ -1,5 +1,12 @@
1
1
  // Generated by CoffeeScript 2.7.0
2
- // arrow.coffee
2
+ // arrow.coffee
3
+ import {
4
+ undef,
5
+ OL,
6
+ setCharsAt
7
+ } from '@jdeighan/coffee-utils';
8
+
9
+ // --- We use spaces here because Windows Terminal handles TAB chars badly
3
10
  export var vbar = '│'; // unicode 2502
4
11
 
5
12
  export var hbar = '─'; // unicode 2500
@@ -14,20 +21,24 @@ export var oneIndent = vbar + space + space + space;
14
21
 
15
22
  export var arrow = corner + hbar + arrowhead + space;
16
23
 
17
- export var fourSpaces = space + space + space + space;
24
+ export var clearIndent = space + space + space + space;
18
25
 
19
26
  // ---------------------------------------------------------------------------
20
27
  export var getPrefix = function(level, option = 'none') {
21
28
  var result;
22
29
  if (level === 0) {
23
- return '';
30
+ if (option === 'object') {
31
+ return clearIndent;
32
+ } else {
33
+ return '';
34
+ }
24
35
  }
25
36
  switch (option) {
26
37
  case 'withArrow':
27
38
  result = oneIndent.repeat(level - 1) + arrow;
28
39
  break;
29
- case 'returnVal':
30
- result = oneIndent.repeat(level - 1) + fourSpaces;
40
+ case 'object':
41
+ result = oneIndent.repeat(level) + clearIndent;
31
42
  break;
32
43
  case 'none':
33
44
  result = oneIndent.repeat(level);
@@ -40,3 +51,33 @@ export var getPrefix = function(level, option = 'none') {
40
51
  }
41
52
  return result;
42
53
  };
54
+
55
+ // ---------------------------------------------------------------------------
56
+ export var addArrow = function(prefix) {
57
+ var pos, result;
58
+ // console.log "in addArrow(#{OL(prefix)})"
59
+ pos = prefix.lastIndexOf(vbar);
60
+ // console.log "pos = #{pos}"
61
+ if (pos === -1) {
62
+ result = prefix;
63
+ } else {
64
+ result = setCharsAt(prefix, pos, arrow);
65
+ }
66
+ // console.log "result = #{OL(result)}"
67
+ return result;
68
+ };
69
+
70
+ // ---------------------------------------------------------------------------
71
+ export var removeLastVbar = function(prefix) {
72
+ var pos, result;
73
+ // console.log "in removeLastVbar(#{OL(prefix)})"
74
+ pos = prefix.lastIndexOf(vbar);
75
+ // console.log "pos = #{pos}"
76
+ if (pos === -1) {
77
+ result = prefix;
78
+ } else {
79
+ result = setCharsAt(prefix, pos, ' ');
80
+ }
81
+ // console.log "result = #{OL(result)}"
82
+ return result;
83
+ };
@@ -1,7 +1,7 @@
1
1
  # call_stack.coffee
2
2
 
3
3
  import {
4
- undef, defined, croak, assert, isBoolean,
4
+ undef, defined, croak, assert, OL, isBoolean, escapeStr,
5
5
  } from '@jdeighan/coffee-utils'
6
6
  import {log, LOG} from '@jdeighan/coffee-utils/log'
7
7
  import {getPrefix} from '@jdeighan/coffee-utils/arrow'
@@ -21,7 +21,8 @@ export class CallStack
21
21
 
22
22
  constructor: () ->
23
23
 
24
- @reset()
24
+ @lStack = []
25
+ @level = 0
25
26
 
26
27
  # ........................................................................
27
28
 
@@ -29,86 +30,130 @@ export class CallStack
29
30
 
30
31
  if doDebugStack
31
32
  LOG "RESET STACK"
32
-
33
33
  @lStack = []
34
34
  @level = 0
35
35
  return
36
36
 
37
37
  # ........................................................................
38
38
 
39
- addCall: (funcName, hInfo, isLogged) ->
39
+ enter: (funcName, oldFlag=undef) ->
40
+ # --- funcName might be <object>.<method>
40
41
 
41
- @lStack.push({funcName, hInfo, isLogged})
42
- if isLogged
43
- @level += 1
42
+ assert (oldFlag == undef), "enter() takes only 1 arg"
43
+ if doDebugStack
44
+ LOG "[--> ENTER #{funcName}]"
45
+
46
+ lMatches = funcName.match(///^
47
+ ([A-Za-z_][A-Za-z0-9_]*)
48
+ (?:
49
+ \.
50
+ ([A-Za-z_][A-Za-z0-9_]*)
51
+ )?
52
+ $///)
53
+ assert defined(lMatches), "Bad funcName: #{OL(funcName)}"
54
+ [_, ident1, ident2] = lMatches
55
+ if ident2
56
+ @lStack.push({
57
+ fullName: "#{ident1}.#{ident2}"
58
+ funcName: ident2
59
+ isLogged: false
60
+ })
61
+ else
62
+ @lStack.push({
63
+ fullName: ident1
64
+ funcName: ident1
65
+ isLogged: false
66
+ })
44
67
  return
45
68
 
46
69
  # ........................................................................
47
70
 
48
- removeCall: (fName) ->
49
-
50
- {funcName, hInfo, isLogged} = @lStack.pop()
51
- if isLogged && (@level > 0)
52
- @level -= 1
53
- while (funcName != fName) && (@lStack.length > 0)
54
- LOG "[MISSING RETURN FROM #{funcName} (return from #{fName})]"
55
- {funcName, hInfo, isLogged} = @lStack.pop()
56
- if isLogged && (@level > 0)
57
- @level -= 1
71
+ isLogging: () ->
58
72
 
59
- if funcName == fName
60
- return hInfo
73
+ if (@lStack.length == 0)
74
+ return false
61
75
  else
62
- @dump()
63
- LOG "BAD BAD BAD BAD returnFrom('#{fName}')"
64
- return undef
76
+ return @lStack[@lStack.length - 1].isLogged
65
77
 
66
78
  # ........................................................................
79
+
80
+ isLoggingPrev: () ->
81
+
82
+ if (@lStack.length < 2)
83
+ return false
84
+ else
85
+ return @lStack[@lStack.length - 2].isLogged
86
+
67
87
  # ........................................................................
68
88
 
69
- doCall: (funcName, hInfo, isLogged) ->
89
+ logCurFunc: () ->
70
90
 
71
- assert isBoolean(isLogged), "CallStack.call(): 3 args required"
72
- mainPre = getPrefix(@level)
91
+ # --- funcName must be the current function
92
+ # and the isLogged flag must currently be false
93
+ cur = @lStack[@lStack.length - 1]
94
+ assert (cur.isLogged == false), "isLogged is already true"
95
+ cur.isLogged = true
96
+ @level += 1
97
+ return
98
+
99
+ # ........................................................................
100
+ # --- if stack is empty, log the error, but continue
101
+
102
+ returnFrom: (fName) ->
73
103
 
74
104
  if doDebugStack
75
- prefix = ' '.repeat(@lStack.length)
76
- LOG "#{prefix}[--> CALL #{funcName}]"
105
+ LOG "[<-- BACK #{fName}]"
77
106
 
78
- @addCall funcName, hInfo, isLogged
79
- auxPre = getPrefix(@level)
80
- return [mainPre, auxPre]
107
+ if @lStack.length == 0
108
+ LOG "ERROR: returnFrom('#{funcName}') but stack is empty"
109
+ return
110
+
111
+ {fullName, isLogged} = @lStack.pop()
112
+ if isLogged && (@level > 0)
113
+ @level -= 1
114
+
115
+ # --- This should do nothing
116
+ while (fullName != fName) && (@lStack.length > 0)
117
+ LOG "[MISSING RETURN FROM #{fullName} (return from #{fName})]"
118
+ {fullName, isLogged} = @lStack.pop()
119
+ if isLogged && (@level > 0)
120
+ @level -= 1
121
+
122
+ if fullName != fName
123
+ @dump()
124
+ LOG "BAD BAD BAD BAD returnFrom('#{fName}')"
125
+ return
81
126
 
82
127
  # ........................................................................
83
128
 
84
- logStr: () ->
129
+ getLevel: () ->
85
130
 
86
- pre = getPrefix(@level)
87
- return [pre, pre, undef]
131
+ return @level
88
132
 
89
133
  # ........................................................................
90
134
 
91
- returnFrom: (funcName) ->
135
+ curFunc: () ->
92
136
 
93
- # --- Prefixes are based on level before stack adjustment
94
- mainPre = getPrefix(@level, 'withArrow')
95
- auxPre = getPrefix(@level, 'returnVal')
137
+ if (@lStack.length == 0)
138
+ return 'main'
139
+ else
140
+ return @lStack[@lStack.length - 1].funcName
96
141
 
97
- if @lStack.length == 0
98
- LOG "returnFrom('#{funcName}') but stack is empty"
99
- return [mainPre, auxPre, undef]
142
+ # ........................................................................
100
143
 
101
- hInfo = @removeCall(funcName)
102
- if doDebugStack
103
- prefix = ' '.repeat(@lStack.length)
104
- LOG "#{prefix}[<-- BACK #{funcName}]"
144
+ isActive: (funcName) ->
145
+ # --- funcName won't be <obj>.<method>
146
+ # but the stack might contain that form
105
147
 
106
- return [mainPre, auxPre, hInfo]
148
+ for h in @lStack
149
+ if (h.funcName == funcName)
150
+ return true
151
+ return false
107
152
 
108
153
  # ........................................................................
109
154
  # ........................................................................
110
155
 
111
- dump: (label='CALL STACK') ->
156
+ dump: (prefix='', label='CALL STACK') ->
112
157
 
113
158
  LOG "#{label}:"
114
159
  if @lStack.length == 0
package/src/call_stack.js CHANGED
@@ -7,7 +7,9 @@ import {
7
7
  defined,
8
8
  croak,
9
9
  assert,
10
- isBoolean
10
+ OL,
11
+ isBoolean,
12
+ escapeStr
11
13
  } from '@jdeighan/coffee-utils';
12
14
 
13
15
  import {
@@ -29,7 +31,8 @@ export var debugStack = function(flag = true) {
29
31
  // ---------------------------------------------------------------------------
30
32
  export var CallStack = class CallStack {
31
33
  constructor() {
32
- this.reset();
34
+ this.lStack = [];
35
+ this.level = 0;
33
36
  }
34
37
 
35
38
  // ........................................................................
@@ -42,79 +45,121 @@ export var CallStack = class CallStack {
42
45
  }
43
46
 
44
47
  // ........................................................................
45
- addCall(funcName, hInfo, isLogged) {
46
- this.lStack.push({funcName, hInfo, isLogged});
47
- if (isLogged) {
48
- this.level += 1;
48
+ enter(funcName, oldFlag = undef) {
49
+ var _, ident1, ident2, lMatches;
50
+ // --- funcName might be <object>.<method>
51
+ assert(oldFlag === undef, "enter() takes only 1 arg");
52
+ if (doDebugStack) {
53
+ LOG(`[--> ENTER ${funcName}]`);
54
+ }
55
+ lMatches = funcName.match(/^([A-Za-z_][A-Za-z0-9_]*)(?:\.([A-Za-z_][A-Za-z0-9_]*))?$/);
56
+ assert(defined(lMatches), `Bad funcName: ${OL(funcName)}`);
57
+ [_, ident1, ident2] = lMatches;
58
+ if (ident2) {
59
+ this.lStack.push({
60
+ fullName: `${ident1}.${ident2}`,
61
+ funcName: ident2,
62
+ isLogged: false
63
+ });
64
+ } else {
65
+ this.lStack.push({
66
+ fullName: ident1,
67
+ funcName: ident1,
68
+ isLogged: false
69
+ });
49
70
  }
50
71
  }
51
72
 
52
73
  // ........................................................................
53
- removeCall(fName) {
54
- var funcName, hInfo, isLogged;
55
- ({funcName, hInfo, isLogged} = this.lStack.pop());
74
+ isLogging() {
75
+ if (this.lStack.length === 0) {
76
+ return false;
77
+ } else {
78
+ return this.lStack[this.lStack.length - 1].isLogged;
79
+ }
80
+ }
81
+
82
+ // ........................................................................
83
+ isLoggingPrev() {
84
+ if (this.lStack.length < 2) {
85
+ return false;
86
+ } else {
87
+ return this.lStack[this.lStack.length - 2].isLogged;
88
+ }
89
+ }
90
+
91
+ // ........................................................................
92
+ logCurFunc() {
93
+ var cur;
94
+ // --- funcName must be the current function
95
+ // and the isLogged flag must currently be false
96
+ cur = this.lStack[this.lStack.length - 1];
97
+ assert(cur.isLogged === false, "isLogged is already true");
98
+ cur.isLogged = true;
99
+ this.level += 1;
100
+ }
101
+
102
+ // ........................................................................
103
+ // --- if stack is empty, log the error, but continue
104
+ returnFrom(fName) {
105
+ var fullName, isLogged;
106
+ if (doDebugStack) {
107
+ LOG(`[<-- BACK ${fName}]`);
108
+ }
109
+ if (this.lStack.length === 0) {
110
+ LOG(`ERROR: returnFrom('${funcName}') but stack is empty`);
111
+ return;
112
+ }
113
+ ({fullName, isLogged} = this.lStack.pop());
56
114
  if (isLogged && (this.level > 0)) {
57
115
  this.level -= 1;
58
116
  }
59
- while ((funcName !== fName) && (this.lStack.length > 0)) {
60
- LOG(`[MISSING RETURN FROM ${funcName} (return from ${fName})]`);
61
- ({funcName, hInfo, isLogged} = this.lStack.pop());
117
+ // --- This should do nothing
118
+ while ((fullName !== fName) && (this.lStack.length > 0)) {
119
+ LOG(`[MISSING RETURN FROM ${fullName} (return from ${fName})]`);
120
+ ({fullName, isLogged} = this.lStack.pop());
62
121
  if (isLogged && (this.level > 0)) {
63
122
  this.level -= 1;
64
123
  }
65
124
  }
66
- if (funcName === fName) {
67
- return hInfo;
68
- } else {
125
+ if (fullName !== fName) {
69
126
  this.dump();
70
127
  LOG(`BAD BAD BAD BAD returnFrom('${fName}')`);
71
- return undef;
72
128
  }
73
129
  }
74
130
 
75
131
  // ........................................................................
76
- // ........................................................................
77
- doCall(funcName, hInfo, isLogged) {
78
- var auxPre, mainPre, prefix;
79
- assert(isBoolean(isLogged), "CallStack.call(): 3 args required");
80
- mainPre = getPrefix(this.level);
81
- if (doDebugStack) {
82
- prefix = ' '.repeat(this.lStack.length);
83
- LOG(`${prefix}[--> CALL ${funcName}]`);
84
- }
85
- this.addCall(funcName, hInfo, isLogged);
86
- auxPre = getPrefix(this.level);
87
- return [mainPre, auxPre];
132
+ getLevel() {
133
+ return this.level;
88
134
  }
89
135
 
90
136
  // ........................................................................
91
- logStr() {
92
- var pre;
93
- pre = getPrefix(this.level);
94
- return [pre, pre, undef];
137
+ curFunc() {
138
+ if (this.lStack.length === 0) {
139
+ return 'main';
140
+ } else {
141
+ return this.lStack[this.lStack.length - 1].funcName;
142
+ }
95
143
  }
96
144
 
97
145
  // ........................................................................
98
- returnFrom(funcName) {
99
- var auxPre, hInfo, mainPre, prefix;
100
- // --- Prefixes are based on level before stack adjustment
101
- mainPre = getPrefix(this.level, 'withArrow');
102
- auxPre = getPrefix(this.level, 'returnVal');
103
- if (this.lStack.length === 0) {
104
- LOG(`returnFrom('${funcName}') but stack is empty`);
105
- return [mainPre, auxPre, undef];
106
- }
107
- hInfo = this.removeCall(funcName);
108
- if (doDebugStack) {
109
- prefix = ' '.repeat(this.lStack.length);
110
- LOG(`${prefix}[<-- BACK ${funcName}]`);
146
+ isActive(funcName) {
147
+ var h, j, len, ref;
148
+ ref = this.lStack;
149
+ // --- funcName won't be <obj>.<method>
150
+ // but the stack might contain that form
151
+ for (j = 0, len = ref.length; j < len; j++) {
152
+ h = ref[j];
153
+ if (h.funcName === funcName) {
154
+ return true;
155
+ }
111
156
  }
112
- return [mainPre, auxPre, hInfo];
157
+ return false;
113
158
  }
114
159
 
115
160
  // ........................................................................
116
161
  // ........................................................................
117
- dump(label = 'CALL STACK') {
162
+ dump(prefix = '', label = 'CALL STACK') {
118
163
  var i, item, j, len, ref;
119
164
  LOG(`${label}:`);
120
165
  if (this.lStack.length === 0) {
@@ -503,3 +503,15 @@ export className = (aClass) ->
503
503
  export range = (n) ->
504
504
 
505
505
  return [0..n-1]
506
+
507
+ # ---------------------------------------------------------------------------
508
+
509
+ export setCharsAt = (str, pos, str2) ->
510
+
511
+ assert (pos >= 0), "negative pos #{pos} not allowed"
512
+ assert (pos < str.length), "pos #{pos} not in #{OL(str)}"
513
+ if (pos + str2.length >= str.length)
514
+ return str.substring(0, pos) + str2
515
+ else
516
+ return str.substring(0, pos) + str2 + str.substring(pos + str2.length)
517
+
@@ -543,3 +543,14 @@ export var range = function(n) {
543
543
  return results;
544
544
  }).apply(this);
545
545
  };
546
+
547
+ // ---------------------------------------------------------------------------
548
+ export var setCharsAt = function(str, pos, str2) {
549
+ assert(pos >= 0, `negative pos ${pos} not allowed`);
550
+ assert(pos < str.length, `pos ${pos} not in ${OL(str)}`);
551
+ if (pos + str2.length >= str.length) {
552
+ return str.substring(0, pos) + str2;
553
+ } else {
554
+ return str.substring(0, pos) + str2 + str.substring(pos + str2.length);
555
+ }
556
+ };