@meadown/logger 1.8.9 → 1.8.10

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.
@@ -11,7 +11,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
11
11
  Object.defineProperty(exports, "__esModule", { value: true });
12
12
  exports.default = createLog;
13
13
  const getCaller_js_1 = __importDefault(require("../caller/getCaller.js"));
14
- const writeLog_js_1 = require("./writeLog.js");
14
+ const index_js_1 = require("./writeLog/index.js");
15
15
  const config_js_1 = require("../config.js");
16
16
  /**
17
17
  * Builds a log function bound to a console channel and tag. The returned closure
@@ -24,6 +24,6 @@ function createLog(channel, tag) {
24
24
  if (!(0, config_js_1.isLogAllowed)())
25
25
  return;
26
26
  const caller = (0, getCaller_js_1.default)();
27
- (0, writeLog_js_1.writeLog)({ channel, tag, args, caller });
27
+ (0, index_js_1.writeLog)({ channel, tag, args, caller });
28
28
  };
29
29
  }
@@ -0,0 +1,6 @@
1
+ import { type Caller } from "../../caller/getCaller.js";
2
+ /**
3
+ * Renders a caller as a `(file:line)` location — a clickable OSC-8 link on a
4
+ * supporting terminal, plain text otherwise. Pure (no stack access).
5
+ */
6
+ export declare function formatLocation(caller: Caller, interactive: boolean): string;
@@ -0,0 +1,19 @@
1
+ "use strict";
2
+ /*
3
+ * formatLocation.ts
4
+ * Created by Dewan Mobashirul
5
+ * Copyright (c) 2026 dewan-meadown
6
+ * All rights reserved
7
+ */
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.formatLocation = formatLocation;
10
+ const link_js_1 = require("../../decorations/link.js");
11
+ /**
12
+ * Renders a caller as a `(file:line)` location — a clickable OSC-8 link on a
13
+ * supporting terminal, plain text otherwise. Pure (no stack access).
14
+ */
15
+ function formatLocation(caller, interactive) {
16
+ if (caller.file !== null && caller.line !== null && interactive)
17
+ return (0, link_js_1.hyperlink)(caller.label, (0, link_js_1.fileUrl)(caller.file));
18
+ return caller.label;
19
+ }
@@ -1,9 +1,6 @@
1
- import { type LogChannel } from "../constants.js";
2
- import { type Caller } from "../caller/getCaller.js";
3
- /** How many lines a long message shows before collapsing (0 = all). */
4
- export declare function getVisibleLines(): number;
5
- /** Set how many lines a long message shows before collapsing (0 = all). */
6
- export declare function setVisibleLines(value: number): void;
1
+ import { type LogChannel } from "../../constants.js";
2
+ import { type Caller } from "../../caller/getCaller.js";
3
+ export { getVisibleLines, setVisibleLines } from "./visibleLines.js";
7
4
  /**
8
5
  * Renders and writes one log entry. The `caller` is resolved by the *caller* of
9
6
  * this function (the log closure or `tap`) and passed in, so this helper never
@@ -0,0 +1,48 @@
1
+ "use strict";
2
+ /*
3
+ * index.ts
4
+ * Created by Dewan Mobashirul
5
+ * Copyright (c) 2026 dewan-meadown
6
+ * All rights reserved
7
+ */
8
+ var __importDefault = (this && this.__importDefault) || function (mod) {
9
+ return (mod && mod.__esModule) ? mod : { "default": mod };
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.setVisibleLines = exports.getVisibleLines = void 0;
13
+ exports.writeLog = writeLog;
14
+ const constants_js_1 = require("../../constants.js");
15
+ const getTimeStamp_js_1 = __importDefault(require("../../time/getTimeStamp.js"));
16
+ const color_js_1 = require("../../colors/color.js");
17
+ const isTTY_js_1 = require("../../terminal/isTTY.js");
18
+ const renderMessage_js_1 = require("./renderMessage.js");
19
+ const formatLocation_js_1 = require("./formatLocation.js");
20
+ var visibleLines_js_1 = require("./visibleLines.js");
21
+ Object.defineProperty(exports, "getVisibleLines", { enumerable: true, get: function () { return visibleLines_js_1.getVisibleLines; } });
22
+ Object.defineProperty(exports, "setVisibleLines", { enumerable: true, get: function () { return visibleLines_js_1.setVisibleLines; } });
23
+ /**
24
+ * Renders and writes one log entry. The `caller` is resolved by the *caller* of
25
+ * this function (the log closure or `tap`) and passed in, so this helper never
26
+ * touches the stack — keeping {@link getCaller}'s frame depth correct no matter
27
+ * which user-facing function delegates here.
28
+ */
29
+ function writeLog(opts) {
30
+ const { channel, tag, args, caller } = opts;
31
+ const streamName = channel === "log" ? "stdout" : "stderr";
32
+ // One terminal check drives both color and clickable links — `isTTY` is the
33
+ // single source of truth (DRY). Off when output is piped/redirected.
34
+ const useColor = (0, isTTY_js_1.isTTY)(streamName);
35
+ const paint = (s, c) => useColor ? (0, color_js_1.colorize)(s, c) : s;
36
+ const location = (0, formatLocation_js_1.formatLocation)(caller, useColor);
37
+ const tagOut = paint(tag, constants_js_1.TAG_COLOR[channel]);
38
+ const timeStamp = paint((0, getTimeStamp_js_1.default)(), "teal");
39
+ const locOut = paint(`(${location})`, "dimTeal");
40
+ const connector = paint(constants_js_1.BRANCH, "gray");
41
+ const connectorBottom = paint(constants_js_1.BRANCH_END, "gray");
42
+ const separator = paint(constants_js_1.SEPARATOR, "gray");
43
+ // Layout: the tag, the message hanging off a `├──` branch, then the timestamp
44
+ // and location on a `└──` branch below. Leading `\n` spaces entries apart.
45
+ const message = (0, renderMessage_js_1.renderMessage)(args, useColor);
46
+ const meta = `\n${connectorBottom} ${timeStamp} ${separator} ${locOut}`;
47
+ console[channel](`\n${tagOut}`, `\n${connector}`, message, meta);
48
+ }
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Renders the args into a single message string exactly as console would —
3
+ * objects/errors via util.inspect, `%s`/`%d` format specifiers, and colors when
4
+ * on a terminal — then hang-indents every continuation line so multi-line
5
+ * output stays left-aligned under the branch, and collapses very long output.
6
+ */
7
+ export declare function renderMessage(args: unknown[], useColor: boolean): string;
@@ -0,0 +1,40 @@
1
+ "use strict";
2
+ /*
3
+ * renderMessage.ts
4
+ * Created by Dewan Mobashirul
5
+ * Copyright (c) 2026 dewan-meadown
6
+ * All rights reserved
7
+ */
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.renderMessage = renderMessage;
10
+ const node_util_1 = require("node:util");
11
+ const constants_js_1 = require("../../constants.js");
12
+ const color_js_1 = require("../../colors/color.js");
13
+ const visibleLines_js_1 = require("./visibleLines.js");
14
+ /**
15
+ * Collapses a long multi-line message to {@link visibleLines} lines, replacing
16
+ * the rest with a dimmed `… N more lines` summary. When `visibleLines` is 0
17
+ * (the default) nothing is collapsed — the full message is shown.
18
+ */
19
+ function collapse(text, useColor) {
20
+ if (visibleLines_js_1.visibleLines < 1)
21
+ return text;
22
+ const lines = text.split("\n");
23
+ if (lines.length <= visibleLines_js_1.visibleLines)
24
+ return text;
25
+ const hidden = lines.length - visibleLines_js_1.visibleLines;
26
+ const summary = `${constants_js_1.MESSAGE_INDENT}... ${hidden} more line${hidden === 1 ? "" : "s"}`;
27
+ const visible = lines.slice(0, visibleLines_js_1.visibleLines);
28
+ visible.push(useColor ? (0, color_js_1.colorize)(summary, "gray") : summary);
29
+ return visible.join("\n");
30
+ }
31
+ /**
32
+ * Renders the args into a single message string exactly as console would —
33
+ * objects/errors via util.inspect, `%s`/`%d` format specifiers, and colors when
34
+ * on a terminal — then hang-indents every continuation line so multi-line
35
+ * output stays left-aligned under the branch, and collapses very long output.
36
+ */
37
+ function renderMessage(args, useColor) {
38
+ const text = (0, node_util_1.formatWithOptions)({ colors: useColor }, ...args);
39
+ return collapse(text.replace(/\n/g, `\n${(0, color_js_1.colorize)(constants_js_1.MESSAGE_INDENT, "gray")}`), useColor);
40
+ }
@@ -0,0 +1,6 @@
1
+ /** Max message lines to show before collapsing the rest; 0 (default) shows all. */
2
+ export declare let visibleLines: number;
3
+ /** How many lines a long message shows before collapsing (0 = all). */
4
+ export declare function getVisibleLines(): number;
5
+ /** Set how many lines a long message shows before collapsing (0 = all). */
6
+ export declare function setVisibleLines(value: number): void;
@@ -0,0 +1,22 @@
1
+ "use strict";
2
+ /*
3
+ * visibleLines.ts
4
+ * Created by Dewan Mobashirul
5
+ * Copyright (c) 2026 dewan-meadown
6
+ * All rights reserved
7
+ */
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.visibleLines = void 0;
10
+ exports.getVisibleLines = getVisibleLines;
11
+ exports.setVisibleLines = setVisibleLines;
12
+ const constants_js_1 = require("../../constants.js");
13
+ /** Max message lines to show before collapsing the rest; 0 (default) shows all. */
14
+ exports.visibleLines = constants_js_1.DEFAULT_MAX_LINES;
15
+ /** How many lines a long message shows before collapsing (0 = all). */
16
+ function getVisibleLines() {
17
+ return exports.visibleLines;
18
+ }
19
+ /** Set how many lines a long message shows before collapsing (0 = all). */
20
+ function setVisibleLines(value) {
21
+ exports.visibleLines = Number.isFinite(value) && value > 0 ? Math.floor(value) : 0;
22
+ }
@@ -1,9 +1,5 @@
1
- /**
2
- * Builds a `file://` URL for a path so terminals can open it on click.
3
- * When `line` is provided, appends `:line` so supporting terminals (VS Code,
4
- * iTerm2, WezTerm) jump straight to that line.
5
- */
6
- export declare function fileUrl(file: string, line?: number): string;
1
+ /** Builds a `file://` URL for a path so terminals can open it on click. */
2
+ export declare function fileUrl(file: string): string;
7
3
  /**
8
4
  * Wraps `text` in an OSC-8 terminal hyperlink pointing at `url`. Terminals that
9
5
  * support OSC-8 render `text` as a clickable link; others ignore the escape and
@@ -9,14 +9,9 @@ Object.defineProperty(exports, "__esModule", { value: true });
9
9
  exports.fileUrl = fileUrl;
10
10
  exports.hyperlink = hyperlink;
11
11
  const node_url_1 = require("node:url");
12
- /**
13
- * Builds a `file://` URL for a path so terminals can open it on click.
14
- * When `line` is provided, appends `:line` so supporting terminals (VS Code,
15
- * iTerm2, WezTerm) jump straight to that line.
16
- */
17
- function fileUrl(file, line) {
18
- const base = file.startsWith("file://") ? file : (0, node_url_1.pathToFileURL)(file).href;
19
- return line != null ? `${base}:${line}` : base;
12
+ /** Builds a `file://` URL for a path so terminals can open it on click. */
13
+ function fileUrl(file) {
14
+ return file.startsWith("file://") ? file : (0, node_url_1.pathToFileURL)(file).href;
20
15
  }
21
16
  /**
22
17
  * Wraps `text` in an OSC-8 terminal hyperlink pointing at `url`. Terminals that
package/dist/cjs/index.js CHANGED
@@ -12,7 +12,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
12
12
  exports.logger = void 0;
13
13
  const createLog_js_1 = __importDefault(require("./core/createLog.js"));
14
14
  const createTap_js_1 = __importDefault(require("./tap/createTap.js"));
15
- const writeLog_js_1 = require("./core/writeLog.js");
15
+ const index_js_1 = require("./core/writeLog/index.js");
16
16
  /**
17
17
  * Logs to the console, but only outside production. Each line is prefixed with
18
18
  * a level tag, a short local timestamp, and a clickable link to the file it was
@@ -32,8 +32,8 @@ exports.logger = logger;
32
32
  // `maxLines` is a live getter/setter backed by the shared collapse setting, so
33
33
  // setting it once affects info, error, and warn alike.
34
34
  Object.defineProperty(logger, "maxLines", {
35
- get: writeLog_js_1.getVisibleLines,
36
- set: writeLog_js_1.setVisibleLines,
35
+ get: index_js_1.getVisibleLines,
36
+ set: index_js_1.setVisibleLines,
37
37
  enumerable: true,
38
38
  configurable: true,
39
39
  });
@@ -11,7 +11,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
11
11
  Object.defineProperty(exports, "__esModule", { value: true });
12
12
  exports.default = createTap;
13
13
  const getCaller_js_1 = __importDefault(require("../caller/getCaller.js"));
14
- const writeLog_js_1 = require("../core/writeLog.js");
14
+ const index_js_1 = require("../core/writeLog/index.js");
15
15
  const config_js_1 = require("../config.js");
16
16
  const tapAsync_js_1 = require("./tapAsync.js");
17
17
  /**
@@ -38,7 +38,7 @@ function createTap() {
38
38
  (0, tapAsync_js_1.tapAsync)(value, label, caller);
39
39
  }
40
40
  else {
41
- (0, writeLog_js_1.writeLog)({
41
+ (0, index_js_1.writeLog)({
42
42
  channel: "log",
43
43
  tag: "[TAP]",
44
44
  args: label === undefined ? [value] : [label, value],
@@ -14,7 +14,7 @@ exports.isThenable = isThenable;
14
14
  exports.tapAsync = tapAsync;
15
15
  const node_perf_hooks_1 = require("node:perf_hooks");
16
16
  const node_util_1 = require("node:util");
17
- const writeLog_js_1 = require("../core/writeLog.js");
17
+ const index_js_1 = require("../core/writeLog/index.js");
18
18
  const color_js_1 = require("../colors/color.js");
19
19
  const isTTY_js_1 = require("../terminal/isTTY.js");
20
20
  /** Whether `value` is thenable (a promise we can await + time). */
@@ -151,7 +151,7 @@ function tapAsync(promise, label, caller) {
151
151
  clone = null;
152
152
  }
153
153
  if (clone === null) {
154
- (0, writeLog_js_1.writeLog)({
154
+ (0, index_js_1.writeLog)({
155
155
  channel: "log", tag: "[TAP]",
156
156
  args: buildBlock(label, ms, resolved, { data: undefined, size: "unknown" }, useColor),
157
157
  caller,
@@ -161,7 +161,7 @@ function tapAsync(promise, label, caller) {
161
161
  const cl = resolved.headers?.get?.("content-length");
162
162
  const tooLarge = cl != null && cl !== "" && Number(cl) > 512 * 1024;
163
163
  if (tooLarge) {
164
- (0, writeLog_js_1.writeLog)({
164
+ (0, index_js_1.writeLog)({
165
165
  channel: "log", tag: "[TAP]",
166
166
  args: buildBlock(label, ms, resolved, { data: "(body too large to display)", size: formatBytes(Number(cl)) }, useColor),
167
167
  caller,
@@ -169,13 +169,13 @@ function tapAsync(promise, label, caller) {
169
169
  return;
170
170
  }
171
171
  void readBody(clone).then((body) => {
172
- (0, writeLog_js_1.writeLog)({ channel: "log", tag: "[TAP]", args: buildBlock(label, ms, resolved, body, useColor), caller });
172
+ (0, index_js_1.writeLog)({ channel: "log", tag: "[TAP]", args: buildBlock(label, ms, resolved, body, useColor), caller });
173
173
  });
174
174
  return;
175
175
  }
176
176
  // Non-Response promise — plain value with elapsed time.
177
177
  const elapsed = formatDuration(ms, useColor);
178
- (0, writeLog_js_1.writeLog)({
178
+ (0, index_js_1.writeLog)({
179
179
  channel: "log", tag: "[TAP]",
180
180
  args: label === undefined ? [elapsed, resolved] : [`${label} ${elapsed}`, resolved],
181
181
  caller,
@@ -183,7 +183,7 @@ function tapAsync(promise, label, caller) {
183
183
  }, (err) => {
184
184
  const ms = Math.round(node_perf_hooks_1.performance.now() - start);
185
185
  const elapsed = formatDuration(ms, useColor);
186
- (0, writeLog_js_1.writeLog)({
186
+ (0, index_js_1.writeLog)({
187
187
  channel: "error", tag: "[TAP]",
188
188
  args: [label === undefined ? `rejected after ${elapsed}` : `${label} rejected after ${elapsed}`, err],
189
189
  caller,
@@ -5,7 +5,7 @@
5
5
  * All rights reserved
6
6
  */
7
7
  import getCaller from "../caller/getCaller.js";
8
- import { writeLog } from "./writeLog.js";
8
+ import { writeLog } from "./writeLog/index.js";
9
9
  import { isLogAllowed } from "../config.js";
10
10
  /**
11
11
  * Builds a log function bound to a console channel and tag. The returned closure
@@ -0,0 +1,6 @@
1
+ import { type Caller } from "../../caller/getCaller.js";
2
+ /**
3
+ * Renders a caller as a `(file:line)` location — a clickable OSC-8 link on a
4
+ * supporting terminal, plain text otherwise. Pure (no stack access).
5
+ */
6
+ export declare function formatLocation(caller: Caller, interactive: boolean): string;
@@ -0,0 +1,16 @@
1
+ /*
2
+ * formatLocation.ts
3
+ * Created by Dewan Mobashirul
4
+ * Copyright (c) 2026 dewan-meadown
5
+ * All rights reserved
6
+ */
7
+ import { fileUrl, hyperlink } from "../../decorations/link.js";
8
+ /**
9
+ * Renders a caller as a `(file:line)` location — a clickable OSC-8 link on a
10
+ * supporting terminal, plain text otherwise. Pure (no stack access).
11
+ */
12
+ export function formatLocation(caller, interactive) {
13
+ if (caller.file !== null && caller.line !== null && interactive)
14
+ return hyperlink(caller.label, fileUrl(caller.file));
15
+ return caller.label;
16
+ }
@@ -1,9 +1,6 @@
1
- import { type LogChannel } from "../constants.js";
2
- import { type Caller } from "../caller/getCaller.js";
3
- /** How many lines a long message shows before collapsing (0 = all). */
4
- export declare function getVisibleLines(): number;
5
- /** Set how many lines a long message shows before collapsing (0 = all). */
6
- export declare function setVisibleLines(value: number): void;
1
+ import { type LogChannel } from "../../constants.js";
2
+ import { type Caller } from "../../caller/getCaller.js";
3
+ export { getVisibleLines, setVisibleLines } from "./visibleLines.js";
7
4
  /**
8
5
  * Renders and writes one log entry. The `caller` is resolved by the *caller* of
9
6
  * this function (the log closure or `tap`) and passed in, so this helper never
@@ -0,0 +1,39 @@
1
+ /*
2
+ * index.ts
3
+ * Created by Dewan Mobashirul
4
+ * Copyright (c) 2026 dewan-meadown
5
+ * All rights reserved
6
+ */
7
+ import { TAG_COLOR, BRANCH, BRANCH_END, SEPARATOR, } from "../../constants.js";
8
+ import getTimeStamp from "../../time/getTimeStamp.js";
9
+ import { colorize } from "../../colors/color.js";
10
+ import { isTTY } from "../../terminal/isTTY.js";
11
+ import { renderMessage } from "./renderMessage.js";
12
+ import { formatLocation } from "./formatLocation.js";
13
+ export { getVisibleLines, setVisibleLines } from "./visibleLines.js";
14
+ /**
15
+ * Renders and writes one log entry. The `caller` is resolved by the *caller* of
16
+ * this function (the log closure or `tap`) and passed in, so this helper never
17
+ * touches the stack — keeping {@link getCaller}'s frame depth correct no matter
18
+ * which user-facing function delegates here.
19
+ */
20
+ export function writeLog(opts) {
21
+ const { channel, tag, args, caller } = opts;
22
+ const streamName = channel === "log" ? "stdout" : "stderr";
23
+ // One terminal check drives both color and clickable links — `isTTY` is the
24
+ // single source of truth (DRY). Off when output is piped/redirected.
25
+ const useColor = isTTY(streamName);
26
+ const paint = (s, c) => useColor ? colorize(s, c) : s;
27
+ const location = formatLocation(caller, useColor);
28
+ const tagOut = paint(tag, TAG_COLOR[channel]);
29
+ const timeStamp = paint(getTimeStamp(), "teal");
30
+ const locOut = paint(`(${location})`, "dimTeal");
31
+ const connector = paint(BRANCH, "gray");
32
+ const connectorBottom = paint(BRANCH_END, "gray");
33
+ const separator = paint(SEPARATOR, "gray");
34
+ // Layout: the tag, the message hanging off a `├──` branch, then the timestamp
35
+ // and location on a `└──` branch below. Leading `\n` spaces entries apart.
36
+ const message = renderMessage(args, useColor);
37
+ const meta = `\n${connectorBottom} ${timeStamp} ${separator} ${locOut}`;
38
+ console[channel](`\n${tagOut}`, `\n${connector}`, message, meta);
39
+ }
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Renders the args into a single message string exactly as console would —
3
+ * objects/errors via util.inspect, `%s`/`%d` format specifiers, and colors when
4
+ * on a terminal — then hang-indents every continuation line so multi-line
5
+ * output stays left-aligned under the branch, and collapses very long output.
6
+ */
7
+ export declare function renderMessage(args: unknown[], useColor: boolean): string;
@@ -0,0 +1,37 @@
1
+ /*
2
+ * renderMessage.ts
3
+ * Created by Dewan Mobashirul
4
+ * Copyright (c) 2026 dewan-meadown
5
+ * All rights reserved
6
+ */
7
+ import { formatWithOptions } from "node:util";
8
+ import { MESSAGE_INDENT } from "../../constants.js";
9
+ import { colorize } from "../../colors/color.js";
10
+ import { visibleLines } from "./visibleLines.js";
11
+ /**
12
+ * Collapses a long multi-line message to {@link visibleLines} lines, replacing
13
+ * the rest with a dimmed `… N more lines` summary. When `visibleLines` is 0
14
+ * (the default) nothing is collapsed — the full message is shown.
15
+ */
16
+ function collapse(text, useColor) {
17
+ if (visibleLines < 1)
18
+ return text;
19
+ const lines = text.split("\n");
20
+ if (lines.length <= visibleLines)
21
+ return text;
22
+ const hidden = lines.length - visibleLines;
23
+ const summary = `${MESSAGE_INDENT}... ${hidden} more line${hidden === 1 ? "" : "s"}`;
24
+ const visible = lines.slice(0, visibleLines);
25
+ visible.push(useColor ? colorize(summary, "gray") : summary);
26
+ return visible.join("\n");
27
+ }
28
+ /**
29
+ * Renders the args into a single message string exactly as console would —
30
+ * objects/errors via util.inspect, `%s`/`%d` format specifiers, and colors when
31
+ * on a terminal — then hang-indents every continuation line so multi-line
32
+ * output stays left-aligned under the branch, and collapses very long output.
33
+ */
34
+ export function renderMessage(args, useColor) {
35
+ const text = formatWithOptions({ colors: useColor }, ...args);
36
+ return collapse(text.replace(/\n/g, `\n${colorize(MESSAGE_INDENT, "gray")}`), useColor);
37
+ }
@@ -0,0 +1,6 @@
1
+ /** Max message lines to show before collapsing the rest; 0 (default) shows all. */
2
+ export declare let visibleLines: number;
3
+ /** How many lines a long message shows before collapsing (0 = all). */
4
+ export declare function getVisibleLines(): number;
5
+ /** Set how many lines a long message shows before collapsing (0 = all). */
6
+ export declare function setVisibleLines(value: number): void;
@@ -0,0 +1,17 @@
1
+ /*
2
+ * visibleLines.ts
3
+ * Created by Dewan Mobashirul
4
+ * Copyright (c) 2026 dewan-meadown
5
+ * All rights reserved
6
+ */
7
+ import { DEFAULT_MAX_LINES } from "../../constants.js";
8
+ /** Max message lines to show before collapsing the rest; 0 (default) shows all. */
9
+ export let visibleLines = DEFAULT_MAX_LINES;
10
+ /** How many lines a long message shows before collapsing (0 = all). */
11
+ export function getVisibleLines() {
12
+ return visibleLines;
13
+ }
14
+ /** Set how many lines a long message shows before collapsing (0 = all). */
15
+ export function setVisibleLines(value) {
16
+ visibleLines = Number.isFinite(value) && value > 0 ? Math.floor(value) : 0;
17
+ }
@@ -1,9 +1,5 @@
1
- /**
2
- * Builds a `file://` URL for a path so terminals can open it on click.
3
- * When `line` is provided, appends `:line` so supporting terminals (VS Code,
4
- * iTerm2, WezTerm) jump straight to that line.
5
- */
6
- export declare function fileUrl(file: string, line?: number): string;
1
+ /** Builds a `file://` URL for a path so terminals can open it on click. */
2
+ export declare function fileUrl(file: string): string;
7
3
  /**
8
4
  * Wraps `text` in an OSC-8 terminal hyperlink pointing at `url`. Terminals that
9
5
  * support OSC-8 render `text` as a clickable link; others ignore the escape and
@@ -5,14 +5,9 @@
5
5
  * All rights reserved
6
6
  */
7
7
  import { pathToFileURL } from "node:url";
8
- /**
9
- * Builds a `file://` URL for a path so terminals can open it on click.
10
- * When `line` is provided, appends `:line` so supporting terminals (VS Code,
11
- * iTerm2, WezTerm) jump straight to that line.
12
- */
13
- export function fileUrl(file, line) {
14
- const base = file.startsWith("file://") ? file : pathToFileURL(file).href;
15
- return line != null ? `${base}:${line}` : base;
8
+ /** Builds a `file://` URL for a path so terminals can open it on click. */
9
+ export function fileUrl(file) {
10
+ return file.startsWith("file://") ? file : pathToFileURL(file).href;
16
11
  }
17
12
  /**
18
13
  * Wraps `text` in an OSC-8 terminal hyperlink pointing at `url`. Terminals that
package/dist/index.js CHANGED
@@ -6,7 +6,7 @@
6
6
  */
7
7
  import createLog from "./core/createLog.js";
8
8
  import createTap from "./tap/createTap.js";
9
- import { getVisibleLines, setVisibleLines } from "./core/writeLog.js";
9
+ import { getVisibleLines, setVisibleLines } from "./core/writeLog/index.js";
10
10
  /**
11
11
  * Logs to the console, but only outside production. Each line is prefixed with
12
12
  * a level tag, a short local timestamp, and a clickable link to the file it was
@@ -5,7 +5,7 @@
5
5
  * All rights reserved
6
6
  */
7
7
  import getCaller from "../caller/getCaller.js";
8
- import { writeLog } from "../core/writeLog.js";
8
+ import { writeLog } from "../core/writeLog/index.js";
9
9
  import { isLogAllowed } from "../config.js";
10
10
  import { isThenable, tapAsync } from "./tapAsync.js";
11
11
  /**
@@ -10,7 +10,7 @@
10
10
  */
11
11
  import { performance } from "node:perf_hooks";
12
12
  import { formatWithOptions } from "node:util";
13
- import { writeLog } from "../core/writeLog.js";
13
+ import { writeLog } from "../core/writeLog/index.js";
14
14
  import { colorize } from "../colors/color.js";
15
15
  import { isTTY } from "../terminal/isTTY.js";
16
16
  /** Whether `value` is thenable (a promise we can await + time). */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@meadown/logger",
3
- "version": "1.8.9",
3
+ "version": "1.8.10",
4
4
  "description": "A development-focused logger for Node.js and TypeScript — zero dependencies, clickable source links, and API response logging built in.",
5
5
  "keywords": [
6
6
  "logger",
@@ -1,92 +0,0 @@
1
- "use strict";
2
- /*
3
- * writeLog.ts
4
- * Created by Dewan Mobashirul
5
- * Copyright (c) 2026 dewan-meadown
6
- * All rights reserved
7
- */
8
- var __importDefault = (this && this.__importDefault) || function (mod) {
9
- return (mod && mod.__esModule) ? mod : { "default": mod };
10
- };
11
- Object.defineProperty(exports, "__esModule", { value: true });
12
- exports.getVisibleLines = getVisibleLines;
13
- exports.setVisibleLines = setVisibleLines;
14
- exports.writeLog = writeLog;
15
- const node_util_1 = require("node:util");
16
- const constants_js_1 = require("../constants.js");
17
- const getTimeStamp_js_1 = __importDefault(require("../time/getTimeStamp.js"));
18
- const link_js_1 = require("../decorations/link.js");
19
- const color_js_1 = require("../colors/color.js");
20
- const isTTY_js_1 = require("../terminal/isTTY.js");
21
- /** Max message lines to show before collapsing the rest; 0 (default) shows all. */
22
- let visibleLines = constants_js_1.DEFAULT_MAX_LINES;
23
- /** How many lines a long message shows before collapsing (0 = all). */
24
- function getVisibleLines() {
25
- return visibleLines;
26
- }
27
- /** Set how many lines a long message shows before collapsing (0 = all). */
28
- function setVisibleLines(value) {
29
- visibleLines = Number.isFinite(value) && value > 0 ? Math.floor(value) : 0;
30
- }
31
- /**
32
- * Collapses a long multi-line message to {@link visibleLines} lines, replacing
33
- * the rest with a dimmed `… N more lines` summary. When `visibleLines` is 0
34
- * (the default) nothing is collapsed — the full message is shown.
35
- */
36
- function collapse(text, useColor) {
37
- if (visibleLines < 1)
38
- return text;
39
- const lines = text.split("\n");
40
- if (lines.length <= visibleLines)
41
- return text;
42
- const hidden = lines.length - visibleLines;
43
- const summary = `${constants_js_1.MESSAGE_INDENT}... ${hidden} more line${hidden === 1 ? "" : "s"}`;
44
- const visible = lines.slice(0, visibleLines);
45
- visible.push(useColor ? (0, color_js_1.colorize)(summary, "gray") : summary);
46
- return visible.join("\n");
47
- }
48
- /**
49
- * Renders the args into a single message string exactly as console would —
50
- * objects/errors via util.inspect, `%s`/`%d` format specifiers, and colors when
51
- * on a terminal — then hang-indents every continuation line so multi-line
52
- * output stays left-aligned under the branch, and collapses very long output.
53
- */
54
- function renderMessage(args, useColor) {
55
- const text = (0, node_util_1.formatWithOptions)({ colors: useColor }, ...args);
56
- return collapse(text.replace(/\n/g, `\n${(0, color_js_1.colorize)(constants_js_1.MESSAGE_INDENT, "gray")}`), useColor);
57
- }
58
- /**
59
- * Renders a caller as a `(file:line)` location — a clickable OSC-8 link on a
60
- * supporting terminal, plain text otherwise. Pure (no stack access).
61
- */
62
- function formatLocation(caller, interactive) {
63
- if (caller.file !== null && caller.line !== null && interactive)
64
- return (0, link_js_1.hyperlink)(caller.label, (0, link_js_1.fileUrl)(caller.file, caller.line));
65
- return caller.label;
66
- }
67
- /**
68
- * Renders and writes one log entry. The `caller` is resolved by the *caller* of
69
- * this function (the log closure or `tap`) and passed in, so this helper never
70
- * touches the stack — keeping {@link getCaller}'s frame depth correct no matter
71
- * which user-facing function delegates here.
72
- */
73
- function writeLog(opts) {
74
- const { channel, tag, args, caller } = opts;
75
- const streamName = channel === "log" ? "stdout" : "stderr";
76
- // One terminal check drives both color and clickable links — `isTTY` is the
77
- // single source of truth (DRY). Off when output is piped/redirected.
78
- const useColor = (0, isTTY_js_1.isTTY)(streamName);
79
- const paint = (s, c) => useColor ? (0, color_js_1.colorize)(s, c) : s;
80
- const location = formatLocation(caller, useColor);
81
- const tagOut = paint(tag, constants_js_1.TAG_COLOR[channel]);
82
- const timeStamp = paint((0, getTimeStamp_js_1.default)(), "teal");
83
- const locOut = paint(`(${location})`, "dimTeal");
84
- const connector = paint(constants_js_1.BRANCH, "gray");
85
- const connectorBottom = paint(constants_js_1.BRANCH_END, "gray");
86
- const separator = paint(constants_js_1.SEPARATOR, "gray");
87
- // Layout: the tag, the message hanging off a `├──` branch, then the timestamp
88
- // and location on a `└──` branch below. Leading `\n` spaces entries apart.
89
- const message = renderMessage(args, useColor);
90
- const meta = `\n${connectorBottom} ${timeStamp} ${separator} ${locOut}`;
91
- console[channel](`\n${tagOut}`, `\n${connector}`, message, meta);
92
- }
@@ -1,84 +0,0 @@
1
- /*
2
- * writeLog.ts
3
- * Created by Dewan Mobashirul
4
- * Copyright (c) 2026 dewan-meadown
5
- * All rights reserved
6
- */
7
- import { formatWithOptions } from "node:util";
8
- import { TAG_COLOR, BRANCH, BRANCH_END, SEPARATOR, MESSAGE_INDENT, DEFAULT_MAX_LINES, } from "../constants.js";
9
- import getTimeStamp from "../time/getTimeStamp.js";
10
- import { fileUrl, hyperlink } from "../decorations/link.js";
11
- import { colorize } from "../colors/color.js";
12
- import { isTTY } from "../terminal/isTTY.js";
13
- /** Max message lines to show before collapsing the rest; 0 (default) shows all. */
14
- let visibleLines = DEFAULT_MAX_LINES;
15
- /** How many lines a long message shows before collapsing (0 = all). */
16
- export function getVisibleLines() {
17
- return visibleLines;
18
- }
19
- /** Set how many lines a long message shows before collapsing (0 = all). */
20
- export function setVisibleLines(value) {
21
- visibleLines = Number.isFinite(value) && value > 0 ? Math.floor(value) : 0;
22
- }
23
- /**
24
- * Collapses a long multi-line message to {@link visibleLines} lines, replacing
25
- * the rest with a dimmed `… N more lines` summary. When `visibleLines` is 0
26
- * (the default) nothing is collapsed — the full message is shown.
27
- */
28
- function collapse(text, useColor) {
29
- if (visibleLines < 1)
30
- return text;
31
- const lines = text.split("\n");
32
- if (lines.length <= visibleLines)
33
- return text;
34
- const hidden = lines.length - visibleLines;
35
- const summary = `${MESSAGE_INDENT}... ${hidden} more line${hidden === 1 ? "" : "s"}`;
36
- const visible = lines.slice(0, visibleLines);
37
- visible.push(useColor ? colorize(summary, "gray") : summary);
38
- return visible.join("\n");
39
- }
40
- /**
41
- * Renders the args into a single message string exactly as console would —
42
- * objects/errors via util.inspect, `%s`/`%d` format specifiers, and colors when
43
- * on a terminal — then hang-indents every continuation line so multi-line
44
- * output stays left-aligned under the branch, and collapses very long output.
45
- */
46
- function renderMessage(args, useColor) {
47
- const text = formatWithOptions({ colors: useColor }, ...args);
48
- return collapse(text.replace(/\n/g, `\n${colorize(MESSAGE_INDENT, "gray")}`), useColor);
49
- }
50
- /**
51
- * Renders a caller as a `(file:line)` location — a clickable OSC-8 link on a
52
- * supporting terminal, plain text otherwise. Pure (no stack access).
53
- */
54
- function formatLocation(caller, interactive) {
55
- if (caller.file !== null && caller.line !== null && interactive)
56
- return hyperlink(caller.label, fileUrl(caller.file, caller.line));
57
- return caller.label;
58
- }
59
- /**
60
- * Renders and writes one log entry. The `caller` is resolved by the *caller* of
61
- * this function (the log closure or `tap`) and passed in, so this helper never
62
- * touches the stack — keeping {@link getCaller}'s frame depth correct no matter
63
- * which user-facing function delegates here.
64
- */
65
- export function writeLog(opts) {
66
- const { channel, tag, args, caller } = opts;
67
- const streamName = channel === "log" ? "stdout" : "stderr";
68
- // One terminal check drives both color and clickable links — `isTTY` is the
69
- // single source of truth (DRY). Off when output is piped/redirected.
70
- const useColor = isTTY(streamName);
71
- const paint = (s, c) => useColor ? colorize(s, c) : s;
72
- const location = formatLocation(caller, useColor);
73
- const tagOut = paint(tag, TAG_COLOR[channel]);
74
- const timeStamp = paint(getTimeStamp(), "teal");
75
- const locOut = paint(`(${location})`, "dimTeal");
76
- const connector = paint(BRANCH, "gray");
77
- const connectorBottom = paint(BRANCH_END, "gray");
78
- const separator = paint(SEPARATOR, "gray");
79
- // Layout: the tag, the message hanging off a `├──` branch, then the timestamp
80
- // and location on a `└──` branch below. Leading `\n` spaces entries apart.
81
- const message = renderMessage(args, useColor);
82
- const meta = `\n${connectorBottom} ${timeStamp} ${separator} ${locOut}`;
83
- console[channel](`\n${tagOut}`, `\n${connector}`, message, meta);
84
- }