<commit_before>import {SHARED_DOMAIN_OP_INDEX} from '../../aggregate';
import {binToString} from '../../bin';
import {Channel} from '../../channel';
import {MAIN, RAW} from '../../data';
import {DateTime, dateTimeExpr, isDateTime} from '../../datetime';
import {FieldDef} from '../../fielddef';
import * as log from '../../log';
import {Domain, hasDiscreteDomain, isBinScale, isSelectionDomain, Scale, ScaleConfig, ScaleType} from '../../scale';
import {isSortField} from '../../sort';
import * as util from '../../util';
import {
  FieldRefUnionDomain,
  isDataRefDomain,
  isDataRefUnionedDomain,
  isFieldRefUnionDomain,
  isSignalRefDomain,
  VgDataRef,
  VgDomain,
  VgSortField
} from '../../vega.schema';
import {VgSignalRef} from '../../vega.schema';
import {UnitModel} from '../unit';


export function initDomain(domain: Domain, fieldDef: FieldDef<string>, scale: ScaleType, scaleConfig: ScaleConfig) {
  if (domain === 'unaggregated') {
    const {valid, reason} = canUseUnaggregatedDomain(fieldDef, scale);
    if(!valid) {
      log.warn(reason);
      return undefined;
    }
  } else if (domain === undefined && scaleConfig.useUnaggregatedDomain) {
    // Apply config if domain is not specified.
    const {valid} = canUseUnaggregatedDomain(fieldDef, scale);
    if (valid) {
      return 'unaggregated';
    }
  }

  return domain;
}


export function parseDomain(model: UnitModel, channel: Channel): VgDomain {
  const scale = model.scale(channel);

  // If channel is either X or Y then union them with X2 & Y2 if they exist
  if (channel === 'x' && model.channelHasField('x2')) {
    if (model.channelHasField('x')) {
      return unionDomains(parseSingleChannelDomain(scale, model, 'x'), parseSingleChannelDomain(scale, model, 'x2'));
    } else {
      return parseSingleChannelDomain(scale, model, 'x2');
    }
  } else if (channel === 'y' && model.channelHasField('y2')) {
    if (model.channelHasField('y')) {
      return unionDomains(parseSingleChannelDomain(scale, model, 'y'), parseSingleChannelDomain(scale, model, 'y2'));
    } else {
      return parseSingleChannelDomain(scale, model, 'y2');
    }
  }
  return parseSingleChannelDomain(scale, model, channel);
}

