From bf13086752f818421ddd30e430b6e2fed706764b Mon Sep 17 00:00:00 2001 From: "Queen Vinyl Da.i'gyu-Kazotetsu" Date: Fri, 17 Jun 2022 14:09:05 -0700 Subject: [PATCH] Allow JSON imports in NodeJS 16.15 (#1792) * Allow JSON imports in NodeJS 16.15 * Update tests * Run formatter * tweak testing * fix Co-authored-by: Andrew Bradley --- .../node-internal-modules-esm-get_format.js | 1 + src/test/esm-loader.spec.ts | 64 ++++++++++--------- src/test/helpers.ts | 19 ++++-- 3 files changed, 49 insertions(+), 35 deletions(-) diff --git a/dist-raw/node-internal-modules-esm-get_format.js b/dist-raw/node-internal-modules-esm-get_format.js index 1f3586adf..e85e0ab49 100644 --- a/dist-raw/node-internal-modules-esm-get_format.js +++ b/dist-raw/node-internal-modules-esm-get_format.js @@ -12,6 +12,7 @@ const [nodeMajor, nodeMinor] = process.versions.node.split('.').map(s => parseIn const experimentalJsonModules = nodeMajor > 17 || (nodeMajor === 17 && nodeMinor >= 5) + || (nodeMajor === 16 && nodeMinor >= 15) || getOptionValue('--experimental-json-modules'); const experimentalWasmModules = getOptionValue('--experimental-wasm-modules'); const { URL, fileURLToPath } = require('url'); diff --git a/src/test/esm-loader.spec.ts b/src/test/esm-loader.spec.ts index 54242abff..41c421fd6 100644 --- a/src/test/esm-loader.spec.ts +++ b/src/test/esm-loader.spec.ts @@ -15,10 +15,13 @@ import { EXPERIMENTAL_MODULES_FLAG, nodeSupportsEsmHooks, nodeSupportsImportAssertions, + nodeSupportsUnflaggedJsonImports, nodeSupportsSpawningChildProcess, nodeUsesNewHooksApi, resetNodeEnvironment, TEST_DIR, + tsSupportsImportAssertions, + tsSupportsResolveJsonModule, } from './helpers'; import { createExec, createSpawn, ExecReturn } from './exec-helpers'; import { join, resolve } from 'path'; @@ -268,40 +271,39 @@ test.suite('esm', (test) => { }); test.suite('supports import assertions', (test) => { - test.runIf(nodeSupportsImportAssertions); - - test.suite('node >=17.5.0', (test) => { - test.runIf(semver.gte(process.version, '17.5.0')); + test.runIf( + nodeSupportsImportAssertions && + tsSupportsImportAssertions && + tsSupportsResolveJsonModule + ); - test('Can import JSON modules with appropriate assertion', async (t) => { - const { err, stdout } = await exec( - `${CMD_ESM_LOADER_WITHOUT_PROJECT} ./importJson.ts`, - { - cwd: resolve(TEST_DIR, 'esm-import-assertions'), - } - ); - expect(err).toBe(null); - expect(stdout.trim()).toBe( - 'A fuchsia car has 2 seats and the doors are open.\nDone!' - ); - }); + const macro = test.macro((flags: string) => async (t) => { + const { err, stdout } = await exec( + `${CMD_ESM_LOADER_WITHOUT_PROJECT} ${flags} ./importJson.ts`, + { + cwd: resolve(TEST_DIR, 'esm-import-assertions'), + } + ); + expect(err).toBe(null); + expect(stdout.trim()).toBe( + 'A fuchsia car has 2 seats and the doors are open.\nDone!' + ); }); - test.suite('node <17.5.0', (test) => { - test.runIf(semver.lt(process.version, '17.5.0')); - - test('Can import JSON using the appropriate flag and assertion', async (t) => { - const { err, stdout } = await exec( - `${CMD_ESM_LOADER_WITHOUT_PROJECT} --experimental-json-modules ./importJson.ts`, - { - cwd: resolve(TEST_DIR, 'esm-import-assertions'), - } - ); - expect(err).toBe(null); - expect(stdout.trim()).toBe( - 'A fuchsia car has 2 seats and the doors are open.\nDone!' - ); - }); + test.suite( + 'when node does not require --experimental-json-modules', + (test) => { + test.runIf(nodeSupportsUnflaggedJsonImports); + test('Can import JSON modules with appropriate assertion', macro, ''); + } + ); + test.suite('when node requires --experimental-json-modules', (test) => { + test.runIf(!nodeSupportsUnflaggedJsonImports); + test( + 'Can import JSON using the appropriate flag and assertion', + macro, + '--experimental-json-modules' + ); }); }); diff --git a/src/test/helpers.ts b/src/test/helpers.ts index 08392a29e..c4ea9e8a4 100644 --- a/src/test/helpers.ts +++ b/src/test/helpers.ts @@ -64,10 +64,19 @@ export const nodeSupportsSpawningChildProcess = semver.gte( '12.17.0' ); export const nodeUsesNewHooksApi = semver.gte(process.version, '16.12.0'); -export const nodeSupportsImportAssertions = semver.gte( - process.version, - '17.1.0' -); +// 16.14.0: https://github.com/nodejs/node/blob/main/doc/changelogs/CHANGELOG_V16.md#notable-changes-4 +// 17.1.0: https://github.com/nodejs/node/blob/main/doc/changelogs/CHANGELOG_V17.md#2021-11-09-version-1710-current-targos +export const nodeSupportsImportAssertions = + (semver.gte(process.version, '16.14.0') && + semver.lt(process.version, '17.0.0')) || + semver.gte(process.version, '17.1.0'); +// These versions do not require `--experimental-json-modules` +// 16.15.0: https://github.com/nodejs/node/blob/main/doc/changelogs/CHANGELOG_V16.md#2022-04-26-version-16150-gallium-lts-danielleadams +// 17.5.0: https://github.com/nodejs/node/blob/main/doc/changelogs/CHANGELOG_V17.md#2022-02-10-version-1750-current-ruyadorno +export const nodeSupportsUnflaggedJsonImports = + (semver.gte(process.version, '16.15.0') && + semver.lt(process.version, '17.0.0')) || + semver.gte(process.version, '17.5.0'); // Node 14.13.0 has a bug where it tries to lex CJS files to discover named exports *before* // we transform the code. // In other words, it tries to parse raw TS as CJS and balks at `export const foo =`, expecting to see `exports.foo =` @@ -76,6 +85,7 @@ export const nodeSupportsImportingTransformedCjsFromEsm = semver.gte( process.version, '14.13.1' ); +export const tsSupportsResolveJsonModule = semver.gte(ts.version, '2.9.0'); /** Supports tsconfig "extends" >= v3.2.0 */ export const tsSupportsTsconfigInheritanceViaNodePackages = semver.gte( ts.version, @@ -88,6 +98,7 @@ export const tsSupportsStableNodeNextNode16 = ts.version.startsWith('4.7.') || semver.gte(ts.version, '4.7.0'); // TS 4.5 is first version to understand .cts, .mts, .cjs, and .mjs extensions export const tsSupportsMtsCtsExtensions = semver.gte(ts.version, '4.5.0'); +export const tsSupportsImportAssertions = semver.gte(ts.version, '4.5.0'); //#endregion export const xfs = new NodeFS(fs);