Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make variable names case-insensitive #3

Merged
merged 1 commit into from
Mar 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
# Changelog

## v1.3.0
- Make variable names case-insensitive

## v1.2.0
- Replace `merge` with `flattenAndMerge` to flatten objects and merge

Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ Example: `**/*.json; !local/ => out/*.json` will match all files ending with `.j

`--variables <list>`

A list of JSON encoded key/values.
A list of JSON encoded key/values (keys are **case-insensitive**).

If an entry starts with:
- `@`: the value will be interpreted as a path to a JSON file
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@qetza/replacetokens",
"version": "1.2.0",
"version": "1.3.0",
"description": "replace tokens in files",
"author": "Guillaume ROUCHON",
"license": "MIT",
Expand Down
2 changes: 1 addition & 1 deletion src/bin/run.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ export async function run() {
// parse arguments
var argv = await yargs(process.argv.slice(2))
.scriptName('replacetokens')
.version('1.2.0')
.version('1.3.0')
.usage('$0 [args]')
.help()
.options({
Expand Down
47 changes: 29 additions & 18 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,21 +66,29 @@ export class Counter {
transforms: number = 0;
}

export function flattenAndMerge(separator: string, ...objects: { [key: string]: any }[]): { [key: string]: any } {
export function flattenAndMerge(separator: string, ...objects: { [key: string]: any }[]): { [key: string]: string } {
return objects.reduce((result, current) => {
return { ...result, ...flatten(current, separator) };
const values = {};
for (const [key, value] of Object.entries(flatten(current, separator))) {
values[key] = value.value;
}

return { ...result, ...values };
}, {});
}
function flatten(object: Object, separator: string, parentKey?: string): { [key: string]: string } {
function flatten(
object: Object,
separator: string,
parentKey?: string
): { [key: string]: { name: string; value: string } } {
let result = {};

Object.keys(object).forEach((key: string) => {
const value = object[key];
const flattenKey = parentKey ? `${parentKey}${separator}${key}` : key;
for (const [key, value] of Object.entries(object)) {
let flattenKey = parentKey ? `${parentKey}${separator}${key}` : key;

if (value && typeof value === 'object') result = { ...result, ...flatten(value, separator, flattenKey) };
else result[flattenKey] = value?.toString() ?? '';
});
else result[flattenKey.toUpperCase()] = { name: flattenKey, value: value?.toString() ?? '' };
}

return result;
}
Expand Down Expand Up @@ -256,19 +264,21 @@ function loadVariables(variables: { [key: string]: any }, options: Options): { [
console.group('loading variables');

try {
// parse, flatten and stringify json variables
// flatten with uppercase and stringify json variables
const data = flatten(variables ?? {}, options.separator!);

// log variables
let count = 0;
for (const key of Object.keys(data)) {
++count;
console.debug(`loaded '${key}'`);
// get variables with case-insensitive key and value
const vars = {};
for (const [key, value] of Object.entries(data)) {
vars[key] = value.value;

console.debug(`loaded '${value.name}'`);
}

const count = Object.keys(vars).length;
console.info(`${count} variable${count > 1 ? 's' : ''} loaded`);

return data;
return vars;
} finally {
console.groupEnd();
}
Expand Down Expand Up @@ -461,10 +471,11 @@ function replaceTokensInString(
}

// check recursion
if (options.recursive && names.includes(name)) throw new Error(`found cycle with token '${name}'`);
const key = name.toUpperCase();
if (options.recursive && names.includes(key)) throw new Error(`found cycle with token '${name}'`);

// replace token
let value: string = variables[name];
let value: string = variables[key];

if (value === undefined) {
// variable not found
Expand Down Expand Up @@ -515,7 +526,7 @@ function replaceTokensInString(
transformRegex,
customEscapeRegex,
options,
names.concat(name)
names.concat(key)
);
value = result.content;

Expand Down
38 changes: 19 additions & 19 deletions tests/flattenAndMerge.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ describe('flattenAndMerge', () => {

// assert
expect(result).not.toBe(source);
expect(result).toEqual(source);
expect(result).toEqual({ STRING: 'hello' });
});

it('multiple objects', async () => {
Expand All @@ -22,7 +22,7 @@ describe('flattenAndMerge', () => {
const result = flattenAndMerge('.', source1, source2);

// assert
expect(result).toEqual({ msg: 'hello world!', private: 'true', count: '2' });
expect(result).toEqual({ MSG: 'hello world!', PRIVATE: 'true', COUNT: '2' });
});

it('objects with array', async () => {
Expand All @@ -35,10 +35,10 @@ describe('flattenAndMerge', () => {

// assert
expect(result).toEqual({
'msgs.0': 'hello',
'msgs.1': 'world!',
private: 'true',
count: '2'
'MSGS.0': 'hello',
'MSGS.1': 'world!',
PRIVATE: 'true',
COUNT: '2'
});
});

Expand All @@ -50,8 +50,8 @@ describe('flattenAndMerge', () => {
obj: { scalar: true, obj: { scalar: 1.2, array: ['hello', { value: 'world!' }], scalar2: 'a' } }
};
const source2 = {
array: [{ scalar: 'hello' }],
obj: { scalar2: false, obj: { scalar: '1.3', array: ['hello world!'] } },
ARRAY: [{ scalar: 'hello' }],
obj: { scalar2: false, obj: { SCALAR: '1.3', array: ['hello world!'] } },
count: 2
};
const source3 = [
Expand All @@ -66,18 +66,18 @@ describe('flattenAndMerge', () => {

// assert
expect(result).toEqual({
scalar: 'string',
'array.0.scalar': 'hello',
'array.1.scalar': 'world!',
'obj.scalar': 'true',
'obj.scalar2': 'false',
'obj.obj.scalar': '1.3',
'obj.obj.array.0': 'hello world!',
'obj.obj.array.1.value': 'world!',
'obj.obj.scalar2': 'a',
count: '2',
SCALAR: 'string',
'ARRAY.0.SCALAR': 'hello',
'ARRAY.1.SCALAR': 'world!',
'OBJ.SCALAR': 'true',
'OBJ.SCALAR2': 'false',
'OBJ.OBJ.SCALAR': '1.3',
'OBJ.OBJ.ARRAY.0': 'hello world!',
'OBJ.OBJ.ARRAY.1.VALUE': 'world!',
'OBJ.OBJ.SCALAR2': 'a',
COUNT: '2',
'0': 'a',
'1.scalar': '2'
'1.SCALAR': '2'
});
});
});
45 changes: 43 additions & 2 deletions tests/replacetokens.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,47 @@ describe('replaceTokens', () => {
});
});

describe('variables', () => {
it('logs', async () => {
// arrange
const input = await copyData('default.json', 'default1.json');
const consoleSpies = spyOnConsole();

// act
const result = await replaceTokens(normalizeSources(input), {
var1: 'var1_value',
var2: 'var2_value',
VAR3: ['var3_value0', 'var3_value1']
});

// assert
expect(consoleSpies.group).toHaveBeenCalledWith('loading variables');
expect(consoleSpies.debug).toHaveBeenCalledWith("loaded 'var1'");
expect(consoleSpies.debug).toHaveBeenCalledWith("loaded 'var2'");
expect(consoleSpies.debug).toHaveBeenCalledWith("loaded 'VAR3.0'");
expect(consoleSpies.debug).toHaveBeenCalledWith("loaded 'VAR3.1'");
expect(consoleSpies.info).toHaveBeenCalledWith('4 variables loaded');
expect(consoleSpies.groupEnd).toHaveBeenCalled();
});

it('case insensitive', async () => {
// arrange
const input = await copyData('default.separator.json', 'default1.json');
spyOnConsole();

// act
const result = await replaceTokens(
normalizeSources(input),
{ VARS: [{ value: 'var1_value' }, { VALUE: 'var2_value' }] },
{ separator: ':' }
);

// assert
expectCountersToEqual(result, 0, 1, 2, 2, 0);
await expectFilesToEqual(input, 'default.expected.json');
});
});

describe('token', () => {
it('default pattern', async () => {
// arrange
Expand Down Expand Up @@ -622,7 +663,7 @@ describe('replaceTokens', () => {
// act
const result = await replaceTokens(
normalizeSources(input),
{ var1: 'var1#{var3}#', var2: 'var2_value', var3: '_#{var4}#', var4: 'value' },
{ VAR1: 'var1#{var3}#', var2: 'var2_value', var3: '_#{var4}#', VAR4: 'value' },
{ recursive: true }
);

Expand All @@ -640,7 +681,7 @@ describe('replaceTokens', () => {
await expect(
replaceTokens(
normalizeSources(input),
{ var1: 'var1#{var2}#', var2: '_#{var1}#', var3: 'value' },
{ VAR1: 'var1#{var2}#', var2: '_#{var1}#', var3: 'value' },
{ recursive: true }
)
).rejects.toThrow("found cycle with token 'var1'");
Expand Down
Loading