@aarock1234/slopscan 0.1.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 (195) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +143 -0
  3. package/SKILL.md +149 -0
  4. package/dist/analyzer.d.ts +5 -0
  5. package/dist/analyzer.js +13 -0
  6. package/dist/analyzer.js.map +1 -0
  7. package/dist/analyzers/ast.d.ts +12 -0
  8. package/dist/analyzers/ast.js +73 -0
  9. package/dist/analyzers/ast.js.map +1 -0
  10. package/dist/analyzers/judge-chunks.d.ts +13 -0
  11. package/dist/analyzers/judge-chunks.js +87 -0
  12. package/dist/analyzers/judge-chunks.js.map +1 -0
  13. package/dist/analyzers/judge-validate.d.ts +19 -0
  14. package/dist/analyzers/judge-validate.js +81 -0
  15. package/dist/analyzers/judge-validate.js.map +1 -0
  16. package/dist/analyzers/judge.d.ts +44 -0
  17. package/dist/analyzers/judge.js +177 -0
  18. package/dist/analyzers/judge.js.map +1 -0
  19. package/dist/change.d.ts +19 -0
  20. package/dist/change.js +87 -0
  21. package/dist/change.js.map +1 -0
  22. package/dist/cli.d.ts +2 -0
  23. package/dist/cli.js +125 -0
  24. package/dist/cli.js.map +1 -0
  25. package/dist/config.d.ts +91 -0
  26. package/dist/config.js +61 -0
  27. package/dist/config.js.map +1 -0
  28. package/dist/confirm.d.ts +11 -0
  29. package/dist/confirm.js +100 -0
  30. package/dist/confirm.js.map +1 -0
  31. package/dist/finding.d.ts +13 -0
  32. package/dist/finding.js +18 -0
  33. package/dist/finding.js.map +1 -0
  34. package/dist/lang.d.ts +16 -0
  35. package/dist/lang.js +37 -0
  36. package/dist/lang.js.map +1 -0
  37. package/dist/model.d.ts +2 -0
  38. package/dist/model.js +34 -0
  39. package/dist/model.js.map +1 -0
  40. package/dist/report.d.ts +124 -0
  41. package/dist/report.js +112 -0
  42. package/dist/report.js.map +1 -0
  43. package/dist/rule.d.ts +66 -0
  44. package/dist/rule.js +259 -0
  45. package/dist/rule.js.map +1 -0
  46. package/dist/scan.d.ts +14 -0
  47. package/dist/scan.js +33 -0
  48. package/dist/scan.js.map +1 -0
  49. package/dist/score.d.ts +147 -0
  50. package/dist/score.js +142 -0
  51. package/dist/score.js.map +1 -0
  52. package/dist/shared/concurrency.d.ts +5 -0
  53. package/dist/shared/concurrency.js +17 -0
  54. package/dist/shared/concurrency.js.map +1 -0
  55. package/dist/shared/env.d.ts +27 -0
  56. package/dist/shared/env.js +29 -0
  57. package/dist/shared/env.js.map +1 -0
  58. package/dist/shared/errors.d.ts +18 -0
  59. package/dist/shared/errors.js +26 -0
  60. package/dist/shared/errors.js.map +1 -0
  61. package/dist/shared/log.d.ts +2 -0
  62. package/dist/shared/log.js +18 -0
  63. package/dist/shared/log.js.map +1 -0
  64. package/dist/shared/paths.d.ts +3 -0
  65. package/dist/shared/paths.js +6 -0
  66. package/dist/shared/paths.js.map +1 -0
  67. package/dist/shared/prompts.d.ts +3 -0
  68. package/dist/shared/prompts.js +34 -0
  69. package/dist/shared/prompts.js.map +1 -0
  70. package/package.json +79 -0
  71. package/prompts/judge.md +37 -0
  72. package/rules/any/futureproof/abstraction/pass-through-wrapper.md +70 -0
  73. package/rules/any/futureproof/abstraction/single-caller-helper.md +38 -0
  74. package/rules/any/futureproof/abstraction/single-impl-interface.md +83 -0
  75. package/rules/any/futureproof/exports/dead-export.md +62 -0
  76. package/rules/any/futureproof/layering/framework-type-in-domain.md +83 -0
  77. package/rules/any/futureproof/layering/logic-in-handler.md +94 -0
  78. package/rules/any/futureproof/params/boolean-positional-param.md +128 -0
  79. package/rules/any/futureproof/params/positional-config-args.md +135 -0
  80. package/rules/any/futureproof/structure/wide-function.md +138 -0
  81. package/rules/any/futureproof/testing/test-asserts-implementation.md +70 -0
  82. package/rules/any/hacky/comments/comment-restates-code.md +50 -0
  83. package/rules/any/hacky/comments/shipped-todo-comment.md +55 -0
  84. package/rules/any/hacky/concurrency/sleep-based-sync.md +95 -0
  85. package/rules/any/hacky/config/hardcoded-url.md +88 -0
  86. package/rules/any/hacky/constants/magic-number.md +94 -0
  87. package/rules/any/hacky/debugging/debug-print.md +73 -0
  88. package/rules/any/hacky/duplication/copy-paste-block.md +117 -0
  89. package/rules/any/hacky/types/stringly-typed-enum.md +86 -0
  90. package/rules/any/idiom/comments/no-section-banners.md +47 -0
  91. package/rules/go/futureproof/constants/string-enums-when-serialized.md +47 -0
  92. package/rules/go/futureproof/constants/typed-constants-for-enums.md +45 -0
  93. package/rules/go/futureproof/interfaces/compile-time-impl-assertion.md +43 -0
  94. package/rules/go/futureproof/interfaces/define-interfaces-at-consumer.md +47 -0
  95. package/rules/go/futureproof/interfaces/keep-interfaces-small.md +53 -0
  96. package/rules/go/futureproof/naming/no-utils-helpers-common-package.md +34 -0
  97. package/rules/go/futureproof/structs/zero-value-usable.md +50 -0
  98. package/rules/go/futureproof/types/generics-over-any.md +55 -0
  99. package/rules/go/hacky/concurrency/no-goroutine-without-wait.md +44 -0
  100. package/rules/go/hacky/context/never-pass-nil-context.md +64 -0
  101. package/rules/go/hacky/context/no-context-in-struct.md +44 -0
  102. package/rules/go/hacky/errors/check-close-error-on-writable.md +53 -0
  103. package/rules/go/hacky/errors/custom-error-type-errors-as.md +54 -0
  104. package/rules/go/hacky/errors/ignored-error-blank.md +84 -0
  105. package/rules/go/hacky/errors/panic-only-unrecoverable.md +77 -0
  106. package/rules/go/hacky/errors/sentinel-errors-with-errors-is.md +63 -0
  107. package/rules/go/hacky/errors/wrap-errors-with-w.md +71 -0
  108. package/rules/go/hacky/state/package-level-mutable-var.md +95 -0
  109. package/rules/go/hacky/structure/os-exit-only-in-main.md +61 -0
  110. package/rules/go/hacky/type-safety/no-map-string-any.md +49 -0
  111. package/rules/go/hacky/types/json-into-struct-not-map.md +48 -0
  112. package/rules/go/hacky/types/no-any.md +71 -0
  113. package/rules/go/hacky/types/no-map-any-any.md +35 -0
  114. package/rules/go/idiom/comments/doc-comment-on-exported.md +81 -0
  115. package/rules/go/idiom/comments/doc-comment-starts-with-name.md +36 -0
  116. package/rules/go/idiom/concurrency/mutex-over-channels-for-state.md +47 -0
  117. package/rules/go/idiom/constructors/constructor-named-new.md +37 -0
  118. package/rules/go/idiom/context/context-is-first-param.md +47 -0
  119. package/rules/go/idiom/context/io-takes-context.md +50 -0
  120. package/rules/go/idiom/errors/capitalized-error-message.md +52 -0
  121. package/rules/go/idiom/errors/check-error-immediately.md +45 -0
  122. package/rules/go/idiom/errors/defer-close-explicit-discard.md +65 -0
  123. package/rules/go/idiom/errors/error-is-last-return-value.md +53 -0
  124. package/rules/go/idiom/errors/no-log-and-return.md +45 -0
  125. package/rules/go/idiom/formatting/blank-line-before-return.md +48 -0
  126. package/rules/go/idiom/formatting/multiline-struct-literals.md +56 -0
  127. package/rules/go/idiom/imports/import-order-groups.md +42 -0
  128. package/rules/go/idiom/imports/side-effect-imports-own-group.md +51 -0
  129. package/rules/go/idiom/interfaces/accept-interfaces-return-concrete.md +39 -0
  130. package/rules/go/idiom/iterators/prefer-iter-seq.md +47 -0
  131. package/rules/go/idiom/logging/lowercase-log-messages.md +80 -0
  132. package/rules/go/idiom/logging/use-slog.md +46 -0
  133. package/rules/go/idiom/naming/acronyms-consistent-case.md +97 -0
  134. package/rules/go/idiom/naming/interface-er-suffix.md +33 -0
  135. package/rules/go/idiom/naming/no-package-name-stutter.md +37 -0
  136. package/rules/go/idiom/naming/package-name-single-lowercase-word.md +40 -0
  137. package/rules/go/idiom/receivers/consistent-receiver-kind-per-type.md +40 -0
  138. package/rules/go/idiom/receivers/no-this-receiver.md +37 -0
  139. package/rules/go/idiom/receivers/pointer-vs-value-receiver-choice.md +49 -0
  140. package/rules/go/idiom/receivers/short-receiver-names.md +43 -0
  141. package/rules/go/idiom/structs/new-expr-for-pointer-fields.md +40 -0
  142. package/rules/go/idiom/structure/main-delegates-to-run.md +54 -0
  143. package/rules/ts/futureproof/classes/composition-over-abstract-base.md +73 -0
  144. package/rules/ts/futureproof/functions/explicit-return-type-on-exports.md +50 -0
  145. package/rules/ts/futureproof/structure/colocate-zod-schemas.md +46 -0
  146. package/rules/ts/futureproof/types/exhaustive-switch-never-check.md +52 -0
  147. package/rules/ts/futureproof/types/readonly-for-immutable-data.md +46 -0
  148. package/rules/ts/futureproof/zod/enum-values-from-const-object.md +37 -0
  149. package/rules/ts/futureproof/zod/no-z-native-enum.md +36 -0
  150. package/rules/ts/futureproof/zod/schema-first-infer-type.md +46 -0
  151. package/rules/ts/hacky/async/no-floating-promises.md +52 -0
  152. package/rules/ts/hacky/config/env-read-outside-config.md +56 -0
  153. package/rules/ts/hacky/errors/catch-param-typed-unknown.md +67 -0
  154. package/rules/ts/hacky/errors/custom-error-class-instanceof.md +66 -0
  155. package/rules/ts/hacky/errors/empty-catch.md +52 -0
  156. package/rules/ts/hacky/errors/log-and-swallow.md +65 -0
  157. package/rules/ts/hacky/errors/throw-typed-error-with-context.md +64 -0
  158. package/rules/ts/hacky/operators/nullish-coalescing-over-or.md +50 -0
  159. package/rules/ts/hacky/state/exported-let.md +60 -0
  160. package/rules/ts/hacky/type-safety/no-double-assertion.md +34 -0
  161. package/rules/ts/hacky/type-safety/no-explicit-any.md +48 -0
  162. package/rules/ts/hacky/type-safety/no-non-null-assertion.md +43 -0
  163. package/rules/ts/hacky/type-safety/no-unchecked-type-assertion.md +54 -0
  164. package/rules/ts/hacky/type-safety/validate-parsed-json.md +48 -0
  165. package/rules/ts/idiom/async/no-promise-chains.md +45 -0
  166. package/rules/ts/idiom/async/parallelize-independent-awaits.md +46 -0
  167. package/rules/ts/idiom/comments/doc-comment-above-declaration.md +43 -0
  168. package/rules/ts/idiom/constants/as-const-for-literal-config.md +65 -0
  169. package/rules/ts/idiom/constants/no-enum.md +37 -0
  170. package/rules/ts/idiom/control-flow/always-brace-if.md +56 -0
  171. package/rules/ts/idiom/control-flow/guard-clauses-early-return.md +52 -0
  172. package/rules/ts/idiom/control-flow/no-nested-ternary.md +54 -0
  173. package/rules/ts/idiom/errors/error-message-lowercase.md +56 -0
  174. package/rules/ts/idiom/errors/log-at-boundary-not-every-layer.md +66 -0
  175. package/rules/ts/idiom/exports/inline-export-at-declaration.md +49 -0
  176. package/rules/ts/idiom/exports/no-default-export.md +37 -0
  177. package/rules/ts/idiom/formatting/multiline-object-literals.md +46 -0
  178. package/rules/ts/idiom/functions/arrow-for-callbacks.md +44 -0
  179. package/rules/ts/idiom/functions/function-declaration-for-top-level.md +56 -0
  180. package/rules/ts/idiom/imports/export-type-for-types.md +34 -0
  181. package/rules/ts/idiom/imports/import-order.md +66 -0
  182. package/rules/ts/idiom/imports/import-type-for-types.md +50 -0
  183. package/rules/ts/idiom/imports/side-effect-imports-last.md +42 -0
  184. package/rules/ts/idiom/logging/structured-logging-lowercase.md +45 -0
  185. package/rules/ts/idiom/naming/boolean-name-question-prefix.md +42 -0
  186. package/rules/ts/idiom/naming/descriptive-identifier-quality.md +48 -0
  187. package/rules/ts/idiom/naming/screaming-snake-module-constants.md +58 -0
  188. package/rules/ts/idiom/strings/template-literals-over-concat.md +51 -0
  189. package/rules/ts/idiom/types/interface-extends-over-intersection.md +44 -0
  190. package/rules/ts/idiom/types/null-vs-undefined-convention.md +43 -0
  191. package/rules/ts/idiom/types/prefer-type-over-interface.md +64 -0
  192. package/rules/ts/idiom/types/satisfies-over-annotation.md +43 -0
  193. package/rules/ts/idiom/types/type-predicates-for-narrowing.md +53 -0
  194. package/rules/ts/idiom/variables/const-by-default.md +41 -0
  195. package/rules/ts/idiom/variables/no-var.md +36 -0
