()
| 104 | }); |
| 105 | } |
| 106 | |
| 107 | return toolsData; |
| 108 | } catch (error) { |
| 109 | logError(`Failed to load tools configuration: ${error.message}`); |
| 110 | process.exit(1); |
| 111 | } |
| 112 | } |
| 113 | |
| 114 | // Read and parse README.md |
| 115 | function loadReadmeTools() { |
| 116 | try { |
| 117 | const readmePath = path.join(__dirname, "..", "README.md"); |
| 118 | const readmeContent = fs.readFileSync(readmePath, "utf8"); |
| 119 | |
| 120 | const tools = []; |
| 121 | const lines = readmeContent.split("\n"); |
| 122 | let currentCategory = ""; |
| 123 | |
| 124 | for (const line of lines) { |
| 125 | // Match category headers (e.g., "### 🖼️ Image Tools") |
| 126 | const categoryMatch = line.match(/^###\s+[^\s]+\s+(.+)$/); |
| 127 | if (categoryMatch) { |
| 128 | currentCategory = categoryMatch[1]; |
| 129 | continue; |
| 130 | } |
| 131 | |
| 132 | // Match tool entries (e.g., "- **Background Removal**: AI-powered...") |
| 133 | // Only match lines that are in the Features section and have proper tool descriptions |
| 134 | const toolMatch = line.match(/^-\s+\*\*([^*]+)\*\*:/); |
| 135 | if (toolMatch && currentCategory && line.includes(":")) { |
| 136 | // Skip if this looks like a tech stack item or other non-tool content |
| 137 | const toolName = toolMatch[1]; |
| 138 | const isTechStackItem = [ |
| 139 | "Framework", |
| 140 | "Language", |
| 141 | "Styling", |
| 142 | "UI Components", |
| 143 | "State Management", |
| 144 | "Icons", |
| 145 | "Animations", |
| 146 | "Build Tool", |
| 147 | ].includes(toolName); |
| 148 | const isOtherNonTool = [ |
| 149 | "Title", |
| 150 | "Description", |
| 151 | "Testing", |
| 152 | "Breaking Changes", |
| 153 | "Screenshots", |
| 154 | "GitHub Sponsors", |
| 155 | "Ziina", |
| 156 | "GitHub Issues", |
| 157 | "Twitter", |
| 158 | ].includes(toolName); |
| 159 | |
| 160 | if (!isTechStackItem && !isOtherNonTool) { |
| 161 | tools.push({ |
| 162 | name: toolName, |
| 163 | category: currentCategory, |
no test coverage detected