pumuki 6.3.206 → 6.3.207

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.
@@ -54,6 +54,7 @@ import {
54
54
  hasSwiftInsecureTransportUsage,
55
55
  hasSwiftJSONSerializationUsage,
56
56
  hasSwiftStringFormatUsage,
57
+ hasSwiftStrongDelegateReferenceUsage,
57
58
  hasSwiftTabItemUsage,
58
59
  hasSwiftTaskDetachedUsage,
59
60
  hasSwiftWaitForExpectationsUsage,
@@ -177,6 +178,37 @@ Task {
177
178
  assert.equal(hasSwiftTaskDetachedUsage(negative), false);
178
179
  });
179
180
 
181
+ test('hasSwiftStrongDelegateReferenceUsage detecta delegates fuertes y preserva weak delegates', () => {
182
+ const positive = `
183
+ final class CheckoutCoordinator {
184
+ var delegate: CheckoutCoordinatorDelegate?
185
+ let tableDataSource: OrdersTableDataSource
186
+ }
187
+ `;
188
+ const negative = `
189
+ final class CheckoutCoordinator {
190
+ weak var delegate: CheckoutCoordinatorDelegate?
191
+ private weak var dataSource: OrdersTableDataSource?
192
+ let text = "var delegate: CheckoutCoordinatorDelegate?"
193
+ // var delegate: CheckoutCoordinatorDelegate?
194
+ }
195
+ `;
196
+
197
+ assert.equal(hasSwiftStrongDelegateReferenceUsage(positive), true);
198
+ assert.equal(hasSwiftStrongDelegateReferenceUsage(negative), false);
199
+ });
200
+
201
+ test('hasSwiftStrongDelegateReferenceUsage no marca propiedades no delegate', () => {
202
+ const source = `
203
+ final class CheckoutCoordinator {
204
+ var repository: OrdersRepository
205
+ let presenter: CheckoutPresenter
206
+ }
207
+ `;
208
+
209
+ assert.equal(hasSwiftStrongDelegateReferenceUsage(source), false);
210
+ });
211
+
180
212
  test('detectores de logging iOS detectan logs ad-hoc y PII en produccion', () => {
181
213
  const adHoc = `
182
214
  print(user.id)
@@ -437,6 +437,19 @@ export const hasSwiftTaskDetachedUsage = (source: string): boolean => {
437
437
  });
438
438
  };
439
439
 
440
+ export const hasSwiftStrongDelegateReferenceUsage = (source: string): boolean => {
441
+ const delegatePropertyPattern =
442
+ /\b(?:var|let)\s+(?:[A-Za-z_][A-Za-z0-9_]*(?:Delegate|DataSource)|delegate|dataSource)\s*:\s*(?:any\s+)?[A-Za-z_][A-Za-z0-9_]*(?:Delegate|DataSource)\b/;
443
+
444
+ return source.split(/\r?\n/).some((line) => {
445
+ const sanitizedLine = stripSwiftLineForSemanticScan(line);
446
+ if (!delegatePropertyPattern.test(sanitizedLine)) {
447
+ return false;
448
+ }
449
+ return !/\bweak\s+var\b/.test(sanitizedLine);
450
+ });
451
+ };
452
+
440
453
  export const hasSwiftAdHocLoggingUsage = (source: string): boolean => {
441
454
  return collectSwiftRegexLines(
442
455
  source,
@@ -646,6 +646,7 @@ const textDetectorRegistry: ReadonlyArray<TextDetectorRegistryEntry> = [
646
646
  { platform: 'ios', pathCheck: isIOSSwiftPath, excludePaths: [isSwiftTestPath], detect: TextIOS.hasSwiftDispatchSemaphoreUsage, ruleId: 'heuristics.ios.dispatchsemaphore.ast', code: 'HEURISTICS_IOS_DISPATCHSEMAPHORE_AST', message: 'AST heuristic detected DispatchSemaphore usage.' },
647
647
  { platform: 'ios', pathCheck: isIOSSwiftPath, excludePaths: [isSwiftTestPath], detect: TextIOS.hasSwiftOperationQueueUsage, ruleId: 'heuristics.ios.operation-queue.ast', code: 'HEURISTICS_IOS_OPERATION_QUEUE_AST', message: 'AST heuristic detected OperationQueue usage.' },
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
+ { 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.' },
649
650
  { 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.' },
650
651
  { 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.' },
651
652
  { 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.' },
@@ -181,6 +181,25 @@ export const iosRules: RuleSet = [
181
181
  code: 'HEURISTICS_IOS_TASK_DETACHED_AST',
182
182
  },
183
183
  },
184
+ {
185
+ id: 'heuristics.ios.memory.strong-delegate.ast',
186
+ description: 'Detects strong delegate/dataSource references in iOS production code.',
187
+ severity: 'WARN',
188
+ platform: 'ios',
189
+ locked: true,
190
+ when: {
191
+ kind: 'Heuristic',
192
+ where: {
193
+ ruleId: 'heuristics.ios.memory.strong-delegate.ast',
194
+ },
195
+ },
196
+ then: {
197
+ kind: 'Finding',
198
+ message:
199
+ 'AST heuristic detected a strong delegate/dataSource reference; weak delegates remain the preferred baseline to avoid retain cycles.',
200
+ code: 'HEURISTICS_IOS_MEMORY_STRONG_DELEGATE_AST',
201
+ },
202
+ },
184
203
  {
185
204
  id: 'heuristics.ios.logging.adhoc-print.ast',
186
205
  description: 'Detects print/debugPrint/dump/NSLog/os_log usage in iOS production code.',
@@ -47,6 +47,14 @@ const registryByRuleId: Record<string, SkillsDetectorBinding> = {
47
47
  'skills.ios.no-task-detached': heuristicDetector('ios.task-detached', [
48
48
  'heuristics.ios.task-detached.ast',
49
49
  ]),
50
+ 'skills.ios.guideline.ios.delegation-pattern-weak-delegates-para-evitar-retain-cycles': heuristicDetector(
51
+ 'ios.memory.strong-delegate',
52
+ ['heuristics.ios.memory.strong-delegate.ast']
53
+ ),
54
+ 'skills.ios.guideline.ios.evitar-retain-cycles-especialmente-en-closures-delegates': heuristicDetector(
55
+ 'ios.memory.strong-delegate',
56
+ ['heuristics.ios.memory.strong-delegate.ast']
57
+ ),
50
58
  'skills.ios.guideline.ios.prohibido-print-y-logs-ad-hoc': heuristicDetector(
51
59
  'ios.logging.adhoc-print',
52
60
  ['heuristics.ios.logging.adhoc-print.ast']
@@ -423,6 +423,15 @@ const normalizeKnownRuleTarget = (
423
423
  ) {
424
424
  return 'skills.ios.guideline.ios.accessibility-labels-accessibilitylabel';
425
425
  }
426
+ if (
427
+ includes('weak delegates') ||
428
+ includes('delegation pattern') ||
429
+ includes('closures delegates') ||
430
+ includes('avoid retain cycles') ||
431
+ includes('evitar retain cycles')
432
+ ) {
433
+ return 'skills.ios.guideline.ios.delegation-pattern-weak-delegates-para-evitar-retain-cycles';
434
+ }
426
435
  if (
427
436
  includes('mixing legacy xctest style') ||
428
437
  includes('mixed xctest and swift testing') ||
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pumuki",
3
- "version": "6.3.206",
3
+ "version": "6.3.207",
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:03:23.736Z",
4
+ "generatedAt": "2026-05-13T12:26:53.436Z",
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": "41ef368c744a0b772fa408e83fe7edf4621fe2766ba3ea47d6753339690dbbd2",
5767
+ "hash": "672f428af5b852cb406bda732533581a045a0cc7e40a1f5c32b4ba57a5b248f7",
5768
5768
  "rules": [
5769
5769
  {
5770
5770
  "id": "skills.ios.guideline.ios.accessibility-identifiers-para-localizar-elementos",
@@ -6363,7 +6363,7 @@
6363
6363
  "sourcePath": "vendor/skills/ios-enterprise-rules/SKILL.md",
6364
6364
  "confidence": "MEDIUM",
6365
6365
  "locked": true,
6366
- "evaluationMode": "DECLARATIVE",
6366
+ "evaluationMode": "AUTO",
6367
6367
  "origin": "core"
6368
6368
  },
6369
6369
  {
@@ -6510,18 +6510,6 @@
6510
6510
  "evaluationMode": "DECLARATIVE",
6511
6511
  "origin": "core"
6512
6512
  },
6513
- {
6514
- "id": "skills.ios.guideline.ios.evitar-retain-cycles-especialmente-en-closures-delegates",
6515
- "description": "Evitar retain cycles - Especialmente en closures, delegates",
6516
- "severity": "ERROR",
6517
- "platform": "ios",
6518
- "sourceSkill": "ios-guidelines",
6519
- "sourcePath": "vendor/skills/ios-enterprise-rules/SKILL.md",
6520
- "confidence": "MEDIUM",
6521
- "locked": true,
6522
- "evaluationMode": "DECLARATIVE",
6523
- "origin": "core"
6524
- },
6525
6513
  {
6526
6514
  "id": "skills.ios.guideline.ios.expect-y-require-assertions-de-swift-testing",
6527
6515
  "description": "#expect y #require - Assertions de Swift Testing",