Mirror of https://github.com/roostorg/coop
github.com/roostorg/coop
1/**
2 * Wrapper around `recharts-scale/es6/getNiceTickValues` that recovers from
3 * `[DecimalError] Division by zero` errors thrown by upstream when a chart
4 * receives a degenerate domain (e.g., all values identical, or non-numeric).
5 *
6 * Aliased via `resolve.alias` in `client/vite.config.ts`, so any `recharts`
7 * import of `recharts-scale/es6/getNiceTickValues` resolves to this module
8 * instead of the upstream implementation. We use Vite's alias — not craco —
9 * because this app is built with Vite, not Create React App.
10 */
11const actual = require('recharts-scale/es6/getNiceTickValues');
12
13const DEFAULT_TICK_COUNT = 5;
14
15/**
16 * Build a plain linear set of ticks as a last resort when upstream can't
17 * compute one. Safe for any `tickCount >= 1` (returns a single tick when
18 * `tickCount === 1`, avoiding its own division-by-zero).
19 */
20function fallbackTicks(domain, tickCount) {
21 const count =
22 Number.isInteger(tickCount) && tickCount > 0 ? tickCount : DEFAULT_TICK_COUNT;
23 const min = typeof domain[0] === 'number' ? domain[0] : 0;
24 const max = typeof domain[1] === 'number' && domain[1] > min ? domain[1] : min + 1;
25 if (count === 1) return [min];
26 const step = (max - min) / (count - 1);
27 const ticks = new Array(count);
28 for (let i = 0; i < count; i++) {
29 ticks[i] = min + step * i;
30 }
31 return ticks;
32}
33
34function isDivisionByZeroError(err) {
35 // `recharts-scale` uses `decimal.js` under the hood, which tags the error
36 // with `name === 'DecimalError'`. Fall back to a message-substring check
37 // for older versions that don't set `name`.
38 return (
39 (err && err.name === 'DecimalError') ||
40 (err && typeof err.message === 'string' && err.message.includes('Division by zero'))
41 );
42}
43
44function safelyCall(fn, fnName, domain, tickCount, allowDecimals) {
45 try {
46 return fn(domain, tickCount, allowDecimals);
47 } catch (err) {
48 if (!isDivisionByZeroError(err)) throw err;
49 // eslint-disable-next-line no-console
50 console.warn(
51 `[rechartsScaleWrapper] ${fnName} threw DecimalError; using linear fallback.`,
52 { domain, tickCount },
53 );
54 return fallbackTicks(domain, tickCount);
55 }
56}
57
58function getNiceTickValues(domain, tickCount, allowDecimals) {
59 return safelyCall(
60 actual.getNiceTickValues,
61 'getNiceTickValues',
62 domain,
63 tickCount,
64 allowDecimals,
65 );
66}
67
68function getTickValuesFixedDomain(domain, tickCount, allowDecimals) {
69 return safelyCall(
70 actual.getTickValuesFixedDomain,
71 'getTickValuesFixedDomain',
72 domain,
73 tickCount,
74 allowDecimals,
75 );
76}
77
78exports.getNiceTickValues = getNiceTickValues;
79exports.getTickValuesFixedDomain = getTickValuesFixedDomain;