@jackens/nnn 2024.2.17 → 2024.2.19

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
@@ -2,30 +2,30 @@
2
2
  * A helper for creating a chart based on a table (conf. <https://jackens.github.io/nnn/chartable/>).
3
3
  *
4
4
  * Options:
5
- * - `bottom`: bottom padding (for X axis labels)
6
- * - `gapX`: X axis spacing
7
- * - `gapY`: Y axis spacing
8
- * - `headerColumn`: flag indicating that `table` has a header column (with X axis labels)
9
- * - `left`: left padding
10
- * - `maxY`: number of Y axis lines
11
- * - `reverse`: flag to reverse all data series
12
- * - `right`: right padding (for data series labels)
13
- * - `rotate`: flag to rotate X axis labels
14
5
  * - `table`: `HTMLTableElement` to extract data, data series labels and X axis labels
15
- * - `top`: top padding
6
+ * - `headerColumn`: flag indicating that `table` has a header column with X axis labels
7
+ * - `xGap`: X axis spacing
8
+ * - `xLabelsPx`:
9
+ * - `xLabelsRotate`: flag to rotate X axis labels
10
+ * - `xReverse`: flag to reverse all data series
11
+ * - `yGap`: Y axis spacing
12
+ * - `yLabelsLeftPx`:
13
+ * - `yLabelsRightPx`:
14
+ * - `yMax`: number of Y axis lines
15
+ * - `zLabelsPx`:
16
16
  */
17
- export function chartable({ bottom, gapX, gapY, headerColumn, left, maxY, reverse, right, rotate, table, top }: {
18
- bottom?: number;
19
- gapX?: number;
20
- gapY?: number;
21
- headerColumn?: boolean;
22
- left?: number;
23
- maxY?: number;
24
- reverse?: boolean;
25
- right?: number;
26
- rotate?: boolean;
17
+ export function chartable({ table, headerColumn, xGap, xLabelsPx, xLabelsRotate, xReverse, yGap, yLabelsLeftPx, yLabelsRightPx, yMax, zLabelsPx }: {
27
18
  table: HTMLTableElement;
28
- top?: number;
29
- }): Node;
19
+ headerColumn?: boolean;
20
+ xGap?: number;
21
+ xLabelsPx?: number;
22
+ xLabelsRotate?: boolean;
23
+ xReverse?: boolean;
24
+ yGap?: number;
25
+ yLabelsLeftPx?: number;
26
+ yLabelsRightPx?: number;
27
+ yMax?: number;
28
+ zLabelsPx?: number;
29
+ }): SVGSVGElement;
30
30
 
31
31
  export const tests: {};
package/chartable.js CHANGED
@@ -1,50 +1,54 @@
1
- import { s } from './h.js'
1
+ import { h, s } from './h.js'
2
2
 
3
3
  const COLORS = ['#e22', '#e73', '#fc3', '#ad4', '#4d9', '#3be', '#45d', '#c3e']
4
4
  const PADDING = 15
5
5
 
6
+ const _svg = s('svg', { viewBox: '0 0 0 0', width: 0, height: 0 })
7
+
8
+ h(document.body, ['div', { $style: { width: 0, height: 0 } }, _svg])
9
+
6
10
  /**
7
11
  * A helper for creating a chart based on a table (conf. <https://jackens.github.io/nnn/chartable/>).
8
12
  *
9
13
  * Options:
10
- * - `bottom`: bottom padding (for X axis labels)
11
- * - `gapX`: X axis spacing
12
- * - `gapY`: Y axis spacing
13
- * - `headerColumn`: flag indicating that `table` has a header column (with X axis labels)
14
- * - `left`: left padding
15
- * - `maxY`: number of Y axis lines
16
- * - `reverse`: flag to reverse all data series
17
- * - `right`: right padding (for data series labels)
18
- * - `rotate`: flag to rotate X axis labels
19
14
  * - `table`: `HTMLTableElement` to extract data, data series labels and X axis labels
20
- * - `top`: top padding
15
+ * - `headerColumn`: flag indicating that `table` has a header column with X axis labels
16
+ * - `xGap`: X axis spacing
17
+ * - `xLabelsPx`:
18
+ * - `xLabelsRotate`: flag to rotate X axis labels
19
+ * - `xReverse`: flag to reverse all data series
20
+ * - `yGap`: Y axis spacing
21
+ * - `yLabelsLeftPx`:
22
+ * - `yLabelsRightPx`:
23
+ * - `yMax`: number of Y axis lines
24
+ * - `zLabelsPx`:
21
25
  *
22
26
  * @param {{
23
- * bottom?: number;
24
- * gapX?: number;
25
- * gapY?: number;
26
- * headerColumn?: boolean;
27
- * left?: number;
28
- * maxY?: number;
29
- * reverse?: boolean;
30
- * right?: number;
31
- * rotate?: boolean;
32
27
  * table: HTMLTableElement;
33
- * top?: number;
28
+ * headerColumn?: boolean;
29
+ * xGap?: number;
30
+ * xLabelsPx?: number;
31
+ * xLabelsRotate?: boolean;
32
+ * xReverse?: boolean;
33
+ * yGap?: number;
34
+ * yLabelsLeftPx?: number;
35
+ * yLabelsRightPx?: number;
36
+ * yMax?: number;
37
+ * zLabelsPx?: number;
34
38
  * }} options
35
39
  */
36
40
  export const chartable = ({
37
- bottom = 50,
38
- gapX = 70,
39
- gapY = 30,
40
- headerColumn = false,
41
- left = 300,
42
- maxY = 10,
43
- reverse = false,
44
- right = 100,
45
- rotate = false,
46
41
  table,
47
- top = PADDING
42
+ headerColumn = false,
43
+ xGap = 70,
44
+ xLabelsPx = 0,
45
+ xLabelsRotate = false,
46
+ xReverse = false,
47
+ yGap = 30,
48
+ yLabelsLeftPx = 100,
49
+ yLabelsRightPx = 100,
50
+ yMax = 10,
51
+ zLabelsPx = 0
48
52
  }) => {
49
53
  const /** @type {number[][]} */ zxValues = []
50
54
  const /** @type {string[]} */ xLabels = []
@@ -67,92 +71,123 @@ export const chartable = ({
67
71
  }
68
72
  }))
