bun-git-hooks 0.2.15 → 0.2.17
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/dist/bin/cli.js +460 -1803
- package/dist/git-hooks.d.ts +11 -9
- package/dist/index.js +315 -1658
- package/package.json +7 -6
- package/dist/bin/config.d.ts +0 -3
- package/dist/bin/git-hooks.d.ts +0 -62
- package/dist/bin/index.d.ts +0 -3
- package/dist/bin/types.d.ts +0 -20
package/dist/index.js
CHANGED
|
@@ -18,12 +18,12 @@ var __toESM = (mod, isNodeMode, target) => {
|
|
|
18
18
|
var __require = /* @__PURE__ */ createRequire(import.meta.url);
|
|
19
19
|
|
|
20
20
|
// src/config.ts
|
|
21
|
-
import
|
|
21
|
+
import process6 from "node:process";
|
|
22
22
|
|
|
23
23
|
// node_modules/bunfig/dist/index.js
|
|
24
24
|
import { existsSync as existsSync3, mkdirSync as mkdirSync2, readdirSync as readdirSync2, writeFileSync as writeFileSync3 } from "fs";
|
|
25
25
|
import { dirname as dirname2, resolve as resolve3 } from "path";
|
|
26
|
-
import
|
|
26
|
+
import process8 from "process";
|
|
27
27
|
import { join, relative, resolve as resolve2 } from "path";
|
|
28
28
|
import process2 from "process";
|
|
29
29
|
import { existsSync, mkdirSync, readdirSync, writeFileSync } from "fs";
|
|
@@ -198,11 +198,23 @@ async function loadConfig({
|
|
|
198
198
|
for (const ext of extensions) {
|
|
199
199
|
const fullPath = resolve(baseDir, `${configPath}${ext}`);
|
|
200
200
|
const config2 = await tryLoadConfig(fullPath, defaultConfig);
|
|
201
|
-
if (config2 !== null)
|
|
201
|
+
if (config2 !== null) {
|
|
202
202
|
return config2;
|
|
203
|
+
}
|
|
203
204
|
}
|
|
204
205
|
}
|
|
205
|
-
|
|
206
|
+
try {
|
|
207
|
+
const pkgPath = resolve(baseDir, "package.json");
|
|
208
|
+
if (existsSync(pkgPath)) {
|
|
209
|
+
const pkg = await import(pkgPath);
|
|
210
|
+
const pkgConfig = pkg[name];
|
|
211
|
+
if (pkgConfig && typeof pkgConfig === "object" && !Array.isArray(pkgConfig)) {
|
|
212
|
+
try {
|
|
213
|
+
return deepMerge(defaultConfig, pkgConfig);
|
|
214
|
+
} catch {}
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
} catch {}
|
|
206
218
|
return defaultConfig;
|
|
207
219
|
}
|
|
208
220
|
var defaultConfigDir = resolve(process.cwd(), "config");
|
|
@@ -407,12 +419,6 @@ class Logger {
|
|
|
407
419
|
...configOptions,
|
|
408
420
|
timestamp: hasTimestamp || this.config.timestamp
|
|
409
421
|
};
|
|
410
|
-
if (!this.config.logDirectory) {
|
|
411
|
-
this.config.logDirectory = config.logDirectory;
|
|
412
|
-
}
|
|
413
|
-
if (!isBrowserProcess()) {
|
|
414
|
-
mkdir(this.config.logDirectory, { recursive: true, mode: 493 }).catch((err) => console.error("Failed to create log directory:", err));
|
|
415
|
-
}
|
|
416
422
|
this.currentLogFile = this.generateLogFilename();
|
|
417
423
|
this.encryptionKeys = new Map;
|
|
418
424
|
if (this.validateEncryptionConfig()) {
|
|
@@ -1626,25 +1632,86 @@ async function tryLoadConfig2(configPath, defaultConfig2) {
|
|
|
1626
1632
|
return null;
|
|
1627
1633
|
}
|
|
1628
1634
|
}
|
|
1635
|
+
function applyEnvVarsToConfig(name, config3, verbose = false) {
|
|
1636
|
+
if (!name)
|
|
1637
|
+
return config3;
|
|
1638
|
+
const envPrefix = name.toUpperCase().replace(/-/g, "_");
|
|
1639
|
+
const result = { ...config3 };
|
|
1640
|
+
function processObject(obj, path = []) {
|
|
1641
|
+
const result2 = { ...obj };
|
|
1642
|
+
for (const [key, value] of Object.entries(obj)) {
|
|
1643
|
+
const envPath = [...path, key];
|
|
1644
|
+
const formatKey = (k) => k.replace(/([A-Z])/g, "_$1").toUpperCase();
|
|
1645
|
+
const envKey = `${envPrefix}_${envPath.map(formatKey).join("_")}`;
|
|
1646
|
+
const oldEnvKey = `${envPrefix}_${envPath.map((p) => p.toUpperCase()).join("_")}`;
|
|
1647
|
+
if (verbose)
|
|
1648
|
+
log.info(`Checking environment variable ${envKey} for config ${name}.${envPath.join(".")}`);
|
|
1649
|
+
if (typeof value === "object" && value !== null && !Array.isArray(value)) {
|
|
1650
|
+
result2[key] = processObject(value, envPath);
|
|
1651
|
+
} else {
|
|
1652
|
+
const envValue = process8.env[envKey] || process8.env[oldEnvKey];
|
|
1653
|
+
if (envValue !== undefined) {
|
|
1654
|
+
if (verbose) {
|
|
1655
|
+
log.info(`Using environment variable ${envValue ? envKey : oldEnvKey} for config ${name}.${envPath.join(".")}`);
|
|
1656
|
+
}
|
|
1657
|
+
if (typeof value === "number") {
|
|
1658
|
+
result2[key] = Number(envValue);
|
|
1659
|
+
} else if (typeof value === "boolean") {
|
|
1660
|
+
result2[key] = envValue.toLowerCase() === "true";
|
|
1661
|
+
} else if (Array.isArray(value)) {
|
|
1662
|
+
try {
|
|
1663
|
+
const parsed = JSON.parse(envValue);
|
|
1664
|
+
if (Array.isArray(parsed)) {
|
|
1665
|
+
result2[key] = parsed;
|
|
1666
|
+
} else {
|
|
1667
|
+
result2[key] = envValue.split(",").map((item) => item.trim());
|
|
1668
|
+
}
|
|
1669
|
+
} catch {
|
|
1670
|
+
result2[key] = envValue.split(",").map((item) => item.trim());
|
|
1671
|
+
}
|
|
1672
|
+
} else {
|
|
1673
|
+
result2[key] = envValue;
|
|
1674
|
+
}
|
|
1675
|
+
}
|
|
1676
|
+
}
|
|
1677
|
+
}
|
|
1678
|
+
return result2;
|
|
1679
|
+
}
|
|
1680
|
+
return processObject(result);
|
|
1681
|
+
}
|
|
1629
1682
|
async function loadConfig3({
|
|
1630
1683
|
name = "",
|
|
1684
|
+
alias,
|
|
1631
1685
|
cwd,
|
|
1632
|
-
defaultConfig: defaultConfig2
|
|
1686
|
+
defaultConfig: defaultConfig2,
|
|
1687
|
+
verbose = false,
|
|
1688
|
+
checkEnv = true
|
|
1633
1689
|
}) {
|
|
1634
|
-
const
|
|
1690
|
+
const configWithEnvVars = checkEnv && typeof defaultConfig2 === "object" && defaultConfig2 !== null && !Array.isArray(defaultConfig2) ? applyEnvVarsToConfig(name, defaultConfig2, verbose) : defaultConfig2;
|
|
1691
|
+
const baseDir = cwd || process8.cwd();
|
|
1635
1692
|
const extensions = [".ts", ".js", ".mjs", ".cjs", ".json"];
|
|
1636
|
-
|
|
1637
|
-
|
|
1638
|
-
|
|
1639
|
-
|
|
1640
|
-
|
|
1641
|
-
|
|
1642
|
-
|
|
1693
|
+
if (verbose) {
|
|
1694
|
+
log.info(`Loading configuration for "${name}"${alias ? ` (alias: "${alias}")` : ""} from ${baseDir}`);
|
|
1695
|
+
}
|
|
1696
|
+
const configPatterns = [];
|
|
1697
|
+
configPatterns.push(`${name}.config`);
|
|
1698
|
+
configPatterns.push(`.${name}.config`);
|
|
1699
|
+
configPatterns.push(name);
|
|
1700
|
+
configPatterns.push(`.${name}`);
|
|
1701
|
+
if (alias) {
|
|
1702
|
+
configPatterns.push(`${alias}.config`);
|
|
1703
|
+
configPatterns.push(`.${alias}.config`);
|
|
1704
|
+
configPatterns.push(alias);
|
|
1705
|
+
configPatterns.push(`.${alias}`);
|
|
1706
|
+
}
|
|
1707
|
+
for (const configPath of configPatterns) {
|
|
1643
1708
|
for (const ext of extensions) {
|
|
1644
1709
|
const fullPath = resolve3(baseDir, `${configPath}${ext}`);
|
|
1645
|
-
const config3 = await tryLoadConfig2(fullPath,
|
|
1710
|
+
const config3 = await tryLoadConfig2(fullPath, configWithEnvVars);
|
|
1646
1711
|
if (config3 !== null) {
|
|
1647
|
-
|
|
1712
|
+
if (verbose) {
|
|
1713
|
+
log.success(`Configuration loaded from: ${configPath}${ext}`);
|
|
1714
|
+
}
|
|
1648
1715
|
return config3;
|
|
1649
1716
|
}
|
|
1650
1717
|
}
|
|
@@ -1653,28 +1720,50 @@ async function loadConfig3({
|
|
|
1653
1720
|
const pkgPath = resolve3(baseDir, "package.json");
|
|
1654
1721
|
if (existsSync3(pkgPath)) {
|
|
1655
1722
|
const pkg = await import(pkgPath);
|
|
1656
|
-
|
|
1723
|
+
let pkgConfig = pkg[name];
|
|
1724
|
+
if (!pkgConfig && alias) {
|
|
1725
|
+
pkgConfig = pkg[alias];
|
|
1726
|
+
if (pkgConfig && verbose) {
|
|
1727
|
+
log.success(`Using alias "${alias}" configuration from package.json`);
|
|
1728
|
+
}
|
|
1729
|
+
}
|
|
1657
1730
|
if (pkgConfig && typeof pkgConfig === "object" && !Array.isArray(pkgConfig)) {
|
|
1658
1731
|
try {
|
|
1659
|
-
|
|
1660
|
-
|
|
1661
|
-
|
|
1732
|
+
if (verbose) {
|
|
1733
|
+
log.success(`Configuration loaded from package.json: ${pkgConfig === pkg[name] ? name : alias}`);
|
|
1734
|
+
}
|
|
1735
|
+
return deepMerge2(configWithEnvVars, pkgConfig);
|
|
1736
|
+
} catch (error) {
|
|
1737
|
+
if (verbose) {
|
|
1738
|
+
log.warn(`Failed to merge package.json config:`, error);
|
|
1739
|
+
}
|
|
1740
|
+
}
|
|
1662
1741
|
}
|
|
1663
1742
|
}
|
|
1664
|
-
} catch {
|
|
1665
|
-
|
|
1666
|
-
|
|
1743
|
+
} catch (error) {
|
|
1744
|
+
if (verbose) {
|
|
1745
|
+
log.warn(`Failed to load package.json:`, error);
|
|
1746
|
+
}
|
|
1747
|
+
}
|
|
1748
|
+
if (verbose) {
|
|
1749
|
+
log.info(`No configuration found for "${name}"${alias ? ` or alias "${alias}"` : ""}, using default configuration with environment variables`);
|
|
1750
|
+
}
|
|
1751
|
+
return configWithEnvVars;
|
|
1667
1752
|
}
|
|
1668
|
-
var defaultConfigDir2 = resolve3(
|
|
1669
|
-
var defaultGeneratedDir2 = resolve3(
|
|
1753
|
+
var defaultConfigDir2 = resolve3(process8.cwd(), "config");
|
|
1754
|
+
var defaultGeneratedDir2 = resolve3(process8.cwd(), "src/generated");
|
|
1670
1755
|
|
|
1671
1756
|
// git-hooks.config.ts
|
|
1672
1757
|
var config2 = {
|
|
1673
1758
|
"pre-commit": {
|
|
1674
1759
|
"staged-lint": {
|
|
1675
|
-
"
|
|
1760
|
+
"**/*.{js,ts}": [
|
|
1761
|
+
"bunx --bun eslint --max-warnings=0",
|
|
1762
|
+
"bunx --bun tsc --noEmit"
|
|
1763
|
+
]
|
|
1676
1764
|
}
|
|
1677
1765
|
},
|
|
1766
|
+
"commit-msg": "bunx gitlint .git/COMMIT_EDITMSG",
|
|
1678
1767
|
verbose: true
|
|
1679
1768
|
};
|
|
1680
1769
|
var git_hooks_config_default = config2;
|
|
@@ -1682,26 +1771,21 @@ var git_hooks_config_default = config2;
|
|
|
1682
1771
|
// src/config.ts
|
|
1683
1772
|
var config3 = await loadConfig3({
|
|
1684
1773
|
name: "git-hooks",
|
|
1685
|
-
cwd:
|
|
1774
|
+
cwd: process6.cwd(),
|
|
1686
1775
|
defaultConfig: git_hooks_config_default
|
|
1687
1776
|
});
|
|
1688
1777
|
// src/git-hooks.ts
|
|
1689
1778
|
import fs from "node:fs";
|
|
1690
1779
|
import path from "node:path";
|
|
1691
|
-
import
|
|
1780
|
+
import process11 from "node:process";
|
|
1692
1781
|
import { exec } from "node:child_process";
|
|
1693
1782
|
import { promisify } from "node:util";
|
|
1694
1783
|
|
|
1695
1784
|
// node_modules/@stacksjs/clarity/dist/index.js
|
|
1696
|
-
import { join as join3, relative as relative2, resolve as
|
|
1697
|
-
import process72 from "process";
|
|
1698
|
-
import { existsSync as existsSync32, mkdirSync as mkdirSync22, readdirSync as readdirSync22, writeFileSync as writeFileSync32 } from "fs";
|
|
1699
|
-
import { dirname as dirname22, resolve as resolve32 } from "path";
|
|
1700
|
-
import process62 from "process";
|
|
1701
|
-
import { join as join4, relative as relative3, resolve as resolve22 } from "path";
|
|
1785
|
+
import { join as join3, relative as relative2, resolve as resolve22 } from "path";
|
|
1702
1786
|
import process22 from "process";
|
|
1703
1787
|
import { existsSync as existsSync4, mkdirSync as mkdirSync3, readdirSync as readdirSync3, writeFileSync as writeFileSync4 } from "fs";
|
|
1704
|
-
import { dirname as dirname3, resolve as
|
|
1788
|
+
import { dirname as dirname3, resolve as resolve4 } from "path";
|
|
1705
1789
|
import process9 from "process";
|
|
1706
1790
|
import { Buffer as Buffer2 } from "buffer";
|
|
1707
1791
|
import { createCipheriv as createCipheriv2, createDecipheriv as createDecipheriv2, randomBytes as randomBytes2 } from "crypto";
|
|
@@ -1713,16 +1797,6 @@ import { pipeline as pipeline2 } from "stream/promises";
|
|
|
1713
1797
|
import { createGzip as createGzip2 } from "zlib";
|
|
1714
1798
|
import process42 from "process";
|
|
1715
1799
|
import process32 from "process";
|
|
1716
|
-
import { Buffer as Buffer22 } from "buffer";
|
|
1717
|
-
import { createCipheriv as createCipheriv22, createDecipheriv as createDecipheriv22, randomBytes as randomBytes22 } from "crypto";
|
|
1718
|
-
import { closeSync as closeSync22, createReadStream as createReadStream22, createWriteStream as createWriteStream22, existsSync as existsSync42, fsyncSync as fsyncSync22, openSync as openSync22, writeFileSync as writeFileSync42 } from "fs";
|
|
1719
|
-
import { access as access22, constants as constants22, mkdir as mkdir22, readdir as readdir22, rename as rename22, stat as stat22, unlink as unlink22, writeFile as writeFile22 } from "fs/promises";
|
|
1720
|
-
import { join as join5 } from "path";
|
|
1721
|
-
import process11 from "process";
|
|
1722
|
-
import { pipeline as pipeline22 } from "stream/promises";
|
|
1723
|
-
import { createGzip as createGzip22 } from "zlib";
|
|
1724
|
-
import process10 from "process";
|
|
1725
|
-
import process92 from "process";
|
|
1726
1800
|
function deepMerge3(target, source) {
|
|
1727
1801
|
if (Array.isArray(source) && Array.isArray(target) && source.length === 2 && target.length === 2 && isObject3(source[0]) && "id" in source[0] && source[0].id === 3 && isObject3(source[1]) && "id" in source[1] && source[1].id === 4) {
|
|
1728
1802
|
return source;
|
|
@@ -1880,27 +1954,39 @@ async function loadConfig4({
|
|
|
1880
1954
|
];
|
|
1881
1955
|
for (const configPath of configPaths) {
|
|
1882
1956
|
for (const ext of extensions) {
|
|
1883
|
-
const fullPath =
|
|
1957
|
+
const fullPath = resolve4(baseDir, `${configPath}${ext}`);
|
|
1884
1958
|
const config22 = await tryLoadConfig3(fullPath, defaultConfig2);
|
|
1885
|
-
if (config22 !== null)
|
|
1959
|
+
if (config22 !== null) {
|
|
1886
1960
|
return config22;
|
|
1961
|
+
}
|
|
1887
1962
|
}
|
|
1888
1963
|
}
|
|
1889
|
-
|
|
1964
|
+
try {
|
|
1965
|
+
const pkgPath = resolve4(baseDir, "package.json");
|
|
1966
|
+
if (existsSync4(pkgPath)) {
|
|
1967
|
+
const pkg = await import(pkgPath);
|
|
1968
|
+
const pkgConfig = pkg[name];
|
|
1969
|
+
if (pkgConfig && typeof pkgConfig === "object" && !Array.isArray(pkgConfig)) {
|
|
1970
|
+
try {
|
|
1971
|
+
return deepMerge3(defaultConfig2, pkgConfig);
|
|
1972
|
+
} catch {}
|
|
1973
|
+
}
|
|
1974
|
+
}
|
|
1975
|
+
} catch {}
|
|
1890
1976
|
return defaultConfig2;
|
|
1891
1977
|
}
|
|
1892
|
-
var defaultConfigDir3 =
|
|
1893
|
-
var defaultGeneratedDir3 =
|
|
1978
|
+
var defaultConfigDir3 = resolve4(process9.cwd(), "config");
|
|
1979
|
+
var defaultGeneratedDir3 = resolve4(process9.cwd(), "src/generated");
|
|
1894
1980
|
function getProjectRoot2(filePath, options = {}) {
|
|
1895
1981
|
let path = process22.cwd();
|
|
1896
1982
|
while (path.includes("storage"))
|
|
1897
1983
|
path = resolve22(path, "..");
|
|
1898
1984
|
const finalPath = resolve22(path, filePath || "");
|
|
1899
1985
|
if (options?.relative)
|
|
1900
|
-
return
|
|
1986
|
+
return relative2(process22.cwd(), finalPath);
|
|
1901
1987
|
return finalPath;
|
|
1902
1988
|
}
|
|
1903
|
-
var defaultLogDirectory2 = process22.env.CLARITY_LOG_DIR ||
|
|
1989
|
+
var defaultLogDirectory2 = process22.env.CLARITY_LOG_DIR || join3(getProjectRoot2(), "logs");
|
|
1904
1990
|
var defaultConfig2 = {
|
|
1905
1991
|
level: "info",
|
|
1906
1992
|
defaultName: "clarity",
|
|
@@ -1960,7 +2046,6 @@ async function isServerProcess2() {
|
|
|
1960
2046
|
}
|
|
1961
2047
|
return false;
|
|
1962
2048
|
}
|
|
1963
|
-
|
|
1964
2049
|
class JsonFormatter2 {
|
|
1965
2050
|
async format(entry) {
|
|
1966
2051
|
const isServer = await isServerProcess2();
|
|
@@ -2091,12 +2176,6 @@ class Logger2 {
|
|
|
2091
2176
|
...configOptions,
|
|
2092
2177
|
timestamp: hasTimestamp || this.config.timestamp
|
|
2093
2178
|
};
|
|
2094
|
-
if (!this.config.logDirectory) {
|
|
2095
|
-
this.config.logDirectory = config4.logDirectory;
|
|
2096
|
-
}
|
|
2097
|
-
if (!isBrowserProcess2()) {
|
|
2098
|
-
mkdir2(this.config.logDirectory, { recursive: true, mode: 493 }).catch((err) => console.error("Failed to create log directory:", err));
|
|
2099
|
-
}
|
|
2100
2179
|
this.currentLogFile = this.generateLogFilename();
|
|
2101
2180
|
this.encryptionKeys = new Map;
|
|
2102
2181
|
if (this.validateEncryptionConfig()) {
|
|
@@ -2210,7 +2289,7 @@ class Logger2 {
|
|
|
2210
2289
|
const errorMessage = typeof error.message === "string" ? error.message : "Unknown error";
|
|
2211
2290
|
console.error(`Network error during write attempt ${retries + 1}/${maxRetries}:`, errorMessage);
|
|
2212
2291
|
const delay = backoffDelay * 2 ** retries;
|
|
2213
|
-
await new Promise((
|
|
2292
|
+
await new Promise((resolve32) => setTimeout(resolve32, delay));
|
|
2214
2293
|
retries++;
|
|
2215
2294
|
continue;
|
|
2216
2295
|
}
|
|
@@ -2238,7 +2317,7 @@ class Logger2 {
|
|
|
2238
2317
|
}
|
|
2239
2318
|
retries++;
|
|
2240
2319
|
const delay = backoffDelay * 2 ** (retries - 1);
|
|
2241
|
-
await new Promise((
|
|
2320
|
+
await new Promise((resolve32) => setTimeout(resolve32, delay));
|
|
2242
2321
|
}
|
|
2243
2322
|
}
|
|
2244
2323
|
})();
|
|
@@ -2361,11 +2440,11 @@ class Logger2 {
|
|
|
2361
2440
|
};
|
|
2362
2441
|
}
|
|
2363
2442
|
async compressData(data) {
|
|
2364
|
-
return new Promise((
|
|
2443
|
+
return new Promise((resolve32, reject) => {
|
|
2365
2444
|
const gzip = createGzip2();
|
|
2366
2445
|
const chunks = [];
|
|
2367
2446
|
gzip.on("data", (chunk2) => chunks.push(chunk2));
|
|
2368
|
-
gzip.on("end", () =>
|
|
2447
|
+
gzip.on("end", () => resolve32(Buffer2.from(Buffer2.concat(chunks))));
|
|
2369
2448
|
gzip.on("error", reject);
|
|
2370
2449
|
gzip.write(data);
|
|
2371
2450
|
gzip.end();
|
|
@@ -2951,7 +3030,7 @@ class Logger2 {
|
|
|
2951
3030
|
if (isBrowserProcess2()) {
|
|
2952
3031
|
return Promise.resolve(true);
|
|
2953
3032
|
}
|
|
2954
|
-
return new Promise((
|
|
3033
|
+
return new Promise((resolve32) => {
|
|
2955
3034
|
console.error(`${styles2.cyan("?")} ${message} (y/n) `);
|
|
2956
3035
|
const onData = (data) => {
|
|
2957
3036
|
const input = data.toString().trim().toLowerCase();
|
|
@@ -2963,7 +3042,7 @@ class Logger2 {
|
|
|
2963
3042
|
} catch {}
|
|
2964
3043
|
process52.stdin.pause();
|
|
2965
3044
|
console.error("");
|
|
2966
|
-
|
|
3045
|
+
resolve32(input === "y" || input === "yes");
|
|
2967
3046
|
};
|
|
2968
3047
|
try {
|
|
2969
3048
|
if (typeof process52.stdin.setRawMode === "function") {
|
|
@@ -3165,1577 +3244,118 @@ class Logger2 {
|
|
|
3165
3244
|
}
|
|
3166
3245
|
}
|
|
3167
3246
|
var logger2 = new Logger2("stacks");
|
|
3168
|
-
|
|
3169
|
-
|
|
3170
|
-
|
|
3171
|
-
|
|
3172
|
-
|
|
3173
|
-
|
|
3174
|
-
|
|
3175
|
-
|
|
3176
|
-
|
|
3247
|
+
|
|
3248
|
+
// src/git-hooks.ts
|
|
3249
|
+
var execAsync = promisify(exec);
|
|
3250
|
+
var log2 = new Logger2("git-hooks", {
|
|
3251
|
+
showTags: true
|
|
3252
|
+
});
|
|
3253
|
+
var VALID_GIT_HOOKS = [
|
|
3254
|
+
"applypatch-msg",
|
|
3255
|
+
"pre-applypatch",
|
|
3256
|
+
"post-applypatch",
|
|
3257
|
+
"pre-commit",
|
|
3258
|
+
"pre-merge-commit",
|
|
3259
|
+
"prepare-commit-msg",
|
|
3260
|
+
"commit-msg",
|
|
3261
|
+
"post-commit",
|
|
3262
|
+
"pre-rebase",
|
|
3263
|
+
"post-checkout",
|
|
3264
|
+
"post-merge",
|
|
3265
|
+
"pre-push",
|
|
3266
|
+
"pre-receive",
|
|
3267
|
+
"update",
|
|
3268
|
+
"proc-receive",
|
|
3269
|
+
"post-receive",
|
|
3270
|
+
"post-update",
|
|
3271
|
+
"reference-transaction",
|
|
3272
|
+
"push-to-checkout",
|
|
3273
|
+
"pre-auto-gc",
|
|
3274
|
+
"post-rewrite",
|
|
3275
|
+
"sendemail-validate",
|
|
3276
|
+
"fsmonitor-watchman",
|
|
3277
|
+
"p4-changelist",
|
|
3278
|
+
"p4-prepare-changelist",
|
|
3279
|
+
"p4-post-changelist",
|
|
3280
|
+
"p4-pre-submit",
|
|
3281
|
+
"post-index-change"
|
|
3282
|
+
];
|
|
3283
|
+
var VALID_OPTIONS = ["preserveUnused", "verbose", "staged-lint"];
|
|
3284
|
+
var PREPEND_SCRIPT = `#!/bin/sh
|
|
3285
|
+
|
|
3286
|
+
if [ "$SKIP_BUN_GIT_HOOKS" = "1" ]; then
|
|
3287
|
+
echo "[INFO] SKIP_BUN_GIT_HOOKS is set to 1, skipping hook."
|
|
3288
|
+
exit 0
|
|
3289
|
+
fi
|
|
3290
|
+
|
|
3291
|
+
if [ -f "$BUN_GIT_HOOKS_RC" ]; then
|
|
3292
|
+
. "$BUN_GIT_HOOKS_RC"
|
|
3293
|
+
fi
|
|
3294
|
+
|
|
3295
|
+
`;
|
|
3296
|
+
function getGitProjectRoot(directory = process11.cwd()) {
|
|
3297
|
+
if (directory.endsWith(".git")) {
|
|
3298
|
+
return path.normalize(directory);
|
|
3177
3299
|
}
|
|
3178
|
-
|
|
3179
|
-
|
|
3300
|
+
let start = path.normalize(directory);
|
|
3301
|
+
if (!start || start === path.sep || start === ".") {
|
|
3302
|
+
return;
|
|
3180
3303
|
}
|
|
3181
|
-
|
|
3182
|
-
|
|
3183
|
-
|
|
3184
|
-
|
|
3185
|
-
|
|
3186
|
-
|
|
3187
|
-
|
|
3188
|
-
|
|
3189
|
-
|
|
3190
|
-
|
|
3191
|
-
|
|
3192
|
-
}
|
|
3193
|
-
} else if (isObject22(targetItem) && "path" in targetItem) {
|
|
3194
|
-
const existingItem = result.find((item) => isObject22(item) && ("path" in item) && item.path === targetItem.path);
|
|
3195
|
-
if (!existingItem) {
|
|
3196
|
-
result.push(targetItem);
|
|
3197
|
-
}
|
|
3198
|
-
} else if (!result.some((item) => deepEquals22(item, targetItem))) {
|
|
3199
|
-
result.push(targetItem);
|
|
3200
|
-
}
|
|
3201
|
-
}
|
|
3202
|
-
return result;
|
|
3203
|
-
}
|
|
3204
|
-
if (source.every((item) => typeof item === "string") && target.every((item) => typeof item === "string")) {
|
|
3205
|
-
const result = [...source];
|
|
3206
|
-
for (const item of target) {
|
|
3207
|
-
if (!result.includes(item)) {
|
|
3208
|
-
result.push(item);
|
|
3304
|
+
const fullPath = path.join(start, ".git");
|
|
3305
|
+
if (fs.existsSync(fullPath)) {
|
|
3306
|
+
if (!fs.lstatSync(fullPath).isDirectory()) {
|
|
3307
|
+
const content = fs.readFileSync(fullPath, { encoding: "utf-8" });
|
|
3308
|
+
const match = /^gitdir: (.*)\s*$/.exec(content);
|
|
3309
|
+
if (match) {
|
|
3310
|
+
const gitDir = match[1];
|
|
3311
|
+
let commonDir = path.join(gitDir, "commondir");
|
|
3312
|
+
if (fs.existsSync(commonDir)) {
|
|
3313
|
+
commonDir = fs.readFileSync(commonDir, "utf8").trim();
|
|
3314
|
+
return path.resolve(gitDir, commonDir);
|
|
3209
3315
|
}
|
|
3316
|
+
return path.normalize(gitDir);
|
|
3210
3317
|
}
|
|
3211
|
-
return result;
|
|
3212
3318
|
}
|
|
3213
|
-
return
|
|
3319
|
+
return path.normalize(fullPath);
|
|
3214
3320
|
}
|
|
3215
|
-
|
|
3216
|
-
|
|
3321
|
+
const parentDir = path.dirname(start);
|
|
3322
|
+
if (parentDir === start) {
|
|
3323
|
+
return;
|
|
3217
3324
|
}
|
|
3218
|
-
|
|
3219
|
-
|
|
3220
|
-
|
|
3221
|
-
|
|
3222
|
-
|
|
3223
|
-
continue;
|
|
3224
|
-
} else if (isObject22(sourceValue) && isObject22(merged[key])) {
|
|
3225
|
-
merged[key] = deepMerge22(merged[key], sourceValue);
|
|
3226
|
-
} else if (Array.isArray(sourceValue) && Array.isArray(merged[key])) {
|
|
3227
|
-
if (sourceValue.length > 0 && merged[key].length > 0 && isObject22(sourceValue[0]) && isObject22(merged[key][0])) {
|
|
3228
|
-
const result = [...sourceValue];
|
|
3229
|
-
for (const targetItem of merged[key]) {
|
|
3230
|
-
if (isObject22(targetItem) && "name" in targetItem) {
|
|
3231
|
-
const existingItem = result.find((item) => isObject22(item) && ("name" in item) && item.name === targetItem.name);
|
|
3232
|
-
if (!existingItem) {
|
|
3233
|
-
result.push(targetItem);
|
|
3234
|
-
}
|
|
3235
|
-
} else if (isObject22(targetItem) && "path" in targetItem) {
|
|
3236
|
-
const existingItem = result.find((item) => isObject22(item) && ("path" in item) && item.path === targetItem.path);
|
|
3237
|
-
if (!existingItem) {
|
|
3238
|
-
result.push(targetItem);
|
|
3239
|
-
}
|
|
3240
|
-
} else if (!result.some((item) => deepEquals22(item, targetItem))) {
|
|
3241
|
-
result.push(targetItem);
|
|
3242
|
-
}
|
|
3243
|
-
}
|
|
3244
|
-
merged[key] = result;
|
|
3245
|
-
} else if (sourceValue.every((item) => typeof item === "string") && merged[key].every((item) => typeof item === "string")) {
|
|
3246
|
-
const result = [...sourceValue];
|
|
3247
|
-
for (const item of merged[key]) {
|
|
3248
|
-
if (!result.includes(item)) {
|
|
3249
|
-
result.push(item);
|
|
3250
|
-
}
|
|
3251
|
-
}
|
|
3252
|
-
merged[key] = result;
|
|
3253
|
-
} else {
|
|
3254
|
-
merged[key] = sourceValue;
|
|
3255
|
-
}
|
|
3256
|
-
} else {
|
|
3257
|
-
merged[key] = sourceValue;
|
|
3258
|
-
}
|
|
3259
|
-
}
|
|
3325
|
+
return getGitProjectRoot(parentDir);
|
|
3326
|
+
}
|
|
3327
|
+
function getProjectRootDirectoryFromNodeModules(projectPath) {
|
|
3328
|
+
function _arraysAreEqual(a1, a2) {
|
|
3329
|
+
return JSON.stringify(a1) === JSON.stringify(a2);
|
|
3260
3330
|
}
|
|
3261
|
-
|
|
3331
|
+
const projDir = projectPath.split(/[\\/]/);
|
|
3332
|
+
const indexOfStoreDir = projDir.indexOf(".store");
|
|
3333
|
+
if (indexOfStoreDir > -1) {
|
|
3334
|
+
return projDir.slice(0, indexOfStoreDir - 1).join("/");
|
|
3335
|
+
}
|
|
3336
|
+
if (projDir.length > 3 && _arraysAreEqual(projDir.slice(-3), ["node_modules", ".bin", "bun-git-hooks"])) {
|
|
3337
|
+
return projDir.slice(0, -3).join("/");
|
|
3338
|
+
}
|
|
3339
|
+
if (projDir.length > 2 && _arraysAreEqual(projDir.slice(-2), ["node_modules", "bun-git-hooks"])) {
|
|
3340
|
+
return projDir.slice(0, -2).join("/");
|
|
3341
|
+
}
|
|
3342
|
+
return;
|
|
3262
3343
|
}
|
|
3263
|
-
function
|
|
3264
|
-
if (
|
|
3265
|
-
|
|
3266
|
-
if (Array.isArray(a) && Array.isArray(b)) {
|
|
3267
|
-
if (a.length !== b.length)
|
|
3268
|
-
return false;
|
|
3269
|
-
for (let i = 0;i < a.length; i++) {
|
|
3270
|
-
if (!deepEquals22(a[i], b[i]))
|
|
3271
|
-
return false;
|
|
3272
|
-
}
|
|
3273
|
-
return true;
|
|
3344
|
+
function checkBunGitHooksInDependencies(projectRootPath) {
|
|
3345
|
+
if (typeof projectRootPath !== "string") {
|
|
3346
|
+
throw new TypeError("Package json path is not a string!");
|
|
3274
3347
|
}
|
|
3275
|
-
|
|
3276
|
-
|
|
3277
|
-
|
|
3278
|
-
if (keysA.length !== keysB.length)
|
|
3279
|
-
return false;
|
|
3280
|
-
for (const key of keysA) {
|
|
3281
|
-
if (!Object.prototype.hasOwnProperty.call(b, key))
|
|
3282
|
-
return false;
|
|
3283
|
-
if (!deepEquals22(a[key], b[key]))
|
|
3284
|
-
return false;
|
|
3285
|
-
}
|
|
3348
|
+
const { packageJsonContent } = _getPackageJson(projectRootPath);
|
|
3349
|
+
if ("dependencies" in packageJsonContent && "bun-git-hooks" in packageJsonContent.dependencies) {
|
|
3350
|
+
console.warn("[WARN] You should move `bun-git-hooks` to your devDependencies!");
|
|
3286
3351
|
return true;
|
|
3287
3352
|
}
|
|
3288
|
-
|
|
3289
|
-
|
|
3290
|
-
|
|
3291
|
-
return
|
|
3353
|
+
if (!("devDependencies" in packageJsonContent)) {
|
|
3354
|
+
return false;
|
|
3355
|
+
}
|
|
3356
|
+
return "bun-git-hooks" in packageJsonContent.devDependencies;
|
|
3292
3357
|
}
|
|
3293
|
-
|
|
3294
|
-
showTags: true
|
|
3295
|
-
});
|
|
3296
|
-
async function tryLoadConfig22(configPath, defaultConfig22) {
|
|
3297
|
-
if (!existsSync32(configPath))
|
|
3298
|
-
return null;
|
|
3299
|
-
try {
|
|
3300
|
-
const importedConfig = await import(configPath);
|
|
3301
|
-
const loadedConfig = importedConfig.default || importedConfig;
|
|
3302
|
-
if (typeof loadedConfig !== "object" || loadedConfig === null || Array.isArray(loadedConfig))
|
|
3303
|
-
return null;
|
|
3304
|
-
try {
|
|
3305
|
-
return deepMerge22(defaultConfig22, loadedConfig);
|
|
3306
|
-
} catch {
|
|
3307
|
-
return null;
|
|
3308
|
-
}
|
|
3309
|
-
} catch {
|
|
3310
|
-
return null;
|
|
3311
|
-
}
|
|
3312
|
-
}
|
|
3313
|
-
async function loadConfig32({
|
|
3314
|
-
name = "",
|
|
3315
|
-
cwd,
|
|
3316
|
-
defaultConfig: defaultConfig22
|
|
3317
|
-
}) {
|
|
3318
|
-
const baseDir = cwd || process62.cwd();
|
|
3319
|
-
const extensions = [".ts", ".js", ".mjs", ".cjs", ".json"];
|
|
3320
|
-
const configPaths = [
|
|
3321
|
-
`${name}.config`,
|
|
3322
|
-
`.${name}.config`,
|
|
3323
|
-
name,
|
|
3324
|
-
`.${name}`
|
|
3325
|
-
];
|
|
3326
|
-
for (const configPath of configPaths) {
|
|
3327
|
-
for (const ext of extensions) {
|
|
3328
|
-
const fullPath = resolve32(baseDir, `${configPath}${ext}`);
|
|
3329
|
-
const config32 = await tryLoadConfig22(fullPath, defaultConfig22);
|
|
3330
|
-
if (config32 !== null) {
|
|
3331
|
-
log2.debug(`Configuration found: ${configPath}${ext}`);
|
|
3332
|
-
return config32;
|
|
3333
|
-
}
|
|
3334
|
-
}
|
|
3335
|
-
}
|
|
3336
|
-
try {
|
|
3337
|
-
const pkgPath = resolve32(baseDir, "package.json");
|
|
3338
|
-
if (existsSync32(pkgPath)) {
|
|
3339
|
-
const pkg = await import(pkgPath);
|
|
3340
|
-
const pkgConfig = pkg[name];
|
|
3341
|
-
if (pkgConfig && typeof pkgConfig === "object" && !Array.isArray(pkgConfig)) {
|
|
3342
|
-
try {
|
|
3343
|
-
log2.debug(`Configuration found in package.json!`);
|
|
3344
|
-
return deepMerge22(defaultConfig22, pkgConfig);
|
|
3345
|
-
} catch {}
|
|
3346
|
-
}
|
|
3347
|
-
}
|
|
3348
|
-
} catch {}
|
|
3349
|
-
log2.debug("No configuration found, now using default config");
|
|
3350
|
-
return defaultConfig22;
|
|
3351
|
-
}
|
|
3352
|
-
var defaultConfigDir22 = resolve32(process62.cwd(), "config");
|
|
3353
|
-
var defaultGeneratedDir22 = resolve32(process62.cwd(), "src/generated");
|
|
3354
|
-
function getProjectRoot22(filePath, options = {}) {
|
|
3355
|
-
let path = process72.cwd();
|
|
3356
|
-
while (path.includes("storage"))
|
|
3357
|
-
path = resolve4(path, "..");
|
|
3358
|
-
const finalPath = resolve4(path, filePath || "");
|
|
3359
|
-
if (options?.relative)
|
|
3360
|
-
return relative2(process72.cwd(), finalPath);
|
|
3361
|
-
return finalPath;
|
|
3362
|
-
}
|
|
3363
|
-
var defaultLogDirectory22 = process72.env.CLARITY_LOG_DIR || join3(getProjectRoot22(), "logs");
|
|
3364
|
-
var defaultConfig22 = {
|
|
3365
|
-
level: "info",
|
|
3366
|
-
defaultName: "clarity",
|
|
3367
|
-
timestamp: true,
|
|
3368
|
-
colors: true,
|
|
3369
|
-
format: "text",
|
|
3370
|
-
maxLogSize: 10485760,
|
|
3371
|
-
logDatePattern: "YYYY-MM-DD",
|
|
3372
|
-
logDirectory: defaultLogDirectory22,
|
|
3373
|
-
rotation: {
|
|
3374
|
-
frequency: "daily",
|
|
3375
|
-
maxSize: 10485760,
|
|
3376
|
-
maxFiles: 5,
|
|
3377
|
-
compress: false,
|
|
3378
|
-
rotateHour: 0,
|
|
3379
|
-
rotateMinute: 0,
|
|
3380
|
-
rotateDayOfWeek: 0,
|
|
3381
|
-
rotateDayOfMonth: 1,
|
|
3382
|
-
encrypt: false
|
|
3383
|
-
},
|
|
3384
|
-
verbose: false
|
|
3385
|
-
};
|
|
3386
|
-
async function loadConfig42() {
|
|
3387
|
-
try {
|
|
3388
|
-
const loadedConfig = await loadConfig32({
|
|
3389
|
-
name: "clarity",
|
|
3390
|
-
defaultConfig: defaultConfig22,
|
|
3391
|
-
cwd: process72.cwd(),
|
|
3392
|
-
endpoint: "",
|
|
3393
|
-
headers: {}
|
|
3394
|
-
});
|
|
3395
|
-
return { ...defaultConfig22, ...loadedConfig };
|
|
3396
|
-
} catch {
|
|
3397
|
-
return defaultConfig22;
|
|
3398
|
-
}
|
|
3399
|
-
}
|
|
3400
|
-
var config22 = await loadConfig42();
|
|
3401
|
-
function isBrowserProcess22() {
|
|
3402
|
-
if (process92.env.NODE_ENV === "test" || process92.env.BUN_ENV === "test") {
|
|
3403
|
-
return false;
|
|
3404
|
-
}
|
|
3405
|
-
return typeof window !== "undefined";
|
|
3406
|
-
}
|
|
3407
|
-
async function isServerProcess22() {
|
|
3408
|
-
if (process92.env.NODE_ENV === "test" || process92.env.BUN_ENV === "test") {
|
|
3409
|
-
return true;
|
|
3410
|
-
}
|
|
3411
|
-
if (typeof navigator !== "undefined" && navigator.product === "ReactNative") {
|
|
3412
|
-
return true;
|
|
3413
|
-
}
|
|
3414
|
-
if (typeof process92 !== "undefined") {
|
|
3415
|
-
const type = process92.type;
|
|
3416
|
-
if (type === "renderer" || type === "worker") {
|
|
3417
|
-
return false;
|
|
3418
|
-
}
|
|
3419
|
-
return !!(process92.versions && (process92.versions.node || process92.versions.bun));
|
|
3420
|
-
}
|
|
3421
|
-
return false;
|
|
3422
|
-
}
|
|
3423
|
-
class JsonFormatter22 {
|
|
3424
|
-
async format(entry) {
|
|
3425
|
-
const isServer = await isServerProcess22();
|
|
3426
|
-
const metadata = await this.getMetadata(isServer);
|
|
3427
|
-
return JSON.stringify({
|
|
3428
|
-
timestamp: entry.timestamp.toISOString(),
|
|
3429
|
-
level: entry.level,
|
|
3430
|
-
name: entry.name,
|
|
3431
|
-
message: entry.message,
|
|
3432
|
-
metadata
|
|
3433
|
-
});
|
|
3434
|
-
}
|
|
3435
|
-
async getMetadata(isServer) {
|
|
3436
|
-
if (isServer) {
|
|
3437
|
-
const { hostname } = await import("os");
|
|
3438
|
-
return {
|
|
3439
|
-
pid: process10.pid,
|
|
3440
|
-
hostname: hostname(),
|
|
3441
|
-
environment: process10.env.NODE_ENV || "development",
|
|
3442
|
-
platform: process10.platform,
|
|
3443
|
-
version: process10.version
|
|
3444
|
-
};
|
|
3445
|
-
}
|
|
3446
|
-
return {
|
|
3447
|
-
userAgent: navigator.userAgent,
|
|
3448
|
-
hostname: window.location.hostname || "browser",
|
|
3449
|
-
environment: process10.env.NODE_ENV || process10.env.BUN_ENV || "development",
|
|
3450
|
-
viewport: {
|
|
3451
|
-
width: window.innerWidth,
|
|
3452
|
-
height: window.innerHeight
|
|
3453
|
-
},
|
|
3454
|
-
language: navigator.language
|
|
3455
|
-
};
|
|
3456
|
-
}
|
|
3457
|
-
}
|
|
3458
|
-
var terminalStyles22 = {
|
|
3459
|
-
red: (text) => `\x1B[31m${text}\x1B[0m`,
|
|
3460
|
-
green: (text) => `\x1B[32m${text}\x1B[0m`,
|
|
3461
|
-
yellow: (text) => `\x1B[33m${text}\x1B[0m`,
|
|
3462
|
-
blue: (text) => `\x1B[34m${text}\x1B[0m`,
|
|
3463
|
-
magenta: (text) => `\x1B[35m${text}\x1B[0m`,
|
|
3464
|
-
cyan: (text) => `\x1B[36m${text}\x1B[0m`,
|
|
3465
|
-
white: (text) => `\x1B[37m${text}\x1B[0m`,
|
|
3466
|
-
gray: (text) => `\x1B[90m${text}\x1B[0m`,
|
|
3467
|
-
bgRed: (text) => `\x1B[41m${text}\x1B[0m`,
|
|
3468
|
-
bgYellow: (text) => `\x1B[43m${text}\x1B[0m`,
|
|
3469
|
-
bold: (text) => `\x1B[1m${text}\x1B[0m`,
|
|
3470
|
-
dim: (text) => `\x1B[2m${text}\x1B[0m`,
|
|
3471
|
-
italic: (text) => `\x1B[3m${text}\x1B[0m`,
|
|
3472
|
-
underline: (text) => `\x1B[4m${text}\x1B[0m`,
|
|
3473
|
-
reset: "\x1B[0m"
|
|
3474
|
-
};
|
|
3475
|
-
var styles22 = terminalStyles22;
|
|
3476
|
-
var red22 = terminalStyles22.red;
|
|
3477
|
-
var green22 = terminalStyles22.green;
|
|
3478
|
-
var yellow22 = terminalStyles22.yellow;
|
|
3479
|
-
var blue22 = terminalStyles22.blue;
|
|
3480
|
-
var magenta22 = terminalStyles22.magenta;
|
|
3481
|
-
var cyan22 = terminalStyles22.cyan;
|
|
3482
|
-
var white22 = terminalStyles22.white;
|
|
3483
|
-
var gray22 = terminalStyles22.gray;
|
|
3484
|
-
var bgRed22 = terminalStyles22.bgRed;
|
|
3485
|
-
var bgYellow22 = terminalStyles22.bgYellow;
|
|
3486
|
-
var bold22 = terminalStyles22.bold;
|
|
3487
|
-
var dim22 = terminalStyles22.dim;
|
|
3488
|
-
var italic22 = terminalStyles22.italic;
|
|
3489
|
-
var underline22 = terminalStyles22.underline;
|
|
3490
|
-
var reset22 = terminalStyles22.reset;
|
|
3491
|
-
var defaultFingersCrossedConfig22 = {
|
|
3492
|
-
activationLevel: "error",
|
|
3493
|
-
bufferSize: 50,
|
|
3494
|
-
flushOnDeactivation: true,
|
|
3495
|
-
stopBuffering: false
|
|
3496
|
-
};
|
|
3497
|
-
var levelIcons22 = {
|
|
3498
|
-
debug: "\uD83D\uDD0D",
|
|
3499
|
-
info: blue22("ℹ"),
|
|
3500
|
-
success: green22("✓"),
|
|
3501
|
-
warning: bgYellow22(white22(bold22(" WARN "))),
|
|
3502
|
-
error: bgRed22(white22(bold22(" ERROR ")))
|
|
3503
|
-
};
|
|
3504
|
-
|
|
3505
|
-
class Logger22 {
|
|
3506
|
-
name;
|
|
3507
|
-
fileLocks = new Map;
|
|
3508
|
-
currentKeyId = null;
|
|
3509
|
-
keys = new Map;
|
|
3510
|
-
config;
|
|
3511
|
-
options;
|
|
3512
|
-
formatter;
|
|
3513
|
-
timers = new Set;
|
|
3514
|
-
subLoggers = new Set;
|
|
3515
|
-
fingersCrossedBuffer = [];
|
|
3516
|
-
fingersCrossedConfig;
|
|
3517
|
-
fingersCrossedActive = false;
|
|
3518
|
-
currentLogFile;
|
|
3519
|
-
rotationTimeout;
|
|
3520
|
-
keyRotationTimeout;
|
|
3521
|
-
encryptionKeys;
|
|
3522
|
-
logBuffer = [];
|
|
3523
|
-
isActivated = false;
|
|
3524
|
-
pendingOperations = [];
|
|
3525
|
-
enabled;
|
|
3526
|
-
fancy;
|
|
3527
|
-
tagFormat;
|
|
3528
|
-
timestampPosition;
|
|
3529
|
-
environment;
|
|
3530
|
-
ANSI_PATTERN = /\u001B\[.*?m/g;
|
|
3531
|
-
activeProgressBar = null;
|
|
3532
|
-
constructor(name, options = {}) {
|
|
3533
|
-
this.name = name;
|
|
3534
|
-
this.config = { ...config22 };
|
|
3535
|
-
this.options = this.normalizeOptions(options);
|
|
3536
|
-
this.formatter = this.options.formatter || new JsonFormatter22;
|
|
3537
|
-
this.enabled = options.enabled ?? true;
|
|
3538
|
-
this.fancy = options.fancy ?? true;
|
|
3539
|
-
this.tagFormat = options.tagFormat ?? { prefix: "[", suffix: "]" };
|
|
3540
|
-
this.timestampPosition = options.timestampPosition ?? "right";
|
|
3541
|
-
this.environment = options.environment ?? process11.env.APP_ENV ?? "local";
|
|
3542
|
-
this.fingersCrossedConfig = this.initializeFingersCrossedConfig(options);
|
|
3543
|
-
const configOptions = { ...options };
|
|
3544
|
-
const hasTimestamp = options.timestamp !== undefined;
|
|
3545
|
-
if (hasTimestamp) {
|
|
3546
|
-
delete configOptions.timestamp;
|
|
3547
|
-
}
|
|
3548
|
-
this.config = {
|
|
3549
|
-
...this.config,
|
|
3550
|
-
...configOptions,
|
|
3551
|
-
timestamp: hasTimestamp || this.config.timestamp
|
|
3552
|
-
};
|
|
3553
|
-
if (!this.config.logDirectory) {
|
|
3554
|
-
this.config.logDirectory = config22.logDirectory;
|
|
3555
|
-
}
|
|
3556
|
-
if (!isBrowserProcess22()) {
|
|
3557
|
-
mkdir22(this.config.logDirectory, { recursive: true, mode: 493 }).catch((err) => console.error("Failed to create log directory:", err));
|
|
3558
|
-
}
|
|
3559
|
-
this.currentLogFile = this.generateLogFilename();
|
|
3560
|
-
this.encryptionKeys = new Map;
|
|
3561
|
-
if (this.validateEncryptionConfig()) {
|
|
3562
|
-
this.setupRotation();
|
|
3563
|
-
const initialKeyId = this.generateKeyId();
|
|
3564
|
-
const initialKey = this.generateKey();
|
|
3565
|
-
this.currentKeyId = initialKeyId;
|
|
3566
|
-
this.keys.set(initialKeyId, initialKey);
|
|
3567
|
-
this.encryptionKeys.set(initialKeyId, {
|
|
3568
|
-
key: initialKey,
|
|
3569
|
-
createdAt: new Date
|
|
3570
|
-
});
|
|
3571
|
-
this.setupKeyRotation();
|
|
3572
|
-
}
|
|
3573
|
-
}
|
|
3574
|
-
initializeFingersCrossedConfig(options) {
|
|
3575
|
-
if (!options.fingersCrossedEnabled && options.fingersCrossed) {
|
|
3576
|
-
return {
|
|
3577
|
-
...defaultFingersCrossedConfig22,
|
|
3578
|
-
...options.fingersCrossed
|
|
3579
|
-
};
|
|
3580
|
-
}
|
|
3581
|
-
if (!options.fingersCrossedEnabled) {
|
|
3582
|
-
return null;
|
|
3583
|
-
}
|
|
3584
|
-
if (!options.fingersCrossed) {
|
|
3585
|
-
return { ...defaultFingersCrossedConfig22 };
|
|
3586
|
-
}
|
|
3587
|
-
return {
|
|
3588
|
-
...defaultFingersCrossedConfig22,
|
|
3589
|
-
...options.fingersCrossed
|
|
3590
|
-
};
|
|
3591
|
-
}
|
|
3592
|
-
normalizeOptions(options) {
|
|
3593
|
-
const defaultOptions = {
|
|
3594
|
-
format: "json",
|
|
3595
|
-
level: "info",
|
|
3596
|
-
logDirectory: config22.logDirectory,
|
|
3597
|
-
rotation: undefined,
|
|
3598
|
-
timestamp: undefined,
|
|
3599
|
-
fingersCrossed: {},
|
|
3600
|
-
enabled: true,
|
|
3601
|
-
showTags: false,
|
|
3602
|
-
formatter: undefined
|
|
3603
|
-
};
|
|
3604
|
-
const mergedOptions = {
|
|
3605
|
-
...defaultOptions,
|
|
3606
|
-
...Object.fromEntries(Object.entries(options).filter(([, value]) => value !== undefined))
|
|
3607
|
-
};
|
|
3608
|
-
if (!mergedOptions.level || !["debug", "info", "success", "warning", "error"].includes(mergedOptions.level)) {
|
|
3609
|
-
mergedOptions.level = defaultOptions.level;
|
|
3610
|
-
}
|
|
3611
|
-
return mergedOptions;
|
|
3612
|
-
}
|
|
3613
|
-
async writeToFile(data) {
|
|
3614
|
-
const cancelled = false;
|
|
3615
|
-
const operationPromise = (async () => {
|
|
3616
|
-
let fd;
|
|
3617
|
-
let retries = 0;
|
|
3618
|
-
const maxRetries = 3;
|
|
3619
|
-
const backoffDelay = 1000;
|
|
3620
|
-
while (retries < maxRetries) {
|
|
3621
|
-
try {
|
|
3622
|
-
try {
|
|
3623
|
-
try {
|
|
3624
|
-
await access22(this.config.logDirectory, constants22.F_OK | constants22.W_OK);
|
|
3625
|
-
} catch (err) {
|
|
3626
|
-
if (err instanceof Error && "code" in err) {
|
|
3627
|
-
if (err.code === "ENOENT") {
|
|
3628
|
-
await mkdir22(this.config.logDirectory, { recursive: true, mode: 493 });
|
|
3629
|
-
} else if (err.code === "EACCES") {
|
|
3630
|
-
throw new Error(`No write permission for log directory: ${this.config.logDirectory}`);
|
|
3631
|
-
} else {
|
|
3632
|
-
throw err;
|
|
3633
|
-
}
|
|
3634
|
-
} else {
|
|
3635
|
-
throw err;
|
|
3636
|
-
}
|
|
3637
|
-
}
|
|
3638
|
-
} catch (err) {
|
|
3639
|
-
console.error("Debug: [writeToFile] Failed to create log directory:", err);
|
|
3640
|
-
throw err;
|
|
3641
|
-
}
|
|
3642
|
-
if (cancelled)
|
|
3643
|
-
throw new Error("Operation cancelled: Logger was destroyed");
|
|
3644
|
-
const dataToWrite = this.validateEncryptionConfig() ? (await this.encrypt(data)).encrypted : Buffer22.from(data);
|
|
3645
|
-
try {
|
|
3646
|
-
if (!existsSync42(this.currentLogFile)) {
|
|
3647
|
-
await writeFile22(this.currentLogFile, "", { mode: 420 });
|
|
3648
|
-
}
|
|
3649
|
-
fd = openSync22(this.currentLogFile, "a", 420);
|
|
3650
|
-
writeFileSync42(fd, dataToWrite, { flag: "a" });
|
|
3651
|
-
fsyncSync22(fd);
|
|
3652
|
-
if (fd !== undefined) {
|
|
3653
|
-
closeSync22(fd);
|
|
3654
|
-
fd = undefined;
|
|
3655
|
-
}
|
|
3656
|
-
const stats = await stat22(this.currentLogFile);
|
|
3657
|
-
if (stats.size === 0) {
|
|
3658
|
-
await writeFile22(this.currentLogFile, dataToWrite, { flag: "w", mode: 420 });
|
|
3659
|
-
const retryStats = await stat22(this.currentLogFile);
|
|
3660
|
-
if (retryStats.size === 0) {
|
|
3661
|
-
throw new Error("File exists but is empty after retry write");
|
|
3662
|
-
}
|
|
3663
|
-
}
|
|
3664
|
-
return;
|
|
3665
|
-
} catch (err) {
|
|
3666
|
-
const error = err;
|
|
3667
|
-
if (error.code && ["ENETDOWN", "ENETUNREACH", "ENOTFOUND", "ETIMEDOUT"].includes(error.code)) {
|
|
3668
|
-
if (retries < maxRetries - 1) {
|
|
3669
|
-
const errorMessage = typeof error.message === "string" ? error.message : "Unknown error";
|
|
3670
|
-
console.error(`Network error during write attempt ${retries + 1}/${maxRetries}:`, errorMessage);
|
|
3671
|
-
const delay = backoffDelay * 2 ** retries;
|
|
3672
|
-
await new Promise((resolve52) => setTimeout(resolve52, delay));
|
|
3673
|
-
retries++;
|
|
3674
|
-
continue;
|
|
3675
|
-
}
|
|
3676
|
-
}
|
|
3677
|
-
if (error?.code && ["ENOSPC", "EDQUOT"].includes(error.code)) {
|
|
3678
|
-
throw new Error(`Disk quota exceeded or no space left on device: ${error.message}`);
|
|
3679
|
-
}
|
|
3680
|
-
console.error("Debug: [writeToFile] Error writing to file:", error);
|
|
3681
|
-
throw error;
|
|
3682
|
-
} finally {
|
|
3683
|
-
if (fd !== undefined) {
|
|
3684
|
-
try {
|
|
3685
|
-
closeSync22(fd);
|
|
3686
|
-
} catch (err) {
|
|
3687
|
-
console.error("Debug: [writeToFile] Error closing file descriptor:", err);
|
|
3688
|
-
}
|
|
3689
|
-
}
|
|
3690
|
-
}
|
|
3691
|
-
} catch (err) {
|
|
3692
|
-
if (retries === maxRetries - 1) {
|
|
3693
|
-
const error = err;
|
|
3694
|
-
const errorMessage = typeof error.message === "string" ? error.message : "Unknown error";
|
|
3695
|
-
console.error("Debug: [writeToFile] Max retries reached. Final error:", errorMessage);
|
|
3696
|
-
throw err;
|
|
3697
|
-
}
|
|
3698
|
-
retries++;
|
|
3699
|
-
const delay = backoffDelay * 2 ** (retries - 1);
|
|
3700
|
-
await new Promise((resolve52) => setTimeout(resolve52, delay));
|
|
3701
|
-
}
|
|
3702
|
-
}
|
|
3703
|
-
})();
|
|
3704
|
-
this.pendingOperations.push(operationPromise);
|
|
3705
|
-
const index = this.pendingOperations.length - 1;
|
|
3706
|
-
try {
|
|
3707
|
-
await operationPromise;
|
|
3708
|
-
} catch (err) {
|
|
3709
|
-
console.error("Debug: [writeToFile] Error in operation:", err);
|
|
3710
|
-
throw err;
|
|
3711
|
-
} finally {
|
|
3712
|
-
this.pendingOperations.splice(index, 1);
|
|
3713
|
-
}
|
|
3714
|
-
}
|
|
3715
|
-
generateLogFilename() {
|
|
3716
|
-
if (this.name.includes("stream-throughput") || this.name.includes("decompress-perf-test") || this.name.includes("decompression-latency") || this.name.includes("concurrent-read-test") || this.name.includes("clock-change-test")) {
|
|
3717
|
-
return join5(this.config.logDirectory, `${this.name}.log`);
|
|
3718
|
-
}
|
|
3719
|
-
if (this.name.includes("pending-test") || this.name.includes("temp-file-test") || this.name === "crash-test" || this.name === "corrupt-test" || this.name.includes("rotation-load-test") || this.name === "sigterm-test" || this.name === "sigint-test" || this.name === "failed-rotation-test" || this.name === "integration-test") {
|
|
3720
|
-
return join5(this.config.logDirectory, `${this.name}.log`);
|
|
3721
|
-
}
|
|
3722
|
-
const date = new Date().toISOString().split("T")[0];
|
|
3723
|
-
return join5(this.config.logDirectory, `${this.name}-${date}.log`);
|
|
3724
|
-
}
|
|
3725
|
-
setupRotation() {
|
|
3726
|
-
if (isBrowserProcess22())
|
|
3727
|
-
return;
|
|
3728
|
-
if (typeof this.config.rotation === "boolean")
|
|
3729
|
-
return;
|
|
3730
|
-
const config32 = this.config.rotation;
|
|
3731
|
-
let interval;
|
|
3732
|
-
switch (config32.frequency) {
|
|
3733
|
-
case "daily":
|
|
3734
|
-
interval = 86400000;
|
|
3735
|
-
break;
|
|
3736
|
-
case "weekly":
|
|
3737
|
-
interval = 604800000;
|
|
3738
|
-
break;
|
|
3739
|
-
case "monthly":
|
|
3740
|
-
interval = 2592000000;
|
|
3741
|
-
break;
|
|
3742
|
-
default:
|
|
3743
|
-
return;
|
|
3744
|
-
}
|
|
3745
|
-
this.rotationTimeout = setInterval(() => {
|
|
3746
|
-
this.rotateLog();
|
|
3747
|
-
}, interval);
|
|
3748
|
-
}
|
|
3749
|
-
setupKeyRotation() {
|
|
3750
|
-
if (!this.validateEncryptionConfig()) {
|
|
3751
|
-
console.error("Invalid encryption configuration detected during key rotation setup");
|
|
3752
|
-
return;
|
|
3753
|
-
}
|
|
3754
|
-
const rotation = this.config.rotation;
|
|
3755
|
-
const keyRotation = rotation.keyRotation;
|
|
3756
|
-
if (!keyRotation?.enabled) {
|
|
3757
|
-
return;
|
|
3758
|
-
}
|
|
3759
|
-
const rotationInterval = typeof keyRotation.interval === "number" ? keyRotation.interval : 60;
|
|
3760
|
-
const interval = Math.max(rotationInterval, 60) * 1000;
|
|
3761
|
-
this.keyRotationTimeout = setInterval(() => {
|
|
3762
|
-
this.rotateKeys().catch((error) => {
|
|
3763
|
-
console.error("Error rotating keys:", error);
|
|
3764
|
-
});
|
|
3765
|
-
}, interval);
|
|
3766
|
-
}
|
|
3767
|
-
async rotateKeys() {
|
|
3768
|
-
if (!this.validateEncryptionConfig()) {
|
|
3769
|
-
console.error("Invalid encryption configuration detected during key rotation");
|
|
3770
|
-
return;
|
|
3771
|
-
}
|
|
3772
|
-
const rotation = this.config.rotation;
|
|
3773
|
-
const keyRotation = rotation.keyRotation;
|
|
3774
|
-
const newKeyId = this.generateKeyId();
|
|
3775
|
-
const newKey = this.generateKey();
|
|
3776
|
-
this.currentKeyId = newKeyId;
|
|
3777
|
-
this.keys.set(newKeyId, newKey);
|
|
3778
|
-
this.encryptionKeys.set(newKeyId, {
|
|
3779
|
-
key: newKey,
|
|
3780
|
-
createdAt: new Date
|
|
3781
|
-
});
|
|
3782
|
-
const sortedKeys = Array.from(this.encryptionKeys.entries()).sort(([, a], [, b]) => b.createdAt.getTime() - a.createdAt.getTime());
|
|
3783
|
-
const maxKeyCount = typeof keyRotation.maxKeys === "number" ? keyRotation.maxKeys : 1;
|
|
3784
|
-
const maxKeys = Math.max(1, maxKeyCount);
|
|
3785
|
-
if (sortedKeys.length > maxKeys) {
|
|
3786
|
-
for (const [keyId] of sortedKeys.slice(maxKeys)) {
|
|
3787
|
-
this.encryptionKeys.delete(keyId);
|
|
3788
|
-
this.keys.delete(keyId);
|
|
3789
|
-
}
|
|
3790
|
-
}
|
|
3791
|
-
}
|
|
3792
|
-
generateKeyId() {
|
|
3793
|
-
return randomBytes22(16).toString("hex");
|
|
3794
|
-
}
|
|
3795
|
-
generateKey() {
|
|
3796
|
-
return randomBytes22(32);
|
|
3797
|
-
}
|
|
3798
|
-
getCurrentKey() {
|
|
3799
|
-
if (!this.currentKeyId) {
|
|
3800
|
-
throw new Error("Encryption is not properly initialized. Make sure encryption is enabled in the configuration.");
|
|
3801
|
-
}
|
|
3802
|
-
const key = this.keys.get(this.currentKeyId);
|
|
3803
|
-
if (!key) {
|
|
3804
|
-
throw new Error(`No key found for ID ${this.currentKeyId}. The encryption key may have been rotated or removed.`);
|
|
3805
|
-
}
|
|
3806
|
-
return { key, id: this.currentKeyId };
|
|
3807
|
-
}
|
|
3808
|
-
encrypt(data) {
|
|
3809
|
-
const { key } = this.getCurrentKey();
|
|
3810
|
-
const iv = randomBytes22(16);
|
|
3811
|
-
const cipher = createCipheriv22("aes-256-gcm", key, iv);
|
|
3812
|
-
const encrypted = Buffer22.concat([
|
|
3813
|
-
cipher.update(data, "utf8"),
|
|
3814
|
-
cipher.final()
|
|
3815
|
-
]);
|
|
3816
|
-
const authTag = cipher.getAuthTag();
|
|
3817
|
-
return {
|
|
3818
|
-
encrypted: Buffer22.concat([iv, encrypted, authTag]),
|
|
3819
|
-
iv
|
|
3820
|
-
};
|
|
3821
|
-
}
|
|
3822
|
-
async compressData(data) {
|
|
3823
|
-
return new Promise((resolve52, reject) => {
|
|
3824
|
-
const gzip = createGzip22();
|
|
3825
|
-
const chunks = [];
|
|
3826
|
-
gzip.on("data", (chunk2) => chunks.push(chunk2));
|
|
3827
|
-
gzip.on("end", () => resolve52(Buffer22.from(Buffer22.concat(chunks))));
|
|
3828
|
-
gzip.on("error", reject);
|
|
3829
|
-
gzip.write(data);
|
|
3830
|
-
gzip.end();
|
|
3831
|
-
});
|
|
3832
|
-
}
|
|
3833
|
-
getEncryptionOptions() {
|
|
3834
|
-
if (!this.config.rotation || typeof this.config.rotation === "boolean" || !this.config.rotation.encrypt) {
|
|
3835
|
-
return {};
|
|
3836
|
-
}
|
|
3837
|
-
const defaultOptions = {
|
|
3838
|
-
algorithm: "aes-256-cbc",
|
|
3839
|
-
compress: false
|
|
3840
|
-
};
|
|
3841
|
-
if (typeof this.config.rotation.encrypt === "object") {
|
|
3842
|
-
const encryptConfig = this.config.rotation.encrypt;
|
|
3843
|
-
return {
|
|
3844
|
-
...defaultOptions,
|
|
3845
|
-
...encryptConfig
|
|
3846
|
-
};
|
|
3847
|
-
}
|
|
3848
|
-
return defaultOptions;
|
|
3849
|
-
}
|
|
3850
|
-
async rotateLog() {
|
|
3851
|
-
if (isBrowserProcess22())
|
|
3852
|
-
return;
|
|
3853
|
-
const stats = await stat22(this.currentLogFile).catch(() => null);
|
|
3854
|
-
if (!stats)
|
|
3855
|
-
return;
|
|
3856
|
-
const config32 = this.config.rotation;
|
|
3857
|
-
if (typeof config32 === "boolean")
|
|
3858
|
-
return;
|
|
3859
|
-
if (config32.maxSize && stats.size >= config32.maxSize) {
|
|
3860
|
-
const oldFile = this.currentLogFile;
|
|
3861
|
-
const newFile = this.generateLogFilename();
|
|
3862
|
-
if (this.name.includes("rotation-load-test") || this.name === "failed-rotation-test") {
|
|
3863
|
-
const files = await readdir22(this.config.logDirectory);
|
|
3864
|
-
const rotatedFiles = files.filter((f) => f.startsWith(this.name) && /\.log\.\d+$/.test(f)).sort((a, b) => {
|
|
3865
|
-
const numA = Number.parseInt(a.match(/\.log\.(\d+)$/)?.[1] || "0");
|
|
3866
|
-
const numB = Number.parseInt(b.match(/\.log\.(\d+)$/)?.[1] || "0");
|
|
3867
|
-
return numB - numA;
|
|
3868
|
-
});
|
|
3869
|
-
const nextNum = rotatedFiles.length > 0 ? Number.parseInt(rotatedFiles[0].match(/\.log\.(\d+)$/)?.[1] || "0") + 1 : 1;
|
|
3870
|
-
const rotatedFile = `${oldFile}.${nextNum}`;
|
|
3871
|
-
if (await stat22(oldFile).catch(() => null)) {
|
|
3872
|
-
try {
|
|
3873
|
-
await rename22(oldFile, rotatedFile);
|
|
3874
|
-
if (config32.compress) {
|
|
3875
|
-
try {
|
|
3876
|
-
const compressedPath = `${rotatedFile}.gz`;
|
|
3877
|
-
await this.compressLogFile(rotatedFile, compressedPath);
|
|
3878
|
-
await unlink22(rotatedFile);
|
|
3879
|
-
} catch (err) {
|
|
3880
|
-
console.error("Error compressing rotated file:", err);
|
|
3881
|
-
}
|
|
3882
|
-
}
|
|
3883
|
-
if (rotatedFiles.length === 0 && !files.some((f) => f.endsWith(".log.1"))) {
|
|
3884
|
-
try {
|
|
3885
|
-
const backupPath = `${oldFile}.1`;
|
|
3886
|
-
await writeFile22(backupPath, "");
|
|
3887
|
-
} catch (err) {
|
|
3888
|
-
console.error("Error creating backup file:", err);
|
|
3889
|
-
}
|
|
3890
|
-
}
|
|
3891
|
-
} catch (err) {
|
|
3892
|
-
console.error(`Error during rotation: ${err instanceof Error ? err.message : String(err)}`);
|
|
3893
|
-
}
|
|
3894
|
-
}
|
|
3895
|
-
} else {
|
|
3896
|
-
const timestamp = new Date().toISOString().replace(/[:.]/g, "-");
|
|
3897
|
-
const rotatedFile = oldFile.replace(/\.log$/, `-${timestamp}.log`);
|
|
3898
|
-
if (await stat22(oldFile).catch(() => null)) {
|
|
3899
|
-
await rename22(oldFile, rotatedFile);
|
|
3900
|
-
}
|
|
3901
|
-
}
|
|
3902
|
-
this.currentLogFile = newFile;
|
|
3903
|
-
if (config32.maxFiles) {
|
|
3904
|
-
const files = await readdir22(this.config.logDirectory);
|
|
3905
|
-
const logFiles = files.filter((f) => f.startsWith(this.name)).sort((a, b) => b.localeCompare(a));
|
|
3906
|
-
for (const file of logFiles.slice(config32.maxFiles)) {
|
|
3907
|
-
await unlink22(join5(this.config.logDirectory, file));
|
|
3908
|
-
}
|
|
3909
|
-
}
|
|
3910
|
-
}
|
|
3911
|
-
}
|
|
3912
|
-
async compressLogFile(inputPath, outputPath) {
|
|
3913
|
-
const readStream = createReadStream22(inputPath);
|
|
3914
|
-
const writeStream = createWriteStream22(outputPath);
|
|
3915
|
-
const gzip = createGzip22();
|
|
3916
|
-
await pipeline22(readStream, gzip, writeStream);
|
|
3917
|
-
}
|
|
3918
|
-
async handleFingersCrossedBuffer(level, formattedEntry) {
|
|
3919
|
-
if (!this.fingersCrossedConfig)
|
|
3920
|
-
return;
|
|
3921
|
-
if (this.shouldActivateFingersCrossed(level) && !this.isActivated) {
|
|
3922
|
-
this.isActivated = true;
|
|
3923
|
-
for (const entry of this.logBuffer) {
|
|
3924
|
-
const formattedBufferedEntry = await this.formatter.format(entry);
|
|
3925
|
-
await this.writeToFile(formattedBufferedEntry);
|
|
3926
|
-
console.log(formattedBufferedEntry);
|
|
3927
|
-
}
|
|
3928
|
-
if (this.fingersCrossedConfig.stopBuffering)
|
|
3929
|
-
this.logBuffer = [];
|
|
3930
|
-
}
|
|
3931
|
-
if (this.isActivated) {
|
|
3932
|
-
await this.writeToFile(formattedEntry);
|
|
3933
|
-
console.log(formattedEntry);
|
|
3934
|
-
} else {
|
|
3935
|
-
if (this.logBuffer.length >= this.fingersCrossedConfig.bufferSize)
|
|
3936
|
-
this.logBuffer.shift();
|
|
3937
|
-
const entry = {
|
|
3938
|
-
timestamp: new Date,
|
|
3939
|
-
level,
|
|
3940
|
-
message: formattedEntry,
|
|
3941
|
-
name: this.name
|
|
3942
|
-
};
|
|
3943
|
-
this.logBuffer.push(entry);
|
|
3944
|
-
}
|
|
3945
|
-
}
|
|
3946
|
-
shouldActivateFingersCrossed(level) {
|
|
3947
|
-
if (!this.fingersCrossedConfig)
|
|
3948
|
-
return false;
|
|
3949
|
-
return this.getLevelValue(level) >= this.getLevelValue(this.fingersCrossedConfig.activationLevel);
|
|
3950
|
-
}
|
|
3951
|
-
getLevelValue(level) {
|
|
3952
|
-
const levels = {
|
|
3953
|
-
debug: 0,
|
|
3954
|
-
info: 1,
|
|
3955
|
-
success: 2,
|
|
3956
|
-
warning: 3,
|
|
3957
|
-
error: 4
|
|
3958
|
-
};
|
|
3959
|
-
return levels[level];
|
|
3960
|
-
}
|
|
3961
|
-
shouldLog(level) {
|
|
3962
|
-
if (!this.enabled)
|
|
3963
|
-
return false;
|
|
3964
|
-
const levels = {
|
|
3965
|
-
debug: 0,
|
|
3966
|
-
info: 1,
|
|
3967
|
-
success: 2,
|
|
3968
|
-
warning: 3,
|
|
3969
|
-
error: 4
|
|
3970
|
-
};
|
|
3971
|
-
return levels[level] >= levels[this.config.level];
|
|
3972
|
-
}
|
|
3973
|
-
async flushPendingWrites() {
|
|
3974
|
-
await Promise.all(this.pendingOperations.map((op) => {
|
|
3975
|
-
if (op instanceof Promise) {
|
|
3976
|
-
return op.catch((err) => {
|
|
3977
|
-
console.error("Error in pending write operation:", err);
|
|
3978
|
-
});
|
|
3979
|
-
}
|
|
3980
|
-
return Promise.resolve();
|
|
3981
|
-
}));
|
|
3982
|
-
if (existsSync42(this.currentLogFile)) {
|
|
3983
|
-
try {
|
|
3984
|
-
const fd = openSync22(this.currentLogFile, "r+");
|
|
3985
|
-
fsyncSync22(fd);
|
|
3986
|
-
closeSync22(fd);
|
|
3987
|
-
} catch (error) {
|
|
3988
|
-
console.error(`Error flushing file: ${error}`);
|
|
3989
|
-
}
|
|
3990
|
-
}
|
|
3991
|
-
}
|
|
3992
|
-
async destroy() {
|
|
3993
|
-
if (this.rotationTimeout)
|
|
3994
|
-
clearInterval(this.rotationTimeout);
|
|
3995
|
-
if (this.keyRotationTimeout)
|
|
3996
|
-
clearInterval(this.keyRotationTimeout);
|
|
3997
|
-
this.timers.clear();
|
|
3998
|
-
for (const op of this.pendingOperations) {
|
|
3999
|
-
if (typeof op.cancel === "function") {
|
|
4000
|
-
op.cancel();
|
|
4001
|
-
}
|
|
4002
|
-
}
|
|
4003
|
-
return (async () => {
|
|
4004
|
-
if (this.pendingOperations.length > 0) {
|
|
4005
|
-
try {
|
|
4006
|
-
await Promise.allSettled(this.pendingOperations);
|
|
4007
|
-
} catch (err) {
|
|
4008
|
-
console.error("Error waiting for pending operations:", err);
|
|
4009
|
-
}
|
|
4010
|
-
}
|
|
4011
|
-
if (!isBrowserProcess22() && this.config.rotation && typeof this.config.rotation !== "boolean" && this.config.rotation.compress) {
|
|
4012
|
-
try {
|
|
4013
|
-
const files = await readdir22(this.config.logDirectory);
|
|
4014
|
-
const tempFiles = files.filter((f) => (f.includes("temp") || f.includes(".tmp")) && f.includes(this.name));
|
|
4015
|
-
for (const tempFile of tempFiles) {
|
|
4016
|
-
try {
|
|
4017
|
-
await unlink22(join5(this.config.logDirectory, tempFile));
|
|
4018
|
-
} catch (err) {
|
|
4019
|
-
console.error(`Failed to delete temp file ${tempFile}:`, err);
|
|
4020
|
-
}
|
|
4021
|
-
}
|
|
4022
|
-
} catch (err) {
|
|
4023
|
-
console.error("Error cleaning up temporary files:", err);
|
|
4024
|
-
}
|
|
4025
|
-
}
|
|
4026
|
-
})();
|
|
4027
|
-
}
|
|
4028
|
-
getCurrentLogFilePath() {
|
|
4029
|
-
return this.currentLogFile;
|
|
4030
|
-
}
|
|
4031
|
-
formatTag(name) {
|
|
4032
|
-
if (!name)
|
|
4033
|
-
return "";
|
|
4034
|
-
return `${this.tagFormat.prefix}${name}${this.tagFormat.suffix}`;
|
|
4035
|
-
}
|
|
4036
|
-
formatFileTimestamp(date) {
|
|
4037
|
-
return `[${date.toISOString()}]`;
|
|
4038
|
-
}
|
|
4039
|
-
formatConsoleTimestamp(date) {
|
|
4040
|
-
return this.fancy ? styles22.gray(date.toLocaleTimeString()) : date.toLocaleTimeString();
|
|
4041
|
-
}
|
|
4042
|
-
formatConsoleMessage(parts) {
|
|
4043
|
-
const { timestamp, icon = "", tag = "", message, level, showTimestamp = true } = parts;
|
|
4044
|
-
const stripAnsi = (str) => str.replace(this.ANSI_PATTERN, "");
|
|
4045
|
-
if (!this.fancy) {
|
|
4046
|
-
const components = [];
|
|
4047
|
-
if (showTimestamp)
|
|
4048
|
-
components.push(timestamp);
|
|
4049
|
-
if (level === "warning")
|
|
4050
|
-
components.push("WARN");
|
|
4051
|
-
else if (level === "error")
|
|
4052
|
-
components.push("ERROR");
|
|
4053
|
-
else if (icon)
|
|
4054
|
-
components.push(icon.replace(/[^\p{L}\p{N}\p{P}\p{Z}]/gu, ""));
|
|
4055
|
-
if (tag)
|
|
4056
|
-
components.push(tag.replace(/[[\]]/g, ""));
|
|
4057
|
-
components.push(message);
|
|
4058
|
-
return components.join(" ");
|
|
4059
|
-
}
|
|
4060
|
-
const terminalWidth = process11.stdout.columns || 120;
|
|
4061
|
-
let mainPart = "";
|
|
4062
|
-
if (level === "warning" || level === "error") {
|
|
4063
|
-
mainPart = `${icon} ${message}`;
|
|
4064
|
-
} else if (level === "info" || level === "success") {
|
|
4065
|
-
mainPart = `${icon} ${tag} ${message}`;
|
|
4066
|
-
} else {
|
|
4067
|
-
mainPart = `${icon} ${tag} ${styles22.cyan(message)}`;
|
|
4068
|
-
}
|
|
4069
|
-
if (!showTimestamp) {
|
|
4070
|
-
return mainPart.trim();
|
|
4071
|
-
}
|
|
4072
|
-
const visibleMainPartLength = stripAnsi(mainPart).trim().length;
|
|
4073
|
-
const visibleTimestampLength = stripAnsi(timestamp).length;
|
|
4074
|
-
const padding = Math.max(1, terminalWidth - 2 - visibleMainPartLength - visibleTimestampLength);
|
|
4075
|
-
return `${mainPart.trim()}${" ".repeat(padding)}${timestamp}`;
|
|
4076
|
-
}
|
|
4077
|
-
formatMessage(message, args) {
|
|
4078
|
-
if (args.length === 1 && Array.isArray(args[0])) {
|
|
4079
|
-
return message.replace(/\{(\d+)\}/g, (match, index) => {
|
|
4080
|
-
const position = Number.parseInt(index, 10);
|
|
4081
|
-
return position < args[0].length ? String(args[0][position]) : match;
|
|
4082
|
-
});
|
|
4083
|
-
}
|
|
4084
|
-
const formatRegex = /%([sdijfo%])/g;
|
|
4085
|
-
let argIndex = 0;
|
|
4086
|
-
let formattedMessage = message.replace(formatRegex, (match, type) => {
|
|
4087
|
-
if (type === "%")
|
|
4088
|
-
return "%";
|
|
4089
|
-
if (argIndex >= args.length)
|
|
4090
|
-
return match;
|
|
4091
|
-
const arg = args[argIndex++];
|
|
4092
|
-
switch (type) {
|
|
4093
|
-
case "s":
|
|
4094
|
-
return String(arg);
|
|
4095
|
-
case "d":
|
|
4096
|
-
case "i":
|
|
4097
|
-
return Number(arg).toString();
|
|
4098
|
-
case "j":
|
|
4099
|
-
case "o":
|
|
4100
|
-
return JSON.stringify(arg, null, 2);
|
|
4101
|
-
default:
|
|
4102
|
-
return match;
|
|
4103
|
-
}
|
|
4104
|
-
});
|
|
4105
|
-
if (argIndex < args.length) {
|
|
4106
|
-
formattedMessage += ` ${args.slice(argIndex).map((arg) => typeof arg === "object" ? JSON.stringify(arg, null, 2) : String(arg)).join(" ")}`;
|
|
4107
|
-
}
|
|
4108
|
-
return formattedMessage;
|
|
4109
|
-
}
|
|
4110
|
-
async log(level, message, ...args) {
|
|
4111
|
-
const timestamp = new Date;
|
|
4112
|
-
const consoleTime = this.formatConsoleTimestamp(timestamp);
|
|
4113
|
-
const fileTime = this.formatFileTimestamp(timestamp);
|
|
4114
|
-
let formattedMessage;
|
|
4115
|
-
let errorStack;
|
|
4116
|
-
if (message instanceof Error) {
|
|
4117
|
-
formattedMessage = message.message;
|
|
4118
|
-
errorStack = message.stack;
|
|
4119
|
-
} else {
|
|
4120
|
-
formattedMessage = this.formatMessage(message, args);
|
|
4121
|
-
}
|
|
4122
|
-
if (this.fancy && !isBrowserProcess22()) {
|
|
4123
|
-
const icon = levelIcons22[level];
|
|
4124
|
-
const tag = this.options.showTags !== false && this.name ? styles22.gray(this.formatTag(this.name)) : "";
|
|
4125
|
-
let consoleMessage;
|
|
4126
|
-
switch (level) {
|
|
4127
|
-
case "debug":
|
|
4128
|
-
consoleMessage = this.formatConsoleMessage({
|
|
4129
|
-
timestamp: consoleTime,
|
|
4130
|
-
icon,
|
|
4131
|
-
tag,
|
|
4132
|
-
message: styles22.gray(formattedMessage),
|
|
4133
|
-
level
|
|
4134
|
-
});
|
|
4135
|
-
console.error(consoleMessage);
|
|
4136
|
-
break;
|
|
4137
|
-
case "info":
|
|
4138
|
-
consoleMessage = this.formatConsoleMessage({
|
|
4139
|
-
timestamp: consoleTime,
|
|
4140
|
-
icon,
|
|
4141
|
-
tag,
|
|
4142
|
-
message: formattedMessage,
|
|
4143
|
-
level
|
|
4144
|
-
});
|
|
4145
|
-
console.error(consoleMessage);
|
|
4146
|
-
break;
|
|
4147
|
-
case "success":
|
|
4148
|
-
consoleMessage = this.formatConsoleMessage({
|
|
4149
|
-
timestamp: consoleTime,
|
|
4150
|
-
icon,
|
|
4151
|
-
tag,
|
|
4152
|
-
message: styles22.green(formattedMessage),
|
|
4153
|
-
level
|
|
4154
|
-
});
|
|
4155
|
-
console.error(consoleMessage);
|
|
4156
|
-
break;
|
|
4157
|
-
case "warning":
|
|
4158
|
-
consoleMessage = this.formatConsoleMessage({
|
|
4159
|
-
timestamp: consoleTime,
|
|
4160
|
-
icon,
|
|
4161
|
-
tag,
|
|
4162
|
-
message: formattedMessage,
|
|
4163
|
-
level
|
|
4164
|
-
});
|
|
4165
|
-
console.warn(consoleMessage);
|
|
4166
|
-
break;
|
|
4167
|
-
case "error":
|
|
4168
|
-
consoleMessage = this.formatConsoleMessage({
|
|
4169
|
-
timestamp: consoleTime,
|
|
4170
|
-
icon,
|
|
4171
|
-
tag,
|
|
4172
|
-
message: formattedMessage,
|
|
4173
|
-
level
|
|
4174
|
-
});
|
|
4175
|
-
console.error(consoleMessage);
|
|
4176
|
-
if (errorStack) {
|
|
4177
|
-
const stackLines = errorStack.split(`
|
|
4178
|
-
`);
|
|
4179
|
-
for (const line of stackLines) {
|
|
4180
|
-
if (line.trim() && !line.includes(formattedMessage)) {
|
|
4181
|
-
console.error(this.formatConsoleMessage({
|
|
4182
|
-
timestamp: consoleTime,
|
|
4183
|
-
message: styles22.gray(` ${line}`),
|
|
4184
|
-
level,
|
|
4185
|
-
showTimestamp: false
|
|
4186
|
-
}));
|
|
4187
|
-
}
|
|
4188
|
-
}
|
|
4189
|
-
}
|
|
4190
|
-
break;
|
|
4191
|
-
}
|
|
4192
|
-
} else if (!isBrowserProcess22()) {
|
|
4193
|
-
console.error(`${fileTime} ${this.environment}.${level.toUpperCase()}: ${formattedMessage}`);
|
|
4194
|
-
if (errorStack) {
|
|
4195
|
-
console.error(errorStack);
|
|
4196
|
-
}
|
|
4197
|
-
}
|
|
4198
|
-
if (!this.shouldLog(level))
|
|
4199
|
-
return;
|
|
4200
|
-
let logEntry = `${fileTime} ${this.environment}.${level.toUpperCase()}: ${formattedMessage}
|
|
4201
|
-
`;
|
|
4202
|
-
if (errorStack) {
|
|
4203
|
-
logEntry += `${errorStack}
|
|
4204
|
-
`;
|
|
4205
|
-
}
|
|
4206
|
-
logEntry = logEntry.replace(this.ANSI_PATTERN, "");
|
|
4207
|
-
await this.writeToFile(logEntry);
|
|
4208
|
-
}
|
|
4209
|
-
time(label) {
|
|
4210
|
-
const start = performance.now();
|
|
4211
|
-
if (this.fancy && !isBrowserProcess22()) {
|
|
4212
|
-
const tag = this.options.showTags !== false && this.name ? styles22.gray(this.formatTag(this.name)) : "";
|
|
4213
|
-
const consoleTime = this.formatConsoleTimestamp(new Date);
|
|
4214
|
-
console.error(this.formatConsoleMessage({
|
|
4215
|
-
timestamp: consoleTime,
|
|
4216
|
-
icon: styles22.blue("◐"),
|
|
4217
|
-
tag,
|
|
4218
|
-
message: `${styles22.cyan(label)}...`
|
|
4219
|
-
}));
|
|
4220
|
-
}
|
|
4221
|
-
return async (metadata) => {
|
|
4222
|
-
if (!this.enabled)
|
|
4223
|
-
return;
|
|
4224
|
-
const end = performance.now();
|
|
4225
|
-
const elapsed = Math.round(end - start);
|
|
4226
|
-
const completionMessage = `${label} completed in ${elapsed}ms`;
|
|
4227
|
-
const timestamp = new Date;
|
|
4228
|
-
const consoleTime = this.formatConsoleTimestamp(timestamp);
|
|
4229
|
-
const fileTime = this.formatFileTimestamp(timestamp);
|
|
4230
|
-
let logEntry = `${fileTime} ${this.environment}.INFO: ${completionMessage}`;
|
|
4231
|
-
if (metadata) {
|
|
4232
|
-
logEntry += ` ${JSON.stringify(metadata)}`;
|
|
4233
|
-
}
|
|
4234
|
-
logEntry += `
|
|
4235
|
-
`;
|
|
4236
|
-
logEntry = logEntry.replace(this.ANSI_PATTERN, "");
|
|
4237
|
-
if (this.fancy && !isBrowserProcess22()) {
|
|
4238
|
-
const tag = this.options.showTags !== false && this.name ? styles22.gray(this.formatTag(this.name)) : "";
|
|
4239
|
-
console.error(this.formatConsoleMessage({
|
|
4240
|
-
timestamp: consoleTime,
|
|
4241
|
-
icon: styles22.green("✓"),
|
|
4242
|
-
tag,
|
|
4243
|
-
message: `${completionMessage}${metadata ? ` ${JSON.stringify(metadata)}` : ""}`
|
|
4244
|
-
}));
|
|
4245
|
-
} else if (!isBrowserProcess22()) {
|
|
4246
|
-
console.error(logEntry.trim());
|
|
4247
|
-
}
|
|
4248
|
-
await this.writeToFile(logEntry);
|
|
4249
|
-
};
|
|
4250
|
-
}
|
|
4251
|
-
async debug(message, ...args) {
|
|
4252
|
-
await this.log("debug", message, ...args);
|
|
4253
|
-
}
|
|
4254
|
-
async info(message, ...args) {
|
|
4255
|
-
await this.log("info", message, ...args);
|
|
4256
|
-
}
|
|
4257
|
-
async success(message, ...args) {
|
|
4258
|
-
await this.log("success", message, ...args);
|
|
4259
|
-
}
|
|
4260
|
-
async warn(message, ...args) {
|
|
4261
|
-
await this.log("warning", message, ...args);
|
|
4262
|
-
}
|
|
4263
|
-
async error(message, ...args) {
|
|
4264
|
-
await this.log("error", message, ...args);
|
|
4265
|
-
}
|
|
4266
|
-
validateEncryptionConfig() {
|
|
4267
|
-
if (!this.config.rotation)
|
|
4268
|
-
return false;
|
|
4269
|
-
if (typeof this.config.rotation === "boolean")
|
|
4270
|
-
return false;
|
|
4271
|
-
const rotation = this.config.rotation;
|
|
4272
|
-
const { encrypt } = rotation;
|
|
4273
|
-
return !!encrypt;
|
|
4274
|
-
}
|
|
4275
|
-
async only(fn) {
|
|
4276
|
-
if (!this.enabled)
|
|
4277
|
-
return;
|
|
4278
|
-
return await fn();
|
|
4279
|
-
}
|
|
4280
|
-
isEnabled() {
|
|
4281
|
-
return this.enabled;
|
|
4282
|
-
}
|
|
4283
|
-
setEnabled(enabled) {
|
|
4284
|
-
this.enabled = enabled;
|
|
4285
|
-
}
|
|
4286
|
-
extend(namespace) {
|
|
4287
|
-
const childName = `${this.name}:${namespace}`;
|
|
4288
|
-
const childLogger = new Logger22(childName, {
|
|
4289
|
-
...this.options,
|
|
4290
|
-
logDirectory: this.config.logDirectory,
|
|
4291
|
-
level: this.config.level,
|
|
4292
|
-
format: this.config.format,
|
|
4293
|
-
rotation: typeof this.config.rotation === "boolean" ? undefined : this.config.rotation,
|
|
4294
|
-
timestamp: typeof this.config.timestamp === "boolean" ? undefined : this.config.timestamp
|
|
4295
|
-
});
|
|
4296
|
-
this.subLoggers.add(childLogger);
|
|
4297
|
-
return childLogger;
|
|
4298
|
-
}
|
|
4299
|
-
createReadStream() {
|
|
4300
|
-
if (isBrowserProcess22())
|
|
4301
|
-
throw new Error("createReadStream is not supported in browser environments");
|
|
4302
|
-
if (!existsSync42(this.currentLogFile))
|
|
4303
|
-
throw new Error(`Log file does not exist: ${this.currentLogFile}`);
|
|
4304
|
-
return createReadStream22(this.currentLogFile, { encoding: "utf8" });
|
|
4305
|
-
}
|
|
4306
|
-
async decrypt(data) {
|
|
4307
|
-
if (!this.validateEncryptionConfig())
|
|
4308
|
-
throw new Error("Encryption is not configured");
|
|
4309
|
-
const encryptionConfig = this.config.rotation;
|
|
4310
|
-
if (!encryptionConfig.encrypt || typeof encryptionConfig.encrypt === "boolean")
|
|
4311
|
-
throw new Error("Invalid encryption configuration");
|
|
4312
|
-
if (!this.currentKeyId || !this.keys.has(this.currentKeyId))
|
|
4313
|
-
throw new Error("No valid encryption key available");
|
|
4314
|
-
const key = this.keys.get(this.currentKeyId);
|
|
4315
|
-
try {
|
|
4316
|
-
const encryptedData = Buffer22.isBuffer(data) ? data : Buffer22.from(data, "base64");
|
|
4317
|
-
const iv = encryptedData.slice(0, 16);
|
|
4318
|
-
const authTag = encryptedData.slice(-16);
|
|
4319
|
-
const ciphertext = encryptedData.slice(16, -16);
|
|
4320
|
-
const decipher = createDecipheriv22("aes-256-gcm", key, iv);
|
|
4321
|
-
decipher.setAuthTag(authTag);
|
|
4322
|
-
const decrypted = Buffer22.concat([
|
|
4323
|
-
decipher.update(ciphertext),
|
|
4324
|
-
decipher.final()
|
|
4325
|
-
]);
|
|
4326
|
-
return decrypted.toString("utf8");
|
|
4327
|
-
} catch (err) {
|
|
4328
|
-
throw new Error(`Decryption failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
4329
|
-
}
|
|
4330
|
-
}
|
|
4331
|
-
getLevel() {
|
|
4332
|
-
return this.config.level;
|
|
4333
|
-
}
|
|
4334
|
-
getLogDirectory() {
|
|
4335
|
-
return this.config.logDirectory;
|
|
4336
|
-
}
|
|
4337
|
-
getFormat() {
|
|
4338
|
-
return this.config.format;
|
|
4339
|
-
}
|
|
4340
|
-
getRotationConfig() {
|
|
4341
|
-
return this.config.rotation;
|
|
4342
|
-
}
|
|
4343
|
-
isBrowserMode() {
|
|
4344
|
-
return isBrowserProcess22();
|
|
4345
|
-
}
|
|
4346
|
-
isServerMode() {
|
|
4347
|
-
return !isBrowserProcess22();
|
|
4348
|
-
}
|
|
4349
|
-
setTestEncryptionKey(keyId, key) {
|
|
4350
|
-
this.currentKeyId = keyId;
|
|
4351
|
-
this.keys.set(keyId, key);
|
|
4352
|
-
}
|
|
4353
|
-
getTestCurrentKey() {
|
|
4354
|
-
if (!this.currentKeyId || !this.keys.has(this.currentKeyId)) {
|
|
4355
|
-
return null;
|
|
4356
|
-
}
|
|
4357
|
-
return {
|
|
4358
|
-
id: this.currentKeyId,
|
|
4359
|
-
key: this.keys.get(this.currentKeyId)
|
|
4360
|
-
};
|
|
4361
|
-
}
|
|
4362
|
-
getConfig() {
|
|
4363
|
-
return this.config;
|
|
4364
|
-
}
|
|
4365
|
-
async box(message) {
|
|
4366
|
-
if (!this.enabled)
|
|
4367
|
-
return;
|
|
4368
|
-
const timestamp = new Date;
|
|
4369
|
-
const consoleTime = this.formatConsoleTimestamp(timestamp);
|
|
4370
|
-
const fileTime = this.formatFileTimestamp(timestamp);
|
|
4371
|
-
if (this.fancy && !isBrowserProcess22()) {
|
|
4372
|
-
const lines = message.split(`
|
|
4373
|
-
`);
|
|
4374
|
-
const width = Math.max(...lines.map((line) => line.length)) + 2;
|
|
4375
|
-
const top = `┌${"─".repeat(width)}┐`;
|
|
4376
|
-
const bottom = `└${"─".repeat(width)}┘`;
|
|
4377
|
-
const boxedLines = lines.map((line) => {
|
|
4378
|
-
const padding = " ".repeat(width - line.length - 2);
|
|
4379
|
-
return `│ ${line}${padding} │`;
|
|
4380
|
-
});
|
|
4381
|
-
if (this.options.showTags !== false && this.name) {
|
|
4382
|
-
console.error(this.formatConsoleMessage({
|
|
4383
|
-
timestamp: consoleTime,
|
|
4384
|
-
message: styles22.gray(this.formatTag(this.name)),
|
|
4385
|
-
showTimestamp: false
|
|
4386
|
-
}));
|
|
4387
|
-
}
|
|
4388
|
-
console.error(this.formatConsoleMessage({
|
|
4389
|
-
timestamp: consoleTime,
|
|
4390
|
-
message: styles22.cyan(top)
|
|
4391
|
-
}));
|
|
4392
|
-
boxedLines.forEach((line) => console.error(this.formatConsoleMessage({
|
|
4393
|
-
timestamp: consoleTime,
|
|
4394
|
-
message: styles22.cyan(line),
|
|
4395
|
-
showTimestamp: false
|
|
4396
|
-
})));
|
|
4397
|
-
console.error(this.formatConsoleMessage({
|
|
4398
|
-
timestamp: consoleTime,
|
|
4399
|
-
message: styles22.cyan(bottom),
|
|
4400
|
-
showTimestamp: false
|
|
4401
|
-
}));
|
|
4402
|
-
} else if (!isBrowserProcess22()) {
|
|
4403
|
-
console.error(`${fileTime} ${this.environment}.INFO: [BOX] ${message}`);
|
|
4404
|
-
}
|
|
4405
|
-
const logEntry = `${fileTime} ${this.environment}.INFO: [BOX] ${message}
|
|
4406
|
-
`.replace(this.ANSI_PATTERN, "");
|
|
4407
|
-
await this.writeToFile(logEntry);
|
|
4408
|
-
}
|
|
4409
|
-
async prompt(message) {
|
|
4410
|
-
if (isBrowserProcess22()) {
|
|
4411
|
-
return Promise.resolve(true);
|
|
4412
|
-
}
|
|
4413
|
-
return new Promise((resolve52) => {
|
|
4414
|
-
console.error(`${styles22.cyan("?")} ${message} (y/n) `);
|
|
4415
|
-
const onData = (data) => {
|
|
4416
|
-
const input = data.toString().trim().toLowerCase();
|
|
4417
|
-
process11.stdin.removeListener("data", onData);
|
|
4418
|
-
try {
|
|
4419
|
-
if (typeof process11.stdin.setRawMode === "function") {
|
|
4420
|
-
process11.stdin.setRawMode(false);
|
|
4421
|
-
}
|
|
4422
|
-
} catch {}
|
|
4423
|
-
process11.stdin.pause();
|
|
4424
|
-
console.error("");
|
|
4425
|
-
resolve52(input === "y" || input === "yes");
|
|
4426
|
-
};
|
|
4427
|
-
try {
|
|
4428
|
-
if (typeof process11.stdin.setRawMode === "function") {
|
|
4429
|
-
process11.stdin.setRawMode(true);
|
|
4430
|
-
}
|
|
4431
|
-
} catch {}
|
|
4432
|
-
process11.stdin.resume();
|
|
4433
|
-
process11.stdin.once("data", onData);
|
|
4434
|
-
});
|
|
4435
|
-
}
|
|
4436
|
-
setFancy(enabled) {
|
|
4437
|
-
this.fancy = enabled;
|
|
4438
|
-
}
|
|
4439
|
-
isFancy() {
|
|
4440
|
-
return this.fancy;
|
|
4441
|
-
}
|
|
4442
|
-
pause() {
|
|
4443
|
-
this.enabled = false;
|
|
4444
|
-
}
|
|
4445
|
-
resume() {
|
|
4446
|
-
this.enabled = true;
|
|
4447
|
-
}
|
|
4448
|
-
async start(message, ...args) {
|
|
4449
|
-
if (!this.enabled)
|
|
4450
|
-
return;
|
|
4451
|
-
let formattedMessage = message;
|
|
4452
|
-
if (args && args.length > 0) {
|
|
4453
|
-
const formatRegex = /%([sdijfo%])/g;
|
|
4454
|
-
let argIndex = 0;
|
|
4455
|
-
formattedMessage = message.replace(formatRegex, (match, type) => {
|
|
4456
|
-
if (type === "%")
|
|
4457
|
-
return "%";
|
|
4458
|
-
if (argIndex >= args.length)
|
|
4459
|
-
return match;
|
|
4460
|
-
const arg = args[argIndex++];
|
|
4461
|
-
switch (type) {
|
|
4462
|
-
case "s":
|
|
4463
|
-
return String(arg);
|
|
4464
|
-
case "d":
|
|
4465
|
-
case "i":
|
|
4466
|
-
return Number(arg).toString();
|
|
4467
|
-
case "j":
|
|
4468
|
-
case "o":
|
|
4469
|
-
return JSON.stringify(arg, null, 2);
|
|
4470
|
-
default:
|
|
4471
|
-
return match;
|
|
4472
|
-
}
|
|
4473
|
-
});
|
|
4474
|
-
if (argIndex < args.length) {
|
|
4475
|
-
formattedMessage += ` ${args.slice(argIndex).map((arg) => typeof arg === "object" ? JSON.stringify(arg, null, 2) : String(arg)).join(" ")}`;
|
|
4476
|
-
}
|
|
4477
|
-
}
|
|
4478
|
-
if (this.fancy && !isBrowserProcess22()) {
|
|
4479
|
-
const tag = this.options.showTags !== false && this.name ? styles22.gray(this.formatTag(this.name)) : "";
|
|
4480
|
-
const spinnerChar = styles22.blue("◐");
|
|
4481
|
-
console.error(`${spinnerChar} ${tag} ${styles22.cyan(formattedMessage)}`);
|
|
4482
|
-
}
|
|
4483
|
-
const timestamp = new Date;
|
|
4484
|
-
const formattedDate = timestamp.toISOString();
|
|
4485
|
-
const logEntry = `[${formattedDate}] ${this.environment}.INFO: [START] ${formattedMessage}
|
|
4486
|
-
`.replace(this.ANSI_PATTERN, "");
|
|
4487
|
-
await this.writeToFile(logEntry);
|
|
4488
|
-
}
|
|
4489
|
-
progress(total, initialMessage = "") {
|
|
4490
|
-
if (!this.enabled || !this.fancy || isBrowserProcess22() || total <= 0) {
|
|
4491
|
-
return {
|
|
4492
|
-
update: () => {},
|
|
4493
|
-
finish: () => {},
|
|
4494
|
-
interrupt: () => {}
|
|
4495
|
-
};
|
|
4496
|
-
}
|
|
4497
|
-
if (this.activeProgressBar) {
|
|
4498
|
-
console.warn("Warning: Another progress bar is already active. Finishing the previous one.");
|
|
4499
|
-
this.finishProgressBar(this.activeProgressBar, "[Auto-finished]");
|
|
4500
|
-
}
|
|
4501
|
-
const barLength = 20;
|
|
4502
|
-
this.activeProgressBar = {
|
|
4503
|
-
total,
|
|
4504
|
-
current: 0,
|
|
4505
|
-
message: initialMessage,
|
|
4506
|
-
barLength,
|
|
4507
|
-
lastRenderedLine: ""
|
|
4508
|
-
};
|
|
4509
|
-
this.renderProgressBar(this.activeProgressBar);
|
|
4510
|
-
const update = (current, message) => {
|
|
4511
|
-
if (!this.activeProgressBar || !this.enabled || !this.fancy || isBrowserProcess22())
|
|
4512
|
-
return;
|
|
4513
|
-
this.activeProgressBar.current = Math.max(0, Math.min(total, current));
|
|
4514
|
-
if (message !== undefined) {
|
|
4515
|
-
this.activeProgressBar.message = message;
|
|
4516
|
-
}
|
|
4517
|
-
const isFinished = this.activeProgressBar.current === this.activeProgressBar.total;
|
|
4518
|
-
this.renderProgressBar(this.activeProgressBar, isFinished);
|
|
4519
|
-
};
|
|
4520
|
-
const finish = (message) => {
|
|
4521
|
-
if (!this.activeProgressBar || !this.enabled || !this.fancy || isBrowserProcess22())
|
|
4522
|
-
return;
|
|
4523
|
-
this.activeProgressBar.current = this.activeProgressBar.total;
|
|
4524
|
-
if (message !== undefined) {
|
|
4525
|
-
this.activeProgressBar.message = message;
|
|
4526
|
-
}
|
|
4527
|
-
this.renderProgressBar(this.activeProgressBar, true);
|
|
4528
|
-
this.finishProgressBar(this.activeProgressBar);
|
|
4529
|
-
};
|
|
4530
|
-
const interrupt = (interruptMessage, level = "info") => {
|
|
4531
|
-
if (!this.activeProgressBar || !this.enabled || !this.fancy || isBrowserProcess22())
|
|
4532
|
-
return;
|
|
4533
|
-
process11.stdout.write(`${"\r".padEnd(process11.stdout.columns || 80)}\r`);
|
|
4534
|
-
this.log(level, interruptMessage);
|
|
4535
|
-
setTimeout(() => {
|
|
4536
|
-
if (this.activeProgressBar) {
|
|
4537
|
-
this.renderProgressBar(this.activeProgressBar);
|
|
4538
|
-
}
|
|
4539
|
-
}, 50);
|
|
4540
|
-
};
|
|
4541
|
-
return { update, finish, interrupt };
|
|
4542
|
-
}
|
|
4543
|
-
renderProgressBar(barState, isFinished = false) {
|
|
4544
|
-
if (!this.enabled || !this.fancy || isBrowserProcess22() || !process11.stdout.isTTY)
|
|
4545
|
-
return;
|
|
4546
|
-
const percent = Math.min(100, Math.max(0, Math.round(barState.current / barState.total * 100)));
|
|
4547
|
-
const filledLength = Math.round(barState.barLength * percent / 100);
|
|
4548
|
-
const emptyLength = barState.barLength - filledLength;
|
|
4549
|
-
const filledBar = styles22.green("━".repeat(filledLength));
|
|
4550
|
-
const emptyBar = styles22.gray("━".repeat(emptyLength));
|
|
4551
|
-
const bar = `[${filledBar}${emptyBar}]`;
|
|
4552
|
-
const percentageText = `${percent}%`.padStart(4);
|
|
4553
|
-
const messageText = barState.message ? ` ${barState.message}` : "";
|
|
4554
|
-
const icon = isFinished || percent === 100 ? styles22.green("✓") : styles22.blue("▶");
|
|
4555
|
-
const tag = this.options.showTags !== false && this.name ? ` ${styles22.gray(this.formatTag(this.name))}` : "";
|
|
4556
|
-
const line = `\r${icon}${tag} ${bar} ${percentageText}${messageText}`;
|
|
4557
|
-
const terminalWidth = process11.stdout.columns || 80;
|
|
4558
|
-
const clearLine = " ".repeat(Math.max(0, terminalWidth - line.replace(this.ANSI_PATTERN, "").length));
|
|
4559
|
-
barState.lastRenderedLine = `${line}${clearLine}`;
|
|
4560
|
-
process11.stdout.write(barState.lastRenderedLine);
|
|
4561
|
-
if (isFinished) {
|
|
4562
|
-
process11.stdout.write(`
|
|
4563
|
-
`);
|
|
4564
|
-
}
|
|
4565
|
-
}
|
|
4566
|
-
finishProgressBar(barState, finalMessage) {
|
|
4567
|
-
if (!this.enabled || !this.fancy || isBrowserProcess22() || !process11.stdout.isTTY) {
|
|
4568
|
-
this.activeProgressBar = null;
|
|
4569
|
-
return;
|
|
4570
|
-
}
|
|
4571
|
-
if (barState.current < barState.total) {
|
|
4572
|
-
barState.current = barState.total;
|
|
4573
|
-
}
|
|
4574
|
-
if (finalMessage)
|
|
4575
|
-
barState.message = finalMessage;
|
|
4576
|
-
this.renderProgressBar(barState, true);
|
|
4577
|
-
this.activeProgressBar = null;
|
|
4578
|
-
}
|
|
4579
|
-
async clear(filters = {}) {
|
|
4580
|
-
if (isBrowserProcess22()) {
|
|
4581
|
-
console.warn("Log clearing is not supported in browser environments.");
|
|
4582
|
-
return;
|
|
4583
|
-
}
|
|
4584
|
-
try {
|
|
4585
|
-
console.warn("Clearing logs...", this.config.logDirectory);
|
|
4586
|
-
const files = await readdir22(this.config.logDirectory);
|
|
4587
|
-
const logFilesToDelete = [];
|
|
4588
|
-
for (const file of files) {
|
|
4589
|
-
const nameMatches = filters.name ? new RegExp(filters.name.replace("*", ".*")).test(file) : file.startsWith(this.name);
|
|
4590
|
-
if (!nameMatches || !file.endsWith(".log")) {
|
|
4591
|
-
continue;
|
|
4592
|
-
}
|
|
4593
|
-
const filePath = join5(this.config.logDirectory, file);
|
|
4594
|
-
if (filters.before) {
|
|
4595
|
-
try {
|
|
4596
|
-
const fileStats = await stat22(filePath);
|
|
4597
|
-
if (fileStats.mtime >= filters.before) {
|
|
4598
|
-
continue;
|
|
4599
|
-
}
|
|
4600
|
-
} catch (statErr) {
|
|
4601
|
-
console.error(`Failed to get stats for file ${filePath}:`, statErr);
|
|
4602
|
-
continue;
|
|
4603
|
-
}
|
|
4604
|
-
}
|
|
4605
|
-
logFilesToDelete.push(filePath);
|
|
4606
|
-
}
|
|
4607
|
-
if (logFilesToDelete.length === 0) {
|
|
4608
|
-
console.warn("No log files matched the criteria for clearing.");
|
|
4609
|
-
return;
|
|
4610
|
-
}
|
|
4611
|
-
console.warn(`Preparing to delete ${logFilesToDelete.length} log file(s)...`);
|
|
4612
|
-
for (const filePath of logFilesToDelete) {
|
|
4613
|
-
try {
|
|
4614
|
-
await unlink22(filePath);
|
|
4615
|
-
console.warn(`Deleted log file: ${filePath}`);
|
|
4616
|
-
} catch (unlinkErr) {
|
|
4617
|
-
console.error(`Failed to delete log file ${filePath}:`, unlinkErr);
|
|
4618
|
-
}
|
|
4619
|
-
}
|
|
4620
|
-
console.warn("Log clearing process finished.");
|
|
4621
|
-
} catch (err) {
|
|
4622
|
-
console.error("Error during log clearing process:", err);
|
|
4623
|
-
}
|
|
4624
|
-
}
|
|
4625
|
-
}
|
|
4626
|
-
var logger22 = new Logger22("stacks");
|
|
4627
|
-
|
|
4628
|
-
// src/git-hooks.ts
|
|
4629
|
-
var execAsync = promisify(exec);
|
|
4630
|
-
var log3 = new Logger22("git-hooks", {
|
|
4631
|
-
showTags: true
|
|
4632
|
-
});
|
|
4633
|
-
var VALID_GIT_HOOKS = [
|
|
4634
|
-
"applypatch-msg",
|
|
4635
|
-
"pre-applypatch",
|
|
4636
|
-
"post-applypatch",
|
|
4637
|
-
"pre-commit",
|
|
4638
|
-
"pre-merge-commit",
|
|
4639
|
-
"prepare-commit-msg",
|
|
4640
|
-
"commit-msg",
|
|
4641
|
-
"post-commit",
|
|
4642
|
-
"pre-rebase",
|
|
4643
|
-
"post-checkout",
|
|
4644
|
-
"post-merge",
|
|
4645
|
-
"pre-push",
|
|
4646
|
-
"pre-receive",
|
|
4647
|
-
"update",
|
|
4648
|
-
"proc-receive",
|
|
4649
|
-
"post-receive",
|
|
4650
|
-
"post-update",
|
|
4651
|
-
"reference-transaction",
|
|
4652
|
-
"push-to-checkout",
|
|
4653
|
-
"pre-auto-gc",
|
|
4654
|
-
"post-rewrite",
|
|
4655
|
-
"sendemail-validate",
|
|
4656
|
-
"fsmonitor-watchman",
|
|
4657
|
-
"p4-changelist",
|
|
4658
|
-
"p4-prepare-changelist",
|
|
4659
|
-
"p4-post-changelist",
|
|
4660
|
-
"p4-pre-submit",
|
|
4661
|
-
"post-index-change"
|
|
4662
|
-
];
|
|
4663
|
-
var VALID_OPTIONS = ["preserveUnused", "verbose", "staged-lint"];
|
|
4664
|
-
var PREPEND_SCRIPT = `#!/bin/sh
|
|
4665
|
-
|
|
4666
|
-
if [ "$SKIP_BUN_GIT_HOOKS" = "1" ]; then
|
|
4667
|
-
echo "[INFO] SKIP_BUN_GIT_HOOKS is set to 1, skipping hook."
|
|
4668
|
-
exit 0
|
|
4669
|
-
fi
|
|
4670
|
-
|
|
4671
|
-
if [ -f "$BUN_GIT_HOOKS_RC" ]; then
|
|
4672
|
-
. "$BUN_GIT_HOOKS_RC"
|
|
4673
|
-
fi
|
|
4674
|
-
|
|
4675
|
-
`;
|
|
4676
|
-
function getGitProjectRoot(directory = process12.cwd()) {
|
|
4677
|
-
if (directory.endsWith(".git")) {
|
|
4678
|
-
return path.normalize(directory);
|
|
4679
|
-
}
|
|
4680
|
-
let start = path.normalize(directory);
|
|
4681
|
-
if (!start || start === path.sep || start === ".") {
|
|
4682
|
-
return;
|
|
4683
|
-
}
|
|
4684
|
-
const fullPath = path.join(start, ".git");
|
|
4685
|
-
if (fs.existsSync(fullPath)) {
|
|
4686
|
-
if (!fs.lstatSync(fullPath).isDirectory()) {
|
|
4687
|
-
const content = fs.readFileSync(fullPath, { encoding: "utf-8" });
|
|
4688
|
-
const match = /^gitdir: (.*)\s*$/.exec(content);
|
|
4689
|
-
if (match) {
|
|
4690
|
-
const gitDir = match[1];
|
|
4691
|
-
let commonDir = path.join(gitDir, "commondir");
|
|
4692
|
-
if (fs.existsSync(commonDir)) {
|
|
4693
|
-
commonDir = fs.readFileSync(commonDir, "utf8").trim();
|
|
4694
|
-
return path.resolve(gitDir, commonDir);
|
|
4695
|
-
}
|
|
4696
|
-
return path.normalize(gitDir);
|
|
4697
|
-
}
|
|
4698
|
-
}
|
|
4699
|
-
return path.normalize(fullPath);
|
|
4700
|
-
}
|
|
4701
|
-
const parentDir = path.dirname(start);
|
|
4702
|
-
if (parentDir === start) {
|
|
4703
|
-
return;
|
|
4704
|
-
}
|
|
4705
|
-
return getGitProjectRoot(parentDir);
|
|
4706
|
-
}
|
|
4707
|
-
function getProjectRootDirectoryFromNodeModules(projectPath) {
|
|
4708
|
-
function _arraysAreEqual(a1, a2) {
|
|
4709
|
-
return JSON.stringify(a1) === JSON.stringify(a2);
|
|
4710
|
-
}
|
|
4711
|
-
const projDir = projectPath.split(/[\\/]/);
|
|
4712
|
-
const indexOfStoreDir = projDir.indexOf(".store");
|
|
4713
|
-
if (indexOfStoreDir > -1) {
|
|
4714
|
-
return projDir.slice(0, indexOfStoreDir - 1).join("/");
|
|
4715
|
-
}
|
|
4716
|
-
if (projDir.length > 3 && _arraysAreEqual(projDir.slice(-3), ["node_modules", ".bin", "bun-git-hooks"])) {
|
|
4717
|
-
return projDir.slice(0, -3).join("/");
|
|
4718
|
-
}
|
|
4719
|
-
if (projDir.length > 2 && _arraysAreEqual(projDir.slice(-2), ["node_modules", "bun-git-hooks"])) {
|
|
4720
|
-
return projDir.slice(0, -2).join("/");
|
|
4721
|
-
}
|
|
4722
|
-
return;
|
|
4723
|
-
}
|
|
4724
|
-
function checkBunGitHooksInDependencies(projectRootPath) {
|
|
4725
|
-
if (typeof projectRootPath !== "string") {
|
|
4726
|
-
throw new TypeError("Package json path is not a string!");
|
|
4727
|
-
}
|
|
4728
|
-
const { packageJsonContent } = _getPackageJson(projectRootPath);
|
|
4729
|
-
if ("dependencies" in packageJsonContent && "bun-git-hooks" in packageJsonContent.dependencies) {
|
|
4730
|
-
console.warn("[WARN] You should move `bun-git-hooks` to your devDependencies!");
|
|
4731
|
-
return true;
|
|
4732
|
-
}
|
|
4733
|
-
if (!("devDependencies" in packageJsonContent)) {
|
|
4734
|
-
return false;
|
|
4735
|
-
}
|
|
4736
|
-
return "bun-git-hooks" in packageJsonContent.devDependencies;
|
|
4737
|
-
}
|
|
4738
|
-
function _getPackageJson(projectPath = process12.cwd()) {
|
|
3358
|
+
function _getPackageJson(projectPath = process11.cwd()) {
|
|
4739
3359
|
if (typeof projectPath !== "string") {
|
|
4740
3360
|
throw new TypeError("projectPath is not a string");
|
|
4741
3361
|
}
|
|
@@ -4746,7 +3366,7 @@ function _getPackageJson(projectPath = process12.cwd()) {
|
|
|
4746
3366
|
const packageJsonDataRaw = fs.readFileSync(targetPackageJson, { encoding: "utf-8" });
|
|
4747
3367
|
return { packageJsonContent: JSON.parse(packageJsonDataRaw), packageJsonPath: targetPackageJson };
|
|
4748
3368
|
}
|
|
4749
|
-
function setHooksFromConfig(projectRootPath =
|
|
3369
|
+
function setHooksFromConfig(projectRootPath = process11.cwd(), options) {
|
|
4750
3370
|
if (!config3 || Object.keys(config3).length === 0)
|
|
4751
3371
|
throw new Error("[ERROR] Config was not found! Please add `.git-hooks.config.{ts,js,mjs,cjs,json}` or `git-hooks.config.{ts,js,mjs,cjs,json}` or the `git-hooks` entry in package.json.\r\nCheck README for details");
|
|
4752
3372
|
const configFile = options?.configFile || { ...config3 };
|
|
@@ -4756,8 +3376,8 @@ function setHooksFromConfig(projectRootPath = process12.cwd(), options) {
|
|
|
4756
3376
|
if (!isValidConfig)
|
|
4757
3377
|
throw new Error("[ERROR] Config was not in correct format. Please check git hooks or options name");
|
|
4758
3378
|
const preserveUnused = Array.isArray(configFile.preserveUnused) ? configFile.preserveUnused : configFile.preserveUnused ? VALID_GIT_HOOKS : [];
|
|
4759
|
-
const logKeys = Object.keys(configFile).filter((key) => !VALID_OPTIONS.includes(key)).sort().map((key) =>
|
|
4760
|
-
|
|
3379
|
+
const logKeys = Object.keys(configFile).filter((key) => !VALID_OPTIONS.includes(key)).sort().map((key) => italic2(key)).join(", ");
|
|
3380
|
+
log2.debug(`Hook Keys: ${logKeys}`);
|
|
4761
3381
|
for (const hook of VALID_GIT_HOOKS) {
|
|
4762
3382
|
if (Object.prototype.hasOwnProperty.call(configFile, hook)) {
|
|
4763
3383
|
if (!configFile[hook])
|
|
@@ -4768,48 +3388,85 @@ function setHooksFromConfig(projectRootPath = process12.cwd(), options) {
|
|
|
4768
3388
|
}
|
|
4769
3389
|
}
|
|
4770
3390
|
}
|
|
4771
|
-
async function getStagedFiles(projectRoot =
|
|
3391
|
+
async function getStagedFiles(projectRoot = process11.cwd()) {
|
|
4772
3392
|
try {
|
|
4773
|
-
const { stdout } = await execAsync("git diff --
|
|
4774
|
-
|
|
3393
|
+
const { stdout } = await execAsync("git diff --cached --name-only --diff-filter=ACMR", { cwd: projectRoot });
|
|
3394
|
+
const files = stdout.trim().split(`
|
|
4775
3395
|
`).filter(Boolean);
|
|
3396
|
+
if (config3.verbose && files.length > 0) {
|
|
3397
|
+
console.info("[INFO] Staged files found:", files);
|
|
3398
|
+
}
|
|
3399
|
+
return files;
|
|
4776
3400
|
} catch (error) {
|
|
4777
3401
|
console.error("[ERROR] Failed to get staged files:", error);
|
|
4778
3402
|
return [];
|
|
4779
3403
|
}
|
|
4780
3404
|
}
|
|
3405
|
+
function expandBracePattern(pattern) {
|
|
3406
|
+
const braceMatch = pattern.match(/{([^}]+)}/g);
|
|
3407
|
+
if (!braceMatch)
|
|
3408
|
+
return [pattern];
|
|
3409
|
+
const results = [pattern];
|
|
3410
|
+
braceMatch.forEach((brace) => {
|
|
3411
|
+
const options = brace.slice(1, -1).split(",");
|
|
3412
|
+
const newResults = [];
|
|
3413
|
+
results.forEach((result) => {
|
|
3414
|
+
options.forEach((option) => {
|
|
3415
|
+
newResults.push(result.replace(brace, option.trim()));
|
|
3416
|
+
});
|
|
3417
|
+
});
|
|
3418
|
+
results.length = 0;
|
|
3419
|
+
results.push(...newResults);
|
|
3420
|
+
});
|
|
3421
|
+
return results;
|
|
3422
|
+
}
|
|
4781
3423
|
function matchesGlob(file, pattern) {
|
|
4782
|
-
if (pattern.
|
|
4783
|
-
|
|
4784
|
-
const regex = new RegExp(`^${regexPattern}$`);
|
|
4785
|
-
return regex.test(file);
|
|
3424
|
+
if (pattern.startsWith("!")) {
|
|
3425
|
+
return !matchesGlob(file, pattern.slice(1));
|
|
4786
3426
|
}
|
|
4787
|
-
|
|
3427
|
+
const regexPattern = pattern.replace(/[.+^${}()|[\]\\]/g, "\\$&").replace(/\*\*/g, "(?:.*?)").replace(/\*/g, "[^/]*").replace(/\?/g, "[^/]");
|
|
3428
|
+
const regex = new RegExp(`^${regexPattern}$`);
|
|
3429
|
+
return regex.test(file);
|
|
4788
3430
|
}
|
|
4789
3431
|
function filterFilesByPattern(files, pattern) {
|
|
4790
|
-
|
|
3432
|
+
const expandedPatterns = expandBracePattern(pattern);
|
|
3433
|
+
const includePatterns = expandedPatterns.filter((p) => !p.startsWith("!"));
|
|
3434
|
+
const excludePatterns = expandedPatterns.filter((p) => p.startsWith("!"));
|
|
3435
|
+
return files.filter((file) => {
|
|
3436
|
+
const isIncluded = includePatterns.some((p) => matchesGlob(file, p));
|
|
3437
|
+
const isExcluded = excludePatterns.some((p) => matchesGlob(file, p.slice(1)));
|
|
3438
|
+
return isIncluded && !isExcluded;
|
|
3439
|
+
});
|
|
4791
3440
|
}
|
|
4792
|
-
async function runCommandOnStagedFiles(command, files, projectRoot =
|
|
3441
|
+
async function runCommandOnStagedFiles(command, files, projectRoot = process11.cwd(), verbose = false) {
|
|
4793
3442
|
if (files.length === 0) {
|
|
4794
3443
|
if (verbose)
|
|
4795
3444
|
console.info("[INFO] No matching files for pattern");
|
|
4796
3445
|
return true;
|
|
4797
3446
|
}
|
|
4798
3447
|
const commands = Array.isArray(command) ? command : [command];
|
|
3448
|
+
const fileList = files.join(" ");
|
|
4799
3449
|
for (const cmd of commands) {
|
|
4800
3450
|
try {
|
|
4801
|
-
const fullCommand = `${cmd} ${
|
|
4802
|
-
if (verbose)
|
|
4803
|
-
console.info(`[INFO] Running: ${fullCommand}`);
|
|
4804
|
-
const { stdout, stderr } = await execAsync(fullCommand, { cwd: projectRoot });
|
|
3451
|
+
const fullCommand = `${cmd} ${fileList}`;
|
|
4805
3452
|
if (verbose) {
|
|
4806
|
-
|
|
4807
|
-
|
|
4808
|
-
|
|
4809
|
-
|
|
3453
|
+
console.info("[INFO] Running command:", cmd);
|
|
3454
|
+
console.info("[INFO] On files:", files);
|
|
3455
|
+
}
|
|
3456
|
+
const { stdout, stderr } = await execAsync(fullCommand, { cwd: projectRoot });
|
|
3457
|
+
if (stdout && (verbose || stdout.includes("error") || stdout.includes("warning"))) {
|
|
3458
|
+
console.info(stdout);
|
|
3459
|
+
}
|
|
3460
|
+
if (stderr) {
|
|
3461
|
+
console.error("[ERROR] Command output:", stderr);
|
|
3462
|
+
return false;
|
|
4810
3463
|
}
|
|
4811
3464
|
} catch (error) {
|
|
4812
|
-
|
|
3465
|
+
if (error.stdout)
|
|
3466
|
+
console.info(error.stdout);
|
|
3467
|
+
if (error.stderr)
|
|
3468
|
+
console.error("[ERROR] Command stderr:", error.stderr);
|
|
3469
|
+
console.error(`[ERROR] Command failed: ${cmd}`);
|
|
4813
3470
|
return false;
|
|
4814
3471
|
}
|
|
4815
3472
|
}
|
|
@@ -4833,7 +3490,7 @@ async function processStagedLint(stagedLintConfig, projectRoot, verbose = false)
|
|
|
4833
3490
|
}
|
|
4834
3491
|
return success;
|
|
4835
3492
|
}
|
|
4836
|
-
function _setHook(hook, commandOrConfig, projectRoot =
|
|
3493
|
+
function _setHook(hook, commandOrConfig, projectRoot = process11.cwd()) {
|
|
4837
3494
|
const gitRoot = getGitProjectRoot(projectRoot);
|
|
4838
3495
|
if (!gitRoot) {
|
|
4839
3496
|
console.info("[INFO] No `.git` root folder found, skipping");
|
|
@@ -4843,7 +3500,7 @@ function _setHook(hook, commandOrConfig, projectRoot = process12.cwd()) {
|
|
|
4843
3500
|
if (typeof commandOrConfig === "string") {
|
|
4844
3501
|
hookCommand = PREPEND_SCRIPT + commandOrConfig;
|
|
4845
3502
|
} else if (commandOrConfig.stagedLint || commandOrConfig["staged-lint"]) {
|
|
4846
|
-
hookCommand = PREPEND_SCRIPT + `git-hooks run-staged-lint ${hook}`;
|
|
3503
|
+
hookCommand = PREPEND_SCRIPT + `bun git-hooks run-staged-lint ${hook}`;
|
|
4847
3504
|
} else {
|
|
4848
3505
|
console.error(`[ERROR] Invalid command or config for hook ${hook}`);
|
|
4849
3506
|
return;
|
|
@@ -4854,25 +3511,25 @@ function _setHook(hook, commandOrConfig, projectRoot = process12.cwd()) {
|
|
|
4854
3511
|
fs.mkdirSync(hookDirectory, { recursive: true });
|
|
4855
3512
|
}
|
|
4856
3513
|
const addOrModify = fs.existsSync(hookPath) ? "Modify" : "Add";
|
|
4857
|
-
|
|
3514
|
+
log2.debug(`${addOrModify} ${italic2(hook)} hook`);
|
|
4858
3515
|
fs.writeFileSync(hookPath, hookCommand, { mode: 493 });
|
|
4859
3516
|
}
|
|
4860
|
-
function removeHooks(projectRoot =
|
|
3517
|
+
function removeHooks(projectRoot = process11.cwd(), verbose = false) {
|
|
4861
3518
|
for (const configEntry of VALID_GIT_HOOKS)
|
|
4862
3519
|
_removeHook(configEntry, projectRoot, verbose);
|
|
4863
3520
|
}
|
|
4864
|
-
function _removeHook(hook, projectRoot =
|
|
3521
|
+
function _removeHook(hook, projectRoot = process11.cwd(), verbose = false) {
|
|
4865
3522
|
const gitRoot = getGitProjectRoot(projectRoot);
|
|
4866
3523
|
const hookPath = path.normalize(`${gitRoot}/hooks/${hook}`);
|
|
4867
3524
|
if (fs.existsSync(hookPath)) {
|
|
4868
|
-
|
|
3525
|
+
log2.debug(`Hook ${hook} is not set, removing!`);
|
|
4869
3526
|
fs.unlinkSync(hookPath);
|
|
4870
3527
|
}
|
|
4871
3528
|
if (verbose)
|
|
4872
|
-
|
|
3529
|
+
log2.success(`Successfully removed the ${hook} hook`);
|
|
4873
3530
|
}
|
|
4874
3531
|
async function runStagedLint(hook) {
|
|
4875
|
-
const projectRoot =
|
|
3532
|
+
const projectRoot = process11.cwd();
|
|
4876
3533
|
const configFile = config3;
|
|
4877
3534
|
if (!configFile) {
|
|
4878
3535
|
console.error(`[ERROR] No configuration found`);
|