@incanta/config
Advanced tools
Comparing version 0.3.0 to 0.3.1
@@ -39,8 +39,12 @@ "use strict"; | ||
path_1.default.join(process.cwd(), defaultConfigDir); | ||
const defaultValues = loader_1.Loader.load(path_1.default.join(this.configDir, "default")); | ||
const configEnvDir = options?.configEnv || process.env["NODE_CONFIG_ENV"] || defaultConfigEnv; | ||
const configFolderOptions = loader_1.Loader.readConfigSettings(path_1.default.join(this.configDir, configEnvDir)); | ||
const defaultValues = loader_1.Loader.loadRoot(path_1.default.join(this.configDir, "default"), { | ||
...configFolderOptions, | ||
parentNames: [], | ||
}); | ||
let envValues = {}; | ||
const configEnvDir = options?.configEnv || process.env["NODE_CONFIG_ENV"] || defaultConfigEnv; | ||
if (configEnvDir) { | ||
if (fs_1.default.existsSync(path_1.default.join(this.configDir, configEnvDir))) { | ||
envValues = loader_1.Loader.load(path_1.default.join(this.configDir, configEnvDir)); | ||
envValues = loader_1.Loader.loadRoot(path_1.default.join(this.configDir, configEnvDir), configFolderOptions); | ||
} | ||
@@ -51,3 +55,3 @@ else { | ||
} | ||
const overrideValues = loader_1.Loader.loadFile(path_1.default.join(this.configDir, "override.json")); | ||
const overrideValues = loader_1.Loader.loadFile(path_1.default.join(this.configDir, "override.json"), {}); | ||
(0, lodash_merge_1.default)(this.values, defaultValues, envValues, overrideValues); | ||
@@ -60,3 +64,3 @@ // load the environment variables that are configured to be injected | ||
if (file.startsWith("environment.")) { | ||
this.envVarConfig = loader_1.Loader.loadFile(path_1.default.join(this.configDir, file)); | ||
this.envVarConfig = loader_1.Loader.loadFile(path_1.default.join(this.configDir, file), {}); | ||
break; | ||
@@ -89,6 +93,10 @@ } | ||
for (const part of keyParts) { | ||
if (typeof obj[part] === "undefined") { | ||
// convert to camelCase first | ||
const newPart = part.replace(/-([a-zA-Z0-9])/g, function (_, match) { | ||
return match.toUpperCase(); | ||
}); | ||
if (typeof obj[newPart] === "undefined") { | ||
throw new Error(`Could not find value for key ${keyParts.join(".")}`); | ||
} | ||
obj = obj[part]; | ||
obj = obj[newPart]; | ||
} | ||
@@ -95,0 +103,0 @@ const variableRegex = /\$\{[a-zA-Z\-_0-9./]+\}/g; |
@@ -1,9 +0,12 @@ | ||
export interface IConfigOptions { | ||
export interface IConfigFolderOptions { | ||
keepKebabCase?: boolean; | ||
parentNames?: string[]; | ||
} | ||
export declare class Loader { | ||
static convertKebabToCamelCase(obj: any): any; | ||
static loadFile(filePath: string): any; | ||
static load(folder: string): any; | ||
static readConfigSettings(folder: string): IConfigFolderOptions; | ||
static convertKebabToCamelCase(obj: any, options: IConfigFolderOptions): any; | ||
static loadFile(filePath: string, options: IConfigFolderOptions): any; | ||
static loadRoot(folder: string, options: IConfigFolderOptions): any; | ||
static load(folder: string, options: IConfigFolderOptions): any; | ||
} | ||
//# sourceMappingURL=loader.d.ts.map |
@@ -14,17 +14,44 @@ "use strict"; | ||
class Loader { | ||
static readConfigSettings(folder) { | ||
let options = {}; | ||
const configFiles = ["_config.json", "config.json"]; | ||
for (const configFile of configFiles) { | ||
if (fs_1.default.existsSync(path_1.default.join(folder, configFile))) { | ||
try { | ||
options = JSON.parse(fs_1.default.readFileSync(path_1.default.join(folder, configFile), { | ||
encoding: "utf-8", | ||
})); | ||
break; | ||
} | ||
catch (e) { | ||
console.error(`Invalid JSON in ${path_1.default.join(folder, configFile)} file; skipping configuration`); | ||
break; | ||
} | ||
} | ||
} | ||
return options; | ||
} | ||
// add additional camelCase keys for any kebab-case keys (without overwriting existing keys) | ||
static convertKebabToCamelCase(obj) { | ||
static convertKebabToCamelCase(obj, options) { | ||
const newObj = {}; | ||
for (const key of Object.keys(obj)) { | ||
const newKey = key.replace(/-([a-zA-Z0-9])/g, function (_, match) { | ||
return match.toUpperCase(); | ||
}); | ||
if (typeof obj[newKey] !== "undefined" && newKey !== key) { | ||
console.error(`Key ${newKey} already exists in object, but ${key} was also defined, skipping ${key}`); | ||
continue; | ||
} | ||
let newSubObj = {}; | ||
if (typeof obj[key] === "object" && | ||
!Array.isArray(obj[key]) && | ||
obj[key] !== null) { | ||
newObj[key] = Loader.convertKebabToCamelCase(obj[key]); | ||
newSubObj = Loader.convertKebabToCamelCase(obj[key], options); | ||
} | ||
else if (Array.isArray(obj[key])) { | ||
newObj[key] = obj[key].map((item) => { | ||
newSubObj = obj[key].map((item) => { | ||
if (typeof item === "object" && | ||
!Array.isArray(item) && | ||
item !== null) { | ||
return Loader.convertKebabToCamelCase(item); | ||
return Loader.convertKebabToCamelCase(item, options); | ||
} | ||
@@ -37,9 +64,7 @@ else { | ||
else { | ||
newObj[key] = obj[key]; | ||
newSubObj = obj[key]; | ||
} | ||
const newKey = key.replace(/-([a-zA-Z0-9])/g, function (_, match) { | ||
return match.toUpperCase(); | ||
}); | ||
if (newKey !== key) { | ||
newObj[newKey] = newObj[key]; | ||
newObj[newKey] = newSubObj; | ||
if (options.keepKebabCase === true && newKey !== key) { | ||
newObj[key] = newSubObj; | ||
} | ||
@@ -49,3 +74,3 @@ } | ||
} | ||
static loadFile(filePath) { | ||
static loadFile(filePath, options) { | ||
if (!fs_1.default.existsSync(filePath)) { | ||
@@ -81,7 +106,21 @@ return {}; | ||
if (typeof obj === "object" && obj !== null && !Array.isArray(obj)) { | ||
obj = Loader.convertKebabToCamelCase(obj); | ||
obj = Loader.convertKebabToCamelCase(obj, options); | ||
} | ||
return obj; | ||
} | ||
static load(folder) { | ||
static loadRoot(folder, options) { | ||
const baseObj = {}; | ||
if (options.parentNames) { | ||
for (const parentName of options.parentNames) { | ||
if (parentName === "default") { | ||
// skip explicitly stated default parents; they're already loaded | ||
continue; | ||
} | ||
(0, lodash_merge_1.default)(baseObj, Loader.load(path_1.default.join(folder, "..", parentName), options)); | ||
} | ||
} | ||
(0, lodash_merge_1.default)(baseObj, Loader.load(folder, options)); | ||
return baseObj; | ||
} | ||
static load(folder, options) { | ||
if (!fs_1.default.existsSync(folder)) { | ||
@@ -91,26 +130,2 @@ return {}; | ||
const baseObj = {}; | ||
const configFiles = ["_config.json", "config.json"]; | ||
for (const configFile of configFiles) { | ||
if (fs_1.default.existsSync(path_1.default.join(folder, configFile))) { | ||
try { | ||
const folderConfig = JSON.parse(fs_1.default.readFileSync(path_1.default.join(folder, configFile), { | ||
encoding: "utf-8", | ||
})); | ||
if (folderConfig.parentNames) { | ||
for (const parentName of folderConfig.parentNames) { | ||
if (parentName === "default") { | ||
// skip explicitly stated default parents; they're already loaded | ||
continue; | ||
} | ||
(0, lodash_merge_1.default)(baseObj, Loader.load(path_1.default.join(folder, "..", parentName))); | ||
} | ||
} | ||
break; | ||
} | ||
catch (e) { | ||
console.error(`Invalid JSON in ${path_1.default.join(folder, configFile)} file; skipping configuration`); | ||
break; | ||
} | ||
} | ||
} | ||
const contents = fs_1.default.readdirSync(folder, { | ||
@@ -123,3 +138,3 @@ encoding: "utf-8", | ||
if (!content.isDirectory() && /^_?index\./.exec(content.name) !== null) { | ||
(0, lodash_merge_1.default)(baseObj, Loader.loadFile(path_1.default.join(folder, content.name))); | ||
(0, lodash_merge_1.default)(baseObj, Loader.loadFile(path_1.default.join(folder, content.name), options)); | ||
} | ||
@@ -138,3 +153,3 @@ } | ||
} | ||
const obj = Loader.load(path_1.default.join(folder, content.name)); | ||
const obj = Loader.load(path_1.default.join(folder, content.name), options); | ||
(0, lodash_merge_1.default)(baseObj[key], obj); | ||
@@ -153,3 +168,3 @@ } | ||
} | ||
const obj = Loader.loadFile(path_1.default.join(folder, content.name)); | ||
const obj = Loader.loadFile(path_1.default.join(folder, content.name), options); | ||
(0, lodash_merge_1.default)(baseObj[key], obj); | ||
@@ -156,0 +171,0 @@ } |
{ | ||
"name": "@incanta/config", | ||
"version": "0.3.0", | ||
"version": "0.3.1", | ||
"main": "lib/index.js", | ||
@@ -5,0 +5,0 @@ "exports": { |
@@ -54,10 +54,24 @@ import merge from "lodash.merge"; | ||
const defaultValues = Loader.load(path.join(this.configDir, "default")); | ||
const configEnvDir = | ||
options?.configEnv || process.env["NODE_CONFIG_ENV"] || defaultConfigEnv; | ||
const configFolderOptions = Loader.readConfigSettings( | ||
path.join(this.configDir, configEnvDir) | ||
); | ||
const defaultValues = Loader.loadRoot( | ||
path.join(this.configDir, "default"), | ||
{ | ||
...configFolderOptions, | ||
parentNames: [], | ||
} | ||
); | ||
let envValues: any = {}; | ||
const configEnvDir = | ||
options?.configEnv || process.env["NODE_CONFIG_ENV"] || defaultConfigEnv; | ||
if (configEnvDir) { | ||
if (fs.existsSync(path.join(this.configDir, configEnvDir))) { | ||
envValues = Loader.load(path.join(this.configDir, configEnvDir)); | ||
envValues = Loader.loadRoot( | ||
path.join(this.configDir, configEnvDir), | ||
configFolderOptions | ||
); | ||
} else { | ||
@@ -74,3 +88,4 @@ console.log( | ||
const overrideValues = Loader.loadFile( | ||
path.join(this.configDir, "override.json") | ||
path.join(this.configDir, "override.json"), | ||
{} | ||
); | ||
@@ -86,3 +101,6 @@ | ||
if (file.startsWith("environment.")) { | ||
this.envVarConfig = Loader.loadFile(path.join(this.configDir, file)); | ||
this.envVarConfig = Loader.loadFile( | ||
path.join(this.configDir, file), | ||
{} | ||
); | ||
break; | ||
@@ -125,7 +143,12 @@ } | ||
for (const part of keyParts) { | ||
if (typeof obj[part] === "undefined") { | ||
// convert to camelCase first | ||
const newPart = part.replace(/-([a-zA-Z0-9])/g, function (_, match) { | ||
return match.toUpperCase(); | ||
}); | ||
if (typeof obj[newPart] === "undefined") { | ||
throw new Error(`Could not find value for key ${keyParts.join(".")}`); | ||
} | ||
obj = obj[part]; | ||
obj = obj[newPart]; | ||
} | ||
@@ -132,0 +155,0 @@ |
@@ -8,3 +8,4 @@ import fs from "fs"; | ||
export interface IConfigOptions { | ||
export interface IConfigFolderOptions { | ||
keepKebabCase?: boolean; | ||
parentNames?: string[]; | ||
@@ -14,7 +15,51 @@ } | ||
export class Loader { | ||
public static readConfigSettings(folder: string): IConfigFolderOptions { | ||
let options: IConfigFolderOptions = {}; | ||
const configFiles = ["_config.json", "config.json"]; | ||
for (const configFile of configFiles) { | ||
if (fs.existsSync(path.join(folder, configFile))) { | ||
try { | ||
options = JSON.parse( | ||
fs.readFileSync(path.join(folder, configFile), { | ||
encoding: "utf-8", | ||
}) | ||
); | ||
break; | ||
} catch (e: any) { | ||
console.error( | ||
`Invalid JSON in ${path.join( | ||
folder, | ||
configFile | ||
)} file; skipping configuration` | ||
); | ||
break; | ||
} | ||
} | ||
} | ||
return options; | ||
} | ||
// add additional camelCase keys for any kebab-case keys (without overwriting existing keys) | ||
public static convertKebabToCamelCase(obj: any): any { | ||
public static convertKebabToCamelCase( | ||
obj: any, | ||
options: IConfigFolderOptions | ||
): any { | ||
const newObj: any = {}; | ||
for (const key of Object.keys(obj)) { | ||
const newKey = key.replace(/-([a-zA-Z0-9])/g, function (_, match) { | ||
return match.toUpperCase(); | ||
}); | ||
if (typeof obj[newKey] !== "undefined" && newKey !== key) { | ||
console.error( | ||
`Key ${newKey} already exists in object, but ${key} was also defined, skipping ${key}` | ||
); | ||
continue; | ||
} | ||
let newSubObj: any = {}; | ||
if ( | ||
@@ -25,5 +70,5 @@ typeof obj[key] === "object" && | ||
) { | ||
newObj[key] = Loader.convertKebabToCamelCase(obj[key]); | ||
newSubObj = Loader.convertKebabToCamelCase(obj[key], options); | ||
} else if (Array.isArray(obj[key])) { | ||
newObj[key] = obj[key].map((item: any) => { | ||
newSubObj = obj[key].map((item: any) => { | ||
if ( | ||
@@ -34,3 +79,3 @@ typeof item === "object" && | ||
) { | ||
return Loader.convertKebabToCamelCase(item); | ||
return Loader.convertKebabToCamelCase(item, options); | ||
} else { | ||
@@ -41,11 +86,9 @@ return item; | ||
} else { | ||
newObj[key] = obj[key]; | ||
newSubObj = obj[key]; | ||
} | ||
const newKey = key.replace(/-([a-zA-Z0-9])/g, function (_, match) { | ||
return match.toUpperCase(); | ||
}); | ||
newObj[newKey] = newSubObj; | ||
if (newKey !== key) { | ||
newObj[newKey] = newObj[key]; | ||
if (options.keepKebabCase === true && newKey !== key) { | ||
newObj[key] = newSubObj; | ||
} | ||
@@ -57,3 +100,3 @@ } | ||
public static loadFile(filePath: string): any { | ||
public static loadFile(filePath: string, options: IConfigFolderOptions): any { | ||
if (!fs.existsSync(filePath)) { | ||
@@ -91,3 +134,3 @@ return {}; | ||
if (typeof obj === "object" && obj !== null && !Array.isArray(obj)) { | ||
obj = Loader.convertKebabToCamelCase(obj); | ||
obj = Loader.convertKebabToCamelCase(obj, options); | ||
} | ||
@@ -98,43 +141,30 @@ | ||
public static load(folder: string): any { | ||
if (!fs.existsSync(folder)) { | ||
return {}; | ||
} | ||
public static loadRoot(folder: string, options: IConfigFolderOptions): any { | ||
const baseObj: any = {}; | ||
const configFiles = ["_config.json", "config.json"]; | ||
for (const configFile of configFiles) { | ||
if (fs.existsSync(path.join(folder, configFile))) { | ||
try { | ||
const folderConfig: IConfigOptions = JSON.parse( | ||
fs.readFileSync(path.join(folder, configFile), { | ||
encoding: "utf-8", | ||
}) | ||
); | ||
if (options.parentNames) { | ||
for (const parentName of options.parentNames) { | ||
if (parentName === "default") { | ||
// skip explicitly stated default parents; they're already loaded | ||
continue; | ||
} | ||
merge( | ||
baseObj, | ||
Loader.load(path.join(folder, "..", parentName), options) | ||
); | ||
} | ||
} | ||
if (folderConfig.parentNames) { | ||
for (const parentName of folderConfig.parentNames) { | ||
if (parentName === "default") { | ||
// skip explicitly stated default parents; they're already loaded | ||
continue; | ||
} | ||
merge(baseObj, Loader.load(path.join(folder, "..", parentName))); | ||
} | ||
} | ||
merge(baseObj, Loader.load(folder, options)); | ||
break; | ||
} catch (e: any) { | ||
console.error( | ||
`Invalid JSON in ${path.join( | ||
folder, | ||
configFile | ||
)} file; skipping configuration` | ||
); | ||
return baseObj; | ||
} | ||
break; | ||
} | ||
} | ||
public static load(folder: string, options: IConfigFolderOptions): any { | ||
if (!fs.existsSync(folder)) { | ||
return {}; | ||
} | ||
const baseObj: any = {}; | ||
const contents = fs.readdirSync(folder, { | ||
@@ -148,3 +178,6 @@ encoding: "utf-8", | ||
if (!content.isDirectory() && /^_?index\./.exec(content.name) !== null) { | ||
merge(baseObj, Loader.loadFile(path.join(folder, content.name))); | ||
merge( | ||
baseObj, | ||
Loader.loadFile(path.join(folder, content.name), options) | ||
); | ||
} | ||
@@ -167,3 +200,3 @@ } | ||
const obj = Loader.load(path.join(folder, content.name)); | ||
const obj = Loader.load(path.join(folder, content.name), options); | ||
@@ -185,3 +218,3 @@ merge(baseObj[key], obj); | ||
const obj = Loader.loadFile(path.join(folder, content.name)); | ||
const obj = Loader.loadFile(path.join(folder, content.name), options); | ||
@@ -188,0 +221,0 @@ merge(baseObj[key], obj); |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
45274
823