@jackens/nnn 2025.12.13 → 2025.12.23

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 (4) hide show
  1. package/nnn.d.ts +58 -70
  2. package/nnn.js +58 -10
  3. package/package.json +8 -5
  4. package/readme.md +113 -107
package/nnn.d.ts CHANGED
@@ -62,7 +62,6 @@ export declare const c: (root: CRoot, splitter?: string) => string;
62
62
  * - `height` (optional, default `1`): number of vertical cells the element spans.
63
63
  */
64
64
  export declare const rwd: (root: CRoot, selector: string, cell_width_px: number, cell_height_px: number, ...specs: [number, number?, number?][]) => void;
65
-
66
65
  /**
67
66
  * Parses a CSV string into a two-dimensional array of strings.
68
67
  *
@@ -81,11 +80,10 @@ export declare const rwd: (root: CRoot, selector: string, cell_width_px: number,
81
80
  * A 2D array where each inner array represents a row of fields.
82
81
  */
83
82
  export declare const csv_parse: (csv: string, separator?: string) => string[][];
84
-
85
83
  /**
86
84
  * A map from value constructors (or `null`/`undefined`) to escape functions.
87
85
  *
88
- * Used by {@link escape_values} and {@link escape}.
86
+ * Used by {@link escape_values} and {@link new_escape}.
89
87
  */
90
88
  export type EscapeMap = Map<unknown, (value?: unknown) => string>;
91
89
  /**
@@ -105,26 +103,17 @@ export type EscapeMap = Map<unknown, (value?: unknown) => string>;
105
103
  */
106
104
  export declare const escape_values: (escape_map: EscapeMap, values: unknown[]) => string[];
107
105
  /**
108
- * Escapes interpolated values in a tagged template literal using the provided escape map.
106
+ * Creates a tag function for escaping interpolated values in template literals.
109
107
  *
110
108
  * @param escape_map
111
109
  *
112
110
  * A map where keys are constructors and values are escape functions.
113
111
  *
114
- * @param template
115
- *
116
- * The template strings array from the tagged template.
117
- *
118
- * @param values
119
- *
120
- * The interpolated values to escape.
121
- *
122
112
  * @returns
123
113
  *
124
- * The resulting string with all interpolated values escaped.
114
+ * A tag function that escapes interpolated values using the provided escape map.
125
115
  */
126
- export declare const escape: (escape_map: EscapeMap, template: TemplateStringsArray, ...values: unknown[]) => string;
127
-
116
+ export declare const new_escape: (escape_map: EscapeMap) => (template: TemplateStringsArray, ...values: unknown[]) => string;
128
117
  /**
129
118
  * Applies Polish-specific typographic corrections to a DOM subtree.
130
119
  *
@@ -138,7 +127,6 @@ export declare const escape: (escape_map: EscapeMap, template: TemplateStringsAr
138
127
  * except those inside `IFRAME`, `NOSCRIPT`, `PRE`, `SCRIPT`, `STYLE`, or `TEXTAREA` elements.
139
128
  */
140
129
  export declare const fix_typography: (node: Node) => void;
141
-
142
130
  /**
143
131
  * Single argument type for the {@link h} and {@link s} helpers.
144
132
  */
