#!/usr/bin/env node /** * Auto-generates integration feature mappings by scanning the filesystem. * * This script scans content/docs/integrations/ to detect which integrations * have which feature pages (e.g., shared-state, generative-ui, etc.) and * generates lib/integration-features.ts with type-safe mappings. * * Runs automatically: * - Before every `pnpm dev` (via predev script) * - Before every `pnpm build` (via prebuild script) * - Manually via `pnpm generate` * * To add a feature to an integration, just create the directory/file: * mkdir content/docs/integrations/my-framework/shared-state * # Next build will auto-detect it! * * See docs/README.md for full documentation. */ import fs from 'fs'; import path from 'path'; import { fileURLToPath } from 'url'; const __filename = fileURLToPath(import.meta.url); const __dirname = path.dirname(__filename); const docsRoot = path.resolve(__dirname, '..'); const integrationsDir = path.join(docsRoot, 'content/docs/integrations'); // Features to check for (can be either directories or .mdx files) // For each feature, we check for BOTH: // 1. A directory with that name (e.g., shared-state/) // 2. A file with that name (e.g., frontend-actions.mdx) // The route is the same either way: /integration/feature-name const FEATURES = [ 'shared-state', 'generative-ui', 'generative-ui/render-only', 'generative-ui/tool-rendering', 'generative-ui/state-rendering', 'generative-ui/mcp-apps', 'generative-ui/a2ui', 'frontend-actions', 'human-in-the-loop', 'agentic-chat-ui', 'custom-look-and-feel', ]; // Valid integration IDs — must match INTEGRATION_ORDER in lib/integrations.ts const VALID_INTEGRATIONS = new Set([ 'direct-to-llm', 'langgraph', 'deepagents', 'adk', 'microsoft-agent-framework', 'aws-strands', 'mastra', 'pydantic-ai', 'crewai-flows', 'agno', 'ag2', 'agent-spec', 'llamaindex', 'a2a', ]); function getIntegrations() { return fs.readdirSync(integrationsDir, { withFileTypes: true }) .filter(dirent => dirent.isDirectory() && VALID_INTEGRATIONS.has(dirent.name)) .map(dirent => dirent.name); } function hasFeature(integrationId, featureName) { const integrationPath = path.join(integrationsDir, integrationId); // Check for directory (e.g., shared-state/) const featureDir = path.join(integrationPath, featureName); if (fs.existsSync(featureDir) && fs.statSync(featureDir).isDirectory()) { return true; } // Check for file (e.g., frontend-actions.mdx) const featureFile = path.join(integrationPath, `${featureName}.mdx`); if (fs.existsSync(featureFile)) { return true; } return false; } function generateFeatureMap() { const integrations = getIntegrations(); const featureMap = {}; // For each feature, list which integrations have it for (const featureName of FEATURES) { featureMap[featureName] = integrations.filter(id => hasFeature(id, featureName) ); } return featureMap; } function main() { const featureMap = generateFeatureMap(); const output = `// Auto-generated by scripts/generate-integration-features.mjs // Do not edit manually - run: node scripts/generate-integration-features.mjs import { IntegrationId } from './integrations'; /** * Maps feature names to the list of integration IDs that have that feature. * This is auto-generated at build time by scanning the content/docs/integrations directory. */ export const INTEGRATION_FEATURES: Record = ${JSON.stringify(featureMap, null, 2)}; /** * Check if an integration has a specific feature page. */ export function hasIntegrationFeature(integrationId: IntegrationId, feature: string): boolean { return INTEGRATION_FEATURES[feature]?.includes(integrationId) ?? false; } `; const outputPath = path.join(docsRoot, 'lib/integration-features.ts'); fs.writeFileSync(outputPath, output); console.log('✓ Generated lib/integration-features.ts'); console.log(` Features mapped: ${Object.keys(featureMap).length}`); console.log(` Integrations scanned: ${getIntegrations().length}`); } main();