@fabriziosalmi/slopless 1.13.1 → 1.15.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.
package/README.md CHANGED
@@ -6,7 +6,7 @@ Slopless is a static analysis tool designed to identify and mitigate unstructure
6
6
 
7
7
  ## Architecture and Capabilities
8
8
 
9
- - **Rule Engine**: 150 rigorous rules spanning security, maintainability, accessibility, and documentation integrity. Every rule ships executable examples — a snippet it must flag and one it must leave alone — run on every commit.
9
+ - **Rule Engine**: 152 rigorous rules spanning security, maintainability, accessibility, and documentation integrity. Every rule ships executable examples — a snippet it must flag and one it must leave alone — run on every commit.
10
10
  - **AST Inspection**: Deep structural validation to identify excessive cyclomatic complexity, parameter limits, and empty control flow blocks.
11
11
  - **Deep Semantic Validation**: Opt-in TypeScript TypeChecker (`--type-check`) for resolving inherited types, identifying floating promises, and validating structural intent beyond AST boundaries.
12
12
  - **Heuristic Auto-Fixes**: Autonomous modification of known anti-patterns (e.g., `var` to `let`) using `--fix`.
@@ -14,7 +14,7 @@ Slopless is a static analysis tool designed to identify and mitigate unstructure
14
14
  - **Lexical Scoping**: Every string, comment and regular expression literal is mapped before a rule reads a byte — with the TypeScript scanner where it can, and a declarative tokeniser for Python, Go, Rust, shell, Java, C, C++, C#, Kotlin, Swift and Ruby. Each rule declares what it looks at (`code`, `strings`, `comments`, `regex`, `all`). A rule about `eval()` stays quiet inside a comment; a rule about insecure URLs does not read the pattern that validates them; a Python docstring is documentation rather than a string value.
15
15
  - **Exceptions That Say Why**: A rule can skip test code that lives inside the file it tests (`#[cfg(test)] mod tests`), skip documentation comments in languages that mandate them, and be excused by name on one line with `// slopless-disable-next-line VBC-001 -- reason`. A project can claim its own vocabulary, so `blacklist` in a firewall is the domain rather than a finding — and the run reports how many findings that excused.
16
16
  - **Rule Precedence**: A specific rule declares the general ones it `supersedes`, so a single `// TODO: implement this` produces one finding, not four.
17
- - **LSP IDE Integration**: Ships with `vscode-slopless` for real-time Squiggly-Line diagnostics inside VS Code and Cursor.
17
+ - **In the editor, and while writing**: [`packages/vscode-slopless`](packages/vscode-slopless) is a language server and a Slopless panel — diagnostics as you type, and a list of what the rules found across the workspace, ordered errors first. Build the `.vsix` and install it; it is not on the Marketplace. [`packages/mcp-slopless`](packages/mcp-slopless) is an MCP server, so a coding agent can check a buffer *before* it writes the file rather than after the commit. Both run the same engine and the same rules as the CLI.
18
18
 
19
19
  ## GitHub Action
20
20
 
@@ -123,32 +123,32 @@ count, written from the rules rather than from memory:
123
123
  <!-- coverage:start -->
124
124
  | language | rules |
125
125
  | --- | --- |
126
- | TypeScript (JSX) (`.tsx`) | 97 of 150 |
127
- | TypeScript (`.ts`) | 95 of 150 |
128
- | JavaScript (`.js`) | 94 of 150 |
129
- | Astro (`.astro`) | 83 of 150 |
130
- | Python (`.py`) | 32 of 150 |
131
- | JavaScript (JSX) (`.jsx`) | 31 of 150 |
132
- | Markdown (`.md`) | 26 of 150 |
133
- | CSS (`.css`) | 23 of 150 |
134
- | HTML (`.html`) | 21 of 150 |
135
- | Go (`.go`) | 19 of 150 |
136
- | Plain text (`.txt`) | 18 of 150 |
137
- | Shell (`.sh`) | 16 of 150 |
138
- | Java (`.java`) | 15 of 150 |
139
- | Rust (`.rs`) | 15 of 150 |
140
- | Sass (SCSS) (`.scss`) | 15 of 150 |
141
- | Ruby (`.rb`) | 14 of 150 |
142
- | C# (`.cs`) | 13 of 150 |
143
- | C (`.c`) | 12 of 150 |
144
- | C++ (`.cpp`) | 12 of 150 |
145
- | Kotlin (`.kt`) | 12 of 150 |
146
- | Swift (`.swift`) | 12 of 150 |
147
- | Less (`.less`) | 9 of 150 |
148
- | JSON (`.json`) | 5 of 150 |
149
- | PHP (`.php`) | 5 of 150 |
150
- | Dotenv (`.env`) | 4 of 150 |
151
- | YAML (`.yaml`) | 3 of 150 |
126
+ | TypeScript (JSX) (`.tsx`) | 98 of 152 |
127
+ | TypeScript (`.ts`) | 96 of 152 |
128
+ | JavaScript (`.js`) | 95 of 152 |
129
+ | Astro (`.astro`) | 84 of 152 |
130
+ | JavaScript (JSX) (`.jsx`) | 32 of 152 |
131
+ | Python (`.py`) | 32 of 152 |
132
+ | Markdown (`.md`) | 26 of 152 |
133
+ | CSS (`.css`) | 23 of 152 |
134
+ | HTML (`.html`) | 21 of 152 |
135
+ | Go (`.go`) | 19 of 152 |
136
+ | Plain text (`.txt`) | 18 of 152 |
137
+ | Shell (`.sh`) | 16 of 152 |
138
+ | Java (`.java`) | 15 of 152 |
139
+ | Rust (`.rs`) | 15 of 152 |
140
+ | Sass (SCSS) (`.scss`) | 15 of 152 |
141
+ | Ruby (`.rb`) | 14 of 152 |
142
+ | C# (`.cs`) | 13 of 152 |
143
+ | C (`.c`) | 12 of 152 |
144
+ | C++ (`.cpp`) | 12 of 152 |
145
+ | Kotlin (`.kt`) | 12 of 152 |
146
+ | Swift (`.swift`) | 12 of 152 |
147
+ | Less (`.less`) | 9 of 152 |
148
+ | JSON (`.json`) | 5 of 152 |
149
+ | PHP (`.php`) | 5 of 152 |
150
+ | Dotenv (`.env`) | 4 of 152 |
151
+ | YAML (`.yaml`) | 3 of 152 |
152
152
  <!-- coverage:end -->
