import { Vault } from "obsidian"; import * as path from "path"; import { base32 } from "rfc4648"; import XRegExp from "xregexp"; /** * If any part of the file starts with '.' or '_' then it's a hidden file. * @param item * @param loose * @returns */ export const isHiddenPath = (item: string, loose: boolean = true) => { const k = path.posix.normalize(item); // TODO: only unix path now const k2 = k.split("/"); // TODO: only unix path now // console.log(k2) for (const singlePart of k2) { if (singlePart === "." || singlePart === ".." || singlePart === "") { continue; } if (singlePart[0] === ".") { return true; } if (loose && singlePart[0] === "_") { return true; } } return false; }; /** * Util func for mkdir -p based on the "path" of original file or folder * "a/b/c/" => ["a", "a/b", "a/b/c"] * "a/b/c/d/e.txt" => ["a", "a/b", "a/b/c", "a/b/c/d"] * @param x string * @returns string[] might be empty */ export const getFolderLevels = (x: string) => { const res: string[] = []; if (x === "" || x === "/") { return res; } const y1 = x.split("/"); let i = 0; for (let index = 0; index + 1 < y1.length; index++) { const k = y1.slice(0, index + 1).join("/"); if (k !== "" && k !== "/") { res.push(k); } } return res; }; export const mkdirpInVault = async (thePath: string, vault: Vault) => { // console.log(thePath); const foldersToBuild = getFolderLevels(thePath); // console.log(foldersToBuild); for (const folder of foldersToBuild) { const r = await vault.adapter.exists(folder); // console.log(r); if (!r) { console.log(`mkdir ${folder}`); await vault.adapter.mkdir(folder); } } }; /** * https://stackoverflow.com/questions/8609289 * @param b Buffer * @returns ArrayBuffer */ export const bufferToArrayBuffer = (b: Buffer | Uint8Array) => { return b.buffer.slice(b.byteOffset, b.byteOffset + b.byteLength); }; /** * Simple func. * @param b * @returns */ export const arrayBufferToBuffer = (b: ArrayBuffer) => { return Buffer.from(b); }; export const arrayBufferToBase64 = (b: ArrayBuffer) => { return arrayBufferToBuffer(b).toString("base64"); }; export const arrayBufferToHex = (b: ArrayBuffer) => { return arrayBufferToBuffer(b).toString("hex"); }; export const base64ToArrayBuffer = (b64text: string) => { return bufferToArrayBuffer(Buffer.from(b64text, "base64")); }; /** * https://stackoverflow.com/questions/43131242 * @param hex * @returns */ export const hexStringToTypedArray = (hex: string) => { return new Uint8Array( hex.match(/[\da-f]{2}/gi).map(function (h) { return parseInt(h, 16); }) ); }; export const base64ToBase32 = (a: string) => { return base32.stringify(Buffer.from(a, "base64")); }; /** * iOS Safari could decrypt string with invalid password! * So we need an extra way to test the decrypted result. * One simple way is testing the result are "valid", printable chars or not. * * https://stackoverflow.com/questions/6198986 * https://www.regular-expressions.info/unicode.html * Manual test shows that emojis like '🍎' match '\\p{Cs}', * so we need to write the regrex in a form that \p{C} minus \p{Cs} * @param a */ export const isVaildText = (a: string) => { // If the regex matches, the string is invalid. return !XRegExp("\\p{Cc}|\\p{Cf}|\\p{Co}|\\p{Cn}|\\p{Zl}|\\p{Zp}", "A").test( a ); }; /** * If input is already a folder, returns it as is; * And if input is a file, returns its direname. * @param a * @returns */ export const getPathFolder = (a: string) => { if (a.endsWith("/")) { return a; } const b = path.posix.dirname(a); return b.endsWith("/") ? b : `${b}/`; }; /** * https://stackoverflow.com/questions/54511144 * @param a * @param delimiter * @returns */ export const setToString = (a: Set, delimiter: string = ",") => { return [...a].join(delimiter); }; export const extractSvgSub = (x: string, subEl: string = "rect") => { const parser = new window.DOMParser(); const dom = parser.parseFromString(x, "image/svg+xml"); const svg = dom.querySelector("svg"); svg.setAttribute("viewbox", "0 0 10 10"); return svg.innerHTML; }; /** * https://stackoverflow.com/questions/18230217 * @param min * @param max * @returns */ export const getRandomIntInclusive = (min: number, max: number) => { const randomBuffer = new Uint32Array(1); window.crypto.getRandomValues(randomBuffer); let randomNumber = randomBuffer[0] / (0xffffffff + 1); min = Math.ceil(min); max = Math.floor(max); return Math.floor(randomNumber * (max - min + 1)) + min; }; /** * Random buffer * @param byteLength * @returns */ export const getRandomArrayBuffer = (byteLength: number) => { const k = window.crypto.getRandomValues(new Uint8Array(byteLength)); return bufferToArrayBuffer(k); };