@jackens/nnn 2025.12.23 → 2026.2.6
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.
- package/nnn.d.ts +60 -54
- package/nnn.js +75 -65
- package/package.json +4 -2
- package/readme.md +120 -86
package/nnn.d.ts
CHANGED
|
@@ -126,7 +126,7 @@ export declare const new_escape: (escape_map: EscapeMap) => (template: TemplateS
|
|
|
126
126
|
* The root DOM node to process. All descendant text nodes are corrected recursively,
|
|
127
127
|
* except those inside `IFRAME`, `NOSCRIPT`, `PRE`, `SCRIPT`, `STYLE`, or `TEXTAREA` elements.
|
|
128
128
|
*/
|
|
129
|
-
export declare const
|
|
129
|
+
export declare const fix_pl_typography: (node: Node) => void;
|
|
130
130
|
/**
|
|
131
131
|
* Single argument type for the {@link h} and {@link s} helpers.
|
|
132
132
|
*/
|
|
@@ -307,55 +307,32 @@ export declare const is_string: (arg: unknown) => arg is string;
|
|
|
307
307
|
*/
|
|
308
308
|
export declare const js_on_parse: (handlers: Record<PropertyKey, Function>, text: string) => any;
|
|
309
309
|
/**
|
|
310
|
-
*
|
|
311
|
-
*
|
|
312
|
-
* Defines CSS custom properties for eight colors (`--black`, `--blue`, `--green`, `--grey`,
|
|
313
|
-
* `--purple`, `--red`, `--white`, `--yellow`) with both light and dark mode variants.
|
|
314
|
-
*
|
|
315
|
-
* @remarks
|
|
316
|
-
*
|
|
317
|
-
* - In light mode, `--black` is a light background and `--white` is dark text.
|
|
318
|
-
* - In dark mode (via `prefers-color-scheme: dark`), the palette inverts to a dark background with light text.
|
|
319
|
-
* - Includes base styles for `body`, `pre` and `code>span.*` (syntax highlighting).
|
|
320
|
-
*/
|
|
321
|
-
export declare const monokai: CRoot;
|
|
322
|
-
/**
|
|
323
|
-
* A TypeScript/JavaScript syntax highlighting tokenizer built using {@link new_tokenizer}.
|
|
324
|
-
*
|
|
325
|
-
* @param code
|
|
326
|
-
*
|
|
327
|
-
* The source code string to tokenize.
|
|
328
|
-
*
|
|
329
|
-
* @returns
|
|
330
|
-
*
|
|
331
|
-
* An array of {@link HArgs1} elements suitable for rendering with {@link h}.
|
|
332
|
-
*/
|
|
333
|
-
export declare const nanolight_ts: (code: string) => HArgs1[];
|
|
334
|
-
/**
|
|
335
|
-
* Creates a function that returns the appropriate Polish noun form based on a numeric value.
|
|
336
|
-
*
|
|
337
|
-
* Polish has three plural forms depending on the number:
|
|
338
|
-
* - Singular: used for exactly 1.
|
|
339
|
-
* - “Plural 2-4”: used for 2, 3, 4, 22, 23, 24, etc. (but not 12, 13, 14).
|
|
340
|
-
* - “Plural 5+”: used for 0, 5–21, 25–31, etc.
|
|
310
|
+
* Creates a function that returns the appropriate noun form based on a numeric value using `Intl.PluralRules`.
|
|
341
311
|
*
|
|
342
|
-
*
|
|
312
|
+
* Different languages have different plural rules. The `Intl.PluralRules` API provides
|
|
313
|
+
* locale-aware plural category selection. Possible categories are:
|
|
343
314
|
*
|
|
344
|
-
*
|
|
315
|
+
* - `zero` - for zero items (used in some languages like Arabic, Latvian)
|
|
316
|
+
* - `one` - for singular (e.g., 1 item)
|
|
317
|
+
* - `two` - for dual (used in some languages like Arabic, Hebrew)
|
|
318
|
+
* - `few` - for small plurals (e.g., 2-4 in Polish)
|
|
319
|
+
* - `many` - for larger plurals (e.g., 5-21 in Polish)
|
|
320
|
+
* - `other` - fallback category (used by all languages)
|
|
345
321
|
*
|
|
346
|
-
* @param
|
|
322
|
+
* @param locale
|
|
347
323
|
*
|
|
348
|
-
*
|
|
324
|
+
* A BCP 47 language tag (e.g., "pl", "en").
|
|
349
325
|
*
|
|
350
|
-
* @param
|
|
326
|
+
* @param forms
|
|
351
327
|
*
|
|
352
|
-
*
|
|
328
|
+
* An object mapping plural categories to noun forms. Not all categories need to be provided;
|
|
329
|
+
* if a category is missing, the function falls back to `other`, then to an empty string.
|
|
353
330
|
*
|
|
354
331
|
* @returns
|
|
355
332
|
*
|
|
356
333
|
* A function that takes a numeric value and returns the appropriate noun form.
|
|
357
334
|
*/
|
|
358
|
-
export declare const new_noun_form: (
|
|
335
|
+
export declare const new_noun_form: (locale: string, forms: Partial<Record<Intl.LDMLPluralRule, string>>) => (value: number) => string;
|
|
359
336
|
/**
|
|
360
337
|
* Creates a new object containing only the specified keys from the source object.
|
|
361
338
|
*
|
|
@@ -392,21 +369,6 @@ export declare const pick: <T, K extends keyof T>(ref: T, keys: K[]) => Pick<T,
|
|
|
392
369
|
* A new object without the specified keys.
|
|
393
370
|
*/
|
|
394
371
|
export declare const omit: <T, K extends keyof T>(ref: T, keys: unknown[]) => Omit<T, K>;
|
|
395
|
-
/**
|
|
396
|
-
* A Proxy-based helper for auto-vivification of nested object structures.
|
|
397
|
-
*
|
|
398
|
-
* Accessing any property on the returned proxy automatically creates an empty object if the property does not exist,
|
|
399
|
-
* allowing deep assignments without explicit null checks.
|
|
400
|
-
*
|
|
401
|
-
* @param ref
|
|
402
|
-
*
|
|
403
|
-
* The root object to wrap.
|
|
404
|
-
*
|
|
405
|
-
* @returns
|
|
406
|
-
*
|
|
407
|
-
* A proxy that auto-creates nested objects on property access.
|
|
408
|
-
*/
|
|
409
|
-
export declare const pro: (ref: unknown) => any;
|
|
410
372
|
/**
|
|
411
373
|
* A helper for building simple tokenizers (see also {@link nanolight_ts}).
|
|
412
374
|
*
|
|
@@ -433,6 +395,31 @@ export declare const pro: (ref: unknown) => any;
|
|
|
433
395
|
* 3. Among matches of the same position and length, the one defined earlier wins.
|
|
434
396
|
*/
|
|
435
397
|
export declare const new_tokenizer: <M, T>(decorator: (chunk: string, metadata?: M) => T, ...specs: [M, string | RegExp][]) => (code: string) => T[];
|
|
398
|
+
/**
|
|
399
|
+
* A TypeScript/JavaScript syntax highlighting tokenizer built using {@link new_tokenizer}.
|
|
400
|
+
*
|
|
401
|
+
* @param code
|
|
402
|
+
*
|
|
403
|
+
* The source code string to tokenize.
|
|
404
|
+
*
|
|
405
|
+
* @returns
|
|
406
|
+
*
|
|
407
|
+
* An array of {@link HArgs1} elements suitable for rendering with {@link h}.
|
|
408
|
+
*/
|
|
409
|
+
export declare const nanolight_ts: (code: string) => HArgs1[];
|
|
410
|
+
/**
|
|
411
|
+
* A Monokai-inspired color scheme for use with the {@link c} helper and {@link nanolight_ts} tokenizer.
|
|
412
|
+
*
|
|
413
|
+
* Defines CSS custom properties for eight colors (`--black`, `--blue`, `--green`, `--grey`,
|
|
414
|
+
* `--purple`, `--red`, `--white`, `--yellow`) with both light and dark mode variants.
|
|
415
|
+
*
|
|
416
|
+
* @remarks
|
|
417
|
+
*
|
|
418
|
+
* - In light mode, `--black` is a light background and `--white` is dark text.
|
|
419
|
+
* - In dark mode (via `prefers-color-scheme: dark`), the palette inverts to a dark background with light text.
|
|
420
|
+
* - Includes base styles for `body`, `pre` and `code>span.*` (syntax highlighting).
|
|
421
|
+
*/
|
|
422
|
+
export declare const monokai: CRoot;
|
|
436
423
|
/**
|
|
437
424
|
* Generates a UUID v1 (time-based) identifier.
|
|
438
425
|
*
|
|
@@ -450,3 +437,22 @@ export declare const new_tokenizer: <M, T>(decorator: (chunk: string, metadata?:
|
|
|
450
437
|
* A UUID v1 `string` in the standard format `xxxxxxxx-xxxx-1xxx-xxxx-xxxxxxxxxxxx`.
|
|
451
438
|
*/
|
|
452
439
|
export declare const uuid_v1: (date?: Date, node?: string) => string;
|
|
440
|
+
/**
|
|
441
|
+
* A Proxy-based helper for auto-vivification of nested object structures.
|
|
442
|
+
*
|
|
443
|
+
* Accessing any property on the returned proxy automatically creates an empty object
|
|
444
|
+
* (or array for numeric keys) if the property does not exist,
|
|
445
|
+
* allowing deep assignments without explicit null checks.
|
|
446
|
+
*
|
|
447
|
+
* When a numeric key (like `[42]`) is accessed, the parent structure is
|
|
448
|
+
* automatically converted to an array if it isn’t one already.
|
|
449
|
+
*
|
|
450
|
+
* @param ref
|
|
451
|
+
*
|
|
452
|
+
* The root object to wrap.
|
|
453
|
+
*
|
|
454
|
+
* @returns
|
|
455
|
+
*
|
|
456
|
+
* A proxy that auto-creates nested objects/arrays on property access.
|
|
457
|
+
*/
|
|
458
|
+
export declare const vivify: (ref: unknown) => any;
|
package/nnn.js
CHANGED
|
@@ -5,12 +5,26 @@ var is_number = (arg) => typeof arg === "number";
|
|
|
5
5
|
var is_record = (arg) => typeof arg === "object" && arg != null && !is_array(arg);
|
|
6
6
|
var is_string = (arg) => typeof arg === "string";
|
|
7
7
|
|
|
8
|
-
// src/nnn/
|
|
9
|
-
var
|
|
8
|
+
// src/nnn/vivify.ts
|
|
9
|
+
var ARRAY_INDEX_REGEXP = /^(0|[1-9]\d*)$/;
|
|
10
|
+
var should_convert_target_to_array = (target, key, parent) => parent != null && typeof key === "string" && ARRAY_INDEX_REGEXP.test(key) && !is_array(target);
|
|
11
|
+
var _vivify = (ref, parent, parentKey) => new Proxy(ref, {
|
|
10
12
|
get(target, key) {
|
|
11
|
-
|
|
13
|
+
if (should_convert_target_to_array(target, key, parent)) {
|
|
14
|
+
target = parent[parentKey] = [];
|
|
15
|
+
}
|
|
16
|
+
target[key] ??= {};
|
|
17
|
+
return _vivify(target[key], target, key);
|
|
18
|
+
},
|
|
19
|
+
set(target, key, value) {
|
|
20
|
+
if (should_convert_target_to_array(target, key, parent)) {
|
|
21
|
+
target = parent[parentKey] = [];
|
|
22
|
+
}
|
|
23
|
+
target[key] = value;
|
|
24
|
+
return true;
|
|
12
25
|
}
|
|
13
26
|
});
|
|
27
|
+
var vivify = (ref) => _vivify(ref);
|
|
14
28
|
|
|
15
29
|
// src/nnn/c.ts
|
|
16
30
|
var _c = (node, prefix, result, splitter) => {
|
|
@@ -65,7 +79,7 @@ var c = (root, splitter = "$$") => {
|
|
|
65
79
|
return chunks.join("");
|
|
66
80
|
};
|
|
67
81
|
var rwd = (root, selector, cell_width_px, cell_height_px, ...specs) => {
|
|
68
|
-
const main =
|
|
82
|
+
const main = vivify(root)[selector];
|
|
69
83
|
main.boxSizing = "border-box";
|
|
70
84
|
main.display = "block";
|
|
71
85
|
main.float = "left";
|
|
@@ -73,7 +87,7 @@ var rwd = (root, selector, cell_width_px, cell_height_px, ...specs) => {
|
|
|
73
87
|
main.height = `${cell_height_px}px`;
|
|
74
88
|
specs.sort(([a], [b]) => a - b);
|
|
75
89
|
for (let [max_width, width, height] of specs) {
|
|
76
|
-
const node = max_width === 1 ? main :
|
|
90
|
+
const node = max_width === 1 ? main : vivify(root)[`@media(min-width:${cell_width_px * max_width}px)`][selector];
|
|
77
91
|
width ??= 1;
|
|
78
92
|
height ??= 1;
|
|
79
93
|
let gcd = 100 * width;
|
|
@@ -158,9 +172,9 @@ var h = /* @__PURE__ */ _h();
|
|
|
158
172
|
var s = /* @__PURE__ */ _h("http://www.w3.org/2000/svg");
|
|
159
173
|
var svg_use = (id, ...args) => s("svg", ["use", { "xlink:href": "#" + id }], ...args);
|
|
160
174
|
|
|
161
|
-
// src/nnn/
|
|
175
|
+
// src/nnn/fix_pl_typography.ts
|
|
162
176
|
var TAGS_TO_SKIP = ["IFRAME", "NOSCRIPT", "PRE", "SCRIPT", "STYLE", "TEXTAREA"];
|
|
163
|
-
var
|
|
177
|
+
var fix_pl_typography = (node) => {
|
|
164
178
|
const queue = [node];
|
|
165
179
|
while (queue.length > 0) {
|
|
166
180
|
const node_0 = queue.shift();
|
|
@@ -209,53 +223,14 @@ var js_on_parse = (handlers, text) => JSON.parse(text, (key, value) => {
|
|
|
209
223
|
}
|
|
210
224
|
return value;
|
|
211
225
|
});
|
|
212
|
-
// src/nnn/
|
|
213
|
-
var
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
__blue: "#1c8ca8",
|
|
217
|
-
__green: "#269d69",
|
|
218
|
-
__grey: "#918c8e",
|
|
219
|
-
__purple: "#7058be",
|
|
220
|
-
__red: "#e14775",
|
|
221
|
-
__white: "#29242a",
|
|
222
|
-
__yellow: "#cc7a0a"
|
|
223
|
-
},
|
|
224
|
-
body$$monokai: {
|
|
225
|
-
backgroundColor: "var(--black)",
|
|
226
|
-
color: "var(--white)"
|
|
227
|
-
},
|
|
228
|
-
"code>span.": {
|
|
229
|
-
black: { color: "var(--black)" },
|
|
230
|
-
blue: { color: "var(--blue)" },
|
|
231
|
-
green: { color: "var(--green)" },
|
|
232
|
-
grey: { color: "var(--grey)" },
|
|
233
|
-
purple: { color: "var(--purple)" },
|
|
234
|
-
red: { color: "var(--red)" },
|
|
235
|
-
white: { color: "var(--white)" },
|
|
236
|
-
yellow: { color: "var(--yellow)" }
|
|
237
|
-
},
|
|
238
|
-
pre: {
|
|
239
|
-
margin: 0,
|
|
240
|
-
overflow: "visible",
|
|
241
|
-
" code": {
|
|
242
|
-
fontFamily: '"Source Code Pro"',
|
|
243
|
-
padding: 0
|
|
244
|
-
}
|
|
245
|
-
},
|
|
246
|
-
"@media only screen and (prefers-color-scheme: dark)": {
|
|
247
|
-
":root": {
|
|
248
|
-
__black: "#2d2a2e",
|
|
249
|
-
__blue: "#66d9ef",
|
|
250
|
-
__green: "#a9dc76",
|
|
251
|
-
__grey: "#727072",
|
|
252
|
-
__purple: "#ae81ff",
|
|
253
|
-
__red: "#ff6188",
|
|
254
|
-
__white: "#fcfcfa",
|
|
255
|
-
__yellow: "#ffd866"
|
|
256
|
-
}
|
|
257
|
-
}
|
|
226
|
+
// src/nnn/new_noun_form.ts
|
|
227
|
+
var new_noun_form = (locale, forms) => {
|
|
228
|
+
const plural_rules = new Intl.PluralRules(locale);
|
|
229
|
+
return (value) => forms[plural_rules.select(value)] ?? forms.other ?? "";
|
|
258
230
|
};
|
|
231
|
+
// src/nnn/omit_pick.ts
|
|
232
|
+
var pick = (ref, keys) => Object.fromEntries(Object.entries(ref).filter(([key]) => keys.includes(key)));
|
|
233
|
+
var omit = (ref, keys) => Object.fromEntries(Object.entries(ref).filter(([key]) => !keys.includes(key)));
|
|
259
234
|
// src/nnn/tokenizer.ts
|
|
260
235
|
var new_tokenizer = (decorator, ...specs) => (code) => {
|
|
261
236
|
const result = [];
|
|
@@ -294,8 +269,6 @@ var new_tokenizer = (decorator, ...specs) => (code) => {
|
|
|
294
269
|
}
|
|
295
270
|
return result;
|
|
296
271
|
};
|
|
297
|
-
|
|
298
|
-
// src/nnn/nanolight.ts
|
|
299
272
|
var BLUE = "blue";
|
|
300
273
|
var GREEN = "green";
|
|
301
274
|
var GREY = "grey";
|
|
@@ -304,15 +277,52 @@ var RED = "red";
|
|
|
304
277
|
var WHITE = "white";
|
|
305
278
|
var YELLOW = "yellow";
|
|
306
279
|
var nanolight_ts = /* @__PURE__ */ new_tokenizer((chunk, name) => name != null ? ["span", { class: name }, chunk] : chunk, [YELLOW, /".*?"/], [YELLOW, /'.*?'/], [YELLOW, /`[\s\S]*?`/], [RED, "?"], [RED, /(?<=\s):/], [GREY, "("], [GREY, ")"], [GREY, ","], [GREY, "."], [GREY, ":"], [GREY, ";"], [GREY, "?."], [GREY, "["], [GREY, "]"], [GREY, "{"], [GREY, "}"], [GREY, /\/\*[\s\S]*?\*\//], [GREY, /(?<!\\)\/\/.*?(?=\n)/], [RED, "!"], [RED, "!="], [RED, "!=="], [RED, "%"], [RED, "%="], [RED, "&&"], [RED, "&&="], [RED, "&"], [RED, "&="], [RED, "*"], [RED, "**"], [RED, "**="], [RED, "*="], [RED, "+"], [RED, "++"], [RED, "+="], [RED, "-"], [RED, "--"], [RED, "-="], [RED, "..."], [RED, "/"], [RED, "/="], [RED, ":"], [RED, "<"], [RED, "<<"], [RED, "<<="], [RED, "<="], [RED, "="], [RED, "=="], [RED, "==="], [RED, "=>"], [RED, ">"], [RED, ">="], [RED, ">>"], [RED, ">>="], [RED, ">>>"], [RED, ">>>="], [RED, "?"], [RED, "??"], [RED, "??="], [RED, "^"], [RED, "^="], [RED, "as"], [RED, "async"], [RED, "await"], [RED, "break"], [RED, "case"], [RED, "catch"], [RED, "class"], [RED, "const"], [RED, "continue"], [RED, "debugger"], [RED, "default"], [RED, "delete"], [RED, "do"], [RED, "else"], [RED, "export"], [RED, "extends"], [RED, "finally"], [RED, "for"], [RED, "from"], [RED, "function"], [RED, "function*"], [RED, "goto"], [RED, "if"], [RED, "import"], [RED, "in"], [RED, "instanceof"], [RED, "is"], [RED, "keyof"], [RED, "let"], [RED, "new"], [RED, "of"], [RED, "package"], [RED, "return"], [RED, "super"], [RED, "switch"], [RED, "this"], [RED, "throw"], [RED, "try"], [RED, "type"], [RED, "typeof"], [RED, "var"], [RED, "void"], [RED, "while"], [RED, "with"], [RED, "yield"], [RED, "yield*"], [RED, "|"], [RED, "|="], [RED, "||"], [RED, "||="], [RED, "~"], [RED, "~="], [PURPLE, "false"], [PURPLE, "Infinity"], [PURPLE, "NaN"], [PURPLE, "null"], [PURPLE, "true"], [PURPLE, "undefined"], [PURPLE, /0b[01_]+/], [PURPLE, /0o[01234567_]+/], [PURPLE, /0x[\dabcdef_]+/], [PURPLE, /[\p{Lu}_$][\p{Lu}\d_$]+/u], [PURPLE, /\d[\d_]*(\.[\d_]+)?(e[+-]?[\d_]+)?/], [BLUE, "any"], [BLUE, "bigint"], [BLUE, "boolean"], [BLUE, "eval"], [BLUE, "number"], [BLUE, "string"], [BLUE, "symbol"], [BLUE, "unknown"], [GREEN, /[\p{L}_$][\p{L}\d_$]+(?=\()/u], [BLUE, /\p{Lu}[\p{L}\d_$]+/u], [WHITE, /[\p{L}_$][\p{L}\d_$]+/u]);
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
280
|
+
var monokai = {
|
|
281
|
+
":root": {
|
|
282
|
+
__black: "$faf4f2",
|
|
283
|
+
__blue: "#1c8ca8",
|
|
284
|
+
__green: "#269d69",
|
|
285
|
+
__grey: "#918c8e",
|
|
286
|
+
__purple: "#7058be",
|
|
287
|
+
__red: "#e14775",
|
|
288
|
+
__white: "#29242a",
|
|
289
|
+
__yellow: "#cc7a0a"
|
|
290
|
+
},
|
|
291
|
+
body$$monokai: {
|
|
292
|
+
backgroundColor: "var(--black)",
|
|
293
|
+
color: "var(--white)"
|
|
294
|
+
},
|
|
295
|
+
"code>span.": {
|
|
296
|
+
black: { color: "var(--black)" },
|
|
297
|
+
blue: { color: "var(--blue)" },
|
|
298
|
+
green: { color: "var(--green)" },
|
|
299
|
+
grey: { color: "var(--grey)" },
|
|
300
|
+
purple: { color: "var(--purple)" },
|
|
301
|
+
red: { color: "var(--red)" },
|
|
302
|
+
white: { color: "var(--white)" },
|
|
303
|
+
yellow: { color: "var(--yellow)" }
|
|
304
|
+
},
|
|
305
|
+
pre: {
|
|
306
|
+
margin: 0,
|
|
307
|
+
overflow: "visible",
|
|
308
|
+
" code": {
|
|
309
|
+
fontFamily: '"Source Code Pro"',
|
|
310
|
+
padding: 0
|
|
311
|
+
}
|
|
312
|
+
},
|
|
313
|
+
"@media only screen and (prefers-color-scheme: dark)": {
|
|
314
|
+
":root": {
|
|
315
|
+
__black: "#2d2a2e",
|
|
316
|
+
__blue: "#66d9ef",
|
|
317
|
+
__green: "#a9dc76",
|
|
318
|
+
__grey: "#727072",
|
|
319
|
+
__purple: "#ae81ff",
|
|
320
|
+
__red: "#ff6188",
|
|
321
|
+
__white: "#fcfcfa",
|
|
322
|
+
__yellow: "#ffd866"
|
|
323
|
+
}
|
|
324
|
+
}
|
|
312
325
|
};
|
|
313
|
-
// src/nnn/omit_pick.ts
|
|
314
|
-
var pick = (ref, keys) => Object.fromEntries(Object.entries(ref).filter(([key]) => keys.includes(key)));
|
|
315
|
-
var omit = (ref, keys) => Object.fromEntries(Object.entries(ref).filter(([key]) => !keys.includes(key)));
|
|
316
326
|
// src/nnn/uuid_v1.ts
|
|
317
327
|
var ZEROS = /* @__PURE__ */ "0".repeat(16);
|
|
318
328
|
var counter = 0;
|
|
@@ -322,11 +332,11 @@ var uuid_v1 = (date = new Date, node = Math.random().toString(16).slice(2)) => {
|
|
|
322
332
|
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));
|
|
323
333
|
};
|
|
324
334
|
export {
|
|
335
|
+
vivify,
|
|
325
336
|
uuid_v1,
|
|
326
337
|
svg_use,
|
|
327
338
|
s,
|
|
328
339
|
rwd,
|
|
329
|
-
pro,
|
|
330
340
|
pick,
|
|
331
341
|
omit,
|
|
332
342
|
new_tokenizer,
|
|
@@ -342,7 +352,7 @@ export {
|
|
|
342
352
|
is_array,
|
|
343
353
|
has_own,
|
|
344
354
|
h,
|
|
345
|
-
|
|
355
|
+
fix_pl_typography,
|
|
346
356
|
escape_values,
|
|
347
357
|
csv_parse,
|
|
348
358
|
c
|
package/package.json
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
"author": "Jackens",
|
|
3
3
|
"description": "Jackens’ JavaScript helpers.",
|
|
4
4
|
"keywords": [
|
|
5
|
+
"autovivify",
|
|
5
6
|
"c",
|
|
6
7
|
"CSS-in-JS",
|
|
7
8
|
"CSV parse",
|
|
@@ -34,12 +35,13 @@
|
|
|
34
35
|
"tokenizer",
|
|
35
36
|
"typography",
|
|
36
37
|
"uuid",
|
|
37
|
-
"uuidv1"
|
|
38
|
+
"uuidv1",
|
|
39
|
+
"vivify"
|
|
38
40
|
],
|
|
39
41
|
"license": "MIT",
|
|
40
42
|
"main": "nnn.js",
|
|
41
43
|
"name": "@jackens/nnn",
|
|
42
44
|
"type": "module",
|
|
43
45
|
"types": "nnn.d.ts",
|
|
44
|
-
"version": "
|
|
46
|
+
"version": "2026.2.6"
|
|
45
47
|
}
|
package/readme.md
CHANGED
|
@@ -5,25 +5,43 @@ A collection of Jackens’ JavaScript helper utilities.
|
|
|
5
5
|
## Installation
|
|
6
6
|
|
|
7
7
|
```sh
|
|
8
|
-
bun i @jackens/nnn
|
|
9
|
-
```
|
|
10
|
-
|
|
11
|
-
or
|
|
12
|
-
|
|
13
|
-
```sh
|
|
14
|
-
npm i @jackens/nnn
|
|
8
|
+
bun i @jackens/nnn # npm i @jackens/nnn
|
|
15
9
|
```
|
|
16
10
|
|
|
17
11
|
## Usage
|
|
18
12
|
|
|
19
13
|
```js
|
|
20
|
-
import {
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
14
|
+
import {
|
|
15
|
+
CNode,
|
|
16
|
+
CRoot,
|
|
17
|
+
EscapeMap,
|
|
18
|
+
HArgs,
|
|
19
|
+
HArgs1,
|
|
20
|
+
c,
|
|
21
|
+
csv_parse,
|
|
22
|
+
escape_values,
|
|
23
|
+
fix_pl_typography,
|
|
24
|
+
h,
|
|
25
|
+
has_own,
|
|
26
|
+
is_array,
|
|
27
|
+
is_finite_number,
|
|
28
|
+
is_number,
|
|
29
|
+
is_record,
|
|
30
|
+
is_string,
|
|
31
|
+
js_on_parse,
|
|
32
|
+
monokai,
|
|
33
|
+
nanolight_ts,
|
|
34
|
+
new_escape,
|
|
35
|
+
new_noun_form,
|
|
36
|
+
new_tokenizer,
|
|
37
|
+
omit,
|
|
38
|
+
pick,
|
|
39
|
+
rwd,
|
|
40
|
+
s,
|
|
41
|
+
svg_use,
|
|
42
|
+
uuid_v1,
|
|
43
|
+
vivify
|
|
44
|
+
} from '@jackens/nnn' // './node_modules/@jackens/nnn/nnn.js'
|
|
27
45
|
```
|
|
28
46
|
|
|
29
47
|
## Exports
|
|
@@ -36,8 +54,9 @@ import { «something» } from './node_modules/@jackens/nnn/nnn.js'
|
|
|
36
54
|
- [`c`](#c): A minimal CSS-in-JS helper that converts a JavaScript object hierarchy into a CSS string.
|
|
37
55
|
- [`csv_parse`](#csv_parse): Parses a CSV string into a two-dimensional array of strings.
|
|
38
56
|
- [`escape_values`](#escape_values): Escapes an array of values using the provided escape map.
|
|
39
|
-
- [`
|
|
57
|
+
- [`fix_pl_typography`](#fix_pl_typography): Applies Polish-specific typographic corrections to a DOM subtree.
|
|
40
58
|
- [`h`](#h): A lightweight [HyperScript](https://github.com/hyperhype/hyperscript)-style helper
|
|
59
|
+
for creating and modifying `HTMLElement`s (see also [`s`](#s)).
|
|
41
60
|
- [`has_own`](#has_own): Checks whether an object has the specified key as its own property.
|
|
42
61
|
- [`is_array`](#is_array): Checks whether the argument is an array.
|
|
43
62
|
- [`is_finite_number`](#is_finite_number): Checks whether the argument is a finite number (excludes `±Infinity` and `NaN`).
|
|
@@ -48,15 +67,16 @@ import { «something» } from './node_modules/@jackens/nnn/nnn.js'
|
|
|
48
67
|
- [`monokai`](#monokai): A Monokai-inspired color scheme for use with the [`c`](#c) helper and [`nanolight_ts`](#nanolight_ts) tokenizer.
|
|
49
68
|
- [`nanolight_ts`](#nanolight_ts): A TypeScript/JavaScript syntax highlighting tokenizer built using [`new_tokenizer`](#new_tokenizer).
|
|
50
69
|
- [`new_escape`](#new_escape): Creates a tag function for escaping interpolated values in template literals.
|
|
51
|
-
- [`new_noun_form`](#new_noun_form): Creates a function that returns the appropriate
|
|
70
|
+
- [`new_noun_form`](#new_noun_form): Creates a function that returns the appropriate noun form based on a numeric value using `Intl.PluralRules`.
|
|
52
71
|
- [`new_tokenizer`](#new_tokenizer): A helper for building simple tokenizers (see also [`nanolight_ts`](#nanolight_ts)).
|
|
53
72
|
- [`omit`](#omit): Creates a new object excluding the specified keys from the source object.
|
|
54
73
|
- [`pick`](#pick): Creates a new object containing only the specified keys from the source object.
|
|
55
|
-
- [`pro`](#pro): A Proxy-based helper for auto-vivification of nested object structures.
|
|
56
74
|
- [`rwd`](#rwd): A responsive web design helper that generates CSS rules for a grid-like layout.
|
|
57
75
|
- [`s`](#s): A lightweight [HyperScript](https://github.com/hyperhype/hyperscript)-style helper
|
|
76
|
+
for creating and modifying `SVGElement`s (see also [`h`](#h)).
|
|
58
77
|
- [`svg_use`](#svg_use): Shorthand for creating an SVG element with a `<use>` child referencing an icon by ID.
|
|
59
78
|
- [`uuid_v1`](#uuid_v1): Generates a UUID v1 (time-based) identifier.
|
|
79
|
+
- [`vivify`](#vivify): A Proxy-based helper for auto-vivification of nested object structures.
|
|
60
80
|
|
|
61
81
|
### CNode
|
|
62
82
|
|
|
@@ -389,10 +409,10 @@ The array of values to escape.
|
|
|
389
409
|
|
|
390
410
|
An array of escaped strings.
|
|
391
411
|
|
|
392
|
-
###
|
|
412
|
+
### fix_pl_typography
|
|
393
413
|
|
|
394
414
|
```ts
|
|
395
|
-
const
|
|
415
|
+
const fix_pl_typography: (node: Node) => void;
|
|
396
416
|
```
|
|
397
417
|
|
|
398
418
|
Applies Polish-specific typographic corrections to a DOM subtree.
|
|
@@ -411,7 +431,7 @@ except those inside `IFRAME`, `NOSCRIPT`, `PRE`, `SCRIPT`, `STYLE`, or `TEXTAREA
|
|
|
411
431
|
```ts
|
|
412
432
|
const p = h('p', 'Pchnąć w tę łódź jeża lub ośm skrzyń fig (zob. https://pl.wikipedia.org/wiki/Pangram).')
|
|
413
433
|
|
|
414
|
-
|
|
434
|
+
fix_pl_typography(p)
|
|
415
435
|
|
|
416
436
|
expect(p.innerHTML).to.deep.equal(
|
|
417
437
|
'Pchnąć <span style="white-space:nowrap">w </span>tę łódź jeża lub ośm skrzyń fig ' +
|
|
@@ -877,12 +897,12 @@ const sql = new_escape(escape_map)
|
|
|
877
897
|
const actual = sql`
|
|
878
898
|
SELECT *
|
|
879
899
|
FROM table_name
|
|
880
|
-
WHERE column_name IN (${[true, null, undefined, 42, '42', "4'2",
|
|
900
|
+
WHERE column_name IN (${[true, null, undefined, 42, '42', "4'2", new Date(323325000000)]})`
|
|
881
901
|
|
|
882
902
|
const expected = `
|
|
883
903
|
SELECT *
|
|
884
904
|
FROM table_name
|
|
885
|
-
WHERE column_name IN (b'1', NULL, NULL, 42, '42', '4''2',
|
|
905
|
+
WHERE column_name IN (b'1', NULL, NULL, 42, '42', '4''2', '1980-03-31 04:30:00')`
|
|
886
906
|
|
|
887
907
|
expect(actual).to.deep.equal(expected)
|
|
888
908
|
```
|
|
@@ -890,27 +910,29 @@ expect(actual).to.deep.equal(expected)
|
|
|
890
910
|
### new_noun_form
|
|
891
911
|
|
|
892
912
|
```ts
|
|
893
|
-
const new_noun_form: (
|
|
913
|
+
const new_noun_form: (locale: string, forms: Partial<Record<Intl.LDMLPluralRule, string>>) => (value: number) => string;
|
|
894
914
|
```
|
|
895
915
|
|
|
896
|
-
Creates a function that returns the appropriate
|
|
897
|
-
|
|
898
|
-
Polish has three plural forms depending on the number:
|
|
899
|
-
- Singular: used for exactly 1.
|
|
900
|
-
- “Plural 2-4”: used for 2, 3, 4, 22, 23, 24, etc. (but not 12, 13, 14).
|
|
901
|
-
- “Plural 5+”: used for 0, 5–21, 25–31, etc.
|
|
916
|
+
Creates a function that returns the appropriate noun form based on a numeric value using `Intl.PluralRules`.
|
|
902
917
|
|
|
903
|
-
|
|
918
|
+
Different languages have different plural rules. The `Intl.PluralRules` API provides
|
|
919
|
+
locale-aware plural category selection. Possible categories are:
|
|
904
920
|
|
|
905
|
-
|
|
921
|
+
- `zero` - for zero items (used in some languages like Arabic, Latvian)
|
|
922
|
+
- `one` - for singular (e.g., 1 item)
|
|
923
|
+
- `two` - for dual (used in some languages like Arabic, Hebrew)
|
|
924
|
+
- `few` - for small plurals (e.g., 2-4 in Polish)
|
|
925
|
+
- `many` - for larger plurals (e.g., 5-21 in Polish)
|
|
926
|
+
- `other` - fallback category (used by all languages)
|
|
906
927
|
|
|
907
|
-
####
|
|
928
|
+
#### locale
|
|
908
929
|
|
|
909
|
-
|
|
930
|
+
A BCP 47 language tag (e.g., "pl", "en").
|
|
910
931
|
|
|
911
|
-
####
|
|
932
|
+
#### forms
|
|
912
933
|
|
|
913
|
-
|
|
934
|
+
An object mapping plural categories to noun forms. Not all categories need to be provided;
|
|
935
|
+
if a category is missing, the function falls back to `other`, then to an empty string.
|
|
914
936
|
|
|
915
937
|
#### Returns
|
|
916
938
|
|
|
@@ -919,14 +941,14 @@ A function that takes a numeric value and returns the appropriate noun form.
|
|
|
919
941
|
#### Usage Examples
|
|
920
942
|
|
|
921
943
|
```ts
|
|
922
|
-
const auto = new_noun_form('auto', 'auta', 'aut')
|
|
944
|
+
const auto = new_noun_form('pl', { one: 'auto', few: 'auta', other: 'aut' })
|
|
923
945
|
|
|
924
946
|
expect(auto(0)).to.deep.equal('aut')
|
|
925
947
|
expect(auto(1)).to.deep.equal('auto')
|
|
926
948
|
expect(auto(17)).to.deep.equal('aut')
|
|
927
949
|
expect(auto(42)).to.deep.equal('auta')
|
|
928
950
|
|
|
929
|
-
const car = new_noun_form('
|
|
951
|
+
const car = new_noun_form('en', { one: 'car', other: 'cars' })
|
|
930
952
|
|
|
931
953
|
expect(car(0)).to.deep.equal('cars')
|
|
932
954
|
expect(car(1)).to.deep.equal('car')
|
|
@@ -1024,55 +1046,6 @@ const obj = { a: 42, b: '42', c: 17 }
|
|
|
1024
1046
|
expect(pick(obj, ['a', 'b'])).to.deep.equal({ a: 42, b: '42' })
|
|
1025
1047
|
```
|
|
1026
1048
|
|
|
1027
|
-
### pro
|
|
1028
|
-
|
|
1029
|
-
```ts
|
|
1030
|
-
const pro: (ref: unknown) => any;
|
|
1031
|
-
```
|
|
1032
|
-
|
|
1033
|
-
A Proxy-based helper for auto-vivification of nested object structures.
|
|
1034
|
-
|
|
1035
|
-
Accessing any property on the returned proxy automatically creates an empty object if the property does not exist,
|
|
1036
|
-
allowing deep assignments without explicit null checks.
|
|
1037
|
-
|
|
1038
|
-
#### ref
|
|
1039
|
-
|
|
1040
|
-
The root object to wrap.
|
|
1041
|
-
|
|
1042
|
-
#### Returns
|
|
1043
|
-
|
|
1044
|
-
A proxy that auto-creates nested objects on property access.
|
|
1045
|
-
|
|
1046
|
-
#### Usage Examples
|
|
1047
|
-
|
|
1048
|
-
```ts
|
|
1049
|
-
const ref = {}
|
|
1050
|
-
|
|
1051
|
-
pro(ref).one.two[3][4] = 1234
|
|
1052
|
-
|
|
1053
|
-
expect(ref).to.deep.equal({ one: { two: { 3: { 4: 1234 } } } })
|
|
1054
|
-
|
|
1055
|
-
pro(ref).one.two.tree = 123
|
|
1056
|
-
|
|
1057
|
-
expect(ref).to.deep.equal({ one: { two: { 3: { 4: 1234 }, tree: 123 } } })
|
|
1058
|
-
|
|
1059
|
-
pro(ref).one.two = undefined
|
|
1060
|
-
|
|
1061
|
-
expect(ref).to.deep.equal({ one: { two: undefined } })
|
|
1062
|
-
|
|
1063
|
-
delete pro(ref).one.two
|
|
1064
|
-
|
|
1065
|
-
expect(ref).to.deep.equal({ one: {} })
|
|
1066
|
-
|
|
1067
|
-
pro(ref).one.two.three.four
|
|
1068
|
-
|
|
1069
|
-
expect(ref).to.deep.equal({ one: { two: { three: { four: {} } } } })
|
|
1070
|
-
|
|
1071
|
-
pro(ref).one.two.three.four = 1234
|
|
1072
|
-
|
|
1073
|
-
expect(ref).to.deep.equal({ one: { two: { three: { four: 1234 } } } })
|
|
1074
|
-
```
|
|
1075
|
-
|
|
1076
1049
|
### rwd
|
|
1077
1050
|
|
|
1078
1051
|
```ts
|
|
@@ -1271,6 +1244,67 @@ expect(uuid_v1(new Date(), '123456789').split('-')[4]).to.deep.equal('0001234567
|
|
|
1271
1244
|
expect(uuid_v1(new Date(323325000000)).startsWith('c1399400-9a71-11bd')).to.be.true
|
|
1272
1245
|
```
|
|
1273
1246
|
|
|
1247
|
+
### vivify
|
|
1248
|
+
|
|
1249
|
+
```ts
|
|
1250
|
+
const vivify: (ref: unknown) => any;
|
|
1251
|
+
```
|
|
1252
|
+
|
|
1253
|
+
A Proxy-based helper for auto-vivification of nested object structures.
|
|
1254
|
+
|
|
1255
|
+
Accessing any property on the returned proxy automatically creates an empty object
|
|
1256
|
+
(or array for numeric keys) if the property does not exist,
|
|
1257
|
+
allowing deep assignments without explicit null checks.
|
|
1258
|
+
|
|
1259
|
+
When a numeric key (like `[42]`) is accessed, the parent structure is
|
|
1260
|
+
automatically converted to an array if it isn’t one already.
|
|
1261
|
+
|
|
1262
|
+
#### ref
|
|
1263
|
+
|
|
1264
|
+
The root object to wrap.
|
|
1265
|
+
|
|
1266
|
+
#### Returns
|
|
1267
|
+
|
|
1268
|
+
A proxy that auto-creates nested objects/arrays on property access.
|
|
1269
|
+
|
|
1270
|
+
#### Usage Examples
|
|
1271
|
+
|
|
1272
|
+
```ts
|
|
1273
|
+
const ref: any = {}
|
|
1274
|
+
|
|
1275
|
+
vivify(ref).one.two[3][4] = 1234
|
|
1276
|
+
|
|
1277
|
+
expect(ref).to.deep.equal({ one: { two: [, , , [, , , , 1234]] } })
|
|
1278
|
+
|
|
1279
|
+
vivify(ref).one.two[3][5] = 12345
|
|
1280
|
+
|
|
1281
|
+
expect(ref).to.deep.equal({ one: { two: [, , , [, , , , 1234, 12345]] } })
|
|
1282
|
+
|
|
1283
|
+
vivify(ref).one.two[1] = 'one'
|
|
1284
|
+
|
|
1285
|
+
expect(ref).to.deep.equal({ one: { two: [, 'one', , [, , , , 1234, 12345]] } })
|
|
1286
|
+
|
|
1287
|
+
vivify(ref).one.two = 'tree'
|
|
1288
|
+
|
|
1289
|
+
expect(ref).to.deep.equal({ one: { two: 'tree' } })
|
|
1290
|
+
|
|
1291
|
+
vivify(ref).one.two = undefined
|
|
1292
|
+
|
|
1293
|
+
expect(ref).to.deep.equal({ one: { two: undefined } })
|
|
1294
|
+
|
|
1295
|
+
delete vivify(ref).one.two
|
|
1296
|
+
|
|
1297
|
+
expect(ref).to.deep.equal({ one: {} })
|
|
1298
|
+
|
|
1299
|
+
vivify(ref).one.two.three.four
|
|
1300
|
+
|
|
1301
|
+
expect(ref).to.deep.equal({ one: { two: { three: { four: {} } } } })
|
|
1302
|
+
|
|
1303
|
+
vivify(ref).one.two.three.four = 1234
|
|
1304
|
+
|
|
1305
|
+
expect(ref).to.deep.equal({ one: { two: { three: { four: 1234 } } } })
|
|
1306
|
+
```
|
|
1307
|
+
|
|
1274
1308
|
## License
|
|
1275
1309
|
|
|
1276
1310
|
The MIT License (MIT)
|