templates/sync-function/document-properties-validation-module.js
function validateObjectProperties(propertyValidators, allowUnknownProperties, ignoreInternalProperties) {
        var currentItemEntry = itemStack[itemStack.length - 1];
        var objectValue = currentItemEntry.itemValue;
        var oldObjectValue = currentItemEntry.oldItemValue;

        var supportedProperties = [ ];
        for (var propertyValidatorName in propertyValidators) {
          var validator = propertyValidators[propertyValidatorName];
          if (utils.isValueNullOrUndefined(validator) || utils.isValueNullOrUndefined(resolveItemConstraint(validator.type))) {
            // Skip over non-validator fields/properties
            continue;
          }

          var propertyValue = objectValue[propertyValidatorName];

          var oldPropertyValue;
          if (!utils.isValueNullOrUndefined(oldObjectValue)) {
            oldPropertyValue = oldObjectValue[propertyValidatorName];
          }

          supportedProperties.push(propertyValidatorName);

          itemStack.push({
            itemValue: propertyValue,
            oldItemValue: oldPropertyValue,
            itemName: propertyValidatorName
          });

          validateItemValue(validator);

          itemStack.pop();
        }

        // Verify there are no unsupported properties in the object
        if (!allowUnknownProperties) {
          for (var propertyName in objectValue) {
            if (ignoreInternalProperties && propertyName.indexOf('_') === 0) {
              // These properties are special cases that should always be allowed - generally only applied at the root
              // level of the document
              continue;
            }

            if (supportedProperties.indexOf(propertyName) < 0) {
              var objectPath = buildItemPath(itemStack);
              var fullPropertyPath = objectPath ? objectPath + '.' + propertyName : propertyName;
              validationErrors.push('property "' + fullPropertyPath + '" is not supported');
            }
          }
        }
      }
function validateObjectProperties(propertyValidators, allowUnknownProperties, ignoreInternalProperties) {
        var currentItemEntry = itemStack[itemStack.length - 1];
        var objectValue = currentItemEntry.itemValue;
        var oldObjectValue = currentItemEntry.oldItemValue;

        var supportedProperties = [ ];
        for (var propertyValidatorName in propertyValidators) {
          var validator = propertyValidators[propertyValidatorName];
          if (utils.isValueNullOrUndefined(validator) || utils.isValueNullOrUndefined(resolveItemConstraint(validator.type))) {
            // Skip over non-validator fields/properties
            continue;
          }

          var propertyValue = objectValue[propertyValidatorName];

          var oldPropertyValue;
          if (!utils.isValueNullOrUndefined(oldObjectValue)) {
            oldPropertyValue = oldObjectValue[propertyValidatorName];
          }

          supportedProperties.push(propertyValidatorName);

          itemStack.push({
            itemValue: propertyValue,
            oldItemValue: oldPropertyValue,
            itemName: propertyValidatorName
          });

          validateItemValue(validator);

          itemStack.pop();
        }

        // Verify there are no unsupported properties in the object
        if (!allowUnknownProperties) {
          for (var propertyName in objectValue) {
            if (ignoreInternalProperties && propertyName.indexOf('_') === 0) {
              // These properties are special cases that should always be allowed - generally only applied at the root
              // level of the document
              continue;
            }

            if (supportedProperties.indexOf(propertyName) < 0) {
              var objectPath = buildItemPath(itemStack);
              var fullPropertyPath = objectPath ? objectPath + '.' + propertyName : propertyName;
              validationErrors.push('property "' + fullPropertyPath + '" is not supported');
            }
          }
        }
      }
The following functions are nested within this function so they can share access to the doc, oldDoc and validationErrors params and the attachmentReferenceValidators and itemStack variables