@jackens/nnn 2026.9.28 → 2026.9.29
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/README.md +256 -126
- package/nnn.d.ts +41 -36
- package/nnn.js +7 -7
- package/package.json +3 -3
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
|
+
A collection of Jackens’ JavaScript helper utilities (version: `2026.9.29`).
|
|
4
4
|
|
|
5
5
|
## Installation
|
|
6
6
|
|
|
@@ -21,10 +21,10 @@ import {
|
|
|
21
21
|
CNode,
|
|
22
22
|
HArgs,
|
|
23
23
|
HArgs1,
|
|
24
|
-
|
|
25
|
-
|
|
24
|
+
LexerSpec,
|
|
25
|
+
LexerSpecOptions,
|
|
26
26
|
c,
|
|
27
|
-
|
|
27
|
+
createLexer,
|
|
28
28
|
h,
|
|
29
29
|
monokai,
|
|
30
30
|
nanolightTs,
|
|
@@ -42,26 +42,26 @@ import {
|
|
|
42
42
|
Tuple argument type for the [`h`](#h) and [`s`](#s) helpers.
|
|
43
43
|
- [`HArgs1`](#HArgs1):
|
|
44
44
|
Single argument type for the [`h`](#h) and [`s`](#s) helpers.
|
|
45
|
-
- [`
|
|
46
|
-
A [`
|
|
47
|
-
- [`
|
|
48
|
-
Options of a [`
|
|
45
|
+
- [`LexerSpec`](#LexerSpec):
|
|
46
|
+
A [`createLexer`](#createLexer) spec: a `[metadata, pattern, options?]` tuple.
|
|
47
|
+
- [`LexerSpecOptions`](#LexerSpecOptions):
|
|
48
|
+
Options of a [`createLexer`](#createLexer) spec controlling the lexer state stack.
|
|
49
49
|
- [`c`](#c):
|
|
50
50
|
A minimal CSS-in-JS helper that converts a JavaScript object hierarchy into a CSS string.
|
|
51
|
-
- [`
|
|
52
|
-
A helper for building simple stateful
|
|
51
|
+
- [`createLexer`](#createLexer):
|
|
52
|
+
A helper for building simple stateful lexers (see also [`nanolightTs`](#nanolightTs)).
|
|
53
53
|
- [`h`](#h):
|
|
54
54
|
A lightweight _HyperScript_-style helper for creating and modifying `HTMLElement`s (see also [`s`](#s)).
|
|
55
55
|
- [`monokai`](#monokai):
|
|
56
|
-
A Monokai-inspired color scheme for use with the [`c`](#c) helper and [`nanolightTs`](#nanolightTs)
|
|
56
|
+
A Monokai-inspired color scheme for use with the [`c`](#c) helper and [`nanolightTs`](#nanolightTs) lexer.
|
|
57
57
|
- [`nanolightTs`](#nanolightTs):
|
|
58
|
-
A TypeScript/JavaScript syntax highlighting
|
|
58
|
+
A TypeScript/JavaScript syntax highlighting lexer built using [`createLexer`](#createLexer).
|
|
59
59
|
- [`rwd`](#rwd):
|
|
60
|
-
A responsive web design helper that generates CSS rules for a grid-like layout.
|
|
60
|
+
A responsive web design helper that generates CSS rules for a grid-like layout of floating elements.
|
|
61
61
|
- [`s`](#s):
|
|
62
62
|
A lightweight _HyperScript_-style helper for creating and modifying `SVGElement`s (see also [`h`](#h)).
|
|
63
63
|
- [`svgUse`](#svgUse):
|
|
64
|
-
Shorthand for creating an
|
|
64
|
+
Shorthand for creating an `<svg>` element with a `<use>` child referencing a symbol (e.g. an icon) by ID.
|
|
65
65
|
|
|
66
66
|
### CNode
|
|
67
67
|
|
|
@@ -89,25 +89,25 @@ type HArgs1 = Record<PropertyKey, unknown> | null | undefined | Node | string |
|
|
|
89
89
|
|
|
90
90
|
Single argument type for the [`h`](#h) and [`s`](#s) helpers.
|
|
91
91
|
|
|
92
|
-
###
|
|
92
|
+
### LexerSpec
|
|
93
93
|
|
|
94
94
|
```ts
|
|
95
|
-
type
|
|
95
|
+
type LexerSpec<M> = [metadata: M, pattern: string | RegExp, options?: LexerSpecOptions]
|
|
96
96
|
```
|
|
97
97
|
|
|
98
|
-
A [`
|
|
98
|
+
A [`createLexer`](#createLexer) spec: a `[metadata, pattern, options?]` tuple.
|
|
99
99
|
|
|
100
|
-
###
|
|
100
|
+
### LexerSpecOptions
|
|
101
101
|
|
|
102
102
|
```ts
|
|
103
|
-
type
|
|
103
|
+
type LexerSpecOptions = {
|
|
104
104
|
in?: string | string[]
|
|
105
105
|
pop?: boolean
|
|
106
106
|
push?: string
|
|
107
107
|
}
|
|
108
108
|
```
|
|
109
109
|
|
|
110
|
-
Options of a [`
|
|
110
|
+
Options of a [`createLexer`](#createLexer) spec controlling the lexer state stack.
|
|
111
111
|
|
|
112
112
|
#### in
|
|
113
113
|
|
|
@@ -133,12 +133,15 @@ A minimal CSS-in-JS helper that converts a JavaScript object hierarchy into a CS
|
|
|
133
133
|
|
|
134
134
|
An object describing CSS rules.
|
|
135
135
|
Keys are selectors or at-rules; values are either CSS property values or nested rule objects.
|
|
136
|
+
Nested selectors are appended to the parent selector as is (e.g. `'.c'` inside `a` → `a.c`), so a leading space is needed for a descendant combinator (e.g. `' .c'` → `a .c`).
|
|
136
137
|
A selector key may contain comma-separated alternatives (e.g. `'.b,.c'`); when nested, each alternative is combined with each parent alternative (cartesian product), producing a comma-joined selector list (e.g. `'a.b,a.c'`).
|
|
138
|
+
Top-level at-rules (e.g. `'@media …'`) wrap their nested rules; inside a top-level `:root` rule nested keys are concatenated into property names (e.g. `{ ':root': { '--': { bg: 'red' } } }` → `:root{--bg:red}`).
|
|
139
|
+
`null`/`undefined` values are skipped.
|
|
137
140
|
|
|
138
141
|
#### splitter
|
|
139
142
|
|
|
140
143
|
A delimiter used to create unique keys (default: `'$$'`).
|
|
141
|
-
The substring from `splitter` to the end of a key is ignored (e.g
|
|
144
|
+
The substring from `splitter` to the end of a key is ignored (e.g. `src$$1` → `src`).
|
|
142
145
|
|
|
143
146
|
#### Returns
|
|
144
147
|
|
|
@@ -435,16 +438,16 @@ const expected = `
|
|
|
435
438
|
expect(actual).toBe(expected)
|
|
436
439
|
```
|
|
437
440
|
|
|
438
|
-
###
|
|
441
|
+
### createLexer
|
|
439
442
|
|
|
440
443
|
```ts
|
|
441
|
-
const
|
|
444
|
+
const createLexer: <M, T>(
|
|
442
445
|
decorator: (chunk: string, metadata?: M) => T,
|
|
443
|
-
...specs:
|
|
446
|
+
...specs: LexerSpec<M>[]
|
|
444
447
|
) => (code: string) => T[]
|
|
445
448
|
```
|
|
446
449
|
|
|
447
|
-
A helper for building simple stateful
|
|
450
|
+
A helper for building simple stateful lexers (see also [`nanolightTs`](#nanolightTs)).
|
|
448
451
|
|
|
449
452
|
#### Remarks
|
|
450
453
|
|
|
@@ -457,32 +460,32 @@ A helper for building simple stateful tokenizers (see also [`nanolightTs`](#nano
|
|
|
457
460
|
|
|
458
461
|
#### decorator
|
|
459
462
|
|
|
460
|
-
A function that wraps each
|
|
461
|
-
It receives the matched text (`chunk`) and
|
|
462
|
-
For unmatched text between
|
|
463
|
+
A function that wraps each chunk of the input.
|
|
464
|
+
It receives the matched text (`chunk`) and the `metadata` of the spec whose pattern produced the match.
|
|
465
|
+
For unmatched text between matches, `metadata` is `undefined`.
|
|
463
466
|
|
|
464
467
|
#### specs
|
|
465
468
|
|
|
466
469
|
An array of tuples `[metadata, pattern, options?]` where:
|
|
467
470
|
|
|
468
471
|
- `metadata`: arbitrary data (e.g., a CSS class name) passed to `decorator` when the pattern matches.
|
|
469
|
-
- `pattern`: a `string` or `RegExp` to match against the input.
|
|
470
|
-
- `options`: optional [`
|
|
472
|
+
- `pattern`: a `string` (matched literally) or `RegExp` to match against the input.
|
|
473
|
+
- `options`: optional [`LexerSpecOptions`](#LexerSpecOptions) (states in which the spec is active and state transitions).
|
|
471
474
|
|
|
472
475
|
#### Returns
|
|
473
476
|
|
|
474
|
-
A
|
|
477
|
+
A lexer function that accepts an input string and returns an array of decorated chunks covering the whole input (in order).
|
|
475
478
|
|
|
476
479
|
#### Usage Examples
|
|
477
480
|
|
|
478
481
|
```ts
|
|
479
|
-
const
|
|
482
|
+
const lexer = createLexer(
|
|
480
483
|
(chunk, metadata) => ({ chunk, metadata }),
|
|
481
484
|
['keyword', /\b(if|else|for)\b/],
|
|
482
485
|
['string', /"[^"]*"/]
|
|
483
486
|
)
|
|
484
487
|
|
|
485
|
-
const result =
|
|
488
|
+
const result = lexer('if "hello" else "world"')
|
|
486
489
|
|
|
487
490
|
expect(result).toEqual([
|
|
488
491
|
{ chunk: 'if', metadata: 'keyword' },
|
|
@@ -496,25 +499,25 @@ expect(result).toEqual([
|
|
|
496
499
|
```
|
|
497
500
|
|
|
498
501
|
```ts
|
|
499
|
-
const
|
|
502
|
+
const lexer = createLexer((chunk, metadata) => `${metadata}:${chunk}`, ['tag', 'BEGIN'], ['end', 'END'])
|
|
500
503
|
|
|
501
|
-
const result =
|
|
504
|
+
const result = lexer('aBEGINbENDc')
|
|
502
505
|
|
|
503
506
|
expect(result).toEqual(['undefined:a', 'tag:BEGIN', 'undefined:b', 'end:END', 'undefined:c'])
|
|
504
507
|
```
|
|
505
508
|
|
|
506
509
|
```ts
|
|
507
|
-
const
|
|
510
|
+
const lexer = createLexer(chunk => chunk, ['test', /test/])
|
|
508
511
|
|
|
509
|
-
const result =
|
|
512
|
+
const result = lexer('')
|
|
510
513
|
|
|
511
514
|
expect(result).toEqual([])
|
|
512
515
|
```
|
|
513
516
|
|
|
514
517
|
```ts
|
|
515
|
-
const
|
|
518
|
+
const lexer = createLexer((chunk, metadata) => ({ chunk, metadata }), ['start', /^test/])
|
|
516
519
|
|
|
517
|
-
const result =
|
|
520
|
+
const result = lexer('test here')
|
|
518
521
|
|
|
519
522
|
expect(result).toEqual([
|
|
520
523
|
{ chunk: 'test', metadata: 'start' },
|
|
@@ -523,90 +526,90 @@ expect(result).toEqual([
|
|
|
523
526
|
```
|
|
524
527
|
|
|
525
528
|
```ts
|
|
526
|
-
const
|
|
529
|
+
const lexer = createLexer((chunk, metadata) => metadata, ['later', /x/], ['earlier', /y/])
|
|
527
530
|
|
|
528
|
-
const result =
|
|
531
|
+
const result = lexer('yx')
|
|
529
532
|
|
|
530
533
|
expect(result).toEqual(['earlier', 'later'])
|
|
531
534
|
```
|
|
532
535
|
|
|
533
536
|
```ts
|
|
534
|
-
const
|
|
537
|
+
const lexer = createLexer(chunk => chunk, ['short', 'a'], ['long', 'abc'])
|
|
535
538
|
|
|
536
|
-
const result =
|
|
539
|
+
const result = lexer('abc')
|
|
537
540
|
|
|
538
541
|
expect(result).toEqual(['abc'])
|
|
539
542
|
```
|
|
540
543
|
|
|
541
544
|
```ts
|
|
542
|
-
const
|
|
545
|
+
const lexer = createLexer(chunk => chunk, ['empty', ''], ['word', /\w+/])
|
|
543
546
|
|
|
544
|
-
const result =
|
|
547
|
+
const result = lexer('hello')
|
|
545
548
|
|
|
546
549
|
expect(result).toEqual(['hello'])
|
|
547
550
|
```
|
|
548
551
|
|
|
549
552
|
```ts
|
|
550
|
-
const
|
|
553
|
+
const lexer = createLexer(chunk => chunk, ['test', /xyz/])
|
|
551
554
|
|
|
552
|
-
const result =
|
|
555
|
+
const result = lexer('abc')
|
|
553
556
|
|
|
554
557
|
expect(result).toEqual(['abc'])
|
|
555
558
|
```
|
|
556
559
|
|
|
557
560
|
```ts
|
|
558
|
-
const
|
|
561
|
+
const lexer = createLexer((_chunk, metadata) => metadata, ['a', 'a'], ['b', 'b'])
|
|
559
562
|
|
|
560
|
-
const result =
|
|
563
|
+
const result = lexer('aabb')
|
|
561
564
|
|
|
562
565
|
expect(result).toEqual(['a', 'a', 'b', 'b'])
|
|
563
566
|
```
|
|
564
567
|
|
|
565
568
|
```ts
|
|
566
|
-
const
|
|
569
|
+
const lexer = createLexer(
|
|
567
570
|
(chunk, metadata) => `${metadata}:${chunk}`,
|
|
568
571
|
['open', '(', { push: 'inner' }],
|
|
569
572
|
['word', /\w+/, { in: 'inner' }],
|
|
570
573
|
['close', ')', { in: 'inner', pop: true }]
|
|
571
574
|
)
|
|
572
575
|
|
|
573
|
-
const result =
|
|
576
|
+
const result = lexer('a(b)c)')
|
|
574
577
|
|
|
575
578
|
expect(result).toEqual(['undefined:a', 'open:(', 'word:b', 'close:)', 'undefined:c)'])
|
|
576
579
|
```
|
|
577
580
|
|
|
578
581
|
```ts
|
|
579
|
-
const
|
|
582
|
+
const lexer = createLexer(
|
|
580
583
|
(chunk, metadata) => `${metadata}:${chunk}`,
|
|
581
584
|
['open', '{', { in: ['root', 'nested'], push: 'nested' }],
|
|
582
585
|
['close', '}', { in: 'nested', pop: true }]
|
|
583
586
|
)
|
|
584
587
|
|
|
585
|
-
const result =
|
|
588
|
+
const result = lexer('{{}}}')
|
|
586
589
|
|
|
587
590
|
expect(result).toEqual(['open:{', 'open:{', 'close:}', 'close:}', 'undefined:}'])
|
|
588
591
|
```
|
|
589
592
|
|
|
590
593
|
```ts
|
|
591
|
-
const
|
|
594
|
+
const lexer = createLexer((chunk, metadata) => `${metadata}:${chunk}`, ['a', 'a'], ['b', /(?<=a)b/])
|
|
592
595
|
|
|
593
|
-
const result =
|
|
596
|
+
const result = lexer('abcb')
|
|
594
597
|
|
|
595
598
|
expect(result).toEqual(['a:a', 'b:b', 'undefined:cb'])
|
|
596
599
|
```
|
|
597
600
|
|
|
598
601
|
```ts
|
|
599
|
-
const
|
|
602
|
+
const lexer = createLexer((chunk, metadata) => `${metadata}:${chunk}`, ['x', /x/y], ['y', 'y'])
|
|
600
603
|
|
|
601
|
-
const result =
|
|
604
|
+
const result = lexer('xyx.x')
|
|
602
605
|
|
|
603
606
|
expect(result).toEqual(['x:x', 'y:y', 'x:x', 'undefined:.x'])
|
|
604
607
|
```
|
|
605
608
|
|
|
606
609
|
```ts
|
|
607
|
-
const
|
|
610
|
+
const lexer = createLexer((chunk, metadata) => `${metadata}:${chunk}`, ['digits', /\d*/])
|
|
608
611
|
|
|
609
|
-
const result =
|
|
612
|
+
const result = lexer('ab12')
|
|
610
613
|
|
|
611
614
|
expect(result).toEqual(['undefined:ab', 'digits:12'])
|
|
612
615
|
```
|
|
@@ -615,9 +618,9 @@ expect(result).toEqual(['undefined:ab', 'digits:12'])
|
|
|
615
618
|
|
|
616
619
|
```ts
|
|
617
620
|
const h: {
|
|
618
|
-
<T extends keyof HTMLElementTagNameMap>(tag: T, ...
|
|
619
|
-
<N extends Node>(node: N, ...
|
|
620
|
-
(tagOrNode: string | Node, ...
|
|
621
|
+
<T extends keyof HTMLElementTagNameMap>(tag: T, ...args: HArgs1[]): HTMLElementTagNameMap[T]
|
|
622
|
+
<N extends Node>(node: N, ...args: HArgs1[]): N
|
|
623
|
+
(tagOrNode: string | Node, ...args: HArgs1[]): Node
|
|
621
624
|
}
|
|
622
625
|
```
|
|
623
626
|
|
|
@@ -633,17 +636,17 @@ If a `Node`, that node is modified in place.
|
|
|
633
636
|
Additional arguments processed as follows:
|
|
634
637
|
|
|
635
638
|
- `Object`: maps attributes/properties.
|
|
636
|
-
Keys starting with `$` set element properties (without the `$` prefix); if the value is a plain object, it is shallow-merged into the existing property instead of replacing it (useful e.g. for `$style`).
|
|
637
|
-
Other keys set attributes: a key prefixed with `xlink:` sets the attribute via `setAttributeNS` in the XLink namespace; any other key (without a colon) sets it via `setAttribute`.
|
|
638
|
-
|
|
639
|
+
- Keys starting with `$` set element properties (without the `$` prefix); if the value is a plain object, it is shallow-merged into the existing property instead of replacing it (useful e.g. for `$style`).
|
|
640
|
+
- Other keys set attributes: a key prefixed with `xlink:` sets the attribute via `setAttributeNS` in the XLink namespace; any other key (without a colon) sets it via `setAttribute`.
|
|
641
|
+
A value of `true` sets an empty attribute (e.g. `checked=""`), a value of `false` removes the attribute.
|
|
639
642
|
- `null`/`undefined`: ignored.
|
|
640
643
|
- `Node`: appended as a child.
|
|
641
644
|
- `string`/`number`: converted to a `Text` node and appended.
|
|
642
|
-
- [`HArgs`](#HArgs) array: processed recursively.
|
|
645
|
+
- [`HArgs`](#HArgs) array: processed recursively (creates or modifies a child node and appends it).
|
|
643
646
|
|
|
644
647
|
#### Returns
|
|
645
648
|
|
|
646
|
-
The created or modified
|
|
649
|
+
The created `HTMLElement` or the modified node.
|
|
647
650
|
|
|
648
651
|
#### Usage Examples
|
|
649
652
|
|
|
@@ -753,7 +756,26 @@ expect(elemWithNested.outerHTML).toBe('<div><span>hello</span><b>world</b></div>
|
|
|
753
756
|
const monokai: CNode
|
|
754
757
|
```
|
|
755
758
|
|
|
756
|
-
A Monokai-inspired color scheme for use with the [`c`](#c) helper and [`nanolightTs`](#nanolightTs)
|
|
759
|
+
A Monokai-inspired color scheme for use with the [`c`](#c) helper and [`nanolightTs`](#nanolightTs) lexer.
|
|
760
|
+
It styles `pre` and `code>span` elements with the class names produced by [`nanolightTs`](#nanolightTs) (with light, dark and print variants).
|
|
761
|
+
|
|
762
|
+
#### Usage Examples
|
|
763
|
+
|
|
764
|
+
```ts
|
|
765
|
+
const style = h('style', c(monokai))
|
|
766
|
+
const pre = h('pre', ['code', ...nanolightTs('const x = 42')])
|
|
767
|
+
|
|
768
|
+
expect(style.textContent).toContain('code>span.keyword1{color:var(--keyword1)}')
|
|
769
|
+
expect(style.textContent).toContain('@media only screen and (prefers-color-scheme: dark){:root{--bg:#2d2a2e;')
|
|
770
|
+
expect(pre.outerHTML).toBe(
|
|
771
|
+
'<pre><code>' +
|
|
772
|
+
'<span class="keyword1">const</span> ' +
|
|
773
|
+
'<span class="identifier4">x</span> ' +
|
|
774
|
+
'<span class="operator">=</span> ' +
|
|
775
|
+
'<span class="number">42</span>' +
|
|
776
|
+
'</code></pre>'
|
|
777
|
+
)
|
|
778
|
+
```
|
|
757
779
|
|
|
758
780
|
### nanolightTs
|
|
759
781
|
|
|
@@ -761,7 +783,7 @@ A Monokai-inspired color scheme for use with the [`c`](#c) helper and [`nanoligh
|
|
|
761
783
|
const nanolightTs: (code: string) => HArgs1[]
|
|
762
784
|
```
|
|
763
785
|
|
|
764
|
-
A TypeScript/JavaScript syntax highlighting
|
|
786
|
+
A TypeScript/JavaScript syntax highlighting lexer built using [`createLexer`](#createLexer).
|
|
765
787
|
|
|
766
788
|
#### code
|
|
767
789
|
|
|
@@ -769,7 +791,7 @@ The source code string to tokenize.
|
|
|
769
791
|
|
|
770
792
|
#### Returns
|
|
771
793
|
|
|
772
|
-
An array of [`HArgs1`](#HArgs1) elements suitable for rendering with [`h`](#h).
|
|
794
|
+
An array of [`HArgs1`](#HArgs1) elements suitable for rendering with [`h`](#h): plain `string`s for unrecognized text (e.g. whitespace) and `['span', { class }, chunk]` tuples for recognized tokens (class names are styled by [`monokai`](#monokai)).
|
|
773
795
|
|
|
774
796
|
#### Usage Examples
|
|
775
797
|
|
|
@@ -800,77 +822,184 @@ expect(nanolightTs(codeJs)).toEqual([
|
|
|
800
822
|
```
|
|
801
823
|
|
|
802
824
|
```ts
|
|
803
|
-
|
|
804
|
-
|
|
825
|
+
const codeJs = 'const x = 42 // answer'
|
|
826
|
+
|
|
827
|
+
expect(nanolightTs(codeJs)).toEqual([
|
|
828
|
+
['span', { class: 'keyword1' }, 'const'],
|
|
805
829
|
' ',
|
|
806
|
-
'
|
|
830
|
+
['span', { class: 'identifier4' }, 'x'],
|
|
807
831
|
' ',
|
|
808
|
-
|
|
809
|
-
'punctuation:.',
|
|
810
|
-
'identifier2:test',
|
|
811
|
-
'punctuation:(',
|
|
812
|
-
'identifier4:y',
|
|
813
|
-
'punctuation:)',
|
|
832
|
+
['span', { class: 'operator' }, '='],
|
|
814
833
|
' ',
|
|
815
|
-
'
|
|
834
|
+
['span', { class: 'number' }, '42'],
|
|
816
835
|
' ',
|
|
817
|
-
'
|
|
836
|
+
['span', { class: 'comment' }, '// answer'],
|
|
818
837
|
])
|
|
838
|
+
```
|
|
819
839
|
|
|
820
|
-
|
|
821
|
-
|
|
840
|
+
```ts
|
|
841
|
+
expect(nanolightTs('x = /a\\/b[/]c/gi.test(y) / 2')).toEqual([
|
|
842
|
+
['span', { class: 'identifier4' }, 'x'],
|
|
843
|
+
' ',
|
|
844
|
+
['span', { class: 'operator' }, '='],
|
|
845
|
+
' ',
|
|
846
|
+
['span', { class: 'string' }, '/a\\/b[/]c/gi'],
|
|
847
|
+
['span', { class: 'punctuation' }, '.'],
|
|
848
|
+
['span', { class: 'identifier2' }, 'test'],
|
|
849
|
+
['span', { class: 'punctuation' }, '('],
|
|
850
|
+
['span', { class: 'identifier4' }, 'y'],
|
|
851
|
+
['span', { class: 'punctuation' }, ')'],
|
|
852
|
+
' ',
|
|
853
|
+
['span', { class: 'operator' }, '/'],
|
|
854
|
+
' ',
|
|
855
|
+
['span', { class: 'number' }, '2'],
|
|
856
|
+
])
|
|
857
|
+
|
|
858
|
+
expect(nanolightTs('a / b / c')).toEqual([
|
|
859
|
+
['span', { class: 'identifier4' }, 'a'],
|
|
860
|
+
' ',
|
|
861
|
+
['span', { class: 'operator' }, '/'],
|
|
862
|
+
' ',
|
|
863
|
+
['span', { class: 'identifier4' }, 'b'],
|
|
864
|
+
' ',
|
|
865
|
+
['span', { class: 'operator' }, '/'],
|
|
866
|
+
' ',
|
|
867
|
+
['span', { class: 'identifier4' }, 'c'],
|
|
868
|
+
])
|
|
869
|
+
|
|
870
|
+
expect(nanolightTs('return / x /')).toEqual([
|
|
871
|
+
['span', { class: 'keyword1' }, 'return'],
|
|
872
|
+
' ',
|
|
873
|
+
['span', { class: 'string' }, '/ x /'],
|
|
874
|
+
])
|
|
875
|
+
```
|
|
876
|
+
|
|
877
|
+
```ts
|
|
878
|
+
expect(nanolightTs('`a ${b + `c ${ {d}.d }`} \\${e} $f`')).toEqual([
|
|
879
|
+
['span', { class: 'string' }, '`a '],
|
|
880
|
+
['span', { class: 'punctuation' }, '${'],
|
|
881
|
+
['span', { class: 'identifier4' }, 'b'],
|
|
882
|
+
' ',
|
|
883
|
+
['span', { class: 'operator' }, '+'],
|
|
884
|
+
' ',
|
|
885
|
+
['span', { class: 'string' }, '`c '],
|
|
886
|
+
['span', { class: 'punctuation' }, '${'],
|
|
887
|
+
' ',
|
|
888
|
+
['span', { class: 'punctuation' }, '{'],
|
|
889
|
+
['span', { class: 'identifier4' }, 'd'],
|
|
890
|
+
['span', { class: 'punctuation' }, '}'],
|
|
891
|
+
['span', { class: 'punctuation' }, '.'],
|
|
892
|
+
['span', { class: 'identifier4' }, 'd'],
|
|
822
893
|
' ',
|
|
823
|
-
'
|
|
894
|
+
['span', { class: 'punctuation' }, '}'],
|
|
895
|
+
['span', { class: 'string' }, '`'],
|
|
896
|
+
['span', { class: 'punctuation' }, '}'],
|
|
897
|
+
['span', { class: 'string' }, ' \\${e} $f`'],
|
|
898
|
+
])
|
|
899
|
+
|
|
900
|
+
expect(nanolightTs('`${x}` / 2')).toEqual([
|
|
901
|
+
['span', { class: 'string' }, '`'],
|
|
902
|
+
['span', { class: 'punctuation' }, '${'],
|
|
903
|
+
['span', { class: 'identifier4' }, 'x'],
|
|
904
|
+
['span', { class: 'punctuation' }, '}'],
|
|
905
|
+
['span', { class: 'string' }, '`'],
|
|
824
906
|
' ',
|
|
825
|
-
'
|
|
907
|
+
['span', { class: 'operator' }, '/'],
|
|
826
908
|
' ',
|
|
827
|
-
'
|
|
909
|
+
['span', { class: 'number' }, '2'],
|
|
910
|
+
])
|
|
911
|
+
```
|
|
912
|
+
|
|
913
|
+
```ts
|
|
914
|
+
expect(nanolightTs('"a // b" // c')).toEqual([
|
|
915
|
+
['span', { class: 'string' }, '"a // b"'],
|
|
828
916
|
' ',
|
|
829
|
-
'
|
|
917
|
+
['span', { class: 'comment' }, '// c'],
|
|
830
918
|
])
|
|
831
919
|
|
|
832
|
-
expect(
|
|
920
|
+
expect(nanolightTs("'it\\'s' /* x")).toEqual([
|
|
921
|
+
['span', { class: 'string' }, "'it\\'s'"],
|
|
922
|
+
' ',
|
|
923
|
+
['span', { class: 'comment' }, '/* x'],
|
|
924
|
+
])
|
|
833
925
|
```
|
|
834
926
|
|
|
835
927
|
```ts
|
|
836
|
-
expect(
|
|
837
|
-
'
|
|
838
|
-
'punctuation:${',
|
|
839
|
-
'identifier4:b',
|
|
928
|
+
expect(nanolightTs('0xFF + 1_000n + .5e-3')).toEqual([
|
|
929
|
+
['span', { class: 'number' }, '0xFF'],
|
|
840
930
|
' ',
|
|
841
|
-
'operator
|
|
931
|
+
['span', { class: 'operator' }, '+'],
|
|
842
932
|
' ',
|
|
843
|
-
'
|
|
844
|
-
'punctuation:${',
|
|
933
|
+
['span', { class: 'number' }, '1_000n'],
|
|
845
934
|
' ',
|
|
846
|
-
'
|
|
847
|
-
'identifier4:d',
|
|
848
|
-
'punctuation:}',
|
|
849
|
-
'punctuation:.',
|
|
850
|
-
'identifier4:d',
|
|
935
|
+
['span', { class: 'operator' }, '+'],
|
|
851
936
|
' ',
|
|
852
|
-
'
|
|
853
|
-
'string:`',
|
|
854
|
-
'punctuation:}',
|
|
855
|
-
'string: \\${e} $f`',
|
|
937
|
+
['span', { class: 'number' }, '.5e-3'],
|
|
856
938
|
])
|
|
939
|
+
```
|
|
857
940
|
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
'
|
|
861
|
-
'
|
|
862
|
-
'punctuation:}',
|
|
863
|
-
'string:`',
|
|
941
|
+
```ts
|
|
942
|
+
expect(nanolightTs('a++ / 2 / b')).toEqual([
|
|
943
|
+
['span', { class: 'identifier4' }, 'a'],
|
|
944
|
+
['span', { class: 'operator' }, '++'],
|
|
864
945
|
' ',
|
|
865
|
-
'operator
|
|
946
|
+
['span', { class: 'operator' }, '/'],
|
|
866
947
|
' ',
|
|
867
|
-
'number
|
|
948
|
+
['span', { class: 'number' }, '2'],
|
|
949
|
+
' ',
|
|
950
|
+
['span', { class: 'operator' }, '/'],
|
|
951
|
+
' ',
|
|
952
|
+
['span', { class: 'identifier4' }, 'b'],
|
|
953
|
+
])
|
|
954
|
+
|
|
955
|
+
expect(nanolightTs('x?.5:a?.b')).toEqual([
|
|
956
|
+
['span', { class: 'identifier4' }, 'x'],
|
|
957
|
+
['span', { class: 'operator' }, '?'],
|
|
958
|
+
['span', { class: 'number' }, '.5'],
|
|
959
|
+
['span', { class: 'operator' }, ':'],
|
|
960
|
+
['span', { class: 'identifier4' }, 'a'],
|
|
961
|
+
['span', { class: 'punctuation' }, '?.'],
|
|
962
|
+
['span', { class: 'identifier4' }, 'b'],
|
|
868
963
|
])
|
|
869
964
|
```
|
|
870
965
|
|
|
871
966
|
```ts
|
|
872
|
-
expect(
|
|
873
|
-
|
|
967
|
+
expect(nanolightTs('p.catch(obj.in, ...this)')).toEqual([
|
|
968
|
+
['span', { class: 'identifier4' }, 'p'],
|
|
969
|
+
['span', { class: 'punctuation' }, '.'],
|
|
970
|
+
['span', { class: 'identifier2' }, 'catch'],
|
|
971
|
+
['span', { class: 'punctuation' }, '('],
|
|
972
|
+
['span', { class: 'identifier4' }, 'obj'],
|
|
973
|
+
['span', { class: 'punctuation' }, '.'],
|
|
974
|
+
['span', { class: 'identifier4' }, 'in'],
|
|
975
|
+
['span', { class: 'punctuation' }, ','],
|
|
976
|
+
' ',
|
|
977
|
+
['span', { class: 'operator' }, '...'],
|
|
978
|
+
['span', { class: 'keyword1' }, 'this'],
|
|
979
|
+
['span', { class: 'punctuation' }, ')'],
|
|
980
|
+
])
|
|
981
|
+
```
|
|
982
|
+
|
|
983
|
+
```ts
|
|
984
|
+
expect(nanolightTs('#!/usr/bin/env bun\n@sealed class A { #x = 1 }')).toEqual([
|
|
985
|
+
['span', { class: 'comment' }, '#!/usr/bin/env bun'],
|
|
986
|
+
'\n',
|
|
987
|
+
['span', { class: 'identifier2' }, '@sealed'],
|
|
988
|
+
' ',
|
|
989
|
+
['span', { class: 'keyword1' }, 'class'],
|
|
990
|
+
' ',
|
|
991
|
+
['span', { class: 'identifier1' }, 'A'],
|
|
992
|
+
' ',
|
|
993
|
+
['span', { class: 'punctuation' }, '{'],
|
|
994
|
+
' ',
|
|
995
|
+
['span', { class: 'identifier4' }, '#x'],
|
|
996
|
+
' ',
|
|
997
|
+
['span', { class: 'operator' }, '='],
|
|
998
|
+
' ',
|
|
999
|
+
['span', { class: 'number' }, '1'],
|
|
1000
|
+
' ',
|
|
1001
|
+
['span', { class: 'punctuation' }, '}'],
|
|
1002
|
+
])
|
|
874
1003
|
```
|
|
875
1004
|
|
|
876
1005
|
### rwd
|
|
@@ -885,7 +1014,8 @@ const rwd: (
|
|
|
885
1014
|
) => void
|
|
886
1015
|
```
|
|
887
1016
|
|
|
888
|
-
A responsive web design helper that generates CSS rules for a grid-like layout.
|
|
1017
|
+
A responsive web design helper that generates CSS rules for a grid-like layout of floating elements.
|
|
1018
|
+
It modifies `root` in place: it sets base styles for `selector` and adds a `@media(min-width:…px)` rule for each breakpoint.
|
|
889
1019
|
|
|
890
1020
|
#### root
|
|
891
1021
|
|
|
@@ -907,7 +1037,7 @@ The base cell height in pixels.
|
|
|
907
1037
|
|
|
908
1038
|
An array of breakpoint specifications, each a tuple of:
|
|
909
1039
|
|
|
910
|
-
- `maxWidth`:
|
|
1040
|
+
- `maxWidth`: number of cells per row; the breakpoint is `min-width: cellWidthPx * maxWidth` (`1` modifies the base rule).
|
|
911
1041
|
- `width` (optional, default `1`): number of horizontal cells the element spans.
|
|
912
1042
|
- `height` (optional, default `1`): number of vertical cells the element spans.
|
|
913
1043
|
|
|
@@ -937,7 +1067,7 @@ expect(style).toEqual({
|
|
|
937
1067
|
'.no-border': {
|
|
938
1068
|
border: 'none',
|
|
939
1069
|
},
|
|
940
|
-
|
|
1070
|
+
'box-sizing': 'border-box',
|
|
941
1071
|
display: 'block',
|
|
942
1072
|
float: 'left',
|
|
943
1073
|
width: '100%',
|
|
@@ -962,9 +1092,9 @@ expect(style).toEqual({
|
|
|
962
1092
|
|
|
963
1093
|
```ts
|
|
964
1094
|
const s: {
|
|
965
|
-
<T extends keyof SVGElementTagNameMap>(tag: T, ...
|
|
966
|
-
<N extends Node>(node: N, ...
|
|
967
|
-
(tagOrNode: string | Node, ...
|
|
1095
|
+
<T extends keyof SVGElementTagNameMap>(tag: T, ...args: HArgs1[]): SVGElementTagNameMap[T]
|
|
1096
|
+
<N extends Node>(node: N, ...args: HArgs1[]): N
|
|
1097
|
+
(tagOrNode: string | Node, ...args: HArgs1[]): Node
|
|
968
1098
|
}
|
|
969
1099
|
```
|
|
970
1100
|
|
|
@@ -980,17 +1110,17 @@ If a `Node`, that node is modified in place.
|
|
|
980
1110
|
Additional arguments processed as follows:
|
|
981
1111
|
|
|
982
1112
|
- `Object`: maps attributes/properties.
|
|
983
|
-
Keys starting with `$` set element properties (without the `$` prefix); if the value is a plain object, it is shallow-merged into the existing property instead of replacing it.
|
|
984
|
-
Other keys set attributes: a key prefixed with `xlink:` sets the attribute via `setAttributeNS` in the XLink namespace; any other key (without a colon) sets it via `setAttribute`.
|
|
985
|
-
|
|
1113
|
+
- Keys starting with `$` set element properties (without the `$` prefix); if the value is a plain object, it is shallow-merged into the existing property instead of replacing it.
|
|
1114
|
+
- Other keys set attributes: a key prefixed with `xlink:` sets the attribute via `setAttributeNS` in the XLink namespace; any other key (without a colon) sets it via `setAttribute`.
|
|
1115
|
+
A value of `true` sets an empty attribute (e.g. `checked=""`), a value of `false` removes the attribute.
|
|
986
1116
|
- `null`/`undefined`: ignored.
|
|
987
1117
|
- `Node`: appended as a child.
|
|
988
1118
|
- `string`/`number`: converted to a `Text` node and appended.
|
|
989
|
-
- [`HArgs`](#HArgs) array: processed recursively.
|
|
1119
|
+
- [`HArgs`](#HArgs) array: processed recursively (creates or modifies a child node and appends it).
|
|
990
1120
|
|
|
991
1121
|
#### Returns
|
|
992
1122
|
|
|
993
|
-
The created or modified
|
|
1123
|
+
The created `SVGElement` or the modified node.
|
|
994
1124
|
|
|
995
1125
|
#### Usage Examples
|
|
996
1126
|
|
|
@@ -1024,7 +1154,7 @@ expect(svg.getAttributeNS('http://www.w3.org/1999/xlink', 'title')).toBe('42')
|
|
|
1024
1154
|
const svgUse: (id: string, ...args: HArgs1[]) => SVGSVGElement
|
|
1025
1155
|
```
|
|
1026
1156
|
|
|
1027
|
-
Shorthand for creating an
|
|
1157
|
+
Shorthand for creating an `<svg>` element with a `<use>` child referencing a symbol (e.g. an icon) by ID.
|
|
1028
1158
|
|
|
1029
1159
|
Equivalent to:
|
|
1030
1160
|
|
package/nnn.d.ts
CHANGED
|
@@ -9,12 +9,15 @@ export type CNode = {
|
|
|
9
9
|
*
|
|
10
10
|
* An object describing CSS rules.
|
|
11
11
|
* Keys are selectors or at-rules; values are either CSS property values or nested rule objects.
|
|
12
|
+
* Nested selectors are appended to the parent selector as is (e.g. `'.c'` inside `a` → `a.c`), so a leading space is needed for a descendant combinator (e.g. `' .c'` → `a .c`).
|
|
12
13
|
* A selector key may contain comma-separated alternatives (e.g. `'.b,.c'`); when nested, each alternative is combined with each parent alternative (cartesian product), producing a comma-joined selector list (e.g. `'a.b,a.c'`).
|
|
14
|
+
* Top-level at-rules (e.g. `'@media …'`) wrap their nested rules; inside a top-level `:root` rule nested keys are concatenated into property names (e.g. `{ ':root': { '--': { bg: 'red' } } }` → `:root{--bg:red}`).
|
|
15
|
+
* `null`/`undefined` values are skipped.
|
|
13
16
|
*
|
|
14
17
|
* @param splitter
|
|
15
18
|
*
|
|
16
19
|
* A delimiter used to create unique keys (default: `'$$'`).
|
|
17
|
-
* The substring from `splitter` to the end of a key is ignored (e.g
|
|
20
|
+
* The substring from `splitter` to the end of a key is ignored (e.g. `src$$1` → `src`).
|
|
18
21
|
*
|
|
19
22
|
* @returns
|
|
20
23
|
*
|
|
@@ -22,7 +25,7 @@ export type CNode = {
|
|
|
22
25
|
*/
|
|
23
26
|
export declare const c: (node: CNode, splitter?: string) => string
|
|
24
27
|
/**
|
|
25
|
-
* Options of a {@link
|
|
28
|
+
* Options of a {@link createLexer} spec controlling the lexer state stack.
|
|
26
29
|
*
|
|
27
30
|
* @property in
|
|
28
31
|
*
|
|
@@ -36,15 +39,15 @@ export declare const c: (node: CNode, splitter?: string) => string
|
|
|
36
39
|
*
|
|
37
40
|
* State to push onto the stack after a match (applied after `pop`).
|
|
38
41
|
*/
|
|
39
|
-
export type
|
|
42
|
+
export type LexerSpecOptions = {
|
|
40
43
|
in?: string | string[]
|
|
41
44
|
pop?: boolean
|
|
42
45
|
push?: string
|
|
43
46
|
}
|
|
44
|
-
/** A {@link
|
|
45
|
-
export type
|
|
47
|
+
/** A {@link createLexer} spec: a `[metadata, pattern, options?]` tuple. */
|
|
48
|
+
export type LexerSpec<M> = [metadata: M, pattern: string | RegExp, options?: LexerSpecOptions]
|
|
46
49
|
/**
|
|
47
|
-
* A helper for building simple stateful
|
|
50
|
+
* A helper for building simple stateful lexers (see also {@link nanolightTs}).
|
|
48
51
|
*
|
|
49
52
|
* @remarks
|
|
50
53
|
*
|
|
@@ -57,25 +60,25 @@ export type TokenizerSpec<M> = [metadata: M, pattern: string | RegExp, options?:
|
|
|
57
60
|
*
|
|
58
61
|
* @param decorator
|
|
59
62
|
*
|
|
60
|
-
* A function that wraps each
|
|
61
|
-
* It receives the matched text (`chunk`) and
|
|
62
|
-
* For unmatched text between
|
|
63
|
+
* A function that wraps each chunk of the input.
|
|
64
|
+
* It receives the matched text (`chunk`) and the `metadata` of the spec whose pattern produced the match.
|
|
65
|
+
* For unmatched text between matches, `metadata` is `undefined`.
|
|
63
66
|
*
|
|
64
67
|
* @param specs
|
|
65
68
|
*
|
|
66
69
|
* An array of tuples `[metadata, pattern, options?]` where:
|
|
67
70
|
*
|
|
68
71
|
* - `metadata`: arbitrary data (e.g., a CSS class name) passed to `decorator` when the pattern matches.
|
|
69
|
-
* - `pattern`: a `string` or `RegExp` to match against the input.
|
|
70
|
-
* - `options`: optional {@link
|
|
72
|
+
* - `pattern`: a `string` (matched literally) or `RegExp` to match against the input.
|
|
73
|
+
* - `options`: optional {@link LexerSpecOptions} (states in which the spec is active and state transitions).
|
|
71
74
|
*
|
|
72
75
|
* @returns
|
|
73
76
|
*
|
|
74
|
-
* A
|
|
77
|
+
* A lexer function that accepts an input string and returns an array of decorated chunks covering the whole input (in order).
|
|
75
78
|
*/
|
|
76
|
-
export declare const
|
|
79
|
+
export declare const createLexer: <M, T>(
|
|
77
80
|
decorator: (chunk: string, metadata?: M) => T,
|
|
78
|
-
...specs:
|
|
81
|
+
...specs: LexerSpec<M>[]
|
|
79
82
|
) => (code: string) => T[]
|
|
80
83
|
/** Single argument type for the {@link h} and {@link s} helpers. */
|
|
81
84
|
export type HArgs1 = Record<PropertyKey, unknown> | null | undefined | Node | string | number | HArgs
|
|
@@ -94,22 +97,22 @@ export type HArgs = [string | Node, ...HArgs1[]]
|
|
|
94
97
|
* Additional arguments processed as follows:
|
|
95
98
|
*
|
|
96
99
|
* - `Object`: maps attributes/properties.
|
|
97
|
-
* Keys starting with `$` set element properties (without the `$` prefix); if the value is a plain object, it is shallow-merged into the existing property instead of replacing it (useful e.g. for `$style`).
|
|
98
|
-
* Other keys set attributes: a key prefixed with `xlink:` sets the attribute via `setAttributeNS` in the XLink namespace; any other key (without a colon) sets it via `setAttribute`.
|
|
99
|
-
*
|
|
100
|
+
* - Keys starting with `$` set element properties (without the `$` prefix); if the value is a plain object, it is shallow-merged into the existing property instead of replacing it (useful e.g. for `$style`).
|
|
101
|
+
* - Other keys set attributes: a key prefixed with `xlink:` sets the attribute via `setAttributeNS` in the XLink namespace; any other key (without a colon) sets it via `setAttribute`.
|
|
102
|
+
* A value of `true` sets an empty attribute (e.g. `checked=""`), a value of `false` removes the attribute.
|
|
100
103
|
* - `null`/`undefined`: ignored.
|
|
101
104
|
* - `Node`: appended as a child.
|
|
102
105
|
* - `string`/`number`: converted to a `Text` node and appended.
|
|
103
|
-
* - {@link HArgs} array: processed recursively.
|
|
106
|
+
* - {@link HArgs} array: processed recursively (creates or modifies a child node and appends it).
|
|
104
107
|
*
|
|
105
108
|
* @returns
|
|
106
109
|
*
|
|
107
|
-
* The created or modified
|
|
110
|
+
* The created `HTMLElement` or the modified node.
|
|
108
111
|
*/
|
|
109
112
|
export declare const h: {
|
|
110
|
-
<T extends keyof HTMLElementTagNameMap>(tag: T, ...
|
|
111
|
-
<N extends Node>(node: N, ...
|
|
112
|
-
(tagOrNode: string | Node, ...
|
|
113
|
+
<T extends keyof HTMLElementTagNameMap>(tag: T, ...args: HArgs1[]): HTMLElementTagNameMap[T]
|
|
114
|
+
<N extends Node>(node: N, ...args: HArgs1[]): N
|
|
115
|
+
(tagOrNode: string | Node, ...args: HArgs1[]): Node
|
|
113
116
|
}
|
|
114
117
|
/**
|
|
115
118
|
* A lightweight _HyperScript_-style helper for creating and modifying `SVGElement`s (see also {@link h}).
|
|
@@ -124,25 +127,25 @@ export declare const h: {
|
|
|
124
127
|
* Additional arguments processed as follows:
|
|
125
128
|
*
|
|
126
129
|
* - `Object`: maps attributes/properties.
|
|
127
|
-
* Keys starting with `$` set element properties (without the `$` prefix); if the value is a plain object, it is shallow-merged into the existing property instead of replacing it.
|
|
128
|
-
* Other keys set attributes: a key prefixed with `xlink:` sets the attribute via `setAttributeNS` in the XLink namespace; any other key (without a colon) sets it via `setAttribute`.
|
|
129
|
-
*
|
|
130
|
+
* - Keys starting with `$` set element properties (without the `$` prefix); if the value is a plain object, it is shallow-merged into the existing property instead of replacing it.
|
|
131
|
+
* - Other keys set attributes: a key prefixed with `xlink:` sets the attribute via `setAttributeNS` in the XLink namespace; any other key (without a colon) sets it via `setAttribute`.
|
|
132
|
+
* A value of `true` sets an empty attribute (e.g. `checked=""`), a value of `false` removes the attribute.
|
|
130
133
|
* - `null`/`undefined`: ignored.
|
|
131
134
|
* - `Node`: appended as a child.
|
|
132
135
|
* - `string`/`number`: converted to a `Text` node and appended.
|
|
133
|
-
* - {@link HArgs} array: processed recursively.
|
|
136
|
+
* - {@link HArgs} array: processed recursively (creates or modifies a child node and appends it).
|
|
134
137
|
*
|
|
135
138
|
* @returns
|
|
136
139
|
*
|
|
137
|
-
* The created or modified
|
|
140
|
+
* The created `SVGElement` or the modified node.
|
|
138
141
|
*/
|
|
139
142
|
export declare const s: {
|
|
140
|
-
<T extends keyof SVGElementTagNameMap>(tag: T, ...
|
|
141
|
-
<N extends Node>(node: N, ...
|
|
142
|
-
(tagOrNode: string | Node, ...
|
|
143
|
+
<T extends keyof SVGElementTagNameMap>(tag: T, ...args: HArgs1[]): SVGElementTagNameMap[T]
|
|
144
|
+
<N extends Node>(node: N, ...args: HArgs1[]): N
|
|
145
|
+
(tagOrNode: string | Node, ...args: HArgs1[]): Node
|
|
143
146
|
}
|
|
144
147
|
/**
|
|
145
|
-
* Shorthand for creating an
|
|
148
|
+
* Shorthand for creating an `<svg>` element with a `<use>` child referencing a symbol (e.g. an icon) by ID.
|
|
146
149
|
*
|
|
147
150
|
* Equivalent to:
|
|
148
151
|
*
|
|
@@ -164,11 +167,12 @@ export declare const s: {
|
|
|
164
167
|
*/
|
|
165
168
|
export declare const svgUse: (id: string, ...args: HArgs1[]) => SVGSVGElement
|
|
166
169
|
/**
|
|
167
|
-
* A Monokai-inspired color scheme for use with the {@link c} helper and {@link nanolightTs}
|
|
170
|
+
* A Monokai-inspired color scheme for use with the {@link c} helper and {@link nanolightTs} lexer.
|
|
171
|
+
* It styles `pre` and `code>span` elements with the class names produced by {@link nanolightTs} (with light, dark and print variants).
|
|
168
172
|
*/
|
|
169
173
|
export declare const monokai: CNode
|
|
170
174
|
/**
|
|
171
|
-
* A TypeScript/JavaScript syntax highlighting
|
|
175
|
+
* A TypeScript/JavaScript syntax highlighting lexer built using {@link createLexer}.
|
|
172
176
|
*
|
|
173
177
|
* @param code
|
|
174
178
|
*
|
|
@@ -176,11 +180,12 @@ export declare const monokai: CNode
|
|
|
176
180
|
*
|
|
177
181
|
* @returns
|
|
178
182
|
*
|
|
179
|
-
* An array of {@link HArgs1} elements suitable for rendering with {@link h}.
|
|
183
|
+
* An array of {@link HArgs1} elements suitable for rendering with {@link h}: plain `string`s for unrecognized text (e.g. whitespace) and `['span', { class }, chunk]` tuples for recognized tokens (class names are styled by {@link monokai}).
|
|
180
184
|
*/
|
|
181
185
|
export declare const nanolightTs: (code: string) => HArgs1[]
|
|
182
186
|
/**
|
|
183
|
-
* A responsive web design helper that generates CSS rules for a grid-like layout.
|
|
187
|
+
* A responsive web design helper that generates CSS rules for a grid-like layout of floating elements.
|
|
188
|
+
* It modifies `root` in place: it sets base styles for `selector` and adds a `@media(min-width:…px)` rule for each breakpoint.
|
|
184
189
|
*
|
|
185
190
|
* @param root
|
|
186
191
|
*
|
|
@@ -202,7 +207,7 @@ export declare const nanolightTs: (code: string) => HArgs1[]
|
|
|
202
207
|
*
|
|
203
208
|
* An array of breakpoint specifications, each a tuple of:
|
|
204
209
|
*
|
|
205
|
-
* - `maxWidth`:
|
|
210
|
+
* - `maxWidth`: number of cells per row; the breakpoint is `min-width: cellWidthPx * maxWidth` (`1` modifies the base rule).
|
|
206
211
|
* - `width` (optional, default `1`): number of horizontal cells the element spans.
|
|
207
212
|
* - `height` (optional, default `1`): number of vertical cells the element spans.
|
|
208
213
|
*/
|
package/nnn.js
CHANGED
|
@@ -50,9 +50,9 @@ var _c = (node, splitter = DEFAULT_SPLITTER, prefix = "", flatten = false) => {
|
|
|
50
50
|
return out.join(flatten ? ";" : "");
|
|
51
51
|
};
|
|
52
52
|
var c = (node, splitter = DEFAULT_SPLITTER) => _c(node, splitter);
|
|
53
|
-
// src/nnn/
|
|
53
|
+
// src/nnn/createLexer.ts
|
|
54
54
|
var ROOT = "root";
|
|
55
|
-
var
|
|
55
|
+
var createLexer = (decorator, ...specs) => {
|
|
56
56
|
const compiled = specs.map(([metadata, pattern, options]) => ({
|
|
57
57
|
metadata,
|
|
58
58
|
pattern: pattern instanceof RegExp ? new RegExp(pattern.source, pattern.sticky ? pattern.flags : pattern.flags.replace("g", "") + "g") : pattern,
|
|
@@ -283,14 +283,14 @@ var PUNCTUATION = "punctuation";
|
|
|
283
283
|
var STRING = "string";
|
|
284
284
|
var ROOT2 = "root";
|
|
285
285
|
var TEMPLATE = "template";
|
|
286
|
-
var nanolightTs = /* @__PURE__ */
|
|
286
|
+
var nanolightTs = /* @__PURE__ */ createLexer((chunk, name) => name != null ? ["span", { class: name }, chunk] : chunk, [COMMENT, /^#!.*/], [COMMENT, /\/\*[\s\S]*?(?:\*\/|$)/], [COMMENT, /\/\/.*/], [STRING, /"(?:[^"\\\n]|\\[\s\S])*"?/], [STRING, /'(?:[^'\\\n]|\\[\s\S])*'?/], [STRING, /`(?:[^`\\$]|\\[\s\S]|\$(?!\{))*(?:`|$)/], [STRING, /`(?:[^`\\$]|\\[\s\S]|\$(?!\{))*(?=\$\{)/, { push: TEMPLATE }], [STRING, /(?:[^`\\$]|\\[\s\S]|\$(?!\{))*(?:`|$)/y, { in: TEMPLATE, pop: true }], [STRING, /(?:[^`\\$]|\\[\s\S]|\$(?!\{))+(?=\$\{)/y, { in: TEMPLATE }], [PUNCTUATION, "${", { in: TEMPLATE, push: ROOT2 }], [
|
|
287
287
|
STRING,
|
|
288
|
-
/(?<=(?:^|[!%&(
|
|
289
|
-
], [NUMBER, /0b[01_]
|
|
288
|
+
/(?<=(?:^|[!%&(*,:;<=>?[^{|}~]|(?<!\+)\+|(?<!-)-|(?<!\.)\b(?:await|case|delete|do|else|in|instanceof|new|of|return|throw|typeof|void|yield))\s*)\/(?![*/])(?:[^\\/[\n]|\\.|\[(?:[^\\\]\n]|\\.)*\]?)+\/[dgimsuvy]*/
|
|
289
|
+
], [NUMBER, /0b[01_]+n?/i], [NUMBER, /0o[0-7_]+n?/i], [NUMBER, /0x[\da-f_]+n?/i], [NUMBER, /(?:\d[\d_]*(?:\.[\d_]+)?|\.\d[\d_]*)(?:e[+-]?\d[\d_]*)?n?/i], [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, /\?\.(?!\d)/], [PUNCTUATION, "["], [PUNCTUATION, "]"], [PUNCTUATION, "{", { push: ROOT2 }], [PUNCTUATION, "}", { pop: true }], [IDENTIFIER2, /(?<=(?<!\.)\.)\p{Ll}[\p{L}\d_$]*(?=[(`])/u], [IDENTIFIER4, /(?<=(?<!\.)\.)\p{Ll}[\p{L}\d_$]*/u], [KEYWORD1, "as"], [KEYWORD1, "async"], [KEYWORD1, "await"], [KEYWORD1, "break"], [KEYWORD1, "case"], [KEYWORD1, "catch"], [KEYWORD1, "class"], [KEYWORD1, "const"], [KEYWORD1, "continue"], [KEYWORD1, "debugger"], [KEYWORD1, "default"], [KEYWORD1, "delete"], [KEYWORD1, "do"], [KEYWORD1, "else"], [KEYWORD1, "export"], [KEYWORD1, "extends"], [KEYWORD1, "finally"], [KEYWORD1, "for"], [KEYWORD1, "from"], [KEYWORD1, "function"], [KEYWORD1, "function*"], [KEYWORD1, "goto"], [KEYWORD1, "if"], [KEYWORD1, "import"], [KEYWORD1, "in"], [KEYWORD1, "instanceof"], [KEYWORD1, "is"], [KEYWORD1, "keyof"], [KEYWORD1, "let"], [KEYWORD1, "new"], [KEYWORD1, "of"], [KEYWORD1, "package"], [KEYWORD1, "return"], [KEYWORD1, "super"], [KEYWORD1, "switch"], [KEYWORD1, "this"], [KEYWORD1, "throw"], [KEYWORD1, "try"], [KEYWORD1, "type"], [KEYWORD1, "typeof"], [KEYWORD1, "var"], [KEYWORD1, "void"], [KEYWORD1, "while"], [KEYWORD1, "with"], [KEYWORD1, "yield"], [KEYWORD1, "yield*"], [KEYWORD2, "false"], [KEYWORD2, "Infinity"], [KEYWORD2, "NaN"], [KEYWORD2, "null"], [KEYWORD2, "true"], [KEYWORD2, "undefined"], [KEYWORD3, "any"], [KEYWORD3, "bigint"], [KEYWORD3, "boolean"], [KEYWORD3, "eval"], [KEYWORD3, "number"], [KEYWORD3, "string"], [KEYWORD3, "symbol"], [KEYWORD3, "unknown"], [IDENTIFIER2, /@[\p{L}_$][\p{L}\d_$]*/u], [IDENTIFIER1, /#?[\p{Lu}_$][\p{Lu}\d_$]*/u], [IDENTIFIER2, /#?[\p{L}_$][\p{L}\d_$]*(?=[(`])/u], [IDENTIFIER3, /#?\p{Lu}[\p{L}\d_$]*/u], [IDENTIFIER4, /#?[\p{L}_$][\p{L}\d_$]*/u]);
|
|
290
290
|
// src/nnn/rwd.ts
|
|
291
291
|
var rwd = (root, selector, cellWidthPx, cellHeightPx, ...specs) => {
|
|
292
292
|
const main = root[selector] ??= {};
|
|
293
|
-
main
|
|
293
|
+
main["box-sizing"] = "border-box";
|
|
294
294
|
main.display = "block";
|
|
295
295
|
main.float = "left";
|
|
296
296
|
main.width = "100%";
|
|
@@ -313,7 +313,7 @@ var rwd = (root, selector, cellWidthPx, cellHeightPx, ...specs) => {
|
|
|
313
313
|
};
|
|
314
314
|
export {
|
|
315
315
|
c,
|
|
316
|
-
|
|
316
|
+
createLexer,
|
|
317
317
|
h,
|
|
318
318
|
monokai,
|
|
319
319
|
nanolightTs,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jackens/nnn",
|
|
3
|
-
"version": "2026.9.
|
|
3
|
+
"version": "2026.9.29",
|
|
4
4
|
"description": "Jackens’ JavaScript helpers.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"CSS-in-JS",
|
|
@@ -11,10 +11,10 @@
|
|
|
11
11
|
"Responsive Web Design",
|
|
12
12
|
"SVG",
|
|
13
13
|
"highlight",
|
|
14
|
+
"lexer",
|
|
14
15
|
"nanolight",
|
|
15
16
|
"nnn",
|
|
16
|
-
"tokenize"
|
|
17
|
-
"tokenizer"
|
|
17
|
+
"tokenize"
|
|
18
18
|
],
|
|
19
19
|
"license": "MIT",
|
|
20
20
|
"author": "Jackens",
|