pumuki 6.3.226 → 6.3.228

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.
@@ -36,8 +36,10 @@ import {
36
36
  hasSwiftLegacyXCTestImportUsage,
37
37
  hasSwiftModernizableXCTestSuiteUsage,
38
38
  hasSwiftNonLazyScrollForEachUsage,
39
+ hasSwiftUiForEachConditionalViewCountUsage,
39
40
  hasSwiftViewBodyObjectCreationUsage,
40
41
  hasSwiftUiImageDataDecodingUsage,
42
+ hasSwiftUiInlineActionLogicUsage,
41
43
  hasSwiftAssumeIsolatedUsage,
42
44
  hasSwiftCoreDataLayerLeakUsage,
43
45
  hasSwiftSwiftDataLayerLeakUsage,
@@ -164,6 +166,40 @@ struct FeedView: View {
164
166
  assert.equal(hasSwiftNonLazyScrollForEachUsage(safe), false);
165
167
  });
166
168
 
169
+ test('hasSwiftUiForEachConditionalViewCountUsage detecta branching condicional dentro de ForEach', () => {
170
+ const source = `
171
+ struct FeedView: View {
172
+ let items: [Item]
173
+
174
+ var body: some View {
175
+ ForEach(items) { item in
176
+ if item.isPromoted {
177
+ PromotedRow(item: item)
178
+ } else {
179
+ RegularRow(item: item)
180
+ }
181
+ }
182
+ }
183
+ }
184
+ `;
185
+ const safe = `
186
+ struct FeedView: View {
187
+ let items: [Item]
188
+
189
+ var body: some View {
190
+ ForEach(items) { item in
191
+ FeedRow(item: item)
192
+ }
193
+ let sample = "ForEach(items) { item in if item.isPromoted { PromotedRow(item: item) } }"
194
+ // ForEach(items) { item in if item.isPromoted { PromotedRow(item: item) } }
195
+ }
196
+ }
197
+ `;
198
+
199
+ assert.equal(hasSwiftUiForEachConditionalViewCountUsage(source), true);
200
+ assert.equal(hasSwiftUiForEachConditionalViewCountUsage(safe), false);
201
+ });
202
+
167
203
  test('hasSwiftViewBodyObjectCreationUsage detecta formatter creado en body y preserva dependencia externa', () => {
168
204
  const source = `
169
205
  struct PriceView: View {
@@ -220,6 +256,41 @@ struct AvatarView: View {
220
256
  assert.equal(hasSwiftUiImageDataDecodingUsage(safe), false);
221
257
  });
222
258
 
259
+ test('hasSwiftUiInlineActionLogicUsage detecta lógica inline en Button y preserva método referenciado', () => {
260
+ const source = `
261
+ struct CheckoutView: View {
262
+ @State private var isLoading = false
263
+
264
+ var body: some View {
265
+ Button {
266
+ if isLoading {
267
+ return
268
+ }
269
+ Task {
270
+ await submit()
271
+ }
272
+ } label: {
273
+ Text("Pay")
274
+ }
275
+ }
276
+ }
277
+ `;
278
+ const safe = `
279
+ struct CheckoutView: View {
280
+ var body: some View {
281
+ Button(action: submit) {
282
+ Text("Pay")
283
+ }
284
+ let sample = "Button { if loading { return } } label:"
285
+ // Button { if loading { return } } label:
286
+ }
287
+ }
288
+ `;
289
+
290
+ assert.equal(hasSwiftUiInlineActionLogicUsage(source), true);
291
+ assert.equal(hasSwiftUiInlineActionLogicUsage(safe), false);
292
+ });
293
+
223
294
  test('hasSwiftForceTryUsage detecta try! y descarta try?', () => {
224
295
  const positive = `
225
296
  func load() {
@@ -388,6 +388,14 @@ export const hasSwiftNonLazyScrollForEachUsage = (source: string): boolean => {
388
388
  return nonLazyScrollableCollectionPattern.test(swiftSource);
389
389
  };
390
390
 
391
+ export const hasSwiftUiForEachConditionalViewCountUsage = (source: string): boolean => {
392
+ const swiftSource = sanitizeSwiftSourceForMultilineRegex(source);
393
+ const conditionalForEachPattern =
394
+ /\bForEach\s*\([^)]*\)\s*\{[\s\S]{0,1600}\b(?:if|switch)\b[\s\S]{0,1600}\}/;
395
+
396
+ return conditionalForEachPattern.test(swiftSource);
397
+ };
398
+
391
399
  export const hasSwiftViewBodyObjectCreationUsage = (source: string): boolean => {
392
400
  const swiftSource = sanitizeSwiftSourceForMultilineRegex(source);
393
401
  const viewBodyObjectCreationPattern =
@@ -401,6 +409,16 @@ export const hasSwiftUiImageDataDecodingUsage = (source: string): boolean => {
401
409
  return /\bUIImage\s*\(\s*data\s*:/.test(swiftSource);
402
410
  };
403
411
 
412
+ export const hasSwiftUiInlineActionLogicUsage = (source: string): boolean => {
413
+ const swiftSource = sanitizeSwiftSourceForMultilineRegex(source);
414
+ const inlineButtonActionPattern =
415
+ /\bButton\s*\{[\s\S]{0,900}\b(?:if|guard|switch|for|while|Task)\b[\s\S]{0,900}\}\s*label\s*:/;
416
+ const inlineActionParameterPattern =
417
+ /\bButton\s*\([^)]*\baction\s*:\s*\{[\s\S]{0,900}\b(?:if|guard|switch|for|while|Task)\b[\s\S]{0,900}\}/;
418
+
419
+ return inlineButtonActionPattern.test(swiftSource) || inlineActionParameterPattern.test(swiftSource);
420
+ };
421
+
404
422
  export const hasSwiftDispatchQueueUsage = (source: string): boolean => {
405
423
  return scanCodeLikeSource(source, ({ source: swiftSource, index, current }) => {
406
424
  if (current !== 'D' || !hasIdentifierAt(swiftSource, index, 'DispatchQueue')) {
@@ -679,6 +679,7 @@ const textDetectorRegistry: ReadonlyArray<TextDetectorRegistryEntry> = [
679
679
  { platform: 'ios', pathCheck: isIOSSwiftPath, excludePaths: [isSwiftTestPath], detect: TextIOS.hasSwiftPassedValueStateWrapperUsage, ruleId: 'heuristics.ios.passed-value-state-wrapper.ast', code: 'HEURISTICS_IOS_PASSED_VALUE_STATE_WRAPPER_AST', message: 'AST heuristic detected a passed value stored as @State/@StateObject via init wrapper ownership.' },
680
680
  { platform: 'ios', pathCheck: isIOSPresentationPath, excludePaths: [isSwiftTestPath], detect: TextIOS.hasSwiftForEachIndicesUsage, ruleId: 'heuristics.ios.foreach-indices.ast', code: 'HEURISTICS_IOS_FOREACH_INDICES_AST', message: 'AST heuristic detected ForEach(...indices...) usage where stable element identity may be preferred.' },
681
681
  { platform: 'ios', pathCheck: isIOSPresentationPath, excludePaths: [isSwiftTestPath], detect: TextIOS.hasSwiftInlineForEachTransformUsage, ruleId: 'heuristics.ios.swiftui.inline-foreach-transform.ast', code: 'HEURISTICS_IOS_SWIFTUI_INLINE_FOREACH_TRANSFORM_AST', message: 'AST heuristic detected inline filter/map/sort work inside ForEach; prefiltered or cached collections remain the preferred baseline.' },
682
+ { platform: 'ios', pathCheck: isIOSPresentationPath, excludePaths: [isSwiftTestPath], detect: TextIOS.hasSwiftUiForEachConditionalViewCountUsage, ruleId: 'heuristics.ios.swiftui.foreach-conditional-view-count.ast', code: 'HEURISTICS_IOS_SWIFTUI_FOREACH_CONDITIONAL_VIEW_COUNT_AST', message: 'AST heuristic detected conditional view count inside ForEach; keep a constant number of views per element by moving branching into row views or modifiers.' },
682
683
  { platform: 'ios', pathCheck: isIOSApplicationOrPresentationPath, excludePaths: [isSwiftTestPath], detect: TextIOS.hasSwiftContainsUserFilterUsage, ruleId: 'heuristics.ios.contains-user-filter.ast', code: 'HEURISTICS_IOS_CONTAINS_USER_FILTER_AST', message: 'AST heuristic detected contains() in a user-facing filter where localizedStandardContains() may be preferred.' },
683
684
  { platform: 'ios', pathCheck: isIOSPresentationPath, excludePaths: [isSwiftTestPath], detect: TextIOS.hasSwiftGeometryReaderUsage, ruleId: 'heuristics.ios.geometryreader.ast', code: 'HEURISTICS_IOS_GEOMETRYREADER_AST', message: 'AST heuristic detected GeometryReader usage that may be replaceable with modern layout APIs.' },
684
685
  { platform: 'ios', pathCheck: isIOSPresentationPath, excludePaths: [isSwiftTestPath], detect: TextIOS.hasSwiftFontWeightBoldUsage, ruleId: 'heuristics.ios.font-weight-bold.ast', code: 'HEURISTICS_IOS_FONT_WEIGHT_BOLD_AST', message: 'AST heuristic detected fontWeight(.bold) usage where bold() may be preferred.' },
@@ -688,6 +689,7 @@ const textDetectorRegistry: ReadonlyArray<TextDetectorRegistryEntry> = [
688
689
  { platform: 'ios', pathCheck: isIOSPresentationPath, excludePaths: [isSwiftTestPath], detect: TextIOS.hasSwiftNonLazyScrollForEachUsage, ruleId: 'heuristics.ios.swiftui.non-lazy-scroll-foreach.ast', code: 'HEURISTICS_IOS_SWIFTUI_NON_LAZY_SCROLL_FOREACH_AST', message: 'AST heuristic detected ScrollView with a non-lazy stack feeding ForEach; LazyVStack/LazyHStack remain the preferred baseline for large scrollable collections.' },
689
690
  { platform: 'ios', pathCheck: isIOSPresentationPath, excludePaths: [isSwiftTestPath], detect: TextIOS.hasSwiftViewBodyObjectCreationUsage, ruleId: 'heuristics.ios.swiftui.body-object-creation.ast', code: 'HEURISTICS_IOS_SWIFTUI_BODY_OBJECT_CREATION_AST', message: 'AST heuristic detected formatter object creation inside SwiftUI body; keep body simple and move expensive objects out of render paths.' },
690
691
  { platform: 'ios', pathCheck: isIOSPresentationPath, excludePaths: [isSwiftTestPath], detect: TextIOS.hasSwiftUiImageDataDecodingUsage, ruleId: 'heuristics.ios.swiftui.image-data-decoding.ast', code: 'HEURISTICS_IOS_SWIFTUI_IMAGE_DATA_DECODING_AST', message: 'AST heuristic detected UIImage(data:) in SwiftUI presentation; downsample image data before rendering large images.' },
692
+ { platform: 'ios', pathCheck: isIOSPresentationPath, excludePaths: [isSwiftTestPath], detect: TextIOS.hasSwiftUiInlineActionLogicUsage, ruleId: 'heuristics.ios.swiftui.inline-action-logic.ast', code: 'HEURISTICS_IOS_SWIFTUI_INLINE_ACTION_LOGIC_AST', message: 'AST heuristic detected inline logic inside a SwiftUI action handler; action handlers should reference methods and keep view declarations focused.' },
691
693
  { platform: 'ios', pathCheck: isIOSSwiftPath, excludePaths: [isSwiftTestPath], detect: TextIOS.hasSwiftNavigationViewUsage, ruleId: 'heuristics.ios.navigation-view.ast', code: 'HEURISTICS_IOS_NAVIGATION_VIEW_AST', message: 'AST heuristic detected NavigationView usage.' },
692
694
  { platform: 'ios', pathCheck: isIOSSwiftPath, excludePaths: [isSwiftTestPath], detect: TextIOS.hasSwiftForegroundColorUsage, ruleId: 'heuristics.ios.foreground-color.ast', code: 'HEURISTICS_IOS_FOREGROUND_COLOR_AST', message: 'AST heuristic detected foregroundColor usage.' },
693
695
  { platform: 'ios', pathCheck: isIOSSwiftPath, excludePaths: [isSwiftTestPath], detect: TextIOS.hasSwiftCornerRadiusUsage, ruleId: 'heuristics.ios.corner-radius.ast', code: 'HEURISTICS_IOS_CORNER_RADIUS_AST', message: 'AST heuristic detected cornerRadius usage.' },
@@ -803,6 +803,25 @@ export const iosRules: RuleSet = [
803
803
  code: 'HEURISTICS_IOS_SWIFTUI_INLINE_FOREACH_TRANSFORM_AST',
804
804
  },
805
805
  },
806
+ {
807
+ id: 'heuristics.ios.swiftui.foreach-conditional-view-count.ast',
808
+ description: 'Detects conditional view counts inside SwiftUI ForEach rows.',
809
+ severity: 'WARN',
810
+ platform: 'ios',
811
+ locked: true,
812
+ when: {
813
+ kind: 'Heuristic',
814
+ where: {
815
+ ruleId: 'heuristics.ios.swiftui.foreach-conditional-view-count.ast',
816
+ },
817
+ },
818
+ then: {
819
+ kind: 'Finding',
820
+ message:
821
+ 'AST heuristic detected conditional view count inside ForEach; keep a constant number of views per element by moving branching into row views or modifiers.',
822
+ code: 'HEURISTICS_IOS_SWIFTUI_FOREACH_CONDITIONAL_VIEW_COUNT_AST',
823
+ },
824
+ },
806
825
  {
807
826
  id: 'heuristics.ios.contains-user-filter.ast',
808
827
  description: 'Detects contains() usage in user-facing filter flows where localizedStandardContains() may be preferred.',
@@ -968,6 +987,25 @@ export const iosRules: RuleSet = [
968
987
  code: 'HEURISTICS_IOS_SWIFTUI_IMAGE_DATA_DECODING_AST',
969
988
  },
970
989
  },
990
+ {
991
+ id: 'heuristics.ios.swiftui.inline-action-logic.ast',
992
+ description: 'Detects inline control-flow logic inside SwiftUI action handlers.',
993
+ severity: 'WARN',
994
+ platform: 'ios',
995
+ locked: true,
996
+ when: {
997
+ kind: 'Heuristic',
998
+ where: {
999
+ ruleId: 'heuristics.ios.swiftui.inline-action-logic.ast',
1000
+ },
1001
+ },
1002
+ then: {
1003
+ kind: 'Finding',
1004
+ message:
1005
+ 'AST heuristic detected inline logic inside a SwiftUI action handler; action handlers should reference methods and keep view declarations focused.',
1006
+ code: 'HEURISTICS_IOS_SWIFTUI_INLINE_ACTION_LOGIC_AST',
1007
+ },
1008
+ },
971
1009
  {
972
1010
  id: 'heuristics.ios.navigation-view.ast',
973
1011
  description: 'Detects NavigationView usage in iOS production code.',
@@ -233,6 +233,10 @@ const registryByRuleId: Record<string, SkillsDetectorBinding> = {
233
233
  heuristicDetector('ios.swiftui.inline-foreach-transform', [
234
234
  'heuristics.ios.swiftui.inline-foreach-transform.ast',
235
235
  ]),
236
+ 'skills.ios.guideline.ios-swiftui-expert.ensure-constant-number-of-views-per-foreach-element':
237
+ heuristicDetector('ios.swiftui.foreach-conditional-view-count', [
238
+ 'heuristics.ios.swiftui.foreach-conditional-view-count.ast',
239
+ ]),
236
240
  'skills.ios.no-contains-user-filter': heuristicDetector('ios.contains-user-filter', [
237
241
  'heuristics.ios.contains-user-filter.ast',
238
242
  ]),
@@ -266,6 +270,10 @@ const registryByRuleId: Record<string, SkillsDetectorBinding> = {
266
270
  heuristicDetector('ios.swiftui.image-data-decoding', [
267
271
  'heuristics.ios.swiftui.image-data-decoding.ast',
268
272
  ]),
273
+ 'skills.ios.guideline.ios-swiftui-expert.action-handlers-should-reference-methods-not-contain-inline-logic':
274
+ heuristicDetector('ios.swiftui.inline-action-logic', [
275
+ 'heuristics.ios.swiftui.inline-action-logic.ast',
276
+ ]),
269
277
  'skills.ios.no-scrollview-shows-indicators': heuristicDetector(
270
278
  'ios.scrollview-shows-indicators',
271
279
  ['heuristics.ios.scrollview-shows-indicators.ast']
@@ -16,7 +16,7 @@ const MARKDOWN_BOLD_PATTERN = /[*_]{1,3}/g;
16
16
  const MULTISPACE_PATTERN = /\s+/g;
17
17
  const AST_NODE_ID_PATTERN = /\bheuristics\.[a-z0-9._-]+\.ast\b/gi;
18
18
  const RULE_KEYWORDS =
19
- /\b(always|siempre|prefer|use|usar|avoid|evitar|never|nunca|must|obligatorio|required|disallow|do not|no|suggest)\b/i;
19
+ /\b(always|siempre|prefer|use|usar|avoid|evitar|ensure|never|nunca|must|obligatorio|required|disallow|do not|no|suggest|should)\b/i;
20
20
 
21
21
  const normalizeForLookup = (value: string): string => {
22
22
  return value
@@ -316,6 +316,12 @@ const normalizeKnownRuleTarget = (
316
316
  ) {
317
317
  return 'skills.ios.guideline.ios-swiftui-expert.avoid-inline-filtering-in-foreach-prefilter-and-cache';
318
318
  }
319
+ if (
320
+ includes('constant number of views per foreach element') ||
321
+ (includes('foreach') && includes('constant number of views'))
322
+ ) {
323
+ return 'skills.ios.guideline.ios-swiftui-expert.ensure-constant-number-of-views-per-foreach-element';
324
+ }
319
325
  if (
320
326
  includes('localizedstandardcontains') ||
321
327
  includes('localized standard contains') ||
@@ -381,6 +387,13 @@ const normalizeKnownRuleTarget = (
381
387
  ) {
382
388
  return 'skills.ios.guideline.ios-swiftui-expert.suggest-image-downsampling-when-uiimage-data-is-encountered';
383
389
  }
390
+ if (
391
+ (includes('action handlers') && includes('reference methods')) ||
392
+ (includes('action handlers') && includes('inline logic')) ||
393
+ (includes('handlers should reference methods') && includes('inline logic'))
394
+ ) {
395
+ return 'skills.ios.guideline.ios-swiftui-expert.action-handlers-should-reference-methods-not-contain-inline-logic';
396
+ }
384
397
  if (
385
398
  includes('scrollindicators hidden') ||
386
399
  includes('scroll indicators hidden') ||
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pumuki",
3
- "version": "6.3.226",
3
+ "version": "6.3.228",
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-13T16:23:26.589Z",
4
+ "generatedAt": "2026-05-13T16:36:55.011Z",
5
5
  "bundles": [
6
6
  {
7
7
  "name": "android-guidelines",
@@ -8632,8 +8632,20 @@
8632
8632
  "name": "ios-swiftui-expert-guidelines",
8633
8633
  "version": "1.0.0",
8634
8634
  "source": "file:vendor/skills/swiftui-expert-skill/SKILL.md",
8635
- "hash": "10b8966d8204f1abb91af3254cfb809bf0a3822b8d09347c28639d23e6dfc1c7",
8635
+ "hash": "87916172b71811a09b147336b1625bce94571b1f9c66885bd136cfac27079b0d",
8636
8636
  "rules": [
8637
+ {
8638
+ "id": "skills.ios.guideline.ios-swiftui-expert.action-handlers-should-reference-methods-not-contain-inline-logic",
8639
+ "description": "Action handlers should reference methods, not contain inline logic",
8640
+ "severity": "WARN",
8641
+ "platform": "ios",
8642
+ "sourceSkill": "ios-swiftui-expert-guidelines",
8643
+ "sourcePath": "vendor/skills/swiftui-expert-skill/SKILL.md",
8644
+ "confidence": "MEDIUM",
8645
+ "locked": true,
8646
+ "evaluationMode": "AUTO",
8647
+ "origin": "core"
8648
+ },
8637
8649
  {
8638
8650
  "id": "skills.ios.guideline.ios-swiftui-expert.always-mark-state-and-stateobject-as-private-makes-dependencies-clear",
8639
8651
  "description": "Always mark @State and @StateObject as private (makes dependencies clear)",
@@ -8670,6 +8682,30 @@
8670
8682
  "evaluationMode": "AUTO",
8671
8683
  "origin": "core"
8672
8684
  },
8685
+ {
8686
+ "id": "skills.ios.guideline.ios-swiftui-expert.ensure-constant-number-of-views-per-foreach-element",
8687
+ "description": "Ensure constant number of views per ForEach element",
8688
+ "severity": "WARN",
8689
+ "platform": "ios",
8690
+ "sourceSkill": "ios-swiftui-expert-guidelines",
8691
+ "sourcePath": "vendor/skills/swiftui-expert-skill/SKILL.md",
8692
+ "confidence": "MEDIUM",
8693
+ "locked": true,
8694
+ "evaluationMode": "AUTO",
8695
+ "origin": "core"
8696
+ },
8697
+ {
8698
+ "id": "skills.ios.guideline.ios-swiftui-expert.ensure-foreach-uses-stable-identity-see-references-list-patterns-md",
8699
+ "description": "Ensure ForEach uses stable identity (see references/list-patterns.md)",
8700
+ "severity": "WARN",
8701
+ "platform": "ios",
8702
+ "sourceSkill": "ios-swiftui-expert-guidelines",
8703
+ "sourcePath": "vendor/skills/swiftui-expert-skill/SKILL.md",
8704
+ "confidence": "MEDIUM",
8705
+ "locked": true,
8706
+ "evaluationMode": "DECLARATIVE",
8707
+ "origin": "core"
8708
+ },
8673
8709
  {
8674
8710
  "id": "skills.ios.guideline.ios-swiftui-expert.keep-view-body-simple-and-pure-no-side-effects-or-complex-logic",
8675
8711
  "description": "Keep view body simple and pure (no side effects or complex logic)",
@@ -8742,6 +8778,18 @@
8742
8778
  "evaluationMode": "DECLARATIVE",
8743
8779
  "origin": "core"
8744
8780
  },
8781
+ {
8782
+ "id": "skills.ios.guideline.ios-swiftui-expert.sheets-should-own-their-actions-and-call-dismiss-internally",
8783
+ "description": "Sheets should own their actions and call dismiss() internally",
8784
+ "severity": "WARN",
8785
+ "platform": "ios",
8786
+ "sourceSkill": "ios-swiftui-expert-guidelines",
8787
+ "sourcePath": "vendor/skills/swiftui-expert-skill/SKILL.md",
8788
+ "confidence": "MEDIUM",
8789
+ "locked": true,
8790
+ "evaluationMode": "DECLARATIVE",
8791
+ "origin": "core"
8792
+ },
8745
8793
  {
8746
8794
  "id": "skills.ios.guideline.ios-swiftui-expert.suggest-image-downsampling-when-uiimage-data-is-encountered",
8747
8795
  "description": "Suggest image downsampling when UIImage(data:) is used (as optional optimization, see references/image-optimization.md)",
@@ -8946,6 +8994,18 @@
8946
8994
  "evaluationMode": "DECLARATIVE",
8947
8995
  "origin": "core"
8948
8996
  },
8997
+ {
8998
+ "id": "skills.ios.guideline.ios-swiftui-expert.views-should-work-in-any-context-don-t-assume-screen-size-or-presentat",
8999
+ "description": "Views should work in any context (don't assume screen size or presentation style)",
9000
+ "severity": "WARN",
9001
+ "platform": "ios",
9002
+ "sourceSkill": "ios-swiftui-expert-guidelines",
9003
+ "sourcePath": "vendor/skills/swiftui-expert-skill/SKILL.md",
9004
+ "confidence": "MEDIUM",
9005
+ "locked": true,
9006
+ "evaluationMode": "DECLARATIVE",
9007
+ "origin": "core"
9008
+ },
8949
9009
  {
8950
9010
  "id": "skills.ios.no-anyview",
8951
9011
  "description": "Avoid AnyView in list rows",