codesift-mcp 0.9.5 → 0.10.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 +62 -23
- package/dist/cli/commands.d.ts.map +1 -1
- package/dist/cli/commands.js +92 -2
- package/dist/cli/commands.js.map +1 -1
- package/dist/cli/help.d.ts +1 -1
- package/dist/cli/help.d.ts.map +1 -1
- package/dist/cli/help.js +18 -0
- package/dist/cli/help.js.map +1 -1
- package/dist/cli/hooks/input.d.ts +11 -0
- package/dist/cli/hooks/input.d.ts.map +1 -0
- package/dist/cli/hooks/input.js +111 -0
- package/dist/cli/hooks/input.js.map +1 -0
- package/dist/cli/hooks/post-tool-use.d.ts +2 -0
- package/dist/cli/hooks/post-tool-use.d.ts.map +1 -0
- package/dist/cli/hooks/post-tool-use.js +339 -0
- package/dist/cli/hooks/post-tool-use.js.map +1 -0
- package/dist/cli/hooks/pre-compact.d.ts +2 -0
- package/dist/cli/hooks/pre-compact.d.ts.map +1 -0
- package/dist/cli/hooks/pre-compact.js +41 -0
- package/dist/cli/hooks/pre-compact.js.map +1 -0
- package/dist/cli/hooks/pre-tool-use.d.ts +5 -0
- package/dist/cli/hooks/pre-tool-use.d.ts.map +1 -0
- package/dist/cli/hooks/pre-tool-use.js +215 -0
- package/dist/cli/hooks/pre-tool-use.js.map +1 -0
- package/dist/cli/hooks/session.d.ts +5 -0
- package/dist/cli/hooks/session.d.ts.map +1 -0
- package/dist/cli/hooks/session.js +188 -0
- package/dist/cli/hooks/session.js.map +1 -0
- package/dist/cli/hooks/shared.d.ts +6 -0
- package/dist/cli/hooks/shared.d.ts.map +1 -0
- package/dist/cli/hooks/shared.js +70 -0
- package/dist/cli/hooks/shared.js.map +1 -0
- package/dist/cli/hooks/wiki.d.ts +10 -0
- package/dist/cli/hooks/wiki.d.ts.map +1 -0
- package/dist/cli/hooks/wiki.js +202 -0
- package/dist/cli/hooks/wiki.js.map +1 -0
- package/dist/cli/hooks.d.ts +5 -16
- package/dist/cli/hooks.d.ts.map +1 -1
- package/dist/cli/hooks.js +5 -1132
- package/dist/cli/hooks.js.map +1 -1
- package/dist/cli/setup/claude.d.ts +4 -0
- package/dist/cli/setup/claude.d.ts.map +1 -0
- package/dist/cli/setup/claude.js +123 -0
- package/dist/cli/setup/claude.js.map +1 -0
- package/dist/cli/setup/codex.d.ts +12 -0
- package/dist/cli/setup/codex.d.ts.map +1 -0
- package/dist/cli/setup/codex.js +182 -0
- package/dist/cli/setup/codex.js.map +1 -0
- package/dist/cli/setup/cursor.d.ts +3 -0
- package/dist/cli/setup/cursor.d.ts.map +1 -0
- package/dist/cli/setup/cursor.js +6 -0
- package/dist/cli/setup/cursor.js.map +1 -0
- package/dist/cli/setup/fs.d.ts +6 -0
- package/dist/cli/setup/fs.d.ts.map +1 -0
- package/dist/cli/setup/fs.js +44 -0
- package/dist/cli/setup/fs.js.map +1 -0
- package/dist/cli/setup/gemini.d.ts +5 -0
- package/dist/cli/setup/gemini.d.ts.map +1 -0
- package/dist/cli/setup/gemini.js +46 -0
- package/dist/cli/setup/gemini.js.map +1 -0
- package/dist/cli/setup/hooks.d.ts +12 -0
- package/dist/cli/setup/hooks.d.ts.map +1 -0
- package/dist/cli/setup/hooks.js +29 -0
- package/dist/cli/setup/hooks.js.map +1 -0
- package/dist/cli/setup/mcp.d.ts +13 -0
- package/dist/cli/setup/mcp.d.ts.map +1 -0
- package/dist/cli/setup/mcp.js +104 -0
- package/dist/cli/setup/mcp.js.map +1 -0
- package/dist/cli/setup/rules.d.ts +4 -0
- package/dist/cli/setup/rules.d.ts.map +1 -0
- package/dist/cli/setup/rules.js +157 -0
- package/dist/cli/setup/rules.js.map +1 -0
- package/dist/cli/setup/types.d.ts +24 -0
- package/dist/cli/setup/types.d.ts.map +1 -0
- package/dist/cli/setup/types.js +2 -0
- package/dist/cli/setup/types.js.map +1 -0
- package/dist/cli/setup.d.ts +8 -48
- package/dist/cli/setup.d.ts.map +1 -1
- package/dist/cli/setup.js +49 -705
- package/dist/cli/setup.js.map +1 -1
- package/dist/cli/telemetry-commands.d.ts +2 -0
- package/dist/cli/telemetry-commands.d.ts.map +1 -0
- package/dist/cli/telemetry-commands.js +50 -0
- package/dist/cli/telemetry-commands.js.map +1 -0
- package/dist/config.d.ts +15 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +56 -2
- package/dist/config.js.map +1 -1
- package/dist/formatter-dispatch.d.ts +53 -0
- package/dist/formatter-dispatch.d.ts.map +1 -0
- package/dist/formatter-dispatch.js +54 -0
- package/dist/formatter-dispatch.js.map +1 -0
- package/dist/formatters-analysis.d.ts +9 -0
- package/dist/formatters-analysis.d.ts.map +1 -0
- package/dist/formatters-analysis.js +166 -0
- package/dist/formatters-analysis.js.map +1 -0
- package/dist/formatters-core.d.ts +200 -0
- package/dist/formatters-core.d.ts.map +1 -0
- package/dist/formatters-core.js +206 -0
- package/dist/formatters-core.js.map +1 -0
- package/dist/formatters-graph.d.ts +124 -0
- package/dist/formatters-graph.d.ts.map +1 -0
- package/dist/formatters-graph.js +175 -0
- package/dist/formatters-graph.js.map +1 -0
- package/dist/formatters-nextjs.d.ts +22 -0
- package/dist/formatters-nextjs.d.ts.map +1 -0
- package/dist/formatters-nextjs.js +394 -0
- package/dist/formatters-nextjs.js.map +1 -0
- package/dist/formatters.d.ts +8 -349
- package/dist/formatters.d.ts.map +1 -1
- package/dist/formatters.js +10 -929
- package/dist/formatters.js.map +1 -1
- package/dist/parser/astro-template/preprocess.d.ts +12 -0
- package/dist/parser/astro-template/preprocess.d.ts.map +1 -0
- package/dist/parser/astro-template/preprocess.js +34 -0
- package/dist/parser/astro-template/preprocess.js.map +1 -0
- package/dist/parser/astro-template/resolution.d.ts +16 -0
- package/dist/parser/astro-template/resolution.d.ts.map +1 -0
- package/dist/parser/astro-template/resolution.js +58 -0
- package/dist/parser/astro-template/resolution.js.map +1 -0
- package/dist/parser/astro-template/scanner.d.ts +4 -0
- package/dist/parser/astro-template/scanner.d.ts.map +1 -0
- package/dist/parser/astro-template/scanner.js +71 -0
- package/dist/parser/astro-template/scanner.js.map +1 -0
- package/dist/parser/astro-template/state.d.ts +22 -0
- package/dist/parser/astro-template/state.d.ts.map +1 -0
- package/dist/parser/astro-template/state.js +48 -0
- package/dist/parser/astro-template/state.js.map +1 -0
- package/dist/parser/astro-template/tag-processor.d.ts +3 -0
- package/dist/parser/astro-template/tag-processor.d.ts.map +1 -0
- package/dist/parser/astro-template/tag-processor.js +63 -0
- package/dist/parser/astro-template/tag-processor.js.map +1 -0
- package/dist/parser/astro-template/types.d.ts +42 -0
- package/dist/parser/astro-template/types.d.ts.map +1 -0
- package/dist/parser/astro-template/types.js +2 -0
- package/dist/parser/astro-template/types.js.map +1 -0
- package/dist/parser/astro-template.d.ts +2 -45
- package/dist/parser/astro-template.d.ts.map +1 -1
- package/dist/parser/astro-template.js +7 -168
- package/dist/parser/astro-template.js.map +1 -1
- package/dist/parser/extractors/_shared.js +1 -1
- package/dist/parser/extractors/_shared.js.map +1 -1
- package/dist/parser/extractors/astro.js +1 -1
- package/dist/parser/extractors/astro.js.map +1 -1
- package/dist/parser/extractors/conversation.js +1 -1
- package/dist/parser/extractors/conversation.js.map +1 -1
- package/dist/parser/extractors/hono-app-discovery.d.ts +4 -0
- package/dist/parser/extractors/hono-app-discovery.d.ts.map +1 -0
- package/dist/parser/extractors/hono-app-discovery.js +169 -0
- package/dist/parser/extractors/hono-app-discovery.js.map +1 -0
- package/dist/parser/extractors/hono-ast-utils.d.ts +6 -0
- package/dist/parser/extractors/hono-ast-utils.d.ts.map +1 -0
- package/dist/parser/extractors/hono-ast-utils.js +77 -0
- package/dist/parser/extractors/hono-ast-utils.js.map +1 -0
- package/dist/parser/extractors/hono-context-extractor.d.ts +15 -0
- package/dist/parser/extractors/hono-context-extractor.d.ts.map +1 -0
- package/dist/parser/extractors/hono-context-extractor.js +191 -0
- package/dist/parser/extractors/hono-context-extractor.js.map +1 -0
- package/dist/parser/extractors/hono-middleware-extractor.d.ts +38 -0
- package/dist/parser/extractors/hono-middleware-extractor.d.ts.map +1 -0
- package/dist/parser/extractors/hono-middleware-extractor.js +480 -0
- package/dist/parser/extractors/hono-middleware-extractor.js.map +1 -0
- package/dist/parser/extractors/hono-openapi-extractor.d.ts +11 -0
- package/dist/parser/extractors/hono-openapi-extractor.d.ts.map +1 -0
- package/dist/parser/extractors/hono-openapi-extractor.js +119 -0
- package/dist/parser/extractors/hono-openapi-extractor.js.map +1 -0
- package/dist/parser/extractors/hono-route-extractor.d.ts +11 -0
- package/dist/parser/extractors/hono-route-extractor.d.ts.map +1 -0
- package/dist/parser/extractors/hono-route-extractor.js +128 -0
- package/dist/parser/extractors/hono-route-extractor.js.map +1 -0
- package/dist/parser/extractors/hono-route-utils.d.ts +11 -0
- package/dist/parser/extractors/hono-route-utils.d.ts.map +1 -0
- package/dist/parser/extractors/hono-route-utils.js +40 -0
- package/dist/parser/extractors/hono-route-utils.js.map +1 -0
- package/dist/parser/extractors/hono-runtime-extractor.d.ts +17 -0
- package/dist/parser/extractors/hono-runtime-extractor.d.ts.map +1 -0
- package/dist/parser/extractors/hono-runtime-extractor.js +141 -0
- package/dist/parser/extractors/hono-runtime-extractor.js.map +1 -0
- package/dist/parser/extractors/hono.d.ts +5 -79
- package/dist/parser/extractors/hono.d.ts.map +1 -1
- package/dist/parser/extractors/hono.js +32 -1159
- package/dist/parser/extractors/hono.js.map +1 -1
- package/dist/parser/extractors/kotlin-ast-helpers.d.ts +43 -0
- package/dist/parser/extractors/kotlin-ast-helpers.d.ts.map +1 -0
- package/dist/parser/extractors/kotlin-ast-helpers.js +187 -0
- package/dist/parser/extractors/kotlin-ast-helpers.js.map +1 -0
- package/dist/parser/extractors/kotlin-test-symbols.d.ts +21 -0
- package/dist/parser/extractors/kotlin-test-symbols.d.ts.map +1 -0
- package/dist/parser/extractors/kotlin-test-symbols.js +162 -0
- package/dist/parser/extractors/kotlin-test-symbols.js.map +1 -0
- package/dist/parser/extractors/kotlin.d.ts.map +1 -1
- package/dist/parser/extractors/kotlin.js +3 -334
- package/dist/parser/extractors/kotlin.js.map +1 -1
- package/dist/parser/extractors/markdown.js +1 -1
- package/dist/parser/extractors/markdown.js.map +1 -1
- package/dist/parser/extractors/prisma.js +1 -1
- package/dist/parser/extractors/prisma.js.map +1 -1
- package/dist/parser/extractors/sql-boundaries.d.ts +3 -0
- package/dist/parser/extractors/sql-boundaries.d.ts.map +1 -0
- package/dist/parser/extractors/sql-boundaries.js +19 -0
- package/dist/parser/extractors/sql-boundaries.js.map +1 -0
- package/dist/parser/extractors/sql-columns.d.ts +14 -0
- package/dist/parser/extractors/sql-columns.d.ts.map +1 -0
- package/dist/parser/extractors/sql-columns.js +59 -0
- package/dist/parser/extractors/sql-columns.js.map +1 -0
- package/dist/parser/extractors/sql-docstrings.d.ts +2 -0
- package/dist/parser/extractors/sql-docstrings.d.ts.map +1 -0
- package/dist/parser/extractors/sql-docstrings.js +45 -0
- package/dist/parser/extractors/sql-docstrings.js.map +1 -0
- package/dist/parser/extractors/sql-end-scanner.d.ts +5 -0
- package/dist/parser/extractors/sql-end-scanner.d.ts.map +1 -0
- package/dist/parser/extractors/sql-end-scanner.js +84 -0
- package/dist/parser/extractors/sql-end-scanner.js.map +1 -0
- package/dist/parser/extractors/sql-jinja.d.ts +2 -0
- package/dist/parser/extractors/sql-jinja.d.ts.map +1 -0
- package/dist/parser/extractors/sql-jinja.js +8 -0
- package/dist/parser/extractors/sql-jinja.js.map +1 -0
- package/dist/parser/extractors/sql-matcher-catalog.d.ts +9 -0
- package/dist/parser/extractors/sql-matcher-catalog.d.ts.map +1 -0
- package/dist/parser/extractors/sql-matcher-catalog.js +15 -0
- package/dist/parser/extractors/sql-matcher-catalog.js.map +1 -0
- package/dist/parser/extractors/sql-matchers.d.ts +9 -0
- package/dist/parser/extractors/sql-matchers.d.ts.map +1 -0
- package/dist/parser/extractors/sql-matchers.js +20 -0
- package/dist/parser/extractors/sql-matchers.js.map +1 -0
- package/dist/parser/extractors/sql-offsets.d.ts +2 -0
- package/dist/parser/extractors/sql-offsets.d.ts.map +1 -0
- package/dist/parser/extractors/sql-offsets.js +25 -0
- package/dist/parser/extractors/sql-offsets.js.map +1 -0
- package/dist/parser/extractors/sql-parens.d.ts +4 -0
- package/dist/parser/extractors/sql-parens.d.ts.map +1 -0
- package/dist/parser/extractors/sql-parens.js +70 -0
- package/dist/parser/extractors/sql-parens.js.map +1 -0
- package/dist/parser/extractors/sql-symbols.d.ts +11 -0
- package/dist/parser/extractors/sql-symbols.d.ts.map +1 -0
- package/dist/parser/extractors/sql-symbols.js +23 -0
- package/dist/parser/extractors/sql-symbols.js.map +1 -0
- package/dist/parser/extractors/sql.d.ts +2 -30
- package/dist/parser/extractors/sql.d.ts.map +1 -1
- package/dist/parser/extractors/sql.js +23 -496
- package/dist/parser/extractors/sql.js.map +1 -1
- package/dist/parser/extractors/typescript-cjs-nodes.d.ts +5 -0
- package/dist/parser/extractors/typescript-cjs-nodes.d.ts.map +1 -0
- package/dist/parser/extractors/typescript-cjs-nodes.js +148 -0
- package/dist/parser/extractors/typescript-cjs-nodes.js.map +1 -0
- package/dist/parser/extractors/typescript-class-nodes.d.ts +8 -0
- package/dist/parser/extractors/typescript-class-nodes.d.ts.map +1 -0
- package/dist/parser/extractors/typescript-class-nodes.js +183 -0
- package/dist/parser/extractors/typescript-class-nodes.js.map +1 -0
- package/dist/parser/extractors/typescript-declaration-nodes.d.ts +5 -0
- package/dist/parser/extractors/typescript-declaration-nodes.d.ts.map +1 -0
- package/dist/parser/extractors/typescript-declaration-nodes.js +105 -0
- package/dist/parser/extractors/typescript-declaration-nodes.js.map +1 -0
- package/dist/parser/extractors/typescript-module-nodes.d.ts +6 -0
- package/dist/parser/extractors/typescript-module-nodes.d.ts.map +1 -0
- package/dist/parser/extractors/typescript-module-nodes.js +151 -0
- package/dist/parser/extractors/typescript-module-nodes.js.map +1 -0
- package/dist/parser/extractors/typescript-react.d.ts +11 -0
- package/dist/parser/extractors/typescript-react.d.ts.map +1 -0
- package/dist/parser/extractors/typescript-react.js +101 -0
- package/dist/parser/extractors/typescript-react.js.map +1 -0
- package/dist/parser/extractors/typescript-shared.d.ts +26 -0
- package/dist/parser/extractors/typescript-shared.d.ts.map +1 -0
- package/dist/parser/extractors/typescript-shared.js +101 -0
- package/dist/parser/extractors/typescript-shared.js.map +1 -0
- package/dist/parser/extractors/typescript-test-nodes.d.ts +4 -0
- package/dist/parser/extractors/typescript-test-nodes.d.ts.map +1 -0
- package/dist/parser/extractors/typescript-test-nodes.js +112 -0
- package/dist/parser/extractors/typescript-test-nodes.js.map +1 -0
- package/dist/parser/extractors/typescript-type-nodes.d.ts +6 -0
- package/dist/parser/extractors/typescript-type-nodes.d.ts.map +1 -0
- package/dist/parser/extractors/typescript-type-nodes.js +48 -0
- package/dist/parser/extractors/typescript-type-nodes.js.map +1 -0
- package/dist/parser/extractors/typescript.d.ts.map +1 -1
- package/dist/parser/extractors/typescript.js +68 -1127
- package/dist/parser/extractors/typescript.js.map +1 -1
- package/dist/parser/parser-manager.d.ts.map +1 -1
- package/dist/parser/parser-manager.js +5 -0
- package/dist/parser/parser-manager.js.map +1 -1
- package/dist/parser/symbol-extractor.d.ts +1 -12
- package/dist/parser/symbol-extractor.d.ts.map +1 -1
- package/dist/parser/symbol-extractor.js +2 -24
- package/dist/parser/symbol-extractor.js.map +1 -1
- package/dist/parser/symbol-utils.d.ts +4 -0
- package/dist/parser/symbol-utils.d.ts.map +1 -0
- package/dist/parser/symbol-utils.js +20 -0
- package/dist/parser/symbol-utils.js.map +1 -0
- package/dist/register-tool-groups/analysis/cross-repo.d.ts +4 -0
- package/dist/register-tool-groups/analysis/cross-repo.d.ts.map +1 -0
- package/dist/register-tool-groups/analysis/cross-repo.js +108 -0
- package/dist/register-tool-groups/analysis/cross-repo.js.map +1 -0
- package/dist/register-tool-groups/analysis/review.d.ts +3 -0
- package/dist/register-tool-groups/analysis/review.d.ts.map +1 -0
- package/dist/register-tool-groups/analysis/review.js +96 -0
- package/dist/register-tool-groups/analysis/review.js.map +1 -0
- package/dist/register-tool-groups/analysis/workspace.d.ts +3 -0
- package/dist/register-tool-groups/analysis/workspace.d.ts.map +1 -0
- package/dist/register-tool-groups/analysis/workspace.js +82 -0
- package/dist/register-tool-groups/analysis/workspace.js.map +1 -0
- package/dist/register-tool-groups/analysis.d.ts +3 -0
- package/dist/register-tool-groups/analysis.d.ts.map +1 -0
- package/dist/register-tool-groups/analysis.js +541 -0
- package/dist/register-tool-groups/analysis.js.map +1 -0
- package/dist/register-tool-groups/astro.d.ts +3 -0
- package/dist/register-tool-groups/astro.d.ts.map +1 -0
- package/dist/register-tool-groups/astro.js +302 -0
- package/dist/register-tool-groups/astro.js.map +1 -0
- package/dist/register-tool-groups/core/index.d.ts +3 -0
- package/dist/register-tool-groups/core/index.d.ts.map +1 -0
- package/dist/register-tool-groups/core/index.js +96 -0
- package/dist/register-tool-groups/core/index.js.map +1 -0
- package/dist/register-tool-groups/core/meta.d.ts +3 -0
- package/dist/register-tool-groups/core/meta.d.ts.map +1 -0
- package/dist/register-tool-groups/core/meta.js +180 -0
- package/dist/register-tool-groups/core/meta.js.map +1 -0
- package/dist/register-tool-groups/core/schema.d.ts +3 -0
- package/dist/register-tool-groups/core/schema.d.ts.map +1 -0
- package/dist/register-tool-groups/core/schema.js +16 -0
- package/dist/register-tool-groups/core/schema.js.map +1 -0
- package/dist/register-tool-groups/core/search.d.ts +4 -0
- package/dist/register-tool-groups/core/search.d.ts.map +1 -0
- package/dist/register-tool-groups/core/search.js +262 -0
- package/dist/register-tool-groups/core/search.js.map +1 -0
- package/dist/register-tool-groups/core/symbols.d.ts +3 -0
- package/dist/register-tool-groups/core/symbols.d.ts.map +1 -0
- package/dist/register-tool-groups/core/symbols.js +338 -0
- package/dist/register-tool-groups/core/symbols.js.map +1 -0
- package/dist/register-tool-groups/core.d.ts +3 -0
- package/dist/register-tool-groups/core.d.ts.map +1 -0
- package/dist/register-tool-groups/core.js +12 -0
- package/dist/register-tool-groups/core.js.map +1 -0
- package/dist/register-tool-groups/deps.d.ts +10 -0
- package/dist/register-tool-groups/deps.d.ts.map +1 -0
- package/dist/register-tool-groups/deps.js +6 -0
- package/dist/register-tool-groups/deps.js.map +1 -0
- package/dist/register-tool-groups/handler-wrappers.d.ts +63 -0
- package/dist/register-tool-groups/handler-wrappers.d.ts.map +1 -0
- package/dist/register-tool-groups/handler-wrappers.js +106 -0
- package/dist/register-tool-groups/handler-wrappers.js.map +1 -0
- package/dist/register-tool-groups/hono.d.ts +3 -0
- package/dist/register-tool-groups/hono.d.ts.map +1 -0
- package/dist/register-tool-groups/hono.js +179 -0
- package/dist/register-tool-groups/hono.js.map +1 -0
- package/dist/register-tool-groups/index.d.ts +3 -0
- package/dist/register-tool-groups/index.d.ts.map +1 -0
- package/dist/register-tool-groups/index.js +28 -0
- package/dist/register-tool-groups/index.js.map +1 -0
- package/dist/register-tool-groups/kotlin.d.ts +3 -0
- package/dist/register-tool-groups/kotlin.d.ts.map +1 -0
- package/dist/register-tool-groups/kotlin.js +162 -0
- package/dist/register-tool-groups/kotlin.js.map +1 -0
- package/dist/register-tool-groups/meta.d.ts +3 -0
- package/dist/register-tool-groups/meta.d.ts.map +1 -0
- package/dist/register-tool-groups/meta.js +563 -0
- package/dist/register-tool-groups/meta.js.map +1 -0
- package/dist/register-tool-groups/nextjs.d.ts +3 -0
- package/dist/register-tool-groups/nextjs.d.ts.map +1 -0
- package/dist/register-tool-groups/nextjs.js +78 -0
- package/dist/register-tool-groups/nextjs.js.map +1 -0
- package/dist/register-tool-groups/php.d.ts +3 -0
- package/dist/register-tool-groups/php.d.ts.map +1 -0
- package/dist/register-tool-groups/php.js +312 -0
- package/dist/register-tool-groups/php.js.map +1 -0
- package/dist/register-tool-groups/python.d.ts +3 -0
- package/dist/register-tool-groups/python.d.ts.map +1 -0
- package/dist/register-tool-groups/python.js +366 -0
- package/dist/register-tool-groups/python.js.map +1 -0
- package/dist/register-tool-groups/react.d.ts +3 -0
- package/dist/register-tool-groups/react.d.ts.map +1 -0
- package/dist/register-tool-groups/react.js +119 -0
- package/dist/register-tool-groups/react.js.map +1 -0
- package/dist/register-tool-groups/shared.d.ts +156 -0
- package/dist/register-tool-groups/shared.d.ts.map +1 -0
- package/dist/register-tool-groups/shared.js +182 -0
- package/dist/register-tool-groups/shared.js.map +1 -0
- package/dist/register-tool-groups/sql.d.ts +3 -0
- package/dist/register-tool-groups/sql.d.ts.map +1 -0
- package/dist/register-tool-groups/sql.js +260 -0
- package/dist/register-tool-groups/sql.js.map +1 -0
- package/dist/register-tool-loaders.d.ts +22 -22
- package/dist/register-tool-loaders.d.ts.map +1 -1
- package/dist/register-tools/autoload.d.ts +8 -0
- package/dist/register-tools/autoload.d.ts.map +1 -0
- package/dist/register-tools/autoload.js +517 -0
- package/dist/register-tools/autoload.js.map +1 -0
- package/dist/register-tools/discovery.d.ts +55 -0
- package/dist/register-tools/discovery.d.ts.map +1 -0
- package/dist/register-tools/discovery.js +206 -0
- package/dist/register-tools/discovery.js.map +1 -0
- package/dist/register-tools/runtime.d.ts +89 -0
- package/dist/register-tools/runtime.d.ts.map +1 -0
- package/dist/register-tools/runtime.js +491 -0
- package/dist/register-tools/runtime.js.map +1 -0
- package/dist/register-tools.d.ts +5 -172
- package/dist/register-tools.d.ts.map +1 -1
- package/dist/register-tools.js +27 -4878
- package/dist/register-tools.js.map +1 -1
- package/dist/search/bm25.js +1 -1
- package/dist/search/bm25.js.map +1 -1
- package/dist/search/tool-embedding-cache.d.ts +4 -0
- package/dist/search/tool-embedding-cache.d.ts.map +1 -0
- package/dist/search/tool-embedding-cache.js +44 -0
- package/dist/search/tool-embedding-cache.js.map +1 -0
- package/dist/search/tool-embedding-storage.d.ts +8 -0
- package/dist/search/tool-embedding-storage.d.ts.map +1 -0
- package/dist/search/tool-embedding-storage.js +56 -0
- package/dist/search/tool-embedding-storage.js.map +1 -0
- package/dist/search/tool-ranker-bm25.d.ts +6 -0
- package/dist/search/tool-ranker-bm25.d.ts.map +1 -0
- package/dist/search/tool-ranker-bm25.js +40 -0
- package/dist/search/tool-ranker-bm25.js.map +1 -0
- package/dist/search/tool-ranker-orchestrator.d.ts +3 -0
- package/dist/search/tool-ranker-orchestrator.d.ts.map +1 -0
- package/dist/search/tool-ranker-orchestrator.js +49 -0
- package/dist/search/tool-ranker-orchestrator.js.map +1 -0
- package/dist/search/tool-ranker-reasoning.d.ts +4 -0
- package/dist/search/tool-ranker-reasoning.d.ts.map +1 -0
- package/dist/search/tool-ranker-reasoning.js +35 -0
- package/dist/search/tool-ranker-reasoning.js.map +1 -0
- package/dist/search/tool-ranker-signal-math.d.ts +6 -0
- package/dist/search/tool-ranker-signal-math.d.ts.map +1 -0
- package/dist/search/tool-ranker-signal-math.js +51 -0
- package/dist/search/tool-ranker-signal-math.js.map +1 -0
- package/dist/search/tool-ranker-signals.d.ts +20 -0
- package/dist/search/tool-ranker-signals.d.ts.map +1 -0
- package/dist/search/tool-ranker-signals.js +50 -0
- package/dist/search/tool-ranker-signals.js.map +1 -0
- package/dist/search/tool-ranker-types.d.ts +26 -0
- package/dist/search/tool-ranker-types.d.ts.map +1 -0
- package/dist/search/tool-ranker-types.js +2 -0
- package/dist/search/tool-ranker-types.js.map +1 -0
- package/dist/search/tool-ranker.d.ts +6 -89
- package/dist/search/tool-ranker.d.ts.map +1 -1
- package/dist/search/tool-ranker.js +5 -419
- package/dist/search/tool-ranker.js.map +1 -1
- package/dist/server-helpers/repo-resolution.d.ts +45 -0
- package/dist/server-helpers/repo-resolution.d.ts.map +1 -0
- package/dist/server-helpers/repo-resolution.js +113 -0
- package/dist/server-helpers/repo-resolution.js.map +1 -0
- package/dist/server-helpers/response-hints.d.ts +9 -0
- package/dist/server-helpers/response-hints.d.ts.map +1 -0
- package/dist/server-helpers/response-hints.js +225 -0
- package/dist/server-helpers/response-hints.js.map +1 -0
- package/dist/server-helpers.d.ts +14 -35
- package/dist/server-helpers.d.ts.map +1 -1
- package/dist/server-helpers.js +62 -322
- package/dist/server-helpers.js.map +1 -1
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +45 -0
- package/dist/server.js.map +1 -1
- package/dist/storage/_shared.d.ts +9 -0
- package/dist/storage/_shared.d.ts.map +1 -1
- package/dist/storage/_shared.js +24 -0
- package/dist/storage/_shared.js.map +1 -1
- package/dist/storage/telemetry/aggregator.d.ts +52 -0
- package/dist/storage/telemetry/aggregator.d.ts.map +1 -0
- package/dist/storage/telemetry/aggregator.js +188 -0
- package/dist/storage/telemetry/aggregator.js.map +1 -0
- package/dist/storage/telemetry/anon-id.d.ts +11 -0
- package/dist/storage/telemetry/anon-id.d.ts.map +1 -0
- package/dist/storage/telemetry/anon-id.js +62 -0
- package/dist/storage/telemetry/anon-id.js.map +1 -0
- package/dist/storage/telemetry/config.d.ts +37 -0
- package/dist/storage/telemetry/config.d.ts.map +1 -0
- package/dist/storage/telemetry/config.js +130 -0
- package/dist/storage/telemetry/config.js.map +1 -0
- package/dist/storage/telemetry/env-profile.d.ts +19 -0
- package/dist/storage/telemetry/env-profile.d.ts.map +1 -0
- package/dist/storage/telemetry/env-profile.js +67 -0
- package/dist/storage/telemetry/env-profile.js.map +1 -0
- package/dist/storage/telemetry/payload.d.ts +8 -0
- package/dist/storage/telemetry/payload.d.ts.map +1 -0
- package/dist/storage/telemetry/payload.js +22 -0
- package/dist/storage/telemetry/payload.js.map +1 -0
- package/dist/storage/telemetry/sanitizer.d.ts +48 -0
- package/dist/storage/telemetry/sanitizer.d.ts.map +1 -0
- package/dist/storage/telemetry/sanitizer.js +82 -0
- package/dist/storage/telemetry/sanitizer.js.map +1 -0
- package/dist/storage/telemetry/uploader.d.ts +11 -0
- package/dist/storage/telemetry/uploader.d.ts.map +1 -0
- package/dist/storage/telemetry/uploader.js +140 -0
- package/dist/storage/telemetry/uploader.js.map +1 -0
- package/dist/storage/usage-tracker.d.ts +13 -0
- package/dist/storage/usage-tracker.d.ts.map +1 -1
- package/dist/storage/usage-tracker.js +33 -0
- package/dist/storage/usage-tracker.js.map +1 -1
- package/dist/tools/astro-actions/ast.d.ts +14 -0
- package/dist/tools/astro-actions/ast.d.ts.map +1 -0
- package/dist/tools/astro-actions/ast.js +75 -0
- package/dist/tools/astro-actions/ast.js.map +1 -0
- package/dist/tools/astro-actions/audit.d.ts +5 -0
- package/dist/tools/astro-actions/audit.d.ts.map +1 -0
- package/dist/tools/astro-actions/audit.js +102 -0
- package/dist/tools/astro-actions/audit.js.map +1 -0
- package/dist/tools/astro-actions/callers.d.ts +9 -0
- package/dist/tools/astro-actions/callers.d.ts.map +1 -0
- package/dist/tools/astro-actions/callers.js +84 -0
- package/dist/tools/astro-actions/callers.js.map +1 -0
- package/dist/tools/astro-actions/parser.d.ts +3 -0
- package/dist/tools/astro-actions/parser.d.ts.map +1 -0
- package/dist/tools/astro-actions/parser.js +156 -0
- package/dist/tools/astro-actions/parser.js.map +1 -0
- package/dist/tools/astro-actions/types.d.ts +58 -0
- package/dist/tools/astro-actions/types.d.ts.map +1 -0
- package/dist/tools/astro-actions/types.js +2 -0
- package/dist/tools/astro-actions/types.js.map +1 -0
- package/dist/tools/astro-actions/zod-ast.d.ts +7 -0
- package/dist/tools/astro-actions/zod-ast.d.ts.map +1 -0
- package/dist/tools/astro-actions/zod-ast.js +51 -0
- package/dist/tools/astro-actions/zod-ast.js.map +1 -0
- package/dist/tools/astro-actions.d.ts +6 -46
- package/dist/tools/astro-actions.d.ts.map +1 -1
- package/dist/tools/astro-actions.js +6 -545
- package/dist/tools/astro-actions.js.map +1 -1
- package/dist/tools/astro-content-collections/diagnostics.d.ts +3 -0
- package/dist/tools/astro-content-collections/diagnostics.d.ts.map +1 -0
- package/dist/tools/astro-content-collections/diagnostics.js +277 -0
- package/dist/tools/astro-content-collections/diagnostics.js.map +1 -0
- package/dist/tools/astro-content-collections/discovery.d.ts +6 -0
- package/dist/tools/astro-content-collections/discovery.d.ts.map +1 -0
- package/dist/tools/astro-content-collections/discovery.js +152 -0
- package/dist/tools/astro-content-collections/discovery.js.map +1 -0
- package/dist/tools/astro-content-collections/schema.d.ts +15 -0
- package/dist/tools/astro-content-collections/schema.d.ts.map +1 -0
- package/dist/tools/astro-content-collections/schema.js +119 -0
- package/dist/tools/astro-content-collections/schema.js.map +1 -0
- package/dist/tools/astro-content-collections/types.d.ts +61 -0
- package/dist/tools/astro-content-collections/types.d.ts.map +1 -0
- package/dist/tools/astro-content-collections/types.js +2 -0
- package/dist/tools/astro-content-collections/types.js.map +1 -0
- package/dist/tools/astro-content-collections.d.ts +5 -40
- package/dist/tools/astro-content-collections.d.ts.map +1 -1
- package/dist/tools/astro-content-collections.js +42 -449
- package/dist/tools/astro-content-collections.js.map +1 -1
- package/dist/tools/astro-routes.js +1 -1
- package/dist/tools/astro-routes.js.map +1 -1
- package/dist/tools/complexity-tools.d.ts +6 -0
- package/dist/tools/complexity-tools.d.ts.map +1 -1
- package/dist/tools/complexity-tools.js +26 -0
- package/dist/tools/complexity-tools.js.map +1 -1
- package/dist/tools/context-levels/l0.d.ts +4 -0
- package/dist/tools/context-levels/l0.d.ts.map +1 -0
- package/dist/tools/context-levels/l0.js +17 -0
- package/dist/tools/context-levels/l0.js.map +1 -0
- package/dist/tools/context-levels/l1.d.ts +4 -0
- package/dist/tools/context-levels/l1.d.ts.map +1 -0
- package/dist/tools/context-levels/l1.js +26 -0
- package/dist/tools/context-levels/l1.js.map +1 -0
- package/dist/tools/context-levels/l2.d.ts +4 -0
- package/dist/tools/context-levels/l2.d.ts.map +1 -0
- package/dist/tools/context-levels/l2.js +36 -0
- package/dist/tools/context-levels/l2.js.map +1 -0
- package/dist/tools/context-levels/l3.d.ts +4 -0
- package/dist/tools/context-levels/l3.d.ts.map +1 -0
- package/dist/tools/context-levels/l3.js +30 -0
- package/dist/tools/context-levels/l3.js.map +1 -0
- package/dist/tools/context-levels/shared.d.ts +2 -0
- package/dist/tools/context-levels/shared.d.ts.map +1 -0
- package/dist/tools/context-levels/shared.js +4 -0
- package/dist/tools/context-levels/shared.js.map +1 -0
- package/dist/tools/context-levels/types.d.ts +34 -0
- package/dist/tools/context-levels/types.d.ts.map +1 -0
- package/dist/tools/context-levels/types.js +2 -0
- package/dist/tools/context-levels/types.js.map +1 -0
- package/dist/tools/context-tools.d.ts +2 -34
- package/dist/tools/context-tools.d.ts.map +1 -1
- package/dist/tools/context-tools.js +11 -127
- package/dist/tools/context-tools.js.map +1 -1
- package/dist/tools/conversation-cache.d.ts +6 -0
- package/dist/tools/conversation-cache.d.ts.map +1 -0
- package/dist/tools/conversation-cache.js +29 -0
- package/dist/tools/conversation-cache.js.map +1 -0
- package/dist/tools/conversation-index-tools.d.ts +39 -0
- package/dist/tools/conversation-index-tools.d.ts.map +1 -0
- package/dist/tools/conversation-index-tools.js +136 -0
- package/dist/tools/conversation-index-tools.js.map +1 -0
- package/dist/tools/conversation-paths.d.ts +4 -0
- package/dist/tools/conversation-paths.d.ts.map +1 -0
- package/dist/tools/conversation-paths.js +15 -0
- package/dist/tools/conversation-paths.js.map +1 -0
- package/dist/tools/conversation-search-tools.d.ts +52 -0
- package/dist/tools/conversation-search-tools.d.ts.map +1 -0
- package/dist/tools/conversation-search-tools.js +229 -0
- package/dist/tools/conversation-search-tools.js.map +1 -0
- package/dist/tools/conversation-tools.d.ts +6 -112
- package/dist/tools/conversation-tools.d.ts.map +1 -1
- package/dist/tools/conversation-tools.js +4 -425
- package/dist/tools/conversation-tools.js.map +1 -1
- package/dist/tools/cross-repo-outbound-lexer/call-detectors.d.ts +5 -0
- package/dist/tools/cross-repo-outbound-lexer/call-detectors.d.ts.map +1 -0
- package/dist/tools/cross-repo-outbound-lexer/call-detectors.js +76 -0
- package/dist/tools/cross-repo-outbound-lexer/call-detectors.js.map +1 -0
- package/dist/tools/cross-repo-outbound-lexer/context.d.ts +18 -0
- package/dist/tools/cross-repo-outbound-lexer/context.d.ts.map +1 -0
- package/dist/tools/cross-repo-outbound-lexer/context.js +33 -0
- package/dist/tools/cross-repo-outbound-lexer/context.js.map +1 -0
- package/dist/tools/cross-repo-outbound-lexer/literal-readers.d.ts +6 -0
- package/dist/tools/cross-repo-outbound-lexer/literal-readers.d.ts.map +1 -0
- package/dist/tools/cross-repo-outbound-lexer/literal-readers.js +65 -0
- package/dist/tools/cross-repo-outbound-lexer/literal-readers.js.map +1 -0
- package/dist/tools/cross-repo-outbound-lexer/non-code-states.d.ts +3 -0
- package/dist/tools/cross-repo-outbound-lexer/non-code-states.d.ts.map +1 -0
- package/dist/tools/cross-repo-outbound-lexer/non-code-states.js +103 -0
- package/dist/tools/cross-repo-outbound-lexer/non-code-states.js.map +1 -0
- package/dist/tools/cross-repo-outbound-lexer/template-reader.d.ts +3 -0
- package/dist/tools/cross-repo-outbound-lexer/template-reader.d.ts.map +1 -0
- package/dist/tools/cross-repo-outbound-lexer/template-reader.js +82 -0
- package/dist/tools/cross-repo-outbound-lexer/template-reader.js.map +1 -0
- package/dist/tools/cross-repo-outbound-lexer/types.d.ts +18 -0
- package/dist/tools/cross-repo-outbound-lexer/types.d.ts.map +1 -0
- package/dist/tools/cross-repo-outbound-lexer/types.js +2 -0
- package/dist/tools/cross-repo-outbound-lexer/types.js.map +1 -0
- package/dist/tools/cross-repo-outbound-lexer.d.ts +5 -31
- package/dist/tools/cross-repo-outbound-lexer.d.ts.map +1 -1
- package/dist/tools/cross-repo-outbound-lexer.js +75 -575
- package/dist/tools/cross-repo-outbound-lexer.js.map +1 -1
- package/dist/tools/dependency-audit-freshness-tools.d.ts +3 -0
- package/dist/tools/dependency-audit-freshness-tools.d.ts.map +1 -0
- package/dist/tools/dependency-audit-freshness-tools.js +62 -0
- package/dist/tools/dependency-audit-freshness-tools.js.map +1 -0
- package/dist/tools/dependency-audit-license-tools.d.ts +5 -0
- package/dist/tools/dependency-audit-license-tools.d.ts.map +1 -0
- package/dist/tools/dependency-audit-license-tools.js +75 -0
- package/dist/tools/dependency-audit-license-tools.js.map +1 -0
- package/dist/tools/dependency-audit-lockfile-tools.d.ts +3 -0
- package/dist/tools/dependency-audit-lockfile-tools.d.ts.map +1 -0
- package/dist/tools/dependency-audit-lockfile-tools.js +147 -0
- package/dist/tools/dependency-audit-lockfile-tools.js.map +1 -0
- package/dist/tools/dependency-audit-tools.d.ts +2 -54
- package/dist/tools/dependency-audit-tools.d.ts.map +1 -1
- package/dist/tools/dependency-audit-tools.js +69 -484
- package/dist/tools/dependency-audit-tools.js.map +1 -1
- package/dist/tools/dependency-audit-types.d.ts +65 -0
- package/dist/tools/dependency-audit-types.d.ts.map +1 -0
- package/dist/tools/dependency-audit-types.js +19 -0
- package/dist/tools/dependency-audit-types.js.map +1 -0
- package/dist/tools/dependency-audit-vulnerability-tools.d.ts +4 -0
- package/dist/tools/dependency-audit-vulnerability-tools.d.ts.map +1 -0
- package/dist/tools/dependency-audit-vulnerability-tools.js +103 -0
- package/dist/tools/dependency-audit-vulnerability-tools.js.map +1 -0
- package/dist/tools/diff-tools.d.ts.map +1 -1
- package/dist/tools/diff-tools.js +5 -7
- package/dist/tools/diff-tools.js.map +1 -1
- package/dist/tools/impact-tools.d.ts.map +1 -1
- package/dist/tools/impact-tools.js +5 -4
- package/dist/tools/impact-tools.js.map +1 -1
- package/dist/tools/index-shared.d.ts +17 -0
- package/dist/tools/index-shared.d.ts.map +1 -0
- package/dist/tools/index-shared.js +18 -0
- package/dist/tools/index-shared.js.map +1 -0
- package/dist/tools/index-tools/file-indexer.d.ts +27 -0
- package/dist/tools/index-tools/file-indexer.d.ts.map +1 -0
- package/dist/tools/index-tools/file-indexer.js +223 -0
- package/dist/tools/index-tools/file-indexer.js.map +1 -0
- package/dist/tools/index-tools/folder-indexer.d.ts +21 -0
- package/dist/tools/index-tools/folder-indexer.d.ts.map +1 -0
- package/dist/tools/index-tools/folder-indexer.js +399 -0
- package/dist/tools/index-tools/folder-indexer.js.map +1 -0
- package/dist/tools/index-tools/folder-merge.d.ts +23 -0
- package/dist/tools/index-tools/folder-merge.d.ts.map +1 -0
- package/dist/tools/index-tools/folder-merge.js +205 -0
- package/dist/tools/index-tools/folder-merge.js.map +1 -0
- package/dist/tools/index-tools/parse.d.ts +35 -0
- package/dist/tools/index-tools/parse.d.ts.map +1 -0
- package/dist/tools/index-tools/parse.js +262 -0
- package/dist/tools/index-tools/parse.js.map +1 -0
- package/dist/tools/index-tools/registry.d.ts +40 -0
- package/dist/tools/index-tools/registry.d.ts.map +1 -0
- package/dist/tools/index-tools/registry.js +258 -0
- package/dist/tools/index-tools/registry.js.map +1 -0
- package/dist/tools/index-tools/snapshots.d.ts +51 -0
- package/dist/tools/index-tools/snapshots.d.ts.map +1 -0
- package/dist/tools/index-tools/snapshots.js +223 -0
- package/dist/tools/index-tools/snapshots.js.map +1 -0
- package/dist/tools/index-tools/state.d.ts +8 -0
- package/dist/tools/index-tools/state.d.ts.map +1 -0
- package/dist/tools/index-tools/state.js +6 -0
- package/dist/tools/index-tools/state.js.map +1 -0
- package/dist/tools/index-tools/types.d.ts +20 -0
- package/dist/tools/index-tools/types.d.ts.map +1 -0
- package/dist/tools/index-tools/types.js +2 -0
- package/dist/tools/index-tools/types.js.map +1 -0
- package/dist/tools/index-tools/watcher.d.ts +10 -0
- package/dist/tools/index-tools/watcher.d.ts.map +1 -0
- package/dist/tools/index-tools/watcher.js +130 -0
- package/dist/tools/index-tools/watcher.js.map +1 -0
- package/dist/tools/index-tools.d.ts +16 -152
- package/dist/tools/index-tools.d.ts.map +1 -1
- package/dist/tools/index-tools.js +12 -1674
- package/dist/tools/index-tools.js.map +1 -1
- package/dist/tools/kotlin-extension-tools.d.ts +16 -0
- package/dist/tools/kotlin-extension-tools.d.ts.map +1 -0
- package/dist/tools/kotlin-extension-tools.js +31 -0
- package/dist/tools/kotlin-extension-tools.js.map +1 -0
- package/dist/tools/kotlin-flow-tools.d.ts +12 -0
- package/dist/tools/kotlin-flow-tools.d.ts.map +1 -0
- package/dist/tools/kotlin-flow-tools.js +72 -0
- package/dist/tools/kotlin-flow-tools.js.map +1 -0
- package/dist/tools/kotlin-kmp-tools.d.ts +29 -0
- package/dist/tools/kotlin-kmp-tools.d.ts.map +1 -0
- package/dist/tools/kotlin-kmp-tools.js +87 -0
- package/dist/tools/kotlin-kmp-tools.js.map +1 -0
- package/dist/tools/kotlin-sealed-tools.d.ts +27 -0
- package/dist/tools/kotlin-sealed-tools.d.ts.map +1 -0
- package/dist/tools/kotlin-sealed-tools.js +130 -0
- package/dist/tools/kotlin-sealed-tools.js.map +1 -0
- package/dist/tools/kotlin-suspend-tools.d.ts +24 -0
- package/dist/tools/kotlin-suspend-tools.d.ts.map +1 -0
- package/dist/tools/kotlin-suspend-tools.js +161 -0
- package/dist/tools/kotlin-suspend-tools.js.map +1 -0
- package/dist/tools/kotlin-tools.d.ts +6 -141
- package/dist/tools/kotlin-tools.d.ts.map +1 -1
- package/dist/tools/kotlin-tools.js +6 -571
- package/dist/tools/kotlin-tools.js.map +1 -1
- package/dist/tools/nest-audit-tools.d.ts +43 -0
- package/dist/tools/nest-audit-tools.d.ts.map +1 -0
- package/dist/tools/nest-audit-tools.js +232 -0
- package/dist/tools/nest-audit-tools.js.map +1 -0
- package/dist/tools/nest-di-tools.d.ts +32 -0
- package/dist/tools/nest-di-tools.d.ts.map +1 -0
- package/dist/tools/nest-di-tools.js +161 -0
- package/dist/tools/nest-di-tools.js.map +1 -0
- package/dist/tools/nest-guard-tools.d.ts +34 -0
- package/dist/tools/nest-guard-tools.d.ts.map +1 -0
- package/dist/tools/nest-guard-tools.js +240 -0
- package/dist/tools/nest-guard-tools.js.map +1 -0
- package/dist/tools/nest-lifecycle-tools.d.ts +16 -0
- package/dist/tools/nest-lifecycle-tools.d.ts.map +1 -0
- package/dist/tools/nest-lifecycle-tools.js +54 -0
- package/dist/tools/nest-lifecycle-tools.js.map +1 -0
- package/dist/tools/nest-module-tools.d.ts +28 -0
- package/dist/tools/nest-module-tools.d.ts.map +1 -0
- package/dist/tools/nest-module-tools.js +86 -0
- package/dist/tools/nest-module-tools.js.map +1 -0
- package/dist/tools/nest-pipeline-tools.d.ts +32 -0
- package/dist/tools/nest-pipeline-tools.d.ts.map +1 -0
- package/dist/tools/nest-pipeline-tools.js +122 -0
- package/dist/tools/nest-pipeline-tools.js.map +1 -0
- package/dist/tools/nest-route-tools.d.ts +43 -0
- package/dist/tools/nest-route-tools.d.ts.map +1 -0
- package/dist/tools/nest-route-tools.js +261 -0
- package/dist/tools/nest-route-tools.js.map +1 -0
- package/dist/tools/nest-shared-tools.d.ts +13 -0
- package/dist/tools/nest-shared-tools.d.ts.map +1 -0
- package/dist/tools/nest-shared-tools.js +36 -0
- package/dist/tools/nest-shared-tools.js.map +1 -0
- package/dist/tools/nest-tools.d.ts +18 -195
- package/dist/tools/nest-tools.d.ts.map +1 -1
- package/dist/tools/nest-tools.js +11 -1140
- package/dist/tools/nest-tools.js.map +1 -1
- package/dist/tools/pattern-registry.d.ts +4 -0
- package/dist/tools/pattern-registry.d.ts.map +1 -0
- package/dist/tools/pattern-registry.js +3 -0
- package/dist/tools/pattern-registry.js.map +1 -0
- package/dist/tools/pattern-tools.d.ts +5 -46
- package/dist/tools/pattern-tools.d.ts.map +1 -1
- package/dist/tools/pattern-tools.js +4 -1102
- package/dist/tools/pattern-tools.js.map +1 -1
- package/dist/tools/patterns/adapters/astro.d.ts +3 -0
- package/dist/tools/patterns/adapters/astro.d.ts.map +1 -0
- package/dist/tools/patterns/adapters/astro.js +56 -0
- package/dist/tools/patterns/adapters/astro.js.map +1 -0
- package/dist/tools/patterns/adapters/common.d.ts +3 -0
- package/dist/tools/patterns/adapters/common.d.ts.map +1 -0
- package/dist/tools/patterns/adapters/common.js +38 -0
- package/dist/tools/patterns/adapters/common.js.map +1 -0
- package/dist/tools/patterns/adapters/database.d.ts +3 -0
- package/dist/tools/patterns/adapters/database.d.ts.map +1 -0
- package/dist/tools/patterns/adapters/database.js +32 -0
- package/dist/tools/patterns/adapters/database.js.map +1 -0
- package/dist/tools/patterns/adapters/hono.d.ts +3 -0
- package/dist/tools/patterns/adapters/hono.d.ts.map +1 -0
- package/dist/tools/patterns/adapters/hono.js +32 -0
- package/dist/tools/patterns/adapters/hono.js.map +1 -0
- package/dist/tools/patterns/adapters/kotlin.d.ts +3 -0
- package/dist/tools/patterns/adapters/kotlin.d.ts.map +1 -0
- package/dist/tools/patterns/adapters/kotlin.js +50 -0
- package/dist/tools/patterns/adapters/kotlin.js.map +1 -0
- package/dist/tools/patterns/adapters/nest.d.ts +3 -0
- package/dist/tools/patterns/adapters/nest.d.ts.map +1 -0
- package/dist/tools/patterns/adapters/nest.js +122 -0
- package/dist/tools/patterns/adapters/nest.js.map +1 -0
- package/dist/tools/patterns/adapters/nextjs.d.ts +4 -0
- package/dist/tools/patterns/adapters/nextjs.d.ts.map +1 -0
- package/dist/tools/patterns/adapters/nextjs.js +59 -0
- package/dist/tools/patterns/adapters/nextjs.js.map +1 -0
- package/dist/tools/patterns/adapters/php.d.ts +3 -0
- package/dist/tools/patterns/adapters/php.d.ts.map +1 -0
- package/dist/tools/patterns/adapters/php.js +157 -0
- package/dist/tools/patterns/adapters/php.js.map +1 -0
- package/dist/tools/patterns/adapters/python.d.ts +3 -0
- package/dist/tools/patterns/adapters/python.d.ts.map +1 -0
- package/dist/tools/patterns/adapters/python.js +72 -0
- package/dist/tools/patterns/adapters/python.js.map +1 -0
- package/dist/tools/patterns/adapters/react.d.ts +4 -0
- package/dist/tools/patterns/adapters/react.d.ts.map +1 -0
- package/dist/tools/patterns/adapters/react.js +345 -0
- package/dist/tools/patterns/adapters/react.js.map +1 -0
- package/dist/tools/patterns/catalog.d.ts +8 -0
- package/dist/tools/patterns/catalog.d.ts.map +1 -0
- package/dist/tools/patterns/catalog.js +30 -0
- package/dist/tools/patterns/catalog.js.map +1 -0
- package/dist/tools/patterns/execution.d.ts +38 -0
- package/dist/tools/patterns/execution.d.ts.map +1 -0
- package/dist/tools/patterns/execution.js +298 -0
- package/dist/tools/patterns/execution.js.map +1 -0
- package/dist/tools/patterns/types.d.ts +13 -0
- package/dist/tools/patterns/types.d.ts.map +1 -0
- package/dist/tools/patterns/types.js +2 -0
- package/dist/tools/patterns/types.js.map +1 -0
- package/dist/tools/pg-drift-compare.d.ts +3 -0
- package/dist/tools/pg-drift-compare.d.ts.map +1 -0
- package/dist/tools/pg-drift-compare.js +30 -0
- package/dist/tools/pg-drift-compare.js.map +1 -0
- package/dist/tools/pg-drift-schema.d.ts +5 -0
- package/dist/tools/pg-drift-schema.d.ts.map +1 -0
- package/dist/tools/pg-drift-schema.js +28 -0
- package/dist/tools/pg-drift-schema.js.map +1 -0
- package/dist/tools/pg-drift-types.d.ts +25 -0
- package/dist/tools/pg-drift-types.d.ts.map +1 -0
- package/dist/tools/pg-drift-types.js +2 -0
- package/dist/tools/pg-drift-types.js.map +1 -0
- package/dist/tools/pg-drift.d.ts +5 -0
- package/dist/tools/pg-drift.d.ts.map +1 -0
- package/dist/tools/pg-drift.js +30 -0
- package/dist/tools/pg-drift.js.map +1 -0
- package/dist/tools/pg-introspect-formatters.d.ts +7 -0
- package/dist/tools/pg-introspect-formatters.d.ts.map +1 -0
- package/dist/tools/pg-introspect-formatters.js +66 -0
- package/dist/tools/pg-introspect-formatters.js.map +1 -0
- package/dist/tools/pg-introspect-tools.d.ts +5 -146
- package/dist/tools/pg-introspect-tools.d.ts.map +1 -1
- package/dist/tools/pg-introspect-tools.js +3 -395
- package/dist/tools/pg-introspect-tools.js.map +1 -1
- package/dist/tools/pg-introspection.d.ts +90 -0
- package/dist/tools/pg-introspection.d.ts.map +1 -0
- package/dist/tools/pg-introspection.js +288 -0
- package/dist/tools/pg-introspection.js.map +1 -0
- package/dist/tools/php-active-record-tools.d.ts +22 -0
- package/dist/tools/php-active-record-tools.d.ts.map +1 -0
- package/dist/tools/php-active-record-tools.js +165 -0
- package/dist/tools/php-active-record-tools.js.map +1 -0
- package/dist/tools/php-event-tools.d.ts +21 -0
- package/dist/tools/php-event-tools.d.ts.map +1 -0
- package/dist/tools/php-event-tools.js +205 -0
- package/dist/tools/php-event-tools.js.map +1 -0
- package/dist/tools/php-god-model-tools.d.ts +34 -0
- package/dist/tools/php-god-model-tools.d.ts.map +1 -0
- package/dist/tools/php-god-model-tools.js +88 -0
- package/dist/tools/php-god-model-tools.js.map +1 -0
- package/dist/tools/php-import-utils.d.ts +10 -0
- package/dist/tools/php-import-utils.d.ts.map +1 -0
- package/dist/tools/php-import-utils.js +71 -0
- package/dist/tools/php-import-utils.js.map +1 -0
- package/dist/tools/php-namespace-tools.d.ts +10 -0
- package/dist/tools/php-namespace-tools.d.ts.map +1 -0
- package/dist/tools/php-namespace-tools.js +98 -0
- package/dist/tools/php-namespace-tools.js.map +1 -0
- package/dist/tools/php-nplus1-tools.d.ts +27 -0
- package/dist/tools/php-nplus1-tools.d.ts.map +1 -0
- package/dist/tools/php-nplus1-tools.js +191 -0
- package/dist/tools/php-nplus1-tools.js.map +1 -0
- package/dist/tools/php-project-audit-tools.d.ts +31 -0
- package/dist/tools/php-project-audit-tools.d.ts.map +1 -0
- package/dist/tools/php-project-audit-tools.js +173 -0
- package/dist/tools/php-project-audit-tools.js.map +1 -0
- package/dist/tools/php-security-tools.d.ts +24 -0
- package/dist/tools/php-security-tools.d.ts.map +1 -0
- package/dist/tools/php-security-tools.js +172 -0
- package/dist/tools/php-security-tools.js.map +1 -0
- package/dist/tools/php-service-tools.d.ts +25 -0
- package/dist/tools/php-service-tools.d.ts.map +1 -0
- package/dist/tools/php-service-tools.js +326 -0
- package/dist/tools/php-service-tools.js.map +1 -0
- package/dist/tools/php-tools.d.ts +21 -255
- package/dist/tools/php-tools.d.ts.map +1 -1
- package/dist/tools/php-tools.js +12 -1423
- package/dist/tools/php-tools.js.map +1 -1
- package/dist/tools/php-view-tools.d.ts +76 -0
- package/dist/tools/php-view-tools.d.ts.map +1 -0
- package/dist/tools/php-view-tools.js +413 -0
- package/dist/tools/php-view-tools.js.map +1 -0
- package/dist/tools/plan-turn/formatter.d.ts +3 -0
- package/dist/tools/plan-turn/formatter.d.ts.map +1 -0
- package/dist/tools/plan-turn/formatter.js +88 -0
- package/dist/tools/plan-turn/formatter.js.map +1 -0
- package/dist/tools/plan-turn/framework-context.d.ts +5 -0
- package/dist/tools/plan-turn/framework-context.d.ts.map +1 -0
- package/dist/tools/plan-turn/framework-context.js +68 -0
- package/dist/tools/plan-turn/framework-context.js.map +1 -0
- package/dist/tools/plan-turn/framework-data.d.ts +5 -0
- package/dist/tools/plan-turn/framework-data.d.ts.map +1 -0
- package/dist/tools/plan-turn/framework-data.js +48 -0
- package/dist/tools/plan-turn/framework-data.js.map +1 -0
- package/dist/tools/plan-turn/orchestrator.d.ts +4 -0
- package/dist/tools/plan-turn/orchestrator.d.ts.map +1 -0
- package/dist/tools/plan-turn/orchestrator.js +262 -0
- package/dist/tools/plan-turn/orchestrator.js.map +1 -0
- package/dist/tools/plan-turn/query-parser.d.ts +6 -0
- package/dist/tools/plan-turn/query-parser.d.ts.map +1 -0
- package/dist/tools/plan-turn/query-parser.js +60 -0
- package/dist/tools/plan-turn/query-parser.js.map +1 -0
- package/dist/tools/plan-turn/recommendations.d.ts +11 -0
- package/dist/tools/plan-turn/recommendations.d.ts.map +1 -0
- package/dist/tools/plan-turn/recommendations.js +93 -0
- package/dist/tools/plan-turn/recommendations.js.map +1 -0
- package/dist/tools/plan-turn/stale-index.d.ts +4 -0
- package/dist/tools/plan-turn/stale-index.d.ts.map +1 -0
- package/dist/tools/plan-turn/stale-index.js +17 -0
- package/dist/tools/plan-turn/stale-index.js.map +1 -0
- package/dist/tools/plan-turn/types.d.ts +61 -0
- package/dist/tools/plan-turn/types.d.ts.map +1 -0
- package/dist/tools/plan-turn/types.js +2 -0
- package/dist/tools/plan-turn/types.js.map +1 -0
- package/dist/tools/plan-turn-tools.d.ts +8 -111
- package/dist/tools/plan-turn-tools.d.ts.map +1 -1
- package/dist/tools/plan-turn-tools.js +6 -696
- package/dist/tools/plan-turn-tools.js.map +1 -1
- package/dist/tools/project-profile-express.d.ts +3 -0
- package/dist/tools/project-profile-express.d.ts.map +1 -0
- package/dist/tools/project-profile-express.js +46 -0
- package/dist/tools/project-profile-express.js.map +1 -0
- package/dist/tools/project-profile-extractors.d.ts +9 -0
- package/dist/tools/project-profile-extractors.d.ts.map +1 -0
- package/dist/tools/project-profile-extractors.js +312 -0
- package/dist/tools/project-profile-extractors.js.map +1 -0
- package/dist/tools/project-profile-fs.d.ts +3 -0
- package/dist/tools/project-profile-fs.d.ts.map +1 -0
- package/dist/tools/project-profile-fs.js +19 -0
- package/dist/tools/project-profile-fs.js.map +1 -0
- package/dist/tools/project-profile-hono.d.ts +13 -0
- package/dist/tools/project-profile-hono.d.ts.map +1 -0
- package/dist/tools/project-profile-hono.js +110 -0
- package/dist/tools/project-profile-hono.js.map +1 -0
- package/dist/tools/project-profile-imports.d.ts +6 -0
- package/dist/tools/project-profile-imports.d.ts.map +1 -0
- package/dist/tools/project-profile-imports.js +95 -0
- package/dist/tools/project-profile-imports.js.map +1 -0
- package/dist/tools/project-profile-nest.d.ts +8 -0
- package/dist/tools/project-profile-nest.d.ts.map +1 -0
- package/dist/tools/project-profile-nest.js +352 -0
- package/dist/tools/project-profile-nest.js.map +1 -0
- package/dist/tools/project-profile-next.d.ts +5 -0
- package/dist/tools/project-profile-next.d.ts.map +1 -0
- package/dist/tools/project-profile-next.js +92 -0
- package/dist/tools/project-profile-next.js.map +1 -0
- package/dist/tools/project-profile-persistence.d.ts +3 -0
- package/dist/tools/project-profile-persistence.d.ts.map +1 -0
- package/dist/tools/project-profile-persistence.js +19 -0
- package/dist/tools/project-profile-persistence.js.map +1 -0
- package/dist/tools/project-profile-php.d.ts +8 -0
- package/dist/tools/project-profile-php.d.ts.map +1 -0
- package/dist/tools/project-profile-php.js +76 -0
- package/dist/tools/project-profile-php.js.map +1 -0
- package/dist/tools/project-profile-python.d.ts +5 -0
- package/dist/tools/project-profile-python.d.ts.map +1 -0
- package/dist/tools/project-profile-python.js +51 -0
- package/dist/tools/project-profile-python.js.map +1 -0
- package/dist/tools/project-profile-react.d.ts +6 -0
- package/dist/tools/project-profile-react.d.ts.map +1 -0
- package/dist/tools/project-profile-react.js +106 -0
- package/dist/tools/project-profile-react.js.map +1 -0
- package/dist/tools/project-profile-stack.d.ts +3 -0
- package/dist/tools/project-profile-stack.d.ts.map +1 -0
- package/dist/tools/project-profile-stack.js +354 -0
- package/dist/tools/project-profile-stack.js.map +1 -0
- package/dist/tools/project-profile-summary.d.ts +30 -0
- package/dist/tools/project-profile-summary.d.ts.map +1 -0
- package/dist/tools/project-profile-summary.js +112 -0
- package/dist/tools/project-profile-summary.js.map +1 -0
- package/dist/tools/project-profile-types.d.ts +315 -0
- package/dist/tools/project-profile-types.d.ts.map +1 -0
- package/dist/tools/project-profile-types.js +2 -0
- package/dist/tools/project-profile-types.js.map +1 -0
- package/dist/tools/project-tools.d.ts +20 -383
- package/dist/tools/project-tools.d.ts.map +1 -1
- package/dist/tools/project-tools.js +37 -1621
- package/dist/tools/project-tools.js.map +1 -1
- package/dist/tools/python-audit/aggregate.d.ts +3 -0
- package/dist/tools/python-audit/aggregate.d.ts.map +1 -0
- package/dist/tools/python-audit/aggregate.js +103 -0
- package/dist/tools/python-audit/aggregate.js.map +1 -0
- package/dist/tools/python-audit/checks/anti-patterns.d.ts +6 -0
- package/dist/tools/python-audit/checks/anti-patterns.d.ts.map +1 -0
- package/dist/tools/python-audit/checks/anti-patterns.js +14 -0
- package/dist/tools/python-audit/checks/anti-patterns.js.map +1 -0
- package/dist/tools/python-audit/checks/celery.d.ts +2 -0
- package/dist/tools/python-audit/checks/celery.d.ts.map +1 -0
- package/dist/tools/python-audit/checks/celery.js +5 -0
- package/dist/tools/python-audit/checks/celery.js.map +1 -0
- package/dist/tools/python-audit/checks/circular-imports.d.ts +2 -0
- package/dist/tools/python-audit/checks/circular-imports.d.ts.map +1 -0
- package/dist/tools/python-audit/checks/circular-imports.js +5 -0
- package/dist/tools/python-audit/checks/circular-imports.js.map +1 -0
- package/dist/tools/python-audit/checks/dead-code.d.ts +2 -0
- package/dist/tools/python-audit/checks/dead-code.d.ts.map +1 -0
- package/dist/tools/python-audit/checks/dead-code.js +5 -0
- package/dist/tools/python-audit/checks/dead-code.js.map +1 -0
- package/dist/tools/python-audit/checks/dependencies.d.ts +2 -0
- package/dist/tools/python-audit/checks/dependencies.d.ts.map +1 -0
- package/dist/tools/python-audit/checks/dependencies.js +5 -0
- package/dist/tools/python-audit/checks/dependencies.js.map +1 -0
- package/dist/tools/python-audit/checks/django-settings.d.ts +2 -0
- package/dist/tools/python-audit/checks/django-settings.d.ts.map +1 -0
- package/dist/tools/python-audit/checks/django-settings.js +5 -0
- package/dist/tools/python-audit/checks/django-settings.js.map +1 -0
- package/dist/tools/python-audit/checks/framework-wiring.d.ts +2 -0
- package/dist/tools/python-audit/checks/framework-wiring.d.ts.map +1 -0
- package/dist/tools/python-audit/checks/framework-wiring.js +5 -0
- package/dist/tools/python-audit/checks/framework-wiring.js.map +1 -0
- package/dist/tools/python-audit/checks/pytest-fixtures.d.ts +2 -0
- package/dist/tools/python-audit/checks/pytest-fixtures.d.ts.map +1 -0
- package/dist/tools/python-audit/checks/pytest-fixtures.js +5 -0
- package/dist/tools/python-audit/checks/pytest-fixtures.js.map +1 -0
- package/dist/tools/python-audit/runner.d.ts +5 -0
- package/dist/tools/python-audit/runner.d.ts.map +1 -0
- package/dist/tools/python-audit/runner.js +18 -0
- package/dist/tools/python-audit/runner.js.map +1 -0
- package/dist/tools/python-audit/types.d.ts +43 -0
- package/dist/tools/python-audit/types.d.ts.map +1 -0
- package/dist/tools/python-audit/types.js +2 -0
- package/dist/tools/python-audit/types.js.map +1 -0
- package/dist/tools/python-audit.d.ts +3 -39
- package/dist/tools/python-audit.d.ts.map +1 -1
- package/dist/tools/python-audit.js +34 -233
- package/dist/tools/python-audit.js.map +1 -1
- package/dist/tools/react-compiler-tools.d.ts +37 -0
- package/dist/tools/react-compiler-tools.d.ts.map +1 -0
- package/dist/tools/react-compiler-tools.js +104 -0
- package/dist/tools/react-compiler-tools.js.map +1 -0
- package/dist/tools/react-component-tree-tools.d.ts +58 -0
- package/dist/tools/react-component-tree-tools.d.ts.map +1 -0
- package/dist/tools/react-component-tree-tools.js +292 -0
- package/dist/tools/react-component-tree-tools.js.map +1 -0
- package/dist/tools/react-context-tools.d.ts +41 -0
- package/dist/tools/react-context-tools.d.ts.map +1 -0
- package/dist/tools/react-context-tools.js +76 -0
- package/dist/tools/react-context-tools.js.map +1 -0
- package/dist/tools/react-hooks-tools.d.ts +58 -0
- package/dist/tools/react-hooks-tools.d.ts.map +1 -0
- package/dist/tools/react-hooks-tools.js +144 -0
- package/dist/tools/react-hooks-tools.js.map +1 -0
- package/dist/tools/react-quickstart-tools.d.ts +59 -0
- package/dist/tools/react-quickstart-tools.d.ts.map +1 -0
- package/dist/tools/react-quickstart-tools.js +164 -0
- package/dist/tools/react-quickstart-tools.js.map +1 -0
- package/dist/tools/react-render-tools.d.ts +75 -0
- package/dist/tools/react-render-tools.d.ts.map +1 -0
- package/dist/tools/react-render-tools.js +234 -0
- package/dist/tools/react-render-tools.js.map +1 -0
- package/dist/tools/react-shared-tools.d.ts +5 -0
- package/dist/tools/react-shared-tools.d.ts.map +1 -0
- package/dist/tools/react-shared-tools.js +12 -0
- package/dist/tools/react-shared-tools.js.map +1 -0
- package/dist/tools/react-suspense-tools.d.ts +29 -0
- package/dist/tools/react-suspense-tools.d.ts.map +1 -0
- package/dist/tools/react-suspense-tools.js +269 -0
- package/dist/tools/react-suspense-tools.js.map +1 -0
- package/dist/tools/react-tools.d.ts +19 -340
- package/dist/tools/react-tools.d.ts.map +1 -1
- package/dist/tools/react-tools.js +10 -1263
- package/dist/tools/react-tools.js.map +1 -1
- package/dist/tools/review-diff/check-runner.d.ts +5 -0
- package/dist/tools/review-diff/check-runner.d.ts.map +1 -0
- package/dist/tools/review-diff/check-runner.js +26 -0
- package/dist/tools/review-diff/check-runner.js.map +1 -0
- package/dist/tools/review-diff/checks/astro-hydration.d.ts +8 -0
- package/dist/tools/review-diff/checks/astro-hydration.d.ts.map +1 -0
- package/dist/tools/review-diff/checks/astro-hydration.js +54 -0
- package/dist/tools/review-diff/checks/astro-hydration.js.map +1 -0
- package/dist/tools/review-diff/checks/blast-radius.d.ts +7 -0
- package/dist/tools/review-diff/checks/blast-radius.d.ts.map +1 -0
- package/dist/tools/review-diff/checks/blast-radius.js +39 -0
- package/dist/tools/review-diff/checks/blast-radius.js.map +1 -0
- package/dist/tools/review-diff/checks/breaking.d.ts +13 -0
- package/dist/tools/review-diff/checks/breaking.d.ts.map +1 -0
- package/dist/tools/review-diff/checks/breaking.js +115 -0
- package/dist/tools/review-diff/checks/breaking.js.map +1 -0
- package/dist/tools/review-diff/checks/bug-patterns.d.ts +8 -0
- package/dist/tools/review-diff/checks/bug-patterns.d.ts.map +1 -0
- package/dist/tools/review-diff/checks/bug-patterns.js +130 -0
- package/dist/tools/review-diff/checks/bug-patterns.js.map +1 -0
- package/dist/tools/review-diff/checks/complexity.d.ts +8 -0
- package/dist/tools/review-diff/checks/complexity.d.ts.map +1 -0
- package/dist/tools/review-diff/checks/complexity.js +41 -0
- package/dist/tools/review-diff/checks/complexity.js.map +1 -0
- package/dist/tools/review-diff/checks/coupling.d.ts +7 -0
- package/dist/tools/review-diff/checks/coupling.d.ts.map +1 -0
- package/dist/tools/review-diff/checks/coupling.js +52 -0
- package/dist/tools/review-diff/checks/coupling.js.map +1 -0
- package/dist/tools/review-diff/checks/dead-code.d.ts +7 -0
- package/dist/tools/review-diff/checks/dead-code.d.ts.map +1 -0
- package/dist/tools/review-diff/checks/dead-code.js +39 -0
- package/dist/tools/review-diff/checks/dead-code.js.map +1 -0
- package/dist/tools/review-diff/checks/hotspots.d.ts +8 -0
- package/dist/tools/review-diff/checks/hotspots.d.ts.map +1 -0
- package/dist/tools/review-diff/checks/hotspots.js +39 -0
- package/dist/tools/review-diff/checks/hotspots.js.map +1 -0
- package/dist/tools/review-diff/checks/secrets.d.ts +7 -0
- package/dist/tools/review-diff/checks/secrets.d.ts.map +1 -0
- package/dist/tools/review-diff/checks/secrets.js +38 -0
- package/dist/tools/review-diff/checks/secrets.js.map +1 -0
- package/dist/tools/review-diff/checks/test-gaps.d.ts +16 -0
- package/dist/tools/review-diff/checks/test-gaps.d.ts.map +1 -0
- package/dist/tools/review-diff/checks/test-gaps.js +77 -0
- package/dist/tools/review-diff/checks/test-gaps.js.map +1 -0
- package/dist/tools/review-diff/constants.d.ts +6 -0
- package/dist/tools/review-diff/constants.d.ts.map +1 -0
- package/dist/tools/review-diff/constants.js +16 -0
- package/dist/tools/review-diff/constants.js.map +1 -0
- package/dist/tools/review-diff/file-pattern.d.ts +2 -0
- package/dist/tools/review-diff/file-pattern.d.ts.map +1 -0
- package/dist/tools/review-diff/file-pattern.js +9 -0
- package/dist/tools/review-diff/file-pattern.js.map +1 -0
- package/dist/tools/review-diff/orchestrator.d.ts +3 -0
- package/dist/tools/review-diff/orchestrator.d.ts.map +1 -0
- package/dist/tools/review-diff/orchestrator.js +173 -0
- package/dist/tools/review-diff/orchestrator.js.map +1 -0
- package/dist/tools/review-diff/scoring.d.ts +31 -0
- package/dist/tools/review-diff/scoring.d.ts.map +1 -0
- package/dist/tools/review-diff/scoring.js +82 -0
- package/dist/tools/review-diff/scoring.js.map +1 -0
- package/dist/tools/review-diff/timeout.d.ts +5 -0
- package/dist/tools/review-diff/timeout.d.ts.map +1 -0
- package/dist/tools/review-diff/timeout.js +14 -0
- package/dist/tools/review-diff/timeout.js.map +1 -0
- package/dist/tools/review-diff/types.d.ts +56 -0
- package/dist/tools/review-diff/types.d.ts.map +1 -0
- package/dist/tools/review-diff/types.js +2 -0
- package/dist/tools/review-diff/types.js.map +1 -0
- package/dist/tools/review-diff-tools.d.ts +19 -147
- package/dist/tools/review-diff-tools.d.ts.map +1 -1
- package/dist/tools/review-diff-tools.js +18 -941
- package/dist/tools/review-diff-tools.js.map +1 -1
- package/dist/tools/route-shared.d.ts +6 -0
- package/dist/tools/route-shared.d.ts.map +1 -0
- package/dist/tools/route-shared.js +37 -0
- package/dist/tools/route-shared.js.map +1 -0
- package/dist/tools/route-tools.d.ts +1 -7
- package/dist/tools/route-tools.d.ts.map +1 -1
- package/dist/tools/route-tools.js +2 -22
- package/dist/tools/route-tools.js.map +1 -1
- package/dist/tools/search-tools/constants.d.ts +33 -0
- package/dist/tools/search-tools/constants.d.ts.map +1 -0
- package/dist/tools/search-tools/constants.js +54 -0
- package/dist/tools/search-tools/constants.js.map +1 -0
- package/dist/tools/search-tools/ripgrep.d.ts +13 -0
- package/dist/tools/search-tools/ripgrep.d.ts.map +1 -0
- package/dist/tools/search-tools/ripgrep.js +138 -0
- package/dist/tools/search-tools/ripgrep.js.map +1 -0
- package/dist/tools/search-tools/semantic-search.d.ts +9 -0
- package/dist/tools/search-tools/semantic-search.d.ts.map +1 -0
- package/dist/tools/search-tools/semantic-search.js +19 -0
- package/dist/tools/search-tools/semantic-search.js.map +1 -0
- package/dist/tools/search-tools/symbol-search.d.ts +4 -0
- package/dist/tools/search-tools/symbol-search.d.ts.map +1 -0
- package/dist/tools/search-tools/symbol-search.js +146 -0
- package/dist/tools/search-tools/symbol-search.js.map +1 -0
- package/dist/tools/search-tools/text-search.d.ts +10 -0
- package/dist/tools/search-tools/text-search.d.ts.map +1 -0
- package/dist/tools/search-tools/text-search.js +260 -0
- package/dist/tools/search-tools/text-search.js.map +1 -0
- package/dist/tools/search-tools/types.d.ts +28 -0
- package/dist/tools/search-tools/types.d.ts.map +1 -0
- package/dist/tools/search-tools/types.js +2 -0
- package/dist/tools/search-tools/types.js.map +1 -0
- package/dist/tools/search-tools/zero-hit.d.ts +3 -0
- package/dist/tools/search-tools/zero-hit.d.ts.map +1 -0
- package/dist/tools/search-tools/zero-hit.js +92 -0
- package/dist/tools/search-tools/zero-hit.js.map +1 -0
- package/dist/tools/search-tools.d.ts +5 -64
- package/dist/tools/search-tools.d.ts.map +1 -1
- package/dist/tools/search-tools.js +4 -770
- package/dist/tools/search-tools.js.map +1 -1
- package/dist/tools/secret-detectors.d.ts +12 -0
- package/dist/tools/secret-detectors.d.ts.map +1 -0
- package/dist/tools/secret-detectors.js +86 -0
- package/dist/tools/secret-detectors.js.map +1 -0
- package/dist/tools/secret-file-scanner.d.ts +7 -0
- package/dist/tools/secret-file-scanner.d.ts.map +1 -0
- package/dist/tools/secret-file-scanner.js +52 -0
- package/dist/tools/secret-file-scanner.js.map +1 -0
- package/dist/tools/secret-scan-cache.d.ts +6 -0
- package/dist/tools/secret-scan-cache.d.ts.map +1 -0
- package/dist/tools/secret-scan-cache.js +14 -0
- package/dist/tools/secret-scan-cache.js.map +1 -0
- package/dist/tools/secret-scan-shared.d.ts +5 -0
- package/dist/tools/secret-scan-shared.d.ts.map +1 -0
- package/dist/tools/secret-scan-shared.js +4 -0
- package/dist/tools/secret-scan-shared.js.map +1 -0
- package/dist/tools/secret-scan-types.d.ts +21 -0
- package/dist/tools/secret-scan-types.d.ts.map +1 -0
- package/dist/tools/secret-scan-types.js +2 -0
- package/dist/tools/secret-scan-types.js.map +1 -0
- package/dist/tools/secret-tools.d.ts +3 -75
- package/dist/tools/secret-tools.d.ts.map +1 -1
- package/dist/tools/secret-tools.js +4 -316
- package/dist/tools/secret-tools.js.map +1 -1
- package/dist/tools/sql-audit-tools.d.ts +42 -0
- package/dist/tools/sql-audit-tools.d.ts.map +1 -0
- package/dist/tools/sql-audit-tools.js +130 -0
- package/dist/tools/sql-audit-tools.js.map +1 -0
- package/dist/tools/sql-column-tools.d.ts +28 -0
- package/dist/tools/sql-column-tools.d.ts.map +1 -0
- package/dist/tools/sql-column-tools.js +58 -0
- package/dist/tools/sql-column-tools.js.map +1 -0
- package/dist/tools/sql-complexity-tools.d.ts +22 -0
- package/dist/tools/sql-complexity-tools.d.ts.map +1 -0
- package/dist/tools/sql-complexity-tools.js +60 -0
- package/dist/tools/sql-complexity-tools.js.map +1 -0
- package/dist/tools/sql-dml-safety-tools.d.ts +26 -0
- package/dist/tools/sql-dml-safety-tools.d.ts.map +1 -0
- package/dist/tools/sql-dml-safety-tools.js +104 -0
- package/dist/tools/sql-dml-safety-tools.js.map +1 -0
- package/dist/tools/sql-drift-tools.d.ts +39 -0
- package/dist/tools/sql-drift-tools.d.ts.map +1 -0
- package/dist/tools/sql-drift-tools.js +238 -0
- package/dist/tools/sql-drift-tools.js.map +1 -0
- package/dist/tools/sql-lint-schema-tools.d.ts +28 -0
- package/dist/tools/sql-lint-schema-tools.d.ts.map +1 -0
- package/dist/tools/sql-lint-schema-tools.js +96 -0
- package/dist/tools/sql-lint-schema-tools.js.map +1 -0
- package/dist/tools/sql-migration-diff-tools.d.ts +24 -0
- package/dist/tools/sql-migration-diff-tools.d.ts.map +1 -0
- package/dist/tools/sql-migration-diff-tools.js +120 -0
- package/dist/tools/sql-migration-diff-tools.js.map +1 -0
- package/dist/tools/sql-orphan-table-tools.d.ts +20 -0
- package/dist/tools/sql-orphan-table-tools.d.ts.map +1 -0
- package/dist/tools/sql-orphan-table-tools.js +70 -0
- package/dist/tools/sql-orphan-table-tools.js.map +1 -0
- package/dist/tools/sql-query-tools.d.ts +32 -0
- package/dist/tools/sql-query-tools.d.ts.map +1 -0
- package/dist/tools/sql-query-tools.js +130 -0
- package/dist/tools/sql-query-tools.js.map +1 -0
- package/dist/tools/sql-schema-tools.d.ts +47 -0
- package/dist/tools/sql-schema-tools.d.ts.map +1 -0
- package/dist/tools/sql-schema-tools.js +202 -0
- package/dist/tools/sql-schema-tools.js.map +1 -0
- package/dist/tools/sql-shared-tools.d.ts +6 -0
- package/dist/tools/sql-shared-tools.d.ts.map +1 -0
- package/dist/tools/sql-shared-tools.js +59 -0
- package/dist/tools/sql-shared-tools.js.map +1 -0
- package/dist/tools/sql-tools.d.ts +25 -296
- package/dist/tools/sql-tools.d.ts.map +1 -1
- package/dist/tools/sql-tools.js +15 -1232
- package/dist/tools/sql-tools.js.map +1 -1
- package/dist/tools/status-tools.js +1 -1
- package/dist/tools/status-tools.js.map +1 -1
- package/dist/tools/workspace-tools.d.ts +1 -1
- package/dist/tools/yii3-migration-categories-application.d.ts +4 -0
- package/dist/tools/yii3-migration-categories-application.d.ts.map +1 -0
- package/dist/tools/yii3-migration-categories-application.js +56 -0
- package/dist/tools/yii3-migration-categories-application.js.map +1 -0
- package/dist/tools/yii3-migration-categories-infrastructure.d.ts +4 -0
- package/dist/tools/yii3-migration-categories-infrastructure.d.ts.map +1 -0
- package/dist/tools/yii3-migration-categories-infrastructure.js +67 -0
- package/dist/tools/yii3-migration-categories-infrastructure.js.map +1 -0
- package/dist/tools/yii3-migration-categories-model-view.d.ts +4 -0
- package/dist/tools/yii3-migration-categories-model-view.d.ts.map +1 -0
- package/dist/tools/yii3-migration-categories-model-view.js +59 -0
- package/dist/tools/yii3-migration-categories-model-view.js.map +1 -0
- package/dist/tools/yii3-migration-categories-runtime.d.ts +4 -0
- package/dist/tools/yii3-migration-categories-runtime.d.ts.map +1 -0
- package/dist/tools/yii3-migration-categories-runtime.js +49 -0
- package/dist/tools/yii3-migration-categories-runtime.js.map +1 -0
- package/dist/tools/yii3-migration-categories.d.ts +5 -0
- package/dist/tools/yii3-migration-categories.d.ts.map +1 -0
- package/dist/tools/yii3-migration-categories.js +18 -0
- package/dist/tools/yii3-migration-categories.js.map +1 -0
- package/dist/tools/yii3-migration-report.d.ts +4 -0
- package/dist/tools/yii3-migration-report.d.ts.map +1 -0
- package/dist/tools/yii3-migration-report.js +88 -0
- package/dist/tools/yii3-migration-report.js.map +1 -0
- package/dist/tools/yii3-migration-scanner.d.ts +28 -0
- package/dist/tools/yii3-migration-scanner.d.ts.map +1 -0
- package/dist/tools/yii3-migration-scanner.js +87 -0
- package/dist/tools/yii3-migration-scanner.js.map +1 -0
- package/dist/tools/yii3-migration-tools.d.ts +4 -73
- package/dist/tools/yii3-migration-tools.d.ts.map +1 -1
- package/dist/tools/yii3-migration-tools.js +5 -433
- package/dist/tools/yii3-migration-tools.js.map +1 -1
- package/dist/tools/yii3-migration-types.d.ts +50 -0
- package/dist/tools/yii3-migration-types.d.ts.map +1 -0
- package/dist/tools/yii3-migration-types.js +3 -0
- package/dist/tools/yii3-migration-types.js.map +1 -0
- package/dist/utils/edge-provenance.d.ts +55 -0
- package/dist/utils/edge-provenance.d.ts.map +1 -0
- package/dist/utils/edge-provenance.js +53 -0
- package/dist/utils/edge-provenance.js.map +1 -0
- package/dist/utils/git-validation.d.ts +24 -0
- package/dist/utils/git-validation.d.ts.map +1 -1
- package/dist/utils/git-validation.js +30 -0
- package/dist/utils/git-validation.js.map +1 -1
- package/dist/utils/overlay-cache.d.ts +38 -0
- package/dist/utils/overlay-cache.d.ts.map +1 -0
- package/dist/utils/overlay-cache.js +73 -0
- package/dist/utils/overlay-cache.js.map +1 -0
- package/dist/utils/source-stripper/code-handler.d.ts +3 -0
- package/dist/utils/source-stripper/code-handler.d.ts.map +1 -0
- package/dist/utils/source-stripper/code-handler.js +79 -0
- package/dist/utils/source-stripper/code-handler.js.map +1 -0
- package/dist/utils/source-stripper/comment-handler.d.ts +4 -0
- package/dist/utils/source-stripper/comment-handler.d.ts.map +1 -0
- package/dist/utils/source-stripper/comment-handler.js +24 -0
- package/dist/utils/source-stripper/comment-handler.js.map +1 -0
- package/dist/utils/source-stripper/machine.d.ts +2 -0
- package/dist/utils/source-stripper/machine.d.ts.map +1 -0
- package/dist/utils/source-stripper/machine.js +34 -0
- package/dist/utils/source-stripper/machine.js.map +1 -0
- package/dist/utils/source-stripper/regex-handler.d.ts +3 -0
- package/dist/utils/source-stripper/regex-handler.d.ts.map +1 -0
- package/dist/utils/source-stripper/regex-handler.js +44 -0
- package/dist/utils/source-stripper/regex-handler.js.map +1 -0
- package/dist/utils/source-stripper/state.d.ts +4 -0
- package/dist/utils/source-stripper/state.d.ts.map +1 -0
- package/dist/utils/source-stripper/state.js +20 -0
- package/dist/utils/source-stripper/state.js.map +1 -0
- package/dist/utils/source-stripper/string-handler.d.ts +3 -0
- package/dist/utils/source-stripper/string-handler.d.ts.map +1 -0
- package/dist/utils/source-stripper/string-handler.js +19 -0
- package/dist/utils/source-stripper/string-handler.js.map +1 -0
- package/dist/utils/source-stripper/template-handler.d.ts +4 -0
- package/dist/utils/source-stripper/template-handler.d.ts.map +1 -0
- package/dist/utils/source-stripper/template-handler.js +40 -0
- package/dist/utils/source-stripper/template-handler.js.map +1 -0
- package/dist/utils/source-stripper/types.d.ts +17 -0
- package/dist/utils/source-stripper/types.d.ts.map +1 -0
- package/dist/utils/source-stripper/types.js +4 -0
- package/dist/utils/source-stripper/types.js.map +1 -0
- package/dist/utils/source-stripper.d.ts +0 -21
- package/dist/utils/source-stripper.d.ts.map +1 -1
- package/dist/utils/source-stripper.js +6 -234
- package/dist/utils/source-stripper.js.map +1 -1
- package/dist/utils/walk/errors.d.ts +4 -0
- package/dist/utils/walk/errors.d.ts.map +1 -0
- package/dist/utils/walk/errors.js +18 -0
- package/dist/utils/walk/errors.js.map +1 -0
- package/dist/utils/walk/filters.d.ts +11 -0
- package/dist/utils/walk/filters.d.ts.map +1 -0
- package/dist/utils/walk/filters.js +53 -0
- package/dist/utils/walk/filters.js.map +1 -0
- package/dist/utils/walk/limits.d.ts +10 -0
- package/dist/utils/walk/limits.d.ts.map +1 -0
- package/dist/utils/walk/limits.js +22 -0
- package/dist/utils/walk/limits.js.map +1 -0
- package/dist/utils/walk/traversal.d.ts +9 -0
- package/dist/utils/walk/traversal.d.ts.map +1 -0
- package/dist/utils/walk/traversal.js +38 -0
- package/dist/utils/walk/traversal.js.map +1 -0
- package/dist/utils/walk/types.d.ts +18 -0
- package/dist/utils/walk/types.d.ts.map +1 -0
- package/dist/utils/walk/types.js +2 -0
- package/dist/utils/walk/types.js.map +1 -0
- package/dist/utils/walk.d.ts +4 -65
- package/dist/utils/walk.d.ts.map +1 -1
- package/dist/utils/walk.js +23 -151
- package/dist/utils/walk.js.map +1 -1
- package/package.json +6 -5
package/dist/tools/php-tools.js
CHANGED
|
@@ -1,1427 +1,16 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* PHP/Yii2-specific code intelligence tools.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
export
|
|
15
|
-
|
|
16
|
-
if (!index)
|
|
17
|
-
throw new Error(`Repository "${repo}" not found.`);
|
|
18
|
-
const composer = await readJsonSafe(join(index.root, "composer.json"));
|
|
19
|
-
const psr4 = {
|
|
20
|
-
...(composer?.autoload?.["psr-4"] ?? {}),
|
|
21
|
-
...(composer?.["autoload-dev"]?.["psr-4"] ?? {}),
|
|
22
|
-
};
|
|
23
|
-
// Strip leading backslash
|
|
24
|
-
const normalized = className.replace(/^\\/, "");
|
|
25
|
-
const parts = normalized.split("\\");
|
|
26
|
-
const namespaceOnly = parts.slice(0, -1).join("\\");
|
|
27
|
-
const shortName = parts[parts.length - 1];
|
|
28
|
-
// Find matching PSR-4 prefix (longest match wins)
|
|
29
|
-
let bestPrefix = null;
|
|
30
|
-
let bestRoot = null;
|
|
31
|
-
for (const [prefix, roots] of Object.entries(psr4)) {
|
|
32
|
-
const normalizedPrefix = prefix.replace(/\\$/, "");
|
|
33
|
-
if (normalized.startsWith(normalizedPrefix + "\\") || normalized === normalizedPrefix) {
|
|
34
|
-
if (!bestPrefix || normalizedPrefix.length > bestPrefix.length) {
|
|
35
|
-
bestPrefix = normalizedPrefix;
|
|
36
|
-
bestRoot = Array.isArray(roots) ? roots[0] ?? null : roots;
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
if (!bestPrefix || !bestRoot) {
|
|
41
|
-
return {
|
|
42
|
-
class_name: shortName,
|
|
43
|
-
namespace: namespaceOnly,
|
|
44
|
-
file_path: null,
|
|
45
|
-
exists: false,
|
|
46
|
-
psr4_root: null,
|
|
47
|
-
psr4_prefix: null,
|
|
48
|
-
};
|
|
49
|
-
}
|
|
50
|
-
// Construct file path: strip prefix, replace \ with /, append .php
|
|
51
|
-
const remainder = normalized.slice(bestPrefix.length).replace(/^\\/, "");
|
|
52
|
-
const relativePath = remainder.replace(/\\/g, "/") + ".php";
|
|
53
|
-
const root = bestRoot.replace(/\/$/, "");
|
|
54
|
-
const filePath = root + "/" + relativePath;
|
|
55
|
-
// Check if file exists in index (strip leading ./ for comparison)
|
|
56
|
-
const normalizedFP = filePath.replace(/^\.\//, "");
|
|
57
|
-
const exists = index.files.some((f) => f.path === normalizedFP || f.path === filePath);
|
|
58
|
-
return {
|
|
59
|
-
class_name: shortName,
|
|
60
|
-
namespace: namespaceOnly,
|
|
61
|
-
file_path: filePath,
|
|
62
|
-
exists,
|
|
63
|
-
psr4_root: bestRoot,
|
|
64
|
-
psr4_prefix: bestPrefix,
|
|
65
|
-
};
|
|
66
|
-
}
|
|
67
|
-
/**
|
|
68
|
-
* Names of class roots that we treat as "this is an ActiveRecord". The check
|
|
69
|
-
* is done on the LAST namespace segment so prefixed forms (yii\\db\\ActiveRecord,
|
|
70
|
-
* \\yii\\db\\ActiveRecord, app\\models\\ActiveRecord) all match. Includes
|
|
71
|
-
* yii\\base\\Model because Yii2 form models extending Model share the
|
|
72
|
-
* rules() / behaviors() lifecycle that analyzeActiveRecord introspects;
|
|
73
|
-
* downstream callers can filter by tableName() presence if they need a
|
|
74
|
-
* stricter "real DB-backed AR" criterion.
|
|
75
|
-
*/
|
|
76
|
-
const AR_ROOT_NAMES = new Set(["ActiveRecord", "Model", "BaseActiveRecord"]);
|
|
77
|
-
/**
|
|
78
|
-
* Walk a class symbol's `extends` chain and return true if any ancestor
|
|
79
|
-
* matches a known ActiveRecord base class. Resolves transitively via the
|
|
80
|
-
* symbol index — handles cases like `User extends BaseUser` where
|
|
81
|
-
* `BaseUser extends ActiveRecord`.
|
|
82
|
-
*
|
|
83
|
-
* Direct match (root name in our AR_ROOT_NAMES set) wins immediately.
|
|
84
|
-
* Otherwise we look up the parent class symbol by name and recurse. The
|
|
85
|
-
* lookup uses last-segment name matching (e.g. `BaseUser` matches a class
|
|
86
|
-
* symbol whose `name` is exactly `BaseUser`, regardless of namespace) which
|
|
87
|
-
* is good enough for the codebases we care about; cross-package aliased
|
|
88
|
-
* resolution would require parsing per-file `use` tables.
|
|
89
|
-
*
|
|
90
|
-
* Cycle protection via a visited set; depth-cap of 5 (no real Yii2 model
|
|
91
|
-
* has a deeper chain).
|
|
92
|
-
*/
|
|
93
|
-
function isActiveRecordHierarchy(cls, index, visited = new Set(), depth = 0) {
|
|
94
|
-
if (depth > 5)
|
|
95
|
-
return false;
|
|
96
|
-
if (visited.has(cls.name))
|
|
97
|
-
return false;
|
|
98
|
-
visited.add(cls.name);
|
|
99
|
-
const exts = cls.extends ?? [];
|
|
100
|
-
for (const baseFqcn of exts) {
|
|
101
|
-
// Last segment of FQCN (handles "\\yii\\db\\ActiveRecord" and aliases).
|
|
102
|
-
const last = baseFqcn.split(/[\\\\]+/).pop() ?? baseFqcn;
|
|
103
|
-
if (AR_ROOT_NAMES.has(last))
|
|
104
|
-
return true;
|
|
105
|
-
// Look up the base class as an indexed symbol and recurse.
|
|
106
|
-
const baseSym = index.symbols.find((s) => s.kind === "class" && s.name === last);
|
|
107
|
-
if (baseSym && isActiveRecordHierarchy(baseSym, index, visited, depth + 1)) {
|
|
108
|
-
return true;
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
// Fallback for older indexes (e.g. before the v2.0.0 extractor bump): if
|
|
112
|
-
// `extends` is missing on this symbol, try the legacy regex against
|
|
113
|
-
// `source` so we don't regress on unindexed projects.
|
|
114
|
-
if (!cls.extends && cls.source) {
|
|
115
|
-
return /extends\s+(?:ActiveRecord|Model|\\yii\\db\\ActiveRecord)\b/.test(cls.source);
|
|
116
|
-
}
|
|
117
|
-
return false;
|
|
118
|
-
}
|
|
119
|
-
export async function analyzeActiveRecord(repo, options) {
|
|
120
|
-
const index = await getCodeIndex(repo);
|
|
121
|
-
if (!index)
|
|
122
|
-
throw new Error(`Repository "${repo}" not found.`);
|
|
123
|
-
// Find PHP class symbols in model files
|
|
124
|
-
const classSymbols = index.symbols.filter((s) => {
|
|
125
|
-
if (s.kind !== "class")
|
|
126
|
-
return false;
|
|
127
|
-
if (!s.file.endsWith(".php"))
|
|
128
|
-
return false;
|
|
129
|
-
if (options?.model_name && s.name !== options.model_name)
|
|
130
|
-
return false;
|
|
131
|
-
if (options?.file_pattern && !s.file.includes(options.file_pattern))
|
|
132
|
-
return false;
|
|
133
|
-
return true;
|
|
134
|
-
});
|
|
135
|
-
const models = [];
|
|
136
|
-
for (const cls of classSymbols) {
|
|
137
|
-
if (!cls.source)
|
|
138
|
-
continue;
|
|
139
|
-
if (!isActiveRecordHierarchy(cls, index))
|
|
140
|
-
continue;
|
|
141
|
-
const model = {
|
|
142
|
-
name: cls.name,
|
|
143
|
-
file: cls.file,
|
|
144
|
-
table_name: null,
|
|
145
|
-
relations: [],
|
|
146
|
-
rules: [],
|
|
147
|
-
behaviors: [],
|
|
148
|
-
methods: [],
|
|
149
|
-
};
|
|
150
|
-
// Extract tableName() return value
|
|
151
|
-
const tableMatch = /function\s+tableName\s*\([^)]*\)[^{]*\{[^}]*return\s+['"]([^'"]+)['"]/s.exec(cls.source);
|
|
152
|
-
if (tableMatch)
|
|
153
|
-
model.table_name = tableMatch[1];
|
|
154
|
-
// Find child method symbols
|
|
155
|
-
const methods = index.symbols.filter((s) => s.parent === cls.id && s.kind === "method");
|
|
156
|
-
model.methods = methods.map((m) => m.name);
|
|
157
|
-
// Extract relations from getX() methods that return hasOne/hasMany.
|
|
158
|
-
// Two-pass detection:
|
|
159
|
-
// Pass 1: find the primary `->hasOne(Target::class, ...)` or
|
|
160
|
-
// `->hasMany(Target::class, ...)` call.
|
|
161
|
-
// Pass 2: scan the rest of the source for modifiers:
|
|
162
|
-
// ->via('relation') (Yii2 2.0.13+ junction table via relation)
|
|
163
|
-
// ->viaTable('tbl', [...]) (direct junction table)
|
|
164
|
-
// ->inverseOf('relation') (bidirectional relation)
|
|
165
|
-
// The presence of `via` or `viaTable` upgrades the relation type
|
|
166
|
-
// to `manyMany`. `inverseOf` is decorative and doesn't change type.
|
|
167
|
-
for (const m of methods) {
|
|
168
|
-
if (!m.name.startsWith("get") || !m.source)
|
|
169
|
-
continue;
|
|
170
|
-
const relName = m.name.slice(3);
|
|
171
|
-
const primaryRe = /->(hasOne|hasMany)\s*\(\s*([\w\\]+)(?:::class)?/;
|
|
172
|
-
const primaryMatch = primaryRe.exec(m.source);
|
|
173
|
-
if (!primaryMatch)
|
|
174
|
-
continue;
|
|
175
|
-
const baseType = primaryMatch[1] === "hasOne" ? "hasOne" : "hasMany";
|
|
176
|
-
const targetClass = primaryMatch[2];
|
|
177
|
-
// Scan the method source for junction-table modifiers on the same chain.
|
|
178
|
-
// If found, the semantic type is manyMany even though the primary call was hasMany.
|
|
179
|
-
const hasJunction = /->(?:via|viaTable)\s*\(/.test(m.source);
|
|
180
|
-
const type = hasJunction ? "manyMany" : baseType;
|
|
181
|
-
model.relations.push({
|
|
182
|
-
name: relName.charAt(0).toLowerCase() + relName.slice(1),
|
|
183
|
-
type,
|
|
184
|
-
target_class: targetClass,
|
|
185
|
-
});
|
|
186
|
-
}
|
|
187
|
-
// Extract rule validators (loose regex on rules() method source)
|
|
188
|
-
const rulesMethod = methods.find((m) => m.name === "rules");
|
|
189
|
-
if (rulesMethod?.source) {
|
|
190
|
-
const ruleMatches = rulesMethod.source.matchAll(/\[\s*\[?['"]?[\w,\s'"]+['"]?\]?\s*,\s*['"]([\w]+)['"]/g);
|
|
191
|
-
for (const rm of ruleMatches) {
|
|
192
|
-
if (rm[1] && !model.rules.includes(rm[1]))
|
|
193
|
-
model.rules.push(rm[1]);
|
|
194
|
-
}
|
|
195
|
-
}
|
|
196
|
-
// Extract behaviors from behaviors() method
|
|
197
|
-
const behaviorsMethod = methods.find((m) => m.name === "behaviors");
|
|
198
|
-
if (behaviorsMethod?.source) {
|
|
199
|
-
const bMatches = behaviorsMethod.source.matchAll(/([A-Z]\w+Behavior)(?:::class)?/g);
|
|
200
|
-
for (const bm of bMatches) {
|
|
201
|
-
if (bm[1] && !model.behaviors.includes(bm[1]))
|
|
202
|
-
model.behaviors.push(bm[1]);
|
|
203
|
-
}
|
|
204
|
-
}
|
|
205
|
-
models.push(model);
|
|
206
|
-
}
|
|
207
|
-
return { models, total: models.length };
|
|
208
|
-
}
|
|
209
|
-
/**
|
|
210
|
-
* Build a class-const → literal-value map for the entire index. Yii2's
|
|
211
|
-
* canonical event idiom is `Event::on(User::class, User::EVENT_AFTER_LOGIN, ...)`,
|
|
212
|
-
* where `EVENT_AFTER_LOGIN` is a class constant with a string value. The
|
|
213
|
-
* default tracePhpEvent regex only sees literals, so without resolution
|
|
214
|
-
* `Class::CONST` references look like dead code. This pre-pass walks all
|
|
215
|
-
* `constant` symbols belonging to PHP classes and extracts their string /
|
|
216
|
-
* int literal values from `source`.
|
|
217
|
-
*
|
|
218
|
-
* Map keys are `ClassName::CONST_NAME`. Class lookup is by last name segment
|
|
219
|
-
* — same convention as isActiveRecordHierarchy — so namespace prefixes don't
|
|
220
|
-
* matter for callers using `User::EVENT_X` against a class named `User`.
|
|
221
|
-
*
|
|
222
|
-
* Returns an empty map if no constants resolve. Cost is one O(n) walk per
|
|
223
|
-
* call; could be cached on the index in the future if event tracing becomes
|
|
224
|
-
* a hot path.
|
|
225
|
-
*/
|
|
226
|
-
function buildConstantValueMap(index) {
|
|
227
|
-
const out = new Map();
|
|
228
|
-
// First, build classId → className map so we can resolve const owners.
|
|
229
|
-
const classIdToName = new Map();
|
|
230
|
-
for (const s of index.symbols) {
|
|
231
|
-
if (s.kind === "class" || s.kind === "interface" || s.kind === "enum") {
|
|
232
|
-
// Use the symbol id as key — every constant carries `parent` referring
|
|
233
|
-
// to its enclosing class id, so we only need the id→name lookup.
|
|
234
|
-
const id = s.id;
|
|
235
|
-
if (id)
|
|
236
|
-
classIdToName.set(id, s.name);
|
|
237
|
-
}
|
|
238
|
-
}
|
|
239
|
-
for (const s of index.symbols) {
|
|
240
|
-
if (s.kind !== "constant")
|
|
241
|
-
continue;
|
|
242
|
-
if (!s.parent || !s.source)
|
|
243
|
-
continue;
|
|
244
|
-
const className = classIdToName.get(s.parent);
|
|
245
|
-
if (!className)
|
|
246
|
-
continue;
|
|
247
|
-
// Match the literal value: `const NAME = 'value';` or `const NAME = "v";`
|
|
248
|
-
// or `const NAME = 42;`. We accept the first occurrence in the constant's
|
|
249
|
-
// source slice — the extractor already narrows source to a single decl.
|
|
250
|
-
const m = /=\s*(?:['"]([^'"]+)['"]|(-?\d+(?:\.\d+)?))/.exec(s.source);
|
|
251
|
-
if (!m)
|
|
252
|
-
continue;
|
|
253
|
-
const value = m[1] ?? m[2];
|
|
254
|
-
if (value === undefined)
|
|
255
|
-
continue;
|
|
256
|
-
out.set(`${className}::${s.name}`, value);
|
|
257
|
-
}
|
|
258
|
-
return out;
|
|
259
|
-
}
|
|
260
|
-
export async function tracePhpEvent(repo, options) {
|
|
261
|
-
const index = await getCodeIndex(repo);
|
|
262
|
-
if (!index)
|
|
263
|
-
throw new Error(`Repository "${repo}" not found.`);
|
|
264
|
-
const eventMap = new Map();
|
|
265
|
-
const constantValues = buildConstantValueMap(index);
|
|
266
|
-
const getOrCreate = (name) => {
|
|
267
|
-
let e = eventMap.get(name);
|
|
268
|
-
if (!e) {
|
|
269
|
-
e = { event_name: name, triggers: [], listeners: [] };
|
|
270
|
-
eventMap.set(name, e);
|
|
271
|
-
}
|
|
272
|
-
return e;
|
|
273
|
-
};
|
|
274
|
-
// Resolve `Class::CONST` references to their literal values via the pre-pass
|
|
275
|
-
// map. Returns the original key when the class+const pair isn't indexed
|
|
276
|
-
// (e.g. constants defined in vendor/) so the trace at least shows there's
|
|
277
|
-
// SOMETHING happening at this site.
|
|
278
|
-
const resolveEventName = (raw) => {
|
|
279
|
-
return constantValues.get(raw) ?? raw;
|
|
280
|
-
};
|
|
281
|
-
// Scan PHP file symbols for event triggers and listeners
|
|
282
|
-
const phpSymbols = index.symbols.filter((s) => s.file.endsWith(".php") && s.source);
|
|
283
|
-
for (const sym of phpSymbols) {
|
|
284
|
-
const source = sym.source;
|
|
285
|
-
// Triggers: ->trigger('eventName') or ->trigger(Class::CONST)
|
|
286
|
-
// Now also accepts a bare identifier path (Foo::BAR) in addition to the
|
|
287
|
-
// string-literal form.
|
|
288
|
-
const triggerRe = /->trigger\s*\(\s*(?:['"]([^'"]+)['"]|([A-Z_][\w]*::[A-Z_][\w]*))/g;
|
|
289
|
-
let match;
|
|
290
|
-
while ((match = triggerRe.exec(source)) !== null) {
|
|
291
|
-
const literal = match[1];
|
|
292
|
-
const constRef = match[2];
|
|
293
|
-
const eventName = literal ?? (constRef ? resolveEventName(constRef) : undefined);
|
|
294
|
-
if (!eventName)
|
|
295
|
-
continue;
|
|
296
|
-
if (options?.event_name && eventName !== options.event_name)
|
|
297
|
-
continue;
|
|
298
|
-
const line = sym.start_line + (source.slice(0, match.index).match(/\n/g)?.length ?? 0);
|
|
299
|
-
getOrCreate(eventName).triggers.push({
|
|
300
|
-
file: sym.file,
|
|
301
|
-
line,
|
|
302
|
-
context: extractLineContext(source, match.index),
|
|
303
|
-
});
|
|
304
|
-
}
|
|
305
|
-
// Listeners: ->on('eventName', ...) or ::on('eventName', ...) or
|
|
306
|
-
// ::on(Foo::class, Foo::EVENT_BAR, ...)
|
|
307
|
-
// Yii2 prefers the class-const form for built-in events, so resolution is
|
|
308
|
-
// critical here.
|
|
309
|
-
const listenerRe = /(?:->|::)on\s*\(\s*(?:[A-Z_][\w]*::class\s*,\s*)?(?:['"]([^'"]+)['"]|([A-Z_][\w]*::[A-Z_][\w]*))/g;
|
|
310
|
-
while ((match = listenerRe.exec(source)) !== null) {
|
|
311
|
-
const literal = match[1];
|
|
312
|
-
const constRef = match[2];
|
|
313
|
-
const eventName = literal ?? (constRef ? resolveEventName(constRef) : undefined);
|
|
314
|
-
if (!eventName)
|
|
315
|
-
continue;
|
|
316
|
-
if (options?.event_name && eventName !== options.event_name)
|
|
317
|
-
continue;
|
|
318
|
-
const line = sym.start_line + (source.slice(0, match.index).match(/\n/g)?.length ?? 0);
|
|
319
|
-
getOrCreate(eventName).listeners.push({
|
|
320
|
-
file: sym.file,
|
|
321
|
-
line,
|
|
322
|
-
context: extractLineContext(source, match.index),
|
|
323
|
-
});
|
|
324
|
-
}
|
|
325
|
-
}
|
|
326
|
-
const events = [...eventMap.values()];
|
|
327
|
-
return { events, total: events.length };
|
|
328
|
-
}
|
|
329
|
-
/**
|
|
330
|
-
* Yii2 view + layout + widget + asset-bundle inventory.
|
|
331
|
-
*
|
|
332
|
-
* Beyond the original render→view mapping (Sprint 1), the tool now also:
|
|
333
|
-
* - Distinguishes render flavors (full/partial/ajax/json/file) so
|
|
334
|
-
* downstream caching/SEO audits can scope their checks.
|
|
335
|
-
* - Resolves `@alias/...` paths via the path-alias map sourced from
|
|
336
|
-
* `Yii::setAlias()` calls and `aliases` keys in config files.
|
|
337
|
-
* - Captures `$this->layout = '...'` assignments (controller-wide and
|
|
338
|
-
* per-action overrides).
|
|
339
|
-
* - Lists widget references (`GridView::begin/widget`) found anywhere
|
|
340
|
-
* in the codebase.
|
|
341
|
-
* - Lists `AssetBundle::register($this)` calls.
|
|
342
|
-
*/
|
|
343
|
-
export async function findPhpViews(repo, options) {
|
|
344
|
-
const index = await getCodeIndex(repo);
|
|
345
|
-
if (!index)
|
|
346
|
-
throw new Error(`Repository "${repo}" not found.`);
|
|
347
|
-
const includeWidgets = options?.include_widgets ?? true;
|
|
348
|
-
const includeBundles = options?.include_asset_bundles ?? true;
|
|
349
|
-
const mappings = [];
|
|
350
|
-
const layouts = [];
|
|
351
|
-
const widgets = [];
|
|
352
|
-
const assetBundles = [];
|
|
353
|
-
// Resolve path aliases up-front. The map is consulted for every
|
|
354
|
-
// render() / layout assignment / view file path that begins with `@`.
|
|
355
|
-
const aliasMap = await resolvePathAliases(index);
|
|
356
|
-
// Find action methods in controllers
|
|
357
|
-
const controllers = index.symbols.filter((s) => s.kind === "class" && s.name.endsWith("Controller") && s.file.endsWith(".php"));
|
|
358
|
-
for (const ctrl of controllers) {
|
|
359
|
-
if (options?.controller && !ctrl.name.includes(options.controller))
|
|
360
|
-
continue;
|
|
361
|
-
// Controller-wide layout: `$this->layout = '...'` declared as a property
|
|
362
|
-
// OR set in init() / beforeAction() / a per-action method.
|
|
363
|
-
if (ctrl.source) {
|
|
364
|
-
const layoutPropRe = /(?:public|protected|private)?\s*\$layout\s*=\s*['"]([^'"]+)['"]/;
|
|
365
|
-
const propMatch = layoutPropRe.exec(ctrl.source);
|
|
366
|
-
if (propMatch) {
|
|
367
|
-
const layoutName = propMatch[1];
|
|
368
|
-
layouts.push({
|
|
369
|
-
controller: ctrl.name,
|
|
370
|
-
action: null,
|
|
371
|
-
layout: layoutName,
|
|
372
|
-
layout_file: resolveLayoutFile(layoutName, ctrl.name, aliasMap, index),
|
|
373
|
-
set_at_line: ctrl.start_line + (ctrl.source.slice(0, propMatch.index).match(/\n/g)?.length ?? 0),
|
|
374
|
-
});
|
|
375
|
-
}
|
|
376
|
-
}
|
|
377
|
-
const actions = index.symbols.filter((s) => s.parent === ctrl.id && s.kind === "method" && s.name.startsWith("action"));
|
|
378
|
-
for (const action of actions) {
|
|
379
|
-
if (!action.source)
|
|
380
|
-
continue;
|
|
381
|
-
// Match $this->render('viewName'), renderPartial('...'), renderAjax('...')
|
|
382
|
-
// Capture the render KIND from the suffix so callers can filter by
|
|
383
|
-
// flavor downstream.
|
|
384
|
-
const renderRe = /\$this->render(Partial|Ajax|AsJson|File)?\s*\(\s*['"]([^'"]+)['"]/g;
|
|
385
|
-
let match;
|
|
386
|
-
while ((match = renderRe.exec(action.source)) !== null) {
|
|
387
|
-
const suffix = match[1] ?? "";
|
|
388
|
-
const viewName = match[2];
|
|
389
|
-
const renderKind = suffix === ""
|
|
390
|
-
? "full"
|
|
391
|
-
: suffix.toLowerCase().replace("asjson", "json");
|
|
392
|
-
const { file: viewFile, alias } = resolveViewFile(viewName, ctrl.name, aliasMap, index);
|
|
393
|
-
const line = action.start_line + (action.source.slice(0, match.index).match(/\n/g)?.length ?? 0);
|
|
394
|
-
mappings.push({
|
|
395
|
-
controller: ctrl.name,
|
|
396
|
-
action: action.name,
|
|
397
|
-
view_name: viewName,
|
|
398
|
-
view_file: viewFile,
|
|
399
|
-
render_line: line,
|
|
400
|
-
render_kind: renderKind,
|
|
401
|
-
path_alias: alias,
|
|
402
|
-
});
|
|
403
|
-
}
|
|
404
|
-
// Per-action layout override: `$this->layout = '...'` inside the
|
|
405
|
-
// action body. Distinct entry from the controller-wide property.
|
|
406
|
-
const layoutAssignRe = /\$this->layout\s*=\s*['"]([^'"]+)['"]/g;
|
|
407
|
-
while ((match = layoutAssignRe.exec(action.source)) !== null) {
|
|
408
|
-
const layoutName = match[1];
|
|
409
|
-
const line = action.start_line +
|
|
410
|
-
(action.source.slice(0, match.index).match(/\n/g)?.length ?? 0);
|
|
411
|
-
layouts.push({
|
|
412
|
-
controller: ctrl.name,
|
|
413
|
-
action: action.name,
|
|
414
|
-
layout: layoutName,
|
|
415
|
-
layout_file: resolveLayoutFile(layoutName, ctrl.name, aliasMap, index),
|
|
416
|
-
set_at_line: line,
|
|
417
|
-
});
|
|
418
|
-
}
|
|
419
|
-
}
|
|
420
|
-
}
|
|
421
|
-
// Widget references — scan ALL PHP symbols + all .php files at module
|
|
422
|
-
// level (views are file-scope code, not symbols).
|
|
423
|
-
if (includeWidgets) {
|
|
424
|
-
collectWidgetRefs(index, widgets);
|
|
425
|
-
}
|
|
426
|
-
// AssetBundle::register() — same scope.
|
|
427
|
-
if (includeBundles) {
|
|
428
|
-
collectAssetBundleRefs(index, assetBundles);
|
|
429
|
-
}
|
|
430
|
-
return {
|
|
431
|
-
mappings,
|
|
432
|
-
total: mappings.length,
|
|
433
|
-
layouts,
|
|
434
|
-
widgets,
|
|
435
|
-
asset_bundles: assetBundles,
|
|
436
|
-
};
|
|
437
|
-
}
|
|
438
|
-
/**
|
|
439
|
-
* Build a path-alias map from Yii::setAlias() calls + config-file aliases.
|
|
440
|
-
* Map is keyed by the alias INCLUDING the leading `@` (so callers can
|
|
441
|
-
* test membership cheaply against the input string).
|
|
442
|
-
*
|
|
443
|
-
* Default Yii2 aliases (`@app`, `@webroot`, etc.) are inferred from the
|
|
444
|
-
* repo root when not explicitly set, so a fresh project still gets a
|
|
445
|
-
* useful default map.
|
|
446
|
-
*/
|
|
447
|
-
async function resolvePathAliases(index) {
|
|
448
|
-
const aliases = new Map();
|
|
449
|
-
// Default aliases. `@app` is the conventional Yii2 anchor — almost
|
|
450
|
-
// every project has it pointing at the repo root.
|
|
451
|
-
aliases.set("@app", ".");
|
|
452
|
-
// Scan main config files for explicit aliases. Both
|
|
453
|
-
// 'aliases' => ['@foo' => 'path']
|
|
454
|
-
// and
|
|
455
|
-
// Yii::setAlias('@foo', 'path');
|
|
456
|
-
// are recognized.
|
|
457
|
-
const configFiles = index.files.filter((f) => /config\/(?:web|main|console|api|backend|frontend|common)(?:[-_][\w-]+)?\.php$/.test(f.path));
|
|
458
|
-
for (const cf of configFiles) {
|
|
459
|
-
let source;
|
|
460
|
-
try {
|
|
461
|
-
source = await readFile(join(index.root, cf.path), "utf-8");
|
|
462
|
-
}
|
|
463
|
-
catch {
|
|
464
|
-
continue;
|
|
465
|
-
}
|
|
466
|
-
// `aliases` => ['@x' => 'path', ...]
|
|
467
|
-
const aliasArrayRe = /['"]aliases['"]\s*=>\s*\[([^\]]+)\]/g;
|
|
468
|
-
let m;
|
|
469
|
-
while ((m = aliasArrayRe.exec(source)) !== null) {
|
|
470
|
-
const inner = m[1];
|
|
471
|
-
const entryRe = /['"](@[\w/.-]+)['"]\s*=>\s*['"]([^'"]+)['"]/g;
|
|
472
|
-
let em;
|
|
473
|
-
while ((em = entryRe.exec(inner)) !== null) {
|
|
474
|
-
aliases.set(em[1], em[2]);
|
|
475
|
-
}
|
|
476
|
-
}
|
|
477
|
-
// Yii::setAlias('@x', 'path');
|
|
478
|
-
const setAliasRe = /Yii::setAlias\s*\(\s*['"](@[\w/.-]+)['"]\s*,\s*['"]([^'"]+)['"]/g;
|
|
479
|
-
while ((m = setAliasRe.exec(source)) !== null) {
|
|
480
|
-
aliases.set(m[1], m[2]);
|
|
481
|
-
}
|
|
482
|
-
}
|
|
483
|
-
return aliases;
|
|
484
|
-
}
|
|
485
|
-
/**
|
|
486
|
-
* Resolve a view name to a path within the indexed file set. Prefers
|
|
487
|
-
* explicit `@alias/...` resolution; otherwise falls back to the Yii2
|
|
488
|
-
* convention `views/<controller-id>/<view>.php`. Returns the resolved
|
|
489
|
-
* (path, alias) pair — alias is the leading `@token` if one was used.
|
|
490
|
-
*
|
|
491
|
-
* The resolved path is matched against `index.files` to confirm the view
|
|
492
|
-
* actually exists; if not, file is null but alias is still surfaced so
|
|
493
|
-
* callers can flag missing-file findings against external asset paths.
|
|
494
|
-
*/
|
|
495
|
-
function resolveViewFile(viewName, controllerClass, aliases, index) {
|
|
496
|
-
// Path alias: `@app/views/...` or any alias-prefixed string.
|
|
497
|
-
if (viewName.startsWith("@")) {
|
|
498
|
-
const aliasMatch = /^(@[\w-]+)(\/.*)?$/.exec(viewName);
|
|
499
|
-
if (aliasMatch) {
|
|
500
|
-
const alias = aliasMatch[1];
|
|
501
|
-
const remainder = aliasMatch[2] ?? "";
|
|
502
|
-
const aliasTarget = aliases.get(alias);
|
|
503
|
-
if (aliasTarget !== undefined) {
|
|
504
|
-
const candidate = (aliasTarget.replace(/\/$/, "") + remainder).replace(/^\.\//, "");
|
|
505
|
-
const final = candidate.endsWith(".php") ? candidate : candidate + ".php";
|
|
506
|
-
const exists = index.files.some((f) => f.path === final || f.path.endsWith("/" + final));
|
|
507
|
-
return { file: exists ? final : null, alias };
|
|
508
|
-
}
|
|
509
|
-
return { file: null, alias };
|
|
510
|
-
}
|
|
511
|
-
}
|
|
512
|
-
// Path-style relative name: `subdir/foo` keeps the explicit subdir.
|
|
513
|
-
const isPath = viewName.includes("/");
|
|
514
|
-
const controllerId = pascalToKebab(controllerClass.replace(/Controller$/, ""));
|
|
515
|
-
const candidate = isPath
|
|
516
|
-
? `views/${viewName}.php`
|
|
517
|
-
: `views/${controllerId}/${viewName}.php`;
|
|
518
|
-
const exists = index.files.some((f) => f.path === candidate || f.path.endsWith("/" + candidate));
|
|
519
|
-
return { file: exists ? candidate : null, alias: null };
|
|
520
|
-
}
|
|
521
|
-
function resolveLayoutFile(layoutName, controllerClass, aliases, index) {
|
|
522
|
-
// Layouts default to `views/layouts/<name>.php` rather than per-controller.
|
|
523
|
-
if (layoutName.startsWith("@")) {
|
|
524
|
-
const aliasMatch = /^(@[\w-]+)(\/.*)?$/.exec(layoutName);
|
|
525
|
-
if (aliasMatch) {
|
|
526
|
-
const aliasTarget = aliases.get(aliasMatch[1]);
|
|
527
|
-
if (!aliasTarget)
|
|
528
|
-
return null;
|
|
529
|
-
const remainder = aliasMatch[2] ?? "";
|
|
530
|
-
const candidate = (aliasTarget.replace(/\/$/, "") + remainder).replace(/^\.\//, "");
|
|
531
|
-
const final = candidate.endsWith(".php") ? candidate : candidate + ".php";
|
|
532
|
-
const exists = index.files.some((f) => f.path === final || f.path.endsWith("/" + final));
|
|
533
|
-
return exists ? final : null;
|
|
534
|
-
}
|
|
535
|
-
return null;
|
|
536
|
-
}
|
|
537
|
-
const isPath = layoutName.includes("/");
|
|
538
|
-
const candidate = isPath
|
|
539
|
-
? `views/${layoutName}.php`
|
|
540
|
-
: `views/layouts/${layoutName}.php`;
|
|
541
|
-
const exists = index.files.some((f) => f.path === candidate || f.path.endsWith("/" + candidate));
|
|
542
|
-
return exists ? candidate : null;
|
|
543
|
-
void controllerClass; // referenced for future per-module path resolution
|
|
544
|
-
}
|
|
545
|
-
function collectWidgetRefs(index, out) {
|
|
546
|
-
// Build a quick parentId → class name map so we can attribute widget
|
|
547
|
-
// references to their containing class (when the widget lives inside
|
|
548
|
-
// a class method).
|
|
549
|
-
const idToClass = new Map();
|
|
550
|
-
for (const s of index.symbols) {
|
|
551
|
-
if (s.kind === "class") {
|
|
552
|
-
const id = s.id;
|
|
553
|
-
if (id)
|
|
554
|
-
idToClass.set(id, s.name);
|
|
555
|
-
}
|
|
556
|
-
}
|
|
557
|
-
// Yii2 widget API: `Widget::begin([...])` (followed by ::end()) and
|
|
558
|
-
// `Widget::widget([...])`. Both are method-call forms; we look for any
|
|
559
|
-
// CamelCase identifier ending in expected widget suffixes (Form, View,
|
|
560
|
-
// Pjax, Menu, Pager, Breadcrumbs, Modal) to filter out unrelated
|
|
561
|
-
// static calls. The bound list is pragmatic — the Yii2 ecosystem has
|
|
562
|
-
// hundreds of widget classes but ~95% match this suffix family.
|
|
563
|
-
const WIDGET_SUFFIXES = /(?:Form|View|Pjax|Menu|Pager|Breadcrumbs|Modal|GridView|ListView|DetailView|LinkPager|Captcha|Alert|Tabs|NavBar|Carousel|Dropdown|FileInput|DatePicker|RangeInput|Select2|TimePicker|Slider|MaskedInput|RadioButton|Tag)$/;
|
|
564
|
-
const re = /\b([A-Z][\w]*?)::(begin|widget)\s*\(/g;
|
|
565
|
-
for (const sym of index.symbols) {
|
|
566
|
-
if (!sym.source)
|
|
567
|
-
continue;
|
|
568
|
-
if (!sym.file.endsWith(".php"))
|
|
569
|
-
continue;
|
|
570
|
-
let m;
|
|
571
|
-
while ((m = re.exec(sym.source)) !== null) {
|
|
572
|
-
const widgetName = m[1];
|
|
573
|
-
const kindRaw = m[2];
|
|
574
|
-
if (!WIDGET_SUFFIXES.test(widgetName))
|
|
575
|
-
continue;
|
|
576
|
-
const callerClass = sym.parent ? idToClass.get(sym.parent) ?? null : null;
|
|
577
|
-
const callerMethod = sym.kind === "method" ? sym.name : null;
|
|
578
|
-
const line = sym.start_line +
|
|
579
|
-
(sym.source.slice(0, m.index).match(/\n/g)?.length ?? 0);
|
|
580
|
-
out.push({
|
|
581
|
-
widget: widgetName,
|
|
582
|
-
caller_class: callerClass,
|
|
583
|
-
caller_method: callerMethod,
|
|
584
|
-
file: sym.file,
|
|
585
|
-
line,
|
|
586
|
-
kind: kindRaw === "begin" ? "begin" : "widget",
|
|
587
|
-
});
|
|
588
|
-
}
|
|
589
|
-
}
|
|
590
|
-
}
|
|
591
|
-
function collectAssetBundleRefs(index, out) {
|
|
592
|
-
// `BundleClass::register($this)` — the canonical AssetBundle entry
|
|
593
|
-
// point. We capture the class name (last segment for FQCN forms).
|
|
594
|
-
const re = /\b([A-Z][\w\\]*?)::register\s*\(\s*\$this\b/g;
|
|
595
|
-
for (const sym of index.symbols) {
|
|
596
|
-
if (!sym.source)
|
|
597
|
-
continue;
|
|
598
|
-
if (!sym.file.endsWith(".php"))
|
|
599
|
-
continue;
|
|
600
|
-
let m;
|
|
601
|
-
while ((m = re.exec(sym.source)) !== null) {
|
|
602
|
-
const fqcn = m[1];
|
|
603
|
-
const last = fqcn.split(/[\\\\]+/).pop() ?? fqcn;
|
|
604
|
-
// Reject obvious false positives — `Yii::register()` doesn't exist
|
|
605
|
-
// but a few user classes might also expose `register($this)` for
|
|
606
|
-
// unrelated reasons. Filter to names that LOOK like an AssetBundle:
|
|
607
|
-
// suffix `Asset` is the universal Yii2 convention.
|
|
608
|
-
if (!/Asset(?:s|Bundle)?$/.test(last))
|
|
609
|
-
continue;
|
|
610
|
-
const line = sym.start_line +
|
|
611
|
-
(sym.source.slice(0, m.index).match(/\n/g)?.length ?? 0);
|
|
612
|
-
out.push({ bundle: last, file: sym.file, line });
|
|
613
|
-
}
|
|
614
|
-
}
|
|
615
|
-
}
|
|
616
|
-
export async function resolvePhpService(repo, options) {
|
|
617
|
-
const index = await getCodeIndex(repo);
|
|
618
|
-
if (!index)
|
|
619
|
-
throw new Error(`Repository "${repo}" not found.`);
|
|
620
|
-
const services = [];
|
|
621
|
-
// Sprint 3: include `params*.php` only as suppress-source — those files
|
|
622
|
-
// hold flat key-value pairs that look like components but aren't. We also
|
|
623
|
-
// drop config/test*.php (intentionally divergent) and pick up the broader
|
|
624
|
-
// *-local.php and main-*.php variants (advanced template + per-env splits).
|
|
625
|
-
const configFiles = index.files.filter((f) => {
|
|
626
|
-
if (!f.path.endsWith(".php"))
|
|
627
|
-
return false;
|
|
628
|
-
if (/config\/test/.test(f.path))
|
|
629
|
-
return false;
|
|
630
|
-
return /config\/(?:web|console|main|db|api|backend|frontend|common)(?:[-_][\w-]+)?\.php$/.test(f.path);
|
|
631
|
-
});
|
|
632
|
-
// Track (name, class, source, configFile) tuples so we don't duplicate
|
|
633
|
-
// when the same component appears in both web.php and main-local.php.
|
|
634
|
-
const seen = new Set();
|
|
635
|
-
const dedupKey = (name, cls, sourceLabel, file) => `${sourceLabel}::${name}::${cls ?? "<factory>"}::${file}`;
|
|
636
|
-
const pushService = (s) => {
|
|
637
|
-
const key = dedupKey(s.name, s.class, s.source, s.config_file ?? "");
|
|
638
|
-
if (seen.has(key))
|
|
639
|
-
return;
|
|
640
|
-
seen.add(key);
|
|
641
|
-
services.push(s);
|
|
642
|
-
};
|
|
643
|
-
for (const cf of configFiles) {
|
|
644
|
-
let source;
|
|
645
|
-
try {
|
|
646
|
-
source = await readFile(join(index.root, cf.path), "utf-8");
|
|
647
|
-
}
|
|
648
|
-
catch {
|
|
649
|
-
continue;
|
|
650
|
-
}
|
|
651
|
-
// Match component definitions: 'componentName' => ['class' => 'FQCN', ...]
|
|
652
|
-
// Top-level components live under 'components' => [...]; module-scoped
|
|
653
|
-
// ones live under 'modules' => ['<id>' => ['components' => [...]]]. We
|
|
654
|
-
// don't try to distinguish here — every match is tagged via post-pass.
|
|
655
|
-
//
|
|
656
|
-
// The key pattern accepts both bare names ("db") and FQCNs
|
|
657
|
-
// ("app\\interfaces\\LoggerInterface") because container.singletons /
|
|
658
|
-
// container.definitions almost always use FQCNs as keys.
|
|
659
|
-
const componentRe = /['"]([\w\\-]+)['"]\s*=>\s*\[\s*['"]class['"]\s*=>\s*['"]([\w\\]+)['"]/g;
|
|
660
|
-
let match;
|
|
661
|
-
while ((match = componentRe.exec(source)) !== null) {
|
|
662
|
-
const name = match[1];
|
|
663
|
-
const cls = match[2];
|
|
664
|
-
if (options?.service_name && name !== options.service_name)
|
|
665
|
-
continue;
|
|
666
|
-
// Resolve class to file via PSR-4
|
|
667
|
-
let filePath = null;
|
|
668
|
-
try {
|
|
669
|
-
const resolved = await resolvePhpNamespace(repo, cls);
|
|
670
|
-
if (resolved.exists)
|
|
671
|
-
filePath = resolved.file_path;
|
|
672
|
-
}
|
|
673
|
-
catch { /* ignore */ }
|
|
674
|
-
// Best-effort source labeling: scan the prefix up to the match to see
|
|
675
|
-
// whether we're inside `'modules' => ['x' => ['components' => [...]]]`
|
|
676
|
-
// or `'container' => ['singletons' => [...]]`. This is fuzzy; the
|
|
677
|
-
// labeling failures fall back to "components".
|
|
678
|
-
const prefix = source.slice(0, match.index);
|
|
679
|
-
const sourceLabel = inferConfigSection(prefix);
|
|
680
|
-
pushService({
|
|
681
|
-
name,
|
|
682
|
-
class: cls,
|
|
683
|
-
file: filePath,
|
|
684
|
-
config_file: cf.path,
|
|
685
|
-
source: sourceLabel,
|
|
686
|
-
});
|
|
687
|
-
}
|
|
688
|
-
// DI container: `Yii::$container->set(InterfaceName::class, ImplName::class)`
|
|
689
|
-
// and the static `'container' => ['definitions' => [...]]` form. Both are
|
|
690
|
-
// common in Yii2 codebases that use interface-based DI.
|
|
691
|
-
const containerSetRe = /Yii::\$container->set\s*\(\s*([\w\\]+)::class\s*,\s*([\w\\]+)::class/g;
|
|
692
|
-
while ((match = containerSetRe.exec(source)) !== null) {
|
|
693
|
-
const iface = match[1];
|
|
694
|
-
const impl = match[2];
|
|
695
|
-
if (options?.service_name && iface !== options.service_name)
|
|
696
|
-
continue;
|
|
697
|
-
let filePath = null;
|
|
698
|
-
try {
|
|
699
|
-
const resolved = await resolvePhpNamespace(repo, impl);
|
|
700
|
-
if (resolved.exists)
|
|
701
|
-
filePath = resolved.file_path;
|
|
702
|
-
}
|
|
703
|
-
catch { /* ignore */ }
|
|
704
|
-
pushService({
|
|
705
|
-
name: iface,
|
|
706
|
-
class: impl,
|
|
707
|
-
file: filePath,
|
|
708
|
-
config_file: cf.path,
|
|
709
|
-
source: "container.set",
|
|
710
|
-
});
|
|
711
|
-
}
|
|
712
|
-
// Closure / factory: `'mailer' => function() { return new Mailer(); }`
|
|
713
|
-
// We can't statically resolve the produced class, so we surface the
|
|
714
|
-
// service name with class=null and is_factory=true so callers can
|
|
715
|
-
// either ignore them or flag them as needs-manual-review.
|
|
716
|
-
const factoryRe = /['"]([\w-]+)['"]\s*=>\s*function\s*\(/g;
|
|
717
|
-
while ((match = factoryRe.exec(source)) !== null) {
|
|
718
|
-
const name = match[1];
|
|
719
|
-
if (options?.service_name && name !== options.service_name)
|
|
720
|
-
continue;
|
|
721
|
-
pushService({
|
|
722
|
-
name,
|
|
723
|
-
class: null,
|
|
724
|
-
file: null,
|
|
725
|
-
config_file: cf.path,
|
|
726
|
-
source: "factory",
|
|
727
|
-
is_factory: true,
|
|
728
|
-
});
|
|
729
|
-
}
|
|
730
|
-
}
|
|
731
|
-
return { services, total: services.length };
|
|
732
|
-
}
|
|
733
|
-
/**
|
|
734
|
-
* Sprint 3 helper: given the source prefix up to a component match, identify
|
|
735
|
-
* which Yii2 config section we're inside by walking the prefix forward with a
|
|
736
|
-
* bracket-balanced stack. Each `'KEY' => [` pushes KEY onto the stack; each
|
|
737
|
-
* matching `]` pops it. At the end of the prefix the stack tells us the
|
|
738
|
-
* exact nesting path, regardless of how many sibling sections came before.
|
|
739
|
-
*
|
|
740
|
-
* Why not regex: regex can't track balanced brackets. The previous version
|
|
741
|
-
* used non-greedy `[\\s\\S]*?` which incorrectly matched a `'modules' =>
|
|
742
|
-
* ['x' => [...]]` block that had already closed by the time we reached a
|
|
743
|
-
* `'container' => ['singletons' => ...]` later in the file.
|
|
744
|
-
*
|
|
745
|
-
* Returns one of:
|
|
746
|
-
* "module:<id>" — inside `'modules' => ['<id>' => ['components' => [<HERE>...
|
|
747
|
-
* "container.singletons" — inside `'container' => ['singletons' => [<HERE>...
|
|
748
|
-
* "container.definitions" — inside `'container' => ['definitions' => [<HERE>...
|
|
749
|
-
* "components" — fallback (top-level components or unknown)
|
|
750
|
-
*
|
|
751
|
-
* String literals (single + double quoted) and PHP comments are skipped so
|
|
752
|
-
* brackets inside them don't confuse the depth counter.
|
|
753
|
-
*/
|
|
754
|
-
function inferConfigSection(prefix) {
|
|
755
|
-
const stack = [];
|
|
756
|
-
let depth = 0;
|
|
757
|
-
let i = 0;
|
|
758
|
-
while (i < prefix.length) {
|
|
759
|
-
const c = prefix[i];
|
|
760
|
-
// Skip comments
|
|
761
|
-
if (c === "/" && prefix[i + 1] === "/") {
|
|
762
|
-
const nl = prefix.indexOf("\n", i);
|
|
763
|
-
i = nl === -1 ? prefix.length : nl + 1;
|
|
764
|
-
continue;
|
|
765
|
-
}
|
|
766
|
-
if (c === "/" && prefix[i + 1] === "*") {
|
|
767
|
-
const end = prefix.indexOf("*/", i + 2);
|
|
768
|
-
i = end === -1 ? prefix.length : end + 2;
|
|
769
|
-
continue;
|
|
770
|
-
}
|
|
771
|
-
if (c === "#") {
|
|
772
|
-
const nl = prefix.indexOf("\n", i);
|
|
773
|
-
i = nl === -1 ? prefix.length : nl + 1;
|
|
774
|
-
continue;
|
|
775
|
-
}
|
|
776
|
-
// Look for `'KEY' => [` BEFORE the generic string-skip — otherwise the
|
|
777
|
-
// string-skip swallows the opening quote and we never push the key.
|
|
778
|
-
if (c === '"' || c === "'") {
|
|
779
|
-
const m = /^(['"])([\w\\-]+)\1\s*=>\s*\[/.exec(prefix.slice(i));
|
|
780
|
-
if (m) {
|
|
781
|
-
const keyName = m[2];
|
|
782
|
-
// Push at the new depth (after the bracket we're about to enter).
|
|
783
|
-
stack.push({ key: keyName, depth: depth + 1 });
|
|
784
|
-
depth++;
|
|
785
|
-
i += m[0].length;
|
|
786
|
-
continue;
|
|
787
|
-
}
|
|
788
|
-
// Plain string literal — skip past the closing quote.
|
|
789
|
-
const quote = c;
|
|
790
|
-
i++;
|
|
791
|
-
while (i < prefix.length) {
|
|
792
|
-
if (prefix[i] === "\\") {
|
|
793
|
-
i += 2;
|
|
794
|
-
continue;
|
|
795
|
-
}
|
|
796
|
-
if (prefix[i] === quote) {
|
|
797
|
-
i++;
|
|
798
|
-
break;
|
|
799
|
-
}
|
|
800
|
-
i++;
|
|
801
|
-
}
|
|
802
|
-
continue;
|
|
803
|
-
}
|
|
804
|
-
if (c === "[") {
|
|
805
|
-
depth++;
|
|
806
|
-
i++;
|
|
807
|
-
continue;
|
|
808
|
-
}
|
|
809
|
-
if (c === "]") {
|
|
810
|
-
depth--;
|
|
811
|
-
while (stack.length > 0 && stack[stack.length - 1].depth > depth) {
|
|
812
|
-
stack.pop();
|
|
813
|
-
}
|
|
814
|
-
i++;
|
|
815
|
-
continue;
|
|
816
|
-
}
|
|
817
|
-
i++;
|
|
818
|
-
}
|
|
819
|
-
// Read the live nesting path from the stack.
|
|
820
|
-
const keys = stack.map((f) => f.key);
|
|
821
|
-
// module:<id> when we're inside modules.<id>.components.<*>
|
|
822
|
-
const modIdx = keys.indexOf("modules");
|
|
823
|
-
if (modIdx !== -1 && keys.length >= modIdx + 3) {
|
|
824
|
-
const moduleId = keys[modIdx + 1];
|
|
825
|
-
const inner = keys[modIdx + 2];
|
|
826
|
-
if (inner === "components")
|
|
827
|
-
return `module:${moduleId}`;
|
|
828
|
-
}
|
|
829
|
-
const cIdx = keys.indexOf("container");
|
|
830
|
-
if (cIdx !== -1 && keys.length >= cIdx + 2) {
|
|
831
|
-
const sub = keys[cIdx + 1];
|
|
832
|
-
if (sub === "singletons")
|
|
833
|
-
return "container.singletons";
|
|
834
|
-
if (sub === "definitions")
|
|
835
|
-
return "container.definitions";
|
|
836
|
-
}
|
|
837
|
-
return "components";
|
|
838
|
-
}
|
|
839
|
-
const PHP_SECURITY_CHECKS = [
|
|
840
|
-
// Original 8 checks
|
|
841
|
-
{ pattern: "sql-injection-php", severity: "critical" },
|
|
842
|
-
{ pattern: "xss-php", severity: "critical" },
|
|
843
|
-
{ pattern: "eval-php", severity: "critical" },
|
|
844
|
-
{ pattern: "exec-php", severity: "critical" },
|
|
845
|
-
{ pattern: "unserialize-php", severity: "high" },
|
|
846
|
-
{ pattern: "file-include-var", severity: "high" },
|
|
847
|
-
{ pattern: "unescaped-yii-view", severity: "high" },
|
|
848
|
-
{ pattern: "raw-query-yii", severity: "high" },
|
|
849
|
-
// Sprint 2 additions: Yii2- + PHP-specific patterns informed by tgm-panel
|
|
850
|
-
// db-audit + perf-audit findings, plus the gap analysis section 4 catalog.
|
|
851
|
-
{ pattern: "yii-csrf-disabled", severity: "high" },
|
|
852
|
-
{ pattern: "yii-debug-mode-prod", severity: "critical" },
|
|
853
|
-
{ pattern: "yii-cookie-no-validation", severity: "high" },
|
|
854
|
-
{ pattern: "yii-mass-assignment-unsafe", severity: "medium" },
|
|
855
|
-
{ pattern: "yii-raw-sql-where", severity: "high" },
|
|
856
|
-
{ pattern: "php-md5-password", severity: "high" },
|
|
857
|
-
{ pattern: "php-rand-token", severity: "high" },
|
|
858
|
-
{ pattern: "php-loose-comparison-secret", severity: "medium" },
|
|
859
|
-
{ pattern: "yii-rbac-cached-permission", severity: "low" },
|
|
860
|
-
{ pattern: "yii-no-row-level-locking", severity: "high" },
|
|
861
|
-
{ pattern: "yii-config-hardcoded-secret", severity: "critical" },
|
|
862
|
-
{ pattern: "yii-unbounded-all", severity: "medium" },
|
|
863
|
-
];
|
|
864
|
-
/**
|
|
865
|
-
* Patterns that hit code at module level (top-level `return [...]`,
|
|
866
|
-
* top-level `define(...)` calls in entry-point files) and therefore are
|
|
867
|
-
* NOT visible via `searchPatterns` — that helper iterates `index.symbols`,
|
|
868
|
-
* so files without any class/function/method produce zero hits. We scan
|
|
869
|
-
* these patterns by reading file content directly.
|
|
870
|
-
*/
|
|
871
|
-
const FILE_LEVEL_PATTERNS = new Set([
|
|
872
|
-
"yii-debug-mode-prod",
|
|
873
|
-
"yii-cookie-no-validation",
|
|
874
|
-
"yii-config-hardcoded-secret",
|
|
875
|
-
]);
|
|
876
|
-
export async function phpSecurityScan(repo, options) {
|
|
877
|
-
const selectedChecks = options?.checks
|
|
878
|
-
? PHP_SECURITY_CHECKS.filter((c) => options.checks.includes(c.pattern))
|
|
879
|
-
: PHP_SECURITY_CHECKS;
|
|
880
|
-
const findings = [];
|
|
881
|
-
const summary = { critical: 0, high: 0, medium: 0, low: 0, total: 0 };
|
|
882
|
-
// Symbol-level scans run via the existing searchPatterns helper. Skip the
|
|
883
|
-
// file-level patterns here — they're handled below by a direct file read.
|
|
884
|
-
const symbolLevelChecks = selectedChecks.filter((c) => !FILE_LEVEL_PATTERNS.has(c.pattern));
|
|
885
|
-
const fileLevelChecks = selectedChecks.filter((c) => FILE_LEVEL_PATTERNS.has(c.pattern));
|
|
886
|
-
// Run pattern checks in parallel
|
|
887
|
-
const results = await Promise.all(symbolLevelChecks.map((check) => searchPatterns(repo, check.pattern, {
|
|
888
|
-
file_pattern: options?.file_pattern ?? ".php",
|
|
889
|
-
include_tests: false,
|
|
890
|
-
}).then((r) => ({ check, result: r })).catch(() => null)));
|
|
891
|
-
for (const res of results) {
|
|
892
|
-
if (!res)
|
|
893
|
-
continue;
|
|
894
|
-
for (const m of res.result.matches) {
|
|
895
|
-
findings.push({
|
|
896
|
-
severity: res.check.severity,
|
|
897
|
-
pattern: res.check.pattern,
|
|
898
|
-
file: m.file,
|
|
899
|
-
line: m.start_line,
|
|
900
|
-
context: m.context,
|
|
901
|
-
description: "", // description populated by searchPatterns but not in PatternMatch type
|
|
902
|
-
});
|
|
903
|
-
summary[res.check.severity]++;
|
|
904
|
-
summary.total++;
|
|
905
|
-
}
|
|
906
|
-
}
|
|
907
|
-
// File-level scan: read every PHP file once, run each file-level pattern
|
|
908
|
-
// against it. This catches top-level `define('YII_DEBUG', true)` and
|
|
909
|
-
// hardcoded literals in `return [...]` config arrays which never live
|
|
910
|
-
// inside a class or function.
|
|
911
|
-
if (fileLevelChecks.length > 0) {
|
|
912
|
-
const fileFindings = await runFileLevelChecks(repo, fileLevelChecks, options?.file_pattern);
|
|
913
|
-
for (const f of fileFindings) {
|
|
914
|
-
findings.push(f);
|
|
915
|
-
summary[f.severity]++;
|
|
916
|
-
summary.total++;
|
|
917
|
-
}
|
|
918
|
-
}
|
|
919
|
-
return {
|
|
920
|
-
findings,
|
|
921
|
-
summary,
|
|
922
|
-
checks_run: selectedChecks.map((c) => c.pattern),
|
|
923
|
-
};
|
|
924
|
-
}
|
|
925
|
-
async function runFileLevelChecks(repo, checks, filePattern) {
|
|
926
|
-
const index = await getCodeIndex(repo);
|
|
927
|
-
if (!index)
|
|
928
|
-
return [];
|
|
929
|
-
const { BUILTIN_PATTERNS } = await import("./pattern-tools.js");
|
|
930
|
-
const out = [];
|
|
931
|
-
const phpFiles = index.files.filter((f) => {
|
|
932
|
-
if (!f.path.endsWith(".php"))
|
|
933
|
-
return false;
|
|
934
|
-
if (filePattern && !f.path.includes(filePattern))
|
|
935
|
-
return false;
|
|
936
|
-
return true;
|
|
937
|
-
});
|
|
938
|
-
// Pull each pattern definition up-front. We want one regex object per
|
|
939
|
-
// check, not per file, to avoid re-compilation churn.
|
|
940
|
-
const compiled = checks
|
|
941
|
-
.map((check) => {
|
|
942
|
-
const def = BUILTIN_PATTERNS[check.pattern];
|
|
943
|
-
if (!def)
|
|
944
|
-
return null;
|
|
945
|
-
// Re-create the regex with /g so we can iterate matches across the
|
|
946
|
-
// whole file content. Built-in patterns are stored without /g because
|
|
947
|
-
// searchPatterns calls .exec() once per symbol.
|
|
948
|
-
const flags = (def.regex.flags.includes("g") ? "" : "g") + def.regex.flags;
|
|
949
|
-
return {
|
|
950
|
-
check,
|
|
951
|
-
regex: new RegExp(def.regex.source, flags),
|
|
952
|
-
fileIncludePattern: def.fileIncludePattern,
|
|
953
|
-
fileExcludePattern: def.fileExcludePattern,
|
|
954
|
-
};
|
|
955
|
-
})
|
|
956
|
-
.filter((c) => c !== null);
|
|
957
|
-
await Promise.all(phpFiles.map(async (file) => {
|
|
958
|
-
let content;
|
|
959
|
-
try {
|
|
960
|
-
content = await readFile(join(index.root, file.path), "utf-8");
|
|
961
|
-
}
|
|
962
|
-
catch {
|
|
963
|
-
return;
|
|
964
|
-
}
|
|
965
|
-
for (const c of compiled) {
|
|
966
|
-
if (c.fileIncludePattern && !c.fileIncludePattern.test(file.path))
|
|
967
|
-
continue;
|
|
968
|
-
if (c.fileExcludePattern && c.fileExcludePattern.test(file.path))
|
|
969
|
-
continue;
|
|
970
|
-
c.regex.lastIndex = 0;
|
|
971
|
-
let m;
|
|
972
|
-
while ((m = c.regex.exec(content)) !== null) {
|
|
973
|
-
const line = countLines(content, m.index);
|
|
974
|
-
out.push({
|
|
975
|
-
severity: c.check.severity,
|
|
976
|
-
pattern: c.check.pattern,
|
|
977
|
-
file: file.path,
|
|
978
|
-
line,
|
|
979
|
-
context: extractLine(content, m.index),
|
|
980
|
-
description: "",
|
|
981
|
-
});
|
|
982
|
-
}
|
|
983
|
-
}
|
|
984
|
-
}));
|
|
985
|
-
return out;
|
|
986
|
-
}
|
|
987
|
-
function countLines(source, idx) {
|
|
988
|
-
let line = 1;
|
|
989
|
-
for (let i = 0; i < idx; i++) {
|
|
990
|
-
if (source.charCodeAt(i) === 10)
|
|
991
|
-
line++;
|
|
992
|
-
}
|
|
993
|
-
return line;
|
|
994
|
-
}
|
|
995
|
-
function extractLine(source, idx) {
|
|
996
|
-
const start = source.lastIndexOf("\n", idx) + 1;
|
|
997
|
-
const end = source.indexOf("\n", idx);
|
|
998
|
-
const out = source.slice(start, end === -1 ? source.length : end);
|
|
999
|
-
return out.trim().slice(0, 200);
|
|
1000
|
-
}
|
|
1001
|
-
// ---------------------------------------------------------------------------
|
|
1002
|
-
// 7h. find_php_n_plus_one — detect foreach + relation access without ->with()
|
|
1003
|
-
// ---------------------------------------------------------------------------
|
|
1004
|
-
/**
|
|
1005
|
-
* Common ActiveRecord scalar field names. Property access like $user->id or
|
|
1006
|
-
* $user->created_at inside a foreach is NOT a relation (no N+1 risk), so we
|
|
1007
|
-
* allow-list these to cut false positives.
|
|
1008
|
-
*/
|
|
1009
|
-
const SCALAR_FIELD_NAMES = new Set([
|
|
1010
|
-
"id", "name", "title", "created_at", "updated_at", "deleted_at", "status",
|
|
1011
|
-
"email", "slug", "code", "type", "value", "label", "description", "enabled",
|
|
1012
|
-
"active", "position", "sort", "order", "count", "total", "amount", "price",
|
|
1013
|
-
"uuid", "hash", "token", "key", "url", "path", "image", "avatar",
|
|
1014
|
-
]);
|
|
1015
|
-
/**
|
|
1016
|
-
* PHP method names that look like `get*` but are NOT ActiveRecord relation
|
|
1017
|
-
* getters. `$item->save()` / `$item->validate()` inside a foreach is fine;
|
|
1018
|
-
* flagging them as N+1 would be a false positive. These names are stripped
|
|
1019
|
-
* from the `get\w+()` method-call detection before the eager-load check.
|
|
1020
|
-
*/
|
|
1021
|
-
const METHOD_CALL_BLOCKLIST = new Set([
|
|
1022
|
-
"save", "validate", "delete", "refresh", "load", "populate", "toArray",
|
|
1023
|
-
"afterSave", "beforeSave", "beforeDelete", "afterDelete",
|
|
1024
|
-
"getAttributes", "getAttribute", "getIsNewRecord", "getErrors", "getFirstError",
|
|
1025
|
-
"getOldAttributes", "getDirtyAttributes", "getPrimaryKey", "getTableSchema",
|
|
1026
|
-
]);
|
|
1027
|
-
/**
|
|
1028
|
-
* Detect N+1 query patterns in Yii2/Eloquent controllers.
|
|
1029
|
-
*
|
|
1030
|
-
* Pattern: `foreach ($items as $item) { $item->relation->... }` without a
|
|
1031
|
-
* prior `->with('relation')` call in the same method scope. This is the
|
|
1032
|
-
* most common N+1 anti-pattern in Yii2 ActiveRecord code.
|
|
1033
|
-
*
|
|
1034
|
-
* Known limitations (acceptable for a "discovery" tool, not a gate):
|
|
1035
|
-
* - Regex-based — can miss multi-line foreach bodies split across nested blocks
|
|
1036
|
-
* - Doesn't cross function boundaries — eager loading in caller is invisible
|
|
1037
|
-
* - False positives on nested loops if the outer collection is already eager-loaded
|
|
1038
|
-
*/
|
|
1039
|
-
export async function findPhpNPlusOne(repo, options) {
|
|
1040
|
-
const index = await getCodeIndex(repo);
|
|
1041
|
-
if (!index)
|
|
1042
|
-
throw new Error(`Repository "${repo}" not found.`);
|
|
1043
|
-
const findings = [];
|
|
1044
|
-
const limit = options?.limit ?? 100;
|
|
1045
|
-
const filePattern = options?.file_pattern;
|
|
1046
|
-
// Normalize `getProfile` → `profile` so the ->with() check matches whether
|
|
1047
|
-
// the relation is accessed as a property or via its auto-generated getter.
|
|
1048
|
-
const normalizeGetter = (name) => {
|
|
1049
|
-
const bare = name.replace(/^get/, "");
|
|
1050
|
-
return bare.length > 0 ? bare.charAt(0).toLowerCase() + bare.slice(1) : "";
|
|
1051
|
-
};
|
|
1052
|
-
// A finding is emitted exactly once per (foreach × relation-name) tuple so
|
|
1053
|
-
// that chained patterns don't double-report the same relation that the
|
|
1054
|
-
// property pattern already caught in the same loop body.
|
|
1055
|
-
const emitFinding = (sym, foreachIdx, relation, pattern, seen) => {
|
|
1056
|
-
if (!relation || seen.has(relation))
|
|
1057
|
-
return findings.length >= limit;
|
|
1058
|
-
seen.add(relation);
|
|
1059
|
-
if (SCALAR_FIELD_NAMES.has(relation.toLowerCase()))
|
|
1060
|
-
return findings.length >= limit;
|
|
1061
|
-
const beforeForeach = sym.source.slice(0, foreachIdx);
|
|
1062
|
-
const withRe = new RegExp(`\\bwith\\s*\\(\\s*['"]${relation}['"]`);
|
|
1063
|
-
if (withRe.test(beforeForeach))
|
|
1064
|
-
return findings.length >= limit;
|
|
1065
|
-
const lineOffset = beforeForeach.split("\n").length - 1;
|
|
1066
|
-
findings.push({
|
|
1067
|
-
file: sym.file,
|
|
1068
|
-
method: sym.name,
|
|
1069
|
-
line: sym.start_line + lineOffset,
|
|
1070
|
-
relation,
|
|
1071
|
-
pattern,
|
|
1072
|
-
});
|
|
1073
|
-
return findings.length >= limit;
|
|
1074
|
-
};
|
|
1075
|
-
// Helper: scan a single chunk of source (a method body OR a view file) for
|
|
1076
|
-
// all 4 N+1 patterns. Returns true once `limit` is hit so the caller can
|
|
1077
|
-
// short-circuit.
|
|
1078
|
-
function scanChunk(file, methodName, src, startLine) {
|
|
1079
|
-
const foreachRe = /foreach\s*\(\s*\$(\w+)\s+as\s+(?:\$\w+\s*=>\s*)?\$(\w+)\s*\)/g;
|
|
1080
|
-
let fm;
|
|
1081
|
-
while ((fm = foreachRe.exec(src)) !== null) {
|
|
1082
|
-
const itemVar = fm[2];
|
|
1083
|
-
const foreachIdx = fm.index;
|
|
1084
|
-
const after = src.slice(foreachIdx);
|
|
1085
|
-
const seen = new Set();
|
|
1086
|
-
// Pattern 1 — property access: $item->profile
|
|
1087
|
-
const propRe = new RegExp(`\\$${itemVar}->(\\w+)(?![\\w(])`, "g");
|
|
1088
|
-
let m;
|
|
1089
|
-
while ((m = propRe.exec(after)) !== null) {
|
|
1090
|
-
if (emitFinding({ file, name: methodName, source: src, start_line: startLine }, foreachIdx, m[1], "foreach-access-without-with", seen)) {
|
|
1091
|
-
return true;
|
|
1092
|
-
}
|
|
1093
|
-
}
|
|
1094
|
-
// Pattern 2 — getter method call: $item->getProfile()
|
|
1095
|
-
const getterRe = new RegExp(`\\$${itemVar}->(get\\w+)\\s*\\(\\s*\\)`, "g");
|
|
1096
|
-
while ((m = getterRe.exec(after)) !== null) {
|
|
1097
|
-
const rawMethod = m[1];
|
|
1098
|
-
if (METHOD_CALL_BLOCKLIST.has(rawMethod))
|
|
1099
|
-
continue;
|
|
1100
|
-
const normalized = normalizeGetter(rawMethod);
|
|
1101
|
-
if (!normalized || METHOD_CALL_BLOCKLIST.has(normalized.toLowerCase()))
|
|
1102
|
-
continue;
|
|
1103
|
-
if (emitFinding({ file, name: methodName, source: src, start_line: startLine }, foreachIdx, normalized, "foreach-getter-without-with", seen)) {
|
|
1104
|
-
return true;
|
|
1105
|
-
}
|
|
1106
|
-
}
|
|
1107
|
-
// Pattern 3 — chained access: $item->rel->sub
|
|
1108
|
-
const chainRe = new RegExp(`\\$${itemVar}->(\\w+)->\\w`, "g");
|
|
1109
|
-
while ((m = chainRe.exec(after)) !== null) {
|
|
1110
|
-
if (emitFinding({ file, name: methodName, source: src, start_line: startLine }, foreachIdx, m[1], "foreach-chained-without-with", seen)) {
|
|
1111
|
-
return true;
|
|
1112
|
-
}
|
|
1113
|
-
}
|
|
1114
|
-
// Pattern 4 (Sprint 3) — explicit lookup in loop body. Inside the foreach,
|
|
1115
|
-
// a `Model::findOne(...)` / `Model::findAll(...)` / `->find()` is the
|
|
1116
|
-
// lazy-load smell — each iteration hits the database.
|
|
1117
|
-
//
|
|
1118
|
-
// We scan a bounded 2000-char window after the foreach header to keep
|
|
1119
|
-
// the regex cost predictable on large methods. A nested foreach inside
|
|
1120
|
-
// the window will still match on its own /g iteration, and the outer
|
|
1121
|
-
// `seen` set deduplicates so we never double-report a single class+method.
|
|
1122
|
-
const body = after.slice(0, Math.min(after.length, 2000));
|
|
1123
|
-
const findOneRe = /(\w+)::(findOne|findAll|find|findBySql)\s*\(/g;
|
|
1124
|
-
let lm;
|
|
1125
|
-
while ((lm = findOneRe.exec(body)) !== null) {
|
|
1126
|
-
const targetClass = lm[1];
|
|
1127
|
-
const method = lm[2];
|
|
1128
|
-
// Filter common false positives: top-level utility classes that
|
|
1129
|
-
// happen to expose static `find*` methods but aren't AR.
|
|
1130
|
-
if (targetClass === "Yii" ||
|
|
1131
|
-
targetClass === "ArrayHelper" ||
|
|
1132
|
-
targetClass === "self" ||
|
|
1133
|
-
targetClass === "static") {
|
|
1134
|
-
continue;
|
|
1135
|
-
}
|
|
1136
|
-
const synthetic = `${targetClass}::${method}`;
|
|
1137
|
-
if (emitFinding({ file, name: methodName, source: src, start_line: startLine }, foreachIdx, synthetic, "foreach-findone-in-loop", seen)) {
|
|
1138
|
-
return true;
|
|
1139
|
-
}
|
|
1140
|
-
}
|
|
1141
|
-
}
|
|
1142
|
-
return false;
|
|
1143
|
-
}
|
|
1144
|
-
// Method-level scan (Patterns 1-4 inside class methods, the original surface).
|
|
1145
|
-
for (const sym of index.symbols) {
|
|
1146
|
-
if (sym.kind !== "method" || !sym.file.endsWith(".php") || !sym.source)
|
|
1147
|
-
continue;
|
|
1148
|
-
if (filePattern && !sym.file.includes(filePattern))
|
|
1149
|
-
continue;
|
|
1150
|
-
if (scanChunk(sym.file, sym.name, sym.source, sym.start_line)) {
|
|
1151
|
-
return { findings, total: findings.length };
|
|
1152
|
-
}
|
|
1153
|
-
}
|
|
1154
|
-
// View-level scan (Sprint 3 Pattern 5) — Yii2 views/**/*.php files render
|
|
1155
|
-
// lists of models at module level. They're not class methods so they have
|
|
1156
|
-
// no symbol; scan the raw file content. `views/**/*.php` is the canonical
|
|
1157
|
-
// path; `_*.php` partials live at the same level.
|
|
1158
|
-
const viewFiles = index.files.filter((f) => {
|
|
1159
|
-
if (!f.path.endsWith(".php"))
|
|
1160
|
-
return false;
|
|
1161
|
-
if (filePattern && !f.path.includes(filePattern))
|
|
1162
|
-
return false;
|
|
1163
|
-
// Standard Yii2 view paths (basic + advanced + module-scoped layouts).
|
|
1164
|
-
return /(?:^|\/)(?:views|widgets|layouts)\//.test(f.path);
|
|
1165
|
-
});
|
|
1166
|
-
await Promise.all(viewFiles.map(async (file) => {
|
|
1167
|
-
if (findings.length >= limit)
|
|
1168
|
-
return;
|
|
1169
|
-
let content;
|
|
1170
|
-
try {
|
|
1171
|
-
content = await readFile(join(index.root, file.path), "utf-8");
|
|
1172
|
-
}
|
|
1173
|
-
catch {
|
|
1174
|
-
return;
|
|
1175
|
-
}
|
|
1176
|
-
// For views the "method name" is just the file basename — that's what
|
|
1177
|
-
// the caller sees in the finding when there is no enclosing function.
|
|
1178
|
-
const methodName = file.path.split("/").pop() ?? file.path;
|
|
1179
|
-
scanChunk(file.path, methodName, content, 1);
|
|
1180
|
-
}));
|
|
1181
|
-
return { findings, total: findings.length };
|
|
1182
|
-
}
|
|
1183
|
-
/**
|
|
1184
|
-
* Flag oversized PHP classes. Two scopes:
|
|
1185
|
-
*
|
|
1186
|
-
* - `scope: "activerecord"` (default) — only models extending ActiveRecord.
|
|
1187
|
-
* Uses `analyzeActiveRecord` for model detection and counts relations as a
|
|
1188
|
-
* third threshold alongside methods and lines. Classic Yii2 god-model case:
|
|
1189
|
-
* Survey.php in Mobi2 with 175 methods, 30 relations, 2291 lines.
|
|
1190
|
-
*
|
|
1191
|
-
* - `scope: "all"` — every PHP class in the index, regardless of base class.
|
|
1192
|
-
* Captures service god-classes (UserService with 80 methods), component
|
|
1193
|
-
* aggregates, and any other PHP class that outgrew its responsibility.
|
|
1194
|
-
* `relation_count` is 0 for non-AR classes — the `min_relations` check is
|
|
1195
|
-
* skipped so a service with 60 methods isn't hidden by a relation threshold.
|
|
1196
|
-
*
|
|
1197
|
-
* Thresholds default to 50/15/500 but are configurable for both scopes.
|
|
1198
|
-
*/
|
|
1199
|
-
export async function findPhpGodModel(repo, options) {
|
|
1200
|
-
const index = await getCodeIndex(repo);
|
|
1201
|
-
if (!index)
|
|
1202
|
-
throw new Error(`Repository "${repo}" not found.`);
|
|
1203
|
-
const minM = options?.min_methods ?? 50;
|
|
1204
|
-
const minR = options?.min_relations ?? 15;
|
|
1205
|
-
const minL = options?.min_lines ?? 500;
|
|
1206
|
-
const scope = options?.scope ?? "activerecord";
|
|
1207
|
-
const models = [];
|
|
1208
|
-
if (scope === "activerecord") {
|
|
1209
|
-
const ar = await analyzeActiveRecord(repo);
|
|
1210
|
-
for (const m of ar.models) {
|
|
1211
|
-
// Look up the class symbol by (name, kind, file) — file match keeps
|
|
1212
|
-
// duplicate class names in different paths reported independently.
|
|
1213
|
-
const classSym = index.symbols.find((s) => s.name === m.name && s.kind === "class" && s.file === m.file);
|
|
1214
|
-
const lineCount = classSym ? classSym.end_line - classSym.start_line : 0;
|
|
1215
|
-
const reasons = [];
|
|
1216
|
-
if (m.methods.length > minM)
|
|
1217
|
-
reasons.push(`methods: ${m.methods.length} > ${minM}`);
|
|
1218
|
-
if (m.relations.length > minR)
|
|
1219
|
-
reasons.push(`relations: ${m.relations.length} > ${minR}`);
|
|
1220
|
-
if (lineCount > minL)
|
|
1221
|
-
reasons.push(`lines: ${lineCount} > ${minL}`);
|
|
1222
|
-
if (reasons.length > 0) {
|
|
1223
|
-
models.push({
|
|
1224
|
-
name: m.name,
|
|
1225
|
-
file: m.file,
|
|
1226
|
-
method_count: m.methods.length,
|
|
1227
|
-
relation_count: m.relations.length,
|
|
1228
|
-
line_count: lineCount,
|
|
1229
|
-
reasons,
|
|
1230
|
-
});
|
|
1231
|
-
}
|
|
1232
|
-
}
|
|
1233
|
-
}
|
|
1234
|
-
else {
|
|
1235
|
-
// scope === "all" — iterate every PHP class symbol directly.
|
|
1236
|
-
const classSyms = index.symbols.filter((s) => s.kind === "class" && s.file.endsWith(".php"));
|
|
1237
|
-
for (const cls of classSyms) {
|
|
1238
|
-
const methodCount = index.symbols.filter((s) => s.parent === cls.id && s.kind === "method").length;
|
|
1239
|
-
const lineCount = cls.end_line - cls.start_line;
|
|
1240
|
-
const reasons = [];
|
|
1241
|
-
if (methodCount > minM)
|
|
1242
|
-
reasons.push(`methods: ${methodCount} > ${minM}`);
|
|
1243
|
-
if (lineCount > minL)
|
|
1244
|
-
reasons.push(`lines: ${lineCount} > ${minL}`);
|
|
1245
|
-
// min_relations intentionally skipped in "all" scope — not AR, no relations
|
|
1246
|
-
if (reasons.length > 0) {
|
|
1247
|
-
models.push({
|
|
1248
|
-
name: cls.name,
|
|
1249
|
-
file: cls.file,
|
|
1250
|
-
method_count: methodCount,
|
|
1251
|
-
relation_count: 0,
|
|
1252
|
-
line_count: lineCount,
|
|
1253
|
-
reasons,
|
|
1254
|
-
});
|
|
1255
|
-
}
|
|
1256
|
-
}
|
|
1257
|
-
}
|
|
1258
|
-
// Sort by severity (number of reasons desc, then methods desc)
|
|
1259
|
-
models.sort((a, b) => b.reasons.length - a.reasons.length || b.method_count - a.method_count);
|
|
1260
|
-
return { models, total: models.length };
|
|
1261
|
-
}
|
|
1262
|
-
const AUDIT_TIMEOUT = 8000;
|
|
1263
|
-
export async function phpProjectAudit(repo, options) {
|
|
1264
|
-
const startTime = Date.now();
|
|
1265
|
-
const gates = [];
|
|
1266
|
-
const allChecks = ["security", "activerecord", "complexity", "dead_code", "patterns", "clones", "hotspots", "n_plus_one", "god_model", "yii_performance"];
|
|
1267
|
-
const enabled = new Set(options?.checks ?? allChecks);
|
|
1268
|
-
const fp = options?.file_pattern ?? ".php";
|
|
1269
|
-
const secOpts = {};
|
|
1270
|
-
if (options?.file_pattern)
|
|
1271
|
-
secOpts.file_pattern = options.file_pattern;
|
|
1272
|
-
const tasks = [];
|
|
1273
|
-
if (enabled.has("security"))
|
|
1274
|
-
tasks.push({ name: "security", run: () => phpSecurityScan(repo, secOpts) });
|
|
1275
|
-
if (enabled.has("activerecord"))
|
|
1276
|
-
tasks.push({ name: "activerecord", run: () => analyzeActiveRecord(repo, options?.file_pattern ? { file_pattern: options.file_pattern } : undefined) });
|
|
1277
|
-
if (enabled.has("complexity"))
|
|
1278
|
-
tasks.push({ name: "complexity", run: async () => { const { analyzeComplexity } = await import("./complexity-tools.js"); return analyzeComplexity(repo, { file_pattern: fp, top_n: 10 }); } });
|
|
1279
|
-
if (enabled.has("dead_code"))
|
|
1280
|
-
tasks.push({ name: "dead_code", run: async () => { const { findDeadCode } = await import("./symbol-tools.js"); return findDeadCode(repo, { file_pattern: fp }); } });
|
|
1281
|
-
if (enabled.has("patterns"))
|
|
1282
|
-
tasks.push({ name: "patterns", run: () => searchPatterns(repo, "empty-catch", { file_pattern: fp }) });
|
|
1283
|
-
if (enabled.has("clones"))
|
|
1284
|
-
tasks.push({ name: "clones", run: async () => { const { findClones } = await import("./clone-tools.js"); return findClones(repo, { file_pattern: fp }); } });
|
|
1285
|
-
if (enabled.has("hotspots"))
|
|
1286
|
-
tasks.push({ name: "hotspots", run: async () => { const { analyzeHotspots } = await import("./hotspot-tools.js"); return analyzeHotspots(repo, {}); } });
|
|
1287
|
-
if (enabled.has("n_plus_one"))
|
|
1288
|
-
tasks.push({ name: "n_plus_one", run: () => findPhpNPlusOne(repo, options?.file_pattern ? { file_pattern: options.file_pattern } : undefined) });
|
|
1289
|
-
if (enabled.has("god_model"))
|
|
1290
|
-
tasks.push({ name: "god_model", run: () => findPhpGodModel(repo) });
|
|
1291
|
-
if (enabled.has("yii_performance")) {
|
|
1292
|
-
// Sprint 7: 5 perf patterns sourced from tgm-panel performance-audit
|
|
1293
|
-
// findings. Run them through the file-level scanner alongside
|
|
1294
|
-
// file-level security patterns so module-level matches (configs,
|
|
1295
|
-
// entry-points, view files) are picked up. Each pattern uses its own
|
|
1296
|
-
// severity tier consistent with the perf-audit recommendations.
|
|
1297
|
-
const PERF_PATTERNS = [
|
|
1298
|
-
{ pattern: "yii-translate-in-loop", severity: "medium" },
|
|
1299
|
-
{ pattern: "yii-dbtarget-info-level", severity: "medium" },
|
|
1300
|
-
{ pattern: "yii-find-with-large-then-filter", severity: "high" },
|
|
1301
|
-
{ pattern: "yii-cache-no-ttl", severity: "low" },
|
|
1302
|
-
{ pattern: "yii-no-batch-on-large", severity: "high" },
|
|
1303
|
-
];
|
|
1304
|
-
tasks.push({
|
|
1305
|
-
name: "yii_performance",
|
|
1306
|
-
run: async () => {
|
|
1307
|
-
// We reuse the security scan plumbing (parallel pattern runs +
|
|
1308
|
-
// file-level fallback) but with the perf catalog. The result shape
|
|
1309
|
-
// matches PhpSecurityScanResult — caller treats it as informational.
|
|
1310
|
-
const findings = [];
|
|
1311
|
-
const summary = { critical: 0, high: 0, medium: 0, low: 0, total: 0 };
|
|
1312
|
-
const symbolResults = await Promise.all(PERF_PATTERNS.map((check) => searchPatterns(repo, check.pattern, {
|
|
1313
|
-
file_pattern: fp,
|
|
1314
|
-
include_tests: false,
|
|
1315
|
-
}).then((r) => ({ check, result: r })).catch(() => null)));
|
|
1316
|
-
for (const res of symbolResults) {
|
|
1317
|
-
if (!res)
|
|
1318
|
-
continue;
|
|
1319
|
-
for (const m of res.result.matches) {
|
|
1320
|
-
findings.push({
|
|
1321
|
-
severity: res.check.severity,
|
|
1322
|
-
pattern: res.check.pattern,
|
|
1323
|
-
file: m.file,
|
|
1324
|
-
line: m.start_line,
|
|
1325
|
-
context: m.context,
|
|
1326
|
-
description: "",
|
|
1327
|
-
});
|
|
1328
|
-
summary[res.check.severity]++;
|
|
1329
|
-
summary.total++;
|
|
1330
|
-
}
|
|
1331
|
-
}
|
|
1332
|
-
return {
|
|
1333
|
-
findings,
|
|
1334
|
-
summary,
|
|
1335
|
-
checks_run: PERF_PATTERNS.map((p) => p.pattern),
|
|
1336
|
-
};
|
|
1337
|
-
},
|
|
1338
|
-
});
|
|
1339
|
-
}
|
|
1340
|
-
const settled = await Promise.allSettled(tasks.map(async (t) => {
|
|
1341
|
-
const s = Date.now();
|
|
1342
|
-
const r = await Promise.race([t.run(), new Promise((ok) => setTimeout(() => ok("TIMEOUT"), AUDIT_TIMEOUT))]);
|
|
1343
|
-
return { name: t.name, result: r, ms: Date.now() - s };
|
|
1344
|
-
}));
|
|
1345
|
-
let securityResult = { findings: [], summary: { critical: 0, high: 0, medium: 0, low: 0, total: 0 }, checks_run: [] };
|
|
1346
|
-
let arResult = { models: [], total: 0 };
|
|
1347
|
-
let totalFindings = 0;
|
|
1348
|
-
for (const s of settled) {
|
|
1349
|
-
if (s.status === "rejected") {
|
|
1350
|
-
gates.push({ name: "unknown", status: "error", findings_count: 0, duration_ms: 0, error: String(s.reason) });
|
|
1351
|
-
continue;
|
|
1352
|
-
}
|
|
1353
|
-
const { name, result, ms } = s.value;
|
|
1354
|
-
if (result === "TIMEOUT") {
|
|
1355
|
-
gates.push({ name, status: "timeout", findings_count: 0, duration_ms: ms });
|
|
1356
|
-
continue;
|
|
1357
|
-
}
|
|
1358
|
-
let count = 0;
|
|
1359
|
-
// activerecord is informational (model count), not a problem finding — excluded from totalFindings and health score
|
|
1360
|
-
if (name === "security") {
|
|
1361
|
-
securityResult = result;
|
|
1362
|
-
count = securityResult.summary.total;
|
|
1363
|
-
}
|
|
1364
|
-
else if (name === "activerecord") {
|
|
1365
|
-
arResult = result;
|
|
1366
|
-
count = arResult.total;
|
|
1367
|
-
}
|
|
1368
|
-
else if (name === "complexity")
|
|
1369
|
-
count = result?.summary?.above_threshold ?? 0;
|
|
1370
|
-
else if (name === "dead_code")
|
|
1371
|
-
count = result?.candidates?.length ?? 0;
|
|
1372
|
-
else if (name === "patterns")
|
|
1373
|
-
count = result?.matches?.length ?? 0;
|
|
1374
|
-
else if (name === "clones")
|
|
1375
|
-
count = result?.clones?.length ?? 0;
|
|
1376
|
-
else if (name === "hotspots")
|
|
1377
|
-
count = result?.hotspots?.length ?? 0;
|
|
1378
|
-
else if (name === "n_plus_one")
|
|
1379
|
-
count = result?.findings?.length ?? 0;
|
|
1380
|
-
else if (name === "god_model")
|
|
1381
|
-
count = result?.models?.length ?? 0;
|
|
1382
|
-
else if (name === "yii_performance")
|
|
1383
|
-
count = result?.findings?.length ?? 0;
|
|
1384
|
-
if (name !== "activerecord")
|
|
1385
|
-
totalFindings += count;
|
|
1386
|
-
gates.push({ name, status: "ok", findings_count: count, duration_ms: ms });
|
|
1387
|
-
}
|
|
1388
|
-
const sec = securityResult.summary;
|
|
1389
|
-
// Logarithmic penalties — a few critical findings are serious, but hundreds of
|
|
1390
|
-
// complexity warnings shouldn't tank the score to 0. Each gate uses log2 scaling
|
|
1391
|
-
// so 1 finding ≈ 0, 10 ≈ 17, 100 ≈ 33, 1000 ≈ 50 penalty points.
|
|
1392
|
-
const secPenalty = sec.total > 0 ? Math.round(Math.log2(sec.total + 1) * (sec.critical > 0 ? 8 : 4)) : 0;
|
|
1393
|
-
const qualityFindings = totalFindings - sec.total;
|
|
1394
|
-
const qualPenalty = qualityFindings > 0 ? Math.round(Math.log2(qualityFindings + 1) * 4) : 0;
|
|
1395
|
-
const healthScore = Math.max(0, Math.min(100, 100 - secPenalty - qualPenalty));
|
|
1396
|
-
const topRisks = gates.filter(g => g.findings_count > 0 && g.name !== "activerecord").sort((a, b) => b.findings_count - a.findings_count).slice(0, 3).map(g => `${g.name}: ${g.findings_count} findings`);
|
|
1397
|
-
return {
|
|
1398
|
-
repo, duration_ms: Date.now() - startTime,
|
|
1399
|
-
checks_run: gates.filter(g => g.status === "ok").map(g => g.name),
|
|
1400
|
-
gates,
|
|
1401
|
-
summary: { total_findings: totalFindings, critical: sec.critical, high: sec.high, medium: sec.medium, low: sec.low, health_score: healthScore, top_risks: topRisks },
|
|
1402
|
-
security: securityResult,
|
|
1403
|
-
activerecord: arResult,
|
|
1404
|
-
};
|
|
1405
|
-
}
|
|
1406
|
-
// ---------------------------------------------------------------------------
|
|
1407
|
-
// Helpers
|
|
1408
|
-
// ---------------------------------------------------------------------------
|
|
1409
|
-
async function readJsonSafe(path) {
|
|
1410
|
-
try {
|
|
1411
|
-
const content = await readFile(path, "utf-8");
|
|
1412
|
-
return JSON.parse(content);
|
|
1413
|
-
}
|
|
1414
|
-
catch {
|
|
1415
|
-
return null;
|
|
1416
|
-
}
|
|
1417
|
-
}
|
|
1418
|
-
function extractLineContext(source, index) {
|
|
1419
|
-
const lineStart = source.lastIndexOf("\n", index) + 1;
|
|
1420
|
-
const lineEnd = source.indexOf("\n", index);
|
|
1421
|
-
const end = lineEnd === -1 ? source.length : lineEnd;
|
|
1422
|
-
return source.slice(lineStart, end).trim().slice(0, 200);
|
|
1423
|
-
}
|
|
1424
|
-
function pascalToKebab(s) {
|
|
1425
|
-
return s.replace(/([a-z0-9])([A-Z])/g, "$1-$2").toLowerCase();
|
|
1426
|
-
}
|
|
4
|
+
* Compatibility facade: public exports remain stable while implementations
|
|
5
|
+
* live in per-tool modules.
|
|
6
|
+
*/
|
|
7
|
+
export { resolvePhpNamespace } from "./php-namespace-tools.js";
|
|
8
|
+
export { analyzeActiveRecord } from "./php-active-record-tools.js";
|
|
9
|
+
export { tracePhpEvent } from "./php-event-tools.js";
|
|
10
|
+
export { findPhpViews } from "./php-view-tools.js";
|
|
11
|
+
export { resolvePhpService } from "./php-service-tools.js";
|
|
12
|
+
export { phpSecurityScan } from "./php-security-tools.js";
|
|
13
|
+
export { findPhpNPlusOne } from "./php-nplus1-tools.js";
|
|
14
|
+
export { findPhpGodModel } from "./php-god-model-tools.js";
|
|
15
|
+
export { phpProjectAudit } from "./php-project-audit-tools.js";
|
|
1427
16
|
//# sourceMappingURL=php-tools.js.map
|