mirror of
https://github.com/toddbluhm/env-cmd.git
synced 2025-12-08 18:23:33 +00:00
feat: support loading TypeScript files
This commit is contained in:
parent
642c451d08
commit
b314da93c5
6
dist/get-env-vars.js
vendored
6
dist/get-env-vars.js
vendored
@ -1,5 +1,6 @@
|
||||
import { getRCFileVars } from './parse-rc-file.js';
|
||||
import { getEnvFileVars } from './parse-env-file.js';
|
||||
import { isLoaderError } from './utils.js';
|
||||
const RC_FILE_DEFAULT_LOCATIONS = ['./.env-cmdrc', './.env-cmdrc.js', './.env-cmdrc.json'];
|
||||
const ENV_FILE_DEFAULT_LOCATIONS = ['./.env', './.env.js', './.env.json'];
|
||||
export async function getEnvVars(options = {}) {
|
||||
@ -28,7 +29,10 @@ export async function getEnvFile({ filePath, fallback, verbose }) {
|
||||
}
|
||||
return env;
|
||||
}
|
||||
catch {
|
||||
catch (error) {
|
||||
if (isLoaderError(error)) {
|
||||
throw error;
|
||||
}
|
||||
if (verbose === true) {
|
||||
console.info(`Failed to find .env file at path: ${filePath}`);
|
||||
}
|
||||
|
||||
1
dist/loaders/typescript.d.ts
vendored
Normal file
1
dist/loaders/typescript.d.ts
vendored
Normal file
@ -0,0 +1 @@
|
||||
export declare function checkIfTypescriptSupported(): void;
|
||||
8
dist/loaders/typescript.js
vendored
Normal file
8
dist/loaders/typescript.js
vendored
Normal file
@ -0,0 +1,8 @@
|
||||
export function checkIfTypescriptSupported() {
|
||||
if (!process.features.typescript) {
|
||||
const error = new Error('To load typescript files with env-cmd, you need to upgrade to node v23.6' +
|
||||
' or later. See https://nodejs.org/en/learn/typescript/run-natively');
|
||||
Object.assign(error, { code: 'ERR_UNKNOWN_FILE_EXTENSION' });
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
3
dist/parse-env-file.js
vendored
3
dist/parse-env-file.js
vendored
@ -2,6 +2,7 @@ import { existsSync, readFileSync } from 'node:fs';
|
||||
import { extname } from 'node:path';
|
||||
import { pathToFileURL } from 'node:url';
|
||||
import { resolveEnvFilePath, IMPORT_HOOK_EXTENSIONS, isPromise } from './utils.js';
|
||||
import { checkIfTypescriptSupported } from './loaders/typescript.js';
|
||||
/**
|
||||
* Gets the environment vars from an env file
|
||||
*/
|
||||
@ -16,6 +17,8 @@ export async function getEnvFileVars(envFilePath) {
|
||||
const ext = extname(absolutePath).toLowerCase();
|
||||
let env;
|
||||
if (IMPORT_HOOK_EXTENSIONS.includes(ext)) {
|
||||
if (/tsx?$/.test(ext))
|
||||
checkIfTypescriptSupported();
|
||||
// For some reason in ES Modules, only JSON file types need to be specifically delinated when importing them
|
||||
let attributeTypes = {};
|
||||
if (ext === '.json') {
|
||||
|
||||
3
dist/parse-rc-file.js
vendored
3
dist/parse-rc-file.js
vendored
@ -3,6 +3,7 @@ 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 { checkIfTypescriptSupported } from './loaders/typescript.js';
|
||||
const statAsync = promisify(stat);
|
||||
const readFileAsync = promisify(readFile);
|
||||
/**
|
||||
@ -23,6 +24,8 @@ export async function getRCFileVars({ environments, filePath }) {
|
||||
let parsedData = {};
|
||||
try {
|
||||
if (IMPORT_HOOK_EXTENSIONS.includes(ext)) {
|
||||
if (/tsx?$/.test(ext))
|
||||
checkIfTypescriptSupported();
|
||||
// For some reason in ES Modules, only JSON file types need to be specifically delinated when importing them
|
||||
let attributeTypes = {};
|
||||
if (ext === '.json') {
|
||||
|
||||
2
dist/utils.d.ts
vendored
2
dist/utils.d.ts
vendored
@ -11,3 +11,5 @@ 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>;
|
||||
/** @returns true if the error is `ERR_UNKNOWN_FILE_EXTENSION` */
|
||||
export declare function isLoaderError(error: unknown): error is Error;
|
||||
|
||||
17
dist/utils.js
vendored
17
dist/utils.js
vendored
@ -2,7 +2,16 @@ import { resolve } from 'node:path';
|
||||
import { homedir } from 'node:os';
|
||||
import { cwd } from 'node:process';
|
||||
// Special file extensions that node can natively import
|
||||
export const IMPORT_HOOK_EXTENSIONS = ['.json', '.js', '.cjs', '.mjs'];
|
||||
export const IMPORT_HOOK_EXTENSIONS = [
|
||||
'.json',
|
||||
'.js',
|
||||
'.cjs',
|
||||
'.mjs',
|
||||
'.ts',
|
||||
'.mts',
|
||||
'.cts',
|
||||
'.tsx',
|
||||
];
|
||||
/**
|
||||
* A simple function for resolving the path the user entered
|
||||
*/
|
||||
@ -29,3 +38,9 @@ export function isPromise(value) {
|
||||
&& 'then' in value
|
||||
&& typeof value.then === 'function';
|
||||
}
|
||||
/** @returns true if the error is `ERR_UNKNOWN_FILE_EXTENSION` */
|
||||
export function isLoaderError(error) {
|
||||
return (error instanceof Error &&
|
||||
'code' in error &&
|
||||
error.code === 'ERR_UNKNOWN_FILE_EXTENSION');
|
||||
}
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
import type { GetEnvVarOptions, Environment } from './types.ts'
|
||||
import { getRCFileVars } from './parse-rc-file.js'
|
||||
import { getEnvFileVars } from './parse-env-file.js'
|
||||
import { isLoaderError } from './utils.js'
|
||||
|
||||
const RC_FILE_DEFAULT_LOCATIONS = ['./.env-cmdrc', './.env-cmdrc.js', './.env-cmdrc.json']
|
||||
const ENV_FILE_DEFAULT_LOCATIONS = ['./.env', './.env.js', './.env.json']
|
||||
@ -34,7 +35,11 @@ export async function getEnvFile(
|
||||
}
|
||||
return env
|
||||
}
|
||||
catch {
|
||||
catch (error) {
|
||||
if (isLoaderError(error)) {
|
||||
throw error
|
||||
}
|
||||
|
||||
if (verbose === true) {
|
||||
console.info(`Failed to find .env file at path: ${filePath}`)
|
||||
}
|
||||
|
||||
10
src/loaders/typescript.ts
Normal file
10
src/loaders/typescript.ts
Normal file
@ -0,0 +1,10 @@
|
||||
export function checkIfTypescriptSupported() {
|
||||
if (!process.features.typescript) {
|
||||
const error = new Error(
|
||||
'To load typescript files with env-cmd, you need to upgrade to node v23.6' +
|
||||
' or later. See https://nodejs.org/en/learn/typescript/run-natively',
|
||||
);
|
||||
Object.assign(error, { code: 'ERR_UNKNOWN_FILE_EXTENSION' });
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
@ -3,6 +3,7 @@ import { extname } from 'node:path'
|
||||
import { pathToFileURL } from 'node:url'
|
||||
import { resolveEnvFilePath, IMPORT_HOOK_EXTENSIONS, isPromise } from './utils.js'
|
||||
import type { Environment } from './types.ts'
|
||||
import { checkIfTypescriptSupported } from './loaders/typescript.js'
|
||||
|
||||
/**
|
||||
* Gets the environment vars from an env file
|
||||
@ -19,6 +20,8 @@ export async function getEnvFileVars(envFilePath: string): Promise<Environment>
|
||||
const ext = extname(absolutePath).toLowerCase()
|
||||
let env: unknown;
|
||||
if (IMPORT_HOOK_EXTENSIONS.includes(ext)) {
|
||||
if (/tsx?$/.test(ext)) checkIfTypescriptSupported();
|
||||
|
||||
// For some reason in ES Modules, only JSON file types need to be specifically delinated when importing them
|
||||
let attributeTypes = {}
|
||||
if (ext === '.json') {
|
||||
|
||||
@ -4,6 +4,7 @@ import { extname } from 'node:path'
|
||||
import { pathToFileURL } from 'node:url'
|
||||
import { resolveEnvFilePath, IMPORT_HOOK_EXTENSIONS, isPromise } from './utils.js'
|
||||
import type { Environment, RCEnvironment } from './types.ts'
|
||||
import { checkIfTypescriptSupported } from './loaders/typescript.js'
|
||||
|
||||
const statAsync = promisify(stat)
|
||||
const readFileAsync = promisify(readFile)
|
||||
@ -30,6 +31,8 @@ export async function getRCFileVars(
|
||||
let parsedData: Partial<RCEnvironment> = {}
|
||||
try {
|
||||
if (IMPORT_HOOK_EXTENSIONS.includes(ext)) {
|
||||
if (/tsx?$/.test(ext)) checkIfTypescriptSupported()
|
||||
|
||||
// For some reason in ES Modules, only JSON file types need to be specifically delinated when importing them
|
||||
let attributeTypes = {}
|
||||
if (ext === '.json') {
|
||||
|
||||
20
src/utils.ts
20
src/utils.ts
@ -3,7 +3,16 @@ import { homedir } from 'node:os'
|
||||
import { cwd } from 'node:process'
|
||||
|
||||
// Special file extensions that node can natively import
|
||||
export const IMPORT_HOOK_EXTENSIONS = ['.json', '.js', '.cjs', '.mjs']
|
||||
export const IMPORT_HOOK_EXTENSIONS = [
|
||||
'.json',
|
||||
'.js',
|
||||
'.cjs',
|
||||
'.mjs',
|
||||
'.ts',
|
||||
'.mts',
|
||||
'.cts',
|
||||
'.tsx',
|
||||
];
|
||||
|
||||
/**
|
||||
* A simple function for resolving the path the user entered
|
||||
@ -32,3 +41,12 @@ export function isPromise<T>(value?: T | PromiseLike<T>): value is PromiseLike<T
|
||||
&& 'then' in value
|
||||
&& typeof value.then === 'function'
|
||||
}
|
||||
|
||||
/** @returns true if the error is `ERR_UNKNOWN_FILE_EXTENSION` */
|
||||
export function isLoaderError(error: unknown): error is Error {
|
||||
return (
|
||||
error instanceof Error &&
|
||||
'code' in error &&
|
||||
error.code === 'ERR_UNKNOWN_FILE_EXTENSION'
|
||||
);
|
||||
}
|
||||
|
||||
@ -192,6 +192,32 @@ describe('getEnvFileVars', (): void => {
|
||||
THANKS: 'FOR ALL THE FISH',
|
||||
ANSWER: '0',
|
||||
})
|
||||
});
|
||||
|
||||
(process.features.typescript ? describe : describe.skip)('TS', () => {
|
||||
it('should parse a .ts file', async () => {
|
||||
const env = await getEnvFileVars('./test/test-files/ts-test.ts');
|
||||
assert.deepEqual(env, {
|
||||
THANKS: 'FOR ALL THE FISH',
|
||||
ANSWER: '1',
|
||||
});
|
||||
});
|
||||
|
||||
it('should parse a .cts file', async () => {
|
||||
const env = await getEnvFileVars('./test/test-files/cts-test.cts');
|
||||
assert.deepEqual(env, {
|
||||
THANKS: 'FOR ALL THE FISH',
|
||||
ANSWER: '0',
|
||||
});
|
||||
});
|
||||
|
||||
it('should parse a .tsx file', async () => {
|
||||
const env = await getEnvFileVars('./test/test-files/tsx-test.tsx');
|
||||
assert.deepEqual(env, {
|
||||
THANKS: 'FOR ALL THE FISH',
|
||||
ANSWER: '2',
|
||||
});
|
||||
});
|
||||
})
|
||||
|
||||
it('should parse an env file', async (): Promise<void> => {
|
||||
|
||||
5
test/test-files/cts-test.cts
Normal file
5
test/test-files/cts-test.cts
Normal file
@ -0,0 +1,5 @@
|
||||
const env: unknown = {
|
||||
THANKS: 'FOR ALL THE FISH',
|
||||
ANSWER: 0,
|
||||
};
|
||||
export default env;
|
||||
7
test/test-files/ts-test.ts
Normal file
7
test/test-files/ts-test.ts
Normal file
@ -0,0 +1,7 @@
|
||||
import type { Environment } from '../../src/types.js';
|
||||
|
||||
const env: Environment = {
|
||||
THANKS: 'FOR ALL THE FISH',
|
||||
ANSWER: 1,
|
||||
};
|
||||
export default env;
|
||||
8
test/test-files/tsx-test.tsx
Normal file
8
test/test-files/tsx-test.tsx
Normal file
@ -0,0 +1,8 @@
|
||||
import type { Environment } from '../../src/types.js';
|
||||
|
||||
const env: Environment = {
|
||||
THANKS: 'FOR ALL THE FISH',
|
||||
ANSWER: 2,
|
||||
};
|
||||
|
||||
export default env;
|
||||
Loading…
x
Reference in New Issue
Block a user