Comparing version 2.4.0 to 3.0.0
@@ -58,12 +58,25 @@ import { Pointer } from './pointer'; | ||
/** | ||
subtract(a, b) returns the keys in `a` that are not in `b`. | ||
List the keys in `minuend` that are not in `subtrahend`. | ||
A key is only considered if it is both 1) an own-property (o.hasOwnProperty(k)) | ||
of the object, and 2) has a value that is not undefined. This is to match JSON | ||
semantics, where JSON object serialization drops keys with undefined values. | ||
@param minuend Object of interest | ||
@param subtrahend Object of comparison | ||
@returns Array of keys that are in `minuend` but not in `subtrahend`. | ||
*/ | ||
export declare function subtract<A, B>(a: A, b: B): string[]; | ||
export declare function subtract(minuend: object, subtrahend: object): string[]; | ||
/** | ||
intersection(objects) returns the keys that shared by all given `objects`. | ||
List the keys that shared by all `objects`. | ||
The semantics of what constitutes a "key" is described in {@link subtract}. | ||
@param objects Array of objects to compare | ||
@returns Array of keys that are in ("own-properties" of) every object in `objects`. | ||
*/ | ||
export declare function intersection<T>(objects: T[]): string[]; | ||
export declare function objectType(object: any): string; | ||
export declare function intersection(objects: ArrayLike<object>): string[]; | ||
/** | ||
Array-diffing smarter (levenshtein-like) diffing here | ||
Calculate the shortest sequence of operations to get from `input` to `output`, | ||
using a dynamic programming implementation of the Levenshtein distance algorithm. | ||
@@ -87,5 +100,8 @@ To get from the input ABC to the output AZ we could just delete all the input | ||
if input (source) is empty, they'll all be in the top row, just a bunch of | ||
additions. If the output is empty, everything will be in the left column, as a | ||
bunch of deletions. | ||
If the `input` (source) is empty, they'll all be in the top row, resulting in an | ||
array of 'add' operations. | ||
If the `output` (target) is empty, everything will be in the left column, | ||
resulting in an array of 'remove' operations. | ||
@returns A list of add/remove/replace operations. | ||
*/ | ||
@@ -92,0 +108,0 @@ export declare function diffArrays<T>(input: T[], output: T[], ptr: Pointer, diff?: Diff): Operation[]; |
165
diff.js
@@ -10,12 +10,29 @@ "use strict"; | ||
/** | ||
subtract(a, b) returns the keys in `a` that are not in `b`. | ||
List the keys in `minuend` that are not in `subtrahend`. | ||
A key is only considered if it is both 1) an own-property (o.hasOwnProperty(k)) | ||
of the object, and 2) has a value that is not undefined. This is to match JSON | ||
semantics, where JSON object serialization drops keys with undefined values. | ||
@param minuend Object of interest | ||
@param subtrahend Object of comparison | ||
@returns Array of keys that are in `minuend` but not in `subtrahend`. | ||
*/ | ||
function subtract(a, b) { | ||
function subtract(minuend, subtrahend) { | ||
// initialize empty object; we only care about the keys, the values can be anything | ||
var obj = {}; | ||
for (var add_key in a) { | ||
obj[add_key] = 1; | ||
// build up obj with all the properties of minuend | ||
for (var add_key in minuend) { | ||
if (minuend.hasOwnProperty(add_key) && minuend[add_key] !== undefined) { | ||
obj[add_key] = 1; | ||
} | ||
} | ||
for (var del_key in b) { | ||
delete obj[del_key]; | ||
// now delete all the properties of subtrahend from obj | ||
// (deleting a missing key has no effect) | ||
for (var del_key in subtrahend) { | ||
if (subtrahend.hasOwnProperty(del_key) && subtrahend[del_key] !== undefined) { | ||
delete obj[del_key]; | ||
} | ||
} | ||
// finally, extract whatever keys remain in obj | ||
return Object.keys(obj); | ||
@@ -25,35 +42,32 @@ } | ||
/** | ||
intersection(objects) returns the keys that shared by all given `objects`. | ||
List the keys that shared by all `objects`. | ||
The semantics of what constitutes a "key" is described in {@link subtract}. | ||
@param objects Array of objects to compare | ||
@returns Array of keys that are in ("own-properties" of) every object in `objects`. | ||
*/ | ||
function intersection(objects) { | ||
// initialize like union() | ||
var key_counts = {}; | ||
objects.forEach(function (object) { | ||
var length = objects.length; | ||
// prepare empty counter to keep track of how many objects each key occurred in | ||
var counter = {}; | ||
// go through each object and increment the counter for each key in that object | ||
for (var i = 0; i < length; i++) { | ||
var object = objects[i]; | ||
for (var key in object) { | ||
key_counts[key] = (key_counts[key] || 0) + 1; | ||
if (object.hasOwnProperty(key) && object[key] !== undefined) { | ||
counter[key] = (counter[key] || 0) + 1; | ||
} | ||
} | ||
}); | ||
// but then, extra requirement: delete less commonly-seen keys | ||
var threshold = objects.length; | ||
for (var key in key_counts) { | ||
if (key_counts[key] < threshold) { | ||
delete key_counts[key]; | ||
} | ||
// now delete all keys from the counter that were not seen in every object | ||
for (var key in counter) { | ||
if (counter[key] < length) { | ||
delete counter[key]; | ||
} | ||
} | ||
return Object.keys(key_counts); | ||
// finally, extract whatever keys remain in the counter | ||
return Object.keys(counter); | ||
} | ||
exports.intersection = intersection; | ||
function objectType(object) { | ||
if (object === undefined) { | ||
return 'undefined'; | ||
} | ||
if (object === null) { | ||
return 'null'; | ||
} | ||
if (Array.isArray(object)) { | ||
return 'array'; | ||
} | ||
return typeof object; | ||
} | ||
exports.objectType = objectType; | ||
function isArrayAdd(array_operation) { | ||
@@ -65,7 +79,12 @@ return array_operation.op === 'add'; | ||
} | ||
function isArrayReplace(array_operation) { | ||
return array_operation.op === 'replace'; | ||
function appendArrayOperation(base, operation) { | ||
return { | ||
// the new operation must be pushed on the end | ||
operations: base.operations.concat(operation), | ||
cost: base.cost + 1, | ||
}; | ||
} | ||
/** | ||
Array-diffing smarter (levenshtein-like) diffing here | ||
Calculate the shortest sequence of operations to get from `input` to `output`, | ||
using a dynamic programming implementation of the Levenshtein distance algorithm. | ||
@@ -89,5 +108,8 @@ To get from the input ABC to the output AZ we could just delete all the input | ||
if input (source) is empty, they'll all be in the top row, just a bunch of | ||
additions. If the output is empty, everything will be in the left column, as a | ||
bunch of deletions. | ||
If the `input` (source) is empty, they'll all be in the top row, resulting in an | ||
array of 'add' operations. | ||
If the `output` (target) is empty, everything will be in the left column, | ||
resulting in an array of 'remove' operations. | ||
@returns A list of add/remove/replace operations. | ||
*/ | ||
@@ -101,10 +123,10 @@ function diffArrays(input, output, ptr, diff) { | ||
/** | ||
input[i's] -> output[j's] | ||
Calculate the cheapest sequence of operations required to get from | ||
input.slice(0, i) to output.slice(0, j). | ||
There may be other valid sequences with the same cost, but none cheaper. | ||
Given the layout above, i is the row, j is the col | ||
returns a list of Operations needed to get to from input.slice(0, i) to | ||
output.slice(0, j), the each marked with the total cost of getting there. | ||
`cost` is a non-negative integer. | ||
Recursive. | ||
@param i The row in the layout above | ||
@param j The column in the layout above | ||
@returns An object containing a list of operations, along with the total cost | ||
of applying them (+1 for each add/remove/replace operation) | ||
*/ | ||
@@ -116,3 +138,3 @@ function dist(i, j) { | ||
if (memoized === undefined) { | ||
if (equal_1.compare(input[i - 1], output[j - 1])) { | ||
if (i > 0 && j > 0 && equal_1.compare(input[i - 1], output[j - 1])) { | ||
// equal (no operations => no cost) | ||
@@ -125,23 +147,18 @@ memoized = dist(i - 1, j - 1); | ||
// NOT topmost row | ||
var remove_alternative = dist(i - 1, j); | ||
alternatives.push({ | ||
// the new operation must be pushed on the end | ||
operations: remove_alternative.operations.concat({ | ||
op: 'remove', | ||
index: i - 1, | ||
}), | ||
cost: remove_alternative.cost + 1, | ||
}); | ||
var remove_base = dist(i - 1, j); | ||
var remove_operation = { | ||
op: 'remove', | ||
index: i - 1, | ||
}; | ||
alternatives.push(appendArrayOperation(remove_base, remove_operation)); | ||
} | ||
if (j > 0) { | ||
// NOT leftmost column | ||
var add_alternative = dist(i, j - 1); | ||
alternatives.push({ | ||
operations: add_alternative.operations.concat({ | ||
op: 'add', | ||
index: i - 1, | ||
value: output[j - 1], | ||
}), | ||
cost: add_alternative.cost + 1, | ||
}); | ||
var add_base = dist(i, j - 1); | ||
var add_operation = { | ||
op: 'add', | ||
index: i - 1, | ||
value: output[j - 1], | ||
}; | ||
alternatives.push(appendArrayOperation(add_base, add_operation)); | ||
} | ||
@@ -151,15 +168,13 @@ if (i > 0 && j > 0) { | ||
// supposing we replaced it, compute the rest of the costs: | ||
var replace_alternative = dist(i - 1, j - 1); | ||
var replace_base = dist(i - 1, j - 1); | ||
// okay, the general plan is to replace it, but we can be smarter, | ||
// recursing into the structure and replacing only part of it if | ||
// possible, but to do so we'll need the original value | ||
alternatives.push({ | ||
operations: replace_alternative.operations.concat({ | ||
op: 'replace', | ||
index: i - 1, | ||
original: input[i - 1], | ||
value: output[j - 1], | ||
}), | ||
cost: replace_alternative.cost + 1, | ||
}); | ||
var replace_operation = { | ||
op: 'replace', | ||
index: i - 1, | ||
original: input[i - 1], | ||
value: output[j - 1], | ||
}; | ||
alternatives.push(appendArrayOperation(replace_base, replace_operation)); | ||
} | ||
@@ -239,4 +254,4 @@ // the only other case, i === 0 && j === 0, has already been memoized | ||
if (diff === void 0) { diff = diffAny; } | ||
var input_type = objectType(input); | ||
var output_type = objectType(output); | ||
var input_type = equal_1.objectType(input); | ||
var output_type = equal_1.objectType(output); | ||
if (input_type == 'array' && output_type == 'array') { | ||
@@ -243,0 +258,0 @@ return diffArrays(input, output, ptr, diff); |
@@ -0,1 +1,2 @@ | ||
export declare function objectType(object: any): "string" | "number" | "boolean" | "symbol" | "undefined" | "object" | "function" | "null" | "array"; | ||
/** | ||
@@ -2,0 +3,0 @@ `compare()` returns true if `left` and `right` are materially equal |
62
equal.js
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
/** | ||
zip(a, b) assumes that a.length === b.length. | ||
*/ | ||
function zip(a, b) { | ||
var zipped = []; | ||
for (var i = 0, l = a.length; i < l; i++) { | ||
zipped.push([a[i], b[i]]); | ||
function objectType(object) { | ||
if (object === undefined) { | ||
return 'undefined'; | ||
} | ||
return zipped; | ||
if (object === null) { | ||
return 'null'; | ||
} | ||
if (Array.isArray(object)) { | ||
return 'array'; | ||
} | ||
return typeof object; | ||
} | ||
exports.objectType = objectType; | ||
/** | ||
compareArrays(left, right) assumes that `left` and `right` are both Arrays. | ||
Evaluate `left === right`, treating `left` and `right` as ordered lists. | ||
@returns true iff `left` and `right` have identical lengths, and every element | ||
of `left` is equal to the corresponding element of `right`. Equality is | ||
determined recursivly, via `compare`. | ||
*/ | ||
function compareArrays(left, right) { | ||
if (left.length !== right.length) { | ||
var length = left.length; | ||
if (length !== right.length) { | ||
return false; | ||
} | ||
return zip(left, right).every(function (pair) { return compare(pair[0], pair[1]); }); | ||
for (var i = 0; i < length; i++) { | ||
if (!compare(left[i], right[i])) { | ||
return false; | ||
} | ||
} | ||
return true; | ||
} | ||
/** | ||
compareObjects(left, right) assumes that `left` and `right` are both Objects. | ||
Evaluate `left === right`, treating `left` and `right` as property maps. | ||
@returns true iff every property in `left` has a value equal to the value of the | ||
corresponding property in `right`, and vice-versa, stopping as soon as | ||
possible. Equality is determined recursivly, via `compare`. | ||
*/ | ||
@@ -28,6 +45,17 @@ function compareObjects(left, right) { | ||
var right_keys = Object.keys(right); | ||
if (!compareArrays(left_keys, right_keys)) { | ||
var length = left_keys.length; | ||
// quick exit if the number of keys don't match up | ||
if (length !== right_keys.length) { | ||
return false; | ||
} | ||
return left_keys.every(function (key) { return compare(left[key], right[key]); }); | ||
// we don't know for sure that Set(left_keys) is equal to Set(right_keys), | ||
// much less that their values in left and right are equal, but if right | ||
// contains each key in left, we know it can't have any additional keys | ||
for (var i = 0; i < length; i++) { | ||
var key = left_keys[i]; | ||
if (!right.hasOwnProperty(key) || !compare(left[key], right[key])) { | ||
return false; | ||
} | ||
} | ||
return true; | ||
} | ||
@@ -61,8 +89,10 @@ /** | ||
} | ||
var left_type = objectType(left); | ||
var right_type = objectType(right); | ||
// check arrays | ||
if (Array.isArray(left) && Array.isArray(right)) { | ||
if (left_type == 'array' && right_type == 'array') { | ||
return compareArrays(left, right); | ||
} | ||
// check objects | ||
if (Object(left) === left && Object(right) === right) { | ||
if (left_type == 'object' && right_type == 'object') { | ||
return compareObjects(left, right); | ||
@@ -69,0 +99,0 @@ } |
"use strict"; | ||
var __extends = (this && this.__extends) || (function () { | ||
var extendStatics = Object.setPrototypeOf || | ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || | ||
function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; }; | ||
var extendStatics = function (d, b) { | ||
extendStatics = Object.setPrototypeOf || | ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || | ||
function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; }; | ||
return extendStatics(d, b); | ||
} | ||
return function (d, b) { | ||
@@ -13,13 +16,2 @@ extendStatics(d, b); | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
var MissingError = /** @class */ (function (_super) { | ||
__extends(MissingError, _super); | ||
function MissingError(path) { | ||
var _this = _super.call(this, "Value required at path: " + path) || this; | ||
_this.path = path; | ||
_this.name = 'MissingError'; | ||
return _this; | ||
} | ||
return MissingError; | ||
}(Error)); | ||
exports.MissingError = MissingError; | ||
var InvalidOperationError = /** @class */ (function (_super) { | ||
@@ -36,15 +28,1 @@ __extends(InvalidOperationError, _super); | ||
exports.InvalidOperationError = InvalidOperationError; | ||
var TestError = /** @class */ (function (_super) { | ||
__extends(TestError, _super); | ||
function TestError(actual, expected) { | ||
var _this = _super.call(this, "Test failed: " + actual + " != " + expected) || this; | ||
_this.actual = actual; | ||
_this.expected = expected; | ||
_this.name = 'TestError'; | ||
_this.actual = actual; | ||
_this.expected = expected; | ||
return _this; | ||
} | ||
return TestError; | ||
}(Error)); | ||
exports.TestError = TestError; |
@@ -14,10 +14,9 @@ import { Operation, TestOperation, VoidableDiff } from './diff'; | ||
This method currently operates on the target object in-place. | ||
This method mutates the target object in-place. | ||
Returns list of results, one for each operation. | ||
- `null` indicated success. | ||
- otherwise, the result will be an instance of one of the Error classe | ||
defined in errors.js. | ||
@returns list of results, one for each operation: `null` indicated success, | ||
otherwise, the result will be an instance of one of the Error classes: | ||
MissingError, InvalidOperationError, or TestError. | ||
*/ | ||
export declare function applyPatch(object: any, patch: any): any; | ||
export declare function applyPatch(object: any, patch: Operation[]): (import("./patch").MissingError | import("./patch").TestError | import("./patch").InvalidOperationError)[]; | ||
/** | ||
@@ -24,0 +23,0 @@ Produce a 'application/json-patch+json'-type patch to get from one object to |
25
index.js
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
var errors_1 = require("./errors"); | ||
var pointer_1 = require("./pointer"); | ||
var operationFunctions = require("./patch"); | ||
var patch_1 = require("./patch"); | ||
var diff_1 = require("./diff"); | ||
@@ -17,18 +16,10 @@ /** | ||
This method currently operates on the target object in-place. | ||
This method mutates the target object in-place. | ||
Returns list of results, one for each operation. | ||
- `null` indicated success. | ||
- otherwise, the result will be an instance of one of the Error classe | ||
defined in errors.js. | ||
@returns list of results, one for each operation: `null` indicated success, | ||
otherwise, the result will be an instance of one of the Error classes: | ||
MissingError, InvalidOperationError, or TestError. | ||
*/ | ||
function applyPatch(object, patch) { | ||
return patch.map(function (operation) { | ||
var operationFunction = operationFunctions[operation.op]; | ||
// speedy exit if we don't recognize the operation name | ||
if (operationFunction === undefined) { | ||
return new errors_1.InvalidOperationError(operation.op); | ||
} | ||
return operationFunction(object, operation); | ||
}); | ||
return patch.map(function (operation) { return patch_1.apply(object, operation); }); | ||
} | ||
@@ -63,2 +54,6 @@ exports.applyPatch = applyPatch; | ||
exports.createPatch = createPatch; | ||
/** | ||
Create a test operation based on `input`'s current evaluation of the JSON | ||
Pointer `path`; if such a pointer cannot be resolved, returns undefined. | ||
*/ | ||
function createTest(input, path) { | ||
@@ -65,0 +60,0 @@ var endpoint = pointer_1.Pointer.fromJSON(path).evaluate(input); |
{ | ||
"name": "rfc6902", | ||
"version": "2.4.0", | ||
"version": "3.0.0", | ||
"description": "Complete implementation of RFC6902 (patch and diff)", | ||
@@ -12,19 +12,14 @@ "keywords": [ | ||
"homepage": "https://github.com/chbrown/rfc6902", | ||
"repository": { | ||
"type": "git", | ||
"url": "https://github.com/chbrown/rfc6902.git" | ||
}, | ||
"repository": "github:chbrown/rfc6902", | ||
"author": "Christopher Brown <io@henrian.com> (http://henrian.com)", | ||
"license": "MIT", | ||
"devDependencies": { | ||
"@types/js-yaml": "^3.11.1", | ||
"@types/mocha": "^5.2.2", | ||
"@types/node": "^10.3.3", | ||
"coveralls": "^3.0.1", | ||
"istanbul": "0.4.5", | ||
"@types/js-yaml": "^3.11.2", | ||
"@types/node": "10.9.4", | ||
"ava": "1.0.0-beta.7", | ||
"coveralls": "^3.0.2", | ||
"js-yaml": "3.12.0", | ||
"mocha": "^5.2.0", | ||
"mocha-lcov-reporter": "1.3.0", | ||
"rollup": "^0.60.7", | ||
"typescript": "^2.9.2" | ||
"nyc": "12.0.2", | ||
"rollup": "^0.65.0", | ||
"typescript": "^3.0.1" | ||
}, | ||
@@ -34,4 +29,4 @@ "scripts": { | ||
"pretest": "tsc", | ||
"test": "istanbul cover _mocha -- tests/ -R spec", | ||
"posttest": "coveralls < coverage/lcov.info || true", | ||
"test": "nyc ava", | ||
"posttest": "nyc report --reporter=text-lcov | coveralls || true", | ||
"dist": "tsc -t ES2015 -m es2015 && rollup index.js --output.format umd --name rfc6902 --output.file dist/rfc6902.js && closure-compiler dist/rfc6902.js > dist/rfc6902.min.js", | ||
@@ -38,0 +33,0 @@ "clean": "tsc -d --listEmittedFiles | sed 's/^TSFILE: //' | xargs rm -v" |
@@ -1,2 +0,11 @@ | ||
import { MissingError, TestError } from './errors'; | ||
import { AddOperation, RemoveOperation, ReplaceOperation, MoveOperation, CopyOperation, TestOperation, Operation } from './diff'; | ||
export declare class MissingError extends Error { | ||
path: string; | ||
constructor(path: string); | ||
} | ||
export declare class TestError extends Error { | ||
actual: any; | ||
expected: any; | ||
constructor(actual: any, expected: any); | ||
} | ||
/** | ||
@@ -10,3 +19,3 @@ > o If the target location specifies an array index, a new value is | ||
*/ | ||
export declare function add(object: any, operation: any): MissingError; | ||
export declare function add(object: any, operation: AddOperation): MissingError | null; | ||
/** | ||
@@ -16,3 +25,3 @@ > The "remove" operation removes the value at the target location. | ||
*/ | ||
export declare function remove(object: any, operation: any): MissingError; | ||
export declare function remove(object: any, operation: RemoveOperation): MissingError | null; | ||
/** | ||
@@ -30,3 +39,3 @@ > The "replace" operation replaces the value at the target location | ||
*/ | ||
export declare function replace(object: any, operation: any): MissingError; | ||
export declare function replace(object: any, operation: ReplaceOperation): MissingError | null; | ||
/** | ||
@@ -47,3 +56,3 @@ > The "move" operation removes the value at a specified location and | ||
*/ | ||
export declare function move(object: any, operation: any): MissingError; | ||
export declare function move(object: any, operation: MoveOperation): MissingError | null; | ||
/** | ||
@@ -62,3 +71,3 @@ > The "copy" operation copies the value at a specified location to the | ||
*/ | ||
export declare function copy(object: any, operation: any): MissingError; | ||
export declare function copy(object: any, operation: CopyOperation): MissingError | null; | ||
/** | ||
@@ -72,2 +81,11 @@ > The "test" operation tests that a value at the target location is | ||
*/ | ||
export declare function test(object: any, operation: any): TestError; | ||
export declare function test(object: any, operation: TestOperation): TestError | null; | ||
export declare class InvalidOperationError extends Error { | ||
operation: Operation; | ||
constructor(operation: Operation); | ||
} | ||
/** | ||
Switch on `operation.op`, applying the corresponding patch function for each | ||
case to `object`. | ||
*/ | ||
export declare function apply(object: any, operation: Operation): MissingError | InvalidOperationError | TestError | null; |
122
patch.js
"use strict"; | ||
var __extends = (this && this.__extends) || (function () { | ||
var extendStatics = function (d, b) { | ||
extendStatics = Object.setPrototypeOf || | ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || | ||
function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; }; | ||
return extendStatics(d, b); | ||
} | ||
return function (d, b) { | ||
extendStatics(d, b); | ||
function __() { this.constructor = d; } | ||
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); | ||
}; | ||
})(); | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
var pointer_1 = require("./pointer"); | ||
var util_1 = require("./util"); | ||
var equal_1 = require("./equal"); | ||
var errors_1 = require("./errors"); | ||
var MissingError = /** @class */ (function (_super) { | ||
__extends(MissingError, _super); | ||
function MissingError(path) { | ||
var _this = _super.call(this, "Value required at path: " + path) || this; | ||
_this.path = path; | ||
_this.name = 'MissingError'; | ||
return _this; | ||
} | ||
return MissingError; | ||
}(Error)); | ||
exports.MissingError = MissingError; | ||
var TestError = /** @class */ (function (_super) { | ||
__extends(TestError, _super); | ||
function TestError(actual, expected) { | ||
var _this = _super.call(this, "Test failed: " + actual + " != " + expected) || this; | ||
_this.actual = actual; | ||
_this.expected = expected; | ||
_this.name = 'TestError'; | ||
_this.actual = actual; | ||
_this.expected = expected; | ||
return _this; | ||
} | ||
return TestError; | ||
}(Error)); | ||
exports.TestError = TestError; | ||
function _add(object, key, value) { | ||
@@ -13,3 +51,4 @@ if (Array.isArray(object)) { | ||
else { | ||
object.splice(key, 0, value); | ||
var index = parseInt(key, 10); | ||
object.splice(index, 0, value); | ||
} | ||
@@ -24,3 +63,4 @@ } | ||
// '-' syntax doesn't make sense when removing | ||
object.splice(key, 1); | ||
var index = parseInt(key, 10); | ||
object.splice(index, 1); | ||
} | ||
@@ -44,3 +84,3 @@ else { | ||
if (endpoint.parent === undefined) { | ||
return new errors_1.MissingError(operation.path); | ||
return new MissingError(operation.path); | ||
} | ||
@@ -59,3 +99,3 @@ _add(endpoint.parent, endpoint.key, operation.value); | ||
if (endpoint.value === undefined) { | ||
return new errors_1.MissingError(operation.path); | ||
return new MissingError(operation.path); | ||
} | ||
@@ -81,4 +121,14 @@ // not sure what the proper behavior is when path = '' | ||
var endpoint = pointer_1.Pointer.fromJSON(operation.path).evaluate(object); | ||
if (endpoint.value === undefined) | ||
return new errors_1.MissingError(operation.path); | ||
if (endpoint.parent === null) { | ||
return new MissingError(operation.path); | ||
} | ||
// this existence check treats arrays as a special case | ||
if (Array.isArray(endpoint.parent)) { | ||
if (parseInt(endpoint.key, 10) >= endpoint.parent.length) { | ||
return new MissingError(operation.path); | ||
} | ||
} | ||
else if (endpoint.value === undefined) { | ||
return new MissingError(operation.path); | ||
} | ||
endpoint.parent[endpoint.key] = operation.value; | ||
@@ -105,7 +155,9 @@ return null; | ||
var from_endpoint = pointer_1.Pointer.fromJSON(operation.from).evaluate(object); | ||
if (from_endpoint.value === undefined) | ||
return new errors_1.MissingError(operation.from); | ||
if (from_endpoint.value === undefined) { | ||
return new MissingError(operation.from); | ||
} | ||
var endpoint = pointer_1.Pointer.fromJSON(operation.path).evaluate(object); | ||
if (endpoint.parent === undefined) | ||
return new errors_1.MissingError(operation.path); | ||
if (endpoint.parent === undefined) { | ||
return new MissingError(operation.path); | ||
} | ||
_remove(from_endpoint.parent, from_endpoint.key); | ||
@@ -131,9 +183,10 @@ _add(endpoint.parent, endpoint.key, from_endpoint.value); | ||
var from_endpoint = pointer_1.Pointer.fromJSON(operation.from).evaluate(object); | ||
if (from_endpoint.value === undefined) | ||
return new errors_1.MissingError(operation.from); | ||
if (from_endpoint.value === undefined) { | ||
return new MissingError(operation.from); | ||
} | ||
var endpoint = pointer_1.Pointer.fromJSON(operation.path).evaluate(object); | ||
if (endpoint.parent === undefined) | ||
return new errors_1.MissingError(operation.path); | ||
_remove(from_endpoint.parent, from_endpoint.key); | ||
_add(endpoint.parent, endpoint.key, from_endpoint.value); | ||
if (endpoint.parent === undefined) { | ||
return new MissingError(operation.path); | ||
} | ||
_add(endpoint.parent, endpoint.key, util_1.clone(from_endpoint.value)); | ||
return null; | ||
@@ -153,6 +206,37 @@ } | ||
var result = equal_1.compare(endpoint.value, operation.value); | ||
if (!result) | ||
return new errors_1.TestError(endpoint.value, operation.value); | ||
if (!result) { | ||
return new TestError(endpoint.value, operation.value); | ||
} | ||
return null; | ||
} | ||
exports.test = test; | ||
var InvalidOperationError = /** @class */ (function (_super) { | ||
__extends(InvalidOperationError, _super); | ||
function InvalidOperationError(operation) { | ||
var _this = _super.call(this, "Invalid operation: " + operation.op) || this; | ||
_this.operation = operation; | ||
_this.name = 'InvalidOperationError'; | ||
return _this; | ||
} | ||
return InvalidOperationError; | ||
}(Error)); | ||
exports.InvalidOperationError = InvalidOperationError; | ||
/** | ||
Switch on `operation.op`, applying the corresponding patch function for each | ||
case to `object`. | ||
*/ | ||
function apply(object, operation) { | ||
// not sure why TypeScript can't infer typesafety of: | ||
// {add, remove, replace, move, copy, test}[operation.op](object, operation) | ||
// (seems like a bug) | ||
switch (operation.op) { | ||
case 'add': return add(object, operation); | ||
case 'remove': return remove(object, operation); | ||
case 'replace': return replace(object, operation); | ||
case 'move': return move(object, operation); | ||
case 'copy': return copy(object, operation); | ||
case 'test': return test(object, operation); | ||
} | ||
return new InvalidOperationError(operation); | ||
} | ||
exports.apply = apply; |
@@ -19,4 +19,5 @@ export interface PointerEvaluation { | ||
Returns an object with 'parent', 'key', and 'value' properties. | ||
In the special case that pointer = "", parent and key will be null, and `value = obj` | ||
Otherwise, parent will be the such that `parent[key] == value` | ||
In the special case that this Pointer's path == "", | ||
this object will be {parent: null, key: '', value: object}. | ||
Otherwise, parent and key will have the property such that parent[key] == value. | ||
*/ | ||
@@ -23,0 +24,0 @@ evaluate(object: any): PointerEvaluation; |
@@ -59,16 +59,17 @@ "use strict"; | ||
Returns an object with 'parent', 'key', and 'value' properties. | ||
In the special case that pointer = "", parent and key will be null, and `value = obj` | ||
Otherwise, parent will be the such that `parent[key] == value` | ||
In the special case that this Pointer's path == "", | ||
this object will be {parent: null, key: '', value: object}. | ||
Otherwise, parent and key will have the property such that parent[key] == value. | ||
*/ | ||
Pointer.prototype.evaluate = function (object) { | ||
var parent = null; | ||
var key = ''; | ||
var value = object; | ||
var parent = null; | ||
var token = null; | ||
for (var i = 1, l = this.tokens.length; i < l; i++) { | ||
parent = value; | ||
token = this.tokens[i]; | ||
key = this.tokens[i]; | ||
// not sure if this the best way to handle non-existant paths... | ||
value = (parent || {})[token]; | ||
value = (parent || {})[key]; | ||
} | ||
return { parent: parent, key: token, value: value }; | ||
return { parent: parent, key: key, value: value }; | ||
}; | ||
@@ -75,0 +76,0 @@ Pointer.prototype.get = function (object) { |
# rfc6902 | ||
[![latest version published to npm](https://badge.fury.io/js/rfc6902.svg)](https://www.npmjs.com/package/rfc6902) | ||
[![monthly downloads from npm](https://img.shields.io/npm/dm/rfc6902.svg?style=flat)](https://www.npmjs.com/package/rfc6902) | ||
[![Travis CI build status](https://travis-ci.org/chbrown/rfc6902.svg?branch=master)](https://travis-ci.org/chbrown/rfc6902) | ||
@@ -5,0 +6,0 @@ [![Coverage status on Coveralls](https://coveralls.io/repos/github/chbrown/rfc6902/badge.svg?branch=master)](https://coveralls.io/github/chbrown/rfc6902?branch=master) |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
No repository
Supply chain riskPackage does not have a linked source code repository. Without this field, a package will have no reference to the location of the source code use to generate the package.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
56100
8
17
1130
188
1