<commit_before>import { L10nError } from './errors';

export function keysFromContext(ctx, keys, method) {
  return keys.map(key => {
    const [id, args] = Array.isArray(key) ?
      key : [key, undefined];

    // XXX Handle errors somehow; emit?
    const [result] = method.call(this, ctx, id, args);
    return result;
  });
}

export function valueFromContext(ctx, id, args) {
  const entity = ctx.messages.get(id);

  if (!entity) {
    return [id, [new L10nError(`Unknown entity: ${id}`)]];
  }

  return ctx.format(entity, args);
}

export function entityFromContext(ctx, id, args) {
  const entity = ctx.messages.get(id);

  if (!entity)  {
    return [
      { value: id, attrs: null },
      [new L10nError(`Unknown entity: ${id}`)]
    ];
  }

  const [value] = ctx.formatToPrimitive(entity, args);

  const formatted = {
    value,
    attrs: null,
  };

  if (entity.traits) {
    formatted.attrs = Object.create(null);
    for (let trait of entity.traits) {
      const [attrValue] = ctx.format(trait, args);
      formatted.attrs[trait.key.name] = attrValue;
    }
  }

  return [formatted, []];
}
<commit_msg>Empty strings are valid as entity values<commit_after>import { L10nError } from './errors';

export function keysFromContext(ctx, keys, method) {
  return keys.map(key => {
    const [id, args] = Array.isArray(key) ?
      key : [key, undefined];

    // XXX Handle errors somehow; emit?
    const [result] = method.call(this, ctx, id, args);
    return result;
  });
}

export function valueFromContext(ctx, id, args) {
  const entity = ctx.messages.get(id);

  if (entity === undefined) {
    return [id, [new L10nError(`Unknown entity: ${id}`)]];
  }

  return ctx.format(entity, args);
}

export function entityFromContext(ctx, id, args) {
  const entity = ctx.messages.get(id);

  if (entity === undefined) {
    return [
      { value: id, attrs: null },
      [new L10nError(`Unknown entity: ${id}`)]
    ];
  }

  const [value] = ctx.formatToPrimitive(entity, args);

  const formatted = {
    value,
    attrs: null,
  };

  if (entity.traits) {
    formatted.attrs = Object.create(null);
    for (let trait of entity.traits) {
      const [attrValue] = ctx.format(trait, args);
      formatted.attrs[trait.key.name] = attrValue;
    }
  }

  return [formatted, []];
}

{'fraction_non_alphanumeric': 0.1545138888888889, 'fraction_numerical': 0.005208333333333333, 'mean_word_length': 3.130824372759857, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 5, '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': '4965353', 'n_tokens_mistral': 786, 'n_tokens_neox': 771, 'n_words': 198}