devflow-kit 0.9.0 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +167 -29
- package/LICENSE +1 -1
- package/README.md +179 -310
- package/dist/cli.js +3 -1
- package/dist/commands/init.d.ts +21 -0
- package/dist/commands/init.js +311 -576
- package/dist/commands/list.d.ts +3 -0
- package/dist/commands/list.js +20 -0
- package/dist/commands/uninstall.d.ts +10 -0
- package/dist/commands/uninstall.js +351 -78
- package/dist/plugins.d.ts +46 -0
- package/dist/plugins.js +162 -0
- package/dist/utils/cli.d.ts +5 -0
- package/dist/utils/cli.js +14 -0
- package/dist/utils/installer.d.ts +41 -0
- package/dist/utils/installer.js +177 -0
- package/dist/utils/paths.d.ts +10 -0
- package/dist/utils/paths.js +23 -3
- package/dist/utils/post-install.d.ts +68 -0
- package/dist/utils/post-install.js +427 -0
- package/dist/utils/safe-delete-install.d.ts +22 -0
- package/dist/utils/safe-delete-install.js +156 -0
- package/dist/utils/safe-delete.d.ts +12 -0
- package/dist/utils/safe-delete.js +83 -0
- package/package.json +18 -8
- package/plugins/devflow-audit-claude/.claude-plugin/plugin.json +7 -0
- package/plugins/devflow-audit-claude/README.md +46 -0
- package/plugins/devflow-audit-claude/agents/claude-md-auditor.md +134 -0
- package/plugins/devflow-audit-claude/commands/audit-claude.md +85 -0
- package/plugins/devflow-code-review/.claude-plugin/plugin.json +31 -0
- package/plugins/devflow-code-review/README.md +73 -0
- package/plugins/devflow-code-review/agents/git.md +272 -0
- package/plugins/devflow-code-review/agents/reviewer.md +119 -0
- package/plugins/devflow-code-review/agents/synthesizer.md +204 -0
- package/plugins/devflow-code-review/commands/code-review-teams.md +262 -0
- package/plugins/devflow-code-review/commands/code-review.md +141 -0
- package/plugins/devflow-code-review/skills/accessibility/SKILL.md +229 -0
- package/plugins/devflow-code-review/skills/accessibility/references/detection.md +171 -0
- package/plugins/devflow-code-review/skills/accessibility/references/patterns.md +670 -0
- package/plugins/devflow-code-review/skills/accessibility/references/violations.md +419 -0
- package/plugins/devflow-code-review/skills/agent-teams/SKILL.md +124 -0
- package/plugins/devflow-code-review/skills/agent-teams/references/cleanup.md +104 -0
- package/plugins/devflow-code-review/skills/agent-teams/references/communication.md +122 -0
- package/plugins/devflow-code-review/skills/agent-teams/references/team-patterns.md +217 -0
- package/plugins/devflow-code-review/skills/architecture-patterns/SKILL.md +153 -0
- package/plugins/devflow-code-review/skills/architecture-patterns/references/detection.md +337 -0
- package/plugins/devflow-code-review/skills/architecture-patterns/references/patterns.md +873 -0
- package/plugins/devflow-code-review/skills/architecture-patterns/references/violations.md +575 -0
- package/plugins/devflow-code-review/skills/complexity-patterns/SKILL.md +143 -0
- package/plugins/devflow-code-review/skills/complexity-patterns/references/detection.md +264 -0
- package/plugins/devflow-code-review/skills/complexity-patterns/references/patterns.md +487 -0
- package/plugins/devflow-code-review/skills/complexity-patterns/references/violations.md +361 -0
- package/plugins/devflow-code-review/skills/consistency-patterns/SKILL.md +140 -0
- package/plugins/devflow-code-review/skills/consistency-patterns/references/detection.md +207 -0
- package/plugins/devflow-code-review/skills/consistency-patterns/references/patterns.md +202 -0
- package/plugins/devflow-code-review/skills/consistency-patterns/references/violations.md +213 -0
- package/plugins/devflow-code-review/skills/database-patterns/SKILL.md +134 -0
- package/plugins/devflow-code-review/skills/database-patterns/references/detection.md +208 -0
- package/plugins/devflow-code-review/skills/database-patterns/references/patterns.md +394 -0
- package/plugins/devflow-code-review/skills/database-patterns/references/violations.md +332 -0
- package/plugins/devflow-code-review/skills/dependencies-patterns/SKILL.md +141 -0
- package/plugins/devflow-code-review/skills/dependencies-patterns/references/detection.md +181 -0
- package/plugins/devflow-code-review/skills/dependencies-patterns/references/patterns.md +225 -0
- package/plugins/devflow-code-review/skills/dependencies-patterns/references/violations.md +247 -0
- package/plugins/devflow-code-review/skills/documentation-patterns/SKILL.md +125 -0
- package/plugins/devflow-code-review/skills/documentation-patterns/references/detection.md +190 -0
- package/plugins/devflow-code-review/skills/documentation-patterns/references/patterns.md +189 -0
- package/plugins/devflow-code-review/skills/documentation-patterns/references/violations.md +163 -0
- package/plugins/devflow-code-review/skills/frontend-design/SKILL.md +254 -0
- package/plugins/devflow-code-review/skills/frontend-design/references/detection.md +184 -0
- package/plugins/devflow-code-review/skills/frontend-design/references/patterns.md +511 -0
- package/plugins/devflow-code-review/skills/frontend-design/references/violations.md +453 -0
- package/plugins/devflow-code-review/skills/performance-patterns/SKILL.md +154 -0
- package/plugins/devflow-code-review/skills/performance-patterns/references/detection.md +351 -0
- package/plugins/devflow-code-review/skills/performance-patterns/references/patterns.md +503 -0
- package/plugins/devflow-code-review/skills/performance-patterns/references/violations.md +354 -0
- package/plugins/devflow-code-review/skills/react/SKILL.md +276 -0
- package/plugins/devflow-code-review/skills/react/references/patterns.md +1331 -0
- package/plugins/devflow-code-review/skills/react/references/violations.md +565 -0
- package/plugins/devflow-code-review/skills/regression-patterns/SKILL.md +146 -0
- package/plugins/devflow-code-review/skills/regression-patterns/references/detection.md +237 -0
- package/plugins/devflow-code-review/skills/regression-patterns/references/patterns.md +226 -0
- package/plugins/devflow-code-review/skills/regression-patterns/references/violations.md +225 -0
- package/plugins/devflow-code-review/skills/review-methodology/SKILL.md +119 -0
- package/plugins/devflow-code-review/skills/review-methodology/references/patterns.md +186 -0
- package/plugins/devflow-code-review/skills/review-methodology/references/report-template.md +142 -0
- package/plugins/devflow-code-review/skills/review-methodology/references/violations.md +125 -0
- package/plugins/devflow-code-review/skills/security-patterns/SKILL.md +156 -0
- package/plugins/devflow-code-review/skills/security-patterns/references/detection.md +287 -0
- package/plugins/devflow-code-review/skills/security-patterns/references/patterns.md +507 -0
- package/plugins/devflow-code-review/skills/security-patterns/references/violations.md +237 -0
- package/plugins/devflow-code-review/skills/test-patterns/SKILL.md +183 -0
- package/plugins/devflow-code-review/skills/test-patterns/references/detection.md +149 -0
- package/plugins/devflow-code-review/skills/test-patterns/references/patterns.md +220 -0
- package/plugins/devflow-code-review/skills/test-patterns/references/report-template.md +108 -0
- package/plugins/devflow-code-review/skills/test-patterns/references/violations.md +221 -0
- package/plugins/devflow-core-skills/.claude-plugin/plugin.json +27 -0
- package/plugins/devflow-core-skills/README.md +50 -0
- package/plugins/devflow-core-skills/skills/accessibility/SKILL.md +229 -0
- package/plugins/devflow-core-skills/skills/accessibility/references/detection.md +171 -0
- package/plugins/devflow-core-skills/skills/accessibility/references/patterns.md +670 -0
- package/plugins/devflow-core-skills/skills/accessibility/references/violations.md +419 -0
- package/plugins/devflow-core-skills/skills/core-patterns/SKILL.md +162 -0
- package/plugins/devflow-core-skills/skills/core-patterns/references/checklist.md +276 -0
- package/plugins/devflow-core-skills/skills/core-patterns/references/code-smell-violations.md +144 -0
- package/plugins/devflow-core-skills/skills/core-patterns/references/detection.md +303 -0
- package/plugins/devflow-core-skills/skills/core-patterns/references/patterns.md +576 -0
- package/plugins/devflow-core-skills/skills/core-patterns/references/violations.md +369 -0
- package/plugins/devflow-core-skills/skills/docs-framework/SKILL.md +134 -0
- package/plugins/devflow-core-skills/skills/docs-framework/references/patterns.md +346 -0
- package/plugins/devflow-core-skills/skills/docs-framework/references/violations.md +221 -0
- package/plugins/devflow-core-skills/skills/frontend-design/SKILL.md +254 -0
- package/plugins/devflow-core-skills/skills/frontend-design/references/detection.md +184 -0
- package/plugins/devflow-core-skills/skills/frontend-design/references/patterns.md +511 -0
- package/plugins/devflow-core-skills/skills/frontend-design/references/violations.md +453 -0
- package/plugins/devflow-core-skills/skills/git-safety/SKILL.md +122 -0
- package/plugins/devflow-core-skills/skills/git-safety/references/detection.md +290 -0
- package/plugins/devflow-core-skills/skills/git-safety/references/patterns.md +289 -0
- package/plugins/devflow-core-skills/skills/git-safety/references/violations.md +18 -0
- package/plugins/devflow-core-skills/skills/git-workflow/SKILL.md +158 -0
- package/plugins/devflow-core-skills/skills/git-workflow/references/commit-patterns.md +115 -0
- package/plugins/devflow-core-skills/skills/git-workflow/references/commit-violations.md +77 -0
- package/plugins/devflow-core-skills/skills/git-workflow/references/pr-patterns.md +127 -0
- package/plugins/devflow-core-skills/skills/git-workflow/references/pr-violations.md +96 -0
- package/plugins/devflow-core-skills/skills/github-patterns/SKILL.md +153 -0
- package/plugins/devflow-core-skills/skills/github-patterns/references/patterns.md +572 -0
- package/plugins/devflow-core-skills/skills/github-patterns/references/violations.md +298 -0
- package/plugins/devflow-core-skills/skills/input-validation/SKILL.md +148 -0
- package/plugins/devflow-core-skills/skills/input-validation/references/detection.md +283 -0
- package/plugins/devflow-core-skills/skills/input-validation/references/patterns.md +361 -0
- package/plugins/devflow-core-skills/skills/input-validation/references/violations.md +224 -0
- package/plugins/devflow-core-skills/skills/react/SKILL.md +276 -0
- package/plugins/devflow-core-skills/skills/react/references/patterns.md +1331 -0
- package/plugins/devflow-core-skills/skills/react/references/violations.md +565 -0
- package/plugins/devflow-core-skills/skills/test-patterns/SKILL.md +183 -0
- package/plugins/devflow-core-skills/skills/test-patterns/references/detection.md +149 -0
- package/plugins/devflow-core-skills/skills/test-patterns/references/patterns.md +220 -0
- package/plugins/devflow-core-skills/skills/test-patterns/references/report-template.md +108 -0
- package/plugins/devflow-core-skills/skills/test-patterns/references/violations.md +221 -0
- package/plugins/devflow-core-skills/skills/typescript/SKILL.md +176 -0
- package/plugins/devflow-core-skills/skills/typescript/references/patterns.md +1105 -0
- package/plugins/devflow-core-skills/skills/typescript/references/violations.md +433 -0
- package/plugins/devflow-debug/.claude-plugin/plugin.json +18 -0
- package/plugins/devflow-debug/README.md +65 -0
- package/plugins/devflow-debug/agents/git.md +272 -0
- package/plugins/devflow-debug/commands/debug-teams.md +231 -0
- package/plugins/devflow-debug/commands/debug.md +160 -0
- package/plugins/devflow-debug/skills/agent-teams/SKILL.md +124 -0
- package/plugins/devflow-debug/skills/agent-teams/references/cleanup.md +104 -0
- package/plugins/devflow-debug/skills/agent-teams/references/communication.md +122 -0
- package/plugins/devflow-debug/skills/agent-teams/references/team-patterns.md +217 -0
- package/plugins/devflow-debug/skills/git-safety/SKILL.md +122 -0
- package/plugins/devflow-debug/skills/git-safety/references/detection.md +290 -0
- package/plugins/devflow-debug/skills/git-safety/references/patterns.md +289 -0
- package/plugins/devflow-debug/skills/git-safety/references/violations.md +18 -0
- package/plugins/devflow-implement/.claude-plugin/plugin.json +21 -0
- package/plugins/devflow-implement/README.md +71 -0
- package/plugins/devflow-implement/agents/coder.md +122 -0
- package/plugins/devflow-implement/agents/git.md +272 -0
- package/plugins/devflow-implement/agents/scrutinizer.md +80 -0
- package/plugins/devflow-implement/agents/shepherd.md +94 -0
- package/plugins/devflow-implement/agents/simplifier.md +62 -0
- package/plugins/devflow-implement/agents/skimmer.md +88 -0
- package/plugins/devflow-implement/agents/synthesizer.md +204 -0
- package/plugins/devflow-implement/agents/validator.md +86 -0
- package/plugins/devflow-implement/commands/implement-teams.md +608 -0
- package/plugins/devflow-implement/commands/implement.md +426 -0
- package/plugins/devflow-implement/skills/accessibility/SKILL.md +229 -0
- package/plugins/devflow-implement/skills/accessibility/references/detection.md +171 -0
- package/plugins/devflow-implement/skills/accessibility/references/patterns.md +670 -0
- package/plugins/devflow-implement/skills/accessibility/references/violations.md +419 -0
- package/plugins/devflow-implement/skills/agent-teams/SKILL.md +124 -0
- package/plugins/devflow-implement/skills/agent-teams/references/cleanup.md +104 -0
- package/plugins/devflow-implement/skills/agent-teams/references/communication.md +122 -0
- package/plugins/devflow-implement/skills/agent-teams/references/team-patterns.md +217 -0
- package/plugins/devflow-implement/skills/frontend-design/SKILL.md +254 -0
- package/plugins/devflow-implement/skills/frontend-design/references/detection.md +184 -0
- package/plugins/devflow-implement/skills/frontend-design/references/patterns.md +511 -0
- package/plugins/devflow-implement/skills/frontend-design/references/violations.md +453 -0
- package/plugins/devflow-implement/skills/implementation-patterns/SKILL.md +162 -0
- package/plugins/devflow-implement/skills/implementation-patterns/references/patterns.md +1063 -0
- package/plugins/devflow-implement/skills/implementation-patterns/references/violations.md +483 -0
- package/plugins/devflow-implement/skills/self-review/SKILL.md +149 -0
- package/plugins/devflow-implement/skills/self-review/references/patterns.md +405 -0
- package/plugins/devflow-implement/skills/self-review/references/report-template.md +253 -0
- package/plugins/devflow-implement/skills/self-review/references/violations.md +308 -0
- package/plugins/devflow-resolve/.claude-plugin/plugin.json +19 -0
- package/plugins/devflow-resolve/README.md +65 -0
- package/plugins/devflow-resolve/agents/git.md +272 -0
- package/plugins/devflow-resolve/agents/resolver.md +131 -0
- package/plugins/devflow-resolve/agents/simplifier.md +62 -0
- package/plugins/devflow-resolve/commands/resolve-teams.md +298 -0
- package/plugins/devflow-resolve/commands/resolve.md +237 -0
- package/plugins/devflow-resolve/skills/agent-teams/SKILL.md +124 -0
- package/plugins/devflow-resolve/skills/agent-teams/references/cleanup.md +104 -0
- package/plugins/devflow-resolve/skills/agent-teams/references/communication.md +122 -0
- package/plugins/devflow-resolve/skills/agent-teams/references/team-patterns.md +217 -0
- package/plugins/devflow-resolve/skills/implementation-patterns/SKILL.md +162 -0
- package/plugins/devflow-resolve/skills/implementation-patterns/references/patterns.md +1063 -0
- package/plugins/devflow-resolve/skills/implementation-patterns/references/violations.md +483 -0
- package/plugins/devflow-resolve/skills/security-patterns/SKILL.md +156 -0
- package/plugins/devflow-resolve/skills/security-patterns/references/detection.md +287 -0
- package/plugins/devflow-resolve/skills/security-patterns/references/patterns.md +507 -0
- package/plugins/devflow-resolve/skills/security-patterns/references/violations.md +237 -0
- package/plugins/devflow-self-review/.claude-plugin/plugin.json +7 -0
- package/plugins/devflow-self-review/README.md +38 -0
- package/plugins/devflow-self-review/agents/scrutinizer.md +80 -0
- package/plugins/devflow-self-review/agents/simplifier.md +62 -0
- package/plugins/devflow-self-review/agents/validator.md +86 -0
- package/plugins/devflow-self-review/commands/self-review.md +126 -0
- package/plugins/devflow-self-review/skills/core-patterns/SKILL.md +162 -0
- package/plugins/devflow-self-review/skills/core-patterns/references/checklist.md +276 -0
- package/plugins/devflow-self-review/skills/core-patterns/references/code-smell-violations.md +144 -0
- package/plugins/devflow-self-review/skills/core-patterns/references/detection.md +303 -0
- package/plugins/devflow-self-review/skills/core-patterns/references/patterns.md +576 -0
- package/plugins/devflow-self-review/skills/core-patterns/references/violations.md +369 -0
- package/plugins/devflow-self-review/skills/self-review/SKILL.md +149 -0
- package/plugins/devflow-self-review/skills/self-review/references/patterns.md +405 -0
- package/plugins/devflow-self-review/skills/self-review/references/report-template.md +253 -0
- package/plugins/devflow-self-review/skills/self-review/references/violations.md +308 -0
- package/plugins/devflow-specify/.claude-plugin/plugin.json +15 -0
- package/plugins/devflow-specify/README.md +46 -0
- package/plugins/devflow-specify/agents/skimmer.md +88 -0
- package/plugins/devflow-specify/agents/synthesizer.md +204 -0
- package/plugins/devflow-specify/commands/specify-teams.md +314 -0
- package/plugins/devflow-specify/commands/specify.md +179 -0
- package/plugins/devflow-specify/skills/agent-teams/SKILL.md +124 -0
- package/plugins/devflow-specify/skills/agent-teams/references/cleanup.md +104 -0
- package/plugins/devflow-specify/skills/agent-teams/references/communication.md +122 -0
- package/plugins/devflow-specify/skills/agent-teams/references/team-patterns.md +217 -0
- package/scripts/hooks/background-memory-update.sh +167 -0
- package/scripts/hooks/pre-compact-memory.sh +81 -0
- package/scripts/hooks/session-start-memory.sh +84 -0
- package/scripts/hooks/stop-update-memory.sh +81 -0
- package/shared/agents/coder.md +122 -0
- package/shared/agents/git.md +272 -0
- package/shared/agents/resolver.md +131 -0
- package/shared/agents/reviewer.md +119 -0
- package/shared/agents/scrutinizer.md +80 -0
- package/shared/agents/shepherd.md +94 -0
- package/shared/agents/simplifier.md +62 -0
- package/shared/agents/skimmer.md +88 -0
- package/shared/agents/synthesizer.md +204 -0
- package/shared/agents/validator.md +86 -0
- package/shared/skills/accessibility/SKILL.md +229 -0
- package/shared/skills/accessibility/references/detection.md +171 -0
- package/shared/skills/accessibility/references/patterns.md +670 -0
- package/shared/skills/accessibility/references/violations.md +419 -0
- package/shared/skills/agent-teams/SKILL.md +124 -0
- package/shared/skills/agent-teams/references/cleanup.md +104 -0
- package/shared/skills/agent-teams/references/communication.md +122 -0
- package/shared/skills/agent-teams/references/team-patterns.md +217 -0
- package/shared/skills/architecture-patterns/SKILL.md +153 -0
- package/shared/skills/architecture-patterns/references/detection.md +337 -0
- package/shared/skills/architecture-patterns/references/patterns.md +873 -0
- package/shared/skills/architecture-patterns/references/violations.md +575 -0
- package/shared/skills/complexity-patterns/SKILL.md +143 -0
- package/shared/skills/complexity-patterns/references/detection.md +264 -0
- package/shared/skills/complexity-patterns/references/patterns.md +487 -0
- package/shared/skills/complexity-patterns/references/violations.md +361 -0
- package/shared/skills/consistency-patterns/SKILL.md +140 -0
- package/shared/skills/consistency-patterns/references/detection.md +207 -0
- package/shared/skills/consistency-patterns/references/patterns.md +202 -0
- package/shared/skills/consistency-patterns/references/violations.md +213 -0
- package/shared/skills/core-patterns/SKILL.md +162 -0
- package/shared/skills/core-patterns/references/checklist.md +276 -0
- package/shared/skills/core-patterns/references/code-smell-violations.md +144 -0
- package/shared/skills/core-patterns/references/detection.md +303 -0
- package/shared/skills/core-patterns/references/patterns.md +576 -0
- package/shared/skills/core-patterns/references/violations.md +369 -0
- package/shared/skills/database-patterns/SKILL.md +134 -0
- package/shared/skills/database-patterns/references/detection.md +208 -0
- package/shared/skills/database-patterns/references/patterns.md +394 -0
- package/shared/skills/database-patterns/references/violations.md +332 -0
- package/shared/skills/dependencies-patterns/SKILL.md +141 -0
- package/shared/skills/dependencies-patterns/references/detection.md +181 -0
- package/shared/skills/dependencies-patterns/references/patterns.md +225 -0
- package/shared/skills/dependencies-patterns/references/violations.md +247 -0
- package/shared/skills/docs-framework/SKILL.md +134 -0
- package/shared/skills/docs-framework/references/patterns.md +346 -0
- package/shared/skills/docs-framework/references/violations.md +221 -0
- package/shared/skills/documentation-patterns/SKILL.md +125 -0
- package/shared/skills/documentation-patterns/references/detection.md +190 -0
- package/shared/skills/documentation-patterns/references/patterns.md +189 -0
- package/shared/skills/documentation-patterns/references/violations.md +163 -0
- package/shared/skills/frontend-design/SKILL.md +254 -0
- package/shared/skills/frontend-design/references/detection.md +184 -0
- package/shared/skills/frontend-design/references/patterns.md +511 -0
- package/shared/skills/frontend-design/references/violations.md +453 -0
- package/shared/skills/git-safety/SKILL.md +122 -0
- package/shared/skills/git-safety/references/detection.md +290 -0
- package/shared/skills/git-safety/references/patterns.md +289 -0
- package/shared/skills/git-safety/references/violations.md +18 -0
- package/shared/skills/git-workflow/SKILL.md +158 -0
- package/shared/skills/git-workflow/references/commit-patterns.md +115 -0
- package/shared/skills/git-workflow/references/commit-violations.md +77 -0
- package/shared/skills/git-workflow/references/pr-patterns.md +127 -0
- package/shared/skills/git-workflow/references/pr-violations.md +96 -0
- package/shared/skills/github-patterns/SKILL.md +153 -0
- package/shared/skills/github-patterns/references/patterns.md +572 -0
- package/shared/skills/github-patterns/references/violations.md +298 -0
- package/shared/skills/implementation-patterns/SKILL.md +162 -0
- package/shared/skills/implementation-patterns/references/patterns.md +1063 -0
- package/shared/skills/implementation-patterns/references/violations.md +483 -0
- package/shared/skills/input-validation/SKILL.md +148 -0
- package/shared/skills/input-validation/references/detection.md +283 -0
- package/shared/skills/input-validation/references/patterns.md +361 -0
- package/shared/skills/input-validation/references/violations.md +224 -0
- package/shared/skills/performance-patterns/SKILL.md +154 -0
- package/shared/skills/performance-patterns/references/detection.md +351 -0
- package/shared/skills/performance-patterns/references/patterns.md +503 -0
- package/shared/skills/performance-patterns/references/violations.md +354 -0
- package/shared/skills/react/SKILL.md +276 -0
- package/shared/skills/react/references/patterns.md +1331 -0
- package/shared/skills/react/references/violations.md +565 -0
- package/shared/skills/regression-patterns/SKILL.md +146 -0
- package/shared/skills/regression-patterns/references/detection.md +237 -0
- package/shared/skills/regression-patterns/references/patterns.md +226 -0
- package/shared/skills/regression-patterns/references/violations.md +225 -0
- package/shared/skills/review-methodology/SKILL.md +119 -0
- package/shared/skills/review-methodology/references/patterns.md +186 -0
- package/shared/skills/review-methodology/references/report-template.md +142 -0
- package/shared/skills/review-methodology/references/violations.md +125 -0
- package/shared/skills/security-patterns/SKILL.md +156 -0
- package/shared/skills/security-patterns/references/detection.md +287 -0
- package/shared/skills/security-patterns/references/patterns.md +507 -0
- package/shared/skills/security-patterns/references/violations.md +237 -0
- package/shared/skills/self-review/SKILL.md +149 -0
- package/shared/skills/self-review/references/patterns.md +405 -0
- package/shared/skills/self-review/references/report-template.md +253 -0
- package/shared/skills/self-review/references/violations.md +308 -0
- package/shared/skills/test-patterns/SKILL.md +183 -0
- package/shared/skills/test-patterns/references/detection.md +149 -0
- package/shared/skills/test-patterns/references/patterns.md +220 -0
- package/shared/skills/test-patterns/references/report-template.md +108 -0
- package/shared/skills/test-patterns/references/violations.md +221 -0
- package/shared/skills/typescript/SKILL.md +176 -0
- package/shared/skills/typescript/references/patterns.md +1105 -0
- package/shared/skills/typescript/references/violations.md +433 -0
- package/src/templates/claudeignore.template +188 -0
- package/src/templates/managed-settings.json +146 -0
- package/src/templates/settings.json +59 -0
- package/dist/cli.d.ts.map +0 -1
- package/dist/cli.js.map +0 -1
- package/dist/commands/init.d.ts.map +0 -1
- package/dist/commands/init.js.map +0 -1
- package/dist/commands/uninstall.d.ts.map +0 -1
- package/dist/commands/uninstall.js.map +0 -1
- package/dist/utils/git.d.ts.map +0 -1
- package/dist/utils/git.js.map +0 -1
- package/dist/utils/paths.d.ts.map +0 -1
- package/dist/utils/paths.js.map +0 -1
- package/src/claude/CLAUDE.md +0 -400
- package/src/claude/agents/devflow/audit-architecture.md +0 -132
- package/src/claude/agents/devflow/audit-complexity.md +0 -132
- package/src/claude/agents/devflow/audit-database.md +0 -132
- package/src/claude/agents/devflow/audit-dependencies.md +0 -132
- package/src/claude/agents/devflow/audit-documentation.md +0 -132
- package/src/claude/agents/devflow/audit-performance.md +0 -256
- package/src/claude/agents/devflow/audit-security.md +0 -259
- package/src/claude/agents/devflow/audit-tests.md +0 -132
- package/src/claude/agents/devflow/audit-typescript.md +0 -132
- package/src/claude/agents/devflow/brainstorm.md +0 -279
- package/src/claude/agents/devflow/catch-up.md +0 -345
- package/src/claude/agents/devflow/code-review.md +0 -307
- package/src/claude/agents/devflow/commit.md +0 -380
- package/src/claude/agents/devflow/debug.md +0 -476
- package/src/claude/agents/devflow/design.md +0 -491
- package/src/claude/agents/devflow/get-issue.md +0 -286
- package/src/claude/agents/devflow/pr-comments.md +0 -285
- package/src/claude/agents/devflow/project-state.md +0 -419
- package/src/claude/agents/devflow/pull-request.md +0 -493
- package/src/claude/agents/devflow/release.md +0 -1137
- package/src/claude/agents/devflow/tech-debt.md +0 -338
- package/src/claude/commands/devflow/brainstorm.md +0 -68
- package/src/claude/commands/devflow/breakdown.md +0 -125
- package/src/claude/commands/devflow/catch-up.md +0 -29
- package/src/claude/commands/devflow/code-review.md +0 -237
- package/src/claude/commands/devflow/commit.md +0 -17
- package/src/claude/commands/devflow/debug.md +0 -56
- package/src/claude/commands/devflow/design.md +0 -82
- package/src/claude/commands/devflow/devlog.md +0 -408
- package/src/claude/commands/devflow/get-issue.md +0 -16
- package/src/claude/commands/devflow/implement.md +0 -100
- package/src/claude/commands/devflow/plan.md +0 -223
- package/src/claude/commands/devflow/pull-request.md +0 -20
- package/src/claude/commands/devflow/release.md +0 -251
- package/src/claude/commands/devflow/resolve-comments.md +0 -583
- package/src/claude/scripts/statusline.sh +0 -47
- package/src/claude/settings.json +0 -6
- package/src/claude/skills/devflow/code-smell/SKILL.md +0 -428
- package/src/claude/skills/devflow/debug/SKILL.md +0 -119
- package/src/claude/skills/devflow/error-handling/SKILL.md +0 -597
- package/src/claude/skills/devflow/input-validation/SKILL.md +0 -514
- package/src/claude/skills/devflow/pattern-check/SKILL.md +0 -238
- package/src/claude/skills/devflow/research/SKILL.md +0 -138
- package/src/claude/skills/devflow/test-design/SKILL.md +0 -384
|
@@ -0,0 +1,1105 @@
|
|
|
1
|
+
# TypeScript Correct Patterns
|
|
2
|
+
|
|
3
|
+
Extended correct patterns for TypeScript development. Reference from main SKILL.md.
|
|
4
|
+
|
|
5
|
+
## Type Safety Patterns
|
|
6
|
+
|
|
7
|
+
### Using Unknown with Type Guards
|
|
8
|
+
|
|
9
|
+
```typescript
|
|
10
|
+
// CORRECT: unknown requires type checking
|
|
11
|
+
function parse(json: string): unknown {
|
|
12
|
+
return JSON.parse(json);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
// Usage requires narrowing
|
|
16
|
+
const data = parse(input);
|
|
17
|
+
if (isUser(data)) {
|
|
18
|
+
console.log(data.name); // Now type-safe
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
// CORRECT: Typed catch clause
|
|
22
|
+
try {
|
|
23
|
+
riskyOperation();
|
|
24
|
+
} catch (e) {
|
|
25
|
+
if (e instanceof Error) {
|
|
26
|
+
console.log(e.message);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
### Exhaustive Pattern Matching
|
|
32
|
+
|
|
33
|
+
```typescript
|
|
34
|
+
// CORRECT: Exhaustive switch with never check
|
|
35
|
+
type Status = 'pending' | 'active' | 'completed' | 'failed';
|
|
36
|
+
|
|
37
|
+
function handleStatus(status: Status): string {
|
|
38
|
+
switch (status) {
|
|
39
|
+
case 'pending':
|
|
40
|
+
return 'Waiting';
|
|
41
|
+
case 'active':
|
|
42
|
+
return 'Running';
|
|
43
|
+
case 'completed':
|
|
44
|
+
return 'Done';
|
|
45
|
+
case 'failed':
|
|
46
|
+
return 'Error';
|
|
47
|
+
default:
|
|
48
|
+
// Compile error if case missing
|
|
49
|
+
const _exhaustive: never = status;
|
|
50
|
+
throw new Error(`Unhandled status: ${_exhaustive}`);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// CORRECT: Exhaustive discriminated union helper
|
|
55
|
+
function assertNever(value: never, message?: string): never {
|
|
56
|
+
throw new Error(message ?? `Unexpected value: ${value}`);
|
|
57
|
+
}
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
### Safe Property Access
|
|
61
|
+
|
|
62
|
+
```typescript
|
|
63
|
+
// CORRECT: Typed property access
|
|
64
|
+
function getProperty<T, K extends keyof T>(obj: T, key: K): T[K] {
|
|
65
|
+
return obj[key];
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// CORRECT: Optional chaining with nullish coalescing
|
|
69
|
+
function getName(user: User | null): string {
|
|
70
|
+
return user?.name ?? 'Anonymous';
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// CORRECT: Optional property with default
|
|
74
|
+
interface Config {
|
|
75
|
+
timeout?: number;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
function getTimeout(config: Config): number {
|
|
79
|
+
return (config.timeout ?? 5000) * 1000;
|
|
80
|
+
}
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
---
|
|
84
|
+
|
|
85
|
+
## Type Guard Patterns
|
|
86
|
+
|
|
87
|
+
### Assertion Functions
|
|
88
|
+
|
|
89
|
+
```typescript
|
|
90
|
+
// Assert value is defined (not undefined)
|
|
91
|
+
function assertDefined<T>(value: T | undefined, message: string): asserts value is T {
|
|
92
|
+
if (value === undefined) {
|
|
93
|
+
throw new Error(message);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// Assert value is non-null
|
|
98
|
+
function assertNonNull<T>(value: T | null, message: string): asserts value is T {
|
|
99
|
+
if (value === null) {
|
|
100
|
+
throw new Error(message);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// Assert value exists (not null or undefined)
|
|
105
|
+
function assertExists<T>(value: T | null | undefined, message: string): asserts value is T {
|
|
106
|
+
if (value === null || value === undefined) {
|
|
107
|
+
throw new Error(message);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// Usage
|
|
112
|
+
function processUser(user: User | undefined): void {
|
|
113
|
+
assertDefined(user, 'User is required');
|
|
114
|
+
console.log(user.name); // user is definitely defined here
|
|
115
|
+
}
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
### Primitive Type Guards
|
|
119
|
+
|
|
120
|
+
```typescript
|
|
121
|
+
// Reusable primitive guards
|
|
122
|
+
const isString = (value: unknown): value is string =>
|
|
123
|
+
typeof value === 'string';
|
|
124
|
+
|
|
125
|
+
const isNumber = (value: unknown): value is number =>
|
|
126
|
+
typeof value === 'number' && !Number.isNaN(value);
|
|
127
|
+
|
|
128
|
+
const isBoolean = (value: unknown): value is boolean =>
|
|
129
|
+
typeof value === 'boolean';
|
|
130
|
+
|
|
131
|
+
const isNull = (value: unknown): value is null =>
|
|
132
|
+
value === null;
|
|
133
|
+
|
|
134
|
+
const isUndefined = (value: unknown): value is undefined =>
|
|
135
|
+
value === undefined;
|
|
136
|
+
|
|
137
|
+
const isNullish = (value: unknown): value is null | undefined =>
|
|
138
|
+
value === null || value === undefined;
|
|
139
|
+
|
|
140
|
+
const isFunction = (value: unknown): value is Function =>
|
|
141
|
+
typeof value === 'function';
|
|
142
|
+
|
|
143
|
+
const isObject = (value: unknown): value is object =>
|
|
144
|
+
typeof value === 'object' && value !== null;
|
|
145
|
+
|
|
146
|
+
const isArray = (value: unknown): value is unknown[] =>
|
|
147
|
+
Array.isArray(value);
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
### Array Type Guards
|
|
151
|
+
|
|
152
|
+
```typescript
|
|
153
|
+
// Check if array is non-empty
|
|
154
|
+
function isNonEmpty<T>(arr: T[]): arr is [T, ...T[]] {
|
|
155
|
+
return arr.length > 0;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
// Check if all elements match predicate
|
|
159
|
+
function allMatch<T, S extends T>(
|
|
160
|
+
arr: T[],
|
|
161
|
+
guard: (item: T) => item is S
|
|
162
|
+
): arr is S[] {
|
|
163
|
+
return arr.every(guard);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
// Usage
|
|
167
|
+
const items: (string | number)[] = ['a', 'b', 'c'];
|
|
168
|
+
|
|
169
|
+
if (allMatch(items, (x): x is string => typeof x === 'string')) {
|
|
170
|
+
// items is string[] here
|
|
171
|
+
items.forEach(s => console.log(s.toUpperCase()));
|
|
172
|
+
}
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
### Object Shape Guards
|
|
176
|
+
|
|
177
|
+
```typescript
|
|
178
|
+
// Check if object has specific property
|
|
179
|
+
function hasProperty<K extends string>(
|
|
180
|
+
obj: unknown,
|
|
181
|
+
key: K
|
|
182
|
+
): obj is { [P in K]: unknown } {
|
|
183
|
+
return typeof obj === 'object' && obj !== null && key in obj;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
// Check if object has property of specific type
|
|
187
|
+
function hasTypedProperty<K extends string, V>(
|
|
188
|
+
obj: unknown,
|
|
189
|
+
key: K,
|
|
190
|
+
guard: (value: unknown) => value is V
|
|
191
|
+
): obj is { [P in K]: V } {
|
|
192
|
+
return hasProperty(obj, key) && guard(obj[key]);
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
// Check multiple properties
|
|
196
|
+
function hasProperties<K extends string>(
|
|
197
|
+
obj: unknown,
|
|
198
|
+
...keys: K[]
|
|
199
|
+
): obj is { [P in K]: unknown } {
|
|
200
|
+
return typeof obj === 'object' && obj !== null && keys.every(k => k in obj);
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
// Usage
|
|
204
|
+
function processData(data: unknown): void {
|
|
205
|
+
if (hasProperty(data, 'id') && hasProperty(data, 'name')) {
|
|
206
|
+
console.log(data.id, data.name);
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
### Discriminated Union Guards
|
|
212
|
+
|
|
213
|
+
```typescript
|
|
214
|
+
// Generic discriminant checker
|
|
215
|
+
function isVariant<T extends { type: string }, K extends T['type']>(
|
|
216
|
+
obj: T,
|
|
217
|
+
type: K
|
|
218
|
+
): obj is Extract<T, { type: K }> {
|
|
219
|
+
return obj.type === type;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
// Usage
|
|
223
|
+
type Event =
|
|
224
|
+
| { type: 'click'; x: number; y: number }
|
|
225
|
+
| { type: 'keypress'; key: string }
|
|
226
|
+
| { type: 'scroll'; offset: number };
|
|
227
|
+
|
|
228
|
+
function handleEvent(event: Event): void {
|
|
229
|
+
if (isVariant(event, 'click')) {
|
|
230
|
+
console.log(`Clicked at ${event.x}, ${event.y}`);
|
|
231
|
+
} else if (isVariant(event, 'keypress')) {
|
|
232
|
+
console.log(`Pressed ${event.key}`);
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
### Error Type Guards
|
|
238
|
+
|
|
239
|
+
```typescript
|
|
240
|
+
// Check if error has specific shape
|
|
241
|
+
function isErrorWithMessage(error: unknown): error is { message: string } {
|
|
242
|
+
return (
|
|
243
|
+
typeof error === 'object' &&
|
|
244
|
+
error !== null &&
|
|
245
|
+
'message' in error &&
|
|
246
|
+
typeof (error as { message: unknown }).message === 'string'
|
|
247
|
+
);
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
// Check if error has code
|
|
251
|
+
function isErrorWithCode(error: unknown): error is { code: string | number } {
|
|
252
|
+
return (
|
|
253
|
+
typeof error === 'object' &&
|
|
254
|
+
error !== null &&
|
|
255
|
+
'code' in error &&
|
|
256
|
+
(typeof (error as { code: unknown }).code === 'string' ||
|
|
257
|
+
typeof (error as { code: unknown }).code === 'number')
|
|
258
|
+
);
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
// Usage
|
|
262
|
+
try {
|
|
263
|
+
riskyOperation();
|
|
264
|
+
} catch (error) {
|
|
265
|
+
if (isErrorWithMessage(error)) {
|
|
266
|
+
console.error(error.message);
|
|
267
|
+
}
|
|
268
|
+
if (isErrorWithCode(error) && error.code === 'ENOENT') {
|
|
269
|
+
console.error('File not found');
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
```
|
|
273
|
+
|
|
274
|
+
### Composable Guards
|
|
275
|
+
|
|
276
|
+
```typescript
|
|
277
|
+
// Combine guards with AND
|
|
278
|
+
function and<A, B extends A>(
|
|
279
|
+
guardA: (v: unknown) => v is A,
|
|
280
|
+
guardB: (v: A) => v is B
|
|
281
|
+
): (v: unknown) => v is B {
|
|
282
|
+
return (v: unknown): v is B => guardA(v) && guardB(v);
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
// Combine guards with OR
|
|
286
|
+
function or<A, B>(
|
|
287
|
+
guardA: (v: unknown) => v is A,
|
|
288
|
+
guardB: (v: unknown) => v is B
|
|
289
|
+
): (v: unknown) => v is A | B {
|
|
290
|
+
return (v: unknown): v is A | B => guardA(v) || guardB(v);
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
// Usage
|
|
294
|
+
const isStringOrNumber = or(isString, isNumber);
|
|
295
|
+
const isNonNullObject = and(isObject, (v): v is object => v !== null);
|
|
296
|
+
```
|
|
297
|
+
|
|
298
|
+
### API Response Guards
|
|
299
|
+
|
|
300
|
+
```typescript
|
|
301
|
+
interface SuccessResponse<T> {
|
|
302
|
+
status: 'success';
|
|
303
|
+
data: T;
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
interface ErrorResponse {
|
|
307
|
+
status: 'error';
|
|
308
|
+
error: {
|
|
309
|
+
code: string;
|
|
310
|
+
message: string;
|
|
311
|
+
};
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
type ApiResponse<T> = SuccessResponse<T> | ErrorResponse;
|
|
315
|
+
|
|
316
|
+
function isSuccess<T>(
|
|
317
|
+
response: ApiResponse<T>
|
|
318
|
+
): response is SuccessResponse<T> {
|
|
319
|
+
return response.status === 'success';
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
function isError<T>(
|
|
323
|
+
response: ApiResponse<T>
|
|
324
|
+
): response is ErrorResponse {
|
|
325
|
+
return response.status === 'error';
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
// Usage
|
|
329
|
+
async function fetchData<T>(url: string): Promise<T> {
|
|
330
|
+
const response: ApiResponse<T> = await fetch(url).then(r => r.json());
|
|
331
|
+
|
|
332
|
+
if (isError(response)) {
|
|
333
|
+
throw new Error(response.error.message);
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
return response.data;
|
|
337
|
+
}
|
|
338
|
+
```
|
|
339
|
+
|
|
340
|
+
---
|
|
341
|
+
|
|
342
|
+
## Utility Type Patterns
|
|
343
|
+
|
|
344
|
+
### Property Manipulation
|
|
345
|
+
|
|
346
|
+
```typescript
|
|
347
|
+
// Make specific properties required
|
|
348
|
+
type RequiredProps<T, K extends keyof T> = T & Required<Pick<T, K>>;
|
|
349
|
+
type UserWithEmail = RequiredProps<Partial<User>, 'email'>;
|
|
350
|
+
|
|
351
|
+
// Make specific properties optional
|
|
352
|
+
type OptionalProps<T, K extends keyof T> = Omit<T, K> & Partial<Pick<T, K>>;
|
|
353
|
+
type UserWithOptionalRole = OptionalProps<User, 'role'>;
|
|
354
|
+
|
|
355
|
+
// Make specific properties mutable (remove readonly)
|
|
356
|
+
type Mutable<T> = { -readonly [P in keyof T]: T[P] };
|
|
357
|
+
type MutableUser = Mutable<Readonly<User>>;
|
|
358
|
+
|
|
359
|
+
// Make specific properties readonly
|
|
360
|
+
type ReadonlyProps<T, K extends keyof T> = Omit<T, K> & Readonly<Pick<T, K>>;
|
|
361
|
+
type UserWithReadonlyId = ReadonlyProps<User, 'id'>;
|
|
362
|
+
```
|
|
363
|
+
|
|
364
|
+
### Deep Transformations
|
|
365
|
+
|
|
366
|
+
```typescript
|
|
367
|
+
// Deep partial - all nested properties optional
|
|
368
|
+
type DeepPartial<T> = {
|
|
369
|
+
[P in keyof T]?: T[P] extends object ? DeepPartial<T[P]> : T[P];
|
|
370
|
+
};
|
|
371
|
+
|
|
372
|
+
// Deep readonly - prevents mutation at any depth
|
|
373
|
+
type DeepReadonly<T> = {
|
|
374
|
+
readonly [P in keyof T]: T[P] extends object ? DeepReadonly<T[P]> : T[P];
|
|
375
|
+
};
|
|
376
|
+
|
|
377
|
+
// Deep required - all nested properties required
|
|
378
|
+
type DeepRequired<T> = {
|
|
379
|
+
[P in keyof T]-?: T[P] extends object ? DeepRequired<T[P]> : T[P];
|
|
380
|
+
};
|
|
381
|
+
|
|
382
|
+
// Usage
|
|
383
|
+
interface Config {
|
|
384
|
+
database: {
|
|
385
|
+
host: string;
|
|
386
|
+
port: number;
|
|
387
|
+
credentials: {
|
|
388
|
+
username: string;
|
|
389
|
+
password: string;
|
|
390
|
+
};
|
|
391
|
+
};
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
type PartialConfig = DeepPartial<Config>;
|
|
395
|
+
const config: DeepReadonly<Config> = { ... };
|
|
396
|
+
```
|
|
397
|
+
|
|
398
|
+
### Nullable Helpers
|
|
399
|
+
|
|
400
|
+
```typescript
|
|
401
|
+
// Nullable type
|
|
402
|
+
type Nullable<T> = T | null;
|
|
403
|
+
|
|
404
|
+
// Maybe type (nullable and optional)
|
|
405
|
+
type Maybe<T> = T | null | undefined;
|
|
406
|
+
|
|
407
|
+
// NonNullableProps - remove null/undefined from specific properties
|
|
408
|
+
type NonNullableProps<T, K extends keyof T> = {
|
|
409
|
+
[P in keyof T]: P extends K ? NonNullable<T[P]> : T[P];
|
|
410
|
+
};
|
|
411
|
+
|
|
412
|
+
// Example
|
|
413
|
+
interface ApiResponse {
|
|
414
|
+
data: User | null;
|
|
415
|
+
error: string | null;
|
|
416
|
+
timestamp: number;
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
type SuccessResponse = NonNullableProps<ApiResponse, 'data'>;
|
|
420
|
+
// { data: User; error: string | null; timestamp: number }
|
|
421
|
+
```
|
|
422
|
+
|
|
423
|
+
### Key Manipulation
|
|
424
|
+
|
|
425
|
+
```typescript
|
|
426
|
+
// Get keys where value is of specific type
|
|
427
|
+
type KeysOfType<T, V> = {
|
|
428
|
+
[K in keyof T]: T[K] extends V ? K : never;
|
|
429
|
+
}[keyof T];
|
|
430
|
+
|
|
431
|
+
interface User {
|
|
432
|
+
id: string;
|
|
433
|
+
name: string;
|
|
434
|
+
age: number;
|
|
435
|
+
active: boolean;
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
type StringKeys = KeysOfType<User, string>; // 'id' | 'name'
|
|
439
|
+
type NumberKeys = KeysOfType<User, number>; // 'age'
|
|
440
|
+
|
|
441
|
+
// Pick properties by value type
|
|
442
|
+
type PickByType<T, V> = {
|
|
443
|
+
[K in keyof T as T[K] extends V ? K : never]: T[K];
|
|
444
|
+
};
|
|
445
|
+
|
|
446
|
+
type StringProps = PickByType<User, string>;
|
|
447
|
+
// { id: string; name: string }
|
|
448
|
+
|
|
449
|
+
// Omit properties by value type
|
|
450
|
+
type OmitByType<T, V> = {
|
|
451
|
+
[K in keyof T as T[K] extends V ? never : K]: T[K];
|
|
452
|
+
};
|
|
453
|
+
|
|
454
|
+
type NonStringProps = OmitByType<User, string>;
|
|
455
|
+
// { age: number; active: boolean }
|
|
456
|
+
```
|
|
457
|
+
|
|
458
|
+
### Function Utilities
|
|
459
|
+
|
|
460
|
+
```typescript
|
|
461
|
+
// Get return type of async function (unwraps Promise)
|
|
462
|
+
type AsyncReturnType<T extends (...args: any[]) => Promise<any>> =
|
|
463
|
+
T extends (...args: any[]) => Promise<infer R> ? R : never;
|
|
464
|
+
|
|
465
|
+
async function fetchUser(id: string): Promise<User> { ... }
|
|
466
|
+
type UserType = AsyncReturnType<typeof fetchUser>; // User
|
|
467
|
+
|
|
468
|
+
// Get first argument type
|
|
469
|
+
type FirstArgument<T extends (...args: any[]) => any> =
|
|
470
|
+
T extends (first: infer F, ...rest: any[]) => any ? F : never;
|
|
471
|
+
|
|
472
|
+
// Get last argument type
|
|
473
|
+
type LastArgument<T extends (...args: any[]) => any> =
|
|
474
|
+
T extends (...args: [...any[], infer L]) => any ? L : never;
|
|
475
|
+
```
|
|
476
|
+
|
|
477
|
+
### Tuple Utilities
|
|
478
|
+
|
|
479
|
+
```typescript
|
|
480
|
+
// Head - first element
|
|
481
|
+
type Head<T extends any[]> = T extends [infer H, ...any[]] ? H : never;
|
|
482
|
+
|
|
483
|
+
// Tail - all but first
|
|
484
|
+
type Tail<T extends any[]> = T extends [any, ...infer R] ? R : never;
|
|
485
|
+
|
|
486
|
+
// Last - last element
|
|
487
|
+
type Last<T extends any[]> = T extends [...any[], infer L] ? L : never;
|
|
488
|
+
|
|
489
|
+
// Init - all but last
|
|
490
|
+
type Init<T extends any[]> = T extends [...infer I, any] ? I : never;
|
|
491
|
+
|
|
492
|
+
// Concat
|
|
493
|
+
type Concat<A extends any[], B extends any[]> = [...A, ...B];
|
|
494
|
+
|
|
495
|
+
// Usage
|
|
496
|
+
type Tuple = [string, number, boolean];
|
|
497
|
+
type First = Head<Tuple>; // string
|
|
498
|
+
type Rest = Tail<Tuple>; // [number, boolean]
|
|
499
|
+
type End = Last<Tuple>; // boolean
|
|
500
|
+
```
|
|
501
|
+
|
|
502
|
+
### String Utilities
|
|
503
|
+
|
|
504
|
+
```typescript
|
|
505
|
+
// Split string
|
|
506
|
+
type Split<S extends string, D extends string> =
|
|
507
|
+
S extends `${infer T}${D}${infer U}` ? [T, ...Split<U, D>] : [S];
|
|
508
|
+
|
|
509
|
+
// Join array to string
|
|
510
|
+
type Join<T extends string[], D extends string> =
|
|
511
|
+
T extends [] ? '' :
|
|
512
|
+
T extends [infer F extends string] ? F :
|
|
513
|
+
T extends [infer F extends string, ...infer R extends string[]] ? `${F}${D}${Join<R, D>}` :
|
|
514
|
+
never;
|
|
515
|
+
|
|
516
|
+
// Usage
|
|
517
|
+
type Parts = Split<'a.b.c', '.'>; // ['a', 'b', 'c']
|
|
518
|
+
type Joined = Join<['a', 'b', 'c'], '-'>; // 'a-b-c'
|
|
519
|
+
```
|
|
520
|
+
|
|
521
|
+
### Branded Types
|
|
522
|
+
|
|
523
|
+
```typescript
|
|
524
|
+
// Create nominal types that are structurally different
|
|
525
|
+
declare const brand: unique symbol;
|
|
526
|
+
|
|
527
|
+
type Brand<T, B> = T & { [brand]: B };
|
|
528
|
+
|
|
529
|
+
// Usage
|
|
530
|
+
type UserId = Brand<string, 'UserId'>;
|
|
531
|
+
type OrderId = Brand<string, 'OrderId'>;
|
|
532
|
+
|
|
533
|
+
function getUser(id: UserId): User { ... }
|
|
534
|
+
function getOrder(id: OrderId): Order { ... }
|
|
535
|
+
|
|
536
|
+
const userId = 'abc' as UserId;
|
|
537
|
+
const orderId = 'xyz' as OrderId;
|
|
538
|
+
|
|
539
|
+
getUser(userId); // OK
|
|
540
|
+
getUser(orderId); // Error: OrderId not assignable to UserId
|
|
541
|
+
```
|
|
542
|
+
|
|
543
|
+
---
|
|
544
|
+
|
|
545
|
+
## Async Patterns
|
|
546
|
+
|
|
547
|
+
### Async Function Types
|
|
548
|
+
|
|
549
|
+
```typescript
|
|
550
|
+
// Async function type
|
|
551
|
+
type AsyncFn<T, R> = (arg: T) => Promise<R>;
|
|
552
|
+
|
|
553
|
+
// Async with multiple args
|
|
554
|
+
type AsyncFn2<T1, T2, R> = (arg1: T1, arg2: T2) => Promise<R>;
|
|
555
|
+
|
|
556
|
+
// Async with result
|
|
557
|
+
type AsyncResult<T, E = Error> = Promise<Result<T, E>>;
|
|
558
|
+
|
|
559
|
+
// Async void function
|
|
560
|
+
type AsyncVoidFn<T> = (arg: T) => Promise<void>;
|
|
561
|
+
```
|
|
562
|
+
|
|
563
|
+
### Result-Based Async
|
|
564
|
+
|
|
565
|
+
```typescript
|
|
566
|
+
// Basic async result pattern
|
|
567
|
+
async function fetchUser(id: string): AsyncResult<User> {
|
|
568
|
+
try {
|
|
569
|
+
const user = await db.users.findById(id);
|
|
570
|
+
if (!user) {
|
|
571
|
+
return { ok: false, error: new Error('User not found') };
|
|
572
|
+
}
|
|
573
|
+
return { ok: true, value: user };
|
|
574
|
+
} catch (error) {
|
|
575
|
+
return { ok: false, error: error as Error };
|
|
576
|
+
}
|
|
577
|
+
}
|
|
578
|
+
|
|
579
|
+
// Wrapping async operations
|
|
580
|
+
async function tryCatch<T>(
|
|
581
|
+
fn: () => Promise<T>
|
|
582
|
+
): Promise<Result<T, Error>> {
|
|
583
|
+
try {
|
|
584
|
+
const value = await fn();
|
|
585
|
+
return { ok: true, value };
|
|
586
|
+
} catch (error) {
|
|
587
|
+
return { ok: false, error: error as Error };
|
|
588
|
+
}
|
|
589
|
+
}
|
|
590
|
+
|
|
591
|
+
// Usage
|
|
592
|
+
const result = await tryCatch(() => fetchUserFromApi(id));
|
|
593
|
+
if (!result.ok) {
|
|
594
|
+
console.error('Failed:', result.error.message);
|
|
595
|
+
}
|
|
596
|
+
```
|
|
597
|
+
|
|
598
|
+
### Promise Utilities
|
|
599
|
+
|
|
600
|
+
```typescript
|
|
601
|
+
// Wait for all, but handle errors individually
|
|
602
|
+
async function settleAll<T>(
|
|
603
|
+
promises: Promise<T>[]
|
|
604
|
+
): Promise<Array<Result<T, Error>>> {
|
|
605
|
+
const results = await Promise.allSettled(promises);
|
|
606
|
+
return results.map((result) =>
|
|
607
|
+
result.status === 'fulfilled'
|
|
608
|
+
? { ok: true as const, value: result.value }
|
|
609
|
+
: { ok: false as const, error: result.reason }
|
|
610
|
+
);
|
|
611
|
+
}
|
|
612
|
+
|
|
613
|
+
// Timeout wrapper
|
|
614
|
+
function withTimeout<T>(
|
|
615
|
+
promise: Promise<T>,
|
|
616
|
+
timeoutMs: number,
|
|
617
|
+
message = 'Operation timed out'
|
|
618
|
+
): Promise<T> {
|
|
619
|
+
return Promise.race([
|
|
620
|
+
promise,
|
|
621
|
+
new Promise<never>((_, reject) =>
|
|
622
|
+
setTimeout(() => reject(new Error(message)), timeoutMs)
|
|
623
|
+
),
|
|
624
|
+
]);
|
|
625
|
+
}
|
|
626
|
+
|
|
627
|
+
// Retry with exponential backoff
|
|
628
|
+
interface RetryOptions {
|
|
629
|
+
attempts: number;
|
|
630
|
+
delayMs: number;
|
|
631
|
+
backoff?: 'linear' | 'exponential';
|
|
632
|
+
onRetry?: (error: Error, attempt: number) => void;
|
|
633
|
+
}
|
|
634
|
+
|
|
635
|
+
async function retry<T>(
|
|
636
|
+
fn: () => Promise<T>,
|
|
637
|
+
options: RetryOptions
|
|
638
|
+
): Promise<T> {
|
|
639
|
+
const { attempts, delayMs, backoff = 'linear', onRetry } = options;
|
|
640
|
+
let lastError: Error;
|
|
641
|
+
|
|
642
|
+
for (let i = 0; i < attempts; i++) {
|
|
643
|
+
try {
|
|
644
|
+
return await fn();
|
|
645
|
+
} catch (error) {
|
|
646
|
+
lastError = error as Error;
|
|
647
|
+
onRetry?.(lastError, i + 1);
|
|
648
|
+
|
|
649
|
+
if (i < attempts - 1) {
|
|
650
|
+
const delay = backoff === 'exponential'
|
|
651
|
+
? delayMs * Math.pow(2, i)
|
|
652
|
+
: delayMs;
|
|
653
|
+
await sleep(delay);
|
|
654
|
+
}
|
|
655
|
+
}
|
|
656
|
+
}
|
|
657
|
+
|
|
658
|
+
throw lastError!;
|
|
659
|
+
}
|
|
660
|
+
|
|
661
|
+
function sleep(ms: number): Promise<void> {
|
|
662
|
+
return new Promise(resolve => setTimeout(resolve, ms));
|
|
663
|
+
}
|
|
664
|
+
```
|
|
665
|
+
|
|
666
|
+
### Concurrent Execution
|
|
667
|
+
|
|
668
|
+
```typescript
|
|
669
|
+
// Controlled concurrency
|
|
670
|
+
async function pMap<T, R>(
|
|
671
|
+
items: T[],
|
|
672
|
+
fn: (item: T, index: number) => Promise<R>,
|
|
673
|
+
concurrency: number
|
|
674
|
+
): Promise<R[]> {
|
|
675
|
+
const results: R[] = [];
|
|
676
|
+
const executing: Promise<void>[] = [];
|
|
677
|
+
|
|
678
|
+
for (let i = 0; i < items.length; i++) {
|
|
679
|
+
const promise = fn(items[i], i).then(result => {
|
|
680
|
+
results[i] = result;
|
|
681
|
+
});
|
|
682
|
+
|
|
683
|
+
executing.push(promise);
|
|
684
|
+
|
|
685
|
+
if (executing.length >= concurrency) {
|
|
686
|
+
await Promise.race(executing);
|
|
687
|
+
executing.splice(
|
|
688
|
+
executing.findIndex(p => p === promise),
|
|
689
|
+
1
|
|
690
|
+
);
|
|
691
|
+
}
|
|
692
|
+
}
|
|
693
|
+
|
|
694
|
+
await Promise.all(executing);
|
|
695
|
+
return results;
|
|
696
|
+
}
|
|
697
|
+
|
|
698
|
+
// Batch processing
|
|
699
|
+
async function batch<T, R>(
|
|
700
|
+
items: T[],
|
|
701
|
+
batchSize: number,
|
|
702
|
+
fn: (batch: T[]) => Promise<R[]>
|
|
703
|
+
): Promise<R[]> {
|
|
704
|
+
const results: R[] = [];
|
|
705
|
+
|
|
706
|
+
for (let i = 0; i < items.length; i += batchSize) {
|
|
707
|
+
const batch = items.slice(i, i + batchSize);
|
|
708
|
+
const batchResults = await fn(batch);
|
|
709
|
+
results.push(...batchResults);
|
|
710
|
+
}
|
|
711
|
+
|
|
712
|
+
return results;
|
|
713
|
+
}
|
|
714
|
+
```
|
|
715
|
+
|
|
716
|
+
### Cancellation
|
|
717
|
+
|
|
718
|
+
```typescript
|
|
719
|
+
interface Cancellable<T> {
|
|
720
|
+
promise: Promise<T>;
|
|
721
|
+
cancel: () => void;
|
|
722
|
+
}
|
|
723
|
+
|
|
724
|
+
function cancellable<T>(
|
|
725
|
+
fn: (signal: AbortSignal) => Promise<T>
|
|
726
|
+
): Cancellable<T> {
|
|
727
|
+
const controller = new AbortController();
|
|
728
|
+
|
|
729
|
+
const promise = fn(controller.signal);
|
|
730
|
+
|
|
731
|
+
return {
|
|
732
|
+
promise,
|
|
733
|
+
cancel: () => controller.abort()
|
|
734
|
+
};
|
|
735
|
+
}
|
|
736
|
+
|
|
737
|
+
// Usage
|
|
738
|
+
const { promise, cancel } = cancellable(async (signal) => {
|
|
739
|
+
const response = await fetch(url, { signal });
|
|
740
|
+
return response.json();
|
|
741
|
+
});
|
|
742
|
+
|
|
743
|
+
// Cancel if takes too long
|
|
744
|
+
setTimeout(cancel, 5000);
|
|
745
|
+
|
|
746
|
+
try {
|
|
747
|
+
const data = await promise;
|
|
748
|
+
} catch (error) {
|
|
749
|
+
if (error.name === 'AbortError') {
|
|
750
|
+
console.log('Request cancelled');
|
|
751
|
+
}
|
|
752
|
+
}
|
|
753
|
+
```
|
|
754
|
+
|
|
755
|
+
### Debounce / Throttle
|
|
756
|
+
|
|
757
|
+
```typescript
|
|
758
|
+
// Debounce
|
|
759
|
+
function debounce<T extends (...args: any[]) => any>(
|
|
760
|
+
fn: T,
|
|
761
|
+
delayMs: number
|
|
762
|
+
): (...args: Parameters<T>) => void {
|
|
763
|
+
let timeoutId: NodeJS.Timeout | null = null;
|
|
764
|
+
|
|
765
|
+
return (...args: Parameters<T>) => {
|
|
766
|
+
if (timeoutId) clearTimeout(timeoutId);
|
|
767
|
+
timeoutId = setTimeout(() => fn(...args), delayMs);
|
|
768
|
+
};
|
|
769
|
+
}
|
|
770
|
+
|
|
771
|
+
// Throttle
|
|
772
|
+
function throttle<T extends (...args: any[]) => any>(
|
|
773
|
+
fn: T,
|
|
774
|
+
limitMs: number
|
|
775
|
+
): (...args: Parameters<T>) => void {
|
|
776
|
+
let lastRun = 0;
|
|
777
|
+
let timeoutId: NodeJS.Timeout | null = null;
|
|
778
|
+
|
|
779
|
+
return (...args: Parameters<T>) => {
|
|
780
|
+
const now = Date.now();
|
|
781
|
+
|
|
782
|
+
if (now - lastRun >= limitMs) {
|
|
783
|
+
lastRun = now;
|
|
784
|
+
fn(...args);
|
|
785
|
+
} else if (!timeoutId) {
|
|
786
|
+
timeoutId = setTimeout(() => {
|
|
787
|
+
lastRun = Date.now();
|
|
788
|
+
timeoutId = null;
|
|
789
|
+
fn(...args);
|
|
790
|
+
}, limitMs - (now - lastRun));
|
|
791
|
+
}
|
|
792
|
+
};
|
|
793
|
+
}
|
|
794
|
+
```
|
|
795
|
+
|
|
796
|
+
### Lazy Async
|
|
797
|
+
|
|
798
|
+
```typescript
|
|
799
|
+
class LazyAsync<T> {
|
|
800
|
+
private promise: Promise<T> | null = null;
|
|
801
|
+
private value: T | null = null;
|
|
802
|
+
private resolved = false;
|
|
803
|
+
|
|
804
|
+
constructor(private factory: () => Promise<T>) {}
|
|
805
|
+
|
|
806
|
+
async get(): Promise<T> {
|
|
807
|
+
if (this.resolved) return this.value!;
|
|
808
|
+
|
|
809
|
+
if (!this.promise) {
|
|
810
|
+
this.promise = this.factory().then(v => {
|
|
811
|
+
this.value = v;
|
|
812
|
+
this.resolved = true;
|
|
813
|
+
return v;
|
|
814
|
+
});
|
|
815
|
+
}
|
|
816
|
+
|
|
817
|
+
return this.promise;
|
|
818
|
+
}
|
|
819
|
+
|
|
820
|
+
isResolved(): boolean {
|
|
821
|
+
return this.resolved;
|
|
822
|
+
}
|
|
823
|
+
|
|
824
|
+
reset(): void {
|
|
825
|
+
this.promise = null;
|
|
826
|
+
this.value = null;
|
|
827
|
+
this.resolved = false;
|
|
828
|
+
}
|
|
829
|
+
}
|
|
830
|
+
|
|
831
|
+
// Usage
|
|
832
|
+
const config = new LazyAsync(async () => {
|
|
833
|
+
const response = await fetch('/config');
|
|
834
|
+
return response.json();
|
|
835
|
+
});
|
|
836
|
+
|
|
837
|
+
// First call fetches
|
|
838
|
+
const cfg1 = await config.get();
|
|
839
|
+
|
|
840
|
+
// Subsequent calls return cached
|
|
841
|
+
const cfg2 = await config.get();
|
|
842
|
+
```
|
|
843
|
+
|
|
844
|
+
---
|
|
845
|
+
|
|
846
|
+
## Module Patterns
|
|
847
|
+
|
|
848
|
+
### Barrel Exports
|
|
849
|
+
|
|
850
|
+
```typescript
|
|
851
|
+
// src/models/index.ts
|
|
852
|
+
export { User } from './user';
|
|
853
|
+
export { Order } from './order';
|
|
854
|
+
export { Product } from './product';
|
|
855
|
+
export type { UserDTO, CreateUserInput } from './user';
|
|
856
|
+
|
|
857
|
+
// Usage
|
|
858
|
+
import { User, Order, type UserDTO } from './models';
|
|
859
|
+
```
|
|
860
|
+
|
|
861
|
+
### Type-Only Exports
|
|
862
|
+
|
|
863
|
+
```typescript
|
|
864
|
+
// Separate type exports for clarity
|
|
865
|
+
export type { User, UserDTO, CreateUserInput };
|
|
866
|
+
export { createUser, updateUser, deleteUser };
|
|
867
|
+
|
|
868
|
+
// Type-only imports (won't be in JS output)
|
|
869
|
+
import type { User } from './user';
|
|
870
|
+
import { createUser } from './user';
|
|
871
|
+
```
|
|
872
|
+
|
|
873
|
+
### Dependency Injection Pattern
|
|
874
|
+
|
|
875
|
+
```typescript
|
|
876
|
+
// Define interface
|
|
877
|
+
interface Logger {
|
|
878
|
+
info(message: string, context?: object): void;
|
|
879
|
+
error(message: string, context?: object): void;
|
|
880
|
+
}
|
|
881
|
+
|
|
882
|
+
// Implementation
|
|
883
|
+
class ConsoleLogger implements Logger {
|
|
884
|
+
info(message: string, context?: object): void {
|
|
885
|
+
console.log(message, context);
|
|
886
|
+
}
|
|
887
|
+
error(message: string, context?: object): void {
|
|
888
|
+
console.error(message, context);
|
|
889
|
+
}
|
|
890
|
+
}
|
|
891
|
+
|
|
892
|
+
// Service depends on interface
|
|
893
|
+
class UserService {
|
|
894
|
+
constructor(
|
|
895
|
+
private readonly logger: Logger,
|
|
896
|
+
private readonly repository: UserRepository
|
|
897
|
+
) {}
|
|
898
|
+
|
|
899
|
+
async createUser(input: CreateUserInput): Promise<Result<User, Error>> {
|
|
900
|
+
this.logger.info('Creating user', { email: input.email });
|
|
901
|
+
// ...
|
|
902
|
+
}
|
|
903
|
+
}
|
|
904
|
+
|
|
905
|
+
// Composition root
|
|
906
|
+
const logger = new ConsoleLogger();
|
|
907
|
+
const repository = new PostgresUserRepository(db);
|
|
908
|
+
const userService = new UserService(logger, repository);
|
|
909
|
+
```
|
|
910
|
+
|
|
911
|
+
---
|
|
912
|
+
|
|
913
|
+
## Generic Patterns
|
|
914
|
+
|
|
915
|
+
### Generic Classes
|
|
916
|
+
|
|
917
|
+
```typescript
|
|
918
|
+
class Cache<T> {
|
|
919
|
+
private store = new Map<string, { value: T; expiry: number }>();
|
|
920
|
+
|
|
921
|
+
set(key: string, value: T, ttlMs: number): void {
|
|
922
|
+
this.store.set(key, {
|
|
923
|
+
value,
|
|
924
|
+
expiry: Date.now() + ttlMs,
|
|
925
|
+
});
|
|
926
|
+
}
|
|
927
|
+
|
|
928
|
+
get(key: string): T | undefined {
|
|
929
|
+
const entry = this.store.get(key);
|
|
930
|
+
if (!entry) return undefined;
|
|
931
|
+
if (Date.now() > entry.expiry) {
|
|
932
|
+
this.store.delete(key);
|
|
933
|
+
return undefined;
|
|
934
|
+
}
|
|
935
|
+
return entry.value;
|
|
936
|
+
}
|
|
937
|
+
|
|
938
|
+
has(key: string): boolean {
|
|
939
|
+
const entry = this.store.get(key);
|
|
940
|
+
if (!entry) return false;
|
|
941
|
+
if (Date.now() > entry.expiry) {
|
|
942
|
+
this.store.delete(key);
|
|
943
|
+
return false;
|
|
944
|
+
}
|
|
945
|
+
return true;
|
|
946
|
+
}
|
|
947
|
+
}
|
|
948
|
+
|
|
949
|
+
// Usage
|
|
950
|
+
const userCache = new Cache<User>();
|
|
951
|
+
userCache.set('user-1', user, 60000);
|
|
952
|
+
```
|
|
953
|
+
|
|
954
|
+
### Generic Repository Pattern
|
|
955
|
+
|
|
956
|
+
```typescript
|
|
957
|
+
interface Repository<T, ID = string> {
|
|
958
|
+
findById(id: ID): Promise<T | null>;
|
|
959
|
+
findAll(): Promise<T[]>;
|
|
960
|
+
findMany(query: Partial<T>): Promise<T[]>;
|
|
961
|
+
save(entity: T): Promise<T>;
|
|
962
|
+
update(id: ID, changes: Partial<T>): Promise<T>;
|
|
963
|
+
delete(id: ID): Promise<void>;
|
|
964
|
+
exists(id: ID): Promise<boolean>;
|
|
965
|
+
count(query?: Partial<T>): Promise<number>;
|
|
966
|
+
}
|
|
967
|
+
|
|
968
|
+
// With constraints
|
|
969
|
+
interface Identifiable {
|
|
970
|
+
id: string;
|
|
971
|
+
}
|
|
972
|
+
|
|
973
|
+
interface Timestamped {
|
|
974
|
+
createdAt: Date;
|
|
975
|
+
updatedAt: Date;
|
|
976
|
+
}
|
|
977
|
+
|
|
978
|
+
interface CRUDRepository<T extends Identifiable & Timestamped> {
|
|
979
|
+
findById(id: string): Promise<T | null>;
|
|
980
|
+
save(entity: Omit<T, 'id' | 'createdAt' | 'updatedAt'>): Promise<T>;
|
|
981
|
+
update(id: string, changes: Partial<Omit<T, 'id' | 'createdAt'>>): Promise<T>;
|
|
982
|
+
}
|
|
983
|
+
```
|
|
984
|
+
|
|
985
|
+
### Builder Pattern with Types
|
|
986
|
+
|
|
987
|
+
```typescript
|
|
988
|
+
class QueryBuilder<T> {
|
|
989
|
+
private conditions: Array<(item: T) => boolean> = [];
|
|
990
|
+
private sortFn?: (a: T, b: T) => number;
|
|
991
|
+
private limitCount?: number;
|
|
992
|
+
|
|
993
|
+
where<K extends keyof T>(key: K, value: T[K]): this {
|
|
994
|
+
this.conditions.push((item) => item[key] === value);
|
|
995
|
+
return this;
|
|
996
|
+
}
|
|
997
|
+
|
|
998
|
+
whereIn<K extends keyof T>(key: K, values: T[K][]): this {
|
|
999
|
+
this.conditions.push((item) => values.includes(item[key]));
|
|
1000
|
+
return this;
|
|
1001
|
+
}
|
|
1002
|
+
|
|
1003
|
+
orderBy<K extends keyof T>(key: K, direction: 'asc' | 'desc' = 'asc'): this {
|
|
1004
|
+
this.sortFn = (a, b) => {
|
|
1005
|
+
const aVal = a[key];
|
|
1006
|
+
const bVal = b[key];
|
|
1007
|
+
if (aVal < bVal) return direction === 'asc' ? -1 : 1;
|
|
1008
|
+
if (aVal > bVal) return direction === 'asc' ? 1 : -1;
|
|
1009
|
+
return 0;
|
|
1010
|
+
};
|
|
1011
|
+
return this;
|
|
1012
|
+
}
|
|
1013
|
+
|
|
1014
|
+
limit(count: number): this {
|
|
1015
|
+
this.limitCount = count;
|
|
1016
|
+
return this;
|
|
1017
|
+
}
|
|
1018
|
+
|
|
1019
|
+
execute(items: T[]): T[] {
|
|
1020
|
+
let result = items.filter((item) =>
|
|
1021
|
+
this.conditions.every((condition) => condition(item))
|
|
1022
|
+
);
|
|
1023
|
+
if (this.sortFn) {
|
|
1024
|
+
result = [...result].sort(this.sortFn);
|
|
1025
|
+
}
|
|
1026
|
+
if (this.limitCount !== undefined) {
|
|
1027
|
+
result = result.slice(0, this.limitCount);
|
|
1028
|
+
}
|
|
1029
|
+
return result;
|
|
1030
|
+
}
|
|
1031
|
+
}
|
|
1032
|
+
|
|
1033
|
+
// Usage
|
|
1034
|
+
const activeAdmins = new QueryBuilder<User>()
|
|
1035
|
+
.where('status', 'active')
|
|
1036
|
+
.where('role', 'admin')
|
|
1037
|
+
.orderBy('createdAt', 'desc')
|
|
1038
|
+
.limit(10)
|
|
1039
|
+
.execute(users);
|
|
1040
|
+
```
|
|
1041
|
+
|
|
1042
|
+
---
|
|
1043
|
+
|
|
1044
|
+
## Discriminated Unions
|
|
1045
|
+
|
|
1046
|
+
### State Machines
|
|
1047
|
+
|
|
1048
|
+
```typescript
|
|
1049
|
+
type RequestState<T> =
|
|
1050
|
+
| { status: 'idle' }
|
|
1051
|
+
| { status: 'loading' }
|
|
1052
|
+
| { status: 'success'; data: T }
|
|
1053
|
+
| { status: 'error'; error: Error };
|
|
1054
|
+
|
|
1055
|
+
function renderRequest<T>(state: RequestState<T>): string {
|
|
1056
|
+
switch (state.status) {
|
|
1057
|
+
case 'idle':
|
|
1058
|
+
return 'Ready to fetch';
|
|
1059
|
+
case 'loading':
|
|
1060
|
+
return 'Loading...';
|
|
1061
|
+
case 'success':
|
|
1062
|
+
return `Data: ${JSON.stringify(state.data)}`;
|
|
1063
|
+
case 'error':
|
|
1064
|
+
return `Error: ${state.error.message}`;
|
|
1065
|
+
}
|
|
1066
|
+
}
|
|
1067
|
+
```
|
|
1068
|
+
|
|
1069
|
+
### Event Types
|
|
1070
|
+
|
|
1071
|
+
```typescript
|
|
1072
|
+
type AppEvent =
|
|
1073
|
+
| { type: 'USER_LOGIN'; userId: string }
|
|
1074
|
+
| { type: 'USER_LOGOUT'; userId: string }
|
|
1075
|
+
| { type: 'PAGE_VIEW'; path: string }
|
|
1076
|
+
| { type: 'CLICK'; elementId: string };
|
|
1077
|
+
|
|
1078
|
+
function handleEvent(event: AppEvent): void {
|
|
1079
|
+
switch (event.type) {
|
|
1080
|
+
case 'USER_LOGIN':
|
|
1081
|
+
console.log(`User ${event.userId} logged in`);
|
|
1082
|
+
break;
|
|
1083
|
+
case 'USER_LOGOUT':
|
|
1084
|
+
console.log(`User ${event.userId} logged out`);
|
|
1085
|
+
break;
|
|
1086
|
+
case 'PAGE_VIEW':
|
|
1087
|
+
console.log(`Page viewed: ${event.path}`);
|
|
1088
|
+
break;
|
|
1089
|
+
case 'CLICK':
|
|
1090
|
+
console.log(`Element clicked: ${event.elementId}`);
|
|
1091
|
+
break;
|
|
1092
|
+
}
|
|
1093
|
+
}
|
|
1094
|
+
```
|
|
1095
|
+
|
|
1096
|
+
### Form State
|
|
1097
|
+
|
|
1098
|
+
```typescript
|
|
1099
|
+
type FormState<T> =
|
|
1100
|
+
| { status: 'pristine'; values: T }
|
|
1101
|
+
| { status: 'dirty'; values: T; touched: Set<keyof T> }
|
|
1102
|
+
| { status: 'submitting'; values: T }
|
|
1103
|
+
| { status: 'submitted'; values: T; result: unknown }
|
|
1104
|
+
| { status: 'error'; values: T; errors: Partial<Record<keyof T, string>> };
|
|
1105
|
+
```
|