pumuki 6.3.189 → 6.3.190

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/VERSION CHANGED
@@ -1 +1 @@
1
- v6.3.189
1
+ v6.3.190
@@ -13,6 +13,7 @@ import {
13
13
  hasKotlinJUnit4Usage,
14
14
  hasKotlinLiveDataStateExposureUsage,
15
15
  hasKotlinLifecycleScopeUsage,
16
+ hasKotlinProductionMockUsage,
16
17
  hasKotlinSharedPreferencesUsage,
17
18
  hasKotlinWithContextUsage,
18
19
  hasKotlinManualCoroutineScopeInViewModelUsage,
@@ -315,6 +316,42 @@ class OrdersViewModelTest {
315
316
  assert.equal(hasKotlinJUnit4Usage(source), false);
316
317
  });
317
318
 
319
+ test('hasKotlinProductionMockUsage detecta mocks y spies en Kotlin Android production', () => {
320
+ const mockkSource = `
321
+ class OrdersRepositoryFactory {
322
+ fun create(): OrdersRepository = mockk(relaxed = true)
323
+ }
324
+ `;
325
+ const mockitoSource = `
326
+ class OrdersRepositoryFactory {
327
+ private val api = Mockito.mock(OrdersApi::class.java)
328
+ }
329
+ `;
330
+ const annotationSource = `
331
+ class OrdersRepositoryFactory {
332
+ @Spy
333
+ lateinit var repository: OrdersRepository
334
+ }
335
+ `;
336
+
337
+ assert.equal(hasKotlinProductionMockUsage(mockkSource), true);
338
+ assert.equal(hasKotlinProductionMockUsage(mockitoSource), true);
339
+ assert.equal(hasKotlinProductionMockUsage(annotationSource), true);
340
+ });
341
+
342
+ test('hasKotlinProductionMockUsage ignora imports, comentarios, strings y nombres parciales', () => {
343
+ const source = `
344
+ import io.mockk.mockk
345
+ import org.mockito.Mockito
346
+ // val api = mockk<OrdersApi>()
347
+ val sample = "Mockito.mock(OrdersApi::class.java)"
348
+ class OrdersRepositoryFactory {
349
+ fun create() = mockkitoFactory()
350
+ }
351
+ `;
352
+ assert.equal(hasKotlinProductionMockUsage(source), false);
353
+ });
354
+
318
355
  test('hasKotlinSupervisorScopeUsage detecta supervisorScope con parentesis y llaves', () => {
319
356
  const parenthesesSource = `
320
357
  class SyncOrdersUseCase {
@@ -282,6 +282,13 @@ export const hasKotlinJUnit4Usage = (source: string): boolean => {
282
282
  });
283
283
  };
284
284
 
285
+ export const hasKotlinProductionMockUsage = (source: string): boolean => {
286
+ return collectKotlinRegexLines(
287
+ source,
288
+ /(?:\b(?:mockk|spyk|mockkObject|mockkStatic|mockkConstructor|mockito|mockitoSession|mockitoRule)\s*(?:<[^>\n]+>\s*)?\(|\bMockito\s*\.\s*(?:mock|spy)\s*\(|@(?:Mock|Spy|MockK|RelaxedMockK)\b)/
289
+ ).length > 0;
290
+ };
291
+
285
292
  export const hasKotlinSupervisorScopeUsage = (source: string): boolean => {
286
293
  return collectKotlinRegexLines(source, /\bsupervisorScope\s*(?:<[^>\n]+>\s*)?(?:\(|\{)/).length > 0;
287
294
  };
@@ -658,6 +658,7 @@ const textDetectorRegistry: ReadonlyArray<TextDetectorRegistryEntry> = [
658
658
  { platform: 'android', pathCheck: isAndroidKotlinPath, excludePaths: [isKotlinTestPath], detect: TextAndroid.hasKotlinRunBlockingUsage, ruleId: 'heuristics.android.run-blocking.ast', code: 'HEURISTICS_ANDROID_RUN_BLOCKING_AST', message: 'AST heuristic detected runBlocking usage in production Kotlin code.' },
659
659
  { platform: 'android', pathCheck: isAndroidLocalPropertiesPath, excludePaths: [], detect: detectsTrackedFilePresence, ruleId: 'heuristics.android.security.local-properties-tracked.ast', code: 'HEURISTICS_ANDROID_SECURITY_LOCAL_PROPERTIES_TRACKED_AST', message: 'AST heuristic detected tracked Android local.properties file.' },
660
660
  { platform: 'android', pathCheck: isAndroidKotlinPath, excludePaths: [isKotlinTestPath], detect: TextAndroid.hasKotlinSharedPreferencesUsage, ruleId: 'heuristics.android.persistence.shared-preferences-usage.ast', code: 'HEURISTICS_ANDROID_PERSISTENCE_SHARED_PREFERENCES_USAGE_AST', message: 'AST heuristic detected SharedPreferences usage in Android production Kotlin code.' },
661
+ { platform: 'android', pathCheck: isAndroidKotlinPath, excludePaths: [isKotlinTestPath], detect: TextAndroid.hasKotlinProductionMockUsage, ruleId: 'heuristics.android.testing.production-mock-usage.ast', code: 'HEURISTICS_ANDROID_TESTING_PRODUCTION_MOCK_USAGE_AST', message: 'AST heuristic detected mock or spy usage in Android production Kotlin code.' },
661
662
  { platform: 'android', pathCheck: isAndroidKotlinTestPath, excludePaths: [], detect: TextAndroid.hasKotlinJUnit4Usage, ruleId: 'heuristics.android.testing.junit4-usage.ast', code: 'HEURISTICS_ANDROID_TESTING_JUNIT4_USAGE_AST', message: 'AST heuristic detected JUnit4 usage in Android Kotlin tests where JUnit5 is preferred.' },
662
663
  { platform: 'android', pathCheck: isAndroidPresentationPath, excludePaths: [isKotlinTestPath], detect: TextAndroid.hasKotlinLiveDataStateExposureUsage, ruleId: 'heuristics.android.flow.livedata-state-exposure.ast', code: 'HEURISTICS_ANDROID_FLOW_LIVEDATA_STATE_EXPOSURE_AST', message: 'AST heuristic detected LiveData state exposure in Android presentation code where StateFlow or SharedFlow should be preferred.' },
663
664
  { platform: 'android', pathCheck: isAndroidPresentationPath, excludePaths: [isKotlinTestPath], detect: TextAndroid.hasKotlinManualCoroutineScopeInViewModelUsage, ruleId: 'heuristics.android.coroutines.manual-scope-in-viewmodel.ast', code: 'HEURISTICS_ANDROID_COROUTINES_MANUAL_SCOPE_IN_VIEWMODEL_AST', message: 'AST heuristic detected manual CoroutineScope inside an Android ViewModel where viewModelScope should be preferred.' },
@@ -3,7 +3,7 @@ import test from 'node:test';
3
3
  import { androidRules } from './android';
4
4
 
5
5
  test('androidRules define reglas heurísticas locked para plataforma android', () => {
6
- assert.equal(androidRules.length, 19);
6
+ assert.equal(androidRules.length, 20);
7
7
 
8
8
  const ids = androidRules.map((rule) => rule.id);
9
9
  assert.deepEqual(ids, [
@@ -14,6 +14,7 @@ test('androidRules define reglas heurísticas locked para plataforma android', (
14
14
  'heuristics.android.security.local-properties-tracked.ast',
15
15
  'heuristics.android.persistence.shared-preferences-usage.ast',
16
16
  'heuristics.android.testing.junit4-usage.ast',
17
+ 'heuristics.android.testing.production-mock-usage.ast',
17
18
  'heuristics.android.coroutines.manual-scope-in-viewmodel.ast',
18
19
  'heuristics.android.coroutines.dispatchers-main-boundary-leak.ast',
19
20
  'heuristics.android.coroutines.hardcoded-background-dispatcher.ast',
@@ -67,6 +68,10 @@ test('androidRules define reglas heurísticas locked para plataforma android', (
67
68
  byId.get('heuristics.android.testing.junit4-usage.ast')?.then.code,
68
69
  'HEURISTICS_ANDROID_TESTING_JUNIT4_USAGE_AST'
69
70
  );
71
+ assert.equal(
72
+ byId.get('heuristics.android.testing.production-mock-usage.ast')?.then.code,
73
+ 'HEURISTICS_ANDROID_TESTING_PRODUCTION_MOCK_USAGE_AST'
74
+ );
70
75
  assert.equal(
71
76
  byId.get('heuristics.android.coroutines.manual-scope-in-viewmodel.ast')?.then.code,
72
77
  'HEURISTICS_ANDROID_COROUTINES_MANUAL_SCOPE_IN_VIEWMODEL_AST'
@@ -135,6 +135,26 @@ export const androidRules: RuleSet = [
135
135
  code: 'HEURISTICS_ANDROID_TESTING_JUNIT4_USAGE_AST',
136
136
  },
137
137
  },
138
+ {
139
+ id: 'heuristics.android.testing.production-mock-usage.ast',
140
+ description:
141
+ 'Detects mock or spy usage in Android production Kotlin code.',
142
+ severity: 'WARN',
143
+ platform: 'android',
144
+ locked: true,
145
+ when: {
146
+ kind: 'Heuristic',
147
+ where: {
148
+ ruleId: 'heuristics.android.testing.production-mock-usage.ast',
149
+ },
150
+ },
151
+ then: {
152
+ kind: 'Finding',
153
+ message:
154
+ 'AST heuristic detected mock or spy usage in Android production Kotlin code.',
155
+ code: 'HEURISTICS_ANDROID_TESTING_PRODUCTION_MOCK_USAGE_AST',
156
+ },
157
+ },
138
158
  {
139
159
  id: 'heuristics.android.coroutines.manual-scope-in-viewmodel.ast',
140
160
  description:
@@ -150,6 +150,9 @@ app/
150
150
  ✅ `skills.android.guideline.android.junit5-framework-de-testing-preferido-sobre-junit4` debe mapear a señal ejecutable de uso JUnit4 en tests Kotlin Android.
151
151
  ✅ Este baseline detecta imports/anotaciones JUnit4 (`org.junit.Test`, `org.junit.Assert`, `@RunWith`, reglas JUnit4) bajo `apps/android/**/test/**` y `apps/android/**/androidTest/**`.
152
152
  ✅ JUnit5/Jupiter queda preservado como caso limpio; migración completa de runner, Gradle y APIs de assertions queda fuera hasta tener detectores propios.
153
+ ✅ `skills.android.guideline.android.en-produccio-n-ni-un-mocks-ni-un-spies-todo-real-de-apis-y-persistenci` debe mapear a señal ejecutable de mocks/spies en Kotlin Android production.
154
+ ✅ Este baseline detecta usos explícitos de MockK/Mockito y anotaciones `@Mock`/`@Spy` fuera de `test` y `androidTest`; los dobles en tests siguen permitidos.
155
+ ✅ La regla no prohíbe clases fake de test doubles en suites de test ni analiza wiring Gradle todavía.
153
156
 
154
157
  ### Dependency Injection (Hilt):
155
158
  ✅ **Hilt** - DI framework (NO manual factories)
@@ -259,6 +259,10 @@ const registryByRuleId: Record<string, SkillsDetectorBinding> = {
259
259
  'android.testing.junit4-usage',
260
260
  ['heuristics.android.testing.junit4-usage.ast']
261
261
  ),
262
+ 'skills.android.guideline.android.en-produccio-n-ni-un-mocks-ni-un-spies-todo-real-de-apis-y-persistenci': heuristicDetector(
263
+ 'android.testing.production-mock-usage',
264
+ ['heuristics.android.testing.production-mock-usage.ast']
265
+ ),
262
266
  'skills.android.guideline.android.stateflow-estado-mutable-observable': heuristicDetector(
263
267
  'android.flow.state-exposure',
264
268
  ['heuristics.android.flow.livedata-state-exposure.ast']
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pumuki",
3
- "version": "6.3.189",
3
+ "version": "6.3.190",
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-12T21:22:02.797Z",
4
+ "generatedAt": "2026-05-12T21:28:07.507Z",
5
5
  "bundles": [
6
6
  {
7
7
  "name": "android-guidelines",