vite-plugin-better-console 1.0.2
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 +238 -0
- package/dist/caller.d.ts +93 -0
- package/dist/config.d.ts +116 -0
- package/dist/format.d.ts +137 -0
- package/dist/index.d.ts +39 -0
- package/dist/logger.d.ts +156 -0
- package/dist/plugin.d.ts +6 -0
- package/dist/plugin.js +144 -0
- package/dist/runtime/index.d.ts +34 -0
- package/dist/runtime/index.js +352 -0
- package/dist/types.d.ts +125 -0
- package/package.json +49 -0
package/dist/logger.d.ts
ADDED
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
import type { LogLevel, LoggerOptions, LogFn, LogCallOptions } from './types.js'
|
|
2
|
+
import { resolveOptions, shouldLog } from './config.js'
|
|
3
|
+
import { getCaller } from './caller.js'
|
|
4
|
+
import { typeOf, formatTimestamp, printMeta, printValue } from './format.js'
|
|
5
|
+
|
|
6
|
+
// ─── Production warning (fires at most once per page load) ───────────────────
|
|
7
|
+
|
|
8
|
+
const warnProductionOnce = (() => {
|
|
9
|
+
let fired = false
|
|
10
|
+
return () => {
|
|
11
|
+
if (fired) return
|
|
12
|
+
fired = true
|
|
13
|
+
console.log(
|
|
14
|
+
'%c better-console %c disabled in production ',
|
|
15
|
+
'background:#dc2626;color:#fff;font-size:11px;padding:3px 6px;border-radius:4px 0 0 4px;font-weight:700',
|
|
16
|
+
'background:#1e293b;color:#94a3b8;font-size:11px;padding:3px 8px;border-radius:0 4px 4px 0',
|
|
17
|
+
)
|
|
18
|
+
}
|
|
19
|
+
})()
|
|
20
|
+
|
|
21
|
+
// ─── Default badges per level ─────────────────────────────────────────────────
|
|
22
|
+
|
|
23
|
+
const DEFAULT_BADGES: Record<LogLevel, string> = {
|
|
24
|
+
debug: 'DEBUG',
|
|
25
|
+
info: 'INFO',
|
|
26
|
+
warn: 'WARN',
|
|
27
|
+
error: 'ERROR',
|
|
28
|
+
silent: '',
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// ─── createLogger ────────────────────────────────────────────────────────────
|
|
32
|
+
|
|
33
|
+
export function createLogger(userOptions: LoggerOptions = {}): LogFn {
|
|
34
|
+
const opts = resolveOptions(userOptions)
|
|
35
|
+
|
|
36
|
+
const {
|
|
37
|
+
dev,
|
|
38
|
+
warnInProduction,
|
|
39
|
+
logLevel,
|
|
40
|
+
collapsed: defaultCollapsed,
|
|
41
|
+
showPath,
|
|
42
|
+
showLine,
|
|
43
|
+
showFn,
|
|
44
|
+
showType,
|
|
45
|
+
timestamp: defaultTimestamp,
|
|
46
|
+
timestampFormat,
|
|
47
|
+
theme,
|
|
48
|
+
badge: badgeMap,
|
|
49
|
+
} = opts
|
|
50
|
+
|
|
51
|
+
// ── Core dispatcher ────────────────────────────────────────────────────────
|
|
52
|
+
|
|
53
|
+
function logAtLevel(
|
|
54
|
+
level: LogLevel,
|
|
55
|
+
label: string,
|
|
56
|
+
value: unknown,
|
|
57
|
+
callOpts: LogCallOptions = {},
|
|
58
|
+
): void {
|
|
59
|
+
// 1. Production guard
|
|
60
|
+
if (!dev) {
|
|
61
|
+
if (warnInProduction) warnProductionOnce()
|
|
62
|
+
return
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// 2. Level filter
|
|
66
|
+
const effectiveLevel = callOpts.level ?? level
|
|
67
|
+
if (!shouldLog(effectiveLevel, logLevel)) return
|
|
68
|
+
|
|
69
|
+
// 3. enabled flag
|
|
70
|
+
if (callOpts.enabled === false) return
|
|
71
|
+
|
|
72
|
+
// 4. Resolve per-call options
|
|
73
|
+
const {
|
|
74
|
+
comment,
|
|
75
|
+
collapsed = defaultCollapsed,
|
|
76
|
+
path: overridePath,
|
|
77
|
+
line: overrideLine,
|
|
78
|
+
fn: overrideFn,
|
|
79
|
+
timestamp: showTimestamp = defaultTimestamp,
|
|
80
|
+
} = callOpts
|
|
81
|
+
|
|
82
|
+
// 5. Caller detection
|
|
83
|
+
let caller = getCaller()
|
|
84
|
+
if (overridePath != null) caller = { ...caller, path: overridePath }
|
|
85
|
+
if (overrideLine != null) caller = { ...caller, line: String(overrideLine) }
|
|
86
|
+
if (overrideFn != null) caller = { ...caller, fn: overrideFn }
|
|
87
|
+
|
|
88
|
+
// 6. Badge label
|
|
89
|
+
const badgeText =
|
|
90
|
+
badgeMap === false
|
|
91
|
+
? label
|
|
92
|
+
: `${(badgeMap && badgeMap[effectiveLevel]) ?? DEFAULT_BADGES[effectiveLevel]} · ${label}`
|
|
93
|
+
|
|
94
|
+
const badgeStyle = theme[`badge_${effectiveLevel}` as keyof typeof theme] ?? theme.badge_info
|
|
95
|
+
|
|
96
|
+
// 7. Open group
|
|
97
|
+
const groupFn = collapsed ? console.groupCollapsed : console.group
|
|
98
|
+
groupFn(`%c ${badgeText} `, badgeStyle)
|
|
99
|
+
|
|
100
|
+
// 8. Meta rows
|
|
101
|
+
if (showTimestamp) {
|
|
102
|
+
printMeta('time', formatTimestamp(new Date(), timestampFormat), opts)
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
if (showFn && caller.fn) {
|
|
106
|
+
printMeta('function', caller.fn, opts)
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
if (showPath && caller.path) {
|
|
110
|
+
printMeta('file', caller.path, opts)
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
if (showLine && caller.line) {
|
|
114
|
+
printMeta('line', caller.line, opts)
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
if (showType && value !== undefined) {
|
|
118
|
+
printMeta('type', typeOf(value), opts)
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// 9. The value
|
|
122
|
+
printValue(value)
|
|
123
|
+
|
|
124
|
+
// 10. Optional comment
|
|
125
|
+
if (comment) {
|
|
126
|
+
printMeta('note', comment, opts)
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
console.groupEnd()
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// ── Public API ─────────────────────────────────────────────────────────────
|
|
133
|
+
|
|
134
|
+
const log = (label: string, value?: unknown, options?: LogCallOptions) =>
|
|
135
|
+
logAtLevel('info', label, value, options)
|
|
136
|
+
|
|
137
|
+
log.debug = (label: string, value?: unknown, options?: LogCallOptions) =>
|
|
138
|
+
logAtLevel('debug', label, value, options)
|
|
139
|
+
|
|
140
|
+
log.info = (label: string, value?: unknown, options?: LogCallOptions) =>
|
|
141
|
+
logAtLevel('info', label, value, options)
|
|
142
|
+
|
|
143
|
+
log.warn = (label: string, value?: unknown, options?: LogCallOptions) =>
|
|
144
|
+
logAtLevel('warn', label, value, options)
|
|
145
|
+
|
|
146
|
+
log.error = (label: string, value?: unknown, options?: LogCallOptions) =>
|
|
147
|
+
logAtLevel('error', label, value, options)
|
|
148
|
+
|
|
149
|
+
log.table = (label: string, data: unknown, options: LogCallOptions = {}) =>
|
|
150
|
+
logAtLevel('info', label, data, { ...options, collapsed: false })
|
|
151
|
+
|
|
152
|
+
Object.defineProperty(log, 'dev', { get: () => dev, enumerable: true })
|
|
153
|
+
Object.defineProperty(log, 'level', { get: () => logLevel, enumerable: true })
|
|
154
|
+
|
|
155
|
+
return log as LogFn
|
|
156
|
+
}
|
package/dist/plugin.d.ts
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { Plugin } from 'vite'
|
|
2
|
+
export type { BetterConsoleOptions, LoggerOptions, LogLevel, LogCallOptions, ThemeStyles } from './types.js'
|
|
3
|
+
export { betterConsole } from './plugin.js'
|
|
4
|
+
export default betterConsole
|
|
5
|
+
|
|
6
|
+
declare function betterConsole(options?: import('./types.js').BetterConsoleOptions): Plugin
|
package/dist/plugin.js
ADDED
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
// src/plugin.ts
|
|
2
|
+
var PLUGIN_NAME = "vite-plugin-better-console";
|
|
3
|
+
var VIRTUAL_ID = "virtual:better-console";
|
|
4
|
+
var RESOLVED_VIRTUAL = "\0virtual:better-console";
|
|
5
|
+
var RUNTIME_PKG = `${PLUGIN_NAME}/runtime`;
|
|
6
|
+
var ENTRY_EXTS = /* @__PURE__ */ new Set([".js", ".ts", ".jsx", ".tsx", ".mjs", ".mts", ".cjs", ".cts", ".vue", ".svelte"]);
|
|
7
|
+
function normalize(p) {
|
|
8
|
+
return p.replace(/\\/g, "/");
|
|
9
|
+
}
|
|
10
|
+
function resolveEntry(root, entry) {
|
|
11
|
+
const e = entry.startsWith("/") ? entry.slice(1) : entry;
|
|
12
|
+
return normalize(`${normalize(root)}/${e}`.replace(/\/+/g, "/"));
|
|
13
|
+
}
|
|
14
|
+
function globToRegex(glob) {
|
|
15
|
+
const escaped = glob.replace(/\\/g, "/").replace(/[.+^${}()|[\]]/g, "\\$&").replace(/\*\*/g, "\0").replace(/\*/g, "[^/]*").replace(/\x00/g, ".*").replace(/\?/g, "[^/]");
|
|
16
|
+
return new RegExp(`^${escaped}$`);
|
|
17
|
+
}
|
|
18
|
+
function matchPattern(pattern, id) {
|
|
19
|
+
if (!pattern) return false;
|
|
20
|
+
const normalized = normalize(id);
|
|
21
|
+
if (pattern instanceof RegExp) return pattern.test(normalized);
|
|
22
|
+
return globToRegex(pattern).test(normalized);
|
|
23
|
+
}
|
|
24
|
+
function htmlModuleEntries(html, root) {
|
|
25
|
+
const result = /* @__PURE__ */ new Set();
|
|
26
|
+
const re = /<script([^>]*)>/gi;
|
|
27
|
+
let m;
|
|
28
|
+
while ((m = re.exec(html)) !== null) {
|
|
29
|
+
const attrs = m[1];
|
|
30
|
+
if (!/type\s*=\s*["']module["']/i.test(attrs)) continue;
|
|
31
|
+
const src = attrs.match(/\bsrc\s*=\s*["']([^"']+)["']/i)?.[1];
|
|
32
|
+
if (!src || /^https?:\/\//i.test(src) || src.startsWith("//")) continue;
|
|
33
|
+
result.add(resolveEntry(root, src));
|
|
34
|
+
}
|
|
35
|
+
return result;
|
|
36
|
+
}
|
|
37
|
+
function rollupEntries(config) {
|
|
38
|
+
const result = /* @__PURE__ */ new Set();
|
|
39
|
+
const { root } = config;
|
|
40
|
+
const input = config.build?.rollupOptions?.input;
|
|
41
|
+
if (typeof input === "string") {
|
|
42
|
+
result.add(resolveEntry(root, input));
|
|
43
|
+
} else if (Array.isArray(input)) {
|
|
44
|
+
for (const e of input) result.add(resolveEntry(root, e));
|
|
45
|
+
} else if (input && typeof input === "object") {
|
|
46
|
+
for (const e of Object.values(input)) result.add(resolveEntry(root, e));
|
|
47
|
+
}
|
|
48
|
+
return result;
|
|
49
|
+
}
|
|
50
|
+
function serializeRuntimeOptions(options) {
|
|
51
|
+
const { inject: _i, injectEntries: _ie, injectPattern: _ip, ...rest } = options;
|
|
52
|
+
return JSON.stringify(rest);
|
|
53
|
+
}
|
|
54
|
+
function betterConsole(options = {}) {
|
|
55
|
+
const {
|
|
56
|
+
inject = true,
|
|
57
|
+
injectEntries = [],
|
|
58
|
+
injectPattern,
|
|
59
|
+
warnInProduction = true
|
|
60
|
+
} = options;
|
|
61
|
+
const serialized = serializeRuntimeOptions(options);
|
|
62
|
+
const injected = /* @__PURE__ */ new Set();
|
|
63
|
+
let entryPaths = /* @__PURE__ */ new Set();
|
|
64
|
+
let projectRoot = process.cwd();
|
|
65
|
+
let isDev = false;
|
|
66
|
+
function shouldInject(id) {
|
|
67
|
+
if (!inject) return false;
|
|
68
|
+
if (injected.has(id)) return false;
|
|
69
|
+
if (id.includes("node_modules")) return false;
|
|
70
|
+
if (id.startsWith("\0")) return false;
|
|
71
|
+
if (id.startsWith("virtual:")) return false;
|
|
72
|
+
if (id.includes(PLUGIN_NAME)) return false;
|
|
73
|
+
const norm = normalize(id);
|
|
74
|
+
if (injectEntries.some((e) => {
|
|
75
|
+
const resolved = resolveEntry(projectRoot, e);
|
|
76
|
+
return matchPattern(e, norm) || matchPattern(resolved, norm) || norm.endsWith("/" + normalize(e));
|
|
77
|
+
})) return true;
|
|
78
|
+
if (injectPattern && matchPattern(injectPattern, norm)) return true;
|
|
79
|
+
if (entryPaths.has(norm)) {
|
|
80
|
+
return ENTRY_EXTS.has(norm.slice(norm.lastIndexOf(".")));
|
|
81
|
+
}
|
|
82
|
+
return false;
|
|
83
|
+
}
|
|
84
|
+
return {
|
|
85
|
+
name: PLUGIN_NAME,
|
|
86
|
+
enforce: "pre",
|
|
87
|
+
// run before framework plugins (e.g. @vitejs/plugin-vue)
|
|
88
|
+
// 1. Inject compile-time defines so the runtime knows mode and options
|
|
89
|
+
config(_cfg, env) {
|
|
90
|
+
isDev = env.command === "serve" || env.mode !== "production";
|
|
91
|
+
return {
|
|
92
|
+
define: {
|
|
93
|
+
__BETTER_CONSOLE_DEV__: JSON.stringify(isDev),
|
|
94
|
+
__BETTER_CONSOLE_WARN__: JSON.stringify(warnInProduction),
|
|
95
|
+
__BETTER_CONSOLE_OPTIONS__: serialized
|
|
96
|
+
},
|
|
97
|
+
optimizeDeps: {
|
|
98
|
+
// Pre-bundle the runtime so HMR doesn't break on first load
|
|
99
|
+
include: [RUNTIME_PKG]
|
|
100
|
+
}
|
|
101
|
+
};
|
|
102
|
+
},
|
|
103
|
+
// 2. Save the resolved root and collect rollup entries
|
|
104
|
+
configResolved(config) {
|
|
105
|
+
projectRoot = config.root;
|
|
106
|
+
entryPaths = rollupEntries(config);
|
|
107
|
+
},
|
|
108
|
+
// 3. Collect <script type="module"> entries from index.html
|
|
109
|
+
transformIndexHtml: {
|
|
110
|
+
order: "pre",
|
|
111
|
+
handler(html) {
|
|
112
|
+
for (const path of htmlModuleEntries(html, projectRoot)) {
|
|
113
|
+
entryPaths.add(path);
|
|
114
|
+
}
|
|
115
|
+
return [];
|
|
116
|
+
}
|
|
117
|
+
},
|
|
118
|
+
// 4. Virtual module: the thin glue that imports the runtime
|
|
119
|
+
resolveId(id) {
|
|
120
|
+
if (id === VIRTUAL_ID) return RESOLVED_VIRTUAL;
|
|
121
|
+
},
|
|
122
|
+
load(id) {
|
|
123
|
+
if (id === RESOLVED_VIRTUAL) {
|
|
124
|
+
return `import '${RUNTIME_PKG}'`;
|
|
125
|
+
}
|
|
126
|
+
},
|
|
127
|
+
// 5. Prepend the virtual import to every matched entry
|
|
128
|
+
transform(code, id) {
|
|
129
|
+
if (!shouldInject(id)) return null;
|
|
130
|
+
if (!isDev) return null;
|
|
131
|
+
injected.add(id);
|
|
132
|
+
return {
|
|
133
|
+
code: `import '${VIRTUAL_ID}'
|
|
134
|
+
${code}`,
|
|
135
|
+
map: null
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
var plugin_default = betterConsole;
|
|
141
|
+
export {
|
|
142
|
+
betterConsole,
|
|
143
|
+
plugin_default as default
|
|
144
|
+
};
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
// Injected by `vite-plugin-better-console` — do not set manually.
|
|
2
|
+
declare const __BETTER_CONSOLE_DEV__: boolean | undefined
|
|
3
|
+
declare const __BETTER_CONSOLE_WARN__: boolean | undefined
|
|
4
|
+
declare const __BETTER_CONSOLE_OPTIONS__: string | undefined
|
|
5
|
+
|
|
6
|
+
export type {
|
|
7
|
+
LogLevel,
|
|
8
|
+
LoggerOptions,
|
|
9
|
+
LogCallOptions,
|
|
10
|
+
LogFn,
|
|
11
|
+
ThemeStyles,
|
|
12
|
+
BetterConsoleOptions,
|
|
13
|
+
} from './types.js'
|
|
14
|
+
|
|
15
|
+
export { LOG_LEVEL_RANK } from './types.js'
|
|
16
|
+
export { DEFAULT_THEME, DEFAULT_OPTIONS, resolveOptions, shouldLog, detectDev, detectWarnInProduction } from './config.js'
|
|
17
|
+
export { getCaller } from './caller.js'
|
|
18
|
+
export { typeOf, formatTimestamp, printMeta, printValue } from './format.js'
|
|
19
|
+
export { createLogger } from './logger.js'
|
|
20
|
+
export { attachRuntime } from './index.js'
|
|
21
|
+
|
|
22
|
+
declare const _logger: import('./types.js').LogFn
|
|
23
|
+
export default _logger
|
|
24
|
+
|
|
25
|
+
// ── Augment global console ─────────────────────────────────────────────────
|
|
26
|
+
|
|
27
|
+
declare global {
|
|
28
|
+
interface Console {
|
|
29
|
+
/** Better-console logger (primary) */
|
|
30
|
+
better: import('./types.js').LogFn
|
|
31
|
+
/** Better-console logger (legacy alias) */
|
|
32
|
+
logger: import('./types.js').LogFn
|
|
33
|
+
}
|
|
34
|
+
}
|
|
@@ -0,0 +1,352 @@
|
|
|
1
|
+
// src/types.ts
|
|
2
|
+
var LOG_LEVEL_RANK = {
|
|
3
|
+
debug: 0,
|
|
4
|
+
info: 1,
|
|
5
|
+
warn: 2,
|
|
6
|
+
error: 3,
|
|
7
|
+
silent: 99
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
// src/config.ts
|
|
11
|
+
var DEFAULT_THEME = {
|
|
12
|
+
badge_debug: "display:inline-block;padding:2px 8px;border-radius:4px;font-size:11px;font-weight:700;letter-spacing:.5px;background:#f3f0ff;color:#6d28d9;border:1px solid #c4b5fd",
|
|
13
|
+
badge_info: "display:inline-block;padding:2px 8px;border-radius:4px;font-size:11px;font-weight:700;letter-spacing:.5px;background:#eff6ff;color:#1d4ed8;border:1px solid #93c5fd",
|
|
14
|
+
badge_warn: "display:inline-block;padding:2px 8px;border-radius:4px;font-size:11px;font-weight:700;letter-spacing:.5px;background:#fffbeb;color:#b45309;border:1px solid #fcd34d",
|
|
15
|
+
badge_error: "display:inline-block;padding:2px 8px;border-radius:4px;font-size:11px;font-weight:700;letter-spacing:.5px;background:#fef2f2;color:#dc2626;border:1px solid #fca5a5",
|
|
16
|
+
label: "color:#94a3b8;font-size:11px;min-width:68px;display:inline-block",
|
|
17
|
+
value: "color:#0ea5e9;font-weight:600",
|
|
18
|
+
meta: "color:#64748b;font-size:11px",
|
|
19
|
+
divider: "color:#cbd5e1"
|
|
20
|
+
};
|
|
21
|
+
var DEFAULT_OPTIONS = {
|
|
22
|
+
logLevel: "debug",
|
|
23
|
+
collapsed: true,
|
|
24
|
+
showPath: true,
|
|
25
|
+
showLine: true,
|
|
26
|
+
showFn: true,
|
|
27
|
+
showType: true,
|
|
28
|
+
timestamp: true,
|
|
29
|
+
timestampFormat: "locale"
|
|
30
|
+
};
|
|
31
|
+
function detectDev() {
|
|
32
|
+
if (typeof __BETTER_CONSOLE_DEV__ !== "undefined") {
|
|
33
|
+
return __BETTER_CONSOLE_DEV__;
|
|
34
|
+
}
|
|
35
|
+
try {
|
|
36
|
+
if (import.meta.env?.PROD) return false;
|
|
37
|
+
if (import.meta.env?.DEV) return true;
|
|
38
|
+
} catch {
|
|
39
|
+
}
|
|
40
|
+
if (typeof process !== "undefined") {
|
|
41
|
+
return true;
|
|
42
|
+
}
|
|
43
|
+
return true;
|
|
44
|
+
}
|
|
45
|
+
function detectWarnInProduction() {
|
|
46
|
+
if (typeof __BETTER_CONSOLE_WARN__ !== "undefined") {
|
|
47
|
+
return __BETTER_CONSOLE_WARN__;
|
|
48
|
+
}
|
|
49
|
+
return true;
|
|
50
|
+
}
|
|
51
|
+
function parseInjectedOptions() {
|
|
52
|
+
if (typeof __BETTER_CONSOLE_OPTIONS__ === "undefined") return {};
|
|
53
|
+
try {
|
|
54
|
+
const raw = __BETTER_CONSOLE_OPTIONS__;
|
|
55
|
+
return (typeof raw === "string" ? JSON.parse(raw) : raw) ?? {};
|
|
56
|
+
} catch {
|
|
57
|
+
return {};
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
function resolveOptions(overrides = {}) {
|
|
61
|
+
const injected = parseInjectedOptions();
|
|
62
|
+
return {
|
|
63
|
+
...DEFAULT_OPTIONS,
|
|
64
|
+
...injected,
|
|
65
|
+
...overrides,
|
|
66
|
+
dev: overrides.dev ?? detectDev(),
|
|
67
|
+
warnInProduction: overrides.warnInProduction ?? detectWarnInProduction(),
|
|
68
|
+
theme: {
|
|
69
|
+
...DEFAULT_THEME,
|
|
70
|
+
...injected.theme,
|
|
71
|
+
...overrides.theme
|
|
72
|
+
},
|
|
73
|
+
badge: overrides.badge ?? injected.badge ?? {}
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
function shouldLog(level, minLevel = "debug") {
|
|
77
|
+
return (LOG_LEVEL_RANK[level] ?? 0) >= (LOG_LEVEL_RANK[minLevel] ?? 0);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// src/caller.ts
|
|
81
|
+
var SKIP_TOKENS = [
|
|
82
|
+
"vite-plugin-better-console",
|
|
83
|
+
"betterConsole",
|
|
84
|
+
"getCaller",
|
|
85
|
+
"createLogger",
|
|
86
|
+
"attachRuntime",
|
|
87
|
+
"logAtLevel",
|
|
88
|
+
"printMeta",
|
|
89
|
+
"printValue"
|
|
90
|
+
];
|
|
91
|
+
var RE_V8 = /^\s*at\s+(?:async\s+)?(?:([\w$.<>\[\] ]+?)\s+\()?(?:file:\/\/)?(.+?):(\d+)(?::(\d+))?\)?$/;
|
|
92
|
+
var RE_FF = /^\s*(?:([\w$.<>\[\]]+)@)?(?:file:\/\/)?(.+?):(\d+)(?::(\d+))?$/;
|
|
93
|
+
function parseFrame(raw) {
|
|
94
|
+
let m = raw.match(RE_V8);
|
|
95
|
+
if (m) {
|
|
96
|
+
const [, fn, path, line, col] = m;
|
|
97
|
+
if (!path) return null;
|
|
98
|
+
return { fn: fn?.trim() || void 0, path: cleanPath(path), line, col };
|
|
99
|
+
}
|
|
100
|
+
m = raw.match(RE_FF);
|
|
101
|
+
if (m) {
|
|
102
|
+
const [, fn, path, line, col] = m;
|
|
103
|
+
if (!path) return null;
|
|
104
|
+
return { fn: fn?.trim() || void 0, path: cleanPath(path), line, col };
|
|
105
|
+
}
|
|
106
|
+
return null;
|
|
107
|
+
}
|
|
108
|
+
function cleanPath(raw) {
|
|
109
|
+
return raw.replace(/^file:\/\//, "").replace(/\\/g, "/").replace(/\?.*$/, "").replace(/^\/\//, "/");
|
|
110
|
+
}
|
|
111
|
+
function isInternal(info) {
|
|
112
|
+
const haystack = `${info.path ?? ""} ${info.fn ?? ""}`.toLowerCase();
|
|
113
|
+
return SKIP_TOKENS.some((tok) => haystack.includes(tok.toLowerCase()));
|
|
114
|
+
}
|
|
115
|
+
function getCaller(extraSkip = 0) {
|
|
116
|
+
const stack = new Error().stack;
|
|
117
|
+
if (!stack) return {};
|
|
118
|
+
const lines = stack.split("\n").slice(1 + extraSkip);
|
|
119
|
+
for (const line of lines) {
|
|
120
|
+
const frame = parseFrame(line);
|
|
121
|
+
if (!frame) continue;
|
|
122
|
+
if (isInternal(frame)) continue;
|
|
123
|
+
return frame;
|
|
124
|
+
}
|
|
125
|
+
return {};
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
// src/format.ts
|
|
129
|
+
function typeOf(value) {
|
|
130
|
+
return Object.prototype.toString.call(value).slice(8, -1);
|
|
131
|
+
}
|
|
132
|
+
var _start = Date.now();
|
|
133
|
+
function formatTimestamp(date, format) {
|
|
134
|
+
if (typeof format === "function") return format(date);
|
|
135
|
+
switch (format) {
|
|
136
|
+
case "iso":
|
|
137
|
+
return date.toISOString();
|
|
138
|
+
case "time-only":
|
|
139
|
+
return date.toLocaleTimeString("en-GB", {
|
|
140
|
+
hour: "2-digit",
|
|
141
|
+
minute: "2-digit",
|
|
142
|
+
second: "2-digit"
|
|
143
|
+
});
|
|
144
|
+
case "date-only":
|
|
145
|
+
return date.toLocaleDateString("en-GB", {
|
|
146
|
+
year: "numeric",
|
|
147
|
+
month: "short",
|
|
148
|
+
day: "2-digit"
|
|
149
|
+
});
|
|
150
|
+
case "relative": {
|
|
151
|
+
const ms = date.getTime() - _start;
|
|
152
|
+
if (ms < 1e3) return `+${ms}ms`;
|
|
153
|
+
if (ms < 6e4) return `+${(ms / 1e3).toFixed(2)}s`;
|
|
154
|
+
return `+${(ms / 6e4).toFixed(1)}min`;
|
|
155
|
+
}
|
|
156
|
+
case "locale":
|
|
157
|
+
default: {
|
|
158
|
+
const d = date.toLocaleDateString("en-GB", {
|
|
159
|
+
year: "numeric",
|
|
160
|
+
month: "short",
|
|
161
|
+
day: "2-digit"
|
|
162
|
+
});
|
|
163
|
+
const t = date.toLocaleTimeString("en-GB", {
|
|
164
|
+
hour: "2-digit",
|
|
165
|
+
minute: "2-digit",
|
|
166
|
+
second: "2-digit"
|
|
167
|
+
});
|
|
168
|
+
return `${d} ${t}`;
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
function printMeta(label, value, opts) {
|
|
173
|
+
if (value == null || value === "") return;
|
|
174
|
+
console.info(
|
|
175
|
+
`%c${label.padEnd(10)}%c${value}`,
|
|
176
|
+
opts.theme.label,
|
|
177
|
+
opts.theme.value
|
|
178
|
+
);
|
|
179
|
+
}
|
|
180
|
+
function printValue(value) {
|
|
181
|
+
const kind = typeOf(value);
|
|
182
|
+
switch (kind) {
|
|
183
|
+
case "Map": {
|
|
184
|
+
const rows = Array.from(value, ([k, v]) => ({ key: k, value: v }));
|
|
185
|
+
console.table(rows);
|
|
186
|
+
return;
|
|
187
|
+
}
|
|
188
|
+
case "Set": {
|
|
189
|
+
const rows = Array.from(value, (v, i) => ({ index: i, value: v }));
|
|
190
|
+
console.table(rows);
|
|
191
|
+
return;
|
|
192
|
+
}
|
|
193
|
+
case "Array":
|
|
194
|
+
case "Object":
|
|
195
|
+
console.table(value);
|
|
196
|
+
return;
|
|
197
|
+
case "Date": {
|
|
198
|
+
const d = value;
|
|
199
|
+
console.info(`${d.toISOString()} (local: ${d.toLocaleString()})`);
|
|
200
|
+
return;
|
|
201
|
+
}
|
|
202
|
+
case "Promise":
|
|
203
|
+
console.info("%cPromise { <pending> }", "color:#94a3b8;font-style:italic");
|
|
204
|
+
value.then(
|
|
205
|
+
(r) => console.info(" \u21B3 resolved \u2192", r),
|
|
206
|
+
(e) => console.info(" \u21B3 rejected \u2192", e)
|
|
207
|
+
);
|
|
208
|
+
return;
|
|
209
|
+
case "Error": {
|
|
210
|
+
const err = value;
|
|
211
|
+
console.info(err.stack ?? err.message ?? String(err));
|
|
212
|
+
return;
|
|
213
|
+
}
|
|
214
|
+
case "Function":
|
|
215
|
+
console.info(`\u0192 ${value.name || "(anonymous)"}`);
|
|
216
|
+
return;
|
|
217
|
+
case "RegExp":
|
|
218
|
+
console.info(String(value));
|
|
219
|
+
return;
|
|
220
|
+
case "Null":
|
|
221
|
+
console.info("%cnull", "color:#94a3b8;font-style:italic");
|
|
222
|
+
return;
|
|
223
|
+
case "Undefined":
|
|
224
|
+
console.info("%cundefined", "color:#94a3b8;font-style:italic");
|
|
225
|
+
return;
|
|
226
|
+
default:
|
|
227
|
+
if (value !== void 0) console.info(value);
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
// src/logger.ts
|
|
232
|
+
var warnProductionOnce = /* @__PURE__ */ (() => {
|
|
233
|
+
let fired = false;
|
|
234
|
+
return () => {
|
|
235
|
+
if (fired) return;
|
|
236
|
+
fired = true;
|
|
237
|
+
console.log(
|
|
238
|
+
"%c better-console %c disabled in production ",
|
|
239
|
+
"background:#dc2626;color:#fff;font-size:11px;padding:3px 6px;border-radius:4px 0 0 4px;font-weight:700",
|
|
240
|
+
"background:#1e293b;color:#94a3b8;font-size:11px;padding:3px 8px;border-radius:0 4px 4px 0"
|
|
241
|
+
);
|
|
242
|
+
};
|
|
243
|
+
})();
|
|
244
|
+
var DEFAULT_BADGES = {
|
|
245
|
+
debug: "DEBUG",
|
|
246
|
+
info: "INFO",
|
|
247
|
+
warn: "WARN",
|
|
248
|
+
error: "ERROR",
|
|
249
|
+
silent: ""
|
|
250
|
+
};
|
|
251
|
+
function createLogger(userOptions = {}) {
|
|
252
|
+
const opts = resolveOptions(userOptions);
|
|
253
|
+
const {
|
|
254
|
+
dev,
|
|
255
|
+
warnInProduction,
|
|
256
|
+
logLevel,
|
|
257
|
+
collapsed: defaultCollapsed,
|
|
258
|
+
showPath,
|
|
259
|
+
showLine,
|
|
260
|
+
showFn,
|
|
261
|
+
showType,
|
|
262
|
+
timestamp: defaultTimestamp,
|
|
263
|
+
timestampFormat,
|
|
264
|
+
theme,
|
|
265
|
+
badge: badgeMap
|
|
266
|
+
} = opts;
|
|
267
|
+
function logAtLevel(level, label, value, callOpts = {}) {
|
|
268
|
+
if (!dev) {
|
|
269
|
+
if (warnInProduction) warnProductionOnce();
|
|
270
|
+
return;
|
|
271
|
+
}
|
|
272
|
+
const effectiveLevel = callOpts.level ?? level;
|
|
273
|
+
if (!shouldLog(effectiveLevel, logLevel)) return;
|
|
274
|
+
if (callOpts.enabled === false) return;
|
|
275
|
+
const {
|
|
276
|
+
comment,
|
|
277
|
+
collapsed = defaultCollapsed,
|
|
278
|
+
path: overridePath,
|
|
279
|
+
line: overrideLine,
|
|
280
|
+
fn: overrideFn,
|
|
281
|
+
timestamp: showTimestamp = defaultTimestamp
|
|
282
|
+
} = callOpts;
|
|
283
|
+
let caller = getCaller();
|
|
284
|
+
if (overridePath != null) caller = { ...caller, path: overridePath };
|
|
285
|
+
if (overrideLine != null) caller = { ...caller, line: String(overrideLine) };
|
|
286
|
+
if (overrideFn != null) caller = { ...caller, fn: overrideFn };
|
|
287
|
+
const badgeText = badgeMap === false ? label : `${(badgeMap && badgeMap[effectiveLevel]) ?? DEFAULT_BADGES[effectiveLevel]} \xB7 ${label}`;
|
|
288
|
+
const badgeStyle = theme[`badge_${effectiveLevel}`] ?? theme.badge_info;
|
|
289
|
+
const groupFn = collapsed ? console.groupCollapsed : console.group;
|
|
290
|
+
groupFn(`%c ${badgeText} `, badgeStyle);
|
|
291
|
+
if (showTimestamp) {
|
|
292
|
+
printMeta("time", formatTimestamp(/* @__PURE__ */ new Date(), timestampFormat), opts);
|
|
293
|
+
}
|
|
294
|
+
if (showFn && caller.fn) {
|
|
295
|
+
printMeta("function", caller.fn, opts);
|
|
296
|
+
}
|
|
297
|
+
if (showPath && caller.path) {
|
|
298
|
+
printMeta("file", caller.path, opts);
|
|
299
|
+
}
|
|
300
|
+
if (showLine && caller.line) {
|
|
301
|
+
printMeta("line", caller.line, opts);
|
|
302
|
+
}
|
|
303
|
+
if (showType && value !== void 0) {
|
|
304
|
+
printMeta("type", typeOf(value), opts);
|
|
305
|
+
}
|
|
306
|
+
printValue(value);
|
|
307
|
+
if (comment) {
|
|
308
|
+
printMeta("note", comment, opts);
|
|
309
|
+
}
|
|
310
|
+
console.groupEnd();
|
|
311
|
+
}
|
|
312
|
+
const log = (label, value, options) => logAtLevel("info", label, value, options);
|
|
313
|
+
log.debug = (label, value, options) => logAtLevel("debug", label, value, options);
|
|
314
|
+
log.info = (label, value, options) => logAtLevel("info", label, value, options);
|
|
315
|
+
log.warn = (label, value, options) => logAtLevel("warn", label, value, options);
|
|
316
|
+
log.error = (label, value, options) => logAtLevel("error", label, value, options);
|
|
317
|
+
log.table = (label, data, options = {}) => logAtLevel("info", label, data, { ...options, collapsed: false });
|
|
318
|
+
Object.defineProperty(log, "dev", { get: () => dev, enumerable: true });
|
|
319
|
+
Object.defineProperty(log, "level", { get: () => logLevel, enumerable: true });
|
|
320
|
+
return log;
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
// src/index.ts
|
|
324
|
+
function attachRuntime(logger) {
|
|
325
|
+
const instance = logger ?? createLogger(resolveOptions());
|
|
326
|
+
if (typeof console !== "undefined") {
|
|
327
|
+
;
|
|
328
|
+
console.log = console.log;
|
|
329
|
+
console.better = instance;
|
|
330
|
+
console.logger = instance;
|
|
331
|
+
}
|
|
332
|
+
return instance;
|
|
333
|
+
}
|
|
334
|
+
var _logger = attachRuntime();
|
|
335
|
+
var index_default = _logger;
|
|
336
|
+
export {
|
|
337
|
+
DEFAULT_OPTIONS,
|
|
338
|
+
DEFAULT_THEME,
|
|
339
|
+
LOG_LEVEL_RANK,
|
|
340
|
+
attachRuntime,
|
|
341
|
+
createLogger,
|
|
342
|
+
index_default as default,
|
|
343
|
+
detectDev,
|
|
344
|
+
detectWarnInProduction,
|
|
345
|
+
formatTimestamp,
|
|
346
|
+
getCaller,
|
|
347
|
+
printMeta,
|
|
348
|
+
printValue,
|
|
349
|
+
resolveOptions,
|
|
350
|
+
shouldLog,
|
|
351
|
+
typeOf
|
|
352
|
+
};
|