@sun-asterisk/sunlint 1.3.34 → 1.3.36
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 +102 -2
- package/core/cli-program.js +102 -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 +551 -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,192 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* PR002: Presentation Logic Layer Exists
|
|
4
|
+
* Xác nhận có tầng xử lý presentation logic (ViewModel/Presenter)
|
|
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.PR002PresentationLogic = 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)('PR002', 'Presentation Logic Layer Exists', 'Xác nhận có tầng xử lý presentation logic (ViewModel, Presenter)', enums_1.RuleCategory.CORE, 0.12, [enums_1.PatternType.PRESENTATION, enums_1.PatternType.MVVM, enums_1.PatternType.VIPER], {
|
|
50
|
+
folderPatterns: ['viewmodels', 'view-models', 'presenters', 'ViewModels', 'Presenters'],
|
|
51
|
+
filePatterns: ['*ViewModel.*', '*Presenter.*', '*VM.*'],
|
|
52
|
+
codePatterns: [
|
|
53
|
+
// Android
|
|
54
|
+
{
|
|
55
|
+
language: enums_1.Language.KOTLIN,
|
|
56
|
+
type: enums_1.CodePatternType.CLASS,
|
|
57
|
+
pattern: /class\s+\w+ViewModel\s*:\s*ViewModel\s*\(/,
|
|
58
|
+
},
|
|
59
|
+
{ language: enums_1.Language.KOTLIN, type: enums_1.CodePatternType.ANNOTATION, pattern: /@HiltViewModel/ },
|
|
60
|
+
// iOS
|
|
61
|
+
{
|
|
62
|
+
language: enums_1.Language.SWIFT,
|
|
63
|
+
type: enums_1.CodePatternType.CLASS,
|
|
64
|
+
pattern: /class\s+\w+ViewModel\s*:\s*ObservableObject/,
|
|
65
|
+
},
|
|
66
|
+
{ language: enums_1.Language.SWIFT, type: enums_1.CodePatternType.ANNOTATION, pattern: /@Published/ },
|
|
67
|
+
// Flutter
|
|
68
|
+
{
|
|
69
|
+
language: enums_1.Language.DART,
|
|
70
|
+
type: enums_1.CodePatternType.CLASS,
|
|
71
|
+
pattern: /class\s+\w+ViewModel\s+extends\s+ChangeNotifier/,
|
|
72
|
+
},
|
|
73
|
+
// Vue
|
|
74
|
+
{ language: enums_1.Language.TYPESCRIPT, type: enums_1.CodePatternType.PATTERN, pattern: /ref\s*[<(]/ },
|
|
75
|
+
{ language: enums_1.Language.TYPESCRIPT, type: enums_1.CodePatternType.PATTERN, pattern: /reactive\s*[<(]/ },
|
|
76
|
+
// WPF
|
|
77
|
+
{
|
|
78
|
+
language: enums_1.Language.CSHARP,
|
|
79
|
+
type: enums_1.CodePatternType.PATTERN,
|
|
80
|
+
pattern: /:\s*INotifyPropertyChanged/,
|
|
81
|
+
},
|
|
82
|
+
],
|
|
83
|
+
}, {
|
|
84
|
+
isKeyIndicator: true,
|
|
85
|
+
tags: ['presentation', 'viewmodel', 'presenter'],
|
|
86
|
+
});
|
|
87
|
+
let PR002PresentationLogic = (() => {
|
|
88
|
+
let _classDecorators = [(0, rule_registry_1.RegisterRule)(rule)];
|
|
89
|
+
let _classDescriptor;
|
|
90
|
+
let _classExtraInitializers = [];
|
|
91
|
+
let _classThis;
|
|
92
|
+
let _classSuper = base_rule_1.BaseRule;
|
|
93
|
+
var PR002PresentationLogic = _classThis = class extends _classSuper {
|
|
94
|
+
constructor() {
|
|
95
|
+
super(...arguments);
|
|
96
|
+
this.rule = rule;
|
|
97
|
+
}
|
|
98
|
+
async customDetection(context) {
|
|
99
|
+
const matches = [];
|
|
100
|
+
let hasFolders = false;
|
|
101
|
+
let hasFiles = false;
|
|
102
|
+
let hasCode = false;
|
|
103
|
+
// Check for viewmodel/presenter folders
|
|
104
|
+
const vmFolders = ['viewmodels', 'view-models', 'presenters', 'view_models'];
|
|
105
|
+
for (const folder of vmFolders) {
|
|
106
|
+
const found = context.files.some((f) => f.relativePath.toLowerCase().includes(`/${folder}/`) ||
|
|
107
|
+
f.relativePath.toLowerCase().startsWith(`${folder}/`));
|
|
108
|
+
if (found) {
|
|
109
|
+
matches.push({
|
|
110
|
+
type: enums_1.MatchType.FOLDER,
|
|
111
|
+
path: folder,
|
|
112
|
+
matchedPattern: 'ViewModel folder',
|
|
113
|
+
});
|
|
114
|
+
hasFolders = true;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
// Check for viewmodel/presenter files
|
|
118
|
+
const vmFiles = context.files.filter((f) => /ViewModel\.(ts|tsx|js|swift|kt|dart|cs)$/i.test(f.fileName) ||
|
|
119
|
+
/Presenter\.(ts|tsx|js|swift|kt|dart|cs)$/i.test(f.fileName) ||
|
|
120
|
+
/\.viewmodel\.(ts|js)$/i.test(f.fileName) ||
|
|
121
|
+
/_view_model\.dart$/i.test(f.fileName));
|
|
122
|
+
if (vmFiles.length > 0) {
|
|
123
|
+
for (const file of vmFiles.slice(0, 5)) {
|
|
124
|
+
matches.push({
|
|
125
|
+
type: enums_1.MatchType.FILE,
|
|
126
|
+
path: file.relativePath,
|
|
127
|
+
matchedPattern: 'ViewModel file',
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
hasFiles = true;
|
|
131
|
+
}
|
|
132
|
+
// Check for code patterns
|
|
133
|
+
const sourceFiles = context.files
|
|
134
|
+
.filter((f) => !f.isTest && !f.isConfig && f.language)
|
|
135
|
+
.slice(0, 50);
|
|
136
|
+
const codePatterns = [
|
|
137
|
+
/class\s+\w+ViewModel/,
|
|
138
|
+
/@HiltViewModel/,
|
|
139
|
+
/ObservableObject/,
|
|
140
|
+
/@Published/,
|
|
141
|
+
/extends\s+ChangeNotifier/,
|
|
142
|
+
/INotifyPropertyChanged/,
|
|
143
|
+
/ref\s*</,
|
|
144
|
+
/reactive\s*</,
|
|
145
|
+
];
|
|
146
|
+
for (const file of sourceFiles) {
|
|
147
|
+
try {
|
|
148
|
+
const content = await context.helpers.readFile(file.absolutePath);
|
|
149
|
+
for (const pattern of codePatterns) {
|
|
150
|
+
if (pattern.test(content)) {
|
|
151
|
+
hasCode = true;
|
|
152
|
+
matches.push({
|
|
153
|
+
type: enums_1.MatchType.CODE,
|
|
154
|
+
path: file.relativePath,
|
|
155
|
+
matchedPattern: 'ViewModel pattern',
|
|
156
|
+
});
|
|
157
|
+
break;
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
if (hasCode && matches.length >= 10)
|
|
161
|
+
break;
|
|
162
|
+
}
|
|
163
|
+
catch {
|
|
164
|
+
// Skip
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
// Calculate score
|
|
168
|
+
let score = 0;
|
|
169
|
+
if (hasFolders && hasFiles)
|
|
170
|
+
score = 1;
|
|
171
|
+
else if (hasFiles)
|
|
172
|
+
score = 0.7;
|
|
173
|
+
else if (hasCode)
|
|
174
|
+
score = 0.6;
|
|
175
|
+
else if (hasFolders)
|
|
176
|
+
score = 0.4;
|
|
177
|
+
return { matches, violations: [], score };
|
|
178
|
+
}
|
|
179
|
+
};
|
|
180
|
+
__setFunctionName(_classThis, "PR002PresentationLogic");
|
|
181
|
+
(() => {
|
|
182
|
+
const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0;
|
|
183
|
+
__esDecorate(null, _classDescriptor = { value: _classThis }, _classDecorators, { kind: "class", name: _classThis.name, metadata: _metadata }, null, _classExtraInitializers);
|
|
184
|
+
PR002PresentationLogic = _classThis = _classDescriptor.value;
|
|
185
|
+
if (_metadata) Object.defineProperty(_classThis, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
|
|
186
|
+
__runInitializers(_classThis, _classExtraInitializers);
|
|
187
|
+
})();
|
|
188
|
+
return PR002PresentationLogic = _classThis;
|
|
189
|
+
})();
|
|
190
|
+
exports.PR002PresentationLogic = PR002PresentationLogic;
|
|
191
|
+
exports.default = PR002PresentationLogic;
|
|
192
|
+
//# sourceMappingURL=pr002-presentation-logic.js.map
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* PR004: Data Binding Mechanism (MVVM Indicator)
|
|
4
|
+
* Xác nhận có cơ chế data binding - KEY INDICATOR FOR MVVM
|
|
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.PR004DataBinding = 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)('PR004', 'Data Binding Mechanism', 'Xác nhận có cơ chế data binding - KEY INDICATOR FOR MVVM', enums_1.RuleCategory.CORE, 0.14, [enums_1.PatternType.PRESENTATION, enums_1.PatternType.MVVM], {
|
|
50
|
+
codePatterns: [
|
|
51
|
+
// Android Jetpack
|
|
52
|
+
{ language: enums_1.Language.KOTLIN, type: enums_1.CodePatternType.PATTERN, pattern: /LiveData\s*</ },
|
|
53
|
+
{ language: enums_1.Language.KOTLIN, type: enums_1.CodePatternType.PATTERN, pattern: /MutableLiveData\s*</ },
|
|
54
|
+
{ language: enums_1.Language.KOTLIN, type: enums_1.CodePatternType.PATTERN, pattern: /StateFlow\s*</ },
|
|
55
|
+
{ language: enums_1.Language.KOTLIN, type: enums_1.CodePatternType.PATTERN, pattern: /MutableStateFlow\s*</ },
|
|
56
|
+
{ language: enums_1.Language.KOTLIN, type: enums_1.CodePatternType.PATTERN, pattern: /collectAsState\s*\(/ },
|
|
57
|
+
// Android Compose
|
|
58
|
+
{
|
|
59
|
+
language: enums_1.Language.KOTLIN,
|
|
60
|
+
type: enums_1.CodePatternType.PATTERN,
|
|
61
|
+
pattern: /remember\s*\{\s*mutableStateOf/,
|
|
62
|
+
},
|
|
63
|
+
{ language: enums_1.Language.KOTLIN, type: enums_1.CodePatternType.PATTERN, pattern: /State\s*</ },
|
|
64
|
+
// iOS SwiftUI
|
|
65
|
+
{ language: enums_1.Language.SWIFT, type: enums_1.CodePatternType.ANNOTATION, pattern: /@Published/ },
|
|
66
|
+
{ language: enums_1.Language.SWIFT, type: enums_1.CodePatternType.ANNOTATION, pattern: /@ObservedObject/ },
|
|
67
|
+
{ language: enums_1.Language.SWIFT, type: enums_1.CodePatternType.ANNOTATION, pattern: /@StateObject/ },
|
|
68
|
+
{ language: enums_1.Language.SWIFT, type: enums_1.CodePatternType.ANNOTATION, pattern: /@Binding/ },
|
|
69
|
+
{ language: enums_1.Language.SWIFT, type: enums_1.CodePatternType.ANNOTATION, pattern: /@State/ },
|
|
70
|
+
// Vue 3
|
|
71
|
+
{ language: enums_1.Language.TYPESCRIPT, type: enums_1.CodePatternType.PATTERN, pattern: /ref\s*[<(]/ },
|
|
72
|
+
{ language: enums_1.Language.TYPESCRIPT, type: enums_1.CodePatternType.PATTERN, pattern: /reactive\s*[<(]/ },
|
|
73
|
+
{ language: enums_1.Language.TYPESCRIPT, type: enums_1.CodePatternType.PATTERN, pattern: /computed\s*\(/ },
|
|
74
|
+
{ language: enums_1.Language.TYPESCRIPT, type: enums_1.CodePatternType.PATTERN, pattern: /watch\s*\(/ },
|
|
75
|
+
// Flutter
|
|
76
|
+
{ language: enums_1.Language.DART, type: enums_1.CodePatternType.PATTERN, pattern: /ChangeNotifier/ },
|
|
77
|
+
{ language: enums_1.Language.DART, type: enums_1.CodePatternType.PATTERN, pattern: /notifyListeners\s*\(/ },
|
|
78
|
+
{ language: enums_1.Language.DART, type: enums_1.CodePatternType.PATTERN, pattern: /ValueNotifier/ },
|
|
79
|
+
// WPF/MAUI
|
|
80
|
+
{
|
|
81
|
+
language: enums_1.Language.CSHARP,
|
|
82
|
+
type: enums_1.CodePatternType.PATTERN,
|
|
83
|
+
pattern: /INotifyPropertyChanged/,
|
|
84
|
+
},
|
|
85
|
+
{
|
|
86
|
+
language: enums_1.Language.CSHARP,
|
|
87
|
+
type: enums_1.CodePatternType.PATTERN,
|
|
88
|
+
pattern: /PropertyChanged\?\s*\.Invoke/,
|
|
89
|
+
},
|
|
90
|
+
// React
|
|
91
|
+
{ language: enums_1.Language.TYPESCRIPT, type: enums_1.CodePatternType.PATTERN, pattern: /useState\s*[<(]/ },
|
|
92
|
+
{ language: enums_1.Language.TYPESCRIPT, type: enums_1.CodePatternType.PATTERN, pattern: /useReducer\s*\(/ },
|
|
93
|
+
// Angular
|
|
94
|
+
{ language: enums_1.Language.TYPESCRIPT, type: enums_1.CodePatternType.PATTERN, pattern: /\|\s*async/ },
|
|
95
|
+
],
|
|
96
|
+
}, {
|
|
97
|
+
isKeyIndicator: true,
|
|
98
|
+
tags: ['presentation', 'mvvm', 'data-binding'],
|
|
99
|
+
});
|
|
100
|
+
let PR004DataBinding = (() => {
|
|
101
|
+
let _classDecorators = [(0, rule_registry_1.RegisterRule)(rule)];
|
|
102
|
+
let _classDescriptor;
|
|
103
|
+
let _classExtraInitializers = [];
|
|
104
|
+
let _classThis;
|
|
105
|
+
let _classSuper = base_rule_1.BaseRule;
|
|
106
|
+
var PR004DataBinding = _classThis = class extends _classSuper {
|
|
107
|
+
constructor() {
|
|
108
|
+
super(...arguments);
|
|
109
|
+
this.rule = rule;
|
|
110
|
+
}
|
|
111
|
+
async customDetection(context) {
|
|
112
|
+
const matches = [];
|
|
113
|
+
const bindingPatterns = [];
|
|
114
|
+
// Patterns grouped by platform
|
|
115
|
+
const platformPatterns = {
|
|
116
|
+
'Android StateFlow': [/StateFlow\s*</, /MutableStateFlow\s*</],
|
|
117
|
+
'Android LiveData': [/LiveData\s*</, /MutableLiveData\s*</],
|
|
118
|
+
'Android Compose': [/mutableStateOf/, /collectAsState/],
|
|
119
|
+
'iOS SwiftUI': [/@Published/, /@StateObject/, /@ObservedObject/, /@Binding/],
|
|
120
|
+
'iOS Combine': [/PassthroughSubject/, /CurrentValueSubject/],
|
|
121
|
+
'Vue Reactivity': [/ref\s*[<(]/, /reactive\s*[<(]/, /computed\s*\(/],
|
|
122
|
+
'Flutter ChangeNotifier': [/ChangeNotifier/, /notifyListeners/],
|
|
123
|
+
'WPF Binding': [/INotifyPropertyChanged/, /PropertyChanged\?/],
|
|
124
|
+
'React Hooks': [/useState\s*[<(]/, /useReducer\s*\(/],
|
|
125
|
+
};
|
|
126
|
+
const sourceFiles = context.files
|
|
127
|
+
.filter((f) => !f.isTest && !f.isConfig && f.language)
|
|
128
|
+
.slice(0, 100);
|
|
129
|
+
for (const file of sourceFiles) {
|
|
130
|
+
try {
|
|
131
|
+
const content = await context.helpers.readFile(file.absolutePath);
|
|
132
|
+
for (const [platform, patterns] of Object.entries(platformPatterns)) {
|
|
133
|
+
for (const pattern of patterns) {
|
|
134
|
+
if (pattern.test(content)) {
|
|
135
|
+
if (!bindingPatterns.includes(platform)) {
|
|
136
|
+
bindingPatterns.push(platform);
|
|
137
|
+
matches.push({
|
|
138
|
+
type: enums_1.MatchType.CODE,
|
|
139
|
+
path: file.relativePath,
|
|
140
|
+
matchedPattern: `Data binding: ${platform}`,
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
break;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
if (matches.length >= 10)
|
|
148
|
+
break;
|
|
149
|
+
}
|
|
150
|
+
catch {
|
|
151
|
+
// Skip
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
// Calculate score based on binding patterns found
|
|
155
|
+
let score = 0;
|
|
156
|
+
if (bindingPatterns.length >= 2)
|
|
157
|
+
score = 1;
|
|
158
|
+
else if (bindingPatterns.length === 1)
|
|
159
|
+
score = 0.7;
|
|
160
|
+
else
|
|
161
|
+
score = 0;
|
|
162
|
+
return { matches, violations: [], score };
|
|
163
|
+
}
|
|
164
|
+
getMetadata(context, matches) {
|
|
165
|
+
const platforms = matches
|
|
166
|
+
.filter((m) => m.matchedPattern?.startsWith('Data binding'))
|
|
167
|
+
.map((m) => m.matchedPattern?.replace('Data binding: ', ''));
|
|
168
|
+
return {
|
|
169
|
+
...super.getMetadata(context, matches),
|
|
170
|
+
dataBindingPlatforms: [...new Set(platforms)],
|
|
171
|
+
hasDataBinding: platforms.length > 0,
|
|
172
|
+
};
|
|
173
|
+
}
|
|
174
|
+
};
|
|
175
|
+
__setFunctionName(_classThis, "PR004DataBinding");
|
|
176
|
+
(() => {
|
|
177
|
+
const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0;
|
|
178
|
+
__esDecorate(null, _classDescriptor = { value: _classThis }, _classDecorators, { kind: "class", name: _classThis.name, metadata: _metadata }, null, _classExtraInitializers);
|
|
179
|
+
PR004DataBinding = _classThis = _classDescriptor.value;
|
|
180
|
+
if (_metadata) Object.defineProperty(_classThis, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
|
|
181
|
+
__runInitializers(_classThis, _classExtraInitializers);
|
|
182
|
+
})();
|
|
183
|
+
return PR004DataBinding = _classThis;
|
|
184
|
+
})();
|
|
185
|
+
exports.PR004DataBinding = PR004DataBinding;
|
|
186
|
+
exports.default = PR004DataBinding;
|
|
187
|
+
//# sourceMappingURL=pr004-data-binding.js.map
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* PR006: Router/Wireframe Layer (VIPER Indicator)
|
|
4
|
+
* Xác nhận có Router tách biệt - KEY INDICATOR FOR VIPER
|
|
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.PR006RouterLayer = 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)('PR006', 'Router/Wireframe Layer', 'Xác nhận có Router tách biệt - KEY INDICATOR FOR VIPER', enums_1.RuleCategory.CORE, 0.1, [enums_1.PatternType.PRESENTATION, enums_1.PatternType.VIPER], {
|
|
50
|
+
folderPatterns: ['routers', 'wireframes', 'navigation', 'routing', 'Routers', 'coordinators'],
|
|
51
|
+
filePatterns: ['*Router.*', '*Wireframe.*', '*Coordinator.*', '*Navigator.*'],
|
|
52
|
+
codePatterns: [
|
|
53
|
+
{ language: enums_1.Language.SWIFT, type: enums_1.CodePatternType.PATTERN, pattern: /protocol\s+\w+Router/ },
|
|
54
|
+
{ language: enums_1.Language.SWIFT, type: enums_1.CodePatternType.PATTERN, pattern: /class\s+\w+Router/ },
|
|
55
|
+
{
|
|
56
|
+
language: enums_1.Language.SWIFT,
|
|
57
|
+
type: enums_1.CodePatternType.PATTERN,
|
|
58
|
+
pattern: /class\s+\w+Coordinator/,
|
|
59
|
+
},
|
|
60
|
+
{ language: enums_1.Language.SWIFT, type: enums_1.CodePatternType.METHOD, pattern: /func\s+navigate/ },
|
|
61
|
+
{ language: enums_1.Language.SWIFT, type: enums_1.CodePatternType.METHOD, pattern: /func\s+present/ },
|
|
62
|
+
{
|
|
63
|
+
language: enums_1.Language.KOTLIN,
|
|
64
|
+
type: enums_1.CodePatternType.PATTERN,
|
|
65
|
+
pattern: /interface\s+\w+Router/,
|
|
66
|
+
},
|
|
67
|
+
{ language: enums_1.Language.KOTLIN, type: enums_1.CodePatternType.PATTERN, pattern: /class\s+\w+Router/ },
|
|
68
|
+
],
|
|
69
|
+
}, {
|
|
70
|
+
isKeyIndicator: true,
|
|
71
|
+
tags: ['presentation', 'viper', 'router', 'navigation'],
|
|
72
|
+
});
|
|
73
|
+
let PR006RouterLayer = (() => {
|
|
74
|
+
let _classDecorators = [(0, rule_registry_1.RegisterRule)(rule)];
|
|
75
|
+
let _classDescriptor;
|
|
76
|
+
let _classExtraInitializers = [];
|
|
77
|
+
let _classThis;
|
|
78
|
+
let _classSuper = base_rule_1.BaseRule;
|
|
79
|
+
var PR006RouterLayer = _classThis = class extends _classSuper {
|
|
80
|
+
constructor() {
|
|
81
|
+
super(...arguments);
|
|
82
|
+
this.rule = rule;
|
|
83
|
+
}
|
|
84
|
+
async customDetection(context) {
|
|
85
|
+
const matches = [];
|
|
86
|
+
let hasFolders = false;
|
|
87
|
+
let hasFiles = false;
|
|
88
|
+
let hasCode = false;
|
|
89
|
+
// Check for router folders - include singular forms for VIPER
|
|
90
|
+
const routerFolders = [
|
|
91
|
+
'routers',
|
|
92
|
+
'router',
|
|
93
|
+
'wireframes',
|
|
94
|
+
'wireframe',
|
|
95
|
+
'navigation',
|
|
96
|
+
'routing',
|
|
97
|
+
'coordinators',
|
|
98
|
+
'coordinator',
|
|
99
|
+
];
|
|
100
|
+
for (const folder of routerFolders) {
|
|
101
|
+
const found = context.files.some((f) => f.relativePath.toLowerCase().includes(`/${folder}/`) ||
|
|
102
|
+
f.relativePath.toLowerCase().startsWith(`${folder}/`));
|
|
103
|
+
if (found) {
|
|
104
|
+
matches.push({
|
|
105
|
+
type: enums_1.MatchType.FOLDER,
|
|
106
|
+
path: folder,
|
|
107
|
+
matchedPattern: 'Router folder',
|
|
108
|
+
});
|
|
109
|
+
hasFolders = true;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
// Check for router files - match any file containing Router/Wireframe/WireFrame/Coordinator
|
|
113
|
+
const routerFiles = context.files.filter((f) => /Router\.(swift|kt|java|ts|js)$/i.test(f.fileName) ||
|
|
114
|
+
/WireFrame\.(swift|kt|java)$/i.test(f.fileName) ||
|
|
115
|
+
/Wireframe\.(swift|kt|java)$/i.test(f.fileName) ||
|
|
116
|
+
/Coordinator\.(swift|kt|java|ts)$/i.test(f.fileName));
|
|
117
|
+
if (routerFiles.length > 0) {
|
|
118
|
+
for (const file of routerFiles.slice(0, 5)) {
|
|
119
|
+
matches.push({
|
|
120
|
+
type: enums_1.MatchType.FILE,
|
|
121
|
+
path: file.relativePath,
|
|
122
|
+
matchedPattern: 'Router file',
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
hasFiles = true;
|
|
126
|
+
}
|
|
127
|
+
// Check for code patterns
|
|
128
|
+
const sourceFiles = context.files
|
|
129
|
+
.filter((f) => !f.isTest && !f.isConfig && f.language)
|
|
130
|
+
.slice(0, 50);
|
|
131
|
+
const codePatterns = [
|
|
132
|
+
/protocol\s+\w+Router/,
|
|
133
|
+
/class\s+\w+Router/,
|
|
134
|
+
/class\s+\w+Coordinator/,
|
|
135
|
+
/func\s+navigateTo/,
|
|
136
|
+
/func\s+presentModule/,
|
|
137
|
+
/interface\s+\w+Router/,
|
|
138
|
+
];
|
|
139
|
+
for (const file of sourceFiles) {
|
|
140
|
+
try {
|
|
141
|
+
const content = await context.helpers.readFile(file.absolutePath);
|
|
142
|
+
for (const pattern of codePatterns) {
|
|
143
|
+
if (pattern.test(content)) {
|
|
144
|
+
hasCode = true;
|
|
145
|
+
matches.push({
|
|
146
|
+
type: enums_1.MatchType.CODE,
|
|
147
|
+
path: file.relativePath,
|
|
148
|
+
matchedPattern: 'Router pattern',
|
|
149
|
+
});
|
|
150
|
+
break;
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
if (hasCode && matches.length >= 10)
|
|
154
|
+
break;
|
|
155
|
+
}
|
|
156
|
+
catch {
|
|
157
|
+
// Skip
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
// Calculate score
|
|
161
|
+
let score = 0;
|
|
162
|
+
if (hasFolders && hasFiles)
|
|
163
|
+
score = 1;
|
|
164
|
+
else if (hasFiles)
|
|
165
|
+
score = 0.7;
|
|
166
|
+
else if (hasCode)
|
|
167
|
+
score = 0.6;
|
|
168
|
+
else if (hasFolders)
|
|
169
|
+
score = 0.4;
|
|
170
|
+
return { matches, violations: [], score };
|
|
171
|
+
}
|
|
172
|
+
};
|
|
173
|
+
__setFunctionName(_classThis, "PR006RouterLayer");
|
|
174
|
+
(() => {
|
|
175
|
+
const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0;
|
|
176
|
+
__esDecorate(null, _classDescriptor = { value: _classThis }, _classDecorators, { kind: "class", name: _classThis.name, metadata: _metadata }, null, _classExtraInitializers);
|
|
177
|
+
PR006RouterLayer = _classThis = _classDescriptor.value;
|
|
178
|
+
if (_metadata) Object.defineProperty(_classThis, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
|
|
179
|
+
__runInitializers(_classThis, _classExtraInitializers);
|
|
180
|
+
})();
|
|
181
|
+
return PR006RouterLayer = _classThis;
|
|
182
|
+
})();
|
|
183
|
+
exports.PR006RouterLayer = PR006RouterLayer;
|
|
184
|
+
exports.default = PR006RouterLayer;
|
|
185
|
+
//# sourceMappingURL=pr006-router-layer.js.map
|