69
73
 
70
- if (reverse) {
74
+ if (xReverse) {
71
75
  xLabels.reverse()
72
76
  zxValues.forEach(xValues => xValues.reverse())
73
77
  }
74
78
 
75
- const maxX = zxValues[0].length
76
- const xPx = Array.from({ length: maxX }, (_, x) => x * gapX)
77
- const yPx = Array.from({ length: maxY }, (_, y) => y * gapY)
78
- const width = gapX * (maxX - 1)
79
- const height = gapY * (maxY - 1)
80
- const svgW = left + width + right
81
- const svgH = top + height + bottom
79
+ const xMax = zxValues[0].length
80
+ const xPx = Array.from({ length: xMax }, (_, x) => x * xGap)
81
+ const yPx = Array.from({ length: yMax }, (_, y) => y * yGap)
82
82
 
83
- const /** @type {import('./h.js').HArgs1} */ gGraph = ['g', { transform: `translate(${left} ${top})` },
84
- ...yPx.map(px => ['line', { x1: 0, x2: width, y1: px, y2: px, stroke: '#8888' }]),
85
- ...xPx.map(px => ['line', { x1: px, x2: px, y1: 0, y2: height, stroke: '#8888' }])]
86
- const /** @type {import('./h.js').HArgs1} */ gZColors = ['g', { transform: `translate(${PADDING} ${top})` }]
87
- const /** @type {import('./h.js').HArgs1} */ gZLabels = ['g', { transform: `translate(${2 * PADDING} ${top})` }]
88
- const /** @type {import('./h.js').HArgs} */ svg = ['svg',
89
- { viewBox: `0 0 ${svgW} ${svgH}`, width: `${svgW}px`, height: `${svgH}px`, class: 'chartable' },
90
- gGraph, gZColors, gZLabels]
83
+ const width = xGap * (xMax - 1)
84
+ const height = yGap * (yMax - 1)
91
85
 
92
- if (xLabels.length > 0) {
93
- svg.push(['g', { transform: `translate(${left} ${top + height + PADDING})` },
94
- ...xPx.slice(0).map((xp, x) => ['text',
95
- rotate
96
- ? { x: 0, y: -xp, 'text-anchor': 'start', 'alignment-baseline': 'middle', transform: 'rotate(90)' }
97
- : { x: xp, y: PADDING, 'text-anchor': 'middle', 'alignment-baseline': 'middle' },
98
- xLabels[x]])])
86
+ const gGraph = s('g',
87
+ ...yPx.map(px => ['line', { x1: 0, x2: width, y1: px, y2: px, stroke: '#8888' }]),
88
+ ...xPx.map(px => ['line', { x1: px, x2: px, y1: 0, y2: height, stroke: '#8888' }]))
89
+ const gXLabels = s('g')
90
+ const gYLabelsL = zxValues.map(_ => s('g'))
91
+ const gYLabelsR = zxValues.map(_ => s('g'))
92
+ const gZColors = s('g')
93
+ const /** @type {SVGTextElement[]} */ gZLabels = []
94
+
95
+ const onclick = (/** @type {number} */ z) => {
96
+ gYLabelsL.forEach((g, z2) => s(g, { $style: { display: z2 === z ? 'block' : 'none' } }))
97
+ gYLabelsR.forEach((g, z2) => s(g, { $style: { display: z2 === z ? 'block' : 'none' } }))
98
+ gZLabels.forEach((text, z2) => s(text, { $style: { fontWeight: z2 === z ? 'bold' : 'normal', cursor: 'pointer' } }))
99
99
  }
100
100
 
101
- const /** @type {[SVGElement, SVGElement, SVGTextElement][]} */ toUpdate = []
102
-
103
- const onclick = (/** @type {number} */ z) => toUpdate.forEach(([gLeftYLabels, gRightYLabels, zLabel], z2) => {
104
- s(gLeftYLabels, { $style: { display: z2 === z ? 'block' : 'none' } })
105
- s(gRightYLabels, { $style: { display: z2 === z ? 'block' : 'none' } })
106
- s(zLabel, { $style: { textDecoration: z2 === z ? 'underline' : 'none', cursor: 'pointer' } })
107
- })
108
-
109
101
  zxValues.forEach((values, z) => {
110
102
  const fill = COLORS[z % COLORS.length]
111
103
  const minValue = Math.min(...values.filter(value => !isNaN(value)))
112
104
  const maxValue = Math.max(...values.filter(value => !isNaN(value)))
113
105
 
114
- const valuesPx = values.map(value => isNaN(value) ? value : height * (maxValue - value) / (maxValue - minValue))
115
-
116
- const gLeftYLabels = s('g', { transform: `translate(${left - PADDING} ${top})` },
117
- ...yPx.map((yp, y) => ['text',
106
+ yPx.forEach((yp, y) => {
107
+ const textL = s('text',
118
108
  { x: 0, y: yp, 'text-anchor': 'end', 'alignment-baseline': 'middle' },
119
- (maxValue - (maxValue - minValue) / maxY * (y + 1)).toFixed(2)]))
120
-
121
- const gRightYLabels = s('g', { transform: `translate(${left + width + PADDING} ${top})` },
122
- ...yPx.map((yp, y) => ['text',
109
+ (maxValue - (maxValue - minValue) / yMax * (y + 1)).toFixed(2))
110
+ const textR = s('text',
123
111
  { x: 0, y: yp, 'text-anchor': 'start', 'alignment-baseline': 'middle' },
124
- (maxValue - (maxValue - minValue) / maxY * (y + 1)).toFixed(2)]))
112
+ (maxValue - (maxValue - minValue) / yMax * (y + 1)).toFixed(2))
125
113
 
126
- svg.push(gLeftYLabels, gRightYLabels)
114
+ s(_svg, textL, textR)
127
115
 
128
- const zLabel = s('text', {
116
+ yLabelsLeftPx = Math.max(yLabelsLeftPx, textL.getBBox().width)
117
+ yLabelsRightPx = Math.max(yLabelsRightPx, textL.getBBox().width)
118
+
119
+ s(gYLabelsL[z], textL)
120
+ s(gYLabelsR[z], textR)
121
+ })
122
+
123
+ const text = s('text', {
129
124
  x: 0,
130
- y: gapY * (gZLabels.length - 2),
125
+ y: yGap * z,
131
126
  'text-anchor': 'start',
132
127
  'alignment-baseline': 'middle',
133
- $onclick: () => onclick(z)
128
+ $onclick: () => onclick(z),
129
+ $style: { fontWeight: 'bold' }
134
130
  },
135
131
  zLabels[z])
136
132
 
137
- gZLabels.push(zLabel)
138
- gZColors.push(['circle', { cx: 0, cy: gapY * (gZColors.length - 2), r: 5, fill }])
133
+ s(_svg, text)
134
+
135
+ zLabelsPx = Math.max(zLabelsPx, text.getBBox().width)
136
+
137
+ gZLabels[z] = text
139
138
 
140
- toUpdate.push([gLeftYLabels, gRightYLabels, zLabel])
139
+ s(gZColors, ['circle', { cx: 0, cy: yGap * z, r: 5, fill }])
140
+
141
+ const valuesPx = values.map(value => isNaN(value) ? value : height * (maxValue - value) / (maxValue - minValue))
141
142
 
142
143
  xPx.forEach((px, x) => {
143
144
  if (!isNaN(valuesPx[x])) {
144
- gGraph.push(['g', ['circle', { cx: px, cy: valuesPx[x], r: 5, fill }]])
145
+ s(gGraph, ['g', ['circle', { cx: px, cy: valuesPx[x], r: 5, fill }]])
145
146
 
146
147
  if (!isNaN(valuesPx[x - 1])) {
147
- gGraph.push(['line', { x1: px, x2: xPx[x - 1], y1: valuesPx[x], y2: valuesPx[x - 1], stroke: fill }])
148
+ s(gGraph, ['line', { x1: px, x2: xPx[x - 1], y1: valuesPx[x], y2: valuesPx[x - 1], stroke: fill }])
148
149
  }
149
150
  }
150
151
  })
151
152
  })
152
153
 
154
+ if (xLabels.length > 0) {
155
+ xPx.forEach((xp, x) => {
156
+ const text = s('text',
157
+ xLabelsRotate
158
+ ? { x: 0, y: -xp, 'text-anchor': 'start', 'alignment-baseline': 'middle', transform: 'rotate(90)' }
159
+ : { x: xp, y: PADDING, 'text-anchor': 'middle', 'alignment-baseline': 'middle' },
160
+ xLabels[x])
161
+
162
+ s(_svg, text)
163
+
164
+ xLabelsPx = Math.max(xLabelsPx, xLabelsRotate ? text.getBBox().width : text.getBBox().height)
165
+
166
+ s(gXLabels, text)
167
+ })
168
+ }
169
+
170
+ const svgW = width + yLabelsLeftPx + yLabelsRightPx + zLabelsPx + 4 * PADDING
171
+ const svgH = height + xLabelsPx + (xLabels.length > 0 ? 3 : 2) * PADDING
172
+
173
+ s(gGraph, { transform: `translate(${yLabelsLeftPx + PADDING} ${PADDING})` })
174
+
175
+ gYLabelsL.forEach(g => s(g, { transform: `translate(${yLabelsLeftPx} ${PADDING})` }))
176
+ gYLabelsR.forEach(g => s(g, { transform: `translate(${width + yLabelsLeftPx + 2 * PADDING} ${PADDING})` }))
177
+
178
+ s(gZColors, { transform: `translate(${width + yLabelsLeftPx + yLabelsRightPx + 3 * PADDING} ${PADDING})` })
179
+ s(gXLabels, { transform: `translate(${yLabelsLeftPx + PADDING} ${height + 2 * PADDING})` })
180
+
153
181
  onclick(0)
154
182
 
155
- return s(...svg)
183
+ return s('svg',
184
+ { viewBox: `0 0 ${svgW} ${svgH}`, width: `${svgW}px`, height: `${svgH}px`, class: 'chartable' },
185
+ gGraph,
186
+ gXLabels,
187
+ ...gYLabelsL,
188
+ ...gYLabelsR,
189
+ gZColors,
190
+ ['g', { transform: `translate(${width + yLabelsLeftPx + yLabelsRightPx + 4 * PADDING} ${PADDING})` }, ...gZLabels])
156
191
  }
157
192
 
158
193
  export const tests = {}
package/eq.d.ts CHANGED
@@ -4,5 +4,5 @@
4
4
  export function eq(x: any, y: any): boolean;
5
5
 
6
6
  export namespace tests {
7
- function eq(expect: import("bun:test").Expect): void;
7
+ function eq(expect: Chai.ExpectStatic): void;
8
8
  }
package/eq.js CHANGED
@@ -45,39 +45,39 @@ export const eq = /** @return {boolean} */ (/** @type {any} */ x, /** @type {any
45
45
  }
46
46
 
47
47
  export const tests = {
48
- eq: (/** @type {import('bun:test').Expect} */ expect) => {
49
- expect(eq(true, true)).toBe(true)
50
- expect(eq(NaN, NaN)).toBe(true)
51
- expect(eq(null, undefined)).toBe(false)
52
- expect(eq(42, 42)).toBe(true)
48
+ eq: (/** @type {import('chai').expect} */ expect) => {
49
+ expect(eq(true, true)).to.be.true
50
+ expect(eq(NaN, NaN)).to.be.true
51
+ expect(eq(null, undefined)).to.be.false
52
+ expect(eq(42, 42)).to.be.true
53
53
  // eslint-disable-next-line no-new-wrappers
54
- expect(eq(42, new Number(42))).toBe(true)
55
- expect(eq(42, Number(42))).toBe(true)
54
+ expect(eq(42, new Number(42))).to.be.true
55
+ expect(eq(42, Number(42))).to.be.true
56
56
  // eslint-disable-next-line no-new-wrappers
57
- expect(eq(new Number(42), Number(42))).toBe(true)
58
- expect(eq(42, '42')).toBe(false)
59
- expect(eq('42', '42')).toBe(true)
57
+ expect(eq(new Number(42), Number(42))).to.be.true
58
+ expect(eq(42, '42')).to.be.false
59
+ expect(eq('42', '42')).to.be.true
60
60
  // eslint-disable-next-line no-new-wrappers
61
- expect(eq('42', new String('42'))).toBe(true)
62
- expect(eq('42', String('42'))).toBe(true)
61
+ expect(eq('42', new String('42'))).to.be.true
62
+ expect(eq('42', String('42'))).to.be.true
63
63
  // eslint-disable-next-line no-new-wrappers
64
- expect(eq(String('42'), new String('42'))).toBe(true)
65
- expect(eq(/42/, /42/)).toBe(true)
66
- expect(eq(/42/, /42/g)).toBe(false)
67
- expect(eq(new Date(42), new Date(42))).toBe(true)
68
- expect(eq(new Date(), new Date(42))).toBe(false)
69
- expect(eq({ j: '42', c: 42 }, { c: 42, j: '42' })).toBe(true)
70
- expect(eq([42, '42'], [42, '42'])).toBe(true)
71
- expect(eq(new Set(['42', 42]), new Set([42, '42']))).toBe(true)
72
- expect(eq(new Set(['42', 42]), new Set([42]))).toBe(false)
73
- expect(eq(new Set([42, undefined]), new Set([42]))).toBe(false)
64
+ expect(eq(String('42'), new String('42'))).to.be.true
65
+ expect(eq(/42/, /42/)).to.be.true
66
+ expect(eq(/42/, /42/g)).to.be.false
67
+ expect(eq(new Date(42), new Date(42))).to.be.true
68
+ expect(eq(new Date(), new Date(42))).to.be.false
69
+ expect(eq({ j: '42', c: 42 }, { c: 42, j: '42' })).to.be.true
70
+ expect(eq([42, '42'], [42, '42'])).to.be.true
71
+ expect(eq(new Set(['42', 42]), new Set([42, '42']))).to.be.true
72
+ expect(eq(new Set(['42', 42]), new Set([42]))).to.be.false
73
+ expect(eq(new Set([42, undefined]), new Set([42]))).to.be.false
74
74
  expect(eq(
75
75
  new Map([[{ j: 42 }, { J: '42' }], [{ c: 42 }, { C: '42' }]]),
76
76
  new Map([[{ c: 42 }, { C: '42' }], [{ j: 42 }, { J: '42' }]])
77
- )).toBe(true)
77
+ )).to.be.true
78
78
  expect(eq(
79
79
  new Map([[{ j: 42 }, { J: '42' }], [{ c: 42 }, { C: '42' }]]),
80
80
  new Map([[{ j: '42' }, { J: 42 }], [{ c: '42' }, { C: 42 }]])
81
- )).toBe(false)
81
+ )).to.be.false
82
82
  }
