pumuki 6.3.172 → 6.3.174
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/AGENTS.md +1 -16
- package/CHANGELOG.md +0 -101
- package/README.md +10 -14
- package/VERSION +1 -1
- package/core/facts/detectors/text/android.test.ts +0 -2827
- package/core/facts/detectors/text/android.ts +182 -5121
- package/core/facts/detectors/text/ios.test.ts +12 -290
- package/core/facts/detectors/text/ios.ts +28 -301
- package/core/facts/detectors/typescript/index.test.ts +139 -3733
- package/core/facts/detectors/typescript/index.ts +264 -4959
- package/core/facts/extractHeuristicFacts.ts +11 -328
- package/core/gate/evaluateRules.test.ts +0 -7
- package/core/gate/evaluateRules.ts +2 -1
- package/core/rules/presets/heuristics/android.test.ts +1 -399
- package/core/rules/presets/heuristics/android.ts +1 -1481
- package/core/rules/presets/heuristics/ios.test.ts +1 -11
- package/core/rules/presets/heuristics/ios.ts +0 -36
- package/core/rules/presets/heuristics/typescript.test.ts +2 -158
- package/core/rules/presets/heuristics/typescript.ts +0 -508
- package/core/rules/presets/iosEnterpriseRuleSet.test.ts +0 -5
- package/core/rules/presets/iosEnterpriseRuleSet.ts +5 -5
- package/docs/README.md +3 -3
- package/docs/operations/RELEASE_NOTES.md +1 -94
- package/docs/operations/framework-menu-consumer-walkthrough.md +15 -18
- package/docs/product/API_REFERENCE.md +1 -1
- package/docs/product/CONFIGURATION.md +0 -7
- package/docs/product/USAGE.md +1 -1
- package/docs/validation/README.md +1 -3
- package/docs/validation/ios-avdlee-parity-matrix.md +1 -1
- package/integrations/config/skillsCompilerTemplates.test.ts +0 -145
- package/integrations/config/skillsCompilerTemplates.ts +2 -1013
- package/integrations/config/skillsDetectorRegistry.ts +8 -523
- package/integrations/config/skillsMarkdownRules.ts +8 -1088
- package/integrations/config/skillsRuleSet.ts +3 -44
- package/integrations/evidence/buildEvidence.ts +5 -34
- package/integrations/evidence/platformSummary.test.ts +9 -73
- package/integrations/evidence/platformSummary.ts +7 -165
- package/integrations/evidence/repoState.ts +0 -3
- package/integrations/evidence/rulesCoverage.ts +0 -83
- package/integrations/evidence/schema.ts +0 -29
- package/integrations/evidence/writeEvidence.test.ts +0 -4
- package/integrations/evidence/writeEvidence.ts +2 -41
- package/integrations/gate/evaluateAiGate.ts +8 -312
- package/integrations/gate/remediationCatalog.ts +2 -20
- package/integrations/gate/stagePolicies.ts +18 -24
- package/integrations/git/astIntelligenceDualValidation.ts +2 -2
- package/integrations/git/gitAtomicity.ts +39 -284
- package/integrations/git/resolveGitRefs.ts +6 -35
- package/integrations/git/runPlatformGate.ts +143 -512
- package/integrations/git/runPlatformGateOutput.ts +8 -13
- package/integrations/git/stageRunners.ts +41 -25
- package/integrations/lifecycle/adapter.ts +0 -24
- package/integrations/lifecycle/audit.ts +16 -14
- package/integrations/lifecycle/cli.ts +20 -37
- package/integrations/lifecycle/cliSdd.ts +3 -4
- package/integrations/lifecycle/doctor.ts +1 -1
- package/integrations/lifecycle/packageInfo.ts +1 -118
- package/integrations/lifecycle/policyReconcile.ts +4 -27
- package/integrations/lifecycle/preWriteAutomation.ts +5 -5
- package/integrations/lifecycle/state.ts +1 -8
- package/integrations/lifecycle/watch.ts +8 -28
- package/integrations/mcp/aiGateCheck.ts +10 -194
- package/integrations/mcp/autoExecuteAiStart.ts +4 -7
- package/integrations/mcp/enterpriseServer.ts +3 -19
- package/integrations/mcp/preFlightCheck.ts +10 -89
- package/integrations/policy/gitAtomicityEnforcement.ts +2 -2
- package/integrations/policy/heuristicsEnforcement.ts +2 -2
- package/integrations/policy/policyProfiles.ts +18 -24
- package/integrations/policy/preWriteEnforcement.ts +1 -1
- package/integrations/policy/sddCompletenessEnforcement.ts +2 -2
- package/integrations/policy/skillsEnforcement.ts +47 -1
- package/integrations/policy/tddBddEnforcement.ts +2 -2
- package/integrations/sdd/evidenceScaffold.ts +8 -124
- package/integrations/tdd/contract.ts +0 -1
- package/integrations/tdd/enforcement.ts +0 -103
- package/integrations/tdd/types.ts +0 -6
- package/package.json +1 -1
- package/scripts/check-tracking-single-active.sh +1 -1
- package/scripts/framework-menu-advanced-view-lib.ts +0 -49
- package/scripts/framework-menu-consumer-actions-lib.ts +32 -32
- package/scripts/framework-menu-consumer-preflight-render.ts +0 -10
- package/scripts/framework-menu-consumer-preflight-run.ts +5 -31
- package/scripts/framework-menu-consumer-preflight-types.ts +0 -12
- package/scripts/framework-menu-consumer-runtime-actions.ts +5 -11
- package/scripts/framework-menu-consumer-runtime-audit.ts +28 -0
- package/scripts/framework-menu-consumer-runtime-evidence-classic.ts +42 -118
- package/scripts/framework-menu-consumer-runtime-lib.ts +0 -38
- package/scripts/framework-menu-consumer-runtime-menu.ts +15 -55
- package/scripts/framework-menu-consumer-runtime-types.ts +0 -4
- package/scripts/framework-menu-evidence-summary-read.ts +1 -17
- package/scripts/framework-menu-evidence-summary-types.ts +0 -3
- package/scripts/framework-menu-layout-data.ts +23 -3
- package/scripts/framework-menu-system-notifications-cause.ts +1 -24
- package/scripts/framework-menu-system-notifications-env.ts +0 -8
- package/scripts/framework-menu-system-notifications-gate.ts +2 -9
- package/scripts/framework-menu-system-notifications-macos-applescript-dialog.ts +1 -1
- package/scripts/framework-menu-system-notifications-macos-dialog-payload.ts +2 -14
- package/scripts/framework-menu-system-notifications-macos-swift-source.ts +1 -1
- package/scripts/framework-menu-system-notifications-payloads-blocked.ts +4 -128
- package/scripts/framework-menu-system-notifications-payloads.ts +1 -8
- package/scripts/framework-menu-system-notifications-remediation.ts +1 -15
- package/scripts/framework-menu-system-notifications-text.ts +1 -7
- package/scripts/framework-menu.ts +2 -37
- package/scripts/package-install-smoke-consumer-git-repo-lib.ts +1 -10
- package/scripts/package-install-smoke-consumer-npm-lib.ts +9 -46
- package/skills.lock.json +1244 -807
- package/integrations/evidence/trackingContract.ts +0 -17
- package/integrations/gate/blockingCause.ts +0 -40
- package/integrations/gate/governanceActionCatalog.ts +0 -296
- package/integrations/gate/runPlatformGateConfig.ts +0 -55
- package/integrations/gate/runPlatformGateDefaults.ts +0 -19
- package/integrations/lifecycle/bootstrapManifest.ts +0 -248
- package/integrations/lifecycle/cliGovernanceConsole.ts +0 -69
- package/integrations/lifecycle/governanceNextAction.ts +0 -181
- package/integrations/lifecycle/governanceObservationSnapshot.ts +0 -376
- package/integrations/lifecycle/trackingState.ts +0 -403
- package/integrations/mcp/alignedPlatformGate.ts +0 -248
- package/integrations/mcp/readMcpPrePushStdin.ts +0 -7
- package/scripts/build-ruralgo-s1-evidence-pack.ts +0 -85
- package/scripts/ruralgo-s1-evidence-pack-lib.ts +0 -200
|
@@ -32,8 +32,6 @@ export type SwiftPresentationSrpMatch = {
|
|
|
32
32
|
lines: readonly number[];
|
|
33
33
|
};
|
|
34
34
|
|
|
35
|
-
export type SwiftXCTestSrpMatch = SwiftPresentationSrpMatch;
|
|
36
|
-
|
|
37
35
|
export type SwiftConcreteDependencyDipMatch = {
|
|
38
36
|
primary_node: SwiftSemanticNodeMatch;
|
|
39
37
|
related_nodes: readonly SwiftSemanticNodeMatch[];
|
|
@@ -100,63 +98,6 @@ const hasSwiftSanitizedRegexMatch = (source: string, regex: RegExp): boolean =>
|
|
|
100
98
|
return regex.test(sanitizeSwiftSourceForMultilineRegex(source));
|
|
101
99
|
};
|
|
102
100
|
|
|
103
|
-
type SwiftFunctionDeclaration = {
|
|
104
|
-
signature: string;
|
|
105
|
-
body: string;
|
|
106
|
-
};
|
|
107
|
-
|
|
108
|
-
const collectSwiftFunctionDeclarations = (source: string): readonly SwiftFunctionDeclaration[] => {
|
|
109
|
-
const lines = source.split(/\r?\n/);
|
|
110
|
-
const functions: SwiftFunctionDeclaration[] = [];
|
|
111
|
-
|
|
112
|
-
for (let index = 0; index < lines.length; index += 1) {
|
|
113
|
-
const firstLine = stripSwiftLineForSemanticScan(lines[index] ?? '');
|
|
114
|
-
if (!/\bfunc\b/.test(firstLine)) {
|
|
115
|
-
continue;
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
const signatureLines: string[] = [];
|
|
119
|
-
let cursor = index;
|
|
120
|
-
let openingLineIndex = -1;
|
|
121
|
-
for (; cursor < lines.length && cursor < index + 24; cursor += 1) {
|
|
122
|
-
const line = stripSwiftLineForSemanticScan(lines[cursor] ?? '');
|
|
123
|
-
signatureLines.push(line);
|
|
124
|
-
if (line.includes('{')) {
|
|
125
|
-
openingLineIndex = cursor;
|
|
126
|
-
break;
|
|
127
|
-
}
|
|
128
|
-
if (line.includes('}')) {
|
|
129
|
-
break;
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
if (openingLineIndex < 0) {
|
|
134
|
-
continue;
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
const bodyLines: string[] = [];
|
|
138
|
-
let braceDepth = 0;
|
|
139
|
-
for (let bodyCursor = openingLineIndex; bodyCursor < lines.length; bodyCursor += 1) {
|
|
140
|
-
const line = stripSwiftLineForSemanticScan(lines[bodyCursor] ?? '');
|
|
141
|
-
braceDepth += countTokenOccurrences(line, '{');
|
|
142
|
-
braceDepth -= countTokenOccurrences(line, '}');
|
|
143
|
-
bodyLines.push(line);
|
|
144
|
-
if (bodyCursor > openingLineIndex && braceDepth <= 0) {
|
|
145
|
-
cursor = bodyCursor;
|
|
146
|
-
break;
|
|
147
|
-
}
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
functions.push({
|
|
151
|
-
signature: signatureLines.join('\n'),
|
|
152
|
-
body: bodyLines.join('\n'),
|
|
153
|
-
});
|
|
154
|
-
index = cursor;
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
return functions;
|
|
158
|
-
};
|
|
159
|
-
|
|
160
101
|
const hasSwiftUiModernizationSnapshotMatch = (source: string, entryId: string): boolean => {
|
|
161
102
|
const entry = getIosSwiftUiModernizationEntry(entryId);
|
|
162
103
|
if (!entry) {
|
|
@@ -536,17 +477,6 @@ export const hasSwiftForEachIndicesUsage = (source: string): boolean => {
|
|
|
536
477
|
);
|
|
537
478
|
};
|
|
538
479
|
|
|
539
|
-
export const hasSwiftInlineFilteringInForEachUsage = (source: string): boolean => {
|
|
540
|
-
return hasSwiftSanitizedRegexMatch(
|
|
541
|
-
source,
|
|
542
|
-
/\bForEach\s*\(\s*[A-Za-z_][A-Za-z0-9_.]*\s*\.\s*filter\s*\{/g
|
|
543
|
-
);
|
|
544
|
-
};
|
|
545
|
-
|
|
546
|
-
export const hasSwiftExplicitColorStaticMemberUsage = (source: string): boolean => {
|
|
547
|
-
return hasSwiftSanitizedRegexMatch(source, /\bColor\s*\.\s*[a-z][A-Za-z0-9_]*\b/g);
|
|
548
|
-
};
|
|
549
|
-
|
|
550
480
|
const isUserSearchIdentifier = (value: string): boolean => {
|
|
551
481
|
return /^(?:query|search(?:Text|Term|Query|Value)?|filter(?:Text|Value)?|text|term|input)$/i.test(
|
|
552
482
|
value
|
|
@@ -597,36 +527,6 @@ export const hasSwiftLegacySwiftUiObservableWrapperUsage = (source: string): boo
|
|
|
597
527
|
return hasSwiftSanitizedRegexMatch(source, /@\s*(?:StateObject|ObservedObject)\b/);
|
|
598
528
|
};
|
|
599
529
|
|
|
600
|
-
export const hasSwiftStateWrapperWithoutPrivateUsage = (source: string): boolean => {
|
|
601
|
-
const typeDeclarations = parseSwiftTypeDeclarations(source);
|
|
602
|
-
if (typeDeclarations.length === 0) {
|
|
603
|
-
return false;
|
|
604
|
-
}
|
|
605
|
-
|
|
606
|
-
const sourceLines = source.split(/\r?\n/);
|
|
607
|
-
const stateWrapperPattern = /@\s*(?:State|StateObject)\b/;
|
|
608
|
-
|
|
609
|
-
for (const typeDeclaration of typeDeclarations) {
|
|
610
|
-
if (!typeDeclaration.conformances.includes('View')) {
|
|
611
|
-
continue;
|
|
612
|
-
}
|
|
613
|
-
|
|
614
|
-
const hasViolation = visitSwiftTopLevelTypeBodyLines(sourceLines, typeDeclaration, ({ line }) => {
|
|
615
|
-
if (!stateWrapperPattern.test(line)) {
|
|
616
|
-
return false;
|
|
617
|
-
}
|
|
618
|
-
|
|
619
|
-
return !/\bprivate\b/.test(line);
|
|
620
|
-
});
|
|
621
|
-
|
|
622
|
-
if (hasViolation) {
|
|
623
|
-
return true;
|
|
624
|
-
}
|
|
625
|
-
}
|
|
626
|
-
|
|
627
|
-
return false;
|
|
628
|
-
};
|
|
629
|
-
|
|
630
530
|
const hasSwiftPassedValueWrapperInitialization = (
|
|
631
531
|
source: string,
|
|
632
532
|
options: {
|
|
@@ -788,10 +688,6 @@ const hasSwiftTestingSuiteAttributeUsage = (source: string): boolean => {
|
|
|
788
688
|
return hasSwiftSanitizedRegexMatch(source, /\B@(?:Test|Suite)\b/);
|
|
789
689
|
};
|
|
790
690
|
|
|
791
|
-
const hasSwiftTestingFrameworkMarkerUsage = (source: string): boolean => {
|
|
792
|
-
return hasSwiftTestingImportUsage(source) || hasSwiftTestingSuiteAttributeUsage(source);
|
|
793
|
-
};
|
|
794
|
-
|
|
795
691
|
const hasSwiftXCTestCaseSubclassUsage = (source: string): boolean => {
|
|
796
692
|
return hasSwiftSanitizedRegexMatch(
|
|
797
693
|
source,
|
|
@@ -804,59 +700,15 @@ const hasSwiftLegacyXCTestMethodUsage = (source: string): boolean => {
|
|
|
804
700
|
.length > 0;
|
|
805
701
|
};
|
|
806
702
|
|
|
807
|
-
const hasSwiftMakeSutUsage = (source: string): boolean => {
|
|
808
|
-
return hasSwiftSanitizedRegexMatch(source, /\bmakeSUT\s*\(/);
|
|
809
|
-
};
|
|
810
|
-
|
|
811
|
-
const hasSwiftMemoryLeakTrackingUsage = (source: string): boolean => {
|
|
812
|
-
return hasSwiftSanitizedRegexMatch(source, /\btrackForMemoryLeaks\s*\(/);
|
|
813
|
-
};
|
|
814
|
-
|
|
815
|
-
const hasSwiftBrownfieldCompatibleXCTestUsage = (source: string): boolean => {
|
|
816
|
-
if (!hasSwiftXCTestImportUsage(source) || !hasSwiftXCTestCaseSubclassUsage(source)) {
|
|
817
|
-
return false;
|
|
818
|
-
}
|
|
819
|
-
|
|
820
|
-
if (!hasSwiftLegacyXCTestMethodUsage(source)) {
|
|
821
|
-
return false;
|
|
822
|
-
}
|
|
823
|
-
|
|
824
|
-
if (hasSwiftTestingImportUsage(source) || hasSwiftTestingSuiteAttributeUsage(source)) {
|
|
825
|
-
return false;
|
|
826
|
-
}
|
|
827
|
-
|
|
828
|
-
return hasSwiftMakeSutUsage(source) && hasSwiftMemoryLeakTrackingUsage(source);
|
|
829
|
-
};
|
|
830
|
-
|
|
831
|
-
const hasSwiftXCTestOnlyBrownfieldSuiteUsage = (source: string): boolean => {
|
|
832
|
-
if (!hasSwiftXCTestImportUsage(source) || !hasSwiftXCTestCaseSubclassUsage(source)) {
|
|
833
|
-
return false;
|
|
834
|
-
}
|
|
835
|
-
|
|
836
|
-
if (hasSwiftLegacyXCTestUiOrPerformanceUsage(source)) {
|
|
837
|
-
return false;
|
|
838
|
-
}
|
|
839
|
-
|
|
840
|
-
return !hasSwiftTestingImportUsage(source) && !hasSwiftTestingSuiteAttributeUsage(source);
|
|
841
|
-
};
|
|
842
|
-
|
|
843
703
|
export const hasSwiftLegacyXCTestImportUsage = (source: string): boolean => {
|
|
844
704
|
if (!hasSwiftXCTestImportUsage(source)) {
|
|
845
705
|
return false;
|
|
846
706
|
}
|
|
847
707
|
|
|
848
|
-
if (!hasSwiftXCTestCaseSubclassUsage(source) || !hasSwiftLegacyXCTestMethodUsage(source)) {
|
|
849
|
-
return false;
|
|
850
|
-
}
|
|
851
|
-
|
|
852
708
|
if (hasSwiftLegacyXCTestUiOrPerformanceUsage(source)) {
|
|
853
709
|
return false;
|
|
854
710
|
}
|
|
855
711
|
|
|
856
|
-
if (hasSwiftXCTestOnlyBrownfieldSuiteUsage(source)) {
|
|
857
|
-
return false;
|
|
858
|
-
}
|
|
859
|
-
|
|
860
712
|
return true;
|
|
861
713
|
};
|
|
862
714
|
|
|
@@ -877,18 +729,14 @@ export const hasSwiftModernizableXCTestSuiteUsage = (source: string): boolean =>
|
|
|
877
729
|
};
|
|
878
730
|
|
|
879
731
|
export const hasSwiftMixedTestingFrameworksUsage = (source: string): boolean => {
|
|
880
|
-
|
|
881
|
-
};
|
|
882
|
-
|
|
883
|
-
export const hasSwiftXCTestAssertionUsage = (source: string): boolean => {
|
|
884
|
-
if (hasSwiftLegacyXCTestUiOrPerformanceUsage(source)) {
|
|
732
|
+
if (!hasSwiftXCTestImportUsage(source) || !hasSwiftXCTestCaseSubclassUsage(source)) {
|
|
885
733
|
return false;
|
|
886
734
|
}
|
|
887
735
|
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
}
|
|
736
|
+
return hasSwiftTestingImportUsage(source) || hasSwiftTestingSuiteAttributeUsage(source);
|
|
737
|
+
};
|
|
891
738
|
|
|
739
|
+
export const hasSwiftXCTestAssertionUsage = (source: string): boolean => {
|
|
892
740
|
return (
|
|
893
741
|
collectSwiftRegexLines(source, /\bXCTAssert[A-Za-z0-9_]*\s*\(/).length > 0 ||
|
|
894
742
|
collectSwiftRegexLines(source, /\bXCTFail\s*\(/).length > 0
|
|
@@ -896,14 +744,6 @@ export const hasSwiftXCTestAssertionUsage = (source: string): boolean => {
|
|
|
896
744
|
};
|
|
897
745
|
|
|
898
746
|
export const hasSwiftXCTUnwrapUsage = (source: string): boolean => {
|
|
899
|
-
if (hasSwiftLegacyXCTestUiOrPerformanceUsage(source)) {
|
|
900
|
-
return false;
|
|
901
|
-
}
|
|
902
|
-
|
|
903
|
-
if (hasSwiftXCTestOnlyBrownfieldSuiteUsage(source)) {
|
|
904
|
-
return false;
|
|
905
|
-
}
|
|
906
|
-
|
|
907
747
|
return collectSwiftRegexLines(source, /\bXCTUnwrap\s*\(/).length > 0;
|
|
908
748
|
};
|
|
909
749
|
|
|
@@ -916,59 +756,40 @@ const hasSwiftConfirmationUsage = (source: string): boolean => {
|
|
|
916
756
|
};
|
|
917
757
|
|
|
918
758
|
export const hasSwiftWaitForExpectationsUsage = (source: string): boolean => {
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
}
|
|
924
|
-
legacyWaitPattern.lastIndex = 0;
|
|
925
|
-
return legacyWaitPattern.test(declaration.body);
|
|
926
|
-
});
|
|
759
|
+
return hasSwiftSanitizedRegexMatch(
|
|
760
|
+
source,
|
|
761
|
+
/\bwait\s*\(\s*for\s*:|\bwaitForExpectations\s*\(/
|
|
762
|
+
);
|
|
927
763
|
};
|
|
928
764
|
|
|
929
765
|
export const hasSwiftLegacyExpectationDescriptionUsage = (source: string): boolean => {
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
if (!hasSwiftSanitizedRegexMatch(declaration.body, /\bexpectation\s*\(\s*description\s*:/)) {
|
|
935
|
-
return false;
|
|
936
|
-
}
|
|
937
|
-
return !hasSwiftAwaitFulfillmentUsage(declaration.body) && !hasSwiftConfirmationUsage(declaration.body);
|
|
938
|
-
});
|
|
939
|
-
};
|
|
766
|
+
const hasLegacyExpectation = collectSwiftRegexLines(
|
|
767
|
+
source,
|
|
768
|
+
/\bexpectation\s*\(\s*description\s*:/
|
|
769
|
+
).length > 0;
|
|
940
770
|
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
const swiftManagedObjectSubclassPattern =
|
|
945
|
-
/\b(?:final\s+)?class\s+[A-Za-z_][A-Za-z0-9_]*\s*:\s*NSManagedObject\b/;
|
|
771
|
+
if (!hasLegacyExpectation) {
|
|
772
|
+
return false;
|
|
773
|
+
}
|
|
946
774
|
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
775
|
+
if (hasSwiftAwaitFulfillmentUsage(source) || hasSwiftConfirmationUsage(source)) {
|
|
776
|
+
return false;
|
|
777
|
+
}
|
|
778
|
+
|
|
779
|
+
return true;
|
|
951
780
|
};
|
|
952
781
|
|
|
953
782
|
export const hasSwiftNSManagedObjectBoundaryUsage = (source: string): boolean => {
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
return source.split(/\r?\n/).some((line) => {
|
|
959
|
-
const sanitized = stripSwiftLineForSemanticScan(line);
|
|
960
|
-
return (
|
|
961
|
-
swiftStoredPropertyBoundaryPattern.test(sanitized) &&
|
|
962
|
-
!swiftManagedObjectSubclassPattern.test(sanitized)
|
|
963
|
-
);
|
|
964
|
-
});
|
|
783
|
+
return hasSwiftSanitizedRegexMatch(
|
|
784
|
+
source,
|
|
785
|
+
/\bfunc\b[\s\S]{0,240}\([^)]*\bNSManagedObject\b(?!ID\b|Context\b)[^)]*\)|\b(?:var|let)\s+[A-Za-z_][A-Za-z0-9_]*\s*:\s*(?:\[[^\]]*NSManagedObject\b(?!ID\b|Context\b)[^\]]*\]|NSManagedObject\b(?!ID\b|Context\b))/g
|
|
786
|
+
);
|
|
965
787
|
};
|
|
966
788
|
|
|
967
789
|
export const hasSwiftNSManagedObjectAsyncBoundaryUsage = (source: string): boolean => {
|
|
968
|
-
return
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
swiftManagedObjectBoundaryTypePattern.test(declaration.signature)
|
|
790
|
+
return hasSwiftSanitizedRegexMatch(
|
|
791
|
+
source,
|
|
792
|
+
/\bfunc\b[\s\S]{0,240}\basync\b[\s\S]{0,200}(?:\([^)]*\bNSManagedObject\b(?!ID\b|Context\b)[^)]*\)|->\s*(?:\[[^\]]*NSManagedObject\b(?!ID\b|Context\b)[^\]]*\]|NSManagedObject\b(?!ID\b|Context\b)))/g
|
|
972
793
|
);
|
|
973
794
|
};
|
|
974
795
|
|
|
@@ -1290,100 +1111,6 @@ export const findSwiftPresentationSrpMatch = (
|
|
|
1290
1111
|
};
|
|
1291
1112
|
};
|
|
1292
1113
|
|
|
1293
|
-
export const findSwiftXCTestSrpMatch = (source: string): SwiftXCTestSrpMatch | undefined => {
|
|
1294
|
-
if (!hasSwiftXCTestCaseSubclassUsage(source)) {
|
|
1295
|
-
return undefined;
|
|
1296
|
-
}
|
|
1297
|
-
|
|
1298
|
-
const classPattern = /\b(?:final\s+)?class\s+([A-Za-z0-9_]*Tests?)\s*:\s*XCTestCase\b/;
|
|
1299
|
-
const classLines = collectSwiftRegexLines(source, classPattern);
|
|
1300
|
-
if (classLines.length === 0) {
|
|
1301
|
-
return undefined;
|
|
1302
|
-
}
|
|
1303
|
-
|
|
1304
|
-
const classLine = source.split(/\r?\n/)[classLines[0] - 1] ?? '';
|
|
1305
|
-
const className = classLine.match(classPattern)?.[1];
|
|
1306
|
-
if (!className) {
|
|
1307
|
-
return undefined;
|
|
1308
|
-
}
|
|
1309
|
-
|
|
1310
|
-
const sourceLines = source.split(/\r?\n/);
|
|
1311
|
-
const familyPatterns: ReadonlyArray<{
|
|
1312
|
-
key: string;
|
|
1313
|
-
name: string;
|
|
1314
|
-
tokens: readonly string[];
|
|
1315
|
-
}> = [
|
|
1316
|
-
{ key: 'configuration', name: 'configuration outcome tests', tokens: ['config', 'configuration', 'update', 'cache'] },
|
|
1317
|
-
{ key: 'session', name: 'session routing tests', tokens: ['session', 'login', 'auth', 'valid', 'invalid'] },
|
|
1318
|
-
{ key: 'onboarding', name: 'onboarding progress tests', tokens: ['onboarding', 'progress', 'completeonboarding'] },
|
|
1319
|
-
{ key: 'permissions', name: 'permissions routing tests', tokens: ['permission', 'camera', 'location', 'notification'] },
|
|
1320
|
-
{ key: 'tutorial', name: 'tutorial or feature discovery tests', tokens: ['tutorial', 'featurediscovery'] },
|
|
1321
|
-
{ key: 'splash', name: 'splash delay tests', tokens: ['splash', 'delay', 'start'] },
|
|
1322
|
-
];
|
|
1323
|
-
const matchesFamily = (value: string, tokens: readonly string[]): boolean => {
|
|
1324
|
-
const normalizedValue = value.toLowerCase();
|
|
1325
|
-
return tokens.some((token) => normalizedValue.includes(token));
|
|
1326
|
-
};
|
|
1327
|
-
|
|
1328
|
-
const classFamilyKeys = new Set(
|
|
1329
|
-
familyPatterns
|
|
1330
|
-
.filter((entry) => matchesFamily(className, entry.tokens))
|
|
1331
|
-
.map((entry) => entry.key)
|
|
1332
|
-
);
|
|
1333
|
-
const matchedFamilies = new Map<string, SwiftSemanticNodeMatch>();
|
|
1334
|
-
|
|
1335
|
-
sourceLines.forEach((line, index) => {
|
|
1336
|
-
const sanitizedLine = stripSwiftLineForSemanticScan(line);
|
|
1337
|
-
const methodMatch = sanitizedLine.match(/\bfunc\s+(test[A-Za-z0-9_]+)\s*\(/);
|
|
1338
|
-
const methodName = methodMatch?.[1];
|
|
1339
|
-
if (!methodName) {
|
|
1340
|
-
return;
|
|
1341
|
-
}
|
|
1342
|
-
|
|
1343
|
-
for (const family of familyPatterns) {
|
|
1344
|
-
if (!matchesFamily(methodName, family.tokens)) {
|
|
1345
|
-
continue;
|
|
1346
|
-
}
|
|
1347
|
-
if (classFamilyKeys.has(family.key)) {
|
|
1348
|
-
continue;
|
|
1349
|
-
}
|
|
1350
|
-
if (!matchedFamilies.has(family.key)) {
|
|
1351
|
-
matchedFamilies.set(family.key, {
|
|
1352
|
-
kind: 'member',
|
|
1353
|
-
name: family.name,
|
|
1354
|
-
lines: [index + 1],
|
|
1355
|
-
});
|
|
1356
|
-
}
|
|
1357
|
-
}
|
|
1358
|
-
});
|
|
1359
|
-
|
|
1360
|
-
const relatedNodes = [...matchedFamilies.values()];
|
|
1361
|
-
if (relatedNodes.length < 2) {
|
|
1362
|
-
return undefined;
|
|
1363
|
-
}
|
|
1364
|
-
|
|
1365
|
-
const relatedNodeNames = relatedNodes.map((node) => node.name).join(', ');
|
|
1366
|
-
const allLines = sortedUniqueLines([
|
|
1367
|
-
...classLines,
|
|
1368
|
-
...relatedNodes.flatMap((node) => [...node.lines]),
|
|
1369
|
-
]);
|
|
1370
|
-
|
|
1371
|
-
return {
|
|
1372
|
-
primary_node: {
|
|
1373
|
-
kind: 'class',
|
|
1374
|
-
name: className,
|
|
1375
|
-
lines: classLines,
|
|
1376
|
-
},
|
|
1377
|
-
related_nodes: relatedNodes,
|
|
1378
|
-
why: `${className} mezcla ${relatedNodeNames} dentro del mismo XCTestCase, rompiendo SRP en la suite de tests.`,
|
|
1379
|
-
impact:
|
|
1380
|
-
'La suite acumula múltiples razones de cambio, oculta regresiones por responsabilidad y hace más difícil aislar el baseline afectado antes de PRE_WRITE.',
|
|
1381
|
-
expected_fix:
|
|
1382
|
-
'Divide la suite por responsabilidad observable: configuración, sesión, onboarding, permisos, tutorial o splash deben vivir en XCTestCase separados.',
|
|
1383
|
-
lines: allLines,
|
|
1384
|
-
};
|
|
1385
|
-
};
|
|
1386
|
-
|
|
1387
1114
|
export const findSwiftConcreteDependencyDipMatch = (
|
|
1388
1115
|
source: string
|
|
1389
1116
|
): SwiftConcreteDependencyDipMatch | undefined => {
|
|
@@ -1474,7 +1201,7 @@ export const findSwiftOpenClosedSwitchMatch = (
|
|
|
1474
1201
|
}
|
|
1475
1202
|
|
|
1476
1203
|
const lines = source.split(/\r?\n/);
|
|
1477
|
-
const discriminatorPattern = /\b(?:kind|type|mode|channel|variant|provider|route|flow|source|experience
|
|
1204
|
+
const discriminatorPattern = /\b(?:kind|type|mode|channel|variant|provider|route|flow|source|experience)\b/i;
|
|
1478
1205
|
const switchPattern = /\bswitch\s+([A-Za-z_][A-Za-z0-9_\.]*)\s*\{/;
|
|
1479
1206
|
|
|
1480
1207
|
for (let index = 0; index < lines.length; index += 1) {
|