ronantakizawa/codereview-bench huggingface dataset:
Repository: apache/superset
File: superset/utils/core.py (Python)

Code before:
    from superset.connectors.sqla.models import BaseDatasource, TableColumn
    from superset.models.core import Database
    from superset.models.sql_lab import Query

logging.getLogger("MARKDOWN").setLevel(logging.INFO)
logger = logging.getLogger(__name__)

DTTM_ALIAS = "__timestamp"

TIME_COMPARISON = "__"

JS_MAX_INTEGER = 9007199254740991  # Largest int Java Script can handle 2^53-1

InputType = TypeVar("InputType")  # pylint: disable=invalid-name

ADHOC_FILTERS_REGEX = re.compile("^adhoc_filters")

TYPE_MAPPING = {
    re.compile(r"INT", re.IGNORECASE): "integer",
    re.compile(r"CHAR|TEXT|VARCHAR", re.IGNORECASE): "string",
    re.compile(r"DECIMAL|NUMERIC|FLOAT|DOUBLE", re.IGNORECASE): "floating",
    re.compile(r"BOOL", re.IGNORECASE): "boolean",
    re.compile(r"DATE|TIME", re.IGNORECASE): "datetime64",
}

Metric_Map_Type = {
    "SUM": "floating",
    "AVG": "floating",
    "COUNT": "floating",
    "COUNT_DISTINCT": "floating",
    "MIN": "numeric",
    "MAX": "numeric",
    "FIRST": "string",
    "LAST": "string",
    "GROUP_CONCAT": "string",
    "ARRAY_AGG": "string",
    "STRING_AGG": "string",
    "MEDIAN": "floating",
    "PERCENTILE": "floating",
    "VARIANCE": "floating",
    "STDDEV": "floating",
}


class AdhocMetricExpressionType(StrEnum):
    SIMPLE = "SIMPLE"
    SQL = "SQL"


class AnnotationType(StrEnum):
    FORMULA = "FORMULA"

Review comment (suggestion):
This is a constant, so the naming should be capital snake case same as the other ones
```suggestion
METRIC_MAP_TYPE = {
```

Code after:
    from superset.connectors.sqla.models import BaseDatasource, TableColumn
    from superset.models.core import Database
    from superset.models.sql_lab import Query

logging.getLogger("MARKDOWN").setLevel(logging.INFO)
logger = logging.getLogger(__name__)

DTTM_ALIAS = "__timestamp"

TIME_COMPARISON = "__"

JS_MAX_INTEGER = 9007199254740991  # Largest int Java Script can handle 2^53-1

InputType = TypeVar("InputType")  # pylint: disable=invalid-name

ADHOC_FILTERS_REGEX = re.compile("^adhoc_filters")

TYPE_MAPPING = {
    re.compile(r"INT", re.IGNORECASE): "integer",
    re.compile(r"CHAR|TEXT|VARCHAR", re.IGNORECASE): "string",
    re.compile(r"DECIMAL|NUMERIC|FLOAT|DOUBLE", re.IGNORECASE): "floating",
    re.compile(r"BOOL", re.IGNORECASE): "boolean",
    re.compile(r"DATE|TIME", re.IGNORECASE): "datetime64",
}

METRIC_MAP_TYPE = {
    "SUM": "floating",
    "AVG": "floating",
    "COUNT": "floating",
    "COUNT_DISTINCT": "floating",
    "MIN": "numeric",
    "MAX": "numeric",
    "FIRST": "string",
    "LAST": "string",
    "GROUP_CONCAT": "string",
    "ARRAY_AGG": "string",
    "STRING_AGG": "string",
    "MEDIAN": "floating",
    "PERCENTILE": "floating",
    "VARIANCE": "floating",
    "STDDEV": "floating",
}


class AdhocMetricExpressionType(StrEnum):
    SIMPLE = "SIMPLE"
    SQL = "SQL"


class AnnotationType(StrEnum):
    FORMULA = "FORMULA"
Repository: apache/superset
File: superset-frontend/packages/superset-ui-core/src/query/types/Query.ts (TypeScript)

