<commit_before>import {isNumber} from 'vega-util';
import {Channel, COLOR, OPACITY, SCALE_CHANNELS, ScaleChannel, SHAPE, SIZE, X, Y} from '../../channel';
import {Config} from '../../config';
import * as log from '../../log';
import {Mark} from '../../mark';
import {channelScalePropertyIncompatability, isExtendedScheme, Range, Scale, ScaleConfig, ScaleType, scaleTypeSupportProperty, Scheme} from '../../scale';
import {Type} from '../../type';
import * as util from '../../util';
import {isVgRangeStep, VgRange, VgRangeScheme, VgSignalRef} from '../../vega.schema';
import {LayoutSize} from '../layout/component';
import {Model} from '../model';
import {Explicit, makeImplicit, Split} from '../split';
import {UnitModel} from '../unit';
import {ScaleComponent, ScaleComponentIndex} from './component';
import {parseNonUnitScaleProperty} from './properties';


export type RangeMixins = {range: Range} | {rangeStep: number} | {scheme: Scheme};

export const RANGE_PROPERTIES: (keyof Scale)[] = ['range', 'rangeStep', 'scheme'];


export function parseScaleRange(model: Model) {
  if (model instanceof UnitModel) {
    parseUnitScaleRange(model);
  } else {
    parseNonUnitScaleProperty(model, 'range');
  }
}

function parseUnitScaleRange(model: UnitModel) {
  const  localScaleComponents: ScaleComponentIndex = model.component.scales;

  // use SCALE_CHANNELS instead of scales[channel] to ensure that x, y come first!
  SCALE_CHANNELS.forEach((channel: ScaleChannel) => {
    const localScaleCmpt = localScaleComponents[channel];
    if (!localScaleCmpt) {
      return;
    }

    const specifiedScale = model.specifiedScales[channel];
    const fieldDef = model.fieldDef(channel);

    // Read if there is a specified width/height
    const sizeType = channel === 'x' ? 'width' : channel === 'y' ? 'height' : undefined;
    const specifiedSize = sizeType ? model.component.layoutSize.get(sizeType) : undefined;

    const xyRangeSteps = getXYRangeStep(model);

    const rangeWithExplicit = parseRangeForChannel(
      channel, localScaleCmpt.get('type'), fieldDef.type, specifiedScale, model.config,
      localScaleCmpt.get('zero'), model.mark(), specifiedSize, model.getSizeSignalRef(sizeType), xyRangeSteps
    );

    localScaleCmpt.setWithExplicit('range', rangeWithExplicit);
  });
}

function getXYRangeStep(model: UnitModel) {
  const xyRangeSteps: number[] = [];

  const xScale = model.getScaleComponent('x');
  const xRange = xScale && xScale.get('range');
  if (xRange && isVgRangeStep(xRange) && isNumber(xRange.step)) {
    xyRangeSteps.push(xRange.step);
  }

  const yScale = model.getScaleComponent('y');
  const yRange = yScale && yScale.get('range');
  if (yRange && isVgRangeStep(yRange) && isNumber(yRange.step)) {
    xyRangeSteps.push(yRange.step);
  }

  return xyRangeSteps;
}

/**
 * Return mixins that includes one of the range properties (range, rangeStep, scheme).
 */
export function parseRangeForChannel(
    channel: Channel, scaleType: ScaleType, type: Type, specifiedScale: Scale, config: Config,
    zero: boolean, mark: Mark, specifiedSize: LayoutSize, sizeSignal: VgSignalRef, xyRangeSteps: number[]
  ): Explicit<VgRange> {

  let noRangeStep = !!specifiedSize;

  // Check if any of the range properties is specified.
  // If so, check if it is compatible and make sure that we only output one of the properties
  for (const property of RANGE_PROPERTIES) {
    if (specifiedScale[property] !== undefined) {
      const supportedByScaleType = scaleTypeSupportProperty(scaleType, property);
      const channelIncompatability = channelScalePropertyIncompatability(channel, property);
      if (!supportedByScaleType) {
        log.warn(log.message.scalePropertyNotWorkWithScaleType(scaleType, property, channel));
      } else if (channelIncompatability) { // channel
        log.warn(channelIncompatability);
      } else {
        switch (property) {
          case 'range':
            return makeImplicit(specifiedScale[property]);
          case 'scheme':
            return makeImplicit(parseScheme(specifiedScale[property]));
          case 'rangeStep':
            if (specifiedSize === undefined) {
              const rangeStep = specifiedScale[property];
              if (rangeStep !== null) {
                return makeImplicit({step: rangeStep});
              } else {
                noRangeStep = true;
              }
            } else {
              // If top-level size is specified, we ignore specified rangeStep.
              log.warn(log.message.rangeStepDropped(channel));
            }
        }
      }
    }
  }
  return {
    explicit: false,
    value: defaultRange(
      channel, scaleType, type, config,
      zero, mark, sizeSignal, xyRangeSteps, noRangeStep
    )
  };
}

