From 3d0d6c1c84fcd5a0f669089ed5bc9f22177a431b Mon Sep 17 00:00:00 2001 From: DanMat Date: Wed, 19 Aug 2026 00:45:24 -0400 Subject: [PATCH 1/2] fix: skip postinstall when project has no package.json checkSimpleGitHooksInDependencies (called from postinstall.js outside a try/catch) crashed with an uncaught ENOENT when the resolved project directory had no package.json, failing the whole install (#112). - checkSimpleGitHooksInDependencies returns false when there's no package.json, so postinstall skips instead of throwing. - _getPackageJson guards with fs.existsSync so its documented "Package.json doesn't exist" error is thrown instead of a raw statSync crash (the previous check was dead code, statSync threw first). Adds a regression test. --- .changeset/skip-when-no-package-json.md | 5 +++++ simple-git-hooks.js | 8 +++++++- simple-git-hooks.test.js | 9 +++++++++ 3 files changed, 21 insertions(+), 1 deletion(-) create mode 100644 .changeset/skip-when-no-package-json.md diff --git a/.changeset/skip-when-no-package-json.md b/.changeset/skip-when-no-package-json.md new file mode 100644 index 0000000..ed7bb0d --- /dev/null +++ b/.changeset/skip-when-no-package-json.md @@ -0,0 +1,5 @@ +--- +"simple-git-hooks": patch +--- + +fix: don't crash `postinstall` when the resolved project directory has no package.json — skip instead of throwing an uncaught ENOENT diff --git a/simple-git-hooks.js b/simple-git-hooks.js index 9ade519..bf673d4 100644 --- a/simple-git-hooks.js +++ b/simple-git-hooks.js @@ -152,6 +152,12 @@ function checkSimpleGitHooksInDependencies(projectRootPath) { throw TypeError("Package json path is not a string!") } + // No package.json means we're not in a project that depends on simple-git-hooks + // (e.g. postinstall resolved to a directory without one) — skip instead of crashing. + if (!fs.existsSync(path.normalize(projectRootPath + '/package.json'))) { + return false + } + const {packageJsonContent} = _getPackageJson(projectRootPath) // if simple-git-hooks in dependencies -> note user that he should remove move it to devDeps! @@ -325,7 +331,7 @@ function _getPackageJson(projectPath = process.cwd()) { const targetPackageJson = path.normalize(projectPath + '/package.json') - if (!fs.statSync(targetPackageJson).isFile()) { + if (!fs.existsSync(targetPackageJson) || !fs.statSync(targetPackageJson).isFile()) { throw Error("Package.json doesn't exist") } diff --git a/simple-git-hooks.test.js b/simple-git-hooks.test.js index 0093217..434f934 100644 --- a/simple-git-hooks.test.js +++ b/simple-git-hooks.test.js @@ -129,6 +129,15 @@ describe("Simple Git Hooks tests", () => { simpleGitHooks.checkSimpleGitHooksInDependencies(PROJECT_WITHOUT_SIMPLE_GIT_HOOKS) ).toBe(false); }); + + it("returns false (does not throw) when package.json does not exist", () => { + const NON_EXISTENT_PROJECT = path.normalize( + path.join(process.cwd(), "_tests", "this_directory_does_not_exist") + ); + expect( + simpleGitHooks.checkSimpleGitHooksInDependencies(NON_EXISTENT_PROJECT) + ).toBe(false); + }); }); }); From faaed4f5adbf20907401e0a76a400313d96e5d8e Mon Sep 17 00:00:00 2001 From: DanMat Date: Wed, 19 Aug 2026 01:07:30 -0400 Subject: [PATCH 2/2] test: exercise an existing directory without package.json Use a real (mkdtemp) directory that exists but has no package.json to match the postinstall scenario in #112, rather than a fully-nonexistent path. Still fails on the original code (statSync ENOENT) and passes with the fix. --- simple-git-hooks.test.js | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/simple-git-hooks.test.js b/simple-git-hooks.test.js index 434f934..1bf4ea4 100644 --- a/simple-git-hooks.test.js +++ b/simple-git-hooks.test.js @@ -131,12 +131,17 @@ describe("Simple Git Hooks tests", () => { }); it("returns false (does not throw) when package.json does not exist", () => { - const NON_EXISTENT_PROJECT = path.normalize( - path.join(process.cwd(), "_tests", "this_directory_does_not_exist") + // A directory that exists but has no package.json (the postinstall scenario in #112) + const dirWithoutPackageJson = fs.mkdtempSync( + path.join(process.cwd(), "_tests", "no_package_json_") ); - expect( - simpleGitHooks.checkSimpleGitHooksInDependencies(NON_EXISTENT_PROJECT) - ).toBe(false); + try { + expect( + simpleGitHooks.checkSimpleGitHooksInDependencies(dirWithoutPackageJson) + ).toBe(false); + } finally { + fs.rmSync(dirWithoutPackageJson, { recursive: true, force: true }); + } }); }); });