codesift-mcp 0.3.0 → 0.5.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/README.md +215 -23
- package/dist/cache/hono-cache.d.ts +50 -0
- package/dist/cache/hono-cache.d.ts.map +1 -0
- package/dist/cache/hono-cache.js +132 -0
- package/dist/cache/hono-cache.js.map +1 -0
- package/dist/cli/help.d.ts.map +1 -1
- package/dist/cli/help.js +8 -6
- package/dist/cli/help.js.map +1 -1
- package/dist/cli/platform.d.ts.map +1 -1
- package/dist/cli/platform.js +12 -14
- package/dist/cli/platform.js.map +1 -1
- package/dist/cli/setup.d.ts +1 -1
- package/dist/cli/setup.d.ts.map +1 -1
- package/dist/cli/setup.js +27 -3
- package/dist/cli/setup.js.map +1 -1
- package/dist/formatters-shortening.d.ts +13 -0
- package/dist/formatters-shortening.d.ts.map +1 -1
- package/dist/formatters-shortening.js +131 -0
- package/dist/formatters-shortening.js.map +1 -1
- package/dist/formatters.d.ts +38 -0
- package/dist/formatters.d.ts.map +1 -1
- package/dist/formatters.js +521 -0
- package/dist/formatters.js.map +1 -1
- package/dist/instructions.d.ts +1 -1
- package/dist/instructions.d.ts.map +1 -1
- package/dist/instructions.js +39 -38
- package/dist/instructions.js.map +1 -1
- package/dist/lsp/lsp-servers.d.ts.map +1 -1
- package/dist/lsp/lsp-servers.js +5 -0
- package/dist/lsp/lsp-servers.js.map +1 -1
- package/dist/lsp/lsp-tools.d.ts.map +1 -1
- package/dist/lsp/lsp-tools.js +1 -0
- package/dist/lsp/lsp-tools.js.map +1 -1
- package/dist/parser/astro-template.d.ts +47 -0
- package/dist/parser/astro-template.d.ts.map +1 -0
- package/dist/parser/astro-template.js +171 -0
- package/dist/parser/astro-template.js.map +1 -0
- package/dist/parser/extractors/_shared.d.ts +4 -0
- package/dist/parser/extractors/_shared.d.ts.map +1 -1
- package/dist/parser/extractors/_shared.js +8 -0
- package/dist/parser/extractors/_shared.js.map +1 -1
- package/dist/parser/extractors/astro.d.ts +4 -5
- package/dist/parser/extractors/astro.d.ts.map +1 -1
- package/dist/parser/extractors/astro.js +102 -26
- package/dist/parser/extractors/astro.js.map +1 -1
- package/dist/parser/extractors/gradle-kts.d.ts +4 -0
- package/dist/parser/extractors/gradle-kts.d.ts.map +1 -0
- package/dist/parser/extractors/gradle-kts.js +246 -0
- package/dist/parser/extractors/gradle-kts.js.map +1 -0
- package/dist/parser/extractors/hono-inline-analyzer.d.ts +34 -0
- package/dist/parser/extractors/hono-inline-analyzer.d.ts.map +1 -0
- package/dist/parser/extractors/hono-inline-analyzer.js +465 -0
- package/dist/parser/extractors/hono-inline-analyzer.js.map +1 -0
- package/dist/parser/extractors/hono-model.d.ts +196 -0
- package/dist/parser/extractors/hono-model.d.ts.map +1 -0
- package/dist/parser/extractors/hono-model.js +10 -0
- package/dist/parser/extractors/hono-model.js.map +1 -0
- package/dist/parser/extractors/hono.d.ts +118 -0
- package/dist/parser/extractors/hono.d.ts.map +1 -0
- package/dist/parser/extractors/hono.js +1527 -0
- package/dist/parser/extractors/hono.js.map +1 -0
- package/dist/parser/extractors/kotlin.d.ts +4 -0
- package/dist/parser/extractors/kotlin.d.ts.map +1 -0
- package/dist/parser/extractors/kotlin.js +521 -0
- package/dist/parser/extractors/kotlin.js.map +1 -0
- package/dist/parser/extractors/php.d.ts +22 -0
- package/dist/parser/extractors/php.d.ts.map +1 -0
- package/dist/parser/extractors/php.js +334 -0
- package/dist/parser/extractors/php.js.map +1 -0
- package/dist/parser/extractors/python.d.ts.map +1 -1
- package/dist/parser/extractors/python.js +234 -11
- package/dist/parser/extractors/python.js.map +1 -1
- package/dist/parser/extractors/sql.d.ts +33 -0
- package/dist/parser/extractors/sql.d.ts.map +1 -0
- package/dist/parser/extractors/sql.js +506 -0
- package/dist/parser/extractors/sql.js.map +1 -0
- package/dist/parser/extractors/typescript.d.ts.map +1 -1
- package/dist/parser/extractors/typescript.js +209 -3
- package/dist/parser/extractors/typescript.js.map +1 -1
- package/dist/parser/languages/tree-sitter-javascript.wasm +0 -0
- package/dist/parser/languages/tree-sitter-kotlin.wasm +0 -0
- package/dist/parser/languages/tree-sitter-php.wasm +0 -0
- package/dist/parser/languages/tree-sitter-php_only.wasm +0 -0
- package/dist/parser/languages/tree-sitter-python.wasm +0 -0
- package/dist/parser/parse-cache.d.ts +39 -0
- package/dist/parser/parse-cache.d.ts.map +1 -0
- package/dist/parser/parse-cache.js +87 -0
- package/dist/parser/parse-cache.js.map +1 -0
- package/dist/parser/parser-manager.d.ts +32 -0
- package/dist/parser/parser-manager.d.ts.map +1 -1
- package/dist/parser/parser-manager.js +93 -3
- package/dist/parser/parser-manager.js.map +1 -1
- package/dist/parser/symbol-extractor.d.ts.map +1 -1
- package/dist/parser/symbol-extractor.js +16 -0
- package/dist/parser/symbol-extractor.js.map +1 -1
- package/dist/register-tools.d.ts +38 -2
- package/dist/register-tools.d.ts.map +1 -1
- package/dist/register-tools.js +2444 -195
- package/dist/register-tools.js.map +1 -1
- package/dist/search/reranker.js +1 -1
- package/dist/search/reranker.js.map +1 -1
- package/dist/search/tool-ranker.d.ts +90 -0
- package/dist/search/tool-ranker.d.ts.map +1 -0
- package/dist/search/tool-ranker.js +420 -0
- package/dist/search/tool-ranker.js.map +1 -0
- package/dist/server-helpers.d.ts.map +1 -1
- package/dist/server-helpers.js +11 -0
- package/dist/server-helpers.js.map +1 -1
- package/dist/server.js +47 -14
- package/dist/server.js.map +1 -1
- package/dist/storage/index-store.d.ts +15 -1
- package/dist/storage/index-store.d.ts.map +1 -1
- package/dist/storage/index-store.js +27 -1
- package/dist/storage/index-store.js.map +1 -1
- package/dist/storage/session-state.d.ts +1 -1
- package/dist/storage/session-state.d.ts.map +1 -1
- package/dist/storage/session-state.js +6 -4
- package/dist/storage/session-state.js.map +1 -1
- package/dist/storage/usage-tracker.d.ts.map +1 -1
- package/dist/storage/usage-tracker.js +4 -1
- package/dist/storage/usage-tracker.js.map +1 -1
- package/dist/tools/agent-config-tools.d.ts +24 -0
- package/dist/tools/agent-config-tools.d.ts.map +1 -0
- package/dist/tools/agent-config-tools.js +119 -0
- package/dist/tools/agent-config-tools.js.map +1 -0
- package/dist/tools/architecture-tools.d.ts +23 -0
- package/dist/tools/architecture-tools.d.ts.map +1 -0
- package/dist/tools/architecture-tools.js +140 -0
- package/dist/tools/architecture-tools.js.map +1 -0
- package/dist/tools/astro-actions.d.ts +54 -0
- package/dist/tools/astro-actions.d.ts.map +1 -0
- package/dist/tools/astro-actions.js +561 -0
- package/dist/tools/astro-actions.js.map +1 -0
- package/dist/tools/astro-audit.d.ts +87 -0
- package/dist/tools/astro-audit.d.ts.map +1 -0
- package/dist/tools/astro-audit.js +345 -0
- package/dist/tools/astro-audit.js.map +1 -0
- package/dist/tools/astro-config.d.ts +33 -0
- package/dist/tools/astro-config.d.ts.map +1 -0
- package/dist/tools/astro-config.js +260 -0
- package/dist/tools/astro-config.js.map +1 -0
- package/dist/tools/astro-content-collections.d.ts +44 -0
- package/dist/tools/astro-content-collections.d.ts.map +1 -0
- package/dist/tools/astro-content-collections.js +630 -0
- package/dist/tools/astro-content-collections.js.map +1 -0
- package/dist/tools/astro-islands.d.ts +63 -0
- package/dist/tools/astro-islands.d.ts.map +1 -0
- package/dist/tools/astro-islands.js +255 -0
- package/dist/tools/astro-islands.js.map +1 -0
- package/dist/tools/astro-migration.d.ts +31 -0
- package/dist/tools/astro-migration.d.ts.map +1 -0
- package/dist/tools/astro-migration.js +378 -0
- package/dist/tools/astro-migration.js.map +1 -0
- package/dist/tools/astro-routes.d.ts +49 -0
- package/dist/tools/astro-routes.d.ts.map +1 -0
- package/dist/tools/astro-routes.js +119 -0
- package/dist/tools/astro-routes.js.map +1 -0
- package/dist/tools/async-correctness.d.ts +26 -0
- package/dist/tools/async-correctness.d.ts.map +1 -0
- package/dist/tools/async-correctness.js +166 -0
- package/dist/tools/async-correctness.js.map +1 -0
- package/dist/tools/audit-tools.d.ts +38 -0
- package/dist/tools/audit-tools.d.ts.map +1 -0
- package/dist/tools/audit-tools.js +248 -0
- package/dist/tools/audit-tools.js.map +1 -0
- package/dist/tools/celery-tools.d.ts +38 -0
- package/dist/tools/celery-tools.d.ts.map +1 -0
- package/dist/tools/celery-tools.js +154 -0
- package/dist/tools/celery-tools.js.map +1 -0
- package/dist/tools/clone-tools.js +1 -1
- package/dist/tools/clone-tools.js.map +1 -1
- package/dist/tools/complexity-tools.d.ts +4 -0
- package/dist/tools/complexity-tools.d.ts.map +1 -1
- package/dist/tools/complexity-tools.js +78 -4
- package/dist/tools/complexity-tools.js.map +1 -1
- package/dist/tools/compose-tools.d.ts +60 -0
- package/dist/tools/compose-tools.d.ts.map +1 -0
- package/dist/tools/compose-tools.js +203 -0
- package/dist/tools/compose-tools.js.map +1 -0
- package/dist/tools/coupling-tools.d.ts +50 -0
- package/dist/tools/coupling-tools.d.ts.map +1 -0
- package/dist/tools/coupling-tools.js +262 -0
- package/dist/tools/coupling-tools.js.map +1 -0
- package/dist/tools/dependency-audit-tools.d.ts +65 -0
- package/dist/tools/dependency-audit-tools.d.ts.map +1 -0
- package/dist/tools/dependency-audit-tools.js +553 -0
- package/dist/tools/dependency-audit-tools.js.map +1 -0
- package/dist/tools/django-settings.d.ts +22 -0
- package/dist/tools/django-settings.d.ts.map +1 -0
- package/dist/tools/django-settings.js +301 -0
- package/dist/tools/django-settings.js.map +1 -0
- package/dist/tools/django-view-security-tools.d.ts +32 -0
- package/dist/tools/django-view-security-tools.d.ts.map +1 -0
- package/dist/tools/django-view-security-tools.js +184 -0
- package/dist/tools/django-view-security-tools.js.map +1 -0
- package/dist/tools/fastapi-depends.d.ts +63 -0
- package/dist/tools/fastapi-depends.d.ts.map +1 -0
- package/dist/tools/fastapi-depends.js +191 -0
- package/dist/tools/fastapi-depends.js.map +1 -0
- package/dist/tools/frequency-tools.js +1 -1
- package/dist/tools/frequency-tools.js.map +1 -1
- package/dist/tools/graph-tools.d.ts +8 -2
- package/dist/tools/graph-tools.d.ts.map +1 -1
- package/dist/tools/graph-tools.js +44 -3
- package/dist/tools/graph-tools.js.map +1 -1
- package/dist/tools/hilt-tools.d.ts +55 -0
- package/dist/tools/hilt-tools.d.ts.map +1 -0
- package/dist/tools/hilt-tools.js +258 -0
- package/dist/tools/hilt-tools.js.map +1 -0
- package/dist/tools/hono-analyze-app.d.ts +48 -0
- package/dist/tools/hono-analyze-app.d.ts.map +1 -0
- package/dist/tools/hono-analyze-app.js +94 -0
- package/dist/tools/hono-analyze-app.js.map +1 -0
- package/dist/tools/hono-api-contract.d.ts +22 -0
- package/dist/tools/hono-api-contract.d.ts.map +1 -0
- package/dist/tools/hono-api-contract.js +112 -0
- package/dist/tools/hono-api-contract.js.map +1 -0
- package/dist/tools/hono-conditional-middleware.d.ts +27 -0
- package/dist/tools/hono-conditional-middleware.d.ts.map +1 -0
- package/dist/tools/hono-conditional-middleware.js +62 -0
- package/dist/tools/hono-conditional-middleware.js.map +1 -0
- package/dist/tools/hono-context-flow.d.ts +24 -0
- package/dist/tools/hono-context-flow.d.ts.map +1 -0
- package/dist/tools/hono-context-flow.js +70 -0
- package/dist/tools/hono-context-flow.js.map +1 -0
- package/dist/tools/hono-dead-routes.d.ts +26 -0
- package/dist/tools/hono-dead-routes.d.ts.map +1 -0
- package/dist/tools/hono-dead-routes.js +102 -0
- package/dist/tools/hono-dead-routes.js.map +1 -0
- package/dist/tools/hono-entry-resolver.d.ts +27 -0
- package/dist/tools/hono-entry-resolver.d.ts.map +1 -0
- package/dist/tools/hono-entry-resolver.js +31 -0
- package/dist/tools/hono-entry-resolver.js.map +1 -0
- package/dist/tools/hono-env-regression.d.ts +29 -0
- package/dist/tools/hono-env-regression.d.ts.map +1 -0
- package/dist/tools/hono-env-regression.js +157 -0
- package/dist/tools/hono-env-regression.js.map +1 -0
- package/dist/tools/hono-inline-analyze.d.ts +31 -0
- package/dist/tools/hono-inline-analyze.d.ts.map +1 -0
- package/dist/tools/hono-inline-analyze.js +59 -0
- package/dist/tools/hono-inline-analyze.js.map +1 -0
- package/dist/tools/hono-middleware-chain.d.ts +40 -0
- package/dist/tools/hono-middleware-chain.d.ts.map +1 -0
- package/dist/tools/hono-middleware-chain.js +121 -0
- package/dist/tools/hono-middleware-chain.js.map +1 -0
- package/dist/tools/hono-modules.d.ts +22 -0
- package/dist/tools/hono-modules.d.ts.map +1 -0
- package/dist/tools/hono-modules.js +118 -0
- package/dist/tools/hono-modules.js.map +1 -0
- package/dist/tools/hono-response-types.d.ts +37 -0
- package/dist/tools/hono-response-types.d.ts.map +1 -0
- package/dist/tools/hono-response-types.js +76 -0
- package/dist/tools/hono-response-types.js.map +1 -0
- package/dist/tools/hono-rpc-types.d.ts +21 -0
- package/dist/tools/hono-rpc-types.d.ts.map +1 -0
- package/dist/tools/hono-rpc-types.js +49 -0
- package/dist/tools/hono-rpc-types.js.map +1 -0
- package/dist/tools/hono-security.d.ts +31 -0
- package/dist/tools/hono-security.d.ts.map +1 -0
- package/dist/tools/hono-security.js +269 -0
- package/dist/tools/hono-security.js.map +1 -0
- package/dist/tools/hono-visualize.d.ts +13 -0
- package/dist/tools/hono-visualize.d.ts.map +1 -0
- package/dist/tools/hono-visualize.js +64 -0
- package/dist/tools/hono-visualize.js.map +1 -0
- package/dist/tools/hotspot-tools.d.ts.map +1 -1
- package/dist/tools/hotspot-tools.js +9 -7
- package/dist/tools/hotspot-tools.js.map +1 -1
- package/dist/tools/index-tools.d.ts +17 -0
- package/dist/tools/index-tools.d.ts.map +1 -1
- package/dist/tools/index-tools.js +210 -10
- package/dist/tools/index-tools.js.map +1 -1
- package/dist/tools/kotlin-tools.d.ts +142 -0
- package/dist/tools/kotlin-tools.d.ts.map +1 -0
- package/dist/tools/kotlin-tools.js +572 -0
- package/dist/tools/kotlin-tools.js.map +1 -0
- package/dist/tools/legacy-hono-conventions.d.ts +14 -0
- package/dist/tools/legacy-hono-conventions.d.ts.map +1 -0
- package/dist/tools/legacy-hono-conventions.js +152 -0
- package/dist/tools/legacy-hono-conventions.js.map +1 -0
- package/dist/tools/migration-lint-tools.d.ts +26 -0
- package/dist/tools/migration-lint-tools.d.ts.map +1 -0
- package/dist/tools/migration-lint-tools.js +247 -0
- package/dist/tools/migration-lint-tools.js.map +1 -0
- package/dist/tools/model-tools.d.ts +30 -0
- package/dist/tools/model-tools.d.ts.map +1 -0
- package/dist/tools/model-tools.js +145 -0
- package/dist/tools/model-tools.js.map +1 -0
- package/dist/tools/nest-ext-tools.d.ts +207 -0
- package/dist/tools/nest-ext-tools.d.ts.map +1 -0
- package/dist/tools/nest-ext-tools.js +752 -0
- package/dist/tools/nest-ext-tools.js.map +1 -0
- package/dist/tools/nest-tools.d.ts +198 -0
- package/dist/tools/nest-tools.d.ts.map +1 -0
- package/dist/tools/nest-tools.js +1142 -0
- package/dist/tools/nest-tools.js.map +1 -0
- package/dist/tools/nextjs-api-contract-readers.d.ts +14 -0
- package/dist/tools/nextjs-api-contract-readers.d.ts.map +1 -0
- package/dist/tools/nextjs-api-contract-readers.js +204 -0
- package/dist/tools/nextjs-api-contract-readers.js.map +1 -0
- package/dist/tools/nextjs-api-contract-tools.d.ts +57 -0
- package/dist/tools/nextjs-api-contract-tools.d.ts.map +1 -0
- package/dist/tools/nextjs-api-contract-tools.js +144 -0
- package/dist/tools/nextjs-api-contract-tools.js.map +1 -0
- package/dist/tools/nextjs-boundary-tools.d.ts +39 -0
- package/dist/tools/nextjs-boundary-tools.d.ts.map +1 -0
- package/dist/tools/nextjs-boundary-tools.js +152 -0
- package/dist/tools/nextjs-boundary-tools.js.map +1 -0
- package/dist/tools/nextjs-component-readers.d.ts +101 -0
- package/dist/tools/nextjs-component-readers.d.ts.map +1 -0
- package/dist/tools/nextjs-component-readers.js +287 -0
- package/dist/tools/nextjs-component-readers.js.map +1 -0
- package/dist/tools/nextjs-component-tools.d.ts +51 -0
- package/dist/tools/nextjs-component-tools.d.ts.map +1 -0
- package/dist/tools/nextjs-component-tools.js +212 -0
- package/dist/tools/nextjs-component-tools.js.map +1 -0
- package/dist/tools/nextjs-data-flow-tools.d.ts +42 -0
- package/dist/tools/nextjs-data-flow-tools.d.ts.map +1 -0
- package/dist/tools/nextjs-data-flow-tools.js +158 -0
- package/dist/tools/nextjs-data-flow-tools.js.map +1 -0
- package/dist/tools/nextjs-framework-audit-tools.d.ts +60 -0
- package/dist/tools/nextjs-framework-audit-tools.d.ts.map +1 -0
- package/dist/tools/nextjs-framework-audit-tools.js +394 -0
- package/dist/tools/nextjs-framework-audit-tools.js.map +1 -0
- package/dist/tools/nextjs-link-tools.d.ts +41 -0
- package/dist/tools/nextjs-link-tools.d.ts.map +1 -0
- package/dist/tools/nextjs-link-tools.js +157 -0
- package/dist/tools/nextjs-link-tools.js.map +1 -0
- package/dist/tools/nextjs-metadata-tools.d.ts +74 -0
- package/dist/tools/nextjs-metadata-tools.d.ts.map +1 -0
- package/dist/tools/nextjs-metadata-tools.js +252 -0
- package/dist/tools/nextjs-metadata-tools.js.map +1 -0
- package/dist/tools/nextjs-middleware-coverage-tools.d.ts +41 -0
- package/dist/tools/nextjs-middleware-coverage-tools.d.ts.map +1 -0
- package/dist/tools/nextjs-middleware-coverage-tools.js +88 -0
- package/dist/tools/nextjs-middleware-coverage-tools.js.map +1 -0
- package/dist/tools/nextjs-route-readers.d.ts +81 -0
- package/dist/tools/nextjs-route-readers.d.ts.map +1 -0
- package/dist/tools/nextjs-route-readers.js +340 -0
- package/dist/tools/nextjs-route-readers.js.map +1 -0
- package/dist/tools/nextjs-route-tools.d.ts +36 -0
- package/dist/tools/nextjs-route-tools.d.ts.map +1 -0
- package/dist/tools/nextjs-route-tools.js +175 -0
- package/dist/tools/nextjs-route-tools.js.map +1 -0
- package/dist/tools/nextjs-security-readers.d.ts +22 -0
- package/dist/tools/nextjs-security-readers.d.ts.map +1 -0
- package/dist/tools/nextjs-security-readers.js +318 -0
- package/dist/tools/nextjs-security-readers.js.map +1 -0
- package/dist/tools/nextjs-security-scoring.d.ts +15 -0
- package/dist/tools/nextjs-security-scoring.d.ts.map +1 -0
- package/dist/tools/nextjs-security-scoring.js +65 -0
- package/dist/tools/nextjs-security-scoring.js.map +1 -0
- package/dist/tools/nextjs-security-tools.d.ts +75 -0
- package/dist/tools/nextjs-security-tools.d.ts.map +1 -0
- package/dist/tools/nextjs-security-tools.js +153 -0
- package/dist/tools/nextjs-security-tools.js.map +1 -0
- package/dist/tools/nextjs-tools.d.ts +15 -0
- package/dist/tools/nextjs-tools.d.ts.map +1 -0
- package/dist/tools/nextjs-tools.js +15 -0
- package/dist/tools/nextjs-tools.js.map +1 -0
- package/dist/tools/outline-tools.d.ts.map +1 -1
- package/dist/tools/outline-tools.js +20 -0
- package/dist/tools/outline-tools.js.map +1 -1
- package/dist/tools/pattern-tools.d.ts +8 -0
- package/dist/tools/pattern-tools.d.ts.map +1 -1
- package/dist/tools/pattern-tools.js +651 -3
- package/dist/tools/pattern-tools.js.map +1 -1
- package/dist/tools/perf-tools.d.ts +32 -0
- package/dist/tools/perf-tools.d.ts.map +1 -0
- package/dist/tools/perf-tools.js +227 -0
- package/dist/tools/perf-tools.js.map +1 -0
- package/dist/tools/php-tools.d.ts +185 -0
- package/dist/tools/php-tools.d.ts.map +1 -0
- package/dist/tools/php-tools.js +645 -0
- package/dist/tools/php-tools.js.map +1 -0
- package/dist/tools/plan-turn-tools.d.ts +89 -0
- package/dist/tools/plan-turn-tools.d.ts.map +1 -0
- package/dist/tools/plan-turn-tools.js +508 -0
- package/dist/tools/plan-turn-tools.js.map +1 -0
- package/dist/tools/prisma-schema-tools.d.ts +44 -0
- package/dist/tools/prisma-schema-tools.d.ts.map +1 -0
- package/dist/tools/prisma-schema-tools.js +358 -0
- package/dist/tools/prisma-schema-tools.js.map +1 -0
- package/dist/tools/project-tools.d.ts +116 -7
- package/dist/tools/project-tools.d.ts.map +1 -1
- package/dist/tools/project-tools.js +595 -218
- package/dist/tools/project-tools.js.map +1 -1
- package/dist/tools/pydantic-models.d.ts +46 -0
- package/dist/tools/pydantic-models.d.ts.map +1 -0
- package/dist/tools/pydantic-models.js +249 -0
- package/dist/tools/pydantic-models.js.map +1 -0
- package/dist/tools/pyproject-tools.d.ts +23 -0
- package/dist/tools/pyproject-tools.d.ts.map +1 -0
- package/dist/tools/pyproject-tools.js +133 -0
- package/dist/tools/pyproject-tools.js.map +1 -0
- package/dist/tools/pytest-tools.d.ts +20 -0
- package/dist/tools/pytest-tools.d.ts.map +1 -0
- package/dist/tools/pytest-tools.js +106 -0
- package/dist/tools/pytest-tools.js.map +1 -0
- package/dist/tools/python-audit.d.ts +40 -0
- package/dist/tools/python-audit.d.ts.map +1 -0
- package/dist/tools/python-audit.js +244 -0
- package/dist/tools/python-audit.js.map +1 -0
- package/dist/tools/python-callers.d.ts +28 -0
- package/dist/tools/python-callers.d.ts.map +1 -0
- package/dist/tools/python-callers.js +110 -0
- package/dist/tools/python-callers.js.map +1 -0
- package/dist/tools/python-circular-imports.d.ts +19 -0
- package/dist/tools/python-circular-imports.d.ts.map +1 -0
- package/dist/tools/python-circular-imports.js +126 -0
- package/dist/tools/python-circular-imports.js.map +1 -0
- package/dist/tools/python-constants-tools.d.ts +44 -0
- package/dist/tools/python-constants-tools.d.ts.map +1 -0
- package/dist/tools/python-constants-tools.js +525 -0
- package/dist/tools/python-constants-tools.js.map +1 -0
- package/dist/tools/python-deps-analyzer.d.ts +46 -0
- package/dist/tools/python-deps-analyzer.d.ts.map +1 -0
- package/dist/tools/python-deps-analyzer.js +227 -0
- package/dist/tools/python-deps-analyzer.js.map +1 -0
- package/dist/tools/query-tools.d.ts +23 -0
- package/dist/tools/query-tools.d.ts.map +1 -0
- package/dist/tools/query-tools.js +256 -0
- package/dist/tools/query-tools.js.map +1 -0
- package/dist/tools/react-tools.d.ts +263 -0
- package/dist/tools/react-tools.d.ts.map +1 -0
- package/dist/tools/react-tools.js +839 -0
- package/dist/tools/react-tools.js.map +1 -0
- package/dist/tools/report-tools.js +47 -0
- package/dist/tools/report-tools.js.map +1 -1
- package/dist/tools/review-diff-tools.d.ts +5 -4
- package/dist/tools/review-diff-tools.d.ts.map +1 -1
- package/dist/tools/review-diff-tools.js +157 -66
- package/dist/tools/review-diff-tools.js.map +1 -1
- package/dist/tools/room-tools.d.ts +36 -0
- package/dist/tools/room-tools.d.ts.map +1 -0
- package/dist/tools/room-tools.js +147 -0
- package/dist/tools/room-tools.js.map +1 -0
- package/dist/tools/route-tools.d.ts +27 -1
- package/dist/tools/route-tools.d.ts.map +1 -1
- package/dist/tools/route-tools.js +744 -18
- package/dist/tools/route-tools.js.map +1 -1
- package/dist/tools/ruff-tools.d.ts +32 -0
- package/dist/tools/ruff-tools.d.ts.map +1 -0
- package/dist/tools/ruff-tools.js +114 -0
- package/dist/tools/ruff-tools.js.map +1 -0
- package/dist/tools/search-ranker.d.ts.map +1 -1
- package/dist/tools/search-ranker.js +7 -0
- package/dist/tools/search-ranker.js.map +1 -1
- package/dist/tools/search-tools.d.ts +3 -2
- package/dist/tools/search-tools.d.ts.map +1 -1
- package/dist/tools/search-tools.js +16 -3
- package/dist/tools/search-tools.js.map +1 -1
- package/dist/tools/serialization-tools.d.ts +24 -0
- package/dist/tools/serialization-tools.d.ts.map +1 -0
- package/dist/tools/serialization-tools.js +156 -0
- package/dist/tools/serialization-tools.js.map +1 -0
- package/dist/tools/sql-tools.d.ts +274 -0
- package/dist/tools/sql-tools.d.ts.map +1 -0
- package/dist/tools/sql-tools.js +1160 -0
- package/dist/tools/sql-tools.js.map +1 -0
- package/dist/tools/status-tools.d.ts +10 -0
- package/dist/tools/status-tools.d.ts.map +1 -0
- package/dist/tools/status-tools.js +32 -0
- package/dist/tools/status-tools.js.map +1 -0
- package/dist/tools/symbol-tools.d.ts +19 -0
- package/dist/tools/symbol-tools.d.ts.map +1 -1
- package/dist/tools/symbol-tools.js +75 -4
- package/dist/tools/symbol-tools.js.map +1 -1
- package/dist/tools/taint-tools.d.ts +43 -0
- package/dist/tools/taint-tools.d.ts.map +1 -0
- package/dist/tools/taint-tools.js +922 -0
- package/dist/tools/taint-tools.js.map +1 -0
- package/dist/tools/test-impact-tools.d.ts +29 -0
- package/dist/tools/test-impact-tools.d.ts.map +1 -0
- package/dist/tools/test-impact-tools.js +156 -0
- package/dist/tools/test-impact-tools.js.map +1 -0
- package/dist/tools/typecheck-tools.d.ts +39 -0
- package/dist/tools/typecheck-tools.d.ts.map +1 -0
- package/dist/tools/typecheck-tools.js +191 -0
- package/dist/tools/typecheck-tools.js.map +1 -0
- package/dist/tools/wiring-tools.d.ts +19 -0
- package/dist/tools/wiring-tools.d.ts.map +1 -0
- package/dist/tools/wiring-tools.js +147 -0
- package/dist/tools/wiring-tools.js.map +1 -0
- package/dist/types.d.ts +9 -1
- package/dist/types.d.ts.map +1 -1
- package/dist/utils/framework-detect.d.ts +18 -2
- package/dist/utils/framework-detect.d.ts.map +1 -1
- package/dist/utils/framework-detect.js +150 -3
- package/dist/utils/framework-detect.js.map +1 -1
- package/dist/utils/import-graph.d.ts +42 -0
- package/dist/utils/import-graph.d.ts.map +1 -1
- package/dist/utils/import-graph.js +248 -9
- package/dist/utils/import-graph.js.map +1 -1
- package/dist/utils/language-detect.d.ts +21 -0
- package/dist/utils/language-detect.d.ts.map +1 -0
- package/dist/utils/language-detect.js +183 -0
- package/dist/utils/language-detect.js.map +1 -0
- package/dist/utils/nextjs-ast-readers.d.ts +44 -0
- package/dist/utils/nextjs-ast-readers.d.ts.map +1 -0
- package/dist/utils/nextjs-ast-readers.js +341 -0
- package/dist/utils/nextjs-ast-readers.js.map +1 -0
- package/dist/utils/nextjs-audit-cache.d.ts +51 -0
- package/dist/utils/nextjs-audit-cache.d.ts.map +1 -0
- package/dist/utils/nextjs-audit-cache.js +116 -0
- package/dist/utils/nextjs-audit-cache.js.map +1 -0
- package/dist/utils/nextjs-metadata-readers.d.ts +65 -0
- package/dist/utils/nextjs-metadata-readers.d.ts.map +1 -0
- package/dist/utils/nextjs-metadata-readers.js +447 -0
- package/dist/utils/nextjs-metadata-readers.js.map +1 -0
- package/dist/utils/nextjs.d.ts +42 -0
- package/dist/utils/nextjs.d.ts.map +1 -0
- package/dist/utils/nextjs.js +284 -0
- package/dist/utils/nextjs.js.map +1 -0
- package/dist/utils/python-import-resolver.d.ts +42 -0
- package/dist/utils/python-import-resolver.d.ts.map +1 -0
- package/dist/utils/python-import-resolver.js +101 -0
- package/dist/utils/python-import-resolver.js.map +1 -0
- package/dist/utils/python-imports.d.ts +28 -0
- package/dist/utils/python-imports.d.ts.map +1 -0
- package/dist/utils/python-imports.js +117 -0
- package/dist/utils/python-imports.js.map +1 -0
- package/dist/utils/react-alias.d.ts +15 -0
- package/dist/utils/react-alias.d.ts.map +1 -0
- package/dist/utils/react-alias.js +31 -0
- package/dist/utils/react-alias.js.map +1 -0
- package/dist/utils/test-file.d.ts.map +1 -1
- package/dist/utils/test-file.js +7 -0
- package/dist/utils/test-file.js.map +1 -1
- package/dist/utils/walk.d.ts +22 -0
- package/dist/utils/walk.d.ts.map +1 -1
- package/dist/utils/walk.js +70 -2
- package/dist/utils/walk.js.map +1 -1
- package/package.json +4 -3
- package/rules/codesift.md +71 -5
- package/rules/codesift.mdc +71 -5
- package/rules/codex.md +71 -5
- package/rules/gemini.md +71 -5
- package/src/parser/languages/tree-sitter-javascript.wasm +0 -0
- package/src/parser/languages/tree-sitter-kotlin.wasm +0 -0
- package/src/parser/languages/tree-sitter-php.wasm +0 -0
- package/src/parser/languages/tree-sitter-php_only.wasm +0 -0
- package/src/parser/languages/tree-sitter-python.wasm +0 -0
|
@@ -0,0 +1,752 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* NestJS extended analysis tools — Wave 2 (G5, G6, G7/G8, G12, G14).
|
|
3
|
+
* Separate file from nest-tools.ts to keep it under the CQ11 soft limit.
|
|
4
|
+
* All tools follow the established regex-over-source pattern with CQ6/CQ8 guarantees.
|
|
5
|
+
*/
|
|
6
|
+
import { readFile } from "node:fs/promises";
|
|
7
|
+
import { join } from "node:path";
|
|
8
|
+
import { getCodeIndex } from "./index-tools.js";
|
|
9
|
+
import { detectCycles } from "./nest-tools.js";
|
|
10
|
+
export async function nestGraphQLMap(repo, options) {
|
|
11
|
+
const index = await getCodeIndex(repo);
|
|
12
|
+
if (!index)
|
|
13
|
+
throw new Error(`Repository "${repo}" not found. Index it first with index_folder.`);
|
|
14
|
+
const maxEntries = options?.max_entries ?? 300;
|
|
15
|
+
const entries = [];
|
|
16
|
+
const errors = [];
|
|
17
|
+
let truncated = false;
|
|
18
|
+
const resolverFiles = index.files.filter((f) => f.path.endsWith(".resolver.ts") || f.path.endsWith(".resolver.js"));
|
|
19
|
+
for (const file of resolverFiles) {
|
|
20
|
+
if (entries.length >= maxEntries) {
|
|
21
|
+
truncated = true;
|
|
22
|
+
break;
|
|
23
|
+
}
|
|
24
|
+
let source;
|
|
25
|
+
try {
|
|
26
|
+
source = await readFile(join(index.root, file.path), "utf-8");
|
|
27
|
+
}
|
|
28
|
+
catch (err) {
|
|
29
|
+
errors.push({ file: file.path, reason: `readFile failed: ${err instanceof Error ? err.message : String(err)}` });
|
|
30
|
+
continue;
|
|
31
|
+
}
|
|
32
|
+
// Find resolver class name (searches for class declaration near @Resolver decorator)
|
|
33
|
+
const resolverClassMatch = /@Resolver\s*\([\s\S]*?\)\s*(?:export\s+)?class\s+(\w+)/.exec(source);
|
|
34
|
+
const resolverClass = resolverClassMatch?.[1] ?? "UnknownResolver";
|
|
35
|
+
// Extract GraphQL operation decorators with their handler names
|
|
36
|
+
// R-2 fix: cap decorator args to 300 chars to prevent cross-method boundary matching
|
|
37
|
+
const opRe = /@(Query|Mutation|Subscription|ResolveField)\s*\(([\s\S]{0,300}?)\)\s*\n?\s*(?:(?:public|private|protected|static)\s+)?(?:async\s+)?(\w+)\s*\(/g;
|
|
38
|
+
let m;
|
|
39
|
+
while ((m = opRe.exec(source)) !== null) {
|
|
40
|
+
if (entries.length >= maxEntries) {
|
|
41
|
+
truncated = true;
|
|
42
|
+
break;
|
|
43
|
+
}
|
|
44
|
+
const operation = m[1];
|
|
45
|
+
const args = m[2];
|
|
46
|
+
const handler = m[3];
|
|
47
|
+
// Extract return type from decorator arg: () => Article → Article
|
|
48
|
+
const returnTypeMatch = /\(\s*\)\s*=>\s*(?:\[\s*)?(\w+)/.exec(args);
|
|
49
|
+
const entry = {
|
|
50
|
+
resolver_class: resolverClass,
|
|
51
|
+
file: file.path,
|
|
52
|
+
operation,
|
|
53
|
+
handler,
|
|
54
|
+
};
|
|
55
|
+
if (returnTypeMatch)
|
|
56
|
+
entry.return_type = returnTypeMatch[1];
|
|
57
|
+
entries.push(entry);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
return {
|
|
61
|
+
entries,
|
|
62
|
+
...(errors.length > 0 ? { errors } : {}),
|
|
63
|
+
...(truncated ? { truncated } : {}),
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
export async function nestWebSocketMap(repo, options) {
|
|
67
|
+
const index = await getCodeIndex(repo);
|
|
68
|
+
if (!index)
|
|
69
|
+
throw new Error(`Repository "${repo}" not found. Index it first with index_folder.`);
|
|
70
|
+
const maxGateways = options?.max_gateways ?? 100;
|
|
71
|
+
const gateways = [];
|
|
72
|
+
const errors = [];
|
|
73
|
+
let truncated = false;
|
|
74
|
+
const gatewayFiles = index.files.filter((f) => f.path.endsWith(".gateway.ts") || f.path.endsWith(".gateway.js"));
|
|
75
|
+
for (const file of gatewayFiles) {
|
|
76
|
+
if (gateways.length >= maxGateways) {
|
|
77
|
+
truncated = true;
|
|
78
|
+
break;
|
|
79
|
+
}
|
|
80
|
+
let source;
|
|
81
|
+
try {
|
|
82
|
+
source = await readFile(join(index.root, file.path), "utf-8");
|
|
83
|
+
}
|
|
84
|
+
catch (err) {
|
|
85
|
+
errors.push({ file: file.path, reason: `readFile failed: ${err instanceof Error ? err.message : String(err)}` });
|
|
86
|
+
continue;
|
|
87
|
+
}
|
|
88
|
+
// Parse @WebSocketGateway decorator with optional port + options
|
|
89
|
+
// Form 1: @WebSocketGateway()
|
|
90
|
+
// Form 2: @WebSocketGateway(3001)
|
|
91
|
+
// Form 3: @WebSocketGateway(3001, { namespace: '/chat' })
|
|
92
|
+
// Form 4: @WebSocketGateway({ namespace: '/chat' })
|
|
93
|
+
const wsGwRe = /@WebSocketGateway\s*\(([\s\S]*?)\)\s*(?:export\s+)?class\s+(\w+)/;
|
|
94
|
+
const gwMatch = wsGwRe.exec(source);
|
|
95
|
+
if (!gwMatch)
|
|
96
|
+
continue;
|
|
97
|
+
const gwArgs = gwMatch[1];
|
|
98
|
+
const gatewayClass = gwMatch[2];
|
|
99
|
+
const entry = {
|
|
100
|
+
gateway_class: gatewayClass,
|
|
101
|
+
file: file.path,
|
|
102
|
+
events: [],
|
|
103
|
+
};
|
|
104
|
+
// Port — first integer literal in args
|
|
105
|
+
// R-4 fix: only accept a leading bare integer as port (not nums inside namespace strings)
|
|
106
|
+
const portMatch = /^\s*(\d+)\s*(?:,|\))/.exec(gwArgs);
|
|
107
|
+
if (portMatch)
|
|
108
|
+
entry.port = parseInt(portMatch[1], 10);
|
|
109
|
+
// Namespace — from options object
|
|
110
|
+
const nsMatch = /namespace:\s*['"`]([^'"`]+)['"`]/.exec(gwArgs);
|
|
111
|
+
if (nsMatch)
|
|
112
|
+
entry.namespace = nsMatch[1];
|
|
113
|
+
// Find @SubscribeMessage handlers
|
|
114
|
+
const subRe = /@SubscribeMessage\s*\(\s*['"`]([^'"`]+)['"`]\s*\)\s*\n?\s*(?:(?:public|private|protected|static)\s+)?(?:async\s+)?(\w+)\s*\(/g;
|
|
115
|
+
let sm;
|
|
116
|
+
while ((sm = subRe.exec(source)) !== null) {
|
|
117
|
+
entry.events.push({ event: sm[1], handler: sm[2] });
|
|
118
|
+
}
|
|
119
|
+
gateways.push(entry);
|
|
120
|
+
}
|
|
121
|
+
return {
|
|
122
|
+
gateways,
|
|
123
|
+
...(errors.length > 0 ? { errors } : {}),
|
|
124
|
+
...(truncated ? { truncated } : {}),
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
export async function nestScheduleMap(repo, options) {
|
|
128
|
+
const index = await getCodeIndex(repo);
|
|
129
|
+
if (!index)
|
|
130
|
+
throw new Error(`Repository "${repo}" not found. Index it first with index_folder.`);
|
|
131
|
+
const maxSchedules = options?.max_schedules ?? 300;
|
|
132
|
+
const maxFilesScanned = options?.max_files_scanned ?? 2000;
|
|
133
|
+
const entries = [];
|
|
134
|
+
const errors = [];
|
|
135
|
+
let truncated = false;
|
|
136
|
+
// Pre-filter: only .ts/.js files, exclude spec/test files, prefer .service.ts
|
|
137
|
+
const candidateFiles = index.files.filter((f) => {
|
|
138
|
+
if (!f.path.endsWith(".ts") && !f.path.endsWith(".js"))
|
|
139
|
+
return false;
|
|
140
|
+
if (/\.(spec|test)\./.test(f.path))
|
|
141
|
+
return false;
|
|
142
|
+
if (f.path.includes("/node_modules/"))
|
|
143
|
+
return false;
|
|
144
|
+
return true;
|
|
145
|
+
});
|
|
146
|
+
let scanned = 0;
|
|
147
|
+
for (const file of candidateFiles) {
|
|
148
|
+
if (scanned >= maxFilesScanned) {
|
|
149
|
+
truncated = true;
|
|
150
|
+
break;
|
|
151
|
+
}
|
|
152
|
+
if (entries.length >= maxSchedules) {
|
|
153
|
+
truncated = true;
|
|
154
|
+
break;
|
|
155
|
+
}
|
|
156
|
+
scanned++;
|
|
157
|
+
let source;
|
|
158
|
+
try {
|
|
159
|
+
source = await readFile(join(index.root, file.path), "utf-8");
|
|
160
|
+
}
|
|
161
|
+
catch (err) {
|
|
162
|
+
errors.push({ file: file.path, reason: `readFile failed: ${err instanceof Error ? err.message : String(err)}` });
|
|
163
|
+
continue;
|
|
164
|
+
}
|
|
165
|
+
// Quick substring filter to skip files without schedule/event decorators
|
|
166
|
+
if (!/@Cron|@Interval|@Timeout|@OnEvent/.test(source))
|
|
167
|
+
continue;
|
|
168
|
+
// Find enclosing class name — single-class-per-file assumption for simplicity
|
|
169
|
+
const classMatch = /(?:export\s+)?class\s+(\w+)/.exec(source);
|
|
170
|
+
const className = classMatch?.[1] ?? "UnknownClass";
|
|
171
|
+
// Parse each decorator type
|
|
172
|
+
const decoratorPatterns = [
|
|
173
|
+
{
|
|
174
|
+
type: "@Cron",
|
|
175
|
+
regex: /@Cron\s*\(\s*['"`]([^'"`]+)['"`][^)]*\)\s*\n?\s*(?:(?:public|private|protected|static)\s+)?(?:async\s+)?(\w+)\s*\(/g,
|
|
176
|
+
parseArg: (arg) => ({ expression: arg }),
|
|
177
|
+
},
|
|
178
|
+
{
|
|
179
|
+
type: "@Interval",
|
|
180
|
+
regex: /@Interval\s*\(\s*(\d+)\s*\)\s*\n?\s*(?:(?:public|private|protected|static)\s+)?(?:async\s+)?(\w+)\s*\(/g,
|
|
181
|
+
parseArg: (arg) => ({ interval_ms: parseInt(arg, 10) }),
|
|
182
|
+
},
|
|
183
|
+
{
|
|
184
|
+
type: "@Timeout",
|
|
185
|
+
regex: /@Timeout\s*\(\s*(\d+)\s*\)\s*\n?\s*(?:(?:public|private|protected|static)\s+)?(?:async\s+)?(\w+)\s*\(/g,
|
|
186
|
+
parseArg: (arg) => ({ interval_ms: parseInt(arg, 10) }),
|
|
187
|
+
},
|
|
188
|
+
{
|
|
189
|
+
type: "@OnEvent",
|
|
190
|
+
regex: /@OnEvent\s*\(\s*['"`]([^'"`]+)['"`][^)]*\)\s*\n?\s*(?:(?:public|private|protected|static)\s+)?(?:async\s+)?(\w+)\s*\(/g,
|
|
191
|
+
parseArg: (arg) => ({ expression: arg }),
|
|
192
|
+
},
|
|
193
|
+
];
|
|
194
|
+
for (const { type, regex, parseArg } of decoratorPatterns) {
|
|
195
|
+
regex.lastIndex = 0;
|
|
196
|
+
let m;
|
|
197
|
+
while ((m = regex.exec(source)) !== null) {
|
|
198
|
+
if (entries.length >= maxSchedules) {
|
|
199
|
+
truncated = true;
|
|
200
|
+
break;
|
|
201
|
+
}
|
|
202
|
+
const arg = m[1];
|
|
203
|
+
const handler = m[2];
|
|
204
|
+
entries.push({
|
|
205
|
+
class_name: className,
|
|
206
|
+
file: file.path,
|
|
207
|
+
handler,
|
|
208
|
+
decorator: type,
|
|
209
|
+
...parseArg(arg),
|
|
210
|
+
});
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
// R-12 fix: fallback — catch constant/expression args like @Cron(CronExpression.EVERY_10_SECONDS)
|
|
214
|
+
// These are not captured by the literal-specific regexes above.
|
|
215
|
+
const fallbackRe = /@(Cron|Interval|Timeout|OnEvent)\s*\(\s*([A-Z][\w.]+)\s*\)\s*\n?\s*(?:(?:public|private|protected|static)\s+)?(?:async\s+)?(\w+)\s*\(/g;
|
|
216
|
+
let fm;
|
|
217
|
+
while ((fm = fallbackRe.exec(source)) !== null) {
|
|
218
|
+
if (entries.length >= maxSchedules) {
|
|
219
|
+
truncated = true;
|
|
220
|
+
break;
|
|
221
|
+
}
|
|
222
|
+
const handler = fm[3];
|
|
223
|
+
// Skip if already captured by a literal regex above
|
|
224
|
+
if (entries.some((e) => e.file === file.path && e.handler === handler))
|
|
225
|
+
continue;
|
|
226
|
+
entries.push({
|
|
227
|
+
class_name: className,
|
|
228
|
+
file: file.path,
|
|
229
|
+
handler,
|
|
230
|
+
decorator: `@${fm[1]}`,
|
|
231
|
+
expression: fm[2], // raw constant expression, e.g. "CronExpression.EVERY_10_SECONDS"
|
|
232
|
+
});
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
return {
|
|
236
|
+
entries,
|
|
237
|
+
...(errors.length > 0 ? { errors } : {}),
|
|
238
|
+
...(truncated ? { truncated } : {}),
|
|
239
|
+
};
|
|
240
|
+
}
|
|
241
|
+
export async function nestTypeOrmMap(repo, options) {
|
|
242
|
+
const index = await getCodeIndex(repo);
|
|
243
|
+
if (!index)
|
|
244
|
+
throw new Error(`Repository "${repo}" not found. Index it first with index_folder.`);
|
|
245
|
+
const maxEntities = options?.max_entities ?? 200;
|
|
246
|
+
const entities = [];
|
|
247
|
+
const edges = [];
|
|
248
|
+
const errors = [];
|
|
249
|
+
let truncated = false;
|
|
250
|
+
const entityFiles = index.files.filter((f) => f.path.endsWith(".entity.ts") || f.path.endsWith(".entity.js"));
|
|
251
|
+
for (const file of entityFiles) {
|
|
252
|
+
if (entities.length >= maxEntities) {
|
|
253
|
+
truncated = true;
|
|
254
|
+
break;
|
|
255
|
+
}
|
|
256
|
+
let source;
|
|
257
|
+
try {
|
|
258
|
+
source = await readFile(join(index.root, file.path), "utf-8");
|
|
259
|
+
}
|
|
260
|
+
catch (err) {
|
|
261
|
+
errors.push({ file: file.path, reason: `readFile failed: ${err instanceof Error ? err.message : String(err)}` });
|
|
262
|
+
continue;
|
|
263
|
+
}
|
|
264
|
+
// @Entity() or @Entity('table_name') followed by class declaration
|
|
265
|
+
// R-10 fix: also accept object-form @Entity({ name: 'users' }) — capture table from name field
|
|
266
|
+
const entityRe = /@Entity\s*\(\s*(?:['"`]([^'"`]+)['"`]|\{[^}]*\})?\s*\)\s*(?:export\s+)?class\s+(\w+)/g;
|
|
267
|
+
let em;
|
|
268
|
+
while ((em = entityRe.exec(source)) !== null) {
|
|
269
|
+
if (entities.length >= maxEntities) {
|
|
270
|
+
truncated = true;
|
|
271
|
+
break;
|
|
272
|
+
}
|
|
273
|
+
let tableName = em[1]; // from string form @Entity('users')
|
|
274
|
+
const entityName = em[2];
|
|
275
|
+
// R-10: extract table name from object form @Entity({ name: 'users' })
|
|
276
|
+
if (!tableName) {
|
|
277
|
+
const objNameMatch = em[0].match(/\{\s*[^}]*name:\s*['"`]([^'"`]+)['"`]/);
|
|
278
|
+
if (objNameMatch)
|
|
279
|
+
tableName = objNameMatch[1];
|
|
280
|
+
}
|
|
281
|
+
const node = { name: entityName, file: file.path };
|
|
282
|
+
if (tableName)
|
|
283
|
+
node.table = tableName;
|
|
284
|
+
entities.push(node);
|
|
285
|
+
// Find relations within this entity's class body
|
|
286
|
+
// Scan forward from the class match until the next @Entity or end of file
|
|
287
|
+
const classStart = em.index + em[0].length;
|
|
288
|
+
const nextEntityMatch = /@Entity\s*\(/.exec(source.slice(classStart));
|
|
289
|
+
const classEnd = nextEntityMatch ? classStart + nextEntityMatch.index : source.length;
|
|
290
|
+
const classBody = source.slice(classStart, classEnd);
|
|
291
|
+
const relRe = /@(OneToMany|ManyToOne|OneToOne|ManyToMany)\s*\(\s*\(\)\s*=>\s*(\w+)/g;
|
|
292
|
+
let rm;
|
|
293
|
+
while ((rm = relRe.exec(classBody)) !== null) {
|
|
294
|
+
edges.push({ from: entityName, to: rm[2], relation: rm[1] });
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
// Detect cycles in entity relation graph
|
|
299
|
+
const entityNames = entities.map((e) => e.name);
|
|
300
|
+
const cycles = detectCycles(entityNames, edges.map((e) => ({ from: e.from, to: e.to })));
|
|
301
|
+
return {
|
|
302
|
+
entities,
|
|
303
|
+
edges,
|
|
304
|
+
cycles,
|
|
305
|
+
...(errors.length > 0 ? { errors } : {}),
|
|
306
|
+
...(truncated ? { truncated } : {}),
|
|
307
|
+
};
|
|
308
|
+
}
|
|
309
|
+
export async function nestMicroserviceMap(repo, options) {
|
|
310
|
+
const index = await getCodeIndex(repo);
|
|
311
|
+
if (!index)
|
|
312
|
+
throw new Error(`Repository "${repo}" not found. Index it first with index_folder.`);
|
|
313
|
+
const maxPatterns = options?.max_patterns ?? 300;
|
|
314
|
+
const patterns = [];
|
|
315
|
+
const errors = [];
|
|
316
|
+
let truncated = false;
|
|
317
|
+
// Microservice patterns are typically in controller files (hybrid apps)
|
|
318
|
+
const controllerFiles = index.files.filter((f) => f.path.endsWith(".controller.ts") || f.path.endsWith(".controller.js"));
|
|
319
|
+
for (const file of controllerFiles) {
|
|
320
|
+
if (patterns.length >= maxPatterns) {
|
|
321
|
+
truncated = true;
|
|
322
|
+
break;
|
|
323
|
+
}
|
|
324
|
+
let source;
|
|
325
|
+
try {
|
|
326
|
+
source = await readFile(join(index.root, file.path), "utf-8");
|
|
327
|
+
}
|
|
328
|
+
catch (err) {
|
|
329
|
+
errors.push({ file: file.path, reason: `readFile failed: ${err instanceof Error ? err.message : String(err)}` });
|
|
330
|
+
continue;
|
|
331
|
+
}
|
|
332
|
+
// Quick substring filter
|
|
333
|
+
if (!/@(MessagePattern|EventPattern)/.test(source))
|
|
334
|
+
continue;
|
|
335
|
+
const classMatch = /class\s+(\w+)/.exec(source);
|
|
336
|
+
const controller = classMatch?.[1] ?? "UnknownController";
|
|
337
|
+
const patternRe = /@(MessagePattern|EventPattern)\s*\(\s*['"`]([^'"`]+)['"`]\s*\)\s*\n?\s*(?:(?:public|private|protected|static)\s+)?(?:async\s+)?(\w+)\s*\(/g;
|
|
338
|
+
let m;
|
|
339
|
+
while ((m = patternRe.exec(source)) !== null) {
|
|
340
|
+
if (patterns.length >= maxPatterns) {
|
|
341
|
+
truncated = true;
|
|
342
|
+
break;
|
|
343
|
+
}
|
|
344
|
+
patterns.push({
|
|
345
|
+
type: m[1],
|
|
346
|
+
pattern: m[2],
|
|
347
|
+
handler: m[3],
|
|
348
|
+
controller,
|
|
349
|
+
file: file.path,
|
|
350
|
+
});
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
return {
|
|
354
|
+
patterns,
|
|
355
|
+
...(errors.length > 0 ? { errors } : {}),
|
|
356
|
+
...(truncated ? { truncated } : {}),
|
|
357
|
+
};
|
|
358
|
+
}
|
|
359
|
+
export async function nestQueueMap(repo, options) {
|
|
360
|
+
const index = await getCodeIndex(repo);
|
|
361
|
+
if (!index)
|
|
362
|
+
throw new Error(`Repository "${repo}" not found. Index it first with index_folder.`);
|
|
363
|
+
const maxProcessors = options?.max_processors ?? 200;
|
|
364
|
+
const processors = [];
|
|
365
|
+
const producers = [];
|
|
366
|
+
const errors = [];
|
|
367
|
+
let truncated = false;
|
|
368
|
+
// Scan .ts/.js files for @Processor or @InjectQueue decorators
|
|
369
|
+
const candidateFiles = index.files.filter((f) => {
|
|
370
|
+
if (!f.path.endsWith(".ts") && !f.path.endsWith(".js"))
|
|
371
|
+
return false;
|
|
372
|
+
if (/\.(spec|test)\./.test(f.path))
|
|
373
|
+
return false;
|
|
374
|
+
if (f.path.includes("/node_modules/"))
|
|
375
|
+
return false;
|
|
376
|
+
return true;
|
|
377
|
+
});
|
|
378
|
+
for (const file of candidateFiles) {
|
|
379
|
+
if (processors.length >= maxProcessors) {
|
|
380
|
+
truncated = true;
|
|
381
|
+
break;
|
|
382
|
+
}
|
|
383
|
+
let source;
|
|
384
|
+
try {
|
|
385
|
+
source = await readFile(join(index.root, file.path), "utf-8");
|
|
386
|
+
}
|
|
387
|
+
catch (err) {
|
|
388
|
+
errors.push({ file: file.path, reason: `readFile failed: ${err instanceof Error ? err.message : String(err)}` });
|
|
389
|
+
continue;
|
|
390
|
+
}
|
|
391
|
+
// Quick substring filter
|
|
392
|
+
if (!/@Processor|@InjectQueue/.test(source))
|
|
393
|
+
continue;
|
|
394
|
+
// --- Parse @Processor('queue-name') classes ---
|
|
395
|
+
const procRe = /@Processor\s*\(\s*(?:['"`]([^'"`]+)['"`])?\s*\)\s*(?:export\s+)?class\s+(\w+)/g;
|
|
396
|
+
let pm;
|
|
397
|
+
while ((pm = procRe.exec(source)) !== null) {
|
|
398
|
+
if (processors.length >= maxProcessors) {
|
|
399
|
+
truncated = true;
|
|
400
|
+
break;
|
|
401
|
+
}
|
|
402
|
+
const queueName = pm[1] ?? "default";
|
|
403
|
+
const processorClass = pm[2];
|
|
404
|
+
// Find the class body (forward scan for @Process handlers)
|
|
405
|
+
const classStart = pm.index + pm[0].length;
|
|
406
|
+
const nextClassMatch = /(?:export\s+)?class\s+\w+/.exec(source.slice(classStart));
|
|
407
|
+
const classEnd = nextClassMatch ? classStart + nextClassMatch.index : source.length;
|
|
408
|
+
const classBody = source.slice(classStart, classEnd);
|
|
409
|
+
const handlers = [];
|
|
410
|
+
const handlerDecorators = [
|
|
411
|
+
["Process", "@Process"],
|
|
412
|
+
["OnQueueActive", "@OnQueueActive"],
|
|
413
|
+
["OnQueueCompleted", "@OnQueueCompleted"],
|
|
414
|
+
["OnQueueFailed", "@OnQueueFailed"],
|
|
415
|
+
["OnQueueStalled", "@OnQueueStalled"],
|
|
416
|
+
["OnQueueWaiting", "@OnQueueWaiting"],
|
|
417
|
+
["OnQueueProgress", "@OnQueueProgress"],
|
|
418
|
+
["OnQueueError", "@OnQueueError"],
|
|
419
|
+
];
|
|
420
|
+
for (const [decName, decType] of handlerDecorators) {
|
|
421
|
+
// Match decorator with optional job name arg, then method name (skip modifiers)
|
|
422
|
+
const re = new RegExp(`@${decName}\\s*\\(\\s*(?:['"\`]([^'"\`]+)['"\`])?\\s*\\)\\s*\\n?\\s*(?:(?:public|private|protected|static)\\s+)?(?:async\\s+)?(\\w+)\\s*\\(`, "g");
|
|
423
|
+
let hm;
|
|
424
|
+
while ((hm = re.exec(classBody)) !== null) {
|
|
425
|
+
const jobName = hm[1];
|
|
426
|
+
const handler = hm[2];
|
|
427
|
+
handlers.push({
|
|
428
|
+
decorator: decType,
|
|
429
|
+
handler,
|
|
430
|
+
...(jobName ? { job_name: jobName } : {}),
|
|
431
|
+
});
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
processors.push({
|
|
435
|
+
processor_class: processorClass,
|
|
436
|
+
queue_name: queueName,
|
|
437
|
+
file: file.path,
|
|
438
|
+
handlers,
|
|
439
|
+
});
|
|
440
|
+
}
|
|
441
|
+
// --- Parse @InjectQueue('queue-name') producers ---
|
|
442
|
+
const injectRe = /@InjectQueue\s*\(\s*['"`]([^'"`]+)['"`]\s*\)/g;
|
|
443
|
+
let im;
|
|
444
|
+
while ((im = injectRe.exec(source)) !== null) {
|
|
445
|
+
const queueName = im[1];
|
|
446
|
+
// Find the enclosing class
|
|
447
|
+
const beforeInject = source.slice(0, im.index);
|
|
448
|
+
const lastClass = beforeInject.match(/(?:export\s+)?class\s+(\w+)[\s\S]*$/);
|
|
449
|
+
const className = lastClass ? lastClass[1] : "UnknownClass";
|
|
450
|
+
producers.push({ class_name: className, queue_name: queueName, file: file.path });
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
return {
|
|
454
|
+
processors,
|
|
455
|
+
producers,
|
|
456
|
+
...(errors.length > 0 ? { errors } : {}),
|
|
457
|
+
...(truncated ? { truncated } : {}),
|
|
458
|
+
};
|
|
459
|
+
}
|
|
460
|
+
export async function nestScopeAudit(repo, options) {
|
|
461
|
+
const index = await getCodeIndex(repo);
|
|
462
|
+
if (!index)
|
|
463
|
+
throw new Error(`Repository "${repo}" not found. Index it first with index_folder.`);
|
|
464
|
+
const maxProviders = options?.max_providers ?? 200;
|
|
465
|
+
const errors = [];
|
|
466
|
+
let truncated = false;
|
|
467
|
+
const providers = new Map();
|
|
468
|
+
const injectEdges = []; // consumer → injected
|
|
469
|
+
const candidateFiles = index.files.filter((f) => f.path.endsWith(".ts") || f.path.endsWith(".js"));
|
|
470
|
+
for (const file of candidateFiles) {
|
|
471
|
+
if (providers.size >= maxProviders) {
|
|
472
|
+
truncated = true;
|
|
473
|
+
break;
|
|
474
|
+
}
|
|
475
|
+
let source;
|
|
476
|
+
try {
|
|
477
|
+
source = await readFile(join(index.root, file.path), "utf-8");
|
|
478
|
+
}
|
|
479
|
+
catch (err) {
|
|
480
|
+
errors.push({ file: file.path, reason: `readFile failed: ${err instanceof Error ? err.message : String(err)}` });
|
|
481
|
+
continue;
|
|
482
|
+
}
|
|
483
|
+
if (!/@Injectable/.test(source))
|
|
484
|
+
continue;
|
|
485
|
+
// Parse each @Injectable class and capture scope
|
|
486
|
+
const injRe = /@Injectable\s*\(([^)]*)\)\s*(?:export\s+)?class\s+(\w+)/g;
|
|
487
|
+
let m;
|
|
488
|
+
while ((m = injRe.exec(source)) !== null) {
|
|
489
|
+
const args = m[1] ?? "";
|
|
490
|
+
const name = m[2];
|
|
491
|
+
const scopeMatch = args.match(/scope:\s*Scope\.(\w+)/);
|
|
492
|
+
const scope = (scopeMatch?.[1] ?? "DEFAULT");
|
|
493
|
+
providers.set(name, { name, file: file.path, scope });
|
|
494
|
+
// Extract constructor-injected types (simple regex — reuse existing helper via import would be cleaner)
|
|
495
|
+
const classIdx = source.indexOf(`class ${name}`);
|
|
496
|
+
if (classIdx === -1)
|
|
497
|
+
continue;
|
|
498
|
+
const classSource = source.slice(classIdx);
|
|
499
|
+
const ctorMatch = /constructor\s*\(([\s\S]*?)\)\s*\{/.exec(classSource);
|
|
500
|
+
if (!ctorMatch)
|
|
501
|
+
continue;
|
|
502
|
+
const ctorBody = ctorMatch[1];
|
|
503
|
+
// Extract type references (match `: TypeName` or generic inner)
|
|
504
|
+
const typeRe = /:\s*(\w+)(?:<\s*(\w+)\s*>)?/g;
|
|
505
|
+
let tm;
|
|
506
|
+
while ((tm = typeRe.exec(ctorBody)) !== null) {
|
|
507
|
+
const outer = tm[1];
|
|
508
|
+
const inner = tm[2];
|
|
509
|
+
// Container generic (Repository<User>) → use inner
|
|
510
|
+
const target = /^(Repository|Model|Collection|Array|Set|Map|List|Observable|Promise)$/.test(outer) && inner ? inner : outer;
|
|
511
|
+
injectEdges.push({ from: name, to: target });
|
|
512
|
+
}
|
|
513
|
+
}
|
|
514
|
+
}
|
|
515
|
+
// Build reverse index: for each target, who injects it?
|
|
516
|
+
const injectedBy = new Map();
|
|
517
|
+
for (const edge of injectEdges) {
|
|
518
|
+
if (!injectedBy.has(edge.to))
|
|
519
|
+
injectedBy.set(edge.to, new Set());
|
|
520
|
+
injectedBy.get(edge.to).add(edge.from);
|
|
521
|
+
}
|
|
522
|
+
// For each REQUEST/TRANSIENT provider, walk the reverse graph (BFS) to find all consumers
|
|
523
|
+
const walkConsumers = (startName) => {
|
|
524
|
+
const visited = new Set();
|
|
525
|
+
const queue = [startName];
|
|
526
|
+
const consumers = [];
|
|
527
|
+
while (queue.length > 0) {
|
|
528
|
+
const cur = queue.shift();
|
|
529
|
+
const parents = injectedBy.get(cur);
|
|
530
|
+
if (!parents)
|
|
531
|
+
continue;
|
|
532
|
+
for (const parent of parents) {
|
|
533
|
+
if (visited.has(parent))
|
|
534
|
+
continue;
|
|
535
|
+
visited.add(parent);
|
|
536
|
+
consumers.push(parent);
|
|
537
|
+
queue.push(parent);
|
|
538
|
+
}
|
|
539
|
+
}
|
|
540
|
+
return consumers;
|
|
541
|
+
};
|
|
542
|
+
const request_scoped = [];
|
|
543
|
+
const transient_scoped = [];
|
|
544
|
+
for (const [name, info] of providers) {
|
|
545
|
+
if (info.scope === "REQUEST") {
|
|
546
|
+
request_scoped.push({
|
|
547
|
+
provider: name,
|
|
548
|
+
scope: "REQUEST",
|
|
549
|
+
file: info.file,
|
|
550
|
+
escalated_consumers: walkConsumers(name),
|
|
551
|
+
});
|
|
552
|
+
}
|
|
553
|
+
else if (info.scope === "TRANSIENT") {
|
|
554
|
+
transient_scoped.push({
|
|
555
|
+
provider: name,
|
|
556
|
+
scope: "TRANSIENT",
|
|
557
|
+
file: info.file,
|
|
558
|
+
escalated_consumers: walkConsumers(name),
|
|
559
|
+
});
|
|
560
|
+
}
|
|
561
|
+
}
|
|
562
|
+
return {
|
|
563
|
+
request_scoped,
|
|
564
|
+
transient_scoped,
|
|
565
|
+
...(errors.length > 0 ? { errors } : {}),
|
|
566
|
+
...(truncated ? { truncated } : {}),
|
|
567
|
+
};
|
|
568
|
+
}
|
|
569
|
+
export async function nestOpenAPIExtract(repo, options) {
|
|
570
|
+
const index = await getCodeIndex(repo);
|
|
571
|
+
if (!index)
|
|
572
|
+
throw new Error(`Repository "${repo}" not found. Index it first with index_folder.`);
|
|
573
|
+
const errors = [];
|
|
574
|
+
const paths = {};
|
|
575
|
+
const schemas = {};
|
|
576
|
+
// Step 1: Extract DTO schemas from files with @ApiProperty decorators
|
|
577
|
+
const allFiles = index.files.filter((f) => {
|
|
578
|
+
if (!f.path.endsWith(".ts") && !f.path.endsWith(".js"))
|
|
579
|
+
return false;
|
|
580
|
+
if (/\.(spec|test)\./.test(f.path))
|
|
581
|
+
return false;
|
|
582
|
+
return true;
|
|
583
|
+
});
|
|
584
|
+
for (const file of allFiles) {
|
|
585
|
+
let source;
|
|
586
|
+
try {
|
|
587
|
+
source = await readFile(join(index.root, file.path), "utf-8");
|
|
588
|
+
}
|
|
589
|
+
catch (err) {
|
|
590
|
+
errors.push({ file: file.path, reason: `readFile failed: ${err instanceof Error ? err.message : String(err)}` });
|
|
591
|
+
continue;
|
|
592
|
+
}
|
|
593
|
+
if (!/@ApiProperty/.test(source))
|
|
594
|
+
continue;
|
|
595
|
+
// Parse DTO classes
|
|
596
|
+
const classRe = /(?:export\s+)?class\s+(\w+)(?:\s+extends\s+\w+)?\s*\{([\s\S]*?)^\}/gm;
|
|
597
|
+
let cm;
|
|
598
|
+
while ((cm = classRe.exec(source)) !== null) {
|
|
599
|
+
const className = cm[1];
|
|
600
|
+
const body = cm[2];
|
|
601
|
+
if (!/@ApiProperty/.test(body))
|
|
602
|
+
continue;
|
|
603
|
+
const schema = { type: "object", properties: {}, required: [] };
|
|
604
|
+
// Match @ApiProperty({ ... }) followed by field: type;
|
|
605
|
+
const propRe = /@ApiProperty(?:Optional)?\s*\(\s*(\{[^}]*\})?\s*\)\s*(?:(?:readonly|public|private)\s+)?(\w+)(\??)\s*:\s*(\w+(?:<[\w,\s]+>)?)/g;
|
|
606
|
+
let pm;
|
|
607
|
+
while ((pm = propRe.exec(body)) !== null) {
|
|
608
|
+
const argsStr = pm[1] ?? "";
|
|
609
|
+
const fieldName = pm[2];
|
|
610
|
+
const isOptional = pm[3] === "?";
|
|
611
|
+
const tsType = pm[4];
|
|
612
|
+
// Extract description/enum from args
|
|
613
|
+
const descMatch = /description:\s*['"`]([^'"`]+)['"`]/.exec(argsStr);
|
|
614
|
+
const enumMatch = /enum:\s*\[([^\]]*)\]/.exec(argsStr);
|
|
615
|
+
const prop = {
|
|
616
|
+
type: mapTsTypeToOpenAPI(tsType),
|
|
617
|
+
};
|
|
618
|
+
if (descMatch)
|
|
619
|
+
prop.description = descMatch[1];
|
|
620
|
+
if (enumMatch) {
|
|
621
|
+
prop.enum = enumMatch[1]
|
|
622
|
+
.split(",")
|
|
623
|
+
.map((s) => s.trim().replace(/^['"`]|['"`]$/g, ""))
|
|
624
|
+
.filter(Boolean);
|
|
625
|
+
}
|
|
626
|
+
schema.properties[fieldName] = prop;
|
|
627
|
+
if (!isOptional && !/@ApiPropertyOptional/.test(pm[0])) {
|
|
628
|
+
schema.required.push(fieldName);
|
|
629
|
+
}
|
|
630
|
+
}
|
|
631
|
+
if (Object.keys(schema.properties).length > 0) {
|
|
632
|
+
if (schema.required.length === 0)
|
|
633
|
+
delete schema.required;
|
|
634
|
+
schemas[className] = schema;
|
|
635
|
+
}
|
|
636
|
+
}
|
|
637
|
+
}
|
|
638
|
+
// Step 2: Extract routes from controllers + project @ApiOperation/@ApiResponse into paths
|
|
639
|
+
const controllerFiles = index.files.filter((f) => f.path.endsWith(".controller.ts"));
|
|
640
|
+
for (const file of controllerFiles) {
|
|
641
|
+
let source;
|
|
642
|
+
try {
|
|
643
|
+
source = await readFile(join(index.root, file.path), "utf-8");
|
|
644
|
+
}
|
|
645
|
+
catch (err) {
|
|
646
|
+
errors.push({ file: file.path, reason: `readFile failed: ${err instanceof Error ? err.message : String(err)}` });
|
|
647
|
+
continue;
|
|
648
|
+
}
|
|
649
|
+
// Controller prefix
|
|
650
|
+
const ctrlMatch = /@Controller\s*\(\s*(?:['"`]([^'"`]*)['"`]|\{[^}]*path:\s*['"`]([^'"`]*)['"`])/.exec(source);
|
|
651
|
+
const ctrlPrefix = ctrlMatch?.[1] ?? ctrlMatch?.[2] ?? "";
|
|
652
|
+
// @ApiTags at class level
|
|
653
|
+
const tagsMatch = /@ApiTags\s*\(\s*((?:['"`][^'"`]+['"`]\s*,?\s*)+)\)/.exec(source);
|
|
654
|
+
const tags = tagsMatch
|
|
655
|
+
? [...tagsMatch[1].matchAll(/['"`]([^'"`]+)['"`]/g)].map((m) => m[1])
|
|
656
|
+
: undefined;
|
|
657
|
+
// Each HTTP method decorator
|
|
658
|
+
const methods = ["Get", "Post", "Put", "Delete", "Patch", "All", "Head", "Options"];
|
|
659
|
+
for (const method of methods) {
|
|
660
|
+
const methodRe = new RegExp(`@${method}\\s*\\(\\s*(?:['"\`]([^'"\`]*)['"\`])?\\s*\\)`, "g");
|
|
661
|
+
let mm;
|
|
662
|
+
while ((mm = methodRe.exec(source)) !== null) {
|
|
663
|
+
const routePath = mm[1] ?? "";
|
|
664
|
+
// Scan forward 500 chars for stacked @Api* decorators + handler name
|
|
665
|
+
const lookFwd = source.slice(mm.index, mm.index + 800);
|
|
666
|
+
const summaryMatch = /@ApiOperation\s*\(\s*\{[^}]*summary:\s*['"`]([^'"`]+)['"`]/.exec(lookFwd);
|
|
667
|
+
const descMatch = /@ApiOperation\s*\(\s*\{[^}]*description:\s*['"`]([^'"`]+)['"`]/.exec(lookFwd);
|
|
668
|
+
const bearerMatch = /@ApiBearerAuth\s*\(/.test(lookFwd);
|
|
669
|
+
// Collect @ApiResponse decorators
|
|
670
|
+
const responses = {};
|
|
671
|
+
const respRe = /@ApiResponse\s*\(\s*\{\s*status:\s*(\d+)(?:[\s\S]*?description:\s*['"`]([^'"`]+)['"`])?(?:[\s\S]*?type:\s*(\w+))?/g;
|
|
672
|
+
let rm;
|
|
673
|
+
while ((rm = respRe.exec(lookFwd)) !== null) {
|
|
674
|
+
const status = rm[1];
|
|
675
|
+
const description = rm[2];
|
|
676
|
+
const type = rm[3];
|
|
677
|
+
responses[status] = {
|
|
678
|
+
...(description ? { description } : {}),
|
|
679
|
+
...(type ? { content: { "application/json": { schema: { $ref: `#/components/schemas/${type}` } } } } : {}),
|
|
680
|
+
};
|
|
681
|
+
}
|
|
682
|
+
// Default 200 if no @ApiResponse
|
|
683
|
+
if (Object.keys(responses).length === 0) {
|
|
684
|
+
responses["200"] = { description: "Success" };
|
|
685
|
+
}
|
|
686
|
+
// @Param / @Query / @Body
|
|
687
|
+
const parameters = [];
|
|
688
|
+
const paramRe = /@(Param|Query)\s*\(\s*['"`](\w+)['"`]\s*\)\s*(\w+)\s*:\s*(\w+)/g;
|
|
689
|
+
let pm2;
|
|
690
|
+
while ((pm2 = paramRe.exec(lookFwd)) !== null) {
|
|
691
|
+
parameters.push({
|
|
692
|
+
name: pm2[2],
|
|
693
|
+
in: pm2[1] === "Param" ? "path" : "query",
|
|
694
|
+
required: pm2[1] === "Param", // path params always required
|
|
695
|
+
schema: { type: mapTsTypeToOpenAPI(pm2[4]) },
|
|
696
|
+
});
|
|
697
|
+
}
|
|
698
|
+
let requestBody;
|
|
699
|
+
const bodyMatch = /@Body\s*\(\s*\)\s*(\w+)\s*:\s*(\w+)/.exec(lookFwd);
|
|
700
|
+
if (bodyMatch) {
|
|
701
|
+
requestBody = {
|
|
702
|
+
content: { "application/json": { schema: { $ref: `#/components/schemas/${bodyMatch[2]}` } } },
|
|
703
|
+
};
|
|
704
|
+
}
|
|
705
|
+
const fullPath = `/${ctrlPrefix}/${routePath}`.replace(/\/+/g, "/").replace(/\/$/, "") || "/";
|
|
706
|
+
if (!paths[fullPath])
|
|
707
|
+
paths[fullPath] = {};
|
|
708
|
+
const op = {
|
|
709
|
+
path: fullPath,
|
|
710
|
+
method: method.toUpperCase(),
|
|
711
|
+
parameters,
|
|
712
|
+
responses,
|
|
713
|
+
};
|
|
714
|
+
if (summaryMatch)
|
|
715
|
+
op.summary = summaryMatch[1];
|
|
716
|
+
if (descMatch)
|
|
717
|
+
op.description = descMatch[1];
|
|
718
|
+
if (tags)
|
|
719
|
+
op.tags = tags;
|
|
720
|
+
if (bearerMatch)
|
|
721
|
+
op.security = [{ bearer: [] }];
|
|
722
|
+
if (requestBody)
|
|
723
|
+
op.requestBody = requestBody;
|
|
724
|
+
paths[fullPath][method.toLowerCase()] = op;
|
|
725
|
+
}
|
|
726
|
+
}
|
|
727
|
+
}
|
|
728
|
+
return {
|
|
729
|
+
openapi: "3.1.0",
|
|
730
|
+
info: {
|
|
731
|
+
title: options?.title ?? "NestJS API",
|
|
732
|
+
version: options?.version ?? "1.0.0",
|
|
733
|
+
},
|
|
734
|
+
paths,
|
|
735
|
+
components: { schemas },
|
|
736
|
+
...(errors.length > 0 ? { errors } : {}),
|
|
737
|
+
};
|
|
738
|
+
}
|
|
739
|
+
/** Map TypeScript type names to OpenAPI 3.1 primitive types */
|
|
740
|
+
function mapTsTypeToOpenAPI(tsType) {
|
|
741
|
+
const normalized = tsType.replace(/<.*>/, "").trim();
|
|
742
|
+
switch (normalized) {
|
|
743
|
+
case "string": return "string";
|
|
744
|
+
case "number": return "number";
|
|
745
|
+
case "boolean": return "boolean";
|
|
746
|
+
case "Date": return "string";
|
|
747
|
+
case "Array":
|
|
748
|
+
case "any[]": return "array";
|
|
749
|
+
default: return "object";
|
|
750
|
+
}
|
|
751
|
+
}
|
|
752
|
+
//# sourceMappingURL=nest-ext-tools.js.map
|