# 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;
  };
};
```
