@swiftbrowser/swift 0.1.0 → 0.3.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 (393) hide show
  1. package/Package.swift +200 -9
  2. package/README.md +7 -9
  3. package/Sources/AVFoundation/AVFoundation.swift +131 -0
  4. package/Sources/AVFoundation/Asset.swift +487 -0
  5. package/Sources/AVFoundation/AudioSession.swift +144 -0
  6. package/Sources/AVFoundation/CMTime.swift +303 -0
  7. package/Sources/AVFoundation/Capture.swift +688 -0
  8. package/Sources/AVFoundation/Player.swift +749 -0
  9. package/Sources/AVFoundation/PlayerView.swift +117 -0
  10. package/Sources/AVKit/AVKit.swift +132 -0
  11. package/Sources/Accelerate/Accelerate.swift +122 -0
  12. package/Sources/AppIntents/AppIntents.swift +144 -0
  13. package/Sources/AppIntents/Parameters.swift +220 -0
  14. package/Sources/AppIntents/Shortcuts.swift +159 -0
  15. package/Sources/AudioToolbox/AudioToolbox.swift +55 -0
  16. package/Sources/AuthenticationServices/AuthenticationServices.swift +257 -0
  17. package/Sources/AuthenticationServices/Authorization.swift +251 -0
  18. package/Sources/Charts/Charts.swift +0 -4
  19. package/Sources/Combine/AnyCancellable.swift +65 -0
  20. package/Sources/Combine/AnyPublisher.swift +148 -0
  21. package/Sources/Combine/AnySubscriber.swift +230 -0
  22. package/Sources/Combine/Cancellable.swift +35 -0
  23. package/Sources/Combine/Codable.swift +29 -0
  24. package/Sources/Combine/CombineIdentifier.swift +45 -0
  25. package/Sources/Combine/Concurrency/ConcurrencyHelpers.swift +24 -0
  26. package/Sources/Combine/Concurrency/Future+Concurrency.swift +136 -0
  27. package/Sources/Combine/Concurrency/GENERATED-Publisher+Concurrency.swift +397 -0
  28. package/Sources/Combine/CurrentValueSubject.swift +252 -0
  29. package/Sources/Combine/CustomCombineIdentifierConvertible.swift +28 -0
  30. package/Sources/Combine/Future.swift +228 -0
  31. package/Sources/Combine/GENERATED-RootProtocols.swift +426 -0
  32. package/Sources/Combine/Helpers/ConduitBase.swift +40 -0
  33. package/Sources/Combine/Helpers/ConduitList.swift +59 -0
  34. package/Sources/Combine/Helpers/DebugHook.swift +177 -0
  35. package/Sources/Combine/Helpers/FilterProducer.swift +174 -0
  36. package/Sources/Combine/Helpers/Locking.swift +30 -0
  37. package/Sources/Combine/Helpers/PartialCompletion.swift +26 -0
  38. package/Sources/Combine/Helpers/ReduceProducer.swift +249 -0
  39. package/Sources/Combine/Helpers/SubjectSubscriber.swift +96 -0
  40. package/Sources/Combine/Helpers/SubscriberTap.swift +69 -0
  41. package/Sources/Combine/Helpers/SubscriptionStatus.swift +33 -0
  42. package/Sources/Combine/Helpers/SubscriptionTap.swift +33 -0
  43. package/Sources/Combine/Helpers/Utils.swift +30 -0
  44. package/Sources/Combine/Helpers/Violations.swift +33 -0
  45. package/Sources/Combine/ImmediateScheduler.swift +178 -0
  46. package/Sources/Combine/LICENSE +21 -0
  47. package/Sources/Combine/NotificationPublisher.swift +48 -0
  48. package/Sources/Combine/ObjectWillChange.swift +46 -0
  49. package/Sources/Combine/PassthroughSubject.swift +222 -0
  50. package/Sources/Combine/Publisher+Subscribe.swift +53 -0
  51. package/Sources/Combine/Publishers/Deferred.swift +48 -0
  52. package/Sources/Combine/Publishers/Empty.swift +54 -0
  53. package/Sources/Combine/Publishers/Fail.swift +42 -0
  54. package/Sources/Combine/Publishers/GENERATED-Publishers.Catch.swift +673 -0
  55. package/Sources/Combine/Publishers/GENERATED-Publishers.Encode.swift +388 -0
  56. package/Sources/Combine/Publishers/GENERATED-Publishers.MapKeyPath.swift +384 -0
  57. package/Sources/Combine/Publishers/Just.swift +313 -0
  58. package/Sources/Combine/Publishers/Optional.Publisher.swift +315 -0
  59. package/Sources/Combine/Publishers/Publishers.AllSatisfy.swift +217 -0
  60. package/Sources/Combine/Publishers/Publishers.AssertNoFailure.swift +158 -0
  61. package/Sources/Combine/Publishers/Publishers.Autoconnect.swift +193 -0
  62. package/Sources/Combine/Publishers/Publishers.Breakpoint.swift +231 -0
  63. package/Sources/Combine/Publishers/Publishers.Buffer.swift +356 -0
  64. package/Sources/Combine/Publishers/Publishers.Collect.swift +102 -0
  65. package/Sources/Combine/Publishers/Publishers.CollectByCount.swift +195 -0
  66. package/Sources/Combine/Publishers/Publishers.CompactMap.swift +241 -0
  67. package/Sources/Combine/Publishers/Publishers.Comparison.swift +371 -0
  68. package/Sources/Combine/Publishers/Publishers.Concatenate.swift +474 -0
  69. package/Sources/Combine/Publishers/Publishers.Contains.swift +293 -0
  70. package/Sources/Combine/Publishers/Publishers.Count.swift +87 -0
  71. package/Sources/Combine/Publishers/Publishers.Debounce.swift +332 -0
  72. package/Sources/Combine/Publishers/Publishers.Delay.swift +269 -0
  73. package/Sources/Combine/Publishers/Publishers.Drop.swift +155 -0
  74. package/Sources/Combine/Publishers/Publishers.DropUntilOutput.swift +283 -0
  75. package/Sources/Combine/Publishers/Publishers.DropWhile.swift +378 -0
  76. package/Sources/Combine/Publishers/Publishers.Filter.swift +248 -0
  77. package/Sources/Combine/Publishers/Publishers.First.swift +261 -0
  78. package/Sources/Combine/Publishers/Publishers.FlatMap.swift +533 -0
  79. package/Sources/Combine/Publishers/Publishers.HandleEvents.swift +260 -0
  80. package/Sources/Combine/Publishers/Publishers.IgnoreOutput.swift +109 -0
  81. package/Sources/Combine/Publishers/Publishers.Last.swift +252 -0
  82. package/Sources/Combine/Publishers/Publishers.MakeConnectable.swift +82 -0
  83. package/Sources/Combine/Publishers/Publishers.Map.swift +351 -0
  84. package/Sources/Combine/Publishers/Publishers.MapError.swift +140 -0
  85. package/Sources/Combine/Publishers/Publishers.MeasureInterval.swift +187 -0
  86. package/Sources/Combine/Publishers/Publishers.Multicast.swift +284 -0
  87. package/Sources/Combine/Publishers/Publishers.Output.swift +241 -0
  88. package/Sources/Combine/Publishers/Publishers.PrefixUntilOutput.swift +197 -0
  89. package/Sources/Combine/Publishers/Publishers.PrefixWhile.swift +176 -0
  90. package/Sources/Combine/Publishers/Publishers.Print.swift +206 -0
  91. package/Sources/Combine/Publishers/Publishers.ReceiveOn.swift +227 -0
  92. package/Sources/Combine/Publishers/Publishers.Reduce.swift +204 -0
  93. package/Sources/Combine/Publishers/Publishers.RemoveDuplicates.swift +264 -0
  94. package/Sources/Combine/Publishers/Publishers.ReplaceEmpty.swift +201 -0
  95. package/Sources/Combine/Publishers/Publishers.ReplaceError.swift +211 -0
  96. package/Sources/Combine/Publishers/Publishers.Retry.swift +274 -0
  97. package/Sources/Combine/Publishers/Publishers.Scan.swift +331 -0
  98. package/Sources/Combine/Publishers/Publishers.Sequence.swift +437 -0
  99. package/Sources/Combine/Publishers/Publishers.SetFailureType.swift +120 -0
  100. package/Sources/Combine/Publishers/Publishers.Share.swift +104 -0
  101. package/Sources/Combine/Publishers/Publishers.SubscribeOn.swift +197 -0
  102. package/Sources/Combine/Publishers/Publishers.SwitchToLatest.swift +444 -0
  103. package/Sources/Combine/Publishers/Publishers.Throttle.swift +359 -0
  104. package/Sources/Combine/Publishers/Publishers.Timeout.swift +301 -0
  105. package/Sources/Combine/Publishers/Publishers.Zip.swift +720 -0
  106. package/Sources/Combine/Publishers/Publishers.swift +13 -0
  107. package/Sources/Combine/Publishers/Record.swift +237 -0
  108. package/Sources/Combine/Publishers/Result.Publisher.swift +337 -0
  109. package/Sources/Combine/Result.swift +46 -0
  110. package/Sources/Combine/Scheduler.swift +89 -0
  111. package/Sources/Combine/Schedulers.swift +211 -0
  112. package/Sources/Combine/Subject+Void.swift +17 -0
  113. package/Sources/Combine/Subscriber+Void.swift +20 -0
  114. package/Sources/Combine/Subscribers/Subscribers.Assign.swift +175 -0
  115. package/Sources/Combine/Subscribers/Subscribers.Completion.swift +90 -0
  116. package/Sources/Combine/Subscribers/Subscribers.Demand.swift +476 -0
  117. package/Sources/Combine/Subscribers/Subscribers.Sink.swift +206 -0
  118. package/Sources/Combine/Subscribers/Subscribers.swift +9 -0
  119. package/Sources/Combine/Subscription.swift +22 -0
  120. package/Sources/Combine/Subscriptions.swift +42 -0
  121. package/Sources/Combine/SwiftUIObservation.swift +10 -0
  122. package/Sources/Combine/_Introspection.swift +107 -0
  123. package/Sources/CommonCrypto/CommonCrypto.swift +80 -0
  124. package/Sources/Compression/Compression.swift +365 -0
  125. package/Sources/Compression/Deflate.swift +407 -0
  126. package/Sources/Compression/Zlib.swift +179 -0
  127. package/Sources/CoreFoundationTypes/CoreFoundationTypes.swift +101 -0
  128. package/Sources/CoreGraphics/CoreGraphics.swift +411 -0
  129. package/Sources/CoreGraphics/ProjectionTransforms.swift +28 -0
  130. package/Sources/CoreHaptics/CoreHaptics.swift +399 -0
  131. package/Sources/CoreImage/CIColor.swift +41 -0
  132. package/Sources/CoreImage/CIContext.swift +31 -0
  133. package/Sources/CoreImage/CIDetector.swift +57 -0
  134. package/Sources/CoreImage/CIFilter.swift +243 -0
  135. package/Sources/CoreImage/CIFilterBuiltins.swift +136 -0
  136. package/Sources/CoreImage/CIImage.swift +162 -0
  137. package/Sources/CoreImage/QRCode.swift +393 -0
  138. package/Sources/CoreLocation/Coordinate.swift +30 -0
  139. package/Sources/CoreLocation/Location.swift +65 -0
  140. package/Sources/CoreML/Evaluation.swift +414 -0
  141. package/Sources/CoreML/FeatureValue.swift +266 -0
  142. package/Sources/CoreML/Model.swift +269 -0
  143. package/Sources/CoreML/MultiArray.swift +92 -0
  144. package/Sources/CoreML/Specification.swift +233 -0
  145. package/Sources/CoreText/CoreText.swift +64 -0
  146. package/Sources/CoreTransferable/CoreTransferable.swift +606 -0
  147. package/Sources/CryptoKit/ChaChaPoly.swift +258 -0
  148. package/Sources/CryptoKit/CryptoKit.swift +375 -0
  149. package/Sources/CryptoKit/Curve25519.swift +317 -0
  150. package/Sources/CryptoKit/P256.swift +321 -0
  151. package/Sources/FoundationBridge/AppStorage.swift +165 -0
  152. package/Sources/FoundationBridge/AssetResources.swift +90 -0
  153. package/Sources/FoundationBridge/AsyncBytes.swift +128 -0
  154. package/Sources/FoundationBridge/AsyncImage.swift +116 -0
  155. package/Sources/FoundationBridge/AttributedStrings.swift +16 -0
  156. package/Sources/{_FoundationCommon → FoundationBridge}/Bundle.swift +41 -4
  157. package/Sources/FoundationBridge/CombineExports.swift +8 -0
  158. package/Sources/FoundationBridge/CoreFoundation.swift +77 -0
  159. package/Sources/FoundationBridge/Dispatch.swift +458 -0
  160. package/Sources/FoundationBridge/EnvironmentFoundation.swift +41 -0
  161. package/Sources/FoundationBridge/FileImporter.swift +128 -0
  162. package/Sources/FoundationBridge/FileSystem.swift +68 -0
  163. package/Sources/FoundationBridge/FoundationBridge.swift +24 -72
  164. package/Sources/FoundationBridge/HostResolution.swift +31 -0
  165. package/Sources/FoundationBridge/ItemProvider.swift +655 -0
  166. package/Sources/FoundationBridge/KeyValueObserving.swift +138 -0
  167. package/Sources/FoundationBridge/Links.swift +127 -0
  168. package/Sources/FoundationBridge/ListFormatter.swift +32 -0
  169. package/Sources/FoundationBridge/Localization.swift +149 -0
  170. package/Sources/FoundationBridge/Locks.swift +50 -0
  171. package/Sources/FoundationBridge/Markdown.swift +527 -0
  172. package/Sources/FoundationBridge/MeasurementFormat.swift +95 -0
  173. package/Sources/FoundationBridge/NotificationCenter.swift +154 -0
  174. package/Sources/FoundationBridge/OpenURLHandlers.swift +60 -0
  175. package/Sources/FoundationBridge/Operation.swift +195 -0
  176. package/Sources/FoundationBridge/ProcessInfo.swift +32 -0
  177. package/Sources/FoundationBridge/RelativeDateTimeFormatter.swift +136 -0
  178. package/Sources/FoundationBridge/SceneStorage.swift +78 -0
  179. package/Sources/FoundationBridge/SecurityExports.swift +8 -0
  180. package/Sources/FoundationBridge/Selector.swift +226 -0
  181. package/Sources/FoundationBridge/StringComparators.swift +17 -0
  182. package/Sources/FoundationBridge/Table.swift +211 -0
  183. package/Sources/FoundationBridge/TextAttributes.swift +42 -0
  184. package/Sources/FoundationBridge/Timer.swift +6 -1
  185. package/Sources/FoundationBridge/URLSession.swift +718 -0
  186. package/Sources/{_FoundationCommon → FoundationBridge}/UserDefaults.swift +17 -4
  187. package/Sources/FoundationBridge/WebAuthRedirects.swift +227 -0
  188. package/Sources/FoundationBridge/WebSocket.swift +187 -0
  189. package/Sources/FoundationModels/FoundationModels.swift +1098 -0
  190. package/Sources/ImageIO/GIF.swift +72 -0
  191. package/Sources/ImageIO/ImageIO.swift +248 -0
  192. package/Sources/ImageIO/ImageTypes.swift +28 -0
  193. package/Sources/LinkPresentation/LinkPresentation.swift +249 -0
  194. package/Sources/LocalAuthentication/LAContext.swift +86 -0
  195. package/Sources/MapKit/Geometry.swift +223 -0
  196. package/Sources/MapKit/Map.swift +638 -0
  197. package/Sources/MapKit/MapView.swift +229 -0
  198. package/Sources/MobileCoreServices/MobileCoreServices.swift +28 -0
  199. package/Sources/NaturalLanguage/LanguageIdentifier.swift +317 -0
  200. package/Sources/NaturalLanguage/NaturalLanguage.swift +135 -0
  201. package/Sources/OSLog/OSLog.swift +6 -0
  202. package/Sources/Photos/Photos.swift +572 -0
  203. package/Sources/PhotosUI/PhotosPicker.swift +248 -0
  204. package/Sources/PhotosUI/PhotosPickerItem.swift +261 -0
  205. package/Sources/QuickLook/QuickLook.swift +168 -0
  206. package/Sources/SafariServices/SafariServices.swift +106 -0
  207. package/Sources/Security/Security.swift +332 -0
  208. package/Sources/StoreKit/AppStore.swift +207 -0
  209. package/Sources/StoreKit/Products.swift +280 -0
  210. package/Sources/StoreKit/RequestReview.swift +28 -0
  211. package/Sources/StoreKit/StoreKit1.swift +486 -0
  212. package/Sources/StoreKit/StoreViews.swift +428 -0
  213. package/Sources/StoreKit/Transactions.swift +197 -0
  214. package/Sources/SwiftData/Macros.swift +58 -0
  215. package/Sources/SwiftData/ModelActor.swift +38 -0
  216. package/Sources/SwiftData/ModelContainer.swift +129 -0
  217. package/Sources/SwiftData/ModelContext.swift +451 -0
  218. package/Sources/SwiftData/PersistentModel.swift +238 -0
  219. package/Sources/SwiftData/Properties.swift +261 -0
  220. package/Sources/SwiftData/Query.swift +256 -0
  221. package/Sources/SwiftData/Schema.swift +192 -0
  222. package/Sources/SwiftData/Store.swift +146 -0
  223. package/Sources/SwiftData/StringPredicates.swift +125 -0
  224. package/Sources/SwiftDataMacros/EntryMacro.swift +82 -0
  225. package/Sources/SwiftDataMacros/GenerableMacro.swift +183 -0
  226. package/Sources/SwiftDataMacros/ModelActorMacro.swift +46 -0
  227. package/Sources/SwiftDataMacros/ModelMacro.swift +260 -0
  228. package/Sources/SwiftDataMacros/Plugin.swift +18 -0
  229. package/Sources/SwiftDataMacros/PredicateMacro.swift +1244 -0
  230. package/Sources/SwiftUI/API/Accessibility.swift +55 -6
  231. package/Sources/SwiftUI/API/AccessibilityExtras.swift +33 -0
  232. package/Sources/SwiftUI/API/AccessibilityFocus.swift +63 -0
  233. package/Sources/SwiftUI/API/Alert.swift +1 -1
  234. package/Sources/SwiftUI/API/AlignmentGuides.swift +68 -0
  235. package/Sources/SwiftUI/API/Animation.swift +37 -5
  236. package/Sources/SwiftUI/API/App.swift +31 -1
  237. package/Sources/SwiftUI/API/BindingCollections.swift +35 -0
  238. package/Sources/SwiftUI/API/BindingForEach.swift +27 -0
  239. package/Sources/SwiftUI/API/Bitmaps.swift +254 -0
  240. package/Sources/SwiftUI/API/ButtonStyles.swift +96 -0
  241. package/Sources/SwiftUI/API/Canvas.swift +337 -0
  242. package/Sources/SwiftUI/API/Color.swift +104 -28
  243. package/Sources/SwiftUI/API/ColorEffects.swift +52 -0
  244. package/Sources/SwiftUI/API/ColorPickerAndLabeledContent.swift +138 -0
  245. package/Sources/SwiftUI/API/ColorSpaces.swift +161 -0
  246. package/Sources/SwiftUI/API/Commands.swift +106 -0
  247. package/Sources/SwiftUI/API/ContainerBackground.swift +28 -0
  248. package/Sources/SwiftUI/API/ContentShape.swift +33 -0
  249. package/Sources/SwiftUI/API/ContentSizeCategory.swift +35 -0
  250. package/Sources/SwiftUI/API/ContentUnavailable.swift +101 -0
  251. package/Sources/SwiftUI/API/Controls.swift +59 -27
  252. package/Sources/SwiftUI/API/CustomLayout.swift +49 -10
  253. package/Sources/SwiftUI/API/CustomToolbarContent.swift +46 -0
  254. package/Sources/SwiftUI/API/Decorations.swift +1 -1
  255. package/Sources/SwiftUI/API/EditMode.swift +25 -82
  256. package/Sources/SwiftUI/API/Effects.swift +125 -10
  257. package/Sources/SwiftUI/API/Entry.swift +8 -0
  258. package/Sources/SwiftUI/API/Environment.swift +100 -9
  259. package/Sources/SwiftUI/API/EnvironmentSendable.swift +6 -0
  260. package/Sources/SwiftUI/API/Focus.swift +11 -3
  261. package/Sources/SwiftUI/API/Gauge.swift +26 -10
  262. package/Sources/SwiftUI/API/GeometryEffects.swift +232 -0
  263. package/Sources/SwiftUI/API/GeometryReader.swift +13 -2
  264. package/Sources/SwiftUI/API/GestureState.swift +65 -0
  265. package/Sources/SwiftUI/API/Gestures.swift +1 -1
  266. package/Sources/SwiftUI/API/Glass.swift +127 -0
  267. package/Sources/SwiftUI/API/Grid.swift +1 -1
  268. package/Sources/SwiftUI/API/GroupBoxAndControlGroup.swift +130 -0
  269. package/Sources/SwiftUI/API/KeyPress.swift +54 -0
  270. package/Sources/SwiftUI/API/LabelStyle.swift +13 -6
  271. package/Sources/SwiftUI/API/Layout.swift +71 -12
  272. package/Sources/SwiftUI/API/LazyStacks.swift +49 -0
  273. package/Sources/SwiftUI/API/LegacyAlert.swift +97 -0
  274. package/Sources/SwiftUI/API/Lists.swift +61 -6
  275. package/Sources/SwiftUI/API/Menu.swift +8 -1
  276. package/Sources/SwiftUI/API/Modifiers.swift +88 -12
  277. package/Sources/SwiftUI/API/MoreModifiers.swift +100 -0
  278. package/Sources/SwiftUI/API/Namespace.swift +44 -0
  279. package/Sources/SwiftUI/API/Navigation.swift +24 -9
  280. package/Sources/SwiftUI/API/NavigationDestinationBindings.swift +55 -0
  281. package/Sources/SwiftUI/API/ObservableObject.swift +16 -2
  282. package/Sources/SwiftUI/API/Path.swift +543 -0
  283. package/Sources/SwiftUI/API/Phase8Controls.swift +48 -31
  284. package/Sources/SwiftUI/API/PhaseAnimator.swift +130 -0
  285. package/Sources/SwiftUI/API/Picker.swift +14 -4
  286. package/Sources/SwiftUI/API/PointerAndKeyboard.swift +77 -0
  287. package/Sources/SwiftUI/API/Popover.swift +41 -0
  288. package/Sources/SwiftUI/API/Preferences.swift +262 -0
  289. package/Sources/SwiftUI/API/Presentation.swift +17 -4
  290. package/Sources/SwiftUI/API/PresentationExtras.swift +60 -0
  291. package/Sources/SwiftUI/API/Primitives.swift +168 -39
  292. package/Sources/SwiftUI/API/Publishers.swift +4 -4
  293. package/Sources/SwiftUI/API/Redaction.swift +75 -0
  294. package/Sources/SwiftUI/API/RowActions.swift +3 -2
  295. package/Sources/SwiftUI/API/Scenes.swift +131 -0
  296. package/Sources/SwiftUI/API/ScrollModifiers.swift +132 -0
  297. package/Sources/SwiftUI/API/ScrollTargets.swift +3 -3
  298. package/Sources/SwiftUI/API/ScrollViewReader.swift +144 -0
  299. package/Sources/SwiftUI/API/SectionSupplements.swift +86 -0
  300. package/Sources/SwiftUI/API/Shape.swift +214 -0
  301. package/Sources/SwiftUI/API/ShapeStyle.swift +187 -8
  302. package/Sources/SwiftUI/API/ShapeTrim.swift +78 -0
  303. package/Sources/SwiftUI/API/Sharing.swift +193 -0
  304. package/Sources/SwiftUI/API/StackLayouts.swift +199 -0
  305. package/Sources/SwiftUI/API/State.swift +18 -1
  306. package/Sources/SwiftUI/API/StatusGaps.swift +121 -0
  307. package/Sources/SwiftUI/API/SymbolEffects.swift +203 -0
  308. package/Sources/SwiftUI/API/TabContent.swift +841 -0
  309. package/Sources/SwiftUI/API/Table.swift +382 -0
  310. package/Sources/SwiftUI/API/Tabs.swift +148 -4
  311. package/Sources/SwiftUI/API/Tasks.swift +2 -2
  312. package/Sources/SwiftUI/API/Text.swift +386 -0
  313. package/Sources/SwiftUI/API/TextDates.swift +61 -0
  314. package/Sources/SwiftUI/API/TextDecorations.swift +52 -0
  315. package/Sources/SwiftUI/API/TextFieldAxis.swift +103 -0
  316. package/Sources/SwiftUI/API/TextFieldCommit.swift +52 -0
  317. package/Sources/SwiftUI/API/Toolbar.swift +52 -16
  318. package/Sources/SwiftUI/API/Transfer.swift +145 -0
  319. package/Sources/SwiftUI/API/UnevenRoundedRectangle.swift +66 -0
  320. package/Sources/SwiftUI/API/Video.swift +64 -0
  321. package/Sources/SwiftUI/API/View.swift +46 -2
  322. package/Sources/SwiftUI/API/ViewModifier.swift +4 -1
  323. package/Sources/SwiftUI/API/VisualEffect.swift +74 -1
  324. package/Sources/SwiftUI/API/Windows.swift +25 -0
  325. package/Sources/SwiftUI/Charts/Axis.swift +7 -1
  326. package/Sources/SwiftUI/Charts/AxisFormatsAndRanges.swift +68 -0
  327. package/Sources/SwiftUI/Charts/Chart.swift +17 -3
  328. package/Sources/SwiftUI/Charts/ChartProxy.swift +57 -0
  329. package/Sources/SwiftUI/Localization/Localization.swift +524 -0
  330. package/Sources/SwiftUI/Localization/PluralRules.swift +127 -0
  331. package/Sources/SwiftUI/Runtime/Executor.swift +2 -0
  332. package/Sources/SwiftUI/Runtime/Exports.swift +37 -1
  333. package/Sources/SwiftUI/Runtime/ImageSource.swift +310 -0
  334. package/Sources/SwiftUI/Runtime/JSON.swift +76 -4
  335. package/Sources/SwiftUI/Runtime/LazyRows.swift +99 -0
  336. package/Sources/SwiftUI/Runtime/Measurements.swift +140 -0
  337. package/Sources/SwiftUI/Runtime/Ops.swift +58 -12
  338. package/Sources/SwiftUI/Runtime/Reconciler.swift +10 -1
  339. package/Sources/SwiftUI/Runtime/Replay.swift +382 -0
  340. package/Sources/SwiftUI/Runtime/Runtime.swift +977 -198
  341. package/Sources/SwiftUI/Runtime/Sameness.swift +152 -0
  342. package/Sources/SwiftUI/Runtime/ViewPath.swift +89 -0
  343. package/Sources/SwiftUI/Runtime/ViewTraits.swift +175 -0
  344. package/Sources/SwiftUI/Runtime/WebAuthHeadless.swift +49 -0
  345. package/Sources/Symbols/Symbols.swift +25 -0
  346. package/Sources/Translation/Translation.swift +423 -0
  347. package/Sources/UIKit/Activity.swift +213 -0
  348. package/Sources/UIKit/Alerts.swift +69 -0
  349. package/Sources/UIKit/AppDelegate.swift +222 -0
  350. package/Sources/UIKit/Appearance.swift +84 -0
  351. package/Sources/UIKit/ColorConversions.swift +70 -0
  352. package/Sources/UIKit/Controls.swift +225 -0
  353. package/Sources/UIKit/Device.swift +200 -0
  354. package/Sources/UIKit/Feedback.swift +65 -0
  355. package/Sources/UIKit/Font.swift +307 -0
  356. package/Sources/UIKit/Graphics.swift +204 -0
  357. package/Sources/UIKit/HostingController.swift +185 -0
  358. package/Sources/UIKit/Identity.swift +24 -0
  359. package/Sources/UIKit/Introspectable.swift +510 -0
  360. package/Sources/UIKit/Pasteboard.swift +363 -0
  361. package/Sources/UIKit/PhotoAlbum.swift +81 -0
  362. package/Sources/UIKit/RemoteNotifications.swift +15 -0
  363. package/Sources/UIKit/Representable.swift +288 -0
  364. package/Sources/UIKit/SafeArea.swift +12 -0
  365. package/Sources/UIKit/SceneDelegates.swift +132 -0
  366. package/Sources/UIKit/Scenes.swift +40 -0
  367. package/Sources/UIKit/ScrollView.swift +157 -0
  368. package/Sources/UIKit/ShortcutItems.swift +67 -0
  369. package/Sources/UIKit/SymbolConfiguration.swift +124 -0
  370. package/Sources/UIKit/TargetAction.swift +123 -0
  371. package/Sources/UIKit/TextPaste.swift +161 -0
  372. package/Sources/UIKit/TextView.swift +538 -0
  373. package/Sources/UIKit/UIKit.swift +292 -0
  374. package/Sources/UIKit/UIView.swift +855 -0
  375. package/Sources/UIKit/ViewTranslation.swift +311 -0
  376. package/Sources/UniformTypeIdentifiers/UTType.swift +196 -0
  377. package/Sources/UserNotifications/Content.swift +370 -0
  378. package/Sources/UserNotifications/NotificationCenter.swift +309 -0
  379. package/Sources/WeatherKit/WeatherKit.swift +228 -0
  380. package/Sources/WebKit/WebKit.swift +245 -0
  381. package/Sources/os/os.swift +376 -0
  382. package/Sources/zlib/zlib.swift +6 -0
  383. package/index.d.ts +1 -1
  384. package/index.mjs +2 -2
  385. package/manifest.d.mts +2 -0
  386. package/manifest.mjs +41 -0
  387. package/package.json +5 -3
  388. package/sync-sources.mjs +21 -7
  389. package/Sources/FoundationLite/Common.swift +0 -3
  390. package/Sources/FoundationLite/FoundationLite.swift +0 -171
  391. package/Sources/FoundationLite/Interaction.swift +0 -146
  392. package/Sources/FoundationLite/Timer.swift +0 -48
  393. package/Sources/_FoundationCommon/_FoundationCommon.swift +0 -10
