omgkit 2.1.0 → 2.2.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.
Files changed (56) hide show
  1. package/package.json +1 -1
  2. package/plugin/skills/SKILL_STANDARDS.md +743 -0
  3. package/plugin/skills/databases/mongodb/SKILL.md +797 -28
  4. package/plugin/skills/databases/postgresql/SKILL.md +494 -18
  5. package/plugin/skills/databases/prisma/SKILL.md +776 -30
  6. package/plugin/skills/databases/redis/SKILL.md +885 -25
  7. package/plugin/skills/devops/aws/SKILL.md +686 -28
  8. package/plugin/skills/devops/docker/SKILL.md +466 -18
  9. package/plugin/skills/devops/github-actions/SKILL.md +684 -29
  10. package/plugin/skills/devops/kubernetes/SKILL.md +621 -24
  11. package/plugin/skills/frameworks/django/SKILL.md +920 -20
  12. package/plugin/skills/frameworks/express/SKILL.md +1361 -35
  13. package/plugin/skills/frameworks/fastapi/SKILL.md +1260 -33
  14. package/plugin/skills/frameworks/laravel/SKILL.md +1244 -31
  15. package/plugin/skills/frameworks/nestjs/SKILL.md +1005 -26
  16. package/plugin/skills/frameworks/nextjs/SKILL.md +407 -44
  17. package/plugin/skills/frameworks/rails/SKILL.md +594 -28
  18. package/plugin/skills/frameworks/react/SKILL.md +1006 -32
  19. package/plugin/skills/frameworks/spring/SKILL.md +528 -35
  20. package/plugin/skills/frameworks/vue/SKILL.md +1296 -27
  21. package/plugin/skills/frontend/accessibility/SKILL.md +1108 -34
  22. package/plugin/skills/frontend/frontend-design/SKILL.md +1304 -26
  23. package/plugin/skills/frontend/responsive/SKILL.md +847 -21
  24. package/plugin/skills/frontend/shadcn-ui/SKILL.md +976 -38
  25. package/plugin/skills/frontend/tailwindcss/SKILL.md +831 -35
  26. package/plugin/skills/frontend/threejs/SKILL.md +1298 -29
  27. package/plugin/skills/languages/javascript/SKILL.md +935 -31
  28. package/plugin/skills/languages/python/SKILL.md +489 -25
  29. package/plugin/skills/languages/typescript/SKILL.md +379 -30
  30. package/plugin/skills/methodology/brainstorming/SKILL.md +597 -23
  31. package/plugin/skills/methodology/defense-in-depth/SKILL.md +832 -34
  32. package/plugin/skills/methodology/dispatching-parallel-agents/SKILL.md +665 -31
  33. package/plugin/skills/methodology/executing-plans/SKILL.md +556 -24
  34. package/plugin/skills/methodology/finishing-development-branch/SKILL.md +595 -25
  35. package/plugin/skills/methodology/problem-solving/SKILL.md +429 -61
  36. package/plugin/skills/methodology/receiving-code-review/SKILL.md +536 -24
  37. package/plugin/skills/methodology/requesting-code-review/SKILL.md +632 -21
  38. package/plugin/skills/methodology/root-cause-tracing/SKILL.md +641 -30
  39. package/plugin/skills/methodology/sequential-thinking/SKILL.md +262 -3
  40. package/plugin/skills/methodology/systematic-debugging/SKILL.md +571 -32
  41. package/plugin/skills/methodology/test-driven-development/SKILL.md +779 -24
  42. package/plugin/skills/methodology/testing-anti-patterns/SKILL.md +691 -29
  43. package/plugin/skills/methodology/token-optimization/SKILL.md +598 -29
  44. package/plugin/skills/methodology/verification-before-completion/SKILL.md +543 -22
  45. package/plugin/skills/methodology/writing-plans/SKILL.md +590 -18
  46. package/plugin/skills/omega/omega-architecture/SKILL.md +838 -39
  47. package/plugin/skills/omega/omega-coding/SKILL.md +636 -39
  48. package/plugin/skills/omega/omega-sprint/SKILL.md +855 -48
  49. package/plugin/skills/omega/omega-testing/SKILL.md +940 -41
  50. package/plugin/skills/omega/omega-thinking/SKILL.md +703 -50
  51. package/plugin/skills/security/better-auth/SKILL.md +1065 -28
  52. package/plugin/skills/security/oauth/SKILL.md +968 -31
  53. package/plugin/skills/security/owasp/SKILL.md +894 -33
  54. package/plugin/skills/testing/playwright/SKILL.md +764 -38
  55. package/plugin/skills/testing/pytest/SKILL.md +873 -36
  56. package/plugin/skills/testing/vitest/SKILL.md +980 -35
