// SPDX-FileCopyrightText: 2021 Johannes Loher // // SPDX-License-Identifier: MIT import { logger } from "../utils/logger.js"; import { getGame } from "../utils/utils.js"; /** * @template T * @typedef {(document: T) => Promise} Migrator */ /** * Migrate a collection. * @template T * @param {WorldCollection} collection * @param {Migrator} migrateDocument * @returns {Promise} A promise that resolves once the migration is complete */ export async function migrateCollection(collection, migrateDocument) { /** @type {import("./migration.js").Result} */ let result = "success"; const { documentName } = collection.constructor; for (const document of collection) { logger.info(`Migrating ${documentName} document ${document.name} (${document.id})`); try { await migrateDocument(document); } catch (err) { logger.error( `Error during migration of ${documentName} document ${document.name} (${document.id}), continuing anyways.`, err, ); result = "error"; } } return result; } /** * @param {Migrator} [migrateActiveEffect] * @returns {Migrator} */ export function getItemMigrator(migrateActiveEffect) { /** * @param {Item} item */ return async (item) => { if (migrateActiveEffect) { for (const effect of item.effects) { await migrateActiveEffect(effect); } } }; } /** * @param {Migrator} [migrateItem] * @param {Migrator} [migrateActiveEffect] * @returns {Migrator} */ export function getActorMigrator(migrateItem, migrateActiveEffect) { /** * @param {Actor} actor */ return async (actor) => { if (migrateItem) { for (const item of actor.items) { await migrateItem(item); } } if (migrateActiveEffect) { for (const effect of actor.effects) { await migrateActiveEffect(effect); } } }; } /** * @param {Migrator} [migrateActor] * @returns {Migrator} */ export function getSceneMigrator(migrateActor) { /** * @param {Scene} scene */ return async (scene) => { if (migrateActor) { for (const token of scene.tokens) { if (!token.actorLink && token.actor) { await migrateActor(token.actor); } } } }; } /** @typedef {(pack: CompendiumCollection) => Promise} CompendiumMigrator */ /** * Migrate world compendium packs. * @param {CompendiumMigrator} migrateCompendium A function for migrating a single compendium pack * @returns {Promise} A promise that resolves once the migration is complete */ export async function migrateCompendiums(migrateCompendium) { /** @type {import("./migration.js").Result} */ let result = "success"; for (const compendium of getGame().packs ?? []) { if (compendium.metadata.package !== "world") continue; if (!["Actor", "Item", "Scene"].includes(compendium.metadata.type)) continue; const r = await migrateCompendium(compendium); if (r === "error") { result = "error"; } } return result; } /** * @typedef {object} Migrators * @property {Migrator} [migrateItem] * @property {Migrator} [migrateActor] * @property {Migrator} [migrateScene] */ /** * Get a compendium migrator for the given migrators. * @param {Migrators} [migrators={}] The functions to use for getting update data * @param {{migrateToTemplateEarly?: boolean}} [options={}] Additional options for the compendium migrator * @returns {CompendiumMigrator} The resulting compendium migrator */ export function getCompendiumMigrator( { migrateItem, migrateActor, migrateScene } = {}, { migrateToTemplateEarly = true } = {}, ) { return async (pack) => { /** @type {import("./migration.js").Result} */ let result = "success"; const type = pack.metadata.type; const migrateDocument = { Item: migrateItem, Actor: migrateActor, Scene: migrateScene, }[type]; if (migrateDocument) { const wasLocked = pack.locked; await pack.configure({ locked: false }); if (migrateToTemplateEarly) { await pack.migrate(); } const documents = await pack.getDocuments(); for (const doc of documents) { try { logger.info(`Migrating document ${doc.name} (${doc.id}) in compendium ${pack.collection}`); await migrateDocument(doc); } catch (err) { logger.error( `Error during migration of document ${doc.name} (${doc.id}) in compendium ${pack.collection}, continuing anyways.`, err, ); result = "error"; } } if (!migrateToTemplateEarly) { await pack.migrate(); } await pack.configure({ locked: wasLocked }); } return result; }; }