dslop 1.6.1 → 1.7.1

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.
Files changed (4) hide show
  1. package/CHANGELOG.md +24 -0
  2. package/README.md +132 -32
  3. package/dist/index.cjs +774 -1736
  4. package/package.json +1 -1
package/CHANGELOG.md CHANGED
@@ -1,5 +1,29 @@
1
1
  # Changelog
2
2
 
3
+ ## v1.7.1
4
+
5
+ [compare changes](https://github.com/turf-sports/dslop/compare/v1.7.0...v1.7.1)
6
+
7
+ ### 🔥 Performance
8
+
9
+ - 28x faster with caching, remove text-based detection ([b93742c](https://github.com/turf-sports/dslop/commit/b93742c))
10
+
11
+ ### ❤️ Contributors
12
+
13
+ - Siddharth Sharma <sharmasiddharthcs@gmail.com>
14
+
15
+ ## v1.7.0
16
+
17
+ [compare changes](https://github.com/turf-sports/dslop/compare/v1.6.1...v1.7.0)
18
+
19
+ ### 🚀 Enhancements
20
+
21
+ - AST-only output, filter same-file dupes, sort by occurrences ([53acc46](https://github.com/turf-sports/dslop/commit/53acc46))
22
+
23
+ ### ❤️ Contributors
24
+
25
+ - Siddharth Sharma <sharmasiddharthcs@gmail.com>
26
+
3
27
  ## v1.6.1
4
28
 
5
29
  [compare changes](https://github.com/turf-sports/dslop/compare/v1.6.0...v1.6.1)
package/README.md CHANGED
@@ -1,12 +1,92 @@
1
1
  # dslop
2
2
 
3
- Find duplicate code in your codebase.
3
+ Find duplicate functions, types, and code in your codebase using AST analysis.
4
4
 
5
5
  ```bash
6
6
  npx dslop
7
7
  ```
8
8
 
9
- By default, checks your branch changes against the codebase. If no changes found, automatically does a full scan.
9
+ ## What it finds
10
+
11
+ **Real duplicates, not noise.** dslop uses AST parsing to find semantically identical code - functions with the same logic but different variable names, types defined in multiple places, copy-pasted utilities.
12
+
13
+ ```bash
14
+ $ dslop --all --json
15
+
16
+ {
17
+ "summary": { "duplicateGroups": 101 },
18
+ "duplicates": [
19
+ {
20
+ "type": "function",
21
+ "name": "loadEnv",
22
+ "occurrences": 6,
23
+ "locations": [
24
+ { "name": "loadEnv", "file": "scripts/migrate.ts", "line": 8 },
25
+ { "name": "loadEnv", "file": "scripts/seed.ts", "line": 12 },
26
+ { "name": "loadEnv", "file": "lib/db/migrate.ts", "line": 7 },
27
+ { "name": "loadEnv", "file": "lib/db/check-state.ts", "line": 9 }
28
+ ]
29
+ },
30
+ {
31
+ "type": "interface",
32
+ "name": "Params",
33
+ "occurrences": 6,
34
+ "locations": [
35
+ { "name": "Params", "file": "app/api/games/[id]/route.ts", "line": 5 },
36
+ { "name": "Params", "file": "app/api/games/[id]/state/route.ts", "line": 8 },
37
+ { "name": "Params", "file": "app/api/games/[id]/details/route.ts", "line": 12 }
38
+ ]
39
+ },
40
+ {
41
+ "type": "type",
42
+ "name": "LeaderboardPlayer",
43
+ "occurrences": 3,
44
+ "locations": [
45
+ { "name": "LeaderboardPlayer", "file": "packages/types/leaderboard.ts", "line": 45, "exported": true },
46
+ { "name": "LeaderboardPlayer", "file": "apps/mobile/types.ts", "line": 52, "exported": false },
47
+ { "name": "LeaderboardPlayer", "file": "apps/web/lib/types.ts", "line": 30, "exported": false }
48
+ ]
49
+ }
50
+ ]
51
+ }
52
+ ```
53
+
54
+ ### Monorepo cross-package duplicates
55
+
56
+ Find types and functions duplicated across packages:
57
+
58
+ ```bash
59
+ $ dslop --all --cross-package
60
+
61
+ Found 48 duplicate functions/types
62
+
63
+ # Types duplicated between packages/types and apps/
64
+ PrizeDistribution packages/types/game.ts ↔ packages/db/schema/game.ts
65
+ DevicePlatform apps/web/lib/notifications.ts ↔ apps/listener/lib/notifications.ts
66
+ TeamColors apps/mobile/store/types.ts ↔ apps/web/lib/types/colors.ts
67
+
68
+ # Functions copy-pasted between apps/
69
+ subscribeToChannel apps/web/lib/subscriptions.ts ↔ apps/listener/lib/subscriptions.ts
70
+ getTeamLogoUrl packages/shared/logos.ts → also in apps/web (3 copies)
71
+ normalizeError apps/web/sentry.config.ts ↔ apps/listener/lib/sentry.ts
72
+ ```
73
+
74
+ ### PR review mode
75
+
76
+ By default, dslop checks your branch changes against the existing codebase:
77
+
78
+ ```bash
79
+ $ dslop
80
+
81
+ Scanning...
82
+ Mode: checking changed lines in 3 files
83
+
84
+ Found 2 duplicate functions/types
85
+
86
+ # You're adding code that already exists elsewhere:
87
+ getUserDisplayName your change: app/profile/page.tsx:19
88
+ exists in: components/sidebar.tsx:50
89
+ ```
10
90
 
11
91
  ## Install
12
92
 
@@ -18,9 +98,10 @@ npm i -g dslop
18
98
 
19
99
  ```bash
20
100
  dslop # check PR changes (or full scan if none)
21
- dslop ./apps/web # scan apps/web (full if no changes there)
22
- dslop -c # changes only, exit if none found
23
- dslop --cross-package # cross-package dupes (monorepos)
101
+ dslop --all # full codebase scan
102
+ dslop --all --json # JSON output for tooling
103
+ dslop --cross-package # only cross-package dupes (monorepos)
104
+ dslop ./apps/web # scan specific directory
24
105
  ```
25
106
 
26
107
  ## Options
@@ -32,47 +113,66 @@ dslop --cross-package # cross-package dupes (monorepos)
32
113
  | `-m, --min-lines` | min lines per block (default: 4) |
33
114
  | `-s, --similarity` | similarity threshold 0-100 (default: 70) |
34
115
  | `-e, --extensions` | file extensions (default: ts,tsx,js,jsx) |
35
- | `--cross-package` | only show dupes across packages |
36
- | `--json` | json output |
116
+ | `--cross-package` | only show dupes across packages/apps |
117
+ | `--json` | JSON output |
37
118
 
38
119
  ## How it works
39
120
 
40
- dslop uses two detection methods in parallel:
121
+ dslop parses TypeScript/JavaScript with Babel and extracts functions, classes, types, and interfaces. It normalizes the AST by replacing all identifiers with generic placeholders (`$0`, `$1`, etc.), preserving only the code structure.
41
122
 
42
- ### 1. AST-based detection (functions/classes)
43
-
44
- Parses TypeScript/JavaScript with Babel to extract functions and classes. Normalizes the AST by replacing all identifiers with generic placeholders (`$0`, `$1`, etc.), preserving only the code structure.
45
-
46
- **This catches:**
123
+ This catches:
47
124
  - Functions with identical logic but different variable names
48
- - Renamed copies of existing functions
49
- - Structurally identical classes
125
+ - Types/interfaces defined in multiple places
126
+ - Copy-pasted utilities across packages
127
+
128
+ Example: these two functions are detected as duplicates:
129
+
130
+ ```ts
131
+ // apps/web/utils.ts
132
+ function getUserInitials(user: User): string {
133
+ const first = user.firstName?.[0] ?? '';
134
+ const last = user.lastName?.[0] ?? '';
135
+ return (first + last).toUpperCase();
136
+ }
137
+
138
+ // apps/admin/helpers.ts
139
+ function getInitials(person: Person): string {
140
+ const f = person.firstName?.[0] ?? '';
141
+ const l = person.lastName?.[0] ?? '';
142
+ return (f + l).toUpperCase();
143
+ }
144
+ ```
50
145
 
51
- Example: `calculateSum(numbers)` and `computeTotal(items)` with the same loop structure will match.
146
+ ### What it ignores
52
147
 
53
- ### 2. Text-based detection (code blocks)
148
+ - Same-file duplicates (patterns within a single file)
149
+ - Tiny functions (configurable via `--min-lines`)
150
+ - Common patterns from UI libraries (shadcn components, etc.)
54
151
 
55
- Sliding window over source files extracts overlapping blocks at sizes 4, 6, 9, 13... lines. Before hashing, code is normalized:
56
- - String literals → `"<STRING>"`
57
- - Numbers → `<NUMBER>`
58
- - Whitespace collapsed
59
- - Comments preserved (intentional - comments often indicate copy-paste)
152
+ ## Performance
60
153
 
61
- Exact hash matches = exact duplicates. For similar (non-exact) matches, uses character-level similarity.
154
+ dslop uses aggressive caching to make subsequent runs fast:
155
+
156
+ ```bash
157
+ # First run (builds cache)
158
+ $ dslop --all
159
+ Scanned 1410 files in 2862ms
160
+ Cache: 0 hits, 1410 misses (0% hit rate)
161
+
162
+ # Second run (uses cache)
163
+ $ dslop --all
164
+ Scanned 1410 files in 305ms
165
+ Cache: 1410 hits, 0 misses (100% hit rate)
166
+ ```
62
167
 
63
- ### Smart defaults
168
+ Cache is stored in `.dslop-cache` in your project root. Add it to `.gitignore`.
64
169
 
65
- 1. If you have branch changes → checks those against the codebase
66
- 2. If no changes found → automatically scans the entire target path
67
- 3. Use `-c` to force changes-only mode (useful in CI)
170
+ Use `--no-cache` to bypass the cache.
68
171
 
69
172
  ## Limitations
70
173
 
71
- - **TypeScript/JavaScript only for AST:** AST parsing uses Babel with TS/JSX plugins. Other languages fall back to text-based only.
72
- - **No cross-language:** Won't detect a Python function duplicated in TypeScript.
73
- - **Comments affect text matching:** Intentional tradeoff. Copy-pasted code often includes comments.
74
- - **Minimum 4 lines:** Shorter duplicates ignored to reduce noise. Use `-m 2` for stricter.
75
- - **Memory:** Loads all blocks in memory. Very large codebases (>1M lines) may be slow.
174
+ - **TypeScript/JavaScript only:** AST parsing uses Babel with TS/JSX plugins
175
+ - **No cross-language:** Won't detect duplication across languages
76
176
 
77
177
  ## License
78
178