aios-core 2.1.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/.aios-core/.session/current-session.json +14 -0
- package/.aios-core/cli/commands/generate/index.js +222 -0
- package/.aios-core/cli/commands/manifest/index.js +46 -0
- package/.aios-core/cli/commands/manifest/regenerate.js +96 -0
- package/.aios-core/cli/commands/manifest/validate.js +66 -0
- package/.aios-core/cli/commands/mcp/add.js +234 -0
- package/.aios-core/cli/commands/mcp/index.js +76 -0
- package/.aios-core/cli/commands/mcp/link.js +217 -0
- package/.aios-core/cli/commands/mcp/setup.js +164 -0
- package/.aios-core/cli/commands/mcp/status.js +183 -0
- package/.aios-core/cli/commands/metrics/cleanup.js +91 -0
- package/.aios-core/cli/commands/metrics/index.js +65 -0
- package/.aios-core/cli/commands/metrics/record.js +154 -0
- package/.aios-core/cli/commands/metrics/seed.js +126 -0
- package/.aios-core/cli/commands/metrics/show.js +209 -0
- package/.aios-core/cli/commands/migrate/analyze.js +353 -0
- package/.aios-core/cli/commands/migrate/backup.js +352 -0
- package/.aios-core/cli/commands/migrate/execute.js +292 -0
- package/.aios-core/cli/commands/migrate/index.js +441 -0
- package/.aios-core/cli/commands/migrate/rollback.js +323 -0
- package/.aios-core/cli/commands/migrate/update-imports.js +396 -0
- package/.aios-core/cli/commands/migrate/validate.js +452 -0
- package/.aios-core/cli/commands/qa/index.js +56 -0
- package/.aios-core/cli/commands/qa/run.js +163 -0
- package/.aios-core/cli/commands/qa/status.js +195 -0
- package/.aios-core/cli/commands/workers/formatters/info-formatter.js +274 -0
- package/.aios-core/cli/commands/workers/formatters/list-table.js +265 -0
- package/.aios-core/cli/commands/workers/formatters/list-tree.js +159 -0
- package/.aios-core/cli/commands/workers/index.js +56 -0
- package/.aios-core/cli/commands/workers/info.js +194 -0
- package/.aios-core/cli/commands/workers/list.js +214 -0
- package/.aios-core/cli/commands/workers/search-filters.js +185 -0
- package/.aios-core/cli/commands/workers/search-keyword.js +310 -0
- package/.aios-core/cli/commands/workers/search-semantic.js +293 -0
- package/.aios-core/cli/commands/workers/search.js +154 -0
- package/.aios-core/cli/commands/workers/utils/pagination.js +102 -0
- package/.aios-core/cli/index.js +128 -0
- package/.aios-core/cli/utils/output-formatter-cli.js +232 -0
- package/.aios-core/cli/utils/score-calculator.js +221 -0
- package/.aios-core/core/README.md +229 -0
- package/.aios-core/core/config/config-cache.js +233 -0
- package/.aios-core/core/config/config-loader.js +277 -0
- package/.aios-core/core/data/agent-config-requirements.yaml +368 -0
- package/.aios-core/core/data/aios-kb.md +924 -0
- package/.aios-core/core/data/workflow-patterns.yaml +267 -0
- package/.aios-core/core/docs/SHARD-TRANSLATION-GUIDE.md +335 -0
- package/.aios-core/core/docs/component-creation-guide.md +458 -0
- package/.aios-core/core/docs/session-update-pattern.md +307 -0
- package/.aios-core/core/docs/template-syntax.md +267 -0
- package/.aios-core/core/docs/troubleshooting-guide.md +625 -0
- package/.aios-core/core/elicitation/agent-elicitation.js +272 -0
- package/.aios-core/core/elicitation/elicitation-engine.js +479 -0
- package/.aios-core/core/elicitation/session-manager.js +320 -0
- package/.aios-core/core/elicitation/task-elicitation.js +281 -0
- package/.aios-core/core/elicitation/workflow-elicitation.js +315 -0
- package/.aios-core/core/index.esm.js +42 -0
- package/.aios-core/core/index.js +76 -0
- package/.aios-core/core/manifest/manifest-generator.js +386 -0
- package/.aios-core/core/manifest/manifest-validator.js +429 -0
- package/.aios-core/core/mcp/config-migrator.js +340 -0
- package/.aios-core/core/mcp/global-config-manager.js +369 -0
- package/.aios-core/core/mcp/index.js +34 -0
- package/.aios-core/core/mcp/os-detector.js +188 -0
- package/.aios-core/core/mcp/symlink-manager.js +413 -0
- package/.aios-core/core/migration/migration-config.yaml +83 -0
- package/.aios-core/core/migration/module-mapping.yaml +89 -0
- package/.aios-core/core/quality-gates/base-layer.js +134 -0
- package/.aios-core/core/quality-gates/checklist-generator.js +329 -0
- package/.aios-core/core/quality-gates/focus-area-recommender.js +359 -0
- package/.aios-core/core/quality-gates/human-review-orchestrator.js +529 -0
- package/.aios-core/core/quality-gates/layer1-precommit.js +336 -0
- package/.aios-core/core/quality-gates/layer2-pr-automation.js +324 -0
- package/.aios-core/core/quality-gates/layer3-human-review.js +348 -0
- package/.aios-core/core/quality-gates/notification-manager.js +550 -0
- package/.aios-core/core/quality-gates/quality-gate-config.yaml +86 -0
- package/.aios-core/core/quality-gates/quality-gate-manager.js +601 -0
- package/.aios-core/core/registry/README.md +179 -0
- package/.aios-core/core/registry/build-registry.js +452 -0
- package/.aios-core/core/registry/registry-loader.js +330 -0
- package/.aios-core/core/registry/registry-schema.json +166 -0
- package/.aios-core/core/registry/service-registry.json +6586 -0
- package/.aios-core/core/registry/validate-registry.js +340 -0
- package/.aios-core/core/session/context-detector.js +229 -0
- package/.aios-core/core/session/context-loader.js +288 -0
- package/.aios-core/core/utils/output-formatter.js +298 -0
- package/.aios-core/core/utils/security-utils.js +333 -0
- package/.aios-core/core/utils/yaml-validator.js +419 -0
- package/.aios-core/core-config.yaml +382 -0
- package/.aios-core/data/agent-config-requirements.yaml +368 -0
- package/.aios-core/data/aios-kb.md +924 -0
- package/.aios-core/data/technical-preferences.md +4 -0
- package/.aios-core/data/workflow-patterns.yaml +267 -0
- package/.aios-core/development/README.md +142 -0
- package/.aios-core/development/agent-teams/team-all.yaml +15 -0
- package/.aios-core/development/agent-teams/team-fullstack.yaml +18 -0
- package/.aios-core/development/agent-teams/team-ide-minimal.yaml +10 -0
- package/.aios-core/development/agent-teams/team-no-ui.yaml +13 -0
- package/.aios-core/development/agent-teams/team-qa-focused.yaml +155 -0
- package/.aios-core/development/agents/aios-master.md +339 -0
- package/.aios-core/development/agents/analyst.md +195 -0
- package/.aios-core/development/agents/architect.md +359 -0
- package/.aios-core/development/agents/data-engineer.md +468 -0
- package/.aios-core/development/agents/dev.md +390 -0
- package/.aios-core/development/agents/devops.md +398 -0
- package/.aios-core/development/agents/pm.md +198 -0
- package/.aios-core/development/agents/po.md +256 -0
- package/.aios-core/development/agents/qa.md +312 -0
- package/.aios-core/development/agents/sm.md +220 -0
- package/.aios-core/development/agents/ux-design-expert.md +451 -0
- package/.aios-core/development/scripts/agent-assignment-resolver.js +231 -0
- package/.aios-core/development/scripts/agent-config-loader.js +624 -0
- package/.aios-core/development/scripts/agent-exit-hooks.js +96 -0
- package/.aios-core/development/scripts/apply-inline-greeting-all-agents.js +146 -0
- package/.aios-core/development/scripts/audit-agent-config.js +380 -0
- package/.aios-core/development/scripts/backlog-manager.js +404 -0
- package/.aios-core/development/scripts/batch-update-agents-session-context.js +95 -0
- package/.aios-core/development/scripts/decision-context.js +228 -0
- package/.aios-core/development/scripts/decision-log-generator.js +293 -0
- package/.aios-core/development/scripts/decision-log-indexer.js +284 -0
- package/.aios-core/development/scripts/decision-recorder.js +168 -0
- package/.aios-core/development/scripts/dev-context-loader.js +297 -0
- package/.aios-core/development/scripts/generate-greeting.js +160 -0
- package/.aios-core/development/scripts/greeting-builder.js +866 -0
- package/.aios-core/development/scripts/greeting-config-cli.js +85 -0
- package/.aios-core/development/scripts/greeting-preference-manager.js +145 -0
- package/.aios-core/development/scripts/migrate-task-to-v2.js +377 -0
- package/.aios-core/development/scripts/story-index-generator.js +337 -0
- package/.aios-core/development/scripts/story-manager.js +375 -0
- package/.aios-core/development/scripts/story-update-hook.js +259 -0
- package/.aios-core/development/scripts/task-identifier-resolver.js +145 -0
- package/.aios-core/development/scripts/test-greeting-system.js +142 -0
- package/.aios-core/development/scripts/validate-task-v2.js +319 -0
- package/.aios-core/development/scripts/workflow-navigator.js +214 -0
- package/.aios-core/development/tasks/add-mcp.md +319 -0
- package/.aios-core/development/tasks/advanced-elicitation.md +319 -0
- package/.aios-core/development/tasks/analyst-facilitate-brainstorming.md +342 -0
- package/.aios-core/development/tasks/analyze-framework.md +697 -0
- package/.aios-core/development/tasks/analyze-performance.md +637 -0
- package/.aios-core/development/tasks/apply-qa-fixes.md +340 -0
- package/.aios-core/development/tasks/architect-analyze-impact.md +827 -0
- package/.aios-core/development/tasks/audit-codebase.md +429 -0
- package/.aios-core/development/tasks/audit-tailwind-config.md +270 -0
- package/.aios-core/development/tasks/audit-utilities.md +358 -0
- package/.aios-core/development/tasks/bootstrap-shadcn-library.md +286 -0
- package/.aios-core/development/tasks/brownfield-create-epic.md +486 -0
- package/.aios-core/development/tasks/brownfield-create-story.md +357 -0
- package/.aios-core/development/tasks/build-component.md +478 -0
- package/.aios-core/development/tasks/calculate-roi.md +455 -0
- package/.aios-core/development/tasks/ci-cd-configuration.md +764 -0
- package/.aios-core/development/tasks/cleanup-utilities.md +670 -0
- package/.aios-core/development/tasks/collaborative-edit.md +1109 -0
- package/.aios-core/development/tasks/compose-molecule.md +284 -0
- package/.aios-core/development/tasks/consolidate-patterns.md +414 -0
- package/.aios-core/development/tasks/correct-course.md +280 -0
- package/.aios-core/development/tasks/create-agent.md +322 -0
- package/.aios-core/development/tasks/create-brownfield-story.md +727 -0
- package/.aios-core/development/tasks/create-deep-research-prompt.md +499 -0
- package/.aios-core/development/tasks/create-doc.md +316 -0
- package/.aios-core/development/tasks/create-next-story.md +774 -0
- package/.aios-core/development/tasks/create-suite.md +284 -0
- package/.aios-core/development/tasks/create-task.md +372 -0
- package/.aios-core/development/tasks/create-workflow.md +371 -0
- package/.aios-core/development/tasks/db-analyze-hotpaths.md +572 -0
- package/.aios-core/development/tasks/db-apply-migration.md +381 -0
- package/.aios-core/development/tasks/db-bootstrap.md +642 -0
- package/.aios-core/development/tasks/db-domain-modeling.md +693 -0
- package/.aios-core/development/tasks/db-dry-run.md +293 -0
- package/.aios-core/development/tasks/db-env-check.md +260 -0
- package/.aios-core/development/tasks/db-expansion-pack-integration.md +663 -0
- package/.aios-core/development/tasks/db-explain.md +631 -0
- package/.aios-core/development/tasks/db-impersonate.md +495 -0
- package/.aios-core/development/tasks/db-load-csv.md +593 -0
- package/.aios-core/development/tasks/db-policy-apply.md +653 -0
- package/.aios-core/development/tasks/db-rls-audit.md +411 -0
- package/.aios-core/development/tasks/db-rollback.md +739 -0
- package/.aios-core/development/tasks/db-run-sql.md +613 -0
- package/.aios-core/development/tasks/db-schema-audit.md +1011 -0
- package/.aios-core/development/tasks/db-seed.md +390 -0
- package/.aios-core/development/tasks/db-smoke-test.md +351 -0
- package/.aios-core/development/tasks/db-snapshot.md +569 -0
- package/.aios-core/development/tasks/db-supabase-setup.md +712 -0
- package/.aios-core/development/tasks/db-verify-order.md +515 -0
- package/.aios-core/development/tasks/deprecate-component.md +957 -0
- package/.aios-core/development/tasks/dev-apply-qa-fixes.md +318 -0
- package/.aios-core/development/tasks/dev-backlog-debt.md +469 -0
- package/.aios-core/development/tasks/dev-develop-story.md +846 -0
- package/.aios-core/development/tasks/dev-improve-code-quality.md +873 -0
- package/.aios-core/development/tasks/dev-optimize-performance.md +1034 -0
- package/.aios-core/development/tasks/dev-suggest-refactoring.md +871 -0
- package/.aios-core/development/tasks/dev-validate-next-story.md +349 -0
- package/.aios-core/development/tasks/document-project.md +553 -0
- package/.aios-core/development/tasks/environment-bootstrap.md +1311 -0
- package/.aios-core/development/tasks/execute-checklist.md +301 -0
- package/.aios-core/development/tasks/export-design-tokens-dtcg.md +274 -0
- package/.aios-core/development/tasks/extend-pattern.md +269 -0
- package/.aios-core/development/tasks/extract-tokens.md +467 -0
- package/.aios-core/development/tasks/facilitate-brainstorming-session.md +518 -0
- package/.aios-core/development/tasks/generate-ai-frontend-prompt.md +261 -0
- package/.aios-core/development/tasks/generate-documentation.md +284 -0
- package/.aios-core/development/tasks/generate-migration-strategy.md +522 -0
- package/.aios-core/development/tasks/generate-shock-report.md +501 -0
- package/.aios-core/development/tasks/github-devops-github-pr-automation.md +427 -0
- package/.aios-core/development/tasks/github-devops-pre-push-quality-gate.md +733 -0
- package/.aios-core/development/tasks/github-devops-repository-cleanup.md +374 -0
- package/.aios-core/development/tasks/github-devops-version-management.md +483 -0
- package/.aios-core/development/tasks/improve-self.md +823 -0
- package/.aios-core/development/tasks/index-docs.md +388 -0
- package/.aios-core/development/tasks/init-project-status.md +506 -0
- package/.aios-core/development/tasks/integrate-expansion-pack.md +314 -0
- package/.aios-core/development/tasks/kb-mode-interaction.md +284 -0
- package/.aios-core/development/tasks/learn-patterns.md +901 -0
- package/.aios-core/development/tasks/mcp-workflow.md +437 -0
- package/.aios-core/development/tasks/modify-agent.md +382 -0
- package/.aios-core/development/tasks/modify-task.md +425 -0
- package/.aios-core/development/tasks/modify-workflow.md +466 -0
- package/.aios-core/development/tasks/po-backlog-add.md +370 -0
- package/.aios-core/development/tasks/po-manage-story-backlog.md +523 -0
- package/.aios-core/development/tasks/po-pull-story-from-clickup.md +540 -0
- package/.aios-core/development/tasks/po-pull-story.md +316 -0
- package/.aios-core/development/tasks/po-stories-index.md +351 -0
- package/.aios-core/development/tasks/po-sync-story-to-clickup.md +457 -0
- package/.aios-core/development/tasks/po-sync-story.md +303 -0
- package/.aios-core/development/tasks/pr-automation.md +701 -0
- package/.aios-core/development/tasks/propose-modification.md +843 -0
- package/.aios-core/development/tasks/qa-backlog-add-followup.md +425 -0
- package/.aios-core/development/tasks/qa-gate.md +374 -0
- package/.aios-core/development/tasks/qa-generate-tests.md +1175 -0
- package/.aios-core/development/tasks/qa-nfr-assess.md +558 -0
- package/.aios-core/development/tasks/qa-review-proposal.md +1158 -0
- package/.aios-core/development/tasks/qa-review-story.md +683 -0
- package/.aios-core/development/tasks/qa-risk-profile.md +567 -0
- package/.aios-core/development/tasks/qa-run-tests.md +277 -0
- package/.aios-core/development/tasks/qa-test-design.md +388 -0
- package/.aios-core/development/tasks/qa-trace-requirements.md +477 -0
- package/.aios-core/development/tasks/release-management.md +723 -0
- package/.aios-core/development/tasks/security-audit.md +554 -0
- package/.aios-core/development/tasks/security-scan.md +790 -0
- package/.aios-core/development/tasks/setup-database.md +741 -0
- package/.aios-core/development/tasks/setup-design-system.md +462 -0
- package/.aios-core/development/tasks/setup-github.md +874 -0
- package/.aios-core/development/tasks/setup-llm-routing.md +229 -0
- package/.aios-core/development/tasks/setup-mcp-docker.md +584 -0
- package/.aios-core/development/tasks/shard-doc.md +538 -0
- package/.aios-core/development/tasks/sm-create-next-story.md +480 -0
- package/.aios-core/development/tasks/sync-documentation.md +865 -0
- package/.aios-core/development/tasks/tailwind-upgrade.md +294 -0
- package/.aios-core/development/tasks/test-as-user.md +621 -0
- package/.aios-core/development/tasks/test-validation-task.md +171 -0
- package/.aios-core/development/tasks/undo-last.md +347 -0
- package/.aios-core/development/tasks/update-manifest.md +410 -0
- package/.aios-core/development/tasks/ux-create-wireframe.md +617 -0
- package/.aios-core/development/tasks/ux-ds-scan-artifact.md +672 -0
- package/.aios-core/development/tasks/ux-user-research.md +559 -0
- package/.aios-core/development/tasks/validate-next-story.md +423 -0
- package/.aios-core/development/tasks/validate-structure.md +243 -0
- package/.aios-core/development/workflows/README.md +84 -0
- package/.aios-core/development/workflows/brownfield-fullstack.yaml +297 -0
- package/.aios-core/development/workflows/brownfield-service.yaml +187 -0
- package/.aios-core/development/workflows/brownfield-ui.yaml +197 -0
- package/.aios-core/development/workflows/greenfield-fullstack.yaml +333 -0
- package/.aios-core/development/workflows/greenfield-service.yaml +206 -0
- package/.aios-core/development/workflows/greenfield-ui.yaml +235 -0
- package/.aios-core/docs/SHARD-TRANSLATION-GUIDE.md +335 -0
- package/.aios-core/docs/component-creation-guide.md +458 -0
- package/.aios-core/docs/session-update-pattern.md +307 -0
- package/.aios-core/docs/standards/AGENT-PERSONALIZATION-STANDARD-V1.md +572 -0
- package/.aios-core/docs/standards/AIOS-COLOR-PALETTE-QUICK-REFERENCE.md +185 -0
- package/.aios-core/docs/standards/AIOS-COLOR-PALETTE-V2.1.md +354 -0
- package/.aios-core/docs/standards/AIOS-FRAMEWORK-MASTER.md +1963 -0
- package/.aios-core/docs/standards/AIOS-LIVRO-DE-OURO-V2.1-COMPLETE.md +821 -0
- package/.aios-core/docs/standards/AIOS-LIVRO-DE-OURO-V2.1-SUMMARY.md +1190 -0
- package/.aios-core/docs/standards/AIOS-LIVRO-DE-OURO-V2.1.md +439 -0
- package/.aios-core/docs/standards/AIOS-LIVRO-DE-OURO-V2.2-SUMMARY.md +1339 -0
- package/.aios-core/docs/standards/AIOS-LIVRO-DE-OURO.md +5398 -0
- package/.aios-core/docs/standards/EXECUTOR-DECISION-TREE.md +697 -0
- package/.aios-core/docs/standards/OPEN-SOURCE-VS-SERVICE-DIFFERENCES.md +511 -0
- package/.aios-core/docs/standards/QUALITY-GATES-SPECIFICATION.md +556 -0
- package/.aios-core/docs/standards/STANDARDS-INDEX.md +210 -0
- package/.aios-core/docs/standards/STORY-TEMPLATE-V2-SPECIFICATION.md +550 -0
- package/.aios-core/docs/standards/TASK-FORMAT-SPECIFICATION-V1.md +1414 -0
- package/.aios-core/docs/standards/V3-ARCHITECTURAL-DECISIONS.md +523 -0
- package/.aios-core/docs/template-syntax.md +267 -0
- package/.aios-core/docs/troubleshooting-guide.md +625 -0
- package/.aios-core/elicitation/agent-elicitation.js +272 -0
- package/.aios-core/elicitation/task-elicitation.js +281 -0
- package/.aios-core/elicitation/workflow-elicitation.js +315 -0
- package/.aios-core/index.d.ts +8 -0
- package/.aios-core/index.esm.js +16 -0
- package/.aios-core/index.js +16 -0
- package/.aios-core/infrastructure/README.md +126 -0
- package/.aios-core/infrastructure/index.js +199 -0
- package/.aios-core/infrastructure/integrations/pm-adapters/README.md +59 -0
- package/.aios-core/infrastructure/integrations/pm-adapters/clickup-adapter.js +345 -0
- package/.aios-core/infrastructure/integrations/pm-adapters/github-adapter.js +392 -0
- package/.aios-core/infrastructure/integrations/pm-adapters/jira-adapter.js +448 -0
- package/.aios-core/infrastructure/integrations/pm-adapters/local-adapter.js +175 -0
- package/.aios-core/infrastructure/scripts/_archived/final-todo-count.js +122 -0
- package/.aios-core/infrastructure/scripts/_archived/fix-yaml-formatting.js +89 -0
- package/.aios-core/infrastructure/scripts/_archived/migration-generator.js +780 -0
- package/.aios-core/infrastructure/scripts/_archived/migration-path-generator.js +950 -0
- package/.aios-core/infrastructure/scripts/_archived/phase2-entrada-saida-errors.js +425 -0
- package/.aios-core/infrastructure/scripts/_archived/phase2-spot-check.js +132 -0
- package/.aios-core/infrastructure/scripts/_archived/phase3-tools-scripts-validation.js +381 -0
- package/.aios-core/infrastructure/scripts/_archived/phase4-metadata-performance.js +203 -0
- package/.aios-core/infrastructure/scripts/_archived/test-yaml-parsing.js +24 -0
- package/.aios-core/infrastructure/scripts/_archived/verify-yaml-fix.js +51 -0
- package/.aios-core/infrastructure/scripts/aios-validator.js +294 -0
- package/.aios-core/infrastructure/scripts/approval-workflow.js +643 -0
- package/.aios-core/infrastructure/scripts/atomic-layer-classifier.js +308 -0
- package/.aios-core/infrastructure/scripts/backup-manager.js +607 -0
- package/.aios-core/infrastructure/scripts/batch-creator.js +608 -0
- package/.aios-core/infrastructure/scripts/branch-manager.js +391 -0
- package/.aios-core/infrastructure/scripts/capability-analyzer.js +535 -0
- package/.aios-core/infrastructure/scripts/clickup-helpers.js +226 -0
- package/.aios-core/infrastructure/scripts/code-quality-improver.js +1312 -0
- package/.aios-core/infrastructure/scripts/commit-message-generator.js +850 -0
- package/.aios-core/infrastructure/scripts/component-generator.js +738 -0
- package/.aios-core/infrastructure/scripts/component-metadata.js +627 -0
- package/.aios-core/infrastructure/scripts/component-search.js +277 -0
- package/.aios-core/infrastructure/scripts/config-cache.js +322 -0
- package/.aios-core/infrastructure/scripts/config-loader.js +349 -0
- package/.aios-core/infrastructure/scripts/conflict-resolver.js +675 -0
- package/.aios-core/infrastructure/scripts/coverage-analyzer.js +882 -0
- package/.aios-core/infrastructure/scripts/dependency-analyzer.js +638 -0
- package/.aios-core/infrastructure/scripts/dependency-impact-analyzer.js +703 -0
- package/.aios-core/infrastructure/scripts/diff-generator.js +129 -0
- package/.aios-core/infrastructure/scripts/documentation-integrity/brownfield-analyzer.js +501 -0
- package/.aios-core/infrastructure/scripts/documentation-integrity/config-generator.js +329 -0
- package/.aios-core/infrastructure/scripts/documentation-integrity/deployment-config-loader.js +282 -0
- package/.aios-core/infrastructure/scripts/documentation-integrity/doc-generator.js +331 -0
- package/.aios-core/infrastructure/scripts/documentation-integrity/gitignore-generator.js +313 -0
- package/.aios-core/infrastructure/scripts/documentation-integrity/index.js +74 -0
- package/.aios-core/infrastructure/scripts/documentation-integrity/mode-detector.js +358 -0
- package/.aios-core/infrastructure/scripts/documentation-synchronizer.js +1432 -0
- package/.aios-core/infrastructure/scripts/framework-analyzer.js +746 -0
- package/.aios-core/infrastructure/scripts/git-config-detector.js +293 -0
- package/.aios-core/infrastructure/scripts/git-wrapper.js +443 -0
- package/.aios-core/infrastructure/scripts/improvement-engine.js +758 -0
- package/.aios-core/infrastructure/scripts/improvement-validator.js +710 -0
- package/.aios-core/infrastructure/scripts/llm-routing/install-llm-routing.js +267 -0
- package/.aios-core/infrastructure/scripts/llm-routing/templates/claude-free.cmd +80 -0
- package/.aios-core/infrastructure/scripts/llm-routing/templates/claude-free.sh +62 -0
- package/.aios-core/infrastructure/scripts/llm-routing/templates/claude-max.cmd +26 -0
- package/.aios-core/infrastructure/scripts/llm-routing/templates/claude-max.sh +18 -0
- package/.aios-core/infrastructure/scripts/modification-risk-assessment.js +970 -0
- package/.aios-core/infrastructure/scripts/modification-validator.js +555 -0
- package/.aios-core/infrastructure/scripts/output-formatter.js +297 -0
- package/.aios-core/infrastructure/scripts/performance-analyzer.js +758 -0
- package/.aios-core/infrastructure/scripts/performance-and-error-resolver.js +258 -0
- package/.aios-core/infrastructure/scripts/performance-optimizer.js +1902 -0
- package/.aios-core/infrastructure/scripts/performance-tracker.js +452 -0
- package/.aios-core/infrastructure/scripts/pm-adapter-factory.js +181 -0
- package/.aios-core/infrastructure/scripts/pm-adapter.js +134 -0
- package/.aios-core/infrastructure/scripts/project-status-loader.js +445 -0
- package/.aios-core/infrastructure/scripts/refactoring-suggester.js +1139 -0
- package/.aios-core/infrastructure/scripts/repository-detector.js +64 -0
- package/.aios-core/infrastructure/scripts/sandbox-tester.js +618 -0
- package/.aios-core/infrastructure/scripts/security-checker.js +359 -0
- package/.aios-core/infrastructure/scripts/source-tree-guardian/index.js +375 -0
- package/.aios-core/infrastructure/scripts/source-tree-guardian/manifest-generator.js +410 -0
- package/.aios-core/infrastructure/scripts/source-tree-guardian/rules/naming-rules.yaml +285 -0
- package/.aios-core/infrastructure/scripts/source-tree-guardian/rules/placement-rules.yaml +262 -0
- package/.aios-core/infrastructure/scripts/source-tree-guardian/validator.js +468 -0
- package/.aios-core/infrastructure/scripts/spot-check-validator.js +149 -0
- package/.aios-core/infrastructure/scripts/status-mapper.js +115 -0
- package/.aios-core/infrastructure/scripts/template-engine.js +240 -0
- package/.aios-core/infrastructure/scripts/template-validator.js +279 -0
- package/.aios-core/infrastructure/scripts/test-generator.js +844 -0
- package/.aios-core/infrastructure/scripts/test-quality-assessment.js +1081 -0
- package/.aios-core/infrastructure/scripts/test-utilities-fast.js +126 -0
- package/.aios-core/infrastructure/scripts/test-utilities.js +200 -0
- package/.aios-core/infrastructure/scripts/tool-resolver.js +360 -0
- package/.aios-core/infrastructure/scripts/transaction-manager.js +590 -0
- package/.aios-core/infrastructure/scripts/usage-analytics.js +634 -0
- package/.aios-core/infrastructure/scripts/validate-output-pattern.js +213 -0
- package/.aios-core/infrastructure/scripts/visual-impact-generator.js +1056 -0
- package/.aios-core/infrastructure/scripts/yaml-validator.js +397 -0
- package/.aios-core/infrastructure/templates/coderabbit.yaml.template +279 -0
- package/.aios-core/infrastructure/templates/core-config/core-config-brownfield.tmpl.yaml +182 -0
- package/.aios-core/infrastructure/templates/core-config/core-config-greenfield.tmpl.yaml +127 -0
- package/.aios-core/infrastructure/templates/github-workflows/README.md +109 -0
- package/.aios-core/infrastructure/templates/github-workflows/ci.yml.template +169 -0
- package/.aios-core/infrastructure/templates/github-workflows/pr-automation.yml.template +330 -0
- package/.aios-core/infrastructure/templates/github-workflows/release.yml.template +196 -0
- package/.aios-core/infrastructure/templates/gitignore/gitignore-aios-base.tmpl +63 -0
- package/.aios-core/infrastructure/templates/gitignore/gitignore-brownfield-merge.tmpl +18 -0
- package/.aios-core/infrastructure/templates/gitignore/gitignore-node.tmpl +85 -0
- package/.aios-core/infrastructure/templates/gitignore/gitignore-python.tmpl +145 -0
- package/.aios-core/infrastructure/templates/project-docs/coding-standards-tmpl.md +346 -0
- package/.aios-core/infrastructure/templates/project-docs/source-tree-tmpl.md +177 -0
- package/.aios-core/infrastructure/templates/project-docs/tech-stack-tmpl.md +267 -0
- package/.aios-core/infrastructure/tests/project-status-loader.test.js +394 -0
- package/.aios-core/infrastructure/tests/regression-suite-v2.md +621 -0
- package/.aios-core/infrastructure/tests/utilities-audit-results.json +501 -0
- package/.aios-core/infrastructure/tests/validate-module.js +97 -0
- package/.aios-core/infrastructure/tools/README.md +222 -0
- package/.aios-core/infrastructure/tools/cli/github-cli.yaml +200 -0
- package/.aios-core/infrastructure/tools/cli/llm-routing.yaml +126 -0
- package/.aios-core/infrastructure/tools/cli/railway-cli.yaml +260 -0
- package/.aios-core/infrastructure/tools/cli/supabase-cli.yaml +224 -0
- package/.aios-core/infrastructure/tools/local/ffmpeg.yaml +261 -0
- package/.aios-core/infrastructure/tools/mcp/21st-dev-magic.yaml +127 -0
- package/.aios-core/infrastructure/tools/mcp/browser.yaml +103 -0
- package/.aios-core/infrastructure/tools/mcp/clickup.yaml +534 -0
- package/.aios-core/infrastructure/tools/mcp/context7.yaml +78 -0
- package/.aios-core/infrastructure/tools/mcp/desktop-commander.yaml +180 -0
- package/.aios-core/infrastructure/tools/mcp/exa.yaml +103 -0
- package/.aios-core/infrastructure/tools/mcp/google-workspace.yaml +930 -0
- package/.aios-core/infrastructure/tools/mcp/n8n.yaml +551 -0
- package/.aios-core/infrastructure/tools/mcp/supabase.yaml +808 -0
- package/.aios-core/install-manifest.yaml +347 -0
- package/.aios-core/manifests/agents.csv +1 -0
- package/.aios-core/manifests/schema/manifest-schema.json +190 -0
- package/.aios-core/manifests/tasks.csv +121 -0
- package/.aios-core/manifests/workers.csv +204 -0
- package/.aios-core/package.json +103 -0
- package/.aios-core/product/README.md +56 -0
- package/.aios-core/product/checklists/architect-checklist.md +444 -0
- package/.aios-core/product/checklists/change-checklist.md +183 -0
- package/.aios-core/product/checklists/database-design-checklist.md +119 -0
- package/.aios-core/product/checklists/dba-predeploy-checklist.md +97 -0
- package/.aios-core/product/checklists/dba-rollback-checklist.md +99 -0
- package/.aios-core/product/checklists/pm-checklist.md +376 -0
- package/.aios-core/product/checklists/po-master-checklist.md +442 -0
- package/.aios-core/product/checklists/pre-push-checklist.md +108 -0
- package/.aios-core/product/checklists/release-checklist.md +122 -0
- package/.aios-core/product/checklists/story-dod-checklist.md +102 -0
- package/.aios-core/product/checklists/story-draft-checklist.md +216 -0
- package/.aios-core/product/data/brainstorming-techniques.md +37 -0
- package/.aios-core/product/data/elicitation-methods.md +135 -0
- package/.aios-core/product/data/mode-selection-best-practices.md +471 -0
- package/.aios-core/product/data/test-levels-framework.md +149 -0
- package/.aios-core/product/data/test-priorities-matrix.md +175 -0
- package/.aios-core/product/templates/1mcp-config.yaml +225 -0
- package/.aios-core/product/templates/activation-instructions-inline-greeting.yaml +63 -0
- package/.aios-core/product/templates/activation-instructions-template.md +258 -0
- package/.aios-core/product/templates/adr.hbs +125 -0
- package/.aios-core/product/templates/agent-template.yaml +121 -0
- package/.aios-core/product/templates/architecture-tmpl.yaml +651 -0
- package/.aios-core/product/templates/brainstorming-output-tmpl.yaml +156 -0
- package/.aios-core/product/templates/brownfield-architecture-tmpl.yaml +476 -0
- package/.aios-core/product/templates/brownfield-prd-tmpl.yaml +280 -0
- package/.aios-core/product/templates/changelog-template.md +134 -0
- package/.aios-core/product/templates/command-rationalization-matrix.md +152 -0
- package/.aios-core/product/templates/competitor-analysis-tmpl.yaml +293 -0
- package/.aios-core/product/templates/component-react-tmpl.tsx +98 -0
- package/.aios-core/product/templates/dbdr.hbs +241 -0
- package/.aios-core/product/templates/design-story-tmpl.yaml +587 -0
- package/.aios-core/product/templates/ds-artifact-analysis.md +70 -0
- package/.aios-core/product/templates/engine/elicitation.js +298 -0
- package/.aios-core/product/templates/engine/index.js +308 -0
- package/.aios-core/product/templates/engine/loader.js +231 -0
- package/.aios-core/product/templates/engine/renderer.js +343 -0
- package/.aios-core/product/templates/engine/schemas/adr.schema.json +102 -0
- package/.aios-core/product/templates/engine/schemas/dbdr.schema.json +205 -0
- package/.aios-core/product/templates/engine/schemas/epic.schema.json +175 -0
- package/.aios-core/product/templates/engine/schemas/pmdr.schema.json +175 -0
- package/.aios-core/product/templates/engine/schemas/prd-v2.schema.json +300 -0
- package/.aios-core/product/templates/engine/schemas/prd.schema.json +152 -0
- package/.aios-core/product/templates/engine/schemas/story.schema.json +222 -0
- package/.aios-core/product/templates/engine/schemas/task.schema.json +154 -0
- package/.aios-core/product/templates/engine/validator.js +294 -0
- package/.aios-core/product/templates/epic.hbs +212 -0
- package/.aios-core/product/templates/eslintrc-security.json +32 -0
- package/.aios-core/product/templates/front-end-architecture-tmpl.yaml +206 -0
- package/.aios-core/product/templates/front-end-spec-tmpl.yaml +349 -0
- package/.aios-core/product/templates/fullstack-architecture-tmpl.yaml +805 -0
- package/.aios-core/product/templates/github-actions-cd.yml +212 -0
- package/.aios-core/product/templates/github-actions-ci.yml +172 -0
- package/.aios-core/product/templates/github-pr-template.md +67 -0
- package/.aios-core/product/templates/gordon-mcp.yaml +140 -0
- package/.aios-core/product/templates/ide-rules/antigravity-rules.md +115 -0
- package/.aios-core/product/templates/ide-rules/claude-rules.md +221 -0
- package/.aios-core/product/templates/ide-rules/cline-rules.md +84 -0
- package/.aios-core/product/templates/ide-rules/copilot-rules.md +92 -0
- package/.aios-core/product/templates/ide-rules/cursor-rules.md +115 -0
- package/.aios-core/product/templates/ide-rules/gemini-rules.md +85 -0
- package/.aios-core/product/templates/ide-rules/roo-rules.md +86 -0
- package/.aios-core/product/templates/ide-rules/trae-rules.md +104 -0
- package/.aios-core/product/templates/ide-rules/windsurf-rules.md +80 -0
- package/.aios-core/product/templates/index-strategy-tmpl.yaml +53 -0
- package/.aios-core/product/templates/market-research-tmpl.yaml +252 -0
- package/.aios-core/product/templates/mcp-workflow.js +271 -0
- package/.aios-core/product/templates/migration-plan-tmpl.yaml +1022 -0
- package/.aios-core/product/templates/migration-strategy-tmpl.md +524 -0
- package/.aios-core/product/templates/personalized-agent-template.md +258 -0
- package/.aios-core/product/templates/personalized-checklist-template.md +340 -0
- package/.aios-core/product/templates/personalized-task-template-v2.md +905 -0
- package/.aios-core/product/templates/personalized-task-template.md +344 -0
- package/.aios-core/product/templates/personalized-template-file.yaml +322 -0
- package/.aios-core/product/templates/personalized-workflow-template.yaml +460 -0
- package/.aios-core/product/templates/pmdr.hbs +186 -0
- package/.aios-core/product/templates/prd-tmpl.yaml +202 -0
- package/.aios-core/product/templates/prd-v2.0.hbs +216 -0
- package/.aios-core/product/templates/prd.hbs +201 -0
- package/.aios-core/product/templates/project-brief-tmpl.yaml +221 -0
- package/.aios-core/product/templates/qa-gate-tmpl.yaml +240 -0
- package/.aios-core/product/templates/rls-policies-tmpl.yaml +1203 -0
- package/.aios-core/product/templates/schema-design-tmpl.yaml +428 -0
- package/.aios-core/product/templates/shock-report-tmpl.html +502 -0
- package/.aios-core/product/templates/state-persistence-tmpl.yaml +219 -0
- package/.aios-core/product/templates/story-tmpl.yaml +332 -0
- package/.aios-core/product/templates/story.hbs +263 -0
- package/.aios-core/product/templates/task-execution-report.md +495 -0
- package/.aios-core/product/templates/task-template.md +123 -0
- package/.aios-core/product/templates/task.hbs +170 -0
- package/.aios-core/product/templates/tmpl-comment-on-examples.sql +158 -0
- package/.aios-core/product/templates/tmpl-migration-script.sql +91 -0
- package/.aios-core/product/templates/tmpl-rls-granular-policies.sql +104 -0
- package/.aios-core/product/templates/tmpl-rls-kiss-policy.sql +10 -0
- package/.aios-core/product/templates/tmpl-rls-roles.sql +135 -0
- package/.aios-core/product/templates/tmpl-rls-simple.sql +77 -0
- package/.aios-core/product/templates/tmpl-rls-tenant.sql +152 -0
- package/.aios-core/product/templates/tmpl-rollback-script.sql +77 -0
- package/.aios-core/product/templates/tmpl-seed-data.sql +140 -0
- package/.aios-core/product/templates/tmpl-smoke-test.sql +16 -0
- package/.aios-core/product/templates/tmpl-staging-copy-merge.sql +139 -0
- package/.aios-core/product/templates/tmpl-stored-proc.sql +140 -0
- package/.aios-core/product/templates/tmpl-trigger.sql +152 -0
- package/.aios-core/product/templates/tmpl-view-materialized.sql +133 -0
- package/.aios-core/product/templates/tmpl-view.sql +177 -0
- package/.aios-core/product/templates/token-exports-css-tmpl.css +240 -0
- package/.aios-core/product/templates/token-exports-tailwind-tmpl.js +395 -0
- package/.aios-core/product/templates/tokens-schema-tmpl.yaml +305 -0
- package/.aios-core/product/templates/workflow-template.yaml +134 -0
- package/.aios-core/quality/metrics-collector.js +572 -0
- package/.aios-core/quality/metrics-hook.js +260 -0
- package/.aios-core/quality/schemas/quality-metrics.schema.json +233 -0
- package/.aios-core/quality/seed-metrics.js +336 -0
- package/.aios-core/scripts/README.md +354 -0
- package/.aios-core/scripts/aios-doc-template.md +325 -0
- package/.aios-core/scripts/batch-migrate-phase1.ps1 +36 -0
- package/.aios-core/scripts/batch-migrate-phase2.ps1 +88 -0
- package/.aios-core/scripts/batch-migrate-phase3.ps1 +45 -0
- package/.aios-core/scripts/command-execution-hook.js +201 -0
- package/.aios-core/scripts/context-detector.js +226 -0
- package/.aios-core/scripts/elicitation-engine.js +385 -0
- package/.aios-core/scripts/elicitation-session-manager.js +300 -0
- package/.aios-core/scripts/migrate-framework-docs.sh +300 -0
- package/.aios-core/scripts/session-context-loader.js +286 -0
- package/.aios-core/scripts/test-template-system.js +941 -0
- package/.aios-core/scripts/validate-phase1.ps1 +35 -0
- package/.aios-core/scripts/workflow-management.md +69 -0
- package/.aios-core/tasks/find-component.md.legacy +391 -0
- package/.aios-core/tasks/generate-commit-message.md.legacy +426 -0
- package/.aios-core/tasks/generate-migration.md.legacy +382 -0
- package/.aios-core/tasks/rollback-modification.md.legacy +307 -0
- package/.aios-core/tasks/update-tests.md.legacy +283 -0
- package/.aios-core/user-guide.md +1413 -0
- package/.aios-core/working-in-the-brownfield.md +361 -0
- package/.claude/CLAUDE.md +221 -0
- package/LICENSE +48 -0
- package/README.md +703 -0
- package/bin/aios-init-old.js +532 -0
- package/bin/aios-init-v4.js +390 -0
- package/bin/aios-init.backup-v1.1.4.js +352 -0
- package/bin/aios-init.js +736 -0
- package/bin/aios-minimal.js +26 -0
- package/bin/aios.js +279 -0
- package/bin/migrate-pm-config.js +219 -0
- package/bin/modules/env-config.js +436 -0
- package/bin/modules/mcp-installer.js +383 -0
- package/bin/utils/install-errors.js +339 -0
- package/bin/utils/install-transaction.js +445 -0
- package/index.d.ts +19 -0
- package/index.esm.js +21 -0
- package/index.js +94 -0
- package/package.json +161 -0
- package/packages/installer/package.json +39 -0
- package/packages/installer/src/config/configure-environment.js +312 -0
- package/packages/installer/src/config/templates/core-config-template.js +183 -0
- package/packages/installer/src/config/templates/env-template.js +127 -0
- package/packages/installer/src/config/validation/config-validator.js +243 -0
- package/packages/installer/src/detection/detect-project-type.js +81 -0
- package/packages/installer/src/wizard/wizard.js +244 -0
- package/packages/installer/tests/integration/environment-configuration.test.js +328 -0
- package/packages/installer/tests/integration/wizard-detection.test.js +349 -0
- package/packages/installer/tests/unit/config-validator.test.js +315 -0
- package/packages/installer/tests/unit/detection/detect-project-type.test.js +401 -0
- package/packages/installer/tests/unit/env-template.test.js +185 -0
- package/src/config/ide-configs.js +189 -0
- package/src/installer/aios-core-installer.js +319 -0
- package/src/installer/dependency-installer.js +335 -0
- package/src/utils/aios-colors.js +234 -0
- package/src/wizard/feedback.js +218 -0
- package/src/wizard/ide-config-generator.js +488 -0
- package/src/wizard/ide-selector.js +84 -0
- package/src/wizard/index.js +589 -0
- package/src/wizard/questions.js +249 -0
- package/src/wizard/validation/index.js +120 -0
- package/src/wizard/validation/report-generator.js +269 -0
- package/src/wizard/validation/troubleshooting-system.js +346 -0
- package/src/wizard/validation/validators/config-validator.js +362 -0
- package/src/wizard/validation/validators/dependency-validator.js +333 -0
- package/src/wizard/validation/validators/file-structure-validator.js +181 -0
- package/src/wizard/validation/validators/mcp-health-checker.js +310 -0
- package/src/wizard/validators.js +274 -0
- package/templates/squad/LICENSE +21 -0
- package/templates/squad/README.md +37 -0
- package/templates/squad/agents/example-agent.yaml +36 -0
- package/templates/squad/package.json +19 -0
- package/templates/squad/squad.yaml +25 -0
- package/templates/squad/tasks/example-task.yaml +46 -0
- package/templates/squad/templates/example-template.md +24 -0
- package/templates/squad/tests/example-agent.test.js +53 -0
- package/templates/squad/workflows/example-workflow.yaml +54 -0
- package/tools/package-builder.js +35 -0
|
@@ -0,0 +1,1902 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AIOS Performance Optimizer
|
|
3
|
+
*
|
|
4
|
+
* Analyzes code for performance bottlenecks and suggests optimizations
|
|
5
|
+
* to improve runtime performance, memory usage, and scalability.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
const fs = require('fs').promises;
|
|
9
|
+
const path = require('path');
|
|
10
|
+
const { EventEmitter } = require('events');
|
|
11
|
+
const parser = require('@babel/parser');
|
|
12
|
+
const traverse = require('@babel/traverse').default;
|
|
13
|
+
const t = require('@babel/types');
|
|
14
|
+
const { performance } = require('perf_hooks');
|
|
15
|
+
|
|
16
|
+
class PerformanceOptimizer extends EventEmitter {
|
|
17
|
+
constructor(options = {}) {
|
|
18
|
+
super();
|
|
19
|
+
this.rootPath = options.rootPath || process.cwd();
|
|
20
|
+
this.optimizationPatterns = new Map();
|
|
21
|
+
this.performanceMetrics = new Map();
|
|
22
|
+
this.optimizationHistory = [];
|
|
23
|
+
this.options = {
|
|
24
|
+
enableProfiling: options.enableProfiling !== false,
|
|
25
|
+
profileDuration: options.profileDuration || 5000, // 5 seconds
|
|
26
|
+
memoryThreshold: options.memoryThreshold || 100 * 1024 * 1024, // 100MB
|
|
27
|
+
timeThreshold: options.timeThreshold || 1000, // 1 second
|
|
28
|
+
complexityThreshold: options.complexityThreshold || 10,
|
|
29
|
+
...options,
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
this.initializeOptimizationPatterns();
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
initializeOptimizationPatterns() {
|
|
36
|
+
// Algorithm optimizations
|
|
37
|
+
this.optimizationPatterns.set('algorithm_complexity', {
|
|
38
|
+
name: 'Algorithm Complexity',
|
|
39
|
+
description: 'Optimize algorithms with high time complexity',
|
|
40
|
+
detector: this.detectHighComplexityAlgorithms.bind(this),
|
|
41
|
+
optimizer: this.suggestAlgorithmOptimizations.bind(this),
|
|
42
|
+
impact: 'high',
|
|
43
|
+
category: 'algorithm',
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
// Loop optimizations
|
|
47
|
+
this.optimizationPatterns.set('loop_optimization', {
|
|
48
|
+
name: 'Loop Optimization',
|
|
49
|
+
description: 'Optimize nested loops and inefficient iterations',
|
|
50
|
+
detector: this.detectIneffientLoops.bind(this),
|
|
51
|
+
optimizer: this.suggestLoopOptimizations.bind(this),
|
|
52
|
+
impact: 'high',
|
|
53
|
+
category: 'algorithm',
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
// Memory optimizations
|
|
57
|
+
this.optimizationPatterns.set('memory_usage', {
|
|
58
|
+
name: 'Memory Usage',
|
|
59
|
+
description: 'Reduce memory consumption and prevent leaks',
|
|
60
|
+
detector: this.detectMemoryIssues.bind(this),
|
|
61
|
+
optimizer: this.suggestMemoryOptimizations.bind(this),
|
|
62
|
+
impact: 'medium',
|
|
63
|
+
category: 'memory',
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
// Async optimizations
|
|
67
|
+
this.optimizationPatterns.set('async_operations', {
|
|
68
|
+
name: 'Async Operations',
|
|
69
|
+
description: 'Optimize async/await patterns and Promise usage',
|
|
70
|
+
detector: this.detectAsyncIssues.bind(this),
|
|
71
|
+
optimizer: this.suggestAsyncOptimizations.bind(this),
|
|
72
|
+
impact: 'high',
|
|
73
|
+
category: 'async',
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
// Caching opportunities
|
|
77
|
+
this.optimizationPatterns.set('caching', {
|
|
78
|
+
name: 'Caching Opportunities',
|
|
79
|
+
description: 'Identify opportunities for memoization and caching',
|
|
80
|
+
detector: this.detectCachingOpportunities.bind(this),
|
|
81
|
+
optimizer: this.suggestCachingStrategies.bind(this),
|
|
82
|
+
impact: 'medium',
|
|
83
|
+
category: 'caching',
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
// Database query optimizations
|
|
87
|
+
this.optimizationPatterns.set('database_queries', {
|
|
88
|
+
name: 'Database Query Optimization',
|
|
89
|
+
description: 'Optimize database queries and reduce N+1 problems',
|
|
90
|
+
detector: this.detectDatabaseIssues.bind(this),
|
|
91
|
+
optimizer: this.suggestDatabaseOptimizations.bind(this),
|
|
92
|
+
impact: 'high',
|
|
93
|
+
category: 'database',
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
// Bundle size optimizations
|
|
97
|
+
this.optimizationPatterns.set('bundle_size', {
|
|
98
|
+
name: 'Bundle Size',
|
|
99
|
+
description: 'Reduce JavaScript bundle size',
|
|
100
|
+
detector: this.detectBundleSizeIssues.bind(this),
|
|
101
|
+
optimizer: this.suggestBundleOptimizations.bind(this),
|
|
102
|
+
impact: 'medium',
|
|
103
|
+
category: 'bundle',
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
// React-specific optimizations
|
|
107
|
+
this.optimizationPatterns.set('react_performance', {
|
|
108
|
+
name: 'React Performance',
|
|
109
|
+
description: 'Optimize React component rendering',
|
|
110
|
+
detector: this.detectReactIssues.bind(this),
|
|
111
|
+
optimizer: this.suggestReactOptimizations.bind(this),
|
|
112
|
+
impact: 'medium',
|
|
113
|
+
category: 'framework',
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
// String operation optimizations
|
|
117
|
+
this.optimizationPatterns.set('string_operations', {
|
|
118
|
+
name: 'String Operations',
|
|
119
|
+
description: 'Optimize string concatenation and manipulation',
|
|
120
|
+
detector: this.detectStringIssues.bind(this),
|
|
121
|
+
optimizer: this.suggestStringOptimizations.bind(this),
|
|
122
|
+
impact: 'low',
|
|
123
|
+
category: 'algorithm',
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
// Object operation optimizations
|
|
127
|
+
this.optimizationPatterns.set('object_operations', {
|
|
128
|
+
name: 'Object Operations',
|
|
129
|
+
description: 'Optimize object creation and manipulation',
|
|
130
|
+
detector: this.detectObjectIssues.bind(this),
|
|
131
|
+
optimizer: this.suggestObjectOptimizations.bind(this),
|
|
132
|
+
impact: 'medium',
|
|
133
|
+
category: 'memory',
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
async analyzePerformance(filePath, options = {}) {
|
|
138
|
+
const startTime = performance.now();
|
|
139
|
+
const analysis = {
|
|
140
|
+
filePath,
|
|
141
|
+
timestamp: new Date().toISOString(),
|
|
142
|
+
issues: [],
|
|
143
|
+
suggestions: [],
|
|
144
|
+
metrics: {},
|
|
145
|
+
};
|
|
146
|
+
|
|
147
|
+
try {
|
|
148
|
+
const content = await fs.readFile(filePath, 'utf-8');
|
|
149
|
+
|
|
150
|
+
// Parse the code
|
|
151
|
+
const ast = parser.parse(content, {
|
|
152
|
+
sourceType: 'module',
|
|
153
|
+
plugins: ['jsx', 'typescript', 'decorators-legacy'],
|
|
154
|
+
errorRecovery: true,
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
// Run static analysis
|
|
158
|
+
await this.performStaticAnalysis(ast, analysis, content);
|
|
159
|
+
|
|
160
|
+
// Run pattern detection
|
|
161
|
+
const patterns = options.patterns || Array.from(this.optimizationPatterns.keys());
|
|
162
|
+
|
|
163
|
+
for (const patternName of patterns) {
|
|
164
|
+
const pattern = this.optimizationPatterns.get(patternName);
|
|
165
|
+
if (!pattern) continue;
|
|
166
|
+
|
|
167
|
+
try {
|
|
168
|
+
const issues = await pattern.detector(ast, content, filePath);
|
|
169
|
+
|
|
170
|
+
if (issues && issues.length > 0) {
|
|
171
|
+
for (const issue of issues) {
|
|
172
|
+
const suggestion = await pattern.optimizer(issue, ast, content);
|
|
173
|
+
|
|
174
|
+
analysis.issues.push({
|
|
175
|
+
pattern: patternName,
|
|
176
|
+
category: pattern.category,
|
|
177
|
+
impact: pattern.impact,
|
|
178
|
+
...issue,
|
|
179
|
+
});
|
|
180
|
+
|
|
181
|
+
if (suggestion) {
|
|
182
|
+
analysis.suggestions.push({
|
|
183
|
+
pattern: patternName,
|
|
184
|
+
issueId: issue.id || `${patternName}-${analysis.issues.length}`,
|
|
185
|
+
...suggestion,
|
|
186
|
+
});
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
} catch (error) {
|
|
191
|
+
console.warn(`Pattern detection failed for ${patternName}:`, error);
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
// Calculate performance score
|
|
196
|
+
analysis.metrics.performanceScore = this.calculatePerformanceScore(analysis);
|
|
197
|
+
analysis.metrics.analysisTime = performance.now() - startTime;
|
|
198
|
+
|
|
199
|
+
// Run runtime profiling if enabled and applicable
|
|
200
|
+
if (this.options.enableProfiling && this.isExecutable(filePath)) {
|
|
201
|
+
const runtimeMetrics = await this.profileRuntime(filePath);
|
|
202
|
+
analysis.metrics.runtime = runtimeMetrics;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
this.emit('analyzed', analysis);
|
|
206
|
+
return analysis;
|
|
207
|
+
|
|
208
|
+
} catch (error) {
|
|
209
|
+
analysis.error = error.message;
|
|
210
|
+
this.emit('error', { phase: 'analysis', error, filePath });
|
|
211
|
+
return analysis;
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
async performStaticAnalysis(ast, analysis, content) {
|
|
216
|
+
const metrics = {
|
|
217
|
+
complexity: 0,
|
|
218
|
+
functionCount: 0,
|
|
219
|
+
loopDepth: 0,
|
|
220
|
+
asyncOperations: 0,
|
|
221
|
+
stringOperations: 0,
|
|
222
|
+
objectOperations: 0,
|
|
223
|
+
arrayOperations: 0,
|
|
224
|
+
domOperations: 0,
|
|
225
|
+
fileSize: content.length,
|
|
226
|
+
lineCount: content.split('\n').length,
|
|
227
|
+
};
|
|
228
|
+
|
|
229
|
+
let currentLoopDepth = 0;
|
|
230
|
+
let maxLoopDepth = 0;
|
|
231
|
+
|
|
232
|
+
traverse(ast, {
|
|
233
|
+
FunctionDeclaration(path) {
|
|
234
|
+
metrics.functionCount++;
|
|
235
|
+
metrics.complexity += calculateCyclomaticComplexity(path.node);
|
|
236
|
+
},
|
|
237
|
+
FunctionExpression(path) {
|
|
238
|
+
metrics.functionCount++;
|
|
239
|
+
metrics.complexity += calculateCyclomaticComplexity(path.node);
|
|
240
|
+
},
|
|
241
|
+
ArrowFunctionExpression(path) {
|
|
242
|
+
metrics.functionCount++;
|
|
243
|
+
metrics.complexity += calculateCyclomaticComplexity(path.node);
|
|
244
|
+
},
|
|
245
|
+
'ForStatement|WhileStatement|DoWhileStatement|ForInStatement|ForOfStatement': {
|
|
246
|
+
enter() {
|
|
247
|
+
currentLoopDepth++;
|
|
248
|
+
maxLoopDepth = Math.max(maxLoopDepth, currentLoopDepth);
|
|
249
|
+
metrics.loopDepth = maxLoopDepth;
|
|
250
|
+
},
|
|
251
|
+
exit() {
|
|
252
|
+
currentLoopDepth--;
|
|
253
|
+
},
|
|
254
|
+
},
|
|
255
|
+
AwaitExpression() {
|
|
256
|
+
metrics.asyncOperations++;
|
|
257
|
+
},
|
|
258
|
+
BinaryExpression(path) {
|
|
259
|
+
if (path.node.operator === '+' &&
|
|
260
|
+
(t.isStringLiteral(path.node.left) || t.isStringLiteral(path.node.right))) {
|
|
261
|
+
metrics.stringOperations++;
|
|
262
|
+
}
|
|
263
|
+
},
|
|
264
|
+
TemplateLiteral() {
|
|
265
|
+
metrics.stringOperations++;
|
|
266
|
+
},
|
|
267
|
+
ObjectExpression() {
|
|
268
|
+
metrics.objectOperations++;
|
|
269
|
+
},
|
|
270
|
+
ArrayExpression() {
|
|
271
|
+
metrics.arrayOperations++;
|
|
272
|
+
},
|
|
273
|
+
CallExpression(path) {
|
|
274
|
+
const callee = path.node.callee;
|
|
275
|
+
|
|
276
|
+
// Check for DOM operations
|
|
277
|
+
if (t.isMemberExpression(callee)) {
|
|
278
|
+
const object = callee.object;
|
|
279
|
+
const property = callee.property;
|
|
280
|
+
|
|
281
|
+
if (t.isIdentifier(object, { name: 'document' }) ||
|
|
282
|
+
(t.isIdentifier(property) && ['querySelector', 'getElementById', 'getElementsBy'].some(m => property.name.startsWith(m)))) {
|
|
283
|
+
metrics.domOperations++;
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
},
|
|
287
|
+
});
|
|
288
|
+
|
|
289
|
+
analysis.metrics.static = metrics;
|
|
290
|
+
|
|
291
|
+
function calculateCyclomaticComplexity(node) {
|
|
292
|
+
let complexity = 1;
|
|
293
|
+
|
|
294
|
+
traverse(node, {
|
|
295
|
+
'IfStatement|ConditionalExpression|SwitchCase|WhileStatement|DoWhileStatement|ForStatement': {
|
|
296
|
+
enter() {
|
|
297
|
+
complexity++;
|
|
298
|
+
},
|
|
299
|
+
},
|
|
300
|
+
LogicalExpression(path) {
|
|
301
|
+
if (path.node.operator === '&&' || path.node.operator === '||') {
|
|
302
|
+
complexity++;
|
|
303
|
+
}
|
|
304
|
+
},
|
|
305
|
+
}, null, { noScope: true });
|
|
306
|
+
|
|
307
|
+
return complexity;
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
async detectHighComplexityAlgorithms(ast, content) {
|
|
312
|
+
const issues = [];
|
|
313
|
+
const self = this;
|
|
314
|
+
|
|
315
|
+
traverse(ast, {
|
|
316
|
+
FunctionDeclaration: checkFunction,
|
|
317
|
+
FunctionExpression: checkFunction,
|
|
318
|
+
ArrowFunctionExpression: checkFunction,
|
|
319
|
+
});
|
|
320
|
+
|
|
321
|
+
function checkFunction(path) {
|
|
322
|
+
const complexity = calculateTimeComplexity(path.node);
|
|
323
|
+
|
|
324
|
+
if (complexity.score > self.options.complexityThreshold) {
|
|
325
|
+
issues.push({
|
|
326
|
+
type: 'high_complexity',
|
|
327
|
+
location: {
|
|
328
|
+
start: path.node.loc?.start,
|
|
329
|
+
end: path.node.loc?.end,
|
|
330
|
+
},
|
|
331
|
+
functionName: path.node.id?.name || '<anonymous>',
|
|
332
|
+
complexity: complexity,
|
|
333
|
+
description: `Function has high time complexity: ${complexity.notation}`,
|
|
334
|
+
severity: complexity.score > 15 ? 'critical' : 'warning',
|
|
335
|
+
});
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
function calculateTimeComplexity(node) {
|
|
340
|
+
let loopDepth = 0;
|
|
341
|
+
let maxLoopDepth = 0;
|
|
342
|
+
let recursiveCall = false;
|
|
343
|
+
let exponentialPatterns = 0;
|
|
344
|
+
|
|
345
|
+
traverse(node, {
|
|
346
|
+
'ForStatement|WhileStatement|DoWhileStatement|ForInStatement|ForOfStatement': {
|
|
347
|
+
enter(path) {
|
|
348
|
+
loopDepth++;
|
|
349
|
+
maxLoopDepth = Math.max(maxLoopDepth, loopDepth);
|
|
350
|
+
|
|
351
|
+
// Check for exponential patterns
|
|
352
|
+
if (loopDepth > 1 && isNestedLoopOverSameData(path)) {
|
|
353
|
+
exponentialPatterns++;
|
|
354
|
+
}
|
|
355
|
+
},
|
|
356
|
+
exit() {
|
|
357
|
+
loopDepth--;
|
|
358
|
+
},
|
|
359
|
+
},
|
|
360
|
+
CallExpression(path) {
|
|
361
|
+
// Check for recursive calls
|
|
362
|
+
if (t.isIdentifier(path.node.callee) &&
|
|
363
|
+
path.node.callee.name === node.id?.name) {
|
|
364
|
+
recursiveCall = true;
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
// Check for expensive operations
|
|
368
|
+
if (t.isMemberExpression(path.node.callee)) {
|
|
369
|
+
const property = path.node.callee.property;
|
|
370
|
+
if (t.isIdentifier(property) &&
|
|
371
|
+
['sort', 'reverse', 'includes', 'indexOf'].includes(property.name)) {
|
|
372
|
+
// These can be expensive in loops
|
|
373
|
+
if (loopDepth > 0) exponentialPatterns++;
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
},
|
|
377
|
+
}, null, { noScope: true });
|
|
378
|
+
|
|
379
|
+
// Calculate complexity score and notation
|
|
380
|
+
let score = maxLoopDepth * 5;
|
|
381
|
+
let notation = 'O(1)';
|
|
382
|
+
|
|
383
|
+
if (recursiveCall) {
|
|
384
|
+
score += 10;
|
|
385
|
+
notation = exponentialPatterns > 0 ? 'O(2^n)' : 'O(n)';
|
|
386
|
+
} else if (maxLoopDepth === 1) {
|
|
387
|
+
notation = 'O(n)';
|
|
388
|
+
} else if (maxLoopDepth === 2) {
|
|
389
|
+
notation = exponentialPatterns > 0 ? 'O(n³)' : 'O(n²)';
|
|
390
|
+
} else if (maxLoopDepth >= 3) {
|
|
391
|
+
notation = `O(n^${maxLoopDepth})`;
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
if (exponentialPatterns > 0) {
|
|
395
|
+
score += exponentialPatterns * 5;
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
return { score, notation, loopDepth: maxLoopDepth, hasRecursion: recursiveCall };
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
function isNestedLoopOverSameData(path) {
|
|
402
|
+
// Simplified check - would need more sophisticated analysis
|
|
403
|
+
return false;
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
return issues;
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
async suggestAlgorithmOptimizations(issue, ast, content) {
|
|
410
|
+
const suggestions = [];
|
|
411
|
+
|
|
412
|
+
if (issue.complexity.loopDepth >= 2) {
|
|
413
|
+
suggestions.push({
|
|
414
|
+
type: 'algorithm_optimization',
|
|
415
|
+
description: 'Consider using a more efficient algorithm',
|
|
416
|
+
recommendations: [
|
|
417
|
+
'Use hash maps/Set for lookups instead of nested loops',
|
|
418
|
+
'Consider sorting data first if searching frequently',
|
|
419
|
+
'Use dynamic programming for overlapping subproblems',
|
|
420
|
+
'Consider using binary search for sorted data',
|
|
421
|
+
],
|
|
422
|
+
example: this.generateOptimizationExample(issue.complexity),
|
|
423
|
+
});
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
if (issue.complexity.hasRecursion) {
|
|
427
|
+
suggestions.push({
|
|
428
|
+
type: 'recursion_optimization',
|
|
429
|
+
description: 'Optimize recursive algorithm',
|
|
430
|
+
recommendations: [
|
|
431
|
+
'Add memoization to cache results',
|
|
432
|
+
'Convert to iterative approach if possible',
|
|
433
|
+
'Implement tail recursion optimization',
|
|
434
|
+
'Add base case optimization',
|
|
435
|
+
],
|
|
436
|
+
});
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
return {
|
|
440
|
+
optimizations: suggestions,
|
|
441
|
+
estimatedImprovement: this.estimatePerformanceImprovement(issue),
|
|
442
|
+
priority: issue.severity === 'critical' ? 'high' : 'medium',
|
|
443
|
+
};
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
async detectIneffientLoops(ast, content) {
|
|
447
|
+
const issues = [];
|
|
448
|
+
|
|
449
|
+
traverse(ast, {
|
|
450
|
+
'ForStatement|WhileStatement|DoWhileStatement|ForInStatement|ForOfStatement'(path) {
|
|
451
|
+
// Check for array operations in loops
|
|
452
|
+
const loopIssues = [];
|
|
453
|
+
|
|
454
|
+
path.traverse({
|
|
455
|
+
CallExpression(innerPath) {
|
|
456
|
+
if (t.isMemberExpression(innerPath.node.callee)) {
|
|
457
|
+
const property = innerPath.node.callee.property;
|
|
458
|
+
|
|
459
|
+
// Check for inefficient array methods in loops
|
|
460
|
+
if (t.isIdentifier(property)) {
|
|
461
|
+
if (['push', 'unshift'].includes(property.name)) {
|
|
462
|
+
loopIssues.push({
|
|
463
|
+
type: 'array_growth_in_loop',
|
|
464
|
+
method: property.name,
|
|
465
|
+
description: 'Growing array in loop can cause performance issues',
|
|
466
|
+
});
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
if (['concat', 'slice'].includes(property.name)) {
|
|
470
|
+
loopIssues.push({
|
|
471
|
+
type: 'array_copy_in_loop',
|
|
472
|
+
method: property.name,
|
|
473
|
+
description: 'Creating array copies in loop is inefficient',
|
|
474
|
+
});
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
if (['find', 'filter', 'map', 'reduce'].includes(property.name)) {
|
|
478
|
+
// Check if this is nested iteration
|
|
479
|
+
const parentLoop = innerPath.findParent(p =>
|
|
480
|
+
p.isForStatement() || p.isWhileStatement() || p.isDoWhileStatement(),
|
|
481
|
+
);
|
|
482
|
+
|
|
483
|
+
if (parentLoop && parentLoop !== path) {
|
|
484
|
+
loopIssues.push({
|
|
485
|
+
type: 'nested_iteration',
|
|
486
|
+
method: property.name,
|
|
487
|
+
description: 'Nested iteration can lead to O(n²) complexity',
|
|
488
|
+
});
|
|
489
|
+
}
|
|
490
|
+
}
|
|
491
|
+
}
|
|
492
|
+
}
|
|
493
|
+
},
|
|
494
|
+
BinaryExpression(innerPath) {
|
|
495
|
+
// Check for string concatenation in loops
|
|
496
|
+
if (innerPath.node.operator === '+' &&
|
|
497
|
+
innerPath.isAncestor(path) &&
|
|
498
|
+
(t.isStringLiteral(innerPath.node.left) || t.isStringLiteral(innerPath.node.right))) {
|
|
499
|
+
loopIssues.push({
|
|
500
|
+
type: 'string_concatenation_in_loop',
|
|
501
|
+
description: 'String concatenation in loop is inefficient',
|
|
502
|
+
});
|
|
503
|
+
}
|
|
504
|
+
},
|
|
505
|
+
});
|
|
506
|
+
|
|
507
|
+
if (loopIssues.length > 0) {
|
|
508
|
+
issues.push({
|
|
509
|
+
type: 'inefficient_loop',
|
|
510
|
+
location: {
|
|
511
|
+
start: path.node.loc?.start,
|
|
512
|
+
end: path.node.loc?.end,
|
|
513
|
+
},
|
|
514
|
+
problems: loopIssues,
|
|
515
|
+
description: 'Loop contains inefficient operations',
|
|
516
|
+
});
|
|
517
|
+
}
|
|
518
|
+
},
|
|
519
|
+
});
|
|
520
|
+
|
|
521
|
+
return issues;
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
async suggestLoopOptimizations(issue) {
|
|
525
|
+
const optimizations = [];
|
|
526
|
+
|
|
527
|
+
for (const problem of issue.problems) {
|
|
528
|
+
switch (problem.type) {
|
|
529
|
+
case 'array_growth_in_loop':
|
|
530
|
+
optimizations.push({
|
|
531
|
+
type: 'preallocate_array',
|
|
532
|
+
description: 'Preallocate array with known size',
|
|
533
|
+
code: 'const result = new Array(knownSize);',
|
|
534
|
+
improvement: 'Avoids dynamic array resizing',
|
|
535
|
+
});
|
|
536
|
+
break;
|
|
537
|
+
|
|
538
|
+
case 'array_copy_in_loop':
|
|
539
|
+
optimizations.push({
|
|
540
|
+
type: 'avoid_copies',
|
|
541
|
+
description: 'Work with original array or use single copy',
|
|
542
|
+
improvement: 'Reduces memory allocation and copying',
|
|
543
|
+
});
|
|
544
|
+
break;
|
|
545
|
+
|
|
546
|
+
case 'nested_iteration':
|
|
547
|
+
optimizations.push({
|
|
548
|
+
type: 'use_lookup',
|
|
549
|
+
description: 'Use Set or Map for O(1) lookups',
|
|
550
|
+
code: 'const lookup = new Set(array2);\nfor (const item of array1) {\n if (lookup.has(item)) { ... }\n}',
|
|
551
|
+
improvement: 'Reduces complexity from O(n²) to O(n)',
|
|
552
|
+
});
|
|
553
|
+
break;
|
|
554
|
+
|
|
555
|
+
case 'string_concatenation_in_loop':
|
|
556
|
+
optimizations.push({
|
|
557
|
+
type: 'use_array_join',
|
|
558
|
+
description: 'Use array push and join',
|
|
559
|
+
code: 'const parts = [];\nfor (...) { parts.push(str); }\nconst result = parts.join(\'\');',
|
|
560
|
+
improvement: 'Avoids creating intermediate strings',
|
|
561
|
+
});
|
|
562
|
+
break;
|
|
563
|
+
}
|
|
564
|
+
}
|
|
565
|
+
|
|
566
|
+
return {
|
|
567
|
+
optimizations,
|
|
568
|
+
priority: issue.problems.some(p => p.type === 'nested_iteration') ? 'high' : 'medium',
|
|
569
|
+
};
|
|
570
|
+
}
|
|
571
|
+
|
|
572
|
+
async detectMemoryIssues(ast, content) {
|
|
573
|
+
const issues = [];
|
|
574
|
+
|
|
575
|
+
traverse(ast, {
|
|
576
|
+
VariableDeclarator(path) {
|
|
577
|
+
// Check for potential memory leaks
|
|
578
|
+
if (t.isIdentifier(path.node.id)) {
|
|
579
|
+
const binding = path.scope.getBinding(path.node.id.name);
|
|
580
|
+
|
|
581
|
+
// Check if variable holds large data
|
|
582
|
+
if (t.isArrayExpression(path.node.init) &&
|
|
583
|
+
path.node.init.elements.length > 1000) {
|
|
584
|
+
issues.push({
|
|
585
|
+
type: 'large_array',
|
|
586
|
+
variableName: path.node.id.name,
|
|
587
|
+
size: path.node.init.elements.length,
|
|
588
|
+
location: path.node.loc,
|
|
589
|
+
description: 'Large array allocation',
|
|
590
|
+
});
|
|
591
|
+
}
|
|
592
|
+
|
|
593
|
+
// Check for potential closures holding references
|
|
594
|
+
if (binding && !binding.referenced) {
|
|
595
|
+
path.traverse({
|
|
596
|
+
FunctionExpression(innerPath) {
|
|
597
|
+
if (innerPath.node.id?.name || innerPath.parent.type === 'VariableDeclarator') {
|
|
598
|
+
issues.push({
|
|
599
|
+
type: 'potential_closure_leak',
|
|
600
|
+
variableName: path.node.id.name,
|
|
601
|
+
location: innerPath.node.loc,
|
|
602
|
+
description: 'Closure may retain reference to large object',
|
|
603
|
+
});
|
|
604
|
+
}
|
|
605
|
+
},
|
|
606
|
+
});
|
|
607
|
+
}
|
|
608
|
+
}
|
|
609
|
+
},
|
|
610
|
+
CallExpression(path) {
|
|
611
|
+
// Check for common memory-intensive operations
|
|
612
|
+
if (t.isMemberExpression(path.node.callee)) {
|
|
613
|
+
const object = path.node.callee.object;
|
|
614
|
+
const property = path.node.callee.property;
|
|
615
|
+
|
|
616
|
+
// Check for potential memory issues
|
|
617
|
+
if (t.isIdentifier(property)) {
|
|
618
|
+
if (property.name === 'slice' && path.node.arguments.length === 0) {
|
|
619
|
+
issues.push({
|
|
620
|
+
type: 'unnecessary_copy',
|
|
621
|
+
method: 'slice',
|
|
622
|
+
location: path.node.loc,
|
|
623
|
+
description: 'Creating unnecessary array copy',
|
|
624
|
+
});
|
|
625
|
+
}
|
|
626
|
+
|
|
627
|
+
if (property.name === 'concat' && isInLoop(path)) {
|
|
628
|
+
issues.push({
|
|
629
|
+
type: 'concat_in_loop',
|
|
630
|
+
location: path.node.loc,
|
|
631
|
+
description: 'Concatenating arrays in loop creates many intermediate arrays',
|
|
632
|
+
});
|
|
633
|
+
}
|
|
634
|
+
}
|
|
635
|
+
}
|
|
636
|
+
},
|
|
637
|
+
});
|
|
638
|
+
|
|
639
|
+
function isInLoop(path) {
|
|
640
|
+
return path.findParent(p =>
|
|
641
|
+
p.isForStatement() || p.isWhileStatement() || p.isDoWhileStatement(),
|
|
642
|
+
);
|
|
643
|
+
}
|
|
644
|
+
|
|
645
|
+
return issues;
|
|
646
|
+
}
|
|
647
|
+
|
|
648
|
+
async suggestMemoryOptimizations(issue) {
|
|
649
|
+
const optimizations = [];
|
|
650
|
+
|
|
651
|
+
switch (issue.type) {
|
|
652
|
+
case 'large_array':
|
|
653
|
+
optimizations.push({
|
|
654
|
+
type: 'lazy_loading',
|
|
655
|
+
description: 'Consider lazy loading or pagination',
|
|
656
|
+
recommendation: 'Load data in chunks as needed',
|
|
657
|
+
});
|
|
658
|
+
optimizations.push({
|
|
659
|
+
type: 'typed_array',
|
|
660
|
+
description: 'Use TypedArray for numeric data',
|
|
661
|
+
code: `const data = new Float32Array(${issue.size});`,
|
|
662
|
+
improvement: 'More memory efficient for numbers',
|
|
663
|
+
});
|
|
664
|
+
break;
|
|
665
|
+
|
|
666
|
+
case 'potential_closure_leak':
|
|
667
|
+
optimizations.push({
|
|
668
|
+
type: 'cleanup_references',
|
|
669
|
+
description: 'Clear references when no longer needed',
|
|
670
|
+
code: `${issue.variableName} = null; // Clear reference`,
|
|
671
|
+
improvement: 'Allows garbage collection',
|
|
672
|
+
});
|
|
673
|
+
break;
|
|
674
|
+
|
|
675
|
+
case 'unnecessary_copy':
|
|
676
|
+
optimizations.push({
|
|
677
|
+
type: 'avoid_copy',
|
|
678
|
+
description: 'Use original array if not modifying',
|
|
679
|
+
improvement: 'Saves memory and copying time',
|
|
680
|
+
});
|
|
681
|
+
break;
|
|
682
|
+
|
|
683
|
+
case 'concat_in_loop':
|
|
684
|
+
optimizations.push({
|
|
685
|
+
type: 'use_push_spread',
|
|
686
|
+
description: 'Use push with spread operator',
|
|
687
|
+
code: 'result.push(...newItems);',
|
|
688
|
+
improvement: 'Modifies array in place',
|
|
689
|
+
});
|
|
690
|
+
break;
|
|
691
|
+
}
|
|
692
|
+
|
|
693
|
+
return {
|
|
694
|
+
optimizations,
|
|
695
|
+
estimatedMemorySaving: this.estimateMemorySaving(issue),
|
|
696
|
+
};
|
|
697
|
+
}
|
|
698
|
+
|
|
699
|
+
async detectAsyncIssues(ast, content) {
|
|
700
|
+
const issues = [];
|
|
701
|
+
|
|
702
|
+
traverse(ast, {
|
|
703
|
+
AwaitExpression(path) {
|
|
704
|
+
// Check for sequential awaits that could be parallelized
|
|
705
|
+
const parent = path.getFunctionParent();
|
|
706
|
+
if (!parent) return;
|
|
707
|
+
|
|
708
|
+
const awaits = [];
|
|
709
|
+
parent.traverse({
|
|
710
|
+
AwaitExpression(innerPath) {
|
|
711
|
+
awaits.push(innerPath);
|
|
712
|
+
},
|
|
713
|
+
});
|
|
714
|
+
|
|
715
|
+
// Check for sequential independent awaits
|
|
716
|
+
if (awaits.length > 1) {
|
|
717
|
+
const sequentialAwaits = this.findSequentialAwaits(awaits);
|
|
718
|
+
if (sequentialAwaits.length > 1) {
|
|
719
|
+
issues.push({
|
|
720
|
+
type: 'sequential_awaits',
|
|
721
|
+
count: sequentialAwaits.length,
|
|
722
|
+
location: parent.node.loc,
|
|
723
|
+
description: 'Sequential awaits could be parallelized',
|
|
724
|
+
});
|
|
725
|
+
}
|
|
726
|
+
}
|
|
727
|
+
},
|
|
728
|
+
CallExpression(path) {
|
|
729
|
+
// Check for Promise anti-patterns
|
|
730
|
+
if (t.isMemberExpression(path.node.callee)) {
|
|
731
|
+
const property = path.node.callee.property;
|
|
732
|
+
|
|
733
|
+
if (t.isIdentifier(property, { name: 'forEach' })) {
|
|
734
|
+
// Check if forEach contains async operations
|
|
735
|
+
const callback = path.node.arguments[0];
|
|
736
|
+
if (t.isArrowFunctionExpression(callback) && callback.async) {
|
|
737
|
+
issues.push({
|
|
738
|
+
type: 'async_foreach',
|
|
739
|
+
location: path.node.loc,
|
|
740
|
+
description: 'forEach does not wait for async operations',
|
|
741
|
+
});
|
|
742
|
+
}
|
|
743
|
+
}
|
|
744
|
+
}
|
|
745
|
+
|
|
746
|
+
// Check for Promise constructor anti-pattern
|
|
747
|
+
if (t.isNewExpression(path.node) &&
|
|
748
|
+
t.isIdentifier(path.node.callee, { name: 'Promise' })) {
|
|
749
|
+
const executor = path.node.arguments[0];
|
|
750
|
+
if (t.isFunctionExpression(executor) || t.isArrowFunctionExpression(executor)) {
|
|
751
|
+
let hasAsyncOperation = false;
|
|
752
|
+
|
|
753
|
+
path.traverse({
|
|
754
|
+
AwaitExpression() {
|
|
755
|
+
hasAsyncOperation = true;
|
|
756
|
+
},
|
|
757
|
+
});
|
|
758
|
+
|
|
759
|
+
if (hasAsyncOperation) {
|
|
760
|
+
issues.push({
|
|
761
|
+
type: 'promise_constructor_antipattern',
|
|
762
|
+
location: path.node.loc,
|
|
763
|
+
description: 'Avoid using async/await in Promise constructor',
|
|
764
|
+
});
|
|
765
|
+
}
|
|
766
|
+
}
|
|
767
|
+
}
|
|
768
|
+
},
|
|
769
|
+
});
|
|
770
|
+
|
|
771
|
+
return issues;
|
|
772
|
+
}
|
|
773
|
+
|
|
774
|
+
findSequentialAwaits(awaits) {
|
|
775
|
+
// Simplified check - would need data flow analysis for accuracy
|
|
776
|
+
const sequential = [];
|
|
777
|
+
|
|
778
|
+
for (let i = 0; i < awaits.length - 1; i++) {
|
|
779
|
+
const current = awaits[i];
|
|
780
|
+
const next = awaits[i + 1];
|
|
781
|
+
|
|
782
|
+
// Check if they're in the same block and sequential
|
|
783
|
+
if (current.parent === next.parent) {
|
|
784
|
+
sequential.push(current);
|
|
785
|
+
if (i === awaits.length - 2) {
|
|
786
|
+
sequential.push(next);
|
|
787
|
+
}
|
|
788
|
+
}
|
|
789
|
+
}
|
|
790
|
+
|
|
791
|
+
return sequential;
|
|
792
|
+
}
|
|
793
|
+
|
|
794
|
+
async suggestAsyncOptimizations(issue) {
|
|
795
|
+
const optimizations = [];
|
|
796
|
+
|
|
797
|
+
switch (issue.type) {
|
|
798
|
+
case 'sequential_awaits':
|
|
799
|
+
optimizations.push({
|
|
800
|
+
type: 'parallel_execution',
|
|
801
|
+
description: 'Use Promise.all for parallel execution',
|
|
802
|
+
code: 'const [result1, result2] = await Promise.all([\n asyncOperation1(),\n asyncOperation2()\n]);',
|
|
803
|
+
improvement: `Execute ${issue.count} operations in parallel`,
|
|
804
|
+
});
|
|
805
|
+
break;
|
|
806
|
+
|
|
807
|
+
case 'async_foreach':
|
|
808
|
+
optimizations.push({
|
|
809
|
+
type: 'use_for_of',
|
|
810
|
+
description: 'Use for...of loop for sequential async operations',
|
|
811
|
+
code: 'for (const item of items) {\n await processItem(item);\n}',
|
|
812
|
+
});
|
|
813
|
+
optimizations.push({
|
|
814
|
+
type: 'use_promise_all',
|
|
815
|
+
description: 'Use Promise.all for parallel async operations',
|
|
816
|
+
code: 'await Promise.all(items.map(item => processItem(item)));',
|
|
817
|
+
});
|
|
818
|
+
break;
|
|
819
|
+
|
|
820
|
+
case 'promise_constructor_antipattern':
|
|
821
|
+
optimizations.push({
|
|
822
|
+
type: 'use_async_function',
|
|
823
|
+
description: 'Use async function instead of Promise constructor',
|
|
824
|
+
code: 'async function operation() {\n const result = await asyncCall();\n return result;\n}',
|
|
825
|
+
});
|
|
826
|
+
break;
|
|
827
|
+
}
|
|
828
|
+
|
|
829
|
+
return {
|
|
830
|
+
optimizations,
|
|
831
|
+
priority: issue.type === 'sequential_awaits' ? 'high' : 'medium',
|
|
832
|
+
};
|
|
833
|
+
}
|
|
834
|
+
|
|
835
|
+
async detectCachingOpportunities(ast, content) {
|
|
836
|
+
const issues = [];
|
|
837
|
+
const functionCalls = new Map();
|
|
838
|
+
|
|
839
|
+
traverse(ast, {
|
|
840
|
+
CallExpression(path) {
|
|
841
|
+
// Track repeated function calls
|
|
842
|
+
const callSignature = this.getFunctionCallSignature(path.node);
|
|
843
|
+
if (callSignature) {
|
|
844
|
+
if (!functionCalls.has(callSignature)) {
|
|
845
|
+
functionCalls.set(callSignature, []);
|
|
846
|
+
}
|
|
847
|
+
functionCalls.get(callSignature).push(path);
|
|
848
|
+
}
|
|
849
|
+
|
|
850
|
+
// Check for expensive operations without caching
|
|
851
|
+
if (t.isMemberExpression(path.node.callee)) {
|
|
852
|
+
const property = path.node.callee.property;
|
|
853
|
+
|
|
854
|
+
if (t.isIdentifier(property)) {
|
|
855
|
+
// Check for repeated expensive operations
|
|
856
|
+
if (['filter', 'map', 'reduce', 'sort'].includes(property.name)) {
|
|
857
|
+
const parent = path.getFunctionParent();
|
|
858
|
+
if (parent) {
|
|
859
|
+
// Count similar operations in same function
|
|
860
|
+
let count = 0;
|
|
861
|
+
parent.traverse({
|
|
862
|
+
CallExpression(innerPath) {
|
|
863
|
+
if (this.isSimilarCall(path.node, innerPath.node)) {
|
|
864
|
+
count++;
|
|
865
|
+
}
|
|
866
|
+
},
|
|
867
|
+
});
|
|
868
|
+
|
|
869
|
+
if (count > 1) {
|
|
870
|
+
issues.push({
|
|
871
|
+
type: 'repeated_computation',
|
|
872
|
+
operation: property.name,
|
|
873
|
+
count,
|
|
874
|
+
location: path.node.loc,
|
|
875
|
+
description: `${property.name} called ${count} times with similar data`,
|
|
876
|
+
});
|
|
877
|
+
}
|
|
878
|
+
}
|
|
879
|
+
}
|
|
880
|
+
}
|
|
881
|
+
}
|
|
882
|
+
},
|
|
883
|
+
FunctionDeclaration(path) {
|
|
884
|
+
// Check for pure functions that could benefit from memoization
|
|
885
|
+
if (this.isPureFunction(path)) {
|
|
886
|
+
const complexity = this.calculateComplexity(path.node);
|
|
887
|
+
if (complexity > 5) {
|
|
888
|
+
issues.push({
|
|
889
|
+
type: 'memoization_candidate',
|
|
890
|
+
functionName: path.node.id?.name,
|
|
891
|
+
complexity,
|
|
892
|
+
location: path.node.loc,
|
|
893
|
+
description: 'Pure function with high complexity could benefit from memoization',
|
|
894
|
+
});
|
|
895
|
+
}
|
|
896
|
+
}
|
|
897
|
+
},
|
|
898
|
+
});
|
|
899
|
+
|
|
900
|
+
// Check for repeated function calls
|
|
901
|
+
for (const [signature, calls] of functionCalls) {
|
|
902
|
+
if (calls.length > 2) {
|
|
903
|
+
issues.push({
|
|
904
|
+
type: 'repeated_calls',
|
|
905
|
+
signature,
|
|
906
|
+
count: calls.length,
|
|
907
|
+
location: calls[0].node.loc,
|
|
908
|
+
description: `Function called ${calls.length} times with same signature`,
|
|
909
|
+
});
|
|
910
|
+
}
|
|
911
|
+
}
|
|
912
|
+
|
|
913
|
+
return issues;
|
|
914
|
+
}
|
|
915
|
+
|
|
916
|
+
getFunctionCallSignature(node) {
|
|
917
|
+
if (t.isIdentifier(node.callee)) {
|
|
918
|
+
return node.callee.name;
|
|
919
|
+
} else if (t.isMemberExpression(node.callee)) {
|
|
920
|
+
const object = node.callee.object;
|
|
921
|
+
const property = node.callee.property;
|
|
922
|
+
|
|
923
|
+
if (t.isIdentifier(object) && t.isIdentifier(property)) {
|
|
924
|
+
return `${object.name}.${property.name}`;
|
|
925
|
+
}
|
|
926
|
+
}
|
|
927
|
+
return null;
|
|
928
|
+
}
|
|
929
|
+
|
|
930
|
+
isSimilarCall(call1, call2) {
|
|
931
|
+
// Simplified comparison
|
|
932
|
+
return this.getFunctionCallSignature(call1) === this.getFunctionCallSignature(call2);
|
|
933
|
+
}
|
|
934
|
+
|
|
935
|
+
isPureFunction(path) {
|
|
936
|
+
const isPure = true;
|
|
937
|
+
let hasSideEffects = false;
|
|
938
|
+
|
|
939
|
+
path.traverse({
|
|
940
|
+
AssignmentExpression(innerPath) {
|
|
941
|
+
// Check if assignment is to external variable
|
|
942
|
+
if (t.isIdentifier(innerPath.node.left)) {
|
|
943
|
+
const binding = innerPath.scope.getBinding(innerPath.node.left.name);
|
|
944
|
+
if (!binding || binding.scope !== path.scope) {
|
|
945
|
+
hasSideEffects = true;
|
|
946
|
+
}
|
|
947
|
+
}
|
|
948
|
+
},
|
|
949
|
+
CallExpression(innerPath) {
|
|
950
|
+
// Check for console.log, DOM manipulation, etc.
|
|
951
|
+
const callee = innerPath.node.callee;
|
|
952
|
+
if (t.isMemberExpression(callee)) {
|
|
953
|
+
const object = callee.object;
|
|
954
|
+
if (t.isIdentifier(object) &&
|
|
955
|
+
['console', 'document', 'window'].includes(object.name)) {
|
|
956
|
+
hasSideEffects = true;
|
|
957
|
+
}
|
|
958
|
+
}
|
|
959
|
+
},
|
|
960
|
+
UpdateExpression() {
|
|
961
|
+
hasSideEffects = true;
|
|
962
|
+
},
|
|
963
|
+
});
|
|
964
|
+
|
|
965
|
+
return !hasSideEffects;
|
|
966
|
+
}
|
|
967
|
+
|
|
968
|
+
calculateComplexity(node) {
|
|
969
|
+
let complexity = 1;
|
|
970
|
+
|
|
971
|
+
traverse(node, {
|
|
972
|
+
'IfStatement|ConditionalExpression|SwitchCase': {
|
|
973
|
+
enter() {
|
|
974
|
+
complexity++;
|
|
975
|
+
},
|
|
976
|
+
},
|
|
977
|
+
'ForStatement|WhileStatement|DoWhileStatement': {
|
|
978
|
+
enter() {
|
|
979
|
+
complexity += 2;
|
|
980
|
+
},
|
|
981
|
+
},
|
|
982
|
+
CallExpression() {
|
|
983
|
+
complexity++;
|
|
984
|
+
},
|
|
985
|
+
}, null, { noScope: true });
|
|
986
|
+
|
|
987
|
+
return complexity;
|
|
988
|
+
}
|
|
989
|
+
|
|
990
|
+
async suggestCachingStrategies(issue) {
|
|
991
|
+
const strategies = [];
|
|
992
|
+
|
|
993
|
+
switch (issue.type) {
|
|
994
|
+
case 'repeated_computation':
|
|
995
|
+
strategies.push({
|
|
996
|
+
type: 'cache_result',
|
|
997
|
+
description: 'Cache computation result',
|
|
998
|
+
code: `const cached${issue.operation} = data.${issue.operation}(...);\n// Use cached result instead of recomputing`,
|
|
999
|
+
improvement: `Avoid ${issue.count - 1} redundant computations`,
|
|
1000
|
+
});
|
|
1001
|
+
break;
|
|
1002
|
+
|
|
1003
|
+
case 'memoization_candidate':
|
|
1004
|
+
strategies.push({
|
|
1005
|
+
type: 'add_memoization',
|
|
1006
|
+
description: 'Add memoization to function',
|
|
1007
|
+
code: `const memoized${issue.functionName} = memoize(${issue.functionName});`,
|
|
1008
|
+
improvement: 'Cache results for repeated calls with same arguments',
|
|
1009
|
+
});
|
|
1010
|
+
break;
|
|
1011
|
+
|
|
1012
|
+
case 'repeated_calls':
|
|
1013
|
+
strategies.push({
|
|
1014
|
+
type: 'cache_calls',
|
|
1015
|
+
description: 'Cache function call results',
|
|
1016
|
+
code: 'const cache = new Map();\nfunction getCached(key) {\n if (!cache.has(key)) {\n cache.set(key, expensiveOperation(key));\n }\n return cache.get(key);\n}',
|
|
1017
|
+
improvement: `Reduce ${issue.count} calls to 1 + cache lookups`,
|
|
1018
|
+
});
|
|
1019
|
+
break;
|
|
1020
|
+
}
|
|
1021
|
+
|
|
1022
|
+
return {
|
|
1023
|
+
strategies,
|
|
1024
|
+
estimatedImprovement: this.estimateCachingImprovement(issue),
|
|
1025
|
+
};
|
|
1026
|
+
}
|
|
1027
|
+
|
|
1028
|
+
async detectDatabaseIssues(ast, content) {
|
|
1029
|
+
const issues = [];
|
|
1030
|
+
|
|
1031
|
+
traverse(ast, {
|
|
1032
|
+
CallExpression(path) {
|
|
1033
|
+
// Look for database query patterns
|
|
1034
|
+
const callee = path.node.callee;
|
|
1035
|
+
|
|
1036
|
+
// Check for ORM/database methods
|
|
1037
|
+
if (t.isMemberExpression(callee)) {
|
|
1038
|
+
const property = callee.property;
|
|
1039
|
+
|
|
1040
|
+
if (t.isIdentifier(property)) {
|
|
1041
|
+
// Check for N+1 query patterns
|
|
1042
|
+
if (['find', 'findOne', 'findById', 'query', 'get'].includes(property.name)) {
|
|
1043
|
+
const inLoop = path.findParent(p =>
|
|
1044
|
+
p.isForStatement() || p.isWhileStatement() ||
|
|
1045
|
+
p.isDoWhileStatement() ||
|
|
1046
|
+
(p.isCallExpression() && t.isMemberExpression(p.node.callee) &&
|
|
1047
|
+
['forEach', 'map', 'filter'].includes(p.node.callee.property?.name)),
|
|
1048
|
+
);
|
|
1049
|
+
|
|
1050
|
+
if (inLoop) {
|
|
1051
|
+
issues.push({
|
|
1052
|
+
type: 'n_plus_one',
|
|
1053
|
+
method: property.name,
|
|
1054
|
+
location: path.node.loc,
|
|
1055
|
+
description: 'Database query inside loop (N+1 problem)',
|
|
1056
|
+
});
|
|
1057
|
+
}
|
|
1058
|
+
}
|
|
1059
|
+
|
|
1060
|
+
// Check for missing indexes
|
|
1061
|
+
if (property.name === 'find' || property.name === 'findOne') {
|
|
1062
|
+
const args = path.node.arguments;
|
|
1063
|
+
if (args.length > 0 && t.isObjectExpression(args[0])) {
|
|
1064
|
+
const fields = args[0].properties.map(p =>
|
|
1065
|
+
t.isIdentifier(p.key) ? p.key.name : null,
|
|
1066
|
+
).filter(Boolean);
|
|
1067
|
+
|
|
1068
|
+
if (fields.length > 0) {
|
|
1069
|
+
issues.push({
|
|
1070
|
+
type: 'potential_missing_index',
|
|
1071
|
+
fields,
|
|
1072
|
+
location: path.node.loc,
|
|
1073
|
+
description: `Query on fields: ${fields.join(', ')}`,
|
|
1074
|
+
});
|
|
1075
|
+
}
|
|
1076
|
+
}
|
|
1077
|
+
}
|
|
1078
|
+
}
|
|
1079
|
+
}
|
|
1080
|
+
|
|
1081
|
+
// Check for inefficient query patterns
|
|
1082
|
+
if (t.isIdentifier(callee) || t.isMemberExpression(callee)) {
|
|
1083
|
+
// Look for multiple sequential queries
|
|
1084
|
+
const parent = path.getFunctionParent();
|
|
1085
|
+
if (parent) {
|
|
1086
|
+
const queries = [];
|
|
1087
|
+
parent.traverse({
|
|
1088
|
+
CallExpression(innerPath) {
|
|
1089
|
+
if (this.isDatabaseQuery(innerPath.node)) {
|
|
1090
|
+
queries.push(innerPath);
|
|
1091
|
+
}
|
|
1092
|
+
},
|
|
1093
|
+
});
|
|
1094
|
+
|
|
1095
|
+
if (queries.length > 3) {
|
|
1096
|
+
issues.push({
|
|
1097
|
+
type: 'multiple_queries',
|
|
1098
|
+
count: queries.length,
|
|
1099
|
+
location: parent.node.loc,
|
|
1100
|
+
description: `${queries.length} database queries in single function`,
|
|
1101
|
+
});
|
|
1102
|
+
}
|
|
1103
|
+
}
|
|
1104
|
+
}
|
|
1105
|
+
},
|
|
1106
|
+
});
|
|
1107
|
+
|
|
1108
|
+
return issues;
|
|
1109
|
+
}
|
|
1110
|
+
|
|
1111
|
+
isDatabaseQuery(node) {
|
|
1112
|
+
// Simplified check - would need to identify actual database libraries
|
|
1113
|
+
if (t.isMemberExpression(node.callee)) {
|
|
1114
|
+
const property = node.callee.property;
|
|
1115
|
+
if (t.isIdentifier(property)) {
|
|
1116
|
+
return ['find', 'findOne', 'findById', 'query', 'select', 'insert', 'update', 'delete']
|
|
1117
|
+
.includes(property.name);
|
|
1118
|
+
}
|
|
1119
|
+
}
|
|
1120
|
+
return false;
|
|
1121
|
+
}
|
|
1122
|
+
|
|
1123
|
+
async suggestDatabaseOptimizations(issue) {
|
|
1124
|
+
const optimizations = [];
|
|
1125
|
+
|
|
1126
|
+
switch (issue.type) {
|
|
1127
|
+
case 'n_plus_one':
|
|
1128
|
+
optimizations.push({
|
|
1129
|
+
type: 'use_join',
|
|
1130
|
+
description: 'Use JOIN or populate to fetch related data',
|
|
1131
|
+
code: 'const results = await Model.find().populate(\'relatedField\');',
|
|
1132
|
+
improvement: 'Reduce N+1 queries to single query',
|
|
1133
|
+
});
|
|
1134
|
+
optimizations.push({
|
|
1135
|
+
type: 'batch_loading',
|
|
1136
|
+
description: 'Load all data upfront',
|
|
1137
|
+
code: 'const ids = items.map(item => item.id);\nconst related = await RelatedModel.find({ id: { $in: ids } });',
|
|
1138
|
+
improvement: 'Single query instead of N queries',
|
|
1139
|
+
});
|
|
1140
|
+
break;
|
|
1141
|
+
|
|
1142
|
+
case 'potential_missing_index':
|
|
1143
|
+
optimizations.push({
|
|
1144
|
+
type: 'add_index',
|
|
1145
|
+
description: `Consider adding index on: ${issue.fields.join(', ')}`,
|
|
1146
|
+
code: `db.collection.createIndex({ ${issue.fields.map(f => `${f}: 1`).join(', ')} });`,
|
|
1147
|
+
improvement: 'Faster query execution',
|
|
1148
|
+
});
|
|
1149
|
+
break;
|
|
1150
|
+
|
|
1151
|
+
case 'multiple_queries':
|
|
1152
|
+
optimizations.push({
|
|
1153
|
+
type: 'aggregate_queries',
|
|
1154
|
+
description: 'Combine multiple queries using aggregation',
|
|
1155
|
+
improvement: `Reduce ${issue.count} queries to fewer operations`,
|
|
1156
|
+
});
|
|
1157
|
+
optimizations.push({
|
|
1158
|
+
type: 'use_transactions',
|
|
1159
|
+
description: 'Use database transactions for consistency',
|
|
1160
|
+
code: 'const session = await mongoose.startSession();\nawait session.withTransaction(async () => {\n // Multiple operations\n});',
|
|
1161
|
+
});
|
|
1162
|
+
break;
|
|
1163
|
+
}
|
|
1164
|
+
|
|
1165
|
+
return {
|
|
1166
|
+
optimizations,
|
|
1167
|
+
priority: issue.type === 'n_plus_one' ? 'critical' : 'high',
|
|
1168
|
+
};
|
|
1169
|
+
}
|
|
1170
|
+
|
|
1171
|
+
async detectBundleSizeIssues(ast, content) {
|
|
1172
|
+
const issues = [];
|
|
1173
|
+
const imports = new Map();
|
|
1174
|
+
|
|
1175
|
+
traverse(ast, {
|
|
1176
|
+
ImportDeclaration(path) {
|
|
1177
|
+
const source = path.node.source.value;
|
|
1178
|
+
|
|
1179
|
+
// Track imports
|
|
1180
|
+
if (!imports.has(source)) {
|
|
1181
|
+
imports.set(source, []);
|
|
1182
|
+
}
|
|
1183
|
+
|
|
1184
|
+
// Check for large library imports
|
|
1185
|
+
if (this.isLargeLibrary(source)) {
|
|
1186
|
+
const specifiers = path.node.specifiers;
|
|
1187
|
+
|
|
1188
|
+
if (specifiers.some(s => t.isImportNamespaceSpecifier(s))) {
|
|
1189
|
+
issues.push({
|
|
1190
|
+
type: 'namespace_import',
|
|
1191
|
+
library: source,
|
|
1192
|
+
location: path.node.loc,
|
|
1193
|
+
description: `Importing entire ${source} library`,
|
|
1194
|
+
});
|
|
1195
|
+
} else if (specifiers.some(s => t.isImportDefaultSpecifier(s))) {
|
|
1196
|
+
issues.push({
|
|
1197
|
+
type: 'default_import',
|
|
1198
|
+
library: source,
|
|
1199
|
+
location: path.node.loc,
|
|
1200
|
+
description: `Default import from ${source} may include unnecessary code`,
|
|
1201
|
+
});
|
|
1202
|
+
}
|
|
1203
|
+
}
|
|
1204
|
+
|
|
1205
|
+
// Check for duplicate imports
|
|
1206
|
+
imports.get(source).push(path.node);
|
|
1207
|
+
},
|
|
1208
|
+
CallExpression(path) {
|
|
1209
|
+
// Check for dynamic imports
|
|
1210
|
+
if (t.isImport(path.node.callee)) {
|
|
1211
|
+
issues.push({
|
|
1212
|
+
type: 'dynamic_import',
|
|
1213
|
+
location: path.node.loc,
|
|
1214
|
+
description: 'Dynamic import found - ensure it\'s necessary',
|
|
1215
|
+
});
|
|
1216
|
+
}
|
|
1217
|
+
|
|
1218
|
+
// Check for require() in browser code
|
|
1219
|
+
if (t.isIdentifier(path.node.callee, { name: 'require' })) {
|
|
1220
|
+
issues.push({
|
|
1221
|
+
type: 'commonjs_require',
|
|
1222
|
+
location: path.node.loc,
|
|
1223
|
+
description: 'CommonJS require may not tree-shake well',
|
|
1224
|
+
});
|
|
1225
|
+
}
|
|
1226
|
+
},
|
|
1227
|
+
});
|
|
1228
|
+
|
|
1229
|
+
// Check for duplicate imports
|
|
1230
|
+
for (const [source, importNodes] of imports) {
|
|
1231
|
+
if (importNodes.length > 1) {
|
|
1232
|
+
issues.push({
|
|
1233
|
+
type: 'duplicate_imports',
|
|
1234
|
+
source,
|
|
1235
|
+
count: importNodes.length,
|
|
1236
|
+
description: `${source} imported ${importNodes.length} times`,
|
|
1237
|
+
});
|
|
1238
|
+
}
|
|
1239
|
+
}
|
|
1240
|
+
|
|
1241
|
+
return issues;
|
|
1242
|
+
}
|
|
1243
|
+
|
|
1244
|
+
isLargeLibrary(source) {
|
|
1245
|
+
const largeLibraries = [
|
|
1246
|
+
'lodash',
|
|
1247
|
+
'moment',
|
|
1248
|
+
'rxjs',
|
|
1249
|
+
'd3',
|
|
1250
|
+
'three',
|
|
1251
|
+
'antd',
|
|
1252
|
+
'material-ui',
|
|
1253
|
+
'@material-ui/core',
|
|
1254
|
+
];
|
|
1255
|
+
|
|
1256
|
+
return largeLibraries.some(lib => source.includes(lib));
|
|
1257
|
+
}
|
|
1258
|
+
|
|
1259
|
+
async suggestBundleOptimizations(issue) {
|
|
1260
|
+
const optimizations = [];
|
|
1261
|
+
|
|
1262
|
+
switch (issue.type) {
|
|
1263
|
+
case 'namespace_import':
|
|
1264
|
+
optimizations.push({
|
|
1265
|
+
type: 'named_imports',
|
|
1266
|
+
description: 'Use named imports instead of namespace import',
|
|
1267
|
+
code: `import { specificFunction } from '${issue.library}';`,
|
|
1268
|
+
improvement: 'Enable tree-shaking to reduce bundle size',
|
|
1269
|
+
});
|
|
1270
|
+
break;
|
|
1271
|
+
|
|
1272
|
+
case 'default_import':
|
|
1273
|
+
if (issue.library.includes('lodash')) {
|
|
1274
|
+
optimizations.push({
|
|
1275
|
+
type: 'modular_import',
|
|
1276
|
+
description: 'Import specific lodash modules',
|
|
1277
|
+
code: 'import debounce from \'lodash/debounce\';',
|
|
1278
|
+
improvement: 'Import only what you need',
|
|
1279
|
+
});
|
|
1280
|
+
}
|
|
1281
|
+
break;
|
|
1282
|
+
|
|
1283
|
+
case 'duplicate_imports':
|
|
1284
|
+
optimizations.push({
|
|
1285
|
+
type: 'consolidate_imports',
|
|
1286
|
+
description: 'Combine duplicate imports',
|
|
1287
|
+
code: `import { func1, func2, func3 } from '${issue.source}';`,
|
|
1288
|
+
improvement: 'Cleaner code and potential optimization',
|
|
1289
|
+
});
|
|
1290
|
+
break;
|
|
1291
|
+
|
|
1292
|
+
case 'commonjs_require':
|
|
1293
|
+
optimizations.push({
|
|
1294
|
+
type: 'use_esm',
|
|
1295
|
+
description: 'Use ES modules for better tree-shaking',
|
|
1296
|
+
code: 'import module from \'module-name\';',
|
|
1297
|
+
improvement: 'Better optimization and tree-shaking',
|
|
1298
|
+
});
|
|
1299
|
+
break;
|
|
1300
|
+
}
|
|
1301
|
+
|
|
1302
|
+
return {
|
|
1303
|
+
optimizations,
|
|
1304
|
+
estimatedSizeReduction: this.estimateBundleSizeReduction(issue),
|
|
1305
|
+
};
|
|
1306
|
+
}
|
|
1307
|
+
|
|
1308
|
+
async detectReactIssues(ast, content) {
|
|
1309
|
+
const issues = [];
|
|
1310
|
+
|
|
1311
|
+
// Only run React checks if React is imported
|
|
1312
|
+
const hasReact = content.includes('react') || content.includes('React');
|
|
1313
|
+
if (!hasReact) return issues;
|
|
1314
|
+
|
|
1315
|
+
traverse(ast, {
|
|
1316
|
+
CallExpression(path) {
|
|
1317
|
+
// Check for setState in loops
|
|
1318
|
+
if (t.isMemberExpression(path.node.callee) &&
|
|
1319
|
+
t.isThisExpression(path.node.callee.object) &&
|
|
1320
|
+
t.isIdentifier(path.node.callee.property, { name: 'setState' })) {
|
|
1321
|
+
|
|
1322
|
+
const inLoop = path.findParent(p =>
|
|
1323
|
+
p.isForStatement() || p.isWhileStatement() || p.isDoWhileStatement(),
|
|
1324
|
+
);
|
|
1325
|
+
|
|
1326
|
+
if (inLoop) {
|
|
1327
|
+
issues.push({
|
|
1328
|
+
type: 'setState_in_loop',
|
|
1329
|
+
location: path.node.loc,
|
|
1330
|
+
description: 'Multiple setState calls in loop cause unnecessary re-renders',
|
|
1331
|
+
});
|
|
1332
|
+
}
|
|
1333
|
+
}
|
|
1334
|
+
|
|
1335
|
+
// Check for missing React.memo
|
|
1336
|
+
if (t.isIdentifier(path.node.callee) || t.isMemberExpression(path.node.callee)) {
|
|
1337
|
+
const funcParent = path.getFunctionParent();
|
|
1338
|
+
if (funcParent && this.isReactComponent(funcParent)) {
|
|
1339
|
+
const componentName = this.getComponentName(funcParent);
|
|
1340
|
+
|
|
1341
|
+
// Check if component is wrapped in React.memo
|
|
1342
|
+
const hasReactMemo = funcParent.parent?.callee?.property?.name === 'memo';
|
|
1343
|
+
|
|
1344
|
+
if (!hasReactMemo && this.shouldMemoize(funcParent)) {
|
|
1345
|
+
issues.push({
|
|
1346
|
+
type: 'missing_memo',
|
|
1347
|
+
componentName,
|
|
1348
|
+
location: funcParent.node.loc,
|
|
1349
|
+
description: 'Component could benefit from React.memo',
|
|
1350
|
+
});
|
|
1351
|
+
}
|
|
1352
|
+
}
|
|
1353
|
+
}
|
|
1354
|
+
},
|
|
1355
|
+
JSXElement(path) {
|
|
1356
|
+
// Check for inline function props
|
|
1357
|
+
const openingElement = path.node.openingElement;
|
|
1358
|
+
|
|
1359
|
+
for (const attr of openingElement.attributes) {
|
|
1360
|
+
if (t.isJSXAttribute(attr) && t.isJSXExpressionContainer(attr.value)) {
|
|
1361
|
+
const expression = attr.value.expression;
|
|
1362
|
+
|
|
1363
|
+
if (t.isArrowFunctionExpression(expression) || t.isFunctionExpression(expression)) {
|
|
1364
|
+
issues.push({
|
|
1365
|
+
type: 'inline_function_prop',
|
|
1366
|
+
propName: attr.name.name,
|
|
1367
|
+
location: attr.loc,
|
|
1368
|
+
description: 'Inline function prop causes unnecessary re-renders',
|
|
1369
|
+
});
|
|
1370
|
+
}
|
|
1371
|
+
}
|
|
1372
|
+
}
|
|
1373
|
+
},
|
|
1374
|
+
});
|
|
1375
|
+
|
|
1376
|
+
return issues;
|
|
1377
|
+
}
|
|
1378
|
+
|
|
1379
|
+
isReactComponent(path) {
|
|
1380
|
+
// Check if it's a React component
|
|
1381
|
+
const node = path.node;
|
|
1382
|
+
|
|
1383
|
+
// Function component
|
|
1384
|
+
if (t.isFunctionDeclaration(node) || t.isArrowFunctionExpression(node)) {
|
|
1385
|
+
// Check if returns JSX
|
|
1386
|
+
let returnsJSX = false;
|
|
1387
|
+
|
|
1388
|
+
path.traverse({
|
|
1389
|
+
ReturnStatement(returnPath) {
|
|
1390
|
+
if (t.isJSXElement(returnPath.node.argument) ||
|
|
1391
|
+
t.isJSXFragment(returnPath.node.argument)) {
|
|
1392
|
+
returnsJSX = true;
|
|
1393
|
+
}
|
|
1394
|
+
},
|
|
1395
|
+
});
|
|
1396
|
+
|
|
1397
|
+
return returnsJSX;
|
|
1398
|
+
}
|
|
1399
|
+
|
|
1400
|
+
return false;
|
|
1401
|
+
}
|
|
1402
|
+
|
|
1403
|
+
getComponentName(path) {
|
|
1404
|
+
if (t.isFunctionDeclaration(path.node)) {
|
|
1405
|
+
return path.node.id?.name;
|
|
1406
|
+
} else if (t.isVariableDeclarator(path.parent)) {
|
|
1407
|
+
return path.parent.id?.name;
|
|
1408
|
+
}
|
|
1409
|
+
return '<Component>';
|
|
1410
|
+
}
|
|
1411
|
+
|
|
1412
|
+
shouldMemoize(componentPath) {
|
|
1413
|
+
// Simple heuristic - component with props and no side effects
|
|
1414
|
+
let hasProps = false;
|
|
1415
|
+
let hasSideEffects = false;
|
|
1416
|
+
|
|
1417
|
+
// Check for props parameter
|
|
1418
|
+
const params = componentPath.node.params;
|
|
1419
|
+
if (params.length > 0) {
|
|
1420
|
+
hasProps = true;
|
|
1421
|
+
}
|
|
1422
|
+
|
|
1423
|
+
// Check for side effects
|
|
1424
|
+
componentPath.traverse({
|
|
1425
|
+
CallExpression(path) {
|
|
1426
|
+
const callee = path.node.callee;
|
|
1427
|
+
if (t.isMemberExpression(callee)) {
|
|
1428
|
+
const object = callee.object;
|
|
1429
|
+
if (t.isIdentifier(object) &&
|
|
1430
|
+
['console', 'document', 'window'].includes(object.name)) {
|
|
1431
|
+
hasSideEffects = true;
|
|
1432
|
+
}
|
|
1433
|
+
}
|
|
1434
|
+
},
|
|
1435
|
+
});
|
|
1436
|
+
|
|
1437
|
+
return hasProps && !hasSideEffects;
|
|
1438
|
+
}
|
|
1439
|
+
|
|
1440
|
+
async suggestReactOptimizations(issue) {
|
|
1441
|
+
const optimizations = [];
|
|
1442
|
+
|
|
1443
|
+
switch (issue.type) {
|
|
1444
|
+
case 'setState_in_loop':
|
|
1445
|
+
optimizations.push({
|
|
1446
|
+
type: 'batch_state_updates',
|
|
1447
|
+
description: 'Batch state updates outside loop',
|
|
1448
|
+
code: 'const updates = [];\nfor (...) {\n updates.push(...);\n}\nthis.setState({ items: updates });',
|
|
1449
|
+
improvement: 'Single re-render instead of multiple',
|
|
1450
|
+
});
|
|
1451
|
+
break;
|
|
1452
|
+
|
|
1453
|
+
case 'missing_memo':
|
|
1454
|
+
optimizations.push({
|
|
1455
|
+
type: 'add_react_memo',
|
|
1456
|
+
description: 'Wrap component in React.memo',
|
|
1457
|
+
code: `const ${issue.componentName} = React.memo(function ${issue.componentName}(props) {\n // component code\n});`,
|
|
1458
|
+
improvement: 'Prevent unnecessary re-renders',
|
|
1459
|
+
});
|
|
1460
|
+
break;
|
|
1461
|
+
|
|
1462
|
+
case 'inline_function_prop':
|
|
1463
|
+
optimizations.push({
|
|
1464
|
+
type: 'use_callback',
|
|
1465
|
+
description: 'Use useCallback for function props',
|
|
1466
|
+
code: `const handle${issue.propName} = useCallback(() => {\n // handler code\n}, [dependencies]);`,
|
|
1467
|
+
improvement: 'Stable function reference',
|
|
1468
|
+
});
|
|
1469
|
+
break;
|
|
1470
|
+
}
|
|
1471
|
+
|
|
1472
|
+
return {
|
|
1473
|
+
optimizations,
|
|
1474
|
+
priority: 'medium',
|
|
1475
|
+
};
|
|
1476
|
+
}
|
|
1477
|
+
|
|
1478
|
+
async detectStringIssues(ast, content) {
|
|
1479
|
+
const issues = [];
|
|
1480
|
+
|
|
1481
|
+
traverse(ast, {
|
|
1482
|
+
BinaryExpression(path) {
|
|
1483
|
+
// Check for string concatenation in loops
|
|
1484
|
+
if (path.node.operator === '+') {
|
|
1485
|
+
const inLoop = path.findParent(p =>
|
|
1486
|
+
p.isForStatement() || p.isWhileStatement() || p.isDoWhileStatement(),
|
|
1487
|
+
);
|
|
1488
|
+
|
|
1489
|
+
if (inLoop && (t.isStringLiteral(path.node.left) || t.isStringLiteral(path.node.right))) {
|
|
1490
|
+
issues.push({
|
|
1491
|
+
type: 'string_concat_in_loop',
|
|
1492
|
+
location: path.node.loc,
|
|
1493
|
+
description: 'String concatenation in loop is inefficient',
|
|
1494
|
+
});
|
|
1495
|
+
}
|
|
1496
|
+
}
|
|
1497
|
+
},
|
|
1498
|
+
CallExpression(path) {
|
|
1499
|
+
if (t.isMemberExpression(path.node.callee)) {
|
|
1500
|
+
const property = path.node.callee.property;
|
|
1501
|
+
|
|
1502
|
+
if (t.isIdentifier(property)) {
|
|
1503
|
+
// Check for repeated string operations
|
|
1504
|
+
if (['split', 'replace', 'substring', 'substr'].includes(property.name)) {
|
|
1505
|
+
const parent = path.getFunctionParent();
|
|
1506
|
+
if (parent) {
|
|
1507
|
+
// Count similar operations
|
|
1508
|
+
let count = 0;
|
|
1509
|
+
parent.traverse({
|
|
1510
|
+
CallExpression(innerPath) {
|
|
1511
|
+
if (t.isMemberExpression(innerPath.node.callee) &&
|
|
1512
|
+
innerPath.node.callee.property?.name === property.name) {
|
|
1513
|
+
count++;
|
|
1514
|
+
}
|
|
1515
|
+
},
|
|
1516
|
+
});
|
|
1517
|
+
|
|
1518
|
+
if (count > 2) {
|
|
1519
|
+
issues.push({
|
|
1520
|
+
type: 'repeated_string_operation',
|
|
1521
|
+
operation: property.name,
|
|
1522
|
+
count,
|
|
1523
|
+
location: path.node.loc,
|
|
1524
|
+
description: `${property.name} called ${count} times`,
|
|
1525
|
+
});
|
|
1526
|
+
}
|
|
1527
|
+
}
|
|
1528
|
+
}
|
|
1529
|
+
}
|
|
1530
|
+
}
|
|
1531
|
+
},
|
|
1532
|
+
});
|
|
1533
|
+
|
|
1534
|
+
return issues;
|
|
1535
|
+
}
|
|
1536
|
+
|
|
1537
|
+
async suggestStringOptimizations(issue) {
|
|
1538
|
+
const optimizations = [];
|
|
1539
|
+
|
|
1540
|
+
switch (issue.type) {
|
|
1541
|
+
case 'string_concat_in_loop':
|
|
1542
|
+
optimizations.push({
|
|
1543
|
+
type: 'use_array_join',
|
|
1544
|
+
description: 'Use array and join for string building',
|
|
1545
|
+
code: 'const parts = [];\nfor (...) {\n parts.push(stringPart);\n}\nconst result = parts.join(\'\');',
|
|
1546
|
+
improvement: 'More efficient string concatenation',
|
|
1547
|
+
});
|
|
1548
|
+
break;
|
|
1549
|
+
|
|
1550
|
+
case 'repeated_string_operation':
|
|
1551
|
+
optimizations.push({
|
|
1552
|
+
type: 'cache_result',
|
|
1553
|
+
description: `Cache ${issue.operation} result`,
|
|
1554
|
+
code: `const processed = str.${issue.operation}(...);\n// Reuse processed instead of calling again`,
|
|
1555
|
+
improvement: `Avoid ${issue.count - 1} redundant operations`,
|
|
1556
|
+
});
|
|
1557
|
+
break;
|
|
1558
|
+
}
|
|
1559
|
+
|
|
1560
|
+
return {
|
|
1561
|
+
optimizations,
|
|
1562
|
+
priority: 'low',
|
|
1563
|
+
};
|
|
1564
|
+
}
|
|
1565
|
+
|
|
1566
|
+
async detectObjectIssues(ast, content) {
|
|
1567
|
+
const issues = [];
|
|
1568
|
+
|
|
1569
|
+
traverse(ast, {
|
|
1570
|
+
ObjectExpression(path) {
|
|
1571
|
+
// Check for large object literals
|
|
1572
|
+
if (path.node.properties.length > 50) {
|
|
1573
|
+
issues.push({
|
|
1574
|
+
type: 'large_object_literal',
|
|
1575
|
+
size: path.node.properties.length,
|
|
1576
|
+
location: path.node.loc,
|
|
1577
|
+
description: 'Large object literal may impact performance',
|
|
1578
|
+
});
|
|
1579
|
+
}
|
|
1580
|
+
},
|
|
1581
|
+
MemberExpression(path) {
|
|
1582
|
+
// Check for deep property access
|
|
1583
|
+
let depth = 0;
|
|
1584
|
+
let current = path.node;
|
|
1585
|
+
|
|
1586
|
+
while (t.isMemberExpression(current)) {
|
|
1587
|
+
depth++;
|
|
1588
|
+
current = current.object;
|
|
1589
|
+
}
|
|
1590
|
+
|
|
1591
|
+
if (depth > 3) {
|
|
1592
|
+
issues.push({
|
|
1593
|
+
type: 'deep_property_access',
|
|
1594
|
+
depth,
|
|
1595
|
+
location: path.node.loc,
|
|
1596
|
+
description: `Deep property access (${depth} levels)`,
|
|
1597
|
+
});
|
|
1598
|
+
}
|
|
1599
|
+
},
|
|
1600
|
+
CallExpression(path) {
|
|
1601
|
+
// Check for Object.keys/values/entries in loops
|
|
1602
|
+
if (t.isMemberExpression(path.node.callee)) {
|
|
1603
|
+
const object = path.node.callee.object;
|
|
1604
|
+
const property = path.node.callee.property;
|
|
1605
|
+
|
|
1606
|
+
if (t.isIdentifier(object, { name: 'Object' }) &&
|
|
1607
|
+
t.isIdentifier(property) &&
|
|
1608
|
+
['keys', 'values', 'entries'].includes(property.name)) {
|
|
1609
|
+
|
|
1610
|
+
const inLoop = path.findParent(p =>
|
|
1611
|
+
p.isForStatement() || p.isWhileStatement() || p.isDoWhileStatement(),
|
|
1612
|
+
);
|
|
1613
|
+
|
|
1614
|
+
if (inLoop) {
|
|
1615
|
+
issues.push({
|
|
1616
|
+
type: 'object_iteration_in_loop',
|
|
1617
|
+
method: property.name,
|
|
1618
|
+
location: path.node.loc,
|
|
1619
|
+
description: `Object.${property.name} in loop creates intermediate array`,
|
|
1620
|
+
});
|
|
1621
|
+
}
|
|
1622
|
+
}
|
|
1623
|
+
}
|
|
1624
|
+
},
|
|
1625
|
+
});
|
|
1626
|
+
|
|
1627
|
+
return issues;
|
|
1628
|
+
}
|
|
1629
|
+
|
|
1630
|
+
async suggestObjectOptimizations(issue) {
|
|
1631
|
+
const optimizations = [];
|
|
1632
|
+
|
|
1633
|
+
switch (issue.type) {
|
|
1634
|
+
case 'large_object_literal':
|
|
1635
|
+
optimizations.push({
|
|
1636
|
+
type: 'use_map',
|
|
1637
|
+
description: 'Consider using Map for large key-value stores',
|
|
1638
|
+
code: 'const map = new Map([\n [\'key1\', value1],\n [\'key2\', value2]\n]);',
|
|
1639
|
+
improvement: 'Better performance for frequent updates',
|
|
1640
|
+
});
|
|
1641
|
+
break;
|
|
1642
|
+
|
|
1643
|
+
case 'deep_property_access':
|
|
1644
|
+
optimizations.push({
|
|
1645
|
+
type: 'cache_reference',
|
|
1646
|
+
description: 'Cache intermediate references',
|
|
1647
|
+
code: 'const intermediate = obj.level1.level2;\nconst value = intermediate.level3.level4;',
|
|
1648
|
+
improvement: 'Reduce property lookup overhead',
|
|
1649
|
+
});
|
|
1650
|
+
optimizations.push({
|
|
1651
|
+
type: 'flatten_structure',
|
|
1652
|
+
description: 'Consider flattening data structure',
|
|
1653
|
+
improvement: 'Simpler and faster access',
|
|
1654
|
+
});
|
|
1655
|
+
break;
|
|
1656
|
+
|
|
1657
|
+
case 'object_iteration_in_loop':
|
|
1658
|
+
optimizations.push({
|
|
1659
|
+
type: 'cache_iteration',
|
|
1660
|
+
description: `Cache Object.${issue.method} result`,
|
|
1661
|
+
code: `const ${issue.method} = Object.${issue.method}(obj);\nfor (...) {\n // Use cached ${issue.method}\n}`,
|
|
1662
|
+
improvement: 'Avoid creating array multiple times',
|
|
1663
|
+
});
|
|
1664
|
+
break;
|
|
1665
|
+
}
|
|
1666
|
+
|
|
1667
|
+
return {
|
|
1668
|
+
optimizations,
|
|
1669
|
+
priority: issue.type === 'large_object_literal' ? 'medium' : 'low',
|
|
1670
|
+
};
|
|
1671
|
+
}
|
|
1672
|
+
|
|
1673
|
+
generateOptimizationExample(complexity) {
|
|
1674
|
+
if (complexity.loopDepth >= 2) {
|
|
1675
|
+
return '// Instead of nested loops O(n²):\nfor (const item1 of array1) {\n for (const item2 of array2) {\n if (item1.id === item2.id) { ... }\n }\n}\n\n// Use a Map for O(n):\nconst map = new Map(array2.map(item => [item.id, item]));\nfor (const item1 of array1) {\n const item2 = map.get(item1.id);\n if (item2) { ... }\n}';
|
|
1676
|
+
}
|
|
1677
|
+
return '';
|
|
1678
|
+
}
|
|
1679
|
+
|
|
1680
|
+
estimatePerformanceImprovement(issue) {
|
|
1681
|
+
const improvements = {
|
|
1682
|
+
high_complexity: {
|
|
1683
|
+
'O(n²)': '10-100x faster for large datasets',
|
|
1684
|
+
'O(n³)': '100-1000x faster for large datasets',
|
|
1685
|
+
'O(2^n)': 'Exponential improvement',
|
|
1686
|
+
},
|
|
1687
|
+
};
|
|
1688
|
+
|
|
1689
|
+
if (issue.type === 'high_complexity' && issue.complexity.notation) {
|
|
1690
|
+
return improvements.high_complexity[issue.complexity.notation] || 'Significant improvement';
|
|
1691
|
+
}
|
|
1692
|
+
|
|
1693
|
+
return 'Performance improvement depends on data size';
|
|
1694
|
+
}
|
|
1695
|
+
|
|
1696
|
+
estimateMemorySaving(issue) {
|
|
1697
|
+
const savings = {
|
|
1698
|
+
large_array: `~${(issue.size * 8 / 1024 / 1024).toFixed(1)}MB`,
|
|
1699
|
+
concat_in_loop: 'Reduces intermediate array allocations',
|
|
1700
|
+
unnecessary_copy: 'Saves memory equal to array size',
|
|
1701
|
+
};
|
|
1702
|
+
|
|
1703
|
+
return savings[issue.type] || 'Memory savings depend on data size';
|
|
1704
|
+
}
|
|
1705
|
+
|
|
1706
|
+
estimateCachingImprovement(issue) {
|
|
1707
|
+
if (issue.type === 'repeated_calls') {
|
|
1708
|
+
return `${((issue.count - 1) / issue.count * 100).toFixed(0)}% reduction in computation`;
|
|
1709
|
+
}
|
|
1710
|
+
return 'Significant for repeated operations';
|
|
1711
|
+
}
|
|
1712
|
+
|
|
1713
|
+
estimateBundleSizeReduction(issue) {
|
|
1714
|
+
const reductions = {
|
|
1715
|
+
namespace_import: {
|
|
1716
|
+
lodash: '~500KB to ~5KB per function',
|
|
1717
|
+
moment: '~300KB to ~50KB with date-fns',
|
|
1718
|
+
rxjs: '~200KB to ~20KB with proper imports',
|
|
1719
|
+
},
|
|
1720
|
+
default_import: {
|
|
1721
|
+
lodash: '~70KB to ~5KB per function',
|
|
1722
|
+
},
|
|
1723
|
+
};
|
|
1724
|
+
|
|
1725
|
+
if (reductions[issue.type]?.[issue.library]) {
|
|
1726
|
+
return reductions[issue.type][issue.library];
|
|
1727
|
+
}
|
|
1728
|
+
|
|
1729
|
+
return 'Size reduction depends on usage';
|
|
1730
|
+
}
|
|
1731
|
+
|
|
1732
|
+
calculatePerformanceScore(analysis) {
|
|
1733
|
+
let score = 100;
|
|
1734
|
+
|
|
1735
|
+
// Deduct points for issues based on impact
|
|
1736
|
+
for (const issue of analysis.issues) {
|
|
1737
|
+
switch (issue.impact) {
|
|
1738
|
+
case 'critical':
|
|
1739
|
+
score -= 20;
|
|
1740
|
+
break;
|
|
1741
|
+
case 'high':
|
|
1742
|
+
score -= 10;
|
|
1743
|
+
break;
|
|
1744
|
+
case 'medium':
|
|
1745
|
+
score -= 5;
|
|
1746
|
+
break;
|
|
1747
|
+
case 'low':
|
|
1748
|
+
score -= 2;
|
|
1749
|
+
break;
|
|
1750
|
+
}
|
|
1751
|
+
}
|
|
1752
|
+
|
|
1753
|
+
// Factor in static metrics
|
|
1754
|
+
const metrics = analysis.metrics.static;
|
|
1755
|
+
if (metrics) {
|
|
1756
|
+
if (metrics.complexity > 20) score -= 10;
|
|
1757
|
+
if (metrics.loopDepth > 3) score -= 15;
|
|
1758
|
+
if (metrics.fileSize > 50000) score -= 5;
|
|
1759
|
+
}
|
|
1760
|
+
|
|
1761
|
+
return Math.max(0, Math.min(100, score));
|
|
1762
|
+
}
|
|
1763
|
+
|
|
1764
|
+
isExecutable(filePath) {
|
|
1765
|
+
// Check if file is a script that can be profiled
|
|
1766
|
+
return filePath.endsWith('.js') && !filePath.includes('.test.') && !filePath.includes('.spec.');
|
|
1767
|
+
}
|
|
1768
|
+
|
|
1769
|
+
async profileRuntime(filePath) {
|
|
1770
|
+
// This would require actual runtime profiling
|
|
1771
|
+
// For now, return placeholder metrics
|
|
1772
|
+
return {
|
|
1773
|
+
executionTime: 0,
|
|
1774
|
+
memoryUsage: 0,
|
|
1775
|
+
cpuUsage: 0,
|
|
1776
|
+
};
|
|
1777
|
+
}
|
|
1778
|
+
|
|
1779
|
+
async applyOptimization(filePath, optimization) {
|
|
1780
|
+
// Apply specific optimization to file
|
|
1781
|
+
const result = {
|
|
1782
|
+
success: false,
|
|
1783
|
+
changes: [],
|
|
1784
|
+
error: null,
|
|
1785
|
+
};
|
|
1786
|
+
|
|
1787
|
+
try {
|
|
1788
|
+
const content = await fs.readFile(filePath, 'utf-8');
|
|
1789
|
+
|
|
1790
|
+
// Parse and transform based on optimization type
|
|
1791
|
+
// This would involve AST transformation
|
|
1792
|
+
|
|
1793
|
+
result.success = true;
|
|
1794
|
+
result.changes.push({
|
|
1795
|
+
type: optimization.type,
|
|
1796
|
+
description: optimization.description,
|
|
1797
|
+
});
|
|
1798
|
+
|
|
1799
|
+
this.optimizationHistory.push({
|
|
1800
|
+
filePath,
|
|
1801
|
+
optimization,
|
|
1802
|
+
timestamp: new Date().toISOString(),
|
|
1803
|
+
result,
|
|
1804
|
+
});
|
|
1805
|
+
|
|
1806
|
+
} catch (error) {
|
|
1807
|
+
result.error = error.message;
|
|
1808
|
+
}
|
|
1809
|
+
|
|
1810
|
+
return result;
|
|
1811
|
+
}
|
|
1812
|
+
|
|
1813
|
+
async generateOptimizationReport() {
|
|
1814
|
+
const report = {
|
|
1815
|
+
timestamp: new Date().toISOString(),
|
|
1816
|
+
summary: {
|
|
1817
|
+
filesAnalyzed: this.performanceMetrics.size,
|
|
1818
|
+
totalIssues: 0,
|
|
1819
|
+
criticalIssues: 0,
|
|
1820
|
+
optimizationsApplied: this.optimizationHistory.length,
|
|
1821
|
+
},
|
|
1822
|
+
byCategory: {},
|
|
1823
|
+
topIssues: [],
|
|
1824
|
+
recommendations: [],
|
|
1825
|
+
};
|
|
1826
|
+
|
|
1827
|
+
// Aggregate metrics
|
|
1828
|
+
for (const [file, metrics] of this.performanceMetrics) {
|
|
1829
|
+
report.summary.totalIssues += metrics.issues.length;
|
|
1830
|
+
report.summary.criticalIssues += metrics.issues.filter(i => i.severity === 'critical').length;
|
|
1831
|
+
|
|
1832
|
+
// Group by category
|
|
1833
|
+
for (const issue of metrics.issues) {
|
|
1834
|
+
const category = issue.category || 'other';
|
|
1835
|
+
if (!report.byCategory[category]) {
|
|
1836
|
+
report.byCategory[category] = {
|
|
1837
|
+
count: 0,
|
|
1838
|
+
issues: [],
|
|
1839
|
+
};
|
|
1840
|
+
}
|
|
1841
|
+
report.byCategory[category].count++;
|
|
1842
|
+
report.byCategory[category].issues.push({
|
|
1843
|
+
file: file.replace(this.rootPath, '.'),
|
|
1844
|
+
...issue,
|
|
1845
|
+
});
|
|
1846
|
+
}
|
|
1847
|
+
}
|
|
1848
|
+
|
|
1849
|
+
// Top issues
|
|
1850
|
+
const allIssues = [];
|
|
1851
|
+
for (const [file, metrics] of this.performanceMetrics) {
|
|
1852
|
+
allIssues.push(...metrics.issues.map(i => ({
|
|
1853
|
+
file: file.replace(this.rootPath, '.'),
|
|
1854
|
+
...i,
|
|
1855
|
+
})));
|
|
1856
|
+
}
|
|
1857
|
+
|
|
1858
|
+
report.topIssues = allIssues
|
|
1859
|
+
.sort((a, b) => {
|
|
1860
|
+
const impactScore = { critical: 3, high: 2, medium: 1, low: 0 };
|
|
1861
|
+
return (impactScore[b.impact] || 0) - (impactScore[a.impact] || 0);
|
|
1862
|
+
})
|
|
1863
|
+
.slice(0, 10);
|
|
1864
|
+
|
|
1865
|
+
// General recommendations
|
|
1866
|
+
report.recommendations = this.generateRecommendations(report);
|
|
1867
|
+
|
|
1868
|
+
return report;
|
|
1869
|
+
}
|
|
1870
|
+
|
|
1871
|
+
generateRecommendations(report) {
|
|
1872
|
+
const recommendations = [];
|
|
1873
|
+
|
|
1874
|
+
if (report.byCategory.algorithm?.count > 5) {
|
|
1875
|
+
recommendations.push({
|
|
1876
|
+
category: 'algorithm',
|
|
1877
|
+
recommendation: 'Consider algorithm optimization training for the team',
|
|
1878
|
+
priority: 'high',
|
|
1879
|
+
});
|
|
1880
|
+
}
|
|
1881
|
+
|
|
1882
|
+
if (report.byCategory.async?.count > 10) {
|
|
1883
|
+
recommendations.push({
|
|
1884
|
+
category: 'async',
|
|
1885
|
+
recommendation: 'Review async/await patterns and consider using Promise.all',
|
|
1886
|
+
priority: 'medium',
|
|
1887
|
+
});
|
|
1888
|
+
}
|
|
1889
|
+
|
|
1890
|
+
if (report.byCategory.memory?.count > 0) {
|
|
1891
|
+
recommendations.push({
|
|
1892
|
+
category: 'memory',
|
|
1893
|
+
recommendation: 'Implement memory profiling in development',
|
|
1894
|
+
priority: 'medium',
|
|
1895
|
+
});
|
|
1896
|
+
}
|
|
1897
|
+
|
|
1898
|
+
return recommendations;
|
|
1899
|
+
}
|
|
1900
|
+
}
|
|
1901
|
+
|
|
1902
|
+
module.exports = PerformanceOptimizer;
|