pumuki-ast-hooks 5.5.46 → 5.5.48

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 (31) hide show
  1. package/docs/CODE_STANDARDS.md +5 -0
  2. package/docs/VIOLATIONS_RESOLUTION_PLAN.md +22 -34
  3. package/package.json +2 -2
  4. package/scripts/hooks-system/.audit_tmp/hook-metrics.jsonl +36 -0
  5. package/scripts/hooks-system/application/services/installation/FileSystemInstallerService.js +1 -1
  6. package/scripts/hooks-system/application/services/installation/VSCodeTaskConfigurator.js +8 -2
  7. package/scripts/hooks-system/bin/gitflow-cycle.js +0 -0
  8. package/scripts/hooks-system/config/project.config.json +1 -1
  9. package/scripts/hooks-system/infrastructure/ast/android/analyzers/AndroidSOLIDAnalyzer.js +11 -255
  10. package/scripts/hooks-system/infrastructure/ast/android/detectors/android-solid-detectors.js +227 -0
  11. package/scripts/hooks-system/infrastructure/ast/ast-core.js +12 -3
  12. package/scripts/hooks-system/infrastructure/ast/ast-intelligence.js +36 -13
  13. package/scripts/hooks-system/infrastructure/ast/backend/ast-backend.js +10 -83
  14. package/scripts/hooks-system/infrastructure/ast/backend/detectors/god-class-detector.js +83 -0
  15. package/scripts/hooks-system/infrastructure/ast/common/ast-common.js +17 -2
  16. package/scripts/hooks-system/infrastructure/ast/frontend/analyzers/FrontendArchitectureDetector.js +12 -142
  17. package/scripts/hooks-system/infrastructure/ast/frontend/detectors/frontend-architecture-strategies.js +126 -0
  18. package/scripts/hooks-system/infrastructure/ast/ios/analyzers/iOSASTIntelligentAnalyzer.js +30 -783
  19. package/scripts/hooks-system/infrastructure/ast/ios/analyzers/iOSArchitectureDetector.js +21 -224
  20. package/scripts/hooks-system/infrastructure/ast/ios/analyzers/iOSArchitectureRules.js +18 -605
  21. package/scripts/hooks-system/infrastructure/ast/ios/analyzers/iOSModernPracticesRules.js +4 -1
  22. package/scripts/hooks-system/infrastructure/ast/ios/ast-ios.js +4 -1
  23. package/scripts/hooks-system/infrastructure/ast/ios/detectors/ios-architecture-rules-strategies.js +595 -0
  24. package/scripts/hooks-system/infrastructure/ast/ios/detectors/ios-architecture-strategies.js +192 -0
  25. package/scripts/hooks-system/infrastructure/ast/ios/detectors/ios-ast-intelligent-strategies.js +789 -0
  26. package/scripts/hooks-system/infrastructure/ast/ios/detectors/ios-god-class-detector.js +79 -0
  27. package/scripts/hooks-system/infrastructure/ast/ios/native-bridge.js +4 -1
  28. package/skills/android-guidelines/SKILL.md +1 -0
  29. package/skills/backend-guidelines/SKILL.md +1 -0
  30. package/skills/frontend-guidelines/SKILL.md +1 -0
  31. package/skills/ios-guidelines/SKILL.md +1 -0
