@jackens/nnn 2023.10.13 → 2023.11.1

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 (2) hide show
  1. package/nnn.js +417 -1423
  2. package/package.json +1 -1
package/nnn.js CHANGED
@@ -1,132 +1,111 @@
1
- /* eslint-disable no-console */
2
-
3
- export const _test = {}
4
- export const _version = '2023.10.13'
5
-
6
- /**
7
- * ```ts
8
- * export type EscapeMap = Map<any, (value?: any) => string>;
9
- * ```
10
- */
11
-
12
- /**
13
- * @typedef {Map<any, (value?: any) => string>} EscapeMap
14
- *
15
- * The type of arguments of the `escapeValues` and `escape` helpers.
16
- */
17
-
18
- /**
19
- * ```ts
20
- * export type HArgs = [
21
- * string | Node,
22
- * ...(Record<string, any> | null | undefined | Node | string | number | HArgs)[]
23
- * ];
24
- * ```
25
- */
26
-
27
- /**
28
- * @typedef {[
29
- * string | Node,
30
- * ...(Record<string, any> | null | undefined | Node | string | number | HArgs)[]
31
- * ]} HArgs
32
- *
33
- * The type of arguments of the `h` and `s` helpers.
34
- */
35
-
36
- /**
37
- * ```ts
38
- * export type JcssNode = {
39
- * [attributeOrSelector: string]: string | number | JcssNode;
40
- * };
41
- * ```
42
- */
43
-
44
- /**
45
- * @typedef {{
46
- * [attributeOrSelector: string]: string | number | JcssNode;
47
- * }} JcssNode
48
- *
49
- * The type of arguments of the `jcss` helper.
50
- */
51
-
52
- /**
53
- * ```ts
54
- * export type JcssRoot = Record<string, JcssNode>;
55
- * ```
56
- */
57
-
58
- /**
59
- * @typedef {Record<string, JcssNode>} JcssRoot
60
- *
61
- * The type of arguments of the `jcss` helper.
62
- */
63
-
64
- const _COLORS = ['#e22', '#e73', '#fc3', '#ad4', '#4d9', '#3be', '#45d', '#c3e']
65
-
66
- /**
67
- * ```ts
68
- * export function chartable(options?: {
69
- * bottom?: number;
70
- * gapX?: number;
71
- * gapY?: number;
72
- * headerColumn?: boolean;
73
- * headerRow?: boolean;
74
- * id?: string;
75
- * left?: number;
76
- * maxY?: number;
77
- * right?: number;
78
- * singleScale?: boolean;
79
- * table?: HTMLTableElement;
80
- * title?: string;
81
- * top?: number;
82
- * xLabels?: string[];
83
- * zLabels?: string[];
84
- * zxY?: number[][];
85
- * }): SVGSVGElement;
86
- * ```
87
- */
1
+ // src/eq.js
2
+ var eq = (
3
+ /** @return {boolean} */
4
+ (x, y) => {
5
+ if (x === y) {
6
+ return true;
7
+ }
8
+ const xConstructor = x?.constructor;
9
+ if (xConstructor === y?.constructor) {
10
+ if (xConstructor === Number) {
11
+ return isNaN(x) && isNaN(y) || +x === +y;
12
+ }
13
+ if (xConstructor === Date) {
14
+ return +x === +y;
15
+ }
16
+ if (xConstructor === String || xConstructor === RegExp) {
17
+ return "" + x === "" + y;
18
+ }
19
+ if (xConstructor === Array) {
20
+ return x.length === y.length && x.every((item, index) => eq(item, y[index]));
21
+ }
22
+ if (xConstructor === Object) {
23
+ const keysOfX = Object.keys(x);
24
+ return keysOfX.length === Object.keys(y).length && keysOfX.every((key) => eq(x[key], y[key]));
25
+ }
26
+ if (xConstructor === Set || xConstructor === Map) {
27
+ if (x.size !== y.size) {
28
+ return false;
29
+ }
30
+ const xa = [...x];
31
+ const ya = [...y];
32
+ return xa.every((xv) => ya.find((yv) => eq(xv, yv)));
33
+ }
34
+ }
35
+ return false;
36
+ }
37
+ );
38
+
39
+ // src/is.js
40
+ var is = (type, arg) => arg?.constructor === type;
41
+
42
+ // src/h.js
43
+ var _NS = {
44
+ xlink: "http://www.w3.org/1999/xlink"
45
+ };
46
+ var _h = (namespaceURI) => {
47
+ const createElement = namespaceURI == null ? (tag) => document.createElement(tag) : (tag) => document.createElementNS(namespaceURI, tag);
48
+ const h2 = (tagOrNode, ...args) => {
49
+ const node = is(String, tagOrNode) ? createElement(tagOrNode) : tagOrNode;
50
+ for (const arg of args) {
51
+ let child = null;
52
+ if (arg instanceof Node) {
53
+ child = arg;
54
+ } else if (is(String, arg) || is(Number, arg)) {
55
+ child = new Text(arg);
56
+ } else if (is(Array, arg)) {
57
+ child = h2(...arg);
58
+ } else if (arg != null) {
59
+ for (const name in arg) {
60
+ const value = arg[name];
61
+ if (name[0] === "$") {
62
+ const name1 = name.slice(1);
63
+ if (is(Object, value)) {
64
+ node[name1] = node[name1] ?? {};
65
+ Object.assign(node[name1], value);
66
+ } else {
67
+ node[name1] = value;
68
+ }
69
+ } else if (node instanceof Element) {
70
+ const indexOfColon = name.indexOf(":");
71
+ if (indexOfColon >= 0) {
72
+ const ns = _NS[name.slice(0, indexOfColon)];
73
+ if (ns != null) {
74
+ const basename = name.slice(indexOfColon + 1);
75
+ if (value === true) {
76
+ node.setAttributeNS(ns, basename, "");
77
+ } else if (value === false) {
78
+ node.removeAttributeNS(ns, basename);
79
+ } else {
80
+ node.setAttributeNS(ns, basename, is(String, value) ? value : "" + value);
81
+ }
82
+ }
83
+ } else {
84
+ if (value === true) {
85
+ node.setAttribute(name, "");
86
+ } else if (value === false) {
87
+ node.removeAttribute(name);
88
+ } else {
89
+ node.setAttribute(name, is(String, value) ? value : "" + value);
90
+ }
91
+ }
92
+ }
93
+ }
94
+ }
95
+ if (child != null) {
96
+ node.appendChild(child);
97
+ }
98
+ }
99
+ return node;
100
+ };
101
+ return h2;
102
+ };
103
+ var h = _h();
104
+ var s = _h("http://www.w3.org/2000/svg");
88
105
 
