From 0003bc193499481d9c7d9a7696c2ac8e89f6a91d Mon Sep 17 00:00:00 2001 From: Robert Monfera Date: Wed, 22 Sep 2021 11:44:45 +0200 Subject: [PATCH] refactor: scale improvements and TS 4.4 (#1383) * switch to TS 4.4 and bump other deps * type strength increase via removing many `any` occurrences * domain oriented generic typing for scales * replacement and future prevention of coercive `==` and `!=` ops * refactoring: simplification and shortening of numerous functions, about 300 runtime lines gone * removal of numerous let, if/then, optional parameters etc. BREAKING CHANGE: The public type varieties for domains are discontinued, in favor of retaining the single `DomainRange` export, which now has a mandatory `{min: number, max: number}`. The developer can supply `NaN` where a finite min, max or both aren't defined (ie. in place of former effective `undefined`). In addition, some console.warn punctuations changed Co-authored-by: Marco Vettorello Co-authored-by: Nick Partridge --- .eslintrc.js | 5 +- integration/page_objects/common.ts | 28 +- .../mocks/@storybook/addon-knobs/index.ts | 21 +- package.json | 11 +- packages/charts/api/charts.api.md | 36 +- .../heatmap/layout/viewmodel/viewmodel.ts | 2 +- .../selectors/get_legend_items_labels.ts | 10 +- .../selectors/get_x_axis_right_overflow.ts | 2 +- .../layout/utils/legend_labels.ts | 7 +- .../layout/viewmodel/hierarchy_of_arrays.ts | 17 +- .../layout/viewmodel/scenegraph.ts | 4 +- .../xy_chart/annotations/line/dimensions.ts | 25 +- .../rect/dimensions.integration.test.ts | 2 +- .../xy_chart/annotations/rect/dimensions.ts | 46 +-- .../src/chart_types/xy_chart/domains/nice.ts | 12 - .../xy_chart/domains/x_domain.test.ts | 33 +- .../chart_types/xy_chart/domains/x_domain.ts | 108 ++---- .../xy_chart/domains/y_domain.test.ts | 25 +- .../chart_types/xy_chart/domains/y_domain.ts | 130 ++----- .../xy_chart/rendering/rendering.bars.test.ts | 9 +- .../rendering/rendering.bubble.test.ts | 4 +- .../rendering/rendering.lines.test.ts | 4 +- .../state/selectors/compute_annotations.ts | 5 +- .../selectors/compute_per_panel_axes_geoms.ts | 13 +- .../compute_small_multiple_scales.ts | 7 +- .../state/selectors/get_api_scale_configs.ts | 7 +- .../state/selectors/get_cursor_band.ts | 2 +- .../selectors/get_elements_at_cursor_pos.ts | 2 +- .../state/selectors/get_highlighted_series.ts | 9 +- .../state/selectors/get_highlighted_values.ts | 4 +- .../selectors/get_legend_items_labels.ts | 13 +- .../state/selectors/merge_y_custom_domains.ts | 37 +- .../state/selectors/on_brush_end_caller.ts | 8 +- .../chart_types/xy_chart/state/utils/types.ts | 2 +- .../xy_chart/state/utils/utils.test.ts | 4 + .../chart_types/xy_chart/state/utils/utils.ts | 10 +- .../chart_types/xy_chart/tooltip/tooltip.ts | 4 +- .../xy_chart/utils/axis_type_utils.test.ts | 15 +- .../xy_chart/utils/axis_type_utils.ts | 21 -- .../xy_chart/utils/axis_utils.test.ts | 8 + .../chart_types/xy_chart/utils/axis_utils.ts | 29 +- .../chart_types/xy_chart/utils/panel_utils.ts | 21 +- .../src/chart_types/xy_chart/utils/scales.ts | 38 +- .../chart_types/xy_chart/utils/series.test.ts | 10 +- .../src/chart_types/xy_chart/utils/specs.ts | 36 +- packages/charts/src/components/icons/icon.tsx | 3 +- .../charts/src/components/legend/utils.ts | 10 +- .../src/components/portal/tooltip_portal.tsx | 11 +- .../charts/src/components/portal/utils.ts | 2 +- packages/charts/src/mocks/specs/specs.ts | 1 + packages/charts/src/scales/index.ts | 9 +- packages/charts/src/scales/scale_band.test.ts | 4 +- packages/charts/src/scales/scale_band.ts | 43 +-- .../charts/src/scales/scale_continuous.ts | 14 +- packages/charts/src/scales/types.ts | 2 +- .../selectors/is_external_tooltip_visible.ts | 2 +- packages/charts/src/utils/common.test.ts | 11 - packages/charts/src/utils/common.tsx | 5 - .../charts/src/utils/d3-delaunay/index.ts | 4 +- packages/charts/src/utils/dimensions.ts | 2 +- packages/charts/src/utils/domain.test.ts | 104 +++--- packages/charts/src/utils/domain.ts | 95 ++--- packages/charts/src/utils/fast_deep_equal.ts | 2 +- storybook/package.json | 2 +- .../stories/bar/32_scale_to_extent.story.tsx | 10 +- storybook/webpack.config.js | 4 +- yarn.lock | 331 +++++++++++------- 67 files changed, 625 insertions(+), 892 deletions(-) delete mode 100644 packages/charts/src/chart_types/xy_chart/domains/nice.ts diff --git a/.eslintrc.js b/.eslintrc.js index 694b28038d..19699c5be6 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -90,11 +90,12 @@ module.exports = { 'jsx-a11y/mouse-events-have-key-events': 1, 'jsx-a11y/click-events-have-key-events': 1, '@typescript-eslint/member-ordering': 1, - eqeqeq: 1, + eqeqeq: 2, /* * Standard rules */ + '@typescript-eslint/object-curly-spacing': 0, 'no-restricted-syntax': 0, // this is a good rule, for-of is good 'no-console': process.env.NODE_ENV === 'production' ? 2 : 1, 'no-debugger': process.env.NODE_ENV === 'production' ? 2 : 1, @@ -112,7 +113,7 @@ module.exports = { 'no-continue': 0, 'no-lonely-if': 0, 'no-return-assign': 0, - 'no-underscore-dangle': 0, + 'no-underscore-dangle': ['error', { allow: ['__REDUX_DEVTOOLS_EXTENSION_COMPOSE__'] }], 'no-confusing-arrow': 0, 'prefer-destructuring': 0, 'function-paren-newline': 0, diff --git a/integration/page_objects/common.ts b/integration/page_objects/common.ts index c2590dbbda..164fa8af0e 100644 --- a/integration/page_objects/common.ts +++ b/integration/page_objects/common.ts @@ -321,27 +321,23 @@ class CommonPage { selector: string = 'body', options?: ScreenshotElementAtUrlOptions, ) { - try { - await this.loadElementFromURL(url, options?.waitSelector ?? selector, options?.timeout); + await this.loadElementFromURL(url, options?.waitSelector ?? selector, options?.timeout); - if (options?.action) { - await options.action(); - } - - if (options?.delay) { - await page.waitFor(options.delay); - } + if (options?.action) { + await options.action(); + } - const element = await this.screenshotDOMElement(options?.screenshotSelector ?? selector, options); + if (options?.delay) { + await page.waitFor(options.delay); + } - if (!element) { - throw new Error(`Error: Unable to find element\n\n\t${url}`); - } + const element = await this.screenshotDOMElement(options?.screenshotSelector ?? selector, options); - expect(element).toMatchImageSnapshot(); - } catch (error) { - throw new Error(error); + if (!element) { + throw new Error(`Error: Unable to find element\n\n\t${url}`); } + + expect(element).toMatchImageSnapshot(); } /** diff --git a/integration/server/mocks/@storybook/addon-knobs/index.ts b/integration/server/mocks/@storybook/addon-knobs/index.ts index 5a3b2edc49..abe2869fed 100644 --- a/integration/server/mocks/@storybook/addon-knobs/index.ts +++ b/integration/server/mocks/@storybook/addon-knobs/index.ts @@ -15,13 +15,8 @@ function getKnobKey(name: string, groupId?: string) { } export function boolean(name: string, dftValue: boolean, groupId?: string) { - const params = getParams(); - const key = getKnobKey(name, groupId); - const param = params.get(key); - if (param === '' || param == null) { - return dftValue; - } - return params.get(key) === 'true'; + const param = getParams().get(getKnobKey(name, groupId)); + return param ? param === 'true' : dftValue; } export function number(name: string, dftValue: number, options?: any, groupId?: string) { @@ -43,19 +38,15 @@ export function select(name: string, b: unknown, dftValue: string, groupId?: str } export function text(name: string, dftValue: string, groupId?: string) { - const params = getParams(); - const key = getKnobKey(name, groupId); - const value = params.get(key); - if (value != null) { - // the # used for the color knob needs to be escaped on the URL and unescaped here - return unescape(value); - } - return dftValue; + const value = getParams().get(getKnobKey(name, groupId)); + // the # used for the color knob needs to be escaped on the URL and unescaped here + return value === null ? dftValue : unescape(value); } export function array(name: string, dftValues: unknown[], options: any, groupId?: string) { const params = getParams(); const values = []; + // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore for (const [key, value] of params) { if (key.startsWith(`${getKnobKey(name, groupId)}[`)) { diff --git a/package.json b/package.json index 1b296ac0a4..6fe17e1972 100644 --- a/package.json +++ b/package.json @@ -68,7 +68,7 @@ "@elastic/eui": "^38.0.0", "@mdx-js/loader": "^1.6.6", "@microsoft/api-documenter": "^7.12.7", - "@microsoft/api-extractor": "^7.13.1", + "@microsoft/api-extractor": "^7.18.9", "@semantic-release/changelog": "^5.0.1", "@semantic-release/commit-analyzer": "^8.0.1", "@semantic-release/exec": "^5.0.0", @@ -102,8 +102,8 @@ "@types/seedrandom": "^2.4.28", "@types/url-parse": "^1.4.3", "@types/uuid": "^3.4.4", - "@typescript-eslint/eslint-plugin": "^4.12.0", - "@typescript-eslint/parser": "^4.12.0", + "@typescript-eslint/eslint-plugin": "^4.31.1", + "@typescript-eslint/parser": "^4.31.1", "autoprefixer": "^9.0.0", "backport": "^5.6.6", "canvas": "^2.8.0", @@ -113,7 +113,8 @@ "enzyme": "^3.11.0", "enzyme-adapter-react-16": "^1.15.5", "eslint": "^7.17.0", - "eslint-config-airbnb-typescript": "^12.0.0", + "eslint-config-airbnb": "^18.2.1", + "eslint-config-airbnb-typescript": "^14.0.0", "eslint-config-prettier": "^7.1.0", "eslint-plugin-elastic-charts": "link:./packages/eslint-plugin-elastic-charts", "eslint-plugin-eslint-comments": "^3.2.0", @@ -167,7 +168,7 @@ "speed-measure-webpack-plugin": "^1.5.0", "ts-jest": "^26.5.5", "ts-prune": "^0.8.4", - "typescript": "^4.1.3", + "typescript": "^4.4.3", "webpack": "^4.46.0", "webpack-cli": "^4.8.0", "webpack-dev-server": "^4.1.0" diff --git a/packages/charts/api/charts.api.md b/packages/charts/api/charts.api.md index 4bb3c9c78c..1138d28e62 100644 --- a/packages/charts/api/charts.api.md +++ b/packages/charts/api/charts.api.md @@ -410,7 +410,7 @@ export class Chart extends React_2.Component { } | null; // (undocumented) render(): JSX.Element; - } +} // @public (undocumented) export type ChartSize = number | string | ChartSizeArray | ChartSizeObject; @@ -473,13 +473,6 @@ export const ColorVariant: Readonly<{ // @public (undocumented) export type ColorVariant = $Values; -// Warning: (ae-forgotten-export) The symbol "DomainBase" needs to be exported by the entry point index.d.ts -// Warning: (ae-forgotten-export) The symbol "LowerBound" needs to be exported by the entry point index.d.ts -// Warning: (ae-forgotten-export) The symbol "UpperBound" needs to be exported by the entry point index.d.ts -// -// @public (undocumented) -export type CompleteBoundedDomain = DomainBase & LowerBound & UpperBound; - // @public export type ComponentWithAnnotationDatum = ComponentType; @@ -564,7 +557,7 @@ export class DataGenerator { y: number; g: string; }[]; - } +} // @public (undocumented) export type DataName = CategoryKey; @@ -706,7 +699,13 @@ export const DomainPaddingUnit: Readonly<{ export type DomainPaddingUnit = $Values; // @public (undocumented) -export type DomainRange = LowerBoundedDomain | UpperBoundedDomain | CompleteBoundedDomain | UnboundedDomainWithInterval; +export interface DomainRange { + // (undocumented) + max: number; + min: number; + // (undocumented) + minInterval?: number; +} // @public (undocumented) export type ElementClickListener = (elements: Array) => void; @@ -1109,9 +1108,9 @@ export type HistogramModeAlignment = 'start' | 'center' | 'end'; // @public (undocumented) export const HistogramModeAlignments: Readonly<{ - Start: LineAlignSetting; - Center: LineAlignSetting; - End: LineAlignSetting; + Start: HistogramModeAlignment; + Center: HistogramModeAlignment; + End: HistogramModeAlignment; }>; // @public (undocumented) @@ -1359,9 +1358,6 @@ export interface LogScaleOptions { logMinLimit?: number; } -// @public (undocumented) -export type LowerBoundedDomain = DomainBase & LowerBound; - // @public export type MarkBuffer = number | ((radius: number) => number); @@ -1534,7 +1530,6 @@ export type Placement = $Values; // @public (undocumented) type PointerEvent_2 = PointerOverEvent | PointerOutEvent; - export { PointerEvent_2 as PointerEvent } // @public (undocumented) @@ -2256,12 +2251,6 @@ export interface UnaryAccessorFn { fieldName?: string; } -// @public (undocumented) -export type UnboundedDomainWithInterval = DomainBase; - -// @public (undocumented) -export type UpperBoundedDomain = DomainBase & UpperBound; - // @public (undocumented) export type ValueAccessor = (d: Datum) => AdditiveNumber; @@ -2433,7 +2422,6 @@ export interface YDomainBase { // @public (undocumented) export type YDomainRange = YDomainBase & DomainRange & LogScaleOptions; - // Warnings were encountered during analysis: // // src/chart_types/heatmap/layout/types/config_types.ts:19:13 - (ae-forgotten-export) The symbol "SizeRatio" needs to be exported by the entry point index.d.ts diff --git a/packages/charts/src/chart_types/heatmap/layout/viewmodel/viewmodel.ts b/packages/charts/src/chart_types/heatmap/layout/viewmodel/viewmodel.ts index 455af53328..a91e82f322 100644 --- a/packages/charts/src/chart_types/heatmap/layout/viewmodel/viewmodel.ts +++ b/packages/charts/src/chart_types/heatmap/layout/viewmodel/viewmodel.ts @@ -107,7 +107,7 @@ export function shapeViewModel( ? new ScaleContinuous( { type: ScaleType.Time, - domain: xDomain.domain, + domain: xDomain.domain as number[], range: [0, chartDimensions.width], nice: false, }, diff --git a/packages/charts/src/chart_types/heatmap/state/selectors/get_legend_items_labels.ts b/packages/charts/src/chart_types/heatmap/state/selectors/get_legend_items_labels.ts index 9f1dd2fde8..94b932c073 100644 --- a/packages/charts/src/chart_types/heatmap/state/selectors/get_legend_items_labels.ts +++ b/packages/charts/src/chart_types/heatmap/state/selectors/get_legend_items_labels.ts @@ -15,10 +15,8 @@ import { computeLegendSelector } from './compute_legend'; export const getLegendItemsLabelsSelector = createCustomCachedSelector( [computeLegendSelector, getSettingsSpecSelector], (legendItems, { showLegendExtra }): LegendItemLabel[] => - legendItems.map(({ label, defaultExtra }) => { - if (defaultExtra?.formatted != null) { - return { label: `${label}${showLegendExtra ? defaultExtra.formatted : ''}`, depth: 0 }; - } - return { label, depth: 0 }; - }), + legendItems.map(({ label, defaultExtra }) => ({ + label: `${label}${showLegendExtra ? defaultExtra?.formatted ?? '' : ''}`, + depth: 0, + })), ); diff --git a/packages/charts/src/chart_types/heatmap/state/selectors/get_x_axis_right_overflow.ts b/packages/charts/src/chart_types/heatmap/state/selectors/get_x_axis_right_overflow.ts index a06de80717..03add7284f 100644 --- a/packages/charts/src/chart_types/heatmap/state/selectors/get_x_axis_right_overflow.ts +++ b/packages/charts/src/chart_types/heatmap/state/selectors/get_x_axis_right_overflow.ts @@ -30,7 +30,7 @@ export const getXAxisRightOverflow = createCustomCachedSelector( const timeScale = new ScaleContinuous( { type: ScaleType.Time, - domain: xDomain.domain, + domain: xDomain.domain as number[], range: [0, 1], }, { diff --git a/packages/charts/src/chart_types/partition_chart/layout/utils/legend_labels.ts b/packages/charts/src/chart_types/partition_chart/layout/utils/legend_labels.ts index a73bb1f7b5..1a4cae5c9e 100644 --- a/packages/charts/src/chart_types/partition_chart/layout/utils/legend_labels.ts +++ b/packages/charts/src/chart_types/partition_chart/layout/utils/legend_labels.ts @@ -29,12 +29,9 @@ function flatSlicesNames( // format the key with the layer formatter const layer = layers[depth - 1]; const formatter = layer?.nodeLabel; - let formattedValue = ''; - if (key != null) { - formattedValue = formatter ? formatter(key) : `${key}`; - } + const formattedValue = formatter ? formatter(key) : `${key}`; // preventing errors from external formatters - if (formattedValue != null && formattedValue !== '' && formattedValue !== HIERARCHY_ROOT_KEY) { + if (formattedValue && formattedValue !== HIERARCHY_ROOT_KEY) { // save only the max depth, so we can compute the the max extension of the legend keys.set(formattedValue, Math.max(depth, keys.get(formattedValue) ?? 0)); } diff --git a/packages/charts/src/chart_types/partition_chart/layout/viewmodel/hierarchy_of_arrays.ts b/packages/charts/src/chart_types/partition_chart/layout/viewmodel/hierarchy_of_arrays.ts index 3e66eb157e..66ed92433c 100644 --- a/packages/charts/src/chart_types/partition_chart/layout/viewmodel/hierarchy_of_arrays.ts +++ b/packages/charts/src/chart_types/partition_chart/layout/viewmodel/hierarchy_of_arrays.ts @@ -115,18 +115,11 @@ export function getExtraValueMap( const branch = tree[i]; const [key, arrayNode] = branch; const { value, path, [CHILDREN_KEY]: children } = arrayNode; - - if (key != null) { - const values: LegendItemExtraValues = new Map(); - const formattedValue = valueFormatter ? valueFormatter(value) : value; - - values.set(key, formattedValue); - keys.set(path.map(({ index }) => index).join('__'), values); - } - - if (depth < maxDepth) { - getExtraValueMap(layers, valueFormatter, children, maxDepth, depth + 1, keys); - } + const values: LegendItemExtraValues = new Map(); + const formattedValue = valueFormatter ? valueFormatter(value) : value; + values.set(key, formattedValue); + keys.set(path.map(({ index }) => index).join('__'), values); + if (depth < maxDepth) getExtraValueMap(layers, valueFormatter, children, maxDepth, depth + 1, keys); } return keys; } diff --git a/packages/charts/src/chart_types/partition_chart/layout/viewmodel/scenegraph.ts b/packages/charts/src/chart_types/partition_chart/layout/viewmodel/scenegraph.ts index 671af9078f..5a80b2ca6e 100644 --- a/packages/charts/src/chart_types/partition_chart/layout/viewmodel/scenegraph.ts +++ b/packages/charts/src/chart_types/partition_chart/layout/viewmodel/scenegraph.ts @@ -8,7 +8,7 @@ import { measureText } from '../../../../common/text_utils'; import { SmallMultiplesStyle } from '../../../../specs'; -import { Color, identity, mergePartial, RecursivePartial } from '../../../../utils/common'; +import { Color, mergePartial, RecursivePartial } from '../../../../utils/common'; import { Dimensions } from '../../../../utils/dimensions'; import { Layer, PartitionSpec } from '../../specs'; import { config as defaultConfig, VALUE_GETTERS } from '../config'; @@ -26,7 +26,7 @@ import { shapeViewModel } from './viewmodel'; function rawTextGetter(layers: Layer[]): RawTextGetter { return (node: ShapeTreeNode) => { - const accessorFn = layers[node[DEPTH_KEY] - 1].nodeLabel || identity; + const accessorFn = layers[node[DEPTH_KEY] - 1].nodeLabel || ((d) => d); return `${accessorFn(node.dataName)}`; }; } diff --git a/packages/charts/src/chart_types/xy_chart/annotations/line/dimensions.ts b/packages/charts/src/chart_types/xy_chart/annotations/line/dimensions.ts index 71a999fef6..e73e8cdf73 100644 --- a/packages/charts/src/chart_types/xy_chart/annotations/line/dimensions.ts +++ b/packages/charts/src/chart_types/xy_chart/annotations/line/dimensions.ts @@ -8,7 +8,7 @@ import { Line } from '../../../../geoms/types'; import { Scale } from '../../../../scales'; -import { isContinuousScale, isBandScale } from '../../../../scales/types'; +import { isBandScale, isContinuousScale } from '../../../../scales/types'; import { isNil, Position, Rotation } from '../../../../utils/common'; import { Dimensions, Size } from '../../../../utils/dimensions'; import { GroupId } from '../../../../utils/ids'; @@ -17,7 +17,7 @@ import { SmallMultipleScales } from '../../state/selectors/compute_small_multipl import { isHorizontalRotation, isVerticalRotation } from '../../state/utils/common'; import { computeXScaleOffset } from '../../state/utils/utils'; import { getPanelSize } from '../../utils/panel'; -import { AnnotationDomainType, LineAnnotationSpec, LineAnnotationDatum } from '../../utils/specs'; +import { AnnotationDomainType, LineAnnotationDatum, LineAnnotationSpec } from '../../utils/specs'; import { AnnotationLineProps } from './types'; function computeYDomainLineAnnotationDimensions( @@ -155,32 +155,27 @@ function computeXDomainLineAnnotationDimensions( if (isHistogramMode) { const offset = computeXScaleOffset(xScale, true); const pureScaledValue = xScale.pureScale(dataValue); - if (pureScaledValue == null) { - return; + if (typeof pureScaledValue === 'number') { + // Number.isFinite is regrettably not a type guard yet https://github.com/microsoft/TypeScript/issues/10038#issuecomment-924115831 + annotationValueXPosition = pureScaledValue - offset; } - annotationValueXPosition = pureScaledValue - offset; } else { annotationValueXPosition += (xScale.bandwidth * xScale.totalBarsInCluster) / 2; } } else if (isBandScale(xScale)) { - if (isHistogramMode) { - const padding = (xScale.step - xScale.originalBandwidth) / 2; - annotationValueXPosition -= padding; - } else { - annotationValueXPosition += xScale.originalBandwidth / 2; - } + annotationValueXPosition += isHistogramMode + ? -(xScale.step - xScale.originalBandwidth) / 2 + : xScale.originalBandwidth / 2; } else { return; } - if (isNaN(annotationValueXPosition) || annotationValueXPosition == null) { + if (!isFinite(annotationValueXPosition)) { return; } vertical.domain.forEach((verticalValue) => { horizontal.domain.forEach((horizontalValue) => { - if (annotationValueXPosition == null) { - return; - } + if (annotationValueXPosition === null) return; const top = vertical.scaleOrThrow(verticalValue); const left = horizontal.scaleOrThrow(horizontalValue); diff --git a/packages/charts/src/chart_types/xy_chart/annotations/rect/dimensions.integration.test.ts b/packages/charts/src/chart_types/xy_chart/annotations/rect/dimensions.integration.test.ts index 1b81edf12f..fd69cac3e2 100644 --- a/packages/charts/src/chart_types/xy_chart/annotations/rect/dimensions.integration.test.ts +++ b/packages/charts/src/chart_types/xy_chart/annotations/rect/dimensions.integration.test.ts @@ -267,7 +267,7 @@ describe('Render rect annotation within', () => { const heightFromStore = 200; const store = MockStore.default({ top: 0, left: 0, width: 20, height: heightFromStore }); const settings = MockGlobalSpec.settingsNoMargins(); - const yDomainFitted = MockGlobalSpec.axis({ domain: { fit: true } }); + const yDomainFitted = MockGlobalSpec.axis({ domain: { min: NaN, max: NaN, fit: true } }); const annotation = MockAnnotationSpec.rect({ dataValues: [{ coordinates: { x0: 2, x1: 4 } }], }); diff --git a/packages/charts/src/chart_types/xy_chart/annotations/rect/dimensions.ts b/packages/charts/src/chart_types/xy_chart/annotations/rect/dimensions.ts index f0730f6401..7c47253031 100644 --- a/packages/charts/src/chart_types/xy_chart/annotations/rect/dimensions.ts +++ b/packages/charts/src/chart_types/xy_chart/annotations/rect/dimensions.ts @@ -50,14 +50,14 @@ export function computeRectAnnotationDimensions( const { x0: initialX0, x1: initialX1, y0: initialY0, y1: initialY1 } = datum.coordinates; // if everything is null, return; otherwise we coerce the other coordinates - if (initialX0 == null && initialX1 == null && initialY0 == null && initialY1 == null) { + if (initialX0 === null && initialX1 === null && initialY0 === null && initialY1 === null) { return; } let height: number | undefined; const [x0, x1] = limitValueToDomainRange(xScale, initialX0, initialX1, isHistogram); // something is wrong with the data types, don't draw this annotation - if (x0 == null || x1 == null) { + if (x0 === null || x1 === null) { return; } @@ -104,13 +104,13 @@ export function computeRectAnnotationDimensions( const [y0, y1] = limitValueToDomainRange(yScale, initialY0, initialY1); // something is wrong with the data types, don't draw this annotation - if (y0 == null || y1 == null) { + if (y0 === null || y1 === null) { return; } let scaledY1 = yScale.pureScale(y1); const scaledY0 = yScale.pureScale(y0); - if (scaledY1 == null || scaledY0 == null) { + if (scaledY1 === null || scaledY0 === null) { return; } height = Math.abs(scaledY0 - scaledY1); @@ -171,7 +171,7 @@ function scaleXonBandScale( const padding = (xScale.step - xScale.originalBandwidth) / 2; let scaledX1 = xScale.scale(x1); let scaledX0 = xScale.scale(x0); - if (scaledX1 == null || scaledX0 == null) { + if (scaledX1 === null || scaledX0 === null) { return null; } // extend the x1 scaled value to fully cover the last bar @@ -204,7 +204,7 @@ function scaleXonContinuousScale( const scaledX0 = xScale.scale(x0); const scaledX1: number | null = xScale.totalBarsInCluster > 0 && !isHistogramModeEnabled ? xScale.scale(x1 + xScale.minInterval) : xScale.scale(x1); - if (scaledX1 == null || scaledX0 == null) { + if (scaledX1 === null || scaledX0 === null) { return null; } // the width needs to be computed before adjusting the x anchor @@ -231,38 +231,18 @@ function limitValueToDomainRange( const [domainStartValue] = scale.domain; // this fix the case where rendering on categorical scale and we have only one element const domainEndValue = scale.domain.length > 0 ? scale.domain[scale.domain.length - 1] : scale.domain[0]; - - const min = getMin(domainStartValue, minValue); - - const max = getMax(isHistogram ? domainEndValue + scale.minInterval : domainEndValue, maxValue); + const min = maxOf(domainStartValue, minValue); + const max = minOf(isHistogram ? domainEndValue + scale.minInterval : domainEndValue, maxValue); // extend to edge values if values are null/undefined - if (!isContinuousScale(scale)) { - return [min, max]; - } - if (min !== null && max !== null && min > max) { - return [null, null]; - } - return [min, max]; + return isContinuousScale(scale) && min !== null && max !== null && min > max ? [null, null] : [min, max]; } -function getMax(max: number, value?: number | string | null) { - if (value == null) { - return max; - } - if (typeof value === 'number') { - return Math.min(value, max); - } - return value; +function minOf(base: number, value?: number | string | null | undefined): number | string { + return typeof value === 'number' ? Math.min(value, base) : typeof value === 'string' ? value : base; } -function getMin(min: number, value?: number | string | null) { - if (value == null) { - return min; - } - if (typeof value === 'number') { - return Math.max(value, min); - } - return value; +function maxOf(base: number, value: number | string | null | undefined): number | string { + return typeof value === 'number' ? Math.max(value, base) : typeof value === 'string' ? value : base; } function getOutsideDimension(style: AxisStyle): number { diff --git a/packages/charts/src/chart_types/xy_chart/domains/nice.ts b/packages/charts/src/chart_types/xy_chart/domains/nice.ts deleted file mode 100644 index f53adbb501..0000000000 --- a/packages/charts/src/chart_types/xy_chart/domains/nice.ts +++ /dev/null @@ -1,12 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0 and the Server Side Public License, v 1; you may not use this file except - * in compliance with, at your election, the Elastic License 2.0 or the Server - * Side Public License, v 1. - */ - -/** @internal */ -export function areAllNiceDomain(nice: Array) { - return nice.length > 0 && nice.every((d) => d); -} diff --git a/packages/charts/src/chart_types/xy_chart/domains/x_domain.test.ts b/packages/charts/src/chart_types/xy_chart/domains/x_domain.test.ts index 383b49d33c..4a5ef8c7d0 100644 --- a/packages/charts/src/chart_types/xy_chart/domains/x_domain.test.ts +++ b/packages/charts/src/chart_types/xy_chart/domains/x_domain.test.ts @@ -42,6 +42,7 @@ describe('X Domain', () => { type: getXScaleTypeFromSpec(ScaleType.Linear), nice: getXNiceFromSpec(), isBandScale: true, + timeZone: 'utc', }); }); @@ -57,6 +58,7 @@ describe('X Domain', () => { type: getXScaleTypeFromSpec(ScaleType.Ordinal), nice: getXNiceFromSpec(), isBandScale: true, + timeZone: 'utc', }); }); @@ -72,6 +74,7 @@ describe('X Domain', () => { type: getXScaleTypeFromSpec(ScaleType.Linear), nice: getXNiceFromSpec(), isBandScale: false, + timeZone: 'utc', }); }); test('Should return correct scale type with single line (time)', () => { @@ -149,6 +152,7 @@ describe('X Domain', () => { type: getXScaleTypeFromSpec(ScaleType.Ordinal), nice: getXNiceFromSpec(), isBandScale: false, + timeZone: 'utc', }); }); test('Should return correct scale type with multi bar, area with different scale types (linear, ordinal)', () => { @@ -167,6 +171,7 @@ describe('X Domain', () => { type: getXScaleTypeFromSpec(ScaleType.Ordinal), nice: getXNiceFromSpec(), isBandScale: true, + timeZone: 'utc', }); }); test('Should return correct scale type with multi bar, area with same scale types (linear, linear)', () => { @@ -186,6 +191,7 @@ describe('X Domain', () => { type: getXScaleTypeFromSpec(ScaleType.Linear), nice: getXNiceFromSpec(), isBandScale: true, + timeZone: 'utc+3', }); }); @@ -423,6 +429,7 @@ describe('X Domain', () => { const specDataSeries = [ds1, ds2]; const customDomain = { min: 0, + max: NaN, }; const { xValues } = getDataSeriesFromSpecs(specDataSeries); @@ -655,12 +662,12 @@ describe('X Domain', () => { xValues, ).domain; expect(domain).toEqual([1, 5]); - expect(Logger.warn).toBeCalledWith('custom xDomain is invalid, min is greater than max. Custom domain is ignored.'); + expect(Logger.warn).toBeCalledWith('Custom xDomain is invalid: min is greater than max. Custom domain is ignored.'); }); test('should account for custom domain when merging a linear domain: lower bounded domain', () => { const xValues = new Set([1, 2, 3, 4, 5]); - const xDomain = { min: 0 }; + const xDomain = { min: 0, max: NaN }; const specs = [MockSeriesSpec.line({ xScaleType: ScaleType.Linear })]; const mergedDomain = mergeXDomain( @@ -669,20 +676,20 @@ describe('X Domain', () => { ); expect(mergedDomain.domain).toEqual([0, 5]); - const invalidXDomain = { min: 10 }; + const invalidXDomain = { min: 10, max: NaN }; const { domain } = mergeXDomain( getScaleConfigsFromSpecs([], specs, MockGlobalSpec.settings({ xDomain: invalidXDomain })).x, xValues, ); expect(domain).toEqual([1, 5]); expect(Logger.warn).toBeCalledWith( - 'custom xDomain is invalid, custom min is greater than computed max. Custom domain is ignored.', + 'Custom xDomain is invalid: custom min is greater than computed max. Custom domain is ignored.', ); }); test('should account for custom domain when merging a linear domain: upper bounded domain', () => { const xValues = new Set([1, 2, 3, 4, 5]); - const xDomain = { max: 3 }; + const xDomain = { min: NaN, max: 3 }; const specs = [MockSeriesSpec.line({ xScaleType: ScaleType.Linear })]; const mergedDomain = mergeXDomain( @@ -691,14 +698,14 @@ describe('X Domain', () => { ); expect(mergedDomain.domain).toEqual([1, 3]); - const invalidXDomain = { max: -1 }; + const invalidXDomain = { min: NaN, max: -1 }; const { domain } = mergeXDomain( getScaleConfigsFromSpecs([], specs, MockGlobalSpec.settings({ xDomain: invalidXDomain })).x, xValues, ); expect(domain).toEqual([1, 5]); expect(Logger.warn).toBeCalledWith( - 'custom xDomain is invalid, computed min is greater than custom max. Custom domain is ignored.', + 'Custom xDomain is invalid: computed min is greater than custom max. Custom domain is ignored.', ); }); @@ -728,7 +735,7 @@ describe('X Domain', () => { const specs = [MockSeriesSpec.bar({ xScaleType: ScaleType.Linear })]; test('with valid minInterval', () => { - const xDomain = { minInterval: 0.5 }; + const xDomain = { minInterval: 0.5, min: NaN, max: NaN }; const mergedDomain = mergeXDomain( getScaleConfigsFromSpecs([], specs, MockGlobalSpec.settings({ xDomain })).x, xValues, @@ -737,7 +744,7 @@ describe('X Domain', () => { }); test('with valid minInterval greater than computed minInterval for single datum set', () => { - const xDomain = { minInterval: 10 }; + const xDomain = { minInterval: 10, min: NaN, max: NaN }; const mergedDomain = mergeXDomain( getScaleConfigsFromSpecs([], specs, MockGlobalSpec.settings({ xDomain })).x, new Set([5]), @@ -746,26 +753,26 @@ describe('X Domain', () => { }); test('with invalid minInterval greater than computed minInterval for multi data set', () => { - const invalidXDomain = { minInterval: 10 }; + const invalidXDomain = { minInterval: 10, min: NaN, max: NaN }; const { minInterval } = mergeXDomain( getScaleConfigsFromSpecs([], specs, MockGlobalSpec.settings({ xDomain: invalidXDomain })).x, xValues, ); expect(minInterval).toEqual(1); const expectedWarning = - 'custom xDomain is invalid, custom minInterval is greater than computed minInterval. Using computed minInterval.'; + 'Custom xDomain is invalid: custom minInterval is greater than computed minInterval. Using computed minInterval.'; expect(Logger.warn).toBeCalledWith(expectedWarning); }); test('with invalid minInterval less than 0', () => { - const invalidXDomain = { minInterval: -1 }; + const invalidXDomain = { minInterval: -1, min: NaN, max: NaN }; const { minInterval } = mergeXDomain( getScaleConfigsFromSpecs([], specs, MockGlobalSpec.settings({ xDomain: invalidXDomain })).x, xValues, ); expect(minInterval).toEqual(1); const expectedWarning = - 'custom xDomain is invalid, custom minInterval is less than 0. Using computed minInterval.'; + 'Custom xDomain is invalid: custom minInterval is less than 0. Using computed minInterval.'; expect(Logger.warn).toBeCalledWith(expectedWarning); }); }); diff --git a/packages/charts/src/chart_types/xy_chart/domains/x_domain.ts b/packages/charts/src/chart_types/xy_chart/domains/x_domain.ts index 9e0f1589aa..e9de518e7b 100644 --- a/packages/charts/src/chart_types/xy_chart/domains/x_domain.ts +++ b/packages/charts/src/chart_types/xy_chart/domains/x_domain.ts @@ -9,14 +9,12 @@ import { Optional } from 'utility-types'; import { ScaleType } from '../../../scales/constants'; -import { compareByValueAsc, identity } from '../../../utils/common'; +import { compareByValueAsc } from '../../../utils/common'; import { computeContinuousDataDomain, computeOrdinalDataDomain } from '../../../utils/domain'; import { Logger } from '../../../utils/logger'; import { getXNiceFromSpec, getXScaleTypeFromSpec } from '../scales/get_api_scales'; import { ScaleConfigs } from '../state/selectors/get_api_scale_configs'; -import { isCompleteBound, isLowerBound, isUpperBound } from '../utils/axis_type_utils'; import { BasicSeriesSpec, SeriesType, XScaleType } from '../utils/specs'; -import { areAllNiceDomain } from './nice'; import { XDomain } from './types'; /** @@ -28,7 +26,6 @@ export function mergeXDomain( xValues: Set, fallbackScale?: XScaleType, ): XDomain { - const values = [...xValues.values()]; let seriesXComputedDomains; let minInterval = 0; @@ -37,14 +34,13 @@ export function mergeXDomain( Logger.warn(`Each X value in a ${type} x scale needs be be a number. Using ordinal x scale as fallback.`); } - seriesXComputedDomains = computeOrdinalDataDomain(values, identity, false, true); + seriesXComputedDomains = computeOrdinalDataDomain([...xValues], false, true); if (customDomain) { if (Array.isArray(customDomain)) { seriesXComputedDomains = [...customDomain]; } else { if (fallbackScale === ScaleType.Ordinal) { Logger.warn(`xDomain ignored for fallback ordinal scale. Options to resolve: - 1) Correct data to match ${type} scale type (see previous warning) 2) Change xScaleType to ordinal and set xDomain to Domain array`); } else { @@ -55,9 +51,8 @@ export function mergeXDomain( } } } else { - seriesXComputedDomains = computeContinuousDataDomain(values, identity, type, { - fit: true, - }); + const domainOptions = { min: NaN, max: NaN, fit: true }; + seriesXComputedDomains = computeContinuousDataDomain([...xValues] as number[], type, domainOptions); let customMinInterval: undefined | number; if (customDomain) { @@ -67,24 +62,24 @@ export function mergeXDomain( customMinInterval = customDomain.minInterval; const [computedDomainMin, computedDomainMax] = seriesXComputedDomains; - if (isCompleteBound(customDomain)) { + if (Number.isFinite(customDomain.min) && Number.isFinite(customDomain.max)) { if (customDomain.min > customDomain.max) { - Logger.warn('custom xDomain is invalid, min is greater than max. Custom domain is ignored.'); + Logger.warn('Custom xDomain is invalid: min is greater than max. Custom domain is ignored.'); } else { seriesXComputedDomains = [customDomain.min, customDomain.max]; } - } else if (isLowerBound(customDomain)) { + } else if (Number.isFinite(customDomain.min)) { if (customDomain.min > computedDomainMax) { Logger.warn( - 'custom xDomain is invalid, custom min is greater than computed max. Custom domain is ignored.', + 'Custom xDomain is invalid: custom min is greater than computed max. Custom domain is ignored.', ); } else { seriesXComputedDomains = [customDomain.min, computedDomainMax]; } - } else if (isUpperBound(customDomain)) { + } else if (Number.isFinite(customDomain.max)) { if (computedDomainMin > customDomain.max) { Logger.warn( - 'custom xDomain is invalid, computed min is greater than custom max. Custom domain is ignored.', + 'Custom xDomain is invalid: computed min is greater than custom max. Custom domain is ignored.', ); } else { seriesXComputedDomains = [computedDomainMin, customDomain.max]; @@ -92,7 +87,7 @@ export function mergeXDomain( } } } - const computedMinInterval = findMinInterval(values as number[]); + const computedMinInterval = findMinInterval([...xValues.values()] as number[]); minInterval = getMinInterval(computedMinInterval, xValues.size, customMinInterval); } @@ -109,18 +104,18 @@ export function mergeXDomain( } function getMinInterval(computedMinInterval: number, size: number, customMinInterval?: number): number { - if (customMinInterval == null) { + if (customMinInterval === undefined) { return computedMinInterval; } // Allow greater custom min if xValues has 1 member. if (size > 1 && customMinInterval > computedMinInterval) { Logger.warn( - 'custom xDomain is invalid, custom minInterval is greater than computed minInterval. Using computed minInterval.', + 'Custom xDomain is invalid: custom minInterval is greater than computed minInterval. Using computed minInterval.', ); return computedMinInterval; } if (customMinInterval < 0) { - Logger.warn('custom xDomain is invalid, custom minInterval is less than 0. Using computed minInterval.'); + Logger.warn('Custom xDomain is invalid: custom minInterval is less than 0. Using computed minInterval.'); return computedMinInterval; } @@ -133,23 +128,11 @@ function getMinInterval(computedMinInterval: number, size: number, customMinInte * @internal */ export function findMinInterval(xValues: number[]): number { - const valuesLength = xValues.length; - if (valuesLength <= 0) { - return 0; - } - if (valuesLength === 1) { - return 1; - } - const sortedValues = [...xValues].sort(compareByValueAsc); - let i; - let minInterval = Math.abs(sortedValues[1] - sortedValues[0]); - for (i = 1; i < valuesLength - 1; i++) { - const current = sortedValues[i]; - const next = sortedValues[i + 1]; - const interval = Math.abs(next - current); - minInterval = Math.min(minInterval, interval); - } - return minInterval; + return xValues.length < 2 + ? xValues.length + : [...xValues].sort(compareByValueAsc).reduce((minInterval, current, i, sortedValues) => { + return i < xValues.length - 1 ? Math.min(minInterval, Math.abs(sortedValues[i + 1] - current)) : minInterval; + }, Infinity); } /** @@ -167,45 +150,20 @@ export function convertXScaleTypes( type: XScaleType; nice: boolean; isBandScale: boolean; - timeZone?: string; + timeZone: string; } { - const seriesTypes = new Set(); - const scaleTypes = new Set(); - const timeZones = new Set(); - const niceDomainConfigs: Array = []; - specs.forEach((spec) => { - niceDomainConfigs.push(getXNiceFromSpec(spec.xNice)); - seriesTypes.add(spec.seriesType); - scaleTypes.add(getXScaleTypeFromSpec(spec.xScaleType)); - if (spec.timeZone) { - timeZones.add(spec.timeZone.toLowerCase()); - } - }); - if (specs.length === 0 || seriesTypes.size === 0 || scaleTypes.size === 0) { - return { - type: ScaleType.Linear, - nice: true, - isBandScale: false, - }; - } - const nice = areAllNiceDomain(niceDomainConfigs); + const seriesTypes = new Set(specs.map((s) => s.seriesType)); + const scaleTypes = new Set(specs.map((s) => getXScaleTypeFromSpec(s.xScaleType))); + const timeZones = new Set(specs.filter((s) => s.timeZone).map((s) => s.timeZone!.toLowerCase())); + const niceDomains = specs.map((s) => getXNiceFromSpec(s.xNice)); + const type = + scaleTypes.size === 1 + ? scaleTypes.values().next().value // pick the only scaleType present + : scaleTypes.has(ScaleType.Ordinal) + ? ScaleType.Ordinal + : ScaleType.Linear; // if Ordinal is not present, coerce to Linear, whether it's present or not + const nice = !niceDomains.includes(false); const isBandScale = seriesTypes.has(SeriesType.Bar); - if (scaleTypes.size === 1) { - const scaleType = scaleTypes.values().next().value; - const timeZone = timeZones.size > 1 ? 'utc' : timeZones.values().next().value; - return { type: scaleType, nice, isBandScale, timeZone }; - } - - if (scaleTypes.size > 1 && scaleTypes.has(ScaleType.Ordinal)) { - return { - type: ScaleType.Ordinal, - nice, - isBandScale, - }; - } - return { - type: ScaleType.Linear, - nice, - isBandScale, - }; + const timeZone = timeZones.size === 1 ? timeZones.values().next().value : 'utc'; + return { type, nice, isBandScale, timeZone }; } diff --git a/packages/charts/src/chart_types/xy_chart/domains/y_domain.test.ts b/packages/charts/src/chart_types/xy_chart/domains/y_domain.test.ts index b142fb72f3..ceed87a022 100644 --- a/packages/charts/src/chart_types/xy_chart/domains/y_domain.test.ts +++ b/packages/charts/src/chart_types/xy_chart/domains/y_domain.test.ts @@ -62,7 +62,7 @@ describe('Y Domain', () => { MockGlobalSpec.axis({ id: 'y', position: Position.Left, - domain: { fit: true }, + domain: { fit: true, min: NaN, max: NaN }, }), MockSeriesSpec.line({ ...DEMO_AREA_SPEC_1, @@ -88,7 +88,7 @@ describe('Y Domain', () => { MockGlobalSpec.axis({ id: 'y', position: Position.Left, - domain: { fit: true }, + domain: { fit: true, min: NaN, max: NaN }, }), MockSeriesSpec.area({ ...DEMO_AREA_SPEC_1, @@ -115,13 +115,13 @@ describe('Y Domain', () => { id: 'y a', groupId: 'a', position: Position.Left, - domain: { fit: true }, + domain: { fit: true, min: NaN, max: NaN }, }), MockGlobalSpec.axis({ id: 'y b', groupId: 'b', position: Position.Left, - domain: { fit: true }, + domain: { fit: true, min: NaN, max: NaN }, }), MockSeriesSpec.line(DEMO_AREA_SPEC_1), MockSeriesSpec.line({ @@ -154,7 +154,7 @@ describe('Y Domain', () => { id: 'y a', groupId: 'a', position: Position.Left, - domain: { fit: true }, + domain: { fit: true, min: NaN, max: NaN }, }), MockSeriesSpec.area(DEMO_AREA_SPEC_1), MockSeriesSpec.area({ @@ -183,7 +183,7 @@ describe('Y Domain', () => { id: 'y a', groupId: 'a', position: Position.Left, - domain: { fit: true }, + domain: { fit: true, min: NaN, max: NaN }, }), MockSeriesSpec.area(DEMO_AREA_SPEC_1), MockSeriesSpec.area({ @@ -362,10 +362,7 @@ describe('Y Domain', () => { }); test('Should return a default Scale Linear for YScaleType when there are no specs', () => { - expect(coerceYScaleTypes([])).toEqual({ - nice: false, - type: ScaleType.Linear, - }); + expect(coerceYScaleTypes([]).type).toEqual(ScaleType.Linear); }); test('Should merge Y domain accounting for custom domain limits: complete bounded domain', () => { @@ -400,7 +397,7 @@ describe('Y Domain', () => { id: 'y a', groupId: 'a', position: Position.Left, - domain: { min: 0, fit: true }, + domain: { min: 0, fit: true, max: NaN }, }), MockSeriesSpec.area(DEMO_AREA_SPEC_1), ], @@ -424,7 +421,7 @@ describe('Y Domain', () => { id: 'y a', groupId: 'a', position: Position.Left, - domain: { min: 20, fit: true }, + domain: { min: 20, fit: true, max: NaN }, }), MockSeriesSpec.area(DEMO_AREA_SPEC_1), ], @@ -447,7 +444,7 @@ describe('Y Domain', () => { id: 'y a', groupId: 'a', position: Position.Left, - domain: { max: 20, fit: true }, + domain: { min: NaN, max: 20, fit: true }, }), MockSeriesSpec.line(DEMO_AREA_SPEC_1), ], @@ -471,7 +468,7 @@ describe('Y Domain', () => { id: 'y a', groupId: 'a', position: Position.Left, - domain: { max: -1, fit: true }, + domain: { min: NaN, max: -1, fit: true }, }), MockSeriesSpec.area(DEMO_AREA_SPEC_1), ], diff --git a/packages/charts/src/chart_types/xy_chart/domains/y_domain.ts b/packages/charts/src/chart_types/xy_chart/domains/y_domain.ts index 50865bf923..94b6e301aa 100644 --- a/packages/charts/src/chart_types/xy_chart/domains/y_domain.ts +++ b/packages/charts/src/chart_types/xy_chart/domains/y_domain.ts @@ -6,19 +6,16 @@ * Side Public License, v 1. */ -import { ScaleContinuousType } from '../../../scales'; import { ScaleType } from '../../../scales/constants'; -import { identity } from '../../../utils/common'; import { computeContinuousDataDomain, ContinuousDomain } from '../../../utils/domain'; import { GroupId } from '../../../utils/ids'; import { Logger } from '../../../utils/logger'; +import { getYNiceFromSpec, getYScaleTypeFromSpec } from '../scales/get_api_scales'; import { ScaleConfigs } from '../state/selectors/get_api_scale_configs'; import { getSpecDomainGroupId } from '../state/utils/spec'; -import { isCompleteBound, isLowerBound, isUpperBound } from '../utils/axis_type_utils'; import { groupBy } from '../utils/group_data_series'; import { DataSeries } from '../utils/series'; -import { BasicSeriesSpec, YDomainRange, SeriesType, StackMode, DomainPaddingUnit } from '../utils/specs'; -import { areAllNiceDomain } from './nice'; +import { BasicSeriesSpec, DomainPaddingUnit, SeriesScales, SeriesType, StackMode, YDomainRange } from '../utils/specs'; import { YDomain } from './types'; /** @internal */ @@ -30,7 +27,6 @@ export type YBasicSeriesSpec = Pick< /** @internal */ export function mergeYDomain(dataSeries: DataSeries[], yScaleAPIConfig: ScaleConfigs['y']): YDomain[] { const dataSeriesByGroupId = groupBy(dataSeries, ({ spec }) => getSpecDomainGroupId(spec), true); - return dataSeriesByGroupId.reduce((acc, groupedDataSeries) => { const stacked = groupedDataSeries.filter(({ isStacked, isFiltered }) => isStacked && !isFiltered); const nonStacked = groupedDataSeries.filter(({ isStacked, isFiltered }) => !isStacked && !isFiltered); @@ -38,10 +34,7 @@ export function mergeYDomain(dataSeries: DataSeries[], yScaleAPIConfig: ScaleCon ({ seriesType, isFiltered }) => seriesType === SeriesType.Bar || (seriesType === SeriesType.Area && !isFiltered), ); const domain = mergeYDomainForGroup(stacked, nonStacked, hasNonZeroBaselineTypes, yScaleAPIConfig); - if (!domain) { - return acc; - } - return [...acc, domain]; + return domain ? [...acc, domain] : acc; }, []); } @@ -52,47 +45,39 @@ function mergeYDomainForGroup( yScaleConfig: ScaleConfigs['y'], ): YDomain | null { const dataSeries = [...stacked, ...nonStacked]; - if (dataSeries.length === 0) { - return null; - } + if (dataSeries.length === 0) return null; const [{ stackMode, spec }] = dataSeries; const groupId = getSpecDomainGroupId(spec); const { customDomain, type, nice, desiredTickCount } = yScaleConfig[groupId]; - const newCustomDomain: YDomainRange = customDomain ? { ...customDomain } : {}; + const newCustomDomain: YDomainRange = customDomain ? { ...customDomain } : { min: NaN, max: NaN }; const { paddingUnit, padding, constrainPadding } = newCustomDomain; - let domain: ContinuousDomain; + let mergedDomain: ContinuousDomain; if (stackMode === StackMode.Percentage) { - domain = computeContinuousDataDomain([0, 1], identity, type, customDomain); + mergedDomain = computeContinuousDataDomain([0, 1], type, customDomain); } else { - // compute stacked domain const stackedDomain = computeYDomain(stacked, hasZeroBaselineSpecs, type, newCustomDomain); - - // compute non stacked domain const nonStackedDomain = computeYDomain(nonStacked, hasZeroBaselineSpecs, type, newCustomDomain); + mergedDomain = computeContinuousDataDomain([...stackedDomain, ...nonStackedDomain], type, newCustomDomain); + const [computedDomainMin, computedDomainMax] = mergedDomain; - // merge stacked and non stacked domain together - domain = computeContinuousDataDomain([...stackedDomain, ...nonStackedDomain], identity, type, newCustomDomain); - - const [computedDomainMin, computedDomainMax] = domain; - - if (newCustomDomain && isCompleteBound(newCustomDomain)) { + if (newCustomDomain && Number.isFinite(newCustomDomain.min) && Number.isFinite(newCustomDomain.max)) { // Don't need to check min > max because this has been validated on axis domain merge - domain = [newCustomDomain.min, newCustomDomain.max]; - } else if (newCustomDomain && isLowerBound(newCustomDomain)) { + mergedDomain = [newCustomDomain.min, newCustomDomain.max]; + } else if (newCustomDomain && Number.isFinite(newCustomDomain.min)) { if (newCustomDomain.min > computedDomainMax) { Logger.warn(`custom yDomain for ${groupId} is invalid, custom min is greater than computed max.`); - domain = [newCustomDomain.min, newCustomDomain.min]; + mergedDomain = [newCustomDomain.min, newCustomDomain.min]; } else { - domain = [newCustomDomain.min, computedDomainMax]; + mergedDomain = [newCustomDomain.min, computedDomainMax]; } - } else if (newCustomDomain && isUpperBound(newCustomDomain)) { + } else if (newCustomDomain && Number.isFinite(newCustomDomain.max)) { if (computedDomainMin > newCustomDomain.max) { Logger.warn(`custom yDomain for ${groupId} is invalid, custom max is less than computed max.`); - domain = [newCustomDomain.max, newCustomDomain.max]; + mergedDomain = [newCustomDomain.max, newCustomDomain.max]; } else { - domain = [computedDomainMin, newCustomDomain.max]; + mergedDomain = [computedDomainMin, newCustomDomain.max]; } } } @@ -102,7 +87,7 @@ function mergeYDomainForGroup( nice, isBandScale: false, groupId, - domain, + domain: mergedDomain, logBase: customDomain?.logBase, logMinLimit: customDomain?.logMinLimit, desiredTickCount, @@ -115,27 +100,21 @@ function computeYDomain( dataSeries: DataSeries[], hasZeroBaselineSpecs: boolean, scaleType: ScaleType, - customDomain?: YDomainRange, + customDomain: YDomainRange, ) { const yValues = new Set(); dataSeries.forEach(({ data }) => { - for (let i = 0; i < data.length; i++) { - const datum = data[i]; + for (const datum of data) { yValues.add(datum.y1); - if (hasZeroBaselineSpecs && datum.y0 != null) { - yValues.add(datum.y0); - } + if (hasZeroBaselineSpecs && datum.y0 !== null) yValues.add(datum.y0); } }); if (yValues.size === 0) { return []; } - const domainOptions = { - ...customDomain, - // padding already applied, set to 0 here to avoid duplicating - padding: 0, - }; - return computeContinuousDataDomain([...yValues.values()], identity, scaleType, domainOptions); + // padding already applied, set to 0 here to avoid duplicating + const domainOptions = { ...customDomain, padding: 0 }; + return computeContinuousDataDomain([...yValues], scaleType, domainOptions); } /** @internal */ @@ -171,67 +150,22 @@ export function groupSeriesByYGroup(specs: YBasicSeriesSpec[]) { return specsByGroupIds; } -/** - * Histogram mode is forced on every specs if at least one specs has that prop flagged - * @remarks - * After mobx->redux https://github.com/elastic/elastic-charts/pull/281 we keep the specs untouched on mount - * in MobX version, the stackAccessors was programmatically added to every histogram specs - * in ReduX version, we left untouched the specs, so we have to manually check that - * @param specs - * @internal - */ +/** @internal */ export function isHistogramEnabled(specs: YBasicSeriesSpec[]) { return specs.some(({ seriesType, enableHistogramMode }) => seriesType === SeriesType.Bar && enableHistogramMode); } -/** - * Return true if the passed spec needs to be rendered as stack - * @param spec - * @param histogramEnabled - * @internal - */ +/** @internal */ export function isStackedSpec(spec: YBasicSeriesSpec, histogramEnabled: boolean) { const isBarAndHistogram = spec.seriesType === SeriesType.Bar && histogramEnabled; const hasStackAccessors = spec.stackAccessors && spec.stackAccessors.length > 0; return isBarAndHistogram || hasStackAccessors; } -/** - * Coerce the scale types of a set of specification to a generic one. - * If there is at least one bar series type, than the response will specity - * that the coerced scale is a `scaleBand` (each point needs to have a surrounding empty - * space to draw the bar width). - * If there are multiple continuous scale types, is coerced to linear. - * If there are at least one Ordinal scale type, is coerced to ordinal. - * If none of the above, than coerce to the specified scale. - * @returns {ScaleContinuousType} - * @internal - */ -export function coerceYScaleTypes( - scales: Array<{ type: ScaleContinuousType; nice: boolean }>, -): { - type: ScaleContinuousType; - nice: boolean; -} { - const scaleCollection = scales.reduce<{ - types: Set; - nice: Array; - }>( - (acc, scale) => { - acc.types.add(scale.type); - acc.nice.push(scale.nice); - return acc; - }, - { - types: new Set(), - nice: [], - }, - ); - const nice = areAllNiceDomain(scaleCollection.nice); - return scaleCollection.types.size === 1 - ? { type: scaleCollection.types.values().next().value, nice } - : { - type: ScaleType.Linear, - nice, - }; +/** @internal */ +export function coerceYScaleTypes(series: Pick[]) { + const scaleTypes = new Set(series.map((s) => getYScaleTypeFromSpec(s.yScaleType))); + const niceDomains = series.map((s) => getYNiceFromSpec(s.yNice)); + const type = scaleTypes.size === 1 ? scaleTypes.values().next().value : ScaleType.Linear; + return { type, nice: !niceDomains.includes(false) }; } diff --git a/packages/charts/src/chart_types/xy_chart/rendering/rendering.bars.test.ts b/packages/charts/src/chart_types/xy_chart/rendering/rendering.bars.test.ts index 3eb1feabf1..44e4e827b7 100644 --- a/packages/charts/src/chart_types/xy_chart/rendering/rendering.bars.test.ts +++ b/packages/charts/src/chart_types/xy_chart/rendering/rendering.bars.test.ts @@ -9,7 +9,6 @@ import { MockGlobalSpec, MockSeriesSpec } from '../../../mocks/specs'; import { MockStore } from '../../../mocks/store'; import { ScaleType } from '../../../scales/constants'; -import { identity } from '../../../utils/common'; import { computeSeriesGeometriesSelector } from '../state/selectors/compute_series_geometries'; const SPEC_ID = 'spec_1'; @@ -60,7 +59,7 @@ describe('Rendering bars', () => { displayValueSettings: { showValueLabel: true, isAlternatingValueLabel: true, - valueFormatter: identity, + valueFormatter: (d) => d, }, }), MockGlobalSpec.settingsNoMargins({ xDomain: [0, 1], theme: { colors: { vizColors: ['red'] } } }), @@ -90,7 +89,7 @@ describe('Rendering bars', () => { displayValueSettings: { showValueLabel: false, isAlternatingValueLabel: true, - valueFormatter: identity, + valueFormatter: (d) => d, }, }), MockGlobalSpec.settingsNoMargins({ xDomain: [0, 1], theme: { colors: { vizColors: ['red'] } } }), @@ -120,7 +119,7 @@ describe('Rendering bars', () => { displayValueSettings: { showValueLabel: true, isAlternatingValueLabel: true, - valueFormatter: identity, + valueFormatter: (d) => d, }, }), MockGlobalSpec.settingsNoMargins({ xDomain: [0, 1], theme: { colors: { vizColors: ['red'] } } }), @@ -152,7 +151,7 @@ describe('Rendering bars', () => { displayValueSettings: { showValueLabel: true, isValueContainedInElement: true, - valueFormatter: identity, + valueFormatter: (d) => d, }, }), MockGlobalSpec.settingsNoMargins({ xDomain: [0, 1], theme: { colors: { vizColors: ['red'] } } }), diff --git a/packages/charts/src/chart_types/xy_chart/rendering/rendering.bubble.test.ts b/packages/charts/src/chart_types/xy_chart/rendering/rendering.bubble.test.ts index 4b19ecbba4..9d19c45a9d 100644 --- a/packages/charts/src/chart_types/xy_chart/rendering/rendering.bubble.test.ts +++ b/packages/charts/src/chart_types/xy_chart/rendering/rendering.bubble.test.ts @@ -386,10 +386,10 @@ describe('Rendering points - bubble', () => { yScaleType: ScaleType.Linear, }); const settings = MockGlobalSpec.settingsNoMargins({ - xDomain: { max: 2 }, + xDomain: { min: NaN, max: 2 }, theme: { colors: { vizColors: ['red', 'blue'] } }, }); - const axis = MockGlobalSpec.axis({ position: Position.Left, hide: true, domain: { max: 1 } }); + const axis = MockGlobalSpec.axis({ position: Position.Left, hide: true, domain: { min: NaN, max: 1 } }); const store = MockStore.default({ width: 100, height: 100, top: 0, left: 0 }); MockStore.addSpecs([pointSeriesSpec, axis, settings], store); const { diff --git a/packages/charts/src/chart_types/xy_chart/rendering/rendering.lines.test.ts b/packages/charts/src/chart_types/xy_chart/rendering/rendering.lines.test.ts index 015a703a22..fcc764b627 100644 --- a/packages/charts/src/chart_types/xy_chart/rendering/rendering.lines.test.ts +++ b/packages/charts/src/chart_types/xy_chart/rendering/rendering.lines.test.ts @@ -404,10 +404,10 @@ describe('Rendering points - line', () => { yScaleType: ScaleType.Linear, }); const settings = MockGlobalSpec.settingsNoMargins({ - xDomain: { max: 2 }, + xDomain: { min: NaN, max: 2 }, theme: { colors: { vizColors: ['red', 'blue'] } }, }); - const axis = MockGlobalSpec.axis({ position: Position.Left, hide: true, domain: { max: 1 } }); + const axis = MockGlobalSpec.axis({ position: Position.Left, hide: true, domain: { min: NaN, max: 1 } }); const store = MockStore.default({ width: 100, height: 100, top: 0, left: 0 }); MockStore.addSpecs([pointSeriesSpec, axis, settings], store); diff --git a/packages/charts/src/chart_types/xy_chart/state/selectors/compute_annotations.ts b/packages/charts/src/chart_types/xy_chart/state/selectors/compute_annotations.ts index c534e0bffa..6725bd0b66 100644 --- a/packages/charts/src/chart_types/xy_chart/state/selectors/compute_annotations.ts +++ b/packages/charts/src/chart_types/xy_chart/state/selectors/compute_annotations.ts @@ -6,11 +6,10 @@ * Side Public License, v 1. */ -import { Scale } from '../../../../scales'; import { createCustomCachedSelector } from '../../../../state/create_selector'; import { getChartThemeSelector } from '../../../../state/selectors/get_chart_theme'; import { getSettingsSpecSelector } from '../../../../state/selectors/get_settings_specs'; -import { AnnotationId, AxisId, GroupId } from '../../../../utils/ids'; +import { AnnotationId, AxisId } from '../../../../utils/ids'; import { AnnotationDimensions } from '../../annotations/types'; import { computeAnnotationDimensions } from '../../annotations/utils'; import { computeSeriesGeometriesSelector } from './compute_series_geometries'; @@ -45,7 +44,7 @@ export const computeAnnotationDimensionsSelector = createCustomCachedSelector( return computeAnnotationDimensions( annotationSpecs, settingsSpec.rotation, - yScales as Map>, + yScales, xScale, axesSpecs, isHistogramMode, diff --git a/packages/charts/src/chart_types/xy_chart/state/selectors/compute_per_panel_axes_geoms.ts b/packages/charts/src/chart_types/xy_chart/state/selectors/compute_per_panel_axes_geoms.ts index 39e6aec796..7c5ca17eb2 100644 --- a/packages/charts/src/chart_types/xy_chart/state/selectors/compute_per_panel_axes_geoms.ts +++ b/packages/charts/src/chart_types/xy_chart/state/selectors/compute_per_panel_axes_geoms.ts @@ -51,22 +51,13 @@ export const computePerPanelAxesGeomsSelector = createCustomCachedSelector( return getPerPanelMap(scales, (_, h, v) => ({ axesGeoms: axesGeoms.map((geom) => { - const { - axis: { position }, - } = geom; + const { position } = geom.axis; const isVertical = isVerticalAxis(position); const usePanelTitle = isVertical ? hasSMDomain(vertical) : hasSMDomain(horizontal); const panelTitle = usePanelTitle ? getPanelTitle(isVertical, v, h, groupBySpec) : undefined; const secondary = !isPrimaryColumn(position, h) && !isPrimaryRow(position, v); - return { - ...geom, - axis: { - ...geom.axis, - panelTitle, - secondary, - }, - }; + return { ...geom, axis: { ...geom.axis, panelTitle, secondary } }; }), })); }, diff --git a/packages/charts/src/chart_types/xy_chart/state/selectors/compute_small_multiple_scales.ts b/packages/charts/src/chart_types/xy_chart/state/selectors/compute_small_multiple_scales.ts index a439de61f1..04605b60ef 100644 --- a/packages/charts/src/chart_types/xy_chart/state/selectors/compute_small_multiple_scales.ts +++ b/packages/charts/src/chart_types/xy_chart/state/selectors/compute_small_multiple_scales.ts @@ -43,10 +43,5 @@ export function getScale( padding: RelativeBandsPadding = DEFAULT_SM_PANEL_PADDING, ) { const singlePanelSmallMultiple = domain.length <= 1; - return new ScaleBand( - domain.length > 0 ? domain : [(undefined as unknown) as number], - [0, maxRange], - undefined, - singlePanelSmallMultiple ? 0 : padding, - ); + return new ScaleBand(domain, [0, maxRange], undefined, singlePanelSmallMultiple ? 0 : padding); } diff --git a/packages/charts/src/chart_types/xy_chart/state/selectors/get_api_scale_configs.ts b/packages/charts/src/chart_types/xy_chart/state/selectors/get_api_scale_configs.ts index 8c1f82a6e3..a9fae4e248 100644 --- a/packages/charts/src/chart_types/xy_chart/state/selectors/get_api_scale_configs.ts +++ b/packages/charts/src/chart_types/xy_chart/state/selectors/get_api_scale_configs.ts @@ -14,7 +14,6 @@ import { getSettingsSpecSelector } from '../../../../state/selectors/get_setting import { GroupId } from '../../../../utils/ids'; import { convertXScaleTypes } from '../../domains/x_domain'; import { coerceYScaleTypes } from '../../domains/y_domain'; -import { getYNiceFromSpec, getYScaleTypeFromSpec } from '../../scales/get_api_scales'; import { X_SCALE_DEFAULT, Y_SCALE_DEFAULT } from '../../scales/scale_defaults'; import { isHorizontalAxis, isVerticalAxis } from '../../utils/axis_type_utils'; import { groupBy } from '../../utils/group_data_series'; @@ -74,12 +73,8 @@ export function getScaleConfigsFromSpecs( const scaleConfigsByGroupId = groupBy(seriesSpecs, getSpecDomainGroupId, true).reduce< Record >((acc, series) => { - const yScaleTypes = series.map(({ yScaleType, yNice }) => ({ - nice: getYNiceFromSpec(yNice), - type: getYScaleTypeFromSpec(yScaleType), - })); const groupId = getSpecDomainGroupId(series[0]); - acc[groupId] = coerceYScaleTypes(yScaleTypes); + acc[groupId] = coerceYScaleTypes(series); return acc; }, {}); diff --git a/packages/charts/src/chart_types/xy_chart/state/selectors/get_cursor_band.ts b/packages/charts/src/chart_types/xy_chart/state/selectors/get_cursor_band.ts index 396bc9c56f..30f7804d8a 100644 --- a/packages/charts/src/chart_types/xy_chart/state/selectors/get_cursor_band.ts +++ b/packages/charts/src/chart_types/xy_chart/state/selectors/get_cursor_band.ts @@ -95,7 +95,7 @@ function getCursorBand( if (isValidPointerOverEvent(xScale, externalPointerEvent)) { fromExternalEvent = true; const x = xScale.pureScale(externalPointerEvent.x); - if (x == null || x > chartDimensions.width || x < 0) { + if (x === null || x > chartDimensions.width || x < 0) { return; } pointerPosition = { diff --git a/packages/charts/src/chart_types/xy_chart/state/selectors/get_elements_at_cursor_pos.ts b/packages/charts/src/chart_types/xy_chart/state/selectors/get_elements_at_cursor_pos.ts index bc968e40b9..ad57db478c 100644 --- a/packages/charts/src/chart_types/xy_chart/state/selectors/get_elements_at_cursor_pos.ts +++ b/packages/charts/src/chart_types/xy_chart/state/selectors/get_elements_at_cursor_pos.ts @@ -48,7 +48,7 @@ function getElementAtCursorPosition( if (isValidPointerOverEvent(scales.xScale, externalPointerEvent)) { const x = scales.xScale.pureScale(externalPointerEvent.x); - if (x == null || x > chartDimensions.width + chartDimensions.left || x < 0) { + if (x === null || x > chartDimensions.width + chartDimensions.left || x < 0) { return []; } // TODO: Handle external event with spatial points diff --git a/packages/charts/src/chart_types/xy_chart/state/selectors/get_highlighted_series.ts b/packages/charts/src/chart_types/xy_chart/state/selectors/get_highlighted_series.ts index 59f7f2a6d3..d85f1792bb 100644 --- a/packages/charts/src/chart_types/xy_chart/state/selectors/get_highlighted_series.ts +++ b/packages/charts/src/chart_types/xy_chart/state/selectors/get_highlighted_series.ts @@ -17,12 +17,9 @@ const getHighlightedLegendPath = (state: GlobalChartState) => state.interactions export const getHighlightedSeriesSelector = createCustomCachedSelector( [getHighlightedLegendPath, computeLegendSelector], (highlightedLegendPaths, legendItems): LegendItem | undefined => { - if (highlightedLegendPaths.length === 0) { - return; + if (highlightedLegendPaths.length > 0) { + const lookup = new Set(highlightedLegendPaths.map(({ value }) => value)); + return legendItems.find(({ seriesIdentifiers }) => seriesIdentifiers.some(({ key }) => lookup.has(key))); } - const highlightedSeriesKeys = highlightedLegendPaths.map(({ value }) => value); - return legendItems.find(({ seriesIdentifiers }) => - seriesIdentifiers.some(({ key }) => highlightedSeriesKeys.some((hKey) => hKey === key)), - ); }, ); diff --git a/packages/charts/src/chart_types/xy_chart/state/selectors/get_highlighted_values.ts b/packages/charts/src/chart_types/xy_chart/state/selectors/get_highlighted_values.ts index ebca417c61..d6c53168e3 100644 --- a/packages/charts/src/chart_types/xy_chart/state/selectors/get_highlighted_values.ts +++ b/packages/charts/src/chart_types/xy_chart/state/selectors/get_highlighted_values.ts @@ -9,11 +9,11 @@ import { LegendItemExtraValues } from '../../../../common/legend'; import { SeriesKey } from '../../../../common/series_id'; import { createCustomCachedSelector } from '../../../../state/create_selector'; -import { getHighligthedValues } from '../../tooltip/tooltip'; +import { getHighlightedValues } from '../../tooltip/tooltip'; import { getTooltipInfoSelector } from './get_tooltip_values_highlighted_geoms'; /** @internal */ export const getHighlightedValuesSelector = createCustomCachedSelector( [getTooltipInfoSelector], - ({ values }): Map => getHighligthedValues(values), + ({ values }): Map => getHighlightedValues(values), ); diff --git a/packages/charts/src/chart_types/xy_chart/state/selectors/get_legend_items_labels.ts b/packages/charts/src/chart_types/xy_chart/state/selectors/get_legend_items_labels.ts index 06751a4ceb..f345895820 100644 --- a/packages/charts/src/chart_types/xy_chart/state/selectors/get_legend_items_labels.ts +++ b/packages/charts/src/chart_types/xy_chart/state/selectors/get_legend_items_labels.ts @@ -15,10 +15,11 @@ import { computeLegendSelector } from './compute_legend'; export const getLegendItemsLabelsSelector = createCustomCachedSelector( [computeLegendSelector, getSettingsSpecSelector], (legendItems, { showLegendExtra }): LegendItemLabel[] => - legendItems.map(({ label, defaultExtra }) => { - if (defaultExtra?.legendSizingLabel != null) { - return { label: `${label}${showLegendExtra ? defaultExtra.legendSizingLabel : ''}`, depth: 0 }; - } - return { label, depth: 0 }; - }), + legendItems.map(({ label, defaultExtra }) => ({ + label: + defaultExtra && (defaultExtra.legendSizingLabel ?? null) !== null + ? `${label}${showLegendExtra ? defaultExtra.legendSizingLabel : ''}` + : label, + depth: 0, + })), ); diff --git a/packages/charts/src/chart_types/xy_chart/state/selectors/merge_y_custom_domains.ts b/packages/charts/src/chart_types/xy_chart/state/selectors/merge_y_custom_domains.ts index 244c65ffb2..fdfbcf6697 100644 --- a/packages/charts/src/chart_types/xy_chart/state/selectors/merge_y_custom_domains.ts +++ b/packages/charts/src/chart_types/xy_chart/state/selectors/merge_y_custom_domains.ts @@ -8,7 +8,6 @@ import { Rotation } from '../../../../utils/common'; import { GroupId } from '../../../../utils/ids'; -import { isBounded, isCompleteBound, isLowerBound, isUpperBound } from '../../utils/axis_type_utils'; import { isXDomain } from '../../utils/axis_utils'; import { AxisSpec, YDomainRange } from '../../utils/specs'; @@ -27,40 +26,28 @@ export function mergeYCustomDomainsByGroupId( } if (isXDomain(spec.position, chartRotation)) { - const errorMessage = `[Axis ${id}]: custom domain for xDomain should be defined in Settings`; - throw new Error(errorMessage); + throw new Error(`[Axis ${id}]: custom domain for xDomain should be defined in Settings`); } - if (isCompleteBound(domain) && domain.min > domain.max) { - const errorMessage = `[Axis ${id}]: custom domain is invalid, min is greater than max`; - throw new Error(errorMessage); + if (domain.min > domain.max) { + throw new Error(`[Axis ${id}]: custom domain is invalid, min is greater than max`); } const prevGroupDomain = domainsByGroupId.get(groupId); if (prevGroupDomain) { - const prevDomain = prevGroupDomain; - const prevMin = isLowerBound(prevDomain) ? prevDomain.min : undefined; - const prevMax = isUpperBound(prevDomain) ? prevDomain.max : undefined; - - let max = prevMax; - let min = prevMin; - - if (isCompleteBound(domain)) { - min = prevMin != null ? Math.min(domain.min, prevMin) : domain.min; - max = prevMax != null ? Math.max(domain.max, prevMax) : domain.max; - } else if (isLowerBound(domain)) { - min = prevMin != null ? Math.min(domain.min, prevMin) : domain.min; - } else if (isUpperBound(domain)) { - max = prevMax != null ? Math.max(domain.max, prevMax) : domain.max; - } - const mergedDomain = { - min, - max, + min: Math.min( + Number.isFinite(domain.min) ? domain.min : Infinity, + prevGroupDomain && Number.isFinite(prevGroupDomain.min) ? prevGroupDomain.min : Infinity, + ), + max: Math.max( + Number.isFinite(domain.max) ? domain.max : -Infinity, + prevGroupDomain && Number.isFinite(prevGroupDomain.max) ? prevGroupDomain.max : -Infinity, + ), }; - if (isBounded(mergedDomain)) { + if (Number.isFinite(mergedDomain.min) || Number.isFinite(mergedDomain.max)) { domainsByGroupId.set(groupId, mergedDomain); } } else { diff --git a/packages/charts/src/chart_types/xy_chart/state/selectors/on_brush_end_caller.ts b/packages/charts/src/chart_types/xy_chart/state/selectors/on_brush_end_caller.ts index 2cb63c4dd1..f8e1ebff15 100644 --- a/packages/charts/src/chart_types/xy_chart/state/selectors/on_brush_end_caller.ts +++ b/packages/charts/src/chart_types/xy_chart/state/selectors/on_brush_end_caller.ts @@ -156,7 +156,7 @@ function getXBrushExtent( const offset = histogramMode ? 0 : -(xScale.bandwidth + xScale.bandwidthPadding) / 2; const invertValue = roundHistogramBrushValues - ? (value: number) => xScale.invertWithStep(value, xScale.domain)?.value + ? (value: number) => xScale.invertWithStep(value, xScale.domain).value : (value: number) => xScale.invert(value); const minPosScaled = invertValue(minPos + offset); const maxPosScaled = invertValue(maxPos + offset); @@ -190,7 +190,7 @@ function getYBrushExtents( chartDimensions: Dimensions, lastDrag: DragState, rotation: Rotation, - yScales: Map>, + yScales: Map>, smallMultipleScales: SmallMultipleScales, minBrushDelta?: number, ): GroupBrushExtent[] | undefined { @@ -212,8 +212,8 @@ function getYBrushExtents( const minPosScaled = yScale.invert(minPos); const maxPosScaled = yScale.invert(maxPos); - const minValue = clamp(minPosScaled, (yScale as Scale).domain[0], maxPosScaled); - const maxValue = clamp(minPosScaled, maxPosScaled, (yScale as Scale).domain[1]); + const minValue = clamp(minPosScaled, yScale.domain[0], maxPosScaled); + const maxValue = clamp(minPosScaled, maxPosScaled, yScale.domain[1]); yValues.push({ extent: [minValue, maxValue], groupId }); }); return yValues.length === 0 ? undefined : yValues; diff --git a/packages/charts/src/chart_types/xy_chart/state/utils/types.ts b/packages/charts/src/chart_types/xy_chart/state/utils/types.ts index 559668a7c8..a42f106a8e 100644 --- a/packages/charts/src/chart_types/xy_chart/state/utils/types.ts +++ b/packages/charts/src/chart_types/xy_chart/state/utils/types.ts @@ -43,7 +43,7 @@ export interface GeometriesCounts { /** @internal */ export interface ComputedScales { xScale: Scale; - yScales: Map>; + yScales: Map>; } /** @internal */ diff --git a/packages/charts/src/chart_types/xy_chart/state/utils/utils.test.ts b/packages/charts/src/chart_types/xy_chart/state/utils/utils.test.ts index 2a400b66f0..26cd40e191 100644 --- a/packages/charts/src/chart_types/xy_chart/state/utils/utils.test.ts +++ b/packages/charts/src/chart_types/xy_chart/state/utils/utils.test.ts @@ -74,6 +74,8 @@ describe('Chart State utils', () => { domain: [0, 3], isBandScale: false, minInterval: 1, + logBase: undefined, + timeZone: 'utc', }), ); expect(domains.yDomains).toEqual([ @@ -123,6 +125,8 @@ describe('Chart State utils', () => { domain: [0, 3], isBandScale: false, minInterval: 1, + logBase: undefined, + timeZone: 'utc', }), ); expect(domains.yDomains).toEqual([ diff --git a/packages/charts/src/chart_types/xy_chart/state/utils/utils.ts b/packages/charts/src/chart_types/xy_chart/state/utils/utils.ts index 3ad34dc4dd..766d1ff575 100644 --- a/packages/charts/src/chart_types/xy_chart/state/utils/utils.ts +++ b/packages/charts/src/chart_types/xy_chart/state/utils/utils.ts @@ -278,7 +278,7 @@ export function computeXScaleOffset( function renderGeometries( dataSeries: DataSeries[], xDomain: XDomain, - yScales: Map>, + yScales: Map>, smVScale: Scale, smHScale: Scale, barIndexOrderPerPanel: Record, @@ -379,7 +379,7 @@ function renderGeometries( shift, ds, xScale, - yScale as Scale, + yScale, panel, chartRotation, spec.minBarHeight ?? 0, @@ -405,7 +405,7 @@ function renderGeometries( (xScale.bandwidth * bubbleShift) / 2, ds, xScale, - yScale as Scale, + yScale, color, panel, isBandedSpec(spec.y0Accessors), @@ -438,7 +438,7 @@ function renderGeometries( (xScale.bandwidth * lineShift) / 2, ds, xScale, - yScale as Scale, + yScale, panel, color, spec.curve || CurveType.LINEAR, @@ -471,7 +471,7 @@ function renderGeometries( (xScale.bandwidth * areaShift) / 2, ds, xScale, - yScale as Scale, + yScale, panel, color, spec.curve || CurveType.LINEAR, diff --git a/packages/charts/src/chart_types/xy_chart/tooltip/tooltip.ts b/packages/charts/src/chart_types/xy_chart/tooltip/tooltip.ts index f4e68f4cd9..74e04ff8aa 100644 --- a/packages/charts/src/chart_types/xy_chart/tooltip/tooltip.ts +++ b/packages/charts/src/chart_types/xy_chart/tooltip/tooltip.ts @@ -29,7 +29,7 @@ export const Y0_ACCESSOR_POSTFIX = ' - lower'; export const Y1_ACCESSOR_POSTFIX = ' - upper'; /** @internal */ -export function getHighligthedValues( +export function getHighlightedValues( tooltipValues: TooltipValue[], defaultValue?: string, ): Map { @@ -47,7 +47,7 @@ export function getHighligthedValues( } } - if (valueAccessor != null && (valueAccessor === BandedAccessorType.Y0 || valueAccessor === BandedAccessorType.Y1)) { + if (valueAccessor === BandedAccessorType.Y0 || valueAccessor === BandedAccessorType.Y1) { current.set(valueAccessor, seriesValue); } seriesTooltipValues.set(seriesIdentifier.key, current); diff --git a/packages/charts/src/chart_types/xy_chart/utils/axis_type_utils.test.ts b/packages/charts/src/chart_types/xy_chart/utils/axis_type_utils.test.ts index 2bfc838115..1f293d762d 100644 --- a/packages/charts/src/chart_types/xy_chart/utils/axis_type_utils.test.ts +++ b/packages/charts/src/chart_types/xy_chart/utils/axis_type_utils.test.ts @@ -7,7 +7,7 @@ */ import { Position } from '../../../utils/common'; -import { isBounded, isVerticalAxis, isHorizontalAxis, isVerticalGrid, isHorizontalGrid } from './axis_type_utils'; +import { isVerticalAxis, isHorizontalAxis, isVerticalGrid, isHorizontalGrid } from './axis_type_utils'; describe('Axis type utils', () => { test('should determine orientation of axis position', () => { @@ -33,17 +33,4 @@ describe('Axis type utils', () => { expect(isHorizontalGrid(Position.Top)).toBe(false); expect(isHorizontalGrid(Position.Bottom)).toBe(false); }); - - test('should determine that a domain has at least one bound', () => { - const lowerBounded = { - min: 0, - }; - - const upperBounded = { - max: 0, - }; - - expect(isBounded(lowerBounded)).toBe(true); - expect(isBounded(upperBounded)).toBe(true); - }); }); diff --git a/packages/charts/src/chart_types/xy_chart/utils/axis_type_utils.ts b/packages/charts/src/chart_types/xy_chart/utils/axis_type_utils.ts index b15eda433f..8147abff0a 100644 --- a/packages/charts/src/chart_types/xy_chart/utils/axis_type_utils.ts +++ b/packages/charts/src/chart_types/xy_chart/utils/axis_type_utils.ts @@ -7,27 +7,6 @@ */ import { Position } from '../../../utils/common'; -import { CompleteBoundedDomain, LowerBoundedDomain, UpperBoundedDomain, DomainRange } from './specs'; - -/** @internal */ -export function isLowerBound(domain: Partial): domain is LowerBoundedDomain { - return domain.min != null; -} - -/** @internal */ -export function isUpperBound(domain: Partial): domain is UpperBoundedDomain { - return domain.max != null; -} - -/** @internal */ -export function isCompleteBound(domain: Partial): domain is CompleteBoundedDomain { - return domain.max != null && domain.min != null; -} - -/** @internal */ -export function isBounded(domain: Partial): domain is DomainRange { - return domain.max != null || domain.min != null; -} /** @internal */ export function isVerticalAxis(axisPosition: Position): axisPosition is Extract { diff --git a/packages/charts/src/chart_types/xy_chart/utils/axis_utils.test.ts b/packages/charts/src/chart_types/xy_chart/utils/axis_utils.test.ts index 929d7e40ba..c309b40992 100644 --- a/packages/charts/src/chart_types/xy_chart/utils/axis_utils.test.ts +++ b/packages/charts/src/chart_types/xy_chart/utils/axis_utils.test.ts @@ -1129,6 +1129,7 @@ describe('Axis computational utils', () => { test('should merge axis domains by group id: partial upper bounded prevDomain with complete domain', () => { const groupId = 'group_1'; const domainRange1 = { + min: NaN, max: 9, }; @@ -1155,6 +1156,7 @@ describe('Axis computational utils', () => { const groupId = 'group_1'; const domainRange1 = { min: -1, + max: NaN, }; const domainRange2 = { @@ -1179,15 +1181,18 @@ describe('Axis computational utils', () => { test('should merge axis domains by group id: partial upper bounded prevDomain with lower bounded domain', () => { const groupId = 'group_1'; const domainRange1 = { + min: NaN, max: 9, }; const domainRange2 = { min: 0, + max: NaN, }; const domainRange3 = { min: -1, + max: NaN, }; verticalAxisSpec.domain = domainRange1; @@ -1216,13 +1221,16 @@ describe('Axis computational utils', () => { const groupId = 'group_1'; const domainRange1 = { min: 2, + max: NaN, }; const domainRange2 = { + min: NaN, max: 7, }; const domainRange3 = { + min: NaN, max: 9, }; diff --git a/packages/charts/src/chart_types/xy_chart/utils/axis_utils.ts b/packages/charts/src/chart_types/xy_chart/utils/axis_utils.ts index c65fe3c77b..4a2348c5c7 100644 --- a/packages/charts/src/chart_types/xy_chart/utils/axis_utils.ts +++ b/packages/charts/src/chart_types/xy_chart/utils/axis_utils.ts @@ -252,7 +252,7 @@ function axisMinMax(axisPosition: Position, chartRotation: Rotation, { width, he /** @internal */ export function getAvailableTicks( axisSpec: AxisSpec, - scale: Scale, + scale: Scale, totalBarsInCluster: number, enableHistogramMode: boolean, fallBackTickFormatter: TickFormatter, @@ -263,18 +263,15 @@ export function getAvailableTicks( const isSingleValueScale = scale.domain[0] === scale.domain[1]; const hasAdditionalTicks = enableHistogramMode && scale.bandwidth > 0; - if (hasAdditionalTicks) { - const lastComputedTick = ticks[ticks.length - 1]; + if (hasAdditionalTicks && !isSingleValueScale) { + // todo sure hope something ascertains this, otherwise we can't subtract in runtime: + const numericalTicks = ticks as number[]; + const lastComputedTick = numericalTicks[numericalTicks.length - 1]; + const penultimateComputedTick = numericalTicks[numericalTicks.length - 2]; + const computedTickDistance = lastComputedTick - penultimateComputedTick; + const numTicks = scale.minInterval / computedTickDistance; - if (!isSingleValueScale) { - const penultimateComputedTick = ticks[ticks.length - 2]; - const computedTickDistance = lastComputedTick - penultimateComputedTick; - const numTicks = scale.minInterval / computedTickDistance; - - for (let i = 1; i <= numTicks; i++) { - ticks.push(i * computedTickDistance + lastComputedTick); - } - } + for (let i = 1; i <= numTicks; i++) ticks.push(i * computedTickDistance + lastComputedTick); } const shift = totalBarsInCluster > 0 ? totalBarsInCluster : 1; const band = scale.bandwidth / (1 - scale.barsPadding); @@ -285,7 +282,8 @@ export function getAvailableTicks( const labelFormatter = axisSpec.labelFormat ?? tickFormatter; if (isSingleValueScale && hasAdditionalTicks) { - const [firstTickValue] = ticks; + // todo sure hope something ascertains this, otherwise we can't add in runtime: + const [firstTickValue] = ticks as number[]; const firstLabel = tickFormatter(firstTickValue, tickFormatOptions); const firstTick = { value: firstTickValue, @@ -293,7 +291,6 @@ export function getAvailableTicks( axisTickLabel: labelFormatter(firstTickValue, tickFormatOptions), position: (scale.scale(firstTickValue) ?? 0) + offset, }; - const lastTickValue = firstTickValue + scale.minInterval; const lastLabel = tickFormatter(lastTickValue, tickFormatOptions); const lastTick = { @@ -311,7 +308,7 @@ export function getAvailableTicks( /** @internal */ export function enableDuplicatedTicks( axisSpec: AxisSpec, - scale: Scale, + scale: Scale, offset: number, fallBackTickFormatter: TickFormatter, tickFormatOptions?: TickFormatterOptions, @@ -449,7 +446,7 @@ export function getAxesGeometries( const vertical = isVerticalAxis(axisSpec.position); const allTicks = getAvailableTicks( axisSpec, - scale as Scale, + scale, totalGroupsCount, enableHistogramMode, vertical ? fallBackTickFormatter : defaultTickFormatter, diff --git a/packages/charts/src/chart_types/xy_chart/utils/panel_utils.ts b/packages/charts/src/chart_types/xy_chart/utils/panel_utils.ts index 3603d9604c..a82b142002 100644 --- a/packages/charts/src/chart_types/xy_chart/utils/panel_utils.ts +++ b/packages/charts/src/chart_types/xy_chart/utils/panel_utils.ts @@ -9,17 +9,19 @@ import { Point } from '../../../utils/point'; import { SmallMultipleScales } from '../state/selectors/compute_small_multiple_scales'; +type Value = string | number; + /** @internal */ export interface PerPanelMap { panelAnchor: Point; - horizontalValue: any; - verticalValue: any; + horizontalValue: Value; + verticalValue: Value; } /** @internal */ export function getPerPanelMap( scales: SmallMultipleScales, - fn: (panelAnchor: Point, horizontalValue: any, verticalValue: any, scales: SmallMultipleScales) => T | null, + fn: (anchor: Point, horizontalValue: Value, verticalValue: Value, smScales: SmallMultipleScales) => T | null, ): Array { const { horizontal, vertical } = scales; return vertical.domain.reduce>((acc, verticalValue) => { @@ -31,18 +33,7 @@ export function getPerPanelMap( y: vertical.scale(verticalValue) ?? 0, }; const fnObj = fn(panelAnchor, horizontalValue, verticalValue, scales); - if (!fnObj) { - return hAcc; - } - return [ - ...hAcc, - { - panelAnchor, - horizontalValue, - verticalValue, - ...fnObj, - }, - ]; + return fnObj ? [...hAcc, { panelAnchor, horizontalValue, verticalValue, ...fnObj }] : hAcc; }, []), ]; }, []); diff --git a/packages/charts/src/chart_types/xy_chart/utils/scales.ts b/packages/charts/src/chart_types/xy_chart/utils/scales.ts index 53ef0f31ab..a0fc9ddef8 100644 --- a/packages/charts/src/chart_types/xy_chart/utils/scales.ts +++ b/packages/charts/src/chart_types/xy_chart/utils/scales.ts @@ -84,20 +84,21 @@ export function computeXScale(options: XScaleOptions): Scale { logBase, }, ); + } else { + return new ScaleContinuous( + { type, domain: domain as number[], range, nice }, + { + bandwidth: 0, + minInterval, + timeZone, + totalBarsInCluster, + barsPadding, + desiredTickCount, + integersOnly, + logBase, + }, + ); } - return new ScaleContinuous( - { type, domain, range, nice }, - { - bandwidth: 0, - minInterval, - timeZone, - totalBarsInCluster, - barsPadding, - desiredTickCount, - integersOnly, - logBase, - }, - ); } interface YScaleOptions { @@ -110,7 +111,7 @@ interface YScaleOptions { * Compute the y scales, one per groupId for the y axis. * @internal */ -export function computeYScales(options: YScaleOptions): Map> { +export function computeYScales(options: YScaleOptions): Map> { const { yDomains, range, integersOnly } = options; return yDomains.reduce( ( @@ -128,12 +129,7 @@ export function computeYScales(options: YScaleOptions): Map { const yScale = new ScaleContinuous( - { - type, - domain, - range, - nice, - }, + { type, domain, range, nice }, { desiredTickCount, integersOnly, @@ -146,6 +142,6 @@ export function computeYScales(options: YScaleOptions): Map>(), + new Map>(), ); } diff --git a/packages/charts/src/chart_types/xy_chart/utils/series.test.ts b/packages/charts/src/chart_types/xy_chart/utils/series.test.ts index c2a3dded15..16839174ae 100644 --- a/packages/charts/src/chart_types/xy_chart/utils/series.test.ts +++ b/packages/charts/src/chart_types/xy_chart/utils/series.test.ts @@ -297,7 +297,7 @@ describe('Series', () => { MockGlobalSpec.axis({ id: 'y', position: Position.Left, - domain: { fit: true }, + domain: { fit: true, min: NaN, max: NaN }, }), MockSeriesSpec.bar({ id: 'spec1', @@ -327,7 +327,7 @@ describe('Series', () => { MockGlobalSpec.axis({ id: 'y', position: Position.Left, - domain: { fit: true }, + domain: { fit: true, min: NaN, max: NaN }, }), MockSeriesSpec.bar({ id: 'spec1', @@ -368,7 +368,7 @@ describe('Series', () => { MockGlobalSpec.axis({ id: 'y', position: Position.Left, - domain: { fit: true }, + domain: { fit: true, min: NaN, max: NaN }, }), MockSeriesSpec.bar({ id: 'spec1', @@ -401,7 +401,7 @@ describe('Series', () => { MockGlobalSpec.axis({ id: 'y', position: Position.Left, - domain: { fit: true }, + domain: { fit: true, min: NaN, max: NaN }, }), MockSeriesSpec.bar({ id: 'spec1', @@ -859,7 +859,7 @@ describe('Series', () => { expect([...splitSeries.dataSeries.values()].length).toBe(2); expect([...splitSeries.dataSeries.values()].map(matchOnlyDataSeriesLegacySnapshot)).toMatchSnapshot(); }); - test('Should ignore series if splitSeriesAccessors are defined but not contained in any datum', () => { + test('Should ignore series if splitSerie§sAccessors are defined but not contained in any datum', () => { const spec = MockSeriesSpec.bar({ data: [ [0, 1], diff --git a/packages/charts/src/chart_types/xy_chart/utils/specs.ts b/packages/charts/src/chart_types/xy_chart/utils/specs.ts index dc5a27a491..8613926b24 100644 --- a/packages/charts/src/chart_types/xy_chart/utils/specs.ts +++ b/packages/charts/src/chart_types/xy_chart/utils/specs.ts @@ -117,6 +117,7 @@ export type SeriesName = string | number | null; * @public */ export type SeriesNameFn = (series: XYChartSeriesIdentifier, isTooltip: boolean) => SeriesName; + /** * Accessor mapping to replace names * @public @@ -144,6 +145,7 @@ export interface SeriesNameConfig { */ sortIndex?: number; } + /** @public */ export interface SeriesNameConfigOptions { /** @@ -165,6 +167,7 @@ export interface SeriesNameConfigOptions { */ delimiter?: string; } + /** @public */ export type SeriesNameAccessor = string | SeriesNameFn | SeriesNameConfigOptions; @@ -256,9 +259,11 @@ export const Fit = Object.freeze({ /** @public */ export type Fit = $Values; -interface DomainBase { +/** @public */ +export interface DomainRange { /** - * Custom minInterval for the domain which will affect data bucket size. + * Custom minInterval for the domain which will affect data bin size. + * `min: NaN` or `max: NaN` can be used for either or both extrema, when unbounded. * The minInterval cannot be greater than the computed minimum interval between any two adjacent data points. * Further, if you specify a custom numeric minInterval for a time-series, please note that due to the restriction * above, the specified numeric minInterval will be interpreted as a fixed interval. @@ -266,6 +271,8 @@ interface DomainBase { * compute the interval between 2016 and 2017, you'll have 366 days due to 2016 being a leap year. This will not * be a valid interval because it is greater than the computed minInterval of 365 days between the other years. */ + min: number; + max: number; minInterval?: number; } @@ -342,31 +349,6 @@ export interface YDomainBase { constrainPadding?: boolean; } -interface LowerBound { - /** - * Lower bound of domain range - */ - min: number; -} - -interface UpperBound { - /** - * Upper bound of domain range - */ - max: number; -} - -/** @public */ -export type LowerBoundedDomain = DomainBase & LowerBound; -/** @public */ -export type UpperBoundedDomain = DomainBase & UpperBound; -/** @public */ -export type CompleteBoundedDomain = DomainBase & LowerBound & UpperBound; -/** @public */ -export type UnboundedDomainWithInterval = DomainBase; - -/** @public */ -export type DomainRange = LowerBoundedDomain | UpperBoundedDomain | CompleteBoundedDomain | UnboundedDomainWithInterval; /** @public */ export type YDomainRange = YDomainBase & DomainRange & LogScaleOptions; diff --git a/packages/charts/src/components/icons/icon.tsx b/packages/charts/src/components/icons/icon.tsx index f0763ad6dc..f890129ac5 100644 --- a/packages/charts/src/components/icons/icon.tsx +++ b/packages/charts/src/components/icons/icon.tsx @@ -63,10 +63,11 @@ function IconComponent({ type, color, className, tabIndex, ...rest }: IconCompon * - If tab index is -1, then the consumer wants the icon to not be focusable. * - For all other values, the consumer wants the icon to be focusable. */ - const focusable = tabIndex == null || tabIndex === -1 ? 'false' : 'true'; + const focusable = tabIndex === undefined || tabIndex === -1 ? 'false' : 'true'; return ; } + IconComponent.displayName = 'Icon'; /** @internal */ diff --git a/packages/charts/src/components/legend/utils.ts b/packages/charts/src/components/legend/utils.ts index d4ba2929a0..30d1518274 100644 --- a/packages/charts/src/components/legend/utils.ts +++ b/packages/charts/src/components/legend/utils.ts @@ -18,12 +18,6 @@ export function getExtra(extraValues: Map, item: const [{ key }] = seriesIdentifiers; const extraValueKey = path.map(({ index }) => index).join('__'); const itemExtraValues = extraValues.has(extraValueKey) ? extraValues.get(extraValueKey) : extraValues.get(key); - const actionExtra = (childId && itemExtraValues?.get(childId)) ?? null; - if (extraValues.size !== totalItems) { - if (actionExtra != null) { - return actionExtra; - } - return ''; - } - return actionExtra !== null ? actionExtra : defaultExtra?.formatted ?? ''; + const actionExtra = childId && itemExtraValues?.get(childId); + return actionExtra ?? (extraValues.size === totalItems ? defaultExtra?.formatted : null) ?? ''; } diff --git a/packages/charts/src/components/portal/tooltip_portal.tsx b/packages/charts/src/components/portal/tooltip_portal.tsx index 5585f27e02..e80470851f 100644 --- a/packages/charts/src/components/portal/tooltip_portal.tsx +++ b/packages/charts/src/components/portal/tooltip_portal.tsx @@ -7,12 +7,12 @@ */ import { createPopper, Instance } from '@popperjs/core'; -import { useRef, useEffect, useCallback, ReactNode, useMemo } from 'react'; +import { ReactNode, useCallback, useEffect, useMemo, useRef } from 'react'; import { createPortal } from 'react-dom'; -import { mergePartial, isDefined } from '../../utils/common'; +import { isDefined, mergePartial } from '../../utils/common'; import { Padding } from '../../utils/dimensions'; -import { TooltipPortalSettings, PortalAnchorRef } from './types'; +import { PortalAnchorRef, TooltipPortalSettings } from './types'; import { DEFAULT_POPPER_SETTINGS, getOrCreateNode, isHTMLElement } from './utils'; /** @@ -94,16 +94,13 @@ const TooltipPortalComponent = ({ * Popper instance used to manage position of tooltip. */ const popper = useRef(null); - const popperSettings = useMemo( + // @ts-ignore () => mergePartial(DEFAULT_POPPER_SETTINGS, settings, { mergeOptionalPartialValues: true }), - [settings], ); - const anchorPosition = (anchor as PortalAnchorRef)?.position; const position = useMemo(() => (isHTMLElement(anchor) ? null : anchorPosition), [anchor, anchorPosition]); - const destroyPopper = useCallback(() => { if (popper.current) { popper.current.destroy(); diff --git a/packages/charts/src/components/portal/utils.ts b/packages/charts/src/components/portal/utils.ts index a8efa5206d..a50f33e0d2 100644 --- a/packages/charts/src/components/portal/utils.ts +++ b/packages/charts/src/components/portal/utils.ts @@ -90,7 +90,7 @@ export function getElementZIndex(element: HTMLElement, cousin: HTMLElement): num element = element.offsetParent as HTMLElement; // stop if there is no parent - if (element == null) { + if (!element) { break; } diff --git a/packages/charts/src/mocks/specs/specs.ts b/packages/charts/src/mocks/specs/specs.ts index 5d7a7f80b6..faaeef28c7 100644 --- a/packages/charts/src/mocks/specs/specs.ts +++ b/packages/charts/src/mocks/specs/specs.ts @@ -343,6 +343,7 @@ export class MockGlobalSpec { }; static settings(partial?: Partial): SettingsSpec { + // @ts-ignore return mergePartial(MockGlobalSpec.settingsBase, partial, { mergeOptionalPartialValues: true }); } diff --git a/packages/charts/src/scales/index.ts b/packages/charts/src/scales/index.ts index b504e82a9c..33a738504f 100644 --- a/packages/charts/src/scales/index.ts +++ b/packages/charts/src/scales/index.ts @@ -37,16 +37,15 @@ export interface Scale { step: number; ticks: () => T[]; scale: (value?: PrimitiveValue) => number | null; - scaleOrThrow(value?: PrimitiveValue): number; pureScale: (value?: PrimitiveValue) => number | null; - invert: (value: number) => any; + invert: (value: number) => T; invertWithStep: ( value: number, data: any[], ) => { - value: any; + value: T; withinBandwidth: boolean; - } | null; + }; isSingleValue: () => boolean; /** Check if the passed value is within the scale domain */ isValueInDomain: (value: any) => boolean; @@ -61,6 +60,8 @@ export interface Scale { unit?: string; isInverted: boolean; barsPadding: number; + + scaleOrThrow(value?: PrimitiveValue): number; } /** @internal */ diff --git a/packages/charts/src/scales/scale_band.test.ts b/packages/charts/src/scales/scale_band.test.ts index 7d64fb5cb0..cdc22073d4 100644 --- a/packages/charts/src/scales/scale_band.test.ts +++ b/packages/charts/src/scales/scale_band.test.ts @@ -41,8 +41,8 @@ describe('Scale Band', () => { expect(scale.bandwidth).toBe(25); expect(scale.isValueInDomain('a')).toBe(true); expect(scale.isValueInDomain('b')).toBe(true); - expect(scale.isValueInDomain('z')).toBe(false); - expect(scale.isValueInDomain(null)).toBe(false); + expect(scale.isValueInDomain('z' as any)).toBe(false); + expect(scale.isValueInDomain(null as any)).toBe(false); }); it('shall scale remove domain duplicates', () => { const scale = new ScaleBand(['a', 'a', 'b', 'c', 'c', 'd'], [0, 100]); diff --git a/packages/charts/src/scales/scale_band.ts b/packages/charts/src/scales/scale_band.ts index 538dd093fd..2abcf1a5c1 100644 --- a/packages/charts/src/scales/scale_band.ts +++ b/packages/charts/src/scales/scale_band.ts @@ -35,7 +35,7 @@ export class ScaleBand implements Scale { readonly type: ScaleBandType; - readonly domain: T[]; + readonly domain: [T, ...T[]]; readonly range: number[]; @@ -50,7 +50,7 @@ export class ScaleBand implements Scale { private readonly d3Scale: D3ScaleBand>; constructor( - domain: T[], + inputDomain: T[], range: Range, overrideBandwidth?: number, /** @@ -60,36 +60,27 @@ export class ScaleBand implements Scale { */ barsPadding: Ratio | RelativeBandsPadding = 0, ) { + const isObjectPad = typeof barsPadding === 'object'; + const safeBarPadding = isObjectPad ? 0 : clamp(barsPadding, 0, 1); this.type = ScaleType.Ordinal; this.d3Scale = scaleBand>(); - this.d3Scale.domain(domain); + this.d3Scale.domain(inputDomain.length > 0 ? inputDomain : [(undefined as unknown) as T]); this.d3Scale.range(range); - let safeBarPadding = 0; - if (typeof barsPadding === 'object') { - this.d3Scale.paddingInner(barsPadding.inner); - this.d3Scale.paddingOuter(barsPadding.outer); - this.barsPadding = barsPadding.inner; - } else { - safeBarPadding = clamp(barsPadding, 0, 1); - this.d3Scale.paddingInner(safeBarPadding); - this.barsPadding = safeBarPadding; - this.d3Scale.paddingOuter(safeBarPadding / 2); - } - + this.d3Scale.paddingInner(isObjectPad ? barsPadding.inner : safeBarPadding); + this.d3Scale.paddingOuter(isObjectPad ? barsPadding.outer : safeBarPadding / 2); + this.barsPadding = isObjectPad ? barsPadding.inner : safeBarPadding; this.outerPadding = this.d3Scale.paddingOuter(); this.innerPadding = this.d3Scale.paddingInner(); - this.bandwidth = this.d3Scale.bandwidth() || 0; + this.bandwidth = overrideBandwidth ? overrideBandwidth * (1 - safeBarPadding) : this.d3Scale.bandwidth() || 0; this.originalBandwidth = this.d3Scale.bandwidth() || 0; this.step = this.d3Scale.step(); - this.domain = [...new Set(domain)]; + this.domain = (inputDomain.length > 0 ? [...new Set(inputDomain)] : [undefined]) as [T, ...T[]]; this.range = range.slice(); - if (overrideBandwidth) { - this.bandwidth = overrideBandwidth * (1 - safeBarPadding); - } this.bandwidthPadding = this.bandwidth; - // TO FIX: we are assuming that it's ordered - this.isInverted = this.domain[0] > this.domain[1]; - this.invertedScale = scaleQuantize().domain(range).range(this.domain); + this.isInverted = false; + this.invertedScale = scaleQuantize() + .domain(range) + .range(inputDomain.length > 0 ? [...new Set(inputDomain)] : [(undefined as unknown) as T]); this.minInterval = 0; } @@ -125,11 +116,11 @@ export class ScaleBand implements Scale { return this.domain; } - invert(value: any) { + invert(value: number) { return this.invertedScale(value); } - invertWithStep(value: any) { + invertWithStep(value: number) { return { value: this.invertedScale(value), withinBandwidth: true, @@ -140,7 +131,7 @@ export class ScaleBand implements Scale { return this.domain.length < 2; } - isValueInDomain(value: any) { + isValueInDomain(value: T) { return this.domain.includes(value); } } diff --git a/packages/charts/src/scales/scale_continuous.ts b/packages/charts/src/scales/scale_continuous.ts index f0ef6148f8..0864e66ddc 100644 --- a/packages/charts/src/scales/scale_continuous.ts +++ b/packages/charts/src/scales/scale_continuous.ts @@ -182,7 +182,7 @@ interface ScaleData { /** The Type of continuous scale */ type: ScaleContinuousType; /** The data input domain */ - domain: any[]; + domain: number[]; /** The data output range */ range: Range; nice?: boolean; @@ -210,7 +210,7 @@ export interface LogScaleOptions { type ScaleOptions = Required & { /** - * The desidered bandwidth for a linear band scale. + * The desired bandwidth for a linear band scale. * @defaultValue 0 */ bandwidth: number; @@ -295,7 +295,7 @@ export class ScaleContinuous implements Scale { readonly type: ScaleContinuousType; - readonly domain: any[]; + readonly domain: number[]; readonly range: Range; @@ -342,7 +342,7 @@ export class ScaleContinuous implements Scale { if (nice && type !== ScaleType.Time) { (this.d3Scale as ScaleContinuousNumeric).domain(this.domain).nice(desiredTickCount); - this.domain = this.d3Scale.domain(); + this.domain = this.d3Scale.domain() as number[]; } const safeBarPadding = clamp(barsPadding, 0, 1); @@ -372,7 +372,7 @@ export class ScaleContinuous implements Scale { if (nice) { (this.d3Scale as ScaleContinuousNumeric).domain(newDomain).nice(desiredTickCount); - this.domain = this.d3Scale.domain(); + this.domain = this.d3Scale.domain() as number[]; } else { this.domain = newDomain; this.d3Scale.domain(newDomain); @@ -476,9 +476,9 @@ export class ScaleContinuous implements Scale { ): { value: number; withinBandwidth: boolean; - } | null { + } { if (data.length === 0) { - return null; + return { value: NaN, withinBandwidth: false }; } const invertedValue = this.invert(value); const bisectValue = this.bandwidth === 0 ? invertedValue + this.minInterval / 2 : invertedValue; diff --git a/packages/charts/src/scales/types.ts b/packages/charts/src/scales/types.ts index c05234bd09..df0a977301 100644 --- a/packages/charts/src/scales/types.ts +++ b/packages/charts/src/scales/types.ts @@ -23,7 +23,7 @@ export function isLogarithmicScale(scale: Scale): scale is Scal * Check if a scale is Band * @internal */ -export function isBandScale(scale: Scale): scale is ScaleBand { +export function isBandScale(scale: Scale): scale is ScaleBand { return scale.type === ScaleType.Ordinal; } diff --git a/packages/charts/src/state/selectors/is_external_tooltip_visible.ts b/packages/charts/src/state/selectors/is_external_tooltip_visible.ts index a4ca924d76..a15cddde98 100644 --- a/packages/charts/src/state/selectors/is_external_tooltip_visible.ts +++ b/packages/charts/src/state/selectors/is_external_tooltip_visible.ts @@ -31,7 +31,7 @@ export const isExternalTooltipVisibleSelector = createCustomCachedSelector( } const x = xScale.pureScale(pointer.x); - if (x == null || x > chartDimensions.width + chartDimensions.left || x < 0) { + if (x === null || x > chartDimensions.width + chartDimensions.left || x < 0) { return false; } return Boolean(hasExternalEvent && externalPointerEvents.tooltip?.visible); diff --git a/packages/charts/src/utils/common.test.ts b/packages/charts/src/utils/common.test.ts index 4efd01e9d2..4392dc0c36 100644 --- a/packages/charts/src/utils/common.test.ts +++ b/packages/charts/src/utils/common.test.ts @@ -9,7 +9,6 @@ import { clamp, compareByValueAsc, - identity, hasPartialObjectToMerge, mergePartial, RecursivePartial, @@ -34,16 +33,6 @@ describe('common utilities', () => { expect(clamp(0.1, 0, 1)).toBe(0.1); expect(clamp(0.8, 0, 1)).toBe(0.8); }); - test('identity', () => { - expect(identity('text')).toBe('text'); - expect(identity(2)).toBe(2); - const a = {}; - expect(identity(a)).toBe(a); - expect(identity(null)).toBe(null); - expect(identity(undefined)).toBeUndefined(); - const fn = () => ({}); - expect(identity(fn)).toBe(fn); - }); test('compareByValueAsc', () => { expect([2, 1, 4, 3].sort(compareByValueAsc)).toEqual([1, 2, 3, 4]); diff --git a/packages/charts/src/utils/common.tsx b/packages/charts/src/utils/common.tsx index 3802c8de7b..4557decfca 100644 --- a/packages/charts/src/utils/common.tsx +++ b/packages/charts/src/utils/common.tsx @@ -125,11 +125,6 @@ export type Color = string; // todo static/runtime type it this for proper color /** @public */ export type StrokeStyle = Color; // now narrower than string | CanvasGradient | CanvasPattern -/** @internal */ -export function identity(value: T): T { - return value; -} - /** @internal */ export function compareByValueAsc(a: number | string, b: number | string): number { return a > b ? 1 : a < b ? -1 : 0; diff --git a/packages/charts/src/utils/d3-delaunay/index.ts b/packages/charts/src/utils/d3-delaunay/index.ts index eae4d0d23c..a8cbe8c527 100644 --- a/packages/charts/src/utils/d3-delaunay/index.ts +++ b/packages/charts/src/utils/d3-delaunay/index.ts @@ -929,7 +929,7 @@ export class Voronoi

implements VoronoiI

{ * The specified context must implement the context.moveTo and context.lineTo methods from the CanvasPathMethods API. */ render(context: MoveContext & LineContext): void { - const buffer = context == null ? (context = new Path()) : undefined; + const buffer = context === null ? (context = new Path()) : undefined; const { delaunay: { halfedges, inedges, hull }, circumcenters, @@ -966,7 +966,7 @@ export class Voronoi

implements VoronoiI

{ * Equivalent to context.rect(voronoi.xmin, voronoi.ymin, voronoi.xmax - voronoi.xmin, voronoi.ymax - voronoi.ymin). */ renderBounds(context: RectContext): void { - const buffer = context == null ? (context = new Path()) : undefined; + const buffer = context === null ? (context = new Path()) : undefined; context.rect(this.xmin, this.ymin, this.xmax - this.xmin, this.ymax - this.ymin); return buffer && buffer.value(); } diff --git a/packages/charts/src/utils/dimensions.ts b/packages/charts/src/utils/dimensions.ts index 22c5d51091..e58d06975b 100644 --- a/packages/charts/src/utils/dimensions.ts +++ b/packages/charts/src/utils/dimensions.ts @@ -32,7 +32,7 @@ export interface PerSideDistance { } /** - * fixme consider deactivating @typescript-eslint/no-empty-interface + * fixme consider deactivating \@typescript-eslint/no-empty-interface * see https://github.com/elastic/elastic-charts/pull/660#discussion_r419474171 * @public */ diff --git a/packages/charts/src/utils/domain.test.ts b/packages/charts/src/utils/domain.test.ts index 8b3790f314..deb2ce7f1b 100644 --- a/packages/charts/src/utils/domain.test.ts +++ b/packages/charts/src/utils/domain.test.ts @@ -9,19 +9,18 @@ import { ScaleType } from '../scales/constants'; import { DomainPaddingUnit } from '../specs'; import { AccessorFn } from './accessor'; -import { identity } from './common'; import { computeContinuousDataDomain, computeDomainExtent, computeOrdinalDataDomain } from './domain'; describe('utils/domain', () => { - test('should return [0] domain if no data', () => { + test('should return [] domain if no data', () => { const data: any[] = []; const accessor: AccessorFn = (datum: any) => datum.x; const isSorted = true; const removeNull = true; - const ordinalDataDomain = computeOrdinalDataDomain(data, accessor, isSorted, removeNull); + const ordinalDataDomain = computeOrdinalDataDomain(data.map(accessor), isSorted, removeNull); - expect(ordinalDataDomain).toEqual([0]); + expect(ordinalDataDomain).toEqual([]); }); test('should compute ordinal data domain: sort & remove nulls', () => { @@ -30,7 +29,7 @@ describe('utils/domain', () => { const isSorted = true; const removeNull = true; - const ordinalDataDomain = computeOrdinalDataDomain(data, accessor, isSorted, removeNull); + const ordinalDataDomain = computeOrdinalDataDomain(data.map(accessor), isSorted, removeNull); const expectedOrdinalDomain = ['a', 'b', 'd']; @@ -43,7 +42,7 @@ describe('utils/domain', () => { const isSorted = false; const removeNull = true; - const ordinalDataDomain = computeOrdinalDataDomain(data, accessor, isSorted, removeNull); + const ordinalDataDomain = computeOrdinalDataDomain(data.map(accessor), isSorted, removeNull); const expectedOrdinalDomain = ['d', 'a', 'b']; @@ -56,7 +55,7 @@ describe('utils/domain', () => { const isSorted = true; const removeNull = false; - const ordinalDataDomain = computeOrdinalDataDomain(data, accessor, isSorted, removeNull); + const ordinalDataDomain = computeOrdinalDataDomain(data.map(accessor), isSorted, removeNull); const expectedOrdinalDomain = ['a', 'b', 'd', null]; @@ -69,7 +68,7 @@ describe('utils/domain', () => { const isSorted = false; const removeNull = false; - const ordinalDataDomain = computeOrdinalDataDomain(data, accessor, isSorted, removeNull); + const ordinalDataDomain = computeOrdinalDataDomain(data.map(accessor), isSorted, removeNull); const expectedOrdinalDomain = ['d', 'a', null, 'b']; @@ -79,7 +78,8 @@ describe('utils/domain', () => { test('should compute continuous data domain: data scaled to extent', () => { const data = [{ x: 12 }, { x: 6 }, { x: 8 }]; const accessor = (datum: any) => datum.x; - const continuousDataDomain = computeContinuousDataDomain(data, accessor, ScaleType.Linear, { fit: true }); + const domainOptions = { min: NaN, max: NaN, fit: true }; + const continuousDataDomain = computeContinuousDataDomain(data.map(accessor), ScaleType.Linear, domainOptions); const expectedContinuousDomain = [6, 12]; expect(continuousDataDomain).toEqual(expectedContinuousDomain); @@ -88,20 +88,15 @@ describe('utils/domain', () => { test('should compute continuous data domain: data not scaled to extent', () => { const data = [{ x: 12 }, { x: 6 }, { x: 8 }]; const accessor = (datum: any) => datum.x; - - const continuousDataDomain = computeContinuousDataDomain(data, accessor, ScaleType.Linear); - + const domainOptions3 = { min: NaN, max: NaN }; + const continuousDataDomain = computeContinuousDataDomain(data.map(accessor), ScaleType.Linear, domainOptions3); const expectedContinuousDomain = [0, 12]; expect(continuousDataDomain).toEqual(expectedContinuousDomain); }); test('should compute continuous data domain: empty data not scaled to extent', () => { - const data: any[] = []; - const accessor = (datum: any) => datum.x; - - const continuousDataDomain = computeContinuousDataDomain(data, accessor, ScaleType.Linear); - + const continuousDataDomain = computeContinuousDataDomain([], ScaleType.Linear, undefined); const expectedContinuousDomain = [0, 0]; expect(continuousDataDomain).toEqual(expectedContinuousDomain); @@ -109,98 +104,98 @@ describe('utils/domain', () => { test('should filter zeros on log scale domain when fit is true', () => { const data: number[] = [0.0001, 0, 1, 0, 10, 0, 100, 0, 0, 1000]; - const continuousDataDomain = computeContinuousDataDomain(data, identity, ScaleType.Log, { fit: true }); + const domainOptions1 = { fit: true, min: NaN, max: NaN }; + const continuousDataDomain = computeContinuousDataDomain(data, ScaleType.Log, domainOptions1); expect(continuousDataDomain).toEqual([0.0001, 1000]); }); test('should not filter zeros on log scale domain when fit is false', () => { const data: number[] = [0.0001, 0, 1, 0, 10, 0, 100, 0, 0, 1000]; - const continuousDataDomain = computeContinuousDataDomain(data, identity, ScaleType.Log, { fit: false }); + const domainOptions2 = { fit: false, min: NaN, max: NaN }; + const continuousDataDomain = computeContinuousDataDomain(data, ScaleType.Log, domainOptions2); expect(continuousDataDomain).toEqual([0, 1000]); }); describe('YDomainOptions', () => { it('should not effect domain when domain.fit is true', () => { - expect(computeDomainExtent([5, 10], { fit: true })).toEqual([5, 10]); + expect(computeDomainExtent([5, 10], { fit: true, min: NaN, max: NaN })).toEqual([5, 10]); }); // Note: padded domains are possible with log scale but not very practical it('should not effect positive domain if log scale with padding', () => { - expect(computeDomainExtent([0.001, 10], { padding: 5 })).toEqual([0, 15]); + expect(computeDomainExtent([0.001, 10], { padding: 5, min: NaN, max: NaN })).toEqual([0, 15]); }); it('should not effect negative domain if log scale with padding', () => { - expect(computeDomainExtent([-10, -0.001], { padding: 5 })).toEqual([-15, 0]); + expect(computeDomainExtent([-10, -0.001], { padding: 5, min: NaN, max: NaN })).toEqual([-15, 0]); }); describe('domain.fit is true', () => { it('should find domain when start & end are positive', () => { - expect(computeDomainExtent([5, 10], { fit: true })).toEqual([5, 10]); + expect(computeDomainExtent([5, 10], { fit: true, min: NaN, max: NaN })).toEqual([5, 10]); }); it('should find domain when start & end are negative', () => { - expect(computeDomainExtent([-15, -10], { fit: true })).toEqual([-15, -10]); + expect(computeDomainExtent([-15, -10], { fit: true, min: NaN, max: NaN })).toEqual([-15, -10]); }); it('should find domain when start is negative, end is positive', () => { - expect(computeDomainExtent([-15, 10], { fit: true })).toEqual([-15, 10]); + expect(computeDomainExtent([-15, 10], { fit: true, min: NaN, max: NaN })).toEqual([-15, 10]); }); }); describe('domain.fit is false', () => { it('should find domain when start & end are positive', () => { - expect(computeDomainExtent([5, 10])).toEqual([0, 10]); + expect(computeDomainExtent([5, 10], { min: NaN, max: NaN })).toEqual([0, 10]); }); it('should find domain when start & end are negative', () => { - expect(computeDomainExtent([-15, -10])).toEqual([-15, 0]); + expect(computeDomainExtent([-15, -10], { min: NaN, max: NaN })).toEqual([-15, 0]); }); it('should find domain when start is negative, end is positive', () => { - expect(computeDomainExtent([-15, 10])).toEqual([-15, 10]); + expect(computeDomainExtent([-15, 10], { min: NaN, max: NaN })).toEqual([-15, 10]); }); }); describe('padding does NOT cause domain to cross zero baseline', () => { it('should get domain from positive domain', () => { - expect(computeDomainExtent([10, 70], { fit: true, padding: 5 })).toEqual([5, 75]); + expect(computeDomainExtent([10, 70], { fit: true, padding: 5, min: NaN, max: NaN })).toEqual([5, 75]); }); it('should get domain from positive & negative domain', () => { - expect(computeDomainExtent([-30, 30], { fit: true, padding: 5 })).toEqual([-35, 35]); + expect(computeDomainExtent([-30, 30], { fit: true, padding: 5, min: NaN, max: NaN })).toEqual([-35, 35]); }); it('should get domain from negative domain', () => { - expect(computeDomainExtent([-70, -10], { fit: true, padding: 5 })).toEqual([-75, -5]); + expect(computeDomainExtent([-70, -10], { fit: true, padding: 5, min: NaN, max: NaN })).toEqual([-75, -5]); }); it('should use absolute padding value', () => { - expect(computeDomainExtent([10, 70], { fit: true, padding: -5 })).toEqual([5, 75]); + expect(computeDomainExtent([10, 70], { fit: true, padding: -5, min: NaN, max: NaN })).toEqual([5, 75]); }); }); describe('padding caused domain to cross zero baseline', () => { describe('constrainPadding true - default', () => { it('should set min baseline as 0 if original domain is less than zero', () => { - expect(computeDomainExtent([5, 65], { fit: true, padding: 15 })).toEqual([0, 80]); + expect(computeDomainExtent([5, 65], { fit: true, padding: 15, min: NaN, max: NaN })).toEqual([0, 80]); }); it('should set max baseline as 0 if original domain is less than zero', () => { - expect(computeDomainExtent([-65, -5], { fit: true, padding: 15 })).toEqual([-80, 0]); + expect(computeDomainExtent([-65, -5], { fit: true, padding: 15, min: NaN, max: NaN })).toEqual([-80, 0]); }); }); describe('constrainPadding false', () => { + const domainOptions = { fit: true, padding: 15, constrainPadding: false, min: NaN, max: NaN }; it('should allow min past baseline as 0, even if original domain is less than zero', () => { - expect(computeDomainExtent([5, 65], { fit: true, padding: 15, constrainPadding: false })).toEqual([-10, 80]); + expect(computeDomainExtent([5, 65], domainOptions)).toEqual([-10, 80]); }); it('should allow max past baseline as 0, even if original domain is less than zero', () => { - expect(computeDomainExtent([-65, -5], { fit: true, padding: 15, constrainPadding: false })).toEqual([ - -80, - 10, - ]); + expect(computeDomainExtent([-65, -5], domainOptions)).toEqual([-80, 10]); }); }); }); @@ -208,24 +203,31 @@ describe('utils/domain', () => { describe('padding units', () => { // Note: domain pixel padding computed in continuous scale it('should not change domain when using Pixel padding unit', () => { - expect(computeDomainExtent([5, 65], { fit: true, padding: 15, paddingUnit: DomainPaddingUnit.Pixel })).toEqual([ - 5, - 65, - ]); - }); + const domainOptions = { fit: true, padding: 15, paddingUnit: DomainPaddingUnit.Pixel, min: NaN, max: NaN }; + expect(computeDomainExtent([5, 65], domainOptions)).toEqual([5, 65]); + }); + const domainOptions1 = { + fit: true, + padding: 0.5, + paddingUnit: DomainPaddingUnit.DomainRatio, + min: NaN, + max: NaN, + }; it('should handle DomainRatio padding unit', () => { - expect( - computeDomainExtent([50, 60], { fit: true, padding: 0.5, paddingUnit: DomainPaddingUnit.DomainRatio }), - ).toEqual([45, 65]); + expect(computeDomainExtent([50, 60], domainOptions1)).toEqual([45, 65]); }); it('should handle negative inverted DomainRatio padding unit', () => { - expect( - computeDomainExtent([-50, -60], { fit: true, padding: 0.5, paddingUnit: DomainPaddingUnit.DomainRatio }), - ).toEqual([-45, -65]); + expect(computeDomainExtent([-50, -60], domainOptions1)).toEqual([-45, -65]); }); it('should handle negative inverted Domain padding unit', () => { expect( - computeDomainExtent([-50, -60], { fit: true, padding: 10, paddingUnit: DomainPaddingUnit.Domain }), + computeDomainExtent([-50, -60], { + fit: true, + padding: 10, + paddingUnit: DomainPaddingUnit.Domain, + min: NaN, + max: NaN, + }), ).toEqual([-40, -70]); }); }); diff --git a/packages/charts/src/utils/domain.ts b/packages/charts/src/utils/domain.ts index 49edabd589..31016ce845 100644 --- a/packages/charts/src/utils/domain.ts +++ b/packages/charts/src/utils/domain.ts @@ -10,7 +10,6 @@ import { extent } from 'd3-array'; import { ScaleType } from '../scales/constants'; import { DomainPaddingUnit, YDomainRange } from '../specs'; -import { AccessorFn } from './accessor'; /** @public */ export type OrdinalDomain = (number | string)[]; @@ -19,105 +18,61 @@ export type ContinuousDomain = [min: number, max: number]; /** @public */ export type Range = [min: number, max: number]; -/** - * Returns padded domain given constrain - * @internal */ -export function constrainPadding( +function constrainPadding( start: number, end: number, newStart: number, newEnd: number, constrain: boolean = true, ): [number, number] { - if (constrain) { - if (start < end) { - return [start >= 0 && newStart < 0 ? 0 : newStart, end <= 0 && newEnd > 0 ? 0 : newEnd]; - } - - return [end >= 0 && newEnd < 0 ? 0 : newEnd, start <= 0 && newStart > 0 ? 0 : newStart]; - } - - return [newStart, newEnd]; + return constrain + ? start < end + ? [newStart >= 0 || start < 0 ? newStart : 0, newEnd <= 0 || end > 0 ? newEnd : 0] + : [newEnd >= 0 || end < 0 ? newEnd : 0, newStart <= 0 || start > 0 ? newStart : 0] + : [newStart, newEnd]; } /** @internal */ -export function computeOrdinalDataDomain( - data: any[], - accessor: AccessorFn, - sorted?: boolean, - removeNull?: boolean, -): string[] | number[] { - // TODO: Check for empty data before computing domain - if (data.length === 0) { - return [0]; - } - - const domain = data.map(accessor).filter((d) => (removeNull ? d !== null : true)); - const uniqueValues = [...new Set(domain)]; +export function computeOrdinalDataDomain(data: T[], sorted: boolean, removeNull: boolean): T[] { + const uniqueValues = [...new Set(removeNull ? data.filter((d) => d !== null) : data)]; return sorted ? uniqueValues.sort((a, b) => `${a}`.localeCompare(`${b}`)) : uniqueValues; } -function getPaddedDomain(start: number, end: number, domainOptions?: YDomainRange): [number, number] { - if (!domainOptions || !domainOptions.padding || domainOptions.paddingUnit === DomainPaddingUnit.Pixel) { - return [start, end]; - } - +function getPaddedDomain(start: number, end: number, domainOptions: YDomainRange): [number, number] { const { padding, paddingUnit = DomainPaddingUnit.Domain } = domainOptions; - const absPadding = Math.abs(padding); - const computedPadding = paddingUnit === DomainPaddingUnit.Domain ? absPadding : absPadding * Math.abs(end - start); - - if (computedPadding === 0) { - return [start, end]; - } - - const newStart = start - computedPadding; - const newEnd = end + computedPadding; - - return constrainPadding(start, end, newStart, newEnd, domainOptions.constrainPadding); + if (!padding || paddingUnit === DomainPaddingUnit.Pixel) return [start, end]; + const computedPadding = Math.abs(padding * (paddingUnit === DomainPaddingUnit.Domain ? 1 : end - start)); + return constrainPadding(start, end, start - computedPadding, end + computedPadding, domainOptions.constrainPadding); } /** @internal */ export function computeDomainExtent( domain: [number, number] | [undefined, undefined], - domainOptions?: YDomainRange, + domainOptions: YDomainRange, ): [number, number] { - if (domain[0] == null || domain[1] == null) return [0, 0]; - + if (domain[0] === undefined) return [0, 0]; // if domain[1] is undefined, domain[0] is undefined too const inverted = domain[0] > domain[1]; const paddedDomain = (([start, end]: Range): Range => { const [paddedStart, paddedEnd] = getPaddedDomain(start, end, domainOptions); - - if (paddedStart >= 0 && paddedEnd >= 0) { - return domainOptions?.fit ? [paddedStart, paddedEnd] : [0, paddedEnd]; - } - if (paddedStart < 0 && paddedEnd < 0) { - return domainOptions?.fit ? [paddedStart, paddedEnd] : [paddedStart, 0]; - } - + if (paddedStart >= 0 && paddedEnd >= 0) return domainOptions.fit ? [paddedStart, paddedEnd] : [0, paddedEnd]; + if (paddedStart < 0 && paddedEnd < 0) return domainOptions.fit ? [paddedStart, paddedEnd] : [paddedStart, 0]; return [paddedStart, paddedEnd]; - })(inverted ? (domain.slice().reverse() as Range) : domain); + })(inverted ? [domain[1], domain[0]] : domain); - return inverted ? (paddedDomain.slice().reverse() as Range) : paddedDomain; + return inverted ? [paddedDomain[1], paddedDomain[0]] : paddedDomain; } /** - * Get Continuous domain from data. May alters domain to constrain to zero baseline. - * - * when `domainOptions` is null the domain will not be altered + * Get continuous domain from data. May yield domain to constrain to zero baseline. * @internal */ export function computeContinuousDataDomain( - data: any[], - accessor: (n: any) => number, + data: number[], scaleType: ScaleType, - domainOptions?: YDomainRange | null, + domainOptions: YDomainRange | undefined, ): ContinuousDomain { - const filteredData = domainOptions?.fit && scaleType === ScaleType.Log ? data.filter((d) => accessor(d) !== 0) : data; - const range = extent(filteredData, accessor); - - if (domainOptions === null) { - return [range[0] ?? 0, range[1] ?? 0]; - } - - return computeDomainExtent(range, domainOptions); + // todo check for DRY violations: this may not be the only place for non-positives removal for the log scale + const filteredData = domainOptions?.fit && scaleType === ScaleType.Log ? data.filter((d) => d !== 0) : data; + const range = extent(filteredData, (d) => d); + return domainOptions === undefined ? [range[0] ?? 0, range[1] ?? 0] : computeDomainExtent(range, domainOptions); } diff --git a/packages/charts/src/utils/fast_deep_equal.ts b/packages/charts/src/utils/fast_deep_equal.ts index d59ca584cb..e1af35f953 100644 --- a/packages/charts/src/utils/fast_deep_equal.ts +++ b/packages/charts/src/utils/fast_deep_equal.ts @@ -45,7 +45,7 @@ export function deepEqual(a: any, b: any, partial = false): boolean { if (Array.isArray(a)) { length = a.length; - if (length != b.length) return false; + if (length !== b.length) return false; for (i = length; i-- !== 0; ) if (!deepEqual(a[i], b[i])) return false; return true; } diff --git a/storybook/package.json b/storybook/package.json index 20459feebc..231941fd7d 100644 --- a/storybook/package.json +++ b/storybook/package.json @@ -39,6 +39,6 @@ "storybook-addon-background-toggle": "^0.0.1", "terser-webpack-plugin": "^4.2.3", "ts-loader": "^7.0.5", - "typescript": "^4.1.3" + "typescript": "^4.4.3" } } diff --git a/storybook/stories/bar/32_scale_to_extent.story.tsx b/storybook/stories/bar/32_scale_to_extent.story.tsx index aa43f134ad..243966fad8 100644 --- a/storybook/stories/bar/32_scale_to_extent.story.tsx +++ b/storybook/stories/bar/32_scale_to_extent.story.tsx @@ -16,13 +16,11 @@ import { useBaseTheme } from '../../use_base_theme'; import { getKnobsFromEnum, getXYSeriesKnob } from '../utils/knobs'; const logDomains = (data: any[], customDomain: any) => { + const dataY = data.map((d) => d.y); /* eslint-disable no-console */ console.clear(); - console.log('data domain:', JSON.stringify(computeContinuousDataDomain(data, (d) => d.y, ScaleType.Linear))); - console.log( - 'computed domain:', - JSON.stringify(computeContinuousDataDomain(data, (d) => d.y, ScaleType.Linear, customDomain)), - ); + console.log('data domain:', JSON.stringify(computeContinuousDataDomain(dataY, ScaleType.Linear, undefined))); + console.log('computed domain:', JSON.stringify(computeContinuousDataDomain(dataY, ScaleType.Linear, customDomain))); /* eslint-enable */ }; @@ -69,7 +67,7 @@ export const Example = () => { default: data = mixed; } - const customDomain = { fit, padding, paddingUnit, constrainPadding, nice }; + const customDomain = { fit, padding, paddingUnit, constrainPadding, nice, min: NaN, max: NaN }; if (shouldLogDomains) { logDomains(data, customDomain); diff --git a/storybook/webpack.config.js b/storybook/webpack.config.js index 7205e9330a..55a4243805 100644 --- a/storybook/webpack.config.js +++ b/storybook/webpack.config.js @@ -32,7 +32,7 @@ const scssLoaders = [ const MAX_CYCLES = 0; let numCyclesDetected = 0; -module.exports = async ({ config }) => { +module.exports = ({ config }) => { const FAST = Boolean(JSON.parse(process.env.FAST ?? false)); config.plugins.push( @@ -120,5 +120,5 @@ module.exports = async ({ config }) => { '@elastic/charts/': path.resolve(__dirname, '../packages/charts/'), }; - return await config; + return config; }; diff --git a/yarn.lock b/yarn.lock index e74ec4baed..b3a847fc9d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4081,28 +4081,53 @@ "@microsoft/tsdoc" "0.12.24" "@rushstack/node-core-library" "3.36.0" -"@microsoft/api-extractor@^7.13.1": - version "7.13.1" - resolved "https://registry.yarnpkg.com/@microsoft/api-extractor/-/api-extractor-7.13.1.tgz#0ed26ac18ccda075553e9fbe26dce4104d8d042f" - integrity sha512-mnWb5Vuyn/JnjC359HfsRmLDM4/vzyKcJuxQr5Cg/apbkMHuTB1hQrqA8zBda4N+MJZ5ET2BPsrKaUX1qhz8jw== - dependencies: - "@microsoft/api-extractor-model" "7.12.2" - "@microsoft/tsdoc" "0.12.24" - "@rushstack/node-core-library" "3.36.0" - "@rushstack/rig-package" "0.2.9" - "@rushstack/ts-command-line" "4.7.8" +"@microsoft/api-extractor-model@7.13.7": + version "7.13.7" + resolved "https://registry.yarnpkg.com/@microsoft/api-extractor-model/-/api-extractor-model-7.13.7.tgz#2ae0948cb7458b336694c458675717ef8a9dcc85" + integrity sha512-emwhcaSF/h3WdqBWps4UU0RtGOGzy53IsplxuoLwtCuMAx3namYvJSfUGa5ajGPBao4MCyRYGsMc3EZ6IdR8cQ== + dependencies: + "@microsoft/tsdoc" "0.13.2" + "@microsoft/tsdoc-config" "~0.15.2" + "@rushstack/node-core-library" "3.40.2" + +"@microsoft/api-extractor@^7.18.9": + version "7.18.9" + resolved "https://registry.yarnpkg.com/@microsoft/api-extractor/-/api-extractor-7.18.9.tgz#82f50f8791bfacd5e3dd5d9400cdb6d69a499249" + integrity sha512-N+fbG+6SwA1i6EW3iGRp/nAT8vQpRSDvZ1DzBUr8xIS7tNfJ0C75ndPPziUT8EmalhLixRnIw6Ncmur8AFELRg== + dependencies: + "@microsoft/api-extractor-model" "7.13.7" + "@microsoft/tsdoc" "0.13.2" + "@microsoft/tsdoc-config" "~0.15.2" + "@rushstack/node-core-library" "3.40.2" + "@rushstack/rig-package" "0.3.0" + "@rushstack/ts-command-line" "4.9.0" colors "~1.2.1" lodash "~4.17.15" resolve "~1.17.0" semver "~7.3.0" source-map "~0.6.1" - typescript "~4.1.3" + typescript "~4.3.5" + +"@microsoft/tsdoc-config@~0.15.2": + version "0.15.2" + resolved "https://registry.yarnpkg.com/@microsoft/tsdoc-config/-/tsdoc-config-0.15.2.tgz#eb353c93f3b62ab74bdc9ab6f4a82bcf80140f14" + integrity sha512-mK19b2wJHSdNf8znXSMYVShAHktVr/ib0Ck2FA3lsVBSEhSI/TfXT7DJQkAYgcztTuwazGcg58ZjYdk0hTCVrA== + dependencies: + "@microsoft/tsdoc" "0.13.2" + ajv "~6.12.6" + jju "~1.4.0" + resolve "~1.19.0" "@microsoft/tsdoc@0.12.24": version "0.12.24" resolved "https://registry.yarnpkg.com/@microsoft/tsdoc/-/tsdoc-0.12.24.tgz#30728e34ebc90351dd3aff4e18d038eed2c3e098" integrity sha512-Mfmij13RUTmHEMi9vRUhMXD7rnGR2VvxeNYtaGtaJ4redwwjT4UXYJ+nzmVJF7hhd4pn/Fx5sncDKxMVFJSWPg== +"@microsoft/tsdoc@0.13.2": + version "0.13.2" + resolved "https://registry.yarnpkg.com/@microsoft/tsdoc/-/tsdoc-0.13.2.tgz#3b0efb6d3903bd49edb073696f60e90df08efb26" + integrity sha512-WrHvO8PDL8wd8T2+zBGKrMwVL5IyzR3ryWUsl0PXgEV0QHup4mTLi0QcATefGI6Gx9Anu7vthPyyyLpY0EpiQg== + "@mrmlnc/readdir-enhanced@^2.2.1": version "2.2.1" resolved "https://registry.yarnpkg.com/@mrmlnc/readdir-enhanced/-/readdir-enhanced-2.2.1.tgz#524af240d1a360527b730475ecfa1344aa540dde" @@ -4485,12 +4510,26 @@ timsort "~0.3.0" z-schema "~3.18.3" -"@rushstack/rig-package@0.2.9": - version "0.2.9" - resolved "https://registry.yarnpkg.com/@rushstack/rig-package/-/rig-package-0.2.9.tgz#57ef94e7f7703b18e275b603d3f59a1a16580716" - integrity sha512-4tqsZ/m+BjeNAGeAJYzPF53CT96TsAYeZ3Pq3T4tb1pGGM3d3TWfkmALZdKNhpRlAeShKUrb/o/f/0sAuK/1VQ== +"@rushstack/node-core-library@3.40.2": + version "3.40.2" + resolved "https://registry.yarnpkg.com/@rushstack/node-core-library/-/node-core-library-3.40.2.tgz#71d92180f14bafd212f720b2cfe8892e688159b6" + integrity sha512-wzcRucwnhOENTfx6hZ2M+CA1Zmp8Dr572mFFtjxmcQzBWTbNFRB1Mi1wLb7DLza+69OUBoSZcHUqydlwL+gvSA== dependencies: "@types/node" "10.17.13" + colors "~1.2.1" + fs-extra "~7.0.1" + import-lazy "~4.0.0" + jju "~1.4.0" + resolve "~1.17.0" + semver "~7.3.0" + timsort "~0.3.0" + z-schema "~3.18.3" + +"@rushstack/rig-package@0.3.0": + version "0.3.0" + resolved "https://registry.yarnpkg.com/@rushstack/rig-package/-/rig-package-0.3.0.tgz#334ad2846797861361b3445d4cc9ae9164b1885c" + integrity sha512-Lj6noF7Q4BBm1hKiBDw94e6uZvq1xlBwM/d2cBFaPqXeGdV+G6r3qaCWfRiSXK0pcHpGGpV5Tb2MdfhVcO6G/g== + dependencies: resolve "~1.17.0" strip-json-comments "~3.1.1" @@ -4504,6 +4543,16 @@ colors "~1.2.1" string-argv "~0.3.1" +"@rushstack/ts-command-line@4.9.0": + version "4.9.0" + resolved "https://registry.yarnpkg.com/@rushstack/ts-command-line/-/ts-command-line-4.9.0.tgz#781ba42cff73cae097b6d5241b6441e7cc2fe6e0" + integrity sha512-kmT8t+JfnvphISF1C5WwY56RefjwgajhSjs9J4ckvAFXZDXR6F5cvF5/RTh7fGCzIomg8esy2PHO/b52zFoZvA== + dependencies: + "@types/argparse" "1.0.38" + argparse "~1.0.9" + colors "~1.2.1" + string-argv "~0.3.1" + "@semantic-release/changelog@^5.0.1": version "5.0.1" resolved "https://registry.yarnpkg.com/@semantic-release/changelog/-/changelog-5.0.1.tgz#50a84b63e5d391b7debfe021421589fa2bcdafe4" @@ -5752,7 +5801,7 @@ resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.7.tgz#98a993516c859eb0d5c4c8f098317a9ea68db9ad" integrity sha512-cxWFQVseBm6O9Gbw1IWb8r6OS4OhSt3hPZLkFApLjM8TEXROBuQGLAH2i2gZpcXdLBIrpXuTDhH7Vbm1iXmNGA== -"@types/json-schema@^7.0.8": +"@types/json-schema@^7.0.7", "@types/json-schema@^7.0.8": version "7.0.9" resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.9.tgz#97edc9037ea0c38585320b28964dde3b39e4660d" integrity sha512-qcUXuemtEu+E5wZSJHNxUXeCZhAfXKQ41D+duX+VYPde7xyEVZci+/oXKJL13tnRs9lR2pr4fod59GT6/X1/yQ== @@ -6145,20 +6194,32 @@ dependencies: "@types/yargs-parser" "*" -"@typescript-eslint/eslint-plugin@^4.12.0": - version "4.12.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.12.0.tgz#00d1b23b40b58031e6d7c04a5bc6c1a30a2e834a" - integrity sha512-wHKj6q8s70sO5i39H2g1gtpCXCvjVszzj6FFygneNFyIAxRvNSVz9GML7XpqrB9t7hNutXw+MHnLN/Ih6uyB8Q== +"@typescript-eslint/eslint-plugin@^4.31.1": + version "4.31.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.31.1.tgz#e938603a136f01dcabeece069da5fb2e331d4498" + integrity sha512-UDqhWmd5i0TvPLmbK5xY3UZB0zEGseF+DHPghZ37Sb83Qd3p8ujhvAtkU4OF46Ka5Pm5kWvFIx0cCTBFKo0alA== dependencies: - "@typescript-eslint/experimental-utils" "4.12.0" - "@typescript-eslint/scope-manager" "4.12.0" - debug "^4.1.1" + "@typescript-eslint/experimental-utils" "4.31.1" + "@typescript-eslint/scope-manager" "4.31.1" + debug "^4.3.1" functional-red-black-tree "^1.0.1" - regexpp "^3.0.0" - semver "^7.3.2" - tsutils "^3.17.1" + regexpp "^3.1.0" + semver "^7.3.5" + tsutils "^3.21.0" + +"@typescript-eslint/experimental-utils@4.31.1": + version "4.31.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-4.31.1.tgz#0c900f832f270b88e13e51753647b02d08371ce5" + integrity sha512-NtoPsqmcSsWty0mcL5nTZXMf7Ei0Xr2MT8jWjXMVgRK0/1qeQ2jZzLFUh4QtyJ4+/lPUyMw5cSfeeME+Zrtp9Q== + dependencies: + "@types/json-schema" "^7.0.7" + "@typescript-eslint/scope-manager" "4.31.1" + "@typescript-eslint/types" "4.31.1" + "@typescript-eslint/typescript-estree" "4.31.1" + eslint-scope "^5.1.1" + eslint-utils "^3.0.0" -"@typescript-eslint/experimental-utils@4.12.0", "@typescript-eslint/experimental-utils@^4.0.1": +"@typescript-eslint/experimental-utils@^4.0.1": version "4.12.0" resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-4.12.0.tgz#372838e76db76c9a56959217b768a19f7129546b" integrity sha512-MpXZXUAvHt99c9ScXijx7i061o5HEjXltO+sbYfZAAHxv3XankQkPaNi5myy0Yh0Tyea3Hdq1pi7Vsh0GJb0fA== @@ -6170,25 +6231,15 @@ eslint-scope "^5.0.0" eslint-utils "^2.0.0" -"@typescript-eslint/parser@4.4.1": - version "4.4.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-4.4.1.tgz#25fde9c080611f303f2f33cedb145d2c59915b80" - integrity sha512-S0fuX5lDku28Au9REYUsV+hdJpW/rNW0gWlc4SXzF/kdrRaAVX9YCxKpziH7djeWT/HFAjLZcnY7NJD8xTeUEg== - dependencies: - "@typescript-eslint/scope-manager" "4.4.1" - "@typescript-eslint/types" "4.4.1" - "@typescript-eslint/typescript-estree" "4.4.1" - debug "^4.1.1" - -"@typescript-eslint/parser@^4.12.0": - version "4.12.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-4.12.0.tgz#e1cf30436e4f916c31fcc962158917bd9e9d460a" - integrity sha512-9XxVADAo9vlfjfoxnjboBTxYOiNY93/QuvcPgsiKvHxW6tOZx1W4TvkIQ2jB3k5M0pbFP5FlXihLK49TjZXhuQ== +"@typescript-eslint/parser@^4.31.1": + version "4.31.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-4.31.1.tgz#8f9a2672033e6f6d33b1c0260eebdc0ddf539064" + integrity sha512-dnVZDB6FhpIby6yVbHkwTKkn2ypjVIfAR9nh+kYsA/ZL0JlTsd22BiDjouotisY3Irmd3OW1qlk9EI5R8GrvRQ== dependencies: - "@typescript-eslint/scope-manager" "4.12.0" - "@typescript-eslint/types" "4.12.0" - "@typescript-eslint/typescript-estree" "4.12.0" - debug "^4.1.1" + "@typescript-eslint/scope-manager" "4.31.1" + "@typescript-eslint/types" "4.31.1" + "@typescript-eslint/typescript-estree" "4.31.1" + debug "^4.3.1" "@typescript-eslint/scope-manager@4.12.0": version "4.12.0" @@ -6198,23 +6249,23 @@ "@typescript-eslint/types" "4.12.0" "@typescript-eslint/visitor-keys" "4.12.0" -"@typescript-eslint/scope-manager@4.4.1": - version "4.4.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-4.4.1.tgz#d19447e60db2ce9c425898d62fa03b2cce8ea3f9" - integrity sha512-2oD/ZqD4Gj41UdFeWZxegH3cVEEH/Z6Bhr/XvwTtGv66737XkR4C9IqEkebCuqArqBJQSj4AgNHHiN1okzD/wQ== +"@typescript-eslint/scope-manager@4.31.1": + version "4.31.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-4.31.1.tgz#0c21e8501f608d6a25c842fcf59541ef4f1ab561" + integrity sha512-N1Uhn6SqNtU2XpFSkD4oA+F0PfKdWHyr4bTX0xTj8NRx1314gBDRL1LUuZd5+L3oP+wo6hCbZpaa1in6SwMcVQ== dependencies: - "@typescript-eslint/types" "4.4.1" - "@typescript-eslint/visitor-keys" "4.4.1" + "@typescript-eslint/types" "4.31.1" + "@typescript-eslint/visitor-keys" "4.31.1" "@typescript-eslint/types@4.12.0": version "4.12.0" resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-4.12.0.tgz#fb891fe7ccc9ea8b2bbd2780e36da45d0dc055e5" integrity sha512-N2RhGeheVLGtyy+CxRmxdsniB7sMSCfsnbh8K/+RUIXYYq3Ub5+sukRCjVE80QerrUBvuEvs4fDhz5AW/pcL6g== -"@typescript-eslint/types@4.4.1": - version "4.4.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-4.4.1.tgz#c507b35cf523bc7ba00aae5f75ee9b810cdabbc1" - integrity sha512-KNDfH2bCyax5db+KKIZT4rfA8rEk5N0EJ8P0T5AJjo5xrV26UAzaiqoJCxeaibqc0c/IvZxp7v2g3difn2Pn3w== +"@typescript-eslint/types@4.31.1": + version "4.31.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-4.31.1.tgz#5f255b695627a13401d2fdba5f7138bc79450d66" + integrity sha512-kixltt51ZJGKENNW88IY5MYqTBA8FR0Md8QdGbJD2pKZ+D5IvxjTYDNtJPDxFBiXmka2aJsITdB1BtO1fsgmsQ== "@typescript-eslint/typescript-estree@4.12.0": version "4.12.0" @@ -6230,19 +6281,18 @@ semver "^7.3.2" tsutils "^3.17.1" -"@typescript-eslint/typescript-estree@4.4.1": - version "4.4.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-4.4.1.tgz#598f6de488106c2587d47ca2462c60f6e2797cb8" - integrity sha512-wP/V7ScKzgSdtcY1a0pZYBoCxrCstLrgRQ2O9MmCUZDtmgxCO/TCqOTGRVwpP4/2hVfqMz/Vw1ZYrG8cVxvN3g== +"@typescript-eslint/typescript-estree@4.31.1": + version "4.31.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-4.31.1.tgz#4a04d5232cf1031232b7124a9c0310b577a62d17" + integrity sha512-EGHkbsUvjFrvRnusk6yFGqrqMBTue5E5ROnS5puj3laGQPasVUgwhrxfcgkdHNFECHAewpvELE1Gjv0XO3mdWg== dependencies: - "@typescript-eslint/types" "4.4.1" - "@typescript-eslint/visitor-keys" "4.4.1" - debug "^4.1.1" - globby "^11.0.1" + "@typescript-eslint/types" "4.31.1" + "@typescript-eslint/visitor-keys" "4.31.1" + debug "^4.3.1" + globby "^11.0.3" is-glob "^4.0.1" - lodash "^4.17.15" - semver "^7.3.2" - tsutils "^3.17.1" + semver "^7.3.5" + tsutils "^3.21.0" "@typescript-eslint/visitor-keys@4.12.0": version "4.12.0" @@ -6252,12 +6302,12 @@ "@typescript-eslint/types" "4.12.0" eslint-visitor-keys "^2.0.0" -"@typescript-eslint/visitor-keys@4.4.1": - version "4.4.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-4.4.1.tgz#1769dc7a9e2d7d2cfd3318b77ed8249187aed5c3" - integrity sha512-H2JMWhLaJNeaylSnMSQFEhT/S/FsJbebQALmoJxMPMxLtlVAMy2uJP/Z543n9IizhjRayLSqoInehCeNW9rWcw== +"@typescript-eslint/visitor-keys@4.31.1": + version "4.31.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-4.31.1.tgz#f2e7a14c7f20c4ae07d7fc3c5878c4441a1da9cc" + integrity sha512-PCncP8hEqKw6SOJY+3St4LVtoZpPPn+Zlpm7KW5xnviMhdqcsBty4Lsg4J/VECpJjw1CkROaZhH4B8M1OfnXTQ== dependencies: - "@typescript-eslint/types" "4.4.1" + "@typescript-eslint/types" "4.31.1" eslint-visitor-keys "^2.0.0" "@webassemblyjs/ast@1.9.0": @@ -6601,7 +6651,7 @@ ajv-keywords@^3.1.0, ajv-keywords@^3.4.1, ajv-keywords@^3.5.2: resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-3.5.2.tgz#31f29da5ab6e00d1c2d329acf7b5929614d5014d" integrity sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ== -ajv@^6.1.0, ajv@^6.10.2, ajv@^6.12.3, ajv@^6.12.5: +ajv@^6.1.0, ajv@^6.1.1, ajv@^6.10.2, ajv@^6.12.3, ajv@^6.12.5, ajv@~6.12.6: version "6.12.6" resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4" integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== @@ -6611,7 +6661,7 @@ ajv@^6.1.0, ajv@^6.10.2, ajv@^6.12.3, ajv@^6.12.5: json-schema-traverse "^0.4.1" uri-js "^4.2.2" -ajv@^6.1.1, ajv@^6.10.0: +ajv@^6.10.0: version "6.10.2" resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.10.2.tgz#d3cea04d6b017b2894ad69040fec8b623eb4bd52" integrity sha512-TXtUUEYHuaTEbLZWIKUr5pmBuhDLy+8KYtPYdcV8qC+pOZL+NKqYwvWSRrVXHn+ZmRRAu8vJTAznH7Oag6RVRw== @@ -8761,11 +8811,6 @@ confusing-browser-globals@^1.0.10: resolved "https://registry.yarnpkg.com/confusing-browser-globals/-/confusing-browser-globals-1.0.10.tgz#30d1e7f3d1b882b25ec4933d1d1adac353d20a59" integrity sha512-gNld/3lySHwuhaVluJUKLePYirM3QNCKzVxqAdhJII9/WXKVX5PURzMVJspS1jTslSqjeuG4KMVTSouit5YPHA== -confusing-browser-globals@^1.0.9: - version "1.0.9" - resolved "https://registry.yarnpkg.com/confusing-browser-globals/-/confusing-browser-globals-1.0.9.tgz#72bc13b483c0276801681871d4898516f8f54fdd" - integrity sha512-KbS1Y0jMtyPgIxjO7ZzMAuUpAKMt1SzCL9fsrKsX6b0zJPTaT0SiSPmewwVZg9UAO83HVIlEhZF84LIjZ0lmAw== - connect-history-api-fallback@^1.6.0: version "1.6.0" resolved "https://registry.yarnpkg.com/connect-history-api-fallback/-/connect-history-api-fallback-1.6.0.tgz#8b32089359308d111115d81cad3fceab888f97bc" @@ -9495,6 +9540,13 @@ debug@^4.0.1, debug@^4.1.0, debug@^4.1.1: dependencies: ms "^2.1.1" +debug@^4.3.1: + version "4.3.2" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.2.tgz#f0a49c18ac8779e31d4a0c6029dfb76873c7428b" + integrity sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw== + dependencies: + ms "2.1.2" + debuglog@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/debuglog/-/debuglog-1.0.1.tgz#aa24ffb9ac3df9a2351837cfb2d279360cd78492" @@ -10435,14 +10487,14 @@ es-to-primitive@^1.2.1: is-date-object "^1.0.1" is-symbol "^1.0.2" -es5-ext@^0.10.35, es5-ext@^0.10.50, es5-ext@^0.10.51: - version "0.10.51" - resolved "https://registry.yarnpkg.com/es5-ext/-/es5-ext-0.10.51.tgz#ed2d7d9d48a12df86e0299287e93a09ff478842f" - integrity sha512-oRpWzM2WcLHVKpnrcyB7OW8j/s67Ba04JCm0WnNv3RiABSvs7mrQlutB8DBv793gKcp0XENR8Il8WxGTlZ73gQ== +es5-ext@^0.10.35, es5-ext@^0.10.50: + version "0.10.53" + resolved "https://registry.yarnpkg.com/es5-ext/-/es5-ext-0.10.53.tgz#93c5a3acfdbef275220ad72644ad02ee18368de1" + integrity sha512-Xs2Stw6NiNHWypzRTY1MtaG/uJlwCk8kH81920ma8mvN8Xq1gsfhZvpkImLQArw8AHnv8MT2I45J3c0R8slE+Q== dependencies: es6-iterator "~2.0.3" - es6-symbol "~3.1.1" - next-tick "^1.0.0" + es6-symbol "~3.1.3" + next-tick "~1.0.0" es5-shim@^4.5.13: version "4.5.13" @@ -10475,13 +10527,13 @@ es6-shim@^0.35.5: resolved "https://registry.yarnpkg.com/es6-shim/-/es6-shim-0.35.5.tgz#46f59dc0a84a1c5029e8ff1166ca0a902077a9ab" integrity sha512-E9kK/bjtCQRpN1K28Xh4BlmP8egvZBGJJ+9GtnzOwt7mdqtrjHFuVGr7QJfdjBIKqrlU5duPf3pCBoDrkjVYFg== -es6-symbol@^3.1.1, es6-symbol@~3.1.1: - version "3.1.2" - resolved "https://registry.yarnpkg.com/es6-symbol/-/es6-symbol-3.1.2.tgz#859fdd34f32e905ff06d752e7171ddd4444a7ed1" - integrity sha512-/ZypxQsArlv+KHpGvng52/Iz8by3EQPxhmbuz8yFG89N/caTFBSbcXONDw0aMjy827gQg26XAjP4uXFvnfINmQ== +es6-symbol@^3.1.1, es6-symbol@~3.1.3: + version "3.1.3" + resolved "https://registry.yarnpkg.com/es6-symbol/-/es6-symbol-3.1.3.tgz#bad5d3c1bcdac28269f4cb331e431c78ac705d18" + integrity sha512-NJ6Yn3FuDinBaBRWl/q5X/s4koRHBrgKAu+yGI6JCBeiu3qrcbJhwT2GeR/EXVfylRk8dpQVJoLEFhK+Mu31NA== dependencies: d "^1.0.1" - es5-ext "^0.10.51" + ext "^1.1.2" escalade@^3.0.1: version "3.0.1" @@ -10540,16 +10592,7 @@ eslint-ast-utils@^1.1.0: lodash.get "^4.4.2" lodash.zip "^4.2.0" -eslint-config-airbnb-base@14.2.0: - version "14.2.0" - resolved "https://registry.yarnpkg.com/eslint-config-airbnb-base/-/eslint-config-airbnb-base-14.2.0.tgz#fe89c24b3f9dc8008c9c0d0d88c28f95ed65e9c4" - integrity sha512-Snswd5oC6nJaevs3nZoLSTvGJBvzTfnBqOIArkf3cbyTyq9UD79wOk8s+RiL6bhca0p/eRO6veczhf6A/7Jy8Q== - dependencies: - confusing-browser-globals "^1.0.9" - object.assign "^4.1.0" - object.entries "^1.1.2" - -eslint-config-airbnb-base@^14.2.0: +eslint-config-airbnb-base@^14.2.1: version "14.2.1" resolved "https://registry.yarnpkg.com/eslint-config-airbnb-base/-/eslint-config-airbnb-base-14.2.1.tgz#8a2eb38455dc5a312550193b319cdaeef042cd1e" integrity sha512-GOrQyDtVEc1Xy20U7vsB2yAoB4nBlfH5HZJeatRXHleO+OS5Ot+MWij4Dpltw4/DyIkqUfqz1epfhVR5XWWQPA== @@ -10558,22 +10601,18 @@ eslint-config-airbnb-base@^14.2.0: object.assign "^4.1.2" object.entries "^1.1.2" -eslint-config-airbnb-typescript@^12.0.0: - version "12.0.0" - resolved "https://registry.yarnpkg.com/eslint-config-airbnb-typescript/-/eslint-config-airbnb-typescript-12.0.0.tgz#4bb6b4b72b1cfc45ef1fa0607735679ceb9a3814" - integrity sha512-TUCVru1Z09eKnVAX5i3XoNzjcCOU3nDQz2/jQGkg1jVYm+25fKClveziSl16celfCq+npU0MBPW/ZnXdGFZ9lw== - dependencies: - "@typescript-eslint/parser" "4.4.1" - eslint-config-airbnb "18.2.0" - eslint-config-airbnb-base "14.2.0" +eslint-config-airbnb-typescript@^14.0.0: + version "14.0.0" + resolved "https://registry.yarnpkg.com/eslint-config-airbnb-typescript/-/eslint-config-airbnb-typescript-14.0.0.tgz#fc22246973b99f0820e2ad1ab929fdd011dfa039" + integrity sha512-d2Nit2ByZARGRYK6tgSNl3nnmGZPyvsgbsKFcmm+nAhvT8VjVpifG5jI4tzObUUPb0sWw0E1oO/0pSpBD/pIuQ== -eslint-config-airbnb@18.2.0: - version "18.2.0" - resolved "https://registry.yarnpkg.com/eslint-config-airbnb/-/eslint-config-airbnb-18.2.0.tgz#8a82168713effce8fc08e10896a63f1235499dcd" - integrity sha512-Fz4JIUKkrhO0du2cg5opdyPKQXOI2MvF8KUvN2710nJMT6jaRUpRE2swrJftAjVGL7T1otLM5ieo5RqS1v9Udg== +eslint-config-airbnb@^18.2.1: + version "18.2.1" + resolved "https://registry.yarnpkg.com/eslint-config-airbnb/-/eslint-config-airbnb-18.2.1.tgz#b7fe2b42f9f8173e825b73c8014b592e449c98d9" + integrity sha512-glZNDEZ36VdlZWoxn/bUR1r/sdFKPd1mHPbqUtkctgNG4yT2DLLtJ3D+yCV+jzZCc2V1nBVkmdknOJBZ5Hc0fg== dependencies: - eslint-config-airbnb-base "^14.2.0" - object.assign "^4.1.0" + eslint-config-airbnb-base "^14.2.1" + object.assign "^4.1.2" object.entries "^1.1.2" eslint-config-prettier@^7.1.0: @@ -10762,6 +10801,13 @@ eslint-utils@^2.1.0: dependencies: eslint-visitor-keys "^1.1.0" +eslint-utils@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-3.0.0.tgz#8aebaface7345bb33559db0a1f13a1d2d48c3672" + integrity sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA== + dependencies: + eslint-visitor-keys "^2.0.0" + eslint-visitor-keys@^1.0.0, eslint-visitor-keys@^1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz#30ebd1ef7c2fdff01c3a4f151044af25fab0523e" @@ -11049,6 +11095,13 @@ express@^4.17.1: utils-merge "1.0.1" vary "~1.1.2" +ext@^1.1.2: + version "1.5.0" + resolved "https://registry.yarnpkg.com/ext/-/ext-1.5.0.tgz#e93b97ae0cb23f8370380f6107d2d2b7887687ad" + integrity sha512-+ONcYoWj/SoQwUofMr94aGu05Ou4FepKi7N7b+O8T4jVfyIsZQV1/xeS8jpaBzF0csAk0KLXoHCxU7cKYZjo1Q== + dependencies: + type "^2.5.0" + extend-shallow@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-2.0.1.tgz#51af7d614ad9a9f610ea1bafbb989d6b1c56890f" @@ -12207,6 +12260,18 @@ globby@^11.0.2: merge2 "^1.3.0" slash "^3.0.0" +globby@^11.0.3: + version "11.0.4" + resolved "https://registry.yarnpkg.com/globby/-/globby-11.0.4.tgz#2cbaff77c2f2a62e71e9b2813a67b97a3a3001a5" + integrity sha512-9O4MVG9ioZJ08ffbcyVYyLOJLk5JQ688pJ4eMGLpdWLHq/Wr1D9BlriLQyL0E+jbkuePVZXYFj47QM/v093wHg== + dependencies: + array-union "^2.1.0" + dir-glob "^3.0.1" + fast-glob "^3.1.1" + ignore "^5.1.4" + merge2 "^1.3.0" + slash "^3.0.0" + globby@^9.2.0: version "9.2.0" resolved "https://registry.yarnpkg.com/globby/-/globby-9.2.0.tgz#fd029a706c703d29bdd170f4b6db3a3f7a7cb63d" @@ -16380,7 +16445,7 @@ newtype-ts@^0.2.4: fp-ts "^1.0.0" monocle-ts "^1.0.0" -next-tick@^1.0.0: +next-tick@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/next-tick/-/next-tick-1.0.0.tgz#ca86d1fe8828169b0120208e3dc8424b9db8342c" integrity sha1-yobR/ogoFpsBICCOPchCS524NCw= @@ -18757,9 +18822,9 @@ react-docgen-typescript-webpack-plugin@^1.1.0: react-docgen-typescript "^1.2.3" react-docgen-typescript@^1.15.0, react-docgen-typescript@^1.2.3: - version "1.15.0" - resolved "https://registry.yarnpkg.com/react-docgen-typescript/-/react-docgen-typescript-1.15.0.tgz#963f14210841f9b51ed18c65152a6cc37f1c3184" - integrity sha512-8xObdkRQbrc0505tEdVRO+pdId8pKFyD6jhLYM9FDdceKma+iB+a17Dk7e3lPRBRh8ArQLCedOCOfN/bO338kw== + version "1.22.0" + resolved "https://registry.yarnpkg.com/react-docgen-typescript/-/react-docgen-typescript-1.22.0.tgz#00232c8e8e47f4437cac133b879b3e9437284bee" + integrity sha512-MPLbF8vzRwAG3GcjdL+OHQlhgtWsLTXs+7uJiHfEeT3Ur7IsZaNYqRTLQ9sj2nB6M6jylcPCeCmH7qbszJmecg== react-docgen-typescript@^2.0.0: version "2.0.0" @@ -19417,11 +19482,6 @@ regexp.prototype.flags@^1.3.0: define-properties "^1.1.3" es-abstract "^1.17.0-next.1" -regexpp@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-3.0.0.tgz#dd63982ee3300e67b41c1956f850aa680d9d330e" - integrity sha512-Z+hNr7RAVWxznLPuA7DIh8UNX1j9CDrUQxskw9IrBE1Dxue2lyXT+shqEIeLUjrokxIP8CMy1WkjgG3rTsd5/g== - regexpp@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-3.1.0.tgz#206d0ad0a5648cffbdb8ae46438f3dc51c9f78e2" @@ -19846,7 +19906,7 @@ resolve-url@^0.2.1: resolved "https://registry.yarnpkg.com/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a" integrity sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo= -resolve@^1.1.6, resolve@^1.10.0, resolve@^1.18.1: +resolve@^1.1.6, resolve@^1.10.0, resolve@^1.18.1, resolve@~1.19.0: version "1.19.0" resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.19.0.tgz#1af5bf630409734a067cae29318aac7fa29a267c" integrity sha512-rArEXAgsBG4UgRGcynxWIWKFvh/XZCcS8UJdHhwy91zwAvCZIbcs+vAbflgBnNjYMs/i/i+/Ux6IZhML1yPvxg== @@ -21946,6 +22006,13 @@ tsutils@^3.17.1: dependencies: tslib "^1.8.1" +tsutils@^3.21.0: + version "3.21.0" + resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-3.21.0.tgz#b48717d394cea6c1e096983eed58e9d61715b623" + integrity sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA== + dependencies: + tslib "^1.8.1" + tty-browserify@0.0.0: version "0.0.0" resolved "https://registry.yarnpkg.com/tty-browserify/-/tty-browserify-0.0.0.tgz#a157ba402da24e9bf957f9aa69d524eed42901a6" @@ -22030,6 +22097,11 @@ type@^1.0.1: resolved "https://registry.yarnpkg.com/type/-/type-1.2.0.tgz#848dd7698dafa3e54a6c479e759c4bc3f18847a0" integrity sha512-+5nt5AAniqsCnu2cEQQdpzCAh33kVx8n0VoFidKpB1dVVLAN/F+bgVOqOJqOnEnrhp222clB5p3vUlD+1QAnfg== +type@^2.5.0: + version "2.5.0" + resolved "https://registry.yarnpkg.com/type/-/type-2.5.0.tgz#0a2e78c2e77907b252abe5f298c1b01c63f0db3d" + integrity sha512-180WMDQaIMm3+7hGXWf12GtdniDEy7nYcyFMKJn/eZz/6tSLXrUN9V0wKSbMjej0I1WHWbpREDEKHtqPQa9NNw== + typedarray-to-buffer@^3.1.5: version "3.1.5" resolved "https://registry.yarnpkg.com/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz#a97ee7a9ff42691b9f783ff1bc5112fe3fca9080" @@ -22042,16 +22114,21 @@ typedarray@^0.0.6: resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c= -typescript@^4.1.3, typescript@~4.1.3: - version "4.1.3" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.1.3.tgz#519d582bd94cba0cf8934c7d8e8467e473f53bb7" - integrity sha512-B3ZIOf1IKeH2ixgHhj6la6xdwR9QrLC5d1VKeCSY4tvkqhF2eqd9O7txNlS0PO3GrBAFIdr3L1ndNwteUbZLYg== +typescript@^4.4.3: + version "4.4.3" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.4.3.tgz#bdc5407caa2b109efd4f82fe130656f977a29324" + integrity sha512-4xfscpisVgqqDfPaJo5vkd+Qd/ItkoagnHpufr+i2QCHBsNYp+G7UAoyFl8aPtx879u38wPV65rZ8qbGZijalA== typescript@~3.9.7: version "3.9.7" resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.9.7.tgz#98d600a5ebdc38f40cb277522f12dc800e9e25fa" integrity sha512-BLbiRkiBzAwsjut4x/dsibSTB6yWpwT5qWmC2OfuCg3GgVQCSgMs4vEctYPhsaGtd0AeuuHMkjZ2h2WG8MSzRw== +typescript@~4.3.5: + version "4.3.5" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.3.5.tgz#4d1c37cc16e893973c45a06886b7113234f119f4" + integrity sha512-DqQgihaQ9cUrskJo9kIyW/+g0Vxsk8cDtZ52a3NGh0YNTfpUSArXSohyUGnvbPazEPLu398C0UxmKSOrPumUzA== + uglify-js@^3.1.4: version "3.13.5" resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.13.5.tgz#5d71d6dbba64cf441f32929b1efce7365bb4f113"