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 stringArrayValidator = getArrayOfStringValidator(prop);

	return value => {
		if (prop.type === 'string' && stringValidations.length === 0) { return null; }
		if (isNullable && value === '') { return ''; }

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

		if (isNumeric) {
			if (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') {
			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 '';
	};
}