Skip to content

Commit

Permalink
Merge pull request #106 from ajthinking/nested-merge
Browse files Browse the repository at this point in the history
Nested merge
  • Loading branch information
ajthinking authored Jan 7, 2024
2 parents 2cdb810 + 1e12fe9 commit ee38e4b
Show file tree
Hide file tree
Showing 6 changed files with 81 additions and 11 deletions.
24 changes: 20 additions & 4 deletions packages/core/src/computers/ReplaceItem/ReplaceItem.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,17 +26,33 @@ it('merges items when mode is set to MERGE', () => {
.hasParams({
mode: 'MERGE',
json: `{
newKey: newValue
properties: {
newProp: newPropValue
}
}`
})
.getsInput([
{},
{ existingKey: 'existingValue' }
{
id: 1,
properties: {
existingProp: 'existingPropValue'
}
}
])
.doRun()
.expectOutput([
{ newKey: 'newValue' },
{ existingKey: 'existingValue', newKey: 'newValue' },
{
properties: {
newProp: 'newPropValue',
}
},
{
properties: {
existingProp: 'existingPropValue',
newProp: 'newPropValue',
}
},
])
.ok()
})
6 changes: 2 additions & 4 deletions packages/core/src/computers/ReplaceItem/ReplaceItem.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import { JsEvaluation, JsonEvaluation, HjsonEvaluation, json_ } from '../../Param';
import { ComputerConfig } from '../../types/ComputerConfig';
import { ItemValue } from '../../types/ItemValue';
import { merge } from '../../utils/merge';
import { multiline } from '../../utils/multiline';

export const ReplaceItem: ComputerConfig = {
Expand Down Expand Up @@ -45,10 +46,7 @@ export const ReplaceItem: ComputerConfig = {
const replacers = incoming.map(item => {
if(params.mode === 'REPLACE') return item.params.json as ItemValue;

if(params.mode === 'MERGE')return {
...item.value,
...item.params.json as Object,
}
if(params.mode === 'MERGE') return merge(item.value, item.params.json as Object);

throw new Error(`Unknown mode: ${params.mode}`)
})
Expand Down
15 changes: 15 additions & 0 deletions packages/core/src/utils/merge.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { merge } from './merge';

it('merges flat objects', () => {
const first = { a: 1 };
const second = { a: 2, b: 3 };

expect(merge(first, second)).toEqual({ a: 2, b: 3 });
});

it('merges nested objects', () => {
const first = { a: { b: 1, c: 2 } };
const second = { a: { b: 'new' } };

expect(merge(first, second)).toEqual({ a: { b: 'new', c: 2 } });
});
14 changes: 14 additions & 0 deletions packages/core/src/utils/merge.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
type Obj = {
[key: string]: any
}

export const merge = (first: Obj, second: Obj) => {
// Iterate through `source` properties and if an `Object` set property to merge of `target` and `source` properties
for (const key of Object.keys(second)) {
if (second[key] instanceof Object)
Object.assign(second[key], merge(first[key], second[key]));
}
// Join `target` and modified `source`
Object.assign(first || {}, second);
return first;
}
24 changes: 24 additions & 0 deletions packages/core/src/utils/multiline.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { multiline } from './multiline';


it('removes first line when it is empty', () => {
const result = multiline`
content
`;

expect(result).toEqual('content\n');
});

it('bases indentation on the first content line', () => {
const result = multiline`
heading
p1
p2
`;

expect(result).toEqual('heading\n p1\n p2\n');
});

it('throws if it gets content on first line', () => {
expect(() => multiline`content-on-first-line`).toThrow();
});
9 changes: 6 additions & 3 deletions packages/core/src/utils/multiline.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,14 @@ export const multiline = (strings: TemplateStringsArray, ...values: any[]) => {
// Split the string into lines
let lines = combinedString.split('\n');

// Remove the first line if it is empty
if (lines[0].trim() === '') {
lines = lines.slice(1);
// Throw if the first line is not empty
if (lines[0].trim() !== '') {
throw new Error(`First line of multiline string must be empty. The content was ${combinedString}`);
}

// Remove the first line
lines = lines.slice(1);

// Find the minimum indentation of all lines (except empty lines)
const baseIndentation = Math.min(...lines.filter(line => line.trim() !== '').map(line => line.search(/\S|$/)));

Expand Down

0 comments on commit ee38e4b

Please sign in to comment.