UNPKG

@jackens/nnn

Version:

Jackens’ JavaScript helpers.

389 lines (381 loc) 15.9 kB
// src/nnn/isArray.ts var isArray = Array.isArray; // src/nnn/isNumber.ts var isNumber = (arg) => typeof arg === "number"; // src/nnn/isString.ts var isString = (arg) => typeof arg === "string"; // src/nnn/c.ts var _c = (node, prefix, result, splitter) => { const queue = [[node, prefix]]; while (queue.length > 0) { const [style0, prefix0] = queue.shift(); if (isArray(style0)) { result.push(prefix0, prefix0 !== "" ? "{" : "", style0.join(";"), prefix0 !== "" ? "}" : ""); } else { const todo = []; let attributes = []; let attributesPushed = false; for (const key in style0) { const value = style0[key]; if (isString(value) || isNumber(value)) { if (!attributesPushed) { attributesPushed = true; attributes = []; todo.push([attributes, prefix0]); } const attribute = key.split(splitter)[0].replace(/_/g, "-").replace(/([A-Z])/g, (_, letter) => "-" + letter.toLowerCase()); attributes.push(`${attribute}:${value}`); } else if (value != null) { attributesPushed = false; const prefixN = []; const keyChunks = key.split(","); prefix0.split(",").forEach((prefixChunk) => keyChunks.forEach((keyChunk) => prefixN.push(prefixChunk + keyChunk))); todo.push([value, prefixN.join()]); } } queue.unshift(...todo); } } }; var c = (root, splitter = "$$") => { const chunks = []; for (const key in root) { const value = root[key]; if (value != null) { if (key[0] === "@") { chunks.push(key.split(splitter)[0] + "{"); _c(value, "", chunks, splitter); chunks.push("}"); } else { _c(value, key.split(splitter)[0], chunks, splitter); } } } return chunks.join(""); }; // src/nnn/csvParse.ts var MAIN_PATTERN = /\n|(?<!")("(?:[^"]|"")*")(?!")/g; var csvParse = (csv, separator = ",") => { const linePattern = new RegExp(`${separator}|(?<!")\\s*"((?:[^"]|"")*)"\\s*(?!")`, "g"); return csv.replace(/\r/g, "").replace(/\n+$/, "").replace(MAIN_PATTERN, (_, chunk) => chunk ?? "\r").split("\r").map((line) => line.replace(linePattern, (_, chunk) => chunk == null ? "\r" : chunk.replace(/""/g, '"')).split("\r")); }; // src/nnn/isRecord.ts var isRecord = (arg) => typeof arg === "object" && arg != null && !isArray(arg); // src/nnn/h.ts var _h = (namespaceUri) => { const createElement = namespaceUri == null ? (tag) => document.createElement(tag) : (tag) => document.createElementNS(namespaceUri, tag); const h = (tagOrNode, ...args) => { const node = isString(tagOrNode) ? createElement(tagOrNode) : tagOrNode; args.forEach((arg) => { let child = null; if (arg instanceof Node) { child = arg; } else if (isArray(arg)) { child = h(...arg); } else if (isRecord(arg)) { for (const name in arg) { const value = arg[name]; if (name[0] === "$") { const name1 = name.slice(1); if (isRecord(value)) { node[name1] ??= {}; Object.assign(node[name1], value); } else { node[name1] = value; } } else if (node instanceof Element) { const indexOfColon = name.indexOf(":"); if (indexOfColon >= 0) { const nsKey = name.slice(0, indexOfColon); if (nsKey === "xlink") { const ns = "http://www.w3.org/1999/xlink"; const basename = name.slice(indexOfColon + 1); if (value === true) { node.setAttributeNS(ns, basename, ""); } else if (value === false) { node.removeAttributeNS(ns, basename); } else { node.setAttributeNS(ns, basename, "" + value); } } } else { if (value === true) { node.setAttribute(name, ""); } else if (value === false) { node.removeAttribute(name); } else { node.setAttribute(name, "" + value); } } } } } else if (isString(arg) || isNumber(arg)) { child = document.createTextNode(arg); } if (child != null) { node.appendChild(child); } }); return node; }; return h; }; var h = /* @__PURE__ */ _h(); var s = /* @__PURE__ */ _h("http://www.w3.org/2000/svg"); // src/nnn/fixPlTypography.ts var TAGS_TO_SKIP = ["IFRAME", "NOSCRIPT", "PRE", "SCRIPT", "STYLE", "TEXTAREA"]; var fixPlTypography = (node) => { const queue = [node]; while (queue.length > 0) { const node0 = queue.shift(); if (node0 instanceof Element) { node0.childNodes.forEach((childNode) => { if (childNode instanceof Text) { queue.push(childNode); } else if (childNode instanceof Element && !TAGS_TO_SKIP.includes(childNode.tagName)) { queue.push(childNode); } }); } else if (node0 instanceof Text) { const nodeValue = node0.nodeValue?.trim?.(); if (nodeValue != null) { let previousNode = node0; nodeValue.split(/(\s|\(|„)([aiouwz—]\s)/gi).forEach((chunk, i) => { i %= 3; const currentNode = i === 2 ? h("span", { style: "white-space:nowrap" }, chunk) : i === 1 ? document.createTextNode(chunk) : document.createTextNode(chunk.replace(/(\/(?=[^/\s])|\.(?=[^\s]))/g, "$1​")); if (node0.parentNode != null) { node0.parentNode.insertBefore(currentNode, previousNode.nextSibling); } previousNode = currentNode; }); node0.parentNode?.removeChild(node0); } } } }; // src/nnn/hasOwn.ts var hasOwn = (ref, key) => ref != null && Object.hasOwn(ref, key); // src/nnn/isFiniteNumber.ts var isFiniteNumber = Number.isFinite; // src/nnn/jsOnParse.ts var jsOnParse = (handlers, text) => JSON.parse(text, (key, value) => { if (isRecord(value)) { let isSecondKey = false; for (key in value) { if (isSecondKey) { return value; } isSecondKey = true; } const handler = handlers[key]; const params = value[key]; if (handler instanceof Function && isArray(params)) { return handler(...params); } } return value; }); // src/nnn/monokai.ts var monokai = { ":root$$monokai": { __bg: "#faf4f2", __fg: "#29242a", __comment: "#918c8e", __identifier_1: "#7058be", __identifier_2: "#269d69", __identifier_3: "#1c8ca8", __identifier_4: "#29242a", __keyword_1: "#e14775", __keyword_2: "#7058be", __keyword_3: "#1c8ca8", __number: "#7058be", __operator: "#e14775", __punctuation: "#918c8e", __string: "#cc7a0a" }, pre$$monokai: { backgroundColor: "var(--bg)", color: "var(--fg)", margin: 0, padding: "1em", overflow: "visible", " code": { fontFamily: '"Source Code Pro"', padding: 0 } }, "code>span.$$monokai": { bg: { color: "var(--bg)" }, fg: { color: "var(--fg)" }, comment: { color: "var(--comment)" }, "identifier-1": { color: "var(--identifier-1)" }, "identifier-2": { color: "var(--identifier-2)" }, "identifier-3": { color: "var(--identifier-3)" }, "identifier-4": { color: "var(--identifier-4)" }, "keyword-1": { color: "var(--keyword-1)" }, "keyword-2": { color: "var(--keyword-2)" }, "keyword-3": { color: "var(--keyword-3)" }, number: { color: "var(--number)" }, operator: { color: "var(--operator)" }, punctuation: { color: "var(--punctuation)" }, string: { color: "var(--string)" } }, "@media only screen and (prefers-color-scheme: dark)$$monokai": { ":root": { __bg: "#2d2a2e", __fg: "#fcfcfa", __comment: "#727072", __identifier_1: "#ae81ff", __identifier_2: "#a9dc76", __identifier_3: "#66d9ef", __identifier_4: "#fcfcfa", __keyword_1: "#ff6188", __keyword_2: "#ae81ff", __keyword_3: "#66d9ef", __number: "#ae81ff", __operator: "#ff6188", __punctuation: "#727072", __string: "#ffd866" } } }; // src/nnn/newTokenizer.ts var newTokenizer = (decorator, ...specs) => (code) => { const result = []; while (code.length > 0) { let bestMetadata; let bestIndex = Infinity; let bestChunk = ""; for (const [metadata, pattern] of specs) { let index = -1; let chunk = ""; if (isString(pattern) && pattern.length > 0) { index = code.indexOf(pattern); chunk = code.slice(index, index + pattern.length); } if (pattern instanceof RegExp) { const match = code.match(pattern); index = match?.index ?? -1; chunk = match?.[0] ?? ""; } if (index >= 0 && chunk.length > 0 && (index < bestIndex || index === bestIndex && chunk.length > bestChunk.length)) { bestMetadata = metadata; bestIndex = index; bestChunk = chunk; } } if (bestMetadata != null) { if (bestIndex > 0) { result.push(decorator(code.slice(0, bestIndex))); } result.push(decorator(bestChunk, bestMetadata)); code = code.slice(bestIndex + bestChunk.length); } else { result.push(decorator(code)); break; } } return result; }; // src/nnn/nanolightTs.ts var COMMENT = "comment"; var IDENTIFIER_1 = "identifier-1"; var IDENTIFIER_2 = "identifier-2"; var IDENTIFIER_3 = "identifier-3"; var IDENTIFIER_4 = "identifier-4"; var KEYWORD_1 = "keyword-1"; var KEYWORD_2 = "keyword-2"; var KEYWORD_3 = "keyword-3"; var NUMBER = "number"; var OPERATOR = "operator"; var PUNCTUATION = "punctuation"; var STRING = "string"; var nanolightTs = /* @__PURE__ */ newTokenizer((chunk, name) => name != null ? ["span", { class: name }, chunk] : chunk, [COMMENT, /\/\*.*?\*\//s], [COMMENT, /(?<!\\)\/\/.*?(?=\n)/], [STRING, /".*?"/], [STRING, /'.*?'/], [STRING, /`.*?`/s], [STRING, /\/[^\s]*[^\\]\/[dgimsuvy]*/], [NUMBER, /0b[01_]+/], [NUMBER, /0o[01234567_]+/], [NUMBER, /0x[\dabcdef_]+/], [NUMBER, /\d[\d_]*(\.[\d_]+)?(e[+-]?[\d_]+)?/], [OPERATOR, "!"], [OPERATOR, "!="], [OPERATOR, "!=="], [OPERATOR, "%"], [OPERATOR, "%="], [OPERATOR, "&&"], [OPERATOR, "&&="], [OPERATOR, "&"], [OPERATOR, "&="], [OPERATOR, "*"], [OPERATOR, "**"], [OPERATOR, "**="], [OPERATOR, "*="], [OPERATOR, "+"], [OPERATOR, "++"], [OPERATOR, "+="], [OPERATOR, "-"], [OPERATOR, "--"], [OPERATOR, "-="], [OPERATOR, "..."], [OPERATOR, "/"], [OPERATOR, "/="], [OPERATOR, ":"], [OPERATOR, "<"], [OPERATOR, "<<"], [OPERATOR, "<<="], [OPERATOR, "<="], [OPERATOR, "="], [OPERATOR, "=="], [OPERATOR, "==="], [OPERATOR, "=>"], [OPERATOR, ">"], [OPERATOR, ">="], [OPERATOR, ">>"], [OPERATOR, ">>="], [OPERATOR, ">>>"], [OPERATOR, ">>>="], [OPERATOR, "?"], [OPERATOR, "?"], [OPERATOR, "??"], [OPERATOR, "??="], [OPERATOR, "^"], [OPERATOR, "^="], [OPERATOR, "|"], [OPERATOR, "|="], [OPERATOR, "||"], [OPERATOR, "||="], [OPERATOR, "~"], [OPERATOR, "~="], [OPERATOR, /(?<=\s):/], [PUNCTUATION, "("], [PUNCTUATION, ")"], [PUNCTUATION, ","], [PUNCTUATION, "."], [PUNCTUATION, ":"], [PUNCTUATION, ";"], [PUNCTUATION, "?."], [PUNCTUATION, "["], [PUNCTUATION, "]"], [PUNCTUATION, "{"], [PUNCTUATION, "}"], [KEYWORD_1, "as"], [KEYWORD_1, "async"], [KEYWORD_1, "await"], [KEYWORD_1, "break"], [KEYWORD_1, "case"], [KEYWORD_1, "catch"], [KEYWORD_1, "class"], [KEYWORD_1, "const"], [KEYWORD_1, "continue"], [KEYWORD_1, "debugger"], [KEYWORD_1, "default"], [KEYWORD_1, "delete"], [KEYWORD_1, "do"], [KEYWORD_1, "else"], [KEYWORD_1, "export"], [KEYWORD_1, "extends"], [KEYWORD_1, "finally"], [KEYWORD_1, "for"], [KEYWORD_1, "from"], [KEYWORD_1, "function"], [KEYWORD_1, "function*"], [KEYWORD_1, "goto"], [KEYWORD_1, "if"], [KEYWORD_1, "import"], [KEYWORD_1, "in"], [KEYWORD_1, "instanceof"], [KEYWORD_1, "is"], [KEYWORD_1, "keyof"], [KEYWORD_1, "let"], [KEYWORD_1, "new"], [KEYWORD_1, "of"], [KEYWORD_1, "package"], [KEYWORD_1, "return"], [KEYWORD_1, "super"], [KEYWORD_1, "switch"], [KEYWORD_1, "this"], [KEYWORD_1, "throw"], [KEYWORD_1, "try"], [KEYWORD_1, "type"], [KEYWORD_1, "typeof"], [KEYWORD_1, "var"], [KEYWORD_1, "void"], [KEYWORD_1, "while"], [KEYWORD_1, "with"], [KEYWORD_1, "yield"], [KEYWORD_1, "yield*"], [KEYWORD_2, "false"], [KEYWORD_2, "Infinity"], [KEYWORD_2, "NaN"], [KEYWORD_2, "null"], [KEYWORD_2, "true"], [KEYWORD_2, "undefined"], [KEYWORD_3, "any"], [KEYWORD_3, "bigint"], [KEYWORD_3, "boolean"], [KEYWORD_3, "eval"], [KEYWORD_3, "number"], [KEYWORD_3, "string"], [KEYWORD_3, "symbol"], [KEYWORD_3, "unknown"], [IDENTIFIER_1, /[\p{Lu}_$][\p{Lu}\d_$]*/u], [IDENTIFIER_2, /[\p{L}_$][\p{L}\d_$]*(?=[(`])/u], [IDENTIFIER_3, /\p{Lu}[\p{L}\d_$]*/u], [IDENTIFIER_4, /[\p{L}_$][\p{L}\d_$]*/u]); // src/nnn/newEscape.ts var newEscape = (escapeFn) => (template, ...values) => String.raw(template, ...values.map(escapeFn)); // src/nnn/newNounForm.ts var PLURAL_RULES = {}; var newNounForm = (locale, forms) => (value) => forms[(PLURAL_RULES[locale] ??= new Intl.PluralRules(locale)).select(value)] ?? forms.other ?? ""; // src/nnn/omit.ts var omit = (ref, keys) => Object.fromEntries(Object.entries(ref).filter(([key]) => !keys.includes(key))); // src/nnn/pick.ts var pick = (ref, keys) => Object.fromEntries(Object.entries(ref).filter(([key]) => keys.includes(key))); // src/nnn/vivify.ts var ARRAY_INDEX_REGEXP = /^(0|[1-9]\d*)$/; var isObject = (ref) => typeof ref === "object"; var getTarget = (parent, parentKey, key) => parent[parentKey] ??= isString(key) && ARRAY_INDEX_REGEXP.test(key) ? [] : {}; var _vivify = (parent, parentKey) => new Proxy(parent, { get(_, key) { const target = getTarget(parent, parentKey, key); const value = target[key]; return isString(key) && isObject(target) && (value == null || isObject(value)) ? _vivify(target, key) : value; }, set(_, key, value) { const target = getTarget(parent, parentKey, key); target[key] = value; return true; }, deleteProperty(_, key) { const target = getTarget(parent, parentKey, key); return delete target[key]; } }); var vivify = (ref) => _vivify({ _: ref }, "_"); // src/nnn/rwd.ts var rwd = (root, selector, cellWidthPx, cellHeightPx, ...specs) => { const main = vivify(root)[selector]; main.boxSizing = "border-box"; main.display = "block"; main.float = "left"; main.width = "100%"; main.height = `${cellHeightPx}px`; specs.sort(([a], [b]) => a - b); for (let [maxWidth, width, height] of specs) { const node = maxWidth === 1 ? main : vivify(root)[`@media(min-width:${cellWidthPx * maxWidth}px)`][selector]; width ??= 1; height ??= 1; let gcd = 100 * width; let tmp = maxWidth; while (tmp > 0) { [gcd, tmp] = [tmp, gcd % tmp]; } const widthOverGcd = 100 * width / gcd; node.width = maxWidth === gcd ? `${widthOverGcd}%` : `calc(${widthOverGcd}% / ${maxWidth / gcd})`; node.height = `${cellHeightPx * height}px`; } }; // src/nnn/svgUse.ts var svgUse = (id, ...args) => s("svg", ["use", { "xlink:href": "#" + id }], ...args); // src/nnn/uuidV1.ts var ZEROS = /* @__PURE__ */ "0".repeat(16); var counter = 0; var uuidV1 = (date = new Date, node = Math.random().toString(16).slice(2)) => { const time = ZEROS + (1e4 * (+date + 12219292800000)).toString(16); counter = counter + 1 & 16383; return time.slice(-8).concat("-", time.slice(-12, -8), -1, time.slice(-15, -12), "-", (8 | counter >> 12).toString(16), (ZEROS + (counter & 4095).toString(16)).slice(-3), "-", (ZEROS + node).slice(-12)); }; export { vivify, uuidV1, svgUse, s, rwd, pick, omit, newTokenizer, newNounForm, newEscape, nanolightTs, monokai, jsOnParse, isString, isRecord, isNumber, isFiniteNumber, isArray, hasOwn, h, fixPlTypography, csvParse, c };