pumuki 6.3.220 → 6.3.221
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 +32 -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
|
@@ -61,6 +61,7 @@ import {
|
|
|
61
61
|
hasSwiftSensitiveUserDefaultsStorageUsage,
|
|
62
62
|
hasSwiftInsecureTransportUsage,
|
|
63
63
|
hasSwiftJSONSerializationUsage,
|
|
64
|
+
hasSwiftExplicitColorStaticMemberUsage,
|
|
64
65
|
hasSwiftInlineForEachTransformUsage,
|
|
65
66
|
hasSwiftStringFormatUsage,
|
|
66
67
|
hasSwiftStrongDelegateReferenceUsage,
|
|
@@ -733,6 +734,7 @@ GeometryReader { proxy in
|
|
|
733
734
|
Text("x").frame(width: proxy.size.width)
|
|
734
735
|
}
|
|
735
736
|
Text("Headline").fontWeight(.bold)
|
|
737
|
+
Text("State").foregroundStyle(Color.green)
|
|
736
738
|
let filtered = items.filter { $0.title.contains(searchText) }
|
|
737
739
|
ForEach(items.indices, id: \\.self) { index in
|
|
738
740
|
Text(items[index].title)
|
|
@@ -779,6 +781,7 @@ MainActor.assumeIsolated { reload() }
|
|
|
779
781
|
assert.equal(hasSwiftContainsUserFilterUsage(source), true);
|
|
780
782
|
assert.equal(hasSwiftGeometryReaderUsage(source), true);
|
|
781
783
|
assert.equal(hasSwiftFontWeightBoldUsage(source), true);
|
|
784
|
+
assert.equal(hasSwiftExplicitColorStaticMemberUsage(source), true);
|
|
782
785
|
assert.equal(hasSwiftObservableObjectUsage(source), true);
|
|
783
786
|
assert.equal(hasSwiftLegacySwiftUiObservableWrapperUsage(source), true);
|
|
784
787
|
assert.equal(hasSwiftNavigationViewUsage(source), true);
|
|
@@ -818,6 +821,7 @@ let r = "@preconcurrency import LegacyFramework"
|
|
|
818
821
|
let s = "nonisolated(unsafe) static var sharedBridge: Model?"
|
|
819
822
|
let t = "MainActor.assumeIsolated { reload() }"
|
|
820
823
|
let u = "ForEach(items.filter { $0.isVisible }) { item in }"
|
|
824
|
+
let v = "Color.green"
|
|
821
825
|
`;
|
|
822
826
|
assert.equal(hasSwiftPreconcurrencyUsage(source), false);
|
|
823
827
|
assert.equal(hasSwiftNonisolatedUnsafeUsage(source), false);
|
|
@@ -827,6 +831,7 @@ let u = "ForEach(items.filter { $0.isVisible }) { item in }"
|
|
|
827
831
|
assert.equal(hasSwiftContainsUserFilterUsage(source), false);
|
|
828
832
|
assert.equal(hasSwiftGeometryReaderUsage(source), false);
|
|
829
833
|
assert.equal(hasSwiftFontWeightBoldUsage(source), false);
|
|
834
|
+
assert.equal(hasSwiftExplicitColorStaticMemberUsage(source), false);
|
|
830
835
|
assert.equal(hasSwiftTaskDetachedUsage(source), false);
|
|
831
836
|
assert.equal(hasSwiftNavigationViewUsage(source), false);
|
|
832
837
|
assert.equal(hasSwiftForegroundColorUsage(source), false);
|
|
@@ -844,6 +849,7 @@ let u = "ForEach(items.filter { $0.isVisible }) { item in }"
|
|
|
844
849
|
test('detectores snapshot SwiftUI ignoran reemplazos modernos', () => {
|
|
845
850
|
const source = `
|
|
846
851
|
Text("Primary").foregroundStyle(.blue)
|
|
852
|
+
Text("State").foregroundStyle(.green)
|
|
847
853
|
Image("hero").clipShape(.rect(cornerRadius: 12))
|
|
848
854
|
Text("Headline").bold()
|
|
849
855
|
TabView {
|
|
@@ -877,6 +883,7 @@ ScrollView {
|
|
|
877
883
|
assert.equal(hasSwiftContainsUserFilterUsage(source), false);
|
|
878
884
|
assert.equal(hasSwiftGeometryReaderUsage(source), false);
|
|
879
885
|
assert.equal(hasSwiftFontWeightBoldUsage(source), false);
|
|
886
|
+
assert.equal(hasSwiftExplicitColorStaticMemberUsage(source), false);
|
|
880
887
|
assert.equal(hasSwiftForegroundColorUsage(source), false);
|
|
881
888
|
assert.equal(hasSwiftCornerRadiusUsage(source), false);
|
|
882
889
|
assert.equal(hasSwiftTabItemUsage(source), false);
|
|
@@ -885,6 +892,31 @@ ScrollView {
|
|
|
885
892
|
assert.equal(hasSwiftLegacyOnChangeUsage(source), false);
|
|
886
893
|
});
|
|
887
894
|
|
|
895
|
+
test('hasSwiftExplicitColorStaticMemberUsage detecta Color.* y preserva static member lookup', () => {
|
|
896
|
+
const source = `
|
|
897
|
+
struct StatusView: View {
|
|
898
|
+
var body: some View {
|
|
899
|
+
Text("Ready").foregroundStyle(Color.green)
|
|
900
|
+
Circle().fill(Color.primary)
|
|
901
|
+
}
|
|
902
|
+
}
|
|
903
|
+
`;
|
|
904
|
+
const safe = `
|
|
905
|
+
struct StatusView: View {
|
|
906
|
+
var body: some View {
|
|
907
|
+
Text("Ready").foregroundStyle(.green)
|
|
908
|
+
Circle().fill(.primary)
|
|
909
|
+
Rectangle().fill(Color("BrandPrimary"))
|
|
910
|
+
}
|
|
911
|
+
}
|
|
912
|
+
let ignored = "Color.green"
|
|
913
|
+
// Color.primary
|
|
914
|
+
`;
|
|
915
|
+
|
|
916
|
+
assert.equal(hasSwiftExplicitColorStaticMemberUsage(source), true);
|
|
917
|
+
assert.equal(hasSwiftExplicitColorStaticMemberUsage(safe), false);
|
|
918
|
+
});
|
|
919
|
+
|
|
888
920
|
test('hasSwiftLegacyXCTestImportUsage detecta XCTest unitario y excluye UI/performance', () => {
|
|
889
921
|
const unitTest = `
|
|
890
922
|
import XCTest
|
|
@@ -863,6 +863,13 @@ export const hasSwiftFontWeightBoldUsage = (source: string): boolean => {
|
|
|
863
863
|
return hasSwiftSanitizedRegexMatch(source, /\.\s*fontWeight\s*\(\s*\.bold\s*\)/g);
|
|
864
864
|
};
|
|
865
865
|
|
|
866
|
+
export const hasSwiftExplicitColorStaticMemberUsage = (source: string): boolean => {
|
|
867
|
+
return hasSwiftSanitizedRegexMatch(
|
|
868
|
+
source,
|
|
869
|
+
/\bColor\s*\.\s*(?:accentColor|black|blue|brown|clear|cyan|gray|green|indigo|mint|orange|pink|primary|purple|red|secondary|teal|white|yellow)\b/g
|
|
870
|
+
);
|
|
871
|
+
};
|
|
872
|
+
|
|
866
873
|
export const hasSwiftLegacySwiftUiObservableWrapperUsage = (source: string): boolean => {
|
|
867
874
|
return hasSwiftSanitizedRegexMatch(source, /@\s*(?:StateObject|ObservedObject)\b/);
|
|
868
875
|
};
|
|
@@ -682,6 +682,7 @@ const textDetectorRegistry: ReadonlyArray<TextDetectorRegistryEntry> = [
|
|
|
682
682
|
{ 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
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
|
+
{ 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.' },
|
|
685
686
|
{ 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.' },
|
|
686
687
|
{ 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.' },
|
|
687
688
|
{ 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.' },
|
|
@@ -857,6 +857,24 @@ export const iosRules: RuleSet = [
|
|
|
857
857
|
code: 'HEURISTICS_IOS_FONT_WEIGHT_BOLD_AST',
|
|
858
858
|
},
|
|
859
859
|
},
|
|
860
|
+
{
|
|
861
|
+
id: 'heuristics.ios.swiftui.explicit-color-static-member.ast',
|
|
862
|
+
description: 'Detects Color.* static member usage where SwiftUI static member lookup is available.',
|
|
863
|
+
severity: 'WARN',
|
|
864
|
+
platform: 'ios',
|
|
865
|
+
locked: true,
|
|
866
|
+
when: {
|
|
867
|
+
kind: 'Heuristic',
|
|
868
|
+
where: {
|
|
869
|
+
ruleId: 'heuristics.ios.swiftui.explicit-color-static-member.ast',
|
|
870
|
+
},
|
|
871
|
+
},
|
|
872
|
+
then: {
|
|
873
|
+
kind: 'Finding',
|
|
874
|
+
message: 'AST heuristic detected Color.* static member usage where SwiftUI static member lookup may be preferred.',
|
|
875
|
+
code: 'HEURISTICS_IOS_SWIFTUI_EXPLICIT_COLOR_STATIC_MEMBER_AST',
|
|
876
|
+
},
|
|
877
|
+
},
|
|
860
878
|
{
|
|
861
879
|
id: 'heuristics.ios.navigation-view.ast',
|
|
862
880
|
description: 'Detects NavigationView usage in iOS production code.',
|
|
@@ -242,6 +242,10 @@ const registryByRuleId: Record<string, SkillsDetectorBinding> = {
|
|
|
242
242
|
'skills.ios.no-font-weight-bold': heuristicDetector('ios.font-weight-bold', [
|
|
243
243
|
'heuristics.ios.font-weight-bold.ast',
|
|
244
244
|
]),
|
|
245
|
+
'skills.ios.guideline.ios-swiftui-expert.prefer-static-member-lookup-blue-vs-color-blue':
|
|
246
|
+
heuristicDetector('ios.swiftui.explicit-color-static-member', [
|
|
247
|
+
'heuristics.ios.swiftui.explicit-color-static-member.ast',
|
|
248
|
+
]),
|
|
245
249
|
'skills.ios.no-scrollview-shows-indicators': heuristicDetector(
|
|
246
250
|
'ios.scrollview-shows-indicators',
|
|
247
251
|
['heuristics.ios.scrollview-shows-indicators.ast']
|
|
@@ -339,6 +339,13 @@ const normalizeKnownRuleTarget = (
|
|
|
339
339
|
) {
|
|
340
340
|
return 'skills.ios.no-font-weight-bold';
|
|
341
341
|
}
|
|
342
|
+
if (
|
|
343
|
+
includes('static member lookup') ||
|
|
344
|
+
includes('color.blue') ||
|
|
345
|
+
(includes('.blue') && includes('color'))
|
|
346
|
+
) {
|
|
347
|
+
return 'skills.ios.guideline.ios-swiftui-expert.prefer-static-member-lookup-blue-vs-color-blue';
|
|
348
|
+
}
|
|
342
349
|
if (
|
|
343
350
|
includes('scrollindicators hidden') ||
|
|
344
351
|
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.221",
|
|
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-
|
|
4
|
+
"generatedAt": "2026-05-13T16:00:47.572Z",
|
|
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": "50cdc96e8e5b03ef6709edea0cde8959344ce5a3c57dfc93fe39d03d5695b7aa",
|
|
8636
8636
|
"rules": [
|
|
8637
8637
|
{
|
|
8638
8638
|
"id": "skills.ios.guideline.ios-swiftui-expert.always-mark-state-and-stateobject-as-private-makes-dependencies-clear",
|
|
@@ -8715,7 +8715,7 @@
|
|
|
8715
8715
|
"sourcePath": "vendor/skills/swiftui-expert-skill/SKILL.md",
|
|
8716
8716
|
"confidence": "MEDIUM",
|
|
8717
8717
|
"locked": true,
|
|
8718
|
-
"evaluationMode": "
|
|
8718
|
+
"evaluationMode": "AUTO",
|
|
8719
8719
|
"origin": "core"
|
|
8720
8720
|
},
|
|
8721
8721
|
{
|