()
| 40 | |
| 41 | // Read and parse tools-config.ts |
| 42 | function loadToolsConfig() { |
| 43 | try { |
| 44 | const configPath = path.join( |
| 45 | __dirname, |
| 46 | "..", |
| 47 | "src", |
| 48 | "lib", |
| 49 | "tools-config.ts" |
| 50 | ); |
| 51 | const configContent = fs.readFileSync(configPath, "utf8"); |
| 52 | |
| 53 | // Extract tools data using regex (simple approach for this script) |
| 54 | const toolsRegex = /export const tools: ToolCategory\[\] = \[([\s\S]*?)\];/; |
| 55 | const match = configContent.match(toolsRegex); |
| 56 | |
| 57 | if (!match) { |
| 58 | throw new Error("Could not find tools configuration in tools-config.ts"); |
| 59 | } |
| 60 | |
| 61 | // Parse the tools configuration |
| 62 | // This is a simplified parser - in a real scenario, you might want to use a proper TypeScript parser |
| 63 | const toolsData = []; |
| 64 | const categoryRegex = |
| 65 | /category:\s*"([^"]+)",[\s\S]*?items:\s*\[([\s\S]*?)\]/g; |
| 66 | let categoryMatch; |
| 67 | |
| 68 | while ((categoryMatch = categoryRegex.exec(match[1])) !== null) { |
| 69 | const category = categoryMatch[1]; |
| 70 | const itemsContent = categoryMatch[2]; |
| 71 | |
| 72 | // Parse items within the category (only non-commented items) |
| 73 | const itemRegex = |
| 74 | /{\s*name:\s*"([^"]+)",[\s\S]*?available:\s*(true|false)/g; |
| 75 | let itemMatch; |
| 76 | const items = []; |
| 77 | |
| 78 | while ((itemMatch = itemRegex.exec(itemsContent)) !== null) { |
| 79 | // Check if this item is commented out by looking at the context before the match |
| 80 | const beforeMatch = itemsContent.substring(0, itemMatch.index); |
| 81 | const isCommentedOut = |
| 82 | beforeMatch.includes("// {") || beforeMatch.includes("//{"); |
| 83 | |
| 84 | // SEO landing variants (entries carrying `landingFor`, which follows |
| 85 | // `available` in field order) are exempt from README sync — they are |
| 86 | // neither required in README nor flagged as missing. Scan this item's |
| 87 | // full block (from its `{` up to the next item / end of the category). |
| 88 | const rest = itemsContent.substring(itemMatch.index); |
| 89 | const nextItem = rest.slice(1).search(/{\s*name:\s*"/); |
| 90 | const block = nextItem === -1 ? rest : rest.substring(0, nextItem + 1); |
| 91 | const isLandingVariant = /landingFor\s*:/.test(block); |
| 92 | |
| 93 | if (!isCommentedOut && !isLandingVariant) { |
| 94 | items.push({ |
| 95 | name: itemMatch[1], |
| 96 | available: itemMatch[2] === "true", |
| 97 | }); |
| 98 | } |
| 99 | } |
no test coverage detected