From 48b36c45f98c2392795bf669432315be8aac0946 Mon Sep 17 00:00:00 2001 From: Kyle Hensel Date: Mon, 9 Dec 2024 16:25:16 +1100 Subject: [PATCH] fix(*): fix crash on node v18.0 caused by Import Attribute syntax --- dist/parse-args.js | 5 ++++- dist/parse-env-file.js | 4 ++-- dist/parse-rc-file.js | 4 ++-- dist/utils.d.ts | 1 + dist/utils.js | 6 ++++++ src/parse-args.ts | 8 +++++++- src/parse-env-file.ts | 4 ++-- src/parse-rc-file.ts | 4 ++-- src/utils.ts | 10 ++++++++++ 9 files changed, 36 insertions(+), 10 deletions(-) diff --git a/dist/parse-args.js b/dist/parse-args.js index 873f783..4c7a632 100644 --- a/dist/parse-args.js +++ b/dist/parse-args.js @@ -1,6 +1,9 @@ +import { createRequire } from 'node:module'; import { Command } from '@commander-js/extra-typings'; import { parseArgList } from './utils.js'; -import { default as packageJson } from '../package.json' with { type: 'json' }; +// TODO: once we drop support for node (value?: T | PromiseLike): value is PromiseLike; +export declare const importAttributesKeyword: string; diff --git a/dist/utils.js b/dist/utils.js index 7535a34..649629d 100644 --- a/dist/utils.js +++ b/dist/utils.js @@ -29,3 +29,9 @@ export function isPromise(value) { && 'then' in value && typeof value.then === 'function'; } +// "Import Attributes" are only supported since node v18.20 and v20.10. +// For older node versions, we have to use "Import Assertions". +// TODO: remove this check when we drop support for node v20 +const [major, minor] = process.version.slice(1).split('.').map(Number); +const legacyImportAssertions = (major === 18 && minor < 20) || (major === 20 && minor < 10); +export const importAttributesKeyword = legacyImportAssertions ? 'assert' : 'with'; diff --git a/src/parse-args.ts b/src/parse-args.ts index 981c7bc..8f0120c 100644 --- a/src/parse-args.ts +++ b/src/parse-args.ts @@ -1,7 +1,13 @@ +import { createRequire } from 'node:module' import { Command } from '@commander-js/extra-typings' import type { EnvCmdOptions, CommanderOptions, EnvFileOptions, RCFileOptions } from './types.ts' import { parseArgList } from './utils.js' -import { default as packageJson } from '../package.json' with { type: 'json' }; + +// TODO: once we drop support for node // For some reason in ES Modules, only JSON file types need to be specifically delinated when importing them let attributeTypes = {} if (ext === '.json') { - attributeTypes = { with: { type: 'json' } } + attributeTypes = { [importAttributesKeyword]: { type: 'json' } } } const res = await import(pathToFileURL(absolutePath).href, attributeTypes) as Environment | { default: Environment } if ('default' in res) { diff --git a/src/parse-rc-file.ts b/src/parse-rc-file.ts index 09ea9dd..f4bfa14 100644 --- a/src/parse-rc-file.ts +++ b/src/parse-rc-file.ts @@ -2,7 +2,7 @@ import { stat, readFile } from 'node:fs' import { promisify } from 'node:util' import { extname } from 'node:path' import { pathToFileURL } from 'node:url' -import { resolveEnvFilePath, IMPORT_HOOK_EXTENSIONS, isPromise } from './utils.js' +import { resolveEnvFilePath, IMPORT_HOOK_EXTENSIONS, isPromise, importAttributesKeyword } from './utils.js' import type { Environment, RCEnvironment } from './types.ts' const statAsync = promisify(stat) @@ -33,7 +33,7 @@ export async function getRCFileVars( // For some reason in ES Modules, only JSON file types need to be specifically delinated when importing them let attributeTypes = {} if (ext === '.json') { - attributeTypes = { with: { type: 'json' } } + attributeTypes = { [importAttributesKeyword]: { type: 'json' } } } const res = await import(pathToFileURL(absolutePath).href, attributeTypes) as RCEnvironment | { default: RCEnvironment } if ('default' in res) { diff --git a/src/utils.ts b/src/utils.ts index 466c483..2b005c1 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -32,3 +32,13 @@ export function isPromise(value?: T | PromiseLike): value is PromiseLike