JSON.parse(fs.readFileSync()) returning a buffer - string of numbers

fs.readFileSync() returns a Buffer if you don't specify an encoding.

https://nodejs.org/api/fs.html#fs_fs_readfilesync_path_options

So, tell fs.readFileSync() what encoding to use:

squadJSON = JSON.parse(fs.readFileSync('./squads/squad' + whichSquad + '.json', 'utf8')); 

The "why" has been answered by Sidney, but a better "what to do" would be to use require(), which supports parsing valid JSON files synchronously and returning the result as an object:

squadJSON = require('./squads/squad' + whichSquad + '.json');

or even nicer, using an ES6 template literal:

squadJSON = require(`./squads/squad${whichSquad}.json`);

One notable difference using require() is that it resolves relative paths from __dirname, which is the directory path of the current module, whereas fs methods resolve relative paths using process.cwd(), or "current working directory". It is the directory within a shell session from which the main module of the program is executed by node.

Hopefully the examples below demonstrate how their relative path resolution differs:

To make require(...) behave like JSON.parse(fs.readFileSync(..., 'utf8')):

const { resolve } = require('path');

function readFileSyncJson (path) {
  return require(resolve(process.cwd(), path));
}

And to make JSON.parse(fs.readFileSync(..., 'utf8')) behave like require(...):

const { resolve } = require('path');

function requireJson (path) {
  return JSON.parse(fs.readFileSync(resolve(__dirname, path), 'utf8'));
}