feat: refactor utility functions for improved consistency and usability; consolidate parsing logic

This commit is contained in:
2026-01-17 12:36:58 +00:00
parent bc76b6e725
commit 07ea17dacf
25 changed files with 162 additions and 211 deletions
@@ -4,6 +4,7 @@ import type { ScenarioMeta } from '@sammo-ts/logic/world/types.js';
import type { WarAftermathConfig, WarEngineConfig, WarTimeContext } from '@sammo-ts/logic/war/types.js';
import type { UnitSetDefinition } from '@sammo-ts/logic/world/types.js';
import type { ActionContextWorldRef, ActionContextWorldState } from './actionContext.js';
import { asRecord } from '@sammo-ts/common';
export interface WorldSummary {
totalGeneralCount: number;
@@ -112,9 +113,6 @@ const DEFAULT_AFTER_CONFIG = {
defaultCityWall: 1000,
};
const asRecord = (value: unknown): Record<string, unknown> =>
value && typeof value === 'object' && !Array.isArray(value) ? (value as Record<string, unknown>) : {};
const resolveNumber = (record: Record<string, unknown>, keys: string[], fallback: number): number => {
for (const key of keys) {
const value = record[key];
@@ -1,19 +1,17 @@
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 { asStringArray, isRecord } from '@sammo-ts/common';
export interface TurnCommandProfile {
general: GeneralTurnCommandKey[];
nation: NationTurnCommandKey[];
}
const isRecord = (value: unknown): value is Record<string, unknown> =>
value !== null && typeof value === 'object' && !Array.isArray(value);
const asStringArray = (value: unknown): string[] | null => {
const asStringArrayOrNull = (value: unknown): string[] | null => {
if (!Array.isArray(value)) {
return null;
}
const list = value.filter((entry): entry is string => typeof entry === 'string');
const list = asStringArray(value);
return list.length > 0 ? list : null;
};
@@ -23,7 +21,7 @@ const parseKeyList = <T extends string>(options: {
isKey: (value: string) => value is T;
label: string;
}): T[] => {
const rawList = asStringArray(options.raw);
const rawList = asStringArrayOrNull(options.raw);
if (!rawList) {
return options.defaults;
}
+1 -14
View File
@@ -1,4 +1,5 @@
import { z } from 'zod';
import { asNullableNumber, asNullableString, asNumber, asString, asStringArray, isRecord } from '@sammo-ts/common';
import type {
ScenarioConfig,
@@ -23,24 +24,10 @@ const FALLBACK_STAT: ScenarioStatBlock = {
chiefMin: 0,
};
const isRecord = (value: unknown): value is UnknownRecord =>
typeof value === 'object' && value !== null && !Array.isArray(value);
const toRecordOrUndefined = (value: unknown): UnknownRecord | undefined => (isRecord(value) ? value : undefined);
const toArrayOrUndefined = (value: unknown): unknown[] | undefined => (Array.isArray(value) ? value : undefined);
const asNumber = (value: unknown, fallback: number): number => (typeof value === 'number' ? value : fallback);
const asString = (value: unknown, fallback: string): string => (typeof value === 'string' ? value : fallback);
const asNullableNumber = (value: unknown): number | null => (typeof value === 'number' ? value : null);
const asNullableString = (value: unknown): string | null => (typeof value === 'string' ? value : null);
const asStringArray = (value: unknown): string[] =>
Array.isArray(value) ? value.filter((item): item is string => typeof item === 'string') : [];
const zRecord = z.record(z.string(), z.unknown());
const zUnknownArray = z.array(z.unknown());
const zOptionalRecord = z.preprocess(toRecordOrUndefined, zRecord.optional());
@@ -1,10 +1,10 @@
import { isRecord } from '@sammo-ts/common';
export interface WarDexAux {
isAttacker?: boolean;
opposeType?: { armType: number };
}
const isRecord = (value: unknown): value is Record<string, unknown> => value !== null && typeof value === 'object';
export const parseWarDexAux = (aux: unknown): WarDexAux => {
if (!isRecord(aux)) {
return {};
+8 -20
View File
@@ -1,5 +1,13 @@
import type { City, General, Nation } from '@sammo-ts/logic/domain/entities.js';
import type { CrewTypeDefinition, CrewTypeRequirement, MapDefinition, UnitSetDefinition } from './types.js';
import {
asNullableStringArray,
asNumber,
asRecord,
asString,
asStringArray,
isRecord,
} from '@sammo-ts/common';
const DEFAULT_REGION_MAP: Record<string, number> = {
하북: 1,
@@ -14,26 +22,6 @@ const DEFAULT_REGION_MAP: Record<string, number> = {
const DEFAULT_MAX_TECH_LEVEL = 12;
const isRecord = (value: unknown): value is Record<string, unknown> =>
value !== null && typeof value === 'object' && !Array.isArray(value);
const asRecord = (value: unknown): Record<string, unknown> => (isRecord(value) ? value : {});
const asNumber = (value: unknown, fallback: number): number =>
typeof value === 'number' && Number.isFinite(value) ? value : fallback;
const asString = (value: unknown, fallback: string): string => (typeof value === 'string' ? value : fallback);
const asStringArray = (value: unknown): string[] =>
Array.isArray(value) ? value.filter((item): item is string => typeof item === 'string') : [];
const asNullableStringArray = (value: unknown): string[] | null => {
if (value === null || value === undefined) {
return null;
}
return asStringArray(value);
};
const normalizeCoef = (value: unknown): Record<string, number> => {
if (!isRecord(value)) {
return {};