@jackens/nnn 2026.2.13 → 2026.2.18
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 +148 -112
- package/package.json +1 -1
- package/readme.md +125 -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,72 @@ 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
|
+
body$$monokai: {
|
|
205
|
+
backgroundColor: "var(--bg)",
|
|
206
|
+
color: "var(--fg)"
|
|
207
|
+
},
|
|
208
|
+
"code>span.": {
|
|
209
|
+
bg: { color: "var(--bg)" },
|
|
210
|
+
fg: { color: "var(--fg)" },
|
|
211
|
+
comment: { color: "var(--comment)" },
|
|
212
|
+
"identifier-1": { color: "var(--identifier-1)" },
|
|
213
|
+
"identifier-2": { color: "var(--identifier-2)" },
|
|
214
|
+
"identifier-3": { color: "var(--identifier-3)" },
|
|
215
|
+
"identifier-4": { color: "var(--identifier-4)" },
|
|
216
|
+
"keyword-1": { color: "var(--keyword-1)" },
|
|
217
|
+
"keyword-2": { color: "var(--keyword-2)" },
|
|
218
|
+
"keyword-3": { color: "var(--keyword-3)" },
|
|
219
|
+
number: { color: "var(--number)" },
|
|
220
|
+
operator: { color: "var(--operator)" },
|
|
221
|
+
punctuation: { color: "var(--punctuation)" },
|
|
222
|
+
string: { color: "var(--string)" }
|
|
223
|
+
},
|
|
224
|
+
pre: {
|
|
225
|
+
margin: 0,
|
|
226
|
+
overflow: "visible",
|
|
227
|
+
" code": {
|
|
228
|
+
fontFamily: '"Source Code Pro"',
|
|
229
|
+
padding: 0
|
|
230
|
+
}
|
|
231
|
+
},
|
|
232
|
+
"@media only screen and (prefers-color-scheme: dark)": {
|
|
233
|
+
":root": {
|
|
234
|
+
__bg: "#2d2a2e",
|
|
235
|
+
__fg: "#fcfcfa",
|
|
236
|
+
__comment: "#727072",
|
|
237
|
+
__identifier_1: "#ae81ff",
|
|
238
|
+
__identifier_2: "#a9dc76",
|
|
239
|
+
__identifier_3: "#66d9ef",
|
|
240
|
+
__identifier_4: "#fcfcfa",
|
|
241
|
+
__keyword_1: "#ff6188",
|
|
242
|
+
__keyword_2: "#ae81ff",
|
|
243
|
+
__keyword_3: "#66d9ef",
|
|
244
|
+
__number: "#ae81ff",
|
|
245
|
+
__operator: "#ff6188",
|
|
246
|
+
__punctuation: "#727072",
|
|
247
|
+
__string: "#ffd866"
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
};
|
|
251
|
+
// src/nnn/new_tokenizer.ts
|
|
236
252
|
var new_tokenizer = (decorator, ...specs) => (code) => {
|
|
237
253
|
const result = [];
|
|
238
254
|
while (code.length > 0) {
|
|
@@ -270,60 +286,80 @@ var new_tokenizer = (decorator, ...specs) => (code) => {
|
|
|
270
286
|
}
|
|
271
287
|
return result;
|
|
272
288
|
};
|
|
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
|
-
|
|
289
|
+
|
|
290
|
+
// src/nnn/nanolight_ts.ts
|
|
291
|
+
var COMMENT = "comment";
|
|
292
|
+
var IDENTIFIER_1 = "identifier-1";
|
|
293
|
+
var IDENTIFIER_2 = "identifier-2";
|
|
294
|
+
var IDENTIFIER_3 = "identifier-3";
|
|
295
|
+
var IDENTIFIER_4 = "identifier-4";
|
|
296
|
+
var KEYWORD_1 = "keyword-1";
|
|
297
|
+
var KEYWORD_2 = "keyword-2";
|
|
298
|
+
var KEYWORD_3 = "keyword-3";
|
|
299
|
+
var NUMBER = "number";
|
|
300
|
+
var OPERATOR = "operator";
|
|
301
|
+
var PUNCTUATION = "punctuation";
|
|
302
|
+
var STRING = "string";
|
|
303
|
+
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]);
|
|
304
|
+
// src/nnn/new_escape.ts
|
|
305
|
+
var escape_values = (escape_map, values) => values.map((value) => (value == null ? escape_map.get(value) : escape_map.get(value?.constructor))?.(value) ?? "");
|
|
306
|
+
var new_escape = (escape_map) => (template, ...values) => String.raw(template, ...escape_values(escape_map, values));
|
|
307
|
+
// src/nnn/new_noun_form.ts
|
|
308
|
+
var PLURAL_RULES = {};
|
|
309
|
+
var new_noun_form = (locale, forms) => (value) => forms[(PLURAL_RULES[locale] ??= new Intl.PluralRules(locale)).select(value)] ?? forms.other ?? "";
|
|
310
|
+
// src/nnn/omit.ts
|
|
311
|
+
var omit = (ref, keys) => Object.fromEntries(Object.entries(ref).filter(([key]) => !keys.includes(key)));
|
|
312
|
+
// src/nnn/pick.ts
|
|
313
|
+
var pick = (ref, keys) => Object.fromEntries(Object.entries(ref).filter(([key]) => keys.includes(key)));
|
|
314
|
+
// src/nnn/vivify.ts
|
|
315
|
+
var ARRAY_INDEX_REGEXP = /^(0|[1-9]\d*)$/;
|
|
316
|
+
var is_object = (ref) => typeof ref === "object";
|
|
317
|
+
var get_target = (parent, parent_key, key) => parent[parent_key] ??= is_string(key) && ARRAY_INDEX_REGEXP.test(key) ? [] : {};
|
|
318
|
+
var _vivify = (parent, parent_key) => {
|
|
319
|
+
return parent != null && is_object(parent) ? new Proxy(parent, {
|
|
320
|
+
get(_, key) {
|
|
321
|
+
const target = get_target(parent, parent_key, key);
|
|
322
|
+
const value = target[key];
|
|
323
|
+
return is_string(key) && is_object(target) && (value == null || is_object(value)) ? _vivify(target, key) : value;
|
|
324
|
+
},
|
|
325
|
+
set(_, key, value) {
|
|
326
|
+
const target = get_target(parent, parent_key, key);
|
|
327
|
+
target[key] = value;
|
|
328
|
+
return true;
|
|
329
|
+
},
|
|
330
|
+
deleteProperty(_, key) {
|
|
331
|
+
const target = get_target(parent, parent_key, key);
|
|
332
|
+
return delete target[key];
|
|
312
333
|
}
|
|
313
|
-
}
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
334
|
+
}) : parent?.[parent_key];
|
|
335
|
+
};
|
|
336
|
+
var vivify = (ref) => _vivify({ _: ref }, "_");
|
|
337
|
+
|
|
338
|
+
// src/nnn/rwd.ts
|
|
339
|
+
var rwd = (root, selector, cell_width_px, cell_height_px, ...specs) => {
|
|
340
|
+
const main = vivify(root)[selector];
|
|
341
|
+
main.boxSizing = "border-box";
|
|
342
|
+
main.display = "block";
|
|
343
|
+
main.float = "left";
|
|
344
|
+
main.width = "100%";
|
|
345
|
+
main.height = `${cell_height_px}px`;
|
|
346
|
+
specs.sort(([a], [b]) => a - b);
|
|
347
|
+
for (let [max_width, width, height] of specs) {
|
|
348
|
+
const node = max_width === 1 ? main : vivify(root)[`@media(min-width:${cell_width_px * max_width}px)`][selector];
|
|
349
|
+
width ??= 1;
|
|
350
|
+
height ??= 1;
|
|
351
|
+
let gcd = 100 * width;
|
|
352
|
+
let tmp = max_width;
|
|
353
|
+
while (tmp > 0) {
|
|
354
|
+
[gcd, tmp] = [tmp, gcd % tmp];
|
|
324
355
|
}
|
|
356
|
+
const w_100_per_gcd = 100 * width / gcd;
|
|
357
|
+
node.width = max_width === gcd ? `${w_100_per_gcd}%` : `calc(${w_100_per_gcd}% / ${max_width / gcd})`;
|
|
358
|
+
node.height = `${cell_height_px * height}px`;
|
|
325
359
|
}
|
|
326
360
|
};
|
|
361
|
+
// src/nnn/svg_use.ts
|
|
362
|
+
var svg_use = (id, ...args) => s("svg", ["use", { "xlink:href": "#" + id }], ...args);
|
|
327
363
|
// src/nnn/uuid_v1.ts
|
|
328
364
|
var ZEROS = /* @__PURE__ */ "0".repeat(16);
|
|
329
365
|
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.18`).
|
|
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
|
|
@@ -700,6 +679,7 @@ expect(is_record(new Number(42))).to.be.true
|
|
|
700
679
|
expect(is_record(new String('42'))).to.be.true
|
|
701
680
|
|
|
702
681
|
class Foo_Bar { }
|
|
682
|
+
|
|
703
683
|
expect(is_record(new Foo_Bar())).to.be.true
|
|
704
684
|
```
|
|
705
685
|
|
|
@@ -810,15 +790,6 @@ const monokai: CRoot;
|
|
|
810
790
|
|
|
811
791
|
A Monokai-inspired color scheme for use with the [`c`](#c) helper and [`nanolight_ts`](#nanolight_ts) tokenizer.
|
|
812
792
|
|
|
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
793
|
### nanolight_ts
|
|
823
794
|
|
|
824
795
|
```ts
|
|
@@ -841,25 +812,25 @@ An array of [`HArgs1`](#HArgs1) elements suitable for rendering with [`h`](#h).
|
|
|
841
812
|
const code_js = "const answer_to_life_the_universe_and_everything = { 42: 42 }['42'] /* 42 */"
|
|
842
813
|
|
|
843
814
|
expect(nanolight_ts(code_js)).to.deep.equal([
|
|
844
|
-
['span', { class: '
|
|
815
|
+
['span', { class: 'keyword-1' }, 'const'],
|
|
845
816
|
' ',
|
|
846
|
-
['span', { class: '
|
|
817
|
+
['span', { class: 'identifier-4' }, 'answer_to_life_the_universe_and_everything'],
|
|
847
818
|
' ',
|
|
848
|
-
['span', { class: '
|
|
819
|
+
['span', { class: 'operator' }, '='],
|
|
849
820
|
' ',
|
|
850
|
-
['span', { class: '
|
|
821
|
+
['span', { class: 'punctuation' }, '{'],
|
|
851
822
|
' ',
|
|
852
|
-
['span', { class: '
|
|
853
|
-
['span', { class: '
|
|
823
|
+
['span', { class: 'number' }, '42'],
|
|
824
|
+
['span', { class: 'operator' }, ':'],
|
|
854
825
|
' ',
|
|
855
|
-
['span', { class: '
|
|
826
|
+
['span', { class: 'number' }, '42'],
|
|
856
827
|
' ',
|
|
857
|
-
['span', { class: '
|
|
858
|
-
['span', { class: '
|
|
859
|
-
['span', { class: '
|
|
860
|
-
['span', { class: '
|
|
828
|
+
['span', { class: 'punctuation' }, '}'],
|
|
829
|
+
['span', { class: 'punctuation' }, '['],
|
|
830
|
+
['span', { class: 'string' }, "'42'"],
|
|
831
|
+
['span', { class: 'punctuation' }, ']'],
|
|
861
832
|
' ',
|
|
862
|
-
['span', { class: '
|
|
833
|
+
['span', { class: 'comment' }, '/* 42 */']
|
|
863
834
|
])
|
|
864
835
|
```
|
|
865
836
|
|
|
@@ -904,7 +875,7 @@ const expected = `
|
|
|
904
875
|
FROM table_name
|
|
905
876
|
WHERE column_name IN (b'1', NULL, NULL, 42, '42', '4''2', '1980-03-31 04:30:00')`
|
|
906
877
|
|
|
907
|
-
expect(actual).to.
|
|
878
|
+
expect(actual).to.equal(expected)
|
|
908
879
|
```
|
|
909
880
|
|
|
910
881
|
### new_noun_form
|
|
@@ -915,8 +886,8 @@ const new_noun_form: (locale: string, forms: Partial<Record<Intl.LDMLPluralRule,
|
|
|
915
886
|
|
|
916
887
|
Creates a function that returns the appropriate noun form based on a numeric value using `Intl.PluralRules`.
|
|
917
888
|
|
|
918
|
-
Different languages have different plural rules. The `Intl.PluralRules` API provides
|
|
919
|
-
|
|
889
|
+
Different languages have different plural rules. The `Intl.PluralRules` API provides locale-aware plural category selection.
|
|
890
|
+
Possible categories are:
|
|
920
891
|
|
|
921
892
|
- `zero`: for zero items (used in some languages like Arabic, Latvian)
|
|
922
893
|
- `one`: for singular (e.g., 1 item)
|
|
@@ -943,17 +914,17 @@ A function that takes a numeric value and returns the appropriate noun form.
|
|
|
943
914
|
```ts
|
|
944
915
|
const auto = new_noun_form('pl', { one: 'auto', few: 'auta', other: 'aut' })
|
|
945
916
|
|
|
946
|
-
expect(auto(0)).to.
|
|
947
|
-
expect(auto(1)).to.
|
|
948
|
-
expect(auto(17)).to.
|
|
949
|
-
expect(auto(42)).to.
|
|
917
|
+
expect(auto(0)).to.equal('aut')
|
|
918
|
+
expect(auto(1)).to.equal('auto')
|
|
919
|
+
expect(auto(17)).to.equal('aut')
|
|
920
|
+
expect(auto(42)).to.equal('auta')
|
|
950
921
|
|
|
951
922
|
const car = new_noun_form('en', { one: 'car', other: 'cars' })
|
|
952
923
|
|
|
953
|
-
expect(car(0)).to.
|
|
954
|
-
expect(car(1)).to.
|
|
955
|
-
expect(car(17)).to.
|
|
956
|
-
expect(car(42)).to.
|
|
924
|
+
expect(car(0)).to.equal('cars')
|
|
925
|
+
expect(car(1)).to.equal('car')
|
|
926
|
+
expect(car(17)).to.equal('cars')
|
|
927
|
+
expect(car(42)).to.equal('cars')
|
|
957
928
|
```
|
|
958
929
|
|
|
959
930
|
### new_tokenizer
|
|
@@ -1011,9 +982,9 @@ A new object without the specified keys.
|
|
|
1011
982
|
#### Usage Examples
|
|
1012
983
|
|
|
1013
984
|
```ts
|
|
1014
|
-
const
|
|
985
|
+
const ref = { a: 42, b: '42', c: 17 }
|
|
1015
986
|
|
|
1016
|
-
expect(omit(
|
|
987
|
+
expect(omit(ref, ['c'])).to.deep.equal({ a: 42, b: '42' })
|
|
1017
988
|
```
|
|
1018
989
|
|
|
1019
990
|
### pick
|
|
@@ -1041,9 +1012,9 @@ A new object with only the specified keys.
|
|
|
1041
1012
|
#### Usage Examples
|
|
1042
1013
|
|
|
1043
1014
|
```ts
|
|
1044
|
-
const
|
|
1015
|
+
const ref = { a: 42, b: '42', c: 17 }
|
|
1045
1016
|
|
|
1046
|
-
expect(pick(
|
|
1017
|
+
expect(pick(ref, ['a', 'b'])).to.deep.equal({ a: 42, b: '42' })
|
|
1047
1018
|
```
|
|
1048
1019
|
|
|
1049
1020
|
### rwd
|
|
@@ -1134,8 +1105,7 @@ const s: {
|
|
|
1134
1105
|
};
|
|
1135
1106
|
```
|
|
1136
1107
|
|
|
1137
|
-
A lightweight [HyperScript](https://github.com/hyperhype/hyperscript)-style helper
|
|
1138
|
-
for creating and modifying `SVGElement`s (see also [`h`](#h)).
|
|
1108
|
+
A lightweight [HyperScript](https://github.com/hyperhype/hyperscript)-style helper for creating and modifying `SVGElement`s (see also [`h`](#h)).
|
|
1139
1109
|
|
|
1140
1110
|
#### tag_or_node
|
|
1141
1111
|
|
|
@@ -1206,41 +1176,37 @@ for (let i = 1; i <= 22136; ++i) {
|
|
|
1206
1176
|
const uuid = uuid_v1()
|
|
1207
1177
|
|
|
1208
1178
|
if (i === 1) {
|
|
1209
|
-
expect(uuid.split('-')[3]).to.
|
|
1179
|
+
expect(uuid.split('-')[3]).to.equal('8001')
|
|
1210
1180
|
}
|
|
1211
1181
|
|
|
1212
1182
|
if (i === 4095) {
|
|
1213
|
-
expect(uuid.split('-')[3]).to.
|
|
1183
|
+
expect(uuid.split('-')[3]).to.equal('8fff')
|
|
1214
1184
|
}
|
|
1215
1185
|
|
|
1216
1186
|
if (i === 4096) {
|
|
1217
|
-
expect(uuid.split('-')[3]).to.
|
|
1187
|
+
expect(uuid.split('-')[3]).to.equal('9000')
|
|
1218
1188
|
}
|
|
1219
1189
|
|
|
1220
1190
|
if (i === 9029) {
|
|
1221
|
-
expect(uuid.split('-')[3]).to.
|
|
1191
|
+
expect(uuid.split('-')[3]).to.equal('a345')
|
|
1222
1192
|
}
|
|
1223
1193
|
|
|
1224
1194
|
if (i === 13398) {
|
|
1225
|
-
expect(uuid.split('-')[3]).to.
|
|
1195
|
+
expect(uuid.split('-')[3]).to.equal('b456')
|
|
1226
1196
|
}
|
|
1227
1197
|
|
|
1228
1198
|
if (i === 16384) {
|
|
1229
|
-
expect(uuid.split('-')[3]).to.
|
|
1199
|
+
expect(uuid.split('-')[3]).to.equal('8000')
|
|
1230
1200
|
}
|
|
1231
1201
|
|
|
1232
1202
|
if (i === 17767) {
|
|
1233
|
-
expect(uuid.split('-')[3]).to.
|
|
1203
|
+
expect(uuid.split('-')[3]).to.equal('8567')
|
|
1234
1204
|
}
|
|
1235
1205
|
}
|
|
1236
|
-
```
|
|
1237
1206
|
|
|
1238
|
-
|
|
1239
|
-
expect(uuid_v1(new Date(), '
|
|
1240
|
-
expect(uuid_v1(new Date(), '123456789').split('-')[4]).to.deep.equal('000123456789')
|
|
1241
|
-
```
|
|
1207
|
+
expect(uuid_v1(new Date(), '000123456789abc').split('-')[4]).to.equal('123456789abc')
|
|
1208
|
+
expect(uuid_v1(new Date(), '123456789').split('-')[4]).to.equal('000123456789')
|
|
1242
1209
|
|
|
1243
|
-
```ts
|
|
1244
1210
|
expect(uuid_v1(new Date(323325000000)).startsWith('c1399400-9a71-11bd')).to.be.true
|
|
1245
1211
|
```
|
|
1246
1212
|
|
|
@@ -1258,14 +1224,14 @@ Accessing, assigning, or deleting any nested property on the returned proxy auto
|
|
|
1258
1224
|
Intermediates of the last level in a get-only property chain are NOT auto-created.
|
|
1259
1225
|
For example, `vivify(ref).one.two` will create `ref.one` as `{}`, but will NOT create `ref.one.two`.
|
|
1260
1226
|
Only when a deeper access, assignment, or deletion occurs
|
|
1261
|
-
(e.g. `vivify(ref).one.two
|
|
1227
|
+
(e.g. `delete vivify(ref).one.two.three` or `vivify(ref).one.two.three = 4`) will `ref.one.two` be materialized.
|
|
1262
1228
|
|
|
1263
1229
|
When traversal reaches a primitive value, no auto-creation happens;
|
|
1264
1230
|
the primitive’s own property is returned instead
|
|
1265
1231
|
(e.g. accessing `.toString.name` on a number yields `'toString'` without modifying the underlying structure).
|
|
1266
1232
|
|
|
1267
1233
|
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).
|
|
1234
|
+
(e.g. `delete vivify(ref).one.two.three` will create `ref.one.two` as `{}` if it does not exist).
|
|
1269
1235
|
|
|
1270
1236
|
#### ref
|
|
1271
1237
|
|
|
@@ -1280,33 +1246,49 @@ A proxy that auto-creates nested objects/arrays on property access.
|
|
|
1280
1246
|
```ts
|
|
1281
1247
|
const ref: any = {}
|
|
1282
1248
|
|
|
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
|
|
1249
|
+
vivify(ref).one.two[3][4]
|
|
1288
1250
|
|
|
1289
|
-
expect(ref).to.deep.equal({
|
|
1251
|
+
expect(ref).to.deep.equal({
|
|
1252
|
+
one: {
|
|
1253
|
+
two: [undefined, undefined, undefined, []]
|
|
1254
|
+
}
|
|
1255
|
+
})
|
|
1290
1256
|
|
|
1291
|
-
vivify(ref).one.two[
|
|
1257
|
+
vivify(ref).one.two[3][4] = 5
|
|
1292
1258
|
|
|
1293
|
-
expect(ref).to.deep.equal({
|
|
1259
|
+
expect(ref).to.deep.equal({
|
|
1260
|
+
one: {
|
|
1261
|
+
two: [undefined, undefined, undefined, [undefined, undefined, undefined, undefined, 5]]
|
|
1262
|
+
}
|
|
1263
|
+
})
|
|
1294
1264
|
|
|
1295
|
-
vivify(ref).one.two[3]
|
|
1265
|
+
vivify(ref).one.two[3].length = 1
|
|
1296
1266
|
|
|
1297
|
-
expect(ref).to.deep.equal({
|
|
1267
|
+
expect(ref).to.deep.equal({
|
|
1268
|
+
one: {
|
|
1269
|
+
two: [undefined, undefined, undefined, [undefined]]
|
|
1270
|
+
}
|
|
1271
|
+
})
|
|
1298
1272
|
|
|
1299
|
-
vivify(ref).one.two[3]
|
|
1273
|
+
vivify(ref).one.two[3] = 4
|
|
1300
1274
|
|
|
1301
|
-
expect(ref).to.deep.equal({
|
|
1275
|
+
expect(ref).to.deep.equal({
|
|
1276
|
+
one: {
|
|
1277
|
+
two: [undefined, undefined, undefined, 4]
|
|
1278
|
+
}
|
|
1279
|
+
})
|
|
1302
1280
|
|
|
1303
|
-
expect(vivify(ref).one.two.length).to.
|
|
1281
|
+
expect(vivify(ref).one.two.length).to.equal(4)
|
|
1304
1282
|
|
|
1305
|
-
expect(ref).to.deep.equal({
|
|
1283
|
+
expect(ref).to.deep.equal({
|
|
1284
|
+
one: {
|
|
1285
|
+
two: [undefined, undefined, undefined, 4]
|
|
1286
|
+
}
|
|
1287
|
+
})
|
|
1306
1288
|
|
|
1307
|
-
vivify(ref).one.two =
|
|
1289
|
+
vivify(ref).one.two = 3
|
|
1308
1290
|
|
|
1309
|
-
expect(ref).to.deep.equal({ one: { two:
|
|
1291
|
+
expect(ref).to.deep.equal({ one: { two: 3 } })
|
|
1310
1292
|
|
|
1311
1293
|
vivify(ref).one.two = undefined
|
|
1312
1294
|
|
|
@@ -1334,13 +1316,13 @@ vivify(ref).one.two[3]
|
|
|
1334
1316
|
|
|
1335
1317
|
expect(ref).to.deep.equal({ one: { two: { three: {} } } })
|
|
1336
1318
|
|
|
1337
|
-
vivify(ref).one.two.three.four =
|
|
1319
|
+
vivify(ref).one.two.three.four = 5
|
|
1338
1320
|
|
|
1339
|
-
expect(ref).to.deep.equal({ one: { two: { three: { four:
|
|
1321
|
+
expect(ref).to.deep.equal({ one: { two: { three: { four: 5 } } } })
|
|
1340
1322
|
|
|
1341
|
-
expect(vivify(ref).one.two.three.four.toString.name).to.
|
|
1323
|
+
expect(vivify(ref).one.two.three.four.toString.name).to.equal('toString')
|
|
1342
1324
|
|
|
1343
|
-
expect(ref).to.deep.equal({ one: { two: { three: { four:
|
|
1325
|
+
expect(ref).to.deep.equal({ one: { two: { three: { four: 5 } } } })
|
|
1344
1326
|
```
|
|
1345
1327
|
|
|
1346
1328
|
## License
|