@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.
Files changed (3) hide show
  1. package/nnn.d.ts +59 -59
  2. package/nnn.js +135 -135
  3. package/package.json +4 -1
package/nnn.d.ts CHANGED
@@ -1,40 +1,27 @@
1
1
  /**
2
- * The type of arguments of the `$c` helper.
2
+ * The type of arguments of the `escapeValues` and `escape` helpers.
3
3
  */
4
- export type $CNode = {
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 `$escapeValues` and `$escape` helpers.
7
+ * The type of arguments of the `h` and `s` helpers.
15
8
  */
16
- export type $EscapeMap = Map<any, (value?: any) => string>;
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 `$h` and `$s` helpers.
15
+ * The type of arguments of the `jcss` helper.
20
16
  */
21
- export type $HArgs = [
22
- string | Node,
23
- ...(Record<string, any> | null | undefined | Node | string | number | $HArgs)[]
24
- ];
17
+ export type JcssNode = {
18
+ [attributeOrSelector: string]: string | number | JcssNode;
19
+ };
25
20
 
26
21
  /**
27
- * A simple CSS-in-JS helper.
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 function $c(root: $CRoot, splitter?: string): string;
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 $chartable(options?: {
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 $eq(x: any, y: any): boolean;
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 $escape(escapeMap: $EscapeMap, template: TemplateStringsArray, ...values: any[]): string;
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 $escapeValues(escapeMap: $EscapeMap, values: any[]): string[];
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 $fixTypography(node: Node): void;
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 $get(defaultValue: any, ref: any, ...keys: (string | number | symbol)[]): any;
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 `$s`).
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 `$HArgs` are passed to `$h` and the results are appended to the element being created or modified.
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 $h<T extends keyof HTMLElementTagNameMap>(tag: T, ...args: $HArgs[1][]): HTMLElementTagNameMap[T];
120
- export function $h<N extends Node>(node: N, ...args: $HArgs[1][]): N;
121
- export function $h(...args: $HArgs): Node;
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 $in(key: any, ref: any): boolean;
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 $is(type: BigIntConstructor, arg: any): arg is bigint;
132
- export function $is(type: BooleanConstructor, arg: any): arg is boolean;
133
- export function $is(type: NumberConstructor, arg: any): arg is number;
134
- export function $is(type: StringConstructor, arg: any): arg is string;
135
- export function $is(type: SymbolConstructor, arg: any): arg is symbol;
136
- export function $is(type: undefined, arg: any): arg is null | undefined;
137
- export function $is<T extends abstract new (...args: any[]) => any>(type: T, arg: any): arg is InstanceType<T>;
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 $locale(
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 `$nanolightJs`).
149
+ * A generic helper for syntax highlighting (see also `nanolightJs`).
150
150
  */
151
- export function $nanolight(
151
+ export function nanolight(
152
152
  pattern: RegExp,
153
- highlighters: ((chunk: string, index: number) => $HArgs[1])[],
153
+ highlighters: ((chunk: string, index: number) => HArgs[1])[],
154
154
  code: string
155
- ): $HArgs[1][];
155
+ ): HArgs[1][];
156
156
 
157
157
  /**
158
158
  * A helper for highlighting JavaScript.
159
159
  */
160
- export function $nanolightJs(codeJs: string): $HArgs[1][];
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 $plUral(singular: string, plural2: string, plural5: string, value: number): string;
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 `$h`).
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 `$HArgs` are passed to `$s` and the results are appended to the element being created or modified.
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 $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;
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 $set(value: any, ref: any, ...keys: (string | number | symbol)[]): void;
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 $uuid1(options?: {
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
- * [attributeOrSelector: string]: string | number | $CNode;
11
- * }} $CNode
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 {Record<string, $CNode>} $CRoot
13
+ * @typedef {{
14
+ * [attributeOrSelector: string]: string | number | JcssNode;
15
+ * }} JcssNode
16
16
  */
17
17
 