@@ -0,0 +1,192 @@
1
+ const fs = require('fs');
2
+ const path = require('path');
3
+
4
+ function readFileSafe(file) {
5
+ try {
6
+ return fs.readFileSync(file, 'utf-8');
7
+ } catch (error) {
8
+ if (process.env.DEBUG) {
9
+ console.debug(`[iOSArchitectureDetector] Failed to read file ${file}: ${error.message}`);
10
+ }
11
+ return '';
12
+ }
13
+ }
14
+
15
+ function detectFeatureFirstClean(files, patterns, projectRoot) {
16
+ const hasFeaturesFolders = files.some(f =>
17
+ /\/Features?\/\w+\/(domain|application|infrastructure|presentation)\//i.test(f)
18
+ );
19
+
20
+ const cleanArchFolders = ['domain', 'application', 'infrastructure', 'presentation'];
21
+ const foundCleanFolders = cleanArchFolders.filter(folder =>
22
+ files.some(f => f.toLowerCase().includes(`/${folder}/`))
23
+ );
24
+
25
+ const dddConcepts = files.filter(f =>
26
+ f.includes('/entities/') ||
27
+ f.includes('/value-objects/') ||
28
+ f.includes('/use-cases/') ||
29
+ f.includes('Entity.swift') ||
30
+ f.includes('VO.swift') ||
31
+ f.includes('UseCase.swift')
32
+ );
33
+
34
+ if (hasFeaturesFolders) patterns.featureFirstClean += 10;
35
+ if (foundCleanFolders.length >= 3) patterns.featureFirstClean += foundCleanFolders.length * 3;
36
+ if (dddConcepts.length > 0) patterns.featureFirstClean += dddConcepts.length * 2;
37
+
38
+ const featureNames = new Set();
39
+ files.forEach(f => {
40
+ const match = f.match(/\/Features?\/(\w+)\//i);
41
+ if (match) featureNames.add(match[1]);
42
+ });
43
+ if (featureNames.size >= 2) patterns.featureFirstClean += featureNames.size * 4;
44
+
45
+ files.forEach(file => {
46
+ const content = readFileSafe(file);
47
+ if (content.includes('struct ') && content.includes('VO')) patterns.featureFirstClean += 2;
48
+ if (file.includes('Entity.swift') && content.includes('func ')) patterns.featureFirstClean += 2;
49
+ if (file.toLowerCase().includes('/domain/') && content.includes('protocol ') && content.includes('Repository')) {
50
+ patterns.featureFirstClean += 3;
51
+ }
52
+ if (file.toLowerCase().includes('/application/') && content.includes('UseCase')) {
53
+ patterns.featureFirstClean += 2;
54
+ }
55
+ });
56
+ }
57
+
58
+ function detectTCA(files, patterns) {
59
+ const tcaIndicators = [
60
+ 'import ComposableArchitecture',
61
+ 'Store<',
62
+ 'struct.*State',
63
+ 'enum.*Action',
64
+ ': Reducer',
65
+ 'Effect<'
66
+ ];
67
+
68
+ files.forEach(file => {
69
+ const content = readFileSafe(file);
70
+ const matches = tcaIndicators.filter(indicator =>
71
+ new RegExp(indicator).test(content)
72
+ ).length;
73
+ if (matches >= 3) patterns.tca += matches;
74
+ });
75
+ }
76
+
77
+ function detectVIPER(files, patterns, projectRoot) {
78
+ const viperFiles = files.filter(f =>
79
+ /Presenter\.swift$|Interactor\.swift$|Router\.swift$|Entity\.swift$/i.test(f)
80
+ );
81
+ if (viperFiles.length >= 4) patterns.viper += viperFiles.length;
82
+
83
+ files.forEach(file => {
84
+ const content = readFileSafe(file);
85
+ const viperProtocols = [
86
+ 'ViewProtocol',
87
+ 'PresenterProtocol',
88
+ 'InteractorProtocol',
89
+ 'RouterProtocol'
90
+ ];
91
+ const matches = viperProtocols.filter(proto => content.includes(proto)).length;
92
+ if (matches >= 2) patterns.viper += matches * 2;
93
+ });
94
+
95
+ const viperFolders = ['View', 'Interactor', 'Presenter', 'Entity', 'Router'];
96
+ const hasViperStructure = viperFolders.filter(folder => {
97
+ const folderPath = path.join(projectRoot, folder);
98
+ return fs.existsSync(folderPath);
99
+ }).length;
100
+ if (hasViperStructure >= 3) patterns.viper += hasViperStructure * 3;
101
+ }
102
+
103
+ function detectCleanSwift(files, patterns) {
104
+ files.forEach(file => {
105
+ const content = readFileSafe(file);
106
+ const cleanSwiftIndicators = [
107
+ 'DisplayLogic',
108
+ 'BusinessLogic',
109
+ 'PresentationLogic',
110
+ 'Request\\s*{',
111
+ 'Response\\s*{',
112
+ 'ViewModel\\s*{'
113
+ ];
114
+ const matches = cleanSwiftIndicators.filter(indicator =>
115
+ new RegExp(indicator).test(content)
116
+ ).length;
117
+ if (matches >= 3) patterns.cleanSwift += matches * 2;
118
+ });
119
+ }
120
+
121
+ function detectMVP(files, patterns) {
122
+ const presenterFiles = files.filter(f => /Presenter\.swift$/i.test(f));
123
+ const interactorFiles = files.filter(f => /Interactor\.swift$/i.test(f));
124
+ const routerFiles = files.filter(f => /Router\.swift$/i.test(f));
125
+ if (presenterFiles.length >= 2 && interactorFiles.length === 0 && routerFiles.length === 0) {
126
+ patterns.mvp += presenterFiles.length * 3;
127
+ }
128
+ files.forEach(file => {
129
+ const content = readFileSafe(file);
130
+ const hasMVPProtocols =
131
+ content.includes('ViewProtocol') &&
132
+ content.includes('PresenterProtocol') &&
133
+ !content.includes('InteractorProtocol');
134
+ if (hasMVPProtocols) patterns.mvp += 3;
135
+ });
136
+ }
137
+
138
+ function detectMVVMC(files, patterns) {
139
+ const coordinatorFiles = files.filter(f => /Coordinator\.swift$/i.test(f));
140
+ if (coordinatorFiles.length >= 1) patterns.mvvmc += coordinatorFiles.length * 3;
141
+ files.forEach(file => {
142
+ const content = readFileSafe(file);
143
+ if (content.includes('protocol Coordinator') ||
144
+ content.includes(': Coordinator') ||
145
+ (/func\s+start\(\)/.test(content) && /func\s+navigate/.test(content))) {
146
+ patterns.mvvmc += 2;
147
+ }
148
+ });
149
+ }
150
+
151
+ function detectMVVM(files, patterns) {
152
+ const viewModelFiles = files.filter(f => /ViewModel\.swift$/i.test(f));
153
+ if (viewModelFiles.length >= 2) patterns.mvvm += viewModelFiles.length * 2;
154
+ files.forEach(file => {
155
+ const content = readFileSafe(file);
156
+ const mvvmIndicators = [
157
+ '@Published',
158
+ ': ObservableObject',
159
+ 'import Combine',
160
+ 'class.*ViewModel'
161
+ ];
162
+ const matches = mvvmIndicators.filter(indicator =>
163
+ new RegExp(indicator).test(content)
164
+ ).length;
165
+ if (matches >= 2) patterns.mvvm += matches;
166
+ });
167
+ }
168
+
169
+ function detectMVC(files, patterns) {
170
+ const viewControllerFiles = files.filter(f => /ViewController\.swift$/i.test(f));
171
+ if (viewControllerFiles.length >= 2) {
172
+ viewControllerFiles.forEach(file => {
173
+ const content = readFileSafe(file);
174
+ const lines = content.split('\n').length;
175
+ if (lines > 300) patterns.mvc += 3;
176
+ else if (lines > 150) patterns.mvc += 2;
177
+ else patterns.mvc += 1;
178
+ });
179
+ }
180
+ }
181
+
182
+ module.exports = {
183
+ readFileSafe,
184
+ detectFeatureFirstClean,
185
+ detectTCA,
186
+ detectVIPER,
187
+ detectCleanSwift,
188
+ detectMVP,
189
+ detectMVVMC,
190
+ detectMVVM,
191
+ detectMVC,
192
+ };