function normalizeChildren(
	ctx, container, subtypeName, containerObj, validationSets) {

	// validate type if polymorphic object container
	let subtype;
	if (container.isPolymorphObject()) {
		subtype = containerObj[container.typePropertyName];
		if (((typeof subtype) !== 'string') || !container.hasProperty(subtype)) {
			ctx.addErrorFor(
				ctx.currentPointer.toString() + '/' + container.typePropertyName,
				'{invalidType}');
			return;
		}
	}

	// go over container properties
	for (let propName of container.allPropertyNames) {
		const propDesc = container.getPropertyDesc(propName);

		// skip views
		if (propDesc.isView())
			continue;

		// check if subtype
		if (propDesc.isSubtype()) {
			if (propDesc.name === subtype) {
				normalizeChildren(
					ctx, propDesc.nestedProperties, subtype, containerObj,
					validationSets);
				const validators = getValidators(propDesc, false, validationSets);
				if (validators)
					for (let validator of validators)
						validator(ctx, containerObj);
			}
			continue;
		}

		// get property value from the record
		const originalValue = containerObj[propName];

		// descend into validating the property
		ctx.descend(
			(subtypeName ? subtypeName + ':' + propName : propName),
			containerObj
		);

		// validate property's nested elements if any
		let value = originalValue;
		if (propDesc.isArray()) {
			if (Array.isArray(value) && (value.length > 0)) {
				const elementValidators = getValidators(
					propDesc, true, validationSets);
				if (propDesc.scalarValueType === 'object') {
					for (let i = 0, len = value.length; i < len; i++) {
						const originalElementValue = value[i];
						let elementValue = originalElementValue;
						ctx.descend(String(i), value);
						if (((typeof elementValue) === 'object') &&
							(elementValue !== null))
							normalizeChildren(
								ctx, propDesc.nestedProperties, null,
								elementValue, validationSets);
						if (elementValidators) {
							for (let validator of elementValidators)
								elementValue = validator(ctx, elementValue);
							if (elementValue !== originalElementValue)
								value[i] = elementValue;
						}
						ctx.ascend();
					}
				} else if (elementValidators) {
					for (let i = 0, len = value.length; i < len; i++) {
						const originalElementValue = value[i];
						let elementValue = originalElementValue;
						ctx.descend(String(i), value);
						for (let validator of elementValidators)
							elementValue = validator(ctx, elementValue);
						if (elementValue !== originalElementValue)
							value[i] = elementValue;
						ctx.ascend();
					}
				}
			}
		} else if (propDesc.isMap()) {
			if (((typeof value) === 'object') && (value !== null)) {
				const keys = Object.keys(value);
				const elementValidators = getValidators(
					propDesc, true, validationSets);
				if (propDesc.scalarValueType === 'object') {
					for (let key of keys) {
						const originalElementValue = value[key];
						let elementValue = originalElementValue;
						ctx.descend(key, value);
						if (((typeof elementValue) === 'object') &&
							(elementValue !== null))
							normalizeChildren(
								ctx, propDesc.nestedProperties, null,
								elementValue, validationSets);
						if (elementValidators) {
							for (let validator of elementValidators)
								elementValue = validator(ctx, elementValue);
							if (elementValue !== originalElementValue)
								value[key] = elementValue;
						}
						ctx.ascend();
					}
				} else if (elementValidators) {
					for (let key of keys) {
						const originalElementValue = value[key];
						let elementValue = originalElementValue;
						ctx.descend(key, value);
						for (let validator of elementValidators)
							elementValue = validator(ctx, elementValue);
						if (elementValue !== originalElementValue)
							value[key] = elementValue;
						ctx.ascend();
					}
				}
			}
		} else if ((propDesc.scalarValueType === 'object') &&
			((typeof value) === 'object') && (value !== null)) {
			normalizeChildren(
				ctx, propDesc.nestedProperties, null, value, validationSets);
		}

		// run property validators
		const validators = getValidators(propDesc, false, validationSets);
		if (validators)
			for (let validator of validators)
				value = validator(ctx, value);

		// replace original value in the record if was normalized
		if (value !== originalValue)
			containerObj[propName] = value;

		// ascend from the property validation
		ctx.ascend();
	}
}
/**
 * Recursively validate/normalize record element's children.
 *
 * @private
 * @param {module:x2node-validators~ValidationContext} ctx Validation context.
 * @param {module:x2node-records~PropertiesContainer} container Container
 * descriptor.
 * @param {?string} subtypeName For a subtype sub-container of a polymorphic
 * object container this is the subtype name.
 * @param {Object} containerObj Unvalidated container object matching the
 * container descriptor.
 * @param {Set.<string>} validationSets Validation sets.
 */
