Skip to content

Commit cdc04e4

Browse files
authored
refactor(frontend) :: convert the browser sources to TypeScript
The browser modules become .ts and their JSDoc annotations become types. The emitted bundles are unchanged.
1 parent 8247dc9 commit cdc04e4

9 files changed

Lines changed: 133 additions & 143 deletions

File tree

‎frontend/package.json‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"type": "module"
3+
}
Lines changed: 34 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,18 @@
1+
import type { ApexOptions } from "apexcharts";
12
import ApexCharts from "apexcharts";
2-
import { align_series_for, xaxis_type_for } from "./chart_series.js";
3-
import { add_init_fn } from "./init.js";
4-
5-
/**
6-
* @typedef {import("./chart_series.js").ChartSeries} ChartSeries
7-
* @typedef {import("./chart_series.js").Series} Series
8-
*/
3+
import {
4+
align_series_for,
5+
type ChartSeries,
6+
type Series,
7+
xaxis_type_for,
8+
} from "./chart_series.ts";
9+
import { add_init_fn } from "./init.ts";
910

1011
const sqlpage_chart = (() => {
1112
function sqlpage_chart() {
12-
/** @type {NodeListOf<HTMLElement>} */
13-
const charts = document.querySelectorAll("[data-pre-init=chart]");
13+
const charts = document.querySelectorAll<HTMLElement>(
14+
"[data-pre-init=chart]",
15+
);
1416
for (const c of charts) {
1517
try {
1618
build_sqlpage_chart(c);
@@ -50,24 +52,21 @@ const sqlpage_chart = (() => {
5052

5153
const referenceColor = colorNames[isDarkTheme ? "gray-lt" : "gray"];
5254

53-
/** @typedef { {[property:string]: string|number|null} } ReferenceLine */
55+
type ReferenceLine = { [property: string]: string | number | null };
5456

55-
/** @param {unknown} name @returns {string|undefined} */
56-
const named_color = (name) =>
57+
const named_color = (name: unknown): string | undefined =>
5758
typeof name === "string" ? colorNames[name] : undefined;
5859

59-
/** @param {string|number|null} name */
60-
const reference_color = (name) => named_color(name) || referenceColor;
60+
const reference_color = (name: string | number | null) =>
61+
named_color(name) || referenceColor;
6162

62-
/**
63-
* @param {ReferenceLine[]} rows - the rows that carry an xline or a yline
64-
* @param {"x"|"y"} column - the column the reference is written in
65-
* @param {"x"|"y"} axis - the apexcharts axis that column is drawn on
66-
* @param {(value: any) => any} to_axis_value - puts a SQL value on the axis
67-
* @returns {object[]} apexcharts axis annotations
68-
*/
69-
function reference_lines(rows, column, axis, to_axis_value) {
70-
const on_axis = (value) => {
63+
function reference_lines(
64+
rows: ReferenceLine[],
65+
column: "x" | "y",
66+
axis: "x" | "y",
67+
to_axis_value: (value: string | number) => unknown,
68+
): object[] {
69+
const on_axis = (value: string | number | null) => {
7170
if (value == null) return null;
7271
const placed = to_axis_value(value);
7372
return Number.isNaN(placed) ? null : placed;
@@ -94,13 +93,10 @@ const sqlpage_chart = (() => {
9493
});
9594
}
9695

97-
/** @param {HTMLElement} c */
98-
function build_sqlpage_chart(c) {
96+
function build_sqlpage_chart(c: HTMLElement) {
9997
const [data_element] = c.getElementsByTagName("data");
10098
const data = JSON.parse(data_element.textContent);
101-
const chartContainer = /** @type {HTMLElement} */ (
102-
c.querySelector(".chart")
103-
);
99+
const chartContainer = c.querySelector(".chart") as HTMLElement;
104100
chartContainer.innerHTML = "";
105101
const is_timeseries = !!data.time;
106102
const chart_type =
@@ -109,11 +105,12 @@ const sqlpage_chart = (() => {
109105
!!data.stacked && STACKABLE_CHART_TYPES.includes(chart_type);
110106
const points = data.points.filter(Array.isArray);
111107
const reference_rows = data.points.filter((row) => !Array.isArray(row));
112-
/** @type { Series } */
113-
const series_map = new Map();
108+
const series_map: Series = new Map();
114109
for (const [name, old_x, old_y, color, z] of points) {
115-
/** @type {ChartSeries} */
116-
const point_series = series_map.get(name) ?? { name, data: [] };
110+
const point_series: ChartSeries = series_map.get(name) ?? {
111+
name,
112+
data: [],
113+
};
117114
series_map.set(name, point_series);
118115
let x = old_x;
119116
let y = old_y;
@@ -145,7 +142,7 @@ const sqlpage_chart = (() => {
145142
!!data.horizontal,
146143
);
147144

148-
let labels;
145+
let labels: (number | string | Date)[] | undefined;
149146
if (chart_type === "pie") {
150147
labels = points.map(([name, x, _y]) => x || name);
151148
series = points.map(([_name, _x, y]) => Number.parseFloat(y));
@@ -297,14 +294,12 @@ const sqlpage_chart = (() => {
297294
colors,
298295
series,
299296
};
300-
if (labels) options.labels = labels;
297+
if (labels) (options as { labels?: unknown }).labels = labels;
301298
// Numeric axes count intervals; category and time axes use tickAmount as a
302299
// target for label density.
303-
if (data.xticks) options.xaxis.tickAmount = data.xticks;
304-
const chart = new ApexCharts(
305-
chartContainer,
306-
/** @type {import("apexcharts").ApexOptions} */ (options),
307-
);
300+
if (data.xticks)
301+
(options.xaxis as { tickAmount?: number }).tickAmount = data.xticks;
302+
const chart = new ApexCharts(chartContainer, options as ApexOptions);
308303
chart.render().catch(console.error);
309304
if (window.charts) window.charts.push(chart);
310305
else window.charts = [chart];
Lines changed: 34 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,16 @@
1-
/** @typedef {number|string|Date} XValue */
2-
/** @typedef { {x:XValue, y:number|string|number[]|null, z?:number, fillColor?:string} } ChartPoint */
3-
/** @typedef { {name:string, data:ChartPoint[]} } ChartSeries */
4-
/** @typedef { Map<string, ChartSeries> } Series */
1+
export type XValue = number | string | Date;
2+
export type ChartPoint = {
3+
x: XValue;
4+
y: number | string | number[] | null;
5+
z?: number;
6+
fillColor?: string;
7+
};
8+
export type ChartSeries = { name: string; data: ChartPoint[] };
9+
export type Series = Map<string, ChartSeries>;
510

611
const NUMERIC_X_CHART_TYPES = ["line", "area", "bar", "scatter", "bubble"];
712

8-
const Y_WHEN_A_SERIES_SKIPS_A_LABEL = {
13+
const Y_WHEN_A_SERIES_SKIPS_A_LABEL: Record<string, number | null> = {
914
bar: 0,
1015
line: null,
1116
area: null,
@@ -14,18 +19,18 @@ const Y_WHEN_A_SERIES_SKIPS_A_LABEL = {
1419
heatmap: null,
1520
};
1621

17-
/** @param {XValue} x @returns {number|string} equal x values share a key */
18-
const x_key = (x) => (x instanceof Date ? x.getTime() : x);
22+
/** equal x values share a key */
23+
const x_key = (x: XValue): number | string =>
24+
x instanceof Date ? x.getTime() : x;
1925

20-
/** @param {ChartSeries[]} series */
21-
const x_is_text = (series) => typeof series[0]?.data?.[0]?.x === "string";
26+
const x_is_text = (series: ChartSeries[]) =>
27+
typeof series[0]?.data?.[0]?.x === "string";
2228

23-
/** @param {ChartSeries[]} series @param {string} chart_type */
2429
export function xaxis_type_for(
25-
series,
26-
chart_type,
27-
is_timeseries,
28-
is_horizontal,
30+
series: ChartSeries[],
31+
chart_type: string,
32+
is_timeseries: boolean,
33+
is_horizontal: boolean,
2934
) {
3035
if (is_timeseries) return "datetime";
3136
if (x_is_text(series)) return "category";
@@ -38,18 +43,17 @@ export function xaxis_type_for(
3843
}
3944

4045
/**
41-
* @param {ChartSeries[]} series
42-
* @returns {XValue[]} every x the series hold, in their own order where they
43-
* agree and in ascending order where they diverge
46+
* @returns every x the series hold, in their own order where they agree and in
47+
* ascending order where they diverge
4448
*/
45-
export function merged_x_values(series) {
49+
export function merged_x_values(series: ChartSeries[]): XValue[] {
4650
const unread = series.map(({ data }) => data.map(({ x }) => x));
4751
const merged = new Map();
4852
while (unread.some((xs) => xs.length > 0)) {
4953
const with_lowest_x = unread
5054
.filter((xs) => xs.length > 0)
5155
.reduce((a, b) => (b[0] < a[0] ? b : a));
52-
const x = /** @type {XValue} */ (with_lowest_x.shift());
56+
const x = with_lowest_x.shift() as XValue;
5357
merged.set(x_key(x), x);
5458
}
5559
return [...merged.values()];
@@ -60,12 +64,13 @@ export function merged_x_values(series) {
6064
* series that skips an x lands on the wrong one. Give every series the same
6165
* amount of x values.
6266
*
63-
* @param {ChartSeries[]} series
64-
* @param {number|null} y_when_missing what a series with no value at an x is
65-
* worth there: zero to add nothing to a stack, null to leave a gap.
66-
* @returns {ChartSeries[]}
67+
* @param y_when_missing what a series with no value at an x is worth there:
68+
* zero to add nothing to a stack, null to leave a gap.
6769
*/
68-
export function align_series(series, y_when_missing) {
70+
export function align_series(
71+
series: ChartSeries[],
72+
y_when_missing: number | null,
73+
): ChartSeries[] {
6974
const all_x = merged_x_values(series);
7075
return series.map(({ name, data }) => {
7176
const by_x = new Map(data.map((point) => [x_key(point.x), point]));
@@ -79,13 +84,11 @@ export function align_series(series, y_when_missing) {
7984
});
8085
}
8186

82-
/**
83-
* @param {ChartSeries[]} series
84-
* @param {string} chart_type
85-
* @param {boolean} is_stacked
86-
* @returns {ChartSeries[]}
87-
*/
88-
export function align_series_for(series, chart_type, is_stacked) {
87+
export function align_series_for(
88+
series: ChartSeries[],
89+
chart_type: string,
90+
is_stacked: boolean,
91+
): ChartSeries[] {
8992
if (is_stacked) return align_series(series, 0);
9093
if (x_is_text(series) && chart_type in Y_WHEN_A_SERIES_SKIPS_A_LABEL)
9194
return align_series(series, Y_WHEN_A_SERIES_SKIPS_A_LABEL[chart_type]);
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
export function add_init_fn(f) {
1+
export function add_init_fn(f: () => void) {
22
document.addEventListener("DOMContentLoaded", f);
33
document.addEventListener("fragment-loaded", f);
44
if (document.readyState !== "loading") setTimeout(f, 0);

0 commit comments

Comments
 (0)