omgkit 2.2.0 → 2.3.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.
Files changed (60) hide show
  1. package/README.md +3 -3
  2. package/package.json +1 -1
  3. package/plugin/skills/databases/database-management/SKILL.md +288 -0
  4. package/plugin/skills/databases/database-migration/SKILL.md +285 -0
  5. package/plugin/skills/databases/database-schema-design/SKILL.md +195 -0
  6. package/plugin/skills/databases/mongodb/SKILL.md +60 -776
  7. package/plugin/skills/databases/prisma/SKILL.md +53 -744
  8. package/plugin/skills/databases/redis/SKILL.md +53 -860
  9. package/plugin/skills/databases/supabase/SKILL.md +283 -0
  10. package/plugin/skills/devops/aws/SKILL.md +68 -672
  11. package/plugin/skills/devops/github-actions/SKILL.md +54 -657
  12. package/plugin/skills/devops/kubernetes/SKILL.md +67 -602
  13. package/plugin/skills/devops/performance-profiling/SKILL.md +59 -863
  14. package/plugin/skills/frameworks/django/SKILL.md +87 -853
  15. package/plugin/skills/frameworks/express/SKILL.md +95 -1301
  16. package/plugin/skills/frameworks/fastapi/SKILL.md +90 -1198
  17. package/plugin/skills/frameworks/laravel/SKILL.md +87 -1187
  18. package/plugin/skills/frameworks/nestjs/SKILL.md +106 -973
  19. package/plugin/skills/frameworks/react/SKILL.md +94 -962
  20. package/plugin/skills/frameworks/vue/SKILL.md +95 -1242
  21. package/plugin/skills/frontend/accessibility/SKILL.md +91 -1056
  22. package/plugin/skills/frontend/frontend-design/SKILL.md +69 -1262
  23. package/plugin/skills/frontend/responsive/SKILL.md +76 -799
  24. package/plugin/skills/frontend/shadcn-ui/SKILL.md +73 -921
  25. package/plugin/skills/frontend/tailwindcss/SKILL.md +60 -788
  26. package/plugin/skills/frontend/threejs/SKILL.md +72 -1266
  27. package/plugin/skills/languages/javascript/SKILL.md +106 -849
  28. package/plugin/skills/methodology/brainstorming/SKILL.md +70 -576
  29. package/plugin/skills/methodology/defense-in-depth/SKILL.md +79 -831
  30. package/plugin/skills/methodology/dispatching-parallel-agents/SKILL.md +81 -654
  31. package/plugin/skills/methodology/executing-plans/SKILL.md +86 -529
  32. package/plugin/skills/methodology/finishing-development-branch/SKILL.md +95 -586
  33. package/plugin/skills/methodology/problem-solving/SKILL.md +67 -681
  34. package/plugin/skills/methodology/receiving-code-review/SKILL.md +70 -533
  35. package/plugin/skills/methodology/requesting-code-review/SKILL.md +70 -610
  36. package/plugin/skills/methodology/root-cause-tracing/SKILL.md +70 -646
  37. package/plugin/skills/methodology/sequential-thinking/SKILL.md +70 -478
  38. package/plugin/skills/methodology/systematic-debugging/SKILL.md +66 -559
  39. package/plugin/skills/methodology/test-driven-development/SKILL.md +91 -752
  40. package/plugin/skills/methodology/testing-anti-patterns/SKILL.md +78 -687
  41. package/plugin/skills/methodology/token-optimization/SKILL.md +72 -602
  42. package/plugin/skills/methodology/verification-before-completion/SKILL.md +108 -529
  43. package/plugin/skills/methodology/writing-plans/SKILL.md +79 -566
  44. package/plugin/skills/omega/omega-architecture/SKILL.md +91 -752
  45. package/plugin/skills/omega/omega-coding/SKILL.md +161 -552
  46. package/plugin/skills/omega/omega-sprint/SKILL.md +132 -777
  47. package/plugin/skills/omega/omega-testing/SKILL.md +157 -845
  48. package/plugin/skills/omega/omega-thinking/SKILL.md +165 -606
  49. package/plugin/skills/security/better-auth/SKILL.md +46 -1034
  50. package/plugin/skills/security/oauth/SKILL.md +80 -934
  51. package/plugin/skills/security/owasp/SKILL.md +78 -862
  52. package/plugin/skills/testing/playwright/SKILL.md +77 -700
  53. package/plugin/skills/testing/pytest/SKILL.md +73 -811
  54. package/plugin/skills/testing/vitest/SKILL.md +60 -920
  55. package/plugin/skills/tools/document-processing/SKILL.md +111 -838
  56. package/plugin/skills/tools/image-processing/SKILL.md +126 -659
  57. package/plugin/skills/tools/mcp-development/SKILL.md +85 -758
  58. package/plugin/skills/tools/media-processing/SKILL.md +118 -735
  59. package/plugin/stdrules/SKILL_STANDARDS.md +490 -0
  60. package/plugin/skills/SKILL_STANDARDS.md +0 -743
