UNPKG

codemirror-ot

Version:

Operational Transformation adapter for CodeMirror 6.

1,397 lines (1,288 loc) 1 MB
'use strict'; var assert = require('assert'); var json1 = require('ot-json1'); var json0 = require('ot-json0'); var state = require('@codemirror/state'); var fs = require('fs'); var path = require('path'); var jsdom = require('jsdom'); var ShareDB = require('sharedb'); function _interopNamespaceDefault(e) { var n = Object.create(null); if (e) { Object.keys(e).forEach(function (k) { if (k !== 'default') { var d = Object.getOwnPropertyDescriptor(e, k); Object.defineProperty(n, k, d.get ? d : { enumerable: true, get: function () { return e[k]; } }); } }); } n.default = e; return Object.freeze(n); } var assert__namespace = /*#__PURE__*/_interopNamespaceDefault(assert); var fs__namespace = /*#__PURE__*/_interopNamespaceDefault(fs); var path__namespace = /*#__PURE__*/_interopNamespaceDefault(path); function getDefaultExportFromCjs (x) { return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x; } var dist$1 = {}; var unicount = {}; var hasRequiredUnicount; function requireUnicount () { if (hasRequiredUnicount) return unicount; hasRequiredUnicount = 1; Object.defineProperty(unicount, "__esModule", { value: true }); unicount.uniToStrPos = unicount.strPosToUni = void 0; unicount.strPosToUni = (s, strOffset = s.length) => { let pairs = 0; let i = 0; for (; i < strOffset; i++) { const code = s.charCodeAt(i); if (code >= 0xd800 && code <= 0xdfff) { pairs++; i++; // Skip the second part of the pair. } } if (i !== strOffset) throw Error('Invalid offset - splits unicode bytes'); return i - pairs; }; unicount.uniToStrPos = (s, uniOffset) => { let pos = 0; for (; uniOffset > 0; uniOffset--) { const code = s.charCodeAt(pos); pos += code >= 0xd800 && code <= 0xdfff ? 2 : 1; } return pos; }; return unicount; } var type = {}; var hasRequiredType; function requireType () { if (hasRequiredType) return type; hasRequiredType = 1; (function (exports) { /* Text OT! * * This is an OT implementation for text. It is the standard implementation of * text used by ShareJS. * * This type is composable and by default non-invertable (operations do not by * default contain enough information to invert them). Its similar to ShareJS's * old text-composable type, but its not invertable and its very similar to the * text-tp2 implementation but it doesn't support tombstones or purging. * * Ops are lists of components which iterate over the document. Components are * either: * * - A number N: Skip N characters in the original document * - "str": Insert "str" at the current position in the document * - {d:N}: Delete N characters at the current position in the document * - {d:"str"}: Delete "str" at the current position in the document. This is * equivalent to {d:N} but provides extra information for operation * invertability. * * Eg: [3, 'hi', 5, {d:8}] * * The operation does not have to skip the last characters in the document. * * Snapshots are by default strings. * * Cursors are either a single number (which is the cursor position) or a pair * of [anchor, focus] (aka [start, end]). Be aware that end can be before start. * * The actual string type is configurable. The OG default exposed text type uses * raw javascript strings, but they're not compatible with OT implementations in * other languages because string.length returns the wrong value for unicode * characters that don't fit in 2 bytes. And JS strings are quite an inefficient * data structure for manipulating lines & UTF8 offsets. For this reason, you * can use your own data structure underneath the text OT code. * * Note that insert operations themselves are always raw strings. Its just * snapshots that are configurable. */ Object.defineProperty(exports, "__esModule", { value: true }); exports.uniSlice = exports.dlen = exports.eachOp = void 0; const unicount_1 = requireUnicount(); /** Check the operation is valid. Throws if not valid. */ const checkOp = (op) => { if (!Array.isArray(op)) throw Error('Op must be an array of components'); let last = null; for (let i = 0; i < op.length; i++) { const c = op[i]; switch (typeof c) { case 'object': // The only valid objects are {d:X} for +ive values of X or non-empty strings. if (typeof c.d !== 'number' && typeof c.d !== 'string') throw Error('Delete must be number or string'); if (exports.dlen(c.d) <= 0) throw Error('Deletes must not be empty'); break; case 'string': // Strings are inserts. if (!(c.length > 0)) throw Error('Inserts cannot be empty'); break; case 'number': // Numbers must be skips. They have to be +ive numbers. if (!(c > 0)) throw Error('Skip components must be >0'); if (typeof last === 'number') throw Error('Adjacent skip components should be combined'); break; } last = c; } if (typeof last === 'number') throw Error('Op has a trailing skip'); }; // TODO: Consider exposing this at the library level. // TODO: Also consider rewriting this to use es iterators instead of callback-passing style. function eachOp(op, fn) { let prePos = 0, postPos = 0; for (let i = 0; i < op.length; i++) { const c = op[i]; fn(c, prePos, postPos); switch (typeof c) { case 'object': // Delete prePos += exports.dlen(c.d); break; case 'string': // Insert postPos += unicount_1.strPosToUni(c); break; case 'number': // Skip prePos += c; postPos += c; break; } } } exports.eachOp = eachOp; function mapOp(op, fn) { const newOp = []; const append = makeAppend(newOp); eachOp(op, (c, prePos, postPos) => { append(fn(c, prePos, postPos)); }); return trim(newOp); } const id = (x) => x; const normalize = (op) => { return mapOp(op, id); }; exports.dlen = (d) => typeof d === 'number' ? d : unicount_1.strPosToUni(d); /** Make a function that appends to the given operation. */ const makeAppend = (op) => (component) => { if (!component || component.d === 0 || component.d === '') ; else if (op.length === 0) { op.push(component); } else if (typeof component === typeof op[op.length - 1]) { if (typeof component === 'object') { // Concatenate deletes. This is annoying because the op or component could // contain strings or numbers. const last = op[op.length - 1]; last.d = typeof last.d === 'string' && typeof component.d === 'string' ? last.d + component.d // Preserve invert information : exports.dlen(last.d) + exports.dlen(component.d); // Discard invert information, if any. // (op[op.length - 1] as {d:number}).d += component.d } else { // Concat strings / inserts. TSC should be smart enough for this :p op[op.length - 1] += component; } } else { op.push(component); } }; /** Get the length of a component */ const componentLength = (c) => (typeof c === 'number' ? c : typeof c === 'string' ? unicount_1.strPosToUni(c) : typeof c.d === 'number' ? c.d : unicount_1.strPosToUni(c.d)); // Does not support negative numbers. exports.uniSlice = (s, startUni, endUni) => { const start = unicount_1.uniToStrPos(s, startUni); const end = endUni == null ? Infinity : unicount_1.uniToStrPos(s, endUni); return s.slice(start, end); }; const dslice = (d, start, end) => (typeof d === 'number' ? (end == null) ? d - start : Math.min(d, end) - start : exports.uniSlice(d, start, end)); /** Makes and returns utility functions take and peek. */ const makeTake = (op) => { // TODO: Rewrite this by passing a context, like the rust code does. Its cleaner that way. // The index of the next component to take let idx = 0; // The offset into the component. For strings this is in UCS2 length, not // unicode codepoints. let offset = 0; // Take up to length n from the front of op. If n is -1, take the entire next // op component. If indivisableField == 'd', delete components won't be separated. // If indivisableField == 'i', insert components won't be separated. const take = (n, indivisableField) => { // We're at the end of the operation. The op has skips, forever. Infinity // might make more sense than null here. if (idx === op.length) return n === -1 ? null : n; const c = op[idx]; let part; if (typeof c === 'number') { // Skip if (n === -1 || c - offset <= n) { part = c - offset; ++idx; offset = 0; return part; } else { offset += n; return n; } } else if (typeof c === 'string') { // Insert if (n === -1 || indivisableField === 'i' || unicount_1.strPosToUni(c.slice(offset)) <= n) { part = c.slice(offset); ++idx; offset = 0; return part; } else { const offset2 = offset + unicount_1.uniToStrPos(c.slice(offset), n); part = c.slice(offset, offset2); offset = offset2; return part; } } else { // Delete // // So this is a little weird - the insert case uses UCS2 length offsets // directly instead of counting in codepoints. Thats more efficient, but // more complicated. It only matters for non-invertable ops with huge // deletes being composed / transformed by other very complicated ops. // Probably not common enough to optimize for. Esp since this is a little // bit of a mess anyway, and the tests should iron out any problems. if (n === -1 || indivisableField === 'd' || exports.dlen(c.d) - offset <= n) { // Emit the remainder of the delete. part = { d: dslice(c.d, offset) }; // part = {d: dlen(c.d) - offset} ++idx; offset = 0; return part; } else { // Slice into the delete content let result = dslice(c.d, offset, offset + n); offset += n; return { d: result }; } } }; // Peek at the next op that will be returned. const peek = () => op[idx]; return { take, peek }; }; /** Trim any excess skips from the end of an operation. * * There should only be at most one, because the operation was made with append. */ const trim = (op) => { if (op.length > 0 && typeof op[op.length - 1] === 'number') { op.pop(); } return op; }; /** Transform op by otherOp. * * @param op - The operation to transform * @param otherOp - Operation to transform it by * @param side - Either 'left' or 'right' */ function transform(op1, op2, side) { if (side !== 'left' && side !== 'right') { throw Error("side (" + side + ") must be 'left' or 'right'"); } checkOp(op1); checkOp(op2); const newOp = []; const append = makeAppend(newOp); const { take, peek } = makeTake(op1); for (let i = 0; i < op2.length; i++) { const c2 = op2[i]; let length, c1; switch (typeof c2) { case 'number': // Skip length = c2; while (length > 0) { c1 = take(length, 'i'); append(c1); if (typeof c1 !== 'string') { length -= componentLength(c1); } } break; case 'string': // Insert if (side === 'left') { // The left insert should go first. if (typeof peek() === 'string') { append(take(-1)); } } // Otherwise skip the inserted text. append(unicount_1.strPosToUni(c2)); break; case 'object': // Delete length = exports.dlen(c2.d); while (length > 0) { c1 = take(length, 'i'); switch (typeof c1) { case 'number': length -= c1; break; case 'string': append(c1); break; case 'object': // The delete is unnecessary now - the text has already been deleted. length -= exports.dlen(c1.d); } } break; } } // Append any extra data in op1. let c; while ((c = take(-1))) append(c); return trim(newOp); } /** Compose op1 and op2 together and return the result */ function compose(op1, op2) { checkOp(op1); checkOp(op2); const result = []; const append = makeAppend(result); const { take } = makeTake(op1); for (let i = 0; i < op2.length; i++) { const component = op2[i]; let length, chunk; switch (typeof component) { case 'number': // Skip length = component; while (length > 0) { chunk = take(length, 'd'); append(chunk); if (typeof chunk !== 'object') { length -= componentLength(chunk); } } break; case 'string': // Insert append(component); break; case 'object': // Delete length = exports.dlen(component.d); // Length of the delete we're doing let offset = 0; // Offset into our deleted content while (offset < length) { chunk = take(length - offset, 'd'); switch (typeof chunk) { case 'number': // We're deleting the skipped characters. append({ d: dslice(component.d, offset, offset + chunk) }); offset += chunk; break; case 'string': offset += unicount_1.strPosToUni(chunk); break; case 'object': append(chunk); } } break; } } let c; while ((c = take(-1))) append(c); return trim(result); } // This operates in unicode offsets to make it consistent with the equivalent // methods in other languages / systems. const transformPosition = (cursor, op) => { let pos = 0; for (let i = 0; i < op.length && cursor > pos; i++) { const c = op[i]; // I could actually use the op_iter stuff above - but I think its simpler // like this. switch (typeof c) { case 'number': { // skip pos += c; break; } case 'string': // insert // Its safe to use c.length here because they're both utf16 offsets. // Ignoring pos because the doc doesn't know about the insert yet. const offset = unicount_1.strPosToUni(c); pos += offset; cursor += offset; break; case 'object': // delete cursor -= Math.min(exports.dlen(c.d), cursor - pos); break; } } return cursor; }; const transformSelection = (selection, op) => (typeof selection === 'number' ? transformPosition(selection, op) : selection.map(s => transformPosition(s, op))); function makeInvertible(op, doc, ropeImpl) { return mapOp(op, (c, prePos) => ((typeof c === 'object' && typeof c.d === 'number') // Delete ? { d: ropeImpl.slice(doc, prePos, prePos + c.d) } : c)); } /** Attempt to invert the operation. Operations with {d:N} components cannot be inverted, and this method will throw. */ function invert(op) { return mapOp(op, c => { switch (typeof c) { case 'object': // Delete if (typeof c.d === 'number') { throw Error('Cannot invert text op: Deleted characters missing from operation. makeInvertible must be called first.'); } else return c.d; // delete -> insert case 'string': return { d: c }; // Insert -> delete case 'number': return c; // skip -> skip } }); } /** Strip extraneous invertibility information from the operation */ function stripInvertible(op) { return mapOp(op, c => ((typeof c === 'object' && typeof c.d === 'string') ? { d: unicount_1.strPosToUni(c.d) } : c)); } /** Helper method. returns true if the operation can be successfully inverted. */ function isInvertible(op) { let invertible = true; eachOp(op, c => { if (typeof c === 'object' && typeof c.d === 'number') invertible = false; }); return invertible; } function makeType(ropeImpl) { return { name: 'text-unicode', uri: 'http://sharejs.org/types/text-unicode', trim, normalize, checkOp, /** Create a new text snapshot. * * @param {string} initial - initial snapshot data. Optional. Defaults to ''. * @returns {Snap} Initial document snapshot object */ create(initial = '') { if (typeof initial !== 'string') { throw Error('Initial data must be a string'); } return ropeImpl.create(initial); }, /** Apply an operation to a document snapshot */ apply(str, op) { checkOp(op); const builder = ropeImpl.builder(str); for (let i = 0; i < op.length; i++) { const component = op[i]; switch (typeof component) { case 'number': builder.skip(component); break; case 'string': builder.append(component); break; case 'object': builder.del(exports.dlen(component.d)); break; } } return builder.build(); }, transform, compose, transformPosition, transformSelection, isInvertible, makeInvertible(op, doc) { return makeInvertible(op, doc, ropeImpl); }, stripInvertible, invert, invertWithDoc(op, doc) { return invert(makeInvertible(op, doc, ropeImpl)); }, isNoop: (op) => op.length === 0 }; } exports.default = makeType; } (type)); return type; } var api = {}; var hasRequiredApi; function requireApi () { if (hasRequiredApi) return api; hasRequiredApi = 1; Object.defineProperty(api, "__esModule", { value: true }); // Text document API for the 'text' type. This implements some standard API // methods for any text-like type, so you can easily bind a textarea or // something without being fussy about the underlying OT implementation. // // The API is desigend as a set of functions to be mixed in to some context // object as part of its lifecycle. It expects that object to have getSnapshot // and submitOp methods, and call _onOp when an operation is received. // // This API defines: // // - getLength() returns the length of the document in characters // - getText() returns a string of the document // - insert(pos, text, [callback]) inserts text at position pos in the document // - remove(pos, length, [callback]) removes length characters at position pos // // A user can define: // - onInsert(pos, text): Called when text is inserted. // - onRemove(pos, length): Called when text is removed. const type_1 = requireType(); const unicount_1 = requireUnicount(); function api$1(getSnapshot, submitOp) { return { // Returns the text content of the document get: getSnapshot, // Returns the number of characters in the string getLength() { return getSnapshot().length; }, // Insert the specified text at the given position in the document insert(pos, text, callback) { const uniPos = unicount_1.strPosToUni(getSnapshot(), pos); return submitOp([uniPos, text], callback); }, remove(pos, lengthOrContent, callback) { const uniPos = unicount_1.strPosToUni(getSnapshot(), pos); return submitOp([uniPos, { d: lengthOrContent }], callback); }, // When you use this API, you should implement these two methods // in your editing context. //onInsert: function(pos, text) {}, //onRemove: function(pos, removedLength) {}, _onOp(op) { type_1.eachOp(op, (component, prePos, postPos) => { switch (typeof component) { case 'string': if (this.onInsert) this.onInsert(postPos, component); break; case 'object': const dl = type_1.dlen(component.d); if (this.onRemove) this.onRemove(postPos, dl); } }); }, onInsert: null, onRemove: null, }; } api.default = api$1; api$1.provides = { text: true }; return api; } var hasRequiredDist; function requireDist () { if (hasRequiredDist) return dist$1; hasRequiredDist = 1; (function (exports) { var __createBinding = (dist$1 && dist$1.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } }); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (dist$1 && dist$1.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (dist$1 && dist$1.__importStar) || function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); __setModuleDefault(result, mod); return result; }; var __importDefault = (dist$1 && dist$1.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.type = exports.remove = exports.insert = void 0; // This is an implementation of the text OT type built on top of JS strings. // You would think this would be horribly inefficient, but its surpringly // good. JS strings are magic. const unicount_1 = requireUnicount(); const type_1 = __importStar(requireType()); const api_1 = __importDefault(requireApi()); const ropeImplUnicodeString = { create(s) { return s; }, toString(s) { return s; }, builder(oldDoc) { if (typeof oldDoc !== 'string') throw Error('Invalid document snapshot: ' + oldDoc); const newDoc = []; return { skip(n) { let offset = unicount_1.uniToStrPos(oldDoc, n); if (offset > oldDoc.length) throw Error('The op is too long for this document'); newDoc.push(oldDoc.slice(0, offset)); oldDoc = oldDoc.slice(offset); }, append(s) { newDoc.push(s); }, del(n) { oldDoc = oldDoc.slice(unicount_1.uniToStrPos(oldDoc, n)); }, build() { return newDoc.join('') + oldDoc; }, }; }, slice: type_1.uniSlice, }; const textString = type_1.default(ropeImplUnicodeString); const type = Object.assign(Object.assign({}, textString), { api: api_1.default }); exports.type = type; exports.insert = (pos, text) => (text.length === 0 ? [] : pos === 0 ? [text] : [pos, text]); exports.remove = (pos, textOrLen) => (type_1.dlen(textOrLen) === 0 ? [] : pos === 0 ? [{ d: textOrLen }] : [pos, { d: textOrLen }]); var type_2 = requireType(); Object.defineProperty(exports, "makeType", { enumerable: true, get: function () { return type_2.default; } }); } (dist$1)); return dist$1; } var distExports = requireDist(); var textUnicode = /*@__PURE__*/getDefaultExportFromCjs(distExports); var isArguments$1; var hasRequiredIsArguments$1; function requireIsArguments$1 () { if (hasRequiredIsArguments$1) return isArguments$1; hasRequiredIsArguments$1 = 1; var toStr = Object.prototype.toString; isArguments$1 = function isArguments(value) { var str = toStr.call(value); var isArgs = str === '[object Arguments]'; if (!isArgs) { isArgs = str !== '[object Array]' && value !== null && typeof value === 'object' && typeof value.length === 'number' && value.length >= 0 && toStr.call(value.callee) === '[object Function]'; } return isArgs; }; return isArguments$1; } var implementation$3; var hasRequiredImplementation$3; function requireImplementation$3 () { if (hasRequiredImplementation$3) return implementation$3; hasRequiredImplementation$3 = 1; var keysShim; if (!Object.keys) { // modified from https://github.com/es-shims/es5-shim var has = Object.prototype.hasOwnProperty; var toStr = Object.prototype.toString; var isArgs = requireIsArguments$1(); // eslint-disable-line global-require var isEnumerable = Object.prototype.propertyIsEnumerable; var hasDontEnumBug = !isEnumerable.call({ toString: null }, 'toString'); var hasProtoEnumBug = isEnumerable.call(function () {}, 'prototype'); var dontEnums = [ 'toString', 'toLocaleString', 'valueOf', 'hasOwnProperty', 'isPrototypeOf', 'propertyIsEnumerable', 'constructor' ]; var equalsConstructorPrototype = function (o) { var ctor = o.constructor; return ctor && ctor.prototype === o; }; var excludedKeys = { $applicationCache: true, $console: true, $external: true, $frame: true, $frameElement: true, $frames: true, $innerHeight: true, $innerWidth: true, $onmozfullscreenchange: true, $onmozfullscreenerror: true, $outerHeight: true, $outerWidth: true, $pageXOffset: true, $pageYOffset: true, $parent: true, $scrollLeft: true, $scrollTop: true, $scrollX: true, $scrollY: true, $self: true, $webkitIndexedDB: true, $webkitStorageInfo: true, $window: true }; var hasAutomationEqualityBug = (function () { /* global window */ if (typeof window === 'undefined') { return false; } for (var k in window) { try { if (!excludedKeys['$' + k] && has.call(window, k) && window[k] !== null && typeof window[k] === 'object') { try { equalsConstructorPrototype(window[k]); } catch (e) { return true; } } } catch (e) { return true; } } return false; }()); var equalsConstructorPrototypeIfNotBuggy = function (o) { /* global window */ if (typeof window === 'undefined' || !hasAutomationEqualityBug) { return equalsConstructorPrototype(o); } try { return equalsConstructorPrototype(o); } catch (e) { return false; } }; keysShim = function keys(object) { var isObject = object !== null && typeof object === 'object'; var isFunction = toStr.call(object) === '[object Function]'; var isArguments = isArgs(object); var isString = isObject && toStr.call(object) === '[object String]'; var theKeys = []; if (!isObject && !isFunction && !isArguments) { throw new TypeError('Object.keys called on a non-object'); } var skipProto = hasProtoEnumBug && isFunction; if (isString && object.length > 0 && !has.call(object, 0)) { for (var i = 0; i < object.length; ++i) { theKeys.push(String(i)); } } if (isArguments && object.length > 0) { for (var j = 0; j < object.length; ++j) { theKeys.push(String(j)); } } else { for (var name in object) { if (!(skipProto && name === 'prototype') && has.call(object, name)) { theKeys.push(String(name)); } } } if (hasDontEnumBug) { var skipConstructor = equalsConstructorPrototypeIfNotBuggy(object); for (var k = 0; k < dontEnums.length; ++k) { if (!(skipConstructor && dontEnums[k] === 'constructor') && has.call(object, dontEnums[k])) { theKeys.push(dontEnums[k]); } } } return theKeys; }; } implementation$3 = keysShim; return implementation$3; } var objectKeys; var hasRequiredObjectKeys; function requireObjectKeys () { if (hasRequiredObjectKeys) return objectKeys; hasRequiredObjectKeys = 1; var slice = Array.prototype.slice; var isArgs = requireIsArguments$1(); var origKeys = Object.keys; var keysShim = origKeys ? function keys(o) { return origKeys(o); } : requireImplementation$3(); var originalKeys = Object.keys; keysShim.shim = function shimObjectKeys() { if (Object.keys) { var keysWorksWithArguments = (function () { // Safari 5.0 bug var args = Object.keys(arguments); return args && args.length === arguments.length; }(1, 2)); if (!keysWorksWithArguments) { Object.keys = function keys(object) { // eslint-disable-line func-name-matching if (isArgs(object)) { return originalKeys(slice.call(object)); } return originalKeys(object); }; } } else { Object.keys = keysShim; } return Object.keys || keysShim; }; objectKeys = keysShim; return objectKeys; } var shams$1; var hasRequiredShams$1; function requireShams$1 () { if (hasRequiredShams$1) return shams$1; hasRequiredShams$1 = 1; /* eslint complexity: [2, 18], max-statements: [2, 33] */ shams$1 = function hasSymbols() { if (typeof Symbol !== 'function' || typeof Object.getOwnPropertySymbols !== 'function') { return false; } if (typeof Symbol.iterator === 'symbol') { return true; } var obj = {}; var sym = Symbol('test'); var symObj = Object(sym); if (typeof sym === 'string') { return false; } if (Object.prototype.toString.call(sym) !== '[object Symbol]') { return false; } if (Object.prototype.toString.call(symObj) !== '[object Symbol]') { return false; } // temp disabled per https://github.com/ljharb/object.assign/issues/17 // if (sym instanceof Symbol) { return false; } // temp disabled per https://github.com/WebReflection/get-own-property-symbols/issues/4 // if (!(symObj instanceof Symbol)) { return false; } // if (typeof Symbol.prototype.toString !== 'function') { return false; } // if (String(sym) !== Symbol.prototype.toString.call(sym)) { return false; } var symVal = 42; obj[sym] = symVal; for (sym in obj) { return false; } // eslint-disable-line no-restricted-syntax, no-unreachable-loop if (typeof Object.keys === 'function' && Object.keys(obj).length !== 0) { return false; } if (typeof Object.getOwnPropertyNames === 'function' && Object.getOwnPropertyNames(obj).length !== 0) { return false; } var syms = Object.getOwnPropertySymbols(obj); if (syms.length !== 1 || syms[0] !== sym) { return false; } if (!Object.prototype.propertyIsEnumerable.call(obj, sym)) { return false; } if (typeof Object.getOwnPropertyDescriptor === 'function') { var descriptor = Object.getOwnPropertyDescriptor(obj, sym); if (descriptor.value !== symVal || descriptor.enumerable !== true) { return false; } } return true; }; return shams$1; } var shams; var hasRequiredShams; function requireShams () { if (hasRequiredShams) return shams; hasRequiredShams = 1; var hasSymbols = requireShams$1(); shams = function hasToStringTagShams() { return hasSymbols() && !!Symbol.toStringTag; }; return shams; } var hasSymbols; var hasRequiredHasSymbols; function requireHasSymbols () { if (hasRequiredHasSymbols) return hasSymbols; hasRequiredHasSymbols = 1; var origSymbol = typeof Symbol !== 'undefined' && Symbol; var hasSymbolSham = requireShams$1(); hasSymbols = function hasNativeSymbols() { if (typeof origSymbol !== 'function') { return false; } if (typeof Symbol !== 'function') { return false; } if (typeof origSymbol('foo') !== 'symbol') { return false; } if (typeof Symbol('bar') !== 'symbol') { return false; } return hasSymbolSham(); }; return hasSymbols; } var implementation$2; var hasRequiredImplementation$2; function requireImplementation$2 () { if (hasRequiredImplementation$2) return implementation$2; hasRequiredImplementation$2 = 1; /* eslint no-invalid-this: 1 */ var ERROR_MESSAGE = 'Function.prototype.bind called on incompatible '; var slice = Array.prototype.slice; var toStr = Object.prototype.toString; var funcType = '[object Function]'; implementation$2 = function bind(that) { var target = this; if (typeof target !== 'function' || toStr.call(target) !== funcType) { throw new TypeError(ERROR_MESSAGE + target); } var args = slice.call(arguments, 1); var bound; var binder = function () { if (this instanceof bound) { var result = target.apply( this, args.concat(slice.call(arguments)) ); if (Object(result) === result) { return result; } return this; } else { return target.apply( that, args.concat(slice.call(arguments)) ); } }; var boundLength = Math.max(0, target.length - args.length); var boundArgs = []; for (var i = 0; i < boundLength; i++) { boundArgs.push('$' + i); } bound = Function('binder', 'return function (' + boundArgs.join(',') + '){ return binder.apply(this,arguments); }')(binder); if (target.prototype) { var Empty = function Empty() {}; Empty.prototype = target.prototype; bound.prototype = new Empty(); Empty.prototype = null; } return bound; }; return implementation$2; } var functionBind; var hasRequiredFunctionBind; function requireFunctionBind () { if (hasRequiredFunctionBind) return functionBind; hasRequiredFunctionBind = 1; var implementation = requireImplementation$2(); functionBind = Function.prototype.bind || implementation; return functionBind; } var src; var hasRequiredSrc; function requireSrc () { if (hasRequiredSrc) return src; hasRequiredSrc = 1; var bind = requireFunctionBind(); src = bind.call(Function.call, Object.prototype.hasOwnProperty); return src; } var getIntrinsic; var hasRequiredGetIntrinsic; function requireGetIntrinsic () { if (hasRequiredGetIntrinsic) return getIntrinsic; hasRequiredGetIntrinsic = 1; var undefined$1; var $SyntaxError = SyntaxError; var $Function = Function; var $TypeError = TypeError; // eslint-disable-next-line consistent-return var getEvalledConstructor = function (expressionSyntax) { try { return $Function('"use strict"; return (' + expressionSyntax + ').constructor;')(); } catch (e) {} }; var $gOPD = Object.getOwnPropertyDescriptor; if ($gOPD) { try { $gOPD({}, ''); } catch (e) { $gOPD = null; // this is IE 8, which has a broken gOPD } } var throwTypeError = function () { throw new $TypeError(); }; var ThrowTypeError = $gOPD ? (function () { try { // eslint-disable-next-line no-unused-expressions, no-caller, no-restricted-properties arguments.callee; // IE 8 does not throw here return throwTypeError; } catch (calleeThrows) { try { // IE 8 throws on Object.getOwnPropertyDescriptor(arguments, '') return $gOPD(arguments, 'callee').get; } catch (gOPDthrows) { return throwTypeError; } } }()) : throwTypeError; var hasSymbols = requireHasSymbols()(); var getProto = Object.getPrototypeOf || function (x) { return x.__proto__; }; // eslint-disable-line no-proto var needsEval = {}; var TypedArray = typeof Uint8Array === 'undefined' ? undefined$1 : getProto(Uint8Array); var INTRINSICS = { '%AggregateError%': typeof AggregateError === 'undefined' ? undefined$1 : AggregateError, '%Array%': Array, '%ArrayBuffer%': typeof ArrayBuffer === 'undefined' ? undefined$1 : ArrayBuffer, '%ArrayIteratorPrototype%': hasSymbols ? getProto([][Symbol.iterator]()) : undefined$1, '%AsyncFromSyncIteratorPrototype%': undefined$1, '%AsyncFunction%': needsEval, '%AsyncGenerator%': needsEval, '%AsyncGeneratorFunction%': needsEval, '%AsyncIteratorPrototype%': needsEval, '%Atomics%': typeof Atomics === 'undefined' ? undefined$1 : Atomics, '%BigInt%': typeof BigInt === 'undefined' ? undefined$1 : BigInt, '%BigInt64Array%': typeof BigInt64Array === 'undefined' ? undefined$1 : BigInt64Array, '%BigUint64Array%': typeof BigUint64Array === 'undefined' ? undefined$1 : BigUint64Array, '%Boolean%': Boolean, '%DataView%': typeof DataView === 'undefined' ? undefined$1 : DataView, '%Date%': Date, '%decodeURI%': decodeURI, '%decodeURIComponent%': decodeURIComponent, '%encodeURI%': encodeURI, '%encodeURIComponent%': encodeURIComponent, '%Error%': Error, '%eval%': eval, // eslint-disable-line no-eval '%EvalError%': EvalError, '%Float32Array%': typeof Float32Array === 'undefined' ? undefined$1 : Float32Array, '%Float64Array%': typeof Float64Array === 'undefined' ? undefined$1 : Float64Array, '%FinalizationRegistry%': typeof FinalizationRegistry === 'undefined' ? undefined$1 : FinalizationRegistry, '%Function%': $Function, '%GeneratorFunction%': needsEval, '%Int8Array%': typeof Int8Array === 'undefined' ? undefined$1 : Int8Array, '%Int16Array%': typeof Int16Array === 'undefined' ? undefined$1 : Int16Array, '%Int32Array%': typeof Int32Array === 'undefined' ? undefined$1 : Int32Array, '%isFinite%': isFinite, '%isNaN%': isNaN, '%IteratorPrototype%': hasSymbols ? getProto(getProto([][Symbol.iterator]())) : undefined$1, '%JSON%': typeof JSON === 'object' ? JSON : undefined$1, '%Map%': typeof Map === 'undefined' ? undefined$1 : Map, '%MapIteratorPrototype%': typeof Map === 'undefined' || !hasSymbols ? undefined$1 : getProto(new Map()[Symbol.iterator]()), '%Math%': Math, '%Number%': Number, '%Object%': Object, '%parseFloat%': parseFloat, '%parseInt%': parseInt, '%Promise%': typeof Promise === 'undefined' ? undefined$1 : Promise, '%Proxy%': typeof Proxy === 'undefined' ? undefined$1 : Proxy, '%RangeError%': RangeError, '%ReferenceError%': ReferenceError, '%Reflect%': typeof Reflect === 'undefined' ? undefined$1 : Reflect, '%RegExp%': RegExp, '%Set%': typeof Set === 'undefined' ? undefined$1 : Set, '%SetIteratorPrototype%': typeof Set === 'undefined' || !hasSymbols ? undefined$1 : getProto(new Set()[Symbol.iterator]()), '%SharedArrayBuffer%': typeof SharedArrayBuffer === 'undefined' ? undefined$1 : SharedArrayBuffer, '%String%': String, '%StringIteratorPrototype%': hasSymbols ? getProto(''[Symbol.iterator]()) : undefined$1, '%Symbol%': hasSymbols ? Symbol : undefined$1, '%SyntaxError%': $SyntaxError, '%ThrowTypeError%': ThrowTypeError, '%TypedArray%': TypedArray, '%TypeError%': $TypeError, '%Uint8Array%': typeof Uint8Array === 'undefined' ? undefined$1 : Uint8Array, '%Uint8ClampedArray%': typeof Uint8ClampedArray === 'undefined' ? undefined$1 : Uint8ClampedArray, '%Uint16Array%': typeof Uint16Array === 'undefined' ? undefined$1 : Uint16Array, '%Uint32Array%': typeof Uint32Array === 'undefined' ? undefined$1 : Uint32Array, '%URIError%': URIError, '%WeakMap%': typeof WeakMap === 'undefined' ? undefined$1 : WeakMap, '%WeakRef%': typeof WeakRef === 'undefined' ? undefined$1 : WeakRef, '%WeakSet%': typeof WeakSet === 'undefined' ? undefined$1 : WeakSet }; try { null.error; // eslint-disable-line no-unused-expressions } catch (e) { // https://github.com/tc39/proposal-shadowrealm/pull/384#issuecomment-1364264229 var errorProto = getProto(getProto(e)); INTRINSICS['%Error.prototype%'] = errorProto; } var doEval = function doEval(name) { var value; if (name === '%AsyncFunction%') { value = getEvalledConstructor('async function () {}'); } else if (name === '%GeneratorFunction%') { value = getEvalledConstructor('function* () {}'); } else if (name === '%AsyncGeneratorFunction%') { value = getEvalledConstructor('async function* () {}'); } else if (name === '%AsyncGenerator%') { var fn = doEval('%AsyncGeneratorFunction%'); if (fn) { value = fn.prototype; } } else if (name === '%AsyncIteratorPrototype%') { var gen = doEval('%AsyncGenerator%'); if (gen) { value = getProto(gen.prototype); } } INTRINSICS[name] = value; return value; }; var LEGACY_ALIASES = { '%ArrayBufferPrototype%': ['ArrayBuffer', 'prototype'], '%ArrayPrototype%': ['Array', 'prototype'], '%ArrayProto_entries%': ['Array', 'prototype', 'entries'], '%ArrayProto_forEach%': ['Array', 'prototype', 'forEach'], '%ArrayProto_keys%': ['Array', 'prototype', 'keys'], '%ArrayProto_values%': ['Array', 'prototype', 'values'], '%AsyncFunctionPrototype%': ['AsyncFunction', 'prototype'], '%AsyncGenerator%': ['AsyncGeneratorFunction', 'prototype'], '%AsyncGeneratorPrototype%': ['AsyncGeneratorFunction', 'prototype', 'prototype'], '%BooleanPrototype%': ['Boolean', 'prototype'], '%DataViewPrototype%': ['DataView', 'prototype'], '%DatePrototype%': ['Date', 'prototype'], '%ErrorPrototype%': ['Error', 'prototype'], '%EvalErrorPrototype%': ['EvalError', 'prototype'], '%Float32ArrayPrototype%': ['Float32Array', 'prototype'], '%Float64ArrayPrototype%': ['Float64Array', 'prototype'], '%FunctionPrototype%': ['Function', 'prototype'], '%Generator%': ['GeneratorFunction', 'prototype'], '%GeneratorPrototype%': ['GeneratorFunction', 'prototype', 'prototype'], '%Int8ArrayPrototype%': ['Int8Array', 'prototype'], '%Int16ArrayPrototype%': ['Int16Array', 'prototype'], '%Int32ArrayPrototype%': ['Int32Array', 'prototype'], '%JSONParse%': ['JSON', 'parse'], '%JSONStringify%': ['JSON', 'stringify'], '%MapPrototype%': ['Map', 'prototype'], '%NumberPrototype%': ['Number', 'prototype'], '%ObjectPrototype%': ['Object', 'prototype'], '%ObjProto_toString%': ['Object', 'prototype', 'toString'], '%ObjProto_valueOf%': ['Object', 'prototype', 'valueOf'], '%PromisePrototype%': ['Promise', 'prototype'], '%PromiseProto_then%': ['Promise', 'prototype', 'then'], '%Promise_all%': ['Promise', 'all'], '%Promise_reject%': ['Promise', 'reject'], '%Promise_resolve%': ['Promise', 'resolve'], '%RangeErrorPrototype%': ['RangeError', 'prototype'], '%ReferenceErrorPrototype%': ['ReferenceError', 'prototype'], '%RegExpPrototype%': ['RegExp', 'prototype'], '%SetPrototype%': ['Set', 'prototype'], '%SharedArrayBufferPrototype%': ['SharedArrayBuffer', 'prototype'], '%StringPrototype%': ['String', 'prototype'], '%SymbolPrototype%': ['Symbol', 'prototype'], '%SyntaxErrorPrototype%': ['SyntaxError', 'prototype'], '%TypedArrayPrototype%': ['TypedArray', 'prototype'], '%TypeErrorPrototype%': ['TypeError', 'prototype'], '%Uint8ArrayPrototype%': ['Uint8Array', 'prototype'], '%Uint8ClampedArrayPrototype%': ['Uint8ClampedArray', 'prototype'], '%Uint16ArrayPrototype%': ['Uint16Array', 'prototype'], '%Uint32ArrayPrototype%': ['Uint32Array', 'prototype'], '%URIErrorPrototype%': ['URIError', 'prototype'], '%WeakMapPrototype%': ['WeakMap', 'prototype'], '%WeakSetPrototype%': ['WeakSet', 'prototype'] }; var bind = requireFunctionBind(); var hasOwn = requireSrc(); var $concat = bind.call(Function.call, Array.prototype.concat); var $spliceApply = bind.call(Function.apply, Array.prototype.splice); var $replace = bind.call(Function.call, String.prototype.replace); var $strSlice = bind.call(Function.call, String.prototype.slice); var $exec = bind.call(Function.call, RegExp.prototype.exec); /* adapted from https://github.com/lodash/lodash/blob/4.17.15/dist/lodash.js#L6735-L6744 */ var rePropName = /[^%.[\]]+|\[(?:(-?\d+(?:\.\d+)?)|(["'])((?:(?!\2)[^\\]|\\.)*?)\2)\]|(?=(?:\.|\[\])(?:\.|\[\]|%$))/g; var reEscapeChar = /\\(\\)?/g; /** Used to match backslashes in property paths. */ var stringToPath = function stringToPath(string) { var first = $strSlice(string, 0, 1); var last = $strSlice(string, -1); if (first === '%' && last !== '%') { throw new $SyntaxError('invalid intrinsic syntax, expected closing `%`'); } else if (last === '%' && first !== '%') { throw new $SyntaxError('invalid intrinsic syntax, expected opening `%`'); } var result = []; $replace(string, rePropName, function (match, number, quote, subString) { result[result.length] = quote ? $replace(subString, reEscapeChar, '$1') : number || match; }); return result; }; /* end adaptation */ var getBaseIntrinsic = function getBaseIntrinsic(name, allowMissing) { var intrinsicName = name; var alias; if (hasOwn(LEGACY_ALIASES, intrinsicName)) { alias = LEGACY_ALIASES[intrinsicName]; intrinsicName = '%' + alias[0] + '%'; } if (hasOwn(INTRINSICS, intrinsicName)) { var value = INTRINSICS[intrinsicName]; if (value === needsEval) { value = doEval(intrinsicName); } if (typeof value === 'undefined' && !allowMissing) { throw new $TypeError('intrinsic ' + name + ' exists, but is not available. Please file an issue!'); } return { alias: alias, name: intrinsicName, value: value }; } throw new $SyntaxError('intrinsic ' + name + ' does not exist!'); }; getIntrinsic = function GetIntrinsic(name, allowMissing) { if (typeof name !== 'string' || name.length === 0) { throw new $TypeError('intrinsic name must be a non-empty string'); } if (arguments.length > 1 && typeof allowMissing !== 'boolean') { throw new $TypeError('"allowMissing" argument must be a boolean'); } if ($exec(/^%?[^%]*%?$/, name) === null) { throw new $SyntaxError('`%` may not be present anywhere but at the beginning and end of the intrinsic name'); } var parts = stringToPath(name); var intrinsicBaseName = parts.length > 0 ? parts[0] : ''; var intrinsic = getBaseIntrinsic('%' + intrinsicBaseName + '%', allowMissing); var intrinsicRealName = intrinsic.name; var value = intrinsic.value; var skipFurtherCaching = false; var alias = intrinsic.alias; if (alias) { intrinsicBaseName = alias[0]; $spliceApply(parts, $concat([0, 1], alias)); } for (var i = 1, isOwn = true; i < parts.length; i += 1) { var part = parts[i]; var first = $strSlice(part, 0, 1); var last = $strSlice(part, -1); if ( ( (first === '"' || first === "'" || first === '`') || (last === '"' || last === "'" || last === '`') ) && first !== last ) { throw new $SyntaxError('property names with quotes must have matching quotes'); } if (part === 'constructor' || !isOwn) { skipFurtherCaching = true; } intrinsicBaseName += '.' + part; intrinsicRealName = '%' + intrinsicBaseName + '%'; if (hasOwn(INTRINSICS, intrinsicRealName)) { value = INTRINSICS[intrinsicRealName]; } else if (value != null) { if (!(part in value)) { if (!allowMissing) { throw new $TypeError('base intrinsic for ' + name + ' exists, but the property is not available.'); } return void undefined$1; } if ($gOPD && (i + 1) >= parts.length) { var desc = $gOPD(value, part); isOwn = !!desc; // By convention, when a data property is converted to an accessor // property to emulate a data property that does not suffer from // the override mistake, that accessor's getter is marked with // an `originalValue` property. Here, when we detect this, we