Explorar o código

feat(docs): Generate index files with LinkCards for API reference folders

- Modified typescript-docs-renderer to generate index.mdx files with
  LinkCard components linking to each subfolder
- Added logic to merge LinkCards across multiple doc generation sections
- Generates section root index files for typescript-api, admin-ui-api,
  dashboard, and core-plugins
- Updated manifest to reference index.mdx instead of _index.mdx for
  typescript-api section
David Höck hai 3 días
pai
achega
07f154ab2f

+ 25 - 0
docs/docs/reference/admin-ui-api/index.mdx

@@ -0,0 +1,25 @@
+---
+title: "Admin Ui Api"
+generated: true
+---
+
+<LinkCard href="/reference/admin-ui-api/action-bar" title="Action Bar" />
+<LinkCard href="/reference/admin-ui-api/alerts" title="Alerts" />
+<LinkCard href="/reference/admin-ui-api/bulk-actions" title="Bulk Actions" />
+<LinkCard href="/reference/admin-ui-api/components" title="Components" />
+<LinkCard href="/reference/admin-ui-api/custom-detail-components" title="Custom Detail Components" />
+<LinkCard href="/reference/admin-ui-api/custom-history-entry-components" title="Custom History Entry Components" />
+<LinkCard href="/reference/admin-ui-api/custom-input-components" title="Custom Input Components" />
+<LinkCard href="/reference/admin-ui-api/custom-table-components" title="Custom Table Components" />
+<LinkCard href="/reference/admin-ui-api/dashboard-widgets" title="Dashboard Widgets" />
+<LinkCard href="/reference/admin-ui-api/directives" title="Directives" />
+<LinkCard href="/reference/admin-ui-api/list-detail-views" title="List Detail Views" />
+<LinkCard href="/reference/admin-ui-api/nav-menu" title="Nav Menu" />
+<LinkCard href="/reference/admin-ui-api/pipes" title="Pipes" />
+<LinkCard href="/reference/admin-ui-api/react-components" title="React Components" />
+<LinkCard href="/reference/admin-ui-api/react-extensions" title="React Extensions" />
+<LinkCard href="/reference/admin-ui-api/react-hooks" title="React Hooks" />
+<LinkCard href="/reference/admin-ui-api/routes" title="Routes" />
+<LinkCard href="/reference/admin-ui-api/services" title="Services" />
+<LinkCard href="/reference/admin-ui-api/tabs" title="Tabs" />
+<LinkCard href="/reference/admin-ui-api/ui-devkit" title="Ui Devkit" />

+ 13 - 0
docs/docs/reference/core-plugins/index.mdx

@@ -2,3 +2,16 @@
 title: "Core Plugins"
 generated: true
 ---
+
+<LinkCard href="/reference/core-plugins/admin-ui-plugin" title="Admin Ui Plugin" />
+<LinkCard href="/reference/core-plugins/asset-server-plugin" title="Asset Server Plugin" />
+<LinkCard href="/reference/core-plugins/dashboard-plugin" title="Dashboard Plugin" />
+<LinkCard href="/reference/core-plugins/elasticsearch-plugin" title="Elasticsearch Plugin" />
+<LinkCard href="/reference/core-plugins/email-plugin" title="Email Plugin" />
+<LinkCard href="/reference/core-plugins/graphiql-plugin" title="Graphiql Plugin" />
+<LinkCard href="/reference/core-plugins/harden-plugin" title="Harden Plugin" />
+<LinkCard href="/reference/core-plugins/job-queue-plugin" title="Job Queue Plugin" />
+<LinkCard href="/reference/core-plugins/payments-plugin" title="Payments Plugin" />
+<LinkCard href="/reference/core-plugins/sentry-plugin" title="Sentry Plugin" />
+<LinkCard href="/reference/core-plugins/stellate-plugin" title="Stellate Plugin" />
+<LinkCard href="/reference/core-plugins/telemetry-plugin" title="Telemetry Plugin" />

+ 13 - 0
docs/docs/reference/dashboard/index.mdx

