@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.
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 +102 -2
  4. package/core/cli-program.js +102 -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 +551 -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,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