@@ -1,6 +1,6 @@
1
1
  ---
2
- name: javascript
3
- description: Modern JavaScript development with ES2024+, async patterns, functional programming, and Node.js
2
+ name: Writing JavaScript
3
+ description: Writes modern JavaScript with ES2024+ features, async patterns, and functional programming. Use when building Node.js applications, implementing async workflows, or writing clean maintainable code.
4
4
  category: languages
5
5
  triggers:
6
6
  - javascript
@@ -13,949 +13,207 @@ triggers:
13
13
  - npm
14
14
  ---
15
15
 
16
- # JavaScript
16
+ # Writing JavaScript
17
17
 
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+)
18
+ ## Quick Start
35
19
 
36
20
  ```javascript
37
- // Destructuring - Objects and Arrays
38
- const user = { name: 'John', email: 'john@example.com', role: 'admin' };
21
+ // Modern destructuring and spread
39
22
  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
- }
23
+ const settings = { ...defaults, theme: 'dark' };
24
+ const [first, ...rest] = items;
62
25
 
63
26
  // Optional chaining and nullish coalescing
64
27
  const street = user?.address?.street ?? 'Unknown';
65
- const callback = options?.onComplete;
66
- callback?.();
67
-
68
- // Logical assignment operators
69
- let config = {};
70
28
  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
29
 
107
- get value() {
108
- return this.#count;
109
- }
110
- }
111
- ```
112
-
113
- ### 2. Async Patterns
114
-
115
- ```javascript
116
- // Basic async/await
30
+ // Async/await with error handling
117
31
  async function fetchUser(id) {
118
32
  try {
119
33
  const response = await fetch(`/api/users/${id}`);
120
- if (!response.ok) {
121
- throw new Error(`HTTP error! status: ${response.status}`);
122
- }
34
+ if (!response.ok) throw new Error(`HTTP ${response.status}`);
123
35
  return await response.json();
124
36
  } catch (error) {
125
- console.error('Failed to fetch user:', error);
37
+ console.error('Failed to fetch:', error);
126
38
  throw error;
127
39
  }
128
40
  }
129
41
 
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 });
42
+ // Functional composition
43
+ const pipe = (...fns) => x => fns.reduce((acc, fn) => fn(acc), x);
44
+ const processData = pipe(filter(isValid), map(transform), reduce(aggregate, []));
45
+ ```
168
46
 
169
- return Promise.race([fetchPromise, timeoutPromise]);
170
- }
47
+ ## Features
171
48
 
