@jackens/nnn 2026.9.9 → 2026.9.29

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (5) hide show
  1. package/README.md +1229 -0
  2. package/nnn.d.ts +180 -204
  3. package/nnn.js +84 -95
  4. package/package.json +3 -14
  5. package/readme.md +0 -1370
package/nnn.js CHANGED
@@ -50,51 +50,78 @@ var _c = (node, splitter = DEFAULT_SPLITTER, prefix = "", flatten = false) => {
50
50
  return out.join(flatten ? ";" : "");
51
51
  };
52
52
  var c = (node, splitter = DEFAULT_SPLITTER) => _c(node, splitter);
53
- // src/nnn/createEscape.ts
54
- var createEscape = (escapeFn) => (template, ...values) => String.raw(template, ...values.map(escapeFn));
55
- // src/nnn/createTokenizer.ts
56
- var createTokenizer = (decorator, ...specs) => (code) => {
57
- const result = [];
58
- while (code.length > 0) {
59
- let bestMetadata;
60
- let bestIndex = Infinity;
61
- let bestChunk = "";
62
- for (const [metadata, pattern] of specs) {
63
- let index = -1;
64
- let chunk = "";
65
- if (typeof pattern === "string" && pattern.length > 0) {
66
- index = code.indexOf(pattern);
67
- chunk = code.slice(index, index + pattern.length);
68
- }
69
- if (pattern instanceof RegExp) {
70
- const match = code.match(pattern);
71
- index = match?.index ?? -1;
72
- chunk = match?.[0] ?? "";
53
+ // src/nnn/createLexer.ts
54
+ var ROOT = "root";
55
+ var createLexer = (decorator, ...specs) => {
56
+ const compiled = specs.map(([metadata, pattern, options]) => ({
57
+ metadata,
58
+ pattern: pattern instanceof RegExp ? new RegExp(pattern.source, pattern.sticky ? pattern.flags : pattern.flags.replace("g", "") + "g") : pattern,
59
+ states: [options?.in ?? ROOT].flat(),
60
+ pop: options?.pop ?? false,
61
+ push: options?.push
62
+ }));
63
+ const find = (pattern, code, position) => {
64
+ if (typeof pattern === "string") {
65
+ const index = pattern.length > 0 ? code.indexOf(pattern, position) : -1;
66
+ return [index, pattern];
67
+ }
68
+ pattern.lastIndex = position;
69
+ for (let match = pattern.exec(code);match != null; match = pattern.exec(code)) {
70
+ if (match[0].length > 0) {
71
+ return [match.index, match[0]];
73
72
  }
74
- if (index >= 0 && chunk.length > 0 && (index < bestIndex || index === bestIndex && chunk.length > bestChunk.length)) {
75
- bestMetadata = metadata;
76
- bestIndex = index;
77
- bestChunk = chunk;
73
+ if (pattern.sticky) {
74
+ break;
78
75
  }
76
+ pattern.lastIndex = match.index + 1;
79
77
  }
80
- if (bestMetadata != null) {
81
- if (bestIndex > 0) {
82
- result.push(decorator(code.slice(0, bestIndex)));
78
+ return [-1, ""];
79
+ };
80
+ return (code) => {
81
+ const result = [];
82
+ const stack = [ROOT];
83
+ const cache = compiled.map(() => ({ from: -1, index: -1, chunk: "" }));
84
+ let position = 0;
85
+ while (position < code.length) {
86
+ const state = stack.at(-1);
87
+ let best = -1;
88
+ let bestIndex = Infinity;
89
+ let bestChunk = "";
90
+ compiled.forEach(({ pattern, states }, i) => {
91
+ if (!states.includes(state)) {
92
+ return;
93
+ }
94
+ const cached = cache[i];
95
+ const isValid = cached.from >= 0 && (pattern instanceof RegExp && pattern.sticky ? cached.from === position : cached.from <= position && (cached.index < 0 || cached.index >= position));
96
+ if (!isValid) {
97
+ [cached.index, cached.chunk] = find(pattern, code, position);
98
+ cached.from = position;
99
+ }
100
+ if (cached.index >= 0 && (cached.index < bestIndex || cached.index === bestIndex && cached.chunk.length > bestChunk.length)) {
101
+ best = i;
102
+ bestIndex = cached.index;
103
+ bestChunk = cached.chunk;
104
+ }
105
+ });
106
+ if (best < 0) {
107
+ result.push(decorator(code.slice(position)));
108
+ break;
109
+ }
110
+ const { metadata, pop, push } = compiled[best];
111
+ if (bestIndex > position) {
112
+ result.push(decorator(code.slice(position, bestIndex)));
113
+ }
114
+ result.push(decorator(bestChunk, metadata));
115
+ position = bestIndex + bestChunk.length;
116
+ if (pop && stack.length > 1) {
117
+ stack.pop();
118
+ }
119
+ if (push != null) {
120
+ stack.push(push);
83
121
  }
84
- result.push(decorator(bestChunk, bestMetadata));
85
- code = code.slice(bestIndex + bestChunk.length);
86
- } else {
87
- result.push(decorator(code));
88
- break;
89
122
  }
90
- }
91
- return result;
92
- };
93
- // src/nnn/csvParse.ts
94
- var MAIN_PATTERN = /\n|(?<!")("(?:[^"]|"")*")(?!")/g;
95
- var csvParse = (csv, separator = ",") => {
96
- const linePattern = new RegExp(`${separator}|(?<!")\\s*"((?:[^"]|"")*)"\\s*(?!")`, "g");
97
- 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"));
123
+ return result;
124
+ };
98
125
  };
99
126
  // src/nnn/h.ts
100
127
  var XLINK_NS = "http://www.w3.org/1999/xlink";
@@ -153,45 +180,6 @@ var _h = (createElement, tagOrNode, ...args) => {
153
180
  var h = _h.bind(null, (tag) => document.createElement(tag));
154
181
  var s = _h.bind(null, (tag) => document.createElementNS("http://www.w3.org/2000/svg", tag));
155
182
  var svgUse = (id, ...args) => s("svg", ["use", { "xlink:href": "#" + id }], ...args);
156
-
157
- // src/nnn/fixPlTypography.ts
158
- var TAGS_TO_SKIP = [
159
- "IFRAME",
160
- "NOSCRIPT",
161
- "PRE",
162
- "SCRIPT",
163
- "STYLE",
164
- "TEXTAREA"
165
- ];
166
- var fixPlTypography = (node) => {
167
- const queue = [node];
168
- while (queue.length > 0) {
169
- const node0 = queue.shift();
170
- if (node0 instanceof Element) {
171
- node0.childNodes.forEach((childNode) => {
172
- if (childNode instanceof Text) {
173
- queue.push(childNode);
174
- } else if (childNode instanceof Element && !TAGS_TO_SKIP.includes(childNode.tagName)) {
175
- queue.push(childNode);
176
- }
177
- });
178
- } else if (node0 instanceof Text) {
179
- const nodeValue = node0.nodeValue?.trim?.();
180
- if (nodeValue != null) {
181
- let previousNode = node0;
182
- nodeValue.split(/(\s|\(|„)([aiouwz—]\s)/gi).forEach((chunk, i) => {
183
- i %= 3;
184
- const currentNode = i === 2 ? h("span", { style: "white-space:nowrap" }, chunk) : document.createTextNode(i === 1 ? chunk : chunk.replace(/(\/(?=[^/\s])|\.(?=[^\s]))/g, "$1​"));
185
- if (node0.parentNode != null) {
186
- node0.parentNode.insertBefore(currentNode, previousNode.nextSibling);
187
- }
188
- previousNode = currentNode;
189
- });
190
- node0.parentNode?.removeChild(node0);
191
- }
192
- }
193
- }
194
- };
195
183
  // src/nnn/monokai.ts
196
184
  var monokai = {
197
185
  ":root$$monokai": {
@@ -270,6 +258,14 @@ var monokai = {
270
258
  string: "#ffd866"
271
259
  }
272
260
  }
261
+ },
262
+ "@media print$$monokai": {
263
+ pre: {
264
+ "background-color": "white"
265
+ },
266
+ ":root": {
267
+ "--bg": "white"
268
+ }
273
269
  }
274
270
  };
275
271
  // src/nnn/nanolightTs.ts
@@ -285,11 +281,16 @@ var NUMBER = "number";
285
281
  var OPERATOR = "operator";
286
282
  var PUNCTUATION = "punctuation";
287
283
  var STRING = "string";
288
- var nanolightTs = /* @__PURE__ */ createTokenizer((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, "}"], [KEYWORD1, "as"], [KEYWORD1, "async"], [KEYWORD1, "await"], [KEYWORD1, "break"], [KEYWORD1, "case"], [KEYWORD1, "catch"], [KEYWORD1, "class"], [KEYWORD1, "const"], [KEYWORD1, "continue"], [KEYWORD1, "debugger"], [KEYWORD1, "default"], [KEYWORD1, "delete"], [KEYWORD1, "do"], [KEYWORD1, "else"], [KEYWORD1, "export"], [KEYWORD1, "extends"], [KEYWORD1, "finally"], [KEYWORD1, "for"], [KEYWORD1, "from"], [KEYWORD1, "function"], [KEYWORD1, "function*"], [KEYWORD1, "goto"], [KEYWORD1, "if"], [KEYWORD1, "import"], [KEYWORD1, "in"], [KEYWORD1, "instanceof"], [KEYWORD1, "is"], [KEYWORD1, "keyof"], [KEYWORD1, "let"], [KEYWORD1, "new"], [KEYWORD1, "of"], [KEYWORD1, "package"], [KEYWORD1, "return"], [KEYWORD1, "super"], [KEYWORD1, "switch"], [KEYWORD1, "this"], [KEYWORD1, "throw"], [KEYWORD1, "try"], [KEYWORD1, "type"], [KEYWORD1, "typeof"], [KEYWORD1, "var"], [KEYWORD1, "void"], [KEYWORD1, "while"], [KEYWORD1, "with"], [KEYWORD1, "yield"], [KEYWORD1, "yield*"], [KEYWORD2, "false"], [KEYWORD2, "Infinity"], [KEYWORD2, "NaN"], [KEYWORD2, "null"], [KEYWORD2, "true"], [KEYWORD2, "undefined"], [KEYWORD3, "any"], [KEYWORD3, "bigint"], [KEYWORD3, "boolean"], [KEYWORD3, "eval"], [KEYWORD3, "number"], [KEYWORD3, "string"], [KEYWORD3, "symbol"], [KEYWORD3, "unknown"], [IDENTIFIER1, /[\p{Lu}_$][\p{Lu}\d_$]*/u], [IDENTIFIER2, /[\p{L}_$][\p{L}\d_$]*(?=[(`])/u], [IDENTIFIER3, /\p{Lu}[\p{L}\d_$]*/u], [IDENTIFIER4, /[\p{L}_$][\p{L}\d_$]*/u]);
284
+ var ROOT2 = "root";
285
+ var TEMPLATE = "template";
286
+ var nanolightTs = /* @__PURE__ */ createLexer((chunk, name) => name != null ? ["span", { class: name }, chunk] : chunk, [COMMENT, /^#!.*/], [COMMENT, /\/\*[\s\S]*?(?:\*\/|$)/], [COMMENT, /\/\/.*/], [STRING, /"(?:[^"\\\n]|\\[\s\S])*"?/], [STRING, /'(?:[^'\\\n]|\\[\s\S])*'?/], [STRING, /`(?:[^`\\$]|\\[\s\S]|\$(?!\{))*(?:`|$)/], [STRING, /`(?:[^`\\$]|\\[\s\S]|\$(?!\{))*(?=\$\{)/, { push: TEMPLATE }], [STRING, /(?:[^`\\$]|\\[\s\S]|\$(?!\{))*(?:`|$)/y, { in: TEMPLATE, pop: true }], [STRING, /(?:[^`\\$]|\\[\s\S]|\$(?!\{))+(?=\$\{)/y, { in: TEMPLATE }], [PUNCTUATION, "${", { in: TEMPLATE, push: ROOT2 }], [
287
+ STRING,
288
+ /(?<=(?:^|[!%&(*,:;<=>?[^{|}~]|(?<!\+)\+|(?<!-)-|(?<!\.)\b(?:await|case|delete|do|else|in|instanceof|new|of|return|throw|typeof|void|yield))\s*)\/(?![*/])(?:[^\\/[\n]|\\.|\[(?:[^\\\]\n]|\\.)*\]?)+\/[dgimsuvy]*/
289
+ ], [NUMBER, /0b[01_]+n?/i], [NUMBER, /0o[0-7_]+n?/i], [NUMBER, /0x[\da-f_]+n?/i], [NUMBER, /(?:\d[\d_]*(?:\.[\d_]+)?|\.\d[\d_]*)(?:e[+-]?\d[\d_]*)?n?/i], [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, /\?\.(?!\d)/], [PUNCTUATION, "["], [PUNCTUATION, "]"], [PUNCTUATION, "{", { push: ROOT2 }], [PUNCTUATION, "}", { pop: true }], [IDENTIFIER2, /(?<=(?<!\.)\.)\p{Ll}[\p{L}\d_$]*(?=[(`])/u], [IDENTIFIER4, /(?<=(?<!\.)\.)\p{Ll}[\p{L}\d_$]*/u], [KEYWORD1, "as"], [KEYWORD1, "async"], [KEYWORD1, "await"], [KEYWORD1, "break"], [KEYWORD1, "case"], [KEYWORD1, "catch"], [KEYWORD1, "class"], [KEYWORD1, "const"], [KEYWORD1, "continue"], [KEYWORD1, "debugger"], [KEYWORD1, "default"], [KEYWORD1, "delete"], [KEYWORD1, "do"], [KEYWORD1, "else"], [KEYWORD1, "export"], [KEYWORD1, "extends"], [KEYWORD1, "finally"], [KEYWORD1, "for"], [KEYWORD1, "from"], [KEYWORD1, "function"], [KEYWORD1, "function*"], [KEYWORD1, "goto"], [KEYWORD1, "if"], [KEYWORD1, "import"], [KEYWORD1, "in"], [KEYWORD1, "instanceof"], [KEYWORD1, "is"], [KEYWORD1, "keyof"], [KEYWORD1, "let"], [KEYWORD1, "new"], [KEYWORD1, "of"], [KEYWORD1, "package"], [KEYWORD1, "return"], [KEYWORD1, "super"], [KEYWORD1, "switch"], [KEYWORD1, "this"], [KEYWORD1, "throw"], [KEYWORD1, "try"], [KEYWORD1, "type"], [KEYWORD1, "typeof"], [KEYWORD1, "var"], [KEYWORD1, "void"], [KEYWORD1, "while"], [KEYWORD1, "with"], [KEYWORD1, "yield"], [KEYWORD1, "yield*"], [KEYWORD2, "false"], [KEYWORD2, "Infinity"], [KEYWORD2, "NaN"], [KEYWORD2, "null"], [KEYWORD2, "true"], [KEYWORD2, "undefined"], [KEYWORD3, "any"], [KEYWORD3, "bigint"], [KEYWORD3, "boolean"], [KEYWORD3, "eval"], [KEYWORD3, "number"], [KEYWORD3, "string"], [KEYWORD3, "symbol"], [KEYWORD3, "unknown"], [IDENTIFIER2, /@[\p{L}_$][\p{L}\d_$]*/u], [IDENTIFIER1, /#?[\p{Lu}_$][\p{Lu}\d_$]*/u], [IDENTIFIER2, /#?[\p{L}_$][\p{L}\d_$]*(?=[(`])/u], [IDENTIFIER3, /#?\p{Lu}[\p{L}\d_$]*/u], [IDENTIFIER4, /#?[\p{L}_$][\p{L}\d_$]*/u]);
289
290
  // src/nnn/rwd.ts
290
291
  var rwd = (root, selector, cellWidthPx, cellHeightPx, ...specs) => {
291
292
  const main = root[selector] ??= {};
292
- main.boxSizing = "border-box";
293
+ main["box-sizing"] = "border-box";
293
294
  main.display = "block";
294
295
  main.float = "left";
295
296
  main.width = "100%";
@@ -310,25 +311,13 @@ var rwd = (root, selector, cellWidthPx, cellHeightPx, ...specs) => {
310
311
  node.height = `${cellHeightPx * height}px`;
311
312
  }
312
313
  };
313
- // src/nnn/uuidV1.ts
314
- var ZEROS = /* @__PURE__ */ "0".repeat(16);
315
- var counter = 0;
316
- var uuidV1 = (date = new Date, node = Math.random().toString(16).slice(2)) => {
317
- const time = ZEROS + (1e4 * (+date + 12219292800000)).toString(16);
318
- counter = counter + 1 & 16383;
319
- 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));
320
- };
321
314
  export {
322
315
  c,
323
- createEscape,
324
- createTokenizer,
325
- csvParse,
326
- fixPlTypography,
316
+ createLexer,
327
317
  h,
328
318
  monokai,
329
319
  nanolightTs,
330
320
  rwd,
331
321
  s,
332
- svgUse,
333
- uuidV1
322
+ svgUse
334
323
  };
package/package.json CHANGED
@@ -1,31 +1,20 @@
1
1
  {
2
2
  "name": "@jackens/nnn",
3
- "version": "2026.9.9",
3
+ "version": "2026.9.29",
4
4
  "description": "Jackens’ JavaScript helpers.",
5
5
  "keywords": [
6
6
  "CSS-in-JS",
7
- "CSV parse",
8
- "DOM",
9
7
  "HyperScript",
10
8
  "JS-to-CSS",
11
9
  "Monokai",
12
10
  "RWD",
13
11
  "Responsive Web Design",
14
12
  "SVG",
15
- "autovivify",
16
- "c",
17
- "escape",
18
- "h",
19
13
  "highlight",
14
+ "lexer",
20
15
  "nanolight",
21
16
  "nnn",
22
- "tokenize",
23
- "tokenizer",
24
- "typography",
25
- "uuid",
26
- "uuid1",
27
- "uuidV1",
28
- "vivify"
17
+ "tokenize"
29
18
  ],
30
19
  "license": "MIT",
31
20
  "author": "Jackens",