@@ -0,0 +1,13 @@
+---
+title: "Dashboard"
+generated: true
+---
+
+<LinkCard href="/reference/dashboard/components" title="Components" />
+<LinkCard href="/reference/dashboard/detail-views" title="Detail Views" />
+<LinkCard href="/reference/dashboard/extensions-api" title="Extensions Api" />
+<LinkCard href="/reference/dashboard/form-components" title="Form Components" />
+<LinkCard href="/reference/dashboard/hooks" title="Hooks" />
+<LinkCard href="/reference/dashboard/list-views" title="List Views" />
+<LinkCard href="/reference/dashboard/page-layout" title="Page Layout" />
+<LinkCard href="/reference/dashboard/vite-plugin" title="Vite Plugin" />

+ 2 - 0
docs/docs/reference/typescript-api/common/index.mdx

@@ -2,3 +2,5 @@
 title: "Common"
 generated: true
 ---
+
+<LinkCard href="/reference/typescript-api/common/admin-ui" title="Admin Ui" />

+ 40 - 0
docs/docs/reference/typescript-api/index.mdx

@@ -0,0 +1,40 @@
+---
+title: "Typescript Api"
+generated: true
+---
+
+<LinkCard href="/reference/typescript-api/assets" title="Assets" />
+<LinkCard href="/reference/typescript-api/auth" title="Auth" />
+<LinkCard href="/reference/typescript-api/cache" title="Cache" />
+<LinkCard href="/reference/typescript-api/common" title="Common" />
+<LinkCard href="/reference/typescript-api/configurable-operation-def" title="Configurable Operation Def" />
+<LinkCard href="/reference/typescript-api/configuration" title="Configuration" />
+<LinkCard href="/reference/typescript-api/custom-fields" title="Custom Fields" />
+<LinkCard href="/reference/typescript-api/data-access" title="Data Access" />
+<LinkCard href="/reference/typescript-api/default-search-plugin" title="Default Search Plugin" />
+<LinkCard href="/reference/typescript-api/entities" title="Entities" />
+<LinkCard href="/reference/typescript-api/errors" title="Errors" />
+<LinkCard href="/reference/typescript-api/events" title="Events" />
+<LinkCard href="/reference/typescript-api/fulfillment" title="Fulfillment" />
+<LinkCard href="/reference/typescript-api/health-check" title="Health Check" />
+<LinkCard href="/reference/typescript-api/import-export" title="Import Export" />
+<LinkCard href="/reference/typescript-api/job-queue" title="Job Queue" />
+<LinkCard href="/reference/typescript-api/logger" title="Logger" />
+<LinkCard href="/reference/typescript-api/migration" title="Migration" />
+<LinkCard href="/reference/typescript-api/money" title="Money" />
+<LinkCard href="/reference/typescript-api/orders" title="Orders" />
+<LinkCard href="/reference/typescript-api/payment" title="Payment" />
+<LinkCard href="/reference/typescript-api/plugin" title="Plugin" />
+<LinkCard href="/reference/typescript-api/products-stock" title="Products Stock" />
+<LinkCard href="/reference/typescript-api/promotions" title="Promotions" />
+<LinkCard href="/reference/typescript-api/request" title="Request" />
+<LinkCard href="/reference/typescript-api/scheduled-tasks" title="Scheduled Tasks" />
+<LinkCard href="/reference/typescript-api/service-helpers" title="Service Helpers" />
+<LinkCard href="/reference/typescript-api/services" title="Services" />
+<LinkCard href="/reference/typescript-api/settings-store" title="Settings Store" />
+<LinkCard href="/reference/typescript-api/shipping" title="Shipping" />
+<LinkCard href="/reference/typescript-api/state-machine" title="State Machine" />
+<LinkCard href="/reference/typescript-api/tax" title="Tax" />
+<LinkCard href="/reference/typescript-api/telemetry" title="Telemetry" />
+<LinkCard href="/reference/typescript-api/testing" title="Testing" />
+<LinkCard href="/reference/typescript-api/worker" title="Worker" />

+ 10 - 19
docs/src/manifest.ts

