
/**
 * @callback DataFieldValidator
 * A Custom DataField validator function.
 *
 * A boolean return value indicates that the value is valid (true) or invalid (false) with certainty. With an explicit
 * boolean return value no further validation functions will be evaluated.
 *
 * An undefined return indicates that the value may be valid but further validation functions should be performed,
 * if defined.
 *
 * An Error may be thrown which provides a custom error message explaining the reason the value is invalid.
 *
 * @param {any} value                     The value provided for validation
 * @param {DataFieldValidationOptions} options  Validation options
 * @returns {boolean|void}
 * @throws {Error}
 */

/**
 * @typedef DataFieldOptions
 * @property {boolean} [required=false]   Is this field required to be populated?
 * @property {boolean} [nullable=false]   Can this field have null values?
 * @property {boolean} [readonly=false]   Should the initialized (prepared) property of the DataModel instance for this
 *                                        field be read-only, i.e. nonwritable and nonconfigurable? The source value of
 *                                        a read-only field can still be changed by `updateSource`, but a source change
 *                                        won't necessarily be reflected on the prepared value. Usually the prepared
 *                                        value of a read-only field is effectively immutable, but not in all cases:
 *                                        for example, `EmbeddedCollectionField`. The `_id` field is a special behavior:
 *                                        the prepared property becomes nonconfigurable only after the source value
 *                                        becomes a nonnull value for the first time.
 * @property {boolean} [persisted=true]   Is a value of this field written to source data? A Non-persisted value is
 *                                        initialized (with its initial value), and ActiveEffects can use the field
 *                                        for change application.
 * @property {boolean} [gmOnly=false]     Can this field only be modified by a gamemaster or assistant gamemaster?
 * @property {Function|*} [initial]       The initial value of a field, or a function which assigns that initial value.
 * @property {string} [label]             A localizable label displayed on forms which render this field.
 * @property {string} [hint]              Localizable help text displayed on forms which render this field.
 * @property {string} [placeholder]  Localizable text displayed in placeholders of form inputs which render this field.
 * @property {DataFieldValidator} [validate] A custom data field validation function.
 * @property {string} [validationError]   A custom validation error string. When displayed will be prepended with the
 *                                        document name, field name, and candidate value. This error string is only
 *                                        used when the return type of the validate function is a boolean. If an Error
 *                                        is thrown in the validate function, the string message of that Error is used.
 */

/**
 * @typedef DataFieldContext
 * @property {string} [name]               A field name to assign to the constructed field
 * @property {DataField} [parent]          Another data field which is a hierarchical parent of this one
 */

/**
 * @typedef DataFieldValidationOptions
 * @property {boolean} [partial]   Whether this is a partial schema validation, or a complete one.
 * @property {boolean} [fallback]  Whether to allow replacing invalid values with valid fallbacks.
 * @property {object} [source]     The full source object being evaluated.
 * @property {boolean} [strict=false] Whether to throw a DataModelValidationFailure (true) or simply return it (false)
 * @property {boolean} [dropInvalidEmbedded]  If true, invalid embedded documents will emit a warning and be placed in
 *                                            the invalidDocuments collection rather than causing the parent to be
 *                                            considered invalid.
 * @param {"pre"|"recursive"|"post"} [phase]  A specific validation phase to perform, specifying this is generally
 *                                  only necessary for _updateDiff workflows
 *                                    - "pre" occurs before recursion to child nodes
 *                                    - "recursive" performs recursive validation of child nodes
 *                                    - "post" occurs after validation of child nodes
 * @property {boolean} [recursive=true] When validating a field, also validate its children. This can be explicitly
 *                                  set to false to efficiently validate the outer field without validating its
 *                                  contained values.
 * @property {DataModel} [model]    The DataModel instance the field belongs to
 */

/**
 * @typedef DataModelCleaningOptions
 * @property {boolean} [addTypes=false]   Impute types for polymorphic so that those typed fields can be later used or
 *                                        validated
 * @property {boolean} [copy=true]        Copy the provided input data to avoid mutating the provided source
 * @property {boolean} [expand=true]      Automatically expand any flattened objects encountered during cleaning
 * @property {boolean} [migrate=true]     Apply model-specific data migrations
 * @property {boolean} [model=true]       Apply joint model-level cleaning rules
 * @property {boolean} [partial=false]    Perform partial cleaning only on the subset of keys included in the input
 *                                        data. If partial is `false`, values for keys missing in the input data will be
 *                                        imputed if possible
 * @property {boolean} [prune=true]       Remove keys which do not belong to the defined data schema
 * @property {boolean} [persisted=true]   Remove keys corresponding with non-persisted DataFields.
 * @property {boolean|DataModelSanitizationOptions} [sanitize]  Configuration of user input sanitization steps that are
 *                                        applied as part of cleaning. For internal server-side use only.
 */

