@gtkx/utils 0.21.0 → 1.0.0-rc.1

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.
Files changed (52) hide show
  1. package/README.md +173 -0
  2. package/dist/class.d.ts +17 -11
  3. package/dist/class.d.ts.map +1 -1
  4. package/dist/class.js +27 -1
  5. package/dist/class.js.map +1 -1
  6. package/dist/collection.d.ts +17 -45
  7. package/dist/collection.d.ts.map +1 -1
  8. package/dist/collection.js +42 -76
  9. package/dist/collection.js.map +1 -1
  10. package/dist/error.d.ts +16 -8
  11. package/dist/error.d.ts.map +1 -1
  12. package/dist/error.js +35 -8
  13. package/dist/error.js.map +1 -1
  14. package/dist/graceful-shutdown.d.ts +9 -57
  15. package/dist/graceful-shutdown.d.ts.map +1 -1
  16. package/dist/graceful-shutdown.js +70 -75
  17. package/dist/graceful-shutdown.js.map +1 -1
  18. package/dist/index.d.ts +9 -6
  19. package/dist/index.d.ts.map +1 -1
  20. package/dist/index.js +9 -5
  21. package/dist/index.js.map +1 -1
  22. package/dist/log.d.ts +103 -0
  23. package/dist/log.d.ts.map +1 -0
  24. package/dist/log.js +129 -0
  25. package/dist/log.js.map +1 -0
  26. package/dist/package-version.d.ts +7 -0
  27. package/dist/package-version.d.ts.map +1 -0
  28. package/dist/package-version.js +8 -0
  29. package/dist/package-version.js.map +1 -0
  30. package/dist/reflect.d.ts +11 -0
  31. package/dist/reflect.d.ts.map +1 -0
  32. package/dist/reflect.js +14 -0
  33. package/dist/reflect.js.map +1 -0
  34. package/dist/source.d.ts +12 -25
  35. package/dist/source.d.ts.map +1 -1
  36. package/dist/source.js +20 -41
  37. package/dist/source.js.map +1 -1
  38. package/dist/string.d.ts +13 -40
  39. package/dist/string.d.ts.map +1 -1
  40. package/dist/string.js +18 -48
  41. package/dist/string.js.map +1 -1
  42. package/package.json +20 -7
  43. package/src/class.ts +30 -11
  44. package/src/collection.ts +43 -81
  45. package/src/error.ts +38 -8
  46. package/src/graceful-shutdown.ts +87 -114
  47. package/src/index.ts +18 -9
  48. package/src/log.ts +164 -0
  49. package/src/package-version.ts +9 -0
  50. package/src/reflect.ts +13 -0
  51. package/src/source.ts +24 -43
  52. package/src/string.ts +19 -47
@@ -1,70 +1,22 @@
1
1
  /**
2
- * Cross-process graceful shutdown primitive for long-running Node processes.
2
+ * Maps a terminating signal to its conventional process exit code (130 for `SIGINT`, 143 otherwise),
3
+ * or 0 when no signal is given.
3
4
  *
4
- * The helper installs `SIGINT`/`SIGTERM`/`SIGHUP` handlers, routes the first
5
- * delivered signal through a user-supplied close callback, and escalates either
6
- * on a second `SIGINT` or after a configurable timeout. On completion it calls
7
- * `process.exit` with the canonical exit code for the signal.
8
- */
9
- /**
10
- * Maps the POSIX signal that ended a process into the exit code shells use to
11
- * report it. `SIGINT` yields `130` (Ctrl-C), every other tracked signal yields
12
- * `143` (`SIGTERM`). A `null` signal — i.e. a clean exit — yields `0`.
13
- *
14
- * @param signal - The signal name, or `null` for a clean exit.
15
- * @returns The exit code shells expect for `signal`.
5
+ * @param signal The signal that triggered termination, or `null`.
16
6
  */
17
7
  export declare const exitCodeForSignal: (signal: NodeJS.Signals | null) => number;
18
- /**
19
- * Caller-supplied behaviour for {@link installGracefulShutdown}.
20
- */
21
8
  export type GracefulShutdownOptions = {
22
- /**
23
- * Invoked once on the first delivered signal. Its returned promise is
24
- * awaited before {@link process.exit} fires; rejection is logged but does
25
- * not block the exit.
26
- */
27
9
  onSignal: (signal: NodeJS.Signals) => void | Promise<void>;
28
- /**
29
- * Invoked when escalation is required: on a second `SIGINT`, or when
30
- * {@link GracefulShutdownOptions.forceKillAfterMs} elapses before the
31
- * primary close finishes.
32
- */
33
10
  onForce?: () => void;
34
- /**
35
- * Milliseconds to wait for the primary close before invoking `onForce`
36
- * and exiting. Defaults to {@link DEFAULT_FORCE_KILL_TIMEOUT_MS}. Set to
37
- * `0` to disable timeout-based escalation.
38
- */
39
11
  forceKillAfterMs?: number;
40
- /**
41
- * Overrides the exit code computed from the triggering signal. Use this
42
- * when the caller wants to propagate a child's own exit code instead.
43
- */
44
- exitCode?: (signal: NodeJS.Signals) => number;
12
+ coalesceWindowMs?: number;
13
+ exitCode?: (signal: NodeJS.Signals, graceful: boolean) => number;
45
14
  };
