code-quality-lib 2.0.2 → 2.6.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.
@@ -0,0 +1,311 @@
1
+ import js from '@eslint/js'
2
+ import typescript from '@typescript-eslint/eslint-plugin'
3
+ import tsParser from '@typescript-eslint/parser'
4
+ import prettier from 'eslint-config-prettier'
5
+ import importPlugin from 'eslint-plugin-import'
6
+ import react from 'eslint-plugin-react'
7
+ import reactHooks from 'eslint-plugin-react-hooks'
8
+ import sonarjs from 'eslint-plugin-sonarjs'
9
+ import unicorn from 'eslint-plugin-unicorn'
10
+
11
+ // Import optional plugins - these may or may not be installed
12
+ let nextPlugin
13
+ let jsxA11yPlugin
14
+ let prettierPlugin
15
+
16
+ try {
17
+ const nextModule = await import('eslint-plugin-next')
18
+ nextPlugin = nextModule.default || nextModule
19
+ } catch {
20
+ // Next.js plugin not installed, skip Next.js rules
21
+ }
22
+
23
+ try {
24
+ const jsxA11yModule = await import('eslint-plugin-jsx-a11y')
25
+ jsxA11yPlugin = jsxA11yModule.default || jsxA11yModule
26
+ } catch {
27
+ // jsx-a11y plugin not installed, skip accessibility rules
28
+ }
29
+
30
+ try {
31
+ const prettierModule = await import('eslint-plugin-prettier')
32
+ prettierPlugin = prettierModule.default || prettierModule
33
+ } catch {
34
+ // eslint-plugin-prettier not installed, skip prettier rules
35
+ }
36
+
37
+ const eslintConfig = [
38
+ {
39
+ ignores: [
40
+ 'node_modules/',
41
+ '.pnp',
42
+ '.pnp.js',
43
+ '.next/',
44
+ 'out/',
45
+ 'dist/',
46
+ 'build/',
47
+ '.env*',
48
+ '*.log',
49
+ 'pids',
50
+ '*.pid',
51
+ '*.seed',
52
+ '*.pid.lock',
53
+ 'coverage/',
54
+ '.nyc_output',
55
+ '.cache/',
56
+ '.parcel-cache/',
57
+ '*.tsbuildinfo',
58
+ '.DS_Store',
59
+ '.DS_Store?',
60
+ '._*',
61
+ '.Spotlight-V100',
62
+ '.Trashes',
63
+ 'ehthumbs.db',
64
+ 'Thumbs.db',
65
+ '.vscode/',
66
+ '.idea/',
67
+ 'tmp/',
68
+ 'temp/',
69
+ '*.tmp',
70
+ '*.temp',
71
+ 'public/',
72
+ '.code-quality/',
73
+ '**/.code-quality/**', // More specific pattern
74
+ 'eslint.config.mjs',
75
+ 'next.config.ts',
76
+ '.venv/',
77
+ ],
78
+ },
79
+ js.configs.recommended,
80
+ {
81
+ files: ['**/*.{js,jsx,ts,tsx}'],
82
+ languageOptions: {
83
+ parser: tsParser,
84
+ parserOptions: {
85
+ ecmaVersion: 'latest',
86
+ sourceType: 'module',
87
+ ecmaFeatures: {
88
+ jsx: true,
89
+ },
90
+ project: './tsconfig.json',
91
+ tsconfigRootDir: import.meta.dirname,
92
+ },
93
+ globals: {
94
+ console: 'readonly',
95
+ process: 'readonly',
96
+ __dirname: 'readonly',
97
+ module: 'readonly',
98
+ require: 'readonly',
99
+ // Browser globals
100
+ window: 'readonly',
101
+ document: 'readonly',
102
+ fetch: 'readonly',
103
+ setTimeout: 'readonly',
104
+ clearTimeout: 'readonly',
105
+ setInterval: 'readonly',
106
+ clearInterval: 'readonly',
107
+ requestAnimationFrame: 'readonly',
108
+ URL: 'readonly',
109
+ URLSearchParams: 'readonly',
110
+ FormData: 'readonly',
111
+ HeadersInit: 'readonly',
112
+ RequestInit: 'readonly',
113
+ TextEncoder: 'readonly',
114
+ btoa: 'readonly',
115
+ crypto: 'readonly',
116
+ sessionStorage: 'readonly',
117
+ // React globals
118
+ React: 'readonly',
119
+ // DOM types
120
+ HTMLDivElement: 'readonly',
121
+ // Node.js globals
122
+ Buffer: 'readonly',
123
+ // Type globals
124
+ Item: 'readonly',
125
+ Bundle: 'readonly',
126
+ ConstStallCategory: 'readonly',
127
+ },
128
+ },
129
+ settings: {
130
+ 'import/resolver': {
131
+ typescript: {
132
+ alwaysTryTypes: true,
133
+ project: './tsconfig.json',
134
+ },
135
+ },
136
+ },
137
+ plugins: {
138
+ '@typescript-eslint': typescript,
139
+ react,
140
+ 'react-hooks': reactHooks,
141
+ sonarjs,
142
+ unicorn,
143
+ import: importPlugin,
144
+ ...(nextPlugin ? { '@next/next': nextPlugin } : {}),
145
+ ...(jsxA11yPlugin ? { 'jsx-a11y': jsxA11yPlugin } : {}),
146
+ ...(prettierPlugin ? { prettier: prettierPlugin } : {}),
147
+ },
148
+ rules: {
149
+ // React
150
+ 'react/jsx-no-literals': 'off',
151
+ 'react/prop-types': 'off',
152
+ 'react/self-closing-comp': 'warn',
153
+ 'react/jsx-sort-props': [
154
+ 'warn',
155
+ {
156
+ callbacksLast: true,
157
+ shorthandFirst: true,
158
+ noSortAlphabetically: false,
159
+ reservedFirst: true,
160
+ },
161
+ ],
162
+ 'react/jsx-fragments': ['warn', 'syntax'],
163
+ 'react/jsx-no-useless-fragment': 'warn',
164
+ 'react/jsx-pascal-case': 'warn',
165
+ 'react/no-array-index-key': 'warn',
166
+ 'react/react-in-jsx-scope': 'off',
167
+ // JSX quotes consistency with Prettier jsxSingleQuote: true
168
+ 'jsx-quotes': ['error', 'prefer-single'],
169
+
170
+ // TypeScript
171
+ '@typescript-eslint/no-explicit-any': 'warn',
172
+ '@typescript-eslint/no-require-imports': 'off',
173
+ '@typescript-eslint/no-unused-vars': [
174
+ 'warn',
175
+ {
176
+ args: 'after-used',
177
+ ignoreRestSiblings: false,
178
+ argsIgnorePattern: '^_.*$',
179
+ },
180
+ ],
181
+ '@typescript-eslint/explicit-function-return-type': 'off',
182
+ '@typescript-eslint/explicit-module-boundary-types': 'off',
183
+ '@typescript-eslint/no-empty-interface': 'warn',
184
+ '@typescript-eslint/no-non-null-assertion': 'warn',
185
+ '@typescript-eslint/prefer-as-const': 'warn',
186
+
187
+ // Next.js (if available)
188
+ ...(nextPlugin
189
+ ? {
190
+ '@next/next/no-html-link-for-pages': 'off',
191
+ '@next/next/no-img-element': 'warn',
192
+ '@next/next/no-sync-scripts': 'warn',
193
+ }
194
+ : {}),
195
+
196
+ // Accessibility (if jsx-a11y plugin available)
197
+ ...(jsxA11yPlugin
198
+ ? {
199
+ 'jsx-a11y/alt-text': 'warn',
200
+ 'jsx-a11y/interactive-supports-focus': 'off',
201
+ 'jsx-a11y/click-events-have-key-events': 'warn',
202
+ 'jsx-a11y/no-static-element-interactions': 'warn',
203
+ }
204
+ : {}),
205
+
206
+ // Import ordering
207
+ 'import/order': [
208
+ 'error',
209
+ {
210
+ groups: [
211
+ 'type',
212
+ 'builtin',
213
+ 'external',
214
+ 'internal',
215
+ 'parent',
216
+ 'sibling',
217
+ 'index',
218
+ 'object',
219
+ ],
220
+ pathGroups: [
221
+ {
222
+ pattern: '~/**',
223
+ group: 'external',
224
+ position: 'after',
225
+ },
226
+ ],
227
+ pathGroupsExcludedImportTypes: ['builtin'],
228
+ 'newlines-between': 'always',
229
+ alphabetize: {
230
+ order: 'asc',
231
+ caseInsensitive: true,
232
+ },
233
+ },
234
+ ],
235
+ 'import/no-duplicates': 'error',
236
+ 'import/no-unresolved': 'error',
237
+ 'import/no-cycle': 'error',
238
+
239
+ // Code quality
240
+ 'no-console': ['error', { allow: ['warn', 'error'] }],
241
+ ...(prettierPlugin
242
+ ? {
243
+ 'prettier/prettier': [
244
+ 'error',
245
+ {
246
+ endOfLine: 'auto',
247
+ },
248
+ ],
249
+ }
250
+ : {}),
251
+ 'padding-line-between-statements': [
252
+ 'warn',
253
+ { blankLine: 'always', prev: '*', next: 'return' },
254
+ { blankLine: 'always', prev: ['const', 'let', 'var'], next: '*' },
255
+ {
256
+ blankLine: 'any',
257
+ prev: ['const', 'let', 'var'],
258
+ next: ['const', 'let', 'var'],
259
+ },
260
+ ],
261
+
262
+ 'react-hooks/exhaustive-deps': 'warn',
263
+ 'react-hooks/rules-of-hooks': 'error',
264
+ 'no-param-reassign': 'warn',
265
+ 'no-return-await': 'warn',
266
+ 'prefer-const': 'warn',
267
+ 'no-var': 'error',
268
+ eqeqeq: ['error', 'always'],
269
+ 'no-unused-expressions': 'error',
270
+ // Semicolons consistency with Prettier semi: false
271
+ semi: ['error', 'never'],
272
+
273
+ // SonarJS
274
+ 'sonarjs/cognitive-complexity': ['error', 15],
275
+ 'sonarjs/no-duplicate-string': 'warn',
276
+
277
+ // Unicorn
278
+ 'unicorn/no-array-for-each': 'error',
279
+ 'unicorn/prefer-node-protocol': 'error',
280
+ },
281
+ },
282
+ {
283
+ files: ['**/*.{js,jsx,ts,tsx}'],
284
+ rules: {
285
+ 'no-restricted-syntax': [
286
+ 'error',
287
+ {
288
+ selector:
289
+ "MemberExpression[object.object.name='process'][object.property.name='env'][property.type='Identifier'][property.name=/^NEXT_PUBLIC_/]",
290
+ message:
291
+ 'Do not access process.env.NEXT_PUBLIC_* directly. Use src/constants/environment.ts instead.',
292
+ },
293
+ {
294
+ selector:
295
+ "MemberExpression[object.object.name='process'][object.property.name='env'][property.type='Literal'][property.value=/^NEXT_PUBLIC_/]",
296
+ message:
297
+ 'Do not access process.env.NEXT_PUBLIC_* directly. Use src/constants/environment.ts instead.',
298
+ },
299
+ ],
300
+ },
301
+ },
302
+ {
303
+ files: ['src/constants/environment.ts'],
304
+ rules: {
305
+ 'no-restricted-syntax': 'off',
306
+ },
307
+ },
308
+ prettier,
309
+ ]
310
+
311
+ export default eslintConfig
@@ -0,0 +1,30 @@
1
+ {
2
+ "entry": ["index.js"],
3
+ "project": ["*.js"],
4
+ "ignore": [
5
+ "node_modules/**",
6
+ "dist/**",
7
+ "build/**",
8
+ "coverage/**",
9
+ "*.config.js",
10
+ "*.config.ts",
11
+ "test/**",
12
+ "**/*.test.*",
13
+ "**/*.spec.*",
14
+ "examples/**",
15
+ ".code-quality/**",
16
+ "**/*.d.ts"
17
+ ],
18
+ "ignoreBinaries": ["code-quality"],
19
+ "ignoreDependencies": [
20
+ "eslint-plugin-*",
21
+ "@typescript-eslint/*",
22
+ "@eslint/js",
23
+ "prettier",
24
+ "@types/*",
25
+ "typescript",
26
+ "knip",
27
+ "snyk",
28
+ "dotenv"
29
+ ]
30
+ }
@@ -0,0 +1,28 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2022",
4
+ "lib": ["dom", "dom.iterable", "esnext"],
5
+ "allowJs": true,
6
+ "skipLibCheck": true,
7
+ "strict": true,
8
+ "noUncheckedIndexedAccess": true,
9
+ "noImplicitOverride": true,
10
+ "noPropertyAccessFromIndexSignature": true,
11
+ "useUnknownInCatchVariables": true,
12
+ "noEmit": true,
13
+ "esModuleInterop": true,
14
+ "module": "ESNext",
15
+ "moduleResolution": "bundler",
16
+ "resolveJsonModule": true,
17
+ "isolatedModules": true,
18
+ "jsx": "react-jsx",
19
+ "incremental": true,
20
+ "forceConsistentCasingInFileNames": true,
21
+ "baseUrl": ".",
22
+ "paths": {
23
+ "@/*": ["src/*"]
24
+ }
25
+ },
26
+ "include": ["**/*.ts", "**/*.tsx", "**/*.mts"],
27
+ "exclude": ["node_modules", "dist", "build", "coverage", "examples"]
28
+ }
package/index.d.ts CHANGED
@@ -1,49 +1,60 @@
1
+ export interface EnvironmentConfig {
2
+ tools: string[]
3
+ }
4
+
1
5
  export interface CodeQualityOptions {
2
6
  /** Load environment variables from .env file (default: true) */
3
- loadEnv?: boolean;
7
+ loadEnv?: boolean
4
8
  /** Use project's own config files instead of bundled configs (default: true) */
5
- useProjectConfig?: boolean;
9
+ useProjectConfig?: boolean
6
10
  /** Array of tool names to run (default: all tools) */
7
- tools?: string[];
11
+ tools?: string[]
8
12
  /** Custom commands for each tool, keyed by tool name */
9
- commands?: Record<string, string>;
13
+ commands?: Record<string, string>
10
14
  /** Custom descriptions for each tool, keyed by tool name */
11
- descriptions?: Record<string, string>;
15
+ descriptions?: Record<string, string>
12
16
  /** Force a specific package manager (auto-detected if not specified) */
13
- packageManager?: 'bun' | 'pnpm' | 'yarn' | 'npm';
17
+ packageManager?: 'bun' | 'pnpm' | 'yarn' | 'npm'
14
18
  /** Show detailed error logs in terminal */
15
- showLogs?: boolean;
19
+ showLogs?: boolean
20
+ /** Set the active environment (default: development) */
21
+ environment?: string
22
+ /** Environment-specific tool configurations */
23
+ environments?: Record<string, EnvironmentConfig>
16
24
  }