Code before:

  // Generic errors
  GENERIC_COMMAND_ERROR: 'GENERIC_COMMAND_ERROR',
  GENERIC_BACKEND_ERROR: 'GENERIC_BACKEND_ERROR',

  // API errors
  INVALID_PAYLOAD_FORMAT_ERROR: 'INVALID_PAYLOAD_FORMAT_ERROR',
  INVALID_PAYLOAD_SCHEMA_ERROR: 'INVALID_PAYLOAD_SCHEMA_ERROR',
  MARSHMALLOW_ERROR: 'MARSHMALLOW_ERROR',

  // Report errors
  REPORT_NOTIFICATION_ERROR: 'REPORT_NOTIFICATION_ERROR',
} as const;

type ValueOf<T> = T[keyof T];

export type ErrorType = ValueOf<typeof ErrorTypeEnum>;

// Keep in sync with superset/errors.py
export type ErrorLevel = 'info' | 'warning' | 'error';

export type ErrorSource = 'dashboard' | 'explore' | 'sqllab' | 'crud';

export type SupersetError<ExtraType = Record<string, any> | null> = {
  error_type: ErrorType;
  errorType?: ErrorType;
  extra: ExtraType;
  level: ErrorLevel;
  message: string;
};

export const CtasEnum = {
  TABLE: 'TABLE',
  VIEW: 'VIEW',
};

export type QueryColumn = {
  name?: string;
  column_name: string;
  type: string | null;
  type_generic: GenericDataType;
  is_dttm: boolean;
};

// Possible states of a query object for processing on the server
export enum QueryState {
  Started = 'started',
  Stopped = 'stopped',
  Failed = 'failed',
  Pending = 'pending',
  Running = 'running',

Review comment (suggestion):
@justinpark Can't we fix the API responses to use the same field? Having both in the type definition looks really bad and is an indicative that we should fix the APIs.

Code after:

  // Generic errors
  GENERIC_COMMAND_ERROR: 'GENERIC_COMMAND_ERROR',
  GENERIC_BACKEND_ERROR: 'GENERIC_BACKEND_ERROR',

  // API errors
  INVALID_PAYLOAD_FORMAT_ERROR: 'INVALID_PAYLOAD_FORMAT_ERROR',
  INVALID_PAYLOAD_SCHEMA_ERROR: 'INVALID_PAYLOAD_SCHEMA_ERROR',
  MARSHMALLOW_ERROR: 'MARSHMALLOW_ERROR',

  // Report errors
  REPORT_NOTIFICATION_ERROR: 'REPORT_NOTIFICATION_ERROR',
} as const;

type ValueOf<T> = T[keyof T];

export type ErrorType = ValueOf<typeof ErrorTypeEnum>;

// Keep in sync with superset/errors.py
export type ErrorLevel = 'info' | 'warning' | 'error';

export type ErrorSource = 'dashboard' | 'explore' | 'sqllab' | 'crud';

export type SupersetError<ExtraType = Record<string, any> | null> = {
  error_type: ErrorType;
  extra: ExtraType;
  level: ErrorLevel;
  message: string;
};

export const CtasEnum = {
  TABLE: 'TABLE',
  VIEW: 'VIEW',
};

export type QueryColumn = {
  name?: string;
  column_name: string;
  type: string | null;
  type_generic: GenericDataType;
  is_dttm: boolean;
};

// Possible states of a query object for processing on the server
export enum QueryState {
  Started = 'started',
  Stopped = 'stopped',
  Failed = 'failed',
  Pending = 'pending',
  Running = 'running',
  Scheduled = 'scheduled',
Repository: apache/superset
File: superset-frontend/src/explore/components/controls/VizTypeControl/VizTile.tsx (TypeScript)

Code before:
            background-color: ${theme.colors.grayscale.light4};
            transition:
              width ${TILE_TRANSITION_TIME} ease-out,
              background-color ${TILE_TRANSITION_TIME} ease-out;
            cursor: default;
            svg path {
              fill: ${theme.colorPrimary};
            }
          `}
        `}
      >
        <span
          css={css`
            padding: 0px ${theme.sizeUnit}px;
          `}
        >
          {vizMeta.icon}
        </span>
        <span
          css={css`
            overflow: hidden;
            text-overflow: ellipsis;
            font-size: ${theme.fontSizeSM}px;
            min-width: 0;
            padding-right: ${theme.sizeUnit}px;
          `}
          ref={chartNameRef}
        >
          {chartName}
        </span>
      </div>
    </Tooltip>
  );
};


Review comment (suggestion):
This doesn't seem to affect anything.
```suggestion
```

