omgkit 2.2.0 → 2.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/plugin/skills/databases/mongodb/SKILL.md +60 -776
- package/plugin/skills/databases/prisma/SKILL.md +53 -744
- package/plugin/skills/databases/redis/SKILL.md +53 -860
- package/plugin/skills/devops/aws/SKILL.md +68 -672
- package/plugin/skills/devops/github-actions/SKILL.md +54 -657
- package/plugin/skills/devops/kubernetes/SKILL.md +67 -602
- package/plugin/skills/devops/performance-profiling/SKILL.md +59 -863
- package/plugin/skills/frameworks/django/SKILL.md +87 -853
- package/plugin/skills/frameworks/express/SKILL.md +95 -1301
- package/plugin/skills/frameworks/fastapi/SKILL.md +90 -1198
- package/plugin/skills/frameworks/laravel/SKILL.md +87 -1187
- package/plugin/skills/frameworks/nestjs/SKILL.md +106 -973
- package/plugin/skills/frameworks/react/SKILL.md +94 -962
- package/plugin/skills/frameworks/vue/SKILL.md +95 -1242
- package/plugin/skills/frontend/accessibility/SKILL.md +91 -1056
- package/plugin/skills/frontend/frontend-design/SKILL.md +69 -1262
- package/plugin/skills/frontend/responsive/SKILL.md +76 -799
- package/plugin/skills/frontend/shadcn-ui/SKILL.md +73 -921
- package/plugin/skills/frontend/tailwindcss/SKILL.md +60 -788
- package/plugin/skills/frontend/threejs/SKILL.md +72 -1266
- package/plugin/skills/languages/javascript/SKILL.md +106 -849
- package/plugin/skills/methodology/brainstorming/SKILL.md +70 -576
- package/plugin/skills/methodology/defense-in-depth/SKILL.md +79 -831
- package/plugin/skills/methodology/dispatching-parallel-agents/SKILL.md +81 -654
- package/plugin/skills/methodology/executing-plans/SKILL.md +86 -529
- package/plugin/skills/methodology/finishing-development-branch/SKILL.md +95 -586
- package/plugin/skills/methodology/problem-solving/SKILL.md +67 -681
- package/plugin/skills/methodology/receiving-code-review/SKILL.md +70 -533
- package/plugin/skills/methodology/requesting-code-review/SKILL.md +70 -610
- package/plugin/skills/methodology/root-cause-tracing/SKILL.md +70 -646
- package/plugin/skills/methodology/sequential-thinking/SKILL.md +70 -478
- package/plugin/skills/methodology/systematic-debugging/SKILL.md +66 -559
- package/plugin/skills/methodology/test-driven-development/SKILL.md +91 -752
- package/plugin/skills/methodology/testing-anti-patterns/SKILL.md +78 -687
- package/plugin/skills/methodology/token-optimization/SKILL.md +72 -602
- package/plugin/skills/methodology/verification-before-completion/SKILL.md +108 -529
- package/plugin/skills/methodology/writing-plans/SKILL.md +79 -566
- package/plugin/skills/omega/omega-architecture/SKILL.md +91 -752
- package/plugin/skills/omega/omega-coding/SKILL.md +161 -552
- package/plugin/skills/omega/omega-sprint/SKILL.md +132 -777
- package/plugin/skills/omega/omega-testing/SKILL.md +157 -845
- package/plugin/skills/omega/omega-thinking/SKILL.md +165 -606
- package/plugin/skills/security/better-auth/SKILL.md +46 -1034
- package/plugin/skills/security/oauth/SKILL.md +80 -934
- package/plugin/skills/security/owasp/SKILL.md +78 -862
- package/plugin/skills/testing/playwright/SKILL.md +77 -700
- package/plugin/skills/testing/pytest/SKILL.md +73 -811
- package/plugin/skills/testing/vitest/SKILL.md +60 -920
- package/plugin/skills/tools/document-processing/SKILL.md +111 -838
- package/plugin/skills/tools/image-processing/SKILL.md +126 -659
- package/plugin/skills/tools/mcp-development/SKILL.md +85 -758
- package/plugin/skills/tools/media-processing/SKILL.md +118 -735
- package/plugin/stdrules/SKILL_STANDARDS.md +490 -0
- package/plugin/skills/SKILL_STANDARDS.md +0 -743
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
|
-
name:
|
|
3
|
-
description:
|
|
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
|
-
|
|
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
|
-
//
|
|
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
|
|
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
|
-
|
|
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
|
|
37
|
+
console.error('Failed to fetch:', error);
|
|
126
38
|
throw error;
|
|
127
39
|
}
|
|
128
40
|
}
|
|
129
41
|
|
|
130
|
-
//
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
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
|
-
|
|
170
|
-
}
|
|
47
|
+
## Features
|
|
171
48
|
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
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
|
-
|
|
178
|
-
const response = await fetch(`${baseUrl}?page=${page}`);
|
|
179
|
-
const data = await response.json();
|
|
62
|
+
## Common Patterns
|
|
180
63
|
|
|
181
|
-
|
|
64
|
+
### Async Patterns with Concurrency Control
|
|
182
65
|
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
}
|
|
66
|
+
```javascript
|
|
67
|
+
// Parallel execution
|
|
68
|
+
const [user, posts] = await Promise.all([fetchUser(id), fetchPosts(id)]);
|
|
187
69
|
|
|
188
|
-
//
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
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
|
|
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
|
-
|
|
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
|
|
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(
|
|
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
|
-
###
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
331
|
-
|
|
332
|
-
|
|
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
|
-
###
|
|
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
|
-
|
|
413
|
-
|
|
414
|
-
}
|
|
415
|
-
|
|
416
|
-
|
|
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
|
|
470
|
-
if (!
|
|
471
|
-
|
|
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
|
-
//
|
|
658
|
-
const
|
|
659
|
-
const
|
|
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
|
-
|
|
816
|
-
|
|
817
|
-
|
|
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
|
-
###
|
|
175
|
+
### Modern Collection Usage
|
|
851
176
|
|
|
852
177
|
```javascript
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
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
|
-
|
|
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
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
-
|
|
950
|
-
-
|
|
951
|
-
-
|
|
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)
|