graplix
Version:
Authorization framework for implementing Relation-based Access Control (ReBAC) with the Resolver (Inspired by [GraphQL](https://graphql.org))
1,570 lines (1,546 loc) • 190 kB
JavaScript
//#region rolldown:runtime
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __commonJS = (cb, mod) => function() {
return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
key = keys[i];
if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
get: ((k) => from[k]).bind(null, key),
enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
});
}
return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
value: mod,
enumerable: true
}) : target, mod));
//#endregion
const events = __toESM(require("events"));
const remeda = __toESM(require("remeda"));
const __openfga_syntax_transformer = __toESM(require("@openfga/syntax-transformer"));
//#region ../../node_modules/obliterator/iterator.js
var require_iterator = __commonJS({ "../../node_modules/obliterator/iterator.js"(exports, module) {
/**
* Obliterator Iterator Class
* ===========================
*
* Simple class representing the library's iterators.
*/
/**
* Iterator class.
*
* @constructor
* @param {function} next - Next function.
*/
function Iterator$11(next) {
if (typeof next !== "function") throw new Error("obliterator/iterator: expecting a function!");
this.next = next;
}
/**
* If symbols are supported, we add `next` to `Symbol.iterator`.
*/
if (typeof Symbol !== "undefined") Iterator$11.prototype[Symbol.iterator] = function() {
return this;
};
/**
* Returning an iterator of the given values.
*
* @param {any...} values - Values.
* @return {Iterator}
*/
Iterator$11.of = function() {
var args = arguments, l = args.length, i = 0;
return new Iterator$11(function() {
if (i >= l) return { done: true };
return {
done: false,
value: args[i++]
};
});
};
/**
* Returning an empty iterator.
*
* @return {Iterator}
*/
Iterator$11.empty = function() {
var iterator = new Iterator$11(function() {
return { done: true };
});
return iterator;
};
/**
* Returning an iterator over the given indexed sequence.
*
* @param {string|Array} sequence - Target sequence.
* @return {Iterator}
*/
Iterator$11.fromSequence = function(sequence) {
var i = 0, l = sequence.length;
return new Iterator$11(function() {
if (i >= l) return { done: true };
return {
done: false,
value: sequence[i++]
};
});
};
/**
* Returning whether the given value is an iterator.
*
* @param {any} value - Value.
* @return {boolean}
*/
Iterator$11.is = function(value) {
if (value instanceof Iterator$11) return true;
return typeof value === "object" && value !== null && typeof value.next === "function";
};
/**
* Exporting.
*/
module.exports = Iterator$11;
} });
//#endregion
//#region ../../node_modules/obliterator/support.js
var require_support = __commonJS({ "../../node_modules/obliterator/support.js"(exports) {
exports.ARRAY_BUFFER_SUPPORT = typeof ArrayBuffer !== "undefined";
exports.SYMBOL_SUPPORT = typeof Symbol !== "undefined";
} });
//#endregion
//#region ../../node_modules/obliterator/iter.js
var require_iter = __commonJS({ "../../node_modules/obliterator/iter.js"(exports, module) {
/**
* Obliterator Iter Function
* ==========================
*
* Function coercing values to an iterator. It can be quite useful when needing
* to handle iterables and iterators the same way.
*/
var Iterator$10 = require_iterator();
var support$2 = require_support();
var ARRAY_BUFFER_SUPPORT$2 = support$2.ARRAY_BUFFER_SUPPORT;
var SYMBOL_SUPPORT$2 = support$2.SYMBOL_SUPPORT;
function iterOrNull(target) {
if (typeof target === "string" || Array.isArray(target) || ARRAY_BUFFER_SUPPORT$2 && ArrayBuffer.isView(target)) return Iterator$10.fromSequence(target);
if (typeof target !== "object" || target === null) return null;
if (SYMBOL_SUPPORT$2 && typeof target[Symbol.iterator] === "function") return target[Symbol.iterator]();
if (typeof target.next === "function") return target;
return null;
}
module.exports = function iter$9(target) {
var iterator = iterOrNull(target);
if (!iterator) throw new Error("obliterator: target is not iterable nor a valid iterator.");
return iterator;
};
} });
//#endregion
//#region ../../node_modules/obliterator/chain.js
var require_chain = __commonJS({ "../../node_modules/obliterator/chain.js"(exports, module) {
/**
* Obliterator Chain Function
* ===========================
*
* Variadic function combining the given iterables.
*/
var Iterator$9 = require_iterator();
var iter$8 = require_iter();
/**
* Chain.
*
* @param {...Iterator} iterables - Target iterables.
* @return {Iterator}
*/
module.exports = function chain$2() {
var iterables = arguments;
var current = null;
var i = -1;
return new Iterator$9(function next() {
var step = null;
do {
if (current === null) {
i++;
if (i >= iterables.length) return { done: true };
current = iter$8(iterables[i]);
}
step = current.next();
if (step.done === true) {
current = null;
continue;
}
break;
} while (true);
return step;
});
};
} });
//#endregion
//#region ../../node_modules/obliterator/combinations.js
var require_combinations = __commonJS({ "../../node_modules/obliterator/combinations.js"(exports, module) {
/**
* Obliterator Combinations Function
* ==================================
*
* Iterator returning combinations of the given array.
*/
var Iterator$8 = require_iterator();
/**
* Helper mapping indices to items.
*/
function indicesToItems$1(target, items, indices, r) {
for (var i = 0; i < r; i++) target[i] = items[indices[i]];
}
/**
* Combinations.
*
* @param {array} array - Target array.
* @param {number} r - Size of the subsequences.
* @return {Iterator}
*/
module.exports = function combinations$1(array, r) {
if (!Array.isArray(array)) throw new Error("obliterator/combinations: first argument should be an array.");
var n = array.length;
if (typeof r !== "number") throw new Error("obliterator/combinations: second argument should be omitted or a number.");
if (r > n) throw new Error("obliterator/combinations: the size of the subsequences should not exceed the length of the array.");
if (r === n) return Iterator$8.of(array.slice());
var indices = new Array(r), subsequence = new Array(r), first = true, i;
for (i = 0; i < r; i++) indices[i] = i;
return new Iterator$8(function next() {
if (first) {
first = false;
indicesToItems$1(subsequence, array, indices, r);
return {
value: subsequence,
done: false
};
}
if (indices[r - 1]++ < n - 1) {
indicesToItems$1(subsequence, array, indices, r);
return {
value: subsequence,
done: false
};
}
i = r - 2;
while (i >= 0 && indices[i] >= n - (r - i)) --i;
if (i < 0) return { done: true };
indices[i]++;
while (++i < r) indices[i] = indices[i - 1] + 1;
indicesToItems$1(subsequence, array, indices, r);
return {
value: subsequence,
done: false
};
});
};
} });
//#endregion
//#region ../../node_modules/obliterator/consume.js
var require_consume = __commonJS({ "../../node_modules/obliterator/consume.js"(exports, module) {
/**
* Obliterator Consume Function
* =============================
*
* Function consuming the given iterator for n or every steps.
*/
/**
* Consume.
*
* @param {Iterator} iterator - Target iterator.
* @param {number} [steps] - Optional steps.
*/
module.exports = function consume(iterator, steps) {
var step, l = arguments.length > 1 ? steps : Infinity, i = 0;
while (true) {
if (i === l) return;
step = iterator.next();
if (step.done) return;
i++;
}
};
} });
//#endregion
//#region ../../node_modules/obliterator/every.js
var require_every = __commonJS({ "../../node_modules/obliterator/every.js"(exports, module) {
/**
* Obliterator Every Function
* ==========================
*
* Function taking an iterable and a predicate and returning whether all
* its items match the given predicate.
*/
var iter$7 = require_iter();
/**
* Every.
*
* @param {Iterable} iterable - Target iterable.
* @param {function} predicate - Predicate function.
* @return {boolean}
*/
module.exports = function every(iterable, predicate) {
var iterator = iter$7(iterable);
var step;
while (step = iterator.next(), !step.done) if (!predicate(step.value)) return false;
return true;
};
} });
//#endregion
//#region ../../node_modules/obliterator/filter.js
var require_filter = __commonJS({ "../../node_modules/obliterator/filter.js"(exports, module) {
/**
* Obliterator Filter Function
* ===========================
*
* Function returning a iterator filtering the given iterator.
*/
var Iterator$7 = require_iterator();
var iter$6 = require_iter();
/**
* Filter.
*
* @param {Iterable} target - Target iterable.
* @param {function} predicate - Predicate function.
* @return {Iterator}
*/
module.exports = function filter(target, predicate) {
var iterator = iter$6(target);
var step;
return new Iterator$7(function() {
do
step = iterator.next();
while (!step.done && !predicate(step.value));
return step;
});
};
} });
//#endregion
//#region ../../node_modules/obliterator/find.js
var require_find = __commonJS({ "../../node_modules/obliterator/find.js"(exports, module) {
/**
* Obliterator Find Function
* ==========================
*
* Function taking an iterable and a predicate and returning the first item
* matching the given predicate.
*/
var iter$5 = require_iter();
/**
* Find.
*
* @param {Iterable} iterable - Target iterable.
* @param {function} predicate - Predicate function.
* @return {boolean}
*/
module.exports = function find(iterable, predicate) {
var iterator = iter$5(iterable);
var step;
while (step = iterator.next(), !step.done) if (predicate(step.value)) return step.value;
return;
};
} });
//#endregion
//#region ../../node_modules/obliterator/foreach.js
var require_foreach = __commonJS({ "../../node_modules/obliterator/foreach.js"(exports, module) {
/**
* Obliterator ForEach Function
* =============================
*
* Helper function used to easily iterate over mixed values.
*/
var support$1 = require_support();
var ARRAY_BUFFER_SUPPORT$1 = support$1.ARRAY_BUFFER_SUPPORT;
var SYMBOL_SUPPORT$1 = support$1.SYMBOL_SUPPORT;
/**
* Function able to iterate over almost any iterable JS value.
*
* @param {any} iterable - Iterable value.
* @param {function} callback - Callback function.
*/
module.exports = function forEach(iterable, callback) {
var iterator, k, i, l, s;
if (!iterable) throw new Error("obliterator/forEach: invalid iterable.");
if (typeof callback !== "function") throw new Error("obliterator/forEach: expecting a callback.");
if (Array.isArray(iterable) || ARRAY_BUFFER_SUPPORT$1 && ArrayBuffer.isView(iterable) || typeof iterable === "string" || iterable.toString() === "[object Arguments]") {
for (i = 0, l = iterable.length; i < l; i++) callback(iterable[i], i);
return;
}
if (typeof iterable.forEach === "function") {
iterable.forEach(callback);
return;
}
if (SYMBOL_SUPPORT$1 && Symbol.iterator in iterable && typeof iterable.next !== "function") iterable = iterable[Symbol.iterator]();
if (typeof iterable.next === "function") {
iterator = iterable;
i = 0;
while (s = iterator.next(), s.done !== true) {
callback(s.value, i);
i++;
}
return;
}
for (k in iterable) if (iterable.hasOwnProperty(k)) callback(iterable[k], k);
return;
};
} });
//#endregion
//#region ../../node_modules/obliterator/foreach-with-null-keys.js
var require_foreach_with_null_keys = __commonJS({ "../../node_modules/obliterator/foreach-with-null-keys.js"(exports, module) {
/**
* Obliterator ForEachWithNullKeys Function
* =========================================
*
* Helper function used to easily iterate over mixed values.
*/
var support = require_support();
var ARRAY_BUFFER_SUPPORT = support.ARRAY_BUFFER_SUPPORT;
var SYMBOL_SUPPORT = support.SYMBOL_SUPPORT;
/**
* Same function as the `forEach` but will yield `null` when the target
* does not have keys.
*
* @param {any} iterable - Iterable value.
* @param {function} callback - Callback function.
*/
module.exports = function forEachWithNullKeys(iterable, callback) {
var iterator, k, i, l, s;
if (!iterable) throw new Error("obliterator/forEachWithNullKeys: invalid iterable.");
if (typeof callback !== "function") throw new Error("obliterator/forEachWithNullKeys: expecting a callback.");
if (Array.isArray(iterable) || ARRAY_BUFFER_SUPPORT && ArrayBuffer.isView(iterable) || typeof iterable === "string" || iterable.toString() === "[object Arguments]") {
for (i = 0, l = iterable.length; i < l; i++) callback(iterable[i], null);
return;
}
if (iterable instanceof Set) {
iterable.forEach(function(value) {
callback(value, null);
});
return;
}
if (iterable instanceof Map) {
iterable.forEach(function(value, key) {
callback(value, key);
});
return;
}
if (SYMBOL_SUPPORT && Symbol.iterator in iterable && typeof iterable.next !== "function") iterable = iterable[Symbol.iterator]();
if (typeof iterable.next === "function") {
iterator = iterable;
i = 0;
while (s = iterator.next(), s.done !== true) {
callback(s.value, null);
i++;
}
return;
}
if (typeof iterable.forEach === "function") {
iterable.forEach(callback);
return;
}
for (k in iterable) if (iterable.hasOwnProperty(k)) callback(iterable[k], k);
return;
};
} });
//#endregion
//#region ../../node_modules/obliterator/includes.js
var require_includes = __commonJS({ "../../node_modules/obliterator/includes.js"(exports, module) {
/**
* Obliterator Includes Function
* ==============================
*
* Function taking an iterable and returning whether the given item can be
* found in it.
*/
var iter$4 = require_iter();
/**
* Includes.
*
* @param {Iterable} iterable - Target iterable.
* @param {function} value - Searched value.
* @return {boolean}
*/
module.exports = function includes(iterable, value) {
var iterator = iter$4(iterable);
var step;
while (step = iterator.next(), !step.done) if (step.value === value) return true;
return false;
};
} });
//#endregion
//#region ../../node_modules/obliterator/map.js
var require_map = __commonJS({ "../../node_modules/obliterator/map.js"(exports, module) {
/**
* Obliterator Map Function
* ===========================
*
* Function returning a iterator mapping the given iterator's values.
*/
var Iterator$6 = require_iterator();
var iter$3 = require_iter();
/**
* Map.
*
* @param {Iterator} target - Target iterable.
* @param {function} mapper - Map function.
* @return {Iterator}
*/
module.exports = function map(target, mapper) {
var iterator = iter$3(target);
return new Iterator$6(function next() {
var step = iterator.next();
if (step.done) return step;
return { value: mapper(step.value) };
});
};
} });
//#endregion
//#region ../../node_modules/obliterator/match.js
var require_match = __commonJS({ "../../node_modules/obliterator/match.js"(exports, module) {
/**
* Obliterator Match Function
* ===========================
*
* Function returning an iterator over the matches of the given regex on the
* target string.
*/
var Iterator$5 = require_iterator();
/**
* Match.
*
* @param {RegExp} pattern - Regular expression to use.
* @param {string} string - Target string.
* @return {Iterator}
*/
module.exports = function match(pattern, string) {
var executed = false;
if (!(pattern instanceof RegExp)) throw new Error("obliterator/match: invalid pattern. Expecting a regular expression.");
if (typeof string !== "string") throw new Error("obliterator/match: invalid target. Expecting a string.");
return new Iterator$5(function() {
if (executed && !pattern.global) {
pattern.lastIndex = 0;
return { done: true };
}
executed = true;
var m = pattern.exec(string);
if (m) return { value: m };
pattern.lastIndex = 0;
return { done: true };
});
};
} });
//#endregion
//#region ../../node_modules/obliterator/permutations.js
var require_permutations = __commonJS({ "../../node_modules/obliterator/permutations.js"(exports, module) {
/**
* Obliterator Permutations Function
* ==================================
*
* Iterator returning permutations of the given array.
*/
var Iterator$4 = require_iterator();
/**
* Helper mapping indices to items.
*/
function indicesToItems(target, items, indices, r) {
for (var i = 0; i < r; i++) target[i] = items[indices[i]];
}
/**
* Permutations.
*
* @param {array} array - Target array.
* @param {number} r - Size of the subsequences.
* @return {Iterator}
*/
module.exports = function permutations(array, r) {
if (!Array.isArray(array)) throw new Error("obliterator/permutations: first argument should be an array.");
var n = array.length;
if (arguments.length < 2) r = n;
if (typeof r !== "number") throw new Error("obliterator/permutations: second argument should be omitted or a number.");
if (r > n) throw new Error("obliterator/permutations: the size of the subsequences should not exceed the length of the array.");
var indices = new Uint32Array(n), subsequence = new Array(r), cycles = new Uint32Array(r), first = true, i;
for (i = 0; i < n; i++) {
indices[i] = i;
if (i < r) cycles[i] = n - i;
}
i = r;
return new Iterator$4(function next() {
if (first) {
first = false;
indicesToItems(subsequence, array, indices, r);
return {
value: subsequence,
done: false
};
}
var tmp, j;
i--;
if (i < 0) return { done: true };
cycles[i]--;
if (cycles[i] === 0) {
tmp = indices[i];
for (j = i; j < n - 1; j++) indices[j] = indices[j + 1];
indices[n - 1] = tmp;
cycles[i] = n - i;
return next();
} else {
j = cycles[i];
tmp = indices[i];
indices[i] = indices[n - j];
indices[n - j] = tmp;
i = r;
indicesToItems(subsequence, array, indices, r);
return {
value: subsequence,
done: false
};
}
});
};
} });
//#endregion
//#region ../../node_modules/obliterator/power-set.js
var require_power_set = __commonJS({ "../../node_modules/obliterator/power-set.js"(exports, module) {
/**
* Obliterator Power Set Function
* ===============================
*
* Iterator returning the power set of the given array.
*/
var Iterator$3 = require_iterator(), combinations = require_combinations(), chain$1 = require_chain();
/**
* Power set.
*
* @param {array} array - Target array.
* @return {Iterator}
*/
module.exports = function powerSet(array) {
var n = array.length;
var iterators = new Array(n + 1);
iterators[0] = Iterator$3.of([]);
for (var i = 1; i < n + 1; i++) iterators[i] = combinations(array, i);
return chain$1.apply(null, iterators);
};
} });
//#endregion
//#region ../../node_modules/obliterator/range.js
var require_range = __commonJS({ "../../node_modules/obliterator/range.js"(exports, module) {
/**
* Obliterator Range Function
* ===========================
*
* Function returning a range iterator.
*/
var Iterator$2 = require_iterator();
/**
* Range.
*
* @param {number} start - Start.
* @param {number} end - End.
* @param {number} step - Step.
* @return {Iterator}
*/
module.exports = function range(start, end, step) {
if (arguments.length === 1) {
end = start;
start = 0;
}
if (arguments.length < 3) step = 1;
var i = start;
var iterator = new Iterator$2(function() {
if (i < end) {
var value = i;
i += step;
return {
value,
done: false
};
}
return { done: true };
});
iterator.start = start;
iterator.end = end;
iterator.step = step;
return iterator;
};
} });
//#endregion
//#region ../../node_modules/obliterator/some.js
var require_some = __commonJS({ "../../node_modules/obliterator/some.js"(exports, module) {
/**
* Obliterator Some Function
* ==========================
*
* Function taking an iterable and a predicate and returning whether a
* matching item can be found.
*/
var iter$2 = require_iter();
/**
* Some.
*
* @param {Iterable} iterable - Target iterable.
* @param {function} predicate - Predicate function.
* @return {boolean}
*/
module.exports = function some(iterable, predicate) {
var iterator = iter$2(iterable);
var step;
while (step = iterator.next(), !step.done) if (predicate(step.value)) return true;
return false;
};
} });
//#endregion
//#region ../../node_modules/obliterator/split.js
var require_split = __commonJS({ "../../node_modules/obliterator/split.js"(exports, module) {
/**
* Obliterator Split Function
* ===========================
*
* Function returning an iterator over the pieces of a regex split.
*/
var Iterator$1 = require_iterator();
/**
* Function used to make the given pattern global.
*
* @param {RegExp} pattern - Regular expression to make global.
* @return {RegExp}
*/
function makeGlobal(pattern) {
var flags = "g";
if (pattern.multiline) flags += "m";
if (pattern.ignoreCase) flags += "i";
if (pattern.sticky) flags += "y";
if (pattern.unicode) flags += "u";
return new RegExp(pattern.source, flags);
}
/**
* Split.
*
* @param {RegExp} pattern - Regular expression to use.
* @param {string} string - Target string.
* @return {Iterator}
*/
module.exports = function split(pattern, string) {
if (!(pattern instanceof RegExp)) throw new Error("obliterator/split: invalid pattern. Expecting a regular expression.");
if (typeof string !== "string") throw new Error("obliterator/split: invalid target. Expecting a string.");
pattern = makeGlobal(pattern);
var consumed = false, current = 0;
return new Iterator$1(function() {
if (consumed) return { done: true };
var match = pattern.exec(string), value, length;
if (match) {
length = match.index + match[0].length;
value = string.slice(current, match.index);
current = length;
} else {
consumed = true;
value = string.slice(current);
}
return {
value,
done: false
};
});
};
} });
//#endregion
//#region ../../node_modules/obliterator/take.js
var require_take = __commonJS({ "../../node_modules/obliterator/take.js"(exports, module) {
/**
* Obliterator Take Function
* ==========================
*
* Function taking n or every value of the given iterator and returns them
* into an array.
*/
var iter$1 = require_iter();
/**
* Take.
*
* @param {Iterable} iterable - Target iterable.
* @param {number} [n] - Optional number of items to take.
* @return {array}
*/
module.exports = function take$1(iterable, n) {
var l = arguments.length > 1 ? n : Infinity, array = l !== Infinity ? new Array(l) : [], step, i = 0;
var iterator = iter$1(iterable);
while (true) {
if (i === l) return array;
step = iterator.next();
if (step.done) {
if (i !== n) array.length = i;
return array;
}
array[i++] = step.value;
}
};
} });
//#endregion
//#region ../../node_modules/obliterator/take-into.js
var require_take_into = __commonJS({ "../../node_modules/obliterator/take-into.js"(exports, module) {
/**
* Obliterator Take Into Function
* ===============================
*
* Same as the take function but enables the user to select an array class
* in which to insert the retrieved values.
*/
var iter = require_iter();
/**
* Take Into.
*
* @param {function} ArrayClass - Array class to use.
* @param {Iterable} iterable - Target iterable.
* @param {number} n - Number of items to take.
* @return {array}
*/
module.exports = function takeInto(ArrayClass, iterable, n) {
var array = new ArrayClass(n), step, i = 0;
var iterator = iter(iterable);
while (true) {
if (i === n) return array;
step = iterator.next();
if (step.done) {
if (i !== n) return array.slice(0, i);
return array;
}
array[i++] = step.value;
}
};
} });
//#endregion
//#region ../../node_modules/obliterator/index.js
var require_obliterator = __commonJS({ "../../node_modules/obliterator/index.js"(exports) {
/**
* Obliterator Library Endpoint
* =============================
*
* Exporting the library's functions.
*/
exports.Iterator = require_iterator();
exports.iter = require_iter();
exports.chain = require_chain();
exports.combinations = require_combinations();
exports.consume = require_consume();
exports.every = require_every();
exports.filter = require_filter();
exports.find = require_find();
exports.forEach = require_foreach();
exports.forEachWithNullKeys = require_foreach_with_null_keys();
exports.includes = require_includes();
exports.map = require_map();
exports.match = require_match();
exports.permutations = require_permutations();
exports.powerSet = require_power_set();
exports.range = require_range();
exports.some = require_some();
exports.split = require_split();
exports.take = require_take();
exports.takeInto = require_take_into();
} });
//#endregion
//#region ../../node_modules/graphology/dist/graphology.esm.js
var import_obliterator = __toESM(require_obliterator(), 1);
const { Iterator, take, chain } = import_obliterator.default;
/**
* Graphology Utilities
* =====================
*
* Collection of helpful functions used by the implementation.
*/
/**
* Object.assign-like polyfill.
*
* @param {object} target - First object.
* @param {object} [...objects] - Objects to merge.
* @return {object}
*/
function assignPolyfill() {
const target = arguments[0];
for (let i = 1, l = arguments.length; i < l; i++) {
if (!arguments[i]) continue;
for (const k in arguments[i]) target[k] = arguments[i][k];
}
return target;
}
let assign = assignPolyfill;
if (typeof Object.assign === "function") assign = Object.assign;
/**
* Function returning the first matching edge for given path.
* Note: this function does not check the existence of source & target. This
* must be performed by the caller.
*
* @param {Graph} graph - Target graph.
* @param {any} source - Source node.
* @param {any} target - Target node.
* @param {string} type - Type of the edge (mixed, directed or undirected).
* @return {string|null}
*/
function getMatchingEdge(graph, source, target, type) {
const sourceData = graph._nodes.get(source);
let edge = null;
if (!sourceData) return edge;
if (type === "mixed") edge = sourceData.out && sourceData.out[target] || sourceData.undirected && sourceData.undirected[target];
else if (type === "directed") edge = sourceData.out && sourceData.out[target];
else edge = sourceData.undirected && sourceData.undirected[target];
return edge;
}
/**
* Checks whether the given value is a plain object.
*
* @param {mixed} value - Target value.
* @return {boolean}
*/
function isPlainObject(value) {
return typeof value === "object" && value !== null;
}
/**
* Checks whether the given object is empty.
*
* @param {object} o - Target Object.
* @return {boolean}
*/
function isEmpty(o) {
let k;
for (k in o) return false;
return true;
}
/**
* Creates a "private" property for the given member name by concealing it
* using the `enumerable` option.
*
* @param {object} target - Target object.
* @param {string} name - Member name.
*/
function privateProperty(target, name, value) {
Object.defineProperty(target, name, {
enumerable: false,
configurable: false,
writable: true,
value
});
}
/**
* Creates a read-only property for the given member name & the given getter.
*
* @param {object} target - Target object.
* @param {string} name - Member name.
* @param {mixed} value - The attached getter or fixed value.
*/
function readOnlyProperty(target, name, value) {
const descriptor = {
enumerable: true,
configurable: true
};
if (typeof value === "function") descriptor.get = value;
else {
descriptor.value = value;
descriptor.writable = false;
}
Object.defineProperty(target, name, descriptor);
}
/**
* Returns whether the given object constitute valid hints.
*
* @param {object} hints - Target object.
*/
function validateHints(hints) {
if (!isPlainObject(hints)) return false;
if (hints.attributes && !Array.isArray(hints.attributes)) return false;
return true;
}
/**
* Creates a function generating incremental ids for edges.
*
* @return {function}
*/
function incrementalIdStartingFromRandomByte() {
let i = Math.floor(Math.random() * 256) & 255;
return () => {
return i++;
};
}
/**
* Graphology Custom Errors
* =========================
*
* Defining custom errors for ease of use & easy unit tests across
* implementations (normalized typology rather than relying on error
* messages to check whether the correct error was found).
*/
var GraphError = class extends Error {
constructor(message) {
super();
this.name = "GraphError";
this.message = message;
}
};
var InvalidArgumentsGraphError = class InvalidArgumentsGraphError extends GraphError {
constructor(message) {
super(message);
this.name = "InvalidArgumentsGraphError";
if (typeof Error.captureStackTrace === "function") Error.captureStackTrace(this, InvalidArgumentsGraphError.prototype.constructor);
}
};
var NotFoundGraphError = class NotFoundGraphError extends GraphError {
constructor(message) {
super(message);
this.name = "NotFoundGraphError";
if (typeof Error.captureStackTrace === "function") Error.captureStackTrace(this, NotFoundGraphError.prototype.constructor);
}
};
var UsageGraphError = class UsageGraphError extends GraphError {
constructor(message) {
super(message);
this.name = "UsageGraphError";
if (typeof Error.captureStackTrace === "function") Error.captureStackTrace(this, UsageGraphError.prototype.constructor);
}
};
/**
* Graphology Internal Data Classes
* =================================
*
* Internal classes hopefully reduced to structs by engines & storing
* necessary information for nodes & edges.
*
* Note that those classes don't rely on the `class` keyword to avoid some
* cruft introduced by most of ES2015 transpilers.
*/
/**
* MixedNodeData class.
*
* @constructor
* @param {string} string - The node's key.
* @param {object} attributes - Node's attributes.
*/
function MixedNodeData(key, attributes) {
this.key = key;
this.attributes = attributes;
this.clear();
}
MixedNodeData.prototype.clear = function() {
this.inDegree = 0;
this.outDegree = 0;
this.undirectedDegree = 0;
this.undirectedLoops = 0;
this.directedLoops = 0;
this.in = {};
this.out = {};
this.undirected = {};
};
/**
* DirectedNodeData class.
*
* @constructor
* @param {string} string - The node's key.
* @param {object} attributes - Node's attributes.
*/
function DirectedNodeData(key, attributes) {
this.key = key;
this.attributes = attributes;
this.clear();
}
DirectedNodeData.prototype.clear = function() {
this.inDegree = 0;
this.outDegree = 0;
this.directedLoops = 0;
this.in = {};
this.out = {};
};
/**
* UndirectedNodeData class.
*
* @constructor
* @param {string} string - The node's key.
* @param {object} attributes - Node's attributes.
*/
function UndirectedNodeData(key, attributes) {
this.key = key;
this.attributes = attributes;
this.clear();
}
UndirectedNodeData.prototype.clear = function() {
this.undirectedDegree = 0;
this.undirectedLoops = 0;
this.undirected = {};
};
/**
* EdgeData class.
*
* @constructor
* @param {boolean} undirected - Whether the edge is undirected.
* @param {string} string - The edge's key.
* @param {string} source - Source of the edge.
* @param {string} target - Target of the edge.
* @param {object} attributes - Edge's attributes.
*/
function EdgeData(undirected, key, source, target, attributes) {
this.key = key;
this.attributes = attributes;
this.undirected = undirected;
this.source = source;
this.target = target;
}
EdgeData.prototype.attach = function() {
let outKey = "out";
let inKey = "in";
if (this.undirected) outKey = inKey = "undirected";
const source = this.source.key;
const target = this.target.key;
this.source[outKey][target] = this;
if (this.undirected && source === target) return;
this.target[inKey][source] = this;
};
EdgeData.prototype.attachMulti = function() {
let outKey = "out";
let inKey = "in";
const source = this.source.key;
const target = this.target.key;
if (this.undirected) outKey = inKey = "undirected";
const adj = this.source[outKey];
const head = adj[target];
if (typeof head === "undefined") {
adj[target] = this;
if (!(this.undirected && source === target)) this.target[inKey][source] = this;
return;
}
head.previous = this;
this.next = head;
adj[target] = this;
this.target[inKey][source] = this;
};
EdgeData.prototype.detach = function() {
const source = this.source.key;
const target = this.target.key;
let outKey = "out";
let inKey = "in";
if (this.undirected) outKey = inKey = "undirected";
delete this.source[outKey][target];
delete this.target[inKey][source];
};
EdgeData.prototype.detachMulti = function() {
const source = this.source.key;
const target = this.target.key;
let outKey = "out";
let inKey = "in";
if (this.undirected) outKey = inKey = "undirected";
if (this.previous === void 0) if (this.next === void 0) {
delete this.source[outKey][target];
delete this.target[inKey][source];
} else {
this.next.previous = void 0;
this.source[outKey][target] = this.next;
this.target[inKey][source] = this.next;
}
else {
this.previous.next = this.next;
if (this.next !== void 0) this.next.previous = this.previous;
}
};
/**
* Graphology Node Attributes methods
* ===================================
*/
const NODE = 0;
const SOURCE = 1;
const TARGET = 2;
const OPPOSITE = 3;
function findRelevantNodeData(graph, method, mode, nodeOrEdge, nameOrEdge, add1, add2) {
let nodeData, edgeData, arg1, arg2;
nodeOrEdge = "" + nodeOrEdge;
if (mode === NODE) {
nodeData = graph._nodes.get(nodeOrEdge);
if (!nodeData) throw new NotFoundGraphError(`Graph.${method}: could not find the "${nodeOrEdge}" node in the graph.`);
arg1 = nameOrEdge;
arg2 = add1;
} else if (mode === OPPOSITE) {
nameOrEdge = "" + nameOrEdge;
edgeData = graph._edges.get(nameOrEdge);
if (!edgeData) throw new NotFoundGraphError(`Graph.${method}: could not find the "${nameOrEdge}" edge in the graph.`);
const source = edgeData.source.key;
const target = edgeData.target.key;
if (nodeOrEdge === source) nodeData = edgeData.target;
else if (nodeOrEdge === target) nodeData = edgeData.source;
else throw new NotFoundGraphError(`Graph.${method}: the "${nodeOrEdge}" node is not attached to the "${nameOrEdge}" edge (${source}, ${target}).`);
arg1 = add1;
arg2 = add2;
} else {
edgeData = graph._edges.get(nodeOrEdge);
if (!edgeData) throw new NotFoundGraphError(`Graph.${method}: could not find the "${nodeOrEdge}" edge in the graph.`);
if (mode === SOURCE) nodeData = edgeData.source;
else nodeData = edgeData.target;
arg1 = nameOrEdge;
arg2 = add1;
}
return [
nodeData,
arg1,
arg2
];
}
function attachNodeAttributeGetter(Class, method, mode) {
Class.prototype[method] = function(nodeOrEdge, nameOrEdge, add1) {
const [data, name] = findRelevantNodeData(this, method, mode, nodeOrEdge, nameOrEdge, add1);
return data.attributes[name];
};
}
function attachNodeAttributesGetter(Class, method, mode) {
Class.prototype[method] = function(nodeOrEdge, nameOrEdge) {
const [data] = findRelevantNodeData(this, method, mode, nodeOrEdge, nameOrEdge);
return data.attributes;
};
}
function attachNodeAttributeChecker(Class, method, mode) {
Class.prototype[method] = function(nodeOrEdge, nameOrEdge, add1) {
const [data, name] = findRelevantNodeData(this, method, mode, nodeOrEdge, nameOrEdge, add1);
return data.attributes.hasOwnProperty(name);
};
}
function attachNodeAttributeSetter(Class, method, mode) {
Class.prototype[method] = function(nodeOrEdge, nameOrEdge, add1, add2) {
const [data, name, value] = findRelevantNodeData(this, method, mode, nodeOrEdge, nameOrEdge, add1, add2);
data.attributes[name] = value;
this.emit("nodeAttributesUpdated", {
key: data.key,
type: "set",
attributes: data.attributes,
name
});
return this;
};
}
function attachNodeAttributeUpdater(Class, method, mode) {
Class.prototype[method] = function(nodeOrEdge, nameOrEdge, add1, add2) {
const [data, name, updater] = findRelevantNodeData(this, method, mode, nodeOrEdge, nameOrEdge, add1, add2);
if (typeof updater !== "function") throw new InvalidArgumentsGraphError(`Graph.${method}: updater should be a function.`);
const attributes = data.attributes;
const value = updater(attributes[name]);
attributes[name] = value;
this.emit("nodeAttributesUpdated", {
key: data.key,
type: "set",
attributes: data.attributes,
name
});
return this;
};
}
function attachNodeAttributeRemover(Class, method, mode) {
Class.prototype[method] = function(nodeOrEdge, nameOrEdge, add1) {
const [data, name] = findRelevantNodeData(this, method, mode, nodeOrEdge, nameOrEdge, add1);
delete data.attributes[name];
this.emit("nodeAttributesUpdated", {
key: data.key,
type: "remove",
attributes: data.attributes,
name
});
return this;
};
}
function attachNodeAttributesReplacer(Class, method, mode) {
Class.prototype[method] = function(nodeOrEdge, nameOrEdge, add1) {
const [data, attributes] = findRelevantNodeData(this, method, mode, nodeOrEdge, nameOrEdge, add1);
if (!isPlainObject(attributes)) throw new InvalidArgumentsGraphError(`Graph.${method}: provided attributes are not a plain object.`);
data.attributes = attributes;
this.emit("nodeAttributesUpdated", {
key: data.key,
type: "replace",
attributes: data.attributes
});
return this;
};
}
function attachNodeAttributesMerger(Class, method, mode) {
Class.prototype[method] = function(nodeOrEdge, nameOrEdge, add1) {
const [data, attributes] = findRelevantNodeData(this, method, mode, nodeOrEdge, nameOrEdge, add1);
if (!isPlainObject(attributes)) throw new InvalidArgumentsGraphError(`Graph.${method}: provided attributes are not a plain object.`);
assign(data.attributes, attributes);
this.emit("nodeAttributesUpdated", {
key: data.key,
type: "merge",
attributes: data.attributes,
data: attributes
});
return this;
};
}
function attachNodeAttributesUpdater(Class, method, mode) {
Class.prototype[method] = function(nodeOrEdge, nameOrEdge, add1) {
const [data, updater] = findRelevantNodeData(this, method, mode, nodeOrEdge, nameOrEdge, add1);
if (typeof updater !== "function") throw new InvalidArgumentsGraphError(`Graph.${method}: provided updater is not a function.`);
data.attributes = updater(data.attributes);
this.emit("nodeAttributesUpdated", {
key: data.key,
type: "update",
attributes: data.attributes
});
return this;
};
}
/**
* List of methods to attach.
*/
const NODE_ATTRIBUTES_METHODS = [
{
name: (element) => `get${element}Attribute`,
attacher: attachNodeAttributeGetter
},
{
name: (element) => `get${element}Attributes`,
attacher: attachNodeAttributesGetter
},
{
name: (element) => `has${element}Attribute`,
attacher: attachNodeAttributeChecker
},
{
name: (element) => `set${element}Attribute`,
attacher: attachNodeAttributeSetter
},
{
name: (element) => `update${element}Attribute`,
attacher: attachNodeAttributeUpdater
},
{
name: (element) => `remove${element}Attribute`,
attacher: attachNodeAttributeRemover
},
{
name: (element) => `replace${element}Attributes`,
attacher: attachNodeAttributesReplacer
},
{
name: (element) => `merge${element}Attributes`,
attacher: attachNodeAttributesMerger
},
{
name: (element) => `update${element}Attributes`,
attacher: attachNodeAttributesUpdater
}
];
/**
* Attach every attributes-related methods to a Graph class.
*
* @param {function} Graph - Target class.
*/
function attachNodeAttributesMethods(Graph$1) {
NODE_ATTRIBUTES_METHODS.forEach(function({ name, attacher }) {
attacher(Graph$1, name("Node"), NODE);
attacher(Graph$1, name("Source"), SOURCE);
attacher(Graph$1, name("Target"), TARGET);
attacher(Graph$1, name("Opposite"), OPPOSITE);
});
}
/**
* Graphology Edge Attributes methods
* ===================================
*/
/**
* Attach an attribute getter method onto the provided class.
*
* @param {function} Class - Target class.
* @param {string} method - Method name.
* @param {string} type - Type of the edge to find.
*/
function attachEdgeAttributeGetter(Class, method, type) {
/**
* Get the desired attribute for the given element (node or edge).
*
* Arity 2:
* @param {any} element - Target element.
* @param {string} name - Attribute's name.
*
* Arity 3 (only for edges):
* @param {any} source - Source element.
* @param {any} target - Target element.
* @param {string} name - Attribute's name.
*
* @return {mixed} - The attribute's value.
*
* @throws {Error} - Will throw if too many arguments are provided.
* @throws {Error} - Will throw if any of the elements is not found.
*/
Class.prototype[method] = function(element, name) {
let data;
if (this.type !== "mixed" && type !== "mixed" && type !== this.type) throw new UsageGraphError(`Graph.${method}: cannot find this type of edges in your ${this.type} graph.`);
if (arguments.length > 2) {
if (this.multi) throw new UsageGraphError(`Graph.${method}: cannot use a {source,target} combo when asking about an edge's attributes in a MultiGraph since we cannot infer the one you want information about.`);
const source = "" + element;
const target = "" + name;
name = arguments[2];
data = getMatchingEdge(this, source, target, type);
if (!data) throw new NotFoundGraphError(`Graph.${method}: could not find an edge for the given path ("${source}" - "${target}").`);
} else {
if (type !== "mixed") throw new UsageGraphError(`Graph.${method}: calling this method with only a key (vs. a source and target) does not make sense since an edge with this key could have the other type.`);
element = "" + element;
data = this._edges.get(element);
if (!data) throw new NotFoundGraphError(`Graph.${method}: could not find the "${element}" edge in the graph.`);
}
return data.attributes[name];
};
}
/**
* Attach an attributes getter method onto the provided class.
*
* @param {function} Class - Target class.
* @param {string} method - Method name.
* @param {string} type - Type of the edge to find.
*/
function attachEdgeAttributesGetter(Class, method, type) {
/**
* Retrieves all the target element's attributes.
*
* Arity 2:
* @param {any} element - Target element.
*
* Arity 3 (only for edges):
* @param {any} source - Source element.
* @param {any} target - Target element.
*
* @return {object} - The element's attributes.
*
* @throws {Error} - Will throw if too many arguments are provided.
* @throws {Error} - Will throw if any of the elements is not found.
*/
Class.prototype[method] = function(element) {
let data;
if (this.type !== "mixed" && type !== "mixed" && type !== this.type) throw new UsageGraphError(`Graph.${method}: cannot find this type of edges in your ${this.type} graph.`);
if (arguments.length > 1) {
if (this.multi) throw new UsageGraphError(`Graph.${method}: cannot use a {source,target} combo when asking about an edge's attributes in a MultiGraph since we cannot infer the one you want information about.`);
const source = "" + element, target = "" + arguments[1];
data = getMatchingEdge(this, source, target, type);
if (!data) throw new NotFoundGraphError(`Graph.${method}: could not find an edge for the given path ("${source}" - "${target}").`);
} else {
if (type !== "mixed") throw new UsageGraphError(`Graph.${method}: calling this method with only a key (vs. a source and target) does not make sense since an edge with this key could have the other type.`);
element = "" + element;
data = this._edges.get(element);
if (!data) throw new NotFoundGraphError(`Graph.${method}: could not find the "${element}" edge in the graph.`);
}
return data.attributes;
};
}
/**
* Attach an attribute checker method onto the provided class.
*
* @param {function} Class - Target class.
* @param {string} method - Method name.
* @param {string} type - Type of the edge to find.
*/
function attachEdgeAttributeChecker(Class, method, type) {
/**
* Checks whether the desired attribute is set for the given element (node or edge).
*
* Arity 2:
* @param {any} element - Target element.
* @param {string} name - Attribute's name.
*
* Arity 3 (only for edges):
* @param {any} source - Source element.
* @param {any} target - Target element.
* @param {string} name - Attribute's name.
*
* @return {boolean}
*
* @throws {Error} - Will throw if too many arguments are provided.
* @throws {Error} - Will throw if any of the elements is not found.
*/
Class.prototype[method] = function(element, name) {
let data;
if (this.type !== "mixed" && type !== "mixed" && type !== this.type) throw new UsageGraphError(`Graph.${method}: cannot find this type of edges in your ${this.type} graph.`);
if (arguments.length > 2) {
if (this.multi) throw new UsageGraphError(`Graph.${method}: cannot use a {source,target} combo when asking about an edge's attributes in a MultiGraph since we cannot infer the one you want information about.`);
const source = "" + element;
const target = "" + name;
name = arguments[2];
data = getMatchingEdge(this, source, target, type);
if (!data) throw new NotFoundGraphError(`Graph.${method}: could not find an edge for the given path ("${source}" - "${target}").`);
} else {
if (type !== "mixed") throw new UsageGraphError(`Graph.${method}: calling this method with only a key (vs. a source and target) does not make sense since an edge with this key could have the other type.`);
element = "" + element;
data = this._edges.get(element);
if (!data) throw new NotFoundGraphError(`Graph.${method}: could not find the "${element}" edge in the graph.`);
}
return data.attributes.hasOwnProperty(name);
};
}
/**
* Attach an attribute setter method onto the provided class.
*
* @param {function} Class - Target class.
* @param {string} method - Method name.
* @param {string} type - Type of the edge to find.
*/
function attachEdgeAttributeSetter(Class, method, type) {
/**
* Set the desired attribute for the given element (node or edge).
*
* Arity 2:
* @param {any} element - Target element.
* @param {string} name - Attribute's name.
* @param {mixed} value - New attribute value.
*
* Arity 3 (only for edges):
* @param {any} source - Source element.
* @param {any} target - Target element.
* @param {string} name - Attribute's name.
* @param {mixed} value - New attribute value.
*
* @return {Graph} - Returns itself for chaining.
*
* @throws {Error} - Will throw if too many arguments are provided.
* @throws {Error} - Will throw if any of the elements is not found.
*/
Class.prototype[method] = function(element, name, value) {
let data;
if (this.type !== "mixed" && type !== "mixed" && type !== this.type) throw new UsageGraphError(`Graph.${method}: cannot find this type of edges in your ${this.type} graph.`);
if (arguments.length > 3) {
if (this.multi) throw new UsageGraphError(`Graph.${method}: cannot use a {source,target} combo when asking about an edge's attributes in a MultiGraph since we cannot infer the one you want information about.`);
const source = "" + element;
const target = "" + name;
name = arguments[2];
value = arguments[3];
data = getMatchingEdge(this, source, target, type);
if (!data) throw new NotFoundGraphError(`Graph.${method}: could not find an edge for the given path ("${source}" - "${target}").`);
} else {
if (type !== "mixed") throw new UsageGraphError(`Graph.${method}: calling this method with only a key (vs. a source and target) does not make sense since an edge with this key could have the other type.`);
element = "" + element;
data = this._edges.get(element);
if (!data) throw new NotFoundGraphError(`Graph.${method}: could not find the "${element}" edge in the graph.`);
}
data.attributes[name] = value;
this.emit("edgeAttributesUpdated", {
key: data.key,
type: "set",
attributes: data.attributes,
name
});
return this;
};
}
/**
* Attach an attribute updater method onto the provided class.
*
* @param {function} Class - Target class.
* @param {string} method - Method name.
* @param {string} type - Type of the edge to find.
*/
function attachEdgeAttributeUpdater(Class, method, type) {
/**
* Update the desired attribute for the given element (node or edge) using
* the provided function.
*
* Arity 2:
* @param {any} element - Target element.
* @param {string} name - Attribute's name.
* @param {function} updater - Updater function.
*
* Arity 3 (only for edges):
* @param {any} source - Source element.
* @param {any} target - Target element.
* @param {string} name - Attribute's name.
* @param {function} upda