Skip to content

Commit

Permalink
Merge pull request #30 from canjs/defined-keys
Browse files Browse the repository at this point in the history
adding `parentHasKey` to return value of read()
  • Loading branch information
phillipskevin authored Jun 6, 2018
2 parents e2dc850 + 0bbbace commit 395ec6f
Show file tree
Hide file tree
Showing 2 changed files with 93 additions and 10 deletions.
77 changes: 74 additions & 3 deletions can-stache-key-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ test("can read from strings", function(){
);
});

test("read / write to DefineMap", function(){
test("read / write to SimpleMap", function(){
var map = new SimpleMap();
var c = new Observation(function(){
var data = observeReader.read(map,observeReader.reads("value"),{
Expand All @@ -154,7 +154,7 @@ test("read / write to DefineMap", function(){
observeReader.write(map,"value",1);
});

test("write deep in DefineMap", function(){
test("write deep in SimpleMap", function(){
var map = new SimpleMap();
observeReader.write(map,"foo", new SimpleMap());
observeReader.write(map,"foo.bar", 1);
Expand Down Expand Up @@ -227,7 +227,6 @@ QUnit.test("set onto observable objects and values", function(){

QUnit.equal(map.get("a"), "b", "merged");


var simple = new SimpleObservable();
observeReader.write({simple: simple},"simple", 1);
QUnit.equal(simple.get(), 1);
Expand Down Expand Up @@ -266,3 +265,75 @@ QUnit.test("writing to a null observable is ignored", function(){
observeReader.write(null,"foo.bar", "value");
QUnit.ok(true, "all passed without error");
});

QUnit.test("read sets parentHasKey even for undefined values", function() {
var child = {
prop: "foo"
};
canReflect.assignSymbols(child, {
"can.hasKey": function(key) {
return key === "prop" || key === "undefinedProp";
}
});

var parent = {
child: child
};
canReflect.assignSymbols(parent, {
"can.hasKey": function(key) {
return key === "child" || key === "undefinedChild";
}
});

var map = {
parent: parent
};

// map.parent
var reads = observeReader.reads("parent");
var value = observeReader.read(map, reads);

QUnit.equal(value.value, parent, "parent.value === map");
QUnit.equal(value.parent, map, "parent.parent === map");
QUnit.equal(value.parentHasKey, true, "parent.parentHasKey === true");

// map.parent.child
reads = observeReader.reads("parent.child");
value = observeReader.read(map, reads);

QUnit.equal(value.value, child, "parent.child.value === child");
QUnit.equal(value.parent, parent, "parent.child.parent === parent");
QUnit.equal(value.parentHasKey, true, "parent.child.parentHasKey === true");

// map.parent.undefinedChild
reads = observeReader.reads("parent.undefinedChild");
value = observeReader.read(map, reads);

QUnit.equal(value.value, undefined, "parent.undefinedChild.value === undefined");
QUnit.equal(value.parent, parent, "parent.undefinedChild.parent === parent");
QUnit.equal(value.parentHasKey, true, "parent.undefinedChild.parentHasKey === true");

// map.parent.undefinedChild.prop
reads = observeReader.reads("parent.undefinedChild.prop");
value = observeReader.read(map, reads);

QUnit.equal(value.value, undefined, "parent.undefinedChild.prop.value === undefined");
QUnit.equal(value.parent, parent, "parent.undefinedChild.prop.parent === parent");
QUnit.equal(value.parentHasKey, true, "parent.undefinedChild.prop.parentHasKey === true");

// map.parent.child.prop
reads = observeReader.reads("parent.child.prop");
value = observeReader.read(map, reads);

QUnit.equal(value.value, "foo", "parent.child.prop.value === 'foo'");
QUnit.equal(value.parent, child, "parent.child.prop.parent === child");
QUnit.equal(value.parentHasKey, true, "parent.child.prop.parentHasKey === true");

// map.parent.child.undefinedProp
reads = observeReader.reads("parent.child.undefinedProp");
value = observeReader.read(map, reads);

QUnit.equal(value.value, undefined, "parent.child.undefinedProp.value === undefined");
QUnit.equal(value.parent, child, "parent.child.undefinedProp.parent === child");
QUnit.equal(value.parentHasKey, true, "parent.child.undefinedProp.parentHasKey === true");
});
26 changes: 19 additions & 7 deletions can-stache-key.js
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,14 @@ var checkForObservableAndNotify = function(options, state, getObserves, value, i
}
};

var objHasKeyAtIndex = function(obj, reads, index) {
return !!(
obj && typeof obj === "object" &&
reads && reads.length &&
canReflect.hasKey(obj, reads[index].key)
);
};

observeReader = {
// there are things that you need to evaluate when you get them back as a property read
// for example a compute or a function you might need to call to get the next value to
Expand Down Expand Up @@ -88,7 +96,8 @@ observeReader = {
// `foundObs` did we find an observable.
readLength = reads.length,
i = 0,
last;
last,
parentHasKey;

checkForObservableAndNotify(options, state, getObserves, parent, 0);

Expand All @@ -110,31 +119,34 @@ observeReader = {

checkForObservableAndNotify(options, state, getObserves, prev, i-1);



type = typeof cur;
// early exit if need be
if (i < reads.length && (cur === null || cur === undefined )) {
if (options.earlyExit) {
parentHasKey = objHasKeyAtIndex(prev, reads, i - 1);
if (options.earlyExit && !parentHasKey) {
options.earlyExit(prev, i - 1, cur);
}
// return undefined so we know this isn't the right value
return {
value: undefined,
parent: prev
parent: prev,
parentHasKey: parentHasKey
};
}

}

parentHasKey = objHasKeyAtIndex(prev, reads, reads.length - 1);
// if we don't have a value, exit early.
if (cur === undefined) {
if (cur === undefined && !parentHasKey) {
if (options.earlyExit) {
options.earlyExit(prev, i - 1);
}
}
return {
value: cur,
parent: prev
parent: prev,
parentHasKey: parentHasKey
};
},
get: function(parent, reads, options){
Expand Down

0 comments on commit 395ec6f

Please sign in to comment.