Add eslint and run linter in workflow

This commit is contained in:
Carlos Fernandez 2026-04-20 17:47:37 -04:00
parent f850cbda76
commit 69adeb7e0e
23 changed files with 974 additions and 36 deletions

View file

@ -1,3 +1,5 @@
[*] [*]
indent_size = 4 indent_size = 4
indent_style = spaces indent_style = spaces
[*.yml]
indent_size = 2

42
.github/workflows/ci.yml vendored Normal file
View file

@ -0,0 +1,42 @@
name: Project CI
on:
pull_request:
branches: [main]
push:
branches: [main]
workflow_dispatch:
branches: [main]
jobs:
build:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [24.x]
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}
- uses: pnpm/action-setup@v4
with:
version: 10
- name: Cache NPM Deps
id: cache-npm
uses: actions/cache@v3
with:
path: node_modules/
key: npm-${{ hashFiles('package-lock.json') }}
- name: Install NPM Deps
if: ${{ steps.cache-npm.outputs.cache-hit != 'true' }}
run: npm ci
- name: Lint
run: npm run lint

14
eslint.config.mjs Normal file
View file

@ -0,0 +1,14 @@
import globals from 'globals';
import { defineConfig } from 'eslint/config';
import prettier from 'eslint-plugin-prettier';
export default defineConfig([
{ files: ['**/*.{js,mjs,cjs}'], languageOptions: { globals: globals.browser } },
{ plugins: { prettier } },
{
files: ['**/*.{js,mjs,cjs}'],
rules: {
'prettier/prettier': 'error'
}
}
]);

View file

@ -173,7 +173,7 @@ export default class CharacterSheet extends DHBaseActorSheet {
// Overriden to only disable text inputs by default. // Overriden to only disable text inputs by default.
// Everything else is done by checking @root.editable in the sheet // Everything else is done by checking @root.editable in the sheet
const form = this.form; const form = this.form;
for (const input of form.querySelectorAll("input:not([type=search]), .editor.prosemirror")) { for (const input of form.querySelectorAll('input:not([type=search]), .editor.prosemirror')) {
input.disabled = disabled; input.disabled = disabled;
} }
} }

View file

