@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.
Files changed (90) hide show
  1. package/core/architecture-integration.js +16 -7
  2. package/core/auto-performance-manager.js +1 -1
  3. package/core/cli-action-handler.js +92 -2
  4. package/core/cli-program.js +96 -138
  5. package/core/file-targeting-service.js +62 -4
  6. package/core/git-utils.js +19 -12
  7. package/core/github-annotate-service.js +326 -11
  8. package/core/html-report-generator.js +326 -731
  9. package/core/impact-integration.js +433 -0
  10. package/core/output-service.js +293 -21
  11. package/core/scoring-service.js +3 -2
  12. package/engines/arch-detect/core/analyzer.js +413 -0
  13. package/engines/arch-detect/core/index.js +22 -0
  14. package/engines/arch-detect/engine/hybrid-detector.js +176 -0
  15. package/engines/arch-detect/engine/index.js +24 -0
  16. package/engines/arch-detect/engine/rule-executor.js +228 -0
  17. package/engines/arch-detect/engine/score-calculator.js +214 -0
  18. package/engines/arch-detect/engine/violation-detector.js +616 -0
  19. package/engines/arch-detect/index.js +50 -0
  20. package/engines/arch-detect/rules/base-rule.js +187 -0
  21. package/engines/arch-detect/rules/index.js +35 -0
  22. package/engines/arch-detect/rules/layered/index.js +28 -0
  23. package/engines/arch-detect/rules/layered/l001-presentation-layer.js +237 -0
  24. package/engines/arch-detect/rules/layered/l002-business-layer.js +215 -0
  25. package/engines/arch-detect/rules/layered/l003-data-layer.js +229 -0
  26. package/engines/arch-detect/rules/layered/l004-model-layer.js +204 -0
  27. package/engines/arch-detect/rules/layered/l005-layer-separation.js +215 -0
  28. package/engines/arch-detect/rules/layered/l006-dependency-direction.js +221 -0
  29. package/engines/arch-detect/rules/layered/layered-rules-collection.js +445 -0
  30. package/engines/arch-detect/rules/modular/index.js +27 -0
  31. package/engines/arch-detect/rules/modular/m001-feature-modules.js +238 -0
  32. package/engines/arch-detect/rules/modular/m002-core-module.js +169 -0
  33. package/engines/arch-detect/rules/modular/m003-module-declaration.js +186 -0
  34. package/engines/arch-detect/rules/modular/m004-public-api.js +171 -0
  35. package/engines/arch-detect/rules/modular/m005-no-deep-imports.js +220 -0
  36. package/engines/arch-detect/rules/modular/modular-rules-collection.js +357 -0
  37. package/engines/arch-detect/rules/presentation/index.js +27 -0
  38. package/engines/arch-detect/rules/presentation/pr001-view-layer.js +221 -0
  39. package/engines/arch-detect/rules/presentation/pr002-presentation-logic.js +192 -0
  40. package/engines/arch-detect/rules/presentation/pr004-data-binding.js +187 -0
  41. package/engines/arch-detect/rules/presentation/pr006-router-layer.js +185 -0
  42. package/engines/arch-detect/rules/presentation/pr007-interactor-layer.js +181 -0
  43. package/engines/arch-detect/rules/presentation/presentation-rules-collection.js +507 -0
  44. package/engines/arch-detect/rules/project-scanner/index.js +31 -0
  45. package/engines/arch-detect/rules/project-scanner/ps001-project-root.js +213 -0
  46. package/engines/arch-detect/rules/project-scanner/ps002-language-detection.js +192 -0
  47. package/engines/arch-detect/rules/project-scanner/ps003-framework-detection.js +339 -0
  48. package/engines/arch-detect/rules/project-scanner/ps004-build-system.js +171 -0
  49. package/engines/arch-detect/rules/project-scanner/ps005-source-directory.js +163 -0
  50. package/engines/arch-detect/rules/project-scanner/ps006-test-directory.js +184 -0
  51. package/engines/arch-detect/rules/project-scanner/ps007-documentation.js +149 -0
  52. package/engines/arch-detect/rules/project-scanner/ps008-cicd-detection.js +163 -0
  53. package/engines/arch-detect/rules/project-scanner/ps009-code-quality.js +152 -0
  54. package/engines/arch-detect/rules/project-scanner/ps010-statistics.js +180 -0
  55. package/engines/arch-detect/rules/rule-registry.js +111 -0
  56. package/engines/arch-detect/types/context.types.js +60 -0
  57. package/engines/arch-detect/types/enums.js +161 -0
  58. package/engines/arch-detect/types/index.js +25 -0
  59. package/engines/arch-detect/types/result.types.js +7 -0
  60. package/engines/arch-detect/types/rule.types.js +7 -0
  61. package/engines/arch-detect/utils/file-scanner.js +411 -0
  62. package/engines/arch-detect/utils/index.js +23 -0
  63. package/engines/arch-detect/utils/pattern-matcher.js +328 -0
  64. package/engines/impact/cli.js +106 -0
  65. package/engines/impact/config/default-config.js +54 -0
  66. package/engines/impact/core/change-detector.js +258 -0
  67. package/engines/impact/core/detectors/database-detector.js +1317 -0
  68. package/engines/impact/core/detectors/endpoint-detector.js +55 -0
  69. package/engines/impact/core/impact-analyzer.js +124 -0
  70. package/engines/impact/core/report-generator.js +462 -0
  71. package/engines/impact/core/utils/ast-parser.js +241 -0
  72. package/engines/impact/core/utils/dependency-graph.js +159 -0
  73. package/engines/impact/core/utils/file-utils.js +116 -0
  74. package/engines/impact/core/utils/git-utils.js +203 -0
  75. package/engines/impact/core/utils/logger.js +13 -0
  76. package/engines/impact/core/utils/method-call-graph.js +1192 -0
  77. package/engines/impact/index.js +135 -0
  78. package/engines/impact/package.json +29 -0
  79. package/package.json +18 -43
  80. package/scripts/build-release.sh +0 -0
  81. package/scripts/copy-impact-analyzer.js +135 -0
  82. package/scripts/install.sh +0 -0
  83. package/scripts/manual-release.sh +0 -0
  84. package/scripts/pre-release-test.sh +0 -0
  85. package/scripts/prepare-release.sh +0 -0
  86. package/scripts/quick-performance-test.js +0 -0
  87. package/scripts/setup-github-registry.sh +0 -0
  88. package/scripts/trigger-release.sh +0 -0
  89. package/scripts/verify-install.sh +0 -0
  90. 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