@jackens/nnn 2024.2.15 → 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 +21 -23
- package/chartable.js +143 -80
- package/eq.d.ts +1 -1
- package/eq.js +24 -24
- package/escape.d.ts +1 -1
- package/escape.js +2 -2
- package/fixTypography.d.ts +1 -1
- package/fixTypography.js +2 -2
- package/h.d.ts +5 -5
- package/h.js +26 -26
- package/has.d.ts +2 -2
- package/has.js +11 -11
- package/is.d.ts +2 -2
- package/is.js +27 -27
- package/jcss.d.ts +6 -6
- package/jcss.js +12 -12
- package/jsOnParse.d.ts +1 -1
- package/jsOnParse.js +2 -2
- package/locale.d.ts +1 -1
- package/locale.js +9 -9
- package/nanolightJs.d.ts +1 -1
- package/nanolightJs.js +2 -2
- package/package.json +1 -1
- package/pick.d.ts +2 -2
- package/pick.js +4 -4
- package/plUral.d.ts +1 -1
- package/plUral.js +9 -9
- package/pro.d.ts +1 -1
- package/pro.js +7 -7
- package/readme.md +146 -148
- package/refsInfo.d.ts +2 -2
- package/refsInfo.js +4 -4
- package/uuid1.d.ts +3 -3
- package/uuid1.js +13 -13
package/chartable.d.ts
CHANGED
|
@@ -2,32 +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
|
-
* - `id`: chart id
|
|
10
|
-
* - `left`: left padding
|
|
11
|
-
* - `maxY`: number of Y axis lines
|
|
12
|
-
* - `reverse`: flag to reverse all data series
|
|
13
|
-
* - `right`: right padding (for data series labels)
|
|
14
|
-
* - `rotate`: flag to rotate X axis labels
|
|
15
5
|
* - `table`: `HTMLTableElement` to extract data, data series labels and X axis labels
|
|
16
|
-
* - `
|
|
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`:
|
|
17
16
|
*/
|
|
18
|
-
export function chartable({
|
|
19
|
-
bottom?: number;
|
|
20
|
-
gapX?: number;
|
|
21
|
-
gapY?: number;
|
|
22
|
-
headerColumn?: boolean;
|
|
23
|
-
id?: string;
|
|
24
|
-
left?: number;
|
|
25
|
-
maxY?: number;
|
|
26
|
-
reverse?: boolean;
|
|
27
|
-
right?: number;
|
|
28
|
-
rotate?: boolean;
|
|
17
|
+
export function chartable({ table, headerColumn, xGap, xLabelsPx, xLabelsRotate, xReverse, yGap, yLabelsLeftPx, yLabelsRightPx, yMax, zLabelsPx }: {
|
|
29
18
|
table: HTMLTableElement;
|
|
30
|
-
|
|
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;
|
|
31
29
|
}): SVGSVGElement;
|
|
32
30
|
|
|
33
31
|
export const tests: {};
|
package/chartable.js
CHANGED
|
@@ -1,54 +1,56 @@
|
|
|
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
|
+
const PADDING = 15
|
|
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])
|
|
4
9
|
|
|
5
10
|
/**
|
|
6
11
|
* A helper for creating a chart based on a table (conf. <https://jackens.github.io/nnn/chartable/>).
|
|
7
12
|
*
|
|
8
13
|
* Options:
|
|
9
|
-
* - `bottom`: bottom padding (for X axis labels)
|
|
10
|
-
* - `gapX`: X axis spacing
|
|
11
|
-
* - `gapY`: Y axis spacing
|
|
12
|
-
* - `headerColumn`: flag indicating that `table` has a header column (with X axis labels)
|
|
13
|
-
* - `id`: chart id
|
|
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
|
-
* - `
|
|
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
|
-
* id?: string;
|
|
28
|
-
* left?: number;
|
|
29
|
-
* maxY?: number;
|
|
30
|
-
* reverse?: boolean;
|
|
31
|
-
* right?: number;
|
|
32
|
-
* rotate?: boolean;
|
|
33
27
|
* table: HTMLTableElement;
|
|
34
|
-
*
|
|
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;
|
|
35
38
|
* }} options
|
|
36
39
|
*/
|
|
37
40
|
export const chartable = ({
|
|
38
|
-
bottom = 50,
|
|
39
|
-
gapX = 70,
|
|
40
|
-
gapY = 30,
|
|
41
|
-
headerColumn = false,
|
|
42
|
-
id,
|
|
43
|
-
left = 15,
|
|
44
|
-
maxY = 10,
|
|
45
|
-
reverse = false,
|
|
46
|
-
right = 200,
|
|
47
|
-
rotate = false,
|
|
48
41
|
table,
|
|
49
|
-
|
|
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
|
|
50
52
|
}) => {
|
|
51
|
-
const /** @type {number[][]} */
|
|
53
|
+
const /** @type {number[][]} */ zxValues = []
|
|
52
54
|
const /** @type {string[]} */ xLabels = []
|
|
53
55
|
const /** @type {string[]} */ zLabels = []
|
|
54
56
|
|
|
@@ -60,8 +62,8 @@ export const chartable = ({
|
|
|
60
62
|
const value = col.innerText
|
|
61
63
|
|
|
62
64
|
if (x >= 0 && z >= 0) {
|
|
63
|
-
|
|
64
|
-
|
|
65
|
+
zxValues[z] = zxValues[z] ?? []
|
|
66
|
+
zxValues[z][x] = parseFloat(value)
|
|
65
67
|
} else if (x >= 0 && z < 0) {
|
|
66
68
|
xLabels[x] = value
|
|
67
69
|
} else if (x < 0 && z >= 0) {
|
|
@@ -69,62 +71,123 @@ export const chartable = ({
|
|
|
69
71
|
}
|
|
70
72
|
}))
|
|
71
73
|
|
|
72
|
-
if (
|
|
74
|
+
if (xReverse) {
|
|
73
75
|
xLabels.reverse()
|
|
74
|
-
|
|
76
|
+
zxValues.forEach(xValues => xValues.reverse())
|
|
77
|
+
}
|
|
78
|
+
|
|
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
|
+
|
|
83
|
+
const width = xGap * (xMax - 1)
|
|
84
|
+
const height = yGap * (yMax - 1)
|
|
85
|
+
|
|
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' } }))
|
|
75
99
|
}
|
|
76
100
|
|
|
77
|
-
|
|
78
|
-
const xi = Array.from({ length: maxX }, (_, x) => x * gapX)
|
|
79
|
-
const yi = Array.from({ length: maxY }, (_, y) => y * gapY)
|
|
80
|
-
const w = gapX * (maxX - 1)
|
|
81
|
-
const h = gapY * (maxY - 1)
|
|
82
|
-
const svgW = left + w + right
|
|
83
|
-
const svgH = top + h + bottom
|
|
84
|
-
const /** @type {import('./h.js').HArgs1} */ graph = ['g', { transform: `translate(${left} ${top})` },
|
|
85
|
-
...yi.map(y => ['line', { x1: 0, x2: w, y1: y, y2: y, stroke: '#8888' }]),
|
|
86
|
-
...xi.map(x => ['line', { x1: x, x2: x, y1: 0, y2: h, stroke: '#8888' }])]
|
|
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})` }]
|
|
89
|
-
|
|
90
|
-
zxY.forEach((xY, z) => {
|
|
101
|
+
zxValues.forEach((values, z) => {
|
|
91
102
|
const fill = COLORS[z % COLORS.length]
|
|
92
|
-
const
|
|
93
|
-
const
|
|
103
|
+
const minValue = Math.min(...values.filter(value => !isNaN(value)))
|
|
104
|
+
const maxValue = Math.max(...values.filter(value => !isNaN(value)))
|
|
105
|
+
|
|
106
|
+
yPx.forEach((yp, y) => {
|
|
107
|
+
const textL = s('text',
|
|
108
|
+
{ x: 0, y: yp, 'text-anchor': 'end', 'alignment-baseline': 'middle' },
|
|
109
|
+
(maxValue - (maxValue - minValue) / yMax * (y + 1)).toFixed(2))
|
|
110
|
+
const textR = s('text',
|
|
111
|
+
{ x: 0, y: yp, 'text-anchor': 'start', 'alignment-baseline': 'middle' },
|
|
112
|
+
(maxValue - (maxValue - minValue) / yMax * (y + 1)).toFixed(2))
|
|
113
|
+
|
|
114
|
+
s(_svg, textL, textR)
|
|
115
|
+
|
|
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
|
+
})
|
|
94
122
|
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
123
|
+
const text = s('text', {
|
|
124
|
+
x: 0,
|
|
125
|
+
y: yGap * z,
|
|
126
|
+
'text-anchor': 'start',
|
|
127
|
+
'alignment-baseline': 'middle',
|
|
128
|
+
$onclick: () => onclick(z),
|
|
129
|
+
$style: { fontWeight: 'bold' }
|
|
130
|
+
},
|
|
131
|
+
zLabels[z])
|
|
99
132
|
|
|
100
|
-
|
|
133
|
+
s(_svg, text)
|
|
101
134
|
|
|
102
|
-
|
|
103
|
-
if (!isNaN(y[i])) {
|
|
104
|
-
graph.push(['g', ['circle', { cx: x, cy: y[i], r: 5, fill }, ['title', `${zLabels[z]}: ${xY[i]}`]]])
|
|
135
|
+
zLabelsPx = Math.max(zLabelsPx, text.getBBox().width)
|
|
105
136
|
|
|
106
|
-
|
|
107
|
-
|
|
137
|
+
gZLabels[z] = text
|
|
138
|
+
|
|
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))
|
|
142
|
+
|
|
143
|
+
xPx.forEach((px, x) => {
|
|
144
|
+
if (!isNaN(valuesPx[x])) {
|
|
145
|
+
s(gGraph, ['g', ['circle', { cx: px, cy: valuesPx[x], r: 5, fill }]])
|
|
146
|
+
|
|
147
|
+
if (!isNaN(valuesPx[x - 1])) {
|
|
148
|
+
s(gGraph, ['line', { x1: px, x2: xPx[x - 1], y1: valuesPx[x], y2: valuesPx[x - 1], stroke: fill }])
|
|
108
149
|
}
|
|
109
150
|
}
|
|
110
151
|
})
|
|
111
152
|
})
|
|
112
153
|
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
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
|
+
|
|
181
|
+
onclick(0)
|
|
182
|
+
|
|
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])
|
|
128
191
|
}
|
|
129
192
|
|
|
130
193
|
export const tests = {}
|
package/eq.d.ts
CHANGED
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('
|
|
49
|
-
expect(eq(true, true)).
|
|
50
|
-
expect(eq(NaN, NaN)).
|
|
51
|
-
expect(eq(null, undefined)).
|
|
52
|
-
expect(eq(42, 42)).
|
|
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))).
|
|
55
|
-
expect(eq(42, Number(42))).
|
|
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))).
|
|
58
|
-
expect(eq(42, '42')).
|
|
59
|
-
expect(eq('42', '42')).
|
|
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'))).
|
|
62
|
-
expect(eq('42', String('42'))).
|
|
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'))).
|
|
65
|
-
expect(eq(/42/, /42/)).
|
|
66
|
-
expect(eq(/42/, /42/g)).
|
|
67
|
-
expect(eq(new Date(42), new Date(42))).
|
|
68
|
-
expect(eq(new Date(), new Date(42))).
|
|
69
|
-
expect(eq({ j: '42', c: 42 }, { c: 42, j: '42' })).
|
|
70
|
-
expect(eq([42, '42'], [42, '42'])).
|
|
71
|
-
expect(eq(new Set(['42', 42]), new Set([42, '42']))).
|
|
72
|
-
expect(eq(new Set(['42', 42]), new Set([42]))).
|
|
73
|
-
expect(eq(new Set([42, undefined]), new Set([42]))).
|
|
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
|
-
)).
|
|
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
|
-
)).
|
|
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:
|
|
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('
|
|
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).
|
|
49
|
+
expect(actual).to.deep.equal(expected)
|
|
50
50
|
}
|
|
51
51
|
}
|
package/fixTypography.d.ts
CHANGED
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('
|
|
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).
|
|
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:
|
|
51
|
-
'h: innerText vs items': (expect:
|
|
52
|
-
'h: style': (expect:
|
|
53
|
-
'h: attributes vs properties': (expect:
|
|
54
|
-
'h: nested properties': (expect:
|
|
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('
|
|
145
|
+
h: (/** @type {import('chai').expect} */ expect) => {
|
|
146
146
|
const b = h('b')
|
|
147
147
|
|
|
148
|
-
expect(b.outerHTML).
|
|
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).
|
|
155
|
-
expect(b.outerHTML).
|
|
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).
|
|
160
|
-
expect(b.outerHTML).
|
|
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('
|
|
164
|
-
expect(h('span', 'text').outerHTML).
|
|
165
|
-
expect(h('span', { $innerText: 'text' }).outerHTML).
|
|
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('
|
|
168
|
+
'h: style': (/** @type {import('chai').expect} */ expect) => {
|
|
169
169
|
expect(h('div', { style: 'margin:0;padding:0' }).outerHTML)
|
|
170
|
-
.
|
|
170
|
+
.to.deep.equal('<div style="margin:0;padding:0"></div>')
|
|
171
171
|
expect(h('div', { $style: 'margin:0;padding:0' }).outerHTML)
|
|
172
|
-
.
|
|
172
|
+
.to.deep.equal('<div style="margin: 0px; padding: 0px;"></div>')
|
|
173
173
|
expect(h('div', { $style: { margin: 0, padding: 0 } }).outerHTML)
|
|
174
|
-
.
|
|
174
|
+
.to.deep.equal('<div style="margin: 0px; padding: 0px;"></div>')
|
|
175
175
|
},
|
|
176
176
|
|
|
177
|
-
'h: attributes vs properties': (/** @type {import('
|
|
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).
|
|
182
|
-
expect(input2.value).
|
|
181
|
+
expect(input1.value).to.deep.equal('42')
|
|
182
|
+
expect(input2.value).to.deep.equal('42')
|
|
183
183
|
|
|
184
|
-
expect(input1.outerHTML).
|
|
185
|
-
expect(input2.outerHTML).
|
|
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).
|
|
191
|
-
expect(checkbox2.checked).
|
|
190
|
+
expect(checkbox1.checked).to.be.true
|
|
191
|
+
expect(checkbox2.checked).to.be.true
|
|
192
192
|
|
|
193
|
-
expect(checkbox1.outerHTML).
|
|
194
|
-
expect(checkbox2.outerHTML).
|
|
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('
|
|
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).
|
|
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).
|
|
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).
|
|
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:
|
|
8
|
-
'has: null': (expect:
|
|
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('
|
|
10
|
+
has: (/** @type {import('chai').expect} */ expect) => {
|
|
11
11
|
const obj = { key: 'K', null: 'N' }
|
|
12
12
|
|
|
13
|
-
expect('key' in obj).
|
|
14
|
-
expect(has('key', obj)).
|
|
13
|
+
expect('key' in obj).to.be.true
|
|
14
|
+
expect(has('key', obj)).to.be.true
|
|
15
15
|
|
|
16
|
-
expect('null' in obj).
|
|
17
|
-
expect(has('null', obj)).
|
|
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).
|
|
21
|
-
expect(has(null, obj)).
|
|
20
|
+
expect(null in obj).to.be.true
|
|
21
|
+
expect(has(null, obj)).to.be.false
|
|
22
22
|
|
|
23
|
-
expect('toString' in obj).
|
|
24
|
-
expect(has('toString', obj)).
|
|
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('
|
|
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)).
|
|
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:
|
|
16
|
-
'is: toString.call': (expect:
|
|
15
|
+
is: (expect: Chai.ExpectStatic) => void;
|
|
16
|
+
'is: toString.call': (expect: Chai.ExpectStatic) => void;
|
|
17
17
|
};
|