bun-git-hooks 0.2.12 โ†’ 0.2.13

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -12,16 +12,17 @@
12
12
 
13
13
  ## Features
14
14
 
15
- - ๐ŸŽฏ **Simple Configuration**: Easy setup through multiple config file formats
16
- - ๐Ÿ”„ **Automatic Installation**: Hooks are installed on package installation
17
- - ๐Ÿ›ก๏ธ **Type Safe**: Written in TypeScript with comprehensive type definitions
18
- - ๐Ÿ”ง **Flexible Config**: Supports `.ts`, `.js`, `.mjs`, `.json` configurations
19
- - ๐Ÿ’ช **Robust**: Handles complex Git workspace configurations
20
- - ๐Ÿšซ **Skip Option**: Environment variable to skip hook installation
21
- - ๐Ÿงน **Cleanup**: Optional cleanup of unused hooks
22
- - ๐Ÿ“ฆ **Zero Dependencies**: Minimal footprint
23
- - โšก **Fast**: Built for Bun with performance in mind
24
- - ๐Ÿ” **Verbose Mode**: Detailed logging for troubleshooting
15
+ - ๐ŸŽฏ **Simple Configuration** _Easy setup through multiple config file formats_
16
+ - ๐Ÿ”„ **Automatic Installation** _Hooks are installed on package installation_
17
+ - ๐Ÿ›ก๏ธ **Type Safe** _Written in TypeScript with comprehensive type definitions_
18
+ - ๐Ÿ”ง **Flexible Config** _Supports `.ts`, `.js`, `.mjs`, `.json` configurations_
19
+ - ๐Ÿ’ช **Robust** _Handles complex Git workspace configurations_
20
+ - ๐Ÿšซ **Skip Option** _Environment variable to skip hook installation_
21
+ - ๐Ÿงน **Cleanup** _Optional cleanup of unused hooks_
22
+ - ๐Ÿ“ฆ **Zero Dependencies** _Minimal footprint_
23
+ - โšก **Fast** _Built for Bun with performance in mind_
24
+ - ๐Ÿ” **Verbose Mode** _Detailed logging for troubleshooting_
25
+ - ๐Ÿ”€ **Staged Lint** _Run commands only on staged files that match specific patterns_
25
26
 
26
27
  ## Installation
27
28
 
@@ -79,6 +80,9 @@ git-hooks uninstall
79
80
 
80
81
  # Enable verbose logging
81
82
  git-hooks --verbose
83
+
84
+ # Run staged lint for a specific hook manually
85
+ git-hooks run-staged-lint pre-commit
82
86
  ```
83
87
 
84
88
  ### Environment Variables
@@ -115,6 +119,73 @@ export default {
115
119
  }
116
120
  ```
117
121
 
122
+ ### Staged Lint (Lint Only Changed Files)
123
+
124
+ You can run linters and formatters only on staged files that match specific patterns, similar to lint-staged. This is particularly useful in pre-commit hooks to ensure quality checks run only on the files being committed.
125
+
126
+ #### Configuration
127
+
128
+ Add a `stagedLint` property to your hook configuration:
129
+
130
+ ```ts
131
+ // git-hooks.config.ts
132
+ export default {
133
+ 'pre-commit': {
134
+ stagedLint: {
135
+ '*.js': 'eslint --fix',
136
+ '*.{ts,tsx}': ['eslint --fix', 'prettier --write'],
137
+ '*.css': 'stylelint --fix',
138
+ '*.md': 'prettier --write'
139
+ }
140
+ },
141
+ 'verbose': true
142
+ }
143
+ ```
144
+
145
+ #### Manual CLI Usage
146
+
147
+ You can also run the staged lint manually using the CLI:
148
+
149
+ ```bash
150
+ # Run staged lint for pre-commit
151
+ git-hooks run-staged-lint pre-commit
152
+
153
+ # Run with verbose output
154
+ git-hooks run-staged-lint pre-commit --verbose
155
+ ```
156
+
157
+ #### Pattern Matching
158
+
159
+ For each file pattern, you can specify either a single command or an array of commands that will run in sequence. The commands will only receive the staged files that match the pattern.
160
+
161
+ For example:
162
+
163
+ ```ts
164
+ // git-hooks.config.ts
165
+ export default {
166
+ '*.{js,jsx}': 'eslint --fix', // Run eslint only on JavaScript files
167
+ '*.{ts,tsx}': ['eslint --fix', 'prettier --write'], // Run eslint and then prettier on TypeScript files
168
+ '*.css': 'stylelint --fix', // Run stylelint only on CSS files
169
+ '*.md': 'prettier --write' // Run prettier only on Markdown files
170
+ }
171
+ ```
172
+
173
+ The output will show which files are being processed and which tasks are being run:
174
+
175
+ ```bash
176
+ $ git commit
177
+
178
+ โฏ Running tasks for staged files...
179
+ โฏ *.js โ€” 2 files
180
+ โ ผ eslint --fix
181
+ โฏ *.{ts,tsx} โ€” 3 files
182
+ โ น eslint --fix
183
+ โ น prettier --write
184
+ โฏ *.css โ€” 1 file
185
+ โ ผ stylelint --fix
186
+ โฏ *.md โ€” no files [SKIPPED]
187
+ ```
188
+
118
189
  ### Error Handling
119
190
 
120
191
  The library provides clear error messages:
package/dist/bin/cli.js CHANGED
@@ -604,7 +604,7 @@ class CAC extends EventEmitter {
604
604
  }
605
605
  }
606
606
  // package.json
607
- var version = "0.2.12";
607
+ var version = "0.2.13";
608
608
 
609
609
  // src/git-hooks.ts
610
610
  import fs from "fs";
@@ -777,11 +777,26 @@ async function loadConfig({
777
777
  for (const ext of extensions) {
778
778
  const fullPath = resolve(baseDir, `${configPath}${ext}`);
779
779
  const config2 = await tryLoadConfig(fullPath, defaultConfig);
780
- if (config2 !== null)
780
+ if (config2 !== null) {
781
+ console.log("config found:", `${configPath}${ext}`);
781
782
  return config2;
783
+ }
782
784
  }
783
785
  }
784
- console.error("Failed to load client config from any expected location");
786
+ try {
787
+ const pkgPath = resolve(baseDir, "package.json");
788
+ if (existsSync(pkgPath)) {
789
+ const pkg = await import(pkgPath);
790
+ const pkgConfig = pkg[name];
791
+ if (pkgConfig && typeof pkgConfig === "object" && !Array.isArray(pkgConfig)) {
792
+ try {
793
+ console.log("package config found!");
794
+ return deepMerge(defaultConfig, pkgConfig);
795
+ } catch {}
796
+ }
797
+ }
798
+ } catch {}
799
+ console.log("No config found, using default config");
785
800
  return defaultConfig;
786
801
  }
787
802
  var defaultConfigDir = resolve(process2.cwd(), "config");