Recursively validate/normalize record element's children.
@private
@param {module:x2node-validators~ValidationContext} ctx Validation context.
@param {module:x2node-records~PropertiesContainer} container Container
descriptor.
@param {?string} subtypeName For a subtype sub-container of a polymorphic
object container this is the subtype name.
@param {Object} containerObj Unvalidated container object matching the
container descriptor.
@param {Set.} validationSets Validation sets.
Recursively validate / normalize record element ' s children . @private @param { module : x2node - validators~ValidationContext } ctx Validation context . @param { module : x2node - records~PropertiesContainer } container Container descriptor . @param { ?string } subtypeName For a subtype sub - container of a polymorphic object container this is the subtype name . @param { Object } containerObj Unvalidated container object matching the container descriptor . @param { Set . } validationSets Validation sets .
function normalizeChildren(
	ctx, container, subtypeName, containerObj, validationSets) {
	let subtype;
	if (container.isPolymorphObject()) {
		subtype = containerObj[container.typePropertyName];
		if (((typeof subtype) !== 'string') || !container.hasProperty(subtype)) {
			ctx.addErrorFor(
				ctx.currentPointer.toString() + '/' + container.typePropertyName,
				'{invalidType}');
			return;
		}
	}
	for (let propName of container.allPropertyNames) {
		const propDesc = container.getPropertyDesc(propName);
		if (propDesc.isView())
			continue;
		if (propDesc.isSubtype()) {
			if (propDesc.name === subtype) {
				normalizeChildren(
					ctx, propDesc.nestedProperties, subtype, containerObj,
					validationSets);
				const validators = getValidators(propDesc, false, validationSets);
				if (validators)
					for (let validator of validators)
						validator(ctx, containerObj);
			}
			continue;
		}
		const originalValue = containerObj[propName];
		ctx.descend(
			(subtypeName ? subtypeName + ':' + propName : propName),
			containerObj
		);
		let value = originalValue;
		if (propDesc.isArray()) {
			if (Array.isArray(value) && (value.length > 0)) {
				const elementValidators = getValidators(
					propDesc, true, validationSets);
				if (propDesc.scalarValueType === 'object') {
					for (let i = 0, len = value.length; i < len; i++) {
						const originalElementValue = value[i];
						let elementValue = originalElementValue;
						ctx.descend(String(i), value);
						if (((typeof elementValue) === 'object') &&
							(elementValue !== null))
							normalizeChildren(
								ctx, propDesc.nestedProperties, null,
								elementValue, validationSets);
						if (elementValidators) {
							for (let validator of elementValidators)
								elementValue = validator(ctx, elementValue);
							if (elementValue !== originalElementValue)
								value[i] = elementValue;
						}
						ctx.ascend();
					}
				} else if (elementValidators) {
					for (let i = 0, len = value.length; i < len; i++) {
						const originalElementValue = value[i];
						let elementValue = originalElementValue;
						ctx.descend(String(i), value);
						for (let validator of elementValidators)
							elementValue = validator(ctx, elementValue);
						if (elementValue !== originalElementValue)
							value[i] = elementValue;
						ctx.ascend();
					}
				}
			}
		} else if (propDesc.isMap()) {
			if (((typeof value) === 'object') && (value !== null)) {
				const keys = Object.keys(value);
				const elementValidators = getValidators(
					propDesc, true, validationSets);
				if (propDesc.scalarValueType === 'object') {
					for (let key of keys) {
						const originalElementValue = value[key];
						let elementValue = originalElementValue;
						ctx.descend(key, value);
						if (((typeof elementValue) === 'object') &&
							(elementValue !== null))
							normalizeChildren(
								ctx, propDesc.nestedProperties, null,
								elementValue, validationSets);
						if (elementValidators) {
							for (let validator of elementValidators)
								elementValue = validator(ctx, elementValue);
							if (elementValue !== originalElementValue)
								value[key] = elementValue;
						}
						ctx.ascend();
					}
				} else if (elementValidators) {
					for (let key of keys) {
						const originalElementValue = value[key];
						let elementValue = originalElementValue;
						ctx.descend(key, value);
						for (let validator of elementValidators)
							elementValue = validator(ctx, elementValue);
						if (elementValue !== originalElementValue)
							value[key] = elementValue;
						ctx.ascend();
					}
				}
			}
		} else if ((propDesc.scalarValueType === 'object') &&
			((typeof value) === 'object') && (value !== null)) {
			normalizeChildren(
				ctx, propDesc.nestedProperties, null, value, validationSets);
		}
		const validators = getValidators(propDesc, false, validationSets);
		if (validators)
			for (let validator of validators)
				value = validator(ctx, value);
		if (value !== originalValue)
			containerObj[propName] = value;
		ctx.ascend();
	}
}
function normalizeChildren ( ctx , container , subtypeName , containerObj , validationSets ) { let subtype ; if ( container . isPolymorphObject ( ) ) { subtype = containerObj [ container . typePropertyName ] ; if ( ( ( typeof subtype ) !== 'string' ) || ! container . hasProperty ( subtype ) ) { ctx . addErrorFor ( ctx . currentPointer . toString ( ) + '/' + container . typePropertyName , '{invalidType}' ) ; return ; } } for ( let propName of container . allPropertyNames ) { const propDesc = container . getPropertyDesc ( propName ) ; if ( propDesc . isView ( ) ) continue ; if ( propDesc . isSubtype ( ) ) { if ( propDesc . name === subtype ) { normalizeChildren ( ctx , propDesc . nestedProperties , subtype , containerObj , validationSets ) ; const validators = getValidators ( propDesc , false , validationSets ) ; if ( validators ) for ( let validator of validators ) validator ( ctx , containerObj ) ; } continue ; } const originalValue = containerObj [ propName ] ; ctx . descend ( ( subtypeName ? subtypeName + ':' + propName : propName ) , containerObj ) ; let value = originalValue ; if ( propDesc . isArray ( ) ) { if ( Array . isArray ( value ) && ( value . length > 0 ) ) { const elementValidators = getValidators ( propDesc , true , validationSets ) ; if ( propDesc . scalarValueType === 'object' ) { for ( let i = 0 , len = value . length ; i < len ; i ++ ) { const originalElementValue = value [ i ] ; let elementValue = originalElementValue ; ctx . descend ( String ( i ) , value ) ; if ( ( ( typeof elementValue ) === 'object' ) && ( elementValue !== null ) ) normalizeChildren ( ctx , propDesc . nestedProperties , null , elementValue , validationSets ) ; if ( elementValidators ) { for ( let validator of elementValidators ) elementValue = validator ( ctx , elementValue ) ; if ( elementValue !== originalElementValue ) value [ i ] = elementValue ; } ctx . ascend ( ) ; } } else if ( elementValidators ) { for ( let i = 0 , len = value . length ; i < len ; i ++ ) { const originalElementValue = value [ i ] ; let elementValue = originalElementValue ; ctx . descend ( String ( i ) , value ) ; for ( let validator of elementValidators ) elementValue = validator ( ctx , elementValue ) ; if ( elementValue !== originalElementValue ) value [ i ] = elementValue ; ctx . ascend ( ) ; } } } } else if ( propDesc . isMap ( ) ) { if ( ( ( typeof value ) === 'object' ) && ( value !== null ) ) { const keys = Object . keys ( value ) ; const elementValidators = getValidators ( propDesc , true , validationSets ) ; if ( propDesc . scalarValueType === 'object' ) { for ( let key of keys ) { const originalElementValue = value [ key ] ; let elementValue = originalElementValue ; ctx . descend ( key , value ) ; if ( ( ( typeof elementValue ) === 'object' ) && ( elementValue !== null ) ) normalizeChildren ( ctx , propDesc . nestedProperties , null , elementValue , validationSets ) ; if ( elementValidators ) { for ( let validator of elementValidators ) elementValue = validator ( ctx , elementValue ) ; if ( elementValue !== originalElementValue ) value [ key ] = elementValue ; } ctx . ascend ( ) ; } } else if ( elementValidators ) { for ( let key of keys ) { const originalElementValue = value [ key ] ; let elementValue = originalElementValue ; ctx . descend ( key , value ) ; for ( let validator of elementValidators ) elementValue = validator ( ctx , elementValue ) ; if ( elementValue !== originalElementValue ) value [ key ] = elementValue ; ctx . ascend ( ) ; } } } } else if ( ( propDesc . scalarValueType === 'object' ) && ( ( typeof value ) === 'object' ) && ( value !== null ) ) { normalizeChildren ( ctx , propDesc . nestedProperties , null , value , validationSets ) ; } const validators = getValidators ( propDesc , false , validationSets ) ; if ( validators ) for ( let validator of validators ) value = validator ( ctx , value ) ; if ( value !== originalValue ) containerObj [ propName ] = value ; ctx . ascend ( ) ; } }
Recursively validate/normalize record element's children.
Recursively validate / normalize record element ' s children .
// validate type if polymorphic object container // go over container properties // skip views // check if subtype // get property value from the record // descend into validating the property // validate property's nested elements if any // run property validators // replace original value in the record if was normalized // ascend from the property validation