@jackens/nnn 2023.8.20 → 2023.8.26
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 +59 -59
- package/nnn.js +135 -135
- package/package.json +4 -1
package/nnn.d.ts
CHANGED
|
@@ -1,40 +1,27 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* The type of arguments of the
|
|
2
|
+
* The type of arguments of the `escapeValues` and `escape` helpers.
|
|
3
3
|
*/
|
|
4
|
-
export type
|
|
5
|
-
[attributeOrSelector: string]: string | number | $CNode;
|
|
6
|
-
};
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
* The type of arguments of the `$c` helper.
|
|
10
|
-
*/
|
|
11
|
-
export type $CRoot = Record<string, $CNode>;
|
|
4
|
+
export type EscapeMap = Map<any, (value?: any) => string>;
|
|
12
5
|
|
|
13
6
|
/**
|
|
14
|
-
* The type of arguments of the
|
|
7
|
+
* The type of arguments of the `h` and `s` helpers.
|
|
15
8
|
*/
|
|
16
|
-
export type
|
|
9
|
+
export type HArgs = [
|
|
10
|
+
string | Node,
|
|
11
|
+
...(Record<string, any> | null | undefined | Node | string | number | HArgs)[]
|
|
12
|
+
];
|
|
17
13
|
|
|
18
14
|
/**
|
|
19
|
-
* The type of arguments of the
|
|
15
|
+
* The type of arguments of the `jcss` helper.
|
|
20
16
|
*/
|
|
21
|
-
export type
|
|
22
|
-
string |
|
|
23
|
-
|
|
24
|
-
];
|
|
17
|
+
export type JcssNode = {
|
|
18
|
+
[attributeOrSelector: string]: string | number | JcssNode;
|
|
19
|
+
};
|
|
25
20
|
|
|
26
21
|
/**
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
* The `root` parameter provides a hierarchical description of CSS rules.
|
|
30
|
-
*
|
|
31
|
-
* - Keys of sub-objects whose values are NOT objects are treated as CSS attribute, and values are treated as values of those CSS attributes; the concatenation of keys of all parent objects is a CSS rule.
|
|
32
|
-
* - All keys ignore the part starting with a splitter (default: `$$`) sign until the end of the key (e.g. `src$$1` → `src`, `@font-face$$1` → `@font-face`).
|
|
33
|
-
* - In keys specifying CSS attribute, all uppercase letters are replaced by lowercase letters with an additional `-` character preceding them (e.g. `fontFamily` → `font-family`).
|
|
34
|
-
* - Commas in keys that makes a CSS rule cause it to “split” and create separate rules for each part (e.g. `{div:{margin:1,'.a,.b,.c':{margin:2}}}` → `div{margin:1}div.a,div.b,div.c{margin:2}`).
|
|
35
|
-
* - Top-level keys that begin with `@` are not concatenated with sub-object keys.
|
|
22
|
+
* The type of arguments of the `jcss` helper.
|
|
36
23
|
*/
|
|
37
|
-
export
|
|
24
|
+
export type JcssRoot = Record<string, JcssNode>;
|
|
38
25
|
|
|
39
26
|
/**
|
|
40
27
|
* A helper for creating a chart based on a table (conf. <https://jackens.github.io/nnn/chartable/>).
|
|
@@ -57,7 +44,7 @@ export function $c(root: $CRoot, splitter?: string): string;
|
|
|
57
44
|
* - `zLabels`: data series labels
|
|
58
45
|
* - `zxY`: chart data
|
|
59
46
|
*/
|
|
60
|
-
export function
|
|
47
|
+
export function chartable(options?: {
|
|
61
48
|
bottom?: number;
|
|
62
49
|
gapX?: number;
|
|
63
50
|
gapY?: number;
|
|
@@ -79,30 +66,30 @@ export function $chartable(options?: {
|
|
|
79
66
|
/**
|
|
80
67
|
* A helper that checks equality of the given arguments.
|
|
81
68
|
*/
|
|
82
|
-
export function
|
|
69
|
+
export function eq(x: any, y: any): boolean;
|
|
83
70
|
|
|
84
71
|
/**
|
|
85
72
|
* A generic helper for escaping `values` by given `escapeMap` (in *TemplateStrings* flavor).
|
|
86
73
|
*/
|
|
87
|
-
export function
|
|
74
|
+
export function escape(escapeMap: EscapeMap, template: TemplateStringsArray, ...values: any[]): string;
|
|
88
75
|
|
|
89
76
|
/**
|
|
90
77
|
* A generic helper for escaping `values` by given `escapeMap`.
|
|
91
78
|
*/
|
|
92
|
-
export function
|
|
79
|
+
export function escapeValues(escapeMap: EscapeMap, values: any[]): string[];
|
|
93
80
|
|
|
94
81
|
/**
|
|
95
82
|
* A helper that implements typographic corrections specific to Polish typography.
|
|
96
83
|
*/
|
|
97
|
-
export function
|
|
84
|
+
export function fixTypography(node: Node): void;
|
|
98
85
|
|
|
99
86
|
/**
|
|
100
87
|
* A convenient helper for getting values of nested objects.
|
|
101
88
|
*/
|
|
102
|
-
export function
|
|
89
|
+
export function get(defaultValue: any, ref: any, ...keys: (string | number | symbol)[]): any;
|
|
103
90
|
|
|
104
91
|
/**
|
|
105
|
-
* A lightweight [HyperScript](https://github.com/hyperhype/hyperscript)-style helper for creating and modifying `HTMLElement`s (see also
|
|
92
|
+
* A lightweight [HyperScript](https://github.com/hyperhype/hyperscript)-style helper for creating and modifying `HTMLElement`s (see also `s`).
|
|
106
93
|
*
|
|
107
94
|
* - The first argument of type `string` specifies the tag of the element to be created.
|
|
108
95
|
* - The first argument of type `Node` specifies the element to be modified.
|
|
@@ -114,58 +101,71 @@ export function $get(defaultValue: any, ref: any, ...keys: (string | number | sy
|
|
|
114
101
|
* - All other arguments of type `null` or `undefined` are simply ignored.
|
|
115
102
|
* - All other arguments of type `Node` are appended to the element being created or modified.
|
|
116
103
|
* - All other arguments of type `string`/`number` are converted to `Text` nodes and appended to the element being created or modified.
|
|
117
|
-
* - All other arguments of type
|
|
104
|
+
* - All other arguments of type `HArgs` are passed to `h` and the results are appended to the element being created or modified.
|
|
118
105
|
*/
|
|
119
|
-
export function
|
|
120
|
-
export function
|
|
121
|
-
export function
|
|
106
|
+
export function h<T extends keyof HTMLElementTagNameMap>(tag: T, ...args: HArgs[1][]): HTMLElementTagNameMap[T];
|
|
107
|
+
export function h<N extends Node>(node: N, ...args: HArgs[1][]): N;
|
|
108
|
+
export function h(...args: HArgs): Node;
|
|
122
109
|
|
|
123
110
|
/**
|
|
124
111
|
* A replacement for the `in` operator (not to be confused with the `for-in` loop) that works properly.
|
|
125
112
|
*/
|
|
126
|
-
export function
|
|
113
|
+
export function has(key: any, ref: any): boolean;
|
|
127
114
|
|
|
128
115
|
/**
|
|
129
116
|
* A helper that checks if the given argument is of a certain type.
|
|
130
117
|
*/
|
|
131
|
-
export function
|
|
132
|
-
export function
|
|
133
|
-
export function
|
|
134
|
-
export function
|
|
135
|
-
export function
|
|
136
|
-
export function
|
|
137
|
-
export function
|
|
118
|
+
export function is(type: BigIntConstructor, arg: any): arg is bigint;
|
|
119
|
+
export function is(type: BooleanConstructor, arg: any): arg is boolean;
|
|
120
|
+
export function is(type: NumberConstructor, arg: any): arg is number;
|
|
121
|
+
export function is(type: StringConstructor, arg: any): arg is string;
|
|
122
|
+
export function is(type: SymbolConstructor, arg: any): arg is symbol;
|
|
123
|
+
export function is(type: undefined, arg: any): arg is null | undefined;
|
|
124
|
+
export function is<T extends abstract new (...args: any[]) => any>(type: T, arg: any): arg is InstanceType<T>;
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* A simple CSS-in-JS helper.
|
|
128
|
+
*
|
|
129
|
+
* The `root` parameter provides a hierarchical description of CSS rules.
|
|
130
|
+
*
|
|
131
|
+
* - Keys of sub-objects whose values are NOT objects are treated as CSS attribute, and values are treated as values of those CSS attributes; the concatenation of keys of all parent objects is a CSS rule.
|
|
132
|
+
* - All keys ignore the part starting with a splitter (default: `$$`) sign until the end of the key (e.g. `src$$1` → `src`, `@font-face$$1` → `@font-face`).
|
|
133
|
+
* - In keys specifying CSS attribute, all uppercase letters are replaced by lowercase letters with an additional `-` character preceding them (e.g. `fontFamily` → `font-family`).
|
|
134
|
+
* - Commas in keys that makes a CSS rule cause it to “split” and create separate rules for each part (e.g. `{div:{margin:1,'.a,.b,.c':{margin:2}}}` → `div{margin:1}div.a,div.b,div.c{margin:2}`).
|
|
135
|
+
* - Top-level keys that begin with `@` are not concatenated with sub-object keys.
|
|
136
|
+
*/
|
|
137
|
+
export function jcss(root: JcssRoot, splitter?: string): string;
|
|
138
138
|
|
|
139
139
|
/**
|
|
140
140
|
* Language translations helper.
|
|
141
141
|
*/
|
|
142
|
-
export function
|
|
142
|
+
export function locale(
|
|
143
143
|
locales: Record<string, Record<string, string | Record<string, string>>>,
|
|
144
144
|
defaultLanguage: string,
|
|
145
145
|
languages?: readonly string[]
|
|
146
146
|
): (text?: string, version?: string) => string;
|
|
147
147
|
|
|
148
148
|
/**
|
|
149
|
-
* A generic helper for syntax highlighting (see also
|
|
149
|
+
* A generic helper for syntax highlighting (see also `nanolightJs`).
|
|
150
150
|
*/
|
|
151
|
-
export function
|
|
151
|
+
export function nanolight(
|
|
152
152
|
pattern: RegExp,
|
|
153
|
-
highlighters: ((chunk: string, index: number) =>
|
|
153
|
+
highlighters: ((chunk: string, index: number) => HArgs[1])[],
|
|
154
154
|
code: string
|
|
155
|
-
):
|
|
155
|
+
): HArgs[1][];
|
|
156
156
|
|
|
157
157
|
/**
|
|
158
158
|
* A helper for highlighting JavaScript.
|
|
159
159
|
*/
|
|
160
|
-
export function
|
|
160
|
+
export function nanolightJs(codeJs: string): HArgs[1][];
|
|
161
161
|
|
|
162
162
|
/**
|
|
163
163
|
* A helper for choosing the correct singular and plural.
|
|
164
164
|
*/
|
|
165
|
-
export function
|
|
165
|
+
export function plUral(singular: string, plural2: string, plural5: string, value: number): string;
|
|
166
166
|
|
|
167
167
|
/**
|
|
168
|
-
* A lightweight [HyperScript](https://github.com/hyperhype/hyperscript)-style helper for creating and modifying `SVGElement`s (see also
|
|
168
|
+
* A lightweight [HyperScript](https://github.com/hyperhype/hyperscript)-style helper for creating and modifying `SVGElement`s (see also `h`).
|
|
169
169
|
*
|
|
170
170
|
* - The first argument of type `string` specifies the tag of the element to be created.
|
|
171
171
|
* - The first argument of type `Node` specifies the element to be modified.
|
|
@@ -177,16 +177,16 @@ export function $plUral(singular: string, plural2: string, plural5: string, valu
|
|
|
177
177
|
* - All other arguments of type `null` or `undefined` are simply ignored.
|
|
178
178
|
* - All other arguments of type `Node` are appended to the element being created or modified.
|
|
179
179
|
* - All other arguments of type `string`/`number` are converted to `Text` nodes and appended to the element being created or modified.
|
|
180
|
-
* - All other arguments of type
|
|
180
|
+
* - All other arguments of type `HArgs` are passed to `s` and the results are appended to the element being created or modified.
|
|
181
181
|
*/
|
|
182
|
-
export function
|
|
183
|
-
export function
|
|
184
|
-
export function
|
|
182
|
+
export function s<T extends keyof SVGElementTagNameMap>(tag: T, ...args: HArgs[1][]): SVGElementTagNameMap[T];
|
|
183
|
+
export function s<N extends Node>(node: N, ...args: HArgs[1][]): N;
|
|
184
|
+
export function s(...args: HArgs): Node;
|
|
185
185
|
|
|
186
186
|
/**
|
|
187
187
|
* A convenient helper for setting values of nested objects.
|
|
188
188
|
*/
|
|
189
|
-
export function
|
|
189
|
+
export function set(value: any, ref: any, ...keys: (string | number | symbol)[]): void;
|
|
190
190
|
|
|
191
191
|
/**
|
|
192
192
|
* A helper that generates a UUID v1 identifier (with a creation timestamp).
|
|
@@ -194,7 +194,7 @@ export function $set(value: any, ref: any, ...keys: (string | number | symbol)[]
|
|
|
194
194
|
* - The optional `node` parameter should have the format `/^[0123456789abcdef]+$/`.
|
|
195
195
|
* Its value will be trimmed to last 12 characters and left padded with zeros.
|
|
196
196
|
*/
|
|
197
|
-
export function
|
|
197
|
+
export function uuid1(options?: {
|
|
198
198
|
date?: Date;
|
|
199
199
|
node?: string;
|
|
200
200
|
}): string;
|
package/nnn.js
CHANGED
|
@@ -1,97 +1,24 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @typedef {
|
|
3
|
-
* string | Node,
|
|
4
|
-
* ...(Record<string, any> | null | undefined | Node | string | number | $HArgs)[]
|
|
5
|
-
* ]} $HArgs
|
|
2
|
+
* @typedef {Map<any, (value?: any) => string>} EscapeMap
|
|
6
3
|
*/
|
|
7
4
|
|
|
8
5
|
/**
|
|
9
|
-
* @typedef {
|
|
10
|
-
*
|
|
11
|
-
*
|
|
6
|
+
* @typedef {[
|
|
7
|
+
* string | Node,
|
|
8
|
+
* ...(Record<string, any> | null | undefined | Node | string | number | HArgs)[]
|
|
9
|
+
* ]} HArgs
|
|
12
10
|
*/
|
|
13
11
|
|
|
14
12
|
/**
|
|
15
|
-
* @typedef {
|
|
13
|
+
* @typedef {{
|
|
14
|
+
* [attributeOrSelector: string]: string | number | JcssNode;
|
|
15
|
+
* }} JcssNode
|
|
16
16
|
*/
|
|
17
17
|
|
|
18
18
|
/**
|
|
19
|
-
* @typedef {
|
|
19
|
+
* @typedef {Record<string, JcssNode>} JcssRoot
|
|
20
20
|
*/
|
|
21
21
|
|
|
22
|
-
const _c = (
|
|
23
|
-
/** @type {$CNode} */ node,
|
|
24
|
-
/** @type {string} */ prefix,
|
|
25
|
-
/** @type {string[]} */ result,
|
|
26
|
-
/** @type {(text: string) => string} */ split
|
|
27
|
-
) => {
|
|
28
|
-
const /** @type {[$CNode | string[], string][]} */ queue = [[node, prefix]]
|
|
29
|
-
|
|
30
|
-
while (queue.length) {
|
|
31
|
-
const [style2, prefix2] = queue.shift() ?? []
|
|
32
|
-
|
|
33
|
-
if (style2 == null || prefix2 == null) {
|
|
34
|
-
continue
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
if ($is(Array, style2)) {
|
|
38
|
-
result.push(prefix2, prefix2 !== '' ? '{' : '', style2.join(';'), prefix2 !== '' ? '}' : '')
|
|
39
|
-
} else {
|
|
40
|
-
const /** @type {[$CNode | string[], string][]} */ todo = []
|
|
41
|
-
let /** @type {string[]} */ attributes = []
|
|
42
|
-
let attributesPushed = false
|
|
43
|
-
|
|
44
|
-
for (const key in style2) {
|
|
45
|
-
const value = style2[key]
|
|
46
|
-
|
|
47
|
-
if ($is(String, value) || $is(Number, value)) {
|
|
48
|
-
if (!attributesPushed) {
|
|
49
|
-
attributesPushed = true
|
|
50
|
-
attributes = []
|
|
51
|
-
todo.push([attributes, prefix2])
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
attributes.push(`${split(key).replace(/([A-Z])/g, (_, letter) => '-' + letter.toLowerCase())}:${value}`)
|
|
55
|
-
} else {
|
|
56
|
-
attributesPushed = false
|
|
57
|
-
|
|
58
|
-
const /** @type {string[]} */ newPrefix = []
|
|
59
|
-
const keySplitted = key.split(',')
|
|
60
|
-
|
|
61
|
-
for (const prefixItem of prefix2.split(',')) {
|
|
62
|
-
for (const keyItem of keySplitted) {
|
|
63
|
-
newPrefix.push(prefixItem + keyItem)
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
todo.push([value, newPrefix.join(',')])
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
queue.unshift(...todo)
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
export const $c = (/** @type {$CRoot} */ root, splitter = '$$') => {
|
|
77
|
-
const split = (/** @type {string} */ text) => text.split(splitter)[0]
|
|
78
|
-
const /** @type {string[]} */ result = []
|
|
79
|
-
|
|
80
|
-
for (const key in root) {
|
|
81
|
-
const value = root[key]
|
|
82
|
-
|
|
83
|
-
if (key[0] === '@') {
|
|
84
|
-
result.push(split(key) + '{')
|
|
85
|
-
_c(value, '', result, split)
|
|
86
|
-
result.push('}')
|
|
87
|
-
} else {
|
|
88
|
-
_c(value, split(key), result, split)
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
return result.join('')
|
|
93
|
-
}
|
|
94
|
-
|
|
95
22
|
const _COLORS = ['#e22', '#e73', '#fc3', '#ad4', '#4d9', '#3be', '#45d', '#c3e']
|
|
96
23
|
|
|
97
24
|
/**
|
|
@@ -114,7 +41,7 @@ const _COLORS = ['#e22', '#e73', '#fc3', '#ad4', '#4d9', '#3be', '#45d', '#c3e']
|
|
|
114
41
|
* zxY?: number[][];
|
|
115
42
|
* }} options
|
|
116
43
|
*/
|
|
117
|
-
export const
|
|
44
|
+
export const chartable = ({
|
|
118
45
|
bottom = 50,
|
|
119
46
|
gapX = 70,
|
|
120
47
|
gapY = 30,
|
|
@@ -144,7 +71,7 @@ export const $chartable = ({
|
|
|
144
71
|
const value = col.innerText
|
|
145
72
|
|
|
146
73
|
if (x >= 0 && z >= 0 && zxYNotPassed) {
|
|
147
|
-
|
|
74
|
+
set(parseFloat(value), zxY, z, x)
|
|
148
75
|
} else if (x >= 0 && z < 0 && xLabelsNotPassed) {
|
|
149
76
|
xLabels[x] = value
|
|
150
77
|
} else if (x < 0 && z >= 0 && zLabelsNotPassed) {
|
|
@@ -203,13 +130,13 @@ export const $chartable = ({
|
|
|
203
130
|
const h = gapY * (maxY - 1)
|
|
204
131
|
const svgW = left + w + right
|
|
205
132
|
const svgH = top + h + bottom
|
|
206
|
-
const /** @type {
|
|
133
|
+
const /** @type {HArgs} */ graph = ['g', { transform: `translate(${left} ${top})` },
|
|
207
134
|
...yi.map(y => ['line', { x1: 0, x2: w, y1: y, y2: y, stroke: '#8888' }]),
|
|
208
135
|
...xi.map(x => ['line', { x1: x, x2: x, y1: 0, y2: h, stroke: '#8888' }])]
|
|
209
|
-
const /** @type {
|
|
210
|
-
const /** @type {
|
|
211
|
-
const /** @type {
|
|
212
|
-
const /** @type {
|
|
136
|
+
const /** @type {HArgs} */ lColors = ['g', { class: 'chartable-z-colors', transform: 'translate(-80 0)' }]
|
|
137
|
+
const /** @type {HArgs} */ lLabels = ['g', { class: 'chartable-z-labels', transform: 'translate(-95 0)' }]
|
|
138
|
+
const /** @type {HArgs} */ rColors = ['g', { class: 'chartable-z-colors', transform: 'translate(80 0)' }]
|
|
139
|
+
const /** @type {HArgs} */ rLabels = ['g', { class: 'chartable-z-labels', transform: 'translate(95 0)' }]
|
|
213
140
|
const yLabel = (/** @type {number} */ min, /** @type {number} */ max, /** @type {number} */ y) =>
|
|
214
141
|
(min + (max - min) * (maxY - 1 - y) / (maxY - 1)).toFixed(2).replace(/\.?0+$/, '')
|
|
215
142
|
|
|
@@ -247,7 +174,7 @@ export const $chartable = ({
|
|
|
247
174
|
})
|
|
248
175
|
})
|
|
249
176
|
|
|
250
|
-
return
|
|
177
|
+
return s('svg', {
|
|
251
178
|
viewBox: `0 0 ${svgW} ${svgH}`,
|
|
252
179
|
width: `${svgW}px`,
|
|
253
180
|
height: `${svgH}px`,
|
|
@@ -284,7 +211,7 @@ export const $chartable = ({
|
|
|
284
211
|
)
|
|
285
212
|
}
|
|
286
213
|
|
|
287
|
-
export const
|
|
214
|
+
export const eq = /** @returns {boolean} */ (/** @type {any} */ x, /** @type {any} */ y) => {
|
|
288
215
|
if (x === y) {
|
|
289
216
|
return true
|
|
290
217
|
}
|
|
@@ -305,12 +232,12 @@ export const $eq = /** @returns {boolean} */ (/** @type {any} */ x, /** @type {a
|
|
|
305
232
|
}
|
|
306
233
|
|
|
307
234
|
if (xConstructor === Array) {
|
|
308
|
-
return x.length === y.length && x.every((/** @type {any} */ item, /** @type {number} */ index) =>
|
|
235
|
+
return x.length === y.length && x.every((/** @type {any} */ item, /** @type {number} */ index) => eq(item, y[index]))
|
|
309
236
|
}
|
|
310
237
|
|
|
311
238
|
if (xConstructor === Object) {
|
|
312
239
|
const keysOfX = Object.keys(x)
|
|
313
|
-
return keysOfX.length === Object.keys(y).length && keysOfX.every(key =>
|
|
240
|
+
return keysOfX.length === Object.keys(y).length && keysOfX.every(key => eq(x[key], y[key]))
|
|
314
241
|
}
|
|
315
242
|
|
|
316
243
|
if (xConstructor === Set || xConstructor === Map) {
|
|
@@ -319,27 +246,27 @@ export const $eq = /** @returns {boolean} */ (/** @type {any} */ x, /** @type {a
|
|
|
319
246
|
}
|
|
320
247
|
const xa = [...x]
|
|
321
248
|
const ya = [...y]
|
|
322
|
-
return xa.every(xv => ya.find(yv =>
|
|
249
|
+
return xa.every(xv => ya.find(yv => eq(xv, yv)))
|
|
323
250
|
}
|
|
324
251
|
}
|
|
325
252
|
|
|
326
253
|
return false
|
|
327
254
|
}
|
|
328
255
|
|
|
329
|
-
export const
|
|
330
|
-
/** @type {
|
|
256
|
+
export const escape = (
|
|
257
|
+
/** @type {EscapeMap} */ escapeMap,
|
|
331
258
|
/** @type {TemplateStringsArray} */ template,
|
|
332
259
|
/** @type {any[]} */ ...values
|
|
333
|
-
) => String.raw(template,
|
|
260
|
+
) => String.raw(template, ...escapeValues(escapeMap, values))
|
|
334
261
|
|
|
335
|
-
export const
|
|
336
|
-
/** @type {
|
|
262
|
+
export const escapeValues = (
|
|
263
|
+
/** @type {EscapeMap} */ escapeMap,
|
|
337
264
|
/** @type {any[]} */ values
|
|
338
265
|
) => values.map(value => (escapeMap.get(value?.constructor) ?? escapeMap.get(undefined))?.(value) ?? '')
|
|
339
266
|
|
|
340
267
|
const TAGS_TO_SKIP = { IFRAME: 1, NOSCRIPT: 1, PRE: 1, SCRIPT: 1, STYLE: 1, TEXTAREA: 1 }
|
|
341
268
|
|
|
342
|
-
export const
|
|
269
|
+
export const fixTypography = (/** @type {Node} */ node) => {
|
|
343
270
|
const /** @type {Node[]} */ queue = [node]
|
|
344
271
|
|
|
345
272
|
while (queue.length > 0) {
|
|
@@ -351,7 +278,7 @@ export const $fixTypography = (/** @type {Node} */ node) => {
|
|
|
351
278
|
|
|
352
279
|
if (childNode instanceof Text) {
|
|
353
280
|
queue.push(childNode)
|
|
354
|
-
} else if (childNode instanceof Element &&
|
|
281
|
+
} else if (childNode instanceof Element && !has(childNode.tagName, TAGS_TO_SKIP)) {
|
|
355
282
|
queue.push(childNode)
|
|
356
283
|
}
|
|
357
284
|
}
|
|
@@ -362,7 +289,7 @@ export const $fixTypography = (/** @type {Node} */ node) => {
|
|
|
362
289
|
i %= 3
|
|
363
290
|
|
|
364
291
|
const currentNode = i === 2
|
|
365
|
-
?
|
|
292
|
+
? h('span', { style: 'white-space:nowrap' }, chunk)
|
|
366
293
|
: i === 1
|
|
367
294
|
? document.createTextNode(chunk)
|
|
368
295
|
: document.createTextNode(chunk.replace(/(\/(?=[^/\s])|\.(?=[^\s]))/g, '$1\u200B'))
|
|
@@ -379,13 +306,13 @@ export const $fixTypography = (/** @type {Node} */ node) => {
|
|
|
379
306
|
}
|
|
380
307
|
}
|
|
381
308
|
|
|
382
|
-
export const
|
|
309
|
+
export const get = (
|
|
383
310
|
/** @type {any} */ defaultValue,
|
|
384
311
|
/** @type {any} */ ref,
|
|
385
312
|
/** @type {(string | number | symbol)[]} */ ...keys
|
|
386
313
|
) => {
|
|
387
314
|
for (const key of keys) {
|
|
388
|
-
if (
|
|
315
|
+
if (!has(key, ref)) {
|
|
389
316
|
return defaultValue
|
|
390
317
|
}
|
|
391
318
|
|
|
@@ -402,14 +329,14 @@ const /** @type {Record<string, string>} */ NS = {
|
|
|
402
329
|
/**
|
|
403
330
|
* @type {{
|
|
404
331
|
* (namespaceURI?: null | undefined): {
|
|
405
|
-
* <T extends keyof HTMLElementTagNameMap>(tag: T, ...args:
|
|
406
|
-
* <N extends Node> (node: N, ...args:
|
|
407
|
-
* (...args:
|
|
332
|
+
* <T extends keyof HTMLElementTagNameMap>(tag: T, ...args: HArgs[1][]): HTMLElementTagNameMap[T];
|
|
333
|
+
* <N extends Node> (node: N, ...args: HArgs[1][]): N;
|
|
334
|
+
* (...args: HArgs): Node;
|
|
408
335
|
* };
|
|
409
336
|
* (namespaceURI: 'http://www.w3.org/2000/svg'): {
|
|
410
|
-
* <T extends keyof SVGElementTagNameMap> (tag: T, ...args:
|
|
411
|
-
* <N extends Node> (node: N, ...args:
|
|
412
|
-
* (...args:
|
|
337
|
+
* <T extends keyof SVGElementTagNameMap> (tag: T, ...args: HArgs[1][]): SVGElementTagNameMap[T];
|
|
338
|
+
* <N extends Node> (node: N, ...args: HArgs[1][]): N;
|
|
339
|
+
* (...args: HArgs): Node;
|
|
413
340
|
* };
|
|
414
341
|
* }}
|
|
415
342
|
*/
|
|
@@ -418,18 +345,18 @@ const _h = (/** @type {string?=} */ namespaceURI) => {
|
|
|
418
345
|
? (/** @type {string } */ tag) => document.createElement(tag)
|
|
419
346
|
: (/** @type {string } */ tag) => document.createElementNS(namespaceURI, tag)
|
|
420
347
|
|
|
421
|
-
const h = (/** @type {
|
|
422
|
-
const node =
|
|
348
|
+
const h = (/** @type {HArgs[0]} */ tagOrNode, /** @type {HArgs[1][]} */ ...args) => {
|
|
349
|
+
const node = is(String, tagOrNode) ? createElement(tagOrNode) : tagOrNode
|
|
423
350
|
|
|
424
351
|
for (const arg of args) {
|
|
425
352
|
let child = null
|
|
426
353
|
|
|
427
354
|
if (arg instanceof Node) {
|
|
428
355
|
child = arg
|
|
429
|
-
} else if (
|
|
356
|
+
} else if (is(String, arg) || is(Number, arg)) {
|
|
430
357
|
// @ts-expect-error
|
|
431
358
|
child = new Text(arg)
|
|
432
|
-
} else if (
|
|
359
|
+
} else if (is(Array, arg)) {
|
|
433
360
|
// @ts-expect-error
|
|
434
361
|
child = h(...arg)
|
|
435
362
|
} else if (arg != null) {
|
|
@@ -439,7 +366,7 @@ const _h = (/** @type {string?=} */ namespaceURI) => {
|
|
|
439
366
|
if (name[0] === '$') {
|
|
440
367
|
const name1 = name.slice(1)
|
|
441
368
|
|
|
442
|
-
if (
|
|
369
|
+
if (is(Object, value)) {
|
|
443
370
|
// @ts-expect-error
|
|
444
371
|
node[name1] = node[name1] ?? {}
|
|
445
372
|
// @ts-expect-error
|
|
@@ -462,7 +389,7 @@ const _h = (/** @type {string?=} */ namespaceURI) => {
|
|
|
462
389
|
} else if (value === false) {
|
|
463
390
|
node.removeAttributeNS(ns, basename)
|
|
464
391
|
} else {
|
|
465
|
-
node.setAttributeNS(ns, basename,
|
|
392
|
+
node.setAttributeNS(ns, basename, is(String, value) ? value : '' + value)
|
|
466
393
|
}
|
|
467
394
|
}
|
|
468
395
|
} else {
|
|
@@ -471,7 +398,7 @@ const _h = (/** @type {string?=} */ namespaceURI) => {
|
|
|
471
398
|
} else if (value === false) {
|
|
472
399
|
node.removeAttribute(name)
|
|
473
400
|
} else {
|
|
474
|
-
node.setAttribute(name,
|
|
401
|
+
node.setAttribute(name, is(String, value) ? value : '' + value)
|
|
475
402
|
}
|
|
476
403
|
}
|
|
477
404
|
}
|
|
@@ -489,10 +416,10 @@ const _h = (/** @type {string?=} */ namespaceURI) => {
|
|
|
489
416
|
return h
|
|
490
417
|
}
|
|
491
418
|
|
|
492
|
-
export const
|
|
419
|
+
export const h = _h()
|
|
493
420
|
|
|
494
|
-
export const
|
|
495
|
-
(
|
|
421
|
+
export const has = (/** @type {any} */ key, /** @type {any} */ ref) =>
|
|
422
|
+
(is(String, key) || is(Number, key) || is(Symbol, key)) && Object.hasOwnProperty.call(ref ?? Object, key)
|
|
496
423
|
|
|
497
424
|
/**
|
|
498
425
|
* @template {abstract new (...args: any[]) => any} T
|
|
@@ -509,7 +436,80 @@ export const $in = (/** @type {any} */ key, /** @type {any} */ ref) =>
|
|
|
509
436
|
*
|
|
510
437
|
* @returns {arg is bigint | boolean | number | string | symbol | undefined | null | InstanceType<T>}
|
|
511
438
|
*/
|
|
512
|
-
export const
|
|
439
|
+
export const is = (/** @type {T} */ type, /** @type {any} */ arg) => arg?.constructor === type
|
|
440
|
+
|
|
441
|
+
const _jcss = (
|
|
442
|
+
/** @type {JcssNode} */ node,
|
|
443
|
+
/** @type {string} */ prefix,
|
|
444
|
+
/** @type {string[]} */ result,
|
|
445
|
+
/** @type {(text: string) => string} */ split
|
|
446
|
+
) => {
|
|
447
|
+
const /** @type {[JcssNode | string[], string][]} */ queue = [[node, prefix]]
|
|
448
|
+
|
|
449
|
+
while (queue.length) {
|
|
450
|
+
const [style2, prefix2] = queue.shift() ?? []
|
|
451
|
+
|
|
452
|
+
if (style2 == null || prefix2 == null) {
|
|
453
|
+
continue
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
if (is(Array, style2)) {
|
|
457
|
+
result.push(prefix2, prefix2 !== '' ? '{' : '', style2.join(';'), prefix2 !== '' ? '}' : '')
|
|
458
|
+
} else {
|
|
459
|
+
const /** @type {[JcssNode | string[], string][]} */ todo = []
|
|
460
|
+
let /** @type {string[]} */ attributes = []
|
|
461
|
+
let attributesPushed = false
|
|
462
|
+
|
|
463
|
+
for (const key in style2) {
|
|
464
|
+
const value = style2[key]
|
|
465
|
+
|
|
466
|
+
if (is(String, value) || is(Number, value)) {
|
|
467
|
+
if (!attributesPushed) {
|
|
468
|
+
attributesPushed = true
|
|
469
|
+
attributes = []
|
|
470
|
+
todo.push([attributes, prefix2])
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
attributes.push(`${split(key).replace(/([A-Z])/g, (_, letter) => '-' + letter.toLowerCase())}:${value}`)
|
|
474
|
+
} else {
|
|
475
|
+
attributesPushed = false
|
|
476
|
+
|
|
477
|
+
const /** @type {string[]} */ newPrefix = []
|
|
478
|
+
const keySplitted = key.split(',')
|
|
479
|
+
|
|
480
|
+
for (const prefixItem of prefix2.split(',')) {
|
|
481
|
+
for (const keyItem of keySplitted) {
|
|
482
|
+
newPrefix.push(prefixItem + keyItem)
|
|
483
|
+
}
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
todo.push([value, newPrefix.join(',')])
|
|
487
|
+
}
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
queue.unshift(...todo)
|
|
491
|
+
}
|
|
492
|
+
}
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
export const jcss = (/** @type {JcssRoot} */ root, splitter = '$$') => {
|
|
496
|
+
const split = (/** @type {string} */ text) => text.split(splitter)[0]
|
|
497
|
+
const /** @type {string[]} */ result = []
|
|
498
|
+
|
|
499
|
+
for (const key in root) {
|
|
500
|
+
const value = root[key]
|
|
501
|
+
|
|
502
|
+
if (key[0] === '@') {
|
|
503
|
+
result.push(split(key) + '{')
|
|
504
|
+
_jcss(value, '', result, split)
|
|
505
|
+
result.push('}')
|
|
506
|
+
} else {
|
|
507
|
+
_jcss(value, split(key), result, split)
|
|
508
|
+
}
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
return result.join('')
|
|
512
|
+
}
|
|
513
513
|
|
|
514
514
|
const _locale = (
|
|
515
515
|
/** @type {Record<string, Record<string, string | Record<string, string>>>} */ locales,
|
|
@@ -520,22 +520,22 @@ const _locale = (
|
|
|
520
520
|
// @ts-expect-error
|
|
521
521
|
const v = locales?.[language]?.[version]?.[text]
|
|
522
522
|
|
|
523
|
-
if (
|
|
523
|
+
if (is(String, v)) {
|
|
524
524
|
return v
|
|
525
525
|
}
|
|
526
526
|
|
|
527
527
|
const t = locales?.[language]?.[text]
|
|
528
528
|
|
|
529
|
-
return
|
|
529
|
+
return is(String, t) ? t : text
|
|
530
530
|
}
|
|
531
531
|
|
|
532
|
-
export const
|
|
532
|
+
export const locale = (
|
|
533
533
|
/** @type {Record<string, Record<string, string | Record<string, string>>>} */ locales,
|
|
534
534
|
/** @type {string} */ defaultLanguage,
|
|
535
535
|
languages = navigator.languages
|
|
536
536
|
) => {
|
|
537
537
|
for (const language of languages) {
|
|
538
|
-
if (
|
|
538
|
+
if (has(language, locales)) {
|
|
539
539
|
// @ts-expect-error
|
|
540
540
|
return _locale.bind(0, locales, language)
|
|
541
541
|
}
|
|
@@ -545,12 +545,12 @@ export const $locale = (
|
|
|
545
545
|
return _locale.bind(0, locales, defaultLanguage)
|
|
546
546
|
}
|
|
547
547
|
|
|
548
|
-
export const
|
|
548
|
+
export const nanolight = (
|
|
549
549
|
/** @type {RegExp} */ pattern,
|
|
550
|
-
/** @type {((chunk: string, index: number) =>
|
|
550
|
+
/** @type {((chunk: string, index: number) => HArgs[1])[]} */ highlighters,
|
|
551
551
|
/** @type {string} */ code
|
|
552
552
|
) => {
|
|
553
|
-
const /** @type {
|
|
553
|
+
const /** @type {HArgs[1][]} */ result = []
|
|
554
554
|
|
|
555
555
|
code.split(pattern).forEach((chunk, index) => {
|
|
556
556
|
index %= highlighters.length
|
|
@@ -563,7 +563,7 @@ export const $nanolight = (
|
|
|
563
563
|
}
|
|
564
564
|
|
|
565
565
|
// @ts-expect-error
|
|
566
|
-
export const
|
|
566
|
+
export const nanolightJs = nanolight.bind(0,
|
|
567
567
|
/('.*?'|".*?"|`[\s\S]*?`)|(\/\/.*?\n|\/\*[\s\S]*?\*\/)|(break|case|catch|const|continue|debugger|default|delete|do|else|eval|export\s+type|export|extends|false|finally|for|from|function|goto|if|import|in|instanceof|is|keyof|let|NaN|new|null|package|return|super|switch|this|throw|true|try|typeof|undefined|var|void|while|with|yield)(?!\w)|([<>=.?:&|!~*/%+-])|(0x[\dabcdef]+|0o[01234567]+|0b[01]+|\d+(?:\.[\d_]+)?(?:e[+-]?[\d_]+)?)|([$\w]+)(?=\()|([$\wąćęłńóśżźĄĆĘŁŃÓŚŻŹ]+)/,
|
|
568
568
|
[
|
|
569
569
|
chunk => chunk, // no match
|
|
@@ -577,7 +577,7 @@ export const $nanolightJs = $nanolight.bind(0,
|
|
|
577
577
|
]
|
|
578
578
|
)
|
|
579
579
|
|
|
580
|
-
export const
|
|
580
|
+
export const plUral = (
|
|
581
581
|
/** @type {string} */ singular,
|
|
582
582
|
/** @type {string} */ plural2,
|
|
583
583
|
/** @type {string} */ plural5,
|
|
@@ -595,9 +595,9 @@ export const $plUral = (
|
|
|
595
595
|
: plural5
|
|
596
596
|
}
|
|
597
597
|
|
|
598
|
-
export const
|
|
598
|
+
export const s = _h('http://www.w3.org/2000/svg')
|
|
599
599
|
|
|
600
|
-
export const
|
|
600
|
+
export const set = (
|
|
601
601
|
/** @type {any} */ value,
|
|
602
602
|
/** @type {any} */ ref,
|
|
603
603
|
/** @type {(string | number | symbol)[]} */ ...keys
|
|
@@ -611,8 +611,8 @@ export const $set = (
|
|
|
611
611
|
for (let k = 0; k < last; ++k) {
|
|
612
612
|
const key = keys[k]
|
|
613
613
|
|
|
614
|
-
if (
|
|
615
|
-
ref[key] =
|
|
614
|
+
if (!has(key, ref)) {
|
|
615
|
+
ref[key] = is(Number, keys[k + 1]) ? [] : {}
|
|
616
616
|
}
|
|
617
617
|
|
|
618
618
|
ref = ref[key]
|
|
@@ -624,7 +624,7 @@ export const $set = (
|
|
|
624
624
|
const _ZEROS = '0'.repeat(16)
|
|
625
625
|
let _counter = 0
|
|
626
626
|
|
|
627
|
-
export const
|
|
627
|
+
export const uuid1 = ({
|
|
628
628
|
date = new Date(),
|
|
629
629
|
node = Math.random().toString(16).slice(2)
|
|
630
630
|
} = {}) => {
|
package/package.json
CHANGED
|
@@ -9,14 +9,17 @@
|
|
|
9
9
|
"CSS-in-JS",
|
|
10
10
|
"deepEqual",
|
|
11
11
|
"DOM",
|
|
12
|
+
"eq",
|
|
12
13
|
"equal",
|
|
13
14
|
"escape",
|
|
15
|
+
"gantt",
|
|
14
16
|
"graph",
|
|
15
17
|
"h",
|
|
16
18
|
"highlight",
|
|
17
19
|
"HyperScript",
|
|
18
20
|
"in",
|
|
19
21
|
"is",
|
|
22
|
+
"jcss",
|
|
20
23
|
"locale",
|
|
21
24
|
"localization",
|
|
22
25
|
"nanolight",
|
|
@@ -33,5 +36,5 @@
|
|
|
33
36
|
"types": "nnn.d.ts",
|
|
34
37
|
"name": "@jackens/nnn",
|
|
35
38
|
"type": "module",
|
|
36
|
-
"version": "2023.8.
|
|
39
|
+
"version": "2023.8.26"
|
|
37
40
|
}
|