slop-police 0.1.0 → 0.2.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.
Files changed (2) hide show
  1. package/README.md +76 -24
  2. package/package.json +5 -5
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # slop-police
2
2
 
3
- A fast, type-aware linter for TypeScript that catches the dead code and needless indirection AI coding agents tend to leave behind: methods nobody calls, object keys nobody reads, getters and aliases that only rename something.
3
+ A fast, type-aware linter for TypeScript that catches the dead code and needless indirection AI coding agents tend to leave behind: methods nobody calls, object keys nobody reads, getters, aliases and wrappers that only rename or forward something, helpers copied instead of reused, comments that only promise future work, and errors swallowed or flattened into strings.
4
4
 
5
5
  It runs the TypeScript 7 compiler in-process, so rules resolve symbols the same way `tsc` does, across all of your tsconfig projects at once.
6
6
 
@@ -31,7 +31,12 @@ slop-police reads `slop-police.json` from the current directory:
31
31
  "no-identity-type-alias": "warn",
32
32
  "no-pass-through-getter": "error",
33
33
  "no-redundant-value-alias": "error",
34
- "no-single-string-cn": "off"
34
+ "no-single-string-cn": "off",
35
+ "no-pass-through-wrapper": "error",
36
+ "no-duplicate-function": "warn",
37
+ "no-placeholder-comment": "error",
38
+ "no-promise-default-fallback": "error",
39
+ "no-stringified-unknown-error": "warn"
35
40
  }
36
41
  }
37
42
  ```
@@ -91,6 +96,24 @@ class Store {
91
96
  }
92
97
  ```
93
98
 
