Skip to content

Commit d10a23b

Browse files
committed
refactor: replace uiMap with dynamic component discovery and update HTML generation logic
1 parent 74270b7 commit d10a23b

File tree

3 files changed

+32
-32
lines changed

3 files changed

+32
-32
lines changed

src/ui/generated/tools/list-databases.ts

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/ui/registry/uiMap.ts

Lines changed: 0 additions & 12 deletions
This file was deleted.

vite.ui.config.ts

Lines changed: 31 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,8 @@ import { defineConfig, Plugin, PluginOption } from "vite";
22
import react from "@vitejs/plugin-react";
33
import { viteSingleFile } from "vite-plugin-singlefile";
44
import { nodePolyfills } from "vite-plugin-node-polyfills";
5-
import { readFileSync, writeFileSync, mkdirSync, existsSync } from "fs";
6-
import { join, resolve, dirname } from "path";
7-
import { uiMap } from "./src/ui/registry/uiMap.js";
5+
import { readFileSync, writeFileSync, mkdirSync, existsSync, readdirSync, statSync } from "fs";
6+
import { join, resolve } from "path";
87

98
const componentsDir = resolve(__dirname, "src/ui/components");
109
// Use node_modules/.cache for generated HTML entries - these are build artifacts, not source files
@@ -14,14 +13,37 @@ const mountPath = resolve(__dirname, "src/ui/build/mount.tsx");
1413
const generatedDir = resolve(__dirname, "src/ui/generated");
1514
const uiDistPath = resolve(__dirname, "dist/ui");
1615

17-
// Unique component names from uiMap - only these will be built
18-
const components = [...new Set(Object.values(uiMap))];
16+
// Converts PascalCase to kebab-case: "ListDatabases" -> "list-databases"
17+
function toKebabCase(pascalCase: string): string {
18+
return pascalCase
19+
.replace(/([a-z0-9])([A-Z])/g, "$1-$2")
20+
.replace(/([A-Z])([A-Z][a-z])/g, "$1-$2")
21+
.toLowerCase();
22+
}
23+
24+
// Discovers component directories and builds tool name mappings
25+
function discoverComponents(): { components: string[]; toolToComponentMap: Record<string, string> } {
26+
const components: string[] = [];
27+
const toolToComponentMap: Record<string, string> = {};
28+
29+
for (const entry of readdirSync(componentsDir)) {
30+
const entryPath = join(componentsDir, entry);
31+
const indexPath = join(entryPath, "index.ts");
32+
33+
if (statSync(entryPath).isDirectory() && existsSync(indexPath)) {
34+
components.push(entry);
35+
toolToComponentMap[toKebabCase(entry)] = entry;
36+
}
37+
}
38+
39+
return { components, toolToComponentMap };
40+
}
41+
42+
const { components, toolToComponentMap } = discoverComponents();
1943

2044
/**
21-
* Vite plugin that generates HTML entry files for each mapped component
45+
* Vite plugin that generates HTML entry files for each discovered component
2246
* based on the template.html file.
23-
*
24-
* Only builds components that are referenced in uiMap.
2547
*/
2648
function generateHtmlEntries(): Plugin {
2749
return {
@@ -34,14 +56,6 @@ function generateHtmlEntries(): Plugin {
3456
}
3557

3658
for (const componentName of components) {
37-
// Verify the component exists
38-
const componentPath = join(componentsDir, componentName, "index.ts");
39-
if (!existsSync(componentPath)) {
40-
throw new Error(
41-
`Component "${componentName}" referenced in uiMap but not found at ${componentPath}`
42-
);
43-
}
44-
4559
const html = template
4660
.replace("{{COMPONENT_NAME}}", componentName)
4761
.replace("{{TITLE}}", componentName.replace(/([A-Z])/g, " $1").trim()) // "ListDatabases" -> "List Databases"
@@ -57,8 +71,6 @@ function generateHtmlEntries(): Plugin {
5771

5872
/**
5973
* Vite plugin that generates per-tool UI modules after the build completes.
60-
*
61-
* Uses the uiMap to map tool names to component HTML files.
6274
*/
6375
function generateUIModule(): Plugin {
6476
return {
@@ -79,7 +91,7 @@ function generateUIModule(): Plugin {
7991

8092
const generatedTools: string[] = [];
8193

82-
for (const [toolName, componentName] of Object.entries(uiMap)) {
94+
for (const [toolName, componentName] of Object.entries(toolToComponentMap)) {
8395
const htmlFile = join(uiDistPath, `${componentName}.html`);
8496
if (!existsSync(htmlFile)) {
8597
console.warn(

0 commit comments

Comments
 (0)