46
15
  /**
47
- * Handle returned by {@link installGracefulShutdown}, used to detach the
48
- * helper's signal handlers (for example in tests).
49
- */
50
- export type GracefulShutdownHandle = {
51
- /**
52
- * Removes the installed signal handlers and cancels any pending
53
- * escalation timer. Idempotent.
54
- */
55
- uninstall: () => void;
56
- };
57
- /**
58
- * Installs the graceful-shutdown primitive on the current process.
59
- *
60
- * On the first matching signal: invokes `onSignal`, optionally schedules
61
- * `onForce` after `forceKillAfterMs`, awaits the close, then exits. A second
62
- * `SIGINT` (the canonical "force-kill" gesture) invokes `onForce`
63
- * immediately. The exit code defaults to {@link exitCodeForSignal} but can
64
- * be overridden by `exitCode`.
16
+ * Registers handlers for `SIGINT`, `SIGTERM`, and `SIGHUP` that run the given cleanup callback once
17
+ * and then exit, forcing exit if a repeated signal arrives or the cleanup exceeds its timeout.
65
18
  *
66
- * @param options - Shutdown behaviour.
67
- * @returns A handle that detaches the installed signal handlers.
19
+ * @param options The shutdown callbacks and timing configuration.
68
20
  */
69
- export declare const installGracefulShutdown: (options: GracefulShutdownOptions) => GracefulShutdownHandle;
21
+ export declare const installGracefulShutdown: (options: GracefulShutdownOptions) => void;
70
22
  //# sourceMappingURL=graceful-shutdown.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"graceful-shutdown.d.ts","sourceRoot":"","sources":["../src/graceful-shutdown.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAKH;;;;;;;GAOG;AACH,eAAO,MAAM,iBAAiB,GAAI,QAAQ,MAAM,CAAC,OAAO,GAAG,IAAI,KAAG,MAGjE,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,uBAAuB,GAAG;IAClC;;;;OAIG;IACH,QAAQ,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,OAAO,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC3D;;;;OAIG;IACH,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB;;;;OAIG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B;;;OAGG;IACH,QAAQ,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,OAAO,KAAK,MAAM,CAAC;CACjD,CAAC;AAEF;;;GAGG;AACH,MAAM,MAAM,sBAAsB,GAAG;IACjC;;;OAGG;IACH,SAAS,EAAE,MAAM,IAAI,CAAC;CACzB,CAAC;AAEF;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,uBAAuB,GAAI,SAAS,uBAAuB,KAAG,sBA8D1E,CAAC"}
1
+ {"version":3,"file":"graceful-shutdown.d.ts","sourceRoot":"","sources":["../src/graceful-shutdown.ts"],"names":[],"mappings":"AAMA;;;;;GAKG;AACH,eAAO,MAAM,iBAAiB,WAAY,MAAM,CAAC,OAAO,GAAG,IAAI,KAAG,MAGjE,CAAC;AAEF,MAAM,MAAM,uBAAuB,GAAG;IAClC,QAAQ,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,OAAO,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC3D,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,OAAO,EAAE,QAAQ,EAAE,OAAO,KAAK,MAAM,CAAC;CACpE,CAAC;AAsEF;;;;;GAKG;AACH,eAAO,MAAM,uBAAuB,YAAa,uBAAuB,KAAG,IAc1E,CAAC"}
@@ -1,94 +1,89 @@
1
- /**
2
- * Cross-process graceful shutdown primitive for long-running Node processes.
3
- *
4
- * The helper installs `SIGINT`/`SIGTERM`/`SIGHUP` handlers, routes the first
5
- * delivered signal through a user-supplied close callback, and escalates either
6
- * on a second `SIGINT` or after a configurable timeout. On completion it calls
7
- * `process.exit` with the canonical exit code for the signal.
8
- */
1
+ import { error } from "./log.js";
9
2
  const HANDLED_SIGNALS = ["SIGINT", "SIGTERM", "SIGHUP"];
10
3
  const DEFAULT_FORCE_KILL_TIMEOUT_MS = 5000;
4
+ const DEFAULT_COALESCE_WINDOW_MS = 500;
11
5
  /**
12
- * Maps the POSIX signal that ended a process into the exit code shells use to
13
- * report it. `SIGINT` yields `130` (Ctrl-C), every other tracked signal yields
14
- * `143` (`SIGTERM`). A `null` signal — i.e. a clean exit — yields `0`.
6
+ * Maps a terminating signal to its conventional process exit code (130 for `SIGINT`, 143 otherwise),
7
+ * or 0 when no signal is given.
15
8
  *
16
- * @param signal - The signal name, or `null` for a clean exit.
17
- * @returns The exit code shells expect for `signal`.
9
+ * @param signal The signal that triggered termination, or `null`.
18
10
  */
19
11
  export const exitCodeForSignal = (signal) => {
20
12
  if (!signal)
21
13
  return 0;
22
14
  return signal === "SIGINT" ? 130 : 143;
23
15
  };
