diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 6f8ca9a..47239bb 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -11,6 +11,7 @@ env: TEST_ROOT_DATABASE_URL: postgres://postgres:postgres@127.0.0.1:5432/postgres TEST_DATABASE_URL: postgres://someone:something@127.0.0.1:5432/graphile_migrate_test PGVERSION: 10 + NODE_OPTIONS: "--experimental-vm-modules" jobs: test: diff --git a/__tests__/settings.test.ts b/__tests__/settings.test.ts index 801d975..5d71a55 100644 --- a/__tests__/settings.test.ts +++ b/__tests__/settings.test.ts @@ -3,7 +3,12 @@ import "./helpers"; // Side effects - must come first import mockFs from "mock-fs"; import * as path from "path"; -import { DEFAULT_GMRC_PATH, getSettings } from "../src/commands/_common"; +import { + DEFAULT_GMRC_COMMONJS_PATH, + DEFAULT_GMRC_PATH, + DEFAULT_GMRCJS_PATH, + getSettings, +} from "../src/commands/_common"; import { makeRootDatabaseConnectionString, ParsedSettings, @@ -342,3 +347,48 @@ describe("gmrc path", () => { mockFs.restore(); }); }); + +describe("gmrc from JS", () => { + const nodeMajor = parseInt(process.versions.node.split(".")[0], 10); + // Only test these on Node20+ + const node20PlusIt = nodeMajor >= 20 ? it : it.skip.bind(it); + node20PlusIt("supports .gmrc.js", async () => { + mockFs.restore(); + // The warmups force all the parts of Node import to be exercised before we + // try and import something from our mocked filesystem. + // @ts-ignore + await Promise.all([import("./warmup.js"), import("./warmup.cjs")]); + + mockFs({ + [DEFAULT_GMRCJS_PATH]: /* JavaScript */ `\ +module.exports = { + connectionString: "postgres://appuser:apppassword@host:5432/gmrcjs_test", +};`, + }); + const settings = await getSettings(); + expect(settings.connectionString).toEqual( + "postgres://appuser:apppassword@host:5432/gmrcjs_test", + ); + mockFs.restore(); + }); + + node20PlusIt("supports .gmrc.cjs", async () => { + mockFs.restore(); + // The warmups force all the parts of Node import to be exercised before we + // try and import something from our mocked filesystem. + // @ts-ignore + await Promise.all([import("./warmup.js"), import("./warmup.cjs")]); + + mockFs({ + [DEFAULT_GMRC_COMMONJS_PATH]: /* JavaScript */ `\ +module.exports = { + connectionString: "postgres://appuser:apppassword@host:5432/gmrc_commonjs_test", +};`, + }); + const settings = await getSettings(); + expect(settings.connectionString).toEqual( + "postgres://appuser:apppassword@host:5432/gmrc_commonjs_test", + ); + mockFs.restore(); + }); +}); diff --git a/__tests__/warmup.cjs b/__tests__/warmup.cjs new file mode 100644 index 0000000..f053ebf --- /dev/null +++ b/__tests__/warmup.cjs @@ -0,0 +1 @@ +module.exports = {}; diff --git a/__tests__/warmup.js b/__tests__/warmup.js new file mode 100644 index 0000000..f053ebf --- /dev/null +++ b/__tests__/warmup.js @@ -0,0 +1 @@ +module.exports = {}; diff --git a/package.json b/package.json index 3c641b3..907ccd0 100644 --- a/package.json +++ b/package.json @@ -12,7 +12,7 @@ "prepack": "npm run tsc && chmod +x dist/cli.js", "clean": "rm -Rf dist", "test": "yarn lint && yarn run lint:deps && FORCE_COLOR=1 yarn run test:only --ci", - "test:only": "jest -i", + "test:only": "NODE_OPTIONS=\"--experimental-vm-modules\" jest -i", "version": "yarn prepack && ./scripts/update-docs.js && node ./scripts/version.mjs && git add README.md src/version.ts", "watch": "mkdir -p dist && touch dist/cli.js && chmod +x dist/cli.js && npm run tsc --watch" }, diff --git a/src/commands/_common.ts b/src/commands/_common.ts index bfd7f41..958a9ce 100644 --- a/src/commands/_common.ts +++ b/src/commands/_common.ts @@ -77,7 +77,8 @@ export async function getSettings(options: Options = {}): Promise { const relativePath = pathToFileURL(resolve(process.cwd(), path)).href; try { - return (await import(relativePath)) as Settings; + const module = (await import(relativePath)) as Record; + return (module.default ?? module) as Settings; } catch (e) { throw new Error( `Failed to import '${relativePath}'; error:\n ${