gitset
Version:
Enhanced git init with user configuration management
167 lines • 6.23 kB
JavaScript
import { promises as fs } from 'fs';
import path from 'path';
import os from 'os';
import { MESSAGES, VALIDATION_CONFIG } from '../config/constants.js';
export class ValidationUtils {
/**
* Validate email format using standard email regex
*/
validateEmail(email) {
const errors = [];
const warnings = [];
let format = false;
let domain;
if (!email || email.trim() === '') {
errors.push('Email is required');
}
else {
const trimmedEmail = email.trim();
// Email regex that handles common valid patterns while rejecting obvious invalid ones
// Prevents consecutive dots, leading/trailing dots, and other invalid patterns
const emailRegex = /^[a-zA-Z0-9]([a-zA-Z0-9._+-]*[a-zA-Z0-9])?@[a-zA-Z0-9]([a-zA-Z0-9-]*[a-zA-Z0-9])?(\.[a-zA-Z]{2,})+$/;
const hasConsecutiveDots = /\.\./.test(trimmedEmail);
const hasValidDomain = /@[a-zA-Z0-9]/.test(trimmedEmail) && !/\.$/.test(trimmedEmail.split('@')[1]);
format = emailRegex.test(trimmedEmail) && !hasConsecutiveDots && hasValidDomain;
if (format) {
domain = trimmedEmail.split('@')[1];
}
else {
errors.push('Invalid email format. Please use format: user@domain.com');
}
}
return {
valid: errors.length === 0,
errors,
warnings,
format,
domain
};
}
/**
* Validate username according to Git standards
*/
validateUsername(name) {
const errors = [];
const warnings = [];
if (!name || name.trim() === '') {
errors.push(MESSAGES.validation.usernameRequired);
}
else {
const trimmedName = name.trim();
if (trimmedName.length < VALIDATION_CONFIG.username.minLength) {
errors.push(MESSAGES.validation.usernameMinLength);
}
if (trimmedName.length > VALIDATION_CONFIG.username.maxLength) {
errors.push(MESSAGES.validation.usernameMaxLength);
}
// Check for potentially problematic characters
if (/[<>"'&]/.test(trimmedName)) {
warnings.push(MESSAGES.validation.usernameSpecialChars);
}
}
return {
valid: errors.length === 0,
errors,
warnings
};
}
async validateDirectoryPath(directoryPath) {
const errors = [];
const warnings = [];
let exists = false;
let writable = false;
let isEmpty = false;
try {
// Resolve path (handle ~, relative paths, etc.)
const resolvedPath = this.resolvePath(directoryPath);
// Check if directory exists
try {
const stats = await fs.stat(resolvedPath);
exists = true;
if (!stats.isDirectory()) {
errors.push(MESSAGES.validation.pathNotDirectory);
return { valid: false, exists, writable, isEmpty, errors, warnings };
}
// Check if writable
try {
await fs.access(resolvedPath, fs.constants.W_OK);
writable = true;
}
catch {
errors.push(MESSAGES.validation.directoryNotWritable);
}
// Check if empty
try {
const files = await fs.readdir(resolvedPath);
isEmpty = files.length === 0;
if (!isEmpty) {
warnings.push(MESSAGES.validation.directoryNotEmpty);
}
}
catch {
warnings.push(MESSAGES.validation.cannotReadDirectory);
}
}
catch {
exists = false;
// For non-existing directories, we'll create them
// Only check if the parent path structure is reasonable
try {
const parentDir = path.dirname(resolvedPath);
// If parent is root or exists, we can create the directory
if (parentDir === '/' || parentDir === '.' || parentDir === resolvedPath) {
warnings.push(MESSAGES.validation.directoryWillBeCreated);
}
else {
try {
await fs.stat(parentDir);
warnings.push(MESSAGES.validation.directoryWillBeCreated);
}
catch {
// Parent doesn't exist, but we can create it recursively
warnings.push('Directory and parent directories will be created');
}
}
}
catch {
warnings.push(MESSAGES.validation.directoryWillBeCreated);
}
}
}
catch (error) {
errors.push(`${MESSAGES.validation.invalidPath} ${error}`);
}
return {
valid: errors.length === 0,
exists,
writable,
isEmpty,
errors,
warnings
};
}
resolvePath(inputPath) {
// Handle home directory
if (inputPath.startsWith('~/')) {
return path.join(os.homedir(), inputPath.slice(2));
}
if (inputPath === '~') {
return os.homedir();
}
// Handle relative paths
if (!path.isAbsolute(inputPath)) {
return path.resolve(process.cwd(), inputPath);
}
return inputPath;
}
async ensureDirectoryExists(directoryPath) {
const resolvedPath = this.resolvePath(directoryPath);
try {
await fs.mkdir(resolvedPath, { recursive: true });
}
catch (error) {
throw new Error(`Failed to create directory: ${error}`);
}
}
}
//# sourceMappingURL=validation.js.map