docs: function (beanDef, beanName, packageDef) {
  
                  // used for error reporting
                  this._currentBeanName = beanName;
  
                  var baseType = beanDef[this._MD_BASETYPE];
  
                  // check if base type is already defined for this bean definition (already preprocessed)
                  if (baseType) {
                      return baseType;
                  }
  
                  beanDef[this._MD_TYPENAME] = beanName;
  
                  // temporary value to avoid an infinite loop in case of a recursive type definition:
                  beanDef[this._MD_BASETYPE] = this._typeBeingComputed;
  
                  var typeName = beanDef.$type;
                  var typeRef = this._typeRefError;
  
                  // check if this is valid declared type
                  if (typeof(typeName) != "string" || !typeName) {
                      this._logError(this.INVALID_TYPE_NAME, [beanDef[this._MD_TYPENAME], typeName]);
                  } else {
                      // retrieve type reference
                      typeRef = this.__getTypeRef(typeName, packageDef);
                      if (typeRef[this._MD_BASETYPE] !== this._typeError && !typeRef.$type) {
                          this._logError(this.ONLY_FASTNORM_PARENT, [typeRef[this._MD_TYPENAME], beanDef[this._MD_TYPENAME]]);
                          typeRef = this._typeRefError;
                      }
                  }
  
                  // store parent type
                  beanDef[this._MD_PARENTDEF] = typeRef;
                  // update typeName with fully qualified typeName
                  typeName = typeRef[this._MD_TYPENAME];
  
                  // preprocess reference type if not done yet
                  baseType = this._preprocessBean(typeRef, typeName, packageDef);
                  if (baseType == this._typeBeingComputed) {
                      // a recursive definition is normal for base types
                      if (packageDef.$package == this._BASE_TYPES_PACKAGE) {
                          return this._getBuiltInBaseType(beanDef);
                      }
                      // there was a recursive type definition
                      this._logError(this.RECURSIVE_BEAN, beanDef[this._MD_TYPENAME]);
                      return this._typeError;
                  }
  
                  beanDef[this._MD_BASETYPE] = baseType;
  
                  // check this bean definition with given base type
                  if (!this.__checkBean(beanDef)) {
                      beanDef[this._MD_BASETYPE] = this._typeError;
                  }
  
                  // description inheritance
                  if (!beanDef.$description && !typeRef[this._MD_BUILTIN]) {
                      beanDef.$description = typeRef.$description;
                  }
  
                  var hasNoDefault = !("$default" in beanDef), hasNoMandatory = !("$mandatory" in beanDef);
  
                  // mandatory and default value inheritance
                  if (hasNoDefault && hasNoMandatory) {
                      beanDef.$mandatory = false;
                      hasNoMandatory = false;
                  }
                  if (hasNoMandatory) {
                      beanDef.$mandatory = typeRef.$mandatory;
                  }
                  if (hasNoDefault && ("$default" in typeRef) && !beanDef.$mandatory) {
                      beanDef.$default = jsonUtils.copy(typeRef.$default);
                      beanDef.$simpleCopyType = typeRef.$simpleCopyType;
                      beanDef.$strDefault = typeRef.$strDefault;
                      if (typeRef.$getDefault) {
                          beanDef.$getDefault = typeRef.$getDefault;
                      }
                  }
  
                  if (baseType && baseType.makeFastNorm && !beanDef.$fastNorm) {
                      // the order in which fast normalization is done is important:
                      // a parent bean should be done before its children (so that the parent $fastNorm can be reused when possible),
                      // and so even when properties reference a parent bean (e.g. to describe a recursive structure)
                      this.__toGenerateFastNorm.push(beanDef);
                  }
  
                  // apply baseType preprocessing if any
                  if (baseType && baseType.preprocess) {
                      baseType.preprocess(beanDef, beanName, packageDef);
                  }
  
                  // if an error occur during preprocessing, return error type
                  if (beanDef[this._MD_BASETYPE] == this._typeError) {
                      return this._typeError;
                  }
  
                  // apply default configuration.
                  if ("$default" in beanDef) {
  
                      // there cannot be default and mandatory at the same time
                      if (beanDef.$mandatory === true) {
                          this._logError(this.BOTH_MANDATORY_DEFAULT, beanDef[this._MD_TYPENAME]);
                          return this._typeError;
                      }
  
                      var defaultValue = beanDef.$default;
  
                      // check the default value, this will not change it
                      // (as addDefaults is false when preprocessing beans)
                      if (this._options.checkDefaults) {
  
                          // save error state as normalization will erase it
                          var currentErrors = this._errors;
                          this._errors = [];
  
                          var errors = this._processJsonValidation({
                              beanDef : beanDef,
                              json : defaultValue
                          });
  
                          // restore errors
                          this._errors = currentErrors;
  
                          if (errors.length > 0) {
                              this._logError(this.INVALID_DEFAULTVALUE, [defaultValue, beanDef[this._MD_TYPENAME],
                                      errors]);
  
                              return this._typeError;
                          }
                      }
  
                      // simpleCopyType help to fasten copy of element
                      if (!("$simpleCopyType" in beanDef)) {
                          beanDef.$simpleCopyType = !defaultValue || typeUtils.isString(defaultValue)
                                  || typeUtils.isNumber(defaultValue) || defaultValue === true;
                      }
  
                      // strDefault is a string representation of the default value, used in fast normalization
                      // it is not normalized yet, so that the output of beans pre-compilation does not take too much space
                      if (!beanDef.$strDefault) {
                          // make a string with "reversible" set to true, or null if cannot convert
                          beanDef.$strDefault = jsonUtils.convertToJsonString(defaultValue, {
                              reversible : true
                          });
                      }
  
                      var strDefault = beanDef.$strDefault;
                      if (strDefault && !beanDef.$getDefault && baseType.makeFastNorm) {
                          beanDef.$getDefault = commonGetDefault.hasOwnProperty(strDefault) ? commonGetDefault[strDefault] : new Function("return " + strDefault + ";");
                      }
                  }
  
                  // store processed bean definition
                  this.__processedBeans[beanName] = beanDef;
  
                  return baseType;
              }