@@ -1,62 +1,966 @@
1
1
  ---
2
2
  name: javascript
3
- description: JavaScript development. Use for ES6+, async patterns, DOM manipulation.
3
+ description: Modern JavaScript development with ES2024+, async patterns, functional programming, and Node.js
4
+ category: languages
5
+ triggers:
6
+ - javascript
7
+ - js
8
+ - es6
9
+ - es2024
10
+ - ecmascript
11
+ - node
12
+ - nodejs
13
+ - npm
4
14
  ---
5
15
 
6
- # JavaScript Skill
16
+ # JavaScript
7
17
 
8
- ## Patterns
18
+ Modern **JavaScript development** following industry best practices. This skill covers ES2024+ features, async patterns, functional programming, error handling, testing, and production-ready patterns used by top engineering teams.
19
+
20
+ ## Purpose
21
+
22
+ Write clean, maintainable JavaScript code:
23
+
24
+ - Master modern ES2024+ syntax and features
25
+ - Implement robust async/await patterns
26
+ - Use functional programming effectively
27
+ - Handle errors properly
28
+ - Structure projects for maintainability
29
+ - Write comprehensive tests
30
+ - Build for performance
31
+
32
+ ## Features
33
+
34
+ ### 1. Modern Syntax (ES2024+)
35
+
36
+ ```javascript
37
+ // Destructuring - Objects and Arrays
38
+ const user = { name: 'John', email: 'john@example.com', role: 'admin' };
39
+ const { name, email, role = 'user' } = user;
40
+
41
+ const numbers = [1, 2, 3, 4, 5];
42
+ const [first, second, ...rest] = numbers;
43
+
44
+ // Nested destructuring
45
+ const response = {
46
+ data: {
47
+ user: { id: 1, profile: { avatar: 'url' } }
48
+ }
49
+ };
50
+ const { data: { user: { profile: { avatar } } } } = response;
51
+
52
+ // Spread operator - Objects and Arrays
53
+ const defaults = { theme: 'light', language: 'en' };
54
+ const settings = { ...defaults, theme: 'dark', notifications: true };
55
+
56
+ const combined = [...numbers, 6, 7, 8];
57
+
58
+ // Rest parameters
59
+ function sum(...numbers) {
60
+ return numbers.reduce((acc, n) => acc + n, 0);
61
+ }
62
+
63
+ // Optional chaining and nullish coalescing
64
+ const street = user?.address?.street ?? 'Unknown';
65
+ const callback = options?.onComplete;
66
+ callback?.();
67
+
68
+ // Logical assignment operators
69
+ let config = {};
70
+ config.timeout ??= 5000;
71
+ config.retries ||= 3;
72
+ config.debug &&= process.env.NODE_ENV !== 'production';
73
+
74
+ // Array methods - at(), findLast(), toSorted(), toReversed()
75
+ const lastItem = numbers.at(-1);
76
+ const lastEven = numbers.findLast(n => n % 2 === 0);
77
+ const sorted = numbers.toSorted((a, b) => b - a); // Non-mutating
78
+ const reversed = numbers.toReversed(); // Non-mutating
79
+
80
+ // Object.groupBy() (ES2024)
81
+ const items = [
82
+ { type: 'fruit', name: 'apple' },
83
+ { type: 'vegetable', name: 'carrot' },
84
+ { type: 'fruit', name: 'banana' },
85
+ ];
86
+ const grouped = Object.groupBy(items, item => item.type);
87
+
88
+ // Promise.withResolvers() (ES2024)
89
+ const { promise, resolve, reject } = Promise.withResolvers();
90
+
91
+ // Template literals with tags
92
+ function highlight(strings, ...values) {
93
+ return strings.reduce((result, str, i) =>
94
+ `${result}${str}${values[i] ? `<mark>${values[i]}</mark>` : ''}`, ''
95
+ );
96
+ }
97
+ const message = highlight`Hello ${name}, your role is ${role}`;
98
+
99
+ // Private class fields
100
+ class Counter {
101
+ #count = 0;
102
+
103
+ increment() {
104
+ this.#count++;
105
+ }
106
+
107
+ get value() {
108
+ return this.#count;
109
+ }
110
+ }
111
+ ```
112
+
113
+ ### 2. Async Patterns
9
114
 
