slop-police 0.3.0 → 0.3.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.
package/README.md CHANGED
@@ -6,17 +6,19 @@
6
6
  A type-aware TypeScript linter for the dead code and needless indirection AI agents leave behind.
7
7
  </p>
8
8
 
9
- | | pnpm | npm |
10
- | --- | --- | --- |
11
- | Add to the project | `pnpm add -D slop-police` | `npm i -D slop-police` |
12
- | Run | `pnpm exec slop-police` | `npx slop-police` |
13
- | Run once, no install | `pnpm dlx slop-police` | `npx slop-police` |
9
+ ```sh
10
+ pnpm add slop-police
11
+ # or
12
+ npm i slop-police
13
+ ```
14
+
15
+ Run it with `pnpm exec slop-police` or `npx slop-police`.
14
16
 
15
17
  Example output:
16
18
 
17
19
  ```
18
- packages/frontend/src/store/deck-store.ts:42:3 error unused-methods Method DeckStore.reset is never used
19
- packages/api/src/shared/links/links.ts:30:3 error unused-object-keys links.privacyPolicy is never read
20
+ deck-store.ts:42:3 error unused-methods Method DeckStore.reset is never used
21
+ links.ts:30:3 error unused-object-keys links.privacyPolicy is never read
20
22
 
21
23
  2 errors, 0 warnings
22
24
  ```
@@ -270,7 +272,7 @@ export const noRepeatedUrl = defineRule({
270
272
  });
271
273
  ```
272
274
 
273
- Test rules with `lint` from `slop-police/testing`, which runs a rule alone on a source string (or on files, given an object of paths to contents) in a strict TypeScript project:
275
+ Test rules with `lint` from `slop-police/testing`, which runs a rule alone on a source string (as `index.ts`) or on files (an object of paths to contents) in a strict TypeScript project:
274
276
 
275
277
  ```ts
276
278
  import { lint } from "slop-police/testing";
@@ -278,12 +280,12 @@ import { noDirectFetch } from "./slop-rules.ts";
278
280
 
279
281
  test("no-direct-fetch", () => {
280
282
  expect(lint(noDirectFetch, `fetch("/users");`)).toEqual([
281
- { line: 1, column: 1, message: "Use the API client instead of fetch()" },
283
+ { file: "index.ts", line: 1, column: 1, message: "Use the API client instead of fetch()" },
282
284
  ]);
283
285
  });