Code after:
            background-color: ${theme.colors.grayscale.light4};
            transition:
              width ${TILE_TRANSITION_TIME} ease-out,
              background-color ${TILE_TRANSITION_TIME} ease-out;
            cursor: default;
            svg path {
              fill: ${theme.colorPrimary};
            }
          `}
        `}
      >
        <span
          css={css`
            padding: 0px ${theme.sizeUnit * 1.25}px;
          `}
        >
          {vizMeta.icon}
        </span>
        <span
          css={css`
            overflow: hidden;
            text-overflow: ellipsis;
            font-size: ${theme.fontSizeSM}px;
            min-width: 0;
            padding-right: ${theme.sizeUnit}px;
            line-height: 1;
          `}
          ref={chartNameRef}
        >
          {chartName}
        </span>
      </div>
    </Tooltip>
  );
};
Repository: apache/superset
File: superset-frontend/packages/superset-ui-core/src/query/types/QueryFormData.ts (TypeScript)

Code before:
  result_type?: string;
  annotation_layers?: AnnotationLayer[];
  url_params?: Record<string, string>;
  custom_params?: Record<string, string>;
  /** limit number of series */
  series_columns?: QueryFormColumn[];
  series_limit?: number;
  series_limit_metric?: QueryFormMetric;
}

/**
 * Form data for SQLAlchemy based datasources.
 */
export interface SqlaFormData extends BaseFormData {
  /**
   * Name of the Time Column. Time column is optional.
   */
  granularity?: string;
  granularity_sqla?: string;
  time_grain_sqla?: TimeGranularity;
  having?: string;
}

export type QueryFormData = SqlaFormData;

export type LatestQueryFormData =
  | {}
  | (Pick<QueryFormData, 'viz_type'> &
      Pick<QueryFormData, 'datasource'> &
      Partial<QueryFormData>)
  | (Pick<QueryFormData, 'vizType'> &
      Pick<QueryFormData, 'datasource'> &
      Partial<QueryFormData>);

//---------------------------------------------------
// Type guards
//---------------------------------------------------

export default {};


Review comment (suggestion):
The `{}` union could be risky, as it allows any object. If you want to require at least `datasource` and one of `viz_type` or `vizType`, you could do:

```
type LatestQueryFormDataBase = Partial<QueryFormData> & { datasource: QueryFormData['datasource'] };

export type LatestQueryFormData =
  | (LatestQueryFormDataBase & { viz_type: QueryFormData['viz_type'] })
  | (LatestQueryFormDataBase & { vizType: QueryFormData['vizType'] });
```

Code after:
  result_type?: string;
  annotation_layers?: AnnotationLayer[];
  url_params?: Record<string, string>;
  custom_params?: Record<string, string>;
  /** limit number of series */
  series_columns?: QueryFormColumn[];
  series_limit?: number;
  series_limit_metric?: QueryFormMetric;
}

/**
 * Form data for SQLAlchemy based datasources.
 */
export interface SqlaFormData extends BaseFormData {
  /**
   * Name of the Time Column. Time column is optional.
   */
  granularity?: string;
  granularity_sqla?: string;
  time_grain_sqla?: TimeGranularity;
  having?: string;
}

export type QueryFormData = SqlaFormData;

export type LatestQueryFormData = Partial<QueryFormData>;

//---------------------------------------------------
// Type guards
//---------------------------------------------------

export default {};
Repository: apache/superset
File: superset/constants.py (Python)

Code before:
    WEEK_ENDING_SUNDAY = "P1W/1970-01-04T00:00:00Z"
    MONTH = "P1M"
    QUARTER = "P3M"
    QUARTER_YEAR = "P0.25Y"
    YEAR = "P1Y"


class PandasAxis(int, Enum):
    ROW = 0
    COLUMN = 1


class PandasPostprocessingCompare(StrEnum):
    DIFF = "difference"
    PCT = "percentage"
    RAT = "ratio"


class CacheRegion(StrEnum):
    DEFAULT = "default"
    DATA = "data"
    THUMBNAIL = "thumbnail"


# Cache timeout constants
CACHE_NO_TIMEOUT = -1  # Special value indicating no caching should occur


Review comment (performance):
nit: rename to `CACHE_DISABLED_TIMEOUT` because the `NO_TIMEOUT` in my mind reads like "it's cached forever because it has no timeout"

Code after:
    WEEK_ENDING_SUNDAY = "P1W/1970-01-04T00:00:00Z"
    MONTH = "P1M"
    QUARTER = "P3M"
    QUARTER_YEAR = "P0.25Y"
    YEAR = "P1Y"


