pumuki 6.3.253 → 6.3.255

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,13 @@
1
1
  # Changelog
2
2
 
3
+ ## [6.3.255] - 2026-05-14
4
+
5
+ - iOS: `skills.ios.no-mixed-testing-frameworks` now emits actionable AST-style evidence for files mixing `XCTestCase` with Swift Testing markers, including exact lines, primary/related nodes and a concrete split-or-migrate remediation.
6
+
7
+ ## [6.3.254] - 2026-05-14
8
+
9
+ - iOS Swift Testing parity: `skills.ios.no-legacy-expectation-description` now emits AST-style line and node evidence for legacy `expectation(description:)` scaffolding, with actionable replacement guidance toward `await confirmation(...)` or awaited fulfillment flows.
10
+
3
11
  ## [6.3.253] - 2026-05-14
4
12
 
5
13
  ### Added
@@ -6,6 +6,8 @@ import {
6
6
  findSwiftOpenClosedSwitchMatch,
7
7
  findSwiftConcreteDependencyDipMatch,
8
8
  findSwiftPresentationSrpMatch,
9
+ collectSwiftLegacyExpectationDescriptionLines,
10
+ collectSwiftMixedTestingFrameworkLines,
9
11
  collectSwiftWaitForExpectationsLines,
10
12
  hasSwiftAnyViewUsage,
11
13
  hasSwiftAsyncWithoutAwaitUsage,
@@ -1758,6 +1760,8 @@ await confirmation("Done") { confirm in
1758
1760
  assert.equal(hasSwiftLegacyExpectationDescriptionUsage(legacyExpectation), true);
1759
1761
  assert.equal(hasSwiftLegacyExpectationDescriptionUsage(modernExpectation), false);
1760
1762
  assert.equal(hasSwiftLegacyExpectationDescriptionUsage(confirmationOnly), false);
1763
+ assert.deepEqual(collectSwiftLegacyExpectationDescriptionLines(legacyExpectation), [2]);
1764
+ assert.deepEqual(collectSwiftLegacyExpectationDescriptionLines(confirmationOnly), []);
1761
1765
  });
1762
1766
 
1763
1767
  test('hasSwiftNSManagedObjectBoundaryUsage detecta boundaries con NSManagedObject y excluye IDs o subclases', () => {
@@ -2231,3 +2235,32 @@ struct EditItemSheet: View {
2231
2235
  assert.equal(hasSwiftUiParentOwnedSheetActionUsage(source), true);
2232
2236
  assert.equal(hasSwiftUiParentOwnedSheetActionUsage(safe), false);
2233
2237
  });
2238
+
2239
+
2240
+ test('collectSwiftMixedTestingFrameworkLines localiza nodos de mezcla XCTest y Swift Testing', () => {
2241
+ const mixedSuite = `
2242
+ import XCTest
2243
+ import Testing
2244
+
2245
+ final class LoginTests: XCTestCase {
2246
+ func testLegacyLogin() {}
2247
+ }
2248
+
2249
+ @Suite
2250
+ struct LoginModernTests {
2251
+ @Test func login() async {}
2252
+ }
2253
+ `;
2254
+ const legacyOnly = `
2255
+ import XCTest
2256
+
2257
+ final class LoginTests: XCTestCase {
2258
+ func testLegacyLogin() {}
2259
+ }
2260
+ `;
2261
+
2262
+ assert.equal(hasSwiftMixedTestingFrameworksUsage(mixedSuite), true);
2263
+ assert.deepEqual(collectSwiftMixedTestingFrameworkLines(mixedSuite), [2, 3, 5, 9, 11]);
2264
+ assert.equal(hasSwiftMixedTestingFrameworksUsage(legacyOnly), false);
2265
+ assert.deepEqual(collectSwiftMixedTestingFrameworkLines(legacyOnly), []);
2266
+ });
@@ -1336,6 +1336,19 @@ export const hasSwiftMixedTestingFrameworksUsage = (source: string): boolean =>
1336
1336
  return hasSwiftTestingImportUsage(source) || hasSwiftTestingSuiteAttributeUsage(source);
1337
1337
  };
1338
1338
 
