@drmxrcy/tcg-core 0.0.0-202602060542

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (157) hide show
  1. package/README.md +882 -0
  2. package/package.json +58 -0
  3. package/src/__tests__/alpha-clash-engine-definition.test.ts +319 -0
  4. package/src/__tests__/createMockAlphaClashGame.ts +462 -0
  5. package/src/__tests__/createMockGrandArchiveGame.ts +373 -0
  6. package/src/__tests__/createMockGundamGame.ts +379 -0
  7. package/src/__tests__/createMockLorcanaGame.ts +328 -0
  8. package/src/__tests__/createMockOnePieceGame.ts +429 -0
  9. package/src/__tests__/createMockRiftboundGame.ts +462 -0
  10. package/src/__tests__/grand-archive-engine-definition.test.ts +118 -0
  11. package/src/__tests__/gundam-engine-definition.test.ts +110 -0
  12. package/src/__tests__/integration-complete-game.test.ts +508 -0
  13. package/src/__tests__/integration-network-sync.test.ts +469 -0
  14. package/src/__tests__/lorcana-engine-definition.test.ts +100 -0
  15. package/src/__tests__/move-enumeration.test.ts +725 -0
  16. package/src/__tests__/multiplayer-engine.test.ts +555 -0
  17. package/src/__tests__/one-piece-engine-definition.test.ts +114 -0
  18. package/src/__tests__/riftbound-engine-definition.test.ts +124 -0
  19. package/src/actions/action-definition.test.ts +201 -0
  20. package/src/actions/action-definition.ts +122 -0
  21. package/src/actions/action-timing.test.ts +490 -0
  22. package/src/actions/action-timing.ts +257 -0
  23. package/src/cards/card-definition.test.ts +268 -0
  24. package/src/cards/card-definition.ts +27 -0
  25. package/src/cards/card-instance.test.ts +422 -0
  26. package/src/cards/card-instance.ts +49 -0
  27. package/src/cards/computed-properties.test.ts +530 -0
  28. package/src/cards/computed-properties.ts +84 -0
  29. package/src/cards/conditional-modifiers.test.ts +390 -0
  30. package/src/cards/modifiers.test.ts +286 -0
  31. package/src/cards/modifiers.ts +51 -0
  32. package/src/engine/MULTIPLAYER.md +425 -0
  33. package/src/engine/__tests__/rule-engine-flow.test.ts +348 -0
  34. package/src/engine/__tests__/rule-engine-history.test.ts +535 -0
  35. package/src/engine/__tests__/rule-engine-moves.test.ts +488 -0
  36. package/src/engine/__tests__/rule-engine.test.ts +366 -0
  37. package/src/engine/index.ts +14 -0
  38. package/src/engine/multiplayer-engine.example.ts +571 -0
  39. package/src/engine/multiplayer-engine.ts +409 -0
  40. package/src/engine/rule-engine.test.ts +286 -0
  41. package/src/engine/rule-engine.ts +1539 -0
  42. package/src/engine/tracker-system.ts +172 -0
  43. package/src/examples/__tests__/coin-flip-game.test.ts +641 -0
  44. package/src/filtering/card-filter.test.ts +230 -0
  45. package/src/filtering/card-filter.ts +91 -0
  46. package/src/filtering/card-query.test.ts +901 -0
  47. package/src/filtering/card-query.ts +273 -0
  48. package/src/filtering/filter-matching.test.ts +944 -0
  49. package/src/filtering/filter-matching.ts +315 -0
  50. package/src/flow/SERIALIZATION.md +428 -0
  51. package/src/flow/__tests__/flow-definition.test.ts +427 -0
  52. package/src/flow/__tests__/flow-manager.test.ts +756 -0
  53. package/src/flow/__tests__/flow-serialization.test.ts +565 -0
  54. package/src/flow/flow-definition.ts +453 -0
  55. package/src/flow/flow-manager.ts +1044 -0
  56. package/src/flow/index.ts +35 -0
  57. package/src/game-definition/__tests__/game-definition-validation.test.ts +359 -0
  58. package/src/game-definition/__tests__/game-definition.test.ts +291 -0
  59. package/src/game-definition/__tests__/move-definitions.test.ts +328 -0
  60. package/src/game-definition/game-definition.ts +261 -0
  61. package/src/game-definition/index.ts +28 -0
  62. package/src/game-definition/move-definitions.ts +188 -0
  63. package/src/game-definition/validation.ts +183 -0
  64. package/src/history/history-manager.test.ts +497 -0
  65. package/src/history/history-manager.ts +312 -0
  66. package/src/history/history-operations.ts +122 -0
  67. package/src/history/index.ts +9 -0
  68. package/src/history/types.ts +255 -0
  69. package/src/index.ts +32 -0
  70. package/src/logging/index.ts +27 -0
  71. package/src/logging/log-formatter.ts +187 -0
  72. package/src/logging/logger.ts +276 -0
  73. package/src/logging/types.ts +148 -0
  74. package/src/moves/create-move.test.ts +331 -0
  75. package/src/moves/create-move.ts +64 -0
  76. package/src/moves/move-enumeration.ts +228 -0
  77. package/src/moves/move-executor.test.ts +431 -0
  78. package/src/moves/move-executor.ts +195 -0
  79. package/src/moves/move-system.test.ts +380 -0
  80. package/src/moves/move-system.ts +463 -0
  81. package/src/moves/standard-moves.ts +231 -0
  82. package/src/operations/card-operations.test.ts +236 -0
  83. package/src/operations/card-operations.ts +116 -0
  84. package/src/operations/card-registry-impl.test.ts +251 -0
  85. package/src/operations/card-registry-impl.ts +70 -0
  86. package/src/operations/card-registry.test.ts +234 -0
  87. package/src/operations/card-registry.ts +106 -0
  88. package/src/operations/counter-operations.ts +152 -0
  89. package/src/operations/game-operations.test.ts +280 -0
  90. package/src/operations/game-operations.ts +140 -0
  91. package/src/operations/index.ts +24 -0
  92. package/src/operations/operations-impl.test.ts +354 -0
  93. package/src/operations/operations-impl.ts +468 -0
  94. package/src/operations/zone-operations.test.ts +295 -0
  95. package/src/operations/zone-operations.ts +223 -0
  96. package/src/rng/seeded-rng.test.ts +339 -0
  97. package/src/rng/seeded-rng.ts +123 -0
  98. package/src/targeting/index.ts +48 -0
  99. package/src/targeting/target-definition.test.ts +273 -0
  100. package/src/targeting/target-definition.ts +37 -0
  101. package/src/targeting/target-dsl.ts +279 -0
  102. package/src/targeting/target-resolver.ts +486 -0
  103. package/src/targeting/target-validation.test.ts +994 -0
  104. package/src/targeting/target-validation.ts +286 -0
  105. package/src/telemetry/events.ts +202 -0
  106. package/src/telemetry/index.ts +21 -0
  107. package/src/telemetry/telemetry-manager.ts +127 -0
  108. package/src/telemetry/types.ts +68 -0
  109. package/src/testing/__tests__/testing-utilities-integration.test.ts +161 -0
  110. package/src/testing/index.ts +88 -0
  111. package/src/testing/test-assertions.test.ts +341 -0
  112. package/src/testing/test-assertions.ts +256 -0
  113. package/src/testing/test-card-factory.test.ts +228 -0
  114. package/src/testing/test-card-factory.ts +111 -0
  115. package/src/testing/test-context-factory.ts +187 -0
  116. package/src/testing/test-end-assertions.test.ts +262 -0
  117. package/src/testing/test-end-assertions.ts +95 -0
  118. package/src/testing/test-engine-builder.test.ts +389 -0
  119. package/src/testing/test-engine-builder.ts +46 -0
  120. package/src/testing/test-flow-assertions.test.ts +284 -0
  121. package/src/testing/test-flow-assertions.ts +115 -0
  122. package/src/testing/test-player-builder.test.ts +132 -0
  123. package/src/testing/test-player-builder.ts +46 -0
  124. package/src/testing/test-replay-assertions.test.ts +356 -0
  125. package/src/testing/test-replay-assertions.ts +164 -0
  126. package/src/testing/test-rng-helpers.test.ts +260 -0
  127. package/src/testing/test-rng-helpers.ts +190 -0
  128. package/src/testing/test-state-builder.test.ts +373 -0
  129. package/src/testing/test-state-builder.ts +99 -0
  130. package/src/testing/test-zone-factory.test.ts +295 -0
  131. package/src/testing/test-zone-factory.ts +224 -0
  132. package/src/types/branded-utils.ts +54 -0
  133. package/src/types/branded.test.ts +175 -0
  134. package/src/types/branded.ts +33 -0
  135. package/src/types/index.ts +8 -0
  136. package/src/types/state.test.ts +198 -0
  137. package/src/types/state.ts +154 -0
  138. package/src/validation/card-type-guards.test.ts +242 -0
  139. package/src/validation/card-type-guards.ts +179 -0
  140. package/src/validation/index.ts +40 -0
  141. package/src/validation/schema-builders.test.ts +403 -0
  142. package/src/validation/schema-builders.ts +345 -0
  143. package/src/validation/type-guard-builder.test.ts +216 -0
  144. package/src/validation/type-guard-builder.ts +109 -0
  145. package/src/validation/validator-builder.test.ts +375 -0
  146. package/src/validation/validator-builder.ts +273 -0
  147. package/src/zones/index.ts +28 -0
  148. package/src/zones/zone-factory.test.ts +183 -0
  149. package/src/zones/zone-factory.ts +44 -0
  150. package/src/zones/zone-operations.test.ts +800 -0
  151. package/src/zones/zone-operations.ts +306 -0
  152. package/src/zones/zone-state-helpers.test.ts +337 -0
  153. package/src/zones/zone-state-helpers.ts +128 -0
  154. package/src/zones/zone-visibility.test.ts +156 -0
  155. package/src/zones/zone-visibility.ts +36 -0
  156. package/src/zones/zone.test.ts +186 -0
  157. package/src/zones/zone.ts +66 -0
