alinea
Version:
[](https://npmjs.org/package/alinea) [](https://packagephobia.com/result?p=alinea)
228 lines (226 loc) • 5.7 kB
JavaScript
import "../../chunks/chunk-U5RRZUYZ.js";
// src/core/util/FractionalIndexing.ts
var BASE_62_DIGITS = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
var SMALLEST_INTEGER = "A00000000000000000000000000";
var INTEGER_ZERO = "a0";
function midpoint(a, b, digits) {
if (b !== null && a >= b) {
throw new Error(a + " >= " + b);
}
if (a.slice(-1) === "0" || b && b.slice(-1) === "0") {
throw new Error("trailing zero");
}
if (b) {
let n = 0;
while ((a[n] || "0") === b[n]) {
n++;
}
if (n > 0) {
return b.slice(0, n) + midpoint(a.slice(n), b.slice(n), digits);
}
}
const digitA = a ? digits.indexOf(a[0]) : 0;
const digitB = b !== null ? digits.indexOf(b[0]) : digits.length;
if (digitB - digitA > 1) {
const midDigit = Math.round(0.5 * (digitA + digitB));
return digits[midDigit];
} else {
if (b && b.length > 1) {
return b.slice(0, 1);
} else {
return digits[digitA] + midpoint(a.slice(1), null, digits);
}
}
}
function validateInteger(int) {
if (int.length !== getIntegerLength(int[0])) {
throw new Error("invalid integer part of order key: " + int);
}
}
function getIntegerLength(head) {
if (head >= "a" && head <= "z") {
return head.charCodeAt(0) - "a".charCodeAt(0) + 2;
} else if (head >= "A" && head <= "Z") {
return "Z".charCodeAt(0) - head.charCodeAt(0) + 2;
} else {
throw new Error("invalid order key head: " + head);
}
}
function getIntegerPart(key) {
const integerPartLength = getIntegerLength(key[0]);
if (integerPartLength > key.length) {
throw new Error("invalid order key: " + key);
}
return key.slice(0, integerPartLength);
}
function validateOrderKey(key) {
if (key === SMALLEST_INTEGER) {
throw new Error("invalid order key: " + key);
}
const i = getIntegerPart(key);
const f = key.slice(i.length);
if (f.slice(-1) === "0") {
throw new Error("invalid order key: " + key);
}
}
function isValidOrderKey(key) {
try {
validateOrderKey(key);
return true;
} catch (e) {
return false;
}
}
function incrementInteger(x, digits) {
validateInteger(x);
const [head, ...digs] = x.split("");
let carry = true;
for (let i = digs.length - 1; carry && i >= 0; i--) {
const d = digits.indexOf(digs[i]) + 1;
if (d === digits.length) {
digs[i] = "0";
} else {
digs[i] = digits[d];
carry = false;
}
}
if (carry) {
if (head === "Z") {
return "a0";
}
if (head === "z") {
return null;
}
const h = String.fromCharCode(head.charCodeAt(0) + 1);
if (h > "a") {
digs.push("0");
} else {
digs.pop();
}
return h + digs.join("");
} else {
return head + digs.join("");
}
}
function decrementInteger(x, digits) {
validateInteger(x);
const [head, ...digs] = x.split("");
let borrow = true;
for (let i = digs.length - 1; borrow && i >= 0; i--) {
const d = digits.indexOf(digs[i]) - 1;
if (d === -1) {
digs[i] = digits.slice(-1);
} else {
digs[i] = digits[d];
borrow = false;
}
}
if (borrow) {
if (head === "a") {
return "Z" + digits.slice(-1);
}
if (head === "A") {
return null;
}
const h = String.fromCharCode(head.charCodeAt(0) - 1);
if (h < "Z") {
digs.push(digits.slice(-1));
} else {
digs.pop();
}
return h + digs.join("");
} else {
return head + digs.join("");
}
}
function generateKeyBetween(a, b, digits = BASE_62_DIGITS) {
if (a !== null) {
validateOrderKey(a);
}
if (b !== null) {
validateOrderKey(b);
}
if (a !== null && b !== null && a >= b) {
throw new Error(a + " >= " + b);
}
if (a === null) {
if (b === null) {
return INTEGER_ZERO;
}
const ib2 = getIntegerPart(b);
const fb2 = b.slice(ib2.length);
if (ib2 === SMALLEST_INTEGER) {
return ib2 + midpoint("", fb2, digits);
}
if (ib2 < b) {
return ib2;
}
const res = decrementInteger(ib2, digits);
if (res === null) {
throw new Error("cannot decrement any more");
}
return res;
}
if (b === null) {
const ia2 = getIntegerPart(a);
const fa2 = a.slice(ia2.length);
const i2 = incrementInteger(ia2, digits);
return i2 === null ? ia2 + midpoint(fa2, null, digits) : i2;
}
const ia = getIntegerPart(a);
const fa = a.slice(ia.length);
const ib = getIntegerPart(b);
const fb = b.slice(ib.length);
if (ia === ib) {
return ia + midpoint(fa, fb, digits);
}
const i = incrementInteger(ia, digits);
if (i === null) {
throw new Error("cannot increment any more");
}
if (i < b) {
return i;
}
return ia + midpoint(fa, null, digits);
}
function generateNKeysBetween(a, b, n, digits = BASE_62_DIGITS) {
if (n === 0) {
return [];
}
if (n === 1) {
return [generateKeyBetween(a, b, digits)];
}
if (b === null) {
let c2 = generateKeyBetween(a, b, digits);
const result = [c2];
for (let i = 0; i < n - 1; i++) {
c2 = generateKeyBetween(c2, b, digits);
result.push(c2);
}
return result;
}
if (a === null) {
let c2 = generateKeyBetween(a, b, digits);
const result = [c2];
for (let i = 0; i < n - 1; i++) {
c2 = generateKeyBetween(a, c2, digits);
result.push(c2);
}
result.reverse();
return result;
}
const mid = Math.floor(n / 2);
const c = generateKeyBetween(a, b, digits);
return [
...generateNKeysBetween(a, c, mid, digits),
c,
...generateNKeysBetween(c, b, n - mid - 1, digits)
];
}
export {
BASE_62_DIGITS,
generateKeyBetween,
generateNKeysBetween,
isValidOrderKey,
validateOrderKey
};