@jackens/nnn 2026.2.13 → 2026.2.19
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 +116 -127
- package/nnn.js +147 -112
- package/package.json +1 -1
- package/readme.md +127 -143
package/nnn.d.ts
CHANGED
|
@@ -35,33 +35,6 @@ export type CRoot = Record<PropertyKey, CNode>;
|
|
|
35
35
|
* - Top-level keys starting with `@` (at-rules) are not concatenated with child selectors.
|
|
36
36
|
*/
|
|
37
37
|
export declare const c: (root: CRoot, splitter?: string) => string;
|
|
38
|
-
/**
|
|
39
|
-
* A responsive web design helper that generates CSS rules for a grid-like layout.
|
|
40
|
-
*
|
|
41
|
-
* @param root
|
|
42
|
-
*
|
|
43
|
-
* The CSS root object to populate (see {@link c}).
|
|
44
|
-
*
|
|
45
|
-
* @param selector
|
|
46
|
-
*
|
|
47
|
-
* The CSS selector for the grid item.
|
|
48
|
-
*
|
|
49
|
-
* @param cell_width_px
|
|
50
|
-
*
|
|
51
|
-
* The base cell width in pixels.
|
|
52
|
-
*
|
|
53
|
-
* @param cell_height_px
|
|
54
|
-
*
|
|
55
|
-
* The base cell height in pixels.
|
|
56
|
-
*
|
|
57
|
-
* @param specs
|
|
58
|
-
*
|
|
59
|
-
* An array of breakpoint specifications, each a tuple of:
|
|
60
|
-
* - `max_width`: maximum number of cells per row (defines the viewport breakpoint).
|
|
61
|
-
* - `width` (optional, default `1`): number of horizontal cells the element spans.
|
|
62
|
-
* - `height` (optional, default `1`): number of vertical cells the element spans.
|
|
63
|
-
*/
|
|
64
|
-
export declare const rwd: (root: CRoot, selector: string, cell_width_px: number, cell_height_px: number, ...specs: [number, number?, number?][]) => void;
|
|
65
38
|
/**
|
|
66
39
|
* Parses a CSV string into a two-dimensional array of strings.
|
|
67
40
|
*
|
|
@@ -80,40 +53,6 @@ export declare const rwd: (root: CRoot, selector: string, cell_width_px: number,
|
|
|
80
53
|
* A 2D array where each inner array represents a row of fields.
|
|
81
54
|
*/
|
|
82
55
|
export declare const csv_parse: (csv: string, separator?: string) => string[][];
|
|
83
|
-
/**
|
|
84
|
-
* A map from value constructors (or `null`/`undefined`) to escape functions.
|
|
85
|
-
*
|
|
86
|
-
* Used by {@link escape_values} and {@link new_escape}.
|
|
87
|
-
*/
|
|
88
|
-
export type EscapeMap = Map<unknown, (value?: unknown) => string>;
|
|
89
|
-
/**
|
|
90
|
-
* Escapes an array of values using the provided escape map.
|
|
91
|
-
*
|
|
92
|
-
* @param escape_map
|
|
93
|
-
*
|
|
94
|
-
* A map where keys are constructors (e.g., `String`, `Number`) and values are escape functions.
|
|
95
|
-
*
|
|
96
|
-
* @param values
|
|
97
|
-
*
|
|
98
|
-
* The array of values to escape.
|
|
99
|
-
*
|
|
100
|
-
* @returns
|
|
101
|
-
*
|
|
102
|
-
* An array of escaped strings.
|
|
103
|
-
*/
|
|
104
|
-
export declare const escape_values: (escape_map: EscapeMap, values: unknown[]) => string[];
|
|
105
|
-
/**
|
|
106
|
-
* Creates a tag function for escaping interpolated values in template literals.
|
|
107
|
-
*
|
|
108
|
-
* @param escape_map
|
|
109
|
-
*
|
|
110
|
-
* A map where keys are constructors and values are escape functions.
|
|
111
|
-
*
|
|
112
|
-
* @returns
|
|
113
|
-
*
|
|
114
|
-
* A tag function that escapes interpolated values using the provided escape map.
|
|
115
|
-
*/
|
|
116
|
-
export declare const new_escape: (escape_map: EscapeMap) => (template: TemplateStringsArray, ...values: unknown[]) => string;
|
|
117
56
|
/**
|
|
118
57
|
* Applies Polish-specific typographic corrections to a DOM subtree.
|
|
119
58
|
*
|
|
@@ -136,8 +75,7 @@ export type HArgs1 = Record<PropertyKey, unknown> | null | undefined | Node | st
|
|
|
136
75
|
*/
|
|
137
76
|
export type HArgs = [string | Node, ...HArgs1[]];
|
|
138
77
|
/**
|
|
139
|
-
* A lightweight [HyperScript](https://github.com/hyperhype/hyperscript)-style helper
|
|
140
|
-
* for creating and modifying `HTMLElement`s (see also {@link s}).
|
|
78
|
+
* A lightweight [HyperScript](https://github.com/hyperhype/hyperscript)-style helper for creating and modifying `HTMLElement`s (see also {@link s}).
|
|
141
79
|
*
|
|
142
80
|
* @param tag_or_node
|
|
143
81
|
*
|
|
@@ -164,8 +102,7 @@ export declare const h: {
|
|
|
164
102
|
(tag_or_node: string | Node, ...args1: HArgs1[]): Node;
|
|
165
103
|
};
|
|
166
104
|
/**
|
|
167
|
-
* A lightweight [HyperScript](https://github.com/hyperhype/hyperscript)-style helper
|
|
168
|
-
* for creating and modifying `SVGElement`s (see also {@link h}).
|
|
105
|
+
* A lightweight [HyperScript](https://github.com/hyperhype/hyperscript)-style helper for creating and modifying `SVGElement`s (see also {@link h}).
|
|
169
106
|
*
|
|
170
107
|
* @param tag_or_node
|
|
171
108
|
*
|
|
@@ -191,24 +128,6 @@ export declare const s: {
|
|
|
191
128
|
<N extends Node>(node: N, ...args1: HArgs1[]): N;
|
|
192
129
|
(tag_or_node: string | Node, ...args1: HArgs1[]): Node;
|
|
193
130
|
};
|
|
194
|
-
/**
|
|
195
|
-
* Shorthand for creating an SVG element with a `<use>` child referencing an icon by ID.
|
|
196
|
-
*
|
|
197
|
-
* Equivalent to: `s('svg', ['use', { 'xlink:href': '#' + id }], ...args)`.
|
|
198
|
-
*
|
|
199
|
-
* @param id
|
|
200
|
-
*
|
|
201
|
-
* The ID of the symbol to reference (without the `#` prefix).
|
|
202
|
-
*
|
|
203
|
-
* @param args
|
|
204
|
-
*
|
|
205
|
-
* Additional arguments passed to the outer `<svg>` element.
|
|
206
|
-
*
|
|
207
|
-
* @returns
|
|
208
|
-
*
|
|
209
|
-
* An `SVGSVGElement` containing a `<use>` element.
|
|
210
|
-
*/
|
|
211
|
-
export declare const svg_use: (id: string, ...args: HArgs1[]) => SVGSVGElement;
|
|
212
131
|
/**
|
|
213
132
|
* Checks whether an object has the specified key as its own property.
|
|
214
133
|
*
|
|
@@ -306,11 +225,61 @@ export declare const is_string: (arg: unknown) => arg is string;
|
|
|
306
225
|
* The parsed value with handler substitutions applied.
|
|
307
226
|
*/
|
|
308
227
|
export declare const js_on_parse: (handlers: Record<PropertyKey, Function>, text: string) => any;
|
|
228
|
+
/**
|
|
229
|
+
* A Monokai-inspired color scheme for use with the {@link c} helper and {@link nanolight_ts} tokenizer.
|
|
230
|
+
*/
|
|
231
|
+
export declare const monokai: CRoot;
|
|
232
|
+
/**
|
|
233
|
+
* A TypeScript/JavaScript syntax highlighting tokenizer built using {@link new_tokenizer}.
|
|
234
|
+
*
|
|
235
|
+
* @param code
|
|
236
|
+
*
|
|
237
|
+
* The source code string to tokenize.
|
|
238
|
+
*
|
|
239
|
+
* @returns
|
|
240
|
+
*
|
|
241
|
+
* An array of {@link HArgs1} elements suitable for rendering with {@link h}.
|
|
242
|
+
*/
|
|
243
|
+
export declare const nanolight_ts: (code: string) => HArgs1[];
|
|
244
|
+
/**
|
|
245
|
+
* A map from value constructors (or `null`/`undefined`) to escape functions.
|
|
246
|
+
*
|
|
247
|
+
* Used by {@link escape_values} and {@link new_escape}.
|
|
248
|
+
*/
|
|
249
|
+
export type EscapeMap = Map<unknown, (value?: unknown) => string>;
|
|
250
|
+
/**
|
|
251
|
+
* Escapes an array of values using the provided escape map.
|
|
252
|
+
*
|
|
253
|
+
* @param escape_map
|
|
254
|
+
*
|
|
255
|
+
* A map where keys are constructors (e.g., `String`, `Number`) and values are escape functions.
|
|
256
|
+
*
|
|
257
|
+
* @param values
|
|
258
|
+
*
|
|
259
|
+
* The array of values to escape.
|
|
260
|
+
*
|
|
261
|
+
* @returns
|
|
262
|
+
*
|
|
263
|
+
* An array of escaped strings.
|
|
264
|
+
*/
|
|
265
|
+
export declare const escape_values: (escape_map: EscapeMap, values: unknown[]) => string[];
|
|
266
|
+
/**
|
|
267
|
+
* Creates a tag function for escaping interpolated values in template literals.
|
|
268
|
+
*
|
|
269
|
+
* @param escape_map
|
|
270
|
+
*
|
|
271
|
+
* A map where keys are constructors and values are escape functions.
|
|
272
|
+
*
|
|
273
|
+
* @returns
|
|
274
|
+
*
|
|
275
|
+
* A tag function that escapes interpolated values using the provided escape map.
|
|
276
|
+
*/
|
|
277
|
+
export declare const new_escape: (escape_map: EscapeMap) => (template: TemplateStringsArray, ...values: unknown[]) => string;
|
|
309
278
|
/**
|
|
310
279
|
* Creates a function that returns the appropriate noun form based on a numeric value using `Intl.PluralRules`.
|
|
311
280
|
*
|
|
312
|
-
* Different languages have different plural rules. The `Intl.PluralRules` API provides
|
|
313
|
-
*
|
|
281
|
+
* Different languages have different plural rules. The `Intl.PluralRules` API provides locale-aware plural category selection.
|
|
282
|
+
* Possible categories are:
|
|
314
283
|
*
|
|
315
284
|
* - `zero`: for zero items (used in some languages like Arabic, Latvian)
|
|
316
285
|
* - `one`: for singular (e.g., 1 item)
|
|
@@ -334,23 +303,31 @@ export declare const js_on_parse: (handlers: Record<PropertyKey, Function>, text
|
|
|
334
303
|
*/
|
|
335
304
|
export declare const new_noun_form: (locale: string, forms: Partial<Record<Intl.LDMLPluralRule, string>>) => (value: number) => string;
|
|
336
305
|
/**
|
|
337
|
-
*
|
|
338
|
-
*
|
|
339
|
-
* A runtime equivalent of TypeScript’s `Pick<T, K>` utility type. See also {@link omit}.
|
|
306
|
+
* A helper for building simple tokenizers (see also {@link nanolight_ts}).
|
|
340
307
|
*
|
|
341
|
-
* @param
|
|
308
|
+
* @param decorator
|
|
342
309
|
*
|
|
343
|
-
*
|
|
310
|
+
* A function that wraps each matched chunk. It receives the matched text (`chunk`)
|
|
311
|
+
* and optionally the `metadata` associated with the pattern that produced the match.
|
|
312
|
+
* For unmatched text between patterns, `metadata` is `undefined`.
|
|
344
313
|
*
|
|
345
|
-
* @param
|
|
314
|
+
* @param specs
|
|
346
315
|
*
|
|
347
|
-
* An array of
|
|
316
|
+
* An array of tuples `[metadata, pattern]` where:
|
|
317
|
+
* - `metadata`: arbitrary data (e.g., a CSS class name) passed to `decorator` when the pattern matches.
|
|
318
|
+
* - `pattern`: a `string` or `RegExp` to match against the input.
|
|
348
319
|
*
|
|
349
320
|
* @returns
|
|
350
321
|
*
|
|
351
|
-
* A
|
|
322
|
+
* A tokenizer function that accepts a code string and returns an array of decorated tokens.
|
|
323
|
+
*
|
|
324
|
+
* @remarks
|
|
325
|
+
*
|
|
326
|
+
* 1. Matches starting at an earlier position take precedence.
|
|
327
|
+
* 2. Among matches at the same position, the longer one wins.
|
|
328
|
+
* 3. Among matches of the same position and length, the one defined earlier wins.
|
|
352
329
|
*/
|
|
353
|
-
export declare const
|
|
330
|
+
export declare const new_tokenizer: <M, T>(decorator: (chunk: string, metadata?: M) => T, ...specs: [M, string | RegExp][]) => (code: string) => T[];
|
|
354
331
|
/**
|
|
355
332
|
* Creates a new object excluding the specified keys from the source object.
|
|
356
333
|
*
|
|
@@ -370,56 +347,68 @@ export declare const pick: <T, K extends keyof T>(ref: T, keys: K[]) => Pick<T,
|
|
|
370
347
|
*/
|
|
371
348
|
export declare const omit: <T, K extends keyof T>(ref: T, keys: unknown[]) => Omit<T, K>;
|
|
372
349
|
/**
|
|
373
|
-
*
|
|
374
|
-
*
|
|
375
|
-
* @param decorator
|
|
350
|
+
* Creates a new object containing only the specified keys from the source object.
|
|
376
351
|
*
|
|
377
|
-
* A
|
|
378
|
-
* and optionally the `metadata` associated with the pattern that produced the match.
|
|
379
|
-
* For unmatched text between patterns, `metadata` is `undefined`.
|
|
352
|
+
* A runtime equivalent of TypeScript’s `Pick<T, K>` utility type. See also {@link omit}.
|
|
380
353
|
*
|
|
381
|
-
* @param
|
|
354
|
+
* @param ref
|
|
382
355
|
*
|
|
383
|
-
*
|
|
384
|
-
* - `metadata`: arbitrary data (e.g., a CSS class name) passed to `decorator` when the pattern matches.
|
|
385
|
-
* - `pattern`: a `string` or `RegExp` to match against the input.
|
|
356
|
+
* The source object.
|
|
386
357
|
*
|
|
387
|
-
* @
|
|
358
|
+
* @param keys
|
|
388
359
|
*
|
|
389
|
-
*
|
|
360
|
+
* An array of keys to include in the result.
|
|
390
361
|
*
|
|
391
|
-
* @
|
|
362
|
+
* @returns
|
|
392
363
|
*
|
|
393
|
-
*
|
|
394
|
-
* 2. Among matches at the same position, the longer one wins.
|
|
395
|
-
* 3. Among matches of the same position and length, the one defined earlier wins.
|
|
364
|
+
* A new object with only the specified keys.
|
|
396
365
|
*/
|
|
397
|
-
export declare const
|
|
366
|
+
export declare const pick: <T, K extends keyof T>(ref: T, keys: K[]) => Pick<T, K>;
|
|
398
367
|
/**
|
|
399
|
-
* A
|
|
368
|
+
* A responsive web design helper that generates CSS rules for a grid-like layout.
|
|
400
369
|
*
|
|
401
|
-
* @param
|
|
370
|
+
* @param root
|
|
402
371
|
*
|
|
403
|
-
* The
|
|
372
|
+
* The CSS root object to populate (see {@link c}).
|
|
404
373
|
*
|
|
405
|
-
* @
|
|
374
|
+
* @param selector
|
|
406
375
|
*
|
|
407
|
-
*
|
|
376
|
+
* The CSS selector for the grid item.
|
|
377
|
+
*
|
|
378
|
+
* @param cell_width_px
|
|
379
|
+
*
|
|
380
|
+
* The base cell width in pixels.
|
|
381
|
+
*
|
|
382
|
+
* @param cell_height_px
|
|
383
|
+
*
|
|
384
|
+
* The base cell height in pixels.
|
|
385
|
+
*
|
|
386
|
+
* @param specs
|
|
387
|
+
*
|
|
388
|
+
* An array of breakpoint specifications, each a tuple of:
|
|
389
|
+
* - `max_width`: maximum number of cells per row (defines the viewport breakpoint).
|
|
390
|
+
* - `width` (optional, default `1`): number of horizontal cells the element spans.
|
|
391
|
+
* - `height` (optional, default `1`): number of vertical cells the element spans.
|
|
408
392
|
*/
|
|
409
|
-
export declare const
|
|
393
|
+
export declare const rwd: (root: CRoot, selector: string, cell_width_px: number, cell_height_px: number, ...specs: [number, number?, number?][]) => void;
|
|
410
394
|
/**
|
|
411
|
-
*
|
|
395
|
+
* Shorthand for creating an SVG element with a `<use>` child referencing an icon by ID.
|
|
412
396
|
*
|
|
413
|
-
*
|
|
414
|
-
* `--purple`, `--red`, `--white`, `--yellow`) with both light and dark mode variants.
|
|
397
|
+
* Equivalent to: `s('svg', ['use', { 'xlink:href': '#' + id }], ...args)`.
|
|
415
398
|
*
|
|
416
|
-
* @
|
|
399
|
+
* @param id
|
|
400
|
+
*
|
|
401
|
+
* The ID of the symbol to reference (without the `#` prefix).
|
|
402
|
+
*
|
|
403
|
+
* @param args
|
|
417
404
|
*
|
|
418
|
-
*
|
|
419
|
-
*
|
|
420
|
-
*
|
|
405
|
+
* Additional arguments passed to the outer `<svg>` element.
|
|
406
|
+
*
|
|
407
|
+
* @returns
|
|
408
|
+
*
|
|
409
|
+
* An `SVGSVGElement` containing a `<use>` element.
|
|
421
410
|
*/
|
|
422
|
-
export declare const
|
|
411
|
+
export declare const svg_use: (id: string, ...args: HArgs1[]) => SVGSVGElement;
|
|
423
412
|
/**
|
|
424
413
|
* Generates a UUID v1 (time-based) identifier.
|
|
425
414
|
*
|
|
@@ -446,14 +435,14 @@ export declare const uuid_v1: (date?: Date, node?: string) => string;
|
|
|
446
435
|
* Intermediates of the last level in a get-only property chain are NOT auto-created.
|
|
447
436
|
* For example, `vivify(ref).one.two` will create `ref.one` as `{}`, but will NOT create `ref.one.two`.
|
|
448
437
|
* Only when a deeper access, assignment, or deletion occurs
|
|
449
|
-
* (e.g. `vivify(ref).one.two
|
|
438
|
+
* (e.g. `delete vivify(ref).one.two.three` or `vivify(ref).one.two.three = 4`) will `ref.one.two` be materialized.
|
|
450
439
|
*
|
|
451
440
|
* When traversal reaches a primitive value, no auto-creation happens;
|
|
452
441
|
* the primitive’s own property is returned instead
|
|
453
442
|
* (e.g. accessing `.toString.name` on a number yields `'toString'` without modifying the underlying structure).
|
|
454
443
|
*
|
|
455
444
|
* Deletion on a non-existing intermediate path will auto-create intermediates up to the parent of the deleted key
|
|
456
|
-
* (e.g. `delete vivify(ref).
|
|
445
|
+
* (e.g. `delete vivify(ref).one.two.three` will create `ref.one.two` as `{}` if it does not exist).
|
|
457
446
|
*
|
|
458
447
|
* @param ref
|
|
459
448
|
*
|
package/nnn.js
CHANGED
|
@@ -1,33 +1,11 @@
|
|
|
1
|
-
// src/nnn/
|
|
1
|
+
// src/nnn/is_array.ts
|
|
2
2
|
var is_array = Array.isArray;
|
|
3
|
-
|
|
3
|
+
|
|
4
|
+
// src/nnn/is_number.ts
|
|
4
5
|
var is_number = (arg) => typeof arg === "number";
|
|
5
|
-
var is_record = (arg) => typeof arg === "object" && arg != null && !is_array(arg);
|
|
6
|
-
var is_string = (arg) => typeof arg === "string";
|
|
7
6
|
|
|
8
|
-
// src/nnn/
|
|
9
|
-
var
|
|
10
|
-
var _is_object = (ref) => typeof ref === "object";
|
|
11
|
-
var _get_target = (parent, parent_key, key) => parent[parent_key] ??= is_string(key) && ARRAY_INDEX_REGEXP.test(key) ? [] : {};
|
|
12
|
-
var _vivify = (parent, parent_key) => {
|
|
13
|
-
return parent != null && _is_object(parent) ? new Proxy(parent, {
|
|
14
|
-
get(_, key) {
|
|
15
|
-
const target = _get_target(parent, parent_key, key);
|
|
16
|
-
const value = target[key];
|
|
17
|
-
return is_string(key) && _is_object(target) && (value == null || _is_object(value)) ? _vivify(target, key) : value;
|
|
18
|
-
},
|
|
19
|
-
set(_, key, value) {
|
|
20
|
-
const target = _get_target(parent, parent_key, key);
|
|
21
|
-
target[key] = value;
|
|
22
|
-
return true;
|
|
23
|
-
},
|
|
24
|
-
deleteProperty(_, key) {
|
|
25
|
-
const target = _get_target(parent, parent_key, key);
|
|
26
|
-
return delete target[key];
|
|
27
|
-
}
|
|
28
|
-
}) : parent?.[parent_key];
|
|
29
|
-
};
|
|
30
|
-
var vivify = (ref) => _vivify({ _: ref }, "_");
|
|
7
|
+
// src/nnn/is_string.ts
|
|
8
|
+
var is_string = (arg) => typeof arg === "string";
|
|
31
9
|
|
|
32
10
|
// src/nnn/c.ts
|
|
33
11
|
var _c = (node, prefix, result, splitter) => {
|
|
@@ -81,37 +59,15 @@ var c = (root, splitter = "$$") => {
|
|
|
81
59
|
}
|
|
82
60
|
return chunks.join("");
|
|
83
61
|
};
|
|
84
|
-
var rwd = (root, selector, cell_width_px, cell_height_px, ...specs) => {
|
|
85
|
-
const main = vivify(root)[selector];
|
|
86
|
-
main.boxSizing = "border-box";
|
|
87
|
-
main.display = "block";
|
|
88
|
-
main.float = "left";
|
|
89
|
-
main.width = "100%";
|
|
90
|
-
main.height = `${cell_height_px}px`;
|
|
91
|
-
specs.sort(([a], [b]) => a - b);
|
|
92
|
-
for (let [max_width, width, height] of specs) {
|
|
93
|
-
const node = max_width === 1 ? main : vivify(root)[`@media(min-width:${cell_width_px * max_width}px)`][selector];
|
|
94
|
-
width ??= 1;
|
|
95
|
-
height ??= 1;
|
|
96
|
-
let gcd = 100 * width;
|
|
97
|
-
let tmp = max_width;
|
|
98
|
-
while (tmp > 0) {
|
|
99
|
-
[gcd, tmp] = [tmp, gcd % tmp];
|
|
100
|
-
}
|
|
101
|
-
const w_100_per_gcd = 100 * width / gcd;
|
|
102
|
-
node.width = max_width === gcd ? `${w_100_per_gcd}%` : `calc(${w_100_per_gcd}% / ${max_width / gcd})`;
|
|
103
|
-
node.height = `${cell_height_px * height}px`;
|
|
104
|
-
}
|
|
105
|
-
};
|
|
106
62
|
// src/nnn/csv_parse.ts
|
|
63
|
+
var MAIN_PATTERN = /\n|(?<!")("(?:[^"]|"")*")(?!")/g;
|
|
107
64
|
var csv_parse = (csv, separator = ",") => {
|
|
108
|
-
const main_pattern = /\n|(?<!")("(?:[^"]|"")*")(?!")/g;
|
|
109
65
|
const line_pattern = new RegExp(`${separator}|(?<!")\\s*"((?:[^"]|"")*)"\\s*(?!")`, "g");
|
|
110
|
-
return csv.replace(/\r/g, "").replace(/\n+$/, "").replace(
|
|
66
|
+
return csv.replace(/\r/g, "").replace(/\n+$/, "").replace(MAIN_PATTERN, (_, chunk) => chunk ?? "\r").split("\r").map((line) => line.replace(line_pattern, (_, chunk) => chunk == null ? "\r" : chunk.replace(/""/g, '"')).split("\r"));
|
|
111
67
|
};
|
|
112
|
-
// src/nnn/
|
|
113
|
-
var
|
|
114
|
-
|
|
68
|
+
// src/nnn/is_record.ts
|
|
69
|
+
var is_record = (arg) => typeof arg === "object" && arg != null && !is_array(arg);
|
|
70
|
+
|
|
115
71
|
// src/nnn/h.ts
|
|
116
72
|
var _h = (namespace_uri) => {
|
|
117
73
|
const create_element = namespace_uri == null ? (tag) => document.createElement(tag) : (tag) => document.createElementNS(namespace_uri, tag);
|
|
@@ -173,7 +129,6 @@ var _h = (namespace_uri) => {
|
|
|
173
129
|
};
|
|
174
130
|
var h = /* @__PURE__ */ _h();
|
|
175
131
|
var s = /* @__PURE__ */ _h("http://www.w3.org/2000/svg");
|
|
176
|
-
var svg_use = (id, ...args) => s("svg", ["use", { "xlink:href": "#" + id }], ...args);
|
|
177
132
|
|
|
178
133
|
// src/nnn/fix_pl_typography.ts
|
|
179
134
|
var TAGS_TO_SKIP = ["IFRAME", "NOSCRIPT", "PRE", "SCRIPT", "STYLE", "TEXTAREA"];
|
|
@@ -208,6 +163,8 @@ var fix_pl_typography = (node) => {
|
|
|
208
163
|
};
|
|
209
164
|
// src/nnn/has_own.ts
|
|
210
165
|
var has_own = (ref, key) => ref != null && Object.hasOwn(ref, key);
|
|
166
|
+
// src/nnn/is_finite_number.ts
|
|
167
|
+
var is_finite_number = Number.isFinite;
|
|
211
168
|
// src/nnn/js_on_parse.ts
|
|
212
169
|
var js_on_parse = (handlers, text) => JSON.parse(text, (key, value) => {
|
|
213
170
|
if (is_record(value)) {
|
|
@@ -226,13 +183,71 @@ var js_on_parse = (handlers, text) => JSON.parse(text, (key, value) => {
|
|
|
226
183
|
}
|
|
227
184
|
return value;
|
|
228
185
|
});
|
|
229
|
-
// src/nnn/
|
|
230
|
-
var
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
186
|
+
// src/nnn/monokai.ts
|
|
187
|
+
var monokai = {
|
|
188
|
+
":root": {
|
|
189
|
+
__bg: "#faf4f2",
|
|
190
|
+
__fg: "#29242a",
|
|
191
|
+
__comment: "#918c8e",
|
|
192
|
+
__identifier_1: "#7058be",
|
|
193
|
+
__identifier_2: "#269d69",
|
|
194
|
+
__identifier_3: "#1c8ca8",
|
|
195
|
+
__identifier_4: "#29242a",
|
|
196
|
+
__keyword_1: "#e14775",
|
|
197
|
+
__keyword_2: "#7058be",
|
|
198
|
+
__keyword_3: "#1c8ca8",
|
|
199
|
+
__number: "#7058be",
|
|
200
|
+
__operator: "#e14775",
|
|
201
|
+
__punctuation: "#918c8e",
|
|
202
|
+
__string: "#cc7a0a"
|
|
203
|
+
},
|
|
204
|
+
pre: {
|
|
205
|
+
backgroundColor: "var(--bg)",
|
|
206
|
+
color: "var(--fg)",
|
|
207
|
+
margin: 0,
|
|
208
|
+
padding: "1em",
|
|
209
|
+
overflow: "visible",
|
|
210
|
+
" code": {
|
|
211
|
+
fontFamily: '"Source Code Pro"',
|
|
212
|
+
padding: 0
|
|
213
|
+
}
|
|
214
|
+
},
|
|
215
|
+
"code>span.": {
|
|
216
|
+
bg: { color: "var(--bg)" },
|
|
217
|
+
fg: { color: "var(--fg)" },
|
|
218
|
+
comment: { color: "var(--comment)" },
|
|
219
|
+
"identifier-1": { color: "var(--identifier-1)" },
|
|
220
|
+
"identifier-2": { color: "var(--identifier-2)" },
|
|
221
|
+
"identifier-3": { color: "var(--identifier-3)" },
|
|
222
|
+
"identifier-4": { color: "var(--identifier-4)" },
|
|
223
|
+
"keyword-1": { color: "var(--keyword-1)" },
|
|
224
|
+
"keyword-2": { color: "var(--keyword-2)" },
|
|
225
|
+
"keyword-3": { color: "var(--keyword-3)" },
|
|
226
|
+
number: { color: "var(--number)" },
|
|
227
|
+
operator: { color: "var(--operator)" },
|
|
228
|
+
punctuation: { color: "var(--punctuation)" },
|
|
229
|
+
string: { color: "var(--string)" }
|
|
230
|
+
},
|
|
231
|
+
"@media only screen and (prefers-color-scheme: dark)": {
|
|
232
|
+
":root": {
|
|
233
|
+
__bg: "#2d2a2e",
|
|
234
|
+
__fg: "#fcfcfa",
|
|
235
|
+
__comment: "#727072",
|
|
236
|
+
__identifier_1: "#ae81ff",
|
|
237
|
+
__identifier_2: "#a9dc76",
|
|
238
|
+
__identifier_3: "#66d9ef",
|
|
239
|
+
__identifier_4: "#fcfcfa",
|
|
240
|
+
__keyword_1: "#ff6188",
|
|
241
|
+
__keyword_2: "#ae81ff",
|
|
242
|
+
__keyword_3: "#66d9ef",
|
|
243
|
+
__number: "#ae81ff",
|
|
244
|
+
__operator: "#ff6188",
|
|
245
|
+
__punctuation: "#727072",
|
|
246
|
+
__string: "#ffd866"
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
};
|
|
250
|
+
// src/nnn/new_tokenizer.ts
|
|
236
251
|
var new_tokenizer = (decorator, ...specs) => (code) => {
|
|
237
252
|
const result = [];
|
|
238
253
|
while (code.length > 0) {
|
|
@@ -270,60 +285,80 @@ var new_tokenizer = (decorator, ...specs) => (code) => {
|
|
|
270
285
|
}
|
|
271
286
|
return result;
|
|
272
287
|
};
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
var
|
|
276
|
-
var
|
|
277
|
-
var
|
|
278
|
-
var
|
|
279
|
-
var
|
|
280
|
-
var
|
|
281
|
-
var
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
288
|
+
|
|
289
|
+
// src/nnn/nanolight_ts.ts
|
|
290
|
+
var COMMENT = "comment";
|
|
291
|
+
var IDENTIFIER_1 = "identifier-1";
|
|
292
|
+
var IDENTIFIER_2 = "identifier-2";
|
|
293
|
+
var IDENTIFIER_3 = "identifier-3";
|
|
294
|
+
var IDENTIFIER_4 = "identifier-4";
|
|
295
|
+
var KEYWORD_1 = "keyword-1";
|
|
296
|
+
var KEYWORD_2 = "keyword-2";
|
|
297
|
+
var KEYWORD_3 = "keyword-3";
|
|
298
|
+
var NUMBER = "number";
|
|
299
|
+
var OPERATOR = "operator";
|
|
300
|
+
var PUNCTUATION = "punctuation";
|
|
301
|
+
var STRING = "string";
|
|
302
|
+
var nanolight_ts = /* @__PURE__ */ new_tokenizer((chunk, name) => name != null ? ["span", { class: name }, chunk] : chunk, [STRING, /".*?"/], [STRING, /'.*?'/], [STRING, /`[\s\S]*?`/], [COMMENT, /\/\*[\s\S]*?\*\//], [COMMENT, /(?<!\\)\/\/.*?(?=\n)/], [NUMBER, /0b[01_]+/], [NUMBER, /0o[01234567_]+/], [NUMBER, /0x[\dabcdef_]+/], [NUMBER, /\d[\d_]*(\.[\d_]+)?(e[+-]?[\d_]+)?/], [OPERATOR, "!"], [OPERATOR, "!="], [OPERATOR, "!=="], [OPERATOR, "%"], [OPERATOR, "%="], [OPERATOR, "&&"], [OPERATOR, "&&="], [OPERATOR, "&"], [OPERATOR, "&="], [OPERATOR, "*"], [OPERATOR, "**"], [OPERATOR, "**="], [OPERATOR, "*="], [OPERATOR, "+"], [OPERATOR, "++"], [OPERATOR, "+="], [OPERATOR, "-"], [OPERATOR, "--"], [OPERATOR, "-="], [OPERATOR, "..."], [OPERATOR, "/"], [OPERATOR, "/="], [OPERATOR, ":"], [OPERATOR, "<"], [OPERATOR, "<<"], [OPERATOR, "<<="], [OPERATOR, "<="], [OPERATOR, "="], [OPERATOR, "=="], [OPERATOR, "==="], [OPERATOR, "=>"], [OPERATOR, ">"], [OPERATOR, ">="], [OPERATOR, ">>"], [OPERATOR, ">>="], [OPERATOR, ">>>"], [OPERATOR, ">>>="], [OPERATOR, "?"], [OPERATOR, "?"], [OPERATOR, "??"], [OPERATOR, "??="], [OPERATOR, "^"], [OPERATOR, "^="], [OPERATOR, "|"], [OPERATOR, "|="], [OPERATOR, "||"], [OPERATOR, "||="], [OPERATOR, "~"], [OPERATOR, "~="], [OPERATOR, /(?<=\s):/], [PUNCTUATION, "("], [PUNCTUATION, ")"], [PUNCTUATION, ","], [PUNCTUATION, "."], [PUNCTUATION, ":"], [PUNCTUATION, ";"], [PUNCTUATION, "?."], [PUNCTUATION, "["], [PUNCTUATION, "]"], [PUNCTUATION, "{"], [PUNCTUATION, "}"], [KEYWORD_1, "as"], [KEYWORD_1, "async"], [KEYWORD_1, "await"], [KEYWORD_1, "break"], [KEYWORD_1, "case"], [KEYWORD_1, "catch"], [KEYWORD_1, "class"], [KEYWORD_1, "const"], [KEYWORD_1, "continue"], [KEYWORD_1, "debugger"], [KEYWORD_1, "default"], [KEYWORD_1, "delete"], [KEYWORD_1, "do"], [KEYWORD_1, "else"], [KEYWORD_1, "export"], [KEYWORD_1, "extends"], [KEYWORD_1, "finally"], [KEYWORD_1, "for"], [KEYWORD_1, "from"], [KEYWORD_1, "function"], [KEYWORD_1, "function*"], [KEYWORD_1, "goto"], [KEYWORD_1, "if"], [KEYWORD_1, "import"], [KEYWORD_1, "in"], [KEYWORD_1, "instanceof"], [KEYWORD_1, "is"], [KEYWORD_1, "keyof"], [KEYWORD_1, "let"], [KEYWORD_1, "new"], [KEYWORD_1, "of"], [KEYWORD_1, "package"], [KEYWORD_1, "return"], [KEYWORD_1, "super"], [KEYWORD_1, "switch"], [KEYWORD_1, "this"], [KEYWORD_1, "throw"], [KEYWORD_1, "try"], [KEYWORD_1, "type"], [KEYWORD_1, "typeof"], [KEYWORD_1, "var"], [KEYWORD_1, "void"], [KEYWORD_1, "while"], [KEYWORD_1, "with"], [KEYWORD_1, "yield"], [KEYWORD_1, "yield*"], [KEYWORD_2, "false"], [KEYWORD_2, "Infinity"], [KEYWORD_2, "NaN"], [KEYWORD_2, "null"], [KEYWORD_2, "true"], [KEYWORD_2, "undefined"], [KEYWORD_3, "any"], [KEYWORD_3, "bigint"], [KEYWORD_3, "boolean"], [KEYWORD_3, "eval"], [KEYWORD_3, "number"], [KEYWORD_3, "string"], [KEYWORD_3, "symbol"], [KEYWORD_3, "unknown"], [IDENTIFIER_1, /[\p{Lu}_$][\p{Lu}\d_$]*/u], [IDENTIFIER_2, /[\p{L}_$][\p{L}\d_$]*(?=[(`])/u], [IDENTIFIER_3, /\p{Lu}[\p{L}\d_$]*/u], [IDENTIFIER_4, /[\p{L}_$][\p{L}\d_$]*/u]);
|
|
303
|
+
// src/nnn/new_escape.ts
|
|
304
|
+
var escape_values = (escape_map, values) => values.map((value) => (value == null ? escape_map.get(value) : escape_map.get(value?.constructor))?.(value) ?? "");
|
|
305
|
+
var new_escape = (escape_map) => (template, ...values) => String.raw(template, ...escape_values(escape_map, values));
|
|
306
|
+
// src/nnn/new_noun_form.ts
|
|
307
|
+
var PLURAL_RULES = {};
|
|
308
|
+
var new_noun_form = (locale, forms) => (value) => forms[(PLURAL_RULES[locale] ??= new Intl.PluralRules(locale)).select(value)] ?? forms.other ?? "";
|
|
309
|
+
// src/nnn/omit.ts
|
|
310
|
+
var omit = (ref, keys) => Object.fromEntries(Object.entries(ref).filter(([key]) => !keys.includes(key)));
|
|
311
|
+
// src/nnn/pick.ts
|
|
312
|
+
var pick = (ref, keys) => Object.fromEntries(Object.entries(ref).filter(([key]) => keys.includes(key)));
|
|
313
|
+
// src/nnn/vivify.ts
|
|
314
|
+
var ARRAY_INDEX_REGEXP = /^(0|[1-9]\d*)$/;
|
|
315
|
+
var is_object = (ref) => typeof ref === "object";
|
|
316
|
+
var get_target = (parent, parent_key, key) => parent[parent_key] ??= is_string(key) && ARRAY_INDEX_REGEXP.test(key) ? [] : {};
|
|
317
|
+
var _vivify = (parent, parent_key) => {
|
|
318
|
+
return parent != null && is_object(parent) ? new Proxy(parent, {
|
|
319
|
+
get(_, key) {
|
|
320
|
+
const target = get_target(parent, parent_key, key);
|
|
321
|
+
const value = target[key];
|
|
322
|
+
return is_string(key) && is_object(target) && (value == null || is_object(value)) ? _vivify(target, key) : value;
|
|
323
|
+
},
|
|
324
|
+
set(_, key, value) {
|
|
325
|
+
const target = get_target(parent, parent_key, key);
|
|
326
|
+
target[key] = value;
|
|
327
|
+
return true;
|
|
328
|
+
},
|
|
329
|
+
deleteProperty(_, key) {
|
|
330
|
+
const target = get_target(parent, parent_key, key);
|
|
331
|
+
return delete target[key];
|
|
312
332
|
}
|
|
313
|
-
}
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
333
|
+
}) : parent?.[parent_key];
|
|
334
|
+
};
|
|
335
|
+
var vivify = (ref) => _vivify({ _: ref }, "_");
|
|
336
|
+
|
|
337
|
+
// src/nnn/rwd.ts
|
|
338
|
+
var rwd = (root, selector, cell_width_px, cell_height_px, ...specs) => {
|
|
339
|
+
const main = vivify(root)[selector];
|
|
340
|
+
main.boxSizing = "border-box";
|
|
341
|
+
main.display = "block";
|
|
342
|
+
main.float = "left";
|
|
343
|
+
main.width = "100%";
|
|
344
|
+
main.height = `${cell_height_px}px`;
|
|
345
|
+
specs.sort(([a], [b]) => a - b);
|
|
346
|
+
for (let [max_width, width, height] of specs) {
|
|
347
|
+
const node = max_width === 1 ? main : vivify(root)[`@media(min-width:${cell_width_px * max_width}px)`][selector];
|
|
348
|
+
width ??= 1;
|
|
349
|
+
height ??= 1;
|
|
350
|
+
let gcd = 100 * width;
|
|
351
|
+
let tmp = max_width;
|
|
352
|
+
while (tmp > 0) {
|
|
353
|
+
[gcd, tmp] = [tmp, gcd % tmp];
|
|
324
354
|
}
|
|
355
|
+
const w_100_per_gcd = 100 * width / gcd;
|
|
356
|
+
node.width = max_width === gcd ? `${w_100_per_gcd}%` : `calc(${w_100_per_gcd}% / ${max_width / gcd})`;
|
|
357
|
+
node.height = `${cell_height_px * height}px`;
|
|
325
358
|
}
|
|
326
359
|
};
|
|
360
|
+
// src/nnn/svg_use.ts
|
|
361
|
+
var svg_use = (id, ...args) => s("svg", ["use", { "xlink:href": "#" + id }], ...args);
|
|
327
362
|
// src/nnn/uuid_v1.ts
|
|
328
363
|
var ZEROS = /* @__PURE__ */ "0".repeat(16);
|
|
329
364
|
var counter = 0;
|
package/package.json
CHANGED
package/readme.md
CHANGED
|
@@ -1,22 +1,23 @@
|
|
|
1
1
|
# nnn
|
|
2
2
|
|
|
3
|
-
A collection of Jackens’ JavaScript helper utilities.
|
|
3
|
+
A collection of Jackens’ JavaScript helper utilities (version: `2026.2.19`).
|
|
4
4
|
|
|
5
5
|
## Installation
|
|
6
6
|
|
|
7
7
|
```sh
|
|
8
|
-
bun i @jackens/nnn
|
|
8
|
+
bun i @jackens/nnn
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
or
|
|
12
|
+
|
|
13
|
+
```sh
|
|
14
|
+
npm i @jackens/nnn
|
|
9
15
|
```
|
|
10
16
|
|
|
11
17
|
## Usage
|
|
12
18
|
|
|
13
19
|
```js
|
|
14
20
|
import {
|
|
15
|
-
CNode,
|
|
16
|
-
CRoot,
|
|
17
|
-
EscapeMap,
|
|
18
|
-
HArgs,
|
|
19
|
-
HArgs1,
|
|
20
21
|
c,
|
|
21
22
|
csv_parse,
|
|
22
23
|
escape_values,
|
|
@@ -41,7 +42,7 @@ import {
|
|
|
41
42
|
svg_use,
|
|
42
43
|
uuid_v1,
|
|
43
44
|
vivify
|
|
44
|
-
} from '@jackens/nnn' // './node_modules/@jackens/nnn/nnn.js'
|
|
45
|
+
} from '@jackens/nnn' // or './node_modules/@jackens/nnn/nnn.js'
|
|
45
46
|
```
|
|
46
47
|
|
|
47
48
|
## Exports
|
|
@@ -55,8 +56,7 @@ import {
|
|
|
55
56
|
- [`csv_parse`](#csv_parse): Parses a CSV string into a two-dimensional array of strings.
|
|
56
57
|
- [`escape_values`](#escape_values): Escapes an array of values using the provided escape map.
|
|
57
58
|
- [`fix_pl_typography`](#fix_pl_typography): Applies Polish-specific typographic corrections to a DOM subtree.
|
|
58
|
-
- [`h`](#h): A lightweight [HyperScript](https://github.com/hyperhype/hyperscript)-style helper
|
|
59
|
-
for creating and modifying `HTMLElement`s (see also [`s`](#s)).
|
|
59
|
+
- [`h`](#h): A lightweight [HyperScript](https://github.com/hyperhype/hyperscript)-style helper for creating and modifying `HTMLElement`s (see also [`s`](#s)).
|
|
60
60
|
- [`has_own`](#has_own): Checks whether an object has the specified key as its own property.
|
|
61
61
|
- [`is_array`](#is_array): Checks whether the argument is an array.
|
|
62
62
|
- [`is_finite_number`](#is_finite_number): Checks whether the argument is a finite number (excludes `±Infinity` and `NaN`).
|
|
@@ -72,8 +72,7 @@ import {
|
|
|
72
72
|
- [`omit`](#omit): Creates a new object excluding the specified keys from the source object.
|
|
73
73
|
- [`pick`](#pick): Creates a new object containing only the specified keys from the source object.
|
|
74
74
|
- [`rwd`](#rwd): A responsive web design helper that generates CSS rules for a grid-like layout.
|
|
75
|
-
- [`s`](#s): A lightweight [HyperScript](https://github.com/hyperhype/hyperscript)-style helper
|
|
76
|
-
for creating and modifying `SVGElement`s (see also [`h`](#h)).
|
|
75
|
+
- [`s`](#s): A lightweight [HyperScript](https://github.com/hyperhype/hyperscript)-style helper for creating and modifying `SVGElement`s (see also [`h`](#h)).
|
|
77
76
|
- [`svg_use`](#svg_use): Shorthand for creating an SVG element with a `<use>` child referencing an icon by ID.
|
|
78
77
|
- [`uuid_v1`](#uuid_v1): Generates a UUID v1 (time-based) identifier.
|
|
79
78
|
- [`vivify`](#vivify): A Proxy-based helper for auto-vivification of nested object structures.
|
|
@@ -156,7 +155,7 @@ A CSS string representing the compiled rules.
|
|
|
156
155
|
#### Usage Examples
|
|
157
156
|
|
|
158
157
|
```ts
|
|
159
|
-
const
|
|
158
|
+
const actual_1 = c({
|
|
160
159
|
a: {
|
|
161
160
|
color: 'red',
|
|
162
161
|
margin: 1,
|
|
@@ -165,7 +164,7 @@ const actual = c({
|
|
|
165
164
|
}
|
|
166
165
|
})
|
|
167
166
|
|
|
168
|
-
const
|
|
167
|
+
const expected_1 = `
|
|
169
168
|
a{
|
|
170
169
|
color:red;
|
|
171
170
|
margin:1
|
|
@@ -178,11 +177,9 @@ a{
|
|
|
178
177
|
padding:1
|
|
179
178
|
}`.replace(/\n\s*/g, '')
|
|
180
179
|
|
|
181
|
-
expect(
|
|
182
|
-
```
|
|
180
|
+
expect(actual_1).to.equal(expected_1)
|
|
183
181
|
|
|
184
|
-
|
|
185
|
-
const actual = c({
|
|
182
|
+
const actual_2 = c({
|
|
186
183
|
a: {
|
|
187
184
|
'.b': {
|
|
188
185
|
color: 'red',
|
|
@@ -193,7 +190,7 @@ const actual = c({
|
|
|
193
190
|
}
|
|
194
191
|
})
|
|
195
192
|
|
|
196
|
-
const
|
|
193
|
+
const expected_2 = `
|
|
197
194
|
a.b{
|
|
198
195
|
color:red;
|
|
199
196
|
margin:1
|
|
@@ -206,11 +203,9 @@ a.b{
|
|
|
206
203
|
padding:1
|
|
207
204
|
}`.replace(/\n\s*/g, '')
|
|
208
205
|
|
|
209
|
-
expect(
|
|
210
|
-
```
|
|
206
|
+
expect(actual_2).to.equal(expected_2)
|
|
211
207
|
|
|
212
|
-
|
|
213
|
-
const actual = c({
|
|
208
|
+
const actual_3 = c({
|
|
214
209
|
'@font-face$$1': {
|
|
215
210
|
fontFamily: 'Jackens',
|
|
216
211
|
src$$1: 'url(otf/jackens.otf)',
|
|
@@ -239,7 +234,7 @@ const actual = c({
|
|
|
239
234
|
}
|
|
240
235
|
})
|
|
241
236
|
|
|
242
|
-
const
|
|
237
|
+
const expected_3 = `
|
|
243
238
|
@font-face{
|
|
244
239
|
font-family:Jackens;
|
|
245
240
|
src:url(otf/jackens.otf);
|
|
@@ -281,11 +276,9 @@ div.c2{
|
|
|
281
276
|
}
|
|
282
277
|
}`.replace(/\n\s*/g, '')
|
|
283
278
|
|
|
284
|
-
expect(
|
|
285
|
-
```
|
|
279
|
+
expect(actual_3).to.equal(expected_3)
|
|
286
280
|
|
|
287
|
-
|
|
288
|
-
const actual = c({
|
|
281
|
+
const actual_4 = c({
|
|
289
282
|
a: {
|
|
290
283
|
'.b,.c': {
|
|
291
284
|
margin: 1,
|
|
@@ -296,7 +289,7 @@ const actual = c({
|
|
|
296
289
|
}
|
|
297
290
|
})
|
|
298
291
|
|
|
299
|
-
const
|
|
292
|
+
const expected_4 = `
|
|
300
293
|
a.b,a.c{
|
|
301
294
|
margin:1
|
|
302
295
|
}
|
|
@@ -304,11 +297,9 @@ a.b.d,a.c.d{
|
|
|
304
297
|
margin:2
|
|
305
298
|
}`.replace(/\n\s*/g, '')
|
|
306
299
|
|
|
307
|
-
expect(
|
|
308
|
-
```
|
|
300
|
+
expect(actual_4).to.equal(expected_4)
|
|
309
301
|
|
|
310
|
-
|
|
311
|
-
const actual = c({
|
|
302
|
+
const actual_5 = c({
|
|
312
303
|
'.b,.c': {
|
|
313
304
|
margin: 1,
|
|
314
305
|
'.d': {
|
|
@@ -317,7 +308,7 @@ const actual = c({
|
|
|
317
308
|
}
|
|
318
309
|
})
|
|
319
310
|
|
|
320
|
-
const
|
|
311
|
+
const expected_5 = `
|
|
321
312
|
.b,.c{
|
|
322
313
|
margin:1
|
|
323
314
|
}
|
|
@@ -325,11 +316,9 @@ const expected = `
|
|
|
325
316
|
margin:2
|
|
326
317
|
}`.replace(/\n\s*/g, '')
|
|
327
318
|
|
|
328
|
-
expect(
|
|
329
|
-
```
|
|
319
|
+
expect(actual_5).to.equal(expected_5)
|
|
330
320
|
|
|
331
|
-
|
|
332
|
-
const actual = c({
|
|
321
|
+
const actual_6 = c({
|
|
333
322
|
'.a,.b': {
|
|
334
323
|
margin: 1,
|
|
335
324
|
'.c,.d': {
|
|
@@ -338,7 +327,7 @@ const actual = c({
|
|
|
338
327
|
}
|
|
339
328
|
})
|
|
340
329
|
|
|
341
|
-
const
|
|
330
|
+
const expected_6 = `
|
|
342
331
|
.a,.b{
|
|
343
332
|
margin:1
|
|
344
333
|
}
|
|
@@ -346,7 +335,7 @@ const expected = `
|
|
|
346
335
|
margin:2
|
|
347
336
|
}`.replace(/\n\s*/g, '')
|
|
348
337
|
|
|
349
|
-
expect(
|
|
338
|
+
expect(actual_6).to.equal(expected_6)
|
|
350
339
|
```
|
|
351
340
|
|
|
352
341
|
### csv_parse
|
|
@@ -382,6 +371,7 @@ yyy",zzz
|
|
|
382
371
|
42 , "42" , 17
|
|
383
372
|
|
|
384
373
|
`
|
|
374
|
+
|
|
385
375
|
expect(csv_parse(text)).to.deep.equal([
|
|
386
376
|
['aaa\n"aaa"\naaa', 'bbb', 'ccc,ccc'],
|
|
387
377
|
['xxx,xxx', 'yyy\nyyy', 'zzz'],
|
|
@@ -448,8 +438,7 @@ const h: {
|
|
|
448
438
|
};
|
|
449
439
|
```
|
|
450
440
|
|
|
451
|
-
A lightweight [HyperScript](https://github.com/hyperhype/hyperscript)-style helper
|
|
452
|
-
for creating and modifying `HTMLElement`s (see also [`s`](#s)).
|
|
441
|
+
A lightweight [HyperScript](https://github.com/hyperhype/hyperscript)-style helper for creating and modifying `HTMLElement`s (see also [`s`](#s)).
|
|
453
442
|
|
|
454
443
|
#### tag_or_node
|
|
455
444
|
|
|
@@ -475,49 +464,41 @@ The created or modified `HTMLElement`.
|
|
|
475
464
|
```ts
|
|
476
465
|
const b = h('b')
|
|
477
466
|
|
|
478
|
-
expect(b.outerHTML).to.
|
|
467
|
+
expect(b.outerHTML).to.equal('<b></b>')
|
|
479
468
|
|
|
480
469
|
const i = h('i', 'text')
|
|
481
470
|
|
|
482
471
|
h(b, i)
|
|
483
472
|
|
|
484
|
-
expect(i.outerHTML).to.
|
|
485
|
-
expect(b.outerHTML).to.
|
|
473
|
+
expect(i.outerHTML).to.equal('<i>text</i>')
|
|
474
|
+
expect(b.outerHTML).to.equal('<b><i>text</i></b>')
|
|
486
475
|
|
|
487
476
|
h(i, { $className: 'some class' })
|
|
488
477
|
|
|
489
|
-
expect(i.outerHTML).to.
|
|
490
|
-
expect(b.outerHTML).to.
|
|
491
|
-
```
|
|
478
|
+
expect(i.outerHTML).to.equal('<i class="some class">text</i>')
|
|
479
|
+
expect(b.outerHTML).to.equal('<b><i class="some class">text</i></b>')
|
|
492
480
|
|
|
493
|
-
|
|
494
|
-
expect(h('span', 'text').outerHTML).to.
|
|
495
|
-
expect(h('span', { $innerText: 'text' }).outerHTML).to.deep.equal('<span>text</span>')
|
|
496
|
-
```
|
|
481
|
+
expect(h('span', 'text').outerHTML).to.equal('<span>text</span>')
|
|
482
|
+
expect(h('span', { $innerText: 'text' }).outerHTML).to.equal('<span>text</span>')
|
|
497
483
|
|
|
498
|
-
|
|
499
|
-
expect(h('span',
|
|
500
|
-
expect(h('span', 42).outerHTML).to.deep.equal('<span>42</span>')
|
|
501
|
-
```
|
|
484
|
+
expect(h('span', '42').outerHTML).to.equal('<span>42</span>')
|
|
485
|
+
expect(h('span', 42).outerHTML).to.equal('<span>42</span>')
|
|
502
486
|
|
|
503
|
-
```ts
|
|
504
487
|
expect(h('div', { style: 'margin:0;padding:0' }).outerHTML)
|
|
505
|
-
.to.
|
|
488
|
+
.to.equal('<div style="margin:0;padding:0"></div>')
|
|
506
489
|
expect(h('div', { $style: 'margin:0;padding:0' }).outerHTML)
|
|
507
|
-
.to.
|
|
490
|
+
.to.equal('<div style="margin: 0px; padding: 0px;"></div>')
|
|
508
491
|
expect(h('div', { $style: { margin: 0, padding: 0 } }).outerHTML)
|
|
509
|
-
.to.
|
|
510
|
-
```
|
|
492
|
+
.to.equal('<div style="margin: 0px; padding: 0px;"></div>')
|
|
511
493
|
|
|
512
|
-
```ts
|
|
513
494
|
const input1 = h('input', { value: 42 })
|
|
514
495
|
const input2 = h('input', { $value: '42' })
|
|
515
496
|
|
|
516
|
-
expect(input1.value).to.
|
|
517
|
-
expect(input2.value).to.
|
|
497
|
+
expect(input1.value).to.equal('42')
|
|
498
|
+
expect(input2.value).to.equal('42')
|
|
518
499
|
|
|
519
|
-
expect(input1.outerHTML).to.
|
|
520
|
-
expect(input2.outerHTML).to.
|
|
500
|
+
expect(input1.outerHTML).to.equal('<input value="42">')
|
|
501
|
+
expect(input2.outerHTML).to.equal('<input>')
|
|
521
502
|
|
|
522
503
|
const checkbox1 = h('input', { type: 'checkbox', checked: true })
|
|
523
504
|
const checkbox2 = h('input', { type: 'checkbox', $checked: true })
|
|
@@ -525,11 +506,9 @@ const checkbox2 = h('input', { type: 'checkbox', $checked: true })
|
|
|
525
506
|
expect(checkbox1.checked).to.be.true
|
|
526
507
|
expect(checkbox2.checked).to.be.true
|
|
527
508
|
|
|
528
|
-
expect(checkbox1.outerHTML).to.
|
|
529
|
-
expect(checkbox2.outerHTML).to.
|
|
530
|
-
```
|
|
509
|
+
expect(checkbox1.outerHTML).to.equal('<input type="checkbox" checked="">')
|
|
510
|
+
expect(checkbox2.outerHTML).to.equal('<input type="checkbox">')
|
|
531
511
|
|
|
532
|
-
```ts
|
|
533
512
|
const div = h('div')
|
|
534
513
|
|
|
535
514
|
expect(div.key).to.be.undefined
|
|
@@ -618,6 +597,8 @@ The value to check.
|
|
|
618
597
|
|
|
619
598
|
```ts
|
|
620
599
|
expect(is_array([])).to.be.true
|
|
600
|
+
expect(is_array(Object.create({ constructor: Array }))).to.be.false
|
|
601
|
+
expect(is_array(Object.create({ [Symbol.toStringTag]: Array.name }))).to.be.false
|
|
621
602
|
```
|
|
622
603
|
|
|
623
604
|
### is_finite_number
|
|
@@ -700,6 +681,7 @@ expect(is_record(new Number(42))).to.be.true
|
|
|
700
681
|
expect(is_record(new String('42'))).to.be.true
|
|
701
682
|
|
|
702
683
|
class Foo_Bar { }
|
|
684
|
+
|
|
703
685
|
expect(is_record(new Foo_Bar())).to.be.true
|
|
704
686
|
```
|
|
705
687
|
|
|
@@ -810,15 +792,6 @@ const monokai: CRoot;
|
|
|
810
792
|
|
|
811
793
|
A Monokai-inspired color scheme for use with the [`c`](#c) helper and [`nanolight_ts`](#nanolight_ts) tokenizer.
|
|
812
794
|
|
|
813
|
-
Defines CSS custom properties for eight colors (`--black`, `--blue`, `--green`, `--grey`,
|
|
814
|
-
`--purple`, `--red`, `--white`, `--yellow`) with both light and dark mode variants.
|
|
815
|
-
|
|
816
|
-
#### Remarks
|
|
817
|
-
|
|
818
|
-
- In light mode, `--black` is a light background and `--white` is dark text.
|
|
819
|
-
- In dark mode (via `prefers-color-scheme: dark`), the palette inverts to a dark background with light text.
|
|
820
|
-
- Includes base styles for `body`, `pre` and `code>span.*` (syntax highlighting).
|
|
821
|
-
|
|
822
795
|
### nanolight_ts
|
|
823
796
|
|
|
824
797
|
```ts
|
|
@@ -841,25 +814,25 @@ An array of [`HArgs1`](#HArgs1) elements suitable for rendering with [`h`](#h).
|
|
|
841
814
|
const code_js = "const answer_to_life_the_universe_and_everything = { 42: 42 }['42'] /* 42 */"
|
|
842
815
|
|
|
843
816
|
expect(nanolight_ts(code_js)).to.deep.equal([
|
|
844
|
-
['span', { class: '
|
|
817
|
+
['span', { class: 'keyword-1' }, 'const'],
|
|
845
818
|
' ',
|
|
846
|
-
['span', { class: '
|
|
819
|
+
['span', { class: 'identifier-4' }, 'answer_to_life_the_universe_and_everything'],
|
|
847
820
|
' ',
|
|
848
|
-
['span', { class: '
|
|
821
|
+
['span', { class: 'operator' }, '='],
|
|
849
822
|
' ',
|
|
850
|
-
['span', { class: '
|
|
823
|
+
['span', { class: 'punctuation' }, '{'],
|
|
851
824
|
' ',
|
|
852
|
-
['span', { class: '
|
|
853
|
-
['span', { class: '
|
|
825
|
+
['span', { class: 'number' }, '42'],
|
|
826
|
+
['span', { class: 'operator' }, ':'],
|
|
854
827
|
' ',
|
|
855
|
-
['span', { class: '
|
|
828
|
+
['span', { class: 'number' }, '42'],
|
|
856
829
|
' ',
|
|
857
|
-
['span', { class: '
|
|
858
|
-
['span', { class: '
|
|
859
|
-
['span', { class: '
|
|
860
|
-
['span', { class: '
|
|
830
|
+
['span', { class: 'punctuation' }, '}'],
|
|
831
|
+
['span', { class: 'punctuation' }, '['],
|
|
832
|
+
['span', { class: 'string' }, "'42'"],
|
|
833
|
+
['span', { class: 'punctuation' }, ']'],
|
|
861
834
|
' ',
|
|
862
|
-
['span', { class: '
|
|
835
|
+
['span', { class: 'comment' }, '/* 42 */']
|
|
863
836
|
])
|
|
864
837
|
```
|
|
865
838
|
|
|
@@ -904,7 +877,7 @@ const expected = `
|
|
|
904
877
|
FROM table_name
|
|
905
878
|
WHERE column_name IN (b'1', NULL, NULL, 42, '42', '4''2', '1980-03-31 04:30:00')`
|
|
906
879
|
|
|
907
|
-
expect(actual).to.
|
|
880
|
+
expect(actual).to.equal(expected)
|
|
908
881
|
```
|
|
909
882
|
|
|
910
883
|
### new_noun_form
|
|
@@ -915,8 +888,8 @@ const new_noun_form: (locale: string, forms: Partial<Record<Intl.LDMLPluralRule,
|
|
|
915
888
|
|
|
916
889
|
Creates a function that returns the appropriate noun form based on a numeric value using `Intl.PluralRules`.
|
|
917
890
|
|
|
918
|
-
Different languages have different plural rules. The `Intl.PluralRules` API provides
|
|
919
|
-
|
|
891
|
+
Different languages have different plural rules. The `Intl.PluralRules` API provides locale-aware plural category selection.
|
|
892
|
+
Possible categories are:
|
|
920
893
|
|
|
921
894
|
- `zero`: for zero items (used in some languages like Arabic, Latvian)
|
|
922
895
|
- `one`: for singular (e.g., 1 item)
|
|
@@ -943,17 +916,17 @@ A function that takes a numeric value and returns the appropriate noun form.
|
|
|
943
916
|
```ts
|
|
944
917
|
const auto = new_noun_form('pl', { one: 'auto', few: 'auta', other: 'aut' })
|
|
945
918
|
|
|
946
|
-
expect(auto(0)).to.
|
|
947
|
-
expect(auto(1)).to.
|
|
948
|
-
expect(auto(17)).to.
|
|
949
|
-
expect(auto(42)).to.
|
|
919
|
+
expect(auto(0)).to.equal('aut')
|
|
920
|
+
expect(auto(1)).to.equal('auto')
|
|
921
|
+
expect(auto(17)).to.equal('aut')
|
|
922
|
+
expect(auto(42)).to.equal('auta')
|
|
950
923
|
|
|
951
924
|
const car = new_noun_form('en', { one: 'car', other: 'cars' })
|
|
952
925
|
|
|
953
|
-
expect(car(0)).to.
|
|
954
|
-
expect(car(1)).to.
|
|
955
|
-
expect(car(17)).to.
|
|
956
|
-
expect(car(42)).to.
|
|
926
|
+
expect(car(0)).to.equal('cars')
|
|
927
|
+
expect(car(1)).to.equal('car')
|
|
928
|
+
expect(car(17)).to.equal('cars')
|
|
929
|
+
expect(car(42)).to.equal('cars')
|
|
957
930
|
```
|
|
958
931
|
|
|
959
932
|
### new_tokenizer
|
|
@@ -1011,9 +984,9 @@ A new object without the specified keys.
|
|
|
1011
984
|
#### Usage Examples
|
|
1012
985
|
|
|
1013
986
|
```ts
|
|
1014
|
-
const
|
|
987
|
+
const ref = { a: 42, b: '42', c: 17 }
|
|
1015
988
|
|
|
1016
|
-
expect(omit(
|
|
989
|
+
expect(omit(ref, ['c'])).to.deep.equal({ a: 42, b: '42' })
|
|
1017
990
|
```
|
|
1018
991
|
|
|
1019
992
|
### pick
|
|
@@ -1041,9 +1014,9 @@ A new object with only the specified keys.
|
|
|
1041
1014
|
#### Usage Examples
|
|
1042
1015
|
|
|
1043
1016
|
```ts
|
|
1044
|
-
const
|
|
1017
|
+
const ref = { a: 42, b: '42', c: 17 }
|
|
1045
1018
|
|
|
1046
|
-
expect(pick(
|
|
1019
|
+
expect(pick(ref, ['a', 'b'])).to.deep.equal({ a: 42, b: '42' })
|
|
1047
1020
|
```
|
|
1048
1021
|
|
|
1049
1022
|
### rwd
|
|
@@ -1134,8 +1107,7 @@ const s: {
|
|
|
1134
1107
|
};
|
|
1135
1108
|
```
|
|
1136
1109
|
|
|
1137
|
-
A lightweight [HyperScript](https://github.com/hyperhype/hyperscript)-style helper
|
|
1138
|
-
for creating and modifying `SVGElement`s (see also [`h`](#h)).
|
|
1110
|
+
A lightweight [HyperScript](https://github.com/hyperhype/hyperscript)-style helper for creating and modifying `SVGElement`s (see also [`h`](#h)).
|
|
1139
1111
|
|
|
1140
1112
|
#### tag_or_node
|
|
1141
1113
|
|
|
@@ -1206,41 +1178,37 @@ for (let i = 1; i <= 22136; ++i) {
|
|
|
1206
1178
|
const uuid = uuid_v1()
|
|
1207
1179
|
|
|
1208
1180
|
if (i === 1) {
|
|
1209
|
-
expect(uuid.split('-')[3]).to.
|
|
1181
|
+
expect(uuid.split('-')[3]).to.equal('8001')
|
|
1210
1182
|
}
|
|
1211
1183
|
|
|
1212
1184
|
if (i === 4095) {
|
|
1213
|
-
expect(uuid.split('-')[3]).to.
|
|
1185
|
+
expect(uuid.split('-')[3]).to.equal('8fff')
|
|
1214
1186
|
}
|
|
1215
1187
|
|
|
1216
1188
|
if (i === 4096) {
|
|
1217
|
-
expect(uuid.split('-')[3]).to.
|
|
1189
|
+
expect(uuid.split('-')[3]).to.equal('9000')
|
|
1218
1190
|
}
|
|
1219
1191
|
|
|
1220
1192
|
if (i === 9029) {
|
|
1221
|
-
expect(uuid.split('-')[3]).to.
|
|
1193
|
+
expect(uuid.split('-')[3]).to.equal('a345')
|
|
1222
1194
|
}
|
|
1223
1195
|
|
|
1224
1196
|
if (i === 13398) {
|
|
1225
|
-
expect(uuid.split('-')[3]).to.
|
|
1197
|
+
expect(uuid.split('-')[3]).to.equal('b456')
|
|
1226
1198
|
}
|
|
1227
1199
|
|
|
1228
1200
|
if (i === 16384) {
|
|
1229
|
-
expect(uuid.split('-')[3]).to.
|
|
1201
|
+
expect(uuid.split('-')[3]).to.equal('8000')
|
|
1230
1202
|
}
|
|
1231
1203
|
|
|
1232
1204
|
if (i === 17767) {
|
|
1233
|
-
expect(uuid.split('-')[3]).to.
|
|
1205
|
+
expect(uuid.split('-')[3]).to.equal('8567')
|
|
1234
1206
|
}
|
|
1235
1207
|
}
|
|
1236
|
-
```
|
|
1237
1208
|
|
|
1238
|
-
|
|
1239
|
-
expect(uuid_v1(new Date(), '
|
|
1240
|
-
expect(uuid_v1(new Date(), '123456789').split('-')[4]).to.deep.equal('000123456789')
|
|
1241
|
-
```
|
|
1209
|
+
expect(uuid_v1(new Date(), '000123456789abc').split('-')[4]).to.equal('123456789abc')
|
|
1210
|
+
expect(uuid_v1(new Date(), '123456789').split('-')[4]).to.equal('000123456789')
|
|
1242
1211
|
|
|
1243
|
-
```ts
|
|
1244
1212
|
expect(uuid_v1(new Date(323325000000)).startsWith('c1399400-9a71-11bd')).to.be.true
|
|
1245
1213
|
```
|
|
1246
1214
|
|
|
@@ -1258,14 +1226,14 @@ Accessing, assigning, or deleting any nested property on the returned proxy auto
|
|
|
1258
1226
|
Intermediates of the last level in a get-only property chain are NOT auto-created.
|
|
1259
1227
|
For example, `vivify(ref).one.two` will create `ref.one` as `{}`, but will NOT create `ref.one.two`.
|
|
1260
1228
|
Only when a deeper access, assignment, or deletion occurs
|
|
1261
|
-
(e.g. `vivify(ref).one.two
|
|
1229
|
+
(e.g. `delete vivify(ref).one.two.three` or `vivify(ref).one.two.three = 4`) will `ref.one.two` be materialized.
|
|
1262
1230
|
|
|
1263
1231
|
When traversal reaches a primitive value, no auto-creation happens;
|
|
1264
1232
|
the primitive’s own property is returned instead
|
|
1265
1233
|
(e.g. accessing `.toString.name` on a number yields `'toString'` without modifying the underlying structure).
|
|
1266
1234
|
|
|
1267
1235
|
Deletion on a non-existing intermediate path will auto-create intermediates up to the parent of the deleted key
|
|
1268
|
-
(e.g. `delete vivify(ref).
|
|
1236
|
+
(e.g. `delete vivify(ref).one.two.three` will create `ref.one.two` as `{}` if it does not exist).
|
|
1269
1237
|
|
|
1270
1238
|
#### ref
|
|
1271
1239
|
|
|
@@ -1280,33 +1248,49 @@ A proxy that auto-creates nested objects/arrays on property access.
|
|
|
1280
1248
|
```ts
|
|
1281
1249
|
const ref: any = {}
|
|
1282
1250
|
|
|
1283
|
-
vivify(ref).one.two[
|
|
1284
|
-
|
|
1285
|
-
expect(ref).to.deep.equal({ one: { two: [undefined, [undefined, undefined, 42]] } })
|
|
1286
|
-
|
|
1287
|
-
vivify(ref).one.two[1][3] = 42
|
|
1251
|
+
vivify(ref).one.two[3][4]
|
|
1288
1252
|
|
|
1289
|
-
expect(ref).to.deep.equal({
|
|
1253
|
+
expect(ref).to.deep.equal({
|
|
1254
|
+
one: {
|
|
1255
|
+
two: [undefined, undefined, undefined, []]
|
|
1256
|
+
}
|
|
1257
|
+
})
|
|
1290
1258
|
|
|
1291
|
-
vivify(ref).one.two[
|
|
1259
|
+
vivify(ref).one.two[3][4] = 5
|
|
1292
1260
|
|
|
1293
|
-
expect(ref).to.deep.equal({
|
|
1261
|
+
expect(ref).to.deep.equal({
|
|
1262
|
+
one: {
|
|
1263
|
+
two: [undefined, undefined, undefined, [undefined, undefined, undefined, undefined, 5]]
|
|
1264
|
+
}
|
|
1265
|
+
})
|
|
1294
1266
|
|
|
1295
|
-
vivify(ref).one.two[3]
|
|
1267
|
+
vivify(ref).one.two[3].length = 1
|
|
1296
1268
|
|
|
1297
|
-
expect(ref).to.deep.equal({
|
|
1269
|
+
expect(ref).to.deep.equal({
|
|
1270
|
+
one: {
|
|
1271
|
+
two: [undefined, undefined, undefined, [undefined]]
|
|
1272
|
+
}
|
|
1273
|
+
})
|
|
1298
1274
|
|
|
1299
|
-
vivify(ref).one.two[3]
|
|
1275
|
+
vivify(ref).one.two[3] = 4
|
|
1300
1276
|
|
|
1301
|
-
expect(ref).to.deep.equal({
|
|
1277
|
+
expect(ref).to.deep.equal({
|
|
1278
|
+
one: {
|
|
1279
|
+
two: [undefined, undefined, undefined, 4]
|
|
1280
|
+
}
|
|
1281
|
+
})
|
|
1302
1282
|
|
|
1303
|
-
expect(vivify(ref).one.two.length).to.
|
|
1283
|
+
expect(vivify(ref).one.two.length).to.equal(4)
|
|
1304
1284
|
|
|
1305
|
-
expect(ref).to.deep.equal({
|
|
1285
|
+
expect(ref).to.deep.equal({
|
|
1286
|
+
one: {
|
|
1287
|
+
two: [undefined, undefined, undefined, 4]
|
|
1288
|
+
}
|
|
1289
|
+
})
|
|
1306
1290
|
|
|
1307
|
-
vivify(ref).one.two =
|
|
1291
|
+
vivify(ref).one.two = 3
|
|
1308
1292
|
|
|
1309
|
-
expect(ref).to.deep.equal({ one: { two:
|
|
1293
|
+
expect(ref).to.deep.equal({ one: { two: 3 } })
|
|
1310
1294
|
|
|
1311
1295
|
vivify(ref).one.two = undefined
|
|
1312
1296
|
|
|
@@ -1334,13 +1318,13 @@ vivify(ref).one.two[3]
|
|
|
1334
1318
|
|
|
1335
1319
|
expect(ref).to.deep.equal({ one: { two: { three: {} } } })
|
|
1336
1320
|
|
|
1337
|
-
vivify(ref).one.two.three.four =
|
|
1321
|
+
vivify(ref).one.two.three.four = 5
|
|
1338
1322
|
|
|
1339
|
-
expect(ref).to.deep.equal({ one: { two: { three: { four:
|
|
1323
|
+
expect(ref).to.deep.equal({ one: { two: { three: { four: 5 } } } })
|
|
1340
1324
|
|
|
1341
|
-
expect(vivify(ref).one.two.three.four.toString.name).to.
|
|
1325
|
+
expect(vivify(ref).one.two.three.four.toString.name).to.equal('toString')
|
|
1342
1326
|
|
|
1343
|
-
expect(ref).to.deep.equal({ one: { two: { three: { four:
|
|
1327
|
+
expect(ref).to.deep.equal({ one: { two: { three: { four: 5 } } } })
|
|
1344
1328
|
```
|
|
1345
1329
|
|
|
1346
1330
|
## License
|