/**
 * @typedef DataModelUpdateState
 * @property {boolean} [creation]         Are we in the context of a new model creation?
 * @property {DataModel} [model]          The DataModel instance being cleaned
 * @property {any} [source]               Prior source data at the current node
 * @property {object} [modelSource]       Prior source data at the nearest DataModel root being cleaned
 * @property {boolean} [expanded]         Has source data already been expanded?
 * @property {object} [sanitization]      Metadata resulting from sanitization workflows
 * @property {string} [documentId]        In a Document context, records its _id
 * @property {string} [documentType]      In a Document context, records its base type
 * @property {number} [modifiedTime]      In a ServerDocument context, records the timestamp of modification
 * @property {User} [user]                In a ServerDocument context, records the user performing the operation
 * @property {boolean} [cleanOptions]     Have the {@link DataModelCleaningOptions} been fully populated?
 */

/**
 * @typedef DataModelSanitizationOptions
 * @property {boolean} [creation=false]     Sanitization as part of creation?
 * @property {string} [assetPath]           A file path to which sanitized assets should be persisted to disk
 * @property {boolean} [skipSystem=false]   Skip system sanitization?
 * @property {User} [user]                  The User performing an operation which requires sanitization
 * @property {boolean} [deleteStats=false]  Clean data out of stats?
 */


/**
 * @typedef EmbeddedCollectionUpdateContext
 * @property {object[]} source                      The current source array of the parent collection.
 * @property {object[]} newSource                   The replacement source array, same as source unless replacement.
 * @property {boolean} isReplacement                Whether the requested update is a ForcedReplacement.
 * @property {object[]} diff                        The accumulating diff array of changes.
 * @property {DocumentCollection} collection        The embedded collection on the parent Document.
 * @property {object} state                         The DataModel update state shared with the rest of _updateDiff.
 * @property {DataModelValidationFailure} failure   The collection-level validation failure under construction.
 */

/**
 * @typedef FormGroupConfig
 * @property {string} label                         A text label to apply to the form group
 * @property {string} [units]                       An optional units string which is appended to the label
 * @property {HTMLElement|HTMLCollection} input     An HTML element or collection of elements which provide the inputs
 *                                                  for the group
 * @property {string} [hint]                        Hint text displayed as part of the form group
 * @property {string} [rootId]                      Some parent CSS id within which field names are unique. If provided,
 *                                                  this root ID is used to automatically assign "id" attributes to
 *                                                  input elements and "for" attributes to corresponding labels.
 * @property {string[]} [classes]                   An array of CSS classes applied to the form group element
 * @property {boolean} [stacked=false]              Is the "stacked" class applied to the form group
 * @property {boolean} [localize=false]             Should labels or other elements within this form group be
 *                                                  automatically localized?
 * @property {boolean|"until-found"} [hidden=false] The value of the form group's hidden attribute
 * @property {CustomFormGroup} [widget]             A custom form group widget function which replaces the default
 *                                                  group HTML generation
 */

/**
 * @template [FormInputValue=unknown]
 * @typedef FormInputConfig
 * @property {string} name                        The name of the form element
 * @property {boolean} [named=true]               Whether the element should be named in the form. If false, the element
 *                                                will be given a name via data attribute only.
 * @property {FormInputValue} [value]             The current value of the form element
 * @property {string} [id]                        An id to assign to the element
 * @property {boolean} [required=false]           Is the field required?
 * @property {boolean} [disabled=false]           Is the field disabled?
 * @property {boolean} [readonly=false]           Is the field readonly?
 * @property {boolean} [autofocus=false]          Is the field autofocused?
 * @property {boolean} [localize=false]           Localize values of this field?
 * @property {Record<string, string>} [dataset]   Additional dataset attributes to assign to the input
 * @property {Record<string, string>} [aria]      Aria attributes to assign to the input
 * @property {string} [placeholder]               A placeholder value, if supported by the element type
 * @property {string} [classes]                   Space-delimited class names to apply to the input.
 * @property {string} [rootId]                    Some parent CSS id within which field names are unique. If provided,
 *                                                this root ID is used to automatically assign "id" attributes to
 *                                                input elements and "for" attributes to corresponding labels.
 * @property {CustomFormInput} [input]
 * @property {DataModel} [model]                  The DataModel instance the field belongs to
 */

/**
 * @typedef StringFieldInputConfig
 * @property {"input"|"textarea"|"prose-mirror"|"code-mirror"} [elementType="input"] The element to create for this
 *                                                                                   form field
 */

/** @typedef {"javascript" | "json" | "html" | "markdown" | "" | "plain"} CodeMirrorLanguage */

/**
 * @typedef CodeMirrorInputConfig
 * @property {CodeMirrorLanguage} [language=""] The value's language
 * @property {number} [indent=2] The number of spaces per level of indentation
 */

/**
 * @typedef LightAnimationData
 * @property {string} type          The animation type which is applied
 * @property {number} speed         The speed of the animation, a number between 0 and 10
 * @property {number} intensity     The intensity of the animation, a number between 1 and 10
 * @property {boolean} reverse      Reverse the direction of animation.
 */

