@league-of-foundry-developers/foundry-vtt-types
Version:
TypeScript type definitions for Foundry VTT
1,245 lines (1,092 loc) • 188 kB
text/typescript
import type {
RemoveIndexSignatures,
SimpleMerge,
AnyObject,
EmptyObject,
NullishProps,
InexactPartial,
FixedInstanceType,
Identity,
PrettifyType,
InterfaceToObject,
AnyArray,
} from "#utils";
import type { DataModel } from "../abstract/data.mts";
import type Document from "../abstract/document.mts";
import type { EmbeddedCollection, EmbeddedCollectionDelta, TypeDataModel } from "../abstract/module.d.mts";
import type { DOCUMENT_OWNERSHIP_LEVELS } from "../constants.d.mts";
import type { CONST } from "../../client-esm/client.d.mts";
import type { DataModelValidationFailure } from "./validation-failure.mts";
import type {
FormGroupConfig,
FormInputConfig,
FormSelectOption,
MultiSelectInputConfig,
SelectInputConfig,
TextAreaInputConfig,
} from "../../client-esm/applications/forms/fields.d.mts";
export type DataSchema = Record<string, DataField.Any>;
/**
* An abstract class that defines the base pattern for a data field within a data schema.
* @typeParam Options - the options of the DataField instance
* @typeParam AssignmentType - the type of the allowed assignment values of the DataField
* @typeParam InitializedType - the type of the initialized values of the DataField
* @typeParam PersistedType - the type of the persisted values of the DataField
* @remarks
* Defaults:
* - AssignmentType: `unknown | null | undefined`
* - InitializedType: `unknown | undefined`
* - PersistedType: `unknown | undefined`
* - InitialValue: `undefined`
*/
declare abstract class DataField<
const Options extends DataField.Options.Any = DataField.DefaultOptions,
const AssignmentType = DataField.AssignmentType<Options>,
const InitializedType = DataField.InitializedType<Options>,
const PersistedType = InitializedType,
> {
// Prevent from being bivariant.
#assignmentType: AssignmentType;
/**
* @param options - Options which configure the behavior of the field
* @param context - Additional context which describes the field
*/
// options: not null (unchecked `in` operation), context: not null (destructured)
constructor(options?: Options, context?: DataField.ConstructionContext);
/** @internal */
" __fvtt_types_internal_source_data": PersistedType;
/** @internal */
" __fvtt_types_internal_assignment_data": AssignmentType;
/** @internal */
" __fvtt_types_internal_initialized_data": InitializedType;
/** The initially provided options which configure the data field */
options: Options;
/**
* Is this field required to be populated?
* @defaultValue `false`
*/
required: boolean;
/**
* Can this field have null values?
* @defaultValue `false`
*/
nullable: boolean;
/**
* Can this field only be modified by a gamemaster or assistant gamemaster?
* @defaultValue `false`
*/
gmOnly: boolean;
/**
* The initial value of a field, or a function which assigns that initial value.
* @defaultValue `undefined`
*/
initial: DataField.Options.InitialType<InitializedType>;
/**
* Should the prepared value of the field be read-only, preventing it from being
* changed unless a change to the _source data is applied.
* @defaultValue `false`
*/
readonly: boolean;
/**
* A localizable label displayed on forms which render this field.
* @defaultValue `""`
*/
label: string;
/**
* Localizable help text displayed on forms which render this field.
* @defaultValue `""`
*/
hint: string;
/**
* 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.
* @defaultValue `"is not a valid value"`
*/
validationError: string;
/**
* The name of this data field within the schema that contains it
*
* The field name of this DataField instance.
* This is assigned by SchemaField#initialize.
* @remarks Foundry marked `@internal`
*/
name: string | undefined;
/**
* A reference to the parent schema to which this DataField belongs.
* This is assigned by SchemaField#initialize.
* @remarks Foundry marked `@internal`
*/
parent: DataField.Any | undefined;
/**
* Whether this field defines part of a Document/Embedded Document hierarchy.
* @defaultValue `false`
*/
static hierarchical: boolean;
/**
* Does this field type contain other fields in a recursive structure?
* Examples of recursive fields are SchemaField, ArrayField, or TypeDataField
* Examples of non-recursive fields are StringField, NumberField, or ObjectField
* @defaultValue `false`
*/
static recursive: boolean;
/**
* Default parameters for this field type
* @remarks This is not entirely type-safe, overrides should specify a more concrete return type.
*/
protected static get _defaults(): DataField.Options.Any;
/**
* A dot-separated string representation of the field path within the parent schema.
* @remarks Returns `""` if both `this.parent?.fieldPath` and `this.name` are falsey
*/
get fieldPath(): string;
/**
* Apply a function to this DataField which propagates through recursively to any contained data schema.
* @param fn - The function to apply
* @param value - The current value of this field
* @param options - Additional options passed to the applied function (default `{}`)
* @returns The results object
*/
// TODO: Determine `value` based upon the field metadata in fields-v2 (while allowing subclasses to narrow allowed values)
// options: not null (could be forwarded somewhere destructured, parameter default only)
apply<Options, Return>(
fn: keyof this | ((this: this, value: unknown, options: Options) => Return),
value?: unknown,
options?: Options,
): Return;
/**
* Coerce source data to ensure that it conforms to the correct data type for the field.
* Data coercion operations should be simple and synchronous as these are applied whenever a DataModel is constructed.
* For one-off cleaning of user-provided input the sanitize method should be used.
* @param value - The initial value
* @param options - Additional options for how the field is cleaned
* @returns The cast value
*/
// options: not null (parameter default only, property access)
clean(value: AssignmentType, options?: DataField.CleanOptions): InitializedType;
/**
* Apply any cleaning logic specific to this DataField type.
* @param value - The appropriately coerced value.
* @param options - Additional options for how the field is cleaned.
* @returns The cleaned value.
* @remarks Simply returns `value` in `DataField`. `options` is unused in `DataField`
*/
protected _cleanType(value: InitializedType, options?: DataField.CleanOptions | null): InitializedType;
/**
* Cast a non-default value to ensure it is the correct type for the field
* @param value - The provided non-default value
* @returns The standardized value
*/
protected abstract _cast(value: AssignmentType): InitializedType;
/**
* Attempt to retrieve a valid initial value for the DataField.
* @param data - The source data object for which an initial value is required
* @returns A valid initial value
* @throws An error if there is no valid initial value defined
* @remarks The `@throws` is Foundry's, and is wrong, as all fields will at a minimum inherit `initial: undefined` from DataField.
*
* `data` is unused if the field's `initial` is not a function.
*/
// TODO: the @throws is omitted in v13, clean up remarks
getInitialValue(data?: unknown): InitializedType;
/**
* Validate a candidate input for this field, ensuring it meets the field requirements.
* A validation failure can be provided as a raised Error (with a string message), by returning false, or by returning
* a DataModelValidationFailure instance.
* A validator which returns true denotes that the result is certainly valid and further validations are unnecessary.
* @param value - The initial value
* @param options - Options which affect validation behavior
* (default: `{}`)
* @returns Returns a ModelValidationError if a validation failure occurred
*/
// options: not null (parameter default only, property access)
validate(value: AssignmentType, options?: DataField.ValidateOptions<this>): DataModelValidationFailure | void;
/**
* Special validation rules which supersede regular field validation.
* This validator screens for certain values which are otherwise incompatible with this field like null or undefined.
* @param value - The candidate value
* @returns A boolean to indicate with certainty whether the value is valid.
* Otherwise, return void.
* @throws May throw a specific error if the value is not valid
*/
protected _validateSpecial(value: AssignmentType): boolean | void;
/**
* A default type-specific validator that can be overridden by child classes
* @param value - The candidate value
* @param options - Options which affect validation behavior
* @returns A boolean to indicate with certainty whether the value is
* valid, or specific DataModelValidationFailure information,
* otherwise void.
* @throws May throw a specific error if the value is not valid
*/
// options: not null (parameter default only, property access in subclasses)
protected _validateType(
value: InitializedType,
options?: DataField.ValidateOptions<this>,
): boolean | DataModelValidationFailure | void;
/**
* Certain fields may declare joint data validation criteria.
* This method will only be called if the field is designated as recursive.
* @param data - Candidate data for joint model validation
* @param options - Options which modify joint model validation
* @throws An error if joint model validation fails
* @remarks Foundry marked `@internal`
*
* The only place core checks the `options` for any property is in {@link TypeDataField._validateModel | `TypeDataField#_validateModel`},
* where it checks `options.source?.type`
*
* {@link SchemaField._validateModel | `SchemaField._validateModel`} enforces `source`'s existence for subsidiary calls
*
* The only place core *calls* this at a top level, it does not pass anything for `options`, relying on SchemaField above
* to make TypeDataField work
*/
protected _validateModel(data: AnyObject, options?: DataField.ValidateModelOptions | null): void; // TODO: Type further.
/**
* Initialize the original source data into a mutable copy for the DataModel instance.
* @param value - The source value of the field
* @param model - The DataModel instance that this field belongs to
* @param options - Initialization options
* @returns An initialized copy of the source data
* @remarks Core fields that return a function:
* - {@link ForeignDocumentField | `ForeignDocumentField`}
* - `ActorDeltaField` (exported in the BaseToken file but not re-exported by the relevant `_module`, so unlinkable)
*/
// TODO: investigate narrowing return to just `InitializedType` on inheritance lines that don't possibly return one
// TODO: (everything except SchemaField and ObjectField and their descendants)
// options: not null (parameter default only)
initialize(
value: PersistedType,
model: DataModel.Any,
options?: DataField.InitializeOptions,
): InitializedType | (() => InitializedType | null);
/**
* Export the current value of the field into a serializable object.
* @param value - The initialized value of the field
* @returns An exported representation of the field
*/
toObject(value: InitializedType): PersistedType;
/**
* Recursively traverse a schema and retrieve a field specification by a given path
* @param path - The field path as an array of strings
*/
protected _getField(path: string[]): DataField.Any | undefined;
/**
* Does this form field class have defined form support?
*/
static get hasFormSupport(): boolean;
/**
* Render this DataField as an HTML element.
* @param config - Form element configuration parameters
* @throws An Error if this DataField subclass does not support input rendering
* @returns A rendered HTMLElement for the field
*/
toInput(config?: DataField.ToInputConfig<InitializedType>): HTMLElement | HTMLCollection;
/**
* Render this DataField as an HTML element.
* Subclasses should implement this method rather than the public toInput method which wraps it.
* @param config - Form element configuration parameters
* @throws An Error if this DataField subclass does not support input rendering
* @returns A rendered HTMLElement for the field
*/
protected _toInput(config: DataField.ToInputConfig<InitializedType>): HTMLElement | HTMLCollection;
/**
* Render this DataField as a standardized form-group element.
* @param groupConfig - Configuration options passed to the wrapping form-group
* @param inputConfig - Input element configuration options passed to DataField#toInput
* @returns The rendered form group element
*/
toFormGroup(
groupConfig?: DataField.GroupConfig,
inputConfig?: DataField.ToInputConfig<InitializedType>,
): HTMLDivElement;
/**
* Apply an ActiveEffectChange to this field.
* @param value - The field's current value.
* @param model - The model instance.
* @param change - The change to apply.
* @returns The updated value.
*/
applyChange(value: InitializedType, model: DataModel.Any, change: ActiveEffect.EffectChangeData): InitializedType;
/**
* Cast a change delta into an appropriate type to be applied to this field.
* @param delta - The change delta.
* @internal
*/
// Note(LukeAbby): Technically since this defers to `_cast` it should take whatever `_cast` can.
// But it always must be able to take a `string` because that's how `applyChange` calls it.
protected _castChangeDelta(delta: string): InitializedType;
/**
* Apply an ADD change to this field.
* @param value - The field's current value.
* @param delta - The change delta.
* @param model - The model instance.
* @param change - The original change data.
* @returns - The updated value.
*
* @remarks Returns `value + delta`. `model` and `change` are unused in `DataField`
*/
protected _applyChangeAdd(
value: InitializedType,
delta: InitializedType,
model: DataModel.Any,
change: ActiveEffect.EffectChangeData,
): InitializedType;
/**
* Apply a MULTIPLY change to this field.
* @param value - The field's current value.
* @param delta - The change delta.
* @param model - The model instance.
* @param change - The original change data.
* @returns The updated value.
*
* @remarks No-op in `DataField`, returns `undefined` unless overridden
*/
protected _applyChangeMultiply(
value: InitializedType,
delta: InitializedType,
model: DataModel.Any,
change: ActiveEffect.EffectChangeData,
): InitializedType | undefined;
/**
* Apply an OVERRIDE change to this field.
* @param value - The field's current value.
* @param delta - The change delta.
* @param model - The model instance.
* @param change - The original change data.
* @returns The updated value.
*
* @returns Simply returns `delta`. `value`, `model`, and `change` are unused in `DataField`
*/
protected _applyChangeOverride(
value: InitializedType,
delta: InitializedType,
model: DataModel.Any,
change: ActiveEffect.EffectChangeData,
): InitializedType;
/**
* Apply an UPGRADE change to this field.
* @param value - The field's current value.
* @param delta - The change delta.
* @param model - The model instance.
* @param change - The original change data.
* @returns - The updated value.
*
* @remarks No-op in `DataField`, returns `undefined` unless overridden
*/
protected _applyChangeUpgrade(
value: InitializedType,
delta: InitializedType,
model: DataModel.Any,
change: ActiveEffect.EffectChangeData,
): InitializedType | undefined;
/**
* Apply a DOWNGRADE change to this field.
* @param value - The field's current value.
* @param delta - The change delta.
* @param model - The model instance.
* @param change - The original change data.
* @returns The updated value.
*
* @remarks No-op in `DataField`, returns `undefined` unless overridden
*/
protected _applyChangeDowngrade(
value: InitializedType,
delta: InitializedType,
model: DataModel.Any,
change: ActiveEffect.EffectChangeData,
): InitializedType | undefined;
/**
* Apply a CUSTOM change to this field.
* @param value - The field's current value.
* @param delta - The change delta.
* @param model - The model instance.
* @param change - The original change data.
* @returns - The updated value.
* @remarks Only returns a value if the target value of the change actually changed
*/
protected _applyChangeCustom(
value: InitializedType,
delta: InitializedType,
model: DataModel.Any,
change: ActiveEffect.EffectChangeData,
): InitializedType | undefined;
}
declare namespace DataField {
/** Any DataField. */
interface Any extends AnyDataField {}
interface AnyConstructor extends Identity<typeof AnyDataField> {}
/** A DataField with unknown inner types. */
type Unknown = DataField<any, unknown, unknown, unknown>;
type AssignmentTypeFor<ConcreteDataField extends Any> =
ConcreteDataField extends DataField<any, infer AssignmentType, any, any> ? AssignmentType : never;
type InitializedTypeFor<ConcreteDataField extends Any> =
ConcreteDataField extends DataField<any, any, infer InitializedType, any> ? InitializedType : never;
type PersistedTypeFor<ConcreteDataField extends Any> =
ConcreteDataField extends DataField<any, any, any, infer PersistedType> ? PersistedType : never;
/** The type of the default options for the {@link DataField | `DataField`} class. */
interface DefaultOptions {
required: false;
nullable: false;
initial: undefined;
readonly: false;
gmOnly: false;
label: "";
hint: "";
validationError: "is not a valid value";
}
interface Options<BaseAssignmentType> {
/**
* Is this field required to be populated?
* @defaultValue `false`
*/
required?: boolean | undefined;
/**
* Can this field have null values?
* @defaultValue `false`
*/
nullable?: boolean | undefined;
/**
* Can this field only be modified by a gamemaster or assistant gamemaster?
* @defaultValue `false`
*/
gmOnly?: boolean | undefined;
/** The initial value of a field, or a function which assigns that initial value. */
initial?:
| DataField.Options.InitialType<
// TODO(LukeAbby): Add a `ValidateOptions` type or something of that sort in order to
// catch incorrect initial types.
DataField.Options.InitialReturnType<BaseAssignmentType, boolean, boolean>
>
| undefined;
/** A data validation function which accepts one argument with the current value. */
validate?: DataField.Validator<DataField.Any, BaseAssignmentType> | undefined;
/** A localizable label displayed on forms which render this field. */
label?: string | undefined;
/** Localizable help text displayed on forms which render this field. */
hint?: string | undefined;
/**
* 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.
*/
validationError?: string | undefined;
}
namespace Options {
/** Any DataField.Options. */
// Note(LukeAbby): This `& object` is intentional. Its purpose is to allow options like `{ integer: true }` to be assigned.
// This is an issue because `{ integer: true }` does not extend `{ required?: boolean }` because they have no properties in common.
// Even though `{ integer: true, required: undefined }` would extend `{ required?: boolean }` following the regular rules of surplus properties being allowed.
// `object` was chosen over `AnyObject` so that people may pass in interfaces.
interface Any extends DataField.Options<any>, Identity<object> {}
/**
* A helper type for the {@link DataField.Options.initial | `DataField.Options.initial`} option.
* @typeParam ReturnType - the return type of the option
*/
type InitialType<ReturnType> = ReturnType | ((initialData: unknown) => ReturnType);
/**
* The decorated return type for the {@link DataField.Options.initial | `DataField.Options.initial`} option.
* @typeParam BaseAssignmentType - the base assignment type for a DataField
* @typeParam NullableOption - the value of the nullable option
* @typeParam RequiredOption - the value of the required option
*/
type InitialReturnType<BaseAssignmentType, NullableOption, RequiredOption> =
| Exclude<BaseAssignmentType, null | undefined>
| (NullableOption extends true ? null : never)
| (RequiredOption extends true ? never : undefined);
}
/**
* A helper type for the given options type merged into the default options of the DataField class.
* @typeParam Options - the options that override the default options
*/
type MergedOptions<Options extends DataField.Options.Any> = SimpleMerge<DefaultOptions, Options>;
/**
* A type to decorate the base assignment type to a DataField, based on the options of the field.
* @typeParam BaseAssignmentType - the base assignment type of the DataField, without null or undefined
* @typeParam Options - the options of the DataField
*/
type DerivedAssignmentType<BaseAssignmentType, Options extends DataField.Options.Any> =
| Exclude<BaseAssignmentType, null | undefined> // Always include the base type
| (Options["nullable"] extends true // determine whether null is in the union
? // when nullable, null is always allowed
null
: // otherwise, it depends on required
Options["required"] extends true
? // when required and not nullable, null can only be passed when initial is present
"initial" extends keyof Options
? // when initial is present, null can be passed
null
: // when initial is not in the options, then null can not be passed
never
: // when not required, null can safely be passed
null)
| (Options["required"] extends true // determine whether undefined is in the union
? // when required, it depends on initial
"initial" extends keyof Options
? // when initial is in the options, undefined is allowed
undefined
: // when initial is not in the options, then undefined is not allowed
never
: // when not required, undefined can safely be passed
undefined);
/**
* A type to decorate the base initialized type of a DataField, based on the options of the field.
* @typeParam BaseInitializedType - the base initialized type of the DataField, without null or undefined
* @typeParam Options - the options of the DataField
*/
type DerivedInitializedType<BaseInitializedType, Options extends DataField.Options.Any> =
| Exclude<BaseInitializedType, null | undefined>
| (Options["nullable"] extends true ? null : never)
| (Options["required"] extends true ? never : undefined);
/**
* A shorthand for the assignment type of a DataField class.
* @typeParam Options - the options overriding the defaults
*/
type AssignmentType<Options extends DataField.Options.Any> = DerivedAssignmentType<any, MergedOptions<Options>>;
/**
* A shorthand for the initialized type of a DataField class.
* @typeParam Options - the options overriding the defaults
*/
type InitializedType<Options extends DataField.Options.Any> = DerivedInitializedType<any, MergedOptions<Options>>;
/** @internal */
type _ConstructionContext = NullishProps<{
/** A field name to assign to the constructed field */
name?: string;
}> &
InexactPartial<{
/**
* Another data field which is a hierarchical parent of this one
* @remarks Can't be `null` as there's a `!== undefined` check in {@link SchemaField._initialize | `SchemaField#_initialize`}
*/
parent?: DataField.Any;
}>;
interface ConstructionContext extends _ConstructionContext {}
/** @internal */
type _ValidationOptions = NullishProps<{
/** Whether this is a partial schema validation, or a complete one. */
partial: boolean;
/** Whether to allow replacing invalid values with valid fallbacks. */
fallback: boolean;
/**
* 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.
*/
dropInvalidEmbedded?: boolean;
}> &
InexactPartial<{
/**
* The full source object being evaluated.
* @privateRemarks Disallowing `null` as this value gets passed to provided `initial` functions,
* and users shouldn't have to expect `null`
*/
source: AnyObject;
}>;
/**
* @remarks This is the type for the options for `#validate` and associate methods *without* the
* possible inclusion of a `validator` function.
*
* If you are looking for the type with a generic formerly under this name, see {@link ValidateOptions | `DataField.ValidateOptions`}
*/
interface ValidationOptions extends _ValidationOptions {}
/**
* @deprecated Use {@link ValidateOptions | `DataField.ValidationOptions`} instead if you need a direct replacement,
* or {@link ValidateOptions | `DataField.ValidateOptions`} if you're typing the options of `#validate` or an associated
* method.
*/
interface DataValidationOptions extends ValidationOptions {}
/** @internal */
type _CleanOptions = NullishProps<{
/** Whether to perform partial cleaning? */
partial: boolean;
/** The root data model being cleaned */
source: AnyObject;
}>;
/** An interface for the options of {@link DataField.clean | `DataField#clean`} and {@link DataField._cleanType | `DataField#_cleanType`}. */
interface CleanOptions extends _CleanOptions {}
/**
* @remarks The only place core checks the `options` for any property is in {@link TypeDataField._validateModel | `TypeDataField#_validateModel`},
* where it checks `options.source?.type`
*
* {@link SchemaField._validateModel | `SchemaField._validateModel`} enforces `source`'s existence for subsidiary calls
*
* The only place core *calls* this at a top level, it does not pass anything for `options`, relying on SchemaField above
* to make TypeDataField work
*/
interface ValidateModelOptions extends Pick<ValidationOptions, "source"> {}
/**
* 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.
*/
type Validator<CurrentField extends DataField.Any, BaseAssignmentType> =
| {
validate(
this: CurrentField,
value: unknown,
options: ValidateOptions<CurrentField>,
): value is BaseAssignmentType;
}["validate"]
| {
validate(
this: CurrentField,
value: unknown,
options: ValidateOptions<CurrentField>,
): asserts value is BaseAssignmentType;
}["validate"]
| {
validate(
this: CurrentField,
value: unknown,
options: ValidateOptions<CurrentField>,
): DataModelValidationFailure | boolean | void;
}["validate"];
/**
* An interface for the options of the {@link DataField | `DataField`} validation functions.
* @typeParam CurrentField - the type of the DataField, which is the receiver of the validate function
*/
interface ValidateOptions<CurrentField extends DataField.Any> extends ValidationOptions {
/**
* @remarks If {@link DataField.validate | `DataField#validate`} is called with a `validate: someFunc` in its `options`,
* it will then pass that `options` object on to that function when it calls it, without alteration.
* Nothing in core makes use of the fact that a reference to the function is available, this seems incidental.
*/
validate?: Validator<CurrentField, DataField.AssignmentTypeFor<CurrentField>>;
}
/**
* @remarks The `options` passed to {@link DataField.initialize | `DataField#initialize`} exclusively (in core) come from
* {@link DataModel._initialize | `DataModel#_initialize`} or an override (meaning `parent` has been stripped from the
* interface), and eventually hits one of:
* 1. Document construction, in all cases with `parent` already provided
* 2. Gets fed back {@link DataModel._initialize | `DataModel#_initialize`} or an override
* 3. {@link Document.get | `Document.get`}, but the one place this happens, `pack` is already provided, and that's the only
* option that method cares about.
*
* This extends the `Document` interface because several core fields use the `pack` property, which isn't available on the
* `DataModel` interface
*/
interface InitializeOptions extends Document.InitializeOptions {}
interface ToInputConfig<InitializedType> extends FormInputConfig<InitializedType> {}
interface ToInputConfigWithOptions<InitializedType> extends FormInputConfig<InitializedType>, SelectInputConfig {}
type AnyChoices = StringField.Choices | NumberField.Choices;
type ToInputConfigWithChoices<InitializedType, Choices extends AnyChoices | undefined> = SimpleMerge<
Omit<ToInputConfigWithOptions<InitializedType>, "options">,
Choices extends undefined ? StringField.GetChoicesOptions : NullishProps<StringField.GetChoicesOptions, "choices">
>;
type SelectableToInputConfig<InitializedType, Choices extends StringField.Choices | undefined> =
| ToInputConfig<InitializedType>
| ToInputConfigWithOptions<InitializedType>
| ToInputConfigWithChoices<InitializedType, Choices>;
// `DataField#toFormGroup` provides default values for these by way of `??=`.
interface GroupConfig extends NullishProps<FormGroupConfig, "label" | "hint" | "input"> {}
}
declare abstract class AnyDataField extends DataField<any, any, any, any> {
constructor(...args: never);
}
/**
* A special class of {@link DataField | `DataField`} which defines a data schema.
* @typeParam Fields - the DataSchema fields of the SchemaField
* @typeParam Options - the options of the SchemaField instance
* @typeParam AssignmentType - the type of the allowed assignment values of the SchemaField
* @typeParam InitializedType - the type of the initialized values of the SchemaField
* @typeParam PersistedType - the type of the persisted values of the SchemaField
* @remarks
* Defaults:
* - AssignmentType: `SchemaField.AssignmentType<Fields> | null | undefined`
* - InitializedType: `SchemaField.InitializedType<Fields>`
* - PersistedType: `SchemaField.PersistedType<Fields>`
*/
declare class SchemaField<
Fields extends DataSchema,
Options extends SchemaField.Options<Fields> = SchemaField.DefaultOptions,
AssignmentType = SchemaField.Internal.AssignmentType<Fields, SimpleMerge<Options, SchemaField.DefaultOptions>>,
InitializedType = SchemaField.Internal.InitializedType<Fields, SimpleMerge<Options, SchemaField.DefaultOptions>>,
PersistedType extends AnyObject | null | undefined = SchemaField.Internal.PersistedType<
Fields,
SimpleMerge<Options, SchemaField.DefaultOptions>
>,
> extends DataField<Options, AssignmentType, InitializedType, PersistedType> {
/**
* @param fields - The contained field definitions
* @param options - Options which configure the behavior of the field
* @param context - Additional context which describes the field
*/
// Saying `fields: Fields` here causes the inference for the fields to be unnecessarily widened. This might effectively be a no-op but it fixes the inference.
// options: not null (unchecked `in` operation in super), context: not null (destructured in super)
constructor(fields: { [K in keyof Fields]: Fields[K] }, options?: Options, context?: DataField.ConstructionContext);
/** @defaultValue `true` */
override required: boolean;
/** @defaultValue `false` */
override nullable: boolean;
/** @defaultValue `() => this.clean({})` */
override initial: DataField.Options.InitialType<InitializedType>;
protected static override get _defaults(): SchemaField.Options<DataSchema>;
/** @defaultValue `true` */
static override recursive: boolean;
/**
* The contained field definitions.
*/
fields: Fields;
/**
* Initialize and validate the structure of the provided field definitions.
* @param fields - The provided field definitions
* @returns The validated schema
*/
protected _initialize(fields: Fields): Fields;
/**
* Iterate over a SchemaField by iterating over its fields.
*/
[Symbol.iterator](): Generator<DataField.Unknown>;
// TODO: see if its viable to narrow keys, values, entries, has, and get's types via the schema
/**
* An array of field names which are present in the schema.
*/
keys(): string[];
/**
* An array of DataField instances which are present in the schema.
*/
values(): DataField.Unknown[];
/**
* An array of [name, DataField] tuples which define the schema.
*/
entries(): [name: string, dataField: DataField.Unknown][];
/**
* Test whether a certain field name belongs to this schema definition.
* @param fieldName - The field name
* @returns Does the named field exist in this schema?
*/
has(fieldName: string): boolean;
/**
* Get a DataField instance from the schema by name
* @param fieldName - The field name
* @returns The DataField instance or undefined
*/
get(fieldName: string): DataField.Unknown | undefined;
/**
* Traverse the schema, obtaining the DataField definition for a particular field.
* @param fieldName - A field path like ["abilities", "strength"] or "abilities.strength"
* @returns The corresponding DataField definition for that field, or undefined
*/
getField(fieldName: string | string[]): DataField.Unknown | undefined;
protected override _getField(path: string[]): DataField.Any;
protected override _cast(value: AssignmentType): InitializedType;
/**
* @remarks Ensures `options.source` is set via effectively `||= data`, then forwards to each field's `#clean`
*
* Deletes any keys from `value` not in the schema
*/
// options: not null (parameter default only, property access)
protected override _cleanType(value: InitializedType, options?: DataField.CleanOptions): InitializedType;
// options: not null (parameter default only)
override initialize(
value: PersistedType,
model: DataModel.Any,
options?: DataField.InitializeOptions,
): InitializedType | (() => InitializedType | null);
// options: not null (parameter default only, property access)
protected override _validateType(
value: InitializedType,
options?: DataField.ValidateOptions<this>,
): boolean | DataModelValidationFailure | void;
// options: not null (parameter default only, property access)
protected override _validateModel(data: AnyObject, options?: DataField.ValidateModelOptions): void;
override toObject(value: InitializedType): PersistedType;
// options: not null (could be forwarded somewhere destructured, parameter default only)
override apply<Options, Return>(
fn: keyof this | ((this: this, value: AnyObject, options: Options) => Return),
value?: AnyObject,
options?: Options,
): Return;
/**
* Migrate this field's candidate source data.
* @param sourceData - Candidate source data of the root model
* @param fieldData - The value of this field within the source data
*/
migrateSource(sourceData: AnyObject, fieldData: unknown): unknown;
}
// FIXME(LukeAbby): This is a quick patch that avoids issues with the fact that the `initial` in `SchemaField` is not actually assignable to its assignment type etc.
// This will be superseded once proper field treatment is applied.
declare const __SchemaFieldInitialSymbol: unique symbol;
type __SchemaFieldInitial = typeof __SchemaFieldInitialSymbol;
declare namespace SchemaField {
/**
* A shorthand for the options of a SchemaField class.
* @typeParam Fields - the DataSchema fields of the SchemaField
*/
type Options<Fields extends DataSchema> = DataField.Options<AssignmentData<Fields> | __SchemaFieldInitial>;
/** Any SchemaField. */
interface Any extends SchemaField<any, any, any, any, any> {}
/**
* Get the constructor type for the given DataSchema.
* @typeParam Fields - the DataSchema fields of the SchemaField
*/
// Note(LukeAbby): Currently this is identical to the assignment type. The intent is to make this
// More accurate in the future, e.g. requiring some requisite properties.
type CreateData<Fields extends DataSchema> = AssignmentData<Fields>;
/**
* Get the inner assignment type for the given DataSchema.
* @typeParam Fields - the DataSchema fields of the SchemaField
*/
type AssignmentData<Fields extends DataSchema> = PrettifyType<
RemoveIndexSignatures<{
[Key in keyof Fields]?: Fields[Key] extends EmbeddedDataField<any, any, infer AssignmentType, any, any>
? AssignmentType
: Fields[Key] extends SchemaField<infer SubSchema, any, any, any, any>
? // FIXME(LukeAbby): This is a quick hack into AssignmentData that assumes that the `initial` of `SchemaField` is not changed from the default of `{}`
// This will be fixed with the refactoring of the types
EmptyObject extends AssignmentData<SubSchema>
? AssignmentData<SubSchema> | undefined | null
: AssignmentData<SubSchema>
: Fields[Key] extends DataField<any, infer AssignType, any, any>
? AssignType
: never;
}>
>;
/**
* The required type of data used when updating a document.
* @typeParam Fields - the DataSchema fields of the SchemaField
*/
// Note(LukeAbby): Currently this is identical to `AssignmentData` but the intent is to make it
// more accurate in the future.
type UpdateData<Fields extends DataSchema> = AssignmentData<Fields>;
/**
* Gets the initialized version of a schema. This means a
* @typeParam Fields - the DataSchema fields of the SchemaField
*/
type InitializedData<Fields extends DataSchema> = PrettifyType<
RemoveIndexSignatures<{
[Key in keyof Fields]: Fields[Key] extends EmbeddedDataField<infer Model, any, any, any, any>
? FixedInstanceType<Model>
: Fields[Key] extends SchemaField<infer SubSchema, any, any, any, any>
? InitializedData<SubSchema>
: Fields[Key] extends DataField<any, any, infer InitType, any>
? InitType
: never;
}>
>;
/**
* @deprecated {@link SourceData | `SourceData`}
*/
type PersistedData<Fields extends DataSchema> = SourceData<Fields>;
/**
* Get the persisted type for the given DataSchema. This is the type used for source.
* @typeParam Fields - the DataSchema fields of the SchemaField
*/
type SourceData<Fields extends DataSchema> = PrettifyType<
RemoveIndexSignatures<{
[Key in keyof Fields]: Fields[Key] extends EmbeddedDataField<any, any, any, any, infer PersistType>
? PersistType
: Fields[Key] extends SchemaField<infer SubSchema, any, any, any, any>
? SourceData<SubSchema>
: Fields[Key] extends DataField<any, any, any, infer PersistType>
? PersistType
: never;
}>
>;
type UpdateSourceData<Fields extends DataSchema> = PrettifyType<
RemoveIndexSignatures<{
[Key in keyof Fields]: Fields[Key] extends EmbeddedDataField<any, any, any, any, infer PersistType>
? PersistType
: Fields[Key] extends SchemaField<infer SubSchema, any, any, any, any>
? SourceData<SubSchema>
: Fields[Key] extends DataField<any, any, any, infer PersistType>
? PersistType
: never;
}>
>;
/** The type of the default options for the {@link SchemaField | `SchemaField`} class. */
type DefaultOptions = SimpleMerge<
DataField.DefaultOptions,
{
required: true;
nullable: false;
initial: __SchemaFieldInitial;
}
>;
/**
* A helper type for the given options type merged into the default options of the SchemaField class.
* @typeParam Fields - the DataSchema fields of the SchemaField
* @typeParam Opts - the options that override the default options
*/
type MergedOptions<Fields extends DataSchema, Opts extends Options<Fields>> = SimpleMerge<DefaultOptions, Opts>;
// These exist for calculating the type of schema field with options.
// This will be deleted once fields are refactored.
// The names are also confusing. Hence these it's put into `Internal.
namespace Internal {
// FIXME: null or undefined should be permissible, cast as the initialized type
/**
* A shorthand for the assignment type of a SchemaField class.
* @typeParam Fields - the DataSchema fields of the SchemaField
* @typeParam Opts - the options that override the default options
*/
type AssignmentType<
Fields extends DataSchema,
Opts extends Options<Fields> = DefaultOptions,
> = DataField.DerivedAssignmentType<AssignmentData<Fields>, MergedOptions<Fields, Opts>>;
/**
* A shorthand for the assignment type of a SchemaField class.
* @typeParam Fields - the DataSchema fields of the SchemaField
* @typeParam Opts - the options that override the default options
*/
type InitializedType<
Fields extends DataSchema,
Opts extends Options<Fields> = DefaultOptions,
> = DataField.DerivedInitializedType<InitializedData<Fields>, MergedOptions<Fields, Opts>>;
/**
* A shorthand for the assignment type of a SchemaField class.
* @typeParam Fields - the DataSchema fields of the SchemaField
* @typeParam Opts - the options that override the default options
*/
type PersistedType<
Fields extends DataSchema,
Opts extends Options<Fields> = DefaultOptions,
> = DataField.DerivedInitializedType<SourceData<Fields>, MergedOptions<Fields, Opts>>;
}
/**
* This is deprecated because of likely confusion between `SchemaField.AssignmentData` and `SchemaField.AssignmentType`.
* @deprecated {@link SchemaField.Internal.AssignmentType | `SchemaField.Internal.AssignmentType`}
*/
type AssignmentType<
Fields extends DataSchema,
Opts extends Options<Fields> = DefaultOptions,
> = Internal.AssignmentType<Fields, Opts>;
/**
* This is deprecated because of likely confusion between `SchemaField.InitializedData` and `SchemaField.InitializedType`.
* @deprecated {@link SchemaField.Internal.InitializedType | `SchemaField.Internal.InitializedType`}
*/
type InitializedType<
Fields extends DataSchema,
Opts extends Options<Fields> = DefaultOptions,
> = Internal.InitializedType<Fields, Opts>;
/**
* This is deprecated because of likely confusion between `SchemaField.PersistedData` and `SchemaField.PersistedType`.
* @deprecated {@link SchemaField.Internal.PersistedType | `SchemaField.Internal.PersistedType`}
*/
type PersistedType<Fields extends DataSchema, Opts extends Options<Fields> = DefaultOptions> = Internal.PersistedType<
Fields,
Opts
>;
/**
* @deprecated {@link SchemaField.CreateData | `SchemaField.CreateData`}
*/
type InnerConstructorType<Fields extends DataSchema> = CreateData<Fields>;
/**
* @deprecated {@link SchemaField.AssignmentData | `SchemaField.AssignmentData`}
*/
type InnerAssignmentType<Fields extends DataSchema> = AssignmentData<Fields>;
/**
* @deprecated {@link SchemaField.InitializedData | `SchemaField.InitializedData`}
*/
type InnerInitializedType<Fields extends DataSchema> = InitializedData<Fields>;
/**
* @deprecated {@link SchemaField.UpdateData | `SchemaField.UpdateData`}
*/
type InnerUpdateData<Fields extends DataSchema> = UpdateData<Fields>;
/**
* @deprecated {@link SchemaField.SourceData | `SchemaField.SourceData`}
*/
type InnerPersistedType<Fields extends DataSchema> = SourceData<Fields>;
}
/**
* A subclass of {@link DataField | `DataField`} which deals with boolean-typed data.
* @typeParam Options - the options of the BooleanField instance
* @typeParam AssignmentType - the type of the allowed assignment values of the BooleanField
* @typeParam InitializedType - the type of the initialized values of the BooleanField
* @typeParam PersistedType - the type of the persisted values of the BooleanField
* @remarks
* Defaults:
* - AssignmentType: `boolean | null | undefined`
* - InitializedType: `boolean`
* - PersistedType: `boolean`
* - InitialValue: `false`
*/
declare class BooleanField<
const Options extends BooleanField.Options = BooleanField.DefaultOptions,
const AssignmentType = BooleanField.AssignmentType<SimpleMerge<Options, BooleanField.DefaultOptions>>,
const InitializedType = BooleanField.InitializedType<SimpleMerge<Options, BooleanField.DefaultOptions>>,
const PersistedType extends boolean | null | undefined = BooleanField.InitializedType<
SimpleMerge<Options, BooleanField.DefaultOptions>
>,
> extends DataField<Options, AssignmentType, InitializedType, PersistedType> {
/** @defaultValue `true` */
override required: boolean;
/** @defaultValue `false` */
override nullable: boolean;
/** @defaultValue `false` */
override initial: DataField.Options.InitialType<InitializedType>;
protected static override get _defaults(): BooleanField.Options;
protected override _cast(value: AssignmentType): InitializedType;
/** @remarks `options` is unused in `BooleanField` */
protected override _validateType(
value: InitializedType,
options?: DataField.ValidateOptions<this> | null,
): boolean | DataModelValidationFailure | void;
protected override _toInput(config: DataField.ToInputConfig<InitializedType>): HTMLElement | HTMLCollection;
/** @remarks Returns `value || delta`. `model` and `change` are unused in `BooleanField` */
protected override _applyChangeAdd(
value: InitializedType,
delta: InitializedType,
model: DataModel.Any,
change: ActiveEffect.EffectChangeData,
): InitializedType;
/** @remarks Returns `value && delta`. `model` and `change` are unused in `BooleanField` */
protected override _applyChangeMultiply(
value: InitializedType,
delta: InitializedType,
model: DataModel.Any,
change: ActiveEffect.EffectChangeData,
): InitializedType;
/** @remarks Returns `delta > value ? delta : value`. `model` and `change` are unused in `BooleanField` */
protected override _applyChangeUpgrade(
value: InitializedType,
delta: InitializedType,
model: DataModel.Any,
change: ActiveEffect.EffectChangeData,
): InitializedType;
/** @remarks Returns `delta < value ? delta : value`. `model` and `change` are unused in `BooleanField` */
protected override _applyChangeDowngrade(
value: InitializedType,
delta: InitializedType,
model: DataModel.Any,
change: ActiveEffect.EffectChangeData,
): InitializedType;
}
declare namespace BooleanField {
/** A shorthand for the options of a BooleanField class. */
type Options = DataField.Options<boolean>;
/** The type of the default options for the {@link BooleanField | `BooleanField`} class. */
type DefaultOptions = SimpleMerge<
DataField.DefaultOptions,
{
required: true;
nullable: false;
initial: boolean;
}
>;
/**
* A helper type for the given options type merged into the default options of the BooleanField class.
* @typeParam Opts - the options that override the default options
*/
type MergedOptions<Opts extends Options> = SimpleMerge<DefaultOptions, Opts>;
/**
* A shorthand for the assignment type of a BooleanField class.
* @typeParam Opts - the options that override the default options
*/
type AssignmentType<Opts extends Options> = DataField.DerivedAssignmentType<boolean, MergedOptions<Opts>>;
/**
* A shorthand for the initialized type of a BooleanField class.
* @typeParam Opts - the options that override the default options
*/
type InitializedType<Opts extends Options> = DataField.DerivedInitializedType<boolean, MergedOptions<Opts>>;
}
/**
* A subclass of {@link DataField | `DataField`} which deals with number-typed data.
* @typeParam Options - the options of the NumberField instance
* @typeParam AssignmentType - the type of the allowed assignment values of the NumberField
* @type