UNPKG

kokopu

Version:

A JavaScript/TypeScript library implementing the chess game rules and providing tools to read/write the standard chess file formats.

159 lines (139 loc) 5.53 kB
/*! * -------------------------------------------------------------------------- * * * * Kokopu - A JavaScript/TypeScript chess library. * * <https://www.npmjs.com/package/kokopu> * * Copyright (C) 2018-2025 Yoann Le Montagner <yo35 -at- melix.net> * * * * Kokopu is free software: you can redistribute it and/or * * modify it under the terms of the GNU Lesser General Public License * * as published by the Free Software Foundation, either version 3 of * * the License, or (at your option) any later version. * * * * Kokopu is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU Lesser General Public License for more details. * * * * You should have received a copy of the GNU Lesser General * * Public License along with this program. If not, see * * <http://www.gnu.org/licenses/>. * * * * -------------------------------------------------------------------------- */ import { InvalidPOJO } from '../exception'; import { i18n } from '../i18n'; /** * Helper class to build a {@link InvalidPOJO}. */ export class POJOExceptionBuilder { #pojo: unknown; #path: (string | number)[] = []; constructor(pojo: unknown) { this.#pojo = pojo; } push(fieldName: string | number) { this.#path.push(fieldName); } pop() { this.#path.pop(); } build(message: string, ...tokens: unknown[]) { let fieldName = ''; let isFirstPathComponent = true; for (const pathComponent of this.#path) { if (typeof pathComponent === 'number') { fieldName += `[${pathComponent}]`; } else { fieldName += isFirstPathComponent ? pathComponent : '.' + pathComponent; } isFirstPathComponent = false; } return new InvalidPOJO(this.#pojo, fieldName, message, ...tokens); } } /** * Validate a string-valued field read from a POJO. */ export function decodeStringField(pojo: Partial<Record<string, unknown>>, fieldName: string, exceptionBuilder: POJOExceptionBuilder, setter: (value: string) => void) { if (!(fieldName in pojo)) { return; } exceptionBuilder.push(fieldName); const value = pojo[fieldName]; if (typeof value === 'string') { setter(value); } else if (value !== undefined) { throw exceptionBuilder.build(i18n.INVALID_POJO_STRING_FIELD); } exceptionBuilder.pop(); } /** * Validate a number-valued field read from a POJO. */ export function decodeNumberField(pojo: Partial<Record<string, unknown>>, fieldName: string, exceptionBuilder: POJOExceptionBuilder, setter: (value: number) => void) { if (!(fieldName in pojo)) { return; } exceptionBuilder.push(fieldName); const value = pojo[fieldName]; if (typeof value === 'number') { setter(value); } else if (value !== undefined) { throw exceptionBuilder.build(i18n.INVALID_POJO_NUMBER_FIELD); } exceptionBuilder.pop(); } /** * Validate a boolean-valued field read from a POJO. */ export function decodeBooleanField(pojo: Partial<Record<string, unknown>>, fieldName: string, exceptionBuilder: POJOExceptionBuilder, setter: (value: boolean) => void) { if (!(fieldName in pojo)) { return; } exceptionBuilder.push(fieldName); const value = pojo[fieldName]; if (typeof value === 'boolean') { setter(value); } else if (value !== undefined) { throw exceptionBuilder.build(i18n.INVALID_POJO_BOOLEAN_FIELD); } exceptionBuilder.pop(); } /** * Validate an array-valued field read from a POJO. */ export function decodeArrayField(pojo: Partial<Record<string, unknown>>, fieldName: string, exceptionBuilder: POJOExceptionBuilder, setter: (value: unknown[]) => void) { if (!(fieldName in pojo)) { return; } exceptionBuilder.push(fieldName); const value = pojo[fieldName]; if (Array.isArray(value)) { setter(value); } else if (value !== undefined) { throw exceptionBuilder.build(i18n.INVALID_POJO_ARRAY_FIELD); } exceptionBuilder.pop(); } /** * Validate an object-valued field read from a POJO. */ export function decodeObjectField(pojo: Partial<Record<string, unknown>>, fieldName: string, exceptionBuilder: POJOExceptionBuilder, setter: (value: Partial<Record<string, unknown>>) => void) { if (!(fieldName in pojo)) { return; } exceptionBuilder.push(fieldName); const value = pojo[fieldName]; if (typeof value === 'object' && value !== null) { setter(value); } else if (value !== undefined) { throw exceptionBuilder.build(i18n.INVALID_POJO_OBJECT_FIELD); } exceptionBuilder.pop(); }