@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.
- package/.husky/pre-commit +27 -0
- package/LICENSE +21 -0
- package/README.md +646 -0
- package/config/angular.config.ts +223 -0
- package/config/guidelines.config.ts +229 -0
- package/config/nextjs.config.ts +160 -0
- package/config/react.config.ts +330 -0
- package/dist/config/angular.config.d.ts +15 -0
- package/dist/config/angular.config.d.ts.map +1 -0
- package/dist/config/angular.config.js +187 -0
- package/dist/config/angular.config.js.map +1 -0
- package/dist/config/guidelines.config.d.ts +63 -0
- package/dist/config/guidelines.config.d.ts.map +1 -0
- package/dist/config/guidelines.config.js +167 -0
- package/dist/config/guidelines.config.js.map +1 -0
- package/dist/config/nextjs.config.d.ts +18 -0
- package/dist/config/nextjs.config.d.ts.map +1 -0
- package/dist/config/nextjs.config.js +133 -0
- package/dist/config/nextjs.config.js.map +1 -0
- package/dist/config/react.config.d.ts +15 -0
- package/dist/config/react.config.d.ts.map +1 -0
- package/dist/config/react.config.js +287 -0
- package/dist/config/react.config.js.map +1 -0
- package/dist/scripts/auto-fix.d.ts +16 -0
- package/dist/scripts/auto-fix.d.ts.map +1 -0
- package/dist/scripts/auto-fix.js +130 -0
- package/dist/scripts/auto-fix.js.map +1 -0
- package/dist/scripts/cli.d.ts +17 -0
- package/dist/scripts/cli.d.ts.map +1 -0
- package/dist/scripts/cli.js +255 -0
- package/dist/scripts/cli.js.map +1 -0
- package/dist/scripts/delete-bypass-logs.d.ts +17 -0
- package/dist/scripts/delete-bypass-logs.d.ts.map +1 -0
- package/dist/scripts/delete-bypass-logs.js +242 -0
- package/dist/scripts/delete-bypass-logs.js.map +1 -0
- package/dist/scripts/generate-doc.d.ts +18 -0
- package/dist/scripts/generate-doc.d.ts.map +1 -0
- package/dist/scripts/generate-doc.js +300 -0
- package/dist/scripts/generate-doc.js.map +1 -0
- package/dist/scripts/generate-pr-checklist.d.ts +20 -0
- package/dist/scripts/generate-pr-checklist.d.ts.map +1 -0
- package/dist/scripts/generate-pr-checklist.js +276 -0
- package/dist/scripts/generate-pr-checklist.js.map +1 -0
- package/dist/scripts/precommit-check.d.ts +23 -0
- package/dist/scripts/precommit-check.d.ts.map +1 -0
- package/dist/scripts/precommit-check.js +331 -0
- package/dist/scripts/precommit-check.js.map +1 -0
- package/dist/scripts/set-admin-password.d.ts +14 -0
- package/dist/scripts/set-admin-password.d.ts.map +1 -0
- package/dist/scripts/set-admin-password.js +116 -0
- package/dist/scripts/set-admin-password.js.map +1 -0
- package/dist/scripts/set-bypass-password.d.ts +11 -0
- package/dist/scripts/set-bypass-password.d.ts.map +1 -0
- package/dist/scripts/set-bypass-password.js +106 -0
- package/dist/scripts/set-bypass-password.js.map +1 -0
- package/dist/scripts/utils/auto-fixer.d.ts +28 -0
- package/dist/scripts/utils/auto-fixer.d.ts.map +1 -0
- package/dist/scripts/utils/auto-fixer.js +177 -0
- package/dist/scripts/utils/auto-fixer.js.map +1 -0
- package/dist/scripts/utils/bypass-manager.d.ts +101 -0
- package/dist/scripts/utils/bypass-manager.d.ts.map +1 -0
- package/dist/scripts/utils/bypass-manager.js +496 -0
- package/dist/scripts/utils/bypass-manager.js.map +1 -0
- package/dist/scripts/utils/code-analyzer.d.ts +34 -0
- package/dist/scripts/utils/code-analyzer.d.ts.map +1 -0
- package/dist/scripts/utils/code-analyzer.js +323 -0
- package/dist/scripts/utils/code-analyzer.js.map +1 -0
- package/dist/scripts/utils/file-checker.d.ts +93 -0
- package/dist/scripts/utils/file-checker.d.ts.map +1 -0
- package/dist/scripts/utils/file-checker.js +248 -0
- package/dist/scripts/utils/file-checker.js.map +1 -0
- package/dist/scripts/utils/logger.d.ts +26 -0
- package/dist/scripts/utils/logger.d.ts.map +1 -0
- package/dist/scripts/utils/logger.js +86 -0
- package/dist/scripts/utils/logger.js.map +1 -0
- package/dist/scripts/utils/project-detector.d.ts +34 -0
- package/dist/scripts/utils/project-detector.d.ts.map +1 -0
- package/dist/scripts/utils/project-detector.js +124 -0
- package/dist/scripts/utils/project-detector.js.map +1 -0
- package/dist/scripts/utils/rule-engine.d.ts +57 -0
- package/dist/scripts/utils/rule-engine.d.ts.map +1 -0
- package/dist/scripts/utils/rule-engine.js +158 -0
- package/dist/scripts/utils/rule-engine.js.map +1 -0
- package/dist/scripts/view-bypass-log.d.ts +13 -0
- package/dist/scripts/view-bypass-log.d.ts.map +1 -0
- package/dist/scripts/view-bypass-log.js +117 -0
- package/dist/scripts/view-bypass-log.js.map +1 -0
- package/package.json +74 -0
- package/scripts/auto-fix.ts +115 -0
- package/scripts/cli.ts +246 -0
- package/scripts/delete-bypass-logs.ts +253 -0
- package/scripts/generate-doc.ts +317 -0
- package/scripts/generate-pr-checklist.ts +285 -0
- package/scripts/precommit-check.ts +349 -0
- package/scripts/set-admin-password.ts +90 -0
- package/scripts/set-bypass-password.ts +80 -0
- package/scripts/utils/auto-fixer.ts +181 -0
- package/scripts/utils/bypass-manager.ts +566 -0
- package/scripts/utils/code-analyzer.ts +341 -0
- package/scripts/utils/file-checker.ts +253 -0
- package/scripts/utils/logger.ts +88 -0
- package/scripts/utils/project-detector.ts +115 -0
- package/scripts/utils/rule-engine.ts +186 -0
- package/scripts/view-bypass-log.ts +92 -0
- package/templates/feature-doc-api.md +101 -0
- package/templates/feature-doc-service.md +113 -0
- package/templates/feature-doc-ui.md +91 -0
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ============================================================================
|
|
3
|
+
* project-detector.ts โ Automatically detect the frontend framework in use
|
|
4
|
+
* ============================================================================
|
|
5
|
+
*
|
|
6
|
+
* Inspects the project's package.json and file system to determine whether the
|
|
7
|
+
* current repository uses Angular, React, NextJS, or an unknown framework.
|
|
8
|
+
* This drives which set of coding rules should be enforced.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import * as fs from 'fs';
|
|
12
|
+
import * as path from 'path';
|
|
13
|
+
|
|
14
|
+
// โโ Supported project types โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
|
15
|
+
|
|
16
|
+
export type ProjectType = 'angular' | 'react' | 'nextjs' | 'unknown';
|
|
17
|
+
|
|
18
|
+
export interface DetectionResult {
|
|
19
|
+
/** Which framework was detected */
|
|
20
|
+
type: ProjectType;
|
|
21
|
+
/** Human-readable label for logging */
|
|
22
|
+
label: string;
|
|
23
|
+
/** Root directory of the project */
|
|
24
|
+
rootDir: string;
|
|
25
|
+
/** package.json contents (parsed) */
|
|
26
|
+
packageJson: Record<string, any>;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// โโ Detection logic โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Read the nearest package.json starting from `startDir` and walking up.
|
|
33
|
+
* Returns the parsed contents and the directory that contained it.
|
|
34
|
+
*/
|
|
35
|
+
function findPackageJson(startDir: string): { dir: string; pkg: Record<string, any> } | null {
|
|
36
|
+
let current = path.resolve(startDir);
|
|
37
|
+
|
|
38
|
+
while (true) {
|
|
39
|
+
const candidate = path.join(current, 'package.json');
|
|
40
|
+
if (fs.existsSync(candidate)) {
|
|
41
|
+
try {
|
|
42
|
+
const content = fs.readFileSync(candidate, 'utf-8');
|
|
43
|
+
return { dir: current, pkg: JSON.parse(content) };
|
|
44
|
+
} catch {
|
|
45
|
+
// Malformed JSON โ keep walking
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const parent = path.dirname(current);
|
|
50
|
+
if (parent === current) break; // reached filesystem root
|
|
51
|
+
current = parent;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
return null;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Check whether a dependency name exists in `dependencies` or
|
|
59
|
+
* `devDependencies` of the given package.json object.
|
|
60
|
+
*/
|
|
61
|
+
function hasDep(pkg: Record<string, any>, name: string): boolean {
|
|
62
|
+
return !!(pkg.dependencies?.[name] || pkg.devDependencies?.[name]);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Detect the project type based on the nearest package.json.
|
|
67
|
+
*
|
|
68
|
+
* Priority order (first match wins):
|
|
69
|
+
* 1. NextJS โ has `next` as a dependency
|
|
70
|
+
* 2. Angular โ has `@angular/core` as a dependency
|
|
71
|
+
* 3. React โ has `react` as a dependency
|
|
72
|
+
* 4. Unknown โ none of the above
|
|
73
|
+
*
|
|
74
|
+
* NextJS is checked first because it also pulls in React, so we want
|
|
75
|
+
* the more specific framework to win.
|
|
76
|
+
*/
|
|
77
|
+
export function detectProject(startDir: string = process.cwd()): DetectionResult {
|
|
78
|
+
const result = findPackageJson(startDir);
|
|
79
|
+
|
|
80
|
+
if (!result) {
|
|
81
|
+
return {
|
|
82
|
+
type: 'unknown',
|
|
83
|
+
label: 'Unknown Project',
|
|
84
|
+
rootDir: startDir,
|
|
85
|
+
packageJson: {},
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
const { dir, pkg } = result;
|
|
90
|
+
|
|
91
|
+
// NextJS check (must come before React โ NextJS depends on React)
|
|
92
|
+
if (hasDep(pkg, 'next')) {
|
|
93
|
+
return { type: 'nextjs', label: 'Next.js', rootDir: dir, packageJson: pkg };
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// Angular check
|
|
97
|
+
if (hasDep(pkg, '@angular/core')) {
|
|
98
|
+
return { type: 'angular', label: 'Angular', rootDir: dir, packageJson: pkg };
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// React check
|
|
102
|
+
if (hasDep(pkg, 'react')) {
|
|
103
|
+
return { type: 'react', label: 'React', rootDir: dir, packageJson: pkg };
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// Fallback โ additional heuristics
|
|
107
|
+
if (fs.existsSync(path.join(dir, 'angular.json'))) {
|
|
108
|
+
return { type: 'angular', label: 'Angular (heuristic)', rootDir: dir, packageJson: pkg };
|
|
109
|
+
}
|
|
110
|
+
if (fs.existsSync(path.join(dir, 'next.config.js')) || fs.existsSync(path.join(dir, 'next.config.mjs'))) {
|
|
111
|
+
return { type: 'nextjs', label: 'Next.js (heuristic)', rootDir: dir, packageJson: pkg };
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
return { type: 'unknown', label: 'Unknown Project', rootDir: dir, packageJson: pkg };
|
|
115
|
+
}
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ============================================================================
|
|
3
|
+
* rule-engine.ts โ Orchestrates rule execution against a set of files
|
|
4
|
+
* ============================================================================
|
|
5
|
+
*
|
|
6
|
+
* The rule engine is the core processor. It takes a list of files and a list
|
|
7
|
+
* of rules, then runs each rule against each applicable file. Results are
|
|
8
|
+
* collected into a structured report.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import { Rule, Severity } from '../../config/guidelines.config';
|
|
12
|
+
import { FileInfo, findMatches, hasInlineSuppression } from './file-checker';
|
|
13
|
+
import * as logger from './logger';
|
|
14
|
+
|
|
15
|
+
// โโ Result types โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
|
16
|
+
|
|
17
|
+
export interface Violation {
|
|
18
|
+
/** The file where the violation was found */
|
|
19
|
+
file: string;
|
|
20
|
+
/** 1-based line number (null for file-level violations) */
|
|
21
|
+
line: number | null;
|
|
22
|
+
/** The rule that was violated */
|
|
23
|
+
ruleId: string;
|
|
24
|
+
/** Human-readable label */
|
|
25
|
+
ruleLabel: string;
|
|
26
|
+
/** Description of the violation */
|
|
27
|
+
message: string;
|
|
28
|
+
/** How severe is this? */
|
|
29
|
+
severity: Severity;
|
|
30
|
+
/** Category for grouping */
|
|
31
|
+
category: string;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export interface RuleEngineReport {
|
|
35
|
+
/** All violations found */
|
|
36
|
+
violations: Violation[];
|
|
37
|
+
/** Total number of error-severity violations */
|
|
38
|
+
errorCount: number;
|
|
39
|
+
/** Total number of warning-severity violations */
|
|
40
|
+
warningCount: number;
|
|
41
|
+
/** Total number of info-severity violations */
|
|
42
|
+
infoCount: number;
|
|
43
|
+
/** How many files were checked */
|
|
44
|
+
filesChecked: number;
|
|
45
|
+
/** How many rules were executed */
|
|
46
|
+
rulesExecuted: number;
|
|
47
|
+
/** Was the check bypassed? */
|
|
48
|
+
bypassed: boolean;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// โโ Engine โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Run all `rules` against all `files` and collect a report.
|
|
55
|
+
*
|
|
56
|
+
* @param files - The list of files to check (usually staged files).
|
|
57
|
+
* @param rules - The list of rules to apply.
|
|
58
|
+
* @param verbose - If true, logs each rule as it runs.
|
|
59
|
+
* @returns A structured report of all findings.
|
|
60
|
+
*/
|
|
61
|
+
export function executeRules(
|
|
62
|
+
files: FileInfo[],
|
|
63
|
+
rules: Rule[],
|
|
64
|
+
verbose: boolean = false
|
|
65
|
+
): RuleEngineReport {
|
|
66
|
+
const violations: Violation[] = [];
|
|
67
|
+
let rulesExecuted = 0;
|
|
68
|
+
|
|
69
|
+
for (const rule of rules) {
|
|
70
|
+
rulesExecuted++;
|
|
71
|
+
|
|
72
|
+
if (verbose) {
|
|
73
|
+
logger.dim(`Running rule: ${rule.id} โ ${rule.label}`);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
for (const file of files) {
|
|
77
|
+
// โโ Extension filter โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
|
78
|
+
if (
|
|
79
|
+
rule.fileExtensions.length > 0 &&
|
|
80
|
+
!rule.fileExtensions.includes(file.extension)
|
|
81
|
+
) {
|
|
82
|
+
continue;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// โโ Regex-based check โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
|
86
|
+
if (rule.pattern) {
|
|
87
|
+
const matches = findMatches(file, rule.pattern);
|
|
88
|
+
|
|
89
|
+
for (const match of matches) {
|
|
90
|
+
// Check for inline suppression
|
|
91
|
+
if (hasInlineSuppression(file, rule.id, match.line)) {
|
|
92
|
+
continue;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
violations.push({
|
|
96
|
+
file: file.relativePath,
|
|
97
|
+
line: match.line,
|
|
98
|
+
ruleId: rule.id,
|
|
99
|
+
ruleLabel: rule.label,
|
|
100
|
+
message: `${rule.description} (found: "${match.text.substring(0, 80)}")`,
|
|
101
|
+
severity: rule.severity,
|
|
102
|
+
category: rule.category,
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// โโ Custom check โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
|
108
|
+
if (rule.customCheck) {
|
|
109
|
+
const customViolations = rule.customCheck(file);
|
|
110
|
+
|
|
111
|
+
for (const cv of customViolations) {
|
|
112
|
+
// Check for inline suppression (if there's a line number)
|
|
113
|
+
if (cv.line && hasInlineSuppression(file, rule.id, cv.line)) {
|
|
114
|
+
continue;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
violations.push({
|
|
118
|
+
file: file.relativePath,
|
|
119
|
+
line: cv.line,
|
|
120
|
+
ruleId: rule.id,
|
|
121
|
+
ruleLabel: rule.label,
|
|
122
|
+
message: cv.message,
|
|
123
|
+
severity: rule.severity,
|
|
124
|
+
category: rule.category,
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// โโ Count by severity โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
|
132
|
+
|
|
133
|
+
const errorCount = violations.filter((v) => v.severity === 'error').length;
|
|
134
|
+
const warningCount = violations.filter((v) => v.severity === 'warning').length;
|
|
135
|
+
const infoCount = violations.filter((v) => v.severity === 'info').length;
|
|
136
|
+
|
|
137
|
+
return {
|
|
138
|
+
violations,
|
|
139
|
+
errorCount,
|
|
140
|
+
warningCount,
|
|
141
|
+
infoCount,
|
|
142
|
+
filesChecked: files.length,
|
|
143
|
+
rulesExecuted,
|
|
144
|
+
bypassed: false,
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* Display a pretty-printed report in the terminal.
|
|
150
|
+
*/
|
|
151
|
+
export function printReport(report: RuleEngineReport): void {
|
|
152
|
+
if (report.bypassed) {
|
|
153
|
+
logger.warn('Rules bypassed โ skipping checks.');
|
|
154
|
+
return;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
logger.header(`Code Guardian Report โ ${report.filesChecked} file(s), ${report.rulesExecuted} rule(s)`);
|
|
158
|
+
|
|
159
|
+
if (report.violations.length === 0) {
|
|
160
|
+
logger.success('No violations found!');
|
|
161
|
+
logger.summary(0, 0);
|
|
162
|
+
return;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
// Group violations by category
|
|
166
|
+
const byCategory = new Map<string, Violation[]>();
|
|
167
|
+
for (const v of report.violations) {
|
|
168
|
+
const existing = byCategory.get(v.category) || [];
|
|
169
|
+
existing.push(v);
|
|
170
|
+
byCategory.set(v.category, existing);
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
for (const [category, items] of byCategory) {
|
|
174
|
+
console.log(`\n ๐ ${category}`);
|
|
175
|
+
|
|
176
|
+
for (const v of items) {
|
|
177
|
+
logger.violation(v.file, v.line, v.ruleId, v.message);
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
logger.summary(report.errorCount, report.warningCount);
|
|
182
|
+
|
|
183
|
+
if (report.infoCount > 0) {
|
|
184
|
+
logger.info(`${report.infoCount} informational notice(s) โ consider addressing them.`);
|
|
185
|
+
}
|
|
186
|
+
}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
#!/usr/bin/env ts-node
|
|
2
|
+
/**
|
|
3
|
+
* ============================================================================
|
|
4
|
+
* view-bypass-log.ts โ View bypass audit log
|
|
5
|
+
* ============================================================================
|
|
6
|
+
*
|
|
7
|
+
* Usage:
|
|
8
|
+
* npm run view-bypass-log
|
|
9
|
+
* npm run view-bypass-log -- --author="john@example.com"
|
|
10
|
+
* npm run view-bypass-log -- --days=7
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import { generateBypassReport, getBypassesByAuthor, getRecentBypasses } from './utils/bypass-manager';
|
|
14
|
+
import * as logger from './utils/logger';
|
|
15
|
+
|
|
16
|
+
function parseArgs(): { author?: string; days?: number } {
|
|
17
|
+
const args = process.argv.slice(2);
|
|
18
|
+
const opts: { author?: string; days?: number } = {};
|
|
19
|
+
|
|
20
|
+
for (const arg of args) {
|
|
21
|
+
const [key, ...valueParts] = arg.replace(/^--/, '').split('=');
|
|
22
|
+
const value = valueParts.join('=').replace(/^["']|["']$/g, '');
|
|
23
|
+
|
|
24
|
+
switch (key) {
|
|
25
|
+
case 'author':
|
|
26
|
+
opts.author = value;
|
|
27
|
+
break;
|
|
28
|
+
case 'days':
|
|
29
|
+
opts.days = parseInt(value, 10);
|
|
30
|
+
break;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
return opts;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function main() {
|
|
38
|
+
logger.header('๐ Code Guardian โ Bypass Audit Log');
|
|
39
|
+
|
|
40
|
+
const opts = parseArgs();
|
|
41
|
+
|
|
42
|
+
if (opts.author) {
|
|
43
|
+
logger.info(`Filtering by author: ${opts.author}`);
|
|
44
|
+
const entries = getBypassesByAuthor(opts.author);
|
|
45
|
+
|
|
46
|
+
if (entries.length === 0) {
|
|
47
|
+
logger.info(`No bypass entries found for ${opts.author}`);
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
console.log(`\nFound ${entries.length} bypass(es) by ${opts.author}:\n`);
|
|
52
|
+
for (const entry of entries) {
|
|
53
|
+
const date = new Date(entry.timestamp).toLocaleString();
|
|
54
|
+
console.log(`โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ`);
|
|
55
|
+
console.log(`๐
${date}`);
|
|
56
|
+
console.log(`๐ Reason: ${entry.reason}`);
|
|
57
|
+
console.log(`๐ฟ Branch: ${entry.branch}`);
|
|
58
|
+
console.log(`๐ Files: ${entry.files.length} file(s)`);
|
|
59
|
+
console.log(`๐ Method: ${entry.method}`);
|
|
60
|
+
if (entry.commitHash) {
|
|
61
|
+
console.log(`๐ Commit: ${entry.commitHash}`);
|
|
62
|
+
}
|
|
63
|
+
console.log('');
|
|
64
|
+
}
|
|
65
|
+
} else if (opts.days) {
|
|
66
|
+
logger.info(`Showing bypasses from last ${opts.days} day(s)`);
|
|
67
|
+
const entries = getRecentBypasses(opts.days);
|
|
68
|
+
|
|
69
|
+
if (entries.length === 0) {
|
|
70
|
+
logger.info(`No bypass entries found in the last ${opts.days} day(s)`);
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
console.log(`\nFound ${entries.length} bypass(es) in the last ${opts.days} day(s):\n`);
|
|
75
|
+
for (const entry of entries) {
|
|
76
|
+
const date = new Date(entry.timestamp).toLocaleString();
|
|
77
|
+
console.log(`โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ`);
|
|
78
|
+
console.log(`๐ค ${entry.author} <${entry.email}>`);
|
|
79
|
+
console.log(`๐
${date}`);
|
|
80
|
+
console.log(`๐ Reason: ${entry.reason}`);
|
|
81
|
+
console.log(`๐ฟ Branch: ${entry.branch}`);
|
|
82
|
+
console.log(`๐ Method: ${entry.method}`);
|
|
83
|
+
console.log('');
|
|
84
|
+
}
|
|
85
|
+
} else {
|
|
86
|
+
// Show full report
|
|
87
|
+
const report = generateBypassReport();
|
|
88
|
+
console.log(report);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
main();
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
# {{FEATURE_TITLE}} โ API
|
|
2
|
+
|
|
3
|
+
> **Type**: API Endpoint / Route
|
|
4
|
+
> **Created**: {{DATE}}
|
|
5
|
+
> **Author**: {{AUTHOR}}
|
|
6
|
+
> **Status**: ๐ง Draft
|
|
7
|
+
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
## ๐ Description
|
|
11
|
+
|
|
12
|
+
{{DESCRIPTION}}
|
|
13
|
+
|
|
14
|
+
## ๐ Endpoint
|
|
15
|
+
|
|
16
|
+
| Method | Path | Auth Required |
|
|
17
|
+
| ------ | ----------------------- | ------------- |
|
|
18
|
+
| `GET` | `/api/{{FEATURE_NAME}}` | โ
Yes |
|
|
19
|
+
| `POST` | `/api/{{FEATURE_NAME}}` | โ
Yes |
|
|
20
|
+
| _TODO_ | _TODO_ | _TODO_ |
|
|
21
|
+
|
|
22
|
+
## ๐ฅ Request
|
|
23
|
+
|
|
24
|
+
### Headers
|
|
25
|
+
|
|
26
|
+
| Header | Value | Required |
|
|
27
|
+
| --------------- | ------------------ | -------- |
|
|
28
|
+
| `Authorization` | `Bearer <token>` | Yes |
|
|
29
|
+
| `Content-Type` | `application/json` | Yes |
|
|
30
|
+
|
|
31
|
+
### Query Parameters (GET)
|
|
32
|
+
|
|
33
|
+
| Param | Type | Default | Description |
|
|
34
|
+
| -------- | -------- | ------- | ----------------- |
|
|
35
|
+
| `page` | `number` | `1` | Page number |
|
|
36
|
+
| `limit` | `number` | `20` | Items per page |
|
|
37
|
+
| `search` | `string` | `""` | Search query |
|
|
38
|
+
| _TODO_ | _TODO_ | _TODO_ | _Add more params_ |
|
|
39
|
+
|
|
40
|
+
### Request Body (POST/PUT)
|
|
41
|
+
|
|
42
|
+
```typescript
|
|
43
|
+
interface {{FEATURE_TITLE}}Request {
|
|
44
|
+
// TODO: Define request body
|
|
45
|
+
name: string;
|
|
46
|
+
description?: string;
|
|
47
|
+
}
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
### Example Request
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
curl -X POST /api/{{FEATURE_NAME}} \
|
|
54
|
+
-H "Authorization: Bearer <token>" \
|
|
55
|
+
-H "Content-Type: application/json" \
|
|
56
|
+
-d '{"name": "example"}'
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
## ๐ค Response
|
|
60
|
+
|
|
61
|
+
### Success Response (200)
|
|
62
|
+
|
|
63
|
+
```typescript
|
|
64
|
+
interface {{FEATURE_TITLE}}Response {
|
|
65
|
+
success: boolean;
|
|
66
|
+
data: {
|
|
67
|
+
id: string;
|
|
68
|
+
// TODO: Define response shape
|
|
69
|
+
};
|
|
70
|
+
meta?: {
|
|
71
|
+
total: number;
|
|
72
|
+
page: number;
|
|
73
|
+
limit: number;
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
### Error Responses
|
|
79
|
+
|
|
80
|
+
| Status | Code | Description |
|
|
81
|
+
| ------ | ------------------ | ------------------------ |
|
|
82
|
+
| `400` | `VALIDATION_ERROR` | Invalid request body |
|
|
83
|
+
| `401` | `UNAUTHORIZED` | Missing or invalid token |
|
|
84
|
+
| `404` | `NOT_FOUND` | Resource not found |
|
|
85
|
+
| `500` | `INTERNAL_ERROR` | Server error |
|
|
86
|
+
|
|
87
|
+
## ๐ Authorization
|
|
88
|
+
|
|
89
|
+
- Requires authenticated user
|
|
90
|
+
- Role-based access: _TODO: define roles_
|
|
91
|
+
- Rate limiting: _TODO: define limits_
|
|
92
|
+
|
|
93
|
+
## ๐ Notes
|
|
94
|
+
|
|
95
|
+
- _TODO: Add implementation notes_
|
|
96
|
+
- _TODO: Add links to related endpoints_
|
|
97
|
+
- _TODO: Add caching strategy if applicable_
|
|
98
|
+
|
|
99
|
+
---
|
|
100
|
+
|
|
101
|
+
_Generated by Code Guardian โ {{DOC_TYPE}} template_
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
# {{FEATURE_TITLE}} โ Service
|
|
2
|
+
|
|
3
|
+
> **Type**: Service / Business Logic
|
|
4
|
+
> **Created**: {{DATE}}
|
|
5
|
+
> **Author**: {{AUTHOR}}
|
|
6
|
+
> **Status**: ๐ง Draft
|
|
7
|
+
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
## ๐ Description
|
|
11
|
+
|
|
12
|
+
{{DESCRIPTION}}
|
|
13
|
+
|
|
14
|
+
## ๐๏ธ Architecture
|
|
15
|
+
|
|
16
|
+
### Location
|
|
17
|
+
|
|
18
|
+
```
|
|
19
|
+
src/
|
|
20
|
+
โโโ services/
|
|
21
|
+
โ โโโ {{FEATURE_NAME}}/
|
|
22
|
+
โ โโโ {{FEATURE_NAME}}.service.ts # Main service
|
|
23
|
+
โ โโโ {{FEATURE_NAME}}.types.ts # TypeScript interfaces
|
|
24
|
+
โ โโโ {{FEATURE_NAME}}.utils.ts # Helper functions
|
|
25
|
+
โ โโโ {{FEATURE_NAME}}.spec.ts # Unit tests
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
### Dependency Graph
|
|
29
|
+
|
|
30
|
+
```
|
|
31
|
+
{{FEATURE_TITLE}}Service
|
|
32
|
+
โโโ HttpClient / fetch
|
|
33
|
+
โโโ AuthService (injection)
|
|
34
|
+
โโโ LoggingService (injection)
|
|
35
|
+
โโโ ConfigService (injection)
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## ๐ Usage
|
|
39
|
+
|
|
40
|
+
### Angular (Injectable)
|
|
41
|
+
|
|
42
|
+
```typescript
|
|
43
|
+
@Injectable({ providedIn: 'root' })
|
|
44
|
+
export class {{FEATURE_TITLE}}Service {
|
|
45
|
+
private readonly http = inject(HttpClient);
|
|
46
|
+
|
|
47
|
+
getAll(): Observable<{{FEATURE_TITLE}}[]> {
|
|
48
|
+
return this.http.get<{{FEATURE_TITLE}}[]>('/api/{{FEATURE_NAME}}');
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
### React / Next.js (Hook or Module)
|
|
54
|
+
|
|
55
|
+
```typescript
|
|
56
|
+
export function use{{FEATURE_TITLE}}() {
|
|
57
|
+
const [data, setData] = useState<{{FEATURE_TITLE}}[]>([]);
|
|
58
|
+
const [loading, setLoading] = useState(true);
|
|
59
|
+
|
|
60
|
+
useEffect(() => {
|
|
61
|
+
fetch('/api/{{FEATURE_NAME}}')
|
|
62
|
+
.then(res => res.json())
|
|
63
|
+
.then(setData)
|
|
64
|
+
.finally(() => setLoading(false));
|
|
65
|
+
}, []);
|
|
66
|
+
|
|
67
|
+
return { data, loading };
|
|
68
|
+
}
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
## ๐ฅ Inputs / Parameters
|
|
72
|
+
|
|
73
|
+
| Method | Params | Return Type | Description |
|
|
74
|
+
| ----------- | ------------------- | --------------------------- | ------------------- |
|
|
75
|
+
| `getAll()` | `filters?: Filters` | `Observable<T[]>` / `T[]` | Fetch all records |
|
|
76
|
+
| `getById()` | `id: string` | `Observable<T>` / `T` | Fetch single record |
|
|
77
|
+
| `create()` | `data: CreateDTO` | `Observable<T>` / `T` | Create new record |
|
|
78
|
+
| `update()` | `id, data: Partial` | `Observable<T>` / `T` | Update existing |
|
|
79
|
+
| `delete()` | `id: string` | `Observable<void>` / `void` | Delete record |
|
|
80
|
+
|
|
81
|
+
## ๐ค Outputs / Events
|
|
82
|
+
|
|
83
|
+
| Event | Payload | Description |
|
|
84
|
+
| ----------- | -------- | ------------------------------- |
|
|
85
|
+
| `onCreated` | `T` | Emitted after successful create |
|
|
86
|
+
| `onUpdated` | `T` | Emitted after successful update |
|
|
87
|
+
| `onDeleted` | `string` | Emitted after successful delete |
|
|
88
|
+
| `onError` | `Error` | Emitted on any error |
|
|
89
|
+
|
|
90
|
+
## ๐งช Testing
|
|
91
|
+
|
|
92
|
+
```typescript
|
|
93
|
+
describe("{{FEATURE_TITLE}}Service", () => {
|
|
94
|
+
it("should fetch all records", async () => {
|
|
95
|
+
// TODO: Add test implementation
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
it("should handle errors gracefully", async () => {
|
|
99
|
+
// TODO: Add error handling tests
|
|
100
|
+
});
|
|
101
|
+
});
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
## ๐ Notes
|
|
105
|
+
|
|
106
|
+
- _TODO: Add state management considerations_
|
|
107
|
+
- _TODO: Add caching strategy_
|
|
108
|
+
- _TODO: Add retry/error-handling approach_
|
|
109
|
+
- _TODO: Add performance considerations_
|
|
110
|
+
|
|
111
|
+
---
|
|
112
|
+
|
|
113
|
+
_Generated by Code Guardian โ {{DOC_TYPE}} template_
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
# {{FEATURE_TITLE}}
|
|
2
|
+
|
|
3
|
+
> **Type**: UI Component
|
|
4
|
+
> **Created**: {{DATE}}
|
|
5
|
+
> **Author**: {{AUTHOR}}
|
|
6
|
+
> **Status**: ๐ง Draft
|
|
7
|
+
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
## ๐ Description
|
|
11
|
+
|
|
12
|
+
{{DESCRIPTION}}
|
|
13
|
+
|
|
14
|
+
## ๐ผ๏ธ Visual Reference
|
|
15
|
+
|
|
16
|
+
<!-- Add screenshots or Figma links here -->
|
|
17
|
+
|
|
18
|
+
_TODO: Add screenshots_
|
|
19
|
+
|
|
20
|
+
## ๐ Usage
|
|
21
|
+
|
|
22
|
+
### Basic Usage
|
|
23
|
+
|
|
24
|
+
```html
|
|
25
|
+
<!-- Angular -->
|
|
26
|
+
<app-{{FEATURE_NAME}}></app-{{FEATURE_NAME}}>
|
|
27
|
+
|
|
28
|
+
<!-- React / Next.js -->
|
|
29
|
+
<{{FEATURE_TITLE}} />
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
### With Options
|
|
33
|
+
|
|
34
|
+
```html
|
|
35
|
+
<!-- Angular -->
|
|
36
|
+
<app-{{FEATURE_NAME}}
|
|
37
|
+
[variant]="'primary'"
|
|
38
|
+
[size]="'md'"
|
|
39
|
+
(action)="onAction($event)"
|
|
40
|
+
>
|
|
41
|
+
</app-{{FEATURE_NAME}}>
|
|
42
|
+
|
|
43
|
+
<!-- React / Next.js -->
|
|
44
|
+
<{{FEATURE_TITLE}} variant="primary" size="md" onAction={handleAction} />
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
## ๐ฅ Inputs / Props
|
|
48
|
+
|
|
49
|
+
| Name | Type | Default | Description |
|
|
50
|
+
| ---------- | --------- | ----------- | ---------------------------------- |
|
|
51
|
+
| `variant` | `string` | `'default'` | Visual variant: primary, secondary |
|
|
52
|
+
| `size` | `string` | `'md'` | Size: sm, md, lg |
|
|
53
|
+
| `disabled` | `boolean` | `false` | Whether the component is disabled |
|
|
54
|
+
| _TODO_ | _TODO_ | _TODO_ | _Add more inputs as needed_ |
|
|
55
|
+
|
|
56
|
+
## ๐ค Outputs / Events
|
|
57
|
+
|
|
58
|
+
| Name | Payload | Description |
|
|
59
|
+
| -------- | ------- | ------------------------------- |
|
|
60
|
+
| `action` | `Event` | Emitted when the user interacts |
|
|
61
|
+
| _TODO_ | _TODO_ | _Add more outputs as needed_ |
|
|
62
|
+
|
|
63
|
+
## ๐จ Styling
|
|
64
|
+
|
|
65
|
+
- Uses **Tailwind CSS** utility classes
|
|
66
|
+
- Supports dark mode via `dark:` variants
|
|
67
|
+
- Responsive breakpoints: `sm`, `md`, `lg`, `xl`
|
|
68
|
+
|
|
69
|
+
### CSS Custom Properties
|
|
70
|
+
|
|
71
|
+
```css
|
|
72
|
+
/* Override defaults in parent context */
|
|
73
|
+
--{{FEATURE_NAME}}-bg: theme('colors.white');
|
|
74
|
+
--{{FEATURE_NAME}}-border: theme('colors.gray.200');
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
## โฟ Accessibility
|
|
78
|
+
|
|
79
|
+
- [ ] Keyboard navigable
|
|
80
|
+
- [ ] Screen reader compatible (aria labels)
|
|
81
|
+
- [ ] Focus indicators visible
|
|
82
|
+
- [ ] Color contrast meets WCAG AA
|
|
83
|
+
|
|
84
|
+
## ๐ Notes
|
|
85
|
+
|
|
86
|
+
- _TODO: Add implementation notes, caveats, or known limitations._
|
|
87
|
+
- _TODO: Add links to related components or documentation._
|
|
88
|
+
|
|
89
|
+
---
|
|
90
|
+
|
|
91
|
+
_Generated by Code Guardian โ {{DOC_TYPE}} template_
|