pumuki 6.3.269 → 6.3.271

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 (35) hide show
  1. package/CHANGELOG.md +4 -0
  2. package/VERSION +1 -1
  3. package/core/facts/detectors/text/android.test.ts +538 -0
  4. package/core/facts/detectors/text/android.ts +436 -0
  5. package/core/facts/detectors/text/ios.test.ts +328 -1
  6. package/core/facts/detectors/text/ios.ts +241 -0
  7. package/core/facts/detectors/typescript/index.test.ts +393 -0
  8. package/core/facts/detectors/typescript/index.ts +316 -0
  9. package/core/facts/extractHeuristicFacts.ts +70 -1
  10. package/core/rules/presets/heuristics/android.test.ts +91 -1
  11. package/core/rules/presets/heuristics/android.ts +360 -0
  12. package/core/rules/presets/heuristics/ios.test.ts +54 -1
  13. package/core/rules/presets/heuristics/ios.ts +243 -2
  14. package/core/rules/presets/heuristics/typescript.test.ts +50 -2
  15. package/core/rules/presets/heuristics/typescript.ts +162 -0
  16. package/docs/operations/RELEASE_NOTES.md +4 -0
  17. package/integrations/config/skillsDetectorRegistry.ts +501 -0
  18. package/integrations/config/skillsRuleClassification.ts +127 -3
  19. package/integrations/context/contextGate.ts +192 -0
  20. package/integrations/git/runPlatformGate.ts +4 -1
  21. package/integrations/lifecycle/preWriteAutomation.ts +1 -0
  22. package/integrations/lifecycle/preWriteLease.ts +41 -4
  23. package/package.json +2 -1
  24. package/scripts/classify-skills-rules.ts +2 -2
  25. package/scripts/framework-menu-consumer-actions-lib.ts +9 -9
  26. package/scripts/framework-menu-consumer-runtime-actions.ts +53 -117
  27. package/scripts/framework-menu-consumer-runtime-audit.ts +66 -0
  28. package/scripts/framework-menu-consumer-runtime-menu.ts +4 -4
  29. package/scripts/framework-menu-gate-lib.ts +86 -1
  30. package/scripts/framework-menu-layout-data.ts +3 -3
  31. package/scripts/framework-menu-legacy-audit-render-sections.ts +6 -0
  32. package/scripts/framework-menu.ts +10 -6
  33. package/scripts/package-install-smoke-consumer-npm-lib.ts +10 -4
  34. package/scripts/package-install-smoke-lifecycle-lib.ts +19 -0
  35. package/scripts/package-manifest-lib.ts +1 -0
@@ -25,6 +25,23 @@ const registryByRuleId: Record<string, SkillsDetectorBinding> = {
25
25
  'heuristics.ios.force-try.ast',
26
26
  ]),
27
27
  'skills.ios.no-anyview': heuristicDetector('ios.anyview', ['heuristics.ios.anyview.ast']),
28
+ 'skills.ios.guideline.ios.any-type-erasure-usar-generics-con-protocolos-de-frontera': heuristicDetector(
29
+ 'ios.type-erasure.any',
30
+ ['heuristics.ios.type-erasure.any.ast']
31
+ ),
32
+ 'skills.ios.guideline.ios.generics-reutilizar-co-digo-type-safe': heuristicDetector(
33
+ 'ios.generics-over-any-type-erasure',
34
+ ['heuristics.ios.type-erasure.any.ast']
35
+ ),
36
+ 'skills.ios.guideline.ios.associated-types-generics-en-protocols': heuristicDetector(
37
+ 'ios.associated-types-generics-over-any-type-erasure',
38
+ ['heuristics.ios.type-erasure.any.ast']
39
+ ),
40
+ 'skills.ios.guideline.ios.opaque-types-some-view-some-publisher-cuando-sea-apropiado':
41
+ heuristicDetector('ios.opaque-types-over-type-erasure', [
42
+ 'heuristics.ios.anyview.ast',
43
+ 'heuristics.ios.type-erasure.any.ast',
44
+ ]),
28
45
  'skills.ios.no-force-cast': heuristicDetector('ios.force-cast', [
29
46
  'heuristics.ios.force-cast.ast',
30
47
  ]),
@@ -32,9 +49,22 @@ const registryByRuleId: Record<string, SkillsDetectorBinding> = {
32
49
  'ios.callback-style',
33
50
  ['heuristics.ios.callback-style.ast']
34
51
  ),
52
+ 'skills.ios.guideline.ios.cancellables-almacenar-en-set-anycancellable': heuristicDetector(
53
+ 'ios.combine.sink-without-store',
54
+ ['heuristics.ios.combine.sink-without-store.ast']
55
+ ),
35
56
  'skills.ios.no-dispatchqueue': heuristicDetector('ios.dispatchqueue', [
36
57
  'heuristics.ios.dispatchqueue.ast',
37
58
  ]),
59
+ 'skills.ios.guideline.ios.mainactor-para-co-digo-que-debe-ejecutarse-en-el-hilo-principal':
60
+ heuristicDetector('ios.concurrency.mainactor-dispatchqueue', [
61
+ 'heuristics.ios.dispatchqueue.ast',
62
+ ]),
63
+ 'skills.ios.guideline.ios.actor-para-estado-compartido-thread-safe':
64
+ heuristicDetector('ios.concurrency.shared-state-actor-boundary', [
65
+ 'heuristics.ios.dispatchqueue.ast',
66
+ 'heuristics.ios.dispatchsemaphore.ast',
67
+ ]),
38
68
  'skills.ios.no-dispatchgroup': heuristicDetector('ios.dispatchgroup', [
39
69
  'heuristics.ios.dispatchgroup.ast',
40
70
  ]),
@@ -68,6 +98,22 @@ const registryByRuleId: Record<string, SkillsDetectorBinding> = {
68
98
  'heuristics.ios.memory.strong-self-escaping-closure.ast',
69
99
  ]
70
100
  ),
