json-prism
Version:
Immutable Prisms, i.e. Taking a Multifoci Json Path to Immutability, or A sentient item has some ability to communicate, either by sharing its emotions, broadcasting its thoughts telepathically, or speaking aloud.
573 lines (535 loc) • 20.9 kB
JavaScript
;
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/slicedToArray"));
var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
var _defineEnumerableProperties2 = _interopRequireDefault(require("@babel/runtime/helpers/defineEnumerableProperties"));
var _objectSpread2 = _interopRequireDefault(require("@babel/runtime/helpers/objectSpread"));
// const {has, returns} = require('shades');
var F = require('functional-pipelines');
var _require = require('../../utils/sortByPath'),
sortByPath = _require.sortByPath;
var _require2 = require('./SentientBatch'),
MultiWriter = _require2.MultiWriter;
var _require3 = require('rxjs'),
BehaviorSubject = _require3.BehaviorSubject;
var _require4 = require('rxjs/operators'),
take = _require4.take,
toArray = _require4.toArray;
var _require5 = require('../../utils/trace'),
show = _require5.show,
aLine = _require5.aLine;
describe('It should collect deep paths from existing stable-shaped-document (by design)', function () {
it('works', function (done) {
var MiniSeries = require('./mini-series.data'); // const nodes = jp.nodes(MiniSeries, '$..*');
// const pathSheet = nodes.map(({path, value}) => ([jp.stringify(path), value]));
var pathSheet = require('./path-sheet.data');
var pathList = [// '$.sequence',
// '$.episodes',
// '$.sequence[0]',
'$.sequence[1]', // '$.sequence[2]',
// '$.episodes.EP1',
// '$.episodes.EP2',
// '$.episodes.EP3',
// '$.episodes.EP1.sequence',
// '$.episodes.EP1.EP11',
// '$.episodes.EP1.EP12',
// '$.episodes.EP1.EP13',
// '$.episodes.EP1.sequence[0]',
'$.episodes.EP1.sequence[1]', // '$.episodes.EP1.sequence[2]',
// '$.episodes.EP1.EP11.start',
'$.episodes.EP1.EP11.start.place', '$.episodes.EP1.EP11.start.time', // '$.episodes.EP1.EP12.start',
// '$.episodes.EP1.EP12.start.place',
// '$.episodes.EP1.EP12.start.time',
// '$.episodes.EP1.EP13.start',
// '$.episodes.EP1.EP13.start.place',
// '$.episodes.EP1.EP13.start.time',
// '$.episodes.EP2.sequence',
// '$.episodes.EP2.EP21',
// '$.episodes.EP2.EP22',
// '$.episodes.EP2.EP23',
// '$.episodes.EP2.sequence[0]',
// '$.episodes.EP2.sequence[1]',
// '$.episodes.EP2.sequence[2]',
// '$.episodes.EP2.EP21.start',
// '$.episodes.EP2.EP21.start.place',
// '$.episodes.EP2.EP21.start.time',
// '$.episodes.EP2.EP22.start',
// '$.episodes.EP2.EP22.start.place',
// '$.episodes.EP2.EP22.start.time',
// '$.episodes.EP2.EP23.start',
// '$.episodes.EP2.EP23.start.place',
// '$.episodes.EP2.EP23.start.time',
// '$.episodes.EP3.sequence',
// '$.episodes.EP3.EP31',
// '$.episodes.EP3.EP32',
// '$.episodes.EP3.EP33',
// '$.episodes.EP3.sequence[0]',
// '$.episodes.EP3.sequence[1]',
// '$.episodes.EP3.sequence[2]',
// '$.episodes.EP3.EP31.start',
'$.episodes.EP3.EP31.start.place', '$.episodes.EP3.EP31.start.time', // '$.episodes.EP3.EP32.start',
'$.episodes.EP3.EP32.start.place', '$.episodes.EP3.EP32.start.time', // '$.episodes.EP3.EP33.start',
'$.episodes.EP3.EP33.start.place', '$.episodes.EP3.EP33.start.time'];
var journal = new BehaviorSubject({
value: MiniSeries
});
var clicks = 0;
var fs = require('fs'); // const journalLog = fs.createWriteStream('./journal-expected-log.json');
journal.subscribe(function (entry) {
show('+JournalEntry', ++clicks, entry, entry.gets ? entry.gets('$.___marker.version') : 'NO .gets');
}, function (error) {
return console.error(error);
});
journal.pipe(take(21), toArray()).subscribe(function (journal) {
try {
// expect(journal.map(({gets, sets, ...rest}) => rest)).toEqual(require('./journal-expected-stringified'));
// @NOTICE we strip out the gets/sets attrs before we compare with the JSON.stringified sanitized version of the json-tree
// journalLog.write(JSON.stringify(journal, null, 0) + '\n', undefined, done);
done();
} catch (error) {
done.fail(error);
}
}, function (error) {
return done.fail(error);
}, function () {
return (
/*journalLog.end(`@clicks: ${clicks}`),*/
show('ALL-DONE')
);
});
var multiCatcher = MultiWriter(journal, {
labels: ['BatchSentient-007']
})(pathList);
var v1Values = ["EP2", "EP12", "EP11-Place", "EP11 @ Wed May 15 2019 23:48:27 GMT+0200 (EET)", "EP31-Place", "EP31 @ Wed May 15 2019 23:48:27 GMT+0200 (EET)", "EP32-Place", "EP32 @ Wed May 15 2019 23:48:27 GMT+0200 (EET)", "EP33-Place", "EP33 @ Wed May 15 2019 23:48:27 GMT+0200 (EET)"];
expect(multiCatcher.updates()).toEqual(v1Values);
var notAvailables = [];
notAvailables.length = pathList.length;
notAvailables.fill('NOT-AVAILABLE');
var revisions = multiCatcher.updates(notAvailables);
expect(revisions.version).toEqual(notAvailables.length);
expect(revisions).toEqual({
"action": "set",
"gets": expect.any(Function),
"labels": ["BatchSentient-007"],
"path": "$.episodes.EP3.EP33.start.time",
"sets": expect.any(Function),
"value": {
"episodes": {
"EP1": {
"EP11": {
"start": {
"place": "NOT-AVAILABLE",
"time": "NOT-AVAILABLE"
}
},
"EP12": {
"start": {
"place": "EP12-Place",
"time": "EP12 @ Wed May 15 2019 23:48:27 GMT+0200 (EET)"
}
},
"EP13": {
"start": {
"place": "EP13-Place",
"time": "EP13 @ Wed May 15 2019 23:48:27 GMT+0200 (EET)"
}
},
"sequence": ["EP11", "NOT-AVAILABLE", "EP13"]
},
"EP2": {
"EP21": {
"start": {
"place": "EP21-Place",
"time": "EP21 @ Wed May 15 2019 23:48:27 GMT+0200 (EET)"
}
},
"EP22": {
"start": {
"place": "EP22-Place",
"time": "EP22 @ Wed May 15 2019 23:48:27 GMT+0200 (EET)"
}
},
"EP23": {
"start": {
"place": "EP23-Place",
"time": "EP23 @ Wed May 15 2019 23:48:27 GMT+0200 (EET)"
}
},
"sequence": ["EP21", "EP22", "EP23"]
},
"EP3": {
"EP31": {
"start": {
"place": "NOT-AVAILABLE",
"time": "NOT-AVAILABLE"
}
},
"EP32": {
"start": {
"place": "NOT-AVAILABLE",
"time": "NOT-AVAILABLE"
}
},
"EP33": {
"start": {
"place": "NOT-AVAILABLE",
"time": "NOT-AVAILABLE"
}
},
"sequence": ["EP31", "EP32", "EP33"]
}
},
"sequence": ["EP1", "NOT-AVAILABLE", "EP3"]
},
"version": 10
});
multiCatcher.updates(v1Values);
expect(multiCatcher.updates()).toEqual(v1Values);
});
}); ///// @TODO: LEGACY CODE AHEAD //////
describe.skip('scenario: shades', function () {
it('inspiration:: should handle binding', function () {
var base = {
IDTag: function IDTag() {
return this.tag;
}
};
var extended = (0, _objectSpread2["default"])({}, base, {
tag: 'hi'
});
expect(has({
IDTag: returns('hi')
})).toBeTruthy();
});
it('property accessors get/set do not survive shallow copying and turn into normal attributes', function () {
var _virtual, _base, _mutatorMap;
var base = (_base = {}, _virtual = 'virtual', _mutatorMap = {}, _mutatorMap[_virtual] = _mutatorMap[_virtual] || {}, _mutatorMap[_virtual].get = function () {
console.log('GET-ATTR');
return "Oh - ".concat(this.tag);
}, (0, _defineEnumerableProperties2["default"])(_base, _mutatorMap), _base);
var extended = (0, _objectSpread2["default"])({}, base, {
tag: 'hi'
});
expect(base.virtual).toEqual('Oh - undefined');
expect(extended.virtual).toEqual('Oh - undefined');
base.tag = 'Bye'; // old school patching
expect(base.virtual).toEqual('Oh - Bye');
expect(extended.virtual).toEqual('Oh - undefined'); // getter and setters don't survive the ...spread operator
});
it('should handle first-level (shallow) virtual accessors with context this', function () {
var forKey = function forKey(key) {
return (0, _defineProperty2["default"])({}, "".concat(key), function _(newValue) {
if (newValue === undefined) {
console.log('GET-ATTR');
return "Oh - ".concat(this.tag);
} else {
this.tag = newValue;
console.log('SET-ATTR');
return newValue;
}
});
};
var base = forKey('virtual');
expect(base.virtual()).toEqual('Oh - undefined');
var extended = (0, _objectSpread2["default"])({}, base, {
tag: 'hi',
childAttr: 'protected against access from base references'
});
expect(base.virtual()).toEqual('Oh - undefined');
expect(extended.virtual()).toEqual('Oh - hi');
base.virtual('Bye');
expect(base.virtual()).toEqual('Oh - Bye');
expect(extended.virtual()).toEqual('Oh - hi');
});
it('should handle first-level (shallow) virtual accessors with caller reference this', function () {
var forKey = function forKey(key) {
return (0, _defineProperty2["default"])({}, "".concat(key), function _(newValue) {
if (newValue === undefined) {
console.log('GET-ATTR');
return "Oh - ".concat(this.tag);
} else {
this.tag = newValue;
console.log('SET-ATTR');
return newValue;
}
});
};
var base = forKey('virtual');
expect(base.virtual()).toEqual('Oh - undefined');
var extended = (0, _objectSpread2["default"])({}, base, {
tag: 'hi',
childAttr: 'protected against access from base references'
});
expect(base.virtual()).toEqual('Oh - undefined');
expect(extended.virtual()).toEqual('Oh - hi');
base.virtual('Bye');
expect(base.virtual()).toEqual('Oh - Bye');
expect(extended.virtual()).toEqual('Oh - hi');
extended.virtual('Welcome');
expect(base.virtual()).toEqual('Oh - Bye');
expect(extended.virtual()).toEqual('Oh - Welcome');
});
it('should handle dynamic first-level (shallow) virtual accessors', function () {
var forKey = function forKey(key) {
return (0, _defineProperty2["default"])({}, "get".concat(key[0].toUpperCase()).concat(key.slice(1)), function get(newValue) {
if (newValue === undefined) {
console.log("GET-ATTR::".concat(key));
return this[key];
} else {
this[key] = newValue;
console.log("SET-ATTR::".concat(key));
return newValue;
}
});
};
var attrName = 'childAttr';
var expectedAccessorName = "get".concat(attrName[0].toUpperCase()).concat(attrName.slice(1));
var base = forKey('childAttr');
expect(base[expectedAccessorName]()).toEqual();
var theGist = 'protected against access from base references';
var extended = (0, _objectSpread2["default"])({}, base, {
tag: 'hi',
childAttr: theGist
});
expect(base[expectedAccessorName]()).toEqual();
expect(extended[expectedAccessorName]()).toEqual(theGist);
base[expectedAccessorName]('Bye');
expect(base[expectedAccessorName]()).toEqual('Bye');
expect(extended[expectedAccessorName]()).toEqual(theGist);
extended[expectedAccessorName]('Welcome');
expect(base[expectedAccessorName]()).toEqual('Bye');
expect(extended[expectedAccessorName]()).toEqual('Welcome');
});
});
describe.skip('Catchers', function () {
it('should handle dynamic first-level (shallow) virtual accessors', function () {
var catcher = function catcher(keys) {
var _ref6;
var setInto = function setInto(self) {
return function (name) {
return function (value) {
return self[name] = value;
};
};
};
var getFrom = function getFrom(self) {
return function (name) {
return self[name];
};
};
return _ref6 = {}, (0, _defineProperty2["default"])(_ref6, '___included', function ___included() {
return keys;
}), (0, _defineProperty2["default"])(_ref6, "get___", function get___(newValues) {
if (newValues === undefined) {
var getter = getFrom(this);
var ___included = this.___included();
console.log("GET-ATTR::".concat(___included));
return ___included.map(function (k) {
return getter(k);
});
} else {
var setter = setInto(this);
var _included = this.___included();
F.map(function (_ref4) {
var _ref5 = (0, _slicedToArray2["default"])(_ref4, 2),
k = _ref5[0],
nV = _ref5[1];
return setter(k)(nV);
}, F.zip(_included, newValues));
console.log("SET-ATTR::".concat(_included, " ---> ").concat(newValues));
return this; // mutating catcher
}
}), _ref6;
};
var attrName = 'childAttr';
var expectedAccessorName = "get___"; // const base = forKey('childAttr');
// expect(base[expectedAccessorName]()).toEqual();
var theGist = 'protected against access from base references';
var theList = ['tag', attrName, 'notThere', 'not-there', 'catchMeIYCe', 'catchMeiyce', 'catch[Mice]', 'catchMeIntoYourContainer', 'catchMeIntoYourContainerEventually'];
var shallowCatcher = catcher(theList);
var extended = (0, _objectSpread2["default"])({}, shallowCatcher, {
tag: 'hi',
childAttr: theGist,
catchMeIYC: {},
catchMeIntoYourContainer: []
});
var lotsOfUndefind = [];
lotsOfUndefind.length = theList.length;
expect(shallowCatcher[expectedAccessorName]()).toEqual(lotsOfUndefind);
var catcherResults = ['hi', theGist,,,,,, [], undefined];
expect(extended[expectedAccessorName]()).toEqual(catcherResults);
shallowCatcher[expectedAccessorName]('Bye');
var stringIteratorResults = ["B", "y", "e", undefined, undefined, undefined, undefined, undefined, undefined];
expect(shallowCatcher[expectedAccessorName]()).toEqual(stringIteratorResults);
expect(extended[expectedAccessorName]()).toEqual(catcherResults);
expect(extended).toEqual({
"___included": expect.any(Function),
"catchMeIYC": {},
"catchMeIntoYourContainer": [],
"childAttr": "protected against access from base references",
"get___": expect.any(Function),
"tag": "hi"
});
extended[expectedAccessorName]('Welcome');
expect(shallowCatcher[expectedAccessorName]()).toEqual(stringIteratorResults);
expect(extended[expectedAccessorName]()).toEqual(["W", "e", "l", "c", "o", "m", "e", [], undefined]);
expect(extended).toEqual({
"___included": expect.any(Function),
"catchMeIYC": {},
"catchMeIYCe": "o",
"catchMeIntoYourContainer": [],
"catchMeiyce": "m",
"catch[Mice]": "e",
"childAttr": "e",
"get___": expect.any(Function),
"not-there": "c",
"notThere": "l",
"tag": "W"
});
});
it('should handle dynamic json-atom immutable virtual accessors', function () {
// const catcher = function (keys) {
// const setInto = self => path => value => set(`$.${path}`)(value)(self);
// const getFrom = self => path => get(`$.${path}`)(self);
//
// return {
// ['___included']() {
// return keys;
// },
// //
// [`get___`](newValues) {
// if (newValues === undefined) {
// const getter = getFrom(this);
// const ___included = this.___included();
// console.log(`GET-ATTR::${___included}`);
// return ___included.map(k => (console.log('<< K::', k), console.log('<< V::', getter(k)), getter(k)));
// } else {
// const setter = setInto(this);
// const ___included = this.___included();
//
// const reducingFn = ({revisionSetter, value}, [k, nV]) => {
// const newRevision = revisionSetter(k)(nV);
// return {revisionSetter: setInto(newRevision), value: newRevision};
// };
// const initFn = () => ({revisionSetter: setInto(this)});
// const enumerable = F.zip(___included, newValues);
// const resultFn = x => x.value;
//
//
// const revisions = F.reduce(reducingFn, initFn, enumerable, resultFn);
// //
// // const revisions = F.map(
// // ([k, nV]) => (console.log('>> K::', k), console.log('>> V::', nV), setter(k)(nV)),
// // F.zip(___included, newValues));
// console.log(`SET-ATTR::${___included} ---> ${JSON.stringify(newValues, null, 0)}`);
// return revisions;
// }
// }
// };
// };
var attrName = 'childAttr';
var expectedAccessorName = "get___"; // const base = forKey('childAttr');
// expect(base[expectedAccessorName]()).toEqual();
var theGist = 'protected against access from base references';
var theList = ['a1', 'a1.b1', 'a1.b1.c1', 'a1.b1.c1.name', 'a1.b1.c1.id', 'a2', 'a2.b2', 'a2.b2[0]', 'a2.b2[0].value'];
var theProvided = [{}, {}, {
id: '007'
}, 'Bond ... James Bond', 'SLYD', {}, [], {
value: 'Gothca'
}, {
value: 'NO!'
}];
expect(theList.length).toEqual(theProvided.length);
var accessors = require('./accessors');
var deepCatcher = accessors.catcher(theList);
var extended = (0, _objectSpread2["default"])({}, deepCatcher, {
a1: {
some: 'a1-stale-value',
b1: {
value: 'b1-stale-value'
}
},
catchMeIntoYourContainer: []
});
var lotsOfUndefind = [];
lotsOfUndefind.length = theList.length;
expect(function () {
return deepCatcher[expectedAccessorName]();
}).toThrow(/Cannot read property 'b1' of undefined/); // Cannot read property 'c1' of undefined
var catcherResults = ['hi', theGist,,,,,, [], undefined];
expect(function () {
return extended[expectedAccessorName]();
}).toThrow(/Cannot read property 'name' of undefined/);
var newRevision = deepCatcher[expectedAccessorName](theProvided);
expect(newRevision).toEqual({
"___included": expect.any(Function),
"a1": {
"b1": {
"c1": {
"id": "SLYD",
"name": "Bond ... James Bond"
}
}
},
"a2": {
"b2": [{
"value": {
"value": "NO!"
}
}]
},
"get___": expect.any(Function)
});
expect(function () {
return deepCatcher[expectedAccessorName]();
}).toThrow(/Cannot read property 'b1' of undefined/);
expect(function () {
return extended[expectedAccessorName]();
}).toThrow(/Cannot read property 'name' of undefined/);
expect(extended).toEqual({
"___included": expect.any(Function),
"a1": {
"b1": {
"value": "b1-stale-value"
},
"some": "a1-stale-value"
},
"catchMeIntoYourContainer": [],
"get___": expect.any(Function)
});
var extendedNewRevision = (0, _objectSpread2["default"])({}, deepCatcher, newRevision);
expect(extendedNewRevision.___included()).toEqual(["a1", "a1.b1", "a1.b1.c1", "a1.b1.c1.name", "a1.b1.c1.id", "a2", "a2.b2", "a2.b2[0]", "a2.b2[0].value"]);
expect(extendedNewRevision[expectedAccessorName]()).toEqual([{
"b1": {
"c1": {
"id": "SLYD",
"name": "Bond ... James Bond"
}
}
}, {
"c1": {
"id": "SLYD",
"name": "Bond ... James Bond"
}
}, {
"id": "SLYD",
"name": "Bond ... James Bond"
}, "Bond ... James Bond", "SLYD", {
"b2": [{
"value": {
"value": "NO!"
}
}]
}, [{
"value": {
"value": "NO!"
}
}], {
"value": {
"value": "NO!"
}
}, {
"value": "NO!"
}]);
});
});