16
+ const clearTimers = (state) => {
17
+ if (state.forceTimer) {
18
+ clearTimeout(state.forceTimer);
19
+ state.forceTimer = null;
20
+ }
21
+ if (state.coalesceTimer) {
22
+ clearTimeout(state.coalesceTimer);
23
+ state.coalesceTimer = null;
24
+ }
25
+ };
26
+ const finish = (state, signal, graceful) => {
27
+ if (state.exited)
28
+ return;
29
+ state.exited = true;
30
+ clearTimers(state);
31
+ const { exitCode } = state.options;
32
+ const code = exitCode ? exitCode(signal, graceful) : graceful ? 0 : exitCodeForSignal(signal);
33
+ process.exit(code);
34
+ };
35
+ const beginShutdown = (state, signal) => {
36
+ state.firstSignal = signal;
37
+ if (state.coalesceWindowMs > 0) {
38
+ state.coalescing = true;
39
+ state.coalesceTimer = setTimeout(() => {
40
+ state.coalescing = false;
41
+ }, state.coalesceWindowMs);
42
+ state.coalesceTimer.unref();
43
+ }
44
+ if (state.options.onForce && state.forceKillMs > 0) {
45
+ state.forceTimer = setTimeout(() => {
46
+ state.options.onForce?.();
47
+ finish(state, signal, false);
48
+ }, state.forceKillMs);
49
+ state.forceTimer.unref();
50
+ }
51
+ Promise.resolve()
52
+ .then(() => state.options.onSignal(signal))
53
+ .then(() => finish(state, signal, true), (reason) => {
54
+ error("graceful shutdown failed", reason);
55
+ finish(state, signal, false);
56
+ });
57
+ };
58
+ const handle = (state, signal) => {
59
+ if (state.firstSignal === null) {
60
+ beginShutdown(state, signal);
61
+ return;
62
+ }
63
+ if (state.coalescing)
64
+ return;
65
+ state.options.onForce?.();
66
+ finish(state, signal, false);
67
+ };
24
68
  /**
25
- * Installs the graceful-shutdown primitive on the current process.
69
+ * Registers handlers for `SIGINT`, `SIGTERM`, and `SIGHUP` that run the given cleanup callback once
70
+ * and then exit, forcing exit if a repeated signal arrives or the cleanup exceeds its timeout.
26
71
  *
27
- * On the first matching signal: invokes `onSignal`, optionally schedules
28
- * `onForce` after `forceKillAfterMs`, awaits the close, then exits. A second
29
- * `SIGINT` (the canonical "force-kill" gesture) invokes `onForce`
30
- * immediately. The exit code defaults to {@link exitCodeForSignal} but can
31
- * be overridden by `exitCode`.
32
- *
33
- * @param options - Shutdown behaviour.
34
- * @returns A handle that detaches the installed signal handlers.
72
+ * @param options The shutdown callbacks and timing configuration.
35
73
  */
