pumuki 6.3.212 → 6.3.214

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.
@@ -51,6 +51,7 @@ import {
51
51
  hasSwiftPassedValueStateWrapperUsage,
52
52
  hasSwiftPhysicalTextAlignmentUsage,
53
53
  hasSwiftPreconcurrencyUsage,
54
+ hasSwiftQuickNimbleUsage,
54
55
  hasSwiftSheetIsPresentedUsage,
55
56
  hasSwiftScrollViewShowsIndicatorsUsage,
56
57
  hasSwiftSensitiveLoggingUsage,
@@ -940,6 +941,41 @@ struct LoginModernTests {
940
941
  assert.equal(hasSwiftMixedTestingFrameworksUsage(modernOnly), false);
941
942
  });
942
943
 
944
+ test('hasSwiftQuickNimbleUsage detecta Quick y Nimble en tests Swift', () => {
945
+ const quickSpec = `
946
+ import Quick
947
+ import Nimble
948
+
949
+ final class CheckoutSpec: QuickSpec {
950
+ override class func spec() {
951
+ describe("checkout") {
952
+ it("loads") {
953
+ expect(true).to(beTrue())
954
+ }
955
+ }
956
+ }
957
+ }
958
+ `;
959
+ const nativeSwiftTesting = `
960
+ import Testing
961
+
962
+ @Suite
963
+ struct CheckoutTests {
964
+ @Test func loads() {
965
+ #expect(true)
966
+ }
967
+ }
968
+ `;
969
+ const ignored = `
970
+ let text = "import Quick"
971
+ // import Nimble
972
+ `;
973
+
974
+ assert.equal(hasSwiftQuickNimbleUsage(quickSpec), true);
975
+ assert.equal(hasSwiftQuickNimbleUsage(nativeSwiftTesting), false);
976
+ assert.equal(hasSwiftQuickNimbleUsage(ignored), false);
977
+ });
978
+
943
979
  test('hasSwiftXCTestAssertionUsage detecta XCTAssert y XCTFail reales', () => {
944
980
  const source = `
945
981
  XCTAssertEqual(value, expected)
@@ -1050,6 +1050,13 @@ export const hasSwiftMixedTestingFrameworksUsage = (source: string): boolean =>
1050
1050
  return hasSwiftTestingImportUsage(source) || hasSwiftTestingSuiteAttributeUsage(source);
1051
1051
  };
1052
1052
 
1053
+ export const hasSwiftQuickNimbleUsage = (source: string): boolean => {
1054
+ return hasSwiftSanitizedRegexMatch(
1055
+ source,
1056
+ /\bimport\s+(?:Quick|Nimble)\b|\bclass\s+[A-Za-z_][A-Za-z0-9_]*\s*:\s*QuickSpec\b/
1057
+ );
1058
+ };
1059
+
1053
1060
  export const hasSwiftXCTestAssertionUsage = (source: string): boolean => {
1054
1061
  return (
1055
1062
  collectSwiftRegexLines(source, /\bXCTAssert[A-Za-z0-9_]*\s*\(/).length > 0 ||
@@ -694,6 +694,7 @@ const textDetectorRegistry: ReadonlyArray<TextDetectorRegistryEntry> = [
694
694
  { platform: 'ios', pathCheck: isIOSSwiftTestPath, excludePaths: [], detect: TextIOS.hasSwiftWaitForExpectationsUsage, ruleId: 'heuristics.ios.testing.wait-for-expectations.ast', code: 'HEURISTICS_IOS_TESTING_WAIT_FOR_EXPECTATIONS_AST', message: 'AST heuristic detected wait(for:)/waitForExpectations usage where await fulfillment(of:) may be preferred.' },
695
695
  { platform: 'ios', pathCheck: isIOSSwiftTestPath, excludePaths: [], detect: TextIOS.hasSwiftLegacyExpectationDescriptionUsage, ruleId: 'heuristics.ios.testing.legacy-expectation-description.ast', code: 'HEURISTICS_IOS_TESTING_LEGACY_EXPECTATION_DESCRIPTION_AST', message: 'AST heuristic detected expectation(description:) usage without modern fulfillment/confirmation flow.' },
696
696
  { platform: 'ios', pathCheck: isIOSSwiftTestPath, excludePaths: [], detect: TextIOS.hasSwiftMixedTestingFrameworksUsage, ruleId: 'heuristics.ios.testing.mixed-frameworks.ast', code: 'HEURISTICS_IOS_TESTING_MIXED_FRAMEWORKS_AST', message: 'AST heuristic detected XCTestCase and Swift Testing markers mixed in the same test file without explicit compatibility reason.' },
697
+ { platform: 'ios', pathCheck: isIOSSwiftTestPath, excludePaths: [], detect: TextIOS.hasSwiftQuickNimbleUsage, ruleId: 'heuristics.ios.testing.quick-nimble.ast', code: 'HEURISTICS_IOS_TESTING_QUICK_NIMBLE_AST', message: 'AST heuristic detected Quick/Nimble usage where native Swift Testing remains the preferred baseline.' },
697
698
  { platform: 'ios', pathCheck: isIOSSwiftPath, excludePaths: [isSwiftTestPath], detect: TextIOS.hasSwiftNSManagedObjectBoundaryUsage, ruleId: 'heuristics.ios.core-data.nsmanagedobject-boundary.ast', code: 'HEURISTICS_IOS_CORE_DATA_NSMANAGEDOBJECT_BOUNDARY_AST', message: 'AST heuristic detected NSManagedObject in a shared boundary.' },
698
699
  { platform: 'ios', pathCheck: isIOSSwiftPath, excludePaths: [isSwiftTestPath], detect: TextIOS.hasSwiftNSManagedObjectAsyncBoundaryUsage, ruleId: 'heuristics.ios.core-data.nsmanagedobject-async-boundary.ast', code: 'HEURISTICS_IOS_CORE_DATA_NSMANAGEDOBJECT_ASYNC_BOUNDARY_AST', message: 'AST heuristic detected NSManagedObject in an async boundary.' },
699
700
  { platform: 'ios', pathCheck: isIOSApplicationOrPresentationPath, excludePaths: [isSwiftTestPath], detect: TextIOS.hasSwiftCoreDataLayerLeakUsage, ruleId: 'heuristics.ios.core-data.layer-leak.ast', code: 'HEURISTICS_IOS_CORE_DATA_LAYER_LEAK_AST', message: 'AST heuristic detected Core Data APIs leaking into application/presentation code.' },
@@ -1073,6 +1073,25 @@ export const iosRules: RuleSet = [
1073
1073
  code: 'HEURISTICS_IOS_TESTING_MIXED_FRAMEWORKS_AST',
1074
1074
  },
1075
1075
  },
1076
+ {
1077
+ id: 'heuristics.ios.testing.quick-nimble.ast',
1078
+ description: 'Detects Quick/Nimble usage in iOS Swift tests.',
1079
+ severity: 'WARN',
1080
+ platform: 'ios',
1081
+ locked: true,
1082
+ when: {
1083
+ kind: 'Heuristic',
1084
+ where: {
1085
+ ruleId: 'heuristics.ios.testing.quick-nimble.ast',
1086
+ },
1087
+ },
1088
+ then: {
1089
+ kind: 'Finding',
1090
+ message:
1091
+ 'AST heuristic detected Quick/Nimble usage where native Swift Testing remains the preferred baseline.',
1092
+ code: 'HEURISTICS_IOS_TESTING_QUICK_NIMBLE_AST',
1093
+ },
1094
+ },
1076
1095
  {
1077
1096
  id: 'heuristics.ios.core-data.nsmanagedobject-boundary.ast',
1078
1097
  description: 'Detects NSManagedObject usage in shared iOS boundaries.',
@@ -259,6 +259,10 @@ const registryByRuleId: Record<string, SkillsDetectorBinding> = {
259
259
  'skills.ios.no-mixed-testing-frameworks': heuristicDetector('ios.testing.mixed-frameworks', [
260
260
  'heuristics.ios.testing.mixed-frameworks.ast',
261
261
  ]),
262
+ 'skills.ios.guideline.ios.quick-nimble-prohibido-usar-swift-testing-nativo': heuristicDetector(
263
+ 'ios.testing.quick-nimble',
264
+ ['heuristics.ios.testing.quick-nimble.ast']
265
+ ),
262
266
  'skills.ios.no-nsmanagedobject-boundary': heuristicDetector(
263
267
  'ios.core-data.nsmanagedobject-boundary',
264
268
  ['heuristics.ios.core-data.nsmanagedobject-boundary.ast']
@@ -108,6 +108,17 @@ const resolveDefaultStageForKnownRule = (
108
108
  return KNOWN_RULE_DEFAULT_STAGE[ruleId];
109
109
  };
110
110
 
111
+ const KNOWN_RULE_DEFAULT_SEVERITY: Readonly<Record<string, Severity>> = {
112
+ 'skills.ios.guideline.ios.magic-numbers-usar-constantes-con-nombres': 'WARN',
113
+ };
114
+
115
+ const resolveDefaultSeverityForKnownRule = (
116
+ ruleId: string,
117
+ inferredSeverity: Severity
118
+ ): Severity => {
119
+ return KNOWN_RULE_DEFAULT_SEVERITY[ruleId] ?? inferredSeverity;
120
+ };
121
+
111
122
  const isRuleCandidateLine = (line: string): boolean => {
112
123
  if (CHECK_RULE_PREFIX.test(line)) {
113
124
  return true;
@@ -476,6 +487,9 @@ const normalizeKnownRuleTarget = (
476
487
  ) {
477
488
  return 'skills.ios.no-mixed-testing-frameworks';
478
489
  }
490
+ if (includes('quick nimble') || includes('quick/nimble')) {
491
+ return 'skills.ios.guideline.ios.quick-nimble-prohibido-usar-swift-testing-nativo';
492
+ }
479
493
  if (
480
494
  includes('nsmanagedobject across boundaries') ||
481
495
  includes('passing nsmanagedobject') ||
@@ -644,7 +658,9 @@ export const extractCompiledRulesFromSkillMarkdown = (params: {
644
658
  rules.push({
645
659
  id: nextId,
646
660
  description,
647
- severity: inferRuleSeverity(rawLine),
661
+ severity: knownRuleId
662
+ ? resolveDefaultSeverityForKnownRule(knownRuleId, inferRuleSeverity(rawLine))
663
+ : inferRuleSeverity(rawLine),
648
664
  platform,
649
665
  sourceSkill: params.sourceSkill,
650
666
  sourcePath: params.sourcePath,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pumuki",
3
- "version": "6.3.212",
3
+ "version": "6.3.214",
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-13T13:06:24.412Z",
4
+ "generatedAt": "2026-05-13T13:13:49.119Z",
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": "01dc99563d48bb48b8df3262a7c58ca1482c3dd96590b9dd230d2576fa32f7b4",
5767
+ "hash": "45fa3aefa9324032a7a0ce988d5546db63b0d64936bf81c4dbaa4906e5f4a544",
5768
5768
  "rules": [
5769
5769
  {
5770
5770
  "id": "skills.ios.guideline.ios.accessibility-identifiers-para-localizar-elementos",
@@ -6910,7 +6910,7 @@
6910
6910
  {
6911
6911
  "id": "skills.ios.guideline.ios.magic-numbers-usar-constantes-con-nombres",
6912
6912
  "description": "Magic numbers - Usar constantes con nombres",
6913
- "severity": "ERROR",
6913
+ "severity": "WARN",
6914
6914
  "platform": "ios",
6915
6915
  "sourceSkill": "ios-guidelines",
6916
6916
  "sourcePath": "vendor/skills/ios-enterprise-rules/SKILL.md",
@@ -7468,7 +7468,7 @@
7468
7468
  "sourcePath": "vendor/skills/ios-enterprise-rules/SKILL.md",
7469
7469
  "confidence": "HIGH",
7470
7470
  "locked": true,
7471
- "evaluationMode": "DECLARATIVE",
7471
+ "evaluationMode": "AUTO",
7472
7472
  "origin": "core"
7473
7473
  },
7474
7474
  {