@ethanblaisalarms/utils 1.0.0
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/README.md +721 -0
- package/dist/index.d.ts +20 -0
- package/dist/index.js +231 -0
- package/dist/test.d.ts +1 -0
- package/dist/test.js +312 -0
- package/eba_utils.code-workspace +8 -0
- package/package.json +23 -0
- package/src/index.ts +286 -0
- package/src/test.ts +366 -0
- package/tsconfig.json +13 -0
package/src/index.ts
ADDED
|
@@ -0,0 +1,286 @@
|
|
|
1
|
+
//=======================================\\
|
|
2
|
+
// EBA UTILITIES 1.0.0 \\
|
|
3
|
+
// index.ts \\
|
|
4
|
+
// Copyright (c) EthanBlaisAlarms 2026 \\
|
|
5
|
+
//=======================================\\
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
//========================
|
|
9
|
+
// TYPES and INTERFACES
|
|
10
|
+
//========================
|
|
11
|
+
export type TRecord<T = unknown> = Record<string, T>;
|
|
12
|
+
export type TNumRecord<T = unknown> = Record<number, T>;
|
|
13
|
+
export type TCondition = (iteration?:number)=>boolean;
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
//====================
|
|
17
|
+
// OBJECT UTILITIES
|
|
18
|
+
//====================
|
|
19
|
+
export function merge<T extends object>(
|
|
20
|
+
target:T,
|
|
21
|
+
...sources:object[]
|
|
22
|
+
):T {
|
|
23
|
+
// Ignored node names.
|
|
24
|
+
// Prevents accidentally overwriting prototypes and constructors.
|
|
25
|
+
const blocklist = new Set(["__proto__", "prototype", "constructor"]);
|
|
26
|
+
const seen = new WeakSet();
|
|
27
|
+
|
|
28
|
+
const innerMerge = function(
|
|
29
|
+
target:TRecord,
|
|
30
|
+
source:TRecord,
|
|
31
|
+
):void {
|
|
32
|
+
if (seen.has(source)) return;
|
|
33
|
+
seen.add(source);
|
|
34
|
+
|
|
35
|
+
for (const i of Object.keys(source)) {
|
|
36
|
+
// Skip ignored node names.
|
|
37
|
+
// Skip functions.
|
|
38
|
+
if (blocklist.has(i)) continue;
|
|
39
|
+
if (typeof source[i] === "function") continue;
|
|
40
|
+
|
|
41
|
+
// Merge Arrays
|
|
42
|
+
if (Array.isArray(source[i]) && Array.isArray(target[i])) {
|
|
43
|
+
target[i] = target[i].concat(source[i]);
|
|
44
|
+
continue;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// Merge Non-Recursive
|
|
48
|
+
if (!checkPlain(target[i]) || !checkPlain(source[i])) {
|
|
49
|
+
target[i] = source[i];
|
|
50
|
+
continue;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// Merge Recursive
|
|
54
|
+
innerMerge(target[i], source[i]);
|
|
55
|
+
}
|
|
56
|
+
seen.delete(source);
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
for (const source of sources) innerMerge(target as TRecord, source as TRecord);
|
|
60
|
+
return target;
|
|
61
|
+
}
|
|
62
|
+
export function decommentJSON(data:string):string {
|
|
63
|
+
const linebreaks:string[] = ["\n", "\r"];
|
|
64
|
+
let inside = false;
|
|
65
|
+
let escape = false;
|
|
66
|
+
let single = false;
|
|
67
|
+
let multi = false;
|
|
68
|
+
let result = "";
|
|
69
|
+
|
|
70
|
+
for (let i = 0; i < data.length; i++) {
|
|
71
|
+
const char:string = data[i];
|
|
72
|
+
const nextChar:string = data[i+1] ?? "";
|
|
73
|
+
const nextChars:string = char + nextChar;
|
|
74
|
+
|
|
75
|
+
if (inside) {
|
|
76
|
+
if (escape) escape = false;
|
|
77
|
+
else if (char == "\\") escape = true;
|
|
78
|
+
else if (char == "\"") inside = false;
|
|
79
|
+
}
|
|
80
|
+
else if (single) {
|
|
81
|
+
if (linebreaks.includes(char)) single = false;
|
|
82
|
+
else continue;
|
|
83
|
+
}
|
|
84
|
+
else if (multi) {
|
|
85
|
+
if (nextChars == "*/") {
|
|
86
|
+
multi = false;
|
|
87
|
+
i++;
|
|
88
|
+
}
|
|
89
|
+
continue;
|
|
90
|
+
}
|
|
91
|
+
else if (nextChars == "//") {
|
|
92
|
+
single = true;
|
|
93
|
+
i++;
|
|
94
|
+
continue;
|
|
95
|
+
}
|
|
96
|
+
else if (nextChars == "/*") {
|
|
97
|
+
multi = true;
|
|
98
|
+
i++;
|
|
99
|
+
continue;
|
|
100
|
+
}
|
|
101
|
+
else if (char == "\"") inside = true;
|
|
102
|
+
result += char;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
return result;
|
|
106
|
+
}
|
|
107
|
+
export function checkPlain(data:unknown):data is TRecord {
|
|
108
|
+
return Object.prototype.toString.call(data) === "[object Object]";
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
//===================
|
|
113
|
+
// ARRAY UTILITIES
|
|
114
|
+
//===================
|
|
115
|
+
export function pull<T>(
|
|
116
|
+
target:T[],
|
|
117
|
+
...elements:T[]
|
|
118
|
+
):T[] {
|
|
119
|
+
for (const element of elements) {
|
|
120
|
+
const i:number = target.indexOf(element);
|
|
121
|
+
if (i >= 0) target.splice(i, 1);
|
|
122
|
+
}
|
|
123
|
+
return target;
|
|
124
|
+
}
|
|
125
|
+
export function pullAll<T>(
|
|
126
|
+
target:T[],
|
|
127
|
+
...elements:T[]
|
|
128
|
+
):T[] {
|
|
129
|
+
for (const element of elements) {
|
|
130
|
+
let i;
|
|
131
|
+
while ((i = target.indexOf(element)) !== -1) target.splice(i, 1);
|
|
132
|
+
}
|
|
133
|
+
return target;
|
|
134
|
+
}
|
|
135
|
+
export function replace<T>(
|
|
136
|
+
target:T[],
|
|
137
|
+
element:T,
|
|
138
|
+
...replace:T[]
|
|
139
|
+
):T[] {
|
|
140
|
+
const i:number = target.indexOf(element);
|
|
141
|
+
if (i >= 0) target.splice(i, 1, ...replace);
|
|
142
|
+
return target;
|
|
143
|
+
}
|
|
144
|
+
export function replaceAll<T>(
|
|
145
|
+
target:T[],
|
|
146
|
+
element:T,
|
|
147
|
+
...replace:T[]
|
|
148
|
+
):T[] {
|
|
149
|
+
let i;
|
|
150
|
+
while ((i = target.indexOf(element)) !== -1) target.splice(i, 1, ...replace);
|
|
151
|
+
return target;
|
|
152
|
+
}
|
|
153
|
+
export function objectify<T>(source:T[]):TNumRecord<T> {
|
|
154
|
+
const output:TNumRecord<T> = {};
|
|
155
|
+
for (const i of source.keys()) output[i] = source[i];
|
|
156
|
+
return output;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
|
|
160
|
+
//=============
|
|
161
|
+
// STRINGIFY
|
|
162
|
+
//=============
|
|
163
|
+
export function stringify(data:unknown):string {
|
|
164
|
+
if (typeof data === "bigint") return `${data}n`;
|
|
165
|
+
if (typeof data !== "object") return String(data);
|
|
166
|
+
if (data === null) return "null";
|
|
167
|
+
|
|
168
|
+
if (data instanceof Set) return stringify(Array.from(data));
|
|
169
|
+
if (data instanceof Map) return stringify(Array.from(data.entries()));
|
|
170
|
+
|
|
171
|
+
if (Array.isArray(data)) return stringifyJSON(data);
|
|
172
|
+
|
|
173
|
+
if (
|
|
174
|
+
data.toString !== Object.prototype.toString
|
|
175
|
+
&& typeof data.toString === "function"
|
|
176
|
+
) return data.toString();
|
|
177
|
+
|
|
178
|
+
return stringifyJSON({...data});
|
|
179
|
+
}
|
|
180
|
+
export function stringifyArray(data:unknown[]):string[] {
|
|
181
|
+
return data.map(stringify);
|
|
182
|
+
}
|
|
183
|
+
export function stringifyJSON(
|
|
184
|
+
data:object,
|
|
185
|
+
separator:string = " ",
|
|
186
|
+
ignore:string[] = [],
|
|
187
|
+
):string {
|
|
188
|
+
const seen:WeakSet<object> = new WeakSet();
|
|
189
|
+
const paths:WeakMap<object, string> = new WeakMap();
|
|
190
|
+
const ignoreSet = new Set(ignore);
|
|
191
|
+
|
|
192
|
+
const replacer = function(this:any, key:string, value:unknown):unknown {
|
|
193
|
+
const parent = paths.get(this) ?? "";
|
|
194
|
+
const current = key
|
|
195
|
+
? (parent ? parent + "." : "") + key
|
|
196
|
+
: "";
|
|
197
|
+
|
|
198
|
+
if (ignoreSet.has(current)) return undefined;
|
|
199
|
+
|
|
200
|
+
if (typeof value == "bigint") return `${value}n`;
|
|
201
|
+
|
|
202
|
+
if (typeof value == "object" && value) {
|
|
203
|
+
if (seen.has(value)) return `[Circular: ${paths.get(value) || "~"}]`;
|
|
204
|
+
seen.add(value);
|
|
205
|
+
if (current != "") paths.set(value, current);
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
if (value instanceof Set) return Array.from(value);
|
|
209
|
+
if (value instanceof Map) return Array.from(value.entries());
|
|
210
|
+
|
|
211
|
+
return value;
|
|
212
|
+
};
|
|
213
|
+
paths.set(data, "");
|
|
214
|
+
return JSON.stringify(data, replacer, separator);
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
|
|
218
|
+
//=================
|
|
219
|
+
// RANDOMIZATION
|
|
220
|
+
//=================
|
|
221
|
+
export function rand(
|
|
222
|
+
base?:number,
|
|
223
|
+
maxInput?:number,
|
|
224
|
+
):number;
|
|
225
|
+
export function rand<T>(
|
|
226
|
+
base:T[],
|
|
227
|
+
):T|null;
|
|
228
|
+
export function rand(
|
|
229
|
+
base:TRecord,
|
|
230
|
+
):string|null;
|
|
231
|
+
export function rand(
|
|
232
|
+
base?:number|unknown[]|TRecord,
|
|
233
|
+
max?:number,
|
|
234
|
+
):unknown {
|
|
235
|
+
if (typeof base == "number") {
|
|
236
|
+
const hasMax = typeof max == "number";
|
|
237
|
+
const setBase = hasMax ? Math.min(base, max) : 0;
|
|
238
|
+
const setMax = hasMax ? Math.max(base, max) : base;
|
|
239
|
+
return Math.floor(Math.random() * (setMax - setBase + 1)) + setBase;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
if (!base) return Math.random();
|
|
243
|
+
|
|
244
|
+
if (Array.isArray(base)) {
|
|
245
|
+
if (base.length < 1) return null;
|
|
246
|
+
return base[rand(base.length - 1)];
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
const keys = Object.keys(base);
|
|
250
|
+
if (keys.length < 1) return null;
|
|
251
|
+
return rand(keys);
|
|
252
|
+
}
|
|
253
|
+
export function randString(
|
|
254
|
+
len=16,
|
|
255
|
+
charset:string|string[]="0123456789ABCDEF",
|
|
256
|
+
):string {
|
|
257
|
+
if (typeof charset === "string") charset = charset.split("");
|
|
258
|
+
if (charset.length < 1) return "";
|
|
259
|
+
let output = "";
|
|
260
|
+
while (len > 0) {
|
|
261
|
+
output += rand(charset);
|
|
262
|
+
len--;
|
|
263
|
+
}
|
|
264
|
+
return output;
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
|
|
268
|
+
//===================
|
|
269
|
+
// ASYNC UTILITIES
|
|
270
|
+
//===================
|
|
271
|
+
export async function sleep(ms:number):Promise<void> {
|
|
272
|
+
return new Promise((resolve) => {
|
|
273
|
+
setTimeout(resolve, ms);
|
|
274
|
+
});
|
|
275
|
+
}
|
|
276
|
+
export async function until(
|
|
277
|
+
condition:TCondition,
|
|
278
|
+
interval=100,
|
|
279
|
+
attempts:number|null=null,
|
|
280
|
+
):Promise<number> {
|
|
281
|
+
for (let i = 0; (i < (attempts ?? i+1)); i++) {
|
|
282
|
+
if (condition(i+1)) return i+1;
|
|
283
|
+
await sleep(interval);
|
|
284
|
+
}
|
|
285
|
+
throw new RangeError("Maximum number of attempts reached.");
|
|
286
|
+
}
|
package/src/test.ts
ADDED
|
@@ -0,0 +1,366 @@
|
|
|
1
|
+
//=======================================\\
|
|
2
|
+
// EBA UTILITIES 1.0.0 \\
|
|
3
|
+
// test.ts \\
|
|
4
|
+
// Copyright (c) EthanBlaisAlarms 2026 \\
|
|
5
|
+
//=======================================\\
|
|
6
|
+
import * as Assert from "node:assert";
|
|
7
|
+
import {
|
|
8
|
+
checkPlain,
|
|
9
|
+
decommentJSON,
|
|
10
|
+
merge,
|
|
11
|
+
objectify,
|
|
12
|
+
pull,
|
|
13
|
+
pullAll,
|
|
14
|
+
replace,
|
|
15
|
+
replaceAll,
|
|
16
|
+
stringify,
|
|
17
|
+
stringifyArray,
|
|
18
|
+
stringifyJSON,
|
|
19
|
+
TRecord,
|
|
20
|
+
} from "./index.js";
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
console.log("Starting tests...");
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
//====================
|
|
27
|
+
// OBJECT UTILITIES
|
|
28
|
+
//====================
|
|
29
|
+
console.log("\n\nCATEGORY: Object Utilities");
|
|
30
|
+
|
|
31
|
+
//-----------------
|
|
32
|
+
// Merge objects
|
|
33
|
+
//-----------------
|
|
34
|
+
console.log("\nFUNCTION: merge()");
|
|
35
|
+
|
|
36
|
+
console.log("TEST 1: General functionality and object mutation");
|
|
37
|
+
const mrg11 = {
|
|
38
|
+
A: 1,
|
|
39
|
+
B: 2,
|
|
40
|
+
C: 3,
|
|
41
|
+
};
|
|
42
|
+
const mrg12 = {
|
|
43
|
+
A: 10,
|
|
44
|
+
D: 40,
|
|
45
|
+
E: 50,
|
|
46
|
+
};
|
|
47
|
+
const mrg13 = {
|
|
48
|
+
A: 100,
|
|
49
|
+
E: 500,
|
|
50
|
+
F: 600,
|
|
51
|
+
};
|
|
52
|
+
merge(mrg11, mrg12, mrg13);
|
|
53
|
+
Assert.deepStrictEqual(mrg11, {
|
|
54
|
+
A: 100,
|
|
55
|
+
B: 2,
|
|
56
|
+
C: 3,
|
|
57
|
+
D: 40,
|
|
58
|
+
E: 500,
|
|
59
|
+
F: 600,
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
console.log("TEST 2: Exclusions and array concatenation");
|
|
63
|
+
const mrg21 = {
|
|
64
|
+
A: 100,
|
|
65
|
+
B: new Date(-1000),
|
|
66
|
+
C: [0, 1, 2],
|
|
67
|
+
prototype: "I'm a prototype!",
|
|
68
|
+
};
|
|
69
|
+
const mrg22 = {
|
|
70
|
+
A: ():true => {
|
|
71
|
+
return true;
|
|
72
|
+
},
|
|
73
|
+
B: new Date(1000),
|
|
74
|
+
C: [3, 4, 5],
|
|
75
|
+
prototype: "I'm overwriting a prototype!",
|
|
76
|
+
[Symbol("Symbol")]: "I'm a symbol!",
|
|
77
|
+
};
|
|
78
|
+
merge(mrg21, mrg22);
|
|
79
|
+
Assert.deepStrictEqual(mrg21, {
|
|
80
|
+
A: 100,
|
|
81
|
+
B: mrg22.B,
|
|
82
|
+
C: [0, 1, 2, 3, 4, 5],
|
|
83
|
+
prototype: "I'm a prototype!",
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
//-------------------
|
|
88
|
+
// De-Comment JSON
|
|
89
|
+
//-------------------
|
|
90
|
+
console.log("\nFUNCTION: decommentJSON()");
|
|
91
|
+
|
|
92
|
+
console.log("TEST 1: Everything");
|
|
93
|
+
const dcm1 = `{
|
|
94
|
+
// "A" holds the number of apples.
|
|
95
|
+
"A": 10,
|
|
96
|
+
/* "B" holds the number of bananas.
|
|
97
|
+
Must be greater than 0. */
|
|
98
|
+
"B": 20,
|
|
99
|
+
/*
|
|
100
|
+
"C" holds the number of carrots.
|
|
101
|
+
Must be:
|
|
102
|
+
- An even number
|
|
103
|
+
- Divisible by 3
|
|
104
|
+
- Not divisible by 60
|
|
105
|
+
- The digits must no add up to 6
|
|
106
|
+
*/
|
|
107
|
+
"C": 30,
|
|
108
|
+
"D": "//This is not a JSON comment"
|
|
109
|
+
}`;
|
|
110
|
+
const dcm2 = JSON.parse(decommentJSON(dcm1));
|
|
111
|
+
Assert.deepStrictEqual(dcm2, {
|
|
112
|
+
A: 10,
|
|
113
|
+
B: 20,
|
|
114
|
+
C: 30,
|
|
115
|
+
D: "//This is not a JSON comment",
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
//---------------------------
|
|
120
|
+
// Check for plain objects
|
|
121
|
+
//---------------------------
|
|
122
|
+
console.log("\nFUNCTION: checkPlain()");
|
|
123
|
+
|
|
124
|
+
console.log("TEST 1: Everything");
|
|
125
|
+
const chk1 = [
|
|
126
|
+
checkPlain(new Date()),
|
|
127
|
+
checkPlain({}),
|
|
128
|
+
];
|
|
129
|
+
Assert.deepStrictEqual(chk1, [false, true]);
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
//===================
|
|
133
|
+
// ARRAY UTILITIES
|
|
134
|
+
//===================
|
|
135
|
+
console.log("\n\nCATEGORY: Array Utilities");
|
|
136
|
+
|
|
137
|
+
//-------------------
|
|
138
|
+
// Pull from array
|
|
139
|
+
//-------------------
|
|
140
|
+
console.log("\nFUNCTION: pull()");
|
|
141
|
+
|
|
142
|
+
console.log("TEST 1: Everything");
|
|
143
|
+
const pul1 = [10, 20, 30, 40, 50, 20];
|
|
144
|
+
pull(pul1, 20, 50);
|
|
145
|
+
Assert.deepStrictEqual(pul1, [10, 30, 40, 20]);
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
//------------
|
|
149
|
+
// Pull all
|
|
150
|
+
//------------
|
|
151
|
+
console.log("\nFUNCTION: pullAll()");
|
|
152
|
+
|
|
153
|
+
console.log("TEST 1: Everything");
|
|
154
|
+
const pul2 = [10, 20, 30, 40, 50, 20];
|
|
155
|
+
pullAll(pul2, 20, 50);
|
|
156
|
+
Assert.deepStrictEqual(pul2, [10, 30, 40]);
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
//--------------------
|
|
160
|
+
// Pull and replace
|
|
161
|
+
//--------------------
|
|
162
|
+
console.log("\nFUNCTION: replace()");
|
|
163
|
+
|
|
164
|
+
console.log("TEST 1: Everything");
|
|
165
|
+
const pul3 = [10, 20, 30, 40, 50, 20];
|
|
166
|
+
replace(pul3, 20, 60, 70);
|
|
167
|
+
Assert.deepStrictEqual(pul3, [10, 60, 70, 30, 40, 50, 20]);
|
|
168
|
+
|
|
169
|
+
|
|
170
|
+
//------------------------
|
|
171
|
+
// Pull and replace all
|
|
172
|
+
//------------------------
|
|
173
|
+
console.log("\nFUNCTION: replaceAll()");
|
|
174
|
+
|
|
175
|
+
console.log("TEST 1: Everything");
|
|
176
|
+
const pul4 = [10, 20, 30, 40, 50, 20];
|
|
177
|
+
replaceAll(pul4, 20, 60, 70);
|
|
178
|
+
Assert.deepStrictEqual(pul4, [10, 60, 70, 30, 40, 50, 60, 70]);
|
|
179
|
+
|
|
180
|
+
|
|
181
|
+
//--------------------
|
|
182
|
+
// Objectify arrays
|
|
183
|
+
//--------------------
|
|
184
|
+
console.log("\nFUNCTION: objectify()");
|
|
185
|
+
|
|
186
|
+
console.log("TEST 1: Everything");
|
|
187
|
+
const obj1 = ["zero", "one", "two", "three"];
|
|
188
|
+
const obj2 = objectify(obj1);
|
|
189
|
+
Assert.deepStrictEqual(obj2, {
|
|
190
|
+
0: "zero",
|
|
191
|
+
1: "one",
|
|
192
|
+
2: "two",
|
|
193
|
+
3: "three",
|
|
194
|
+
});
|
|
195
|
+
|
|
196
|
+
|
|
197
|
+
//====================
|
|
198
|
+
// STRINGIFY VALUES
|
|
199
|
+
//====================
|
|
200
|
+
console.log("\n\nCATEGORY: Stringify Values");
|
|
201
|
+
|
|
202
|
+
//---------------------
|
|
203
|
+
// General stringify
|
|
204
|
+
//---------------------
|
|
205
|
+
console.log("\nFUNCTION: stringify()");
|
|
206
|
+
|
|
207
|
+
console.log("TEST 1: General functionality with primitives");
|
|
208
|
+
const str1 = [
|
|
209
|
+
stringify("hello"),
|
|
210
|
+
stringify(100),
|
|
211
|
+
stringify(500n),
|
|
212
|
+
stringify(false),
|
|
213
|
+
stringify(Symbol("str")),
|
|
214
|
+
stringify(null),
|
|
215
|
+
stringify(undefined),
|
|
216
|
+
];
|
|
217
|
+
Assert.deepStrictEqual(str1, [
|
|
218
|
+
"hello",
|
|
219
|
+
"100",
|
|
220
|
+
"500n",
|
|
221
|
+
"false",
|
|
222
|
+
"Symbol(str)",
|
|
223
|
+
"null",
|
|
224
|
+
"undefined",
|
|
225
|
+
]);
|
|
226
|
+
|
|
227
|
+
console.log("TEST 2: Plain objects");
|
|
228
|
+
const str2 = [
|
|
229
|
+
stringify({}),
|
|
230
|
+
stringify({
|
|
231
|
+
A: 100,
|
|
232
|
+
B: {
|
|
233
|
+
C: 500,
|
|
234
|
+
},
|
|
235
|
+
}),
|
|
236
|
+
stringify({
|
|
237
|
+
A: 100,
|
|
238
|
+
toString: ():string => {
|
|
239
|
+
return "A is 100";
|
|
240
|
+
},
|
|
241
|
+
}),
|
|
242
|
+
stringify({
|
|
243
|
+
A: 100,
|
|
244
|
+
toString: "Not callable",
|
|
245
|
+
}),
|
|
246
|
+
stringify([1, 2, 3, 4, 5]),
|
|
247
|
+
];
|
|
248
|
+
const str3 = `{
|
|
249
|
+
"A": 100,
|
|
250
|
+
"B": {
|
|
251
|
+
"C": 500
|
|
252
|
+
}
|
|
253
|
+
}`;
|
|
254
|
+
const str4 = `{
|
|
255
|
+
"A": 100,
|
|
256
|
+
"toString": "Not callable"
|
|
257
|
+
}`;
|
|
258
|
+
const str5 = `[
|
|
259
|
+
1,
|
|
260
|
+
2,
|
|
261
|
+
3,
|
|
262
|
+
4,
|
|
263
|
+
5
|
|
264
|
+
]`;
|
|
265
|
+
Assert.deepStrictEqual(str2, [
|
|
266
|
+
"{}",
|
|
267
|
+
str3,
|
|
268
|
+
"A is 100",
|
|
269
|
+
str4,
|
|
270
|
+
str5,
|
|
271
|
+
]);
|
|
272
|
+
|
|
273
|
+
console.log("TEST 3: Object instances");
|
|
274
|
+
const str6 = new Date(0);
|
|
275
|
+
const str7 = [
|
|
276
|
+
stringify(str6),
|
|
277
|
+
stringify(new Error("Something went wrong!")),
|
|
278
|
+
stringify((new Set()).add("One")),
|
|
279
|
+
stringify((new Map()).set("1", "One")),
|
|
280
|
+
];
|
|
281
|
+
const str8 = `[
|
|
282
|
+
"One"
|
|
283
|
+
]`;
|
|
284
|
+
const str9 = `[
|
|
285
|
+
[
|
|
286
|
+
"1",
|
|
287
|
+
"One"
|
|
288
|
+
]
|
|
289
|
+
]`;
|
|
290
|
+
Assert.deepStrictEqual(str7, [
|
|
291
|
+
str6.toString(),
|
|
292
|
+
"Error: Something went wrong!",
|
|
293
|
+
str8,
|
|
294
|
+
str9,
|
|
295
|
+
]);
|
|
296
|
+
|
|
297
|
+
|
|
298
|
+
//------------------
|
|
299
|
+
// Stringify JSON
|
|
300
|
+
//------------------
|
|
301
|
+
console.log("\nFUNCTION: stringifyJSON()");
|
|
302
|
+
|
|
303
|
+
console.log("TEST 1: Everything");
|
|
304
|
+
const jsn1 = {
|
|
305
|
+
A: 1,
|
|
306
|
+
B: 2,
|
|
307
|
+
C: (new Set()).add("Ten"),
|
|
308
|
+
};
|
|
309
|
+
const jsn2 = {
|
|
310
|
+
A: 1,
|
|
311
|
+
B: 2,
|
|
312
|
+
C: {
|
|
313
|
+
A: 100n,
|
|
314
|
+
B: 2,
|
|
315
|
+
},
|
|
316
|
+
};
|
|
317
|
+
const jsn3:TRecord = {
|
|
318
|
+
D: jsn1,
|
|
319
|
+
E: jsn1,
|
|
320
|
+
};
|
|
321
|
+
jsn3.F = jsn3;
|
|
322
|
+
const jsn4 = {
|
|
323
|
+
jsn1: stringifyJSON(jsn1),
|
|
324
|
+
jsn2: stringifyJSON(jsn2, ">", ["A", "C.B"]),
|
|
325
|
+
jsn3: stringifyJSON(jsn3),
|
|
326
|
+
};
|
|
327
|
+
const jsn5 = `{
|
|
328
|
+
"A": 1,
|
|
329
|
+
"B": 2,
|
|
330
|
+
"C": [
|
|
331
|
+
"Ten"
|
|
332
|
+
]
|
|
333
|
+
}`;
|
|
334
|
+
const jsn6 = `{
|
|
335
|
+
>"B": 2,
|
|
336
|
+
>"C": {
|
|
337
|
+
>>"A": "100n"
|
|
338
|
+
>}
|
|
339
|
+
}`;
|
|
340
|
+
const jsn7 = `{
|
|
341
|
+
"D": {
|
|
342
|
+
"A": 1,
|
|
343
|
+
"B": 2,
|
|
344
|
+
"C": [
|
|
345
|
+
"Ten"
|
|
346
|
+
]
|
|
347
|
+
},
|
|
348
|
+
"E": "[Circular: D]",
|
|
349
|
+
"F": "[Circular: ~]"
|
|
350
|
+
}`;
|
|
351
|
+
Assert.deepStrictEqual(jsn4, {
|
|
352
|
+
jsn1: jsn5,
|
|
353
|
+
jsn2: jsn6,
|
|
354
|
+
jsn3: jsn7,
|
|
355
|
+
});
|
|
356
|
+
|
|
357
|
+
|
|
358
|
+
//----------------------------
|
|
359
|
+
// Stringify array elements
|
|
360
|
+
//----------------------------
|
|
361
|
+
console.log("\nFUNCTION: stringifyArray()");
|
|
362
|
+
|
|
363
|
+
console.log("TEST 1: Everything");
|
|
364
|
+
const arr1 = [null, 20, {}];
|
|
365
|
+
const arr2 = stringifyArray(arr1);
|
|
366
|
+
Assert.deepStrictEqual(arr2, ["null", "20", "{}"]);
|
package/tsconfig.json
ADDED