@ -488,11 +488,10 @@ export default function DHApplicationMixin(Base) {
icon: 'fa-solid fa-explosion', icon: 'fa-solid fa-explosion',
visible: target => { visible: target => {
const doc = getDocFromElementSync(target); const doc = getDocFromElementSync(target);
return ( const hasDamage =
doc?.isOwner &&
!foundry.utils.isEmpty(doc?.system?.attack?.damage.parts) || !foundry.utils.isEmpty(doc?.system?.attack?.damage.parts) ||
!foundry.utils.isEmpty(doc?.damage?.parts) !foundry.utils.isEmpty(doc?.damage?.parts);
); return doc?.isOwner && hasDamage;
}, },
callback: async (target, event) => { callback: async (target, event) => {
const doc = await getDocFromElement(target), const doc = await getDocFromElement(target),

View file

@ -75,12 +75,17 @@ export const typeConfig = {
{ {
key: 'type', key: 'type',
label: 'DAGGERHEART.GENERAL.type', label: 'DAGGERHEART.GENERAL.type',
format: type => type ? `TYPES.Item.${type}` : '-' format: type => (type ? `TYPES.Item.${type}` : '-')
}, },
{ {
key: 'system.secondary', key: 'system.secondary',
label: 'DAGGERHEART.UI.ItemBrowser.subtype', label: 'DAGGERHEART.UI.ItemBrowser.subtype',
format: isSecondary => (isSecondary ? 'DAGGERHEART.ITEMS.Weapon.secondaryWeapon.short' : isSecondary === false ? 'DAGGERHEART.ITEMS.Weapon.primaryWeapon.short' : '-') format: isSecondary =>
isSecondary
? 'DAGGERHEART.ITEMS.Weapon.secondaryWeapon.short'
: isSecondary === false
? 'DAGGERHEART.ITEMS.Weapon.primaryWeapon.short'
: '-'
}, },
{ {
key: 'system.tier', key: 'system.tier',
@ -260,12 +265,12 @@ export const typeConfig = {
{ {
key: 'system.type', key: 'system.type',
label: 'DAGGERHEART.GENERAL.type', label: 'DAGGERHEART.GENERAL.type',
format: type => type ? `DAGGERHEART.CONFIG.DomainCardTypes.${type}` : '-' format: type => (type ? `DAGGERHEART.CONFIG.DomainCardTypes.${type}` : '-')
}, },
{ {
key: 'system.domain', key: 'system.domain',
label: 'DAGGERHEART.GENERAL.Domain.single', label: 'DAGGERHEART.GENERAL.Domain.single',
format: domain => domain ? CONFIG.DH.DOMAIN.allDomains()[domain].label : '-' format: domain => (domain ? CONFIG.DH.DOMAIN.allDomains()[domain].label : '-')
}, },
{ {
key: 'system.level', key: 'system.level',

View file

@ -42,7 +42,7 @@ export const gameSettings = {
SpotlightRequestQueue: 'SpotlightRequestQueue', SpotlightRequestQueue: 'SpotlightRequestQueue',
CompendiumBrowserSettings: 'CompendiumBrowserSettings', CompendiumBrowserSettings: 'CompendiumBrowserSettings',
SpotlightTracker: 'SpotlightTracker', SpotlightTracker: 'SpotlightTracker',
ActiveParty: 'ActiveParty', ActiveParty: 'ActiveParty'
}; };
export const actionAutomationChoices = { export const actionAutomationChoices = {

View file

@ -20,7 +20,7 @@ export default class DhCharacter extends DhCreature {
settingSheet: DHCharacterSettings, settingSheet: DHCharacterSettings,
isNPC: false, isNPC: false,
hasInventory: true, hasInventory: true,
quantifiable: ["loot", "consumable"] quantifiable: ['loot', 'consumable']
}); });
} }
@ -302,7 +302,7 @@ export default class DhCharacter extends DhCreature {
choices: CONFIG.DH.GENERAL.dieFaces, choices: CONFIG.DH.GENERAL.dieFaces,
initial: null, initial: null,
label: 'DAGGERHEART.ACTORS.Character.defaultDisadvantageDice' label: 'DAGGERHEART.ACTORS.Character.defaultDisadvantageDice'
}), })
}) })
}) })
}; };

View file