class PandasAxis(int, Enum):
    ROW = 0
    COLUMN = 1


class PandasPostprocessingCompare(StrEnum):
    DIFF = "difference"
    PCT = "percentage"
    RAT = "ratio"


class CacheRegion(StrEnum):
    DEFAULT = "default"
    DATA = "data"
    THUMBNAIL = "thumbnail"


# Cache timeout constants
CACHE_DISABLED_TIMEOUT = -1  # Special value indicating no caching should occur
Repository: apache/superset
File: superset-frontend/src/dashboard/components/SliceHeaderControls/index.tsx (TypeScript)

Code before:
  );
  const history = useHistory();

  const queryMenuRef: RefObject<any> = useRef(null);
  const resultsMenuRef: RefObject<any> = useRef(null);

  const [modalFilters, setFilters] = useState<BinaryQueryObjectFilterClause[]>(
    [],
  );
  const theme = useTheme();

  const canEditCrossFilters =
    useSelector<RootState, boolean>(
      ({ dashboardInfo }) => dashboardInfo.dash_edit_perm,
    ) &&
    getChartMetadataRegistry()
      .get(props.slice.viz_type)
      ?.behaviors?.includes(Behavior.InteractiveChart);
  const canExplore = props.supersetCanExplore;
  const { canDrillToDetail, canViewQuery, canViewTable } = usePermissions();

  const datasetResource = useDatasetDrillInfo(
    props.slice.datasource,
    props.dashboardId,
    props.formData,
  );

  const datasetWithVerboseMap =
    datasetResource.status === ResourceStatus.Complete
      ? datasetResource.result
      : undefined;

  const refreshChart = () => {
    if (props.updatedDttm) {
      props.forceRefresh(props.slice.slice_id, props.dashboardId);
    }
  };

  const handleMenuClick = ({
    key,
    domEvent,
  }: {
    key: Key;
    domEvent: MouseEvent<HTMLElement> | KeyboardEvent<HTMLElement>;
  }) => {
    switch (key) {
      case MenuKeys.ForceRefresh:
        refreshChart();
        props.addSuccessToast(t('Data refreshed'));
        break;
      case MenuKeys.ToggleChartDescription:

Review comment (suggestion):
Only improvement i could think of at first is to move `useDatasetDrillInfo` inside the actual components but not sure if it's an improvement at all. I think having a skip argument is fine.

Code after:
  );
  const history = useHistory();

  const queryMenuRef: RefObject<any> = useRef(null);
  const resultsMenuRef: RefObject<any> = useRef(null);

  const [modalFilters, setFilters] = useState<BinaryQueryObjectFilterClause[]>(
    [],
  );
  const theme = useTheme();

  const canEditCrossFilters =
    useSelector<RootState, boolean>(
      ({ dashboardInfo }) => dashboardInfo.dash_edit_perm,
    ) &&
    getChartMetadataRegistry()
      .get(props.slice.viz_type)
      ?.behaviors?.includes(Behavior.InteractiveChart);
  const canExplore = props.supersetCanExplore;
  const { canDrillToDetail, canViewQuery, canViewTable } = usePermissions();

  const datasetResource = useDatasetDrillInfo(
    props.slice.datasource,
    props.dashboardId,
    props.formData,
    !canDrillToDetail,
  );

  const datasetWithVerboseMap =
    datasetResource.status === ResourceStatus.Complete
      ? datasetResource.result
      : undefined;

  const refreshChart = () => {
    if (props.updatedDttm) {
      props.forceRefresh(props.slice.slice_id, props.dashboardId);
    }
  };

  const handleMenuClick = ({
    key,
    domEvent,
  }: {
    key: Key;
    domEvent: MouseEvent<HTMLElement> | KeyboardEvent<HTMLElement>;
  }) => {
    switch (key) {
      case MenuKeys.ForceRefresh:
        refreshChart();
        props.addSuccessToast(t('Data refreshed'));
        break;
Repository: apache/superset
File: superset-frontend/spec/helpers/shim.tsx (TypeScript)

Code before:
  useTabId: () => 1,
}));

// Check https://github.com/remarkjs/react-markdown/issues/635
jest.mock('react-markdown', () => (props: any) => <>{props.children}</>);
jest.mock('rehype-sanitize', () => () => jest.fn());
jest.mock('rehype-raw', () => () => jest.fn());

