diff --git a/app/server/src/configReader.ts b/app/server/src/configReader.ts index bcb3ab99b..e126b3146 100644 --- a/app/server/src/configReader.ts +++ b/app/server/src/configReader.ts @@ -1,6 +1,19 @@ import * as fs from "fs"; import * as path from "path"; +export function stripBom(str: string): string { + // Catches EFBBBF (UTF-8 BOM) because the buffer-to-string + // conversion translates it to FEFF (UTF-16 BOM). + if (str.charCodeAt(0) === 0xFEFF) { + return str.slice(1); + } + return str; +} + +export function readFile(filename: string): string { + return stripBom(fs.readFileSync(filename, { encoding: "utf-8" })); +} + export class ConfigReader { rootDir: string; @@ -15,7 +28,7 @@ export class ConfigReader { const fullPath = [this.rootDir, ...filePath]; const filename = path.join(...fullPath); if (fs.existsSync(filename)) { - const configText = fs.readFileSync(filename, { encoding: "utf-8" }); + const configText = readFile(filename); return { ...JSON.parse(configText), ...this.overrides }; } return null; diff --git a/app/server/tests/configReader.test.ts b/app/server/tests/configReader.test.ts index feae083b2..b31a771d9 100644 --- a/app/server/tests/configReader.test.ts +++ b/app/server/tests/configReader.test.ts @@ -3,7 +3,7 @@ import { ConfigReader } from "../src/configReader"; describe("configReader", () => { beforeEach(() => { - jest.resetAllMocks(); + jest.restoreAllMocks(); }); it("returns null when config not found", () => { @@ -31,4 +31,9 @@ describe("configReader", () => { expect(mockReadFileSync.mock.calls[0][0]).toBe("root/test.config"); expect(mockReadFileSync.mock.calls[0][1]).toStrictEqual({ encoding: "utf-8" }); }); + + it("copes with BOM markers", () => { + const res: any = new ConfigReader(__dirname).readConfigFile("examples/bom.json"); + expect((res as any).title).toBe("Ebola Project"); + }); }); diff --git a/app/server/tests/examples/bom.json b/app/server/tests/examples/bom.json new file mode 100644 index 000000000..69be7826a --- /dev/null +++ b/app/server/tests/examples/bom.json @@ -0,0 +1,6 @@ +{ + "appType": "fit", + "title": "Ebola Project", + "fitProp": "", + "readOnlyCode": false +}