172
- // Async iteration
173
- async function* fetchPages(baseUrl) {
174
- let page = 1;
175
- let hasMore = true;
49
+ | Feature | Description | Guide |
50
+ |---------|-------------|-------|
51
+ | Destructuring | Extract values from objects and arrays | Use `const { a, b } = obj` or `const [x, y] = arr` |
52
+ | Spread Operator | Expand iterables and merge objects | Use `...` for shallow copies and merging |
53
+ | Optional Chaining | Safe property access on nullable values | Use `?.` to avoid "cannot read property" errors |
54
+ | Nullish Coalescing | Default values for null/undefined only | Use `??` instead of `\|\|` for falsy values |
55
+ | Async/Await | Clean asynchronous code flow | Use try/catch for error handling |
56
+ | Promise Methods | Parallel and conditional execution | Use all, allSettled, race, any for concurrency |
57
+ | Array Methods | Functional array transformations | Use map, filter, reduce, find, at, toSorted |
58
+ | Classes | Object-oriented patterns with private fields | Use # prefix for truly private members |
59
+ | Modules | ESM import/export for code organization | Use named exports and barrel files |
60
+ | Iterators | Custom iteration with generators | Use function* and for...of loops |
176
61
 
177
- while (hasMore) {
178
- const response = await fetch(`${baseUrl}?page=${page}`);
179
- const data = await response.json();
62
+ ## Common Patterns
180
63
 
181
- yield data.items;
64
+ ### Async Patterns with Concurrency Control
182
65
 
183
- hasMore = data.hasMore;
184
- page++;
185
- }
186
- }
66
+ ```javascript
67
+ // Parallel execution
68
+ const [user, posts] = await Promise.all([fetchUser(id), fetchPosts(id)]);
187
69
 
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
- }
70
+ // Handle mixed success/failure
71
+ const results = await Promise.allSettled(ids.map(fetchUser));
72
+ const successful = results.filter(r => r.status === 'fulfilled').map(r => r.value);
73
+ const failed = results.filter(r => r.status === 'rejected').map(r => r.reason);
196
74
 
197
- // Retry pattern with exponential backoff
75
+ // Retry with exponential backoff
198
76
  async function withRetry(fn, maxRetries = 3, baseDelay = 1000) {
199
- let lastError;
200
-
201
77
  for (let attempt = 0; attempt < maxRetries; attempt++) {
202
78
  try {
203
79
  return await fn();
204
80
  } 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
- }
81
+ if (attempt === maxRetries - 1) throw error;
82
+ await new Promise(r => setTimeout(r, baseDelay * Math.pow(2, attempt)));
211
83
  }
212
84
  }
213
-
214
- throw lastError;
215
85
  }
216
86
 
217
87
  // Concurrent execution with limit
218
- async function mapWithConcurrency(items, fn, limit = 5) {
88
+ async function mapConcurrent(items, fn, limit = 5) {
219
89
  const results = [];
220
90
  const executing = new Set();
221
-
222
91
  for (const item of items) {
223
- const promise = fn(item).then(result => {
224
- executing.delete(promise);
225
- return result;
226
- });
227
-
92
+ const promise = fn(item).then(r => { executing.delete(promise); return r; });
228
93
  executing.add(promise);
229
94
  results.push(promise);
230
-
231
- if (executing.size >= limit) {
232
- await Promise.race(executing);
233
- }
95
+ if (executing.size >= limit) await Promise.race(executing);
234
96
  }
235
-
236
97
  return Promise.all(results);
237
98
  }
238
99
  ```
239
100
 
240
- ### 3. Functional Programming
101
+ ### Functional Programming Utilities
241
102
 
242
103
  ```javascript
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
104
  // 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
- };
105
+ const curry = fn => function curried(...args) {
106
+ return args.length >= fn.length ? fn(...args) : (...next) => curried(...args, ...next);
262
107
  };
263
108
 
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
109
  // Memoization
314
110
  const memoize = fn => {
315
111
  const cache = new Map();
316
-
317
112
  return (...args) => {
318
113
  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;
114
+ if (!cache.has(key)) cache.set(key, fn(...args));
115
+ return cache.get(key);
327
116
  };
328
117
  };
329
118
 
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');
119
+ // Immutable updates
120
+ const updateUser = (user, updates) => ({ ...user, ...updates, updatedAt: new Date() });
121
+ const addItem = (arr, item) => [...arr, item];
122
+ const removeAt = (arr, i) => [...arr.slice(0, i), ...arr.slice(i + 1)];
363
123
  ```
364
124
 
365
- ### 4. Error Handling
125
+ ### Error Handling with Result Type
366
126
 
367
127
  ```javascript
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
128
  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
- }
129
+ constructor(value, error) { this.value = value; this.error = error; }
130
+ static ok(value) { return new Result(value, null); }
131
+ static err(error) { return new Result(null, error); }
132
+ isOk() { return this.error === null; }
133
+ map(fn) { return this.isOk() ? Result.ok(fn(this.value)) : this; }
134
+ unwrapOr(defaultValue) { return this.isOk() ? this.value : defaultValue; }
465
135
  }
466
136
 
467
137
  async function safeFetch(url) {
468
138
  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
- });
504
- ```
505
-
506
- ### 5. Modules and Project Structure
507
-
508
- ```javascript
509
- // Named exports
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
- }
562
-
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
- }
570
-
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
- */
598
- ```
599
-
600
- ### 6. Data Structures and Collections
601
-
602
- ```javascript
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
139
+ const res = await fetch(url);
140
+ if (!res.ok) return Result.err(new Error(`HTTP ${res.status}`));
141
+ return Result.ok(await res.json());
142
+ } catch (e) { return Result.err(e); }
655
143
  }
656
144
 
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
- });
145
+ // Usage
146
+ const result = await safeFetch('/api/data');
147
+ const data = result.map(d => d.items).unwrapOr([]);
794
148
  ```
