UNPKG

tdpw

Version:

CLI tool for uploading Playwright test reports to TestDino platform with Azure storage support

200 lines 7.3 kB
"use strict"; /** * Validation utilities for configuration and input */ Object.defineProperty(exports, "__esModule", { value: true }); exports.ValidationUtils = void 0; const zod_1 = require("zod"); const types_1 = require("../types"); /** * Configuration validation utilities */ class ValidationUtils { /** * Validate data against a Zod schema with user-friendly error messages */ static validateSchema(schema, data, context) { try { const validated = schema.parse(data); return { success: true, data: validated, }; } catch (error) { if (error instanceof zod_1.z.ZodError) { const errors = error.issues.map(issue => { const path = issue.path.length > 0 ? issue.path.join('.') : 'root'; return `${path}: ${issue.message}`; }); return { success: false, errors, }; } return { success: false, errors: [`Unexpected validation error in ${context}: ${String(error)}`], }; } } /** * Validate and throw appropriate error with context */ static validateOrThrow(schema, data, context) { const result = this.validateSchema(schema, data, context); if (!result.success) { throw new types_1.ValidationError(`Validation failed for ${context}: ${result.errors?.join(', ')}`); } return result.data; } /** * Validate API token format with detailed feedback */ static validateApiToken(token) { if (!token) { throw new types_1.ValidationError('API token is required'); } if (token.length < 10) { throw new types_1.ValidationError('API token is too short'); } const tokenPattern = /^trx_(development|staging|production)_[a-f0-9]{64}$/; if (!tokenPattern.test(token)) { const parts = token.split('_'); if (parts.length !== 3) { throw new types_1.ValidationError('API token must have 3 parts separated by underscores: trx_{environment}_{key}'); } const prefix = parts[0]; const environment = parts[1]; const key = parts[2]; if (prefix !== 'trx') { throw new types_1.ValidationError(`API token must start with "trx", found "${prefix}"`); } if (!environment || !['development', 'staging', 'production'].includes(environment)) { throw new types_1.ValidationError(`Invalid environment "${environment || 'empty'}". Must be: development, staging, or production`); } if (!key || !/^[a-f0-9]{64}$/.test(key)) { throw new types_1.ValidationError('API token key must be 64 lowercase hexadecimal characters'); } } } /** * Validate URL format with helpful feedback */ static validateUrl(url, context) { if (!url) { throw new types_1.ValidationError(`${context} URL is required`); } try { const parsed = new URL(url); if (!['http:', 'https:'].includes(parsed.protocol)) { throw new types_1.ValidationError(`${context} URL must use HTTP or HTTPS protocol, found: ${parsed.protocol}`); } if (!parsed.hostname) { throw new types_1.ValidationError(`${context} URL must have a valid hostname`); } } catch (error) { if (error instanceof types_1.ValidationError) { throw error; } throw new types_1.ValidationError(`Invalid ${context} URL format: ${url}`); } } /** * Validate file path exists and is accessible */ static validateFilePath(path, context) { if (!path) { throw new types_1.ValidationError(`${context} path is required`); } if (path.includes('..')) { throw new types_1.ValidationError(`${context} path cannot contain parent directory references (..)`); } if (path.startsWith('/') && !process.platform.startsWith('win')) { console.warn(`⚠️ Using absolute path for ${context}: ${path}`); } } /** * Validate Node.js version requirement */ static validateNodeVersion(requiredVersion = '18.0.0') { const currentVersion = process.version; const current = this.parseVersion(currentVersion.slice(1)); // Remove 'v' prefix const required = this.parseVersion(requiredVersion); if (this.compareVersions(current, required) < 0) { throw new types_1.ConfigurationError(`Node.js ${requiredVersion} or higher is required. ` + `Current version: ${currentVersion}`); } } /** * Parse semantic version string */ static parseVersion(version) { const parts = version.split('.').map(Number); return [parts[0] || 0, parts[1] || 0, parts[2] || 0]; } /** * Compare two semantic versions * Returns: -1 if a < b, 0 if a === b, 1 if a > b */ static compareVersions(a, b) { for (let i = 0; i < 3; i++) { const aVal = a[i] ?? 0; const bVal = b[i] ?? 0; if (aVal < bVal) return -1; if (aVal > bVal) return 1; } return 0; } /** * Validate environment variable name */ static validateEnvVarName(name) { if (!name) { throw new types_1.ValidationError('Environment variable name is required'); } if (!/^[A-Z][A-Z0-9_]*$/.test(name)) { throw new types_1.ValidationError(`Environment variable name "${name}" must be uppercase letters, numbers, and underscores only`); } } /** * Sanitize and validate file size */ static validateFileSize(size, maxSize, filename) { if (size < 0) { throw new types_1.ValidationError(`Invalid file size for ${filename}: ${size}`); } if (size > maxSize) { const sizeMB = Math.round(size / 1024 / 1024); const maxSizeMB = Math.round(maxSize / 1024 / 1024); throw new types_1.ValidationError(`File ${filename} is too large: ${sizeMB}MB (max: ${maxSizeMB}MB)`); } } /** * Validate timeout value */ static validateTimeout(timeout) { if (timeout <= 0) { throw new types_1.ValidationError('Timeout must be greater than 0'); } if (timeout > 300000) { // 5 minutes console.warn(`⚠️ Large timeout value: ${timeout}ms (${timeout / 1000}s)`); } } /** * Validate retry count */ static validateRetryCount(retries) { if (retries < 0) { throw new types_1.ValidationError('Retry count cannot be negative'); } if (retries > 10) { console.warn(`⚠️ High retry count: ${retries} (this may cause long delays)`); } } } exports.ValidationUtils = ValidationUtils; //# sourceMappingURL=validation.js.map