@jackens/nnn
Version:
Jackens’ JavaScript helpers.
389 lines (381 loc) • 15.9 kB
JavaScript
// 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
};