pumuki 6.3.198 → 6.3.200
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 +49 -0
- package/core/facts/detectors/text/ios.ts +49 -0
- package/core/facts/extractHeuristicFacts.ts +2 -0
- package/core/rules/presets/heuristics/ios.test.ts +11 -1
- package/core/rules/presets/heuristics/ios.ts +36 -0
- package/docs/codex-skills/ios-enterprise-rules.md +15 -0
- package/integrations/config/skillsDetectorRegistry.ts +12 -0
- package/integrations/config/skillsMarkdownRules.ts +6 -0
- package/package.json +1 -1
- package/skills.lock.json +5 -29
|
@@ -21,6 +21,8 @@ import {
|
|
|
21
21
|
hasSwiftForceTryUsage,
|
|
22
22
|
hasSwiftForceUnwrap,
|
|
23
23
|
hasSwiftGeometryReaderUsage,
|
|
24
|
+
hasSwiftHardcodedUiStringUsage,
|
|
25
|
+
hasSwiftLooseAssetResourceUsage,
|
|
24
26
|
hasSwiftLegacyOnChangeUsage,
|
|
25
27
|
hasSwiftLegacyExpectationDescriptionUsage,
|
|
26
28
|
hasSwiftLegacySwiftUiObservableWrapperUsage,
|
|
@@ -268,6 +270,53 @@ let text = "https://example.com/catalog.json"
|
|
|
268
270
|
assert.equal(hasSwiftInsecureTransportUsage(ignored), false);
|
|
269
271
|
});
|
|
270
272
|
|
|
273
|
+
test('detector iOS de localización detecta strings UI hardcodeadas sin confundir keys ni comentarios', () => {
|
|
274
|
+
const source = `
|
|
275
|
+
struct PaywallView: View {
|
|
276
|
+
var body: some View {
|
|
277
|
+
VStack {
|
|
278
|
+
Text("Start premium trial")
|
|
279
|
+
Button("Continue") {}
|
|
280
|
+
Label("Your orders", systemImage: "cart")
|
|
281
|
+
TextField("Search products", text: $query)
|
|
282
|
+
EmptyView().navigationTitle("Account details")
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
`;
|
|
287
|
+
const ignored = `
|
|
288
|
+
struct OrdersView: View {
|
|
289
|
+
var body: some View {
|
|
290
|
+
Text(String(localized: "orders.title"))
|
|
291
|
+
Text("orders.title")
|
|
292
|
+
Button(String(localized: "orders.checkout")) {}
|
|
293
|
+
let sample = "Text(\\"Start premium trial\\")"
|
|
294
|
+
// Text("Debug")
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
`;
|
|
298
|
+
|
|
299
|
+
assert.equal(hasSwiftHardcodedUiStringUsage(source), true);
|
|
300
|
+
assert.equal(hasSwiftHardcodedUiStringUsage(ignored), false);
|
|
301
|
+
});
|
|
302
|
+
|
|
303
|
+
test('detector iOS de assets detecta recursos sueltos sin confundir asset catalogs', () => {
|
|
304
|
+
const source = `
|
|
305
|
+
let path = Bundle.main.path(forResource: "hero", withExtension: "png")
|
|
306
|
+
let url = Bundle.main.url(forResource: "logo", withExtension: "pdf")
|
|
307
|
+
let image = UIImage(contentsOfFile: path)
|
|
308
|
+
`;
|
|
309
|
+
const ignored = `
|
|
310
|
+
Image("hero")
|
|
311
|
+
UIImage(named: "hero")
|
|
312
|
+
let text = "UIImage(contentsOfFile: path)"
|
|
313
|
+
// Bundle.main.path(forResource: "hero", withExtension: "png")
|
|
314
|
+
`;
|
|
315
|
+
|
|
316
|
+
assert.equal(hasSwiftLooseAssetResourceUsage(source), true);
|
|
317
|
+
assert.equal(hasSwiftLooseAssetResourceUsage(ignored), false);
|
|
318
|
+
});
|
|
319
|
+
|
|
271
320
|
test('hasSwiftUncheckedSendableUsage detecta @unchecked Sendable', () => {
|
|
272
321
|
const source = `
|
|
273
322
|
final class LegacyBox: @unchecked Sendable {}
|
|
@@ -511,6 +511,55 @@ export const hasSwiftInsecureTransportUsage = (source: string): boolean => {
|
|
|
511
511
|
);
|
|
512
512
|
};
|
|
513
513
|
|
|
514
|
+
const swiftUiLiteralTextPatterns = [
|
|
515
|
+
/\b(?:Text|Button|Label|TextField|SecureField)\s*\(\s*"((?:\\.|[^"\\])*)"/,
|
|
516
|
+
/\.navigationTitle\s*\(\s*"((?:\\.|[^"\\])*)"/,
|
|
517
|
+
/\.navigationSubtitle\s*\(\s*"((?:\\.|[^"\\])*)"/,
|
|
518
|
+
/\.accessibilityLabel\s*\(\s*"((?:\\.|[^"\\])*)"/,
|
|
519
|
+
];
|
|
520
|
+
|
|
521
|
+
const looksLikeLocalizationKey = (value: string): boolean => {
|
|
522
|
+
return /^[A-Za-z0-9_]+(?:[.-][A-Za-z0-9_]+)+$/.test(value);
|
|
523
|
+
};
|
|
524
|
+
|
|
525
|
+
export const hasSwiftHardcodedUiStringUsage = (source: string): boolean => {
|
|
526
|
+
const withoutBlockComments = source.replace(/\/\*[\s\S]*?\*\//g, '\n');
|
|
527
|
+
return withoutBlockComments.split(/\r?\n/).some((line) => {
|
|
528
|
+
if (/^\s*\/\//.test(line)) {
|
|
529
|
+
return false;
|
|
530
|
+
}
|
|
531
|
+
const withoutInlineComment = line.replace(/\/\/.*$/, '');
|
|
532
|
+
return swiftUiLiteralTextPatterns.some((pattern) => {
|
|
533
|
+
const match = withoutInlineComment.match(pattern);
|
|
534
|
+
if (!match) {
|
|
535
|
+
return false;
|
|
536
|
+
}
|
|
537
|
+
const literal = match[1]?.trim() ?? '';
|
|
538
|
+
if (literal.length === 0) {
|
|
539
|
+
return false;
|
|
540
|
+
}
|
|
541
|
+
return !looksLikeLocalizationKey(literal);
|
|
542
|
+
});
|
|
543
|
+
});
|
|
544
|
+
};
|
|
545
|
+
|
|
546
|
+
export const hasSwiftLooseAssetResourceUsage = (source: string): boolean => {
|
|
547
|
+
const withoutBlockComments = source.replace(/\/\*[\s\S]*?\*\//g, '\n');
|
|
548
|
+
return withoutBlockComments.split(/\r?\n/).some((line) => {
|
|
549
|
+
if (/^\s*\/\//.test(line)) {
|
|
550
|
+
return false;
|
|
551
|
+
}
|
|
552
|
+
const sanitized = stripSwiftLineForSemanticScan(line);
|
|
553
|
+
return (
|
|
554
|
+
/\bUIImage\s*\(\s*contentsOfFile\s*:/.test(sanitized) ||
|
|
555
|
+
/\bNSImage\s*\(\s*contentsOfFile\s*:/.test(sanitized) ||
|
|
556
|
+
/\bBundle\s*\.\s*main\s*\.\s*(?:path|url)\s*\(\s*forResource\s*:\s*""\s*,\s*withExtension\s*:\s*""/.test(
|
|
557
|
+
sanitized
|
|
558
|
+
)
|
|
559
|
+
);
|
|
560
|
+
});
|
|
561
|
+
};
|
|
562
|
+
|
|
514
563
|
export const hasSwiftUncheckedSendableUsage = (source: string): boolean => {
|
|
515
564
|
return scanCodeLikeSource(source, ({ source: swiftSource, index, current }) => {
|
|
516
565
|
if (current !== '@' || !swiftSource.startsWith('@unchecked', index)) {
|
|
@@ -654,6 +654,8 @@ const textDetectorRegistry: ReadonlyArray<TextDetectorRegistryEntry> = [
|
|
|
654
654
|
{ platform: 'ios', pathCheck: isIOSSwiftPath, excludePaths: [isSwiftTestPath], detect: TextIOS.hasSwiftInsecureTransportUsage, ruleId: 'heuristics.ios.security.insecure-transport.ast', code: 'HEURISTICS_IOS_SECURITY_INSECURE_TRANSPORT_AST', message: 'AST heuristic detected insecure HTTP transport in iOS production code; HTTPS and ATS remain the preferred baseline.' },
|
|
655
655
|
{ platform: 'ios', pathCheck: isIOSInfoPlistPath, excludePaths: [], detect: TextIOS.hasSwiftInsecureTransportUsage, ruleId: 'heuristics.ios.security.insecure-transport.ast', code: 'HEURISTICS_IOS_SECURITY_INSECURE_TRANSPORT_AST', message: 'AST heuristic detected permissive App Transport Security configuration; HTTPS and ATS remain the preferred baseline.' },
|
|
656
656
|
{ platform: 'ios', pathCheck: isIOSLocalizableStringsPath, excludePaths: [], detect: detectsTrackedFilePresence, ruleId: 'heuristics.ios.localization.localizable-strings.ast', code: 'HEURISTICS_IOS_LOCALIZATION_LOCALIZABLE_STRINGS_AST', message: 'AST heuristic detected Localizable.strings usage; String Catalogs (.xcstrings) remain the preferred baseline for new localization work.' },
|
|
657
|
+
{ platform: 'ios', pathCheck: isIOSSwiftPath, excludePaths: [isSwiftTestPath], detect: TextIOS.hasSwiftHardcodedUiStringUsage, ruleId: 'heuristics.ios.localization.hardcoded-ui-string.ast', code: 'HEURISTICS_IOS_LOCALIZATION_HARDCODED_UI_STRING_AST', message: 'AST heuristic detected hardcoded user-facing SwiftUI text; String(localized:) and String Catalogs remain the preferred baseline.' },
|
|
658
|
+
{ platform: 'ios', pathCheck: isIOSSwiftPath, excludePaths: [isSwiftTestPath], detect: TextIOS.hasSwiftLooseAssetResourceUsage, ruleId: 'heuristics.ios.assets.loose-resource.ast', code: 'HEURISTICS_IOS_ASSETS_LOOSE_RESOURCE_AST', message: 'AST heuristic detected loose image resource loading in iOS production code; Asset Catalogs remain the preferred baseline.' },
|
|
657
659
|
{ platform: 'ios', pathCheck: isIOSSwiftPath, excludePaths: [isSwiftTestPath], detect: TextIOS.hasSwiftUncheckedSendableUsage, ruleId: 'heuristics.ios.unchecked-sendable.ast', code: 'HEURISTICS_IOS_UNCHECKED_SENDABLE_AST', message: 'AST heuristic detected @unchecked Sendable usage.' },
|
|
658
660
|
{ platform: 'ios', pathCheck: isIOSSwiftPath, excludePaths: [isSwiftTestPath], detect: TextIOS.hasSwiftPreconcurrencyUsage, ruleId: 'heuristics.ios.preconcurrency.ast', code: 'HEURISTICS_IOS_PRECONCURRENCY_AST', message: 'AST heuristic detected @preconcurrency usage.' },
|
|
659
661
|
{ platform: 'ios', pathCheck: isIOSSwiftPath, excludePaths: [isSwiftTestPath], detect: TextIOS.hasSwiftNonisolatedUnsafeUsage, ruleId: 'heuristics.ios.nonisolated-unsafe.ast', code: 'HEURISTICS_IOS_NONISOLATED_UNSAFE_AST', message: 'AST heuristic detected nonisolated(unsafe) usage.' },
|
|
@@ -3,7 +3,7 @@ import test from 'node:test';
|
|
|
3
3
|
import { iosRules } from './ios';
|
|
4
4
|
|
|
5
5
|
test('iosRules define reglas heurísticas locked para plataforma ios', () => {
|
|
6
|
-
assert.equal(iosRules.length,
|
|
6
|
+
assert.equal(iosRules.length, 54);
|
|
7
7
|
|
|
8
8
|
const ids = iosRules.map((rule) => rule.id);
|
|
9
9
|
assert.deepEqual(ids, [
|
|
@@ -26,6 +26,8 @@ test('iosRules define reglas heurísticas locked para plataforma ios', () => {
|
|
|
26
26
|
'heuristics.ios.security.userdefaults-sensitive-data.ast',
|
|
27
27
|
'heuristics.ios.security.insecure-transport.ast',
|
|
28
28
|
'heuristics.ios.localization.localizable-strings.ast',
|
|
29
|
+
'heuristics.ios.localization.hardcoded-ui-string.ast',
|
|
30
|
+
'heuristics.ios.assets.loose-resource.ast',
|
|
29
31
|
'heuristics.ios.unchecked-sendable.ast',
|
|
30
32
|
'heuristics.ios.preconcurrency.ast',
|
|
31
33
|
'heuristics.ios.nonisolated-unsafe.ast',
|
|
@@ -106,6 +108,14 @@ test('iosRules define reglas heurísticas locked para plataforma ios', () => {
|
|
|
106
108
|
byId.get('heuristics.ios.localization.localizable-strings.ast')?.then.code,
|
|
107
109
|
'HEURISTICS_IOS_LOCALIZATION_LOCALIZABLE_STRINGS_AST'
|
|
108
110
|
);
|
|
111
|
+
assert.equal(
|
|
112
|
+
byId.get('heuristics.ios.localization.hardcoded-ui-string.ast')?.then.code,
|
|
113
|
+
'HEURISTICS_IOS_LOCALIZATION_HARDCODED_UI_STRING_AST'
|
|
114
|
+
);
|
|
115
|
+
assert.equal(
|
|
116
|
+
byId.get('heuristics.ios.assets.loose-resource.ast')?.then.code,
|
|
117
|
+
'HEURISTICS_IOS_ASSETS_LOOSE_RESOURCE_AST'
|
|
118
|
+
);
|
|
109
119
|
assert.equal(
|
|
110
120
|
byId.get('heuristics.ios.preconcurrency.ast')?.then.code,
|
|
111
121
|
'HEURISTICS_IOS_PRECONCURRENCY_AST'
|
|
@@ -343,6 +343,42 @@ export const iosRules: RuleSet = [
|
|
|
343
343
|
code: 'HEURISTICS_IOS_LOCALIZATION_LOCALIZABLE_STRINGS_AST',
|
|
344
344
|
},
|
|
345
345
|
},
|
|
346
|
+
{
|
|
347
|
+
id: 'heuristics.ios.localization.hardcoded-ui-string.ast',
|
|
348
|
+
description: 'Detects hardcoded user-facing SwiftUI text where String(localized:) and String Catalogs are preferred.',
|
|
349
|
+
severity: 'WARN',
|
|
350
|
+
platform: 'ios',
|
|
351
|
+
locked: true,
|
|
352
|
+
when: {
|
|
353
|
+
kind: 'Heuristic',
|
|
354
|
+
where: {
|
|
355
|
+
ruleId: 'heuristics.ios.localization.hardcoded-ui-string.ast',
|
|
356
|
+
},
|
|
357
|
+
},
|
|
358
|
+
then: {
|
|
359
|
+
kind: 'Finding',
|
|
360
|
+
message: 'AST heuristic detected hardcoded user-facing SwiftUI text; String(localized:) and String Catalogs remain the preferred baseline.',
|
|
361
|
+
code: 'HEURISTICS_IOS_LOCALIZATION_HARDCODED_UI_STRING_AST',
|
|
362
|
+
},
|
|
363
|
+
},
|
|
364
|
+
{
|
|
365
|
+
id: 'heuristics.ios.assets.loose-resource.ast',
|
|
366
|
+
description: 'Detects loose image resource loading where Asset Catalogs are the preferred iOS baseline.',
|
|
367
|
+
severity: 'WARN',
|
|
368
|
+
platform: 'ios',
|
|
369
|
+
locked: true,
|
|
370
|
+
when: {
|
|
371
|
+
kind: 'Heuristic',
|
|
372
|
+
where: {
|
|
373
|
+
ruleId: 'heuristics.ios.assets.loose-resource.ast',
|
|
374
|
+
},
|
|
375
|
+
},
|
|
376
|
+
then: {
|
|
377
|
+
kind: 'Finding',
|
|
378
|
+
message: 'AST heuristic detected loose image resource loading in iOS production code; Asset Catalogs remain the preferred baseline.',
|
|
379
|
+
code: 'HEURISTICS_IOS_ASSETS_LOOSE_RESOURCE_AST',
|
|
380
|
+
},
|
|
381
|
+
},
|
|
346
382
|
{
|
|
347
383
|
id: 'heuristics.ios.unchecked-sendable.ast',
|
|
348
384
|
description: 'Detects @unchecked Sendable usage in iOS production code.',
|
|
@@ -607,6 +607,21 @@ struct APIEndpoint: Sendable {
|
|
|
607
607
|
- `skills.ios.guideline.ios.app-transport-security-ats-https-por-defecto` se mapea a `heuristics.ios.security.insecure-transport.ast`.
|
|
608
608
|
- En `PROJECT MODE: brownfield`, este hallazgo detecta `http://` en Swift production y `NSAllowsArbitraryLoads=true` en `Info.plist` como señal de baseline/adopción sin bloquear deuda histórica salvo promoción explícita de policy. HTTPS y ATS permanecen como baseline preferente.
|
|
609
609
|
|
|
610
|
+
### Enforcement AST inicial de localización iOS
|
|
611
|
+
|
|
612
|
+
- `skills.ios.guideline.ios.localizable-strings-deprecado-usar-string-catalogs` se mapea a `heuristics.ios.localization.localizable-strings.ast`.
|
|
613
|
+
- `skills.ios.guideline.ios.string-catalogs-xcstrings` se mapea a `heuristics.ios.localization.localizable-strings.ast`.
|
|
614
|
+
- `skills.ios.guideline.ios.string-catalogs-xcstrings-sistema-moderno-de-localizacio-n-xcode-15` se mapea a `heuristics.ios.localization.localizable-strings.ast`.
|
|
615
|
+
- `skills.ios.guideline.ios.cero-strings-hardcodeadas-en-ui` se mapea a `heuristics.ios.localization.hardcoded-ui-string.ast`.
|
|
616
|
+
- `skills.ios.guideline.ios.string-localized-api-moderna-para-strings-traducibles` se mapea a `heuristics.ios.localization.hardcoded-ui-string.ast`.
|
|
617
|
+
- En `PROJECT MODE: brownfield`, este hallazgo detecta `Localizable.strings` bajo `apps/ios/**` como señal de baseline/adopción sin bloquear deuda histórica salvo promoción explícita de policy. String Catalogs (`.xcstrings`) permanece como baseline preferente.
|
|
618
|
+
- También detecta literales de texto visibles en SwiftUI (`Text`, `Button`, `Label`, `TextField`, `SecureField`, `navigationTitle`, `accessibilityLabel`) como señal de adopción hacia `String(localized:)` y String Catalogs, ignorando keys como `orders.title`.
|
|
619
|
+
|
|
620
|
+
### Enforcement AST inicial de assets iOS
|
|
621
|
+
|
|
622
|
+
- `skills.ios.guideline.ios.assets-en-asset-catalogs-con-soporte-para-todos-los-taman-os` se mapea a `heuristics.ios.assets.loose-resource.ast`.
|
|
623
|
+
- En `PROJECT MODE: brownfield`, este hallazgo detecta carga de imágenes sueltas desde bundle/filesystem (`UIImage(contentsOfFile:)`, `NSImage(contentsOfFile:)`, `Bundle.main.path/url(...png|jpg|jpeg|pdf|svg|webp)`) como señal de adopción hacia Asset Catalogs. No marca `Image("asset")` ni `UIImage(named:)`.
|
|
624
|
+
|
|
610
625
|
### Combine (Reactive):
|
|
611
626
|
✅ **Publishers** - AsyncSequence para async, Combine para streams complejos
|
|
612
627
|
✅ **@Published** - En ViewModels para binding con Views
|
|
@@ -103,6 +103,18 @@ const registryByRuleId: Record<string, SkillsDetectorBinding> = {
|
|
|
103
103
|
'ios.localization.localizable-strings',
|
|
104
104
|
['heuristics.ios.localization.localizable-strings.ast']
|
|
105
105
|
),
|
|
106
|
+
'skills.ios.guideline.ios.cero-strings-hardcodeadas-en-ui': heuristicDetector(
|
|
107
|
+
'ios.localization.hardcoded-ui-string',
|
|
108
|
+
['heuristics.ios.localization.hardcoded-ui-string.ast']
|
|
109
|
+
),
|
|
110
|
+
'skills.ios.guideline.ios.string-localized-api-moderna-para-strings-traducibles': heuristicDetector(
|
|
111
|
+
'ios.localization.hardcoded-ui-string',
|
|
112
|
+
['heuristics.ios.localization.hardcoded-ui-string.ast']
|
|
113
|
+
),
|
|
114
|
+
'skills.ios.guideline.ios.assets-en-asset-catalogs-con-soporte-para-todos-los-taman-os': heuristicDetector(
|
|
115
|
+
'ios.assets.loose-resource',
|
|
116
|
+
['heuristics.ios.assets.loose-resource.ast']
|
|
117
|
+
),
|
|
106
118
|
'skills.ios.no-unchecked-sendable': heuristicDetector('ios.unchecked-sendable', [
|
|
107
119
|
'heuristics.ios.unchecked-sendable.ast',
|
|
108
120
|
]),
|
|
@@ -395,6 +395,12 @@ const normalizeKnownRuleTarget = (
|
|
|
395
395
|
) {
|
|
396
396
|
return 'skills.ios.guideline.ios.localizable-strings-deprecado-usar-string-catalogs';
|
|
397
397
|
}
|
|
398
|
+
if (includes('strings hardcodeadas') || includes('string localized')) {
|
|
399
|
+
return 'skills.ios.guideline.ios.cero-strings-hardcodeadas-en-ui';
|
|
400
|
+
}
|
|
401
|
+
if (includes('assets en asset catalogs') || includes('asset catalogs')) {
|
|
402
|
+
return 'skills.ios.guideline.ios.assets-en-asset-catalogs-con-soporte-para-todos-los-taman-os';
|
|
403
|
+
}
|
|
398
404
|
if (
|
|
399
405
|
includes('mixing legacy xctest style') ||
|
|
400
406
|
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.200",
|
|
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-13T11:
|
|
4
|
+
"generatedAt": "2026-05-13T11:35:11.674Z",
|
|
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": "b364080b578fc2de919d0d7d16c4075167415c3449f2d42a1cd2c6fabec18233",
|
|
5768
5768
|
"rules": [
|
|
5769
5769
|
{
|
|
5770
5770
|
"id": "skills.ios.guideline.ios.accessibility-identifiers-para-localizar-elementos",
|
|
@@ -5895,7 +5895,7 @@
|
|
|
5895
5895
|
"sourcePath": "vendor/skills/ios-enterprise-rules/SKILL.md",
|
|
5896
5896
|
"confidence": "MEDIUM",
|
|
5897
5897
|
"locked": true,
|
|
5898
|
-
"evaluationMode": "
|
|
5898
|
+
"evaluationMode": "AUTO",
|
|
5899
5899
|
"origin": "core"
|
|
5900
5900
|
},
|
|
5901
5901
|
{
|
|
@@ -6092,14 +6092,14 @@
|
|
|
6092
6092
|
},
|
|
6093
6093
|
{
|
|
6094
6094
|
"id": "skills.ios.guideline.ios.cero-strings-hardcodeadas-en-ui",
|
|
6095
|
-
"description": "
|
|
6095
|
+
"description": "String(localized:) y formateadores (Date/Number)",
|
|
6096
6096
|
"severity": "WARN",
|
|
6097
6097
|
"platform": "ios",
|
|
6098
6098
|
"sourceSkill": "ios-guidelines",
|
|
6099
6099
|
"sourcePath": "vendor/skills/ios-enterprise-rules/SKILL.md",
|
|
6100
6100
|
"confidence": "MEDIUM",
|
|
6101
6101
|
"locked": true,
|
|
6102
|
-
"evaluationMode": "
|
|
6102
|
+
"evaluationMode": "AUTO",
|
|
6103
6103
|
"origin": "core"
|
|
6104
6104
|
},
|
|
6105
6105
|
{
|
|
@@ -7879,30 +7879,6 @@
|
|
|
7879
7879
|
"evaluationMode": "DECLARATIVE",
|
|
7880
7880
|
"origin": "core"
|
|
7881
7881
|
},
|
|
7882
|
-
{
|
|
7883
|
-
"id": "skills.ios.guideline.ios.string-localized-api-moderna-para-strings-traducibles",
|
|
7884
|
-
"description": "String(localized:) - API moderna para strings traducibles",
|
|
7885
|
-
"severity": "WARN",
|
|
7886
|
-
"platform": "ios",
|
|
7887
|
-
"sourceSkill": "ios-guidelines",
|
|
7888
|
-
"sourcePath": "vendor/skills/ios-enterprise-rules/SKILL.md",
|
|
7889
|
-
"confidence": "MEDIUM",
|
|
7890
|
-
"locked": true,
|
|
7891
|
-
"evaluationMode": "DECLARATIVE",
|
|
7892
|
-
"origin": "core"
|
|
7893
|
-
},
|
|
7894
|
-
{
|
|
7895
|
-
"id": "skills.ios.guideline.ios.string-localized-y-formateadores-date-number",
|
|
7896
|
-
"description": "String(localized:) y formateadores (Date/Number)",
|
|
7897
|
-
"severity": "WARN",
|
|
7898
|
-
"platform": "ios",
|
|
7899
|
-
"sourceSkill": "ios-guidelines",
|
|
7900
|
-
"sourcePath": "vendor/skills/ios-enterprise-rules/SKILL.md",
|
|
7901
|
-
"confidence": "MEDIUM",
|
|
7902
|
-
"locked": true,
|
|
7903
|
-
"evaluationMode": "DECLARATIVE",
|
|
7904
|
-
"origin": "core"
|
|
7905
|
-
},
|
|
7906
7882
|
{
|
|
7907
7883
|
"id": "skills.ios.guideline.ios.struct-por-defecto-class-solo-cuando-necesites-identity-o-herencia",
|
|
7908
7884
|
"description": "struct por defecto - class solo cuando necesites identity o herencia",
|