18
18
  /**
19
- * @typedef {Map<any, (value?: any) => string>} $EscapeMap
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 $chartable = ({
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
- $set(parseFloat(value), zxY, z, x)
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 {$HArgs} */ graph = ['g', { transform: `translate(${left} ${top})` },
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 {$HArgs} */ lColors = ['g', { class: 'chartable-z-colors', transform: 'translate(-80 0)' }]
210
- const /** @type {$HArgs} */ lLabels = ['g', { class: 'chartable-z-labels', transform: 'translate(-95 0)' }]
211
- const /** @type {$HArgs} */ rColors = ['g', { class: 'chartable-z-colors', transform: 'translate(80 0)' }]
212
- const /** @type {$HArgs} */ rLabels = ['g', { class: 'chartable-z-labels', transform: 'translate(95 0)' }]
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 $s('svg', {
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 $eq = /** @returns {boolean} */ (/** @type {any} */ x, /** @type {any} */ y) => {
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) => $eq(item, y[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 => $eq(x[key], y[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 => $eq(xv, 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 $escape = (
330
- /** @type {$EscapeMap} */ escapeMap,
256
+ export const escape = (
257
+ /** @type {EscapeMap} */ escapeMap,
331
258
  /** @type {TemplateStringsArray} */ template,
332
259
  /** @type {any[]} */ ...values
333
- ) => String.raw(template, ...$escapeValues(escapeMap, values))
260
+ ) => String.raw(template, ...escapeValues(escapeMap, values))
334
261
 
335
- export const $escapeValues = (
336
- /** @type {$EscapeMap} */ escapeMap,
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 $fixTypography = (/** @type {Node} */ node) => {
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 && !$in(childNode.tagName, TAGS_TO_SKIP)) {
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
- ? $h('span', { style: 'white-space:nowrap' }, chunk)
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 $get = (
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 (!$in(key, ref)) {
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: $HArgs[1][]): HTMLElementTagNameMap[T];
406
- * <N extends Node> (node: N, ...args: $HArgs[1][]): N;
407
- * (...args: $HArgs): Node;
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: $HArgs[1][]): SVGElementTagNameMap[T];
411
- * <N extends Node> (node: N, ...args: $HArgs[1][]): N;
412
- * (...args: $HArgs): Node;
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 {$HArgs[0]} */ tagOrNode, /** @type {$HArgs[1][]} */ ...args) => {
422
- const node = $is(String, tagOrNode) ? createElement(tagOrNode) : tagOrNode
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 ($is(String, arg) || $is(Number, arg)) {
356
+ } else if (is(String, arg) || is(Number, arg)) {
430
357
  // @ts-expect-error
431
358
  child = new Text(arg)
432
- } else if ($is(Array, arg)) {
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 ($is(Object, value)) {
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, $is(String, value) ? value : '' + value)
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, $is(String, value) ? value : '' + value)
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 $h = _h()
419
+ export const h = _h()
493
420
 
494
- export const $in = (/** @type {any} */ key, /** @type {any} */ ref) =>
495
- ($is(String, key) || $is(Number, key) || $is(Symbol, key)) && Object.hasOwnProperty.call(ref ?? Object, key)
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 $is = (/** @type {T} */ type, /** @type {any} */ arg) => arg?.constructor === type
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 ($is(String, v)) {
523
+ if (is(String, v)) {
524
524
  return v
525
525
  }
526
526
 
527
527
  const t = locales?.[language]?.[text]
528
528
 
529
- return $is(String, t) ? t : text
529
+ return is(String, t) ? t : text
530
530
  }
531
531
 
532
- export const $locale = (
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 ($in(language, locales)) {
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 $nanolight = (
548
+ export const nanolight = (
549
549
  /** @type {RegExp} */ pattern,
550
- /** @type {((chunk: string, index: number) => $HArgs[1])[]} */ highlighters,
550
+ /** @type {((chunk: string, index: number) => HArgs[1])[]} */ highlighters,
551
551
  /** @type {string} */ code
552
552
  ) => {
553
- const /** @type {$HArgs[1][]} */ result = []
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 $nanolightJs = $nanolight.bind(0,
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 $plUral = (
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 $s = _h('http://www.w3.org/2000/svg')
598
+ export const s = _h('http://www.w3.org/2000/svg')
599
599
 
600
- export const $set = (
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 (!$in(key, ref)) {
615
- ref[key] = $is(Number, keys[k + 1]) ? [] : {}
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 $uuid1 = ({
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.20"
39
+ "version": "2023.8.26"
37
40
  }