fomod
Version:
A library for creating, parsing, editing, and validating XML-based Fomod installers, widely popularized in the Bethesda modding scene
892 lines (875 loc) • 57.6 kB
TypeScript
/** A valid tag for an XML-Based Fomod installer */
declare enum TagName {
Fomod = "fomod",
Config = "config",
ModuleName = "moduleName",
ModuleImage = "moduleImage",
ModuleDependencies = "moduleDependencies",
Dependencies = "dependencies",
FileDependency = "fileDependency",
FlagDependency = "flagDependency",
GameDependency = "gameDependency",
FOMMDependency = "fommDependency",
FOSEDependency = "foseDependency",
RequiredInstallFiles = "requiredInstallFiles",
File = "file",
Folder = "folder",
InstallSteps = "installSteps",
InstallStep = "installStep",
Visible = "visible",
OptionalFileGroups = "optionalFileGroups",
Group = "group",
Plugins = "plugins",
Plugin = "plugin",
Description = "description",
Image = "image",
ConditionFlags = "conditionFlags",
Flag = "flag",
Files = "files",
TypeDescriptor = "typeDescriptor",
Type = "type",
DependencyType = "dependencyType",
DefaultType = "defaultType",
Patterns = "patterns",
Pattern = "pattern",
ConditionalFileInstalls = "conditionalFileInstalls"
}
/** A valid attribute for an XML-Based Fomod installer */
declare enum AttributeName {
Color = "colour",
Colour = "colour",
Path = "path",
Position = "position",
Height = "height",
ShowFade = "showFade",
ShowImage = "showImage",
Operator = "operator",
Source = "source",
Destination = "destination",
Priority = "priority",
AlwaysInstall = "alwaysInstall",
InstallIfUsable = "installIfUsable",
Order = "order",
Name = "name",
Type = "type",
File = "file",
State = "state",
Flag = "flag",
Value = "value",
Version = "version"
}
/** Describes how the group should behave when allowing users to select its options */
declare enum GroupBehaviorType {
/** Users may select or deselect any otherwise-selectable option within the group without restriction. */
SelectAny = "SelectAny",
/** Users must select at least one otherwise-selectable option within the group. */
SelectAtLeastOne = "SelectAtLeastOne",
/** Users may select no option or a single, otherwise-selectable option within the group. */
SelectAtMostOne = "SelectAtMostOne",
/** Users must select exactly one otherwise-selectable option within the group; no more, no less. This is the default behavior. */
SelectExactlyOne = "SelectExactlyOne",
/** All options in the group are forcibly selected and cannot be deselected. */
SelectAll = "SelectAll"
}
/** Describes how an option should behave in regard to user selection */
declare enum OptionType {
/** The option will not be selected and cannot be selected. */
NotUsable = "NotUsable",
/** Acts the same as `Optional`, except that mod managers may show a warning to the user when selecting this option. This is not universal, though, and the majority of mainstream mod managers at the moment forego this. */
CouldBeUsable = "CouldBeUsable",
/** The option will be selectable. This is the default behavior. */
Optional = "Optional",
/** The option will be selected by default but may be deselected. */
Recommended = "Recommended",
/** The option will be selected by default and cannot be deselected. */
Required = "Required"
}
/** Describes how the group should behave when allowing users to select its options */
declare enum SortingOrder {
/** Items are ordered alphabetically starting with A and ending with Z. This is the default behavior. */
Ascending = "Ascending",
/** Items are ordered alphabetically starting with Z and ending with A. */
Descending = "Descending",
/** Items are ordered precisely as they appear in the XML (and, consequently, the Set within JS) */
Explicit = "Explicit"
}
/** A state which this FileDependency expects the file to be in to be satisfied */
declare enum FileDependencyState {
/** The file must not exist on the user's system */
Missing = "Missing",
/** The file must be on the user's system but NOT loaded by the game */
Inactive = "Inactive",
/** The file must be on the user's system and loaded by the game */
Active = "Active"
}
/** An operator which determines the behavior of the dependency group */
declare enum DependencyGroupOperator {
/** The dependency group is satisfied if *any* of its children are satisfied */
Or = "Or",
/** The dependency group is only satisfied if **all** of its children are satisfied */
And = "And"
}
declare enum ModuleNamePosition {
/** Positions the title on the left side of the form header. */
Left = "Left",
/** Positions the title on the right side of the form header. */
Right = "Right",
/** Positions the title on the right side of the image in the form header. */
RightOfImage = "RightOfImage"
}
declare enum BooleanString {
true = "true",
false = "false"
}
interface FomodDocumentConfig {
/** [asElement] Whether or to include a third-party schema for Info.xml
*
* If a string is provided, we'll use that string as the schema location. Otherwise, we'll use the library's default.
*
* @default true
*/
includeInfoSchema?: boolean | string;
/** [asElement] Whether to move all conditional installs with only a dependency on a single option to the <files> tag of that option
*
* Note that this may cause slight performance issues with Vortex on slower machines.
*
* @default false
*/
flattenConditionalInstalls?: boolean;
/** [asElement] Whether to reorganize all conditional installs with no dependencies into the <requiredInstallFiles> tag
*
* @default false
*/
flattenConditionalInstallsNoDependencies?: boolean;
/** [asElement] Whether to remove conditional installs with no dependencies and no files (has no effect when `flattenConditionalInstallsNoDependencies` is `true`)
*
* @default true
*/
removeEmptyConditionalInstalls?: boolean;
/** [parse/asElement] String used for the flag value of option dependencies
*
* @default 'OPTION_SELECTED'
*/
optionSelectedValue?: string;
/** [parse] Whether to attempt to determine if a flag is an option flag to the best of our knowledge
*
* If `'loose'` is provided, we'll accept any flag name or value so long as it's only set by one option.
*
* @default true
*/
parseOptionFlags?: boolean | 'loose';
/**
* [asElement] Whether to discard existing option flag names and generate new ones for all options
*
* @default false
*/
generateNewOptionFlagNames?: boolean;
}
declare const DefaultFomodDocumentConfig: {
readonly includeInfoSchema: true;
readonly flattenConditionalInstalls: false;
readonly flattenConditionalInstallsNoDependencies: false;
readonly removeEmptyConditionalInstalls: true;
readonly optionSelectedValue: "OPTION_SELECTED";
readonly parseOptionFlags: true;
readonly generateNewOptionFlagNames: false;
};
/** A list of reasons why a Fomod might be invalid
*
* If you are using this to provide an explanation for end users, it is up to you to provide human-readable translations.
*/
declare enum InvalidityReason {
FomodModuleNameMetadataInvalidPosition = "fomod.module_name_metadata.position",
FomodModuleNameMetadataColorHexNotHexNumber = "fomod.module_name_metadata.color_hex.not_hex_number",
FomodModuleNameMetadataColorHexNotEvenNumberOfHexDigits = "fomod.module_name_metadata.color_hex.odd_digit_count",
FomodModuleImageMetadataShowFadeNotBool = "fomod.module_image_metadata.show_fade.not_boolean",
FomodModuleImageMetadataShowImageNotBool = "fomod.module_image_metadata.show_image.not_boolean",
DependenciesUnknownOperator = "dependencies.operator.unknown",
DependencyFileInvalidState = "dependencies.file.state.unknown",
StepUnknownGroupSortingOrder = "step.sorting_order.unknown",
GroupUnknownBehaviorType = "group.behavior_type.unknown",
GroupUnknownOptionSortingOrder = "group.sorting_order.unknown",
OptionTypeDescriptorUnknownOptionType = "option.type_descriptor.option_type.unknown",
InstallPriorityNotInteger = "install.priority.not_integer",
InstallAlwaysInstallNotBoolean = "install.always_install.not_boolean",
InstallInstallIfUsableNotBoolean = "install.install_if_usable.not_boolean"
}
/** A report detailing what part of a Fomod is invalid */
interface InvalidityReport {
/** The reason the item is invalid */
reason: InvalidityReason;
/** The value causing the item to be invalid */
offendingValue: string;
/** The tree leading up to the most immediate invalid item */
tree: Omit<Verifiable<false>, 'isValid' | 'reasonForInvalidity'>[];
}
/** The foundation of a class that can be validated against a schema.
*
* This model is important because it allows for the parsing of unsafe documents while providing maximum type safety for generated documents.
*/
declare abstract class Verifiable<TStrict extends boolean> {
/** Checks if this item is compliant with the schema. Can be used both for type narrowing and input validation. */
abstract isValid(): this is Verifiable<true>;
/** Query the reason why the given item is invalid. Returns `null` if the object is valid.
*
* This method tends to be very, very, very slow. If you are only interested in whether or not the object is valid, please use `isValid()` instead.
*
* Depending on how often you expect the object to be invalid, it may be faster to use `isValid()` as a fail-fast check before calling this method.
*/
abstract reasonForInvalidity(...tree: Omit<Verifiable<false>, 'isValid' | 'reasonForInvalidity'>[]): InvalidityReport | null;
}
declare const ElementObjectMap: WeakMap<Element, XmlRepresentation<boolean>>;
/** A representation of an XML element for use with various Fomod classes. helps to facilitate in-place editing of Fomod documents.
*
*/
declare abstract class XmlRepresentation<TStrict extends boolean> extends Verifiable<TStrict> {
static readonly tagName: TagName | TagName[];
abstract readonly tagName: TagName;
/** A [weak map](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WeakMap) of documents to this representation's associated element within that document.
*
* Without this map, in-place editing would be significantly more difficult.
*/
documentMap: WeakMap<Document, Element>;
/** Assigns an element for a document.
*
* @throws If the tag name of the element does not match the tag name of this class.
* @throws If an element has already been assigned for this document
* @throws If the element has already been assigned to a different instance of any Fomod class.
*/
assignElement(element: Element): void;
/** Returns the element assigned to the document. Will create a new one if it does not exist. */
getElementForDocument(document: Document): Element;
/** Preforms non-serializing operations to associate this object with a document. */
abstract associateWithDocument(document: Document): unknown;
abstract decommission?(currentDocument?: Document): unknown;
/** Generates an XML element from this object. */
abstract asElement(document: Document, config?: FomodDocumentConfig): Element;
static parse(element: Element, config?: FomodDocumentConfig): XmlRepresentation<boolean> | null;
}
interface FlagInstances {
all: Set<FlagInstance<boolean, boolean>>;
byName: Map<string | Option<boolean>, Set<FlagInstance<boolean, boolean>>>;
}
/** A [weak map](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WeakMap) of documents to flag instances within that document.
*
* This map allows for quick access to all flag instances within a document as well as all flag instances with a given name.
*/
declare const FlagInstanceStoresByDocument: WeakMap<Document, FlagInstances>;
declare class FlagInstance<TIsOption extends boolean, TWrite extends (TIsOption extends true ? false : boolean)> {
/** The name of the flag this instance refers to
*
* Automatically updates the flag instance map when changed.
*/
private _name;
/** The value being checked/set by this instance
*
* When the flag represents a traditional key-value, this will be a string. When the flag represents an option's select state, this will be `true`.
*/
usedValue: TIsOption extends true ? true : string;
/** Whether this instance is reading or writing the flag value
*
* When the flag represents an option's select state, this mist be `false` (since you cannot set the value of an option's select state)
*/
write: TWrite;
static isOptionFlagGetter(flag: FlagInstance<boolean, boolean>): flag is FlagInstance<true, false>;
static isRegularFlagOrOptionFlagSetter(flag: FlagInstance<boolean, boolean>): flag is FlagInstance<false, boolean>;
get name(): TIsOption extends true ? Option<boolean> : string;
set name(value: TIsOption extends true ? Option<boolean> : string);
/** A list of documents this flag is a part of */
documents: Set<Document>;
/** If this flag instance is the setter for an option flag (not the getter, which would make TIsOption = true),
* this is a map of documents to the option instance that this flag represents.
*/
optionFlagOptionByDocument: WeakMap<Document, Option<boolean>>;
constructor(_name: TIsOption extends true ? never : string, usedValue: string, write: TWrite, document?: Document);
constructor(_name: TIsOption extends true ? Option<boolean> : never, usedValue: true, write: TWrite, document?: Document);
/** Attaches this flag instance to a document */
attachDocument(document: Document): void;
/** Removes this flag instance from a document */
removeFromDocument(document: Document): void;
/** Cleans up the document map */
delete(): void;
decommission(currentDocument?: Document): void;
associateWithDocument(document: Document): void;
}
type SuggestedString<T extends string> = string & {} | T;
type MaybeStrictString<T extends string, TStrict extends boolean> = TStrict extends true ? T : SuggestedString<T>;
type MaybeStrictBoolString<TStrict extends boolean> = MaybeStrictString<BooleanString, TStrict>;
type MaybeStrictIntString<TStrict extends boolean> = MaybeStrictString<`${bigint}`, TStrict>;
/***
* $$$$$$\ $$\ $$\ $$$$$$$$\ $$\ $$\
* $$ __$$\ \__| $$ | $$ _____|\__|$$ |
* $$ / \__|$$\ $$$$$$$\ $$$$$$\ $$ | $$$$$$\ $$ | $$\ $$ | $$$$$$\
* \$$$$$$\ $$ |$$ __$$\ $$ __$$\ $$ |$$ __$$\ $$$$$$\ $$$$$\ $$ |$$ |$$ __$$\
* \____$$\ $$ |$$ | $$ |$$ / $$ |$$ |$$$$$$$$ |\______|$$ __| $$ |$$ |$$$$$$$$ |
* $$\ $$ |$$ |$$ | $$ |$$ | $$ |$$ |$$ ____| $$ | $$ |$$ |$$ ____|
* \$$$$$$ |$$ |$$ | $$ |\$$$$$$$ |$$ |\$$$$$$$\ $$ | $$ |$$ |\$$$$$$$\
* \______/ \__|\__| \__| \____$$ |\__| \_______| \__| \__|\__| \_______|
* $$\ $$ |
* \$$$$$$ |
* \______/
* $$$$$$\ $$\ $$\ $$\
* \_$$ _| $$ | $$ |$$ |
* $$ | $$$$$$$\ $$$$$$$\ $$$$$$\ $$$$$$\ $$ |$$ |
* $$ | $$ __$$\ $$ _____|\_$$ _| \____$$\ $$ |$$ |
* $$ | $$ | $$ |\$$$$$$\ $$ | $$$$$$$ |$$ |$$ |
* $$ | $$ | $$ | \____$$\ $$ |$$\ $$ __$$ |$$ |$$ |
* $$$$$$\ $$ | $$ |$$$$$$$ | \$$$$ |\$$$$$$$ |$$ |$$ |
* \______|\__| \__|\_______/ \____/ \_______|\__|\__|
*
*
*
*/
interface InstallInstances {
all: Set<Install<boolean>>;
bySource: Map<string, Set<Install<boolean>>>;
byDestination: Map<string, Set<Install<boolean>>>;
}
/** A [weak map](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WeakMap) of documents to flag instances within that document.
*
* This map allows for quick access to all flag instances within a document as well as all flag instances with a given name.
*/
declare const InstallInstancesByDocument: WeakMap<Document, InstallInstances>;
type InstallTagName = TagName.File | TagName.Folder;
declare class Install<TStrict extends boolean> extends XmlRepresentation<TStrict> {
/** File path relative to the archive root to install this file from.
*
* Whether a folder is being installed or not will be determined by if the path ends with a slash. It **WILL** cause errors later down the line if the source and destination paths are not the same type.
*/
fileSource: string;
/** File path relative to the archive root to install this file from. If no destination is provided, the file will be installed to the same path as the source.
*
* Whether a folder is being installed or not will be determined by if the path ends with a slash. It **WILL** cause errors later down the line if the source and destination paths are not the same type.
*/
fileDestination: string | null;
/** The priority of this file install. Higher priority files will be installed first. Must be an integer.
*
* Defaults to `0`. If the value is `0`, the value will not be written to the element.
*/
priority: MaybeStrictIntString<TStrict>;
/** Whether to always install the file if it is considered "usable"
*
* @deprecated Has inconsistent behavior between mod managers. Instead, you might consider duplicating the `dependencies` object to specify when a file should be installed. Included for completeness.
*/
installIfUsable: MaybeStrictBoolString<TStrict>;
/** Whether to always install the file, even if the user has not selected it.
*
* @deprecated Has inconsistent behavior between mod managers. Instead, you might consider removing the `dependencies` object instead. Included for completeness.
*/
alwaysInstall: MaybeStrictBoolString<TStrict>;
static readonly tagName: [TagName.File, TagName.Folder];
tagName: InstallTagName;
/** A list of documents this install is a part of */
documents: Set<Document>;
isValid(): this is Install<true>;
reasonForInvalidity(...tree: Omit<Verifiable<false>, 'isValid' | 'reasonForInvalidity'>[]): InvalidityReport | null;
constructor(
/** File path relative to the archive root to install this file from.
*
* Whether a folder is being installed or not will be determined by if the path ends with a slash. It **WILL** cause errors later down the line if the source and destination paths are not the same type.
*/
fileSource?: string,
/** File path relative to the archive root to install this file from. If no destination is provided, the file will be installed to the same path as the source.
*
* Whether a folder is being installed or not will be determined by if the path ends with a slash. It **WILL** cause errors later down the line if the source and destination paths are not the same type.
*/
fileDestination?: string | null,
/** The priority of this file install. Higher priority files will be installed first. Must be an integer.
*
* Defaults to `0`. If the value is `0`, the value will not be written to the element.
*/
priority?: MaybeStrictIntString<TStrict>, document?: Document,
/** Whether to always install the file if it is considered "usable"
*
* @deprecated Has inconsistent behavior between mod managers. Instead, you might consider duplicating the `dependencies` object to specify when a file should be installed. Included for completeness.
*/
installIfUsable?: MaybeStrictBoolString<TStrict>,
/** Whether to always install the file, even if the user has not selected it.
*
* @deprecated Has inconsistent behavior between mod managers. Instead, you might consider removing the `dependencies` object instead. Included for completeness.
*/
alwaysInstall?: MaybeStrictBoolString<TStrict>);
/** Generates an XML element from this object.
*/
asElement(document: Document, config?: FomodDocumentConfig): Element;
static parse(element: Element, config?: FomodDocumentConfig): Install<boolean>;
getElementForDocument(document: Document): Element;
assignElement(element: Element): void;
/** Attaches this flag instance to a document */
attachDocument(document: Document): void;
/** Removes this flag instance from a document */
removeFromDocument(document: Document): void;
associateWithDocument(document: Document): void;
decommission(currentDocument?: Document): void;
}
/***
* $$$$$$$$\ $$\ $$\ $$\ $$\
* $$ _____|\__|$$ | $$ | $\ $$ |
* $$ | $$\ $$ | $$$$$$\ $$$$$$$\ $$ |$$$\ $$ | $$$$$$\ $$$$$$\ $$$$$$\ $$$$$$\ $$$$$$\ $$$$$$\
* $$$$$\ $$ |$$ |$$ __$$\ $$ _____| $$ $$ $$\$$ |$$ __$$\ \____$$\ $$ __$$\ $$ __$$\ $$ __$$\ $$ __$$\
* $$ __| $$ |$$ |$$$$$$$$ |\$$$$$$\ $$$$ _$$$$ |$$ | \__| $$$$$$$ |$$ / $$ |$$ / $$ |$$$$$$$$ |$$ | \__|
* $$ | $$ |$$ |$$ ____| \____$$\ $$$ / \$$$ |$$ | $$ __$$ |$$ | $$ |$$ | $$ |$$ ____|$$ |
* $$ | $$ |$$ |\$$$$$$$\ $$$$$$$ | $$ / \$$ |$$ | \$$$$$$$ |$$$$$$$ |$$$$$$$ |\$$$$$$$\ $$ |
* \__| \__|\__| \_______|\_______/ \__/ \__|\__| \_______|$$ ____/ $$ ____/ \_______|\__|
* $$ | $$ |
* $$ | $$ |
* \__| \__|
*/
/** A helper class to represent the <files> element. Contains a list of files to be installed by a dependency or option. */
declare class InstallPatternFilesWrapper<TStrict extends boolean> extends XmlRepresentation<TStrict> {
installs: Set<Install<TStrict>>;
static tagName: TagName;
readonly tagName = TagName.Files;
constructor(installs?: Set<Install<TStrict>>);
asElement(document: Document, config?: FomodDocumentConfig): Element;
isValid(): this is InstallPatternFilesWrapper<true>;
static parse(element: Element, config?: FomodDocumentConfig): InstallPatternFilesWrapper<boolean>;
reasonForInvalidity(...tree: Omit<Verifiable<false>, 'isValid' | 'reasonForInvalidity'>[]): InvalidityReport | null;
associateWithDocument(document: Document): void;
decommission(currentDocument?: Document): void;
}
/***
* $$$$$$\ $$\ $$\ $$\
* \_$$ _| $$ | $$ |$$ |
* $$ | $$$$$$$\ $$$$$$$\ $$$$$$\ $$$$$$\ $$ |$$ |
* $$ | $$ __$$\ $$ _____|\_$$ _| \____$$\ $$ |$$ |
* $$ | $$ | $$ |\$$$$$$\ $$ | $$$$$$$ |$$ |$$ |
* $$ | $$ | $$ | \____$$\ $$ |$$\ $$ __$$ |$$ |$$ |
* $$$$$$\ $$ | $$ |$$$$$$$ | \$$$$ |\$$$$$$$ |$$ |$$ |
* \______|\__| \__|\_______/ \____/ \_______|\__|\__|
*
*
*
* $$$$$$$\ $$\ $$\
* $$ __$$\ $$ | $$ |
* $$ | $$ | $$$$$$\ $$$$$$\ $$$$$$\ $$$$$$\ $$$$$$\ $$$$$$$\
* $$$$$$$ | \____$$\ \_$$ _| \_$$ _| $$ __$$\ $$ __$$\ $$ __$$\
* $$ ____/ $$$$$$$ | $$ | $$ | $$$$$$$$ |$$ | \__|$$ | $$ |
* $$ | $$ __$$ | $$ |$$\ $$ |$$\ $$ ____|$$ | $$ | $$ |
* $$ | \$$$$$$$ | \$$$$ | \$$$$ |\$$$$$$$\ $$ | $$ | $$ |
* \__| \_______| \____/ \____/ \_______|\__| \__| \__|
*
*
*
*/
/** A helper class to represent the <pattern> element. Contains a list of files to install and a list of dependencies that must first be fulfilled. */
declare class InstallPattern<TStrict extends boolean> extends XmlRepresentation<TStrict> {
dependencies: DependenciesGroup<TagName.Dependencies, TStrict>;
filesWrapper: InstallPatternFilesWrapper<TStrict>;
static tagName: TagName;
readonly tagName = TagName.Pattern;
constructor(dependencies?: DependenciesGroup<TagName.Dependencies, TStrict>, filesWrapper?: InstallPatternFilesWrapper<TStrict>);
asElement(document: Document, config?: FomodDocumentConfig, knownOptions?: Option<boolean>[]): Element;
isValid(): this is InstallPattern<true>;
static parse(element: Element, config?: FomodDocumentConfig): InstallPattern<boolean>;
reasonForInvalidity(...tree: Omit<Verifiable<false>, 'isValid' | 'reasonForInvalidity'>[]): InvalidityReport | null;
decommission(currentDocument?: Document): void;
associateWithDocument(document: Document): void;
}
/***
* $$$$$$\ $$\ $$\ $$$$$$$\ $$\
* $$ __$$\ $$ | \__| $$ __$$\ $$ |
* $$ / $$ | $$$$$$\ $$$$$$\ $$\ $$$$$$\ $$$$$$$\ $$ | $$ | $$$$$$\ $$$$$$$ |$$\ $$\
* $$ | $$ |$$ __$$\ \_$$ _| $$ |$$ __$$\ $$ __$$\ $$$$$$$\ |$$ __$$\ $$ __$$ |$$ | $$ |
* $$ | $$ |$$ / $$ | $$ | $$ |$$ / $$ |$$ | $$ | $$ __$$\ $$ / $$ |$$ / $$ |$$ | $$ |
* $$ | $$ |$$ | $$ | $$ |$$\ $$ |$$ | $$ |$$ | $$ | $$ | $$ |$$ | $$ |$$ | $$ |$$ | $$ |
* $$$$$$ |$$$$$$$ | \$$$$ |$$ |\$$$$$$ |$$ | $$ | $$$$$$$ |\$$$$$$ |\$$$$$$$ |\$$$$$$$ |
* \______/ $$ ____/ \____/ \__| \______/ \__| \__| \_______/ \______/ \_______| \____$$ |
* $$ | $$\ $$ |
* $$ | \$$$$$$ |
* \__| \______/
*/
/** A single option (or "plugin") for a Fomod. These are typically presented as checkboxes or radio buttons. */
declare class Option<TStrict extends boolean> extends XmlRepresentation<TStrict> {
name: string;
description: string;
image: string | null;
typeDescriptor: TypeDescriptor<TStrict>;
flagsToSet: Set<FlagSetter>;
installsToSet: InstallPattern<TStrict>;
static readonly tagName = TagName.Plugin;
readonly tagName = TagName.Plugin;
constructor(name?: string, description?: string, image?: string | null, typeDescriptor?: TypeDescriptor<TStrict>, flagsToSet?: Set<FlagSetter>, installsToSet?: InstallPattern<TStrict>);
asElement(document: Document, config?: FomodDocumentConfig, knownOptions?: Option<boolean>[]): Element;
isValid(): this is Option<true>;
reasonForInvalidity(...tree: Omit<Verifiable<false>, "isValid" | "reasonForInvalidity">[]): InvalidityReport | null;
existingOptionFlagSetterByDocument: WeakMap<Document, FlagSetter>;
getOptionFlagSetter(this: Option<boolean>, document: Document, config?: FomodDocumentConfig, knownOptions?: Option<boolean>[]): FlagSetter;
static parse(element: Element, config?: FomodDocumentConfig): Option<boolean> | null;
decommission(currentDocument?: Document): void;
associateWithDocument(document: Document): void;
}
declare class FlagSetter extends XmlRepresentation<true> {
readonly flagInstance: FlagInstance<false, true>;
static readonly tagName = TagName.Flag;
readonly tagName = TagName.Flag;
get name(): string;
set name(name: string);
get value(): string;
set value(value: string);
constructor(flagInstance: FlagInstance<false, true>);
asElement(document: Document, config?: FomodDocumentConfig): Element;
isValid(): this is FlagSetter;
reasonForInvalidity(): null;
static parse(element: Element, config?: FomodDocumentConfig): FlagSetter | null;
decommission(currentDocument?: Document): void;
associateWithDocument(document: Document): void;
}
/***
* $$$$$$$$\
* \__$$ __|
* $$ | $$\ $$\ $$$$$$\ $$$$$$\
* $$ | $$ | $$ |$$ __$$\ $$ __$$\
* $$ | $$ | $$ |$$ / $$ |$$$$$$$$ |
* $$ | $$ | $$ |$$ | $$ |$$ ____|
* $$ | \$$$$$$$ |$$$$$$$ |\$$$$$$$\
* \__| \____$$ |$$ ____/ \_______|
* $$\ $$ |$$ |
* \$$$$$$ |$$ |
* \______/ \__|
* $$$$$$$\ $$\ $$\
* $$ __$$\ \__| $$ |
* $$ | $$ | $$$$$$\ $$$$$$$\ $$$$$$$\ $$$$$$\ $$\ $$$$$$\ $$$$$$\ $$$$$$\ $$$$$$\
* $$ | $$ |$$ __$$\ $$ _____|$$ _____|$$ __$$\ $$ |$$ __$$\ \_$$ _| $$ __$$\ $$ __$$\
* $$ | $$ |$$$$$$$$ |\$$$$$$\ $$ / $$ | \__|$$ |$$ / $$ | $$ | $$ / $$ |$$ | \__|
* $$ | $$ |$$ ____| \____$$\ $$ | $$ | $$ |$$ | $$ | $$ |$$\ $$ | $$ |$$ |
* $$$$$$$ |\$$$$$$$\ $$$$$$$ |\$$$$$$$\ $$ | $$ |$$$$$$$ | \$$$$ |\$$$$$$ |$$ |
* \_______/ \_______|\_______/ \_______|\__| \__|$$ ____/ \____/ \______/ \__|
* $$ |
* $$ |
* \__|
*/
/** Describes the desired `OptionType` for an option
*
* Supports setting a default type and an optional list of conditions ('patterns') that can change the type.
*
* @see `OptionType`
*/
declare class TypeDescriptor<TStrict extends boolean> extends XmlRepresentation<TStrict> {
/** The type name descriptor */
defaultTypeNameDescriptor: TypeNameDescriptor<TypeDescriptorTagName, TStrict, false>;
patterns: TypeDescriptorPattern<TStrict>[];
static readonly tagName = TagName.TypeDescriptor;
readonly tagName = TagName.TypeDescriptor;
constructor(
/** The type name descriptor */
defaultTypeNameDescriptor?: TypeNameDescriptor<TypeDescriptorTagName, TStrict, false>, patterns?: TypeDescriptorPattern<TStrict>[]);
asElement(document: Document, config?: FomodDocumentConfig): Element;
static parse(element: Element, config?: FomodDocumentConfig): TypeDescriptor<boolean>;
isValid(): this is TypeDescriptor<true>;
reasonForInvalidity(...tree: Omit<Verifiable<false>, "isValid" | "reasonForInvalidity">[]): InvalidityReport | null;
decommission(currentDocument?: Document): void;
associateWithDocument(document: Document): void;
}
declare class TypeDescriptorPattern<TStrict extends boolean> extends XmlRepresentation<TStrict> {
typeNameDescriptor: TypeNameDescriptor<TagName.Type, TStrict, true>;
dependencies: DependenciesGroup<TagName.Dependencies, TStrict>;
static readonly tagName = TagName.Pattern;
readonly tagName = TagName.Pattern;
constructor(typeNameDescriptor?: TypeNameDescriptor<TagName.Type, TStrict, true>, dependencies?: DependenciesGroup<TagName.Dependencies, TStrict>);
asElement(document: Document, config?: FomodDocumentConfig): Element;
static parse(element: Element, config?: FomodDocumentConfig): TypeDescriptorPattern<boolean>;
isValid(): this is TypeDescriptorPattern<true>;
reasonForInvalidity(...tree: Omit<Verifiable<false>, "isValid" | "reasonForInvalidity">[]): InvalidityReport | null;
decommission(currentDocument?: Document): void;
associateWithDocument(document: Document): void;
}
type TypeDescriptorTagName = TagName.Type | TagName.DefaultType;
declare class TypeNameDescriptor<TTagName extends TypeDescriptorTagName, TStrict extends boolean, TTagNameIsReadOnly extends boolean = true> extends XmlRepresentation<TStrict> {
private _tagName;
targetType: MaybeStrictString<OptionType, TStrict>;
tagNameIsReadonly: TTagNameIsReadOnly;
static readonly tagName: [TagName.Type, TagName.DefaultType];
get tagName(): TTagNameIsReadOnly extends true ? TTagName : TypeDescriptorTagName;
set tagName(tagName: TTagNameIsReadOnly extends true ? TTagName : TypeDescriptorTagName);
constructor(_tagName: TTagNameIsReadOnly extends true ? TTagName : TypeDescriptorTagName, targetType: MaybeStrictString<OptionType, TStrict>, tagNameIsReadonly: TTagNameIsReadOnly);
asElement(document: Document, config?: FomodDocumentConfig): Element;
static parse<TTagName extends TypeDescriptorTagName = TypeDescriptorTagName, TTagNameIsReadOnly extends boolean = false>(element: Element, config?: FomodDocumentConfig, tagNameIsReadonly?: TTagNameIsReadOnly): TypeNameDescriptor<TTagName, boolean, TTagNameIsReadOnly>;
isValid(): this is TypeNameDescriptor<TTagName, true, TTagNameIsReadOnly>;
reasonForInvalidity(...tree: Omit<Verifiable<false>, "isValid" | "reasonForInvalidity">[]): InvalidityReport | null;
getElementForDocument(document: Document): Element;
assignElement(element: Element): void;
decommission(currentDocument?: Document): void;
associateWithDocument(document: Document): void;
}
/** A parent class to all forms of dependency.
*
* @template TStrict Whether or not to use strict typing for this class. Any data parsed from user input should be considered untrusted and thus `false` should be used. Otherwise, `true` should be used.
*
* NOTE: Many of the Dependency types cannot be statically validated and thus do not have a `TStrict` parameter.
*/
declare abstract class Dependency<TStrict extends boolean = boolean> extends XmlRepresentation<TStrict> {
abstract asElement(document: Document, config?: FomodDocumentConfig | undefined, knownOptions?: Option<boolean>[]): Element;
}
type DependencyTagName = TagName.Dependencies | TagName.ModuleDependencies | TagName.Visible;
declare class DependenciesGroup<TTagName extends DependencyTagName, TStrict extends boolean> extends Dependency {
readonly tagName: TTagName;
operator: MaybeStrictString<DependencyGroupOperator, TStrict>;
dependencies: Set<ValidDependency<TStrict>>;
static readonly tagName: [TagName.Dependencies, TagName.ModuleDependencies, TagName.Visible];
constructor(tagName: TTagName, operator?: MaybeStrictString<DependencyGroupOperator, TStrict>, dependencies?: Set<ValidDependency<TStrict>>);
isValid(): this is DependenciesGroup<TTagName, true>;
reasonForInvalidity(...tree: Omit<Verifiable<false>, "isValid" | "reasonForInvalidity">[]): InvalidityReport | null;
associateWithDocument(document: Document): void;
asElement(document: Document, config?: FomodDocumentConfig, knownOptions?: Option<boolean>[]): Element;
static parse<TTagName extends DependencyTagName = DependencyTagName>(element: Element, config?: FomodDocumentConfig): DependenciesGroup<TTagName, false>;
decommission(currentDocument?: Document): void;
}
declare class FileDependency<TStrict extends boolean> extends Dependency<TStrict> {
filePath: string;
desiredState: MaybeStrictString<FileDependencyState, TStrict>;
static readonly tagName = TagName.FileDependency;
readonly tagName = TagName.FileDependency;
constructor(filePath?: string, desiredState?: MaybeStrictString<FileDependencyState, TStrict>);
isValid(): this is FileDependency<true>;
reasonForInvalidity(...tree: Omit<Verifiable<false>, 'isValid' | 'reasonForInvalidity'>[]): InvalidityReport | null;
associateWithDocument(document: Document): void;
asElement(document: Document): Element;
static parse(element: Element, config?: FomodDocumentConfig): FileDependency<false>;
decommission: undefined;
}
/** Common parent for version check dependencies to reduce code duplication.
*
* Version dependencies work as a minimum value dependency. [SemVer](https://semver.org/) is used for comparisons.
*/
declare abstract class VersionDependency extends Dependency {
/** The version to use in the comparison
*
* Version dependencies work as a minimum value dependency. [SemVer](https://semver.org/) is used for comparisons.
*/
desiredVersion: string;
constructor(
/** The version to use in the comparison
*
* Version dependencies work as a minimum value dependency. [SemVer](https://semver.org/) is used for comparisons.
*/
desiredVersion?: string);
isValid(): this is VersionDependency;
asElement(document: Document): Element;
static parse(element: Element, config?: FomodDocumentConfig): ScriptExtenderVersionDependency | GameVersionDependency | ModManagerVersionDependency | null;
decommission: undefined;
reasonForInvalidity(): null;
associateWithDocument(document: Document): void;
}
/** A dependency on the version of the game.
*
* Version dependencies work as a minimum value dependency. [SemVer](https://semver.org/) is used for comparisons.
*
* Can be useful in a number of circumstances where the game executable version matters, such as determining what version of a script extender plugin to install.
*/
declare class GameVersionDependency extends VersionDependency {
static readonly tagName = TagName.GameDependency;
readonly tagName = TagName.GameDependency;
constructor(desiredVersion?: string);
static parse(element: Element, config?: FomodDocumentConfig): GameVersionDependency;
}
/** A dependency on the version of the installed script extender.
*
* Version dependencies work as a minimum value dependency. [SemVer](https://semver.org/) is used for comparisons.
*
* Can be useful in a number of circumstances where the script extender version matters, such as determining if a mod is compatible with the given version.
*/
declare class ScriptExtenderVersionDependency extends VersionDependency {
static readonly tagName = TagName.FOSEDependency;
readonly tagName = TagName.FOSEDependency;
constructor(desiredVersion?: string);
static parse(element: Element, config?: FomodDocumentConfig): ScriptExtenderVersionDependency;
}
/** A dependency on the version of the mod manager.
*
* Version dependencies work as a minimum value dependency. [SemVer](https://semver.org/) is used for comparisons.
*
* @deprecated Should generally not be used as the value is inconsistent between mod managers. Included for completeness.
*/
declare class ModManagerVersionDependency extends VersionDependency {
static readonly tagName = TagName.FOMMDependency;
readonly tagName = TagName.FOMMDependency;
constructor(desiredVersion?: string);
static parse(element: Element, config?: FomodDocumentConfig): ModManagerVersionDependency;
}
declare class FlagDependency extends Dependency {
static readonly tagName = TagName.FlagDependency;
readonly tagName = TagName.FlagDependency;
protected readonly flagInstance: FlagInstance<boolean, false>;
get flagKey(): string | Option<boolean>;
set flagKey(value: string | Option<boolean>);
get desiredValue(): string | true;
set desiredValue(value: string | true);
constructor(flagName?: string, desiredValue?: string);
constructor(flagName: Option<boolean>, desiredValue: true);
isValid(): this is FlagDependency;
reasonForInvalidity(): null;
associateWithDocument(document: Document): void;
decommission(currentDocument?: Document): void;
asElement(document: Document, config?: FomodDocumentConfig, knownOptions?: Option<boolean>[]): Element;
static parse(element: Element, config?: FomodDocumentConfig): FlagDependency;
}
type ValidDependency<TStrict extends boolean> = FileDependency<TStrict> | FlagDependency | GameVersionDependency | ScriptExtenderVersionDependency | ModManagerVersionDependency | DependenciesGroup<DependencyTagName, TStrict>;
declare class Group<TStrict extends boolean> extends XmlRepresentation<TStrict> {
name: string;
behaviorType: MaybeStrictString<GroupBehaviorType, TStrict>;
sortingOrder: MaybeStrictString<SortingOrder, TStrict>;
options: Set<Option<TStrict>>;
static readonly tagName = TagName.Group;
readonly tagName = TagName.Group;
constructor(name?: string, behaviorType?: MaybeStrictString<GroupBehaviorType, TStrict>, sortingOrder?: MaybeStrictString<SortingOrder, TStrict>, options?: Set<Option<TStrict>>);
asElement(document: Document, config?: FomodDocumentConfig, knownOptions?: Option<boolean>[]): Element;
isValid(): this is Group<true>;
reasonForInvalidity(...tree: Omit<Verifiable<false>, 'isValid' | 'reasonForInvalidity'>[]): InvalidityReport | null;
gatherOptions(): Option<TStrict>[];
static parse(element: Element, config?: FomodDocumentConfig): Group<boolean>;
decommission(currentDocument?: Document): void;
associateWithDocument(document: Document): void;
}
declare class Step<TStrict extends boolean> extends XmlRepresentation<TStrict> {
name: string;
sortingOrder: MaybeStrictString<typeof SortingOrder[keyof typeof SortingOrder], TStrict>;
groups: Set<Group<TStrict>>;
visibilityDeps: DependenciesGroup<TagName.Visible, TStrict>;
static readonly tagName = TagName.InstallStep;
readonly tagName = TagName.InstallStep;
constructor(name?: string, sortingOrder?: MaybeStrictString<typeof SortingOrder[keyof typeof SortingOrder], TStrict>, groups?: Set<Group<TStrict>>, visibilityDeps?: DependenciesGroup<TagName.Visible, TStrict>);
asElement(document: Document, config?: FomodDocumentConfig, knownOptions?: Option<boolean>[]): Element;
isValid(): this is Step<true>;
reasonForInvalidity(...tree: Omit<Verifiable<false>, 'isValid' | 'reasonForInvalidity'>[]): InvalidityReport | null;
gatherOptions(): Option<TStrict>[];
static parse(element: Element, config?: FomodDocumentConfig): Step<boolean>;
decommission(currentDocument?: Document | undefined): void;
associateWithDocument(document: Document): void;
}
interface ModuleImageMetadata<TStrict extends boolean> {
showFade?: MaybeStrictBoolString<TStrict>;
showImage?: MaybeStrictBoolString<TStrict>;
height?: MaybeStrictIntString<TStrict>;
}
interface ModuleNameMetadata<TStrict extends boolean> {
position?: MaybeStrictString<ModuleNamePosition, TStrict>;
/** Must be an XML-valid hex string. XML-valid hex strings accept the standard `1234567890ABCDEF` range and the length must be even
*
* Should ideally appear as a 6-digit hex string, however this is not enforced by the schema.
*/
colour?: string;
}
/** A FOMOD installer in its entirety.
*
* @template TStrict Whether or not to use strict typing for this class. Any data parsed from user input should be considered untrusted and thus `false` should be used. Otherwise, `true` should be used.
*/
declare class Fomod<TStrict extends boolean> extends XmlRepresentation<TStrict> {
/** The name of the FOMOD. Must be specified in the installer however can be an empty string.
*
* Note that Info.xml also has its own name.
*/
moduleName: string;
moduleImage: string | null;
/** Dependencies required for this FOMOD to be shown to the user.
*
* Mod managers will show the user an error message if attempting to install a FOMOD that does not meet the requirements specified here.
*/
moduleDependencies: DependenciesGroup<TagName.ModuleDependencies, TStrict>;
/** Top-level file installs for the FOMOD
*
* Covers both the `requiredInstallFiles` and `conditionalFileInstalls` tags.
*/
installs: Set<Install<TStrict> | InstallPattern<TStrict>>;
sortingOrder: MaybeStrictString<SortingOrder, TStrict>;
steps: Set<Step<TStrict>>;
/** Unused metadata for `moduleName`. Included for completeness.
*
* @deprecated
*/
moduleNameMetadata: (TStrict extends true ? Record<never, string> : Record<string, string>) & ModuleNameMetadata<TStrict>;
/** Unused metadata for `moduleImage`. Included for completeness.
*
* @deprecated
*/
moduleImageMetadata: (TStrict extends true ? Record<never, string> : Record<Exclude<string, 'path'>, string>) & ModuleImageMetadata<TStrict>;
static readonly tagName = TagName.Config;
readonly tagName = TagName.Config;
constructor(
/** The name of the FOMOD. Must be specified in the installer however can be an empty string.
*
* Note that Info.xml also has its own name.
*/
moduleName?: string, moduleImage?: string | null,
/** Dependencies required for this FOMOD to be shown to the user.
*
* Mod managers will show the user an error message if attempting to install a FOMOD that does not meet the requirements specified here.
*/
moduleDependencies?: DependenciesGroup<TagName.ModuleDependencies, TStrict>,
/** Top-level file installs for the FOMOD
*
* Covers both the `requiredInstallFiles` and `conditionalFileInstalls` tags.
*/
installs?: Set<Install<TStrict> | InstallPattern<TStrict>>, sortingOrder?: MaybeStrictString<SortingOrder, TStrict>, steps?: Set<Step<TStrict>>,
/** Unused metadata for `moduleName`. Included for completeness.
*
* @deprecated
*/
moduleNameMetadata?: (TStrict extends true ? Record<never, string> : Record<string, string>) & ModuleNameMetadata<TStrict>,
/** Unused metadata for `moduleImage`. Included for completeness.
*
* @deprecated
*/
moduleImageMetadata?: (TStrict extends true ? Record<never, string> : Record<Exclude<string, 'path'>, string>) & ModuleImageMetadata<TStrict>);
isValid(): this is Fomod<true>;
reasonForInvalidity(...tree: Omit<Verifiable<false>, "isValid" | "reasonForInvalidity">[]): InvalidityReport | null;
asElement(document: Document, config?: FomodDocumentConfig, knownOptions?: Option<boolean>[]): Element;
gatherOptions(): Option<TStrict>[];
static parse(element: Element, config?: FomodDocumentConfig): Fomod<boolean>;
decommission(currentDocument?: Document): void;
associateWithDocument(document: Document): void;
}
declare enum DependencyType {
Group = "group",
File = "file",
Flag = "flag",
ScriptExtenderVersion = "fose",
GameVersion = "game",
ModManagerVersion = "fomm"
}
interface DependencyJsonItemBase<TSerializable extends boolean> {
type: DependencyType;
}
interface DependenciesJsonGroup<TSerializable extends boolean> extends DependencyJsonItemBase<TSerializable> {
type: DependencyType.Group;
dependencies: DependenciesJsonItem<TSerializable>[];
operator: DependencyGroupOperator;
tagName: typeof DependenciesGroup.tagName extends Array<infer T> ? T : never;
}
interface DependenciesJsonFile extends DependencyJsonItemBase<boolean> {
type: DependencyType.File;
path: string;
state: FileDependencyState;
}
interface DependenciesJsonFlag<TSerializable extends boolean> extends DependencyJsonItemBase<TSerializable> {
type: DependencyType.Flag;
flag: string | (TSerializable extends true ? never : Option<boolean>);
value: string | (TSerializable extends true ? never : true);
isOptionFlag: boolean;
}
interface DependenciesJsonScriptExtender extends DependencyJsonItemBase<boolean> {
type: DependencyType.ScriptExtenderVersion;
version: string;
}
interface DependenciesJsonGameVersion extends DependencyJsonItemBase<boolean> {
type: DependencyType.GameVersion;
version: string;
}
interface DependenciesJsonModManager extends DependencyJsonItemBase<boolean> {
type: DependencyType.ModManagerVersion;
version: string;
}
type DependenciesJsonItem<TSerializable extends boolean> = DependenciesJsonGroup<TSerializable> | DependenciesJsonFile | DependenciesJsonFlag<TSerializable> | DependenciesJsonScriptExtender | DependenciesJsonGameVersion | DependenciesJsonModManager;
declare function jsonifyDependencyElements(elements: Iterable<ValidDependency<true>>, serializable: false, document?: Document): DependenciesJsonItem<false>[];
declare function jsonifyDependencyElements(elements: Iterable<ValidDependency<true>>, serializable: true, document: Document): DependenciesJsonItem<true>[];
declare function jsonifyDependencyElements<TSerializable extends true | false>(elements: Iterable<ValidDependency<true>>, serializable: TSerializable, document: Document | (TSerializable extends true ? never : undefined)): DependenciesJsonItem<TSerializable>[];
declare function jsonifyDependencyElement(dependency: ValidDependency<true>, serializable: false, document?: Document): DependenciesJsonItem<false>;
declare function jsonifyDependencyElement(dependency: ValidDependency<true>, serializable: true, document: Document): DependenciesJsonItem<true>;
declare function jsonifyDependencyElement<TSerializable extends boolean>(dependency: ValidDependency<true>, serializable: TSerializable, document: Document | (TSerializable extends true ? never : undefined)): DependenciesJsonItem<TSerializable>;
declare function jsonifyDependenciesGroup(dependencyGroup: DependenciesGroup<DependencyTagName, true>, serializable: false, document?: undefined): DependenciesJsonGroup<false>;
declare function jsonifyDependenciesGroup(dependencyGroup: DependenciesGroup<DependencyTagName, true>, serializable: true, document: Document): DependenciesJsonGroup<true>;
declare function jsonifyDependenciesGroup<TSerializable extends boolean>(dependencyGroup: DependenciesGroup<DependencyTagName, true>, serializable: TSerializable, document: Document | (TSerializable extends true ? never : undefined)): DependenciesJsonGroup<TSerializable>;
declare function jsonifyFileDependency(file: FileDependency<true>): DependenciesJsonFile;
declare function jsonifyFlagDependency(flagDependency: FlagDependency, serializable: false, document?: undefined): DependenciesJsonFlag<false>;
declare function jsonifyFlagDependency(flagDependency: FlagDependency, serializable: true, document: Document): DependenciesJsonFlag<true>;
declare function jsonifyFlagDependency<TSerializable extends boolean>(flag