initial (real) commit
This commit is contained in:
parent
7feaa19baa
commit
397888b4a8
@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"name": "ts-module-default",
|
"name": "@itsericwoodward/utils",
|
||||||
"version": "0.1.0",
|
"version": "0.1.0",
|
||||||
"description": "",
|
"description": "",
|
||||||
"main": "./lib/cjs/index.js",
|
"main": "./lib/cjs/index.js",
|
||||||
@ -24,12 +24,12 @@
|
|||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://git.itsericwoodward.com/eric/ts-npm-module-default.git"
|
"url": "https://git.itsericwoodward.com/eric/utils.git"
|
||||||
},
|
},
|
||||||
"bugs": {
|
"bugs": {
|
||||||
"url": "https://git.itsericwoodward.com/eric/ts-npm-module-default/issues"
|
"url": "https://git.itsericwoodward.com/eric/utils/issues"
|
||||||
},
|
},
|
||||||
"homepage": "https://git.itsericwoodward.com/eric/ts-npm-module-default#readme",
|
"homepage": "https://git.itsericwoodward.com/eric/utils#readme",
|
||||||
"keywords": [],
|
"keywords": [],
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@tsconfig/node20": "^20.1.2",
|
"@tsconfig/node20": "^20.1.2",
|
||||||
|
2
src/index.ts
Normal file
2
src/index.ts
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
export * from "./utils.js";
|
||||||
|
export { default as loadConfig } from "./loadConfig.js";
|
50
src/loadConfig.ts
Normal file
50
src/loadConfig.ts
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
import path from "path";
|
||||||
|
|
||||||
|
import {
|
||||||
|
convertCamelToUpperSnakeCase,
|
||||||
|
getDirname,
|
||||||
|
readJsonIfExists,
|
||||||
|
} from "./utils";
|
||||||
|
|
||||||
|
export default <T>(
|
||||||
|
opts: Partial<T>,
|
||||||
|
envKey: string,
|
||||||
|
localDefaultFilePath = ""
|
||||||
|
) => {
|
||||||
|
const { env } = process,
|
||||||
|
{ __dirname } = getDirname(),
|
||||||
|
def = readJsonIfExists(
|
||||||
|
path.join(__dirname, localDefaultFilePath || "./defaults.json5")
|
||||||
|
),
|
||||||
|
// gets value from ENV || options || defaults (in that order)
|
||||||
|
getVal = (envName: keyof T) => {
|
||||||
|
const snakeEnvName = `${envKey}_${convertCamelToUpperSnakeCase(
|
||||||
|
envName as string
|
||||||
|
)}`;
|
||||||
|
if (env[snakeEnvName]) return env[snakeEnvName];
|
||||||
|
if (opts[envName]) return opts[envName];
|
||||||
|
return def[envName];
|
||||||
|
},
|
||||||
|
// gets array from ENV || options || defaults (in that order)
|
||||||
|
getArray = (envName: keyof T, optName: keyof T | "" = "") => {
|
||||||
|
let newEnvName;
|
||||||
|
if (optName === "") {
|
||||||
|
optName = envName;
|
||||||
|
newEnvName = convertCamelToUpperSnakeCase(envName as string);
|
||||||
|
}
|
||||||
|
newEnvName = `${envKey}_${String(envName)}`;
|
||||||
|
if (env[newEnvName])
|
||||||
|
return env?.[newEnvName as keyof typeof env]?.split(path.delimiter);
|
||||||
|
if (Array.isArray(opts[optName]) && (opts[optName] as []).length)
|
||||||
|
return opts[optName];
|
||||||
|
return def[optName];
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
...Object.keys(def).reduce((acc: Partial<typeof def>, curr) => {
|
||||||
|
if (Array.isArray(def[curr])) acc[curr] = getArray(curr as keyof T);
|
||||||
|
else acc[curr] = getVal(curr as keyof T);
|
||||||
|
return acc;
|
||||||
|
}, {}),
|
||||||
|
};
|
||||||
|
};
|
67
src/utils.ts
Normal file
67
src/utils.ts
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
import chalk from "chalk";
|
||||||
|
import fs from "fs";
|
||||||
|
import json5 from "json5";
|
||||||
|
|
||||||
|
export interface ErrorWithCode {
|
||||||
|
code: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const convertCamelToUpperSnakeCase = (str: string) =>
|
||||||
|
str.replace(/[A-Z]/g, (letter) => `_${letter}`).toUpperCase();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* From: https://www.webmanajemen.com/2022/05/use-import-meta-cjs.html
|
||||||
|
*/
|
||||||
|
export const getDirname = () => {
|
||||||
|
// get the stack
|
||||||
|
const { stack } = new Error();
|
||||||
|
// get the third line (the original invoker)
|
||||||
|
const invokeFileLine = (stack || "").split(`\n`)[2];
|
||||||
|
// match the file url from file://(.+.(ts|js)) and get the first capturing group
|
||||||
|
const __filename = (invokeFileLine.match(/file:\/\/(.+.(ts|js))/) ||
|
||||||
|
[])[1].slice(1);
|
||||||
|
// match the file URL from file://(.+)/ and get the first capturing group
|
||||||
|
// the (.+) is a greedy quantifier and will make the RegExp expand to the largest match
|
||||||
|
const __dirname = (invokeFileLine.match(/file:\/\/(.+)\//) || [])[1].slice(1);
|
||||||
|
return { __dirname, __filename };
|
||||||
|
};
|
||||||
|
|
||||||
|
export const getTime = () => {
|
||||||
|
const now = new Date(),
|
||||||
|
tzo = -now.getTimezoneOffset(),
|
||||||
|
dif = tzo >= 0 ? "+" : "-",
|
||||||
|
pad = (num: number) => {
|
||||||
|
const norm = Math.floor(Math.abs(num));
|
||||||
|
return `${norm < 10 ? "0" : ""}${norm}`;
|
||||||
|
};
|
||||||
|
return [
|
||||||
|
now.getFullYear(),
|
||||||
|
"-",
|
||||||
|
pad(now.getMonth() + 1),
|
||||||
|
"-",
|
||||||
|
pad(now.getDate()),
|
||||||
|
"T",
|
||||||
|
pad(now.getHours()),
|
||||||
|
":",
|
||||||
|
pad(now.getMinutes()),
|
||||||
|
":",
|
||||||
|
pad(now.getSeconds()),
|
||||||
|
dif,
|
||||||
|
pad(tzo / 60),
|
||||||
|
":",
|
||||||
|
pad(tzo % 60),
|
||||||
|
].join("");
|
||||||
|
};
|
||||||
|
|
||||||
|
export const log = (...msg: unknown[]) =>
|
||||||
|
console.log(`${chalk.grey(`${getTime()}:`)} ${msg}`);
|
||||||
|
|
||||||
|
export const readJsonIfExists = (filePath: string | URL) => {
|
||||||
|
try {
|
||||||
|
return json5.parse(fs.readFileSync(filePath, { encoding: "utf8" }));
|
||||||
|
} catch (err) {
|
||||||
|
// if no file, return empty object
|
||||||
|
if ((err as ErrorWithCode)?.code === "ENOENT") return {};
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
|
};
|
@ -2,7 +2,7 @@
|
|||||||
"extends": "./tsconfig.json",
|
"extends": "./tsconfig.json",
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"module": "CommonJS",
|
"module": "CommonJS",
|
||||||
"moduleResolution": "Classic",
|
"moduleResolution": "Node10",
|
||||||
"outDir": "./lib/cjs"
|
"outDir": "./lib/cjs"
|
||||||
},
|
},
|
||||||
}
|
}
|
@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"extends": "@tsconfig/node18/tsconfig.json",
|
"extends": "@tsconfig/node20/tsconfig.json",
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
/* Visit https://aka.ms/tsconfig to read more about this file */
|
/* Visit https://aka.ms/tsconfig to read more about this file */
|
||||||
|
|
||||||
@ -9,7 +9,7 @@
|
|||||||
|
|
||||||
// values from https://github.com/tsconfig/bases#centralized-recommendations-for-tsconfig-bases
|
// values from https://github.com/tsconfig/bases#centralized-recommendations-for-tsconfig-bases
|
||||||
"module": "Node16",
|
"module": "Node16",
|
||||||
"moduleResolution": "node16",
|
"moduleResolution": "Node16",
|
||||||
|
|
||||||
"declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */
|
"declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */
|
||||||
"declarationMap": true, /* Create sourcemaps for d.ts files. */
|
"declarationMap": true, /* Create sourcemaps for d.ts files. */
|
||||||
|
Loading…
Reference in New Issue
Block a user