@threads/json-patch-ot
Advanced tools
Comparing version
@@ -0,1 +1,8 @@ | ||
# [1.1.0](https://github.com/ThreadsStyling/json-patch-ot/compare/v1.0.1...v1.1.0) (2019-07-08) | ||
### Features | ||
* prepping for public release ([#11](https://github.com/ThreadsStyling/json-patch-ot/issues/11)) ([7827cdb](https://github.com/ThreadsStyling/json-patch-ot/commit/7827cdb)) | ||
## [1.0.1](https://github.com/ThreadsStyling/json-patch-ot/compare/v1.0.0...v1.0.1) (2019-06-28) | ||
@@ -2,0 +9,0 @@ |
@@ -41,4 +41,14 @@ export interface Options { | ||
} | ||
export declare type PathProp = 'path' | 'from'; | ||
export declare type Operation = OperationAdd | OperationRemove | OperationReplace | OperationCopy | OperationMove | OperationTest; | ||
export declare type PathOperation = OperationAdd | OperationRemove | OperationReplace | OperationTest; | ||
export declare type FromOperation = OperationMove | OperationCopy; | ||
export declare type Operation = FromOperation | PathOperation; | ||
export declare type PathProp = keyof Pick<PathOperation & FromOperation, 'from' | 'path'>; | ||
/** | ||
* Takes array of proposed patches and transforms them against an array of already accepted patches. | ||
* @param acceptedOps Array of already accepted patches | ||
* @param proposedOps Array of proposed patches | ||
* @param options Options object | ||
* | ||
* @returns Array of transformed changes | ||
*/ | ||
export default function JSONPatchOT(acceptedOps: Operation[], proposedOps: Operation[], options?: Options): Operation[]; |
@@ -13,8 +13,9 @@ "use strict"; | ||
})(OpType = exports.OpType || (exports.OpType = {})); | ||
const shiftIndices = (acceptedOp, proposedOps, isAdd = false, pathProp = 'path') => { | ||
const lastSlash = acceptedOp[pathProp].lastIndexOf('/'); | ||
function shiftIndices(acceptedOp, proposedOps, isAdd = false, pathProp = 'path') { | ||
const path = acceptedOp[pathProp]; | ||
const lastSlash = path.lastIndexOf('/'); | ||
if (lastSlash === -1) | ||
return; | ||
const index = acceptedOp[pathProp].substr(lastSlash + 1); | ||
const arrayPath = acceptedOp[pathProp].substr(0, lastSlash + 1); | ||
const index = path.substr(lastSlash + 1); | ||
const arrayPath = path.substr(0, lastSlash + 1); | ||
if (!utils_1.isValidIndex(index)) | ||
@@ -25,2 +26,4 @@ return; | ||
if (pathOfSameArray) { | ||
// Does not use `pathProp` on the proposedOp since we need to deal with | ||
// both path types on the proposedOp anyway. See below it deals with `from`. | ||
proposedOp.path = utils_1.replacePathIndices(proposedOp.path, arrayPath, index, isAdd); | ||
@@ -34,16 +37,23 @@ } | ||
} | ||
}; | ||
} | ||
const allowWhitelist = (acceptedOp, proposedOp) => { | ||
return (proposedOp.op === 'add' || proposedOp.op === 'test') && acceptedOp.path === proposedOp.path; | ||
}; | ||
const removeOperations = (acceptedOp, proposedOps, options, skipWhitelist = false, pathProp = 'path') => { | ||
const isFromOperation = (operation) => { | ||
return operation.op === OpType.move || operation.op === OpType.copy; | ||
}; | ||
function removeOperations(acceptedOp, proposedOps, options, skipWhitelist = false, pathProp = 'path') { | ||
const { acceptedWinsOnEqualPath } = options; | ||
let currentIndex = 0; | ||
let proposedOp; | ||
// remove operation objects within replaced JSON node | ||
while (proposedOps[currentIndex]) { | ||
proposedOp = proposedOps[currentIndex]; | ||
const matchesFromToPath = proposedOp.from && | ||
(proposedOp.from === acceptedOp[pathProp] || proposedOp.from.indexOf(acceptedOp[pathProp] + '/') === 0); | ||
const matchesPathToPath = (acceptedWinsOnEqualPath && acceptedOp[pathProp] === proposedOp.path) || | ||
proposedOp.path.indexOf(acceptedOp[pathProp] + '/') === 0; | ||
let matchesFromToPath = false; | ||
const acceptedPath = acceptedOp[pathProp]; | ||
if (isFromOperation(proposedOp)) { | ||
matchesFromToPath = proposedOp.from === acceptedPath || proposedOp.from.indexOf(acceptedPath + '/') === 0; | ||
} | ||
const matchesPathToPath = (acceptedWinsOnEqualPath && acceptedPath === proposedOp.path) || | ||
proposedOp.path.indexOf(`${acceptedPath}/`) === 0; | ||
const shouldSkip = skipWhitelist ? allowWhitelist(acceptedOp, proposedOp) : false; | ||
@@ -56,3 +66,3 @@ if (!shouldSkip && (matchesFromToPath || matchesPathToPath)) { | ||
} | ||
}; | ||
} | ||
const removeTransformer = (acceptedOp, proposedOps) => { | ||
@@ -69,7 +79,11 @@ removeOperations(acceptedOp, proposedOps, { acceptedWinsOnEqualPath: true }, true); | ||
}; | ||
const copyTransformer = (acceptedOp, proposedOps, options) => { | ||
shiftIndices(acceptedOp, proposedOps, true); | ||
removeOperations(acceptedOp, proposedOps, options); | ||
}; | ||
const moveTransformer = (acceptedOp, proposedOps, options) => { | ||
removeOperations(acceptedOp, proposedOps, { acceptedWinsOnEqualPath: true }, true, 'from'); | ||
shiftIndices(acceptedOp, proposedOps, false, 'from'); | ||
shiftIndices(acceptedOp, proposedOps, true, 'path'); | ||
removeOperations(acceptedOp, proposedOps, options, false, 'path'); | ||
removeOperations(acceptedOp, proposedOps, { acceptedWinsOnEqualPath: true }, true, 'from'); // like a remove | ||
shiftIndices(acceptedOp, proposedOps, false, 'from'); // like a remove | ||
shiftIndices(acceptedOp, proposedOps, true, 'path'); // like an add | ||
removeOperations(acceptedOp, proposedOps, options, false, 'path'); // like an add | ||
}; | ||
@@ -80,4 +94,5 @@ const transformAgainst = { | ||
[OpType.add]: addTransformer, | ||
[OpType.copy]: addTransformer, | ||
[OpType.copy]: copyTransformer, | ||
[OpType.move]: moveTransformer, | ||
[OpType.test]: undefined, | ||
}; | ||
@@ -90,2 +105,10 @@ const reduceJSONPatches = (options) => (proposedOps, acceptedOp) => { | ||
}; | ||
/** | ||
* Takes array of proposed patches and transforms them against an array of already accepted patches. | ||
* @param acceptedOps Array of already accepted patches | ||
* @param proposedOps Array of proposed patches | ||
* @param options Options object | ||
* | ||
* @returns Array of transformed changes | ||
*/ | ||
function JSONPatchOT(acceptedOps, proposedOps, options = {}) { | ||
@@ -92,0 +115,0 @@ const clonedProposed = JSON.parse(JSON.stringify(proposedOps)); |
@@ -15,6 +15,7 @@ "use strict"; | ||
const rest = result.substr(slashIndex); | ||
// For incUp we need to match equal to aswell since that element will be bumped foreward. | ||
const isOldBigger = incUp ? oldIndex >= index : oldIndex > index; | ||
const shouldChangeIndex = isValidIndex(oldIndex) && isOldBigger; | ||
if (shouldChangeIndex) { | ||
return arrayPath + (parseInt(oldIndex, 10) + (incUp ? 1 : -1)) + rest; | ||
return `${arrayPath}${parseInt(oldIndex, 10) + (incUp ? 1 : -1)}${rest}`; | ||
} | ||
@@ -21,0 +22,0 @@ else { |
{ | ||
"name": "@threads/json-patch-ot", | ||
"version": "1.0.1", | ||
"version": "1.1.0", | ||
"description": "Library to reconcile JSON patch changes using Operational Transformation", | ||
@@ -25,3 +25,3 @@ "main": "lib/index.js", | ||
"lint": "yarn tslint", | ||
"tslint": "tslint './src/**/*.{ts,tsx}' -t verbose", | ||
"tslint": "tslint './src/**/*.{ts,tsx}' -t verbose -p .", | ||
"commitmsg": "commitlint -E GIT_PARAMS" | ||
@@ -52,3 +52,3 @@ }, | ||
"@semantic-release/npm": "^4.0.0", | ||
"@threads/tslint": "^3.1.0", | ||
"@threads/tsconfig": "^1.0.0", | ||
"@types/jest": "^23.1.5", | ||
@@ -66,3 +66,3 @@ "@types/node": "^10.5.2", | ||
"tslint": "^5.10.0", | ||
"typescript": "^2.9.2" | ||
"typescript": "^3.5.2" | ||
}, | ||
@@ -69,0 +69,0 @@ "dependencies": {}, |
@@ -9,2 +9,4 @@ # json-patch-ot | ||
**Note:** This project only exposes commonjs es2018 modules. | ||
## Example | ||
@@ -14,2 +16,4 @@ | ||
```js | ||
import jsonPatchOT, { Operation } from "@threads/json-patch-ot"; | ||
// [0, 1, 2, 3, 4, 5, 6]; <- Starting array | ||
@@ -48,2 +52,4 @@ const acceptedOps: Operation[] = [ | ||
```js | ||
import jsonPatchOT, { Operation } from "@threads/json-patch-ot"; | ||
const options = {acceptedWinsOnEqualPath: true}; | ||
@@ -66,1 +72,13 @@ const acceptedOps: Operation[] = [ | ||
<!-- prettier-ignore-end --> | ||
## Acknowledgements | ||
Thanks to Palindrom's [JSON-Patch-OT](https://github.com/Palindrom/JSON-Patch-OT/) lib which this was originally built upon. | ||
## License | ||
MIT | ||
## Work in progress | ||
**Please note:** This is a work in progress. You are free to use it how you like, but be aware that you do so at your own risk. |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
Mixed license
License(Experimental) Package contains multiple licenses.
Found 1 instance in 1 package
107748
516.27%19
111.11%947
503.18%81
28.57%1
Infinity%1
Infinity%