@jackens/nnn 2024.2.20 → 2024.2.24
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/nnn.d.ts +220 -21
- package/nnn.js +419 -37
- package/package.json +1 -1
- package/readme.md +177 -172
- package/chartable.d.ts +0 -33
- package/chartable.js +0 -195
- package/eq.d.ts +0 -8
- package/eq.js +0 -83
- package/escape.d.ts +0 -18
- package/escape.js +0 -51
- package/fixTypography.d.ts +0 -8
- package/fixTypography.js +0 -61
- package/h.d.ts +0 -55
- package/h.js +0 -213
- package/has.d.ts +0 -9
- package/has.js +0 -40
- package/is.d.ts +0 -17
- package/is.js +0 -65
- package/jcss.d.ts +0 -33
- package/jcss.js +0 -293
- package/jsOnParse.d.ts +0 -20
- package/jsOnParse.js +0 -85
- package/locale.d.ts +0 -8
- package/locale.js +0 -39
- package/nanolight.d.ts +0 -6
- package/nanolight.js +0 -21
- package/nanolightJs.d.ts +0 -8
- package/nanolightJs.js +0 -29
- package/pick.d.ts +0 -14
- package/pick.js +0 -31
- package/plUral.d.ts +0 -8
- package/plUral.js +0 -39
- package/pro.d.ts +0 -8
- package/pro.js +0 -39
- package/refsInfo.d.ts +0 -11
- package/refsInfo.js +0 -57
- package/uuid1.d.ts +0 -16
- package/uuid1.js +0 -54
package/chartable.d.ts
DELETED
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* A helper for creating a chart based on a table (conf. <https://jackens.github.io/nnn/chartable/>).
|
|
3
|
-
*
|
|
4
|
-
* Options:
|
|
5
|
-
* - `table`: `HTMLTableElement` to extract data, data series labels and X axis labels
|
|
6
|
-
* - `headerColumn`: flag indicating that `table` has a header column with X axis labels
|
|
7
|
-
* - `xGap`: X axis spacing
|
|
8
|
-
* - `xLabelsMinHeight`: minimal height of X axis labels
|
|
9
|
-
* - `xLabelsRotate`: flag to rotate X axis labels
|
|
10
|
-
* - `xReverse`: flag to reverse all data series
|
|
11
|
-
* - `yGap`: Y axis spacing
|
|
12
|
-
* - `yLabelsLeftMinWidth`: minimal width of Y axis left labels
|
|
13
|
-
* - `yLabelsRightMinWidth`: minimal width of Y axis right labels
|
|
14
|
-
* - `yMax`: number of Y axis lines
|
|
15
|
-
* - `zLabelsMinWidth`: minimal width of data series labels
|
|
16
|
-
* - `zyMappings`: mappings per data series
|
|
17
|
-
*/
|
|
18
|
-
export function chartable({ table, headerColumn, xGap, xLabelsMinHeight, xLabelsRotate, xReverse, yGap, yLabelsLeftMinWidth, yLabelsRightMinWidth, yMax, zLabelsMinWidth, zyMappings }: {
|
|
19
|
-
table: HTMLTableElement;
|
|
20
|
-
headerColumn?: boolean | undefined;
|
|
21
|
-
xGap?: number | undefined;
|
|
22
|
-
xLabelsMinHeight?: number | undefined;
|
|
23
|
-
xLabelsRotate?: boolean | undefined;
|
|
24
|
-
xReverse?: boolean | undefined;
|
|
25
|
-
yGap?: number | undefined;
|
|
26
|
-
yLabelsLeftMinWidth?: number | undefined;
|
|
27
|
-
yLabelsRightMinWidth?: number | undefined;
|
|
28
|
-
yMax?: number | undefined;
|
|
29
|
-
zLabelsMinWidth?: number | undefined;
|
|
30
|
-
zyMappings?: [(label: string) => number, (value: number) => string][] | undefined;
|
|
31
|
-
}): SVGSVGElement;
|
|
32
|
-
|
|
33
|
-
export const tests: {};
|
package/chartable.js
DELETED
|
@@ -1,195 +0,0 @@
|
|
|
1
|
-
import { h, s } from './h.js'
|
|
2
|
-
|
|
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])
|
|
9
|
-
|
|
10
|
-
const toFixed2 = (/** @type {number} */ value) => value.toFixed(2)
|
|
11
|
-
|
|
12
|
-
/**
|
|
13
|
-
* A helper for creating a chart based on a table (conf. <https://jackens.github.io/nnn/chartable/>).
|
|
14
|
-
*
|
|
15
|
-
* Options:
|
|
16
|
-
* - `table`: `HTMLTableElement` to extract data, data series labels and X axis labels
|
|
17
|
-
* - `headerColumn`: flag indicating that `table` has a header column with X axis labels
|
|
18
|
-
* - `xGap`: X axis spacing
|
|
19
|
-
* - `xLabelsMinHeight`: minimal height of X axis labels
|
|
20
|
-
* - `xLabelsRotate`: flag to rotate X axis labels
|
|
21
|
-
* - `xReverse`: flag to reverse all data series
|
|
22
|
-
* - `yGap`: Y axis spacing
|
|
23
|
-
* - `yLabelsLeftMinWidth`: minimal width of Y axis left labels
|
|
24
|
-
* - `yLabelsRightMinWidth`: minimal width of Y axis right labels
|
|
25
|
-
* - `yMax`: number of Y axis lines
|
|
26
|
-
* - `zLabelsMinWidth`: minimal width of data series labels
|
|
27
|
-
* - `zyMappings`: mappings per data series
|
|
28
|
-
*
|
|
29
|
-
* @param {{
|
|
30
|
-
* table: HTMLTableElement;
|
|
31
|
-
* headerColumn?: boolean;
|
|
32
|
-
* xGap?: number;
|
|
33
|
-
* xLabelsMinHeight?: number;
|
|
34
|
-
* xLabelsRotate?: boolean;
|
|
35
|
-
* xReverse?: boolean;
|
|
36
|
-
* yGap?: number;
|
|
37
|
-
* yLabelsLeftMinWidth?: number;
|
|
38
|
-
* yLabelsRightMinWidth?: number;
|
|
39
|
-
* yMax?: number;
|
|
40
|
-
* zLabelsMinWidth?: number;
|
|
41
|
-
* zyMappings?: [(label: string) => number, (value: number) => string][];
|
|
42
|
-
* }} options
|
|
43
|
-
*/
|
|
44
|
-
export const chartable = ({
|
|
45
|
-
table,
|
|
46
|
-
headerColumn = false,
|
|
47
|
-
xGap = 70,
|
|
48
|
-
xLabelsMinHeight = 0,
|
|
49
|
-
xLabelsRotate = false,
|
|
50
|
-
xReverse = false,
|
|
51
|
-
yGap = 30,
|
|
52
|
-
yLabelsLeftMinWidth = 100,
|
|
53
|
-
yLabelsRightMinWidth = 100,
|
|
54
|
-
yMax = 10,
|
|
55
|
-
zLabelsMinWidth = 0,
|
|
56
|
-
zyMappings = []
|
|
57
|
-
}) => {
|
|
58
|
-
const /** @type {number[][]} */ zxValues = []
|
|
59
|
-
const /** @type {string[]} */ xLabels = []
|
|
60
|
-
const /** @type {string[]} */ zLabels = []
|
|
61
|
-
|
|
62
|
-
table.querySelectorAll('tr').forEach((row, r) =>
|
|
63
|
-
// @ts-expect-error
|
|
64
|
-
row.querySelectorAll('td,th').forEach((/** @type {HTMLTableCellElement} */ col, c) => {
|
|
65
|
-
const x = r - 1
|
|
66
|
-
const z = c - +headerColumn
|
|
67
|
-
const value = col.innerText
|
|
68
|
-
|
|
69
|
-
if (x >= 0 && z >= 0) {
|
|
70
|
-
zxValues[z] = zxValues[z] ?? []
|
|
71
|
-
zxValues[z][x] = (zyMappings?.[z]?.[0] ?? parseFloat)(value)
|
|
72
|
-
} else if (x >= 0 && z < 0) {
|
|
73
|
-
xLabels[x] = value
|
|
74
|
-
} else if (x < 0 && z >= 0) {
|
|
75
|
-
zLabels[z] = value
|
|
76
|
-
}
|
|
77
|
-
}))
|
|
78
|
-
|
|
79
|
-
if (xReverse) {
|
|
80
|
-
xLabels.reverse()
|
|
81
|
-
zxValues.forEach(xValues => xValues.reverse())
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
const xMax = zxValues[0].length
|
|
85
|
-
const xPx = Array.from({ length: xMax }, (_, x) => x * xGap)
|
|
86
|
-
const yPx = Array.from({ length: yMax }, (_, y) => y * yGap)
|
|
87
|
-
|
|
88
|
-
const width = xGap * (xMax - 1)
|
|
89
|
-
const height = yGap * (yMax - 1)
|
|
90
|
-
|
|
91
|
-
const gGraph = s('g',
|
|
92
|
-
...yPx.map(px => ['line', { x1: 0, x2: width, y1: px, y2: px, stroke: '#8888' }]),
|
|
93
|
-
...xPx.map(px => ['line', { x1: px, x2: px, y1: 0, y2: height, stroke: '#8888' }]))
|
|
94
|
-
const gXLabels = s('g')
|
|
95
|
-
const gYLabelsL = zxValues.map(_ => s('g'))
|
|
96
|
-
const gYLabelsR = zxValues.map(_ => s('g'))
|
|
97
|
-
const gZColors = s('g')
|
|
98
|
-
const /** @type {SVGTextElement[]} */ gZLabels = []
|
|
99
|
-
|
|
100
|
-
const onclick = (/** @type {number} */ z) => {
|
|
101
|
-
gYLabelsL.forEach((g, z2) => s(g, { $style: { display: z2 === z ? 'block' : 'none' } }))
|
|
102
|
-
gYLabelsR.forEach((g, z2) => s(g, { $style: { display: z2 === z ? 'block' : 'none' } }))
|
|
103
|
-
gZLabels.forEach((text, z2) => s(text, { $style: { fontWeight: z2 === z ? 'bold' : 'normal', cursor: 'pointer' } }))
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
zxValues.forEach((values, z) => {
|
|
107
|
-
const fill = COLORS[z % COLORS.length]
|
|
108
|
-
const minValue = Math.min(...values.filter(value => !isNaN(value)))
|
|
109
|
-
const maxValue = Math.max(...values.filter(value => !isNaN(value)))
|
|
110
|
-
|
|
111
|
-
yPx.forEach((yp, y) => {
|
|
112
|
-
const value = (zyMappings?.[z]?.[1] ?? toFixed2)(maxValue - (maxValue - minValue) / yMax * (y + 1))
|
|
113
|
-
const textL = s('text', { x: 0, y: yp, 'text-anchor': 'end', 'alignment-baseline': 'middle' }, value)
|
|
114
|
-
const textR = s('text', { x: 0, y: yp, 'text-anchor': 'start', 'alignment-baseline': 'middle' }, value)
|
|
115
|
-
|
|
116
|
-
s(_svg, textL, textR)
|
|
117
|
-
|
|
118
|
-
yLabelsLeftMinWidth = Math.max(yLabelsLeftMinWidth, textL.getBBox().width)
|
|
119
|
-
yLabelsRightMinWidth = Math.max(yLabelsRightMinWidth, textR.getBBox().width)
|
|
120
|
-
|
|
121
|
-
s(gYLabelsL[z], textL)
|
|
122
|
-
s(gYLabelsR[z], textR)
|
|
123
|
-
})
|
|
124
|
-
|
|
125
|
-
const text = s('text', {
|
|
126
|
-
x: 0,
|
|
127
|
-
y: yGap * z,
|
|
128
|
-
'text-anchor': 'start',
|
|
129
|
-
'alignment-baseline': 'middle',
|
|
130
|
-
$onclick: () => onclick(z),
|
|
131
|
-
$style: { fontWeight: 'bold' }
|
|
132
|
-
},
|
|
133
|
-
zLabels[z])
|
|
134
|
-
|
|
135
|
-
s(_svg, text)
|
|
136
|
-
|
|
137
|
-
zLabelsMinWidth = Math.max(zLabelsMinWidth, text.getBBox().width)
|
|
138
|
-
|
|
139
|
-
gZLabels[z] = text
|
|
140
|
-
|
|
141
|
-
s(gZColors, ['circle', { cx: 0, cy: yGap * z, r: 5, fill }])
|
|
142
|
-
|
|
143
|
-
const valuesPx = values.map(value => isNaN(value) ? value : height * (maxValue - value) / (maxValue - minValue))
|
|
144
|
-
|
|
145
|
-
xPx.forEach((px, x) => {
|
|
146
|
-
if (!isNaN(valuesPx[x])) {
|
|
147
|
-
s(gGraph, ['g', ['circle', { cx: px, cy: valuesPx[x], r: 5, fill }]])
|
|
148
|
-
|
|
149
|
-
if (!isNaN(valuesPx[x - 1])) {
|
|
150
|
-
s(gGraph, ['line', { x1: px, x2: xPx[x - 1], y1: valuesPx[x], y2: valuesPx[x - 1], stroke: fill }])
|
|
151
|
-
}
|
|
152
|
-
}
|
|
153
|
-
})
|
|
154
|
-
})
|
|
155
|
-
|
|
156
|
-
if (xLabels.length > 0) {
|
|
157
|
-
xPx.forEach((xp, x) => {
|
|
158
|
-
const text = s('text',
|
|
159
|
-
xLabelsRotate
|
|
160
|
-
? { x: 0, y: -xp, 'text-anchor': 'start', 'alignment-baseline': 'middle', transform: 'rotate(90)' }
|
|
161
|
-
: { x: xp, y: PADDING, 'text-anchor': 'middle', 'alignment-baseline': 'middle' },
|
|
162
|
-
xLabels[x])
|
|
163
|
-
|
|
164
|
-
s(_svg, text)
|
|
165
|
-
|
|
166
|
-
xLabelsMinHeight = Math.max(xLabelsMinHeight, xLabelsRotate ? text.getBBox().width : text.getBBox().height)
|
|
167
|
-
|
|
168
|
-
s(gXLabels, text)
|
|
169
|
-
})
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
const svgW = width + yLabelsLeftMinWidth + yLabelsRightMinWidth + zLabelsMinWidth + 4 * PADDING
|
|
173
|
-
const svgH = height + xLabelsMinHeight + (xLabels.length > 0 ? 3 : 2) * PADDING
|
|
174
|
-
|
|
175
|
-
s(gGraph, { transform: `translate(${yLabelsLeftMinWidth + PADDING} ${PADDING})` })
|
|
176
|
-
|
|
177
|
-
gYLabelsL.forEach(g => s(g, { transform: `translate(${yLabelsLeftMinWidth} ${PADDING})` }))
|
|
178
|
-
gYLabelsR.forEach(g => s(g, { transform: `translate(${width + yLabelsLeftMinWidth + 2 * PADDING} ${PADDING})` }))
|
|
179
|
-
|
|
180
|
-
s(gZColors, { transform: `translate(${width + yLabelsLeftMinWidth + yLabelsRightMinWidth + 3 * PADDING} ${PADDING})` })
|
|
181
|
-
s(gXLabels, { transform: `translate(${yLabelsLeftMinWidth + PADDING} ${height + 2 * PADDING})` })
|
|
182
|
-
|
|
183
|
-
onclick(0)
|
|
184
|
-
|
|
185
|
-
return s('svg',
|
|
186
|
-
{ viewBox: `0 0 ${svgW} ${svgH}`, width: `${svgW}px`, height: `${svgH}px`, class: 'chartable' },
|
|
187
|
-
gGraph,
|
|
188
|
-
gXLabels,
|
|
189
|
-
...gYLabelsL,
|
|
190
|
-
...gYLabelsR,
|
|
191
|
-
gZColors,
|
|
192
|
-
['g', { transform: `translate(${width + yLabelsLeftMinWidth + yLabelsRightMinWidth + 4 * PADDING} ${PADDING})` }, ...gZLabels])
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
export const tests = {}
|
package/eq.d.ts
DELETED
package/eq.js
DELETED
|
@@ -1,83 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* A helper that checks equality of the given arguments.
|
|
3
|
-
*/
|
|
4
|
-
export const eq = /** @return {boolean} */ (/** @type {any} */ x, /** @type {any} */ y) => {
|
|
5
|
-
if (x === y) {
|
|
6
|
-
return true
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
const xConstructor = x?.constructor
|
|
10
|
-
|
|
11
|
-
if (xConstructor === y?.constructor) {
|
|
12
|
-
if (xConstructor === Number) {
|
|
13
|
-
return (isNaN(x) && isNaN(y)) || +x === +y
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
if (xConstructor === Date) {
|
|
17
|
-
return +x === +y
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
if (xConstructor === String || xConstructor === RegExp) {
|
|
21
|
-
return '' + x === '' + y
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
if (xConstructor === Array) {
|
|
25
|
-
return x.length === y.length &&
|
|
26
|
-
x.every((/** @type {any} */ item, /** @type {number} */ index) => eq(item, y[index]))
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
if (xConstructor === Object) {
|
|
30
|
-
const keysOfX = Object.keys(x)
|
|
31
|
-
return keysOfX.length === Object.keys(y).length && keysOfX.every(key => eq(x[key], y[key]))
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
if (xConstructor === Set || xConstructor === Map) {
|
|
35
|
-
if (x.size !== y.size) {
|
|
36
|
-
return false
|
|
37
|
-
}
|
|
38
|
-
const xa = [...x]
|
|
39
|
-
const ya = [...y]
|
|
40
|
-
return xa.every(xv => ya.find(yv => eq(xv, yv)))
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
return false
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
export const tests = {
|
|
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
|
-
// eslint-disable-next-line no-new-wrappers
|
|
54
|
-
expect(eq(42, new Number(42))).to.be.true
|
|
55
|
-
expect(eq(42, Number(42))).to.be.true
|
|
56
|
-
// eslint-disable-next-line no-new-wrappers
|
|
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
|
-
// eslint-disable-next-line no-new-wrappers
|
|
61
|
-
expect(eq('42', new String('42'))).to.be.true
|
|
62
|
-
expect(eq('42', String('42'))).to.be.true
|
|
63
|
-
// eslint-disable-next-line no-new-wrappers
|
|
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
|
-
expect(eq(
|
|
75
|
-
new Map([[{ j: 42 }, { J: '42' }], [{ c: 42 }, { C: '42' }]]),
|
|
76
|
-
new Map([[{ c: 42 }, { C: '42' }], [{ j: 42 }, { J: '42' }]])
|
|
77
|
-
)).to.be.true
|
|
78
|
-
expect(eq(
|
|
79
|
-
new Map([[{ j: 42 }, { J: '42' }], [{ c: 42 }, { C: '42' }]]),
|
|
80
|
-
new Map([[{ j: '42' }, { J: 42 }], [{ c: '42' }, { C: 42 }]])
|
|
81
|
-
)).to.be.false
|
|
82
|
-
}
|
|
83
|
-
}
|
package/escape.d.ts
DELETED
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* The type of arguments of the `escapeValues` and `escape` helpers.
|
|
3
|
-
*/
|
|
4
|
-
export type EscapeMap = Map<any, (value?: any) => string>;
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* A generic helper for escaping `values` by given `escapeMap` (in *TemplateStrings* flavor).
|
|
8
|
-
*/
|
|
9
|
-
export function escape(escapeMap: EscapeMap, template: TemplateStringsArray, ...values: any[]): string;
|
|
10
|
-
|
|
11
|
-
/**
|
|
12
|
-
* A generic helper for escaping `values` by given `escapeMap`.
|
|
13
|
-
*/
|
|
14
|
-
export function escapeValues(escapeMap: EscapeMap, values: any[]): string[];
|
|
15
|
-
|
|
16
|
-
export namespace tests {
|
|
17
|
-
function escape(expect: Chai.ExpectStatic): void;
|
|
18
|
-
}
|
package/escape.js
DELETED
|
@@ -1,51 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* The type of arguments of the `escapeValues` and `escape` helpers.
|
|
3
|
-
*
|
|
4
|
-
* @typedef {Map<any, (value?: any) => string>} EscapeMap
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
* A generic helper for escaping `values` by given `escapeMap`.
|
|
9
|
-
*/
|
|
10
|
-
export const escapeValues = (
|
|
11
|
-
/** @type {EscapeMap} */ escapeMap,
|
|
12
|
-
/** @type {any[]} */ values
|
|
13
|
-
) => values.map(value => (escapeMap.get(value?.constructor) ?? escapeMap.get(undefined))?.(value) ?? '')
|
|
14
|
-
|
|
15
|
-
/**
|
|
16
|
-
* A generic helper for escaping `values` by given `escapeMap` (in *TemplateStrings* flavor).
|
|
17
|
-
*/
|
|
18
|
-
export const escape = (
|
|
19
|
-
/** @type {EscapeMap} */ escapeMap,
|
|
20
|
-
/** @type {TemplateStringsArray} */ template,
|
|
21
|
-
/** @type {any[]} */ ...values
|
|
22
|
-
) => String.raw(template, ...escapeValues(escapeMap, values))
|
|
23
|
-
|
|
24
|
-
export const tests = {
|
|
25
|
-
escape: (/** @type {import('chai').expect} */ expect) => {
|
|
26
|
-
// @ts-expect-error
|
|
27
|
-
const /** @type {EscapeMap} */ escapeMap = new Map([
|
|
28
|
-
[undefined, () => 'NULL'],
|
|
29
|
-
[Array, (/** @type {any[]} */ values) => escapeValues(escapeMap, values).join(', ')],
|
|
30
|
-
[Boolean, (/** @type {boolean} */ value) => `b'${+value}'`],
|
|
31
|
-
[Date, (/** @type {Date} */ value) => `'${value.toISOString().replace(/^(.+)T(.+)\..*$/, '$1 $2')}'`],
|
|
32
|
-
[Number, (/** @type {number} */ value) => `${value}`],
|
|
33
|
-
[String, (/** @type {string} */ value) => `'${value.replace(/'/g, "''")}'`]
|
|
34
|
-
])
|
|
35
|
-
|
|
36
|
-
// @ts-expect-error
|
|
37
|
-
const sql = escape.bind(null, escapeMap)
|
|
38
|
-
|
|
39
|
-
const actual = sql`
|
|
40
|
-
SELECT *
|
|
41
|
-
FROM table_name
|
|
42
|
-
WHERE column_name IN (${[true, null, undefined, 42, '42', "4'2", /42/, new Date(323325000000)]})`
|
|
43
|
-
|
|
44
|
-
const expected = `
|
|
45
|
-
SELECT *
|
|
46
|
-
FROM table_name
|
|
47
|
-
WHERE column_name IN (b'1', NULL, NULL, 42, '42', '4''2', NULL, '1980-03-31 04:30:00')`
|
|
48
|
-
|
|
49
|
-
expect(actual).to.deep.equal(expected)
|
|
50
|
-
}
|
|
51
|
-
}
|
package/fixTypography.d.ts
DELETED
package/fixTypography.js
DELETED
|
@@ -1,61 +0,0 @@
|
|
|
1
|
-
import { h } from './h.js'
|
|
2
|
-
import { has } from './has.js'
|
|
3
|
-
|
|
4
|
-
const TAGS_TO_SKIP = { IFRAME: 1, NOSCRIPT: 1, PRE: 1, SCRIPT: 1, STYLE: 1, TEXTAREA: 1 }
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* A helper that implements typographic corrections specific to Polish typography.
|
|
8
|
-
*/
|
|
9
|
-
export const fixTypography = (/** @type {Node} */ node) => {
|
|
10
|
-
const /** @type {Node[]} */ queue = [node]
|
|
11
|
-
|
|
12
|
-
while (queue.length > 0) {
|
|
13
|
-
const node0 = queue.shift()
|
|
14
|
-
|
|
15
|
-
if (node0 instanceof Element) {
|
|
16
|
-
node0.childNodes.forEach(childNode => {
|
|
17
|
-
if (childNode instanceof Text) {
|
|
18
|
-
queue.push(childNode)
|
|
19
|
-
} else if (childNode instanceof Element && !has(childNode.tagName, TAGS_TO_SKIP)) {
|
|
20
|
-
queue.push(childNode)
|
|
21
|
-
}
|
|
22
|
-
})
|
|
23
|
-
} else if (node0 instanceof Text) {
|
|
24
|
-
const nodeValue = node0.nodeValue?.trim?.()
|
|
25
|
-
|
|
26
|
-
if (nodeValue != null) {
|
|
27
|
-
let /** @type {Node} */ previousNode = node0
|
|
28
|
-
|
|
29
|
-
nodeValue.split(/(\s|\(|„)([aiouwz—]\s)/gi).forEach((chunk, i) => {
|
|
30
|
-
i %= 3
|
|
31
|
-
|
|
32
|
-
const currentNode = i === 2
|
|
33
|
-
? h('span', { style: 'white-space:nowrap' }, chunk)
|
|
34
|
-
: i === 1
|
|
35
|
-
? document.createTextNode(chunk)
|
|
36
|
-
: document.createTextNode(chunk.replace(/(\/(?=[^/\s])|\.(?=[^\s]))/g, '$1\u200B'))
|
|
37
|
-
|
|
38
|
-
if (node0.parentNode != null) {
|
|
39
|
-
node0.parentNode.insertBefore(currentNode, previousNode.nextSibling)
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
previousNode = currentNode
|
|
43
|
-
})
|
|
44
|
-
|
|
45
|
-
node0.parentNode?.removeChild(node0)
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
export const tests = {
|
|
52
|
-
fixTypography: (/** @type {import('chai').expect} */ expect) => {
|
|
53
|
-
const p = h('p', 'Pchnąć w tę łódź jeża lub ośm skrzyń fig (zob. https://pl.wikipedia.org/wiki/Pangram).')
|
|
54
|
-
|
|
55
|
-
fixTypography(p)
|
|
56
|
-
|
|
57
|
-
expect(p.innerHTML).to.deep.equal(
|
|
58
|
-
'Pchnąć <span style="white-space:nowrap">w </span>tę łódź jeża lub ośm skrzyń fig ' +
|
|
59
|
-
'(zob. https://\u200Bpl.\u200Bwikipedia.\u200Borg/\u200Bwiki/\u200BPangram).')
|
|
60
|
-
}
|
|
61
|
-
}
|
package/h.d.ts
DELETED
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* The type of arguments of the `h` and `s` helpers.
|
|
3
|
-
*/
|
|
4
|
-
export type HArgs = [string | Node, ...HArgs1[]];
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* The type of arguments of the `h` and `s` helpers.
|
|
8
|
-
*/
|
|
9
|
-
export type HArgs1 = Partial<Record<PropertyKey, any>> | null | undefined | Node | string | number | [string | Node, ...HArgs1[]];
|
|
10
|
-
|
|
11
|
-
/**
|
|
12
|
-
* A lightweight [HyperScript](https://github.com/hyperhype/hyperscript)-style helper for creating and modifying `HTMLElement`s (see also `s`).
|
|
13
|
-
*
|
|
14
|
-
* - The first argument of type `string` specifies the tag of the element to be created.
|
|
15
|
-
* - The first argument of type `Node` specifies the element to be modified.
|
|
16
|
-
* - All other arguments of type `Partial<Record<PropertyKey, any>>` are mappings of attributes and properties.
|
|
17
|
-
* Keys starting with `$` specify *properties* (without the leading `$`) to be set on the element being created or modified.
|
|
18
|
-
* (Note that `$` is not a valid attribute name character.)
|
|
19
|
-
* All other keys specify *attributes* to be set by `setAttribute`.
|
|
20
|
-
* An attribute equal to `false` causes the attribute to be removed by `removeAttribute`.
|
|
21
|
-
* - All other arguments of type `null` or `undefined` are simply ignored.
|
|
22
|
-
* - All other arguments of type `Node` are appended to the element being created or modified.
|
|
23
|
-
* - All other arguments of type `string`/`number` are converted to `Text` nodes and appended to the element being created or modified.
|
|
24
|
-
* - All other arguments of type `HArgs` are passed to `h` and the results are appended to the element being created or modified.
|
|
25
|
-
*/
|
|
26
|
-
export function h<T extends keyof HTMLElementTagNameMap>(tag: T, ...args1: HArgs1[]): HTMLElementTagNameMap[T];
|
|
27
|
-
export function h<N extends Node>(node: N, ...args1: HArgs1[]): N;
|
|
28
|
-
export function h(tagOrNode: string | Node, ...args1: HArgs1[]): Node;
|
|
29
|
-
|
|
30
|
-
/**
|
|
31
|
-
* A lightweight [HyperScript](https://github.com/hyperhype/hyperscript)-style helper for creating and modifying `SVGElement`s (see also `h`).
|
|
32
|
-
*
|
|
33
|
-
* - The first argument of type `string` specifies the tag of the element to be created.
|
|
34
|
-
* - The first argument of type `Node` specifies the element to be modified.
|
|
35
|
-
* - All other arguments of type `Partial<Record<PropertyKey, any>>` are mappings of attributes and properties.
|
|
36
|
-
* Keys starting with `$` specify *properties* (without the leading `$`) to be set on the element being created or modified.
|
|
37
|
-
* (Note that `$` is not a valid attribute name character.)
|
|
38
|
-
* All other keys specify *attributes* to be set by `setAttributeNS`.
|
|
39
|
-
* An attribute equal to `false` causes the attribute to be removed by `removeAttributeNS`.
|
|
40
|
-
* - All other arguments of type `null` or `undefined` are simply ignored.
|
|
41
|
-
* - All other arguments of type `Node` are appended to the element being created or modified.
|
|
42
|
-
* - All other arguments of type `string`/`number` are converted to `Text` nodes and appended to the element being created or modified.
|
|
43
|
-
* - All other arguments of type `HArgs` are passed to `s` and the results are appended to the element being created or modified.
|
|
44
|
-
*/
|
|
45
|
-
export function s<T extends keyof SVGElementTagNameMap>(tag: T, ...args1: HArgs1[]): SVGElementTagNameMap[T];
|
|
46
|
-
export function s<N extends Node>(node: N, ...args1: HArgs1[]): N;
|
|
47
|
-
export function s(tagOrNode: string | Node, ...args1: HArgs1[]): Node;
|
|
48
|
-
|
|
49
|
-
export const tests: {
|
|
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
|
-
};
|