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
@@ -1,6 +1,13 @@
1
1
  const fs = require('fs');
2
2
  const path = require('path');
3
3
  const glob = require('glob');
4
+ const {
5
+ detectFeatureFirstClean,
6
+ detectComponentBased,
7
+ detectAtomicDesign,
8
+ detectStateManagement,
9
+ detectMVC,
10
+ } = require('../detectors/frontend-architecture-strategies');
4
11
 
5
12
  class FrontendArchitectureDetector {
6
13
  constructor(projectRoot) {
@@ -62,161 +69,24 @@ class FrontendArchitectureDetector {
62
69
  }
63
70
 
64
71
  detectFeatureFirstClean(files) {
65
- const hasFeaturesFolders = files.some(f =>
66
- /\/features?\/\w+\/(domain|application|infrastructure|presentation)\//.test(f)
67
- );
68
-
69
- const cleanArchFolders = ['domain', 'application', 'infrastructure', 'presentation'];
70
- const foundCleanFolders = cleanArchFolders.filter(folder => {
71
- return files.some(f => f.includes(`/${folder}/`));
72
- });
73
-
74
- const dddConcepts = files.filter(f =>
75
- f.includes('/entities/') ||
76
- f.includes('/value-objects/') ||
77
- f.includes('/use-cases/') ||
78
- f.includes('/repositories/') ||
79
- f.includes('Entity.ts') ||
80
- f.includes('UseCase.ts') ||
81
- f.includes('Repository.ts')
82
- );
83
-
84
- if (hasFeaturesFolders) {
85
- this.patterns.featureFirstClean += 10;
86
- }
87
-
88
- if (foundCleanFolders.length >= 3) {
89
- this.patterns.featureFirstClean += foundCleanFolders.length * 3;
90
- }
91
-
92
- if (dddConcepts.length > 0) {
93
- this.patterns.featureFirstClean += dddConcepts.length * 2;
94
- }
95
-
96
- const featureNames = new Set();
97
- files.forEach(f => {
98
- const match = f.match(/\/features?\/(\w+)\//);
99
- if (match) {
100
- featureNames.add(match[1]);
101
- }
102
- });
103
-
104
- if (featureNames.size >= 2) {
105
- this.patterns.featureFirstClean += featureNames.size * 4;
106
- }
107
-
108
- files.forEach(file => {
109
- const content = this.readFile(file);
110
-
111
- if (file.includes('/domain/') && content.includes('interface ') && content.includes('Repository')) {
112
- this.patterns.featureFirstClean += 3;
113
- }
114
-
115
- if (file.includes('/application/') || file.includes('/use-cases/')) {
116
- if (content.includes('UseCase') || content.includes('useCase')) {
117
- this.patterns.featureFirstClean += 2;
118
- }
119
- }
120
-
121
- if (file.includes('/hooks/') && file.includes('use') && file.endsWith('.ts')) {
122
- this.patterns.featureFirstClean += 1;
123
- }
124
- });
125
-
72
+ detectFeatureFirstClean(this.projectRoot, files, this.patterns);
126
73
  console.log(`[Architecture Detection] Feature-First + Clean + DDD score: ${this.patterns.featureFirstClean}`);
127
74
  }
128
75
 
129
76
  detectComponentBased(files) {
130
- const hasComponentsFolder = files.some(f => f.includes('/components/'));
131
-
132
- if (hasComponentsFolder) {
133
- this.patterns.componentBased += 10;
134
- }
135
-
136
- const componentFiles = files.filter(f =>
137
- f.includes('/components/') && (f.endsWith('.tsx') || f.endsWith('.jsx'))
138
- );
139
-
140
- if (componentFiles.length > 0) {
141
- this.patterns.componentBased += componentFiles.length;
142
- }
143
-
144
- files.forEach(file => {
145
- if (!file.includes('/components/')) return;
146
-
147
- const content = this.readFile(file);
148
- const componentImports = content.match(/from\s+['"]\.\.\/components\//g) || [];
149
-
150
- if (componentImports.length > 0) {
151
- this.patterns.componentBased += componentImports.length;
152
- }
153
- });
77
+ detectComponentBased(this.projectRoot, files, this.patterns);
154
78
  }
155
79
 
156
80
  detectAtomicDesign(files) {
157
- const atomicFolders = ['atoms', 'molecules', 'organisms', 'templates', 'pages'];
158
-
159
- const foundFolders = atomicFolders.filter(folder => {
160
- return files.some(f => f.includes(`/${folder}/`));
161
- });
162
-
163
- if (foundFolders.length >= 3) {
164
- this.patterns.atomicDesign += foundFolders.length * 5;
165
- }
166
-
167
- if (files.some(f => f.includes('/atoms/')) &&
168
- files.some(f => f.includes('/molecules/')) &&
169
- files.some(f => f.includes('/organisms/'))) {
170
- this.patterns.atomicDesign += 10;
171
- }
81
+ detectAtomicDesign(this.projectRoot, files, this.patterns);
172
82
  }
173
83
 
174
84
  detectStateManagement(files) {
175
- files.forEach(file => {
176
- const content = this.readFile(file);
177
-
178
- if (content.includes('zustand') || content.includes('create(') && file.includes('store')) {
179
- this.patterns.stateManagement += 5;
180
- }
181
-
182
- if (content.includes('redux') || content.includes('@reduxjs/toolkit') ||
183
- file.includes('slice') || file.includes('reducer')) {
184
- this.patterns.stateManagement += 5;
185
- }
186
-
187
- if (content.includes('createContext') || content.includes('Context.Provider')) {
188
- this.patterns.stateManagement += 2;
189
- }
190
-
191
- if (file.includes('/stores/') || file.includes('/state/')) {
192
- this.patterns.stateManagement += 3;
193
- }
194
- });
85
+ detectStateManagement(this.projectRoot, files, this.patterns);
195
86
  }
196
87
 
197
88
  detectMVC(files) {
198
- files.forEach(file => {
199
- if (!file.includes('component') && !file.endsWith('.tsx') && !file.endsWith('.jsx')) return;
200
-
201
- const content = this.readFile(file);
202
-
203
- if (content.includes('fetch(') || content.includes('axios.') || content.includes('.get(')) {
204
- const hasHook = files.some(f =>
205
- f.includes('use') && f.endsWith('.ts') && !f.includes('component')
206
- );
207
- const hasService = files.some(f =>
208
- f.includes('service') || f.includes('api')
209
- );
210
-
211
- if (!hasHook && !hasService) {
212
- this.patterns.mvc += 3;
213
- }
214
- }
215
-
216
- if (content.match(/const\s+\w+\s*=\s*\(.*\)\s*=>\s*{[\s\S]{0,500}if\s*\(.*\)\s*{[\s\S]{0,500}if\s*\(.*\)\s*{[\s\S]{0,500}if\s*\(.*\)\s*{/)) {
217
- this.patterns.mvc += 2;
218
- }
219
- });
89
+ detectMVC(this.projectRoot, files, this.patterns);
220
90
  }
221
91
 
222
92
  readFile(relativePath) {
@@ -0,0 +1,126 @@
1
+ const fs = require('fs');
2
+ const path = require('path');
3
+
4
+ function readFileSafe(projectRoot, relativeOrAbsolutePath) {
5
+ try {
6
+ const filePath = path.isAbsolute(relativeOrAbsolutePath)
7
+ ? relativeOrAbsolutePath
8
+ : path.join(projectRoot, relativeOrAbsolutePath);
9
+ return fs.readFileSync(filePath, 'utf-8');
10
+ } catch (error) {
11
+ if (process.env.DEBUG) {
12
+ console.debug(`[FrontendArchitectureDetector] Failed to read file ${relativeOrAbsolutePath}: ${error.message}`);
13
+ }
14
+ return '';
15
+ }
16
+ }
17
+
18
+ function detectFeatureFirstClean(projectRoot, files, patterns) {
19
+ const hasFeaturesFolders = files.some(f =>
20
+ /\/features?\/\w+\/(domain|application|infrastructure|presentation)\//i.test(f)
21
+ );
22
+
23
+ const cleanArchFolders = ['domain', 'application', 'infrastructure', 'presentation'];
24
+ const foundCleanFolders = cleanArchFolders.filter(folder => {
25
+ return files.some(f => f.toLowerCase().includes(`/${folder}/`));
26
+ });
27
+
28
+ const dddConcepts = files.filter(f =>
29
+ f.includes('/entities/') ||
30
+ f.includes('/value-objects/') ||
31
+ f.includes('/use-cases/') ||
32
+ f.includes('/repositories/') ||
33
+ f.includes('Entity.ts') ||
34
+ f.includes('UseCase.ts') ||
35
+ f.includes('Repository.ts')
36
+ );
37
+
38
+ if (hasFeaturesFolders) {
39
+ patterns.featureFirstClean += 10;
40
+ }
41
+
42
+ if (foundCleanFolders.length >= 3) {
43
+ patterns.featureFirstClean += foundCleanFolders.length * 3;
44
+ }
45
+
46
+ if (dddConcepts.length > 0) {
47
+ patterns.featureFirstClean += dddConcepts.length * 2;
48
+ }
49
+
50
+ const featureNames = new Set();
51
+ files.forEach(f => {
52
+ const match = f.match(/\/features?\/(\w+)\//i);
53
+ if (match) {
54
+ featureNames.add(match[1]);
55
+ }
56
+ });
57
+
58
+ if (featureNames.size >= 2) {
59
+ patterns.featureFirstClean += featureNames.size * 4;
60
+ }
61
+
62
+ files.forEach(file => {
63
+ const content = readFileSafe(projectRoot, file);
64
+
65
+ if (file.toLowerCase().includes('/domain/') && content.includes('interface ') && content.includes('Repository')) {
66
+ patterns.featureFirstClean += 3;
67
+ }
68
+
69
+ if (file.toLowerCase().includes('/application/') || file.toLowerCase().includes('/use-cases/')) {
70
+ if (content.includes('UseCase') || content.includes('useCase')) {
71
+ patterns.featureFirstClean += 2;
72
+ }
73
+ }
74
+
75
+ if (/\/features?\/\w+\/presentation\//i.test(file) && /Page|Screen|View|Component/.test(content)) {
76
+ patterns.featureFirstClean += 1;
77
+ }
78
+ });
79
+ }
80
+
81
+ function detectComponentBased(_projectRoot, files, patterns) {
82
+ const componentPatterns = [
83
+ /\/components?\//i,
84
+ /\/ui\//i,
85
+ /\/widgets?\//i
86
+ ];
87
+
88
+ files.forEach(file => {
89
+ if (componentPatterns.some(p => p.test(file))) {
90
+ patterns.componentBased += 2;
91
+ }
92
+ });
93
+ }
94
+
95
+ function detectAtomicDesign(_projectRoot, files, patterns) {
96
+ const atomicFolders = ['atoms', 'molecules', 'organisms', 'templates', 'pages'];
97
+ const foundAtomic = atomicFolders.filter(folder =>
98
+ files.some(f => f.toLowerCase().includes(`/${folder}/`))
99
+ );
100
+
101
+ if (foundAtomic.length >= 3) {
102
+ patterns.atomicDesign += foundAtomic.length * 2;
103
+ }
104
+ }
105
+
106
+ function detectStateManagement(_projectRoot, files, patterns) {
107
+ const stateKeywords = ['redux', 'zustand', 'mobx', 'recoil', 'xstate', 'jotai', 'effector'];
108
+ if (files.some(f => stateKeywords.some(k => f.toLowerCase().includes(k)))) {
109
+ patterns.stateManagement += 5;
110
+ }
111
+ }
112
+
113
+ function detectMVC(_projectRoot, files, patterns) {
114
+ const controllerFiles = files.filter(f => /Controller\.(ts|tsx|jsx)$/i.test(f));
115
+ if (controllerFiles.length > 0) {
116
+ patterns.mvc += controllerFiles.length;
117
+ }
118
+ }
119
+
120
+ module.exports = {
121
+ detectFeatureFirstClean,
122
+ detectComponentBased,
123
+ detectAtomicDesign,
124
+ detectStateManagement,
125
+ detectMVC,
126
+ };