/** * Curve validation strategies for machine curves and generic curves. * Extracted from validationUtils.js for modularity. */ function isSorted(arr) { return arr.every((_, i) => i === 0 || arr[i] >= arr[i - 1]); } function isUnique(arr) { return new Set(arr).size === arr.length; } function areNumbers(arr) { return arr.every((x) => typeof x === "number"); } function validateDimensionStructure(dimension, name, logger) { const validatedDimension = {}; for (const [key, value] of Object.entries(dimension)) { if (typeof value !== "object") { logger.warn(`Dimension '${name}' key '${key}' is not valid. Returning to default.`); return false; } else if (!Array.isArray(value.x) || !Array.isArray(value.y)) { logger.warn(`Dimension '${name}' key '${key}' is missing x or y arrays. Converting to arrays.`); value.x = Object.values(value.x); value.y = Object.values(value.y); if (!Array.isArray(value.x) || !Array.isArray(value.y)) { logger.warn(`Dimension '${name}' key '${key}' is not valid. Returning to default.`); return false; } } else if (value.x.length !== value.y.length) { logger.warn(`Dimension '${name}' key '${key}' has mismatched x and y lengths. Ignoring this key.`); return false; } else if (!isSorted(value.x)) { logger.warn(`Dimension '${name}' key '${key}' has unsorted x values. Sorting...`); const indices = value.x.map((_v, i) => i); indices.sort((a, b) => value.x[a] - value.x[b]); value.x = indices.map(i => value.x[i]); value.y = indices.map(i => value.y[i]); } if (!isUnique(value.x)) { logger.warn(`Dimension '${name}' key '${key}' has duplicate x values. Removing duplicates...`); const seen = new Set(); const uniqueX = []; const uniqueY = []; for (let i = 0; i < value.x.length; i++) { if (!seen.has(value.x[i])) { seen.add(value.x[i]); uniqueX.push(value.x[i]); uniqueY.push(value.y[i]); } } value.x = uniqueX; value.y = uniqueY; } if (!areNumbers(value.y)) { logger.warn(`Dimension '${name}' key '${key}' has non-numeric y values. Ignoring this key.`); return false; } validatedDimension[key] = value; } return validatedDimension; } function validateCurve(configValue, defaultCurve, logger) { if (!configValue || typeof configValue !== "object" || Object.keys(configValue).length === 0) { logger.warn("Curve is missing or invalid. Defaulting to basic curve."); return defaultCurve; } const validatedCurve = validateDimensionStructure(configValue, "curve", logger); if (!validatedCurve) { return defaultCurve; } return validatedCurve; } function validateMachineCurve(configValue, defaultCurve, logger) { if (!configValue || typeof configValue !== "object" || Object.keys(configValue).length === 0) { logger.warn("Curve is missing or invalid. Defaulting to basic curve."); return defaultCurve; } const { nq, np } = configValue; if (!nq || typeof nq !== "object" || !np || typeof np !== "object") { logger.warn("Curve must contain valid 'nq' and 'np' objects. Defaulting to basic curve."); return defaultCurve; } const validatedNq = validateDimensionStructure(nq, "nq", logger); const validatedNp = validateDimensionStructure(np, "np", logger); if (!validatedNq || !validatedNp) { return defaultCurve; } return { nq: validatedNq, np: validatedNp }; } module.exports = { validateCurve, validateMachineCurve, validateDimensionStructure, isSorted, isUnique, areNumbers };