function parseSingleChannelDomain(scale: Scale, model: UnitModel, channel:Channel): VgDomain {
  const fieldDef = model.fieldDef(channel);

  if (scale.domain && scale.domain !== 'unaggregated' && !isSelectionDomain(scale.domain)) { // explicit value
    if (fieldDef.bin) {
      log.warn(log.message.conflictedDomain(channel));
    } else {
      if (isDateTime(scale.domain[0])) {
        return (scale.domain as DateTime[]).map((dt) => {
          return {signal: dateTimeExpr(dt, true)};
        });
      }
      return scale.domain;
    }
  }

  const stack = model.stack;
  if (stack && channel === stack.fieldChannel) {
    if(stack.offset === 'normalize') {
      return [0, 1];
    }
    return {
      data: model.requestDataName(MAIN),
      fields: [
        model.field(channel, {suffix: 'start'}),
        model.field(channel, {suffix: 'end'})
      ]
    };
  }

  const sort = domainSort(model, channel, scale.type);

  if (scale.domain === 'unaggregated') {
    return {
      data: model.requestDataName(MAIN),
      fields: [
        model.field(channel, {aggregate: 'min'}),
        model.field(channel, {aggregate: 'max'})
      ]
    };
  } else if (fieldDef.bin) { // bin
    if (isBinScale(scale.type)) {
      const signal = model.getName(`${binToString(fieldDef.bin)}_${fieldDef.field}_bins`);
      return {signal: `sequence(${signal}.start, ${signal}.stop + ${signal}.step, ${signal}.step)`};
    }

    if (hasDiscreteDomain(scale.type)) {
      // ordinal bin scale takes domain from bin_range, ordered by bin_start
      // This is useful for both axis-based scale (x, y, column, and row) and legend-based scale (other channels).
      return {
        data: model.requestDataName(MAIN),
        field: model.field(channel, {binSuffix: 'range'}),
        sort: {<commit_msg>Refactor `parseSingleChannelDomain` to take `scaleType` and `domain` as parameter rather than the whole scale<commit_after>import {SHARED_DOMAIN_OP_INDEX} from '../../aggregate';
import {binToString} from '../../bin';
import {Channel} from '../../channel';
import {MAIN, RAW} from '../../data';
import {DateTime, dateTimeExpr, isDateTime} from '../../datetime';
import {FieldDef} from '../../fielddef';
import * as log from '../../log';
import {Domain, hasDiscreteDomain, isBinScale, isSelectionDomain, Scale, ScaleConfig, ScaleType} from '../../scale';
import {isSortField} from '../../sort';
import * as util from '../../util';
import {
  FieldRefUnionDomain,
  isDataRefDomain,
  isDataRefUnionedDomain,
  isFieldRefUnionDomain,
  isSignalRefDomain,
  VgDataRef,
  VgDomain,
  VgSortField
} from '../../vega.schema';
import {VgSignalRef} from '../../vega.schema';
import {UnitModel} from '../unit';


export function initDomain(domain: Domain, fieldDef: FieldDef<string>, scale: ScaleType, scaleConfig: ScaleConfig) {
  if (domain === 'unaggregated') {
    const {valid, reason} = canUseUnaggregatedDomain(fieldDef, scale);
    if(!valid) {
      log.warn(reason);
      return undefined;
    }
  } else if (domain === undefined && scaleConfig.useUnaggregatedDomain) {
    // Apply config if domain is not specified.
    const {valid} = canUseUnaggregatedDomain(fieldDef, scale);
    if (valid) {
      return 'unaggregated';
    }
  }

  return domain;
}

// FIXME(https://github.com/vega/vega-lite/issues/2251#issuecomment-306683920)
// parseDomain must be called separately after parseScale
export function parseDomain(model: UnitModel, channel: Channel): VgDomain {
  // FIXME replace this with getScaleComponent once parseScaleDomain a separate parseStep from scale
  const scaleType = model.scale(channel).type;
  const domain = model.scaleDomain(channel);

  // If channel is either X or Y then union them with X2 & Y2 if they exist
  if (channel === 'x' && model.channelHasField('x2')) {
    if (model.channelHasField('x')) {
      return unionDomains(parseSingleChannelDomain(scaleType, domain, model, 'x'), parseSingleChannelDomain(scaleType, domain, model, 'x2'));
    } else {
      return parseSingleChannelDomain(scaleType, domain, model, 'x2');
    }
  } else if (channel === 'y' && model.channelHasField('y2')) {
    if (model.channelHasField('y')) {
      return unionDomains(parseSingleChannelDomain(scaleType, domain, model, 'y'), parseSingleChannelDomain(scaleType, domain, model, 'y2'));
    } else {
      return parseSingleChannelDomain(scaleType, domain, model, 'y2');
    }
  }
  return parseSingleChannelDomain(scaleType, domain, model, channel);
}

function parseSingleChannelDomain(scaleType: ScaleType, domain: Domain, model: UnitModel, channel:Channel): VgDomain {
  const fieldDef = model.fieldDef(channel);

  if (domain && domain !== 'unaggregated' && !isSelectionDomain(domain)) { // explicit value
    if (fieldDef.bin) {
      log.warn(log.message.conflictedDomain(channel));
    } else {
      if (isDateTime(domain[0])) {
        return (domain as DateTime[]).map((dt) => {
          return {signal: dateTimeExpr(dt, true)};
        });
      }
      return domain;
    }
  }

  const stack = model.stack;
  if (stack && channel === stack.fieldChannel) {
    if(stack.offset === 'normalize') {
      return [0, 1];
    }
    return {
      data: model.requestDataName(MAIN),
      fields: [
        model.field(channel, {suffix: 'start'}),
        model.field(channel, {suffix: 'end'})
      ]
    };
  }

  const sort = domainSort(model, channel, scaleType);

  if (domain === 'unaggregated') {
    return {
      data: model.requestDataName(MAIN),
      fields: [
        model.field(channel, {aggregate: 'min'}),
        model.field(channel, {aggregate: 'max'})
      ]
    };
  } else if (fieldDef.bin) { // bin
    if (isBinScale(scaleType)) {
      const signal = model.getName(`${binToString(fieldDef.bin)}_${fieldDef.field}_bins`);
      return {signal: `sequence(${signal}.start, ${signal}.stop + ${signal}.step, ${signal}.step)`};
    }

    if (hasDiscreteDomain(scaleType)) {
      // ordinal bin scale takes domain from bin_range, ordered by bin_start
      // This is useful for both axis-based scale (x, y, column, and row) and legend-based scale (other channels).
      return {
        data: model.requestDataName(MAIN),
        field: model.field(channel, {binSuffix: 'range'}),
        sort: {
{'fraction_non_alphanumeric': 0.15302743614001893, 'fraction_numerical': 0.0041390728476821195, 'mean_word_length': 3.4746031746031747, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 7, 'https://': 1, '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': '3922024', 'n_tokens_mistral': 2596, 'n_tokens_neox': 2549, 'n_words': 657}