36
74
  export const installGracefulShutdown = (options) => {
37
- const forceKillMs = options.forceKillAfterMs ?? DEFAULT_FORCE_KILL_TIMEOUT_MS;
38
- let firstSignal = null;
39
- let exited = false;
40
- let forceTimer = null;
41
- const clearTimer = () => {
42
- if (forceTimer) {
43
- clearTimeout(forceTimer);
44
- forceTimer = null;
45
- }
46
- };
47
- const finish = (signal) => {
48
- if (exited)
49
- return;
50
- exited = true;
51
- clearTimer();
52
- const code = options.exitCode ? options.exitCode(signal) : exitCodeForSignal(signal);
53
- process.exit(code);
75
+ const state = {
76
+ options,
77
+ forceKillMs: options.forceKillAfterMs ?? DEFAULT_FORCE_KILL_TIMEOUT_MS,
78
+ coalesceWindowMs: options.coalesceWindowMs ?? DEFAULT_COALESCE_WINDOW_MS,
79
+ firstSignal: null,
80
+ exited: false,
81
+ coalescing: false,
82
+ forceTimer: null,
83
+ coalesceTimer: null,
54
84
  };
55
- const handle = (signal) => {
56
- if (firstSignal === null) {
57
- firstSignal = signal;
58
- if (options.onForce && forceKillMs > 0) {
59
- forceTimer = setTimeout(() => {
60
- options.onForce?.();
61
- finish(signal);
62
- }, forceKillMs);
63
- forceTimer.unref?.();
64
- }
65
- Promise.resolve()
66
- .then(() => options.onSignal(signal))
67
- .catch((error) => {
68
- console.error("Graceful shutdown error:", error);
69
- })
70
- .finally(() => finish(signal));
71
- return;
72
- }
73
- if (signal === "SIGINT" && firstSignal === "SIGINT") {
74
- options.onForce?.();
75
- finish(signal);
76
- }
77
- };
78
- const handlers = new Map();
79
85
  for (const sig of HANDLED_SIGNALS) {
80
- const listener = () => handle(sig);
81
- handlers.set(sig, listener);
82
- process.on(sig, listener);
86
+ process.on(sig, () => handle(state, sig));
83
87
  }
84
- return {
85
- uninstall: () => {
86
- for (const [sig, listener] of handlers) {
87
- process.removeListener(sig, listener);
88
- }
89
- handlers.clear();
90
- clearTimer();
91
- },
92
- };
93
88
  };
94
89
  //# sourceMappingURL=graceful-shutdown.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"graceful-shutdown.js","sourceRoot":"","sources":["../src/graceful-shutdown.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"graceful-shutdown.js","sourceRoot":"","sources":["../src/graceful-shutdown.ts"],"names":[],"mappings":"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","sourcesContent":["import { error } from \"./log.js\";\n\nconst HANDLED_SIGNALS = [\"SIGINT\", \"SIGTERM\", \"SIGHUP\"] as const satisfies NodeJS.Signals[];\nconst DEFAULT_FORCE_KILL_TIMEOUT_MS = 5000;\nconst DEFAULT_COALESCE_WINDOW_MS = 500;\n\n/**\n * Maps a terminating signal to its conventional process exit code (130 for `SIGINT`, 143 otherwise),\n * or 0 when no signal is given.\n *\n * @param signal The signal that triggered termination, or `null`.\n */\nexport const exitCodeForSignal = (signal: NodeJS.Signals | null): number => {\n if (!signal) return 0;\n return signal === \"SIGINT\" ? 130 : 143;\n};\n\nexport type GracefulShutdownOptions = {\n onSignal: (signal: NodeJS.Signals) => void | Promise<void>;\n onForce?: () => void;\n forceKillAfterMs?: number;\n coalesceWindowMs?: number;\n exitCode?: (signal: NodeJS.Signals, graceful: boolean) => number;\n};\n\ntype ShutdownState = {\n options: GracefulShutdownOptions;\n forceKillMs: number;\n coalesceWindowMs: number;\n firstSignal: NodeJS.Signals | null;\n exited: boolean;\n coalescing: boolean;\n forceTimer: NodeJS.Timeout | null;\n coalesceTimer: NodeJS.Timeout | null;\n};\n\nconst clearTimers = (state: ShutdownState): void => {\n if (state.forceTimer) {\n clearTimeout(state.forceTimer);\n state.forceTimer = null;\n }\n if (state.coalesceTimer) {\n clearTimeout(state.coalesceTimer);\n state.coalesceTimer = null;\n }\n};\n\nconst finish = (state: ShutdownState, signal: NodeJS.Signals, graceful: boolean): void => {\n if (state.exited) return;\n state.exited = true;\n clearTimers(state);\n const { exitCode } = state.options;\n const code = exitCode ? exitCode(signal, graceful) : graceful ? 0 : exitCodeForSignal(signal);\n process.exit(code);\n};\n\nconst beginShutdown = (state: ShutdownState, signal: NodeJS.Signals): void => {\n state.firstSignal = signal;\n if (state.coalesceWindowMs > 0) {\n state.coalescing = true;\n state.coalesceTimer = setTimeout(() => {\n state.coalescing = false;\n }, state.coalesceWindowMs);\n state.coalesceTimer.unref();\n }\n if (state.options.onForce && state.forceKillMs > 0) {\n state.forceTimer = setTimeout(() => {\n state.options.onForce?.();\n finish(state, signal, false);\n }, state.forceKillMs);\n state.forceTimer.unref();\n }\n Promise.resolve()\n .then(() => state.options.onSignal(signal))\n .then(\n () => finish(state, signal, true),\n (reason: unknown) => {\n error(\"graceful shutdown failed\", reason);\n finish(state, signal, false);\n },\n );\n};\n\nconst handle = (state: ShutdownState, signal: NodeJS.Signals): void => {\n if (state.firstSignal === null) {\n beginShutdown(state, signal);\n return;\n }\n if (state.coalescing) return;\n state.options.onForce?.();\n finish(state, signal, false);\n};\n\n/**\n * Registers handlers for `SIGINT`, `SIGTERM`, and `SIGHUP` that run the given cleanup callback once\n * and then exit, forcing exit if a repeated signal arrives or the cleanup exceeds its timeout.\n *\n * @param options The shutdown callbacks and timing configuration.\n */\nexport const installGracefulShutdown = (options: GracefulShutdownOptions): void => {\n const state: ShutdownState = {\n options,\n forceKillMs: options.forceKillAfterMs ?? DEFAULT_FORCE_KILL_TIMEOUT_MS,\n coalesceWindowMs: options.coalesceWindowMs ?? DEFAULT_COALESCE_WINDOW_MS,\n firstSignal: null,\n exited: false,\n coalescing: false,\n forceTimer: null,\n coalesceTimer: null,\n };\n for (const sig of HANDLED_SIGNALS) {\n process.on(sig, () => handle(state, sig));\n }\n};\n"]}
package/dist/index.d.ts CHANGED
@@ -1,7 +1,10 @@
1
- export type { AnyClass } from "./class.js";
2
- export { isShallowArrayEqual, isShallowEqual, omit, reverseNumericEnum } from "./collection.js";
3
- export { errorMessage } from "./error.js";
4
- export { exitCodeForSignal, type GracefulShutdownHandle, installGracefulShutdown, } from "./graceful-shutdown.js";
5
- export { quote, toIdentifier } from "./source.js";
6
- export { toCamelCase, toKebabCase, toPascalCase, toUpperFirst } from "./string.js";
1
+ export { type AnyClass, getParentClass, walkClassChain } from "./class.js";
2
+ export { isSameArray, isShallowEqual, sortStrings, sortStringsBy, uniqBy } from "./collection.js";
3
+ export { errorMessage, formatChildProcessError, normalizeError } from "./error.js";
4
+ export { exitCodeForSignal, installGracefulShutdown } from "./graceful-shutdown.js";
5
+ export { createLogger, debug, error, info, Logger, type LoggerOptions, logger, type OutputStream, warn, } from "./log.js";
6
+ export { packageVersion } from "./package-version.js";
7
+ export { callMethod } from "./reflect.js";
8
+ export { sanitizeIdentifier, sourceStringLiteral, toCamelIdentifier } from "./source.js";
9
+ export { lowerFirst, toCamelCase, toKebabCase, toPascalCase, upperFirst } from "./string.js";
7
10
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAC3C,OAAO,EAAE,mBAAmB,EAAE,cAAc,EAAE,IAAI,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AAChG,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC1C,OAAO,EACH,iBAAiB,EACjB,KAAK,sBAAsB,EAC3B,uBAAuB,GAC1B,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAAE,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAClD,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,QAAQ,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAC3E,OAAO,EAAE,WAAW,EAAE,cAAc,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AAClG,OAAO,EAAE,YAAY,EAAE,uBAAuB,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AACnF,OAAO,EAAE,iBAAiB,EAAE,uBAAuB,EAAE,MAAM,wBAAwB,CAAC;AACpF,OAAO,EACH,YAAY,EACZ,KAAK,EACL,KAAK,EACL,IAAI,EACJ,MAAM,EACN,KAAK,aAAa,EAClB,MAAM,EACN,KAAK,YAAY,EACjB,IAAI,GACP,MAAM,UAAU,CAAC;AAClB,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,EAAE,kBAAkB,EAAE,mBAAmB,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AACzF,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,WAAW,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC"}
package/dist/index.js CHANGED
@@ -1,6 +1,10 @@
1
- export { isShallowArrayEqual, isShallowEqual, omit, reverseNumericEnum } from "./collection.js";
2
- export { errorMessage } from "./error.js";
3
- export { exitCodeForSignal, installGracefulShutdown, } from "./graceful-shutdown.js";
4
- export { quote, toIdentifier } from "./source.js";
5
- export { toCamelCase, toKebabCase, toPascalCase, toUpperFirst } from "./string.js";
1
+ export { getParentClass, walkClassChain } from "./class.js";
2
+ export { isSameArray, isShallowEqual, sortStrings, sortStringsBy, uniqBy } from "./collection.js";
3
+ export { errorMessage, formatChildProcessError, normalizeError } from "./error.js";
4
+ export { exitCodeForSignal, installGracefulShutdown } from "./graceful-shutdown.js";
5
+ export { createLogger, debug, error, info, Logger, logger, warn, } from "./log.js";
6
+ export { packageVersion } from "./package-version.js";
7
+ export { callMethod } from "./reflect.js";
8
+ export { sanitizeIdentifier, sourceStringLiteral, toCamelIdentifier } from "./source.js";
9
+ export { lowerFirst, toCamelCase, toKebabCase, toPascalCase, upperFirst } from "./string.js";
6
10
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,mBAAmB,EAAE,cAAc,EAAE,IAAI,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AAChG,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC1C,OAAO,EACH,iBAAiB,EAEjB,uBAAuB,GAC1B,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAAE,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAClD,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAiB,cAAc,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAC3E,OAAO,EAAE,WAAW,EAAE,cAAc,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AAClG,OAAO,EAAE,YAAY,EAAE,uBAAuB,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AACnF,OAAO,EAAE,iBAAiB,EAAE,uBAAuB,EAAE,MAAM,wBAAwB,CAAC;AACpF,OAAO,EACH,YAAY,EACZ,KAAK,EACL,KAAK,EACL,IAAI,EACJ,MAAM,EAEN,MAAM,EAEN,IAAI,GACP,MAAM,UAAU,CAAC;AAClB,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,EAAE,kBAAkB,EAAE,mBAAmB,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AACzF,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,WAAW,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC","sourcesContent":["export { type AnyClass, getParentClass, walkClassChain } from \"./class.js\";\nexport { isSameArray, isShallowEqual, sortStrings, sortStringsBy, uniqBy } from \"./collection.js\";\nexport { errorMessage, formatChildProcessError, normalizeError } from \"./error.js\";\nexport { exitCodeForSignal, installGracefulShutdown } from \"./graceful-shutdown.js\";\nexport {\n createLogger,\n debug,\n error,\n info,\n Logger,\n type LoggerOptions,\n logger,\n type OutputStream,\n warn,\n} from \"./log.js\";\nexport { packageVersion } from \"./package-version.js\";\nexport { callMethod } from \"./reflect.js\";\nexport { sanitizeIdentifier, sourceStringLiteral, toCamelIdentifier } from \"./source.js\";\nexport { lowerFirst, toCamelCase, toKebabCase, toPascalCase, upperFirst } from \"./string.js\";\n"]}
package/dist/log.d.ts ADDED
@@ -0,0 +1,103 @@
1
+ /**
2
+ * Minimal writable-stream shape a {@link Logger} writes formatted lines to.
3
+ */
4
+ export type OutputStream = {
5
+ write(chunk: string): unknown;
6
+ /** Whether the stream is a terminal, used to decide if colored output is emitted. */
7
+ isTTY?: boolean | undefined;
8
+ };
9
+ /**
10
+ * Options for constructing a {@link Logger}.
11
+ */
12
+ export type LoggerOptions = {
13
+ /** Namespace appended to the log prefix and matched against debug configuration. */
14
+ namespace?: string | undefined;
15
+ /** Stream to write log lines to; defaults to `process.stderr`. */
16
+ stream?: OutputStream | undefined;
17
+ /** Forces debug output on or off; when omitted it is resolved from `--debug` and `GTKX_DEBUG`. */
18
+ debugEnabled?: boolean | undefined;
19
+ };
20
+ /**
21
+ * Writes prefixed, optionally colored log lines to an output stream, with debug lines gated by
22
+ * command-line and environment configuration.
23
+ */
24
+ export declare class Logger {
25
+ private stream;
26
+ private prefix;
27
+ private debugEnabled;
28
+ private colors;
29
+ /**
30
+ * @param options Namespace, target stream, and debug configuration for the logger.
31
+ */
32
+ constructor(options?: LoggerOptions);
33
+ private write;
34
+ /**
35
+ * Writes an informational line.
36
+ *
37
+ * @param message The message text.
38
+ * @param rest Extra values appended after the message, formatted for display.
39
+ */
40
+ info(message: string, ...rest: unknown[]): void;
41
+ /**
42
+ * Writes a line marked as a warning.
43
+ *
44
+ * @param message The message text.
45
+ * @param rest Extra values appended after the message, formatted for display.
46
+ */
47
+ warn(message: string, ...rest: unknown[]): void;
48
+ /**
49
+ * Writes a line marked as an error.
50
+ *
51
+ * @param message The message text.
52
+ * @param rest Extra values appended after the message, formatted for display.
53
+ */
54
+ error(message: string, ...rest: unknown[]): void;
55
+ /**
56
+ * Writes a line only when debug output is enabled for this logger.
57
+ *
58
+ * @param message The message text.
59
+ * @param rest Extra values appended after the message, formatted for display.
60
+ */
61
+ debug(message: string, ...rest: unknown[]): void;
62
+ }
63
+ /**
64
+ * Creates a {@link Logger} scoped to the given namespace.
65
+ *
66
+ * @param namespace Namespace added to the log prefix and matched against debug configuration.
67
+ * @param options Further logger options excluding the namespace.
68
+ */
69
+ export declare const createLogger: (namespace: string, options?: Omit<LoggerOptions, "namespace">) => Logger;
70
+ /**
71
+ * The default namespace-less {@link Logger} backing the module-level {@link info}, {@link warn},
72
+ * {@link error}, and {@link debug} functions.
73
+ */
74
+ export declare const logger: Logger;
75
+ /**
76
+ * Writes an informational line through the shared {@link logger}.
77
+ *
78
+ * @param message The message text.
79
+ * @param rest Extra values appended after the message, formatted for display.
80
+ */
81
+ export declare const info: (message: string, ...rest: unknown[]) => void;
82
+ /**
83
+ * Writes a warning line through the shared {@link logger}.
84
+ *
85
+ * @param message The message text.
86
+ * @param rest Extra values appended after the message, formatted for display.
87
+ */
88
+ export declare const warn: (message: string, ...rest: unknown[]) => void;
89
+ /**
90
+ * Writes an error line through the shared {@link logger}.
91
+ *
92
+ * @param message The message text.
93
+ * @param rest Extra values appended after the message, formatted for display.
94
+ */
95
+ export declare const error: (message: string, ...rest: unknown[]) => void;
96
+ /**
97
+ * Writes a debug line through the shared {@link logger} when debug output is enabled.
98
+ *
99
+ * @param message The message text.
100
+ * @param rest Extra values appended after the message, formatted for display.
101
+ */
102
+ export declare const debug: (message: string, ...rest: unknown[]) => void;
103
+ //# sourceMappingURL=log.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"log.d.ts","sourceRoot":"","sources":["../src/log.ts"],"names":[],"mappings":"AAMA;;GAEG;AACH,MAAM,MAAM,YAAY,GAAG;IACvB,KAAK,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC;IAC9B,qFAAqF;IACrF,KAAK,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;CAC/B,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,aAAa,GAAG;IACxB,oFAAoF;IACpF,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC/B,kEAAkE;IAClE,MAAM,CAAC,EAAE,YAAY,GAAG,SAAS,CAAC;IAClC,kGAAkG;IAClG,YAAY,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;CACtC,CAAC;AA0BF;;;GAGG;AACH,qBAAa,MAAM;IACf,OAAO,CAAC,MAAM,CAAe;IAC7B,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,YAAY,CAAU;IAC9B,OAAO,CAAC,MAAM,CAAS;IAEvB;;OAEG;IACH,YAAY,OAAO,GAAE,aAAkB,EAKtC;IAED,OAAO,CAAC,KAAK;IAKb;;;;;OAKG;IACH,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,IAAI,CAE9C;IAED;;;;;OAKG;IACH,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,IAAI,CAE9C;IAED;;;;;OAKG;IACH,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,IAAI,CAE/C;IAED;;;;;OAKG;IACH,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,IAAI,CAG/C;CACJ;AAED;;;;;GAKG;AACH,eAAO,MAAM,YAAY,cAAe,MAAM,YAAW,IAAI,CAAC,aAAa,EAAE,WAAW,CAAC,KAAQ,MACxD,CAAC;AAE1C;;;GAGG;AACH,eAAO,MAAM,MAAM,EAAE,MAAqB,CAAC;AAE3C;;;;;GAKG;AACH,eAAO,MAAM,IAAI,YAAa,MAAM,WAAW,OAAO,EAAE,KAAG,IAAqC,CAAC;AAEjG;;;;;GAKG;AACH,eAAO,MAAM,IAAI,YAAa,MAAM,WAAW,OAAO,EAAE,KAAG,IAAqC,CAAC;AAEjG;;;;;GAKG;AACH,eAAO,MAAM,KAAK,YAAa,MAAM,WAAW,OAAO,EAAE,KAAG,IAAsC,CAAC;AAEnG;;;;;GAKG;AACH,eAAO,MAAM,KAAK,YAAa,MAAM,WAAW,OAAO,EAAE,KAAG,IAAsC,CAAC"}
package/dist/log.js ADDED
@@ -0,0 +1,129 @@
1
+ import pc from "picocolors";
2
+ const BASE_PREFIX = "[gtkx]";
3
+ const colorsFor = (stream) => pc.createColors(pc.isColorSupported && stream.isTTY === true);
4
+ const formatValue = (value) => {
5
+ if (typeof value === "string")
6
+ return value;
7
+ if (value instanceof Error)
8
+ return value.stack ?? value.message;
9
+ try {
10
+ return JSON.stringify(value);
11
+ }
12
+ catch {
13
+ return String(value);
14
+ }
15
+ };
16
+ const resolveDebugEnabled = (namespace, argv, env) => {
17
+ if (argv.includes("--debug"))
18
+ return true;
19
+ const spec = env.GTKX_DEBUG;
20
+ if (!spec)
21
+ return false;
22
+ const names = spec.split(/[\s,]+/).filter((name) => name.length > 0);
23
+ if (names.includes("1") || names.includes("*"))
24
+ return true;
25
+ return namespace !== undefined && names.includes(namespace);
26
+ };
27
+ const prefixFor = (namespace) => namespace === undefined ? BASE_PREFIX : `[gtkx:${namespace}]`;
28
+ /**
29
+ * Writes prefixed, optionally colored log lines to an output stream, with debug lines gated by
30
+ * command-line and environment configuration.
31
+ */
32
+ export class Logger {
33
+ stream;
34
+ prefix;
35
+ debugEnabled;
36
+ colors;
37
+ /**
38
+ * @param options Namespace, target stream, and debug configuration for the logger.
39
+ */
40
+ constructor(options = {}) {
41
+ this.stream = options.stream ?? process.stderr;
42
+ this.prefix = prefixFor(options.namespace);
43
+ this.debugEnabled = options.debugEnabled ?? resolveDebugEnabled(options.namespace, process.argv, process.env);
44
+ this.colors = colorsFor(this.stream);
45
+ }
46
+ write(message, rest) {
47
+ const suffix = rest.length === 0 ? "" : ` ${rest.map(formatValue).join(" ")}`;
48
+ this.stream.write(`${this.prefix} ${message}${suffix}\n`);
49
+ }
50
+ /**
51
+ * Writes an informational line.
52
+ *
53
+ * @param message The message text.
54
+ * @param rest Extra values appended after the message, formatted for display.
55
+ */
56
+ info(message, ...rest) {
57
+ this.write(message, rest);
58
+ }
59
+ /**
60
+ * Writes a line marked as a warning.
61
+ *
62
+ * @param message The message text.
63
+ * @param rest Extra values appended after the message, formatted for display.
64
+ */
65
+ warn(message, ...rest) {
66
+ this.write(`${this.colors.yellow("warn")} ${message}`, rest);
67
+ }
68
+ /**
69
+ * Writes a line marked as an error.
70
+ *
71
+ * @param message The message text.
72
+ * @param rest Extra values appended after the message, formatted for display.
73
+ */
74
+ error(message, ...rest) {
75
+ this.write(`${this.colors.red("error")} ${message}`, rest);
76
+ }
77
+ /**
78
+ * Writes a line only when debug output is enabled for this logger.
79
+ *
80
+ * @param message The message text.
81
+ * @param rest Extra values appended after the message, formatted for display.
82
+ */
83
+ debug(message, ...rest) {
84
+ if (!this.debugEnabled)
85
+ return;
86
+ this.write(message, rest);
87
+ }
88
+ }
89
+ /**
90
+ * Creates a {@link Logger} scoped to the given namespace.
91
+ *
92
+ * @param namespace Namespace added to the log prefix and matched against debug configuration.
93
+ * @param options Further logger options excluding the namespace.
94
+ */
95
+ export const createLogger = (namespace, options = {}) => new Logger({ ...options, namespace });
96
+ /**
97
+ * The default namespace-less {@link Logger} backing the module-level {@link info}, {@link warn},
98
+ * {@link error}, and {@link debug} functions.
99
+ */
100
+ export const logger = new Logger();
101
+ /**
102
+ * Writes an informational line through the shared {@link logger}.
103
+ *
104
+ * @param message The message text.
105
+ * @param rest Extra values appended after the message, formatted for display.
106
+ */
107
+ export const info = (message, ...rest) => logger.info(message, ...rest);
108
+ /**
109
+ * Writes a warning line through the shared {@link logger}.
110
+ *
111
+ * @param message The message text.
112
+ * @param rest Extra values appended after the message, formatted for display.
113
+ */
114
+ export const warn = (message, ...rest) => logger.warn(message, ...rest);
115
+ /**
116
+ * Writes an error line through the shared {@link logger}.
117
+ *
118
+ * @param message The message text.
119
+ * @param rest Extra values appended after the message, formatted for display.
120
+ */
121
+ export const error = (message, ...rest) => logger.error(message, ...rest);
122
+ /**
123
+ * Writes a debug line through the shared {@link logger} when debug output is enabled.
124
+ *
125
+ * @param message The message text.
126
+ * @param rest Extra values appended after the message, formatted for display.
127
+ */
128
+ export const debug = (message, ...rest) => logger.debug(message, ...rest);
129
+ //# sourceMappingURL=log.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"log.js","sourceRoot":"","sources":["../src/log.ts"],"names":[],"mappings":"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","sourcesContent":["import pc from \"picocolors\";\n\nconst BASE_PREFIX = \"[gtkx]\";\n\ntype Colors = ReturnType<typeof pc.createColors>;\n\n/**\n * Minimal writable-stream shape a {@link Logger} writes formatted lines to.\n */\nexport type OutputStream = {\n write(chunk: string): unknown;\n /** Whether the stream is a terminal, used to decide if colored output is emitted. */\n isTTY?: boolean | undefined;\n};\n\n/**\n * Options for constructing a {@link Logger}.\n */\nexport type LoggerOptions = {\n /** Namespace appended to the log prefix and matched against debug configuration. */\n namespace?: string | undefined;\n /** Stream to write log lines to; defaults to `process.stderr`. */\n stream?: OutputStream | undefined;\n /** Forces debug output on or off; when omitted it is resolved from `--debug` and `GTKX_DEBUG`. */\n debugEnabled?: boolean | undefined;\n};\n\nconst colorsFor = (stream: OutputStream): Colors => pc.createColors(pc.isColorSupported && stream.isTTY === true);\n\nconst formatValue = (value: unknown): string => {\n if (typeof value === \"string\") return value;\n if (value instanceof Error) return value.stack ?? value.message;\n try {\n return JSON.stringify(value);\n } catch {\n return String(value);\n }\n};\n\nconst resolveDebugEnabled = (namespace: string | undefined, argv: string[], env: NodeJS.ProcessEnv): boolean => {\n if (argv.includes(\"--debug\")) return true;\n const spec = env.GTKX_DEBUG;\n if (!spec) return false;\n const names = spec.split(/[\\s,]+/).filter((name) => name.length > 0);\n if (names.includes(\"1\") || names.includes(\"*\")) return true;\n return namespace !== undefined && names.includes(namespace);\n};\n\nconst prefixFor = (namespace: string | undefined): string =>\n namespace === undefined ? BASE_PREFIX : `[gtkx:${namespace}]`;\n\n/**\n * Writes prefixed, optionally colored log lines to an output stream, with debug lines gated by\n * command-line and environment configuration.\n */\nexport class Logger {\n private stream: OutputStream;\n private prefix: string;\n private debugEnabled: boolean;\n private colors: Colors;\n\n /**\n * @param options Namespace, target stream, and debug configuration for the logger.\n */\n constructor(options: LoggerOptions = {}) {\n this.stream = options.stream ?? process.stderr;\n this.prefix = prefixFor(options.namespace);\n this.debugEnabled = options.debugEnabled ?? resolveDebugEnabled(options.namespace, process.argv, process.env);\n this.colors = colorsFor(this.stream);\n }\n\n private write(message: string, rest: unknown[]): void {\n const suffix = rest.length === 0 ? \"\" : ` ${rest.map(formatValue).join(\" \")}`;\n this.stream.write(`${this.prefix} ${message}${suffix}\\n`);\n }\n\n /**\n * Writes an informational line.\n *\n * @param message The message text.\n * @param rest Extra values appended after the message, formatted for display.\n */\n info(message: string, ...rest: unknown[]): void {\n this.write(message, rest);\n }\n\n /**\n * Writes a line marked as a warning.\n *\n * @param message The message text.\n * @param rest Extra values appended after the message, formatted for display.\n */\n warn(message: string, ...rest: unknown[]): void {\n this.write(`${this.colors.yellow(\"warn\")} ${message}`, rest);\n }\n\n /**\n * Writes a line marked as an error.\n *\n * @param message The message text.\n * @param rest Extra values appended after the message, formatted for display.\n */\n error(message: string, ...rest: unknown[]): void {\n this.write(`${this.colors.red(\"error\")} ${message}`, rest);\n }\n\n /**\n * Writes a line only when debug output is enabled for this logger.\n *\n * @param message The message text.\n * @param rest Extra values appended after the message, formatted for display.\n */\n debug(message: string, ...rest: unknown[]): void {\n if (!this.debugEnabled) return;\n this.write(message, rest);\n }\n}\n\n/**\n * Creates a {@link Logger} scoped to the given namespace.\n *\n * @param namespace Namespace added to the log prefix and matched against debug configuration.\n * @param options Further logger options excluding the namespace.\n */\nexport const createLogger = (namespace: string, options: Omit<LoggerOptions, \"namespace\"> = {}): Logger =>\n new Logger({ ...options, namespace });\n\n/**\n * The default namespace-less {@link Logger} backing the module-level {@link info}, {@link warn},\n * {@link error}, and {@link debug} functions.\n */\nexport const logger: Logger = new Logger();\n\n/**\n * Writes an informational line through the shared {@link logger}.\n *\n * @param message The message text.\n * @param rest Extra values appended after the message, formatted for display.\n */\nexport const info = (message: string, ...rest: unknown[]): void => logger.info(message, ...rest);\n\n/**\n * Writes a warning line through the shared {@link logger}.\n *\n * @param message The message text.\n * @param rest Extra values appended after the message, formatted for display.\n */\nexport const warn = (message: string, ...rest: unknown[]): void => logger.warn(message, ...rest);\n\n/**\n * Writes an error line through the shared {@link logger}.\n *\n * @param message The message text.\n * @param rest Extra values appended after the message, formatted for display.\n */\nexport const error = (message: string, ...rest: unknown[]): void => logger.error(message, ...rest);\n\n/**\n * Writes a debug line through the shared {@link logger} when debug output is enabled.\n *\n * @param message The message text.\n * @param rest Extra values appended after the message, formatted for display.\n */\nexport const debug = (message: string, ...rest: unknown[]): void => logger.debug(message, ...rest);\n"]}
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Reads the `version` field from the `package.json` next to the calling module.
3
+ *
4
+ * @param importMetaUrl The caller's `import.meta.url`, used to resolve the sibling `package.json`.
5
+ */
6
+ export declare const packageVersion: (importMetaUrl: string) => string;
7
+ //# sourceMappingURL=package-version.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"package-version.d.ts","sourceRoot":"","sources":["../src/package-version.ts"],"names":[],"mappings":"AAEA;;;;GAIG;AACH,eAAO,MAAM,cAAc,kBAAmB,MAAM,KAAG,MAC6B,CAAC"}
@@ -0,0 +1,8 @@
1
+ import { createRequire } from "node:module";
2
+ /**
3
+ * Reads the `version` field from the `package.json` next to the calling module.
4
+ *
5
+ * @param importMetaUrl The caller's `import.meta.url`, used to resolve the sibling `package.json`.
6
+ */
7
+ export const packageVersion = (importMetaUrl) => createRequire(importMetaUrl)("../package.json").version;
8
+ //# sourceMappingURL=package-version.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"package-version.js","sourceRoot":"","sources":["../src/package-version.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAE5C;;;;GAIG;AACH,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,aAAqB,EAAU,EAAE,CAC3D,aAAa,CAAC,aAAa,CAAC,CAAC,iBAAiB,CAAyB,CAAC,OAAO,CAAC","sourcesContent":["import { createRequire } from \"node:module\";\n\n/**\n * Reads the `version` field from the `package.json` next to the calling module.\n *\n * @param importMetaUrl The caller's `import.meta.url`, used to resolve the sibling `package.json`.\n */\nexport const packageVersion = (importMetaUrl: string): string =>\n (createRequire(importMetaUrl)(\"../package.json\") as { version: string }).version;\n"]}
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Calls the named method on `target` with the given arguments, returning `undefined` when the
3
+ * property is missing or not callable.
4
+ *
5
+ * @param target The object to read the method from and bind as `this`.
6
+ * @param method The method name to look up.
7
+ * @param args Arguments passed to the method.
8
+ * @returns The method's return value, or `undefined` when it is not a function.
9
+ */
10
+ export declare const callMethod: (target: object, method: string, args: unknown[]) => unknown;
11
+ //# sourceMappingURL=reflect.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reflect.d.ts","sourceRoot":"","sources":["../src/reflect.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,eAAO,MAAM,UAAU,WAAY,MAAM,UAAU,MAAM,QAAQ,OAAO,EAAE,KAAG,OAG5E,CAAC"}