From 78079bf1b2f53358b1e663eb05a8043e8c9188c4 Mon Sep 17 00:00:00 2001 From: Lukas Date: Sat, 4 Jul 2026 13:35:14 +0200 Subject: [PATCH] Break import cycle in domain persistent-damage modules Extract persistent damage types and definitions into a leaf module so events.ts and types.ts no longer import back into persistent-damage.ts. Enable oxlint import/no-cycle (whole workspace via root tsconfig) to keep cycles out. Co-Authored-By: Claude Fable 5 --- .oxlintrc.json | 3 +- package.json | 4 +- packages/domain/src/events.ts | 2 +- .../domain/src/persistent-damage-types.ts | 78 ++++++++++++++++ packages/domain/src/persistent-damage.ts | 90 +++---------------- packages/domain/src/rehydrate-combatant.ts | 4 +- packages/domain/src/types.ts | 2 +- 7 files changed, 99 insertions(+), 84 deletions(-) create mode 100644 packages/domain/src/persistent-damage-types.ts diff --git a/.oxlintrc.json b/.oxlintrc.json index 890c28c..55f981f 100644 --- a/.oxlintrc.json +++ b/.oxlintrc.json @@ -1,6 +1,6 @@ { "$schema": "https://raw.githubusercontent.com/nicolo-ribaudo/tc39-proposal-type-annotations/refs/heads/main/packages/oxlint/configuration_file_schema.json", - "plugins": ["typescript", "unicorn", "jest"], + "plugins": ["typescript", "unicorn", "jest", "import"], "categories": {}, "rules": { "typescript/no-unnecessary-type-assertion": "error", @@ -8,6 +8,7 @@ "typescript/prefer-regexp-exec": "error", "unicorn/prefer-string-replace-all": "error", "unicorn/prefer-string-raw": "error", + "import/no-cycle": "error", "jest/expect-expect": [ "error", { diff --git a/package.json b/package.json index c1ebd1e..6de7d1e 100644 --- a/package.json +++ b/package.json @@ -44,10 +44,10 @@ "knip": "knip", "jscpd": "jscpd", "jsinspect": "jsinspect -c .jsinspectrc apps/web/src packages/domain/src packages/application/src", - "oxlint": "oxlint --tsconfig apps/web/tsconfig.json --type-aware --deny-warnings", + "oxlint": "oxlint --tsconfig tsconfig.json --type-aware --deny-warnings", "check:ignores": "node scripts/check-lint-ignores.mjs", "check:classnames": "node scripts/check-cn-classnames.mjs", "check:props": "node scripts/check-component-props.mjs", - "check": "pnpm audit --audit-level=high && knip && biome check . && node scripts/check-lint-ignores.mjs && node scripts/check-cn-classnames.mjs && node scripts/check-component-props.mjs && jscpd && pnpm jsinspect && tsc --build && oxlint --tsconfig apps/web/tsconfig.json --type-aware --deny warnings && vitest run" + "check": "pnpm audit --audit-level=high && knip && biome check . && node scripts/check-lint-ignores.mjs && node scripts/check-cn-classnames.mjs && node scripts/check-component-props.mjs && jscpd && pnpm jsinspect && tsc --build && oxlint --tsconfig tsconfig.json --type-aware --deny warnings && vitest run" } } diff --git a/packages/domain/src/events.ts b/packages/domain/src/events.ts index 4a609fa..5d5258a 100644 --- a/packages/domain/src/events.ts +++ b/packages/domain/src/events.ts @@ -1,6 +1,6 @@ import type { ConditionId } from "./conditions.js"; import type { CreatureId } from "./creature-types.js"; -import type { PersistentDamageType } from "./persistent-damage.js"; +import type { PersistentDamageType } from "./persistent-damage-types.js"; import type { PlayerCharacterId } from "./player-character-types.js"; import type { CombatantId } from "./types.js"; diff --git a/packages/domain/src/persistent-damage-types.ts b/packages/domain/src/persistent-damage-types.ts new file mode 100644 index 0000000..4be891e --- /dev/null +++ b/packages/domain/src/persistent-damage-types.ts @@ -0,0 +1,78 @@ +export const PERSISTENT_DAMAGE_TYPES = [ + "fire", + "bleed", + "acid", + "cold", + "electricity", + "poison", + "mental", + "force", + "void", + "spirit", + "vitality", + "piercing", +] as const; + +export type PersistentDamageType = (typeof PERSISTENT_DAMAGE_TYPES)[number]; + +export const VALID_PERSISTENT_DAMAGE_TYPES: ReadonlySet = new Set( + PERSISTENT_DAMAGE_TYPES, +); + +export interface PersistentDamageEntry { + readonly type: PersistentDamageType; + readonly formula: string; +} + +export interface PersistentDamageDefinition { + readonly type: PersistentDamageType; + readonly label: string; + readonly iconName: string; + readonly color: string; +} + +export const PERSISTENT_DAMAGE_DEFINITIONS: readonly PersistentDamageDefinition[] = + [ + { type: "fire", label: "Fire", iconName: "Flame", color: "orange" }, + { type: "bleed", label: "Bleed", iconName: "Droplets", color: "red" }, + { + type: "acid", + label: "Acid", + iconName: "FlaskConical", + color: "lime", + }, + { type: "cold", label: "Cold", iconName: "Snowflake", color: "sky" }, + { + type: "electricity", + label: "Electricity", + iconName: "Zap", + color: "yellow", + }, + { + type: "poison", + label: "Poison", + iconName: "Droplet", + color: "green", + }, + { + type: "mental", + label: "Mental", + iconName: "BrainCog", + color: "pink", + }, + { type: "force", label: "Force", iconName: "Orbit", color: "indigo" }, + { type: "void", label: "Void", iconName: "Eclipse", color: "purple" }, + { type: "spirit", label: "Spirit", iconName: "Wind", color: "neutral" }, + { + type: "vitality", + label: "Vitality", + iconName: "Sparkle", + color: "amber", + }, + { + type: "piercing", + label: "Piercing", + iconName: "Sword", + color: "neutral", + }, + ]; diff --git a/packages/domain/src/persistent-damage.ts b/packages/domain/src/persistent-damage.ts index b31324a..c870346 100644 --- a/packages/domain/src/persistent-damage.ts +++ b/packages/domain/src/persistent-damage.ts @@ -1,4 +1,10 @@ import type { DomainEvent } from "./events.js"; +import { + PERSISTENT_DAMAGE_DEFINITIONS, + type PersistentDamageEntry, + type PersistentDamageType, + VALID_PERSISTENT_DAMAGE_TYPES, +} from "./persistent-damage-types.js"; import { type CombatantId, type DomainError, @@ -7,84 +13,14 @@ import { isDomainError, } from "./types.js"; -export const PERSISTENT_DAMAGE_TYPES = [ - "fire", - "bleed", - "acid", - "cold", - "electricity", - "poison", - "mental", - "force", - "void", - "spirit", - "vitality", - "piercing", -] as const; - -export type PersistentDamageType = (typeof PERSISTENT_DAMAGE_TYPES)[number]; - -export const VALID_PERSISTENT_DAMAGE_TYPES: ReadonlySet = new Set( +export { + PERSISTENT_DAMAGE_DEFINITIONS, PERSISTENT_DAMAGE_TYPES, -); - -export interface PersistentDamageEntry { - readonly type: PersistentDamageType; - readonly formula: string; -} - -export interface PersistentDamageDefinition { - readonly type: PersistentDamageType; - readonly label: string; - readonly iconName: string; - readonly color: string; -} - -export const PERSISTENT_DAMAGE_DEFINITIONS: readonly PersistentDamageDefinition[] = - [ - { type: "fire", label: "Fire", iconName: "Flame", color: "orange" }, - { type: "bleed", label: "Bleed", iconName: "Droplets", color: "red" }, - { - type: "acid", - label: "Acid", - iconName: "FlaskConical", - color: "lime", - }, - { type: "cold", label: "Cold", iconName: "Snowflake", color: "sky" }, - { - type: "electricity", - label: "Electricity", - iconName: "Zap", - color: "yellow", - }, - { - type: "poison", - label: "Poison", - iconName: "Droplet", - color: "green", - }, - { - type: "mental", - label: "Mental", - iconName: "BrainCog", - color: "pink", - }, - { type: "force", label: "Force", iconName: "Orbit", color: "indigo" }, - { type: "void", label: "Void", iconName: "Eclipse", color: "purple" }, - { type: "spirit", label: "Spirit", iconName: "Wind", color: "neutral" }, - { - type: "vitality", - label: "Vitality", - iconName: "Sparkle", - color: "amber", - }, - { - type: "piercing", - label: "Piercing", - iconName: "Sword", - color: "neutral", - }, - ]; + type PersistentDamageDefinition, + type PersistentDamageEntry, + type PersistentDamageType, + VALID_PERSISTENT_DAMAGE_TYPES, +} from "./persistent-damage-types.js"; export interface PersistentDamageSuccess { readonly encounter: Encounter; diff --git a/packages/domain/src/rehydrate-combatant.ts b/packages/domain/src/rehydrate-combatant.ts index 5891fef..c25f3d8 100644 --- a/packages/domain/src/rehydrate-combatant.ts +++ b/packages/domain/src/rehydrate-combatant.ts @@ -2,8 +2,8 @@ import type { ConditionEntry, ConditionId } from "./conditions.js"; import { VALID_CONDITION_IDS } from "./conditions.js"; import { creatureId } from "./creature-types.js"; import { VALID_CR_VALUES } from "./encounter-difficulty.js"; -import type { PersistentDamageEntry } from "./persistent-damage.js"; -import { VALID_PERSISTENT_DAMAGE_TYPES } from "./persistent-damage.js"; +import type { PersistentDamageEntry } from "./persistent-damage-types.js"; +import { VALID_PERSISTENT_DAMAGE_TYPES } from "./persistent-damage-types.js"; import { playerCharacterId, VALID_PLAYER_COLORS, diff --git a/packages/domain/src/types.ts b/packages/domain/src/types.ts index 4c05eb2..bbdddc2 100644 --- a/packages/domain/src/types.ts +++ b/packages/domain/src/types.ts @@ -7,7 +7,7 @@ export function combatantId(id: string): CombatantId { import type { ConditionEntry } from "./conditions.js"; import type { CreatureId } from "./creature-types.js"; -import type { PersistentDamageEntry } from "./persistent-damage.js"; +import type { PersistentDamageEntry } from "./persistent-damage-types.js"; import type { PlayerCharacterId } from "./player-character-types.js"; export interface Combatant {