From 124824da8399ca27e063c8e56b203473648ec7b8 Mon Sep 17 00:00:00 2001 From: Johannes Loher Date: Sun, 9 Jul 2023 20:53:18 +0200 Subject: [PATCH] refactor: update each document individually during migrations --- src/migration/001.js | 30 ++-- src/migration/002.js | 37 +++-- src/migration/003.js | 41 +++-- src/migration/004.js | 55 ++++--- src/migration/005.js | 49 +++--- src/migration/006.js | 63 ++++---- src/migration/007.js | 42 +++-- src/migration/008.js | 41 +++-- src/migration/migration.js | 22 +-- src/migration/migrationHelpers.js | 250 ++++++++++-------------------- 10 files changed, 255 insertions(+), 375 deletions(-) diff --git a/src/migration/001.js b/src/migration/001.js index 1ea3b956..b0b67cf8 100644 --- a/src/migration/001.js +++ b/src/migration/001.js @@ -2,24 +2,18 @@ // // SPDX-License-Identifier: MIT -import { - getCompendiumMigrator, - getSceneUpdateDataGetter, - migrateActors, - migrateCompendiums, - migrateScenes, -} from "./migrationHelpers"; +import { getSceneMigrator, migrateCollection, migrateCompendiums, getCompendiumMigrator } from "./migrationHelpers.js"; -/** @type {import("./migration").Migration["migrate"]} */ +/** @type {import("./migration.js").Migration["migrate"]} */ async function migrate() { - await migrateActors(getActorUpdateData); - await migrateScenes(getSceneUpdateData); + await migrateCollection(game.actors, migrateActor); + await migrateCollection(game.scenes, migrateScene); await migrateCompendiums(migrateCompendium); } -/** @type {import("./migrationHelpers").ActorUpdateDataGetter} */ -function getActorUpdateData() { - const updateData = { +/** @type {import('./migrationHelpers.js').Migrator} */ +async function migrateActor(actor) { + await actor.update({ system: { combatValues: [ "hitPoints", @@ -35,14 +29,14 @@ function getActorUpdateData() { return acc; }, {}), }, - }; - return updateData; + }); } -const getSceneUpdateData = getSceneUpdateDataGetter(getActorUpdateData); -const migrateCompendium = getCompendiumMigrator({ getActorUpdateData, getSceneUpdateData }); +const migrateScene = getSceneMigrator(migrateActor); -/** @type {import("./migration").Migration} */ +const migrateCompendium = getCompendiumMigrator({ migrateActor, migrateScene }); + +/** @type {import("./migration.js").Migration} */ export const migration = { migrate, migrateCompendium, diff --git a/src/migration/002.js b/src/migration/002.js index 17d9fe90..f2848060 100644 --- a/src/migration/002.js +++ b/src/migration/002.js @@ -3,37 +3,36 @@ // SPDX-License-Identifier: MIT import { - getActorUpdateDataGetter, - getCompendiumMigrator, - getSceneUpdateDataGetter, - migrateActors, + getSceneMigrator, + migrateCollection, migrateCompendiums, - migrateItems, - migrateScenes, -} from "./migrationHelpers"; + getCompendiumMigrator, + getActorMigrator, +} from "./migrationHelpers.js"; -/** @type {import("./migration").Migration["migrate"]} */ +/** @type {import("./migration.js").Migration["migrate"]} */ async function migrate() { - await migrateItems(getItemUpdateData); - await migrateActors(getActorUpdateData); - await migrateScenes(getSceneUpdateData); + await migrateCollection(game.items, migrateItem); + await migrateCollection(game.actors, migrateActor); + await migrateCollection(game.scenes, migrateScene); await migrateCompendiums(migrateCompendium); } -/** @type {import("./migrationHelpers").ItemUpdateDataGetter} */ -function getItemUpdateData(itemData) { - if (!["equipment", "trinket"].includes(itemData.type ?? "")) return undefined; - return { type: itemData.type === "equipment" ? "loot" : "equipment" }; +/** @type {import('./migrationHelpers.js').Migrator} */ +async function migrateItem(item) { + if (item.type === "equipment" || item.type === "trinket") { + await item.update({ type: item.type === "equipment" ? "loot" : "equipment" }); + } } -const getActorUpdateData = getActorUpdateDataGetter(getItemUpdateData); -const getSceneUpdateData = getSceneUpdateDataGetter(getActorUpdateData); +const migrateActor = getActorMigrator(migrateItem); +const migrateScene = getSceneMigrator(migrateActor); const migrateCompendium = getCompendiumMigrator( - { getItemUpdateData, getActorUpdateData, getSceneUpdateData }, + { migrateItem, migrateActor, migrateScene }, { migrateToTemplateEarly: false }, ); -/** @type {import("./migration").Migration} */ +/** @type {import("./migration.js").Migration} */ export const migration = { migrate, migrateCompendium, diff --git a/src/migration/003.js b/src/migration/003.js index 28df66dd..4d62321e 100644 --- a/src/migration/003.js +++ b/src/migration/003.js @@ -3,41 +3,36 @@ // SPDX-License-Identifier: MIT import { - getActorUpdateDataGetter, - getCompendiumMigrator, - getSceneUpdateDataGetter, - migrateActors, + getSceneMigrator, + migrateCollection, migrateCompendiums, - migrateItems, - migrateScenes, -} from "./migrationHelpers"; + getCompendiumMigrator, + getActorMigrator, +} from "./migrationHelpers.js"; -/** @type {import("./migration").Migration["migrate"]} */ +/** @type {import("./migration.js").Migration["migrate"]} */ async function migrate() { - await migrateItems(getItemUpdateData); - await migrateActors(getActorUpdateData); - await migrateScenes(getSceneUpdateData); + await migrateCollection(game.items, migrateItem); + await migrateCollection(game.actors, migrateActor); + await migrateCollection(game.scenes, migrateScene); await migrateCompendiums(migrateCompendium); } -/** @type {import("./migrationHelpers").ItemUpdateDataGetter} */ -function getItemUpdateData(itemData) { - if (!["loot"].includes(itemData.type ?? "")) return undefined; - return { - system: { - "-=equipped": null, - }, - }; +/** @type {import("./migrationHelpers.js").Migrator} */ +async function migrateItem(item) { + if (item.type === "loot") { + await item.update({ system: { "-=equipped": null } }); + } } -const getActorUpdateData = getActorUpdateDataGetter(getItemUpdateData); -const getSceneUpdateData = getSceneUpdateDataGetter(getActorUpdateData); +const migrateActor = getActorMigrator(migrateItem); +const migrateScene = getSceneMigrator(migrateActor); const migrateCompendium = getCompendiumMigrator( - { getItemUpdateData, getActorUpdateData }, + { migrateItem, migrateActor, migrateScene }, { migrateToTemplateEarly: false }, ); -/** @type {import("./migration").Migration} */ +/** @type {import("./migration.js").Migration} */ export const migration = { migrate, migrateCompendium, diff --git a/src/migration/004.js b/src/migration/004.js index 3f1b9168..d211ae6a 100644 --- a/src/migration/004.js +++ b/src/migration/004.js @@ -3,45 +3,44 @@ // SPDX-License-Identifier: MIT import { - getActorUpdateDataGetter, - getCompendiumMigrator, - getSceneUpdateDataGetter, - migrateActors, + getSceneMigrator, + migrateCollection, migrateCompendiums, - migrateItems, - migrateScenes, -} from "./migrationHelpers"; + getCompendiumMigrator, + getActorMigrator, +} from "./migrationHelpers.js"; -/** @type {import("./migration").Migration["migrate"]} */ +/** @type {import("./migration.js").Migration["migrate"]} */ async function migrate() { - await migrateItems(getItemUpdateData); - await migrateActors(getActorUpdateData); - await migrateScenes(getSceneUpdateData); + await migrateCollection(game.items, migrateItem); + await migrateCollection(game.actors, migrateActor); + await migrateCollection(game.scenes, migrateScene); await migrateCompendiums(migrateCompendium); } -/** @type {import("./migrationHelpers").ItemUpdateDataGetter} */ -function getItemUpdateData(itemData) { - if (itemData.type !== "spell") return; - const cooldownDurationUnit = itemData.system?.cooldownDuration.unit; - - const updateData = { - system: { - "-=scrollPrice": null, - minimumLevels: { healer: null, wizard: null, sorcerer: null }, - cooldownDuration: { - unit: cooldownDurationUnit === "custom" ? "rounds" : cooldownDurationUnit, +/** @type {import('./migrationHelpers.js').Migrator} */ +async function migrateItem(item) { + if (item.type === "spell") { + const cooldownDurationUnit = item.system?.cooldownDuration.unit; + await item.update({ + system: { + "-=scrollPrice": null, + minimumLevels: { healer: null, wizard: null, sorcerer: null }, + cooldownDuration: { + unit: cooldownDurationUnit === "custom" ? "rounds" : cooldownDurationUnit, + }, }, - }, - }; + }); + } + return updateData; } -const getActorUpdateData = getActorUpdateDataGetter(getItemUpdateData); -const getSceneUpdateData = getSceneUpdateDataGetter(getActorUpdateData); -const migrateCompendium = getCompendiumMigrator({ getItemUpdateData, getActorUpdateData, getSceneUpdateData }); +const migrateActor = getActorMigrator(migrateItem); +const migrateScene = getSceneMigrator(migrateActor); +const migrateCompendium = getCompendiumMigrator({ migrateItem, migrateActor, migrateScene }); -/** @type {import("./migration").Migration} */ +/** @type {import("./migration.js").Migration} */ export const migration = { migrate, migrateCompendium, diff --git a/src/migration/005.js b/src/migration/005.js index e91903ee..faeebd94 100644 --- a/src/migration/005.js +++ b/src/migration/005.js @@ -3,14 +3,12 @@ // SPDX-License-Identifier: MIT import { - getActorUpdateDataGetter, - getCompendiumMigrator, - getSceneUpdateDataGetter, - migrateActors, + getSceneMigrator, + migrateCollection, migrateCompendiums, - migrateItems, - migrateScenes, -} from "./migrationHelpers"; + getCompendiumMigrator, + getActorMigrator, +} from "./migrationHelpers.js"; const secondsPerRound = 5; const secondsPerMinute = 60; @@ -21,27 +19,22 @@ const hoursPerDay = 24; const roundsPerDay = hoursPerDay / roundsPerHour; const secondsPerDay = secondsPerMinute * minutesPerHour * hoursPerDay; -/** @type {import("./migration").Migration["migrate"]} */ +/** @type {import("./migration.js").Migration["migrate"]} */ async function migrate() { - await migrateItems(getItemUpdateData); - await migrateActors(getActorUpdateData); - await migrateScenes(getSceneUpdateData); + await migrateCollection(game.items, migrateItem); + await migrateCollection(game.actors, migrateActor); + await migrateCollection(game.scenes, migrateScene); await migrateCompendiums(migrateCompendium); } -/** @type {import("./migrationHelpers").ItemUpdateDataGetter} */ -function getItemUpdateData(itemData) { - if (itemData.type !== "spell") return; - const cooldownDurationUnit = itemData.system?.cooldownDuration.unit; - const cooldownDurationValue = itemData.system?.cooldownDuration.value; - const cooldownDuration = migrateCooldownDuration(cooldownDurationValue, cooldownDurationUnit); - - const updateData = { - system: { - cooldownDuration, - }, - }; - return updateData; +/** @type {import('./migrationHelpers.js').Migrator} */ +async function migrateItem(item) { + if (item.type === "spell") { + const cooldownDurationUnit = item.system?.cooldownDuration.unit; + const cooldownDurationValue = item.system?.cooldownDuration.value; + const cooldownDuration = migrateCooldownDuration(cooldownDurationValue, cooldownDurationUnit); + await item.update({ system: { cooldownDuration } }); + } } function migrateCooldownDuration(cooldownDurationValue = "", cooldownDurationUnit = "") { @@ -114,11 +107,11 @@ function getRounds(unit, value) { } } -const getActorUpdateData = getActorUpdateDataGetter(getItemUpdateData); -const getSceneUpdateData = getSceneUpdateDataGetter(getActorUpdateData); -const migrateCompendium = getCompendiumMigrator({ getItemUpdateData, getActorUpdateData, getSceneUpdateData }); +const migrateActor = getActorMigrator(migrateItem); +const migrateScene = getSceneMigrator(migrateActor); +const migrateCompendium = getCompendiumMigrator({ migrateItem, migrateActor, migrateScene }); -/** @type {import("./migration").Migration} */ +/** @type {import("./migration.js").Migration} */ export const migration = { migrate, migrateCompendium, diff --git a/src/migration/006.js b/src/migration/006.js index 0f49cfc1..3afceaa9 100644 --- a/src/migration/006.js +++ b/src/migration/006.js @@ -3,42 +3,37 @@ // SPDX-License-Identifier: MIT import { - getActorUpdateDataGetter, - getCompendiumMigrator, - getSceneUpdateDataGetter, - migrateActors, + getSceneMigrator, + migrateCollection, migrateCompendiums, - migrateItems, - migrateScenes, -} from "./migrationHelpers"; + getCompendiumMigrator, + getActorMigrator, +} from "./migrationHelpers.js"; -/** @type {import("./migration").Migration["migrate"]} */ +/** @type {import("./migration.js").Migration["migrate"]} */ async function migrate() { - await migrateItems(getItemUpdateData); - await migrateActors(getActorUpdateData); - await migrateScenes(getSceneUpdateData); + await migrateCollection(game.items, migrateItem); + await migrateCollection(game.actors, migrateActor); + await migrateCollection(game.scenes, migrateScene); await migrateCompendiums(migrateCompendium); } -/** @type {import("./migrationHelpers").ItemUpdateDataGetter} */ -function getItemUpdateData(itemData) { - if (itemData.type !== "spell") return; - const spellCategory = itemData.system?.spellCategory; - const spellGroups = migrateSpellCategory(spellCategory); - - // @ts-expect-error bonus is removed with this migration - const bonus = itemData.system?.bonus; - const spellModifier = migrateBonus(bonus); - - const updateData = { - system: { - spellGroups, - "-=spellCategory": null, - spellModifier, - "-=bonus": null, - }, - }; - return updateData; +/** @type {import('./migrationHelpers.js').Migrator} */ +async function migrateItem(item) { + if (item.type === "spell") { + const spellCategory = item.system?.spellCategory; + const spellGroups = migrateSpellCategory(spellCategory); + const bonus = itemData.system?.bonus; + const spellModifier = migrateBonus(bonus); + await item.update({ + system: { + spellGroups, + "-=spellCategory": null, + spellModifier, + "-=bonus": null, + }, + }); + } } /** @@ -116,11 +111,11 @@ function migrateBonus(bonus) { return spellModifier; } -const getActorUpdateData = getActorUpdateDataGetter(getItemUpdateData); -const getSceneUpdateData = getSceneUpdateDataGetter(getActorUpdateData); -const migrateCompendium = getCompendiumMigrator({ getItemUpdateData, getActorUpdateData, getSceneUpdateData }); +const migrateActor = getActorMigrator(migrateItem); +const migrateScene = getSceneMigrator(migrateActor); +const migrateCompendium = getCompendiumMigrator({ migrateItem, migrateActor, migrateScene }); -/** @type {import("./migration").Migration} */ +/** @type {import("./migration.js").Migration} */ export const migration = { migrate, migrateCompendium, diff --git a/src/migration/007.js b/src/migration/007.js index 540901ea..70a64437 100644 --- a/src/migration/007.js +++ b/src/migration/007.js @@ -3,39 +3,33 @@ // SPDX-License-Identifier: MIT import { - getActorUpdateDataGetter, - getCompendiumMigrator, - getSceneUpdateDataGetter, - migrateActors, + getSceneMigrator, + migrateCollection, migrateCompendiums, - migrateItems, - migrateScenes, -} from "./migrationHelpers"; + getCompendiumMigrator, + getActorMigrator, +} from "./migrationHelpers.js"; -/** @type {import("./migration").Migration["migrate"]} */ +/** @type {import("./migration.js").Migration["migrate"]} */ async function migrate() { - await migrateItems(getItemUpdateData); - await migrateActors(getActorUpdateData); - await migrateScenes(getSceneUpdateData); + await migrateCollection(game.items, migrateItem); + await migrateCollection(game.actors, migrateActor); + await migrateCollection(game.scenes, migrateScene); await migrateCompendiums(migrateCompendium); } -/** @type {import("./migrationHelpers").ItemUpdateDataGetter} */ -function getItemUpdateData(itemData) { - if (itemData.type !== "spell") return; - - return { - system: { - allowsDefense: false, - }, - }; +/** @type {import('./migrationHelpers.js').Migrator} */ +async function migrateItem(item) { + if (item.type === "spell") { + await item.update({ system: { allowsDefense: false } }); + } } -const getActorUpdateData = getActorUpdateDataGetter(getItemUpdateData); -const getSceneUpdateData = getSceneUpdateDataGetter(getActorUpdateData); -const migrateCompendium = getCompendiumMigrator({ getItemUpdateData, getActorUpdateData, getSceneUpdateData }); +const migrateActor = getActorMigrator(migrateItem); +const migrateScene = getSceneMigrator(migrateActor); +const migrateCompendium = getCompendiumMigrator({ migrateItem, migrateActor, migrateScene }); -/** @type {import("./migration").Migration} */ +/** @type {import("./migration.js").Migration} */ export const migration = { migrate, migrateCompendium, diff --git a/src/migration/008.js b/src/migration/008.js index bb04b1da..e517c429 100644 --- a/src/migration/008.js +++ b/src/migration/008.js @@ -3,28 +3,27 @@ // SPDX-License-Identifier: MIT import { - getActorUpdateDataGetter, - getCompendiumMigrator, - getItemUpdateDataGetter, - getSceneUpdateDataGetter, - migrateActors, + getSceneMigrator, + migrateCollection, migrateCompendiums, - migrateItems, - migrateScenes, -} from "./migrationHelpers"; + getCompendiumMigrator, + getActorMigrator, + getItemMigrator, +} from "./migrationHelpers.js"; -/** @type {import("./migration").Migration["migrate"]} */ +/** @type {import("./migration.js").Migration["migrate"]} */ async function migrate() { - await migrateItems(getItemUpdateData); - await migrateActors(getActorUpdateData); - await migrateScenes(getSceneUpdateData); + await migrateCollection(game.items, migrateItem); + await migrateCollection(game.actors, migrateActor); + await migrateCollection(game.scenes, migrateScene); await migrateCompendiums(migrateCompendium); } -/** @type {import("./migrationHelpers").EffectUpdateDataGetter} */ -function getEffectUpdateData(effectData) { - const data = foundry.utils.deepClone(effectData); +/** @type {import('./migrationHelpers.js').Migrator} */ +async function migrateActiveEffect(activeEffect) { + const data = activeEffect.toObject(); let hasUpdates = false; + if ("changes" in data) { for (const change of data.changes) { const newValue = change.value.replaceAll(/@data\./g, "@system."); @@ -45,16 +44,16 @@ function getEffectUpdateData(effectData) { } } if (hasUpdates) { - return data; + await activeEffect.update(data); } } -const getItemUpdateData = getItemUpdateDataGetter(getEffectUpdateData); -const getActorUpdateData = getActorUpdateDataGetter(getItemUpdateData, getEffectUpdateData); -const getSceneUpdateData = getSceneUpdateDataGetter(getActorUpdateData); -const migrateCompendium = getCompendiumMigrator({ getItemUpdateData, getActorUpdateData, getSceneUpdateData }); +const migrateItem = getItemMigrator(migrateActiveEffect); +const migrateActor = getActorMigrator(migrateItem, migrateActiveEffect); +const migrateScene = getSceneMigrator(migrateActor); +const migrateCompendium = getCompendiumMigrator({ migrateItem, migrateActor, migrateScene }); -/** @type {import("./migration").Migration} */ +/** @type {import("./migration.js").Migration} */ export const migration = { migrate, migrateCompendium, diff --git a/src/migration/migration.js b/src/migration/migration.js index 093559a7..4664c9fd 100644 --- a/src/migration/migration.js +++ b/src/migration/migration.js @@ -2,17 +2,17 @@ // // SPDX-License-Identifier: MIT -import { notifications } from "../ui/notifications"; -import { logger } from "../utils/logger"; -import { getGame } from "../utils/utils"; -import { migration as migration001 } from "./001"; -import { migration as migration002 } from "./002"; -import { migration as migration003 } from "./003"; -import { migration as migration004 } from "./004"; -import { migration as migration005 } from "./005"; -import { migration as migration006 } from "./006"; -import { migration as migration007 } from "./007"; -import { migration as migration008 } from "./008"; +import { notifications } from "../ui/notifications.js"; +import { logger } from "../utils/logger.js"; +import { getGame } from "../utils/utils.js"; +import { migration as migration001 } from "./001.js"; +import { migration as migration002 } from "./002.js"; +import { migration as migration003 } from "./003.js"; +import { migration as migration004 } from "./004.js"; +import { migration as migration005 } from "./005.js"; +import { migration as migration006 } from "./006.js"; +import { migration as migration007 } from "./007.js"; +import { migration as migration008 } from "./008.js"; /** * Perform migrations. diff --git a/src/migration/migrationHelpers.js b/src/migration/migrationHelpers.js index 46b3304c..9b6b036a 100644 --- a/src/migration/migrationHelpers.js +++ b/src/migration/migrationHelpers.js @@ -2,82 +2,95 @@ // // SPDX-License-Identifier: MIT -import { DS4Actor } from "../documents/actor/actor"; -import { DS4Item } from "../documents/item/item"; -import { logger } from "../utils/logger"; -import { getGame } from "../utils/utils"; - -/** @typedef {(effectData: object) => Record | undefined} EffectUpdateDataGetter */ - -/** @typedef {(itemData: object) => Record | undefined} ItemUpdateDataGetter */ +import { DS4Actor } from "../documents/actor/actor.js"; +import { DS4Item } from "../documents/item/item.js"; +import { logger } from "../utils/logger.js"; +import { getGame } from "../utils/utils.js"; /** - * Migrate world items. - * @param {ItemUpdateDataGetter} getItemUpdateData A function for getting the update data for a given item data object - * @returns {Promise} A promise that resolves once the migration is complete + * @template T + * @typedef {(document: T) => Promise} Migrator */ -export async function migrateItems(getItemUpdateData) { - for (const item of getGame().items ?? []) { - try { - const updateData = getItemUpdateData(item.toObject()); - if (updateData) { - logger.info(`Migrating Item document ${item.name} (${item.id})`); - await item.update(updateData), { enforceTypes: false }; - } - } catch (err) { - logger.error(`Error during migration of Item document ${item.name} (${item.id}), continuing anyways.`, err); - } - } -} - -/** @typedef {(actorData: object>) => Record | undefined} ActorUpdateDataGetter */ /** - * Migrate world actors. - * @param {ActorUpdateDataGetter} getActorUpdateData A function for getting the update data for a given actor data object + * 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 migrateActors(getActorUpdateData) { - for (const actor of getGame().actors ?? []) { +export async function migrateCollection(collection, migrateDocument) { + const { documentName } = collection.constructor; + for (const document of collection) { + logger.info(`Migrating ${documentName} document ${document.name} (${document.id})`); try { - const updateData = getActorUpdateData(actor.toObject()); - if (updateData) { - logger.info(`Migrating Actor document ${actor.name} (${actor.id})`); - await actor.update(updateData); - } + await migrateDocument(document); } catch (err) { logger.error( - `Error during migration of Actor document ${actor.name} (${actor.id}), continuing anyways.`, + `Error during migration of ${documentName} document ${document.name} (${document.id}), continuing anyways.`, err, ); } } } -/** @typedef {(scene: Scene) => Record | undefined} SceneUpdateDataGetter */ +/** + * @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); + } + } + }; +} /** - * Migrate world scenes. - * @param {SceneUpdateDataGetter} getSceneUpdateData A function for getting the update data for a given scene data object - * @returns {Promise} A promise that resolves once the migration is complete + * @param {Migrator} [migrateItem] + * @param {Migrator} [migrateActiveEffect] + * @returns {Migrator} */ -export async function migrateScenes(getSceneUpdateData) { - for (const scene of getGame().scenes ?? []) { - try { - const updateData = getSceneUpdateData(scene); - if (updateData) { - logger.info(`Migrating Scene document ${scene.name} (${scene.id})`); - await scene.update(updateData); - // We need to clear the old syntehtic actors from the cache - scene.tokens.forEach((t) => (t._actor = null)); +export function getActorMigrator(migrateItem, migrateActiveEffect) { + /** + * @param {Actor} actor + */ + return async (actor) => { + if (migrateItem) { + for (const item of actor.items) { + await migrateItem(item); } - } catch (err) { - logger.error( - `Error during migration of Scene document ${scene.name} (${scene.id}), continuing anyways.`, - err, - ); } - } + 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 */ @@ -96,118 +109,20 @@ export async function migrateCompendiums(migrateCompendium) { } /** - * Get a function to create item update data based on the given function to update embedded documents. - * @param {EffectUpdateDataGetter} [getEffectUpdateData] A function to generate effect update data - * @returns {ItemUpdateDataGetter} A function to get item update data - */ -export function getItemUpdateDataGetter(getEffectUpdateData) { - return (itemData) => { - let hasEffectUpdates = false; - const effects = itemData.effects?.map((effectData) => { - const update = getEffectUpdateData(effectData); - if (update) { - hasEffectUpdates = true; - return foundry.utils.mergeObject(effectData, update, { inplace: false, performDeletions: true }); - } else { - return effectData; - } - }); - return hasEffectUpdates ? { effects } : undefined; - }; -} - -/** - * Get a function to create actor update data based on the given function to update embedded documents. - * @param {ItemUpdateDataGetter} [getItemUpdateData] A function to generate item update data - * @param {EffectUpdateDataGetter} [getEffectUpdateData] A function to generate effect update data - * @returns {ActorUpdateDataGetter} A function to get actor update data - */ -export function getActorUpdateDataGetter(getItemUpdateData, getEffectUpdateData) { - return (actorData) => { - let hasItemUpdates = false; - const items = actorData.items?.map((itemData) => { - const update = getItemUpdateData?.(itemData); - if (update) { - hasItemUpdates = true; - return foundry.utils.mergeObject(itemData, update, { inplace: false, performDeletions: true }); - } else { - return itemData; - } - }); - let hasEffectUpdates = false; - const effects = actorData.effects?.map((effectData) => { - const update = getEffectUpdateData?.(effectData); - if (update) { - hasEffectUpdates = true; - return foundry.utils.mergeObject(effectData, update, { inplace: false, performDeletions: true }); - } else { - return effectData; - } - }); - const result = { - items: hasItemUpdates ? items : undefined, - effects: hasEffectUpdates ? effects : undefined, - }; - return hasItemUpdates | hasEffectUpdates ? result : undefined; - }; -} - -/** - * Get a function to create scene update data that adjusts the actors of the tokens of the scene according to the given function. - * @param {ActorUpdateDataGetter} [getItemUpdateData] The function to generate actor update data - * @returns {SceneUpdateDataGetter} A function to get scene update data - */ -export function getSceneUpdateDataGetter(getActorUpdateData) { - return (scene) => { - const tokens = scene.tokens.map((token) => { - const t = token.toObject(); - if (!t.actorId || t.actorLink) { - t.actorData = {}; - } else if (!getGame().actors?.has(t.actorId)) { - t.actorId = null; - t.actorData = {}; - } else if (!t.actorLink) { - const actorData = foundry.utils.deepClone(t.actorData); - actorData.type = token.actor?.type; - const update = getActorUpdateData?.(actorData); - if (update !== undefined) { - ["items", "effects"].forEach((embeddedName) => { - const embeddedUpdates = update[embeddedName]; - if (!embeddedUpdates?.length) return; - const updates = new Map(embeddedUpdates.flatMap((u) => (u && u._id ? [[u._id, u]] : []))); - const originals = t.actorData[embeddedName]; - if (!originals) return; - originals.forEach((original) => { - if (!original._id) return; - const update = updates.get(original._id); - if (update) foundry.utils.mergeObject(original, update, { performDeletions: true }); - }); - delete update[embeddedName]; - }); - foundry.utils.mergeObject(t.actorData, update); - } - } - return t; - }); - return { tokens }; - }; -} - -/** - * @typedef {object} UpdateDataGetters - * @property {ItemUpdateDataGetter} [getItemUpdateData] - * @property {ActorUpdateDataGetter} [getActorUpdateData] - * @property {SceneUpdateDataGetter} [getSceneUpdateData] + * @typedef {object} Migrators + * @property {Migrator} [migrateItem] + * @property {Migrator} [migrateActor] + * @property {Migrator} [migrateScene] */ /** - * Get a compendium migrator for the given update data getters. - * @param {UpdateDataGetters} [updateDataGetters={}] The functions to use for getting update data + * 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( - { getItemUpdateData, getActorUpdateData, getSceneUpdateData } = {}, + { migrateItem, migrateActor, migrateScene } = {}, { migrateToTemplateEarly = true } = {}, ) { return async (pack) => { @@ -224,15 +139,12 @@ export function getCompendiumMigrator( for (const doc of documents) { try { logger.info(`Migrating document ${doc.name} (${doc.id}) in compendium ${pack.collection}`); - if (doc instanceof DS4Item && getItemUpdateData) { - const updateData = getItemUpdateData(doc.toObject()); - updateData && (await doc.update(updateData)); - } else if (doc instanceof DS4Actor && getActorUpdateData) { - const updateData = getActorUpdateData(doc.toObject()); - updateData && (await doc.update(updateData)); - } else if (doc instanceof Scene && getSceneUpdateData) { - const updateData = getSceneUpdateData(doc); - updateData && (await doc.update(updateData)); + if (doc instanceof DS4Item && migrateItem) { + await migrateItem(doc); + } else if (doc instanceof DS4Actor && migrateActor) { + await migrateActor(doc); + } else if (doc instanceof Scene && migrateScene) { + await migrateScene(doc); } } catch (err) { logger.error(