Skip to content

Commit

Permalink
fix: synthesizing react subproject fails due to stack overflow (#481)
Browse files Browse the repository at this point in the history
Fixes #480 

---
By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.
  • Loading branch information
Chriscbr authored Jan 11, 2021
1 parent 6e17704 commit 39b2dbe
Show file tree
Hide file tree
Showing 2 changed files with 80 additions and 5 deletions.
71 changes: 71 additions & 0 deletions src/__tests__/util.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import { JsonFile } from '../json';
import { decamelizeKeysRecursively, dedupArray, deepMerge, isTruthy, getFilePermissions } from '../util';
import { TestProject } from './util';

describe('decamelizeRecursively', () => {
test('decamel recurses an object structure', () => {
Expand Down Expand Up @@ -85,26 +87,95 @@ test('isTruthy', () => {
});

test('deepMerge merges objects', () => {
// GIVEN
const original = { a: { b: 3 } };

// WHEN
deepMerge(original, { a: { c: 4 } });

// THEN
expect(original).toEqual({ a: { b: 3, c: 4 } });
});

test('deepMerge overwrites non-objects', () => {
// GIVEN
const original = { a: [] };

// WHEN
deepMerge(original, { a: { b: 3 } });

// THEN
expect(original).toEqual({ a: { b: 3 } });
});

test('deepMerge does not overwrite if rightmost is "undefined"', () => {
// GIVEN
const original = { a: 1 };

// WHEN
deepMerge(original, { a: undefined });

// THEN
expect(original).toEqual({ a: 1 });
});

test('deepMerge does not recurse indefinitely if rightmost is circular', () => {
// GIVEN
const simple: Record<string, any> = { a: 1, b: 2 };
const circular: Record<string, any> = { a: { b: { c: 3 } } };
circular.a.b.c = circular.a;

// WHEN
deepMerge(simple, circular);

// THEN
expect(simple.a.b.c).toEqual(simple.a);
expect(simple.b).toEqual(2);
});

test('deepMerge does not recurse indefinitely if leftmost is circular', () => {
// GIVEN
const simple: Record<string, any> = { a: 1, b: 2 };
const circular: Record<string, any> = { a: { b: { c: 3 } } };
circular.a.b.c = circular.a;

// WHEN
deepMerge(circular, simple);

// THEN
expect(circular.a).toEqual(1);
expect(circular.b).toEqual(2);
});

test('deepMerge should not recurse on projects', () => {
// GIVEN
const proj1 = new TestProject();
const proj2 = new TestProject();
const objA = { a: proj1 };
const objB = { a: proj2 };

// WHEN
deepMerge(objA, objB);

// THEN
expect(objA).toEqual(objB);
});

test('deepMerge should not recurse on components', () => {
// GIVEN
const proj = new TestProject();
const comp1 = new JsonFile(proj, 'foo', { obj: 3 });
const comp2 = new JsonFile(proj, 'bar', { obj: 5 });
const objA = { a: comp1 };
const objB = { a: comp2 };

// WHEN
deepMerge(objA, objB);

// THEN
expect(objA).toEqual(objB);
});

test('dedupArray', () => {
expect(dedupArray(['a', 'b', 'c'])).toEqual(['a', 'b', 'c']);
expect(dedupArray(['a', 'a', 'b', 'a'])).toEqual(['a', 'b']);
Expand Down
14 changes: 9 additions & 5 deletions src/util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -150,11 +150,12 @@ export type Obj<T> = { [key: string]: T };
/**
* Return whether the given value is an object
*
* Even though arrays technically are objects, we usually want to treat them differently,
* so we return false in those cases.
* Even though arrays and instances of classes technically are objects, we
* usually want to treat them differently, so we return false in those cases.
*/
export function isObject(x: any): x is Obj<any> {
return x !== null && typeof x === 'object' && !Array.isArray(x);
return x !== null && typeof x === 'object' && !Array.isArray(x)
&& x.constructor.name === 'Object';
}

/**
Expand All @@ -171,8 +172,11 @@ export function deepMerge(...objects: Array<Obj<any> | undefined>) {
const value = source[key];

if (isObject(value)) {
if (!isObject(target[key])) { target[key] = {}; } // Overwrite on purpose
mergeOne(target[key], value);
if (!isObject(target[key])) {
target[key] = value;
} else {
mergeOne(target[key], value);
}
} else if (typeof value !== 'undefined') {
target[key] = value;
}
Expand Down

0 comments on commit 39b2dbe

Please sign in to comment.