10
- ### Async/Await
11
115
  ```javascript
12
- async function fetchData() {
116
+ // Basic async/await
117
+ async function fetchUser(id) {
13
118
  try {
14
- const response = await fetch('/api/data');
15
- const data = await response.json();
16
- return data;
119
+ const response = await fetch(`/api/users/${id}`);
120
+ if (!response.ok) {
121
+ throw new Error(`HTTP error! status: ${response.status}`);
122
+ }
123
+ return await response.json();
17
124
  } catch (error) {
18
- console.error('Fetch failed:', error);
125
+ console.error('Failed to fetch user:', error);
19
126
  throw error;
20
127
  }
21
128
  }
129
+
130
+ // Parallel execution with Promise.all
131
+ async function fetchUserWithPosts(userId) {
132
+ const [user, posts] = await Promise.all([
133
+ fetchUser(userId),
134
+ fetchPosts(userId),
135
+ ]);
136
+ return { user, posts };
137
+ }
138
+
139
+ // Promise.allSettled for handling mixed results
140
+ async function fetchAllUsers(ids) {
141
+ const results = await Promise.allSettled(
142
+ ids.map(id => fetchUser(id))
143
+ );
144
+
145
+ const successful = results
146
+ .filter(r => r.status === 'fulfilled')
147
+ .map(r => r.value);
148
+
149
+ const failed = results
150
+ .filter(r => r.status === 'rejected')
151
+ .map(r => r.reason);
152
+
153
+ return { successful, failed };
154
+ }
155
+
156
+ // Promise.race for timeouts
157
+ async function fetchWithTimeout(url, timeout = 5000) {
158
+ const controller = new AbortController();
159
+
160
+ const timeoutPromise = new Promise((_, reject) => {
161
+ setTimeout(() => {
162
+ controller.abort();
163
+ reject(new Error('Request timeout'));
164
+ }, timeout);
165
+ });
166
+
167
+ const fetchPromise = fetch(url, { signal: controller.signal });
168
+
169
+ return Promise.race([fetchPromise, timeoutPromise]);
170
+ }
171
+
172
+ // Async iteration
173
+ async function* fetchPages(baseUrl) {
174
+ let page = 1;
175
+ let hasMore = true;
176
+
177
+ while (hasMore) {
178
+ const response = await fetch(`${baseUrl}?page=${page}`);
179
+ const data = await response.json();
180
+
181
+ yield data.items;
182
+
183
+ hasMore = data.hasMore;
184
+ page++;
185
+ }
186
+ }
187
+
188
+ // Using async iterator
189
+ async function processAllPages() {
190
+ for await (const items of fetchPages('/api/items')) {
191
+ for (const item of items) {
192
+ await processItem(item);
193
+ }
194
+ }
195
+ }
196
+
197
+ // Retry pattern with exponential backoff
198
+ async function withRetry(fn, maxRetries = 3, baseDelay = 1000) {
199
+ let lastError;
200
+
201
+ for (let attempt = 0; attempt < maxRetries; attempt++) {
202
+ try {
203
+ return await fn();
204
+ } catch (error) {
205
+ lastError = error;
206
+
207
+ if (attempt < maxRetries - 1) {
208
+ const delay = baseDelay * Math.pow(2, attempt);
209
+ await new Promise(resolve => setTimeout(resolve, delay));
210
+ }
211
+ }
212
+ }
213
+
214
+ throw lastError;
215
+ }
216
+
217
+ // Concurrent execution with limit
218
+ async function mapWithConcurrency(items, fn, limit = 5) {
219
+ const results = [];
220
+ const executing = new Set();
221
+
222
+ for (const item of items) {
223
+ const promise = fn(item).then(result => {
224
+ executing.delete(promise);
225
+ return result;
226
+ });
227
+
228
+ executing.add(promise);
229
+ results.push(promise);
230
+
231
+ if (executing.size >= limit) {
232
+ await Promise.race(executing);
233
+ }
234
+ }
235
+
236
+ return Promise.all(results);
237
+ }
22
238
  ```
23
239
 
