pumuki 6.3.209 → 6.3.210
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/facts/detectors/text/ios.test.ts +34 -0
- package/core/facts/detectors/text/ios.ts +16 -0
- package/core/facts/extractHeuristicFacts.ts +1 -0
- package/core/rules/presets/heuristics/ios.ts +19 -0
- package/integrations/config/skillsDetectorRegistry.ts +8 -0
- package/integrations/config/skillsMarkdownRules.ts +9 -0
- package/package.json +1 -1
- package/skills.lock.json +5 -17
|
@@ -29,6 +29,7 @@ import {
|
|
|
29
29
|
hasSwiftLegacyExpectationDescriptionUsage,
|
|
30
30
|
hasSwiftLegacySwiftUiObservableWrapperUsage,
|
|
31
31
|
hasSwiftMainThreadBlockingSleepUsage,
|
|
32
|
+
hasSwiftMassiveViewControllerResponsibilityUsage,
|
|
32
33
|
hasSwiftMixedTestingFrameworksUsage,
|
|
33
34
|
hasSwiftLegacyXCTestImportUsage,
|
|
34
35
|
hasSwiftModernizableXCTestSuiteUsage,
|
|
@@ -283,6 +284,39 @@ final class APIClient {
|
|
|
283
284
|
assert.equal(hasSwiftCustomSingletonUsage(ignored), false);
|
|
284
285
|
});
|
|
285
286
|
|
|
287
|
+
test('hasSwiftMassiveViewControllerResponsibilityUsage detecta ViewControllers con acceso directo a infraestructura', () => {
|
|
288
|
+
const source = `
|
|
289
|
+
final class CheckoutViewController: UIViewController {
|
|
290
|
+
override func viewDidLoad() {
|
|
291
|
+
super.viewDidLoad()
|
|
292
|
+
URLSession.shared.dataTask(with: URL(string: "https://example.com")!)
|
|
293
|
+
UserDefaults.standard.set(true, forKey: "seen")
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
`;
|
|
297
|
+
const ignored = `
|
|
298
|
+
final class CheckoutViewController: UIViewController {
|
|
299
|
+
private let viewModel: CheckoutViewModel
|
|
300
|
+
|
|
301
|
+
init(viewModel: CheckoutViewModel) {
|
|
302
|
+
self.viewModel = viewModel
|
|
303
|
+
super.init(nibName: nil, bundle: nil)
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
override func viewDidLoad() {
|
|
307
|
+
super.viewDidLoad()
|
|
308
|
+
viewModel.load()
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
let text = "URLSession.shared.dataTask"
|
|
313
|
+
// UserDefaults.standard.set(true, forKey: "seen")
|
|
314
|
+
`;
|
|
315
|
+
|
|
316
|
+
assert.equal(hasSwiftMassiveViewControllerResponsibilityUsage(source), true);
|
|
317
|
+
assert.equal(hasSwiftMassiveViewControllerResponsibilityUsage(ignored), false);
|
|
318
|
+
});
|
|
319
|
+
|
|
286
320
|
test('detectores de logging iOS detectan logs ad-hoc y PII en produccion', () => {
|
|
287
321
|
const adHoc = `
|
|
288
322
|
print(user.id)
|
|
@@ -528,6 +528,22 @@ export const hasSwiftCustomSingletonUsage = (source: string): boolean => {
|
|
|
528
528
|
});
|
|
529
529
|
};
|
|
530
530
|
|
|
531
|
+
export const hasSwiftMassiveViewControllerResponsibilityUsage = (source: string): boolean => {
|
|
532
|
+
const sanitized = sanitizeSwiftSourceForMultilineRegex(source);
|
|
533
|
+
const viewControllerPattern =
|
|
534
|
+
/\bclass\s+[A-Za-z_][A-Za-z0-9_]*\s*:\s*(?:[A-Za-z_][A-Za-z0-9_]*\s*,\s*)*UIViewController\b[\s\S]{0,8000}?\n\}/g;
|
|
535
|
+
const infrastructurePattern =
|
|
536
|
+
/\b(?:URLSession\s*\.\s*shared|JSONSerialization|UserDefaults\s*\.\s*standard|NSManagedObjectContext|NSPersistentContainer|NSFetchRequest|FileManager\s*\.\s*default)\b/;
|
|
537
|
+
|
|
538
|
+
for (const match of sanitized.matchAll(viewControllerPattern)) {
|
|
539
|
+
const body = match[0] ?? '';
|
|
540
|
+
if (infrastructurePattern.test(body)) {
|
|
541
|
+
return true;
|
|
542
|
+
}
|
|
543
|
+
}
|
|
544
|
+
return false;
|
|
545
|
+
};
|
|
546
|
+
|
|
531
547
|
export const hasSwiftAdHocLoggingUsage = (source: string): boolean => {
|
|
532
548
|
return collectSwiftRegexLines(
|
|
533
549
|
source,
|
|
@@ -649,6 +649,7 @@ const textDetectorRegistry: ReadonlyArray<TextDetectorRegistryEntry> = [
|
|
|
649
649
|
{ platform: 'ios', pathCheck: isIOSSwiftPath, excludePaths: [isSwiftTestPath], detect: TextIOS.hasSwiftStrongDelegateReferenceUsage, ruleId: 'heuristics.ios.memory.strong-delegate.ast', code: 'HEURISTICS_IOS_MEMORY_STRONG_DELEGATE_AST', message: 'AST heuristic detected a strong delegate/dataSource reference; weak delegates remain the preferred baseline to avoid retain cycles.' },
|
|
650
650
|
{ platform: 'ios', pathCheck: isIOSSwiftPath, excludePaths: [isSwiftTestPath], detect: TextIOS.hasSwiftStrongSelfEscapingClosureUsage, ruleId: 'heuristics.ios.memory.strong-self-escaping-closure.ast', code: 'HEURISTICS_IOS_MEMORY_STRONG_SELF_ESCAPING_CLOSURE_AST', message: 'AST heuristic detected strong self capture in an escaping iOS closure; weak or unowned captures remain the preferred baseline when ownership is not explicit.' },
|
|
651
651
|
{ platform: 'ios', pathCheck: isIOSSwiftPath, excludePaths: [isSwiftTestPath], detect: TextIOS.hasSwiftCustomSingletonUsage, ruleId: 'heuristics.ios.architecture.custom-singleton.ast', code: 'HEURISTICS_IOS_ARCHITECTURE_CUSTOM_SINGLETON_AST', message: 'AST heuristic detected a custom static shared singleton in iOS production code; dependency injection remains the preferred baseline for app-owned services.' },
|
|
652
|
+
{ platform: 'ios', pathCheck: isIOSSwiftPath, excludePaths: [isSwiftTestPath], detect: TextIOS.hasSwiftMassiveViewControllerResponsibilityUsage, ruleId: 'heuristics.ios.architecture.massive-view-controller.ast', code: 'HEURISTICS_IOS_ARCHITECTURE_MASSIVE_VIEW_CONTROLLER_AST', message: 'AST heuristic detected a UIViewController with direct infrastructure/data access; move data access behind application/domain boundaries.' },
|
|
652
653
|
{ platform: 'ios', pathCheck: isIOSSwiftPath, excludePaths: [isSwiftTestPath], detect: TextIOS.hasSwiftAdHocLoggingUsage, ruleId: 'heuristics.ios.logging.adhoc-print.ast', code: 'HEURISTICS_IOS_LOGGING_ADHOC_PRINT_AST', message: 'AST heuristic detected print/debugPrint/dump/NSLog/os_log usage in iOS production code.' },
|
|
653
654
|
{ platform: 'ios', pathCheck: isIOSSwiftPath, excludePaths: [isSwiftTestPath], detect: TextIOS.hasSwiftSensitiveLoggingUsage, ruleId: 'heuristics.ios.logging.sensitive-data.ast', code: 'HEURISTICS_IOS_LOGGING_SENSITIVE_DATA_AST', message: 'AST heuristic detected sensitive data in an iOS logging call.' },
|
|
654
655
|
{ platform: 'ios', pathCheck: isIOSSwiftPath, excludePaths: [isSwiftTestPath], detect: TextIOS.hasSwiftAlamofireUsage, ruleId: 'heuristics.ios.networking.alamofire.ast', code: 'HEURISTICS_IOS_NETWORKING_ALAMOFIRE_AST', message: 'AST heuristic detected Alamofire usage in iOS production code; URLSession remains the preferred baseline for new code.' },
|
|
@@ -238,6 +238,25 @@ export const iosRules: RuleSet = [
|
|
|
238
238
|
code: 'HEURISTICS_IOS_ARCHITECTURE_CUSTOM_SINGLETON_AST',
|
|
239
239
|
},
|
|
240
240
|
},
|
|
241
|
+
{
|
|
242
|
+
id: 'heuristics.ios.architecture.massive-view-controller.ast',
|
|
243
|
+
description: 'Detects UIViewController classes with direct infrastructure/data access.',
|
|
244
|
+
severity: 'WARN',
|
|
245
|
+
platform: 'ios',
|
|
246
|
+
locked: true,
|
|
247
|
+
when: {
|
|
248
|
+
kind: 'Heuristic',
|
|
249
|
+
where: {
|
|
250
|
+
ruleId: 'heuristics.ios.architecture.massive-view-controller.ast',
|
|
251
|
+
},
|
|
252
|
+
},
|
|
253
|
+
then: {
|
|
254
|
+
kind: 'Finding',
|
|
255
|
+
message:
|
|
256
|
+
'AST heuristic detected a UIViewController with direct infrastructure/data access; move data access behind application/domain boundaries.',
|
|
257
|
+
code: 'HEURISTICS_IOS_ARCHITECTURE_MASSIVE_VIEW_CONTROLLER_AST',
|
|
258
|
+
},
|
|
259
|
+
},
|
|
241
260
|
{
|
|
242
261
|
id: 'heuristics.ios.logging.adhoc-print.ast',
|
|
243
262
|
description: 'Detects print/debugPrint/dump/NSLog/os_log usage in iOS production code.',
|
|
@@ -66,6 +66,14 @@ const registryByRuleId: Record<string, SkillsDetectorBinding> = {
|
|
|
66
66
|
'ios.architecture.custom-singleton',
|
|
67
67
|
['heuristics.ios.architecture.custom-singleton.ast']
|
|
68
68
|
),
|
|
69
|
+
'skills.ios.guideline.ios.massive-view-controllers-viewcontrollers-que-mezclan-presentacio-n-nav': heuristicDetector(
|
|
70
|
+
'ios.architecture.massive-view-controller',
|
|
71
|
+
['heuristics.ios.architecture.massive-view-controller.ast']
|
|
72
|
+
),
|
|
73
|
+
'skills.ios.guideline.ios.mvc-evitar-massive-view-controller-no-escalable': heuristicDetector(
|
|
74
|
+
'ios.architecture.massive-view-controller',
|
|
75
|
+
['heuristics.ios.architecture.massive-view-controller.ast']
|
|
76
|
+
),
|
|
69
77
|
'skills.ios.guideline.ios.prohibido-print-y-logs-ad-hoc': heuristicDetector(
|
|
70
78
|
'ios.logging.adhoc-print',
|
|
71
79
|
['heuristics.ios.logging.adhoc-print.ast']
|
|
@@ -444,6 +444,15 @@ const normalizeKnownRuleTarget = (
|
|
|
444
444
|
) {
|
|
445
445
|
return 'skills.ios.guideline.ios.no-singleton-usar-inyeccio-n-de-dependencias-no-compartir-instancias-g';
|
|
446
446
|
}
|
|
447
|
+
if (
|
|
448
|
+
includes('massive view controller') ||
|
|
449
|
+
includes('massive view controllers') ||
|
|
450
|
+
includes('viewcontrollers que mezclan') ||
|
|
451
|
+
includes('viewcontroller que mezclan') ||
|
|
452
|
+
(includes('mvc') && includes('evitar'))
|
|
453
|
+
) {
|
|
454
|
+
return 'skills.ios.guideline.ios.massive-view-controllers-viewcontrollers-que-mezclan-presentacio-n-nav';
|
|
455
|
+
}
|
|
447
456
|
if (
|
|
448
457
|
includes('mixing legacy xctest style') ||
|
|
449
458
|
includes('mixed xctest and swift testing') ||
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pumuki",
|
|
3
|
-
"version": "6.3.
|
|
3
|
+
"version": "6.3.210",
|
|
4
4
|
"description": "Enterprise-grade AST Intelligence System with multi-platform support (iOS, Android, Backend, Frontend) and Feature-First + DDD + Clean Architecture enforcement. Includes dynamic violations API for intelligent querying.",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"bin": {
|
package/skills.lock.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": "1.0",
|
|
3
3
|
"compilerVersion": "1.0.0",
|
|
4
|
-
"generatedAt": "2026-05-13T12:
|
|
4
|
+
"generatedAt": "2026-05-13T12:51:35.774Z",
|
|
5
5
|
"bundles": [
|
|
6
6
|
{
|
|
7
7
|
"name": "android-guidelines",
|
|
@@ -5764,7 +5764,7 @@
|
|
|
5764
5764
|
"name": "ios-guidelines",
|
|
5765
5765
|
"version": "1.0.0",
|
|
5766
5766
|
"source": "file:vendor/skills/ios-enterprise-rules/SKILL.md",
|
|
5767
|
-
"hash": "
|
|
5767
|
+
"hash": "ad016db5ad38077a418d0bf7c3780b5ae8ff2bfc724691038a65292acc500787",
|
|
5768
5768
|
"rules": [
|
|
5769
5769
|
{
|
|
5770
5770
|
"id": "skills.ios.guideline.ios.accessibility-identifiers-para-localizar-elementos",
|
|
@@ -6957,14 +6957,14 @@
|
|
|
6957
6957
|
},
|
|
6958
6958
|
{
|
|
6959
6959
|
"id": "skills.ios.guideline.ios.massive-view-controllers-viewcontrollers-que-mezclan-presentacio-n-nav",
|
|
6960
|
-
"description": "
|
|
6960
|
+
"description": "MVC (evitar) - Massive View Controller, no escalable",
|
|
6961
6961
|
"severity": "ERROR",
|
|
6962
6962
|
"platform": "ios",
|
|
6963
6963
|
"sourceSkill": "ios-guidelines",
|
|
6964
6964
|
"sourcePath": "vendor/skills/ios-enterprise-rules/SKILL.md",
|
|
6965
|
-
"confidence": "
|
|
6965
|
+
"confidence": "MEDIUM",
|
|
6966
6966
|
"locked": true,
|
|
6967
|
-
"evaluationMode": "
|
|
6967
|
+
"evaluationMode": "AUTO",
|
|
6968
6968
|
"origin": "core"
|
|
6969
6969
|
},
|
|
6970
6970
|
{
|
|
@@ -6991,18 +6991,6 @@
|
|
|
6991
6991
|
"evaluationMode": "DECLARATIVE",
|
|
6992
6992
|
"origin": "core"
|
|
6993
6993
|
},
|
|
6994
|
-
{
|
|
6995
|
-
"id": "skills.ios.guideline.ios.mvc-evitar-massive-view-controller-no-escalable",
|
|
6996
|
-
"description": "MVC (evitar) - Massive View Controller, no escalable",
|
|
6997
|
-
"severity": "ERROR",
|
|
6998
|
-
"platform": "ios",
|
|
6999
|
-
"sourceSkill": "ios-guidelines",
|
|
7000
|
-
"sourcePath": "vendor/skills/ios-enterprise-rules/SKILL.md",
|
|
7001
|
-
"confidence": "MEDIUM",
|
|
7002
|
-
"locked": true,
|
|
7003
|
-
"evaluationMode": "DECLARATIVE",
|
|
7004
|
-
"origin": "core"
|
|
7005
|
-
},
|
|
7006
6994
|
{
|
|
7007
6995
|
"id": "skills.ios.guideline.ios.mvvm-c-coordinator-para-navegacio-n",
|
|
7008
6996
|
"description": "MVVM-C - + Coordinator para navegación",
|