@@ -750,13 +750,10 @@ const manifestInput: DocsPackageManifestInput = {
                 {
                     title: 'TypeScript API',
                     slug: 'typescript-api',
-                    file: file('docs/reference/typescript-api/_index.mdx'),
-                    children: createNestedNavigationFromFolder(
-                        folder('docs/reference/typescript-api'),
-                        {
-                            filter: (info: FileInfo) => info.filename !== '_index.mdx',
-                        },
-                    ),
+                    file: file('docs/reference/typescript-api/index.mdx'),
+                    children: createNestedNavigationFromFolder(folder('docs/reference/typescript-api'), {
+                        filter: (info: FileInfo) => info.filename !== 'index.mdx',
+                    }),
                 },
                 {
                     title: 'Core Plugins',
@@ -929,23 +926,17 @@ const manifestInput: DocsPackageManifestInput = {
                     title: 'Dashboard API',
                     slug: 'dashboard',
                     file: file('docs/reference/dashboard/index.mdx'),
-                    children: createNestedNavigationFromFolder(
-                        folder('docs/reference/dashboard'),
-                        {
-                            filter: (info: FileInfo) => info.filename !== 'index.mdx',
-                        },
-                    ),
+                    children: createNestedNavigationFromFolder(folder('docs/reference/dashboard'), {
+                        filter: (info: FileInfo) => info.filename !== 'index.mdx',
+                    }),
                 },
                 {
                     title: 'Admin UI API',
                     slug: 'admin-ui-api',
                     file: file('docs/reference/admin-ui-api/index.mdx'),
-                    children: createNestedNavigationFromFolder(
-                        folder('docs/reference/admin-ui-api'),
-                        {
-                            filter: (info: FileInfo) => info.filename !== 'index.mdx',
-                        },
-                    ),
+                    children: createNestedNavigationFromFolder(folder('docs/reference/admin-ui-api'), {
+                        filter: (info: FileInfo) => info.filename !== 'index.mdx',
+                    }),
                 },
             ],
         },

+ 134 - 7
scripts/docs/typescript-docs-renderer.ts

@@ -5,7 +5,7 @@ import { HeritageClause } from 'typescript';
 
 import { assertNever } from '../../packages/common/src/shared-utils';
 