24
- ### Destructuring
240
+ ### 3. Functional Programming
241
+
25
242
  ```javascript
26
- const { name, email } = user;
27
- const [first, ...rest] = items;
28
- const { data: userData } = response;
243
+ // Pure functions
244
+ const add = (a, b) => a + b;
245
+ const multiply = (a, b) => a * b;
246
+
247
+ // Function composition
248
+ const compose = (...fns) => x =>
249
+ fns.reduceRight((acc, fn) => fn(acc), x);
250
+
251
+ const pipe = (...fns) => x =>
252
+ fns.reduce((acc, fn) => fn(acc), x);
253
+
254
+ // Currying
255
+ const curry = fn => {
256
+ return function curried(...args) {
257
+ if (args.length >= fn.length) {
258
+ return fn.apply(this, args);
259
+ }
260
+ return (...nextArgs) => curried(...args, ...nextArgs);
261
+ };
262
+ };
263
+
264
+ const addCurried = curry((a, b, c) => a + b + c);
265
+ const add5 = addCurried(5);
266
+ const add5and3 = add5(3);
267
+ const result = add5and3(2); // 10
268
+
269
+ // Partial application
270
+ const partial = (fn, ...presetArgs) =>
271
+ (...laterArgs) => fn(...presetArgs, ...laterArgs);
272
+
273
+ const greet = (greeting, name) => `${greeting}, ${name}!`;
274
+ const sayHello = partial(greet, 'Hello');
275
+ sayHello('World'); // "Hello, World!"
276
+
277
+ // Higher-order functions
278
+ const map = fn => arr => arr.map(fn);
279
+ const filter = pred => arr => arr.filter(pred);
280
+ const reduce = (fn, initial) => arr => arr.reduce(fn, initial);
281
+
282
+ // Point-free style
283
+ const double = x => x * 2;
284
+ const isEven = x => x % 2 === 0;
285
+ const sum = (a, b) => a + b;
286
+
287
+ const processNumbers = pipe(
288
+ filter(isEven),
289
+ map(double),
290
+ reduce(sum, 0)
291
+ );
292
+
293
+ processNumbers([1, 2, 3, 4, 5]); // 12
294
+
295
+ // Immutable operations
296
+ const updateUser = (user, updates) => ({
297
+ ...user,
298
+ ...updates,
299
+ updatedAt: new Date().toISOString(),
300
+ });
301
+
302
+ const addItem = (array, item) => [...array, item];
303
+ const removeItem = (array, index) => [
304
+ ...array.slice(0, index),
305
+ ...array.slice(index + 1),
306
+ ];
307
+ const updateItem = (array, index, item) => [
308
+ ...array.slice(0, index),
309
+ item,
310
+ ...array.slice(index + 1),
311
+ ];
312
+
313
+ // Memoization
314
+ const memoize = fn => {
315
+ const cache = new Map();
316
+
317
+ return (...args) => {
318
+ const key = JSON.stringify(args);
319
+
320
+ if (cache.has(key)) {
321
+ return cache.get(key);
322
+ }
323
+
324
+ const result = fn(...args);
325
+ cache.set(key, result);
326
+ return result;
327
+ };
328
+ };
329
+
330
+ const expensiveCalculation = memoize((n) => {
331
+ console.log('Computing...');
332
+ return n * n;
333
+ });
334
+
335
+ // Option/Maybe pattern
336
+ const Option = {
337
+ some: value => ({
338
+ isSome: true,
339
+ isNone: false,
340
+ map: fn => Option.some(fn(value)),
341
+ flatMap: fn => fn(value),
342
+ getOrElse: () => value,
343
+ filter: pred => pred(value) ? Option.some(value) : Option.none(),
344
+ }),
345
+
346
+ none: () => ({
347
+ isSome: false,
348
+ isNone: true,
349
+ map: () => Option.none(),
350
+ flatMap: () => Option.none(),
351
+ getOrElse: defaultValue => defaultValue,
352
+ filter: () => Option.none(),
353
+ }),
354
+
355
+ fromNullable: value =>
356
+ value != null ? Option.some(value) : Option.none(),
357
+ };
358
+
359
+ // Usage
360
+ const userName = Option.fromNullable(user?.name)
361
+ .map(name => name.toUpperCase())
362
+ .getOrElse('Anonymous');
29
363
  ```
30
364
 
