pumuki 6.3.259 → 6.3.260

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,9 @@
1
1
  # Changelog
2
2
 
3
+ ## [6.3.260] - 2026-05-14
4
+
5
+ - iOS: `skills.ios.no-force-unwrap` now emits actionable AST-style evidence for Swift postfix force unwraps, including exact lines, primary/related nodes and remediation toward guarded optional handling.
6
+
3
7
  ## [6.3.259] - 2026-05-14
4
8
 
5
9
  - iOS: `skills.ios.prefer-swift-testing` now emits actionable AST-style evidence for modernizable `XCTestCase` suites, including exact lines, primary/related nodes and native Swift Testing `import Testing`/`@Suite`/`@Test` remediation.
@@ -82,6 +82,7 @@ import {
82
82
  hasSwiftJSONSerializationUsage,
83
83
  hasSwiftExplicitColorStaticMemberUsage,
84
84
  hasSwiftClosureBasedViewBuilderContentUsage,
85
+ collectSwiftForceUnwrapLines,
85
86
  hasSwiftLargeConfigContextViewPropertyUsage,
86
87
  hasSwiftUiConditionalSameViewIdentityUsage,
87
88
  hasSwiftUiParentOwnedSheetActionUsage,
@@ -106,6 +107,7 @@ let token = optionalToken!
106
107
  let value = loadUser()!
107
108
  `;
108
109
  assert.equal(hasSwiftForceUnwrap(source), true);
110
+ assert.deepEqual(collectSwiftForceUnwrapLines(source), [2, 3]);
109
111
  });
110
112
 
111
113
  test('hasSwiftForceUnwrap excluye type annotations, force cast y operadores', () => {
@@ -116,6 +118,7 @@ if left != right { print("ok") }
116
118
  let flag = value!!
117
119
  `;
118
120
  assert.equal(hasSwiftForceUnwrap(source), false);
121
+ assert.deepEqual(collectSwiftForceUnwrapLines(source), []);
119
122
  });
120
123
 
