pumuki 6.3.340 → 6.3.341
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.
|
@@ -1129,6 +1129,53 @@ struct FeedView: View {
|
|
|
1129
1129
|
assert.equal(hasSwiftUiForEachConditionalViewCountUsage(safe), false);
|
|
1130
1130
|
});
|
|
1131
1131
|
|
|
1132
|
+
test('hasSwiftUiForEachConditionalViewCountUsage preserva filas ForEach extraidas con branching interno', () => {
|
|
1133
|
+
const source = `
|
|
1134
|
+
struct OnboardingCarouselView: View {
|
|
1135
|
+
let pages: [OnboardingPage]
|
|
1136
|
+
let indicators: [OnboardingIndicator]
|
|
1137
|
+
|
|
1138
|
+
var body: some View {
|
|
1139
|
+
LazyVStack {
|
|
1140
|
+
ForEach(pages) { page in
|
|
1141
|
+
OnboardingPageView(page: page)
|
|
1142
|
+
}
|
|
1143
|
+
LazyHStack {
|
|
1144
|
+
ForEach(indicators) { indicator in
|
|
1145
|
+
OnboardingPageIndicatorView(indicator: indicator)
|
|
1146
|
+
}
|
|
1147
|
+
}
|
|
1148
|
+
}
|
|
1149
|
+
}
|
|
1150
|
+
}
|
|
1151
|
+
|
|
1152
|
+
private struct OnboardingPageView: View {
|
|
1153
|
+
let page: OnboardingPage
|
|
1154
|
+
|
|
1155
|
+
var body: some View {
|
|
1156
|
+
switch page.kind {
|
|
1157
|
+
case .hero:
|
|
1158
|
+
OnboardingHeroStepView(page: page)
|
|
1159
|
+
case .feature:
|
|
1160
|
+
OnboardingFeatureStepView(page: page)
|
|
1161
|
+
}
|
|
1162
|
+
}
|
|
1163
|
+
}
|
|
1164
|
+
|
|
1165
|
+
private struct OnboardingPageIndicatorView: View {
|
|
1166
|
+
let indicator: OnboardingIndicator
|
|
1167
|
+
|
|
1168
|
+
var body: some View {
|
|
1169
|
+
Capsule()
|
|
1170
|
+
.fill(indicator.isSelected ? Color.primary : Color.secondary)
|
|
1171
|
+
}
|
|
1172
|
+
}
|
|
1173
|
+
`;
|
|
1174
|
+
|
|
1175
|
+
assert.equal(hasSwiftUiForEachConditionalViewCountUsage(source), false);
|
|
1176
|
+
assert.deepEqual(collectSwiftUiForEachConditionalViewCountLines(source), []);
|
|
1177
|
+
});
|
|
1178
|
+
|
|
1132
1179
|
test('hasSwiftViewBodyObjectCreationUsage detecta formatter creado en body y preserva dependencia externa', () => {
|
|
1133
1180
|
const source = `
|
|
1134
1181
|
struct PriceView: View {
|
|
@@ -2781,7 +2828,7 @@ struct StoresView: View {
|
|
|
2781
2828
|
assert.deepEqual(collectSwiftNonLazyScrollForEachLines(source), [4, 6, 11]);
|
|
2782
2829
|
assert.deepEqual(collectSwiftForEachIndicesLines(source), [6]);
|
|
2783
2830
|
assert.deepEqual(collectSwiftForEachSelfIdentityLines(source), [6]);
|
|
2784
|
-
assert.deepEqual(collectSwiftUiForEachConditionalViewCountLines(source), [6, 7
|
|
2831
|
+
assert.deepEqual(collectSwiftUiForEachConditionalViewCountLines(source), [6, 7]);
|
|
2785
2832
|
assert.deepEqual(collectSwiftInlineForEachTransformLines(source), [11]);
|
|
2786
2833
|
assert.deepEqual(collectSwiftUiConditionalSameViewIdentityLines(source), [7, 14, 20]);
|
|
2787
2834
|
assert.deepEqual(collectSwiftUiInlineActionLogicLines(source), [19]);
|
|
@@ -660,24 +660,99 @@ export const collectSwiftNonLazyScrollForEachLines = (source: string): readonly
|
|
|
660
660
|
]);
|
|
661
661
|
};
|
|
662
662
|
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
663
|
+
const findMatchingSwiftParen = (source: string, openParenIndex: number): number => {
|
|
664
|
+
let depth = 0;
|
|
665
|
+
for (let index = openParenIndex; index < source.length; index += 1) {
|
|
666
|
+
const current = source[index];
|
|
667
|
+
if (current === '(') {
|
|
668
|
+
depth += 1;
|
|
669
|
+
} else if (current === ')') {
|
|
670
|
+
depth -= 1;
|
|
671
|
+
if (depth === 0) {
|
|
672
|
+
return index;
|
|
673
|
+
}
|
|
674
|
+
}
|
|
675
|
+
}
|
|
676
|
+
return -1;
|
|
677
|
+
};
|
|
667
678
|
|
|
668
|
-
|
|
679
|
+
const getLineNumberAtIndex = (source: string, targetIndex: number): number => {
|
|
680
|
+
let lineNumber = 1;
|
|
681
|
+
for (let index = 0; index < targetIndex && index < source.length; index += 1) {
|
|
682
|
+
if (source[index] === '\n') {
|
|
683
|
+
lineNumber += 1;
|
|
684
|
+
}
|
|
685
|
+
}
|
|
686
|
+
return lineNumber;
|
|
687
|
+
};
|
|
688
|
+
|
|
689
|
+
const collectSwiftUiForEachDirectConditionalLines = (source: string): readonly number[] => {
|
|
690
|
+
const sanitized = sanitizeSwiftSourceForMultilineRegex(source);
|
|
691
|
+
const lines: number[] = [];
|
|
692
|
+
const forEachPattern = /\bForEach\s*\(/g;
|
|
693
|
+
|
|
694
|
+
for (const match of sanitized.matchAll(forEachPattern)) {
|
|
695
|
+
const matchIndex = match.index ?? 0;
|
|
696
|
+
const openParenIndex = sanitized.indexOf('(', matchIndex);
|
|
697
|
+
if (openParenIndex < 0) {
|
|
698
|
+
continue;
|
|
699
|
+
}
|
|
700
|
+
|
|
701
|
+
const closeParenIndex = findMatchingSwiftParen(sanitized, openParenIndex);
|
|
702
|
+
if (closeParenIndex < 0) {
|
|
703
|
+
continue;
|
|
704
|
+
}
|
|
705
|
+
|
|
706
|
+
const openBraceIndex = sanitized.indexOf('{', closeParenIndex);
|
|
707
|
+
if (openBraceIndex < 0) {
|
|
708
|
+
continue;
|
|
709
|
+
}
|
|
710
|
+
|
|
711
|
+
const closeBraceIndex = findMatchingSwiftBrace(sanitized, openBraceIndex);
|
|
712
|
+
if (closeBraceIndex < 0) {
|
|
713
|
+
continue;
|
|
714
|
+
}
|
|
715
|
+
|
|
716
|
+
const body = sanitized.slice(openBraceIndex + 1, closeBraceIndex);
|
|
717
|
+
let depth = 0;
|
|
718
|
+
let hasDirectConditional = false;
|
|
719
|
+
const conditionalPattern = /\b(?:if|switch)\b/g;
|
|
720
|
+
|
|
721
|
+
for (const conditionalMatch of body.matchAll(conditionalPattern)) {
|
|
722
|
+
const conditionalIndex = conditionalMatch.index ?? 0;
|
|
723
|
+
for (let index = 0; index < conditionalIndex; index += 1) {
|
|
724
|
+
const current = body[index];
|
|
725
|
+
if (current === '{') {
|
|
726
|
+
depth += 1;
|
|
727
|
+
} else if (current === '}') {
|
|
728
|
+
depth = Math.max(0, depth - 1);
|
|
729
|
+
}
|
|
730
|
+
}
|
|
731
|
+
if (depth === 0) {
|
|
732
|
+
lines.push(getLineNumberAtIndex(sanitized, matchIndex));
|
|
733
|
+
lines.push(getLineNumberAtIndex(sanitized, openBraceIndex + 1 + conditionalIndex));
|
|
734
|
+
hasDirectConditional = true;
|
|
735
|
+
break;
|
|
736
|
+
}
|
|
737
|
+
depth = 0;
|
|
738
|
+
}
|
|
739
|
+
|
|
740
|
+
if (!hasDirectConditional) {
|
|
741
|
+
continue;
|
|
742
|
+
}
|
|
743
|
+
}
|
|
744
|
+
|
|
745
|
+
return sortedUniqueLines(lines);
|
|
746
|
+
};
|
|
747
|
+
|
|
748
|
+
export const hasSwiftUiForEachConditionalViewCountUsage = (source: string): boolean => {
|
|
749
|
+
return collectSwiftUiForEachDirectConditionalLines(source).length > 0;
|
|
669
750
|
};
|
|
670
751
|
|
|
671
752
|
export const collectSwiftUiForEachConditionalViewCountLines = (
|
|
672
753
|
source: string
|
|
673
754
|
): readonly number[] => {
|
|
674
|
-
|
|
675
|
-
return [];
|
|
676
|
-
}
|
|
677
|
-
return sortedUniqueLines([
|
|
678
|
-
...collectSwiftRegexLines(source, /\bForEach\s*\(/),
|
|
679
|
-
...collectSwiftRegexLines(source, /\b(?:if|switch)\b/),
|
|
680
|
-
]);
|
|
755
|
+
return collectSwiftUiForEachDirectConditionalLines(source);
|
|
681
756
|
};
|
|
682
757
|
|
|
683
758
|
export const hasSwiftViewBodyObjectCreationUsage = (source: string): boolean => {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pumuki",
|
|
3
|
-
"version": "6.3.
|
|
3
|
+
"version": "6.3.341",
|
|
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": {
|