@faasjs/node-utils 8.0.0-beta.8 → 8.0.0-beta.9
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 +17 -0
- package/dist/index.cjs +882 -38
- package/dist/index.d.ts +250 -5
- package/dist/index.mjs +875 -38
- package/package.json +14 -25
package/dist/index.cjs
CHANGED
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
2
2
|
let node_fs = require("node:fs");
|
|
3
3
|
let node_path = require("node:path");
|
|
4
|
-
let _faasjs_logger = require("@faasjs/logger");
|
|
5
|
-
let js_yaml = require("js-yaml");
|
|
6
4
|
|
|
7
5
|
//#region src/deep_merge.ts
|
|
8
6
|
const shouldMerge = (item) => {
|
|
@@ -24,21 +22,861 @@ const shouldMerge = (item) => {
|
|
|
24
22
|
*/
|
|
25
23
|
function deepMerge(...sources) {
|
|
26
24
|
let acc = Object.create(null);
|
|
27
|
-
for (const source of sources)
|
|
28
|
-
if (
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
acc = {
|
|
25
|
+
for (const source of sources) {
|
|
26
|
+
if (Array.isArray(source)) {
|
|
27
|
+
if (!Array.isArray(acc)) acc = [];
|
|
28
|
+
acc = [...new Set(source.concat(...acc))];
|
|
29
|
+
continue;
|
|
30
|
+
}
|
|
31
|
+
if (!shouldMerge(source)) continue;
|
|
32
|
+
for (const [key, value] of Object.entries(source)) acc = {
|
|
35
33
|
...acc,
|
|
36
|
-
[key]:
|
|
34
|
+
[key]: shouldMerge(value) ? deepMerge(acc[key], value) : value
|
|
37
35
|
};
|
|
38
36
|
}
|
|
39
37
|
return acc;
|
|
40
38
|
}
|
|
41
39
|
|
|
40
|
+
//#endregion
|
|
41
|
+
//#region src/color.ts
|
|
42
|
+
const Color = {
|
|
43
|
+
DEFAULT: 39,
|
|
44
|
+
BLACK: 30,
|
|
45
|
+
RED: 31,
|
|
46
|
+
GREEN: 32,
|
|
47
|
+
ORANGE: 33,
|
|
48
|
+
BLUE: 34,
|
|
49
|
+
MAGENTA: 35,
|
|
50
|
+
CYAN: 36,
|
|
51
|
+
GRAY: 90
|
|
52
|
+
};
|
|
53
|
+
const LevelColor = {
|
|
54
|
+
debug: Color.GRAY,
|
|
55
|
+
info: Color.GREEN,
|
|
56
|
+
warn: Color.ORANGE,
|
|
57
|
+
error: Color.RED
|
|
58
|
+
};
|
|
59
|
+
/**
|
|
60
|
+
* Apply ANSI color codes to a message based on the log level.
|
|
61
|
+
*
|
|
62
|
+
* @param level - The log level to determine the color.
|
|
63
|
+
* @param message - The message to be colorized.
|
|
64
|
+
* @returns The colorized message string.
|
|
65
|
+
*/
|
|
66
|
+
function colorfy(level, message) {
|
|
67
|
+
return `\u001b[0${LevelColor[level]}m${message}\u001b[39m`;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
//#endregion
|
|
71
|
+
//#region src/format.ts
|
|
72
|
+
/**
|
|
73
|
+
* Formats a string using placeholders and arguments.
|
|
74
|
+
*
|
|
75
|
+
* The function supports the following placeholders:
|
|
76
|
+
* - `%o`: Formats the argument as a JSON string if it's an array, otherwise falls through to `%s`.
|
|
77
|
+
* - `%s`: Converts the argument to a string.
|
|
78
|
+
* - `%d`: Converts the argument to a number.
|
|
79
|
+
* - `%j`: Formats the argument as a JSON string.
|
|
80
|
+
*/
|
|
81
|
+
function format(fmt, ...args) {
|
|
82
|
+
const re = /(%?)(%([ojds]))/g;
|
|
83
|
+
let fmtString;
|
|
84
|
+
if (typeof fmt !== "string") if (fmt instanceof Error) fmtString = `Error: ${fmt.message}\n${fmt.stack}`;
|
|
85
|
+
else if (fmt instanceof Object) fmtString = JSON.stringify(fmt);
|
|
86
|
+
else fmtString = String(fmt);
|
|
87
|
+
else fmtString = fmt;
|
|
88
|
+
if (args.length) fmtString = fmtString.replace(re, (match, escaped, _, flag) => {
|
|
89
|
+
let arg = args.shift();
|
|
90
|
+
switch (flag) {
|
|
91
|
+
case "o": if (Array.isArray(arg)) {
|
|
92
|
+
arg = JSON.stringify(arg);
|
|
93
|
+
break;
|
|
94
|
+
}
|
|
95
|
+
case "s":
|
|
96
|
+
arg = `${arg}`;
|
|
97
|
+
break;
|
|
98
|
+
case "d":
|
|
99
|
+
arg = Number(arg);
|
|
100
|
+
break;
|
|
101
|
+
case "j":
|
|
102
|
+
arg = JSON.stringify(arg);
|
|
103
|
+
break;
|
|
104
|
+
}
|
|
105
|
+
if (!escaped) return arg;
|
|
106
|
+
args.unshift(arg);
|
|
107
|
+
return match;
|
|
108
|
+
});
|
|
109
|
+
if (args.length) fmtString += ` ${args.join(" ")}`;
|
|
110
|
+
fmtString = fmtString.replace(/%{2,2}/g, "%");
|
|
111
|
+
return fmtString;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
//#endregion
|
|
115
|
+
//#region src/transport.ts
|
|
116
|
+
/**
|
|
117
|
+
* The transport class that manages the transport handlers and log messages.
|
|
118
|
+
*
|
|
119
|
+
* **Note: This class is not meant to be used directly. Use the {@link getTransport} instead.**
|
|
120
|
+
*
|
|
121
|
+
* @example
|
|
122
|
+
* ```typescript
|
|
123
|
+
* import { getTransport } from '@faasjs/node-utils'
|
|
124
|
+
*
|
|
125
|
+
* const transport = getTransport()
|
|
126
|
+
*
|
|
127
|
+
* transport.register('test', async (messages) => {
|
|
128
|
+
* for (const { level, message } of messages)
|
|
129
|
+
* console.log(level, message)
|
|
130
|
+
* })
|
|
131
|
+
*
|
|
132
|
+
* transport.config({ label: 'test', debug: true })
|
|
133
|
+
*
|
|
134
|
+
* // If you using Logger, it will automatically insert messages to the transport.
|
|
135
|
+
* // Otherwise, you can insert messages manually.
|
|
136
|
+
* transport.insert({
|
|
137
|
+
* level: 'info',
|
|
138
|
+
* labels: ['server'],
|
|
139
|
+
* message: 'test message',
|
|
140
|
+
* timestamp: Date.now()
|
|
141
|
+
* })
|
|
142
|
+
*
|
|
143
|
+
* process.on('SIGINT', async () => {
|
|
144
|
+
* await transport.stop()
|
|
145
|
+
* process.exit(0)
|
|
146
|
+
* })
|
|
147
|
+
* ```
|
|
148
|
+
*/
|
|
149
|
+
var Transport = class {
|
|
150
|
+
enabled = true;
|
|
151
|
+
handlers = /* @__PURE__ */ new Map();
|
|
152
|
+
logger;
|
|
153
|
+
messages = [];
|
|
154
|
+
flushing = false;
|
|
155
|
+
interval;
|
|
156
|
+
intervalTime = 5e3;
|
|
157
|
+
constructor() {
|
|
158
|
+
this.logger = new Logger("LoggerTransport");
|
|
159
|
+
this.logger.level = "info";
|
|
160
|
+
this.flush = this.flush.bind(this);
|
|
161
|
+
this.interval = setInterval(this.flush, this.intervalTime);
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* Registers a new transport handler.
|
|
165
|
+
*
|
|
166
|
+
* @param name - The name of the transport handler.
|
|
167
|
+
* @param handler - The transport handler function to be registered.
|
|
168
|
+
*/
|
|
169
|
+
register(name, handler) {
|
|
170
|
+
this.logger.info("register", name);
|
|
171
|
+
this.handlers.set(name, handler);
|
|
172
|
+
if (!this.enabled) this.enabled = true;
|
|
173
|
+
}
|
|
174
|
+
/**
|
|
175
|
+
* Unregister a handler by its name.
|
|
176
|
+
*
|
|
177
|
+
* This method logs the unregistration process, removes the handler from the internal collection,
|
|
178
|
+
* and disables the logger if no handlers remain.
|
|
179
|
+
*
|
|
180
|
+
* @param name - The name of the handler to unregister.
|
|
181
|
+
*/
|
|
182
|
+
unregister(name) {
|
|
183
|
+
this.logger.info("unregister", name);
|
|
184
|
+
this.handlers.delete(name);
|
|
185
|
+
if (this.handlers.size === 0) this.enabled = false;
|
|
186
|
+
}
|
|
187
|
+
/**
|
|
188
|
+
* Inserts a log message into the transport if it is enabled.
|
|
189
|
+
*
|
|
190
|
+
* @param message - The log message to be inserted.
|
|
191
|
+
*/
|
|
192
|
+
insert(message) {
|
|
193
|
+
if (!this.enabled) return;
|
|
194
|
+
this.messages.push(message);
|
|
195
|
+
}
|
|
196
|
+
/**
|
|
197
|
+
* Flushes the current messages by processing them with the registered handlers.
|
|
198
|
+
*
|
|
199
|
+
* If the transport is already flushing, it will wait until the current flush is complete.
|
|
200
|
+
* If the transport is disabled or there are no messages to flush, it will return immediately.
|
|
201
|
+
* If there are no handlers registered, it will log a warning, clear the messages, disable the transport, and stop the interval.
|
|
202
|
+
*
|
|
203
|
+
* The method processes all messages with each handler and logs any errors encountered during the process.
|
|
204
|
+
*
|
|
205
|
+
* @returns {Promise<void>} A promise that resolves when the flush operation is complete.
|
|
206
|
+
*/
|
|
207
|
+
async flush() {
|
|
208
|
+
if (this.flushing) return new Promise((resolve) => {
|
|
209
|
+
const interval = setInterval(() => {
|
|
210
|
+
if (!this.flushing) {
|
|
211
|
+
clearInterval(interval);
|
|
212
|
+
resolve();
|
|
213
|
+
}
|
|
214
|
+
}, 100);
|
|
215
|
+
});
|
|
216
|
+
if (!this.enabled || this.messages.length === 0) return;
|
|
217
|
+
if (this.handlers.size === 0) {
|
|
218
|
+
this.logger.warn("no handlers to flush, disable transport");
|
|
219
|
+
this.messages.splice(0, this.messages.length);
|
|
220
|
+
this.enabled = false;
|
|
221
|
+
clearInterval(this.interval);
|
|
222
|
+
return;
|
|
223
|
+
}
|
|
224
|
+
this.flushing = true;
|
|
225
|
+
const messages = this.messages.splice(0, this.messages.length);
|
|
226
|
+
this.logger.debug("flushing %d messages with %d handlers", messages.length, this.handlers.size);
|
|
227
|
+
for (const handler of this.handlers.values()) try {
|
|
228
|
+
await handler(messages);
|
|
229
|
+
} catch (error) {
|
|
230
|
+
this.logger.error(handler.name, error);
|
|
231
|
+
}
|
|
232
|
+
this.flushing = false;
|
|
233
|
+
}
|
|
234
|
+
/**
|
|
235
|
+
* Stops the logger transport.
|
|
236
|
+
*
|
|
237
|
+
* This method performs the following actions:
|
|
238
|
+
* 1. Logs a 'stopping' message.
|
|
239
|
+
* 2. Clears the interval if it is set.
|
|
240
|
+
* 3. Flushes any remaining logs.
|
|
241
|
+
* 4. Disables the transport.
|
|
242
|
+
*
|
|
243
|
+
* @returns {Promise<void>} A promise that resolves when the transport has been stopped.
|
|
244
|
+
*/
|
|
245
|
+
async stop() {
|
|
246
|
+
this.logger.info("stopping");
|
|
247
|
+
if (this.interval) {
|
|
248
|
+
clearInterval(this.interval);
|
|
249
|
+
this.interval = void 0;
|
|
250
|
+
}
|
|
251
|
+
await this.flush();
|
|
252
|
+
this.enabled = false;
|
|
253
|
+
}
|
|
254
|
+
/**
|
|
255
|
+
* Resets the transport by clearing handlers, emptying messages, and re-enabling the transport.
|
|
256
|
+
* If an interval is set, it will be cleared.
|
|
257
|
+
*/
|
|
258
|
+
reset() {
|
|
259
|
+
this.handlers.clear();
|
|
260
|
+
this.messages.splice(0, this.messages.length);
|
|
261
|
+
this.enabled = true;
|
|
262
|
+
if (this.interval) {
|
|
263
|
+
clearInterval(this.interval);
|
|
264
|
+
this.interval = void 0;
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
/**
|
|
268
|
+
* Configure the transport options for the logger.
|
|
269
|
+
*
|
|
270
|
+
* @param {TransportOptions} options - The configuration options for the transport.
|
|
271
|
+
* @param {string} [options.label] - The label to be used by the logger.
|
|
272
|
+
* @param {boolean} [options.debug] - If true, sets the logger level to 'debug', otherwise sets it to 'info'.
|
|
273
|
+
* @param {number} [options.interval] - The interval time in milliseconds for flushing the logs. If different from the current interval, it updates the interval and resets the timer.
|
|
274
|
+
*/
|
|
275
|
+
config(options) {
|
|
276
|
+
if (options.label) this.logger.label = options.label;
|
|
277
|
+
if (typeof options.debug === "boolean") this.logger.level = options.debug ? "debug" : "info";
|
|
278
|
+
if (options.interval && options.interval !== this.intervalTime) {
|
|
279
|
+
this.intervalTime = options.interval;
|
|
280
|
+
clearInterval(this.interval);
|
|
281
|
+
this.interval = setInterval(this.flush, this.intervalTime);
|
|
282
|
+
}
|
|
283
|
+
if (!this.enabled) this.enabled = true;
|
|
284
|
+
}
|
|
285
|
+
};
|
|
286
|
+
let current;
|
|
287
|
+
function getTransport() {
|
|
288
|
+
current ||= new Transport();
|
|
289
|
+
return current;
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
//#endregion
|
|
293
|
+
//#region src/logger.ts
|
|
294
|
+
const LevelPriority = {
|
|
295
|
+
debug: 0,
|
|
296
|
+
info: 1,
|
|
297
|
+
warn: 2,
|
|
298
|
+
error: 3
|
|
299
|
+
};
|
|
300
|
+
/**
|
|
301
|
+
* Formats the provided arguments into a string, filtering out any objects
|
|
302
|
+
* with a `__hidden__` property set to `true`. If formatting fails, it attempts
|
|
303
|
+
* to stringify each argument individually.
|
|
304
|
+
*
|
|
305
|
+
* @param {...any[]} args - The arguments to format.
|
|
306
|
+
* @returns {string} The formatted string.
|
|
307
|
+
*/
|
|
308
|
+
function formatLogger(fmt, ...args) {
|
|
309
|
+
try {
|
|
310
|
+
return format(fmt, ...args.filter((a) => !a || typeof a !== "object" || a.__hidden__ !== true));
|
|
311
|
+
} catch (e) {
|
|
312
|
+
return `[Unable to format] ${e?.message}`;
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
/**
|
|
316
|
+
* Logger Class
|
|
317
|
+
*
|
|
318
|
+
* @example
|
|
319
|
+
* ```ts
|
|
320
|
+
* const logger = new Logger()
|
|
321
|
+
*
|
|
322
|
+
* logger.debug('debug message')
|
|
323
|
+
* logger.info('info message')
|
|
324
|
+
* logger.warn('warn message')
|
|
325
|
+
* logger.error('error message')
|
|
326
|
+
*
|
|
327
|
+
* logger.time('timer name')
|
|
328
|
+
* logger.timeEnd('timer name', 'message') // => 'message +1ms'
|
|
329
|
+
* ```
|
|
330
|
+
*/
|
|
331
|
+
var Logger = class {
|
|
332
|
+
silent = false;
|
|
333
|
+
level = "debug";
|
|
334
|
+
colorfyOutput = true;
|
|
335
|
+
label;
|
|
336
|
+
size = 1e3;
|
|
337
|
+
disableTransport = false;
|
|
338
|
+
stdout = console.log;
|
|
339
|
+
stderr = console.error;
|
|
340
|
+
cachedTimers = {};
|
|
341
|
+
/**
|
|
342
|
+
* @param label {string} Prefix label
|
|
343
|
+
*/
|
|
344
|
+
constructor(label) {
|
|
345
|
+
if (label) this.label = label;
|
|
346
|
+
if (typeof process === "undefined") return;
|
|
347
|
+
if (!process.env.FaasLog && process.env.npm_config_argv && JSON.parse(process.env.npm_config_argv).original.includes("--silent")) this.silent = true;
|
|
348
|
+
if (process.env.FaasLogTransport !== "true" && (process.env.VITEST || process.env.FaasLogTransport === "false")) this.disableTransport = true;
|
|
349
|
+
switch (process.env.FaasLogMode) {
|
|
350
|
+
case "plain":
|
|
351
|
+
this.colorfyOutput = false;
|
|
352
|
+
break;
|
|
353
|
+
case "pretty":
|
|
354
|
+
this.colorfyOutput = true;
|
|
355
|
+
break;
|
|
356
|
+
default:
|
|
357
|
+
this.colorfyOutput = process.env.FaasMode !== "remote";
|
|
358
|
+
break;
|
|
359
|
+
}
|
|
360
|
+
if (process.env.FaasLog) this.level = process.env.FaasLog.toLowerCase();
|
|
361
|
+
if (process.env.FaasLogSize) this.size = Number(process.env.FaasLogSize);
|
|
362
|
+
}
|
|
363
|
+
/**
|
|
364
|
+
* @param message {string} message
|
|
365
|
+
* @param args {...any=} arguments
|
|
366
|
+
*/
|
|
367
|
+
debug(message, ...args) {
|
|
368
|
+
this.log("debug", message, ...args);
|
|
369
|
+
return this;
|
|
370
|
+
}
|
|
371
|
+
/**
|
|
372
|
+
* @param message {string} message
|
|
373
|
+
* @param args {...any=} arguments
|
|
374
|
+
*/
|
|
375
|
+
info(message, ...args) {
|
|
376
|
+
this.log("info", message, ...args);
|
|
377
|
+
return this;
|
|
378
|
+
}
|
|
379
|
+
/**
|
|
380
|
+
* @param message {string} message
|
|
381
|
+
* @param args {...any=} arguments
|
|
382
|
+
*/
|
|
383
|
+
warn(message, ...args) {
|
|
384
|
+
this.log("warn", message, ...args);
|
|
385
|
+
return this;
|
|
386
|
+
}
|
|
387
|
+
/**
|
|
388
|
+
* @param message {any} message or Error object
|
|
389
|
+
* @param args {...any=} arguments
|
|
390
|
+
*/
|
|
391
|
+
error(message, ...args) {
|
|
392
|
+
this.log("error", message, ...args);
|
|
393
|
+
return this;
|
|
394
|
+
}
|
|
395
|
+
/**
|
|
396
|
+
* Start a timer with a specific key and log level.
|
|
397
|
+
*
|
|
398
|
+
* @param key - The unique identifier for the timer.
|
|
399
|
+
* @param level - The log level for the timer. Defaults to 'debug'.
|
|
400
|
+
* @returns The Logger instance for chaining.
|
|
401
|
+
*/
|
|
402
|
+
time(key, level = "debug") {
|
|
403
|
+
this.cachedTimers[key] = {
|
|
404
|
+
level,
|
|
405
|
+
time: Date.now()
|
|
406
|
+
};
|
|
407
|
+
return this;
|
|
408
|
+
}
|
|
409
|
+
/**
|
|
410
|
+
* End a timer with a specific key and log the elapsed time.
|
|
411
|
+
*
|
|
412
|
+
* @param key - The unique identifier for the timer.
|
|
413
|
+
* @param message - The message to log with the elapsed time.
|
|
414
|
+
* @param args - Additional arguments to log with the message.
|
|
415
|
+
* @returns The Logger instance for chaining.
|
|
416
|
+
*/
|
|
417
|
+
timeEnd(key, message, ...args) {
|
|
418
|
+
if (this.cachedTimers[key]) {
|
|
419
|
+
const timer = this.cachedTimers[key];
|
|
420
|
+
const duration = Date.now() - timer.time;
|
|
421
|
+
message = `${message} +${duration}ms`;
|
|
422
|
+
args.push({
|
|
423
|
+
__hidden__: true,
|
|
424
|
+
performance: {
|
|
425
|
+
name: key,
|
|
426
|
+
startTime: timer.time,
|
|
427
|
+
duration
|
|
428
|
+
}
|
|
429
|
+
});
|
|
430
|
+
this[timer.level](message, ...args);
|
|
431
|
+
delete this.cachedTimers[key];
|
|
432
|
+
} else {
|
|
433
|
+
this.warn("timeEnd not found key %s", key);
|
|
434
|
+
this.debug(message);
|
|
435
|
+
}
|
|
436
|
+
return this;
|
|
437
|
+
}
|
|
438
|
+
/**
|
|
439
|
+
* @param message {string} message
|
|
440
|
+
* @param args {...any=} arguments
|
|
441
|
+
*/
|
|
442
|
+
raw(message, ...args) {
|
|
443
|
+
if (this.silent) return this;
|
|
444
|
+
this.stdout(formatLogger(message, ...args));
|
|
445
|
+
return this;
|
|
446
|
+
}
|
|
447
|
+
log(level, message, ...args) {
|
|
448
|
+
if (this.silent) return this;
|
|
449
|
+
if (LevelPriority[level] < LevelPriority[this.level]) return this;
|
|
450
|
+
const formattedMessage = formatLogger(message, ...args);
|
|
451
|
+
if (!formattedMessage && !args.length) return this;
|
|
452
|
+
if (!this.disableTransport) getTransport().insert({
|
|
453
|
+
level,
|
|
454
|
+
labels: this.label?.split(/\]\s*\[/) || [],
|
|
455
|
+
message: formattedMessage,
|
|
456
|
+
timestamp: Date.now(),
|
|
457
|
+
extra: args
|
|
458
|
+
});
|
|
459
|
+
let output = `${level.toUpperCase()} ${this.label ? `[${this.label}] ` : ""}${formattedMessage}`;
|
|
460
|
+
if (this.colorfyOutput) output = colorfy(level, output);
|
|
461
|
+
else if (!this.colorfyOutput) output = output.replace(/\n/g, "");
|
|
462
|
+
if (!output) return this;
|
|
463
|
+
if (this.size > 0 && output.length > this.size && !["error", "warn"].includes(level)) output = `${output.slice(0, this.size - 100)}...[truncated]...${output.slice(output.length - 100)}`;
|
|
464
|
+
if (level === "error") this.stderr(output);
|
|
465
|
+
else this.stdout(output);
|
|
466
|
+
return this;
|
|
467
|
+
}
|
|
468
|
+
};
|
|
469
|
+
|
|
470
|
+
//#endregion
|
|
471
|
+
//#region src/parse_yaml.ts
|
|
472
|
+
function createParseError(line, reason) {
|
|
473
|
+
return Error(`[parseYaml] ${reason} at line ${line}`);
|
|
474
|
+
}
|
|
475
|
+
function isSequenceLine(content) {
|
|
476
|
+
return /^-(\s|$)/.test(content);
|
|
477
|
+
}
|
|
478
|
+
function isMappingValue(value) {
|
|
479
|
+
return !!value && typeof value === "object" && !Array.isArray(value);
|
|
480
|
+
}
|
|
481
|
+
function stripInlineComment(content) {
|
|
482
|
+
let inSingleQuote = false;
|
|
483
|
+
let inDoubleQuote = false;
|
|
484
|
+
let escaped = false;
|
|
485
|
+
for (let i = 0; i < content.length; i++) {
|
|
486
|
+
const char = content[i];
|
|
487
|
+
if (inDoubleQuote) {
|
|
488
|
+
if (escaped) {
|
|
489
|
+
escaped = false;
|
|
490
|
+
continue;
|
|
491
|
+
}
|
|
492
|
+
if (char === "\\") {
|
|
493
|
+
escaped = true;
|
|
494
|
+
continue;
|
|
495
|
+
}
|
|
496
|
+
if (char === "\"") inDoubleQuote = false;
|
|
497
|
+
continue;
|
|
498
|
+
}
|
|
499
|
+
if (inSingleQuote) {
|
|
500
|
+
if (char === "'") {
|
|
501
|
+
if (content[i + 1] === "'") {
|
|
502
|
+
i++;
|
|
503
|
+
continue;
|
|
504
|
+
}
|
|
505
|
+
inSingleQuote = false;
|
|
506
|
+
}
|
|
507
|
+
continue;
|
|
508
|
+
}
|
|
509
|
+
if (char === "\"") {
|
|
510
|
+
inDoubleQuote = true;
|
|
511
|
+
continue;
|
|
512
|
+
}
|
|
513
|
+
if (char === "'") {
|
|
514
|
+
inSingleQuote = true;
|
|
515
|
+
continue;
|
|
516
|
+
}
|
|
517
|
+
if (char === "#" && (i === 0 || /\s/.test(content[i - 1]))) return content.slice(0, i).trimEnd();
|
|
518
|
+
}
|
|
519
|
+
return content.trimEnd();
|
|
520
|
+
}
|
|
521
|
+
function normalizeLines(content) {
|
|
522
|
+
const lines = content.replace(/\r\n?/g, "\n").split("\n");
|
|
523
|
+
const normalized = [];
|
|
524
|
+
for (let i = 0; i < lines.length; i++) {
|
|
525
|
+
const line = lines[i];
|
|
526
|
+
const lineNumber = i + 1;
|
|
527
|
+
const leading = line.match(/^[ \t]*/)?.[0] || "";
|
|
528
|
+
if (leading.includes(" ")) throw createParseError(lineNumber, "Tabs are not supported for indentation");
|
|
529
|
+
const indent = leading.length;
|
|
530
|
+
const contentWithoutComment = stripInlineComment(line.slice(indent));
|
|
531
|
+
if (!contentWithoutComment.trim()) continue;
|
|
532
|
+
if (contentWithoutComment === "---" || contentWithoutComment === "...") throw createParseError(lineNumber, "Multiple YAML documents are not supported");
|
|
533
|
+
normalized.push({
|
|
534
|
+
content: contentWithoutComment,
|
|
535
|
+
indent,
|
|
536
|
+
line: lineNumber
|
|
537
|
+
});
|
|
538
|
+
}
|
|
539
|
+
return normalized;
|
|
540
|
+
}
|
|
541
|
+
function findMappingSeparator(content) {
|
|
542
|
+
let inSingleQuote = false;
|
|
543
|
+
let inDoubleQuote = false;
|
|
544
|
+
let escaped = false;
|
|
545
|
+
for (let i = 0; i < content.length; i++) {
|
|
546
|
+
const char = content[i];
|
|
547
|
+
if (inDoubleQuote) {
|
|
548
|
+
if (escaped) {
|
|
549
|
+
escaped = false;
|
|
550
|
+
continue;
|
|
551
|
+
}
|
|
552
|
+
if (char === "\\") {
|
|
553
|
+
escaped = true;
|
|
554
|
+
continue;
|
|
555
|
+
}
|
|
556
|
+
if (char === "\"") inDoubleQuote = false;
|
|
557
|
+
continue;
|
|
558
|
+
}
|
|
559
|
+
if (inSingleQuote) {
|
|
560
|
+
if (char === "'") {
|
|
561
|
+
if (content[i + 1] === "'") {
|
|
562
|
+
i++;
|
|
563
|
+
continue;
|
|
564
|
+
}
|
|
565
|
+
inSingleQuote = false;
|
|
566
|
+
}
|
|
567
|
+
continue;
|
|
568
|
+
}
|
|
569
|
+
if (char === "\"") {
|
|
570
|
+
inDoubleQuote = true;
|
|
571
|
+
continue;
|
|
572
|
+
}
|
|
573
|
+
if (char === "'") {
|
|
574
|
+
inSingleQuote = true;
|
|
575
|
+
continue;
|
|
576
|
+
}
|
|
577
|
+
if (char !== ":") continue;
|
|
578
|
+
const next = content[i + 1];
|
|
579
|
+
if (typeof next === "undefined" || /\s/.test(next)) return i;
|
|
580
|
+
}
|
|
581
|
+
return -1;
|
|
582
|
+
}
|
|
583
|
+
function parseDoubleQuotedScalar(value, line) {
|
|
584
|
+
let result = "";
|
|
585
|
+
for (let i = 1; i < value.length; i++) {
|
|
586
|
+
const char = value[i];
|
|
587
|
+
if (char === "\"") {
|
|
588
|
+
if (i !== value.length - 1) throw createParseError(line, "Invalid double quoted string");
|
|
589
|
+
return result;
|
|
590
|
+
}
|
|
591
|
+
if (char !== "\\") {
|
|
592
|
+
result += char;
|
|
593
|
+
continue;
|
|
594
|
+
}
|
|
595
|
+
const escaped = value[++i];
|
|
596
|
+
if (typeof escaped === "undefined") throw createParseError(line, "Invalid escape sequence");
|
|
597
|
+
switch (escaped) {
|
|
598
|
+
case "\"":
|
|
599
|
+
case "\\":
|
|
600
|
+
case "/":
|
|
601
|
+
result += escaped;
|
|
602
|
+
break;
|
|
603
|
+
case "b":
|
|
604
|
+
result += "\b";
|
|
605
|
+
break;
|
|
606
|
+
case "f":
|
|
607
|
+
result += "\f";
|
|
608
|
+
break;
|
|
609
|
+
case "n":
|
|
610
|
+
result += "\n";
|
|
611
|
+
break;
|
|
612
|
+
case "r":
|
|
613
|
+
result += "\r";
|
|
614
|
+
break;
|
|
615
|
+
case "t":
|
|
616
|
+
result += " ";
|
|
617
|
+
break;
|
|
618
|
+
case "u": {
|
|
619
|
+
const hex = value.slice(i + 1, i + 5);
|
|
620
|
+
if (!/^[0-9a-fA-F]{4}$/.test(hex)) throw createParseError(line, "Invalid unicode escape sequence");
|
|
621
|
+
result += String.fromCharCode(Number.parseInt(hex, 16));
|
|
622
|
+
i += 4;
|
|
623
|
+
break;
|
|
624
|
+
}
|
|
625
|
+
default: throw createParseError(line, `Unsupported escape sequence \\${escaped}`);
|
|
626
|
+
}
|
|
627
|
+
}
|
|
628
|
+
throw createParseError(line, "Unterminated double quoted string");
|
|
629
|
+
}
|
|
630
|
+
function parseSingleQuotedScalar(value, line) {
|
|
631
|
+
let result = "";
|
|
632
|
+
for (let i = 1; i < value.length; i++) {
|
|
633
|
+
const char = value[i];
|
|
634
|
+
if (char === "'") {
|
|
635
|
+
if (value[i + 1] === "'") {
|
|
636
|
+
result += "'";
|
|
637
|
+
i++;
|
|
638
|
+
continue;
|
|
639
|
+
}
|
|
640
|
+
if (i !== value.length - 1) throw createParseError(line, "Invalid single quoted string");
|
|
641
|
+
return result;
|
|
642
|
+
}
|
|
643
|
+
result += char;
|
|
644
|
+
}
|
|
645
|
+
throw createParseError(line, "Unterminated single quoted string");
|
|
646
|
+
}
|
|
647
|
+
function parseQuotedScalar(value, line) {
|
|
648
|
+
if (value.startsWith("\"")) return parseDoubleQuotedScalar(value, line);
|
|
649
|
+
if (value.startsWith("'")) return parseSingleQuotedScalar(value, line);
|
|
650
|
+
throw createParseError(line, "Invalid quoted string");
|
|
651
|
+
}
|
|
652
|
+
function parsePlainScalar(value) {
|
|
653
|
+
if (value === "~") return null;
|
|
654
|
+
const lower = value.toLowerCase();
|
|
655
|
+
if (lower === "null") return null;
|
|
656
|
+
if (lower === "true") return true;
|
|
657
|
+
if (lower === "false") return false;
|
|
658
|
+
if (/^[-+]?(?:0|[1-9]\d*)(?:\.\d+)?(?:[eE][-+]?\d+)?$/.test(value)) return Number(value);
|
|
659
|
+
return value;
|
|
660
|
+
}
|
|
661
|
+
function parseInlineValue(value, line) {
|
|
662
|
+
if (value.startsWith("|") || value.startsWith(">")) throw createParseError(line, "Block scalar is not supported");
|
|
663
|
+
if (value.startsWith("!")) throw createParseError(line, "YAML tags are not supported");
|
|
664
|
+
if (value === "[]") return [];
|
|
665
|
+
if (value === "{}") return Object.create(null);
|
|
666
|
+
if (value.startsWith("[") || value.startsWith("{")) throw createParseError(line, "Flow collection is not supported");
|
|
667
|
+
if (value.startsWith("\"") || value.startsWith("'")) return parseQuotedScalar(value, line);
|
|
668
|
+
return parsePlainScalar(value);
|
|
669
|
+
}
|
|
670
|
+
function parseKey(rawKey, line) {
|
|
671
|
+
if (!rawKey.length) throw createParseError(line, "Missing mapping key");
|
|
672
|
+
if (rawKey.startsWith("\"") || rawKey.startsWith("'")) return parseQuotedScalar(rawKey, line);
|
|
673
|
+
if (rawKey.startsWith("[") || rawKey.startsWith("{")) throw createParseError(line, "Complex mapping key is not supported");
|
|
674
|
+
return rawKey;
|
|
675
|
+
}
|
|
676
|
+
function parseReferenceToken(value, line, marker) {
|
|
677
|
+
let index = 1;
|
|
678
|
+
while (index < value.length && !/\s/.test(value[index])) index++;
|
|
679
|
+
const name = value.slice(1, index);
|
|
680
|
+
if (!name.length) throw createParseError(line, marker === "&" ? "Missing anchor name" : "Missing alias name");
|
|
681
|
+
if (!/^[^\s\[\]\{\},]+$/.test(name)) throw createParseError(line, marker === "&" ? "Invalid anchor name" : "Invalid alias name");
|
|
682
|
+
return {
|
|
683
|
+
name,
|
|
684
|
+
rest: value.slice(index).trimStart()
|
|
685
|
+
};
|
|
686
|
+
}
|
|
687
|
+
function setAnchor(context, anchorName, value) {
|
|
688
|
+
if (!anchorName) return;
|
|
689
|
+
context.anchors.set(anchorName, value);
|
|
690
|
+
}
|
|
691
|
+
function parseValueToken(token, line, context) {
|
|
692
|
+
let anchorName;
|
|
693
|
+
let rest = token;
|
|
694
|
+
if (rest.startsWith("&")) {
|
|
695
|
+
const anchor = parseReferenceToken(rest, line, "&");
|
|
696
|
+
anchorName = anchor.name;
|
|
697
|
+
rest = anchor.rest;
|
|
698
|
+
if (!rest.length) return {
|
|
699
|
+
anchorName,
|
|
700
|
+
kind: "nested"
|
|
701
|
+
};
|
|
702
|
+
}
|
|
703
|
+
if (rest.startsWith("*")) {
|
|
704
|
+
const alias = parseReferenceToken(rest, line, "*");
|
|
705
|
+
if (alias.rest.length) throw createParseError(line, "Unexpected token after alias");
|
|
706
|
+
if (!context.anchors.has(alias.name)) throw createParseError(line, `Unknown alias "*${alias.name}"`);
|
|
707
|
+
return {
|
|
708
|
+
anchorName,
|
|
709
|
+
kind: "alias",
|
|
710
|
+
value: context.anchors.get(alias.name)
|
|
711
|
+
};
|
|
712
|
+
}
|
|
713
|
+
return {
|
|
714
|
+
anchorName,
|
|
715
|
+
kind: "inline",
|
|
716
|
+
raw: rest
|
|
717
|
+
};
|
|
718
|
+
}
|
|
719
|
+
function parseNode(lines, index, indent, context) {
|
|
720
|
+
const current = lines[index];
|
|
721
|
+
if (!current) return {
|
|
722
|
+
value: null,
|
|
723
|
+
nextIndex: index
|
|
724
|
+
};
|
|
725
|
+
if (current.indent !== indent) throw createParseError(current.line, `Unexpected indentation: expected ${indent} spaces but got ${current.indent}`);
|
|
726
|
+
if (isSequenceLine(current.content)) return parseSequence(lines, index, indent, context);
|
|
727
|
+
return parseMapping(lines, index, indent, context);
|
|
728
|
+
}
|
|
729
|
+
function parseNestedBlockOrNull(lines, index, parentIndent, context) {
|
|
730
|
+
const next = lines[index + 1];
|
|
731
|
+
if (!next || next.indent <= parentIndent) return {
|
|
732
|
+
value: null,
|
|
733
|
+
nextIndex: index + 1
|
|
734
|
+
};
|
|
735
|
+
return parseNode(lines, index + 1, next.indent, context);
|
|
736
|
+
}
|
|
737
|
+
function parseMappingEntry(lines, index, content, entryIndent, line, context) {
|
|
738
|
+
const separator = findMappingSeparator(content);
|
|
739
|
+
if (separator < 0) throw createParseError(line, "Invalid mapping entry, expected \"key: value\"");
|
|
740
|
+
const key = parseKey(content.slice(0, separator).trim(), line);
|
|
741
|
+
const valueToken = content.slice(separator + 1).trimStart();
|
|
742
|
+
if (!valueToken.length) {
|
|
743
|
+
const nested = parseNestedBlockOrNull(lines, index, entryIndent, context);
|
|
744
|
+
return {
|
|
745
|
+
key,
|
|
746
|
+
value: nested.value,
|
|
747
|
+
nextIndex: nested.nextIndex
|
|
748
|
+
};
|
|
749
|
+
}
|
|
750
|
+
const token = parseValueToken(valueToken, line, context);
|
|
751
|
+
if (token.kind === "alias") {
|
|
752
|
+
setAnchor(context, token.anchorName, token.value);
|
|
753
|
+
return {
|
|
754
|
+
key,
|
|
755
|
+
value: token.value,
|
|
756
|
+
nextIndex: index + 1
|
|
757
|
+
};
|
|
758
|
+
}
|
|
759
|
+
if (token.kind === "nested") {
|
|
760
|
+
const nested = parseNestedBlockOrNull(lines, index, entryIndent, context);
|
|
761
|
+
setAnchor(context, token.anchorName, nested.value);
|
|
762
|
+
return {
|
|
763
|
+
key,
|
|
764
|
+
value: nested.value,
|
|
765
|
+
nextIndex: nested.nextIndex
|
|
766
|
+
};
|
|
767
|
+
}
|
|
768
|
+
const inlineValue = parseInlineValue(token.raw, line);
|
|
769
|
+
setAnchor(context, token.anchorName, inlineValue);
|
|
770
|
+
return {
|
|
771
|
+
key,
|
|
772
|
+
value: inlineValue,
|
|
773
|
+
nextIndex: index + 1
|
|
774
|
+
};
|
|
775
|
+
}
|
|
776
|
+
function applyMergeKey(target, source, line) {
|
|
777
|
+
if (Array.isArray(source)) {
|
|
778
|
+
for (const value of source) applyMergeKey(target, value, line);
|
|
779
|
+
return;
|
|
780
|
+
}
|
|
781
|
+
if (!isMappingValue(source)) throw createParseError(line, "Merge key \"<<\" expects a mapping or sequence of mappings");
|
|
782
|
+
for (const key in source) {
|
|
783
|
+
if (Object.hasOwn(target, key)) continue;
|
|
784
|
+
target[key] = source[key];
|
|
785
|
+
}
|
|
786
|
+
}
|
|
787
|
+
function parseMapping(lines, index, indent, context) {
|
|
788
|
+
const value = Object.create(null);
|
|
789
|
+
let currentIndex = index;
|
|
790
|
+
while (currentIndex < lines.length) {
|
|
791
|
+
const line = lines[currentIndex];
|
|
792
|
+
if (line.indent < indent) break;
|
|
793
|
+
if (line.indent > indent) throw createParseError(line.line, `Unexpected indentation in mapping: expected ${indent} spaces but got ${line.indent}`);
|
|
794
|
+
if (isSequenceLine(line.content)) throw createParseError(line.line, "Cannot mix sequence item with mapping at the same indentation");
|
|
795
|
+
const entry = parseMappingEntry(lines, currentIndex, line.content, indent, line.line, context);
|
|
796
|
+
if (entry.key === "<<") applyMergeKey(value, entry.value, line.line);
|
|
797
|
+
else value[entry.key] = entry.value;
|
|
798
|
+
currentIndex = entry.nextIndex;
|
|
799
|
+
}
|
|
800
|
+
return {
|
|
801
|
+
value,
|
|
802
|
+
nextIndex: currentIndex
|
|
803
|
+
};
|
|
804
|
+
}
|
|
805
|
+
function parseSequenceItem(lines, index, indent, context) {
|
|
806
|
+
const line = lines[index];
|
|
807
|
+
const rest = line.content.slice(1);
|
|
808
|
+
if (rest.length && !/^\s/.test(rest)) throw createParseError(line.line, "Missing whitespace after sequence marker \"-\"");
|
|
809
|
+
const token = rest.trimStart();
|
|
810
|
+
if (!token.length) return parseNestedBlockOrNull(lines, index, indent, context);
|
|
811
|
+
const parsedToken = parseValueToken(token, line.line, context);
|
|
812
|
+
if (parsedToken.kind === "alias") {
|
|
813
|
+
setAnchor(context, parsedToken.anchorName, parsedToken.value);
|
|
814
|
+
return {
|
|
815
|
+
value: parsedToken.value,
|
|
816
|
+
nextIndex: index + 1
|
|
817
|
+
};
|
|
818
|
+
}
|
|
819
|
+
if (parsedToken.kind === "nested") {
|
|
820
|
+
const nested = parseNestedBlockOrNull(lines, index, indent, context);
|
|
821
|
+
setAnchor(context, parsedToken.anchorName, nested.value);
|
|
822
|
+
return nested;
|
|
823
|
+
}
|
|
824
|
+
if (findMappingSeparator(parsedToken.raw) < 0) {
|
|
825
|
+
const inlineValue = parseInlineValue(parsedToken.raw, line.line);
|
|
826
|
+
setAnchor(context, parsedToken.anchorName, inlineValue);
|
|
827
|
+
return {
|
|
828
|
+
value: inlineValue,
|
|
829
|
+
nextIndex: index + 1
|
|
830
|
+
};
|
|
831
|
+
}
|
|
832
|
+
const itemIndent = indent + 2;
|
|
833
|
+
const item = Object.create(null);
|
|
834
|
+
const firstEntry = parseMappingEntry(lines, index, parsedToken.raw, itemIndent, line.line, context);
|
|
835
|
+
if (firstEntry.key === "<<") applyMergeKey(item, firstEntry.value, line.line);
|
|
836
|
+
else item[firstEntry.key] = firstEntry.value;
|
|
837
|
+
let currentIndex = firstEntry.nextIndex;
|
|
838
|
+
while (currentIndex < lines.length) {
|
|
839
|
+
const next = lines[currentIndex];
|
|
840
|
+
if (next.indent < itemIndent) break;
|
|
841
|
+
if (next.indent > itemIndent) throw createParseError(next.line, `Unexpected indentation in sequence mapping: expected ${itemIndent} spaces but got ${next.indent}`);
|
|
842
|
+
if (isSequenceLine(next.content)) throw createParseError(next.line, "Cannot mix sequence item with mapping at the same indentation");
|
|
843
|
+
const entry = parseMappingEntry(lines, currentIndex, next.content, itemIndent, next.line, context);
|
|
844
|
+
if (entry.key === "<<") applyMergeKey(item, entry.value, next.line);
|
|
845
|
+
else item[entry.key] = entry.value;
|
|
846
|
+
currentIndex = entry.nextIndex;
|
|
847
|
+
}
|
|
848
|
+
setAnchor(context, parsedToken.anchorName, item);
|
|
849
|
+
return {
|
|
850
|
+
value: item,
|
|
851
|
+
nextIndex: currentIndex
|
|
852
|
+
};
|
|
853
|
+
}
|
|
854
|
+
function parseSequence(lines, index, indent, context) {
|
|
855
|
+
const value = [];
|
|
856
|
+
let currentIndex = index;
|
|
857
|
+
while (currentIndex < lines.length) {
|
|
858
|
+
const line = lines[currentIndex];
|
|
859
|
+
if (line.indent < indent) break;
|
|
860
|
+
if (line.indent > indent) throw createParseError(line.line, `Unexpected indentation in sequence: expected ${indent} spaces but got ${line.indent}`);
|
|
861
|
+
if (!isSequenceLine(line.content)) throw createParseError(line.line, "Cannot mix mapping entry with sequence at the same indentation");
|
|
862
|
+
const item = parseSequenceItem(lines, currentIndex, indent, context);
|
|
863
|
+
value.push(item.value);
|
|
864
|
+
currentIndex = item.nextIndex;
|
|
865
|
+
}
|
|
866
|
+
return {
|
|
867
|
+
value,
|
|
868
|
+
nextIndex: currentIndex
|
|
869
|
+
};
|
|
870
|
+
}
|
|
871
|
+
function parseYaml(content) {
|
|
872
|
+
const lines = normalizeLines(content);
|
|
873
|
+
if (!lines.length) return void 0;
|
|
874
|
+
const context = { anchors: /* @__PURE__ */ new Map() };
|
|
875
|
+
const parsed = parseNode(lines, 0, lines[0].indent, context);
|
|
876
|
+
if (parsed.nextIndex < lines.length) throw createParseError(lines[parsed.nextIndex].line, "Unexpected trailing content");
|
|
877
|
+
return parsed.value;
|
|
878
|
+
}
|
|
879
|
+
|
|
42
880
|
//#endregion
|
|
43
881
|
//#region src/load_config.ts
|
|
44
882
|
function isObject(value) {
|
|
@@ -65,6 +903,13 @@ function validateFaasYaml(filePath, config) {
|
|
|
65
903
|
}
|
|
66
904
|
return config;
|
|
67
905
|
}
|
|
906
|
+
function assignPluginNames(config) {
|
|
907
|
+
if (!config.plugins) return;
|
|
908
|
+
for (const pluginKey in config.plugins) {
|
|
909
|
+
const plugin = config.plugins[pluginKey];
|
|
910
|
+
plugin.name = pluginKey;
|
|
911
|
+
}
|
|
912
|
+
}
|
|
68
913
|
/**
|
|
69
914
|
* Load configuration from faas.yaml
|
|
70
915
|
*/
|
|
@@ -75,28 +920,27 @@ var Config = class {
|
|
|
75
920
|
defaults;
|
|
76
921
|
logger;
|
|
77
922
|
constructor(root, filename, logger) {
|
|
78
|
-
this.logger = new
|
|
923
|
+
this.logger = new Logger(logger?.label ? `${logger.label}] [config` : "config");
|
|
79
924
|
this.root = root;
|
|
80
925
|
if (!this.root.endsWith(node_path.sep)) this.root += node_path.sep;
|
|
81
926
|
this.filename = filename;
|
|
82
927
|
this.logger.debug("load %s in %s", filename, root);
|
|
83
928
|
const configs = [];
|
|
84
|
-
[this.root, "."].concat((0, node_path.dirname)(filename.replace(root, "")).split(node_path.sep))
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
const
|
|
88
|
-
if (
|
|
89
|
-
|
|
90
|
-
|
|
929
|
+
const paths = [this.root, "."].concat((0, node_path.dirname)(filename.replace(root, "")).split(node_path.sep));
|
|
930
|
+
let base = paths[0];
|
|
931
|
+
for (const path of paths.slice(1)) {
|
|
932
|
+
const currentRoot = (0, node_path.join)(base, path);
|
|
933
|
+
if (currentRoot === base) continue;
|
|
934
|
+
const faas = (0, node_path.join)(currentRoot, "faas.yaml");
|
|
935
|
+
if ((0, node_fs.existsSync)(faas)) configs.push(validateFaasYaml(faas, parseYaml((0, node_fs.readFileSync)(faas, "utf8"))));
|
|
936
|
+
base = currentRoot;
|
|
937
|
+
}
|
|
91
938
|
this.origin = deepMerge(...configs);
|
|
92
939
|
this.defaults = deepMerge(this.origin.defaults || {});
|
|
93
940
|
for (const key in this.origin) {
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
const plugin = data.plugins[pluginKey];
|
|
98
|
-
plugin.name = pluginKey;
|
|
99
|
-
}
|
|
941
|
+
const data = key === "defaults" ? this.defaults : deepMerge(this.defaults, this.origin[key]);
|
|
942
|
+
if (key !== "defaults") this[key] = data;
|
|
943
|
+
assignPluginNames(data);
|
|
100
944
|
}
|
|
101
945
|
}
|
|
102
946
|
get(key) {
|
|
@@ -142,19 +986,12 @@ function detectNodeRuntime() {
|
|
|
142
986
|
async function loadPackage(name, defaultNames = "default") {
|
|
143
987
|
const runtime = detectNodeRuntime();
|
|
144
988
|
let module;
|
|
145
|
-
if (runtime === "module")
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
if (runtime === "commonjs") {
|
|
152
|
-
module = globalThis.require(name);
|
|
153
|
-
if (typeof defaultNames === "string") return defaultNames in module ? module[defaultNames] : module;
|
|
154
|
-
for (const key of defaultNames) if (key in module) return module[key];
|
|
155
|
-
return module;
|
|
156
|
-
}
|
|
157
|
-
throw Error("Unknown runtime");
|
|
989
|
+
if (runtime === "module") module = await import(name);
|
|
990
|
+
else if (runtime === "commonjs") module = globalThis.require(name);
|
|
991
|
+
else throw Error("Unknown runtime");
|
|
992
|
+
if (typeof defaultNames === "string") return defaultNames in module ? module[defaultNames] : module;
|
|
993
|
+
for (const key of defaultNames) if (key in module) return module[key];
|
|
994
|
+
return module;
|
|
158
995
|
}
|
|
159
996
|
|
|
160
997
|
//#endregion
|
|
@@ -210,8 +1047,15 @@ async function streamToObject(stream) {
|
|
|
210
1047
|
const streamToString = streamToText;
|
|
211
1048
|
|
|
212
1049
|
//#endregion
|
|
1050
|
+
exports.Color = Color;
|
|
1051
|
+
exports.LevelColor = LevelColor;
|
|
1052
|
+
exports.Logger = Logger;
|
|
1053
|
+
exports.Transport = Transport;
|
|
1054
|
+
exports.colorfy = colorfy;
|
|
213
1055
|
exports.deepMerge = deepMerge;
|
|
214
1056
|
exports.detectNodeRuntime = detectNodeRuntime;
|
|
1057
|
+
exports.formatLogger = formatLogger;
|
|
1058
|
+
exports.getTransport = getTransport;
|
|
215
1059
|
exports.loadConfig = loadConfig;
|
|
216
1060
|
exports.loadFunc = loadFunc;
|
|
217
1061
|
exports.loadPackage = loadPackage;
|