From 96f090bef5b49385b4dbac2160704c797e2ed8f0 Mon Sep 17 00:00:00 2001 From: Carlos Fernandez Date: Sun, 14 Jun 2026 16:10:49 -0400 Subject: [PATCH] Enable no unused vars and add more types (#2005) --- .vscode/settings.json | 3 ++ daggerheart.d.ts | 40 +++++++++++++++++++ eslint.config.mjs | 18 ++++++++- jsconfig.json | 2 +- .../dialogs/damageReductionDialog.mjs | 1 - module/applications/levelup/levelup.mjs | 1 - .../settings/appearanceSettings.mjs | 3 +- module/applications/sheets/actors/_types.d.ts | 8 ++++ module/applications/sheets/api/base-actor.mjs | 6 ++- module/data/actor/_types.d.ts | 14 +++++++ module/data/actor/base.mjs | 10 ++++- module/data/fields/formulaField.mjs | 2 +- module/data/item/_types.d.ts | 8 ++++ module/data/registeredTriggers.mjs | 2 +- module/dice/dhRoll.mjs | 8 ++++ module/documents/_types.d.ts | 22 ++++++++++ module/documents/activeEffect.mjs | 2 +- module/documents/actor.mjs | 16 +------- module/enrichers/FateRollEnricher.mjs | 2 +- module/helpers/utils.mjs | 4 +- 20 files changed, 141 insertions(+), 31 deletions(-) create mode 100644 .vscode/settings.json create mode 100644 module/applications/sheets/actors/_types.d.ts create mode 100644 module/data/actor/_types.d.ts create mode 100644 module/data/item/_types.d.ts create mode 100644 module/documents/_types.d.ts diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 00000000..b472f383 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "js/ts.preferGoToSourceDefinition": true +} \ No newline at end of file diff --git a/daggerheart.d.ts b/daggerheart.d.ts index 7ff7fd59..1641faa8 100644 --- a/daggerheart.d.ts +++ b/daggerheart.d.ts @@ -2,6 +2,7 @@ import '@client/global.mjs'; import '@common/global.mjs'; import '@common/primitives/global.mjs'; import Canvas from '@client/canvas/board.mjs'; +import { ResourceUpdateMap } from './module/data/action/baseAction.mjs'; // Foundry's use of `Object.assign(globalThis) means many globally available objects are not read as such // This declare global hopefully fixes that @@ -39,4 +40,43 @@ declare global { const Collection: foundry.utils.Collection; const FormDataExtended: foundry.applications.ux.FormDataExtended; const TextEditor: foundry.applications.ux.TextEditor; + + /** + * Data used to build rolls such as duality rolls. The definition is incomplete and likely incorrect. + * Objects will often accept a Partial and spit out a non-partial. Those that are not guaranteed should be marked optional. + */ + interface RollConfig { + // unverified, check which ones are used and optional/not optional + event: Event; + title: string; + roll: { + modifier: number; + simple: boolean; + type: string; + difficulty: number; + }; + hasDamage: boolean; + hasEffect: boolean; + hasRoll: boolean; + chatMessage: { + template: string; + mute: boolean; + }; + targets: object; + costs: object; + + // verified + source?: { + /** uuid of the actor this roll is coming from */ + actor: string; + }; + /** Roll data associated with the actor or item */ + data: object; + resourceUpdates: ResourceUpdateMap; + hooks: string[]; + dialog: { + configure: boolean; + }; + damageOptions: object; + } } diff --git a/eslint.config.mjs b/eslint.config.mjs index 3c9b8fd9..74141cc8 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -90,12 +90,26 @@ export default defineConfig([ }, rules: { 'no-undef': 'error', - // 'no-unused-vars': ['error', { argsIgnorePattern: '^_', varsIgnorePattern: '^_' }], + 'no-unused-vars': [ + 'error', + { + args: 'none', + destructuredArrayIgnorePattern: '^_', + varsIgnorePattern: '^_[A-Z]', + ignoreRestSiblings: true + } + ], ...stylisticRules } }, { files: ['**/*.ts'], - extends: [js.configs.recommended, tseslint.configs.recommended] + extends: [js.configs.recommended, tseslint.configs.recommended], + plugins: { + '@stylistic': stylistic + }, + rules: { + ...stylisticRules + } } ]); diff --git a/jsconfig.json b/jsconfig.json index a0d51d0b..42c4b404 100644 --- a/jsconfig.json +++ b/jsconfig.json @@ -8,7 +8,7 @@ } }, "exclude": ["node_modules", "**/node_modules/*"], - "include": ["daggerheart.mjs", "foundry/client/client.mjs", "daggerheart.d.ts"], + "include": ["daggerheart.mjs", "foundry/client/client.mjs", "daggerheart.d.ts", "module/**/*.d.ts"], "typeAcquisition": { "include": ["jquery"] } diff --git a/module/applications/dialogs/damageReductionDialog.mjs b/module/applications/dialogs/damageReductionDialog.mjs index e5108e34..8cb026f0 100644 --- a/module/applications/dialogs/damageReductionDialog.mjs +++ b/module/applications/dialogs/damageReductionDialog.mjs @@ -176,7 +176,6 @@ export default class DamageReductionDialog extends HandlebarsApplicationMixin(Ap } static updateData(event, _, formData) { - const form = foundry.utils.expandObject(formData.object); this.render(true); } diff --git a/module/applications/levelup/levelup.mjs b/module/applications/levelup/levelup.mjs index cafc5c89..f40609a4 100644 --- a/module/applications/levelup/levelup.mjs +++ b/module/applications/levelup/levelup.mjs @@ -1,4 +1,3 @@ -import { abilities, subclassFeatureLabels } from '../../config/actorConfig.mjs'; import { getDeleteKeys, tagifyElement } from '../../helpers/utils.mjs'; const { HandlebarsApplicationMixin, ApplicationV2 } = foundry.applications.api; diff --git a/module/applications/settings/appearanceSettings.mjs b/module/applications/settings/appearanceSettings.mjs index 9de9e752..f2defffb 100644 --- a/module/applications/settings/appearanceSettings.mjs +++ b/module/applications/settings/appearanceSettings.mjs @@ -1,12 +1,13 @@ -import DhAppearance from '../../data/settings/Appearance.mjs'; import { getDiceSoNicePreset } from '../../config/generalConfig.mjs'; const { HandlebarsApplicationMixin, ApplicationV2 } = foundry.applications.api; /** + * @import DhAppearance from '../../data/settings/Appearance.mjs'; * @import {ApplicationClickAction} from "@client/applications/_types.mjs" */ +/** Settings menu for appearance settings */ export default class DHAppearanceSettings extends HandlebarsApplicationMixin(ApplicationV2) { /**@inheritdoc */ static DEFAULT_OPTIONS = { diff --git a/module/applications/sheets/actors/_types.d.ts b/module/applications/sheets/actors/_types.d.ts new file mode 100644 index 00000000..89adc57b --- /dev/null +++ b/module/applications/sheets/actors/_types.d.ts @@ -0,0 +1,8 @@ +import DhCompanion from '../../../data/actor/companion.mjs'; +import DhpActor from '../../../documents/actor.mjs'; + +declare module './companion.mjs' { + export default interface DhCompanionSheet { + actor: DhpActor; + } +} diff --git a/module/applications/sheets/api/base-actor.mjs b/module/applications/sheets/api/base-actor.mjs index 027dd397..e65745c0 100644 --- a/module/applications/sheets/api/base-actor.mjs +++ b/module/applications/sheets/api/base-actor.mjs @@ -1,10 +1,12 @@ import { getDocFromElement, itemIsIdentical } from '../../../helpers/utils.mjs'; -import DHBaseActorSettings from './actor-setting.mjs'; import DHApplicationMixin from './application-mixin.mjs'; const { ActorSheetV2 } = foundry.applications.sheets; -/**@typedef {import('@client/applications/_types.mjs').ApplicationClickAction} ApplicationClickAction */ +/** + * @import DHBaseActorSettings from './actor-setting.mjs'; + * @typedef {import('@client/applications/_types.mjs').ApplicationClickAction} ApplicationClickAction + */ /** * A base actor sheet extending {@link ActorSheetV2} via {@link DHApplicationMixin} diff --git a/module/data/actor/_types.d.ts b/module/data/actor/_types.d.ts new file mode 100644 index 00000000..fec6e638 --- /dev/null +++ b/module/data/actor/_types.d.ts @@ -0,0 +1,14 @@ +import DhpActor from '../../documents/actor.mjs' +import DhCharacter from './character.mjs'; + +declare module './base.mjs' { + export default interface BaseDataActor { + parent: DhpActor; + } +} + +declare module './companion.mjs' { + export default interface DhCompanion { + partner: DhpActor; + } +} diff --git a/module/data/actor/base.mjs b/module/data/actor/base.mjs index 9efbe7d7..995708eb 100644 --- a/module/data/actor/base.mjs +++ b/module/data/actor/base.mjs @@ -1,9 +1,13 @@ -import DHBaseActorSettings from '../../applications/sheets/api/actor-setting.mjs'; -import DHItem from '../../documents/item.mjs'; import { createShallowProxy, getScrollTextData } from '../../helpers/utils.mjs'; const fields = foundry.data.fields; +/** + * @import DHItem from '../../documents/item.mjs'; + * @import DHBaseActorSettings from '../../applications/sheets/api/actor-setting.mjs'; + */ + +/** Function to generate resistance fields for damage types */ const resistanceField = (resistanceLabel, immunityLabel, reductionLabel) => new fields.SchemaField({ resistance: new fields.BooleanField({ @@ -96,6 +100,8 @@ export const commonActorRules = (extendedData = { damageReduction: {}, attack: { * @property {Boolean} isNPC - This data model represents a NPC? * @property {typeof DHBaseActorSettings} settingSheet - The sheet class used to render the settings UI for this actor type. */ + +/** Base actor type data model for all actors in Daggerheart */ export default class BaseDataActor extends foundry.abstract.TypeDataModel { /** @returns {ActorDataModelMetadata}*/ static get metadata() { diff --git a/module/data/fields/formulaField.mjs b/module/data/fields/formulaField.mjs index 85922f1f..c465bec3 100644 --- a/module/data/fields/formulaField.mjs +++ b/module/data/fields/formulaField.mjs @@ -39,7 +39,7 @@ export default class FormulaField extends foundry.data.fields.StringField { let roll = null; try { roll = new Roll(value.replace(/@([a-z.0-9_-]+)/gi, '1')); - } catch (_) { + } catch { roll = new Roll(value.replace(/@([a-z.0-9_-]+)/gi, 'd6')); } roll.evaluateSync({ strict: false }); diff --git a/module/data/item/_types.d.ts b/module/data/item/_types.d.ts new file mode 100644 index 00000000..6004e13b --- /dev/null +++ b/module/data/item/_types.d.ts @@ -0,0 +1,8 @@ +import DHItem from '../../documents/item.mjs'; + +declare module './base.mjs' { + export default interface BaseDataItem { + parent: DHItem; + actor: DhpActor; + } +} \ No newline at end of file diff --git a/module/data/registeredTriggers.mjs b/module/data/registeredTriggers.mjs index ab86351c..0b637930 100644 --- a/module/data/registeredTriggers.mjs +++ b/module/data/registeredTriggers.mjs @@ -149,7 +149,7 @@ export default class RegisteredTriggers extends Map { const result = await command(...args); if (result?.updates?.length) updates.push(...result.updates); - } catch (_) { + } catch { const triggerName = game.i18n.localize(triggerData.label); ui.notifications.error( game.i18n.format('DAGGERHEART.CONFIG.Triggers.triggerError', { diff --git a/module/dice/dhRoll.mjs b/module/dice/dhRoll.mjs index c28db98f..1c6ec829 100644 --- a/module/dice/dhRoll.mjs +++ b/module/dice/dhRoll.mjs @@ -23,6 +23,10 @@ export default class DHRoll extends Roll { static DefaultDialog = D20RollDialog; + /** + * @param {Partial} config + * @returns {Promise} + */ static async build(config = {}, message = {}) { const roll = await this.buildConfigure(config, message); if (!roll) return; @@ -34,6 +38,10 @@ export default class DHRoll extends Roll { return config; } + /** + * @param {Partial} config + * @returns {Promise} + */ static async buildConfigure(config = {}, message = {}) { config.hooks = [...this.getHooks(), '']; config.dialog ??= {}; diff --git a/module/documents/_types.d.ts b/module/documents/_types.d.ts new file mode 100644 index 00000000..a94d6395 --- /dev/null +++ b/module/documents/_types.d.ts @@ -0,0 +1,22 @@ +import BaseDataActor from '../data/actor/base.mjs' +import DHItem from './item.mjs'; +import BaseDataItem from '../data/item/base.mjs'; +import DhActiveEffect from './activeEffect.mjs'; +import EmbeddedCollection from '@common/abstract/embedded-collection.mjs'; + +declare module './actor.mjs' { + export default interface DhpActor { + system: T; + items: EmbeddedCollection; + effects: EmbeddedCollection; + } +} + +declare module './item.mjs' { + export default interface DHItem { + parent: DhpActor; + actor: DhpActor; + system: T; + effects: EmbeddedCollection; + } +} \ No newline at end of file diff --git a/module/documents/activeEffect.mjs b/module/documents/activeEffect.mjs index 3518210b..0e7f5d1e 100644 --- a/module/documents/activeEffect.mjs +++ b/module/documents/activeEffect.mjs @@ -212,7 +212,7 @@ export default class DhActiveEffect extends foundry.documents.ActiveEffect { try { const evl = new Function('sandbox', `with (sandbox) { return ${expression}}`); result = evl(Roll.MATH_PROXY); - } catch (err) { + } catch { return expression; } diff --git a/module/documents/actor.mjs b/module/documents/actor.mjs index fb10435f..1642ed30 100644 --- a/module/documents/actor.mjs +++ b/module/documents/actor.mjs @@ -531,21 +531,7 @@ export default class DhpActor extends Actor { } /** - * @param {object} config - * @param {Event} config.event - * @param {string} config.title - * @param {object} config.roll - * @param {number} config.roll.modifier - * @param {boolean} [config.roll.simple=false] - * @param {string} [config.roll.type] - * @param {number} [config.roll.difficulty] - * @param {boolean} [config.hasDamage] - * @param {boolean} [config.hasEffect] - * @param {object} [config.chatMessage] - * @param {string} config.chatMessage.template - * @param {boolean} [config.chatMessage.mute] - * @param {object} [config.targets] - * @param {object} [config.costs] + * @param {Partial} config */ async diceRoll(config) { config.source = { ...(config.source ?? {}), actor: this.uuid }; diff --git a/module/enrichers/FateRollEnricher.mjs b/module/enrichers/FateRollEnricher.mjs index c82bbcb2..8513ed94 100644 --- a/module/enrichers/FateRollEnricher.mjs +++ b/module/enrichers/FateRollEnricher.mjs @@ -49,7 +49,7 @@ export const renderFateButton = async event => { const fateTypeData = getFateTypeData(button.dataset?.fatetype); if (!fateTypeData) ui.notifications.error(game.i18n.localize('DAGGERHEART.UI.Notifications.fateTypeParsing')); - const { value: fateType, label: fateTypeLabel } = fateTypeData; + const { value: fateType } = fateTypeData; await enrichedFateRoll( { diff --git a/module/helpers/utils.mjs b/module/helpers/utils.mjs index 90a5c29d..3c5192be 100644 --- a/module/helpers/utils.mjs +++ b/module/helpers/utils.mjs @@ -318,7 +318,7 @@ export function getDocFromElementSync(element) { const target = element.closest('[data-item-uuid]'); try { return foundry.utils.fromUuidSync(target.dataset.itemUuid) ?? null; - } catch (_) { + } catch { return null; } } @@ -377,7 +377,7 @@ export const itemAbleRollParse = (value, actor, item) => { try { return Roll.replaceFormulaData(slicedValue, rollData); - } catch (_) { + } catch { return ''; } };