31
- ### Spread Operator
365
+ ### 4. Error Handling
366
+
32
367
  ```javascript
33
- const merged = { ...defaults, ...options };
34
- const combined = [...array1, ...array2];
368
+ // Custom error classes
369
+ class AppError extends Error {
370
+ constructor(message, code, statusCode = 500) {
371
+ super(message);
372
+ this.name = this.constructor.name;
373
+ this.code = code;
374
+ this.statusCode = statusCode;
375
+ Error.captureStackTrace(this, this.constructor);
376
+ }
377
+
378
+ toJSON() {
379
+ return {
380
+ name: this.name,
381
+ message: this.message,
382
+ code: this.code,
383
+ statusCode: this.statusCode,
384
+ };
385
+ }
386
+ }
387
+
388
+ class ValidationError extends AppError {
389
+ constructor(field, message) {
390
+ super(message, 'VALIDATION_ERROR', 400);
391
+ this.field = field;
392
+ }
393
+ }
394
+
395
+ class NotFoundError extends AppError {
396
+ constructor(resource, id) {
397
+ super(`${resource} with id ${id} not found`, 'NOT_FOUND', 404);
398
+ this.resource = resource;
399
+ this.resourceId = id;
400
+ }
401
+ }
402
+
403
+ class UnauthorizedError extends AppError {
404
+ constructor(message = 'Unauthorized') {
405
+ super(message, 'UNAUTHORIZED', 401);
406
+ }
407
+ }
408
+
409
+ // Result type pattern
410
+ class Result {
411
+ constructor(value, error) {
412
+ this.value = value;
413
+ this.error = error;
414
+ }
415
+
416
+ static ok(value) {
417
+ return new Result(value, null);
418
+ }
419
+
420
+ static err(error) {
421
+ return new Result(null, error);
422
+ }
423
+
424
+ isOk() {
425
+ return this.error === null;
426
+ }
427
+
428
+ isErr() {
429
+ return this.error !== null;
430
+ }
431
+
432
+ map(fn) {
433
+ return this.isOk() ? Result.ok(fn(this.value)) : this;
434
+ }
435
+
436
+ flatMap(fn) {
437
+ return this.isOk() ? fn(this.value) : this;
438
+ }
439
+
440
+ mapErr(fn) {
441
+ return this.isErr() ? Result.err(fn(this.error)) : this;
442
+ }
443
+
444
+ unwrap() {
445
+ if (this.isErr()) throw this.error;
446
+ return this.value;
447
+ }
448
+
449
+ unwrapOr(defaultValue) {
450
+ return this.isOk() ? this.value : defaultValue;
451
+ }
452
+
453
+ match({ ok, err }) {
454
+ return this.isOk() ? ok(this.value) : err(this.error);
455
+ }
456
+ }
457
+
458
+ // Usage
459
+ async function safeParseJSON(text) {
460
+ try {
461
+ return Result.ok(JSON.parse(text));
462
+ } catch (error) {
463
+ return Result.err(new ValidationError('json', 'Invalid JSON'));
464
+ }
465
+ }
466
+
467
+ async function safeFetch(url) {
468
+ try {
469
+ const response = await fetch(url);
470
+ if (!response.ok) {
471
+ return Result.err(new AppError(`HTTP ${response.status}`, 'HTTP_ERROR'));
472
+ }
473
+ const data = await response.json();
474
+ return Result.ok(data);
475
+ } catch (error) {
476
+ return Result.err(error);
477
+ }
478
+ }
479
+
480
+ // Error boundary pattern
481
+ async function withErrorBoundary(fn, fallback) {
482
+ try {
483
+ return await fn();
484
+ } catch (error) {
485
+ console.error('Error caught in boundary:', error);
486
+
487
+ if (typeof fallback === 'function') {
488
+ return fallback(error);
489
+ }
490
+
491
+ return fallback;
492
+ }
493
+ }
494
+
495
+ // Global error handling
496
+ process.on('uncaughtException', (error) => {
497
+ console.error('Uncaught Exception:', error);
498
+ process.exit(1);
499
+ });
500
+
501
+ process.on('unhandledRejection', (reason, promise) => {
502
+ console.error('Unhandled Rejection at:', promise, 'reason:', reason);
503
+ });
35
504
  ```
36
505
 
