system-prompts-and-models-o.../scripts/validate.js
Sahiix@1 13254d7cbf feat: Add metadata system, REST API, examples, and CI/CD pipeline
- Added 32 JSON metadata files for all AI coding tools
- Generated 39 REST API endpoints for programmatic access
- Created working examples in Python, JavaScript, and PowerShell
- Set up GitHub Actions workflow for automated deployment
- Enhanced README with comprehensive feature documentation
- Added version comparison and automation tools
- Updated 20+ documentation files
- Ready for GitHub Pages deployment
2025-10-02 22:23:26 +04:00

250 lines
6.6 KiB
JavaScript
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env node
/**
* validate.js - Repository Structure Validator
*
* Validates that all tool directories follow the required structure
* and that files are properly formatted.
*/
const fs = require('fs');
const path = require('path');
// Configuration
const REQUIRED_STRUCTURE = {
toolDir: {
'README.md': true, // Required in each tool directory
'Prompt.txt': false, // At least one prompt file required (can be versioned)
'Tools.json': false, // Optional
}
};
const EXCLUDED_DIRS = ['.git', '.github', 'site', 'assets', 'node_modules', 'scripts', 'metadata'];
const ROOT_DIR = path.join(__dirname, '..');
// Colors for terminal output
const colors = {
reset: '\x1b[0m',
red: '\x1b[31m',
green: '\x1b[32m',
yellow: '\x1b[33m',
blue: '\x1b[34m',
};
class Validator {
constructor() {
this.errors = [];
this.warnings = [];
this.passed = 0;
}
log(message, color = 'reset') {
console.log(`${colors[color]}${message}${colors.reset}`);
}
error(message) {
this.errors.push(message);
this.log(`❌ ERROR: ${message}`, 'red');
}
warn(message) {
this.warnings.push(message);
this.log(`⚠️ WARNING: ${message}`, 'yellow');
}
success(message) {
this.passed++;
this.log(`${message}`, 'green');
}
info(message) {
this.log(` ${message}`, 'blue');
}
// Get all tool directories
getToolDirectories() {
const dirs = fs.readdirSync(ROOT_DIR, { withFileTypes: true })
.filter(dirent => dirent.isDirectory())
.map(dirent => dirent.name)
.filter(name => !EXCLUDED_DIRS.includes(name) && !name.startsWith('.'));
return dirs;
}
// Check if directory has at least one prompt file
hasPromptFile(dirPath) {
const files = fs.readdirSync(dirPath);
return files.some(file =>
file.toLowerCase().includes('prompt') &&
(file.endsWith('.txt') || file.endsWith('.md'))
);
}
// Validate tool directory structure
validateToolDirectory(toolName) {
const toolPath = path.join(ROOT_DIR, toolName);
const files = fs.readdirSync(toolPath);
let valid = true;
// Check for README.md
if (!files.includes('README.md')) {
this.warn(`${toolName}: Missing README.md`);
valid = false;
}
// Check for at least one prompt file
if (!this.hasPromptFile(toolPath)) {
this.error(`${toolName}: No prompt file found`);
valid = false;
}
if (valid) {
this.success(`${toolName}: Structure valid`);
}
return valid;
}
// Validate file content
validatePromptFile(toolName, fileName) {
const filePath = path.join(ROOT_DIR, toolName, fileName);
const content = fs.readFileSync(filePath, 'utf-8');
// Check if file is not empty
if (content.trim().length === 0) {
this.error(`${toolName}/${fileName}: File is empty`);
return false;
}
// Check for common issues
if (content.includes('[REDACTED]') && !content.includes('redaction')) {
this.warn(`${toolName}/${fileName}: Contains [REDACTED] markers`);
}
// Check file size (warn if suspiciously small)
if (content.length < 500) {
this.warn(`${toolName}/${fileName}: Suspiciously small (${content.length} chars)`);
}
return true;
}
// Validate JSON files
validateJsonFile(toolName, fileName) {
const filePath = path.join(ROOT_DIR, toolName, fileName);
try {
const content = fs.readFileSync(filePath, 'utf-8');
JSON.parse(content);
this.success(`${toolName}/${fileName}: Valid JSON`);
return true;
} catch (error) {
this.error(`${toolName}/${fileName}: Invalid JSON - ${error.message}`);
return false;
}
}
// Validate README.md in tool directory
validateToolReadme(toolName) {
const readmePath = path.join(ROOT_DIR, toolName, 'README.md');
if (!fs.existsSync(readmePath)) {
return false; // Already warned in validateToolDirectory
}
const content = fs.readFileSync(readmePath, 'utf-8');
// Check for required sections (basic)
const requiredSections = ['Overview', 'Files'];
const missingSections = requiredSections.filter(section =>
!content.toLowerCase().includes(section.toLowerCase())
);
if (missingSections.length > 0) {
this.warn(`${toolName}/README.md: Missing sections: ${missingSections.join(', ')}`);
}
return true;
}
// Check for duplicate tool names (case-insensitive)
checkDuplicates() {
const dirs = this.getToolDirectories();
const lowerCaseNames = dirs.map(d => d.toLowerCase());
const duplicates = lowerCaseNames.filter((name, index) =>
lowerCaseNames.indexOf(name) !== index
);
if (duplicates.length > 0) {
this.error(`Duplicate tool directories found: ${duplicates.join(', ')}`);
}
}
// Main validation
run() {
this.log('\n🔍 Starting Repository Validation...\n', 'blue');
// Get all tool directories
const toolDirs = this.getToolDirectories();
this.info(`Found ${toolDirs.length} tool directories\n`);
// Validate each tool directory
toolDirs.forEach(toolName => {
this.validateToolDirectory(toolName);
// Validate specific files if they exist
const toolPath = path.join(ROOT_DIR, toolName);
const files = fs.readdirSync(toolPath);
// Validate prompt files
files.filter(f => f.toLowerCase().includes('prompt') && f.endsWith('.txt'))
.forEach(file => this.validatePromptFile(toolName, file));
// Validate JSON files
files.filter(f => f.endsWith('.json'))
.forEach(file => this.validateJsonFile(toolName, file));
// Validate README
this.validateToolReadme(toolName);
});
// Check for duplicates
this.checkDuplicates();
// Print summary
this.printSummary();
// Exit with appropriate code
process.exit(this.errors.length > 0 ? 1 : 0);
}
printSummary() {
this.log('\n' + '='.repeat(50), 'blue');
this.log('📊 Validation Summary', 'blue');
this.log('='.repeat(50) + '\n', 'blue');
this.log(`✅ Passed: ${this.passed}`, 'green');
this.log(`⚠️ Warnings: ${this.warnings.length}`, 'yellow');
this.log(`❌ Errors: ${this.errors.length}`, 'red');
if (this.errors.length === 0 && this.warnings.length === 0) {
this.log('\n🎉 All validations passed!', 'green');
} else if (this.errors.length === 0) {
this.log('\n✅ Validation passed with warnings', 'yellow');
} else {
this.log('\n❌ Validation failed', 'red');
}
this.log('');
}
}
// Run validator
if (require.main === module) {
const validator = new Validator();
validator.run();
}
module.exports = Validator;