284
286
  ```
285
287
 
286
- Plugins need the npm launcher (`npx slop-police` or `pnpm exec slop-police`), which runs them in Node while the linter serves ASTs and types. TypeScript plugins need Node.js 22.18 or later, and published plugin packages must ship JavaScript.
288
+ Plugins need the npm launcher (`npx slop-police` or `pnpm exec slop-police`), which runs them in Node while the linter serves ASTs and types. Published plugin packages must ship JavaScript, since Node doesn't run TypeScript from `node_modules`.
287
289
 
288
290
  ## Ignoring findings
289
291
 
@@ -303,7 +305,7 @@ For `no-placeholder-comment`, put the ignore comment on the line directly above
303
305
 
304
306
  ## Requirements
305
307
 
306
- 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.
308
+ macOS or Linux on arm64 or x64 (on Windows, use WSL), and Node.js 22.18 or later. The linter bundles its own TypeScript 7 compiler, so your tsconfigs need to work with TypeScript 7.
307
309
 
308
310
  ## License
309
311
 
package/lib/runner.js CHANGED
@@ -38,7 +38,7 @@ async function loadPlugins(root, plugins) {
38
38
  try {
39
39
  exports = await import(resolvePlugin(root, plugin));
40
40
  } catch (error) {
41
- throw new LintError(`Unable to load plugin ${plugin}: ${error.message}${loadHint(error, plugin)}`, 2);
41
+ throw new LintError(`Unable to load plugin ${plugin}: ${error.message}`, 2);
42
42
  }
43
43
  const found = Object.values(exports).flat().filter(isRule);
44
44
  if (found.length === 0) {
@@ -62,13 +62,6 @@ function resolvePlugin(root, plugin) {
62
62
  return pathToFileURL(createRequire(path.join(root, "package.json")).resolve(plugin)).href;
63
63
  }
64
64
 
65
- function loadHint(error, plugin) {
66
- if (error.code === "ERR_UNKNOWN_FILE_EXTENSION" && /\.[cm]?tsx?$/.test(plugin)) {
67
- return " (TypeScript plugins need Node.js 22.18 or later)";
68
- }
69
- return "";
70
- }
71
-
72
65
  // lint runs the built-in rules enabled in root's config in the binary and the
73
66
  // enabled ones among rules here, and returns the binary's report: {results,
74
67
  // output, exitCode}. It throws a LintError when the run fails.
package/lib/testing.d.ts CHANGED
@@ -1,6 +1,8 @@
1
1
  import type { Rule, RuleOptions } from "./index.js";
2
2
 
3
3
  export interface Finding {
4
+ /** The path relative to the project: index.ts for a source string. */
5
+ file: string;
4
6
  /** 1-based. */
5
7
  line: number;
6
8
  /** 1-based, in UTF-16 code units. */
@@ -8,14 +10,8 @@ export interface Finding {
8
10
  message: string;
9
11
  }
10
12
 
11
- /** Runs rule alone on source, as index.ts in a strict TypeScript project. */
12
- export declare function lint(rule: Rule<any>, source: string, options?: RuleOptions): Finding[];
13
13
  /**
14
- * Runs rule alone on files (paths to contents), in a strict TypeScript project
15
- * unless files has a tsconfig.json.
14
+ * Runs rule alone on source (as index.ts) or on files (paths to contents), in
15
+ * a strict TypeScript project unless files has a tsconfig.json.
16
16
  */
17
- export declare function lint(
18
- rule: Rule<any>,
19
- files: Record<string, string>,
20
- options?: RuleOptions,
21
- ): (Finding & { file: string })[];
17
+ export declare function lint(rule: Rule<any>, source: string | Record<string, string>, options?: RuleOptions): Finding[];
package/lib/testing.js CHANGED
@@ -17,9 +17,9 @@ const tsconfig = {
17
17
  include: ["**/*.ts", "**/*.tsx"],
18
18
  };
19
19
 
20
- // lint runs rule alone on source (index.ts) or on files (paths to contents,
21
- // with a default strict tsconfig.json unless one is given) and returns the
22
- // findings, with the file of each when given files.
20
+ // lint runs rule alone on source (as index.ts) or on files (paths to
21
+ // contents, with a default strict tsconfig.json unless one is given) and
22
+ // returns its findings.
23
23
  export function lint(rule, source, options) {
24
24
  const files = typeof source === "string" ? { "index.ts": source } : source;
25
25
  const root = fs.mkdtempSync(path.join(os.tmpdir(), "slop-police-test-"));
@@ -31,9 +31,7 @@ export function lint(rule, source, options) {
31
31
  fs.mkdirSync(path.dirname(file), { recursive: true });
32
32
  fs.writeFileSync(file, content);
33
33
  }
34
- return lintWithRules(findBinary(), root, [rule]).results.map(({ file, line, column, message }) =>
35
- typeof source === "string" ? { line, column, message } : { file, line, column, message },
36
- );
34
+ return lintWithRules(findBinary(), root, [rule]).results.map(({ file, line, column, message }) => ({ file, line, column, message }));
37
35
  } finally {
38
36
  fs.rmSync(root, { recursive: true, force: true });
39
37
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "slop-police",
3
- "version": "0.3.0",
3
+ "version": "0.3.1",
4
4
  "description": "Type-aware TypeScript linter for the dead code and needless indirection AI agents leave behind",
5
5
  "keywords": [
6
6
  "typescript",
@@ -38,12 +38,12 @@
38
38
  "LICENSE"
39
39
  ],
40
40
  "engines": {
41
- "node": ">=18"
41
+ "node": ">=22.18"
42
42
  },
43
43
  "optionalDependencies": {
44
- "slop-police-darwin-arm64": "0.3.0",
45
- "slop-police-darwin-x64": "0.3.0",
46
- "slop-police-linux-arm64": "0.3.0",
47
- "slop-police-linux-x64": "0.3.0"
44
+ "slop-police-darwin-arm64": "0.3.1",
45
+ "slop-police-darwin-x64": "0.3.1",
46
+ "slop-police-linux-arm64": "0.3.1",
47
+ "slop-police-linux-x64": "0.3.1"
48
48
  }
49
49
  }