feat(nodejs)!: remove v18 & < 20.10 support

added support for node 24
This commit is contained in:
Todd Bluhm 2025-07-02 00:53:04 -08:00
parent a08ac87f41
commit 33d0ac3461
No known key found for this signature in database
GPG Key ID: 9CF312607477B8AB
13 changed files with 15 additions and 41 deletions

View File

@ -11,7 +11,7 @@ jobs:
strategy:
matrix:
node-version: [18.x, 20.x, 22.x]
node-version: [20.x, 22.x, 24.x]
steps:
- name: Checkout Project

View File

@ -12,7 +12,7 @@ jobs:
strategy:
matrix:
node-version: [18.x, 20.x, 22.x]
node-version: [20.x, 22.x, 24.x]
steps:
- name: Checkout Project

5
dist/parse-args.js vendored
View File

@ -1,9 +1,6 @@
import { createRequire } from 'node:module';
import { Command } from '@commander-js/extra-typings';
import { parseArgList } from './utils.js';
// TODO: once we drop support for node <v20.10, this can be converted to
// a normal import statement
const packageJson = createRequire(import.meta.url)('../package.json');
import packageJson from '../package.json' with { type: 'json' };
/**
* Parses the arguments passed into the cli
*/

View File

@ -1,7 +1,7 @@
import { existsSync, readFileSync } from 'node:fs';
import { extname } from 'node:path';
import { pathToFileURL } from 'node:url';
import { resolveEnvFilePath, IMPORT_HOOK_EXTENSIONS, isPromise, importAttributesKeyword } from './utils.js';
import { resolveEnvFilePath, IMPORT_HOOK_EXTENSIONS, isPromise } from './utils.js';
/**
* Gets the environment vars from an env file
*/
@ -19,7 +19,7 @@ export async function getEnvFileVars(envFilePath) {
// For some reason in ES Modules, only JSON file types need to be specifically delinated when importing them
let attributeTypes = {};
if (ext === '.json') {
attributeTypes = { [importAttributesKeyword]: { type: 'json' } };
attributeTypes = { with: { type: 'json' } };
}
const res = await import(pathToFileURL(absolutePath).href, attributeTypes);
if (typeof res === 'object' && res && 'default' in res) {

View File

@ -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, importAttributesKeyword } from './utils.js';
import { resolveEnvFilePath, IMPORT_HOOK_EXTENSIONS, isPromise } from './utils.js';
const statAsync = promisify(stat);
const readFileAsync = promisify(readFile);
/**
@ -26,7 +26,7 @@ export async function getRCFileVars({ environments, filePath }) {
// For some reason in ES Modules, only JSON file types need to be specifically delinated when importing them
let attributeTypes = {};
if (ext === '.json') {
attributeTypes = { [importAttributesKeyword]: { type: 'json' } };
attributeTypes = { with: { type: 'json' } };
}
const res = await import(pathToFileURL(absolutePath).href, attributeTypes);
if ('default' in res) {

1
dist/utils.d.ts vendored
View File

@ -11,4 +11,3 @@ export declare function parseArgList(list: string): string[];
* A simple function to test if the value is a promise/thenable
*/
export declare function isPromise<T>(value?: T | PromiseLike<T>): value is PromiseLike<T>;
export declare const importAttributesKeyword: string;

6
dist/utils.js vendored
View File

@ -29,9 +29,3 @@ 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';

View File

@ -6,7 +6,7 @@
"types": "dist/index.d.ts",
"type": "module",
"engines": {
"node": ">=18.0.0"
"node": ">=20.10.0"
},
"bin": {
"env-cmd": "bin/env-cmd.js"

View File

@ -1,13 +1,7 @@
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'
// TODO: once we drop support for node <v20.10, this can be converted to
// a normal import statement
const packageJson = createRequire(import.meta.url)('../package.json') as {
version: string;
}
import packageJson from '../package.json' with { type: 'json' }
/**
* Parses the arguments passed into the cli

View File

@ -1,7 +1,7 @@
import { existsSync, readFileSync } from 'node:fs'
import { extname } from 'node:path'
import { pathToFileURL } from 'node:url'
import { resolveEnvFilePath, IMPORT_HOOK_EXTENSIONS, isPromise, importAttributesKeyword } from './utils.js'
import { resolveEnvFilePath, IMPORT_HOOK_EXTENSIONS, isPromise } from './utils.js'
import type { Environment } from './types.ts'
/**
@ -22,7 +22,7 @@ export async function getEnvFileVars(envFilePath: string): Promise<Environment>
// For some reason in ES Modules, only JSON file types need to be specifically delinated when importing them
let attributeTypes = {}
if (ext === '.json') {
attributeTypes = { [importAttributesKeyword]: { type: 'json' } }
attributeTypes = { with: { type: 'json' } }
}
const res: unknown = await import(pathToFileURL(absolutePath).href, attributeTypes)
if (typeof res === 'object' && res && 'default' in res) {

View File

@ -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, importAttributesKeyword } from './utils.js'
import { resolveEnvFilePath, IMPORT_HOOK_EXTENSIONS, isPromise } 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 = { [importAttributesKeyword]: { type: 'json' } }
attributeTypes = { with: { type: 'json' } }
}
const res = await import(pathToFileURL(absolutePath).href, attributeTypes) as RCEnvironment | { default: RCEnvironment }
if ('default' in res) {

View File

@ -32,13 +32,3 @@ export function isPromise<T>(value?: T | PromiseLike<T>): value is PromiseLike<T
&& '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'

View File

@ -1,9 +1,9 @@
{
"compilerOptions": {
"declaration": true,
"esModuleInterop": false,
"esModuleInterop": true,
"lib": ["es2023"],
"module": "NodeNext",
"module": "nodenext",
"moduleDetection": "force",
"outDir": "./dist",
"resolveJsonModule": true,