pumuki 6.3.197 → 6.3.199
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 +31 -0
- package/core/facts/detectors/text/ios.ts +32 -0
- package/core/facts/extractHeuristicFacts.ts +7 -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 +20 -0
- package/integrations/config/skillsMarkdownRules.ts +10 -0
- package/package.json +1 -1
- package/skills.lock.json +8 -68
|
@@ -21,6 +21,7 @@ import {
|
|
|
21
21
|
hasSwiftForceTryUsage,
|
|
22
22
|
hasSwiftForceUnwrap,
|
|
23
23
|
hasSwiftGeometryReaderUsage,
|
|
24
|
+
hasSwiftHardcodedUiStringUsage,
|
|
24
25
|
hasSwiftLegacyOnChangeUsage,
|
|
25
26
|
hasSwiftLegacyExpectationDescriptionUsage,
|
|
26
27
|
hasSwiftLegacySwiftUiObservableWrapperUsage,
|
|
@@ -268,6 +269,36 @@ let text = "https://example.com/catalog.json"
|
|
|
268
269
|
assert.equal(hasSwiftInsecureTransportUsage(ignored), false);
|
|
269
270
|
});
|
|
270
271
|
|
|
272
|
+
test('detector iOS de localización detecta strings UI hardcodeadas sin confundir keys ni comentarios', () => {
|
|
273
|
+
const source = `
|
|
274
|
+
struct PaywallView: View {
|
|
275
|
+
var body: some View {
|
|
276
|
+
VStack {
|
|
277
|
+
Text("Start premium trial")
|
|
278
|
+
Button("Continue") {}
|
|
279
|
+
Label("Your orders", systemImage: "cart")
|
|
280
|
+
TextField("Search products", text: $query)
|
|
281
|
+
EmptyView().navigationTitle("Account details")
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
`;
|
|
286
|
+
const ignored = `
|
|
287
|
+
struct OrdersView: View {
|
|
288
|
+
var body: some View {
|
|
289
|
+
Text(String(localized: "orders.title"))
|
|
290
|
+
Text("orders.title")
|
|
291
|
+
Button(String(localized: "orders.checkout")) {}
|
|
292
|
+
let sample = "Text(\\"Start premium trial\\")"
|
|
293
|
+
// Text("Debug")
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
`;
|
|
297
|
+
|
|
298
|
+
assert.equal(hasSwiftHardcodedUiStringUsage(source), true);
|
|
299
|
+
assert.equal(hasSwiftHardcodedUiStringUsage(ignored), false);
|
|
300
|
+
});
|
|
301
|
+
|
|
271
302
|
test('hasSwiftUncheckedSendableUsage detecta @unchecked Sendable', () => {
|
|
272
303
|
const source = `
|
|
273
304
|
final class LegacyBox: @unchecked Sendable {}
|
|
@@ -511,6 +511,38 @@ 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
|
+
|
|
514
546
|
export const hasSwiftUncheckedSendableUsage = (source: string): boolean => {
|
|
515
547
|
return scanCodeLikeSource(source, ({ source: swiftSource, index, current }) => {
|
|
516
548
|
if (current !== '@' || !swiftSource.startsWith('@unchecked', index)) {
|
|
@@ -97,6 +97,11 @@ const isIOSInfoPlistPath = (path: string): boolean => {
|
|
|
97
97
|
return normalized.startsWith('apps/ios/') && normalized.endsWith('/Info.plist');
|
|
98
98
|
};
|
|
99
99
|
|
|
100
|
+
const isIOSLocalizableStringsPath = (path: string): boolean => {
|
|
101
|
+
const normalized = path.replace(/\\/g, '/');
|
|
102
|
+
return normalized.startsWith('apps/ios/') && normalized.endsWith('/Localizable.strings');
|
|
103
|
+
};
|
|
104
|
+
|
|
100
105
|
const isIOSApplicationOrPresentationPath = (path: string): boolean => {
|
|
101
106
|
return (
|
|
102
107
|
isIOSSwiftPath(path) &&
|
|
@@ -648,6 +653,8 @@ const textDetectorRegistry: ReadonlyArray<TextDetectorRegistryEntry> = [
|
|
|
648
653
|
{ platform: 'ios', pathCheck: isIOSSwiftPath, excludePaths: [isSwiftTestPath], detect: TextIOS.hasSwiftSensitiveUserDefaultsStorageUsage, ruleId: 'heuristics.ios.security.userdefaults-sensitive-data.ast', code: 'HEURISTICS_IOS_SECURITY_USERDEFAULTS_SENSITIVE_DATA_AST', message: 'AST heuristic detected sensitive data stored in UserDefaults/AppStorage; native Keychain remains the preferred baseline for secrets.' },
|
|
649
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.' },
|
|
650
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
|
+
{ 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.' },
|
|
651
658
|
{ 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.' },
|
|
652
659
|
{ 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.' },
|
|
653
660
|
{ 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, 53);
|
|
7
7
|
|
|
8
8
|
const ids = iosRules.map((rule) => rule.id);
|
|
9
9
|
assert.deepEqual(ids, [
|
|
@@ -25,6 +25,8 @@ test('iosRules define reglas heurísticas locked para plataforma ios', () => {
|
|
|
25
25
|
'heuristics.ios.dependencies.carthage.ast',
|
|
26
26
|
'heuristics.ios.security.userdefaults-sensitive-data.ast',
|
|
27
27
|
'heuristics.ios.security.insecure-transport.ast',
|
|
28
|
+
'heuristics.ios.localization.localizable-strings.ast',
|
|
29
|
+
'heuristics.ios.localization.hardcoded-ui-string.ast',
|
|
28
30
|
'heuristics.ios.unchecked-sendable.ast',
|
|
29
31
|
'heuristics.ios.preconcurrency.ast',
|
|
30
32
|
'heuristics.ios.nonisolated-unsafe.ast',
|
|
@@ -101,6 +103,14 @@ test('iosRules define reglas heurísticas locked para plataforma ios', () => {
|
|
|
101
103
|
byId.get('heuristics.ios.security.insecure-transport.ast')?.then.code,
|
|
102
104
|
'HEURISTICS_IOS_SECURITY_INSECURE_TRANSPORT_AST'
|
|
103
105
|
);
|
|
106
|
+
assert.equal(
|
|
107
|
+
byId.get('heuristics.ios.localization.localizable-strings.ast')?.then.code,
|
|
108
|
+
'HEURISTICS_IOS_LOCALIZATION_LOCALIZABLE_STRINGS_AST'
|
|
109
|
+
);
|
|
110
|
+
assert.equal(
|
|
111
|
+
byId.get('heuristics.ios.localization.hardcoded-ui-string.ast')?.then.code,
|
|
112
|
+
'HEURISTICS_IOS_LOCALIZATION_HARDCODED_UI_STRING_AST'
|
|
113
|
+
);
|
|
104
114
|
assert.equal(
|
|
105
115
|
byId.get('heuristics.ios.preconcurrency.ast')?.then.code,
|
|
106
116
|
'HEURISTICS_IOS_PRECONCURRENCY_AST'
|
|
@@ -325,6 +325,42 @@ export const iosRules: RuleSet = [
|
|
|
325
325
|
code: 'HEURISTICS_IOS_SECURITY_INSECURE_TRANSPORT_AST',
|
|
326
326
|
},
|
|
327
327
|
},
|
|
328
|
+
{
|
|
329
|
+
id: 'heuristics.ios.localization.localizable-strings.ast',
|
|
330
|
+
description: 'Detects legacy Localizable.strings files where String Catalogs are the preferred iOS baseline.',
|
|
331
|
+
severity: 'WARN',
|
|
332
|
+
platform: 'ios',
|
|
333
|
+
locked: true,
|
|
334
|
+
when: {
|
|
335
|
+
kind: 'Heuristic',
|
|
336
|
+
where: {
|
|
337
|
+
ruleId: 'heuristics.ios.localization.localizable-strings.ast',
|
|
338
|
+
},
|
|
339
|
+
},
|
|
340
|
+
then: {
|
|
341
|
+
kind: 'Finding',
|
|
342
|
+
message: 'AST heuristic detected Localizable.strings usage; String Catalogs (.xcstrings) remain the preferred baseline for new localization work.',
|
|
343
|
+
code: 'HEURISTICS_IOS_LOCALIZATION_LOCALIZABLE_STRINGS_AST',
|
|
344
|
+
},
|
|
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
|
+
},
|
|
328
364
|
{
|
|
329
365
|
id: 'heuristics.ios.unchecked-sendable.ast',
|
|
330
366
|
description: 'Detects @unchecked Sendable usage in iOS production code.',
|
|
@@ -602,6 +602,21 @@ struct APIEndpoint: Sendable {
|
|
|
602
602
|
- `skills.ios.guideline.ios.userdefaults-settings-simples-no-datos-sensibles` se mapea a `heuristics.ios.security.userdefaults-sensitive-data.ast`.
|
|
603
603
|
- En `PROJECT MODE: brownfield`, este hallazgo es señal de baseline/adopción y debe evitar drift nuevo sin bloquear deuda histórica salvo promoción explícita de policy. Keychain nativo permanece como baseline preferente para secretos.
|
|
604
604
|
|
|
605
|
+
### Enforcement AST inicial de transporte seguro iOS
|
|
606
|
+
|
|
607
|
+
- `skills.ios.guideline.ios.app-transport-security-ats-https-por-defecto` se mapea a `heuristics.ios.security.insecure-transport.ast`.
|
|
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
|
+
|
|
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
|
+
|
|
605
620
|
### Combine (Reactive):
|
|
606
621
|
✅ **Publishers** - AsyncSequence para async, Combine para streams complejos
|
|
607
622
|
✅ **@Published** - En ViewModels para binding con Views
|
|
@@ -91,6 +91,26 @@ const registryByRuleId: Record<string, SkillsDetectorBinding> = {
|
|
|
91
91
|
'ios.security.insecure-transport',
|
|
92
92
|
['heuristics.ios.security.insecure-transport.ast']
|
|
93
93
|
),
|
|
94
|
+
'skills.ios.guideline.ios.localizable-strings-deprecado-usar-string-catalogs': heuristicDetector(
|
|
95
|
+
'ios.localization.localizable-strings',
|
|
96
|
+
['heuristics.ios.localization.localizable-strings.ast']
|
|
97
|
+
),
|
|
98
|
+
'skills.ios.guideline.ios.string-catalogs-xcstrings': heuristicDetector(
|
|
99
|
+
'ios.localization.localizable-strings',
|
|
100
|
+
['heuristics.ios.localization.localizable-strings.ast']
|
|
101
|
+
),
|
|
102
|
+
'skills.ios.guideline.ios.string-catalogs-xcstrings-sistema-moderno-de-localizacio-n-xcode-15': heuristicDetector(
|
|
103
|
+
'ios.localization.localizable-strings',
|
|
104
|
+
['heuristics.ios.localization.localizable-strings.ast']
|
|
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
|
+
),
|
|
94
114
|
'skills.ios.no-unchecked-sendable': heuristicDetector('ios.unchecked-sendable', [
|
|
95
115
|
'heuristics.ios.unchecked-sendable.ast',
|
|
96
116
|
]),
|
|
@@ -388,6 +388,16 @@ const normalizeKnownRuleTarget = (
|
|
|
388
388
|
) {
|
|
389
389
|
return 'skills.ios.guideline.ios.app-transport-security-ats-https-por-defecto';
|
|
390
390
|
}
|
|
391
|
+
if (
|
|
392
|
+
includes('localizable strings') ||
|
|
393
|
+
includes('string catalogs') ||
|
|
394
|
+
includes('xcstrings')
|
|
395
|
+
) {
|
|
396
|
+
return 'skills.ios.guideline.ios.localizable-strings-deprecado-usar-string-catalogs';
|
|
397
|
+
}
|
|
398
|
+
if (includes('strings hardcodeadas') || includes('string localized')) {
|
|
399
|
+
return 'skills.ios.guideline.ios.cero-strings-hardcodeadas-en-ui';
|
|
400
|
+
}
|
|
391
401
|
if (
|
|
392
402
|
includes('mixing legacy xctest style') ||
|
|
393
403
|
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.199",
|
|
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:29:26.365Z",
|
|
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": "6b68665f29f3894ce007abafdd6a766e63ec02f576fc7299e9d7cf17430786d4",
|
|
5768
5768
|
"rules": [
|
|
5769
5769
|
{
|
|
5770
5770
|
"id": "skills.ios.guideline.ios.accessibility-identifiers-para-localizar-elementos",
|
|
@@ -5946,18 +5946,6 @@
|
|
|
5946
5946
|
"evaluationMode": "DECLARATIVE",
|
|
5947
5947
|
"origin": "core"
|
|
5948
5948
|
},
|
|
5949
|
-
{
|
|
5950
|
-
"id": "skills.ios.guideline.ios.automatic-plural-handling-en-string-catalogs",
|
|
5951
|
-
"description": "Automatic plural handling - En String Catalogs",
|
|
5952
|
-
"severity": "WARN",
|
|
5953
|
-
"platform": "ios",
|
|
5954
|
-
"sourceSkill": "ios-guidelines",
|
|
5955
|
-
"sourcePath": "vendor/skills/ios-enterprise-rules/SKILL.md",
|
|
5956
|
-
"confidence": "MEDIUM",
|
|
5957
|
-
"locked": true,
|
|
5958
|
-
"evaluationMode": "DECLARATIVE",
|
|
5959
|
-
"origin": "core"
|
|
5960
|
-
},
|
|
5961
5949
|
{
|
|
5962
5950
|
"id": "skills.ios.guideline.ios.avoid-over-use-async-await-ma-s-simple-para-single-values",
|
|
5963
5951
|
"description": "Avoid over-use - async/await más simple para single values",
|
|
@@ -6104,14 +6092,14 @@
|
|
|
6104
6092
|
},
|
|
6105
6093
|
{
|
|
6106
6094
|
"id": "skills.ios.guideline.ios.cero-strings-hardcodeadas-en-ui",
|
|
6107
|
-
"description": "
|
|
6095
|
+
"description": "String(localized:) y formateadores (Date/Number)",
|
|
6108
6096
|
"severity": "WARN",
|
|
6109
6097
|
"platform": "ios",
|
|
6110
6098
|
"sourceSkill": "ios-guidelines",
|
|
6111
6099
|
"sourcePath": "vendor/skills/ios-enterprise-rules/SKILL.md",
|
|
6112
6100
|
"confidence": "MEDIUM",
|
|
6113
6101
|
"locked": true,
|
|
6114
|
-
"evaluationMode": "
|
|
6102
|
+
"evaluationMode": "AUTO",
|
|
6115
6103
|
"origin": "core"
|
|
6116
6104
|
},
|
|
6117
6105
|
{
|
|
@@ -6933,14 +6921,14 @@
|
|
|
6933
6921
|
},
|
|
6934
6922
|
{
|
|
6935
6923
|
"id": "skills.ios.guideline.ios.localizable-strings-deprecado-usar-string-catalogs",
|
|
6936
|
-
"description": "
|
|
6937
|
-
"severity": "
|
|
6924
|
+
"description": "String Catalogs (.xcstrings)",
|
|
6925
|
+
"severity": "WARN",
|
|
6938
6926
|
"platform": "ios",
|
|
6939
6927
|
"sourceSkill": "ios-guidelines",
|
|
6940
6928
|
"sourcePath": "vendor/skills/ios-enterprise-rules/SKILL.md",
|
|
6941
|
-
"confidence": "
|
|
6929
|
+
"confidence": "MEDIUM",
|
|
6942
6930
|
"locked": true,
|
|
6943
|
-
"evaluationMode": "
|
|
6931
|
+
"evaluationMode": "AUTO",
|
|
6944
6932
|
"origin": "core"
|
|
6945
6933
|
},
|
|
6946
6934
|
{
|
|
@@ -7891,54 +7879,6 @@
|
|
|
7891
7879
|
"evaluationMode": "DECLARATIVE",
|
|
7892
7880
|
"origin": "core"
|
|
7893
7881
|
},
|
|
7894
|
-
{
|
|
7895
|
-
"id": "skills.ios.guideline.ios.string-catalogs-xcstrings",
|
|
7896
|
-
"description": "String Catalogs (.xcstrings)",
|
|
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
|
-
{
|
|
7907
|
-
"id": "skills.ios.guideline.ios.string-catalogs-xcstrings-sistema-moderno-de-localizacio-n-xcode-15",
|
|
7908
|
-
"description": "String Catalogs (.xcstrings) - Sistema moderno de localización (Xcode 15+)",
|
|
7909
|
-
"severity": "WARN",
|
|
7910
|
-
"platform": "ios",
|
|
7911
|
-
"sourceSkill": "ios-guidelines",
|
|
7912
|
-
"sourcePath": "vendor/skills/ios-enterprise-rules/SKILL.md",
|
|
7913
|
-
"confidence": "MEDIUM",
|
|
7914
|
-
"locked": true,
|
|
7915
|
-
"evaluationMode": "DECLARATIVE",
|
|
7916
|
-
"origin": "core"
|
|
7917
|
-
},
|
|
7918
|
-
{
|
|
7919
|
-
"id": "skills.ios.guideline.ios.string-localized-api-moderna-para-strings-traducibles",
|
|
7920
|
-
"description": "String(localized:) - API moderna para strings traducibles",
|
|
7921
|
-
"severity": "WARN",
|
|
7922
|
-
"platform": "ios",
|
|
7923
|
-
"sourceSkill": "ios-guidelines",
|
|
7924
|
-
"sourcePath": "vendor/skills/ios-enterprise-rules/SKILL.md",
|
|
7925
|
-
"confidence": "MEDIUM",
|
|
7926
|
-
"locked": true,
|
|
7927
|
-
"evaluationMode": "DECLARATIVE",
|
|
7928
|
-
"origin": "core"
|
|
7929
|
-
},
|
|
7930
|
-
{
|
|
7931
|
-
"id": "skills.ios.guideline.ios.string-localized-y-formateadores-date-number",
|
|
7932
|
-
"description": "String(localized:) y formateadores (Date/Number)",
|
|
7933
|
-
"severity": "WARN",
|
|
7934
|
-
"platform": "ios",
|
|
7935
|
-
"sourceSkill": "ios-guidelines",
|
|
7936
|
-
"sourcePath": "vendor/skills/ios-enterprise-rules/SKILL.md",
|
|
7937
|
-
"confidence": "MEDIUM",
|
|
7938
|
-
"locked": true,
|
|
7939
|
-
"evaluationMode": "DECLARATIVE",
|
|
7940
|
-
"origin": "core"
|
|
7941
|
-
},
|
|
7942
7882
|
{
|
|
7943
7883
|
"id": "skills.ios.guideline.ios.struct-por-defecto-class-solo-cuando-necesites-identity-o-herencia",
|
|
7944
7884
|
"description": "struct por defecto - class solo cuando necesites identity o herencia",
|