From 761ed2f64f501562e9ded6af87191158a23829c4 Mon Sep 17 00:00:00 2001
From: NullVoxPopuli <199018+NullVoxPopuli@users.noreply.github.com>
Date: Wed, 4 Oct 2023 16:12:51 -0400
Subject: [PATCH] Fix https://github.com/actions/setup-node/issues/864

---
 __tests__/main.test.ts |  1 +
 src/main.ts            | 12 +++++++++++-
 src/util.ts            | 24 +++++++++++++++++++++---
 3 files changed, 33 insertions(+), 4 deletions(-)

diff --git a/__tests__/main.test.ts b/__tests__/main.test.ts
index b5724875..36024e65 100644
--- a/__tests__/main.test.ts
+++ b/__tests__/main.test.ts
@@ -101,6 +101,7 @@ describe('main tests', () => {
       ${'  14.1.0  '}                              | ${'14.1.0'}
       ${'{"volta": {"node": ">=14.0.0 <=17.0.0"}}'}| ${'>=14.0.0 <=17.0.0'}
       ${'{"engines": {"node": "17.0.0"}}'}         | ${'17.0.0'}
+      ${'{}'}                                      | ${null}
     `.it('parses "$contents"', ({contents, expected}) => {
       expect(util.parseNodeVersionFile(contents)).toBe(expected);
     });
diff --git a/src/main.ts b/src/main.ts
index ac051766..34f94310 100644
--- a/src/main.ts
+++ b/src/main.ts
@@ -105,7 +105,17 @@ function resolveVersionInput(): string {
       );
     }
 
-    version = parseNodeVersionFile(fs.readFileSync(versionFilePath, 'utf8'));
+    const parsedVersion = parseNodeVersionFile(
+      fs.readFileSync(versionFilePath, 'utf8')
+    );
+
+    if (parsedVersion) {
+      version = parsedVersion;
+    } else {
+      core.warning(
+        `Could not determine node version from ${versionFilePath}. Falling back`
+      );
+    }
 
     core.info(`Resolved ${versionFileInput} as ${version}`);
   }
diff --git a/src/util.ts b/src/util.ts
index 3ae94a2d..0b2b1490 100644
--- a/src/util.ts
+++ b/src/util.ts
@@ -1,13 +1,31 @@
 import * as core from '@actions/core';
 import * as exec from '@actions/exec';
 
-export function parseNodeVersionFile(contents: string): string {
+export function parseNodeVersionFile(contents: string): string | null {
   let nodeVersion: string | undefined;
 
   // Try parsing the file as an NPM `package.json` file.
   try {
-    nodeVersion = JSON.parse(contents).volta?.node;
-    if (!nodeVersion) nodeVersion = JSON.parse(contents).engines?.node;
+    const manifest = JSON.parse(contents);
+
+    // JSON can parse numbers, but that's handled later
+    if (typeof manifest === 'object') {
+      nodeVersion = manifest.volta?.node;
+      if (!nodeVersion) nodeVersion = manifest.engines?.node;
+
+      // if contents are an object, we parsed JSON
+      // this can happen if node-version-file is a package.json
+      // yet contains no volta.node or engines.node
+      //
+      // if node-version file is _not_ json, control flow
+      // will not have reached these lines.
+      //
+      // And because we've reached here, we know the contents
+      // *are* JSON, so no further string parsing makes sense.
+      if (!nodeVersion) {
+        return null;
+      }
+    }
   } catch {
     core.info('Node version file is not JSON file');
   }