spaghetti-slicer 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.
- package/LICENSE +21 -0
- package/README.md +259 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1158 -0
- package/package.json +37 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 neerajram30
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,259 @@
|
|
|
1
|
+
# π spaghetti-slicer
|
|
2
|
+
|
|
3
|
+
[](https://www.npmjs.com/package/spaghetti-slicer)
|
|
4
|
+
[](https://github.com/neerajram30/spaghetti-slicer/blob/main/LICENSE)
|
|
5
|
+
[](http://makeapullrequest.com)
|
|
6
|
+
[](https://github.com/prettier/prettier)
|
|
7
|
+
|
|
8
|
+
A highly opinionated frontend best practices auditor for React & TypeScript codebases. It is designed to automatically scan, analyze, and slice away "spaghetti code" before it reaches productionβespecially code generated by AI coding assistants like Cursor, v0, Bolt, and Lovable.
|
|
9
|
+
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
## β¨ Features
|
|
13
|
+
|
|
14
|
+
- β‘ **Zero Config**: Works out of the box with zero setup. Point it at your code and let it slice.
|
|
15
|
+
- π **Quantifiable Scores**: Generates a weighted score out of 100 across 5 core categories, grading your repository from **Excellent** to **Poor**.
|
|
16
|
+
- π οΈ **Built for AI-Generated Code**: Catches common anti-patterns that LLMs frequently introduce (such as state bloat, inline fetching, and missing dimensions).
|
|
17
|
+
- π€ **CI/CD Friendly**: Fail pipelines automatically with `--min-score` when code quality falls below your team's threshold.
|
|
18
|
+
- π **Flexible Output**: Print beautiful console summaries with `ora` spinners and `boxen` layouts, or stream raw JSON to stdout using `--json`.
|
|
19
|
+
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
## π Installation
|
|
23
|
+
|
|
24
|
+
### Run instantly with `npx` (No Install)
|
|
25
|
+
```bash
|
|
26
|
+
npx spaghetti-slicer ./src
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
### Install Globally
|
|
30
|
+
```bash
|
|
31
|
+
npm install -g spaghetti-slicer
|
|
32
|
+
|
|
33
|
+
# Run audit
|
|
34
|
+
spaghetti-slicer ./src
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
---
|
|
38
|
+
|
|
39
|
+
## π οΈ Usage & CLI Flags
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
# Audit a whole folder or specific files
|
|
43
|
+
spaghetti-slicer ./src
|
|
44
|
+
spaghetti-slicer ./src/components/Button.tsx
|
|
45
|
+
|
|
46
|
+
# Exit with code 1 if score drops below 80 (perfect for CI checks)
|
|
47
|
+
spaghetti-slicer ./src --min-score=80
|
|
48
|
+
|
|
49
|
+
# Filter rules to run only a specific category
|
|
50
|
+
spaghetti-slicer ./src --rule=architecture
|
|
51
|
+
spaghetti-slicer ./src --rule=react
|
|
52
|
+
|
|
53
|
+
# Print clean JSON for external scripting
|
|
54
|
+
spaghetti-slicer ./src --json
|
|
55
|
+
|
|
56
|
+
# Show interactive lint/eslint autofix recommendations
|
|
57
|
+
spaghetti-slicer ./src --fix
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
---
|
|
61
|
+
|
|
62
|
+
## π Code Quality Rules
|
|
63
|
+
|
|
64
|
+
`spaghetti-slicer` runs rules in several core categories:
|
|
65
|
+
|
|
66
|
+
### ποΈ Architecture (Weight: 25%)
|
|
67
|
+
|
|
68
|
+
| Rule ID | Severity | Description |
|
|
69
|
+
|:---|:---:|:---|
|
|
70
|
+
| `component-length` | π΄ Critical | Components exceeding 200 lines should be broken up |
|
|
71
|
+
| `business-logic-in-jsx` | π‘ Warning | Inline data operations (`.filter()`, `.reduce()`, `.sort()`) in JSX |
|
|
72
|
+
| `direct-fetch-in-component` | π΄ Critical | Making raw HTTP fetch/axios requests directly inside component bodies |
|
|
73
|
+
| `state-bloat` | π‘ Warning | Defining more than 5 `useState` hooks in a single component |
|
|
74
|
+
| `hardcoded-secrets-endpoints` | π΄ Critical | Hardcoded raw URL strings or potential API credentials/keys |
|
|
75
|
+
|
|
76
|
+
### βοΈ React (Weight: 20%)
|
|
77
|
+
|
|
78
|
+
| Rule ID | Severity | Description |
|
|
79
|
+
|:---|:---:|:---|
|
|
80
|
+
| `index-as-key` | π΄ Critical | Array iteration index used as the React `key` prop |
|
|
81
|
+
| `missing-error-boundary` | π‘ Warning | Codebase lacks any React Error Boundary components |
|
|
82
|
+
| `no-sub-renders` | π‘ Warning | Helper render functions (e.g. `renderHeader()`) nested in components |
|
|
83
|
+
| `fat-controller` | π‘ Warning | Non-JSX javascript logic exceeds 75% of a component's total line length |
|
|
84
|
+
|
|
85
|
+
### β‘ Performance (Weight: 15%)
|
|
86
|
+
|
|
87
|
+
| Rule ID | Severity | Description |
|
|
88
|
+
|:---|:---:|:---|
|
|
89
|
+
| `image-missing-dimensions` | π‘ Warning | `<img>` or `<Image>` tags missing `width` or `height` attributes (causes CLS) |
|
|
90
|
+
|
|
91
|
+
---
|
|
92
|
+
|
|
93
|
+
## π‘ Code Patterns: Bad vs. Good
|
|
94
|
+
|
|
95
|
+
Here's how `spaghetti-slicer` helps you clean up common code smells:
|
|
96
|
+
|
|
97
|
+
### 1. Direct Fetch in Component (`direct-fetch-in-component`)
|
|
98
|
+
* β **Bad:** Making raw API calls inside a render or useEffect lifecycle.
|
|
99
|
+
```tsx
|
|
100
|
+
export function UserProfile() {
|
|
101
|
+
useEffect(() => {
|
|
102
|
+
fetch('/api/user/profile').then(res => res.json()).then(data => {...});
|
|
103
|
+
}, []);
|
|
104
|
+
return <div>User Profile</div>;
|
|
105
|
+
}
|
|
106
|
+
```
|
|
107
|
+
* **Good:** Extract to a custom hook or API service layer.
|
|
108
|
+
```tsx
|
|
109
|
+
import { useUserProfile } from '../hooks/useUserProfile';
|
|
110
|
+
|
|
111
|
+
export function UserProfile() {
|
|
112
|
+
const { profile, loading } = useUserProfile();
|
|
113
|
+
return <div>User Profile</div>;
|
|
114
|
+
}
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
### 2. State Bloat (`state-bloat`)
|
|
118
|
+
* β **Bad:** Managing component states using too many individual hooks.
|
|
119
|
+
```tsx
|
|
120
|
+
const [name, setName] = useState('');
|
|
121
|
+
const [email, setEmail] = useState('');
|
|
122
|
+
const [age, setAge] = useState(0);
|
|
123
|
+
const [address, setAddress] = useState('');
|
|
124
|
+
const [phone, setPhone] = useState('');
|
|
125
|
+
const [company, setCompany] = useState(''); // β οΈ State Bloat Triggered (6 hooks)
|
|
126
|
+
```
|
|
127
|
+
* **Good:** Merge related states or delegate to `useReducer` / state containers.
|
|
128
|
+
```tsx
|
|
129
|
+
const [formData, setFormData] = useState({
|
|
130
|
+
name: '', email: '', age: 0, address: '', phone: '', company: ''
|
|
131
|
+
});
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
### 3. Nested Helper Renders (`no-sub-renders`)
|
|
135
|
+
* β **Bad:** Defining sub-rendering helper functions inside the main component body.
|
|
136
|
+
```tsx
|
|
137
|
+
export function ProductCard({ title, price }) {
|
|
138
|
+
const renderBadge = () => <span className="badge">New</span>; // β οΈ Defined inside Card
|
|
139
|
+
return (
|
|
140
|
+
<div>
|
|
141
|
+
<h3>{title}</h3>
|
|
142
|
+
{renderBadge()}
|
|
143
|
+
</div>
|
|
144
|
+
);
|
|
145
|
+
}
|
|
146
|
+
```
|
|
147
|
+
* **Good:** Extract to its own component.
|
|
148
|
+
```tsx
|
|
149
|
+
function Badge() {
|
|
150
|
+
return <span className="badge">New</span>;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
export function ProductCard({ title, price }) {
|
|
154
|
+
return (
|
|
155
|
+
<div>
|
|
156
|
+
<h3>{title}</h3>
|
|
157
|
+
<Badge />
|
|
158
|
+
</div>
|
|
159
|
+
);
|
|
160
|
+
}
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
---
|
|
164
|
+
|
|
165
|
+
## π Scoring System
|
|
166
|
+
|
|
167
|
+
Your project starts with a score of **100** for each category. Points are deducted per violation:
|
|
168
|
+
* π΄ **Critical Violation**: `-10 points`
|
|
169
|
+
* π‘ **Warning Violation**: `-5 points`
|
|
170
|
+
* π΅ **Info Violation**: `-2 points`
|
|
171
|
+
|
|
172
|
+
A total score is calculated using the weighted averages of all categories. Your repository is then assigned a Grade:
|
|
173
|
+
|
|
174
|
+
| Score | Grade | Description |
|
|
175
|
+
|:---:|:---:|:---|
|
|
176
|
+
| **90 β 100** | β
**Excellent** | Clean codebase, minimal code smells |
|
|
177
|
+
| **75 β 89** | β
**Good** | Solid structure, minor refactoring recommended |
|
|
178
|
+
| **60 β 74** | β οΈ **Needs Work** | Code smells present, potential architectural issues |
|
|
179
|
+
| **< 60** | β **Poor** | High risk of bugs and difficult maintenance |
|
|
180
|
+
|
|
181
|
+
---
|
|
182
|
+
|
|
183
|
+
## π€ GitHub Actions CI/CD Integration
|
|
184
|
+
|
|
185
|
+
Catch regressions automatically on every Pull Request. Add this workflow as `.github/workflows/spaghetti-slicer.yml`:
|
|
186
|
+
|
|
187
|
+
```yaml
|
|
188
|
+
name: Code Quality Audit
|
|
189
|
+
on: [pull_request]
|
|
190
|
+
|
|
191
|
+
jobs:
|
|
192
|
+
audit:
|
|
193
|
+
runs-on: ubuntu-latest
|
|
194
|
+
steps:
|
|
195
|
+
- name: Checkout Code
|
|
196
|
+
uses: actions/checkout@v4
|
|
197
|
+
|
|
198
|
+
- name: Setup Node.js
|
|
199
|
+
uses: actions/setup-node@v4
|
|
200
|
+
with:
|
|
201
|
+
node-version: '20'
|
|
202
|
+
cache: 'npm'
|
|
203
|
+
|
|
204
|
+
- name: Install Dependencies
|
|
205
|
+
run: npm ci
|
|
206
|
+
|
|
207
|
+
- name: Build Project
|
|
208
|
+
run: npm run build
|
|
209
|
+
|
|
210
|
+
- name: Run Spaghetti Slicer
|
|
211
|
+
# Exit and fail the action if quality score falls below 80%
|
|
212
|
+
run: npx spaghetti-slicer ./src --min-score=80
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
---
|
|
216
|
+
|
|
217
|
+
## βοΈ Local Development & Contributing
|
|
218
|
+
|
|
219
|
+
We welcome community contributions to add more rules or improve CLI performance!
|
|
220
|
+
|
|
221
|
+
### Prerequisites & Setup
|
|
222
|
+
1. Fork and clone the repository.
|
|
223
|
+
2. Install dependencies:
|
|
224
|
+
```bash
|
|
225
|
+
npm install
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
### Running Tests
|
|
229
|
+
We use `vitest` for fast static-analysis rule validation:
|
|
230
|
+
```bash
|
|
231
|
+
# Run tests once
|
|
232
|
+
npm run test:run
|
|
233
|
+
|
|
234
|
+
# Run tests in watch mode
|
|
235
|
+
npm run test
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
### Linking the CLI locally
|
|
239
|
+
Test your local changes against any separate project directory on your computer:
|
|
240
|
+
```bash
|
|
241
|
+
# 1. From the spaghetti-slicer repository directory
|
|
242
|
+
npm run build
|
|
243
|
+
npm link
|
|
244
|
+
|
|
245
|
+
# 2. Run globally linked CLI in another project directory
|
|
246
|
+
spaghetti-slicer /path/to/other-project/src
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
### Adding a New Rule
|
|
250
|
+
1. Create your rule under `src/rules/<category>/<rule-name>.ts` implementing the `Rule` interface.
|
|
251
|
+
2. Register the rule in `src/rules/index.ts`.
|
|
252
|
+
3. Write test cases covering pass and fail fixtures under `tests/rules/<category>/<rule-name>.test.ts`.
|
|
253
|
+
4. Run `npm run test:run` to confirm everything works!
|
|
254
|
+
|
|
255
|
+
---
|
|
256
|
+
|
|
257
|
+
## π License
|
|
258
|
+
|
|
259
|
+
This project is open-source and licensed under the [MIT License](LICENSE).
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
#!/usr/bin/env node
|