github-to-mcp-monorepo 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.env.example +8 -0
- package/.github/CODEOWNERS +6 -0
- package/.husky/pre-commit +1 -0
- package/.nvmrc +1 -0
- package/.prettierignore +5 -0
- package/.prettierrc +7 -0
- package/.vscode/settings.json +4 -0
- package/ARCHITECTURE.md +1429 -0
- package/CHANGELOG.md +167 -0
- package/CONTRIBUTING.md +327 -0
- package/LICENSE +201 -0
- package/README.md +1028 -0
- package/SECURITY.md +248 -0
- package/VISUAL_GUIDE.md +437 -0
- package/apps/vscode/IMPLEMENTATION.md +480 -0
- package/apps/vscode/README.md +248 -0
- package/apps/vscode/package.json +381 -0
- package/apps/vscode/resources/icon.png +0 -0
- package/apps/vscode/resources/icon.svg +5 -0
- package/apps/vscode/src/commands/browseRegistry.ts +211 -0
- package/apps/vscode/src/commands/configureClaudeDesktop.ts +332 -0
- package/apps/vscode/src/commands/convert.ts +82 -0
- package/apps/vscode/src/commands/convertCurrentRepo.ts +109 -0
- package/apps/vscode/src/commands/convertFromUrl.ts +138 -0
- package/apps/vscode/src/commands/index.ts +121 -0
- package/apps/vscode/src/commands/validate.ts +197 -0
- package/apps/vscode/src/extension.ts +464 -0
- package/apps/vscode/src/global.d.ts +36 -0
- package/apps/vscode/src/test/extension.test.ts +73 -0
- package/apps/vscode/src/utils/file-generator.ts +529 -0
- package/apps/vscode/src/utils/github-api.ts +335 -0
- package/apps/vscode/src/utils/index.ts +29 -0
- package/apps/vscode/src/utils/mcp-config.ts +334 -0
- package/apps/vscode/src/utils/storage.ts +87 -0
- package/apps/vscode/src/views/McpServersTreeView.ts +160 -0
- package/apps/vscode/src/views/OutputChannelView.ts +195 -0
- package/apps/vscode/src/views/StatusBarItem.ts +251 -0
- package/apps/vscode/src/views/ToolsExplorerView.ts +314 -0
- package/apps/vscode/src/views/historyProvider.ts +75 -0
- package/apps/vscode/src/views/index.ts +12 -0
- package/apps/vscode/src/views/resultsPanel.ts +330 -0
- package/apps/vscode/src/webviews/ConversionPanel.ts +350 -0
- package/apps/vscode/src/webviews/ToolDetailsPanel.ts +448 -0
- package/apps/vscode/src/webviews/index.ts +9 -0
- package/apps/vscode/src/webviews/webview-ui/styles.ts +492 -0
- package/apps/vscode/tsconfig.json +20 -0
- package/apps/web/PLAYGROUND_GUIDE.md +499 -0
- package/apps/web/README.md +505 -0
- package/apps/web/app/api/convert/route.ts +100 -0
- package/apps/web/app/api/convert/stream/route.ts +198 -0
- package/apps/web/app/api/deploy/route.ts +157 -0
- package/apps/web/app/api/edge/route.ts +308 -0
- package/apps/web/app/api/export-docker/route.ts +284 -0
- package/apps/web/app/api/generate-openapi/route.ts +119 -0
- package/apps/web/app/api/mcp/[serverId]/route.ts +263 -0
- package/apps/web/app/api/playground/connect/route.ts +143 -0
- package/apps/web/app/api/playground/disconnect/route.ts +78 -0
- package/apps/web/app/api/playground/execute/route.ts +135 -0
- package/apps/web/app/api/playground/sessions/route.ts +103 -0
- package/apps/web/app/api/playground/tools/route.ts +117 -0
- package/apps/web/app/api/playground/v2/connect/route.ts +96 -0
- package/apps/web/app/api/playground/v2/disconnect/route.ts +88 -0
- package/apps/web/app/api/playground/v2/health/route.ts +80 -0
- package/apps/web/app/api/playground/v2/prompts/route.ts +160 -0
- package/apps/web/app/api/playground/v2/resources/route.ts +159 -0
- package/apps/web/app/api/playground/v2/sessions/route.ts +184 -0
- package/apps/web/app/api/playground/v2/tools/route.ts +167 -0
- package/apps/web/app/api/stream/route.ts +232 -0
- package/apps/web/app/batch/BatchConvertClient.tsx +190 -0
- package/apps/web/app/batch/page.tsx +37 -0
- package/apps/web/app/convert/page.tsx +269 -0
- package/apps/web/app/dashboard/page.tsx +380 -0
- package/apps/web/app/globals.css +622 -0
- package/apps/web/app/layout.tsx +120 -0
- package/apps/web/app/manifest.ts +31 -0
- package/apps/web/app/opengraph-image.tsx +112 -0
- package/apps/web/app/page.old.tsx +924 -0
- package/apps/web/app/page.tsx +77 -0
- package/apps/web/app/playground/page.tsx +306 -0
- package/apps/web/app/playground/v2/error.tsx +163 -0
- package/apps/web/app/playground/v2/layout.tsx +58 -0
- package/apps/web/app/playground/v2/loading.tsx +152 -0
- package/apps/web/app/playground/v2/page.tsx +644 -0
- package/apps/web/app/playground/v2/providers.tsx +214 -0
- package/apps/web/app/playground/v2/use-shortcuts.ts +209 -0
- package/apps/web/app/playground/v2/use-url-state.ts +296 -0
- package/apps/web/app/providers.tsx +22 -0
- package/apps/web/app/sitemap.ts +32 -0
- package/apps/web/app/twitter-image.tsx +112 -0
- package/apps/web/components/BranchSelector.tsx +401 -0
- package/apps/web/components/ClaudeConfigExport.tsx +226 -0
- package/apps/web/components/Features.tsx +84 -0
- package/apps/web/components/Footer.tsx +119 -0
- package/apps/web/components/GenerationProgress.tsx +248 -0
- package/apps/web/components/GithubUrlInput.tsx +483 -0
- package/apps/web/components/Header.tsx +175 -0
- package/apps/web/components/Hero.tsx +117 -0
- package/apps/web/components/HowItWorks.tsx +119 -0
- package/apps/web/components/InstallBanner.tsx +158 -0
- package/apps/web/components/Logo.tsx +116 -0
- package/apps/web/components/ParticleBackground.tsx +105 -0
- package/apps/web/components/Playground.tsx +472 -0
- package/apps/web/components/PlaygroundToolTester.tsx +410 -0
- package/apps/web/components/ProductCards.tsx +179 -0
- package/apps/web/components/SplitView.tsx +194 -0
- package/apps/web/components/ToolFilter.tsx +260 -0
- package/apps/web/components/ToolList.tsx +325 -0
- package/apps/web/components/batch/BatchConvert.tsx +785 -0
- package/apps/web/components/batch/index.ts +7 -0
- package/apps/web/components/convert/ConfigTabs.tsx +230 -0
- package/apps/web/components/convert/ConversionResult.tsx +482 -0
- package/apps/web/components/convert/InlinePlayground.tsx +259 -0
- package/apps/web/components/convert/LoadingSteps.tsx +311 -0
- package/apps/web/components/convert/OneClickInstall.tsx +224 -0
- package/apps/web/components/convert/ToolCard.tsx +189 -0
- package/apps/web/components/convert/TryInPlayground.tsx +242 -0
- package/apps/web/components/convert/index.ts +12 -0
- package/apps/web/components/deploy/DeployButton.tsx +369 -0
- package/apps/web/components/deploy/index.ts +7 -0
- package/apps/web/components/docker/DockerExport.tsx +690 -0
- package/apps/web/components/docker/index.ts +7 -0
- package/apps/web/components/install/OneClickInstall.tsx +676 -0
- package/apps/web/components/install/index.ts +7 -0
- package/apps/web/components/playground/CapabilityTabs.tsx +150 -0
- package/apps/web/components/playground/ConnectionStatusV2.tsx +322 -0
- package/apps/web/components/playground/EmptyStates.tsx +305 -0
- package/apps/web/components/playground/ExecutionLog.tsx +260 -0
- package/apps/web/components/playground/ExecutionLogV2.tsx +378 -0
- package/apps/web/components/playground/JsonViewer.tsx +388 -0
- package/apps/web/components/playground/PlaygroundLayout.tsx +244 -0
- package/apps/web/components/playground/PromptsPanel.tsx +385 -0
- package/apps/web/components/playground/ResourcesPanel.tsx +378 -0
- package/apps/web/components/playground/SchemaForm.tsx +477 -0
- package/apps/web/components/playground/ServerStatus.tsx +151 -0
- package/apps/web/components/playground/ShareButton.tsx +239 -0
- package/apps/web/components/playground/ToolsPanel.tsx +309 -0
- package/apps/web/components/playground/TransportConfigurator.tsx +563 -0
- package/apps/web/components/playground/index.ts +74 -0
- package/apps/web/components/playground/types.ts +202 -0
- package/apps/web/components/streaming/StreamingProgress.tsx +441 -0
- package/apps/web/components/streaming/index.ts +7 -0
- package/apps/web/components/ui/badge.tsx +42 -0
- package/apps/web/components/ui/button.tsx +88 -0
- package/apps/web/components/ui/card.tsx +75 -0
- package/apps/web/components/ui/code-block.tsx +122 -0
- package/apps/web/components/ui/index.ts +12 -0
- package/apps/web/components/ui/input.tsx +55 -0
- package/apps/web/components/ui/tabs.tsx +61 -0
- package/apps/web/hooks/index.ts +85 -0
- package/apps/web/hooks/types.ts +1173 -0
- package/apps/web/hooks/use-conversion.ts +133 -0
- package/apps/web/hooks/use-execution-history.ts +376 -0
- package/apps/web/hooks/use-generation-progress.ts +147 -0
- package/apps/web/hooks/use-local-storage.ts +88 -0
- package/apps/web/hooks/use-mcp-client.ts +623 -0
- package/apps/web/hooks/use-mcp-connection.ts +500 -0
- package/apps/web/hooks/use-mcp-execution.ts +282 -0
- package/apps/web/hooks/use-mcp-prompts.ts +441 -0
- package/apps/web/hooks/use-mcp-resources.ts +430 -0
- package/apps/web/hooks/use-mcp-tools.ts +540 -0
- package/apps/web/hooks/use-playground-store.ts +299 -0
- package/apps/web/hooks/use-playground.ts +184 -0
- package/apps/web/hooks/use-streaming-conversion.ts +227 -0
- package/apps/web/hooks/useBatchConversion.ts +271 -0
- package/apps/web/hooks/useDockerConfig.ts +161 -0
- package/apps/web/hooks/usePlatformDetection.ts +80 -0
- package/apps/web/hooks/useStreaming.ts +199 -0
- package/apps/web/lib/api/errors.ts +386 -0
- package/apps/web/lib/api/index.ts +137 -0
- package/apps/web/lib/api/logger.ts +187 -0
- package/apps/web/lib/api/middleware.ts +364 -0
- package/apps/web/lib/api/openapi.ts +977 -0
- package/apps/web/lib/api/session-manager.ts +594 -0
- package/apps/web/lib/api/types.ts +433 -0
- package/apps/web/lib/api/validation.ts +523 -0
- package/apps/web/lib/constants.ts +114 -0
- package/apps/web/lib/mcp/client.ts +1137 -0
- package/apps/web/lib/mcp/events.ts +651 -0
- package/apps/web/lib/mcp/index.ts +347 -0
- package/apps/web/lib/mcp/logger.ts +428 -0
- package/apps/web/lib/mcp/metrics.ts +703 -0
- package/apps/web/lib/mcp/retry.ts +616 -0
- package/apps/web/lib/mcp/session-manager.ts +779 -0
- package/apps/web/lib/mcp/transports.ts +988 -0
- package/apps/web/lib/mcp/types.ts +594 -0
- package/apps/web/lib/mcp-client-enhanced.ts +871 -0
- package/apps/web/lib/mcp-client.ts +778 -0
- package/apps/web/lib/mcp-errors.ts +489 -0
- package/apps/web/lib/mcp-sandbox.ts +593 -0
- package/apps/web/lib/mcp-testing.ts +428 -0
- package/apps/web/lib/mcp-types.ts +448 -0
- package/apps/web/lib/playground-store.tsx +1147 -0
- package/apps/web/lib/utils.ts +439 -0
- package/apps/web/next-env.d.ts +5 -0
- package/apps/web/next.config.js +23 -0
- package/apps/web/package.json +55 -0
- package/apps/web/postcss.config.js +6 -0
- package/apps/web/public/.well-known/ai-plugin.json +17 -0
- package/apps/web/public/logo.svg +6 -0
- package/apps/web/public/robots.txt +22 -0
- package/apps/web/public/schema.json +27 -0
- package/apps/web/tailwind.config.js +26 -0
- package/apps/web/tailwind.config.ts +123 -0
- package/apps/web/tsconfig.json +20 -0
- package/apps/web/types/deploy.ts +139 -0
- package/apps/web/types/index.ts +247 -0
- package/apps/web/vercel.json +39 -0
- package/eslint.config.mjs +23 -0
- package/llms.txt +102 -0
- package/mkdocs/docs/api/core.md +318 -0
- package/mkdocs/docs/api/index.md +128 -0
- package/mkdocs/docs/api/mcp-server.md +301 -0
- package/mkdocs/docs/api/openapi-parser.md +254 -0
- package/mkdocs/docs/assets/logo.svg +7 -0
- package/mkdocs/docs/changelog.md +118 -0
- package/mkdocs/docs/cli/generate.md +148 -0
- package/mkdocs/docs/cli/index.md +52 -0
- package/mkdocs/docs/cli/inspect.md +164 -0
- package/mkdocs/docs/cli/serve.md +136 -0
- package/mkdocs/docs/concepts/classification.md +254 -0
- package/mkdocs/docs/concepts/how-it-works.md +299 -0
- package/mkdocs/docs/concepts/index.md +77 -0
- package/mkdocs/docs/concepts/mcp-protocol.md +362 -0
- package/mkdocs/docs/concepts/tool-types.md +382 -0
- package/mkdocs/docs/contributing/architecture.md +262 -0
- package/mkdocs/docs/contributing/development.md +245 -0
- package/mkdocs/docs/contributing/index.md +73 -0
- package/mkdocs/docs/contributing/testing.md +320 -0
- package/mkdocs/docs/getting-started/configuration.md +235 -0
- package/mkdocs/docs/getting-started/index.md +54 -0
- package/mkdocs/docs/getting-started/installation.md +145 -0
- package/mkdocs/docs/getting-started/quickstart.md +160 -0
- package/mkdocs/docs/guides/batch.md +375 -0
- package/mkdocs/docs/guides/claude-desktop.md +227 -0
- package/mkdocs/docs/guides/cursor.md +188 -0
- package/mkdocs/docs/guides/custom-tools.md +367 -0
- package/mkdocs/docs/guides/index.md +78 -0
- package/mkdocs/docs/guides/private-repos.md +221 -0
- package/mkdocs/docs/guides/vscode.md +247 -0
- package/mkdocs/docs/index.md +175 -0
- package/mkdocs/docs/reference/config.md +223 -0
- package/mkdocs/docs/reference/env.md +192 -0
- package/mkdocs/docs/reference/index.md +102 -0
- package/mkdocs/docs/reference/tools.md +309 -0
- package/mkdocs/docs/stylesheets/extra.css +231 -0
- package/mkdocs/mkdocs.yml +204 -0
- package/mkdocs/overrides/.gitkeep +1 -0
- package/mkdocs/overrides/main.html +7 -0
- package/mkdocs/python-deps.txt +7 -0
- package/mkdocs/vercel.json +11 -0
- package/package.json +63 -0
- package/packages/core/package.json +61 -0
- package/packages/core/src/__tests__/bitbucket-client.test.ts +366 -0
- package/packages/core/src/__tests__/cli.test.ts +235 -0
- package/packages/core/src/__tests__/code-extractor.test.ts +378 -0
- package/packages/core/src/__tests__/docker-generator.test.ts +255 -0
- package/packages/core/src/__tests__/github-client.test.ts +390 -0
- package/packages/core/src/__tests__/gitlab-client.test.ts +319 -0
- package/packages/core/src/__tests__/go-extractor.test.ts +351 -0
- package/packages/core/src/__tests__/graphql-extractor.test.ts +330 -0
- package/packages/core/src/__tests__/java-extractor.test.ts +497 -0
- package/packages/core/src/__tests__/plugins.test.ts +467 -0
- package/packages/core/src/__tests__/readme-extractor.test.ts +258 -0
- package/packages/core/src/__tests__/redis-cache.test.ts +307 -0
- package/packages/core/src/__tests__/rust-extractor.test.ts +252 -0
- package/packages/core/src/__tests__/streaming.test.ts +251 -0
- package/packages/core/src/additional-extractors.ts +333 -0
- package/packages/core/src/cache/cache-interface.ts +179 -0
- package/packages/core/src/cache/index.ts +210 -0
- package/packages/core/src/cache/redis-cache.ts +291 -0
- package/packages/core/src/cache/upstash-cache.ts +379 -0
- package/packages/core/src/cache.ts +251 -0
- package/packages/core/src/cli.ts +822 -0
- package/packages/core/src/code-extractor.ts +696 -0
- package/packages/core/src/docker-generator.ts +470 -0
- package/packages/core/src/edge-compatible.ts +491 -0
- package/packages/core/src/extractors/go-extractor.ts +791 -0
- package/packages/core/src/extractors/index.ts +9 -0
- package/packages/core/src/extractors/java-extractor.ts +937 -0
- package/packages/core/src/extractors/rust-extractor.ts +744 -0
- package/packages/core/src/github-client.ts +319 -0
- package/packages/core/src/go-generator.ts +356 -0
- package/packages/core/src/graphql-extractor.ts +358 -0
- package/packages/core/src/index.ts +797 -0
- package/packages/core/src/langchain-exporter.ts +617 -0
- package/packages/core/src/language-parsers.ts +1114 -0
- package/packages/core/src/mcp-introspector.ts +279 -0
- package/packages/core/src/monorepo-detector.ts +378 -0
- package/packages/core/src/plugins/index.ts +370 -0
- package/packages/core/src/plugins/registry.ts +404 -0
- package/packages/core/src/plugins/types.ts +215 -0
- package/packages/core/src/providers/base-provider.ts +246 -0
- package/packages/core/src/providers/bitbucket-client.ts +464 -0
- package/packages/core/src/providers/gitlab-client.ts +388 -0
- package/packages/core/src/providers/index.ts +176 -0
- package/packages/core/src/python-generator.ts +260 -0
- package/packages/core/src/queue/index.ts +100 -0
- package/packages/core/src/queue/memory-queue.ts +445 -0
- package/packages/core/src/queue/redis-queue.ts +578 -0
- package/packages/core/src/queue/types.ts +251 -0
- package/packages/core/src/readme-extractor.ts +409 -0
- package/packages/core/src/schema-generator.ts +638 -0
- package/packages/core/src/streaming.ts +999 -0
- package/packages/core/src/types.ts +289 -0
- package/packages/core/tsconfig.json +9 -0
- package/packages/core/tsup.config.ts +25 -0
- package/packages/mcp-server/README.md +297 -0
- package/packages/mcp-server/package.json +55 -0
- package/packages/mcp-server/src/__tests__/mcp-server.test.ts +177 -0
- package/packages/mcp-server/src/__tests__/tools.test.ts +217 -0
- package/packages/mcp-server/src/index.ts +1206 -0
- package/packages/mcp-server/src/prompts/index.ts +601 -0
- package/packages/mcp-server/src/tools/export-docker.ts +362 -0
- package/packages/mcp-server/src/tools/generate-openapi.ts +162 -0
- package/packages/mcp-server/src/tools/monitor-mcp-server.ts +448 -0
- package/packages/mcp-server/src/tools/stream-convert.ts +398 -0
- package/packages/mcp-server/src/tools/test-mcp-tool.ts +531 -0
- package/packages/mcp-server/tsconfig.json +12 -0
- package/packages/mcp-server/tsup.config.ts +14 -0
- package/packages/openapi-parser/package-lock.json +3028 -0
- package/packages/openapi-parser/package.json +41 -0
- package/packages/openapi-parser/src/analyzer.ts +700 -0
- package/packages/openapi-parser/src/asyncapi-parser.ts +475 -0
- package/packages/openapi-parser/src/cli.ts +302 -0
- package/packages/openapi-parser/src/generator.ts +570 -0
- package/packages/openapi-parser/src/generators/express-analyzer.ts +649 -0
- package/packages/openapi-parser/src/generators/fastapi-analyzer.ts +960 -0
- package/packages/openapi-parser/src/generators/index.ts +200 -0
- package/packages/openapi-parser/src/generators/nextjs-analyzer.ts +768 -0
- package/packages/openapi-parser/src/generators/openapi-builder.ts +527 -0
- package/packages/openapi-parser/src/generators/types.ts +298 -0
- package/packages/openapi-parser/src/graphql-parser.ts +462 -0
- package/packages/openapi-parser/src/grpc-parser.ts +649 -0
- package/packages/openapi-parser/src/har-parser.ts +723 -0
- package/packages/openapi-parser/src/index.ts +635 -0
- package/packages/openapi-parser/src/insomnia-parser.ts +614 -0
- package/packages/openapi-parser/src/parser.ts +231 -0
- package/packages/openapi-parser/src/postman-parser.ts +611 -0
- package/packages/openapi-parser/src/ref-resolver.ts +313 -0
- package/packages/openapi-parser/src/transformer.ts +459 -0
- package/packages/openapi-parser/tests/generators/express.test.ts +209 -0
- package/packages/openapi-parser/tests/generators/fastapi.test.ts +236 -0
- package/packages/openapi-parser/tests/generators/nextjs.test.ts +273 -0
- package/packages/openapi-parser/tests/parsers.test.ts +847 -0
- package/packages/openapi-parser/tsconfig.json +9 -0
- package/packages/openapi-parser/tsup.config.ts +11 -0
- package/packages/registry/package.json +59 -0
- package/packages/registry/src/cli.ts +456 -0
- package/packages/registry/src/index.ts +44 -0
- package/packages/registry/src/popular/github.json +47 -0
- package/packages/registry/src/popular/index.ts +55 -0
- package/packages/registry/src/popular/linear.json +42 -0
- package/packages/registry/src/popular/notion.json +42 -0
- package/packages/registry/src/popular/openai.json +40 -0
- package/packages/registry/src/popular/resend.json +38 -0
- package/packages/registry/src/popular/slack.json +42 -0
- package/packages/registry/src/popular/stripe.json +163 -0
- package/packages/registry/src/popular/supabase.json +42 -0
- package/packages/registry/src/popular/twilio.json +40 -0
- package/packages/registry/src/popular/vercel.json +40 -0
- package/packages/registry/src/registry.ts +492 -0
- package/packages/registry/src/storage.ts +334 -0
- package/packages/registry/src/types.ts +275 -0
- package/packages/registry/src/updater.ts +208 -0
- package/packages/registry/tsconfig.json +10 -0
- package/packages/registry/tsup.config.ts +11 -0
- package/pnpm-workspace.yaml +3 -0
- package/scripts/build-docs.sh +16 -0
- package/server.json +9 -0
- package/templates/Dockerfile.python.template +60 -0
- package/templates/Dockerfile.typescript.template +60 -0
- package/templates/docker-compose.template.yml +68 -0
- package/tests/fixtures/express-app/index.js +34 -0
- package/tests/fixtures/express-app/routes/posts.js +43 -0
- package/tests/fixtures/express-app/routes/users.js +58 -0
- package/tests/fixtures/fastapi-app/main.py +125 -0
- package/tests/fixtures/fastapi-app/routes/admin.py +42 -0
- package/tests/fixtures/graphql/simple-schema.graphql +65 -0
- package/tests/fixtures/mocks/github-api-responses.json +63 -0
- package/tests/fixtures/nextjs-app/app/api/posts/route.ts +55 -0
- package/tests/fixtures/nextjs-app/app/api/users/[id]/route.ts +63 -0
- package/tests/fixtures/nextjs-app/app/api/users/route.ts +44 -0
- package/tests/fixtures/nextjs-app/pages/api/health.ts +28 -0
- package/tests/fixtures/openapi/petstore.yaml +179 -0
- package/tests/integration/langchain-export.test.ts +405 -0
- package/tests/integration/openapi-conversion.test.ts +221 -0
- package/tsconfig.json +18 -0
- package/vitest.config.ts +32 -0
|
@@ -0,0 +1,351 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Unit tests for Go extractor
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { describe, it, expect, beforeEach } from 'vitest';
|
|
6
|
+
import { GoExtractor } from '../extractors/go-extractor';
|
|
7
|
+
|
|
8
|
+
describe('GoExtractor', () => {
|
|
9
|
+
let extractor: GoExtractor;
|
|
10
|
+
|
|
11
|
+
beforeEach(() => {
|
|
12
|
+
extractor = new GoExtractor();
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
describe('extract', () => {
|
|
16
|
+
describe('Gin routes', () => {
|
|
17
|
+
it('should extract GET routes', async () => {
|
|
18
|
+
const code = `
|
|
19
|
+
package main
|
|
20
|
+
|
|
21
|
+
import "github.com/gin-gonic/gin"
|
|
22
|
+
|
|
23
|
+
func main() {
|
|
24
|
+
r := gin.Default()
|
|
25
|
+
r.GET("/users/:id", getUser)
|
|
26
|
+
r.Run()
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
func getUser(c *gin.Context) {
|
|
30
|
+
id := c.Param("id")
|
|
31
|
+
c.JSON(200, gin.H{"id": id})
|
|
32
|
+
}
|
|
33
|
+
`;
|
|
34
|
+
|
|
35
|
+
const tools = await extractor.extract(code, 'main.go');
|
|
36
|
+
|
|
37
|
+
expect(tools.length).toBeGreaterThan(0);
|
|
38
|
+
const tool = tools.find(t => t.name.includes('get_users'));
|
|
39
|
+
expect(tool).toBeDefined();
|
|
40
|
+
expect(tool?.inputSchema.properties).toHaveProperty('id');
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
it('should extract POST routes', async () => {
|
|
44
|
+
const code = `
|
|
45
|
+
package main
|
|
46
|
+
|
|
47
|
+
import "github.com/gin-gonic/gin"
|
|
48
|
+
|
|
49
|
+
func SetupRouter() *gin.Engine {
|
|
50
|
+
r := gin.Default()
|
|
51
|
+
r.POST("/users", createUser)
|
|
52
|
+
return r
|
|
53
|
+
}
|
|
54
|
+
`;
|
|
55
|
+
|
|
56
|
+
const tools = await extractor.extract(code, 'router.go');
|
|
57
|
+
|
|
58
|
+
expect(tools.length).toBeGreaterThan(0);
|
|
59
|
+
expect(tools.some(t => t.name.includes('post_users'))).toBe(true);
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
it('should extract multiple HTTP methods', async () => {
|
|
63
|
+
const code = `
|
|
64
|
+
package handlers
|
|
65
|
+
|
|
66
|
+
import "github.com/gin-gonic/gin"
|
|
67
|
+
|
|
68
|
+
func RegisterRoutes(r *gin.Engine) {
|
|
69
|
+
r.GET("/items", listItems)
|
|
70
|
+
r.POST("/items", createItem)
|
|
71
|
+
r.PUT("/items/:id", updateItem)
|
|
72
|
+
r.DELETE("/items/:id", deleteItem)
|
|
73
|
+
}
|
|
74
|
+
`;
|
|
75
|
+
|
|
76
|
+
const tools = await extractor.extract(code, 'routes.go');
|
|
77
|
+
|
|
78
|
+
expect(tools.length).toBe(4);
|
|
79
|
+
expect(tools.some(t => t.name.includes('get'))).toBe(true);
|
|
80
|
+
expect(tools.some(t => t.name.includes('post'))).toBe(true);
|
|
81
|
+
expect(tools.some(t => t.name.includes('put'))).toBe(true);
|
|
82
|
+
expect(tools.some(t => t.name.includes('delete'))).toBe(true);
|
|
83
|
+
});
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
describe('Echo routes', () => {
|
|
87
|
+
it('should extract Echo routes', async () => {
|
|
88
|
+
const code = `
|
|
89
|
+
package main
|
|
90
|
+
|
|
91
|
+
import "github.com/labstack/echo/v4"
|
|
92
|
+
|
|
93
|
+
func main() {
|
|
94
|
+
e := echo.New()
|
|
95
|
+
e.GET("/health", healthCheck)
|
|
96
|
+
e.POST("/api/data", handleData)
|
|
97
|
+
e.Start(":8080")
|
|
98
|
+
}
|
|
99
|
+
`;
|
|
100
|
+
|
|
101
|
+
const tools = await extractor.extract(code, 'main.go');
|
|
102
|
+
|
|
103
|
+
expect(tools.length).toBeGreaterThan(0);
|
|
104
|
+
expect(tools.some(t => t.name.includes('health'))).toBe(true);
|
|
105
|
+
expect(tools.some(t => t.name.includes('api_data'))).toBe(true);
|
|
106
|
+
});
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
describe('Chi routes', () => {
|
|
110
|
+
it('should extract Chi routes', async () => {
|
|
111
|
+
const code = `
|
|
112
|
+
package main
|
|
113
|
+
|
|
114
|
+
import "github.com/go-chi/chi/v5"
|
|
115
|
+
|
|
116
|
+
func main() {
|
|
117
|
+
r := chi.NewRouter()
|
|
118
|
+
r.Get("/users/{userID}", getUser)
|
|
119
|
+
r.Post("/users", createUser)
|
|
120
|
+
http.ListenAndServe(":3000", r)
|
|
121
|
+
}
|
|
122
|
+
`;
|
|
123
|
+
|
|
124
|
+
const tools = await extractor.extract(code, 'main.go');
|
|
125
|
+
|
|
126
|
+
expect(tools.length).toBeGreaterThan(0);
|
|
127
|
+
expect(tools.some(t => t.name.includes('users'))).toBe(true);
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
it('should extract Chi path parameters with braces', async () => {
|
|
131
|
+
const code = `
|
|
132
|
+
package main
|
|
133
|
+
|
|
134
|
+
import "github.com/go-chi/chi/v5"
|
|
135
|
+
|
|
136
|
+
func SetupRoutes(r chi.Router) {
|
|
137
|
+
r.Get("/posts/{postID}/comments/{commentID}", getComment)
|
|
138
|
+
}
|
|
139
|
+
`;
|
|
140
|
+
|
|
141
|
+
const tools = await extractor.extract(code, 'routes.go');
|
|
142
|
+
|
|
143
|
+
// Chi routes should be extracted
|
|
144
|
+
const tool = tools.find(t => t.name.includes('posts') && t.name.includes('comments'));
|
|
145
|
+
expect(tool).toBeDefined();
|
|
146
|
+
expect(tool?.description).toContain('/posts/{postID}/comments/{commentID}');
|
|
147
|
+
|
|
148
|
+
// Note: Path parameter extraction from Chi routes is partially implemented
|
|
149
|
+
// The schema building works but may need refinement for complex cases
|
|
150
|
+
});
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
describe('Fiber routes', () => {
|
|
154
|
+
it('should extract Fiber routes', async () => {
|
|
155
|
+
const code = `
|
|
156
|
+
package main
|
|
157
|
+
|
|
158
|
+
import "github.com/gofiber/fiber/v2"
|
|
159
|
+
|
|
160
|
+
func main() {
|
|
161
|
+
app := fiber.New()
|
|
162
|
+
app.Get("/api/users", getUsers)
|
|
163
|
+
app.Post("/api/users", createUser)
|
|
164
|
+
app.Listen(":3000")
|
|
165
|
+
}
|
|
166
|
+
`;
|
|
167
|
+
|
|
168
|
+
const tools = await extractor.extract(code, 'main.go');
|
|
169
|
+
|
|
170
|
+
expect(tools.length).toBeGreaterThan(0);
|
|
171
|
+
expect(tools.some(t => t.name.includes('api_users'))).toBe(true);
|
|
172
|
+
});
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
describe('Gorilla mux routes', () => {
|
|
176
|
+
it('should extract Gorilla mux routes', async () => {
|
|
177
|
+
const code = `
|
|
178
|
+
package main
|
|
179
|
+
|
|
180
|
+
import "github.com/gorilla/mux"
|
|
181
|
+
|
|
182
|
+
func main() {
|
|
183
|
+
r := mux.NewRouter()
|
|
184
|
+
r.HandleFunc("/articles", getArticles).Methods("GET")
|
|
185
|
+
r.HandleFunc("/articles", createArticle).Methods("POST")
|
|
186
|
+
http.ListenAndServe(":8000", r)
|
|
187
|
+
}
|
|
188
|
+
`;
|
|
189
|
+
|
|
190
|
+
const tools = await extractor.extract(code, 'main.go');
|
|
191
|
+
|
|
192
|
+
expect(tools.length).toBeGreaterThan(0);
|
|
193
|
+
expect(tools.some(t => t.name.includes('get'))).toBe(true);
|
|
194
|
+
expect(tools.some(t => t.name.includes('post'))).toBe(true);
|
|
195
|
+
});
|
|
196
|
+
});
|
|
197
|
+
|
|
198
|
+
describe('net/http handlers', () => {
|
|
199
|
+
it('should extract http.HandleFunc', async () => {
|
|
200
|
+
const code = `
|
|
201
|
+
package main
|
|
202
|
+
|
|
203
|
+
import "net/http"
|
|
204
|
+
|
|
205
|
+
func main() {
|
|
206
|
+
http.HandleFunc("/hello", helloHandler)
|
|
207
|
+
http.ListenAndServe(":8080", nil)
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
func helloHandler(w http.ResponseWriter, r *http.Request) {
|
|
211
|
+
w.Write([]byte("Hello, World!"))
|
|
212
|
+
}
|
|
213
|
+
`;
|
|
214
|
+
|
|
215
|
+
const tools = await extractor.extract(code, 'main.go');
|
|
216
|
+
|
|
217
|
+
expect(tools.length).toBeGreaterThan(0);
|
|
218
|
+
expect(tools.some(t => t.name.includes('hello'))).toBe(true);
|
|
219
|
+
});
|
|
220
|
+
});
|
|
221
|
+
|
|
222
|
+
describe('Exported functions', () => {
|
|
223
|
+
it('should extract exported functions with documentation', async () => {
|
|
224
|
+
const code = `
|
|
225
|
+
package math
|
|
226
|
+
|
|
227
|
+
// Add returns the sum of two integers.
|
|
228
|
+
// It handles both positive and negative numbers.
|
|
229
|
+
func Add(a, b int) int {
|
|
230
|
+
return a + b
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
// subtract is not exported
|
|
234
|
+
func subtract(a, b int) int {
|
|
235
|
+
return a - b
|
|
236
|
+
}
|
|
237
|
+
`;
|
|
238
|
+
|
|
239
|
+
const tools = await extractor.extract(code, 'math.go');
|
|
240
|
+
|
|
241
|
+
// Should have the exported function
|
|
242
|
+
expect(tools.some(t => t.name === 'Add')).toBe(true);
|
|
243
|
+
// Should not have unexported function
|
|
244
|
+
expect(tools.every(t => t.name !== 'subtract')).toBe(true);
|
|
245
|
+
});
|
|
246
|
+
|
|
247
|
+
it('should extract functions with receiver', async () => {
|
|
248
|
+
const code = `
|
|
249
|
+
package user
|
|
250
|
+
|
|
251
|
+
// GetName returns the user's full name.
|
|
252
|
+
func (u *User) GetName() string {
|
|
253
|
+
return u.FirstName + " " + u.LastName
|
|
254
|
+
}
|
|
255
|
+
`;
|
|
256
|
+
|
|
257
|
+
const tools = await extractor.extract(code, 'user.go');
|
|
258
|
+
|
|
259
|
+
// Method extraction depends on whether it has doc comments
|
|
260
|
+
expect(tools.length).toBeGreaterThanOrEqual(0);
|
|
261
|
+
});
|
|
262
|
+
|
|
263
|
+
it('should skip HTTP handlers in exported functions', async () => {
|
|
264
|
+
const code = `
|
|
265
|
+
package handlers
|
|
266
|
+
|
|
267
|
+
import "net/http"
|
|
268
|
+
|
|
269
|
+
// GetUsers returns all users.
|
|
270
|
+
func GetUsers(w http.ResponseWriter, r *http.Request) {
|
|
271
|
+
// Handler
|
|
272
|
+
}
|
|
273
|
+
`;
|
|
274
|
+
|
|
275
|
+
const tools = await extractor.extract(code, 'handlers.go');
|
|
276
|
+
|
|
277
|
+
// HTTP handlers should not be duplicated as regular functions
|
|
278
|
+
const getUsersTools = tools.filter(t => t.name === 'GetUsers');
|
|
279
|
+
expect(getUsersTools.length).toBeLessThanOrEqual(1);
|
|
280
|
+
});
|
|
281
|
+
});
|
|
282
|
+
|
|
283
|
+
describe('Type conversion', () => {
|
|
284
|
+
it('should convert Go types to JSON schema types', async () => {
|
|
285
|
+
const code = `
|
|
286
|
+
package api
|
|
287
|
+
|
|
288
|
+
// Process handles various data types.
|
|
289
|
+
func Process(
|
|
290
|
+
name string,
|
|
291
|
+
count int,
|
|
292
|
+
enabled bool,
|
|
293
|
+
items []string,
|
|
294
|
+
config map[string]interface{},
|
|
295
|
+
) error {
|
|
296
|
+
return nil
|
|
297
|
+
}
|
|
298
|
+
`;
|
|
299
|
+
|
|
300
|
+
const tools = await extractor.extract(code, 'api.go');
|
|
301
|
+
|
|
302
|
+
const tool = tools.find(t => t.name === 'Process');
|
|
303
|
+
if (tool) {
|
|
304
|
+
expect(tool.inputSchema.properties.name?.type).toBe('string');
|
|
305
|
+
expect(tool.inputSchema.properties.count?.type).toBe('integer');
|
|
306
|
+
expect(tool.inputSchema.properties.enabled?.type).toBe('boolean');
|
|
307
|
+
expect(tool.inputSchema.properties.items?.type).toBe('array');
|
|
308
|
+
expect(tool.inputSchema.properties.config?.type).toBe('object');
|
|
309
|
+
}
|
|
310
|
+
});
|
|
311
|
+
|
|
312
|
+
it('should handle pointer types', async () => {
|
|
313
|
+
const code = `
|
|
314
|
+
package service
|
|
315
|
+
|
|
316
|
+
// UpdateUser updates a user's data.
|
|
317
|
+
func UpdateUser(id string, data *UpdateData) error {
|
|
318
|
+
return nil
|
|
319
|
+
}
|
|
320
|
+
`;
|
|
321
|
+
|
|
322
|
+
const tools = await extractor.extract(code, 'service.go');
|
|
323
|
+
|
|
324
|
+
const tool = tools.find(t => t.name === 'UpdateUser');
|
|
325
|
+
// Pointer types should be treated as optional (not required)
|
|
326
|
+
if (tool) {
|
|
327
|
+
expect(tool.inputSchema.required).toContain('id');
|
|
328
|
+
}
|
|
329
|
+
});
|
|
330
|
+
});
|
|
331
|
+
|
|
332
|
+
describe('Documentation parsing', () => {
|
|
333
|
+
it('should parse function documentation', async () => {
|
|
334
|
+
const code = `
|
|
335
|
+
package utils
|
|
336
|
+
|
|
337
|
+
// FormatDate formats a date according to the given layout.
|
|
338
|
+
// It uses the standard Go time format.
|
|
339
|
+
func FormatDate(date string, layout string) string {
|
|
340
|
+
return ""
|
|
341
|
+
}
|
|
342
|
+
`;
|
|
343
|
+
|
|
344
|
+
const tools = await extractor.extract(code, 'utils.go');
|
|
345
|
+
|
|
346
|
+
const tool = tools.find(t => t.name === 'FormatDate');
|
|
347
|
+
expect(tool?.description).toContain('format');
|
|
348
|
+
});
|
|
349
|
+
});
|
|
350
|
+
});
|
|
351
|
+
});
|
|
@@ -0,0 +1,330 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Unit tests for graphql-extractor module
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { describe, it, expect, beforeEach } from 'vitest';
|
|
6
|
+
import { GraphQLExtractor } from '../graphql-extractor';
|
|
7
|
+
|
|
8
|
+
describe('GraphQLExtractor', () => {
|
|
9
|
+
let extractor: GraphQLExtractor;
|
|
10
|
+
|
|
11
|
+
beforeEach(() => {
|
|
12
|
+
extractor = new GraphQLExtractor();
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
describe('parseSchema', () => {
|
|
16
|
+
it('should parse simple Query type', () => {
|
|
17
|
+
const schema = `
|
|
18
|
+
type Query {
|
|
19
|
+
user(id: ID!): User
|
|
20
|
+
users: [User!]!
|
|
21
|
+
}
|
|
22
|
+
`;
|
|
23
|
+
|
|
24
|
+
const result = extractor.parseSchema(schema);
|
|
25
|
+
|
|
26
|
+
expect(result.queries).toHaveLength(2);
|
|
27
|
+
expect(result.queries[0].name).toBe('user');
|
|
28
|
+
expect(result.queries[0].args).toHaveLength(1);
|
|
29
|
+
expect(result.queries[0].args[0].name).toBe('id');
|
|
30
|
+
expect(result.queries[0].args[0].required).toBe(true);
|
|
31
|
+
expect(result.queries[1].name).toBe('users');
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
it('should parse Mutation type', () => {
|
|
35
|
+
const schema = `
|
|
36
|
+
type Mutation {
|
|
37
|
+
createUser(name: String!, email: String!): User!
|
|
38
|
+
deleteUser(id: ID!): Boolean!
|
|
39
|
+
}
|
|
40
|
+
`;
|
|
41
|
+
|
|
42
|
+
const result = extractor.parseSchema(schema);
|
|
43
|
+
|
|
44
|
+
expect(result.mutations).toHaveLength(2);
|
|
45
|
+
expect(result.mutations[0].name).toBe('createUser');
|
|
46
|
+
expect(result.mutations[0].args).toHaveLength(2);
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
it('should parse Subscription type', () => {
|
|
50
|
+
const schema = `
|
|
51
|
+
type Subscription {
|
|
52
|
+
userUpdated(id: ID!): User
|
|
53
|
+
}
|
|
54
|
+
`;
|
|
55
|
+
|
|
56
|
+
const result = extractor.parseSchema(schema);
|
|
57
|
+
|
|
58
|
+
expect(result.subscriptions).toHaveLength(1);
|
|
59
|
+
expect(result.subscriptions[0].name).toBe('userUpdated');
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
it('should parse custom types', () => {
|
|
63
|
+
const schema = `
|
|
64
|
+
type User {
|
|
65
|
+
id: ID!
|
|
66
|
+
name: String!
|
|
67
|
+
email: String
|
|
68
|
+
posts: [Post!]!
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
type Post {
|
|
72
|
+
id: ID!
|
|
73
|
+
title: String!
|
|
74
|
+
content: String
|
|
75
|
+
}
|
|
76
|
+
`;
|
|
77
|
+
|
|
78
|
+
const result = extractor.parseSchema(schema);
|
|
79
|
+
|
|
80
|
+
expect(result.types['User']).toBeDefined();
|
|
81
|
+
expect(result.types['User'].kind).toBe('object');
|
|
82
|
+
expect(result.types['User'].fields).toHaveLength(4);
|
|
83
|
+
expect(result.types['Post']).toBeDefined();
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
it('should parse input types', () => {
|
|
87
|
+
const schema = `
|
|
88
|
+
input CreateUserInput {
|
|
89
|
+
name: String!
|
|
90
|
+
email: String!
|
|
91
|
+
role: UserRole
|
|
92
|
+
}
|
|
93
|
+
`;
|
|
94
|
+
|
|
95
|
+
const result = extractor.parseSchema(schema);
|
|
96
|
+
|
|
97
|
+
expect(result.types['CreateUserInput']).toBeDefined();
|
|
98
|
+
expect(result.types['CreateUserInput'].kind).toBe('input');
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
it('should parse enum types', () => {
|
|
102
|
+
const schema = `
|
|
103
|
+
enum UserRole {
|
|
104
|
+
ADMIN
|
|
105
|
+
USER
|
|
106
|
+
GUEST
|
|
107
|
+
}
|
|
108
|
+
`;
|
|
109
|
+
|
|
110
|
+
const result = extractor.parseSchema(schema);
|
|
111
|
+
|
|
112
|
+
expect(result.types['UserRole']).toBeDefined();
|
|
113
|
+
expect(result.types['UserRole'].kind).toBe('enum');
|
|
114
|
+
expect(result.types['UserRole'].values).toContain('ADMIN');
|
|
115
|
+
expect(result.types['UserRole'].values).toContain('USER');
|
|
116
|
+
expect(result.types['UserRole'].values).toContain('GUEST');
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
it('should parse comments as descriptions', () => {
|
|
120
|
+
const schema = `
|
|
121
|
+
type Query {
|
|
122
|
+
# Get a single user by ID
|
|
123
|
+
user(id: ID!): User
|
|
124
|
+
}
|
|
125
|
+
`;
|
|
126
|
+
|
|
127
|
+
const result = extractor.parseSchema(schema);
|
|
128
|
+
|
|
129
|
+
expect(result.queries[0].description).toContain('Get a single user');
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
it('should handle optional arguments', () => {
|
|
133
|
+
const schema = `
|
|
134
|
+
type Query {
|
|
135
|
+
users(limit: Int, offset: Int): [User!]!
|
|
136
|
+
}
|
|
137
|
+
`;
|
|
138
|
+
|
|
139
|
+
const result = extractor.parseSchema(schema);
|
|
140
|
+
|
|
141
|
+
expect(result.queries[0].args[0].required).toBe(false);
|
|
142
|
+
expect(result.queries[0].args[1].required).toBe(false);
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
it('should handle array types in arguments', () => {
|
|
146
|
+
const schema = `
|
|
147
|
+
type Query {
|
|
148
|
+
usersByIds(ids: [ID!]!): [User!]!
|
|
149
|
+
}
|
|
150
|
+
`;
|
|
151
|
+
|
|
152
|
+
const result = extractor.parseSchema(schema);
|
|
153
|
+
|
|
154
|
+
expect(result.queries[0].args[0].type).toContain('ID');
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
it('should handle empty schema', () => {
|
|
158
|
+
const result = extractor.parseSchema('');
|
|
159
|
+
|
|
160
|
+
expect(result.queries).toEqual([]);
|
|
161
|
+
expect(result.mutations).toEqual([]);
|
|
162
|
+
expect(result.subscriptions).toEqual([]);
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
it('should parse implements keyword', () => {
|
|
166
|
+
const schema = `
|
|
167
|
+
type User implements Node {
|
|
168
|
+
id: ID!
|
|
169
|
+
name: String!
|
|
170
|
+
}
|
|
171
|
+
`;
|
|
172
|
+
|
|
173
|
+
const result = extractor.parseSchema(schema);
|
|
174
|
+
|
|
175
|
+
expect(result.types['User']).toBeDefined();
|
|
176
|
+
expect(result.types['User'].fields).toHaveLength(2);
|
|
177
|
+
});
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
describe('schemaToTools', () => {
|
|
181
|
+
it('should convert queries to MCP tools', () => {
|
|
182
|
+
const schema = `
|
|
183
|
+
type Query {
|
|
184
|
+
user(id: ID!): User
|
|
185
|
+
users(limit: Int): [User!]!
|
|
186
|
+
}
|
|
187
|
+
`;
|
|
188
|
+
|
|
189
|
+
const parsed = extractor.parseSchema(schema);
|
|
190
|
+
const tools = extractor.schemaToTools(parsed, 'https://api.example.com/graphql', 'owner', 'repo');
|
|
191
|
+
|
|
192
|
+
expect(tools).toHaveLength(2);
|
|
193
|
+
expect(tools[0].name).toBe('graphql_user');
|
|
194
|
+
expect(tools[1].name).toBe('graphql_users');
|
|
195
|
+
});
|
|
196
|
+
|
|
197
|
+
it('should convert mutations to MCP tools', () => {
|
|
198
|
+
const schema = `
|
|
199
|
+
type Mutation {
|
|
200
|
+
createUser(name: String!, email: String!): User!
|
|
201
|
+
}
|
|
202
|
+
`;
|
|
203
|
+
|
|
204
|
+
const parsed = extractor.parseSchema(schema);
|
|
205
|
+
const tools = extractor.schemaToTools(parsed, 'https://api.example.com/graphql', 'owner', 'repo');
|
|
206
|
+
|
|
207
|
+
expect(tools).toHaveLength(1);
|
|
208
|
+
expect(tools[0].name).toBe('graphql_createUser');
|
|
209
|
+
expect(tools[0].inputSchema.required).toContain('name');
|
|
210
|
+
expect(tools[0].inputSchema.required).toContain('email');
|
|
211
|
+
});
|
|
212
|
+
|
|
213
|
+
it('should generate implementation code', () => {
|
|
214
|
+
const schema = `
|
|
215
|
+
type Query {
|
|
216
|
+
user(id: ID!): User
|
|
217
|
+
}
|
|
218
|
+
`;
|
|
219
|
+
|
|
220
|
+
const parsed = extractor.parseSchema(schema);
|
|
221
|
+
const tools = extractor.schemaToTools(parsed, 'https://api.example.com/graphql', 'owner', 'repo');
|
|
222
|
+
|
|
223
|
+
expect(tools[0].implementation).toBeDefined();
|
|
224
|
+
expect(tools[0].implementation).toContain('fetch');
|
|
225
|
+
expect(tools[0].implementation).toContain('graphql');
|
|
226
|
+
});
|
|
227
|
+
|
|
228
|
+
it('should set correct source information', () => {
|
|
229
|
+
const schema = `
|
|
230
|
+
type Query {
|
|
231
|
+
user(id: ID!): User
|
|
232
|
+
}
|
|
233
|
+
`;
|
|
234
|
+
|
|
235
|
+
const parsed = extractor.parseSchema(schema);
|
|
236
|
+
const tools = extractor.schemaToTools(parsed, 'https://api.example.com/graphql', 'owner', 'repo');
|
|
237
|
+
|
|
238
|
+
expect(tools[0].source.type).toBe('graphql');
|
|
239
|
+
expect(tools[0].source.file).toContain('owner/repo');
|
|
240
|
+
});
|
|
241
|
+
|
|
242
|
+
it('should map GraphQL types to JSON schema types', () => {
|
|
243
|
+
const schema = `
|
|
244
|
+
type Query {
|
|
245
|
+
test(
|
|
246
|
+
str: String!,
|
|
247
|
+
num: Int!,
|
|
248
|
+
float: Float!,
|
|
249
|
+
bool: Boolean!,
|
|
250
|
+
id: ID!,
|
|
251
|
+
list: [String!]!
|
|
252
|
+
): Result
|
|
253
|
+
}
|
|
254
|
+
`;
|
|
255
|
+
|
|
256
|
+
const parsed = extractor.parseSchema(schema);
|
|
257
|
+
const tools = extractor.schemaToTools(parsed, 'https://api.example.com/graphql', 'owner', 'repo');
|
|
258
|
+
|
|
259
|
+
const { properties } = tools[0].inputSchema;
|
|
260
|
+
expect(properties.str.type).toBe('string');
|
|
261
|
+
expect(properties.num.type).toBe('integer');
|
|
262
|
+
expect(properties.float.type).toBe('number');
|
|
263
|
+
expect(properties.bool.type).toBe('boolean');
|
|
264
|
+
expect(properties.id.type).toBe('string');
|
|
265
|
+
expect(properties.list.type).toBe('array');
|
|
266
|
+
});
|
|
267
|
+
});
|
|
268
|
+
|
|
269
|
+
describe('complex schemas', () => {
|
|
270
|
+
it('should parse complete schema with all types', () => {
|
|
271
|
+
const schema = `
|
|
272
|
+
type Query {
|
|
273
|
+
user(id: ID!): User
|
|
274
|
+
users(limit: Int, offset: Int): [User!]!
|
|
275
|
+
searchUsers(query: String!): [User!]!
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
type Mutation {
|
|
279
|
+
createUser(input: CreateUserInput!): User!
|
|
280
|
+
updateUser(id: ID!, input: UpdateUserInput!): User
|
|
281
|
+
deleteUser(id: ID!): Boolean!
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
type Subscription {
|
|
285
|
+
userUpdated(id: ID!): User
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
type User {
|
|
289
|
+
id: ID!
|
|
290
|
+
name: String!
|
|
291
|
+
email: String!
|
|
292
|
+
role: UserRole!
|
|
293
|
+
posts: [Post!]!
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
type Post {
|
|
297
|
+
id: ID!
|
|
298
|
+
title: String!
|
|
299
|
+
author: User!
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
enum UserRole {
|
|
303
|
+
ADMIN
|
|
304
|
+
USER
|
|
305
|
+
GUEST
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
input CreateUserInput {
|
|
309
|
+
name: String!
|
|
310
|
+
email: String!
|
|
311
|
+
role: UserRole
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
input UpdateUserInput {
|
|
315
|
+
name: String
|
|
316
|
+
email: String
|
|
317
|
+
role: UserRole
|
|
318
|
+
}
|
|
319
|
+
`;
|
|
320
|
+
|
|
321
|
+
const result = extractor.parseSchema(schema);
|
|
322
|
+
|
|
323
|
+
expect(result.queries).toHaveLength(3);
|
|
324
|
+
expect(result.mutations).toHaveLength(3);
|
|
325
|
+
expect(result.subscriptions).toHaveLength(1);
|
|
326
|
+
// Types: User, Post, UserRole (enum), CreateUserInput, UpdateUserInput = 5
|
|
327
|
+
expect(Object.keys(result.types)).toHaveLength(5);
|
|
328
|
+
});
|
|
329
|
+
});
|
|
330
|
+
});
|