@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,117 @@
1
+ #!/usr/bin/env ts-node
2
+ "use strict";
3
+ /**
4
+ * ============================================================================
5
+ * view-bypass-log.ts — View bypass audit log
6
+ * ============================================================================
7
+ *
8
+ * Usage:
9
+ * npm run view-bypass-log
10
+ * npm run view-bypass-log -- --author="john@example.com"
11
+ * npm run view-bypass-log -- --days=7
12
+ */
13
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
14
+ if (k2 === undefined) k2 = k;
15
+ var desc = Object.getOwnPropertyDescriptor(m, k);
16
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
17
+ desc = { enumerable: true, get: function() { return m[k]; } };
18
+ }
19
+ Object.defineProperty(o, k2, desc);
20
+ }) : (function(o, m, k, k2) {
21
+ if (k2 === undefined) k2 = k;
22
+ o[k2] = m[k];
23
+ }));
24
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
25
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
26
+ }) : function(o, v) {
27
+ o["default"] = v;
28
+ });
29
+ var __importStar = (this && this.__importStar) || (function () {
30
+ var ownKeys = function(o) {
31
+ ownKeys = Object.getOwnPropertyNames || function (o) {
32
+ var ar = [];
33
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
34
+ return ar;
35
+ };
36
+ return ownKeys(o);
37
+ };
38
+ return function (mod) {
39
+ if (mod && mod.__esModule) return mod;
40
+ var result = {};
41
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
42
+ __setModuleDefault(result, mod);
43
+ return result;
44
+ };
45
+ })();
46
+ Object.defineProperty(exports, "__esModule", { value: true });
47
+ const bypass_manager_1 = require("./utils/bypass-manager");
48
+ const logger = __importStar(require("./utils/logger"));
49
+ function parseArgs() {
50
+ const args = process.argv.slice(2);
51
+ const opts = {};
52
+ for (const arg of args) {
53
+ const [key, ...valueParts] = arg.replace(/^--/, '').split('=');
54
+ const value = valueParts.join('=').replace(/^["']|["']$/g, '');
55
+ switch (key) {
56
+ case 'author':
57
+ opts.author = value;
58
+ break;
59
+ case 'days':
60
+ opts.days = parseInt(value, 10);
61
+ break;
62
+ }
63
+ }
64
+ return opts;
65
+ }
66
+ function main() {
67
+ logger.header('šŸ“Š Code Guardian — Bypass Audit Log');
68
+ const opts = parseArgs();
69
+ if (opts.author) {
70
+ logger.info(`Filtering by author: ${opts.author}`);
71
+ const entries = (0, bypass_manager_1.getBypassesByAuthor)(opts.author);
72
+ if (entries.length === 0) {
73
+ logger.info(`No bypass entries found for ${opts.author}`);
74
+ return;
75
+ }
76
+ console.log(`\nFound ${entries.length} bypass(es) by ${opts.author}:\n`);
77
+ for (const entry of entries) {
78
+ const date = new Date(entry.timestamp).toLocaleString();
79
+ console.log(`━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━`);
80
+ console.log(`šŸ“… ${date}`);
81
+ console.log(`šŸ“ Reason: ${entry.reason}`);
82
+ console.log(`🌿 Branch: ${entry.branch}`);
83
+ console.log(`šŸ“ Files: ${entry.files.length} file(s)`);
84
+ console.log(`šŸ”‘ Method: ${entry.method}`);
85
+ if (entry.commitHash) {
86
+ console.log(`šŸ”— Commit: ${entry.commitHash}`);
87
+ }
88
+ console.log('');
89
+ }
90
+ }
91
+ else if (opts.days) {
92
+ logger.info(`Showing bypasses from last ${opts.days} day(s)`);
93
+ const entries = (0, bypass_manager_1.getRecentBypasses)(opts.days);
94
+ if (entries.length === 0) {
95
+ logger.info(`No bypass entries found in the last ${opts.days} day(s)`);
96
+ return;
97
+ }
98
+ console.log(`\nFound ${entries.length} bypass(es) in the last ${opts.days} day(s):\n`);
99
+ for (const entry of entries) {
100
+ const date = new Date(entry.timestamp).toLocaleString();
101
+ console.log(`━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━`);
102
+ console.log(`šŸ‘¤ ${entry.author} <${entry.email}>`);
103
+ console.log(`šŸ“… ${date}`);
104
+ console.log(`šŸ“ Reason: ${entry.reason}`);
105
+ console.log(`🌿 Branch: ${entry.branch}`);
106
+ console.log(`šŸ”‘ Method: ${entry.method}`);
107
+ console.log('');
108
+ }
109
+ }
110
+ else {
111
+ // Show full report
112
+ const report = (0, bypass_manager_1.generateBypassReport)();
113
+ console.log(report);
114
+ }
115
+ }
116
+ main();
117
+ //# sourceMappingURL=view-bypass-log.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"view-bypass-log.js","sourceRoot":"","sources":["../../scripts/view-bypass-log.ts"],"names":[],"mappings":";;AACA;;;;;;;;;GASG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAEH,2DAAsG;AACtG,uDAAyC;AAEzC,SAAS,SAAS;IAChB,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IACnC,MAAM,IAAI,GAAuC,EAAE,CAAC;IAEpD,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;QACvB,MAAM,CAAC,GAAG,EAAE,GAAG,UAAU,CAAC,GAAG,GAAG,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QAC/D,MAAM,KAAK,GAAG,UAAU,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,cAAc,EAAE,EAAE,CAAC,CAAC;QAE/D,QAAQ,GAAG,EAAE,CAAC;YACZ,KAAK,QAAQ;gBACX,IAAI,CAAC,MAAM,GAAG,KAAK,CAAC;gBACpB,MAAM;YACR,KAAK,MAAM;gBACT,IAAI,CAAC,IAAI,GAAG,QAAQ,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;gBAChC,MAAM;QACV,CAAC;IACH,CAAC;IAED,OAAO,IAAI,CAAC;AACd,CAAC;AAED,SAAS,IAAI;IACX,MAAM,CAAC,MAAM,CAAC,qCAAqC,CAAC,CAAC;IAErD,MAAM,IAAI,GAAG,SAAS,EAAE,CAAC;IAEzB,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;QAChB,MAAM,CAAC,IAAI,CAAC,wBAAwB,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC;QACnD,MAAM,OAAO,GAAG,IAAA,oCAAmB,EAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QAEjD,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACzB,MAAM,CAAC,IAAI,CAAC,+BAA+B,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC;YAC1D,OAAO;QACT,CAAC;QAED,OAAO,CAAC,GAAG,CAAC,WAAW,OAAO,CAAC,MAAM,kBAAkB,IAAI,CAAC,MAAM,KAAK,CAAC,CAAC;QACzE,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;YAC5B,MAAM,IAAI,GAAG,IAAI,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,cAAc,EAAE,CAAC;YACxD,OAAO,CAAC,GAAG,CAAC,4DAA4D,CAAC,CAAC;YAC1E,OAAO,CAAC,GAAG,CAAC,MAAM,IAAI,EAAE,CAAC,CAAC;YAC1B,OAAO,CAAC,GAAG,CAAC,cAAc,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC;YAC1C,OAAO,CAAC,GAAG,CAAC,cAAc,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC;YAC1C,OAAO,CAAC,GAAG,CAAC,aAAa,KAAK,CAAC,KAAK,CAAC,MAAM,UAAU,CAAC,CAAC;YACvD,OAAO,CAAC,GAAG,CAAC,cAAc,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC;YAC1C,IAAI,KAAK,CAAC,UAAU,EAAE,CAAC;gBACrB,OAAO,CAAC,GAAG,CAAC,cAAc,KAAK,CAAC,UAAU,EAAE,CAAC,CAAC;YAChD,CAAC;YACD,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAClB,CAAC;IACH,CAAC;SAAM,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC;QACrB,MAAM,CAAC,IAAI,CAAC,8BAA8B,IAAI,CAAC,IAAI,SAAS,CAAC,CAAC;QAC9D,MAAM,OAAO,GAAG,IAAA,kCAAiB,EAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAE7C,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACzB,MAAM,CAAC,IAAI,CAAC,uCAAuC,IAAI,CAAC,IAAI,SAAS,CAAC,CAAC;YACvE,OAAO;QACT,CAAC;QAED,OAAO,CAAC,GAAG,CAAC,WAAW,OAAO,CAAC,MAAM,2BAA2B,IAAI,CAAC,IAAI,YAAY,CAAC,CAAC;QACvF,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;YAC5B,MAAM,IAAI,GAAG,IAAI,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,cAAc,EAAE,CAAC;YACxD,OAAO,CAAC,GAAG,CAAC,4DAA4D,CAAC,CAAC;YAC1E,OAAO,CAAC,GAAG,CAAC,MAAM,KAAK,CAAC,MAAM,KAAK,KAAK,CAAC,KAAK,GAAG,CAAC,CAAC;YACnD,OAAO,CAAC,GAAG,CAAC,MAAM,IAAI,EAAE,CAAC,CAAC;YAC1B,OAAO,CAAC,GAAG,CAAC,cAAc,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC;YAC1C,OAAO,CAAC,GAAG,CAAC,cAAc,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC;YAC1C,OAAO,CAAC,GAAG,CAAC,cAAc,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC;YAC1C,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAClB,CAAC;IACH,CAAC;SAAM,CAAC;QACN,mBAAmB;QACnB,MAAM,MAAM,GAAG,IAAA,qCAAoB,GAAE,CAAC;QACtC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;IACtB,CAAC;AACH,CAAC;AAED,IAAI,EAAE,CAAC"}
package/package.json ADDED
@@ -0,0 +1,74 @@
1
+ {
2
+ "name": "@hatem427/code-guard-ci",
3
+ "version": "1.0.0",
4
+ "description": "Production-ready TypeScript tooling to enforce PR & coding guidelines for Angular, React, and NextJS projects.",
5
+ "private": false,
6
+ "main": "dist/scripts/cli.js",
7
+ "types": "dist/scripts/cli.d.ts",
8
+ "bin": {
9
+ "code-guard": "dist/scripts/cli.js"
10
+ },
11
+ "files": [
12
+ "dist",
13
+ "config",
14
+ "scripts",
15
+ "templates",
16
+ ".husky",
17
+ "README.md",
18
+ "LICENSE"
19
+ ],
20
+ "scripts": {
21
+ "build": "tsc && chmod +x dist/scripts/cli.js",
22
+ "precommit-check": "ts-node scripts/precommit-check.ts",
23
+ "auto-fix": "ts-node scripts/auto-fix.ts",
24
+ "generate-doc": "ts-node scripts/generate-doc.ts",
25
+ "generate-pr-checklist": "ts-node scripts/generate-pr-checklist.ts",
26
+ "set-bypass-password": "ts-node scripts/set-bypass-password.ts",
27
+ "set-admin-password": "ts-node scripts/set-admin-password.ts",
28
+ "view-bypass-log": "ts-node scripts/view-bypass-log.ts",
29
+ "delete-bypass-logs": "ts-node scripts/delete-bypass-logs.ts",
30
+ "prepare": "husky install",
31
+ "lint": "eslint . --ext .ts,.tsx,.js,.jsx",
32
+ "format": "prettier --write .",
33
+ "prepublishOnly": "npm run build"
34
+ },
35
+ "keywords": [
36
+ "code-quality",
37
+ "pre-commit",
38
+ "git-hooks",
39
+ "angular",
40
+ "react",
41
+ "nextjs",
42
+ "typescript",
43
+ "eslint",
44
+ "prettier",
45
+ "coding-standards",
46
+ "pr-checklist",
47
+ "documentation"
48
+ ],
49
+ "author": "Hatem Bassem",
50
+ "license": "MIT",
51
+ "repository": {
52
+ "type": "git",
53
+ "url": "git+https://github.com/Elsaadany427/code-guard.git"
54
+ },
55
+ "bugs": {
56
+ "url": "https://github.com/Elsaadany427/code-guard/issues"
57
+ },
58
+ "homepage": "https://github.com/Elsaadany427/code-guard#readme",
59
+ "devDependencies": {
60
+ "@types/glob": "^8.1.0",
61
+ "@types/node": "^20.11.0",
62
+ "chalk": "^4.1.2",
63
+ "eslint": "^8.56.0",
64
+ "glob": "^10.3.10",
65
+ "husky": "^9.0.0",
66
+ "prettier": "^3.2.0",
67
+ "ts-morph": "^21.0.0",
68
+ "ts-node": "^10.9.2",
69
+ "typescript": "^5.3.3"
70
+ },
71
+ "engines": {
72
+ "node": ">=18.0.0"
73
+ }
74
+ }
@@ -0,0 +1,115 @@
1
+ #!/usr/bin/env ts-node
2
+ /**
3
+ * ============================================================================
4
+ * auto-fix.ts — Automatically fix code violations
5
+ * ============================================================================
6
+ *
7
+ * Attempts to automatically fix common code violations.
8
+ *
9
+ * Usage:
10
+ * npm run auto-fix
11
+ * npm run auto-fix -- --dry-run
12
+ */
13
+
14
+ import { detectProject } from './utils/project-detector';
15
+ import { getStagedFiles, readStagedFiles } from './utils/file-checker';
16
+ import { getRulesForProject } from '../config/guidelines.config';
17
+ import { executeRules, printReport } from './utils/rule-engine';
18
+ import { autoFixAll } from './utils/auto-fixer';
19
+ import * as logger from './utils/logger';
20
+
21
+ // Load configs
22
+ import '../config/angular.config';
23
+ import '../config/react.config';
24
+ import '../config/nextjs.config';
25
+
26
+ const CHECKABLE_EXTENSIONS = ['ts', 'tsx', 'js', 'jsx', 'html', 'css', 'scss', 'sass', 'less'];
27
+
28
+ function parseArgs(): { dryRun: boolean } {
29
+ const args = process.argv.slice(2);
30
+ return {
31
+ dryRun: args.includes('--dry-run'),
32
+ };
33
+ }
34
+
35
+ async function main(): Promise<void> {
36
+ logger.header('šŸ”§ Code Guardian — Auto-Fix');
37
+
38
+ const opts = parseArgs();
39
+
40
+ if (opts.dryRun) {
41
+ logger.info('Dry-run mode: will show what would be fixed without making changes');
42
+ }
43
+
44
+ // Detect project
45
+ const project = detectProject();
46
+ logger.info(`Detected project: ${project.label}`);
47
+
48
+ // Get staged files
49
+ const stagedPaths = getStagedFiles();
50
+ if (stagedPaths.length === 0) {
51
+ logger.info('No staged files found.');
52
+ process.exit(0);
53
+ }
54
+
55
+ logger.info(`Found ${stagedPaths.length} staged file(s).`);
56
+
57
+ // Read files
58
+ const files = readStagedFiles(CHECKABLE_EXTENSIONS);
59
+ if (files.length === 0) {
60
+ logger.info('No checkable files in staging.');
61
+ process.exit(0);
62
+ }
63
+
64
+ // Load rules and execute
65
+ const rules = getRulesForProject(project.type);
66
+ logger.info(`Loaded ${rules.length} rule(s) for ${project.label}.`);
67
+
68
+ const report = executeRules(files, rules, false);
69
+
70
+ if (report.violations.length === 0) {
71
+ logger.success('āœ… No violations found!');
72
+ process.exit(0);
73
+ }
74
+
75
+ logger.info(`Found ${report.violations.length} violation(s).\n`);
76
+
77
+ // Attempt auto-fix
78
+ if (opts.dryRun) {
79
+ logger.info('Would attempt to fix:');
80
+ for (const v of report.violations) {
81
+ console.log(` • ${v.file}:${v.line} [${v.ruleId}]`);
82
+ }
83
+ logger.info('\nRun without --dry-run to apply fixes.');
84
+ } else {
85
+ logger.info('Attempting to auto-fix violations...\n');
86
+
87
+ const fixResults = autoFixAll(report.violations, process.cwd());
88
+
89
+ console.log(`\nšŸ“Š Results:`);
90
+ console.log(` āœ… Fixed: ${fixResults.fixed}`);
91
+ console.log(` āš ļø Manual fix required: ${fixResults.failed}\n`);
92
+
93
+ // Show what couldn't be fixed
94
+ const manualFixes = fixResults.results.filter((r) => !r.result.fixed);
95
+ if (manualFixes.length > 0) {
96
+ logger.warn('The following require manual fixes:');
97
+ for (const { violation, result } of manualFixes) {
98
+ console.log(` • ${violation.file}:${violation.line} [${violation.ruleId}] - ${result.message}`);
99
+ }
100
+ }
101
+
102
+ if (fixResults.fixed > 0) {
103
+ logger.success(`\nāœ… Auto-fixed ${fixResults.fixed} violation(s)!`);
104
+ logger.info('Remember to review changes and re-stage files:');
105
+ logger.dim(' git add .');
106
+ }
107
+ }
108
+
109
+ process.exit(0);
110
+ }
111
+
112
+ main().catch((err) => {
113
+ logger.error(`Unexpected error: ${err.message || err}`);
114
+ process.exit(1);
115
+ });
package/scripts/cli.ts ADDED
@@ -0,0 +1,246 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * ============================================================================
4
+ * cli.ts — Code Guardian CLI entrypoint
5
+ * ============================================================================
6
+ *
7
+ * Main CLI interface when installed as an npm package.
8
+ * Provides commands: init, check, doc, checklist
9
+ *
10
+ * Usage:
11
+ * npx code-guardian init
12
+ * npx code-guardian check
13
+ * npx code-guardian doc --name="feature" --type=ui
14
+ * npx code-guardian checklist
15
+ */
16
+
17
+ import * as fs from 'fs';
18
+ import * as path from 'path';
19
+ import { execSync } from 'child_process';
20
+
21
+ const VERSION = '1.0.0';
22
+
23
+ // ── CLI argument parsing ────────────────────────────────────────────────────
24
+
25
+ const args = process.argv.slice(2);
26
+ const command = args[0];
27
+
28
+ // ── Commands ────────────────────────────────────────────────────────────────
29
+
30
+ function showHelp(): void {
31
+ console.log(`
32
+ šŸ›”ļø Code Guardian v${VERSION}
33
+
34
+ Usage:
35
+ code-guardian <command> [options]
36
+
37
+ Commands:
38
+ init Setup Code Guardian in current project
39
+ check Run pre-commit checks manually
40
+ doc Generate feature documentation
41
+ checklist Generate PR checklist
42
+ help Show this help message
43
+ version Show version
44
+
45
+ Examples:
46
+ code-guardian init
47
+ code-guardian check
48
+ code-guardian doc --name="user-card" --type=ui
49
+ code-guardian checklist --project=angular
50
+
51
+ For more info: https://github.com/team/code-guardian
52
+ `);
53
+ }
54
+
55
+ function showVersion(): void {
56
+ console.log(`Code Guardian v${VERSION}`);
57
+ }
58
+
59
+ /**
60
+ * Initialize Code Guardian in the current project.
61
+ * Copies config files, templates, and sets up Husky.
62
+ */
63
+ function initProject(): void {
64
+ console.log('šŸ›”ļø Initializing Code Guardian...\n');
65
+
66
+ const cwd = process.cwd();
67
+ const packageJsonPath = path.join(cwd, 'package.json');
68
+
69
+ // Check if package.json exists
70
+ if (!fs.existsSync(packageJsonPath)) {
71
+ console.error('āŒ Error: No package.json found in current directory.');
72
+ console.error(' Run this command from your project root.');
73
+ process.exit(1);
74
+ }
75
+
76
+ // Determine the source directory (where code-guardian is installed)
77
+ const sourceDir = path.join(__dirname, '..');
78
+
79
+ // Copy config files
80
+ console.log('šŸ“ Copying configuration files...');
81
+ const configDir = path.join(cwd, 'config');
82
+ if (!fs.existsSync(configDir)) {
83
+ fs.mkdirSync(configDir, { recursive: true });
84
+ }
85
+
86
+ const configFiles = ['guidelines.config.ts', 'angular.config.ts', 'react.config.ts', 'nextjs.config.ts'];
87
+ for (const file of configFiles) {
88
+ const src = path.join(sourceDir, 'config', file);
89
+ const dest = path.join(configDir, file);
90
+ if (fs.existsSync(src)) {
91
+ fs.copyFileSync(src, dest);
92
+ console.log(` āœ“ ${file}`);
93
+ }
94
+ }
95
+
96
+ // Copy templates
97
+ console.log('\nšŸ“„ Copying documentation templates...');
98
+ const templatesDir = path.join(cwd, 'templates');
99
+ if (!fs.existsSync(templatesDir)) {
100
+ fs.mkdirSync(templatesDir, { recursive: true });
101
+ }
102
+
103
+ const templateFiles = ['feature-doc-ui.md', 'feature-doc-api.md', 'feature-doc-service.md'];
104
+ for (const file of templateFiles) {
105
+ const src = path.join(sourceDir, 'templates', file);
106
+ const dest = path.join(templatesDir, file);
107
+ if (fs.existsSync(src)) {
108
+ fs.copyFileSync(src, dest);
109
+ console.log(` āœ“ ${file}`);
110
+ }
111
+ }
112
+
113
+ // Create docs/features directory
114
+ const docsDir = path.join(cwd, 'docs', 'features');
115
+ if (!fs.existsSync(docsDir)) {
116
+ fs.mkdirSync(docsDir, { recursive: true });
117
+ fs.writeFileSync(path.join(docsDir, '.gitkeep'), '');
118
+ console.log('\nšŸ“‚ Created docs/features directory');
119
+ }
120
+
121
+ // Update package.json scripts
122
+ console.log('\nšŸ“ Updating package.json scripts...');
123
+ const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf-8'));
124
+
125
+ packageJson.scripts = packageJson.scripts || {};
126
+ packageJson.scripts['precommit-check'] = 'code-guardian check';
127
+ packageJson.scripts['generate-doc'] = 'code-guardian doc';
128
+ packageJson.scripts['generate-pr-checklist'] = 'code-guardian checklist';
129
+
130
+ fs.writeFileSync(packageJsonPath, JSON.stringify(packageJson, null, 2) + '\n');
131
+ console.log(' āœ“ Added npm scripts');
132
+
133
+ // Setup Husky
134
+ console.log('\n🐶 Setting up Husky...');
135
+ try {
136
+ execSync('npx husky install', { stdio: 'inherit', cwd });
137
+ execSync('npx husky add .husky/pre-commit "npm run precommit-check"', { stdio: 'inherit', cwd });
138
+ console.log(' āœ“ Husky configured');
139
+ } catch (error) {
140
+ console.warn(' āš ļø Husky setup failed. You may need to run "npx husky install" manually.');
141
+ }
142
+
143
+ console.log('\nāœ… Code Guardian initialized successfully!\n');
144
+ console.log('Next steps:');
145
+ console.log(' 1. Review config files in ./config/');
146
+ console.log(' 2. Customize rules for your team');
147
+ console.log(' 3. Make a commit to test the pre-commit hook');
148
+ console.log(' 4. Run "npm run generate-doc -- --name=test --type=ui" to test doc generation\n');
149
+ }
150
+
151
+ /**
152
+ * Run pre-commit checks manually.
153
+ */
154
+ function runCheck(): void {
155
+ const scriptPath = path.join(__dirname, 'precommit-check.js');
156
+ if (fs.existsSync(scriptPath)) {
157
+ require(scriptPath);
158
+ } else {
159
+ // Fallback: try to run from source
160
+ const tsScriptPath = path.join(__dirname, '..', 'scripts', 'precommit-check.ts');
161
+ if (fs.existsSync(tsScriptPath)) {
162
+ execSync(`npx ts-node ${tsScriptPath}`, { stdio: 'inherit' });
163
+ } else {
164
+ console.error('āŒ Error: Could not find precommit-check script.');
165
+ process.exit(1);
166
+ }
167
+ }
168
+ }
169
+
170
+ /**
171
+ * Generate feature documentation.
172
+ */
173
+ function generateDoc(): void {
174
+ const scriptPath = path.join(__dirname, 'generate-doc.js');
175
+ const scriptArgs = args.slice(1).join(' ');
176
+
177
+ if (fs.existsSync(scriptPath)) {
178
+ execSync(`node ${scriptPath} ${scriptArgs}`, { stdio: 'inherit' });
179
+ } else {
180
+ const tsScriptPath = path.join(__dirname, '..', 'scripts', 'generate-doc.ts');
181
+ if (fs.existsSync(tsScriptPath)) {
182
+ execSync(`npx ts-node ${tsScriptPath} ${scriptArgs}`, { stdio: 'inherit' });
183
+ } else {
184
+ console.error('āŒ Error: Could not find generate-doc script.');
185
+ process.exit(1);
186
+ }
187
+ }
188
+ }
189
+
190
+ /**
191
+ * Generate PR checklist.
192
+ */
193
+ function generateChecklist(): void {
194
+ const scriptPath = path.join(__dirname, 'generate-pr-checklist.js');
195
+ const scriptArgs = args.slice(1).join(' ');
196
+
197
+ if (fs.existsSync(scriptPath)) {
198
+ execSync(`node ${scriptPath} ${scriptArgs}`, { stdio: 'inherit' });
199
+ } else {
200
+ const tsScriptPath = path.join(__dirname, '..', 'scripts', 'generate-pr-checklist.ts');
201
+ if (fs.existsSync(tsScriptPath)) {
202
+ execSync(`npx ts-node ${tsScriptPath} ${scriptArgs}`, { stdio: 'inherit' });
203
+ } else {
204
+ console.error('āŒ Error: Could not find generate-pr-checklist script.');
205
+ process.exit(1);
206
+ }
207
+ }
208
+ }
209
+
210
+ // ── Main ────────────────────────────────────────────────────────────────────
211
+
212
+ switch (command) {
213
+ case 'init':
214
+ initProject();
215
+ break;
216
+
217
+ case 'check':
218
+ runCheck();
219
+ break;
220
+
221
+ case 'doc':
222
+ generateDoc();
223
+ break;
224
+
225
+ case 'checklist':
226
+ generateChecklist();
227
+ break;
228
+
229
+ case 'version':
230
+ case '--version':
231
+ case '-v':
232
+ showVersion();
233
+ break;
234
+
235
+ case 'help':
236
+ case '--help':
237
+ case '-h':
238
+ case undefined:
239
+ showHelp();
240
+ break;
241
+
242
+ default:
243
+ console.error(`āŒ Unknown command: ${command}`);
244
+ console.error('Run "code-guardian help" for usage information.');
245
+ process.exit(1);
246
+ }