feat: add resource schemas and validation scripts

- Introduced new resource schemas for maps, scenarios, unit sets, and turn commands using Zod.
- Implemented a script to generate JSON schemas from Zod schemas.
- Added a validation script to ensure resource JSON files conform to their respective schemas.
- Updated the logic package to export new resource schemas.
- Added new dependencies for schema generation and validation.
- Created a tools-scripts package for resource management tasks.
This commit is contained in:
2026-01-18 08:04:02 +00:00
parent e3f7758187
commit 81594a25c3
20 changed files with 452 additions and 94 deletions
+4
View File
@@ -0,0 +1,4 @@
export * from './mapSchema.js';
export * from './scenarioSchema.js';
export * from './unitSetSchema.js';
export * from './turnCommandSchema.js';
+49
View File
@@ -0,0 +1,49 @@
import { z } from 'zod';
export const MapCityStatsSchema = z.object({
population: z.number(),
agriculture: z.number(),
commerce: z.number(),
security: z.number(),
defence: z.number(),
wall: z.number(),
});
export const MapCityDefinitionSchema = z.object({
id: z.number(),
name: z.string(),
level: z.number(),
region: z.number(),
position: z.object({
x: z.number(),
y: z.number(),
}),
connections: z.array(z.number()),
max: MapCityStatsSchema,
initial: MapCityStatsSchema,
meta: z.record(z.string(), z.unknown()).optional(),
});
export const MapDefaultsSchema = z
.object({
trust: z.number(),
trade: z.number(),
supplyState: z.number(),
frontState: z.number(),
})
.partial();
export const MapDefinitionSchema = z.object({
id: z.string(),
name: z.string(),
cities: z.array(MapCityDefinitionSchema),
defaults: MapDefaultsSchema.optional(),
meta: z.record(z.string(), z.unknown()).optional(),
});
export const RegionMapSchema = z.record(z.string(), z.record(z.string(), z.string()));
export const MapResourceSchema = z.union([MapDefinitionSchema, RegionMapSchema]);
export type MapDefinitionInput = z.infer<typeof MapDefinitionSchema>;
export type RegionMapInput = z.infer<typeof RegionMapSchema>;
@@ -0,0 +1,47 @@
import { z } from 'zod';
export const ScenarioStatBlockSchema = z
.object({
total: z.number(),
min: z.number(),
max: z.number(),
npcTotal: z.number(),
npcMax: z.number(),
npcMin: z.number(),
chiefMin: z.number(),
})
.partial();
export const ScenarioDefaultsInputSchema = z.object({
stat: ScenarioStatBlockSchema.optional(),
iconPath: z.string().optional(),
});
export const ScenarioDefinitionInputSchema = z
.object({
title: z.string(),
startYear: z.number().optional(),
life: z.number().optional(),
fiction: z.number().optional(),
history: z.array(z.string()).optional(),
iconPath: z.string().optional(),
stat: ScenarioStatBlockSchema.optional(),
map: z.record(z.string(), z.unknown()).optional(),
const: z.record(z.string(), z.unknown()).optional(),
nation: z.array(z.unknown()).optional(),
diplomacy: z.array(z.unknown()).optional(),
general: z.array(z.unknown()).optional(),
general_ex: z.array(z.unknown()).optional(),
general_neutral: z.array(z.unknown()).optional(),
cities: z.array(z.unknown()).optional(),
events: z.array(z.unknown()).optional(),
initialEvents: z.array(z.unknown()).optional(),
initialActions: z.array(z.unknown()).optional(),
ignoreDefaultEvents: z.boolean().optional(),
})
.passthrough();
export const ScenarioResourceSchema = z.union([ScenarioDefaultsInputSchema, ScenarioDefinitionInputSchema]);
export type ScenarioDefaultsInput = z.infer<typeof ScenarioDefaultsInputSchema>;
export type ScenarioDefinitionInput = z.infer<typeof ScenarioDefinitionInputSchema>;
@@ -0,0 +1,8 @@
import { z } from 'zod';
export const TurnCommandProfileInputSchema = z.object({
general: z.array(z.string()),
nation: z.array(z.string()),
});
export type TurnCommandProfileInput = z.infer<typeof TurnCommandProfileInputSchema>;
@@ -0,0 +1,54 @@
import { z } from 'zod';
const numericRecordSchema = z.record(z.string(), z.number());
const numericArraySchema = z.array(z.number());
export const CrewTypeRequirementSchema = z.union([
z.object({ type: z.literal('ReqTech'), tech: z.number() }),
z.object({ type: z.literal('ReqRegions'), regions: z.array(z.string()) }),
z.object({ type: z.literal('ReqCities'), cities: z.array(z.string()) }),
z.object({ type: z.literal('ReqCitiesWithCityLevel'), level: z.number(), cities: z.array(z.string()) }),
z.object({ type: z.literal('ReqHighLevelCities'), level: z.number(), count: z.number() }),
z.object({
type: z.literal('ReqNationAux'),
key: z.string(),
op: z.string(),
value: z.union([z.number(), z.string()]),
}),
z.object({ type: z.literal('ReqMinRelYear'), year: z.number() }),
z.object({ type: z.literal('ReqChief') }),
z.object({ type: z.literal('ReqNotChief') }),
z.object({ type: z.literal('Impossible') }),
z.looseObject({ type: z.string() }),
]);
export const CrewTypeDefinitionInputSchema = z.object({
id: z.number(),
armType: z.number(),
name: z.string(),
attack: z.number(),
defence: z.number(),
speed: z.number(),
avoid: z.number(),
magicCoef: z.number(),
cost: z.number(),
rice: z.number(),
requirements: z.array(CrewTypeRequirementSchema),
attackCoef: z.union([numericRecordSchema, numericArraySchema]),
defenceCoef: z.union([numericRecordSchema, numericArraySchema]),
info: z.array(z.string()),
initSkillTrigger: z.array(z.string()).nullable(),
phaseSkillTrigger: z.array(z.string()).nullable(),
iActionList: z.array(z.string()).nullable(),
});
export const UnitSetDefinitionInputSchema = z.object({
id: z.string(),
name: z.string(),
defaultCrewTypeId: z.number().optional(),
armTypes: z.record(z.string(), z.string()).optional(),
crewTypes: z.array(CrewTypeDefinitionInputSchema).optional(),
meta: z.record(z.string(), z.unknown()).optional(),
});
export type UnitSetDefinitionInput = z.infer<typeof UnitSetDefinitionInputSchema>;