Skip to content

Commit 9c7015f

Browse files
authored
Make variable names case-insensitive (#3)
1 parent 98fc023 commit 9c7015f

File tree

8 files changed

+122
-69
lines changed

8 files changed

+122
-69
lines changed

Diff for: CHANGELOG.md

+3
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
# Changelog
22

3+
## v1.3.0
4+
- Make variable names case-insensitive
5+
36
## v1.2.0
47
- Replace `merge` with `flattenAndMerge` to flatten objects and merge
58

Diff for: README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ Example: `**/*.json; !local/ => out/*.json` will match all files ending with `.j
5555

5656
`--variables <list>`
5757

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

6060
If an entry starts with:
6161
- `@`: the value will be interpreted as a path to a JSON file

Diff for: package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@qetza/replacetokens",
3-
"version": "1.2.0",
3+
"version": "1.3.0",
44
"description": "replace tokens in files",
55
"author": "Guillaume ROUCHON",
66
"license": "MIT",

Diff for: src/bin/run.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ export async function run() {
1414
// parse arguments
1515
var argv = await yargs(process.argv.slice(2))
1616
.scriptName('replacetokens')
17-
.version('1.2.0')
17+
.version('1.3.0')
1818
.usage('$0 [args]')
1919
.help()
2020
.options({

Diff for: src/index.ts

+29-18
Original file line numberDiff line numberDiff line change
@@ -66,21 +66,29 @@ export class Counter {
6666
transforms: number = 0;
6767
}
6868

69-
export function flattenAndMerge(separator: string, ...objects: { [key: string]: any }[]): { [key: string]: any } {
69+
export function flattenAndMerge(separator: string, ...objects: { [key: string]: any }[]): { [key: string]: string } {
7070
return objects.reduce((result, current) => {
71-
return { ...result, ...flatten(current, separator) };
71+
const values = {};
72+
for (const [key, value] of Object.entries(flatten(current, separator))) {
73+
values[key] = value.value;
74+
}
75+
76+
return { ...result, ...values };
7277
}, {});
7378
}
74-
function flatten(object: Object, separator: string, parentKey?: string): { [key: string]: string } {
79+
function flatten(
80+
object: Object,
81+
separator: string,
82+
parentKey?: string
83+
): { [key: string]: { name: string; value: string } } {
7584
let result = {};
7685

77-
Object.keys(object).forEach((key: string) => {
78-
const value = object[key];
79-
const flattenKey = parentKey ? `${parentKey}${separator}${key}` : key;
86+
for (const [key, value] of Object.entries(object)) {
87+
let flattenKey = parentKey ? `${parentKey}${separator}${key}` : key;
8088

8189
if (value && typeof value === 'object') result = { ...result, ...flatten(value, separator, flattenKey) };
82-
else result[flattenKey] = value?.toString() ?? '';
83-
});
90+
else result[flattenKey.toUpperCase()] = { name: flattenKey, value: value?.toString() ?? '' };
91+
}
8492

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

258266
try {
259-
// parse, flatten and stringify json variables
267+
// flatten with uppercase and stringify json variables
260268
const data = flatten(variables ?? {}, options.separator!);
261269

262-
// log variables
263-
let count = 0;
264-
for (const key of Object.keys(data)) {
265-
++count;
266-
console.debug(`loaded '${key}'`);
270+
// get variables with case-insensitive key and value
271+
const vars = {};
272+
for (const [key, value] of Object.entries(data)) {
273+
vars[key] = value.value;
274+
275+
console.debug(`loaded '${value.name}'`);
267276
}
268277

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

271-
return data;
281+
return vars;
272282
} finally {
273283
console.groupEnd();
274284
}
@@ -461,10 +471,11 @@ function replaceTokensInString(
461471
}
462472

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

466477
// replace token
467-
let value: string = variables[name];
478+
let value: string = variables[key];
468479

469480
if (value === undefined) {
470481
// variable not found
@@ -515,7 +526,7 @@ function replaceTokensInString(
515526
transformRegex,
516527
customEscapeRegex,
517528
options,
518-
names.concat(name)
529+
names.concat(key)
519530
);
520531
value = result.content;
521532

Diff for: tests/flattenAndMerge.test.ts

+19-19
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ describe('flattenAndMerge', () => {
1010

1111
// assert
1212
expect(result).not.toBe(source);
13-
expect(result).toEqual(source);
13+
expect(result).toEqual({ STRING: 'hello' });
1414
});
1515

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

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

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

3636
// assert
3737
expect(result).toEqual({
38-
'msgs.0': 'hello',
39-
'msgs.1': 'world!',
40-
private: 'true',
41-
count: '2'
38+
'MSGS.0': 'hello',
39+
'MSGS.1': 'world!',
40+
PRIVATE: 'true',
41+
COUNT: '2'
4242
});
4343
});
4444

@@ -50,8 +50,8 @@ describe('flattenAndMerge', () => {
5050
obj: { scalar: true, obj: { scalar: 1.2, array: ['hello', { value: 'world!' }], scalar2: 'a' } }
5151
};
5252
const source2 = {
53-
array: [{ scalar: 'hello' }],
54-
obj: { scalar2: false, obj: { scalar: '1.3', array: ['hello world!'] } },
53+
ARRAY: [{ scalar: 'hello' }],
54+
obj: { scalar2: false, obj: { SCALAR: '1.3', array: ['hello world!'] } },
5555
count: 2
5656
};
5757
const source3 = [
@@ -66,18 +66,18 @@ describe('flattenAndMerge', () => {
6666

6767
// assert
6868
expect(result).toEqual({
69-
scalar: 'string',
70-
'array.0.scalar': 'hello',
71-
'array.1.scalar': 'world!',
72-
'obj.scalar': 'true',
73-
'obj.scalar2': 'false',
74-
'obj.obj.scalar': '1.3',
75-
'obj.obj.array.0': 'hello world!',
76-
'obj.obj.array.1.value': 'world!',
77-
'obj.obj.scalar2': 'a',
78-
count: '2',
69+
SCALAR: 'string',
70+
'ARRAY.0.SCALAR': 'hello',
71+
'ARRAY.1.SCALAR': 'world!',
72+
'OBJ.SCALAR': 'true',
73+
'OBJ.SCALAR2': 'false',
74+
'OBJ.OBJ.SCALAR': '1.3',
75+
'OBJ.OBJ.ARRAY.0': 'hello world!',
76+
'OBJ.OBJ.ARRAY.1.VALUE': 'world!',
77+
'OBJ.OBJ.SCALAR2': 'a',
78+
COUNT: '2',
7979
'0': 'a',
80-
'1.scalar': '2'
80+
'1.SCALAR': '2'
8181
});
8282
});
8383
});

Diff for: tests/replacetokens.test.ts

+43-2
Original file line numberDiff line numberDiff line change
@@ -214,6 +214,47 @@ describe('replaceTokens', () => {
214214
});
215215
});
216216

217+
describe('variables', () => {
218+
it('logs', async () => {
219+
// arrange
220+
const input = await copyData('default.json', 'default1.json');
221+
const consoleSpies = spyOnConsole();
222+
223+
// act
224+
const result = await replaceTokens(normalizeSources(input), {
225+
var1: 'var1_value',
226+
var2: 'var2_value',
227+
VAR3: ['var3_value0', 'var3_value1']
228+
});
229+
230+
// assert
231+
expect(consoleSpies.group).toHaveBeenCalledWith('loading variables');
232+
expect(consoleSpies.debug).toHaveBeenCalledWith("loaded 'var1'");
233+
expect(consoleSpies.debug).toHaveBeenCalledWith("loaded 'var2'");
234+
expect(consoleSpies.debug).toHaveBeenCalledWith("loaded 'VAR3.0'");
235+
expect(consoleSpies.debug).toHaveBeenCalledWith("loaded 'VAR3.1'");
236+
expect(consoleSpies.info).toHaveBeenCalledWith('4 variables loaded');
237+
expect(consoleSpies.groupEnd).toHaveBeenCalled();
238+
});
239+
240+
it('case insensitive', async () => {
241+
// arrange
242+
const input = await copyData('default.separator.json', 'default1.json');
243+
spyOnConsole();
244+
245+
// act
246+
const result = await replaceTokens(
247+
normalizeSources(input),
248+
{ VARS: [{ value: 'var1_value' }, { VALUE: 'var2_value' }] },
249+
{ separator: ':' }
250+
);
251+
252+
// assert
253+
expectCountersToEqual(result, 0, 1, 2, 2, 0);
254+
await expectFilesToEqual(input, 'default.expected.json');
255+
});
256+
});
257+
217258
describe('token', () => {
218259
it('default pattern', async () => {
219260
// arrange
@@ -622,7 +663,7 @@ describe('replaceTokens', () => {
622663
// act
623664
const result = await replaceTokens(
624665
normalizeSources(input),
625-
{ var1: 'var1#{var3}#', var2: 'var2_value', var3: '_#{var4}#', var4: 'value' },
666+
{ VAR1: 'var1#{var3}#', var2: 'var2_value', var3: '_#{var4}#', VAR4: 'value' },
626667
{ recursive: true }
627668
);
628669

@@ -640,7 +681,7 @@ describe('replaceTokens', () => {
640681
await expect(
641682
replaceTokens(
642683
normalizeSources(input),
643-
{ var1: 'var1#{var2}#', var2: '_#{var1}#', var3: 'value' },
684+
{ VAR1: 'var1#{var2}#', var2: '_#{var1}#', var3: 'value' },
644685
{ recursive: true }
645686
)
646687
).rejects.toThrow("found cycle with token 'var1'");

0 commit comments

Comments
 (0)