@jdeighan/coffee-utils 7.0.49 → 7.0.52
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 +2 -2
- package/src/arrow.coffee +40 -4
- package/src/arrow.js +46 -5
- package/src/call_stack.coffee +93 -46
- package/src/call_stack.js +94 -47
- package/src/coffee_utils.coffee +12 -0
- package/src/coffee_utils.js +11 -0
- package/src/debug_utils.coffee +211 -145
- package/src/debug_utils.js +245 -138
- package/src/log_utils.coffee +49 -26
- package/src/log_utils.js +48 -27
package/package.json
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
{
|
2
2
|
"name": "@jdeighan/coffee-utils",
|
3
3
|
"type": "module",
|
4
|
-
"version": "7.0.
|
4
|
+
"version": "7.0.52",
|
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.
|
55
|
+
"@jdeighan/unit-tester": "^2.0.5"
|
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
|
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
|
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 '
|
22
|
-
result = oneIndent.repeat(level
|
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
|
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
|
-
|
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 '
|
30
|
-
result = oneIndent.repeat(level
|
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
|
+
};
|
package/src/call_stack.coffee
CHANGED
@@ -1,6 +1,8 @@
|
|
1
1
|
# call_stack.coffee
|
2
2
|
|
3
|
-
import {
|
3
|
+
import {
|
4
|
+
undef, defined, croak, assert, OL, isBoolean, escapeStr,
|
5
|
+
} from '@jdeighan/coffee-utils'
|
4
6
|
import {log, LOG} from '@jdeighan/coffee-utils/log'
|
5
7
|
import {getPrefix} from '@jdeighan/coffee-utils/arrow'
|
6
8
|
|
@@ -19,7 +21,8 @@ export class CallStack
|
|
19
21
|
|
20
22
|
constructor: () ->
|
21
23
|
|
22
|
-
@
|
24
|
+
@lStack = []
|
25
|
+
@level = 0
|
23
26
|
|
24
27
|
# ........................................................................
|
25
28
|
|
@@ -27,86 +30,130 @@ export class CallStack
|
|
27
30
|
|
28
31
|
if doDebugStack
|
29
32
|
LOG "RESET STACK"
|
30
|
-
|
31
33
|
@lStack = []
|
32
34
|
@level = 0
|
33
35
|
return
|
34
36
|
|
35
37
|
# ........................................................................
|
36
38
|
|
37
|
-
|
39
|
+
enter: (funcName, oldFlag=undef) ->
|
40
|
+
# --- funcName might be <object>.<method>
|
38
41
|
|
39
|
-
|
40
|
-
if
|
41
|
-
|
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
|
+
})
|
42
67
|
return
|
43
68
|
|
44
69
|
# ........................................................................
|
45
70
|
|
46
|
-
|
47
|
-
|
48
|
-
{funcName, hInfo, isLogged} = @lStack.pop()
|
49
|
-
if isLogged && (@level > 0)
|
50
|
-
@level -= 1
|
51
|
-
while (funcName != fName) && (@lStack.length > 0)
|
52
|
-
LOG "[MISSING RETURN FROM #{funcName} (return from #{fName})]"
|
53
|
-
{funcName, hInfo, isLogged} = @lStack.pop()
|
54
|
-
if isLogged && (@level > 0)
|
55
|
-
@level -= 1
|
71
|
+
isLogging: () ->
|
56
72
|
|
57
|
-
if
|
58
|
-
return
|
73
|
+
if (@lStack.length == 0)
|
74
|
+
return false
|
59
75
|
else
|
60
|
-
@
|
61
|
-
LOG "BAD BAD BAD BAD returnFrom('#{fName}')"
|
62
|
-
return undef
|
76
|
+
return @lStack[@lStack.length - 1].isLogged
|
63
77
|
|
64
78
|
# ........................................................................
|
79
|
+
|
80
|
+
isLoggingPrev: () ->
|
81
|
+
|
82
|
+
if (@lStack.length < 2)
|
83
|
+
return false
|
84
|
+
else
|
85
|
+
return @lStack[@lStack.length - 2].isLogged
|
86
|
+
|
65
87
|
# ........................................................................
|
66
88
|
|
67
|
-
|
89
|
+
logCurFunc: () ->
|
68
90
|
|
69
|
-
|
70
|
-
|
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) ->
|
71
103
|
|
72
104
|
if doDebugStack
|
73
|
-
|
74
|
-
LOG "#{prefix}[--> CALL #{funcName}]"
|
105
|
+
LOG "[<-- BACK #{fName}]"
|
75
106
|
|
76
|
-
@
|
77
|
-
|
78
|
-
|
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
|
79
126
|
|
80
127
|
# ........................................................................
|
81
128
|
|
82
|
-
|
129
|
+
getLevel: () ->
|
83
130
|
|
84
|
-
|
85
|
-
return [pre, pre, undef]
|
131
|
+
return @level
|
86
132
|
|
87
133
|
# ........................................................................
|
88
134
|
|
89
|
-
|
135
|
+
curFunc: () ->
|
90
136
|
|
91
|
-
|
92
|
-
|
93
|
-
|
137
|
+
if (@lStack.length == 0)
|
138
|
+
return 'main'
|
139
|
+
else
|
140
|
+
return @lStack[@lStack.length - 1].funcName
|
94
141
|
|
95
|
-
|
96
|
-
LOG "returnFrom('#{funcName}') but stack is empty"
|
97
|
-
return [mainPre, auxPre, undef]
|
142
|
+
# ........................................................................
|
98
143
|
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
LOG "#{prefix}[<-- BACK #{funcName}]"
|
144
|
+
isActive: (funcName) ->
|
145
|
+
# --- funcName won't be <obj>.<method>
|
146
|
+
# but the stack might contain that form
|
103
147
|
|
104
|
-
|
148
|
+
for h in @lStack
|
149
|
+
if (h.funcName == funcName)
|
150
|
+
return true
|
151
|
+
return false
|
105
152
|
|
106
153
|
# ........................................................................
|
107
154
|
# ........................................................................
|
108
155
|
|
109
|
-
dump: (label='CALL STACK') ->
|
156
|
+
dump: (prefix='', label='CALL STACK') ->
|
110
157
|
|
111
158
|
LOG "#{label}:"
|
112
159
|
if @lStack.length == 0
|
package/src/call_stack.js
CHANGED
@@ -4,8 +4,12 @@ var doDebugStack;
|
|
4
4
|
|
5
5
|
import {
|
6
6
|
undef,
|
7
|
+
defined,
|
7
8
|
croak,
|
8
|
-
assert
|
9
|
+
assert,
|
10
|
+
OL,
|
11
|
+
isBoolean,
|
12
|
+
escapeStr
|
9
13
|
} from '@jdeighan/coffee-utils';
|
10
14
|
|
11
15
|
import {
|
@@ -27,7 +31,8 @@ export var debugStack = function(flag = true) {
|
|
27
31
|
// ---------------------------------------------------------------------------
|
28
32
|
export var CallStack = class CallStack {
|
29
33
|
constructor() {
|
30
|
-
this.
|
34
|
+
this.lStack = [];
|
35
|
+
this.level = 0;
|
31
36
|
}
|
32
37
|
|
33
38
|
// ........................................................................
|
@@ -40,79 +45,121 @@ export var CallStack = class CallStack {
|
|
40
45
|
}
|
41
46
|
|
42
47
|
// ........................................................................
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
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
|
+
});
|
47
70
|
}
|
48
71
|
}
|
49
72
|
|
50
73
|
// ........................................................................
|
51
|
-
|
52
|
-
|
53
|
-
|
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());
|
54
114
|
if (isLogged && (this.level > 0)) {
|
55
115
|
this.level -= 1;
|
56
116
|
}
|
57
|
-
|
58
|
-
|
59
|
-
(
|
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());
|
60
121
|
if (isLogged && (this.level > 0)) {
|
61
122
|
this.level -= 1;
|
62
123
|
}
|
63
124
|
}
|
64
|
-
if (
|
65
|
-
return hInfo;
|
66
|
-
} else {
|
125
|
+
if (fullName !== fName) {
|
67
126
|
this.dump();
|
68
127
|
LOG(`BAD BAD BAD BAD returnFrom('${fName}')`);
|
69
|
-
return undef;
|
70
128
|
}
|
71
129
|
}
|
72
130
|
|
73
131
|
// ........................................................................
|
74
|
-
|
75
|
-
|
76
|
-
var auxPre, mainPre, prefix;
|
77
|
-
assert(isLogged !== undef, "CallStack.call(): 3 args required");
|
78
|
-
mainPre = getPrefix(this.level);
|
79
|
-
if (doDebugStack) {
|
80
|
-
prefix = ' '.repeat(this.lStack.length);
|
81
|
-
LOG(`${prefix}[--> CALL ${funcName}]`);
|
82
|
-
}
|
83
|
-
this.addCall(funcName, hInfo, isLogged);
|
84
|
-
auxPre = getPrefix(this.level);
|
85
|
-
return [mainPre, auxPre, undef];
|
132
|
+
getLevel() {
|
133
|
+
return this.level;
|
86
134
|
}
|
87
135
|
|
88
136
|
// ........................................................................
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
137
|
+
curFunc() {
|
138
|
+
if (this.lStack.length === 0) {
|
139
|
+
return 'main';
|
140
|
+
} else {
|
141
|
+
return this.lStack[this.lStack.length - 1].funcName;
|
142
|
+
}
|
93
143
|
}
|
94
144
|
|
95
145
|
// ........................................................................
|
96
|
-
|
97
|
-
var
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
if (doDebugStack) {
|
107
|
-
prefix = ' '.repeat(this.lStack.length);
|
108
|
-
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
|
+
}
|
109
156
|
}
|
110
|
-
return
|
157
|
+
return false;
|
111
158
|
}
|
112
159
|
|
113
160
|
// ........................................................................
|
114
161
|
// ........................................................................
|
115
|
-
dump(label = 'CALL STACK') {
|
162
|
+
dump(prefix = '', label = 'CALL STACK') {
|
116
163
|
var i, item, j, len, ref;
|
117
164
|
LOG(`${label}:`);
|
118
165
|
if (this.lStack.length === 0) {
|
package/src/coffee_utils.coffee
CHANGED
@@ -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
|
+
|
package/src/coffee_utils.js
CHANGED
@@ -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
|
+
};
|