code-quality-lib 1.0.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 +394 -0
- package/index.d.ts +31 -0
- package/index.js +314 -0
- package/package.json +47 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 NoonCore
|
|
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,394 @@
|
|
|
1
|
+
# Code Quality Library
|
|
2
|
+
|
|
3
|
+
[](https://badge.fury.io/js/code-quality-lib)
|
|
4
|
+
[](https://opensource.org/licenses/MIT)
|
|
5
|
+
[](https://nodejs.org/)
|
|
6
|
+
|
|
7
|
+
> A configurable code quality checker library for Node.js projects that supports TypeScript, ESLint, Prettier, Knip, and Snyk with beautiful terminal output.
|
|
8
|
+
|
|
9
|
+
## Features
|
|
10
|
+
|
|
11
|
+
- **Multi-Package Manager Support**: Auto-detects and works with bun, pnpm, yarn, and npm
|
|
12
|
+
- **Configurable**: Customize which tools to run and their commands
|
|
13
|
+
- **Beautiful Output**: Colorized terminal output with clear status indicators
|
|
14
|
+
- **Environment Support**: Automatically loads `.env` files
|
|
15
|
+
- **Snyk Integration**: Handles Snyk authentication gracefully
|
|
16
|
+
- **TypeScript Support**: Full TypeScript definitions included
|
|
17
|
+
- **CLI & Library**: Can be used as both command-line tool and library
|
|
18
|
+
- **Extensible**: Easy to add custom tools and checks
|
|
19
|
+
- **Detailed Reporting**: Clear error counts and status messages
|
|
20
|
+
|
|
21
|
+
## Installation
|
|
22
|
+
|
|
23
|
+
### npm
|
|
24
|
+
```bash
|
|
25
|
+
# Install as development dependency (recommended)
|
|
26
|
+
npm install -D code-quality-lib
|
|
27
|
+
|
|
28
|
+
# Install globally for CLI usage
|
|
29
|
+
npm install -g code-quality-lib
|
|
30
|
+
|
|
31
|
+
# Install from GitHub (development)
|
|
32
|
+
npm install -D https://github.com/NoonCore/code-quality-lib.git
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
### bun (recommended - faster)
|
|
36
|
+
```bash
|
|
37
|
+
# Install as development dependency (recommended)
|
|
38
|
+
bun add -D code-quality-lib
|
|
39
|
+
|
|
40
|
+
# Install globally for CLI usage
|
|
41
|
+
bun add -g code-quality-lib
|
|
42
|
+
|
|
43
|
+
# Install from GitHub (development)
|
|
44
|
+
bun add -D https://github.com/NoonCore/code-quality-lib.git
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
### pnpm
|
|
48
|
+
```bash
|
|
49
|
+
# Install as development dependency (recommended)
|
|
50
|
+
pnpm add -D code-quality-lib
|
|
51
|
+
|
|
52
|
+
# Install globally for CLI usage
|
|
53
|
+
pnpm add -g code-quality-lib
|
|
54
|
+
|
|
55
|
+
# Install from GitHub (development)
|
|
56
|
+
pnpm add -D https://github.com/NoonCore/code-quality-lib.git
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
### yarn
|
|
60
|
+
```bash
|
|
61
|
+
# Install as development dependency (recommended)
|
|
62
|
+
yarn add -D code-quality-lib
|
|
63
|
+
|
|
64
|
+
# Install globally for CLI usage
|
|
65
|
+
yarn global add code-quality-lib
|
|
66
|
+
|
|
67
|
+
# Install from GitHub (development)
|
|
68
|
+
yarn add -D https://github.com/NoonCore/code-quality-lib.git
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
## Usage
|
|
72
|
+
|
|
73
|
+
### As a CLI Tool
|
|
74
|
+
|
|
75
|
+
```bash
|
|
76
|
+
# Run all quality checks
|
|
77
|
+
code-quality
|
|
78
|
+
|
|
79
|
+
# Or use with npx
|
|
80
|
+
npx code-quality-lib
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
### As a Library
|
|
84
|
+
|
|
85
|
+
```javascript
|
|
86
|
+
const { CodeQualityChecker } = require('code-quality-lib');
|
|
87
|
+
|
|
88
|
+
// Use default configuration
|
|
89
|
+
const checker = new CodeQualityChecker();
|
|
90
|
+
checker.run().then(result => {
|
|
91
|
+
console.log(result.success ? 'ā
All checks passed!' : 'ā Some checks failed');
|
|
92
|
+
});
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
## Configuration
|
|
96
|
+
|
|
97
|
+
### Default Tools
|
|
98
|
+
|
|
99
|
+
The library runs these tools by default:
|
|
100
|
+
- **TypeScript** - Type checking and compilation
|
|
101
|
+
- **ESLint** - Code linting and style checking
|
|
102
|
+
- **Prettier** - Code formatting validation
|
|
103
|
+
- **Knip** - Dead code detection and unused exports
|
|
104
|
+
- **Snyk** - Security vulnerability scanning
|
|
105
|
+
|
|
106
|
+
### Custom Configuration
|
|
107
|
+
|
|
108
|
+
```javascript
|
|
109
|
+
const customChecker = new CodeQualityChecker({
|
|
110
|
+
// Force specific package manager
|
|
111
|
+
packageManager: 'pnpm', // 'bun' | 'pnpm' | 'yarn' | 'npm'
|
|
112
|
+
|
|
113
|
+
// Only run specific tools
|
|
114
|
+
tools: ['TypeScript', 'ESLint'],
|
|
115
|
+
|
|
116
|
+
// Custom commands for each tool
|
|
117
|
+
commands: {
|
|
118
|
+
TypeScript: 'tsc --noEmit',
|
|
119
|
+
ESLint: 'eslint src/ --ext .ts,.tsx',
|
|
120
|
+
Prettier: 'prettier --check "src/**/*.{ts,tsx}"'
|
|
121
|
+
},
|
|
122
|
+
|
|
123
|
+
// Custom descriptions
|
|
124
|
+
descriptions: {
|
|
125
|
+
TypeScript: 'TypeScript type checking',
|
|
126
|
+
ESLint: 'ESLint code analysis'
|
|
127
|
+
},
|
|
128
|
+
|
|
129
|
+
// Disable .env loading
|
|
130
|
+
loadEnv: false
|
|
131
|
+
});
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
### Package Manager Detection
|
|
135
|
+
|
|
136
|
+
The library automatically detects your package manager in this order:
|
|
137
|
+
1. **Lock files**: `bun.lock`, `pnpm-lock.yaml`, `yarn.lock`, `package-lock.json`
|
|
138
|
+
2. **Available commands**: Checks if `bun`, `pnpm`, `yarn` are installed
|
|
139
|
+
3. **Fallback**: Uses `npm` if nothing else is found
|
|
140
|
+
|
|
141
|
+
You can also override the detection:
|
|
142
|
+
```javascript
|
|
143
|
+
const checker = new CodeQualityChecker({
|
|
144
|
+
packageManager: 'yarn' // Force yarn usage
|
|
145
|
+
});
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
### Environment-Specific Configuration
|
|
149
|
+
|
|
150
|
+
```javascript
|
|
151
|
+
const isCI = process.env.CI === 'true';
|
|
152
|
+
const ciChecker = new CodeQualityChecker({
|
|
153
|
+
tools: isCI
|
|
154
|
+
? ['TypeScript', 'ESLint']
|
|
155
|
+
: ['TypeScript', 'ESLint', 'Prettier', 'Knip', 'Snyk'],
|
|
156
|
+
loadEnv: !isCI
|
|
157
|
+
});
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
## Integration with Existing Projects
|
|
161
|
+
|
|
162
|
+
### Replace Existing Scripts
|
|
163
|
+
|
|
164
|
+
**Before:**
|
|
165
|
+
```json
|
|
166
|
+
{
|
|
167
|
+
"scripts": {
|
|
168
|
+
"quality": "node scripts/quality-check.js"
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
**After:**
|
|
174
|
+
```json
|
|
175
|
+
{
|
|
176
|
+
"scripts": {
|
|
177
|
+
"quality": "code-quality"
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
### Programmatic Usage
|
|
183
|
+
|
|
184
|
+
```javascript
|
|
185
|
+
// In your build script
|
|
186
|
+
const { CodeQualityChecker } = require('code-quality-lib');
|
|
187
|
+
|
|
188
|
+
async function buildWithQualityCheck() {
|
|
189
|
+
const checker = new CodeQualityChecker({
|
|
190
|
+
tools: ['TypeScript', 'ESLint']
|
|
191
|
+
});
|
|
192
|
+
|
|
193
|
+
const result = await checker.run();
|
|
194
|
+
if (!result.success) {
|
|
195
|
+
console.error('ā Quality checks failed!');
|
|
196
|
+
process.exit(1);
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
// Continue with build...
|
|
200
|
+
console.log('ā
Quality checks passed, building...');
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
buildWithQualityCheck();
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
## Output Example
|
|
207
|
+
|
|
208
|
+
```
|
|
209
|
+
š Professional Code Quality Check
|
|
210
|
+
|
|
211
|
+
āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
|
|
212
|
+
š¦ Using bun package manager
|
|
213
|
+
Checking Snyk authentication...
|
|
214
|
+
Running TypeScript compilation...
|
|
215
|
+
Running ESLint validation...
|
|
216
|
+
Running Prettier formatting...
|
|
217
|
+
Running Dead code detection...
|
|
218
|
+
Running Security vulnerability scan...
|
|
219
|
+
|
|
220
|
+
ā
TypeScript: 0 errors
|
|
221
|
+
ā
ESLint: 0 errors, 0 warnings
|
|
222
|
+
ā
Prettier: All files formatted
|
|
223
|
+
ā
Knip: No critical errors
|
|
224
|
+
ā
Snyk: No vulnerabilities
|
|
225
|
+
āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
|
|
226
|
+
|
|
227
|
+
š All quality checks passed! Code is ready for production.
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
## API Reference
|
|
231
|
+
|
|
232
|
+
### CodeQualityChecker
|
|
233
|
+
|
|
234
|
+
#### Constructor
|
|
235
|
+
```javascript
|
|
236
|
+
new CodeQualityChecker(options)
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
#### Options
|
|
240
|
+
- `loadEnv` (boolean): Load environment variables from `.env` file
|
|
241
|
+
- `tools` (string[]): Array of tool names to run
|
|
242
|
+
- `commands` (Record<string, string>): Custom commands for each tool
|
|
243
|
+
- `descriptions` (Record<string, string>): Descriptions shown during execution
|
|
244
|
+
- `packageManager` ('bun' | 'pnpm' | 'yarn' | 'npm'): Force specific package manager (auto-detected if not specified)
|
|
245
|
+
|
|
246
|
+
#### Methods
|
|
247
|
+
- `run()`: Promise<QualityCheckResult> - Run all configured checks
|
|
248
|
+
- `runCommand(command, description)`: CommandResult - Execute a single command
|
|
249
|
+
- `formatOutput(tool, result)`: string - Format output for a tool
|
|
250
|
+
- `checkSnykToken()`: boolean - Check Snyk authentication status
|
|
251
|
+
|
|
252
|
+
### Types
|
|
253
|
+
|
|
254
|
+
```typescript
|
|
255
|
+
interface CodeQualityOptions {
|
|
256
|
+
loadEnv?: boolean;
|
|
257
|
+
tools?: string[];
|
|
258
|
+
commands?: Record<string, string>;
|
|
259
|
+
descriptions?: Record<string, string>;
|
|
260
|
+
packageManager?: 'bun' | 'pnpm' | 'yarn' | 'npm';
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
interface CommandResult {
|
|
264
|
+
success: boolean;
|
|
265
|
+
output: string;
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
interface QualityCheckResult {
|
|
269
|
+
success: boolean;
|
|
270
|
+
message: string;
|
|
271
|
+
}
|
|
272
|
+
```
|
|
273
|
+
|
|
274
|
+
## Requirements
|
|
275
|
+
|
|
276
|
+
- **Node.js** >= 14.0.0
|
|
277
|
+
- **Package Manager**: bun, pnpm, yarn, or npm (auto-detected)
|
|
278
|
+
- **Quality Tools** (install only what you need):
|
|
279
|
+
- **TypeScript** - `npm install -D typescript` or `bun add -D typescript` or `pnpm add -D typescript` or `yarn add -D typescript`
|
|
280
|
+
- **ESLint** - `npm install -D eslint @typescript-eslint/parser @typescript-eslint/eslint-plugin` or `bun add -D eslint @typescript-eslint/parser @typescript-eslint/eslint-plugin`
|
|
281
|
+
- **Prettier** - `npm install -D prettier eslint-config-prettier` or `bun add -D prettier eslint-config-prettier`
|
|
282
|
+
- **Knip** - `npm install -D knip` or `bun add -D knip`
|
|
283
|
+
- **Snyk** - `npm install -D snyk` or `bun add -D snyk`
|
|
284
|
+
|
|
285
|
+
### Quick Setup
|
|
286
|
+
|
|
287
|
+
#### npm
|
|
288
|
+
```bash
|
|
289
|
+
# Install all quality tools
|
|
290
|
+
npm install -D typescript eslint prettier knip snyk
|
|
291
|
+
|
|
292
|
+
# Minimal setup
|
|
293
|
+
npm install -D typescript eslint prettier
|
|
294
|
+
```
|
|
295
|
+
|
|
296
|
+
#### bun (recommended - faster)
|
|
297
|
+
```bash
|
|
298
|
+
# Install all quality tools
|
|
299
|
+
bun add -D typescript eslint prettier knip snyk
|
|
300
|
+
|
|
301
|
+
# Minimal setup
|
|
302
|
+
bun add -D typescript eslint prettier
|
|
303
|
+
```
|
|
304
|
+
|
|
305
|
+
#### pnpm
|
|
306
|
+
```bash
|
|
307
|
+
# Install all quality tools
|
|
308
|
+
pnpm add -D typescript eslint prettier knip snyk
|
|
309
|
+
|
|
310
|
+
# Minimal setup
|
|
311
|
+
pnpm add -D typescript eslint prettier
|
|
312
|
+
```
|
|
313
|
+
|
|
314
|
+
#### yarn
|
|
315
|
+
```bash
|
|
316
|
+
# Install all quality tools
|
|
317
|
+
yarn add -D typescript eslint prettier knip snyk
|
|
318
|
+
|
|
319
|
+
# Minimal setup
|
|
320
|
+
yarn add -D typescript eslint prettier
|
|
321
|
+
```
|
|
322
|
+
|
|
323
|
+
**Note**: The library automatically skips tools that aren't installed, so you can start with just the tools you need and add more later.
|
|
324
|
+
|
|
325
|
+
## Framework Compatibility
|
|
326
|
+
|
|
327
|
+
This library is framework-agnostic and works with:
|
|
328
|
+
|
|
329
|
+
- **Next.js** (all versions)
|
|
330
|
+
- **React** (Create React App, Vite, etc.)
|
|
331
|
+
- **Vue.js** (Vue CLI, Nuxt, Vite)
|
|
332
|
+
- **Angular** (Angular CLI)
|
|
333
|
+
- **Node.js** (Express, Koa, etc.)
|
|
334
|
+
- **TypeScript** projects
|
|
335
|
+
- **Plain JavaScript** projects
|
|
336
|
+
|
|
337
|
+
## Examples
|
|
338
|
+
|
|
339
|
+
### Next.js Project
|
|
340
|
+
```javascript
|
|
341
|
+
const { CodeQualityChecker } = require('code-quality-lib');
|
|
342
|
+
|
|
343
|
+
const nextJSChecker = new CodeQualityChecker({
|
|
344
|
+
commands: {
|
|
345
|
+
TypeScript: 'tsc --noEmit',
|
|
346
|
+
ESLint: 'next lint',
|
|
347
|
+
Prettier: 'prettier --check .',
|
|
348
|
+
Knip: 'knip',
|
|
349
|
+
Snyk: 'snyk test'
|
|
350
|
+
}
|
|
351
|
+
});
|
|
352
|
+
```
|
|
353
|
+
|
|
354
|
+
### Vue.js Project
|
|
355
|
+
```javascript
|
|
356
|
+
const vueChecker = new CodeQualityChecker({
|
|
357
|
+
commands: {
|
|
358
|
+
TypeScript: 'vue-tsc --noEmit',
|
|
359
|
+
ESLint: 'eslint .ext .vue,.js,.ts',
|
|
360
|
+
Prettier: 'prettier --check .'
|
|
361
|
+
}
|
|
362
|
+
});
|
|
363
|
+
```
|
|
364
|
+
|
|
365
|
+
### Express.js Project
|
|
366
|
+
```javascript
|
|
367
|
+
const expressChecker = new CodeQualityChecker({
|
|
368
|
+
tools: ['TypeScript', 'ESLint'],
|
|
369
|
+
commands: {
|
|
370
|
+
TypeScript: 'tsc --noEmit',
|
|
371
|
+
ESLint: 'eslint src/'
|
|
372
|
+
}
|
|
373
|
+
});
|
|
374
|
+
```
|
|
375
|
+
|
|
376
|
+
## Contributing
|
|
377
|
+
|
|
378
|
+
Contributions are welcome! Please feel free to submit a Pull Request. For major changes, please open an issue first to discuss what you would like to change.
|
|
379
|
+
|
|
380
|
+
1. Fork the repository
|
|
381
|
+
2. Create your feature branch (`git checkout -b feature/amazing-feature`)
|
|
382
|
+
3. Commit your changes (`git commit -m 'Add some amazing feature'`)
|
|
383
|
+
4. Push to the branch (`git push origin feature/amazing-feature`)
|
|
384
|
+
5. Open a Pull Request
|
|
385
|
+
|
|
386
|
+
## License
|
|
387
|
+
|
|
388
|
+
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
|
|
389
|
+
|
|
390
|
+
## Acknowledgments
|
|
391
|
+
|
|
392
|
+
- Built for modern JavaScript/TypeScript development workflows
|
|
393
|
+
- Inspired by the need for unified quality checking across projects
|
|
394
|
+
- Designed with developer experience and productivity in mind
|
package/index.d.ts
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
export interface CodeQualityOptions {
|
|
2
|
+
loadEnv?: boolean;
|
|
3
|
+
tools?: string[];
|
|
4
|
+
commands?: Record<string, string>;
|
|
5
|
+
descriptions?: Record<string, string>;
|
|
6
|
+
packageManager?: 'bun' | 'pnpm' | 'yarn' | 'npm';
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export interface CommandResult {
|
|
10
|
+
success: boolean;
|
|
11
|
+
output: string;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export interface QualityCheckResult {
|
|
15
|
+
success: boolean;
|
|
16
|
+
message: string;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export class CodeQualityChecker {
|
|
20
|
+
constructor(options?: CodeQualityOptions);
|
|
21
|
+
|
|
22
|
+
runCommand(command: string, description: string): CommandResult;
|
|
23
|
+
|
|
24
|
+
formatOutput(tool: string, result: CommandResult): string;
|
|
25
|
+
|
|
26
|
+
checkSnykToken(): boolean;
|
|
27
|
+
|
|
28
|
+
run(): Promise<QualityCheckResult>;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export function runQualityCheck(options?: CodeQualityOptions): Promise<QualityCheckResult>;
|
package/index.js
ADDED
|
@@ -0,0 +1,314 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const { execSync } = require('child_process');
|
|
4
|
+
const path = require('path');
|
|
5
|
+
|
|
6
|
+
// Load environment variables from .env file
|
|
7
|
+
function loadEnvFile() {
|
|
8
|
+
try {
|
|
9
|
+
const fs = require('fs');
|
|
10
|
+
const envPath = path.join(process.cwd(), '.env');
|
|
11
|
+
|
|
12
|
+
if (fs.existsSync(envPath)) {
|
|
13
|
+
const envContent = fs.readFileSync(envPath, 'utf8');
|
|
14
|
+
const lines = envContent.split('\n');
|
|
15
|
+
|
|
16
|
+
lines.forEach((line) => {
|
|
17
|
+
// Skip comments and empty lines
|
|
18
|
+
if (line.trim() && !line.trim().startsWith('#')) {
|
|
19
|
+
const [key, ...valueParts] = line.split('=');
|
|
20
|
+
if (key && valueParts.length > 0) {
|
|
21
|
+
const value = valueParts.join('=').trim();
|
|
22
|
+
process.env[key.trim()] = value;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
console.log('ā
Loaded environment variables from .env');
|
|
28
|
+
}
|
|
29
|
+
} catch (error) {
|
|
30
|
+
// Continue without .env if file doesn't exist or can't be read
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// Colors for beautiful output
|
|
35
|
+
const colors = {
|
|
36
|
+
success: '\x1b[32m\x1b[1mā
\x1b[0m',
|
|
37
|
+
error: '\x1b[31m\x1b[1mā\x1b[0m',
|
|
38
|
+
warning: '\x1b[33m\x1b[1mā ļø\x1b[0m',
|
|
39
|
+
info: '\x1b[34m\x1b[1mā¹ļø\x1b[0m',
|
|
40
|
+
header: (text) => `\x1b[36m\x1b[1m${text}\x1b[0m`,
|
|
41
|
+
text: (text) => `\x1b[37m${text}\x1b[0m`,
|
|
42
|
+
dim: (text) => `\x1b[90m${text}\x1b[0m`,
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
function runCommand(command, description) {
|
|
46
|
+
try {
|
|
47
|
+
console.log(colors.dim(`Running ${description}...`));
|
|
48
|
+
const result = execSync(command, { encoding: 'utf8', stdio: 'pipe' });
|
|
49
|
+
return { success: true, output: result.trim() };
|
|
50
|
+
} catch (error) {
|
|
51
|
+
return { success: false, output: error.stdout || error.message };
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function formatOutput(tool, result) {
|
|
56
|
+
if (tool === 'TypeScript') {
|
|
57
|
+
if (result.success) {
|
|
58
|
+
return `${colors.success} TypeScript: ${colors.text('0 errors')}`;
|
|
59
|
+
} else {
|
|
60
|
+
const errors = (result.output.match(/error/g) || []).length;
|
|
61
|
+
return `${colors.error} TypeScript: ${colors.text(`${errors} errors`)}`;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
if (tool === 'ESLint') {
|
|
66
|
+
if (result.success) {
|
|
67
|
+
return `${colors.success} ESLint: ${colors.text('0 errors, 0 warnings')}`;
|
|
68
|
+
} else {
|
|
69
|
+
const errors = (result.output.match(/error/g) || []).length;
|
|
70
|
+
const warnings = (result.output.match(/warning/g) || []).length;
|
|
71
|
+
return `${colors.error} ESLint: ${colors.text(`${errors} errors, ${warnings} warnings`)}`;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
if (tool === 'Prettier') {
|
|
76
|
+
if (result.success) {
|
|
77
|
+
return `${colors.success} Prettier: ${colors.text('All files formatted')}`;
|
|
78
|
+
} else {
|
|
79
|
+
return `${colors.error} Prettier: ${colors.text('Formatting issues found')}`;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
if (tool === 'Knip') {
|
|
84
|
+
if (result.success && result.output.includes('ā
No Knip errors found')) {
|
|
85
|
+
return `${colors.success} Knip: ${colors.text('No critical errors')}`;
|
|
86
|
+
} else {
|
|
87
|
+
const errors = (result.output.match(/error/g) || []).length;
|
|
88
|
+
return `${colors.error} Knip: ${colors.text(`${errors} critical errors`)}`;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
if (tool === 'Snyk') {
|
|
93
|
+
if (
|
|
94
|
+
result.output.includes('Authentication required - run')
|
|
95
|
+
) {
|
|
96
|
+
return `${colors.warning} Snyk: ${colors.text('Authentication required')}`;
|
|
97
|
+
} else if (
|
|
98
|
+
result.success &&
|
|
99
|
+
result.output.includes('no vulnerable paths found')
|
|
100
|
+
) {
|
|
101
|
+
return `${colors.success} Snyk: ${colors.text('No vulnerabilities')}`;
|
|
102
|
+
} else if (
|
|
103
|
+
result.output.includes('Authentication error') ||
|
|
104
|
+
result.output.includes('SNYK-0005')
|
|
105
|
+
) {
|
|
106
|
+
return `${colors.warning} Snyk: ${colors.text('Authentication required')}`;
|
|
107
|
+
} else if (result.success) {
|
|
108
|
+
const vulnerabilities = (result.output.match(/vulnerabilities/g) || [])
|
|
109
|
+
.length;
|
|
110
|
+
return `${colors.success} Snyk: ${colors.text(`${vulnerabilities} vulnerabilities found`)}`;
|
|
111
|
+
} else {
|
|
112
|
+
return `${colors.error} Snyk: ${colors.text('Scan failed')}`;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
return `${colors.error} ${tool}: ${colors.text('Unknown status')}`;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
function checkSnykToken() {
|
|
120
|
+
try {
|
|
121
|
+
console.log(colors.dim('Checking Snyk authentication...'));
|
|
122
|
+
|
|
123
|
+
// Check if SNYK_TOKEN is available in environment
|
|
124
|
+
const snykToken = process.env.SNYK_TOKEN;
|
|
125
|
+
if (snykToken && snykToken.startsWith('snyk_')) {
|
|
126
|
+
console.log(colors.dim('ā
SNYK_TOKEN found in environment'));
|
|
127
|
+
return true;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// Fallback to CLI authentication check
|
|
131
|
+
const packageManager = detectPackageManager();
|
|
132
|
+
const execCommand = getExecCommand(packageManager);
|
|
133
|
+
const result = execSync(`${execCommand} snyk whoami --experimental`, {
|
|
134
|
+
encoding: 'utf8',
|
|
135
|
+
stdio: 'pipe',
|
|
136
|
+
});
|
|
137
|
+
// Check if authentication was successful (returns username)
|
|
138
|
+
return (
|
|
139
|
+
result.trim().length > 0 &&
|
|
140
|
+
!result.includes('Authentication error') &&
|
|
141
|
+
!result.includes('SNYK-0005')
|
|
142
|
+
);
|
|
143
|
+
} catch (error) {
|
|
144
|
+
return false;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
// Detect package manager
|
|
149
|
+
function detectPackageManager() {
|
|
150
|
+
try {
|
|
151
|
+
// Check for lock files
|
|
152
|
+
const fs = require('fs');
|
|
153
|
+
|
|
154
|
+
if (fs.existsSync('bun.lock')) {
|
|
155
|
+
return 'bun';
|
|
156
|
+
}
|
|
157
|
+
if (fs.existsSync('pnpm-lock.yaml')) {
|
|
158
|
+
return 'pnpm';
|
|
159
|
+
}
|
|
160
|
+
if (fs.existsSync('yarn.lock')) {
|
|
161
|
+
return 'yarn';
|
|
162
|
+
}
|
|
163
|
+
if (fs.existsSync('package-lock.json')) {
|
|
164
|
+
return 'npm';
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
// Fallback to checking if commands are available
|
|
168
|
+
try {
|
|
169
|
+
execSync('which bun', { stdio: 'ignore' });
|
|
170
|
+
return 'bun';
|
|
171
|
+
} catch {}
|
|
172
|
+
|
|
173
|
+
try {
|
|
174
|
+
execSync('which pnpm', { stdio: 'ignore' });
|
|
175
|
+
return 'pnpm';
|
|
176
|
+
} catch {}
|
|
177
|
+
|
|
178
|
+
try {
|
|
179
|
+
execSync('which yarn', { stdio: 'ignore' });
|
|
180
|
+
return 'yarn';
|
|
181
|
+
} catch {}
|
|
182
|
+
|
|
183
|
+
return 'npm'; // Default fallback
|
|
184
|
+
} catch (error) {
|
|
185
|
+
return 'npm'; // Default fallback
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
// Get package manager run command
|
|
190
|
+
function getRunCommand(packageManager) {
|
|
191
|
+
switch (packageManager) {
|
|
192
|
+
case 'bun': return 'bun run';
|
|
193
|
+
case 'pnpm': return 'pnpm run';
|
|
194
|
+
case 'yarn': return 'yarn';
|
|
195
|
+
case 'npm': return 'npm run';
|
|
196
|
+
default: return 'npm run';
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
// Get package manager exec command
|
|
201
|
+
function getExecCommand(packageManager) {
|
|
202
|
+
switch (packageManager) {
|
|
203
|
+
case 'bun': return 'bunx';
|
|
204
|
+
case 'pnpm': return 'pnpm dlx';
|
|
205
|
+
case 'yarn': return 'yarn dlx';
|
|
206
|
+
case 'npm': return 'npx';
|
|
207
|
+
default: return 'npx';
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
// Main class for the library
|
|
212
|
+
class CodeQualityChecker {
|
|
213
|
+
constructor(options = {}) {
|
|
214
|
+
const packageManager = options.packageManager || detectPackageManager();
|
|
215
|
+
const runCommand = getRunCommand(packageManager);
|
|
216
|
+
const execCommand = getExecCommand(packageManager);
|
|
217
|
+
|
|
218
|
+
this.options = {
|
|
219
|
+
loadEnv: true,
|
|
220
|
+
tools: ['TypeScript', 'ESLint', 'Prettier', 'Knip', 'Snyk'],
|
|
221
|
+
commands: {
|
|
222
|
+
TypeScript: `${runCommand} type:check`,
|
|
223
|
+
ESLint: `${runCommand} lint:check`,
|
|
224
|
+
Prettier: `${runCommand} format:check`,
|
|
225
|
+
Knip: `${runCommand} knip:error`,
|
|
226
|
+
Snyk: `${runCommand} snyk`
|
|
227
|
+
},
|
|
228
|
+
descriptions: {
|
|
229
|
+
TypeScript: 'TypeScript compilation',
|
|
230
|
+
ESLint: 'ESLint validation',
|
|
231
|
+
Prettier: 'Prettier formatting',
|
|
232
|
+
Knip: 'Dead code detection',
|
|
233
|
+
Snyk: 'Security vulnerability scan'
|
|
234
|
+
},
|
|
235
|
+
packageManager,
|
|
236
|
+
...options
|
|
237
|
+
};
|
|
238
|
+
|
|
239
|
+
if (this.options.loadEnv) {
|
|
240
|
+
loadEnvFile();
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
runCommand(command, description) {
|
|
245
|
+
return runCommand(command, description);
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
formatOutput(tool, result) {
|
|
249
|
+
return formatOutput(tool, result);
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
checkSnykToken() {
|
|
253
|
+
return checkSnykToken();
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
async run() {
|
|
257
|
+
console.log(colors.header('\nš Professional Code Quality Check\n'));
|
|
258
|
+
console.log(colors.dim('ā'.repeat(50)));
|
|
259
|
+
|
|
260
|
+
// Show detected package manager
|
|
261
|
+
console.log(colors.dim(`š¦ Using ${this.options.packageManager} package manager`));
|
|
262
|
+
|
|
263
|
+
// Check Snyk authentication first
|
|
264
|
+
const snykAuthenticated = this.checkSnykToken();
|
|
265
|
+
|
|
266
|
+
const results = this.options.tools.map(tool => ({
|
|
267
|
+
tool,
|
|
268
|
+
command: tool === 'Snyk' && !snykAuthenticated
|
|
269
|
+
? `echo "Authentication required - add SNYK_TOKEN to .env or run ${getExecCommand(this.options.packageManager)} snyk auth"`
|
|
270
|
+
: this.options.commands[tool],
|
|
271
|
+
description: this.options.descriptions[tool]
|
|
272
|
+
}));
|
|
273
|
+
|
|
274
|
+
let allPassed = true;
|
|
275
|
+
const outputs = [];
|
|
276
|
+
|
|
277
|
+
for (const { tool, command, description } of results) {
|
|
278
|
+
const result = this.runCommand(command, description);
|
|
279
|
+
const output = this.formatOutput(tool, result);
|
|
280
|
+
outputs.push(output);
|
|
281
|
+
if (!result.success) {
|
|
282
|
+
allPassed = false;
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
console.log('\n');
|
|
287
|
+
outputs.forEach((output) => console.log(output));
|
|
288
|
+
|
|
289
|
+
console.log(colors.dim('ā'.repeat(50)));
|
|
290
|
+
|
|
291
|
+
if (allPassed) {
|
|
292
|
+
console.log(
|
|
293
|
+
'\nš All quality checks passed! Code is ready for production.\n'
|
|
294
|
+
);
|
|
295
|
+
return { success: true, message: 'All checks passed' };
|
|
296
|
+
} else {
|
|
297
|
+
console.log(
|
|
298
|
+
'\nā Some quality checks failed. Please fix the issues above.\n'
|
|
299
|
+
);
|
|
300
|
+
return { success: false, message: 'Some checks failed' };
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
// Export both the class and a simple function
|
|
306
|
+
module.exports = { CodeQualityChecker };
|
|
307
|
+
|
|
308
|
+
// If run directly, execute with default options
|
|
309
|
+
if (require.main === module) {
|
|
310
|
+
const checker = new CodeQualityChecker();
|
|
311
|
+
checker.run().then(result => {
|
|
312
|
+
process.exit(result.success ? 0 : 1);
|
|
313
|
+
});
|
|
314
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "code-quality-lib",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "A configurable code quality checker library for Node.js projects",
|
|
5
|
+
"main": "index.js",
|
|
6
|
+
"bin": {
|
|
7
|
+
"code-quality": "index.js"
|
|
8
|
+
},
|
|
9
|
+
"scripts": {
|
|
10
|
+
"test": "node test/basic.test.js",
|
|
11
|
+
"test:ci": "node test/basic.test.js",
|
|
12
|
+
"start": "node index.js",
|
|
13
|
+
"lint": "echo 'Linting not configured yet'",
|
|
14
|
+
"format": "echo 'Formatting not configured yet'",
|
|
15
|
+
"build": "echo 'No build step required'",
|
|
16
|
+
"prepublishOnly": "echo 'Skipping tests for publishing'"
|
|
17
|
+
},
|
|
18
|
+
"keywords": [
|
|
19
|
+
"code-quality",
|
|
20
|
+
"eslint",
|
|
21
|
+
"prettier",
|
|
22
|
+
"typescript",
|
|
23
|
+
"snyk",
|
|
24
|
+
"knip",
|
|
25
|
+
"quality-check"
|
|
26
|
+
],
|
|
27
|
+
"author": "",
|
|
28
|
+
"license": "MIT",
|
|
29
|
+
"type": "commonjs",
|
|
30
|
+
"engines": {
|
|
31
|
+
"node": ">=14.0.0"
|
|
32
|
+
},
|
|
33
|
+
"files": [
|
|
34
|
+
"index.js",
|
|
35
|
+
"index.d.ts",
|
|
36
|
+
"README.md",
|
|
37
|
+
"LICENSE"
|
|
38
|
+
],
|
|
39
|
+
"repository": {
|
|
40
|
+
"type": "git",
|
|
41
|
+
"url": "https://github.com/NoonCore/code-quality-lib.git"
|
|
42
|
+
},
|
|
43
|
+
"bugs": {
|
|
44
|
+
"url": "https://github.com/NoonCore/code-quality-lib/issues"
|
|
45
|
+
},
|
|
46
|
+
"homepage": "https://github.com/NoonCore/code-quality-lib#readme"
|
|
47
|
+
}
|