UNPKG

diffusion

Version:

Diffusion JavaScript client

406 lines (405 loc) 13.1 kB
"use strict"; /** * @module diffusion.datatypes */ var __values = (this && this.__values) || function(o) { var s = typeof Symbol === "function" && Symbol.iterator, m = s && o[s], i = 0; if (m) return m.call(o); if (o && typeof o.length === "number") return { next: function () { if (o && i >= o.length) o = void 0; return { value: o && o[i++], done: !o }; } }; throw new TypeError(s ? "Object is not iterable." : "Symbol.iterator is not defined."); }; Object.defineProperty(exports, "__esModule", { value: true }); exports.ROOT = exports.JSONPointer = exports.KeySegment = exports.IndexSegment = void 0; var errors_1 = require("./../../../errors/errors"); var math_1 = require("./../../util/math"); /** * JSONPointer segment representing an index */ var IndexSegment = /** @class */ (function () { /** * Create a new IndexSegment * * @param index the index of the segment */ function IndexSegment(index) { this.index = index; } /** * Compare two segments. * * Allows comparison of the IndexSegment with another IndexSegment or a * {@link KeySegment}. * * @return 'true' if the other segment is an IndexSegment and the indexes are equal */ IndexSegment.prototype.equals = function (other) { if (other === this) { return true; } if (!other || !(other instanceof IndexSegment)) { return false; } return other.index === this.index; }; /** * Convert the index segment to a string * * @returns a string representation of the segment */ IndexSegment.prototype.toString = function () { return '/' + this.index; }; return IndexSegment; }()); exports.IndexSegment = IndexSegment; var INDEX0 = new IndexSegment(0); /** * JSONPointer segment representing a key * @param key * @constructor */ var KeySegment = /** @class */ (function () { /** * Create a new KeySegment * * @param key the key of the segment */ function KeySegment(key) { this.expression = '/' + escapeKey(key); } /** * Compare two segments. * * Allows comparison of the KeySegment with another KeySegment or a * {@link IndexSegment}. * * @return 'true' if the other segment is an KeySegment and the keys are equal */ KeySegment.prototype.equals = function (other) { if (other === this) { return true; } if (!other || !(other instanceof KeySegment)) { return false; } return other.expression === this.expression; }; /** * Convert the key segment to a string * * @returns a string representation of the segment */ KeySegment.prototype.toString = function () { return this.expression; }; return KeySegment; }()); exports.KeySegment = KeySegment; /** * A parser for parsing JSON pointer string expressions to JSON pointer objects */ var Parser = /** @class */ (function () { /** * Create a new parser * * @param expression the expression to be parsed * @throws an {@link IllegalArgumentError} if the expression is not correctly formatted */ function Parser(expression) { // each iteration leaves p at the next separator this.pos = 0; if (expression !== '' && expression.charAt(0) !== '/') { throw new errors_1.IllegalArgumentError('JSON Pointer expression must be empty or start with \'/\' : ' + expression); } this.expression = expression; } /** * Get the next segment string * * @return a string containing the next segment */ Parser.prototype.nextSegmentString = function () { var start = this.pos; for (; this.pos < this.expression.length; ++this.pos) { var c = this.expression[this.pos]; if (c === '/') { break; } else if (c === '~') { var parts = [this.expression.substring(start, this.pos)]; var length_1 = this.expression.length; for (; this.pos < length_1; ++this.pos) { var c1 = this.expression.charAt(this.pos); if (c1 === '/') { break; } else if (c1 === '~' && this.pos !== length_1 - 1) { ++this.pos; var c2 = this.expression.charAt(this.pos); if (c2 === '0') { parts.push('~'); } else if (c2 === '1') { parts.push('/'); } else { parts.push('~'); parts.push(c2); } } else { parts.push(c1); } } return parts.join(''); } } return this.expression.substring(start, this.pos); }; /** * Create an index segment, if the string contains an index. * * The index must be the decimal representation of a positive 32 bit integer * without leading `0` or `+` * * @return a new index segment if the string contained an index, otherwise `null` */ Parser.prototype.maybeIndex = function (s) { var digits = s.length; // numbers with more than ten digits are larger than MAX_INT32 if (digits === 0 || digits > 10) { return null; } for (var i = 0; i < digits; ++i) { var c = s.charAt(i); if (c < '0' || c > '9') { return null; } if (c === '0' && i === 0) { // no leading zeroes allowed return digits === 1 ? INDEX0 : null; } } var index = parseInt(s, 10); // cap at max int32 if (index > math_1.MAX_INT32) { return null; } return new IndexSegment(index); }; /** * Get the next segment * * @return a key segment or an index segment. `null` if there are no more segments */ Parser.prototype.next = function () { if (this.pos === this.expression.length) { return null; } ++this.pos; var s = this.nextSegmentString(); var is = this.maybeIndex(s); if (is !== null) { return is; } return new KeySegment(s); }; return Parser; }()); /** * JSON Pointer implementation that allows incremental building of pointers. * * @param nodes - Segments from parent context * @constructor * @since 5.9 */ var JSONPointer = /** @class */ (function () { /** * Create a JSONPointer * * @param segments segments from parent context */ function JSONPointer(segments) { this.segments = segments; } /** * Parse a string containing a JSON pointer into a JSONPointer object. * * A segment that has only decimal digits will be interpreted as an index unless it has leading zeros * (RFC 6901, section4), or its value is larger than Integer.MAX_VALUE * * @param expression a string containing the JSON pointer expression. If a JSONPointer object * is supplied, then it will be returned unchanged * @returns a JSONPointer that corresponds to the expression * @throws an {@link IllegalArgumentError} if the expression is not correctly formatted */ JSONPointer.parse = function (expression) { if (expression instanceof JSONPointer) { return expression; } /* tslint:disable-next-line:no-use-before-declare */ var result = exports.ROOT; var segmentParser = new Parser(expression); // eslint-disable-next-line no-constant-condition while (true) { var s = segmentParser.next(); if (s === null) { return result; } result = result.withSegment(s); } }; /** * Append a key segment to the pointer * * @return a new instance equal to this instance with key appended */ JSONPointer.prototype.withKey = function (key) { return this.withSegment(new KeySegment(key)); }; /** * Append a index segment to the pointer * * @return a new instance equal to this instance with index appended */ JSONPointer.prototype.withIndex = function (index) { return this.withSegment(new IndexSegment(index)); }; /** * Append a segment to the pointer * * @return a new instance equal to this instance with segment appended */ JSONPointer.prototype.withSegment = function (newNode) { var newNodes = this.segments.concat(newNode); return new JSONPointer(newNodes); }; /** * Returns whether this JSONPointer is equal to another JSONPointer, * ignoring the values of array index segments. * * This implements an equivalence relation between JSONPointers that * considers two values equal if they have the same number of segments, * corresponding segments are of the same type, and corresponding key * segments are equal. It is used by the structural delta code to identify * potential matches between two pointers to different values. * * @param other the other pointer to compare to * @returns whether the other pointer is equal (ignoring indexes) */ JSONPointer.prototype.equalIgnoringIndexes = function (other) { if (other === this) { return true; } var length = this.segments.length; if (length !== other.segments.length) { return false; } for (var i = 0; i < length; ++i) { var s = this.segments[i]; var o = other.segments[i]; if (s instanceof IndexSegment) { if (o instanceof KeySegment) { return false; } } else if (!s.equals(o)) { return false; } } return true; }; /** * Convert the JSON pointer to a string * * @returns the JSONPointer expression */ JSONPointer.prototype.toString = function () { var e_1, _a; var parts = []; try { for (var _b = __values(this.segments), _c = _b.next(); !_c.done; _c = _b.next()) { var segment = _c.value; parts.push(segment.toString()); } } catch (e_1_1) { e_1 = { error: e_1_1 }; } finally { try { if (_c && !_c.done && (_a = _b.return)) _a.call(_b); } finally { if (e_1) throw e_1.error; } } return parts.join(''); }; /** * Compare two JSONPointer objects * * Non-equal JSONPointer instances can have the same expression. * E.g. ROOT.withIndex(1) is not equal to ROOT.withKey('1'), but both have the same expression '/1' * * @param other the other pointer instance to compare to * @returns whether the two instances are equal */ JSONPointer.prototype.equals = function (other) { if (other === this) { return true; } if (!other || !(other instanceof JSONPointer)) { return false; } if (this.segments.length !== other.segments.length) { return false; } var length = this.segments.length; for (var i = 0; i < length; ++i) { var s1 = this.segments[i]; var s2 = other.segments[i]; if (!s1.equals(s2)) { return false; } } return true; }; return JSONPointer; }()); exports.JSONPointer = JSONPointer; /** * JSONPointer representing the root */ exports.ROOT = new JSONPointer([]); /** * Escape special characters in the JSON pointer key string * * @param key the key string to escape * @return the escaped string */ function escapeKey(key) { for (var i = 0; i < key.length; ++i) { var c = key.charAt(i); if (c === '/' || c === '~') { var length_2 = key.length; var parts = []; parts.push(key.substring(0, i)); for (var j = i; j < length_2; ++j) { var c1 = key.charAt(j); if (c1 === '/') { parts.push('~1'); } else if (c1 === '~') { parts.push('~0'); } else { parts.push(c1); } } return parts.join(''); } } return key; }