101
+ 'skills.ios.guideline.ios.unowned-self-solo-si-self-siempre-existe-mientras-closure-existe': heuristicDetector(
102
+ 'ios.memory.unowned-self-capture',
103
+ ['heuristics.ios.memory.unowned-self-capture.ast']
104
+ ),
105
+ 'skills.ios.guideline.ios.guard-clauses-evitar-pyramid-of-doom-early-returns': heuristicDetector(
106
+ 'ios.maintainability.nested-if-pyramid',
107
+ ['heuristics.ios.maintainability.nested-if-pyramid.ast']
108
+ ),
109
+ 'skills.ios.guideline.ios.guard-let-para-early-return-unwrap-queda-en-scope': heuristicDetector(
110
+ 'ios.maintainability.nested-if-pyramid',
111
+ ['heuristics.ios.maintainability.nested-if-pyramid.ast']
112
+ ),
113
+ 'skills.ios.guideline.ios.no-poner-comentarios-en-el-co-digo-nombres-autodescriptivos': heuristicDetector(
114
+ 'ios.maintainability.comment-trivia',
115
+ ['heuristics.ios.maintainability.comment-trivia.ast']
116
+ ),
71
117
  'skills.ios.guideline.ios.no-singleton-usar-inyeccio-n-de-dependencias-no-compartir-instancias-g': heuristicDetector(
72
118
  'ios.architecture.custom-singleton',
73
119
  ['heuristics.ios.architecture.custom-singleton.ast']
@@ -84,6 +130,11 @@ const registryByRuleId: Record<string, SkillsDetectorBinding> = {
84
130
  'ios.architecture.massive-view-controller',
85
131
  ['heuristics.ios.architecture.massive-view-controller.ast']
86
132
  ),
133
+ 'skills.ios.guideline.ios.swiftui-primero-uikit-solo-cuando-sea-estrictamente-necesario':
134
+ heuristicDetector('ios.ui.swiftui-first-uikit-contained', [
135
+ 'heuristics.ios.architecture.massive-view-controller.ast',
136
+ 'heuristics.ios.interface-builder.storyboard-xib.ast',
137
+ ]),
87
138
  'skills.ios.guideline.ios.implicitly-unwrapped-solo-para-iboutlets-y-casos-muy-especi-ficos': heuristicDetector(
88
139
  'ios.safety.non-iboutlet-iuo',
89
140
  ['heuristics.ios.safety.non-iboutlet-iuo.ast']
@@ -132,6 +183,38 @@ const registryByRuleId: Record<string, SkillsDetectorBinding> = {
132
183
  'ios.json.jsonserialization',
133
184
  ['heuristics.ios.json.jsonserialization.ast']
134
185
  ),
186
+ 'skills.ios.guideline.ios.codable-para-serializacio-n-json-plist': heuristicDetector(
187
+ 'ios.json.jsonserialization',
188
+ ['heuristics.ios.json.jsonserialization.ast']
189
+ ),
190
+ 'skills.ios.guideline.ios.alamofire-prohibido-usar-urlsession-nativo': heuristicDetector(
191
+ 'ios.networking.alamofire',
192
+ ['heuristics.ios.networking.alamofire.ast']
193
+ ),
194
+ 'skills.ios.guideline.ios.cocoapods-prohibido': heuristicDetector(
195
+ 'ios.dependencies.cocoapods',
196
+ ['heuristics.ios.dependencies.cocoapods.ast']
197
+ ),
198
+ 'skills.ios.guideline.ios.carthage-prohibido': heuristicDetector(
199
+ 'ios.dependencies.carthage',
200
+ ['heuristics.ios.dependencies.carthage.ast']
201
+ ),
202
+ 'skills.ios.guideline.ios.cero-libreri-as-de-terceros-siempre-existe-solucio-n-nativa':
203
+ heuristicDetector('ios.dependencies.third-party-native-baseline', [
204
+ 'heuristics.ios.networking.alamofire.ast',
205
+ 'heuristics.ios.dependencies.cocoapods.ast',
206
+ 'heuristics.ios.dependencies.carthage.ast',
207
+ 'heuristics.ios.architecture.swinject.ast',
208
+ ]),
209
+ 'skills.ios.guideline.ios.libreri-as-de-terceros-usar-apis-nativas': heuristicDetector(
210
+ 'ios.dependencies.third-party-native-baseline',
211
+ [
212
+ 'heuristics.ios.networking.alamofire.ast',
213
+ 'heuristics.ios.dependencies.cocoapods.ast',
214
+ 'heuristics.ios.dependencies.carthage.ast',
215
+ 'heuristics.ios.architecture.swinject.ast',
216
+ ]
217
+ ),
135
218
  'skills.ios.guideline.ios.keychain-passwords-tokens-no-userdefaults': heuristicDetector(
136
219
  'ios.security.userdefaults-sensitive-data',
137
220
  ['heuristics.ios.security.userdefaults-sensitive-data.ast']
@@ -148,6 +231,18 @@ const registryByRuleId: Record<string, SkillsDetectorBinding> = {
148
231
  'ios.security.insecure-transport',
149
232
  ['heuristics.ios.security.insecure-transport.ast']
150
233
  ),
234
+ 'skills.ios.guideline.ios.localizable-strings-deprecado-usar-string-catalogs':
235
+ heuristicDetector('ios.localization.localizable-strings', [
236
+ 'heuristics.ios.localization.localizable-strings.ast',
237
+ ]),
238
+ 'skills.ios.guideline.ios.string-catalogs-xcstrings': heuristicDetector(
239
+ 'ios.localization.localizable-strings',
240
+ ['heuristics.ios.localization.localizable-strings.ast']
241
+ ),
242
+ 'skills.ios.guideline.ios.string-catalogs-xcstrings-sistema-moderno-de-localizacio-n-xcode-15':
243
+ heuristicDetector('ios.localization.localizable-strings', [
244
+ 'heuristics.ios.localization.localizable-strings.ast',
245
+ ]),
151
246
  'skills.ios.guideline.ios.cero-strings-hardcodeadas-en-ui': heuristicDetector(
152
247
  'ios.localization.hardcoded-ui-string',
153
248
  ['heuristics.ios.localization.hardcoded-ui-string.ast']
@@ -156,6 +251,14 @@ const registryByRuleId: Record<string, SkillsDetectorBinding> = {
156
251
  'ios.localization.hardcoded-ui-string',
157
252
  ['heuristics.ios.localization.hardcoded-ui-string.ast']
158
253
  ),
254
+ 'skills.ios.guideline.ios.automatic-plural-handling-en-string-catalogs':
255
+ heuristicDetector('ios.localization.localizable-strings', [
256
+ 'heuristics.ios.localization.localizable-strings.ast',
257
+ ]),
258
+ 'skills.ios.guideline.ios.pluralizacio-n-con-tablas-de-strings': heuristicDetector(
259
+ 'ios.localization.localizable-strings',
260
+ ['heuristics.ios.localization.localizable-strings.ast']
261
+ ),
159
262
  'skills.ios.guideline.ios.assets-en-asset-catalogs-con-soporte-para-todos-los-taman-os': heuristicDetector(
160
263
  'ios.assets.loose-resource',
161
264
  ['heuristics.ios.assets.loose-resource.ast']
@@ -176,13 +279,103 @@ const registryByRuleId: Record<string, SkillsDetectorBinding> = {
176
279
  'ios.performance.blocking-sleep',
177
280
  ['heuristics.ios.performance.blocking-sleep.ast']
178
281
  ),
282
+ 'skills.ios.guideline.ios.structured-concurrency-task-taskgroup-actor-asyncsequence-asyncstream':
283
+ heuristicDetector('ios.concurrency.structured-baseline', [
284
+ 'heuristics.ios.callback-style.ast',
285
+ 'heuristics.ios.dispatchqueue.ast',
286
+ 'heuristics.ios.dispatchgroup.ast',
287
+ 'heuristics.ios.dispatchsemaphore.ast',
288
+ 'heuristics.ios.operation-queue.ast',
289
+ 'heuristics.ios.task-detached.ast',
290
+ ]),
291
+ 'skills.ios.guideline.ios.async-await-para-operaciones-asi-ncronas': heuristicDetector(
292
+ 'ios.concurrency.async-await-baseline',
293
+ [
294
+ 'heuristics.ios.callback-style.ast',
295
+ 'heuristics.ios.dispatchqueue.ast',
296
+ 'heuristics.ios.dispatchgroup.ast',
297
+ 'heuristics.ios.dispatchsemaphore.ast',
298
+ 'heuristics.ios.operation-queue.ast',
299
+ 'heuristics.ios.task-detached.ast',
300
+ ]
301
+ ),
302
+ 'skills.ios.guideline.ios.taskgroup-para-operaciones-paralelas': heuristicDetector(
303
+ 'ios.concurrency.taskgroup-preferred',
304
+ ['heuristics.ios.dispatchgroup.ast']
305
+ ),
306
+ 'skills.ios.guideline.ios.urlsession-con-async-await-nativo-obligatorio':
307
+ heuristicDetector('ios.networking.urlsession-native-baseline', [
308
+ 'heuristics.ios.networking.alamofire.ast',
309
+ 'heuristics.ios.callback-style.ast',
310
+ ]),
311
+ 'skills.ios.guideline.ios.os-logger-para-logging-estructurado': heuristicDetector(
312
+ 'ios.logging.structured-os-logger',
313
+ ['heuristics.ios.logging.adhoc-print.ast']
314
+ ),
179
315
  'skills.ios.guideline.ios.accessibility-labels-accessibilitylabel': heuristicDetector(
180
316
  'ios.accessibility.icon-only-control-label',
181
317
  ['heuristics.ios.accessibility.icon-only-control-label.ast']
182
318
  ),
319
+ 'skills.ios.guideline.ios.accessibility-identifiers-para-localizar-elementos':
320
+ heuristicDetector('ios.accessibility.missing-accessibility-identifier', [
321
+ 'heuristics.ios.accessibility.missing-accessibility-identifier.ast',
322
+ ]),
323
+ 'skills.ios.guideline.ios.image-optimization-resize-compress-cache': heuristicDetector(
324
+ 'ios.swiftui.image-data-decoding',
325
+ ['heuristics.ios.swiftui.image-data-decoding.ast']
326
+ ),
327
+ 'skills.ios.guideline.ios.programmatic-ui-no-storyboards-xibs-mejor-control-de-versiones':
328
+ heuristicDetector('ios.interface-builder.storyboard-xib', [
329
+ 'heuristics.ios.interface-builder.storyboard-xib.ast',
330
+ ]),
331
+ 'skills.ios.guideline.ios.storyboards-grandes-merge-conflicts-lentitud':
332
+ heuristicDetector('ios.interface-builder.storyboard-xib', [
333
+ 'heuristics.ios.interface-builder.storyboard-xib.ast',
334
+ ]),
335
+ 'skills.ios.guideline.ios.uiviewcontroller-delgados-lo-gica-en-viewmodels':
336
+ heuristicDetector('ios.architecture.massive-view-controller', [
337
+ 'heuristics.ios.architecture.massive-view-controller.ast',
338
+ ]),
339
+ 'skills.ios.guideline.ios.bindable-para-bindings-con-observable':
340
+ heuristicDetector('ios.swiftui.missing-bindable-observable-binding', [
341
+ 'heuristics.ios.swiftui.missing-bindable-observable-binding.ast',
342
+ ]),
343
+ 'skills.ios.guideline.ios.bindable-para-exponer-bindings-de-un-observable-inyectado':
344
+ heuristicDetector('ios.swiftui.missing-bindable-observable-binding', [
345
+ 'heuristics.ios.swiftui.missing-bindable-observable-binding.ast',
346
+ ]),
347
+ 'skills.ios.guideline.ios.environment-en-swiftui-para-di-moderna': heuristicDetector(
348
+ 'ios.swiftui.environment-di-no-swinject',
349
+ ['heuristics.ios.architecture.swinject.ast']
350
+ ),
351
+ 'skills.ios.guideline.ios.environment-para-inyeccio-n-de-dependencias-y-valores-del-sistema':
352
+ heuristicDetector('ios.swiftui.environment-system-values-no-swinject', [
353
+ 'heuristics.ios.architecture.swinject.ast',
354
+ ]),
183
355
  'skills.ios.no-unchecked-sendable': heuristicDetector('ios.unchecked-sendable', [
184
356
  'heuristics.ios.unchecked-sendable.ast',
185
357
  ]),
358
+ 'skills.ios.guideline.ios.sendable-conformance-para-tipos-thread-safe-que-cruzan-boundaries':
359
+ heuristicDetector('ios.concurrency.sendable-unsafe-escape', [
360
+ 'heuristics.ios.unchecked-sendable.ast',
361
+ 'heuristics.ios.preconcurrency.ast',
362
+ 'heuristics.ios.nonisolated-unsafe.ast',
363
+ 'heuristics.ios.assume-isolated.ast',
364
+ ]),
365
+ 'skills.ios.guideline.ios.sendable-para-tipos-que-cruzan-boundaries-de-concurrencia':
366
+ heuristicDetector('ios.concurrency.sendable-boundary-unsafe-escape', [
367
+ 'heuristics.ios.unchecked-sendable.ast',
368
+ 'heuristics.ios.preconcurrency.ast',
369
+ 'heuristics.ios.nonisolated-unsafe.ast',
370
+ 'heuristics.ios.assume-isolated.ast',
371
+ ]),
372
+ 'skills.ios.guideline.ios.identificar-el-boundary-de-aislamiento-mainactor-actor-nonisolated':
373
+ heuristicDetector('ios.concurrency.isolation-boundary-unsafe-escape', [
374
+ 'heuristics.ios.unchecked-sendable.ast',
375
+ 'heuristics.ios.preconcurrency.ast',
376
+ 'heuristics.ios.nonisolated-unsafe.ast',
377
+ 'heuristics.ios.assume-isolated.ast',
378
+ ]),
186
379
  'skills.ios.no-preconcurrency': heuristicDetector('ios.preconcurrency', [
187
380
  'heuristics.ios.preconcurrency.ast',
188
381
  ]),
@@ -195,8 +388,46 @@ const registryByRuleId: Record<string, SkillsDetectorBinding> = {
195
388
  'skills.ios.no-observable-object': heuristicDetector('ios.observable-object', [
196
389
  'heuristics.ios.observable-object.ast',
197
390
  ]),
391
+ 'skills.ios.guideline.ios.observable-state-para-estado-owned-compartido-por-el-view':
392
+ heuristicDetector('ios.observable-object', ['heuristics.ios.observable-object.ast']),
198
393
  'skills.ios.guideline.ios-swiftui-expert.use-observable-for-shared-state-with-mainactor-if-not-using-default-ac':
199
394
  heuristicDetector('ios.observable-object', ['heuristics.ios.observable-object.ast']),
395
+ 'skills.ios.guideline.ios.macros-observable-preview-custom-macros':
396
+ heuristicDetector('ios.swiftui.macros', [
397
+ 'heuristics.ios.observable-object.ast',
398
+ 'heuristics.ios.swiftui.legacy-preview-provider.ast',
399
+ ]),
400
+ 'skills.ios.guideline.ios-swiftui-expert.references-state-management-md-property-wrappers-and-data-flow-prefer-':
401
+ heuristicDetector('ios.swiftui.state-management', [
402
+ 'heuristics.ios.observable-object.ast',
403
+ 'heuristics.ios.legacy-swiftui-observable-wrapper.ast',
404
+ 'heuristics.ios.swiftui.non-private-state-ownership.ast',
405
+ 'heuristics.ios.passed-value-state-wrapper.ast',
406
+ ]),
407
+ 'skills.ios.guideline.ios.property-wrappers-state-binding-observable-custom-wrappers':
408
+ heuristicDetector('ios.swiftui.property-wrappers', [
409
+ 'heuristics.ios.observable-object.ast',
410
+ 'heuristics.ios.legacy-swiftui-observable-wrapper.ast',
411
+ 'heuristics.ios.swiftui.non-private-state-ownership.ast',
412
+ 'heuristics.ios.passed-value-state-wrapper.ast',
413
+ 'heuristics.ios.swiftui.missing-bindable-observable-binding.ast',
414
+ ]),
415
+ 'skills.ios.guideline.ios.protocols-para-testability-mock-con-clases-que-conforman-protocol':
416
+ heuristicDetector('ios.testing.test-double-protocol-conformance', [
417
+ 'heuristics.ios.testing.test-double-without-protocol.ast',
418
+ ]),
419
+ 'skills.ios.guideline.ios.spies-mocks-verificar-comportamiento-real': heuristicDetector(
420
+ 'ios.testing.production-test-double',
421
+ ['heuristics.ios.testing.production-test-double.ast']
422
+ ),
423
+ 'skills.ios.guideline.ios.color-contrast-wcag-aa-mi-nimo': heuristicDetector(
424
+ 'ios.accessibility.low-contrast-static-color-pair',
425
+ ['heuristics.ios.accessibility.low-contrast-static-color-pair.ast']
426
+ ),
427
+ 'skills.ios.guideline.ios.contraste-wcag-2-1-aa-mi-nimo': heuristicDetector(
428
+ 'ios.accessibility.low-contrast-static-color-pair',
429
+ ['heuristics.ios.accessibility.low-contrast-static-color-pair.ast']
430
+ ),
200
431
  'skills.ios.no-legacy-swiftui-observable-wrapper': heuristicDetector(
201
432
  'ios.legacy-swiftui-observable-wrapper',
202
433
  ['heuristics.ios.legacy-swiftui-observable-wrapper.ast']
@@ -205,16 +436,62 @@ const registryByRuleId: Record<string, SkillsDetectorBinding> = {
205
436
  'ios.swiftui.non-private-state-ownership',
206
437
  ['heuristics.ios.swiftui.non-private-state-ownership.ast']
207
438
  ),
439
+ 'skills.ios.guideline.ios.state-para-local-estado-privado-del-view': heuristicDetector(
440
+ 'ios.swiftui.state-local-private',
441
+ [
442
+ 'heuristics.ios.swiftui.non-private-state-ownership.ast',
443
+ 'heuristics.ios.passed-value-state-wrapper.ast',
444
+ ]
445
+ ),
446
+ 'skills.ios.guideline.ios.state-solo-para-estado-local-y-privado': heuristicDetector(
447
+ 'ios.swiftui.state-local-private',
448
+ [
449
+ 'heuristics.ios.swiftui.non-private-state-ownership.ast',
450
+ 'heuristics.ios.passed-value-state-wrapper.ast',
451
+ ]
452
+ ),
208
453
  'skills.ios.no-passed-value-state-wrapper': heuristicDetector('ios.passed-value-state-wrapper', [
209
454
  'heuristics.ios.passed-value-state-wrapper.ast',
210
455
  ]),
456
+ 'skills.ios.guideline.ios.stateobject-viewmodel-ownership': heuristicDetector(
457
+ 'ios.passed-value-state-wrapper',
458
+ ['heuristics.ios.passed-value-state-wrapper.ast']
459
+ ),
460
+ 'skills.ios.guideline.ios.binding-para-compartir-pasar-estado-editable-a-child-views':
461
+ heuristicDetector('ios.swiftui.binding-passed-state-wrapper', [
462
+ 'heuristics.ios.passed-value-state-wrapper.ast',
463
+ ]),
211
464
  'skills.ios.no-navigation-view': heuristicDetector('ios.navigation-view', [
212
465
  'heuristics.ios.navigation-view.ast',
213
466
  ]),
467
+ 'skills.ios.guideline.ios-swiftui-expert.use-modern-apis-no-deprecated-modifiers-or-patterns-see-references-mod':
468
+ heuristicDetector('ios.swiftui.modern-api-replacements', [
469
+ 'heuristics.ios.navigation-view.ast',
470
+ 'heuristics.ios.foreground-color.ast',
471
+ 'heuristics.ios.corner-radius.ast',
472
+ 'heuristics.ios.tab-item.ast',
473
+ 'heuristics.ios.on-tap-gesture.ast',
474
+ 'heuristics.ios.scrollview-shows-indicators.ast',
475
+ 'heuristics.ios.string-format.ast',
476
+ 'heuristics.ios.sheet-is-presented.ast',
477
+ 'heuristics.ios.legacy-onchange.ast',
478
+ ]),
214
479
  'skills.ios.guideline.ios-swiftui-expert.use-navigationdestination-for-for-type-safe-navigation':
215
480
  heuristicDetector('ios.swiftui.untyped-navigation-link-destination', [
216
481
  'heuristics.ios.swiftui.untyped-navigation-link-destination.ast',
217
482
  ]),
483
+ 'skills.ios.guideline.ios.coordinator-para-navegacio-n-no-acoplamiento-entre-views':
484
+ heuristicDetector('ios.navigation.no-view-coupled-destination', [
485
+ 'heuristics.ios.swiftui.untyped-navigation-link-destination.ast',
486
+ ]),
487
+ 'skills.ios.guideline.ios.coordinator-pattern-para-navegacio-n-compleja':
488
+ heuristicDetector('ios.navigation.coordinator-pattern', [
489
+ 'heuristics.ios.swiftui.untyped-navigation-link-destination.ast',
490
+ ]),
491
+ 'skills.ios.guideline.ios.mvvm-c-coordinator-para-navegacio-n':
492
+ heuristicDetector('ios.navigation.mvvm-c-coordinator', [
493
+ 'heuristics.ios.swiftui.untyped-navigation-link-destination.ast',
494
+ ]),
218
495
  'skills.ios.no-foreground-color': heuristicDetector('ios.foreground-color', [
219
496
  'heuristics.ios.foreground-color.ast',
220
497
  ]),
@@ -241,6 +518,16 @@ const registryByRuleId: Record<string, SkillsDetectorBinding> = {
241
518
  heuristicDetector('ios.swiftui.foreach-self-identity', [
242
519
  'heuristics.ios.swiftui.foreach-self-identity.ast',
243
520
  ]),
521
+ 'skills.ios.guideline.ios-swiftui-expert.use-scrollviewreader-for-programmatic-scrolling-with-stable-ids':
522
+ heuristicDetector('ios.swiftui.scrollviewreader-stable-ids', [
523
+ 'heuristics.ios.foreach-indices.ast',
524
+ 'heuristics.ios.swiftui.foreach-self-identity.ast',
525
+ ]),
526
+ 'skills.ios.guideline.ios.scrollviewreader-scroll-programa-tico':
527
+ heuristicDetector('ios.swiftui.scrollviewreader-programmatic-scroll-stable-ids', [
528
+ 'heuristics.ios.foreach-indices.ast',
529
+ 'heuristics.ios.swiftui.foreach-self-identity.ast',
530
+ ]),
244
531
  'skills.ios.guideline.ios-swiftui-expert.use-self-printchanges-to-debug-unexpected-view-updates':
245
532
  heuristicDetector('ios.swiftui.self-print-changes', [
246
533
  'heuristics.ios.swiftui.self-print-changes.ast',
@@ -270,10 +557,19 @@ const registryByRuleId: Record<string, SkillsDetectorBinding> = {
270
557
  heuristicDetector('ios.swiftui.closure-based-viewbuilder-content', [
271
558
  'heuristics.ios.swiftui.closure-based-viewbuilder-content.ast',
272
559
  ]),
560
+ 'skills.ios.guideline.ios-swiftui-expert.use-viewbuilder-functions-only-for-small-simple-sections':
561
+ heuristicDetector('ios.swiftui.viewbuilder-composition-scope', [
562
+ 'heuristics.ios.swiftui.closure-based-viewbuilder-content.ast',
563
+ ]),
273
564
  'skills.ios.guideline.ios-swiftui-expert.pass-only-needed-values-to-views-avoid-large-config-or-context-objects':
274
565
  heuristicDetector('ios.swiftui.large-config-context-prop', [
275
566
  'heuristics.ios.swiftui.large-config-context-prop.ast',
276
567
  ]),
568
+ 'skills.ios.guideline.ios.evitar-invalidaciones-pasar-valores-mi-nimos-y-evitar-objetos-contexto':
569
+ heuristicDetector('ios.swiftui.invalidation-minimal-inputs', [
570
+ 'heuristics.ios.swiftui.large-config-context-prop.ast',
571
+ 'heuristics.ios.swiftui.redundant-reactive-state-assignment.ast',
572
+ ]),
277
573
  'skills.ios.guideline.ios-swiftui-expert.prefer-modifiers-over-conditional-views-for-state-changes-maintains-vi':
278
574
  heuristicDetector('ios.swiftui.conditional-same-view-identity', [
279
575
  'heuristics.ios.swiftui.conditional-same-view-identity.ast',
@@ -320,6 +616,11 @@ const registryByRuleId: Record<string, SkillsDetectorBinding> = {
320
616
  'ios.swiftui.onappear-task',
321
617
  ['heuristics.ios.swiftui.onappear-task.ast']
322
618
  ),
619
+ 'skills.ios.guideline.ios.task-para-lanzar-contextos-asi-ncronos-desde-co-digo-si-ncrono':
620
+ heuristicDetector('ios.swiftui.sync-triggered-task', [
621
+ 'heuristics.ios.swiftui.onappear-task.ast',
622
+ 'heuristics.ios.swiftui.onchange-task.ast',
623
+ ]),
323
624
  'skills.ios.guideline.ios-swiftui-expert.use-task-modifier-for-automatic-cancellation-of-async-work': heuristicDetector(
324
625
  'ios.swiftui.onappear-task',
325
626
  ['heuristics.ios.swiftui.onappear-task.ast']
@@ -328,22 +629,44 @@ const registryByRuleId: Record<string, SkillsDetectorBinding> = {
328
629
  'ios.swiftui.onchange-task',
329
630
  ['heuristics.ios.swiftui.onchange-task.ast']
330
631
  ),
632
+ 'skills.ios.guideline.ios-swiftui-expert.use-let-for-read-only-values-var-onchange-for-reactive-reads':
633
+ heuristicDetector('ios.swiftui.onchange-readonly-var', [
634
+ 'heuristics.ios.swiftui.onchange-readonly-var.ast',
635
+ ]),
331
636
  'skills.ios.no-uiscreen-main-bounds': heuristicDetector('ios.uiscreen-main-bounds', [
332
637
  'heuristics.ios.uiscreen-main-bounds.ast',
333
638
  ]),
639
+ 'skills.ios.guideline.ios-swiftui-expert.views-should-work-in-any-context-don-t-assume-screen-size-or-presentat':
640
+ heuristicDetector('ios.uiscreen-main-bounds', [
641
+ 'heuristics.ios.uiscreen-main-bounds.ast',
642
+ ]),
334
643
  'skills.ios.prefer-swift-testing': heuristicDetector('ios.testing.xctest-import', [
335
644
  'heuristics.ios.testing.xctest-import.ast',
336
645
  'heuristics.ios.testing.xctest-suite-modernizable.ast',
337
646
  ]),
647
+ 'skills.ios.guideline.ios.swift-testing-ios-17-framework-de-testing-moderno-preferido':
648
+ heuristicDetector('ios.testing.xctest-import', [
649
+ 'heuristics.ios.testing.xctest-import.ast',
650
+ 'heuristics.ios.testing.xctest-suite-modernizable.ast',
651
+ ]),
338
652
  'skills.ios.no-xctassert': heuristicDetector('ios.testing.xctassert', [
339
653
  'heuristics.ios.testing.xctassert.ast',
340
654
  ]),
341
655
  'skills.ios.no-xctunwrap': heuristicDetector('ios.testing.xctunwrap', [
342
656
  'heuristics.ios.testing.xctunwrap.ast',
343
657
  ]),
658
+ 'skills.ios.guideline.ios.expect-y-require-assertions-de-swift-testing':
659
+ heuristicDetector('ios.testing.swift-testing-assertions', [
660
+ 'heuristics.ios.testing.xctassert.ast',
661
+ 'heuristics.ios.testing.xctunwrap.ast',
662
+ ]),
344
663
  'skills.ios.no-wait-for-expectations': heuristicDetector('ios.testing.wait-for-expectations', [
345
664
  'heuristics.ios.testing.wait-for-expectations.ast',
346
665
  ]),
666
+ 'skills.ios.guideline.ios.wait-for-existence-xctwaiter-para-elementos-asi-ncronos':
667
+ heuristicDetector('ios.testing.wait-for-expectations', [
668
+ 'heuristics.ios.testing.wait-for-expectations.ast',
669
+ ]),
347
670
  'skills.ios.no-legacy-expectation-description': heuristicDetector(
348
671
  'ios.testing.legacy-expectation-description',
349
672
  ['heuristics.ios.testing.legacy-expectation-description.ast']
@@ -366,9 +689,23 @@ const registryByRuleId: Record<string, SkillsDetectorBinding> = {
366
689
  'skills.ios.no-core-data-layer-leak': heuristicDetector('ios.core-data.layer-leak', [
367
690
  'heuristics.ios.core-data.layer-leak.ast',
368
691
  ]),
692
+ 'skills.ios.guideline.ios.core-data-solo-para-proyectos-legacy': heuristicDetector(
693
+ 'ios.persistence.core-data-legacy-boundary',
694
+ [
695
+ 'heuristics.ios.core-data.nsmanagedobject-boundary.ast',
696
+ 'heuristics.ios.core-data.nsmanagedobject-async-boundary.ast',
697
+ 'heuristics.ios.core-data.layer-leak.ast',
698
+ 'heuristics.ios.core-data.nsmanagedobject-state-leak.ast',
699
+ ]
700
+ ),
369
701
  'skills.ios.no-swiftdata-layer-leak': heuristicDetector('ios.swiftdata.layer-leak', [
370
702
  'heuristics.ios.swiftdata.layer-leak.ast',
371
703
  ]),
704
+ 'skills.ios.guideline.ios.swiftdata-ios-17-persistencia-moderna-preferida':
705
+ heuristicDetector('ios.persistence.swiftdata-preferred', [
706
+ 'heuristics.ios.core-data.layer-leak.ast',
707
+ 'heuristics.ios.swiftdata.layer-leak.ast',
708
+ ]),
372
709
  'skills.ios.no-nsmanagedobject-state-leak': heuristicDetector(
373
710
  'ios.core-data.nsmanagedobject-state-leak',
374
711
  ['heuristics.ios.core-data.nsmanagedobject-state-leak.ast']
@@ -400,6 +737,32 @@ const registryByRuleId: Record<string, SkillsDetectorBinding> = {
400
737
  'skills.backend.no-god-classes': heuristicDetector('typescript.god-class', [
401
738
  'heuristics.ts.god-class-large-class.ast',
402
739
  ]),
740
+ 'skills.backend.guideline.backend.callback-hell-usar-async-await': heuristicDetector(
741
+ 'typescript.callback-hell',
742
+ ['heuristics.ts.callback-hell.ast']
743
+ ),
744
+ 'skills.backend.guideline.backend.try-catch-silenciosos-siempre-loggear-o-propagar-ast-common-error-empt':
745
+ heuristicDetector('typescript.empty-catch', ['heuristics.ts.empty-catch.ast']),
746
+ 'skills.backend.guideline.backend.hardcoded-values-config-en-variables-de-entorno':
747
+ heuristicDetector('typescript.hardcoded-secret-token', [
748
+ 'heuristics.ts.hardcoded-secret-token.ast',
749
+ ]),
750
+ 'skills.backend.guideline.backend.log-levels-error-warn-info-debug': heuristicDetector(
751
+ 'typescript.console-logging',
752
+ ['heuristics.ts.console-log.ast', 'heuristics.ts.console-error.ast']
753
+ ),
754
+ 'skills.backend.guideline.backend.password-hashing-bcrypt-con-salt-rounds-10':
755
+ heuristicDetector('typescript.bcrypt-weak-salt-rounds', [
756
+ 'heuristics.ts.bcrypt-weak-salt-rounds.ast',
757
+ ]),
758
+ 'skills.backend.guideline.backend.queries-parametrizadas-prevenir-sql-injection':
759
+ heuristicDetector('typescript.sql-interpolated-unsafe-call', [
760
+ 'heuristics.ts.sql-interpolated-unsafe-call.ast',
761
+ ]),
762
+ 'skills.backend.guideline.backend.sql-injection-prevention-queries-parametrizadas':
763
+ heuristicDetector('typescript.sql-interpolated-unsafe-call', [
764
+ 'heuristics.ts.sql-interpolated-unsafe-call.ast',
765
+ ]),
403
766
  'skills.frontend.no-empty-catch': heuristicDetector('typescript.empty-catch', [
404
767
  'heuristics.ts.empty-catch.ast',
405
768
  ]),
@@ -409,6 +772,40 @@ const registryByRuleId: Record<string, SkillsDetectorBinding> = {
409
772
  'skills.frontend.avoid-explicit-any': heuristicDetector('typescript.explicit-any', [
410
773
  'heuristics.ts.explicit-any.ast',
411
774
  ]),
775
+ 'skills.frontend.guideline.frontend.no-any-usar-unknown-si-el-tipo-es-desconocido-luego-type-guard':
776
+ heuristicDetector('typescript.explicit-any', ['heuristics.ts.explicit-any.ast']),
777
+ 'skills.frontend.guideline.frontend.no-catch-vaci-os-prohibido-silenciar-errores-ast-common-error-emptycat':
778
+ heuristicDetector('typescript.empty-catch', ['heuristics.ts.empty-catch.ast']),
779
+ 'skills.frontend.guideline.frontend.tokens-en-headers-authorization-bearer-token-nunca-en-urls':
780
+ heuristicDetector('typescript.sensitive-token-in-url', [
781
+ 'heuristics.ts.sensitive-token-in-url.ast',
782
+ ]),
783
+ 'skills.frontend.guideline.frontend.msw-mock-service-worker-mock-apis-en-tests-no-axios-fetch-directamente':
784
+ heuristicDetector('typescript.frontend-test-direct-network-call', [
785
+ 'heuristics.ts.frontend-test-direct-network-call.ast',
786
+ ]),
787
+ 'skills.frontend.guideline.frontend.keyboard-navigation-todos-los-interactivos-accesibles-por-teclado':
788
+ heuristicDetector('typescript.non-semantic-clickable', [
789
+ 'heuristics.tsx.non-semantic-clickable.ast',
790
+ ]),
791
+ 'skills.frontend.guideline.frontend.semantic-html-button-para-botones-nav-para-navegacio-n-etc':
792
+ heuristicDetector('typescript.non-semantic-clickable', [
793
+ 'heuristics.tsx.non-semantic-clickable.ast',
794
+ ]),
795
+ 'skills.frontend.guideline.frontend.accesibilidad-aria-semantic-html-primero-aria-cuando-sea-necesario':
796
+ heuristicDetector('typescript.semantic-html-aria', [
797
+ 'heuristics.tsx.non-semantic-clickable.ast',
798
+ 'heuristics.tsx.redundant-aria-role.ast',
799
+ ]),
800
+ 'skills.frontend.guideline.frontend.preferir-early-returns-y-destructuring-evitar-if-else-anidados-callbac':
801
+ heuristicDetector('typescript.early-returns-control-flow', [
802
+ 'heuristics.ts.callback-hell.ast',
803
+ 'heuristics.ts.nested-if-else.ast',
804
+ ]),
805
+ 'skills.frontend.guideline.frontend.route-handlers-app-api-para-endpoints-backend':
806
+ heuristicDetector('typescript.next-pages-api-route', [
807
+ 'heuristics.ts.next-pages-api-route.ast',
808
+ ]),
412
809
  'skills.frontend.no-solid-violations': heuristicDetector('typescript.solid', [
413
810
  'heuristics.ts.solid.srp.class-command-query-mix.ast',
414
811
  'heuristics.ts.solid.isp.interface-command-query-mix.ast',
@@ -437,6 +834,26 @@ const registryByRuleId: Record<string, SkillsDetectorBinding> = {
437
834
  'heuristics.ios.solid.lsp.narrowed-precondition.ast',
438
835
  ]
439
836
  ),
837
+ 'skills.ios.guideline.ios.testability-inyectar-protocols-no-tipos-concretos':
838
+ heuristicDetector('ios.testability.protocol-boundaries', [
839
+ 'heuristics.ios.solid.dip.concrete-framework-dependency.ast',
840
+ ]),
841
+ 'skills.ios.guideline.ios.network-layer-abstrai-do-apiclient-protocol-en-domain':
842
+ heuristicDetector('ios.networking.protocol-boundary', [
843
+ 'heuristics.ios.solid.dip.concrete-framework-dependency.ast',
844
+ ]),
845
+ 'skills.ios.guideline.ios.protocols-en-domain-ordersrepositoryprotocol-networkserviceprotocol':
846
+ heuristicDetector('ios.domain.protocol-boundaries', [
847
+ 'heuristics.ios.solid.dip.concrete-framework-dependency.ast',
848
+ ]),
849
+ 'skills.ios.guideline.ios.repository-pattern-ordersrepositoryprotocol-ordersrepository':
850
+ heuristicDetector('ios.repository.protocol-boundary', [
851
+ 'heuristics.ios.solid.dip.concrete-framework-dependency.ast',
852
+ ]),
853
+ 'skills.ios.guideline.ios.protocol-composition-combinar-mu-ltiples-protocols':
854
+ heuristicDetector('ios.protocol-composition.interface-segregation', [
855
+ 'heuristics.ios.solid.isp.fat-protocol-dependency.ast',
856
+ ]),
440
857
  'skills.android.no-thread-sleep': heuristicDetector('android.thread-sleep', [
441
858
  'heuristics.android.thread-sleep.ast',
442
859
  ]),
@@ -453,6 +870,78 @@ const registryByRuleId: Record<string, SkillsDetectorBinding> = {
453
870
  'heuristics.android.run-blocking.ast',
454
871
  ]
455
872
  ),
873
+ 'skills.android.guideline.android.asynctask-deprecated-usar-coroutines': heuristicDetector(
874
+ 'android.concurrency.asynctask',
875
+ ['heuristics.android.concurrency.asynctask.ast']
876
+ ),
877
+ 'skills.android.guideline.android.god-activities-single-activity-composables': heuristicDetector(
878
+ 'android.architecture.god-activity',
879
+ ['heuristics.android.architecture.god-activity.ast']
880
+ ),
881
+ 'skills.android.guideline.android.lazycolumn-lazyrow-virtualizacio-n-de-listas': heuristicDetector(
882
+ 'android.compose.lazy-collection',
883
+ ['heuristics.android.compose.non-lazy-scrollable-collection.ast']
884
+ ),
885
+ 'skills.android.guideline.android.launchedeffect-keys-controlar-cua-ndo-se-relanza-effect': heuristicDetector(
886
+ 'android.compose.launched-effect-key',
887
+ ['heuristics.android.compose.unstable-launched-effect-key.ast']
888
+ ),
889
+ 'skills.android.guideline.android.launchedeffect-side-effects-con-lifecycle': heuristicDetector(
890
+ 'android.compose.launched-effect-lifecycle',
891
+ ['heuristics.android.compose.launched-effect-busy-loop.ast']
892
+ ),
893
+ 'skills.android.guideline.android.log-levels-e-error-w-warn-i-info-d-debug': heuristicDetector(
894
+ 'android.observability.production-logging',
895
+ ['heuristics.android.observability.production-logging.ast']
896
+ ),
897
+ 'skills.android.guideline.android.modifier-orden-importa-padding-antes-que-background': heuristicDetector(
898
+ 'android.compose.modifier-order',
899
+ ['heuristics.android.compose.modifier-background-before-padding.ast']
900
+ ),
901
+ 'skills.android.guideline.android.accessibility-semantics-contentdescription': heuristicDetector(
902
+ 'android.accessibility.content-description',
903
+ ['heuristics.android.accessibility.missing-content-description.ast']
904
+ ),
905
+ 'skills.android.guideline.android.contentdescription-para-ima-genes-y-botones': heuristicDetector(
906
+ 'android.accessibility.content-description',
907
+ ['heuristics.android.accessibility.missing-content-description.ast']
908
+ ),
909
+ 'skills.android.guideline.android.text-scaling-soportar-font-scaling-del-sistema': heuristicDetector(
910
+ 'android.accessibility.fontscale-disabled',
911
+ ['heuristics.android.accessibility.fontscale-disabled.ast']
912
+ ),
913
+ 'skills.android.guideline.android.theme-color-scheme-typography-shapes': heuristicDetector(
914
+ 'android.compose.incomplete-material-theme',
915
+ ['heuristics.android.compose.incomplete-material-theme.ast']
916
+ ),
917
+ 'skills.android.guideline.android.bottom-navigation-material-3-navigationbar': heuristicDetector(
918
+ 'android.compose.material3-navigationbar',
919
+ ['heuristics.android.compose.legacy-bottom-navigation.ast']
920
+ ),
921
+ 'skills.android.guideline.android.navigation-androidx-navigation-navigation-compose': heuristicDetector(
922
+ 'android.navigation.compose',
923
+ ['heuristics.android.navigation.imperative-navigation.ast']
924
+ ),
925
+ 'skills.android.guideline.android.navigation-component-jetpack-navigation-para-compose': heuristicDetector(
926
+ 'android.navigation.compose',
927
+ ['heuristics.android.navigation.imperative-navigation.ast']
928
+ ),
929
+ 'skills.android.guideline.android.navigation-compose-androidx-navigation-navigation-compose': heuristicDetector(
930
+ 'android.navigation.compose',
931
+ ['heuristics.android.navigation.imperative-navigation.ast']
932
+ ),
933
+ 'skills.android.guideline.android.remember-evitar-recrear-objetos': heuristicDetector(
934
+ 'android.compose.object-creation-without-remember',
935
+ ['heuristics.android.compose.object-creation-without-remember.ast']
936
+ ),
937
+ 'skills.android.guideline.android.remember-para-mantener-estado-entre-recomposiciones': heuristicDetector(
938
+ 'android.compose.state-creation-without-remember',
939
+ ['heuristics.android.compose.state-creation-without-remember.ast']
940
+ ),
941
+ 'skills.android.guideline.android.null-safety-no-force-unwrap-usar-let-requirenotnull': heuristicDetector(
942
+ 'android.null-safety.force-unwrap',
943
+ ['heuristics.android.null-safety.force-unwrap.ast']
944
+ ),
456
945
  'skills.android.guideline.android.viewmodelscope-scope-de-viewmodel-cancelado-automa-ticamente': heuristicDetector(
457
946
  'android.coroutines.viewmodel-scope',
458
947
  ['heuristics.android.coroutines.manual-scope-in-viewmodel.ast']
@@ -496,6 +985,10 @@ const registryByRuleId: Record<string, SkillsDetectorBinding> = {
496
985
  'android.testing.production-mock-usage',
497
986
  ['heuristics.android.testing.production-mock-usage.ast']
498
987
  ),
988
+ 'skills.android.guideline.android.hardcoded-strings-usar-strings-xml': heuristicDetector(
989
+ 'android.ui.hardcoded-string',
990
+ ['heuristics.android.ui.hardcoded-string.ast']
991
+ ),
499
992
  'skills.android.guideline.android.stateflow-estado-mutable-observable': heuristicDetector(
500
993
  'android.flow.state-exposure',
501
994
  ['heuristics.android.flow.livedata-state-exposure.ast']
@@ -508,6 +1001,14 @@ const registryByRuleId: Record<string, SkillsDetectorBinding> = {
508
1001
  'android.flow.state-exposure',
509
1002
  ['heuristics.android.flow.livedata-state-exposure.ast']
510
1003
  ),
1004
+ 'skills.android.guideline.android.statein-convertir-cold-flow-a-hot-stateflow': heuristicDetector(
1005
+ 'android.flow.viewmodel-flow-without-statein',
1006
+ ['heuristics.android.flow.viewmodel-flow-without-statein.ast']
1007
+ ),
1008
+ 'skills.android.guideline.android.sharedflow-hot-stream-puede-no-tener-valor-para-eventos': heuristicDetector(
1009
+ 'android.flow.sharedflow-used-as-state',
1010
+ ['heuristics.android.flow.sharedflow-used-as-state.ast']
1011
+ ),
511
1012
  'skills.android.no-solid-violations': heuristicDetector('android.solid', [
512
1013
  'heuristics.android.solid.srp.presentation-mixed-responsibilities.ast',
513
1014
  'heuristics.android.solid.ocp.discriminator-branching.ast',