wp-host
Version:
Automated WordPress hosting deployment tool for bulk site creation with MySQL database management
485 lines • 18.7 kB
JavaScript
;
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.ConfigParser = void 0;
const fs = __importStar(require("fs-extra"));
const path = __importStar(require("path"));
class ConfigParser {
/**
* Parse configuration file (JSON or CSV)
*/
static async parseConfig(configPath) {
const ext = path.extname(configPath).toLowerCase();
if (ext === '.json') {
return this.parseJsonConfig(configPath);
}
else if (ext === '.csv') {
return this.parseCsvConfig(configPath);
}
else {
throw new Error(`Unsupported configuration file format: ${ext}. Supported formats: .json, .csv`);
}
}
/**
* Parse JSON configuration file
*/
static async parseJsonConfig(configPath) {
try {
const content = await fs.readFile(configPath, 'utf-8');
const config = JSON.parse(content);
// Auto-generate missing database names and users
this.autoGenerateDbInfo(config);
this.validateConfig(config);
return config;
}
catch (error) {
if (error instanceof SyntaxError) {
throw new Error(`Invalid JSON in configuration file: ${error.message}`);
}
throw error;
}
}
/**
* Parse CSV configuration file
*/
static async parseCsvConfig(configPath) {
try {
const content = await fs.readFile(configPath, 'utf-8');
const lines = content.trim().split('\n');
if (lines.length < 2) {
throw new Error('CSV file must have at least a header row and one data row');
}
const headers = lines[0].split(',').map(h => h.trim());
// Check if this is the comprehensive format (includes MySQL and WordPress config)
const isComprehensiveFormat = headers.some(h => h.toLowerCase() === 'mysql host' || h === 'mysql_host') &&
headers.some(h => h.toLowerCase() === 'wordpress admin password' || h === 'wordpress_admin_password');
if (isComprehensiveFormat) {
return this.parseComprehensiveCSV(lines, headers);
}
else {
return this.parseSimpleCSV(lines, headers);
}
}
catch (error) {
throw new Error(`Error parsing CSV file: ${error instanceof Error ? error.message : String(error)}`);
}
}
/**
* Parse comprehensive CSV format with all configuration included
*/
static parseComprehensiveCSV(lines, headers) {
// Create header mapping for both technical and user-friendly headers
const headerMap = this.createHeaderMap(headers);
const requiredFields = [
'site_name', 'directory_path', 'wordpress_site_title', 'wordpress_admin_username',
'mysql_host', 'mysql_port', 'mysql_root_user', 'mysql_root_password',
'mysql_shared_db_password', 'wordpress_admin_password', 'wordpress_admin_email'
];
// Check for required headers (using mapped names)
for (const required of requiredFields) {
if (!headerMap[required]) {
throw new Error(`Missing required CSV header: ${required} (or its user-friendly equivalent)`);
}
}
const sites = [];
let mysqlConfig = null;
let wordpressConfig = null;
for (let i = 1; i < lines.length; i++) {
const values = lines[i].split(',').map(v => v.trim());
if (values.length !== headers.length) {
throw new Error(`Row ${i + 1}: Expected ${headers.length} columns, got ${values.length}`);
}
const row = {};
headers.forEach((header, index) => {
row[header] = values[index];
});
// Map headers to standardized field names
const mappedRow = this.mapRowData(row, headerMap);
// Extract MySQL config from first row (assuming all rows have same config)
if (!mysqlConfig) {
mysqlConfig = {
host: mappedRow.mysql_host,
port: parseInt(mappedRow.mysql_port),
rootUser: mappedRow.mysql_root_user,
rootPassword: mappedRow.mysql_root_password,
sharedDbPassword: mappedRow.mysql_shared_db_password
};
}
// Extract WordPress config from first row (shared settings)
if (!wordpressConfig) {
wordpressConfig = {
adminPassword: mappedRow.wordpress_admin_password,
adminEmail: mappedRow.wordpress_admin_email,
adminUsername: 'admin', // Default, will be overridden per site
siteTitle: 'WordPress Site' // Default, will be overridden per site
};
}
// Create site config with per-site WordPress settings
const site = {
site_name: mappedRow.site_name,
directory_path: mappedRow.directory_path,
database_name: `${mappedRow.site_name}_db`,
db_user: `${mappedRow.site_name}_user`,
wordpress_site_title: mappedRow.wordpress_site_title,
wordpress_admin_username: mappedRow.wordpress_admin_username
};
sites.push(site);
}
const config = {
mysql: mysqlConfig,
wordpress: wordpressConfig,
sites
};
this.validateConfig(config);
return config;
}
/**
* Parse simple CSV format (legacy support - requires environment variables)
*/
static parseSimpleCSV(lines, headers) {
const requiredHeaders = ['site_name', 'directory_path'];
// Validate headers
for (const required of requiredHeaders) {
if (!headers.includes(required)) {
throw new Error(`Missing required CSV header: ${required}`);
}
}
const sites = [];
for (let i = 1; i < lines.length; i++) {
const values = lines[i].split(',').map(v => v.trim());
if (values.length !== headers.length) {
throw new Error(`Row ${i + 1}: Expected ${headers.length} columns, got ${values.length}`);
}
const site = {
site_name: '',
directory_path: ''
};
headers.forEach((header, index) => {
const value = values[index];
switch (header) {
case 'site_name':
site.site_name = value;
break;
case 'directory_path':
site.directory_path = value;
break;
case 'database_name':
site.database_name = value;
break;
case 'db_user':
site.db_user = value;
break;
}
});
sites.push(site);
}
// For simple CSV, use default or environment-based config
const config = {
mysql: this.getDefaultMySQLConfig(),
wordpress: this.getDefaultWordPressConfig(),
sites
};
// Auto-generate missing database names and users
this.autoGenerateDbInfo(config);
this.validateConfig(config);
return config;
}
/**
* Auto-generate database names and users if not provided
*/
static autoGenerateDbInfo(config) {
config.sites.forEach(site => {
// Auto-generate database name if not provided
if (!site.database_name) {
site.database_name = `${site.site_name}_db`;
}
// Auto-generate database user if not provided
if (!site.db_user) {
site.db_user = `${site.site_name}_user`;
}
});
}
/**
* Create header mapping for both technical and user-friendly headers
*/
static createHeaderMap(headers) {
const headerMap = {};
// Header mapping from user-friendly to technical names
const mappings = {
'Site Name': 'site_name',
'site_name': 'site_name',
'Directory Path': 'directory_path',
'directory_path': 'directory_path',
'MySQL Host': 'mysql_host',
'mysql_host': 'mysql_host',
'MySQL Port': 'mysql_port',
'mysql_port': 'mysql_port',
'MySQL Username': 'mysql_root_user',
'mysql_root_user': 'mysql_root_user',
'MySQL Password': 'mysql_root_password',
'mysql_root_password': 'mysql_root_password',
'Database Password': 'mysql_shared_db_password',
'mysql_shared_db_password': 'mysql_shared_db_password',
'WordPress Site Title': 'wordpress_site_title',
'wordpress_site_title': 'wordpress_site_title',
'WordPress Admin Username': 'wordpress_admin_username',
'wordpress_admin_username': 'wordpress_admin_username',
'WordPress Admin Password': 'wordpress_admin_password',
'wordpress_admin_password': 'wordpress_admin_password',
'WordPress Admin Email': 'wordpress_admin_email',
'wordpress_admin_email': 'wordpress_admin_email'
};
// Create reverse mapping from technical names to actual headers
headers.forEach(header => {
const technicalName = mappings[header];
if (technicalName) {
headerMap[technicalName] = header;
}
});
return headerMap;
}
/**
* Map row data using header mapping
*/
static mapRowData(row, headerMap) {
const mappedRow = {};
Object.keys(headerMap).forEach(technicalName => {
const actualHeader = headerMap[technicalName];
mappedRow[technicalName] = row[actualHeader];
});
return mappedRow;
}
/**
* Validate configuration structure and data
*/
static validateConfig(config) {
const errors = [];
// Validate MySQL config is provided
if (!config.mysql) {
errors.push({
field: 'mysql',
message: 'MySQL configuration is required'
});
}
else {
this.validateMySQLConfig(config.mysql, errors);
}
// Validate WordPress config is provided
if (!config.wordpress) {
errors.push({
field: 'wordpress',
message: 'WordPress configuration is required'
});
}
else {
this.validateWordPressConfig(config.wordpress, errors);
}
// Validate sites array exists
if (!config.sites || !Array.isArray(config.sites)) {
errors.push({
field: 'sites',
message: 'Configuration must contain a "sites" array'
});
throw new Error(`Configuration validation failed:\n${errors.map(e => `- ${e.field}: ${e.message}`).join('\n')}`);
}
// Validate sites array is not empty
if (config.sites.length === 0) {
errors.push({
field: 'sites',
message: 'Sites array cannot be empty'
});
}
// Validate each site configuration
config.sites.forEach((site, index) => {
this.validateSiteConfig(site, index, errors);
});
// Check for duplicate site names and database names
this.checkDuplicates(config.sites, errors);
if (errors.length > 0) {
throw new Error(`Configuration validation failed:\n${errors.map(e => e.siteIndex !== undefined
? `- Site ${e.siteIndex + 1} (${e.field}): ${e.message}`
: `- ${e.field}: ${e.message}`).join('\n')}`);
}
}
/**
* Validate individual site configuration
*/
static validateSiteConfig(site, index, errors) {
// Required fields
if (!site.site_name || site.site_name.trim() === '') {
errors.push({
field: 'site_name',
message: 'Site name is required and cannot be empty',
siteIndex: index
});
}
if (!site.directory_path || site.directory_path.trim() === '') {
errors.push({
field: 'directory_path',
message: 'Directory path is required and cannot be empty',
siteIndex: index
});
}
// Validate site name format (alphanumeric, underscore, hyphen)
if (site.site_name && !/^[a-zA-Z0-9_-]+$/.test(site.site_name)) {
errors.push({
field: 'site_name',
message: 'Site name can only contain letters, numbers, underscores, and hyphens',
siteIndex: index
});
}
// Validate database name format (MySQL naming rules) - auto-generated, so should be valid
if (site.database_name && !/^[a-zA-Z0-9_]+$/.test(site.database_name)) {
errors.push({
field: 'database_name',
message: 'Database name can only contain letters, numbers, and underscores',
siteIndex: index
});
}
}
/**
* Validate MySQL configuration
*/
static validateMySQLConfig(mysql, errors) {
if (!mysql.host || mysql.host.trim() === '') {
errors.push({
field: 'mysql.host',
message: 'MySQL host is required'
});
}
if (!mysql.port || mysql.port < 1 || mysql.port > 65535) {
errors.push({
field: 'mysql.port',
message: 'MySQL port must be between 1 and 65535'
});
}
if (!mysql.rootUser || mysql.rootUser.trim() === '') {
errors.push({
field: 'mysql.rootUser',
message: 'MySQL root user is required'
});
}
if (!mysql.rootPassword || mysql.rootPassword.trim() === '') {
errors.push({
field: 'mysql.rootPassword',
message: 'MySQL root password is required'
});
}
if (!mysql.sharedDbPassword || mysql.sharedDbPassword.trim() === '') {
errors.push({
field: 'mysql.sharedDbPassword',
message: 'Shared database password is required'
});
}
}
/**
* Validate WordPress configuration
*/
static validateWordPressConfig(wordpress, errors) {
if (!wordpress.adminPassword || wordpress.adminPassword.trim() === '') {
errors.push({
field: 'wordpress.adminPassword',
message: 'WordPress admin password is required'
});
}
if (!wordpress.adminEmail || wordpress.adminEmail.trim() === '') {
errors.push({
field: 'wordpress.adminEmail',
message: 'WordPress admin email is required'
});
}
// Validate email format
if (wordpress.adminEmail && !/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(wordpress.adminEmail)) {
errors.push({
field: 'wordpress.adminEmail',
message: 'Invalid email format'
});
}
}
/**
* Check for duplicate site names and database names
*/
static checkDuplicates(sites, errors) {
const siteNames = new Set();
const dbNames = new Set();
sites.forEach((site, index) => {
if (siteNames.has(site.site_name)) {
errors.push({
field: 'site_name',
message: `Duplicate site name: ${site.site_name}`,
siteIndex: index
});
}
else {
siteNames.add(site.site_name);
}
if (site.database_name && dbNames.has(site.database_name)) {
errors.push({
field: 'database_name',
message: `Duplicate database name: ${site.database_name}`,
siteIndex: index
});
}
else if (site.database_name) {
dbNames.add(site.database_name);
}
});
}
/**
* Get default MySQL configuration
*/
static getDefaultMySQLConfig() {
return {
host: 'localhost',
port: 3306,
rootUser: 'root',
rootPassword: 'your_mysql_root_password',
sharedDbPassword: 'shared_db_password_123'
};
}
/**
* Get default WordPress configuration
*/
static getDefaultWordPressConfig() {
return {
adminPassword: 'wp_admin_password_123',
adminEmail: 'admin@example.com',
adminUsername: 'admin',
siteTitle: 'My WordPress Site'
};
}
}
exports.ConfigParser = ConfigParser;
//# sourceMappingURL=config-parser.js.map