17
25
 
18
26
  export interface CommandResult {
19
- success: boolean;
20
- output: string;
27
+ success: boolean
28
+ output: string
21
29
  }
22
30
 
23
31
  export interface CheckResult {
24
- name: string;
25
- description: string;
26
- success: boolean;
27
- output: string;
32
+ name: string
33
+ description: string
34
+ success: boolean
35
+ output: string
36
+ errors: number
37
+ warnings: number
38
+ errorLines: string[]
28
39
  }
29
40
 
30
41
  export interface QualityCheckResult {
31
- success: boolean;
32
- message: string;
33
- results: CheckResult[];
42
+ success: boolean
43
+ message: string
44
+ results: CheckResult[]
34
45
  }
35
46
 
36
47
  export class CodeQualityChecker {
37
- options: Required<Omit<CodeQualityOptions, 'showLogs'>>;
48
+ options: Required<Omit<CodeQualityOptions, 'showLogs'>>
38
49
 
39
- constructor(options?: CodeQualityOptions);
50
+ constructor(options?: CodeQualityOptions)
40
51
 
41
52
  /** Execute a single shell command and return the result */
42
- runCommand(command: string, description: string): CommandResult;
53
+ runCommand(command: string, description: string): CommandResult
43
54
 
44
55
  /** Run all configured quality checks */
45
- run(options?: { showLogs?: boolean }): Promise<QualityCheckResult>;
56
+ run(options?: { showLogs?: boolean }): Promise<QualityCheckResult>
46
57
  }
47
58
 
48
59
  /** Convenience function to run quality checks without instantiating the class */
49
- export function runQualityCheck(options?: CodeQualityOptions): Promise<QualityCheckResult>;
60
+ export function runQualityCheck(options?: CodeQualityOptions): Promise<QualityCheckResult>