appwrite-utils-cli
Version:
Appwrite Utility Functions to help with database management, data conversion, data import, migrations, and much more. Meant to be used as a CLI tool, I do not recommend installing this in frontend environments.
395 lines (362 loc) • 12.6 kB
text/typescript
import type { AppwriteConfig } from "appwrite-utils";
import {
validateCollectionsTablesConfig,
reportValidationResults,
type ValidationResult as BaseValidationResult,
type ValidationError as BaseValidationError
} from "../configValidation.js";
import { MessageFormatter } from "../../shared/messageFormatter.js";
import { logger } from "../../shared/logging.js";
/**
* Re-export types from configValidation for convenience
*/
export type ValidationError = BaseValidationError;
/**
* Warning-level validation issue (non-blocking)
*/
export interface ValidationWarning extends BaseValidationError {
severity: "warning";
}
/**
* Complete validation result including errors, warnings, and suggestions
*/
export interface ValidationResult {
isValid: boolean;
errors: ValidationError[];
warnings: ValidationWarning[];
suggestions?: ValidationError[];
}
/**
* Options for validation reporting
*/
export interface ValidationReportOptions {
/**
* Include detailed information in the report
* @default false
*/
verbose?: boolean;
/**
* Suppress console output (only log to file)
* @default false
*/
silent?: boolean;
/**
* Exit process if validation fails
* @default false
*/
exitOnError?: boolean;
}
/**
* Service for validating Appwrite configuration with support for multiple validation modes
*
* This service provides centralized configuration validation with:
* - Standard validation (warnings allowed)
* - Strict validation (warnings treated as errors)
* - Detailed error reporting with suggestions
* - Configurable output verbosity
*
* @example
* ```typescript
* const validationService = new ConfigValidationService();
*
* // Standard validation
* const result = validationService.validate(config);
* if (!result.isValid) {
* validationService.reportResults(result, { verbose: true });
* }
*
* // Strict validation (warnings become errors)
* const strictResult = validationService.validateStrict(config);
* if (!strictResult.isValid) {
* throw new Error("Configuration validation failed in strict mode");
* }
* ```
*/
export class ConfigValidationService {
/**
* Validate configuration with standard rules
*
* Standard validation allows warnings - the configuration is considered valid
* even if warnings are present. Only errors cause validation to fail.
*
* Validation checks include:
* - Basic structure validation (required fields, array structure)
* - Naming conflict detection (collections vs tables)
* - Database reference validation
* - Schema consistency validation
* - Duplicate definition detection
*
* @param config - Appwrite configuration to validate
* @returns Validation result with errors, warnings, and suggestions
*
* @example
* ```typescript
* const result = validationService.validate(config);
*
* if (result.isValid) {
* console.log("Configuration is valid");
* if (result.warnings.length > 0) {
* console.log(`Found ${result.warnings.length} warnings`);
* }
* } else {
* console.error(`Configuration has ${result.errors.length} errors`);
* }
* ```
*/
public validate(config: AppwriteConfig): ValidationResult {
logger.debug("Starting configuration validation (standard mode)");
try {
const baseResult = validateCollectionsTablesConfig(config);
const result: ValidationResult = {
isValid: baseResult.isValid,
errors: baseResult.errors,
warnings: baseResult.warnings as ValidationWarning[],
suggestions: baseResult.suggestions
};
logger.debug("Configuration validation complete", {
isValid: result.isValid,
errorCount: result.errors.length,
warningCount: result.warnings.length,
suggestionCount: result.suggestions?.length || 0
});
return result;
} catch (error) {
logger.error("Configuration validation failed with exception", {
error: error instanceof Error ? error.message : String(error)
});
return {
isValid: false,
errors: [
{
type: "schema_inconsistency",
message: "Configuration validation failed",
details: error instanceof Error ? error.message : String(error),
suggestion: "Check configuration file for syntax errors or invalid structure",
severity: "error"
}
],
warnings: []
};
}
}
/**
* Validate configuration with strict rules
*
* Strict validation treats all warnings as errors. This is useful for:
* - CI/CD pipelines (fail builds on any issues)
* - Production deployments (ensure highest quality)
* - Configuration audits (enforce best practices)
*
* All warnings are promoted to errors, so the configuration is only
* considered valid if there are zero warnings and zero errors.
*
* @param config - Appwrite configuration to validate
* @returns Validation result with promoted warnings as errors
*
* @example
* ```typescript
* const result = validationService.validateStrict(config);
*
* if (!result.isValid) {
* console.error("Configuration failed strict validation");
* result.errors.forEach(err => {
* console.error(` - ${err.message}`);
* });
* process.exit(1);
* }
* ```
*/
public validateStrict(config: AppwriteConfig): ValidationResult {
logger.debug("Starting configuration validation (strict mode)");
try {
const baseResult = validateCollectionsTablesConfig(config);
// In strict mode, promote all warnings to errors
const promotedWarnings: ValidationError[] = baseResult.warnings.map(warning => ({
...warning,
severity: "error" as const
}));
const allErrors = [...baseResult.errors, ...promotedWarnings];
const result: ValidationResult = {
isValid: allErrors.length === 0,
errors: allErrors,
warnings: [], // No warnings in strict mode - all promoted to errors
suggestions: baseResult.suggestions
};
logger.debug("Configuration validation complete (strict mode)", {
isValid: result.isValid,
errorCount: result.errors.length,
promotedWarnings: promotedWarnings.length,
suggestionCount: result.suggestions?.length || 0
});
return result;
} catch (error) {
logger.error("Configuration validation failed with exception (strict mode)", {
error: error instanceof Error ? error.message : String(error)
});
return {
isValid: false,
errors: [
{
type: "schema_inconsistency",
message: "Configuration validation failed in strict mode",
details: error instanceof Error ? error.message : String(error),
suggestion: "Check configuration file for syntax errors or invalid structure",
severity: "error"
}
],
warnings: []
};
}
}
/**
* Report validation results to console with formatted output
*
* Provides user-friendly formatting of validation results:
* - Color-coded output (errors in red, warnings in yellow, etc.)
* - Detailed error descriptions with suggestions
* - Affected items listing
* - Optional verbose mode for additional details
*
* @param validation - Validation result to report
* @param options - Reporting options (verbose, silent, exitOnError)
*
* @example
* ```typescript
* const result = validationService.validate(config);
*
* // Basic reporting
* validationService.reportResults(result);
*
* // Verbose reporting with all details
* validationService.reportResults(result, { verbose: true });
*
* // Report and exit on error (useful for scripts)
* validationService.reportResults(result, { exitOnError: true });
* ```
*/
public reportResults(
validation: ValidationResult,
options: ValidationReportOptions = {}
): void {
const { verbose = false, silent = false, exitOnError = false } = options;
if (silent) {
// Only log to file, don't print to console
logger.info("Configuration validation results", {
isValid: validation.isValid,
errorCount: validation.errors.length,
warningCount: validation.warnings.length,
suggestionCount: validation.suggestions?.length || 0
});
if (validation.errors.length > 0) {
validation.errors.forEach(error => {
logger.error("Validation error", {
type: error.type,
message: error.message,
details: error.details,
suggestion: error.suggestion,
affectedItems: error.affectedItems
});
});
}
return;
}
// Use existing reportValidationResults for formatted console output
reportValidationResults(
{
isValid: validation.isValid,
errors: validation.errors,
warnings: validation.warnings,
suggestions: validation.suggestions || []
},
{ verbose }
);
// Exit on error if requested
if (exitOnError && !validation.isValid) {
logger.error("Exiting due to validation errors");
process.exit(1);
}
}
/**
* Validate and report in a single call
*
* Convenience method that combines validation and reporting.
* Useful for quick validation checks in CLI commands.
*
* @param config - Appwrite configuration to validate
* @param strict - Use strict validation mode
* @param reportOptions - Reporting options
* @returns Validation result
*
* @example
* ```typescript
* // Quick validation with reporting
* const result = validationService.validateAndReport(config, false, {
* verbose: true,
* exitOnError: true
* });
* ```
*/
public validateAndReport(
config: AppwriteConfig,
strict: boolean = false,
reportOptions: ValidationReportOptions = {}
): ValidationResult {
const result = strict ? this.validateStrict(config) : this.validate(config);
this.reportResults(result, reportOptions);
return result;
}
/**
* Check if configuration is valid without detailed reporting
*
* Quick validation check that returns a simple boolean.
* Useful for conditional logic where you don't need detailed error information.
*
* @param config - Appwrite configuration to validate
* @param strict - Use strict validation mode
* @returns true if configuration is valid, false otherwise
*
* @example
* ```typescript
* if (validationService.isValid(config)) {
* // Proceed with configuration
* } else {
* // Show error and prompt for correction
* }
* ```
*/
public isValid(config: AppwriteConfig, strict: boolean = false): boolean {
const result = strict ? this.validateStrict(config) : this.validate(config);
return result.isValid;
}
/**
* Get a summary of validation results as a formatted string
*
* Returns a human-readable summary of validation results suitable for
* logging or display in UIs.
*
* @param validation - Validation result to summarize
* @returns Formatted summary string
*
* @example
* ```typescript
* const result = validationService.validate(config);
* const summary = validationService.getSummary(result);
* console.log(summary);
* // Output: "Configuration valid with 2 warnings, 1 suggestion"
* ```
*/
public getSummary(validation: ValidationResult): string {
if (validation.isValid) {
const parts = ["Configuration valid"];
if (validation.warnings.length > 0) {
parts.push(`${validation.warnings.length} warning${validation.warnings.length > 1 ? "s" : ""}`);
}
if (validation.suggestions && validation.suggestions.length > 0) {
parts.push(`${validation.suggestions.length} suggestion${validation.suggestions.length > 1 ? "s" : ""}`);
}
return parts.join(" with ");
} else {
return `Configuration invalid: ${validation.errors.length} error${validation.errors.length > 1 ? "s" : ""}`;
}
}
}