@aicgen/aicgen 1.0.0-beta.1
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/.claude/agents/architecture-reviewer.md +88 -0
- package/.claude/agents/guideline-checker.md +73 -0
- package/.claude/agents/security-auditor.md +108 -0
- package/.claude/guidelines/api-design.md +645 -0
- package/.claude/guidelines/architecture.md +2503 -0
- package/.claude/guidelines/best-practices.md +618 -0
- package/.claude/guidelines/code-style.md +304 -0
- package/.claude/guidelines/design-patterns.md +573 -0
- package/.claude/guidelines/devops.md +226 -0
- package/.claude/guidelines/error-handling.md +413 -0
- package/.claude/guidelines/language.md +782 -0
- package/.claude/guidelines/performance.md +706 -0
- package/.claude/guidelines/security.md +583 -0
- package/.claude/guidelines/testing.md +568 -0
- package/.claude/settings.json +98 -0
- package/.claude/settings.local.json +8 -0
- package/.env.example +23 -0
- package/.eslintrc.json +28 -0
- package/.github/workflows/release.yml +180 -0
- package/.github/workflows/test.yml +81 -0
- package/.gitmodules +3 -0
- package/.vs/ProjectSettings.json +3 -0
- package/.vs/VSWorkspaceState.json +16 -0
- package/.vs/aicgen.slnx/FileContentIndex/5f0ce2a3-fd68-4863-9e23-e428cf1794e3.vsidx +0 -0
- package/.vs/aicgen.slnx/v18/.wsuo +0 -0
- package/.vs/aicgen.slnx/v18/DocumentLayout.json +54 -0
- package/.vs/slnx.sqlite +0 -0
- package/AGENTS.md +121 -0
- package/CLAUDE.md +36 -0
- package/CONTRIBUTING.md +821 -0
- package/LICENSE +21 -0
- package/README.md +199 -0
- package/assets/icon.svg +34 -0
- package/assets/logo.svg +41 -0
- package/bun.lock +848 -0
- package/data/LICENSE +21 -0
- package/data/README.md +203 -0
- package/data/api/basics.md +292 -0
- package/data/api/index.md +8 -0
- package/data/api/pagination.md +142 -0
- package/data/api/rest.md +137 -0
- package/data/api/versioning.md +60 -0
- package/data/architecture/clean-architecture/index.md +7 -0
- package/data/architecture/clean-architecture/layers.md +111 -0
- package/data/architecture/ddd/index.md +8 -0
- package/data/architecture/ddd/strategic.md +89 -0
- package/data/architecture/ddd/tactical.md +132 -0
- package/data/architecture/event-driven/index.md +7 -0
- package/data/architecture/event-driven/messaging.md +242 -0
- package/data/architecture/event-driven/patterns.md +129 -0
- package/data/architecture/feature-toggles/index.md +7 -0
- package/data/architecture/feature-toggles/patterns.md +73 -0
- package/data/architecture/gui/index.md +7 -0
- package/data/architecture/gui/patterns.md +132 -0
- package/data/architecture/hexagonal/ports-adapters.md +132 -0
- package/data/architecture/index.md +12 -0
- package/data/architecture/layered/index.md +7 -0
- package/data/architecture/layered/layers.md +100 -0
- package/data/architecture/microservices/api-gateway.md +56 -0
- package/data/architecture/microservices/boundaries.md +80 -0
- package/data/architecture/microservices/communication.md +97 -0
- package/data/architecture/microservices/data.md +92 -0
- package/data/architecture/microservices/index.md +11 -0
- package/data/architecture/microservices/resilience.md +111 -0
- package/data/architecture/modular-monolith/boundaries.md +133 -0
- package/data/architecture/modular-monolith/structure.md +131 -0
- package/data/architecture/serverless/best-practices.md +322 -0
- package/data/architecture/serverless/index.md +7 -0
- package/data/architecture/serverless/patterns.md +80 -0
- package/data/architecture/solid/index.md +7 -0
- package/data/architecture/solid/principles.md +187 -0
- package/data/database/basics.md +365 -0
- package/data/database/design-patterns.md +68 -0
- package/data/database/index.md +8 -0
- package/data/database/indexing.md +136 -0
- package/data/database/nosql.md +223 -0
- package/data/database/schema.md +137 -0
- package/data/devops/ci-cd.md +66 -0
- package/data/devops/index.md +8 -0
- package/data/devops/observability.md +73 -0
- package/data/devops/practices.md +77 -0
- package/data/error-handling/basics.md +222 -0
- package/data/error-handling/index.md +7 -0
- package/data/error-handling/strategy.md +185 -0
- package/data/guideline-mappings.yml +1077 -0
- package/data/index.md +3 -0
- package/data/language/csharp/basics.md +210 -0
- package/data/language/csharp/testing.md +252 -0
- package/data/language/go/basics.md +158 -0
- package/data/language/go/testing.md +192 -0
- package/data/language/index.md +14 -0
- package/data/language/java/basics.md +184 -0
- package/data/language/java/testing.md +273 -0
- package/data/language/javascript/basics.md +217 -0
- package/data/language/javascript/testing.md +269 -0
- package/data/language/python/async.md +100 -0
- package/data/language/python/basics.md +100 -0
- package/data/language/python/index.md +10 -0
- package/data/language/python/testing.md +125 -0
- package/data/language/python/types.md +99 -0
- package/data/language/ruby/basics.md +227 -0
- package/data/language/ruby/testing.md +267 -0
- package/data/language/rust/basics.md +175 -0
- package/data/language/rust/testing.md +219 -0
- package/data/language/typescript/async.md +103 -0
- package/data/language/typescript/basics.md +87 -0
- package/data/language/typescript/config.md +95 -0
- package/data/language/typescript/error-handling.md +98 -0
- package/data/language/typescript/generics.md +85 -0
- package/data/language/typescript/index.md +14 -0
- package/data/language/typescript/interfaces-types.md +83 -0
- package/data/language/typescript/performance.md +103 -0
- package/data/language/typescript/testing.md +98 -0
- package/data/patterns/base-patterns.md +105 -0
- package/data/patterns/concurrency.md +87 -0
- package/data/patterns/data-access.md +83 -0
- package/data/patterns/distribution.md +86 -0
- package/data/patterns/domain-logic.md +81 -0
- package/data/patterns/gof.md +109 -0
- package/data/patterns/index.md +12 -0
- package/data/performance/async.md +148 -0
- package/data/performance/basics.md +324 -0
- package/data/performance/caching-strategies.md +68 -0
- package/data/performance/caching.md +152 -0
- package/data/performance/index.md +8 -0
- package/data/practices/code-review.md +52 -0
- package/data/practices/documentation.md +260 -0
- package/data/practices/index.md +11 -0
- package/data/practices/planning.md +142 -0
- package/data/practices/refactoring.md +91 -0
- package/data/practices/version-control.md +55 -0
- package/data/security/auth-jwt.md +159 -0
- package/data/security/headers.md +143 -0
- package/data/security/index.md +10 -0
- package/data/security/injection.md +119 -0
- package/data/security/secrets.md +148 -0
- package/data/style/index.md +8 -0
- package/data/style/naming.md +136 -0
- package/data/style/organization.md +162 -0
- package/data/templates/agents/architecture-reviewer.md +88 -0
- package/data/templates/agents/guideline-checker.md +73 -0
- package/data/templates/agents/security-auditor.md +108 -0
- package/data/templates/antigravity/rules/architecture.md.hbs +5 -0
- package/data/templates/antigravity/rules/code-style.md.hbs +5 -0
- package/data/templates/antigravity/rules/language.md.hbs +5 -0
- package/data/templates/antigravity/rules/performance.md.hbs +5 -0
- package/data/templates/antigravity/rules/security.md.hbs +5 -0
- package/data/templates/antigravity/rules/testing.md.hbs +5 -0
- package/data/templates/antigravity/workflows/add-documentation.md.hbs +23 -0
- package/data/templates/antigravity/workflows/generate-integration-tests.md.hbs +17 -0
- package/data/templates/antigravity/workflows/generate-unit-tests.md.hbs +20 -0
- package/data/templates/antigravity/workflows/performance-audit.md.hbs +24 -0
- package/data/templates/antigravity/workflows/refactor-extract-module.md.hbs +17 -0
- package/data/templates/antigravity/workflows/security-audit.md.hbs +20 -0
- package/data/templates/hooks/formatting.json +26 -0
- package/data/templates/hooks/security.json +35 -0
- package/data/templates/hooks/testing.json +17 -0
- package/data/testing/basics.md +151 -0
- package/data/testing/index.md +9 -0
- package/data/testing/integration.md +159 -0
- package/data/testing/unit-fundamentals.md +128 -0
- package/data/testing/unit-mocking.md +116 -0
- package/data/version.json +49 -0
- package/dist/commands/init.d.ts +8 -0
- package/dist/commands/init.d.ts.map +1 -0
- package/dist/commands/init.js +46 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/config/profiles.d.ts +4 -0
- package/dist/config/profiles.d.ts.map +1 -0
- package/dist/config/profiles.js +30 -0
- package/dist/config/profiles.js.map +1 -0
- package/dist/config/settings.d.ts +7 -0
- package/dist/config/settings.d.ts.map +1 -0
- package/dist/config/settings.js +7 -0
- package/dist/config/settings.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +58489 -0
- package/dist/index.js.map +1 -0
- package/dist/models/guideline.d.ts +15 -0
- package/dist/models/guideline.d.ts.map +1 -0
- package/dist/models/guideline.js +2 -0
- package/dist/models/guideline.js.map +1 -0
- package/dist/models/preference.d.ts +9 -0
- package/dist/models/preference.d.ts.map +1 -0
- package/dist/models/preference.js +2 -0
- package/dist/models/preference.js.map +1 -0
- package/dist/models/profile.d.ts +9 -0
- package/dist/models/profile.d.ts.map +1 -0
- package/dist/models/profile.js +2 -0
- package/dist/models/profile.js.map +1 -0
- package/dist/models/project.d.ts +13 -0
- package/dist/models/project.d.ts.map +1 -0
- package/dist/models/project.js +2 -0
- package/dist/models/project.js.map +1 -0
- package/dist/services/ai/anthropic.d.ts +7 -0
- package/dist/services/ai/anthropic.d.ts.map +1 -0
- package/dist/services/ai/anthropic.js +39 -0
- package/dist/services/ai/anthropic.js.map +1 -0
- package/dist/services/generator.d.ts +2 -0
- package/dist/services/generator.d.ts.map +1 -0
- package/dist/services/generator.js +4 -0
- package/dist/services/generator.js.map +1 -0
- package/dist/services/learner.d.ts +2 -0
- package/dist/services/learner.d.ts.map +1 -0
- package/dist/services/learner.js +4 -0
- package/dist/services/learner.js.map +1 -0
- package/dist/services/scanner.d.ts +3 -0
- package/dist/services/scanner.d.ts.map +1 -0
- package/dist/services/scanner.js +54 -0
- package/dist/services/scanner.js.map +1 -0
- package/dist/utils/errors.d.ts +15 -0
- package/dist/utils/errors.d.ts.map +1 -0
- package/dist/utils/errors.js +27 -0
- package/dist/utils/errors.js.map +1 -0
- package/dist/utils/file.d.ts +7 -0
- package/dist/utils/file.d.ts.map +1 -0
- package/dist/utils/file.js +32 -0
- package/dist/utils/file.js.map +1 -0
- package/dist/utils/logger.d.ts +6 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.js +17 -0
- package/dist/utils/logger.js.map +1 -0
- package/dist/utils/path.d.ts +6 -0
- package/dist/utils/path.d.ts.map +1 -0
- package/dist/utils/path.js +14 -0
- package/dist/utils/path.js.map +1 -0
- package/docs/planning/memory-lane.md +83 -0
- package/package.json +64 -0
- package/packaging/linux/aicgen.spec +23 -0
- package/packaging/linux/control +9 -0
- package/packaging/macos/scripts/postinstall +12 -0
- package/packaging/windows/setup.nsi +92 -0
- package/planning/BRANDING-SUMMARY.md +194 -0
- package/planning/BRANDING.md +174 -0
- package/planning/BUILD.md +186 -0
- package/planning/CHUNK-IMPLEMENTATION-PLAN.md +87 -0
- package/planning/CHUNK-TAXONOMY.md +375 -0
- package/planning/CHUNKS-COMPLETE.md +382 -0
- package/planning/DESIGN.md +313 -0
- package/planning/DYNAMIC-GUIDELINES-DESIGN.md +265 -0
- package/planning/ENTERPRISE-UX-COMPLETE.md +281 -0
- package/planning/IMPLEMENTATION-PLAN.md +20 -0
- package/planning/PHASE1-COMPLETE.md +211 -0
- package/planning/PHASE2-COMPLETE.md +350 -0
- package/planning/PHASE3-COMPLETE.md +399 -0
- package/planning/PHASE4-COMPLETE.md +361 -0
- package/planning/PHASE4.5-CHUNKS.md +462 -0
- package/planning/STRUCTURE.md +170 -0
- package/scripts/add-categories.ts +87 -0
- package/scripts/build-binary.ts +46 -0
- package/scripts/embed-data.ts +105 -0
- package/scripts/generate-version.ts +150 -0
- package/scripts/test-decompress.ts +27 -0
- package/scripts/test-extract.ts +31 -0
- package/src/__tests__/services/assistant-file-writer.test.ts +400 -0
- package/src/__tests__/services/guideline-loader.test.ts +281 -0
- package/src/__tests__/services/tarball-extraction.test.ts +125 -0
- package/src/commands/add-guideline.ts +296 -0
- package/src/commands/clear.ts +61 -0
- package/src/commands/guideline-selector.ts +123 -0
- package/src/commands/init.ts +645 -0
- package/src/commands/quick-add.ts +586 -0
- package/src/commands/remove-guideline.ts +152 -0
- package/src/commands/stats.ts +49 -0
- package/src/commands/update.ts +240 -0
- package/src/config.ts +82 -0
- package/src/embedded-data.ts +1492 -0
- package/src/index.ts +67 -0
- package/src/models/profile.ts +24 -0
- package/src/models/project.ts +43 -0
- package/src/services/assistant-file-writer.ts +612 -0
- package/src/services/config-generator.ts +150 -0
- package/src/services/config-manager.ts +70 -0
- package/src/services/data-source.ts +248 -0
- package/src/services/first-run-init.ts +148 -0
- package/src/services/guideline-loader.ts +311 -0
- package/src/services/hook-generator.ts +178 -0
- package/src/services/subagent-generator.ts +310 -0
- package/src/utils/banner.ts +66 -0
- package/src/utils/errors.ts +27 -0
- package/src/utils/file.ts +67 -0
- package/src/utils/formatting.ts +172 -0
- package/src/utils/logger.ts +89 -0
- package/src/utils/path.ts +17 -0
- package/src/utils/wizard-state.ts +132 -0
- package/tsconfig.json +25 -0
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
# Rust Fundamentals
|
|
2
|
+
|
|
3
|
+
## Project Structure
|
|
4
|
+
|
|
5
|
+
```
|
|
6
|
+
myproject/
|
|
7
|
+
├── src/
|
|
8
|
+
│ ├── main.rs # Binary entry point
|
|
9
|
+
│ ├── lib.rs # Library root
|
|
10
|
+
│ ├── models/
|
|
11
|
+
│ │ └── mod.rs
|
|
12
|
+
│ └── services/
|
|
13
|
+
│ └── mod.rs
|
|
14
|
+
├── tests/ # Integration tests
|
|
15
|
+
├── Cargo.toml
|
|
16
|
+
└── Cargo.lock
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## Ownership & Borrowing
|
|
20
|
+
|
|
21
|
+
```rust
|
|
22
|
+
// Ownership: each value has one owner
|
|
23
|
+
let s1 = String::from("hello");
|
|
24
|
+
let s2 = s1; // s1 is moved, no longer valid
|
|
25
|
+
|
|
26
|
+
// Borrowing: references without ownership
|
|
27
|
+
fn print_len(s: &String) {
|
|
28
|
+
println!("{}", s.len());
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// Mutable borrowing (only one at a time)
|
|
32
|
+
fn append(s: &mut String) {
|
|
33
|
+
s.push_str(" world");
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// Lifetimes: ensure references are valid
|
|
37
|
+
fn longest<'a>(x: &'a str, y: &'a str) -> &'a str {
|
|
38
|
+
if x.len() > y.len() { x } else { y }
|
|
39
|
+
}
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
## Error Handling
|
|
43
|
+
|
|
44
|
+
```rust
|
|
45
|
+
// Result for recoverable errors
|
|
46
|
+
fn read_file(path: &str) -> Result<String, io::Error> {
|
|
47
|
+
fs::read_to_string(path)
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// ? operator for propagation
|
|
51
|
+
fn process_file(path: &str) -> Result<Data, Error> {
|
|
52
|
+
let content = fs::read_to_string(path)?;
|
|
53
|
+
let data = parse(&content)?;
|
|
54
|
+
Ok(data)
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// Custom error types
|
|
58
|
+
#[derive(Debug)]
|
|
59
|
+
enum AppError {
|
|
60
|
+
NotFound(String),
|
|
61
|
+
InvalidInput(String),
|
|
62
|
+
Database(sqlx::Error),
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
impl From<sqlx::Error> for AppError {
|
|
66
|
+
fn from(err: sqlx::Error) -> Self {
|
|
67
|
+
AppError::Database(err)
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
## Option & Pattern Matching
|
|
73
|
+
|
|
74
|
+
```rust
|
|
75
|
+
// Option for nullable values
|
|
76
|
+
fn find_user(id: u64) -> Option<User> {
|
|
77
|
+
users.get(&id).cloned()
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// Pattern matching
|
|
81
|
+
match find_user(42) {
|
|
82
|
+
Some(user) => println!("Found: {}", user.name),
|
|
83
|
+
None => println!("Not found"),
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// if let for single patterns
|
|
87
|
+
if let Some(user) = find_user(42) {
|
|
88
|
+
process(user);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// Combinators
|
|
92
|
+
find_user(42)
|
|
93
|
+
.map(|u| u.email)
|
|
94
|
+
.unwrap_or_default()
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
## Traits
|
|
98
|
+
|
|
99
|
+
```rust
|
|
100
|
+
// Define behavior
|
|
101
|
+
trait Repository {
|
|
102
|
+
fn find(&self, id: u64) -> Option<Entity>;
|
|
103
|
+
fn save(&mut self, entity: Entity) -> Result<(), Error>;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// Implement for types
|
|
107
|
+
impl Repository for PostgresRepo {
|
|
108
|
+
fn find(&self, id: u64) -> Option<Entity> {
|
|
109
|
+
// Implementation
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// Trait bounds
|
|
114
|
+
fn process<T: Repository + Clone>(repo: T) {
|
|
115
|
+
// Can use Repository and Clone methods
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// Default implementations
|
|
119
|
+
trait Greet {
|
|
120
|
+
fn greet(&self) -> String {
|
|
121
|
+
String::from("Hello!")
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
## Testing
|
|
127
|
+
|
|
128
|
+
```rust
|
|
129
|
+
#[cfg(test)]
|
|
130
|
+
mod tests {
|
|
131
|
+
use super::*;
|
|
132
|
+
|
|
133
|
+
#[test]
|
|
134
|
+
fn test_create_user() {
|
|
135
|
+
let user = User::new("test@example.com");
|
|
136
|
+
assert_eq!(user.email, "test@example.com");
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
#[test]
|
|
140
|
+
#[should_panic(expected = "invalid email")]
|
|
141
|
+
fn test_invalid_email_panics() {
|
|
142
|
+
User::new("invalid");
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
#[test]
|
|
146
|
+
fn test_find_user() -> Result<(), Error> {
|
|
147
|
+
let repo = TestRepo::new();
|
|
148
|
+
let user = repo.find(1)?;
|
|
149
|
+
assert!(user.is_some());
|
|
150
|
+
Ok(())
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
## Async/Await
|
|
156
|
+
|
|
157
|
+
```rust
|
|
158
|
+
// Async functions
|
|
159
|
+
async fn fetch_data(url: &str) -> Result<Data, Error> {
|
|
160
|
+
let response = reqwest::get(url).await?;
|
|
161
|
+
let data = response.json().await?;
|
|
162
|
+
Ok(data)
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
// Spawning tasks
|
|
166
|
+
let handle = tokio::spawn(async {
|
|
167
|
+
fetch_data("https://api.example.com").await
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
// Concurrent execution
|
|
171
|
+
let (result1, result2) = tokio::join!(
|
|
172
|
+
fetch_data("url1"),
|
|
173
|
+
fetch_data("url2")
|
|
174
|
+
);
|
|
175
|
+
```
|
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
# Rust Testing
|
|
2
|
+
|
|
3
|
+
## Test Module Structure
|
|
4
|
+
|
|
5
|
+
```rust
|
|
6
|
+
// In src/lib.rs or src/user.rs
|
|
7
|
+
pub fn create_user(email: &str) -> Result<User, Error> {
|
|
8
|
+
// implementation
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
#[cfg(test)]
|
|
12
|
+
mod tests {
|
|
13
|
+
use super::*;
|
|
14
|
+
|
|
15
|
+
#[test]
|
|
16
|
+
fn test_create_user() {
|
|
17
|
+
let user = create_user("test@example.com").unwrap();
|
|
18
|
+
assert_eq!(user.email, "test@example.com");
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## Assertions
|
|
24
|
+
|
|
25
|
+
```rust
|
|
26
|
+
#[test]
|
|
27
|
+
fn test_assertions() {
|
|
28
|
+
// Equality
|
|
29
|
+
assert_eq!(actual, expected);
|
|
30
|
+
assert_ne!(value1, value2);
|
|
31
|
+
|
|
32
|
+
// Boolean
|
|
33
|
+
assert!(condition);
|
|
34
|
+
assert!(!condition);
|
|
35
|
+
|
|
36
|
+
// With custom message
|
|
37
|
+
assert_eq!(result, expected, "failed for input: {}", input);
|
|
38
|
+
}
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## Testing Results and Options
|
|
42
|
+
|
|
43
|
+
```rust
|
|
44
|
+
#[test]
|
|
45
|
+
fn test_result() -> Result<(), Error> {
|
|
46
|
+
let user = create_user("test@example.com")?;
|
|
47
|
+
assert_eq!(user.email, "test@example.com");
|
|
48
|
+
Ok(())
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
#[test]
|
|
52
|
+
fn test_option() {
|
|
53
|
+
let result = find_user("123");
|
|
54
|
+
assert!(result.is_some());
|
|
55
|
+
assert_eq!(result.unwrap().id, "123");
|
|
56
|
+
}
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
## Testing Panics
|
|
60
|
+
|
|
61
|
+
```rust
|
|
62
|
+
#[test]
|
|
63
|
+
#[should_panic]
|
|
64
|
+
fn test_panics() {
|
|
65
|
+
divide(1, 0);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
#[test]
|
|
69
|
+
#[should_panic(expected = "division by zero")]
|
|
70
|
+
fn test_panic_message() {
|
|
71
|
+
divide(1, 0);
|
|
72
|
+
}
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
## Test Organization
|
|
76
|
+
|
|
77
|
+
```rust
|
|
78
|
+
#[cfg(test)]
|
|
79
|
+
mod tests {
|
|
80
|
+
use super::*;
|
|
81
|
+
|
|
82
|
+
mod create {
|
|
83
|
+
use super::*;
|
|
84
|
+
|
|
85
|
+
#[test]
|
|
86
|
+
fn with_valid_email() {
|
|
87
|
+
// test
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
#[test]
|
|
91
|
+
fn with_invalid_email() {
|
|
92
|
+
// test
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
mod update {
|
|
97
|
+
use super::*;
|
|
98
|
+
|
|
99
|
+
#[test]
|
|
100
|
+
fn existing_user() {
|
|
101
|
+
// test
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
## Test Fixtures
|
|
108
|
+
|
|
109
|
+
```rust
|
|
110
|
+
struct TestContext {
|
|
111
|
+
db: MockDatabase,
|
|
112
|
+
service: UserService,
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
impl TestContext {
|
|
116
|
+
fn new() -> Self {
|
|
117
|
+
let db = MockDatabase::new();
|
|
118
|
+
let service = UserService::new(db.clone());
|
|
119
|
+
Self { db, service }
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
#[test]
|
|
124
|
+
fn test_with_context() {
|
|
125
|
+
let ctx = TestContext::new();
|
|
126
|
+
let user = ctx.service.create("test@example.com").unwrap();
|
|
127
|
+
assert!(ctx.db.contains(&user.id));
|
|
128
|
+
}
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
## Mocking with Traits
|
|
132
|
+
|
|
133
|
+
```rust
|
|
134
|
+
// Define trait
|
|
135
|
+
trait UserRepository {
|
|
136
|
+
fn save(&self, user: &User) -> Result<(), Error>;
|
|
137
|
+
fn find_by_id(&self, id: &str) -> Option<User>;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
// Mock implementation
|
|
141
|
+
struct MockRepository {
|
|
142
|
+
users: RefCell<HashMap<String, User>>,
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
impl UserRepository for MockRepository {
|
|
146
|
+
fn save(&self, user: &User) -> Result<(), Error> {
|
|
147
|
+
self.users.borrow_mut().insert(user.id.clone(), user.clone());
|
|
148
|
+
Ok(())
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
fn find_by_id(&self, id: &str) -> Option<User> {
|
|
152
|
+
self.users.borrow().get(id).cloned()
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
#[test]
|
|
157
|
+
fn test_service_create() {
|
|
158
|
+
let repo = MockRepository { users: RefCell::new(HashMap::new()) };
|
|
159
|
+
let service = UserService::new(Box::new(repo));
|
|
160
|
+
|
|
161
|
+
let user = service.create("test@example.com").unwrap();
|
|
162
|
+
assert_eq!(user.email, "test@example.com");
|
|
163
|
+
}
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
## Integration Tests
|
|
167
|
+
|
|
168
|
+
```
|
|
169
|
+
tests/
|
|
170
|
+
├── integration_test.rs
|
|
171
|
+
└── common/
|
|
172
|
+
└── mod.rs
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
```rust
|
|
176
|
+
// tests/common/mod.rs
|
|
177
|
+
pub fn setup() -> TestDatabase {
|
|
178
|
+
TestDatabase::new()
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
// tests/integration_test.rs
|
|
182
|
+
mod common;
|
|
183
|
+
|
|
184
|
+
#[test]
|
|
185
|
+
fn test_database_integration() {
|
|
186
|
+
let db = common::setup();
|
|
187
|
+
// integration test...
|
|
188
|
+
}
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
## Async Tests
|
|
192
|
+
|
|
193
|
+
```rust
|
|
194
|
+
#[tokio::test]
|
|
195
|
+
async fn test_async_create() {
|
|
196
|
+
let service = UserService::new();
|
|
197
|
+
let user = service.create_async("test@example.com").await.unwrap();
|
|
198
|
+
assert_eq!(user.email, "test@example.com");
|
|
199
|
+
}
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
## Running Tests
|
|
203
|
+
|
|
204
|
+
```bash
|
|
205
|
+
# Run all tests
|
|
206
|
+
cargo test
|
|
207
|
+
|
|
208
|
+
# Run specific test
|
|
209
|
+
cargo test test_create_user
|
|
210
|
+
|
|
211
|
+
# Run tests with output
|
|
212
|
+
cargo test -- --nocapture
|
|
213
|
+
|
|
214
|
+
# Run ignored tests
|
|
215
|
+
cargo test -- --ignored
|
|
216
|
+
|
|
217
|
+
# Run benchmarks (nightly)
|
|
218
|
+
cargo bench
|
|
219
|
+
```
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
# Async/Await Patterns
|
|
2
|
+
|
|
3
|
+
## Prefer async/await
|
|
4
|
+
|
|
5
|
+
Always use async/await over promise chains:
|
|
6
|
+
|
|
7
|
+
```typescript
|
|
8
|
+
// ✅ Good
|
|
9
|
+
async function fetchUser(id: string): Promise<User> {
|
|
10
|
+
const response = await fetch(`/api/users/${id}`);
|
|
11
|
+
if (!response.ok) {
|
|
12
|
+
throw new Error(`HTTP ${response.status}`);
|
|
13
|
+
}
|
|
14
|
+
return await response.json();
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
// ❌ Avoid
|
|
18
|
+
function fetchUser(id: string): Promise<User> {
|
|
19
|
+
return fetch(`/api/users/${id}`)
|
|
20
|
+
.then(res => res.json());
|
|
21
|
+
}
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## Error Handling
|
|
25
|
+
|
|
26
|
+
Always wrap async operations in try/catch:
|
|
27
|
+
|
|
28
|
+
```typescript
|
|
29
|
+
async function safeOperation(): Promise<Result> {
|
|
30
|
+
try {
|
|
31
|
+
const data = await riskyOperation();
|
|
32
|
+
return { success: true, data };
|
|
33
|
+
} catch (error) {
|
|
34
|
+
logger.error('Operation failed', error);
|
|
35
|
+
return { success: false, error: error.message };
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## Parallel Execution
|
|
41
|
+
|
|
42
|
+
Use `Promise.all()` for independent operations:
|
|
43
|
+
|
|
44
|
+
```typescript
|
|
45
|
+
// ✅ Good - parallel (fast)
|
|
46
|
+
const [users, posts, comments] = await Promise.all([
|
|
47
|
+
fetchUsers(),
|
|
48
|
+
fetchPosts(),
|
|
49
|
+
fetchComments()
|
|
50
|
+
]);
|
|
51
|
+
|
|
52
|
+
// ❌ Bad - sequential (slow)
|
|
53
|
+
const users = await fetchUsers();
|
|
54
|
+
const posts = await fetchPosts();
|
|
55
|
+
const comments = await fetchComments();
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
## Handling Failures
|
|
59
|
+
|
|
60
|
+
Use `Promise.allSettled()` when some failures are acceptable:
|
|
61
|
+
|
|
62
|
+
```typescript
|
|
63
|
+
const results = await Promise.allSettled([
|
|
64
|
+
fetchData1(),
|
|
65
|
+
fetchData2(),
|
|
66
|
+
fetchData3()
|
|
67
|
+
]);
|
|
68
|
+
|
|
69
|
+
results.forEach((result, index) => {
|
|
70
|
+
if (result.status === 'fulfilled') {
|
|
71
|
+
console.log(`Success ${index}:`, result.value);
|
|
72
|
+
} else {
|
|
73
|
+
console.error(`Failed ${index}:`, result.reason);
|
|
74
|
+
}
|
|
75
|
+
});
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
## Retry Pattern
|
|
79
|
+
|
|
80
|
+
Implement retry with exponential backoff:
|
|
81
|
+
|
|
82
|
+
```typescript
|
|
83
|
+
async function retryWithBackoff<T>(
|
|
84
|
+
fn: () => Promise<T>,
|
|
85
|
+
maxRetries: number = 3
|
|
86
|
+
): Promise<T> {
|
|
87
|
+
let lastError: Error;
|
|
88
|
+
|
|
89
|
+
for (let attempt = 0; attempt < maxRetries; attempt++) {
|
|
90
|
+
try {
|
|
91
|
+
return await fn();
|
|
92
|
+
} catch (error) {
|
|
93
|
+
lastError = error as Error;
|
|
94
|
+
if (attempt < maxRetries - 1) {
|
|
95
|
+
const delay = 1000 * Math.pow(2, attempt);
|
|
96
|
+
await new Promise(resolve => setTimeout(resolve, delay));
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
throw lastError!;
|
|
102
|
+
}
|
|
103
|
+
```
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
# TypeScript Fundamentals
|
|
2
|
+
|
|
3
|
+
## Strict Mode (Required)
|
|
4
|
+
|
|
5
|
+
Always use strict mode in `tsconfig.json`:
|
|
6
|
+
|
|
7
|
+
```json
|
|
8
|
+
{
|
|
9
|
+
"compilerOptions": {
|
|
10
|
+
"strict": true,
|
|
11
|
+
"noImplicitAny": true,
|
|
12
|
+
"strictNullChecks": true,
|
|
13
|
+
"strictFunctionTypes": true
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
## Type Annotations
|
|
19
|
+
|
|
20
|
+
Use explicit types for clarity:
|
|
21
|
+
|
|
22
|
+
```typescript
|
|
23
|
+
// Function signatures
|
|
24
|
+
function calculateTotal(items: CartItem[], taxRate: number): number {
|
|
25
|
+
const subtotal = items.reduce((sum, item) => sum + item.price, 0);
|
|
26
|
+
return subtotal * (1 + taxRate);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// Variable declarations
|
|
30
|
+
const userName: string = "Alice";
|
|
31
|
+
const age: number = 30;
|
|
32
|
+
const isActive: boolean = true;
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## Avoid `any`
|
|
36
|
+
|
|
37
|
+
Never use `any` - use `unknown` with type guards:
|
|
38
|
+
|
|
39
|
+
```typescript
|
|
40
|
+
// ❌ Bad
|
|
41
|
+
function processData(data: any) {
|
|
42
|
+
return data.value;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// ✅ Good
|
|
46
|
+
function processData(data: unknown): string {
|
|
47
|
+
if (typeof data === 'object' && data !== null && 'value' in data) {
|
|
48
|
+
return String(data.value);
|
|
49
|
+
}
|
|
50
|
+
throw new Error('Invalid data structure');
|
|
51
|
+
}
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
## Type Guards
|
|
55
|
+
|
|
56
|
+
Implement custom type guards:
|
|
57
|
+
|
|
58
|
+
```typescript
|
|
59
|
+
interface User {
|
|
60
|
+
id: string;
|
|
61
|
+
email: string;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function isUser(value: unknown): value is User {
|
|
65
|
+
return (
|
|
66
|
+
typeof value === 'object' &&
|
|
67
|
+
value !== null &&
|
|
68
|
+
'id' in value &&
|
|
69
|
+
'email' in value &&
|
|
70
|
+
typeof value.id === 'string' &&
|
|
71
|
+
typeof value.email === 'string'
|
|
72
|
+
);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// Usage
|
|
76
|
+
if (isUser(data)) {
|
|
77
|
+
console.log(data.email); // Type: User
|
|
78
|
+
}
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
## Naming Conventions
|
|
82
|
+
|
|
83
|
+
- Classes/Interfaces: `PascalCase`
|
|
84
|
+
- Functions/Variables: `camelCase`
|
|
85
|
+
- Constants: `UPPER_SNAKE_CASE`
|
|
86
|
+
- Files: `kebab-case.ts`
|
|
87
|
+
- No `I` prefix for interfaces
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
# TypeScript Configuration
|
|
2
|
+
|
|
3
|
+
## tsconfig.json Best Practices
|
|
4
|
+
|
|
5
|
+
```json
|
|
6
|
+
{
|
|
7
|
+
"compilerOptions": {
|
|
8
|
+
// Strict type checking
|
|
9
|
+
"strict": true,
|
|
10
|
+
"noImplicitAny": true,
|
|
11
|
+
"strictNullChecks": true,
|
|
12
|
+
"strictFunctionTypes": true,
|
|
13
|
+
"strictBindCallApply": true,
|
|
14
|
+
"strictPropertyInitialization": true,
|
|
15
|
+
"noImplicitThis": true,
|
|
16
|
+
"alwaysStrict": true,
|
|
17
|
+
|
|
18
|
+
// Additional checks
|
|
19
|
+
"noUnusedLocals": true,
|
|
20
|
+
"noUnusedParameters": true,
|
|
21
|
+
"noImplicitReturns": true,
|
|
22
|
+
"noFallthroughCasesInSwitch": true,
|
|
23
|
+
"noUncheckedIndexedAccess": true,
|
|
24
|
+
|
|
25
|
+
// Module resolution
|
|
26
|
+
"module": "ESNext",
|
|
27
|
+
"moduleResolution": "bundler",
|
|
28
|
+
"esModuleInterop": true,
|
|
29
|
+
"allowSyntheticDefaultImports": true,
|
|
30
|
+
"resolveJsonModule": true,
|
|
31
|
+
|
|
32
|
+
// Output
|
|
33
|
+
"target": "ES2022",
|
|
34
|
+
"outDir": "./dist",
|
|
35
|
+
"declaration": true,
|
|
36
|
+
"declarationMap": true,
|
|
37
|
+
"sourceMap": true,
|
|
38
|
+
|
|
39
|
+
// Path aliases
|
|
40
|
+
"baseUrl": ".",
|
|
41
|
+
"paths": {
|
|
42
|
+
"@/*": ["src/*"],
|
|
43
|
+
"@services/*": ["src/services/*"],
|
|
44
|
+
"@models/*": ["src/models/*"]
|
|
45
|
+
}
|
|
46
|
+
},
|
|
47
|
+
"include": ["src/**/*"],
|
|
48
|
+
"exclude": ["node_modules", "dist", "**/*.test.ts"]
|
|
49
|
+
}
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
## Path Aliases Setup
|
|
53
|
+
|
|
54
|
+
```typescript
|
|
55
|
+
// With path aliases configured:
|
|
56
|
+
import { UserService } from '@services/user';
|
|
57
|
+
import { User } from '@models/user';
|
|
58
|
+
|
|
59
|
+
// Instead of relative paths:
|
|
60
|
+
import { UserService } from '../../../services/user';
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
## Project References (Monorepo)
|
|
64
|
+
|
|
65
|
+
```json
|
|
66
|
+
// packages/shared/tsconfig.json
|
|
67
|
+
{
|
|
68
|
+
"compilerOptions": {
|
|
69
|
+
"composite": true,
|
|
70
|
+
"outDir": "./dist"
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// packages/api/tsconfig.json
|
|
75
|
+
{
|
|
76
|
+
"extends": "../../tsconfig.base.json",
|
|
77
|
+
"references": [
|
|
78
|
+
{ "path": "../shared" }
|
|
79
|
+
]
|
|
80
|
+
}
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
## Environment-Specific Configs
|
|
84
|
+
|
|
85
|
+
```json
|
|
86
|
+
// tsconfig.build.json - for production builds
|
|
87
|
+
{
|
|
88
|
+
"extends": "./tsconfig.json",
|
|
89
|
+
"compilerOptions": {
|
|
90
|
+
"sourceMap": false,
|
|
91
|
+
"removeComments": true
|
|
92
|
+
},
|
|
93
|
+
"exclude": ["**/*.test.ts", "**/*.spec.ts"]
|
|
94
|
+
}
|
|
95
|
+
```
|