<commit_before>import React, { PureComponent } from 'react';
import { AlignedData, Range } from 'uplot';
import {
  compareDataFrameStructures,
  DataFrame,
  Field,
  FieldConfig,
  FieldSparkline,
  FieldType,
  getFieldColorModeForField,
} from '@grafana/data';
import {
  AxisPlacement,
  GraphDrawStyle,
  GraphFieldConfig,
  VisibilityMode,
  ScaleDirection,
  ScaleOrientation,
} from '@grafana/schema';
import { UPlotConfigBuilder } from '../uPlot/config/UPlotConfigBuilder';
import { UPlotChart } from '../uPlot/Plot';
import { Themeable2 } from '../../types';
import { preparePlotData } from '../uPlot/utils';
import { preparePlotFrame } from './utils';
import { isEqual } from 'lodash';

export interface SparklineProps extends Themeable2 {
  width: number;
  height: number;
  config?: FieldConfig<GraphFieldConfig>;
  sparkline: FieldSparkline;
}

interface State {
  data: AlignedData;
  alignedDataFrame: DataFrame;
  configBuilder: UPlotConfigBuilder;
}

const defaultConfig: GraphFieldConfig = {
  drawStyle: GraphDrawStyle.Line,
  showPoints: VisibilityMode.Auto,
  axisPlacement: AxisPlacement.Hidden,
};

export class Sparkline extends PureComponent<SparklineProps, State> {
  constructor(props: SparklineProps) {
    super(props);

    const alignedDataFrame = preparePlotFrame(props.sparkline, props.config);

    this.state = {
      data: preparePlotData([alignedDataFrame]),
      alignedDataFrame,
      configBuilder: this.prepareConfig(alignedDataFrame),
    };
  }

  static getDerivedStateFromProps(props: SparklineProps, state: State) {
    const frame = preparePlotFrame(props.sparkline, props.config);
    if (!frame) {
      return { ...state };
    }

    return {
      ...state,
      data: preparePlotData([frame]),
      alignedDataFrame: frame,
    };
  }

  componentDidUpdate(prevProps: SparklineProps, prevState: State) {
    const { alignedDataFrame } = this.state;

    if (!alignedDataFrame) {
      return;
    }

    let rebuildConfig = false;

    if (prevProps.sparkline !== this.props.sparkline) {
      rebuildConfig = !compareDataFrameStructures(this.state.alignedDataFrame, prevState.alignedDataFrame);
    } else {
      rebuildConfig = !isEqual(prevProps.config, this.props.config);
    }

    if (rebuildConfig) {
      this.setState({ configBuilder: this.prepareConfig(alignedDataFrame) });
    }
  }

  getYRange(field: Field) {
    let { min, max } = this.state.alignedDataFrame.fields[1].state?.range!;

    return [
      Math.max(min!, field.config.min ?? -Infinity),
      Math.min(max!, field.config.max ?? Infinity),
    ] as Range.MinMax;
  }<commit_msg>Stat: Fixes an issue that could lead to browser crash with specific values (#40777)<commit_after>import React, { PureComponent } from 'react';
import { AlignedData, Range } from 'uplot';
import {
  compareDataFrameStructures,
  DataFrame,
  Field,
  FieldConfig,
  FieldSparkline,
  FieldType,
  getFieldColorModeForField,
} from '@grafana/data';
import {
  AxisPlacement,
  GraphDrawStyle,
  GraphFieldConfig,
  VisibilityMode,
  ScaleDirection,
  ScaleOrientation,
} from '@grafana/schema';
import { UPlotConfigBuilder } from '../uPlot/config/UPlotConfigBuilder';
import { UPlotChart } from '../uPlot/Plot';
import { Themeable2 } from '../../types';
import { preparePlotData } from '../uPlot/utils';
import { preparePlotFrame } from './utils';
import { isEqual } from 'lodash';

export interface SparklineProps extends Themeable2 {
  width: number;
  height: number;
  config?: FieldConfig<GraphFieldConfig>;
  sparkline: FieldSparkline;
}

interface State {
  data: AlignedData;
  alignedDataFrame: DataFrame;
  configBuilder: UPlotConfigBuilder;
}

const defaultConfig: GraphFieldConfig = {
  drawStyle: GraphDrawStyle.Line,
  showPoints: VisibilityMode.Auto,
  axisPlacement: AxisPlacement.Hidden,
};

export class Sparkline extends PureComponent<SparklineProps, State> {
  constructor(props: SparklineProps) {
    super(props);

    const alignedDataFrame = preparePlotFrame(props.sparkline, props.config);

    this.state = {
      data: preparePlotData([alignedDataFrame]),
      alignedDataFrame,
      configBuilder: this.prepareConfig(alignedDataFrame),
    };
  }

  static getDerivedStateFromProps(props: SparklineProps, state: State) {
    const frame = preparePlotFrame(props.sparkline, props.config);
    if (!frame) {
      return { ...state };
    }

    return {
      ...state,
      data: preparePlotData([frame]),
      alignedDataFrame: frame,
    };
  }

  componentDidUpdate(prevProps: SparklineProps, prevState: State) {
    const { alignedDataFrame } = this.state;

    if (!alignedDataFrame) {
      return;
    }

    let rebuildConfig = false;

    if (prevProps.sparkline !== this.props.sparkline) {
      rebuildConfig = !compareDataFrameStructures(this.state.alignedDataFrame, prevState.alignedDataFrame);
    } else {
      rebuildConfig = !isEqual(prevProps.config, this.props.config);
    }

    if (rebuildConfig) {
      this.setState({ configBuilder: this.prepareConfig(alignedDataFrame) });
    }
  }

  getYRange(field: Field) {
    let { min, max } = this.state.alignedDataFrame.fields[1].state?.range!;

    if (min === max) {
      if (min === 0) {
        max = 100;
      } else {
        min = 0;
        max! *= 2;
      }
    }

    return [
      Math.max(min!, field.config.min ?? -Infinity),
      Math.min(max!, field.config.max ?? Infinity),
    ] as Range.MinMax;
  }
{'fraction_non_alphanumeric': 0.1197868822340621, 'fraction_numerical': 0.0031232776042623553, 'mean_word_length': 3.697152717860224, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 7, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '978241', 'n_tokens_mistral': 1742, 'n_tokens_neox': 1640, 'n_words': 354}