You've already forked obsidian-visualiser
Change shared files naming. Rework tree structure and item management rendering.
This commit is contained in:
216
shared/general.ts
Normal file
216
shared/general.ts
Normal file
@@ -0,0 +1,216 @@
|
||||
const ID_SIZE = 24;
|
||||
const URLSafeCharacters = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-_.~';
|
||||
|
||||
export function unifySlug(slug: string | string[]): string
|
||||
{
|
||||
return (Array.isArray(slug) ? slug.join('/') : slug);
|
||||
}
|
||||
export function getID()
|
||||
{
|
||||
for (var id = [], i = 0; i < ID_SIZE; i++)
|
||||
id.push(URLSafeCharacters[URLSafeCharacters.length * Math.random() | 0]);
|
||||
return id.join("");
|
||||
}
|
||||
export function encodeBase(value: string): string
|
||||
{
|
||||
if(value === '')
|
||||
return '';
|
||||
|
||||
const buffer = Buffer.from(value, 'utf8'), base = BigInt(URLSafeCharacters.length);
|
||||
let nb = BigInt('0x' + buffer.toHex()), result = [];
|
||||
|
||||
while(nb > 0)
|
||||
{
|
||||
const remaining = nb % base;
|
||||
result.push(URLSafeCharacters[Number(remaining)]);
|
||||
nb = (nb - remaining) / base;
|
||||
}
|
||||
|
||||
const text = result.reverse().join('');
|
||||
return text;
|
||||
}
|
||||
export function decodeBase(value: string): string
|
||||
{
|
||||
if(value === '')
|
||||
return '';
|
||||
|
||||
const result = '', base = BigInt(URLSafeCharacters.length);
|
||||
let nb = BigInt(0);
|
||||
value.split('').forEach(e => nb = nb * base + BigInt(URLSafeCharacters.indexOf(e)));
|
||||
|
||||
const text = Buffer.from(nb.toString(16), 'hex').toString('utf8');
|
||||
return text;
|
||||
}
|
||||
export function group<
|
||||
T,
|
||||
K extends keyof T,
|
||||
V extends keyof T,
|
||||
KeyType extends string | number | symbol = Extract<T[K], string | number | symbol>
|
||||
>(
|
||||
table: T[],
|
||||
key: K & (T[K] extends string | number | symbol ? K : never),
|
||||
value: V
|
||||
): Record<KeyType, T[V]> {
|
||||
return table.reduce((p, v) => {
|
||||
p[v[key] as KeyType] = v[value];
|
||||
return p;
|
||||
}, {} as Record<KeyType, T[V]>);
|
||||
}
|
||||
export function parsePath(path: string): string
|
||||
{
|
||||
return path.replace(/(\d+?)\. ?/g, '').toLowerCase().replaceAll(" ", "-").normalize("NFD").replaceAll(/[\u0300-\u036f]/g, "").replaceAll('(', '').replaceAll(')', '').replace(/\-+/g, '-');
|
||||
}
|
||||
export function parseId(id: string | undefined): string | undefined
|
||||
{
|
||||
return id;
|
||||
//return id?.normalize('NFD')?.replace(/[\u0300-\u036f]/g, '')?.replace(/^\d\. */g, '')?.replace(/\s/g, "-")?.replace(/%/g, "-percent")?.replace(/\?/g, "-q")?.toLowerCase();
|
||||
}
|
||||
export function padLeft(text: string, pad: string, length: number): string
|
||||
{
|
||||
return text.concat(pad.repeat(length - text.length));
|
||||
}
|
||||
export function padRight(text: string, pad: string, length: number): string
|
||||
{
|
||||
return pad.repeat(length - text.length).concat(text);
|
||||
}
|
||||
export function deepEquals(a: any, b: any): boolean
|
||||
{
|
||||
if(a === b) return true;
|
||||
|
||||
if (a && b && typeof a == 'object' && typeof b == 'object')
|
||||
{
|
||||
if (a.constructor !== b.constructor) return false;
|
||||
|
||||
let length, i, keys;
|
||||
if (Array.isArray(a))
|
||||
{
|
||||
length = a.length;
|
||||
if (length != b.length) return false;
|
||||
for (i = length; i-- !== 0;)
|
||||
if (!deepEquals(a[i], b[i])) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (a.constructor === RegExp) return a.source === b.source && a.flags === b.flags;
|
||||
if (a.valueOf !== Object.prototype.valueOf) return a.valueOf() === b.valueOf();
|
||||
if (a.toString !== Object.prototype.toString) return a.toString() === b.toString();
|
||||
|
||||
keys = Object.keys(a) as Array<keyof typeof a>;
|
||||
length = keys.length;
|
||||
if (length !== Object.keys(b).length) return false;
|
||||
|
||||
for (i = length; i-- !== 0;)
|
||||
if (!Object.prototype.hasOwnProperty.call(b, keys[i]!)) return false;
|
||||
|
||||
for (i = length; i-- !== 0;)
|
||||
if(!deepEquals(a[keys[i]!], b[keys[i]!])) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return a !== a && b !== b;
|
||||
}
|
||||
export function format(date: Date, template: string): string
|
||||
{
|
||||
const months = {
|
||||
0: 'janvier',
|
||||
1: 'fevrier',
|
||||
2: 'mars',
|
||||
3: 'avril',
|
||||
4: 'mai',
|
||||
5: 'juin',
|
||||
6: 'juillet',
|
||||
7: 'aout',
|
||||
8: 'septembre',
|
||||
9: 'octobre',
|
||||
10: 'novembre',
|
||||
11: 'decembre',
|
||||
};
|
||||
const transforms: Record<string, (date: Date) => string> = {
|
||||
"yyyy": (date: Date) => date.getUTCFullYear().toString(),
|
||||
"MMMM": (date: Date) => months[date.getUTCMonth() as keyof typeof months],
|
||||
"MM": (date: Date) => padRight((date.getUTCMonth() + 1).toString(), '0', 2),
|
||||
"dd": (date: Date) => padRight(date.getUTCDate().toString(), '0', 2),
|
||||
"mm": (date: Date) => padRight(date.getUTCMinutes().toString(), '0', 2),
|
||||
"HH": (date: Date) => padRight(date.getUTCHours().toString(), '0', 2),
|
||||
"ss": (date: Date) => padRight(date.getUTCSeconds().toString(), '0', 2),
|
||||
};
|
||||
const keys = Object.keys(transforms);
|
||||
|
||||
for(const key of keys)
|
||||
{
|
||||
template = key in transforms ? template.replaceAll(key, () => transforms[key]!(date)) : template;
|
||||
}
|
||||
|
||||
return template;
|
||||
}
|
||||
export function clamp(x: number, min: number, max: number): number
|
||||
{
|
||||
return x > max ? max : x < min ? min : x;
|
||||
}
|
||||
export function lerp(x: number, a: number, b: number): number
|
||||
{
|
||||
return (1-x)*a+x*b;
|
||||
}
|
||||
// The value position is randomized
|
||||
// The metadata separator is randomized from the URLSafeCharacters set
|
||||
// The URI is (| == picked separator) |v_length|first part of the hash + value + second part of the hash|v_pos as hex.
|
||||
export function cryptURI(key: string, value: number): string
|
||||
{
|
||||
const hash = Bun.hash.crc32(key + value.toString()).toString(16);
|
||||
const pos = Math.floor(Math.random() * hash.length);
|
||||
const separator = URLSafeCharacters[URLSafeCharacters.length * Math.random() | 0]!;
|
||||
|
||||
return encodeBase(separator + value.toString().length + separator + hash.substring(0, pos) + value + hash.substring(pos) + separator + pos);
|
||||
}
|
||||
export function decryptURI(uri: string, key: string): number | undefined
|
||||
{
|
||||
const _uri = decodeBase(uri);
|
||||
|
||||
const separator = _uri.charAt(0);
|
||||
const length = parseInt(_uri.substring(1, _uri.indexOf(separator, 1)), 10);
|
||||
const pos = parseInt(_uri.substring(_uri.lastIndexOf(separator) + 1), 16);
|
||||
const _hash = _uri.substring(_uri.lastIndexOf(separator, _uri.length - pos.toString(16).length - 2) + 1, _uri.lastIndexOf(separator));
|
||||
|
||||
const value = _hash.substring(pos, pos + length);
|
||||
const hash = _hash.substring(0, pos) + _hash.substring(pos + length);
|
||||
|
||||
if(Bun.hash.crc32(key + value).toString(16) === hash)
|
||||
return parseInt(value, 10);
|
||||
else
|
||||
return undefined;
|
||||
}
|
||||
|
||||
export class WeakerSet<T extends WeakKey>
|
||||
{
|
||||
private _arr: WeakRef<T>[] = [];
|
||||
private _registry: FinalizationRegistry<any>;
|
||||
constructor()
|
||||
{
|
||||
this._registry = new FinalizationRegistry<any>(this.clean);
|
||||
}
|
||||
add(item: T)
|
||||
{
|
||||
this._arr.push(new WeakRef(item));
|
||||
this._registry.register(item, undefined);
|
||||
}
|
||||
clean()
|
||||
{
|
||||
for(let i = this._arr.length; i >= 0; i--)
|
||||
{
|
||||
if(this._arr[i]?.deref() === undefined)
|
||||
this._arr.splice(i, 1);
|
||||
}
|
||||
}
|
||||
forEach(cb: (value: T) => void)
|
||||
{
|
||||
for(let i = this._arr.length; i >= 0; i--)
|
||||
{
|
||||
const ref = this._arr[i]?.deref();
|
||||
if(ref !== undefined)
|
||||
cb(ref);
|
||||
else
|
||||
this._arr.splice(i, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user