@nitrogenbuilder/client-core
Version:
Nitrogen Builder Core Client
72 lines (71 loc) • 2.24 kB
JavaScript
const ALPHA = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
const ALNUM = ALPHA + '0123456789';
// Random 4-char id. Only a FALLBACK now (before a siteId is assigned, or if the
// server runs out of single-char site ids). Primary minting is namespaced and
// collision-free (siteId + base62 counter) — see `nextNamespacedId` / the editor.
export function generateShortId() {
let id = ALPHA[Math.floor(Math.random() * ALPHA.length)];
for (let i = 0; i < 3; i++) {
id += ALNUM[Math.floor(Math.random() * ALNUM.length)];
}
return id;
}
// base62 codec for the per-client id counter (compact, letter-or-digit chars).
const B62 = ALNUM; // a-zA-Z0-9
export function toBase62(n) {
if (n <= 0)
return B62[0]; // zero-digit, so it round-trips (fromBase62 → 0)
let s = '';
while (n > 0) {
s = B62[n % 62] + s;
n = Math.floor(n / 62);
}
return s;
}
export function fromBase62(s) {
let n = 0;
for (const c of s) {
const i = B62.indexOf(c);
if (i < 0)
return NaN;
n = n * 62 + i;
}
return n;
}
export function collectIds(page) {
const ids = new Set();
function walk(mods) {
for (const mod of mods) {
ids.add(mod.id);
const children = mod.props?.children;
if (Array.isArray(children)) {
walk(children);
}
else if (children && typeof children === 'object') {
for (const slot of Object.keys(children)) {
if (Array.isArray(children[slot]))
walk(children[slot]);
}
}
}
}
walk(page);
return ids;
}
export function generateUniqueShortId(page, extraUsed) {
const used = collectIds(page);
if (extraUsed) {
for (const id of extraUsed)
used.add(id);
}
for (let i = 0; i < 100; i++) {
const id = generateShortId();
if (!used.has(id))
return id;
}
throw new Error('shortId: exhausted attempts generating unique id');
}
export const SHORT_ID_PATTERN = /^[A-Za-z][A-Za-z0-9_-]{0,63}$/;
export function isValidId(id) {
return SHORT_ID_PATTERN.test(id);
}