99
+ ### no-pass-through-wrapper
100
+
101
+ A function or method whose body only returns a call (awaited or not) to a named function, passing its own parameters on as they are.
102
+
103
+ ```ts
104
+ function loadUser(id: string) { // Function loadUser only forwards to api.loadUser
105
+ return api.loadUser(id);
106
+ }
107
+ ```
108
+
109
+ It uses types to skip wrappers that do something:
110
+
111
+ - the shape is required: a method of a typed object literal (a `Proxy` handler, a Worker's `fetch`), a method that implements or overrides an inherited member, or a function assigned to a variable with a declared type. An override that only calls `super`'s method of the same name is still reported.
112
+ - the wrapper adds types: type parameters, overloads, or parameter and return types declared differently from the callee's, like `t(key: TranslationKey)` around `translate(key: string)`.
113
+ - it delegates to a private or protected member, like `get(key) { return this.items.get(key); }`.
114
+
115
+ Calls on computed values (`getDay(date).getTime()`, `/^\s*$/.test(text)`) aren't forwarding, so they don't count.
116
+
94
117
  ### no-redundant-value-alias
95
118
 
96
119
  A local `const` that only renames another `const`, when using the original directly means the same thing.
@@ -111,47 +134,76 @@ function render() {
111
134
  <div className={cn("flex gap-2")} /> // Use the class string directly instead of wrapping it in cn()
112
135
  ```
113
136
 
114
- ## Ignoring findings
137
+ ### no-placeholder-comment
115
138
 
116
- A `// slop-police-ignore` comment directly above a statement, class member or object property silences findings in it, including everything nested inside. List rule names to silence only those, and add a reason after `--`:
139
+ A comment that only promises future work instead of describing the code: "add more validation", "handle more cases", "can be extended in the future", "extend this logic", "customize this behavior", "future enhancement", "implement … here". Ordinary TODOs don't match.
117
140
 
118
141
  ```ts
119
- class Store {
120
- // slop-police-ignore unused-methods -- called from the devtools console
121
- debug() {}
142
+ function parse(input: string) {
143
+ // Add more validation here
144
+ return JSON.parse(input);
122
145
  }
146
+ ```
123
147
 
124
- // slop-police-ignore
125
- export const legacyLinks = { a: "/a", b: "/b" };
148
+ ### no-duplicate-function
149
+
150
+ A function whose body has the same shape as functions in at least two other files: a helper that was rewritten instead of reused. Shapes ignore the names of parameters and locals and the values of literals, but not the names of what the body calls or reads. Bodies with fewer than 2 statements or 16 syntax nodes, and functions in test files, don't count. Option: `minFiles` (default `3`, at least `2`), the number of files a shape has to appear in.
151
+
152
+ ```ts
153
+ // users.ts, posts.ts and teams.ts each have:
154
+ export async function loadUsers(id: string) {
155
+ const response = await fetchJson("/users/" + id);
156
+ if (!response.ok) throw new Error("failed to load users");
157
+ return response.data;
158
+ }
159
+ // Function loadUsers has the same body shape as loadPosts (posts.ts:1), loadTeams (teams.ts:1)
126
160
  ```
127
161
 
128
- ## Platforms
162
+ ### no-promise-default-fallback
129
163
 
130
- Prebuilt binaries cover macOS and Linux on arm64 and x64. On Windows, use WSL.
164
+ A promise `.catch()` handler that hides the rejection: an empty handler, or one that only returns `null`, `undefined`, `false`, `0`, `""`, `[]` or `{}`, optionally after `console.*` or `logger.*` calls. Only `.catch` on promises and other thenables counts.
131
165
 
132
- ## TypeScript version
166
+ ```ts
167
+ const config = await fetchConfig().catch(() => null); // Promise rejection is replaced with null
168
+ navigator.clipboard.writeText(text).catch(() => {}); // Promise rejection is swallowed by an empty catch handler
169
+ const enabled = await fetchFlag().catch((error) => { // Promise rejection is logged and replaced with false
170
+ console.error("flag load failed", error);
171
+ return false;
172
+ });
173
+ ```
133
174
 
134
- The binary embeds the TypeScript 7.0.2 compiler (typescript-go), so it doesn't use the `typescript` package from your project. Your tsconfigs need to work with TypeScript 7.
175
+ ### no-stringified-unknown-error
135
176
 
136
- ## Development
177
+ `error instanceof Error ? error.message : String(error)` (in either order), which flattens a caught value into a string and drops its type, stack and cause. A plain `instanceof Error` check counts when the variable is named `error`, `err`, `e` or `cause`; an `||` of `instanceof` checks counts for any name.
137
178
 
138
- ```sh
139
- go test ./...
140
- go build ./cmd/slop-police
179
+ ```ts
180
+ try {
181
+ await sendMessage(chatId, text);
182
+ } catch (error) {
183
+ return { ok: false, error: error instanceof Error ? error.message : String(error) }; // Caught value error is flattened into a string
184
+ }
141
185
  ```
142
186
 
143
- The Go module path is `github.com/microsoft/typescript-go/x/slop-police`. That's on purpose: it lets the linter import typescript-go's internal packages (checker, find-all-references, project loading), which Go only allows from paths under the same prefix. `go.mod` pins typescript-go to the exact commit a TypeScript release was built from; to upgrade, bump that pin and fix what breaks.
187
+ ## Ignoring findings
144
188
 
145
- ### Releasing
189
+ A `// slop-police-ignore` comment directly above a statement, class member or object property silences findings in it, including everything nested inside. List rule names to silence only those, and add a reason after `--`:
146
190
 
147
- Bump `version` in `npm/slop-police/package.json`, commit, then push a matching tag:
191
+ ```ts
192
+ class Store {
193
+ // slop-police-ignore unused-methods -- called from the devtools console
194
+ debug() {}
195
+ }
148
196
 
149
- ```sh
150
- git tag v0.1.0 && git push origin v0.1.0
197
+ // slop-police-ignore
198
+ export const legacyLinks = { a: "/a", b: "/b" };
151
199
  ```
152
200
 
153
- CI builds the binaries for macOS and Linux (arm64 and x64) and publishes `slop-police` plus one `slop-police-<os>-<cpu>` package per platform, which npm installs as an optional dependency. Publishing needs an `NPM_TOKEN` repository secret.
201
+ For `no-placeholder-comment`, put the ignore comment on the line directly above the reported comment.
202
+
203
+ ## Requirements
204
+
205
+ macOS or Linux on arm64 or x64 (on Windows, use WSL). The linter bundles its own TypeScript 7 compiler, so your tsconfigs need to work with TypeScript 7.
154
206
 
155
207
  ## License
156
208
 
157
- MIT. The published binaries include the TypeScript compiler and other dependencies; their licenses ship in `THIRD_PARTY_NOTICES.txt`.
209
+ MIT
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "slop-police",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "description": "Type-aware TypeScript linter for the dead code and needless indirection AI agents leave behind",
5
5
  "keywords": [
6
6
  "typescript",
@@ -28,9 +28,9 @@
28
28
  "node": ">=18"
29
29
  },
30
30
  "optionalDependencies": {
31
- "slop-police-darwin-arm64": "0.1.0",
32
- "slop-police-darwin-x64": "0.1.0",
33
- "slop-police-linux-arm64": "0.1.0",
34
- "slop-police-linux-x64": "0.1.0"
31
+ "slop-police-darwin-arm64": "0.2.0",
32
+ "slop-police-darwin-x64": "0.2.0",
33
+ "slop-police-linux-arm64": "0.2.0",
34
+ "slop-police-linux-x64": "0.2.0"
35
35
  }
36
36
  }