@mmerterden/multi-agent-pipeline 20.7.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 (264) hide show
  1. package/CHANGELOG.md +9 -0
  2. package/LICENSE +0 -10
  3. package/docs/facts.json +1 -1
  4. package/manifest.json +266 -267
  5. package/package.json +2 -2
  6. package/pipeline/scripts/_notices.mjs +1 -1
  7. package/pipeline/skills/.skill-manifest.json +68 -68
  8. package/pipeline/skills/shared/README.md +70 -70
  9. package/pipeline/skills/shared/external/alarmkit/SKILL.md +373 -381
  10. package/pipeline/skills/shared/external/alarmkit/evals/evals.json +23 -18
  11. package/pipeline/skills/shared/external/alarmkit/references/alarmkit-patterns.md +328 -378
  12. package/pipeline/skills/shared/external/app-clips/SKILL.md +260 -160
  13. package/pipeline/skills/shared/external/app-clips/evals/evals.json +27 -27
  14. package/pipeline/skills/shared/external/app-clips/references/data-handoff-notifications-location.md +150 -83
  15. package/pipeline/skills/shared/external/app-clips/references/routing-and-experiences.md +135 -83
  16. package/pipeline/skills/shared/external/app-clips/references/size-capabilities-and-promotion.md +143 -85
  17. package/pipeline/skills/shared/external/app-intents/SKILL.md +302 -304
  18. package/pipeline/skills/shared/external/app-intents/evals/evals.json +21 -21
  19. package/pipeline/skills/shared/external/app-intents/references/appintents-advanced.md +594 -894
  20. package/pipeline/skills/shared/external/app-store-optimization/SKILL.md +339 -277
  21. package/pipeline/skills/shared/external/app-store-optimization/evals/evals.json +27 -23
  22. package/pipeline/skills/shared/external/app-store-optimization/references/keyword-research-methodology.md +105 -122
  23. package/pipeline/skills/shared/external/app-store-optimization/references/product-page-variants.md +143 -166
  24. package/pipeline/skills/shared/external/app-store-review/SKILL.md +307 -326
  25. package/pipeline/skills/shared/external/app-store-review/evals/evals.json +21 -21
  26. package/pipeline/skills/shared/external/app-store-review/references/privacy-manifest.md +105 -67
  27. package/pipeline/skills/shared/external/app-store-review/references/review-checklists.md +114 -101
  28. package/pipeline/skills/shared/external/apple-on-device-ai/SKILL.md +333 -360
  29. package/pipeline/skills/shared/external/apple-on-device-ai/evals/evals.json +24 -27
  30. package/pipeline/skills/shared/external/apple-on-device-ai/references/coreml-conversion.md +215 -322
  31. package/pipeline/skills/shared/external/apple-on-device-ai/references/coreml-optimization.md +161 -256
  32. package/pipeline/skills/shared/external/apple-on-device-ai/references/foundation-models.md +277 -387
  33. package/pipeline/skills/shared/external/apple-on-device-ai/references/mlx-swift.md +196 -210
  34. package/pipeline/skills/shared/external/authentication/SKILL.md +265 -381
  35. package/pipeline/skills/shared/external/authentication/evals/evals.json +25 -25
  36. package/pipeline/skills/shared/external/authentication/references/keychain-biometric.md +133 -178
  37. package/pipeline/skills/shared/external/authentication/references/passkeys.md +111 -147
  38. package/pipeline/skills/shared/external/avkit/SKILL.md +267 -364
  39. package/pipeline/skills/shared/external/avkit/evals/evals.json +26 -26
  40. package/pipeline/skills/shared/external/avkit/references/avkit-patterns.md +375 -493
  41. package/pipeline/skills/shared/external/background-processing/SKILL.md +270 -382
  42. package/pipeline/skills/shared/external/background-processing/evals/evals.json +22 -22
  43. package/pipeline/skills/shared/external/background-processing/references/background-task-patterns.md +169 -317
  44. package/pipeline/skills/shared/external/callkit-voip/SKILL.md +290 -371
  45. package/pipeline/skills/shared/external/callkit-voip/evals/evals.json +24 -24
  46. package/pipeline/skills/shared/external/callkit-voip/references/callkit-patterns.md +175 -343
  47. package/pipeline/skills/shared/external/cloudkit-sync/SKILL.md +292 -381
  48. package/pipeline/skills/shared/external/cloudkit-sync/evals/evals.json +33 -30
  49. package/pipeline/skills/shared/external/cloudkit-sync/references/cloudkit-patterns.md +227 -355
  50. package/pipeline/skills/shared/external/contacts-framework/SKILL.md +197 -346
  51. package/pipeline/skills/shared/external/contacts-framework/evals/evals.json +19 -21
  52. package/pipeline/skills/shared/external/contacts-framework/references/contacts-patterns.md +169 -308
  53. package/pipeline/skills/shared/external/core-bluetooth/SKILL.md +226 -376
  54. package/pipeline/skills/shared/external/core-bluetooth/evals/evals.json +25 -22
  55. package/pipeline/skills/shared/external/core-bluetooth/references/ble-patterns.md +257 -337
  56. package/pipeline/skills/shared/external/core-data/SKILL.md +292 -368
  57. package/pipeline/skills/shared/external/core-data/evals/evals.json +30 -27
  58. package/pipeline/skills/shared/external/core-motion/SKILL.md +235 -324
  59. package/pipeline/skills/shared/external/core-motion/evals/evals.json +31 -27
  60. package/pipeline/skills/shared/external/core-motion/references/motion-patterns.md +210 -310
  61. package/pipeline/skills/shared/external/core-nfc/SKILL.md +292 -366
  62. package/pipeline/skills/shared/external/core-nfc/evals/evals.json +22 -24
  63. package/pipeline/skills/shared/external/core-nfc/references/nfc-patterns.md +233 -329
  64. package/pipeline/skills/shared/external/coreml/SKILL.md +323 -367
  65. package/pipeline/skills/shared/external/coreml/evals/evals.json +24 -21
  66. package/pipeline/skills/shared/external/coreml/references/coreml-swift-integration.md +562 -565
  67. package/pipeline/skills/shared/external/cryptokit/SKILL.md +253 -394
  68. package/pipeline/skills/shared/external/cryptokit/evals/evals.json +20 -18
  69. package/pipeline/skills/shared/external/cryptokit/references/cryptokit-patterns.md +299 -488
  70. package/pipeline/skills/shared/external/debugging-instruments/SKILL.md +270 -323
  71. package/pipeline/skills/shared/external/debugging-instruments/evals/evals.json +27 -30
  72. package/pipeline/skills/shared/external/debugging-instruments/references/instruments-guide.md +167 -315
  73. package/pipeline/skills/shared/external/debugging-instruments/references/lldb-patterns.md +140 -193
  74. package/pipeline/skills/shared/external/device-integrity/SKILL.md +230 -353
  75. package/pipeline/skills/shared/external/device-integrity/evals/evals.json +25 -21
  76. package/pipeline/skills/shared/external/device-integrity/references/device-integrity-patterns.md +159 -197
  77. package/pipeline/skills/shared/external/energykit/SKILL.md +225 -392
  78. package/pipeline/skills/shared/external/energykit/evals/evals.json +29 -28
  79. package/pipeline/skills/shared/external/energykit/references/energykit-patterns.md +174 -470
  80. package/pipeline/skills/shared/external/eventkit-calendar/SKILL.md +261 -383
  81. package/pipeline/skills/shared/external/eventkit-calendar/evals/evals.json +25 -22
  82. package/pipeline/skills/shared/external/eventkit-calendar/references/eventkit-patterns.md +165 -268
  83. package/pipeline/skills/shared/external/healthkit/SKILL.md +252 -303
  84. package/pipeline/skills/shared/external/healthkit/evals/evals.json +24 -23
  85. package/pipeline/skills/shared/external/healthkit/references/healthkit-patterns.md +369 -523
  86. package/pipeline/skills/shared/external/homekit-matter/SKILL.md +233 -348
  87. package/pipeline/skills/shared/external/homekit-matter/evals/evals.json +27 -22
  88. package/pipeline/skills/shared/external/homekit-matter/references/matter-commissioning.md +199 -305
  89. package/pipeline/skills/shared/external/ios-accessibility/SKILL.md +368 -340
  90. package/pipeline/skills/shared/external/ios-accessibility/evals/evals.json +28 -27
  91. package/pipeline/skills/shared/external/ios-accessibility/references/a11y-patterns.md +314 -260
  92. package/pipeline/skills/shared/external/ios-accessibility/references/media-accessibility.md +97 -67
  93. package/pipeline/skills/shared/external/ios-accessibility/references/nutrition-labels.md +165 -101
  94. package/pipeline/skills/shared/external/ios-localization/SKILL.md +258 -371
  95. package/pipeline/skills/shared/external/ios-localization/evals/evals.json +23 -23
  96. package/pipeline/skills/shared/external/ios-localization/references/formatstyle-locale.md +283 -491
  97. package/pipeline/skills/shared/external/ios-localization/references/string-catalogs.md +313 -440
  98. package/pipeline/skills/shared/external/ios-networking/SKILL.md +265 -341
  99. package/pipeline/skills/shared/external/ios-networking/evals/evals.json +24 -24
  100. package/pipeline/skills/shared/external/ios-networking/references/background-websocket.md +425 -652
  101. package/pipeline/skills/shared/external/ios-networking/references/file-storage-patterns.md +143 -285
  102. package/pipeline/skills/shared/external/ios-networking/references/lightweight-clients.md +93 -53
  103. package/pipeline/skills/shared/external/ios-networking/references/network-framework.md +231 -456
  104. package/pipeline/skills/shared/external/ios-networking/references/urlsession-patterns.md +517 -784
  105. package/pipeline/skills/shared/external/ios-simulator/SKILL.md +265 -393
  106. package/pipeline/skills/shared/external/ios-simulator/evals/evals.json +21 -21
  107. package/pipeline/skills/shared/external/ios-simulator/references/simctl-commands.md +177 -270
  108. package/pipeline/skills/shared/external/live-activities/SKILL.md +318 -360
  109. package/pipeline/skills/shared/external/live-activities/evals/evals.json +21 -21
  110. package/pipeline/skills/shared/external/live-activities/references/activitykit-patterns.md +478 -710
  111. package/pipeline/skills/shared/external/mapkit-location/SKILL.md +295 -267
  112. package/pipeline/skills/shared/external/mapkit-location/evals/evals.json +28 -24
  113. package/pipeline/skills/shared/external/mapkit-location/references/mapkit-corelocation-patterns.md +378 -532
  114. package/pipeline/skills/shared/external/mapkit-location/references/mapkit-patterns.md +397 -499
  115. package/pipeline/skills/shared/external/metrickit-diagnostics/SKILL.md +165 -348
  116. package/pipeline/skills/shared/external/metrickit-diagnostics/evals/evals.json +26 -23
  117. package/pipeline/skills/shared/external/metrickit-diagnostics/references/metrickit-patterns.md +123 -130
  118. package/pipeline/skills/shared/external/musickit-audio/SKILL.md +189 -315
  119. package/pipeline/skills/shared/external/musickit-audio/evals/evals.json +22 -21
  120. package/pipeline/skills/shared/external/musickit-audio/references/musickit-patterns.md +181 -270
  121. package/pipeline/skills/shared/external/natural-language/SKILL.md +188 -340
  122. package/pipeline/skills/shared/external/natural-language/evals/evals.json +21 -21
  123. package/pipeline/skills/shared/external/natural-language/references/translation-patterns.md +171 -225
  124. package/pipeline/skills/shared/external/passkit-wallet/SKILL.md +258 -392
  125. package/pipeline/skills/shared/external/passkit-wallet/evals/evals.json +30 -29
  126. package/pipeline/skills/shared/external/passkit-wallet/references/wallet-passes.md +164 -231
  127. package/pipeline/skills/shared/external/pdfkit/SKILL.md +312 -344
  128. package/pipeline/skills/shared/external/pdfkit/evals/evals.json +19 -19
  129. package/pipeline/skills/shared/external/pdfkit/references/pdfkit-patterns.md +413 -624
  130. package/pipeline/skills/shared/external/pencilkit-drawing/SKILL.md +242 -358
  131. package/pipeline/skills/shared/external/pencilkit-drawing/evals/evals.json +25 -21
  132. package/pipeline/skills/shared/external/pencilkit-drawing/references/pencilkit-patterns.md +161 -226
  133. package/pipeline/skills/shared/external/permissionkit/SKILL.md +282 -400
  134. package/pipeline/skills/shared/external/permissionkit/evals/evals.json +27 -30
  135. package/pipeline/skills/shared/external/permissionkit/references/permissionkit-patterns.md +237 -350
  136. package/pipeline/skills/shared/external/photos-camera-media/SKILL.md +276 -325
  137. package/pipeline/skills/shared/external/photos-camera-media/references/av-playback.md +299 -545
  138. package/pipeline/skills/shared/external/photos-camera-media/references/camera-capture.md +344 -588
  139. package/pipeline/skills/shared/external/photos-camera-media/references/image-loading-caching.md +316 -660
  140. package/pipeline/skills/shared/external/photos-camera-media/references/photokit-patterns.md +270 -416
  141. package/pipeline/skills/shared/external/push-notifications/SKILL.md +312 -340
  142. package/pipeline/skills/shared/external/push-notifications/evals/evals.json +27 -26
  143. package/pipeline/skills/shared/external/push-notifications/references/notification-patterns.md +328 -485
  144. package/pipeline/skills/shared/external/push-notifications/references/rich-notifications.md +327 -560
  145. package/pipeline/skills/shared/external/realitykit-ar/SKILL.md +218 -410
  146. package/pipeline/skills/shared/external/realitykit-ar/evals/evals.json +24 -27
  147. package/pipeline/skills/shared/external/realitykit-ar/references/realitykit-patterns.md +221 -348
  148. package/pipeline/skills/shared/external/shareplay-activities/SKILL.md +222 -393
  149. package/pipeline/skills/shared/external/shareplay-activities/evals/evals.json +23 -24
  150. package/pipeline/skills/shared/external/shareplay-activities/references/shareplay-patterns.md +280 -420
  151. package/pipeline/skills/shared/external/speech-recognition/SKILL.md +217 -421
  152. package/pipeline/skills/shared/external/speech-recognition/evals/evals.json +23 -26
  153. package/pipeline/skills/shared/external/speech-recognition/references/speechanalyzer-patterns.md +133 -125
  154. package/pipeline/skills/shared/external/storekit/SKILL.md +228 -204
  155. package/pipeline/skills/shared/external/storekit/evals/evals.json +27 -24
  156. package/pipeline/skills/shared/external/storekit/references/app-review-guidelines.md +98 -109
  157. package/pipeline/skills/shared/external/storekit/references/core-patterns.md +298 -242
  158. package/pipeline/skills/shared/external/storekit/references/storekit-advanced.md +356 -649
  159. package/pipeline/skills/shared/external/swift-api-design-guidelines/SKILL.md +274 -399
  160. package/pipeline/skills/shared/external/swift-api-design-guidelines/evals/evals.json +22 -24
  161. package/pipeline/skills/shared/external/swift-api-design-guidelines/references/argument-labels-and-parameters.md +107 -108
  162. package/pipeline/skills/shared/external/swift-api-design-guidelines/references/conventions-and-special-rules.md +93 -165
  163. package/pipeline/skills/shared/external/swift-api-design-guidelines/references/naming-and-clarity.md +99 -137
  164. package/pipeline/skills/shared/external/swift-api-design-guidelines/references/side-effects-and-mutating-pairs.md +77 -120
  165. package/pipeline/skills/shared/external/swift-architecture/SKILL.md +334 -350
  166. package/pipeline/skills/shared/external/swift-architecture/evals/evals.json +22 -22
  167. package/pipeline/skills/shared/external/swift-charts/SKILL.md +208 -394
  168. package/pipeline/skills/shared/external/swift-charts/evals/evals.json +27 -30
  169. package/pipeline/skills/shared/external/swift-charts/references/charts-patterns.md +351 -762
  170. package/pipeline/skills/shared/external/swift-codable/SKILL.md +339 -343
  171. package/pipeline/skills/shared/external/swift-codable/evals/evals.json +20 -20
  172. package/pipeline/skills/shared/external/swift-concurrency/SKILL.md +303 -351
  173. package/pipeline/skills/shared/external/swift-concurrency/evals/evals.json +27 -24
  174. package/pipeline/skills/shared/external/swift-concurrency/references/approachable-concurrency.md +65 -80
  175. package/pipeline/skills/shared/external/swift-concurrency/references/async-algorithms.md +48 -84
  176. package/pipeline/skills/shared/external/swift-concurrency/references/bridging-interop.md +134 -79
  177. package/pipeline/skills/shared/external/swift-concurrency/references/concurrency-patterns.md +145 -167
  178. package/pipeline/skills/shared/external/swift-concurrency/references/diagnostics.md +62 -50
  179. package/pipeline/skills/shared/external/swift-concurrency/references/swiftui-concurrency.md +92 -121
  180. package/pipeline/skills/shared/external/swift-concurrency/references/synchronization-primitives.md +177 -241
  181. package/pipeline/skills/shared/external/swift-formatstyle/SKILL.md +258 -234
  182. package/pipeline/skills/shared/external/swift-language/SKILL.md +342 -382
  183. package/pipeline/skills/shared/external/swift-language/evals/evals.json +24 -27
  184. package/pipeline/skills/shared/external/swift-language/references/swift-attributes-interop.md +79 -56
  185. package/pipeline/skills/shared/external/swift-language/references/swift-patterns-extended.md +297 -340
  186. package/pipeline/skills/shared/external/swift-security/SKILL.md +180 -161
  187. package/pipeline/skills/shared/external/swift-security/evals/evals.json +25 -25
  188. package/pipeline/skills/shared/external/swift-security/references/biometric-authentication.md +314 -469
  189. package/pipeline/skills/shared/external/swift-security/references/certificate-trust.md +408 -476
  190. package/pipeline/skills/shared/external/swift-security/references/common-anti-patterns.md +260 -530
  191. package/pipeline/skills/shared/external/swift-security/references/compliance-owasp-mapping.md +270 -477
  192. package/pipeline/skills/shared/external/swift-security/references/credential-storage-patterns.md +573 -571
  193. package/pipeline/skills/shared/external/swift-security/references/cryptokit-public-key.md +370 -441
  194. package/pipeline/skills/shared/external/swift-security/references/cryptokit-symmetric.md +332 -433
  195. package/pipeline/skills/shared/external/swift-security/references/keychain-access-control.md +346 -468
  196. package/pipeline/skills/shared/external/swift-security/references/keychain-fundamentals.md +352 -472
  197. package/pipeline/skills/shared/external/swift-security/references/keychain-item-classes.md +431 -432
  198. package/pipeline/skills/shared/external/swift-security/references/keychain-sharing.md +328 -425
  199. package/pipeline/skills/shared/external/swift-security/references/migration-legacy-stores.md +341 -579
  200. package/pipeline/skills/shared/external/swift-security/references/secure-enclave.md +396 -457
  201. package/pipeline/skills/shared/external/swift-security/references/testing-security-code.md +354 -614
  202. package/pipeline/skills/shared/external/swift-testing/SKILL.md +188 -175
  203. package/pipeline/skills/shared/external/swift-testing/evals/evals.json +26 -24
  204. package/pipeline/skills/shared/external/swift-testing/references/testing-advanced.md +80 -84
  205. package/pipeline/skills/shared/external/swift-testing/references/testing-patterns.md +317 -433
  206. package/pipeline/skills/shared/external/swiftdata/SKILL.md +392 -256
  207. package/pipeline/skills/shared/external/swiftdata/evals/evals.json +24 -24
  208. package/pipeline/skills/shared/external/swiftdata/references/core-data-coexistence.md +206 -402
  209. package/pipeline/skills/shared/external/swiftdata/references/indexing.md +59 -52
  210. package/pipeline/skills/shared/external/swiftdata/references/predicate-pitfalls.md +57 -33
  211. package/pipeline/skills/shared/external/swiftdata/references/swiftdata-advanced.md +354 -747
  212. package/pipeline/skills/shared/external/swiftdata/references/swiftdata-queries.md +300 -508
  213. package/pipeline/skills/shared/external/swiftlint/SKILL.md +175 -226
  214. package/pipeline/skills/shared/external/swiftlint/references/adoption-and-configuration.md +141 -208
  215. package/pipeline/skills/shared/external/swiftlint/references/custom-rules-and-analyze.md +100 -109
  216. package/pipeline/skills/shared/external/swiftlint/references/plugins-run-scripts-and-integrations.md +159 -179
  217. package/pipeline/skills/shared/external/swiftlint/references/rule-reference.md +383 -18
  218. package/pipeline/skills/shared/external/swiftlint/references/rules-suppressions-and-baselines.md +143 -229
  219. package/pipeline/skills/shared/external/swiftui-animation/SKILL.md +283 -366
  220. package/pipeline/skills/shared/external/swiftui-animation/references/animation-advanced.md +396 -608
  221. package/pipeline/skills/shared/external/swiftui-animation/references/core-animation-bridge.md +336 -385
  222. package/pipeline/skills/shared/external/swiftui-gestures/SKILL.md +239 -349
  223. package/pipeline/skills/shared/external/swiftui-gestures/references/gesture-patterns.md +228 -310
  224. package/pipeline/skills/shared/external/swiftui-layout-components/SKILL.md +260 -249
  225. package/pipeline/skills/shared/external/swiftui-layout-components/references/form.md +92 -74
  226. package/pipeline/skills/shared/external/swiftui-layout-components/references/grids.md +112 -177
  227. package/pipeline/skills/shared/external/swiftui-layout-components/references/list.md +61 -64
  228. package/pipeline/skills/shared/external/swiftui-layout-components/references/scrollview.md +94 -134
  229. package/pipeline/skills/shared/external/swiftui-liquid-glass/SKILL.md +193 -225
  230. package/pipeline/skills/shared/external/swiftui-liquid-glass/references/liquid-glass.md +173 -327
  231. package/pipeline/skills/shared/external/swiftui-navigation/SKILL.md +193 -168
  232. package/pipeline/skills/shared/external/swiftui-navigation/references/deeplinks.md +127 -150
  233. package/pipeline/skills/shared/external/swiftui-navigation/references/navigationstack.md +132 -133
  234. package/pipeline/skills/shared/external/swiftui-navigation/references/sheets.md +152 -117
  235. package/pipeline/skills/shared/external/swiftui-navigation/references/tabview.md +106 -140
  236. package/pipeline/skills/shared/external/swiftui-patterns/SKILL.md +316 -252
  237. package/pipeline/skills/shared/external/swiftui-patterns/references/architecture-patterns.md +341 -332
  238. package/pipeline/skills/shared/external/swiftui-patterns/references/deprecated-migration.md +547 -854
  239. package/pipeline/skills/shared/external/swiftui-patterns/references/design-polish.md +485 -537
  240. package/pipeline/skills/shared/external/swiftui-patterns/references/platform-and-sharing.md +417 -499
  241. package/pipeline/skills/shared/external/swiftui-performance/SKILL.md +213 -376
  242. package/pipeline/skills/shared/external/swiftui-performance/references/demystify-swiftui-performance-wwdc23.md +86 -175
  243. package/pipeline/skills/shared/external/swiftui-performance/references/optimizing-swiftui-performance-instruments.md +89 -195
  244. package/pipeline/skills/shared/external/swiftui-performance/references/understanding-hangs-in-your-app.md +95 -182
  245. package/pipeline/skills/shared/external/swiftui-performance/references/understanding-improving-swiftui-performance.md +71 -149
  246. package/pipeline/skills/shared/external/swiftui-performance/references/wwdc-session-sources.md +21 -27
  247. package/pipeline/skills/shared/external/swiftui-uikit-interop/SKILL.md +303 -295
  248. package/pipeline/skills/shared/external/swiftui-uikit-interop/references/hosting-migration.md +204 -387
  249. package/pipeline/skills/shared/external/swiftui-uikit-interop/references/representable-recipes.md +469 -683
  250. package/pipeline/skills/shared/external/swiftui-webkit/SKILL.md +140 -186
  251. package/pipeline/skills/shared/external/swiftui-webkit/references/loading-and-observation.md +75 -86
  252. package/pipeline/skills/shared/external/swiftui-webkit/references/local-content-and-custom-schemes.md +63 -60
  253. package/pipeline/skills/shared/external/swiftui-webkit/references/migration-and-fallbacks.md +69 -137
  254. package/pipeline/skills/shared/external/swiftui-webkit/references/navigation-and-javascript.md +95 -67
  255. package/pipeline/skills/shared/external/tipkit/SKILL.md +220 -335
  256. package/pipeline/skills/shared/external/tipkit/references/tipkit-patterns.md +356 -494
  257. package/pipeline/skills/shared/external/vision-framework/SKILL.md +260 -375
  258. package/pipeline/skills/shared/external/vision-framework/references/vision-requests.md +393 -515
  259. package/pipeline/skills/shared/external/vision-framework/references/visionkit-scanner.md +363 -539
  260. package/pipeline/skills/shared/external/weatherkit/SKILL.md +152 -310
  261. package/pipeline/skills/shared/external/weatherkit/references/weatherkit-patterns.md +288 -407
  262. package/pipeline/skills/shared/external/widgetkit/SKILL.md +216 -288
  263. package/pipeline/skills/shared/external/widgetkit/references/widgetkit-advanced.md +414 -719
  264. 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)