@meadown/logger 1.0.1 → 1.2.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 +24 -8
- package/dist/cjs/config.d.ts +6 -0
- package/dist/cjs/config.js +19 -0
- package/dist/cjs/index.d.ts +17 -0
- package/dist/cjs/index.js +24 -0
- package/dist/cjs/package.json +3 -0
- package/dist/cjs/utils/createLog.d.ts +10 -0
- package/dist/cjs/utils/createLog.js +46 -0
- package/dist/cjs/utils/getCaller.d.ts +16 -0
- package/dist/cjs/utils/getCaller.js +37 -0
- package/dist/cjs/utils/getTimeStamp.d.ts +2 -0
- package/dist/cjs/utils/getTimeStamp.js +13 -0
- package/dist/cjs/utils/index.d.ts +4 -0
- package/dist/cjs/utils/index.js +22 -0
- package/dist/cjs/utils/link.d.ts +17 -0
- package/dist/cjs/utils/link.js +63 -0
- package/dist/index.d.ts +3 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -18
- package/dist/index.js.map +1 -1
- package/dist/utils/createLog.d.ts +11 -0
- package/dist/utils/createLog.d.ts.map +1 -0
- package/dist/utils/createLog.js +41 -0
- package/dist/utils/createLog.js.map +1 -0
- package/dist/utils/getCaller.d.ts +17 -0
- package/dist/utils/getCaller.d.ts.map +1 -0
- package/dist/utils/getCaller.js +35 -0
- package/dist/utils/getCaller.js.map +1 -0
- package/dist/utils/index.d.ts +3 -1
- package/dist/utils/index.d.ts.map +1 -1
- package/dist/utils/index.js +3 -1
- package/dist/utils/index.js.map +1 -1
- package/dist/utils/link.d.ts +18 -0
- package/dist/utils/link.d.ts.map +1 -0
- package/dist/utils/link.js +59 -0
- package/dist/utils/link.js.map +1 -0
- package/package.json +13 -7
- package/dist/utils/getFileName.d.ts +0 -6
- package/dist/utils/getFileName.d.ts.map +0 -1
- package/dist/utils/getFileName.js +0 -17
- package/dist/utils/getFileName.js.map +0 -1
package/README.md
CHANGED
|
@@ -5,8 +5,9 @@ remember _which file_ a message came from — and worse, forgetting to pull thos
|
|
|
5
5
|
out before shipping. So I made this.
|
|
6
6
|
|
|
7
7
|
It's basically `console.log` with the rough edges sanded off: every message gets a
|
|
8
|
-
|
|
9
|
-
production, so you can leave your logs where they are and
|
|
8
|
+
level tag, a timestamp, and a **clickable link** to the exact file and line it came
|
|
9
|
+
from. And it stays quiet in production, so you can leave your logs where they are and
|
|
10
|
+
not worry about them.
|
|
10
11
|
|
|
11
12
|
No dependencies. No config. Import it and you're done.
|
|
12
13
|
|
|
@@ -22,7 +23,7 @@ npm install @meadown/logger
|
|
|
22
23
|
import customLog from "@meadown/logger"
|
|
23
24
|
|
|
24
25
|
customLog("Hello world")
|
|
25
|
-
customLog("Auth", "user logged in") //
|
|
26
|
+
customLog("Auth", "user logged in") // every argument is printed as-is, like console.log
|
|
26
27
|
|
|
27
28
|
customLog.warn("This is deprecated")
|
|
28
29
|
customLog.error("Something went wrong")
|
|
@@ -31,13 +32,28 @@ customLog.error("Something went wrong")
|
|
|
31
32
|
You'll see something like:
|
|
32
33
|
|
|
33
34
|
```text
|
|
34
|
-
[INFO]
|
|
35
|
-
|
|
36
|
-
[ERROR] 2026-05-30T10:00:00.000Z (server.ts:60) Something went wrong
|
|
35
|
+
[INFO] 2026-05-30T10:00:00.000Z (server.ts:42)
|
|
36
|
+
Auth user logged in
|
|
37
37
|
```
|
|
38
38
|
|
|
39
|
-
|
|
40
|
-
|
|
39
|
+
Each line is tagged by level — `[INFO]`, `[WARN]`, or `[ERROR]` — followed by the
|
|
40
|
+
timestamp and the source location, with your arguments on the next line.
|
|
41
|
+
|
|
42
|
+
## Click to jump to the source
|
|
43
|
+
|
|
44
|
+
That `(server.ts:42)` at the end of every log isn't just text — in terminals that
|
|
45
|
+
support it, it's a **clickable link** that opens the exact line that wrote the log.
|
|
46
|
+
No more hunting for where a message came from.
|
|
47
|
+
|
|
48
|
+
It works out of the box in editors and terminals like VS Code, iTerm2, WezTerm,
|
|
49
|
+
Kitty, and Windows Terminal. Anywhere else, it quietly falls back to plain
|
|
50
|
+
`(server.ts:42)` text — nothing to configure, never any garbled output.
|
|
51
|
+
|
|
52
|
+
If your terminal supports links but isn't auto-detected, you can force them on:
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
FORCE_HYPERLINK=1 node app.js
|
|
56
|
+
```
|
|
41
57
|
|
|
42
58
|
## What about production?
|
|
43
59
|
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/*
|
|
3
|
+
* config.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.isLogAllowed = isLogAllowed;
|
|
10
|
+
/**
|
|
11
|
+
* Logging is enabled in every environment except production, read directly
|
|
12
|
+
* from `process.env.NODE_ENV`. No configuration — set `NODE_ENV=production`
|
|
13
|
+
* in your runtime to silence logs.
|
|
14
|
+
*/
|
|
15
|
+
function isLogAllowed() {
|
|
16
|
+
// Guard `process` so the logger doesn't throw in non-Node runtimes (browser,
|
|
17
|
+
// edge) where it may be undefined; default to logging when it's absent.
|
|
18
|
+
return typeof process === "undefined" || process.env.NODE_ENV !== "production";
|
|
19
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/** The logger: a callable for info logs, plus `.error` and `.warn` variants. */
|
|
2
|
+
export interface LogFN {
|
|
3
|
+
(...args: unknown[]): void;
|
|
4
|
+
error(...args: unknown[]): void;
|
|
5
|
+
warn(...args: unknown[]): void;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Logs to the console, but only outside production. Each line is prefixed with
|
|
9
|
+
* a level tag, an ISO timestamp, and a clickable link to the file and line it
|
|
10
|
+
* was called from; all arguments are then printed as-is.
|
|
11
|
+
* @example
|
|
12
|
+
* customLog("Auth", "user logged in")
|
|
13
|
+
* // [INFO] 2026-05-30T10:00:00.000Z (server.ts:42) Auth user logged in
|
|
14
|
+
*/
|
|
15
|
+
declare const customLog: LogFN;
|
|
16
|
+
export { customLog };
|
|
17
|
+
export default customLog;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/*
|
|
3
|
+
* index.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.customLog = void 0;
|
|
10
|
+
const index_js_1 = require("./utils/index.js");
|
|
11
|
+
/**
|
|
12
|
+
* Logs to the console, but only outside production. Each line is prefixed with
|
|
13
|
+
* a level tag, an ISO timestamp, and a clickable link to the file and line it
|
|
14
|
+
* was called from; all arguments are then printed as-is.
|
|
15
|
+
* @example
|
|
16
|
+
* customLog("Auth", "user logged in")
|
|
17
|
+
* // [INFO] 2026-05-30T10:00:00.000Z (server.ts:42) Auth user logged in
|
|
18
|
+
*/
|
|
19
|
+
const customLog = Object.assign((0, index_js_1.createLog)("log", "[INFO]"), {
|
|
20
|
+
error: (0, index_js_1.createLog)("error", "[ERROR]"),
|
|
21
|
+
warn: (0, index_js_1.createLog)("warn", "[WARN]"),
|
|
22
|
+
});
|
|
23
|
+
exports.customLog = customLog;
|
|
24
|
+
exports.default = customLog;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/** The console channels the logger writes to. */
|
|
2
|
+
export type LogChannel = "log" | "error" | "warn";
|
|
3
|
+
/**
|
|
4
|
+
* Builds a log function bound to a console channel and tag. The returned closure
|
|
5
|
+
* is what the caller invokes directly, so {@link getCaller} still resolves the
|
|
6
|
+
* caller's own frame (no extra stack frame is inserted). `console[channel]` is
|
|
7
|
+
* looked up at call time, so reassigning `console.log` (e.g. in tests) is
|
|
8
|
+
* respected. Logs only outside production — see {@link isLogAllowed}.
|
|
9
|
+
*/
|
|
10
|
+
export default function createLog(channel: LogChannel, tag: string): (...args: unknown[]) => void;
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/*
|
|
3
|
+
* createLog.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.default = createLog;
|
|
13
|
+
const getCaller_js_1 = __importDefault(require("./getCaller.js"));
|
|
14
|
+
const getTimeStamp_js_1 = __importDefault(require("./getTimeStamp.js"));
|
|
15
|
+
const link_js_1 = require("./link.js");
|
|
16
|
+
const config_js_1 = require("../config.js");
|
|
17
|
+
/**
|
|
18
|
+
* Renders a caller as a `(file:line)` location. When the terminal supports
|
|
19
|
+
* OSC-8 hyperlinks, the location is a clickable link to the exact source line;
|
|
20
|
+
* otherwise it's plain text. Pure (no stack access), so it can be called from a
|
|
21
|
+
* helper without disturbing {@link getCaller}'s frame depth.
|
|
22
|
+
*/
|
|
23
|
+
function formatLocation(caller, streamName) {
|
|
24
|
+
if (caller.file !== null &&
|
|
25
|
+
caller.line !== null &&
|
|
26
|
+
(0, link_js_1.supportsHyperlinks)(streamName))
|
|
27
|
+
return (0, link_js_1.hyperlink)(caller.label, (0, link_js_1.fileUrl)(caller.file, caller.line));
|
|
28
|
+
return caller.label;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Builds a log function bound to a console channel and tag. The returned closure
|
|
32
|
+
* is what the caller invokes directly, so {@link getCaller} still resolves the
|
|
33
|
+
* caller's own frame (no extra stack frame is inserted). `console[channel]` is
|
|
34
|
+
* looked up at call time, so reassigning `console.log` (e.g. in tests) is
|
|
35
|
+
* respected. Logs only outside production — see {@link isLogAllowed}.
|
|
36
|
+
*/
|
|
37
|
+
function createLog(channel, tag) {
|
|
38
|
+
const streamName = channel === "log" ? "stdout" : "stderr";
|
|
39
|
+
return (...args) => {
|
|
40
|
+
if (!(0, config_js_1.isLogAllowed)())
|
|
41
|
+
return;
|
|
42
|
+
const caller = (0, getCaller_js_1.default)();
|
|
43
|
+
const location = formatLocation(caller, streamName);
|
|
44
|
+
console[channel](tag, (0, getTimeStamp_js_1.default)(), `(${location})`, `\n`, ...args, `\n`);
|
|
45
|
+
};
|
|
46
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/** A resolved call site. `file`/`line` are `null` when they can't be determined. */
|
|
2
|
+
export interface Caller {
|
|
3
|
+
/** Short display location, e.g. `server.ts:42`, or `"unknown"`. */
|
|
4
|
+
label: string;
|
|
5
|
+
/** Absolute path (or `file://` URL) of the calling file, or `null`. */
|
|
6
|
+
file: string | null;
|
|
7
|
+
/** 1-based line number, or `null`. */
|
|
8
|
+
line: number | null;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Reads the call stack and returns the caller's location — both a short display
|
|
12
|
+
* label (`file:line`) and the absolute path/line needed to build a clickable
|
|
13
|
+
* link. Returns {@link UNKNOWN} when the frame isn't a resolvable source file
|
|
14
|
+
* (e.g. minified, eval, or native code).
|
|
15
|
+
*/
|
|
16
|
+
export default function getCaller(): Caller;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/*
|
|
3
|
+
* getCaller.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.default = getCaller;
|
|
10
|
+
const UNKNOWN = { label: "unknown", file: null, line: null };
|
|
11
|
+
/** Matches a source file by extension: `.js/.jsx/.ts/.tsx` and `.cjs/.mjs/.cts/.mts`. */
|
|
12
|
+
const SOURCE_FILE = /\.[cm]?[jt]sx?$/;
|
|
13
|
+
/**
|
|
14
|
+
* Reads the call stack and returns the caller's location — both a short display
|
|
15
|
+
* label (`file:line`) and the absolute path/line needed to build a clickable
|
|
16
|
+
* link. Returns {@link UNKNOWN} when the frame isn't a resolvable source file
|
|
17
|
+
* (e.g. minified, eval, or native code).
|
|
18
|
+
*/
|
|
19
|
+
function getCaller() {
|
|
20
|
+
const stack = new Error().stack ?? "";
|
|
21
|
+
const frame = stack.split("\n")[3] ?? "";
|
|
22
|
+
// V8 frames look like `at fn (/path/file.js:10:5)` or `at /path/file.js:10:5`
|
|
23
|
+
// (and `file://…` for ESM). Prefer the parenthesised location when present.
|
|
24
|
+
const parens = frame.match(/\(([^)]+)\)\s*$/);
|
|
25
|
+
const inner = (parens?.[1] ?? frame.replace(/^\s*at\s+(?:async\s+)?/, "")).trim();
|
|
26
|
+
// Split off the trailing `:line:column`, keeping the (possibly colon-bearing)
|
|
27
|
+
// path intact (e.g. Windows `C:\…` or `file://…`).
|
|
28
|
+
const match = inner.match(/^(.*):(\d+):\d+$/);
|
|
29
|
+
const file = match?.[1];
|
|
30
|
+
if (file === undefined)
|
|
31
|
+
return UNKNOWN;
|
|
32
|
+
const line = Number(match?.[2]);
|
|
33
|
+
const base = file.split(/[/\\]/).pop() ?? "";
|
|
34
|
+
if (!SOURCE_FILE.test(base))
|
|
35
|
+
return UNKNOWN;
|
|
36
|
+
return { label: `${base}:${line}`, file, line };
|
|
37
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/*
|
|
3
|
+
* getTimeStamp.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.default = getTimeStamp;
|
|
10
|
+
/** Returns the current time as an ISO-8601 string, e.g. `2026-05-30T10:00:00.000Z`. */
|
|
11
|
+
function getTimeStamp() {
|
|
12
|
+
return new Date().toISOString();
|
|
13
|
+
}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export { default as createLog, type LogChannel } from "./createLog.js";
|
|
2
|
+
export { default as getCaller, type Caller } from "./getCaller.js";
|
|
3
|
+
export { default as getTimeStamp } from "./getTimeStamp.js";
|
|
4
|
+
export { fileUrl, hyperlink, supportsHyperlinks } from "./link.js";
|
|
@@ -0,0 +1,22 @@
|
|
|
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.supportsHyperlinks = exports.hyperlink = exports.fileUrl = exports.getTimeStamp = exports.getCaller = exports.createLog = void 0;
|
|
13
|
+
var createLog_js_1 = require("./createLog.js");
|
|
14
|
+
Object.defineProperty(exports, "createLog", { enumerable: true, get: function () { return __importDefault(createLog_js_1).default; } });
|
|
15
|
+
var getCaller_js_1 = require("./getCaller.js");
|
|
16
|
+
Object.defineProperty(exports, "getCaller", { enumerable: true, get: function () { return __importDefault(getCaller_js_1).default; } });
|
|
17
|
+
var getTimeStamp_js_1 = require("./getTimeStamp.js");
|
|
18
|
+
Object.defineProperty(exports, "getTimeStamp", { enumerable: true, get: function () { return __importDefault(getTimeStamp_js_1).default; } });
|
|
19
|
+
var link_js_1 = require("./link.js");
|
|
20
|
+
Object.defineProperty(exports, "fileUrl", { enumerable: true, get: function () { return link_js_1.fileUrl; } });
|
|
21
|
+
Object.defineProperty(exports, "hyperlink", { enumerable: true, get: function () { return link_js_1.hyperlink; } });
|
|
22
|
+
Object.defineProperty(exports, "supportsHyperlinks", { enumerable: true, get: function () { return link_js_1.supportsHyperlinks; } });
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Builds a `file://` URL with a trailing `:line` so terminals can jump to the
|
|
3
|
+
* exact line. Paths already in `file://` form are used as-is.
|
|
4
|
+
*/
|
|
5
|
+
export declare function fileUrl(file: string, line: number): string;
|
|
6
|
+
/**
|
|
7
|
+
* Wraps `text` in an OSC-8 terminal hyperlink pointing at `url`. Terminals that
|
|
8
|
+
* support OSC-8 render `text` as a clickable link; others simply show `text`.
|
|
9
|
+
*/
|
|
10
|
+
export declare function hyperlink(text: string, url: string): string;
|
|
11
|
+
/**
|
|
12
|
+
* Conservative detection of OSC-8 hyperlink support for the given stream.
|
|
13
|
+
* Honors `FORCE_HYPERLINK` (set to a falsy value to force off), requires a TTY,
|
|
14
|
+
* and otherwise allow-lists terminals known to support hyperlinks. Unknown
|
|
15
|
+
* terminals get plain text so output is never garbled.
|
|
16
|
+
*/
|
|
17
|
+
export declare function supportsHyperlinks(streamName: "stdout" | "stderr"): boolean;
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/*
|
|
3
|
+
* link.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.fileUrl = fileUrl;
|
|
10
|
+
exports.hyperlink = hyperlink;
|
|
11
|
+
exports.supportsHyperlinks = supportsHyperlinks;
|
|
12
|
+
const node_url_1 = require("node:url");
|
|
13
|
+
/**
|
|
14
|
+
* Builds a `file://` URL with a trailing `:line` so terminals can jump to the
|
|
15
|
+
* exact line. Paths already in `file://` form are used as-is.
|
|
16
|
+
*/
|
|
17
|
+
function fileUrl(file, line) {
|
|
18
|
+
const base = file.startsWith("file://") ? file : (0, node_url_1.pathToFileURL)(file).href;
|
|
19
|
+
return `${base}:${line}`;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Wraps `text` in an OSC-8 terminal hyperlink pointing at `url`. Terminals that
|
|
23
|
+
* support OSC-8 render `text` as a clickable link; others simply show `text`.
|
|
24
|
+
*/
|
|
25
|
+
function hyperlink(text, url) {
|
|
26
|
+
const OSC = "\x1b]8;;";
|
|
27
|
+
const BEL = "\x07";
|
|
28
|
+
return `${OSC}${url}${BEL}${text}${OSC}${BEL}`;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Conservative detection of OSC-8 hyperlink support for the given stream.
|
|
32
|
+
* Honors `FORCE_HYPERLINK` (set to a falsy value to force off), requires a TTY,
|
|
33
|
+
* and otherwise allow-lists terminals known to support hyperlinks. Unknown
|
|
34
|
+
* terminals get plain text so output is never garbled.
|
|
35
|
+
*/
|
|
36
|
+
function supportsHyperlinks(streamName) {
|
|
37
|
+
if (typeof process === "undefined")
|
|
38
|
+
return false;
|
|
39
|
+
const env = process.env;
|
|
40
|
+
const force = env.FORCE_HYPERLINK;
|
|
41
|
+
if (force !== undefined && force !== "")
|
|
42
|
+
return force !== "0" && force.toLowerCase() !== "false";
|
|
43
|
+
const stream = streamName === "stdout" ? process.stdout : process.stderr;
|
|
44
|
+
if (!stream || !stream.isTTY)
|
|
45
|
+
return false;
|
|
46
|
+
if (env.TERM === "dumb")
|
|
47
|
+
return false;
|
|
48
|
+
if (env.CI !== undefined && env.CI !== "")
|
|
49
|
+
return false;
|
|
50
|
+
const program = env.TERM_PROGRAM;
|
|
51
|
+
if (program === "vscode" ||
|
|
52
|
+
program === "iTerm.app" ||
|
|
53
|
+
program === "Hyper" ||
|
|
54
|
+
program === "WezTerm")
|
|
55
|
+
return true;
|
|
56
|
+
if (env.WT_SESSION)
|
|
57
|
+
return true; // Windows Terminal
|
|
58
|
+
if (env.KITTY_WINDOW_ID)
|
|
59
|
+
return true;
|
|
60
|
+
if (env.VTE_VERSION !== undefined && Number(env.VTE_VERSION) >= 5000)
|
|
61
|
+
return true; // GNOME, etc.
|
|
62
|
+
return false;
|
|
63
|
+
}
|
package/dist/index.d.ts
CHANGED
|
@@ -6,13 +6,13 @@ export interface LogFN {
|
|
|
6
6
|
}
|
|
7
7
|
/**
|
|
8
8
|
* Logs to the console, but only outside production. Each line is prefixed with
|
|
9
|
-
*
|
|
10
|
-
* all arguments are then printed as-is.
|
|
11
|
-
* with their own tags and console channels.
|
|
9
|
+
* a level tag, an ISO timestamp, and a clickable link to the file and line it
|
|
10
|
+
* was called from; all arguments are then printed as-is.
|
|
12
11
|
* @example
|
|
13
12
|
* customLog("Auth", "user logged in")
|
|
14
13
|
* // [INFO] 2026-05-30T10:00:00.000Z (server.ts:42) Auth user logged in
|
|
15
14
|
*/
|
|
16
15
|
declare const customLog: LogFN;
|
|
16
|
+
export { customLog };
|
|
17
17
|
export default customLog;
|
|
18
18
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AASA,gFAAgF;AAChF,MAAM,WAAW,KAAK;IACpB,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,IAAI,CAAA;IAC1B,KAAK,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,IAAI,CAAA;IAC/B,IAAI,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,IAAI,CAAA;CAC/B;AAED;;;;;;;GAOG;AACH,QAAA,MAAM,SAAS,EAAE,KAGf,CAAA;AAEF,OAAO,EAAE,SAAS,EAAE,CAAA;AACpB,eAAe,SAAS,CAAA"}
|
package/dist/index.js
CHANGED
|
@@ -4,26 +4,11 @@
|
|
|
4
4
|
* Copyright (c) 2026 dewan-meadown
|
|
5
5
|
* All rights reserved
|
|
6
6
|
*/
|
|
7
|
-
import {
|
|
8
|
-
import { isLogAllowed } from "./config.js";
|
|
9
|
-
/**
|
|
10
|
-
* Builds a log function bound to a console channel and tag. The returned closure
|
|
11
|
-
* is what the caller invokes directly, so {@link getFileName} still resolves the
|
|
12
|
-
* caller's own frame (no extra stack frame is inserted). `console[channel]` is
|
|
13
|
-
* looked up at call time, so reassigning `console.log` (e.g. in tests) is
|
|
14
|
-
* respected. Logs only outside production — see {@link isLogAllowed}.
|
|
15
|
-
*/
|
|
16
|
-
function createLog(channel, tag) {
|
|
17
|
-
return (...args) => {
|
|
18
|
-
if (isLogAllowed())
|
|
19
|
-
console[channel](tag, getTimeStamp(), `(${getFileName()})`, ...args);
|
|
20
|
-
};
|
|
21
|
-
}
|
|
7
|
+
import { createLog } from "./utils/index.js";
|
|
22
8
|
/**
|
|
23
9
|
* Logs to the console, but only outside production. Each line is prefixed with
|
|
24
|
-
*
|
|
25
|
-
* all arguments are then printed as-is.
|
|
26
|
-
* with their own tags and console channels.
|
|
10
|
+
* a level tag, an ISO timestamp, and a clickable link to the file and line it
|
|
11
|
+
* was called from; all arguments are then printed as-is.
|
|
27
12
|
* @example
|
|
28
13
|
* customLog("Auth", "user logged in")
|
|
29
14
|
* // [INFO] 2026-05-30T10:00:00.000Z (server.ts:42) Auth user logged in
|
|
@@ -32,5 +17,6 @@ const customLog = Object.assign(createLog("log", "[INFO]"), {
|
|
|
32
17
|
error: createLog("error", "[ERROR]"),
|
|
33
18
|
warn: createLog("warn", "[WARN]"),
|
|
34
19
|
});
|
|
20
|
+
export { customLog };
|
|
35
21
|
export default customLog;
|
|
36
22
|
//# 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":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAA;AAS5C;;;;;;;GAOG;AACH,MAAM,SAAS,GAAU,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC,KAAK,EAAE,QAAQ,CAAC,EAAE;IACjE,KAAK,EAAE,SAAS,CAAC,OAAO,EAAE,SAAS,CAAC;IACpC,IAAI,EAAE,SAAS,CAAC,MAAM,EAAE,QAAQ,CAAC;CAClC,CAAC,CAAA;AAEF,OAAO,EAAE,SAAS,EAAE,CAAA;AACpB,eAAe,SAAS,CAAA"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/** The console channels the logger writes to. */
|
|
2
|
+
export type LogChannel = "log" | "error" | "warn";
|
|
3
|
+
/**
|
|
4
|
+
* Builds a log function bound to a console channel and tag. The returned closure
|
|
5
|
+
* is what the caller invokes directly, so {@link getCaller} still resolves the
|
|
6
|
+
* caller's own frame (no extra stack frame is inserted). `console[channel]` is
|
|
7
|
+
* looked up at call time, so reassigning `console.log` (e.g. in tests) is
|
|
8
|
+
* respected. Logs only outside production — see {@link isLogAllowed}.
|
|
9
|
+
*/
|
|
10
|
+
export default function createLog(channel: LogChannel, tag: string): (...args: unknown[]) => void;
|
|
11
|
+
//# sourceMappingURL=createLog.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"createLog.d.ts","sourceRoot":"","sources":["../../src/utils/createLog.ts"],"names":[],"mappings":"AAYA,iDAAiD;AACjD,MAAM,MAAM,UAAU,GAAG,KAAK,GAAG,OAAO,GAAG,MAAM,CAAA;AAqBjD;;;;;;GAMG;AACH,MAAM,CAAC,OAAO,UAAU,SAAS,CAC/B,OAAO,EAAE,UAAU,EACnB,GAAG,EAAE,MAAM,GACV,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,IAAI,CAQ9B"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* createLog.ts
|
|
3
|
+
* Created by Dewan Mobashirul
|
|
4
|
+
* Copyright (c) 2026 dewan-meadown
|
|
5
|
+
* All rights reserved
|
|
6
|
+
*/
|
|
7
|
+
import getCaller from "./getCaller.js";
|
|
8
|
+
import getTimeStamp from "./getTimeStamp.js";
|
|
9
|
+
import { fileUrl, hyperlink, supportsHyperlinks } from "./link.js";
|
|
10
|
+
import { isLogAllowed } from "../config.js";
|
|
11
|
+
/**
|
|
12
|
+
* Renders a caller as a `(file:line)` location. When the terminal supports
|
|
13
|
+
* OSC-8 hyperlinks, the location is a clickable link to the exact source line;
|
|
14
|
+
* otherwise it's plain text. Pure (no stack access), so it can be called from a
|
|
15
|
+
* helper without disturbing {@link getCaller}'s frame depth.
|
|
16
|
+
*/
|
|
17
|
+
function formatLocation(caller, streamName) {
|
|
18
|
+
if (caller.file !== null &&
|
|
19
|
+
caller.line !== null &&
|
|
20
|
+
supportsHyperlinks(streamName))
|
|
21
|
+
return hyperlink(caller.label, fileUrl(caller.file, caller.line));
|
|
22
|
+
return caller.label;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Builds a log function bound to a console channel and tag. The returned closure
|
|
26
|
+
* is what the caller invokes directly, so {@link getCaller} still resolves the
|
|
27
|
+
* caller's own frame (no extra stack frame is inserted). `console[channel]` is
|
|
28
|
+
* looked up at call time, so reassigning `console.log` (e.g. in tests) is
|
|
29
|
+
* respected. Logs only outside production — see {@link isLogAllowed}.
|
|
30
|
+
*/
|
|
31
|
+
export default function createLog(channel, tag) {
|
|
32
|
+
const streamName = channel === "log" ? "stdout" : "stderr";
|
|
33
|
+
return (...args) => {
|
|
34
|
+
if (!isLogAllowed())
|
|
35
|
+
return;
|
|
36
|
+
const caller = getCaller();
|
|
37
|
+
const location = formatLocation(caller, streamName);
|
|
38
|
+
console[channel](tag, getTimeStamp(), `(${location})`, `\n`, ...args, `\n`);
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
//# sourceMappingURL=createLog.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"createLog.js","sourceRoot":"","sources":["../../src/utils/createLog.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,SAA0B,MAAM,gBAAgB,CAAA;AACvD,OAAO,YAAY,MAAM,mBAAmB,CAAA;AAC5C,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,kBAAkB,EAAE,MAAM,WAAW,CAAA;AAClE,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAA;AAK3C;;;;;GAKG;AACH,SAAS,cAAc,CACrB,MAAc,EACd,UAA+B;IAE/B,IACE,MAAM,CAAC,IAAI,KAAK,IAAI;QACpB,MAAM,CAAC,IAAI,KAAK,IAAI;QACpB,kBAAkB,CAAC,UAAU,CAAC;QAE9B,OAAO,SAAS,CAAC,MAAM,CAAC,KAAK,EAAE,OAAO,CAAC,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC,IAAI,CAAC,CAAC,CAAA;IACnE,OAAO,MAAM,CAAC,KAAK,CAAA;AACrB,CAAC;AAED;;;;;;GAMG;AACH,MAAM,CAAC,OAAO,UAAU,SAAS,CAC/B,OAAmB,EACnB,GAAW;IAEX,MAAM,UAAU,GAAG,OAAO,KAAK,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAA;IAC1D,OAAO,CAAC,GAAG,IAAe,EAAQ,EAAE;QAClC,IAAI,CAAC,YAAY,EAAE;YAAE,OAAM;QAC3B,MAAM,MAAM,GAAG,SAAS,EAAE,CAAA;QAC1B,MAAM,QAAQ,GAAG,cAAc,CAAC,MAAM,EAAE,UAAU,CAAC,CAAA;QACnD,OAAO,CAAC,OAAO,CAAC,CAAC,GAAG,EAAE,YAAY,EAAE,EAAE,IAAI,QAAQ,GAAG,EAAE,IAAI,EAAE,GAAG,IAAI,EAAE,IAAI,CAAC,CAAA;IAC7E,CAAC,CAAA;AACH,CAAC"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/** A resolved call site. `file`/`line` are `null` when they can't be determined. */
|
|
2
|
+
export interface Caller {
|
|
3
|
+
/** Short display location, e.g. `server.ts:42`, or `"unknown"`. */
|
|
4
|
+
label: string;
|
|
5
|
+
/** Absolute path (or `file://` URL) of the calling file, or `null`. */
|
|
6
|
+
file: string | null;
|
|
7
|
+
/** 1-based line number, or `null`. */
|
|
8
|
+
line: number | null;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Reads the call stack and returns the caller's location — both a short display
|
|
12
|
+
* label (`file:line`) and the absolute path/line needed to build a clickable
|
|
13
|
+
* link. Returns {@link UNKNOWN} when the frame isn't a resolvable source file
|
|
14
|
+
* (e.g. minified, eval, or native code).
|
|
15
|
+
*/
|
|
16
|
+
export default function getCaller(): Caller;
|
|
17
|
+
//# sourceMappingURL=getCaller.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"getCaller.d.ts","sourceRoot":"","sources":["../../src/utils/getCaller.ts"],"names":[],"mappings":"AAOA,oFAAoF;AACpF,MAAM,WAAW,MAAM;IACrB,mEAAmE;IACnE,KAAK,EAAE,MAAM,CAAA;IACb,uEAAuE;IACvE,IAAI,EAAE,MAAM,GAAG,IAAI,CAAA;IACnB,sCAAsC;IACtC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAA;CACpB;AAOD;;;;;GAKG;AACH,MAAM,CAAC,OAAO,UAAU,SAAS,IAAI,MAAM,CAsB1C"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* getCaller.ts
|
|
3
|
+
* Created by Dewan Mobashirul
|
|
4
|
+
* Copyright (c) 2026 dewan-meadown
|
|
5
|
+
* All rights reserved
|
|
6
|
+
*/
|
|
7
|
+
const UNKNOWN = { label: "unknown", file: null, line: null };
|
|
8
|
+
/** Matches a source file by extension: `.js/.jsx/.ts/.tsx` and `.cjs/.mjs/.cts/.mts`. */
|
|
9
|
+
const SOURCE_FILE = /\.[cm]?[jt]sx?$/;
|
|
10
|
+
/**
|
|
11
|
+
* Reads the call stack and returns the caller's location — both a short display
|
|
12
|
+
* label (`file:line`) and the absolute path/line needed to build a clickable
|
|
13
|
+
* link. Returns {@link UNKNOWN} when the frame isn't a resolvable source file
|
|
14
|
+
* (e.g. minified, eval, or native code).
|
|
15
|
+
*/
|
|
16
|
+
export default function getCaller() {
|
|
17
|
+
const stack = new Error().stack ?? "";
|
|
18
|
+
const frame = stack.split("\n")[3] ?? "";
|
|
19
|
+
// V8 frames look like `at fn (/path/file.js:10:5)` or `at /path/file.js:10:5`
|
|
20
|
+
// (and `file://…` for ESM). Prefer the parenthesised location when present.
|
|
21
|
+
const parens = frame.match(/\(([^)]+)\)\s*$/);
|
|
22
|
+
const inner = (parens?.[1] ?? frame.replace(/^\s*at\s+(?:async\s+)?/, "")).trim();
|
|
23
|
+
// Split off the trailing `:line:column`, keeping the (possibly colon-bearing)
|
|
24
|
+
// path intact (e.g. Windows `C:\…` or `file://…`).
|
|
25
|
+
const match = inner.match(/^(.*):(\d+):\d+$/);
|
|
26
|
+
const file = match?.[1];
|
|
27
|
+
if (file === undefined)
|
|
28
|
+
return UNKNOWN;
|
|
29
|
+
const line = Number(match?.[2]);
|
|
30
|
+
const base = file.split(/[/\\]/).pop() ?? "";
|
|
31
|
+
if (!SOURCE_FILE.test(base))
|
|
32
|
+
return UNKNOWN;
|
|
33
|
+
return { label: `${base}:${line}`, file, line };
|
|
34
|
+
}
|
|
35
|
+
//# sourceMappingURL=getCaller.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"getCaller.js","sourceRoot":"","sources":["../../src/utils/getCaller.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAYH,MAAM,OAAO,GAAW,EAAE,KAAK,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,CAAA;AAEpE,yFAAyF;AACzF,MAAM,WAAW,GAAG,iBAAiB,CAAA;AAErC;;;;;GAKG;AACH,MAAM,CAAC,OAAO,UAAU,SAAS;IAC/B,MAAM,KAAK,GAAG,IAAI,KAAK,EAAE,CAAC,KAAK,IAAI,EAAE,CAAA;IACrC,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAA;IAExC,8EAA8E;IAC9E,4EAA4E;IAC5E,MAAM,MAAM,GAAG,KAAK,CAAC,KAAK,CAAC,iBAAiB,CAAC,CAAA;IAC7C,MAAM,KAAK,GAAG,CACZ,MAAM,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,OAAO,CAAC,wBAAwB,EAAE,EAAE,CAAC,CAC3D,CAAC,IAAI,EAAE,CAAA;IAER,8EAA8E;IAC9E,mDAAmD;IACnD,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,kBAAkB,CAAC,CAAA;IAC7C,MAAM,IAAI,GAAG,KAAK,EAAE,CAAC,CAAC,CAAC,CAAA;IACvB,IAAI,IAAI,KAAK,SAAS;QAAE,OAAO,OAAO,CAAA;IAEtC,MAAM,IAAI,GAAG,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,CAAC,CAAA;IAC/B,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,GAAG,EAAE,IAAI,EAAE,CAAA;IAC5C,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC;QAAE,OAAO,OAAO,CAAA;IAE3C,OAAO,EAAE,KAAK,EAAE,GAAG,IAAI,IAAI,IAAI,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAA;AACjD,CAAC"}
|
package/dist/utils/index.d.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
-
export { default as
|
|
1
|
+
export { default as createLog, type LogChannel } from "./createLog.js";
|
|
2
|
+
export { default as getCaller, type Caller } from "./getCaller.js";
|
|
2
3
|
export { default as getTimeStamp } from "./getTimeStamp.js";
|
|
4
|
+
export { fileUrl, hyperlink, supportsHyperlinks } from "./link.js";
|
|
3
5
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"AAOA,OAAO,EAAE,OAAO,IAAI,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"AAOA,OAAO,EAAE,OAAO,IAAI,SAAS,EAAE,KAAK,UAAU,EAAE,MAAM,gBAAgB,CAAA;AACtE,OAAO,EAAE,OAAO,IAAI,SAAS,EAAE,KAAK,MAAM,EAAE,MAAM,gBAAgB,CAAA;AAClE,OAAO,EAAE,OAAO,IAAI,YAAY,EAAE,MAAM,mBAAmB,CAAA;AAC3D,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,kBAAkB,EAAE,MAAM,WAAW,CAAA"}
|
package/dist/utils/index.js
CHANGED
|
@@ -4,6 +4,8 @@
|
|
|
4
4
|
* Copyright (c) 2026 dewan-meadown
|
|
5
5
|
* All rights reserved
|
|
6
6
|
*/
|
|
7
|
-
export { default as
|
|
7
|
+
export { default as createLog } from "./createLog.js";
|
|
8
|
+
export { default as getCaller } from "./getCaller.js";
|
|
8
9
|
export { default as getTimeStamp } from "./getTimeStamp.js";
|
|
10
|
+
export { fileUrl, hyperlink, supportsHyperlinks } from "./link.js";
|
|
9
11
|
//# sourceMappingURL=index.js.map
|
package/dist/utils/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,OAAO,IAAI,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,OAAO,IAAI,SAAS,EAAmB,MAAM,gBAAgB,CAAA;AACtE,OAAO,EAAE,OAAO,IAAI,SAAS,EAAe,MAAM,gBAAgB,CAAA;AAClE,OAAO,EAAE,OAAO,IAAI,YAAY,EAAE,MAAM,mBAAmB,CAAA;AAC3D,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,kBAAkB,EAAE,MAAM,WAAW,CAAA"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Builds a `file://` URL with a trailing `:line` so terminals can jump to the
|
|
3
|
+
* exact line. Paths already in `file://` form are used as-is.
|
|
4
|
+
*/
|
|
5
|
+
export declare function fileUrl(file: string, line: number): string;
|
|
6
|
+
/**
|
|
7
|
+
* Wraps `text` in an OSC-8 terminal hyperlink pointing at `url`. Terminals that
|
|
8
|
+
* support OSC-8 render `text` as a clickable link; others simply show `text`.
|
|
9
|
+
*/
|
|
10
|
+
export declare function hyperlink(text: string, url: string): string;
|
|
11
|
+
/**
|
|
12
|
+
* Conservative detection of OSC-8 hyperlink support for the given stream.
|
|
13
|
+
* Honors `FORCE_HYPERLINK` (set to a falsy value to force off), requires a TTY,
|
|
14
|
+
* and otherwise allow-lists terminals known to support hyperlinks. Unknown
|
|
15
|
+
* terminals get plain text so output is never garbled.
|
|
16
|
+
*/
|
|
17
|
+
export declare function supportsHyperlinks(streamName: "stdout" | "stderr"): boolean;
|
|
18
|
+
//# sourceMappingURL=link.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"link.d.ts","sourceRoot":"","sources":["../../src/utils/link.ts"],"names":[],"mappings":"AASA;;;GAGG;AACH,wBAAgB,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAG1D;AAED;;;GAGG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAI3D;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,UAAU,EAAE,QAAQ,GAAG,QAAQ,GAAG,OAAO,CA2B3E"}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* link.ts
|
|
3
|
+
* Created by Dewan Mobashirul
|
|
4
|
+
* Copyright (c) 2026 dewan-meadown
|
|
5
|
+
* All rights reserved
|
|
6
|
+
*/
|
|
7
|
+
import { pathToFileURL } from "node:url";
|
|
8
|
+
/**
|
|
9
|
+
* Builds a `file://` URL with a trailing `:line` so terminals can jump to the
|
|
10
|
+
* exact line. Paths already in `file://` form are used as-is.
|
|
11
|
+
*/
|
|
12
|
+
export function fileUrl(file, line) {
|
|
13
|
+
const base = file.startsWith("file://") ? file : pathToFileURL(file).href;
|
|
14
|
+
return `${base}:${line}`;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Wraps `text` in an OSC-8 terminal hyperlink pointing at `url`. Terminals that
|
|
18
|
+
* support OSC-8 render `text` as a clickable link; others simply show `text`.
|
|
19
|
+
*/
|
|
20
|
+
export function hyperlink(text, url) {
|
|
21
|
+
const OSC = "\x1b]8;;";
|
|
22
|
+
const BEL = "\x07";
|
|
23
|
+
return `${OSC}${url}${BEL}${text}${OSC}${BEL}`;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Conservative detection of OSC-8 hyperlink support for the given stream.
|
|
27
|
+
* Honors `FORCE_HYPERLINK` (set to a falsy value to force off), requires a TTY,
|
|
28
|
+
* and otherwise allow-lists terminals known to support hyperlinks. Unknown
|
|
29
|
+
* terminals get plain text so output is never garbled.
|
|
30
|
+
*/
|
|
31
|
+
export function supportsHyperlinks(streamName) {
|
|
32
|
+
if (typeof process === "undefined")
|
|
33
|
+
return false;
|
|
34
|
+
const env = process.env;
|
|
35
|
+
const force = env.FORCE_HYPERLINK;
|
|
36
|
+
if (force !== undefined && force !== "")
|
|
37
|
+
return force !== "0" && force.toLowerCase() !== "false";
|
|
38
|
+
const stream = streamName === "stdout" ? process.stdout : process.stderr;
|
|
39
|
+
if (!stream || !stream.isTTY)
|
|
40
|
+
return false;
|
|
41
|
+
if (env.TERM === "dumb")
|
|
42
|
+
return false;
|
|
43
|
+
if (env.CI !== undefined && env.CI !== "")
|
|
44
|
+
return false;
|
|
45
|
+
const program = env.TERM_PROGRAM;
|
|
46
|
+
if (program === "vscode" ||
|
|
47
|
+
program === "iTerm.app" ||
|
|
48
|
+
program === "Hyper" ||
|
|
49
|
+
program === "WezTerm")
|
|
50
|
+
return true;
|
|
51
|
+
if (env.WT_SESSION)
|
|
52
|
+
return true; // Windows Terminal
|
|
53
|
+
if (env.KITTY_WINDOW_ID)
|
|
54
|
+
return true;
|
|
55
|
+
if (env.VTE_VERSION !== undefined && Number(env.VTE_VERSION) >= 5000)
|
|
56
|
+
return true; // GNOME, etc.
|
|
57
|
+
return false;
|
|
58
|
+
}
|
|
59
|
+
//# sourceMappingURL=link.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"link.js","sourceRoot":"","sources":["../../src/utils/link.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAA;AAExC;;;GAGG;AACH,MAAM,UAAU,OAAO,CAAC,IAAY,EAAE,IAAY;IAChD,MAAM,IAAI,GAAG,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,IAAI,CAAA;IACzE,OAAO,GAAG,IAAI,IAAI,IAAI,EAAE,CAAA;AAC1B,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,SAAS,CAAC,IAAY,EAAE,GAAW;IACjD,MAAM,GAAG,GAAG,UAAU,CAAA;IACtB,MAAM,GAAG,GAAG,MAAM,CAAA;IAClB,OAAO,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,IAAI,GAAG,GAAG,GAAG,GAAG,EAAE,CAAA;AAChD,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,kBAAkB,CAAC,UAA+B;IAChE,IAAI,OAAO,OAAO,KAAK,WAAW;QAAE,OAAO,KAAK,CAAA;IAChD,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,CAAA;IAEvB,MAAM,KAAK,GAAG,GAAG,CAAC,eAAe,CAAA;IACjC,IAAI,KAAK,KAAK,SAAS,IAAI,KAAK,KAAK,EAAE;QACrC,OAAO,KAAK,KAAK,GAAG,IAAI,KAAK,CAAC,WAAW,EAAE,KAAK,OAAO,CAAA;IAEzD,MAAM,MAAM,GAAG,UAAU,KAAK,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAA;IACxE,IAAI,CAAC,MAAM,IAAI,CAAC,MAAM,CAAC,KAAK;QAAE,OAAO,KAAK,CAAA;IAC1C,IAAI,GAAG,CAAC,IAAI,KAAK,MAAM;QAAE,OAAO,KAAK,CAAA;IACrC,IAAI,GAAG,CAAC,EAAE,KAAK,SAAS,IAAI,GAAG,CAAC,EAAE,KAAK,EAAE;QAAE,OAAO,KAAK,CAAA;IAEvD,MAAM,OAAO,GAAG,GAAG,CAAC,YAAY,CAAA;IAChC,IACE,OAAO,KAAK,QAAQ;QACpB,OAAO,KAAK,WAAW;QACvB,OAAO,KAAK,OAAO;QACnB,OAAO,KAAK,SAAS;QAErB,OAAO,IAAI,CAAA;IACb,IAAI,GAAG,CAAC,UAAU;QAAE,OAAO,IAAI,CAAA,CAAC,mBAAmB;IACnD,IAAI,GAAG,CAAC,eAAe;QAAE,OAAO,IAAI,CAAA;IACpC,IAAI,GAAG,CAAC,WAAW,KAAK,SAAS,IAAI,MAAM,CAAC,GAAG,CAAC,WAAW,CAAC,IAAI,IAAI;QAClE,OAAO,IAAI,CAAA,CAAC,cAAc;IAE5B,OAAO,KAAK,CAAA;AACd,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@meadown/logger",
|
|
3
|
-
"version": "1.0
|
|
3
|
+
"version": "1.2.0",
|
|
4
4
|
"description": "A tiny, zero-dependency logger for Node.js and TypeScript that tags each line, timestamps it, shows the source file and line, and goes quiet in production.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"logger",
|
|
@@ -23,13 +23,19 @@
|
|
|
23
23
|
"license": "MIT",
|
|
24
24
|
"author": "Dewan Mobashirul",
|
|
25
25
|
"type": "module",
|
|
26
|
-
"main": "dist/index.js",
|
|
27
|
-
"
|
|
26
|
+
"main": "./dist/cjs/index.js",
|
|
27
|
+
"module": "./dist/index.js",
|
|
28
|
+
"types": "./dist/index.d.ts",
|
|
28
29
|
"exports": {
|
|
29
30
|
".": {
|
|
30
|
-
"
|
|
31
|
-
|
|
32
|
-
|
|
31
|
+
"import": {
|
|
32
|
+
"types": "./dist/index.d.ts",
|
|
33
|
+
"default": "./dist/index.js"
|
|
34
|
+
},
|
|
35
|
+
"require": {
|
|
36
|
+
"types": "./dist/cjs/index.d.ts",
|
|
37
|
+
"default": "./dist/cjs/index.js"
|
|
38
|
+
}
|
|
33
39
|
}
|
|
34
40
|
},
|
|
35
41
|
"files": [
|
|
@@ -42,7 +48,7 @@
|
|
|
42
48
|
"access": "public"
|
|
43
49
|
},
|
|
44
50
|
"scripts": {
|
|
45
|
-
"build": "tsc",
|
|
51
|
+
"build": "tsc -p tsconfig.json && tsc -p tsconfig.cjs.json && node scripts/write-cjs-pkg.mjs",
|
|
46
52
|
"test": "tsc && node --test \"test/**/*.test.mjs\"",
|
|
47
53
|
"lint": "eslint src",
|
|
48
54
|
"lint:fix": "eslint src --fix",
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"getFileName.d.ts","sourceRoot":"","sources":["../../src/utils/getFileName.ts"],"names":[],"mappings":"AAOA;;;GAGG;AACH,MAAM,CAAC,OAAO,UAAU,WAAW,IAAI,MAAM,CAK5C"}
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
/*
|
|
2
|
-
* getFileName.ts
|
|
3
|
-
* Created by Dewan Mobashirul
|
|
4
|
-
* Copyright (c) 2026 dewan-meadown
|
|
5
|
-
* All rights reserved
|
|
6
|
-
*/
|
|
7
|
-
/**
|
|
8
|
-
* Returns the caller's source location as `file.ext:line` by reading the call
|
|
9
|
-
* stack, or `"unknown"` if it can't be determined (e.g. minified or eval code).
|
|
10
|
-
*/
|
|
11
|
-
export default function getFileName() {
|
|
12
|
-
const stack = new Error().stack ?? "";
|
|
13
|
-
const line = stack.split("\n")[3] ?? "";
|
|
14
|
-
const match = line.match(/([^/\\]+\.[cm]?[jt]sx?):(\d+)/);
|
|
15
|
-
return match ? match[0] : "unknown";
|
|
16
|
-
}
|
|
17
|
-
//# sourceMappingURL=getFileName.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"getFileName.js","sourceRoot":"","sources":["../../src/utils/getFileName.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH;;;GAGG;AACH,MAAM,CAAC,OAAO,UAAU,WAAW;IACjC,MAAM,KAAK,GAAG,IAAI,KAAK,EAAE,CAAC,KAAK,IAAI,EAAE,CAAA;IACrC,MAAM,IAAI,GAAG,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAA;IACvC,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,+BAA+B,CAAC,CAAA;IACzD,OAAO,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAA;AACrC,CAAC"}
|