@aicgen/aicgen 1.0.0 → 1.0.2

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.
@@ -1,786 +0,0 @@
1
- # Language Rules
2
-
3
- # TypeScript Fundamentals
4
-
5
- ## Strict Mode (Required)
6
-
7
- Always use strict mode in `tsconfig.json`:
8
-
9
- ```json
10
- {
11
- "compilerOptions": {
12
- "strict": true,
13
- "noImplicitAny": true,
14
- "strictNullChecks": true,
15
- "strictFunctionTypes": true
16
- }
17
- }
18
- ```
19
-
20
- ## Type Annotations
21
-
22
- Use explicit types for clarity:
23
-
24
- ```typescript
25
- // Function signatures
26
- function calculateTotal(items: CartItem[], taxRate: number): number {
27
- const subtotal = items.reduce((sum, item) => sum + item.price, 0);
28
- return subtotal * (1 + taxRate);
29
- }
30
-
31
- // Variable declarations
32
- const userName: string = "Alice";
33
- const age: number = 30;
34
- const isActive: boolean = true;
35
- ```
36
-
37
- ## Avoid `any`
38
-
39
- Never use `any` - use `unknown` with type guards:
40
-
41
- ```typescript
42
- // ❌ Bad
43
- function processData(data: any) {
44
- return data.value;
45
- }
46
-
47
- // ✅ Good
48
- function processData(data: unknown): string {
49
- if (typeof data === 'object' && data !== null && 'value' in data) {
50
- return String(data.value);
51
- }
52
- throw new Error('Invalid data structure');
53
- }
54
- ```
55
-
56
- ## Type Guards
57
-
58
- Implement custom type guards:
59
-
60
- ```typescript
61
- interface User {
62
- id: string;
63
- email: string;
64
- }
65
-
66
- function isUser(value: unknown): value is User {
67
- return (
68
- typeof value === 'object' &&
69
- value !== null &&
70
- 'id' in value &&
71
- 'email' in value &&
72
- typeof value.id === 'string' &&
73
- typeof value.email === 'string'
74
- );
75
- }
76
-
77
- // Usage
78
- if (isUser(data)) {
79
- console.log(data.email); // Type: User
80
- }
81
- ```
82
-
83
- ## Naming Conventions
84
-
85
- - Classes/Interfaces: `PascalCase`
86
- - Functions/Variables: `camelCase`
87
- - Constants: `UPPER_SNAKE_CASE`
88
- - Files: `kebab-case.ts`
89
- - No `I` prefix for interfaces
90
-
91
-
92
- ---
93
-
94
- # Async/Await Patterns
95
-
96
- ## Prefer async/await
97
-
98
- Always use async/await over promise chains:
99
-
100
- ```typescript
101
- // ✅ Good
102
- async function fetchUser(id: string): Promise<User> {
103
- const response = await fetch(`/api/users/${id}`);
104
- if (!response.ok) {
105
- throw new Error(`HTTP ${response.status}`);
106
- }
107
- return await response.json();
108
- }
109
-
110
- // ❌ Avoid
111
- function fetchUser(id: string): Promise<User> {
112
- return fetch(`/api/users/${id}`)
113
- .then(res => res.json());
114
- }
115
- ```
116
-
117
- ## Error Handling
118
-
119
- Always wrap async operations in try/catch:
120
-
121
- ```typescript
122
- async function safeOperation(): Promise<Result> {
123
- try {
124
- const data = await riskyOperation();
125
- return { success: true, data };
126
- } catch (error) {
127
- logger.error('Operation failed', error);
128
- return { success: false, error: error.message };
129
- }
130
- }
131
- ```
132
-
133
- ## Parallel Execution
134
-
135
- Use `Promise.all()` for independent operations:
136
-
137
- ```typescript
138
- // ✅ Good - parallel (fast)
139
- const [users, posts, comments] = await Promise.all([
140
- fetchUsers(),
141
- fetchPosts(),
142
- fetchComments()
143
- ]);
144
-
145
- // ❌ Bad - sequential (slow)
146
- const users = await fetchUsers();
147
- const posts = await fetchPosts();
148
- const comments = await fetchComments();
149
- ```
150
-
151
- ## Handling Failures
152
-
153
- Use `Promise.allSettled()` when some failures are acceptable:
154
-
155
- ```typescript
156
- const results = await Promise.allSettled([
157
- fetchData1(),
158
- fetchData2(),
159
- fetchData3()
160
- ]);
161
-
162
- results.forEach((result, index) => {
163
- if (result.status === 'fulfilled') {
164
- console.log(`Success ${index}:`, result.value);
165
- } else {
166
- console.error(`Failed ${index}:`, result.reason);
167
- }
168
- });
169
- ```
170
-
171
- ## Retry Pattern
172
-
173
- Implement retry with exponential backoff:
174
-
175
- ```typescript
176
- async function retryWithBackoff<T>(
177
- fn: () => Promise<T>,
178
- maxRetries: number = 3
179
- ): Promise<T> {
180
- let lastError: Error;
181
-
182
- for (let attempt = 0; attempt < maxRetries; attempt++) {
183
- try {
184
- return await fn();
185
- } catch (error) {
186
- lastError = error as Error;
187
- if (attempt < maxRetries - 1) {
188
- const delay = 1000 * Math.pow(2, attempt);
189
- await new Promise(resolve => setTimeout(resolve, delay));
190
- }
191
- }
192
- }
193
-
194
- throw lastError!;
195
- }
196
- ```
197
-
198
-
199
- ---
200
-
201
- # TypeScript Types & Interfaces
202
-
203
- ## Prefer Interfaces for Public APIs
204
-
205
- ```typescript
206
- // ✅ Use interfaces for object shapes
207
- interface User {
208
- id: string;
209
- name: string;
210
- email: string;
211
- createdAt: Date;
212
- }
213
-
214
- // ✅ Use type aliases for unions and complex types
215
- type UserRole = 'admin' | 'editor' | 'viewer';
216
- type ResponseHandler = (response: Response) => void;
217
- ```
218
-
219
- ## Discriminated Unions
220
-
221
- ```typescript
222
- // ✅ Use discriminated unions for variant types
223
- type Result<T> =
224
- | { success: true; data: T }
225
- | { success: false; error: string };
226
-
227
- function handleResult(result: Result<User>) {
228
- if (result.success) {
229
- console.log(result.data.name); // TypeScript knows data exists
230
- } else {
231
- console.error(result.error); // TypeScript knows error exists
232
- }
233
- }
234
- ```
235
-
236
- ## Utility Types
237
-
238
- ```typescript
239
- // Use built-in utility types
240
- type PartialUser = Partial<User>; // All fields optional
241
- type RequiredUser = Required<User>; // All fields required
242
- type ReadonlyUser = Readonly<User>; // All fields readonly
243
- type UserKeys = keyof User; // 'id' | 'name' | 'email' | 'createdAt'
244
- type PickedUser = Pick<User, 'id' | 'name'>; // Only id and name
245
- type OmittedUser = Omit<User, 'createdAt'>; // Everything except createdAt
246
- ```
247
-
248
- ## Type Guards
249
-
250
- ```typescript
251
- // ✅ Use type guards for runtime checking
252
- function isUser(value: unknown): value is User {
253
- return (
254
- typeof value === 'object' &&
255
- value !== null &&
256
- 'id' in value &&
257
- 'email' in value
258
- );
259
- }
260
-
261
- // Usage
262
- const data: unknown = fetchData();
263
- if (isUser(data)) {
264
- console.log(data.email); // TypeScript knows it's a User
265
- }
266
- ```
267
-
268
- ## Avoid `any`
269
-
270
- ```typescript
271
- // ❌ Never use any
272
- function process(data: any) {
273
- return data.name; // No type safety
274
- }
275
-
276
- // ✅ Use unknown with type guards
277
- function process(data: unknown) {
278
- if (isUser(data)) {
279
- return data.name; // Type-safe
280
- }
281
- throw new Error('Invalid data');
282
- }
283
- ```
284
-
285
-
286
- ---
287
-
288
- # TypeScript Generics
289
-
290
- ## Basic Generic Functions
291
-
292
- ```typescript
293
- // ✅ Generic function for type-safe operations
294
- function first<T>(array: T[]): T | undefined {
295
- return array[0];
296
- }
297
-
298
- const numbers = [1, 2, 3];
299
- const firstNumber = first(numbers); // Type: number | undefined
300
-
301
- const users = [{ name: 'John' }];
302
- const firstUser = first(users); // Type: { name: string } | undefined
303
- ```
304
-
305
- ## Generic Interfaces
306
-
307
- ```typescript
308
- // ✅ Generic repository pattern
309
- interface Repository<T> {
310
- findById(id: string): Promise<T | null>;
311
- findAll(): Promise<T[]>;
312
- create(entity: Omit<T, 'id'>): Promise<T>;
313
- update(id: string, data: Partial<T>): Promise<T>;
314
- delete(id: string): Promise<void>;
315
- }
316
-
317
- class UserRepository implements Repository<User> {
318
- async findById(id: string): Promise<User | null> {
319
- return this.db.users.findUnique({ where: { id } });
320
- }
321
- // ... other methods
322
- }
323
- ```
324
-
325
- ## Generic Constraints
326
-
327
- ```typescript
328
- // ✅ Constrain generic types
329
- interface HasId {
330
- id: string;
331
- }
332
-
333
- function getById<T extends HasId>(items: T[], id: string): T | undefined {
334
- return items.find(item => item.id === id);
335
- }
336
-
337
- // Works with any type that has an id
338
- getById(users, '123');
339
- getById(products, '456');
340
- ```
341
-
342
- ## Mapped Types
343
-
344
- ```typescript
345
- // ✅ Create transformed types
346
- type Nullable<T> = {
347
- [K in keyof T]: T[K] | null;
348
- };
349
-
350
- type NullableUser = Nullable<User>;
351
- // { id: string | null; name: string | null; ... }
352
-
353
- // ✅ Conditional types
354
- type ExtractArrayType<T> = T extends Array<infer U> ? U : never;
355
-
356
- type StringArrayElement = ExtractArrayType<string[]>; // string
357
- ```
358
-
359
- ## Default Generic Parameters
360
-
361
- ```typescript
362
- // ✅ Provide defaults for flexibility
363
- interface ApiResponse<T = unknown, E = Error> {
364
- data?: T;
365
- error?: E;
366
- status: number;
367
- }
368
-
369
- // Can use with or without type parameters
370
- const response1: ApiResponse<User> = { data: user, status: 200 };
371
- const response2: ApiResponse = { status: 500, error: new Error('Failed') };
372
- ```
373
-
374
-
375
- ---
376
-
377
- # TypeScript Error Handling
378
-
379
- ## Custom Error Classes
380
-
381
- ```typescript
382
- // ✅ Create structured error hierarchy
383
- class AppError extends Error {
384
- constructor(
385
- message: string,
386
- public statusCode: number = 500,
387
- public code: string = 'INTERNAL_ERROR',
388
- public details?: unknown
389
- ) {
390
- super(message);
391
- this.name = this.constructor.name;
392
- Error.captureStackTrace(this, this.constructor);
393
- }
394
- }
395
-
396
- class NotFoundError extends AppError {
397
- constructor(resource: string, id: string) {
398
- super(`${resource} with id ${id} not found`, 404, 'NOT_FOUND', { resource, id });
399
- }
400
- }
401
-
402
- class ValidationError extends AppError {
403
- constructor(message: string, details: unknown) {
404
- super(message, 400, 'VALIDATION_ERROR', details);
405
- }
406
- }
407
- ```
408
-
409
- ## Async Error Handling
410
-
411
- ```typescript
412
- // ✅ Always handle promise rejections
413
- async function fetchUser(id: string): Promise<User> {
414
- try {
415
- const response = await api.get(`/users/${id}`);
416
- return response.data;
417
- } catch (error) {
418
- if (error instanceof ApiError && error.status === 404) {
419
- throw new NotFoundError('User', id);
420
- }
421
- throw new AppError('Failed to fetch user', 500, 'FETCH_ERROR', { userId: id });
422
- }
423
- }
424
-
425
- // ✅ Use wrapper for Express async handlers
426
- const asyncHandler = (fn: RequestHandler) => {
427
- return (req: Request, res: Response, next: NextFunction) => {
428
- Promise.resolve(fn(req, res, next)).catch(next);
429
- };
430
- };
431
- ```
432
-
433
- ## Result Type Pattern
434
-
435
- ```typescript
436
- // ✅ Explicit success/failure without exceptions
437
- type Result<T, E = Error> =
438
- | { success: true; value: T }
439
- | { success: false; error: E };
440
-
441
- function parseJSON<T>(json: string): Result<T, string> {
442
- try {
443
- return { success: true, value: JSON.parse(json) };
444
- } catch {
445
- return { success: false, error: 'Invalid JSON' };
446
- }
447
- }
448
-
449
- // Usage
450
- const result = parseJSON<User>(data);
451
- if (result.success) {
452
- console.log(result.value.name);
453
- } else {
454
- console.error(result.error);
455
- }
456
- ```
457
-
458
- ## Centralized Error Handler
459
-
460
- ```typescript
461
- // ✅ Express error middleware
462
- app.use((err: Error, req: Request, res: Response, next: NextFunction) => {
463
- if (err instanceof AppError) {
464
- return res.status(err.statusCode).json({
465
- error: { message: err.message, code: err.code, details: err.details }
466
- });
467
- }
468
-
469
- console.error('Unexpected error:', err);
470
- res.status(500).json({
471
- error: { message: 'Internal server error', code: 'INTERNAL_ERROR' }
472
- });
473
- });
474
- ```
475
-
476
-
477
- ---
478
-
479
- # TypeScript Testing
480
-
481
- ## Test Structure: Arrange-Act-Assert
482
-
483
- ```typescript
484
- describe('UserService', () => {
485
- describe('createUser', () => {
486
- it('should create user with hashed password', async () => {
487
- // Arrange
488
- const userData = { email: 'test@example.com', password: 'password123' };
489
- const mockRepo = { save: jest.fn().mockResolvedValue({ id: '1', ...userData }) };
490
- const service = new UserService(mockRepo);
491
-
492
- // Act
493
- const result = await service.createUser(userData);
494
-
495
- // Assert
496
- expect(result.id).toBe('1');
497
- expect(mockRepo.save).toHaveBeenCalledWith(
498
- expect.objectContaining({ email: 'test@example.com' })
499
- );
500
- });
501
- });
502
- });
503
- ```
504
-
505
- ## Test Observable Behavior, Not Implementation
506
-
507
- ```typescript
508
- // ❌ Testing implementation details
509
- it('should call validateEmail method', () => {
510
- const spy = jest.spyOn(service, 'validateEmail');
511
- service.createUser({ email: 'test@example.com' });
512
- expect(spy).toHaveBeenCalled(); // Brittle - breaks if refactored
513
- });
514
-
515
- // ✅ Testing observable behavior
516
- it('should reject invalid email', async () => {
517
- await expect(
518
- service.createUser({ email: 'invalid' })
519
- ).rejects.toThrow('Invalid email');
520
- });
521
- ```
522
-
523
- ## Test Doubles
524
-
525
- ```typescript
526
- // Stub: Returns canned responses
527
- const stubDatabase = {
528
- findUser: () => ({ id: '1', name: 'Test User' })
529
- };
530
-
531
- // Mock: Pre-programmed with expectations
532
- const mockPayment = {
533
- charge: jest.fn()
534
- .mockResolvedValueOnce({ success: true })
535
- .mockResolvedValueOnce({ success: false })
536
- };
537
-
538
- // Fake: Working implementation (not for production)
539
- class FakeDatabase implements Database {
540
- private data = new Map<string, any>();
541
-
542
- async save(id: string, data: any) { this.data.set(id, data); }
543
- async find(id: string) { return this.data.get(id); }
544
- }
545
- ```
546
-
547
- ## One Test Per Condition
548
-
549
- ```typescript
550
- // ❌ Multiple assertions for different scenarios
551
- it('should validate user input', () => {
552
- expect(() => validate({ age: -1 })).toThrow();
553
- expect(() => validate({ age: 200 })).toThrow();
554
- expect(() => validate({ name: '' })).toThrow();
555
- });
556
-
557
- // ✅ One test per condition
558
- it('should reject negative age', () => {
559
- expect(() => validate({ age: -1 })).toThrow('Age must be positive');
560
- });
561
-
562
- it('should reject age over 150', () => {
563
- expect(() => validate({ age: 200 })).toThrow('Age must be under 150');
564
- });
565
- ```
566
-
567
- ## Keep Tests Independent
568
-
569
- ```typescript
570
- // ✅ Each test is self-contained
571
- it('should update user', async () => {
572
- const user = await service.createUser({ name: 'Test' });
573
- const updated = await service.updateUser(user.id, { name: 'Updated' });
574
- expect(updated.name).toBe('Updated');
575
- });
576
- ```
577
-
578
-
579
- ---
580
-
581
- # TypeScript Configuration
582
-
583
- ## tsconfig.json Best Practices
584
-
585
- ```json
586
- {
587
- "compilerOptions": {
588
- // Strict type checking
589
- "strict": true,
590
- "noImplicitAny": true,
591
- "strictNullChecks": true,
592
- "strictFunctionTypes": true,
593
- "strictBindCallApply": true,
594
- "strictPropertyInitialization": true,
595
- "noImplicitThis": true,
596
- "alwaysStrict": true,
597
-
598
- // Additional checks
599
- "noUnusedLocals": true,
600
- "noUnusedParameters": true,
601
- "noImplicitReturns": true,
602
- "noFallthroughCasesInSwitch": true,
603
- "noUncheckedIndexedAccess": true,
604
-
605
- // Module resolution
606
- "module": "ESNext",
607
- "moduleResolution": "bundler",
608
- "esModuleInterop": true,
609
- "allowSyntheticDefaultImports": true,
610
- "resolveJsonModule": true,
611
-
612
- // Output
613
- "target": "ES2022",
614
- "outDir": "./dist",
615
- "declaration": true,
616
- "declarationMap": true,
617
- "sourceMap": true,
618
-
619
- // Path aliases
620
- "baseUrl": ".",
621
- "paths": {
622
- "@/*": ["src/*"],
623
- "@services/*": ["src/services/*"],
624
- "@models/*": ["src/models/*"]
625
- }
626
- },
627
- "include": ["src/**/*"],
628
- "exclude": ["node_modules", "dist", "**/*.test.ts"]
629
- }
630
- ```
631
-
632
- ## Path Aliases Setup
633
-
634
- ```typescript
635
- // With path aliases configured:
636
- import { UserService } from '@services/user';
637
- import { User } from '@models/user';
638
-
639
- // Instead of relative paths:
640
- import { UserService } from '../../../services/user';
641
- ```
642
-
643
- ## Project References (Monorepo)
644
-
645
- ```json
646
- // packages/shared/tsconfig.json
647
- {
648
- "compilerOptions": {
649
- "composite": true,
650
- "outDir": "./dist"
651
- }
652
- }
653
-
654
- // packages/api/tsconfig.json
655
- {
656
- "extends": "../../tsconfig.base.json",
657
- "references": [
658
- { "path": "../shared" }
659
- ]
660
- }
661
- ```
662
-
663
- ## Environment-Specific Configs
664
-
665
- ```json
666
- // tsconfig.build.json - for production builds
667
- {
668
- "extends": "./tsconfig.json",
669
- "compilerOptions": {
670
- "sourceMap": false,
671
- "removeComments": true
672
- },
673
- "exclude": ["**/*.test.ts", "**/*.spec.ts"]
674
- }
675
- ```
676
-
677
-
678
- ---
679
-
680
- # TypeScript Performance
681
-
682
- ## Choose Right Data Structures
683
-
684
- ```typescript
685
- // ❌ Array for lookups (O(n))
686
- const users: User[] = [];
687
- const findUser = (id: string) => users.find(u => u.id === id);
688
-
689
- // ✅ Map for O(1) lookups
690
- const users = new Map<string, User>();
691
- const findUser = (id: string) => users.get(id);
692
-
693
- // ❌ Array for membership checks
694
- const hasPermission = (perms: string[], perm: string) => perms.includes(perm);
695
-
696
- // ✅ Set for O(1) membership
697
- const hasPermission = (perms: Set<string>, perm: string) => perms.has(perm);
698
- ```
699
-
700
- ## Avoid N+1 Queries
701
-
702
- ```typescript
703
- // ❌ N+1 queries
704
- const getOrdersWithCustomers = async () => {
705
- const orders = await db.query('SELECT * FROM orders');
706
- for (const order of orders) {
707
- order.customer = await db.query('SELECT * FROM customers WHERE id = ?', [order.customerId]);
708
- }
709
- return orders;
710
- };
711
-
712
- // ✅ Single JOIN query
713
- const getOrdersWithCustomers = async () => {
714
- return db.query(`
715
- SELECT orders.*, customers.name as customer_name
716
- FROM orders
717
- JOIN customers ON orders.customer_id = customers.id
718
- `);
719
- };
720
-
721
- // ✅ Using ORM with eager loading
722
- const getOrdersWithCustomers = async () => {
723
- return orderRepository.find({ relations: ['customer'] });
724
- };
725
- ```
726
-
727
- ## Parallel Execution
728
-
729
- ```typescript
730
- // ❌ Sequential (slow)
731
- const getUserData = async (userId: string) => {
732
- const user = await fetchUser(userId); // 100ms
733
- const posts = await fetchPosts(userId); // 150ms
734
- const comments = await fetchComments(userId); // 120ms
735
- return { user, posts, comments }; // Total: 370ms
736
- };
737
-
738
- // ✅ Parallel (fast)
739
- const getUserData = async (userId: string) => {
740
- const [user, posts, comments] = await Promise.all([
741
- fetchUser(userId),
742
- fetchPosts(userId),
743
- fetchComments(userId)
744
- ]);
745
- return { user, posts, comments }; // Total: 150ms
746
- };
747
- ```
748
-
749
- ## Memoization
750
-
751
- ```typescript
752
- const memoize = <T extends (...args: any[]) => any>(fn: T): T => {
753
- const cache = new Map<string, ReturnType<T>>();
754
-
755
- return ((...args: any[]) => {
756
- const key = JSON.stringify(args);
757
- if (cache.has(key)) return cache.get(key);
758
- const result = fn(...args);
759
- cache.set(key, result);
760
- return result;
761
- }) as T;
762
- };
763
-
764
- const expensiveCalc = memoize((n: number) => {
765
- // Expensive computation
766
- return result;
767
- });
768
- ```
769
-
770
- ## Batch Processing
771
-
772
- ```typescript
773
- // ✅ Process in batches
774
- const processUsers = async (userIds: string[]) => {
775
- const BATCH_SIZE = 50;
776
-
777
- for (let i = 0; i < userIds.length; i += BATCH_SIZE) {
778
- const batch = userIds.slice(i, i + BATCH_SIZE);
779
- await Promise.all(batch.map(id => updateUser(id)));
780
- }
781
- };
782
- ```
783
-
784
-
785
- ---
786
- *Generated by aicgen*