@brianbuie/node-kit 0.15.1 → 0.16.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 +203 -197
- package/dist/index.d.mts +47 -520
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +113 -156
- package/dist/index.mjs.map +1 -1
- package/package.json +4 -5
- package/src/Cache.ts +4 -3
- package/src/Dir.ts +19 -19
- package/src/Fetcher.ts +2 -2
- package/src/File.ts +70 -56
- package/src/Format.ts +5 -5
- package/src/Log.test.ts +16 -6
- package/src/Log.ts +58 -98
- package/src/TypeWriter.ts +15 -7
- package/src/snapshot.ts +3 -2
- package/src/timeout.ts +1 -1
package/src/Log.ts
CHANGED
|
@@ -1,126 +1,86 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import chalk, { type ChalkInstance } from 'chalk';
|
|
4
|
-
import { snapshot } from './snapshot.ts';
|
|
5
|
-
import { Format } from './Format.ts';
|
|
1
|
+
import { merge } from 'lodash-es';
|
|
2
|
+
import { default as pino, type Logger } from 'pino';
|
|
6
3
|
|
|
7
|
-
|
|
8
|
-
type Severity = 'DEFAULT' | 'DEBUG' | 'INFO' | 'NOTICE' | 'WARNING' | 'ERROR' | 'CRITICAL' | 'ALERT' | 'EMERGENCY';
|
|
4
|
+
export type LogDetails = Record<string, unknown>;
|
|
9
5
|
|
|
10
|
-
type
|
|
11
|
-
severity: Severity;
|
|
12
|
-
color: ChalkInstance;
|
|
13
|
-
};
|
|
6
|
+
export type LogLevel = 'trace' | 'debug' | 'info' | 'warn' | 'error' | 'fatal';
|
|
14
7
|
|
|
15
|
-
type
|
|
16
|
-
|
|
17
|
-
severity: Severity;
|
|
18
|
-
stack?: string;
|
|
19
|
-
details?: unknown[];
|
|
8
|
+
export type LogOptions = pino.LoggerOptions & {
|
|
9
|
+
environment?: string;
|
|
20
10
|
};
|
|
21
11
|
|
|
12
|
+
/**
|
|
13
|
+
* Wrapper for [pino](https://github.com/pinojs/pino)
|
|
14
|
+
* Levels: fatal, error, warn, info, debug, trace
|
|
15
|
+
* Use `LOG_LEVL=info` to limit what's printed to console
|
|
16
|
+
* Use `Log.configure` to customize the pino instance
|
|
17
|
+
*/
|
|
22
18
|
export class Log {
|
|
23
|
-
static
|
|
24
|
-
|
|
25
|
-
// replaces details.stack with current stack trace, excluding this Log.getStack call
|
|
26
|
-
Error.captureStackTrace(details, Log.getStack);
|
|
27
|
-
// remove 'Error' on first line
|
|
28
|
-
return details.stack
|
|
29
|
-
.split('\n')
|
|
30
|
-
.map(l => l.trim())
|
|
31
|
-
.filter(l => l !== 'Error');
|
|
32
|
-
}
|
|
19
|
+
static #logger?: Logger;
|
|
20
|
+
static #options: LogOptions;
|
|
33
21
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
22
|
+
static createLogger(): Logger {
|
|
23
|
+
const isProduction = this.#options?.environment === 'production' || process.env.NODE_ENV === 'production';
|
|
24
|
+
const defaultOptions: LogOptions = {
|
|
25
|
+
level: process.env.LOG_LEVEL ?? (isProduction ? 'info' : 'debug'),
|
|
26
|
+
timestamp: pino.stdTimeFunctions.isoTime,
|
|
27
|
+
formatters: {
|
|
28
|
+
level(label: string) {
|
|
29
|
+
return { level: label };
|
|
30
|
+
},
|
|
31
|
+
},
|
|
32
|
+
transport: isProduction
|
|
33
|
+
? undefined
|
|
34
|
+
: {
|
|
35
|
+
target: 'pino-pretty',
|
|
36
|
+
options: {
|
|
37
|
+
colorize: true,
|
|
38
|
+
singleLine: true,
|
|
39
|
+
ignore: 'pid,hostname',
|
|
40
|
+
},
|
|
41
|
+
},
|
|
42
|
+
};
|
|
43
|
+
return pino(merge(defaultOptions, this.#options));
|
|
41
44
|
}
|
|
42
45
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
static #toConsole(entry: Entry, color: ChalkInstance) {
|
|
47
|
-
if (entry.message) console.log(color(`${Format.date('h:m:s')} [${entry.severity}] ${entry.message}`));
|
|
48
|
-
entry.details?.forEach(detail => {
|
|
49
|
-
console.log(inspect(detail, { depth: 10, breakLength: 100, compact: true, colors: true }));
|
|
50
|
-
});
|
|
46
|
+
static configure(options: LogOptions = {}): void {
|
|
47
|
+
this.#options = options;
|
|
48
|
+
this.#logger = this.createLogger();
|
|
51
49
|
}
|
|
52
50
|
|
|
53
|
-
static #
|
|
54
|
-
|
|
55
|
-
const entry: Entry = { message, severity, details };
|
|
56
|
-
// https://cloud.google.com/run/docs/container-contract#env-vars
|
|
57
|
-
const isGcloud = process.env.K_SERVICE !== undefined || process.env.CLOUD_RUN_JOB !== undefined;
|
|
58
|
-
if (isGcloud) {
|
|
59
|
-
this.#toGcloud(entry);
|
|
60
|
-
} else {
|
|
61
|
-
this.#toConsole(entry, color);
|
|
62
|
-
}
|
|
63
|
-
return entry;
|
|
51
|
+
static #getLogger(): Logger {
|
|
52
|
+
return (this.#logger ??= this.createLogger());
|
|
64
53
|
}
|
|
65
54
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
// First argument is a string, use that as the message
|
|
72
|
-
if (typeof firstArg === 'string') {
|
|
73
|
-
return { message: firstArg, details: rest };
|
|
74
|
-
}
|
|
75
|
-
// First argument is an object with a `message` property
|
|
76
|
-
// @ts-ignore
|
|
77
|
-
if (isObjectLike(firstArg) && typeof firstArg['message'] === 'string') {
|
|
78
|
-
const { message, ...firstDetails } = firstArg as { message: string };
|
|
79
|
-
return { message, details: [firstDetails, ...rest] };
|
|
55
|
+
static #write(level: LogLevel, message: string, details?: LogDetails): void {
|
|
56
|
+
if (details === undefined) {
|
|
57
|
+
Log.#getLogger()[level](message);
|
|
58
|
+
} else {
|
|
59
|
+
Log.#getLogger()[level](details, message);
|
|
80
60
|
}
|
|
81
|
-
// No message found, log all args as details
|
|
82
|
-
return { details: input };
|
|
83
61
|
}
|
|
84
62
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
*/
|
|
88
|
-
static alert(...input: unknown[]) {
|
|
89
|
-
return this.#log({ severity: 'ALERT', color: chalk.bgRed }, ...input);
|
|
63
|
+
static trace(message: string, details?: LogDetails): void {
|
|
64
|
+
Log.#write('trace', message, details);
|
|
90
65
|
}
|
|
91
66
|
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
*/
|
|
95
|
-
static error(...input: unknown[]) {
|
|
96
|
-
return this.#log({ severity: 'ERROR', color: chalk.red }, ...input);
|
|
67
|
+
static debug(message: string, details?: LogDetails): void {
|
|
68
|
+
Log.#write('debug', message, details);
|
|
97
69
|
}
|
|
98
70
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
*/
|
|
102
|
-
static warn(...input: unknown[]) {
|
|
103
|
-
return this.#log({ severity: 'WARNING', color: chalk.yellow }, ...input);
|
|
71
|
+
static info(message: string, details?: LogDetails): void {
|
|
72
|
+
Log.#write('info', message, details);
|
|
104
73
|
}
|
|
105
74
|
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
*/
|
|
109
|
-
static notice(...input: unknown[]) {
|
|
110
|
-
return this.#log({ severity: 'NOTICE', color: chalk.cyan }, ...input);
|
|
75
|
+
static warn(message: string, details?: LogDetails): void {
|
|
76
|
+
Log.#write('warn', message, details);
|
|
111
77
|
}
|
|
112
78
|
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
*/
|
|
116
|
-
static info(...input: unknown[]) {
|
|
117
|
-
return this.#log({ severity: 'INFO', color: chalk.white }, ...input);
|
|
79
|
+
static error(message: string, details?: LogDetails): void {
|
|
80
|
+
Log.#write('error', message, details);
|
|
118
81
|
}
|
|
119
82
|
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
*/
|
|
123
|
-
static debug(...input: unknown[]) {
|
|
124
|
-
return this.#log({ severity: 'DEBUG', color: chalk.gray }, ...input);
|
|
83
|
+
static fatal(message: string, details?: LogDetails): void {
|
|
84
|
+
Log.#write('fatal', message, details);
|
|
125
85
|
}
|
|
126
86
|
}
|
package/src/TypeWriter.ts
CHANGED
|
@@ -2,12 +2,20 @@ import * as fs from 'node:fs';
|
|
|
2
2
|
import { merge } from 'lodash-es';
|
|
3
3
|
import * as qt from 'quicktype-core';
|
|
4
4
|
|
|
5
|
+
/**
|
|
6
|
+
* Wrapper for [quicktype-core](https://github.com/glideapps/quicktype)
|
|
7
|
+
* @example
|
|
8
|
+
* const group = new TypeWriter('Group');
|
|
9
|
+
* await types.addMember('Thing', [{ a: 1 }, { a: 2, b: 1 }]);
|
|
10
|
+
* await types.toFile();
|
|
11
|
+
* // type def for `Thing` saved in `types/Group.types.ts`
|
|
12
|
+
*/
|
|
5
13
|
export class TypeWriter {
|
|
6
|
-
moduleName;
|
|
14
|
+
moduleName: string;
|
|
7
15
|
input = qt.jsonInputForTargetLanguage('typescript');
|
|
8
|
-
outDir;
|
|
9
|
-
outFile;
|
|
10
|
-
qtSettings
|
|
16
|
+
outDir: string;
|
|
17
|
+
outFile: string;
|
|
18
|
+
qtSettings: Partial<qt.Options>;
|
|
11
19
|
|
|
12
20
|
constructor(moduleName: string, settings: { outDir?: string; outFile?: string } & Partial<qt.Options> = {}) {
|
|
13
21
|
this.moduleName = moduleName;
|
|
@@ -26,12 +34,12 @@ export class TypeWriter {
|
|
|
26
34
|
this.qtSettings = merge(defaultSettings, qtSettings);
|
|
27
35
|
}
|
|
28
36
|
|
|
29
|
-
async addMember(name: string, _samples: any[]) {
|
|
37
|
+
async addMember(name: string, _samples: any[]): Promise<void> {
|
|
30
38
|
const samples = _samples.map(s => (typeof s === 'string' ? s : JSON.stringify(s)));
|
|
31
39
|
await this.input.addSource({ name, samples });
|
|
32
40
|
}
|
|
33
41
|
|
|
34
|
-
async toString() {
|
|
42
|
+
async toString(): Promise<string> {
|
|
35
43
|
const inputData = new qt.InputData();
|
|
36
44
|
inputData.addInput(this.input);
|
|
37
45
|
const result = await qt.quicktype({
|
|
@@ -41,7 +49,7 @@ export class TypeWriter {
|
|
|
41
49
|
return result.lines.join('\n');
|
|
42
50
|
}
|
|
43
51
|
|
|
44
|
-
async toFile() {
|
|
52
|
+
async toFile(): Promise<void> {
|
|
45
53
|
const result = await this.toString();
|
|
46
54
|
fs.mkdirSync(this.outDir, { recursive: true });
|
|
47
55
|
fs.writeFileSync(`${this.outDir}/${this.outFile}`, result);
|
package/src/snapshot.ts
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { isObjectLike } from 'lodash-es';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
|
-
*
|
|
5
|
-
* Functions are removed
|
|
4
|
+
* @deprecated
|
|
5
|
+
* Allows special objects (Error, Headers, Set) to be included in JSON.stringify output. Functions are removed.
|
|
6
|
+
* ⚠️ This is bad! Only use it for debugging!
|
|
6
7
|
*/
|
|
7
8
|
export function snapshot(i: unknown, max = 50, depth = 0): any {
|
|
8
9
|
if (Array.isArray(i)) {
|
package/src/timeout.ts
CHANGED