moai-adk 0.4.5__py3-none-any.whl → 0.20.1__py3-none-any.whl
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.
Potentially problematic release.
This version of moai-adk might be problematic. Click here for more details.
- moai_adk/__init__.py +1 -1
- moai_adk/__main__.py +74 -1
- moai_adk/cli/commands/__init__.py +1 -1
- moai_adk/cli/commands/analyze.py +119 -0
- moai_adk/cli/commands/backup.py +25 -1
- moai_adk/cli/commands/doctor.py +31 -5
- moai_adk/cli/commands/improve_user_experience.py +307 -0
- moai_adk/cli/commands/init.py +111 -10
- moai_adk/cli/commands/status.py +33 -3
- moai_adk/cli/commands/update.py +921 -130
- moai_adk/cli/commands/validate_links.py +120 -0
- moai_adk/cli/prompts/init_prompts.py +22 -87
- moai_adk/core/analysis/__init__.py +9 -0
- moai_adk/core/analysis/session_analyzer.py +388 -0
- moai_adk/core/analysis/tag_chain_analyzer.py +344 -0
- moai_adk/core/analysis/tag_chain_repair.py +879 -0
- moai_adk/core/config/__init__.py +19 -0
- moai_adk/core/config/migration.py +235 -0
- moai_adk/core/git/__init__.py +1 -1
- moai_adk/core/git/branch.py +1 -1
- moai_adk/core/git/commit.py +1 -1
- moai_adk/core/git/manager.py +1 -1
- moai_adk/core/issue_creator.py +313 -0
- moai_adk/core/mcp/setup.py +56 -0
- moai_adk/core/mcp/setup_old.py +296 -0
- moai_adk/core/project/backup_utils.py +1 -1
- moai_adk/core/project/checker.py +2 -2
- moai_adk/core/project/detector.py +211 -12
- moai_adk/core/project/initializer.py +85 -15
- moai_adk/core/project/phase_executor.py +76 -13
- moai_adk/core/project/validator.py +13 -13
- moai_adk/core/quality/__init__.py +1 -1
- moai_adk/core/quality/trust_checker.py +1 -1
- moai_adk/core/quality/validators/__init__.py +1 -1
- moai_adk/core/quality/validators/base_validator.py +1 -1
- moai_adk/core/tags/__init__.py +86 -0
- moai_adk/core/tags/auto_corrector.py +693 -0
- moai_adk/core/tags/ci_validator.py +463 -0
- moai_adk/core/tags/cli.py +283 -0
- moai_adk/core/tags/generator.py +109 -0
- moai_adk/core/tags/inserter.py +99 -0
- moai_adk/core/tags/mapper.py +126 -0
- moai_adk/core/tags/parser.py +76 -0
- moai_adk/core/tags/policy_validator.py +580 -0
- moai_adk/core/tags/pre_commit_validator.py +421 -0
- moai_adk/core/tags/reporter.py +956 -0
- moai_adk/core/tags/rollback_manager.py +525 -0
- moai_adk/core/tags/tags.py +149 -0
- moai_adk/core/tags/validator.py +897 -0
- moai_adk/core/template/__init__.py +1 -1
- moai_adk/core/template/backup.py +1 -1
- moai_adk/core/template/merger.py +50 -1
- moai_adk/core/template/processor.py +119 -13
- moai_adk/core/template_engine.py +268 -0
- moai_adk/templates/.claude/agents/alfred/backend-expert.md +348 -0
- moai_adk/templates/.claude/agents/alfred/cc-manager.md +209 -944
- moai_adk/templates/.claude/agents/alfred/database-expert.md +352 -0
- moai_adk/templates/.claude/agents/alfred/debug-helper.md +34 -5
- moai_adk/templates/.claude/agents/alfred/devops-expert.md +464 -0
- moai_adk/templates/.claude/agents/alfred/doc-syncer.md +38 -8
- moai_adk/templates/.claude/agents/alfred/format-expert.md +469 -0
- moai_adk/templates/.claude/agents/alfred/frontend-expert.md +357 -0
- moai_adk/templates/.claude/agents/alfred/git-manager.md +128 -9
- moai_adk/templates/.claude/agents/alfred/implementation-planner.md +104 -6
- moai_adk/templates/.claude/agents/alfred/project-manager.md +88 -16
- moai_adk/templates/.claude/agents/alfred/quality-gate.md +36 -9
- moai_adk/templates/.claude/agents/alfred/security-expert.md +270 -0
- moai_adk/templates/.claude/agents/alfred/skill-factory.md +865 -0
- moai_adk/templates/.claude/agents/alfred/spec-builder.md +214 -43
- moai_adk/templates/.claude/agents/alfred/tag-agent.md +111 -9
- moai_adk/templates/.claude/agents/alfred/tdd-implementer.md +309 -160
- moai_adk/templates/.claude/agents/alfred/trust-checker.md +36 -7
- moai_adk/templates/.claude/agents/alfred/ui-ux-expert.md +605 -0
- moai_adk/templates/.claude/commands/alfred/0-project.md +393 -966
- moai_adk/templates/.claude/commands/alfred/1-plan.md +651 -367
- moai_adk/templates/.claude/commands/alfred/2-run.md +388 -241
- moai_adk/templates/.claude/commands/alfred/3-sync.md +1921 -410
- moai_adk/templates/.claude/commands/alfred/9-feedback.md +153 -0
- moai_adk/templates/.claude/commands/alfred/release-new.md +3604 -0
- moai_adk/templates/.claude/hooks/alfred/core/project.py +484 -20
- moai_adk/templates/.claude/hooks/alfred/core/timeout.py +136 -0
- moai_adk/templates/.claude/hooks/alfred/core/ttl_cache.py +108 -0
- moai_adk/templates/.claude/hooks/alfred/core/version_cache.py +198 -0
- moai_adk/templates/.claude/hooks/alfred/handlers/__init__.py +14 -6
- moai_adk/templates/.claude/hooks/alfred/post_tool__enable_streaming_ui.py +50 -0
- moai_adk/templates/.claude/hooks/alfred/post_tool__log_changes.py +93 -0
- moai_adk/templates/.claude/hooks/alfred/post_tool__tag_auto_corrector.py +407 -0
- moai_adk/templates/.claude/hooks/alfred/pre_tool__auto_checkpoint.py +99 -0
- moai_adk/templates/.claude/hooks/alfred/pre_tool__realtime_tag_monitor.py +335 -0
- moai_adk/templates/.claude/hooks/alfred/pre_tool__tag_policy_validator.py +325 -0
- moai_adk/templates/.claude/hooks/alfred/session_end__cleanup.py +93 -0
- moai_adk/templates/.claude/hooks/alfred/session_start__auto_cleanup.py +580 -0
- moai_adk/templates/.claude/hooks/alfred/session_start__show_project_info.py +298 -0
- moai_adk/templates/.claude/hooks/alfred/shared/core/__init__.py +170 -0
- moai_adk/templates/.claude/hooks/alfred/{core → shared/core}/checkpoint.py +3 -3
- moai_adk/templates/.claude/hooks/alfred/{core → shared/core}/context.py +5 -5
- moai_adk/templates/.claude/hooks/alfred/shared/core/project.py +749 -0
- moai_adk/templates/.claude/hooks/alfred/shared/core/tags.py +230 -0
- moai_adk/templates/.claude/hooks/alfred/shared/core/version_cache.py +198 -0
- moai_adk/templates/.claude/hooks/alfred/shared/handlers/__init__.py +21 -0
- moai_adk/templates/.claude/hooks/alfred/shared/handlers/daily_analysis.py +351 -0
- moai_adk/templates/.claude/hooks/alfred/shared/handlers/notification.py +154 -0
- moai_adk/templates/.claude/hooks/alfred/shared/handlers/session.py +174 -0
- moai_adk/templates/.claude/hooks/alfred/shared/handlers/tool.py +87 -0
- moai_adk/templates/.claude/hooks/alfred/shared/handlers/user.py +61 -0
- moai_adk/templates/.claude/hooks/alfred/user_prompt__jit_load_docs.py +111 -0
- moai_adk/templates/.claude/hooks/alfred/utils/__init__.py +1 -0
- moai_adk/templates/.claude/hooks/alfred/utils/hook_config.py +94 -0
- moai_adk/templates/.claude/hooks/alfred/utils/timeout.py +161 -0
- moai_adk/templates/.claude/output-styles/alfred/alfred-moai-adk-beginner.md +267 -0
- moai_adk/templates/.claude/output-styles/alfred/keating-personal-tutor.md +440 -0
- moai_adk/templates/.claude/output-styles/alfred/r2d2-agentic-coding.md +583 -0
- moai_adk/templates/.claude/settings.json +96 -14
- moai_adk/templates/.claude/skills/moai-alfred-agent-guide/SKILL.md +70 -0
- moai_adk/templates/.claude/skills/moai-alfred-agent-guide/examples.md +62 -0
- moai_adk/templates/.claude/skills/moai-alfred-agent-guide/reference.md +242 -0
- moai_adk/templates/.claude/skills/moai-alfred-ask-user-questions/SKILL.md +237 -0
- moai_adk/templates/.claude/skills/moai-alfred-ask-user-questions/examples.md +871 -0
- moai_adk/templates/.claude/skills/moai-alfred-ask-user-questions/reference.md +653 -0
- moai_adk/templates/.claude/skills/moai-alfred-clone-pattern/README.md +162 -0
- moai_adk/templates/.claude/skills/moai-alfred-clone-pattern/SKILL.md +227 -0
- moai_adk/templates/.claude/skills/moai-alfred-clone-pattern/examples.md +354 -0
- moai_adk/templates/.claude/skills/moai-alfred-clone-pattern/reference.md +158 -0
- moai_adk/templates/.claude/skills/moai-alfred-code-reviewer/SKILL.md +179 -79
- moai_adk/templates/.claude/skills/moai-alfred-code-reviewer/examples.md +117 -0
- moai_adk/templates/.claude/skills/moai-alfred-code-reviewer/scripts/pre-review-check.sh +62 -0
- moai_adk/templates/.claude/skills/moai-alfred-config-schema/SKILL.md +132 -0
- moai_adk/templates/.claude/skills/moai-alfred-config-schema/examples.md +28 -0
- moai_adk/templates/.claude/skills/moai-alfred-config-schema/reference.md +444 -0
- moai_adk/templates/.claude/skills/moai-alfred-context-budget/SKILL.md +62 -0
- moai_adk/templates/.claude/skills/moai-alfred-context-budget/examples.md +28 -0
- moai_adk/templates/.claude/skills/moai-alfred-context-budget/reference.md +405 -0
- moai_adk/templates/.claude/skills/moai-alfred-dev-guide/SKILL.md +51 -0
- moai_adk/templates/.claude/skills/moai-alfred-dev-guide/examples.md +355 -0
- moai_adk/templates/.claude/skills/moai-alfred-dev-guide/reference.md +239 -0
- moai_adk/templates/.claude/skills/moai-alfred-expertise-detection/SKILL.md +323 -0
- moai_adk/templates/.claude/skills/moai-alfred-expertise-detection/examples.md +286 -0
- moai_adk/templates/.claude/skills/moai-alfred-expertise-detection/reference.md +126 -0
- moai_adk/templates/.claude/skills/moai-alfred-issue-labels/SKILL.md +229 -0
- moai_adk/templates/.claude/skills/moai-alfred-issue-labels/examples.md +4 -0
- moai_adk/templates/.claude/skills/moai-alfred-issue-labels/reference.md +150 -0
- moai_adk/templates/.claude/skills/moai-alfred-language-detection/SKILL.md +87 -73
- moai_adk/templates/.claude/skills/moai-alfred-language-detection/examples.md +29 -0
- moai_adk/templates/.claude/skills/moai-alfred-language-detection/reference.md +28 -0
- moai_adk/templates/.claude/skills/moai-alfred-personas/README.md +42 -0
- moai_adk/templates/.claude/skills/moai-alfred-personas/SKILL.md +429 -0
- moai_adk/templates/.claude/skills/moai-alfred-personas/examples.md +520 -0
- moai_adk/templates/.claude/skills/moai-alfred-personas/reference.md +405 -0
- moai_adk/templates/.claude/skills/moai-alfred-practices/SKILL.md +89 -0
- moai_adk/templates/.claude/skills/moai-alfred-practices/examples.md +122 -0
- moai_adk/templates/.claude/skills/moai-alfred-practices/reference.md +369 -0
- moai_adk/templates/.claude/skills/moai-alfred-proactive-suggestions/SKILL.md +508 -0
- moai_adk/templates/.claude/skills/moai-alfred-proactive-suggestions/examples.md +481 -0
- moai_adk/templates/.claude/skills/moai-alfred-proactive-suggestions/reference.md +100 -0
- moai_adk/templates/.claude/skills/moai-alfred-rules/SKILL.md +77 -0
- moai_adk/templates/.claude/skills/moai-alfred-rules/examples.md +265 -0
- moai_adk/templates/.claude/skills/moai-alfred-rules/reference.md +539 -0
- moai_adk/templates/.claude/skills/moai-alfred-session-state/SKILL.md +320 -0
- moai_adk/templates/.claude/skills/moai-alfred-session-state/examples.md +4 -0
- moai_adk/templates/.claude/skills/moai-alfred-session-state/reference.md +84 -0
- moai_adk/templates/.claude/skills/moai-alfred-spec-authoring/README.md +137 -0
- moai_adk/templates/.claude/skills/moai-alfred-spec-authoring/SKILL.md +219 -0
- moai_adk/templates/.claude/skills/moai-alfred-spec-authoring/examples/validate-spec.sh +161 -0
- moai_adk/templates/.claude/skills/moai-alfred-spec-authoring/examples.md +541 -0
- moai_adk/templates/.claude/skills/moai-alfred-spec-authoring/reference.md +622 -0
- moai_adk/templates/.claude/skills/moai-alfred-todowrite-pattern/SKILL.md +19 -0
- moai_adk/templates/.claude/skills/moai-alfred-todowrite-pattern/examples.md +4 -0
- moai_adk/templates/.claude/skills/moai-alfred-todowrite-pattern/reference.md +211 -0
- moai_adk/templates/.claude/skills/moai-alfred-workflow/SKILL.md +288 -0
- moai_adk/templates/.claude/skills/moai-cc-agents/SKILL.md +269 -0
- moai_adk/templates/.claude/skills/moai-cc-agents/templates/agent-template.md +32 -0
- moai_adk/templates/.claude/skills/moai-cc-claude-md/SKILL.md +298 -0
- moai_adk/templates/.claude/skills/moai-cc-claude-md/templates/CLAUDE-template.md +26 -0
- moai_adk/templates/.claude/skills/moai-cc-commands/SKILL.md +307 -0
- moai_adk/templates/.claude/skills/moai-cc-commands/templates/command-template.md +21 -0
- moai_adk/templates/.claude/skills/moai-cc-hooks/SKILL.md +252 -0
- moai_adk/templates/.claude/skills/moai-cc-hooks/scripts/pre-bash-check.sh +19 -0
- moai_adk/templates/.claude/skills/moai-cc-hooks/scripts/preserve-permissions.sh +19 -0
- moai_adk/templates/.claude/skills/moai-cc-hooks/scripts/validate-bash-command.py +24 -0
- moai_adk/templates/.claude/skills/moai-cc-mcp-plugins/SKILL.md +199 -0
- moai_adk/templates/.claude/skills/moai-cc-mcp-plugins/templates/settings-mcp-template.json +39 -0
- moai_adk/templates/.claude/skills/moai-cc-memory/SKILL.md +316 -0
- moai_adk/templates/.claude/skills/moai-cc-memory/templates/session-summary-template.md +18 -0
- moai_adk/templates/.claude/skills/moai-cc-settings/SKILL.md +263 -0
- moai_adk/templates/.claude/skills/moai-cc-settings/templates/settings-complete-template.json +30 -0
- moai_adk/templates/.claude/skills/moai-cc-skill-factory/CHECKLIST.md +482 -0
- moai_adk/templates/.claude/skills/moai-cc-skill-factory/EXAMPLES.md +303 -0
- moai_adk/templates/.claude/skills/moai-cc-skill-factory/INTERACTIVE-DISCOVERY.md +524 -0
- moai_adk/templates/.claude/skills/moai-cc-skill-factory/METADATA.md +477 -0
- moai_adk/templates/.claude/skills/moai-cc-skill-factory/PARALLEL-ANALYSIS-REPORT.md +429 -0
- moai_adk/templates/.claude/skills/moai-cc-skill-factory/PYTHON-VERSION-MATRIX.md +391 -0
- moai_adk/templates/.claude/skills/moai-cc-skill-factory/SKILL-FACTORY-WORKFLOW.md +431 -0
- moai_adk/templates/.claude/skills/moai-cc-skill-factory/SKILL-UPDATE-ADVISOR.md +577 -0
- moai_adk/templates/.claude/skills/moai-cc-skill-factory/SKILL.md +273 -0
- moai_adk/templates/.claude/skills/moai-cc-skill-factory/STEP-BY-STEP-GUIDE.md +466 -0
- moai_adk/templates/.claude/skills/moai-cc-skill-factory/STRUCTURE.md +583 -0
- moai_adk/templates/.claude/skills/moai-cc-skill-factory/WEB-RESEARCH.md +526 -0
- moai_adk/templates/.claude/skills/moai-cc-skill-factory/reference.md +608 -0
- moai_adk/templates/.claude/skills/moai-cc-skill-factory/scripts/generate-structure.sh +328 -0
- moai_adk/templates/.claude/skills/moai-cc-skill-factory/scripts/validate-skill.sh +312 -0
- moai_adk/templates/.claude/skills/moai-cc-skill-factory/templates/SKILL_TEMPLATE.md +245 -0
- moai_adk/templates/.claude/skills/moai-cc-skill-factory/templates/examples-template.md +285 -0
- moai_adk/templates/.claude/skills/moai-cc-skill-factory/templates/reference-template.md +278 -0
- moai_adk/templates/.claude/skills/moai-cc-skill-factory/templates/scripts-template.sh +303 -0
- moai_adk/templates/.claude/skills/moai-cc-skills/SKILL.md +291 -0
- moai_adk/templates/.claude/skills/moai-cc-skills/templates/SKILL-template.md +15 -0
- moai_adk/templates/.claude/skills/moai-change-logger/SKILL.md +563 -0
- moai_adk/templates/.claude/skills/moai-design-systems/SKILL.md +802 -0
- moai_adk/templates/.claude/skills/moai-design-systems/examples.md +1238 -0
- moai_adk/templates/.claude/skills/moai-design-systems/reference.md +673 -0
- moai_adk/templates/.claude/skills/moai-domain-backend/SKILL.md +234 -43
- moai_adk/templates/.claude/skills/moai-domain-backend/examples.md +1633 -0
- moai_adk/templates/.claude/skills/moai-domain-backend/reference.md +660 -0
- moai_adk/templates/.claude/skills/moai-domain-cli-tool/SKILL.md +97 -69
- moai_adk/templates/.claude/skills/moai-domain-cli-tool/examples.md +29 -0
- moai_adk/templates/.claude/skills/moai-domain-cli-tool/reference.md +30 -0
- moai_adk/templates/.claude/skills/moai-domain-data-science/SKILL.md +97 -72
- moai_adk/templates/.claude/skills/moai-domain-data-science/examples.md +29 -0
- moai_adk/templates/.claude/skills/moai-domain-data-science/reference.md +30 -0
- moai_adk/templates/.claude/skills/moai-domain-database/SKILL.md +97 -74
- moai_adk/templates/.claude/skills/moai-domain-database/examples.md +29 -0
- moai_adk/templates/.claude/skills/moai-domain-database/reference.md +30 -0
- moai_adk/templates/.claude/skills/moai-domain-devops/SKILL.md +98 -74
- moai_adk/templates/.claude/skills/moai-domain-devops/examples.md +29 -0
- moai_adk/templates/.claude/skills/moai-domain-devops/reference.md +31 -0
- moai_adk/templates/.claude/skills/moai-domain-frontend/SKILL.md +102 -73
- moai_adk/templates/.claude/skills/moai-domain-frontend/examples.md +29 -0
- moai_adk/templates/.claude/skills/moai-domain-frontend/reference.md +31 -0
- moai_adk/templates/.claude/skills/moai-domain-ml/SKILL.md +97 -73
- moai_adk/templates/.claude/skills/moai-domain-ml/examples.md +29 -0
- moai_adk/templates/.claude/skills/moai-domain-ml/reference.md +30 -0
- moai_adk/templates/.claude/skills/moai-domain-mobile-app/SKILL.md +97 -67
- moai_adk/templates/.claude/skills/moai-domain-mobile-app/examples.md +29 -0
- moai_adk/templates/.claude/skills/moai-domain-mobile-app/reference.md +30 -0
- moai_adk/templates/.claude/skills/moai-domain-security/SKILL.md +97 -79
- moai_adk/templates/.claude/skills/moai-domain-security/examples.md +29 -0
- moai_adk/templates/.claude/skills/moai-domain-security/reference.md +30 -0
- moai_adk/templates/.claude/skills/moai-domain-web-api/SKILL.md +97 -71
- moai_adk/templates/.claude/skills/moai-domain-web-api/examples.md +29 -0
- moai_adk/templates/.claude/skills/moai-domain-web-api/reference.md +30 -0
- moai_adk/templates/.claude/skills/moai-essentials-debug/SKILL.md +265 -64
- moai_adk/templates/.claude/skills/moai-essentials-debug/examples.md +1064 -0
- moai_adk/templates/.claude/skills/moai-essentials-debug/reference.md +1047 -0
- moai_adk/templates/.claude/skills/moai-essentials-perf/SKILL.md +87 -78
- moai_adk/templates/.claude/skills/moai-essentials-perf/examples.md +29 -0
- moai_adk/templates/.claude/skills/moai-essentials-perf/reference.md +28 -0
- moai_adk/templates/.claude/skills/moai-essentials-refactor/SKILL.md +87 -70
- moai_adk/templates/.claude/skills/moai-essentials-refactor/examples.md +29 -0
- moai_adk/templates/.claude/skills/moai-essentials-refactor/reference.md +28 -0
- moai_adk/templates/.claude/skills/moai-essentials-review/SKILL.md +87 -86
- moai_adk/templates/.claude/skills/moai-essentials-review/examples.md +29 -0
- moai_adk/templates/.claude/skills/moai-essentials-review/reference.md +28 -0
- moai_adk/templates/.claude/skills/moai-foundation-ears/SKILL.md +80 -62
- moai_adk/templates/.claude/skills/moai-foundation-ears/examples.md +29 -0
- moai_adk/templates/.claude/skills/moai-foundation-ears/reference.md +28 -0
- moai_adk/templates/.claude/skills/moai-foundation-git/SKILL.md +207 -50
- moai_adk/templates/.claude/skills/moai-foundation-git/examples.md +29 -0
- moai_adk/templates/.claude/skills/moai-foundation-git/reference.md +29 -0
- moai_adk/templates/.claude/skills/moai-foundation-langs/SKILL.md +90 -71
- moai_adk/templates/.claude/skills/moai-foundation-langs/examples.md +29 -0
- moai_adk/templates/.claude/skills/moai-foundation-langs/reference.md +28 -0
- moai_adk/templates/.claude/skills/moai-foundation-specs/SKILL.md +78 -58
- moai_adk/templates/.claude/skills/moai-foundation-specs/examples.md +29 -0
- moai_adk/templates/.claude/skills/moai-foundation-specs/reference.md +28 -0
- moai_adk/templates/.claude/skills/moai-foundation-tags/SKILL.md +78 -51
- moai_adk/templates/.claude/skills/moai-foundation-tags/examples.md +29 -0
- moai_adk/templates/.claude/skills/moai-foundation-tags/reference.md +28 -0
- moai_adk/templates/.claude/skills/moai-foundation-trust/.!11330!examples.md +0 -0
- moai_adk/templates/.claude/skills/moai-foundation-trust/SKILL.md +253 -32
- moai_adk/templates/.claude/skills/moai-foundation-trust/examples.md +0 -0
- moai_adk/templates/.claude/skills/moai-foundation-trust/reference.md +1099 -0
- moai_adk/templates/.claude/skills/moai-jit-docs-enhanced/SKILL.md +460 -0
- moai_adk/templates/.claude/skills/moai-lang-c/SKILL.md +98 -74
- moai_adk/templates/.claude/skills/moai-lang-c/examples.md +29 -0
- moai_adk/templates/.claude/skills/moai-lang-c/reference.md +31 -0
- moai_adk/templates/.claude/skills/moai-lang-cpp/SKILL.md +98 -76
- moai_adk/templates/.claude/skills/moai-lang-cpp/examples.md +29 -0
- moai_adk/templates/.claude/skills/moai-lang-cpp/reference.md +31 -0
- moai_adk/templates/.claude/skills/moai-lang-csharp/SKILL.md +2358 -70
- moai_adk/templates/.claude/skills/moai-lang-csharp/examples.md +29 -0
- moai_adk/templates/.claude/skills/moai-lang-csharp/reference.md +30 -0
- moai_adk/templates/.claude/skills/moai-lang-dart/SKILL.md +2962 -68
- moai_adk/templates/.claude/skills/moai-lang-dart/examples.md +29 -0
- moai_adk/templates/.claude/skills/moai-lang-dart/reference.md +30 -0
- moai_adk/templates/.claude/skills/moai-lang-go/SKILL.md +1898 -70
- moai_adk/templates/.claude/skills/moai-lang-go/examples.md +29 -0
- moai_adk/templates/.claude/skills/moai-lang-go/reference.md +31 -0
- moai_adk/templates/.claude/skills/moai-lang-java/SKILL.md +1465 -68
- moai_adk/templates/.claude/skills/moai-lang-java/examples.md +29 -0
- moai_adk/templates/.claude/skills/moai-lang-java/reference.md +31 -0
- moai_adk/templates/.claude/skills/moai-lang-javascript/SKILL.md +2364 -66
- moai_adk/templates/.claude/skills/moai-lang-javascript/examples.md +29 -0
- moai_adk/templates/.claude/skills/moai-lang-javascript/reference.md +32 -0
- moai_adk/templates/.claude/skills/moai-lang-kotlin/SKILL.md +1630 -69
- moai_adk/templates/.claude/skills/moai-lang-kotlin/examples.md +29 -0
- moai_adk/templates/.claude/skills/moai-lang-kotlin/reference.md +31 -0
- moai_adk/templates/.claude/skills/moai-lang-php/SKILL.md +89 -61
- moai_adk/templates/.claude/skills/moai-lang-php/examples.md +29 -0
- moai_adk/templates/.claude/skills/moai-lang-php/reference.md +30 -0
- moai_adk/templates/.claude/skills/moai-lang-python/SKILL.md +735 -66
- moai_adk/templates/.claude/skills/moai-lang-python/examples.md +624 -0
- moai_adk/templates/.claude/skills/moai-lang-python/reference.md +316 -0
- moai_adk/templates/.claude/skills/moai-lang-r/SKILL.md +97 -73
- moai_adk/templates/.claude/skills/moai-lang-r/examples.md +29 -0
- moai_adk/templates/.claude/skills/moai-lang-r/reference.md +30 -0
- moai_adk/templates/.claude/skills/moai-lang-ruby/SKILL.md +98 -73
- moai_adk/templates/.claude/skills/moai-lang-ruby/examples.md +29 -0
- moai_adk/templates/.claude/skills/moai-lang-ruby/reference.md +31 -0
- moai_adk/templates/.claude/skills/moai-lang-rust/SKILL.md +1834 -70
- moai_adk/templates/.claude/skills/moai-lang-rust/examples.md +29 -0
- moai_adk/templates/.claude/skills/moai-lang-rust/reference.md +31 -0
- moai_adk/templates/.claude/skills/moai-lang-scala/SKILL.md +99 -74
- moai_adk/templates/.claude/skills/moai-lang-scala/examples.md +29 -0
- moai_adk/templates/.claude/skills/moai-lang-scala/reference.md +30 -0
- moai_adk/templates/.claude/skills/moai-lang-shell/SKILL.md +97 -74
- moai_adk/templates/.claude/skills/moai-lang-shell/examples.md +29 -0
- moai_adk/templates/.claude/skills/moai-lang-shell/reference.md +30 -0
- moai_adk/templates/.claude/skills/moai-lang-sql/SKILL.md +98 -74
- moai_adk/templates/.claude/skills/moai-lang-sql/examples.md +29 -0
- moai_adk/templates/.claude/skills/moai-lang-sql/reference.md +31 -0
- moai_adk/templates/.claude/skills/moai-lang-swift/SKILL.md +1959 -69
- moai_adk/templates/.claude/skills/moai-lang-swift/examples.md +29 -0
- moai_adk/templates/.claude/skills/moai-lang-swift/reference.md +30 -0
- moai_adk/templates/.claude/skills/moai-lang-template/SKILL.md +348 -0
- moai_adk/templates/.claude/skills/moai-lang-template/VARIABLES.md +98 -0
- moai_adk/templates/.claude/skills/moai-lang-typescript/SKILL.md +1230 -66
- moai_adk/templates/.claude/skills/moai-lang-typescript/examples.md +29 -0
- moai_adk/templates/.claude/skills/moai-lang-typescript/reference.md +34 -0
- moai_adk/templates/.claude/skills/moai-learning-optimizer/SKILL.md +575 -0
- moai_adk/templates/.claude/skills/moai-project-batch-questions/README.md +50 -0
- moai_adk/templates/.claude/skills/moai-project-batch-questions/SKILL.md +304 -0
- moai_adk/templates/.claude/skills/moai-project-batch-questions/examples.md +417 -0
- moai_adk/templates/.claude/skills/moai-project-batch-questions/reference.md +704 -0
- moai_adk/templates/.claude/skills/moai-project-config-manager/README.md +87 -0
- moai_adk/templates/.claude/skills/moai-project-config-manager/SKILL.md +552 -0
- moai_adk/templates/.claude/skills/moai-project-config-manager/examples.md +1109 -0
- moai_adk/templates/.claude/skills/moai-project-config-manager/reference.md +514 -0
- moai_adk/templates/.claude/skills/moai-project-config-manager/validate.py +106 -0
- moai_adk/templates/.claude/skills/moai-project-documentation/README.md +11 -0
- moai_adk/templates/.claude/skills/moai-project-documentation/SKILL.md +622 -0
- moai_adk/templates/.claude/skills/moai-project-documentation/examples.md +20 -0
- moai_adk/templates/.claude/skills/moai-project-documentation/reference.md +12 -0
- moai_adk/templates/.claude/skills/moai-project-language-initializer/README.md +152 -0
- moai_adk/templates/.claude/skills/moai-project-language-initializer/SKILL.md +285 -0
- moai_adk/templates/.claude/skills/moai-project-language-initializer/examples.md +333 -0
- moai_adk/templates/.claude/skills/moai-project-language-initializer/reference.md +386 -0
- moai_adk/templates/.claude/skills/moai-project-template-optimizer/README.md +49 -0
- moai_adk/templates/.claude/skills/moai-project-template-optimizer/SKILL.md +319 -0
- moai_adk/templates/.claude/skills/moai-project-template-optimizer/examples.md +58 -0
- moai_adk/templates/.claude/skills/moai-project-template-optimizer/reference.md +123 -0
- moai_adk/templates/.claude/skills/moai-session-info/SKILL.md +314 -0
- moai_adk/templates/.claude/skills/moai-streaming-ui/SKILL.md +552 -0
- moai_adk/templates/.claude/skills/moai-tag-policy-validator/SKILL.md +570 -0
- moai_adk/templates/.git-hooks/pre-commit +66 -0
- moai_adk/templates/.git-hooks/pre-push +255 -0
- moai_adk/templates/.github/workflows/c-tag-validation.yml +11 -0
- moai_adk/templates/.github/workflows/cpp-tag-validation.yml +11 -0
- moai_adk/templates/.github/workflows/csharp-tag-validation.yml +11 -0
- moai_adk/templates/.github/workflows/dart-tag-validation.yml +11 -0
- moai_adk/templates/.github/workflows/go-tag-validation.yml +130 -0
- moai_adk/templates/.github/workflows/java-tag-validation.yml +11 -0
- moai_adk/templates/.github/workflows/javascript-tag-validation.yml +135 -0
- moai_adk/templates/.github/workflows/kotlin-tag-validation.yml +11 -0
- moai_adk/templates/.github/workflows/moai-gitflow.yml +166 -3
- moai_adk/templates/.github/workflows/moai-release-create.yml +100 -0
- moai_adk/templates/.github/workflows/moai-release-pipeline.yml +188 -0
- moai_adk/templates/.github/workflows/php-tag-validation.yml +11 -0
- moai_adk/templates/.github/workflows/python-tag-validation.yml +118 -0
- moai_adk/templates/.github/workflows/release.yml +118 -0
- moai_adk/templates/.github/workflows/ruby-tag-validation.yml +11 -0
- moai_adk/templates/.github/workflows/rust-tag-validation.yml +11 -0
- moai_adk/templates/.github/workflows/shell-tag-validation.yml +11 -0
- moai_adk/templates/.github/workflows/spec-issue-sync.yml +338 -0
- moai_adk/templates/.github/workflows/swift-tag-validation.yml +11 -0
- moai_adk/templates/.github/workflows/tag-report.yml +269 -0
- moai_adk/templates/.github/workflows/tag-validation.yml +186 -0
- moai_adk/templates/.github/workflows/typescript-tag-validation.yml +154 -0
- moai_adk/templates/.mcp.json +31 -0
- moai_adk/templates/.moai/config.json +80 -7
- moai_adk/templates/CLAUDE.md +562 -546
- moai_adk/utils/banner.py +5 -5
- moai_adk/utils/common.py +294 -0
- moai_adk/utils/link_validator.py +235 -0
- moai_adk/utils/logger.py +8 -8
- moai_adk/utils/user_experience.py +451 -0
- moai_adk-0.20.1.dist-info/METADATA +233 -0
- moai_adk-0.20.1.dist-info/RECORD +404 -0
- moai_adk/templates/.claude/hooks/alfred/README.md +0 -230
- moai_adk/templates/.claude/hooks/alfred/alfred_hooks.py +0 -156
- moai_adk/templates/.claude/hooks/alfred/core/__init__.py +0 -85
- moai_adk/templates/.claude/hooks/alfred/handlers/notification.py +0 -25
- moai_adk/templates/.claude/hooks/alfred/handlers/session.py +0 -92
- moai_adk/templates/.claude/hooks/alfred/handlers/tool.py +0 -70
- moai_adk/templates/.claude/hooks/alfred/handlers/user.py +0 -41
- moai_adk/templates/.claude/output-styles/alfred/agentic-coding.md +0 -636
- moai_adk/templates/.claude/output-styles/alfred/moai-adk-learning.md +0 -692
- moai_adk/templates/.claude/output-styles/alfred/study-with-alfred.md +0 -470
- moai_adk/templates/.claude/skills/moai-alfred-debugger-pro/SKILL.md +0 -103
- moai_adk/templates/.claude/skills/moai-alfred-ears-authoring/SKILL.md +0 -103
- moai_adk/templates/.claude/skills/moai-alfred-git-workflow/SKILL.md +0 -95
- moai_adk/templates/.claude/skills/moai-alfred-performance-optimizer/SKILL.md +0 -105
- moai_adk/templates/.claude/skills/moai-alfred-refactoring-coach/SKILL.md +0 -97
- moai_adk/templates/.claude/skills/moai-alfred-spec-metadata-validation/SKILL.md +0 -97
- moai_adk/templates/.claude/skills/moai-alfred-tag-scanning/SKILL.md +0 -90
- moai_adk/templates/.claude/skills/moai-alfred-trust-validation/SKILL.md +0 -99
- moai_adk/templates/.claude/skills/moai-alfred-tui-survey/SKILL.md +0 -87
- moai_adk/templates/.claude/skills/moai-alfred-tui-survey/examples.md +0 -62
- moai_adk/templates/.claude/skills/moai-claude-code/SKILL.md +0 -94
- moai_adk/templates/.claude/skills/moai-claude-code/examples.md +0 -513
- moai_adk/templates/.claude/skills/moai-claude-code/reference.md +0 -433
- moai_adk/templates/.claude/skills/moai-claude-code/templates/agent-full.md +0 -332
- moai_adk/templates/.claude/skills/moai-claude-code/templates/command-full.md +0 -384
- moai_adk/templates/.claude/skills/moai-claude-code/templates/plugin-full.json +0 -363
- moai_adk/templates/.claude/skills/moai-claude-code/templates/settings-full.json +0 -595
- moai_adk/templates/.claude/skills/moai-claude-code/templates/skill-full.md +0 -496
- moai_adk/templates/.claude/skills/moai-lang-clojure/SKILL.md +0 -100
- moai_adk/templates/.claude/skills/moai-lang-elixir/SKILL.md +0 -99
- moai_adk/templates/.claude/skills/moai-lang-haskell/SKILL.md +0 -100
- moai_adk/templates/.claude/skills/moai-lang-julia/SKILL.md +0 -98
- moai_adk/templates/.claude/skills/moai-lang-lua/SKILL.md +0 -98
- moai_adk/templates/.github/PULL_REQUEST_TEMPLATE.md +0 -69
- moai_adk/templates/.moai/memory/development-guide.md +0 -344
- moai_adk/templates/.moai/memory/gitflow-protection-policy.md +0 -220
- moai_adk/templates/.moai/memory/spec-metadata.md +0 -356
- moai_adk/templates/.moai/project/product.md +0 -161
- moai_adk/templates/.moai/project/structure.md +0 -156
- moai_adk/templates/.moai/project/tech.md +0 -227
- moai_adk/templates/__init__.py +0 -2
- moai_adk-0.4.5.dist-info/METADATA +0 -369
- moai_adk-0.4.5.dist-info/RECORD +0 -152
- {moai_adk-0.4.5.dist-info → moai_adk-0.20.1.dist-info}/WHEEL +0 -0
- {moai_adk-0.4.5.dist-info → moai_adk-0.20.1.dist-info}/entry_points.txt +0 -0
- {moai_adk-0.4.5.dist-info → moai_adk-0.20.1.dist-info}/licenses/LICENSE +0 -0
|
@@ -1,96 +1,1260 @@
|
|
|
1
1
|
---
|
|
2
|
-
|
|
3
2
|
name: moai-lang-typescript
|
|
4
|
-
|
|
3
|
+
version: 2.0.0
|
|
4
|
+
created: 2025-11-06
|
|
5
|
+
updated: 2025-11-06
|
|
6
|
+
status: active
|
|
7
|
+
description: "TypeScript best practices with modern frameworks, full-stack development, and type-safe patterns for 2025"
|
|
8
|
+
keywords: [typescript, javascript, frontend, backend, fullstack, react, nextjs, nodejs, type-safety]
|
|
5
9
|
allowed-tools:
|
|
6
10
|
- Read
|
|
11
|
+
- Write
|
|
12
|
+
- Edit
|
|
7
13
|
- Bash
|
|
14
|
+
- WebFetch
|
|
15
|
+
- WebSearch
|
|
8
16
|
---
|
|
9
17
|
|
|
10
|
-
# TypeScript
|
|
18
|
+
# TypeScript Development Mastery
|
|
19
|
+
|
|
20
|
+
**Modern TypeScript Development with 2025 Best Practices**
|
|
21
|
+
|
|
22
|
+
> Comprehensive TypeScript development guidance covering full-stack applications, type-safe patterns, modern frameworks, and production-ready code using the latest tools and methodologies.
|
|
23
|
+
|
|
24
|
+
## What It Does
|
|
25
|
+
|
|
26
|
+
- **Full-Stack Development**: Next.js, React, Node.js with end-to-end type safety
|
|
27
|
+
- **Type-Safe APIs**: REST and GraphQL with TypeScript validation
|
|
28
|
+
- **Modern Frontend**: React 19+, Vue 3+, Angular 17+ with TypeScript
|
|
29
|
+
- **Backend Services**: Node.js, Deno, Bun with TypeScript optimization
|
|
30
|
+
- **Testing Strategies**: Vitest, Jest, Playwright with type-safe testing
|
|
31
|
+
- **Build & Deployment**: Modern bundlers, CI/CD, performance optimization
|
|
32
|
+
- **Code Quality**: ESLint, Prettier, automated type checking
|
|
33
|
+
- **Enterprise Patterns**: Monorepos, microservices, scalable architecture
|
|
34
|
+
|
|
35
|
+
## When to Use
|
|
11
36
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
37
|
+
### Perfect Scenarios
|
|
38
|
+
- **Building full-stack web applications**
|
|
39
|
+
- **Developing type-safe APIs and microservices**
|
|
40
|
+
- **Creating modern React/Next.js applications**
|
|
41
|
+
- **Enterprise-scale JavaScript applications**
|
|
42
|
+
- **Projects requiring strict type safety**
|
|
43
|
+
- **Teams with multiple JavaScript skill levels**
|
|
44
|
+
- **Applications with complex data models**
|
|
19
45
|
|
|
20
|
-
|
|
46
|
+
### Common Triggers
|
|
47
|
+
- "Create TypeScript API"
|
|
48
|
+
- "Set up Next.js project"
|
|
49
|
+
- "Type-safe React components"
|
|
50
|
+
- "TypeScript best practices"
|
|
51
|
+
- "Migrate JavaScript to TypeScript"
|
|
52
|
+
- "Full-stack TypeScript application"
|
|
21
53
|
|
|
22
|
-
|
|
54
|
+
## Tool Version Matrix (2025-11-06)
|
|
23
55
|
|
|
24
|
-
|
|
56
|
+
### Core TypeScript
|
|
57
|
+
- **TypeScript**: 5.6.x (latest) / 5.3.x (LTS)
|
|
58
|
+
- **Node.js**: 22.x (LTS) / 20.x (stable)
|
|
59
|
+
- **Package Managers**: pnpm 9.x, npm 10.x, yarn 4.x
|
|
60
|
+
- **Runtimes**: Node.js 22.x, Deno 2.x, Bun 1.1.x
|
|
25
61
|
|
|
26
|
-
|
|
27
|
-
-
|
|
28
|
-
-
|
|
29
|
-
-
|
|
62
|
+
### Frontend Frameworks
|
|
63
|
+
- **Next.js**: 15.x - Full-stack React framework
|
|
64
|
+
- **React**: 19.x - UI library with Server Components
|
|
65
|
+
- **Vue**: 3.5.x - Progressive framework
|
|
66
|
+
- **Angular**: 18.x - Enterprise framework
|
|
67
|
+
- **Svelte**: 5.x - Compiler-based framework
|
|
30
68
|
|
|
31
|
-
|
|
69
|
+
### Build Tools
|
|
70
|
+
- **Vite**: 6.x - Fast build tool
|
|
71
|
+
- **Webpack**: 5.x - Module bundler
|
|
72
|
+
- **esbuild**: 0.24.x - Fast bundler
|
|
73
|
+
- **SWC**: 1.7.x - Rust-based compiler
|
|
32
74
|
|
|
33
|
-
|
|
34
|
-
- **Vitest**: Fast unit testing
|
|
35
|
-
-
|
|
36
|
-
-
|
|
75
|
+
### Testing Tools
|
|
76
|
+
- **Vitest**: 2.x - Fast unit testing
|
|
77
|
+
- **Jest**: 30.x - Comprehensive testing
|
|
78
|
+
- **Playwright**: 1.48.x - E2E testing
|
|
79
|
+
- **Testing Library**: 16.x - Component testing
|
|
37
80
|
|
|
38
|
-
|
|
39
|
-
- **
|
|
40
|
-
- **
|
|
41
|
-
-
|
|
81
|
+
### Code Quality
|
|
82
|
+
- **ESLint**: 9.x - Linting (flat config)
|
|
83
|
+
- **Prettier**: 3.3.x - Code formatting
|
|
84
|
+
- **TypeScript Compiler**: Built-in type checking
|
|
85
|
+
- **Husky**: 9.x - Git hooks
|
|
42
86
|
|
|
43
|
-
|
|
44
|
-
- **
|
|
45
|
-
-
|
|
46
|
-
-
|
|
87
|
+
### Backend Frameworks
|
|
88
|
+
- **Express**: 4.21.x - Minimal web framework
|
|
89
|
+
- **Fastify**: 5.x - Fast web framework
|
|
90
|
+
- **NestJS**: 10.x - Enterprise framework
|
|
91
|
+
- **tRPC**: 11.x - End-to-end typesafe APIs
|
|
47
92
|
|
|
48
|
-
|
|
49
|
-
- **pnpm**: Fast, disk-efficient package manager (preferred)
|
|
50
|
-
- **npm**: Fallback option
|
|
51
|
-
- `package.json` + `tsconfig.json` configuration
|
|
93
|
+
## Ecosystem Overview
|
|
52
94
|
|
|
53
|
-
|
|
54
|
-
- File ≤300 LOC, function ≤50 LOC
|
|
55
|
-
- Prefer interfaces over types for public APIs
|
|
56
|
-
- Use const assertions for literal types
|
|
57
|
-
- Avoid `any`, prefer `unknown` or proper types
|
|
95
|
+
### Project Setup (2025 Best Practice)
|
|
58
96
|
|
|
59
|
-
## Examples
|
|
60
97
|
```bash
|
|
61
|
-
|
|
98
|
+
# Modern TypeScript with pnpm (recommended)
|
|
99
|
+
pnpm create next-app@latest my-app --typescript --tailwind --eslint --app
|
|
100
|
+
cd my-app
|
|
101
|
+
pnpm add @types/node @types/react @types/react-dom
|
|
102
|
+
pnpm add -D vitest @vitest/ui jsdom @testing-library/react
|
|
103
|
+
|
|
104
|
+
# Alternative: Bun for ultra-fast development
|
|
105
|
+
bun create next-app my-app
|
|
106
|
+
cd my-app
|
|
107
|
+
bun add vitest @testing-library/react -d
|
|
108
|
+
|
|
109
|
+
# Monorepo with Nx or Turborepo
|
|
110
|
+
npx create-nx-workspace@latest my-workspace --preset=react-monorepo
|
|
111
|
+
# or
|
|
112
|
+
npx create-turbo@latest my-turbo-app
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
### Modern Project Structure
|
|
116
|
+
|
|
117
|
+
```
|
|
118
|
+
my-typescript-project/
|
|
119
|
+
├── package.json
|
|
120
|
+
├── tsconfig.json # TypeScript configuration
|
|
121
|
+
├── tsconfig.build.json # Build-specific config
|
|
122
|
+
├── vite.config.ts # Build tool configuration
|
|
123
|
+
├── eslint.config.js # ESLint flat config
|
|
124
|
+
├── prettier.config.js # Prettier configuration
|
|
125
|
+
├── playwright.config.ts # E2E testing config
|
|
126
|
+
├── vitest.config.ts # Unit testing config
|
|
127
|
+
├── src/
|
|
128
|
+
│ ├── app/ # Next.js app router
|
|
129
|
+
│ │ ├── layout.tsx
|
|
130
|
+
│ │ ├── page.tsx
|
|
131
|
+
│ │ ├── globals.css
|
|
132
|
+
│ │ └── api/ # API routes
|
|
133
|
+
│ ├── components/ # Reusable components
|
|
134
|
+
│ │ ├── ui/ # UI components
|
|
135
|
+
│ │ └── features/ # Feature components
|
|
136
|
+
│ ├── lib/ # Utilities and configs
|
|
137
|
+
│ │ ├── utils.ts
|
|
138
|
+
│ │ ├── db.ts # Database configuration
|
|
139
|
+
│ │ └── types.ts # Global type definitions
|
|
140
|
+
│ ├── hooks/ # Custom React hooks
|
|
141
|
+
│ └── types/ # Domain-specific types
|
|
142
|
+
├── tests/
|
|
143
|
+
│ ├── __mocks__/ # Mock files
|
|
144
|
+
│ ├── setup.ts # Test setup
|
|
145
|
+
│ └── integration/ # Integration tests
|
|
146
|
+
└── .github/
|
|
147
|
+
└── workflows/ # CI/CD pipelines
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
## Modern TypeScript Patterns
|
|
151
|
+
|
|
152
|
+
### Advanced Type System Features (TypeScript 5.6)
|
|
153
|
+
|
|
154
|
+
```typescript
|
|
155
|
+
// Import attributes for better module management
|
|
156
|
+
import data from "./data.json" with { type: "json" };
|
|
157
|
+
|
|
158
|
+
// Template literal type improvements
|
|
159
|
+
type EventName<T extends string> = `on${Capitalize<T>}`;
|
|
160
|
+
type UserEvent = EventName<'click' | 'hover'>; // 'onClick' | 'onHover'
|
|
161
|
+
|
|
162
|
+
// Enhanced symbol key handling
|
|
163
|
+
const metaKey = Symbol('metadata');
|
|
164
|
+
interface Metadata {
|
|
165
|
+
[metaKey]: string;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
// Improved decorator metadata
|
|
169
|
+
function Entity<T extends { new(...args: any[]): {} }>(constructor: T) {
|
|
170
|
+
return class extends constructor {
|
|
171
|
+
createdAt = new Date();
|
|
172
|
+
};
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
@Entity
|
|
176
|
+
class User {
|
|
177
|
+
constructor(public name: string) {}
|
|
178
|
+
}
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
### Utility Types and Patterns
|
|
182
|
+
|
|
183
|
+
```typescript
|
|
184
|
+
// Advanced utility types
|
|
185
|
+
type StrictOmit<T, K extends keyof T> = T extends Record<string, unknown>
|
|
186
|
+
? Pick<T, Exclude<keyof T, K>>
|
|
187
|
+
: never;
|
|
188
|
+
|
|
189
|
+
type DeepPartial<T> = {
|
|
190
|
+
[P in keyof T]?: T[P] extends object ? DeepPartial<T[P]> : T[P];
|
|
191
|
+
};
|
|
192
|
+
|
|
193
|
+
type Branded<T, B> = T & { __brand: B };
|
|
194
|
+
|
|
195
|
+
// Type-safe IDs
|
|
196
|
+
type UserId = Branded<string, 'UserId'>;
|
|
197
|
+
type ProductId = Branded<string, 'ProductId'>;
|
|
198
|
+
|
|
199
|
+
function createUserId(id: string): UserId {
|
|
200
|
+
return id as UserId;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
// Type-safe API client
|
|
204
|
+
type ApiResponse<T, E = unknown> =
|
|
205
|
+
| { success: true; data: T }
|
|
206
|
+
| { success: false; error: E };
|
|
207
|
+
|
|
208
|
+
interface User {
|
|
209
|
+
id: UserId;
|
|
210
|
+
name: string;
|
|
211
|
+
email: string;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
async function fetchUser(id: UserId): Promise<ApiResponse<User>> {
|
|
215
|
+
try {
|
|
216
|
+
const response = await fetch(`/api/users/${id}`);
|
|
217
|
+
if (!response.ok) throw new Error('Failed to fetch');
|
|
218
|
+
const data = await response.json();
|
|
219
|
+
return { success: true, data };
|
|
220
|
+
} catch (error) {
|
|
221
|
+
return { success: false, error };
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
### React Patterns with TypeScript
|
|
227
|
+
|
|
228
|
+
```typescript
|
|
229
|
+
// Type-safe component props with forwardRef
|
|
230
|
+
import React, { forwardRef, useImperativeHandle } from 'react';
|
|
231
|
+
|
|
232
|
+
interface ButtonProps {
|
|
233
|
+
variant: 'primary' | 'secondary' | 'danger';
|
|
234
|
+
size: 'sm' | 'md' | 'lg';
|
|
235
|
+
disabled?: boolean;
|
|
236
|
+
children: React.ReactNode;
|
|
237
|
+
onClick?: () => void;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
export interface ButtonRef {
|
|
241
|
+
click: () => void;
|
|
242
|
+
focus: () => void;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
export const Button = forwardRef<ButtonRef, ButtonProps>(
|
|
246
|
+
({ variant, size, disabled, children, onClick }, ref) => {
|
|
247
|
+
const buttonRef = React.useRef<HTMLButtonElement>(null);
|
|
248
|
+
|
|
249
|
+
useImperativeHandle(ref, () => ({
|
|
250
|
+
click: () => buttonRef.current?.click(),
|
|
251
|
+
focus: () => buttonRef.current?.focus(),
|
|
252
|
+
}));
|
|
253
|
+
|
|
254
|
+
const baseClasses = 'font-semibold rounded-lg transition-colors';
|
|
255
|
+
const variantClasses = {
|
|
256
|
+
primary: 'bg-blue-600 text-white hover:bg-blue-700',
|
|
257
|
+
secondary: 'bg-gray-200 text-gray-900 hover:bg-gray-300',
|
|
258
|
+
danger: 'bg-red-600 text-white hover:bg-red-700',
|
|
259
|
+
};
|
|
260
|
+
const sizeClasses = {
|
|
261
|
+
sm: 'px-3 py-1 text-sm',
|
|
262
|
+
md: 'px-4 py-2 text-base',
|
|
263
|
+
lg: 'px-6 py-3 text-lg',
|
|
264
|
+
};
|
|
265
|
+
|
|
266
|
+
return (
|
|
267
|
+
<button
|
|
268
|
+
ref={buttonRef}
|
|
269
|
+
className={`${baseClasses} ${variantClasses[variant]} ${sizeClasses[size]}`}
|
|
270
|
+
disabled={disabled}
|
|
271
|
+
onClick={onClick}
|
|
272
|
+
>
|
|
273
|
+
{children}
|
|
274
|
+
</button>
|
|
275
|
+
);
|
|
276
|
+
}
|
|
277
|
+
);
|
|
278
|
+
|
|
279
|
+
Button.displayName = 'Button';
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
### Custom Hooks with TypeScript
|
|
283
|
+
|
|
284
|
+
```typescript
|
|
285
|
+
// Type-safe data fetching hook
|
|
286
|
+
interface UseApiResult<T, E = unknown> {
|
|
287
|
+
data: T | null;
|
|
288
|
+
error: E | null;
|
|
289
|
+
loading: boolean;
|
|
290
|
+
refetch: () => Promise<void>;
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
function useApi<T, E = unknown>(
|
|
294
|
+
url: string,
|
|
295
|
+
options?: RequestInit
|
|
296
|
+
): UseApiResult<T, E> {
|
|
297
|
+
const [data, setData] = React.useState<T | null>(null);
|
|
298
|
+
const [error, setError] = React.useState<E | null>(null);
|
|
299
|
+
const [loading, setLoading] = React.useState(false);
|
|
300
|
+
|
|
301
|
+
const fetchData = React.useCallback(async () => {
|
|
302
|
+
setLoading(true);
|
|
303
|
+
setError(null);
|
|
304
|
+
|
|
305
|
+
try {
|
|
306
|
+
const response = await fetch(url, options);
|
|
307
|
+
if (!response.ok) throw new Error(response.statusText);
|
|
308
|
+
const result = await response.json() as T;
|
|
309
|
+
setData(result);
|
|
310
|
+
} catch (err) {
|
|
311
|
+
setError(err as E);
|
|
312
|
+
} finally {
|
|
313
|
+
setLoading(false);
|
|
314
|
+
}
|
|
315
|
+
}, [url, options]);
|
|
316
|
+
|
|
317
|
+
React.useEffect(() => {
|
|
318
|
+
fetchData();
|
|
319
|
+
}, [fetchData]);
|
|
320
|
+
|
|
321
|
+
return { data, error, loading, refetch: fetchData };
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
// Usage
|
|
325
|
+
interface User {
|
|
326
|
+
id: number;
|
|
327
|
+
name: string;
|
|
328
|
+
email: string;
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
function UserProfile({ userId }: { userId: number }) {
|
|
332
|
+
const { data: user, loading, error } = useApi<User>(`/api/users/${userId}`);
|
|
333
|
+
|
|
334
|
+
if (loading) return <div>Loading...</div>;
|
|
335
|
+
if (error) return <div>Error: {error.message}</div>;
|
|
336
|
+
if (!user) return <div>No user found</div>;
|
|
337
|
+
|
|
338
|
+
return (
|
|
339
|
+
<div>
|
|
340
|
+
<h1>{user.name}</h1>
|
|
341
|
+
<p>{user.email}</p>
|
|
342
|
+
</div>
|
|
343
|
+
);
|
|
344
|
+
}
|
|
345
|
+
```
|
|
346
|
+
|
|
347
|
+
## Performance Optimization
|
|
348
|
+
|
|
349
|
+
### Code Splitting and Lazy Loading
|
|
350
|
+
|
|
351
|
+
```typescript
|
|
352
|
+
// Dynamic imports with type safety
|
|
353
|
+
import { lazy, Suspense } from 'react';
|
|
354
|
+
|
|
355
|
+
const HeavyComponent = lazy(() =>
|
|
356
|
+
import('./HeavyComponent').then(module => ({
|
|
357
|
+
default: module.HeavyComponent
|
|
358
|
+
}))
|
|
359
|
+
);
|
|
360
|
+
|
|
361
|
+
// Route-based code splitting
|
|
362
|
+
import { createBrowserRouter } from 'react-router-dom';
|
|
363
|
+
|
|
364
|
+
const router = createBrowserRouter([
|
|
365
|
+
{
|
|
366
|
+
path: '/',
|
|
367
|
+
element: <HomePage />,
|
|
368
|
+
},
|
|
369
|
+
{
|
|
370
|
+
path: '/dashboard',
|
|
371
|
+
element: (
|
|
372
|
+
<Suspense fallback={<div>Loading dashboard...</div>}>
|
|
373
|
+
<LazyDashboard />
|
|
374
|
+
</Suspense>
|
|
375
|
+
),
|
|
376
|
+
loader: () => import('./loaders/dashboardLoader').then(m => m.dashboardLoader()),
|
|
377
|
+
},
|
|
378
|
+
]);
|
|
379
|
+
|
|
380
|
+
// Preloading strategies
|
|
381
|
+
const preloadComponent = () => {
|
|
382
|
+
import('./HeavyComponent');
|
|
383
|
+
};
|
|
384
|
+
|
|
385
|
+
// Preload on hover
|
|
386
|
+
<button onMouseEnter={preloadComponent}>
|
|
387
|
+
Load Component
|
|
388
|
+
</button>
|
|
389
|
+
```
|
|
390
|
+
|
|
391
|
+
### Bundle Optimization
|
|
392
|
+
|
|
393
|
+
```typescript
|
|
394
|
+
// vite.config.ts - Modern build configuration
|
|
395
|
+
import { defineConfig } from 'vite';
|
|
396
|
+
import react from '@vitejs/plugin-react-swc';
|
|
397
|
+
import { visualizer } from 'rollup-plugin-visualizer';
|
|
398
|
+
|
|
399
|
+
export default defineConfig({
|
|
400
|
+
plugins: [
|
|
401
|
+
react(),
|
|
402
|
+
process.env.ANALYZE && visualizer({
|
|
403
|
+
filename: 'dist/stats.html',
|
|
404
|
+
open: true,
|
|
405
|
+
}),
|
|
406
|
+
],
|
|
407
|
+
build: {
|
|
408
|
+
rollupOptions: {
|
|
409
|
+
output: {
|
|
410
|
+
manualChunks: {
|
|
411
|
+
vendor: ['react', 'react-dom'],
|
|
412
|
+
router: ['react-router-dom'],
|
|
413
|
+
ui: ['@radix-ui/react-dialog', '@radix-ui/react-dropdown-menu'],
|
|
414
|
+
},
|
|
415
|
+
},
|
|
416
|
+
},
|
|
417
|
+
chunkSizeWarningLimit: 1000,
|
|
418
|
+
},
|
|
419
|
+
server: {
|
|
420
|
+
hmr: {
|
|
421
|
+
overlay: true,
|
|
422
|
+
},
|
|
423
|
+
},
|
|
424
|
+
});
|
|
425
|
+
```
|
|
426
|
+
|
|
427
|
+
### Memory Management
|
|
428
|
+
|
|
429
|
+
```typescript
|
|
430
|
+
// Efficient state management with useReducer
|
|
431
|
+
interface State {
|
|
432
|
+
items: Item[];
|
|
433
|
+
filter: string;
|
|
434
|
+
loading: boolean;
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
type Action =
|
|
438
|
+
| { type: 'SET_ITEMS'; payload: Item[] }
|
|
439
|
+
| { type: 'SET_FILTER'; payload: string }
|
|
440
|
+
| { type: 'SET_LOADING'; payload: boolean };
|
|
441
|
+
|
|
442
|
+
function itemsReducer(state: State, action: Action): State {
|
|
443
|
+
switch (action.type) {
|
|
444
|
+
case 'SET_ITEMS':
|
|
445
|
+
return { ...state, items: action.payload, loading: false };
|
|
446
|
+
case 'SET_FILTER':
|
|
447
|
+
return { ...state, filter: action.payload };
|
|
448
|
+
case 'SET_LOADING':
|
|
449
|
+
return { ...state, loading: action.payload };
|
|
450
|
+
default:
|
|
451
|
+
return state;
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
// Memoized components for performance
|
|
456
|
+
import { memo, useMemo, useCallback } from 'react';
|
|
457
|
+
|
|
458
|
+
interface ExpensiveComponentProps {
|
|
459
|
+
data: number[];
|
|
460
|
+
onItemClick: (id: number) => void;
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
const ExpensiveComponent = memo<ExpensiveComponentProps>(({ data, onItemClick }) => {
|
|
464
|
+
const processedData = useMemo(() => {
|
|
465
|
+
return data.map(item => ({
|
|
466
|
+
...item,
|
|
467
|
+
processed: expensiveCalculation(item),
|
|
468
|
+
}));
|
|
469
|
+
}, [data]);
|
|
470
|
+
|
|
471
|
+
const handleClick = useCallback((id: number) => {
|
|
472
|
+
onItemClick(id);
|
|
473
|
+
}, [onItemClick]);
|
|
474
|
+
|
|
475
|
+
return (
|
|
476
|
+
<div>
|
|
477
|
+
{processedData.map(item => (
|
|
478
|
+
<Item key={item.id} item={item} onClick={handleClick} />
|
|
479
|
+
))}
|
|
480
|
+
</div>
|
|
481
|
+
);
|
|
482
|
+
});
|
|
483
|
+
```
|
|
484
|
+
|
|
485
|
+
## Testing Strategies
|
|
486
|
+
|
|
487
|
+
### Vitest Configuration
|
|
488
|
+
|
|
489
|
+
```typescript
|
|
490
|
+
// vitest.config.ts
|
|
491
|
+
import { defineConfig } from 'vitest/config';
|
|
492
|
+
import react from '@vitejs/plugin-react-swc';
|
|
493
|
+
import path from 'path';
|
|
494
|
+
|
|
495
|
+
export default defineConfig({
|
|
496
|
+
plugins: [react()],
|
|
497
|
+
test: {
|
|
498
|
+
globals: true,
|
|
499
|
+
environment: 'jsdom',
|
|
500
|
+
setupFiles: ['./tests/setup.ts'],
|
|
501
|
+
coverage: {
|
|
502
|
+
provider: 'v8',
|
|
503
|
+
reporter: ['text', 'json', 'html'],
|
|
504
|
+
exclude: [
|
|
505
|
+
'node_modules/',
|
|
506
|
+
'tests/',
|
|
507
|
+
'**/*.d.ts',
|
|
508
|
+
'**/*.config.*',
|
|
509
|
+
'dist/',
|
|
510
|
+
],
|
|
511
|
+
},
|
|
512
|
+
},
|
|
513
|
+
resolve: {
|
|
514
|
+
alias: {
|
|
515
|
+
'@': path.resolve(__dirname, './src'),
|
|
516
|
+
},
|
|
517
|
+
},
|
|
518
|
+
});
|
|
519
|
+
```
|
|
520
|
+
|
|
521
|
+
### Type-Safe Testing Patterns
|
|
522
|
+
|
|
523
|
+
```typescript
|
|
524
|
+
// Component testing with Testing Library
|
|
525
|
+
import { render, screen, fireEvent, waitFor } from '@testing-library/react';
|
|
526
|
+
import { vi, type MockedFunction } from 'vitest';
|
|
527
|
+
import { Button } from './Button';
|
|
528
|
+
|
|
529
|
+
describe('Button', () => {
|
|
530
|
+
it('renders with correct variant styles', () => {
|
|
531
|
+
render(
|
|
532
|
+
<Button variant="primary" size="md" onClick={vi.fn()}>
|
|
533
|
+
Click me
|
|
534
|
+
</Button>
|
|
535
|
+
);
|
|
536
|
+
|
|
537
|
+
const button = screen.getByRole('button', { name: 'Click me' });
|
|
538
|
+
expect(button).toBeInTheDocument();
|
|
539
|
+
expect(button).toHaveClass('bg-blue-600', 'text-white');
|
|
540
|
+
});
|
|
541
|
+
|
|
542
|
+
it('handles click events', async () => {
|
|
543
|
+
const handleClick = vi.fn();
|
|
544
|
+
render(
|
|
545
|
+
<Button variant="secondary" size="sm" onClick={handleClick}>
|
|
546
|
+
Submit
|
|
547
|
+
</Button>
|
|
548
|
+
);
|
|
549
|
+
|
|
550
|
+
const button = screen.getByRole('button', { name: 'Submit' });
|
|
551
|
+
fireEvent.click(button);
|
|
552
|
+
|
|
553
|
+
expect(handleClick).toHaveBeenCalledTimes(1);
|
|
554
|
+
});
|
|
555
|
+
|
|
556
|
+
it('can be triggered via ref', () => {
|
|
557
|
+
const handleClick = vi.fn();
|
|
558
|
+
const ref = { current: null };
|
|
559
|
+
|
|
560
|
+
render(
|
|
561
|
+
<Button variant="primary" size="md" onClick={handleClick} ref={ref}>
|
|
562
|
+
Click via ref
|
|
563
|
+
</Button>
|
|
564
|
+
);
|
|
565
|
+
|
|
566
|
+
// TypeScript should infer the correct ref type
|
|
567
|
+
if (ref.current) {
|
|
568
|
+
ref.current.click();
|
|
569
|
+
}
|
|
570
|
+
|
|
571
|
+
expect(handleClick).toHaveBeenCalledTimes(1);
|
|
572
|
+
});
|
|
573
|
+
});
|
|
574
|
+
|
|
575
|
+
// API testing with MSW
|
|
576
|
+
import { rest } from 'msw';
|
|
577
|
+
import { setupServer } from 'msw/node';
|
|
578
|
+
import { fetchUser } from './api';
|
|
579
|
+
|
|
580
|
+
const server = setupServer(
|
|
581
|
+
rest.get('/api/users/1', (req, res, ctx) => {
|
|
582
|
+
return res(
|
|
583
|
+
ctx.json({
|
|
584
|
+
id: 1,
|
|
585
|
+
name: 'John Doe',
|
|
586
|
+
email: 'john@example.com',
|
|
587
|
+
})
|
|
588
|
+
);
|
|
589
|
+
})
|
|
590
|
+
);
|
|
591
|
+
|
|
592
|
+
beforeAll(() => server.listen());
|
|
593
|
+
afterEach(() => server.resetHandlers());
|
|
594
|
+
afterAll(() => server.close());
|
|
595
|
+
|
|
596
|
+
describe('fetchUser', () => {
|
|
597
|
+
it('fetches user data successfully', async () => {
|
|
598
|
+
const userId = createUserId('1');
|
|
599
|
+
const result = await fetchUser(userId);
|
|
600
|
+
|
|
601
|
+
if (result.success) {
|
|
602
|
+
expect(result.data.name).toBe('John Doe');
|
|
603
|
+
expect(result.data.email).toBe('john@example.com');
|
|
604
|
+
} else {
|
|
605
|
+
fail('Expected successful fetch');
|
|
606
|
+
}
|
|
607
|
+
});
|
|
608
|
+
});
|
|
609
|
+
```
|
|
610
|
+
|
|
611
|
+
### E2E Testing with Playwright
|
|
612
|
+
|
|
613
|
+
```typescript
|
|
614
|
+
// tests/e2e/user-journey.spec.ts
|
|
615
|
+
import { test, expect, type Page } from '@playwright/test';
|
|
616
|
+
|
|
617
|
+
test.describe('User Authentication Flow', () => {
|
|
618
|
+
test('should allow user to sign up and log in', async ({ page }) => {
|
|
619
|
+
// Sign up
|
|
620
|
+
await page.goto('/signup');
|
|
621
|
+
|
|
622
|
+
await page.fill('[data-testid=email-input]', 'user@example.com');
|
|
623
|
+
await page.fill('[data-testid=password-input]', 'securepassword123');
|
|
624
|
+
await page.fill('[data-testid=name-input]', 'Test User');
|
|
625
|
+
|
|
626
|
+
await page.click('[data-testid=signup-button]');
|
|
627
|
+
|
|
628
|
+
// Should redirect to dashboard
|
|
629
|
+
await expect(page).toHaveURL('/dashboard');
|
|
630
|
+
await expect(page.locator('[data-testid=user-name]')).toHaveText('Test User');
|
|
631
|
+
|
|
632
|
+
// Log out
|
|
633
|
+
await page.click('[data-testid=logout-button]');
|
|
634
|
+
|
|
635
|
+
// Log in
|
|
636
|
+
await page.goto('/login');
|
|
637
|
+
await page.fill('[data-testid=email-input]', 'user@example.com');
|
|
638
|
+
await page.fill('[data-testid=password-input]', 'securepassword123');
|
|
639
|
+
await page.click('[data-testid=login-button]');
|
|
640
|
+
|
|
641
|
+
// Should be back at dashboard
|
|
642
|
+
await expect(page).toHaveURL('/dashboard');
|
|
643
|
+
});
|
|
644
|
+
|
|
645
|
+
test('should show validation errors for invalid input', async ({ page }) => {
|
|
646
|
+
await page.goto('/signup');
|
|
647
|
+
|
|
648
|
+
// Try to submit with empty fields
|
|
649
|
+
await page.click('[data-testid=signup-button]');
|
|
650
|
+
|
|
651
|
+
await expect(page.locator('[data-testid=email-error]')).toBeVisible();
|
|
652
|
+
await expect(page.locator('[data-testid=password-error]')).toBeVisible();
|
|
653
|
+
await expect(page.locator('[data-testid=name-error]')).toBeVisible();
|
|
654
|
+
});
|
|
655
|
+
});
|
|
656
|
+
```
|
|
657
|
+
|
|
658
|
+
## Security Best Practices
|
|
659
|
+
|
|
660
|
+
### Input Validation and Sanitization
|
|
661
|
+
|
|
662
|
+
```typescript
|
|
663
|
+
// Type-safe validation with Zod
|
|
664
|
+
import { z } from 'zod';
|
|
665
|
+
|
|
666
|
+
const UserSchema = z.object({
|
|
667
|
+
name: z.string().min(1).max(100).trim(),
|
|
668
|
+
email: z.string().email(),
|
|
669
|
+
age: z.number().min(13).max(120),
|
|
670
|
+
bio: z.string().max(1000).optional(),
|
|
671
|
+
});
|
|
672
|
+
|
|
673
|
+
type User = z.infer<typeof UserSchema>;
|
|
674
|
+
|
|
675
|
+
// API route validation
|
|
676
|
+
export async function POST(request: Request) {
|
|
677
|
+
try {
|
|
678
|
+
const body = await request.json();
|
|
679
|
+
const validatedUser = UserSchema.parse(body);
|
|
680
|
+
|
|
681
|
+
// Process validated data
|
|
682
|
+
await createUser(validatedUser);
|
|
683
|
+
|
|
684
|
+
return Response.json({ success: true }, { status: 201 });
|
|
685
|
+
} catch (error) {
|
|
686
|
+
if (error instanceof z.ZodError) {
|
|
687
|
+
return Response.json(
|
|
688
|
+
{
|
|
689
|
+
success: false,
|
|
690
|
+
errors: error.flatten().fieldErrors
|
|
691
|
+
},
|
|
692
|
+
{ status: 400 }
|
|
693
|
+
);
|
|
694
|
+
}
|
|
695
|
+
|
|
696
|
+
return Response.json(
|
|
697
|
+
{ success: false, error: 'Internal server error' },
|
|
698
|
+
{ status: 500 }
|
|
699
|
+
);
|
|
700
|
+
}
|
|
701
|
+
}
|
|
702
|
+
|
|
703
|
+
// XSS prevention
|
|
704
|
+
function sanitizeHtml(input: string): string {
|
|
705
|
+
// Use DOMPurify or similar library
|
|
706
|
+
return input.replace(/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi, '');
|
|
707
|
+
}
|
|
708
|
+
|
|
709
|
+
// CSRF protection
|
|
710
|
+
function getCSRFToken(): string {
|
|
711
|
+
const meta = document.querySelector('meta[name="csrf-token"]');
|
|
712
|
+
return meta?.getAttribute('content') || '';
|
|
713
|
+
}
|
|
714
|
+
|
|
715
|
+
// Secure API client
|
|
716
|
+
class SecureApiClient {
|
|
717
|
+
private baseUrl: string;
|
|
718
|
+
private csrfToken: string;
|
|
719
|
+
|
|
720
|
+
constructor(baseUrl: string) {
|
|
721
|
+
this.baseUrl = baseUrl;
|
|
722
|
+
this.csrfToken = getCSRFToken();
|
|
723
|
+
}
|
|
724
|
+
|
|
725
|
+
async post<T>(endpoint: string, data: unknown): Promise<T> {
|
|
726
|
+
const response = await fetch(`${this.baseUrl}${endpoint}`, {
|
|
727
|
+
method: 'POST',
|
|
728
|
+
headers: {
|
|
729
|
+
'Content-Type': 'application/json',
|
|
730
|
+
'X-CSRF-Token': this.csrfToken,
|
|
731
|
+
},
|
|
732
|
+
body: JSON.stringify(data),
|
|
733
|
+
});
|
|
734
|
+
|
|
735
|
+
if (!response.ok) {
|
|
736
|
+
throw new Error(`HTTP error! status: ${response.status}`);
|
|
737
|
+
}
|
|
738
|
+
|
|
739
|
+
return response.json() as Promise<T>;
|
|
740
|
+
}
|
|
741
|
+
}
|
|
742
|
+
```
|
|
743
|
+
|
|
744
|
+
### Authentication and Authorization
|
|
745
|
+
|
|
746
|
+
```typescript
|
|
747
|
+
// JWT-based authentication
|
|
748
|
+
interface JWTPayload {
|
|
749
|
+
userId: string;
|
|
750
|
+
email: string;
|
|
751
|
+
role: 'user' | 'admin';
|
|
752
|
+
exp: number;
|
|
753
|
+
}
|
|
754
|
+
|
|
755
|
+
class AuthService {
|
|
756
|
+
private static readonly TOKEN_KEY = 'auth_token';
|
|
757
|
+
|
|
758
|
+
static setToken(token: string): void {
|
|
759
|
+
localStorage.setItem(this.TOKEN_KEY, token);
|
|
760
|
+
}
|
|
761
|
+
|
|
762
|
+
static getToken(): string | null {
|
|
763
|
+
return localStorage.getItem(this.TOKEN_KEY);
|
|
764
|
+
}
|
|
765
|
+
|
|
766
|
+
static removeToken(): void {
|
|
767
|
+
localStorage.removeItem(this.TOKEN_KEY);
|
|
768
|
+
}
|
|
769
|
+
|
|
770
|
+
static isTokenExpired(token: string): boolean {
|
|
771
|
+
try {
|
|
772
|
+
const payload = JSON.parse(atob(token.split('.')[1])) as JWTPayload;
|
|
773
|
+
return Date.now() >= payload.exp * 1000;
|
|
774
|
+
} catch {
|
|
775
|
+
return true;
|
|
776
|
+
}
|
|
777
|
+
}
|
|
778
|
+
|
|
779
|
+
static getCurrentUser(): JWTPayload | null {
|
|
780
|
+
const token = this.getToken();
|
|
781
|
+
if (!token || this.isTokenExpired(token)) {
|
|
782
|
+
return null;
|
|
783
|
+
}
|
|
784
|
+
|
|
785
|
+
try {
|
|
786
|
+
return JSON.parse(atob(token.split('.')[1])) as JWTPayload;
|
|
787
|
+
} catch {
|
|
788
|
+
return null;
|
|
789
|
+
}
|
|
790
|
+
}
|
|
791
|
+
}
|
|
792
|
+
|
|
793
|
+
// Protected routes
|
|
794
|
+
interface ProtectedRouteProps {
|
|
795
|
+
children: React.ReactNode;
|
|
796
|
+
requiredRole?: 'user' | 'admin';
|
|
797
|
+
}
|
|
798
|
+
|
|
799
|
+
function ProtectedRoute({ children, requiredRole = 'user' }: ProtectedRouteProps) {
|
|
800
|
+
const user = AuthService.getCurrentUser();
|
|
801
|
+
|
|
802
|
+
if (!user) {
|
|
803
|
+
return <Navigate to="/login" replace />;
|
|
804
|
+
}
|
|
805
|
+
|
|
806
|
+
if (requiredRole === 'admin' && user.role !== 'admin') {
|
|
807
|
+
return <Navigate to="/unauthorized" replace />;
|
|
808
|
+
}
|
|
809
|
+
|
|
810
|
+
return <>{children}</>;
|
|
811
|
+
}
|
|
812
|
+
|
|
813
|
+
// API middleware
|
|
814
|
+
function withAuth<T extends unknown[], R>(
|
|
815
|
+
handler: (...args: T) => Promise<R>
|
|
816
|
+
) {
|
|
817
|
+
return async (...args: T): Promise<R> => {
|
|
818
|
+
const token = AuthService.getToken();
|
|
819
|
+
|
|
820
|
+
if (!token || AuthService.isTokenExpired(token)) {
|
|
821
|
+
throw new Error('Unauthorized');
|
|
822
|
+
}
|
|
823
|
+
|
|
824
|
+
return handler(...args);
|
|
825
|
+
};
|
|
826
|
+
}
|
|
827
|
+
```
|
|
828
|
+
|
|
829
|
+
## Integration Patterns
|
|
830
|
+
|
|
831
|
+
### Full-Stack Type Safety with tRPC
|
|
832
|
+
|
|
833
|
+
```typescript
|
|
834
|
+
// server/router.ts
|
|
835
|
+
import { initTRPC } from '@trpc/server';
|
|
836
|
+
import { z } from 'zod';
|
|
837
|
+
import type { CreateHTTPContextOptions } from '@trpc/server/adapters/standalone';
|
|
838
|
+
|
|
839
|
+
const t = initTRPC.context<CreateHTTPContextOptions>().create();
|
|
840
|
+
|
|
841
|
+
export const appRouter = t.router({
|
|
842
|
+
getUser: t.procedure
|
|
843
|
+
.input(z.object({ id: z.string() }))
|
|
844
|
+
.query(async ({ input, ctx }) => {
|
|
845
|
+
const user = await ctx.db.user.findUnique({
|
|
846
|
+
where: { id: input.id },
|
|
847
|
+
});
|
|
848
|
+
return user;
|
|
849
|
+
}),
|
|
850
|
+
|
|
851
|
+
createUser: t.procedure
|
|
852
|
+
.input(z.object({
|
|
853
|
+
name: z.string().min(1),
|
|
854
|
+
email: z.string().email(),
|
|
855
|
+
}))
|
|
856
|
+
.mutation(async ({ input, ctx }) => {
|
|
857
|
+
const user = await ctx.db.user.create({
|
|
858
|
+
data: input,
|
|
859
|
+
});
|
|
860
|
+
return user;
|
|
861
|
+
}),
|
|
862
|
+
});
|
|
863
|
+
|
|
864
|
+
export type AppRouter = typeof appRouter;
|
|
865
|
+
|
|
866
|
+
// client/trpc.ts
|
|
867
|
+
import { createTRPCProxyClient, httpBatchLink } from '@trpc/client';
|
|
868
|
+
import type { AppRouter } from '../server/router';
|
|
869
|
+
|
|
870
|
+
const trpc = createTRPCProxyClient<AppRouter>({
|
|
871
|
+
links: [
|
|
872
|
+
httpBatchLink({
|
|
873
|
+
url: 'http://localhost:3000/trpc',
|
|
874
|
+
}),
|
|
875
|
+
],
|
|
876
|
+
});
|
|
877
|
+
|
|
878
|
+
// Usage in React component
|
|
879
|
+
function UserProfile({ userId }: { userId: string }) {
|
|
880
|
+
const { data: user, isLoading } = trpc.getUser.useQuery({ id: userId });
|
|
881
|
+
const createUser = trpc.createUser.useMutation();
|
|
882
|
+
|
|
883
|
+
if (isLoading) return <div>Loading...</div>;
|
|
884
|
+
|
|
885
|
+
return (
|
|
886
|
+
<div>
|
|
887
|
+
<h1>{user?.name}</h1>
|
|
888
|
+
<p>{user?.email}</p>
|
|
889
|
+
<button
|
|
890
|
+
onClick={() => createUser.mutate({
|
|
891
|
+
name: 'New User',
|
|
892
|
+
email: 'new@example.com',
|
|
893
|
+
})}
|
|
894
|
+
>
|
|
895
|
+
Create User
|
|
896
|
+
</button>
|
|
897
|
+
</div>
|
|
898
|
+
);
|
|
899
|
+
}
|
|
62
900
|
```
|
|
63
901
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
902
|
+
### Database Integration with Prisma
|
|
903
|
+
|
|
904
|
+
```typescript
|
|
905
|
+
// schema.prisma
|
|
906
|
+
model User {
|
|
907
|
+
id String @id @default(cuid())
|
|
908
|
+
email String @unique
|
|
909
|
+
name String
|
|
910
|
+
createdAt DateTime @default(now())
|
|
911
|
+
updatedAt DateTime @updatedAt
|
|
912
|
+
posts Post[]
|
|
913
|
+
}
|
|
914
|
+
|
|
915
|
+
model Post {
|
|
916
|
+
id String @id @default(cuid())
|
|
917
|
+
title String
|
|
918
|
+
content String
|
|
919
|
+
published Boolean @default(false)
|
|
920
|
+
author User @relation(fields: [authorId], references: [id])
|
|
921
|
+
authorId String
|
|
922
|
+
createdAt DateTime @default(now())
|
|
923
|
+
updatedAt DateTime @updatedAt
|
|
924
|
+
}
|
|
925
|
+
|
|
926
|
+
// lib/db.ts
|
|
927
|
+
import { PrismaClient } from '@prisma/client';
|
|
68
928
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
929
|
+
const globalForPrisma = globalThis as unknown as {
|
|
930
|
+
prisma: PrismaClient | undefined;
|
|
931
|
+
};
|
|
72
932
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
933
|
+
export const prisma = globalForPrisma.prisma ?? new PrismaClient();
|
|
934
|
+
|
|
935
|
+
if (process.env.NODE_ENV !== 'production') globalForPrisma.prisma = prisma;
|
|
936
|
+
|
|
937
|
+
// API routes with type safety
|
|
938
|
+
import { z } from 'zod';
|
|
939
|
+
|
|
940
|
+
const createPostSchema = z.object({
|
|
941
|
+
title: z.string().min(1).max(200),
|
|
942
|
+
content: z.string().min(1),
|
|
943
|
+
authorId: z.string().cuid(),
|
|
944
|
+
});
|
|
945
|
+
|
|
946
|
+
export async function POST(request: Request) {
|
|
947
|
+
try {
|
|
948
|
+
const body = await request.json();
|
|
949
|
+
const { title, content, authorId } = createPostSchema.parse(body);
|
|
950
|
+
|
|
951
|
+
const post = await prisma.post.create({
|
|
952
|
+
data: {
|
|
953
|
+
title,
|
|
954
|
+
content,
|
|
955
|
+
authorId,
|
|
956
|
+
},
|
|
957
|
+
include: {
|
|
958
|
+
author: true,
|
|
959
|
+
},
|
|
960
|
+
});
|
|
961
|
+
|
|
962
|
+
return Response.json(post, { status: 201 });
|
|
963
|
+
} catch (error) {
|
|
964
|
+
if (error instanceof z.ZodError) {
|
|
965
|
+
return Response.json(
|
|
966
|
+
{ errors: error.flatten().fieldErrors },
|
|
967
|
+
{ status: 400 }
|
|
968
|
+
);
|
|
969
|
+
}
|
|
970
|
+
|
|
971
|
+
return Response.json(
|
|
972
|
+
{ error: 'Internal server error' },
|
|
973
|
+
{ status: 500 }
|
|
974
|
+
);
|
|
975
|
+
}
|
|
976
|
+
}
|
|
977
|
+
```
|
|
76
978
|
|
|
77
|
-
|
|
78
|
-
- Access to the project file is required using the Read/Grep tool.
|
|
79
|
-
- When used with `Skill("moai-foundation-langs")`, it is easy to share cross-language conventions.
|
|
979
|
+
### State Management with Zustand
|
|
80
980
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
981
|
+
```typescript
|
|
982
|
+
// store/userStore.ts
|
|
983
|
+
import { create } from 'zustand';
|
|
984
|
+
import { devtools, persist } from 'zustand/middleware';
|
|
84
985
|
|
|
85
|
-
|
|
86
|
-
|
|
986
|
+
interface User {
|
|
987
|
+
id: string;
|
|
988
|
+
name: string;
|
|
989
|
+
email: string;
|
|
990
|
+
}
|
|
87
991
|
|
|
88
|
-
|
|
992
|
+
interface UserStore {
|
|
993
|
+
user: User | null;
|
|
994
|
+
isLoading: boolean;
|
|
995
|
+
login: (email: string, password: string) => Promise<void>;
|
|
996
|
+
logout: () => void;
|
|
997
|
+
updateProfile: (updates: Partial<User>) => void;
|
|
998
|
+
}
|
|
999
|
+
|
|
1000
|
+
export const useUserStore = create<UserStore>()(
|
|
1001
|
+
devtools(
|
|
1002
|
+
persist(
|
|
1003
|
+
(set, get) => ({
|
|
1004
|
+
user: null,
|
|
1005
|
+
isLoading: false,
|
|
1006
|
+
|
|
1007
|
+
login: async (email: string, password: string) => {
|
|
1008
|
+
set({ isLoading: true });
|
|
1009
|
+
try {
|
|
1010
|
+
const response = await fetch('/api/auth/login', {
|
|
1011
|
+
method: 'POST',
|
|
1012
|
+
headers: { 'Content-Type': 'application/json' },
|
|
1013
|
+
body: JSON.stringify({ email, password }),
|
|
1014
|
+
});
|
|
1015
|
+
|
|
1016
|
+
if (response.ok) {
|
|
1017
|
+
const user = await response.json();
|
|
1018
|
+
set({ user, isLoading: false });
|
|
1019
|
+
} else {
|
|
1020
|
+
throw new Error('Login failed');
|
|
1021
|
+
}
|
|
1022
|
+
} catch (error) {
|
|
1023
|
+
set({ isLoading: false });
|
|
1024
|
+
throw error;
|
|
1025
|
+
}
|
|
1026
|
+
},
|
|
1027
|
+
|
|
1028
|
+
logout: () => {
|
|
1029
|
+
set({ user: null });
|
|
1030
|
+
},
|
|
1031
|
+
|
|
1032
|
+
updateProfile: (updates) => {
|
|
1033
|
+
const currentUser = get().user;
|
|
1034
|
+
if (currentUser) {
|
|
1035
|
+
set({ user: { ...currentUser, ...updates } });
|
|
1036
|
+
}
|
|
1037
|
+
},
|
|
1038
|
+
}),
|
|
1039
|
+
{
|
|
1040
|
+
name: 'user-storage',
|
|
1041
|
+
partialize: (state) => ({ user: state.user }),
|
|
1042
|
+
}
|
|
1043
|
+
)
|
|
1044
|
+
)
|
|
1045
|
+
);
|
|
1046
|
+
|
|
1047
|
+
// Usage in components
|
|
1048
|
+
function ProfilePage() {
|
|
1049
|
+
const { user, isLoading, updateProfile } = useUserStore();
|
|
1050
|
+
|
|
1051
|
+
if (isLoading) return <div>Loading...</div>;
|
|
1052
|
+
if (!user) return <div>Please log in</div>;
|
|
1053
|
+
|
|
1054
|
+
return (
|
|
1055
|
+
<div>
|
|
1056
|
+
<h1>Profile</h1>
|
|
1057
|
+
<p>Name: {user.name}</p>
|
|
1058
|
+
<p>Email: {user.email}</p>
|
|
1059
|
+
<button
|
|
1060
|
+
onClick={() => updateProfile({ name: 'Updated Name' })}
|
|
1061
|
+
>
|
|
1062
|
+
Update Name
|
|
1063
|
+
</button>
|
|
1064
|
+
</div>
|
|
1065
|
+
);
|
|
1066
|
+
}
|
|
1067
|
+
```
|
|
1068
|
+
|
|
1069
|
+
## Modern Development Workflow
|
|
1070
|
+
|
|
1071
|
+
### Configuration Files
|
|
1072
|
+
|
|
1073
|
+
```json
|
|
1074
|
+
// package.json
|
|
1075
|
+
{
|
|
1076
|
+
"name": "my-typescript-app",
|
|
1077
|
+
"version": "0.1.0",
|
|
1078
|
+
"type": "module",
|
|
1079
|
+
"scripts": {
|
|
1080
|
+
"dev": "next dev --turbopack",
|
|
1081
|
+
"build": "next build",
|
|
1082
|
+
"start": "next start",
|
|
1083
|
+
"lint": "eslint . --max-warnings 0",
|
|
1084
|
+
"lint:fix": "eslint . --fix",
|
|
1085
|
+
"type-check": "tsc --noEmit",
|
|
1086
|
+
"test": "vitest",
|
|
1087
|
+
"test:ui": "vitest --ui",
|
|
1088
|
+
"test:e2e": "playwright test",
|
|
1089
|
+
"test:e2e:ui": "playwright test --ui"
|
|
1090
|
+
},
|
|
1091
|
+
"dependencies": {
|
|
1092
|
+
"next": "^15.0.0",
|
|
1093
|
+
"react": "^19.0.0",
|
|
1094
|
+
"react-dom": "^19.0.0",
|
|
1095
|
+
"@trpc/client": "^11.0.0",
|
|
1096
|
+
"@trpc/server": "^11.0.0",
|
|
1097
|
+
"@trpc/react-query": "^11.0.0",
|
|
1098
|
+
"zod": "^3.23.0",
|
|
1099
|
+
"zustand": "^5.0.0"
|
|
1100
|
+
},
|
|
1101
|
+
"devDependencies": {
|
|
1102
|
+
"@types/node": "^22.0.0",
|
|
1103
|
+
"@types/react": "^19.0.0",
|
|
1104
|
+
"@types/react-dom": "^19.0.0",
|
|
1105
|
+
"typescript": "^5.6.0",
|
|
1106
|
+
"eslint": "^9.0.0",
|
|
1107
|
+
"prettier": "^3.3.0",
|
|
1108
|
+
"vitest": "^2.0.0",
|
|
1109
|
+
"@testing-library/react": "^16.0.0",
|
|
1110
|
+
"playwright": "^1.48.0"
|
|
1111
|
+
}
|
|
1112
|
+
}
|
|
1113
|
+
```
|
|
1114
|
+
|
|
1115
|
+
```json
|
|
1116
|
+
// tsconfig.json
|
|
1117
|
+
{
|
|
1118
|
+
"compilerOptions": {
|
|
1119
|
+
"target": "ES2022",
|
|
1120
|
+
"lib": ["dom", "dom.iterable", "ES2022"],
|
|
1121
|
+
"allowJs": true,
|
|
1122
|
+
"skipLibCheck": true,
|
|
1123
|
+
"strict": true,
|
|
1124
|
+
"forceConsistentCasingInFileNames": true,
|
|
1125
|
+
"noEmit": true,
|
|
1126
|
+
"esModuleInterop": true,
|
|
1127
|
+
"module": "ESNext",
|
|
1128
|
+
"moduleResolution": "bundler",
|
|
1129
|
+
"resolveJsonModule": true,
|
|
1130
|
+
"isolatedModules": true,
|
|
1131
|
+
"jsx": "preserve",
|
|
1132
|
+
"incremental": true,
|
|
1133
|
+
"plugins": [
|
|
1134
|
+
{
|
|
1135
|
+
"name": "next"
|
|
1136
|
+
}
|
|
1137
|
+
],
|
|
1138
|
+
"baseUrl": ".",
|
|
1139
|
+
"paths": {
|
|
1140
|
+
"@/*": ["./src/*"],
|
|
1141
|
+
"@/components/*": ["./src/components/*"],
|
|
1142
|
+
"@/lib/*": ["./src/lib/*"],
|
|
1143
|
+
"@/types/*": ["./src/types/*"]
|
|
1144
|
+
}
|
|
1145
|
+
},
|
|
1146
|
+
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
|
|
1147
|
+
"exclude": ["node_modules"]
|
|
1148
|
+
}
|
|
1149
|
+
```
|
|
1150
|
+
|
|
1151
|
+
```javascript
|
|
1152
|
+
// eslint.config.js (ESLint Flat Config)
|
|
1153
|
+
import js from '@eslint/js';
|
|
1154
|
+
import typescript from '@typescript-eslint/eslint-plugin';
|
|
1155
|
+
import typescriptParser from '@typescript-eslint/parser';
|
|
1156
|
+
import react from 'eslint-plugin-react';
|
|
1157
|
+
import reactHooks from 'eslint-plugin-react-hooks';
|
|
1158
|
+
|
|
1159
|
+
export default [
|
|
1160
|
+
js.configs.recommended,
|
|
1161
|
+
{
|
|
1162
|
+
files: ['**/*.{ts,tsx}'],
|
|
1163
|
+
languageOptions: {
|
|
1164
|
+
parser: typescriptParser,
|
|
1165
|
+
parserOptions: {
|
|
1166
|
+
ecmaVersion: 'latest',
|
|
1167
|
+
sourceType: 'module',
|
|
1168
|
+
ecmaFeatures: {
|
|
1169
|
+
jsx: true,
|
|
1170
|
+
},
|
|
1171
|
+
},
|
|
1172
|
+
},
|
|
1173
|
+
plugins: {
|
|
1174
|
+
'@typescript-eslint': typescript,
|
|
1175
|
+
'react': react,
|
|
1176
|
+
'react-hooks': reactHooks,
|
|
1177
|
+
},
|
|
1178
|
+
rules: {
|
|
1179
|
+
...typescript.configs.recommended.rules,
|
|
1180
|
+
'@typescript-eslint/no-unused-vars': 'error',
|
|
1181
|
+
'@typescript-eslint/no-explicit-any': 'warn',
|
|
1182
|
+
'react/react-in-jsx-scope': 'off',
|
|
1183
|
+
'react-hooks/rules-of-hooks': 'error',
|
|
1184
|
+
'react-hooks/exhaustive-deps': 'warn',
|
|
1185
|
+
},
|
|
1186
|
+
settings: {
|
|
1187
|
+
react: {
|
|
1188
|
+
version: 'detect',
|
|
1189
|
+
},
|
|
1190
|
+
},
|
|
1191
|
+
},
|
|
1192
|
+
];
|
|
1193
|
+
```
|
|
1194
|
+
|
|
1195
|
+
### CI/CD Pipeline
|
|
1196
|
+
|
|
1197
|
+
```yaml
|
|
1198
|
+
# .github/workflows/ci.yml
|
|
1199
|
+
name: CI
|
|
1200
|
+
|
|
1201
|
+
on:
|
|
1202
|
+
push:
|
|
1203
|
+
branches: [main, develop]
|
|
1204
|
+
pull_request:
|
|
1205
|
+
branches: [main, develop]
|
|
1206
|
+
|
|
1207
|
+
jobs:
|
|
1208
|
+
test:
|
|
1209
|
+
runs-on: ubuntu-latest
|
|
1210
|
+
|
|
1211
|
+
strategy:
|
|
1212
|
+
matrix:
|
|
1213
|
+
node-version: [20.x, 22.x]
|
|
1214
|
+
|
|
1215
|
+
steps:
|
|
1216
|
+
- uses: actions/checkout@v4
|
|
1217
|
+
|
|
1218
|
+
- name: Setup Node.js ${{ matrix.node-version }}
|
|
1219
|
+
uses: actions/setup-node@v4
|
|
1220
|
+
with:
|
|
1221
|
+
node-version: ${{ matrix.node-version }}
|
|
1222
|
+
cache: 'pnpm'
|
|
1223
|
+
|
|
1224
|
+
- name: Install pnpm
|
|
1225
|
+
uses: pnpm/action-setup@v3
|
|
1226
|
+
with:
|
|
1227
|
+
version: 9
|
|
1228
|
+
|
|
1229
|
+
- name: Install dependencies
|
|
1230
|
+
run: pnpm install --frozen-lockfile
|
|
1231
|
+
|
|
1232
|
+
- name: Type check
|
|
1233
|
+
run: pnpm type-check
|
|
1234
|
+
|
|
1235
|
+
- name: Lint
|
|
1236
|
+
run: pnpm lint
|
|
1237
|
+
|
|
1238
|
+
- name: Test
|
|
1239
|
+
run: pnpm test
|
|
1240
|
+
|
|
1241
|
+
- name: E2E tests
|
|
1242
|
+
run: pnpm test:e2e
|
|
1243
|
+
|
|
1244
|
+
- name: Build
|
|
1245
|
+
run: pnpm build
|
|
1246
|
+
|
|
1247
|
+
- name: Upload coverage
|
|
1248
|
+
uses: codecov/codecov-action@v4
|
|
1249
|
+
with:
|
|
1250
|
+
file: ./coverage/lcov.info
|
|
1251
|
+
```
|
|
1252
|
+
|
|
1253
|
+
---
|
|
89
1254
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
1255
|
+
**Created by**: MoAI Language Skill Factory
|
|
1256
|
+
**Last Updated**: 2025-11-06
|
|
1257
|
+
**Version**: 2.0.0
|
|
1258
|
+
**TypeScript Target**: 5.6+ with latest language features
|
|
93
1259
|
|
|
94
|
-
|
|
95
|
-
- Enable automatic validation by matching your linter with the language's official style guide.
|
|
96
|
-
- Fix test/build pipelines with reproducible commands in CI.
|
|
1260
|
+
This skill provides comprehensive TypeScript development guidance with 2025 best practices, covering everything from basic type safety to advanced full-stack patterns and enterprise-grade applications.
|