# DashCaddy Duplicate Code Report > **Generated:** 2026-07-13 > **Functions scanned:** 107 (≥200 chars body length) > **Exact-duplicate groups:** 10 ## Methodology 1. Extract every top-level `function X() { ... }` declaration 2. Skip functions < 200 chars (helpers, getters, trivial wrappers) 3. Normalize: strip comments, collapse whitespace, replace all identifiers with placeholder 4. SHA-1 the normalized body → identical hashes = duplicate bodies ## ⚠️ Caveats - **Anonymous functions and arrow functions are not captured** (regex matches `function name(` only) - **Class methods are not captured** (would need AST parser) - **Near-duplicates with renamed variables are flagged as the same** (that's the point — after normalization, only structure differs) - **`module.exports` factory functions are common and look similar** — many route files have a 5-line wrapper like `module.exports = function(ctx) { const router = express.Router(); ... return router; }`. These will show as duplicate groups. ## Exact Duplicate Groups Functions whose bodies are byte-identical after normalization (ignoring comments, whitespace, and identifier names). | Hash | Count | Functions | |---|---:|---| | `5a3372b656b7` | 2 | `base32Encode`, `base32Encode` | | `9550727efdf2` | 2 | `base32Decode`, `base32Decode` | | `e00959ade524` | 2 | `getSecret`, `getSecret` | | `09498fd55b60` | 2 | `initSecret`, `initSecret` | | `0f89a717e703` | 2 | `generateCode`, `generateCode` | | `d92f81854134` | 2 | `parseCode`, `parseCode` | | `8c3ecfea7f7d` | 2 | `parsePayload`, `parsePayload` | | `fc844dbaca2f` | 2 | `verifyCode`, `verifyCode` | | `221e46c497d9` | 2 | `main`, `main` | | `9573dd3cd485` | 2 | `formatBytes`, `formatBytes` | ### Top Groups (Detail) #### Hash `5a3372b656b7` (2 copies) - `src/managers/license-keygen.js:33` — `base32Encode()` (374 chars) - `license-keygen.js:33` — `base32Encode()` (374 chars) #### Hash `9550727efdf2` (2 copies) - `src/managers/license-keygen.js:48` — `base32Decode()` (415 chars) - `license-keygen.js:48` — `base32Decode()` (415 chars) #### Hash `e00959ade524` (2 copies) - `src/managers/license-keygen.js:62` — `getSecret()` (216 chars) - `license-keygen.js:62` — `getSecret()` (216 chars) #### Hash `09498fd55b60` (2 copies) - `src/managers/license-keygen.js:70` — `initSecret()` (597 chars) - `license-keygen.js:70` — `initSecret()` (597 chars) #### Hash `0f89a717e703` (2 copies) - `src/managers/license-keygen.js:83` — `generateCode()` (1331 chars) - `license-keygen.js:83` — `generateCode()` (1331 chars) #### Hash `d92f81854134` (2 copies) - `src/managers/license-keygen.js:118` — `parseCode()` (523 chars) - `license-keygen.js:118` — `parseCode()` (523 chars) #### Hash `8c3ecfea7f7d` (2 copies) - `src/managers/license-keygen.js:135` — `parsePayload()` (443 chars) - `license-keygen.js:135` — `parsePayload()` (443 chars) #### Hash `fc844dbaca2f` (2 copies) - `src/managers/license-keygen.js:148` — `verifyCode()` (1367 chars) - `license-keygen.js:148` — `verifyCode()` (1367 chars) #### Hash `221e46c497d9` (2 copies) - `src/managers/license-keygen.js:188` — `main()` (4428 chars) - `license-keygen.js:188` — `main()` (4428 chars) #### Hash `9573dd3cd485` (2 copies) - `routes/backups.js:693` — `formatBytes()` (259 chars) - `routes/apps/restore.js:488` — `formatBytes()` (259 chars) ## Common Factory Pattern `module.exports = function(ctx) { const router = express.Router(); ... }` **49 files** use this factory wrapper pattern: - `routes/errorlogs.js` - `routes/docker-resources.js` - `routes/ca.js` - `routes/config-drift.js` - `routes/containers.js` - `routes/context.js` - `routes/monitoring.js` - `routes/workflows.js` - `routes/services.js` - `routes/sites.js` - `routes/logs.js` - `routes/credentials.js` - `routes/themes.js` - `routes/updates.js` - `routes/dns.js` - ... and 34 more Could be extracted to a helper: ```javascript // src/utilities/route-factory.js module.exports = function routeFactory(handlerFn) { return function(deps) { const router = require('express').Router(); handlerFn(router, deps); return router; }; }; ```