@mmerterden/multi-agent-pipeline 20.6.0 → 20.8.0

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.
Files changed (326) hide show
  1. package/CHANGELOG.md +27 -0
  2. package/LICENSE +0 -10
  3. package/docs/facts.json +1 -1
  4. package/manifest.json +328 -329
  5. package/package.json +2 -2
  6. package/pipeline/multi-agent-refs/features/design-conformance.md +62 -64
  7. package/pipeline/scripts/_notices.mjs +12 -1
  8. package/pipeline/scripts/gen-skills-index.mjs +1 -1
  9. package/pipeline/skills/.skill-manifest.json +106 -106
  10. package/pipeline/skills/shared/README.md +71 -71
  11. package/pipeline/skills/shared/external/agent-introspection-debugging/SKILL.md +1 -0
  12. package/pipeline/skills/shared/external/alarmkit/SKILL.md +373 -381
  13. package/pipeline/skills/shared/external/alarmkit/evals/evals.json +23 -18
  14. package/pipeline/skills/shared/external/alarmkit/references/alarmkit-patterns.md +328 -378
  15. package/pipeline/skills/shared/external/android-architecture/SKILL.md +2 -0
  16. package/pipeline/skills/shared/external/android-performance/SKILL.md +2 -0
  17. package/pipeline/skills/shared/external/android-security/SKILL.md +2 -0
  18. package/pipeline/skills/shared/external/app-clips/SKILL.md +260 -160
  19. package/pipeline/skills/shared/external/app-clips/evals/evals.json +27 -27
  20. package/pipeline/skills/shared/external/app-clips/references/data-handoff-notifications-location.md +150 -83
  21. package/pipeline/skills/shared/external/app-clips/references/routing-and-experiences.md +135 -83
  22. package/pipeline/skills/shared/external/app-clips/references/size-capabilities-and-promotion.md +143 -85
  23. package/pipeline/skills/shared/external/app-intents/SKILL.md +302 -304
  24. package/pipeline/skills/shared/external/app-intents/evals/evals.json +21 -21
  25. package/pipeline/skills/shared/external/app-intents/references/appintents-advanced.md +594 -894
  26. package/pipeline/skills/shared/external/app-store-optimization/SKILL.md +339 -277
  27. package/pipeline/skills/shared/external/app-store-optimization/evals/evals.json +27 -23
  28. package/pipeline/skills/shared/external/app-store-optimization/references/keyword-research-methodology.md +105 -122
  29. package/pipeline/skills/shared/external/app-store-optimization/references/product-page-variants.md +143 -166
  30. package/pipeline/skills/shared/external/app-store-review/SKILL.md +307 -326
  31. package/pipeline/skills/shared/external/app-store-review/evals/evals.json +21 -21
  32. package/pipeline/skills/shared/external/app-store-review/references/privacy-manifest.md +105 -67
  33. package/pipeline/skills/shared/external/app-store-review/references/review-checklists.md +114 -101
  34. package/pipeline/skills/shared/external/apple-on-device-ai/SKILL.md +333 -360
  35. package/pipeline/skills/shared/external/apple-on-device-ai/evals/evals.json +24 -27
  36. package/pipeline/skills/shared/external/apple-on-device-ai/references/coreml-conversion.md +215 -322
  37. package/pipeline/skills/shared/external/apple-on-device-ai/references/coreml-optimization.md +161 -256
  38. package/pipeline/skills/shared/external/apple-on-device-ai/references/foundation-models.md +277 -387
  39. package/pipeline/skills/shared/external/apple-on-device-ai/references/mlx-swift.md +196 -210
  40. package/pipeline/skills/shared/external/authentication/SKILL.md +265 -381
  41. package/pipeline/skills/shared/external/authentication/evals/evals.json +25 -25
  42. package/pipeline/skills/shared/external/authentication/references/keychain-biometric.md +133 -178
  43. package/pipeline/skills/shared/external/authentication/references/passkeys.md +111 -147
  44. package/pipeline/skills/shared/external/avkit/SKILL.md +267 -364
  45. package/pipeline/skills/shared/external/avkit/evals/evals.json +26 -26
  46. package/pipeline/skills/shared/external/avkit/references/avkit-patterns.md +375 -493
  47. package/pipeline/skills/shared/external/background-processing/SKILL.md +270 -382
  48. package/pipeline/skills/shared/external/background-processing/evals/evals.json +22 -22
  49. package/pipeline/skills/shared/external/background-processing/references/background-task-patterns.md +169 -317
  50. package/pipeline/skills/shared/external/backlog/BACKLOG.md +1 -1
  51. package/pipeline/skills/shared/external/backlog/SKILL.md +56 -33
  52. package/pipeline/skills/shared/external/callkit-voip/SKILL.md +290 -371
  53. package/pipeline/skills/shared/external/callkit-voip/evals/evals.json +24 -24
  54. package/pipeline/skills/shared/external/callkit-voip/references/callkit-patterns.md +175 -343
  55. package/pipeline/skills/shared/external/ci-cd-pipelines/SKILL.md +1 -0
  56. package/pipeline/skills/shared/external/cloudkit-sync/SKILL.md +292 -381
  57. package/pipeline/skills/shared/external/cloudkit-sync/evals/evals.json +33 -30
  58. package/pipeline/skills/shared/external/cloudkit-sync/references/cloudkit-patterns.md +227 -355
  59. package/pipeline/skills/shared/external/compose-components/SKILL.md +2 -0
  60. package/pipeline/skills/shared/external/compose-navigation/SKILL.md +3 -2
  61. package/pipeline/skills/shared/external/compose-testing/SKILL.md +2 -0
  62. package/pipeline/skills/shared/external/contacts-framework/SKILL.md +197 -346
  63. package/pipeline/skills/shared/external/contacts-framework/evals/evals.json +19 -21
  64. package/pipeline/skills/shared/external/contacts-framework/references/contacts-patterns.md +169 -308
  65. package/pipeline/skills/shared/external/core-bluetooth/SKILL.md +226 -376
  66. package/pipeline/skills/shared/external/core-bluetooth/evals/evals.json +25 -22
  67. package/pipeline/skills/shared/external/core-bluetooth/references/ble-patterns.md +257 -337
  68. package/pipeline/skills/shared/external/core-data/SKILL.md +292 -368
  69. package/pipeline/skills/shared/external/core-data/evals/evals.json +30 -27
  70. package/pipeline/skills/shared/external/core-motion/SKILL.md +235 -324
  71. package/pipeline/skills/shared/external/core-motion/evals/evals.json +31 -27
  72. package/pipeline/skills/shared/external/core-motion/references/motion-patterns.md +210 -310
  73. package/pipeline/skills/shared/external/core-nfc/SKILL.md +292 -366
  74. package/pipeline/skills/shared/external/core-nfc/evals/evals.json +22 -24
  75. package/pipeline/skills/shared/external/core-nfc/references/nfc-patterns.md +233 -329
  76. package/pipeline/skills/shared/external/coreml/SKILL.md +323 -367
  77. package/pipeline/skills/shared/external/coreml/evals/evals.json +24 -21
  78. package/pipeline/skills/shared/external/coreml/references/coreml-swift-integration.md +562 -565
  79. package/pipeline/skills/shared/external/council/SKILL.md +1 -0
  80. package/pipeline/skills/shared/external/cryptokit/SKILL.md +253 -394
  81. package/pipeline/skills/shared/external/cryptokit/evals/evals.json +20 -18
  82. package/pipeline/skills/shared/external/cryptokit/references/cryptokit-patterns.md +299 -488
  83. package/pipeline/skills/shared/external/css-modern/SKILL.md +1 -0
  84. package/pipeline/skills/shared/external/database-patterns/SKILL.md +1 -0
  85. package/pipeline/skills/shared/external/debugging-instruments/SKILL.md +270 -323
  86. package/pipeline/skills/shared/external/debugging-instruments/evals/evals.json +27 -30
  87. package/pipeline/skills/shared/external/debugging-instruments/references/instruments-guide.md +167 -315
  88. package/pipeline/skills/shared/external/debugging-instruments/references/lldb-patterns.md +140 -193
  89. package/pipeline/skills/shared/external/device-integrity/SKILL.md +230 -353
  90. package/pipeline/skills/shared/external/device-integrity/evals/evals.json +25 -21
  91. package/pipeline/skills/shared/external/device-integrity/references/device-integrity-patterns.md +159 -197
  92. package/pipeline/skills/shared/external/energykit/SKILL.md +225 -392
  93. package/pipeline/skills/shared/external/energykit/evals/evals.json +29 -28
  94. package/pipeline/skills/shared/external/energykit/references/energykit-patterns.md +174 -470
  95. package/pipeline/skills/shared/external/eventkit-calendar/SKILL.md +261 -383
  96. package/pipeline/skills/shared/external/eventkit-calendar/evals/evals.json +25 -22
  97. package/pipeline/skills/shared/external/eventkit-calendar/references/eventkit-patterns.md +165 -268
  98. package/pipeline/skills/shared/external/evidence-github/SKILL.md +2 -0
  99. package/pipeline/skills/shared/external/evidence-registry/SKILL.md +2 -0
  100. package/pipeline/skills/shared/external/gradle-kotlin-dsl/SKILL.md +2 -0
  101. package/pipeline/skills/shared/external/healthkit/SKILL.md +252 -303
  102. package/pipeline/skills/shared/external/healthkit/evals/evals.json +24 -23
  103. package/pipeline/skills/shared/external/healthkit/references/healthkit-patterns.md +369 -523
  104. package/pipeline/skills/shared/external/homekit-matter/SKILL.md +233 -348
  105. package/pipeline/skills/shared/external/homekit-matter/evals/evals.json +27 -22
  106. package/pipeline/skills/shared/external/homekit-matter/references/matter-commissioning.md +199 -305
  107. package/pipeline/skills/shared/external/html-semantic/SKILL.md +1 -0
  108. package/pipeline/skills/shared/external/humanizer/SKILL.md +1 -0
  109. package/pipeline/skills/shared/external/ios-accessibility/SKILL.md +368 -340
  110. package/pipeline/skills/shared/external/ios-accessibility/evals/evals.json +28 -27
  111. package/pipeline/skills/shared/external/ios-accessibility/references/a11y-patterns.md +314 -260
  112. package/pipeline/skills/shared/external/ios-accessibility/references/media-accessibility.md +97 -67
  113. package/pipeline/skills/shared/external/ios-accessibility/references/nutrition-labels.md +165 -101
  114. package/pipeline/skills/shared/external/ios-coding-standard/SKILL.md +1 -0
  115. package/pipeline/skills/shared/external/ios-localization/SKILL.md +258 -371
  116. package/pipeline/skills/shared/external/ios-localization/evals/evals.json +23 -23
  117. package/pipeline/skills/shared/external/ios-localization/references/formatstyle-locale.md +283 -491
  118. package/pipeline/skills/shared/external/ios-localization/references/string-catalogs.md +313 -440
  119. package/pipeline/skills/shared/external/ios-module-structure/SKILL.md +1 -0
  120. package/pipeline/skills/shared/external/ios-networking/SKILL.md +265 -341
  121. package/pipeline/skills/shared/external/ios-networking/evals/evals.json +24 -24
  122. package/pipeline/skills/shared/external/ios-networking/references/background-websocket.md +425 -652
  123. package/pipeline/skills/shared/external/ios-networking/references/file-storage-patterns.md +143 -285
  124. package/pipeline/skills/shared/external/ios-networking/references/lightweight-clients.md +93 -53
  125. package/pipeline/skills/shared/external/ios-networking/references/network-framework.md +231 -456
  126. package/pipeline/skills/shared/external/ios-networking/references/urlsession-patterns.md +517 -784
  127. package/pipeline/skills/shared/external/ios-security/SKILL.md +2 -0
  128. package/pipeline/skills/shared/external/ios-simulator/SKILL.md +265 -393
  129. package/pipeline/skills/shared/external/ios-simulator/evals/evals.json +21 -21
  130. package/pipeline/skills/shared/external/ios-simulator/references/simctl-commands.md +177 -270
  131. package/pipeline/skills/shared/external/live-activities/SKILL.md +318 -360
  132. package/pipeline/skills/shared/external/live-activities/evals/evals.json +21 -21
  133. package/pipeline/skills/shared/external/live-activities/references/activitykit-patterns.md +478 -710
  134. package/pipeline/skills/shared/external/localization-reuse-map/SKILL.md +91 -283
  135. package/pipeline/skills/shared/external/localization-reuse-map/reference/format-and-output.md +119 -151
  136. package/pipeline/skills/shared/external/localization-reuse-map/reference/publish-and-snapshot.md +60 -90
  137. package/pipeline/skills/shared/external/localization-reuse-map/reference/sources-and-recipes.md +119 -156
  138. package/pipeline/skills/shared/external/localization-reuse-map/scripts/build-artifact.py +726 -787
  139. package/pipeline/skills/shared/external/localization-reuse-map/scripts/build-spreadsheet.py +253 -288
  140. package/pipeline/skills/shared/external/localization-reuse-map/scripts/fetch-annotations.py +243 -304
  141. package/pipeline/skills/shared/external/localization-reuse-map/scripts/fetch-legacy-labels.py +88 -104
  142. package/pipeline/skills/shared/external/localization-reuse-map/scripts/publish-confluence.py +181 -235
  143. package/pipeline/skills/shared/external/localization-reuse-map/scripts/render-key-shots.py +198 -263
  144. package/pipeline/skills/shared/external/localization-reuse-map/scripts/render-overlay.py +461 -466
  145. package/pipeline/skills/shared/external/localization-reuse-map/scripts/resolve-legacy-values.py +145 -151
  146. package/pipeline/skills/shared/external/localization-reuse-map/scripts/resolve-new-values.py +123 -141
  147. package/pipeline/skills/shared/external/localization-reuse-map/scripts/scan-screen-keys.py +146 -157
  148. package/pipeline/skills/shared/external/localization-reuse-map/scripts/snapshot-resources.sh +22 -19
  149. package/pipeline/skills/shared/external/localization-reuse-map/scripts/verify-map.py +156 -140
  150. package/pipeline/skills/shared/external/mapkit-location/SKILL.md +295 -267
  151. package/pipeline/skills/shared/external/mapkit-location/evals/evals.json +28 -24
  152. package/pipeline/skills/shared/external/mapkit-location/references/mapkit-corelocation-patterns.md +378 -532
  153. package/pipeline/skills/shared/external/mapkit-location/references/mapkit-patterns.md +397 -499
  154. package/pipeline/skills/shared/external/metrickit-diagnostics/SKILL.md +165 -348
  155. package/pipeline/skills/shared/external/metrickit-diagnostics/evals/evals.json +26 -23
  156. package/pipeline/skills/shared/external/metrickit-diagnostics/references/metrickit-patterns.md +123 -130
  157. package/pipeline/skills/shared/external/musickit-audio/SKILL.md +189 -315
  158. package/pipeline/skills/shared/external/musickit-audio/evals/evals.json +22 -21
  159. package/pipeline/skills/shared/external/musickit-audio/references/musickit-patterns.md +181 -270
  160. package/pipeline/skills/shared/external/natural-language/SKILL.md +188 -340
  161. package/pipeline/skills/shared/external/natural-language/evals/evals.json +21 -21
  162. package/pipeline/skills/shared/external/natural-language/references/translation-patterns.md +171 -225
  163. package/pipeline/skills/shared/external/nextjs-app-router/SKILL.md +1 -0
  164. package/pipeline/skills/shared/external/passkit-wallet/SKILL.md +258 -392
  165. package/pipeline/skills/shared/external/passkit-wallet/evals/evals.json +30 -29
  166. package/pipeline/skills/shared/external/passkit-wallet/references/wallet-passes.md +164 -231
  167. package/pipeline/skills/shared/external/pdfkit/SKILL.md +312 -344
  168. package/pipeline/skills/shared/external/pdfkit/evals/evals.json +19 -19
  169. package/pipeline/skills/shared/external/pdfkit/references/pdfkit-patterns.md +413 -624
  170. package/pipeline/skills/shared/external/pencilkit-drawing/SKILL.md +242 -358
  171. package/pipeline/skills/shared/external/pencilkit-drawing/evals/evals.json +25 -21
  172. package/pipeline/skills/shared/external/pencilkit-drawing/references/pencilkit-patterns.md +161 -226
  173. package/pipeline/skills/shared/external/permissionkit/SKILL.md +282 -400
  174. package/pipeline/skills/shared/external/permissionkit/evals/evals.json +27 -30
  175. package/pipeline/skills/shared/external/permissionkit/references/permissionkit-patterns.md +237 -350
  176. package/pipeline/skills/shared/external/photos-camera-media/SKILL.md +276 -325
  177. package/pipeline/skills/shared/external/photos-camera-media/references/av-playback.md +299 -545
  178. package/pipeline/skills/shared/external/photos-camera-media/references/camera-capture.md +344 -588
  179. package/pipeline/skills/shared/external/photos-camera-media/references/image-loading-caching.md +316 -660
  180. package/pipeline/skills/shared/external/photos-camera-media/references/photokit-patterns.md +270 -416
  181. package/pipeline/skills/shared/external/play-store-review/SKILL.md +2 -0
  182. package/pipeline/skills/shared/external/push-notifications/SKILL.md +312 -340
  183. package/pipeline/skills/shared/external/push-notifications/evals/evals.json +27 -26
  184. package/pipeline/skills/shared/external/push-notifications/references/notification-patterns.md +328 -485
  185. package/pipeline/skills/shared/external/push-notifications/references/rich-notifications.md +327 -560
  186. package/pipeline/skills/shared/external/python-patterns/SKILL.md +1 -0
  187. package/pipeline/skills/shared/external/react-best-practices/SKILL.md +1 -0
  188. package/pipeline/skills/shared/external/realitykit-ar/SKILL.md +218 -410
  189. package/pipeline/skills/shared/external/realitykit-ar/evals/evals.json +24 -27
  190. package/pipeline/skills/shared/external/realitykit-ar/references/realitykit-patterns.md +221 -348
  191. package/pipeline/skills/shared/external/rest-api-design/SKILL.md +1 -0
  192. package/pipeline/skills/shared/external/retrofit-networking/SKILL.md +2 -0
  193. package/pipeline/skills/shared/external/room-database/SKILL.md +2 -0
  194. package/pipeline/skills/shared/external/search-first/SKILL.md +1 -0
  195. package/pipeline/skills/shared/external/shareplay-activities/SKILL.md +222 -393
  196. package/pipeline/skills/shared/external/shareplay-activities/evals/evals.json +23 -24
  197. package/pipeline/skills/shared/external/shareplay-activities/references/shareplay-patterns.md +280 -420
  198. package/pipeline/skills/shared/external/signal-community/SKILL.md +2 -0
  199. package/pipeline/skills/shared/external/skill-creator/SKILL.md +80 -41
  200. package/pipeline/skills/shared/external/skill-creator/audit.md +63 -59
  201. package/pipeline/skills/shared/external/skill-creator/checklist.md +28 -20
  202. package/pipeline/skills/shared/external/skill-creator/examples.md +40 -40
  203. package/pipeline/skills/shared/external/skill-creator/label-check.md +48 -36
  204. package/pipeline/skills/shared/external/skill-creator/scripts/audit-panel.js +91 -100
  205. package/pipeline/skills/shared/external/skill-creator/template.md +51 -39
  206. package/pipeline/skills/shared/external/speech-recognition/SKILL.md +217 -421
  207. package/pipeline/skills/shared/external/speech-recognition/evals/evals.json +23 -26
  208. package/pipeline/skills/shared/external/speech-recognition/references/speechanalyzer-patterns.md +133 -125
  209. package/pipeline/skills/shared/external/storekit/SKILL.md +228 -204
  210. package/pipeline/skills/shared/external/storekit/evals/evals.json +27 -24
  211. package/pipeline/skills/shared/external/storekit/references/app-review-guidelines.md +98 -109
  212. package/pipeline/skills/shared/external/storekit/references/core-patterns.md +298 -242
  213. package/pipeline/skills/shared/external/storekit/references/storekit-advanced.md +356 -649
  214. package/pipeline/skills/shared/external/swift-api-design-guidelines/SKILL.md +274 -399
  215. package/pipeline/skills/shared/external/swift-api-design-guidelines/evals/evals.json +22 -24
  216. package/pipeline/skills/shared/external/swift-api-design-guidelines/references/argument-labels-and-parameters.md +107 -108
  217. package/pipeline/skills/shared/external/swift-api-design-guidelines/references/conventions-and-special-rules.md +93 -165
  218. package/pipeline/skills/shared/external/swift-api-design-guidelines/references/naming-and-clarity.md +99 -137
  219. package/pipeline/skills/shared/external/swift-api-design-guidelines/references/side-effects-and-mutating-pairs.md +77 -120
  220. package/pipeline/skills/shared/external/swift-architecture/SKILL.md +334 -350
  221. package/pipeline/skills/shared/external/swift-architecture/evals/evals.json +22 -22
  222. package/pipeline/skills/shared/external/swift-charts/SKILL.md +208 -394
  223. package/pipeline/skills/shared/external/swift-charts/evals/evals.json +27 -30
  224. package/pipeline/skills/shared/external/swift-charts/references/charts-patterns.md +351 -762
  225. package/pipeline/skills/shared/external/swift-codable/SKILL.md +339 -343
  226. package/pipeline/skills/shared/external/swift-codable/evals/evals.json +20 -20
  227. package/pipeline/skills/shared/external/swift-concurrency/SKILL.md +303 -351
  228. package/pipeline/skills/shared/external/swift-concurrency/evals/evals.json +27 -24
  229. package/pipeline/skills/shared/external/swift-concurrency/references/approachable-concurrency.md +65 -80
  230. package/pipeline/skills/shared/external/swift-concurrency/references/async-algorithms.md +48 -84
  231. package/pipeline/skills/shared/external/swift-concurrency/references/bridging-interop.md +134 -79
  232. package/pipeline/skills/shared/external/swift-concurrency/references/concurrency-patterns.md +145 -167
  233. package/pipeline/skills/shared/external/swift-concurrency/references/diagnostics.md +62 -50
  234. package/pipeline/skills/shared/external/swift-concurrency/references/swiftui-concurrency.md +92 -121
  235. package/pipeline/skills/shared/external/swift-concurrency/references/synchronization-primitives.md +177 -241
  236. package/pipeline/skills/shared/external/swift-formatstyle/SKILL.md +258 -234
  237. package/pipeline/skills/shared/external/swift-language/SKILL.md +342 -382
  238. package/pipeline/skills/shared/external/swift-language/evals/evals.json +24 -27
  239. package/pipeline/skills/shared/external/swift-language/references/swift-attributes-interop.md +79 -56
  240. package/pipeline/skills/shared/external/swift-language/references/swift-patterns-extended.md +297 -340
  241. package/pipeline/skills/shared/external/swift-security/SKILL.md +180 -161
  242. package/pipeline/skills/shared/external/swift-security/evals/evals.json +25 -25
  243. package/pipeline/skills/shared/external/swift-security/references/biometric-authentication.md +314 -469
  244. package/pipeline/skills/shared/external/swift-security/references/certificate-trust.md +408 -476
  245. package/pipeline/skills/shared/external/swift-security/references/common-anti-patterns.md +260 -530
  246. package/pipeline/skills/shared/external/swift-security/references/compliance-owasp-mapping.md +270 -477
  247. package/pipeline/skills/shared/external/swift-security/references/credential-storage-patterns.md +573 -571
  248. package/pipeline/skills/shared/external/swift-security/references/cryptokit-public-key.md +370 -441
  249. package/pipeline/skills/shared/external/swift-security/references/cryptokit-symmetric.md +332 -433
  250. package/pipeline/skills/shared/external/swift-security/references/keychain-access-control.md +346 -468
  251. package/pipeline/skills/shared/external/swift-security/references/keychain-fundamentals.md +352 -472
  252. package/pipeline/skills/shared/external/swift-security/references/keychain-item-classes.md +431 -432
  253. package/pipeline/skills/shared/external/swift-security/references/keychain-sharing.md +328 -425
  254. package/pipeline/skills/shared/external/swift-security/references/migration-legacy-stores.md +341 -579
  255. package/pipeline/skills/shared/external/swift-security/references/secure-enclave.md +396 -457
  256. package/pipeline/skills/shared/external/swift-security/references/testing-security-code.md +354 -614
  257. package/pipeline/skills/shared/external/swift-testing/SKILL.md +188 -175
  258. package/pipeline/skills/shared/external/swift-testing/evals/evals.json +26 -24
  259. package/pipeline/skills/shared/external/swift-testing/references/testing-advanced.md +80 -84
  260. package/pipeline/skills/shared/external/swift-testing/references/testing-patterns.md +317 -433
  261. package/pipeline/skills/shared/external/swiftdata/SKILL.md +392 -256
  262. package/pipeline/skills/shared/external/swiftdata/evals/evals.json +24 -24
  263. package/pipeline/skills/shared/external/swiftdata/references/core-data-coexistence.md +206 -402
  264. package/pipeline/skills/shared/external/swiftdata/references/indexing.md +59 -52
  265. package/pipeline/skills/shared/external/swiftdata/references/predicate-pitfalls.md +57 -33
  266. package/pipeline/skills/shared/external/swiftdata/references/swiftdata-advanced.md +354 -747
  267. package/pipeline/skills/shared/external/swiftdata/references/swiftdata-queries.md +300 -508
  268. package/pipeline/skills/shared/external/swiftlint/SKILL.md +175 -226
  269. package/pipeline/skills/shared/external/swiftlint/references/adoption-and-configuration.md +141 -208
  270. package/pipeline/skills/shared/external/swiftlint/references/custom-rules-and-analyze.md +100 -109
  271. package/pipeline/skills/shared/external/swiftlint/references/plugins-run-scripts-and-integrations.md +159 -179
  272. package/pipeline/skills/shared/external/swiftlint/references/rule-reference.md +383 -18
  273. package/pipeline/skills/shared/external/swiftlint/references/rules-suppressions-and-baselines.md +143 -229
  274. package/pipeline/skills/shared/external/swiftui-animation/SKILL.md +283 -366
  275. package/pipeline/skills/shared/external/swiftui-animation/references/animation-advanced.md +396 -608
  276. package/pipeline/skills/shared/external/swiftui-animation/references/core-animation-bridge.md +336 -385
  277. package/pipeline/skills/shared/external/swiftui-gestures/SKILL.md +239 -349
  278. package/pipeline/skills/shared/external/swiftui-gestures/references/gesture-patterns.md +228 -310
  279. package/pipeline/skills/shared/external/swiftui-layout-components/SKILL.md +260 -249
  280. package/pipeline/skills/shared/external/swiftui-layout-components/references/form.md +92 -74
  281. package/pipeline/skills/shared/external/swiftui-layout-components/references/grids.md +112 -177
  282. package/pipeline/skills/shared/external/swiftui-layout-components/references/list.md +61 -64
  283. package/pipeline/skills/shared/external/swiftui-layout-components/references/scrollview.md +94 -134
  284. package/pipeline/skills/shared/external/swiftui-liquid-glass/SKILL.md +193 -225
  285. package/pipeline/skills/shared/external/swiftui-liquid-glass/references/liquid-glass.md +173 -327
  286. package/pipeline/skills/shared/external/swiftui-navigation/SKILL.md +193 -168
  287. package/pipeline/skills/shared/external/swiftui-navigation/references/deeplinks.md +127 -150
  288. package/pipeline/skills/shared/external/swiftui-navigation/references/navigationstack.md +132 -133
  289. package/pipeline/skills/shared/external/swiftui-navigation/references/sheets.md +152 -117
  290. package/pipeline/skills/shared/external/swiftui-navigation/references/tabview.md +106 -140
  291. package/pipeline/skills/shared/external/swiftui-patterns/SKILL.md +316 -252
  292. package/pipeline/skills/shared/external/swiftui-patterns/references/architecture-patterns.md +341 -332
  293. package/pipeline/skills/shared/external/swiftui-patterns/references/deprecated-migration.md +547 -854
  294. package/pipeline/skills/shared/external/swiftui-patterns/references/design-polish.md +485 -537
  295. package/pipeline/skills/shared/external/swiftui-patterns/references/platform-and-sharing.md +417 -499
  296. package/pipeline/skills/shared/external/swiftui-performance/SKILL.md +213 -376
  297. package/pipeline/skills/shared/external/swiftui-performance/references/demystify-swiftui-performance-wwdc23.md +86 -175
  298. package/pipeline/skills/shared/external/swiftui-performance/references/optimizing-swiftui-performance-instruments.md +89 -195
  299. package/pipeline/skills/shared/external/swiftui-performance/references/understanding-hangs-in-your-app.md +95 -182
  300. package/pipeline/skills/shared/external/swiftui-performance/references/understanding-improving-swiftui-performance.md +71 -149
  301. package/pipeline/skills/shared/external/swiftui-performance/references/wwdc-session-sources.md +21 -27
  302. package/pipeline/skills/shared/external/swiftui-uikit-interop/SKILL.md +303 -295
  303. package/pipeline/skills/shared/external/swiftui-uikit-interop/references/hosting-migration.md +204 -387
  304. package/pipeline/skills/shared/external/swiftui-uikit-interop/references/representable-recipes.md +469 -683
  305. package/pipeline/skills/shared/external/swiftui-webkit/SKILL.md +140 -186
  306. package/pipeline/skills/shared/external/swiftui-webkit/references/loading-and-observation.md +75 -86
  307. package/pipeline/skills/shared/external/swiftui-webkit/references/local-content-and-custom-schemes.md +63 -60
  308. package/pipeline/skills/shared/external/swiftui-webkit/references/migration-and-fallbacks.md +69 -137
  309. package/pipeline/skills/shared/external/swiftui-webkit/references/navigation-and-javascript.md +95 -67
  310. package/pipeline/skills/shared/external/tailwind-css/SKILL.md +1 -0
  311. package/pipeline/skills/shared/external/testing-backend/SKILL.md +1 -0
  312. package/pipeline/skills/shared/external/tipkit/SKILL.md +220 -335
  313. package/pipeline/skills/shared/external/tipkit/references/tipkit-patterns.md +356 -494
  314. package/pipeline/skills/shared/external/typescript-patterns/SKILL.md +1 -0
  315. package/pipeline/skills/shared/external/vision-framework/SKILL.md +260 -375
  316. package/pipeline/skills/shared/external/vision-framework/references/vision-requests.md +393 -515
  317. package/pipeline/skills/shared/external/vision-framework/references/visionkit-scanner.md +363 -539
  318. package/pipeline/skills/shared/external/vue-composition/SKILL.md +1 -0
  319. package/pipeline/skills/shared/external/weatherkit/SKILL.md +152 -310
  320. package/pipeline/skills/shared/external/weatherkit/references/weatherkit-patterns.md +288 -407
  321. package/pipeline/skills/shared/external/web-accessibility/SKILL.md +1 -0
  322. package/pipeline/skills/shared/external/web-performance/SKILL.md +1 -0
  323. package/pipeline/skills/shared/external/web-testing/SKILL.md +1 -0
  324. package/pipeline/skills/shared/external/widgetkit/SKILL.md +216 -288
  325. package/pipeline/skills/shared/external/widgetkit/references/widgetkit-advanced.md +414 -719
  326. package/pipeline/skills/shared/external/NOTICE-swift-ios-skills.md +0 -39
