@hatem427/code-guard-ci 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.
Files changed (107) hide show
  1. package/.husky/pre-commit +27 -0
  2. package/LICENSE +21 -0
  3. package/README.md +646 -0
  4. package/config/angular.config.ts +223 -0
  5. package/config/guidelines.config.ts +229 -0
  6. package/config/nextjs.config.ts +160 -0
  7. package/config/react.config.ts +330 -0
  8. package/dist/config/angular.config.d.ts +15 -0
  9. package/dist/config/angular.config.d.ts.map +1 -0
  10. package/dist/config/angular.config.js +187 -0
  11. package/dist/config/angular.config.js.map +1 -0
  12. package/dist/config/guidelines.config.d.ts +63 -0
  13. package/dist/config/guidelines.config.d.ts.map +1 -0
  14. package/dist/config/guidelines.config.js +167 -0
  15. package/dist/config/guidelines.config.js.map +1 -0
  16. package/dist/config/nextjs.config.d.ts +18 -0
  17. package/dist/config/nextjs.config.d.ts.map +1 -0
  18. package/dist/config/nextjs.config.js +133 -0
  19. package/dist/config/nextjs.config.js.map +1 -0
  20. package/dist/config/react.config.d.ts +15 -0
  21. package/dist/config/react.config.d.ts.map +1 -0
  22. package/dist/config/react.config.js +287 -0
  23. package/dist/config/react.config.js.map +1 -0
  24. package/dist/scripts/auto-fix.d.ts +16 -0
  25. package/dist/scripts/auto-fix.d.ts.map +1 -0
  26. package/dist/scripts/auto-fix.js +130 -0
  27. package/dist/scripts/auto-fix.js.map +1 -0
  28. package/dist/scripts/cli.d.ts +17 -0
  29. package/dist/scripts/cli.d.ts.map +1 -0
  30. package/dist/scripts/cli.js +255 -0
  31. package/dist/scripts/cli.js.map +1 -0
  32. package/dist/scripts/delete-bypass-logs.d.ts +17 -0
  33. package/dist/scripts/delete-bypass-logs.d.ts.map +1 -0
  34. package/dist/scripts/delete-bypass-logs.js +242 -0
  35. package/dist/scripts/delete-bypass-logs.js.map +1 -0
  36. package/dist/scripts/generate-doc.d.ts +18 -0
  37. package/dist/scripts/generate-doc.d.ts.map +1 -0
  38. package/dist/scripts/generate-doc.js +300 -0
  39. package/dist/scripts/generate-doc.js.map +1 -0
  40. package/dist/scripts/generate-pr-checklist.d.ts +20 -0
  41. package/dist/scripts/generate-pr-checklist.d.ts.map +1 -0
  42. package/dist/scripts/generate-pr-checklist.js +276 -0
  43. package/dist/scripts/generate-pr-checklist.js.map +1 -0
  44. package/dist/scripts/precommit-check.d.ts +23 -0
  45. package/dist/scripts/precommit-check.d.ts.map +1 -0
  46. package/dist/scripts/precommit-check.js +331 -0
  47. package/dist/scripts/precommit-check.js.map +1 -0
  48. package/dist/scripts/set-admin-password.d.ts +14 -0
  49. package/dist/scripts/set-admin-password.d.ts.map +1 -0
  50. package/dist/scripts/set-admin-password.js +116 -0
  51. package/dist/scripts/set-admin-password.js.map +1 -0
  52. package/dist/scripts/set-bypass-password.d.ts +11 -0
  53. package/dist/scripts/set-bypass-password.d.ts.map +1 -0
  54. package/dist/scripts/set-bypass-password.js +106 -0
  55. package/dist/scripts/set-bypass-password.js.map +1 -0
  56. package/dist/scripts/utils/auto-fixer.d.ts +28 -0
  57. package/dist/scripts/utils/auto-fixer.d.ts.map +1 -0
  58. package/dist/scripts/utils/auto-fixer.js +177 -0
  59. package/dist/scripts/utils/auto-fixer.js.map +1 -0
  60. package/dist/scripts/utils/bypass-manager.d.ts +101 -0
  61. package/dist/scripts/utils/bypass-manager.d.ts.map +1 -0
  62. package/dist/scripts/utils/bypass-manager.js +496 -0
  63. package/dist/scripts/utils/bypass-manager.js.map +1 -0
  64. package/dist/scripts/utils/code-analyzer.d.ts +34 -0
  65. package/dist/scripts/utils/code-analyzer.d.ts.map +1 -0
  66. package/dist/scripts/utils/code-analyzer.js +323 -0
  67. package/dist/scripts/utils/code-analyzer.js.map +1 -0
  68. package/dist/scripts/utils/file-checker.d.ts +93 -0
  69. package/dist/scripts/utils/file-checker.d.ts.map +1 -0
  70. package/dist/scripts/utils/file-checker.js +248 -0
  71. package/dist/scripts/utils/file-checker.js.map +1 -0
  72. package/dist/scripts/utils/logger.d.ts +26 -0
  73. package/dist/scripts/utils/logger.d.ts.map +1 -0
  74. package/dist/scripts/utils/logger.js +86 -0
  75. package/dist/scripts/utils/logger.js.map +1 -0
  76. package/dist/scripts/utils/project-detector.d.ts +34 -0
  77. package/dist/scripts/utils/project-detector.d.ts.map +1 -0
  78. package/dist/scripts/utils/project-detector.js +124 -0
  79. package/dist/scripts/utils/project-detector.js.map +1 -0
  80. package/dist/scripts/utils/rule-engine.d.ts +57 -0
  81. package/dist/scripts/utils/rule-engine.d.ts.map +1 -0
  82. package/dist/scripts/utils/rule-engine.js +158 -0
  83. package/dist/scripts/utils/rule-engine.js.map +1 -0
  84. package/dist/scripts/view-bypass-log.d.ts +13 -0
  85. package/dist/scripts/view-bypass-log.d.ts.map +1 -0
  86. package/dist/scripts/view-bypass-log.js +117 -0
  87. package/dist/scripts/view-bypass-log.js.map +1 -0
  88. package/package.json +74 -0
  89. package/scripts/auto-fix.ts +115 -0
  90. package/scripts/cli.ts +246 -0
  91. package/scripts/delete-bypass-logs.ts +253 -0
  92. package/scripts/generate-doc.ts +317 -0
  93. package/scripts/generate-pr-checklist.ts +285 -0
  94. package/scripts/precommit-check.ts +349 -0
  95. package/scripts/set-admin-password.ts +90 -0
  96. package/scripts/set-bypass-password.ts +80 -0
  97. package/scripts/utils/auto-fixer.ts +181 -0
  98. package/scripts/utils/bypass-manager.ts +566 -0
  99. package/scripts/utils/code-analyzer.ts +341 -0
  100. package/scripts/utils/file-checker.ts +253 -0
  101. package/scripts/utils/logger.ts +88 -0
  102. package/scripts/utils/project-detector.ts +115 -0
  103. package/scripts/utils/rule-engine.ts +186 -0
  104. package/scripts/view-bypass-log.ts +92 -0
  105. package/templates/feature-doc-api.md +101 -0
  106. package/templates/feature-doc-service.md +113 -0
  107. package/templates/feature-doc-ui.md +91 -0
