@jackens/nnn 2025.12.10 → 2025.12.11

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 +389 -79
  2. package/nnn.js +5 -5
  3. package/package.json +1 -1
  4. package/readme.md +382 -108
package/nnn.d.ts CHANGED
@@ -1,20 +1,34 @@
1
- /** Argument type for the `h` and `s` helpers. */
1
+ /**
2
+ * Single argument type for the {@link h} and {@link s} helpers.
3
+ */
2
4
  export type HArgs1 = Record<PropertyKey, unknown> | null | undefined | Node | string | number | HArgs;
3
- /** Argument type for the `h` and `s` helpers. */
5
+ /**
6
+ * Tuple argument type for the {@link h} and {@link s} helpers.
7
+ */
4
8
  export type HArgs = [string | Node, ...HArgs1[]];
5
9
  /**
6
- * A lightweight [HyperScript](https://github.com/hyperhype/hyperscript)-style helper for creating and modifying `HTMLElement`s (see also `s`).
10
+ * A lightweight [HyperScript](https://github.com/hyperhype/hyperscript)-style helper
11
+ * for creating and modifying `HTMLElement`s (see also {@link s}).
12
+ *
13
+ * @param tag_or_node
14
+ *
15
+ * If a `string`, it is treated as the tag name for a new element.
16
+ * If a `Node`, that node is modified in place.
7
17
  *
8
- * - If the first argument is a `string`, it is treated as the tag name to create.
9
- * - If the first argument is a `Node`, that node is modified.
10
- * - Object arguments map attributes/properties:
11
- * - Keys starting with `$` set element properties (without `$`).
12
- * - Other keys set attributes via `setAttribute`.
13
- * - Attributes with value `false` are removed via `removeAttribute`.
14
- * - `null` / `undefined` are ignored.
15
- * - `Node` arguments are appended.
16
- * - `string` / `number` arguments become `Text` nodes.
17
- * - `HArgs` arrays are processed recursively.
18
+ * @param args
19
+ *
20
+ * Additional arguments processed as follows:
21
+ * - `Object`: Maps attributes/properties. Keys starting with `$` set element properties
22
+ * (without the `$` prefix); other keys set attributes via `setAttribute`.
23
+ * A value of `false` removes the attribute.
24
+ * - `null` / `undefined`: Ignored.
25
+ * - `Node`: Appended as a child.
26
+ * - `string` / `number`: Converted to a `Text` node and appended.
27
+ * - {@link HArgs} array: Processed recursively.
28
+ *
29
+ * @returns
30
+ *
31
+ * The created or modified `HTMLElement`.
18
32
  */
