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

feat: set $parent on create and set #50

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
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
24 changes: 24 additions & 0 deletions lib/properties.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
import {
assign,
isArray,
isString
} from 'min-dash';

import Base from './base.js';

/**
* A utility that gets and sets properties of model elements.
*
Expand Down Expand Up @@ -36,6 +39,8 @@ Properties.prototype.set = function(target, name, value) {
// unset the property, if the specified value is undefined;
// delete from $attrs (for extensions) or the target itself
if (property) {
updateParent(target[propertyName], value, undefined);

delete target[propertyName];
} else {
delete target.$attrs[stripGlobal(name)];
Expand All @@ -45,6 +50,12 @@ Properties.prototype.set = function(target, name, value) {
// set the property, defining well defined properties on the fly
// or simply updating them in target.$attrs (for extensions)
if (property) {
const descriptor = this.model.getPropertyDescriptor(target, propertyName);

if (descriptor && !descriptor.isReference) {
updateParent(target[propertyName], value, target);
}

if (propertyName in target) {
target[propertyName] = value;
} else {
Expand Down Expand Up @@ -177,4 +188,17 @@ function defineProperty(target, property, value) {

function stripGlobal(name) {
return name.replace(/^:/, '');
}

function updateParent(oldValues, newValues, parent) {
setParent(oldValues, undefined);
setParent(newValues, parent);
}

function setParent(values, parent) {
if (isArray(values)) {
values.forEach(value => setParent(value, parent));
} else if (values instanceof Base) {
values.$parent = parent;
}
}
197 changes: 197 additions & 0 deletions test/spec/properties.js
Original file line number Diff line number Diff line change
Expand Up @@ -288,6 +288,202 @@ describe('properties', function() {
});


describe('parent', function() {

describe('create', function() {

it('should set parent if model element', function() {

// when
var complexNesting = model.create('props:ComplexNesting', {
nested: model.create('props:Complex')
});

// then
expect(complexNesting.get('nested').$parent).to.equal(complexNesting);
});


it('should not set parent if not model element', function() {

// when
var complexNesting = model.create('props:ComplexNesting', {
foo: {}
});

// then
expect(complexNesting.get('foo').$parent).not.to.exist;
});

});


describe('set', function() {

describe('one', function() {

it('should set parent if model element', function() {

// given
var embedding = model.create('props:Embedding');

var embeddedComplex = model.create('props:Complex');

// when
embedding.set('embeddedComplex', embeddedComplex);

// then
expect(embedding.get('embeddedComplex')).to.equal(embeddedComplex);
expect(embeddedComplex.$parent).to.equal(embedding);
});


it('should unset parent if model element', function() {

// given
var embeddedComplex = model.create('props:Complex');

var embedding = model.create('props:Embedding', {
embeddedComplex
});

// assume
expect(embedding.get('embeddedComplex')).to.equal(embeddedComplex);
expect(embeddedComplex.$parent).to.equal(embedding);

// when
embedding.set('embeddedComplex', undefined);

// then
expect(embedding.get('embeddedComplex')).not.to.exist;
expect(embeddedComplex.$parent).not.to.exist;
});


it('should not set parent if not model element', function() {

// given
var embedding = model.create('props:Embedding');

// when
embedding.set('foo', {});

// then
expect(embedding.get('foo').$parent).not.to.exist;
});


it('should not unset parent if not model element', function() {

// given
var foo = { $parent: true };

var embedding = model.create('props:Embedding', {
foo
});

// assume
expect(foo.$parent).to.exist;

// when
embedding.set('foo', undefined);

// then
expect(foo.$parent).to.exist;
});


it('should not set parent if model element is reference', function() {

// given
var referencingSingle = model.create('props:ReferencingSingle');

var referencedComplex = model.create('props:Complex');

// when
referencingSingle.set('referencedComplex', referencedComplex);

// then
expect(referencingSingle.get('referencedComplex')).to.equal(referencedComplex);
expect(referencedComplex.$parent).not.to.exist;
});

});


describe('many', function() {

it('should set parent if model elements', function() {

// given
var containedColllection = model.create('props:ContainedCollection');

var children = [
model.create('props:Complex'),
model.create('props:Complex')
];

// when
containedColllection.set('children', children);

// then
expect(containedColllection.get('children')).to.eql(children);

containedColllection.get('children').forEach(child => {
expect(child.$parent).to.equal(containedColllection);
});
});


it('should unset parent if model elements', function() {

// given
var fooChild = model.create('props:Complex'),
barChild = model.create('props:Complex');

var containedColllection = model.create('props:ContainedCollection', {
children: [
fooChild,
barChild
]
});

// when
containedColllection.set('children', [
fooChild
]);

// then
expect(containedColllection.get('children')).to.eql([ fooChild ]);

expect(fooChild.$parent).to.equal(containedColllection);
expect(barChild.$parent).not.to.exist;
});


it('should not set parent if not model element', function() {

// given
var containedCollection = model.create('props:ContainedCollection');

// when
containedCollection.set('foos', [
{},
{}
]);

// then
containedCollection.get('foos').forEach(foo => {
expect(foo.$parent).not.to.exist;
});
});

});

});

});

forEach([
false,
true,
Expand Down Expand Up @@ -315,6 +511,7 @@ describe('properties', function() {
});

});

});


Expand Down