@jackens/nnn 2024.2.12 → 2024.2.15

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/chartable.d.ts CHANGED
@@ -7,17 +7,15 @@
7
7
  * - `gapY`: Y axis spacing
8
8
  * - `headerColumn`: flag indicating that `table` has a header column (with X axis labels)
9
9
  * - `id`: chart id
10
- * - `left`: left padding (for data series labels)
10
+ * - `left`: left padding
11
11
  * - `maxY`: number of Y axis lines
12
12
  * - `reverse`: flag to reverse all data series
13
13
  * - `right`: right padding (for data series labels)
14
14
  * - `rotate`: flag to rotate X axis labels
15
- * - `singleScale`: flag to force single scale
16
15
  * - `table`: `HTMLTableElement` to extract data, data series labels and X axis labels
17
- * - `title`: chart title
18
- * - `top`: top padding (for the title)
16
+ * - `top`: top padding
19
17
  */
20
- export function chartable({ bottom, gapX, gapY, headerColumn, id, left, maxY, reverse, right, rotate, singleScale, table, title, top }: {
18
+ export function chartable({ bottom, gapX, gapY, headerColumn, id, left, maxY, reverse, right, rotate, table, top }: {
21
19
  bottom?: number;
22
20
  gapX?: number;
23
21
  gapY?: number;
@@ -28,9 +26,7 @@ export function chartable({ bottom, gapX, gapY, headerColumn, id, left, maxY, re
28
26
  reverse?: boolean;
29
27
  right?: number;
30
28
  rotate?: boolean;
31
- singleScale?: boolean;
32
29
  table: HTMLTableElement;
33
- title?: string;
34
30
  top?: number;
35
31
  }): SVGSVGElement;
36
32
 
package/chartable.js CHANGED
@@ -11,15 +11,13 @@ const COLORS = ['#e22', '#e73', '#fc3', '#ad4', '#4d9', '#3be', '#45d', '#c3e']
11
11
  * - `gapY`: Y axis spacing
12
12
  * - `headerColumn`: flag indicating that `table` has a header column (with X axis labels)
13
13
  * - `id`: chart id
14
- * - `left`: left padding (for data series labels)
14
+ * - `left`: left padding
15
15
  * - `maxY`: number of Y axis lines
16
16
  * - `reverse`: flag to reverse all data series
17
17
  * - `right`: right padding (for data series labels)
18
18
  * - `rotate`: flag to rotate X axis labels
19
- * - `singleScale`: flag to force single scale
20
19
  * - `table`: `HTMLTableElement` to extract data, data series labels and X axis labels
21
- * - `title`: chart title
22
- * - `top`: top padding (for the title)
20
+ * - `top`: top padding
23
21
  *
24
22
  * @param {{
25
23
  * bottom?: number;
@@ -32,9 +30,7 @@ const COLORS = ['#e22', '#e73', '#fc3', '#ad4', '#4d9', '#3be', '#45d', '#c3e']
32
30
  * reverse?: boolean;
33
31
  * right?: number;
34
32
  * rotate?: boolean;
35
- * singleScale?: boolean;
36
33
  * table: HTMLTableElement;
37
- * title?: string;
38
34
  * top?: number;
39
35
  * }} options
40
36
  */
@@ -44,22 +40,20 @@ export const chartable = ({
44
40
  gapY = 30,
45
41
  headerColumn = false,
46
42
  id,
47
- left = 200,
43
+ left = 15,
48
44
  maxY = 10,
49
45
  reverse = false,
50
46
  right = 200,
51
47
  rotate = false,
52
- singleScale = false,
53
48
  table,
54
- title,
55
- top = 70
49
+ top = 15
56
50
  }) => {
57
51
  const /** @type {number[][]} */ zxY = []
58
52
  const /** @type {string[]} */ xLabels = []
59
53
  const /** @type {string[]} */ zLabels = []
60
54
 
61
55
  table.querySelectorAll('tr').forEach((row, r) =>
62
- // @ts-ignore
56
+ // @ts-expect-error
63
57
  row.querySelectorAll('td,th').forEach((/** @type {HTMLTableCellElement} */ col, c) => {
64
58
  const x = r - 1
65
59
  const z = c - +headerColumn
@@ -80,51 +74,6 @@ export const chartable = ({
80
74
  zxY.forEach(xY => xY.reverse())
81
75
  }
82
76
 
83
- let bestScales = [Infinity, -Infinity, Infinity, -Infinity, Infinity]
84
-
85
- const ranges = zxY.map(xY => {
86
- xY = xY.filter(y => !isNaN(y))
87
- return [Math.min(...xY), Math.max(...xY)]
88
- })
89
-
90
- if (singleScale) {
91
- bestScales = ranges.reduce(
92
- ([totalMin, totalMax], [min, max]) => [Math.min(totalMin, min), Math.max(totalMax, max)],
93
- bestScales
94
- )
95
- } else {
96
- ranges.forEach(([min1, max0]) => ranges.forEach(([min0, max1]) => {
97
- if (min0 >= min1 && max1 >= max0) {
98
- let min2 = Infinity
99
- let max2 = -Infinity
100
-
101
- ranges.forEach(([min, max]) => {
102
- if (min < min1 || max1 < max) {
103
- if (min2 > min) {
104
- min2 = min
105
- }
106
- if (max2 < max) {
107
- max2 = max
108
- }
109
- }
110
- })
111
-
112
- let cost = 0
113
-
114
- ranges.forEach(([min, max]) => {
115
- if (min < max) {
116
- cost += 1 - (max - min) / (min1 <= min && max <= max1 ? max1 - min1 : max2 - min2)
117
- }
118
- })
119
-
120
- if (bestScales[4] > cost) {
121
- bestScales = [min1, max1, min2, max2, cost]
122
- }
123
- }
124
- }))
125
- }
126
-
127
- const [min1, max1, min2, max2] = bestScales
128
77
  const maxX = zxY[0].length
129
78
  const xi = Array.from({ length: maxX }, (_, x) => x * gapX)
130
79
  const yi = Array.from({ length: maxY }, (_, y) => y * gapY)
@@ -135,42 +84,27 @@ export const chartable = ({
135
84
  const /** @type {import('./h.js').HArgs1} */ graph = ['g', { transform: `translate(${left} ${top})` },
136
85
  ...yi.map(y => ['line', { x1: 0, x2: w, y1: y, y2: y, stroke: '#8888' }]),
137
86
  ...xi.map(x => ['line', { x1: x, x2: x, y1: 0, y2: h, stroke: '#8888' }])]
138
- const /** @type {import('./h.js').HArgs1} */ lColors = ['g', { class: 'chartable-z-colors', transform: 'translate(-80 0)' }]
139
- const /** @type {import('./h.js').HArgs1} */ lLabels = ['g', { class: 'chartable-z-labels', transform: 'translate(-95 0)' }]
140
- const /** @type {import('./h.js').HArgs1} */ rColors = ['g', { class: 'chartable-z-colors', transform: 'translate(80 0)' }]
141
- const /** @type {import('./h.js').HArgs1} */ rLabels = ['g', { class: 'chartable-z-labels', transform: 'translate(95 0)' }]
142
- const yLabel = (/** @type {number} */ min, /** @type {number} */ max, /** @type {number} */ y) =>
143
- (min + (max - min) * (maxY - 1 - y) / (maxY - 1)).toFixed(2).replace(/\.?0+$/, '')
87
+ const /** @type {import('./h.js').HArgs1} */ colors = ['g', { transform: `translate(${left + w + 25} ${top + 15})` }]
88
+ const /** @type {import('./h.js').HArgs1} */ labels = ['g', { transform: `translate(${left + w + 40} ${top + 15})` }]
144
89
 
145
- zxY.forEach((xa, z) => {
146
- const cls = `chartable-z-${z + 1}`
90
+ zxY.forEach((xY, z) => {
147
91
  const fill = COLORS[z % COLORS.length]
148
- let [min, max] = ranges[z]
92
+ const min = Math.min(...xY.filter(x => !isNaN(x)))
93
+ const max = Math.max(...xY.filter(x => !isNaN(x)))
149
94
 
150
- if (min1 <= min && max <= max1) {
151
- min = min1
152
- max = max1
153
- lColors.push(['circle', { class: cls, cx: 0, cy: gapY * (lColors.length - 2), r: 5, fill }])
154
- lLabels.push(['text',
155
- { x: 0, y: gapY * (lLabels.length - 2), 'text-anchor': 'end', 'alignment-baseline': 'middle' },
156
- zLabels[z]])
157
- } else {
158
- min = min2
159
- max = max2
160
- rColors.push(['circle', { class: cls, cx: 0, cy: gapY * (rColors.length - 2), r: 5, fill }])
161
- rLabels.push(['text',
162
- { x: 0, y: gapY * (rLabels.length - 2), 'text-anchor': 'start', 'alignment-baseline': 'middle' },
163
- zLabels[z]])
164
- }
95
+ colors.push(['circle', { cx: 0, cy: gapY * (colors.length - 2), r: 5, fill }])
96
+ labels.push(['text',
97
+ { x: 0, y: gapY * (labels.length - 2), 'text-anchor': 'start', 'alignment-baseline': 'middle' },
98
+ zLabels[z]])
165
99
 
166
- const y = xa.map(x => isNaN(x) ? x : h * (max - x) / (max - min))
100
+ const y = xY.map(x => isNaN(x) ? x : h * (max - x) / (max - min))
167
101
 
168
102
  xi.forEach((x, i) => {
169
103
  if (!isNaN(y[i])) {
170
- graph.push(['circle', { class: cls, cx: x, cy: y[i], r: 5, fill }])
104
+ graph.push(['g', ['circle', { cx: x, cy: y[i], r: 5, fill }, ['title', `${zLabels[z]}: ${xY[i]}`]]])
171
105
 
172
106
  if (!isNaN(y[i - 1])) {
173
- graph.push(['line', { class: cls, x1: x, x2: xi[i - 1], y1: y[i], y2: y[i - 1], stroke: fill }])
107
+ graph.push(['line', { x1: x, x2: xi[i - 1], y1: y[i], y2: y[i - 1], stroke: fill }])
174
108
  }
175
109
  }
176
110
  })
@@ -181,35 +115,14 @@ export const chartable = ({
181
115
  width: `${svgW}px`,
182
116
  height: `${svgH}px`,
183
117
  class: 'chartable'
184
- }, id != null ? { id } : null, title != null
185
- ? ['text',
186
- { class: 'chartable-title', x: svgW / 2, y: top / 2, 'text-anchor': 'middle', 'alignment-baseline': 'middle' },
187
- title]
188
- : null,
189
- graph,
190
- min1 < Infinity
191
- ? ['g', { class: 'chartable-left', transform: `translate(${left} ${top})` },
192
- ['g', { class: 'chartable-y-labels', transform: 'translate(-15 0)' },
193
- ...yi.map((y, i) => ['text',
194
- { x: 0, y, 'text-anchor': 'end', 'alignment-baseline': 'middle' },
195
- yLabel(min1, max1, i)])],
196
- lColors, lLabels]
197
- : null,
198
- min2 < Infinity
199
- ? ['g', { class: 'chartable-right', transform: `translate(${left + w} ${top})` },
200
- ['g', { class: 'chartable-y-labels', transform: 'translate(15 0)' },
201
- ...yi.map((y, i) => ['text',
202
- { x: 0, y, 'text-anchor': 'start', 'alignment-baseline': 'middle' },
203
- yLabel(min2, max2, i)])],
204
- rColors, rLabels]
205
- : null,
118
+ }, id != null ? { id } : null,
119
+ graph, colors, labels,
206
120
  xLabels.length > 0
207
- ? ['g', { transform: `translate(${left} ${top + h})` },
208
- ['g', { class: 'chartable-x-labels', transform: 'translate(0 15)' },
209
- ...xi.slice(0).map((x, i) => ['text', rotate
210
- ? { x: 0, y: -x, 'text-anchor': 'start', 'alignment-baseline': 'hanging', transform: 'rotate(90)' }
211
- : { x, y: 0, 'text-anchor': 'middle', 'alignment-baseline': 'hanging' },
212
- xLabels[i]])]]
121
+ ? ['g', { transform: `translate(${left} ${top + h + 15})` },
122
+ ...xi.slice(0).map((x, i) => ['text', rotate
123
+ ? { x: 0, y: -x, 'text-anchor': 'start', 'alignment-baseline': 'hanging', transform: 'rotate(90)' }
124
+ : { x, y: 0, 'text-anchor': 'middle', 'alignment-baseline': 'hanging' },
125
+ xLabels[i]])]
213
126
  : null
214
127
  )
215
128
  }
package/escape.js CHANGED
@@ -23,7 +23,7 @@ export const escape = (
23
23
 
24
24
  export const tests = {
25
25
  escape: (/** @type {import('bun:test').Expect} */ expect) => {
26
- // @ts-ignore
26
+ // @ts-expect-error
27
27
  const /** @type {EscapeMap} */ escapeMap = new Map([
28
28
  [undefined, () => 'NULL'],
29
29
  [Array, (/** @type {any[]} */ values) => escapeValues(escapeMap, values).join(', ')],
@@ -33,7 +33,7 @@ export const tests = {
33
33
  [String, (/** @type {string} */ value) => `'${value.replace(/'/g, "''")}'`]
34
34
  ])
35
35
 
36
- // @ts-ignore
36
+ // @ts-expect-error
37
37
  const sql = escape.bind(null, escapeMap)
38
38
 
39
39
  const actual = sql`
package/h.js CHANGED
@@ -44,10 +44,10 @@ const _h = (/** @type {string?=} */ namespaceURI) => {
44
44
  if (arg instanceof Node) {
45
45
  child = arg
46
46
  } else if (is(String, arg) || is(Number, arg)) {
47
- // @ts-ignore
47
+ // @ts-expect-error
48
48
  child = new Text(arg)
49
49
  } else if (is(Array, arg)) {
50
- // @ts-ignore
50
+ // @ts-expect-error
51
51
  child = h(...arg)
52
52
  } else if (arg != null) {
53
53
  for (const name in arg) {
@@ -57,19 +57,19 @@ const _h = (/** @type {string?=} */ namespaceURI) => {
57
57
  const name1 = name.slice(1)
58
58
 
59
59
  if (is(Object, value)) {
60
- // @ts-ignore
60
+ // @ts-expect-error
61
61
  node[name1] = node[name1] ?? {}
62
- // @ts-ignore
62
+ // @ts-expect-error
63
63
  Object.assign(node[name1], value)
64
64
  } else {
65
- // @ts-ignore
65
+ // @ts-expect-error
66
66
  node[name1] = value
67
67
  }
68
68
  } else if (node instanceof Element) {
69
69
  const indexOfColon = name.indexOf(':')
70
70
 
71
71
  if (indexOfColon >= 0) {
72
- // @ts-ignore
72
+ // @ts-expect-error
73
73
  const /** @type {string=} */ ns = NS[name.slice(0, indexOfColon)]
74
74
 
75
75
  if (ns != null) {
@@ -197,17 +197,17 @@ export const tests = {
197
197
  'h: nested properties': (/** @type {import('bun:test').Expect} */ expect) => {
198
198
  const div = h('div')
199
199
 
200
- // @ts-ignore
200
+ // @ts-expect-error
201
201
  expect(div.key).toBeUndefined()
202
202
 
203
203
  h(div, { $key: { one: 1 } })
204
204
 
205
- // @ts-ignore
205
+ // @ts-expect-error
206
206
  expect(div.key).toEqual({ one: 1 })
207
207
 
208
208
  h(div, { $key: { two: 2 } })
209
209
 
210
- // @ts-ignore
210
+ // @ts-expect-error
211
211
  expect(div.key).toEqual({ one: 1, two: 2 })
212
212
  }
213
213
  }
package/has.js CHANGED
@@ -16,7 +16,7 @@ export const tests = {
16
16
  expect('null' in obj).toBe(true)
17
17
  expect(has('null', obj)).toBe(true)
18
18
 
19
- // @ts-ignore
19
+ // @ts-expect-error
20
20
  expect(null in obj).toBe(true)
21
21
  expect(has(null, obj)).toBe(false)
22
22
 
@@ -28,7 +28,7 @@ export const tests = {
28
28
  let typeError
29
29
 
30
30
  try {
31
- // @ts-ignore
31
+ // @ts-expect-error
32
32
  'key' in null
33
33
  } catch (error) {
34
34
  typeError = error
package/is.js CHANGED
@@ -53,7 +53,7 @@ export const tests = {
53
53
 
54
54
  const fakeFooBar = {}
55
55
 
56
- // @ts-ignore
56
+ // @ts-expect-error
57
57
  fakeFooBar[Symbol.toStringTag] = FooBar.name
58
58
 
59
59
  expect(is(FooBar, fakeFooBar)).toBe(false)
package/jsOnParse.js CHANGED
@@ -31,7 +31,7 @@ export const jsOnParse = (
31
31
  }
32
32
 
33
33
  if (has(key, handlers) && is(Array, value[key])) {
34
- // @ts-ignore
34
+ // @ts-expect-error
35
35
  return handlers[key](...value[key])
36
36
  }
37
37
  }
package/nanolightJs.js CHANGED
@@ -4,7 +4,7 @@ import { nanolight } from './nanolight.js'
4
4
  /**
5
5
  * A helper for highlighting JavaScript.
6
6
  */
7
- // @ts-ignore
7
+ // @ts-expect-error
8
8
  export const nanolightJs = nanolight.bind(0,
9
9
  /('.*?'|".*?"|`[\s\S]*?`)|(\/\/.*?\n|\/\*[\s\S]*?\*\/)|(any|bigint|break|boolean|case|catch|const|continue|debugger|default|delete|do|else|eval|export|extends|false|finally|for|from|function|goto|if|import|in|instanceof|is|keyof|let|NaN|new|number|null|package|return|string|super|switch|symbol|this|throw|true|try|type|typeof|undefined|unknown|var|void|while|with|yield)(?!\w)|([<>=.?:&|!^~*/%+-])|(0x[\dabcdef]+|0o[01234567]+|0b[01]+|\d+(?:\.[\d_]+)?(?:e[+-]?[\d_]+)?)|([$\w]+)(?=\()|([$\wąćęłńóśżźĄĆĘŁŃÓŚŻŹ]+)/,
10
10
  [
package/package.json CHANGED
@@ -40,5 +40,5 @@
40
40
  "types": "nnn.d.ts",
41
41
  "name": "@jackens/nnn",
42
42
  "type": "module",
43
- "version": "2024.2.12"
43
+ "version": "2024.2.15"
44
44
  }
package/pick.js CHANGED
@@ -2,45 +2,19 @@
2
2
  * A helper that implements TypeScript’s `Pick` utility type.
3
3
  *
4
4
  * @type {<T extends Partial<Record<PropertyKey, any>>, K extends (keyof T)[]>(obj: T, keys: K) => Pick<T, K[number]>}
5
- * @template {Partial<Record<PropertyKey, any>>} T
6
- * @template {keyof T} K
7
5
  */
8
- export const pick = (/** @type {T} */ obj, /** @type {K[]} */ keys) => {
9
- const result = {}
10
-
11
- for (const key in obj) {
12
- // @ts-ignore
13
- if (keys.includes(key)) {
14
- // @ts-ignore
15
- result[key] = obj[key]
16
- }
17
- }
18
-
19
- // @ts-ignore
20
- return result
21
- }
6
+ export const pick = (/** @type {Partial<Record<PropertyKey, any>>} */ obj, /** @type {any[]} */ keys) =>
7
+ // @ts-expect-error
8
+ Object.fromEntries(Object.entries(obj).filter(([key]) => keys.includes(key)))
22
9
 
23
10
  /**
24
11
  * A helper that implements TypeScript’s `Omit` utility type.
25
12
  *
26
13
  * @type {<T extends Partial<Record<PropertyKey, any>>, K extends (keyof T)[]>(obj: T, keys: K) => Omit<T, K[number]>}
27
- * @template {Partial<Record<PropertyKey, any>>} T
28
- * @template {keyof T} K
29
14
  */
30
- export const omit = (/** @type {T} */ obj, /** @type {K[]} */ keys) => {
31
- const result = {}
32
-
33
- for (const key in obj) {
34
- // @ts-ignore
35
- if (!keys.includes(key)) {
36
- // @ts-ignore
37
- result[key] = obj[key]
38
- }
39
- }
40
-
41
- // @ts-ignore
42
- return result
43
- }
15
+ export const omit = (/** @type {Partial<Record<PropertyKey, any>>} */ obj, /** @type {any[]} */ keys) =>
16
+ // @ts-expect-error
17
+ Object.fromEntries(Object.entries(obj).filter(([key]) => !keys.includes(key)))
44
18
 
45
19
  export const tests = {
46
20
  pick: (/** @type {import('bun:test').Expect} */ expect) => {
package/plUral.js CHANGED
@@ -20,7 +20,7 @@ export const plUral = (
20
20
 
21
21
  export const tests = {
22
22
  plUral: (/** @type {import('bun:test').Expect} */ expect) => {
23
- // @ts-ignore
23
+ // @ts-expect-error
24
24
  const auto = plUral.bind(null, 'auto', 'auta', 'aut')
25
25
 
26
26
  expect(auto(0)).toEqual('aut')
@@ -28,7 +28,7 @@ export const tests = {
28
28
  expect(auto(17)).toEqual('aut')
29
29
  expect(auto(42)).toEqual('auta')
30
30
 
31
- // @ts-ignore
31
+ // @ts-expect-error
32
32
  const car = plUral.bind(null, 'car', 'cars', 'cars')
33
33
 
34
34
  expect(car(0)).toEqual('cars')
package/pro.js CHANGED
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * A helper that protects calls to nested properties by a `Proxy` that initializes non-existent values with an empty object.
3
3
  */
4
- // @ts-ignore
4
+ // @ts-expect-error
5
5
  export const pro = (/** @type {any} */ ref) => new Proxy(ref, {
6
6
  get (target, key) {
7
7
  return pro(target[key] = target[key] ?? {})
package/readme.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  Jackens’ JavaScript helpers.
4
4
 
5
- <sub>Version: <code class="version">2024.2.12</code></sub>
5
+ <sub>Version: <code class="version">2024.2.15</code></sub>
6
6
 
7
7
  ## Installation
8
8
 
@@ -103,7 +103,7 @@ The type of arguments of the `jcss` helper.
103
103
  ### chartable
104
104
 
105
105
  ```ts
106
- export function chartable({ bottom, gapX, gapY, headerColumn, id, left, maxY, reverse, right, rotate, singleScale, table, title, top }: {
106
+ export function chartable({ bottom, gapX, gapY, headerColumn, id, left, maxY, reverse, right, rotate, table, top }: {
107
107
  bottom?: number;
108
108
  gapX?: number;
109
109
  gapY?: number;
@@ -114,9 +114,7 @@ export function chartable({ bottom, gapX, gapY, headerColumn, id, left, maxY, re
114
114
  reverse?: boolean;
115
115
  right?: number;
116
116
  rotate?: boolean;
117
- singleScale?: boolean;
118
117
  table: HTMLTableElement;
119
- title?: string;
120
118
  top?: number;
121
119
  }): SVGSVGElement;
122
120
  ```
@@ -129,15 +127,13 @@ Options:
129
127
  - `gapY`: Y axis spacing
130
128
  - `headerColumn`: flag indicating that `table` has a header column (with X axis labels)
131
129
  - `id`: chart id
132
- - `left`: left padding (for data series labels)
130
+ - `left`: left padding
133
131
  - `maxY`: number of Y axis lines
134
132
  - `reverse`: flag to reverse all data series
135
133
  - `right`: right padding (for data series labels)
136
134
  - `rotate`: flag to rotate X axis labels
137
- - `singleScale`: flag to force single scale
138
135
  - `table`: `HTMLTableElement` to extract data, data series labels and X axis labels
139
- - `title`: chart title
140
- - `top`: top padding (for the title)
136
+ - `top`: top padding
141
137
 
142
138
  ### eq
143
139
 
package/refsInfo.js CHANGED
@@ -32,7 +32,7 @@ export const tests = {
32
32
 
33
33
  'refsInfo: browserFingerprint': (/** @type {import('bun:test').Expect} */ expect) => {
34
34
  const browserFingerprint = () => {
35
- // @ts-ignore
35
+ // @ts-expect-error
36
36
  const refs = Object.getOwnPropertyNames(window).map(name => window[name])
37
37
  const info = refsInfo(...refs)
38
38
  const json = JSON.stringify(info)
package/uuid1.js CHANGED
@@ -18,7 +18,7 @@ export const uuid1 = ({
18
18
  return time.slice(-8).concat(
19
19
  '-',
20
20
  time.slice(-12, -8),
21
- // @ts-ignore
21
+ // @ts-expect-error
22
22
  -1,
23
23
  time.slice(-15, -12),
24
24
  '-',