<commit_before>const Error = require('@cardstack/data-source/error');

module.exports = class ContentType {
  constructor(model, allFields) {
    let fields = new Map();
    for (let fieldRef of model.document.fields.data) {
      fields.set(fieldRef.id, allFields.get(fieldRef.id));
    }
    this.fields = fields;
    this.id = model.id;
  }
  async validationErrors(document) {
    let errors = [];
    let seen = new Map();
    if (document.attributes) {
      for (let fieldName of Object.keys(document.attributes)) {
        let field = this.fields.get(fieldName);
        if (!field) {
          errors.push(new Error(`type "${this.id}" has no field named "${fieldName}"`));
        } else {
          errors = errors.concat(await field.validationErrors(document.attributes[fieldName], document));
          seen.set(fieldName, true);
        }
      }
    }
    for (let [fieldName, field] of this.fields.entries()) {
      if (!seen.get(fieldName)) {
        errors = errors.concat(await field.validationErrors(null, document));
      }
    }
    return errors;
  }
  mapping() {
    let properties = {};
    for (let field of this.fields.values()) {
      properties[field.id] = field.mapping();
    }
    return { properties };
  }
};<commit_msg>better error for undefined fields<commit_after>const Error = require('@cardstack/data-source/error');

module.exports = class ContentType {
  constructor(model, allFields) {
    let fields = new Map();
    for (let fieldRef of model.document.fields.data) {
      fields.set(fieldRef.id, allFields.get(fieldRef.id));
    }
    this.fields = fields;
    this.id = model.id;
  }
  async validationErrors(document) {
    let errors = [];
    let seen = new Map();
    if (document.attributes) {
      for (let fieldName of Object.keys(document.attributes)) {
        let field = this.fields.get(fieldName);
        if (!field) {
          errors.push(new Error(`type "${this.id}" has no field named "${fieldName}"`));
        } else {
          errors = errors.concat(await field.validationErrors(document.attributes[fieldName], document));
          seen.set(fieldName, true);
        }
      }
    }
    for (let [fieldName, field] of this.fields.entries()) {
      if (field && !seen.get(fieldName)) {
        errors = errors.concat(await field.validationErrors(null, document));
      }
    }
    return errors;
  }
  mapping() {
    let properties = {};
    for (let field of this.fields.values()) {
      properties[field.id] = field.mapping();
    }
    return { properties };
  }
};
{'fraction_non_alphanumeric': 0.14313802595359812, 'fraction_numerical': 0.0, 'mean_word_length': 2.703056768558952, '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': '6622877', 'n_tokens_mistral': 751, 'n_tokens_neox': 753, 'n_words': 173}