@sun-asterisk/sunlint 1.3.34 → 1.3.35
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/core/architecture-integration.js +16 -7
- package/core/auto-performance-manager.js +1 -1
- package/core/cli-action-handler.js +92 -2
- package/core/cli-program.js +96 -138
- package/core/file-targeting-service.js +62 -4
- package/core/git-utils.js +19 -12
- package/core/github-annotate-service.js +326 -11
- package/core/html-report-generator.js +326 -731
- package/core/impact-integration.js +433 -0
- package/core/output-service.js +293 -21
- package/core/scoring-service.js +3 -2
- package/engines/arch-detect/core/analyzer.js +413 -0
- package/engines/arch-detect/core/index.js +22 -0
- package/engines/arch-detect/engine/hybrid-detector.js +176 -0
- package/engines/arch-detect/engine/index.js +24 -0
- package/engines/arch-detect/engine/rule-executor.js +228 -0
- package/engines/arch-detect/engine/score-calculator.js +214 -0
- package/engines/arch-detect/engine/violation-detector.js +616 -0
- package/engines/arch-detect/index.js +50 -0
- package/engines/arch-detect/rules/base-rule.js +187 -0
- package/engines/arch-detect/rules/index.js +35 -0
- package/engines/arch-detect/rules/layered/index.js +28 -0
- package/engines/arch-detect/rules/layered/l001-presentation-layer.js +237 -0
- package/engines/arch-detect/rules/layered/l002-business-layer.js +215 -0
- package/engines/arch-detect/rules/layered/l003-data-layer.js +229 -0
- package/engines/arch-detect/rules/layered/l004-model-layer.js +204 -0
- package/engines/arch-detect/rules/layered/l005-layer-separation.js +215 -0
- package/engines/arch-detect/rules/layered/l006-dependency-direction.js +221 -0
- package/engines/arch-detect/rules/layered/layered-rules-collection.js +445 -0
- package/engines/arch-detect/rules/modular/index.js +27 -0
- package/engines/arch-detect/rules/modular/m001-feature-modules.js +238 -0
- package/engines/arch-detect/rules/modular/m002-core-module.js +169 -0
- package/engines/arch-detect/rules/modular/m003-module-declaration.js +186 -0
- package/engines/arch-detect/rules/modular/m004-public-api.js +171 -0
- package/engines/arch-detect/rules/modular/m005-no-deep-imports.js +220 -0
- package/engines/arch-detect/rules/modular/modular-rules-collection.js +357 -0
- package/engines/arch-detect/rules/presentation/index.js +27 -0
- package/engines/arch-detect/rules/presentation/pr001-view-layer.js +221 -0
- package/engines/arch-detect/rules/presentation/pr002-presentation-logic.js +192 -0
- package/engines/arch-detect/rules/presentation/pr004-data-binding.js +187 -0
- package/engines/arch-detect/rules/presentation/pr006-router-layer.js +185 -0
- package/engines/arch-detect/rules/presentation/pr007-interactor-layer.js +181 -0
- package/engines/arch-detect/rules/presentation/presentation-rules-collection.js +507 -0
- package/engines/arch-detect/rules/project-scanner/index.js +31 -0
- package/engines/arch-detect/rules/project-scanner/ps001-project-root.js +213 -0
- package/engines/arch-detect/rules/project-scanner/ps002-language-detection.js +192 -0
- package/engines/arch-detect/rules/project-scanner/ps003-framework-detection.js +339 -0
- package/engines/arch-detect/rules/project-scanner/ps004-build-system.js +171 -0
- package/engines/arch-detect/rules/project-scanner/ps005-source-directory.js +163 -0
- package/engines/arch-detect/rules/project-scanner/ps006-test-directory.js +184 -0
- package/engines/arch-detect/rules/project-scanner/ps007-documentation.js +149 -0
- package/engines/arch-detect/rules/project-scanner/ps008-cicd-detection.js +163 -0
- package/engines/arch-detect/rules/project-scanner/ps009-code-quality.js +152 -0
- package/engines/arch-detect/rules/project-scanner/ps010-statistics.js +180 -0
- package/engines/arch-detect/rules/rule-registry.js +111 -0
- package/engines/arch-detect/types/context.types.js +60 -0
- package/engines/arch-detect/types/enums.js +161 -0
- package/engines/arch-detect/types/index.js +25 -0
- package/engines/arch-detect/types/result.types.js +7 -0
- package/engines/arch-detect/types/rule.types.js +7 -0
- package/engines/arch-detect/utils/file-scanner.js +411 -0
- package/engines/arch-detect/utils/index.js +23 -0
- package/engines/arch-detect/utils/pattern-matcher.js +328 -0
- package/engines/impact/cli.js +106 -0
- package/engines/impact/config/default-config.js +54 -0
- package/engines/impact/core/change-detector.js +258 -0
- package/engines/impact/core/detectors/database-detector.js +1317 -0
- package/engines/impact/core/detectors/endpoint-detector.js +55 -0
- package/engines/impact/core/impact-analyzer.js +124 -0
- package/engines/impact/core/report-generator.js +462 -0
- package/engines/impact/core/utils/ast-parser.js +241 -0
- package/engines/impact/core/utils/dependency-graph.js +159 -0
- package/engines/impact/core/utils/file-utils.js +116 -0
- package/engines/impact/core/utils/git-utils.js +203 -0
- package/engines/impact/core/utils/logger.js +13 -0
- package/engines/impact/core/utils/method-call-graph.js +1192 -0
- package/engines/impact/index.js +135 -0
- package/engines/impact/package.json +29 -0
- package/package.json +18 -43
- package/scripts/build-release.sh +0 -0
- package/scripts/copy-impact-analyzer.js +135 -0
- package/scripts/install.sh +0 -0
- package/scripts/manual-release.sh +0 -0
- package/scripts/pre-release-test.sh +0 -0
- package/scripts/prepare-release.sh +0 -0
- package/scripts/quick-performance-test.js +0 -0
- package/scripts/setup-github-registry.sh +0 -0
- package/scripts/trigger-release.sh +0 -0
- package/scripts/verify-install.sh +0 -0
- package/templates/combined-report.html +1418 -0
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Base Rule Class
|
|
4
|
+
* Abstract class cho tất cả rules
|
|
5
|
+
*/
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.BaseRule = void 0;
|
|
8
|
+
exports.createRule = createRule;
|
|
9
|
+
const enums_1 = require("../types/enums");
|
|
10
|
+
const pattern_matcher_1 = require("../utils/pattern-matcher");
|
|
11
|
+
/**
|
|
12
|
+
* Abstract base class cho tất cả rule implementations
|
|
13
|
+
*/
|
|
14
|
+
class BaseRule {
|
|
15
|
+
constructor() {
|
|
16
|
+
/** Pattern matcher instance */
|
|
17
|
+
this.patternMatcher = null;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Khởi tạo pattern matcher từ context
|
|
21
|
+
*/
|
|
22
|
+
initializePatternMatcher(context) {
|
|
23
|
+
this.patternMatcher = new pattern_matcher_1.PatternMatcher(context.projectInfo.projectRoot);
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Execute rule và trả về kết quả
|
|
27
|
+
*/
|
|
28
|
+
async execute(context) {
|
|
29
|
+
const startTime = Date.now();
|
|
30
|
+
this.initializePatternMatcher(context);
|
|
31
|
+
try {
|
|
32
|
+
// Run detection
|
|
33
|
+
const matches = [];
|
|
34
|
+
const violations = [];
|
|
35
|
+
let score = 0;
|
|
36
|
+
// Match folder patterns
|
|
37
|
+
if (this.rule.detection.folderPatterns?.length) {
|
|
38
|
+
const folderResult = await this.patternMatcher.matchFolderPatterns(this.rule.detection.folderPatterns, context.directoryTree);
|
|
39
|
+
matches.push(...folderResult.matches);
|
|
40
|
+
score += folderResult.score * 0.3;
|
|
41
|
+
}
|
|
42
|
+
// Match file patterns
|
|
43
|
+
if (this.rule.detection.filePatterns?.length) {
|
|
44
|
+
const fileResult = await this.patternMatcher.matchFilePatterns(this.rule.detection.filePatterns, context.files);
|
|
45
|
+
matches.push(...fileResult.matches);
|
|
46
|
+
score += fileResult.score * 0.3;
|
|
47
|
+
}
|
|
48
|
+
// Match code patterns
|
|
49
|
+
if (this.rule.detection.codePatterns?.length) {
|
|
50
|
+
const codeResult = await this.patternMatcher.matchCodePatterns(this.rule.detection.codePatterns, context.files);
|
|
51
|
+
matches.push(...codeResult.matches);
|
|
52
|
+
score += codeResult.score * 0.4;
|
|
53
|
+
}
|
|
54
|
+
// Match config patterns
|
|
55
|
+
if (this.rule.detection.configPatterns?.length) {
|
|
56
|
+
const configResult = await this.patternMatcher.matchConfigPatterns(this.rule.detection.configPatterns, context.files);
|
|
57
|
+
matches.push(...configResult.matches);
|
|
58
|
+
score += configResult.score * 0.2;
|
|
59
|
+
}
|
|
60
|
+
// Custom detection
|
|
61
|
+
const customResult = await this.customDetection(context);
|
|
62
|
+
if (customResult) {
|
|
63
|
+
matches.push(...customResult.matches);
|
|
64
|
+
violations.push(...customResult.violations);
|
|
65
|
+
score = customResult.score ?? score;
|
|
66
|
+
}
|
|
67
|
+
// Normalize score
|
|
68
|
+
score = Math.min(Math.max(score, 0), 1);
|
|
69
|
+
// Calculate final result
|
|
70
|
+
const passed = this.determinePass(score, matches);
|
|
71
|
+
const confidence = this.calculateConfidence(matches, context);
|
|
72
|
+
const weightedScore = score * this.rule.weight;
|
|
73
|
+
const executionTime = Date.now() - startTime;
|
|
74
|
+
return {
|
|
75
|
+
ruleId: this.rule.id,
|
|
76
|
+
ruleName: this.rule.name,
|
|
77
|
+
passed,
|
|
78
|
+
score,
|
|
79
|
+
weightedScore,
|
|
80
|
+
confidence,
|
|
81
|
+
matches,
|
|
82
|
+
violations,
|
|
83
|
+
metadata: this.getMetadata(context, matches),
|
|
84
|
+
executionTime,
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
catch (error) {
|
|
88
|
+
const executionTime = Date.now() - startTime;
|
|
89
|
+
return {
|
|
90
|
+
ruleId: this.rule.id,
|
|
91
|
+
ruleName: this.rule.name,
|
|
92
|
+
passed: false,
|
|
93
|
+
score: 0,
|
|
94
|
+
weightedScore: 0,
|
|
95
|
+
confidence: 0,
|
|
96
|
+
matches: [],
|
|
97
|
+
violations: [
|
|
98
|
+
{
|
|
99
|
+
type: 'execution_error',
|
|
100
|
+
severity: enums_1.Severity.ERROR,
|
|
101
|
+
path: '',
|
|
102
|
+
message: `Error executing rule: ${error}`,
|
|
103
|
+
},
|
|
104
|
+
],
|
|
105
|
+
metadata: { error: String(error) },
|
|
106
|
+
executionTime,
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Custom detection logic - override trong subclass
|
|
112
|
+
*/
|
|
113
|
+
async customDetection(_context) {
|
|
114
|
+
return null;
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Xác định rule có pass không dựa trên score và matches
|
|
118
|
+
*/
|
|
119
|
+
determinePass(score, matches) {
|
|
120
|
+
// Default: pass nếu có ít nhất 1 match và score >= 0.3
|
|
121
|
+
return matches.length > 0 && score >= 0.3;
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Tính confidence dựa trên matches
|
|
125
|
+
*/
|
|
126
|
+
calculateConfidence(matches, _context) {
|
|
127
|
+
if (matches.length === 0)
|
|
128
|
+
return 0;
|
|
129
|
+
// Base confidence từ số lượng matches
|
|
130
|
+
let confidence = Math.min(matches.length / 10, 0.5);
|
|
131
|
+
// Tăng confidence nếu có nhiều loại matches khác nhau
|
|
132
|
+
const matchTypes = new Set(matches.map((m) => m.type));
|
|
133
|
+
confidence += matchTypes.size * 0.1;
|
|
134
|
+
// Tăng confidence nếu matches phân bố đều
|
|
135
|
+
const pathSet = new Set(matches.map((m) => m.path.split('/')[0]));
|
|
136
|
+
confidence += Math.min(pathSet.size / 5, 0.2);
|
|
137
|
+
return Math.min(confidence, 1);
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* Lấy metadata bổ sung
|
|
141
|
+
*/
|
|
142
|
+
getMetadata(_context, matches) {
|
|
143
|
+
return {
|
|
144
|
+
matchCount: matches.length,
|
|
145
|
+
uniquePaths: new Set(matches.map((m) => m.path)).size,
|
|
146
|
+
framework: 'detected',
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* Validate rule configuration
|
|
151
|
+
*/
|
|
152
|
+
validate() {
|
|
153
|
+
if (!this.rule.id || !this.rule.name) {
|
|
154
|
+
return false;
|
|
155
|
+
}
|
|
156
|
+
if (this.rule.weight < 0 || this.rule.weight > 1) {
|
|
157
|
+
return false;
|
|
158
|
+
}
|
|
159
|
+
return true;
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
exports.BaseRule = BaseRule;
|
|
163
|
+
/**
|
|
164
|
+
* Helper để tạo rule definition
|
|
165
|
+
*/
|
|
166
|
+
function createRule(id, name, description, category, weight, applicableTo, detection, options) {
|
|
167
|
+
return {
|
|
168
|
+
id,
|
|
169
|
+
name,
|
|
170
|
+
description,
|
|
171
|
+
category,
|
|
172
|
+
weight,
|
|
173
|
+
applicableTo,
|
|
174
|
+
detection,
|
|
175
|
+
scoring: {
|
|
176
|
+
fullScore: 1,
|
|
177
|
+
partialScoring: options?.partialScoring ?? true,
|
|
178
|
+
partialThresholds: options?.partialThresholds,
|
|
179
|
+
},
|
|
180
|
+
requires: options?.requires,
|
|
181
|
+
conflicts: options?.conflicts,
|
|
182
|
+
isKeyIndicator: options?.isKeyIndicator,
|
|
183
|
+
tags: options?.tags,
|
|
184
|
+
};
|
|
185
|
+
}
|
|
186
|
+
exports.default = BaseRule;
|
|
187
|
+
//# sourceMappingURL=base-rule.js.map
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Rules Index
|
|
4
|
+
* Import và export tất cả các rules
|
|
5
|
+
*/
|
|
6
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
7
|
+
if (k2 === undefined) k2 = k;
|
|
8
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
9
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
10
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
11
|
+
}
|
|
12
|
+
Object.defineProperty(o, k2, desc);
|
|
13
|
+
}) : (function(o, m, k, k2) {
|
|
14
|
+
if (k2 === undefined) k2 = k;
|
|
15
|
+
o[k2] = m[k];
|
|
16
|
+
}));
|
|
17
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
18
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
19
|
+
};
|
|
20
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
21
|
+
exports.ruleRegistry = exports.RegisterRule = void 0;
|
|
22
|
+
// Rule Infrastructure
|
|
23
|
+
__exportStar(require("./base-rule"), exports);
|
|
24
|
+
// Layered Architecture Rules
|
|
25
|
+
__exportStar(require("./layered"), exports);
|
|
26
|
+
// Modular Architecture Rules
|
|
27
|
+
__exportStar(require("./modular"), exports);
|
|
28
|
+
// Presentation Pattern Rules (MVVM, VIPER)
|
|
29
|
+
__exportStar(require("./presentation"), exports);
|
|
30
|
+
// Project Scanner Rules
|
|
31
|
+
__exportStar(require("./project-scanner"), exports);
|
|
32
|
+
var rule_registry_1 = require("./rule-registry");
|
|
33
|
+
Object.defineProperty(exports, "RegisterRule", { enumerable: true, get: function () { return rule_registry_1.RegisterRule; } });
|
|
34
|
+
Object.defineProperty(exports, "ruleRegistry", { enumerable: true, get: function () { return rule_registry_1.ruleRegistry; } });
|
|
35
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Layered/MVC Rules Index
|
|
4
|
+
* Export tất cả Layered Architecture rules (L001-L015)
|
|
5
|
+
*/
|
|
6
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
7
|
+
if (k2 === undefined) k2 = k;
|
|
8
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
9
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
10
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
11
|
+
}
|
|
12
|
+
Object.defineProperty(o, k2, desc);
|
|
13
|
+
}) : (function(o, m, k, k2) {
|
|
14
|
+
if (k2 === undefined) k2 = k;
|
|
15
|
+
o[k2] = m[k];
|
|
16
|
+
}));
|
|
17
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
18
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
19
|
+
};
|
|
20
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
21
|
+
__exportStar(require("./l001-presentation-layer"), exports);
|
|
22
|
+
__exportStar(require("./l002-business-layer"), exports);
|
|
23
|
+
__exportStar(require("./l003-data-layer"), exports);
|
|
24
|
+
__exportStar(require("./l004-model-layer"), exports);
|
|
25
|
+
__exportStar(require("./l005-layer-separation"), exports);
|
|
26
|
+
__exportStar(require("./l006-dependency-direction"), exports);
|
|
27
|
+
__exportStar(require("./layered-rules-collection"), exports);
|
|
28
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* L001: Presentation Layer Exists
|
|
4
|
+
* Xác nhận có tầng xử lý request/response (Controller/Handler)
|
|
5
|
+
*/
|
|
6
|
+
var __esDecorate = (this && this.__esDecorate) || function (ctor, descriptorIn, decorators, contextIn, initializers, extraInitializers) {
|
|
7
|
+
function accept(f) { if (f !== void 0 && typeof f !== "function") throw new TypeError("Function expected"); return f; }
|
|
8
|
+
var kind = contextIn.kind, key = kind === "getter" ? "get" : kind === "setter" ? "set" : "value";
|
|
9
|
+
var target = !descriptorIn && ctor ? contextIn["static"] ? ctor : ctor.prototype : null;
|
|
10
|
+
var descriptor = descriptorIn || (target ? Object.getOwnPropertyDescriptor(target, contextIn.name) : {});
|
|
11
|
+
var _, done = false;
|
|
12
|
+
for (var i = decorators.length - 1; i >= 0; i--) {
|
|
13
|
+
var context = {};
|
|
14
|
+
for (var p in contextIn) context[p] = p === "access" ? {} : contextIn[p];
|
|
15
|
+
for (var p in contextIn.access) context.access[p] = contextIn.access[p];
|
|
16
|
+
context.addInitializer = function (f) { if (done) throw new TypeError("Cannot add initializers after decoration has completed"); extraInitializers.push(accept(f || null)); };
|
|
17
|
+
var result = (0, decorators[i])(kind === "accessor" ? { get: descriptor.get, set: descriptor.set } : descriptor[key], context);
|
|
18
|
+
if (kind === "accessor") {
|
|
19
|
+
if (result === void 0) continue;
|
|
20
|
+
if (result === null || typeof result !== "object") throw new TypeError("Object expected");
|
|
21
|
+
if (_ = accept(result.get)) descriptor.get = _;
|
|
22
|
+
if (_ = accept(result.set)) descriptor.set = _;
|
|
23
|
+
if (_ = accept(result.init)) initializers.unshift(_);
|
|
24
|
+
}
|
|
25
|
+
else if (_ = accept(result)) {
|
|
26
|
+
if (kind === "field") initializers.unshift(_);
|
|
27
|
+
else descriptor[key] = _;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
if (target) Object.defineProperty(target, contextIn.name, descriptor);
|
|
31
|
+
done = true;
|
|
32
|
+
};
|
|
33
|
+
var __runInitializers = (this && this.__runInitializers) || function (thisArg, initializers, value) {
|
|
34
|
+
var useValue = arguments.length > 2;
|
|
35
|
+
for (var i = 0; i < initializers.length; i++) {
|
|
36
|
+
value = useValue ? initializers[i].call(thisArg, value) : initializers[i].call(thisArg);
|
|
37
|
+
}
|
|
38
|
+
return useValue ? value : void 0;
|
|
39
|
+
};
|
|
40
|
+
var __setFunctionName = (this && this.__setFunctionName) || function (f, name, prefix) {
|
|
41
|
+
if (typeof name === "symbol") name = name.description ? "[".concat(name.description, "]") : "";
|
|
42
|
+
return Object.defineProperty(f, "name", { configurable: true, value: prefix ? "".concat(prefix, " ", name) : name });
|
|
43
|
+
};
|
|
44
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
45
|
+
exports.L001PresentationLayer = void 0;
|
|
46
|
+
const enums_1 = require("../../types/enums");
|
|
47
|
+
const base_rule_1 = require("../base-rule");
|
|
48
|
+
const rule_registry_1 = require("../rule-registry");
|
|
49
|
+
const rule = (0, base_rule_1.createRule)('L001', 'Presentation Layer Exists', 'Xác nhận có tầng xử lý request/response (Controller, Handler, Endpoint)', enums_1.RuleCategory.CORE, 0.16, [enums_1.PatternType.LAYERED], {
|
|
50
|
+
folderPatterns: [
|
|
51
|
+
'controllers',
|
|
52
|
+
'controller',
|
|
53
|
+
'api',
|
|
54
|
+
'handlers',
|
|
55
|
+
'endpoints',
|
|
56
|
+
'resources',
|
|
57
|
+
'routes',
|
|
58
|
+
'Http/Controllers',
|
|
59
|
+
'presentation',
|
|
60
|
+
],
|
|
61
|
+
filePatterns: ['*Controller.*', '*Handler.*', '*Endpoint.*', '*Resource.*', '*Api.*'],
|
|
62
|
+
codePatterns: [
|
|
63
|
+
// Java
|
|
64
|
+
{ language: enums_1.Language.JAVA, type: enums_1.CodePatternType.ANNOTATION, pattern: /@Controller\b/ },
|
|
65
|
+
{ language: enums_1.Language.JAVA, type: enums_1.CodePatternType.ANNOTATION, pattern: /@RestController\b/ },
|
|
66
|
+
{ language: enums_1.Language.JAVA, type: enums_1.CodePatternType.ANNOTATION, pattern: /@RequestMapping\b/ },
|
|
67
|
+
{ language: enums_1.Language.JAVA, type: enums_1.CodePatternType.ANNOTATION, pattern: /@GetMapping\b/ },
|
|
68
|
+
{ language: enums_1.Language.JAVA, type: enums_1.CodePatternType.ANNOTATION, pattern: /@PostMapping\b/ },
|
|
69
|
+
// TypeScript/JavaScript
|
|
70
|
+
{
|
|
71
|
+
language: enums_1.Language.TYPESCRIPT,
|
|
72
|
+
type: enums_1.CodePatternType.ANNOTATION,
|
|
73
|
+
pattern: /@Controller\s*\(/,
|
|
74
|
+
},
|
|
75
|
+
{ language: enums_1.Language.TYPESCRIPT, type: enums_1.CodePatternType.ANNOTATION, pattern: /@Get\s*\(/ },
|
|
76
|
+
{ language: enums_1.Language.TYPESCRIPT, type: enums_1.CodePatternType.ANNOTATION, pattern: /@Post\s*\(/ },
|
|
77
|
+
{
|
|
78
|
+
language: enums_1.Language.JAVASCRIPT,
|
|
79
|
+
type: enums_1.CodePatternType.PATTERN,
|
|
80
|
+
pattern: /router\.(get|post|put|delete)\s*\(/,
|
|
81
|
+
},
|
|
82
|
+
{
|
|
83
|
+
language: enums_1.Language.JAVASCRIPT,
|
|
84
|
+
type: enums_1.CodePatternType.PATTERN,
|
|
85
|
+
pattern: /app\.(get|post|put|delete)\s*\(/,
|
|
86
|
+
},
|
|
87
|
+
// C#
|
|
88
|
+
{ language: enums_1.Language.CSHARP, type: enums_1.CodePatternType.ANNOTATION, pattern: /\[ApiController\]/ },
|
|
89
|
+
{ language: enums_1.Language.CSHARP, type: enums_1.CodePatternType.ANNOTATION, pattern: /\[HttpGet\]/ },
|
|
90
|
+
{ language: enums_1.Language.CSHARP, type: enums_1.CodePatternType.ANNOTATION, pattern: /\[HttpPost\]/ },
|
|
91
|
+
// PHP
|
|
92
|
+
{ language: enums_1.Language.PHP, type: enums_1.CodePatternType.CLASS, pattern: /extends\s+Controller\b/ },
|
|
93
|
+
{
|
|
94
|
+
language: enums_1.Language.PHP,
|
|
95
|
+
type: enums_1.CodePatternType.PATTERN,
|
|
96
|
+
pattern: /Route::(get|post|put|delete)\s*\(/,
|
|
97
|
+
},
|
|
98
|
+
// Python
|
|
99
|
+
{ language: enums_1.Language.PYTHON, type: enums_1.CodePatternType.ANNOTATION, pattern: /@app\.route\s*\(/ },
|
|
100
|
+
{ language: enums_1.Language.PYTHON, type: enums_1.CodePatternType.ANNOTATION, pattern: /@api_view\s*\(/ },
|
|
101
|
+
// Go
|
|
102
|
+
{ language: enums_1.Language.GO, type: enums_1.CodePatternType.PATTERN, pattern: /r\.HandleFunc\s*\(/ },
|
|
103
|
+
{ language: enums_1.Language.GO, type: enums_1.CodePatternType.PATTERN, pattern: /gin\.Context/ },
|
|
104
|
+
// Ruby
|
|
105
|
+
{
|
|
106
|
+
language: enums_1.Language.RUBY,
|
|
107
|
+
type: enums_1.CodePatternType.CLASS,
|
|
108
|
+
pattern: /class\s+\w+Controller\s*<\s*ApplicationController/,
|
|
109
|
+
},
|
|
110
|
+
],
|
|
111
|
+
}, {
|
|
112
|
+
isKeyIndicator: true,
|
|
113
|
+
tags: ['layered', 'presentation', 'controller'],
|
|
114
|
+
});
|
|
115
|
+
let L001PresentationLayer = (() => {
|
|
116
|
+
let _classDecorators = [(0, rule_registry_1.RegisterRule)(rule)];
|
|
117
|
+
let _classDescriptor;
|
|
118
|
+
let _classExtraInitializers = [];
|
|
119
|
+
let _classThis;
|
|
120
|
+
let _classSuper = base_rule_1.BaseRule;
|
|
121
|
+
var L001PresentationLayer = _classThis = class extends _classSuper {
|
|
122
|
+
constructor() {
|
|
123
|
+
super(...arguments);
|
|
124
|
+
this.rule = rule;
|
|
125
|
+
}
|
|
126
|
+
async customDetection(context) {
|
|
127
|
+
const matches = [];
|
|
128
|
+
let hasFolders = false;
|
|
129
|
+
let hasFiles = false;
|
|
130
|
+
let hasCode = false;
|
|
131
|
+
// Check for controller folders
|
|
132
|
+
const controllerFolders = [
|
|
133
|
+
'controllers',
|
|
134
|
+
'controller',
|
|
135
|
+
'api',
|
|
136
|
+
'handlers',
|
|
137
|
+
'endpoints',
|
|
138
|
+
'resources',
|
|
139
|
+
'routes',
|
|
140
|
+
];
|
|
141
|
+
for (const folder of controllerFolders) {
|
|
142
|
+
const found = context.files.some((f) => f.relativePath.toLowerCase().includes(`/${folder}/`) ||
|
|
143
|
+
f.relativePath.toLowerCase().startsWith(`${folder}/`));
|
|
144
|
+
if (found) {
|
|
145
|
+
matches.push({
|
|
146
|
+
type: enums_1.MatchType.FOLDER,
|
|
147
|
+
path: folder,
|
|
148
|
+
matchedPattern: 'Controller folder',
|
|
149
|
+
});
|
|
150
|
+
hasFolders = true;
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
// Check for controller files
|
|
154
|
+
const controllerFiles = context.files.filter((f) => /Controller\.(ts|js|java|cs|php|py|rb|go)$/i.test(f.fileName) ||
|
|
155
|
+
/Handler\.(ts|js|java|cs|php|py|rb|go)$/i.test(f.fileName) ||
|
|
156
|
+
/\.controller\.(ts|js)$/i.test(f.fileName));
|
|
157
|
+
if (controllerFiles.length > 0) {
|
|
158
|
+
for (const file of controllerFiles.slice(0, 5)) {
|
|
159
|
+
matches.push({
|
|
160
|
+
type: enums_1.MatchType.FILE,
|
|
161
|
+
path: file.relativePath,
|
|
162
|
+
matchedPattern: 'Controller file',
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
hasFiles = true;
|
|
166
|
+
}
|
|
167
|
+
// Check for code patterns (sampling first 50 source files)
|
|
168
|
+
const sourceFiles = context.files
|
|
169
|
+
.filter((f) => !f.isTest && !f.isConfig && f.language)
|
|
170
|
+
.slice(0, 50);
|
|
171
|
+
const codePatterns = [
|
|
172
|
+
/@Controller\b/,
|
|
173
|
+
/@RestController\b/,
|
|
174
|
+
/@Get\s*\(/,
|
|
175
|
+
/@Post\s*\(/,
|
|
176
|
+
/router\.(get|post|put|delete)\s*\(/,
|
|
177
|
+
/app\.(get|post|put|delete)\s*\(/,
|
|
178
|
+
/\[ApiController\]/,
|
|
179
|
+
/@app\.route\s*\(/,
|
|
180
|
+
];
|
|
181
|
+
for (const file of sourceFiles) {
|
|
182
|
+
try {
|
|
183
|
+
const content = await context.helpers.readFile(file.absolutePath);
|
|
184
|
+
for (const pattern of codePatterns) {
|
|
185
|
+
if (pattern.test(content)) {
|
|
186
|
+
hasCode = true;
|
|
187
|
+
const lineMatch = content.split('\n').findIndex((line) => pattern.test(line));
|
|
188
|
+
matches.push({
|
|
189
|
+
type: enums_1.MatchType.CODE,
|
|
190
|
+
path: file.relativePath,
|
|
191
|
+
line: lineMatch + 1,
|
|
192
|
+
matchedPattern: 'Controller pattern',
|
|
193
|
+
});
|
|
194
|
+
break;
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
if (hasCode && matches.length >= 10)
|
|
198
|
+
break;
|
|
199
|
+
}
|
|
200
|
+
catch {
|
|
201
|
+
// Skip unreadable files
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
// Calculate score based on presence
|
|
205
|
+
let score = 0;
|
|
206
|
+
if (hasFolders && hasFiles)
|
|
207
|
+
score = 1;
|
|
208
|
+
else if (hasFiles)
|
|
209
|
+
score = 0.7;
|
|
210
|
+
else if (hasCode)
|
|
211
|
+
score = 0.6;
|
|
212
|
+
else if (hasFolders)
|
|
213
|
+
score = 0.4;
|
|
214
|
+
return { matches, violations: [], score };
|
|
215
|
+
}
|
|
216
|
+
getMetadata(context, matches) {
|
|
217
|
+
const controllerCount = matches.filter((m) => m.matchedPattern === 'Controller file').length;
|
|
218
|
+
return {
|
|
219
|
+
...super.getMetadata(context, matches),
|
|
220
|
+
controllerCount,
|
|
221
|
+
hasDedicatedFolder: matches.some((m) => m.matchedPattern === 'Controller folder'),
|
|
222
|
+
};
|
|
223
|
+
}
|
|
224
|
+
};
|
|
225
|
+
__setFunctionName(_classThis, "L001PresentationLayer");
|
|
226
|
+
(() => {
|
|
227
|
+
const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0;
|
|
228
|
+
__esDecorate(null, _classDescriptor = { value: _classThis }, _classDecorators, { kind: "class", name: _classThis.name, metadata: _metadata }, null, _classExtraInitializers);
|
|
229
|
+
L001PresentationLayer = _classThis = _classDescriptor.value;
|
|
230
|
+
if (_metadata) Object.defineProperty(_classThis, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
|
|
231
|
+
__runInitializers(_classThis, _classExtraInitializers);
|
|
232
|
+
})();
|
|
233
|
+
return L001PresentationLayer = _classThis;
|
|
234
|
+
})();
|
|
235
|
+
exports.L001PresentationLayer = L001PresentationLayer;
|
|
236
|
+
exports.default = L001PresentationLayer;
|
|
237
|
+
//# sourceMappingURL=l001-presentation-layer.js.map
|