-import { generateFrontMatter } from './docgen-utils';
+import { generateFrontMatter, titleCase } from './docgen-utils';
 import {
     ClassInfo,
     DeclarationInfo,
@@ -28,6 +28,33 @@ export class TypescriptDocsRenderer {
             fs.ensureDirSync(outputPath);
         }
 
+        // Extract the section base path (e.g., 'typescript-api' from '.../reference/typescript-api')
+        const referenceIndex = outputPath.indexOf('/reference/');
+        const sectionBasePath = referenceIndex !== -1
+            ? outputPath.slice(referenceIndex + '/reference/'.length)
+            : '';
+
+        // Build a map of parent category paths to their direct child categories
+        const categoryChildren = new Map<string, Set<string>>();
+        // Also track direct children of the section root (for sections like 'admin-ui-api', 'dashboard')
+        const sectionRootChildren = new Set<string>();
+
+        for (const page of pages) {
+            // Track the first category as a child of the section root
+            if (page.category.length > 0) {
+                sectionRootChildren.add(page.category[0]);
+            }
+            // Track nested category relationships
+            for (let i = 0; i < page.category.length - 1; i++) {
+                const parentPath = page.category.slice(0, i + 1).join('/');
+                const childCategory = page.category[i + 1];
+                if (!categoryChildren.has(parentPath)) {
+                    categoryChildren.set(parentPath, new Set());
+                }
+                categoryChildren.get(parentPath)!.add(childCategory);
+            }
+        }
+
         for (const page of pages) {
             let markdown = '';
             markdown += generateFrontMatter(page.title);
@@ -61,23 +88,123 @@ export class TypescriptDocsRenderer {
             if (!fs.existsSync(categoryDir)) {
                 fs.mkdirsSync(categoryDir);
             }
-            const pathParts = [];
+            const pathParts: string[] = [];
             for (const subCategory of page.category) {
                 pathParts.push(subCategory);
                 const indexFile = path.join(outputPath, ...pathParts, 'index.mdx');
                 const exists = fs.existsSync(indexFile);
-                const existingContent = exists && fs.readFileSync(indexFile).toString();
-                const hasActualContent = existingContent && existingContent.includes('isDefaultIndex: false');
-                if (!exists && !hasActualContent) {
-                    const indexFileContent = generateFrontMatter(subCategory, true);
+                const existingContent = exists ? fs.readFileSync(indexFile).toString() : '';
+                const isGenerated = existingContent.includes('generated: true');
+                const hasCustomContent = existingContent.includes('isDefaultIndex: false');
+
+                // Skip files with custom content
+                if (hasCustomContent) {
+                    continue;
+                }
+
+                const categoryPath = pathParts.join('/');
+                const children = categoryChildren.get(categoryPath);
+
+                // Collect existing LinkCards from the file if it exists
+                const existingLinkCards = new Set<string>();
+                if (exists && isGenerated) {
+                    const linkCardRegex = /<LinkCard href="([^"]+)"/g;
+                    let match;
+                    while ((match = linkCardRegex.exec(existingContent)) !== null) {
+                        existingLinkCards.add(match[1]);
+                    }
+                }
+
+                // Build set of new LinkCards
+                const newLinkCards = new Set<string>();
+                if (children && children.size > 0) {
+                    for (const child of children) {
+                        const basePath = sectionBasePath ? `${sectionBasePath}/` : '';
+                        const absolutePath = `/reference/${basePath}${categoryPath}/${child}`;
+                        newLinkCards.add(absolutePath);
+                    }
+                }
+
+                // Merge and check if we need to write
+                const allLinkCards = new Set([...existingLinkCards, ...newLinkCards]);
+                const hasNewCards = newLinkCards.size > 0 &&
+                    [...newLinkCards].some(card => !existingLinkCards.has(card));
+
+                if (!exists || hasNewCards) {
+                    let indexFileContent = generateFrontMatter(subCategory, true);
+
+                    if (allLinkCards.size > 0) {
+                        indexFileContent += '\n';
+                        const sortedCards = Array.from(allLinkCards).sort();
+                        for (const href of sortedCards) {
+                            // Extract child name from href for title
+                            const childName = href.split('/').pop() || '';
+                            const title = titleCase(childName.replace(/-/g, ' '));
+                            indexFileContent += `<LinkCard href="${href}" title="${title}" />\n`;
+                        }
+                    }
+
                     fs.writeFileSync(indexFile, indexFileContent);
-                    generatedCount++;
+                    if (!exists) {
+                        generatedCount++;
+                    }
                 }
             }
 
             fs.writeFileSync(path.join(categoryDir, page.fileName + '.mdx'), markdown);
             generatedCount++;
         }
+
+        // Generate index file for the section root (e.g., admin-ui-api/index.mdx, dashboard/index.mdx)
+        if (sectionBasePath && sectionRootChildren.size > 0) {
+            const sectionIndexFile = path.join(outputPath, 'index.mdx');
+            const exists = fs.existsSync(sectionIndexFile);
+            const existingContent = exists ? fs.readFileSync(sectionIndexFile).toString() : '';
+            const isGenerated = existingContent.includes('generated: true');
+            const hasCustomContent = existingContent.includes('isDefaultIndex: false');
+
+            if (!hasCustomContent) {
+                // Collect existing LinkCards
+                const existingLinkCards = new Set<string>();
+                if (exists && isGenerated) {
+                    const linkCardRegex = /<LinkCard href="([^"]+)"/g;
+                    let match;
+                    while ((match = linkCardRegex.exec(existingContent)) !== null) {
+                        existingLinkCards.add(match[1]);
+                    }
+                }
+
+                // Build new LinkCards
+                const newLinkCards = new Set<string>();
+                for (const child of sectionRootChildren) {
+                    const absolutePath = `/reference/${sectionBasePath}/${child}`;
+                    newLinkCards.add(absolutePath);
+                }
+
+                // Merge and check if update needed
+                const allLinkCards = new Set([...existingLinkCards, ...newLinkCards]);
+                const hasNewCards = [...newLinkCards].some(card => !existingLinkCards.has(card));
+
+                if (!exists || hasNewCards) {
+                    const sectionTitle = titleCase(sectionBasePath.replace(/-/g, ' '));
+                    let indexFileContent = generateFrontMatter(sectionTitle, true);
+
+                    indexFileContent += '\n';
+                    const sortedCards = Array.from(allLinkCards).sort();
+                    for (const href of sortedCards) {
+                        const childName = href.split('/').pop() || '';
+                        const title = titleCase(childName.replace(/-/g, ' '));
+                        indexFileContent += `<LinkCard href="${href}" title="${title}" />\n`;
+                    }
+
+                    fs.writeFileSync(sectionIndexFile, indexFileContent);
+                    if (!exists) {
+                        generatedCount++;
+                    }
+                }
+            }
+        }
+
         return generatedCount;
     }