@ -78,7 +78,7 @@ export default class DhCompanion extends DhCreature {
choices: CONFIG.DH.GENERAL.dieFaces, choices: CONFIG.DH.GENERAL.dieFaces,
initial: null, initial: null,
label: 'DAGGERHEART.ACTORS.Character.defaultDisadvantageDice' label: 'DAGGERHEART.ACTORS.Character.defaultDisadvantageDice'
}), })
}) })
}), }),
attack: new ActionField({ attack: new ActionField({

View file

@ -9,7 +9,7 @@ export default class DhParty extends BaseDataActor {
static get metadata() { static get metadata() {
return foundry.utils.mergeObject(super.metadata, { return foundry.utils.mergeObject(super.metadata, {
hasInventory: true, hasInventory: true,
quantifiable: ["weapon", "armor", "loot", "consumable"] quantifiable: ['weapon', 'armor', 'loot', 'consumable']
}); });
} }

View file

@ -40,9 +40,7 @@ export default class DHSummonField extends fields.ArrayField {
const roll = new Roll(itemAbleRollParse(summon.count, this.actor, this.item)); const roll = new Roll(itemAbleRollParse(summon.count, this.actor, this.item));
await roll.evaluate(); await roll.evaluate();
const count = roll.total; const count = roll.total;
if (!roll.isDeterministic && game.modules.get('dice-so-nice')?.active) if (!roll.isDeterministic && game.modules.get('dice-so-nice')?.active) rolls.push(roll);
rolls.push(roll);
const actor = await DHSummonField.getWorldActor(await foundry.utils.fromUuid(summon.actorUUID)); const actor = await DHSummonField.getWorldActor(await foundry.utils.fromUuid(summon.actorUUID));
/* Extending summon data in memory so it's available in actionField.toChat. Think it's harmless, but ugly. Could maybe find a better way. */ /* Extending summon data in memory so it's available in actionField.toChat. Think it's harmless, but ugly. Could maybe find a better way. */

View file

@ -11,7 +11,9 @@ export default class DualityRoll extends D20Roll {
this.rallyChoices = this.setRallyChoices(); this.rallyChoices = this.setRallyChoices();
this.guaranteedCritical = options.guaranteedCritical; this.guaranteedCritical = options.guaranteedCritical;
const advantageFaces = data.rules?.roll?.defaultAdvantageDice ? Number.parseInt(data.rules.roll.defaultAdvantageDice) : 6 const advantageFaces = data.rules?.roll?.defaultAdvantageDice
? Number.parseInt(data.rules.roll.defaultAdvantageDice)
: 6;
this.advantageFaces = Number.isNaN(advantageFaces) ? 6 : advantageFaces; this.advantageFaces = Number.isNaN(advantageFaces) ? 6 : advantageFaces;
} }

View file

@ -200,7 +200,6 @@ export default class DhActiveEffect extends foundry.documents.ActiveEffect {
static effectSafeEval(expression) { static effectSafeEval(expression) {
let result; let result;
try { try {
// eslint-disable-next-line no-new-func
const evl = new Function('sandbox', `with (sandbox) { return ${expression}}`); const evl = new Function('sandbox', `with (sandbox) { return ${expression}}`);
result = evl(Roll.MATH_PROXY); result = evl(Roll.MATH_PROXY);
} catch (err) { } catch (err) {

View file

@ -3,7 +3,7 @@ export default class DhActorCollection extends foundry.documents.collections.Act
get party() { get party() {
const id = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.ActiveParty); const id = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.ActiveParty);
const actor = game.actors.get(id); const actor = game.actors.get(id);
return actor?.type === "party" ? actor : null; return actor?.type === 'party' ? actor : null;
} }
/** Ensure companions are initialized after all other subtypes. */ /** Ensure companions are initialized after all other subtypes. */

View file

@ -56,10 +56,10 @@ export const registerKeyBindings = () => {
game.keybindings.register(CONFIG.DH.id, CONFIG.DH.SETTINGS.keybindings.partySheet, { game.keybindings.register(CONFIG.DH.id, CONFIG.DH.SETTINGS.keybindings.partySheet, {
name: _loc('DAGGERHEART.SETTINGS.Keybindings.partySheet.name'), name: _loc('DAGGERHEART.SETTINGS.Keybindings.partySheet.name'),
hint: _loc('DAGGERHEART.SETTINGS.Keybindings.partySheet.hint'), hint: _loc('DAGGERHEART.SETTINGS.Keybindings.partySheet.hint'),
editable: [{ key: "KeyP" }], editable: [{ key: 'KeyP' }],
onDown: () => { onDown: () => {
const controlled = canvas.ready ? canvas.tokens.controlled : []; const controlled = canvas.ready ? canvas.tokens.controlled : [];
const selectedParty = controlled.find((c) => c.actor?.type === 'party')?.actor; const selectedParty = controlled.find(c => c.actor?.type === 'party')?.actor;
const party = selectedParty ?? game.actors.party; const party = selectedParty ?? game.actors.party;
if (!party) return; if (!party) return;
@ -215,6 +215,6 @@ const registerNonConfigSettings = () => {
scope: 'world', scope: 'world',
config: false, config: false,
type: String, type: String,
default: null, default: null
}); });
}; };

872
package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -17,13 +17,18 @@
"pullYMLtoLDB": "node ./tools/pullYMLtoLDB.mjs", "pullYMLtoLDB": "node ./tools/pullYMLtoLDB.mjs",
"pullYMLtoLDBBuild": "node ./tools/pullYMLtoLDB.mjs --build", "pullYMLtoLDBBuild": "node ./tools/pullYMLtoLDB.mjs --build",
"createSymlink": "node ./tools/create-symlink.mjs", "createSymlink": "node ./tools/create-symlink.mjs",
"setup:dev": "node ./tools/dev-setup.mjs" "setup:dev": "node ./tools/dev-setup.mjs",
"lint": "eslint",
"lint:fix": "eslint --fix"
}, },
"devDependencies": { "devDependencies": {
"@foundryvtt/foundryvtt-cli": "^1.0.2", "@foundryvtt/foundryvtt-cli": "^1.0.2",
"@rollup/plugin-commonjs": "^25.0.7", "@rollup/plugin-commonjs": "^25.0.7",
"@rollup/plugin-node-resolve": "^15.2.3", "@rollup/plugin-node-resolve": "^15.2.3",
"concurrently": "^8.2.2", "concurrently": "^8.2.2",
"eslint": "^10.2.1",
"eslint-plugin-prettier": "^5.5.5",
"globals": "^17.5.0",
"husky": "^9.1.5", "husky": "^9.1.5",
"lint-staged": "^15.2.10", "lint-staged": "^15.2.10",
"postcss": "^8.4.32", "postcss": "^8.4.32",

View file

@ -1,12 +1,12 @@
import { compilePack } from '@foundryvtt/foundryvtt-cli'; import { compilePack } from '@foundryvtt/foundryvtt-cli';
import readline from 'node:readline/promises'; import readline from 'node:readline/promises';
import { promises as fs } from 'fs'; import { promises as fs } from 'fs';
import systemJSON from "../system.json" with { type: "json" }; import systemJSON from '../system.json' with { type: 'json' };
const MODULE_ID = process.cwd(); const MODULE_ID = process.cwd();
const answer = await (async () => { const answer = await (async () => {
if (process.argv.includes("--build")) return "overwrite"; if (process.argv.includes('--build')) return 'overwrite';
const rl = readline.createInterface({ const rl = readline.createInterface({
input: process.stdin, input: process.stdin,
@ -42,8 +42,8 @@ async function pullToLDB() {
function transformEntry(entry) { function transformEntry(entry) {
const stats = { const stats = {
coreVersion: systemJSON.compatibility.minimum, coreVersion: systemJSON.compatibility.minimum,
systemId: "daggerheart", systemId: 'daggerheart',
systemVersion: systemJSON.version, systemVersion: systemJSON.version
}; };
entry._stats = { ...stats }; entry._stats = { ...stats };

View file

@ -23,7 +23,7 @@ for (const pack of packs) {
await extractPack(`${MODULE_ID}/${pack}`, `${MODULE_ID}/src/${pack}`, { await extractPack(`${MODULE_ID}/${pack}`, `${MODULE_ID}/src/${pack}`, {
yaml, yaml,
transformName, transformName,
transformEntry, transformEntry
}); });
} }
/** /**
@ -45,12 +45,12 @@ function transformEntry(entry) {
delete entry._stats; delete entry._stats;
for (const effect of entry.effects ?? []) { for (const effect of entry.effects ?? []) {
effect._stats = prune(effect._stats) effect._stats = prune(effect._stats);
} }
for (const item of entry.items ?? []) { for (const item of entry.items ?? []) {
item._stats = prune(item._stats); item._stats = prune(item._stats);
for (const effect of item.effects ?? []) { for (const effect of item.effects ?? []) {
effect._stats = prune(effect._stats) effect._stats = prune(effect._stats);
} }
} }
} }