37
- ### Modules (ESM)
506
+ ### 5. Modules and Project Structure
507
+
38
508
  ```javascript
39
509
  // Named exports
40
- export const helper = () => {};
41
- export function process() {}
510
+ // utils/string.js
511
+ export const capitalize = str =>
512
+ str.charAt(0).toUpperCase() + str.slice(1);
513
+
514
+ export const slugify = str =>
515
+ str.toLowerCase().replace(/\s+/g, '-').replace(/[^a-z0-9-]/g, '');
516
+
517
+ export const truncate = (str, length, suffix = '...') =>
518
+ str.length > length ? str.slice(0, length) + suffix : str;
519
+
520
+ // Default export with named exports
521
+ // services/api.js
522
+ class ApiService {
523
+ constructor(baseUrl) {
524
+ this.baseUrl = baseUrl;
525
+ }
526
+
527
+ async get(path) {
528
+ const response = await fetch(`${this.baseUrl}${path}`);
529
+ return response.json();
530
+ }
531
+
532
+ async post(path, data) {
533
+ const response = await fetch(`${this.baseUrl}${path}`, {
534
+ method: 'POST',
535
+ headers: { 'Content-Type': 'application/json' },
536
+ body: JSON.stringify(data),
537
+ });
538
+ return response.json();
539
+ }
540
+ }
541
+
542
+ export default ApiService;
543
+ export const createApi = baseUrl => new ApiService(baseUrl);
544
+
545
+ // Re-exports (barrel exports)
546
+ // services/index.js
547
+ export { default as ApiService, createApi } from './api.js';
548
+ export { default as AuthService } from './auth.js';
549
+ export { default as UserService } from './user.js';
550
+ export * from './constants.js';
551
+
552
+ // Dynamic imports
553
+ async function loadModule(moduleName) {
554
+ try {
555
+ const module = await import(`./modules/${moduleName}.js`);
556
+ return module.default;
557
+ } catch (error) {
558
+ console.error(`Failed to load module: ${moduleName}`);
559
+ return null;
560
+ }
561
+ }
42
562
 
43
- // Default export
44
- export default class Service {}
563
+ // Conditional imports
564
+ async function loadFeature() {
565
+ if (process.env.FEATURE_FLAG) {
566
+ const { enableFeature } = await import('./features/newFeature.js');
567
+ enableFeature();
568
+ }
569
+ }
45
570
 
46
- // Import
47
- import Service, { helper, process } from './service.js';
571
+ // Project structure example
572
+ /*
573
+ src/
574
+ ├── index.js # Entry point
575
+ ├── config/
576
+ │ ├── index.js # Configuration exports
577
+ │ ├── database.js
578
+ │ └── server.js
579
+ ├── services/
580
+ │ ├── index.js # Barrel exports
581
+ │ ├── api.js
582
+ │ ├── auth.js
583
+ │ └── user.js
584
+ ├── utils/
585
+ │ ├── index.js
586
+ │ ├── string.js
587
+ │ ├── date.js
588
+ │ └── validation.js
589
+ ├── models/
590
+ │ ├── index.js
591
+ │ ├── User.js
592
+ │ └── Post.js
593
+ └── middleware/
594
+ ├── index.js
595
+ ├── auth.js
596
+ └── validation.js
597
+ */
48
598
  ```
49
599
 
