pumuki 6.3.252 → 6.3.253
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/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [6.3.253] - 2026-05-14
|
|
4
|
+
|
|
5
|
+
### Added
|
|
6
|
+
- **iOS AST node evidence for XCTest waits:** `skills.ios.no-wait-for-expectations` now emits actionable line and node metadata for `wait(for:)`, `self.wait(for:)`, `waitForExpectations(timeout:)` and `XCTWaiter.wait(for:)`, while ignoring strings and comments.
|
|
7
|
+
|
|
3
8
|
All notable changes to `pumuki` are documented here.
|
|
4
9
|
|
|
5
10
|
This project follows [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
@@ -6,6 +6,7 @@ import {
|
|
|
6
6
|
findSwiftOpenClosedSwitchMatch,
|
|
7
7
|
findSwiftConcreteDependencyDipMatch,
|
|
8
8
|
findSwiftPresentationSrpMatch,
|
|
9
|
+
collectSwiftWaitForExpectationsLines,
|
|
9
10
|
hasSwiftAnyViewUsage,
|
|
10
11
|
hasSwiftAsyncWithoutAwaitUsage,
|
|
11
12
|
hasSwiftCallbackStyleSignature,
|
|
@@ -1721,14 +1722,20 @@ test('hasSwiftWaitForExpectationsUsage detecta waits legacy y excluye await fulf
|
|
|
1721
1722
|
let expectation = expectation(description: "Done")
|
|
1722
1723
|
wait(for: [expectation], timeout: 1)
|
|
1723
1724
|
waitForExpectations(timeout: 1)
|
|
1725
|
+
self.wait(for: [expectation], timeout: 1)
|
|
1726
|
+
XCTWaiter.wait(for: [expectation], timeout: 1)
|
|
1724
1727
|
`;
|
|
1725
1728
|
const modernWait = `
|
|
1726
1729
|
let expectation = expectation(description: "Done")
|
|
1727
1730
|
await fulfillment(of: [expectation], timeout: 1)
|
|
1731
|
+
let sample = "waitForExpectations(timeout: 1)"
|
|
1732
|
+
// wait(for: [expectation], timeout: 1)
|
|
1728
1733
|
`;
|
|
1729
1734
|
|
|
1730
1735
|
assert.equal(hasSwiftWaitForExpectationsUsage(legacyWait), true);
|
|
1731
1736
|
assert.equal(hasSwiftWaitForExpectationsUsage(modernWait), false);
|
|
1737
|
+
assert.deepEqual(collectSwiftWaitForExpectationsLines(legacyWait), [3, 4, 5, 6]);
|
|
1738
|
+
assert.deepEqual(collectSwiftWaitForExpectationsLines(modernWait), []);
|
|
1732
1739
|
});
|
|
1733
1740
|
|
|
1734
1741
|
test('hasSwiftLegacyExpectationDescriptionUsage detecta expectation(description:) sin flujo moderno', () => {
|
|
@@ -1362,11 +1362,16 @@ const hasSwiftConfirmationUsage = (source: string): boolean => {
|
|
|
1362
1362
|
return hasSwiftSanitizedRegexMatch(source, /\bawait\s+confirmation\b/);
|
|
1363
1363
|
};
|
|
1364
1364
|
|
|
1365
|
+
export const collectSwiftWaitForExpectationsLines = (source: string): readonly number[] => {
|
|
1366
|
+
return sortedUniqueLines([
|
|
1367
|
+
...collectSwiftRegexLines(source, /\b(?:self\s*\.\s*)?wait\s*\(\s*for\s*:/),
|
|
1368
|
+
...collectSwiftRegexLines(source, /\bwaitForExpectations\s*\(/),
|
|
1369
|
+
...collectSwiftRegexLines(source, /\bXCTWaiter\s*\.\s*wait\s*\(\s*for\s*:/),
|
|
1370
|
+
]);
|
|
1371
|
+
};
|
|
1372
|
+
|
|
1365
1373
|
export const hasSwiftWaitForExpectationsUsage = (source: string): boolean => {
|
|
1366
|
-
return
|
|
1367
|
-
source,
|
|
1368
|
-
/\bwait\s*\(\s*for\s*:|\bwaitForExpectations\s*\(/
|
|
1369
|
-
);
|
|
1374
|
+
return collectSwiftWaitForExpectationsLines(source).length > 0;
|
|
1370
1375
|
};
|
|
1371
1376
|
|
|
1372
1377
|
export const hasSwiftLegacyExpectationDescriptionUsage = (source: string): boolean => {
|
|
@@ -627,6 +627,12 @@ type TextDetectorRegistryEntry = {
|
|
|
627
627
|
readonly pathCheck: (path: string) => boolean;
|
|
628
628
|
readonly excludePaths: ReadonlyArray<(path: string) => boolean>;
|
|
629
629
|
readonly detect: (content: string) => boolean;
|
|
630
|
+
readonly locateLines?: (content: string) => readonly number[];
|
|
631
|
+
readonly primaryNode?: (lines: readonly number[]) => HeuristicFact['primary_node'];
|
|
632
|
+
readonly relatedNodes?: (lines: readonly number[]) => HeuristicFact['related_nodes'];
|
|
633
|
+
readonly why?: string;
|
|
634
|
+
readonly impact?: string;
|
|
635
|
+
readonly expected_fix?: string;
|
|
630
636
|
readonly ruleId: string;
|
|
631
637
|
readonly code: string;
|
|
632
638
|
readonly message: string;
|
|
@@ -714,7 +720,7 @@ const textDetectorRegistry: ReadonlyArray<TextDetectorRegistryEntry> = [
|
|
|
714
720
|
{ platform: 'ios', pathCheck: isIOSSwiftTestPath, excludePaths: [], detect: TextIOS.hasSwiftModernizableXCTestSuiteUsage, ruleId: 'heuristics.ios.testing.xctest-suite-modernizable.ast', code: 'HEURISTICS_IOS_TESTING_XCTEST_SUITE_MODERNIZABLE_AST', message: 'AST heuristic detected XCTestCase/test... suite that may be modernizable to Swift Testing with import Testing and @Test.' },
|
|
715
721
|
{ platform: 'ios', pathCheck: isIOSSwiftTestPath, excludePaths: [], detect: TextIOS.hasSwiftXCTestAssertionUsage, ruleId: 'heuristics.ios.testing.xctassert.ast', code: 'HEURISTICS_IOS_TESTING_XCTASSERT_AST', message: 'AST heuristic detected XCTest assertion usage where #expect may be preferred.' },
|
|
716
722
|
{ platform: 'ios', pathCheck: isIOSSwiftTestPath, excludePaths: [], detect: TextIOS.hasSwiftXCTUnwrapUsage, ruleId: 'heuristics.ios.testing.xctunwrap.ast', code: 'HEURISTICS_IOS_TESTING_XCTUNWRAP_AST', message: 'AST heuristic detected XCTUnwrap usage where #require may be preferred.' },
|
|
717
|
-
{ platform: 'ios', pathCheck: isIOSSwiftTestPath, excludePaths: [], detect: TextIOS.hasSwiftWaitForExpectationsUsage, ruleId: 'heuristics.ios.testing.wait-for-expectations.ast', code: 'HEURISTICS_IOS_TESTING_WAIT_FOR_EXPECTATIONS_AST', message: 'AST heuristic detected wait(for:)/waitForExpectations usage where await fulfillment(of:) may be preferred.' },
|
|
723
|
+
{ platform: 'ios', pathCheck: isIOSSwiftTestPath, excludePaths: [], detect: TextIOS.hasSwiftWaitForExpectationsUsage, locateLines: TextIOS.collectSwiftWaitForExpectationsLines, primaryNode: (lines) => ({ kind: 'call', name: 'legacy XCTest wait call', lines }), relatedNodes: (lines) => [{ kind: 'call', name: 'replacement: await fulfillment(of:timeout:)', lines }], why: 'Legacy XCTest wait APIs block the current test thread and hide async intent that Swift concurrency can express directly.', impact: 'Async tests become less deterministic, harder to cancel and easier to keep tied to XCTest-only migration paths.', expected_fix: 'Replace wait(for:timeout:), self.wait(for:timeout:) or waitForExpectations(timeout:) with await fulfillment(of:timeout:) when the test target supports async XCTest migration.', ruleId: 'heuristics.ios.testing.wait-for-expectations.ast', code: 'HEURISTICS_IOS_TESTING_WAIT_FOR_EXPECTATIONS_AST', message: 'AST heuristic detected wait(for:)/waitForExpectations usage where await fulfillment(of:) may be preferred.' },
|
|
718
724
|
{ platform: 'ios', pathCheck: isIOSSwiftTestPath, excludePaths: [], detect: TextIOS.hasSwiftLegacyExpectationDescriptionUsage, ruleId: 'heuristics.ios.testing.legacy-expectation-description.ast', code: 'HEURISTICS_IOS_TESTING_LEGACY_EXPECTATION_DESCRIPTION_AST', message: 'AST heuristic detected expectation(description:) usage without modern fulfillment/confirmation flow.' },
|
|
719
725
|
{ platform: 'ios', pathCheck: isIOSSwiftTestPath, excludePaths: [], detect: TextIOS.hasSwiftMixedTestingFrameworksUsage, ruleId: 'heuristics.ios.testing.mixed-frameworks.ast', code: 'HEURISTICS_IOS_TESTING_MIXED_FRAMEWORKS_AST', message: 'AST heuristic detected XCTestCase and Swift Testing markers mixed in the same test file without explicit compatibility reason.' },
|
|
720
726
|
{ platform: 'ios', pathCheck: isIOSSwiftTestPath, excludePaths: [], detect: TextIOS.hasSwiftQuickNimbleUsage, ruleId: 'heuristics.ios.testing.quick-nimble.ast', code: 'HEURISTICS_IOS_TESTING_QUICK_NIMBLE_AST', message: 'AST heuristic detected Quick/Nimble usage where native Swift Testing remains the preferred baseline.' },
|
|
@@ -812,12 +818,19 @@ export const extractHeuristicFacts = (
|
|
|
812
818
|
(entry.excludePaths ?? []).every((exclude) => !exclude(fileFact.path)) &&
|
|
813
819
|
entry.detect(fileFact.content)
|
|
814
820
|
) {
|
|
821
|
+
const lines = entry.locateLines?.(fileFact.content);
|
|
815
822
|
heuristicFacts.push(
|
|
816
823
|
createHeuristicFact({
|
|
817
824
|
ruleId: entry.ruleId,
|
|
818
825
|
code: entry.code,
|
|
819
826
|
message: entry.message,
|
|
820
827
|
filePath: fileFact.path,
|
|
828
|
+
lines,
|
|
829
|
+
primary_node: lines && lines.length > 0 ? entry.primaryNode?.(lines) : undefined,
|
|
830
|
+
related_nodes: lines && lines.length > 0 ? entry.relatedNodes?.(lines) : undefined,
|
|
831
|
+
why: entry.why,
|
|
832
|
+
impact: entry.impact,
|
|
833
|
+
expected_fix: entry.expected_fix,
|
|
821
834
|
})
|
|
822
835
|
);
|
|
823
836
|
}
|
|
@@ -6,6 +6,11 @@ This file keeps only the operational highlights and rollout notes that matter wh
|
|
|
6
6
|
|
|
7
7
|
## 2026-04 (CLI stability and macOS notifications)
|
|
8
8
|
|
|
9
|
+
### 2026-05-14 (v6.3.253)
|
|
10
|
+
|
|
11
|
+
- **Paridad AST iOS testing:** `skills.ios.no-wait-for-expectations` queda respaldada por evidencia accionable de llamada Swift, con líneas, nodo primario y remediación hacia `await fulfillment(of:timeout:)`.
|
|
12
|
+
- **Rollout recomendado:** publicar `pumuki@6.3.253` y continuar con `skills.ios.no-legacy-expectation-description` si no entra bug externo nuevo.
|
|
13
|
+
|
|
9
14
|
### 2026-05-14 (v6.3.252)
|
|
10
15
|
|
|
11
16
|
- **Parser de tracking estricto:** el refresh SDD ya no interpreta bullets operativos (`Siguiente`, `next`, `delegable`) como IDs de task activa.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pumuki",
|
|
3
|
-
"version": "6.3.
|
|
3
|
+
"version": "6.3.253",
|
|
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": {
|