@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,215 @@
1
+ "use strict";
2
+ /**
3
+ * L002: Business Logic Layer Exists
4
+ * Xác nhận có tầng xử lý business logic tách biệt
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.L002BusinessLayer = 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)('L002', 'Business Logic Layer Exists', 'Xác nhận có tầng xử lý business logic tách biệt (Service, UseCase, Manager)', enums_1.RuleCategory.CORE, 0.16, [enums_1.PatternType.LAYERED], {
50
+ folderPatterns: [
51
+ 'services',
52
+ 'service',
53
+ 'business',
54
+ 'domain',
55
+ 'usecases',
56
+ 'use-cases',
57
+ 'application',
58
+ 'managers',
59
+ 'core',
60
+ ],
61
+ filePatterns: ['*Service.*', '*UseCase.*', '*Manager.*', '*Business.*', '*Interactor.*'],
62
+ codePatterns: [
63
+ // Java
64
+ { language: enums_1.Language.JAVA, type: enums_1.CodePatternType.ANNOTATION, pattern: /@Service\b/ },
65
+ { language: enums_1.Language.JAVA, type: enums_1.CodePatternType.ANNOTATION, pattern: /@Transactional\b/ },
66
+ // TypeScript/JavaScript
67
+ {
68
+ language: enums_1.Language.TYPESCRIPT,
69
+ type: enums_1.CodePatternType.ANNOTATION,
70
+ pattern: /@Injectable\s*\(/,
71
+ },
72
+ { language: enums_1.Language.TYPESCRIPT, type: enums_1.CodePatternType.PATTERN, pattern: /\.service\.ts$/ },
73
+ // C#
74
+ { language: enums_1.Language.CSHARP, type: enums_1.CodePatternType.PATTERN, pattern: /class\s+\w+Service\b/ },
75
+ {
76
+ language: enums_1.Language.CSHARP,
77
+ type: enums_1.CodePatternType.PATTERN,
78
+ pattern: /interface\s+I\w+Service\b/,
79
+ },
80
+ // PHP
81
+ { language: enums_1.Language.PHP, type: enums_1.CodePatternType.PATTERN, pattern: /class\s+\w+Service\b/ },
82
+ // Python
83
+ { language: enums_1.Language.PYTHON, type: enums_1.CodePatternType.PATTERN, pattern: /class\s+\w+Service\b/ },
84
+ // Go
85
+ {
86
+ language: enums_1.Language.GO,
87
+ type: enums_1.CodePatternType.PATTERN,
88
+ pattern: /type\s+\w+Service\s+struct/,
89
+ },
90
+ ],
91
+ }, {
92
+ isKeyIndicator: true,
93
+ tags: ['layered', 'business', 'service'],
94
+ });
95
+ let L002BusinessLayer = (() => {
96
+ let _classDecorators = [(0, rule_registry_1.RegisterRule)(rule)];
97
+ let _classDescriptor;
98
+ let _classExtraInitializers = [];
99
+ let _classThis;
100
+ let _classSuper = base_rule_1.BaseRule;
101
+ var L002BusinessLayer = _classThis = class extends _classSuper {
102
+ constructor() {
103
+ super(...arguments);
104
+ this.rule = rule;
105
+ }
106
+ async customDetection(context) {
107
+ const matches = [];
108
+ let hasFolders = false;
109
+ let hasFiles = false;
110
+ let hasCode = false;
111
+ // Check for service folders
112
+ const serviceFolders = [
113
+ 'services',
114
+ 'service',
115
+ 'business',
116
+ 'domain',
117
+ 'usecases',
118
+ 'use-cases',
119
+ 'application',
120
+ 'managers',
121
+ ];
122
+ for (const folder of serviceFolders) {
123
+ const found = context.files.some((f) => f.relativePath.toLowerCase().includes(`/${folder}/`) ||
124
+ f.relativePath.toLowerCase().startsWith(`${folder}/`));
125
+ if (found) {
126
+ matches.push({
127
+ type: enums_1.MatchType.FOLDER,
128
+ path: folder,
129
+ matchedPattern: 'Service folder',
130
+ });
131
+ hasFolders = true;
132
+ }
133
+ }
134
+ // Check for service files
135
+ const serviceFiles = context.files.filter((f) => /Service\.(ts|js|java|cs|php|py|rb|go)$/i.test(f.fileName) ||
136
+ /UseCase\.(ts|js|java|cs|php|py|rb|go)$/i.test(f.fileName) ||
137
+ /Manager\.(ts|js|java|cs|php|py|rb|go)$/i.test(f.fileName) ||
138
+ /\.service\.(ts|js)$/i.test(f.fileName));
139
+ if (serviceFiles.length > 0) {
140
+ for (const file of serviceFiles.slice(0, 5)) {
141
+ matches.push({
142
+ type: enums_1.MatchType.FILE,
143
+ path: file.relativePath,
144
+ matchedPattern: 'Service file',
145
+ });
146
+ }
147
+ hasFiles = true;
148
+ }
149
+ // Check for code patterns
150
+ const sourceFiles = context.files
151
+ .filter((f) => !f.isTest && !f.isConfig && f.language)
152
+ .slice(0, 50);
153
+ const codePatterns = [
154
+ /@Service\b/,
155
+ /@Injectable\s*\(/,
156
+ /@Transactional\b/,
157
+ /class\s+\w+Service\b/,
158
+ /interface\s+I\w+Service\b/,
159
+ /type\s+\w+Service\s+struct/,
160
+ ];
161
+ for (const file of sourceFiles) {
162
+ try {
163
+ const content = await context.helpers.readFile(file.absolutePath);
164
+ for (const pattern of codePatterns) {
165
+ if (pattern.test(content)) {
166
+ hasCode = true;
167
+ matches.push({
168
+ type: enums_1.MatchType.CODE,
169
+ path: file.relativePath,
170
+ matchedPattern: 'Service pattern',
171
+ });
172
+ break;
173
+ }
174
+ }
175
+ if (hasCode && matches.length >= 10)
176
+ break;
177
+ }
178
+ catch {
179
+ // Skip unreadable files
180
+ }
181
+ }
182
+ // Calculate score
183
+ let score = 0;
184
+ if (hasFolders && hasFiles)
185
+ score = 1;
186
+ else if (hasFiles)
187
+ score = 0.7;
188
+ else if (hasCode)
189
+ score = 0.6;
190
+ else if (hasFolders)
191
+ score = 0.4;
192
+ return { matches, violations: [], score };
193
+ }
194
+ getMetadata(context, matches) {
195
+ const serviceCount = matches.filter((m) => m.matchedPattern === 'Service file').length;
196
+ return {
197
+ ...super.getMetadata(context, matches),
198
+ serviceCount,
199
+ hasDedicatedFolder: matches.some((m) => m.matchedPattern === 'Service folder'),
200
+ };
201
+ }
202
+ };
203
+ __setFunctionName(_classThis, "L002BusinessLayer");
204
+ (() => {
205
+ const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0;
206
+ __esDecorate(null, _classDescriptor = { value: _classThis }, _classDecorators, { kind: "class", name: _classThis.name, metadata: _metadata }, null, _classExtraInitializers);
207
+ L002BusinessLayer = _classThis = _classDescriptor.value;
208
+ if (_metadata) Object.defineProperty(_classThis, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
209
+ __runInitializers(_classThis, _classExtraInitializers);
210
+ })();
211
+ return L002BusinessLayer = _classThis;
212
+ })();
213
+ exports.L002BusinessLayer = L002BusinessLayer;
214
+ exports.default = L002BusinessLayer;
215
+ //# sourceMappingURL=l002-business-layer.js.map
@@ -0,0 +1,229 @@
1
+ "use strict";
2
+ /**
3
+ * L003: Data Access Layer Exists
4
+ * Xác nhận có tầng truy cập dữ liệu tách biệt (Repository, DAO)
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.L003DataLayer = 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)('L003', 'Data Access Layer Exists', 'Xác nhận có tầng truy cập dữ liệu tách biệt (Repository, DAO, Gateway)', enums_1.RuleCategory.CORE, 0.14, [enums_1.PatternType.LAYERED], {
50
+ folderPatterns: [
51
+ 'repositories',
52
+ 'repository',
53
+ 'dao',
54
+ 'daos',
55
+ 'data',
56
+ 'persistence',
57
+ 'infrastructure',
58
+ 'gateways',
59
+ 'store',
60
+ ],
61
+ filePatterns: ['*Repository.*', '*Dao.*', '*Gateway.*', '*DataSource.*', '*Store.*'],
62
+ codePatterns: [
63
+ // Java
64
+ { language: enums_1.Language.JAVA, type: enums_1.CodePatternType.ANNOTATION, pattern: /@Repository\b/ },
65
+ {
66
+ language: enums_1.Language.JAVA,
67
+ type: enums_1.CodePatternType.CLASS,
68
+ pattern: /extends\s+(Jpa|Crud|Mongo)Repository\b/,
69
+ },
70
+ { language: enums_1.Language.JAVA, type: enums_1.CodePatternType.ANNOTATION, pattern: /@Query\b/ },
71
+ // TypeScript/JavaScript
72
+ {
73
+ language: enums_1.Language.TYPESCRIPT,
74
+ type: enums_1.CodePatternType.ANNOTATION,
75
+ pattern: /@EntityRepository\s*\(/,
76
+ },
77
+ {
78
+ language: enums_1.Language.TYPESCRIPT,
79
+ type: enums_1.CodePatternType.PATTERN,
80
+ pattern: /\.repository\.ts$/,
81
+ },
82
+ // C#
83
+ { language: enums_1.Language.CSHARP, type: enums_1.CodePatternType.PATTERN, pattern: /DbContext\b/ },
84
+ { language: enums_1.Language.CSHARP, type: enums_1.CodePatternType.PATTERN, pattern: /DbSet\s*</ },
85
+ {
86
+ language: enums_1.Language.CSHARP,
87
+ type: enums_1.CodePatternType.PATTERN,
88
+ pattern: /interface\s+I\w+Repository\b/,
89
+ },
90
+ // PHP
91
+ { language: enums_1.Language.PHP, type: enums_1.CodePatternType.PATTERN, pattern: /DB::table\s*\(/ },
92
+ // Python
93
+ {
94
+ language: enums_1.Language.PYTHON,
95
+ type: enums_1.CodePatternType.PATTERN,
96
+ pattern: /class\s+\w+Repository\b/,
97
+ },
98
+ // Go
99
+ {
100
+ language: enums_1.Language.GO,
101
+ type: enums_1.CodePatternType.PATTERN,
102
+ pattern: /type\s+\w+Repository\s+struct/,
103
+ },
104
+ ],
105
+ }, {
106
+ isKeyIndicator: true,
107
+ tags: ['layered', 'data', 'repository'],
108
+ });
109
+ let L003DataLayer = (() => {
110
+ let _classDecorators = [(0, rule_registry_1.RegisterRule)(rule)];
111
+ let _classDescriptor;
112
+ let _classExtraInitializers = [];
113
+ let _classThis;
114
+ let _classSuper = base_rule_1.BaseRule;
115
+ var L003DataLayer = _classThis = class extends _classSuper {
116
+ constructor() {
117
+ super(...arguments);
118
+ this.rule = rule;
119
+ }
120
+ async customDetection(context) {
121
+ const matches = [];
122
+ let hasFolders = false;
123
+ let hasFiles = false;
124
+ let hasCode = false;
125
+ // Check for repository folders
126
+ const repoFolders = [
127
+ 'repositories',
128
+ 'repository',
129
+ 'dao',
130
+ 'daos',
131
+ 'data',
132
+ 'persistence',
133
+ 'infrastructure',
134
+ 'gateways',
135
+ ];
136
+ for (const folder of repoFolders) {
137
+ const found = context.files.some((f) => f.relativePath.toLowerCase().includes(`/${folder}/`) ||
138
+ f.relativePath.toLowerCase().startsWith(`${folder}/`));
139
+ if (found) {
140
+ matches.push({
141
+ type: enums_1.MatchType.FOLDER,
142
+ path: folder,
143
+ matchedPattern: 'Repository folder',
144
+ });
145
+ hasFolders = true;
146
+ }
147
+ }
148
+ // Check for repository files
149
+ const repoFiles = context.files.filter((f) => /Repository\.(ts|js|java|cs|php|py|rb|go)$/i.test(f.fileName) ||
150
+ /Dao\.(ts|js|java|cs|php|py|rb|go)$/i.test(f.fileName) ||
151
+ /Gateway\.(ts|js|java|cs|php|py|rb|go)$/i.test(f.fileName) ||
152
+ /\.repository\.(ts|js)$/i.test(f.fileName));
153
+ if (repoFiles.length > 0) {
154
+ for (const file of repoFiles.slice(0, 5)) {
155
+ matches.push({
156
+ type: enums_1.MatchType.FILE,
157
+ path: file.relativePath,
158
+ matchedPattern: 'Repository file',
159
+ });
160
+ }
161
+ hasFiles = true;
162
+ }
163
+ // Check for code patterns
164
+ const sourceFiles = context.files
165
+ .filter((f) => !f.isTest && !f.isConfig && f.language)
166
+ .slice(0, 50);
167
+ const codePatterns = [
168
+ /@Repository\b/,
169
+ /extends\s+(Jpa|Crud|Mongo)Repository\b/,
170
+ /@EntityRepository\s*\(/,
171
+ /DbContext\b/,
172
+ /DbSet\s*</,
173
+ /type\s+\w+Repository\s+struct/,
174
+ ];
175
+ for (const file of sourceFiles) {
176
+ try {
177
+ const content = await context.helpers.readFile(file.absolutePath);
178
+ for (const pattern of codePatterns) {
179
+ if (pattern.test(content)) {
180
+ hasCode = true;
181
+ matches.push({
182
+ type: enums_1.MatchType.CODE,
183
+ path: file.relativePath,
184
+ matchedPattern: 'Repository pattern',
185
+ });
186
+ break;
187
+ }
188
+ }
189
+ if (hasCode && matches.length >= 10)
190
+ break;
191
+ }
192
+ catch {
193
+ // Skip unreadable files
194
+ }
195
+ }
196
+ // Calculate score
197
+ let score = 0;
198
+ if (hasFolders && hasFiles)
199
+ score = 1;
200
+ else if (hasFiles)
201
+ score = 0.7;
202
+ else if (hasCode)
203
+ score = 0.6;
204
+ else if (hasFolders)
205
+ score = 0.4;
206
+ return { matches, violations: [], score };
207
+ }
208
+ getMetadata(context, matches) {
209
+ const repoCount = matches.filter((m) => m.matchedPattern === 'Repository file').length;
210
+ return {
211
+ ...super.getMetadata(context, matches),
212
+ repositoryCount: repoCount,
213
+ hasDedicatedFolder: matches.some((m) => m.matchedPattern === 'Repository folder'),
214
+ };
215
+ }
216
+ };
217
+ __setFunctionName(_classThis, "L003DataLayer");
218
+ (() => {
219
+ const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0;
220
+ __esDecorate(null, _classDescriptor = { value: _classThis }, _classDecorators, { kind: "class", name: _classThis.name, metadata: _metadata }, null, _classExtraInitializers);
221
+ L003DataLayer = _classThis = _classDescriptor.value;
222
+ if (_metadata) Object.defineProperty(_classThis, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
223
+ __runInitializers(_classThis, _classExtraInitializers);
224
+ })();
225
+ return L003DataLayer = _classThis;
226
+ })();
227
+ exports.L003DataLayer = L003DataLayer;
228
+ exports.default = L003DataLayer;
229
+ //# sourceMappingURL=l003-data-layer.js.map
@@ -0,0 +1,204 @@
1
+ "use strict";
2
+ /**
3
+ * L004: Model/Entity Layer Exists
4
+ * Xác nhận có data models/entities định nghĩa rõ ràng
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.L004ModelLayer = 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)('L004', 'Model/Entity Layer Exists', 'Xác nhận có data models/entities định nghĩa rõ ràng', enums_1.RuleCategory.CORE, 0.1, [enums_1.PatternType.LAYERED], {
50
+ folderPatterns: ['models', 'model', 'entities', 'entity', 'domain', 'dtos', 'dto'],
51
+ filePatterns: ['*Entity.*', '*Model.*', '*Dto.*', '*VO.*', '*Domain.*'],
52
+ codePatterns: [
53
+ // Java
54
+ { language: enums_1.Language.JAVA, type: enums_1.CodePatternType.ANNOTATION, pattern: /@Entity\b/ },
55
+ { language: enums_1.Language.JAVA, type: enums_1.CodePatternType.ANNOTATION, pattern: /@Table\b/ },
56
+ { language: enums_1.Language.JAVA, type: enums_1.CodePatternType.ANNOTATION, pattern: /@Data\b/ },
57
+ // Kotlin
58
+ { language: enums_1.Language.KOTLIN, type: enums_1.CodePatternType.CLASS, pattern: /data\s+class\s+\w+/ },
59
+ // TypeScript/JavaScript
60
+ { language: enums_1.Language.TYPESCRIPT, type: enums_1.CodePatternType.ANNOTATION, pattern: /@Entity\s*\(/ },
61
+ { language: enums_1.Language.TYPESCRIPT, type: enums_1.CodePatternType.ANNOTATION, pattern: /@Column\s*\(/ },
62
+ {
63
+ language: enums_1.Language.TYPESCRIPT,
64
+ type: enums_1.CodePatternType.PATTERN,
65
+ pattern: /interface\s+\w+\s*\{/,
66
+ },
67
+ // C#
68
+ { language: enums_1.Language.CSHARP, type: enums_1.CodePatternType.ANNOTATION, pattern: /\[Table\s*\(/ },
69
+ { language: enums_1.Language.CSHARP, type: enums_1.CodePatternType.ANNOTATION, pattern: /\[Key\]/ },
70
+ // PHP
71
+ { language: enums_1.Language.PHP, type: enums_1.CodePatternType.CLASS, pattern: /extends\s+Model\b/ },
72
+ // Python
73
+ { language: enums_1.Language.PYTHON, type: enums_1.CodePatternType.ANNOTATION, pattern: /@dataclass\b/ },
74
+ // Go
75
+ { language: enums_1.Language.GO, type: enums_1.CodePatternType.PATTERN, pattern: /type\s+\w+\s+struct\s*\{/ },
76
+ ],
77
+ }, {
78
+ isKeyIndicator: true,
79
+ tags: ['layered', 'model', 'entity'],
80
+ });
81
+ let L004ModelLayer = (() => {
82
+ let _classDecorators = [(0, rule_registry_1.RegisterRule)(rule)];
83
+ let _classDescriptor;
84
+ let _classExtraInitializers = [];
85
+ let _classThis;
86
+ let _classSuper = base_rule_1.BaseRule;
87
+ var L004ModelLayer = _classThis = class extends _classSuper {
88
+ constructor() {
89
+ super(...arguments);
90
+ this.rule = rule;
91
+ }
92
+ async customDetection(context) {
93
+ const matches = [];
94
+ let hasFolders = false;
95
+ let hasFiles = false;
96
+ let hasCode = false;
97
+ // Check for model folders
98
+ const modelFolders = [
99
+ 'models',
100
+ 'model',
101
+ 'entities',
102
+ 'entity',
103
+ 'domain',
104
+ 'dtos',
105
+ 'dto',
106
+ 'types',
107
+ ];
108
+ for (const folder of modelFolders) {
109
+ const found = context.files.some((f) => f.relativePath.toLowerCase().includes(`/${folder}/`) ||
110
+ f.relativePath.toLowerCase().startsWith(`${folder}/`));
111
+ if (found) {
112
+ matches.push({
113
+ type: enums_1.MatchType.FOLDER,
114
+ path: folder,
115
+ matchedPattern: 'Model folder',
116
+ });
117
+ hasFolders = true;
118
+ }
119
+ }
120
+ // Check for model/entity files
121
+ const modelFiles = context.files.filter((f) => /Entity\.(ts|js|java|cs|php|py|rb|go)$/i.test(f.fileName) ||
122
+ /Model\.(ts|js|java|cs|php|py|rb|go)$/i.test(f.fileName) ||
123
+ /Dto\.(ts|js|java|cs|php|py|rb|go)$/i.test(f.fileName) ||
124
+ /\.entity\.(ts|js)$/i.test(f.fileName) ||
125
+ /\.model\.(ts|js)$/i.test(f.fileName) ||
126
+ /\.dto\.(ts|js)$/i.test(f.fileName));
127
+ if (modelFiles.length > 0) {
128
+ for (const file of modelFiles.slice(0, 5)) {
129
+ matches.push({
130
+ type: enums_1.MatchType.FILE,
131
+ path: file.relativePath,
132
+ matchedPattern: 'Model file',
133
+ });
134
+ }
135
+ hasFiles = true;
136
+ }
137
+ // Check for code patterns
138
+ const sourceFiles = context.files
139
+ .filter((f) => !f.isTest && !f.isConfig && f.language)
140
+ .slice(0, 50);
141
+ const codePatterns = [
142
+ /@Entity\b/,
143
+ /@Table\b/,
144
+ /@Data\b/,
145
+ /data\s+class\s+\w+/,
146
+ /\[Table\s*\(/,
147
+ /extends\s+Model\b/,
148
+ /@dataclass\b/,
149
+ ];
150
+ for (const file of sourceFiles) {
151
+ try {
152
+ const content = await context.helpers.readFile(file.absolutePath);
153
+ for (const pattern of codePatterns) {
154
+ if (pattern.test(content)) {
155
+ hasCode = true;
156
+ matches.push({
157
+ type: enums_1.MatchType.CODE,
158
+ path: file.relativePath,
159
+ matchedPattern: 'Model pattern',
160
+ });
161
+ break;
162
+ }
163
+ }
164
+ if (hasCode && matches.length >= 10)
165
+ break;
166
+ }
167
+ catch {
168
+ // Skip unreadable files
169
+ }
170
+ }
171
+ // Calculate score
172
+ let score = 0;
173
+ if (hasFolders && hasFiles)
174
+ score = 1;
175
+ else if (hasFiles)
176
+ score = 0.7;
177
+ else if (hasCode)
178
+ score = 0.6;
179
+ else if (hasFolders)
180
+ score = 0.4;
181
+ return { matches, violations: [], score };
182
+ }
183
+ getMetadata(context, matches) {
184
+ const modelCount = matches.filter((m) => m.matchedPattern === 'Model file').length;
185
+ return {
186
+ ...super.getMetadata(context, matches),
187
+ modelCount,
188
+ hasDedicatedFolder: matches.some((m) => m.matchedPattern === 'Model folder'),
189
+ };
190
+ }
191
+ };
192
+ __setFunctionName(_classThis, "L004ModelLayer");
193
+ (() => {
194
+ const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0;
195
+ __esDecorate(null, _classDescriptor = { value: _classThis }, _classDecorators, { kind: "class", name: _classThis.name, metadata: _metadata }, null, _classExtraInitializers);
196
+ L004ModelLayer = _classThis = _classDescriptor.value;
197
+ if (_metadata) Object.defineProperty(_classThis, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
198
+ __runInitializers(_classThis, _classExtraInitializers);
199
+ })();
200
+ return L004ModelLayer = _classThis;
201
+ })();
202
+ exports.L004ModelLayer = L004ModelLayer;
203
+ exports.default = L004ModelLayer;
204
+ //# sourceMappingURL=l004-model-layer.js.map