@jackens/nnn 2026.9.3 → 2026.9.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (4) hide show
  1. package/nnn.d.ts +0 -50
  2. package/nnn.js +1 -23
  3. package/package.json +13 -13
  4. package/readme.md +290 -379
package/nnn.d.ts CHANGED
@@ -242,53 +242,3 @@ export declare const rwd: (root: CNode, selector: string, cellWidthPx: number, c
242
242
  * `xxxxxxxx-xxxx-1xxx-xxxx-xxxxxxxxxxxx`.
243
243
  */
244
244
  export declare const uuidV1: (date?: Date, node?: string) => string;
245
- /**
246
- * A Proxy-based helper for auto-vivification of nested
247
- * object structures.
248
- *
249
- * Accessing, assigning, or deleting any nested property on
250
- * the returned proxy automatically creates intermediate
251
- * objects (or arrays for numeric-string keys matching
252
- * `^(0|[1-9]\d*)$`) as needed, allowing deep operations
253
- * without explicit null checks.
254
- *
255
- * Intermediates of the last level in a get-only property
256
- * chain are NOT auto-created. For example,
257
- * `vivify(ref).one.two` will create `ref.one` as `{}`, but
258
- * will NOT create `ref.one.two`. Only when a deeper access,
259
- * assignment, or deletion occurs, e.g.
260
- *
261
- * ```ts
262
- * delete vivify(ref).one.two.three
263
- * ```
264
- *
265
- * or
266
- *
267
- * ```ts
268
- * vivify(ref).one.two.three = 4
269
- * ```
270
- *
271
- * Will `ref.one.two` be materialized.
272
- *
273
- * When traversal reaches a primitive value, no
274
- * auto-creation happens; the primitive’s own property is
275
- * returned instead (e.g. accessing `.toString.name` on a
276
- * number yields `'toString'` without modifying the
277
- * underlying structure).
278
- *
279
- * Deletion on a non-existing intermediate path will
280
- * auto-create intermediates up to the parent of the deleted
281
- * key, e.g.
282
- *
283
- * ```ts
284
- * delete vivify(ref).one.two.three
285
- * ```
286
- *
287
- * Will create `ref.one.two` as `{}` if it does not exist.
288
- *
289
- * @param ref The root object to wrap.
290
- *
291
- * @returns A proxy that auto-creates nested objects/arrays
292
- * on property access.
293
- */
294
- export declare const vivify: (ref: unknown) => any;
package/nnn.js CHANGED
@@ -318,27 +318,6 @@ var uuidV1 = (date = new Date, node = Math.random().toString(16).slice(2)) => {
318
318
  counter = counter + 1 & 16383;
319
319
  return time.slice(-8).concat("-", time.slice(-12, -8), -1, time.slice(-15, -12), "-", (8 | counter >> 12).toString(16), (ZEROS + (counter & 4095).toString(16)).slice(-3), "-", (ZEROS + node).slice(-12));
320
320
  };
321
- // src/nnn/vivify.ts
322
- var ARRAY_INDEX_REGEXP = /^(0|[1-9]\d*)$/;
323
- var isObject = (ref) => typeof ref === "object";
324
- var getTarget = (parent, parentKey, key) => parent[parentKey] ??= typeof key === "string" && ARRAY_INDEX_REGEXP.test(key) ? [] : {};
325
- var _vivify = (parent, parentKey) => new Proxy(parent, {
326
- get(_, key) {
327
- const target = getTarget(parent, parentKey, key);
328
- const value = target[key];
329
- return typeof key === "string" && isObject(target) && (value == null || isObject(value)) ? _vivify(target, key) : value;
330
- },
331
- set(_, key, value) {
332
- const target = getTarget(parent, parentKey, key);
333
- target[key] = value;
334
- return true;
335
- },
336
- deleteProperty(_, key) {
337
- const target = getTarget(parent, parentKey, key);
338
- return delete target[key];
339
- }
340
- });
341
- var vivify = (ref) => _vivify({ _: ref }, "_");
342
321
  export {
343
322
  c,
344
323
  createEscape,
@@ -351,6 +330,5 @@ export {
351
330
  rwd,
352
331
  s,
353
332
  svgUse,
354
- uuidV1,
355
- vivify
333
+ uuidV1
356
334
  };
package/package.json CHANGED
@@ -1,23 +1,24 @@
1
1
  {
2
- "author": "Jackens",
2
+ "name": "@jackens/nnn",
3
+ "version": "2026.9.9",
3
4
  "description": "Jackens’ JavaScript helpers.",
4
5
  "keywords": [
5
- "autovivify",
6
- "c",
7
6
  "CSS-in-JS",
8
7
  "CSV parse",
9
8
  "DOM",
10
- "escape",
11
- "h",
12
- "highlight",
13
9
  "HyperScript",
14
10
  "JS-to-CSS",
15
11
  "Monokai",
16
- "nanolight",
17
- "nnn",
18
- "Responsive Web Design",
19
12
  "RWD",
13
+ "Responsive Web Design",
20
14
  "SVG",
15
+ "autovivify",
16
+ "c",
17
+ "escape",
18
+ "h",
19
+ "highlight",
20
+ "nanolight",
21
+ "nnn",
21
22
  "tokenize",
22
23
  "tokenizer",
23
24
  "typography",
@@ -27,9 +28,8 @@
27
28
  "vivify"
28
29
  ],
29
30
  "license": "MIT",
30
- "main": "nnn.js",
31
- "name": "@jackens/nnn",
31
+ "author": "Jackens",
32
32
  "type": "module",
33
- "types": "nnn.d.ts",
34
- "version": "2026.9.3"
33
+ "main": "nnn.js",
34
+ "types": "nnn.d.ts"
35
35
  }
package/readme.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # nnn
2
2
 
3
- A collection of Jackens’ JavaScript helper utilities (version: `2026.9.3`).
3
+ A collection of Jackens’ JavaScript helper utilities (version: `2026.9.9`).
4
4
 
5
5
  ## Installation
6
6
 
@@ -18,6 +18,9 @@ npm i @jackens/nnn
18
18
 
19
19
  ```js
20
20
  import {
21
+ CNode,
22
+ HArgs,
23
+ HArgs1,
21
24
  c,
22
25
  createEscape,
23
26
  createTokenizer,
@@ -30,7 +33,6 @@ import {
30
33
  s,
31
34
  svgUse,
32
35
  uuidV1,
33
- vivify,
34
36
  } from '@jackens/nnn' // or './node_modules/@jackens/nnn/nnn.js'
35
37
  ```
36
38
 
@@ -80,9 +82,6 @@ import {
80
82
  child referencing an icon by ID.
81
83
  - [`uuidV1`](#uuidV1):
82
84
  Generates a UUID v1 (time-based) identifier.
83
- - [`vivify`](#vivify):
84
- A Proxy-based helper for auto-vivification of nested
85
- object structures.
86
85
 
87
86
  ### CNode
88
87
 
@@ -145,7 +144,7 @@ A CSS string representing the compiled rules.
145
144
  #### Usage Examples
146
145
 
147
146
  ```ts
148
- const actual1 = c({
147
+ const actual = c({
149
148
  a: {
150
149
  color: 'red',
151
150
  margin: 1,
@@ -154,22 +153,25 @@ const actual1 = c({
154
153
  },
155
154
  })
156
155
 
157
- const expected1 = `
158
- a{
159
- color:red;
160
- margin:1
161
- }
162
- a.c{
163
- margin:2;
164
- padding:2
165
- }
166
- a{
167
- padding:1
168
- }`.replace(/\n\s*/g, '')
156
+ const expected = `
157
+ a{
158
+ color:red;
159
+ margin:1
160
+ }
161
+ a.c{
162
+ margin:2;
163
+ padding:2
164
+ }
165
+ a{
166
+ padding:1
167
+ }
168
+ `.replace(/\n\s*/g, '')
169
169
 
170
- expect(actual1).to.equal(expected1)
170
+ expect(actual).toBe(expected)
171
+ ```
171
172
 
172
- const actual2 = c({
173
+ ```ts
174
+ const actual = c({
173
175
  a: {
174
176
  '.b': {
175
177
  color: 'red',
@@ -180,22 +182,25 @@ const actual2 = c({
180
182
  },
181
183
  })
182
184
 
183
- const expected2 = `
184
- a.b{
185
- color:red;
186
- margin:1
187
- }
188
- a.b.c{
189
- margin:2;
190
- padding:2
191
- }
192
- a.b{
193
- padding:1
194
- }`.replace(/\n\s*/g, '')
185
+ const expected = `
186
+ a.b{
187
+ color:red;
188
+ margin:1
189
+ }
190
+ a.b.c{
191
+ margin:2;
192
+ padding:2
193
+ }
194
+ a.b{
195
+ padding:1
196
+ }
197
+ `.replace(/\n\s*/g, '')
195
198
 
196
- expect(actual2).to.equal(expected2)
199
+ expect(actual).toBe(expected)
200
+ ```
197
201
 
198
- const actual3 = c({
202
+ ```ts
203
+ const actual = c({
199
204
  '@font-face$$1': {
200
205
  'font-family': 'Jackens',
201
206
  src$$1: 'url(otf/jackens.otf)',
@@ -225,51 +230,54 @@ const actual3 = c({
225
230
  },
226
231
  })
227
232
 
228
- const expected3 = `
229
- @font-face{
230
- font-family:Jackens;
231
- src:url(otf/jackens.otf);
232
- src:url(otf/jackens.otf) format('opentype'),url(svg/jackens.svg) format('svg');
233
- font-weight:normal;
234
- font-style:normal
235
- }
236
- @font-face{
237
- font-family:C64;
238
- src:url(fonts/C64_Pro_Mono-STYLE.woff)
239
- }
240
- @keyframes spin{
241
- 0%{
242
- transform:rotate(0deg)
233
+ const expected = `
234
+ @font-face{
235
+ font-family:Jackens;
236
+ src:url(otf/jackens.otf);
237
+ src:url(otf/jackens.otf) format('opentype'),url(svg/jackens.svg) format('svg');
238
+ font-weight:normal;
239
+ font-style:normal
243
240
  }
244
- 100%{
245
- transform:rotate(360deg)
241
+ @font-face{
242
+ font-family:C64;
243
+ src:url(fonts/C64_Pro_Mono-STYLE.woff)
244
+ }
245
+ @keyframes spin{
246
+ 0%{
247
+ transform:rotate(0deg)
248
+ }
249
+ 100%{
250
+ transform:rotate(360deg)
251
+ }
246
252
  }
247
- }
248
- div{
249
- border:solid red 1px
250
- }
251
- div.c1{
252
- background-color:#000
253
- }
254
- div .c1{
255
- background-color:black
256
- }
257
- div.c2{
258
- background-color:rgb(0,0,0)
259
- }
260
- @media(min-width:200px){
261
253
  div{
262
- margin:0;
263
- padding:0
254
+ border:solid red 1px
255
+ }
256
+ div.c1{
257
+ background-color:#000
264
258
  }
265
- span{
266
- color:#000
259
+ div .c1{
260
+ background-color:black
267
261
  }
268
- }`.replace(/\n\s*/g, '')
262
+ div.c2{
263
+ background-color:rgb(0,0,0)
264
+ }
265
+ @media(min-width:200px){
266
+ div{
267
+ margin:0;
268
+ padding:0
269
+ }
270
+ span{
271
+ color:#000
272
+ }
273
+ }
274
+ `.replace(/\n\s*/g, '')
269
275
 
270
- expect(actual3).to.equal(expected3)
276
+ expect(actual).toBe(expected)
277
+ ```
271
278
 
272
- const actual4 = c({
279
+ ```ts
280
+ const actual = c({
273
281
  a: {
274
282
  '.b,.c': {
275
283
  margin: 1,
@@ -280,17 +288,20 @@ const actual4 = c({
280
288
  },
281
289
  })
282
290
 
283
- const expected4 = `
284
- a.b,a.c{
285
- margin:1
286
- }
287
- a.b.d,a.c.d{
288
- margin:2
289
- }`.replace(/\n\s*/g, '')
291
+ const expected = `
292
+ a.b,a.c{
293
+ margin:1
294
+ }
295
+ a.b.d,a.c.d{
296
+ margin:2
297
+ }
298
+ `.replace(/\n\s*/g, '')
290
299
 
291
- expect(actual4).to.equal(expected4)
300
+ expect(actual).toBe(expected)
301
+ ```
292
302
 
293
- const actual5 = c({
303
+ ```ts
304
+ const actual = c({
294
305
  '.b,.c': {
295
306
  margin: 1,
296
307
  '.d': {
@@ -299,17 +310,20 @@ const actual5 = c({
299
310
  },
300
311
  })
301
312
 
302
- const expected5 = `
303
- .b,.c{
304
- margin:1
305
- }
306
- .b.d,.c.d{
307
- margin:2
308
- }`.replace(/\n\s*/g, '')
313
+ const expected = `
314
+ .b,.c{
315
+ margin:1
316
+ }
317
+ .b.d,.c.d{
318
+ margin:2
319
+ }
320
+ `.replace(/\n\s*/g, '')
309
321
 
310
- expect(actual5).to.equal(expected5)
322
+ expect(actual).toBe(expected)
323
+ ```
311
324
 
312
- const actual6 = c({
325
+ ```ts
326
+ const actual = c({
313
327
  '.a,.b': {
314
328
  margin: 1,
315
329
  '.c,.d': {
@@ -318,17 +332,20 @@ const actual6 = c({
318
332
  },
319
333
  })
320
334
 
321
- const expected6 = `
322
- .a,.b{
323
- margin:1
324
- }
325
- .a.c,.a.d,.b.c,.b.d{
326
- margin:2
327
- }`.replace(/\n\s*/g, '')
335
+ const expected = `
336
+ .a,.b{
337
+ margin:1
338
+ }
339
+ .a.c,.a.d,.b.c,.b.d{
340
+ margin:2
341
+ }
342
+ `.replace(/\n\s*/g, '')
328
343
 
329
- expect(actual6).to.equal(expected6)
344
+ expect(actual).toBe(expected)
345
+ ```
330
346
 
331
- const actual7 = c({
347
+ ```ts
348
+ const actual = c({
332
349
  ':root$$monokai': {
333
350
  '--': {
334
351
  bg: '#faf4f2',
@@ -378,7 +395,7 @@ const actual7 = c({
378
395
  },
379
396
  })
380
397
 
381
- const expected7 = `
398
+ const expected = `
382
399
  :root{
383
400
  --bg:#faf4f2;
384
401
  --fg:#29242a;
@@ -412,9 +429,10 @@ const expected7 = `
412
429
  --punctuation:#727072;
413
430
  --string:#ffd866
414
431
  }
415
- }`.replace(/\n\s*/g, '')
432
+ }
433
+ `.replace(/\n\s*/g, '')
416
434
 
417
- expect(actual7).to.equal(expected7)
435
+ expect(actual).toBe(expected)
418
436
  ```
419
437
 
420
438
  ### createEscape
@@ -472,16 +490,18 @@ const actual = sql`
472
490
  /42/,
473
491
  new Date(323325000000),
474
492
  ]}
475
- )`
493
+ )
494
+ `
476
495
 
477
496
  const expected = `
478
497
  SELECT *
479
498
  FROM table_name
480
499
  WHERE column_name IN (
481
500
  b'1', NULL, NULL, NULL, NULL, 42, '42', '4''2', NULL, '1980-03-31 04:30:00'
482
- )`
501
+ )
502
+ `
483
503
 
484
- expect(actual).to.equal(expected)
504
+ expect(actual).toBe(expected)
485
505
  ```
486
506
 
487
507
  ### createTokenizer
@@ -528,15 +548,15 @@ and returns an array of decorated tokens.
528
548
  #### Usage Examples
529
549
 
530
550
  ```ts
531
- const tokenizer1 = createTokenizer(
551
+ const tokenizer = createTokenizer(
532
552
  (chunk, metadata) => ({ chunk, metadata }),
533
553
  ['keyword', /\b(if|else|for)\b/],
534
554
  ['string', /"[^"]*"/]
535
555
  )
536
556
 
537
- const result1 = tokenizer1('if "hello" else "world"')
557
+ const result = tokenizer('if "hello" else "world"')
538
558
 
539
- expect(result1).to.deep.equal([
559
+ expect(result).toEqual([
540
560
  { chunk: 'if', metadata: 'keyword' },
541
561
  { chunk: ' ', metadata: undefined },
542
562
  { chunk: '"hello"', metadata: 'string' },
@@ -545,92 +565,108 @@ expect(result1).to.deep.equal([
545
565
  { chunk: ' ', metadata: undefined },
546
566
  { chunk: '"world"', metadata: 'string' },
547
567
  ])
568
+ ```
548
569
 
549
- const tokenizer2 = createTokenizer(
570
+ ```ts
571
+ const tokenizer = createTokenizer(
550
572
  (chunk, metadata) => `${metadata}:${chunk}`,
551
573
  ['tag', 'BEGIN'],
552
574
  ['end', 'END']
553
575
  )
554
576
 
555
- const result2 = tokenizer2('aBEGINbENDc')
577
+ const result = tokenizer('aBEGINbENDc')
556
578
 
557
- expect(result2).to.deep.equal([
579
+ expect(result).toEqual([
558
580
  'undefined:a',
559
581
  'tag:BEGIN',
560
582
  'undefined:b',
561
583
  'end:END',
562
584
  'undefined:c',
563
585
  ])
586
+ ```
564
587
 
565
- const tokenizer3 = createTokenizer(
588
+ ```ts
589
+ const tokenizer = createTokenizer(
566
590
  chunk => chunk,
567
591
  ['test', /test/]
568
592
  )
569
593
 
570
- const result3 = tokenizer3('')
594
+ const result = tokenizer('')
571
595
 
572
- expect(result3).to.deep.equal([])
596
+ expect(result).toEqual([])
597
+ ```
573
598
 
574
- const tokenizer4 = createTokenizer(
599
+ ```ts
600
+ const tokenizer = createTokenizer(
575
601
  (chunk, metadata) => ({ chunk, metadata }),
576
602
  ['start', /^test/]
577
603
  )
578
604
 
579
- const result4 = tokenizer4('test here')
605
+ const result = tokenizer('test here')
580
606
 
581
- expect(result4).to.deep.equal([
607
+ expect(result).toEqual([
582
608
  { chunk: 'test', metadata: 'start' },
583
609
  { chunk: ' here', metadata: undefined },
584
610
  ])
611
+ ```
585
612
 
586
- const tokenizer5 = createTokenizer(
613
+ ```ts
614
+ const tokenizer = createTokenizer(
587
615
  (chunk, metadata) => metadata,
588
616
  ['later', /x/],
589
617
  ['earlier', /y/]
590
618
  )
591
619
 
592
- const result5 = tokenizer5('yx')
620
+ const result = tokenizer('yx')
593
621
 
594
- expect(result5).to.deep.equal(['earlier', 'later'])
622
+ expect(result).toEqual(['earlier', 'later'])
623
+ ```
595
624
 
596
- const tokenizer6 = createTokenizer(
625
+ ```ts
626
+ const tokenizer = createTokenizer(
597
627
  chunk => chunk,
598
628
  ['short', 'a'],
599
629
  ['long', 'abc']
600
630
  )
601
631
 
602
- const result6 = tokenizer6('abc')
632
+ const result = tokenizer('abc')
603
633
 
604
- expect(result6).to.deep.equal(['abc'])
634
+ expect(result).toEqual(['abc'])
635
+ ```
605
636
 
606
- const tokenizer7 = createTokenizer(
637
+ ```ts
638
+ const tokenizer = createTokenizer(
607
639
  chunk => chunk,
608
640
  ['empty', ''],
609
641
  ['word', /\w+/]
610
642
  )
611
643
 
612
- const result7 = tokenizer7('hello')
644
+ const result = tokenizer('hello')
613
645
 
614
- expect(result7).to.deep.equal(['hello'])
646
+ expect(result).toEqual(['hello'])
647
+ ```
615
648
 
616
- const tokenizer8 = createTokenizer(
649
+ ```ts
650
+ const tokenizer = createTokenizer(
617
651
  chunk => chunk,
618
652
  ['test', /xyz/]
619
653
  )
620
654
 
621
- const result8 = tokenizer8('abc')
655
+ const result = tokenizer('abc')
622
656
 
623
- expect(result8).to.deep.equal(['abc'])
657
+ expect(result).toEqual(['abc'])
658
+ ```
624
659
 
625
- const tokenizer9 = createTokenizer(
660
+ ```ts
661
+ const tokenizer = createTokenizer(
626
662
  (_chunk, metadata) => metadata,
627
663
  ['a', 'a'],
628
664
  ['b', 'b']
629
665
  )
630
666
 
631
- const result9 = tokenizer9('aabb')
667
+ const result = tokenizer('aabb')
632
668
 
633
- expect(result9).to.deep.equal(['a', 'a', 'b', 'b'])
669
+ expect(result).toEqual(['a', 'a', 'b', 'b'])
634
670
  ```
635
671
 
636
672
  ### csvParse
@@ -670,7 +706,7 @@ yyy",zzz
670
706
 
671
707
  `
672
708
 
673
- expect(csvParse(text)).to.deep.equal([
709
+ expect(csvParse(text)).toEqual([
674
710
  ['aaa\n"aaa"\naaa', 'bbb', 'ccc,ccc'],
675
711
  ['xxx,xxx', 'yyy\nyyy', 'zzz'],
676
712
  [' 42 ', '42', ' 17'],
@@ -716,7 +752,7 @@ const p = h(
716
752
 
717
753
  fixPlTypography(p)
718
754
 
719
- expect(p.innerHTML).to.deep.equal(
755
+ expect(p.innerHTML).toEqual(
720
756
  'Pchnąć ' +
721
757
  '<span style="white-space:nowrap">w </span>' +
722
758
  'tę łódź jeża lub ośm skrzyń fig ' +
@@ -775,61 +811,66 @@ The created or modified `HTMLElement`.
775
811
  ```ts
776
812
  const b = h('b')
777
813
 
778
- expect(b.outerHTML).to.equal('<b></b>')
814
+ expect(b.outerHTML).toBe('<b></b>')
779
815
 
780
816
  const i = h('i', 'text')
781
817
 
782
818
  h(b, i)
783
819
 
784
- expect(i.outerHTML).to.equal('<i>text</i>')
820
+ expect(i.outerHTML).toBe('<i>text</i>')
785
821
 
786
- expect(b.outerHTML).to.equal('<b><i>text</i></b>')
822
+ expect(b.outerHTML).toBe('<b><i>text</i></b>')
787
823
 
788
824
  h(i, { $className: 'some class' })
789
825
 
790
- expect(i.outerHTML).to.equal(
791
- '<i class="some class">text</i>'
792
- )
826
+ expect(i.outerHTML).toBe('<i class="some class">text</i>')
793
827
 
794
- expect(b.outerHTML).to.equal(
828
+ expect(b.outerHTML).toBe(
795
829
  '<b><i class="some class">text</i></b>'
796
830
  )
831
+ ```
797
832
 
798
- expect(h('span', 'text').outerHTML).to.equal(
833
+ ```ts
834
+ expect(h('span', 'text').outerHTML).toBe(
799
835
  '<span>text</span>'
800
836
  )
801
837
 
802
- expect(
803
- h('span', { $innerText: 'text' }).outerHTML
804
- ).to.equal('<span>text</span>')
805
-
806
- expect(h('span', '42').outerHTML).to.equal(
807
- '<span>42</span>'
838
+ expect(h('span', { $innerText: 'text' }).outerHTML).toBe(
839
+ '<span>text</span>'
808
840
  )
809
841
 
810
- expect(h('span', 42).outerHTML).to.equal('<span>42</span>')
842
+ expect(h('span', '42').outerHTML).toBe('<span>42</span>')
811
843
 
844
+ expect(h('span', 42).outerHTML).toBe('<span>42</span>')
845
+ ```
846
+
847
+ ```ts
812
848
  expect(
813
849
  h('div', { style: 'margin:0;padding:0' }).outerHTML
814
- ).to.equal('<div style="margin:0;padding:0"></div>')
850
+ ).toBe('<div style="margin:0;padding:0"></div>')
815
851
 
816
852
  expect(
817
853
  h('div', { $style: 'margin:0;padding:0' }).outerHTML
818
- ).to.equal('<div style="margin: 0px; padding: 0px;"></div>')
854
+ ).toBe('<div style="margin: 0px; padding: 0px;"></div>')
819
855
 
820
856
  expect(
821
- h('div', { $style: { margin: 0, padding: 0 } }).outerHTML
822
- ).to.equal('<div style="margin: 0px; padding: 0px;"></div>')
857
+ h('div', { $style: { margin: 0, padding: 0 } })
858
+ .outerHTML
859
+ ).toBe('<div style="margin: 0px; padding: 0px;"></div>')
860
+ ```
823
861
 
862
+ ```ts
824
863
  const input1 = h('input', { value: 42 })
825
864
  const input2 = h('input', { $value: '42' })
826
865
 
827
- expect(input1.value).to.equal('42')
828
- expect(input2.value).to.equal('42')
866
+ expect(input1.value).toBe('42')
867
+ expect(input2.value).toBe('42')
829
868
 
830
- expect(input1.outerHTML).to.equal('<input value="42">')
831
- expect(input2.outerHTML).to.equal('<input>')
869
+ expect(input1.outerHTML).toBe('<input value="42">')
870
+ expect(input2.outerHTML).toBe('<input>')
871
+ ```
832
872
 
873
+ ```ts
833
874
  const checkbox1 = h('input', {
834
875
  type: 'checkbox',
835
876
  checked: true,
@@ -840,38 +881,42 @@ const checkbox2 = h('input', {
840
881
  $checked: true,
841
882
  })
842
883
 
843
- expect(checkbox1.checked).to.be.true
844
- expect(checkbox2.checked).to.be.true
884
+ expect(checkbox1.checked).toBe(true)
885
+ expect(checkbox2.checked).toBe(true)
845
886
 
846
- expect(checkbox1.outerHTML).to.equal(
887
+ expect(checkbox1.outerHTML).toBe(
847
888
  '<input type="checkbox" checked="">'
848
889
  )
849
890
 
850
- expect(checkbox2.outerHTML).to.equal(
891
+ expect(checkbox2.outerHTML).toBe(
851
892
  '<input type="checkbox">'
852
893
  )
894
+ ```
853
895
 
896
+ ```ts
854
897
  const div = h('div')
855
898
 
856
- expect(div.key).to.be.undefined
899
+ expect(div.key).toBeUndefined()
857
900
 
858
901
  h(div, { $key: { one: 1 } })
859
902
 
860
- expect(div.key).to.deep.equal({ one: 1 })
903
+ expect(div.key).toEqual({ one: 1 })
861
904
 
862
905
  h(div, { $key: { two: 2 } })
863
906
 
864
- expect(div.key).to.deep.equal({ one: 1, two: 2 })
907
+ expect(div.key).toEqual({ one: 1, two: 2 })
908
+ ```
865
909
 
910
+ ```ts
866
911
  const elemWithClass = h('div', { class: 'test' })
867
912
 
868
- expect(elemWithClass.getAttribute('class')).to.equal('test')
913
+ expect(elemWithClass.getAttribute('class')).toBe('test')
869
914
 
870
915
  const elemWithText = h('div', 'initial')
871
916
 
872
917
  h(elemWithText, ' more')
873
918
 
874
- expect(elemWithText.outerHTML).to.equal(
919
+ expect(elemWithText.outerHTML).toBe(
875
920
  '<div>initial more</div>'
876
921
  )
877
922
 
@@ -881,7 +926,7 @@ const elemWithNested = h(
881
926
  ['b', 'world']
882
927
  )
883
928
 
884
- expect(elemWithNested.outerHTML).to.equal(
929
+ expect(elemWithNested.outerHTML).toBe(
885
930
  '<div><span>hello</span><b>world</b></div>'
886
931
  )
887
932
  ```
@@ -920,7 +965,7 @@ const codeJs =
920
965
  'const answerToLifeTheUniverseAndEverything = ' +
921
966
  "{ 42: 42 }['42'] /* 42 */"
922
967
 
923
- expect(nanolightTs(codeJs)).to.deep.equal([
968
+ expect(nanolightTs(codeJs)).toEqual([
924
969
  ['span', { class: 'keyword1' }, 'const'],
925
970
  ' ',
926
971
  [
@@ -1002,7 +1047,7 @@ const style: CNode = {
1002
1047
 
1003
1048
  rwd(style, '.r6', 200, 50, [6], [3], [1, 1, 2])
1004
1049
 
1005
- expect(style).to.deep.equal({
1050
+ expect(style).toEqual({
1006
1051
  body: {
1007
1052
  margin: 0,
1008
1053
  },
@@ -1077,29 +1122,49 @@ The created or modified `SVGElement`.
1077
1122
  #### Usage Examples
1078
1123
 
1079
1124
  ```ts
1080
- const XLINK_NS = 'http://www.w3.org/1999/xlink'
1081
-
1082
- const svg1 = s('svg', { 'xlink:href': true })
1125
+ const svg = s('svg', { 'xlink:href': true })
1083
1126
 
1084
- expect(svg1.getAttributeNS(XLINK_NS, 'href')).to.equal('')
1127
+ expect(
1128
+ svg.getAttributeNS(
1129
+ 'http://www.w3.org/1999/xlink',
1130
+ 'href'
1131
+ )
1132
+ ).toBe('')
1133
+ ```
1085
1134
 
1086
- const svg2 = s('svg', { 'xlink:href': false })
1135
+ ```ts
1136
+ const svg = s('svg', { 'xlink:href': false })
1087
1137
 
1088
- expect(svg2.getAttributeNS(XLINK_NS, 'href')).to.be.null
1138
+ expect(
1139
+ svg.getAttributeNS(
1140
+ 'http://www.w3.org/1999/xlink',
1141
+ 'href'
1142
+ )
1143
+ ).toBeNull()
1144
+ ```
1089
1145
 
1090
- const svg3 = s('svg', {
1146
+ ```ts
1147
+ const svg = s('svg', {
1091
1148
  'xlink:href': 'http://example.com',
1092
1149
  })
1093
1150
 
1094
- expect(svg3.getAttributeNS(XLINK_NS, 'href')).to.equal(
1095
- 'http://example.com'
1096
- )
1151
+ expect(
1152
+ svg.getAttributeNS(
1153
+ 'http://www.w3.org/1999/xlink',
1154
+ 'href'
1155
+ )
1156
+ ).toBe('http://example.com')
1157
+ ```
1097
1158
 
1098
- const svg4 = s('svg', { 'xlink:title': 42 })
1159
+ ```ts
1160
+ const svg = s('svg', { 'xlink:title': 42 })
1099
1161
 
1100
- expect(svg4.getAttributeNS(XLINK_NS, 'title')).to.equal(
1101
- '42'
1102
- )
1162
+ expect(
1163
+ svg.getAttributeNS(
1164
+ 'http://www.w3.org/1999/xlink',
1165
+ 'title'
1166
+ )
1167
+ ).toBe('42')
1103
1168
  ```
1104
1169
 
1105
1170
  ### svgUse
@@ -1138,47 +1203,54 @@ An `SVGSVGElement` containing a `<use>` element.
1138
1203
  #### Usage Examples
1139
1204
 
1140
1205
  ```ts
1141
- const XLINK_NS = 'http://www.w3.org/1999/xlink'
1142
-
1143
1206
  const svg = svgUse('icon-home')
1144
1207
 
1145
- expect(svg.children.length).to.equal(1)
1208
+ expect(svg.children.length).toBe(1)
1146
1209
 
1147
1210
  const useElement = svg.children[0]
1148
1211
 
1149
1212
  expect(
1150
- useElement.getAttributeNS(XLINK_NS, 'href')
1151
- ).to.equal('#icon-home')
1213
+ useElement.getAttributeNS(
1214
+ 'http://www.w3.org/1999/xlink',
1215
+ 'href'
1216
+ )
1217
+ ).toBe('#icon-home')
1152
1218
 
1153
1219
  const svgWithViewBox = svgUse('icon-star', {
1154
1220
  viewBox: '0 0 24 24',
1155
1221
  })
1156
1222
 
1157
- expect(svgWithViewBox.getAttribute('viewBox')).to.equal(
1223
+ expect(svgWithViewBox.getAttribute('viewBox')).toBe(
1158
1224
  '0 0 24 24'
1159
1225
  )
1160
1226
 
1161
1227
  const useViewBox = svgWithViewBox.children[0]
1162
1228
 
1163
1229
  expect(
1164
- useViewBox.getAttributeNS(XLINK_NS, 'href')
1165
- ).to.equal('#icon-star')
1230
+ useViewBox.getAttributeNS(
1231
+ 'http://www.w3.org/1999/xlink',
1232
+ 'href'
1233
+ )
1234
+ ).toBe('#icon-star')
1166
1235
 
1167
1236
  const svgWithClass = svgUse('icon-menu', {
1168
1237
  class: 'icon-btn',
1169
1238
  })
1170
1239
 
1171
- expect(svgWithClass.getAttribute('class')).to.equal(
1240
+ expect(svgWithClass.getAttribute('class')).toBe(
1172
1241
  'icon-btn'
1173
1242
  )
1174
1243
 
1175
- expect(svgWithClass.children.length).to.equal(1)
1244
+ expect(svgWithClass.children.length).toBe(1)
1176
1245
 
1177
1246
  const useClass = svgWithClass.children[0]
1178
1247
 
1179
- expect(useClass.getAttributeNS(XLINK_NS, 'href')).to.equal(
1180
- '#icon-menu'
1181
- )
1248
+ expect(
1249
+ useClass.getAttributeNS(
1250
+ 'http://www.w3.org/1999/xlink',
1251
+ 'href'
1252
+ )
1253
+ ).toBe('#icon-menu')
1182
1254
 
1183
1255
  const svgWithMultipleAttrs = svgUse('icon-settings', {
1184
1256
  width: 24,
@@ -1186,23 +1258,26 @@ const svgWithMultipleAttrs = svgUse('icon-settings', {
1186
1258
  class: 'icon',
1187
1259
  })
1188
1260
 
1189
- expect(svgWithMultipleAttrs.getAttribute('width')).to.equal(
1261
+ expect(svgWithMultipleAttrs.getAttribute('width')).toBe(
1190
1262
  '24'
1191
1263
  )
1192
1264
 
1193
- expect(
1194
- svgWithMultipleAttrs.getAttribute('height')
1195
- ).to.equal('24')
1265
+ expect(svgWithMultipleAttrs.getAttribute('height')).toBe(
1266
+ '24'
1267
+ )
1196
1268
 
1197
- expect(svgWithMultipleAttrs.getAttribute('class')).to.equal(
1269
+ expect(svgWithMultipleAttrs.getAttribute('class')).toBe(
1198
1270
  'icon'
1199
1271
  )
1200
1272
 
1201
1273
  const useMultiple = svgWithMultipleAttrs.children[0]
1202
1274
 
1203
1275
  expect(
1204
- useMultiple.getAttributeNS(XLINK_NS, 'href')
1205
- ).to.equal('#icon-settings')
1276
+ useMultiple.getAttributeNS(
1277
+ 'http://www.w3.org/1999/xlink',
1278
+ 'href'
1279
+ )
1280
+ ).toBe('#icon-settings')
1206
1281
  ```
1207
1282
 
1208
1283
  ### uuidV1
@@ -1237,213 +1312,49 @@ for (let i = 1; i <= 22136; ++i) {
1237
1312
  const uuid = uuidV1()
1238
1313
 
1239
1314
  if (i === 1) {
1240
- expect(uuid.split('-')[3]).to.equal('8001')
1315
+ expect(uuid.split('-')[3]).toBe('8001')
1241
1316
  }
1242
1317
 
1243
1318
  if (i === 4095) {
1244
- expect(uuid.split('-')[3]).to.equal('8fff')
1319
+ expect(uuid.split('-')[3]).toBe('8fff')
1245
1320
  }
1246
1321
 
1247
1322
  if (i === 4096) {
1248
- expect(uuid.split('-')[3]).to.equal('9000')
1323
+ expect(uuid.split('-')[3]).toBe('9000')
1249
1324
  }
1250
1325
 
1251
1326
  if (i === 9029) {
1252
- expect(uuid.split('-')[3]).to.equal('a345')
1327
+ expect(uuid.split('-')[3]).toBe('a345')
1253
1328
  }
1254
1329
 
1255
1330
  if (i === 13398) {
1256
- expect(uuid.split('-')[3]).to.equal('b456')
1331
+ expect(uuid.split('-')[3]).toBe('b456')
1257
1332
  }
1258
1333
 
1259
1334
  if (i === 16384) {
1260
- expect(uuid.split('-')[3]).to.equal('8000')
1335
+ expect(uuid.split('-')[3]).toBe('8000')
1261
1336
  }
1262
1337
 
1263
1338
  if (i === 17767) {
1264
- expect(uuid.split('-')[3]).to.equal('8567')
1339
+ expect(uuid.split('-')[3]).toBe('8567')
1265
1340
  }
1266
1341
  }
1342
+ ```
1267
1343
 
1344
+ ```ts
1268
1345
  expect(
1269
1346
  uuidV1(new Date(), '000123456789abc').split('-')[4]
1270
- ).to.equal('123456789abc')
1347
+ ).toBe('123456789abc')
1271
1348
 
1272
1349
  expect(
1273
1350
  uuidV1(new Date(), '123456789').split('-')[4]
1274
- ).to.equal('000123456789')
1351
+ ).toBe('000123456789')
1275
1352
 
1276
1353
  expect(
1277
1354
  uuidV1(new Date(323325000000)).startsWith(
1278
1355
  'c1399400-9a71-11bd'
1279
1356
  )
1280
- ).to.be.true
1281
- ```
1282
-
1283
- ### vivify
1284
-
1285
- ```ts
1286
- const vivify: (ref: unknown) => any;
1287
- ```
1288
-
1289
- A Proxy-based helper for auto-vivification of nested
1290
- object structures.
1291
-
1292
- Accessing, assigning, or deleting any nested property on
1293
- the returned proxy automatically creates intermediate
1294
- objects (or arrays for numeric-string keys matching
1295
- `^(0|[1-9]\d*)$`) as needed, allowing deep operations
1296
- without explicit null checks.
1297
-
1298
- Intermediates of the last level in a get-only property
1299
- chain are NOT auto-created. For example,
1300
- `vivify(ref).one.two` will create `ref.one` as `{}`, but
1301
- will NOT create `ref.one.two`. Only when a deeper access,
1302
- assignment, or deletion occurs, e.g.
1303
-
1304
- ```ts
1305
- delete vivify(ref).one.two.three
1306
- ```
1307
-
1308
- or
1309
-
1310
- ```ts
1311
- vivify(ref).one.two.three = 4
1312
- ```
1313
-
1314
- Will `ref.one.two` be materialized.
1315
-
1316
- When traversal reaches a primitive value, no
1317
- auto-creation happens; the primitive’s own property is
1318
- returned instead (e.g. accessing `.toString.name` on a
1319
- number yields `'toString'` without modifying the
1320
- underlying structure).
1321
-
1322
- Deletion on a non-existing intermediate path will
1323
- auto-create intermediates up to the parent of the deleted
1324
- key, e.g.
1325
-
1326
- ```ts
1327
- delete vivify(ref).one.two.three
1328
- ```
1329
-
1330
- Will create `ref.one.two` as `{}` if it does not exist.
1331
-
1332
- #### ref
1333
-
1334
- The root object to wrap.
1335
-
1336
- #### Returns
1337
-
1338
- A proxy that auto-creates nested objects/arrays
1339
- on property access.
1340
-
1341
- #### Usage Examples
1342
-
1343
- ```ts
1344
- const ref: any = {}
1345
-
1346
- vivify(ref).one.two[3][4]
1347
-
1348
- expect(ref).to.deep.equal({
1349
- one: {
1350
- two: [undefined, undefined, undefined, []],
1351
- },
1352
- })
1353
-
1354
- vivify(ref).one.two[3][4] = 5
1355
-
1356
- expect(ref).to.deep.equal({
1357
- one: {
1358
- two: [
1359
- undefined,
1360
- undefined,
1361
- undefined,
1362
- [undefined, undefined, undefined, undefined, 5],
1363
- ],
1364
- },
1365
- })
1366
-
1367
- vivify(ref).one.two[3].length = 1
1368
-
1369
- expect(ref).to.deep.equal({
1370
- one: {
1371
- two: [undefined, undefined, undefined, [undefined]],
1372
- },
1373
- })
1374
-
1375
- vivify(ref).one.two[3] = 4
1376
-
1377
- expect(ref).to.deep.equal({
1378
- one: {
1379
- two: [undefined, undefined, undefined, 4],
1380
- },
1381
- })
1382
-
1383
- expect(vivify(ref).one.two.length).to.equal(4)
1384
-
1385
- expect(ref).to.deep.equal({
1386
- one: {
1387
- two: [undefined, undefined, undefined, 4],
1388
- },
1389
- })
1390
-
1391
- vivify(ref).one.two = 3
1392
-
1393
- expect(ref).to.deep.equal({ one: { two: 3 } })
1394
-
1395
- vivify(ref).one.two = undefined
1396
-
1397
- expect(ref).to.deep.equal({ one: { two: undefined } })
1398
-
1399
- delete vivify(ref).one.two
1400
-
1401
- expect(ref).to.deep.equal({ one: {} })
1402
-
1403
- expect(vivify(ref).one.toString instanceof Function).to.be
1404
- .true
1405
-
1406
- expect(vivify(ref).one.toString.name).to.equal('toString')
1407
-
1408
- expect(ref).to.deep.equal({ one: {} })
1409
-
1410
- delete vivify(ref).one.two.three
1411
-
1412
- expect(ref).to.deep.equal({ one: { two: {} } })
1413
-
1414
- vivify(ref).one.two.three.four
1415
-
1416
- expect(ref).to.deep.equal({ one: { two: { three: {} } } })
1417
-
1418
- vivify(ref).one.two[3]
1419
-
1420
- expect(ref).to.deep.equal({ one: { two: { three: {} } } })
1421
-
1422
- vivify(ref).one.two.three.four = 5
1423
-
1424
- expect(ref).to.deep.equal({
1425
- one: { two: { three: { four: 5 } } },
1426
- })
1427
-
1428
- expect(
1429
- vivify(ref).one.two.three.four.toString.name
1430
- ).to.equal('toString')
1431
-
1432
- expect(ref).to.deep.equal({
1433
- one: { two: { three: { four: 5 } } },
1434
- })
1435
-
1436
- const u = undefined
1437
-
1438
- vivify(u).one.two = 3
1439
-
1440
- expect(u).to.be.undefined
1441
-
1442
- const n = null
1443
-
1444
- delete vivify(n).one.two.three
1445
-
1446
- expect(n).to.be.null
1357
+ ).toBe(true)
1447
1358
  ```
1448
1359
 
1449
1360
  ## License