@@ -1,341 +1,365 @@
1
1
  ---
2
2
  name: swift-formatstyle
3
- description: "Format values for display using the FormatStyle protocol and its concrete types. Use when formatting numbers (integers, floating-point, decimals), currencies, percentages, dates, date ranges, relative dates, durations (Duration.TimeFormatStyle, Duration.UnitsFormatStyle), measurements, person names (PersonNameComponents.FormatStyle), byte counts (ByteCountFormatStyle), lists (ListFormatStyle), and URLs (URL.FormatStyle). Also covers creating custom FormatStyle conformances and replacing legacy Formatter subclasses. FormatStyle is available iOS 15+; Duration styles require iOS 16+."
3
+ description: "Display formatting with FormatStyle (iOS 15+): integers, floating point, decimals, currency, percentages, dates, date ranges, relative and anchored relative dates, durations (Duration.TimeFormatStyle, Duration.UnitsFormatStyle, iOS 16+), measurements, person names, byte counts, lists, URLs (iOS 16+), parsing, custom FormatStyle conformances. Use when formatting values for display, replacing legacy Formatter subclasses, or writing a custom format style. String Catalogs, plurals and RTL review belong to ios-localization."
4
4
  metadata:
5
- source: "dpearson2699/swift-ios-skills (PolyForm Perimeter 1.0.0)"
5
+ source: multi-agent-pipeline
6
6
  ---