121
124
  test('hasSwiftForceUnwrap excluye comparaciones seguras contra nil', () => {
@@ -129,6 +132,7 @@ if waitersByKey[key] != nil {
129
132
  }
130
133
  `;
131
134
  assert.equal(hasSwiftForceUnwrap(source), false);
135
+ assert.deepEqual(collectSwiftForceUnwrapLines(source), []);
132
136
  });
133
137
 
134
138
  test('hasSwiftAnyViewUsage detecta AnyView en codigo real', () => {
@@ -342,7 +342,7 @@ const isForceUnwrapAt = (source: string, index: number): boolean => {
342
342
 
343
343
  const previousChar = source[previousIndex];
344
344
  const previousIdentifier = readIdentifierBackward(source, previousIndex);
345
- if (previousIdentifier.value === 'as') {
345
+ if (previousIdentifier.value === 'as' || previousIdentifier.value === 'try') {
346
346
  return false;
347
347
  }
348
348
  if (
@@ -370,6 +370,20 @@ export const hasSwiftForceUnwrap = (source: string): boolean => {
370
370
  });
371
371
  };
372
372
 
373
+ export const collectSwiftForceUnwrapLines = (source: string): readonly number[] => {
374
+ const lines: number[] = [];
375
+ source.split(/\r?\n/).forEach((line, index) => {
376
+ const sanitizedLine = stripSwiftLineForSemanticScan(line);
377
+ for (let cursor = 0; cursor < sanitizedLine.length; cursor += 1) {
378
+ if (sanitizedLine[cursor] === '!' && isForceUnwrapAt(sanitizedLine, cursor)) {
379
+ lines.push(index + 1);
380
+ break;
381
+ }
382
+ }
383
+ });
384
+ return sortedUniqueLines(lines);
385
+ };
386
+
373
387
  export const hasSwiftAnyViewUsage = (source: string): boolean => {
374
388
  return scanCodeLikeSource(source, ({ source: swiftSource, index, current }) => {
375
389
  if (current !== 'A') {
@@ -642,7 +642,7 @@ const textDetectorRegistry: ReadonlyArray<TextDetectorRegistryEntry> = [
642
642
  // iOS
643
643
  { platform: 'ios', pathCheck: isIOSPodfilePath, excludePaths: [], detect: detectsTrackedFilePresence, ruleId: 'heuristics.ios.dependencies.cocoapods.ast', code: 'HEURISTICS_IOS_DEPENDENCIES_COCOAPODS_AST', message: 'AST heuristic detected CocoaPods dependency files in an iOS project; Swift Package Manager remains the preferred baseline for new code.' },
644
644
  { platform: 'ios', pathCheck: isIOSCartfilePath, excludePaths: [], detect: detectsTrackedFilePresence, ruleId: 'heuristics.ios.dependencies.carthage.ast', code: 'HEURISTICS_IOS_DEPENDENCIES_CARTHAGE_AST', message: 'AST heuristic detected Carthage dependency files in an iOS project; Swift Package Manager remains the preferred baseline for new code.' },
645
- { platform: 'ios', pathCheck: isIOSSwiftPath, excludePaths: [isSwiftTestPath], detect: TextIOS.hasSwiftForceUnwrap, ruleId: 'heuristics.ios.force-unwrap.ast', code: 'HEURISTICS_IOS_FORCE_UNWRAP_AST', message: 'AST heuristic detected force unwrap usage.' },
645
+ { platform: 'ios', pathCheck: isIOSSwiftPath, excludePaths: [isSwiftTestPath], detect: TextIOS.hasSwiftForceUnwrap, locateLines: TextIOS.collectSwiftForceUnwrapLines, primaryNode: (lines) => ({ kind: 'member', name: 'force unwrap postfix !', lines }), relatedNodes: (lines) => [{ kind: 'member', name: 'replacement: guarded optional binding or explicit failure path', lines }], why: 'Force unwrap turns optional handling into a runtime crash path instead of a checked domain, UI or infrastructure decision.', impact: 'A nil value can terminate the app outside the error boundary, making production behavior non-deterministic and hard to recover or test.', expected_fix: 'Replace postfix ! with guard let, if let, nil coalescing, throwing validation, or an explicit fallback. In modern Swift tests prefer #require when the unwrap is part of an assertion contract.', ruleId: 'heuristics.ios.force-unwrap.ast', code: 'HEURISTICS_IOS_FORCE_UNWRAP_AST', message: 'AST heuristic detected force unwrap usage.' },
646
646
  { platform: 'ios', pathCheck: isIOSSwiftPath, excludePaths: [isSwiftTestPath], detect: TextIOS.hasSwiftAnyViewUsage, ruleId: 'heuristics.ios.anyview.ast', code: 'HEURISTICS_IOS_ANYVIEW_AST', message: 'AST heuristic detected AnyView usage.' },
647
647
  { platform: 'ios', pathCheck: isIOSSwiftPath, excludePaths: [isSwiftTestPath], detect: TextIOS.hasSwiftForceTryUsage, ruleId: 'heuristics.ios.force-try.ast', code: 'HEURISTICS_IOS_FORCE_TRY_AST', message: 'AST heuristic detected force try usage.' },
648
648
  { platform: 'ios', pathCheck: isIOSSwiftPath, excludePaths: [isSwiftTestPath], detect: TextIOS.hasSwiftForceCastUsage, ruleId: 'heuristics.ios.force-cast.ast', code: 'HEURISTICS_IOS_FORCE_CAST_AST', message: 'AST heuristic detected force cast usage.' },
@@ -6,6 +6,10 @@ 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.260)
10
+
11
+ - Published `pumuki@6.3.260` with AST-style line/node evidence for `skills.ios.no-force-unwrap`, making postfix `!` crashes remediable through guarded optional handling or explicit failure paths.
12
+
9
13
  ### 2026-05-14 (v6.3.259)
10
14
 
11
15
  - Published `pumuki@6.3.259` with AST-style line/node evidence for `skills.ios.prefer-swift-testing`, making modernizable `XCTestCase` suites remediable through native Swift Testing `import Testing`, `@Suite` and `@Test`.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pumuki",
3
- "version": "6.3.259",
3
+ "version": "6.3.260",
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": {