50
- ### Optional Chaining
600
+ ### 6. Data Structures and Collections
601
+
51
602
  ```javascript
52
- const street = user?.address?.street;
53
- const result = callback?.();
603
+ // Map - key-value with any type keys
604
+ const userCache = new Map();
605
+ userCache.set('user:1', { id: 1, name: 'John' });
606
+ userCache.set('user:2', { id: 2, name: 'Jane' });
607
+
608
+ // Map iteration
609
+ for (const [key, value] of userCache) {
610
+ console.log(key, value);
611
+ }
612
+
613
+ // Map with object keys
614
+ const objectMap = new Map();
615
+ const key1 = { id: 1 };
616
+ const key2 = { id: 2 };
617
+ objectMap.set(key1, 'value1');
618
+ objectMap.set(key2, 'value2');
619
+
620
+ // Set - unique values
621
+ const uniqueIds = new Set([1, 2, 3, 1, 2]); // Set(3) {1, 2, 3}
622
+ uniqueIds.add(4);
623
+ uniqueIds.has(1); // true
624
+ uniqueIds.delete(1);
625
+
626
+ // Set operations
627
+ const setA = new Set([1, 2, 3, 4]);
628
+ const setB = new Set([3, 4, 5, 6]);
629
+
630
+ const union = new Set([...setA, ...setB]);
631
+ const intersection = new Set([...setA].filter(x => setB.has(x)));
632
+ const difference = new Set([...setA].filter(x => !setB.has(x)));
633
+
634
+ // WeakMap - garbage-collected keys
635
+ const privateData = new WeakMap();
636
+
637
+ class User {
638
+ constructor(name, secret) {
639
+ privateData.set(this, { secret });
640
+ this.name = name;
641
+ }
642
+
643
+ getSecret() {
644
+ return privateData.get(this).secret;
645
+ }
646
+ }
647
+
648
+ // WeakSet - garbage-collected values
649
+ const visitedNodes = new WeakSet();
650
+
651
+ function traverseOnce(node) {
652
+ if (visitedNodes.has(node)) return;
653
+ visitedNodes.add(node);
654
+ // Process node
655
+ }
656
+
657
+ // Typed Arrays for binary data
658
+ const buffer = new ArrayBuffer(16);
659
+ const int32View = new Int32Array(buffer);
660
+ const float64View = new Float64Array(buffer);
661
+
662
+ int32View[0] = 42;
663
+ float64View[1] = 3.14;
664
+
665
+ // Proxy for reactive objects
666
+ function reactive(target) {
667
+ return new Proxy(target, {
668
+ get(obj, prop) {
669
+ console.log(`Getting ${prop}`);
670
+ return obj[prop];
671
+ },
672
+ set(obj, prop, value) {
673
+ console.log(`Setting ${prop} to ${value}`);
674
+ obj[prop] = value;
675
+ return true;
676
+ },
677
+ });
678
+ }
679
+
680
+ const state = reactive({ count: 0 });
681
+ state.count++; // Logs: Getting count, Setting count to 1
682
+ ```
683
+
684
+ ### 7. Testing Patterns
685
+
686
+ ```javascript
687
+ // Jest/Vitest test structure
688
+ import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
689
+ import { UserService } from './user.service.js';
690
+ import { ApiService } from './api.service.js';
691
+
692
+ // Mock the API service
693
+ vi.mock('./api.service.js');
694
+
695
+ describe('UserService', () => {
696
+ let userService;
697
+ let mockApi;
698
+
699
+ beforeEach(() => {
700
+ mockApi = {
701
+ get: vi.fn(),
702
+ post: vi.fn(),
703
+ patch: vi.fn(),
704
+ delete: vi.fn(),
705
+ };
706
+ userService = new UserService(mockApi);
707
+ });
708
+
709
+ afterEach(() => {
710
+ vi.clearAllMocks();
711
+ });
712
+
713
+ describe('getUser', () => {
714
+ it('should return user when found', async () => {
715
+ const mockUser = { id: '1', name: 'John', email: 'john@example.com' };
716
+ mockApi.get.mockResolvedValue(mockUser);
717
+
718
+ const user = await userService.getUser('1');
719
+
720
+ expect(mockApi.get).toHaveBeenCalledWith('/users/1');
721
+ expect(user).toEqual(mockUser);
722
+ });
723
+
724
+ it('should throw NotFoundError when user not found', async () => {
725
+ mockApi.get.mockRejectedValue({ status: 404 });
726
+
727
+ await expect(userService.getUser('999'))
728
+ .rejects.toThrow('User not found');
729
+ });
730
+ });
731
+
732
+ describe('createUser', () => {
733
+ it('should create user with valid data', async () => {
734
+ const userData = { name: 'John', email: 'john@example.com' };
735
+ const createdUser = { id: '1', ...userData };
736
+ mockApi.post.mockResolvedValue(createdUser);
737
+
738
+ const user = await userService.createUser(userData);
739
+
740
+ expect(mockApi.post).toHaveBeenCalledWith('/users', userData);
741
+ expect(user).toEqual(createdUser);
742
+ });
743
+
744
+ it('should throw ValidationError for invalid email', async () => {
745
+ const userData = { name: 'John', email: 'invalid' };
746
+
747
+ await expect(userService.createUser(userData))
748
+ .rejects.toThrow('Invalid email format');
749
+ });
750
+ });
751
+ });
752
+
753
+ // Integration test example
754
+ describe('UserService Integration', () => {
755
+ it('should create and fetch user', async () => {
756
+ const userService = new UserService(new ApiService('/api'));
757
+
758
+ const created = await userService.createUser({
759
+ name: 'Test User',
760
+ email: 'test@example.com',
761
+ });
762
+
763
+ const fetched = await userService.getUser(created.id);
764
+
765
+ expect(fetched.name).toBe('Test User');
766
+ expect(fetched.email).toBe('test@example.com');
767
+ });
768
+ });
769
+
770
+ // Testing async code
771
+ describe('Async operations', () => {
772
+ it('should handle promises', async () => {
773
+ const result = await asyncOperation();
774
+ expect(result).toBe('expected');
775
+ });
776
+
777
+ it('should handle rejected promises', async () => {
778
+ await expect(failingOperation()).rejects.toThrow('error message');
779
+ });
780
+
781
+ it('should use fake timers', () => {
782
+ vi.useFakeTimers();
783
+
784
+ const callback = vi.fn();
785
+ setTimeout(callback, 1000);
786
+
787
+ vi.advanceTimersByTime(1000);
788
+
789
+ expect(callback).toHaveBeenCalled();
790
+
791
+ vi.useRealTimers();
792
+ });
793
+ });
794
+ ```
795
+
796
+ ## Use Cases
797
+
798
+ ### Event Emitter Pattern
799
+
800
+ ```javascript
801
+ class EventEmitter {
802
+ constructor() {
803
+ this.events = new Map();
804
+ }
805
+
806
+ on(event, listener) {
807
+ if (!this.events.has(event)) {
808
+ this.events.set(event, new Set());
809
+ }
810
+ this.events.get(event).add(listener);
811
+ return () => this.off(event, listener);
812
+ }
813
+
814
+ off(event, listener) {
815
+ const listeners = this.events.get(event);
816
+ if (listeners) {
817
+ listeners.delete(listener);
818
+ }
819
+ }
820
+
821
+ once(event, listener) {
822
+ const wrapper = (...args) => {
823
+ listener(...args);
824
+ this.off(event, wrapper);
825
+ };
826
+ return this.on(event, wrapper);
827
+ }
828
+
829
+ emit(event, ...args) {
830
+ const listeners = this.events.get(event);
831
+ if (listeners) {
832
+ for (const listener of listeners) {
833
+ listener(...args);
834
+ }
835
+ }
836
+ }
837
+ }
838
+
839
+ // Usage
840
+ const emitter = new EventEmitter();
841
+
842
+ const unsubscribe = emitter.on('user:created', user => {
843
+ console.log('User created:', user);
844
+ });
845
+
846
+ emitter.emit('user:created', { id: 1, name: 'John' });
847
+ unsubscribe();
848
+ ```
849
+
850
+ ### State Machine
851
+
852
+ ```javascript
853
+ function createStateMachine(config) {
854
+ let currentState = config.initial;
855
+
856
+ return {
857
+ get state() {
858
+ return currentState;
859
+ },
860
+
861
+ can(event) {
862
+ const stateConfig = config.states[currentState];
863
+ return stateConfig?.on?.[event] !== undefined;
864
+ },
865
+
866
+ transition(event, payload) {
867
+ const stateConfig = config.states[currentState];
868
+ const transition = stateConfig?.on?.[event];
869
+
870
+ if (!transition) {
871
+ throw new Error(`Invalid transition: ${event} from ${currentState}`);
872
+ }
873
+
874
+ const nextState = typeof transition === 'string'
875
+ ? transition
876
+ : transition.target;
877
+
878
+ // Execute exit action
879
+ stateConfig?.exit?.();
880
+
881
+ // Execute transition action
882
+ if (typeof transition === 'object' && transition.action) {
883
+ transition.action(payload);
884
+ }
885
+
886
+ currentState = nextState;
887
+
888
+ // Execute entry action
889
+ config.states[nextState]?.entry?.();
890
+
891
+ return currentState;
892
+ },
893
+ };
894
+ }
895
+
896
+ // Usage
897
+ const orderMachine = createStateMachine({
898
+ initial: 'pending',
899
+ states: {
900
+ pending: {
901
+ on: {
902
+ CONFIRM: 'confirmed',
903
+ CANCEL: 'cancelled',
904
+ },
905
+ },
906
+ confirmed: {
907
+ entry: () => console.log('Order confirmed!'),
908
+ on: {
909
+ SHIP: 'shipped',
910
+ CANCEL: 'cancelled',
911
+ },
912
+ },
913
+ shipped: {
914
+ on: {
915
+ DELIVER: 'delivered',
916
+ },
917
+ },
918
+ delivered: {
919
+ entry: () => console.log('Order delivered!'),
920
+ },
921
+ cancelled: {
922
+ entry: () => console.log('Order cancelled'),
923
+ },
924
+ },
925
+ });
926
+
927
+ orderMachine.transition('CONFIRM');
928
+ orderMachine.transition('SHIP');
929
+ orderMachine.transition('DELIVER');
54
930
  ```
