Skip to content

Commit a783254

Browse files
committed
Create PROJECT-DRY-2.md
1 parent 1bf05d4 commit a783254

1 file changed

Lines changed: 242 additions & 0 deletions

File tree

INBOX/PROJECT-DRY-2.md

Lines changed: 242 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,242 @@
1+
# PROJECT-DRY-2 — DRY Opportunities for `check-performance.sh`
2+
**Date:** 2026-06-13
3+
**Scope:** Bash performance/security scanner (`dist/bin/check-performance.sh`)
4+
**Goal:** Highlight consolidation targets so the toolkit keeps a single source of truth for shared behaviors without touching runtime logic yet.
5+
6+
---
7+
8+
## 🎯 Summary
9+
- The performance/security scanner has grown a large collection of inline helpers and bespoke check blocks. Several of them duplicate responsibilities that already live (or could live) in `dist/bin/lib/*.sh`.
10+
- Consolidating JSON/reporting helpers, project metadata detection, and the bespoke grep/formatting loops will reduce maintenance risk and align the script with the project’s DRY/SOT expectations.
11+
12+
---
13+
14+
## 🔁 Consolidation Targets
15+
16+
### 1) JSON + Reporting Utilities
17+
**Severity:** 🟡 MEDIUM
18+
**Priority:** 🔵 HIGH
19+
**Effort:** ⚡ MEDIUM (4-6 hours)
20+
21+
**Issue:**
22+
Functions such as `json_escape()`, `add_json_finding()`, `add_json_check()`, `output_json()`, and `generate_html_report()` are defined directly in the script even though `dist/bin/lib/json-helpers.sh` already exists as a shared JSON surface. Keeping these inline makes it easy for future scripts to re-implement similar logic inconsistently.
23+
24+
**Impact:**
25+
- 🔴 **Maintenance Risk:** Any bug fix in JSON escaping must be duplicated across scripts
26+
- 🟡 **Inconsistency:** Future scripts may implement different JSON formatting
27+
- 🟢 **Testing:** Harder to unit test JSON generation in isolation
28+
29+
**Recommendation:**
30+
Move all JSON construction/escaping and HTML report generation into `dist/bin/lib/json-helpers.sh` (or a new `report-helpers.sh`) and source it from the main script. Keep only minimal wiring in `check-performance.sh`.
31+
32+
**Functions to Extract:**
33+
- `json_escape()` - 9 lines
34+
- `url_encode()` - 4 lines
35+
- `add_json_finding()` - 67 lines
36+
- `add_json_check()` - 12 lines
37+
- `output_json()` - 68 lines
38+
- `generate_html_report()` - ~100 lines
39+
40+
**Total Lines to Move:** ~260 lines → `dist/bin/lib/report-helpers.sh`
41+
42+
---
43+
44+
### 2) Project Metadata + Version SOT
45+
**Severity:** 🔴 HIGH
46+
**Priority:** 🔴 CRITICAL
47+
**Effort:** ⚡ LOW (2-3 hours)
48+
49+
**Issue:**
50+
The script recomputes project info multiple times (log header, JSON output) via `detect_project_info()` plus repeated `grep` parsing. Version text is also duplicated with mismatched values (header shows 1.0.59 but could drift from JSON output).
51+
52+
**Impact:**
53+
- 🔴 **Version Drift:** Multiple version strings can get out of sync (critical for auditing)
54+
- 🔴 **Performance:** Redundant file scanning and grep operations
55+
- 🟡 **Maintenance:** Changes to metadata detection must be made in multiple places
56+
57+
**Recommendation:**
58+
Extract project metadata helpers (`detect_project_info()`, `count_analyzed_files()`, `count_lines_of_code()`, `get_local_timestamp()`) into a dedicated helper file and return structured data once per run. Define a single `SCRIPT_VERSION` variable and reuse it in the banner, logs, and JSON payload to avoid drift.
59+
60+
**Functions to Extract:**
61+
- `detect_project_info()` - ~100 lines (complex WordPress header parsing)
62+
- `count_analyzed_files()` - 3 lines
63+
- `count_lines_of_code()` - 19 lines
64+
- `get_local_timestamp()` - 3 lines
65+
66+
**Version Consolidation:**
67+
- Create `SCRIPT_VERSION="1.0.59"` constant at top of script
68+
- Remove hardcoded version from line 4 header comment
69+
- Reuse `$SCRIPT_VERSION` in banner, logs, and JSON output
70+
71+
**Total Lines to Move:** ~125 lines → `dist/bin/lib/project-helpers.sh`
72+
73+
---
74+
75+
### 3) Shared Check Runner for Contextual Grep Blocks
76+
**Severity:** 🟡 MEDIUM
77+
**Priority:** 🟡 MEDIUM
78+
**Effort:** ⚡⚡ HIGH (8-12 hours)
79+
80+
**Issue:**
81+
After `run_check()` there are several bespoke blocks (admin capability checks, AJAX polling, REST pagination, etc.) that repeat the same pattern: `grep`, guard numeric line numbers, apply baseline suppression, build JSON findings, and manage per-check counters. Each block re-implements nearly identical loops and string parsing.
82+
83+
**Impact:**
84+
- 🟡 **Code Duplication:** ~200+ lines of duplicated grep/baseline/counter logic
85+
- 🟡 **Bug Risk:** Fixes to baseline suppression must be applied to 6+ locations
86+
- 🟢 **Extensibility:** Adding new contextual checks requires copying entire pattern
87+
88+
**Recommendation:**
89+
Extend `run_check()` (or add `run_context_check()`) to accept a callback/validator for contextual rules. Centralize baseline suppression, grouping, and JSON/check counter updates so individual rules only provide: patterns, optional context window, and the pass/fail message. This will collapse the duplicated state machines across those sections.
90+
91+
**Affected Check Blocks:**
92+
1. Admin capability checks (lines ~1400-1500)
93+
2. AJAX polling detection (lines ~1500-1600)
94+
3. REST API pagination (lines ~1600-1700)
95+
4. Transient expiration checks (lines ~1700-1800)
96+
5. Direct database queries (lines ~1800-1900)
97+
6. Unescaped output (lines ~1900-2000)
98+
99+
**Refactor Strategy:**
100+
- Create `run_context_check()` function that accepts:
101+
- Check name, severity, impact
102+
- Grep pattern(s)
103+
- Context validator callback (optional)
104+
- Message template
105+
- Centralize baseline suppression logic
106+
- Centralize JSON finding generation
107+
- Centralize counter management
108+
109+
**Total Lines to Consolidate:** ~600 lines → ~150 lines (75% reduction)
110+
111+
---
112+
113+
### 4) Path + Timestamp Handling
114+
**Severity:** 🟢 LOW
115+
**Priority:** 🟢 LOW
116+
**Effort:** ⚡ TRIVIAL (30 minutes)
117+
118+
**Issue:**
119+
`SCRIPT_DIR`/`PLUGIN_DIR` are computed twice, and timestamp helpers live inline despite similar helpers already existing in `dist/bin/lib/common-helpers.sh`.
120+
121+
**Impact:**
122+
- 🟢 **Minor Duplication:** Only ~10 lines duplicated
123+
- 🟢 **Low Risk:** Path computation is stable and rarely changes
124+
- 🟢 **Consistency:** Should use shared helpers for uniformity
125+
126+
**Recommendation:**
127+
Reuse the sourced helper values for directories and timestamps instead of reassigning them mid-file, ensuring a single place to update path or clock logic.
128+
129+
**Current State:**
130+
- `get_local_timestamp()` defined inline (3 lines) - duplicates functionality
131+
- `timestamp_iso8601()` already exists in `common-helpers.sh`
132+
- `timestamp_filename()` already exists in `common-helpers.sh`
133+
134+
**Action:**
135+
- Remove `get_local_timestamp()` function
136+
- Replace calls with `timestamp_iso8601()` or `timestamp_filename()` from common-helpers
137+
- Verify no duplicate `SCRIPT_DIR` assignments
138+
139+
**Total Lines to Remove:** ~10 lines
140+
141+
---
142+
143+
## 📊 Summary Matrix
144+
145+
| Target | Severity | Priority | Effort | Lines Saved | Risk |
146+
|--------|----------|----------|--------|-------------|------|
147+
| **1. JSON + Reporting** | 🟡 MEDIUM | 🔵 HIGH | ⚡ MEDIUM (4-6h) | ~260 lines | Low - Well-isolated functions |
148+
| **2. Project Metadata** | 🔴 HIGH | 🔴 CRITICAL | ⚡ LOW (2-3h) | ~125 lines | Low - Pure data extraction |
149+
| **3. Context Check Runner** | 🟡 MEDIUM | 🟡 MEDIUM | ⚡⚡ HIGH (8-12h) | ~450 lines | Medium - Complex refactor |
150+
| **4. Path/Timestamp** | 🟢 LOW | 🟢 LOW | ⚡ TRIVIAL (30m) | ~10 lines | Very Low - Simple cleanup |
151+
152+
**Total Potential Reduction:** ~845 lines (34% of 2,448-line script)
153+
154+
---
155+
156+
## 🎯 Recommended Implementation Order
157+
158+
### Phase 1: Quick Wins (3-4 hours)
159+
1.**Target #4** - Path/Timestamp cleanup (30 min)
160+
2.**Target #2** - Project Metadata + Version SOT (2-3 hours)
161+
162+
**Rationale:** Low risk, high impact on version drift bug, immediate value
163+
164+
### Phase 2: Core Infrastructure (4-6 hours)
165+
3.**Target #1** - JSON + Reporting utilities (4-6 hours)
166+
167+
**Rationale:** Enables future scripts to reuse JSON generation, prevents inconsistency
168+
169+
### Phase 3: Advanced Refactor (8-12 hours)
170+
4.**Target #3** - Context Check Runner (8-12 hours)
171+
172+
**Rationale:** Highest complexity, but biggest code reduction. Do last when other helpers are stable.
173+
174+
---
175+
176+
## ✅ Next Steps (Implementation Checklist)
177+
178+
### Pre-Implementation
179+
- [ ] Create feature branch: `feature/dry-phase2-check-performance`
180+
- [ ] Backup current test baseline: `cp dist/tests/fixtures/.hcc-baseline .hcc-baseline.backup`
181+
- [ ] Run full test suite to establish baseline: `dist/tests/run-fixture-tests.sh`
182+
183+
### Phase 1: Quick Wins
184+
- [ ] **Target #4:** Remove `get_local_timestamp()`, use `common-helpers.sh` functions
185+
- [ ] **Target #2:** Create `dist/bin/lib/project-helpers.sh`
186+
- [ ] Move `detect_project_info()`, `count_analyzed_files()`, `count_lines_of_code()`
187+
- [ ] Define `SCRIPT_VERSION` constant
188+
- [ ] Update all version references to use `$SCRIPT_VERSION`
189+
- [ ] Run tests: `dist/tests/run-fixture-tests.sh` (verify no regressions)
190+
191+
### Phase 2: Core Infrastructure
192+
- [ ] **Target #1:** Create `dist/bin/lib/report-helpers.sh`
193+
- [ ] Move `json_escape()`, `url_encode()`
194+
- [ ] Move `add_json_finding()`, `add_json_check()`
195+
- [ ] Move `output_json()`, `generate_html_report()`
196+
- [ ] Source in `check-performance.sh`
197+
- [ ] Run tests: `dist/tests/run-fixture-tests.sh` (verify JSON output parity)
198+
- [ ] Test JSON output: `./dist/bin/check-performance.sh --paths dist/tests/fixtures/antipatterns.php --format json`
199+
200+
### Phase 3: Advanced Refactor
201+
- [ ] **Target #3:** Create `run_context_check()` function
202+
- [ ] Design callback interface for context validators
203+
- [ ] Centralize baseline suppression logic
204+
- [ ] Centralize JSON finding generation
205+
- [ ] Refactor admin capability checks to use new runner
206+
- [ ] Refactor AJAX polling checks to use new runner
207+
- [ ] Refactor REST pagination checks to use new runner
208+
- [ ] Refactor remaining contextual checks
209+
- [ ] Run tests: `dist/tests/run-fixture-tests.sh` (verify all checks still work)
210+
- [ ] Compare output: `diff <(old_output) <(new_output)` (should be identical)
211+
212+
### Post-Implementation
213+
- [ ] Update `CHANGELOG.md` with DRY Phase 2 completion
214+
- [ ] Update version to 1.0.60
215+
- [ ] Run full test suite against real projects (Save Cart Later, etc.)
216+
- [ ] Document new helper functions with PHPDoc-style comments
217+
- [ ] Update `PROJECT-DRY-2.md` status to COMPLETE
218+
- [ ] Create `PROJECT-DRY-3.md` for next iteration (if needed)
219+
220+
---
221+
222+
## 🚨 Risk Mitigation
223+
224+
**Testing Strategy:**
225+
1. **Baseline Comparison:** Generate JSON output before/after each phase, compare with `diff`
226+
2. **Fixture Tests:** Run `dist/tests/run-fixture-tests.sh` after each change
227+
3. **Real-World Testing:** Test against known projects (Save Cart Later) before merging
228+
4. **Rollback Plan:** Keep feature branch until all tests pass
229+
230+
**Known Risks:**
231+
- 🟡 **JSON Output Changes:** Any whitespace/formatting changes will break downstream tools
232+
- **Mitigation:** Use `jq` to normalize JSON before comparison
233+
- 🟡 **Baseline Suppression Logic:** Complex state machine, easy to break
234+
- **Mitigation:** Add unit tests for baseline matching before refactoring
235+
- 🟢 **Version Drift:** Low risk, easy to verify with grep
236+
237+
---
238+
239+
**Status:** 📋 READY FOR IMPLEMENTATION
240+
**Estimated Total Effort:** 15-21 hours
241+
**Expected Code Reduction:** 34% (845 lines)
242+
**Next Action:** Create feature branch and start Phase 1

0 commit comments

Comments
 (0)