/**
 * @typedef _NumberFieldOptions
 * {@ignore}
 * @property {number} [min]               A minimum allowed value
 * @property {number} [max]               A maximum allowed value
 * @property {number} [step]              A permitted step size
 * @property {boolean} [integer=false]    Must the number be an integer?
 * @property {boolean} [positive=false]   Must the number be positive?
 * @property {number[]|object|Function} [choices] An array of values or an object of values/labels which represent
 *                                        allowed choices for the field. A function may be provided which dynamically
 *                                        returns the array of choices.
 */

/**
 * @typedef {DataFieldOptions & _NumberFieldOptions} NumberFieldOptions
 * {@interface}
 */

/**
 * @typedef _StringFieldOptions
 * {@ignore}
 * @property {boolean} [blank=true]       Is the string allowed to be blank (empty)?
 * @property {boolean} [trim=true]        Should any provided string be trimmed as part of cleaning?
 * @property {string[]|object|Function} [choices]  An array of values or an object of values/labels which represent
 *                                        allowed choices for the field. A function may be provided which dynamically
 *                                        returns the array of choices.
 * @property {boolean} [textSearch=false] Is this string field a target for text search?
 */

/**
 * @typedef {DataFieldOptions & _StringFieldOptions} StringFieldOptions
 * {@interface}
 */

/**
 * @typedef ChoiceInputConfig
 * @property {FormSelectOption[]} options
 * @property {Record<string|number, any>|any[]|() => Record<string|number, any>|any[]} choices
 * @property {string} [labelAttr="label"]
 * @property {string} [valueAttr]
 */

/**
 * @typedef _ArrayFieldOptions
 * @property {number} [min]          The minimum number of elements.
 * @property {number} [max]          The maximum number of elements.
 */

/**
 * @typedef {DataFieldOptions & _ArrayFieldOptions} ArrayFieldOptions
 */

/**
 * @callback TypedObjectKeyValidator
 * @param {string} key  The key being validated.
 * @returns {boolean}
 */

/**
 * @typedef _TypedObjectFieldOptions
 * @property {TypedObjectKeyValidator} [validateKey]  A predicate to filter out invalid keys.
 * @property {boolean} [expandKeys]                    Whether to expand dot-delimited keys.
 */

/**
 * @typedef {DataFieldOptions & _TypedObjectFieldOptions} TypedObjectFieldOptions
 */

/**
 * @typedef _DocumentUUIDFieldOptions
 * @property {string} [type]      A specific document type in {@link CONST.ALL_DOCUMENT_TYPES} required by this field
 * @property {boolean} [embedded] Does this field require (or prohibit) embedded documents?
 * @property {boolean} [relative] Does this field allow relative document UUIDs?
 */

/**
 * @typedef {StringFieldOptions & _DocumentUUIDFieldOptions} DocumentUUIDFieldOptions
 */

/**
 * @typedef _FilePathFieldOptions
 * @property {string[]} [categories]    A set of categories in {@link CONST.FILE_CATEGORIES} which this field supports
 * @property {boolean} [base64=false]   Is embedded base64 data supported in lieu of a file path?
 * @property {boolean} [virtual=false]  Does the file path field allow specifying a virtual file path which must begin
 *                                      with the "#" character?
 * @property {boolean} [wildcard=false] Does this file path field allow wildcard characters?
 * @property {object} [initial]         The initial values of the fields
 */

/**
 * @typedef {StringFieldOptions & _FilePathFieldOptions} FilePathFieldOptions
 */

/** @typedef {Record<string, Record<string, unknown>>} DocumentFlags */

/**
 * @typedef DocumentStats
 * @property {string|null} coreVersion       The core version whose schema the Document data is in.
 *                                           It is NOT the version the Document was created or last modified in.
 * @property {string|null} systemId          The package name of the system the Document was created in.
 * @property {string|null} systemVersion     The version of the system the Document was created or last modified in.
 * @property {number|null} createdTime       A timestamp of when the Document was created.
 * @property {number|null} modifiedTime      A timestamp of when the Document was last modified.
 * @property {string|null} lastModifiedBy    The ID of the user who last modified the Document.
 * @property {string|null} compendiumSource  The UUID of the compendium Document this one was imported from.
 * @property {string|null} duplicateSource   The UUID of the Document this one is a duplicate of.
 */

/**
 * @typedef _JavaScriptFieldOptions
 * @property {boolean} [async=false]            Does the field allow async code?
 */

/**
 * @typedef {StringFieldOptions & _JavaScriptFieldOptions} JavaScriptFieldOptions
 */

/**
 * @typedef _GridOffsetFieldOptions
 * {@ignore}
 * @property {2|3} [dimensions]   The dimensions. Default: `2`.
 */

/**
 * @typedef {DataFieldOptions & _GridOffsetFieldOptions} GridOffsetFieldOptions
 * {@interface}
 */

/**
 * @typedef {ArrayFieldOptions & _GridOffsetFieldOptions} GridOffsetsFieldOptions
 * {@interface}
 */