7
7
 
8
8
  # Swift FormatStyle
9
9
 
10
- Format values for human-readable display using the `FormatStyle` protocol
11
- and Foundation's concrete format styles. Replaces legacy `Formatter` subclasses
12
- with a type-safe, composable, cacheable API.
13
-
14
- Locale-aware display is an i18n concern even when the app is not adding new languages. For user-facing formatted output, always recommend previewing or testing representative locales such as `en_US`, `de_DE`, `ar_SA`, and `ja_JP`; check separators, numbering systems, calendars, currency and unit conventions, text direction, and layout-sensitive output. Keep this skill focused on `FormatStyle`, `ParseableFormatStyle`, parsing, and reusable formatter API design; route broader localization work such as String Catalogs, bundles, plurals, localized copy, and RTL layout review to `ios-localization`. Do not use "not adding languages" as the reason to skip `ios-localization`; locale-sensitive formatting can be a localization review issue without translation work.
15
-
16
- Docs: [FormatStyle](https://sosumi.ai/documentation/foundation/formatstyle)
17
-
18
- ## Contents
19
-
20
- - [Quick Reference](#quick-reference)
21
- - [Numbers](#numbers)
22
- - [Currency](#currency)
23
- - [Percentages](#percentages)
24
- - [Dates](#dates)
25
- - [Durations](#durations)
26
- - [Measurements](#measurements)
27
- - [Person Names](#person-names)
28
- - [Lists](#lists)
29
- - [Byte Counts](#byte-counts)
30
- - [URLs](#urls)
31
- - [SwiftUI Integration](#swiftui-integration)
32
- - [Custom FormatStyle](#custom-formatstyle)
33
- - [Common Mistakes](#common-mistakes)
34
- - [Review Checklist](#review-checklist)
35
-
36
- ## Quick Reference
37
-
38
- | Type | Style Access | Example |
39
- |------|-------------|---------|
40
- | `Int`, `Double` | `.number` | `42.formatted(.number.precision(.fractionLength(2)))` → `"42.00"` |
41
- | Currency | `.currency(code:)` | `29.99.formatted(.currency(code: "USD"))` → `"$29.99"` |
42
- | Percent | `.percent` | `0.85.formatted(.percent)` → `"85%"` |
43
- | `Date` | `.dateTime` | `Date.now.formatted(.dateTime.month().day().year())` |
44
- | Date range | `.interval` | `(date1..<date2).formatted(.interval)` |
45
- | Relative date | `.relative(presentation:unitsStyle:)` | `date.formatted(.relative(presentation: .named))` → `"yesterday"` |
46
- | `Duration` | `.time(pattern:)` | `Duration.seconds(3661).formatted(.time(pattern: .hourMinuteSecond))` → `"1:01:01"` |
47
- | `Duration` | `.units(allowed:width:)` | `Duration.seconds(90).formatted(.units(allowed: [.minutes, .seconds]))` → `"1 min, 30 sec"` |
48
- | `Measurement` | `.measurement(width:)` | `Measurement(value: 72, unit: UnitTemperature.fahrenheit).formatted(.measurement(width: .abbreviated))` |
49
- | `PersonNameComponents` | `.name(style:)` | `name.formatted(.name(style: .short))` → `"Tom"` |
50
- | `[String]` | `.list(type:width:)` | `["A","B","C"].formatted(.list(type: .and))` → `"A, B, and C"` |
51
- | Byte count | `.byteCount(style:)` | `Int64(1_048_576).formatted(.byteCount(style: .memory))` → `"1 MB"` |
52
- | `URL` | `.url` | `url.formatted(.url.scheme(.never).host().path())` |
10
+ `FormatStyle` describes how one kind of value becomes text, as a small typed
11
+ value you can chain and reuse, instead of configured `Formatter` objects. Foundation caches the
12
+ expensive machinery behind them, so a style can be written inline wherever a
13
+ value is shown. Availability: iOS 15 for the protocol and most styles, iOS 16
14
+ for the `Duration` and `URL` styles, iOS 18 for `Date.AnchoredRelativeFormatStyle`.
15
+
16
+ ## Locale review is part of the job
17
+
18
+ Formatting output changes with the user's region even in an app that ships one
19
+ language. Whenever this skill is used, recommend previewing or testing at least
20
+ `en_US`, `de_DE`, `ar_SA` and `ja_JP`, and check:
21
+
22
+ - decimal and grouping separators,
23
+ - the numbering system (Arabic-Indic digits in `ar_SA`),
24
+ - calendar and date order,
25
+ - where the currency sign goes and which units people expect,
26
+ - right-to-left output, and any layout that depends on the string's length.
27
+
28
+ Work on String Catalogs, bundles, plural rules, translated copy and RTL layout
29
+ review belongs to `ios-localization`. "We are not adding languages" is not a
30
+ reason to skip that review.
31
+
32
+ ## Quick reference
33
+
34
+ | Value | Style | Example output (en_US) |
35
+ | --- | --- | --- |
36
+ | `Int`, `Double` | `.number` | `9.formatted(.number.precision(.fractionLength(2)))` gives "9.00" |
37
+ | Currency | `.currency(code:)` | 12.5 with `"USD"` gives "$12.50" |
38
+ | Percent | `.percent` | 0.4 gives "40%" |
39
+ | `Date` | `.dateTime` | `.dateTime.month().day().year()` gives "Mar 3, 2026" |
40
+ | Date range | `.interval` | `(opening..<closing).formatted(.interval)` |
41
+ | Relative date | `.relative(presentation:unitsStyle:)` | `.named` gives "yesterday" |
42
+ | `Duration` | `.time(pattern:)` | 3661 seconds as `.hourMinuteSecond` is "1:01:01" |
43
+ | `Duration` | `.units(allowed:width:)` | 90 seconds is "1 min, 30 sec" |
44
+ | `Measurement` | `.measurement(width:)` | "72°F" |
45
+ | `PersonNameComponents` | `.name(style:)` | "Ada Lovelace" |
46
+ | `[String]` | `.list(type:width:)` | three names with `.and` read "Mina, Omar, and Lea" |
47
+ | Byte count | `.byteCount(style:)` | one mebibyte (1,048,576 bytes) with `.memory` is "1 MB" |
48
+ | `URL` | `.url` | `.url.scheme(.never).host().path()` drops "https://" and the query |
53
49
 
54
50
  ## Numbers
55
51
 
56
- ```swift
57
- // Default locale-aware formatting
58
- let n = 1234567.formatted() // "1,234,567" (en_US)
59
-
60
- // Precision
61
- 1234.5.formatted(.number.precision(.fractionLength(0...2))) // "1,234.5"
62
- 1234.5.formatted(.number.precision(.significantDigits(3))) // "1,230"
52
+ Plain `formatted()` already follows the user's locale: 2500000 shows as
53
+ "2,500,000" in `en_US` and "2.500.000" in `de_DE`.
63
54
 
64
- // Rounding
65
- 1234.formatted(.number.rounded(rule: .down, increment: 100)) // "1,200"
55
+ ```swift
56
+ let upToTwo = FloatingPointFormatStyle<Double>.number.precision(.fractionLength(0...2))
57
+ let threeSignificant = FloatingPointFormatStyle<Double>.number.precision(.significantDigits(3))
58
+ (7.0 / 3.0).formatted(upToTwo) // "2.33"
59
+ (7.0 / 3.0).formatted(threeSignificant) // "2.33"
60
+
61
+ let seats = 1834
62
+ seats.formatted(.number.rounded(rule: .down, increment: 100)) // "1,800"
63
+ seats.formatted(.number.grouping(.never)) // "1834"
64
+ seats.formatted(.number.sign(strategy: .always())) // "+1,834"
65
+ seats.formatted(.number.locale(Locale(identifier: "fr_FR"))) // "1 834"
66
+
67
+ let audience = 3_400_000
68
+ audience.formatted(.number.notation(.compactName)) // "3.4M"
69
+ 0.00042.formatted(.number.notation(.scientific)) // "4.2E-4"
70
+ ```
66
71
 
67
- // Grouping
68
- 1234567.formatted(.number.grouping(.never)) // "1234567"
72
+ The styles behind these are `IntegerFormatStyle` and
73
+ `FloatingPointFormatStyle` (and `Decimal.FormatStyle`).
69
74
 
70
- // Notation
71
- 1_200_000.formatted(.number.notation(.compactName)) // "1.2M"
72
- 42.formatted(.number.notation(.scientific)) // "4.2E1"
75
+ ## Currency
73
76
 
74
- // Sign display
75
- (-42).formatted(.number.sign(strategy: .always())) // "+42" / "-42"
77
+ The ISO 4217 code decides the symbol and the usual number of fraction digits,
78
+ so yen shows no decimals:
76
79
 
77
- // Locale override
78
- 42.formatted(.number.locale(Locale(identifier: "de_DE"))) // "42"
80
+ ```swift
81
+ 18.75.formatted(.currency(code: "EUR")) // "€18.75" in en_US
82
+ 30.0.formatted(.currency(code: "JPY")) // "¥30"
79
83
  ```
80
84
 
81
- Docs: [IntegerFormatStyle](https://sosumi.ai/documentation/foundation/integerformatstyle),
82
- [FloatingPointFormatStyle](https://sosumi.ai/documentation/foundation/floatingpointformatstyle)
83
-
84
- ## Currency
85
+ To override precision, build the style explicitly:
85
86
 
86
87
  ```swift
87
- 29.99.formatted(.currency(code: "USD")) // "$29.99"
88
- 29.99.formatted(.currency(code: "EUR")) // "€29.99"
89
- 29.99.formatted(.currency(code: "JPY")) // "¥30"
90
-
91
- // Customize precision
92
- let style = FloatingPointFormatStyle<Double>.Currency(code: "USD")
88
+ let noCents = FloatingPointFormatStyle<Double>.Currency(code: "USD")
93
89
  .precision(.fractionLength(0))
94
- 1234.56.formatted(style) // "$1,235"
90
+ let price = 1299.99
91
+ price.formatted(noCents) // "$1,300"
95
92
  ```
96
93
 
97
94
  ## Percentages
98
95
 
96
+ A floating-point value is a fraction; an integer is already a percentage.
97
+
99
98
  ```swift
100
- 0.85.formatted(.percent) // "85%"
101
- 0.8567.formatted(.percent.precision(.fractionLength(1))) // "85.7%"
102
- 42.formatted(.percent) // "42%" (integer)
99
+ let completion = 0.8567
100
+ completion.formatted(.percent) // "85.67%"
101
+ completion.formatted(.percent.precision(.fractionLength(1))) // "85.7%"
102
+ let passRate = 42
103
+ passRate.formatted(.percent) // "42%"
103
104
  ```
104
105
 
105
106
  ## Dates
106
107
 
108
+ Build exactly the fields you want; the locale decides order and punctuation.
109
+
107
110
  ```swift
108
- let now = Date.now
111
+ let launch = Date.now
112
+ launch.formatted(.dateTime.day().month().year()) // "Mar 3, 2026" (order comes from the locale)
113
+ launch.formatted(.dateTime.minute().hour()) // "4:05 PM"
114
+ let spelledOut = Date.FormatStyle.dateTime.day().month(.wide).weekday(.wide)
115
+ launch.formatted(spelledOut) // "Tuesday, March 3"
116
+ ```
117
+
118
+ Predefined combinations:
109
119
 
110
- // Components
111
- now.formatted(.dateTime.year().month().day()) // "Apr 22, 2026"
112
- now.formatted(.dateTime.hour().minute()) // "4:30 PM"
113
- now.formatted(.dateTime.weekday(.wide).month(.wide).day()) // "Wednesday, April 22"
120
+ ```swift
121
+ launch.formatted(date: .long, time: .shortened) // "March 3, 2026 at 4:05 PM"
122
+ launch.formatted(date: .abbreviated, time: .omitted) // "Mar 3, 2026"
123
+ launch.formatted(.iso8601) // "2026-03-03T13:05:00Z"
124
+ ```
114
125
 
115
- // Predefined styles
116
- now.formatted(date: .long, time: .shortened) // "April 22, 2026 at 4:30 PM"
117
- now.formatted(date: .abbreviated, time: .omitted) // "Apr 22, 2026"
126
+ Relative to now:
118
127
 
119
- // ISO 8601
120
- now.formatted(.iso8601) // "2026-04-22T16:30:00Z"
128
+ ```swift
129
+ let dayBefore = Date.now.addingTimeInterval(-86_400)
130
+ dayBefore.formatted(.relative(presentation: .named)) // "yesterday"
131
+ let numericAgo = Date.RelativeFormatStyle(presentation: .numeric)
132
+ dayBefore.formatted(numericAgo) // "1 day ago"
133
+ ```
121
134
 
122
- // Relative
123
- let yesterday = Calendar.current.date(byAdding: .day, value: -1, to: .now)!
124
- yesterday.formatted(.relative(presentation: .named)) // "yesterday"
125
- yesterday.formatted(.relative(presentation: .numeric)) // "1 day ago"
135
+ Ranges and countdowns:
126
136
 
127
- // Interval
128
- (date1..<date2).formatted(.interval.month().day().hour().minute())
137
+ ```swift
138
+ let slot = launch..<launch.addingTimeInterval(5_400)
139
+ let meetingSpan = Date.IntervalFormatStyle().day().month().minute().hour()
140
+ slot.formatted(meetingSpan) // "Mar 3, 4:05 - 5:35 PM" (ICU prints an en dash)
129
141
 
130
- // Components (countdown-style)
131
- (date1..<date2).formatted(.components(style: .wide, fields: [.day, .hour]))
132
- // "2 days, 5 hours"
142
+ let untilDeparture = Date.now..<Date.now.addingTimeInterval(190_800)
143
+ let countdown = Date.ComponentsFormatStyle(style: .wide, fields: [.hour, .day])
144
+ untilDeparture.formatted(countdown) // "2 days, 5 hours"
133
145
  ```
134
146
 
135
- Docs: [Date.FormatStyle](https://sosumi.ai/documentation/foundation/date/formatstyle),
136
- [Date.RelativeFormatStyle](https://sosumi.ai/documentation/foundation/date/relativeformatstyle),
137
- [Date.IntervalFormatStyle](https://sosumi.ai/documentation/foundation/date/intervalformatstyle)
147
+ Related types: `Date.FormatStyle`, `Date.RelativeFormatStyle`,
148
+ `Date.IntervalFormatStyle`, `Date.ComponentsFormatStyle`.
138
149
 
139
- ### Anchored Relative Dates (iOS 18+)
150
+ ### Relative to a chosen reference (iOS 18+)
140
151
 
141
- `Date.AnchoredRelativeFormatStyle` formats relative to a fixed anchor date
142
- rather than the current moment.
152
+ `Date.AnchoredRelativeFormatStyle` describes one fixed date, the anchor,
153
+ relative to whatever moment you format. Plain `.relative` always measures from
154
+ the real current time; the anchored style lets you choose the reference, which
155
+ suits timelines, widgets and tests.
143
156
 
144
- Docs: [Date.AnchoredRelativeFormatStyle](https://sosumi.ai/documentation/foundation/date/anchoredrelativeformatstyle)
157
+ ```swift
158
+ let meetup = Date(timeIntervalSince1970: 1_800_000_000)
159
+ let style = Date.AnchoredRelativeFormatStyle(anchor: meetup, presentation: .named)
160
+ style.format(meetup.addingTimeInterval(86_400)) // "yesterday": the anchor was a day before the reference
161
+ style.format(meetup.addingTimeInterval(-3_600)) // "in 1 hour"
162
+ ```
145
163
 
146
164
  ## Durations
147
165
 
148
- `Duration` (iOS 16+) has two format styles:
166
+ A `Duration` (iOS 16+) can be shown as a clock reading with
167
+ `Duration.TimeFormatStyle` or as labeled units with `Duration.UnitsFormatStyle`.
149
168
 
150
- Docs: [Duration.TimeFormatStyle](https://sosumi.ai/documentation/swift/duration/timeformatstyle),
151
- [Duration.UnitsFormatStyle](https://sosumi.ai/documentation/swift/duration/unitsformatstyle)
169
+ ```swift
170
+ let ride = Duration.seconds(7_384) // 2 h 3 min 4 s
171
+ ride.formatted(.time(pattern: .hourMinuteSecond)) // "2:03:04"
172
+ ride.formatted(.time(pattern: .hourMinute)) // "2:03"
173
+ ride.formatted(.time(pattern: .minuteSecond)) // "123:04" (minutes are not wrapped into hours)
152
174
 
153
- ### TimeFormatStyle - compact separator-based
175
+ let stopwatch = Duration.TimeFormatStyle.Pattern.minuteSecond(padMinuteToLength: 2, fractionalSecondsLength: 2)
176
+ Duration.milliseconds(3_750).formatted(.time(pattern: stopwatch)) // "00:03.75"
177
+ ```
154
178
 
155
179
  ```swift
156
- let d = Duration.seconds(3661)
157
-
158
- d.formatted(.time(pattern: .hourMinuteSecond)) // "1:01:01"
159
- d.formatted(.time(pattern: .hourMinute)) // "1:01"
160
- d.formatted(.time(pattern: .minuteSecond)) // "61:01"
180
+ let clock: Set<Duration.UnitsFormatStyle.Unit> = [.hours, .minutes, .seconds]
181
+ ride.formatted(.units(allowed: clock, width: .abbreviated)) // "2 hr, 3 min, 4 sec"
182
+ ride.formatted(.units(allowed: clock, width: .wide, maximumUnitCount: 1)) // "2 hours"
161
183
 
162
- // Fractional seconds
163
- Duration.seconds(3.75).formatted(
164
- .time(pattern: .minuteSecond(padMinuteToLength: 2, fractionalSecondsLength: 2))
165
- ) // "00:03.75"
184
+ let rest = Duration.seconds(150)
185
+ rest.formatted(.units(allowed: [.minutes, .seconds], width: .wide)) // "2 minutes, 30 seconds"
186
+ rest.formatted(.units(allowed: [.minutes, .seconds], width: .narrow)) // "2m 30s"
166
187
  ```
167
188
 
168
- ### UnitsFormatStyle - labeled units
189
+ `maximumUnitCount` caps how many units appear.
190
+
191
+ ## Measurements
169
192
 
170
193
  ```swift
171
- Duration.seconds(3661).formatted(
172
- .units(allowed: [.hours, .minutes, .seconds], width: .abbreviated)
173
- ) // "1 hr, 1 min, 1 sec"
174
-
175
- Duration.seconds(90).formatted(
176
- .units(allowed: [.minutes, .seconds], width: .wide)
177
- ) // "1 minute, 30 seconds"
178
-
179
- Duration.seconds(90).formatted(
180
- .units(allowed: [.minutes, .seconds], width: .narrow)
181
- ) // "1m 30s"
182
-
183
- // Limit unit count
184
- Duration.seconds(3661).formatted(
185
- .units(allowed: [.hours, .minutes, .seconds], width: .abbreviated, maximumUnitCount: 2)
186
- ) // "1 hr, 1 min"
194
+ let poolWater = Measurement<UnitTemperature>(value: 81, unit: .fahrenheit)
195
+ poolWater.formatted(.measurement(width: .wide)) // "81 degrees Fahrenheit"
196
+ poolWater.formatted(.measurement(width: .abbreviated)) // "81°F"
197
+ poolWater.formatted(.measurement(width: .narrow)) // "81°"
187
198
  ```
188
199
 
189
- ## Measurements
200
+ `usage:` lets the style convert to what the locale expects for that context:
190
201
 
191
202
  ```swift
192
- let temp = Measurement(value: 72, unit: UnitTemperature.fahrenheit)
193
- temp.formatted(.measurement(width: .wide)) // "72 degrees Fahrenheit"
194
- temp.formatted(.measurement(width: .abbreviated)) // "72°F"
195
- temp.formatted(.measurement(width: .narrow)) // "72°"
196
-
197
- let dist = Measurement(value: 5, unit: UnitLength.kilometers)
198
- dist.formatted(.measurement(width: .abbreviated, usage: .road)) // "3.1 mi" (en_US)
203
+ let hike = Measurement<UnitLength>(value: 8, unit: .kilometers)
204
+ let roadSign = Measurement<UnitLength>.FormatStyle(width: .abbreviated, usage: .road)
205
+ hike.formatted(roadSign) // "5 mi" in en_US, "8 km" in de_DE
199
206
  ```
200
207
 
201
- Docs: [Measurement.FormatStyle](https://sosumi.ai/documentation/foundation/measurement/formatstyle)
208
+ The type is `Measurement<Unit>.FormatStyle`.
209
+
210
+ ## Person names
202
211
 
203
- ## Person Names
212
+ `PersonNameComponents` holds `givenName`, `familyName`, `middleName`,
213
+ `namePrefix`, `nickname` and `nameSuffix`.
204
214
 
205
215
  ```swift
206
- var name = PersonNameComponents()
207
- name.givenName = "Thomas"
208
- name.familyName = "Clark"
209
- name.middleName = "Louis"
210
- name.namePrefix = "Dr."
211
- name.nickname = "Tom"
212
- name.nameSuffix = "Esq."
213
-
214
- name.formatted(.name(style: .long)) // "Dr. Thomas Louis Clark Esq."
215
- name.formatted(.name(style: .medium)) // "Thomas Clark"
216
- name.formatted(.name(style: .short)) // "Tom"
217
- name.formatted(.name(style: .abbreviated)) // "TC"
216
+ var person = PersonNameComponents()
217
+ person.namePrefix = "Dr."
218
+ person.givenName = "Ada"
219
+ person.familyName = "Lovelace"
220
+ person.nickname = "Addie"
221
+
222
+ person.formatted(.name(style: .long)) // "Dr. Ada Lovelace"
223
+ person.formatted(.name(style: .medium)) // "Ada Lovelace"
224
+ person.formatted(.name(style: .short)) // "Addie"
225
+ person.formatted(.name(style: .abbreviated)) // "AL"
218
226
  ```
219
227
 
220
- Style resolution follows priority: script → user preferences → locale → developer setting.
221
-
222
- Docs: [PersonNameComponents.FormatStyle](https://sosumi.ai/documentation/foundation/personnamecomponents/formatstyle)
228
+ The final order and form depend, in priority order, on the script of the name,
229
+ the user's preferences, the locale, and only then the style you asked for.
223
230
 
224
231
  ## Lists
225
232
 
226
233
  ```swift
227
- ["Alice", "Bob", "Charlie"].formatted(.list(type: .and))
228
- // "Alice, Bob, and Charlie"
229
-
230
- ["Alice", "Bob", "Charlie"].formatted(.list(type: .or))
231
- // "Alice, Bob, or Charlie"
234
+ let crew = ["Mina", "Omar", "Lea"]
235
+ crew.formatted(.list(type: .and)) // "Mina, Omar, and Lea"
236
+ crew.formatted(.list(type: .or)) // "Mina, Omar, or Lea"
237
+ crew.formatted(.list(type: .and, width: .narrow)) // "Mina, Omar, Lea"
232
238
 
233
- // With member formatting
234
- [1, 2, 3].formatted(.list(memberStyle: .number, type: .and))
235
- // "1, 2, and 3"
236
-
237
- // Narrow width
238
- ["A", "B", "C"].formatted(.list(type: .and, width: .narrow))
239
- // "A, B, C"
239
+ let lanes = [3, 5, 8]
240
+ lanes.formatted(.list(memberStyle: IntegerFormatStyle<Int>(), type: .and)) // "3, 5, and 8"
240
241
  ```
241
242
 
242
- Docs: [ListFormatStyle](https://sosumi.ai/documentation/foundation/listformatstyle)
243
+ The type is `ListFormatStyle`.
243
244
 
244
- ## Byte Counts
245
+ ## Byte counts
245
246
 
246
247
  ```swift
247
- Int64(1_048_576).formatted(.byteCount(style: .memory)) // "1 MB"
248
- Int64(1_048_576).formatted(.byteCount(style: .file)) // "1 MB"
249
- Int64(1_048_576).formatted(.byteCount(style: .binary)) // "1 MiB"
248
+ let attachment: Int64 = 1_048_576
249
+ var labels: [String] = []
250
+ for style in [ByteCountFormatStyle.Style.memory, .file, .binary] {
251
+ labels.append(attachment.formatted(.byteCount(style: style))) // "1 MB" each time
252
+ }
250
253
  ```
251
254
 
252
- Docs: [ByteCountFormatStyle](https://sosumi.ai/documentation/foundation/bytecountformatstyle)
255
+ `.memory` and `.binary` count in powers of 1024; `.file` and `.decimal` count
256
+ in powers of 1000. All four use the same unit labels ("KB", "MB"), never
257
+ "KiB" or "MiB", so a different base only shows once the value is large enough
258
+ for the rounding to differ.
253
259
 
254
260
  ## URLs
255
261
 
256
262
  ```swift
257
- let url = URL(string: "https://example.com/path?q=1")!
258
- url.formatted()
259
- // "https://example.com/path?q=1"
263
+ let guide = URL(string: "https://help.example.org/guides/setup?ref=home")!
264
+ guide.formatted() // the full string
265
+ guide.formatted(.url.scheme(.never).host().path()) // "help.example.org/guides/setup"
266
+ guide.formatted(.url.scheme(.always).host().path(.never)) // "https://help.example.org"
267
+ guide.formatted(.url.scheme(.never).host(.never).path()) // "/guides/setup"
268
+ ```
260
269
 
261
- url.formatted(.url.scheme(.never).host().path())
262
- // "example.com/path"
270
+ (Unwrap the literal URL with `guard let` in real code.)
263
271
 
264
- url.formatted(.url.scheme(.always).host(.never).path())
265
- // "https:///path"
266
- ```
272
+ ## SwiftUI integration
267
273
 
268
- Docs: [URL.FormatStyle](https://sosumi.ai/documentation/foundation/url/formatstyle)
274
+ Pass the value and the style to `Text` instead of building a string first:
269
275
 
270
- ## SwiftUI Integration
276
+ ```swift
277
+ Text(order.total, format: .currency(code: order.currencyCode))
278
+ Text(order.placedAt, format: .dateTime.day().month().hour().minute())
279
+ Text(workout.elapsed, format: .units(allowed: [.hours, .minutes], width: .abbreviated))
280
+ ```
271
281
 
272
- `Text` accepts a `format:` parameter, keeping formatting out of the view model.
282
+ `Text` then formats with the view's `\.locale` environment value, so previews
283
+ and in-app locale overrides are respected, and the value stays typed until the
284
+ moment it is drawn. For live values:
273
285
 
274
286
  ```swift
275
- // Inline format style
276
- Text(price, format: .currency(code: "USD"))
277
- Text(date, format: .dateTime.month().day().year())
278
- Text(duration, format: .units(allowed: [.minutes, .seconds]))
279
-
280
- // Timer-style (live updating)
281
- Text(.now, style: .timer)
282
- Text(.now, style: .relative)
283
- Text(timerInterval: start...end)
287
+ Text(.now, style: .timer) // counts up from the date
288
+ Text(sessionStart, style: .relative) // "2 min"
289
+ Text(timerInterval: sessionStart...sessionEnd) // counts down across the range
284
290
  ```
285
291
 
286
- **Prefer `Text(_:format:)` over string interpolation** - it allows SwiftUI to
287
- re-render only the formatted value and supports accessibility scaling.
292
+ `Text(timerInterval:)` needs iOS 16.
288
293
 
289
294
  ## Custom FormatStyle
290
295
 
291
- Conform to `FormatStyle` for domain-specific formatting. Conform to
292
- `ParseableFormatStyle` if you also need parsing.
296
+ Conform to `FormatStyle` and implement `format(_:)`. Add `ParseableFormatStyle`
297
+ if the text must also be read back. `FormatStyle` inherits `Codable` and
298
+ `Hashable`, so keep stored properties simple value types.
293
299
 
294
300
  ```swift
295
- struct AbbreviatedCountStyle: FormatStyle {
296
- func format(_ value: Int) -> String {
297
- switch value {
298
- case ..<1_000:
299
- return "\(value)"
300
- case 1_000..<1_000_000:
301
- return String(format: "%.1fK", Double(value) / 1_000)
302
- default:
303
- return String(format: "%.1fM", Double(value) / 1_000_000)
301
+ struct CompactCountStyle: FormatStyle {
302
+ func format(_ count: Int) -> String {
303
+ switch abs(count) {
304
+ case 1_000_000...: scaled(count, by: 1_000_000) + "M"
305
+ case 1_000...: scaled(count, by: 1_000) + "K"
306
+ default: count.formatted()
304
307
  }
305
308
  }
309
+
310
+ private func scaled(_ count: Int, by divisor: Double) -> String {
311
+ (Double(count) / divisor).formatted(.number.precision(.fractionLength(0...1)))
312
+ }
306
313
  }
307
314
 
308
- extension FormatStyle where Self == AbbreviatedCountStyle {
309
- static var abbreviatedCount: AbbreviatedCountStyle { .init() }
315
+ extension FormatStyle where Self == CompactCountStyle {
316
+ static var compactCount: CompactCountStyle { CompactCountStyle() }
310
317
  }
311
318
 
312
- // Usage
313
- let followers = 12_500
314
- Text(followers, format: .abbreviatedCount) // "12.5K"
319
+ let followers = 48_700.formatted(.compactCount) // "48.7K"
315
320
  ```
316
321
 
317
- ## Common Mistakes
322
+ The static member in the constrained extension is what enables the
323
+ `.compactCount` dot syntax at call sites. (For real apps, `.notation(.compactName)`
324
+ already does this with localized suffixes; a custom style earns its place when
325
+ the rule is your own.)
326
+
327
+ ## Common mistakes
318
328
 
319
329
  | Mistake | Fix |
320
- |---------|-----|
321
- | Using legacy `NumberFormatter` / `DateFormatter` in new code | Use `FormatStyle` (iOS 15+). Foundation caches format style instances automatically. |
322
- | String interpolation for formatted numbers in `Text` | Use `Text(value, format:)` for locale correctness and accessibility |
323
- | Hardcoding locale in format styles | Omit `.locale()` to inherit the user's current locale by default |
324
- | Using `.time(pattern:)` for labeled duration display | Use `.units(allowed:width:)` for "1 hr, 30 min" style output |
325
- | Creating `Formatter` instances in `body` or tight loops | FormatStyle instances are value types cached by Foundation; safe to create inline |
326
- | Formatting `Duration` with `DateComponentsFormatter` | Use `Duration.TimeFormatStyle` or `Duration.UnitsFormatStyle` directly |
327
- | Ignoring `usage:` parameter for measurements | Specify `.road`, `.asProvided`, etc. for locale-aware unit conversion |
328
-
329
- ## Review Checklist
330
-
331
- - [ ] `FormatStyle` used instead of legacy `Formatter` subclasses for iOS 15+ targets
332
- - [ ] `Text(_:format:)` used instead of pre-formatting strings for SwiftUI text
333
- - [ ] No hardcoded locale unless explicitly needed (e.g., server communication)
334
- - [ ] Duration formatting uses `Duration.TimeFormatStyle` or `Duration.UnitsFormatStyle`
335
- - [ ] Currency codes are ISO 4217 strings, not hardcoded symbols
336
- - [ ] Measurement formatting includes `usage:` for user-facing display
337
- - [ ] Custom FormatStyle types conform to `Codable` + `Hashable` for caching
330
+ | --- | --- |
331
+ | `NumberFormatter` or `DateFormatter` in new code | `FormatStyle` (iOS 15+); Foundation caches the underlying formatters |
332
+ | String interpolation of a value inside `Text` | `Text(value, format:)` |
333
+ | Hardcoded `.locale(...)` for display | Leave it out so the user's locale applies |
334
+ | `.time(pattern:)` where labels are wanted | `.units(allowed:width:)` |
335
+ | A `Formatter` created in `body` or inside a loop | An inline style; it is cheap and cached |
336
+ | `DateComponentsFormatter` for a `Duration` | `Duration.TimeFormatStyle` or `Duration.UnitsFormatStyle` |
337
+ | Measurements formatted without `usage:` | Pass `.road`, `.person`, `.asProvided` or another usage that fits |
338
+
339
+ ## Review checklist
340
+
341
+ - [ ] `FormatStyle` rather than `Formatter` subclasses when targeting iOS 15+
342
+ - [ ] `Text(_:format:)` rather than preformatted strings
343
+ - [ ] No hardcoded locale unless the output is machine-facing (for example, sent to a server)
344
+ - [ ] `Duration` values go through the time or units duration style
345
+ - [ ] Currencies are identified by ISO 4217 code ("EUR"), never by symbol ("€")
346
+ - [ ] Measurement display passes `usage:`
347
+ - [ ] Custom styles keep the `Codable` and `Hashable` conformance that `FormatStyle` requires working (value-type properties only)
348
+ - [ ] Output checked in `en_US`, `de_DE`, `ar_SA` and `ja_JP`
338
349
 
339
350
  ## References
340
351
 
341
- - Apple docs: [FormatStyle](https://sosumi.ai/documentation/foundation/formatstyle) | [Date.FormatStyle](https://sosumi.ai/documentation/foundation/date/formatstyle) | [Duration.TimeFormatStyle](https://sosumi.ai/documentation/swift/duration/timeformatstyle)
352
+ - [FormatStyle](https://developer.apple.com/documentation/foundation/formatstyle)
353
+ - [IntegerFormatStyle](https://developer.apple.com/documentation/foundation/integerformatstyle)
354
+ - [FloatingPointFormatStyle](https://developer.apple.com/documentation/foundation/floatingpointformatstyle)
355
+ - [Date.FormatStyle](https://developer.apple.com/documentation/foundation/date/formatstyle)
356
+ - [Date.RelativeFormatStyle](https://developer.apple.com/documentation/foundation/date/relativeformatstyle)
357
+ - [Date.IntervalFormatStyle](https://developer.apple.com/documentation/foundation/date/intervalformatstyle)
358
+ - [Date.AnchoredRelativeFormatStyle](https://developer.apple.com/documentation/foundation/date/anchoredrelativeformatstyle)
359
+ - [Duration.TimeFormatStyle](https://developer.apple.com/documentation/swift/duration/timeformatstyle)
360
+ - [Duration.UnitsFormatStyle](https://developer.apple.com/documentation/swift/duration/unitsformatstyle)
361
+ - [Measurement.FormatStyle](https://developer.apple.com/documentation/foundation/measurement/formatstyle)
362
+ - [PersonNameComponents.FormatStyle](https://developer.apple.com/documentation/foundation/personnamecomponents/formatstyle)
363
+ - [ListFormatStyle](https://developer.apple.com/documentation/foundation/listformatstyle)
364
+ - [ByteCountFormatStyle](https://developer.apple.com/documentation/foundation/bytecountformatstyle)
365
+ - [URL.FormatStyle](https://developer.apple.com/documentation/foundation/url/formatstyle)