@suffolklitlab/alkiln 5.13.4 → 5.15.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/.github/workflows/github_server.yml +1 -1
- package/.github/workflows/playground.yml +2 -1
- package/.github/workflows/unit_tests.yml +1 -1
- package/CHANGELOG.md +40 -0
- package/action.yml +26 -10
- package/action_for_github_server/action.yml +31 -27
- package/docs/4_environments.md +2 -2
- package/docs/artifacts_folder_name.md +121 -71
- package/docs/constrained_random_tests.md +220 -289
- package/docs/decisions/move_runtime_config_to_sources_folder.md +3 -1
- package/docs/prioritize_constrained_random_tests.md +35 -76
- package/lib/docassemble/server_install.js +0 -2
- package/lib/docassemble/setup.js +1 -3
- package/lib/docassemble/takedown.js +2 -2
- package/lib/globals.js +10 -0
- package/lib/run_cucumber.js +40 -53
- package/lib/scope.js +44 -1
- package/lib/setup/TestGenerator.js +1757 -0
- package/lib/setup/artifacts.js +20 -0
- package/lib/setup/generate.js +42 -0
- package/lib/setup/get_Gherkin_AST.js +26 -0
- package/lib/setup/validate.js +89 -0
- package/lib/steps.js +101 -42
- package/lib/utils/Log.js +317 -165
- package/lib/utils/_alkiln-constrained_random_tests_old.js +1776 -0
- package/lib/utils/get_error_stacks.js +16 -0
- package/lib/utils/reports.js +44 -22
- package/lib/utils/session_vars.js +77 -57
- package/lib/utils/set_sources_paths.js +98 -0
- package/package.json +18 -7
- package/tests/log_codes/check_codes.sh +17 -13
- package/tests/log_codes/log_code_expected_instances.txt +58 -0
- package/tests/unit_tests/constrained_random_answers/invalid.fixtures.js +178 -0
- package/tests/unit_tests/constrained_random_answers/invalid.test.js +251 -0
- package/tests/unit_tests/constrained_random_answers/valid.fixtures.js +957 -0
- package/tests/unit_tests/constrained_random_answers/valid.test.js +563 -0
- package/tests/unit_tests/example_of_chai_test_lifecycle.js +78 -0
- package/tests/unit_tests/log.test.js +17 -41
- package/docs/seprate_file_generation_GitHub_action.md +0 -11
- package/lib/parse.js +0 -36
- package/lib/utils/get_sources_paths.js +0 -162
- package/lib/utils/parse.js +0 -1
- package/lib/utils/proccess_command_line_args.js +0 -267
- /package/docs/{expected_inernal_results.md → expected_internal_results.md} +0 -0
package/lib/utils/Log.js
CHANGED
|
@@ -4,15 +4,59 @@ const session_vars = require( `./session_vars` );
|
|
|
4
4
|
const time = require(`./time`);
|
|
5
5
|
const files = require(`./files`);
|
|
6
6
|
|
|
7
|
-
// ? 🌈 💡 🔎 🤕 🐛
|
|
8
|
-
// Alternatives: 🩹 ❤️🩹 🚑
|
|
7
|
+
// ? 🌈 💡 🔎 🤕 🐛 🖊️
|
|
8
|
+
// Alternatives: 🩹 ❤️🩹 🚑
|
|
9
9
|
|
|
10
10
|
/**
|
|
11
11
|
* Future issues:
|
|
12
|
-
* - [ ] Save logs from GitHub actions as well? Users can download them
|
|
13
|
-
*
|
|
14
|
-
* - [ ] Capture cucumber ProgressFormatter logs instead of making them
|
|
12
|
+
* - [ ] Save logs from GitHub actions as well? Users can download them
|
|
13
|
+
* themselves, but this might not be clear to them.
|
|
14
|
+
* - [ ] Capture cucumber ProgressFormatter logs instead of making them
|
|
15
|
+
* ourselves?
|
|
15
16
|
* - [ ] keeping report separate for now (can just be an issue to integrate)
|
|
17
|
+
* - [ ] Discuss: instead of logging above an error, manipulate the error
|
|
18
|
+
* message to prepend the accompanying log code, etc (all except the `before`
|
|
19
|
+
* prop). Before this, do UX research to see if the current format is as
|
|
20
|
+
* confusing to authors as it seems from this end.
|
|
21
|
+
* - [ ] Discuss: Should `.error()` return an Error? See discussion:
|
|
22
|
+
* https://github.com/SuffolkLITLab/ALKiln/discussions/988
|
|
23
|
+
* */
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Quick examples:
|
|
27
|
+
*
|
|
28
|
+
log.debug({ code: `ALK0%%%`, context: `unspecified context`,},
|
|
29
|
+
`The message`,
|
|
30
|
+
some_val
|
|
31
|
+
);
|
|
32
|
+
|
|
33
|
+
log.success({ code: `ALK0%%%`, context: `unspecified context`,},
|
|
34
|
+
`The message`,
|
|
35
|
+
some_val
|
|
36
|
+
);
|
|
37
|
+
log.info({ code: `ALK0%%%`, context: `unspecified context`,},
|
|
38
|
+
`The message`,
|
|
39
|
+
some_val
|
|
40
|
+
);
|
|
41
|
+
log.warn({ code: `ALK0%%%`, context: `unspecified context`,},
|
|
42
|
+
`The message`,
|
|
43
|
+
some_val
|
|
44
|
+
);
|
|
45
|
+
log.error({ code: `ALK0%%%`, context: `unspecified context`,},
|
|
46
|
+
`The message`,
|
|
47
|
+
some_val
|
|
48
|
+
);
|
|
49
|
+
log.throw({ code: `ALK0%%%`, context: `unspecified context`,
|
|
50
|
+
error: new Error(
|
|
51
|
+
`Error message`
|
|
52
|
+
),}
|
|
53
|
+
);
|
|
54
|
+
log.throw({ code: `ALK0%%%`, context: `unspecified context`,
|
|
55
|
+
error: new Error(
|
|
56
|
+
`Error message`
|
|
57
|
+
),},
|
|
58
|
+
`Additional message`
|
|
59
|
+
);
|
|
16
60
|
* */
|
|
17
61
|
|
|
18
62
|
class Log {
|
|
@@ -103,23 +147,96 @@ class Log {
|
|
|
103
147
|
* const log = new Log({ path: "_alkiln-123", context: "setup" });
|
|
104
148
|
* */
|
|
105
149
|
|
|
106
|
-
//
|
|
107
|
-
|
|
108
|
-
// Other processes, like ALKilnInThePlayground, don't have a path
|
|
109
|
-
else { path = files.make_artifacts_folder(); }
|
|
150
|
+
// These records help internal tests check for correct behavior
|
|
151
|
+
this.internal_log_records = [];
|
|
110
152
|
|
|
111
|
-
this.
|
|
153
|
+
let dir = path; // eventually, convert to this.dir instead of this.path
|
|
154
|
+
|
|
155
|
+
let is_new_folder = this._is_new_folder({ dir }).is_new;
|
|
156
|
+
this.path = this._make_or_get_folder({ dir }).dir;
|
|
157
|
+
// Discuss: Should making/saving the artifacts folder be hidden in here? If
|
|
158
|
+
// not, where should it be? `make_artifacts_folder` maybe...
|
|
112
159
|
session_vars.save_artifacts_path_name( this.path );
|
|
113
160
|
|
|
161
|
+
// Make sure `log` is in the logged context
|
|
162
|
+
if ( context ) { context = context + ` log`; }
|
|
163
|
+
else { context = `log`; }
|
|
164
|
+
let files_msg = `ALKiln will save test results files at "${ this.path }"`;
|
|
165
|
+
if ( is_new_folder ) {
|
|
166
|
+
this.info({ code: `ALK0214`, context, }, files_msg );
|
|
167
|
+
} else {
|
|
168
|
+
this.debug({ code: `ALK0277`, context, }, files_msg );
|
|
169
|
+
}
|
|
170
|
+
|
|
114
171
|
// Has this `Log` ever failed to append to the debug file?
|
|
115
172
|
this.fs_append_to_debug_file_failed = false;
|
|
116
173
|
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
this.
|
|
121
|
-
|
|
122
|
-
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
clear_internal_log_records() {
|
|
177
|
+
this.internal_log_records = [];
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
_is_new_folder({ dir }) {
|
|
181
|
+
/** Check if the artifacts folder is a new folder.
|
|
182
|
+
*
|
|
183
|
+
* @param {object} obj - Named arguments
|
|
184
|
+
* @param {undefined | str} obj.dir - A folder path or undefined
|
|
185
|
+
*
|
|
186
|
+
* @returns {{ is_new: bool, errors: [] | [Error] }} - Whether the folder
|
|
187
|
+
* previously existed (if yes, true) and a list of any Errors that
|
|
188
|
+
* happened
|
|
189
|
+
* */
|
|
190
|
+
let is_new = true;
|
|
191
|
+
try {
|
|
192
|
+
|
|
193
|
+
if ( dir ) {
|
|
194
|
+
if ( fs.existsSync( dir )) { is_new = false; }
|
|
195
|
+
} else if ( session_vars.get_artifacts_path_name() ) {
|
|
196
|
+
is_new = false;
|
|
197
|
+
}
|
|
198
|
+
return { is_new, errors: [] };
|
|
199
|
+
|
|
200
|
+
} catch ( folder_check_error ) {
|
|
201
|
+
return { is_new, errors: [ folder_check_error ]}
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
_make_or_get_folder({ dir }) {
|
|
206
|
+
/** Make a new folder for artifacts or get one that already exists.
|
|
207
|
+
*
|
|
208
|
+
* The chosen directory will be, in order of precedence, the `dir` value,
|
|
209
|
+
* an existing folder, or a completely new folder.
|
|
210
|
+
*
|
|
211
|
+
* @param {object} obj - Named arguments
|
|
212
|
+
* @param {undefined | str} obj.dir - Optional. Desired path to the
|
|
213
|
+
* artifacts folder.
|
|
214
|
+
*
|
|
215
|
+
* @returns { {dir: str, errors: [Error]} } Object with the given directory
|
|
216
|
+
* name and a list of 0 or more Error instances.
|
|
217
|
+
* */
|
|
218
|
+
try {
|
|
219
|
+
|
|
220
|
+
// GitHub actions pass in a dir, but other processes, like
|
|
221
|
+
// ALKilnInThePlayground, don't have a path
|
|
222
|
+
if ( !dir ) {
|
|
223
|
+
if ( session_vars.get_artifacts_path_name() ) {
|
|
224
|
+
dir = session_vars.get_artifacts_path_name();
|
|
225
|
+
} else {
|
|
226
|
+
dir = files.make_artifacts_folder();
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
if ( !fs.existsSync( dir )) {
|
|
231
|
+
files.make_artifacts_folder( dir );
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
return { dir, errors: [] };
|
|
235
|
+
|
|
236
|
+
} catch ( error_making_dir ) {
|
|
237
|
+
return { dir, errors: [ error_making_dir ]};
|
|
238
|
+
}
|
|
239
|
+
|
|
123
240
|
}
|
|
124
241
|
|
|
125
242
|
_console( console_opts = {}, ...logs ) {
|
|
@@ -128,7 +245,8 @@ class Log {
|
|
|
128
245
|
* takedown, run_cucumber (before and after running the tests), and API calls
|
|
129
246
|
* that interact with the server at those times. It writes to the console at
|
|
130
247
|
* different levels and throws errors. If it's not throwing a given error, it
|
|
131
|
-
* returns the combined metadata and the logs as a formatted string.
|
|
248
|
+
* returns the combined metadata and the logs as a formatted string. Only
|
|
249
|
+
* internal code should call this method.
|
|
132
250
|
*
|
|
133
251
|
* The `_console` method will:
|
|
134
252
|
* 1. Save the data to files with `log.debug()`
|
|
@@ -143,9 +261,12 @@ class Log {
|
|
|
143
261
|
* ┌───────────────────────────────────────┐
|
|
144
262
|
* │ ._console() │
|
|
145
263
|
* ├───────────────────────────────────────┤
|
|
146
|
-
*
|
|
147
|
-
*
|
|
148
|
-
* │
|
|
264
|
+
* all below ─┐ │ │
|
|
265
|
+
* ├────► .debug() (formatted logs str) │
|
|
266
|
+
* └────► get metadata string (all) │
|
|
267
|
+
* then... │ │
|
|
268
|
+
* │ │
|
|
269
|
+
* .throw() ──┐ │ │
|
|
149
270
|
* ├────► get safe Error │
|
|
150
271
|
* ├────► console.error() with extra info │
|
|
151
272
|
* └────► throw Error │
|
|
@@ -153,15 +274,17 @@ class Log {
|
|
|
153
274
|
* │ │ │
|
|
154
275
|
* .info() ──╘════► console.info() logs ════════════╗ │
|
|
155
276
|
* │ ║ │
|
|
156
|
-
* .warn() ───────► console.warn() logs
|
|
157
|
-
* │
|
|
277
|
+
* .warn() ───────► console.warn() logs───────┐ ║ │
|
|
278
|
+
* │ │ ║ │
|
|
279
|
+
* .error() ───────► console.error() logs───┐ │ ║ │
|
|
280
|
+
* │ ▼ ▼ ║ │
|
|
158
281
|
* │ return formatted logs string ◄══╝ │
|
|
159
282
|
* └───────────────────────────────────────┘
|
|
160
283
|
*
|
|
161
284
|
* @param { Object } console_opts - Required. Metadata and functional flags
|
|
162
|
-
* and data
|
|
163
|
-
* @param { success|info|warn|error } console_opts.level - Required.
|
|
164
|
-
* level. Functional and metadata. Defined by the internal caller.
|
|
285
|
+
* and data.
|
|
286
|
+
* @param { "success"|"info"|"warn"|"error" } console_opts.level - Required.
|
|
287
|
+
* The log level. Functional and metadata. Defined by the internal caller.
|
|
165
288
|
* @param { string } console_opts.before - Optional. Text to add before the
|
|
166
289
|
* metadata of the log. Metadata. Default "".
|
|
167
290
|
* @param { string } console_opts.icon - Required. Unicode char put at the
|
|
@@ -172,18 +295,14 @@ class Log {
|
|
|
172
295
|
* @param { string } console_opts.context - Optional. Info about the context
|
|
173
296
|
* where the log was called. Metadata. Examples: "setup", "run",
|
|
174
297
|
* "takedown". Default "". Defined by the original caller.
|
|
175
|
-
* @param { Error|any } console_opts.error - Optional.
|
|
176
|
-
* `do_throw`
|
|
177
|
-
*
|
|
178
|
-
*
|
|
179
|
-
* instance of Error. Otherwise, the stack trace will include this
|
|
180
|
-
* function, which is confusing. Avoid that. Default `undefined`. Defined
|
|
181
|
-
* by the original caller.
|
|
298
|
+
* @param { Error|any } console_opts.error - Optional. The error or data to
|
|
299
|
+
* eventually throw if `do_throw` is `true`, like with `.throw()`.
|
|
300
|
+
* Otherwise, just another log. It will keep its original stack trace.
|
|
301
|
+
* Default is `undefined`. Defined by the original caller.
|
|
182
302
|
* @param { boolean } console_opts.do_throw - Optional. If `true` caller wants
|
|
183
|
-
* to throw an error
|
|
184
|
-
* caller.
|
|
303
|
+
* to throw an error. Default `false`. Defined by the internal caller.
|
|
185
304
|
* @param { ...any } logs - Optional. The logs to write to the console. Joined
|
|
186
|
-
* by " " or "\n" depending on the type of the log. Default `
|
|
305
|
+
* by " " or "\n" depending on the type of the log. Default becomes `[]`.
|
|
187
306
|
* Defined by the original caller.
|
|
188
307
|
*
|
|
189
308
|
* @returns { string } Formatted metadata, logs, and, if given, the error.
|
|
@@ -243,44 +362,46 @@ class Log {
|
|
|
243
362
|
error, // Sometimes undefined
|
|
244
363
|
do_throw = false, // Sometimes undefined
|
|
245
364
|
} = console_opts;
|
|
365
|
+
logs = logs || [];
|
|
366
|
+
|
|
367
|
+
if ( do_throw || error !== undefined ) {
|
|
368
|
+
error = this._get_Error_safely({ maybe_error: error });
|
|
369
|
+
}
|
|
246
370
|
|
|
247
|
-
let formatted_str_to_return = this.debug({
|
|
371
|
+
let formatted_str_to_return = this.debug({
|
|
372
|
+
level, before, icon, code, context, error, do_throw,
|
|
373
|
+
}, ...logs );
|
|
248
374
|
|
|
249
375
|
let metadata_str = this._format_metadata({ level, icon, code, context });
|
|
250
376
|
|
|
251
377
|
// Throw whatever we can throw
|
|
252
378
|
if ( do_throw ) {
|
|
253
|
-
|
|
254
|
-
//
|
|
255
|
-
// get logged here before catching will be confusing.
|
|
379
|
+
// WARNING: If someone catches the error we throw, these strings will get
|
|
380
|
+
// logged. The final resulting logs may become confusing.
|
|
256
381
|
try {
|
|
257
|
-
|
|
258
|
-
console.error( `${before}${metadata_str}:`, ...logs );
|
|
382
|
+
console.error( `\n\n\n${before}${metadata_str}:`, ...logs );
|
|
259
383
|
} catch ( pre_throw_error ) {
|
|
260
384
|
this.debug({
|
|
261
385
|
icon: `🖊️`, code: `ALK0215`, context: `internal log`, level: `note`,
|
|
262
386
|
}, `Skipped logging metadata before throwing the error`, pre_throw_error );
|
|
263
387
|
}
|
|
264
388
|
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
// call stack gets created at this point.
|
|
270
|
-
// Discuss: Should we include the metadata in this error since we don't
|
|
271
|
-
// need to preserve a stack trace? That's inconsistent, though.
|
|
272
|
-
throw new Error( error );
|
|
273
|
-
}
|
|
389
|
+
// Readers will see this text in the console, so give a clarifying name
|
|
390
|
+
let error_from_alkiln = error;
|
|
391
|
+
// ALKiln threw an error when preparing, cleaning up, or running the tests
|
|
392
|
+
throw error_from_alkiln;
|
|
274
393
|
}
|
|
275
394
|
|
|
276
395
|
// Avoid using custom-formatted logs and error here.
|
|
277
396
|
// Let the console show them as it wants.
|
|
278
397
|
try {
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
// default
|
|
398
|
+
|
|
399
|
+
let combined = this._combined_logs_and_error({ logs, error, do_throw });
|
|
400
|
+
// log at the given level if console has that method (`log` by default
|
|
401
|
+
// from ._console). If a non-standard level, like `success`, was passed in
|
|
402
|
+
// use `info` by default.
|
|
282
403
|
if ( !console[ level ]) { level = `info`; }
|
|
283
|
-
console[ level ]( `${before}${metadata_str}:`, ...
|
|
404
|
+
console[ level ]( `${before}${metadata_str}:`, ...combined );
|
|
284
405
|
|
|
285
406
|
} catch ( console_log_error ) {
|
|
286
407
|
// Fail silently
|
|
@@ -298,15 +419,28 @@ class Log {
|
|
|
298
419
|
* Returns a formatted string version of the log with its metadata. Avoids
|
|
299
420
|
* throwing internal errors while giving the max info possible. Avoids
|
|
300
421
|
* writing to the visible console. Every log should come through here.
|
|
422
|
+
* External code can call this method.
|
|
301
423
|
*
|
|
302
424
|
* Tries to make saved logs look as similar as possible to console logs.
|
|
303
425
|
*
|
|
304
|
-
*
|
|
305
|
-
*
|
|
306
|
-
*
|
|
307
|
-
*
|
|
308
|
-
*
|
|
309
|
-
*
|
|
426
|
+
* @param { Object } console_opts - Required. Metadata and functional flags
|
|
427
|
+
* and data.
|
|
428
|
+
* @param { "success"|"info"|"warn"|"error" } console_opts.level - Required.
|
|
429
|
+
* The log level. Functional and metadata. Defined by the internal
|
|
430
|
+
* caller.
|
|
431
|
+
* @param { string } console_opts.before - Optional. Text to add before the
|
|
432
|
+
* metadata of the log. Metadata. Default "".
|
|
433
|
+
* @param { string } console_opts.icon - Required. Unicode char put at the
|
|
434
|
+
* start of metadata. Makes the level more easy to see quickly. Defined
|
|
435
|
+
* by the internal caller.
|
|
436
|
+
* @param { string } console_opts.code - Required. Unique consecutive log id
|
|
437
|
+
* with the format ALK####. Defined by the original caller.
|
|
438
|
+
* @param { string } console_opts.context - Optional. Info about the context
|
|
439
|
+
* where the log was called. Metadata. Examples: "setup", "run",
|
|
440
|
+
* "takedown". Default "". Defined by the original caller.
|
|
441
|
+
* @param { ...any } logs - Optional. The logs to write to the console.
|
|
442
|
+
* Joined by " " or "\n" depending on the type of the log. Default
|
|
443
|
+
* becomes `[]`. Defined by the original caller.
|
|
310
444
|
*
|
|
311
445
|
* @returns { string } Same as `._console()`
|
|
312
446
|
*
|
|
@@ -333,9 +467,12 @@ class Log {
|
|
|
333
467
|
icon = `🐛`,
|
|
334
468
|
code = `ALK000d`,
|
|
335
469
|
context = ``,
|
|
336
|
-
error,
|
|
470
|
+
error,
|
|
337
471
|
do_throw = false,
|
|
338
472
|
} = debug_opts;
|
|
473
|
+
logs = logs || [];
|
|
474
|
+
|
|
475
|
+
this.internal_log_records.push({ opts: debug_opts, logs });
|
|
339
476
|
|
|
340
477
|
// "warning" level and icon for for internal devs we use to avoid disrupting
|
|
341
478
|
// the info authors are looking for
|
|
@@ -351,17 +488,13 @@ class Log {
|
|
|
351
488
|
let logging_errors_msgs = [];
|
|
352
489
|
try {
|
|
353
490
|
|
|
354
|
-
|
|
355
|
-
// results logs
|
|
356
|
-
let with_error = this._combine_logs_and_possible_error({
|
|
357
|
-
logs, maybe_error: error, do_throw,
|
|
358
|
-
});
|
|
359
|
-
|
|
360
|
-
let stringified = this._stringify_logs( ...with_error );
|
|
491
|
+
let combined = this._combined_logs_and_error({ logs, error, do_throw });
|
|
361
492
|
|
|
493
|
+
let stringified = this._stringify_logs( ...combined );
|
|
362
494
|
// Question: Does `formatted` double log the error in the console?
|
|
363
495
|
// Answer: `._console` doesn't use `formatted`, just returns it.
|
|
364
496
|
formatted = `${ before }${ metadata_str }: ${ stringified }`;
|
|
497
|
+
|
|
365
498
|
} catch ( formatted_log_error ) {
|
|
366
499
|
formatted = `🖊️ ALK0212 internal debug NOTE [${ Date.now() }]: Skipped formatting debug logs.`;
|
|
367
500
|
this._save_to_debug_safely({ unexpected: true, text: formatted });
|
|
@@ -491,31 +624,28 @@ class Log {
|
|
|
491
624
|
} // Ends Log._stringify_logs()
|
|
492
625
|
|
|
493
626
|
_stringify_inline({ prev_line_type, inline_log }) {
|
|
494
|
-
/** Formats the
|
|
495
|
-
*
|
|
627
|
+
/** Formats the log to add a space or a new line separator. May end up with
|
|
628
|
+
* a leading space for now.
|
|
496
629
|
*
|
|
497
630
|
* @param { "inline"|"block"|null } prev_line_type - Required. The type of
|
|
498
631
|
* the previous log.
|
|
499
632
|
* @param { null|non-obj } inline_log - Required. The log.
|
|
500
633
|
*
|
|
501
|
-
* @returns { string } The formatted
|
|
634
|
+
* @returns { string } The formatted line.
|
|
502
635
|
*
|
|
503
636
|
* @example
|
|
504
637
|
* // Backticks are to make the surrounding white space more clear
|
|
505
638
|
* log._stringify_inline({ prev_line_type: null, inline_log: "apple" });
|
|
506
|
-
* //
|
|
639
|
+
* // "apple "
|
|
507
640
|
* log._stringify_inline({ prev_line_type: 'inline', inline_log: "apple" });
|
|
508
|
-
* //
|
|
641
|
+
* // "apple "
|
|
509
642
|
* log._stringify_inline({ prev_line_type: 'block', inline_log: "apple" });
|
|
510
|
-
* //
|
|
511
|
-
* // apple
|
|
643
|
+
* // "
|
|
644
|
+
* // apple"
|
|
512
645
|
* */
|
|
513
|
-
// An inline log's string starts with nothing if it's the first string...
|
|
514
646
|
let start = ``;
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
// ...or starts on a new line if it's after a block of text, like an error
|
|
518
|
-
// or object.
|
|
647
|
+
if ( prev_line_type === `inline` && !inline_log.startsWith(`\n`) ) { start = ` `; }
|
|
648
|
+
// This is actually the end of the block-type log
|
|
519
649
|
else if ( prev_line_type === `block` ) { start = `\n`; }
|
|
520
650
|
return `${ start }${ inline_log }`;
|
|
521
651
|
}
|
|
@@ -525,6 +655,8 @@ class Log {
|
|
|
525
655
|
* a "block"-type separator at the start. Can handle circular references.
|
|
526
656
|
* Catch ANY error.
|
|
527
657
|
*
|
|
658
|
+
* @param { "inline"|"block"|null } prev_line_type - Required. The type of
|
|
659
|
+
* the previous log.
|
|
528
660
|
* @param { Object } obj_log - Required. The object to format.
|
|
529
661
|
*
|
|
530
662
|
* @returns { string } The obj as a string plus a separator
|
|
@@ -536,15 +668,15 @@ class Log {
|
|
|
536
668
|
* // { fruit: 'bananas' }
|
|
537
669
|
* */
|
|
538
670
|
let start = ``;
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
}
|
|
671
|
+
// Avoid adding a new line to the start of the first line
|
|
672
|
+
let is_first_line = prev_line_type === null;
|
|
673
|
+
if ( !is_first_line ) { start = `\n`; }
|
|
542
674
|
|
|
543
675
|
try {
|
|
544
676
|
// Try to stringify the object.
|
|
545
677
|
return `${ start }${ this._inspect({ value: obj_log }) }`;
|
|
546
678
|
|
|
547
|
-
// Discuss: record
|
|
679
|
+
// Discuss: record the outer error?
|
|
548
680
|
} catch ( outer_error ) {
|
|
549
681
|
// If that fails, see if it has its own way of stringifying
|
|
550
682
|
try {
|
|
@@ -556,48 +688,29 @@ class Log {
|
|
|
556
688
|
} // ends outer try
|
|
557
689
|
}
|
|
558
690
|
|
|
559
|
-
|
|
560
|
-
/**
|
|
561
|
-
*
|
|
562
|
-
*
|
|
563
|
-
* @param {
|
|
564
|
-
*
|
|
565
|
-
*
|
|
566
|
-
* @param { Error|
|
|
567
|
-
* `undefined`.
|
|
568
|
-
*
|
|
569
|
-
*
|
|
570
|
-
*
|
|
571
|
-
* @
|
|
572
|
-
*
|
|
573
|
-
* @example
|
|
574
|
-
* let with_error = log._combine_logs_and_possible_error({
|
|
575
|
-
* [ "a", "b" ], do_throw: true, maybe_error: "A string."
|
|
576
|
-
* });
|
|
577
|
-
* // [ "a", "b", <An error with its stack and the message "A string."> ]
|
|
578
|
-
* @example
|
|
579
|
-
* let with_error = log._combine_logs_and_possible_error({
|
|
580
|
-
* [ "a", "b" ], do_throw: false, maybe_error: new Error("An error.")
|
|
581
|
-
* });
|
|
582
|
-
* // [ "a", "b" ]
|
|
691
|
+
_combined_logs_and_error({ logs=[], error, do_throw=false }) {
|
|
692
|
+
/** Return a list of the given logs combined with the given error, if it
|
|
693
|
+
* exists, ensuring the error is an Error.
|
|
694
|
+
*
|
|
695
|
+
* @param { ...any } logs - Optional. The logs to write to the console.
|
|
696
|
+
* Joined by " " or "\n" depending on the type of the log. Default
|
|
697
|
+
* becomes `[]`. Defined by the original caller.
|
|
698
|
+
* @param { Error|any } console_opts.error - Optional. Any. Default is
|
|
699
|
+
* `undefined`. Defined by the original caller.
|
|
700
|
+
* @param { boolean } console_opts.do_throw - Optional. If `true` caller wants
|
|
701
|
+
* to throw an error. Default `false`. Defined by the internal caller.
|
|
702
|
+
*
|
|
703
|
+
* @return [ any ] - List of logs, potentially with an added error
|
|
704
|
+
*
|
|
583
705
|
* */
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
// If we're supposed to throw, make sure the error gets an Error value.
|
|
587
|
-
if ( do_throw ) {
|
|
588
|
-
combined.push( this._get_Error_safely({ maybe_error }) );
|
|
589
|
-
|
|
590
|
-
// Otherwise error should be `undefined`. If not, we get a warning.
|
|
591
|
-
} else if ( maybe_error !== undefined ) {
|
|
592
|
-
this._save_to_debug_safely({ unexpected: true, text: `🖊️ ALK0223 internal debug NOTE [${ Date.now() }]: Only logs that throw should give a value to \`error\`. Skipping the value.` });
|
|
593
|
-
}
|
|
594
|
-
} catch ( combining_error_error ) {
|
|
595
|
-
this._save_to_debug_safely({ unexpected: true, text: `🖊️ ALK0226 internal debug NOTE [${ Date.now() }]: Skipped combining the logs.` });
|
|
596
|
-
this._save_to_debug_safely({ unexpected: true, text: combining_error_error.stack });
|
|
706
|
+
if ( do_throw || error !== undefined ) {
|
|
707
|
+
error = this._get_Error_safely({ maybe_error: error });
|
|
597
708
|
}
|
|
709
|
+
let logs_maybe_with_error = [ ...logs ];
|
|
710
|
+
if ( error !== undefined ) { logs_maybe_with_error.push( error ); }
|
|
598
711
|
|
|
599
|
-
return
|
|
600
|
-
}
|
|
712
|
+
return logs_maybe_with_error;
|
|
713
|
+
}
|
|
601
714
|
|
|
602
715
|
_get_Error_safely({ maybe_error }) {
|
|
603
716
|
/** Given anything, return an Error. Avoid throwing any errors.
|
|
@@ -605,17 +718,28 @@ class Log {
|
|
|
605
718
|
* @param { Object } opts
|
|
606
719
|
* @param { * } opts.maybe_error - Optional. Can be anything.
|
|
607
720
|
*
|
|
608
|
-
* @returns { Error }
|
|
721
|
+
* @returns { Error|undefined }
|
|
609
722
|
* */
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
723
|
+
try {
|
|
724
|
+
|
|
725
|
+
if ( maybe_error instanceof Error ) {
|
|
726
|
+
return maybe_error;
|
|
727
|
+
} else if ( maybe_error ) {
|
|
728
|
+
|
|
729
|
+
if ( this._json_does_error( maybe_error )) {
|
|
730
|
+
maybe_error = this._get_inspected_val_safely( maybe_error );
|
|
731
|
+
}
|
|
732
|
+
|
|
733
|
+
let error_from_alkiln = maybe_error; // clearer name
|
|
734
|
+
|
|
735
|
+
// The stack trace `new Error()` creates here will be less helpful, but
|
|
736
|
+
// it's all we can do if the caller hasn't already created the error.
|
|
737
|
+
return new Error( error_from_alkiln );
|
|
738
|
+
|
|
615
739
|
}
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
740
|
+
} catch ( get_safe_error_error ) {
|
|
741
|
+
this._save_to_debug_safely({ unexpected: true, text: `🖊️ ALK0226 internal debug NOTE [${ Date.now() }]: Skipped combining the logs.` });
|
|
742
|
+
this._save_to_debug_safely({ unexpected: true, text: get_safe_error_error.stack });
|
|
619
743
|
}
|
|
620
744
|
}
|
|
621
745
|
|
|
@@ -681,7 +805,7 @@ class Log {
|
|
|
681
805
|
* @param logs { ...string } - Optional. Default is `undefined`. Explanation
|
|
682
806
|
* of what happened.
|
|
683
807
|
*
|
|
684
|
-
* @returns { string } Formatted metadata
|
|
808
|
+
* @returns { string } Formatted metadata and logs.
|
|
685
809
|
*
|
|
686
810
|
* @example
|
|
687
811
|
* log.warn({
|
|
@@ -693,13 +817,11 @@ class Log {
|
|
|
693
817
|
* */
|
|
694
818
|
// Discuss: do we want to log some successes as "💡 ... SUCCESS: " for
|
|
695
819
|
// smaller successful operations along the way?
|
|
696
|
-
let {
|
|
697
|
-
code = `ALK000s`, before = ``, context = ``
|
|
698
|
-
} = success_opts;
|
|
699
820
|
return this._console({
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
821
|
+
code: `ALK000s`,
|
|
822
|
+
...success_opts,
|
|
823
|
+
level: `success`, icon: `🌈`, do_throw: false,
|
|
824
|
+
}, ...logs );
|
|
703
825
|
}
|
|
704
826
|
|
|
705
827
|
info( info_opts = {}, ...logs ) {
|
|
@@ -717,7 +839,7 @@ class Log {
|
|
|
717
839
|
* @param logs { ...string } - Optional. Default is `undefined`. Explanation
|
|
718
840
|
* of what happened.
|
|
719
841
|
*
|
|
720
|
-
* @returns { string } Formatted metadata
|
|
842
|
+
* @returns { string } Formatted metadata and logs.
|
|
721
843
|
*
|
|
722
844
|
* @example
|
|
723
845
|
* log.warn({
|
|
@@ -727,13 +849,11 @@ class Log {
|
|
|
727
849
|
* }, "demo log");
|
|
728
850
|
* // ~~~💡 ALK00d4 demo INFO [2024-08-16 00:30:39UTC]: demo log
|
|
729
851
|
* */
|
|
730
|
-
let {
|
|
731
|
-
code = `ALK000i`, before = ``, context = ``,
|
|
732
|
-
} = info_opts;
|
|
733
852
|
return this._console({
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
853
|
+
code: `ALK000i`,
|
|
854
|
+
...info_opts,
|
|
855
|
+
level: `info`, icon: `💡`, do_throw: false,
|
|
856
|
+
}, ...logs );
|
|
737
857
|
}
|
|
738
858
|
|
|
739
859
|
warn( warning_opts = {}, ...logs ) {
|
|
@@ -751,7 +871,7 @@ class Log {
|
|
|
751
871
|
* @param logs { ...string } - Optional. Default is `undefined`. Explanation
|
|
752
872
|
* of what happened.
|
|
753
873
|
*
|
|
754
|
-
* @returns { string } Formatted metadata
|
|
874
|
+
* @returns { string } Formatted metadata and logs.
|
|
755
875
|
*
|
|
756
876
|
* @example
|
|
757
877
|
* log.warn({
|
|
@@ -761,13 +881,47 @@ class Log {
|
|
|
761
881
|
* }, "demo log");
|
|
762
882
|
* // ~~~🔎 ALK00d5 demo WARNING [2024-08-16 00:30:39UTC]: demo log
|
|
763
883
|
* */
|
|
764
|
-
let {
|
|
765
|
-
code = `ALK000w`, before = ``, context = ``
|
|
766
|
-
} = warning_opts;
|
|
767
884
|
return this._console({
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
885
|
+
code: `ALK000w`,
|
|
886
|
+
...warning_opts,
|
|
887
|
+
level: `warn`, icon: `🔎`, do_throw: false,
|
|
888
|
+
}, ...logs );
|
|
889
|
+
}
|
|
890
|
+
|
|
891
|
+
error( error_opts = {}, ...logs ) {
|
|
892
|
+
/** Log errors (messages with the error icon) to the console using
|
|
893
|
+
* additional metadata and the given logs. Use it in ALKlin test suite
|
|
894
|
+
* wrapper functionality, like setup and takedown.
|
|
895
|
+
*
|
|
896
|
+
* @param { Object } error_opts
|
|
897
|
+
* @param { string } error_opts.code - Required. Unique log id of the
|
|
898
|
+
* format "ALK####", where "#" is a digit.
|
|
899
|
+
* @param { string } error_opts.before - Optional. Default is `""`.
|
|
900
|
+
* Decoration to log before the metadata.
|
|
901
|
+
* @param { string } error_opts.context - Optional. Default is `""`. Info
|
|
902
|
+
* about the origin of the logs.
|
|
903
|
+
* @param { ...string } logs - Optional. Default is `undefined`. Explanation
|
|
904
|
+
* of what happened.
|
|
905
|
+
* @param { Error|any } error_opts.error - Default is `undefined`.
|
|
906
|
+
* `.error()` treats this like an item in `logs` since `.error()`
|
|
907
|
+
* doesn't throw.
|
|
908
|
+
*
|
|
909
|
+
* @returns { string } Formatted metadata, logs, and, if given, the error.
|
|
910
|
+
*
|
|
911
|
+
* @example
|
|
912
|
+
* log.warn({
|
|
913
|
+
* before: "~~~",
|
|
914
|
+
* code: "ALK00d5",
|
|
915
|
+
* context: "demo",
|
|
916
|
+
* error:
|
|
917
|
+
* }, "demo log");
|
|
918
|
+
* // ~~~🤕 ALK00d5 demo WARNING [2024-08-16 00:30:39UTC]: demo log
|
|
919
|
+
* */
|
|
920
|
+
return this._console({
|
|
921
|
+
code: `ALK000e`,
|
|
922
|
+
...error_opts,
|
|
923
|
+
level: `error`, icon: `🤕`, do_throw: false,
|
|
924
|
+
}, ...logs );
|
|
771
925
|
}
|
|
772
926
|
|
|
773
927
|
throw( throw_opts = {}, ...logs ){
|
|
@@ -807,14 +961,11 @@ class Log {
|
|
|
807
961
|
* // Uncaught ReferenceError: undefined_value is not defined
|
|
808
962
|
* // <the stack trace>
|
|
809
963
|
* */
|
|
810
|
-
let {
|
|
811
|
-
code = `ALK000t`, before = ``, context = ``, error = `ALKiln default error`,
|
|
812
|
-
} = throw_opts;
|
|
813
|
-
|
|
814
964
|
this._console({
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
965
|
+
code: `ALK000t`, error: new Error(`ALKiln default error`),
|
|
966
|
+
...throw_opts,
|
|
967
|
+
do_throw: true, level: `error`, icon: `🤕`,
|
|
968
|
+
}, ...logs );
|
|
818
969
|
}
|
|
819
970
|
|
|
820
971
|
_save_to_debug_safely( save_debug_opts = {} ) {
|
|
@@ -962,18 +1113,19 @@ class Log {
|
|
|
962
1113
|
}
|
|
963
1114
|
|
|
964
1115
|
clear() {
|
|
965
|
-
/** Empty all files possible without deleting them.
|
|
1116
|
+
/** Empty all files possible without deleting them. Never throw. This is
|
|
1117
|
+
* nice to have, but not crucial.
|
|
966
1118
|
*
|
|
967
1119
|
* @returns { Log } Self.
|
|
968
1120
|
* */
|
|
969
1121
|
try { fs.writeFileSync( `${ this.path }/${ this.debug_log_filename }`, `` ); }
|
|
970
|
-
catch (error) {
|
|
1122
|
+
catch (error) {}
|
|
971
1123
|
try { fs.writeFileSync( `${ this.path }/${ this.report_log_filename }`, `` ); }
|
|
972
|
-
catch (error) {
|
|
1124
|
+
catch (error) {}
|
|
973
1125
|
try { fs.writeFileSync( `${ this.path }/${ this.report_filename }`, `` ); }
|
|
974
|
-
catch (error) {
|
|
1126
|
+
catch (error) {}
|
|
975
1127
|
try { fs.writeFileSync( `${ this.path }/${ this.unexpected_filename }`, `` ); }
|
|
976
|
-
catch (error) {
|
|
1128
|
+
catch (error) {}
|
|
977
1129
|
return this;
|
|
978
1130
|
}
|
|
979
1131
|
|