// Mocks the Icon component due to its async nature
// Tests should override this when needed
jest.mock('@superset-ui/core/components/Icons/AsyncIcon', () => ({
  __esModule: true,
  default: ({
    fileName,
    role,
    'aria-label': ariaLabel,
    onClick,
    ...rest
  }: {
    fileName: string;
    role?: string;
    'aria-label'?: AriaAttributes['aria-label'];
    onClick?: () => void;
  }) => {
    // Simple mock that provides the essential attributes for testing
    const label = ariaLabel || fileName?.replace(/_/g, '-').toLowerCase() || '';
    return (
      <span
        role={role || (onClick ? 'button' : 'img')}
        aria-label={label}
        data-test={label}
        {...rest}
      />
    );
  },
  StyledIcon: ({
    component: Component,
    role,
    'aria-label': ariaLabel,
    ...rest
  }: {
    component: React.ComponentType<any>;
    role: string;
    'aria-label': AriaAttributes['aria-label'];
  }) => (
    <Component
      role={role ?? 'img'}
      alt={ariaLabel}
      aria-label={ariaLabel}
      {...rest}
    />

Review comment (suggestion):
This is why `VizTypeControl.test.tsx` needed to be update. Initially we were just updating the first `_` so we would get something like `first-word_second_word` but now it should all be `first-word-second-word`

Code after:
  useTabId: () => 1,
}));

// Check https://github.com/remarkjs/react-markdown/issues/635
jest.mock('react-markdown', () => (props: any) => <>{props.children}</>);
jest.mock('rehype-sanitize', () => () => jest.fn());
jest.mock('rehype-raw', () => () => jest.fn());

// Mocks the Icon component due to its async nature
// Tests should override this when needed
jest.mock('@superset-ui/core/components/Icons/AsyncIcon', () => ({
  __esModule: true,
  default: ({
    fileName,
    role,
    'aria-label': ariaLabel,
    onClick,
    ...rest
  }: {
    fileName: string;
    role?: string;
    'aria-label'?: AriaAttributes['aria-label'];
    onClick?: () => void;
  }) => {
    // Simple mock that provides the essential attributes for testing
    const label = ariaLabel || fileName?.replace(/_/g, '-').toLowerCase() || '';
    return (
      // eslint-disable-next-line jsx-a11y/no-static-element-interactions
      <span
        role={role || (onClick ? 'button' : 'img')}
        aria-label={label}
        data-test={label}
        onClick={onClick}
        {...rest}
      />
    );
  },
  StyledIcon: ({
    component: Component,
    role,
    'aria-label': ariaLabel,
    ...rest
  }: {
    component: React.ComponentType<any>;
    role: string;
    'aria-label': AriaAttributes['aria-label'];
  }) => (
    <Component
      role={role ?? 'img'}
      alt={ariaLabel}
      aria-label={ariaLabel}
Repository: apache/superset
File: superset-frontend/src/features/alerts/components/AlertStatusIcon.tsx (TypeScript)

Code before:
      break;
    case AlertState.Error:
      lastStateConfig.icon = Icons.CloseOutlined;
      lastStateConfig.label = isReportEnabled
        ? t('Report failed')
        : t('Alert failed');
      lastStateConfig.status = AlertState.Error;
      break;
    case AlertState.Noop:
      lastStateConfig.icon = Icons.CheckOutlined;
      lastStateConfig.label = t('Nothing triggered');
      lastStateConfig.status = AlertState.Noop;
      break;
    case AlertState.Grace:
      lastStateConfig.icon = Icons.WarningOutlined;
      lastStateConfig.label = t('Alert Triggered, In Grace Period');
      lastStateConfig.status = AlertState.Grace;
      break;
    default:
      lastStateConfig.icon = Icons.CheckOutlined;
      lastStateConfig.label = t('Nothing triggered');
      lastStateConfig.status = AlertState.Noop;
  }
  const Icon = lastStateConfig.icon;
  return (
    <Tooltip title={lastStateConfig.label} placement="bottomLeft">
      <Icon
        iconSize="m"
        iconColor={getStatusColor(
          lastStateConfig.status,
          isReportEnabled,
          theme,
        )}
      />
    </Tooltip>
  );
}


Review comment (suggestion):
this is hack needed to fix the size issue with this icon, the main reason is that the original SVG uses only the center portion of their viewBox, changing the SVG could fix this without this hack, but this Icon is being used also in SQLlab and Query history so probably changing the SVG can break those. 

Code after:
      lastStateConfig.icon = Icons.CloseOutlined;
      lastStateConfig.label = isReportEnabled
        ? t('Report failed')
        : t('Alert failed');
      lastStateConfig.status = AlertState.Error;
      break;
    case AlertState.Noop:
      lastStateConfig.icon = Icons.CheckOutlined;
      lastStateConfig.label = t('Nothing triggered');
      lastStateConfig.status = AlertState.Noop;
      break;
    case AlertState.Grace:
      lastStateConfig.icon = Icons.WarningOutlined;
      lastStateConfig.label = t('Alert Triggered, In Grace Period');
      lastStateConfig.status = AlertState.Grace;
      break;
    default:
      lastStateConfig.icon = Icons.CheckOutlined;
      lastStateConfig.label = t('Nothing triggered');
      lastStateConfig.status = AlertState.Noop;
  }
  const Icon = lastStateConfig.icon;
  const isRunningIcon = state === AlertState.Working;
  return (
    <Tooltip title={lastStateConfig.label} placement="bottomLeft">
      <span
        css={
          isRunningIcon
            ? css`
                display: inline-flex;
                align-items: center;
                justify-content: center;
                transform: scale(1.8);
              `
            : undefined
        }
      >
        <Icon
          iconSize="m"
          iconColor={getStatusColor(
            lastStateConfig.status,
            isReportEnabled,
            theme,
          )}
        />
      </span>
    </Tooltip>
  );
}
Repository: apache/superset
File: superset-frontend/packages/superset-ui-core/src/chart/components/SuperChartCore.tsx (TypeScript)

Code before:

export default class SuperChartCore extends PureComponent<Props, {}> {
  /**
   * The HTML element that wraps all chart content
   */
  container?: HTMLElement | null;

  /**
   * memoized function so it will not recompute
   * and return previous value
   * unless one of
   * - preTransformProps
   * - chartProps
   * is changed.
   */
  preSelector = createSelector(
    [
      (input: {
        chartProps: ChartProps;
        preTransformProps?: PreTransformProps;
      }) => input.chartProps,
      input => input.preTransformProps,
    ],
    (chartProps, pre = IDENTITY) => pre(chartProps),
  );

  /**
   * memoized function so it will not recompute
   * and return previous value
   * unless one of
   * - transformProps
   * - preprocessed result
   * is changed.
   */
  transformSelector = createSelector(
    [
      (input: { chartProps: ChartProps; transformProps?: TransformProps }) =>
        input.chartProps,
      input => input.transformProps,
    ],
    (preprocessedChartProps, transform = IDENTITY) =>
      transform(preprocessedChartProps),
  );

  /**
   * memoized function so it will not recompute
   * and return previous value
   * unless one of
   * - postTransformProps
   * - transformed result
   * is changed.

Review comment (suggestion):
Could you adjust the comments for `transformSelector` and `postSelector` to:

> Memoized the function so it will not recompute and return the previous value unless one of the input arguments have changed.

Code after:

export default class SuperChartCore extends PureComponent<Props, {}> {
  /**
   * The HTML element that wraps all chart content
   */
  container?: HTMLElement | null;

  /**
   * memoized function so it will not recompute and return previous value
   * unless one of
   * - preTransformProps
   * - chartProps
   * is changed.
   */
  preSelector = createSelector(
    [
      (input: {
        chartProps: ChartProps;
        preTransformProps?: PreTransformProps;
      }) => input.chartProps,
      input => input.preTransformProps,
    ],
    (chartProps, pre = IDENTITY) => pre(chartProps),
  );

  /**
   * memoized function so it will not recompute and return previous value
   * unless one of the input arguments have changed.
   */
  transformSelector = createSelector(
    [
      (input: { chartProps: ChartProps; transformProps?: TransformProps }) =>
        input.chartProps,
      input => input.transformProps,
    ],
    (preprocessedChartProps, transform = IDENTITY) =>
      transform(preprocessedChartProps),
  );

  /**
   * memoized function so it will not recompute and return previous value
   * unless one of the input arguments have changed.
   */
  postSelector = createSelector(
    [
      (input: {
        chartProps: ChartProps;
        postTransformProps?: PostTransformProps;
      }) => input.chartProps,
      input => input.postTransformProps,
    ],