@@ -0,0 +1,527 @@
1
+ // `AttributedString(markdown:options:baseURL:)`, which swift-foundation has
2
+ // only on Apple platforms. It parses Markdown's inline syntax, as CommonMark
3
+ // and GitHub define it, into the attributes Apple's parser sets:
4
+ //
5
+ // - `inlinePresentationIntent`: emphasis (`*a*`, `_a_`), strong emphasis
6
+ // (`**a**`, `__a__`), code spans (`` `a` ``), strikethrough (`~a~`, `~~a~~`)
7
+ // and hard line breaks;
8
+ // - `link`, from `[text](url "title")` and `<scheme:…>` autolinks;
9
+ // - `imageURL`, from `![alt](url)`, on the alt text (EmojiText marks its
10
+ // custom emoji this way).
11
+ //
12
+ // Backslash escapes and HTML entities are decoded. Block syntax is not
13
+ // interpreted. With `.full`, blank lines separate paragraphs, and the
14
+ // paragraphs are concatenated, as Apple's parser does when it sets no block
15
+ // attributes. `.inlineOnly` turns line breaks into spaces;
16
+ // `.inlineOnlyPreservingWhitespace` keeps the text's whitespace as it is.
17
+ // Parsing never fails, so the initializer never throws.
18
+
19
+ import Foundation
20
+
21
+ /// How a run of text is presented inline: Markdown's emphasis, code and the like.
22
+ public struct InlinePresentationIntent: OptionSet, Hashable, Codable, Sendable {
23
+ public let rawValue: UInt
24
+ public init(rawValue: UInt) { self.rawValue = rawValue }
25
+
26
+ public static let emphasized = InlinePresentationIntent(rawValue: 1 << 0)
27
+ public static let stronglyEmphasized = InlinePresentationIntent(rawValue: 1 << 1)
28
+ public static let code = InlinePresentationIntent(rawValue: 1 << 2)
29
+ public static let strikethrough = InlinePresentationIntent(rawValue: 1 << 5)
30
+ public static let softBreak = InlinePresentationIntent(rawValue: 1 << 6)
31
+ public static let lineBreak = InlinePresentationIntent(rawValue: 1 << 7)
32
+ public static let inlineHTML = InlinePresentationIntent(rawValue: 1 << 8)
33
+ public static let blockHTML = InlinePresentationIntent(rawValue: 1 << 9)
34
+ }
35
+
36
+ extension AttributeScopes.FoundationAttributes {
37
+ /// Markdown's inline presentation (`run.inlinePresentationIntent`).
38
+ public enum InlinePresentationIntentAttribute: CodableAttributedStringKey {
39
+ public typealias Value = InlinePresentationIntent
40
+ public static let name = "NSInlinePresentationIntent"
41
+ }
42
+
43
+ /// For `attributedString.inlinePresentationIntent`: like the scope's own
44
+ /// attributes, the key path names the key and its value is never read.
45
+ public var inlinePresentationIntent: InlinePresentationIntentAttribute { fatalError("an attribute key path is never read") }
46
+ }
47
+
48
+ extension AttributedString {
49
+ public struct MarkdownParsingOptions: Hashable, Sendable {
50
+ public enum InterpretedSyntax: Hashable, Sendable {
51
+ case full
52
+ case inlineOnly
53
+ case inlineOnlyPreservingWhitespace
54
+ }
55
+
56
+ public enum FailurePolicy: Hashable, Sendable {
57
+ case throwError
58
+ case returnPartiallyParsedIfPossible
59
+ }
60
+
61
+ public var allowsExtendedAttributes: Bool
62
+ public var interpretedSyntax: InterpretedSyntax
63
+ public var failurePolicy: FailurePolicy
64
+ public var languageCode: String?
65
+ public var appliesSourcePositionAttributes: Bool
66
+
67
+ public init(allowsExtendedAttributes: Bool = false, interpretedSyntax: InterpretedSyntax = .full,
68
+ failurePolicy: FailurePolicy = .throwError, languageCode: String? = nil,
69
+ appliesSourcePositionAttributes: Bool = false) {
70
+ self.allowsExtendedAttributes = allowsExtendedAttributes
71
+ self.interpretedSyntax = interpretedSyntax
72
+ self.failurePolicy = failurePolicy
73
+ self.languageCode = languageCode
74
+ self.appliesSourcePositionAttributes = appliesSourcePositionAttributes
75
+ }
76
+ }
77
+
78
+ public init(markdown: String, options: MarkdownParsingOptions = .init(), baseURL: URL? = nil) throws {
79
+ self.init()
80
+ for segment in _MarkdownInline.segments(of: markdown, syntax: options.interpretedSyntax) {
81
+ var piece = AttributedString(segment.text)
82
+ if !segment.intent.isEmpty { piece[AttributeScopes.FoundationAttributes.InlinePresentationIntentAttribute.self] = segment.intent }
83
+ if let link = segment.link { piece.link = Self._url(link, relativeTo: baseURL) }
84
+ if let image = segment.image { piece.imageURL = Self._url(image, relativeTo: baseURL) }
85
+ self.append(piece)
86
+ }
87
+ }
88
+
89
+ public init(markdown: Data, options: MarkdownParsingOptions = .init(), baseURL: URL? = nil) throws {
90
+ try self.init(markdown: String(decoding: markdown, as: UTF8.self), options: options, baseURL: baseURL)
91
+ }
92
+
93
+ static func _url(_ string: String, relativeTo base: URL?) -> URL? {
94
+ if let url = URL(string: string, relativeTo: base) { return url }
95
+ let encoded = string.addingPercentEncoding(withAllowedCharacters: .urlFragmentAllowed.union(.urlPathAllowed).union(CharacterSet(charactersIn: "?#:/")))
96
+ return encoded.flatMap { URL(string: $0, relativeTo: base) }
97
+ }
98
+ }
99
+
100
+ /// Markdown's inline syntax, parsed into runs of text with their presentation.
101
+ enum _MarkdownInline {
102
+ struct Segment: Equatable {
103
+ var text: String
104
+ var intent: InlinePresentationIntent = []
105
+ var link: String?
106
+ var image: String?
107
+ }
108
+
109
+ indirect enum Node: Equatable {
110
+ case text(String)
111
+ case code(String)
112
+ case lineBreak
113
+ case styled(InlinePresentationIntent, [Node])
114
+ case link(String, [Node])
115
+ case image(String, [Node])
116
+ }
117
+
118
+ static func segments(of markdown: String, syntax: AttributedString.MarkdownParsingOptions.InterpretedSyntax) -> [Segment] {
119
+ var source = markdown.replacingOccurrences(of: "\r\n", with: "\n")
120
+ switch syntax {
121
+ case .inlineOnlyPreservingWhitespace:
122
+ return merge(flatten(parse(source, keepWhitespace: true)))
123
+ case .inlineOnly:
124
+ return merge(flatten(parse(source, keepWhitespace: false)))
125
+ case .full:
126
+ // Paragraphs: runs of lines between blank lines, concatenated.
127
+ if source.hasSuffix("\n") { source.removeLast() }
128
+ var paragraphs: [String] = []
129
+ var current: [Substring] = []
130
+ for line in source.split(separator: "\n", omittingEmptySubsequences: false) {
131
+ if line.allSatisfy({ $0 == " " || $0 == "\t" }) {
132
+ if !current.isEmpty { paragraphs.append(current.joined(separator: "\n")) }
133
+ current = []
134
+ } else {
135
+ current.append(line)
136
+ }
137
+ }
138
+ if !current.isEmpty { paragraphs.append(current.joined(separator: "\n")) }
139
+ return merge(paragraphs.flatMap { flatten(parse($0, keepWhitespace: false)) })
140
+ }
141
+ }
142
+
143
+ // MARK: Flattening
144
+
145
+ static func flatten(_ nodes: [Node], intent: InlinePresentationIntent = [], link: String? = nil, image: String? = nil) -> [Segment] {
146
+ nodes.flatMap { node -> [Segment] in
147
+ switch node {
148
+ case .text(let text): [Segment(text: text, intent: intent, link: link, image: image)]
149
+ case .code(let text): [Segment(text: text, intent: intent.union(.code), link: link, image: image)]
150
+ case .lineBreak: [Segment(text: "\n", intent: intent.union(.lineBreak), link: link, image: image)]
151
+ case .styled(let style, let children): flatten(children, intent: intent.union(style), link: link, image: image)
152
+ case .link(let url, let children): flatten(children, intent: intent, link: url, image: image)
153
+ case .image(let url, let children): flatten(children, intent: intent, link: link, image: url)
154
+ }
155
+ }
156
+ }
157
+
158
+ /// Joins neighbors with the same attributes, and drops empty ones.
159
+ static func merge(_ segments: [Segment]) -> [Segment] {
160
+ var out: [Segment] = []
161
+ for segment in segments where !segment.text.isEmpty {
162
+ if var last = out.last, last.intent == segment.intent, last.link == segment.link, last.image == segment.image {
163
+ last.text += segment.text
164
+ out[out.count - 1] = last
165
+ } else {
166
+ out.append(segment)
167
+ }
168
+ }
169
+ return out
170
+ }
171
+
172
+ // MARK: Parsing
173
+
174
+ /// A piece of the inline content while it is parsed: finished nodes, and
175
+ /// the delimiters that may yet open or close emphasis or a link.
176
+ enum Piece {
177
+ case node(Node)
178
+ case delimiter(Delimiter)
179
+ }
180
+
181
+ struct Delimiter {
182
+ var char: Character
183
+ var count: Int
184
+ var originalCount: Int
185
+ var canOpen: Bool
186
+ var canClose: Bool
187
+ /// `[` or `![`: a link or image opener.
188
+ var isBracket: Bool { char == "[" || char == "!" }
189
+ var active = true
190
+
191
+ var literal: String { char == "!" ? "![" : String(repeating: char, count: count) }
192
+ }
193
+
194
+ static let punctuation = Set("!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~")
195
+
196
+ static func isPunctuation(_ c: Character?) -> Bool {
197
+ guard let c else { return false }
198
+ return punctuation.contains(c) || c.unicodeScalars.allSatisfy { CharacterSet.punctuationCharacters.contains($0) || CharacterSet.symbols.contains($0) }
199
+ }
200
+
201
+ static func isWhitespace(_ c: Character?) -> Bool {
202
+ guard let c else { return true }
203
+ return c.isWhitespace
204
+ }
205
+
206
+ static func parse(_ source: String, keepWhitespace: Bool) -> [Node] {
207
+ let chars = Array(source)
208
+ var pieces: [Piece] = []
209
+ var text = ""
210
+ var i = 0
211
+
212
+ func flushText() {
213
+ if !text.isEmpty { pieces.append(.node(.text(text))); text = "" }
214
+ }
215
+
216
+ while i < chars.count {
217
+ let c = chars[i]
218
+ switch c {
219
+ case "\\":
220
+ if i + 1 < chars.count, chars[i + 1] == "\n" {
221
+ flushText()
222
+ pieces.append(.node(.lineBreak))
223
+ i += 2
224
+ } else if i + 1 < chars.count, punctuation.contains(chars[i + 1]) {
225
+ text.append(chars[i + 1])
226
+ i += 2
227
+ } else {
228
+ text.append(c)
229
+ i += 1
230
+ }
231
+ case "`":
232
+ var run = 0
233
+ while i + run < chars.count, chars[i + run] == "`" { run += 1 }
234
+ if let end = closingBackticks(chars, from: i + run, count: run) {
235
+ flushText()
236
+ var code = String(chars[(i + run)..<end]).replacingOccurrences(of: "\n", with: " ")
237
+ if code.count >= 2, code.first == " ", code.last == " ", !code.allSatisfy({ $0 == " " }) {
238
+ code = String(code.dropFirst().dropLast())
239
+ }
240
+ pieces.append(.node(.code(code)))
241
+ i = end + run
242
+ } else {
243
+ text += String(repeating: "`", count: run)
244
+ i += run
245
+ }
246
+ case "*", "_", "~":
247
+ var run = 0
248
+ while i + run < chars.count, chars[i + run] == c { run += 1 }
249
+ let before: Character? = i > 0 ? chars[i - 1] : nil
250
+ let after: Character? = i + run < chars.count ? chars[i + run] : nil
251
+ let leftFlanking = !isWhitespace(after) && (!isPunctuation(after) || isWhitespace(before) || isPunctuation(before))
252
+ let rightFlanking = !isWhitespace(before) && (!isPunctuation(before) || isWhitespace(after) || isPunctuation(after))
253
+ var canOpen = leftFlanking
254
+ var canClose = rightFlanking
255
+ if c == "_" {
256
+ canOpen = leftFlanking && (!rightFlanking || isPunctuation(before))
257
+ canClose = rightFlanking && (!leftFlanking || isPunctuation(after))
258
+ }
259
+ if c == "~" && run > 2 {
260
+ text += String(repeating: "~", count: run)
261
+ } else {
262
+ flushText()
263
+ pieces.append(.delimiter(Delimiter(char: c, count: run, originalCount: run, canOpen: canOpen, canClose: canClose)))
264
+ }
265
+ i += run
266
+ case "!" where i + 1 < chars.count && chars[i + 1] == "[":
267
+ flushText()
268
+ pieces.append(.delimiter(Delimiter(char: "!", count: 1, originalCount: 1, canOpen: true, canClose: false)))
269
+ i += 2
270
+ case "[":
271
+ flushText()
272
+ pieces.append(.delimiter(Delimiter(char: "[", count: 1, originalCount: 1, canOpen: true, canClose: false)))
273
+ i += 1
274
+ case "]":
275
+ flushText()
276
+ if let next = closeBracket(&pieces, chars, after: i + 1) {
277
+ i = next
278
+ } else {
279
+ text.append("]")
280
+ i += 1
281
+ }
282
+ case "<":
283
+ if let (url, end) = autolink(chars, from: i) {
284
+ flushText()
285
+ pieces.append(.node(.link(url, [.text(url.hasPrefix("mailto:") && !String(chars[(i + 1)..<end]).hasPrefix("mailto:") ? String(url.dropFirst(7)) : String(chars[(i + 1)..<end]))])))
286
+ i = end + 1
287
+ } else {
288
+ text.append(c)
289
+ i += 1
290
+ }
291
+ case "&":
292
+ if let (decoded, end) = entity(chars, from: i) {
293
+ text += decoded
294
+ i = end
295
+ } else {
296
+ text.append(c)
297
+ i += 1
298
+ }
299
+ case "\n":
300
+ // Two or more spaces before a line break make a hard break.
301
+ if text.hasSuffix(" ") {
302
+ while text.hasSuffix(" ") { text.removeLast() }
303
+ flushText()
304
+ pieces.append(.node(.lineBreak))
305
+ } else if keepWhitespace {
306
+ text.append("\n")
307
+ } else {
308
+ while text.hasSuffix(" ") { text.removeLast() }
309
+ text.append(" ")
310
+ }
311
+ i += 1
312
+ if !keepWhitespace { while i < chars.count, chars[i] == " " { i += 1 } }
313
+ default:
314
+ text.append(c)
315
+ i += 1
316
+ }
317
+ }
318
+ flushText()
319
+ processEmphasis(&pieces, from: 0)
320
+ return nodes(of: pieces)
321
+ }
322
+
323
+ /// The pieces as nodes, with delimiters that matched nothing as text.
324
+ static func nodes(of pieces: some Collection<Piece>) -> [Node] {
325
+ var out: [Node] = []
326
+ for piece in pieces {
327
+ let node: Node
328
+ switch piece {
329
+ case .node(let n): node = n
330
+ case .delimiter(let d): node = .text(d.literal)
331
+ }
332
+ if case .text(let new) = node, case .text(let old)? = out.last {
333
+ out[out.count - 1] = .text(old + new)
334
+ } else {
335
+ out.append(node)
336
+ }
337
+ }
338
+ return out
339
+ }
340
+
341
+ static func closingBackticks(_ chars: [Character], from start: Int, count: Int) -> Int? {
342
+ var j = start
343
+ while j < chars.count {
344
+ if chars[j] == "`" {
345
+ var run = 0
346
+ while j + run < chars.count, chars[j + run] == "`" { run += 1 }
347
+ if run == count { return j }
348
+ j += run
349
+ } else {
350
+ j += 1
351
+ }
352
+ }
353
+ return nil
354
+ }
355
+
356
+ /// `]` after a `[` or `![` opener: when `(destination "title")` follows,
357
+ /// the pieces since the opener become a link or image.
358
+ static func closeBracket(_ pieces: inout [Piece], _ chars: [Character], after start: Int) -> Int? {
359
+ guard let openerIndex = pieces.lastIndex(where: { if case .delimiter(let d) = $0 { return d.isBracket }; return false }),
360
+ case .delimiter(let opener) = pieces[openerIndex] else { return nil }
361
+ guard opener.active, let (destination, end) = inlineDestination(chars, from: start) else {
362
+ // Not a link: the opener is literal text.
363
+ pieces[openerIndex] = .node(.text(opener.literal))
364
+ return nil
365
+ }
366
+ processEmphasis(&pieces, from: openerIndex + 1)
367
+ let children = nodes(of: pieces[(openerIndex + 1)...])
368
+ pieces.removeSubrange(openerIndex...)
369
+ if opener.char == "!" {
370
+ pieces.append(.node(.image(destination, children)))
371
+ } else {
372
+ pieces.append(.node(.link(destination, children)))
373
+ // No links inside links: earlier openers can no longer make one.
374
+ for index in pieces.indices {
375
+ if case .delimiter(var d) = pieces[index], d.char == "[" {
376
+ d.active = false
377
+ pieces[index] = .delimiter(d)
378
+ }
379
+ }
380
+ }
381
+ return end
382
+ }
383
+
384
+ /// `(destination "title")` at `start`: the destination and the index after `)`.
385
+ static func inlineDestination(_ chars: [Character], from start: Int) -> (String, Int)? {
386
+ guard start < chars.count, chars[start] == "(" else { return nil }
387
+ var j = start + 1
388
+ func skipSpaces() { while j < chars.count, chars[j] == " " || chars[j] == "\n" || chars[j] == "\t" { j += 1 } }
389
+ skipSpaces()
390
+ var destination = ""
391
+ if j < chars.count, chars[j] == "<" {
392
+ j += 1
393
+ while j < chars.count, chars[j] != ">" {
394
+ if chars[j] == "\n" || chars[j] == "<" { return nil }
395
+ if chars[j] == "\\", j + 1 < chars.count, punctuation.contains(chars[j + 1]) { j += 1 }
396
+ destination.append(chars[j])
397
+ j += 1
398
+ }
399
+ guard j < chars.count else { return nil }
400
+ j += 1
401
+ } else {
402
+ var depth = 0
403
+ while j < chars.count {
404
+ let c = chars[j]
405
+ if c == " " || c == "\n" || c == "\t" { break }
406
+ if c == "(" { depth += 1 }
407
+ if c == ")" {
408
+ if depth == 0 { break }
409
+ depth -= 1
410
+ }
411
+ if c == "\\", j + 1 < chars.count, punctuation.contains(chars[j + 1]) {
412
+ j += 1
413
+ }
414
+ destination.append(chars[j])
415
+ j += 1
416
+ }
417
+ }
418
+ skipSpaces()
419
+ if j < chars.count, chars[j] == "\"" || chars[j] == "'" || chars[j] == "(" {
420
+ let close: Character = chars[j] == "(" ? ")" : chars[j]
421
+ j += 1
422
+ while j < chars.count, chars[j] != close { j += 1 }
423
+ guard j < chars.count else { return nil }
424
+ j += 1
425
+ skipSpaces()
426
+ }
427
+ guard j < chars.count, chars[j] == ")" else { return nil }
428
+ return (destination, j + 1)
429
+ }
430
+
431
+ /// `<scheme:…>` or `<user@host>`: the URL and the index of `>`.
432
+ static func autolink(_ chars: [Character], from start: Int) -> (String, Int)? {
433
+ var j = start + 1
434
+ var body = ""
435
+ while j < chars.count, chars[j] != ">" {
436
+ if chars[j] == " " || chars[j] == "<" || chars[j] == "\n" { return nil }
437
+ body.append(chars[j])
438
+ j += 1
439
+ }
440
+ guard j < chars.count else { return nil }
441
+ if let colon = body.firstIndex(of: ":") {
442
+ let scheme = body[..<colon]
443
+ guard (2...32).contains(scheme.count), scheme.first!.isLetter,
444
+ scheme.allSatisfy({ $0.isLetter || $0.isNumber || $0 == "+" || $0 == "." || $0 == "-" }) else { return nil }
445
+ return (body, j)
446
+ }
447
+ if body.contains("@"), !body.hasPrefix("@"), !body.hasSuffix("@") { return ("mailto:" + body, j) }
448
+ return nil
449
+ }
450
+
451
+ static let namedEntities: [String: String] = [
452
+ "amp": "&", "lt": "<", "gt": ">", "quot": "\"", "apos": "'", "nbsp": "\u{00A0}",
453
+ "hellip": "…", "mdash": "—", "ndash": "–", "lsquo": "‘", "rsquo": "’", "ldquo": "“", "rdquo": "”",
454
+ "copy": "©", "reg": "®", "trade": "™", "middot": "·", "bull": "•", "laquo": "«", "raquo": "»",
455
+ ]
456
+
457
+ /// `&name;`, `&#123;` or `&#x1F600;` at `start`: the decoded text and the index after `;`.
458
+ static func entity(_ chars: [Character], from start: Int) -> (String, Int)? {
459
+ guard let semicolon = chars[start...].prefix(34).firstIndex(of: ";"), semicolon > start + 1 else { return nil }
460
+ let body = String(chars[(start + 1)..<semicolon])
461
+ if body.hasPrefix("#x") || body.hasPrefix("#X") {
462
+ guard let code = UInt32(body.dropFirst(2), radix: 16), let scalar = Unicode.Scalar(code), code != 0 else { return nil }
463
+ return (String(Character(scalar)), semicolon + 1)
464
+ }
465
+ if body.hasPrefix("#") {
466
+ guard let code = UInt32(body.dropFirst()), let scalar = Unicode.Scalar(code), code != 0 else { return nil }
467
+ return (String(Character(scalar)), semicolon + 1)
468
+ }
469
+ guard let decoded = namedEntities[body] else { return nil }
470
+ return (decoded, semicolon + 1)
471
+ }
472
+
473
+ /// CommonMark's emphasis algorithm over the pieces from `bottom` on: each
474
+ /// closer, left to right, matches the nearest opener of its kind, and
475
+ /// what lies between becomes emphasized (or struck through).
476
+ static func processEmphasis(_ pieces: inout [Piece], from bottom: Int) {
477
+ var closerIndex = bottom
478
+ while closerIndex < pieces.count {
479
+ guard case .delimiter(var closer) = pieces[closerIndex], !closer.isBracket, closer.canClose else {
480
+ closerIndex += 1
481
+ continue
482
+ }
483
+ var openerIndex: Int?
484
+ var j = closerIndex - 1
485
+ while j >= bottom {
486
+ if case .delimiter(let opener) = pieces[j], opener.char == closer.char, opener.canOpen {
487
+ let matches: Bool
488
+ if closer.char == "~" {
489
+ matches = opener.count == closer.count
490
+ } else if (opener.canClose || closer.canOpen),
491
+ (opener.originalCount + closer.originalCount) % 3 == 0,
492
+ !(opener.originalCount % 3 == 0 && closer.originalCount % 3 == 0) {
493
+ matches = false
494
+ } else {
495
+ matches = true
496
+ }
497
+ if matches { openerIndex = j; break }
498
+ }
499
+ j -= 1
500
+ }
501
+ guard let openerIndex, case .delimiter(var opener) = pieces[openerIndex] else {
502
+ closerIndex += 1
503
+ continue
504
+ }
505
+ let used: Int
506
+ let style: InlinePresentationIntent
507
+ if closer.char == "~" {
508
+ used = closer.count
509
+ style = .strikethrough
510
+ } else {
511
+ used = opener.count >= 2 && closer.count >= 2 ? 2 : 1
512
+ style = used == 2 ? .stronglyEmphasized : .emphasized
513
+ }
514
+ let inner = nodes(of: pieces[(openerIndex + 1)..<closerIndex])
515
+ opener.count -= used
516
+ closer.count -= used
517
+ var replacement: [Piece] = []
518
+ if opener.count > 0 { replacement.append(.delimiter(opener)) }
519
+ replacement.append(.node(.styled(style, inner)))
520
+ let styledIndex = openerIndex + replacement.count - 1
521
+ if closer.count > 0 { replacement.append(.delimiter(closer)) }
522
+ pieces.replaceSubrange(openerIndex...closerIndex, with: replacement)
523
+ // A closer with some left over is next again; otherwise the piece after the run.
524
+ closerIndex = styledIndex + 1
525
+ }
526
+ }
527
+ }
@@ -0,0 +1,95 @@
1
+ // `Measurement.formatted()` and `Measurement.FormatStyle`, which corelibs
2
+ // Foundation lacks: the value as `Double.formatted()` writes it, then the
3
+ // unit's symbol ("57°F", "5 km"). A temperature in the general or weather
4
+ // usage is converted to the locale's unit first (Fahrenheit in the United
5
+ // States and the few regions that use it, Celsius elsewhere), as Apple's
6
+ // does; other units are written in their own. Units are written as symbols
7
+ // at every width.
8
+
9
+ import Foundation
10
+
11
+ extension Measurement {
12
+ public struct FormatStyle: Foundation.FormatStyle, Hashable, Sendable {
13
+ public struct UnitWidth: Codable, Hashable, Sendable {
14
+ let name: String
15
+ public static var wide: UnitWidth { UnitWidth(name: "wide") }
16
+ public static var abbreviated: UnitWidth { UnitWidth(name: "abbreviated") }
17
+ public static var narrow: UnitWidth { UnitWidth(name: "narrow") }
18
+ }
19
+
20
+ public var width: UnitWidth
21
+ public var locale: Locale
22
+ /// Whether a temperature is converted to the locale's unit.
23
+ var convertsTemperature: Bool
24
+
25
+ public init(width: UnitWidth = .abbreviated, locale: Locale = .autoupdatingCurrent) {
26
+ self.width = width
27
+ self.locale = locale
28
+ convertsTemperature = true
29
+ }
30
+
31
+ public func locale(_ locale: Locale) -> Self {
32
+ var copy = self
33
+ copy.locale = locale
34
+ return copy
35
+ }
36
+
37
+ public func format(_ measurement: Measurement<UnitType>) -> String {
38
+ var value = measurement.value
39
+ var symbol = measurement.unit.symbol
40
+ if convertsTemperature, let temperature = measurement as? Measurement<UnitTemperature> {
41
+ let unit: UnitTemperature = Self.usesFahrenheit(locale) ? .fahrenheit : .celsius
42
+ let converted = temperature.converted(to: unit)
43
+ value = converted.value
44
+ symbol = unit.symbol
45
+ }
46
+ let number = value.formatted()
47
+ // Temperatures and angles hug their number, as in "21°C".
48
+ let hugs = symbol.hasPrefix("°") || symbol == "%" || symbol == "′" || symbol == "″"
49
+ return hugs ? number + symbol : number + " " + symbol
50
+ }
51
+
52
+ static func usesFahrenheit(_ locale: Locale) -> Bool {
53
+ ["US", "LR", "MM", "BS", "BZ", "KY", "PW", "FM", "MH"].contains(locale.region?.identifier ?? "US")
54
+ }
55
+ }
56
+
57
+ /// The measurement in the locale's style (see the top of the file).
58
+ public func formatted() -> String {
59
+ FormatStyle().format(self)
60
+ }
61
+
62
+ public func formatted<S: Foundation.FormatStyle>(_ style: S) -> S.FormatOutput where S.FormatInput == Measurement<UnitType> {
63
+ style.format(self)
64
+ }
65
+ }
66
+
67
+ extension Measurement.FormatStyle where UnitType == UnitTemperature {
68
+ /// How a temperature is used: in the general and weather usages it is
69
+ /// converted to the locale's unit; `asProvided` keeps its own.
70
+ public struct Usage: Codable, Hashable, Sendable {
71
+ let converts: Bool
72
+ public static var general: Usage { Usage(converts: true) }
73
+ public static var weather: Usage { Usage(converts: true) }
74
+ public static var person: Usage { Usage(converts: true) }
75
+ public static var asProvided: Usage { Usage(converts: false) }
76
+ }
77
+
78
+ public init(width: UnitWidth = .abbreviated, locale: Locale = .autoupdatingCurrent, usage: Usage) {
79
+ self.init(width: width, locale: locale)
80
+ convertsTemperature = usage.converts
81
+ }
82
+ }
83
+
84
+ extension Foundation.FormatStyle {
85
+ public static func measurement<UnitType: Dimension>(width: Measurement<UnitType>.FormatStyle.UnitWidth = .abbreviated) -> Self
86
+ where Self == Measurement<UnitType>.FormatStyle {
87
+ Measurement<UnitType>.FormatStyle(width: width)
88
+ }
89
+
90
+ public static func measurement(width: Measurement<UnitTemperature>.FormatStyle.UnitWidth = .abbreviated,
91
+ usage: Measurement<UnitTemperature>.FormatStyle.Usage) -> Self
92
+ where Self == Measurement<UnitTemperature>.FormatStyle {
93
+ Measurement<UnitTemperature>.FormatStyle(width: width, usage: usage)
94
+ }
95
+ }