@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,167 @@
1
+ "use strict";
2
+ /**
3
+ * ============================================================================
4
+ * guidelines.config.ts — Central guidelines configuration
5
+ * ============================================================================
6
+ *
7
+ * Defines the shape of a rule, severity levels, and the shared rule registry.
8
+ * Each project-type config (angular, react, nextjs) plugs into this registry.
9
+ */
10
+ Object.defineProperty(exports, "__esModule", { value: true });
11
+ exports.sharedRules = void 0;
12
+ exports.registerRules = registerRules;
13
+ exports.getRulesForProject = getRulesForProject;
14
+ exports.getAllRules = getAllRules;
15
+ // ── Shared rules (framework-agnostic) ───────────────────────────────────────
16
+ exports.sharedRules = [
17
+ {
18
+ id: 'no-console-log',
19
+ label: 'No console.log',
20
+ description: 'Remove all console.log statements before committing. Use a proper logging service instead.',
21
+ severity: 'error',
22
+ fileExtensions: ['ts', 'tsx', 'js', 'jsx'],
23
+ pattern: /console\.log\s*\(/g,
24
+ applicableTo: [],
25
+ category: 'Code Quality',
26
+ },
27
+ {
28
+ id: 'no-any-type',
29
+ label: 'No `any` type',
30
+ description: 'Avoid using `any` type. Use proper typing, generics, or `unknown` instead.',
31
+ severity: 'error',
32
+ fileExtensions: ['ts', 'tsx'],
33
+ pattern: /:\s*any\b|<any>|as\s+any\b/g,
34
+ applicableTo: [],
35
+ category: 'TypeScript',
36
+ },
37
+ {
38
+ id: 'no-settimeout',
39
+ label: 'No setTimeout',
40
+ description: 'Avoid using setTimeout. Use RxJS timer(), delay(), or framework-specific alternatives.',
41
+ severity: 'warning',
42
+ fileExtensions: ['ts', 'tsx', 'js', 'jsx'],
43
+ pattern: /setTimeout\s*\(/g,
44
+ applicableTo: [],
45
+ category: 'Async Patterns',
46
+ },
47
+ {
48
+ id: 'max-component-lines',
49
+ label: 'Component size ≤ 400 lines',
50
+ description: 'Components should not exceed 400 lines. Split large components into smaller, focused ones.',
51
+ severity: 'error',
52
+ fileExtensions: ['ts', 'tsx', 'jsx'],
53
+ pattern: null,
54
+ customCheck: (file) => {
55
+ if (file.lineCount > 400) {
56
+ return [
57
+ {
58
+ line: null,
59
+ message: `File has ${file.lineCount} lines (max 400). Consider splitting into smaller components.`,
60
+ },
61
+ ];
62
+ }
63
+ return [];
64
+ },
65
+ applicableTo: [],
66
+ category: 'Architecture',
67
+ },
68
+ {
69
+ id: 'no-custom-css',
70
+ label: 'Use Tailwind instead of custom CSS',
71
+ description: 'Prefer Tailwind utility classes over writing custom CSS. Custom styles should be rare and justified.',
72
+ severity: 'warning',
73
+ fileExtensions: ['css', 'scss', 'sass', 'less'],
74
+ pattern: null,
75
+ customCheck: (file) => {
76
+ // Allow Tailwind config files and global resets
77
+ const allowedFiles = [
78
+ 'tailwind.css',
79
+ 'globals.css',
80
+ 'global.css',
81
+ 'styles.css',
82
+ 'variables.css',
83
+ 'reset.css',
84
+ ];
85
+ const basename = file.relativePath.split('/').pop() || '';
86
+ if (allowedFiles.includes(basename))
87
+ return [];
88
+ // Check for custom CSS declarations (property: value patterns)
89
+ const cssDeclarationRegex = /^\s*[a-z-]+\s*:\s*[^;]+;/gm;
90
+ const matches = [];
91
+ const lines = file.lines;
92
+ for (let i = 0; i < lines.length; i++) {
93
+ const trimmed = lines[i].trim();
94
+ // Skip @apply (Tailwind), @import, @tailwind directives, comments, and CSS custom properties
95
+ if (trimmed.startsWith('@apply') ||
96
+ trimmed.startsWith('@import') ||
97
+ trimmed.startsWith('@tailwind') ||
98
+ trimmed.startsWith('//') ||
99
+ trimmed.startsWith('/*') ||
100
+ trimmed.startsWith('*') ||
101
+ trimmed.startsWith('--') // CSS custom properties
102
+ ) {
103
+ continue;
104
+ }
105
+ cssDeclarationRegex.lastIndex = 0;
106
+ if (cssDeclarationRegex.test(lines[i])) {
107
+ matches.push({
108
+ line: i + 1,
109
+ message: `Custom CSS found: "${trimmed}". Prefer Tailwind utilities.`,
110
+ });
111
+ }
112
+ }
113
+ // Only report if there are a meaningful number of custom declarations
114
+ if (matches.length > 3) {
115
+ return [
116
+ {
117
+ line: null,
118
+ message: `File contains ${matches.length} custom CSS declarations. Consider using Tailwind utilities instead.`,
119
+ },
120
+ ];
121
+ }
122
+ return [];
123
+ },
124
+ applicableTo: [],
125
+ category: 'Styling',
126
+ },
127
+ ];
128
+ // ── Rule registry (populated by project-specific configs) ───────────────────
129
+ const ruleRegistry = new Map();
130
+ /**
131
+ * Register rules for a specific project type.
132
+ * Called by angular.config.ts, react.config.ts, nextjs.config.ts.
133
+ */
134
+ function registerRules(projectType, rules) {
135
+ const existing = ruleRegistry.get(projectType) || [];
136
+ ruleRegistry.set(projectType, [...existing, ...rules]);
137
+ }
138
+ /**
139
+ * Get all applicable rules for a detected project type.
140
+ * Merges shared rules with project-specific rules.
141
+ */
142
+ function getRulesForProject(projectType) {
143
+ const projectRules = ruleRegistry.get(projectType) || [];
144
+ // Filter shared rules: include if applicableTo is empty (all) or includes this project type
145
+ const applicableShared = exports.sharedRules.filter((r) => r.applicableTo.length === 0 || r.applicableTo.includes(projectType));
146
+ return [...applicableShared, ...projectRules];
147
+ }
148
+ /**
149
+ * Get ALL rules across all project types (used for PR checklist generation).
150
+ */
151
+ function getAllRules() {
152
+ const allProjectRules = [];
153
+ for (const rules of ruleRegistry.values()) {
154
+ allProjectRules.push(...rules);
155
+ }
156
+ // Deduplicate by rule id
157
+ const seen = new Set();
158
+ const deduped = [];
159
+ for (const rule of [...exports.sharedRules, ...allProjectRules]) {
160
+ if (!seen.has(rule.id)) {
161
+ seen.add(rule.id);
162
+ deduped.push(rule);
163
+ }
164
+ }
165
+ return deduped;
166
+ }
167
+ //# sourceMappingURL=guidelines.config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"guidelines.config.js","sourceRoot":"","sources":["../../config/guidelines.config.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,18 @@
1
+ /**
2
+ * ============================================================================
3
+ * nextjs.config.ts — Next.js-specific coding rules
4
+ * ============================================================================
5
+ *
6
+ * Registers rules that only apply to Next.js projects:
7
+ * - App Router patterns
8
+ * - Server/Client component boundaries
9
+ * - Image optimization
10
+ * - API route conventions
11
+ *
12
+ * Note: Next.js projects also inherit React rules automatically
13
+ * because the React config registers rules for 'nextjs' too.
14
+ */
15
+ import { Rule } from './guidelines.config';
16
+ declare const nextjsRules: Rule[];
17
+ export { nextjsRules };
18
+ //# sourceMappingURL=nextjs.config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"nextjs.config.d.ts","sourceRoot":"","sources":["../../config/nextjs.config.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,EAAiB,IAAI,EAAE,MAAM,qBAAqB,CAAC;AAE1D,QAAA,MAAM,WAAW,EAAE,IAAI,EAyItB,CAAC;AAKF,OAAO,EAAE,WAAW,EAAE,CAAC"}
@@ -0,0 +1,133 @@
1
+ "use strict";
2
+ /**
3
+ * ============================================================================
4
+ * nextjs.config.ts — Next.js-specific coding rules
5
+ * ============================================================================
6
+ *
7
+ * Registers rules that only apply to Next.js projects:
8
+ * - App Router patterns
9
+ * - Server/Client component boundaries
10
+ * - Image optimization
11
+ * - API route conventions
12
+ *
13
+ * Note: Next.js projects also inherit React rules automatically
14
+ * because the React config registers rules for 'nextjs' too.
15
+ */
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ exports.nextjsRules = void 0;
18
+ const guidelines_config_1 = require("./guidelines.config");
19
+ const nextjsRules = [
20
+ // ── App Router ─────────────────────────────────────────────────────────
21
+ {
22
+ id: 'nextjs-use-client-directive',
23
+ label: 'Verify "use client" / "use server" directives',
24
+ description: 'Components using hooks, event handlers, or browser APIs must have "use client" at the top. Server components must not have it.',
25
+ severity: 'warning',
26
+ fileExtensions: ['tsx', 'jsx', 'ts', 'js'],
27
+ pattern: null,
28
+ customCheck: (file) => {
29
+ const violations = [];
30
+ const hasUseClient = file.content.includes("'use client'") || file.content.includes('"use client"');
31
+ const hasHooks = /use(State|Effect|Context|Reducer|Callback|Memo|Ref)\s*\(/.test(file.content);
32
+ const hasEventHandlers = /on(Click|Change|Submit|KeyDown|KeyUp|Focus|Blur)\s*=/.test(file.content);
33
+ // If file uses hooks or event handlers but lacks "use client"
34
+ if ((hasHooks || hasEventHandlers) && !hasUseClient) {
35
+ // Only flag if this looks like a component file (not a utility/hook file)
36
+ const isComponent = /export\s+(default\s+)?function\s+[A-Z]/.test(file.content) ||
37
+ /const\s+[A-Z]\w+\s*[:=]/.test(file.content);
38
+ if (isComponent) {
39
+ violations.push({
40
+ line: 1,
41
+ message: 'Component uses hooks/events but missing "use client" directive at the top.',
42
+ });
43
+ }
44
+ }
45
+ return violations;
46
+ },
47
+ applicableTo: ['nextjs'],
48
+ category: 'Next.js App Router',
49
+ },
50
+ // ── Image optimization ─────────────────────────────────────────────────
51
+ {
52
+ id: 'nextjs-use-image-component',
53
+ label: 'Use next/image instead of <img>',
54
+ description: 'Always use the Next.js <Image> component for automatic optimization, lazy loading, and proper sizing.',
55
+ severity: 'warning',
56
+ fileExtensions: ['tsx', 'jsx'],
57
+ pattern: /<img\s/g,
58
+ applicableTo: ['nextjs'],
59
+ category: 'Next.js Performance',
60
+ },
61
+ // ── Link component ────────────────────────────────────────────────────
62
+ {
63
+ id: 'nextjs-use-link-component',
64
+ label: 'Use next/link instead of <a>',
65
+ description: 'Use the Next.js <Link> component for client-side navigation. Avoid plain <a> tags for internal links.',
66
+ severity: 'warning',
67
+ fileExtensions: ['tsx', 'jsx'],
68
+ pattern: /<a\s+href\s*=\s*["']\/(?!\/)/g,
69
+ applicableTo: ['nextjs'],
70
+ category: 'Next.js Navigation',
71
+ },
72
+ // ── API routes ─────────────────────────────────────────────────────────
73
+ {
74
+ id: 'nextjs-api-error-handling',
75
+ label: 'API routes must have error handling',
76
+ description: 'All API route handlers (GET, POST, etc.) must wrap logic in try/catch and return proper error responses.',
77
+ severity: 'warning',
78
+ fileExtensions: ['ts', 'js'],
79
+ pattern: null,
80
+ customCheck: (file) => {
81
+ const violations = [];
82
+ // Only check files in api/ or route.ts/route.js paths
83
+ if (!file.relativePath.includes('/api/') &&
84
+ !file.relativePath.includes('route.ts') &&
85
+ !file.relativePath.includes('route.js')) {
86
+ return [];
87
+ }
88
+ const hasExportedHandler = /export\s+(async\s+)?function\s+(GET|POST|PUT|DELETE|PATCH)/.test(file.content);
89
+ const hasTryCatch = file.content.includes('try {') || file.content.includes('try{');
90
+ if (hasExportedHandler && !hasTryCatch) {
91
+ violations.push({
92
+ line: null,
93
+ message: 'API route handler missing try/catch error handling. Wrap logic in try/catch.',
94
+ });
95
+ }
96
+ return violations;
97
+ },
98
+ applicableTo: ['nextjs'],
99
+ category: 'Next.js API Routes',
100
+ },
101
+ // ── Metadata ──────────────────────────────────────────────────────────
102
+ {
103
+ id: 'nextjs-page-metadata',
104
+ label: 'Pages should export metadata',
105
+ description: 'Page components should export a metadata object or generateMetadata function for SEO.',
106
+ severity: 'info',
107
+ fileExtensions: ['tsx', 'ts'],
108
+ pattern: null,
109
+ customCheck: (file) => {
110
+ const violations = [];
111
+ // Only check page.tsx files
112
+ const basename = file.relativePath.split('/').pop() || '';
113
+ if (basename !== 'page.tsx' && basename !== 'page.ts')
114
+ return [];
115
+ const hasMetadata = file.content.includes('export const metadata') ||
116
+ file.content.includes('export function generateMetadata') ||
117
+ file.content.includes('export async function generateMetadata');
118
+ if (!hasMetadata) {
119
+ violations.push({
120
+ line: null,
121
+ message: 'Page is missing metadata export. Add `export const metadata` or `export function generateMetadata`.',
122
+ });
123
+ }
124
+ return violations;
125
+ },
126
+ applicableTo: ['nextjs'],
127
+ category: 'Next.js SEO',
128
+ },
129
+ ];
130
+ exports.nextjsRules = nextjsRules;
131
+ // Register all Next.js-specific rules
132
+ (0, guidelines_config_1.registerRules)('nextjs', nextjsRules);
133
+ //# sourceMappingURL=nextjs.config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"nextjs.config.js","sourceRoot":"","sources":["../../config/nextjs.config.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;GAaG;;;AAEH,2DAA0D;AAE1D,MAAM,WAAW,GAAW;IAC1B,0EAA0E;IAE1E;QACE,EAAE,EAAE,6BAA6B;QACjC,KAAK,EAAE,+CAA+C;QACtD,WAAW,EACT,gIAAgI;QAClI,QAAQ,EAAE,SAAS;QACnB,cAAc,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,CAAC;QAC1C,OAAO,EAAE,IAAI;QACb,WAAW,EAAE,CAAC,IAAI,EAAE,EAAE;YACpB,MAAM,UAAU,GAAoD,EAAE,CAAC;YAEvE,MAAM,YAAY,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAC,IAAI,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAC,CAAC;YACpG,MAAM,QAAQ,GAAG,0DAA0D,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;YAC/F,MAAM,gBAAgB,GAAG,sDAAsD,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;YAEnG,8DAA8D;YAC9D,IAAI,CAAC,QAAQ,IAAI,gBAAgB,CAAC,IAAI,CAAC,YAAY,EAAE,CAAC;gBACpD,0EAA0E;gBAC1E,MAAM,WAAW,GAAG,wCAAwC,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC;oBAC5D,yBAAyB,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;gBAChE,IAAI,WAAW,EAAE,CAAC;oBAChB,UAAU,CAAC,IAAI,CAAC;wBACd,IAAI,EAAE,CAAC;wBACP,OAAO,EAAE,4EAA4E;qBACtF,CAAC,CAAC;gBACL,CAAC;YACH,CAAC;YAED,OAAO,UAAU,CAAC;QACpB,CAAC;QACD,YAAY,EAAE,CAAC,QAAQ,CAAC;QACxB,QAAQ,EAAE,oBAAoB;KAC/B;IAED,0EAA0E;IAE1E;QACE,EAAE,EAAE,4BAA4B;QAChC,KAAK,EAAE,iCAAiC;QACxC,WAAW,EACT,uGAAuG;QACzG,QAAQ,EAAE,SAAS;QACnB,cAAc,EAAE,CAAC,KAAK,EAAE,KAAK,CAAC;QAC9B,OAAO,EAAE,SAAS;QAClB,YAAY,EAAE,CAAC,QAAQ,CAAC;QACxB,QAAQ,EAAE,qBAAqB;KAChC;IAED,yEAAyE;IAEzE;QACE,EAAE,EAAE,2BAA2B;QAC/B,KAAK,EAAE,8BAA8B;QACrC,WAAW,EACT,uGAAuG;QACzG,QAAQ,EAAE,SAAS;QACnB,cAAc,EAAE,CAAC,KAAK,EAAE,KAAK,CAAC;QAC9B,OAAO,EAAE,+BAA+B;QACxC,YAAY,EAAE,CAAC,QAAQ,CAAC;QACxB,QAAQ,EAAE,oBAAoB;KAC/B;IAED,0EAA0E;IAE1E;QACE,EAAE,EAAE,2BAA2B;QAC/B,KAAK,EAAE,qCAAqC;QAC5C,WAAW,EACT,0GAA0G;QAC5G,QAAQ,EAAE,SAAS;QACnB,cAAc,EAAE,CAAC,IAAI,EAAE,IAAI,CAAC;QAC5B,OAAO,EAAE,IAAI;QACb,WAAW,EAAE,CAAC,IAAI,EAAE,EAAE;YACpB,MAAM,UAAU,GAAoD,EAAE,CAAC;YAEvE,sDAAsD;YACtD,IACE,CAAC,IAAI,CAAC,YAAY,CAAC,QAAQ,CAAC,OAAO,CAAC;gBACpC,CAAC,IAAI,CAAC,YAAY,CAAC,QAAQ,CAAC,UAAU,CAAC;gBACvC,CAAC,IAAI,CAAC,YAAY,CAAC,QAAQ,CAAC,UAAU,CAAC,EACvC,CAAC;gBACD,OAAO,EAAE,CAAC;YACZ,CAAC;YAED,MAAM,kBAAkB,GAAG,4DAA4D,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;YAC3G,MAAM,WAAW,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;YAEpF,IAAI,kBAAkB,IAAI,CAAC,WAAW,EAAE,CAAC;gBACvC,UAAU,CAAC,IAAI,CAAC;oBACd,IAAI,EAAE,IAAI;oBACV,OAAO,EAAE,8EAA8E;iBACxF,CAAC,CAAC;YACL,CAAC;YAED,OAAO,UAAU,CAAC;QACpB,CAAC;QACD,YAAY,EAAE,CAAC,QAAQ,CAAC;QACxB,QAAQ,EAAE,oBAAoB;KAC/B;IAED,yEAAyE;IAEzE;QACE,EAAE,EAAE,sBAAsB;QAC1B,KAAK,EAAE,8BAA8B;QACrC,WAAW,EACT,uFAAuF;QACzF,QAAQ,EAAE,MAAM;QAChB,cAAc,EAAE,CAAC,KAAK,EAAE,IAAI,CAAC;QAC7B,OAAO,EAAE,IAAI;QACb,WAAW,EAAE,CAAC,IAAI,EAAE,EAAE;YACpB,MAAM,UAAU,GAAoD,EAAE,CAAC;YAEvE,4BAA4B;YAC5B,MAAM,QAAQ,GAAG,IAAI,CAAC,YAAY,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,IAAI,EAAE,CAAC;YAC1D,IAAI,QAAQ,KAAK,UAAU,IAAI,QAAQ,KAAK,SAAS;gBAAE,OAAO,EAAE,CAAC;YAEjE,MAAM,WAAW,GACf,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,uBAAuB,CAAC;gBAC9C,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,kCAAkC,CAAC;gBACzD,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,wCAAwC,CAAC,CAAC;YAElE,IAAI,CAAC,WAAW,EAAE,CAAC;gBACjB,UAAU,CAAC,IAAI,CAAC;oBACd,IAAI,EAAE,IAAI;oBACV,OAAO,EAAE,qGAAqG;iBAC/G,CAAC,CAAC;YACL,CAAC;YAED,OAAO,UAAU,CAAC;QACpB,CAAC;QACD,YAAY,EAAE,CAAC,QAAQ,CAAC;QACxB,QAAQ,EAAE,aAAa;KACxB;CACF,CAAC;AAKO,kCAAW;AAHpB,sCAAsC;AACtC,IAAA,iCAAa,EAAC,QAAQ,EAAE,WAAW,CAAC,CAAC"}
@@ -0,0 +1,15 @@
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
+ import { Rule } from './guidelines.config';
13
+ declare const reactRules: Rule[];
14
+ export { reactRules };
15
+ //# sourceMappingURL=react.config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"react.config.d.ts","sourceRoot":"","sources":["../../config/react.config.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAiB,IAAI,EAAE,MAAM,qBAAqB,CAAC;AAE1D,QAAA,MAAM,UAAU,EAAE,IAAI,EAsTrB,CAAC;AAKF,OAAO,EAAE,UAAU,EAAE,CAAC"}
@@ -0,0 +1,287 @@
1
+ "use strict";
2
+ /**
3
+ * ============================================================================
4
+ * react.config.ts — React-specific coding rules
5
+ * ============================================================================
6
+ *
7
+ * Registers rules that only apply to React projects:
8
+ * - Hook usage patterns
9
+ * - Props/state typing
10
+ * - Component patterns
11
+ * - Performance anti-patterns
12
+ */
13
+ Object.defineProperty(exports, "__esModule", { value: true });
14
+ exports.reactRules = void 0;
15
+ const guidelines_config_1 = require("./guidelines.config");
16
+ const reactRules = [
17
+ // ── Hooks ──────────────────────────────────────────────────────────────
18
+ {
19
+ id: 'react-no-useeffect-no-deps',
20
+ label: 'useEffect must have dependency array',
21
+ description: 'Every useEffect must have a dependency array. Missing deps causes infinite re-renders or stale closures.',
22
+ severity: 'error',
23
+ fileExtensions: ['tsx', 'jsx', 'ts', 'js'],
24
+ pattern: null,
25
+ customCheck: (file) => {
26
+ const violations = [];
27
+ const lines = file.lines;
28
+ for (let i = 0; i < lines.length; i++) {
29
+ const line = lines[i];
30
+ // Detect useEffect( without a closing bracket on subsequent lines containing dependency array
31
+ if (/useEffect\s*\(\s*\(\s*\)\s*=>\s*\{/.test(line)) {
32
+ // Look ahead for the closing of useEffect — find , [] or , [deps])
33
+ let foundDeps = false;
34
+ let parenDepth = 0;
35
+ for (let j = i; j < Math.min(i + 50, lines.length); j++) {
36
+ for (const ch of lines[j]) {
37
+ if (ch === '(')
38
+ parenDepth++;
39
+ if (ch === ')')
40
+ parenDepth--;
41
+ }
42
+ // Check if the dependency array is present
43
+ if (/\]\s*\)\s*;?\s*$/.test(lines[j]) || /,\s*\[/.test(lines[j])) {
44
+ foundDeps = true;
45
+ break;
46
+ }
47
+ if (parenDepth <= 0)
48
+ break;
49
+ }
50
+ if (!foundDeps) {
51
+ violations.push({
52
+ line: i + 1,
53
+ message: 'useEffect without dependency array detected. Always specify dependencies.',
54
+ });
55
+ }
56
+ }
57
+ }
58
+ return violations;
59
+ },
60
+ applicableTo: ['react', 'nextjs'],
61
+ category: 'React Hooks',
62
+ },
63
+ {
64
+ id: 'react-no-inline-styles',
65
+ label: 'No inline style objects',
66
+ description: 'Avoid inline style={{ }} in JSX. Use Tailwind classes or CSS modules for consistent styling.',
67
+ severity: 'warning',
68
+ fileExtensions: ['tsx', 'jsx'],
69
+ pattern: /style\s*=\s*\{\s*\{/g,
70
+ applicableTo: ['react', 'nextjs'],
71
+ category: 'Styling',
72
+ },
73
+ {
74
+ id: 'react-no-direct-dom',
75
+ label: 'No direct DOM manipulation',
76
+ description: 'Avoid document.getElementById, querySelector, etc. Use useRef() and React state instead.',
77
+ severity: 'error',
78
+ fileExtensions: ['tsx', 'jsx', 'ts', 'js'],
79
+ pattern: /document\.(getElementById|querySelector|querySelectorAll|getElementsBy)/g,
80
+ applicableTo: ['react', 'nextjs'],
81
+ category: 'React Patterns',
82
+ },
83
+ // ── Component patterns ─────────────────────────────────────────────────
84
+ {
85
+ id: 'react-prefer-fc-typing',
86
+ label: 'Type component props explicitly',
87
+ description: 'Define a Props interface/type and use it. Avoid React.FC — type props parameter directly.',
88
+ severity: 'info',
89
+ fileExtensions: ['tsx'],
90
+ pattern: /React\.FC/g,
91
+ applicableTo: ['react', 'nextjs'],
92
+ category: 'TypeScript',
93
+ },
94
+ {
95
+ id: 'react-no-prop-spreading',
96
+ label: 'Avoid prop spreading ({...props})',
97
+ description: 'Spreading props makes component APIs unclear. Explicitly pass required props for better readability and TypeScript safety.',
98
+ severity: 'info',
99
+ fileExtensions: ['tsx', 'jsx'],
100
+ pattern: /\{\s*\.\.\.\w+\s*\}/g,
101
+ applicableTo: ['react', 'nextjs'],
102
+ category: 'React Patterns',
103
+ },
104
+ // ── Security Rules ─────────────────────────────────────────────────────
105
+ {
106
+ id: 'react-no-dangerously-set-html',
107
+ label: 'No dangerouslySetInnerHTML',
108
+ description: 'Using dangerouslySetInnerHTML opens your app to XSS attacks. Sanitize HTML or use safe alternatives.',
109
+ severity: 'error',
110
+ fileExtensions: ['tsx', 'jsx'],
111
+ pattern: /dangerouslySetInnerHTML/g,
112
+ applicableTo: ['react', 'nextjs'],
113
+ category: 'Security',
114
+ },
115
+ {
116
+ id: 'no-eval',
117
+ label: 'No eval() usage',
118
+ description: 'eval() allows arbitrary code execution and is a major security vulnerability. Use JSON.parse() or other safe alternatives.',
119
+ severity: 'error',
120
+ fileExtensions: ['tsx', 'jsx', 'ts', 'js'],
121
+ pattern: /\beval\s*\(/g,
122
+ applicableTo: ['react', 'nextjs'],
123
+ category: 'Security',
124
+ },
125
+ {
126
+ id: 'no-hardcoded-credentials',
127
+ label: 'No hardcoded credentials',
128
+ description: 'Never hardcode API keys, passwords, or secrets. Use environment variables instead.',
129
+ severity: 'error',
130
+ fileExtensions: ['tsx', 'jsx', 'ts', 'js'],
131
+ pattern: null,
132
+ customCheck: (file) => {
133
+ const violations = [];
134
+ const lines = file.lines;
135
+ const suspiciousPatterns = [
136
+ /password\s*[=:]\s*["'`][^"'`]+["'`]/i,
137
+ /apikey\s*[=:]\s*["'`][^"'`]+["'`]/i,
138
+ /api_key\s*[=:]\s*["'`][^"'`]+["'`]/i,
139
+ /secret\s*[=:]\s*["'`][^"'`]+["'`]/i,
140
+ /token\s*[=:]\s*["'`][^"'`]{20,}["'`]/i,
141
+ ];
142
+ for (let i = 0; i < lines.length; i++) {
143
+ const line = lines[i];
144
+ for (const pattern of suspiciousPatterns) {
145
+ if (pattern.test(line)) {
146
+ violations.push({
147
+ line: i + 1,
148
+ message: `Potential hardcoded credential detected. Use environment variables: process.env.API_KEY`,
149
+ });
150
+ break;
151
+ }
152
+ }
153
+ }
154
+ return violations;
155
+ },
156
+ applicableTo: ['react', 'nextjs', 'angular'],
157
+ category: 'Security',
158
+ },
159
+ {
160
+ id: 'require-https',
161
+ label: 'Require HTTPS URLs',
162
+ description: 'HTTP URLs are insecure. Always use HTTPS for API calls and external resources.',
163
+ severity: 'warning',
164
+ fileExtensions: ['tsx', 'jsx', 'ts', 'js'],
165
+ pattern: /['"`]http:\/\/(?!localhost|127\.0\.0\.1)/g,
166
+ applicableTo: ['react', 'nextjs', 'angular'],
167
+ category: 'Security',
168
+ },
169
+ // ── Performance Rules ──────────────────────────────────────────────────
170
+ {
171
+ id: 'react-no-anonymous-functions-in-render',
172
+ label: 'No anonymous functions in JSX',
173
+ description: 'Anonymous functions in JSX props cause unnecessary re-renders. Use useCallback or define functions outside render.',
174
+ severity: 'warning',
175
+ fileExtensions: ['tsx', 'jsx'],
176
+ pattern: /onClick\s*=\s*\{\s*\(\s*\)\s*=>/g,
177
+ applicableTo: ['react', 'nextjs'],
178
+ category: 'Performance',
179
+ },
180
+ {
181
+ id: 'react-missing-key-prop',
182
+ label: 'Missing key prop in list',
183
+ description: 'When rendering lists with .map(), always provide a unique key prop for optimal reconciliation.',
184
+ severity: 'error',
185
+ fileExtensions: ['tsx', 'jsx'],
186
+ pattern: null,
187
+ customCheck: (file) => {
188
+ const violations = [];
189
+ const lines = file.lines;
190
+ for (let i = 0; i < lines.length; i++) {
191
+ const line = lines[i];
192
+ // Detect .map( with JSX but no key prop nearby
193
+ if (/\.\s*map\s*\(/.test(line)) {
194
+ // Look ahead for JSX opening tag
195
+ let foundKey = false;
196
+ for (let j = i; j < Math.min(i + 10, lines.length); j++) {
197
+ if (/key\s*=/.test(lines[j])) {
198
+ foundKey = true;
199
+ break;
200
+ }
201
+ }
202
+ // Check if there's JSX in the map
203
+ let hasJsx = false;
204
+ for (let j = i; j < Math.min(i + 10, lines.length); j++) {
205
+ if (/<[A-Z]/.test(lines[j]) || /<[a-z]/.test(lines[j])) {
206
+ hasJsx = true;
207
+ break;
208
+ }
209
+ }
210
+ if (hasJsx && !foundKey) {
211
+ violations.push({
212
+ line: i + 1,
213
+ message: 'List items rendered with .map() must have a key prop',
214
+ });
215
+ }
216
+ }
217
+ }
218
+ return violations;
219
+ },
220
+ applicableTo: ['react', 'nextjs'],
221
+ category: 'Performance',
222
+ },
223
+ {
224
+ id: 'no-large-bundle-imports',
225
+ label: 'Avoid large library imports',
226
+ description: 'Importing entire lodash or moment.js increases bundle size. Use specific imports: import get from "lodash/get"',
227
+ severity: 'warning',
228
+ fileExtensions: ['tsx', 'jsx', 'ts', 'js'],
229
+ pattern: /import\s+(?:(?:\*\s+as\s+\w+)|(?:\{\s*[^}]{50,}\s*\}))\s+from\s+['"](?:lodash|moment)['"];?$/gm,
230
+ applicableTo: ['react', 'nextjs', 'angular'],
231
+ category: 'Performance',
232
+ },
233
+ // ── Accessibility Rules ────────────────────────────────────────────────
234
+ {
235
+ id: 'require-alt-text',
236
+ label: 'Images must have alt text',
237
+ description: 'All <img> tags must have alt attribute for accessibility. Use empty alt="" for decorative images.',
238
+ severity: 'error',
239
+ fileExtensions: ['tsx', 'jsx'],
240
+ pattern: null,
241
+ customCheck: (file) => {
242
+ const violations = [];
243
+ const lines = file.lines;
244
+ for (let i = 0; i < lines.length; i++) {
245
+ const line = lines[i];
246
+ // Match <img without alt or with empty src
247
+ if (/<img\b/.test(line) && !/alt\s*=/.test(line)) {
248
+ violations.push({
249
+ line: i + 1,
250
+ message: '<img> tag must have alt attribute for accessibility',
251
+ });
252
+ }
253
+ }
254
+ return violations;
255
+ },
256
+ applicableTo: ['react', 'nextjs'],
257
+ category: 'Accessibility',
258
+ },
259
+ {
260
+ id: 'require-button-type',
261
+ label: 'Buttons must have type attribute',
262
+ description: 'Always specify type="button", type="submit", or type="reset" on <button> elements to avoid unexpected form submissions.',
263
+ severity: 'warning',
264
+ fileExtensions: ['tsx', 'jsx'],
265
+ pattern: null,
266
+ customCheck: (file) => {
267
+ const violations = [];
268
+ const lines = file.lines;
269
+ for (let i = 0; i < lines.length; i++) {
270
+ const line = lines[i];
271
+ if (/<button\b/.test(line) && !/type\s*=/.test(line)) {
272
+ violations.push({
273
+ line: i + 1,
274
+ message: '<button> should have explicit type attribute',
275
+ });
276
+ }
277
+ }
278
+ return violations;
279
+ },
280
+ applicableTo: ['react', 'nextjs'],
281
+ category: 'Accessibility',
282
+ },
283
+ ];
284
+ exports.reactRules = reactRules;
285
+ // Register all React-specific rules
286
+ (0, guidelines_config_1.registerRules)('react', reactRules);
287
+ //# sourceMappingURL=react.config.js.map