pumuki 6.3.221 → 6.3.222
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 +29 -0
- package/core/facts/detectors/text/ios.ts +7 -0
- package/core/facts/extractHeuristicFacts.ts +1 -0
- package/core/rules/presets/heuristics/ios.ts +18 -0
- package/integrations/config/skillsDetectorRegistry.ts +4 -0
- package/integrations/config/skillsMarkdownRules.ts +7 -0
- package/package.json +1 -1
- package/skills.lock.json +3 -3
|
@@ -62,6 +62,7 @@ import {
|
|
|
62
62
|
hasSwiftInsecureTransportUsage,
|
|
63
63
|
hasSwiftJSONSerializationUsage,
|
|
64
64
|
hasSwiftExplicitColorStaticMemberUsage,
|
|
65
|
+
hasSwiftClosureBasedViewBuilderContentUsage,
|
|
65
66
|
hasSwiftInlineForEachTransformUsage,
|
|
66
67
|
hasSwiftStringFormatUsage,
|
|
67
68
|
hasSwiftStrongDelegateReferenceUsage,
|
|
@@ -735,6 +736,7 @@ GeometryReader { proxy in
|
|
|
735
736
|
}
|
|
736
737
|
Text("Headline").fontWeight(.bold)
|
|
737
738
|
Text("State").foregroundStyle(Color.green)
|
|
739
|
+
let content: () -> Content
|
|
738
740
|
let filtered = items.filter { $0.title.contains(searchText) }
|
|
739
741
|
ForEach(items.indices, id: \\.self) { index in
|
|
740
742
|
Text(items[index].title)
|
|
@@ -782,6 +784,7 @@ MainActor.assumeIsolated { reload() }
|
|
|
782
784
|
assert.equal(hasSwiftGeometryReaderUsage(source), true);
|
|
783
785
|
assert.equal(hasSwiftFontWeightBoldUsage(source), true);
|
|
784
786
|
assert.equal(hasSwiftExplicitColorStaticMemberUsage(source), true);
|
|
787
|
+
assert.equal(hasSwiftClosureBasedViewBuilderContentUsage(source), true);
|
|
785
788
|
assert.equal(hasSwiftObservableObjectUsage(source), true);
|
|
786
789
|
assert.equal(hasSwiftLegacySwiftUiObservableWrapperUsage(source), true);
|
|
787
790
|
assert.equal(hasSwiftNavigationViewUsage(source), true);
|
|
@@ -822,6 +825,7 @@ let s = "nonisolated(unsafe) static var sharedBridge: Model?"
|
|
|
822
825
|
let t = "MainActor.assumeIsolated { reload() }"
|
|
823
826
|
let u = "ForEach(items.filter { $0.isVisible }) { item in }"
|
|
824
827
|
let v = "Color.green"
|
|
828
|
+
let w = "let content: () -> Content"
|
|
825
829
|
`;
|
|
826
830
|
assert.equal(hasSwiftPreconcurrencyUsage(source), false);
|
|
827
831
|
assert.equal(hasSwiftNonisolatedUnsafeUsage(source), false);
|
|
@@ -832,6 +836,7 @@ let v = "Color.green"
|
|
|
832
836
|
assert.equal(hasSwiftGeometryReaderUsage(source), false);
|
|
833
837
|
assert.equal(hasSwiftFontWeightBoldUsage(source), false);
|
|
834
838
|
assert.equal(hasSwiftExplicitColorStaticMemberUsage(source), false);
|
|
839
|
+
assert.equal(hasSwiftClosureBasedViewBuilderContentUsage(source), false);
|
|
835
840
|
assert.equal(hasSwiftTaskDetachedUsage(source), false);
|
|
836
841
|
assert.equal(hasSwiftNavigationViewUsage(source), false);
|
|
837
842
|
assert.equal(hasSwiftForegroundColorUsage(source), false);
|
|
@@ -850,6 +855,7 @@ test('detectores snapshot SwiftUI ignoran reemplazos modernos', () => {
|
|
|
850
855
|
const source = `
|
|
851
856
|
Text("Primary").foregroundStyle(.blue)
|
|
852
857
|
Text("State").foregroundStyle(.green)
|
|
858
|
+
@ViewBuilder let content: Content
|
|
853
859
|
Image("hero").clipShape(.rect(cornerRadius: 12))
|
|
854
860
|
Text("Headline").bold()
|
|
855
861
|
TabView {
|
|
@@ -884,6 +890,7 @@ ScrollView {
|
|
|
884
890
|
assert.equal(hasSwiftGeometryReaderUsage(source), false);
|
|
885
891
|
assert.equal(hasSwiftFontWeightBoldUsage(source), false);
|
|
886
892
|
assert.equal(hasSwiftExplicitColorStaticMemberUsage(source), false);
|
|
893
|
+
assert.equal(hasSwiftClosureBasedViewBuilderContentUsage(source), false);
|
|
887
894
|
assert.equal(hasSwiftForegroundColorUsage(source), false);
|
|
888
895
|
assert.equal(hasSwiftCornerRadiusUsage(source), false);
|
|
889
896
|
assert.equal(hasSwiftTabItemUsage(source), false);
|
|
@@ -917,6 +924,28 @@ let ignored = "Color.green"
|
|
|
917
924
|
assert.equal(hasSwiftExplicitColorStaticMemberUsage(safe), false);
|
|
918
925
|
});
|
|
919
926
|
|
|
927
|
+
test('hasSwiftClosureBasedViewBuilderContentUsage detecta content closure y preserva @ViewBuilder let content', () => {
|
|
928
|
+
const source = `
|
|
929
|
+
struct Card<Content: View>: View {
|
|
930
|
+
private let content: () -> Content
|
|
931
|
+
|
|
932
|
+
init(@ViewBuilder content: @escaping () -> Content) {
|
|
933
|
+
self.content = content
|
|
934
|
+
}
|
|
935
|
+
}
|
|
936
|
+
`;
|
|
937
|
+
const safe = `
|
|
938
|
+
struct Card<Content: View>: View {
|
|
939
|
+
@ViewBuilder let content: Content
|
|
940
|
+
}
|
|
941
|
+
let ignored = "let content: () -> Content"
|
|
942
|
+
// let content: () -> Content
|
|
943
|
+
`;
|
|
944
|
+
|
|
945
|
+
assert.equal(hasSwiftClosureBasedViewBuilderContentUsage(source), true);
|
|
946
|
+
assert.equal(hasSwiftClosureBasedViewBuilderContentUsage(safe), false);
|
|
947
|
+
});
|
|
948
|
+
|
|
920
949
|
test('hasSwiftLegacyXCTestImportUsage detecta XCTest unitario y excluye UI/performance', () => {
|
|
921
950
|
const unitTest = `
|
|
922
951
|
import XCTest
|
|
@@ -870,6 +870,13 @@ export const hasSwiftExplicitColorStaticMemberUsage = (source: string): boolean
|
|
|
870
870
|
);
|
|
871
871
|
};
|
|
872
872
|
|
|
873
|
+
export const hasSwiftClosureBasedViewBuilderContentUsage = (source: string): boolean => {
|
|
874
|
+
return hasSwiftSanitizedRegexMatch(
|
|
875
|
+
source,
|
|
876
|
+
/\b(?:let|var)\s+content\s*:\s*(?:\(\s*\)\s*->|@\s*escaping\s*\(\s*\)\s*->)\s*(?:some\s+View|Content)\b/g
|
|
877
|
+
);
|
|
878
|
+
};
|
|
879
|
+
|
|
873
880
|
export const hasSwiftLegacySwiftUiObservableWrapperUsage = (source: string): boolean => {
|
|
874
881
|
return hasSwiftSanitizedRegexMatch(source, /@\s*(?:StateObject|ObservedObject)\b/);
|
|
875
882
|
};
|
|
@@ -683,6 +683,7 @@ const textDetectorRegistry: ReadonlyArray<TextDetectorRegistryEntry> = [
|
|
|
683
683
|
{ 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
684
|
{ 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.' },
|
|
685
685
|
{ platform: 'ios', pathCheck: isIOSPresentationPath, excludePaths: [isSwiftTestPath], detect: TextIOS.hasSwiftExplicitColorStaticMemberUsage, ruleId: 'heuristics.ios.swiftui.explicit-color-static-member.ast', code: 'HEURISTICS_IOS_SWIFTUI_EXPLICIT_COLOR_STATIC_MEMBER_AST', message: 'AST heuristic detected Color.* static member usage where SwiftUI static member lookup may be preferred.' },
|
|
686
|
+
{ platform: 'ios', pathCheck: isIOSPresentationPath, excludePaths: [isSwiftTestPath], detect: TextIOS.hasSwiftClosureBasedViewBuilderContentUsage, ruleId: 'heuristics.ios.swiftui.closure-based-viewbuilder-content.ast', code: 'HEURISTICS_IOS_SWIFTUI_CLOSURE_BASED_VIEWBUILDER_CONTENT_AST', message: 'AST heuristic detected closure-based content storage; @ViewBuilder let content: Content remains the preferred SwiftUI container baseline.' },
|
|
686
687
|
{ 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.' },
|
|
687
688
|
{ 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.' },
|
|
688
689
|
{ 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.' },
|
|
@@ -875,6 +875,24 @@ export const iosRules: RuleSet = [
|
|
|
875
875
|
code: 'HEURISTICS_IOS_SWIFTUI_EXPLICIT_COLOR_STATIC_MEMBER_AST',
|
|
876
876
|
},
|
|
877
877
|
},
|
|
878
|
+
{
|
|
879
|
+
id: 'heuristics.ios.swiftui.closure-based-viewbuilder-content.ast',
|
|
880
|
+
description: 'Detects closure-based SwiftUI content properties where @ViewBuilder let content: Content is preferred.',
|
|
881
|
+
severity: 'WARN',
|
|
882
|
+
platform: 'ios',
|
|
883
|
+
locked: true,
|
|
884
|
+
when: {
|
|
885
|
+
kind: 'Heuristic',
|
|
886
|
+
where: {
|
|
887
|
+
ruleId: 'heuristics.ios.swiftui.closure-based-viewbuilder-content.ast',
|
|
888
|
+
},
|
|
889
|
+
},
|
|
890
|
+
then: {
|
|
891
|
+
kind: 'Finding',
|
|
892
|
+
message: 'AST heuristic detected closure-based content storage; @ViewBuilder let content: Content remains the preferred SwiftUI container baseline.',
|
|
893
|
+
code: 'HEURISTICS_IOS_SWIFTUI_CLOSURE_BASED_VIEWBUILDER_CONTENT_AST',
|
|
894
|
+
},
|
|
895
|
+
},
|
|
878
896
|
{
|
|
879
897
|
id: 'heuristics.ios.navigation-view.ast',
|
|
880
898
|
description: 'Detects NavigationView usage in iOS production code.',
|
|
@@ -246,6 +246,10 @@ const registryByRuleId: Record<string, SkillsDetectorBinding> = {
|
|
|
246
246
|
heuristicDetector('ios.swiftui.explicit-color-static-member', [
|
|
247
247
|
'heuristics.ios.swiftui.explicit-color-static-member.ast',
|
|
248
248
|
]),
|
|
249
|
+
'skills.ios.guideline.ios-swiftui-expert.prefer-viewbuilder-let-content-content-over-closure-based-content-prop':
|
|
250
|
+
heuristicDetector('ios.swiftui.closure-based-viewbuilder-content', [
|
|
251
|
+
'heuristics.ios.swiftui.closure-based-viewbuilder-content.ast',
|
|
252
|
+
]),
|
|
249
253
|
'skills.ios.no-scrollview-shows-indicators': heuristicDetector(
|
|
250
254
|
'ios.scrollview-shows-indicators',
|
|
251
255
|
['heuristics.ios.scrollview-shows-indicators.ast']
|
|
@@ -346,6 +346,13 @@ const normalizeKnownRuleTarget = (
|
|
|
346
346
|
) {
|
|
347
347
|
return 'skills.ios.guideline.ios-swiftui-expert.prefer-static-member-lookup-blue-vs-color-blue';
|
|
348
348
|
}
|
|
349
|
+
if (
|
|
350
|
+
includes('viewbuilder let content') ||
|
|
351
|
+
(includes('closure-based content') && includes('content')) ||
|
|
352
|
+
(includes('content: content') && includes('viewbuilder'))
|
|
353
|
+
) {
|
|
354
|
+
return 'skills.ios.guideline.ios-swiftui-expert.prefer-viewbuilder-let-content-content-over-closure-based-content-prop';
|
|
355
|
+
}
|
|
349
356
|
if (
|
|
350
357
|
includes('scrollindicators hidden') ||
|
|
351
358
|
includes('scroll indicators hidden') ||
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pumuki",
|
|
3
|
-
"version": "6.3.
|
|
3
|
+
"version": "6.3.222",
|
|
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:04:37.359Z",
|
|
5
5
|
"bundles": [
|
|
6
6
|
{
|
|
7
7
|
"name": "android-guidelines",
|
|
@@ -8632,7 +8632,7 @@
|
|
|
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": "
|
|
8635
|
+
"hash": "938525eec7fea70ecba6c27711800036b964e4b668f80b177cc918cb268e08c5",
|
|
8636
8636
|
"rules": [
|
|
8637
8637
|
{
|
|
8638
8638
|
"id": "skills.ios.guideline.ios-swiftui-expert.always-mark-state-and-stateobject-as-private-makes-dependencies-clear",
|
|
@@ -8727,7 +8727,7 @@
|
|
|
8727
8727
|
"sourcePath": "vendor/skills/swiftui-expert-skill/SKILL.md",
|
|
8728
8728
|
"confidence": "MEDIUM",
|
|
8729
8729
|
"locked": true,
|
|
8730
|
-
"evaluationMode": "
|
|
8730
|
+
"evaluationMode": "AUTO",
|
|
8731
8731
|
"origin": "core"
|
|
8732
8732
|
},
|
|
8733
8733
|
{
|