89
- /**
90
- * A helper for creating a chart based on a table (conf. <https://jackens.github.io/nnn/chartable/>).
91
- *
92
- * Options:
93
- * - `bottom`: bottom padding (for X axis labels)
94
- * - `gapX`: X axis spacing
95
- * - `gapY`: Y axis spacing
96
- * - `headerColumn`: flag indicating that `table` has a header column (with X axis labels)
97
- * - `headerRow`: flag indicating that `table` has a header row (with data series labels)
98
- * - `id`: chart id
99
- * - `left`: left padding (for data series labels)
100
- * - `maxY`: number of Y axis lines
101
- * - `right`: right padding (for data series labels)
102
- * - `singleScale`: flag to force single scale
103
- * - `table`: `HTMLTableElement` to extract data, data series labels and X axis labels
104
- * - `title`: chart title
105
- * - `top`: top padding (for the title)
106
- * - `xLabels`: X axis labels
107
- * - `zLabels`: data series labels
108
- * - `zxY`: chart data
109
- *
110
- * @param {{
111
- * bottom?: number;
112
- * gapX?: number;
113
- * gapY?: number;
114
- * headerColumn?: boolean;
115
- * headerRow?: boolean;
116
- * id?: string;
117
- * left?: number;
118
- * maxY?: number;
119
- * right?: number;
120
- * singleScale?: boolean;
121
- * table?: HTMLTableElement;
122
- * title?: string;
123
- * top?: number;
124
- * xLabels?: string[];
125
- * zLabels?: string[];
126
- * zxY?: number[][];
127
- * }} options
128
- */
129
- export const chartable = ({
106
+ // src/chartable.js
107
+ var _COLORS = ["#e22", "#e73", "#fc3", "#ad4", "#4d9", "#3be", "#45d", "#c3e"];
108
+ var chartable = ({
130
109
  bottom = 50,
131
110
  gapX = 70,
132
111
  gapY = 30,
@@ -145,1390 +124,405 @@ export const chartable = ({
145
124
  zxY = []
146
125
  } = {}) => {
147
126
  if (table != null) {
148
- const zxYNotPassed = !zxY.length
149
- const xLabelsNotPassed = !xLabels.length
150
- const zLabelsNotPassed = !zLabels.length
151
-
152
- table.querySelectorAll('tr').forEach((row, r) => row.querySelectorAll('td,th').forEach((col, c) => {
153
- const x = r - +headerRow
154
- const z = c - +headerColumn
155
- // @ts-expect-error
156
- const value = col.innerText
157
-
127
+ const zxYNotPassed = !zxY.length;
128
+ const xLabelsNotPassed = !xLabels.length;
129
+ const zLabelsNotPassed = !zLabels.length;
130
+ table.querySelectorAll("tr").forEach((row, r) => row.querySelectorAll("td,th").forEach((col, c) => {
131
+ const x = r - +headerRow;
132
+ const z = c - +headerColumn;
133
+ const value = col.innerText;
158
134
  if (x >= 0 && z >= 0 && zxYNotPassed) {
159
- zxY[z] = zxY[z] ?? []
160
- zxY[z][x] = parseFloat(value)
135
+ zxY[z] = zxY[z] ?? [];
136
+ zxY[z][x] = parseFloat(value);
161
137
  } else if (x >= 0 && z < 0 && xLabelsNotPassed) {
162
- xLabels[x] = value
138
+ xLabels[x] = value;
163
139
  } else if (x < 0 && z >= 0 && zLabelsNotPassed) {
164
- zLabels[z] = value
140
+ zLabels[z] = value;
165
141
  }
166
- }))
142
+ }));
167
143
  }
168
-
169
- let bestScales = [Infinity, -Infinity, Infinity, -Infinity, Infinity]
170
-
171
- const ranges = zxY.map(xY => {
172
- xY = xY.filter(y => !isNaN(y))
173
- return [Math.min(...xY), Math.max(...xY)]
174
- })
175
-
144
+ let bestScales = [Infinity, -Infinity, Infinity, -Infinity, Infinity];
145
+ const ranges = zxY.map((xY) => {
146
+ xY = xY.filter((y) => !isNaN(y));
147
+ return [Math.min(...xY), Math.max(...xY)];
148
+ });
176
149
  if (singleScale) {
177
- bestScales = ranges.reduce(([totalMin, totalMax], [min, max]) =>
178
- [Math.min(totalMin, min), Math.max(totalMax, max)], bestScales)
150
+ bestScales = ranges.reduce(([totalMin, totalMax], [min, max]) => [Math.min(totalMin, min), Math.max(totalMax, max)], bestScales);
179
151
  } else {
180
- ranges.forEach(([min1, max0]) => ranges.forEach(([min0, max1]) => {
181
- if (min0 >= min1 && max1 >= max0) {
182
- let min2 = Infinity
183
- let max2 = -Infinity
184
-
152
+ ranges.forEach(([min12, max0]) => ranges.forEach(([min0, max12]) => {
153
+ if (min0 >= min12 && max12 >= max0) {
154
+ let min22 = Infinity;
155
+ let max22 = -Infinity;
185
156
  ranges.forEach(([min, max]) => {
186
- if (min < min1 || max1 < max) {
187
- if (min2 > min) {
188
- min2 = min
157
+ if (min < min12 || max12 < max) {
158
+ if (min22 > min) {
159
+ min22 = min;
189
160
  }
190
- if (max2 < max) {
191
- max2 = max
161
+ if (max22 < max) {
162
+ max22 = max;
192
163
  }
193
164
  }
194
- })
195
-
196
- let cost = 0
197
-
165
+ });
166
+ let cost = 0;
198
167
  ranges.forEach(([min, max]) => {
199
168
  if (min < max) {
200
- cost += 1 - (max - min) / (min1 <= min && max <= max1 ? max1 - min1 : max2 - min2)
169
+ cost += 1 - (max - min) / (min12 <= min && max <= max12 ? max12 - min12 : max22 - min22);
201
170
  }
202
- })
203
-
171
+ });
204
172
  if (bestScales[4] > cost) {
205
- bestScales = [min1, max1, min2, max2, cost]
173
+ bestScales = [min12, max12, min22, max22, cost];
206
174
  }
207
175
  }
208
- }))
176
+ }));
209
177
  }
210
-
211
- const [min1, max1, min2, max2] = bestScales
212
- const maxX = zxY[0].length
213
- const xi = Array.from({ length: maxX }, (_, x) => x * gapX)
214
- const yi = Array.from({ length: maxY }, (_, y) => y * gapY)
215
- const w = gapX * (maxX - 1)
216
- const h = gapY * (maxY - 1)
217
- const svgW = left + w + right
218
- const svgH = top + h + bottom
219
- const /** @type {HArgs} */ graph = ['g', { transform: `translate(${left} ${top})` },
220
- ...yi.map(y => ['line', { x1: 0, x2: w, y1: y, y2: y, stroke: '#8888' }]),
221
- ...xi.map(x => ['line', { x1: x, x2: x, y1: 0, y2: h, stroke: '#8888' }])]
222
- const /** @type {HArgs} */ lColors = ['g', { class: 'chartable-z-colors', transform: 'translate(-80 0)' }]
223
- const /** @type {HArgs} */ lLabels = ['g', { class: 'chartable-z-labels', transform: 'translate(-95 0)' }]
224
- const /** @type {HArgs} */ rColors = ['g', { class: 'chartable-z-colors', transform: 'translate(80 0)' }]
225
- const /** @type {HArgs} */ rLabels = ['g', { class: 'chartable-z-labels', transform: 'translate(95 0)' }]
226
- const yLabel = (/** @type {number} */ min, /** @type {number} */ max, /** @type {number} */ y) =>
227
- (min + (max - min) * (maxY - 1 - y) / (maxY - 1)).toFixed(2).replace(/\.?0+$/, '')
228
-
178
+ const [min1, max1, min2, max2] = bestScales;
179
+ const maxX = zxY[0].length;
180
+ const xi = Array.from({ length: maxX }, (_, x) => x * gapX);
181
+ const yi = Array.from({ length: maxY }, (_, y) => y * gapY);
182
+ const w = gapX * (maxX - 1);
183
+ const h2 = gapY * (maxY - 1);
184
+ const svgW = left + w + right;
185
+ const svgH = top + h2 + bottom;
186
+ const graph = [
187
+ "g",
188
+ { transform: `translate(${left} ${top})` },
189
+ ...yi.map((y) => ["line", { x1: 0, x2: w, y1: y, y2: y, stroke: "#8888" }]),
190
+ ...xi.map((x) => ["line", { x1: x, x2: x, y1: 0, y2: h2, stroke: "#8888" }])
191
+ ];
192
+ const lColors = ["g", { class: "chartable-z-colors", transform: "translate(-80 0)" }];
193
+ const lLabels = ["g", { class: "chartable-z-labels", transform: "translate(-95 0)" }];
194
+ const rColors = ["g", { class: "chartable-z-colors", transform: "translate(80 0)" }];
195
+ const rLabels = ["g", { class: "chartable-z-labels", transform: "translate(95 0)" }];
196
+ const yLabel = (min, max, y) => (min + (max - min) * (maxY - 1 - y) / (maxY - 1)).toFixed(2).replace(/\.?0+$/, "");
229
197
  zxY.forEach((xa, z) => {
230
- const cls = `chartable-z-${z + 1}`
231
- const fill = _COLORS[z % _COLORS.length]
232
- let [min, max] = ranges[z]
233
-
198
+ const cls = `chartable-z-${z + 1}`;
199
+ const fill = _COLORS[z % _COLORS.length];
200
+ let [min, max] = ranges[z];
234
201
  if (min1 <= min && max <= max1) {
235
- min = min1
236
- max = max1
237
- lColors.push(['circle', { class: cls, cx: 0, cy: gapY * (lColors.length - 2), r: 5, fill }])
238
- lLabels.push(['text',
239
- { x: 0, y: gapY * (lLabels.length - 2), 'text-anchor': 'end', 'alignment-baseline': 'middle' },
240
- zLabels[z]])
202
+ min = min1;
203
+ max = max1;
204
+ lColors.push(["circle", { class: cls, cx: 0, cy: gapY * (lColors.length - 2), r: 5, fill }]);
205
+ lLabels.push([
206
+ "text",
207
+ { x: 0, y: gapY * (lLabels.length - 2), "text-anchor": "end", "alignment-baseline": "middle" },
208
+ zLabels[z]
209
+ ]);
241
210
  } else {
242
- min = min2
243
- max = max2
244
- rColors.push(['circle', { class: cls, cx: 0, cy: gapY * (rColors.length - 2), r: 5, fill }])
245
- rLabels.push(['text',
246
- { x: 0, y: gapY * (rLabels.length - 2), 'text-anchor': 'start', 'alignment-baseline': 'middle' },
247
- zLabels[z]])
248
- }
249
-
250
- const y = xa.map(x => isNaN(x) ? x : h * (max - x) / (max - min))
251
-
211
+ min = min2;
212
+ max = max2;
213
+ rColors.push(["circle", { class: cls, cx: 0, cy: gapY * (rColors.length - 2), r: 5, fill }]);
214
+ rLabels.push([
215
+ "text",
216
+ { x: 0, y: gapY * (rLabels.length - 2), "text-anchor": "start", "alignment-baseline": "middle" },
217
+ zLabels[z]
218
+ ]);
219
+ }
220
+ const y = xa.map((x) => isNaN(x) ? x : h2 * (max - x) / (max - min));
252
221
  xi.forEach((x, i) => {
253
222
  if (!isNaN(y[i])) {
254
- graph.push(['circle', { class: cls, cx: x, cy: y[i], r: 5, fill }])
255
-
223
+ graph.push(["circle", { class: cls, cx: x, cy: y[i], r: 5, fill }]);
256
224
  if (!isNaN(y[i - 1])) {
257
- graph.push(['line', { class: cls, x1: x, x2: xi[i - 1], y1: y[i], y2: y[i - 1], stroke: fill }])
225
+ graph.push(["line", { class: cls, x1: x, x2: xi[i - 1], y1: y[i], y2: y[i - 1], stroke: fill }]);
258
226
  }
259
227
  }
260
- })
261
- })
262
-
263
- return s('svg', {
264
- viewBox: `0 0 ${svgW} ${svgH}`,
265
- width: `${svgW}px`,
266
- height: `${svgH}px`,
267
- class: 'chartable'
268
- }, id != null ? { id } : null, title != null
269
- ? ['text',
270
- { class: 'chartable-title', x: svgW / 2, y: top / 2, 'text-anchor': 'middle', 'alignment-baseline': 'middle' },
271
- title]
272
- : null,
273
- graph,
274
- min1 < Infinity
275
- ? ['g', { class: 'chartable-left', transform: `translate(${left} ${top})` },
276
- ['g', { class: 'chartable-y-labels', transform: 'translate(-15 0)' },
277
- ...yi.map((y, i) => ['text',
278
- { x: 0, y, 'text-anchor': 'end', 'alignment-baseline': 'middle' },
279
- yLabel(min1, max1, i)])],
280
- lColors, lLabels]
281
- : null,
282
- min2 < Infinity
283
- ? ['g', { class: 'chartable-right', transform: `translate(${left + w} ${top})` },
284
- ['g', { class: 'chartable-y-labels', transform: 'translate(15 0)' },
285
- ...yi.map((y, i) => ['text',
286
- { x: 0, y, 'text-anchor': 'start', 'alignment-baseline': 'middle' },
287
- yLabel(min2, max2, i)])],
288
- rColors, rLabels]
289
- : null,
290
- xLabels.length > 0
291
- ? ['g', { transform: `translate(${left} ${top + h})` },
292
- ['g', { class: 'chartable-x-labels', transform: 'translate(0 15)' },
293
- ...xi.map((x, i) => ['text',
294
- { x, y: 0, 'text-anchor': 'middle', 'alignment-baseline': 'hanging' },
295
- xLabels[i]])]]
296
- : null
297
- )
298
- }
299
-
300
- /**
301
- * ```ts
302
- * export function eq(x: any, y: any): boolean;
303
- * ```
304
- */
305
-
306
- /**
307
- * A helper that checks equality of the given arguments.
308
- */
309
- export const eq = /** @returns {boolean} */ (/** @type {any} */ x, /** @type {any} */ y) => {
310
- if (x === y) {
311
- return true
312
- }
313
-
314
- const xConstructor = x?.constructor
315
-
316
- if (xConstructor === y?.constructor) {
317
- if (xConstructor === Number) {
318
- return (isNaN(x) && isNaN(y)) || +x === +y
319
- }
320
-
321
- if (xConstructor === Date) {
322
- return +x === +y
323
- }
324
-
325
- if (xConstructor === String || xConstructor === RegExp) {
326
- return '' + x === '' + y
327
- }
328
-
329
- if (xConstructor === Array) {
330
- return x.length === y.length && x.every((/** @type {any} */ item, /** @type {number} */ index) => eq(item, y[index]))
331
- }
332
-
333
- if (xConstructor === Object) {
334
- const keysOfX = Object.keys(x)
335
- return keysOfX.length === Object.keys(y).length && keysOfX.every(key => eq(x[key], y[key]))
336
- }
337
-
338
- if (xConstructor === Set || xConstructor === Map) {
339
- if (x.size !== y.size) {
340
- return false
341
- }
342
- const xa = [...x]
343
- const ya = [...y]
344
- return xa.every(xv => ya.find(yv => eq(xv, yv)))
345
- }
346
- }
347
-
348
- return false
349
- }
350
-
351
- _test.eq = () => {
352
- console.assert(eq(true, true))
353
- console.assert(eq(NaN, NaN))
354
- console.assert(!eq(null, undefined))
355
- console.assert(eq(42, 42))
356
- // eslint-disable-next-line no-new-wrappers
357
- console.assert(eq(42, new Number(42)))
358
- console.assert(eq(42, Number(42)))
359
- // eslint-disable-next-line no-new-wrappers
360
- console.assert(eq(new Number(42), Number(42)))
361
- console.assert(!eq(42, '42'))
362
- console.assert(eq('42', '42'))
363
- // eslint-disable-next-line no-new-wrappers
364
- console.assert(eq('42', new String('42')))
365
- console.assert(eq('42', String('42')))
366
- // eslint-disable-next-line no-new-wrappers
367
- console.assert(eq(String('42'), new String('42')))
368
- console.assert(eq(/42/, /42/))
369
- console.assert(!eq(/42/, /42/g))
370
- console.assert(eq(new Date(42), new Date(42)))
371
- console.assert(!eq(new Date(), new Date(42)))
372
- console.assert(eq({ j: '42', c: 42 }, { c: 42, j: '42' }))
373
- console.assert(eq([42, '42'], [42, '42']))
374
- console.assert(eq(new Set(['42', 42]), new Set([42, '42'])))
375
- console.assert(!eq(new Set(['42', 42]), new Set([42])))
376
- console.assert(!eq(new Set([42, undefined]), new Set([42])))
377
- console.assert(eq(
378
- new Map([[{ j: 42 }, { J: '42' }], [{ c: 42 }, { C: '42' }]]),
379
- new Map([[{ c: 42 }, { C: '42' }], [{ j: 42 }, { J: '42' }]])
380
- ))
381
- console.assert(!eq(
382
- new Map([[{ j: 42 }, { J: '42' }], [{ c: 42 }, { C: '42' }]]),
383
- new Map([[{ j: '42' }, { J: 42 }], [{ c: '42' }, { C: 42 }]])
384
- ))
385
- }
386
-
387
- /**
388
- * ```ts
389
- * export function escape(escapeMap: EscapeMap, template: TemplateStringsArray, ...values: any[]): string;
390
- * ```
391
- */
392
-
393
- /**
394
- * A generic helper for escaping `values` by given `escapeMap` (in *TemplateStrings* flavor).
395
- */
396
- export const escape = (
397
- /** @type {EscapeMap} */ escapeMap,
398
- /** @type {TemplateStringsArray} */ template,
399
- /** @type {any[]} */ ...values
400
- ) => String.raw(template, ...escapeValues(escapeMap, values))
401
-
402
- _test.escape = () => {
403
- // @ts-expect-error
404
- const /** @type {EscapeMap} */ escapeMap = new Map([
405
- [undefined, () => 'NULL'],
406
- [Array, (/** @type {any[]} */ values) => escapeValues(escapeMap, values).join(', ')],
407
- [Boolean, (/** @type {boolean} */ value) => `b'${+value}'`],
408
- [Date, (/** @type {Date} */ value) => `'${value.toISOString().replace(/^(.+)T(.+)\..*$/, '$1 $2')}'`],
409
- [Number, (/** @type {number} */ value) => `${value}`],
410
- [String, (/** @type {string} */ value) => `'${value.replace(/'/g, "''")}'`]
411
- ])
412
-
413
- // @ts-expect-error
414
- const sql = escape.bind(null, escapeMap)
415
-
416
- const actual = sql`
417
- SELECT *
418
- FROM table_name
419
- WHERE column_name IN (${[true, null, undefined, 42, '42', "4'2", /42/, new Date(323325e6)]})`
420
-
421
- const expected = `
422
- SELECT *
423
- FROM table_name
424
- WHERE column_name IN (b'1', NULL, NULL, 42, '42', '4''2', NULL, '1980-03-31 04:30:00')`
425
-
426
- console.assert(actual === expected)
427
- }
428
-
429
- /**
430
- * ```ts
431
- * export function escapeValues(escapeMap: EscapeMap, values: any[]): string[];
432
- * ```
433
- */
434
-
435
- /**
436
- * A generic helper for escaping `values` by given `escapeMap`.
437
- */
438
- export const escapeValues = (
439
- /** @type {EscapeMap} */ escapeMap,
440
- /** @type {any[]} */ values
441
- ) => values.map(value => (escapeMap.get(value?.constructor) ?? escapeMap.get(undefined))?.(value) ?? '')
442
-
443
- const _TAGS_TO_SKIP = { IFRAME: 1, NOSCRIPT: 1, PRE: 1, SCRIPT: 1, STYLE: 1, TEXTAREA: 1 }
444
-
445
- /**
446
- * ```ts
447
- * export function fixTypography(node: Node): void;
448
- * ```
449
- */
450
-
451
- /**
452
- * A helper that implements typographic corrections specific to Polish typography.
453
- */
454
- export const fixTypography = (/** @type {Node} */ node) => {
455
- const /** @type {Node[]} */ queue = [node]
456
-
228
+ });
229
+ });
230
+ return s(
231
+ "svg",
232
+ {
233
+ viewBox: `0 0 ${svgW} ${svgH}`,
234
+ width: `${svgW}px`,
235
+ height: `${svgH}px`,
236
+ class: "chartable"
237
+ },
238
+ id != null ? { id } : null,
239
+ title != null ? [
240
+ "text",
241
+ { class: "chartable-title", x: svgW / 2, y: top / 2, "text-anchor": "middle", "alignment-baseline": "middle" },
242
+ title
243
+ ] : null,
244
+ graph,
245
+ min1 < Infinity ? [
246
+ "g",
247
+ { class: "chartable-left", transform: `translate(${left} ${top})` },
248
+ [
249
+ "g",
250
+ { class: "chartable-y-labels", transform: "translate(-15 0)" },
251
+ ...yi.map((y, i) => [
252
+ "text",
253
+ { x: 0, y, "text-anchor": "end", "alignment-baseline": "middle" },
254
+ yLabel(min1, max1, i)
255
+ ])
256
+ ],
257
+ lColors,
258
+ lLabels
259
+ ] : null,
260
+ min2 < Infinity ? [
261
+ "g",
262
+ { class: "chartable-right", transform: `translate(${left + w} ${top})` },
263
+ [
264
+ "g",
265
+ { class: "chartable-y-labels", transform: "translate(15 0)" },
266
+ ...yi.map((y, i) => [
267
+ "text",
268
+ { x: 0, y, "text-anchor": "start", "alignment-baseline": "middle" },
269
+ yLabel(min2, max2, i)
270
+ ])
271
+ ],
272
+ rColors,
273
+ rLabels
274
+ ] : null,
275
+ xLabels.length > 0 ? [
276
+ "g",
277
+ { transform: `translate(${left} ${top + h2})` },
278
+ [
279
+ "g",
280
+ { class: "chartable-x-labels", transform: "translate(0 15)" },
281
+ ...xi.map((x, i) => [
282
+ "text",
283
+ { x, y: 0, "text-anchor": "middle", "alignment-baseline": "hanging" },
284
+ xLabels[i]
285
+ ])
286
+ ]
287
+ ] : null
288
+ );
289
+ };
290
+
291
+ // src/escape.js
292
+ var escapeValues = (escapeMap, values) => values.map((value) => (escapeMap.get(value?.constructor) ?? escapeMap.get(void 0))?.(value) ?? "");
293
+ var escape = (escapeMap, template, ...values) => String.raw(template, ...escapeValues(escapeMap, values));
294
+
295
+ // src/has.js
296
+ var has = (key, ref) => (is(String, key) || is(Number, key) || is(Symbol, key)) && Object.hasOwnProperty.call(ref ?? Object, key);
297
+
298
+ // src/fixTypography.js
299
+ var _TAGS_TO_SKIP = { IFRAME: 1, NOSCRIPT: 1, PRE: 1, SCRIPT: 1, STYLE: 1, TEXTAREA: 1 };
300
+ var fixTypography = (node) => {
301
+ const queue = [node];
457
302
  while (queue.length > 0) {
458
- const node0 = queue.shift()
459
-
303
+ const node0 = queue.shift();
460
304
  if (node0 instanceof Element) {
461
305
  for (let i = 0; i < node0.childNodes.length; ++i) {
462
- const childNode = node0.childNodes[i]
463
-
306
+ const childNode = node0.childNodes[i];
464
307
  if (childNode instanceof Text) {
465
- queue.push(childNode)
308
+ queue.push(childNode);
466
309
  } else if (childNode instanceof Element && !has(childNode.tagName, _TAGS_TO_SKIP)) {
467
- queue.push(childNode)
310
+ queue.push(childNode);
468
311
  }
469
312
  }
470
- } else if (node0 instanceof Text && node0.nodeValue != null && node0.nodeValue.trim() !== '') {
471
- let /** @type {Node} */ previousNode = node0
472
-
313
+ } else if (node0 instanceof Text && node0.nodeValue != null && node0.nodeValue.trim() !== "") {
314
+ let previousNode = node0;
473
315
  node0.nodeValue.split(/(\s|\(|„)([aiouwz—]\s)/gi).forEach((chunk, i) => {
474
- i %= 3
475
-
476
- const currentNode = i === 2
477
- ? h('span', { style: 'white-space:nowrap' }, chunk)
478
- : i === 1
479
- ? document.createTextNode(chunk)
480
- : document.createTextNode(chunk.replace(/(\/(?=[^/\s])|\.(?=[^\s]))/g, '$1\u200B'))
481
-
316
+ i %= 3;
317
+ const currentNode = i === 2 ? h("span", { style: "white-space:nowrap" }, chunk) : i === 1 ? document.createTextNode(chunk) : document.createTextNode(chunk.replace(/(\/(?=[^/\s])|\.(?=[^\s]))/g, "$1\u200B"));
482
318
  if (node0.parentNode != null) {
483
- node0.parentNode.insertBefore(currentNode, previousNode.nextSibling)
484
- }
485
-
486
- previousNode = currentNode
487
- })
488
-
489
- node0.parentNode?.removeChild(node0)
490
- }
491
- }
492
- }
493
-
494
- _test.fixTypography = () => {
495
- const p = h('p', 'Pchnąć w tę łódź jeża lub ośm skrzyń fig (zob. https://pl.wikipedia.org/wiki/Pangram).')
496
-
497
- fixTypography(p)
498
-
499
- console.assert(p.innerHTML ===
500
- 'Pchnąć <span style="white-space:nowrap">w </span>tę łódź jeża lub ośm skrzyń fig ' +
501
- '(zob. https://\u200Bpl.\u200Bwikipedia.\u200Borg/\u200Bwiki/\u200BPangram).')
502
- }
503
-
504
- const /** @type {Record<string, string>} */ _NS = {
505
- xlink: 'http://www.w3.org/1999/xlink'
506
- }
507
-
508
- /**
509
- * @type {{
510
- * (namespaceURI?: null | undefined): {
511
- * <T extends keyof HTMLElementTagNameMap>(tag: T, ...args: HArgs[1][]): HTMLElementTagNameMap[T];
512
- * <N extends Node> (node: N, ...args: HArgs[1][]): N;
513
- * (...args: HArgs): Node;
514
- * };
515
- * (namespaceURI: 'http://www.w3.org/2000/svg'): {
516
- * <T extends keyof SVGElementTagNameMap> (tag: T, ...args: HArgs[1][]): SVGElementTagNameMap[T];
517
- * <N extends Node> (node: N, ...args: HArgs[1][]): N;
518
- * (...args: HArgs): Node;
519
- * };
520
- * }}
521
- */
522
- const _h = (/** @type {string?=} */ namespaceURI) => {
523
- const createElement = namespaceURI == null
524
- ? (/** @type {string } */ tag) => document.createElement(tag)
525
- : (/** @type {string } */ tag) => document.createElementNS(namespaceURI, tag)
526
-
527
- const h = (/** @type {HArgs[0]} */ tagOrNode, /** @type {HArgs[1][]} */ ...args) => {
528
- const node = is(String, tagOrNode) ? createElement(tagOrNode) : tagOrNode
529
-
530
- for (const arg of args) {
531
- let child = null
532
-
533
- if (arg instanceof Node) {
534
- child = arg
535
- } else if (is(String, arg) || is(Number, arg)) {
536
- // @ts-expect-error
537
- child = new Text(arg)
538
- } else if (is(Array, arg)) {
539
- // @ts-expect-error
540
- child = h(...arg)
541
- } else if (arg != null) {
542
- for (const name in arg) {
543
- const value = arg[name]
544
-
545
- if (name[0] === '$') {
546
- const name1 = name.slice(1)
547
-
548
- if (is(Object, value)) {
549
- // @ts-expect-error
550
- node[name1] = node[name1] ?? {}
551
- // @ts-expect-error
552
- Object.assign(node[name1], value)
553
- } else {
554
- // @ts-expect-error
555
- node[name1] = value
556
- }
557
- } else if (node instanceof Element) {
558
- const indexOfColon = name.indexOf(':')
559
-
560
- if (indexOfColon >= 0) {
561
- const /** @type {string=} */ ns = _NS[name.slice(0, indexOfColon)]
562
-
563
- if (ns != null) {
564
- const basename = name.slice(indexOfColon + 1)
565
-
566
- if (value === true) {
567
- node.setAttributeNS(ns, basename, '')
568
- } else if (value === false) {
569
- node.removeAttributeNS(ns, basename)
570
- } else {
571
- node.setAttributeNS(ns, basename, is(String, value) ? value : '' + value)
572
- }
573
- }
574
- } else {
575
- if (value === true) {
576
- node.setAttribute(name, '')
577
- } else if (value === false) {
578
- node.removeAttribute(name)
579
- } else {
580
- node.setAttribute(name, is(String, value) ? value : '' + value)
581
- }
582
- }
583
- }
319
+ node0.parentNode.insertBefore(currentNode, previousNode.nextSibling);
584
320
  }
585
- }
586
-
587
- if (child != null) {
588
- node.appendChild(child)
589
- }
321
+ previousNode = currentNode;
322
+ });
323
+ node0.parentNode?.removeChild(node0);
590
324
  }
591
-
592
- return node
593
325
  }
