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

Extended operations a.k.a. user-defined operations #284

Open
wants to merge 14 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
793 changes: 793 additions & 0 deletions EXTENDED.md

Large diffs are not rendered by default.

145 changes: 82 additions & 63 deletions README.md

Large diffs are not rendered by default.

239 changes: 235 additions & 4 deletions commonjs/core.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion commonjs/duplex.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
Object.defineProperty(exports, "__esModule", { value: true });
/*!
* https://github.com/Starcounter-Jack/JSON-Patch
* (c) 2017 Joachim Wester
* (c) 2017-2021 Joachim Wester
* MIT license
*/
var helpers_js_1 = require("./helpers.js");
Expand Down
74 changes: 74 additions & 0 deletions commonjs/helpers.js
Original file line number Diff line number Diff line change
Expand Up @@ -179,3 +179,77 @@ var PatchError = /** @class */ (function (_super) {
return PatchError;
}(Error));
exports.PatchError = PatchError;
// exported for use in jasmine test
exports.PROTO_ERROR_MSG = 'JSON-Patch: modifying `__proto__` or `constructor/prototype` prop is banned for security reasons, if this was on purpose, please set `banPrototypeModifications` flag false and pass it to this function. More info in fast-json-patch README';
function isValidExtendedOpId(xid) {
return typeof xid === 'string' && xid.length >= 3 && xid.indexOf('x-') === 0;
}
exports.isValidExtendedOpId = isValidExtendedOpId;
;
;
/**
* attach/remove source tree to/from target tree at appropriate path.
* modifies targetObj (in place) by reference.
*
* This is necessary to deal with JS "by value" semantics
*/
function _graftTree(sourceObj, targetObj, pathComponents) {
if (pathComponents.comps.length === 0) {
// no changes
return;
}
// traverse document trees until at the appropriate parent level
var graftTgt = targetObj;
var graft = sourceObj;
var graftKey = '';
// single component is top-level key
if (pathComponents.comps.length === 1) {
graftKey = pathComponents.comps[0];
if (pathComponents.modType === 'graft') {
graftTgt[graftKey] = graft[graftKey];
}
else {
// top-level prune is a "best guess" that the provided key was removed from
// the top-level object (we have no visibility into what the extended
// operator has actually done since it comes from "user-space";
// external to the extension api)
// NOTE: pruning is here only to allow the extension api to
// emulate the RFC api; user-defined operations may perform complex
// removals, but they may not be visible during the prune process.
// It is recommended that the user stick to the RFC 'remove' operation
// and not implemennt their own removal operations in extended-space;
// or at least limit removal to the provided path, and not perform other mutations
// combined with removals
if (Array.isArray(targetObj)) {
graftTgt.splice(~~graftKey, 1);
}
else {
delete graftTgt[graftKey];
}
}
return;
}
for (var i = 0; i < pathComponents.comps.length; i++) {
graftKey = pathComponents.comps[i];
graft = graft[graftKey];
// if there is no value in the target obj at the current key,
// than this is a graft point
if (pathComponents.modType === 'graft' && graftTgt[graftKey] === undefined) {
// if both target and source are undefined - No Op
if (graft === undefined) {
return;
}
break;
}
// there was a removal; the graft point needs to be the 2nd to last path comp
// a.k.a. the parent obj of the pruned key
// in order to preserve additional structure that was not pruned
if (i === pathComponents.comps.length - 2) {
break;
}
graftTgt = graftTgt[graftKey];
}
// graft
graftTgt[graftKey] = graft;
}
exports._graftTree = _graftTree;