@@ -789,7 +804,12 @@ var defaultGeneratedDir = resolve(process2.cwd(), "src/generated");
789
804
 
790
805
  // git-hooks.config.ts
791
806
  var config = {
792
- "pre-commit": "bun run lint && bun run test",
807
+ "pre-commit": {
808
+ stagedLint: {
809
+ "*.{js,ts,json,yaml,yml,md}": "bunx --bun eslint . --fix"
810
+ }
811
+ },
812
+ "commit-msg": "bun commitlint --edit $1",
793
813
  verbose: true
794
814
  };
795
815
  var git_hooks_config_default = config;
@@ -802,6 +822,9 @@ var config2 = await loadConfig({
802
822
  });
803
823
 
804
824
  // src/git-hooks.ts
825
+ import { exec } from "child_process";
826
+ import { promisify } from "util";
827
+ var execAsync = promisify(exec);
805
828
  var VALID_GIT_HOOKS = [
806
829
  "applypatch-msg",
807
830
  "pre-applypatch",
@@ -894,13 +917,86 @@ function setHooksFromConfig(projectRootPath = process4.cwd(), options) {
894
917
  }
895
918
  }
896
919
  }
897
- function _setHook(hook, command, projectRoot = process4.cwd()) {
920
+ async function getStagedFiles(projectRoot = process4.cwd()) {
921
+ try {
922
+ const { stdout } = await execAsync("git diff --staged --name-only --diff-filter=ACMR", { cwd: projectRoot });
923
+ return stdout.trim().split(`
924
+ `).filter(Boolean);
925
+ } catch (error) {
926
+ console.error("[ERROR] Failed to get staged files:", error);
927
+ return [];
928
+ }
929
+ }
930
+ function matchesGlob(file, pattern) {
931
+ if (pattern.includes("*")) {
932
+ const regexPattern = pattern.replace(/\./g, "\\.").replace(/\*/g, ".*").replace(/\?/g, ".");
933
+ const regex = new RegExp(`^${regexPattern}$`);
934
+ return regex.test(file);
935
+ }
936
+ return file === pattern;
937
+ }
938
+ function filterFilesByPattern(files, pattern) {
939
+ return files.filter((file) => matchesGlob(file, pattern));
940
+ }
941
+ async function runCommandOnStagedFiles(command, files, projectRoot = process4.cwd(), verbose = false) {
942
+ if (files.length === 0) {
943
+ if (verbose)
944
+ console.info("[INFO] No matching files for pattern");
945
+ return true;
946
+ }
947
+ const commands = Array.isArray(command) ? command : [command];
948
+ for (const cmd of commands) {
949
+ try {
950
+ const fullCommand = `${cmd} ${files.join(" ")}`;
951
+ if (verbose)
952
+ console.info(`[INFO] Running: ${fullCommand}`);
953
+ const { stdout, stderr } = await execAsync(fullCommand, { cwd: projectRoot });
954
+ if (verbose) {
955
+ if (stdout)
956
+ console.info(stdout);
957
+ if (stderr)
958
+ console.error(stderr);
959
+ }
960
+ } catch (error) {
961
+ console.error(`[ERROR] Command failed: ${cmd}`, error);
962
+ return false;
963
+ }
964
+ }
965
+ return true;
966
+ }
967
+ async function processStagedLint(stagedLintConfig, projectRoot, verbose = false) {
968
+ const stagedFiles = await getStagedFiles(projectRoot);
969
+ if (stagedFiles.length === 0) {
970
+ if (verbose)
971
+ console.info("[INFO] No staged files found");
972
+ return true;
973
+ }
974
+ let success = true;
975
+ for (const [pattern, task] of Object.entries(stagedLintConfig)) {
976
+ const matchedFiles = filterFilesByPattern(stagedFiles, pattern);
977
+ const taskResult = await runCommandOnStagedFiles(task, matchedFiles, projectRoot, verbose);
978
+ if (!taskResult) {
979
+ success = false;
980
+ break;
981
+ }
982
+ }
983
+ return success;
984
+ }
985
+ function _setHook(hook, commandOrConfig, projectRoot = process4.cwd()) {
898
986
  const gitRoot = getGitProjectRoot(projectRoot);
899
987
  if (!gitRoot) {
900
988
  console.info("[INFO] No `.git` root folder found, skipping");
901
989
  return;
902
990
  }
903
- const hookCommand = PREPEND_SCRIPT + command;
991
+ let hookCommand;
992
+ if (typeof commandOrConfig === "string") {
993
+ hookCommand = PREPEND_SCRIPT + commandOrConfig;
994
+ } else if (commandOrConfig.stagedLint) {
995
+ hookCommand = PREPEND_SCRIPT + `git-hooks run-staged-lint ${hook}`;
996
+ } else {
997
+ console.error(`[ERROR] Invalid command or config for hook ${hook}`);
998
+ return;
999
+ }
904
1000
  const hookDirectory = path.join(gitRoot, "hooks");
905
1001
  const hookPath = path.normalize(path.join(hookDirectory, hook));
906
1002
  if (!fs.existsSync(hookDirectory)) {
@@ -920,6 +1016,25 @@ function _removeHook(hook, projectRoot = process4.cwd(), verbose = false) {
920
1016
  if (verbose)
921
1017
  console.info(`[INFO] Successfully removed the ${hook} hook`);
922
1018
  }
1019
+ async function runStagedLint(hook) {
1020
+ try {
1021
+ const hookConfig = config2[hook];
1022
+ if (!hookConfig || typeof hookConfig !== "object" || !("stagedLint" in hookConfig)) {
1023
+ console.error(`[ERROR] No stagedLint configuration found for hook ${hook}`);
1024
+ return false;
1025
+ }
1026
+ const stagedLintConfig = hookConfig.stagedLint;
1027
+ if (!stagedLintConfig) {
1028
+ console.error(`[ERROR] Invalid stagedLint configuration for hook ${hook}`);
1029
+ return false;
1030
+ }
1031
+ const verbose = config2.verbose === true;
1032
+ return await processStagedLint(stagedLintConfig, process4.cwd(), verbose);
1033
+ } catch (error) {
1034
+ console.error("[ERROR] Failed to run staged lint:", error);
1035
+ return false;
1036
+ }
1037
+ }
923
1038
 
924
1039
  // bin/cli.ts
925
1040
  var cli = new CAC("git-hooks");
@@ -958,6 +1073,24 @@ cli.command("uninstall", "Remove all git hooks").alias("remove").option("--verbo
958
1073
  process5.exit(1);
959
1074
  }
960
1075
  });
1076
+ cli.command("run-staged-lint <hook>", "Run staged lint for a specific git hook").option("--verbose", "Enable verbose logging").example("git-hooks run-staged-lint pre-commit").example("git-hooks run-staged-lint pre-push --verbose").action(async (hook, options) => {
1077
+ try {
1078
+ if (options?.verbose) {
1079
+ console.log("[DEBUG] Running staged lint for hook:", hook);
1080
+ console.log("[DEBUG] Working directory:", process5.cwd());
1081
+ }
1082
+ const success = await runStagedLint(hook);
1083
+ if (success) {
1084
+ console.log("[INFO] Staged lint completed successfully");
1085
+ } else {
1086
+ console.error("[ERROR] Staged lint failed");
1087
+ process5.exit(1);
1088
+ }
1089
+ } catch (err) {
1090
+ console.error("[ERROR] Was not able to run staged lint. Error:", err);
1091
+ process5.exit(1);
1092
+ }
1093
+ });
961
1094
  cli.version(version);
962
1095
  cli.help();
963
1096
  cli.parse();
@@ -1,5 +1,6 @@
1
- import type { SetHooksFromConfigOptions } from './types';
1
+ import type { SetHooksFromConfigOptions, StagedLintConfig } from './types';
2
2
 
3
+ declare const execAsync: unknown;
3
4
  export declare const VALID_GIT_HOOKS: Array<
4
5
  'applypatch-msg' |
5
6
  'pre-applypatch' |
@@ -36,10 +37,16 @@ export declare function getGitProjectRoot(directory: string): string | undefined
36
37
  export declare function checkBunGitHooksInDependencies(projectRootPath: string): boolean;
37
38
  declare function _getPackageJson(projectPath): void;
38
39
  export declare function setHooksFromConfig(projectRootPath: string, options?: SetHooksFromConfigOptions): void;
39
- declare function _setHook(hook: string, command: string, projectRoot: string): void;
40
+ declare function getStagedFiles(projectRoot: string): Promise<string[]>;
41
+ declare function matchesGlob(file: string, pattern: string): boolean;
42
+ declare function filterFilesByPattern(files: string[], pattern: string): string[];
43
+ declare function runCommandOnStagedFiles(command: string | string[], files: string[], projectRoot: string, verbose): Promise<boolean>;
44
+ declare function processStagedLint(stagedLintConfig: StagedLintConfig, projectRoot: string, verbose): Promise<boolean>;
45
+ declare function _setHook(hook: string, commandOrConfig: string | { stagedLint?: StagedLintConfig }, projectRoot: string): void;
40
46
  export declare function removeHooks(projectRoot: string, verbose): void;
41
47
  declare function _removeHook(hook: string, projectRoot, verbose): void;
42
- declare function _validateHooks(config: Record<string, string>): void;
48
+ export declare function runStagedLint(hook: string): Promise<boolean>;
49
+ declare function _validateHooks(config: Record<string, any>): boolean;
43
50
  declare const gitHooks: {
44
51
  PREPEND_SCRIPT: typeof PREPEND_SCRIPT
45
52
  setHooksFromConfig: typeof setHooksFromConfig
@@ -47,6 +54,8 @@ declare const gitHooks: {
47
54
  checkBunGitHooksInDependencies: typeof checkBunGitHooksInDependencies
48
55
  getProjectRootDirectoryFromNodeModules: typeof getProjectRootDirectoryFromNodeModules
49
56
  getGitProjectRoot: typeof getGitProjectRoot
57
+ runStagedLint: typeof runStagedLint
58
+ getStagedFiles: typeof getStagedFiles
50
59
  };
51
60
 
52
61
  export default gitHooks;
@@ -1,42 +1,11 @@
1
- import type { Buffer } from 'node:buffer';
1
+ export declare type StagedLintTask = string | string[]
2
2
 
3
- export declare interface RawImageData<T> {
4
- width: number
5
- height: number
6
- data: T
7
- }
8
- export declare interface BufferRet {
9
- data: Buffer | Uint8ClampedArray
10
- width: number
11
- height: number
12
- exifBuffer?: ArrayBuffer
13
- comments?: string[]
14
- }
15
- export declare type UintArrRet = ImageData & {
16
- exifBuffer?: ArrayBuffer
17
- comments?: string[]
18
- }
19
-
20
- export interface ImageData {
21
- width: number
22
- height: number
23
- data: Uint8ClampedArray | Buffer
24
- colorSpace?: 'srgb'
25
- }
26
-
27
- export type BufferLike = Buffer | Uint8Array | ArrayLike<number> | Iterable<number> | ArrayBuffer
28
-
29
- export interface DecoderOptions {
30
- useTArray: boolean
31
- colorTransform?: boolean
32
- formatAsRGBA?: boolean
33
- tolerantDecoding?: boolean
34
- maxResolutionInMP?: number
35
- maxMemoryUsageInMB?: number
3
+ export interface StagedLintConfig {
4
+ [pattern: string]: StagedLintTask
36
5
  }
37
6
 
38
7
  export type GitHooksConfig = {
39
- [K in typeof VALID_GIT_HOOKS[number]]?: string
8
+ [K in typeof VALID_GIT_HOOKS[number]]?: string | { stagedLint?: StagedLintConfig }
40
9
  } & {
41
10
  preserveUnused?: boolean | typeof VALID_GIT_HOOKS[number][]
42
11
  verbose?: boolean
@@ -1,5 +1,6 @@
1
- import type { SetHooksFromConfigOptions } from './types';
1
+ import type { SetHooksFromConfigOptions, StagedLintConfig } from './types';
2
2
 
3
+ declare const execAsync: unknown;
3
4
  export declare const VALID_GIT_HOOKS: Array<
4
5
  'applypatch-msg' |
5
6
  'pre-applypatch' |
@@ -36,10 +37,16 @@ export declare function getGitProjectRoot(directory: string): string | undefined
36
37
  export declare function checkBunGitHooksInDependencies(projectRootPath: string): boolean;
37
38
  declare function _getPackageJson(projectPath): void;
38
39
  export declare function setHooksFromConfig(projectRootPath: string, options?: SetHooksFromConfigOptions): void;
39
- declare function _setHook(hook: string, command: string, projectRoot: string): void;
40
+ declare function getStagedFiles(projectRoot: string): Promise<string[]>;
41
+ declare function matchesGlob(file: string, pattern: string): boolean;
42
+ declare function filterFilesByPattern(files: string[], pattern: string): string[];
43
+ declare function runCommandOnStagedFiles(command: string | string[], files: string[], projectRoot: string, verbose): Promise<boolean>;
44
+ declare function processStagedLint(stagedLintConfig: StagedLintConfig, projectRoot: string, verbose): Promise<boolean>;
45
+ declare function _setHook(hook: string, commandOrConfig: string | { stagedLint?: StagedLintConfig }, projectRoot: string): void;
40
46
  export declare function removeHooks(projectRoot: string, verbose): void;
41
47
  declare function _removeHook(hook: string, projectRoot, verbose): void;
42
- declare function _validateHooks(config: Record<string, string>): void;
48
+ export declare function runStagedLint(hook: string): Promise<boolean>;
49
+ declare function _validateHooks(config: Record<string, any>): boolean;
43
50
  declare const gitHooks: {
44
51
  PREPEND_SCRIPT: typeof PREPEND_SCRIPT
45
52
  setHooksFromConfig: typeof setHooksFromConfig
@@ -47,6 +54,8 @@ declare const gitHooks: {
47
54
  checkBunGitHooksInDependencies: typeof checkBunGitHooksInDependencies
48
55
  getProjectRootDirectoryFromNodeModules: typeof getProjectRootDirectoryFromNodeModules
49
56
  getGitProjectRoot: typeof getGitProjectRoot
57
+ runStagedLint: typeof runStagedLint
58
+ getStagedFiles: typeof getStagedFiles
50
59
  };
51
60
 
52
61
  export default gitHooks;
package/dist/index.js CHANGED
@@ -1,355 +1,10 @@
1
- var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
2
-
3
- // node:process
4
- var C, T, q, A, I, Q, S = (e, t) => () => (t || e((t = { exports: {} }).exports, t), t.exports), N = (e, t) => {
5
- for (var n in t)
6
- T(e, n, { get: t[n], enumerable: true });
7
- }, d = (e, t, n, w) => {
8
- if (t && typeof t == "object" || typeof t == "function")
9
- for (let l of A(t))
10
- !Q.call(e, l) && l !== n && T(e, l, { get: () => t[l], enumerable: !(w = q(t, l)) || w.enumerable });
11
- return e;
12
- }, h = (e, t, n) => (d(e, t, "default"), n && d(n, t, "default")), y = (e, t, n) => (n = e != null ? C(I(e)) : {}, d(t || !e || !e.__esModule ? T(n, "default", { value: e, enumerable: true }) : n, e)), v, f, j;
13
- var init_process = __esm(() => {
14
- C = Object.create;
15
- T = Object.defineProperty;
16
- q = Object.getOwnPropertyDescriptor;
17
- A = Object.getOwnPropertyNames;
18
- I = Object.getPrototypeOf;
19
- Q = Object.prototype.hasOwnProperty;
20
- v = S((B, E) => {
21
- var r = E.exports = {}, i, u;
22
- function p() {
23
- throw new Error("setTimeout has not been defined");
24
- }
25
- function g() {
26
- throw new Error("clearTimeout has not been defined");
27
- }
28
- (function() {
29
- try {
30
- typeof setTimeout == "function" ? i = setTimeout : i = p;
31
- } catch {
32
- i = p;
33
- }
34
- try {
35
- typeof clearTimeout == "function" ? u = clearTimeout : u = g;
36
- } catch {
37
- u = g;
38
- }
39
- })();
40
- function b(e) {
41
- if (i === setTimeout)
42
- return setTimeout(e, 0);
43
- if ((i === p || !i) && setTimeout)
44
- return i = setTimeout, setTimeout(e, 0);
45
- try {
46
- return i(e, 0);
47
- } catch {
48
- try {
49
- return i.call(null, e, 0);
50
- } catch {
51
- return i.call(this, e, 0);
52
- }
53
- }
54
- }
55
- function O(e) {
56
- if (u === clearTimeout)
57
- return clearTimeout(e);
58
- if ((u === g || !u) && clearTimeout)
59
- return u = clearTimeout, clearTimeout(e);
60
- try {
61
- return u(e);
62
- } catch {
63
- try {
64
- return u.call(null, e);
65
- } catch {
66
- return u.call(this, e);
67
- }
68
- }
69
- }
70
- var o = [], s = false, a, m = -1;
71
- function U() {
72
- !s || !a || (s = false, a.length ? o = a.concat(o) : m = -1, o.length && x());
73
- }
74
- function x() {
75
- if (!s) {
76
- var e = b(U);
77
- s = true;
78
- for (var t = o.length;t; ) {
79
- for (a = o, o = [];++m < t; )
80
- a && a[m].run();
81
- m = -1, t = o.length;
82
- }
83
- a = null, s = false, O(e);
84
- }
85
- }
86
- r.nextTick = function(e) {
87
- var t = new Array(arguments.length - 1);
88
- if (arguments.length > 1)
89
- for (var n = 1;n < arguments.length; n++)
90
- t[n - 1] = arguments[n];
91
- o.push(new L(e, t)), o.length === 1 && !s && b(x);
92
- };
93
- function L(e, t) {
94
- this.fun = e, this.array = t;
95
- }
96
- L.prototype.run = function() {
97
- this.fun.apply(null, this.array);
98
- };
99
- r.title = "browser";
100
- r.browser = true;
101
- r.env = {};
102
- r.argv = [];
103
- r.version = "";
104
- r.versions = {};
105
- function c() {}
106
- r.on = c;
107
- r.addListener = c;
108
- r.once = c;
109
- r.off = c;
110
- r.removeListener = c;
111
- r.removeAllListeners = c;
112
- r.emit = c;
113
- r.prependListener = c;
114
- r.prependOnceListener = c;
115
- r.listeners = function(e) {
116
- return [];
117
- };
118
- r.binding = function(e) {
119
- throw new Error("process.binding is not supported");
120
- };
121
- r.cwd = function() {
122
- return "/";
123
- };
124
- r.chdir = function(e) {
125
- throw new Error("process.chdir is not supported");
126
- };
127
- r.umask = function() {
128
- return 0;
129
- };
130
- });
131
- f = {};
132
- N(f, { default: () => j });
133
- h(f, y(v()));
134
- j = y(v());
135
- });
136
-
137
1
  // src/config.ts
138
- init_process();
2
+ import process2 from "node:process";
139
3
 
140
4
  // node_modules/bunfig/dist/index.js
141
- var {existsSync, mkdirSync, readdirSync, writeFileSync} = (() => ({}));
142
-
143
- // node:path
144
- var L = Object.create;
145
- var h2 = Object.defineProperty;
146
- var D = Object.getOwnPropertyDescriptor;
147
- var T2 = Object.getOwnPropertyNames;
148
- var _ = Object.getPrototypeOf;
149
- var E = Object.prototype.hasOwnProperty;
150
- var R = (s, e) => () => (e || s((e = { exports: {} }).exports, e), e.exports);
151
- var N2 = (s, e, r, t) => {
152
- if (e && typeof e == "object" || typeof e == "function")
153
- for (let i of T2(e))
154
- !E.call(s, i) && i !== r && h2(s, i, { get: () => e[i], enumerable: !(t = D(e, i)) || t.enumerable });
155
- return s;
156
- };
157
- var j2 = (s, e, r) => (r = s != null ? L(_(s)) : {}, N2(e || !s || !s.__esModule ? h2(r, "default", { value: s, enumerable: true }) : r, s));
158
- var k = R((W, w) => {
159
- function v2(s) {
160
- if (typeof s != "string")
161
- throw new TypeError("Path must be a string. Received " + JSON.stringify(s));
162
- }
163
- function C2(s, e) {
164
- for (var r = "", t = 0, i = -1, a = 0, n, l = 0;l <= s.length; ++l) {
165
- if (l < s.length)
166
- n = s.charCodeAt(l);
167
- else {
168
- if (n === 47)
169
- break;
170
- n = 47;
171
- }
172
- if (n === 47) {
173
- if (!(i === l - 1 || a === 1))
174
- if (i !== l - 1 && a === 2) {
175
- if (r.length < 2 || t !== 2 || r.charCodeAt(r.length - 1) !== 46 || r.charCodeAt(r.length - 2) !== 46) {
176
- if (r.length > 2) {
177
- var f2 = r.lastIndexOf("/");
178
- if (f2 !== r.length - 1) {
179
- f2 === -1 ? (r = "", t = 0) : (r = r.slice(0, f2), t = r.length - 1 - r.lastIndexOf("/")), i = l, a = 0;
180
- continue;
181
- }
182
- } else if (r.length === 2 || r.length === 1) {
183
- r = "", t = 0, i = l, a = 0;
184
- continue;
185
- }
186
- }
187
- e && (r.length > 0 ? r += "/.." : r = "..", t = 2);
188
- } else
189
- r.length > 0 ? r += "/" + s.slice(i + 1, l) : r = s.slice(i + 1, l), t = l - i - 1;
190
- i = l, a = 0;
191
- } else
192
- n === 46 && a !== -1 ? ++a : a = -1;
193
- }
194
- return r;
195
- }
196
- function F(s, e) {
197
- var r = e.dir || e.root, t = e.base || (e.name || "") + (e.ext || "");
198
- return r ? r === e.root ? r + t : r + s + t : t;
199
- }
200
- var m = { resolve: function() {
201
- for (var e = "", r = false, t, i = arguments.length - 1;i >= -1 && !r; i--) {
202
- var a;
203
- i >= 0 ? a = arguments[i] : (t === undefined && (t = process.cwd()), a = t), v2(a), a.length !== 0 && (e = a + "/" + e, r = a.charCodeAt(0) === 47);
204
- }
205
- return e = C2(e, !r), r ? e.length > 0 ? "/" + e : "/" : e.length > 0 ? e : ".";
206
- }, normalize: function(e) {
207
- if (v2(e), e.length === 0)
208
- return ".";
209
- var r = e.charCodeAt(0) === 47, t = e.charCodeAt(e.length - 1) === 47;
210
- return e = C2(e, !r), e.length === 0 && !r && (e = "."), e.length > 0 && t && (e += "/"), r ? "/" + e : e;
211
- }, isAbsolute: function(e) {
212
- return v2(e), e.length > 0 && e.charCodeAt(0) === 47;
213
- }, join: function() {
214
- if (arguments.length === 0)
215
- return ".";
216
- for (var e, r = 0;r < arguments.length; ++r) {
217
- var t = arguments[r];
218
- v2(t), t.length > 0 && (e === undefined ? e = t : e += "/" + t);
219
- }
220
- return e === undefined ? "." : m.normalize(e);
221
- }, relative: function(e, r) {
222
- if (v2(e), v2(r), e === r || (e = m.resolve(e), r = m.resolve(r), e === r))
223
- return "";
224
- for (var t = 1;t < e.length && e.charCodeAt(t) === 47; ++t)
225
- ;
226
- for (var i = e.length, a = i - t, n = 1;n < r.length && r.charCodeAt(n) === 47; ++n)
227
- ;
228
- for (var l = r.length, f2 = l - n, c = a < f2 ? a : f2, d2 = -1, o = 0;o <= c; ++o) {
229
- if (o === c) {
230
- if (f2 > c) {
231
- if (r.charCodeAt(n + o) === 47)
232
- return r.slice(n + o + 1);
233
- if (o === 0)
234
- return r.slice(n + o);
235
- } else
236
- a > c && (e.charCodeAt(t + o) === 47 ? d2 = o : o === 0 && (d2 = 0));
237
- break;
238
- }
239
- var A2 = e.charCodeAt(t + o), z = r.charCodeAt(n + o);
240
- if (A2 !== z)
241
- break;
242
- A2 === 47 && (d2 = o);
243
- }
244
- var b = "";
245
- for (o = t + d2 + 1;o <= i; ++o)
246
- (o === i || e.charCodeAt(o) === 47) && (b.length === 0 ? b += ".." : b += "/..");
247
- return b.length > 0 ? b + r.slice(n + d2) : (n += d2, r.charCodeAt(n) === 47 && ++n, r.slice(n));
248
- }, _makeLong: function(e) {
249
- return e;
250
- }, dirname: function(e) {
251
- if (v2(e), e.length === 0)
252
- return ".";
253
- for (var r = e.charCodeAt(0), t = r === 47, i = -1, a = true, n = e.length - 1;n >= 1; --n)
254
- if (r = e.charCodeAt(n), r === 47) {
255
- if (!a) {
256
- i = n;
257
- break;
258
- }
259
- } else
260
- a = false;
261
- return i === -1 ? t ? "/" : "." : t && i === 1 ? "//" : e.slice(0, i);
262
- }, basename: function(e, r) {
263
- if (r !== undefined && typeof r != "string")
264
- throw new TypeError('"ext" argument must be a string');
265
- v2(e);
266
- var t = 0, i = -1, a = true, n;
267
- if (r !== undefined && r.length > 0 && r.length <= e.length) {
268
- if (r.length === e.length && r === e)
269
- return "";
270
- var l = r.length - 1, f2 = -1;
271
- for (n = e.length - 1;n >= 0; --n) {
272
- var c = e.charCodeAt(n);
273
- if (c === 47) {
274
- if (!a) {
275
- t = n + 1;
276
- break;
277
- }
278
- } else
279
- f2 === -1 && (a = false, f2 = n + 1), l >= 0 && (c === r.charCodeAt(l) ? --l === -1 && (i = n) : (l = -1, i = f2));
280
- }
281
- return t === i ? i = f2 : i === -1 && (i = e.length), e.slice(t, i);
282
- } else {
283
- for (n = e.length - 1;n >= 0; --n)
284
- if (e.charCodeAt(n) === 47) {
285
- if (!a) {
286
- t = n + 1;
287
- break;
288
- }
289
- } else
290
- i === -1 && (a = false, i = n + 1);
291
- return i === -1 ? "" : e.slice(t, i);
292
- }
293
- }, extname: function(e) {
294
- v2(e);
295
- for (var r = -1, t = 0, i = -1, a = true, n = 0, l = e.length - 1;l >= 0; --l) {
296
- var f2 = e.charCodeAt(l);
297
- if (f2 === 47) {
298
- if (!a) {
299
- t = l + 1;
300
- break;
301
- }
302
- continue;
303
- }
304
- i === -1 && (a = false, i = l + 1), f2 === 46 ? r === -1 ? r = l : n !== 1 && (n = 1) : r !== -1 && (n = -1);
305
- }
306
- return r === -1 || i === -1 || n === 0 || n === 1 && r === i - 1 && r === t + 1 ? "" : e.slice(r, i);
307
- }, format: function(e) {
308
- if (e === null || typeof e != "object")
309
- throw new TypeError('The "pathObject" argument must be of type Object. Received type ' + typeof e);
310
- return F("/", e);
311
- }, parse: function(e) {
312
- v2(e);
313
- var r = { root: "", dir: "", base: "", ext: "", name: "" };
314
- if (e.length === 0)
315
- return r;
316
- var t = e.charCodeAt(0), i = t === 47, a;
317
- i ? (r.root = "/", a = 1) : a = 0;
318
- for (var n = -1, l = 0, f2 = -1, c = true, d2 = e.length - 1, o = 0;d2 >= a; --d2) {
319
- if (t = e.charCodeAt(d2), t === 47) {
320
- if (!c) {
321
- l = d2 + 1;
322
- break;
323
- }
324
- continue;
325
- }
326
- f2 === -1 && (c = false, f2 = d2 + 1), t === 46 ? n === -1 ? n = d2 : o !== 1 && (o = 1) : n !== -1 && (o = -1);
327
- }
328
- return n === -1 || f2 === -1 || o === 0 || o === 1 && n === f2 - 1 && n === l + 1 ? f2 !== -1 && (l === 0 && i ? r.base = r.name = e.slice(1, f2) : r.base = r.name = e.slice(l, f2)) : (l === 0 && i ? (r.name = e.slice(1, n), r.base = e.slice(1, f2)) : (r.name = e.slice(l, n), r.base = e.slice(l, f2)), r.ext = e.slice(n, f2)), l > 0 ? r.dir = e.slice(0, l - 1) : i && (r.dir = "/"), r;
329
- }, sep: "/", delimiter: ":", win32: null, posix: null };
330
- m.posix = m;
331
- w.exports = m;
332
- });
333
- var x = j2(k());
334
- var u = x;
335
- var J = x;
336
- var P = function(s) {
337
- return s;
338
- };
339
- var S2 = function() {
340
- throw new Error("Not implemented");
341
- };
342
- u.parse ??= S2;
343
- J.parse ??= S2;
344
- var g = { resolve: u.resolve.bind(u), normalize: u.normalize.bind(u), isAbsolute: u.isAbsolute.bind(u), join: u.join.bind(u), relative: u.relative.bind(u), toNamespacedPath: P, dirname: u.dirname.bind(u), basename: u.basename.bind(u), extname: u.extname.bind(u), format: u.format.bind(u), parse: u.parse.bind(u), sep: "/", delimiter: ":", win32: undefined, posix: undefined, _makeLong: P };
345
- var y2 = { sep: "\\", delimiter: ";", win32: undefined, ...g, posix: g };
346
- g.win32 = y2.win32 = y2;
347
- g.posix = g;
348
- var q2 = g;
349
- var { resolve: B, normalize: G, isAbsolute: H, join: K, relative: Q2, toNamespacedPath: U, dirname: V, basename: X, extname: Y, format: Z, parse: $, sep: I2, delimiter: O } = g;
350
-
351
- // node_modules/bunfig/dist/index.js
352
- init_process();
5
+ import { existsSync, mkdirSync, readdirSync, writeFileSync } from "fs";
6
+ import { dirname, resolve } from "path";
7
+ import process from "process";
353
8
  function deepMerge(target, source) {
354
9
  if (Array.isArray(source) && Array.isArray(target) && source.length === 2 && target.length === 2 && isObject(source[0]) && "id" in source[0] && source[0].id === 3 && isObject(source[1]) && "id" in source[1] && source[1].id === 4) {
355
10
  return source;
@@ -497,7 +152,7 @@ async function loadConfig({
497
152
  cwd,
498
153
  defaultConfig
499
154
  }) {
500
- const baseDir = cwd || j.cwd();
155
+ const baseDir = cwd || process.cwd();
501
156
  const extensions = [".ts", ".js", ".mjs", ".cjs", ".json"];
502
157
  const configPaths = [
503
158
  `${name}.config`,
@@ -507,21 +162,41 @@ async function loadConfig({
507
162
  ];
508
163
  for (const configPath of configPaths) {
509
164
  for (const ext of extensions) {
510
- const fullPath = B(baseDir, `${configPath}${ext}`);
165
+ const fullPath = resolve(baseDir, `${configPath}${ext}`);
511
166
  const config2 = await tryLoadConfig(fullPath, defaultConfig);
512
- if (config2 !== null)
167
+ if (config2 !== null) {
168
+ console.log("config found:", `${configPath}${ext}`);
513
169
  return config2;
170
+ }
514
171
  }
515
172
  }
516
- console.error("Failed to load client config from any expected location");
173
+ try {
174
+ const pkgPath = resolve(baseDir, "package.json");
175
+ if (existsSync(pkgPath)) {
176
+ const pkg = await import(pkgPath);
177
+ const pkgConfig = pkg[name];
178
+ if (pkgConfig && typeof pkgConfig === "object" && !Array.isArray(pkgConfig)) {
179
+ try {
180
+ console.log("package config found!");
181
+ return deepMerge(defaultConfig, pkgConfig);
182
+ } catch {}
183
+ }
184
+ }
185
+ } catch {}
186
+ console.log("No config found, using default config");
517
187
  return defaultConfig;
518
188
  }
519
- var defaultConfigDir = B(j.cwd(), "config");
520
- var defaultGeneratedDir = B(j.cwd(), "src/generated");
189
+ var defaultConfigDir = resolve(process.cwd(), "config");
190
+ var defaultGeneratedDir = resolve(process.cwd(), "src/generated");
521
191
 
522
192
  // git-hooks.config.ts
523
193
  var config = {
524
- "pre-commit": "bun run lint && bun run test",
194
+ "pre-commit": {
195
+ stagedLint: {
196
+ "*.{js,ts,json,yaml,yml,md}": "bunx --bun eslint . --fix"
197
+ }
198
+ },
199
+ "commit-msg": "bun commitlint --edit $1",
525
200
  verbose: true
526
201
  };
527
202
  var git_hooks_config_default = config;
@@ -529,12 +204,16 @@ var git_hooks_config_default = config;
529
204
  // src/config.ts
530
205
  var config2 = await loadConfig({
531
206
  name: "git-hooks",
532
- cwd: j.cwd(),
207
+ cwd: process2.cwd(),
533
208
  defaultConfig: git_hooks_config_default
534
209
  });
535
210
  // src/git-hooks.ts
536
- var { default: fs} = (() => ({}));
537
- init_process();
211
+ import fs from "node:fs";
212
+ import path from "node:path";
213
+ import process3 from "node:process";
214
+ import { exec } from "node:child_process";
215
+ import { promisify } from "node:util";
216
+ var execAsync = promisify(exec);
538
217
  var VALID_GIT_HOOKS = [
539
218
  "applypatch-msg",
540
219
  "pre-applypatch",
@@ -578,32 +257,32 @@ if [ -f "$BUN_GIT_HOOKS_RC" ]; then
578
257
  fi
579
258
 
580
259
  `;
581
- function getGitProjectRoot(directory = j.cwd()) {
260
+ function getGitProjectRoot(directory = process3.cwd()) {
582
261
  if (directory.endsWith(".git")) {
583
- return q2.normalize(directory);
262
+ return path.normalize(directory);
584
263
  }
585
- let start = q2.normalize(directory);
586
- if (!start || start === q2.sep || start === ".") {
264
+ let start = path.normalize(directory);
265
+ if (!start || start === path.sep || start === ".") {
587
266
  return;
588
267
  }
589
- const fullPath = q2.join(start, ".git");
268
+ const fullPath = path.join(start, ".git");
590
269
  if (fs.existsSync(fullPath)) {
591
270
  if (!fs.lstatSync(fullPath).isDirectory()) {
592
271
  const content = fs.readFileSync(fullPath, { encoding: "utf-8" });
593
272
  const match = /^gitdir: (.*)\s*$/.exec(content);
594
273
  if (match) {
595
274
  const gitDir = match[1];
596
- let commonDir = q2.join(gitDir, "commondir");
275
+ let commonDir = path.join(gitDir, "commondir");
597
276
  if (fs.existsSync(commonDir)) {
598
277
  commonDir = fs.readFileSync(commonDir, "utf8").trim();
599
- return q2.resolve(gitDir, commonDir);
278
+ return path.resolve(gitDir, commonDir);
600
279
  }
601
- return q2.normalize(gitDir);
280
+ return path.normalize(gitDir);
602
281
  }
603
282
  }
604
- return q2.normalize(fullPath);
283
+ return path.normalize(fullPath);
605
284
  }
606
- const parentDir = q2.dirname(start);
285
+ const parentDir = path.dirname(start);
607
286
  if (parentDir === start) {
608
287
  return;
609
288
  }
@@ -640,18 +319,18 @@ function checkBunGitHooksInDependencies(projectRootPath) {
640
319
  }
641
320
  return "bun-git-hooks" in packageJsonContent.devDependencies;
642
321
  }
643
- function _getPackageJson(projectPath = j.cwd()) {
322
+ function _getPackageJson(projectPath = process3.cwd()) {
644
323
  if (typeof projectPath !== "string") {
645
324
  throw new TypeError("projectPath is not a string");
646
325
  }
647
- const targetPackageJson = q2.normalize(`${projectPath}/package.json`);
326
+ const targetPackageJson = path.normalize(`${projectPath}/package.json`);
648
327
  if (!fs.statSync(targetPackageJson).isFile()) {
649
328
  throw new Error("Package.json doesn't exist");
650
329
  }
651
330
  const packageJsonDataRaw = fs.readFileSync(targetPackageJson, { encoding: "utf-8" });
652
331
  return { packageJsonContent: JSON.parse(packageJsonDataRaw), packageJsonPath: targetPackageJson };
653
332
  }
654
- function setHooksFromConfig(projectRootPath = j.cwd(), options) {
333
+ function setHooksFromConfig(projectRootPath = process3.cwd(), options) {
655
334
  if (!config2 || Object.keys(config2).length === 0)
656
335
  throw new Error("[ERROR] Config was not found! Please add `.git-hooks.config.{ts,js,mjs,cjs,mts,cts,json}` or `git-hooks.config.{ts,js,mjs,cjs,mts,cts,json}` or the `git-hooks` entry in package.json.\r\nCheck README for details");
657
336
  const configFile = options?.configFile ? options.configFile : config2;
@@ -670,34 +349,127 @@ function setHooksFromConfig(projectRootPath = j.cwd(), options) {
670
349
  }
671
350
  }
672
351
  }
673
- function _setHook(hook, command, projectRoot = j.cwd()) {
352
+ async function getStagedFiles(projectRoot = process3.cwd()) {
353
+ try {
354
+ const { stdout } = await execAsync("git diff --staged --name-only --diff-filter=ACMR", { cwd: projectRoot });
355
+ return stdout.trim().split(`
356
+ `).filter(Boolean);
357
+ } catch (error) {
358
+ console.error("[ERROR] Failed to get staged files:", error);
359
+ return [];
360
+ }
361
+ }
362
+ function matchesGlob(file, pattern) {
363
+ if (pattern.includes("*")) {
364
+ const regexPattern = pattern.replace(/\./g, "\\.").replace(/\*/g, ".*").replace(/\?/g, ".");
365
+ const regex = new RegExp(`^${regexPattern}$`);
366
+ return regex.test(file);
367
+ }
368
+ return file === pattern;
369
+ }
370
+ function filterFilesByPattern(files, pattern) {
371
+ return files.filter((file) => matchesGlob(file, pattern));
372
+ }
373
+ async function runCommandOnStagedFiles(command, files, projectRoot = process3.cwd(), verbose = false) {
374
+ if (files.length === 0) {
375
+ if (verbose)
376
+ console.info("[INFO] No matching files for pattern");
377
+ return true;
378
+ }
379
+ const commands = Array.isArray(command) ? command : [command];
380
+ for (const cmd of commands) {
381
+ try {
382
+ const fullCommand = `${cmd} ${files.join(" ")}`;
383
+ if (verbose)
384
+ console.info(`[INFO] Running: ${fullCommand}`);
385
+ const { stdout, stderr } = await execAsync(fullCommand, { cwd: projectRoot });
386
+ if (verbose) {
387
+ if (stdout)
388
+ console.info(stdout);
389
+ if (stderr)
390
+ console.error(stderr);
391
+ }
392
+ } catch (error) {
393
+ console.error(`[ERROR] Command failed: ${cmd}`, error);
394
+ return false;
395
+ }
396
+ }
397
+ return true;
398
+ }
399
+ async function processStagedLint(stagedLintConfig, projectRoot, verbose = false) {
400
+ const stagedFiles = await getStagedFiles(projectRoot);
401
+ if (stagedFiles.length === 0) {
402
+ if (verbose)
403
+ console.info("[INFO] No staged files found");
404
+ return true;
405
+ }
406
+ let success = true;
407
+ for (const [pattern, task] of Object.entries(stagedLintConfig)) {
408
+ const matchedFiles = filterFilesByPattern(stagedFiles, pattern);
409
+ const taskResult = await runCommandOnStagedFiles(task, matchedFiles, projectRoot, verbose);
410
+ if (!taskResult) {
411
+ success = false;
412
+ break;
413
+ }
414
+ }
415
+ return success;
416
+ }
417
+ function _setHook(hook, commandOrConfig, projectRoot = process3.cwd()) {
674
418
  const gitRoot = getGitProjectRoot(projectRoot);
675
419
  if (!gitRoot) {
676
420
  console.info("[INFO] No `.git` root folder found, skipping");
677
421
  return;
678
422
  }
679
- const hookCommand = PREPEND_SCRIPT + command;
680
- const hookDirectory = q2.join(gitRoot, "hooks");
681
- const hookPath = q2.normalize(q2.join(hookDirectory, hook));
423
+ let hookCommand;
424
+ if (typeof commandOrConfig === "string") {
425
+ hookCommand = PREPEND_SCRIPT + commandOrConfig;
426
+ } else if (commandOrConfig.stagedLint) {
427
+ hookCommand = PREPEND_SCRIPT + `git-hooks run-staged-lint ${hook}`;
428
+ } else {
429
+ console.error(`[ERROR] Invalid command or config for hook ${hook}`);
430
+ return;
431
+ }
432
+ const hookDirectory = path.join(gitRoot, "hooks");
433
+ const hookPath = path.normalize(path.join(hookDirectory, hook));
682
434
  if (!fs.existsSync(hookDirectory)) {
683
435
  fs.mkdirSync(hookDirectory, { recursive: true });
684
436
  }
685
437
  fs.writeFileSync(hookPath, hookCommand, { mode: 493 });
686
438
  }
687
- function removeHooks(projectRoot = j.cwd(), verbose = false) {
439
+ function removeHooks(projectRoot = process3.cwd(), verbose = false) {
688
440
  for (const configEntry of VALID_GIT_HOOKS)
689
441
  _removeHook(configEntry, projectRoot, verbose);
690
442
  }
691
- function _removeHook(hook, projectRoot = j.cwd(), verbose = false) {
443
+ function _removeHook(hook, projectRoot = process3.cwd(), verbose = false) {
692
444
  const gitRoot = getGitProjectRoot(projectRoot);
693
- const hookPath = q2.normalize(`${gitRoot}/hooks/${hook}`);
445
+ const hookPath = path.normalize(`${gitRoot}/hooks/${hook}`);
694
446
  if (fs.existsSync(hookPath))
695
447
  fs.unlinkSync(hookPath);
696
448
  if (verbose)
697
449
  console.info(`[INFO] Successfully removed the ${hook} hook`);
698
450
  }
451
+ async function runStagedLint(hook) {
452
+ try {
453
+ const hookConfig = config2[hook];
454
+ if (!hookConfig || typeof hookConfig !== "object" || !("stagedLint" in hookConfig)) {
455
+ console.error(`[ERROR] No stagedLint configuration found for hook ${hook}`);
456
+ return false;
457
+ }
458
+ const stagedLintConfig = hookConfig.stagedLint;
459
+ if (!stagedLintConfig) {
460
+ console.error(`[ERROR] Invalid stagedLint configuration for hook ${hook}`);
461
+ return false;
462
+ }
463
+ const verbose = config2.verbose === true;
464
+ return await processStagedLint(stagedLintConfig, process3.cwd(), verbose);
465
+ } catch (error) {
466
+ console.error("[ERROR] Failed to run staged lint:", error);
467
+ return false;
468
+ }
469
+ }
699
470
  export {
700
471
  setHooksFromConfig,
472
+ runStagedLint,
701
473
  removeHooks,
702
474
  getProjectRootDirectoryFromNodeModules,
703
475
  getGitProjectRoot,
package/dist/types.d.ts CHANGED
@@ -1,42 +1,11 @@
1
- import type { Buffer } from 'node:buffer';
1
+ export declare type StagedLintTask = string | string[]
2
2
 
3
- export declare interface RawImageData<T> {
4
- width: number
5
- height: number
6
- data: T
7
- }
8
- export declare interface BufferRet {
9
- data: Buffer | Uint8ClampedArray
10
- width: number
11
- height: number
12
- exifBuffer?: ArrayBuffer
13
- comments?: string[]
14
- }
15
- export declare type UintArrRet = ImageData & {
16
- exifBuffer?: ArrayBuffer
17
- comments?: string[]
18
- }
19
-
20
- export interface ImageData {
21
- width: number
22
- height: number
23
- data: Uint8ClampedArray | Buffer
24
- colorSpace?: 'srgb'
25
- }
26
-
27
- export type BufferLike = Buffer | Uint8Array | ArrayLike<number> | Iterable<number> | ArrayBuffer
28
-
29
- export interface DecoderOptions {
30
- useTArray: boolean
31
- colorTransform?: boolean
32
- formatAsRGBA?: boolean
33
- tolerantDecoding?: boolean
34
- maxResolutionInMP?: number
35
- maxMemoryUsageInMB?: number
3
+ export interface StagedLintConfig {
4
+ [pattern: string]: StagedLintTask
36
5
  }
37
6
 
38
7
  export type GitHooksConfig = {
39
- [K in typeof VALID_GIT_HOOKS[number]]?: string
8
+ [K in typeof VALID_GIT_HOOKS[number]]?: string | { stagedLint?: StagedLintConfig }
40
9
  } & {
41
10
  preserveUnused?: boolean | typeof VALID_GIT_HOOKS[number][]
42
11
  verbose?: boolean
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "bun-git-hooks",
3
3
  "type": "module",
4
- "version": "0.2.12",
4
+ "version": "0.2.13",
5
5
  "description": "A modern, zero dependency tool for managing git hooks in Bun projects.",
6
6
  "author": "Chris Breuer <chris@stacksjs.org>",
7
7
  "license": "MIT",
@@ -73,29 +73,17 @@
73
73
  "zip:darwin-arm64": "zip -j bin/git-hooks-darwin-arm64.zip bin/git-hooks-darwin-arm64"
74
74
  },
75
75
  "devDependencies": {
76
- "@iconify-json/carbon": "^1.2.8",
77
- "@shikijs/vitepress-twoslash": "^3.2.2",
76
+ "@stacksjs/docs": "^0.70.23",
78
77
  "@stacksjs/eslint-config": "^4.10.2-beta.3",
79
- "@types/bun": "^1.2.9",
80
- "@types/node": "^22.14.0",
81
- "@vite-pwa/vitepress": "^1.0.0",
78
+ "@types/bun": "^1.2.10",
82
79
  "bumpp": "^10.1.0",
83
80
  "bun-plugin-dtsx": "^0.21.9",
84
- "bunfig": "^0.8.2",
81
+ "bunfig": "^0.8.3",
85
82
  "cac": "^6.7.14",
86
83
  "changelogen": "^0.6.1",
87
- "lint-staged": "^15.5.0",
88
- "typescript": "^5.8.3",
89
- "unocss": "^66.0.0",
90
- "unplugin-icons": "^22.1.0",
91
- "unplugin-vue-components": "^28.4.1",
92
- "vite-plugin-pwa": "^1.0.0",
93
- "vitepress": "^1.6.3"
84
+ "typescript": "^5.8.3"
94
85
  },
95
86
  "overrides": {
96
87
  "unconfig": "0.3.10"
97
- },
98
- "lint-staged": {
99
- "*.{js,ts}": "bunx --bun eslint . --fix"
100
88
  }
101
89
  }