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:
@@ -2,7 +2,7 @@ import fs from 'node:fs/promises';
|
|||||||
import path from 'node:path';
|
import path from 'node:path';
|
||||||
import { fileURLToPath } from 'node:url';
|
import { fileURLToPath } from 'node:url';
|
||||||
|
|
||||||
import type { MapDefinition } from '@sammo-ts/logic';
|
import { MapDefinitionSchema, type MapDefinition } from '@sammo-ts/logic';
|
||||||
|
|
||||||
const __filename = fileURLToPath(import.meta.url);
|
const __filename = fileURLToPath(import.meta.url);
|
||||||
const __dirname = path.dirname(__filename);
|
const __dirname = path.dirname(__filename);
|
||||||
@@ -28,7 +28,7 @@ export const resolveMapDefinitionPath = (mapName: string, options?: MapLoaderOpt
|
|||||||
|
|
||||||
export const loadMapDefinition = async (mapPath: string): Promise<MapDefinition> => {
|
export const loadMapDefinition = async (mapPath: string): Promise<MapDefinition> => {
|
||||||
const raw = await readJsonFile(mapPath);
|
const raw = await readJsonFile(mapPath);
|
||||||
return raw as MapDefinition;
|
return MapDefinitionSchema.parse(raw);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const loadMapDefinitionByName = async (mapName: string, options?: MapLoaderOptions): Promise<MapDefinition> => {
|
export const loadMapDefinitionByName = async (mapName: string, options?: MapLoaderOptions): Promise<MapDefinition> => {
|
||||||
|
|||||||
+6
-2
@@ -13,7 +13,9 @@
|
|||||||
"build": "turbo build",
|
"build": "turbo build",
|
||||||
"typecheck": "turbo typecheck",
|
"typecheck": "turbo typecheck",
|
||||||
"dev": "turbo dev",
|
"dev": "turbo dev",
|
||||||
"build:server": "pnpm --filter ./tools/build-scripts build:server --"
|
"build:server": "pnpm --filter ./tools/build-scripts build:server --",
|
||||||
|
"generate:resource-schemas": "pnpm --filter @sammo-ts/tools-scripts generate:resource-schemas",
|
||||||
|
"validate:resources": "pnpm --filter @sammo-ts/tools-scripts validate:resources"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@eslint/js": "^9.39.2",
|
"@eslint/js": "^9.39.2",
|
||||||
@@ -27,9 +29,11 @@
|
|||||||
"globals": "^17.0.0",
|
"globals": "^17.0.0",
|
||||||
"prettier": "^3.7.4",
|
"prettier": "^3.7.4",
|
||||||
"tsdown": "^0.18.4",
|
"tsdown": "^0.18.4",
|
||||||
|
"tsx": "^4.21.0",
|
||||||
"turbo": "^2.7.2",
|
"turbo": "^2.7.2",
|
||||||
"typescript": "^5.9.3",
|
"typescript": "^5.9.3",
|
||||||
"typescript-eslint": "^8.51.0",
|
"typescript-eslint": "^8.51.0",
|
||||||
"vue-eslint-parser": "^10.2.0"
|
"vue-eslint-parser": "^10.2.0",
|
||||||
|
"zod-to-json-schema": "^3.25.1"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import { GENERAL_TURN_COMMAND_KEYS, isGeneralTurnCommandKey, type GeneralTurnCommandKey } from './general/index.js';
|
import { GENERAL_TURN_COMMAND_KEYS, isGeneralTurnCommandKey, type GeneralTurnCommandKey } from './general/index.js';
|
||||||
import { NATION_TURN_COMMAND_KEYS, isNationTurnCommandKey, type NationTurnCommandKey } from './nation/index.js';
|
import { NATION_TURN_COMMAND_KEYS, isNationTurnCommandKey, type NationTurnCommandKey } from './nation/index.js';
|
||||||
import { asStringArray, isRecord } from '@sammo-ts/common';
|
import { asStringArray } from '@sammo-ts/common';
|
||||||
|
import { TurnCommandProfileInputSchema } from '../../resources/turnCommandSchema.js';
|
||||||
|
|
||||||
export interface TurnCommandProfile {
|
export interface TurnCommandProfile {
|
||||||
general: GeneralTurnCommandKey[];
|
general: GeneralTurnCommandKey[];
|
||||||
@@ -44,18 +45,20 @@ export const parseTurnCommandProfile = (
|
|||||||
raw: unknown,
|
raw: unknown,
|
||||||
fallback: TurnCommandProfile = DEFAULT_TURN_COMMAND_PROFILE
|
fallback: TurnCommandProfile = DEFAULT_TURN_COMMAND_PROFILE
|
||||||
): TurnCommandProfile => {
|
): TurnCommandProfile => {
|
||||||
if (!isRecord(raw)) {
|
const parsed = TurnCommandProfileInputSchema.safeParse(raw);
|
||||||
|
if (!parsed.success) {
|
||||||
return fallback;
|
return fallback;
|
||||||
}
|
}
|
||||||
|
const data = parsed.data;
|
||||||
return {
|
return {
|
||||||
general: parseKeyList({
|
general: parseKeyList({
|
||||||
raw: raw.general,
|
raw: data.general,
|
||||||
defaults: fallback.general,
|
defaults: fallback.general,
|
||||||
isKey: isGeneralTurnCommandKey,
|
isKey: isGeneralTurnCommandKey,
|
||||||
label: 'general',
|
label: 'general',
|
||||||
}),
|
}),
|
||||||
nation: parseKeyList({
|
nation: parseKeyList({
|
||||||
raw: raw.nation,
|
raw: data.nation,
|
||||||
defaults: fallback.nation,
|
defaults: fallback.nation,
|
||||||
isKey: isNationTurnCommandKey,
|
isKey: isNationTurnCommandKey,
|
||||||
label: 'nation',
|
label: 'nation',
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ export * from './logging/index.js';
|
|||||||
export * from './messages/index.js';
|
export * from './messages/index.js';
|
||||||
export * from './items/index.js';
|
export * from './items/index.js';
|
||||||
export { ITEM_KEYS, createItemActionModules, createItemModuleRegistry, loadItemModules } from './items/index.js';
|
export { ITEM_KEYS, createItemActionModules, createItemModuleRegistry, loadItemModules } from './items/index.js';
|
||||||
|
export * from './resources/index.js';
|
||||||
export * from './ports/world.js';
|
export * from './ports/world.js';
|
||||||
export * from './ports/worldSnapshot.js';
|
export * from './ports/worldSnapshot.js';
|
||||||
export * from './scenario/index.js';
|
export * from './scenario/index.js';
|
||||||
|
|||||||
@@ -0,0 +1,4 @@
|
|||||||
|
export * from './mapSchema.js';
|
||||||
|
export * from './scenarioSchema.js';
|
||||||
|
export * from './unitSetSchema.js';
|
||||||
|
export * from './turnCommandSchema.js';
|
||||||
@@ -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>;
|
||||||
@@ -1,6 +1,8 @@
|
|||||||
import { z } from 'zod';
|
import { z } from 'zod';
|
||||||
import { asNullableNumber, asNullableString, asNumber, asString, asStringArray, isRecord } from '@sammo-ts/common';
|
import { asNullableNumber, asNullableString, asNumber, asString, asStringArray, isRecord } from '@sammo-ts/common';
|
||||||
|
|
||||||
|
import { ScenarioDefaultsInputSchema, ScenarioDefinitionInputSchema } from '../resources/scenarioSchema.js';
|
||||||
|
|
||||||
import type {
|
import type {
|
||||||
ScenarioConfig,
|
ScenarioConfig,
|
||||||
ScenarioDefaults,
|
ScenarioDefaults,
|
||||||
@@ -24,56 +26,7 @@ const FALLBACK_STAT: ScenarioStatBlock = {
|
|||||||
chiefMin: 0,
|
chiefMin: 0,
|
||||||
};
|
};
|
||||||
|
|
||||||
const toRecordOrUndefined = (value: unknown): UnknownRecord | undefined => (isRecord(value) ? value : undefined);
|
|
||||||
|
|
||||||
const toArrayOrUndefined = (value: unknown): unknown[] | undefined => (Array.isArray(value) ? value : undefined);
|
|
||||||
|
|
||||||
const zRecord = z.record(z.string(), z.unknown());
|
|
||||||
const zUnknownArray = z.array(z.unknown());
|
const zUnknownArray = z.array(z.unknown());
|
||||||
const zOptionalRecord = z.preprocess(toRecordOrUndefined, zRecord.optional());
|
|
||||||
const zOptionalArray = z.preprocess(toArrayOrUndefined, zUnknownArray.optional());
|
|
||||||
const zStatInput = z
|
|
||||||
.object({
|
|
||||||
total: z.number().optional(),
|
|
||||||
min: z.number().optional(),
|
|
||||||
max: z.number().optional(),
|
|
||||||
npcTotal: z.number().optional(),
|
|
||||||
npcMax: z.number().optional(),
|
|
||||||
npcMin: z.number().optional(),
|
|
||||||
chiefMin: z.number().optional(),
|
|
||||||
})
|
|
||||||
.partial();
|
|
||||||
|
|
||||||
const zScenarioDefaults = z
|
|
||||||
.object({
|
|
||||||
stat: z.preprocess(toRecordOrUndefined, zStatInput.optional()),
|
|
||||||
iconPath: z.string().optional(),
|
|
||||||
})
|
|
||||||
.passthrough();
|
|
||||||
|
|
||||||
const zScenarioInput = z
|
|
||||||
.object({
|
|
||||||
title: z.string(),
|
|
||||||
startYear: z.number().optional(),
|
|
||||||
life: z.number().optional(),
|
|
||||||
fiction: z.number().optional(),
|
|
||||||
history: zOptionalArray,
|
|
||||||
iconPath: z.string().optional(),
|
|
||||||
stat: z.preprocess(toRecordOrUndefined, zStatInput.optional()),
|
|
||||||
map: zOptionalRecord,
|
|
||||||
const: zOptionalRecord,
|
|
||||||
nation: zOptionalArray,
|
|
||||||
diplomacy: zOptionalArray,
|
|
||||||
general: zOptionalArray,
|
|
||||||
general_ex: zOptionalArray,
|
|
||||||
general_neutral: zOptionalArray,
|
|
||||||
cities: zOptionalArray,
|
|
||||||
events: zOptionalArray,
|
|
||||||
initialEvents: zOptionalArray,
|
|
||||||
initialActions: zOptionalArray,
|
|
||||||
ignoreDefaultEvents: z.boolean().optional(),
|
|
||||||
})
|
|
||||||
.passthrough();
|
|
||||||
|
|
||||||
const parseScenarioStatBlock = (value: unknown, fallback: ScenarioStatBlock): ScenarioStatBlock => {
|
const parseScenarioStatBlock = (value: unknown, fallback: ScenarioStatBlock): ScenarioStatBlock => {
|
||||||
const data = isRecord(value) ? value : {};
|
const data = isRecord(value) ? value : {};
|
||||||
@@ -211,7 +164,7 @@ const parseDiplomacyRows = (rows: unknown[]): ScenarioDiplomacy[] =>
|
|||||||
|
|
||||||
export const parseScenarioDefaults = (raw: unknown): ScenarioDefaults => {
|
export const parseScenarioDefaults = (raw: unknown): ScenarioDefaults => {
|
||||||
// 기본 시나리오 설정값을 안전하게 읽는다.
|
// 기본 시나리오 설정값을 안전하게 읽는다.
|
||||||
const data = zScenarioDefaults.parse(raw);
|
const data = ScenarioDefaultsInputSchema.parse(raw);
|
||||||
const stat = parseScenarioStatBlock(data.stat, FALLBACK_STAT);
|
const stat = parseScenarioStatBlock(data.stat, FALLBACK_STAT);
|
||||||
const iconPath = asString(data.iconPath, '.');
|
const iconPath = asString(data.iconPath, '.');
|
||||||
return { stat, iconPath };
|
return { stat, iconPath };
|
||||||
@@ -219,7 +172,7 @@ export const parseScenarioDefaults = (raw: unknown): ScenarioDefaults => {
|
|||||||
|
|
||||||
export const parseScenarioDefinition = (raw: unknown, defaults: ScenarioDefaults): ScenarioDefinition => {
|
export const parseScenarioDefinition = (raw: unknown, defaults: ScenarioDefaults): ScenarioDefinition => {
|
||||||
// 시나리오 JSON을 런타임에서 쓰는 구조로 정규화한다.
|
// 시나리오 JSON을 런타임에서 쓰는 구조로 정규화한다.
|
||||||
const data = zScenarioInput.parse(raw);
|
const data = ScenarioDefinitionInputSchema.parse(raw);
|
||||||
const stat = parseScenarioStatBlock(data.stat, defaults.stat);
|
const stat = parseScenarioStatBlock(data.stat, defaults.stat);
|
||||||
const mapConfig = data.map ?? {};
|
const mapConfig = data.map ?? {};
|
||||||
const constConfig = data.const ?? {};
|
const constConfig = data.const ?? {};
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import {
|
|||||||
asStringArray,
|
asStringArray,
|
||||||
isRecord,
|
isRecord,
|
||||||
} from '@sammo-ts/common';
|
} from '@sammo-ts/common';
|
||||||
|
import { UnitSetDefinitionInputSchema } from '../resources/unitSetSchema.js';
|
||||||
|
|
||||||
const DEFAULT_REGION_MAP: Record<string, number> = {
|
const DEFAULT_REGION_MAP: Record<string, number> = {
|
||||||
하북: 1,
|
하북: 1,
|
||||||
@@ -114,7 +115,7 @@ const parseCrewType = (value: unknown): CrewTypeDefinition | null => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const parseUnitSetDefinition = (value: unknown): UnitSetDefinition => {
|
export const parseUnitSetDefinition = (value: unknown): UnitSetDefinition => {
|
||||||
const data = asRecord(value);
|
const data = UnitSetDefinitionInputSchema.parse(value);
|
||||||
const id = asString(data.id, 'unknown');
|
const id = asString(data.id, 'unknown');
|
||||||
const name = asString(data.name, id);
|
const name = asString(data.name, id);
|
||||||
const defaultCrewTypeId =
|
const defaultCrewTypeId =
|
||||||
|
|||||||
@@ -0,0 +1,19 @@
|
|||||||
|
{
|
||||||
|
"name": "@sammo-ts/tools-scripts",
|
||||||
|
"private": true,
|
||||||
|
"version": "0.0.0",
|
||||||
|
"type": "module",
|
||||||
|
"scripts": {
|
||||||
|
"generate:resource-schemas": "tsx src/generate-resource-schemas.ts",
|
||||||
|
"validate:resources": "tsx src/validate-resources.ts",
|
||||||
|
"typecheck": "tsc -p tsconfig.json --noEmit"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@sammo-ts/logic": "workspace:*",
|
||||||
|
"zod-to-json-schema": "^3.25.1"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"tsx": "^4.21.0",
|
||||||
|
"typescript": "^5.9.3"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
import fs from 'node:fs/promises';
|
||||||
|
import path from 'node:path';
|
||||||
|
import { fileURLToPath } from 'node:url';
|
||||||
|
|
||||||
|
import type { ZodTypeAny } from 'zod';
|
||||||
|
import { zodToJsonSchema } from 'zod-to-json-schema';
|
||||||
|
import {
|
||||||
|
MapResourceSchema,
|
||||||
|
ScenarioResourceSchema,
|
||||||
|
TurnCommandProfileInputSchema,
|
||||||
|
UnitSetDefinitionInputSchema,
|
||||||
|
} from '@sammo-ts/logic';
|
||||||
|
|
||||||
|
const __filename = fileURLToPath(import.meta.url);
|
||||||
|
const __dirname = path.dirname(__filename);
|
||||||
|
const REPO_ROOT = path.resolve(__dirname, '..', '..', '..');
|
||||||
|
const RESOURCE_ROOT = path.join(REPO_ROOT, 'resources');
|
||||||
|
|
||||||
|
const writeSchema = async (relativePath: string, schema: ZodTypeAny, name: string): Promise<void> => {
|
||||||
|
const outputPath = path.join(RESOURCE_ROOT, relativePath);
|
||||||
|
const jsonSchema = zodToJsonSchema(schema, { name, target: 'jsonSchema7' });
|
||||||
|
const serialized = `${JSON.stringify(jsonSchema, null, 4)}\n`;
|
||||||
|
await fs.writeFile(outputPath, serialized, 'utf8');
|
||||||
|
};
|
||||||
|
|
||||||
|
const main = async (): Promise<void> => {
|
||||||
|
await writeSchema(path.join('map', 'schema.json'), MapResourceSchema, 'MapResource');
|
||||||
|
await writeSchema(path.join('scenario', 'schema.json'), ScenarioResourceSchema, 'ScenarioResource');
|
||||||
|
await writeSchema(path.join('unitset', 'schema.json'), UnitSetDefinitionInputSchema, 'UnitSetDefinition');
|
||||||
|
await writeSchema(path.join('turn-commands', 'schema.json'), TurnCommandProfileInputSchema, 'TurnCommandProfile');
|
||||||
|
};
|
||||||
|
|
||||||
|
main().catch((error) => {
|
||||||
|
console.error(error);
|
||||||
|
process.exitCode = 1;
|
||||||
|
});
|
||||||
@@ -0,0 +1,86 @@
|
|||||||
|
import fs from 'node:fs/promises';
|
||||||
|
import path from 'node:path';
|
||||||
|
import { fileURLToPath } from 'node:url';
|
||||||
|
|
||||||
|
import {
|
||||||
|
MapResourceSchema,
|
||||||
|
ScenarioResourceSchema,
|
||||||
|
TurnCommandProfileInputSchema,
|
||||||
|
UnitSetDefinitionInputSchema,
|
||||||
|
} from '@sammo-ts/logic';
|
||||||
|
|
||||||
|
const __filename = fileURLToPath(import.meta.url);
|
||||||
|
const __dirname = path.dirname(__filename);
|
||||||
|
const REPO_ROOT = path.resolve(__dirname, '..', '..', '..');
|
||||||
|
const RESOURCE_ROOT = path.join(REPO_ROOT, 'resources');
|
||||||
|
|
||||||
|
const RESOURCE_SCHEMAS: Record<string, (value: unknown) => void> = {
|
||||||
|
map: (value) => MapResourceSchema.parse(value),
|
||||||
|
scenario: (value) => ScenarioResourceSchema.parse(value),
|
||||||
|
unitset: (value) => UnitSetDefinitionInputSchema.parse(value),
|
||||||
|
'turn-commands': (value) => TurnCommandProfileInputSchema.parse(value),
|
||||||
|
};
|
||||||
|
|
||||||
|
const listJsonFiles = async (dirPath: string): Promise<string[]> => {
|
||||||
|
const entries = await fs.readdir(dirPath, { withFileTypes: true });
|
||||||
|
return entries
|
||||||
|
.filter((entry) => entry.isFile() && entry.name.endsWith('.json') && entry.name !== 'schema.json')
|
||||||
|
.map((entry) => entry.name)
|
||||||
|
.sort((a, b) => a.localeCompare(b));
|
||||||
|
};
|
||||||
|
|
||||||
|
const validateFolder = async (folder: string): Promise<string[]> => {
|
||||||
|
const schema = RESOURCE_SCHEMAS[folder];
|
||||||
|
if (!schema) {
|
||||||
|
return [`Unknown resource folder: ${folder}`];
|
||||||
|
}
|
||||||
|
const folderPath = path.join(RESOURCE_ROOT, folder);
|
||||||
|
const files = await listJsonFiles(folderPath);
|
||||||
|
const errors: string[] = [];
|
||||||
|
|
||||||
|
for (const fileName of files) {
|
||||||
|
const filePath = path.join(folderPath, fileName);
|
||||||
|
const raw = await fs.readFile(filePath, 'utf8');
|
||||||
|
let parsed: unknown;
|
||||||
|
try {
|
||||||
|
parsed = JSON.parse(raw) as unknown;
|
||||||
|
} catch (error) {
|
||||||
|
const message = error instanceof Error ? error.message : String(error);
|
||||||
|
errors.push(`${path.relative(REPO_ROOT, filePath)}: invalid JSON (${message})`);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
schema(parsed);
|
||||||
|
} catch (error) {
|
||||||
|
const message = error instanceof Error ? error.message : String(error);
|
||||||
|
errors.push(`${path.relative(REPO_ROOT, filePath)}: ${message}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return errors;
|
||||||
|
};
|
||||||
|
|
||||||
|
const main = async (): Promise<void> => {
|
||||||
|
const folders = Object.keys(RESOURCE_SCHEMAS).sort((a, b) => a.localeCompare(b));
|
||||||
|
const allErrors: string[] = [];
|
||||||
|
|
||||||
|
for (const folder of folders) {
|
||||||
|
const errors = await validateFolder(folder);
|
||||||
|
allErrors.push(...errors);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (allErrors.length > 0) {
|
||||||
|
for (const error of allErrors) {
|
||||||
|
console.error(`[resource-validate] ${error}`);
|
||||||
|
}
|
||||||
|
process.exitCode = 1;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('[resource-validate] OK');
|
||||||
|
};
|
||||||
|
|
||||||
|
main().catch((error) => {
|
||||||
|
console.error(error);
|
||||||
|
process.exitCode = 1;
|
||||||
|
});
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
{
|
||||||
|
"extends": "../../tsconfig.paths.json",
|
||||||
|
"compilerOptions": {
|
||||||
|
"module": "NodeNext",
|
||||||
|
"moduleResolution": "NodeNext",
|
||||||
|
"target": "ES2023",
|
||||||
|
"lib": ["ES2024"],
|
||||||
|
"verbatimModuleSyntax": true,
|
||||||
|
"noUncheckedIndexedAccess": true,
|
||||||
|
"exactOptionalPropertyTypes": true,
|
||||||
|
"noImplicitOverride": true,
|
||||||
|
"noImplicitReturns": true,
|
||||||
|
"noFallthroughCasesInSwitch": true,
|
||||||
|
"useUnknownInCatchVariables": true,
|
||||||
|
"noUnusedLocals": true,
|
||||||
|
"noUnusedParameters": true
|
||||||
|
},
|
||||||
|
"include": ["src"],
|
||||||
|
"references": [{ "path": "../logic" }]
|
||||||
|
}
|
||||||
Generated
+79
-34
@@ -41,6 +41,9 @@ importers:
|
|||||||
tsdown:
|
tsdown:
|
||||||
specifier: ^0.18.4
|
specifier: ^0.18.4
|
||||||
version: 0.18.4(synckit@0.11.11)(typescript@5.9.3)(vue-tsc@3.2.2(typescript@5.9.3))
|
version: 0.18.4(synckit@0.11.11)(typescript@5.9.3)(vue-tsc@3.2.2(typescript@5.9.3))
|
||||||
|
tsx:
|
||||||
|
specifier: ^4.21.0
|
||||||
|
version: 4.21.0
|
||||||
turbo:
|
turbo:
|
||||||
specifier: ^2.7.2
|
specifier: ^2.7.2
|
||||||
version: 2.7.2
|
version: 2.7.2
|
||||||
@@ -53,6 +56,9 @@ importers:
|
|||||||
vue-eslint-parser:
|
vue-eslint-parser:
|
||||||
specifier: ^10.2.0
|
specifier: ^10.2.0
|
||||||
version: 10.2.0(eslint@9.39.2(jiti@2.6.1))
|
version: 10.2.0(eslint@9.39.2(jiti@2.6.1))
|
||||||
|
zod-to-json-schema:
|
||||||
|
specifier: ^3.25.1
|
||||||
|
version: 3.25.1(zod@4.3.5)
|
||||||
|
|
||||||
app/game-api:
|
app/game-api:
|
||||||
dependencies:
|
dependencies:
|
||||||
@@ -92,10 +98,10 @@ importers:
|
|||||||
version: 0.18.4(synckit@0.11.11)(typescript@5.9.3)(vue-tsc@3.2.2(typescript@5.9.3))
|
version: 0.18.4(synckit@0.11.11)(typescript@5.9.3)(vue-tsc@3.2.2(typescript@5.9.3))
|
||||||
vite-tsconfig-paths:
|
vite-tsconfig-paths:
|
||||||
specifier: ^6.0.3
|
specifier: ^6.0.3
|
||||||
version: 6.0.3(typescript@5.9.3)(vite@7.3.1(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2))
|
version: 6.0.3(typescript@5.9.3)(vite@7.3.1(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.21.0))
|
||||||
vitest:
|
vitest:
|
||||||
specifier: ^4.0.16
|
specifier: ^4.0.16
|
||||||
version: 4.0.16(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)
|
version: 4.0.16(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.21.0)
|
||||||
|
|
||||||
app/game-engine:
|
app/game-engine:
|
||||||
dependencies:
|
dependencies:
|
||||||
@@ -123,10 +129,10 @@ importers:
|
|||||||
version: 0.18.4(synckit@0.11.11)(typescript@5.9.3)(vue-tsc@3.2.2(typescript@5.9.3))
|
version: 0.18.4(synckit@0.11.11)(typescript@5.9.3)(vue-tsc@3.2.2(typescript@5.9.3))
|
||||||
vite-tsconfig-paths:
|
vite-tsconfig-paths:
|
||||||
specifier: ^6.0.3
|
specifier: ^6.0.3
|
||||||
version: 6.0.3(typescript@5.9.3)(vite@7.3.1(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2))
|
version: 6.0.3(typescript@5.9.3)(vite@7.3.1(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.21.0))
|
||||||
vitest:
|
vitest:
|
||||||
specifier: ^4.0.16
|
specifier: ^4.0.16
|
||||||
version: 4.0.16(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)
|
version: 4.0.16(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.21.0)
|
||||||
|
|
||||||
app/game-frontend:
|
app/game-frontend:
|
||||||
dependencies:
|
dependencies:
|
||||||
@@ -175,10 +181,10 @@ importers:
|
|||||||
devDependencies:
|
devDependencies:
|
||||||
'@tailwindcss/vite':
|
'@tailwindcss/vite':
|
||||||
specifier: ^4.1.18
|
specifier: ^4.1.18
|
||||||
version: 4.1.18(vite@7.3.1(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2))
|
version: 4.1.18(vite@7.3.1(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.21.0))
|
||||||
'@vitejs/plugin-vue':
|
'@vitejs/plugin-vue':
|
||||||
specifier: ^6.0.3
|
specifier: ^6.0.3
|
||||||
version: 6.0.3(vite@7.3.1(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2))(vue@3.5.26(typescript@5.9.3))
|
version: 6.0.3(vite@7.3.1(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.21.0))(vue@3.5.26(typescript@5.9.3))
|
||||||
autoprefixer:
|
autoprefixer:
|
||||||
specifier: ^10.4.23
|
specifier: ^10.4.23
|
||||||
version: 10.4.23(postcss@8.5.6)
|
version: 10.4.23(postcss@8.5.6)
|
||||||
@@ -193,7 +199,7 @@ importers:
|
|||||||
version: 5.9.3
|
version: 5.9.3
|
||||||
vite:
|
vite:
|
||||||
specifier: ^7.3.1
|
specifier: ^7.3.1
|
||||||
version: 7.3.1(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)
|
version: 7.3.1(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.21.0)
|
||||||
vue-tsc:
|
vue-tsc:
|
||||||
specifier: ^3.2.2
|
specifier: ^3.2.2
|
||||||
version: 3.2.2(typescript@5.9.3)
|
version: 3.2.2(typescript@5.9.3)
|
||||||
@@ -245,10 +251,10 @@ importers:
|
|||||||
version: 0.18.4(synckit@0.11.11)(typescript@5.9.3)(vue-tsc@3.2.2(typescript@5.9.3))
|
version: 0.18.4(synckit@0.11.11)(typescript@5.9.3)(vue-tsc@3.2.2(typescript@5.9.3))
|
||||||
vite-tsconfig-paths:
|
vite-tsconfig-paths:
|
||||||
specifier: ^6.0.3
|
specifier: ^6.0.3
|
||||||
version: 6.0.3(typescript@5.9.3)(vite@7.3.1(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2))
|
version: 6.0.3(typescript@5.9.3)(vite@7.3.1(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.21.0))
|
||||||
vitest:
|
vitest:
|
||||||
specifier: ^4.0.16
|
specifier: ^4.0.16
|
||||||
version: 4.0.16(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)
|
version: 4.0.16(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.21.0)
|
||||||
|
|
||||||
app/gateway-frontend:
|
app/gateway-frontend:
|
||||||
dependencies:
|
dependencies:
|
||||||
@@ -297,10 +303,10 @@ importers:
|
|||||||
devDependencies:
|
devDependencies:
|
||||||
'@tailwindcss/vite':
|
'@tailwindcss/vite':
|
||||||
specifier: ^4.1.18
|
specifier: ^4.1.18
|
||||||
version: 4.1.18(vite@7.3.0(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2))
|
version: 4.1.18(vite@7.3.0(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.21.0))
|
||||||
'@vitejs/plugin-vue':
|
'@vitejs/plugin-vue':
|
||||||
specifier: ^6.0.3
|
specifier: ^6.0.3
|
||||||
version: 6.0.3(vite@7.3.0(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2))(vue@3.5.26(typescript@5.9.3))
|
version: 6.0.3(vite@7.3.0(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.21.0))(vue@3.5.26(typescript@5.9.3))
|
||||||
autoprefixer:
|
autoprefixer:
|
||||||
specifier: ^10.4.23
|
specifier: ^10.4.23
|
||||||
version: 10.4.23(postcss@8.5.6)
|
version: 10.4.23(postcss@8.5.6)
|
||||||
@@ -315,7 +321,7 @@ importers:
|
|||||||
version: 5.9.3
|
version: 5.9.3
|
||||||
vite:
|
vite:
|
||||||
specifier: ^7.3.0
|
specifier: ^7.3.0
|
||||||
version: 7.3.0(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)
|
version: 7.3.0(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.21.0)
|
||||||
vue-tsc:
|
vue-tsc:
|
||||||
specifier: ^3.2.1
|
specifier: ^3.2.1
|
||||||
version: 3.2.1(typescript@5.9.3)
|
version: 3.2.1(typescript@5.9.3)
|
||||||
@@ -334,7 +340,7 @@ importers:
|
|||||||
version: 0.18.4(synckit@0.11.11)(typescript@5.9.3)(vue-tsc@3.2.2(typescript@5.9.3))
|
version: 0.18.4(synckit@0.11.11)(typescript@5.9.3)(vue-tsc@3.2.2(typescript@5.9.3))
|
||||||
vitest:
|
vitest:
|
||||||
specifier: ^4.0.16
|
specifier: ^4.0.16
|
||||||
version: 4.0.16(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)
|
version: 4.0.16(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.21.0)
|
||||||
|
|
||||||
packages/infra:
|
packages/infra:
|
||||||
dependencies:
|
dependencies:
|
||||||
@@ -390,10 +396,26 @@ importers:
|
|||||||
version: 0.18.4(synckit@0.11.11)(typescript@5.9.3)(vue-tsc@3.2.2(typescript@5.9.3))
|
version: 0.18.4(synckit@0.11.11)(typescript@5.9.3)(vue-tsc@3.2.2(typescript@5.9.3))
|
||||||
vite-tsconfig-paths:
|
vite-tsconfig-paths:
|
||||||
specifier: ^6.0.3
|
specifier: ^6.0.3
|
||||||
version: 6.0.3(typescript@5.9.3)(vite@7.3.1(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2))
|
version: 6.0.3(typescript@5.9.3)(vite@7.3.1(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.21.0))
|
||||||
vitest:
|
vitest:
|
||||||
specifier: ^4.0.16
|
specifier: ^4.0.16
|
||||||
version: 4.0.16(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)
|
version: 4.0.16(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.21.0)
|
||||||
|
|
||||||
|
packages/tools-scripts:
|
||||||
|
dependencies:
|
||||||
|
'@sammo-ts/logic':
|
||||||
|
specifier: workspace:*
|
||||||
|
version: link:../logic
|
||||||
|
zod-to-json-schema:
|
||||||
|
specifier: ^3.25.1
|
||||||
|
version: 3.25.1(zod@4.3.5)
|
||||||
|
devDependencies:
|
||||||
|
tsx:
|
||||||
|
specifier: ^4.21.0
|
||||||
|
version: 4.21.0
|
||||||
|
typescript:
|
||||||
|
specifier: ^5.9.3
|
||||||
|
version: 5.9.3
|
||||||
|
|
||||||
tools/build-scripts: {}
|
tools/build-scripts: {}
|
||||||
|
|
||||||
@@ -420,10 +442,10 @@ importers:
|
|||||||
devDependencies:
|
devDependencies:
|
||||||
vite-tsconfig-paths:
|
vite-tsconfig-paths:
|
||||||
specifier: ^6.0.3
|
specifier: ^6.0.3
|
||||||
version: 6.0.3(typescript@5.9.3)(vite@7.3.1(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2))
|
version: 6.0.3(typescript@5.9.3)(vite@7.3.1(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.21.0))
|
||||||
vitest:
|
vitest:
|
||||||
specifier: ^4.0.16
|
specifier: ^4.0.16
|
||||||
version: 4.0.16(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)
|
version: 4.0.16(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.21.0)
|
||||||
|
|
||||||
packages:
|
packages:
|
||||||
|
|
||||||
@@ -3124,6 +3146,11 @@ packages:
|
|||||||
tslib@2.8.1:
|
tslib@2.8.1:
|
||||||
resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==}
|
resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==}
|
||||||
|
|
||||||
|
tsx@4.21.0:
|
||||||
|
resolution: {integrity: sha512-5C1sg4USs1lfG0GFb2RLXsdpXqBSEhAaA/0kPL01wxzpMqLILNxIxIOKiILz+cdg/pLnOUxFYOR5yhHU666wbw==}
|
||||||
|
engines: {node: '>=18.0.0'}
|
||||||
|
hasBin: true
|
||||||
|
|
||||||
turbo-darwin-64@2.7.2:
|
turbo-darwin-64@2.7.2:
|
||||||
resolution: {integrity: sha512-dxY3X6ezcT5vm3coK6VGixbrhplbQMwgNsCsvZamS/+/6JiebqW9DKt4NwpgYXhDY2HdH00I7FWs3wkVuan4rA==}
|
resolution: {integrity: sha512-dxY3X6ezcT5vm3coK6VGixbrhplbQMwgNsCsvZamS/+/6JiebqW9DKt4NwpgYXhDY2HdH00I7FWs3wkVuan4rA==}
|
||||||
cpu: [x64]
|
cpu: [x64]
|
||||||
@@ -3425,6 +3452,11 @@ packages:
|
|||||||
zeptomatch@2.0.2:
|
zeptomatch@2.0.2:
|
||||||
resolution: {integrity: sha512-H33jtSKf8Ijtb5BW6wua3G5DhnFjbFML36eFu+VdOoVY4HD9e7ggjqdM6639B+L87rjnR6Y+XeRzBXZdy52B/g==}
|
resolution: {integrity: sha512-H33jtSKf8Ijtb5BW6wua3G5DhnFjbFML36eFu+VdOoVY4HD9e7ggjqdM6639B+L87rjnR6Y+XeRzBXZdy52B/g==}
|
||||||
|
|
||||||
|
zod-to-json-schema@3.25.1:
|
||||||
|
resolution: {integrity: sha512-pM/SU9d3YAggzi6MtR4h7ruuQlqKtad8e9S0fmxcMi+ueAK5Korys/aWcV9LIIHTVbj01NdzxcnXSN+O74ZIVA==}
|
||||||
|
peerDependencies:
|
||||||
|
zod: ^3.25 || ^4
|
||||||
|
|
||||||
zod@4.3.4:
|
zod@4.3.4:
|
||||||
resolution: {integrity: sha512-Zw/uYiiyF6pUT1qmKbZziChgNPRu+ZRneAsMUDU6IwmXdWt5JwcUfy2bvLOCUtz5UniaN/Zx5aFttZYbYc7O/A==}
|
resolution: {integrity: sha512-Zw/uYiiyF6pUT1qmKbZziChgNPRu+ZRneAsMUDU6IwmXdWt5JwcUfy2bvLOCUtz5UniaN/Zx5aFttZYbYc7O/A==}
|
||||||
|
|
||||||
@@ -4166,19 +4198,19 @@ snapshots:
|
|||||||
'@tailwindcss/oxide-win32-arm64-msvc': 4.1.18
|
'@tailwindcss/oxide-win32-arm64-msvc': 4.1.18
|
||||||
'@tailwindcss/oxide-win32-x64-msvc': 4.1.18
|
'@tailwindcss/oxide-win32-x64-msvc': 4.1.18
|
||||||
|
|
||||||
'@tailwindcss/vite@4.1.18(vite@7.3.0(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2))':
|
'@tailwindcss/vite@4.1.18(vite@7.3.0(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.21.0))':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@tailwindcss/node': 4.1.18
|
'@tailwindcss/node': 4.1.18
|
||||||
'@tailwindcss/oxide': 4.1.18
|
'@tailwindcss/oxide': 4.1.18
|
||||||
tailwindcss: 4.1.18
|
tailwindcss: 4.1.18
|
||||||
vite: 7.3.0(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)
|
vite: 7.3.0(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.21.0)
|
||||||
|
|
||||||
'@tailwindcss/vite@4.1.18(vite@7.3.1(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2))':
|
'@tailwindcss/vite@4.1.18(vite@7.3.1(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.21.0))':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@tailwindcss/node': 4.1.18
|
'@tailwindcss/node': 4.1.18
|
||||||
'@tailwindcss/oxide': 4.1.18
|
'@tailwindcss/oxide': 4.1.18
|
||||||
tailwindcss: 4.1.18
|
tailwindcss: 4.1.18
|
||||||
vite: 7.3.1(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)
|
vite: 7.3.1(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.21.0)
|
||||||
|
|
||||||
'@tootallnate/quickjs-emscripten@0.23.0': {}
|
'@tootallnate/quickjs-emscripten@0.23.0': {}
|
||||||
|
|
||||||
@@ -4314,16 +4346,16 @@ snapshots:
|
|||||||
'@typescript-eslint/types': 8.51.0
|
'@typescript-eslint/types': 8.51.0
|
||||||
eslint-visitor-keys: 4.2.1
|
eslint-visitor-keys: 4.2.1
|
||||||
|
|
||||||
'@vitejs/plugin-vue@6.0.3(vite@7.3.0(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2))(vue@3.5.26(typescript@5.9.3))':
|
'@vitejs/plugin-vue@6.0.3(vite@7.3.0(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.21.0))(vue@3.5.26(typescript@5.9.3))':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@rolldown/pluginutils': 1.0.0-beta.53
|
'@rolldown/pluginutils': 1.0.0-beta.53
|
||||||
vite: 7.3.0(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)
|
vite: 7.3.0(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.21.0)
|
||||||
vue: 3.5.26(typescript@5.9.3)
|
vue: 3.5.26(typescript@5.9.3)
|
||||||
|
|
||||||
'@vitejs/plugin-vue@6.0.3(vite@7.3.1(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2))(vue@3.5.26(typescript@5.9.3))':
|
'@vitejs/plugin-vue@6.0.3(vite@7.3.1(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.21.0))(vue@3.5.26(typescript@5.9.3))':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@rolldown/pluginutils': 1.0.0-beta.53
|
'@rolldown/pluginutils': 1.0.0-beta.53
|
||||||
vite: 7.3.1(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)
|
vite: 7.3.1(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.21.0)
|
||||||
vue: 3.5.26(typescript@5.9.3)
|
vue: 3.5.26(typescript@5.9.3)
|
||||||
|
|
||||||
'@vitest/expect@4.0.16':
|
'@vitest/expect@4.0.16':
|
||||||
@@ -4335,13 +4367,13 @@ snapshots:
|
|||||||
chai: 6.2.2
|
chai: 6.2.2
|
||||||
tinyrainbow: 3.0.3
|
tinyrainbow: 3.0.3
|
||||||
|
|
||||||
'@vitest/mocker@4.0.16(vite@7.3.1(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2))':
|
'@vitest/mocker@4.0.16(vite@7.3.1(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.21.0))':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@vitest/spy': 4.0.16
|
'@vitest/spy': 4.0.16
|
||||||
estree-walker: 3.0.3
|
estree-walker: 3.0.3
|
||||||
magic-string: 0.30.21
|
magic-string: 0.30.21
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
vite: 7.3.1(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)
|
vite: 7.3.1(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.21.0)
|
||||||
|
|
||||||
'@vitest/pretty-format@4.0.16':
|
'@vitest/pretty-format@4.0.16':
|
||||||
dependencies:
|
dependencies:
|
||||||
@@ -6035,6 +6067,13 @@ snapshots:
|
|||||||
|
|
||||||
tslib@2.8.1: {}
|
tslib@2.8.1: {}
|
||||||
|
|
||||||
|
tsx@4.21.0:
|
||||||
|
dependencies:
|
||||||
|
esbuild: 0.27.2
|
||||||
|
get-tsconfig: 4.13.0
|
||||||
|
optionalDependencies:
|
||||||
|
fsevents: 2.3.3
|
||||||
|
|
||||||
turbo-darwin-64@2.7.2:
|
turbo-darwin-64@2.7.2:
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
@@ -6117,18 +6156,18 @@ snapshots:
|
|||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
typescript: 5.9.3
|
typescript: 5.9.3
|
||||||
|
|
||||||
vite-tsconfig-paths@6.0.3(typescript@5.9.3)(vite@7.3.1(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)):
|
vite-tsconfig-paths@6.0.3(typescript@5.9.3)(vite@7.3.1(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.21.0)):
|
||||||
dependencies:
|
dependencies:
|
||||||
debug: 4.4.3
|
debug: 4.4.3
|
||||||
globrex: 0.1.2
|
globrex: 0.1.2
|
||||||
tsconfck: 3.1.6(typescript@5.9.3)
|
tsconfck: 3.1.6(typescript@5.9.3)
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
vite: 7.3.1(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)
|
vite: 7.3.1(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.21.0)
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- supports-color
|
- supports-color
|
||||||
- typescript
|
- typescript
|
||||||
|
|
||||||
vite@7.3.0(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2):
|
vite@7.3.0(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.21.0):
|
||||||
dependencies:
|
dependencies:
|
||||||
esbuild: 0.27.2
|
esbuild: 0.27.2
|
||||||
fdir: 6.5.0(picomatch@4.0.3)
|
fdir: 6.5.0(picomatch@4.0.3)
|
||||||
@@ -6141,8 +6180,9 @@ snapshots:
|
|||||||
fsevents: 2.3.3
|
fsevents: 2.3.3
|
||||||
jiti: 2.6.1
|
jiti: 2.6.1
|
||||||
lightningcss: 1.30.2
|
lightningcss: 1.30.2
|
||||||
|
tsx: 4.21.0
|
||||||
|
|
||||||
vite@7.3.1(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2):
|
vite@7.3.1(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.21.0):
|
||||||
dependencies:
|
dependencies:
|
||||||
esbuild: 0.27.2
|
esbuild: 0.27.2
|
||||||
fdir: 6.5.0(picomatch@4.0.3)
|
fdir: 6.5.0(picomatch@4.0.3)
|
||||||
@@ -6155,11 +6195,12 @@ snapshots:
|
|||||||
fsevents: 2.3.3
|
fsevents: 2.3.3
|
||||||
jiti: 2.6.1
|
jiti: 2.6.1
|
||||||
lightningcss: 1.30.2
|
lightningcss: 1.30.2
|
||||||
|
tsx: 4.21.0
|
||||||
|
|
||||||
vitest@4.0.16(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2):
|
vitest@4.0.16(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.21.0):
|
||||||
dependencies:
|
dependencies:
|
||||||
'@vitest/expect': 4.0.16
|
'@vitest/expect': 4.0.16
|
||||||
'@vitest/mocker': 4.0.16(vite@7.3.1(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2))
|
'@vitest/mocker': 4.0.16(vite@7.3.1(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.21.0))
|
||||||
'@vitest/pretty-format': 4.0.16
|
'@vitest/pretty-format': 4.0.16
|
||||||
'@vitest/runner': 4.0.16
|
'@vitest/runner': 4.0.16
|
||||||
'@vitest/snapshot': 4.0.16
|
'@vitest/snapshot': 4.0.16
|
||||||
@@ -6176,7 +6217,7 @@ snapshots:
|
|||||||
tinyexec: 1.0.2
|
tinyexec: 1.0.2
|
||||||
tinyglobby: 0.2.15
|
tinyglobby: 0.2.15
|
||||||
tinyrainbow: 3.0.3
|
tinyrainbow: 3.0.3
|
||||||
vite: 7.3.1(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)
|
vite: 7.3.1(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.21.0)
|
||||||
why-is-node-running: 2.3.0
|
why-is-node-running: 2.3.0
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
'@types/node': 25.0.3
|
'@types/node': 25.0.3
|
||||||
@@ -6266,6 +6307,10 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
grammex: 3.1.12
|
grammex: 3.1.12
|
||||||
|
|
||||||
|
zod-to-json-schema@3.25.1(zod@4.3.5):
|
||||||
|
dependencies:
|
||||||
|
zod: 4.3.5
|
||||||
|
|
||||||
zod@4.3.4: {}
|
zod@4.3.4: {}
|
||||||
|
|
||||||
zod@4.3.5: {}
|
zod@4.3.5: {}
|
||||||
|
|||||||
@@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"$ref": "#/definitions/MapResource",
|
||||||
|
"definitions": {
|
||||||
|
"MapResource": {}
|
||||||
|
},
|
||||||
|
"$schema": "http://json-schema.org/draft-07/schema#"
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"$ref": "#/definitions/ScenarioResource",
|
||||||
|
"definitions": {
|
||||||
|
"ScenarioResource": {}
|
||||||
|
},
|
||||||
|
"$schema": "http://json-schema.org/draft-07/schema#"
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"$ref": "#/definitions/TurnCommandProfile",
|
||||||
|
"definitions": {
|
||||||
|
"TurnCommandProfile": {}
|
||||||
|
},
|
||||||
|
"$schema": "http://json-schema.org/draft-07/schema#"
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"$ref": "#/definitions/UnitSetDefinition",
|
||||||
|
"definitions": {
|
||||||
|
"UnitSetDefinition": {}
|
||||||
|
},
|
||||||
|
"$schema": "http://json-schema.org/draft-07/schema#"
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user