function parseScheme(scheme: Scheme) {
  if (isExtendedScheme(scheme)) {
    const r: VgRangeScheme = {scheme: scheme.name};
    if (scheme.count) {
      r.count = scheme.count;
    }
    if (scheme.extent) {
      r.extent = scheme.extent;
    }<commit_msg>Simplify logic for range step rule<commit_after>import {isNumber} from 'vega-util';
import {Channel, COLOR, OPACITY, SCALE_CHANNELS, ScaleChannel, SHAPE, SIZE, X, Y} from '../../channel';
import {Config} from '../../config';
import * as log from '../../log';
import {Mark} from '../../mark';
import {channelScalePropertyIncompatability, isExtendedScheme, Range, Scale, ScaleConfig, ScaleType, scaleTypeSupportProperty, Scheme} from '../../scale';
import {Type} from '../../type';
import * as util from '../../util';
import {isVgRangeStep, VgRange, VgRangeScheme, VgSignalRef} from '../../vega.schema';
import {LayoutSize} from '../layout/component';
import {Model} from '../model';
import {Explicit, makeImplicit, Split} from '../split';
import {UnitModel} from '../unit';
import {ScaleComponent, ScaleComponentIndex} from './component';
import {parseNonUnitScaleProperty} from './properties';


export type RangeMixins = {range: Range} | {rangeStep: number} | {scheme: Scheme};

export const RANGE_PROPERTIES: (keyof Scale)[] = ['range', 'rangeStep', 'scheme'];


export function parseScaleRange(model: Model) {
  if (model instanceof UnitModel) {
    parseUnitScaleRange(model);
  } else {
    parseNonUnitScaleProperty(model, 'range');
  }
}

function parseUnitScaleRange(model: UnitModel) {
  const  localScaleComponents: ScaleComponentIndex = model.component.scales;

  // use SCALE_CHANNELS instead of scales[channel] to ensure that x, y come first!
  SCALE_CHANNELS.forEach((channel: ScaleChannel) => {
    const localScaleCmpt = localScaleComponents[channel];
    if (!localScaleCmpt) {
      return;
    }

    const specifiedScale = model.specifiedScales[channel];
    const fieldDef = model.fieldDef(channel);

    // Read if there is a specified width/height
    const sizeType = channel === 'x' ? 'width' : channel === 'y' ? 'height' : undefined;
    const specifiedSize = sizeType ? model.component.layoutSize.get(sizeType) : undefined;

    const xyRangeSteps = getXYRangeStep(model);

    const rangeWithExplicit = parseRangeForChannel(
      channel, localScaleCmpt.get('type'), fieldDef.type, specifiedScale, model.config,
      localScaleCmpt.get('zero'), model.mark(), specifiedSize, model.getSizeSignalRef(sizeType), xyRangeSteps
    );

    localScaleCmpt.setWithExplicit('range', rangeWithExplicit);
  });
}

function getXYRangeStep(model: UnitModel) {
  const xyRangeSteps: number[] = [];

  const xScale = model.getScaleComponent('x');
  const xRange = xScale && xScale.get('range');
  if (xRange && isVgRangeStep(xRange) && isNumber(xRange.step)) {
    xyRangeSteps.push(xRange.step);
  }

  const yScale = model.getScaleComponent('y');
  const yRange = yScale && yScale.get('range');
  if (yRange && isVgRangeStep(yRange) && isNumber(yRange.step)) {
    xyRangeSteps.push(yRange.step);
  }

  return xyRangeSteps;
}

/**
 * Return mixins that includes one of the range properties (range, rangeStep, scheme).
 */
export function parseRangeForChannel(
    channel: Channel, scaleType: ScaleType, type: Type, specifiedScale: Scale, config: Config,
    zero: boolean, mark: Mark, specifiedSize: LayoutSize, sizeSignal: VgSignalRef, xyRangeSteps: number[]
  ): Explicit<VgRange> {

  const noRangeStep = !!specifiedSize || specifiedScale.rangeStep === null;

  // Check if any of the range properties is specified.
  // If so, check if it is compatible and make sure that we only output one of the properties
  for (const property of RANGE_PROPERTIES) {
    if (specifiedScale[property] !== undefined) {
      const supportedByScaleType = scaleTypeSupportProperty(scaleType, property);
      const channelIncompatability = channelScalePropertyIncompatability(channel, property);
      if (!supportedByScaleType) {
        log.warn(log.message.scalePropertyNotWorkWithScaleType(scaleType, property, channel));
      } else if (channelIncompatability) { // channel
        log.warn(channelIncompatability);
      } else {
        switch (property) {
          case 'range':
            return makeImplicit(specifiedScale[property]);
          case 'scheme':
            return makeImplicit(parseScheme(specifiedScale[property]));
          case 'rangeStep':
            const rangeStep = specifiedScale[property];
            if (rangeStep !== null) {
              if (specifiedSize === undefined) {
                return makeImplicit({step: rangeStep});
              } else {
                // If top-level size is specified, we ignore specified rangeStep.
                log.warn(log.message.rangeStepDropped(channel));
              }
            }
        }
      }
    }
  }
  return {
    explicit: false,
    value: defaultRange(
      channel, scaleType, type, config,
      zero, mark, sizeSignal, xyRangeSteps, noRangeStep
    )
  };
}

function parseScheme(scheme: Scheme) {
  if (isExtendedScheme(scheme)) {
    const r: VgRangeScheme = {scheme: scheme.name};
    if (scheme.count) {
      r.count = scheme.count;
    }
    if (scheme.extent) {
      r.extent = scheme.extent;
    }
{'fraction_non_alphanumeric': 0.1263829363101764, 'fraction_numerical': 0.0, 'mean_word_length': 3.554698138901498, 'pattern_counts': {'":': 0, '<': 5, '<?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': '7218434', 'n_tokens_mistral': 2948, 'n_tokens_neox': 2865, 'n_words': 762}