@@ -221,7 +209,6 @@ export declare const s: {
221
209
  * An `SVGSVGElement` containing a `<use>` element.
222
210
  */
223
211
  export declare const svg_use: (id: string, ...args: HArgs1[]) => SVGSVGElement;
224
-
225
212
  /**
226
213
  * Checks whether an object has the specified key as its own property.
227
214
  *
@@ -240,7 +227,6 @@ export declare const svg_use: (id: string, ...args: HArgs1[]) => SVGSVGElement;
240
227
  * `true` if `ref` is not nullish and has `key` as an own property, `false` otherwise.
241
228
  */
242
229
  export declare const has_own: (ref: unknown, key: unknown) => boolean;
243
-
244
230
  /**
245
231
  * Checks whether the argument is an array.
246
232
  *
@@ -301,7 +287,6 @@ export declare const is_record: (arg: unknown) => arg is Record<PropertyKey, unk
301
287
  * `true` if `typeof arg === 'string'`, `false` otherwise.
302
288
  */
303
289
  export declare const is_string: (arg: unknown) => arg is string;
304
-
305
290
  /**
306
291
  * Parses JSON with support for handler-based value transformation (“JavaScript ON”).
307
292
  *
@@ -321,7 +306,19 @@ export declare const is_string: (arg: unknown) => arg is string;
321
306
  * The parsed value with handler substitutions applied.
322
307
  */
323
308
  export declare const js_on_parse: (handlers: Record<PropertyKey, Function>, text: string) => any;
324
-
309
+ /**
310
+ * A Monokai-inspired color scheme for use with the {@link c} helper and {@link nanolight_ts} tokenizer.
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;
325
322
  /**
326
323
  * A TypeScript/JavaScript syntax highlighting tokenizer built using {@link new_tokenizer}.
327
324
  *
@@ -331,37 +328,34 @@ export declare const js_on_parse: (handlers: Record<PropertyKey, Function>, text
331
328
  *
332
329
  * @returns
333
330
  *
334
- * An array of {@link HArgs1} elements suitable for rendering with {@link h} or {@link s}.
331
+ * An array of {@link HArgs1} elements suitable for rendering with {@link h}.
335
332
  */
336
333
  export declare const nanolight_ts: (code: string) => HArgs1[];
337
-
338
334
  /**
339
- * A helper for building simple tokenizers (see also {@link nanolight_ts}).
335
+ * Creates a function that returns the appropriate Polish noun form based on a numeric value.
340
336
  *
341
- * @param decorator
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.
342
341
  *
343
- * A function that wraps each matched chunk. It receives the matched text (`chunk`)
344
- * and optionally the `metadata` associated with the pattern that produced the match.
345
- * For unmatched text between patterns, `metadata` is `undefined`.
342
+ * @param singular
346
343
  *
347
- * @param specs
344
+ * The singular form (e.g., “auto” for “car”).
348
345
  *
349
- * An array of tuples `[metadata, pattern]` where:
350
- * - `metadata`: arbitrary data (e.g., a CSS class name) passed to `decorator` when the pattern matches.
351
- * - `pattern`: a `string` or `RegExp` to match against the input.
346
+ * @param plural_2
352
347
  *
353
- * @returns
348
+ * The form for 2, 3, 4 (e.g., “auta”).
354
349
  *
355
- * A tokenizer function that accepts a code string and returns an array of decorated tokens.
350
+ * @param plural_5
356
351
  *
357
- * @remarks
352
+ * The form for 5+ (e.g., “aut”).
358
353
  *
359
- * 1. Matches starting at an earlier position take precedence.
360
- * 2. Among matches at the same position, the longer one wins.
361
- * 3. Among matches of the same position and length, the one defined earlier wins.
354
+ * @returns
355
+ *
356
+ * A function that takes a numeric value and returns the appropriate noun form.
362
357
  */
363
- export declare const new_tokenizer: <M, T>(decorator: (chunk: string, metadata?: M) => T, ...specs: [M, string | RegExp][]) => (code: string) => T[];
364
-
358
+ export declare const new_noun_form: (singular: string, plural_2: string, plural_5: string) => (value: number) => string;
365
359
  /**
366
360
  * Creates a new object containing only the specified keys from the source object.
367
361
  *
@@ -398,53 +392,47 @@ export declare const pick: <T, K extends keyof T>(ref: T, keys: K[]) => Pick<T,
398
392
  * A new object without the specified keys.
399
393
  */
400
394
  export declare const omit: <T, K extends keyof T>(ref: T, keys: unknown[]) => Omit<T, K>;
401
-
402
395
  /**
403
- * Returns the appropriate Polish noun form based on a numeric value.
404
- *
405
- * Polish has three plural forms depending on the number:
406
- * - Singular: used for exactly 1.
407
- * - “Plural 2-4”: used for 2, 3, 4, 22, 23, 24, etc. (but not 12, 13, 14).
408
- * - “Plural 5+”: used for 0, 5–21, 25–31, etc.
409
- *
410
- * @param singular
411
- *
412
- * The singular form (e.g., “auto” for “car”).
413
- *
414
- * @param plural_2
415
- *
416
- * The form for 2, 3, 4 (e.g., “auta”).
417
- *
418
- * @param plural_5
396
+ * A Proxy-based helper for auto-vivification of nested object structures.
419
397
  *
420
- * The form for 5+ (e.g., “aut”).
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.
421
400
  *
422
- * @param value
401
+ * @param ref
423
402
  *
424
- * The numeric value to evaluate.
403
+ * The root object to wrap.
425
404
  *
426
405
  * @returns
427
406
  *
428
- * The appropriate noun form for the given value.
407
+ * A proxy that auto-creates nested objects on property access.
429
408
  */
430
- export declare const pl_ural: (singular: string, plural_2: string, plural_5: string, value: number) => string;
431
-
409
+ export declare const pro: (ref: unknown) => any;
432
410
  /**
433
- * A Proxy-based helper for auto-vivification of nested object structures.
411
+ * A helper for building simple tokenizers (see also {@link nanolight_ts}).
434
412
  *
435
- * Accessing any property on the returned proxy automatically creates an empty object if the property does not exist,
436
- * allowing deep assignments without explicit null checks.
413
+ * @param decorator
437
414
  *
438
- * @param ref
415
+ * A function that wraps each matched chunk. It receives the matched text (`chunk`)
416
+ * and optionally the `metadata` associated with the pattern that produced the match.
417
+ * For unmatched text between patterns, `metadata` is `undefined`.
439
418
  *
440
- * The root object to wrap.
419
+ * @param specs
420
+ *
421
+ * An array of tuples `[metadata, pattern]` where:
422
+ * - `metadata`: arbitrary data (e.g., a CSS class name) passed to `decorator` when the pattern matches.
423
+ * - `pattern`: a `string` or `RegExp` to match against the input.
441
424
  *
442
425
  * @returns
443
426
  *
444
- * A proxy that auto-creates nested objects on property access.
427
+ * A tokenizer function that accepts a code string and returns an array of decorated tokens.
428
+ *
429
+ * @remarks
430
+ *
431
+ * 1. Matches starting at an earlier position take precedence.
432
+ * 2. Among matches at the same position, the longer one wins.
433
+ * 3. Among matches of the same position and length, the one defined earlier wins.
445
434
  */
446
- export declare const pro: (ref: unknown) => any;
447
-
435
+ export declare const new_tokenizer: <M, T>(decorator: (chunk: string, metadata?: M) => T, ...specs: [M, string | RegExp][]) => (code: string) => T[];
448
436
  /**
449
437
  * Generates a UUID v1 (time-based) identifier.
450
438
  *
package/nnn.js CHANGED
@@ -94,7 +94,7 @@ var csv_parse = (csv, separator = ",") => {
94
94
  };
95
95
  // src/nnn/escape.ts
96
96
  var escape_values = (escape_map, values) => values.map((value) => (value == null ? escape_map.get(value) : escape_map.get(value?.constructor))?.(value) ?? "");
97
- var escape = (escape_map, template, ...values) => String.raw(template, ...escape_values(escape_map, values));
97
+ var new_escape = (escape_map) => (template, ...values) => String.raw(template, ...escape_values(escape_map, values));
98
98
  // src/nnn/h.ts
99
99
  var _h = (namespace_uri) => {
100
100
  const create_element = namespace_uri == null ? (tag) => document.createElement(tag) : (tag) => document.createElementNS(namespace_uri, tag);
@@ -209,7 +209,54 @@ var js_on_parse = (handlers, text) => JSON.parse(text, (key, value) => {
209
209
  }
210
210
  return value;
211
211
  });
212
- // src/nnn/new_tokenizer.ts
212
+ // src/nnn/monokai.ts
213
+ var monokai = {
214
+ ":root": {
215
+ __black: "$faf4f2",
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
+ }
258
+ };
259
+ // src/nnn/tokenizer.ts
213
260
  var new_tokenizer = (decorator, ...specs) => (code) => {
214
261
  const result = [];
215
262
  while (code.length > 0) {
@@ -256,16 +303,16 @@ var PURPLE = "purple";
256
303
  var RED = "red";
257
304
  var WHITE = "white";
258
305
  var YELLOW = "yellow";
259
- var nanolight_ts = /* @__PURE__ */ new_tokenizer((chunk, name) => name != null ? ["span", { class: name }, chunk] : chunk, [YELLOW, /".*?"/], [YELLOW, /'.*?'/], [YELLOW, /`[\s\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, "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, /[A-Z_$][A-Z0-9_$]+/], [PURPLE, /\d[\d_]*(\.[\d_]+)?(e[+-]?[\d_]+)?/], [BLUE, "any"], [BLUE, "bigint"], [BLUE, "boolean"], [BLUE, "eval"], [BLUE, "number"], [BLUE, "string"], [BLUE, "symbol"], [BLUE, "unknown"], [GREEN, /[$\w]+(?=\()/], [BLUE, /[A-Z][$\w]+/], [WHITE, /[$\w]+/]);
260
- // src/nnn/omit_pick.ts
261
- var pick = (ref, keys) => Object.fromEntries(Object.entries(ref).filter(([key]) => keys.includes(key)));
262
- var omit = (ref, keys) => Object.fromEntries(Object.entries(ref).filter(([key]) => !keys.includes(key)));
263
- // src/nnn/pl_ural.ts
264
- var pl_ural = (singular, plural_2, plural_5, value) => {
306
+ 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
+ // src/nnn/noun_form.ts
308
+ var new_noun_form = (singular, plural_2, plural_5) => (value) => {
265
309
  const abs_value = Math.abs(value);
266
310
  const abs_value_mod_10 = abs_value % 10;
267
311
  return value === 1 ? singular : (abs_value_mod_10 === 2 || abs_value_mod_10 === 3 || abs_value_mod_10 === 4) && abs_value !== 12 && abs_value !== 13 && abs_value !== 14 ? plural_2 : plural_5;
268
312
  };
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)));
269
316
  // src/nnn/uuid_v1.ts
270
317
  var ZEROS = /* @__PURE__ */ "0".repeat(16);
271
318
  var counter = 0;
@@ -280,11 +327,13 @@ export {
280
327
  s,
281
328
  rwd,
282
329
  pro,
283
- pl_ural,
284
330
  pick,
285
331
  omit,
286
332
  new_tokenizer,
333
+ new_noun_form,
334
+ new_escape,
287
335
  nanolight_ts,
336
+ monokai,
288
337
  js_on_parse,
289
338
  is_string,
290
339
  is_record,
@@ -295,7 +344,6 @@ export {
295
344
  h,
296
345
  fix_typography,
297
346
  escape_values,
298
- escape,
299
347
  csv_parse,
300
348
  c
301
349
  };
package/package.json CHANGED
@@ -4,8 +4,7 @@
4
4
  "keywords": [
5
5
  "c",
6
6
  "CSS-in-JS",
7
- "CSV",
8
- "csv_parse",
7
+ "CSV parse",
9
8
  "DOM",
10
9
  "escape",
11
10
  "h",
@@ -20,15 +19,19 @@
20
19
  "is_record",
21
20
  "is_string",
22
21
  "JS-to-CSS",
23
- "JSON",
24
22
  "js_on_parse",
23
+ "JSON",
24
+ "Monokai",
25
25
  "nanolight",
26
26
  "nnn",
27
+ "noun form",
27
28
  "omit",
28
29
  "pick",
29
- "RWD",
30
30
  "Responsive Web Design",
31
+ "RWD",
31
32
  "SVG",
33
+ "tokenize",
34
+ "tokenizer",
32
35
  "typography",
33
36
  "uuid",
34
37
  "uuidv1"
@@ -38,5 +41,5 @@
38
41
  "name": "@jackens/nnn",
39
42
  "type": "module",
40
43
  "types": "nnn.d.ts",
41
- "version": "2025.12.13"
44
+ "version": "2025.12.23"
42
45
  }
package/readme.md CHANGED
@@ -35,7 +35,6 @@ import { «something» } from './node_modules/@jackens/nnn/nnn.js'
35
35
  - [`HArgs1`](#HArgs1): Single argument type for the [`h`](#h) and [`s`](#s) helpers.
36
36
  - [`c`](#c): A minimal CSS-in-JS helper that converts a JavaScript object hierarchy into a CSS string.
37
37
  - [`csv_parse`](#csv_parse): Parses a CSV string into a two-dimensional array of strings.
38
- - [`escape`](#escape): Escapes interpolated values in a tagged template literal using the provided escape map.
39
38
  - [`escape_values`](#escape_values): Escapes an array of values using the provided escape map.
40
39
  - [`fix_typography`](#fix_typography): Applies Polish-specific typographic corrections to a DOM subtree.
41
40
  - [`h`](#h): A lightweight [HyperScript](https://github.com/hyperhype/hyperscript)-style helper
@@ -46,11 +45,13 @@ import { «something» } from './node_modules/@jackens/nnn/nnn.js'
46
45
  - [`is_record`](#is_record): Checks whether the argument is a plain object (not `null` and not an array).
47
46
  - [`is_string`](#is_string): Checks whether the argument is a string.
48
47
  - [`js_on_parse`](#js_on_parse): Parses JSON with support for handler-based value transformation (“JavaScript ON”).
48
+ - [`monokai`](#monokai): A Monokai-inspired color scheme for use with the [`c`](#c) helper and [`nanolight_ts`](#nanolight_ts) tokenizer.
49
49
  - [`nanolight_ts`](#nanolight_ts): A TypeScript/JavaScript syntax highlighting tokenizer built using [`new_tokenizer`](#new_tokenizer).
50
+ - [`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 Polish noun form based on a numeric value.
50
52
  - [`new_tokenizer`](#new_tokenizer): A helper for building simple tokenizers (see also [`nanolight_ts`](#nanolight_ts)).
51
53
  - [`omit`](#omit): Creates a new object excluding the specified keys from the source object.
52
54
  - [`pick`](#pick): Creates a new object containing only the specified keys from the source object.
53
- - [`pl_ural`](#pl_ural): Returns the appropriate Polish noun form based on a numeric value.
54
55
  - [`pro`](#pro): A Proxy-based helper for auto-vivification of nested object structures.
55
56
  - [`rwd`](#rwd): A responsive web design helper that generates CSS rules for a grid-like layout.
56
57
  - [`s`](#s): A lightweight [HyperScript](https://github.com/hyperhype/hyperscript)-style helper
@@ -83,7 +84,7 @@ type EscapeMap = Map<unknown, (value?: unknown) => string>;
83
84
 
84
85
  A map from value constructors (or `null`/`undefined`) to escape functions.
85
86
 
86
- Used by [`escape_values`](#escape_values) and [`escape`](#escape).
87
+ Used by [`escape_values`](#escape_values) and [`new_escape`](#new_escape).
87
88
 
88
89
  ### HArgs
89
90
 
@@ -368,58 +369,6 @@ expect(csv_parse(text)).to.deep.equal([
368
369
  ])
369
370
  ```
370
371
 
371
- ### escape
372
-
373
- ```ts
374
- const escape: (escape_map: EscapeMap, template: TemplateStringsArray, ...values: unknown[]) => string;
375
- ```
376
-
377
- Escapes interpolated values in a tagged template literal using the provided escape map.
378
-
379
- #### escape_map
380
-
381
- A map where keys are constructors and values are escape functions.
382
-
383
- #### template
384
-
385
- The template strings array from the tagged template.
386
-
387
- #### values
388
-
389
- The interpolated values to escape.
390
-
391
- #### Returns
392
-
393
- The resulting string with all interpolated values escaped.
394
-
395
- #### Usage Examples
396
-
397
- ```ts
398
- const escape_map: EscapeMap = new Map([
399
- [null, () => 'NULL'],
400
- [undefined, () => 'NULL'],
401
- [Array, (values: unknown[]) => escape_values(escape_map, values).join(', ')],
402
- [Boolean, (value: boolean) => `b'${+value}'`],
403
- [Date, (value: Date) => `'${value.toISOString().replace(/^(.+)T(.+)\..*$/, '$1 $2')}'`],
404
- [Number, (value: number) => `${value}`],
405
- [String, (value: string) => `'${value.replace(/'/g, "''")}'`]
406
- ])
407
-
408
- const sql = escape.bind(null, escape_map)
409
-
410
- const actual = sql`
411
- SELECT *
412
- FROM table_name
413
- WHERE column_name IN (${[true, null, undefined, 42, '42', "4'2", /42/, new Date(323325000000)]})`
414
-
415
- const expected = `
416
- SELECT *
417
- FROM table_name
418
- WHERE column_name IN (b'1', NULL, NULL, 42, '42', '4''2', NULL, '1980-03-31 04:30:00')`
419
-
420
- expect(actual).to.deep.equal(expected)
421
- ```
422
-
423
372
  ### escape_values
424
373
 
425
374
  ```ts
@@ -833,6 +782,23 @@ const expected = [
833
782
  expect(actual).to.deep.equal(expected)
834
783
  ```
835
784
 
785
+ ### monokai
786
+
787
+ ```ts
788
+ const monokai: CRoot;
789
+ ```
790
+
791
+ A Monokai-inspired color scheme for use with the [`c`](#c) helper and [`nanolight_ts`](#nanolight_ts) tokenizer.
792
+
793
+ Defines CSS custom properties for eight colors (`--black`, `--blue`, `--green`, `--grey`,
794
+ `--purple`, `--red`, `--white`, `--yellow`) with both light and dark mode variants.
795
+
796
+ #### Remarks
797
+
798
+ - In light mode, `--black` is a light background and `--white` is dark text.
799
+ - In dark mode (via `prefers-color-scheme: dark`), the palette inverts to a dark background with light text.
800
+ - Includes base styles for `body`, `pre` and `code>span.*` (syntax highlighting).
801
+
836
802
  ### nanolight_ts
837
803
 
838
804
  ```ts
@@ -847,7 +813,7 @@ The source code string to tokenize.
847
813
 
848
814
  #### Returns
849
815
 
850
- An array of [`HArgs1`](#HArgs1) elements suitable for rendering with [`h`](#h) or [`s`](#s).
816
+ An array of [`HArgs1`](#HArgs1) elements suitable for rendering with [`h`](#h).
851
817
 
852
818
  #### Usage Examples
853
819
 
@@ -877,6 +843,97 @@ expect(nanolight_ts(code_js)).to.deep.equal([
877
843
  ])
878
844
  ```
879
845
 
846
+ ### new_escape
847
+
848
+ ```ts
849
+ const new_escape: (escape_map: EscapeMap) => (template: TemplateStringsArray, ...values: unknown[]) => string;
850
+ ```
851
+
852
+ Creates a tag function for escaping interpolated values in template literals.
853
+
854
+ #### escape_map
855
+
856
+ A map where keys are constructors and values are escape functions.
857
+
858
+ #### Returns
859
+
860
+ A tag function that escapes interpolated values using the provided escape map.
861
+
862
+ #### Usage Examples
863
+
864
+ ```ts
865
+ const escape_map: EscapeMap = new Map([
866
+ [null, () => 'NULL'],
867
+ [undefined, () => 'NULL'],
868
+ [Array, (values: unknown[]) => escape_values(escape_map, values).join(', ')],
869
+ [Boolean, (value: boolean) => `b'${+value}'`],
870
+ [Date, (value: Date) => `'${value.toISOString().replace(/^(.+)T(.+)\..*$/, '$1 $2')}'`],
871
+ [Number, (value: number) => `${value}`],
872
+ [String, (value: string) => `'${value.replace(/'/g, "''")}'`]
873
+ ])
874
+
875
+ const sql = new_escape(escape_map)
876
+
877
+ const actual = sql`
878
+ SELECT *
879
+ FROM table_name
880
+ WHERE column_name IN (${[true, null, undefined, 42, '42', "4'2", /42/, new Date(323325000000)]})`
881
+
882
+ const expected = `
883
+ SELECT *
884
+ FROM table_name
885
+ WHERE column_name IN (b'1', NULL, NULL, 42, '42', '4''2', NULL, '1980-03-31 04:30:00')`
886
+
887
+ expect(actual).to.deep.equal(expected)
888
+ ```
889
+
890
+ ### new_noun_form
891
+
892
+ ```ts
893
+ const new_noun_form: (singular: string, plural_2: string, plural_5: string) => (value: number) => string;
894
+ ```
895
+
896
+ Creates a function that returns the appropriate Polish noun form based on a numeric value.
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.
902
+
903
+ #### singular
904
+
905
+ The singular form (e.g., “auto” for “car”).
906
+
907
+ #### plural_2
908
+
909
+ The form for 2, 3, 4 (e.g., “auta”).
910
+
911
+ #### plural_5
912
+
913
+ The form for 5+ (e.g., “aut”).
914
+
915
+ #### Returns
916
+
917
+ A function that takes a numeric value and returns the appropriate noun form.
918
+
919
+ #### Usage Examples
920
+
921
+ ```ts
922
+ const auto = new_noun_form('auto', 'auta', 'aut')
923
+
924
+ expect(auto(0)).to.deep.equal('aut')
925
+ expect(auto(1)).to.deep.equal('auto')
926
+ expect(auto(17)).to.deep.equal('aut')
927
+ expect(auto(42)).to.deep.equal('auta')
928
+
929
+ const car = new_noun_form('car', 'cars', 'cars')
930
+
931
+ expect(car(0)).to.deep.equal('cars')
932
+ expect(car(1)).to.deep.equal('car')
933
+ expect(car(17)).to.deep.equal('cars')
934
+ expect(car(42)).to.deep.equal('cars')
935
+ ```
936
+
880
937
  ### new_tokenizer
881
938
 
882
939
  ```ts
@@ -967,57 +1024,6 @@ const obj = { a: 42, b: '42', c: 17 }
967
1024
  expect(pick(obj, ['a', 'b'])).to.deep.equal({ a: 42, b: '42' })
968
1025
  ```
969
1026
 
970
- ### pl_ural
971
-
972
- ```ts
973
- const pl_ural: (singular: string, plural_2: string, plural_5: string, value: number) => string;
974
- ```
975
-
976
- Returns the appropriate Polish noun form based on a numeric value.
977
-
978
- Polish has three plural forms depending on the number:
979
- - Singular: used for exactly 1.
980
- - “Plural 2-4”: used for 2, 3, 4, 22, 23, 24, etc. (but not 12, 13, 14).
981
- - “Plural 5+”: used for 0, 5–21, 25–31, etc.
982
-
983
- #### singular
984
-
985
- The singular form (e.g., “auto” for “car”).
986
-
987
- #### plural_2
988
-
989
- The form for 2, 3, 4 (e.g., “auta”).
990
-
991
- #### plural_5
992
-
993
- The form for 5+ (e.g., “aut”).
994
-
995
- #### value
996
-
997
- The numeric value to evaluate.
998
-
999
- #### Returns
1000
-
1001
- The appropriate noun form for the given value.
1002
-
1003
- #### Usage Examples
1004
-
1005
- ```ts
1006
- const auto = pl_ural.bind(null, 'auto', 'auta', 'aut')
1007
-
1008
- expect(auto(0)).to.deep.equal('aut')
1009
- expect(auto(1)).to.deep.equal('auto')
1010
- expect(auto(17)).to.deep.equal('aut')
1011
- expect(auto(42)).to.deep.equal('auta')
1012
-
1013
- const car = pl_ural.bind(null, 'car', 'cars', 'cars')
1014
-
1015
- expect(car(0)).to.deep.equal('cars')
1016
- expect(car(1)).to.deep.equal('car')
1017
- expect(car(17)).to.deep.equal('cars')
1018
- expect(car(42)).to.deep.equal('cars')
1019
- ```
1020
-
1021
1027
  ### pro
1022
1028
 
1023
1029
  ```ts