@booklib/skills 1.6.0 → 1.7.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.
@@ -1,158 +0,0 @@
1
- // order processing thing
2
- // ORIGINAL — intentionally bad code. Do not use in production.
3
-
4
- var db = require('./db')
5
- var mailer = require('./mailer')
6
-
7
- var discount = 0.1
8
- var TAX = 0.23
9
- var items = []
10
- var total = 0
11
- var usr = null
12
-
13
- function process(o, u, pay, s) {
14
- usr = u
15
- if (u != null) {
16
- if (u.active == true) {
17
- if (o != null) {
18
- if (o.items != null && o.items.length > 0) {
19
- var t = 0
20
- for (var i = 0; i < o.items.length; i++) {
21
- var item = o.items[i]
22
- if (item.qty > 0) {
23
- if (item.price > 0) {
24
- t = t + (item.qty * item.price)
25
- items.push(item)
26
- }
27
- }
28
- }
29
- if (u.type == "premium") {
30
- t = t - (t * 0.1)
31
- }
32
- if (u.type == "vip") {
33
- t = t - (t * 0.2)
34
- }
35
- if (u.type == "staff") {
36
- t = t - (t * 0.5)
37
- }
38
- total = t + (t * TAX)
39
- if (pay == "card") {
40
- var res = chargeCard(u.card, total)
41
- if (res == true) {
42
- var q = "INSERT INTO orders VALUES ('" + o.id + "', '" + u.id + "', " + total + ", 'paid')"
43
- db.query(q)
44
- mailer.send(u.email, "Order confirmed", "ur order is confirmed lol total: " + total)
45
- s.orders++
46
- s.revenue = s.revenue + total
47
- return true
48
- } else {
49
- return false
50
- }
51
- }
52
- if (pay == "paypal") {
53
- var res2 = chargePaypal(u.paypal, total)
54
- if (res2 == true) {
55
- var q2 = "INSERT INTO orders VALUES ('" + o.id + "', '" + u.id + "', " + total + ", 'paid')"
56
- db.query(q2)
57
- mailer.send(u.email, "Order confirmed", "ur order is confirmed lol total: " + total)
58
- s.orders++
59
- s.revenue = s.revenue + total
60
- return true
61
- } else {
62
- return false
63
- }
64
- }
65
- if (pay == "crypto") {
66
- // TODO: implement this someday
67
- return false
68
- }
69
- } else {
70
- return false
71
- }
72
- } else {
73
- return false
74
- }
75
- } else {
76
- return false
77
- }
78
- } else {
79
- return false
80
- }
81
- }
82
-
83
- function chargeCard(card, amt) {
84
- // just assume it works
85
- console.log("charging card " + card + " for " + amt)
86
- return true
87
- }
88
-
89
- function chargePaypal(pp, amt) {
90
- console.log("paypal " + pp + " " + amt)
91
- return true
92
- }
93
-
94
- // get user orders
95
- function getOrds(uid) {
96
- var q = "SELECT * FROM orders WHERE user_id = '" + uid + "'"
97
- return db.query(q)
98
- }
99
-
100
- // cancel
101
- function cancel(oid, uid, rsn) {
102
- var q = "SELECT * FROM orders WHERE id = '" + oid + "'"
103
- var ord = db.query(q)
104
- if (ord != null) {
105
- if (ord.user_id == uid) {
106
- if (ord.status != "cancelled") {
107
- if (ord.status != "shipped") {
108
- if (ord.status != "delivered") {
109
- var q2 = "UPDATE orders SET status = 'cancelled', reason = '" + rsn + "' WHERE id = '" + oid + "'"
110
- db.query(q2)
111
- mailer.send(usr.email, "Cancelled", "ok cancelled")
112
- return true
113
- } else {
114
- return false
115
- }
116
- } else {
117
- return false
118
- }
119
- } else {
120
- return false
121
- }
122
- }
123
- }
124
- return false
125
- }
126
-
127
- // stats thing used everywhere
128
- var stats = {
129
- orders: 0,
130
- revenue: 0,
131
- cancelled: 0
132
- }
133
-
134
- function getStats() {
135
- return eval("stats")
136
- }
137
-
138
- // some random util shoved in here
139
- function formatMoney(n) {
140
- return "$" + Math.round(n * 100) / 100
141
- }
142
-
143
- // also does refunds i guess
144
- function refund(oid) {
145
- var q = "SELECT * FROM orders WHERE id = '" + oid + "'"
146
- var ord = db.query(q)
147
- if (ord.status == "paid") {
148
- // refund the money somehow
149
- console.log("refunding " + ord.total)
150
- var q2 = "UPDATE orders SET status = 'refunded' WHERE id = '" + oid + "'"
151
- db.query(q2)
152
- stats.revenue = stats.revenue - ord.total
153
- stats.cancelled++
154
- mailer.send(usr.email, "Refund", "u got ur money back: " + formatMoney(ord.total))
155
- }
156
- }
157
-
158
- module.exports = { process, getOrds, cancel, getStats, refund }
@@ -1,181 +0,0 @@
1
- // code-after-native.js
2
- // Rewritten applying all findings from: pr-review-toolkit:code-reviewer
3
- // Fixes applied (by issue #):
4
- // #1 Parameterised queries — no SQL injection
5
- // #2 eval("stats") → return stats
6
- // #3 No module-level mutable state — all state is local or injected
7
- // #4 items array removed from module scope
8
- // #5 null check before ord.status in refund()
9
- // #6 Card data not logged to console (PCI)
10
- // #7 Unknown payment method throws, not silently returns undefined
11
- // #8 Shared finalizeOrder() — no duplicated block
12
- // #9 discount variable removed; named constants used
13
- // #10 === / !== throughout, no loose equality
14
- // #11/#12 cancel/refund look up user email from order, not global usr
15
- // #13 Single stats object — no two-object inconsistency
16
- // #14 cancel() updates stats.cancelled on success
17
- // #15 try/catch around db and mailer calls
18
- // #16 const/let throughout, no var
19
- // #17 Descriptive parameter names
20
-
21
- 'use strict';
22
-
23
- const db = require('./db');
24
- const mailer = require('./mailer');
25
-
26
- const TAX_RATE = 0.23;
27
- const DISCOUNT_PREMIUM = 0.10;
28
- const DISCOUNT_VIP = 0.20;
29
- const DISCOUNT_STAFF = 0.50;
30
- const NON_CANCELLABLE = ['cancelled', 'shipped', 'delivered'];
31
-
32
- // Module-level stats — single source of truth (#13)
33
- const stats = { orders: 0, revenue: 0, cancelled: 0 };
34
-
35
- // ─── Public API ──────────────────────────────────────────────────────────────
36
-
37
- // Renamed from process() — avoids shadowing Node's global `process` (#17, #13)
38
- async function placeOrder(order, user, paymentMethod, statsRef) {
39
- // Guard clauses replace pyramid nesting (#10)
40
- if (!user || !user.active) return false;
41
- if (!order || !order.items || order.items.length === 0) return false;
42
-
43
- // Local variables — no module-level state (#3, #4)
44
- const validItems = order.items.filter(item => item.qty > 0 && item.price > 0);
45
- if (validItems.length === 0) return false;
46
-
47
- let subtotal = validItems.reduce((sum, item) => sum + item.qty * item.price, 0);
48
-
49
- // Named constants replace magic numbers (#9)
50
- if (user.type === 'premium') subtotal *= (1 - DISCOUNT_PREMIUM);
51
- else if (user.type === 'vip') subtotal *= (1 - DISCOUNT_VIP);
52
- else if (user.type === 'staff') subtotal *= (1 - DISCOUNT_STAFF);
53
-
54
- const total = subtotal * (1 + TAX_RATE);
55
-
56
- // Dispatch — unknown method throws, not silently undefined (#7)
57
- const charged = await chargePayment(paymentMethod, user, total);
58
- if (!charged) return false;
59
-
60
- // Shared confirmation — duplicated block eliminated (#8)
61
- await finalizeOrder(order, user, total, statsRef || stats);
62
- return true;
63
- }
64
-
65
- async function getOrders(userId) {
66
- // Parameterised query (#1)
67
- return db.query('SELECT * FROM orders WHERE user_id = $1', [userId]);
68
- }
69
-
70
- async function cancelOrder(orderId, userId, reason) {
71
- try {
72
- // Parameterised (#1)
73
- const order = await db.query('SELECT * FROM orders WHERE id = $1', [orderId]);
74
-
75
- // Null check (#5); strict equality (#10)
76
- if (!order) return false;
77
- if (order.user_id !== userId) return false;
78
- if (NON_CANCELLABLE.includes(order.status)) return false;
79
-
80
- await db.query(
81
- 'UPDATE orders SET status = $1, reason = $2 WHERE id = $3',
82
- ['cancelled', reason, orderId],
83
- );
84
-
85
- // Use order's own email — not global usr (#11)
86
- mailer.send(order.user_email, 'Order cancelled', 'Your order has been cancelled.');
87
-
88
- // Stats update on cancel (#14)
89
- stats.cancelled++;
90
- stats.revenue -= order.total;
91
-
92
- return true;
93
- } catch (err) {
94
- // Error handling (#15)
95
- console.error('cancelOrder failed:', err.message);
96
- return false;
97
- }
98
- }
99
-
100
- async function refundOrder(orderId) {
101
- try {
102
- const order = await db.query('SELECT * FROM orders WHERE id = $1', [orderId]);
103
-
104
- // Null check added — was missing, caused TypeError crash (#5)
105
- if (!order) return false;
106
- if (order.status !== 'paid') return false;
107
-
108
- await db.query(
109
- 'UPDATE orders SET status = $1 WHERE id = $2',
110
- ['refunded', orderId],
111
- );
112
-
113
- stats.revenue -= order.total;
114
- stats.cancelled++;
115
-
116
- // Use order's own email — not global usr (#12)
117
- mailer.send(
118
- order.user_email,
119
- 'Refund processed',
120
- `Your refund of ${formatMoney(order.total)} is on its way.`,
121
- );
122
-
123
- return true;
124
- } catch (err) {
125
- console.error('refundOrder failed:', err.message);
126
- return false;
127
- }
128
- }
129
-
130
- function getStats() {
131
- return { ...stats }; // eval("stats") → just return the object (#2); defensive copy (#13)
132
- }
133
-
134
- // ─── Private helpers ─────────────────────────────────────────────────────────
135
-
136
- async function chargePayment(method, user, total) {
137
- if (method === 'card') return chargeCard(user.card, total);
138
- if (method === 'paypal') return chargePaypal(user.paypal, total);
139
- if (method === 'crypto') throw new Error('Crypto payments are not yet supported');
140
- // Unknown method throws — no silent undefined return (#7)
141
- throw new Error(`Unknown payment method: ${method}`);
142
- }
143
-
144
- // Shared — eliminates the duplicated card/paypal block (#8)
145
- async function finalizeOrder(order, user, total, statsRef) {
146
- // Parameterised INSERT (#1)
147
- await db.query(
148
- 'INSERT INTO orders (id, user_id, total, status) VALUES ($1, $2, $3, $4)',
149
- [order.id, user.id, total, 'paid'],
150
- );
151
- mailer.send(
152
- user.email,
153
- 'Order confirmed',
154
- `Your order has been confirmed. Total: ${formatMoney(total)}`,
155
- );
156
- statsRef.orders++;
157
- statsRef.revenue += total;
158
- }
159
-
160
- function chargeCard(cardToken, amount) {
161
- // Do NOT log card details — PCI-DSS (#6)
162
- console.log(`Charging card (ending ...${String(cardToken).slice(-4)}) for ${formatMoney(amount)}`);
163
- return true; // TODO: integrate real payment gateway
164
- }
165
-
166
- function chargePaypal(account, amount) {
167
- console.log(`Charging PayPal ${account} for ${formatMoney(amount)}`);
168
- return true; // TODO: integrate PayPal SDK
169
- }
170
-
171
- function formatMoney(amount) {
172
- return `$${(Math.round(amount * 100) / 100).toFixed(2)}`;
173
- }
174
-
175
- module.exports = {
176
- placeOrder,
177
- getOrders,
178
- cancelOrder,
179
- refundOrder,
180
- getStats,
181
- };
@@ -1,271 +0,0 @@
1
- // code-after-custom.js
2
- // Rewritten applying: clean-code-reviewer + design-patterns (via skill-router)
3
- //
4
- // Patterns applied (design-patterns skill):
5
- // Strategy — payment methods (GoF: encapsulate interchangeable algorithms)
6
- // Strategy — discount tiers (GoF: data-driven, open for extension)
7
- // State — order lifecycle (GoF: each status owns its valid transitions)
8
- // Singleton — stats (GoF: deliberate, clean, no accidental shared state)
9
- // Observer — side effects (GoF: email/stats decoupled from business logic)
10
- // Facade — module API (GoF: single clean surface, internals hidden)
11
- // Template Method — validation (GoF: fixed skeleton, variable steps)
12
- //
13
- // Principles applied (clean-code-reviewer skill):
14
- // N1/N2 — intention-revealing names at the right abstraction level
15
- // F1/F2 — small functions, one responsibility each
16
- // G5 — DRY: no duplicated confirmation block
17
- // G25 — named constants, no magic numbers
18
- // G23 — data-driven lookup, not if-chain
19
- // G28 — encapsulated predicates
20
- // G30 — functions do one thing
21
- // Ch.7 — throw with context, never silent return false
22
- // G4 — parameterised queries, no eval, no safety overrides
23
-
24
- 'use strict';
25
-
26
- const db = require('./db');
27
- const mailer = require('./mailer');
28
-
29
- // ─── Constants ────────────────────────────────────────────────────────────────
30
-
31
- const TAX_RATE = 0.23;
32
-
33
- // Strategy: discount tiers — add a new tier here, nothing else changes (G23, G25)
34
- const DISCOUNT_BY_TIER = Object.freeze({
35
- standard: 0,
36
- premium: 0.10,
37
- vip: 0.20,
38
- staff: 0.50,
39
- });
40
-
41
- // Strategy: payment processors — add a new method here, nothing else changes
42
- const PAYMENT_PROCESSORS = Object.freeze({
43
- card: {
44
- charge(user, amount) {
45
- // TODO: integrate real payment gateway
46
- console.log(`Charging card (...${String(user.card).slice(-4)}) for ${formatMoney(amount)}`);
47
- return true;
48
- },
49
- },
50
- paypal: {
51
- charge(user, amount) {
52
- // TODO: integrate PayPal SDK
53
- console.log(`Charging PayPal ${user.paypal} for ${formatMoney(amount)}`);
54
- return true;
55
- },
56
- },
57
- crypto: {
58
- charge() {
59
- throw new Error('Crypto payments are not yet implemented');
60
- },
61
- },
62
- });
63
-
64
- // ─── State: order lifecycle ───────────────────────────────────────────────────
65
- // Each state owns its own transition rules.
66
- // Adding a new status = adding one object. No existing guards change.
67
-
68
- const ORDER_STATES = Object.freeze({
69
- pending: {
70
- canCancel: () => true,
71
- canRefund: () => false,
72
- },
73
- paid: {
74
- canCancel: () => true,
75
- canRefund: () => true,
76
- },
77
- shipped: {
78
- canCancel: () => false,
79
- canRefund: () => false,
80
- },
81
- delivered: {
82
- canCancel: () => false,
83
- canRefund: () => true,
84
- },
85
- cancelled: {
86
- canCancel: () => false,
87
- canRefund: () => false,
88
- },
89
- refunded: {
90
- canCancel: () => false,
91
- canRefund: () => false,
92
- },
93
- });
94
-
95
- function getOrderState(status) {
96
- const state = ORDER_STATES[status];
97
- if (!state) throw new Error(`Unknown order status: ${status}`);
98
- return state;
99
- }
100
-
101
- // ─── Singleton: stats ─────────────────────────────────────────────────────────
102
- // Deliberate, clean singleton. Not an accidental module-scope variable.
103
-
104
- const Stats = (() => {
105
- const data = { orders: 0, revenue: 0, cancelled: 0 };
106
- return {
107
- recordPlaced(total) { data.orders++; data.revenue += total; },
108
- recordCancelled(total) { data.cancelled++; data.revenue -= total; },
109
- recordRefunded(total) { data.cancelled++; data.revenue -= total; },
110
- snapshot() { return { ...data }; },
111
- };
112
- })();
113
-
114
- // ─── Observer: event bus ──────────────────────────────────────────────────────
115
- // Business logic emits events. Side effects (email, stats) register as listeners.
116
- // Adding SMS or audit log = one new listener. Core functions unchanged.
117
-
118
- const EventBus = (() => {
119
- const listeners = {};
120
- return {
121
- on(event, fn) { (listeners[event] = listeners[event] || []).push(fn); },
122
- emit(event, payload) { (listeners[event] || []).forEach(fn => fn(payload)); },
123
- };
124
- })();
125
-
126
- // Register observers at startup — not inside business functions
127
- EventBus.on('order.placed', ({ user, total }) => {
128
- mailer.send(user.email, 'Order confirmed', `Your order total is ${formatMoney(total)}.`);
129
- Stats.recordPlaced(total);
130
- });
131
-
132
- EventBus.on('order.cancelled', ({ order, total }) => {
133
- mailer.send(order.user_email, 'Order cancelled', 'Your order has been cancelled.');
134
- Stats.recordCancelled(total);
135
- });
136
-
137
- EventBus.on('order.refunded', ({ order, total }) => {
138
- mailer.send(order.user_email, 'Refund processed', `Your refund of ${formatMoney(total)} is on its way.`);
139
- Stats.recordRefunded(total);
140
- });
141
-
142
- // ─── Validation (Template Method skeleton) ────────────────────────────────────
143
- // Fixed skeleton: check preconditions, then run action. (G28, Ch.7)
144
-
145
- function assertActiveUser(user) {
146
- if (!user) throw new Error('user is required');
147
- if (!user.active) throw new Error(`User ${user.id} is not active`);
148
- }
149
-
150
- function assertValidOrder(order) {
151
- if (!order?.items?.length) throw new Error('order must contain at least one item');
152
- }
153
-
154
- function assertSupportedPayment(method) {
155
- if (!PAYMENT_PROCESSORS[method]) throw new Error(`Unsupported payment method: ${method}`);
156
- }
157
-
158
- // ─── Calculation (F1: one responsibility each) ────────────────────────────────
159
-
160
- function calculateSubtotal(items) {
161
- return items
162
- .filter(item => item.qty > 0 && item.price > 0)
163
- .reduce((sum, item) => sum + item.qty * item.price, 0);
164
- }
165
-
166
- function applyTierDiscount(amount, userTier) {
167
- const rate = DISCOUNT_BY_TIER[userTier] ?? 0; // G25: named table, not magic number
168
- return amount * (1 - rate);
169
- }
170
-
171
- function applyTax(amount) {
172
- return amount * (1 + TAX_RATE);
173
- }
174
-
175
- // ─── Persistence ──────────────────────────────────────────────────────────────
176
- // Each function does one thing. Parameterised queries throughout (G4).
177
-
178
- async function persistOrder(order, user, total) {
179
- await db.query(
180
- 'INSERT INTO orders (id, user_id, total, status) VALUES (?, ?, ?, ?)',
181
- [order.id, user.id, total, 'paid'],
182
- );
183
- }
184
-
185
- async function fetchOrder(orderId) {
186
- const order = await db.query('SELECT * FROM orders WHERE id = ?', [orderId]);
187
- if (!order) throw new Error(`Order not found: ${orderId}`);
188
- return order;
189
- }
190
-
191
- async function persistCancellation(orderId, reason) {
192
- await db.query(
193
- 'UPDATE orders SET status = ?, reason = ? WHERE id = ?',
194
- ['cancelled', reason, orderId],
195
- );
196
- }
197
-
198
- async function persistRefund(orderId) {
199
- await db.query('UPDATE orders SET status = ? WHERE id = ?', ['refunded', orderId]);
200
- }
201
-
202
- // ─── Formatting ───────────────────────────────────────────────────────────────
203
-
204
- function formatMoney(amount) {
205
- return new Intl.NumberFormat('en-US', { style: 'currency', currency: 'USD' }).format(amount);
206
- }
207
-
208
- // ─── Facade: public API ───────────────────────────────────────────────────────
209
- // Callers import one clean surface. All internals (strategies, state,
210
- // observer, singleton) are hidden and can evolve independently.
211
-
212
- async function processOrder(order, user, paymentMethod) {
213
- // Template Method: validate → calculate → charge → persist → notify (via Observer)
214
- assertActiveUser(user);
215
- assertValidOrder(order);
216
- assertSupportedPayment(paymentMethod);
217
-
218
- const subtotal = calculateSubtotal(order.items);
219
- const discounted = applyTierDiscount(subtotal, user.type);
220
- const total = applyTax(discounted);
221
-
222
- // Strategy pattern: dispatch to the right processor, one confirmation path
223
- PAYMENT_PROCESSORS[paymentMethod].charge(user, total);
224
- await persistOrder(order, user, total);
225
-
226
- // Observer: emit event — email and stats handled by listeners, not here
227
- EventBus.emit('order.placed', { user, order, total });
228
- }
229
-
230
- async function getUserOrders(userId) {
231
- return db.query('SELECT * FROM orders WHERE user_id = ?', [userId]);
232
- }
233
-
234
- async function cancelOrder(orderId, userId, reason) {
235
- const order = await fetchOrder(orderId);
236
-
237
- if (order.userId !== userId) throw new Error('Order does not belong to this user');
238
-
239
- // State pattern: the status object decides whether cancellation is legal
240
- if (!getOrderState(order.status).canCancel()) {
241
- throw new Error(`Order ${orderId} cannot be cancelled (status: ${order.status})`);
242
- }
243
-
244
- await persistCancellation(orderId, reason);
245
- EventBus.emit('order.cancelled', { order, total: order.total });
246
- }
247
-
248
- async function refundOrder(orderId) {
249
- const order = await fetchOrder(orderId);
250
-
251
- // State pattern: the status object decides whether refund is legal
252
- if (!getOrderState(order.status).canRefund()) {
253
- throw new Error(`Order ${orderId} cannot be refunded (status: ${order.status})`);
254
- }
255
-
256
- await persistRefund(orderId);
257
- EventBus.emit('order.refunded', { order, total: order.total });
258
- }
259
-
260
- function getStats() {
261
- return Stats.snapshot(); // Singleton: clean access, defensive copy
262
- }
263
-
264
- // Facade export: one coherent interface
265
- module.exports = {
266
- processOrder,
267
- getUserOrders,
268
- cancelOrder,
269
- refundOrder,
270
- getStats,
271
- };