initial (real) commit

This commit is contained in:
Eric Woodward 2024-01-27 01:54:27 -05:00
parent 7feaa19baa
commit 397888b4a8
6 changed files with 126 additions and 7 deletions

View File

@ -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
View File

@ -0,0 +1,2 @@
export * from "./utils.js";
export { default as loadConfig } from "./loadConfig.js";

50
src/loadConfig.ts Normal file
View 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
View 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;
}
};

View File

@ -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"
}, },
} }

View File

@ -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. */