<commit_before>import parseEncode from '../encode';
import {FrameRole, MarkRole} from '../marks/roles';
import {array, extend, isArray, isObject} from 'vega-util';

export function encoder(_) {
  return isObject(_) ? _ : {value: _};
}

export function addEncode(object, name, value) {
  if (value != null) {
    object[name] = isObject(value) && !isArray(value) ? value : {value: value};
    return 1;
  } else {
    return 0;
  }
}

export function extendEncode(encode, extra, skip) {
  for (var name in extra) {
    if (skip && skip.hasOwnProperty(name)) continue;
    encode[name] = extend(encode[name] || {}, extra[name]);
  }
  return encode;
}

export function encoders(encode, type, role, style, scope, params) {
  var enc, key;
  params = params || {};
  params.encoders = {$encode: (enc = {})};

  encode = applyDefaults(encode, type, role, style, scope.config);

  for (key in encode) {
    enc[key] = parseEncode(encode[key], type, params, scope);
  }

  return params;
}

function applyDefaults(encode, type, role, style, config) {
  var enter = {}, key, skip, props;

  // ignore legend and axis
  if (role == 'legend' || String(role).indexOf('axis') === 0) {
    role = null;
  }

  // resolve mark config
  props = role === FrameRole ? config.group
    : (role === MarkRole) ? extend({}, config.mark, config[type])
    : null;

  for (key in props) {
    // do not apply defaults if relevant fields are defined
    skip = has(key, encode)
      || (key === 'fill' || key === 'stroke')
      && (has('fill', encode) || has('stroke', encode));

    if (!skip) enter[key] = {value: props[key]};
  }

  // resolve styles, apply with increasing precedence
  array(style).forEach(function(name) {
    var props = config.style && config.style[name];
    for (var key in props) {
      if (!has(key, encode)) {
        enter[key] = {value: props[key]};
      }
    }
  });

  encode = extend({}, encode); // defensive copy
  encode.enter = extend(enter, encode.enter);

  return encode;
}

export function has(key, encode) {
  return encode && (
    (encode.enter && encode.enter[key]) ||
    (encode.update && encode.update[key])
  );
}<commit_msg>Update encode utilities to copy objects and allow encoders within config properties.<commit_after>import parseEncode from '../encode';
import {FrameRole, MarkRole} from '../marks/roles';
import {array, extend, isArray, isObject} from 'vega-util';

export function encoder(_) {
  return isObject(_) ? extend({}, _) : {value: _};
}

export function addEncode(object, name, value) {
  if (value != null) {
    object[name] = isObject(value) && !isArray(value) ? value : {value: value};
    return 1;
  } else {
    return 0;
  }
}

export function extendEncode(encode, extra, skip) {
  for (var name in extra) {
    if (skip && skip.hasOwnProperty(name)) continue;
    encode[name] = extend(encode[name] || {}, extra[name]);
  }
  return encode;
}

export function encoders(encode, type, role, style, scope, params) {
  var enc, key;
  params = params || {};
  params.encoders = {$encode: (enc = {})};

  encode = applyDefaults(encode, type, role, style, scope.config);

  for (key in encode) {
    enc[key] = parseEncode(encode[key], type, params, scope);
  }

  return params;
}

function applyDefaults(encode, type, role, style, config) {
  var enter = {}, key, skip, props;

  // ignore legend and axis
  if (role == 'legend' || String(role).indexOf('axis') === 0) {
    role = null;
  }

  // resolve mark config
  props = role === FrameRole ? config.group
    : (role === MarkRole) ? extend({}, config.mark, config[type])
    : null;

  for (key in props) {
    // do not apply defaults if relevant fields are defined
    skip = has(key, encode)
      || (key === 'fill' || key === 'stroke')
      && (has('fill', encode) || has('stroke', encode));

    if (!skip) enter[key] = defaultEncode(props[key]);
  }

  // resolve styles, apply with increasing precedence
  array(style).forEach(function(name) {
    var props = config.style && config.style[name];
    for (var key in props) {
      if (!has(key, encode)) {
        enter[key] = defaultEncode(props[key]);
      }
    }
  });

  encode = extend({}, encode); // defensive copy
  encode.enter = extend(enter, encode.enter);

  return encode;
}

function defaultEncode(value) {
  return value && value.signal
    ? {signal: value.signal}
    : {value: value};
}

export function has(key, encode) {
  return encode && (
    (encode.enter && encode.enter[key]) ||
    (encode.update && encode.update[key])
  );
}
{'fraction_non_alphanumeric': 0.16688770999115826, 'fraction_numerical': 0.001326259946949602, 'mean_word_length': 3.3974732750242955, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, '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': '4312432', 'n_tokens_mistral': 1456, 'n_tokens_neox': 1423, 'n_words': 417}