@@ -0,0 +1,43 @@
1
+ ---
2
+ severity: info
3
+ detect: judge
4
+ falsePositives:
5
+ - values that come from an external API, database column, or library that itself uses `null`, where mirroring it is the honest type
6
+ - React state initialized with `null` to mean not yet loaded or no selection
7
+ - optional properties declared with `?`, which are `undefined` by definition
8
+ ---
9
+
10
+ ## Why
11
+
12
+ `undefined` is what the language produces for structural absence: a missing property, a `Map.get` miss, an `Array.find` with no hit. `null` is a value a developer chooses to mean "explicitly nothing", such as no selection or no error. Returning `null` from a lookup, or writing `foo: string | undefined` where the author means a deliberate empty state, mixes the two and makes callers check for both.
13
+
14
+ ## Message
15
+
16
+ null and undefined used interchangeably; undefined for absence, null for a deliberate empty value
17
+
18
+ ## Bad
19
+
20
+ ```ts
21
+ // BAD: a lookup miss is structural absence, which the language already spells undefined
22
+ function findUser(id: string): User | null {
23
+ const user = users.get(id);
24
+
25
+ return user === undefined ? null : user;
26
+ }
27
+ ```
28
+
29
+ ## Good
30
+
31
+ ```ts
32
+ function findUser(id: string): User | undefined {
33
+ return users.get(id);
34
+ }
35
+ ```
36
+
37
+ ```ts
38
+ type Form = {
39
+ selectedUser: User | null;
40
+ };
41
+
42
+ const [error, setError] = useState<string | null>(null);
43
+ ```
@@ -0,0 +1,64 @@
1
+ ---
2
+ severity: minor
3
+ detect: ast
4
+ ast:
5
+ rule:
6
+ kind: interface_declaration
7
+ not:
8
+ any:
9
+ - has:
10
+ kind: extends_type_clause
11
+ - inside:
12
+ kind: ambient_declaration
13
+ stopBy: end
14
+ - has:
15
+ kind: interface_body
16
+ has:
17
+ kind: method_signature
18
+ ---
19
+
20
+ ## Why
21
+
22
+ A plain data shape is a `type`: it composes with unions, intersections, mapped types, and `z.infer` in one syntax, and it cannot be silently reopened by declaration merging somewhere else in the program. `interface` earns its place when you extend another shape, define a contract that classes implement, or deliberately augment a global. An interface with only properties and no `extends` is a `type` with an extra way to go wrong.
23
+
24
+ ## Message
25
+
26
+ plain data shape declared as `interface`; use `type`
27
+
28
+ ## Bad
29
+
30
+ ```ts
31
+ // BAD: a data shape that gains nothing from being an interface
32
+ interface User {
33
+ id: string;
34
+ name: string;
35
+ }
36
+ ```
37
+
38
+ ## Good
39
+
40
+ ```ts
41
+ type User = {
42
+ id: string;
43
+ name: string;
44
+ };
45
+ ```
46
+
47
+ ```ts
48
+ interface Admin extends User {
49
+ role: 'admin';
50
+ }
51
+
52
+ interface Repository<T> {
53
+ findById(id: string): Promise<T | undefined>;
54
+ save(item: T): Promise<void>;
55
+ }
56
+ ```
57
+
58
+ ```ts
59
+ declare global {
60
+ interface Window {
61
+ analytics: Analytics;
62
+ }
63
+ }
64
+ ```
@@ -0,0 +1,43 @@
1
+ ---
2
+ severity: minor
3
+ detect: ast
4
+ ast:
5
+ rule:
6
+ pattern: 'const $NAME: Record<$K, $V> = $OBJ'
7
+ constraints:
8
+ OBJ:
9
+ kind: object
10
+ ---
11
+
12
+ ## Why
13
+
14
+ Annotating an object literal with `Record<string, T>` throws away the keys the literal actually has, so `config.typo` compiles and every value is widened to `T`. `satisfies Record<string, T>` runs the same check while keeping the literal keys and values, so a misspelled key is an error and `keyof typeof config` is a useful union. The annotation form is only right when the object is genuinely open-ended.
15
+
16
+ ## Message
17
+
18
+ object literal annotated with `Record` loses its keys; use `satisfies`
19
+
20
+ ## Bad
21
+
22
+ ```ts
23
+ // BAD: the keys are gone and any string indexes without error
24
+ const routes: Record<string, string> = {
25
+ home: '/',
26
+ users: '/users',
27
+ };
28
+ ```
29
+
30
+ ## Good
31
+
32
+ ```ts
33
+ const routes = {
34
+ home: '/',
35
+ users: '/users',
36
+ } satisfies Record<string, string>;
37
+
38
+ type RouteKey = keyof typeof routes;
39
+ ```
40
+
41
+ ```ts
42
+ const cache: Record<string, User> = await loadCache();
43
+ ```
@@ -0,0 +1,53 @@
1
+ ---
2
+ severity: minor
3
+ detect: judge
4
+ falsePositives:
5
+ - boolean functions that answer a business question rather than a type question, such as `isActive(user)` or `hasPermission(user, action)`
6
+ - a check that is used once, inline, and never followed by a cast
7
+ - functions that already declare `value is T` or `asserts value is T`
8
+ ---
9
+
10
+ ## Why
11
+
12
+ A function that returns `boolean` after checking a value's shape tells the caller yes or no, but the compiler learns nothing, so the caller follows the check with `as T` and the two drift apart. Declaring the return as `value is T` ties the check to the narrowing: inside the `if`, the value is `T` with no cast, and `filter` returns the narrowed array. Assertion functions with `asserts value is T` do the same for throw-on-failure checks.
13
+
14
+ ## Message
15
+
16
+ type check returns a plain boolean; declare a type predicate so callers narrow without casting
17
+
18
+ ## Bad
19
+
20
+ ```ts
21
+ // BAD: callers learn nothing and cast right after the check
22
+ function isUser(value: unknown): boolean {
23
+ return typeof value === 'object' && value !== null && 'id' in value;
24
+ }
25
+
26
+ function display(value: unknown): string {
27
+ if (isUser(value)) {
28
+ return (value as User).name;
29
+ }
30
+
31
+ return 'unknown';
32
+ }
33
+ ```
34
+
35
+ ## Good
36
+
37
+ ```ts
38
+ function isUser(value: unknown): value is User {
39
+ return typeof value === 'object' && value !== null && 'id' in value;
40
+ }
41
+
42
+ function display(value: unknown): string {
43
+ if (isUser(value)) {
44
+ return value.name;
45
+ }
46
+
47
+ return 'unknown';
48
+ }
49
+ ```
50
+
51
+ ```ts
52
+ const strings = mixed.filter((item): item is string => typeof item === 'string');
53
+ ```
@@ -0,0 +1,41 @@
1
+ ---
2
+ severity: minor
3
+ detect: judge
4
+ falsePositives:
5
+ - a `let` that is assigned in more than one branch or reassigned later in its scope, including inside a loop body or a try block
6
+ - a `let` declared without an initializer and assigned exactly once further down, when merging it into a `const` would need a nested ternary or an IIFE
7
+ - loop counters in a classic `for` statement
8
+ ---
9
+
10
+ ## Why
11
+
12
+ `const` tells the reader that a binding never changes, which removes one question from every later line that uses it. A `let` that is never reassigned makes the reader scan the rest of the scope looking for the mutation that is not there. Declare with `const` and switch to `let` only when there is a real second assignment.
13
+
14
+ ## Message
15
+
16
+ `let` is never reassigned; declare it with `const`
17
+
18
+ ## Bad
19
+
20
+ ```ts
21
+ // BAD: total is assigned once and never changes
22
+ let total = items.reduce((sum, item) => sum + item.price, 0);
23
+
24
+ return formatCurrency(total);
25
+ ```
26
+
27
+ ## Good
28
+
29
+ ```ts
30
+ const total = items.reduce((sum, item) => sum + item.price, 0);
31
+
32
+ return formatCurrency(total);
33
+ ```
34
+
35
+ ```ts
36
+ let attempts = 0;
37
+
38
+ while (attempts < MAX_RETRIES) {
39
+ attempts += 1;
40
+ }
41
+ ```
@@ -0,0 +1,36 @@
1
+ ---
2
+ severity: minor
3
+ detect: ast
4
+ ast:
5
+ rule:
6
+ kind: variable_declaration
7
+ ---
8
+
9
+ ## Why
10
+
11
+ `var` is function-scoped and hoisted, so a variable declared inside a loop or an `if` leaks into the whole function and can be read before its assignment. `const` and `let` are block-scoped, fail loudly when used early, and tell the reader whether the binding changes. There is no situation in modern TypeScript where `var` is the right choice.
12
+
13
+ ## Message
14
+
15
+ `var` is function-scoped and hoisted; use `const` or `let`
16
+
17
+ ## Bad
18
+
19
+ ```ts
20
+ // BAD: var leaks out of the block it was declared in
21
+ var total = 0;
22
+
23
+ for (var i = 0; i < items.length; i += 1) {
24
+ total += items[i];
25
+ }
26
+ ```
27
+
28
+ ## Good
29
+
30
+ ```ts
31
+ let total = 0;
32
+
33
+ for (const item of items) {
34
+ total += item;
35
+ }
36
+ ```