153
153
 
154
154
  The parsing tiers use the TypeScript compiler, so the AST, semantic-naming and
@@ -169,7 +169,7 @@ None of them has an opinion about a section that says "coming soon".
169
169
  - **Documentation**: Detection of generated filler content, non-inclusive language, and broken external references.
170
170
 
171
171
  Full documentation at [fabriziosalmi.github.io/slopless](https://fabriziosalmi.github.io/slopless/):
172
- [all 150 rules](https://fabriziosalmi.github.io/slopless/rules/) ·
172
+ [all 152 rules](https://fabriziosalmi.github.io/slopless/rules/) ·
173
173
  [configuration](https://fabriziosalmi.github.io/slopless/configuration) ·
174
174
  [writing a rule](https://fabriziosalmi.github.io/slopless/writing-a-rule) ·
175
175
  [the scanner bug story](https://fabriziosalmi.github.io/slopless/story)
@@ -11,6 +11,74 @@ interface Violation {
11
11
  };
12
12
  }
13
13
 
14
+ /**
15
+ * The rules a run would use: what is on disk, plus whatever the config adds,
16
+ * with severities overridden, rules turned off removed, and opt-in rules kept
17
+ * only when the config asked for them.
18
+ *
19
+ * Exported because anything that lists rules — an editor panel, an MCP tool —
20
+ * has to list the same ones the linter runs, and rebuilding that set somewhere
21
+ * else is how the two drift apart.
22
+ */
23
+ declare function resolveRules(configPath?: string): {
24
+ id: string;
25
+ name: string;
26
+ category: string;
27
+ severity: "error" | "warning";
28
+ match: {
29
+ regex?: string | undefined;
30
+ flags?: string | undefined;
31
+ file_types?: string[] | undefined;
32
+ scan?: "regex" | "code" | "strings" | "comments" | "all" | undefined;
33
+ multiline?: boolean | undefined;
34
+ exclude_files?: string[] | undefined;
35
+ exclude_selectors?: string[] | undefined;
36
+ require_selectors?: string[] | undefined;
37
+ variants?: {
38
+ file_types: string[];
39
+ regex: string;
40
+ flags?: string | undefined;
41
+ scan?: "regex" | "code" | "strings" | "comments" | "all" | undefined;
42
+ multiline?: boolean | undefined;
43
+ message?: string | undefined;
44
+ }[] | undefined;
45
+ exclude_test_code?: boolean | undefined;
46
+ exclude_doc_comments?: boolean | undefined;
47
+ git_check?: "committed_env" | "private_key" | "binary_file" | "node_modules" | "commit_message_too_short" | "missing_gitignore" | "missing_license" | "missing_readme" | "spaces_in_filenames" | "too_many_staged_files" | "filename_too_long" | "large_file_size" | "committed_ide_settings" | "missing_contributing" | "missing_security" | "missing_changelog" | undefined;
48
+ ast_check?: {
49
+ type: "function-params-limit" | "function-length-limit" | "file-length-limit" | "empty-catch" | "nested-blocks-limit" | "empty-block" | "one-liner-limit" | "redundant-if-true" | "lying-function-names" | "empty-interface" | "async-without-await" | "empty-file";
50
+ threshold?: number | undefined;
51
+ } | undefined;
52
+ heuristic_check?: "link-checker" | "stale-copyright-year" | undefined;
53
+ semantic_check?: "boolean-naming" | "boolean-redundancy" | "collection-suffix" | "semantic-shadowing" | undefined;
54
+ type_check?: "floating-promise" | undefined;
55
+ threshold?: number | undefined;
56
+ };
57
+ message: string;
58
+ tags?: string[] | undefined;
59
+ fix?: {
60
+ regex_replace?: {
61
+ pattern: string;
62
+ replacement: string;
63
+ } | undefined;
64
+ } | undefined;
65
+ supersedes?: string[] | undefined;
66
+ opt_in?: boolean | undefined;
67
+ tests?: {
68
+ fire?: (string | {
69
+ code: string;
70
+ file?: string | undefined;
71
+ repeat?: number | undefined;
72
+ })[] | undefined;
73
+ quiet?: (string | {
74
+ code: string;
75
+ file?: string | undefined;
76
+ repeat?: number | undefined;
77
+ })[] | undefined;
78
+ external?: string | undefined;
79
+ } | undefined;
80
+ docs_url?: string | undefined;
81
+ }[];
14
82
  declare function lintText(content: string, filePath: string, configPath?: string): Promise<Violation[]>;
15
83
 
16
- export { lintText };
84
+ export { lintText, resolveRules };