83
83
  }
package/escape.d.ts CHANGED
@@ -14,5 +14,5 @@ export function escape(escapeMap: EscapeMap, template: TemplateStringsArray, ...
14
14
  export function escapeValues(escapeMap: EscapeMap, values: any[]): string[];
15
15
 
16
16
  export namespace tests {
17
- function escape(expect: import("bun:test").Expect): void;
17
+ function escape(expect: Chai.ExpectStatic): void;
18
18
  }
package/escape.js CHANGED
@@ -22,7 +22,7 @@ export const escape = (
22
22
  ) => String.raw(template, ...escapeValues(escapeMap, values))
23
23
 
24
24
  export const tests = {
25
- escape: (/** @type {import('bun:test').Expect} */ expect) => {
25
+ escape: (/** @type {import('chai').expect} */ expect) => {
26
26
  // @ts-expect-error
27
27
  const /** @type {EscapeMap} */ escapeMap = new Map([
28
28
  [undefined, () => 'NULL'],
@@ -46,6 +46,6 @@ export const tests = {
46
46
  FROM table_name
47
47
  WHERE column_name IN (b'1', NULL, NULL, 42, '42', '4''2', NULL, '1980-03-31 04:30:00')`
48
48
 
49
- expect(actual).toEqual(expected)
49
+ expect(actual).to.deep.equal(expected)
50
50
  }
51
51
  }
@@ -4,5 +4,5 @@
4
4
  export function fixTypography(node: Node): void;
5
5
 
6
6
  export namespace tests {
7
- function fixTypography(expect: import("bun:test").Expect): void;
7
+ function fixTypography(expect: Chai.ExpectStatic): void;
8
8
  }
package/fixTypography.js CHANGED
@@ -49,12 +49,12 @@ export const fixTypography = (/** @type {Node} */ node) => {
49
49
  }
50
50
 
51
51
  export const tests = {
52
- fixTypography: (/** @type {import('bun:test').Expect} */ expect) => {
52
+ fixTypography: (/** @type {import('chai').expect} */ expect) => {
53
53
  const p = h('p', 'Pchnąć w tę łódź jeża lub ośm skrzyń fig (zob. https://pl.wikipedia.org/wiki/Pangram).')
54
54
 
55
55
  fixTypography(p)
56
56
 
57
- expect(p.innerHTML).toEqual(
57
+ expect(p.innerHTML).to.deep.equal(
58
58
  'Pchnąć <span style="white-space:nowrap">w </span>tę łódź jeża lub ośm skrzyń fig ' +
59
59
  '(zob. https://\u200Bpl.\u200Bwikipedia.\u200Borg/\u200Bwiki/\u200BPangram).')
60
60
  }
package/h.d.ts CHANGED
@@ -47,9 +47,9 @@ export function s<N extends Node>(node: N, ...args1: HArgs1[]): N;
47
47
  export function s(tagOrNode: string | Node, ...args1: HArgs1[]): Node;
48
48
 
49
49
  export const tests: {
50
- h: (expect: import('bun:test').Expect) => void;
51
- 'h: innerText vs items': (expect: import('bun:test').Expect) => void;
52
- 'h: style': (expect: import('bun:test').Expect) => void;
53
- 'h: attributes vs properties': (expect: import('bun:test').Expect) => void;
54
- 'h: nested properties': (expect: import('bun:test').Expect) => void;
50
+ h: (expect: Chai.ExpectStatic) => void;
51
+ 'h: innerText vs items': (expect: Chai.ExpectStatic) => void;
52
+ 'h: style': (expect: Chai.ExpectStatic) => void;
53
+ 'h: attributes vs properties': (expect: Chai.ExpectStatic) => void;
54
+ 'h: nested properties': (expect: Chai.ExpectStatic) => void;
55
55
  };
package/h.js CHANGED
@@ -142,72 +142,72 @@ export const h = _h()
142
142
  export const s = _h('http://www.w3.org/2000/svg')
143
143
 
144
144
  export const tests = {
145
- h: (/** @type {import('bun:test').Expect} */ expect) => {
145
+ h: (/** @type {import('chai').expect} */ expect) => {
146
146
  const b = h('b')
147
147
 
148
- expect(b.outerHTML).toEqual('<b></b>')
148
+ expect(b.outerHTML).to.deep.equal('<b></b>')
149
149
 
150
150
  const i = h('i', 'text')
151
151
 
152
152
  h(b, i)
153
153
 
154
- expect(i.outerHTML).toEqual('<i>text</i>')
155
- expect(b.outerHTML).toEqual('<b><i>text</i></b>')
154
+ expect(i.outerHTML).to.deep.equal('<i>text</i>')
155
+ expect(b.outerHTML).to.deep.equal('<b><i>text</i></b>')
156
156
 
157
157
  h(i, { $className: 'some class' })
158
158
 
159
- expect(i.outerHTML).toEqual('<i class="some class">text</i>')
160
- expect(b.outerHTML).toEqual('<b><i class="some class">text</i></b>')
159
+ expect(i.outerHTML).to.deep.equal('<i class="some class">text</i>')
160
+ expect(b.outerHTML).to.deep.equal('<b><i class="some class">text</i></b>')
161
161
  },
162
162
 
163
- 'h: innerText vs items': (/** @type {import('bun:test').Expect} */ expect) => {
164
- expect(h('span', 'text').outerHTML).toEqual('<span>text</span>')
165
- expect(h('span', { $innerText: 'text' }).outerHTML).toEqual('<span>text</span>')
163
+ 'h: innerText vs items': (/** @type {import('chai').expect} */ expect) => {
164
+ expect(h('span', 'text').outerHTML).to.deep.equal('<span>text</span>')
165
+ expect(h('span', { $innerText: 'text' }).outerHTML).to.deep.equal('<span>text</span>')
166
166
  },
167
167
 
168
- 'h: style': (/** @type {import('bun:test').Expect} */ expect) => {
168
+ 'h: style': (/** @type {import('chai').expect} */ expect) => {
169
169
  expect(h('div', { style: 'margin:0;padding:0' }).outerHTML)
170
- .toEqual('<div style="margin:0;padding:0"></div>')
170
+ .to.deep.equal('<div style="margin:0;padding:0"></div>')
171
171
  expect(h('div', { $style: 'margin:0;padding:0' }).outerHTML)
172
- .toEqual('<div style="margin: 0px; padding: 0px;"></div>')
172
+ .to.deep.equal('<div style="margin: 0px; padding: 0px;"></div>')
173
173
  expect(h('div', { $style: { margin: 0, padding: 0 } }).outerHTML)
174
- .toEqual('<div style="margin: 0px; padding: 0px;"></div>')
174
+ .to.deep.equal('<div style="margin: 0px; padding: 0px;"></div>')
175
175
  },
176
176
 
177
- 'h: attributes vs properties': (/** @type {import('bun:test').Expect} */ expect) => {
177
+ 'h: attributes vs properties': (/** @type {import('chai').expect} */ expect) => {
178
178
  const input1 = h('input', { value: 42 })
179
179
  const input2 = h('input', { $value: '42' })
180
180
 
181
- expect(input1.value).toEqual('42')
182
- expect(input2.value).toEqual('42')
181
+ expect(input1.value).to.deep.equal('42')
182
+ expect(input2.value).to.deep.equal('42')
183
183
 
184
- expect(input1.outerHTML).toEqual('<input value="42">')
185
- expect(input2.outerHTML).toEqual('<input>')
184
+ expect(input1.outerHTML).to.deep.equal('<input value="42">')
185
+ expect(input2.outerHTML).to.deep.equal('<input>')
186
186
 
187
187
  const checkbox1 = h('input', { type: 'checkbox', checked: true })
188
188
  const checkbox2 = h('input', { type: 'checkbox', $checked: true })
189
189
 
190
- expect(checkbox1.checked).toBe(true)
191
- expect(checkbox2.checked).toBe(true)
190
+ expect(checkbox1.checked).to.be.true
191
+ expect(checkbox2.checked).to.be.true
192
192
 
193
- expect(checkbox1.outerHTML).toEqual('<input type="checkbox" checked="">')
194
- expect(checkbox2.outerHTML).toEqual('<input type="checkbox">')
193
+ expect(checkbox1.outerHTML).to.deep.equal('<input type="checkbox" checked="">')
194
+ expect(checkbox2.outerHTML).to.deep.equal('<input type="checkbox">')
195
195
  },
196
196
 
197
- 'h: nested properties': (/** @type {import('bun:test').Expect} */ expect) => {
197
+ 'h: nested properties': (/** @type {import('chai').expect} */ expect) => {
198
198
  const div = h('div')
199
199
 
200
200
  // @ts-expect-error
201
- expect(div.key).toBeUndefined()
201
+ expect(div.key).to.be.undefined
202
202
 
203
203
  h(div, { $key: { one: 1 } })
204
204
 
205
205
  // @ts-expect-error
206
- expect(div.key).toEqual({ one: 1 })
206
+ expect(div.key).to.deep.equal({ one: 1 })
207
207
 
208
208
  h(div, { $key: { two: 2 } })
209
209
 
210
210
  // @ts-expect-error
211
- expect(div.key).toEqual({ one: 1, two: 2 })
211
+ expect(div.key).to.deep.equal({ one: 1, two: 2 })
212
212
  }
213
213
  }
package/has.d.ts CHANGED
@@ -4,6 +4,6 @@
4
4
  export function has(key: any, ref: any): boolean;
5
5
 
6
6
  export const tests: {
7
- has: (expect: import('bun:test').Expect) => void;
8
- 'has: null': (expect: import('bun:test').Expect) => void;
7
+ has: (expect: Chai.ExpectStatic) => void;
8
+ 'has: null': (expect: Chai.ExpectStatic) => void;
9
9
  };
package/has.js CHANGED
@@ -7,24 +7,24 @@ export const has = (/** @type {any} */ key, /** @type {any} */ ref) =>
7
7
  (is(String, key) || is(Number, key) || is(Symbol, key)) && Object.hasOwnProperty.call(ref ?? Object, key)
8
8
 
9
9
  export const tests = {
10
- has: (/** @type {import('bun:test').Expect} */ expect) => {
10
+ has: (/** @type {import('chai').expect} */ expect) => {
11
11
  const obj = { key: 'K', null: 'N' }
12
12
 
13
- expect('key' in obj).toBe(true)
14
- expect(has('key', obj)).toBe(true)
13
+ expect('key' in obj).to.be.true
14
+ expect(has('key', obj)).to.be.true
15
15
 
16
- expect('null' in obj).toBe(true)
17
- expect(has('null', obj)).toBe(true)
16
+ expect('null' in obj).to.be.true
17
+ expect(has('null', obj)).to.be.true
18
18
 
19
19
  // @ts-expect-error
20
- expect(null in obj).toBe(true)
21
- expect(has(null, obj)).toBe(false)
20
+ expect(null in obj).to.be.true
21
+ expect(has(null, obj)).to.be.false
22
22
 
23
- expect('toString' in obj).toBe(true)
24
- expect(has('toString', obj)).toBe(false)
23
+ expect('toString' in obj).to.be.true
24
+ expect(has('toString', obj)).to.be.false
25
25
  },
26
26
 
27
- 'has: null': (/** @type {import('bun:test').Expect} */ expect) => {
27
+ 'has: null': (/** @type {import('chai').expect} */ expect) => {
28
28
  let typeError
29
29
 
30
30
  try {
@@ -35,6 +35,6 @@ export const tests = {
35
35
  }
36
36
 
37
37
  expect(typeError instanceof TypeError) // Cannot use 'in' operator to search for 'key' in null
38
- expect(has('key', null)).toBe(false)
38
+ expect(has('key', null)).to.be.false
39
39
  }
40
40
  }
package/is.d.ts CHANGED
@@ -12,6 +12,6 @@ export const is: {
12
12
  };
13
13
 
14
14
  export const tests: {
15
- is: (expect: import('bun:test').Expect) => void;
16
- 'is: toString.call': (expect: import('bun:test').Expect) => void;
15
+ is: (expect: Chai.ExpectStatic) => void;
16
+ 'is: toString.call': (expect: Chai.ExpectStatic) => void;
17
17
  };