19
33
  export declare const h: {
20
34
  <T extends keyof HTMLElementTagNameMap>(tag: T, ...args1: HArgs1[]): HTMLElementTagNameMap[T];
@@ -22,122 +36,418 @@ export declare const h: {
22
36
  (tag_or_node: string | Node, ...args1: HArgs1[]): Node;
23
37
  };
24
38
  /**
25
- * A lightweight [HyperScript](https://github.com/hyperhype/hyperscript)-style helper for creating and modifying `SVGElement`s (see also `h`).
39
+ * A lightweight [HyperScript](https://github.com/hyperhype/hyperscript)-style helper
40
+ * for creating and modifying `SVGElement`s (see also {@link h}).
41
+ *
42
+ * @param tag_or_node
43
+ *
44
+ * If a `string`, it is treated as the tag name for a new element.
45
+ * If a `Node`, that node is modified in place.
26
46
  *
27
- * - If the first argument is a `string`, it is treated as the tag name to create.
28
- * - If the first argument is a `Node`, that node is modified.
29
- * - Object arguments map attributes/properties:
30
- * - Keys starting with `$` set element properties (without `$`).
31
- * - Other keys set attributes via `setAttributeNS`.
32
- * - Attributes with value `false` are removed via `removeAttributeNS`.
33
- * - `null` / `undefined` are ignored.
34
- * - `Node` arguments are appended.
35
- * - `string` / `number` arguments become `Text` nodes.
36
- * - `HArgs` arrays are processed recursively.
47
+ * @param args
48
+ *
49
+ * Additional arguments processed as follows:
50
+ * - `Object`: Maps attributes/properties. Keys starting with `$` set element properties
51
+ * (without the `$` prefix); other keys set attributes via `setAttributeNS`.
52
+ * A value of `false` removes the attribute.
53
+ * - `null` / `undefined`: Ignored.
54
+ * - `Node`: Appended as a child.
55
+ * - `string` / `number`: Converted to a `Text` node and appended.
56
+ * - {@link HArgs} array: Processed recursively.
57
+ *
58
+ * @returns
59
+ *
60
+ * The created or modified `SVGElement`.
37
61
  */
38
62
  export declare const s: {
39
63
  <T extends keyof SVGElementTagNameMap>(tag: T, ...args1: HArgs1[]): SVGElementTagNameMap[T];
40
64
  <N extends Node>(node: N, ...args1: HArgs1[]): N;
41
65
  (tag_or_node: string | Node, ...args1: HArgs1[]): Node;
42
66
  };
43
- /** Shorthand for: `s('svg', ['use', { 'xlink:href': '#' + id }], ...args)`. */
67
+ /**
68
+ * Shorthand for creating an SVG element with a `<use>` child referencing an icon by ID.
69
+ *
70
+ * Equivalent to: `s('svg', ['use', { 'xlink:href': '#' + id }], ...args)`.
71
+ *
72
+ * @param id
73
+ *
74
+ * The ID of the symbol to reference (without the `#` prefix).
75
+ *
76
+ * @param args
77
+ *
78
+ * Additional arguments passed to the outer `<svg>` element.
79
+ *
80
+ * @returns
81
+ *
82
+ * An `SVGSVGElement` containing a `<use>` element.
83
+ */
44
84
  export declare const svg_use: (id: string, ...args: HArgs1[]) => SVGSVGElement;
45
85
  /**
46
- * Generic syntax highlighting helper (see also `nanolight_ts`).
86
+ * A helper for building simple tokenizers (see also {@link nanolight_ts}).
87
+ *
88
+ * @param decorator
89
+ *
90
+ * A function that wraps each matched chunk. It receives the matched text (`chunk`)
91
+ * and optionally the `metadata` associated with the pattern that produced the match.
92
+ * For unmatched text between patterns, `metadata` is `undefined`.
93
+ *
94
+ * @param specs
95
+ *
96
+ * An array of tuples `[metadata, pattern]` where:
97
+ * - `metadata`: Arbitrary data (e.g., a CSS class name) passed to `decorator` when the pattern matches.
98
+ * - `pattern`: A `string` or `RegExp` to match against the input.
99
+ *
100
+ * @returns
101
+ *
102
+ * A tokenizer function that accepts a code string and returns an array of decorated tokens.
103
+ *
104
+ * @remarks
105
+ *
106
+ * 1. Matches starting at an earlier position take precedence.
107
+ * 2. Among matches at the same position, the longer one wins.
108
+ * 3. Among matches of the same position and length, the one defined earlier wins.
109
+ */
110
+ export declare const new_tokenizer: <M, T>(decorator: (chunk: string, metadata?: M) => T, ...specs: [M, string | RegExp][]) => (code: string) => T[];
111
+ /**
112
+ * A TypeScript/JavaScript syntax highlighting tokenizer built using {@link new_tokenizer}.
47
113
  *
48
- * - `decorator` is a function that wraps each matched chunk.
49
- * It receives the matched text (`chunk`) and optionally the `metadata` associated with the pattern that produced the match.
50
- * For unmatched text between patterns, `metadata` is `undefined`.
51
- * - `rules` is an array of tuples `[metadata, pattern]` where:
52
- * - `metadata`: data (e.g. CSS class name) passed to the `decorator` when the pattern matches.
53
- * - `pattern`: a `string` or `RegExp` to match against the code.
114
+ * @param code
54
115
  *
55
- * Matching rules:
56
- * - For any two matches at different positions, the one starting earlier takes precedence.
57
- * - For any two matches at the same position, the longer one takes precedence.
58
- * - For any two matches at the same position and of the same length, the one defined earlier takes precedence.
116
+ * The source code string to tokenize.
117
+ *
118
+ * @returns
119
+ *
120
+ * An array of {@link HArgs1} elements suitable for rendering with {@link h} or {@link s}.
59
121
  */
60
- export declare const nanolight: <M, T>(decorator: (chunk: string, metadata?: M) => T, ...rules: [M, string | RegExp][]) => (code: string) => T[];
61
- /** TypeScript syntax highlighting helper (built on `nanolight`). */
62
122
  export declare const nanolight_ts: (code: string) => HArgs1[];
63
- /** Applies Polish‑specific typographic corrections. */
123
+ /**
124
+ * Applies Polish-specific typographic corrections to a DOM subtree.
125
+ *
126
+ * This function prevents orphaned conjunctions (single-letter words like “a”, “i”, “o”, “u”, “w”, “z”)
127
+ * from appearing at the end of a line by wrapping them with the following word in a non-breaking span.
128
+ * It also inserts zero-width spaces after slashes and dots to allow line breaks.
129
+ *
130
+ * @param node
131
+ *
132
+ * The root DOM node to process. All descendant text nodes are corrected recursively,
133
+ * except those inside `IFRAME`, `NOSCRIPT`, `PRE`, `SCRIPT`, `STYLE`, or `TEXTAREA` elements.
134
+ */
64
135
  export declare const fix_typography: (node: Node) => void;
65
- /** Argument type for the `c` helper. */
136
+ /**
137
+ * Represents a CSS rule node for the {@link c} helper. Keys are CSS properties or nested selectors.
138
+ */
66
139
  export type CNode = {
67
140
  [attribute_or_selector: string]: string | number | CNode | undefined;
68
141
  };
69
- /** Argument type for the `c` helper. */
142
+ /**
143
+ * Represents the root CSS object for the {@link c} helper. Keys are top-level selectors or at-rules.
144
+ */
70
145
  export type CRoot = Record<PropertyKey, CNode>;
71
146
  /**
72
- * A minimal JS-to-CSS (CSS‑in‑JS) helper.
147
+ * A minimal CSS-in-JS helper that converts a JavaScript object hierarchy into a CSS string.
73
148
  *
74
- * The `root` object describes a hierarchy of CSS rules.
149
+ * @param root
75
150
  *
76
- * - Keys whose values are not objects are treated as CSS property names; their values become property values. The concatenation of parent keys produces a selector.
77
- * - For every key, the substring from the splitter (default: `$$`) to the end is ignored (e.g. `src$$1` → `src`, `@font-face$$1` → `@font-face`).
78
- * - In property keys, uppercase letters are converted to lowercase and prefixed with `-` (e.g. `fontFamily` → `font-family`); underscores are converted to `-` (e.g. `font_family` → `font-family`).
79
- * - Commas inside selector keys cause them to expand into multiple selectors (e.g. `{div:{margin:1,'.a,.b,.c':{margin:2}}}` → `div{margin:1}div.a,div.b,div.c{margin:2}`).
80
- * - Top-level keys beginning with `@` (at-rules) are not concatenated with parent keys.
151
+ * An object describing CSS rules.
152
+ * Keys are selectors or at-rules; values are either CSS property values or nested rule objects.
153
+ *
154
+ * @param splitter
155
+ *
156
+ * A delimiter used to create unique keys (default: `'$$'`).
157
+ * The substring from `splitter` to the end of a key is ignored (e.g., `src$$1` → `src`).
158
+ *
159
+ * @returns
160
+ *
161
+ * A CSS string representing the compiled rules.
162
+ *
163
+ * @remarks
164
+ *
165
+ * - Keys whose values are primitives (`string` | `number`) are treated as CSS properties.
166
+ * - In property keys, uppercase letters become lowercase with a `-` prefix (e.g., `fontFamily` → `font-family`);
167
+ * underscores become hyphens (e.g., `font_family` → `font-family`).
168
+ * - Comma-separated selector keys expand into multiple selectors
169
+ * (e.g., `{ div: { '.a,.b': { margin: 1 } } }` → `div.a,div.b{margin:1}`).
170
+ * - Top-level keys starting with `@` (at-rules) are not concatenated with child selectors.
81
171
  */
82
172
  export declare const c: (root: CRoot, splitter?: string) => string;
83
173
  /**
84
- * A responsivewebdesign helper that generates CSS rules for a grid-like layout.
174
+ * A responsive web design helper that generates CSS rules for a grid-like layout.
175
+ *
176
+ * @param root
177
+ *
178
+ * The CSS root object to populate (see {@link c}).
179
+ *
180
+ * @param selector
181
+ *
182
+ * The CSS selector for the grid item.
183
+ *
184
+ * @param cell_width_px
85
185
  *
86
- * - `root` and `selector` specify where to apply the generated rules (see `c`).
87
- * - `cell_width_px` and `cell_height_px` specify the base cell dimensions in pixels.
88
- * - Each entry in `specs` is a tuple of:
89
- * - `max_width`: maximum number of cells in a row (viewport width breakpoint).
90
- * - `width` (optional, default: `1`): number of cells occupied by the element.
91
- * - `height` (optional, default: `1`): number of cells the element occupies vertically.
186
+ * The base cell width in pixels.
187
+ *
188
+ * @param cell_height_px
189
+ *
190
+ * The base cell height in pixels.
191
+ *
192
+ * @param specs
193
+ *
194
+ * An array of breakpoint specifications, each a tuple of:
195
+ * - `max_width`: Maximum number of cells per row (defines the viewport breakpoint).
196
+ * - `width` (optional, default `1`): Number of horizontal cells the element spans.
197
+ * - `height` (optional, default `1`): Number of vertical cells the element spans.
92
198
  */
93
199
  export declare const rwd: (root: CRoot, selector: string, cell_width_px: number, cell_height_px: number, ...specs: [number, number?, number?][]) => void;
94
- /** Argument type accepted by the `escape_values` and `escape` helpers. */
200
+ /**
201
+ * A map from value constructors (or `null`/`undefined`) to escape functions.
202
+ *
203
+ * Used by {@link escape_values} and {@link escape}.
204
+ */
95
205
  export type EscapeMap = Map<unknown, (value?: unknown) => string>;
96
- /** Escapes array `values` using the provided `escape_map`. */
206
+ /**
207
+ * Escapes an array of values using the provided escape map.
208
+ *
209
+ * @param escape_map
210
+ *
211
+ * A map where keys are constructors (e.g., `String`, `Number`) and values are escape functions.
212
+ *
213
+ * @param values
214
+ *
215
+ * The array of values to escape.
216
+ *
217
+ * @returns
218
+ *
219
+ * An array of escaped strings.
220
+ */
97
221
  export declare const escape_values: (escape_map: EscapeMap, values: unknown[]) => string[];
98
- /** Escapes interpolated template `values` using the provided `escape_map`. */
222
+ /**
223
+ * Escapes interpolated values in a tagged template literal using the provided escape map.
224
+ *
225
+ * @param escape_map
226
+ *
227
+ * A map where keys are constructors and values are escape functions.
228
+ *
229
+ * @param template
230
+ *
231
+ * The template strings array from the tagged template.
232
+ *
233
+ * @param values
234
+ *
235
+ * The interpolated values to escape.
236
+ *
237
+ * @returns
238
+ *
239
+ * The resulting string with all interpolated values escaped.
240
+ */
99
241
  export declare const escape: (escape_map: EscapeMap, template: TemplateStringsArray, ...values: unknown[]) => string;
100
- /** Chooses the appropriate Polish noun form based on a numeric value. */
242
+ /**
243
+ * Returns the appropriate Polish noun form based on a numeric value.
244
+ *
245
+ * Polish has three plural forms depending on the number:
246
+ * - Singular: used for exactly 1.
247
+ * - “Plural 2-4”: used for 2, 3, 4, 22, 23, 24, etc. (but not 12, 13, 14).
248
+ * - “Plural 5+”: used for 0, 5–21, 25–31, etc.
249
+ *
250
+ * @param singular
251
+ *
252
+ * The singular form (e.g., ”auto” for “car”).
253
+ *
254
+ * @param plural_2
255
+ *
256
+ * The form for 2, 3, 4 (e.g., “auta”).
257
+ *
258
+ * @param plural_5
259
+ *
260
+ * The form for 5+ (e.g., “aut”).
261
+ *
262
+ * @param value
263
+ *
264
+ * The numeric value to evaluate.
265
+ *
266
+ * @returns
267
+ *
268
+ * The appropriate noun form for the given value.
269
+ */
101
270
  export declare const pl_ural: (singular: string, plural_2: string, plural_5: string, value: number) => string;
102
271
  /**
103
272
  * Generates a UUID v1 (time-based) identifier.
104
273
  *
105
- * - Optional `node` must match `/^[0-9a-f]*$/`; it is trimmed to the last 12 characters and left-padded with zeros.
274
+ * @param date
275
+ *
276
+ * The date to use for the timestamp portion (default: current date/time).
277
+ *
278
+ * @param node
279
+ *
280
+ * A hexadecimal `string` for the node portion (default: random).
281
+ * Must match `/^[0-9a-f]*$/`; it is trimmed to the last 12 characters and left-padded with zeros if shorter.
282
+ *
283
+ * @returns
284
+ *
285
+ * A UUID v1 `string` in the standard format `xxxxxxxx-xxxx-1xxx-xxxx-xxxxxxxxxxxx`.
106
286
  */
107
287
  export declare const uuid_v1: (date?: Date, node?: string) => string;
108
288
  /**
109
- * `JSON.parse` with “JavaScript turned on”.
289
+ * Parses JSON with support for handler-based value transformation (“JavaScript ON”).
110
290
  *
111
- * Objects having *exactly* one property whose name exists in `handlers`, i.e.:
291
+ * Objects with exactly one property whose key exists in `handlers` and whose value is an array
292
+ * are replaced by invoking the corresponding handler with the array elements as arguments.
112
293
  *
113
- * ```js
114
- * { "«handler_name»": [«params»] }
115
- * ```
294
+ * @param handlers
116
295
  *
117
- * are replaced with:
296
+ * An object mapping handler names to functions.
118
297
  *
119
- * ```js
120
- * handlers['«handler_name»'](...«params»)
121
- * ```
298
+ * @param text
299
+ *
300
+ * The JSON string to parse.
301
+ *
302
+ * @returns
303
+ *
304
+ * The parsed value with handler substitutions applied.
122
305
  */
123
306
  export declare const js_on_parse: (handlers: Record<PropertyKey, Function>, text: string) => any;
124
- /** Checks whether the argument is an array. */
307
+ /**
308
+ * Checks whether the argument is an array.
309
+ *
310
+ * @param arg
311
+ *
312
+ * The value to check.
313
+ *
314
+ * @returns
315
+ *
316
+ * `true` if `arg` is an array, `false` otherwise.
317
+ */
125
318
  export declare const is_array: (arg: unknown) => arg is unknown[];
126
- /** Checks whether the argument is a finite number (excluding `±Infinity` and `NaN`). */
319
+ /**
320
+ * Checks whether the argument is a finite number (excludes `±Infinity` and `NaN`).
321
+ *
322
+ * @param arg
323
+ *
324
+ * The value to check.
325
+ *
326
+ * @returns
327
+ *
328
+ * `true` if `arg` is a finite number, `false` otherwise.
329
+ */
127
330
  export declare const is_finite_number: (arg: unknown) => arg is number;
128
- /** Checks whether the argument is a number. */
331
+ /**
332
+ * Checks whether the argument is of type `number` (includes `NaN` and `±Infinity`).
333
+ *
334
+ * @param arg
335
+ *
336
+ * The value to check.
337
+ *
338
+ * @returns
339
+ *
340
+ * `true` if `typeof arg === 'number'`, `false` otherwise.
341
+ */
129
342
  export declare const is_number: (arg: unknown) => arg is number;
130
- /** Checks whether the argument is a plain object record. */
343
+ /**
344
+ * Checks whether the argument is a plain object (not `null` and not an array).
345
+ *
346
+ * @param arg
347
+ *
348
+ * The value to check.
349
+ *
350
+ * @returns
351
+ *
352
+ * `true` if `arg` is a plain object, `false` otherwise.
353
+ */
131
354
  export declare const is_record: (arg: unknown) => arg is Record<PropertyKey, unknown>;
132
- /** Checks whether the argument is a string. */
355
+ /**
356
+ * Checks whether the argument is a string.
357
+ *
358
+ * @param arg
359
+ *
360
+ * The value to check.
361
+ *
362
+ * @returns
363
+ *
364
+ * `true` if `typeof arg === 'string'`, `false` otherwise.
365
+ */
133
366
  export declare const is_string: (arg: unknown) => arg is string;
134
- /** A replacement for the `in` operator (not to be confused with `for-in`). */
367
+ /**
368
+ * Checks whether an object has the specified key as its own property.
369
+ *
370
+ * A null-safe wrapper around `Object.hasOwn`.
371
+ *
372
+ * @param ref
373
+ *
374
+ * The object to check.
375
+ *
376
+ * @param key
377
+ *
378
+ * The property key to look for.
379
+ *
380
+ * @returns
381
+ *
382
+ * `true` if `ref` is not nullish and has `key` as an own property, `false` otherwise.
383
+ */
135
384
  export declare const has_own: (ref: unknown, key: unknown) => boolean;
136
- /** A `Proxy`-based helper that safely creates nested structures on access and allows deep assignment without guards. */
385
+ /**
386
+ * A Proxy-based helper for auto-vivification of nested object structures.
387
+ *
388
+ * Accessing any property on the returned proxy automatically creates an empty object if the property does not exist,
389
+ * allowing deep assignments without explicit null checks.
390
+ *
391
+ * @param ref
392
+ *
393
+ * The root object to wrap.
394
+ *
395
+ * @returns
396
+ *
397
+ * A proxy that auto-creates nested objects on property access.
398
+ */
137
399
  export declare const pro: (ref: unknown) => any;
138
- /** A tiny CSV parsing helper. */
400
+ /**
401
+ * Parses a CSV string into a two-dimensional array of strings.
402
+ *
403
+ * Supports quoted fields with escaped double quotes (`""`). Carriage returns are normalized.
404
+ *
405
+ * @param csv
406
+ *
407
+ * The CSV string to parse.
408
+ *
409
+ * @param separator
410
+ *
411
+ * The field delimiter (default: `','`).
412
+ *
413
+ * @returns
414
+ *
415
+ * A 2D array where each inner array represents a row of fields.
416
+ */
139
417
  export declare const csv_parse: (csv: string, separator?: string) => string[][];
140
- /** Runtime implementation of TypeScript’s `Pick` (see also `omit`). */
418
+ /**
419
+ * Creates a new object containing only the specified keys from the source object.
420
+ *
421
+ * A runtime equivalent of TypeScript’s `Pick<T, K>` utility type. See also {@link omit}.
422
+ *
423
+ * @param ref
424
+ *
425
+ * The source object.
426
+ *
427
+ * @param keys
428
+ *
429
+ * An array of keys to include in the result.
430
+ *
431
+ * @returns
432
+ *
433
+ * A new object with only the specified keys.
434
+ */
141
435
  export declare const pick: <T, K extends keyof T>(ref: T, keys: K[]) => Pick<T, K>;
142
- /** Runtime implementation of TypeScript’s `Omit` (see also `pick`). */
436
+ /**
437
+ * Creates a new object excluding the specified keys from the source object.
438
+ *
439
+ * A runtime equivalent of TypeScript’s `Omit<T, K>` utility type. See also {@link pick}.
440
+ *
441
+ * @param ref
442
+ *
443
+ * The source object.
444
+ *
445
+ * @param keys
446
+ *
447
+ * An array of keys to exclude from the result.
448
+ *
449
+ * @returns
450
+ *
451
+ * A new object without the specified keys.
452
+ */
143
453
  export declare const omit: <T, K extends keyof T>(ref: T, keys: unknown[]) => Omit<T, K>;
package/nnn.js CHANGED
@@ -60,13 +60,13 @@ var _h = (namespace_uri) => {
60
60
  var h = _h();
61
61
  var s = _h("http://www.w3.org/2000/svg");
62
62
  var svg_use = (id, ...args) => s("svg", ["use", { "xlink:href": "#" + id }], ...args);
63
- var nanolight = (decorator, ...rules) => (code) => {
63
+ var new_tokenizer = (decorator, ...specs) => (code) => {
64
64
  const result = [];
65
65
  while (code.length > 0) {
66
66
  let best_metadata;
67
67
  let best_index = Infinity;
68
68
  let best_chunk = "";
69
- for (const [metadata, pattern] of rules) {
69
+ for (const [metadata, pattern] of specs) {
70
70
  let index = -1;
71
71
  let chunk = "";
72
72
  if (is_string(pattern) && pattern.length > 0) {
@@ -104,7 +104,7 @@ var PURPLE = "purple";
104
104
  var RED = "red";
105
105
  var WHITE = "white";
106
106
  var YELLOW = "yellow";
107
- var nanolight_ts = nanolight((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]+/]);
107
+ var nanolight_ts = 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]+/]);
108
108
  var TAGS_TO_SKIP = ["IFRAME", "NOSCRIPT", "PRE", "SCRIPT", "STYLE", "TEXTAREA"];
109
109
  var fix_typography = (node) => {
110
110
  const queue = [node];
@@ -208,7 +208,7 @@ var rwd = (root, selector, cell_width_px, cell_height_px, ...specs) => {
208
208
  node.height = `${cell_height_px * height}px`;
209
209
  }
210
210
  };
211
- var escape_values = (escape_map, values) => values.map((value) => (escape_map.get(value?.constructor) ?? escape_map.get(undefined))?.(value) ?? "");
211
+ var escape_values = (escape_map, values) => values.map((value) => (value == null ? escape_map.get(value) : escape_map.get(value?.constructor))?.(value) ?? "");
212
212
  var escape = (escape_map, template, ...values) => String.raw(template, ...escape_values(escape_map, values));
213
213
  var pl_ural = (singular, plural_2, plural_5, value) => {
214
214
  const abs_value = Math.abs(value);
@@ -266,8 +266,8 @@ export {
266
266
  pl_ural,
267
267
  pick,
268
268
  omit,
269
+ new_tokenizer,
269
270
  nanolight_ts,
270
- nanolight,
271
271
  js_on_parse,
272
272
  is_string,
273
273
  is_record,
package/package.json CHANGED
@@ -38,5 +38,5 @@
38
38
  "name": "@jackens/nnn",
39
39
  "type": "module",
40
40
  "types": "nnn.d.ts",
41
- "version": "2025.12.10"
41
+ "version": "2025.12.11"
42
42
  }
package/readme.md CHANGED
@@ -28,33 +28,33 @@ import { «something» } from './node_modules/@jackens/nnn/nnn.js'
28
28
 
29
29
  ## Exports
30
30
 
31
- - [`CNode`](#CNode): Argument type for the [`c`](#c) helper.
32
- - [`CRoot`](#CRoot): Argument type for the [`c`](#c) helper.
33
- - [`EscapeMap`](#EscapeMap): Argument type accepted by the [`escape_values`](#escape_values) and [`escape`](#escape) helpers.
34
- - [`HArgs`](#HArgs): Argument type for the [`h`](#h) and [`s`](#s) helpers.
35
- - [`HArgs1`](#HArgs1): Argument type for the [`h`](#h) and [`s`](#s) helpers.
36
- - [`c`](#c): A minimal JS-to-CSS (CSS‑in‑JS) helper.
37
- - [`csv_parse`](#csv_parse): A tiny CSV parsing helper.
38
- - [`escape`](#escape): Escapes interpolated template `values` using the provided `escape_map`.
39
- - [`escape_values`](#escape_values): Escapes array `values` using the provided `escape_map`.
40
- - [`fix_typography`](#fix_typography): Applies Polishspecific typographic corrections.
41
- - [`h`](#h): A lightweight [HyperScript](https://github.com/hyperhype/hyperscript)-style helper for creating and modifying `HTMLElement`s (see also [`s`](#s)).
42
- - [`has_own`](#has_own): A replacement for the `in` operator (not to be confused with `for-in`).
31
+ - [`CNode`](#CNode): Represents a CSS rule node for the [`c`](#c) helper. Keys are CSS properties or nested selectors.
32
+ - [`CRoot`](#CRoot): Represents the root CSS object for the [`c`](#c) helper. Keys are top-level selectors or at-rules.
33
+ - [`EscapeMap`](#EscapeMap): A map from value constructors (or `null`/`undefined`) to escape functions.
34
+ - [`HArgs`](#HArgs): Tuple argument type for the [`h`](#h) and [`s`](#s) helpers.
35
+ - [`HArgs1`](#HArgs1): Single argument type for the [`h`](#h) and [`s`](#s) helpers.
36
+ - [`c`](#c): A minimal CSS-in-JS helper that converts a JavaScript object hierarchy into a CSS string.
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
+ - [`escape_values`](#escape_values): Escapes an array of values using the provided escape map.
40
+ - [`fix_typography`](#fix_typography): Applies Polish-specific typographic corrections to a DOM subtree.
41
+ - [`h`](#h): A lightweight [HyperScript](https://github.com/hyperhype/hyperscript)-style helper
42
+ - [`has_own`](#has_own): Checks whether an object has the specified key as its own property.
43
43
  - [`is_array`](#is_array): Checks whether the argument is an array.
44
- - [`is_finite_number`](#is_finite_number): Checks whether the argument is a finite number (excluding `±Infinity` and `NaN`).
45
- - [`is_number`](#is_number): Checks whether the argument is a number.
46
- - [`is_record`](#is_record): Checks whether the argument is a plain object record.
44
+ - [`is_finite_number`](#is_finite_number): Checks whether the argument is a finite number (excludes `±Infinity` and `NaN`).
45
+ - [`is_number`](#is_number): Checks whether the argument is of type `number` (includes `NaN` and `±Infinity`).
46
+ - [`is_record`](#is_record): Checks whether the argument is a plain object (not `null` and not an array).
47
47
  - [`is_string`](#is_string): Checks whether the argument is a string.
48
- - [`js_on_parse`](#js_on_parse): `JSON.parse` with “JavaScript turned on”.
49
- - [`nanolight`](#nanolight): Generic syntax highlighting helper (see also [`nanolight_ts`](#nanolight_ts)).
50
- - [`nanolight_ts`](#nanolight_ts): TypeScript syntax highlighting helper (built on [`nanolight`](#nanolight)).
51
- - [`omit`](#omit): Runtime implementation of TypeScript’s `Omit` (see also [`pick`](#pick)).
52
- - [`pick`](#pick): Runtime implementation of TypeScript’s `Pick` (see also [`omit`](#omit)).
53
- - [`pl_ural`](#pl_ural): Chooses the appropriate Polish noun form based on a numeric value.
54
- - [`pro`](#pro): A `Proxy`-based helper that safely creates nested structures on access and allows deep assignment without guards.
55
- - [`rwd`](#rwd): A responsivewebdesign helper that generates CSS rules for a grid-like layout.
56
- - [`s`](#s): A lightweight [HyperScript](https://github.com/hyperhype/hyperscript)-style helper for creating and modifying `SVGElement`s (see also [`h`](#h)).
57
- - [`svg_use`](#svg_use): Shorthand for: `s('svg', ['use', { 'xlink:href': '#' + id }], ...args)`.
48
+ - [`js_on_parse`](#js_on_parse): Parses JSON with support for handler-based value transformation (“JavaScript ON”).
49
+ - [`nanolight_ts`](#nanolight_ts): A TypeScript/JavaScript syntax highlighting tokenizer built using [`new_tokenizer`](#new_tokenizer).
50
+ - [`new_tokenizer`](#new_tokenizer): A helper for building simple tokenizers (see also [`nanolight_ts`](#nanolight_ts)).
51
+ - [`omit`](#omit): Creates a new object excluding the specified keys from the source object.
52
+ - [`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
+ - [`pro`](#pro): A Proxy-based helper for auto-vivification of nested object structures.
55
+ - [`rwd`](#rwd): A responsive web design helper that generates CSS rules for a grid-like layout.
56
+ - [`s`](#s): A lightweight [HyperScript](https://github.com/hyperhype/hyperscript)-style helper
57
+ - [`svg_use`](#svg_use): Shorthand for creating an SVG element with a `<use>` child referencing an icon by ID.
58
58
  - [`uuid_v1`](#uuid_v1): Generates a UUID v1 (time-based) identifier.
59
59
 
60
60
  ### CNode
@@ -65,7 +65,7 @@ type CNode = {
65
65
  };
66
66
  ```
67
67
 
68
- Argument type for the [`c`](#c) helper.
68
+ Represents a CSS rule node for the [`c`](#c) helper. Keys are CSS properties or nested selectors.
69
69
 
70
70
  ### CRoot
71
71
 
@@ -73,7 +73,7 @@ Argument type for the [`c`](#c) helper.
73
73
  type CRoot = Record<PropertyKey, CNode>;
74
74
  ```
75
75
 
76
- Argument type for the [`c`](#c) helper.
76
+ Represents the root CSS object for the [`c`](#c) helper. Keys are top-level selectors or at-rules.
77
77
 
78
78
  ### EscapeMap
79
79
 
@@ -81,7 +81,9 @@ Argument type for the [`c`](#c) helper.
81
81
  type EscapeMap = Map<unknown, (value?: unknown) => string>;
82
82
  ```
83
83
 
84
- Argument type accepted by the [`escape_values`](#escape_values) and [`escape`](#escape) helpers.
84
+ A map from value constructors (or `null`/`undefined`) to escape functions.
85
+
86
+ Used by [`escape_values`](#escape_values) and [`escape`](#escape).
85
87
 
86
88
  ### HArgs
87
89
 
@@ -89,7 +91,7 @@ Argument type accepted by the [`escape_values`](#escape_values) and [`escape`](#
89
91
  type HArgs = [string | Node, ...HArgs1[]];
90
92
  ```
91
93
 
92
- Argument type for the [`h`](#h) and [`s`](#s) helpers.
94
+ Tuple argument type for the [`h`](#h) and [`s`](#s) helpers.
93
95
 
94
96
  ### HArgs1
95
97
 
@@ -97,7 +99,7 @@ Argument type for the [`h`](#h) and [`s`](#s) helpers.
97
99
  type HArgs1 = Record<PropertyKey, unknown> | null | undefined | Node | string | number | HArgs;
98
100
  ```
99
101
 
100
- Argument type for the [`h`](#h) and [`s`](#s) helpers.
102
+ Single argument type for the [`h`](#h) and [`s`](#s) helpers.
101
103
 
102
104
  ### c
103
105
 
@@ -105,15 +107,30 @@ Argument type for the [`h`](#h) and [`s`](#s) helpers.
105
107
  const c: (root: CRoot, splitter?: string) => string;
106
108
  ```
107
109
 
108
- A minimal JS-to-CSS (CSS‑in‑JS) helper.
110
+ A minimal CSS-in-JS helper that converts a JavaScript object hierarchy into a CSS string.
111
+
112
+ #### root
113
+
114
+ An object describing CSS rules.
115
+ Keys are selectors or at-rules; values are either CSS property values or nested rule objects.
116
+
117
+ #### splitter
118
+
119
+ A delimiter used to create unique keys (default: `'$$'`).
120
+ The substring from `splitter` to the end of a key is ignored (e.g., `src$$1` → `src`).
109
121
 
110
- The `root` object describes a hierarchy of CSS rules.
122
+ #### Returns
111
123
 
112
- - Keys whose values are not objects are treated as CSS property names; their values become property values. The concatenation of parent keys produces a selector.
113
- - For every key, the substring from the splitter (default: `$$`) to the end is ignored (e.g. `src$$1` → `src`, `@font-face$$1` → `@font-face`).
114
- - In property keys, uppercase letters are converted to lowercase and prefixed with `-` (e.g. `fontFamily` → `font-family`); underscores are converted to `-` (e.g. `font_family` → `font-family`).
115
- - Commas inside selector keys cause them to expand into multiple selectors (e.g. `{div:{margin:1,'.a,.b,.c':{margin:2}}}` → `div{margin:1}div.a,div.b,div.c{margin:2}`).
116
- - Top-level keys beginning with `@` (at-rules) are not concatenated with parent keys.
124
+ A CSS string representing the compiled rules.
125
+
126
+ #### Remarks
127
+
128
+ - Keys whose values are primitives (`string` | `number`) are treated as CSS properties.
129
+ - In property keys, uppercase letters become lowercase with a `-` prefix (e.g., `fontFamily` → `font-family`);
130
+ underscores become hyphens (e.g., `font_family` → `font-family`).
131
+ - Comma-separated selector keys expand into multiple selectors
132
+ (e.g., `{ div: { '.a,.b': { margin: 1 } } }` → `div.a,div.b{margin:1}`).
133
+ - Top-level keys starting with `@` (at-rules) are not concatenated with child selectors.
117
134
 
118
135
  #### Usage Examples
119
136
 
@@ -317,7 +334,21 @@ expect(actual).to.deep.equal(expected)
317
334
  const csv_parse: (csv: string, separator?: string) => string[][];
318
335
  ```
319
336
 
320
- A tiny CSV parsing helper.
337
+ Parses a CSV string into a two-dimensional array of strings.
338
+
339
+ Supports quoted fields with escaped double quotes (`""`). Carriage returns are normalized.
340
+
341
+ #### csv
342
+
343
+ The CSV string to parse.
344
+
345
+ #### separator
346
+
347
+ The field delimiter (default: `','`).
348
+
349
+ #### Returns
350
+
351
+ A 2D array where each inner array represents a row of fields.
321
352
 
322
353
  #### Usage Examples
323
354
 
@@ -343,12 +374,29 @@ expect(csv_parse(text)).to.deep.equal([
343
374
  const escape: (escape_map: EscapeMap, template: TemplateStringsArray, ...values: unknown[]) => string;
344
375
  ```
345
376
 
346
- Escapes interpolated template `values` using the provided `escape_map`.
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.
347
394
 
348
395
  #### Usage Examples
349
396
 
350
397
  ```ts
351
398
  const escape_map: EscapeMap = new Map([
399
+ [null, () => 'NULL'],
352
400
  [undefined, () => 'NULL'],
353
401
  [Array, (values: unknown[]) => escape_values(escape_map, values).join(', ')],
354
402
  [Boolean, (value: boolean) => `b'${+value}'`],
@@ -378,7 +426,19 @@ expect(actual).to.deep.equal(expected)
378
426
  const escape_values: (escape_map: EscapeMap, values: unknown[]) => string[];
379
427
  ```
380
428
 
381
- Escapes array `values` using the provided `escape_map`.
429
+ Escapes an array of values using the provided escape map.
430
+
431
+ #### escape_map
432
+
433
+ A map where keys are constructors (e.g., `String`, `Number`) and values are escape functions.
434
+
435
+ #### values
436
+
437
+ The array of values to escape.
438
+
439
+ #### Returns
440
+
441
+ An array of escaped strings.
382
442
 
383
443
  ### fix_typography
384
444
 
@@ -386,7 +446,16 @@ Escapes array `values` using the provided `escape_map`.
386
446
  const fix_typography: (node: Node) => void;
387
447
  ```
388
448
 
389
- Applies Polishspecific typographic corrections.
449
+ Applies Polish-specific typographic corrections to a DOM subtree.
450
+
451
+ This function prevents orphaned conjunctions (single-letter words like “a”, “i”, “o”, “u”, “w”, “z”)
452
+ from appearing at the end of a line by wrapping them with the following word in a non-breaking span.
453
+ It also inserts zero-width spaces after slashes and dots to allow line breaks.
454
+
455
+ #### node
456
+
457
+ The root DOM node to process. All descendant text nodes are corrected recursively,
458
+ except those inside `IFRAME`, `NOSCRIPT`, `PRE`, `SCRIPT`, `STYLE`, or `TEXTAREA` elements.
390
459
 
391
460
  #### Usage Examples
392
461
 
@@ -410,18 +479,28 @@ const h: {
410
479
  };
411
480
  ```
412
481
 
413
- A lightweight [HyperScript](https://github.com/hyperhype/hyperscript)-style helper for creating and modifying `HTMLElement`s (see also [`s`](#s)).
482
+ A lightweight [HyperScript](https://github.com/hyperhype/hyperscript)-style helper
483
+ for creating and modifying `HTMLElement`s (see also [`s`](#s)).
484
+
485
+ #### tag_or_node
486
+
487
+ If a `string`, it is treated as the tag name for a new element.
488
+ If a `Node`, that node is modified in place.
414
489
 
415
- - If the first argument is a `string`, it is treated as the tag name to create.
416
- - If the first argument is a `Node`, that node is modified.
417
- - Object arguments map attributes/properties:
418
- - Keys starting with `$` set element properties (without `$`).
419
- - Other keys set attributes via `setAttribute`.
420
- - Attributes with value `false` are removed via `removeAttribute`.
421
- - `null` / `undefined` are ignored.
422
- - `Node` arguments are appended.
423
- - `string` / `number` arguments become `Text` nodes.
424
- - [`HArgs`](#HArgs) arrays are processed recursively.
490
+ #### args
491
+
492
+ Additional arguments processed as follows:
493
+ - `Object`: Maps attributes/properties. Keys starting with `$` set element properties
494
+ (without the `$` prefix); other keys set attributes via `setAttribute`.
495
+ A value of `false` removes the attribute.
496
+ - `null` / `undefined`: Ignored.
497
+ - `Node`: Appended as a child.
498
+ - `string` / `number`: Converted to a `Text` node and appended.
499
+ - [`HArgs`](#HArgs) array: Processed recursively.
500
+
501
+ #### Returns
502
+
503
+ The created or modified `HTMLElement`.
425
504
 
426
505
  #### Usage Examples
427
506
 
@@ -502,7 +581,21 @@ expect(div.key).to.deep.equal({ one: 1, two: 2 })
502
581
  const has_own: (ref: unknown, key: unknown) => boolean;
503
582
  ```
504
583
 
505
- A replacement for the `in` operator (not to be confused with `for-in`).
584
+ Checks whether an object has the specified key as its own property.
585
+
586
+ A null-safe wrapper around `Object.hasOwn`.
587
+
588
+ #### ref
589
+
590
+ The object to check.
591
+
592
+ #### key
593
+
594
+ The property key to look for.
595
+
596
+ #### Returns
597
+
598
+ `true` if `ref` is not nullish and has `key` as an own property, `false` otherwise.
506
599
 
507
600
  #### Usage Examples
508
601
 
@@ -545,6 +638,14 @@ const is_array: (arg: unknown) => arg is unknown[];
545
638
 
546
639
  Checks whether the argument is an array.
547
640
 
641
+ #### arg
642
+
643
+ The value to check.
644
+
645
+ #### Returns
646
+
647
+ `true` if `arg` is an array, `false` otherwise.
648
+
548
649
  #### Usage Examples
549
650
 
550
651
  ```ts
@@ -557,7 +658,15 @@ expect(is_array([])).to.be.true
557
658
  const is_finite_number: (arg: unknown) => arg is number;
558
659
  ```
559
660
 
560
- Checks whether the argument is a finite number (excluding `±Infinity` and `NaN`).
661
+ Checks whether the argument is a finite number (excludes `±Infinity` and `NaN`).
662
+
663
+ #### arg
664
+
665
+ The value to check.
666
+
667
+ #### Returns
668
+
669
+ `true` if `arg` is a finite number, `false` otherwise.
561
670
 
562
671
  #### Usage Examples
563
672
 
@@ -575,7 +684,15 @@ expect(is_finite_number(Infinity)).to.be.false
575
684
  const is_number: (arg: unknown) => arg is number;
576
685
  ```
577
686
 
578
- Checks whether the argument is a number.
687
+ Checks whether the argument is of type `number` (includes `NaN` and `±Infinity`).
688
+
689
+ #### arg
690
+
691
+ The value to check.
692
+
693
+ #### Returns
694
+
695
+ `true` if `typeof arg === 'number'`, `false` otherwise.
579
696
 
580
697
  #### Usage Examples
581
698
 
@@ -593,7 +710,15 @@ expect(is_number(Infinity)).to.be.true
593
710
  const is_record: (arg: unknown) => arg is Record<PropertyKey, unknown>;
594
711
  ```
595
712
 
596
- Checks whether the argument is a plain object record.
713
+ Checks whether the argument is a plain object (not `null` and not an array).
714
+
715
+ #### arg
716
+
717
+ The value to check.
718
+
719
+ #### Returns
720
+
721
+ `true` if `arg` is a plain object, `false` otherwise.
597
722
 
598
723
  #### Usage Examples
599
724
 
@@ -618,6 +743,14 @@ const is_string: (arg: unknown) => arg is string;
618
743
 
619
744
  Checks whether the argument is a string.
620
745
 
746
+ #### arg
747
+
748
+ The value to check.
749
+
750
+ #### Returns
751
+
752
+ `true` if `typeof arg === 'string'`, `false` otherwise.
753
+
621
754
  #### Usage Examples
622
755
 
623
756
  ```ts
@@ -632,29 +765,36 @@ expect(is_string(new String('42'))).to.be.false
632
765
  const js_on_parse: (handlers: Record<PropertyKey, Function>, text: string) => any;
633
766
  ```
634
767
 
635
- `JSON.parse` with “JavaScript turned on”.
768
+ Parses JSON with support for handler-based value transformation (“JavaScript ON”).
636
769
 
637
- Objects having *exactly* one property whose name exists in `handlers`, i.e.:
770
+ Objects with exactly one property whose key exists in `handlers` and whose value is an array
771
+ are replaced by invoking the corresponding handler with the array elements as arguments.
638
772
 
639
- ```js
640
- { "«handler_name»": [«params»] }
641
- ```
773
+ #### handlers
642
774
 
643
- are replaced with:
775
+ An object mapping handler names to functions.
644
776
 
645
- ```js
646
- handlers['«handler_name»'](...«params»)
647
- ```
777
+ #### text
778
+
779
+ The JSON string to parse.
780
+
781
+ #### Returns
782
+
783
+ The parsed value with handler substitutions applied.
648
784
 
649
785
  #### Usage Examples
650
786
 
651
787
  ```ts
652
788
  const handlers = {
789
+ $add: (a: number, b: number) => a + b,
653
790
  $hello: (name: string) => `Hello ${name}!`,
654
791
  $foo: () => 'bar'
655
792
  }
656
793
 
657
794
  const actual = js_on_parse(handlers, `[
795
+ {
796
+ "$add": [1, 2]
797
+ },
658
798
  {
659
799
  "$hello": ["World"]
660
800
  },
@@ -676,6 +816,7 @@ const actual = js_on_parse(handlers, `[
676
816
  ]`)
677
817
 
678
818
  const expected = [
819
+ 3,
679
820
  'Hello World!',
680
821
  {
681
822
  nested: 'Hello nested World!',
@@ -693,33 +834,21 @@ const expected = [
693
834
  expect(actual).to.deep.equal(expected)
694
835
  ```
695
836
 
696
- ### nanolight
837
+ ### nanolight_ts
697
838
 
698
839
  ```ts
699
- const nanolight: <M, T>(decorator: (chunk: string, metadata?: M) => T, ...rules: [M, string | RegExp][]) => (code: string) => T[];
840
+ const nanolight_ts: (code: string) => HArgs1[];
700
841
  ```
701
842
 
702
- Generic syntax highlighting helper (see also [`nanolight_ts`](#nanolight_ts)).
843
+ A TypeScript/JavaScript syntax highlighting tokenizer built using [`new_tokenizer`](#new_tokenizer).
703
844
 
704
- - `decorator` is a function that wraps each matched chunk.
705
- It receives the matched text (`chunk`) and optionally the `metadata` associated with the pattern that produced the match.
706
- For unmatched text between patterns, `metadata` is `undefined`.
707
- - `rules` is an array of tuples `[metadata, pattern]` where:
708
- - `metadata`: data (e.g. CSS class name) passed to the `decorator` when the pattern matches.
709
- - `pattern`: a `string` or `RegExp` to match against the code.
845
+ #### code
710
846
 
711
- Matching rules:
712
- - For any two matches at different positions, the one starting earlier takes precedence.
713
- - For any two matches at the same position, the longer one takes precedence.
714
- - For any two matches at the same position and of the same length, the one defined earlier takes precedence.
847
+ The source code string to tokenize.
715
848
 
716
- ### nanolight_ts
717
-
718
- ```ts
719
- const nanolight_ts: (code: string) => HArgs1[];
720
- ```
849
+ #### Returns
721
850
 
722
- TypeScript syntax highlighting helper (built on [`nanolight`](#nanolight)).
851
+ An array of [`HArgs1`](#HArgs1) elements suitable for rendering with [`h`](#h) or [`s`](#s).
723
852
 
724
853
  #### Usage Examples
725
854
 
@@ -749,13 +878,57 @@ expect(nanolight_ts(code_js)).to.deep.equal([
749
878
  ])
750
879
  ```
751
880
 
881
+ ### new_tokenizer
882
+
883
+ ```ts
884
+ const new_tokenizer: <M, T>(decorator: (chunk: string, metadata?: M) => T, ...specs: [M, string | RegExp][]) => (code: string) => T[];
885
+ ```
886
+
887
+ A helper for building simple tokenizers (see also [`nanolight_ts`](#nanolight_ts)).
888
+
889
+ #### decorator
890
+
891
+ A function that wraps each matched chunk. It receives the matched text (`chunk`)
892
+ and optionally the `metadata` associated with the pattern that produced the match.
893
+ For unmatched text between patterns, `metadata` is `undefined`.
894
+
895
+ #### specs
896
+
897
+ An array of tuples `[metadata, pattern]` where:
898
+ - `metadata`: Arbitrary data (e.g., a CSS class name) passed to `decorator` when the pattern matches.
899
+ - `pattern`: A `string` or `RegExp` to match against the input.
900
+
901
+ #### Returns
902
+
903
+ A tokenizer function that accepts a code string and returns an array of decorated tokens.
904
+
905
+ #### Remarks
906
+
907
+ 1. Matches starting at an earlier position take precedence.
908
+ 2. Among matches at the same position, the longer one wins.
909
+ 3. Among matches of the same position and length, the one defined earlier wins.
910
+
752
911
  ### omit
753
912
 
754
913
  ```ts
755
914
  const omit: <T, K extends keyof T>(ref: T, keys: unknown[]) => Omit<T, K>;
756
915
  ```
757
916
 
758
- Runtime implementation of TypeScript’s `Omit` (see also [`pick`](#pick)).
917
+ Creates a new object excluding the specified keys from the source object.
918
+
919
+ A runtime equivalent of TypeScript’s `Omit<T, K>` utility type. See also [`pick`](#pick).
920
+
921
+ #### ref
922
+
923
+ The source object.
924
+
925
+ #### keys
926
+
927
+ An array of keys to exclude from the result.
928
+
929
+ #### Returns
930
+
931
+ A new object without the specified keys.
759
932
 
760
933
  #### Usage Examples
761
934
 
@@ -771,7 +944,21 @@ expect(omit(obj, ['c'])).to.deep.equal({ a: 42, b: '42' })
771
944
  const pick: <T, K extends keyof T>(ref: T, keys: K[]) => Pick<T, K>;
772
945
  ```
773
946
 
774
- Runtime implementation of TypeScript’s `Pick` (see also [`omit`](#omit)).
947
+ Creates a new object containing only the specified keys from the source object.
948
+
949
+ A runtime equivalent of TypeScript’s `Pick<T, K>` utility type. See also [`omit`](#omit).
950
+
951
+ #### ref
952
+
953
+ The source object.
954
+
955
+ #### keys
956
+
957
+ An array of keys to include in the result.
958
+
959
+ #### Returns
960
+
961
+ A new object with only the specified keys.
775
962
 
776
963
  #### Usage Examples
777
964
 
@@ -787,7 +974,32 @@ expect(pick(obj, ['a', 'b'])).to.deep.equal({ a: 42, b: '42' })
787
974
  const pl_ural: (singular: string, plural_2: string, plural_5: string, value: number) => string;
788
975
  ```
789
976
 
790
- Chooses the appropriate Polish noun form based on a numeric value.
977
+ Returns the appropriate Polish noun form based on a numeric value.
978
+
979
+ Polish has three plural forms depending on the number:
980
+ - Singular: used for exactly 1.
981
+ - “Plural 2-4”: used for 2, 3, 4, 22, 23, 24, etc. (but not 12, 13, 14).
982
+ - “Plural 5+”: used for 0, 5–21, 25–31, etc.
983
+
984
+ #### singular
985
+
986
+ The singular form (e.g., ”auto” for “car”).
987
+
988
+ #### plural_2
989
+
990
+ The form for 2, 3, 4 (e.g., “auta”).
991
+
992
+ #### plural_5
993
+
994
+ The form for 5+ (e.g., “aut”).
995
+
996
+ #### value
997
+
998
+ The numeric value to evaluate.
999
+
1000
+ #### Returns
1001
+
1002
+ The appropriate noun form for the given value.
791
1003
 
792
1004
  #### Usage Examples
793
1005
 
@@ -813,7 +1025,18 @@ expect(car(42)).to.deep.equal('cars')
813
1025
  const pro: (ref: unknown) => any;
814
1026
  ```
815
1027
 
816
- A `Proxy`-based helper that safely creates nested structures on access and allows deep assignment without guards.
1028
+ A Proxy-based helper for auto-vivification of nested object structures.
1029
+
1030
+ Accessing any property on the returned proxy automatically creates an empty object if the property does not exist,
1031
+ allowing deep assignments without explicit null checks.
1032
+
1033
+ #### ref
1034
+
1035
+ The root object to wrap.
1036
+
1037
+ #### Returns
1038
+
1039
+ A proxy that auto-creates nested objects on property access.
817
1040
 
818
1041
  #### Usage Examples
819
1042
 
@@ -851,14 +1074,30 @@ expect(ref).to.deep.equal({ one: { two: { three: { four: 1234 } } } })
851
1074
  const rwd: (root: CRoot, selector: string, cell_width_px: number, cell_height_px: number, ...specs: [number, number?, number?][]) => void;
852
1075
  ```
853
1076
 
854
- A responsivewebdesign helper that generates CSS rules for a grid-like layout.
1077
+ A responsive web design helper that generates CSS rules for a grid-like layout.
1078
+
1079
+ #### root
1080
+
1081
+ The CSS root object to populate (see [`c`](#c)).
1082
+
1083
+ #### selector
1084
+
1085
+ The CSS selector for the grid item.
1086
+
1087
+ #### cell_width_px
1088
+
1089
+ The base cell width in pixels.
1090
+
1091
+ #### cell_height_px
1092
+
1093
+ The base cell height in pixels.
855
1094
 
856
- - `root` and `selector` specify where to apply the generated rules (see [`c`](#c)).
857
- - `cell_width_px` and `cell_height_px` specify the base cell dimensions in pixels.
858
- - Each entry in `specs` is a tuple of:
859
- - `max_width`: maximum number of cells in a row (viewport width breakpoint).
860
- - `width` (optional, default: `1`): number of cells occupied by the element.
861
- - `height` (optional, default: `1`): number of cells the element occupies vertically.
1095
+ #### specs
1096
+
1097
+ An array of breakpoint specifications, each a tuple of:
1098
+ - `max_width`: Maximum number of cells per row (defines the viewport breakpoint).
1099
+ - `width` (optional, default `1`): Number of horizontal cells the element spans.
1100
+ - `height` (optional, default `1`): Number of vertical cells the element spans.
862
1101
 
863
1102
  #### Usage Examples
864
1103
 
@@ -917,18 +1156,28 @@ const s: {
917
1156
  };
918
1157
  ```
919
1158
 
920
- A lightweight [HyperScript](https://github.com/hyperhype/hyperscript)-style helper for creating and modifying `SVGElement`s (see also [`h`](#h)).
1159
+ A lightweight [HyperScript](https://github.com/hyperhype/hyperscript)-style helper
1160
+ for creating and modifying `SVGElement`s (see also [`h`](#h)).
1161
+
1162
+ #### tag_or_node
1163
+
1164
+ If a `string`, it is treated as the tag name for a new element.
1165
+ If a `Node`, that node is modified in place.
1166
+
1167
+ #### args
1168
+
1169
+ Additional arguments processed as follows:
1170
+ - `Object`: Maps attributes/properties. Keys starting with `$` set element properties
1171
+ (without the `$` prefix); other keys set attributes via `setAttributeNS`.
1172
+ A value of `false` removes the attribute.
1173
+ - `null` / `undefined`: Ignored.
1174
+ - `Node`: Appended as a child.
1175
+ - `string` / `number`: Converted to a `Text` node and appended.
1176
+ - [`HArgs`](#HArgs) array: Processed recursively.
921
1177
 
922
- - If the first argument is a `string`, it is treated as the tag name to create.
923
- - If the first argument is a `Node`, that node is modified.
924
- - Object arguments map attributes/properties:
925
- - Keys starting with `$` set element properties (without `$`).
926
- - Other keys set attributes via `setAttributeNS`.
927
- - Attributes with value `false` are removed via `removeAttributeNS`.
928
- - `null` / `undefined` are ignored.
929
- - `Node` arguments are appended.
930
- - `string` / `number` arguments become `Text` nodes.
931
- - [`HArgs`](#HArgs) arrays are processed recursively.
1178
+ #### Returns
1179
+
1180
+ The created or modified `SVGElement`.
932
1181
 
933
1182
  ### svg_use
934
1183
 
@@ -936,7 +1185,21 @@ A lightweight [HyperScript](https://github.com/hyperhype/hyperscript)-style help
936
1185
  const svg_use: (id: string, ...args: HArgs1[]) => SVGSVGElement;
937
1186
  ```
938
1187
 
939
- Shorthand for: `s('svg', ['use', { 'xlink:href': '#' + id }], ...args)`.
1188
+ Shorthand for creating an SVG element with a `<use>` child referencing an icon by ID.
1189
+
1190
+ Equivalent to: `s('svg', ['use', { 'xlink:href': '#' + id }], ...args)`.
1191
+
1192
+ #### id
1193
+
1194
+ The ID of the symbol to reference (without the `#` prefix).
1195
+
1196
+ #### args
1197
+
1198
+ Additional arguments passed to the outer `<svg>` element.
1199
+
1200
+ #### Returns
1201
+
1202
+ An `SVGSVGElement` containing a `<use>` element.
940
1203
 
941
1204
  ### uuid_v1
942
1205
 
@@ -946,7 +1209,18 @@ const uuid_v1: (date?: Date, node?: string) => string;
946
1209
 
947
1210
  Generates a UUID v1 (time-based) identifier.
948
1211
 
949
- - Optional `node` must match `/^[0-9a-f]*$/`; it is trimmed to the last 12 characters and left-padded with zeros.
1212
+ #### date
1213
+
1214
+ The date to use for the timestamp portion (default: current date/time).
1215
+
1216
+ #### node
1217
+
1218
+ A hexadecimal `string` for the node portion (default: random).
1219
+ Must match `/^[0-9a-f]*$/`; it is trimmed to the last 12 characters and left-padded with zeros if shorter.
1220
+
1221
+ #### Returns
1222
+
1223
+ A UUID v1 `string` in the standard format `xxxxxxxx-xxxx-1xxx-xxxx-xxxxxxxxxxxx`.
950
1224
 
951
1225
  #### Usage Examples
952
1226