@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,334 +1,299 @@
1
1
  #!/usr/bin/env python3
2
- """Build the content-team Excel (CMS import) sheet from a mapping JSON.
2
+ """Write the CMS import sheet for a reuse map as <slug>.localization.xlsx and/or .csv.
3
3
 
4
- One row per localization key, in the columns the content team's CMS import expects:
5
-
6
- Channel | Property Group | Property Module | Key | EN Value | TR Value | AR Value | Anotation EN | Anotation TR
7
-
8
- - Channel - the delivery channel these strings belong to ("Mobile" by default; --channel).
9
- - Property Group - deduced from the key namespace; describe your CMS buckets with --taxonomy, or let a
10
- row override it outright with a "propertyGroup" field.
11
- - Property Module - deduced too (Fields / Validation / Common / <domain>); overridable with "propertyModule".
12
- - Key - our NEW (redesign) key, verbatim (row.newKey). "(owned by ...)" component tags are stripped.
13
- - EN/TR/AR Value - our SUGGESTED values (row.new.en / .tr / .ar - resolve-new-values.py output).
14
- - Anotation EN/TR - the content team's ACTUAL copy, the Figma CMS annotations (row.cms.en / .tr).
15
-
16
- Writes a real `.xlsx` (an OOXML zip built with the Python stdlib only - no pip, no network, same trick
17
- build-artifact.py uses for .docx). `--csv` also emits a UTF-8 CSV alongside it (a terminal-friendly fallback
18
- when Excel is not needed). `--csv-only` skips the xlsx.
19
-
20
- Usage:
21
- python3 build-spreadsheet.py <mapping>.json --out <dir> [--slug <slug>] [--channel Mobile]
22
- [--taxonomy cms-taxonomy.json] [--csv|--csv-only]
4
+ Each mapping row turns into a single sheet row with the nine columns below.
5
+ Text is copied from the row's `new` block and the annotation columns from its
6
+ `cms` block; a column stays empty when the mapping has nothing for it. The
7
+ workbook is assembled from its XML parts with nothing beyond the stdlib.
23
8
  """
24
9
  import argparse
25
10
  import csv
26
- import html
27
- import io
28
11
  import json
29
12
  import os
13
+ import re
30
14
  import sys
31
15
  import zipfile
16
+ from xml.sax.saxutils import escape
32
17
 
33
- COLUMNS = ["Channel", "Property Group", "Property Module", "Key",
34
- "EN Value", "TR Value", "AR Value", "Anotation EN", "Anotation TR"]
35
-
36
- # Approx display widths (chars) per column, for the xlsx.
37
- COL_WIDTHS = [10, 22, 20, 40, 26, 26, 26, 26, 26]
38
-
39
-
40
- def _text(v):
41
- return "" if v in (None, "") else str(v)
42
-
43
-
44
- def slugify(name):
45
- slug = "".join(ch if ch.isalnum() else "-" for ch in _text(name).lower()).strip("-")
46
- while "--" in slug:
47
- slug = slug.replace("--", "-")
48
- return slug or "screen"
49
-
50
-
51
- def clean_key(row):
52
- """The Key column = our new key, without a trailing '(owned by ...)' component tag."""
53
- k = _text(row.get("newKey"))
54
- i = k.find("(owned by")
55
- return (k[:i].strip() if i >= 0 else k).strip()
56
-
57
-
58
- # --- Property Group / Module deduction ------------------------------------------------
59
- # A CMS typically files keys into a group (shared building blocks vs feature areas) and a
60
- # module inside it. The deduction below is a neutral default; every CMS names its buckets
61
- # differently, so point --taxonomy at a JSON file to describe yours:
62
- #
63
- # {
64
- # "errors": {"group": "Common-Errors", "module": ""},
65
- # "lookups": {"group": "Common-Lookup", "module": ""},
66
- # "validation": {"group": "Core", "module": "Validation"},
67
- # "fields": {"group": "Core", "module": "Fields"},
68
- # "fallback": {"group": "Core", "module": "Common"},
69
- # "domainGroup": "Domains",
70
- # "domains": {"auth": ["login", "signup", "otp"], "billing": ["invoice", "card"]}
71
- # }
72
- #
73
- # Any subset may be given; unspecified parts keep the defaults. A mapping row always wins
74
- # over deduction via explicit "propertyGroup" / "propertyModule".
18
+ COLUMNS = [
19
+ "Channel", "Property Group", "Property Module", "Key",
20
+ "EN Value", "TR Value", "AR Value", "Anotation EN", "Anotation TR",
21
+ ]
22
+ WIDTHS = [12, 18, 20, 48, 40, 40, 40, 40, 40]
75
23
 
76
24
  DEFAULT_TAXONOMY = {
77
- "errors": {"group": "Errors", "module": ""},
78
- "lookups": {"group": "Lookups", "module": ""},
79
- "validation": {"group": "Core", "module": "Validation"},
80
- "fields": {"group": "Core", "module": "Fields"},
81
- "fallback": {"group": "Core", "module": "Common"},
25
+ "errors": {"group": "Errors"},
26
+ "lookups": {"group": "Lookups"},
27
+ "validation": {"module": "Validation", "group": "Core"},
28
+ "fields": {"module": "Fields", "group": "Core"},
29
+ "fallback": {"module": "Common", "group": "Core"},
82
30
  "domainGroup": "Domains",
83
31
  "domains": {
84
- "auth": ["auth", "login", "signin", "sign-in", "register", "signup", "otp", "password"],
85
- "account": ["account", "profile", "settings", "preferences"],
86
- "checkout": ["checkout", "cart", "payment", "billing", "order"],
87
- "search": ["search", "filter", "results"],
32
+ "auth": ["login", "sign-in", "signin", "signup", "register", "password", "otp", "auth"],
33
+ "account": ["profile", "account", "preferences", "settings"],
34
+ "checkout": ["cart", "checkout", "billing", "payment", "order"],
35
+ "search": ["results", "filter", "search"],
88
36
  },
89
37
  }
90
38
 
91
- _TAXONOMY = DEFAULT_TAXONOMY
39
+
40
+ def slug(text):
41
+ value = re.sub(r"[\W_]+", "-", str(text or "").strip().lower()).strip("-")
42
+ return value or "screen"
43
+
44
+
45
+ def read_json(source):
46
+ with open(source, encoding="utf-8") as stream:
47
+ return json.load(stream)
92
48
 
93
49
 
94
50
  def load_taxonomy(path):
95
- """Merge a user taxonomy file over the neutral defaults (one level deep)."""
51
+ taxonomy = json.loads(json.dumps(DEFAULT_TAXONOMY))
96
52
  if not path:
97
- return dict(DEFAULT_TAXONOMY)
98
- with open(path, encoding="utf-8") as fh:
99
- user = json.load(fh)
53
+ return taxonomy
54
+ user = read_json(path)
100
55
  if not isinstance(user, dict):
101
- raise SystemExit(f"--taxonomy must be a JSON object, got {type(user).__name__}")
102
- merged = dict(DEFAULT_TAXONOMY)
103
- for k, v in user.items():
104
- if isinstance(v, dict) and isinstance(merged.get(k), dict):
105
- merged[k] = {**merged[k], **v}
56
+ raise SystemExit(f"--taxonomy must hold a JSON object: {path}")
57
+ for key, value in user.items():
58
+ if isinstance(value, dict) and isinstance(taxonomy.get(key), dict):
59
+ taxonomy[key].update(value)
106
60
  else:
107
- merged[k] = v
108
- return merged
109
-
110
-
111
- def _bucket(name, group, module):
112
- b = _TAXONOMY.get(name) or {}
113
- return (group or _text(b.get("group")), module or _text(b.get("module")))
114
-
115
-
116
- def _first_segment(key):
117
- for sep in (".", "-", "_", "/"):
118
- if sep in key:
119
- return key.split(sep, 1)[0]
120
- return key
121
-
122
-
123
- def deduce_group_module(row):
124
- """Return (group, module) for a row, honoring explicit overrides first."""
125
- group = _text(row.get("propertyGroup"))
126
- module = _text(row.get("propertyModule"))
127
- if group and module:
128
- return group, module
129
-
130
- key = clean_key(row)
131
- low = key.lower()
132
-
133
- # Cross-cutting pools first.
134
- if "error" in low or "errormessage" in low:
135
- return _bucket("errors", group, module)
136
- if "lookup" in low:
137
- return _bucket("lookups", group, module)
138
-
139
- # Core building blocks.
140
- if "validation" in low or "invalid" in low or low.endswith(".valid"):
141
- return _bucket("validation", group, module)
142
- if any(w in low for w in ("field", "placeholder", "hint", "label")):
143
- return _bucket("fields", group, module)
144
-
145
- # Feature domains, matched on the first namespace segment then anywhere in the key.
146
- first = _first_segment(low)
147
- for dom, hints in (_TAXONOMY.get("domains") or {}).items():
148
- if first in hints or any(h in low for h in hints):
149
- return (group or _text(_TAXONOMY.get("domainGroup")), module or dom)
150
-
151
- return _bucket("fallback", group, module)
152
-
153
-
154
- def row_to_record(row, channel):
155
- group, module = deduce_group_module(row)
156
- new = row.get("new") or {}
157
- cms = row.get("cms") or {}
158
- return [
159
- channel,
160
- group,
161
- module,
162
- clean_key(row),
163
- _text(new.get("en")),
164
- _text(new.get("tr")),
165
- _text(new.get("ar")),
166
- _text(cms.get("en")),
167
- _text(cms.get("tr")),
168
- ]
61
+ taxonomy[key] = value
62
+ return taxonomy
63
+
64
+
65
+ def clean_key(new_key):
66
+ text = str(new_key or "")
67
+ cut = text.find("(owned by")
68
+ return (text[:cut] if cut >= 0 else text).strip()
69
+
70
+
71
+ def bucket(key, taxonomy):
72
+ lowered = key.lower()
73
+ if "error" in lowered:
74
+ entry = taxonomy["errors"]
75
+ elif "lookup" in lowered:
76
+ entry = taxonomy["lookups"]
77
+ elif "validation" in lowered or "invalid" in lowered or lowered.endswith(".valid"):
78
+ entry = taxonomy["validation"]
79
+ elif any(word in lowered for word in ("field", "placeholder", "hint", "label")):
80
+ entry = taxonomy["fields"]
81
+ else:
82
+ first = re.split(r"[.\-_/]", lowered, maxsplit=1)[0]
83
+ for domain, words in (taxonomy.get("domains") or {}).items():
84
+ if first in words or any(word in lowered for word in words):
85
+ return taxonomy.get("domainGroup", "Domains"), domain
86
+ entry = taxonomy["fallback"]
87
+ return entry.get("group", ""), entry.get("module", "")
88
+
89
+
90
+ def table_rows(mapping, channel, taxonomy):
91
+ out = []
92
+ for row in mapping.get("rows") or []:
93
+ key = clean_key(row.get("newKey"))
94
+ group, module = bucket(key, taxonomy)
95
+ if row.get("propertyGroup"):
96
+ group = row["propertyGroup"]
97
+ if row.get("propertyModule"):
98
+ module = row["propertyModule"]
99
+ new = row.get("new") or {}
100
+ cms = row.get("cms") or {}
101
+ out.append([
102
+ channel, group, module, key,
103
+ new.get("en") or "", new.get("tr") or "", new.get("ar") or "",
104
+ cms.get("en") or "", cms.get("tr") or "",
105
+ ])
106
+ return out
169
107
 
170
108
 
171
- def build_records(mapping, channel):
172
- return [row_to_record(r, channel) for r in mapping.get("rows", [])]
109
+ def column_letter(index):
110
+ letters = ""
111
+ index += 1
112
+ while index:
113
+ index, rem = divmod(index - 1, 26)
114
+ letters = chr(65 + rem) + letters
115
+ return letters
173
116
 
174
117
 
175
- # --- xlsx writer (stdlib only: an .xlsx is a zip of OOXML parts) -----------------------
118
+ XML_DECL = '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>'
119
+ OOXML = "http://schemas.openxmlformats.org/"
120
+ NS_SHEET = OOXML + "spreadsheetml/2006/main"
121
+ NS_PKG_REL = OOXML + "package/2006/relationships"
122
+ NS_TYPES = OOXML + "package/2006/content-types"
123
+ NS_DOC_REL = OOXML + "officeDocument/2006/relationships"
124
+ MIME_OOXML = "application/vnd.openxmlformats-"
125
+ SHEET_NAME = "Localization"
176
126
 
177
- def _xesc(s):
178
- return html.escape(_text(s), quote=True)
179
127
 
128
+ def el(name, attrs=(), *children):
129
+ opening = name + "".join(f' {k}="{v}"' for k, v in attrs)
130
+ if not children:
131
+ return f"<{opening}/>"
132
+ return f"<{opening}>{''.join(children)}</{name}>"
180
133
 
181
- def _col_letter(idx): # 0-based -> A, B, ... Z, AA, ...
182
- idx += 1
183
- out = ""
184
- while idx:
185
- idx, rem = divmod(idx - 1, 26)
186
- out = chr(65 + rem) + out
187
- return out
134
+
135
+ def part(root, attrs, *children):
136
+ return XML_DECL + el(root, attrs, *children)
137
+
138
+
139
+ def cell(ref, value, style):
140
+ text = escape(str(value)).replace("\n", "&#10;")
141
+ attrs = [("r", ref), ("t", "inlineStr")]
142
+ if style:
143
+ attrs.append(("s", style))
144
+ return el("c", attrs, el("is", (), el("t", [("xml:space", "preserve")], text)))
188
145
 
189
146
 
190
- def _sheet_xml(records):
191
- cols = "".join(
192
- f'<col min="{i+1}" max="{i+1}" width="{w}" customWidth="1"/>'
193
- for i, w in enumerate(COL_WIDTHS)
147
+ def sheet_xml(rows):
148
+ span = f"A1:{column_letter(len(COLUMNS) - 1)}{len(rows) + 1}"
149
+ widths = [
150
+ el("col", [("min", n), ("max", n), ("width", width), ("customWidth", 1)])
151
+ for n, width in enumerate(WIDTHS, 1)
152
+ ]
153
+ lines = []
154
+ for number, values in enumerate([COLUMNS] + rows, 1):
155
+ header = 1 if number == 1 else 0
156
+ cells = [cell(f"{column_letter(c)}{number}", v, header) for c, v in enumerate(values)]
157
+ lines.append(el("row", [("r", number)], *cells))
158
+ frozen = el("pane", [("ySplit", 1), ("topLeftCell", "A2"), ("activePane", "bottomLeft"), ("state", "frozen")])
159
+ return part(
160
+ "worksheet", [("xmlns", NS_SHEET)],
161
+ el("dimension", [("ref", span)]),
162
+ el("sheetViews", (), el("sheetView", [("workbookViewId", 0)], frozen)),
163
+ el("cols", (), *widths),
164
+ el("sheetData", (), *lines),
165
+ el("autoFilter", [("ref", span)]),
194
166
  )
195
167
 
196
- def cell(col_idx, row_idx, value, style):
197
- ref = f"{_col_letter(col_idx)}{row_idx}"
198
- return (f'<c r="{ref}" t="inlineStr" s="{style}">'
199
- f'<is><t xml:space="preserve">{_xesc(value)}</t></is></c>')
200
-
201
- rows_xml = []
202
- header = "".join(cell(i, 1, COLUMNS[i], 1) for i in range(len(COLUMNS)))
203
- rows_xml.append(f'<row r="1">{header}</row>')
204
- for ri, rec in enumerate(records, start=2):
205
- cells = "".join(cell(i, ri, rec[i], 0) for i in range(len(COLUMNS)))
206
- rows_xml.append(f'<row r="{ri}">{cells}</row>')
207
-
208
- last = f"{_col_letter(len(COLUMNS)-1)}{max(1, len(records)+1)}"
209
- return (
210
- '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>'
211
- '<worksheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main">'
212
- f'<dimension ref="A1:{last}"/>'
213
- '<sheetViews><sheetView workbookViewId="0">'
214
- '<pane ySplit="1" topLeftCell="A2" activePane="bottomLeft" state="frozen"/>'
215
- '</sheetView></sheetViews>'
216
- '<sheetFormatPr defaultRowHeight="15"/>'
217
- f'<cols>{cols}</cols>'
218
- f'<sheetData>{"".join(rows_xml)}</sheetData>'
219
- f'<autoFilter ref="A1:{_col_letter(len(COLUMNS)-1)}1"/>'
220
- '</worksheet>'
168
+
169
+ def font(bold=False, rgb=None):
170
+ pieces = [el("b")] if bold else []
171
+ pieces.append(el("sz", [("val", 11)]))
172
+ if rgb:
173
+ pieces.append(el("color", [("rgb", rgb)]))
174
+ pieces.append(el("name", [("val", "Calibri")]))
175
+ return el("font", (), *pieces)
176
+
177
+
178
+ def fill(kind, *colors):
179
+ return el("fill", (), el("patternFill", [("patternType", kind)], *colors))
180
+
181
+
182
+ def xf(font_id, fill_id, *extra):
183
+ ids = [("numFmtId", 0), ("fontId", font_id), ("fillId", fill_id), ("borderId", 0)]
184
+ return el("xf", ids + list(extra))
185
+
186
+
187
+ def counted(name, *items):
188
+ return el(name, [("count", len(items))], *items)
189
+
190
+
191
+ def styles_xml():
192
+ edges = [el(side) for side in ("left", "right", "top", "bottom", "diagonal")]
193
+ solid = fill("solid", el("fgColor", [("rgb", "FF4472C4")]), el("bgColor", [("indexed", 64)]))
194
+ return part(
195
+ "styleSheet", [("xmlns", NS_SHEET)],
196
+ counted("fonts", font(), font(bold=True, rgb="FFFFFFFF")),
197
+ counted("fills", fill("none"), fill("gray125"), solid),
198
+ counted("borders", el("border", (), *edges)),
199
+ counted("cellStyleXfs", xf(0, 0)),
200
+ counted("cellXfs", xf(0, 0, ("xfId", 0)), xf(1, 2, ("xfId", 0), ("applyFont", 1), ("applyFill", 1))),
221
201
  )
222
202
 
223
203
 
224
- _STYLES_XML = (
225
- '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>'
226
- '<styleSheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main">'
227
- '<fonts count="2">'
228
- '<font><sz val="11"/><name val="Calibri"/></font>'
229
- '<font><b/><sz val="11"/><color rgb="FFFFFFFF"/><name val="Calibri"/></font>'
230
- '</fonts>'
231
- '<fills count="3">'
232
- '<fill><patternFill patternType="none"/></fill>'
233
- '<fill><patternFill patternType="gray125"/></fill>'
234
- '<fill><patternFill patternType="solid"><fgColor rgb="FF4472C4"/><bgColor indexed="64"/></patternFill></fill>'
235
- '</fills>'
236
- '<borders count="1"><border><left/><right/><top/><bottom/><diagonal/></border></borders>'
237
- '<cellStyleXfs count="1"><xf numFmtId="0" fontId="0" fillId="0" borderId="0"/></cellStyleXfs>'
238
- '<cellXfs count="2">'
239
- '<xf numFmtId="0" fontId="0" fillId="0" borderId="0" xfId="0" applyAlignment="1">'
240
- '<alignment vertical="top" wrapText="1"/></xf>'
241
- '<xf numFmtId="0" fontId="1" fillId="2" borderId="0" xfId="0" applyAlignment="1">'
242
- '<alignment vertical="center" wrapText="1"/></xf>'
243
- '</cellXfs>'
244
- '<cellStyles count="1"><cellStyle name="Normal" xfId="0" builtinId="0"/></cellStyles>'
245
- '</styleSheet>'
246
- )
247
-
248
-
249
- def write_xlsx(records, out_path, sheet_name="Localization"):
250
- safe = "".join(c for c in sheet_name if c not in r'[]:*?/\\')[:31] or "Sheet1"
251
- parts = {
252
- "[Content_Types].xml":
253
- '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>'
254
- '<Types xmlns="http://schemas.openxmlformats.org/package/2006/content-types">'
255
- '<Default Extension="rels" ContentType="application/vnd.openxmlformats-package.relationships+xml"/>'
256
- '<Default Extension="xml" ContentType="application/xml"/>'
257
- '<Override PartName="/xl/workbook.xml" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml"/>'
258
- '<Override PartName="/xl/worksheets/sheet1.xml" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.worksheet+xml"/>'
259
- '<Override PartName="/xl/styles.xml" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.styles+xml"/>'
260
- '</Types>',
261
- "_rels/.rels":
262
- '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>'
263
- '<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">'
264
- '<Relationship Id="rId1" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument" Target="xl/workbook.xml"/>'
265
- '</Relationships>',
266
- "xl/workbook.xml":
267
- '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>'
268
- '<workbook xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" '
269
- 'xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships">'
270
- f'<sheets><sheet name="{_xesc(safe)}" sheetId="1" r:id="rId1"/></sheets></workbook>',
271
- "xl/_rels/workbook.xml.rels":
272
- '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>'
273
- '<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">'
274
- '<Relationship Id="rId1" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/worksheet" Target="worksheets/sheet1.xml"/>'
275
- '<Relationship Id="rId2" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles" Target="styles.xml"/>'
276
- '</Relationships>',
277
- "xl/styles.xml": _STYLES_XML,
278
- "xl/worksheets/sheet1.xml": _sheet_xml(records),
204
+ def content_types_xml():
205
+ kinds = {
206
+ "/xl/workbook.xml": "spreadsheetml.sheet.main",
207
+ "/xl/worksheets/sheet1.xml": "spreadsheetml.worksheet",
208
+ "/xl/styles.xml": "spreadsheetml.styles",
279
209
  }
280
- with zipfile.ZipFile(out_path, "w", zipfile.ZIP_DEFLATED) as z:
281
- for name, data in parts.items():
282
- z.writestr(name, data)
210
+ overrides = [
211
+ el("Override", [("PartName", name), ("ContentType", f"{MIME_OOXML}officedocument.{kind}+xml")])
212
+ for name, kind in kinds.items()
213
+ ]
214
+ return part(
215
+ "Types", [("xmlns", NS_TYPES)],
216
+ el("Default", [("Extension", "rels"), ("ContentType", MIME_OOXML + "package.relationships+xml")]),
217
+ el("Default", [("Extension", "xml"), ("ContentType", "application/xml")]),
218
+ *overrides,
219
+ )
220
+
221
+
222
+ def relationships_xml(*links):
223
+ items = [
224
+ el("Relationship", [("Id", f"rId{n}"), ("Type", f"{NS_DOC_REL}/{kind}"), ("Target", target)])
225
+ for n, (kind, target) in enumerate(links, 1)
226
+ ]
227
+ return part("Relationships", [("xmlns", NS_PKG_REL)], *items)
228
+
229
+
230
+ def workbook_xml():
231
+ last = column_letter(len(COLUMNS) - 1)
232
+ filter_name = el(
233
+ "definedName", [("name", "_xlnm._FilterDatabase"), ("localSheetId", 0), ("hidden", 1)],
234
+ f"{SHEET_NAME}!$A$1:${last}$1",
235
+ )
236
+ return part(
237
+ "workbook", [("xmlns", NS_SHEET), ("xmlns:r", NS_DOC_REL)],
238
+ el("sheets", (), el("sheet", [("name", SHEET_NAME), ("sheetId", 1), ("r:id", "rId1")])),
239
+ el("definedNames", (), filter_name),
240
+ )
241
+
242
+
243
+ def write_xlsx(path, rows):
244
+ members = [
245
+ ("[Content_Types].xml", content_types_xml()),
246
+ ("_rels/.rels", relationships_xml(("officeDocument", "xl/workbook.xml"))),
247
+ ("xl/workbook.xml", workbook_xml()),
248
+ ("xl/_rels/workbook.xml.rels", relationships_xml(("worksheet", "worksheets/sheet1.xml"), ("styles", "styles.xml"))),
249
+ ("xl/styles.xml", styles_xml()),
250
+ ("xl/worksheets/sheet1.xml", sheet_xml(rows)),
251
+ ]
252
+ with zipfile.ZipFile(path, "w", zipfile.ZIP_DEFLATED) as archive:
253
+ for member, xml in members:
254
+ archive.writestr(member, xml)
283
255
 
284
256
 
285
- def write_csv(records, out_path):
286
- with open(out_path, "w", newline="", encoding="utf-8-sig") as f:
287
- w = csv.writer(f)
288
- w.writerow(COLUMNS)
289
- w.writerows(records)
257
+ def write_csv(path, rows):
258
+ with open(path, "w", newline="", encoding="utf-8-sig") as sink:
259
+ out = csv.writer(sink)
260
+ out.writerow(COLUMNS)
261
+ out.writerows(rows)
290
262
 
291
263
 
292
264
  def main():
293
- ap = argparse.ArgumentParser(description=__doc__,
294
- formatter_class=argparse.RawDescriptionHelpFormatter)
295
- ap.add_argument("mapping", help="path to the mapping JSON (- for stdin)")
296
- ap.add_argument("--out", default=".", help="output directory")
297
- ap.add_argument("--slug", help="output basename (default: slug of mapping.screen)")
298
- ap.add_argument("--channel", default="Mobile", help="Channel column value (default: Mobile)")
299
- ap.add_argument("--taxonomy", help="JSON file describing your CMS group/module buckets "
300
- "(merged over the neutral defaults; see the module docstring)")
301
- ap.add_argument("--csv", action="store_true", help="also write a <slug>.localization.csv")
302
- ap.add_argument("--csv-only", action="store_true", help="write only the CSV, skip the xlsx")
303
- args = ap.parse_args()
304
-
305
- global _TAXONOMY
306
- _TAXONOMY = load_taxonomy(args.taxonomy)
307
-
308
- raw = sys.stdin.read() if args.mapping == "-" else open(args.mapping, encoding="utf-8").read()
309
- mapping = json.loads(raw)
310
-
311
- slug = args.slug or slugify(mapping.get("screen"))
312
- os.makedirs(args.out, exist_ok=True)
313
- records = build_records(mapping, args.channel)
314
-
315
- written = []
316
- if not args.csv_only:
317
- xlsx_path = os.path.join(args.out, f"{slug}.localization.xlsx")
318
- write_xlsx(records, xlsx_path)
319
- written.append(xlsx_path)
320
- if args.csv or args.csv_only:
321
- csv_path = os.path.join(args.out, f"{slug}.localization.csv")
322
- write_csv(records, csv_path)
323
- written.append(csv_path)
324
-
325
- print(json.dumps({
326
- "slug": slug,
327
- "rows": len(records),
328
- "columns": COLUMNS,
329
- "channel": args.channel,
330
- "written": [os.path.basename(p) for p in written],
331
- }, ensure_ascii=False, indent=2))
265
+ cli = argparse.ArgumentParser(description=__doc__.splitlines()[0])
266
+ cli.add_argument("mapping", help="reuse-map JSON file; pass - to read it from stdin")
267
+ cli.add_argument("--out", dest="target_dir", default=".", help="folder that receives the generated files")
268
+ cli.add_argument("--slug", help="stem for the file names; derived from the screen name when omitted")
269
+ cli.add_argument("--channel", default="Mobile", help="text placed in every Channel cell")
270
+ cli.add_argument("--taxonomy", help="JSON object laid over the built-in Property Group / Module rules")
271
+ cli.add_argument("--csv", action="store_true", help="emit a CSV next to the workbook")
272
+ cli.add_argument("--csv-only", action="store_true", help="emit only the CSV, no workbook")
273
+ opts = cli.parse_args()
274
+
275
+ mapping = json.load(sys.stdin) if opts.mapping == "-" else read_json(opts.mapping)
276
+ if not isinstance(mapping, dict) or "rows" not in mapping:
277
+ cli.error("mapping must be a JSON object with rows")
278
+
279
+ rows = table_rows(mapping, opts.channel, load_taxonomy(opts.taxonomy))
280
+ stem = opts.slug or slug(mapping.get("screen"))
281
+ os.makedirs(opts.target_dir, exist_ok=True)
282
+
283
+ def target(ext):
284
+ return os.path.join(opts.target_dir, f"{stem}.localization.{ext}")
285
+
286
+ produced = []
287
+ if not opts.csv_only:
288
+ produced.append(target("xlsx"))
289
+ write_xlsx(produced[-1], rows)
290
+ if opts.csv_only or opts.csv:
291
+ produced.append(target("csv"))
292
+ write_csv(produced[-1], rows)
293
+
294
+ summary = {"slug": stem, "rows": len(rows), "columns": COLUMNS, "channel": opts.channel, "written": produced}
295
+ json.dump(summary, sys.stdout, indent=2, ensure_ascii=False)
296
+ sys.stdout.write("\n")
332
297
 
333
298
 
334
299
  if __name__ == "__main__":