<commit_before>(function () {
  'use strict';

  // register the service as ModelDefinitionsService
  angular
    .module('<%= scriptAppName %>')
    .factory('ModelDefinitions', ModelDefinitions);

  // add ModelDefinitions dependencies to inject
  ModelDefinitions.$inject = ['$filter', '$q'];

  /**
   * ModelDefinitions factory constructor
   * AngularJS will instantiate a singleton which is
   * an object that has the members of this factory
   */
  function ModelDefinitions($filter, $q) {
    // public API
    angular.extend(createModelDefinition, {
      flat: flat,
      extend: extendDeep,
      get: getDeepValue,
      display: display,
      set: setDeepValue
    });

    return createModelDefinition;

    function createModelDefinition(modelDef) {
      var propDefs = flat(modelDef);
      return propDefs.map(extendDefault);
    }

    function extendDefault(propDef) {
      var lastDot = propDef.name.lastIndexOf('.');
      var lastName = lastDot === -1 ? propDef.name : propDef.name.substr(lastDot + 1);
      var defaultResourceDef = {
        desc: lastName[0].toUpperCase() + lastName.slice(1)
      };

      if (propDef.type === 'select/resource') {
        angular.extend(defaultResourceDef, {
          getOptions: function() {
            if (!propDef.resource || !propDef.resource.query) {
              console.warn('type is select/resource, but resource is not set');
              return $q.when([])
            }
            return propDef.resource.query(propDef.params).$promise;
          },
          valueKey: '_id',
          displayKey: 'name',
        });
      }

      return angular.extend({}, defaultResourceDef, propDef);
    }

    function flat(nestedDef, preName) {
      var flattenDefs = [];
      angular.forEach(nestedDef, flatPropDefinition);

      function flatPropDefinition(def, name) {
        var propDef = {name: preName ? [preName, name].join('.') : name};

        if (angular.isString(def)) {
          propDef.type = def;
        } else if (angular.isObject(def)) {
          if (angular.isString(def.type)) {
            angular.extend(propDef, def);
          } else {
            flattenDefs = flattenDefs.concat(flat(def, name));
            return;
          }
        } else {
          throw new Error('Model\'s property definition should be a string or an object');
        }
        flattenDefs.push(propDef);
      }
      return flattenDefs;
    }

    function setDeepValue (obj, propChain, value) {
      if (!obj) return;
      if (angular.isString(propChain)) {
        propChain = propChain.split('.');
      }
      if (!propChain.length) return;
      var curProp = propChain[0];
      if (propChain.length === 1) {
        return obj[curProp] = value;
      }
      obj[curProp] = obj[curProp] || {};
      setDeepValue(obj[curProp], propChain.slice(1), value);
    }

    function getDeepValue (obj, propChain) {
      if (!obj) return;
      if (angular.isString(propChain)) {
        propChain = propChain.split('.');
      }
      if (!propChain.length) return obj;
      var nextObj = obj[propChain[0]];
      return nextObj ? getDeepValue(nextObj, propChain.slice(1)) : nextObj;
    }

    function extendDeep(dst) {
      angular.forEach(arguments, function(obj) {
        if (obj === dst) return;

        angular.forEach(obj, function(value, key) {
          if (dst[key] && angular.isObject(dst[key])) {
            extendDeep(dst[key], value);
          } else {
            dst[key] = value;
          }
        });
      });
      return dst;
    }

    function display(obj, propDef) {
      if (!obj || propDef.when && !propDef.when(obj)) return;
      var value = getDeepValue(obj, propDef.name);
      if (!value) return value;
      var displayValue = propDef.displayKey ? value[propDef.displayKey] : value;
      return propDef.ngFilter ? applyFilter(displayValue, propDef.ngFilter) : displayValue;
    }

    function applyFilter(value, filterName) {
      if (!filterName) return value;
      var filter = angular.isString(filterName) ? {
        name: filterName,
      } : angular.copy(filterName);
      filter.args = [value].concat(filter.args || []);
      return $filter(filter.name).apply(null, filter.args);
    }
  }

})();<commit_msg>refactor(ModelDefinitions): alias and validator support<commit_after>(function () {
  'use strict';

  // register the service as ModelDefinitionsService
  angular
    .module('<%= scriptAppName %>')
    .factory('ModelDefinitions', ModelDefinitions);

  // add ModelDefinitions dependencies to inject
  ModelDefinitions.$inject = ['$filter', '$q'];

  /**
   * ModelDefinitions factory constructor
   * AngularJS will instantiate a singleton which is
   * an object that has the members of this factory
   */
  function ModelDefinitions($filter, $q) {
    var aliasAndShortHands = {
      required: 'validators.required',
      format: 'validators.pattern',
      mongoose: 'validators.mongoose',
      repeatInput: 'validators.repeat-input',
      remoteUnique: 'validators.remote-unique'
    };

    var defaultValidatorErrors = {
      required: 'Required',
      pattern: function(validator) {
        return 'Should fit regex ' + validator.value;
      },
      mongoose: 'Already in use',
      'remote-unique': 'Already in use',
      'repeat-input': function(validator, propDef, modelDef) {
        var refDef = modelDef[validator.value];
        var desc = refDef && refDef.desc || validator.value;
        return 'Should repeat ' + desc;
      }
    };

    // public API
    angular.extend(createModelDefinition, {
      flat: flat,
      extend: extendDeep,
      get: getDeepValue,
      display: display,
      set: setDeepValue
    });

    return createModelDefinition;

    function createModelDefinition(modelDef) {
      var propDefs = flat(modelDef);
      return propDefs
        .map(deAliasAndShorthand)
        .map(normalize)
        .map(extendDefaultRoot)
        .map(extendDefaultChildren);

      function extendDefaultChildren(propDef) {
        extendDefaultValidators(propDef.validators);
        return propDef;

        function extendDefaultValidators(validators) {
          angular.forEach(validators, function(validator, name) {
            var error = validator.error || defaultValidatorErrors[name];
            validator.error = angular.isFunction(error) ? error(validator, propDef, propDefs.$map) : error;
          });
        }
      }
    }

    function deAliasAndShorthand(propDef) {
      angular.forEach(aliasAndShortHands, function (name, alias) {
        if (propDef[alias]) {
          var obj = getDeepValue(propDef, name) || {};
          setDeepValue(propDef, name, propDef[alias]);
          delete propDef[alias];
        }
      });
      return propDef;
    }

    function normalize(propDef) {
      normalizeValidators();

      return propDef;

      function normalizeValidators() {
        if (propDef.validators) {
          angular.forEach(propDef.validators, function(validator, name) {
            propDef.validators[name] = angular.isObject(validator) && validator.toString() === '[object Object]'
              ? validator
              : {value: validator};
          });
        }
      }
    }

    function extendDefaultRoot(propDef) {
      var defaultDef = {
        desc: capitalize(propDef.name.substr(propDef.name.lastIndexOf('.') + 1))
      };

      switch(propDef.type) {
        case 'select/resource': {
          selectResource();
          break;
        }
      }

      var overrideDefaults = angular.extend(defaultDef, propDef);
      return angular.extend(propDef, overrideDefaults);

      function selectResource() {
        angular.extend(defaultDef, {
          getOptions: function() {
            if (!propDef.resource || !propDef.resource.query) {
              console.warn('type is select/resource, but resource is not set');
              return $q.when([])
            }
            return propDef.resource.query(propDef.params).$promise;
          },
          valueKey: '_id',
          displayKey: 'name',
        });
      }
    }

    function flat(nestedDef) {
      var flattenDefs = [];
      flattenDefs.$map = {};
      flatNestedPropDefinition(nestedDef);
      return flattenDefs;

      function flatNestedPropDefinition(nestedDef, preName) {
        angular.forEach(nestedDef, flatPropDefinition);

        function flatPropDefinition(def, name) {
          var propDef = {name: preName ? [preName, name].join('.') : name};

          if (angular.isString(def)) {
            propDef.type = def;
          } else if (angular.isObject(def)) {
            if (angular.isString(def.type)) {
              angular.extend(propDef, def);
            } else {
              return flatNestedPropDefinition(def, name);
            }
          } else {
            throw new Error('Model\'s property definition should be a string or an object');
          }
          flattenDefs.push(propDef);
          flattenDefs.$map[propDef.name] = propDef;
        }
      }
    }

    function setDeepValue (obj, propChain, value) {
      if (!obj) return;
      if (angular.isString(propChain)) {
        propChain = propChain.split('.');
      }
      if (!propChain.length) return;
      var curProp = propChain[0];
      if (propChain.length === 1) {
        return obj[curProp] = value;
      }
      obj[curProp] = obj[curProp] || {};
      setDeepValue(obj[curProp], propChain.slice(1), value);
    }

    function getDeepValue (obj, propChain) {
      if (!obj) return;
      if (angular.isString(propChain)) {
        propChain = propChain.split('.');
      }
      if (!propChain.length) return obj;
      var nextObj = obj[propChain[0]];
      return nextObj ? getDeepValue(nextObj, propChain.slice(1)) : nextObj;
    }

    function extendDeep(dst) {
      angular.forEach(arguments, function(obj) {
        if (obj === dst) return;

        angular.forEach(obj, function(value, key) {
          if (dst[key] && angular.isObject(dst[key])) {
            extendDeep(dst[key], value);
          } else {
            dst[key] = value;
          }
        });
      });
      return dst;
    }

    function display(obj, propDef) {
      if (!obj || propDef.when && !propDef.when(obj)) return;
      var value = getDeepValue(obj, propDef.name);
      if (!value) return value;
      var displayValue = propDef.displayKey ? value[propDef.displayKey] : value;
      return propDef.ngFilter ? applyFilter(displayValue, propDef.ngFilter) : displayValue;
    }

    function applyFilter(value, filterName) {
      if (!filterName) return value;
      var filter = angular.isString(filterName) ? {
        name: filterName,
      } : angular.copy(filterName);
      filter.args = [value].concat(filter.args || []);
      return $filter(filter.name).apply(null, filter.args);
    }

    function capitalize(name) {
      return name[0].toUpperCase() + name.slice(1)
    }
  }

})();
{'fraction_non_alphanumeric': 0.12479429511793746, 'fraction_numerical': 0.0015542146644724813, 'mean_word_length': 2.350382848392037, 'pattern_counts': {'":': 0, '<': 5, '<?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': '1699709', 'n_tokens_mistral': 3168, 'n_tokens_neox': 3101, 'n_words': 675}