pumuki 6.3.208 → 6.3.209

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.
@@ -44,6 +44,7 @@ import {
44
44
  hasSwiftOnTapGestureUsage,
45
45
  hasSwiftOperationQueueUsage,
46
46
  hasSwiftContainsUserFilterUsage,
47
+ hasSwiftCustomSingletonUsage,
47
48
  hasSwiftPassedValueStateWrapperUsage,
48
49
  hasSwiftPhysicalTextAlignmentUsage,
49
50
  hasSwiftPreconcurrencyUsage,
@@ -260,6 +261,28 @@ final class CartViewModel {
260
261
  assert.equal(hasSwiftStrongSelfEscapingClosureUsage(source), false);
261
262
  });
262
263
 
264
+ test('hasSwiftCustomSingletonUsage detecta singletons propios y excluye usos de singletons del sistema', () => {
265
+ const source = `
266
+ final class SessionStore {
267
+ static let shared = SessionStore()
268
+ }
269
+
270
+ final class MutableStore {
271
+ public static var shared: MutableStore = MutableStore()
272
+ }
273
+ `;
274
+ const ignored = `
275
+ final class APIClient {
276
+ let session = URLSession.shared
277
+ let text = "static let shared = SessionStore()"
278
+ // static let shared = SessionStore()
279
+ }
280
+ `;
281
+
282
+ assert.equal(hasSwiftCustomSingletonUsage(source), true);
283
+ assert.equal(hasSwiftCustomSingletonUsage(ignored), false);
284
+ });
285
+
263
286
  test('detectores de logging iOS detectan logs ad-hoc y PII en produccion', () => {
264
287
  const adHoc = `
265
288
  print(user.id)
@@ -519,6 +519,15 @@ export const hasSwiftStrongSelfEscapingClosureUsage = (source: string): boolean
519
519
  return false;
520
520
  };
521
521
 
522
+ export const hasSwiftCustomSingletonUsage = (source: string): boolean => {
523
+ const singletonDeclarationPattern =
524
+ /^\s*(?:(?:private|fileprivate|internal|public|open)\s+)?static\s+(?:let|var)\s+shared\b(?:\s*:\s*[A-Za-z_][A-Za-z0-9_.<>]*)?\s*=/;
525
+ return source.split(/\r?\n/).some((line) => {
526
+ const sanitizedLine = stripSwiftLineForSemanticScan(line);
527
+ return singletonDeclarationPattern.test(sanitizedLine);
528
+ });
529
+ };
530
+
522
531
  export const hasSwiftAdHocLoggingUsage = (source: string): boolean => {
523
532
  return collectSwiftRegexLines(
524
533
  source,
@@ -648,6 +648,7 @@ const textDetectorRegistry: ReadonlyArray<TextDetectorRegistryEntry> = [
648
648
  { platform: 'ios', pathCheck: isIOSSwiftPath, excludePaths: [isSwiftTestPath], detect: TextIOS.hasSwiftTaskDetachedUsage, ruleId: 'heuristics.ios.task-detached.ast', code: 'HEURISTICS_IOS_TASK_DETACHED_AST', message: 'AST heuristic detected Task.detached usage.' },
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
+ { 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.' },
651
652
  { 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.' },
652
653
  { 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.' },
653
654
  { 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.' },
@@ -219,6 +219,25 @@ export const iosRules: RuleSet = [
219
219
  code: 'HEURISTICS_IOS_MEMORY_STRONG_SELF_ESCAPING_CLOSURE_AST',
220
220
  },
221
221
  },
222
+ {
223
+ id: 'heuristics.ios.architecture.custom-singleton.ast',
224
+ description: 'Detects custom static shared singletons in iOS production code.',
225
+ severity: 'WARN',
226
+ platform: 'ios',
227
+ locked: true,
228
+ when: {
229
+ kind: 'Heuristic',
230
+ where: {
231
+ ruleId: 'heuristics.ios.architecture.custom-singleton.ast',
232
+ },
233
+ },
234
+ then: {
235
+ kind: 'Finding',
236
+ message:
237
+ 'AST heuristic detected a custom static shared singleton in iOS production code; dependency injection remains the preferred baseline for app-owned services.',
238
+ code: 'HEURISTICS_IOS_ARCHITECTURE_CUSTOM_SINGLETON_AST',
239
+ },
240
+ },
222
241
  {
223
242
  id: 'heuristics.ios.logging.adhoc-print.ast',
224
243
  description: 'Detects print/debugPrint/dump/NSLog/os_log usage in iOS production code.',
@@ -58,6 +58,14 @@ const registryByRuleId: Record<string, SkillsDetectorBinding> = {
58
58
  'heuristics.ios.memory.strong-self-escaping-closure.ast',
59
59
  ]
60
60
  ),
61
+ 'skills.ios.guideline.ios.no-singleton-usar-inyeccio-n-de-dependencias-no-compartir-instancias-g': heuristicDetector(
62
+ 'ios.architecture.custom-singleton',
63
+ ['heuristics.ios.architecture.custom-singleton.ast']
64
+ ),
65
+ 'skills.ios.guideline.ios.no-singletons-excepto-sistema-urlsession-shared-esta-ok': heuristicDetector(
66
+ 'ios.architecture.custom-singleton',
67
+ ['heuristics.ios.architecture.custom-singleton.ast']
68
+ ),
61
69
  'skills.ios.guideline.ios.prohibido-print-y-logs-ad-hoc': heuristicDetector(
62
70
  'ios.logging.adhoc-print',
63
71
  ['heuristics.ios.logging.adhoc-print.ast']
@@ -435,6 +435,15 @@ const normalizeKnownRuleTarget = (
435
435
  ) {
436
436
  return 'skills.ios.guideline.ios.evitar-retain-cycles-especialmente-en-closures-delegates';
437
437
  }
438
+ if (
439
+ includes('no singleton') ||
440
+ includes('no singletons') ||
441
+ includes('static shared') ||
442
+ includes('static let shared') ||
443
+ includes('static var shared')
444
+ ) {
445
+ return 'skills.ios.guideline.ios.no-singleton-usar-inyeccio-n-de-dependencias-no-compartir-instancias-g';
446
+ }
438
447
  if (
439
448
  includes('mixing legacy xctest style') ||
440
449
  includes('mixed xctest and swift testing') ||
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pumuki",
3
- "version": "6.3.208",
3
+ "version": "6.3.209",
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:37:42.811Z",
4
+ "generatedAt": "2026-05-13T12:45:06.608Z",
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": "32c74edc740622834bf48fa060ebc04f8d5ee0c826e9a6dd48a068212dfc2552",
5767
+ "hash": "5c20c168bf6f54010cfac75cce1311a03ed2345ac20eef7b2a4458ad8efd3fc4",
5768
5768
  "rules": [
5769
5769
  {
5770
5770
  "id": "skills.ios.guideline.ios.accessibility-identifiers-para-localizar-elementos",
@@ -6727,18 +6727,6 @@
6727
6727
  "evaluationMode": "DECLARATIVE",
6728
6728
  "origin": "core"
6729
6729
  },
6730
- {
6731
- "id": "skills.ios.guideline.ios.implementaciones-inyectadas-en-initializer-no-singleton",
6732
- "description": "Implementaciones inyectadas - En initializer, no Singleton",
6733
- "severity": "WARN",
6734
- "platform": "ios",
6735
- "sourceSkill": "ios-guidelines",
6736
- "sourcePath": "vendor/skills/ios-enterprise-rules/SKILL.md",
6737
- "confidence": "MEDIUM",
6738
- "locked": true,
6739
- "evaluationMode": "DECLARATIVE",
6740
- "origin": "core"
6741
- },
6742
6730
  {
6743
6731
  "id": "skills.ios.guideline.ios.implicitly-unwrapped-solo-para-iboutlets-y-casos-muy-especi-ficos",
6744
6732
  "description": "Implicitly unwrapped (!) - Solo para IBOutlets y casos muy específicos",
@@ -7180,19 +7168,7 @@
7180
7168
  "sourcePath": "vendor/skills/ios-enterprise-rules/SKILL.md",
7181
7169
  "confidence": "MEDIUM",
7182
7170
  "locked": true,
7183
- "evaluationMode": "DECLARATIVE",
7184
- "origin": "core"
7185
- },
7186
- {
7187
- "id": "skills.ios.guideline.ios.no-singletons-excepto-sistema-urlsession-shared-esta-ok",
7188
- "description": "No singletons - Excepto sistema (URLSession.shared está OK)",
7189
- "severity": "WARN",
7190
- "platform": "ios",
7191
- "sourceSkill": "ios-guidelines",
7192
- "sourcePath": "vendor/skills/ios-enterprise-rules/SKILL.md",
7193
- "confidence": "MEDIUM",
7194
- "locked": true,
7195
- "evaluationMode": "DECLARATIVE",
7171
+ "evaluationMode": "AUTO",
7196
7172
  "origin": "core"
7197
7173
  },
7198
7174
  {