795
149
 
796
- ## Use Cases
797
-
798
150
  ### Event Emitter Pattern
799
151
 
800
152
  ```javascript
801
153
  class EventEmitter {
802
- constructor() {
803
- this.events = new Map();
804
- }
154
+ constructor() { this.events = new Map(); }
805
155
 
806
156
  on(event, listener) {
807
- if (!this.events.has(event)) {
808
- this.events.set(event, new Set());
809
- }
157
+ if (!this.events.has(event)) this.events.set(event, new Set());
810
158
  this.events.get(event).add(listener);
811
159
  return () => this.off(event, listener);
812
160
  }
813
161
 
814
- off(event, listener) {
815
- const listeners = this.events.get(event);
816
- if (listeners) {
817
- listeners.delete(listener);
818
- }
162
+ off(event, listener) { this.events.get(event)?.delete(listener); }
163
+
164
+ emit(event, ...args) {
165
+ this.events.get(event)?.forEach(listener => listener(...args));
819
166
  }
820
167
 
821
168
  once(event, listener) {
822
- const wrapper = (...args) => {
823
- listener(...args);
824
- this.off(event, wrapper);
825
- };
169
+ const wrapper = (...args) => { listener(...args); this.off(event, wrapper); };
826
170
  return this.on(event, wrapper);
827
171
  }
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
172
  }
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
173
  ```
849
174
 
850
- ### State Machine
175
+ ### Modern Collection Usage
851
176
 
852
177
  ```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?.();
178
+ // Map for key-value with any type keys
179
+ const cache = new Map();
180
+ cache.set(userObj, 'data'); // Object as key
181
+ for (const [key, value] of cache) { /* iterate */ }
182
+
183
+ // Set for unique values and operations
184
+ const setA = new Set([1, 2, 3]);
185
+ const setB = new Set([2, 3, 4]);
186
+ const union = new Set([...setA, ...setB]);
187
+ const intersection = new Set([...setA].filter(x => setB.has(x)));
890
188
 
891
- return currentState;
892
- },
893
- };
189
+ // WeakMap for private data without memory leaks
190
+ const privateData = new WeakMap();
191
+ class Secret {
192
+ constructor(value) { privateData.set(this, { value }); }
193
+ getValue() { return privateData.get(this).value; }
894
194
  }
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');
930
195
  ```
931
196
 
932
197
  ## Best Practices
933
198
 
934
- ### Do's
935
-
936
- - Use `const` by default, `let` when needed
937
- - Use arrow functions for callbacks
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
199
+ | Do | Avoid |
200
+ |----|-------|
201
+ | Use `const` by default, `let` only when needed | Using `var` for variable declarations |
202
+ | Use `===` for strict equality comparisons | Using `==` which allows type coercion |
203
+ | Use async/await over raw promise chains | Deep nesting with .then() callbacks |
204
+ | Use optional chaining for safe property access | Manual null checks at every level |
205
+ | Use destructuring for cleaner parameter extraction | Accessing object properties repeatedly |
206
+ | Use template literals for string interpolation | String concatenation with + |
207
+ | Use arrow functions for callbacks | Using function expressions for simple callbacks |
208
+ | Handle promise rejections explicitly | Ignoring unhandled rejection warnings |
209
+ | Use modules (ESM) for code organization | Polluting the global namespace |
210
+ | Write pure functions when possible | Functions with hidden side effects |
211
+
212
+ ## Related Skills
213
+
214
+ - **typescript** - Type-safe JavaScript development
215
+ - **nodejs** - Server-side JavaScript runtime
216
+ - **react** - JavaScript UI framework
959
217
 
960
218
  ## References
961
219
 
@@ -963,4 +221,3 @@ orderMachine.transition('DELIVER');
963
221
  - [ECMAScript Specification](https://tc39.es/ecma262/)
964
222
  - [JavaScript Info](https://javascript.info/)
965
223
  - [Node.js Documentation](https://nodejs.org/docs/)
966
- - [Clean Code JavaScript](https://github.com/ryanmcdermott/clean-code-javascript)