@@ -0,0 +1,242 @@
1
+ import { describe, expect, it } from "bun:test";
2
+ import type { CardDefinition } from "../cards/card-definition";
3
+ import { isCardOfType } from "./card-type-guards";
4
+
5
+ describe("isCardOfType", () => {
6
+ describe("basic usage", () => {
7
+ it("should create a type guard for card type", () => {
8
+ const isCreature = isCardOfType("creature");
9
+
10
+ const creature: CardDefinition = {
11
+ id: "dragon-1",
12
+ name: "Dragon",
13
+ type: "creature",
14
+ basePower: 5,
15
+ baseToughness: 5,
16
+ };
17
+
18
+ const instant: CardDefinition = {
19
+ id: "bolt-1",
20
+ name: "Lightning Bolt",
21
+ type: "instant",
22
+ };
23
+
24
+ expect(isCreature(creature)).toBe(true);
25
+ expect(isCreature(instant)).toBe(false);
26
+ });
27
+
28
+ it("should work with multiple card types", () => {
29
+ const isCreature = isCardOfType("creature");
30
+ const isInstant = isCardOfType("instant");
31
+ const isSorcery = isCardOfType("sorcery");
32
+
33
+ const creature: CardDefinition = {
34
+ id: "creature-1",
35
+ name: "Creature",
36
+ type: "creature",
37
+ };
38
+
39
+ const instant: CardDefinition = {
40
+ id: "instant-1",
41
+ name: "Instant",
42
+ type: "instant",
43
+ };
44
+
45
+ const sorcery: CardDefinition = {
46
+ id: "sorcery-1",
47
+ name: "Sorcery",
48
+ type: "sorcery",
49
+ };
50
+
51
+ expect(isCreature(creature)).toBe(true);
52
+ expect(isCreature(instant)).toBe(false);
53
+ expect(isCreature(sorcery)).toBe(false);
54
+
55
+ expect(isInstant(instant)).toBe(true);
56
+ expect(isInstant(creature)).toBe(false);
57
+ expect(isInstant(sorcery)).toBe(false);
58
+
59
+ expect(isSorcery(sorcery)).toBe(true);
60
+ expect(isSorcery(creature)).toBe(false);
61
+ expect(isSorcery(instant)).toBe(false);
62
+ });
63
+ });
64
+
65
+ describe("filtering arrays", () => {
66
+ it("should filter card arrays by type", () => {
67
+ const cards: CardDefinition[] = [
68
+ { id: "1", name: "Dragon", type: "creature" },
69
+ { id: "2", name: "Bolt", type: "instant" },
70
+ { id: "3", name: "Goblin", type: "creature" },
71
+ { id: "4", name: "Wrath", type: "sorcery" },
72
+ { id: "5", name: "Angel", type: "creature" },
73
+ ];
74
+
75
+ const isCreature = isCardOfType("creature");
76
+ const creatures = cards.filter(isCreature);
77
+
78
+ expect(creatures).toHaveLength(3);
79
+ expect(creatures.map((c) => c.name)).toEqual([
80
+ "Dragon",
81
+ "Goblin",
82
+ "Angel",
83
+ ]);
84
+ });
85
+
86
+ it("should work with Array.some and Array.every", () => {
87
+ const cards: CardDefinition[] = [
88
+ { id: "1", name: "Dragon", type: "creature" },
89
+ { id: "2", name: "Goblin", type: "creature" },
90
+ ];
91
+
92
+ const allCreatures: CardDefinition[] = [
93
+ { id: "3", name: "Angel", type: "creature" },
94
+ ];
95
+
96
+ const isCreature = isCardOfType("creature");
97
+
98
+ expect(cards.some(isCreature)).toBe(true);
99
+ expect(cards.every(isCreature)).toBe(true);
100
+ expect(allCreatures.every(isCreature)).toBe(true);
101
+ });
102
+ });
103
+
104
+ describe("type narrowing", () => {
105
+ it("should narrow types in conditional blocks", () => {
106
+ const card: CardDefinition = {
107
+ id: "dragon-1",
108
+ name: "Dragon",
109
+ type: "creature",
110
+ basePower: 5,
111
+ baseToughness: 5,
112
+ };
113
+
114
+ const isCreature = isCardOfType("creature");
115
+
116
+ if (isCreature(card)) {
117
+ // TypeScript should know card.type is "creature"
118
+ expect(card.type).toBe("creature");
119
+ expect(card.name).toBe("Dragon");
120
+ }
121
+ });
122
+ });
123
+
124
+ describe("game-specific types", () => {
125
+ it("should work with Gundam-specific card types", () => {
126
+ type GundamCard = CardDefinition & {
127
+ type: "unit" | "command" | "character" | "base";
128
+ };
129
+
130
+ const isUnit = isCardOfType<GundamCard>("unit");
131
+ const isCommand = isCardOfType<GundamCard>("command");
132
+
133
+ const unit: GundamCard = {
134
+ id: "gundam-1",
135
+ name: "RX-78-2 Gundam",
136
+ type: "unit",
137
+ basePower: 3,
138
+ };
139
+
140
+ const command: GundamCard = {
141
+ id: "command-1",
142
+ name: "All-Out Attack",
143
+ type: "command",
144
+ };
145
+
146
+ expect(isUnit(unit)).toBe(true);
147
+ expect(isUnit(command)).toBe(false);
148
+ expect(isCommand(command)).toBe(true);
149
+ expect(isCommand(unit)).toBe(false);
150
+ });
151
+
152
+ it("should work with Lorcana-specific card types", () => {
153
+ type LorcanaCard = CardDefinition & {
154
+ type: "character" | "action" | "item" | "location";
155
+ };
156
+
157
+ const isCharacter = isCardOfType<LorcanaCard>("character");
158
+ const isAction = isCardOfType<LorcanaCard>("action");
159
+
160
+ const character: LorcanaCard = {
161
+ id: "mickey-1",
162
+ name: "Mickey Mouse - Brave Little Tailor",
163
+ type: "character",
164
+ basePower: 4,
165
+ };
166
+
167
+ const action: LorcanaCard = {
168
+ id: "action-1",
169
+ name: "Be Prepared",
170
+ type: "action",
171
+ };
172
+
173
+ expect(isCharacter(character)).toBe(true);
174
+ expect(isCharacter(action)).toBe(false);
175
+ expect(isAction(action)).toBe(true);
176
+ expect(isAction(character)).toBe(false);
177
+ });
178
+ });
179
+
180
+ describe("edge cases", () => {
181
+ it("should handle cards with missing type field", () => {
182
+ const isCreature = isCardOfType("creature");
183
+ const cardWithoutType = { id: "1", name: "Card" } as CardDefinition;
184
+
185
+ expect(isCreature(cardWithoutType)).toBe(false);
186
+ });
187
+
188
+ it("should handle empty strings", () => {
189
+ const isEmpty = isCardOfType("");
190
+ const emptyCard: CardDefinition = {
191
+ id: "1",
192
+ name: "Card",
193
+ type: "",
194
+ };
195
+ const normalCard: CardDefinition = {
196
+ id: "2",
197
+ name: "Card",
198
+ type: "creature",
199
+ };
200
+
201
+ expect(isEmpty(emptyCard)).toBe(true);
202
+ expect(isEmpty(normalCard)).toBe(false);
203
+ });
204
+
205
+ it("should be case-sensitive", () => {
206
+ const isCreature = isCardOfType("creature");
207
+ const uppercaseCard: CardDefinition = {
208
+ id: "1",
209
+ name: "Card",
210
+ type: "Creature", // uppercase C
211
+ };
212
+ const lowercaseCard: CardDefinition = {
213
+ id: "2",
214
+ name: "Card",
215
+ type: "creature",
216
+ };
217
+
218
+ expect(isCreature(uppercaseCard)).toBe(false);
219
+ expect(isCreature(lowercaseCard)).toBe(true);
220
+ });
221
+ });
222
+
223
+ describe("performance", () => {
224
+ it("should be efficient for large arrays", () => {
225
+ const cards: CardDefinition[] = Array.from({ length: 10000 }, (_, i) => ({
226
+ id: `card-${i}`,
227
+ name: `Card ${i}`,
228
+ type: i % 3 === 0 ? "creature" : i % 3 === 1 ? "instant" : "sorcery",
229
+ }));
230
+
231
+ const isCreature = isCardOfType("creature");
232
+
233
+ const startTime = performance.now();
234
+ const creatures = cards.filter(isCreature);
235
+ const endTime = performance.now();
236
+
237
+ expect(creatures.length).toBeGreaterThan(0);
238
+ // Should complete in reasonable time (< 1000ms for 10k cards, higher threshold for CI parallel execution)
239
+ expect(endTime - startTime).toBeLessThan(1000);
240
+ });
241
+ });
242
+ });
@@ -0,0 +1,179 @@
1
+ /**
2
+ * Card-specific type guard utilities
3
+ *
4
+ * Provides convenient type guards for filtering and narrowing card types
5
+ * in a type-safe manner.
6
+ */
7
+
8
+ import type { CardDefinition } from "../cards/card-definition";
9
+ import { createTypeGuard } from "./type-guard-builder";
10
+
11
+ /**
12
+ * Creates a type guard for checking if a card is of a specific type
13
+ *
14
+ * This is a specialized version of createTypeGuard optimized for card definitions.
15
+ * It provides better ergonomics for the common use case of filtering cards by type.
16
+ *
17
+ * @template T - The card type (extends CardDefinition)
18
+ * @param cardType - The type value to check against
19
+ * @returns A type guard function that checks if a card matches the type
20
+ *
21
+ * @example
22
+ * ```typescript
23
+ * // Basic usage
24
+ * const isCreature = isCardOfType("creature");
25
+ * const creature: CardDefinition = { id: "1", name: "Dragon", type: "creature" };
26
+ * console.log(isCreature(creature)); // true
27
+ *
28
+ * // Filtering arrays
29
+ * const cards: CardDefinition[] = [...];
30
+ * const creatures = cards.filter(isCardOfType("creature"));
31
+ *
32
+ * // Type narrowing in conditionals
33
+ * if (isCardOfType("creature")(card)) {
34
+ * // TypeScript knows card.type is "creature" here
35
+ * }
36
+ * ```
37
+ *
38
+ * @example
39
+ * ```typescript
40
+ * // Game-specific types
41
+ * type GundamCard = CardDefinition & {
42
+ * type: "unit" | "command" | "character" | "base";
43
+ * };
44
+ *
45
+ * const isUnit = isCardOfType<GundamCard>("unit");
46
+ * const gundamCard: GundamCard = { id: "1", name: "Gundam", type: "unit" };
47
+ * console.log(isUnit(gundamCard)); // true
48
+ * ```
49
+ */
50
+ export function isCardOfType<T extends CardDefinition = CardDefinition>(
51
+ cardType: T["type"],
52
+ ): (card: T) => card is T & { type: typeof cardType } {
53
+ return createTypeGuard<T, "type", T["type"]>("type", cardType);
54
+ }
55
+
56
+ /**
57
+ * Creates a type guard for checking if a card has a specific field value
58
+ *
59
+ * This is a more generic version that works with any card field, not just type.
60
+ * Useful for filtering by other properties like rarity, set, or custom fields.
61
+ *
62
+ * @template T - The card type (extends CardDefinition)
63
+ * @template K - The key of the field to check
64
+ * @template V - The value type to check against
65
+ *
66
+ * @param field - The field name to check
67
+ * @param value - The value to compare against
68
+ * @returns A type guard function
69
+ *
70
+ * @example
71
+ * ```typescript
72
+ * type ExtendedCard = CardDefinition & { rarity: "common" | "rare" | "mythic" };
73
+ *
74
+ * const isRare = isCardWithField<ExtendedCard, "rarity", "rare">("rarity", "rare");
75
+ * const rareCard: ExtendedCard = {
76
+ * id: "1",
77
+ * name: "Rare Dragon",
78
+ * type: "creature",
79
+ * rarity: "rare"
80
+ * };
81
+ *
82
+ * console.log(isRare(rareCard)); // true
83
+ * ```
84
+ */
85
+ export function isCardWithField<
86
+ T extends CardDefinition,
87
+ K extends keyof T,
88
+ V extends T[K],
89
+ >(field: K, value: V): (card: T) => card is T & Record<K, V> {
90
+ return createTypeGuard<T, K, V>(field, value);
91
+ }
92
+
93
+ /**
94
+ * Combines multiple type guards with AND logic
95
+ *
96
+ * Returns a type guard that passes only if all provided type guards pass.
97
+ * Useful for filtering cards that match multiple criteria.
98
+ *
99
+ * @template T - The object type to guard
100
+ * @param guards - Array of type guard functions to combine
101
+ * @returns A combined type guard that checks all conditions
102
+ *
103
+ * @example
104
+ * ```typescript
105
+ * type Card = CardDefinition & {
106
+ * type: string;
107
+ * rarity: string;
108
+ * };
109
+ *
110
+ * const isCreature = isCardOfType<Card>("creature");
111
+ * const isRare = isCardWithField<Card, "rarity", "rare">("rarity", "rare");
112
+ * const isRareCreature = combineTypeGuards([isCreature, isRare]);
113
+ *
114
+ * const cards: Card[] = [...];
115
+ * const rareCreatures = cards.filter(isRareCreature);
116
+ * ```
117
+ */
118
+ export function combineTypeGuards<T>(
119
+ guards: Array<(obj: T) => boolean>,
120
+ ): (obj: T) => obj is T {
121
+ return (obj: T): obj is T => {
122
+ return guards.every((guard) => guard(obj));
123
+ };
124
+ }
125
+
126
+ /**
127
+ * Combines multiple type guards with OR logic
128
+ *
129
+ * Returns a type guard that passes if any of the provided type guards pass.
130
+ * Useful for filtering cards that match any of several criteria.
131
+ *
132
+ * @template T - The object type to guard
133
+ * @param guards - Array of type guard functions to combine
134
+ * @returns A combined type guard that checks any condition
135
+ *
136
+ * @example
137
+ * ```typescript
138
+ * const isCreature = isCardOfType("creature");
139
+ * const isInstant = isCardOfType("instant");
140
+ * const isSpell = combineTypeGuardsOr([isCreature, isInstant]);
141
+ *
142
+ * const cards: CardDefinition[] = [...];
143
+ * const spells = cards.filter(isSpell);
144
+ * ```
145
+ */
146
+ export function combineTypeGuardsOr<T>(
147
+ guards: Array<(obj: T) => boolean>,
148
+ ): (obj: T) => obj is T {
149
+ return (obj: T): obj is T => {
150
+ return guards.some((guard) => guard(obj));
151
+ };
152
+ }
153
+
154
+ /**
155
+ * Negates a type guard
156
+ *
157
+ * Returns a type guard that passes when the provided type guard fails.
158
+ * Useful for filtering cards that don't match a specific criterion.
159
+ *
160
+ * @template T - The object type to guard
161
+ * @param guard - The type guard to negate
162
+ * @returns A negated type guard
163
+ *
164
+ * @example
165
+ * ```typescript
166
+ * const isCreature = isCardOfType("creature");
167
+ * const isNotCreature = negateTypeGuard(isCreature);
168
+ *
169
+ * const cards: CardDefinition[] = [...];
170
+ * const nonCreatures = cards.filter(isNotCreature);
171
+ * ```
172
+ */
173
+ export function negateTypeGuard<T>(
174
+ guard: (obj: T) => boolean,
175
+ ): (obj: T) => obj is T {
176
+ return (obj: T): obj is T => {
177
+ return !guard(obj);
178
+ };
179
+ }
@@ -0,0 +1,40 @@
1
+ /**
2
+ * Validation utilities for @drmxrcy/tcg-core
3
+ *
4
+ * This module provides type guards, validators, and schema builders
5
+ * for runtime validation of cards, moves, and game states.
6
+ *
7
+ * @module validation
8
+ */
9
+
10
+ // Card-specific type guards
11
+ export {
12
+ combineTypeGuards,
13
+ combineTypeGuardsOr,
14
+ isCardOfType,
15
+ isCardWithField,
16
+ negateTypeGuard,
17
+ } from "./card-type-guards";
18
+ // Zod schema builders
19
+ export {
20
+ composeSchemas,
21
+ createArraySchema,
22
+ createCardSchema,
23
+ createDiscriminatedUnion,
24
+ createMultiRefinedSchema,
25
+ createOptionalSchema,
26
+ createRecordSchema,
27
+ createRefinedSchema,
28
+ createStrictSchema,
29
+ extendSchema,
30
+ mergeSchemas,
31
+ } from "./schema-builders";
32
+ // Type guard builder
33
+ export { createTypeGuard } from "./type-guard-builder";
34
+ // Validator builder
35
+ export {
36
+ createValidator,
37
+ type ValidationResult,
38
+ type Validator,
39
+ ValidatorBuilder,
40
+ } from "./validator-builder";