<commit_before>import { dispatch } from 'd3-dispatch';
import { extent } from 'd3-array';
import * as d3Scale from 'd3-scale';
import * as d3ScaleChromatic from 'd3-scale-chromatic';
import supportedScales from './supportedScales';
import readFromScale from './readFromScale';
import d3Interpolators from './d3Interpolators';
import d3ColorSchemes from './d3ColorSchemes';

const Events = {
  // when we change the scale, update is fired
  update: 'update',

  // any time a setter is called on the scale, proxySet is fired
  proxySet: 'proxy-set',
};

// needed for on change scale by type to ensure we have valid initial settings
const defaultScales = {
  scaleOrdinal: d3Scale.scaleOrdinal(d3Scale.schemeCategory10),
  scaleSequential: d3Scale.scaleSequential(d3Scale.interpolateMagma),
  scalePow: d3Scale.scalePow().exponent(10),
};

/**
 * Class for proxying a d3 scale so it can change type and keep stats
 * without changing its reference or interface.
 */
export default class ScaleProxy {

  /**
   * Constructor
   * @param {String} name The name of the scale
   * @param {Function} update The function to call to redraw a chart
  */
  constructor(name) {
    this.name = name;
    this.dispatch = dispatch(Events.update, Events.proxySet);
    this.statsReset();

    this.scale = null;
    this.originalScale = null;
    this.proxyScale = this.proxyScale.bind(this);
  }


  on(event, callback) {
    this.dispatch.on(event, callback);
    return this;
  }

  update() {
    this.dispatch.call(Events.update, this);
  }

  /**
   * Generate the js code to create this scale from scratch
   */
  generateCode() {
    const ignoreKeys = [
      'bandwidth',
      'copy',
      'interpolate',
      'interpolator',
      'invert',
      'nice',
      'quantiles',
      'range',
      'rangeRound',
      'step',
      'ticks',
      'tickFormat',
    ];

    const newDefault = d3Scale[this.scaleType]();

    let settings = Object.keys(this.scale)
      .filter(key => !ignoreKeys.includes(key))
      .map(key => ({ key, value: this.scale[key]() }))
      // filter out values that are the default
      .filter(({ key, value }) => newDefault[key]() != value) // eslint-disable-line
      .map(({ key, value }) => ({ key, value: JSON.stringify(value) }));

    // match the interpolator name
    if (this.scale.interpolator) {
      const interpolator = this.scale.interpolator();
      const interpolators = d3Interpolators();
      for (let i = 0; i < interpolators.length; i++) {
        const checkInterpolator = d3Scale[interpolators[i]] || d3ScaleChromatic[interpolators[i]];
        if (interpolator === checkInterpolator) {
          settings.push({ key: 'interpolator', value: `d3.${interpolators[i]}` });
          break;
        }
      }
    }

    // match a color scheme
    if (this.scale.range) {
      const range = JSON.stringify(this.scale.range());
      const schemes = d3ColorSchemes();

      let rangeSetting;
      for (let i = 0; i < schemes.length; i++) {
        const checkRange = JSON.stringify(d3Scale[schemes[i]] || d3ScaleChromatic[schemes[i]]);
        if (range === checkRange) {
          rangeSetting = { key: 'range', value: `d3.${schemes[i]}` };
          break;
        }
      }

      if (!rangeSetting) {
        rangeSetting = { key: 'range', value: range };<commit_msg>Generated code uses spaces after commas in arrays #6<commit_after>import { dispatch } from 'd3-dispatch';
import { extent } from 'd3-array';
import * as d3Scale from 'd3-scale';
import * as d3ScaleChromatic from 'd3-scale-chromatic';
import supportedScales from './supportedScales';
import readFromScale from './readFromScale';
import d3Interpolators from './d3Interpolators';
import d3ColorSchemes from './d3ColorSchemes';

const Events = {
  // when we change the scale, update is fired
  update: 'update',

  // any time a setter is called on the scale, proxySet is fired
  proxySet: 'proxy-set',
};

// needed for on change scale by type to ensure we have valid initial settings
const defaultScales = {
  scaleOrdinal: d3Scale.scaleOrdinal(d3Scale.schemeCategory10),
  scaleSequential: d3Scale.scaleSequential(d3Scale.interpolateMagma),
  scalePow: d3Scale.scalePow().exponent(10),
};

/**
 * Class for proxying a d3 scale so it can change type and keep stats
 * without changing its reference or interface.
 */
export default class ScaleProxy {

  /**
   * Constructor
   * @param {String} name The name of the scale
   * @param {Function} update The function to call to redraw a chart
  */
  constructor(name) {
    this.name = name;
    this.dispatch = dispatch(Events.update, Events.proxySet);
    this.statsReset();

    this.scale = null;
    this.originalScale = null;
    this.proxyScale = this.proxyScale.bind(this);
  }


  on(event, callback) {
    this.dispatch.on(event, callback);
    return this;
  }

  update() {
    this.dispatch.call(Events.update, this);
  }

  /**
   * Generate the js code to create this scale from scratch
   */
  generateCode() {
    const ignoreKeys = [
      'bandwidth',
      'copy',
      'interpolate',
      'interpolator',
      'invert',
      'nice',
      'quantiles',
      'range',
      'rangeRound',
      'step',
      'ticks',
      'tickFormat',
    ];

    const newDefault = d3Scale[this.scaleType]();

    // helper to get prettier stringified values
    function stringifyValue(value) {
      if (Array.isArray(value)) {
        // get spaces after commas in arrays
        return `[${value.map(v => JSON.stringify(v)).join(', ')}]`;
      }
      return JSON.stringify(value);
    }

    let settings = Object.keys(this.scale)
      .filter(key => !ignoreKeys.includes(key))
      .map(key => ({ key, value: this.scale[key]() }))
      // filter out values that are the default
      .filter(({ key, value }) => newDefault[key]() != value) // eslint-disable-line
      .map(({ key, value }) => ({ key, value: stringifyValue(value) }));

    // match the interpolator name
    if (this.scale.interpolator) {
      const interpolator = this.scale.interpolator();
      const interpolators = d3Interpolators();
      for (let i = 0; i < interpolators.length; i++) {
        const checkInterpolator = d3Scale[interpolators[i]] || d3ScaleChromatic[interpolators[i]];
        if (interpolator === checkInterpolator) {
          settings.push({ key: 'interpolator', value: `d3.${interpolators[i]}` });
          break;
        }
      }
    }

    // match a color scheme
    if (this.scale.range) {
      const range = JSON.stringify(this.scale.range());
      const schemes = d3ColorSchemes();

      let rangeSetting;
      for (let i = 0; i < schemes.length; i++) {
        const checkRange = JSON.stringify(d3Scale[schemes[i]] || d3ScaleChromatic[schemes[i]]);
        if (range === checkRange) {
          rangeSetting = { key: 'range', value: `d3.${schemes[i]}` };
          break;
        }
      }

      if (!rangeSetting) {
        rangeSetting = { key: 'range', value: stringifyValue(this.scale.range()) };
{'fraction_non_alphanumeric': 0.13516985441050527, 'fraction_numerical': 0.008992292320867828, 'mean_word_length': 2.9036211699164345, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 12, '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': '5897284', 'n_tokens_mistral': 2201, 'n_tokens_neox': 2148, 'n_words': 583}