src/vs/workbench/services/preferences/common/preferencesValidation.ts/createValidator
export function createValidator(prop: IConfigurationPropertySchema): (value: any) => (string | null) {
	const type: (string | undefined)[] = Array.isArray(prop.type) ? prop.type : [prop.type];
	const isNullable = canBeType(type, 'null');
	const isNumeric = (canBeType(type, 'number') || canBeType(type, 'integer')) && (type.length === 1 || type.length === 2 && isNullable);

	const numericValidations = getNumericValidators(prop);
	const stringValidations = getStringValidators(prop);
	const arrayValidator = getArrayValidator(prop);
	const objectValidator = getObjectValidator(prop);

	return value => {
		if (isNullable && isNullOrEmpty(value)) { return ''; }

		const errors: string[] = [];
		if (arrayValidator) {
			const err = arrayValidator(value);
			if (err) {
				errors.push(err);
			}
		}

		if (objectValidator) {
			const err = objectValidator(value);
			if (err) {
				errors.push(err);
			}
		}

		if (prop.type === 'boolean' && value !== true && value !== false) {
			errors.push(nls.localize('validations.booleanIncorrectType', 'Incorrect type. Expected "boolean".'));
		}

		if (isNumeric) {
			if (isNullOrEmpty(value) || typeof value === 'boolean' || Array.isArray(value) || isNaN(+value)) {
				errors.push(nls.localize('validations.expectedNumeric', "Value must be a number."));
			} else {
				errors.push(...numericValidations.filter(validator => !validator.isValid(+value)).map(validator => validator.message));
			}
		}

		if (prop.type === 'string') {
			if (prop.enum && !isStringArray(prop.enum)) {
				errors.push(nls.localize('validations.stringIncorrectEnumOptions', 'The enum options should be strings, but there is a non-string option. Please file an issue with the extension author.'));
			} else if (!isString(value)) {
				errors.push(nls.localize('validations.stringIncorrectType', 'Incorrect type. Expected "string".'));
			} else {
				errors.push(...stringValidations.filter(validator => !validator.isValid(value)).map(validator => validator.message));
			}
		}

		if (errors.length) {
			return prop.errorMessage ? [prop.errorMessage, ...errors].join(' ') : errors.join(' ');
		}

		return '';
	};
}