55
931
 
56
932
  ## Best Practices
57
- - Use const/let, never var
933
+
934
+ ### Do's
935
+
936
+ - Use `const` by default, `let` when needed
58
937
  - Use arrow functions for callbacks
59
- - Use template literals
60
- - Use optional chaining
61
- - Use nullish coalescing (??)
62
- - Use modules (ESM)
938
+ - Use template literals for string interpolation
939
+ - Use destructuring for cleaner code
940
+ - Use async/await over raw promises
941
+ - Use optional chaining and nullish coalescing
942
+ - Use modules (ESM) for code organization
943
+ - Handle errors explicitly
944
+ - Write pure functions when possible
945
+ - Use meaningful variable and function names
946
+
947
+ ### Don'ts
948
+
949
+ - Don't use `var` - use `const` or `let`
950
+ - Don't use `==` - use `===` for comparisons
951
+ - Don't mutate function arguments
952
+ - Don't use `arguments` - use rest parameters
953
+ - Don't nest callbacks deeply (callback hell)
954
+ - Don't ignore promise rejections
955
+ - Don't use `eval()` or `Function()` constructor
956
+ - Don't rely on type coercion
957
+ - Don't pollute the global namespace
958
+ - Don't use synchronous operations in async code
959
+
960
+ ## References
961
+
962
+ - [MDN JavaScript Guide](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide)
963
+ - [ECMAScript Specification](https://tc39.es/ecma262/)
964
+ - [JavaScript Info](https://javascript.info/)
965
+ - [Node.js Documentation](https://nodejs.org/docs/)
966
+ - [Clean Code JavaScript](https://github.com/ryanmcdermott/clean-code-javascript)