Comparing version 12.1.0 to 12.1.1
@@ -72,3 +72,3 @@ import { Class, JsonObject, JsonValue } from "../helpers/custom-types"; | ||
private static readonly _fileCandidates; | ||
constructor(config?: JsonObject); | ||
constructor(config?: JsonObject | string); | ||
/** | ||
@@ -75,0 +75,0 @@ * an array of plugin filenames (these must also match the lowercase plugin class name minus |
@@ -74,3 +74,16 @@ "use strict"; | ||
constructor(config) { | ||
this._cfg = config; | ||
dotenv.config(); | ||
try { | ||
if (typeof config === 'string') { | ||
const processedConfigStr = this.processEnvVars(config); | ||
this._cfg = JSON.parse(processedConfigStr); | ||
} | ||
else if (typeof config === 'object') { | ||
this._cfg = config; | ||
} | ||
} | ||
catch (e) { | ||
console.warn(`[${this.constructor.name}] - WARN `, // eslint-disable-line no-undef | ||
'- error processing passed in config argument', 'falling back to config file load...', e); | ||
} | ||
if (!this._cfg) { | ||
@@ -81,3 +94,2 @@ this._cfg = this._loadConfigFile(); | ||
this._sectionCache = new Map(); | ||
dotenv.config(); | ||
} | ||
@@ -268,11 +280,15 @@ /** | ||
processEnvVars(input) { | ||
var _a, _b, _c; | ||
if (input && typeof input === 'string') { | ||
const regx = /^%(.*)%$/; | ||
if (((_b = (_a = input === null || input === void 0 ? void 0 : input.match(regx)) === null || _a === void 0 ? void 0 : _a.length) !== null && _b !== void 0 ? _b : 0) > 0) { | ||
const envVarKey = (_c = input.match(regx)) === null || _c === void 0 ? void 0 : _c[1]; | ||
var _a; | ||
if (input == null || typeof input !== 'string') { | ||
return input; | ||
} | ||
let output = input; | ||
const regx = /%([^\W]+)%/gm; | ||
for (const match of input === null || input === void 0 ? void 0 : input.matchAll(regx)) { // eslint-disable-line no-unsafe-optional-chaining | ||
if (((_a = match === null || match === void 0 ? void 0 : match.length) !== null && _a !== void 0 ? _a : 0) > 0) { | ||
const envVarKey = match[1]; | ||
if (envVarKey) { | ||
const result = process.env[envVarKey]; | ||
if (result) { | ||
input = result; | ||
output = output.replace(`%${envVarKey}%`, result); | ||
} | ||
@@ -282,3 +298,3 @@ } | ||
} | ||
return input; | ||
return output; | ||
} | ||
@@ -292,3 +308,5 @@ _loadConfigFile() { | ||
if (cfgFile.endsWith('.json')) { | ||
return file_io_1.fileio.readAs(cfgFile); | ||
const fileContentsStr = file_io_1.fileio.read(cfgFile); | ||
const updatedContentsStr = this.processEnvVars(fileContentsStr); | ||
return JSON.parse(updatedContentsStr); | ||
} | ||
@@ -295,0 +313,0 @@ else { |
@@ -21,4 +21,11 @@ import { Func } from "./custom-types"; | ||
/** | ||
* opens the specified file and returns the contents as a UTF-8 string | ||
* and then closes the file | ||
* @param file the relative or full path to an existing file | ||
* @returns the contents of the specifie file as a string | ||
*/ | ||
read(file: string): string; | ||
/** | ||
* attempts to parse the contents of a file into a simple JSON object | ||
* @param file the full path to an existing file | ||
* @param file the relative or full path to an existing file | ||
* @returns the contents of the specified file parsed into a simple object | ||
@@ -25,0 +32,0 @@ */ |
@@ -76,7 +76,8 @@ "use strict"; | ||
/** | ||
* attempts to parse the contents of a file into a simple JSON object | ||
* @param file the full path to an existing file | ||
* @returns the contents of the specified file parsed into a simple object | ||
* opens the specified file and returns the contents as a UTF-8 string | ||
* and then closes the file | ||
* @param file the relative or full path to an existing file | ||
* @returns the contents of the specifie file as a string | ||
*/ | ||
readAs(file, jsonParser) { | ||
read(file) { | ||
if (!path.isAbsolute(file)) { | ||
@@ -99,2 +100,11 @@ file = fs.realpathSync(path.join(process.cwd(), file)); | ||
} | ||
return fileContents; | ||
} | ||
/** | ||
* attempts to parse the contents of a file into a simple JSON object | ||
* @param file the relative or full path to an existing file | ||
* @returns the contents of the specified file parsed into a simple object | ||
*/ | ||
readAs(file, jsonParser) { | ||
const fileContents = this.read(file); | ||
const parser = jsonParser || function (inStr) { return JSON.parse(inStr); }; | ||
@@ -101,0 +111,0 @@ let obj; |
@@ -6,4 +6,4 @@ export declare class TitleParser { | ||
* the form of: | ||
* `some test [ID123] with multiple ids [Another]` where | ||
* `['ID123', 'Another']` would be returned | ||
* `some test [ID123] with multiple ids [Another_ID]` where | ||
* `['ID123', 'Another_ID']` would be returned | ||
* @param title the test full title to be parsed | ||
@@ -10,0 +10,0 @@ * @returns an array of TestId strings or empty array |
@@ -9,4 +9,4 @@ "use strict"; | ||
* the form of: | ||
* `some test [ID123] with multiple ids [Another]` where | ||
* `['ID123', 'Another']` would be returned | ||
* `some test [ID123] with multiple ids [Another_ID]` where | ||
* `['ID123', 'Another_ID']` would be returned | ||
* @param title the test full title to be parsed | ||
@@ -16,3 +16,3 @@ * @returns an array of TestId strings or empty array | ||
static parseTestIds(title) { | ||
return this._parseAll(title, /\[([^\[\]\s,]+)\]/gi); // eslint-disable-line no-useless-escape | ||
return this._parseAll(title, /\[([a-zA-Z0-9-_.]+)\]/gi); // eslint-disable-line no-useless-escape | ||
} | ||
@@ -19,0 +19,0 @@ static _parseAll(input, regex) { |
@@ -12,3 +12,2 @@ "use strict"; | ||
} | ||
; | ||
it('can use a Class type to get an existing section from aftconfig', () => { | ||
@@ -40,2 +39,15 @@ const randomEnvVarKey = src_1.rand.getString(12); | ||
it('can load .js file', () => { | ||
/** | ||
* this test relies on having a valid `aftconfig.js` file | ||
* in the project root directory containing the following: | ||
* ```javascript | ||
* module.exports = { | ||
* logLevel: 'none', | ||
* plugins: [], | ||
* ReporterConfig: { | ||
* logLevel: 'none' | ||
* } | ||
* }; | ||
* ``` | ||
*/ | ||
const aftcfg = new src_1.AftConfig(); | ||
@@ -46,2 +58,18 @@ expect(aftcfg.logLevel).toEqual('none'); | ||
}); | ||
it('can parse env vars to expected types', () => { | ||
class FooBarBazConfig { | ||
} | ||
const numKey = src_1.rand.getString(15); | ||
const boolKey = src_1.rand.getString(15); | ||
const objKey = src_1.rand.getString(15); | ||
const jsonStr = `{"FooBarBazConfig": {"foo": %${numKey}%, "bar": %${boolKey}%, "baz": %${objKey}%}}`; | ||
process.env[numKey] = '42'; | ||
process.env[boolKey] = 'true'; | ||
process.env[objKey] = '{"bt": "bt_value"}'; | ||
const cfg = new src_1.AftConfig(jsonStr).getSection(FooBarBazConfig); | ||
expect(cfg.foo).toBe(42); | ||
expect(cfg.bar).toBeTrue(); | ||
expect(cfg.baz).toBeDefined(); | ||
expect(cfg.baz.bt).toEqual('bt_value'); | ||
}); | ||
}); | ||
@@ -48,0 +76,0 @@ class ReporterConfig { |
@@ -23,2 +23,8 @@ "use strict"; | ||
{ title: 'foo [C1234,C2345] bar [C3456] baz', expected: ['C3456'] }, | ||
{ title: 'foo [C1234-C2345] bar [C3456] baz', expected: ['C1234-C2345', 'C3456'] }, | ||
{ title: 'foo [C1234_C2345] bar [C3456] baz', expected: ['C1234_C2345', 'C3456'] }, | ||
{ title: 'foo [C1234!C2345] bar [C3456] baz', expected: ['C3456'] }, | ||
{ title: 'foo [C1234+C2345] bar [C3456] baz', expected: ['C3456'] }, | ||
{ title: 'foo [C1234=C2345] bar [C3456] baz', expected: ['C3456'] }, | ||
{ title: 'foo [C1234^C2345] bar [C3456] baz', expected: ['C3456'] }, | ||
]; | ||
@@ -25,0 +31,0 @@ tcdata.forEach((d) => { |
{ | ||
"name": "aft-core", | ||
"version": "12.1.0", | ||
"version": "12.1.1", | ||
"description": "Automation Framework for Testing (AFT) package supporting JavaScript unit, integration and functional testing", | ||
@@ -52,3 +52,3 @@ "repository": { | ||
}, | ||
"gitHead": "a2e6105d0cdd31ce07b43bb73570ba173525443f" | ||
"gitHead": "07e29bfa73df85323bd4c60d45b334836885940f" | ||
} |
@@ -18,5 +18,6 @@ # AFT-Core | ||
"SomeCustomClassConfig": { | ||
"configField1": "%your_env_var%", | ||
"configField1": %your_env_var%, | ||
"configField2": "some-value", | ||
"configField3": ["foo", true, 10] | ||
"configField3": ["foo", true, 10], | ||
"configField4": "%another_env_var%" | ||
} | ||
@@ -26,3 +27,6 @@ } | ||
and with the following environment variables set: | ||
> export your_env_var="an important value" | ||
``` | ||
> export your_env_var="42" | ||
> export another_env_var="the meaning of everything" | ||
``` | ||
@@ -32,3 +36,3 @@ and a config class of: | ||
export class SomeCustomClassConfig { | ||
configField1: string = 'default_value_here'; | ||
configField1: number = 0; | ||
configField2: string = 'another_default_value'; | ||
@@ -43,6 +47,6 @@ configField3: Array<string | boolean | number> = ['default_val']; | ||
const config = aftConfig.getSection(SomeCustomClassConfig); // or new AftConfig().getSection(SomeCustomClassConfig); | ||
config.configField1; // returns "an important value" | ||
config.configField1; // returns 42 | ||
config.configField2; // returns "some-value" | ||
config.configField3; // returns ["foo", true, 10] as an array | ||
config.configField4; // returns "last_default_value" | ||
config.configField4; // returns "the meaning of everything" | ||
``` | ||
@@ -54,6 +58,6 @@ | ||
SomeCustomClassConfig: { | ||
configField1: 'custom_value_here' | ||
configField1: 42 | ||
} | ||
}); | ||
config.configField1; // returns "custom_value_here" | ||
config.configField1; // returns 42 | ||
config.configField2; // returns "another_default_value" | ||
@@ -60,0 +64,0 @@ config.configField3; // returns ["default_val"] as an array |
@@ -84,4 +84,16 @@ import * as fs from 'node:fs'; | ||
constructor(config?: JsonObject) { | ||
this._cfg = config; | ||
constructor(config?: JsonObject | string) { | ||
dotenv.config(); | ||
try { | ||
if (typeof config === 'string') { | ||
const processedConfigStr = this.processEnvVars(config); | ||
this._cfg = JSON.parse(processedConfigStr); | ||
} else if (typeof config === 'object') { | ||
this._cfg = config; | ||
} | ||
} catch (e) { | ||
console.warn(`[${this.constructor.name}] - WARN `, // eslint-disable-line no-undef | ||
'- error processing passed in config argument', | ||
'falling back to config file load...', e); | ||
} | ||
if (!this._cfg) { | ||
@@ -92,3 +104,2 @@ this._cfg = this._loadConfigFile(); | ||
this._sectionCache = new Map<string, {}>(); | ||
dotenv.config(); | ||
} | ||
@@ -279,10 +290,14 @@ /** | ||
processEnvVars(input: string): string { | ||
if (input && typeof input === 'string') { | ||
const regx = /^%(.*)%$/; | ||
if ((input?.match(regx)?.length ?? 0) > 0) { | ||
const envVarKey = input.match(regx)?.[1]; | ||
if (input == null || typeof input !== 'string') { | ||
return input; | ||
} | ||
let output: string = input; | ||
const regx = /%([^\W]+)%/gm; | ||
for (const match of input?.matchAll(regx)) { // eslint-disable-line no-unsafe-optional-chaining | ||
if ((match?.length ?? 0) > 0) { | ||
const envVarKey = match[1]; | ||
if (envVarKey) { | ||
const result = process.env[envVarKey]; | ||
if (result) { | ||
input = result; | ||
output = output.replace(`%${envVarKey}%`, result); | ||
} | ||
@@ -292,3 +307,3 @@ } | ||
} | ||
return input; | ||
return output; | ||
} | ||
@@ -303,3 +318,5 @@ | ||
if (cfgFile.endsWith('.json')) { | ||
return fileio.readAs<JsonObject>(cfgFile); | ||
const fileContentsStr = fileio.read(cfgFile); | ||
const updatedContentsStr = this.processEnvVars(fileContentsStr); | ||
return JSON.parse(updatedContentsStr) as JsonObject; | ||
} else { | ||
@@ -306,0 +323,0 @@ return require(cfgFile) as JsonObject; // eslint-disable-line no-undef |
@@ -71,7 +71,8 @@ import * as process from 'node:process'; | ||
/** | ||
* attempts to parse the contents of a file into a simple JSON object | ||
* @param file the full path to an existing file | ||
* @returns the contents of the specified file parsed into a simple object | ||
* opens the specified file and returns the contents as a UTF-8 string | ||
* and then closes the file | ||
* @param file the relative or full path to an existing file | ||
* @returns the contents of the specifie file as a string | ||
*/ | ||
readAs<T>(file: string, jsonParser?: Func<string, T>): T { | ||
read(file: string): string { | ||
if (!path.isAbsolute(file)) { | ||
@@ -93,2 +94,12 @@ file = fs.realpathSync(path.join(process.cwd(), file)); | ||
} | ||
return fileContents; | ||
} | ||
/** | ||
* attempts to parse the contents of a file into a simple JSON object | ||
* @param file the relative or full path to an existing file | ||
* @returns the contents of the specified file parsed into a simple object | ||
*/ | ||
readAs<T>(file: string, jsonParser?: Func<string, T>): T { | ||
const fileContents = this.read(file); | ||
const parser: Func<string, T> = jsonParser || function(inStr: string): T { return JSON.parse(inStr) as T; } | ||
@@ -95,0 +106,0 @@ let obj: T; |
@@ -6,4 +6,4 @@ export class TitleParser { | ||
* the form of: | ||
* `some test [ID123] with multiple ids [Another]` where | ||
* `['ID123', 'Another']` would be returned | ||
* `some test [ID123] with multiple ids [Another_ID]` where | ||
* `['ID123', 'Another_ID']` would be returned | ||
* @param title the test full title to be parsed | ||
@@ -13,3 +13,3 @@ * @returns an array of TestId strings or empty array | ||
static parseTestIds(title: string): Array<string> { | ||
return this._parseAll(title, /\[([^\[\]\s,]+)\]/gi); // eslint-disable-line no-useless-escape | ||
return this._parseAll(title, /\[([a-zA-Z0-9-_.]+)\]/gi); // eslint-disable-line no-useless-escape | ||
} | ||
@@ -16,0 +16,0 @@ |
@@ -1,10 +0,9 @@ | ||
import { AftConfig, LogLevel, ReportingManager, rand } from "../../src" | ||
import { AftConfig, LogLevel, rand } from "../../src" | ||
describe('AftConfig', () => { | ||
class FakeSectionConfig { | ||
constructor() {} | ||
option1: number = -1; | ||
option2: boolean = false; | ||
option3: string = "option3val"; | ||
}; | ||
} | ||
@@ -41,2 +40,15 @@ it('can use a Class type to get an existing section from aftconfig', () => { | ||
it('can load .js file', () => { | ||
/** | ||
* this test relies on having a valid `aftconfig.js` file | ||
* in the project root directory containing the following: | ||
* ```javascript | ||
* module.exports = { | ||
* logLevel: 'none', | ||
* plugins: [], | ||
* ReporterConfig: { | ||
* logLevel: 'none' | ||
* } | ||
* }; | ||
* ``` | ||
*/ | ||
const aftcfg = new AftConfig(); | ||
@@ -48,2 +60,27 @@ | ||
}) | ||
it('can parse env vars to expected types', () => { | ||
type BazType = { | ||
bt: string; | ||
}; | ||
class FooBarBazConfig { | ||
foo: number; | ||
bar: boolean; | ||
baz: BazType; | ||
} | ||
const numKey = rand.getString(15); | ||
const boolKey = rand.getString(15); | ||
const objKey = rand.getString(15); | ||
const jsonStr = `{"FooBarBazConfig": {"foo": %${numKey}%, "bar": %${boolKey}%, "baz": %${objKey}%}}`; | ||
process.env[numKey] = '42'; | ||
process.env[boolKey] = 'true'; | ||
process.env[objKey] = '{"bt": "bt_value"}'; | ||
const cfg = new AftConfig(jsonStr).getSection(FooBarBazConfig); | ||
expect(cfg.foo).toBe(42); | ||
expect(cfg.bar).toBeTrue(); | ||
expect(cfg.baz).toBeDefined(); | ||
expect(cfg.baz.bt).toEqual('bt_value'); | ||
}) | ||
}) | ||
@@ -50,0 +87,0 @@ |
@@ -22,2 +22,8 @@ import { TitleParser } from '../../src'; | ||
{title: 'foo [C1234,C2345] bar [C3456] baz', expected: ['C3456']}, | ||
{title: 'foo [C1234-C2345] bar [C3456] baz', expected: ['C1234-C2345', 'C3456']}, | ||
{title: 'foo [C1234_C2345] bar [C3456] baz', expected: ['C1234_C2345', 'C3456']}, | ||
{title: 'foo [C1234!C2345] bar [C3456] baz', expected: ['C3456']}, | ||
{title: 'foo [C1234+C2345] bar [C3456] baz', expected: ['C3456']}, | ||
{title: 'foo [C1234=C2345] bar [C3456] baz', expected: ['C3456']}, | ||
{title: 'foo [C1234^C2345] bar [C3456] baz', expected: ['C3456']}, | ||
]; | ||
@@ -24,0 +30,0 @@ tcdata.forEach((d) => { |
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
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
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 3 instances 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
1000161
15660
278
11