1339
+ export const collectSwiftMixedTestingFrameworkLines = (source: string): readonly number[] => {
1340
+ if (!hasSwiftMixedTestingFrameworksUsage(source)) {
1341
+ return [];
1342
+ }
1343
+
1344
+ return sortedUniqueLines([
1345
+ ...collectSwiftRegexLines(source, /\bimport\s+XCTest\b/),
1346
+ ...collectSwiftRegexLines(source, /\bimport\s+Testing\b/),
1347
+ ...collectSwiftRegexLines(source, /\bclass\s+[A-Za-z_][A-Za-z0-9_]*\s*:\s*XCTestCase\b/),
1348
+ ...collectSwiftRegexLines(source, /@\s*(?:Suite|Test)\b/),
1349
+ ]);
1350
+ };
1351
+
1339
1352
  export const hasSwiftQuickNimbleUsage = (source: string): boolean => {
1340
1353
  return hasSwiftSanitizedRegexMatch(
1341
1354
  source,
@@ -1374,13 +1387,15 @@ export const hasSwiftWaitForExpectationsUsage = (source: string): boolean => {
1374
1387
  return collectSwiftWaitForExpectationsLines(source).length > 0;
1375
1388
  };
1376
1389
 
1377
- export const hasSwiftLegacyExpectationDescriptionUsage = (source: string): boolean => {
1378
- const hasLegacyExpectation = collectSwiftRegexLines(
1390
+ export const collectSwiftLegacyExpectationDescriptionLines = (source: string): readonly number[] => {
1391
+ return sortedUniqueLines(collectSwiftRegexLines(
1379
1392
  source,
1380
1393
  /\bexpectation\s*\(\s*description\s*:/
1381
- ).length > 0;
1394
+ ));
1395
+ };
1382
1396
 
1383
- if (!hasLegacyExpectation) {
1397
+ export const hasSwiftLegacyExpectationDescriptionUsage = (source: string): boolean => {
1398
+ if (collectSwiftLegacyExpectationDescriptionLines(source).length === 0) {
1384
1399
  return false;
1385
1400
  }
1386
1401
 
@@ -721,8 +721,8 @@ const textDetectorRegistry: ReadonlyArray<TextDetectorRegistryEntry> = [
721
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.' },
722
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.' },
723
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.' },
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.' },
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.' },
724
+ { platform: 'ios', pathCheck: isIOSSwiftTestPath, excludePaths: [], detect: TextIOS.hasSwiftLegacyExpectationDescriptionUsage, locateLines: TextIOS.collectSwiftLegacyExpectationDescriptionLines, primaryNode: (lines) => ({ kind: 'call', name: 'legacy XCTest expectation(description:) call', lines }), relatedNodes: (lines) => [{ kind: 'call', name: 'replacement: await confirmation or awaited fulfillment flow', lines }], why: 'Legacy expectation(description:) scaffolding keeps async tests coupled to XCTest-style callbacks instead of expressing confirmation intent directly.', impact: 'Tests can remain harder to read and migrate because the assertion flow is split between expectation creation, callback fulfillment and a later wait.', expected_fix: 'Prefer await confirmation(...) for callback confirmation, or pair legacy expectations with await fulfillment(of:timeout:) when the target still requires XCTest compatibility.', 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.' },
725
+ { platform: 'ios', pathCheck: isIOSSwiftTestPath, excludePaths: [], detect: TextIOS.hasSwiftMixedTestingFrameworksUsage, locateLines: TextIOS.collectSwiftMixedTestingFrameworkLines, primaryNode: (lines) => ({ kind: 'class', name: 'mixed XCTestCase and Swift Testing suite', lines }), relatedNodes: (lines) => [{ kind: 'call', name: 'replacement: isolate XCTest compatibility from Swift Testing suites', lines }], why: 'Mixing XCTestCase and Swift Testing markers in the same file makes the test contract ambiguous and hides whether the target is legacy XCTest compatibility or modern Swift Testing.', impact: 'Migration work becomes harder to audit because one file can carry two lifecycle models, assertion styles and setup conventions at once.', expected_fix: 'Split XCTest compatibility tests and Swift Testing suites into separate files, or migrate the legacy XCTestCase suite fully to import Testing with @Suite/@Test and #expect/#require.', 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.' },
726
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.' },
727
727
  { platform: 'ios', pathCheck: isIOSSwiftPath, excludePaths: [isSwiftTestPath], detect: TextIOS.hasSwiftNSManagedObjectBoundaryUsage, ruleId: 'heuristics.ios.core-data.nsmanagedobject-boundary.ast', code: 'HEURISTICS_IOS_CORE_DATA_NSMANAGEDOBJECT_BOUNDARY_AST', message: 'AST heuristic detected NSManagedObject in a shared boundary.' },
728
728
  { platform: 'ios', pathCheck: isIOSSwiftPath, excludePaths: [isSwiftTestPath], detect: TextIOS.hasSwiftNSManagedObjectAsyncBoundaryUsage, ruleId: 'heuristics.ios.core-data.nsmanagedobject-async-boundary.ast', code: 'HEURISTICS_IOS_CORE_DATA_NSMANAGEDOBJECT_ASYNC_BOUNDARY_AST', message: 'AST heuristic detected NSManagedObject in an async boundary.' },
@@ -6,6 +6,14 @@ 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.255)
10
+
11
+ - Published `pumuki@6.3.255` with AST-style line/node evidence for `skills.ios.no-mixed-testing-frameworks`, closing the XCTestCase + Swift Testing mixed-suite parity gap with a remediable split/migrate contract.
12
+
13
+ ### 2026-05-14 (v6.3.254)
14
+ - **Paridad AST iOS testing:** `skills.ios.no-legacy-expectation-description` ancla `expectation(description:)` a líneas y nodos accionables, con reemplazo recomendado hacia `await confirmation(...)` o `await fulfillment(of:timeout:)`.
15
+ - **Rollout recomendado:** publicar `pumuki@6.3.254` y repinear consumers que dependan de paridad iOS/Swift Testing.
16
+
9
17
  ### 2026-05-14 (v6.3.253)
10
18
 
11
19
  - **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:)`.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pumuki",
3
- "version": "6.3.253",
3
+ "version": "6.3.255",
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": {