pumuki 6.3.206 → 6.3.208
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/core/facts/detectors/text/ios.test.ts +83 -0
- package/core/facts/detectors/text/ios.ts +82 -0
- package/core/facts/extractHeuristicFacts.ts +2 -0
- package/core/rules/presets/heuristics/ios.ts +38 -0
- package/integrations/config/skillsDetectorRegistry.ts +11 -0
- package/integrations/config/skillsMarkdownRules.ts +12 -0
- package/package.json +1 -1
- package/skills.lock.json +6 -30
|
@@ -54,6 +54,8 @@ import {
|
|
|
54
54
|
hasSwiftInsecureTransportUsage,
|
|
55
55
|
hasSwiftJSONSerializationUsage,
|
|
56
56
|
hasSwiftStringFormatUsage,
|
|
57
|
+
hasSwiftStrongDelegateReferenceUsage,
|
|
58
|
+
hasSwiftStrongSelfEscapingClosureUsage,
|
|
57
59
|
hasSwiftTabItemUsage,
|
|
58
60
|
hasSwiftTaskDetachedUsage,
|
|
59
61
|
hasSwiftWaitForExpectationsUsage,
|
|
@@ -177,6 +179,87 @@ Task {
|
|
|
177
179
|
assert.equal(hasSwiftTaskDetachedUsage(negative), false);
|
|
178
180
|
});
|
|
179
181
|
|
|
182
|
+
test('hasSwiftStrongDelegateReferenceUsage detecta delegates fuertes y preserva weak delegates', () => {
|
|
183
|
+
const positive = `
|
|
184
|
+
final class CheckoutCoordinator {
|
|
185
|
+
var delegate: CheckoutCoordinatorDelegate?
|
|
186
|
+
let tableDataSource: OrdersTableDataSource
|
|
187
|
+
}
|
|
188
|
+
`;
|
|
189
|
+
const negative = `
|
|
190
|
+
final class CheckoutCoordinator {
|
|
191
|
+
weak var delegate: CheckoutCoordinatorDelegate?
|
|
192
|
+
private weak var dataSource: OrdersTableDataSource?
|
|
193
|
+
let text = "var delegate: CheckoutCoordinatorDelegate?"
|
|
194
|
+
// var delegate: CheckoutCoordinatorDelegate?
|
|
195
|
+
}
|
|
196
|
+
`;
|
|
197
|
+
|
|
198
|
+
assert.equal(hasSwiftStrongDelegateReferenceUsage(positive), true);
|
|
199
|
+
assert.equal(hasSwiftStrongDelegateReferenceUsage(negative), false);
|
|
200
|
+
});
|
|
201
|
+
|
|
202
|
+
test('hasSwiftStrongDelegateReferenceUsage no marca propiedades no delegate', () => {
|
|
203
|
+
const source = `
|
|
204
|
+
final class CheckoutCoordinator {
|
|
205
|
+
var repository: OrdersRepository
|
|
206
|
+
let presenter: CheckoutPresenter
|
|
207
|
+
}
|
|
208
|
+
`;
|
|
209
|
+
|
|
210
|
+
assert.equal(hasSwiftStrongDelegateReferenceUsage(source), false);
|
|
211
|
+
});
|
|
212
|
+
|
|
213
|
+
test('hasSwiftStrongSelfEscapingClosureUsage detecta self fuerte en closures escapables iOS', () => {
|
|
214
|
+
const source = `
|
|
215
|
+
final class CartViewModel {
|
|
216
|
+
private var cancellables = Set<AnyCancellable>()
|
|
217
|
+
|
|
218
|
+
func bind() {
|
|
219
|
+
Task {
|
|
220
|
+
await self.reload()
|
|
221
|
+
}
|
|
222
|
+
DispatchQueue.main.async {
|
|
223
|
+
self.render()
|
|
224
|
+
}
|
|
225
|
+
Timer.scheduledTimer(withTimeInterval: 1, repeats: true) { timer in
|
|
226
|
+
self.tick(timer)
|
|
227
|
+
}
|
|
228
|
+
NotificationCenter.default.addObserver(forName: .cartChanged, object: nil, queue: .main) { notification in
|
|
229
|
+
self.handle(notification)
|
|
230
|
+
}
|
|
231
|
+
publisher.sink { value in
|
|
232
|
+
self.consume(value)
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
`;
|
|
237
|
+
|
|
238
|
+
assert.equal(hasSwiftStrongSelfEscapingClosureUsage(source), true);
|
|
239
|
+
});
|
|
240
|
+
|
|
241
|
+
test('hasSwiftStrongSelfEscapingClosureUsage preserva capture lists weak/unowned e ignora comentarios y strings', () => {
|
|
242
|
+
const source = `
|
|
243
|
+
final class CartViewModel {
|
|
244
|
+
func bind() {
|
|
245
|
+
Task { [weak self] in
|
|
246
|
+
await self?.reload()
|
|
247
|
+
}
|
|
248
|
+
DispatchQueue.main.async { [unowned self] in
|
|
249
|
+
render()
|
|
250
|
+
}
|
|
251
|
+
publisher.sink(receiveValue: { [weak self] value in
|
|
252
|
+
self?.consume(value)
|
|
253
|
+
})
|
|
254
|
+
let text = "Task { self.reload() }"
|
|
255
|
+
// Timer.scheduledTimer(withTimeInterval: 1, repeats: true) { _ in self.tick() }
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
`;
|
|
259
|
+
|
|
260
|
+
assert.equal(hasSwiftStrongSelfEscapingClosureUsage(source), false);
|
|
261
|
+
});
|
|
262
|
+
|
|
180
263
|
test('detectores de logging iOS detectan logs ad-hoc y PII en produccion', () => {
|
|
181
264
|
const adHoc = `
|
|
182
265
|
print(user.id)
|
|
@@ -437,6 +437,88 @@ export const hasSwiftTaskDetachedUsage = (source: string): boolean => {
|
|
|
437
437
|
});
|
|
438
438
|
};
|
|
439
439
|
|
|
440
|
+
export const hasSwiftStrongDelegateReferenceUsage = (source: string): boolean => {
|
|
441
|
+
const delegatePropertyPattern =
|
|
442
|
+
/\b(?:var|let)\s+(?:[A-Za-z_][A-Za-z0-9_]*(?:Delegate|DataSource)|delegate|dataSource)\s*:\s*(?:any\s+)?[A-Za-z_][A-Za-z0-9_]*(?:Delegate|DataSource)\b/;
|
|
443
|
+
|
|
444
|
+
return source.split(/\r?\n/).some((line) => {
|
|
445
|
+
const sanitizedLine = stripSwiftLineForSemanticScan(line);
|
|
446
|
+
if (!delegatePropertyPattern.test(sanitizedLine)) {
|
|
447
|
+
return false;
|
|
448
|
+
}
|
|
449
|
+
return !/\bweak\s+var\b/.test(sanitizedLine);
|
|
450
|
+
});
|
|
451
|
+
};
|
|
452
|
+
|
|
453
|
+
const swiftStrongSelfEscapingClosurePatterns = [
|
|
454
|
+
/\bTask\s*(?:\([^)]*\))?\s*\{/g,
|
|
455
|
+
/\bDispatchQueue\s*\.\s*[A-Za-z0-9_.]+\s*\.\s*async(?:After)?\s*(?:\([^)]*\))?\s*\{/g,
|
|
456
|
+
/\bTimer\s*\.\s*scheduledTimer\s*\([\s\S]{0,320}?\)\s*\{/g,
|
|
457
|
+
/\bNotificationCenter\s*\.\s*default\s*\.\s*addObserver\s*\([\s\S]{0,420}?\busing\s*:\s*\{/g,
|
|
458
|
+
/\.\s*sink\s*\([\s\S]{0,420}?\b(?:receiveValue|receiveCompletion)\s*:\s*\{/g,
|
|
459
|
+
/\.\s*sink\s*\{/g,
|
|
460
|
+
/\.\s*handleEvents\s*\([\s\S]{0,420}?\b(?:receiveOutput|receiveCompletion|receiveCancel)\s*:\s*\{/g,
|
|
461
|
+
];
|
|
462
|
+
|
|
463
|
+
const findMatchingSwiftBraceIndex = (source: string, openingBraceIndex: number): number => {
|
|
464
|
+
let depth = 0;
|
|
465
|
+
for (let index = openingBraceIndex; index < source.length; index += 1) {
|
|
466
|
+
const char = source[index];
|
|
467
|
+
if (char === '{') {
|
|
468
|
+
depth += 1;
|
|
469
|
+
continue;
|
|
470
|
+
}
|
|
471
|
+
if (char !== '}') {
|
|
472
|
+
continue;
|
|
473
|
+
}
|
|
474
|
+
depth -= 1;
|
|
475
|
+
if (depth === 0) {
|
|
476
|
+
return index;
|
|
477
|
+
}
|
|
478
|
+
}
|
|
479
|
+
return -1;
|
|
480
|
+
};
|
|
481
|
+
|
|
482
|
+
const hasWeakOrUnownedSelfCaptureList = (closureBody: string): boolean => {
|
|
483
|
+
const trimmedStart = closureBody.trimStart();
|
|
484
|
+
if (!trimmedStart.startsWith('[')) {
|
|
485
|
+
return false;
|
|
486
|
+
}
|
|
487
|
+
const captureListEndIndex = trimmedStart.indexOf(']');
|
|
488
|
+
if (captureListEndIndex < 0) {
|
|
489
|
+
return false;
|
|
490
|
+
}
|
|
491
|
+
const captureList = trimmedStart.slice(1, captureListEndIndex);
|
|
492
|
+
return /\b(?:weak|unowned)\s+self\b/.test(captureList);
|
|
493
|
+
};
|
|
494
|
+
|
|
495
|
+
export const hasSwiftStrongSelfEscapingClosureUsage = (source: string): boolean => {
|
|
496
|
+
const sanitized = sanitizeSwiftSourceForMultilineRegex(source);
|
|
497
|
+
for (const pattern of swiftStrongSelfEscapingClosurePatterns) {
|
|
498
|
+
pattern.lastIndex = 0;
|
|
499
|
+
for (const match of sanitized.matchAll(pattern)) {
|
|
500
|
+
const matchedSource = match[0] ?? '';
|
|
501
|
+
const openingBraceOffset = matchedSource.lastIndexOf('{');
|
|
502
|
+
if (openingBraceOffset < 0 || match.index === undefined) {
|
|
503
|
+
continue;
|
|
504
|
+
}
|
|
505
|
+
const openingBraceIndex = match.index + openingBraceOffset;
|
|
506
|
+
const closingBraceIndex = findMatchingSwiftBraceIndex(sanitized, openingBraceIndex);
|
|
507
|
+
if (closingBraceIndex < 0) {
|
|
508
|
+
continue;
|
|
509
|
+
}
|
|
510
|
+
const closureBody = sanitized.slice(openingBraceIndex + 1, closingBraceIndex);
|
|
511
|
+
if (hasWeakOrUnownedSelfCaptureList(closureBody)) {
|
|
512
|
+
continue;
|
|
513
|
+
}
|
|
514
|
+
if (/\bself\s*\./.test(closureBody)) {
|
|
515
|
+
return true;
|
|
516
|
+
}
|
|
517
|
+
}
|
|
518
|
+
}
|
|
519
|
+
return false;
|
|
520
|
+
};
|
|
521
|
+
|
|
440
522
|
export const hasSwiftAdHocLoggingUsage = (source: string): boolean => {
|
|
441
523
|
return collectSwiftRegexLines(
|
|
442
524
|
source,
|
|
@@ -646,6 +646,8 @@ const textDetectorRegistry: ReadonlyArray<TextDetectorRegistryEntry> = [
|
|
|
646
646
|
{ platform: 'ios', pathCheck: isIOSSwiftPath, excludePaths: [isSwiftTestPath], detect: TextIOS.hasSwiftDispatchSemaphoreUsage, ruleId: 'heuristics.ios.dispatchsemaphore.ast', code: 'HEURISTICS_IOS_DISPATCHSEMAPHORE_AST', message: 'AST heuristic detected DispatchSemaphore usage.' },
|
|
647
647
|
{ platform: 'ios', pathCheck: isIOSSwiftPath, excludePaths: [isSwiftTestPath], detect: TextIOS.hasSwiftOperationQueueUsage, ruleId: 'heuristics.ios.operation-queue.ast', code: 'HEURISTICS_IOS_OPERATION_QUEUE_AST', message: 'AST heuristic detected OperationQueue usage.' },
|
|
648
648
|
{ platform: 'ios', pathCheck: isIOSSwiftPath, excludePaths: [isSwiftTestPath], detect: TextIOS.hasSwiftTaskDetachedUsage, ruleId: 'heuristics.ios.task-detached.ast', code: 'HEURISTICS_IOS_TASK_DETACHED_AST', message: 'AST heuristic detected Task.detached usage.' },
|
|
649
|
+
{ platform: 'ios', pathCheck: isIOSSwiftPath, excludePaths: [isSwiftTestPath], detect: TextIOS.hasSwiftStrongDelegateReferenceUsage, ruleId: 'heuristics.ios.memory.strong-delegate.ast', code: 'HEURISTICS_IOS_MEMORY_STRONG_DELEGATE_AST', message: 'AST heuristic detected a strong delegate/dataSource reference; weak delegates remain the preferred baseline to avoid retain cycles.' },
|
|
650
|
+
{ platform: 'ios', pathCheck: isIOSSwiftPath, excludePaths: [isSwiftTestPath], detect: TextIOS.hasSwiftStrongSelfEscapingClosureUsage, ruleId: 'heuristics.ios.memory.strong-self-escaping-closure.ast', code: 'HEURISTICS_IOS_MEMORY_STRONG_SELF_ESCAPING_CLOSURE_AST', message: 'AST heuristic detected strong self capture in an escaping iOS closure; weak or unowned captures remain the preferred baseline when ownership is not explicit.' },
|
|
649
651
|
{ platform: 'ios', pathCheck: isIOSSwiftPath, excludePaths: [isSwiftTestPath], detect: TextIOS.hasSwiftAdHocLoggingUsage, ruleId: 'heuristics.ios.logging.adhoc-print.ast', code: 'HEURISTICS_IOS_LOGGING_ADHOC_PRINT_AST', message: 'AST heuristic detected print/debugPrint/dump/NSLog/os_log usage in iOS production code.' },
|
|
650
652
|
{ platform: 'ios', pathCheck: isIOSSwiftPath, excludePaths: [isSwiftTestPath], detect: TextIOS.hasSwiftSensitiveLoggingUsage, ruleId: 'heuristics.ios.logging.sensitive-data.ast', code: 'HEURISTICS_IOS_LOGGING_SENSITIVE_DATA_AST', message: 'AST heuristic detected sensitive data in an iOS logging call.' },
|
|
651
653
|
{ platform: 'ios', pathCheck: isIOSSwiftPath, excludePaths: [isSwiftTestPath], detect: TextIOS.hasSwiftAlamofireUsage, ruleId: 'heuristics.ios.networking.alamofire.ast', code: 'HEURISTICS_IOS_NETWORKING_ALAMOFIRE_AST', message: 'AST heuristic detected Alamofire usage in iOS production code; URLSession remains the preferred baseline for new code.' },
|
|
@@ -181,6 +181,44 @@ export const iosRules: RuleSet = [
|
|
|
181
181
|
code: 'HEURISTICS_IOS_TASK_DETACHED_AST',
|
|
182
182
|
},
|
|
183
183
|
},
|
|
184
|
+
{
|
|
185
|
+
id: 'heuristics.ios.memory.strong-delegate.ast',
|
|
186
|
+
description: 'Detects strong delegate/dataSource references in iOS production code.',
|
|
187
|
+
severity: 'WARN',
|
|
188
|
+
platform: 'ios',
|
|
189
|
+
locked: true,
|
|
190
|
+
when: {
|
|
191
|
+
kind: 'Heuristic',
|
|
192
|
+
where: {
|
|
193
|
+
ruleId: 'heuristics.ios.memory.strong-delegate.ast',
|
|
194
|
+
},
|
|
195
|
+
},
|
|
196
|
+
then: {
|
|
197
|
+
kind: 'Finding',
|
|
198
|
+
message:
|
|
199
|
+
'AST heuristic detected a strong delegate/dataSource reference; weak delegates remain the preferred baseline to avoid retain cycles.',
|
|
200
|
+
code: 'HEURISTICS_IOS_MEMORY_STRONG_DELEGATE_AST',
|
|
201
|
+
},
|
|
202
|
+
},
|
|
203
|
+
{
|
|
204
|
+
id: 'heuristics.ios.memory.strong-self-escaping-closure.ast',
|
|
205
|
+
description: 'Detects strong self captures in escaping iOS closures.',
|
|
206
|
+
severity: 'WARN',
|
|
207
|
+
platform: 'ios',
|
|
208
|
+
locked: true,
|
|
209
|
+
when: {
|
|
210
|
+
kind: 'Heuristic',
|
|
211
|
+
where: {
|
|
212
|
+
ruleId: 'heuristics.ios.memory.strong-self-escaping-closure.ast',
|
|
213
|
+
},
|
|
214
|
+
},
|
|
215
|
+
then: {
|
|
216
|
+
kind: 'Finding',
|
|
217
|
+
message:
|
|
218
|
+
'AST heuristic detected strong self capture in an escaping iOS closure; weak or unowned captures remain the preferred baseline when ownership is not explicit.',
|
|
219
|
+
code: 'HEURISTICS_IOS_MEMORY_STRONG_SELF_ESCAPING_CLOSURE_AST',
|
|
220
|
+
},
|
|
221
|
+
},
|
|
184
222
|
{
|
|
185
223
|
id: 'heuristics.ios.logging.adhoc-print.ast',
|
|
186
224
|
description: 'Detects print/debugPrint/dump/NSLog/os_log usage in iOS production code.',
|
|
@@ -47,6 +47,17 @@ const registryByRuleId: Record<string, SkillsDetectorBinding> = {
|
|
|
47
47
|
'skills.ios.no-task-detached': heuristicDetector('ios.task-detached', [
|
|
48
48
|
'heuristics.ios.task-detached.ast',
|
|
49
49
|
]),
|
|
50
|
+
'skills.ios.guideline.ios.delegation-pattern-weak-delegates-para-evitar-retain-cycles': heuristicDetector(
|
|
51
|
+
'ios.memory.strong-delegate',
|
|
52
|
+
['heuristics.ios.memory.strong-delegate.ast']
|
|
53
|
+
),
|
|
54
|
+
'skills.ios.guideline.ios.evitar-retain-cycles-especialmente-en-closures-delegates': heuristicDetector(
|
|
55
|
+
'ios.memory.retain-cycles',
|
|
56
|
+
[
|
|
57
|
+
'heuristics.ios.memory.strong-delegate.ast',
|
|
58
|
+
'heuristics.ios.memory.strong-self-escaping-closure.ast',
|
|
59
|
+
]
|
|
60
|
+
),
|
|
50
61
|
'skills.ios.guideline.ios.prohibido-print-y-logs-ad-hoc': heuristicDetector(
|
|
51
62
|
'ios.logging.adhoc-print',
|
|
52
63
|
['heuristics.ios.logging.adhoc-print.ast']
|
|
@@ -423,6 +423,18 @@ const normalizeKnownRuleTarget = (
|
|
|
423
423
|
) {
|
|
424
424
|
return 'skills.ios.guideline.ios.accessibility-labels-accessibilitylabel';
|
|
425
425
|
}
|
|
426
|
+
if (includes('weak delegates') || includes('delegation pattern')) {
|
|
427
|
+
return 'skills.ios.guideline.ios.delegation-pattern-weak-delegates-para-evitar-retain-cycles';
|
|
428
|
+
}
|
|
429
|
+
if (
|
|
430
|
+
includes('closures delegates') ||
|
|
431
|
+
includes('weak self') ||
|
|
432
|
+
includes('capture list') ||
|
|
433
|
+
includes('avoid retain cycles') ||
|
|
434
|
+
includes('evitar retain cycles')
|
|
435
|
+
) {
|
|
436
|
+
return 'skills.ios.guideline.ios.evitar-retain-cycles-especialmente-en-closures-delegates';
|
|
437
|
+
}
|
|
426
438
|
if (
|
|
427
439
|
includes('mixing legacy xctest style') ||
|
|
428
440
|
includes('mixed xctest and swift testing') ||
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pumuki",
|
|
3
|
-
"version": "6.3.
|
|
3
|
+
"version": "6.3.208",
|
|
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": {
|
package/skills.lock.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": "1.0",
|
|
3
3
|
"compilerVersion": "1.0.0",
|
|
4
|
-
"generatedAt": "2026-05-13T12:
|
|
4
|
+
"generatedAt": "2026-05-13T12:37:42.811Z",
|
|
5
5
|
"bundles": [
|
|
6
6
|
{
|
|
7
7
|
"name": "android-guidelines",
|
|
@@ -5764,7 +5764,7 @@
|
|
|
5764
5764
|
"name": "ios-guidelines",
|
|
5765
5765
|
"version": "1.0.0",
|
|
5766
5766
|
"source": "file:vendor/skills/ios-enterprise-rules/SKILL.md",
|
|
5767
|
-
"hash": "
|
|
5767
|
+
"hash": "32c74edc740622834bf48fa060ebc04f8d5ee0c826e9a6dd48a068212dfc2552",
|
|
5768
5768
|
"rules": [
|
|
5769
5769
|
{
|
|
5770
5770
|
"id": "skills.ios.guideline.ios.accessibility-identifiers-para-localizar-elementos",
|
|
@@ -6042,18 +6042,6 @@
|
|
|
6042
6042
|
"evaluationMode": "DECLARATIVE",
|
|
6043
6043
|
"origin": "core"
|
|
6044
6044
|
},
|
|
6045
|
-
{
|
|
6046
|
-
"id": "skills.ios.guideline.ios.capture-lists-capturar-valores-no-referencias",
|
|
6047
|
-
"description": "Capture lists - Capturar valores, no referencias",
|
|
6048
|
-
"severity": "WARN",
|
|
6049
|
-
"platform": "ios",
|
|
6050
|
-
"sourceSkill": "ios-guidelines",
|
|
6051
|
-
"sourcePath": "vendor/skills/ios-enterprise-rules/SKILL.md",
|
|
6052
|
-
"confidence": "MEDIUM",
|
|
6053
|
-
"locked": true,
|
|
6054
|
-
"evaluationMode": "DECLARATIVE",
|
|
6055
|
-
"origin": "core"
|
|
6056
|
-
},
|
|
6057
6045
|
{
|
|
6058
6046
|
"id": "skills.ios.guideline.ios.carthage-prohibido",
|
|
6059
6047
|
"description": "Carthage - Prohibido",
|
|
@@ -6363,7 +6351,7 @@
|
|
|
6363
6351
|
"sourcePath": "vendor/skills/ios-enterprise-rules/SKILL.md",
|
|
6364
6352
|
"confidence": "MEDIUM",
|
|
6365
6353
|
"locked": true,
|
|
6366
|
-
"evaluationMode": "
|
|
6354
|
+
"evaluationMode": "AUTO",
|
|
6367
6355
|
"origin": "core"
|
|
6368
6356
|
},
|
|
6369
6357
|
{
|
|
@@ -6512,14 +6500,14 @@
|
|
|
6512
6500
|
},
|
|
6513
6501
|
{
|
|
6514
6502
|
"id": "skills.ios.guideline.ios.evitar-retain-cycles-especialmente-en-closures-delegates",
|
|
6515
|
-
"description": "
|
|
6516
|
-
"severity": "
|
|
6503
|
+
"description": "[weak self] - En closures que pueden outlive self",
|
|
6504
|
+
"severity": "WARN",
|
|
6517
6505
|
"platform": "ios",
|
|
6518
6506
|
"sourceSkill": "ios-guidelines",
|
|
6519
6507
|
"sourcePath": "vendor/skills/ios-enterprise-rules/SKILL.md",
|
|
6520
6508
|
"confidence": "MEDIUM",
|
|
6521
6509
|
"locked": true,
|
|
6522
|
-
"evaluationMode": "
|
|
6510
|
+
"evaluationMode": "AUTO",
|
|
6523
6511
|
"origin": "core"
|
|
6524
6512
|
},
|
|
6525
6513
|
{
|
|
@@ -8251,18 +8239,6 @@
|
|
|
8251
8239
|
"evaluationMode": "DECLARATIVE",
|
|
8252
8240
|
"origin": "core"
|
|
8253
8241
|
},
|
|
8254
|
-
{
|
|
8255
|
-
"id": "skills.ios.guideline.ios.weak-self-en-closures-que-pueden-outlive-self",
|
|
8256
|
-
"description": "[weak self] - En closures que pueden outlive self",
|
|
8257
|
-
"severity": "WARN",
|
|
8258
|
-
"platform": "ios",
|
|
8259
|
-
"sourceSkill": "ios-guidelines",
|
|
8260
|
-
"sourcePath": "vendor/skills/ios-enterprise-rules/SKILL.md",
|
|
8261
|
-
"confidence": "MEDIUM",
|
|
8262
|
-
"locked": true,
|
|
8263
|
-
"evaluationMode": "DECLARATIVE",
|
|
8264
|
-
"origin": "core"
|
|
8265
|
-
},
|
|
8266
8242
|
{
|
|
8267
8243
|
"id": "skills.ios.guideline.ios.xcode-usar-la-u-ltima-versio-n-estable-disponible",
|
|
8268
8244
|
"description": "Xcode: usar la última versión estable disponible",
|