326
+ };
594
327
 
595
- return h
596
- }
597
-
598
- /**
599
- * ```ts
600
- * export function h<T extends keyof HTMLElementTagNameMap>(tag: T, ...args: HArgs[1][]): HTMLElementTagNameMap[T];
601
- * export function h<N extends Node>(node: N, ...args: HArgs[1][]): N;
602
- * export function h(...args: HArgs): Node;
603
- * ```
604
- */
605
-
606
- /**
607
- * A lightweight [HyperScript](https://github.com/hyperhype/hyperscript)-style helper for creating and modifying `HTMLElement`s (see also `s`).
608
- *
609
- * - The first argument of type `string` specifies the tag of the element to be created.
610
- * - The first argument of type `Node` specifies the element to be modified.
611
- * - All other arguments of type `Record<string, any>` are mappings of attributes and properties.
612
- * Keys starting with `$` specify *properties* (without the leading `$`) to be set on the element being created or modified.
613
- * (Note that `$` is not a valid attribute name character.)
614
- * All other keys specify *attributes* to be set by `setAttribute`.
615
- * An attribute equal to `false` causes the attribute to be removed by `removeAttribute`.
616
- * - All other arguments of type `null` or `undefined` are simply ignored.
617
- * - All other arguments of type `Node` are appended to the element being created or modified.
618
- * - All other arguments of type `string`/`number` are converted to `Text` nodes and appended to the element being created or modified.
619
- * - All other arguments of type `HArgs` are passed to `h` and the results are appended to the element being created or modified.
620
- */
621
- export const h = _h()
622
-
623
- _test.h = () => {
624
- const b = h('b')
625
-
626
- console.assert(b.outerHTML === '<b></b>')
627
-
628
- const i = h('i', 'text')
629
-
630
- h(b, i)
631
-
632
- console.assert(i.outerHTML === '<i>text</i>')
633
- console.assert(b.outerHTML === '<b><i>text</i></b>')
634
-
635
- h(i, { $className: 'some class' })
636
-
637
- console.assert(i.outerHTML === '<i class="some class">text</i>')
638
- console.assert(b.outerHTML === '<b><i class="some class">text</i></b>')
639
- }
640
-
641
- _test['h: innerText vs items'] = () => {
642
- console.assert(h('span', 'text').outerHTML === '<span>text</span>')
643
- console.assert(h('span', { $innerText: 'text' }).outerHTML === '<span>text</span>')
644
- }
645
-
646
- _test['h: style'] = () => {
647
- console.assert(h('div', { style: 'margin:0;padding:0' }).outerHTML ===
648
- '<div style="margin:0;padding:0"></div>')
649
- console.assert(h('div', { $style: 'margin:0;padding:0' }).outerHTML ===
650
- '<div style="margin: 0px; padding: 0px;"></div>')
651
- console.assert(h('div', { $style: { margin: 0, padding: 0 } }).outerHTML ===
652
- '<div style="margin: 0px; padding: 0px;"></div>')
653
- }
654
-
655
- _test['h: attributes vs properties'] = () => {
656
- const input1 = h('input', { value: 42 })
657
- const input2 = h('input', { $value: '42' })
658
-
659
- console.assert(input1.value === '42')
660
- console.assert(input2.value === '42')
661
-
662
- console.assert(input1.outerHTML === '<input value="42">')
663
- console.assert(input2.outerHTML === '<input>')
664
-
665
- const checkbox1 = h('input', { type: 'checkbox', checked: true })
666
- const checkbox2 = h('input', { type: 'checkbox', $checked: true })
667
-
668
- console.assert(checkbox1.checked === true)
669
- console.assert(checkbox2.checked === true)
670
-
671
- console.assert(checkbox1.outerHTML === '<input type="checkbox" checked="">')
672
- console.assert(checkbox2.outerHTML === '<input type="checkbox">')
673
- }
674
-
675
- _test['h: nested properties'] = () => {
676
- const div = h('div')
677
-
678
- // @ts-expect-error
679
- console.assert(div.key === undefined)
680
-
681
- h(div, { $key: { one: 1 } })
682
-
683
- // @ts-expect-error
684
- console.assert(eq(div.key, { one: 1 }))
685
-
686
- h(div, { $key: { two: 2 } })
687
-
688
- // @ts-expect-error
689
- console.assert(eq(div.key, { one: 1, two: 2 }))
690
- }
691
-
692
- /**
693
- * ```ts
694
- * export function has(key: any, ref: any): boolean;
695
- * ```
696
- */
697
-
698
- /**
699
- * A replacement for the `in` operator (not to be confused with the `for-in` loop) that works properly.
700
- */
701
- export const has = (/** @type {any} */ key, /** @type {any} */ ref) =>
702
- (is(String, key) || is(Number, key) || is(Symbol, key)) && Object.hasOwnProperty.call(ref ?? Object, key)
703
-
704
- _test.has = () => {
705
- const obj = { key: 'K', null: 'N' }
706
-
707
- console.assert('key' in obj)
708
- console.assert(has('key', obj))
709
-
710
- console.assert('null' in obj)
711
- console.assert(has('null', obj))
712
-
713
- // @ts-expect-error
714
- console.assert(null in obj)
715
- console.assert(!has(null, obj))
716
-
717
- console.assert('toString' in obj)
718
- console.assert(!has('toString', obj))
719
- }
720
-
721
- _test['has: null'] = () => {
722
- let typeError
723
-
724
- try {
725
- // @ts-expect-error
726
- console.assert('key' in null)
727
- } catch (error) {
728
- typeError = error
729
- }
730
-
731
- console.assert(typeError instanceof TypeError) // Cannot use 'in' operator to search for 'key' in null
732
- console.assert(!has('key', null))
733
- }
734
-
735
- /**
736
- * ```ts
737
- * export function is(type: BigIntConstructor, arg: any): arg is bigint;
738
- * export function is(type: BooleanConstructor, arg: any): arg is boolean;
739
- * export function is(type: NumberConstructor, arg: any): arg is number;
740
- * export function is(type: StringConstructor, arg: any): arg is string;
741
- * export function is(type: SymbolConstructor, arg: any): arg is symbol;
742
- * export function is(type: undefined, arg: any): arg is null | undefined;
743
- * export function is<T extends abstract new (...args: any[]) => any>(type: T, arg: any): arg is InstanceType<T>;
744
- * ```
745
- */
746
-
747
- /**
748
- * A helper that checks if the given argument is of a certain type.
749
- *
750
- * @template {abstract new (...args: any[]) => any} T
751
- *
752
- * @type {{
753
- * (type: BigIntConstructor, arg: any): arg is bigint;
754
- * (type: BooleanConstructor, arg: any): arg is boolean;
755
- * (type: NumberConstructor, arg: any): arg is number;
756
- * (type: StringConstructor, arg: any): arg is string;
757
- * (type: SymbolConstructor, arg: any): arg is symbol;
758
- * (type: undefined, arg: any): arg is undefined | null;
759
- * <T extends abstract new (...args: any[]) => any>(type: T, arg: any): arg is InstanceType<T>;
760
- * }}
761
- *
762
- * @returns {arg is bigint | boolean | number | string | symbol | undefined | null | InstanceType<T>}
763
- */
764
- export const is = (/** @type {T} */ type, /** @type {any} */ arg) => arg?.constructor === type
765
-
766
- _test.is = () => {
767
- console.assert(is(Number, 42))
768
- console.assert(is(Number, Number(42)))
769
- // eslint-disable-next-line no-new-wrappers
770
- console.assert(is(Number, new Number(42)))
771
- console.assert(is(Number, NaN))
772
- console.assert(is(String, '42'))
773
- console.assert(is(String, String('42')))
774
- // eslint-disable-next-line no-new-wrappers
775
- console.assert(is(String, new String('42')))
776
- console.assert(is(Symbol, Symbol('42')))
777
- console.assert(is(Symbol, Object(Symbol('42'))))
778
- console.assert(is(undefined, undefined))
779
- console.assert(is(undefined, null))
780
- console.assert(is(Object, {}))
781
- console.assert(is(Array, []))
782
- console.assert(is(RegExp, /42/))
783
- console.assert(is(Date, new Date(42)))
784
- console.assert(is(Set, new Set(['42', 42])))
785
- console.assert(is(Map, new Map([[{ j: 42 }, { J: '42' }], [{ c: 42 }, { C: '42' }]])))
786
- }
787
-
788
- _test['is vs ‘toString.call’'] = () => {
789
- class FooBar { }
790
-
791
- console.assert(is(FooBar, new FooBar()))
792
-
793
- const fakeFooBar = { [Symbol.toStringTag]: 'FooBar' }
794
-
795
- console.assert(({}).toString.call(new FooBar()) === '[object Object]')
796
- console.assert(({}).toString.call(fakeFooBar) === '[object FooBar]')
797
- }
798
-
799
- const _jcss = (
800
- /** @type {JcssNode} */ node,
801
- /** @type {string} */ prefix,
802
- /** @type {string[]} */ result,
803
- /** @type {(text: string) => string} */ split
804
- ) => {
805
- const /** @type {[JcssNode | string[], string][]} */ queue = [[node, prefix]]
806
-
328
+ // src/jcss.js
329
+ var _jcss = (node, prefix, result, split) => {
330
+ const queue = [[node, prefix]];
807
331
  while (queue.length) {
808
- const [style2, prefix2] = queue.shift() ?? []
809
-
332
+ const [style2, prefix2] = queue.shift() ?? [];
810
333
  if (style2 == null || prefix2 == null) {
811
- continue
334
+ continue;
812
335
  }
813
-
814
336
  if (is(Array, style2)) {
815
- result.push(prefix2, prefix2 !== '' ? '{' : '', style2.join(';'), prefix2 !== '' ? '}' : '')
337
+ result.push(prefix2, prefix2 !== "" ? "{" : "", style2.join(";"), prefix2 !== "" ? "}" : "");
816
338
  } else {
817
- const /** @type {[JcssNode | string[], string][]} */ todo = []
818
- let /** @type {string[]} */ attributes = []
819
- let attributesPushed = false
820
-
339
+ const todo = [];
340
+ let attributes = [];
341
+ let attributesPushed = false;
821
342
  for (const key in style2) {
822
- const value = style2[key]
823
-
343
+ const value = style2[key];
824
344
  if (is(String, value) || is(Number, value)) {
825
345
  if (!attributesPushed) {
826
- attributesPushed = true
827
- attributes = []
828
- todo.push([attributes, prefix2])
346
+ attributesPushed = true;
347
+ attributes = [];
348
+ todo.push([attributes, prefix2]);
829
349
  }
830
-
831
- attributes.push(`${split(key).replace(/([A-Z])/g, (_, letter) => '-' + letter.toLowerCase())}:${value}`)
350
+ attributes.push(`${split(key).replace(/([A-Z])/g, (_, letter) => "-" + letter.toLowerCase())}:${value}`);
832
351
  } else {
833
- attributesPushed = false
834
-
835
- const /** @type {string[]} */ newPrefix = []
836
- const keySplitted = key.split(',')
837
-
838
- for (const prefixItem of prefix2.split(',')) {
352
+ attributesPushed = false;
353
+ const newPrefix = [];
354
+ const keySplitted = key.split(",");
355
+ for (const prefixItem of prefix2.split(",")) {
839
356
  for (const keyItem of keySplitted) {
840
- newPrefix.push(prefixItem + keyItem)
357
+ newPrefix.push(prefixItem + keyItem);
841
358
  }
842
359
  }
843
-
844
- todo.push([value, newPrefix.join(',')])
360
+ todo.push([value, newPrefix.join(",")]);
845
361
  }
846
362
  }
847
-
848
- queue.unshift(...todo)
363
+ queue.unshift(...todo);
849
364
  }
850
365
  }
851
- }
852
-
853
- /**
854
- * ```ts
855
- * export function jcss(root: JcssRoot, splitter?: string): string;
856
- * ```
857
- */
858
-
859
- /**
860
- * A simple CSS-in-JS helper.
861
- *
862
- * The `root` parameter provides a hierarchical description of CSS rules.
863
- *
864
- * - 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.
865
- * - 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`).
866
- * - In keys specifying CSS attribute, all uppercase letters are replaced by lowercase letters with an additional `-` character preceding them (e.g. `fontFamily` → `font-family`).
867
- * - 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}`).
868
- * - Top-level keys that begin with `@` are not concatenated with sub-object keys.
869
- */
870
- export const jcss = (/** @type {JcssRoot} */ root, splitter = '$$') => {
871
- const split = (/** @type {string} */ text) => text.split(splitter)[0]
872
- const /** @type {string[]} */ result = []
873
-
366
+ };
367
+ var jcss = (root, splitter = "$$") => {
368
+ const split = (text) => text.split(splitter)[0];
369
+ const result = [];
874
370
  for (const key in root) {
875
- const value = root[key]
876
-
877
- if (key[0] === '@') {
878
- result.push(split(key) + '{')
879
- _jcss(value, '', result, split)
880
- result.push('}')
371
+ const value = root[key];
372
+ if (key[0] === "@") {
373
+ result.push(split(key) + "{");
374
+ _jcss(value, "", result, split);
375
+ result.push("}");
881
376
  } else {
882
- _jcss(value, split(key), result, split)
377
+ _jcss(value, split(key), result, split);
883
378
  }
884
379
  }
380
+ return result.join("");
381
+ };
885
382
 
886
- return result.join('')
887
- }
888
-
889
- _test['jcss: #1'] = () => {
890
- const actual = jcss({
891
- a: {
892
- color: 'red',
893
- margin: 1,
894
- '.c': { margin: 2, padding: 2 },
895
- padding: 1
896
- }
897
- })
898
-
899
- const expected = `
900
- a{
901
- color:red;
902
- margin:1
903
- }
904
- a.c{
905
- margin:2;
906
- padding:2
907
- }
908
- a{
909
- padding:1
910
- }`.replace(/\n\s*/g, '')
911
-
912
- console.assert(actual === expected)
913
- }
914
-
915
- _test['jcss: #2'] = () => {
916
- const actual = jcss({
917
- a: {
918
- '.b': {
919
- color: 'red',
920
- margin: 1,
921
- '.c': { margin: 2, padding: 2 },
922
- padding: 1
923
- }
924
- }
925
- })
926
-
927
- const expected = `
928
- a.b{
929
- color:red;
930
- margin:1
931
- }
932
- a.b.c{
933
- margin:2;
934
- padding:2
935
- }
936
- a.b{
937
- padding:1
938
- }`.replace(/\n\s*/g, '')
939
-
940
- console.assert(actual === expected)
941
- }
942
-
943
- _test['jcss: #3'] = () => {
944
- const actual = jcss({
945
- '@font-face$$1': {
946
- fontFamily: 'Jackens',
947
- src$$1: 'url(otf/jackens.otf)',
948
- src$$2: "url(otf/jackens.otf) format('opentype')," +
949
- "url(svg/jackens.svg) format('svg')",
950
- fontWeight: 'normal',
951
- fontStyle: 'normal'
952
- },
953
- '@font-face$$2': {
954
- fontFamily: 'C64',
955
- src: 'url(fonts/C64_Pro_Mono-STYLE.woff)'
956
- },
957
- '@keyframes spin': {
958
- '0%': { transform: 'rotate(0deg)' },
959
- '100%': { transform: 'rotate(360deg)' }
960
- },
961
- div: {
962
- border: 'solid red 1px',
963
- '.c1': { 'background-color': '#000' },
964
- ' .c1': { backgroundColor: 'black' },
965
- '.c2': { backgroundColor: 'rgb(0,0,0)' }
966
- },
967
- '@media(min-width:200px)': {
968
- div: { margin: 0, padding: 0 },
969
- span: { color: '#000' }
970
- }
971
- })
972
-
973
- const expected = `
974
- @font-face{
975
- font-family:Jackens;
976
- src:url(otf/jackens.otf);
977
- src:url(otf/jackens.otf) format('opentype'),url(svg/jackens.svg) format('svg');
978
- font-weight:normal;
979
- font-style:normal
980
- }
981
- @font-face{
982
- font-family:C64;
983
- src:url(fonts/C64_Pro_Mono-STYLE.woff)
984
- }
985
- @keyframes spin{
986
- 0%{
987
- transform:rotate(0deg)
988
- }
989
- 100%{
990
- transform:rotate(360deg)
991
- }
992
- }
993
- div{
994
- border:solid red 1px
995
- }
996
- div.c1{
997
- background-color:#000
998
- }
999
- div .c1{
1000
- background-color:black
1001
- }
1002
- div.c2{
1003
- background-color:rgb(0,0,0)
1004
- }
1005
- @media(min-width:200px){
1006
- div{
1007
- margin:0;
1008
- padding:0
1009
- }
1010
- span{
1011
- color:#000
1012
- }
1013
- }`.replace(/\n\s*/g, '')
1014
-
1015
- console.assert(actual === expected)
1016
- }
1017
-
1018
- _test['jcss: #4'] = () => {
1019
- const actual = jcss({
1020
- a: {
1021
- '.b,.c': {
1022
- margin: 1,
1023
- '.d': {
1024
- margin: 2
1025
- }
1026
- }
1027
- }
1028
- })
1029
-
1030
- const expected = `
1031
- a.b,a.c{
1032
- margin:1
1033
- }
1034
- a.b.d,a.c.d{
1035
- margin:2
1036
- }`.replace(/\n\s*/g, '')
1037
-
1038
- console.assert(actual === expected)
1039
- }
1040
-
1041
- _test['jcss: #5'] = () => {
1042
- const actual = jcss({
1043
- '.b,.c': {
1044
- margin: 1,
1045
- '.d': {
1046
- margin: 2
1047
- }
1048
- }
1049
- })
1050
-
1051
- const expected = `
1052
- .b,.c{
1053
- margin:1
1054
- }
1055
- .b.d,.c.d{
1056
- margin:2
1057
- }`.replace(/\n\s*/g, '')
1058
-
1059
- console.assert(actual === expected)
1060
- }
1061
-
1062
- _test['jcss: #6'] = () => {
1063
- const actual = jcss({
1064
- '.a,.b': {
1065
- margin: 1,
1066
- '.c,.d': {
1067
- margin: 2
1068
- }
1069
- }
1070
- })
1071
-
1072
- const expected = `
1073
- .a,.b{
1074
- margin:1
1075
- }
1076
- .a.c,.a.d,.b.c,.b.d{
1077
- margin:2
1078
- }`.replace(/\n\s*/g, '')
1079
-
1080
- console.assert(actual === expected)
1081
- }
1082
-
1083
- /**
1084
- * ```ts
1085
- * export function jsOnParse(handlers: Record<string, Function>, text: string): any;
1086
- * ```
1087
- */
1088
-
1089
- /**
1090
- * `JSON.parse` with “JavaScript turned on”.
1091
- *
1092
- * Objects having *exactly* one property which is present in the `handlers` map, i.e. objects of the form:
1093
- *
1094
- * ```js
1095
- * { "«handlerName»": [«params»] }
1096
- * ```
1097
- *
1098
- * are replaced by the result of call
1099
- *
1100
- * ```js
1101
- * handlers['«handlerName»'](...«params»)
1102
- * ```
1103
- */
1104
- export const jsOnParse = (
1105
- /** @type {Record<string, Function>} */ handlers,
1106
- /** @type {string} */ text
1107
- ) => JSON.parse(text, (key, value) => {
383
+ // src/jsOnParse.js
384
+ var jsOnParse = (handlers, text) => JSON.parse(text, (key, value) => {
1108
385
  if (is(Object, value)) {
1109
- let isSecondKey = false
1110
-
386
+ let isSecondKey = false;
1111
387
  for (key in value) {
1112
388
  if (isSecondKey) {
1113
- return value
389
+ return value;
1114
390
  }
1115
- isSecondKey = true
391
+ isSecondKey = true;
1116
392
  }
1117
-
1118
393
  if (has(key, handlers) && is(Array, value[key])) {
1119
- return handlers[key](...value[key])
394
+ return handlers[key](...value[key]);
1120
395
  }
1121
396
  }
397
+ return value;
398
+ });
1122
399
 
1123
- return value
1124
- })
1125
-
1126
- _test.jsOnParse = () => {
1127
- const handlers = {
1128
- $hello: (/** @type {string} */ name) => `Hello ${name}!`,
1129
- $foo: () => 'bar'
1130
- }
1131
- const actual = jsOnParse(handlers, `
1132
- [
1133
- {
1134
- "$hello": ["World"]
1135
- },
1136
- {
1137
- "nested": {
1138
- "$hello": ["nested World"]
1139
- },
1140
- "one": 1,
1141
- "two": 2
1142
- },
1143
- {
1144
- "$foo": []
1145
- },
1146
- {
1147
- "$foo": ["The parent object does not have exactly one property!"],
1148
- "one": 1,
1149
- "two": 2
1150
- }
1151
- ]`)
1152
- const expected = [
1153
- 'Hello World!',
1154
- {
1155
- nested: 'Hello nested World!',
1156
- one: 1,
1157
- two: 2
1158
- },
1159
- 'bar',
1160
- {
1161
- $foo: ['The parent object does not have exactly one property!'],
1162
- one: 1,
1163
- two: 2
1164
- }]
1165
-
1166
- console.assert(eq(actual, expected))
1167
- }
1168
-
1169
- const _locale = (
1170
- /** @type {Record<string, Record<string, string | Record<string, string>>>} */ locales,
1171
- /** @type {string} */ language,
1172
- /** @type {string} */ text,
1173
- /** @type {string} */ version
1174
- ) => {
1175
- // @ts-expect-error
1176
- const v = locales?.[language]?.[version]?.[text]
1177
-
400
+ // src/locale.js
401
+ var _locale = (locales, language, text, version) => {
402
+ const v = locales?.[language]?.[version]?.[text];
1178
403
  if (is(String, v)) {
1179
- return v
404
+ return v;
1180
405
  }
1181
-
1182
- const t = locales?.[language]?.[text]
1183
-
1184
- return is(String, t) ? t : text
1185
- }
1186
-
1187
- /**
1188
- * ```ts
1189
- * export function locale(
1190
- * locales: Record<string, Record<string, string | Record<string, string>>>,
1191
- * defaultLanguage: string,
1192
- * languages?: readonly string[]
1193
- * ): (text?: string, version?: string) => string;
1194
- * ```
1195
- */
1196
-
1197
- /**
1198
- * Language translations helper.
1199
- */
1200
- export const locale = (
1201
- /** @type {Record<string, Record<string, string | Record<string, string>>>} */ locales,
1202
- /** @type {string} */ defaultLanguage,
1203
- languages = navigator.languages
1204
- ) => {
406
+ const t = locales?.[language]?.[text];
407
+ return is(String, t) ? t : text;
408
+ };
409
+ var locale = (locales, defaultLanguage, languages = navigator.languages) => {
1205
410
  for (const language of languages) {
1206
411
  if (has(language, locales)) {
1207
- // @ts-expect-error
1208
- return _locale.bind(0, locales, language)
412
+ return _locale.bind(0, locales, language);
1209
413
  }
1210
414
  }
415
+ return _locale.bind(0, locales, defaultLanguage);
416
+ };
1211
417
 
1212
- // @ts-expect-error
1213
- return _locale.bind(0, locales, defaultLanguage)
1214
- }
1215
-
1216
- _test.locale = () => {
1217
- const locales = {
1218
- pl: {
1219
- Password: 'Hasło',
1220
- button: { Login: 'Zaloguj' }
1221
- }
1222
- }
1223
- const _ = locale(locales, 'pl', [])
1224
-
1225
- console.assert(_('Login') === 'Login')
1226
- console.assert(_('Password') === 'Hasło')
1227
-
1228
- console.assert(_('Undefined text') === 'Undefined text')
1229
-
1230
- console.assert(_('Login', 'button') === 'Zaloguj')
1231
-
1232
- console.assert(_('Password', 'undefined_version') === 'Hasło')
1233
- console.assert(_('Undefined text', 'undefined_version') === 'Undefined text')
1234
-
1235
- console.assert(_('toString') === 'toString')
1236
- console.assert(_('toString', 'undefined_version') === 'toString')
1237
- }
1238
-
1239
- /**
1240
- * ```ts
1241
- * export function nanolight(
1242
- * pattern: RegExp,
1243
- * highlighters: ((chunk: string, index: number) => HArgs[1])[],
1244
- * code: string
1245
- * ): HArgs[1][];
1246
- * ```
1247
- */
1248
-
1249
- /**
1250
- * A generic helper for syntax highlighting (see also `nanolightJs`).
1251
- */
1252
- export const nanolight = (
1253
- /** @type {RegExp} */ pattern,
1254
- /** @type {((chunk: string, index: number) => HArgs[1])[]} */ highlighters,
1255
- /** @type {string} */ code
1256
- ) => {
1257
- const /** @type {HArgs[1][]} */ result = []
1258
-
418
+ // src/nanolight.js
419
+ var nanolight = (pattern, highlighters, code) => {
420
+ const result = [];
1259
421
  code.split(pattern).forEach((chunk, index) => {
1260
- index %= highlighters.length
422
+ index %= highlighters.length;
1261
423
  if (chunk != null) {
1262
- result.push(highlighters[index](chunk, index))
424
+ result.push(highlighters[index](chunk, index));
1263
425
  }
1264
- })
426
+ });
427
+ return result;
428
+ };
1265
429
 
1266
- return result
1267
- }
1268
-
1269
- /**
1270
- * ```ts
1271
- * export function nanolightJs(codeJs: string): HArgs[1][];
1272
- * ```
1273
- */
1274
-
1275
- /**
1276
- * A helper for highlighting JavaScript.
1277
- */
1278
- // @ts-expect-error
1279
- export const nanolightJs = nanolight.bind(0,
430
+ // src/nanolightJs.js
431
+ var nanolightJs = nanolight.bind(
432
+ 0,
1280
433
  /('.*?'|".*?"|`[\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ąćęłńóśżźĄĆĘŁŃÓŚŻŹ]+)/,
1281
434
  [
1282
- chunk => chunk, // no match
1283
- chunk => ['u', chunk], // string literals
1284
- chunk => ['em', chunk], // comments
1285
- chunk => ['b', chunk], // keywords
1286
- chunk => ['b', chunk], // operators
1287
- chunk => ['u', chunk], // number literals
1288
- chunk => ['u', chunk], // function calls
1289
- chunk => ['i', chunk] // literals
435
+ (chunk) => chunk,
436
+ // no match
437
+ (chunk) => ["u", chunk],
438
+ // string literals
439
+ (chunk) => ["em", chunk],
440
+ // comments
441
+ (chunk) => ["b", chunk],
442
+ // keywords
443
+ (chunk) => ["b", chunk],
444
+ // operators
445
+ (chunk) => ["u", chunk],
446
+ // number literals
447
+ (chunk) => ["ins", chunk],
448
+ // function calls
449
+ (chunk) => ["i", chunk]
450
+ // literals
1290
451
  ]
1291
- )
1292
-
1293
- _test.nanolightJs = () => {
1294
- const codeJs = 'const answerToLifeTheUniverseAndEverything = 42'
1295
-
1296
- console.assert(h('pre', ['code', ...nanolightJs(codeJs)]).outerHTML ===
1297
- '<pre><code><b>const</b> <i>answerToLifeTheUniverseAndEverything</i> <b>=</b> <u>42</u></code></pre>')
1298
- }
1299
-
1300
- /**
1301
- * ```ts
1302
- * export function plUral(singular: string, plural2: string, plural5: string, value: number): string;
1303
- * ```
1304
- */
1305
-
1306
- /**
1307
- * A helper for choosing the correct singular and plural.
1308
- */
1309
- export const plUral = (
1310
- /** @type {string} */ singular,
1311
- /** @type {string} */ plural2,
1312
- /** @type {string} */ plural5,
1313
- /** @type {number} */ value
1314
- ) => {
1315
- const absValue = Math.abs(value)
1316
- const absValueMod10 = absValue % 10
1317
-
1318
- return value === 1
1319
- ? singular
1320
- : absValue === 12 || absValue === 13 || absValue === 14
1321
- ? plural5
1322
- : absValueMod10 === 2 || absValueMod10 === 3 || absValueMod10 === 4
1323
- ? plural2
1324
- : plural5
1325
- }
1326
-
1327
- _test.plUral = () => {
1328
- // @ts-expect-error
1329
- const auto = plUral.bind(null, 'auto', 'auta', 'aut')
1330
-
1331
- console.assert(auto(0) === 'aut')
1332
- console.assert(auto(1) === 'auto')
1333
- console.assert(auto(17) === 'aut')
1334
- console.assert(auto(42) === 'auta')
1335
-
1336
- // @ts-expect-error
1337
- const car = plUral.bind(null, 'car', 'cars', 'cars')
1338
-
1339
- console.assert(car(0) === 'cars')
1340
- console.assert(car(1) === 'car')
1341
- console.assert(car(17) === 'cars')
1342
- console.assert(car(42) === 'cars')
1343
- }
1344
-
1345
- /**
1346
- * ```ts
1347
- * export function pro(ref: any): any;
1348
- * ```
1349
- */
1350
-
1351
- /**
1352
- * A helper that protect calls to nested properties by `Proxy` which initializes non-existent values with an empty object.
1353
- */
1354
- // @ts-expect-error
1355
- export const pro = (/** @type {any} */ ref) => new Proxy(ref, {
1356
- get (target, key) {
1357
- return pro(target[key] = target[key] ?? {})
452
+ );
453
+
454
+ // src/plUral.js
455
+ var plUral = (singular, plural2, plural5, value) => {
456
+ const absValue = Math.abs(value);
457
+ const absValueMod10 = absValue % 10;
458
+ return value === 1 ? singular : absValue === 12 || absValue === 13 || absValue === 14 ? plural5 : absValueMod10 === 2 || absValueMod10 === 3 || absValueMod10 === 4 ? plural2 : plural5;
459
+ };
460
+
461
+ // src/pro.js
462
+ var pro = (ref) => new Proxy(ref, {
463
+ get(target, key) {
464
+ return pro(target[key] = target[key] ?? {});
1358
465
  }
1359
- })
1360
-
1361
- _test.pro = () => {
1362
- const ref = {}
1363
-
1364
- pro(ref).one.two[3][4] = 1234
1365
-
1366
- console.assert(eq(ref, { one: { two: { 3: { 4: 1234 } } } }))
1367
-
1368
- pro(ref).one.two.tree = 123
1369
-
1370
- console.assert(eq(ref, { one: { two: { 3: { 4: 1234 }, tree: 123 } } }))
1371
-
1372
- pro(ref).one.two = undefined
1373
-
1374
- console.assert(eq(ref, { one: { two: undefined } }))
1375
-
1376
- delete pro(ref).one.two
1377
-
1378
- console.assert(eq(ref, { one: {} }))
1379
-
1380
- pro(ref).one.two.three.four
1381
-
1382
- console.assert(eq(ref, { one: { two: { three: { four: {} } } } }))
1383
-
1384
- pro(ref).one.two.three.four = 1234
1385
-
1386
- console.assert(eq(ref, { one: { two: { three: { four: 1234 } } } }))
1387
- }
1388
-
1389
- /**
1390
- * ```ts
1391
- * export function refsInfo(...refs: any[]): [string, string, string[]][];
1392
- * ```
1393
- */
1394
-
1395
- /**
1396
- * A helper that provides information about the given `refs`.
1397
- *
1398
- * It returns an array of triples: `[«name», «prototype-name», «array-of-own-property-names»]`.
1399
- */
1400
- export const refsInfo = (/** @type {any[]} */ ...refs) => {
1401
- const /** @type {Set<Function>} */ fns = new Set()
1402
-
1403
- refs.forEach(ref => {
1404
- while (is(Function, ref) && !fns.has(ref) && ref.toString?.()?.includes?.('[native code]')) {
1405
- fns.add(ref)
1406
- ref = Object.getPrototypeOf(ref)
1407
- }
1408
- })
1409
-
1410
- return Array.from(fns.values()).map(/** @returns {[string, string, string[]]} */ fn => [
1411
- fn.name,
1412
- Object.getPrototypeOf(fn)?.name ?? '',
1413
- Object.getOwnPropertyNames(fn.prototype ?? Object.create(null)).sort()
1414
- ]).sort((a, b) => -(a[0] < b[0]))
1415
- }
1416
-
1417
- _test.refsInfo = () => {
1418
- const info = refsInfo(Array, Function)
1419
-
1420
- console.assert(info.find(([name]) => name === 'Array')?.[2]?.includes?.('length'))
1421
- console.assert(info.find(([name]) => name === 'Function')?.[2]?.includes?.('length'))
1422
- }
1423
-
1424
- _test['refsInfo: browserFingerprint'] = () => {
1425
- const browserFingerprint = () => {
1426
- // @ts-expect-error
1427
- const refs = Object.getOwnPropertyNames(window).map(name => window[name])
1428
- const info = refsInfo(...refs)
1429
- const json = JSON.stringify(info)
1430
- const hash = Array(32).fill(0)
1431
- let j = 0
1432
-
1433
- for (let i = 0; i < json.length; i++) {
1434
- let charCode = json.charCodeAt(i)
1435
-
1436
- while (charCode > 0) {
1437
- hash[j] = hash[j] ^ (charCode & 15)
1438
- charCode >>= 4
1439
- j = (j + 1) & 31
1440
- }
1441
- }
1442
-
1443
- return hash.map(x => x.toString(16)).join('')
1444
- }
1445
-
1446
- console.log(browserFingerprint())
1447
- }
1448
-
1449
- /**
1450
- * ```ts
1451
- * export function s<T extends keyof SVGElementTagNameMap>(tag: T, ...args: HArgs[1][]): SVGElementTagNameMap[T];
1452
- * export function s<N extends Node>(node: N, ...args: HArgs[1][]): N;
1453
- * export function s(...args: HArgs): Node;
1454
- * ```
1455
- */
1456
-
1457
- /**
1458
- * A lightweight [HyperScript](https://github.com/hyperhype/hyperscript)-style helper for creating and modifying `SVGElement`s (see also `h`).
1459
- *
1460
- * - The first argument of type `string` specifies the tag of the element to be created.
1461
- * - The first argument of type `Node` specifies the element to be modified.
1462
- * - All other arguments of type `Record<string, any>` are mappings of attributes and properties.
1463
- * Keys starting with `$` specify *properties* (without the leading `$`) to be set on the element being created or modified.
1464
- * (Note that `$` is not a valid attribute name character.)
1465
- * All other keys specify *attributes* to be set by `setAttributeNS`.
1466
- * An attribute equal to `false` causes the attribute to be removed by `removeAttributeNS`.
1467
- * - All other arguments of type `null` or `undefined` are simply ignored.
1468
- * - All other arguments of type `Node` are appended to the element being created or modified.
1469
- * - All other arguments of type `string`/`number` are converted to `Text` nodes and appended to the element being created or modified.
1470
- * - All other arguments of type `HArgs` are passed to `s` and the results are appended to the element being created or modified.
1471
- */
1472
- export const s = _h('http://www.w3.org/2000/svg')
1473
-
1474
- const _ZEROS = '0'.repeat(16)
1475
- let _counter = 0
1476
-
1477
- /**
1478
- * ```ts
1479
- * export function uuid1(options?: {
1480
- * date?: Date;
1481
- * node?: string;
1482
- * }): string;
1483
- * ```
1484
- */
1485
-
1486
- /**
1487
- * A helper that generates a UUID v1 identifier (with a creation timestamp).
1488
- *
1489
- * - The optional `node` parameter should have the format `/^[0123456789abcdef]+$/`.
1490
- * Its value will be trimmed to last 12 characters and left padded with zeros.
1491
- */
1492
- export const uuid1 = ({
1493
- date = new Date(),
466
+ });
467
+
468
+ // src/refsInfo.js
469
+ var refsInfo = (...refs) => {
470
+ const fns = /* @__PURE__ */ new Set();
471
+ refs.forEach((ref) => {
472
+ while (is(Function, ref) && !fns.has(ref) && ref.toString?.()?.includes?.("[native code]")) {
473
+ fns.add(ref);
474
+ ref = Object.getPrototypeOf(ref);
475
+ }
476
+ });
477
+ return Array.from(fns.values()).map(
478
+ /** @return {[string, string, string[]]} */
479
+ (fn) => [
480
+ fn.name,
481
+ Object.getPrototypeOf(fn)?.name ?? "",
482
+ Object.getOwnPropertyNames(fn.prototype ?? /* @__PURE__ */ Object.create(null)).sort()
483
+ ]
484
+ ).sort((a, b) => -(a[0] < b[0]));
485
+ };
486
+
487
+ // src/uuid1.js
488
+ var ZEROS = "0".repeat(16);
489
+ var counter = 0;
490
+ var uuid1 = ({
491
+ date = /* @__PURE__ */ new Date(),
1494
492
  node = Math.random().toString(16).slice(2)
1495
493
  } = {}) => {
1496
- const time = _ZEROS + (10_000 * (+date + 12_219_292_800_000)).toString(16)
1497
-
1498
- _counter = (_counter + 1) & 0x3fff
1499
-
494
+ const time = ZEROS + (1e4 * (+date + 122192928e5)).toString(16);
495
+ counter = counter + 1 & 16383;
1500
496
  return time.slice(-8).concat(
1501
- '-',
497
+ "-",
1502
498
  time.slice(-12, -8),
1503
499
  // @ts-expect-error
1504
500
  -1,
1505
501
  time.slice(-15, -12),
1506
- '-',
1507
- (8 | (_counter >> 12)).toString(16),
1508
- (_ZEROS + (_counter & 0xfff).toString(16)).slice(-3),
1509
- '-',
1510
- (_ZEROS + node).slice(-12))
1511
- }
1512
-
1513
- _test.uuid1 = () => {
1514
- for (let counter = 1; counter <= 0x5678; ++counter) {
1515
- const uuid = uuid1()
1516
-
1517
- counter === 0x0001 && console.assert(uuid.split('-')[3] === '8001')
1518
- counter === 0x0fff && console.assert(uuid.split('-')[3] === '8fff')
1519
- counter === 0x1000 && console.assert(uuid.split('-')[3] === '9000')
1520
- counter === 0x2345 && console.assert(uuid.split('-')[3] === 'a345')
1521
- counter === 0x3456 && console.assert(uuid.split('-')[3] === 'b456')
1522
- counter === 0x4000 && console.assert(uuid.split('-')[3] === '8000')
1523
- counter === 0x4567 && console.assert(uuid.split('-')[3] === '8567')
1524
- }
1525
- }
1526
-
1527
- _test['uuid1: node'] = () => {
1528
- console.assert(uuid1({ node: '000123456789abc' }).split('-')[4] === '123456789abc')
1529
- console.assert(uuid1({ node: '123456789' }).split('-')[4] === '000123456789')
1530
- }
1531
-
1532
- _test['uuid1: date'] = () => {
1533
- console.assert(uuid1({ date: new Date(323325e6) }).startsWith('c1399400-9a71-11bd'))
1534
- }
502
+ "-",
503
+ (8 | counter >> 12).toString(16),
504
+ (ZEROS + (counter & 4095).toString(16)).slice(-3),
505
+ "-",
506
+ (ZEROS + node).slice(-12)
507
+ );
508
+ };
509
+ export {
510
+ chartable,
511
+ eq,
512
+ escape,
513
+ escapeValues,
514
+ fixTypography,
515
+ h,
516
+ has,
517
+ is,
518
+ jcss,
519
+ jsOnParse,
520
+ locale,
521
+ nanolight,
522
+ nanolightJs,
523
+ plUral,
524
+ pro,
525
+ refsInfo,
526
+ s,
527
+ uuid1
528
+ };