pumuki 6.3.228 → 6.3.230
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/core/facts/detectors/text/ios.test.ts +85 -0
- package/core/facts/detectors/text/ios.ts +13 -0
- package/core/facts/extractHeuristicFacts.ts +2 -0
- package/core/rules/presets/heuristics/ios.ts +38 -0
- package/integrations/config/skillsDetectorRegistry.ts +12 -0
- package/integrations/config/skillsMarkdownRules.ts +16 -0
- package/package.json +1 -1
- package/skills.lock.json +18 -30
|
@@ -15,6 +15,7 @@ import {
|
|
|
15
15
|
hasSwiftAdHocLoggingUsage,
|
|
16
16
|
hasSwiftAlamofireUsage,
|
|
17
17
|
hasSwiftForEachIndicesUsage,
|
|
18
|
+
hasSwiftForEachSelfIdentityUsage,
|
|
18
19
|
hasSwiftForceCastUsage,
|
|
19
20
|
hasSwiftFontWeightBoldUsage,
|
|
20
21
|
hasSwiftFixedFontSizeUsage,
|
|
@@ -48,6 +49,7 @@ import {
|
|
|
48
49
|
hasSwiftNSManagedObjectBoundaryUsage,
|
|
49
50
|
hasSwiftNSManagedObjectStateLeakUsage,
|
|
50
51
|
hasSwiftNavigationViewUsage,
|
|
52
|
+
hasSwiftUntypedNavigationLinkDestinationUsage,
|
|
51
53
|
hasSwiftNonPrivateStateOwnershipUsage,
|
|
52
54
|
hasSwiftNonIBOutletImplicitlyUnwrappedOptionalUsage,
|
|
53
55
|
hasSwiftObservableObjectUsage,
|
|
@@ -291,6 +293,89 @@ struct CheckoutView: View {
|
|
|
291
293
|
assert.equal(hasSwiftUiInlineActionLogicUsage(safe), false);
|
|
292
294
|
});
|
|
293
295
|
|
|
296
|
+
test('hasSwiftForEachSelfIdentityUsage detecta id self y preserva ids estables', () => {
|
|
297
|
+
const source = `
|
|
298
|
+
struct FeedView: View {
|
|
299
|
+
let items: [Item]
|
|
300
|
+
|
|
301
|
+
var body: some View {
|
|
302
|
+
ForEach(items, id: \\.self) { item in
|
|
303
|
+
FeedRow(item: item)
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
`;
|
|
308
|
+
const safe = `
|
|
309
|
+
struct FeedView: View {
|
|
310
|
+
let items: [Item]
|
|
311
|
+
|
|
312
|
+
var body: some View {
|
|
313
|
+
ForEach(items, id: \\.id) { item in
|
|
314
|
+
FeedRow(item: item)
|
|
315
|
+
}
|
|
316
|
+
let sample = "ForEach(items, id: \\.self) { item in FeedRow(item: item) }"
|
|
317
|
+
// ForEach(items, id: \.self) { item in FeedRow(item: item) }
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
`;
|
|
321
|
+
|
|
322
|
+
assert.equal(hasSwiftForEachSelfIdentityUsage(source), true);
|
|
323
|
+
assert.equal(hasSwiftForEachSelfIdentityUsage(safe), false);
|
|
324
|
+
});
|
|
325
|
+
|
|
326
|
+
test('hasSwiftUntypedNavigationLinkDestinationUsage detecta NavigationLink no tipado y preserva value navigation', () => {
|
|
327
|
+
const source = `
|
|
328
|
+
struct FeedView: View {
|
|
329
|
+
let items: [Item]
|
|
330
|
+
|
|
331
|
+
var body: some View {
|
|
332
|
+
NavigationStack {
|
|
333
|
+
List(items) { item in
|
|
334
|
+
NavigationLink(destination: DetailView(item: item)) {
|
|
335
|
+
Text(item.title)
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
`;
|
|
342
|
+
const trailing = `
|
|
343
|
+
struct FeedView: View {
|
|
344
|
+
var body: some View {
|
|
345
|
+
NavigationLink {
|
|
346
|
+
DetailView()
|
|
347
|
+
} label: {
|
|
348
|
+
Text("Open")
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
`;
|
|
353
|
+
const safe = `
|
|
354
|
+
struct FeedView: View {
|
|
355
|
+
let items: [Item]
|
|
356
|
+
|
|
357
|
+
var body: some View {
|
|
358
|
+
NavigationStack {
|
|
359
|
+
List(items) { item in
|
|
360
|
+
NavigationLink(value: item) {
|
|
361
|
+
Text(item.title)
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
.navigationDestination(for: Item.self) { item in
|
|
365
|
+
DetailView(item: item)
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
let sample = "NavigationLink(destination: DetailView())"
|
|
369
|
+
// NavigationLink { DetailView() } label: { Text("Open") }
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
`;
|
|
373
|
+
|
|
374
|
+
assert.equal(hasSwiftUntypedNavigationLinkDestinationUsage(source), true);
|
|
375
|
+
assert.equal(hasSwiftUntypedNavigationLinkDestinationUsage(trailing), true);
|
|
376
|
+
assert.equal(hasSwiftUntypedNavigationLinkDestinationUsage(safe), false);
|
|
377
|
+
});
|
|
378
|
+
|
|
294
379
|
test('hasSwiftForceTryUsage detecta try! y descarta try?', () => {
|
|
295
380
|
const positive = `
|
|
296
381
|
func load() {
|
|
@@ -849,6 +849,10 @@ export const hasSwiftForEachIndicesUsage = (source: string): boolean => {
|
|
|
849
849
|
);
|
|
850
850
|
};
|
|
851
851
|
|
|
852
|
+
export const hasSwiftForEachSelfIdentityUsage = (source: string): boolean => {
|
|
853
|
+
return hasSwiftSanitizedRegexMatch(source, /\bForEach\s*\([^)]*\bid\s*:\s*\\\.self\b/g);
|
|
854
|
+
};
|
|
855
|
+
|
|
852
856
|
export const hasSwiftInlineForEachTransformUsage = (source: string): boolean => {
|
|
853
857
|
const sanitized = sanitizeSwiftSourceForMultilineRegex(source);
|
|
854
858
|
return /\bForEach\s*\(\s*(?:Array\s*\(\s*)?[A-Za-z_][A-Za-z0-9_]*(?:\.[A-Za-z_][A-Za-z0-9_]*)*\s*\.\s*(?:filter|map|compactMap|sorted)\s*(?:\{|\()/g.test(
|
|
@@ -1017,6 +1021,15 @@ export const hasSwiftNavigationViewUsage = (source: string): boolean => {
|
|
|
1017
1021
|
});
|
|
1018
1022
|
};
|
|
1019
1023
|
|
|
1024
|
+
export const hasSwiftUntypedNavigationLinkDestinationUsage = (source: string): boolean => {
|
|
1025
|
+
const swiftSource = sanitizeSwiftSourceForMultilineRegex(source);
|
|
1026
|
+
const destinationParameterPattern = /\bNavigationLink\s*\([^)]*\bdestination\s*:/;
|
|
1027
|
+
const trailingDestinationPattern =
|
|
1028
|
+
/\bNavigationLink\s*\{[\s\S]{0,900}\b[A-Z][A-Za-z0-9_]*View\s*\([^}]*\)[\s\S]{0,900}\}\s*label\s*:/;
|
|
1029
|
+
|
|
1030
|
+
return destinationParameterPattern.test(swiftSource) || trailingDestinationPattern.test(swiftSource);
|
|
1031
|
+
};
|
|
1032
|
+
|
|
1020
1033
|
export const hasSwiftForegroundColorUsage = (source: string): boolean => {
|
|
1021
1034
|
return hasSwiftUiModernizationSnapshotMatch(source, 'foreground-color');
|
|
1022
1035
|
};
|
|
@@ -678,6 +678,7 @@ const textDetectorRegistry: ReadonlyArray<TextDetectorRegistryEntry> = [
|
|
|
678
678
|
{ platform: 'ios', pathCheck: isIOSPresentationPath, excludePaths: [isSwiftTestPath], detect: TextIOS.hasSwiftNonPrivateStateOwnershipUsage, ruleId: 'heuristics.ios.swiftui.non-private-state-ownership.ast', code: 'HEURISTICS_IOS_SWIFTUI_NON_PRIVATE_STATE_OWNERSHIP_AST', message: 'AST heuristic detected @State/@StateObject without private visibility; SwiftUI owned state should be private.' },
|
|
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
|
+
{ platform: 'ios', pathCheck: isIOSPresentationPath, excludePaths: [isSwiftTestPath], detect: TextIOS.hasSwiftForEachSelfIdentityUsage, ruleId: 'heuristics.ios.swiftui.foreach-self-identity.ast', code: 'HEURISTICS_IOS_SWIFTUI_FOREACH_SELF_IDENTITY_AST', message: 'AST heuristic detected ForEach(..., id: \.self) usage; prefer a stable domain identity such as id: \.id or Identifiable models.' },
|
|
681
682
|
{ 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
683
|
{ 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.' },
|
|
683
684
|
{ 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.' },
|
|
@@ -691,6 +692,7 @@ const textDetectorRegistry: ReadonlyArray<TextDetectorRegistryEntry> = [
|
|
|
691
692
|
{ 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
693
|
{ 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.' },
|
|
693
694
|
{ 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.' },
|
|
695
|
+
{ platform: 'ios', pathCheck: isIOSPresentationPath, excludePaths: [isSwiftTestPath], detect: TextIOS.hasSwiftUntypedNavigationLinkDestinationUsage, ruleId: 'heuristics.ios.swiftui.untyped-navigation-link-destination.ast', code: 'HEURISTICS_IOS_SWIFTUI_UNTYPED_NAVIGATION_LINK_DESTINATION_AST', message: 'AST heuristic detected untyped NavigationLink destination usage; prefer NavigationLink(value:) with navigationDestination(for:) for type-safe navigation.' },
|
|
694
696
|
{ 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.' },
|
|
695
697
|
{ 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.' },
|
|
696
698
|
{ platform: 'ios', pathCheck: isIOSSwiftPath, excludePaths: [isSwiftTestPath], detect: TextIOS.hasSwiftTabItemUsage, ruleId: 'heuristics.ios.tab-item.ast', code: 'HEURISTICS_IOS_TAB_ITEM_AST', message: 'AST heuristic detected tabItem usage.' },
|
|
@@ -785,6 +785,25 @@ export const iosRules: RuleSet = [
|
|
|
785
785
|
code: 'HEURISTICS_IOS_FOREACH_INDICES_AST',
|
|
786
786
|
},
|
|
787
787
|
},
|
|
788
|
+
{
|
|
789
|
+
id: 'heuristics.ios.swiftui.foreach-self-identity.ast',
|
|
790
|
+
description: 'Detects SwiftUI ForEach usage with id: \.self instead of stable domain identity.',
|
|
791
|
+
severity: 'WARN',
|
|
792
|
+
platform: 'ios',
|
|
793
|
+
locked: true,
|
|
794
|
+
when: {
|
|
795
|
+
kind: 'Heuristic',
|
|
796
|
+
where: {
|
|
797
|
+
ruleId: 'heuristics.ios.swiftui.foreach-self-identity.ast',
|
|
798
|
+
},
|
|
799
|
+
},
|
|
800
|
+
then: {
|
|
801
|
+
kind: 'Finding',
|
|
802
|
+
message:
|
|
803
|
+
'AST heuristic detected ForEach(..., id: \.self) usage; prefer a stable domain identity such as id: \.id or Identifiable models.',
|
|
804
|
+
code: 'HEURISTICS_IOS_SWIFTUI_FOREACH_SELF_IDENTITY_AST',
|
|
805
|
+
},
|
|
806
|
+
},
|
|
788
807
|
{
|
|
789
808
|
id: 'heuristics.ios.swiftui.inline-foreach-transform.ast',
|
|
790
809
|
description: 'Detects inline filter/map/sort transformations inside SwiftUI ForEach calls.',
|
|
@@ -1024,6 +1043,25 @@ export const iosRules: RuleSet = [
|
|
|
1024
1043
|
code: 'HEURISTICS_IOS_NAVIGATION_VIEW_AST',
|
|
1025
1044
|
},
|
|
1026
1045
|
},
|
|
1046
|
+
{
|
|
1047
|
+
id: 'heuristics.ios.swiftui.untyped-navigation-link-destination.ast',
|
|
1048
|
+
description: 'Detects untyped SwiftUI NavigationLink destination usage.',
|
|
1049
|
+
severity: 'WARN',
|
|
1050
|
+
platform: 'ios',
|
|
1051
|
+
locked: true,
|
|
1052
|
+
when: {
|
|
1053
|
+
kind: 'Heuristic',
|
|
1054
|
+
where: {
|
|
1055
|
+
ruleId: 'heuristics.ios.swiftui.untyped-navigation-link-destination.ast',
|
|
1056
|
+
},
|
|
1057
|
+
},
|
|
1058
|
+
then: {
|
|
1059
|
+
kind: 'Finding',
|
|
1060
|
+
message:
|
|
1061
|
+
'AST heuristic detected untyped NavigationLink destination usage; prefer NavigationLink(value:) with navigationDestination(for:) for type-safe navigation.',
|
|
1062
|
+
code: 'HEURISTICS_IOS_SWIFTUI_UNTYPED_NAVIGATION_LINK_DESTINATION_AST',
|
|
1063
|
+
},
|
|
1064
|
+
},
|
|
1027
1065
|
{
|
|
1028
1066
|
id: 'heuristics.ios.foreground-color.ast',
|
|
1029
1067
|
description: 'Detects foregroundColor usage in modern SwiftUI code paths.',
|
|
@@ -211,6 +211,10 @@ const registryByRuleId: Record<string, SkillsDetectorBinding> = {
|
|
|
211
211
|
'skills.ios.no-navigation-view': heuristicDetector('ios.navigation-view', [
|
|
212
212
|
'heuristics.ios.navigation-view.ast',
|
|
213
213
|
]),
|
|
214
|
+
'skills.ios.guideline.ios-swiftui-expert.use-navigationdestination-for-for-type-safe-navigation':
|
|
215
|
+
heuristicDetector('ios.swiftui.untyped-navigation-link-destination', [
|
|
216
|
+
'heuristics.ios.swiftui.untyped-navigation-link-destination.ast',
|
|
217
|
+
]),
|
|
214
218
|
'skills.ios.no-foreground-color': heuristicDetector('ios.foreground-color', [
|
|
215
219
|
'heuristics.ios.foreground-color.ast',
|
|
216
220
|
]),
|
|
@@ -229,6 +233,14 @@ const registryByRuleId: Record<string, SkillsDetectorBinding> = {
|
|
|
229
233
|
'skills.ios.no-foreach-indices': heuristicDetector('ios.foreach-indices', [
|
|
230
234
|
'heuristics.ios.foreach-indices.ast',
|
|
231
235
|
]),
|
|
236
|
+
'skills.ios.guideline.ios-swiftui-expert.ensure-foreach-uses-stable-identity-see-references-list-patterns-md':
|
|
237
|
+
heuristicDetector('ios.swiftui.foreach-self-identity', [
|
|
238
|
+
'heuristics.ios.swiftui.foreach-self-identity.ast',
|
|
239
|
+
]),
|
|
240
|
+
'skills.ios.guideline.ios-swiftui-expert.verify-list-patterns-use-stable-identity-see-references-list-patterns-':
|
|
241
|
+
heuristicDetector('ios.swiftui.foreach-self-identity', [
|
|
242
|
+
'heuristics.ios.swiftui.foreach-self-identity.ast',
|
|
243
|
+
]),
|
|
232
244
|
'skills.ios.guideline.ios-swiftui-expert.avoid-inline-filtering-in-foreach-prefilter-and-cache':
|
|
233
245
|
heuristicDetector('ios.swiftui.inline-foreach-transform', [
|
|
234
246
|
'heuristics.ios.swiftui.inline-foreach-transform.ast',
|
|
@@ -277,6 +277,13 @@ const normalizeKnownRuleTarget = (
|
|
|
277
277
|
if (includes('navigationview') || includes('navigation view')) {
|
|
278
278
|
return 'skills.ios.no-navigation-view';
|
|
279
279
|
}
|
|
280
|
+
if (
|
|
281
|
+
includes('navigationdestination for') ||
|
|
282
|
+
(includes('navigationdestination') && includes('type safe navigation')) ||
|
|
283
|
+
(includes('navigationlink') && includes('value') && includes('navigationdestination'))
|
|
284
|
+
) {
|
|
285
|
+
return 'skills.ios.guideline.ios-swiftui-expert.use-navigationdestination-for-for-type-safe-navigation';
|
|
286
|
+
}
|
|
280
287
|
if (
|
|
281
288
|
includes('foregroundstyle instead of foregroundcolor') ||
|
|
282
289
|
includes('foregroundstyle over foregroundcolor') ||
|
|
@@ -309,6 +316,15 @@ const normalizeKnownRuleTarget = (
|
|
|
309
316
|
) {
|
|
310
317
|
return 'skills.ios.no-foreach-indices';
|
|
311
318
|
}
|
|
319
|
+
if (
|
|
320
|
+
(includes('foreach') && includes('stable identity')) ||
|
|
321
|
+
(includes('list patterns') && includes('stable identity'))
|
|
322
|
+
) {
|
|
323
|
+
if (includes('verify list patterns')) {
|
|
324
|
+
return 'skills.ios.guideline.ios-swiftui-expert.verify-list-patterns-use-stable-identity-see-references-list-patterns-';
|
|
325
|
+
}
|
|
326
|
+
return 'skills.ios.guideline.ios-swiftui-expert.ensure-foreach-uses-stable-identity-see-references-list-patterns-md';
|
|
327
|
+
}
|
|
312
328
|
if (
|
|
313
329
|
(includes('inline filtering') && includes('foreach')) ||
|
|
314
330
|
(includes('no inline filtering') && includes('foreach')) ||
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pumuki",
|
|
3
|
-
"version": "6.3.
|
|
3
|
+
"version": "6.3.230",
|
|
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:
|
|
4
|
+
"generatedAt": "2026-05-13T16:49:25.074Z",
|
|
5
5
|
"bundles": [
|
|
6
6
|
{
|
|
7
7
|
"name": "android-guidelines",
|
|
@@ -5764,8 +5764,20 @@
|
|
|
5764
5764
|
"name": "ios-guidelines",
|
|
5765
5765
|
"version": "1.0.0",
|
|
5766
5766
|
"source": "file:vendor/skills/ios-enterprise-rules/SKILL.md",
|
|
5767
|
-
"hash": "
|
|
5767
|
+
"hash": "a70065766533e822f2139da42d7933b6f240634c93939ee60969e3fd009409ce",
|
|
5768
5768
|
"rules": [
|
|
5769
|
+
{
|
|
5770
|
+
"id": "skills.ios.guideline.ios-swiftui-expert.use-navigationdestination-for-for-type-safe-navigation",
|
|
5771
|
+
"description": "navigationDestination(for:) - Destinos tipados",
|
|
5772
|
+
"severity": "WARN",
|
|
5773
|
+
"platform": "ios",
|
|
5774
|
+
"sourceSkill": "ios-guidelines",
|
|
5775
|
+
"sourcePath": "vendor/skills/ios-enterprise-rules/SKILL.md",
|
|
5776
|
+
"confidence": "MEDIUM",
|
|
5777
|
+
"locked": true,
|
|
5778
|
+
"evaluationMode": "AUTO",
|
|
5779
|
+
"origin": "core"
|
|
5780
|
+
},
|
|
5769
5781
|
{
|
|
5770
5782
|
"id": "skills.ios.guideline.ios-swiftui-expert.use-task-modifier-for-automatic-cancellation-of-async-work",
|
|
5771
5783
|
"description": ".task/.task(id:) - Trabajos async con cancelación automática",
|
|
@@ -7051,30 +7063,6 @@
|
|
|
7051
7063
|
"evaluationMode": "DECLARATIVE",
|
|
7052
7064
|
"origin": "core"
|
|
7053
7065
|
},
|
|
7054
|
-
{
|
|
7055
|
-
"id": "skills.ios.guideline.ios.navigationdestination-for-destinos-tipados",
|
|
7056
|
-
"description": "navigationDestination(for:) - Destinos tipados",
|
|
7057
|
-
"severity": "WARN",
|
|
7058
|
-
"platform": "ios",
|
|
7059
|
-
"sourceSkill": "ios-guidelines",
|
|
7060
|
-
"sourcePath": "vendor/skills/ios-enterprise-rules/SKILL.md",
|
|
7061
|
-
"confidence": "MEDIUM",
|
|
7062
|
-
"locked": true,
|
|
7063
|
-
"evaluationMode": "DECLARATIVE",
|
|
7064
|
-
"origin": "core"
|
|
7065
|
-
},
|
|
7066
|
-
{
|
|
7067
|
-
"id": "skills.ios.guideline.ios.navigationdestination-for-para-destinos",
|
|
7068
|
-
"description": "NavigationDestination(for:) para destinos",
|
|
7069
|
-
"severity": "WARN",
|
|
7070
|
-
"platform": "ios",
|
|
7071
|
-
"sourceSkill": "ios-guidelines",
|
|
7072
|
-
"sourcePath": "vendor/skills/ios-enterprise-rules/SKILL.md",
|
|
7073
|
-
"confidence": "MEDIUM",
|
|
7074
|
-
"locked": true,
|
|
7075
|
-
"evaluationMode": "DECLARATIVE",
|
|
7076
|
-
"origin": "core"
|
|
7077
|
-
},
|
|
7078
7066
|
{
|
|
7079
7067
|
"id": "skills.ios.guideline.ios.navigationstack-navigationpath-con-rutas-tipadas",
|
|
7080
7068
|
"description": "NavigationStack + NavigationPath con rutas tipadas",
|
|
@@ -8632,7 +8620,7 @@
|
|
|
8632
8620
|
"name": "ios-swiftui-expert-guidelines",
|
|
8633
8621
|
"version": "1.0.0",
|
|
8634
8622
|
"source": "file:vendor/skills/swiftui-expert-skill/SKILL.md",
|
|
8635
|
-
"hash": "
|
|
8623
|
+
"hash": "71169779d2e497e74027e271cc9ada00eb269509218964df2a2ff798b9a63f93",
|
|
8636
8624
|
"rules": [
|
|
8637
8625
|
{
|
|
8638
8626
|
"id": "skills.ios.guideline.ios-swiftui-expert.action-handlers-should-reference-methods-not-contain-inline-logic",
|
|
@@ -8703,7 +8691,7 @@
|
|
|
8703
8691
|
"sourcePath": "vendor/skills/swiftui-expert-skill/SKILL.md",
|
|
8704
8692
|
"confidence": "MEDIUM",
|
|
8705
8693
|
"locked": true,
|
|
8706
|
-
"evaluationMode": "
|
|
8694
|
+
"evaluationMode": "AUTO",
|
|
8707
8695
|
"origin": "core"
|
|
8708
8696
|
},
|
|
8709
8697
|
{
|
|
@@ -8895,7 +8883,7 @@
|
|
|
8895
8883
|
"sourcePath": "vendor/skills/swiftui-expert-skill/SKILL.md",
|
|
8896
8884
|
"confidence": "MEDIUM",
|
|
8897
8885
|
"locked": true,
|
|
8898
|
-
"evaluationMode": "
|
|
8886
|
+
"evaluationMode": "AUTO",
|
|
8899
8887
|
"origin": "core"
|
|
8900
8888
|
},
|
|
8901
8889
|
{
|
|
@@ -8991,7 +8979,7 @@
|
|
|
8991
8979
|
"sourcePath": "vendor/skills/swiftui-expert-skill/SKILL.md",
|
|
8992
8980
|
"confidence": "MEDIUM",
|
|
8993
8981
|
"locked": true,
|
|
8994
|
-
"evaluationMode": "
|
|
8982
|
+
"evaluationMode": "AUTO",
|
|
8995
8983
|
"origin": "core"
|
|
8996
8984
|
},
|
|
8997
8985
|
{
|