pumuki 6.3.259 → 6.3.261
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.261] - 2026-05-14
|
|
4
|
+
|
|
5
|
+
- iOS: `skills.ios.no-force-try` now emits actionable AST-style evidence for Swift `try!` expressions, including exact lines, primary/related nodes and remediation toward explicit error handling.
|
|
6
|
+
|
|
7
|
+
## [6.3.260] - 2026-05-14
|
|
8
|
+
|
|
9
|
+
- 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.
|
|
10
|
+
|
|
3
11
|
## [6.3.259] - 2026-05-14
|
|
4
12
|
|
|
5
13
|
- 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.
|
|
@@ -25,6 +25,7 @@ import {
|
|
|
25
25
|
hasSwiftEmptyCatchUsage,
|
|
26
26
|
hasSwiftForEachIndicesUsage,
|
|
27
27
|
hasSwiftForEachSelfIdentityUsage,
|
|
28
|
+
collectSwiftForceTryLines,
|
|
28
29
|
hasSwiftForceCastUsage,
|
|
29
30
|
hasSwiftFontWeightBoldUsage,
|
|
30
31
|
hasSwiftFixedFontSizeUsage,
|
|
@@ -82,6 +83,7 @@ import {
|
|
|
82
83
|
hasSwiftJSONSerializationUsage,
|
|
83
84
|
hasSwiftExplicitColorStaticMemberUsage,
|
|
84
85
|
hasSwiftClosureBasedViewBuilderContentUsage,
|
|
86
|
+
collectSwiftForceUnwrapLines,
|
|
85
87
|
hasSwiftLargeConfigContextViewPropertyUsage,
|
|
86
88
|
hasSwiftUiConditionalSameViewIdentityUsage,
|
|
87
89
|
hasSwiftUiParentOwnedSheetActionUsage,
|
|
@@ -106,6 +108,7 @@ let token = optionalToken!
|
|
|
106
108
|
let value = loadUser()!
|
|
107
109
|
`;
|
|
108
110
|
assert.equal(hasSwiftForceUnwrap(source), true);
|
|
111
|
+
assert.deepEqual(collectSwiftForceUnwrapLines(source), [2, 3]);
|
|
109
112
|
});
|
|
110
113
|
|
|
111
114
|
test('hasSwiftForceUnwrap excluye type annotations, force cast y operadores', () => {
|
|
@@ -116,6 +119,7 @@ if left != right { print("ok") }
|
|
|
116
119
|
let flag = value!!
|
|
117
120
|
`;
|
|
118
121
|
assert.equal(hasSwiftForceUnwrap(source), false);
|
|
122
|
+
assert.deepEqual(collectSwiftForceUnwrapLines(source), []);
|
|
119
123
|
});
|
|
120
124
|
|
|
121
125
|
test('hasSwiftForceUnwrap excluye comparaciones seguras contra nil', () => {
|
|
@@ -129,6 +133,7 @@ if waitersByKey[key] != nil {
|
|
|
129
133
|
}
|
|
130
134
|
`;
|
|
131
135
|
assert.equal(hasSwiftForceUnwrap(source), false);
|
|
136
|
+
assert.deepEqual(collectSwiftForceUnwrapLines(source), []);
|
|
132
137
|
});
|
|
133
138
|
|
|
134
139
|
test('hasSwiftAnyViewUsage detecta AnyView en codigo real', () => {
|
|
@@ -448,6 +453,8 @@ func load() {
|
|
|
448
453
|
`;
|
|
449
454
|
assert.equal(hasSwiftForceTryUsage(positive), true);
|
|
450
455
|
assert.equal(hasSwiftForceTryUsage(negative), false);
|
|
456
|
+
assert.deepEqual(collectSwiftForceTryLines(positive), [3]);
|
|
457
|
+
assert.deepEqual(collectSwiftForceTryLines(negative), []);
|
|
451
458
|
});
|
|
452
459
|
|
|
453
460
|
test('hasSwiftForceCastUsage detecta as! y descarta as?', () => {
|
|
@@ -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') {
|
|
@@ -1539,6 +1553,10 @@ export const hasSwiftForceTryUsage = (source: string): boolean => {
|
|
|
1539
1553
|
});
|
|
1540
1554
|
};
|
|
1541
1555
|
|
|
1556
|
+
export const collectSwiftForceTryLines = (source: string): readonly number[] => {
|
|
1557
|
+
return sortedUniqueLines(collectSwiftRegexLines(source, /\btry\s*!/));
|
|
1558
|
+
};
|
|
1559
|
+
|
|
1542
1560
|
export const hasSwiftForceCastUsage = (source: string): boolean => {
|
|
1543
1561
|
return scanCodeLikeSource(source, ({ source: swiftSource, index, current }) => {
|
|
1544
1562
|
if (current !== 'a' || !hasIdentifierAt(swiftSource, index, 'as')) {
|
|
@@ -642,9 +642,9 @@ 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
|
-
{ 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.' },
|
|
647
|
+
{ platform: 'ios', pathCheck: isIOSSwiftPath, excludePaths: [isSwiftTestPath], detect: TextIOS.hasSwiftForceTryUsage, locateLines: TextIOS.collectSwiftForceTryLines, primaryNode: (lines) => ({ kind: 'call', name: 'force try expression try!', lines }), relatedNodes: (lines) => [{ kind: 'call', name: 'replacement: do/catch or throwing boundary', lines }], why: 'Force try converts a throwable operation into an unconditional runtime crash instead of preserving the typed error boundary.', impact: 'A recoverable domain, network, persistence or decoding error can terminate the app and bypass user-facing recovery, telemetry and tests.', expected_fix: 'Replace try! with do/catch, try await propagation, throws on the current boundary, or a guarded fallback that handles the error explicitly.', 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.' },
|
|
649
649
|
{ platform: 'ios', pathCheck: isIOSSwiftPath, excludePaths: [isSwiftTestPath, isApprovedIOSBridgePath], detect: TextIOS.hasSwiftCallbackStyleSignature, ruleId: 'heuristics.ios.callback-style.ast', code: 'HEURISTICS_IOS_CALLBACK_STYLE_AST', message: 'AST heuristic detected callback-style API signature outside bridge layers.' },
|
|
650
650
|
{ platform: 'ios', pathCheck: isIOSSwiftPath, excludePaths: [isSwiftTestPath], detect: TextIOS.hasSwiftDispatchQueueUsage, ruleId: 'heuristics.ios.dispatchqueue.ast', code: 'HEURISTICS_IOS_DISPATCHQUEUE_AST', message: 'AST heuristic detected DispatchQueue usage.' },
|
|
@@ -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.261)
|
|
10
|
+
|
|
11
|
+
- Published `pumuki@6.3.261` with AST-style line/node evidence for `skills.ios.no-force-try`, making `try!` crashes remediable through `do/catch`, throwing boundaries or explicit fallback handling.
|
|
12
|
+
|
|
13
|
+
### 2026-05-14 (v6.3.260)
|
|
14
|
+
|
|
15
|
+
- 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.
|
|
16
|
+
|
|
9
17
|
### 2026-05-14 (v6.3.259)
|
|
10
18
|
|
|
11
19
|
- 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.
|
|
3
|
+
"version": "6.3.261",
|
|
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": {
|