<commit_before>// Copyright 2019-2022, University of Colorado Boulder

/**
 * The definition file for "validators" used to validate values. This file holds associated logic that validates the
 * schema of the "validator" object, as well as testing if a value adheres to the restrictions provided by a validator.
 * See validate.js for usage with assertions to check that values are valid.
 *
 * Examples:
 *
 * A {ValidatorDef} (commonly know as "validator") that only accepts number values:
 * { valueType: 'number' }
 *
 * A validator that only accepts the numbers "2" or "3":
 * { valueType: 'number', validValues: [ 2, 3 ] }
 *
 * A validator that accepts any Object:
 * { valueType: Object }
 *
 * A validator that accepts EnumerationDeprecated values (NOTE! This is deprecated, use the new class-based enumeration pattern as the valueType):
 * { valueType: MyEnumeration }
 * and/or
 * { validValues: MyEnumeration.VALUES }
 *
 * A validator that accepts a string or a number greater than 2:
 * { isValidValue: value => { typeof value === 'string' || (typeof value === 'number' && value > 2)} }
 *
 * @author <NAME> (PhET Interactive Simulations)
 * @author <NAME> (PhET Interactive Simulations)
 */

import EnumerationDeprecated from '../../phet-core/js/EnumerationDeprecated.js';
import Constructor from '../../phet-core/js/types/Constructor.js';
import IntentionalAny from '../../phet-core/js/types/IntentionalAny.js';
import optionize from '../../phet-core/js/optionize.js';
import IOType from '../../tandem/js/types/IOType.js';
import axon from './axon.js';

const TYPEOF_STRINGS = [ 'string', 'number', 'boolean', 'function' ];
const ARRAY_VALIDATOR = { valueType: Array, validationMessage: 'Should be an Array' };

export type IsValidValueOptions = {

  // By default validation will always check the validity of the  validator itself.  However, for types like
  // Property and Emitter re-checking the validator every time the Property value changes or the Emitter emits
  // wastes cpu. Hence cases like those can opt-out
  validateValidator?: boolean;
};

type ValueType = string | Constructor | EnumerationDeprecated | null | ValueType[];
export type Validator<T = any> = {
  valueType?: ValueType | ValueType[];
  validValues?: readonly T[] | null;
  isValidValue?: ( v?: any ) => boolean | null | void;
  arrayElementType?: ValueType;
  phetioType?: IOType;

  // if provided, this will provide supplemental information to the assertion/validation messages in addition to the
  // validate-key-specific message that will be given.
  validationMessage?: string;
}

// Key names are verbose so this can be mixed into other contexts like AXON/Property. `undefined` and `null` have the
// same semantics so that we can use this feature without having extend and allocate new objects at every validation.
const VALIDATOR_KEYS: Array<keyof Validator> = [
  // Type of the value.
  // If {function}, the function must be a constructor.
  // If {string}, the string must be one of the primitive types listed in TYPEOF_STRINGS.
  // If {null|undefined}, the value must be null (which doesn't make sense until the next line of doc)
  // If {Array.<string|function|null|undefined>}, each item must be a legal value as explained in the above doc
  // Unused if null.
  // Examples:
  // valueType: Vector2
  // valueType: 'string'
  // valueType: 'number',<commit_msg>better typing, https://github.com/phetsims/studio/issues/253<commit_after>// Copyright 2019-2022, University of Colorado Boulder

/**
 * The definition file for "validators" used to validate values. This file holds associated logic that validates the
 * schema of the "validator" object, as well as testing if a value adheres to the restrictions provided by a validator.
 * See validate.js for usage with assertions to check that values are valid.
 *
 * Examples:
 *
 * A {ValidatorDef} (commonly know as "validator") that only accepts number values:
 * { valueType: 'number' }
 *
 * A validator that only accepts the numbers "2" or "3":
 * { valueType: 'number', validValues: [ 2, 3 ] }
 *
 * A validator that accepts any Object:
 * { valueType: Object }
 *
 * A validator that accepts EnumerationDeprecated values (NOTE! This is deprecated, use the new class-based enumeration pattern as the valueType):
 * { valueType: MyEnumeration }
 * and/or
 * { validValues: MyEnumeration.VALUES }
 *
 * A validator that accepts a string or a number greater than 2:
 * { isValidValue: value => { typeof value === 'string' || (typeof value === 'number' && value > 2)} }
 *
 * @author <NAME> (PhET Interactive Simulations)
 * @author <NAME> (PhET Interactive Simulations)
 */

import EnumerationDeprecated from '../../phet-core/js/EnumerationDeprecated.js';
import Constructor from '../../phet-core/js/types/Constructor.js';
import IntentionalAny from '../../phet-core/js/types/IntentionalAny.js';
import optionize from '../../phet-core/js/optionize.js';
import IOType from '../../tandem/js/types/IOType.js';
import axon from './axon.js';

const TYPEOF_STRINGS = [ 'string', 'number', 'boolean', 'function' ];
const ARRAY_VALIDATOR = { valueType: Array, validationMessage: 'Should be an Array' };

export type IsValidValueOptions = {

  // By default validation will always check the validity of the  validator itself.  However, for types like
  // Property and Emitter re-checking the validator every time the Property value changes or the Emitter emits
  // wastes cpu. Hence cases like those can opt-out
  validateValidator?: boolean;
};

type ValueType = string | Constructor | EnumerationDeprecated | null | ValueType[];
export type Validator<T = any> = {
  valueType?: ValueType | ValueType[];
  validValues?: readonly T[];
  isValidValue?: ( v?: any ) => boolean;
  arrayElementType?: ValueType;
  phetioType?: IOType;

  // if provided, this will provide supplemental information to the assertion/validation messages in addition to the
  // validate-key-specific message that will be given.
  validationMessage?: string;
}

// Key names are verbose so this can be mixed into other contexts like AXON/Property. `undefined` and `null` have the
// same semantics so that we can use this feature without having extend and allocate new objects at every validation.
const VALIDATOR_KEYS: Array<keyof Validator> = [
  // Type of the value.
  // If {function}, the function must be a constructor.
  // If {string}, the string must be one of the primitive types listed in TYPEOF_STRINGS.
  // If {null|undefined}, the value must be null (which doesn't make sense until the next line of doc)
  // If {Array.<string|function|null|undefined>}, each item must be a legal value as explained in the above doc
  // Unused if null.
  // Examples:
  // valueType: Vector2
  // valueType: 'string'
  // valueType: 'number',
{'fraction_non_alphanumeric': 0.10950413223140495, 'fraction_numerical': 0.00487012987012987, 'mean_word_length': 3.9539473684210527, 'pattern_counts': {'":': 2, '<': 13, '<?xml version=': 0, '>': 19, 'https://': 1, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2596216', 'n_tokens_mistral': 1924, 'n_tokens_neox': 1858, 'n_words': 786}