<commit_before>import {Axis} from '../axis';
import {Legend} from '../legend';
import * as log from '../log';
import {Scale} from '../scale';
import {duplicate} from '../util';

/**
 * Generic classs for storing properties that are explicitly specified and implicitly determined by the compiler.
 */
export class Split<T extends Object> {
  constructor(public readonly explicit: T = {} as T, public readonly implicit: T = {} as T) {}

  public clone() {
    return new Split(duplicate(this.explicit), duplicate(this.implicit));
  }

  public combine(keys: (keyof T)[] = []): T {
    const base = keys.reduce((b, key) => {
      const value = this.get(key);
      if (value) {
        b[key] = value;
      }
      return b;
    }, {} as Partial<T>);

    // FIXME remove "as any".
    // Add "as any" to avoid an error "Spread types may only be created from object types".
    return {
      ...base as any,
      ...this.explicit as any, // Explicit properties comes first
      ...this.implicit as any
    };
  }

  public get<K extends keyof T>(key: K): T[K] {
    // Explicit has higher precedence
    return this.explicit[key] !== undefined ? this.explicit[key] : this.implicit[key];
  }

  public getWithExplicit<K extends keyof T>(key: K): Explicit<T[K]> {
    // Explicit has higher precedence
    if (this.explicit[key] !== undefined) {
      return {explicit: true, value: this.explicit[key]};
    } else if (this.implicit[key] !== undefined) {
      return {explicit: false, value: this.implicit[key]};
    }
    return {explicit: false, value: undefined};
  }

  public setWithExplicit<K extends keyof T>(key: K, value: Explicit<T[K]>) {
    if (value.value !== undefined) {
      this.set(key, value.value, value.explicit);
    }
  }

  public set<K extends keyof T>(key: K, value: T[K], explicit: boolean) {
    this[explicit ? 'explicit' : 'implicit'][key] = value;
    if (explicit) {
      delete this.implicit[key];
    }
    return this;
  }

  public copyKeyFromSplit<S, K extends keyof (T|S)>(key: K, s: Split<S>) {
    // Explicit has higher precedence
    if (s.explicit[key] !== undefined) {
      this.set(key, s.explicit[key], true);
    } else if (s.implicit[key] !== undefined) {
      this.set(key, s.implicit[key], false);
    }
  }
  public copyKeyFromObject<S, K extends keyof (T|S)>(key: K, s: S) {
    // Explicit has higher precedence
    if (s[key] !== undefined) {
      this.set(key, s[key], true);
    }
  }
<commit_msg>always remove the other value when setting value for Split<commit_after>import {Axis} from '../axis';
import {Legend} from '../legend';
import * as log from '../log';
import {Scale} from '../scale';
import {duplicate} from '../util';

/**
 * Generic classs for storing properties that are explicitly specified and implicitly determined by the compiler.
 */
export class Split<T extends Object> {
  constructor(public readonly explicit: T = {} as T, public readonly implicit: T = {} as T) {}

  public clone() {
    return new Split(duplicate(this.explicit), duplicate(this.implicit));
  }

  public combine(keys: (keyof T)[] = []): T {
    const base = keys.reduce((b, key) => {
      const value = this.get(key);
      if (value) {
        b[key] = value;
      }
      return b;
    }, {} as Partial<T>);

    // FIXME remove "as any".
    // Add "as any" to avoid an error "Spread types may only be created from object types".
    return {
      ...base as any,
      ...this.explicit as any, // Explicit properties comes first
      ...this.implicit as any
    };
  }

  public get<K extends keyof T>(key: K): T[K] {
    // Explicit has higher precedence
    return this.explicit[key] !== undefined ? this.explicit[key] : this.implicit[key];
  }

  public getWithExplicit<K extends keyof T>(key: K): Explicit<T[K]> {
    // Explicit has higher precedence
    if (this.explicit[key] !== undefined) {
      return {explicit: true, value: this.explicit[key]};
    } else if (this.implicit[key] !== undefined) {
      return {explicit: false, value: this.implicit[key]};
    }
    return {explicit: false, value: undefined};
  }

  public setWithExplicit<K extends keyof T>(key: K, value: Explicit<T[K]>) {
    if (value.value !== undefined) {
      this.set(key, value.value, value.explicit);
    }
  }

  public set<K extends keyof T>(key: K, value: T[K], explicit: boolean) {
    delete this[explicit ? 'implicit' : 'explicit'][key];
    this[explicit ? 'explicit' : 'implicit'][key] = value;
    return this;
  }

  public copyKeyFromSplit<S, K extends keyof (T|S)>(key: K, s: Split<S>) {
    // Explicit has higher precedence
    if (s.explicit[key] !== undefined) {
      this.set(key, s.explicit[key], true);
    } else if (s.implicit[key] !== undefined) {
      this.set(key, s.implicit[key], false);
    }
  }
  public copyKeyFromObject<S, K extends keyof (T|S)>(key: K, s: S) {
    // Explicit has higher precedence
    if (s[key] !== undefined) {
      this.set(key, s[key], true);
    }
  }

{'fraction_non_alphanumeric': 0.1569931479242241, 'fraction_numerical': 0.0, 'mean_word_length': 2.9672262190247802, 'pattern_counts': {'":': 0, '<': 25, '<?xml version=': 0, '>': 27, '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': '6233731', 'n_tokens_mistral': 1643, 'n_tokens_neox': 1608, 'n_words': 491}