@@ -0,0 +1,330 @@
1
+ /**
2
+ * ============================================================================
3
+ * react.config.ts — React-specific coding rules
4
+ * ============================================================================
5
+ *
6
+ * Registers rules that only apply to React projects:
7
+ * - Hook usage patterns
8
+ * - Props/state typing
9
+ * - Component patterns
10
+ * - Performance anti-patterns
11
+ */
12
+
13
+ import { registerRules, Rule } from './guidelines.config';
14
+
15
+ const reactRules: Rule[] = [
16
+ // ── Hooks ──────────────────────────────────────────────────────────────
17
+
18
+ {
19
+ id: 'react-no-useeffect-no-deps',
20
+ label: 'useEffect must have dependency array',
21
+ description:
22
+ 'Every useEffect must have a dependency array. Missing deps causes infinite re-renders or stale closures.',
23
+ severity: 'error',
24
+ fileExtensions: ['tsx', 'jsx', 'ts', 'js'],
25
+ pattern: null,
26
+ customCheck: (file) => {
27
+ const violations: Array<{ line: number | null; message: string }> = [];
28
+ const lines: string[] = file.lines;
29
+
30
+ for (let i = 0; i < lines.length; i++) {
31
+ const line = lines[i];
32
+
33
+ // Detect useEffect( without a closing bracket on subsequent lines containing dependency array
34
+ if (/useEffect\s*\(\s*\(\s*\)\s*=>\s*\{/.test(line)) {
35
+ // Look ahead for the closing of useEffect — find , [] or , [deps])
36
+ let foundDeps = false;
37
+ let parenDepth = 0;
38
+ for (let j = i; j < Math.min(i + 50, lines.length); j++) {
39
+ for (const ch of lines[j]) {
40
+ if (ch === '(') parenDepth++;
41
+ if (ch === ')') parenDepth--;
42
+ }
43
+ // Check if the dependency array is present
44
+ if (/\]\s*\)\s*;?\s*$/.test(lines[j]) || /,\s*\[/.test(lines[j])) {
45
+ foundDeps = true;
46
+ break;
47
+ }
48
+ if (parenDepth <= 0) break;
49
+ }
50
+
51
+ if (!foundDeps) {
52
+ violations.push({
53
+ line: i + 1,
54
+ message: 'useEffect without dependency array detected. Always specify dependencies.',
55
+ });
56
+ }
57
+ }
58
+ }
59
+
60
+ return violations;
61
+ },
62
+ applicableTo: ['react', 'nextjs'],
63
+ category: 'React Hooks',
64
+ },
65
+
66
+ {
67
+ id: 'react-no-inline-styles',
68
+ label: 'No inline style objects',
69
+ description:
70
+ 'Avoid inline style={{ }} in JSX. Use Tailwind classes or CSS modules for consistent styling.',
71
+ severity: 'warning',
72
+ fileExtensions: ['tsx', 'jsx'],
73
+ pattern: /style\s*=\s*\{\s*\{/g,
74
+ applicableTo: ['react', 'nextjs'],
75
+ category: 'Styling',
76
+ },
77
+
78
+ {
79
+ id: 'react-no-direct-dom',
80
+ label: 'No direct DOM manipulation',
81
+ description:
82
+ 'Avoid document.getElementById, querySelector, etc. Use useRef() and React state instead.',
83
+ severity: 'error',
84
+ fileExtensions: ['tsx', 'jsx', 'ts', 'js'],
85
+ pattern: /document\.(getElementById|querySelector|querySelectorAll|getElementsBy)/g,
86
+ applicableTo: ['react', 'nextjs'],
87
+ category: 'React Patterns',
88
+ },
89
+
90
+ // ── Component patterns ─────────────────────────────────────────────────
91
+
92
+ {
93
+ id: 'react-prefer-fc-typing',
94
+ label: 'Type component props explicitly',
95
+ description:
96
+ 'Define a Props interface/type and use it. Avoid React.FC — type props parameter directly.',
97
+ severity: 'info',
98
+ fileExtensions: ['tsx'],
99
+ pattern: /React\.FC/g,
100
+ applicableTo: ['react', 'nextjs'],
101
+ category: 'TypeScript',
102
+ },
103
+
104
+ {
105
+ id: 'react-no-prop-spreading',
106
+ label: 'Avoid prop spreading ({...props})',
107
+ description:
108
+ 'Spreading props makes component APIs unclear. Explicitly pass required props for better readability and TypeScript safety.',
109
+ severity: 'info',
110
+ fileExtensions: ['tsx', 'jsx'],
111
+ pattern: /\{\s*\.\.\.\w+\s*\}/g,
112
+ applicableTo: ['react', 'nextjs'],
113
+ category: 'React Patterns',
114
+ },
115
+
116
+ // ── Security Rules ─────────────────────────────────────────────────────
117
+
118
+ {
119
+ id: 'react-no-dangerously-set-html',
120
+ label: 'No dangerouslySetInnerHTML',
121
+ description:
122
+ 'Using dangerouslySetInnerHTML opens your app to XSS attacks. Sanitize HTML or use safe alternatives.',
123
+ severity: 'error',
124
+ fileExtensions: ['tsx', 'jsx'],
125
+ pattern: /dangerouslySetInnerHTML/g,
126
+ applicableTo: ['react', 'nextjs'],
127
+ category: 'Security',
128
+ },
129
+
130
+ {
131
+ id: 'no-eval',
132
+ label: 'No eval() usage',
133
+ description:
134
+ 'eval() allows arbitrary code execution and is a major security vulnerability. Use JSON.parse() or other safe alternatives.',
135
+ severity: 'error',
136
+ fileExtensions: ['tsx', 'jsx', 'ts', 'js'],
137
+ pattern: /\beval\s*\(/g,
138
+ applicableTo: ['react', 'nextjs'],
139
+ category: 'Security',
140
+ },
141
+
142
+ {
143
+ id: 'no-hardcoded-credentials',
144
+ label: 'No hardcoded credentials',
145
+ description:
146
+ 'Never hardcode API keys, passwords, or secrets. Use environment variables instead.',
147
+ severity: 'error',
148
+ fileExtensions: ['tsx', 'jsx', 'ts', 'js'],
149
+ pattern: null,
150
+ customCheck: (file) => {
151
+ const violations: Array<{ line: number | null; message: string }> = [];
152
+ const lines = file.lines;
153
+ const suspiciousPatterns = [
154
+ /password\s*[=:]\s*["'`][^"'`]+["'`]/i,
155
+ /apikey\s*[=:]\s*["'`][^"'`]+["'`]/i,
156
+ /api_key\s*[=:]\s*["'`][^"'`]+["'`]/i,
157
+ /secret\s*[=:]\s*["'`][^"'`]+["'`]/i,
158
+ /token\s*[=:]\s*["'`][^"'`]{20,}["'`]/i,
159
+ ];
160
+
161
+ for (let i = 0; i < lines.length; i++) {
162
+ const line = lines[i];
163
+ for (const pattern of suspiciousPatterns) {
164
+ if (pattern.test(line)) {
165
+ violations.push({
166
+ line: i + 1,
167
+ message: `Potential hardcoded credential detected. Use environment variables: process.env.API_KEY`,
168
+ });
169
+ break;
170
+ }
171
+ }
172
+ }
173
+
174
+ return violations;
175
+ },
176
+ applicableTo: ['react', 'nextjs', 'angular'],
177
+ category: 'Security',
178
+ },
179
+
180
+ {
181
+ id: 'require-https',
182
+ label: 'Require HTTPS URLs',
183
+ description:
184
+ 'HTTP URLs are insecure. Always use HTTPS for API calls and external resources.',
185
+ severity: 'warning',
186
+ fileExtensions: ['tsx', 'jsx', 'ts', 'js'],
187
+ pattern: /['"`]http:\/\/(?!localhost|127\.0\.0\.1)/g,
188
+ applicableTo: ['react', 'nextjs', 'angular'],
189
+ category: 'Security',
190
+ },
191
+
192
+ // ── Performance Rules ──────────────────────────────────────────────────
193
+
194
+ {
195
+ id: 'react-no-anonymous-functions-in-render',
196
+ label: 'No anonymous functions in JSX',
197
+ description:
198
+ 'Anonymous functions in JSX props cause unnecessary re-renders. Use useCallback or define functions outside render.',
199
+ severity: 'warning',
200
+ fileExtensions: ['tsx', 'jsx'],
201
+ pattern: /onClick\s*=\s*\{\s*\(\s*\)\s*=>/g,
202
+ applicableTo: ['react', 'nextjs'],
203
+ category: 'Performance',
204
+ },
205
+
206
+ {
207
+ id: 'react-missing-key-prop',
208
+ label: 'Missing key prop in list',
209
+ description:
210
+ 'When rendering lists with .map(), always provide a unique key prop for optimal reconciliation.',
211
+ severity: 'error',
212
+ fileExtensions: ['tsx', 'jsx'],
213
+ pattern: null,
214
+ customCheck: (file) => {
215
+ const violations: Array<{ line: number | null; message: string }> = [];
216
+ const lines = file.lines;
217
+
218
+ for (let i = 0; i < lines.length; i++) {
219
+ const line = lines[i];
220
+ // Detect .map( with JSX but no key prop nearby
221
+ if (/\.\s*map\s*\(/.test(line)) {
222
+ // Look ahead for JSX opening tag
223
+ let foundKey = false;
224
+ for (let j = i; j < Math.min(i + 10, lines.length); j++) {
225
+ if (/key\s*=/.test(lines[j])) {
226
+ foundKey = true;
227
+ break;
228
+ }
229
+ }
230
+
231
+ // Check if there's JSX in the map
232
+ let hasJsx = false;
233
+ for (let j = i; j < Math.min(i + 10, lines.length); j++) {
234
+ if (/<[A-Z]/.test(lines[j]) || /<[a-z]/.test(lines[j])) {
235
+ hasJsx = true;
236
+ break;
237
+ }
238
+ }
239
+
240
+ if (hasJsx && !foundKey) {
241
+ violations.push({
242
+ line: i + 1,
243
+ message: 'List items rendered with .map() must have a key prop',
244
+ });
245
+ }
246
+ }
247
+ }
248
+
249
+ return violations;
250
+ },
251
+ applicableTo: ['react', 'nextjs'],
252
+ category: 'Performance',
253
+ },
254
+
255
+ {
256
+ id: 'no-large-bundle-imports',
257
+ label: 'Avoid large library imports',
258
+ description:
259
+ 'Importing entire lodash or moment.js increases bundle size. Use specific imports: import get from "lodash/get"',
260
+ severity: 'warning',
261
+ fileExtensions: ['tsx', 'jsx', 'ts', 'js'],
262
+ pattern: /import\s+(?:(?:\*\s+as\s+\w+)|(?:\{\s*[^}]{50,}\s*\}))\s+from\s+['"](?:lodash|moment)['"];?$/gm,
263
+ applicableTo: ['react', 'nextjs', 'angular'],
264
+ category: 'Performance',
265
+ },
266
+
267
+ // ── Accessibility Rules ────────────────────────────────────────────────
268
+
269
+ {
270
+ id: 'require-alt-text',
271
+ label: 'Images must have alt text',
272
+ description:
273
+ 'All <img> tags must have alt attribute for accessibility. Use empty alt="" for decorative images.',
274
+ severity: 'error',
275
+ fileExtensions: ['tsx', 'jsx'],
276
+ pattern: null,
277
+ customCheck: (file) => {
278
+ const violations: Array<{ line: number | null; message: string }> = [];
279
+ const lines = file.lines;
280
+
281
+ for (let i = 0; i < lines.length; i++) {
282
+ const line = lines[i];
283
+ // Match <img without alt or with empty src
284
+ if (/<img\b/.test(line) && !/alt\s*=/.test(line)) {
285
+ violations.push({
286
+ line: i + 1,
287
+ message: '<img> tag must have alt attribute for accessibility',
288
+ });
289
+ }
290
+ }
291
+
292
+ return violations;
293
+ },
294
+ applicableTo: ['react', 'nextjs'],
295
+ category: 'Accessibility',
296
+ },
297
+
298
+ {
299
+ id: 'require-button-type',
300
+ label: 'Buttons must have type attribute',
301
+ description:
302
+ 'Always specify type="button", type="submit", or type="reset" on <button> elements to avoid unexpected form submissions.',
303
+ severity: 'warning',
304
+ fileExtensions: ['tsx', 'jsx'],
305
+ pattern: null,
306
+ customCheck: (file) => {
307
+ const violations: Array<{ line: number | null; message: string }> = [];
308
+ const lines = file.lines;
309
+
310
+ for (let i = 0; i < lines.length; i++) {
311
+ const line = lines[i];
312
+ if (/<button\b/.test(line) && !/type\s*=/.test(line)) {
313
+ violations.push({
314
+ line: i + 1,
315
+ message: '<button> should have explicit type attribute',
316
+ });
317
+ }
318
+ }
319
+
320
+ return violations;
321
+ },
322
+ applicableTo: ['react', 'nextjs'],
323
+ category: 'Accessibility',
324
+ },
325
+ ];
326
+
327
+ // Register all React-specific rules
328
+ registerRules('react', reactRules);
329
+
330
+ export { reactRules };
@@ -0,0 +1,15 @@
1
+ /**
2
+ * ============================================================================
3
+ * angular.config.ts — Angular-specific coding rules
4
+ * ============================================================================
5
+ *
6
+ * Registers rules that only apply to Angular projects:
7
+ * - ngOnInit misuse
8
+ * - Deprecated APIs (::ng-deep, CommonModule, ngClass, ngStyle)
9
+ * - Function calls in templates
10
+ * - RxJS best practices (async pipe, takeUntilDestroyed, signals)
11
+ */
12
+ import { Rule } from './guidelines.config';
13
+ declare const angularRules: Rule[];
14
+ export { angularRules };
15
+ //# sourceMappingURL=angular.config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"angular.config.d.ts","sourceRoot":"","sources":["../../config/angular.config.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAiB,IAAI,EAAE,MAAM,qBAAqB,CAAC;AAE1D,QAAA,MAAM,YAAY,EAAE,IAAI,EA2MvB,CAAC;AAKF,OAAO,EAAE,YAAY,EAAE,CAAC"}
@@ -0,0 +1,187 @@
1
+ "use strict";
2
+ /**
3
+ * ============================================================================
4
+ * angular.config.ts — Angular-specific coding rules
5
+ * ============================================================================
6
+ *
7
+ * Registers rules that only apply to Angular projects:
8
+ * - ngOnInit misuse
9
+ * - Deprecated APIs (::ng-deep, CommonModule, ngClass, ngStyle)
10
+ * - Function calls in templates
11
+ * - RxJS best practices (async pipe, takeUntilDestroyed, signals)
12
+ */
13
+ Object.defineProperty(exports, "__esModule", { value: true });
14
+ exports.angularRules = void 0;
15
+ const guidelines_config_1 = require("./guidelines.config");
16
+ const angularRules = [
17
+ // ── Lifecycle ──────────────────────────────────────────────────────────
18
+ {
19
+ id: 'angular-no-ngoninit',
20
+ label: 'Avoid ngOnInit for simple initialization',
21
+ description: 'Prefer constructor injection and field initializers. Use ngOnInit only when you need DOM access or @Input values. Modern Angular recommends inject() + signals.',
22
+ severity: 'warning',
23
+ fileExtensions: ['ts'],
24
+ pattern: /ngOnInit\s*\(\s*\)/g,
25
+ applicableTo: ['angular'],
26
+ category: 'Angular Lifecycle',
27
+ },
28
+ // ── Deprecated APIs ────────────────────────────────────────────────────
29
+ {
30
+ id: 'angular-no-ng-deep',
31
+ label: 'No ::ng-deep',
32
+ description: '::ng-deep is deprecated. Use :host, CSS custom properties, or component styling APIs instead.',
33
+ severity: 'error',
34
+ fileExtensions: ['css', 'scss', 'sass', 'less', 'ts'],
35
+ pattern: /::ng-deep/g,
36
+ applicableTo: ['angular'],
37
+ category: 'Angular Deprecated APIs',
38
+ },
39
+ {
40
+ id: 'angular-no-common-module',
41
+ label: 'No CommonModule import in standalone components',
42
+ description: 'Standalone components should import specific directives (NgIf, NgFor, etc.) instead of the entire CommonModule. Better yet, use @if/@for control flow.',
43
+ severity: 'warning',
44
+ fileExtensions: ['ts'],
45
+ pattern: /CommonModule/g,
46
+ applicableTo: ['angular'],
47
+ category: 'Angular Deprecated APIs',
48
+ },
49
+ {
50
+ id: 'angular-no-ngclass',
51
+ label: 'No [ngClass] — use [class] binding or Tailwind',
52
+ description: 'Prefer [class.name]="condition" binding or Tailwind dynamic classes over [ngClass]. It is cleaner and more performant.',
53
+ severity: 'warning',
54
+ fileExtensions: ['html', 'ts'],
55
+ pattern: /\[ngClass\]/g,
56
+ applicableTo: ['angular'],
57
+ category: 'Angular Deprecated APIs',
58
+ },
59
+ {
60
+ id: 'angular-no-ngstyle',
61
+ label: 'No [ngStyle] — use [style] binding or Tailwind',
62
+ description: 'Prefer [style.property]="value" binding or Tailwind utilities over [ngStyle].',
63
+ severity: 'warning',
64
+ fileExtensions: ['html', 'ts'],
65
+ pattern: /\[ngStyle\]/g,
66
+ applicableTo: ['angular'],
67
+ category: 'Angular Deprecated APIs',
68
+ },
69
+ // ── Template best practices ────────────────────────────────────────────
70
+ {
71
+ id: 'angular-no-function-in-template',
72
+ label: 'No function calls in templates',
73
+ description: 'Avoid calling functions in Angular templates — they run on every change detection cycle. Use pipes, computed signals, or memoized getters instead.',
74
+ severity: 'error',
75
+ fileExtensions: ['html'],
76
+ pattern: null,
77
+ customCheck: (file) => {
78
+ const violations = [];
79
+ /**
80
+ * Regex explanation:
81
+ * Match patterns like {{ someFunc() }} or (click)="handler()" but EXCLUDE:
82
+ * - Event handlers: (click)="...", (submit)="...", on*="..."
83
+ * - Known safe pipes: | async, | date, | json, etc.
84
+ * - Structural directives: *ngIf, *ngFor, @if, @for
85
+ *
86
+ * We look for interpolation bindings {{ expr() }} and property bindings [prop]="expr()"
87
+ * that contain function calls which are NOT event bindings.
88
+ */
89
+ const interpolationRegex = /\{\{[^}]*\w+\s*\([^)]*\)[^}]*\}\}/g;
90
+ const propertyBindingRegex = /\[(?!click|submit|keyup|keydown|change|input|focus|blur)\w+\]\s*=\s*"[^"]*\w+\s*\([^)]*\)[^"]*"/g;
91
+ for (let i = 0; i < file.lines.length; i++) {
92
+ const line = file.lines[i];
93
+ // Check interpolation bindings {{ func() }}
94
+ interpolationRegex.lastIndex = 0;
95
+ if (interpolationRegex.test(line)) {
96
+ // Exclude pipe usages like {{ value | pipeName }}
97
+ const trimmed = line.trim();
98
+ if (!trimmed.includes(' | ')) {
99
+ violations.push({
100
+ line: i + 1,
101
+ message: `Function call in interpolation: "${trimmed}". Use a pipe or signal instead.`,
102
+ });
103
+ }
104
+ }
105
+ // Check property bindings [prop]="func()"
106
+ propertyBindingRegex.lastIndex = 0;
107
+ if (propertyBindingRegex.test(line)) {
108
+ violations.push({
109
+ line: i + 1,
110
+ message: `Function call in property binding: "${line.trim()}". Use a signal or memoized getter.`,
111
+ });
112
+ }
113
+ }
114
+ return violations;
115
+ },
116
+ applicableTo: ['angular'],
117
+ category: 'Angular Templates',
118
+ },
119
+ // ── RxJS best practices ────────────────────────────────────────────────
120
+ {
121
+ id: 'angular-use-async-pipe',
122
+ label: 'Use async pipe or toSignal() instead of manual subscribe',
123
+ description: 'Manual .subscribe() in components leads to memory leaks. Use the async pipe in templates or convert to signals with toSignal().',
124
+ severity: 'warning',
125
+ fileExtensions: ['ts'],
126
+ pattern: /\.subscribe\s*\(/g,
127
+ applicableTo: ['angular'],
128
+ category: 'RxJS',
129
+ },
130
+ {
131
+ id: 'angular-use-takeuntildestroyed',
132
+ label: 'Use takeUntilDestroyed() for subscriptions',
133
+ description: 'If you must subscribe manually, use takeUntilDestroyed() from @angular/core/rxjs-interop to auto-unsubscribe.',
134
+ severity: 'warning',
135
+ fileExtensions: ['ts'],
136
+ pattern: null,
137
+ customCheck: (file) => {
138
+ const violations = [];
139
+ // Only check Angular component/directive/service files
140
+ if (!file.content.includes('@Component') &&
141
+ !file.content.includes('@Directive') &&
142
+ !file.content.includes('@Injectable')) {
143
+ return [];
144
+ }
145
+ const hasSubscribe = /\.subscribe\s*\(/.test(file.content);
146
+ const hasTakeUntilDestroyed = file.content.includes('takeUntilDestroyed');
147
+ const hasAsyncPipe = file.content.includes('| async') || file.content.includes('toSignal');
148
+ if (hasSubscribe && !hasTakeUntilDestroyed && !hasAsyncPipe) {
149
+ violations.push({
150
+ line: null,
151
+ message: 'Manual .subscribe() found without takeUntilDestroyed(). Add pipe(takeUntilDestroyed()) or use async pipe / toSignal().',
152
+ });
153
+ }
154
+ return violations;
155
+ },
156
+ applicableTo: ['angular'],
157
+ category: 'RxJS',
158
+ },
159
+ {
160
+ id: 'angular-prefer-signals',
161
+ label: 'Consider using Angular Signals',
162
+ description: 'Angular 16+ supports Signals for reactive state. Consider using signal(), computed(), and effect() for simpler reactivity.',
163
+ severity: 'info',
164
+ fileExtensions: ['ts'],
165
+ pattern: null,
166
+ customCheck: (file) => {
167
+ // Only flag if the component uses BehaviorSubject but no signals
168
+ const hasBehaviorSubject = file.content.includes('BehaviorSubject');
169
+ const hasSignal = file.content.includes('signal(') || file.content.includes('computed(');
170
+ if (hasBehaviorSubject && !hasSignal) {
171
+ return [
172
+ {
173
+ line: null,
174
+ message: 'BehaviorSubject detected. Consider migrating to Angular Signals (signal(), computed()) for simpler state management.',
175
+ },
176
+ ];
177
+ }
178
+ return [];
179
+ },
180
+ applicableTo: ['angular'],
181
+ category: 'Angular Signals',
182
+ },
183
+ ];
184
+ exports.angularRules = angularRules;
185
+ // Register all Angular-specific rules
186
+ (0, guidelines_config_1.registerRules)('angular', angularRules);
187
+ //# sourceMappingURL=angular.config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"angular.config.js","sourceRoot":"","sources":["../../config/angular.config.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,63 @@
1
+ /**
2
+ * ============================================================================
3
+ * guidelines.config.ts — Central guidelines configuration
4
+ * ============================================================================
5
+ *
6
+ * Defines the shape of a rule, severity levels, and the shared rule registry.
7
+ * Each project-type config (angular, react, nextjs) plugs into this registry.
8
+ */
9
+ import { ProjectType } from '../scripts/utils/project-detector';
10
+ export type Severity = 'error' | 'warning' | 'info';
11
+ export interface Rule {
12
+ /** Unique identifier — used in reports and inline suppressions */
13
+ id: string;
14
+ /** Human-readable label for logs and checklists */
15
+ label: string;
16
+ /** Detailed description of what the rule checks */
17
+ description: string;
18
+ /** Severity: 'error' blocks commit, 'warning' allows but logs, 'info' is advisory */
19
+ severity: Severity;
20
+ /**
21
+ * Which file extensions this rule applies to.
22
+ * Empty array = all files.
23
+ */
24
+ fileExtensions: string[];
25
+ /**
26
+ * Regex pattern to search for inside file content.
27
+ * If set, the rule engine will scan each line for this pattern.
28
+ * `null` means the rule uses a custom checker function instead.
29
+ */
30
+ pattern: RegExp | null;
31
+ /**
32
+ * Optional custom checker function for complex rules that cannot be
33
+ * expressed as a simple regex. Receives the file info and returns
34
+ * an array of violation objects.
35
+ */
36
+ customCheck?: (file: any) => Array<{
37
+ line: number | null;
38
+ message: string;
39
+ }>;
40
+ /**
41
+ * Which project types this rule applies to.
42
+ * Empty array = all project types.
43
+ */
44
+ applicableTo: ProjectType[];
45
+ /** Category for grouping in the PR checklist */
46
+ category: string;
47
+ }
48
+ export declare const sharedRules: Rule[];
49
+ /**
50
+ * Register rules for a specific project type.
51
+ * Called by angular.config.ts, react.config.ts, nextjs.config.ts.
52
+ */
53
+ export declare function registerRules(projectType: ProjectType, rules: Rule[]): void;
54
+ /**
55
+ * Get all applicable rules for a detected project type.
56
+ * Merges shared rules with project-specific rules.
57
+ */
58
+ export declare function getRulesForProject(projectType: ProjectType): Rule[];
59
+ /**
60
+ * Get ALL rules across all project types (used for PR checklist generation).
61
+ */
62
+ export declare function getAllRules(): Rule[];
63
+ //# sourceMappingURL=guidelines.config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"guidelines.config.d.ts","sourceRoot":"","sources":["../../config/guidelines.config.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,WAAW,EAAE,MAAM,mCAAmC,CAAC;AAIhE,MAAM,MAAM,QAAQ,GAAG,OAAO,GAAG,SAAS,GAAG,MAAM,CAAC;AAIpD,MAAM,WAAW,IAAI;IACnB,kEAAkE;IAClE,EAAE,EAAE,MAAM,CAAC;IAEX,mDAAmD;IACnD,KAAK,EAAE,MAAM,CAAC;IAEd,mDAAmD;IACnD,WAAW,EAAE,MAAM,CAAC;IAEpB,qFAAqF;IACrF,QAAQ,EAAE,QAAQ,CAAC;IAEnB;;;OAGG;IACH,cAAc,EAAE,MAAM,EAAE,CAAC;IAEzB;;;;OAIG;IACH,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IAEvB;;;;OAIG;IACH,WAAW,CAAC,EAAE,CAAC,IAAI,EAAE,GAAG,KAAK,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAE7E;;;OAGG;IACH,YAAY,EAAE,WAAW,EAAE,CAAC;IAE5B,gDAAgD;IAChD,QAAQ,EAAE,MAAM,CAAC;CAClB;AAID,eAAO,MAAM,WAAW,EAAE,IAAI,EAoH7B,CAAC;AAMF;;;GAGG;AACH,wBAAgB,aAAa,CAAC,WAAW,EAAE,WAAW,EAAE,KAAK,EAAE,IAAI,EAAE,GAAG,IAAI,CAG3E;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,WAAW,EAAE,WAAW,GAAG,IAAI,EAAE,CASnE;AAED;;GAEG;AACH,wBAAgB,WAAW,IAAI,IAAI,EAAE,CAiBpC"}