@chartguard/quality-chartjs 0.0.0-stage → 0.1.0
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/LICENSE +21 -0
- package/README.md +17 -2
- package/dist/axes.d.ts +14 -0
- package/dist/axes.d.ts.map +1 -0
- package/dist/axes.js +146 -0
- package/dist/axes.js.map +1 -0
- package/dist/color.d.ts +8 -0
- package/dist/color.d.ts.map +1 -0
- package/dist/color.js +123 -0
- package/dist/color.js.map +1 -0
- package/dist/fit.d.ts +11 -0
- package/dist/fit.d.ts.map +1 -0
- package/dist/fit.js +137 -0
- package/dist/fit.js.map +1 -0
- package/dist/fixes.d.ts +6 -0
- package/dist/fixes.d.ts.map +1 -0
- package/dist/fixes.js +30 -0
- package/dist/fixes.js.map +1 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +51 -0
- package/dist/index.js.map +1 -0
- package/dist/legend.d.ts +13 -0
- package/dist/legend.d.ts.map +1 -0
- package/dist/legend.js +59 -0
- package/dist/legend.js.map +1 -0
- package/dist/motion.d.ts +8 -0
- package/dist/motion.d.ts.map +1 -0
- package/dist/motion.js +69 -0
- package/dist/motion.js.map +1 -0
- package/dist/scales.d.ts +25 -0
- package/dist/scales.d.ts.map +1 -0
- package/dist/scales.js +95 -0
- package/dist/scales.js.map +1 -0
- package/dist/series.d.ts +12 -0
- package/dist/series.d.ts.map +1 -0
- package/dist/series.js +173 -0
- package/dist/series.js.map +1 -0
- package/dist/values.d.ts +7 -0
- package/dist/values.d.ts.map +1 -0
- package/dist/values.js +43 -0
- package/dist/values.js.map +1 -0
- package/package.json +39 -5
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 ChartGuard contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,3 +1,18 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @chartguard/quality-chartjs
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Advisory quality review of Chart.js configs: it reads the chart the config describes (what the runtime would draw, with its defaults) and reports presentation problems such as bars that do not start at zero, unreadable colours or charts assistive technology cannot describe. Findings are advice, never a verdict: there is no error severity and no `valid`.
|
|
4
|
+
|
|
5
|
+
**Status:** pre-release (0.x). Coverage is partial, and the API and settings may still change between minor versions.
|
|
6
|
+
|
|
7
|
+
```ts
|
|
8
|
+
import { analyze } from "@chartguard/quality-chartjs";
|
|
9
|
+
|
|
10
|
+
const report = analyze({ type: "bar", data: { labels: ["a", "b"], datasets: [{ label: "Sales", data: [60, 70] }] }, options: { scales: { y: { min: 50 } } } });
|
|
11
|
+
for (const finding of report.diagnostics) console.log(finding.code, finding.path, finding.message, finding.fix);
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
- **Rules:** the shared catalog of `@chartguard/quality-core` (`RULE_CATALOG`: each rule with its rationale, sources and documented limits). `analyze(config, { rules: { "value-axis-untitled": "off" } })` sets a rule's level (`off`, `info`, `warning`); `ruleset` picks rules by id or impact.
|
|
15
|
+
- **Context:** facts the chart leaves to the page (`context: { background: "#ffffff" }`) let rules decide what the config alone cannot; a finding the context or a setting suppresses is kept in `report.suppressed`, with why.
|
|
16
|
+
- **Fixes:** a finding may carry a `set-option` fix, offered only when it is verified to remove the finding without a new one. It changes what is drawn: apply it (`applyFix` from `@chartguard/core`) only at the user's request.
|
|
17
|
+
- **Unknown stays unknown:** a fact the config does not decide (an option set by a callback, a size-dependent range) is unknown, and no rule claims anything on it.
|
|
18
|
+
- `normalize(config)` gives the library-neutral `ChartSemantics` the rules read; invalid options throw `QualityOptionsError` (`assertQualityOptions` checks them up front).
|
package/dist/axes.d.ts
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { type AxisSemantics, type Fact, type Item, type Listed, type SeriesSemantics } from '@chartguard/quality-core';
|
|
2
|
+
import type { Scales } from './scales.js';
|
|
3
|
+
/** Chart.js titles are a string or one string per line. */
|
|
4
|
+
export declare const isText: (value: unknown) => value is string | string[];
|
|
5
|
+
export declare const asText: (fact: Fact<string | string[]>) => Fact<string>;
|
|
6
|
+
/** The datasets as read and as series: a fitted range is measured from their values. */
|
|
7
|
+
interface Datasets {
|
|
8
|
+
readonly series: Listed<SeriesSemantics>;
|
|
9
|
+
readonly datasets: Listed<Item>;
|
|
10
|
+
}
|
|
11
|
+
/** Every scale the chart builds that is read (configured or added by a dataset), and any a dataset names. */
|
|
12
|
+
export declare function axesOf(config: unknown, { series, datasets }: Datasets, scales: Scales): AxisSemantics[];
|
|
13
|
+
export {};
|
|
14
|
+
//# sourceMappingURL=axes.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"axes.d.ts","sourceRoot":"","sources":["../src/axes.ts"],"names":[],"mappings":"AAAA,OAAO,EACN,KAAK,aAAa,EAGlB,KAAK,IAAI,EAMT,KAAK,IAAI,EACT,KAAK,MAAM,EAGX,KAAK,eAAe,EAEpB,MAAM,0BAA0B,CAAC;AAGlC,OAAO,KAAK,EAAQ,MAAM,EAAE,MAAM,aAAa,CAAC;AAwFhD,2DAA2D;AAC3D,eAAO,MAAM,MAAM,GAAI,OAAO,OAAO,KAAG,KAAK,IAAI,MAAM,GAAG,MAAM,EACsD,CAAC;AACvH,eAAO,MAAM,MAAM,GAAI,MAAM,IAAI,CAAC,MAAM,GAAG,MAAM,EAAE,CAAC,KAAG,IAAI,CAAC,MAAM,CAGjE,CAAC;AAiDF,wFAAwF;AACxF,UAAU,QAAQ;IACjB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC,eAAe,CAAC,CAAC;IACzC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC,IAAI,CAAC,CAAC;CAChC;AAED,6GAA6G;AAC7G,wBAAgB,MAAM,CAAC,MAAM,EAAE,OAAO,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,GAAG,aAAa,EAAE,CAMvG"}
|
package/dist/axes.js
ADDED
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
import { defaulted, firstSet, formatPath, isBoolean, isNumber, isString, readFact, unknown } from '@chartguard/quality-core';
|
|
2
|
+
import { fitOf } from './fit.js';
|
|
3
|
+
import { INDEX_AXIS } from './series.js';
|
|
4
|
+
/** Bar and line charts default their index scale to `category` and their value scale to `linear`. */
|
|
5
|
+
const BY_ROLE = {
|
|
6
|
+
bar: {
|
|
7
|
+
index: { value: 'category', pointer: "chart.js@4.5.1 dist/chart.js:1393 type: 'category'," },
|
|
8
|
+
value: { value: 'linear', pointer: "chart.js@4.5.1 dist/chart.js:1400 type: 'linear'," }
|
|
9
|
+
},
|
|
10
|
+
line: {
|
|
11
|
+
index: {
|
|
12
|
+
value: 'category',
|
|
13
|
+
pointer: "chart.js@4.5.1 dist/chart.js:2097 type: 'category' [in class LineController]"
|
|
14
|
+
},
|
|
15
|
+
value: { value: 'linear', pointer: "chart.js@4.5.1 dist/chart.js:2100 type: 'linear' [in class LineController]" }
|
|
16
|
+
}
|
|
17
|
+
};
|
|
18
|
+
/** Scatter charts default both scales to `linear`, radar charts their `r` scale to `radialLinear`. */
|
|
19
|
+
const BY_AXIS = {
|
|
20
|
+
scatter: {
|
|
21
|
+
x: {
|
|
22
|
+
value: 'linear',
|
|
23
|
+
pointer: "chart.js@4.5.1 dist/chart.js:2472 type: 'linear' [in class ScatterController] [in x: {]"
|
|
24
|
+
},
|
|
25
|
+
y: {
|
|
26
|
+
value: 'linear',
|
|
27
|
+
pointer: "chart.js@4.5.1 dist/chart.js:2475 type: 'linear' [in class ScatterController] [in y: {]"
|
|
28
|
+
}
|
|
29
|
+
},
|
|
30
|
+
radar: {
|
|
31
|
+
r: {
|
|
32
|
+
value: 'radialLinear',
|
|
33
|
+
pointer: "chart.js@4.5.1 dist/chart.js:2402 type: 'radialLinear' [in class RadarController]"
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
/** A scale title is hidden and empty unless set (`title: { display: false, text: '' }`). */
|
|
38
|
+
const TITLE_SHOWN = {
|
|
39
|
+
value: false,
|
|
40
|
+
pointer: 'chart.js@4.5.1 dist/chunks/helpers.dataset.js:956 display: false,'
|
|
41
|
+
};
|
|
42
|
+
const TITLE_TEXT = {
|
|
43
|
+
value: '',
|
|
44
|
+
pointer: "chart.js@4.5.1 dist/chunks/helpers.dataset.js:957 text: '',"
|
|
45
|
+
};
|
|
46
|
+
const REVERSE = {
|
|
47
|
+
value: false,
|
|
48
|
+
pointer: 'chart.js@4.5.1 dist/chunks/helpers.dataset.js:934 reverse: false,'
|
|
49
|
+
};
|
|
50
|
+
/**
|
|
51
|
+
* Scales without a `stack` share the chart area; scales with one are laid out in bands, one after the
|
|
52
|
+
* other (`buildStacks`, which skips a box without a stack): each such scale is a panel of its own.
|
|
53
|
+
*/
|
|
54
|
+
const UNSTACKED = {
|
|
55
|
+
value: 'chart',
|
|
56
|
+
pointer: 'chart.js@4.5.1 dist/chart.js:2923 if (!stack || !STATIC_POSITIONS.includes(pos)) {'
|
|
57
|
+
};
|
|
58
|
+
function panelOf(config, path, key) {
|
|
59
|
+
const stack = readFact(config, [...path, 'stack'], isString, UNSTACKED);
|
|
60
|
+
return stack.known && stack.source === 'config' ? { ...stack, value: `stack:${stack.value}:${key}` } : stack;
|
|
61
|
+
}
|
|
62
|
+
/** A linear scale labels its ticks with plain numbers unless a callback formats them. */
|
|
63
|
+
const NUMERIC = {
|
|
64
|
+
value: '',
|
|
65
|
+
pointer: 'chart.js@4.5.1 dist/chart.js:10364 callback: Ticks.formatters.numeric [in class LinearScale extends]'
|
|
66
|
+
};
|
|
67
|
+
/** The unit around the tick labels: none on a linear scale without a callback; a callback decides at runtime. */
|
|
68
|
+
function unitOf(config, path, scale) {
|
|
69
|
+
const callback = readFact(config, [...path, 'ticks', 'callback'], (_value) => false);
|
|
70
|
+
if (callback.known || callback.reason !== 'unset')
|
|
71
|
+
return callback;
|
|
72
|
+
return scale.known && scale.value === 'linear'
|
|
73
|
+
? defaulted(NUMERIC, callback.path)
|
|
74
|
+
: unknown(callback.path, 'unmodelled');
|
|
75
|
+
}
|
|
76
|
+
const SCALE_TYPES = {
|
|
77
|
+
linear: 'linear',
|
|
78
|
+
radialLinear: 'linear',
|
|
79
|
+
logarithmic: 'log',
|
|
80
|
+
category: 'category',
|
|
81
|
+
time: 'time',
|
|
82
|
+
timeseries: 'time'
|
|
83
|
+
};
|
|
84
|
+
/** Chart.js titles are a string or one string per line. */
|
|
85
|
+
export const isText = (value) => typeof value === 'string' || (Array.isArray(value) && value.every((line) => typeof line === 'string'));
|
|
86
|
+
export const asText = (fact) => {
|
|
87
|
+
if (!fact.known || typeof fact.value === 'string')
|
|
88
|
+
return fact;
|
|
89
|
+
return { ...fact, value: fact.value.join(' ') };
|
|
90
|
+
};
|
|
91
|
+
/**
|
|
92
|
+
* A configured scale's type defaults from the chart type (`mergeScaleConfig` merges the chart type's
|
|
93
|
+
* scale defaults first): by its role for bar and line charts (the index axis is `options.datasets[type]`
|
|
94
|
+
* or `options.indexAxis`, else `x`), by its axis for scatter and radar charts. Otherwise not modelled.
|
|
95
|
+
*/
|
|
96
|
+
function defaultType(config, axis) {
|
|
97
|
+
const type = readFact(config, ['type'], isString);
|
|
98
|
+
if (!type.known || axis === undefined)
|
|
99
|
+
return undefined;
|
|
100
|
+
const roles = BY_ROLE[type.value];
|
|
101
|
+
if (roles === undefined)
|
|
102
|
+
return BY_AXIS[type.value]?.[axis];
|
|
103
|
+
const index = firstSet([
|
|
104
|
+
readFact(config, ['options', 'datasets', type.value, 'indexAxis'], isString),
|
|
105
|
+
readFact(config, ['options', 'indexAxis'], isString)
|
|
106
|
+
], INDEX_AXIS);
|
|
107
|
+
if (!index.known || axis === 'r')
|
|
108
|
+
return undefined;
|
|
109
|
+
return axis === index.value ? roles.index : roles.value;
|
|
110
|
+
}
|
|
111
|
+
function scaleOf(config, path, axis) {
|
|
112
|
+
const type = readFact(config, [...path, 'type'], isString, defaultType(config, axis));
|
|
113
|
+
if (!type.known)
|
|
114
|
+
return type;
|
|
115
|
+
return { ...type, value: SCALE_TYPES[type.value] ?? 'other' };
|
|
116
|
+
}
|
|
117
|
+
function axisOf(config, key, axis, chart) {
|
|
118
|
+
const path = ['options', 'scales', key];
|
|
119
|
+
const scale = scaleOf(config, path, axis);
|
|
120
|
+
return {
|
|
121
|
+
key,
|
|
122
|
+
path: formatPath(path),
|
|
123
|
+
scale,
|
|
124
|
+
min: readFact(config, [...path, 'min'], isNumber),
|
|
125
|
+
max: readFact(config, [...path, 'max'], isNumber),
|
|
126
|
+
fit: fitOf(config, key, scale, chart),
|
|
127
|
+
unit: unitOf(config, path, scale),
|
|
128
|
+
panel: panelOf(config, path, key),
|
|
129
|
+
reversed: readFact(config, [...path, 'reverse'], isBoolean, REVERSE),
|
|
130
|
+
title: {
|
|
131
|
+
text: asText(readFact(config, [...path, 'title', 'text'], isText, TITLE_TEXT)),
|
|
132
|
+
shown: readFact(config, [...path, 'title', 'display'], isBoolean, TITLE_SHOWN)
|
|
133
|
+
}
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
/** Every scale the chart builds that is read (configured or added by a dataset), and any a dataset names. */
|
|
137
|
+
export function axesOf(config, { series, datasets }, scales) {
|
|
138
|
+
const built = scales.entries.flatMap(({ id, axis }) => (id === undefined ? [] : [[id, axis]]));
|
|
139
|
+
const named = series.known ? series.items.flatMap(({ valueAxis }) => (valueAxis.known ? [valueAxis.value] : [])) : [];
|
|
140
|
+
const axes = new Map(built);
|
|
141
|
+
for (const key of named)
|
|
142
|
+
if (!axes.has(key))
|
|
143
|
+
axes.set(key, undefined);
|
|
144
|
+
return [...axes].map(([key, axis]) => axisOf(config, key, axis, { series, datasets }));
|
|
145
|
+
}
|
|
146
|
+
//# sourceMappingURL=axes.js.map
|
package/dist/axes.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"axes.js","sourceRoot":"","sources":["../src/axes.ts"],"names":[],"mappings":"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"}
|
package/dist/color.d.ts
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { type Fact, type Item, type Listed } from '@chartguard/quality-core';
|
|
2
|
+
/**
|
|
3
|
+
* `colorsDefined` for one analysis, read at most once: every dataset's colour may depend on it, and
|
|
4
|
+
* reading every dataset again for each one is quadratic in a number the caller chooses.
|
|
5
|
+
*/
|
|
6
|
+
export declare function colorsDefinedOnce(config: unknown, datasets: Listed<Item>): () => Fact<boolean>;
|
|
7
|
+
export declare function colorOf(config: unknown, item: Item, type: Fact<string>, definedAnywhere: () => Fact<boolean>): Fact<string>;
|
|
8
|
+
//# sourceMappingURL=color.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"color.d.ts","sourceRoot":"","sources":["../src/color.ts"],"names":[],"mappings":"AACA,OAAO,EACN,KAAK,IAAI,EAIT,KAAK,IAAI,EAET,KAAK,MAAM,EAKX,MAAM,0BAA0B,CAAC;AAkElC;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,CAG9F;AAwBD,wBAAgB,OAAO,CACtB,MAAM,EAAE,OAAO,EACf,IAAI,EAAE,IAAI,EACV,IAAI,EAAE,IAAI,CAAC,MAAM,CAAC,EAClB,eAAe,EAAE,MAAM,IAAI,CAAC,OAAO,CAAC,GAClC,IAAI,CAAC,MAAM,CAAC,CAqBd"}
|
package/dist/color.js
ADDED
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import { isContainer, ownDataProperty } from '@chartguard/core';
|
|
2
|
+
import { firstSet, formatPath, isStaticValue, known, readFact, unknown } from '@chartguard/quality-core';
|
|
3
|
+
/** The option that colours a dataset, and the element whose options it falls back to. */
|
|
4
|
+
const COLORED_BY = {
|
|
5
|
+
line: { key: 'borderColor', element: 'line' },
|
|
6
|
+
bar: { key: 'backgroundColor', element: 'bar' },
|
|
7
|
+
scatter: { key: 'backgroundColor', element: 'point' },
|
|
8
|
+
bubble: { key: 'backgroundColor', element: 'point' }
|
|
9
|
+
};
|
|
10
|
+
/** Chart.js's own colours, used when nothing else colours a dataset. */
|
|
11
|
+
const DEFAULT = {
|
|
12
|
+
backgroundColor: "chart.js@4.5.1 dist/chunks/helpers.dataset.js:1024 this.backgroundColor = 'rgba(0,0,0,0.1)';",
|
|
13
|
+
borderColor: "chart.js@4.5.1 dist/chunks/helpers.dataset.js:1025 this.borderColor = 'rgba(0,0,0,0.1)';"
|
|
14
|
+
};
|
|
15
|
+
const NONE = { known: true, value: false, path: '$', source: 'config' };
|
|
16
|
+
/** Whether `value` defines a colour as `containsColorsDefinitions` sees one (an own truthy colour); unknown behind a getter. */
|
|
17
|
+
function defines(value, path) {
|
|
18
|
+
if (!isContainer(value))
|
|
19
|
+
return NONE;
|
|
20
|
+
for (const key of ['borderColor', 'backgroundColor']) {
|
|
21
|
+
const entry = ownDataProperty(value, key);
|
|
22
|
+
if (!entry.found && entry.accessor)
|
|
23
|
+
return unknown(path, 'accessor');
|
|
24
|
+
if (entry.found && Boolean(entry.value))
|
|
25
|
+
return { known: true, value: true, path, source: 'config' };
|
|
26
|
+
}
|
|
27
|
+
return NONE;
|
|
28
|
+
}
|
|
29
|
+
/** The element options under `options.elements`, read through own data properties. */
|
|
30
|
+
function elementsOf(config) {
|
|
31
|
+
const elements = readFact(config, ['options', 'elements'], isContainer);
|
|
32
|
+
if (!elements.known)
|
|
33
|
+
return elements.reason === 'unset' ? known([], elements.path) : elements;
|
|
34
|
+
const entries = Object.keys(elements.value).map((key) => ({
|
|
35
|
+
entry: ownDataProperty(elements.value, key),
|
|
36
|
+
path: formatPath(['options', 'elements', key])
|
|
37
|
+
}));
|
|
38
|
+
const hidden = entries.find(({ entry }) => !entry.found);
|
|
39
|
+
if (hidden !== undefined)
|
|
40
|
+
return unknown(hidden.path, 'accessor');
|
|
41
|
+
return known(entries.map(({ entry, path }) => ({ value: entry.found ? entry.value : undefined, path })), elements.path);
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Whether the config defines a colour anywhere: in a dataset, the chart options or an element's
|
|
45
|
+
* options. Then the Colors plugin stays out (`if (!options.forceOverride && containsColorDefenition)`,
|
|
46
|
+
* dist/chart.js:7428), registered or not, and an uncoloured dataset takes Chart.js's own colour.
|
|
47
|
+
*/
|
|
48
|
+
function colorsDefined(config, datasets) {
|
|
49
|
+
if (!datasets.known)
|
|
50
|
+
return unknown(datasets.path, datasets.reason);
|
|
51
|
+
const options = readFact(config, ['options'], isContainer);
|
|
52
|
+
if (!options.known && options.reason !== 'unset')
|
|
53
|
+
return options;
|
|
54
|
+
const elements = elementsOf(config);
|
|
55
|
+
if (!elements.known)
|
|
56
|
+
return elements;
|
|
57
|
+
const holders = [
|
|
58
|
+
...datasets.items,
|
|
59
|
+
{ value: options.known ? options.value : undefined, path: '$.options' },
|
|
60
|
+
...elements.value
|
|
61
|
+
];
|
|
62
|
+
return holders.map(({ value, path }) => defines(value, path)).find((fact) => !fact.known || fact.value) ?? NONE;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* `colorsDefined` for one analysis, read at most once: every dataset's colour may depend on it, and
|
|
66
|
+
* reading every dataset again for each one is quadratic in a number the caller chooses.
|
|
67
|
+
*/
|
|
68
|
+
export function colorsDefinedOnce(config, datasets) {
|
|
69
|
+
let defined;
|
|
70
|
+
return () => (defined ??= colorsDefined(config, datasets));
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* The colour a dataset is drawn in: its own (`borderColor` for lines, `backgroundColor` for bars and
|
|
74
|
+
* points), else the options for its type, its element or the chart; else, when the config colours
|
|
75
|
+
* anything, Chart.js's own `rgba(0,0,0,0.1)`. Without any colour in the config the Colors plugin
|
|
76
|
+
* decides, if it is registered: not modelled. Per-point colours (arrays) are not modelled either.
|
|
77
|
+
*/
|
|
78
|
+
/**
|
|
79
|
+
* Whether the Colors plugin may paint over every colour: `forceOverride` skips its test for colours in
|
|
80
|
+
* the config (dist/chart.js:7428), unless the plugin is turned off. Whether it is registered is not in
|
|
81
|
+
* the config, so then no dataset colour is known (K7). Undefined when it cannot override them.
|
|
82
|
+
*/
|
|
83
|
+
function forcedOver(config) {
|
|
84
|
+
const at = ['options', 'plugins', 'colors'];
|
|
85
|
+
const enabled = readFact(config, [...at, 'enabled'], isStaticValue);
|
|
86
|
+
if (enabled.known && enabled.value === false)
|
|
87
|
+
return undefined;
|
|
88
|
+
const force = readFact(config, [...at, 'forceOverride'], isStaticValue);
|
|
89
|
+
if (!force.known)
|
|
90
|
+
return force.reason === 'unset' ? undefined : force;
|
|
91
|
+
return force.value === false || force.value === undefined || force.value === null
|
|
92
|
+
? undefined
|
|
93
|
+
: unknown(force.path, 'unmodelled');
|
|
94
|
+
}
|
|
95
|
+
export function colorOf(config, item, type, definedAnywhere) {
|
|
96
|
+
if (!type.known)
|
|
97
|
+
return unknown(`${item.path}.backgroundColor`, type.reason);
|
|
98
|
+
const forced = forcedOver(config);
|
|
99
|
+
if (forced !== undefined)
|
|
100
|
+
return unknown(`${item.path}.backgroundColor`, forced.reason);
|
|
101
|
+
const by = COLORED_BY[type.value];
|
|
102
|
+
if (by === undefined)
|
|
103
|
+
return unknown(`${item.path}.backgroundColor`, 'unmodelled');
|
|
104
|
+
const at = (path) => readFact(config, [...path, by.key], isStaticValue);
|
|
105
|
+
const own = firstSet([
|
|
106
|
+
at(item.segments),
|
|
107
|
+
at(['options', 'datasets', type.value]),
|
|
108
|
+
at(['options', 'elements', by.element]),
|
|
109
|
+
at(['options'])
|
|
110
|
+
]);
|
|
111
|
+
if (own.known)
|
|
112
|
+
return typeof own.value === 'string' ? own : unknown(own.path, 'unmodelled');
|
|
113
|
+
if (own.reason !== 'unset')
|
|
114
|
+
return own;
|
|
115
|
+
const defined = definedAnywhere();
|
|
116
|
+
const path = formatPath([...item.segments, by.key]);
|
|
117
|
+
if (!defined.known)
|
|
118
|
+
return unknown(path, defined.reason);
|
|
119
|
+
return defined.value
|
|
120
|
+
? { known: true, value: 'rgba(0,0,0,0.1)', path, source: 'default', pointer: DEFAULT[by.key] }
|
|
121
|
+
: unknown(path, 'unmodelled');
|
|
122
|
+
}
|
|
123
|
+
//# sourceMappingURL=color.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"color.js","sourceRoot":"","sources":["../src/color.ts"],"names":[],"mappings":"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"}
|
package/dist/fit.d.ts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { type Fact, type Item, type Listed, type ScaleType, type SeriesSemantics, type ZeroFit } from '@chartguard/quality-core';
|
|
2
|
+
/**
|
|
3
|
+
* Where zero is in the range a linear value scale fits to the data when its `beginAtZero` is `false`
|
|
4
|
+
* (bar charts set it `true` for their value scale). Hidden datasets and the options in `UNMODELLED`
|
|
5
|
+
* are not modelled.
|
|
6
|
+
*/
|
|
7
|
+
export declare function fitOf(config: unknown, key: string, type: Fact<ScaleType>, { series, datasets }: {
|
|
8
|
+
series: Listed<SeriesSemantics>;
|
|
9
|
+
datasets: Listed<Item>;
|
|
10
|
+
}): Fact<ZeroFit>;
|
|
11
|
+
//# sourceMappingURL=fit.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fit.d.ts","sourceRoot":"","sources":["../src/fit.ts"],"names":[],"mappings":"AAAA,OAAO,EAGN,KAAK,IAAI,EAMT,KAAK,IAAI,EACT,KAAK,MAAM,EAEX,KAAK,SAAS,EACd,KAAK,eAAe,EAGpB,KAAK,OAAO,EAEZ,MAAM,0BAA0B,CAAC;AAsHlC;;;;GAIG;AACH,wBAAgB,KAAK,CACpB,MAAM,EAAE,OAAO,EACf,GAAG,EAAE,MAAM,EACX,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EACrB,EAAE,MAAM,EAAE,QAAQ,EAAE,EAAE;IAAE,MAAM,EAAE,MAAM,CAAC,eAAe,CAAC,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC,IAAI,CAAC,CAAA;CAAE,GAC/E,IAAI,CAAC,OAAO,CAAC,CAYf"}
|
package/dist/fit.js
ADDED
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
import { dataRange, formatPath, holds, isBoolean, isNumber, isString, readFact, unknown, zeroFit } from '@chartguard/quality-core';
|
|
2
|
+
const NICE = [1, 2, 5];
|
|
3
|
+
/** `niceNum` (chart.js@4.5.1 dist/chunks/helpers.dataset.js:301). */
|
|
4
|
+
function niceNum(range) {
|
|
5
|
+
const rounded = Math.round(range);
|
|
6
|
+
const near = Math.abs(range - rounded) < range / 1000 ? rounded : range;
|
|
7
|
+
const magnitude = 10 ** Math.floor(Math.log10(near));
|
|
8
|
+
const fraction = near / magnitude;
|
|
9
|
+
return (NICE.find((step) => fraction <= step) ?? 10) * magnitude;
|
|
10
|
+
}
|
|
11
|
+
/** `_decimalPlaces` (dist/chunks/helpers.dataset.js:364). */
|
|
12
|
+
function decimalPlaces(value) {
|
|
13
|
+
let [scale, places] = [1, 0];
|
|
14
|
+
while (Math.round(value * scale) / scale !== value)
|
|
15
|
+
[scale, places] = [scale * 10, places + 1];
|
|
16
|
+
return places;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* The first and last tick `generateTicks$1` (dist/chart.js:10137) makes from a data range with at
|
|
20
|
+
* most `maxTicks` ticks, with `bounds: 'ticks'` and no step, count, precision or bound set.
|
|
21
|
+
*/
|
|
22
|
+
function tickRange(min, max, maxTicks) {
|
|
23
|
+
const spaces = maxTicks - 1;
|
|
24
|
+
let spacing = niceNum((max - min) / spaces);
|
|
25
|
+
if (spacing < 1e-14)
|
|
26
|
+
return [min, max];
|
|
27
|
+
if (Math.ceil(max / spacing) - Math.floor(min / spacing) > spaces)
|
|
28
|
+
spacing = niceNum(((Math.ceil(max / spacing) - Math.floor(min / spacing)) * spacing) / spaces);
|
|
29
|
+
const [niceMin, niceMax] = [Math.floor(min / spacing) * spacing, Math.ceil(max / spacing) * spacing];
|
|
30
|
+
const factor = 10 ** Math.max(decimalPlaces(spacing), decimalPlaces(niceMin));
|
|
31
|
+
return [Math.round(niceMin * factor) / factor, Math.round(niceMax * factor) / factor];
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* `handleTickRangeOptions` (dist/chart.js:10261) without `beginAtZero`: a single value is widened by
|
|
35
|
+
* 5 % of it (by 1 when it is zero) on both sides.
|
|
36
|
+
*/
|
|
37
|
+
function widened([min, max]) {
|
|
38
|
+
if (min !== max)
|
|
39
|
+
return [min, max];
|
|
40
|
+
const offset = max === 0 ? 1 : Math.abs(max * 0.05);
|
|
41
|
+
return [min - offset, max + offset];
|
|
42
|
+
}
|
|
43
|
+
/** Options that change the range or the ticks in ways not modelled: any of them set leaves the fit unknown. */
|
|
44
|
+
const UNMODELLED = [
|
|
45
|
+
['min'],
|
|
46
|
+
['max'],
|
|
47
|
+
['suggestedMin'],
|
|
48
|
+
['suggestedMax'],
|
|
49
|
+
['grace'],
|
|
50
|
+
['ticks', 'stepSize'],
|
|
51
|
+
['ticks', 'count'],
|
|
52
|
+
['ticks', 'precision']
|
|
53
|
+
];
|
|
54
|
+
/** Linear scales place their range on ticks (`bounds: 'ticks'`). */
|
|
55
|
+
const BOUNDS = {
|
|
56
|
+
value: 'ticks',
|
|
57
|
+
pointer: "chart.js@4.5.1 dist/chunks/helpers.dataset.js:936 bounds: 'ticks',"
|
|
58
|
+
};
|
|
59
|
+
/** The most ticks a linear scale makes, at least two (`Math.max(2, maxTicks)`, dist/chart.js:10312). */
|
|
60
|
+
const MAX_TICKS = {
|
|
61
|
+
value: 11,
|
|
62
|
+
pointer: 'chart.js@4.5.1 dist/chart.js:10298 maxTicksLimit = maxTicksLimit || 11;'
|
|
63
|
+
};
|
|
64
|
+
/** Above this many ticks the sizes are not listed one by one: the range is left to the layout. */
|
|
65
|
+
const MOST_LISTED = 1000;
|
|
66
|
+
/**
|
|
67
|
+
* The most ticks the scale makes: `maxTicksLimit || 11`, at least two. The scale's own limit
|
|
68
|
+
* (`computeTickLimit`, its length over the font's line height) has no cap, so a larger
|
|
69
|
+
* `maxTicksLimit` is reached on a long scale (K10). A fractional limit is a count of its own (not modelled).
|
|
70
|
+
*/
|
|
71
|
+
function mostTicks(config, scale) {
|
|
72
|
+
const limit = readFact(config, [...scale, 'ticks', 'maxTicksLimit'], isNumber, MAX_TICKS);
|
|
73
|
+
if (!limit.known)
|
|
74
|
+
return limit;
|
|
75
|
+
if (!Number.isInteger(limit.value))
|
|
76
|
+
return unknown(limit.path, 'unmodelled');
|
|
77
|
+
if (limit.value > MOST_LISTED)
|
|
78
|
+
return unknown(limit.path, 'layout');
|
|
79
|
+
return { ...limit, value: Math.max(2, limit.value === 0 ? MAX_TICKS.value : limit.value) };
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* The ranges a linear value scale with `beginAtZero: false` can take. Its tick limit depends on the
|
|
83
|
+
* scale's length (`computeTickLimit`, :10373), so every limit from 2 to 11 (or to `ticks.maxTicksLimit`)
|
|
84
|
+
* is a size the chart can be drawn at; Chart.js widens the range over its layout passes, so the drawn
|
|
85
|
+
* range lies between them. With `bounds: 'data'` the range is the data's.
|
|
86
|
+
*/
|
|
87
|
+
function ranges(config, scale, data) {
|
|
88
|
+
const at = formatPath(scale);
|
|
89
|
+
const bounds = readFact(config, [...scale, 'bounds'], isString, BOUNDS);
|
|
90
|
+
if (!bounds.known)
|
|
91
|
+
return bounds;
|
|
92
|
+
const [min, max] = widened(data);
|
|
93
|
+
if (bounds.value === 'data')
|
|
94
|
+
return { known: true, value: [[min, max]], path: at, source: 'config' };
|
|
95
|
+
if (bounds.value !== 'ticks')
|
|
96
|
+
return unknown(bounds.path, 'unmodelled');
|
|
97
|
+
const most = mostTicks(config, scale);
|
|
98
|
+
if (!most.known)
|
|
99
|
+
return most;
|
|
100
|
+
const value = Array.from({ length: most.value - 1 }, (_, index) => tickRange(min, max, index + 2));
|
|
101
|
+
return { known: true, value, path: at, source: 'config' };
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Why the fit of the scale is not modelled: an option in `UNMODELLED`, or a dataset with `hidden`
|
|
105
|
+
* (left out of the range, `getMatchingVisibleMetas`). Undefined when it is modelled.
|
|
106
|
+
*/
|
|
107
|
+
function unmodelled(config, scale, datasets) {
|
|
108
|
+
if (UNMODELLED.some((path) => holds(config, [...scale, ...path])))
|
|
109
|
+
return 'unmodelled';
|
|
110
|
+
if (!datasets.known)
|
|
111
|
+
return datasets.reason;
|
|
112
|
+
return datasets.items.some(({ segments }) => holds(config, [...segments, 'hidden'])) ? 'unmodelled' : undefined;
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Where zero is in the range a linear value scale fits to the data when its `beginAtZero` is `false`
|
|
116
|
+
* (bar charts set it `true` for their value scale). Hidden datasets and the options in `UNMODELLED`
|
|
117
|
+
* are not modelled.
|
|
118
|
+
*/
|
|
119
|
+
export function fitOf(config, key, type, { series, datasets }) {
|
|
120
|
+
const scale = ['options', 'scales', key];
|
|
121
|
+
const asked = readFact(config, [...scale, 'beginAtZero'], isBoolean);
|
|
122
|
+
if (!asked.known)
|
|
123
|
+
return asked;
|
|
124
|
+
if (asked.value)
|
|
125
|
+
return unknown(asked.path, 'inapplicable');
|
|
126
|
+
if (!type.known || type.value !== 'linear')
|
|
127
|
+
return unknown(asked.path, type.known ? 'inapplicable' : type.reason);
|
|
128
|
+
const reason = unmodelled(config, scale, datasets);
|
|
129
|
+
if (reason !== undefined)
|
|
130
|
+
return unknown(asked.path, reason);
|
|
131
|
+
const data = dataRange(series, key, asked.path);
|
|
132
|
+
if (!data.known)
|
|
133
|
+
return data;
|
|
134
|
+
const fitted = ranges(config, scale, data.value);
|
|
135
|
+
return fitted.known ? zeroFit(fitted.value, asked) : fitted;
|
|
136
|
+
}
|
|
137
|
+
//# sourceMappingURL=fit.js.map
|
package/dist/fit.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fit.js","sourceRoot":"","sources":["../src/fit.ts"],"names":[],"mappings":"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"}
|
package/dist/fixes.d.ts
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { type LinearScale, type Remedies } from '@chartguard/quality-core';
|
|
2
|
+
/** Chart.js remedies (CG-05-06), each verified by the review before it is offered. */
|
|
3
|
+
export declare const REMEDIES: Remedies;
|
|
4
|
+
/** The linear scale `bar-log-scale` proposes (CG-05-07 Q2.2: only while the bars span less than 10×). */
|
|
5
|
+
export declare const LINEAR: LinearScale;
|
|
6
|
+
//# sourceMappingURL=fixes.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fixes.d.ts","sourceRoot":"","sources":["../src/fixes.ts"],"names":[],"mappings":"AAAA,OAAO,EAEN,KAAK,WAAW,EAEhB,KAAK,QAAQ,EAGb,MAAM,0BAA0B,CAAC;AAElC,sFAAsF;AACtF,eAAO,MAAM,QAAQ,EAAE,QAqBtB,CAAC;AAEF,yGAAyG;AACzG,eAAO,MAAM,MAAM,EAAE,WAIpB,CAAC"}
|
package/dist/fixes.js
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { currentNumber, LONG_MOTION_MS, SHORT_MOTION_MS } from '@chartguard/quality-core';
|
|
2
|
+
/** Chart.js remedies (CG-05-06), each verified by the review before it is offered. */
|
|
3
|
+
export const REMEDIES = {
|
|
4
|
+
'bar-baseline': (now) => {
|
|
5
|
+
const value = currentNumber(now);
|
|
6
|
+
if (value !== undefined && value !== 0)
|
|
7
|
+
return { value: 0, effect: 'The bars grow from zero again, so their lengths are proportional to their values.' };
|
|
8
|
+
return now.set && now.value === false
|
|
9
|
+
? { value: true, effect: 'The value scale includes zero again (`beginAtZero: true`), so the bars grow from it.' }
|
|
10
|
+
: undefined;
|
|
11
|
+
},
|
|
12
|
+
'reversed-value-axis': (now) => now.set && now.value === true
|
|
13
|
+
? { value: false, effect: 'Larger values are drawn higher (or further right) again.' }
|
|
14
|
+
: undefined,
|
|
15
|
+
'long-motion': (now, path) => {
|
|
16
|
+
if (path.endsWith('.loop') && now.set && now.value === true)
|
|
17
|
+
return { value: false, effect: 'The animation runs once instead of forever.' };
|
|
18
|
+
const value = currentNumber(now);
|
|
19
|
+
return path.endsWith('.duration') && value !== undefined && value > LONG_MOTION_MS
|
|
20
|
+
? { value: SHORT_MOTION_MS, effect: 'The animation lasts one second instead of more than five.' }
|
|
21
|
+
: undefined;
|
|
22
|
+
}
|
|
23
|
+
};
|
|
24
|
+
/** The linear scale `bar-log-scale` proposes (CG-05-07 Q2.2: only while the bars span less than 10×). */
|
|
25
|
+
export const LINEAR = {
|
|
26
|
+
log: 'logarithmic',
|
|
27
|
+
linear: 'linear',
|
|
28
|
+
effect: 'The value scale is linear, so bar lengths encode the values; very small values may become hard to see.'
|
|
29
|
+
};
|
|
30
|
+
//# sourceMappingURL=fixes.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fixes.js","sourceRoot":"","sources":["../src/fixes.ts"],"names":[],"mappings":"AAAA,OAAO,EACN,aAAa,EAEb,cAAc,EAGd,eAAe,EACf,MAAM,0BAA0B,CAAC;AAElC,sFAAsF;AACtF,MAAM,CAAC,MAAM,QAAQ,GAAa;IACjC,cAAc,EAAE,CAAC,GAAG,EAAsB,EAAE;QAC3C,MAAM,KAAK,GAAG,aAAa,CAAC,GAAG,CAAC,CAAC;QACjC,IAAI,KAAK,KAAK,SAAS,IAAI,KAAK,KAAK,CAAC;YACrC,OAAO,EAAE,KAAK,EAAE,CAAC,EAAE,MAAM,EAAE,mFAAmF,EAAE,CAAC;QAClH,OAAO,GAAG,CAAC,GAAG,IAAI,GAAG,CAAC,KAAK,KAAK,KAAK;YACpC,CAAC,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,sFAAsF,EAAE;YACjH,CAAC,CAAC,SAAS,CAAC;IACd,CAAC;IACD,qBAAqB,EAAE,CAAC,GAAG,EAAE,EAAE,CAC9B,GAAG,CAAC,GAAG,IAAI,GAAG,CAAC,KAAK,KAAK,IAAI;QAC5B,CAAC,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,0DAA0D,EAAE;QACtF,CAAC,CAAC,SAAS;IACb,aAAa,EAAE,CAAC,GAAG,EAAE,IAAI,EAAE,EAAE;QAC5B,IAAI,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI,GAAG,CAAC,GAAG,IAAI,GAAG,CAAC,KAAK,KAAK,IAAI;YAC1D,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,6CAA6C,EAAE,CAAC;QAChF,MAAM,KAAK,GAAG,aAAa,CAAC,GAAG,CAAC,CAAC;QACjC,OAAO,IAAI,CAAC,QAAQ,CAAC,WAAW,CAAC,IAAI,KAAK,KAAK,SAAS,IAAI,KAAK,GAAG,cAAc;YACjF,CAAC,CAAC,EAAE,KAAK,EAAE,eAAe,EAAE,MAAM,EAAE,2DAA2D,EAAE;YACjG,CAAC,CAAC,SAAS,CAAC;IACd,CAAC;CACD,CAAC;AAEF,yGAAyG;AACzG,MAAM,CAAC,MAAM,MAAM,GAAgB;IAClC,GAAG,EAAE,aAAa;IAClB,MAAM,EAAE,QAAQ;IAChB,MAAM,EAAE,wGAAwG;CAChH,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { QualityReport } from '@chartguard/core';
|
|
2
|
+
import { type ChartSemantics, type QualityOptions } from '@chartguard/quality-core';
|
|
3
|
+
/** The Chart.js config as library-neutral chart semantics (CG-05-02, CG-05-03). */
|
|
4
|
+
export declare function normalize(config: unknown): ChartSemantics;
|
|
5
|
+
/** The options `analyze` takes, and their check: re-exported so a consumer needs only this adapter. */
|
|
6
|
+
export type { QualityOptions } from '@chartguard/quality-core';
|
|
7
|
+
export { assertQualityOptions, QualityOptionsError } from '@chartguard/quality-core';
|
|
8
|
+
/** The rules' advisory findings on the config, shaped by the caller's rule settings and context (CG-05-05). */
|
|
9
|
+
export declare function analyze(config: unknown, options?: QualityOptions): QualityReport;
|
|
10
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACtD,OAAO,EACN,KAAK,cAAc,EAOnB,KAAK,cAAc,EAMnB,MAAM,0BAA0B,CAAC;AAelC,mFAAmF;AACnF,wBAAgB,SAAS,CAAC,MAAM,EAAE,OAAO,GAAG,cAAc,CA6BzD;AAED,uGAAuG;AACvG,YAAY,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAC/D,OAAO,EAAE,oBAAoB,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAErF,+GAA+G;AAC/G,wBAAgB,OAAO,CAAC,MAAM,EAAE,OAAO,EAAE,OAAO,CAAC,EAAE,cAAc,GAAG,aAAa,CAShF"}
|