@swiftbrowser/swift 0.0.0-stage → 0.2.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.
- package/Package.swift +214 -0
- package/README.md +10 -2
- package/Sources/AVFoundation/AVFoundation.swift +131 -0
- package/Sources/AVFoundation/Asset.swift +487 -0
- package/Sources/AVFoundation/AudioSession.swift +144 -0
- package/Sources/AVFoundation/CMTime.swift +303 -0
- package/Sources/AVFoundation/Capture.swift +688 -0
- package/Sources/AVFoundation/Player.swift +749 -0
- package/Sources/AVFoundation/PlayerView.swift +117 -0
- package/Sources/AVKit/AVKit.swift +132 -0
- package/Sources/Accelerate/Accelerate.swift +122 -0
- package/Sources/AppIntents/AppIntents.swift +144 -0
- package/Sources/AppIntents/Parameters.swift +220 -0
- package/Sources/AppIntents/Shortcuts.swift +159 -0
- package/Sources/AudioToolbox/AudioToolbox.swift +55 -0
- package/Sources/AuthenticationServices/AuthenticationServices.swift +257 -0
- package/Sources/AuthenticationServices/Authorization.swift +251 -0
- package/Sources/Charts/Charts.swift +61 -0
- package/Sources/Combine/AnyCancellable.swift +65 -0
- package/Sources/Combine/AnyPublisher.swift +148 -0
- package/Sources/Combine/AnySubscriber.swift +230 -0
- package/Sources/Combine/Cancellable.swift +35 -0
- package/Sources/Combine/Codable.swift +29 -0
- package/Sources/Combine/CombineIdentifier.swift +45 -0
- package/Sources/Combine/Concurrency/ConcurrencyHelpers.swift +24 -0
- package/Sources/Combine/Concurrency/Future+Concurrency.swift +136 -0
- package/Sources/Combine/Concurrency/GENERATED-Publisher+Concurrency.swift +397 -0
- package/Sources/Combine/CurrentValueSubject.swift +252 -0
- package/Sources/Combine/CustomCombineIdentifierConvertible.swift +28 -0
- package/Sources/Combine/Future.swift +228 -0
- package/Sources/Combine/GENERATED-RootProtocols.swift +426 -0
- package/Sources/Combine/Helpers/ConduitBase.swift +40 -0
- package/Sources/Combine/Helpers/ConduitList.swift +59 -0
- package/Sources/Combine/Helpers/DebugHook.swift +177 -0
- package/Sources/Combine/Helpers/FilterProducer.swift +174 -0
- package/Sources/Combine/Helpers/Locking.swift +30 -0
- package/Sources/Combine/Helpers/PartialCompletion.swift +26 -0
- package/Sources/Combine/Helpers/ReduceProducer.swift +249 -0
- package/Sources/Combine/Helpers/SubjectSubscriber.swift +96 -0
- package/Sources/Combine/Helpers/SubscriberTap.swift +69 -0
- package/Sources/Combine/Helpers/SubscriptionStatus.swift +33 -0
- package/Sources/Combine/Helpers/SubscriptionTap.swift +33 -0
- package/Sources/Combine/Helpers/Utils.swift +30 -0
- package/Sources/Combine/Helpers/Violations.swift +33 -0
- package/Sources/Combine/ImmediateScheduler.swift +178 -0
- package/Sources/Combine/LICENSE +21 -0
- package/Sources/Combine/NotificationPublisher.swift +48 -0
- package/Sources/Combine/ObjectWillChange.swift +46 -0
- package/Sources/Combine/PassthroughSubject.swift +222 -0
- package/Sources/Combine/Publisher+Subscribe.swift +53 -0
- package/Sources/Combine/Publishers/Deferred.swift +48 -0
- package/Sources/Combine/Publishers/Empty.swift +54 -0
- package/Sources/Combine/Publishers/Fail.swift +42 -0
- package/Sources/Combine/Publishers/GENERATED-Publishers.Catch.swift +673 -0
- package/Sources/Combine/Publishers/GENERATED-Publishers.Encode.swift +388 -0
- package/Sources/Combine/Publishers/GENERATED-Publishers.MapKeyPath.swift +384 -0
- package/Sources/Combine/Publishers/Just.swift +313 -0
- package/Sources/Combine/Publishers/Optional.Publisher.swift +315 -0
- package/Sources/Combine/Publishers/Publishers.AllSatisfy.swift +217 -0
- package/Sources/Combine/Publishers/Publishers.AssertNoFailure.swift +158 -0
- package/Sources/Combine/Publishers/Publishers.Autoconnect.swift +193 -0
- package/Sources/Combine/Publishers/Publishers.Breakpoint.swift +231 -0
- package/Sources/Combine/Publishers/Publishers.Buffer.swift +356 -0
- package/Sources/Combine/Publishers/Publishers.Collect.swift +102 -0
- package/Sources/Combine/Publishers/Publishers.CollectByCount.swift +195 -0
- package/Sources/Combine/Publishers/Publishers.CompactMap.swift +241 -0
- package/Sources/Combine/Publishers/Publishers.Comparison.swift +371 -0
- package/Sources/Combine/Publishers/Publishers.Concatenate.swift +474 -0
- package/Sources/Combine/Publishers/Publishers.Contains.swift +293 -0
- package/Sources/Combine/Publishers/Publishers.Count.swift +87 -0
- package/Sources/Combine/Publishers/Publishers.Debounce.swift +332 -0
- package/Sources/Combine/Publishers/Publishers.Delay.swift +269 -0
- package/Sources/Combine/Publishers/Publishers.Drop.swift +155 -0
- package/Sources/Combine/Publishers/Publishers.DropUntilOutput.swift +283 -0
- package/Sources/Combine/Publishers/Publishers.DropWhile.swift +378 -0
- package/Sources/Combine/Publishers/Publishers.Filter.swift +248 -0
- package/Sources/Combine/Publishers/Publishers.First.swift +261 -0
- package/Sources/Combine/Publishers/Publishers.FlatMap.swift +533 -0
- package/Sources/Combine/Publishers/Publishers.HandleEvents.swift +260 -0
- package/Sources/Combine/Publishers/Publishers.IgnoreOutput.swift +109 -0
- package/Sources/Combine/Publishers/Publishers.Last.swift +252 -0
- package/Sources/Combine/Publishers/Publishers.MakeConnectable.swift +82 -0
- package/Sources/Combine/Publishers/Publishers.Map.swift +351 -0
- package/Sources/Combine/Publishers/Publishers.MapError.swift +140 -0
- package/Sources/Combine/Publishers/Publishers.MeasureInterval.swift +187 -0
- package/Sources/Combine/Publishers/Publishers.Multicast.swift +284 -0
- package/Sources/Combine/Publishers/Publishers.Output.swift +241 -0
- package/Sources/Combine/Publishers/Publishers.PrefixUntilOutput.swift +197 -0
- package/Sources/Combine/Publishers/Publishers.PrefixWhile.swift +176 -0
- package/Sources/Combine/Publishers/Publishers.Print.swift +206 -0
- package/Sources/Combine/Publishers/Publishers.ReceiveOn.swift +227 -0
- package/Sources/Combine/Publishers/Publishers.Reduce.swift +204 -0
- package/Sources/Combine/Publishers/Publishers.RemoveDuplicates.swift +264 -0
- package/Sources/Combine/Publishers/Publishers.ReplaceEmpty.swift +201 -0
- package/Sources/Combine/Publishers/Publishers.ReplaceError.swift +211 -0
- package/Sources/Combine/Publishers/Publishers.Retry.swift +274 -0
- package/Sources/Combine/Publishers/Publishers.Scan.swift +331 -0
- package/Sources/Combine/Publishers/Publishers.Sequence.swift +437 -0
- package/Sources/Combine/Publishers/Publishers.SetFailureType.swift +120 -0
- package/Sources/Combine/Publishers/Publishers.Share.swift +104 -0
- package/Sources/Combine/Publishers/Publishers.SubscribeOn.swift +197 -0
- package/Sources/Combine/Publishers/Publishers.SwitchToLatest.swift +444 -0
- package/Sources/Combine/Publishers/Publishers.Throttle.swift +359 -0
- package/Sources/Combine/Publishers/Publishers.Timeout.swift +301 -0
- package/Sources/Combine/Publishers/Publishers.Zip.swift +720 -0
- package/Sources/Combine/Publishers/Publishers.swift +13 -0
- package/Sources/Combine/Publishers/Record.swift +237 -0
- package/Sources/Combine/Publishers/Result.Publisher.swift +337 -0
- package/Sources/Combine/Result.swift +46 -0
- package/Sources/Combine/Scheduler.swift +89 -0
- package/Sources/Combine/Schedulers.swift +211 -0
- package/Sources/Combine/Subject+Void.swift +17 -0
- package/Sources/Combine/Subscriber+Void.swift +20 -0
- package/Sources/Combine/Subscribers/Subscribers.Assign.swift +175 -0
- package/Sources/Combine/Subscribers/Subscribers.Completion.swift +90 -0
- package/Sources/Combine/Subscribers/Subscribers.Demand.swift +476 -0
- package/Sources/Combine/Subscribers/Subscribers.Sink.swift +206 -0
- package/Sources/Combine/Subscribers/Subscribers.swift +9 -0
- package/Sources/Combine/Subscription.swift +22 -0
- package/Sources/Combine/Subscriptions.swift +42 -0
- package/Sources/Combine/SwiftUIObservation.swift +10 -0
- package/Sources/Combine/_Introspection.swift +107 -0
- package/Sources/CommonCrypto/CommonCrypto.swift +80 -0
- package/Sources/Compression/Compression.swift +365 -0
- package/Sources/Compression/Deflate.swift +407 -0
- package/Sources/Compression/Zlib.swift +179 -0
- package/Sources/CoreFoundationTypes/CoreFoundationTypes.swift +101 -0
- package/Sources/CoreGraphics/CoreGraphics.swift +411 -0
- package/Sources/CoreGraphics/ProjectionTransforms.swift +28 -0
- package/Sources/CoreHaptics/CoreHaptics.swift +399 -0
- package/Sources/CoreImage/CIColor.swift +41 -0
- package/Sources/CoreImage/CIContext.swift +31 -0
- package/Sources/CoreImage/CIDetector.swift +57 -0
- package/Sources/CoreImage/CIFilter.swift +243 -0
- package/Sources/CoreImage/CIFilterBuiltins.swift +136 -0
- package/Sources/CoreImage/CIImage.swift +162 -0
- package/Sources/CoreImage/QRCode.swift +393 -0
- package/Sources/CoreLocation/Coordinate.swift +30 -0
- package/Sources/CoreLocation/Location.swift +65 -0
- package/Sources/CoreML/Evaluation.swift +414 -0
- package/Sources/CoreML/FeatureValue.swift +266 -0
- package/Sources/CoreML/Model.swift +269 -0
- package/Sources/CoreML/MultiArray.swift +92 -0
- package/Sources/CoreML/Specification.swift +233 -0
- package/Sources/CoreText/CoreText.swift +64 -0
- package/Sources/CoreTransferable/CoreTransferable.swift +606 -0
- package/Sources/CryptoKit/ChaChaPoly.swift +258 -0
- package/Sources/CryptoKit/CryptoKit.swift +375 -0
- package/Sources/CryptoKit/Curve25519.swift +317 -0
- package/Sources/CryptoKit/P256.swift +321 -0
- package/Sources/FoundationBridge/AppStorage.swift +165 -0
- package/Sources/FoundationBridge/AssetResources.swift +90 -0
- package/Sources/FoundationBridge/AsyncBytes.swift +128 -0
- package/Sources/FoundationBridge/AsyncImage.swift +116 -0
- package/Sources/FoundationBridge/AttributedStrings.swift +16 -0
- package/Sources/FoundationBridge/Bundle.swift +119 -0
- package/Sources/FoundationBridge/CombineExports.swift +8 -0
- package/Sources/FoundationBridge/CoreFoundation.swift +77 -0
- package/Sources/FoundationBridge/Dispatch.swift +458 -0
- package/Sources/FoundationBridge/EnvironmentFoundation.swift +41 -0
- package/Sources/FoundationBridge/FileImporter.swift +128 -0
- package/Sources/FoundationBridge/FileSystem.swift +68 -0
- package/Sources/FoundationBridge/FoundationBridge.swift +29 -0
- package/Sources/FoundationBridge/HostResolution.swift +31 -0
- package/Sources/FoundationBridge/ItemProvider.swift +655 -0
- package/Sources/FoundationBridge/KeyValueObserving.swift +138 -0
- package/Sources/FoundationBridge/Links.swift +127 -0
- package/Sources/FoundationBridge/ListFormatter.swift +32 -0
- package/Sources/FoundationBridge/Locale.swift +86 -0
- package/Sources/FoundationBridge/Localization.swift +149 -0
- package/Sources/FoundationBridge/Locks.swift +50 -0
- package/Sources/FoundationBridge/Markdown.swift +527 -0
- package/Sources/FoundationBridge/MeasurementFormat.swift +95 -0
- package/Sources/FoundationBridge/NotificationCenter.swift +154 -0
- package/Sources/FoundationBridge/OpenURLHandlers.swift +60 -0
- package/Sources/FoundationBridge/Operation.swift +195 -0
- package/Sources/FoundationBridge/ProcessInfo.swift +32 -0
- package/Sources/FoundationBridge/RelativeDateTimeFormatter.swift +136 -0
- package/Sources/FoundationBridge/SceneStorage.swift +78 -0
- package/Sources/FoundationBridge/SecurityExports.swift +8 -0
- package/Sources/FoundationBridge/Selector.swift +226 -0
- package/Sources/FoundationBridge/StringComparators.swift +17 -0
- package/Sources/FoundationBridge/Table.swift +211 -0
- package/Sources/FoundationBridge/TextAttributes.swift +42 -0
- package/Sources/FoundationBridge/Timer.swift +53 -0
- package/Sources/FoundationBridge/UITextChecker.swift +30 -0
- package/Sources/FoundationBridge/URLSession.swift +718 -0
- package/Sources/FoundationBridge/UserDefaults.swift +183 -0
- package/Sources/FoundationBridge/WebAuthRedirects.swift +227 -0
- package/Sources/FoundationBridge/WebSocket.swift +187 -0
- package/Sources/FoundationModels/FoundationModels.swift +1098 -0
- package/Sources/ImageIO/GIF.swift +72 -0
- package/Sources/ImageIO/ImageIO.swift +248 -0
- package/Sources/ImageIO/ImageTypes.swift +28 -0
- package/Sources/LinkPresentation/LinkPresentation.swift +249 -0
- package/Sources/LocalAuthentication/LAContext.swift +86 -0
- package/Sources/MapKit/Geometry.swift +223 -0
- package/Sources/MapKit/Map.swift +638 -0
- package/Sources/MapKit/MapView.swift +229 -0
- package/Sources/MobileCoreServices/MobileCoreServices.swift +28 -0
- package/Sources/NaturalLanguage/LanguageIdentifier.swift +317 -0
- package/Sources/NaturalLanguage/NaturalLanguage.swift +135 -0
- package/Sources/OSLog/OSLog.swift +6 -0
- package/Sources/Photos/Photos.swift +572 -0
- package/Sources/PhotosUI/PhotosPicker.swift +248 -0
- package/Sources/PhotosUI/PhotosPickerItem.swift +261 -0
- package/Sources/QuickLook/QuickLook.swift +168 -0
- package/Sources/SafariServices/SafariServices.swift +106 -0
- package/Sources/Security/Security.swift +332 -0
- package/Sources/StoreKit/AppStore.swift +207 -0
- package/Sources/StoreKit/Products.swift +280 -0
- package/Sources/StoreKit/RequestReview.swift +28 -0
- package/Sources/StoreKit/StoreKit1.swift +486 -0
- package/Sources/StoreKit/StoreViews.swift +428 -0
- package/Sources/StoreKit/Transactions.swift +197 -0
- package/Sources/SwiftData/Macros.swift +58 -0
- package/Sources/SwiftData/ModelActor.swift +38 -0
- package/Sources/SwiftData/ModelContainer.swift +129 -0
- package/Sources/SwiftData/ModelContext.swift +451 -0
- package/Sources/SwiftData/PersistentModel.swift +238 -0
- package/Sources/SwiftData/Properties.swift +261 -0
- package/Sources/SwiftData/Query.swift +256 -0
- package/Sources/SwiftData/Schema.swift +192 -0
- package/Sources/SwiftData/Store.swift +146 -0
- package/Sources/SwiftData/StringPredicates.swift +125 -0
- package/Sources/SwiftDataMacros/EntryMacro.swift +82 -0
- package/Sources/SwiftDataMacros/GenerableMacro.swift +183 -0
- package/Sources/SwiftDataMacros/ModelActorMacro.swift +46 -0
- package/Sources/SwiftDataMacros/ModelMacro.swift +260 -0
- package/Sources/SwiftDataMacros/Plugin.swift +18 -0
- package/Sources/SwiftDataMacros/PredicateMacro.swift +1244 -0
- package/Sources/SwiftUI/API/Accessibility.swift +181 -0
- package/Sources/SwiftUI/API/AccessibilityExtras.swift +33 -0
- package/Sources/SwiftUI/API/AccessibilityFocus.swift +63 -0
- package/Sources/SwiftUI/API/Alert.swift +221 -0
- package/Sources/SwiftUI/API/AlignmentGuides.swift +65 -0
- package/Sources/SwiftUI/API/Animation.swift +285 -0
- package/Sources/SwiftUI/API/App.swift +87 -0
- package/Sources/SwiftUI/API/BindingCollections.swift +35 -0
- package/Sources/SwiftUI/API/BindingForEach.swift +27 -0
- package/Sources/SwiftUI/API/Bitmaps.swift +254 -0
- package/Sources/SwiftUI/API/ButtonStyles.swift +96 -0
- package/Sources/SwiftUI/API/Canvas.swift +337 -0
- package/Sources/SwiftUI/API/Color.swift +237 -0
- package/Sources/SwiftUI/API/ColorEffects.swift +52 -0
- package/Sources/SwiftUI/API/ColorPickerAndLabeledContent.swift +138 -0
- package/Sources/SwiftUI/API/ColorSpaces.swift +161 -0
- package/Sources/SwiftUI/API/Commands.swift +106 -0
- package/Sources/SwiftUI/API/ContainerBackground.swift +28 -0
- package/Sources/SwiftUI/API/ContentShape.swift +33 -0
- package/Sources/SwiftUI/API/ContentSizeCategory.swift +35 -0
- package/Sources/SwiftUI/API/ContentUnavailable.swift +101 -0
- package/Sources/SwiftUI/API/Controls.swift +300 -0
- package/Sources/SwiftUI/API/CustomLayout.swift +442 -0
- package/Sources/SwiftUI/API/CustomToolbarContent.swift +46 -0
- package/Sources/SwiftUI/API/Decorations.swift +92 -0
- package/Sources/SwiftUI/API/EditMode.swift +212 -0
- package/Sources/SwiftUI/API/Effects.swift +388 -0
- package/Sources/SwiftUI/API/Entry.swift +8 -0
- package/Sources/SwiftUI/API/Environment.swift +439 -0
- package/Sources/SwiftUI/API/EnvironmentSendable.swift +6 -0
- package/Sources/SwiftUI/API/Focus.swift +137 -0
- package/Sources/SwiftUI/API/Font.swift +131 -0
- package/Sources/SwiftUI/API/Gauge.swift +290 -0
- package/Sources/SwiftUI/API/Geometry.swift +89 -0
- package/Sources/SwiftUI/API/GeometryEffects.swift +232 -0
- package/Sources/SwiftUI/API/GeometryReader.swift +135 -0
- package/Sources/SwiftUI/API/GestureState.swift +65 -0
- package/Sources/SwiftUI/API/Gestures.swift +342 -0
- package/Sources/SwiftUI/API/Glass.swift +127 -0
- package/Sources/SwiftUI/API/Grid.swift +188 -0
- package/Sources/SwiftUI/API/GroupBoxAndControlGroup.swift +130 -0
- package/Sources/SwiftUI/API/KeyPress.swift +54 -0
- package/Sources/SwiftUI/API/LabelStyle.swift +124 -0
- package/Sources/SwiftUI/API/Layout.swift +220 -0
- package/Sources/SwiftUI/API/LazyStacks.swift +49 -0
- package/Sources/SwiftUI/API/LegacyAlert.swift +97 -0
- package/Sources/SwiftUI/API/Lists.swift +331 -0
- package/Sources/SwiftUI/API/Menu.swift +58 -0
- package/Sources/SwiftUI/API/Modifiers.swift +313 -0
- package/Sources/SwiftUI/API/MoreModifiers.swift +100 -0
- package/Sources/SwiftUI/API/Namespace.swift +44 -0
- package/Sources/SwiftUI/API/Navigation.swift +386 -0
- package/Sources/SwiftUI/API/NavigationDestinationBindings.swift +55 -0
- package/Sources/SwiftUI/API/ObservableObject.swift +293 -0
- package/Sources/SwiftUI/API/OnChange.swift +48 -0
- package/Sources/SwiftUI/API/Path.swift +543 -0
- package/Sources/SwiftUI/API/Phase8Controls.swift +411 -0
- package/Sources/SwiftUI/API/PhaseAnimator.swift +130 -0
- package/Sources/SwiftUI/API/Picker.swift +185 -0
- package/Sources/SwiftUI/API/PointerAndKeyboard.swift +77 -0
- package/Sources/SwiftUI/API/Popover.swift +41 -0
- package/Sources/SwiftUI/API/Preferences.swift +262 -0
- package/Sources/SwiftUI/API/Presentation.swift +122 -0
- package/Sources/SwiftUI/API/PresentationExtras.swift +60 -0
- package/Sources/SwiftUI/API/Primitives.swift +517 -0
- package/Sources/SwiftUI/API/Publishers.swift +107 -0
- package/Sources/SwiftUI/API/Redaction.swift +75 -0
- package/Sources/SwiftUI/API/RowActions.swift +84 -0
- package/Sources/SwiftUI/API/Scenes.swift +131 -0
- package/Sources/SwiftUI/API/ScrollModifiers.swift +132 -0
- package/Sources/SwiftUI/API/ScrollTargets.swift +104 -0
- package/Sources/SwiftUI/API/ScrollViewReader.swift +144 -0
- package/Sources/SwiftUI/API/SectionSupplements.swift +96 -0
- package/Sources/SwiftUI/API/Shape.swift +214 -0
- package/Sources/SwiftUI/API/ShapeStyle.swift +409 -0
- package/Sources/SwiftUI/API/ShapeTrim.swift +78 -0
- package/Sources/SwiftUI/API/Sharing.swift +193 -0
- package/Sources/SwiftUI/API/StackLayouts.swift +199 -0
- package/Sources/SwiftUI/API/State.swift +144 -0
- package/Sources/SwiftUI/API/StatusGaps.swift +121 -0
- package/Sources/SwiftUI/API/StrokeStyle.swift +30 -0
- package/Sources/SwiftUI/API/SymbolEffects.swift +203 -0
- package/Sources/SwiftUI/API/TabContent.swift +841 -0
- package/Sources/SwiftUI/API/Table.swift +382 -0
- package/Sources/SwiftUI/API/Tabs.swift +263 -0
- package/Sources/SwiftUI/API/Tasks.swift +35 -0
- package/Sources/SwiftUI/API/Text.swift +386 -0
- package/Sources/SwiftUI/API/TextDates.swift +61 -0
- package/Sources/SwiftUI/API/TextDecorations.swift +52 -0
- package/Sources/SwiftUI/API/TextFieldAxis.swift +103 -0
- package/Sources/SwiftUI/API/TextFieldCommit.swift +52 -0
- package/Sources/SwiftUI/API/Timeline.swift +212 -0
- package/Sources/SwiftUI/API/Toolbar.swift +251 -0
- package/Sources/SwiftUI/API/Transfer.swift +145 -0
- package/Sources/SwiftUI/API/UnevenRoundedRectangle.swift +66 -0
- package/Sources/SwiftUI/API/Video.swift +64 -0
- package/Sources/SwiftUI/API/View.swift +215 -0
- package/Sources/SwiftUI/API/ViewModifier.swift +43 -0
- package/Sources/SwiftUI/API/VisualEffect.swift +155 -0
- package/Sources/SwiftUI/API/Windows.swift +25 -0
- package/Sources/SwiftUI/Charts/Axis.swift +325 -0
- package/Sources/SwiftUI/Charts/AxisFormatsAndRanges.swift +68 -0
- package/Sources/SwiftUI/Charts/Chart.swift +660 -0
- package/Sources/SwiftUI/Charts/ChartContent.swift +376 -0
- package/Sources/SwiftUI/Charts/ChartProxy.swift +57 -0
- package/Sources/SwiftUI/Charts/Marks.swift +204 -0
- package/Sources/SwiftUI/Charts/Plottable.swift +99 -0
- package/Sources/SwiftUI/Charts/Scales.swift +326 -0
- package/Sources/SwiftUI/Localization/Localization.swift +498 -0
- package/Sources/SwiftUI/Localization/PluralRules.swift +127 -0
- package/Sources/SwiftUI/Runtime/Executor.swift +85 -0
- package/Sources/SwiftUI/Runtime/Exports.swift +101 -0
- package/Sources/SwiftUI/Runtime/ImageSource.swift +310 -0
- package/Sources/SwiftUI/Runtime/JSON.swift +143 -0
- package/Sources/SwiftUI/Runtime/JSONParser.swift +443 -0
- package/Sources/SwiftUI/Runtime/LazyRows.swift +99 -0
- package/Sources/SwiftUI/Runtime/Measurements.swift +140 -0
- package/Sources/SwiftUI/Runtime/Ops.swift +152 -0
- package/Sources/SwiftUI/Runtime/Reconciler.swift +219 -0
- package/Sources/SwiftUI/Runtime/Replay.swift +382 -0
- package/Sources/SwiftUI/Runtime/Runtime.swift +2146 -0
- package/Sources/SwiftUI/Runtime/Sameness.swift +152 -0
- package/Sources/SwiftUI/Runtime/ViewPath.swift +89 -0
- package/Sources/SwiftUI/Runtime/ViewTraits.swift +175 -0
- package/Sources/SwiftUI/Runtime/WebAuthHeadless.swift +49 -0
- package/Sources/Symbols/Symbols.swift +25 -0
- package/Sources/Translation/Translation.swift +423 -0
- package/Sources/UIKit/Activity.swift +213 -0
- package/Sources/UIKit/Alerts.swift +69 -0
- package/Sources/UIKit/AppDelegate.swift +222 -0
- package/Sources/UIKit/Appearance.swift +84 -0
- package/Sources/UIKit/ColorConversions.swift +70 -0
- package/Sources/UIKit/Controls.swift +225 -0
- package/Sources/UIKit/Device.swift +200 -0
- package/Sources/UIKit/Feedback.swift +65 -0
- package/Sources/UIKit/Font.swift +307 -0
- package/Sources/UIKit/Graphics.swift +204 -0
- package/Sources/UIKit/HostingController.swift +185 -0
- package/Sources/UIKit/Identity.swift +24 -0
- package/Sources/UIKit/Introspectable.swift +510 -0
- package/Sources/UIKit/Pasteboard.swift +363 -0
- package/Sources/UIKit/PhotoAlbum.swift +81 -0
- package/Sources/UIKit/RemoteNotifications.swift +15 -0
- package/Sources/UIKit/Representable.swift +288 -0
- package/Sources/UIKit/SafeArea.swift +12 -0
- package/Sources/UIKit/SceneDelegates.swift +132 -0
- package/Sources/UIKit/Scenes.swift +40 -0
- package/Sources/UIKit/ScrollView.swift +157 -0
- package/Sources/UIKit/ShortcutItems.swift +67 -0
- package/Sources/UIKit/SymbolConfiguration.swift +124 -0
- package/Sources/UIKit/TargetAction.swift +123 -0
- package/Sources/UIKit/TextPaste.swift +161 -0
- package/Sources/UIKit/TextView.swift +538 -0
- package/Sources/UIKit/UIKit.swift +292 -0
- package/Sources/UIKit/UIView.swift +855 -0
- package/Sources/UIKit/ViewTranslation.swift +311 -0
- package/Sources/UniformTypeIdentifiers/UTType.swift +196 -0
- package/Sources/UserNotifications/Content.swift +370 -0
- package/Sources/UserNotifications/NotificationCenter.swift +309 -0
- package/Sources/WeatherKit/WeatherKit.swift +228 -0
- package/Sources/WebKit/WebKit.swift +245 -0
- package/Sources/os/os.swift +376 -0
- package/Sources/zlib/zlib.swift +6 -0
- package/index.d.ts +2 -0
- package/index.mjs +16 -0
- package/manifest.d.mts +2 -0
- package/manifest.mjs +39 -0
- package/package.json +30 -4
- package/sync-sources.mjs +33 -0
|
@@ -0,0 +1,1244 @@
|
|
|
1
|
+
// Vendored from swift-foundation (Sources/FoundationMacros/PredicateMacro.swift,
|
|
2
|
+
// tag swift-6.4.x-DEVELOPMENT-SNAPSHOT-2026-09-26-a), Apache License v2.0 with
|
|
3
|
+
// Runtime Library Exception; see https://swift.org/LICENSE.txt.
|
|
4
|
+
//
|
|
5
|
+
// SwiftBrowser's changes, so that `#Predicate` accepts what it does on Apple
|
|
6
|
+
// platforms: `localizedStandardContains`, `localizedCompare` and
|
|
7
|
+
// `caseInsensitiveCompare` are listed as supported functions (the open-source
|
|
8
|
+
// build lists them only for Apple's Foundation, `FOUNDATION_FRAMEWORK`, whose
|
|
9
|
+
// expressions corelibs Foundation lacks), and their `build_` functions are
|
|
10
|
+
// SwiftData's (Sources/SwiftData/StringPredicates.swift). Apps that import SwiftData
|
|
11
|
+
// get this macro in place of Foundation's through a declaration the CLI
|
|
12
|
+
// generates in the app module (docs/ops-protocol.md, "Phase 18").
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
import SwiftSyntax
|
|
16
|
+
import SwiftSyntaxMacros
|
|
17
|
+
import SwiftDiagnostics
|
|
18
|
+
import SwiftSyntaxBuilder
|
|
19
|
+
|
|
20
|
+
// A list of all functions supported by Predicate/Expression itself, any other functions called will be diagnosed as an error
|
|
21
|
+
// This allows for checking the function name, the number of arguments, and the argument labels, but the types of the arguments will need to be validated by the post-expansion type checking pass
|
|
22
|
+
// The closure specification is used to determine whether keypaths should be transformed/expanded into closures and whether dropping the final argument in favor of a trailing closure is allowed
|
|
23
|
+
private let _knownSupportedFunctions: Set<FunctionStructure> = [
|
|
24
|
+
FunctionStructure("contains", arguments: [.unlabeled]),
|
|
25
|
+
FunctionStructure("contains", arguments: [.closure(labeled: "where")]),
|
|
26
|
+
FunctionStructure("allSatisfy", arguments: [.closure(labeled: nil)]),
|
|
27
|
+
FunctionStructure("flatMap", arguments: [.closure(labeled: nil)]),
|
|
28
|
+
FunctionStructure("filter", arguments: [.closure(labeled: nil)]),
|
|
29
|
+
FunctionStructure("subscript", arguments: [.unlabeled]),
|
|
30
|
+
FunctionStructure("subscript", arguments: [.unlabeled, "default"]),
|
|
31
|
+
FunctionStructure("starts", arguments: ["with"]),
|
|
32
|
+
FunctionStructure("min", arguments: []),
|
|
33
|
+
FunctionStructure("max", arguments: []),
|
|
34
|
+
]
|
|
35
|
+
|
|
36
|
+
private var knownSupportedFunctions: Set<FunctionStructure> {
|
|
37
|
+
var result = _knownSupportedFunctions
|
|
38
|
+
result.insert(FunctionStructure("localizedStandardContains", arguments: [.unlabeled]))
|
|
39
|
+
result.insert(FunctionStructure("localizedCompare", arguments: [.unlabeled]))
|
|
40
|
+
result.insert(FunctionStructure("caseInsensitiveCompare", arguments: [.unlabeled]))
|
|
41
|
+
return result
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/// The functions whose `build_` SwiftData supplies (Sources/SwiftData/StringPredicates.swift).
|
|
45
|
+
private let swiftDataFunctions: Set<String> = ["localizedStandardContains", "localizedCompare", "caseInsensitiveCompare"]
|
|
46
|
+
|
|
47
|
+
private let _supportedFunctionSuggestions: [FunctionStructure : FunctionStructure] = [
|
|
48
|
+
FunctionStructure("hasPrefix", arguments: [.unlabeled]) : FunctionStructure("starts", arguments: ["with"]),
|
|
49
|
+
]
|
|
50
|
+
|
|
51
|
+
private var supportedFunctionSuggestions: [FunctionStructure : FunctionStructure] {
|
|
52
|
+
var result = _supportedFunctionSuggestions
|
|
53
|
+
result[FunctionStructure("localizedCaseInsensitiveContains", arguments: [.unlabeled])] = FunctionStructure("localizedStandardContains", arguments: [.unlabeled])
|
|
54
|
+
result[FunctionStructure("localizedCaseInsensitiveCompare", arguments: [.unlabeled])] = FunctionStructure("localizedCompare", arguments: [.unlabeled])
|
|
55
|
+
result[FunctionStructure("localizedStandardCompare", arguments: [.unlabeled])] = FunctionStructure("localizedCompare", arguments: [.unlabeled])
|
|
56
|
+
return result
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
extension Array where Element == FunctionStructure.Argument {
|
|
60
|
+
fileprivate func argumentsEqual(_ other: Self) -> Bool {
|
|
61
|
+
let currentPackIndex = self.firstIndex { $0.kind == .pack }
|
|
62
|
+
let otherPackIndex = other.firstIndex { $0.kind == .pack }
|
|
63
|
+
|
|
64
|
+
var full: [FunctionStructure.Argument]
|
|
65
|
+
var prefix: ArraySlice<FunctionStructure.Argument>
|
|
66
|
+
var suffix: ArraySlice<FunctionStructure.Argument>
|
|
67
|
+
switch (currentPackIndex, otherPackIndex) {
|
|
68
|
+
// If neither contains a pack or both contain a pack, just compare arguments as-is
|
|
69
|
+
case (nil, nil), (.some(_), .some(_)):
|
|
70
|
+
return self == other
|
|
71
|
+
|
|
72
|
+
// If one of them contains a pack, compare the prefix and suffix to allow the pack to lazily consume multiple arguments
|
|
73
|
+
case (let .some(idx), nil):
|
|
74
|
+
full = other
|
|
75
|
+
prefix = self[..<idx]
|
|
76
|
+
suffix = self[self.index(after: idx)...]
|
|
77
|
+
case (nil, let .some(idx)):
|
|
78
|
+
full = self
|
|
79
|
+
prefix = other[..<idx]
|
|
80
|
+
suffix = other[other.index(after: idx)...]
|
|
81
|
+
}
|
|
82
|
+
return full.starts(with: prefix) && full.reversed().starts(with: suffix.reversed())
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
fileprivate func expandingPackToMatchCount(_ otherCount: Int) -> Self {
|
|
86
|
+
let countDifference = otherCount - self.count
|
|
87
|
+
guard countDifference >= 0, let packIdx = self.firstIndex(where: { $0.kind == .pack }) else {
|
|
88
|
+
return self
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
var copy = self
|
|
92
|
+
copy[packIdx] = .init(label: copy[packIdx].label, kind: .standard)
|
|
93
|
+
if countDifference > 0 {
|
|
94
|
+
copy.insert(contentsOf: Array(repeating: .unlabeled, count: countDifference), at: packIdx + 1)
|
|
95
|
+
}
|
|
96
|
+
return copy
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
private struct FunctionStructure: Hashable {
|
|
101
|
+
struct Argument : Hashable, ExpressibleByStringLiteral {
|
|
102
|
+
enum Kind : Hashable {
|
|
103
|
+
case standard
|
|
104
|
+
case closure
|
|
105
|
+
case pack
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
let label: String?
|
|
109
|
+
let kind: Kind
|
|
110
|
+
|
|
111
|
+
init(stringLiteral: String) {
|
|
112
|
+
label = stringLiteral
|
|
113
|
+
kind = .standard
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
init(label: String?, kind: Kind) {
|
|
117
|
+
self.label = label
|
|
118
|
+
self.kind = kind
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
static func closure(labeled label: String?) -> Self {
|
|
122
|
+
Self(label: label, kind: .closure)
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
static var unlabeled: Self {
|
|
126
|
+
Self(label: nil, kind: .standard)
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
static func pack(labeled label: String?) -> Self {
|
|
130
|
+
Self(label: label, kind: .pack)
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
static func ==(lhs: Self, rhs: Self) -> Bool {
|
|
134
|
+
lhs.label == rhs.label
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
let name: String
|
|
138
|
+
let arguments: [Argument]
|
|
139
|
+
let hasTrailingClosure: Bool
|
|
140
|
+
|
|
141
|
+
var supportsTrailingClosure: Bool {
|
|
142
|
+
hasTrailingClosure || arguments.last?.kind == .closure
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
var signature: String {
|
|
146
|
+
let args = arguments.map { ($0.label ?? "_") + ":" }.joined()
|
|
147
|
+
return "\(name)(\(args))"
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
init(_ name: String, arguments: [Argument], trailingClosure: Bool = false) {
|
|
151
|
+
self.name = name
|
|
152
|
+
self.arguments = arguments
|
|
153
|
+
self.hasTrailingClosure = trailingClosure
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
func matches(_ other: FunctionStructure) -> Bool {
|
|
157
|
+
guard self.name == other.name else { return false }
|
|
158
|
+
|
|
159
|
+
switch (self.hasTrailingClosure, other.hasTrailingClosure) {
|
|
160
|
+
case (true, true), (false, false):
|
|
161
|
+
return self.arguments.argumentsEqual(other.arguments)
|
|
162
|
+
case (true, false):
|
|
163
|
+
guard let otherLast = other.arguments.last else { return false }
|
|
164
|
+
return self.arguments.argumentsEqual(other.arguments.dropLast()) && otherLast.kind == .closure
|
|
165
|
+
case (false, true):
|
|
166
|
+
guard let last = self.arguments.last else { return false }
|
|
167
|
+
return self.arguments.dropLast().argumentsEqual(other.arguments) && last.kind == .closure
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
func fixItChanges(transformingFrom source: FunctionCallExprSyntax) -> [FixIt.Change]? {
|
|
172
|
+
let sourceHasTrailingClosure = source.trailingClosure != nil
|
|
173
|
+
if sourceHasTrailingClosure {
|
|
174
|
+
guard supportsTrailingClosure else { return nil }
|
|
175
|
+
}
|
|
176
|
+
let sourceArgumentTotalCount = source.arguments.count + (sourceHasTrailingClosure ? 1 : 0)
|
|
177
|
+
let argumentTotalCount = self.arguments.count + (hasTrailingClosure ? 1 : 0)
|
|
178
|
+
guard argumentTotalCount == sourceArgumentTotalCount,
|
|
179
|
+
let calledExpr = source.calledExpression.as(MemberAccessExprSyntax.self) else {
|
|
180
|
+
return nil
|
|
181
|
+
}
|
|
182
|
+
var newFunctionCall = source
|
|
183
|
+
newFunctionCall.calledExpression = ExprSyntax(calledExpr.with(\.declName, DeclReferenceExprSyntax(baseName: .identifier(name))))
|
|
184
|
+
newFunctionCall.arguments = LabeledExprListSyntax(zip(source.arguments, arguments).map {
|
|
185
|
+
if let newLabel = $1.label {
|
|
186
|
+
return $0.with(\.label, .identifier(newLabel)).with(\.colon, .colonToken()).with(\.expression, $0.expression.with(\.leadingTrivia, [.spaces(1)]))
|
|
187
|
+
} else {
|
|
188
|
+
return $0.with(\.label, nil).with(\.colon, nil).with(\.trailingTrivia, []).with(\.expression, $0.expression.with(\.leadingTrivia, []))
|
|
189
|
+
}
|
|
190
|
+
})
|
|
191
|
+
newFunctionCall.leadingTrivia = []
|
|
192
|
+
newFunctionCall.trailingTrivia = []
|
|
193
|
+
if self.hasTrailingClosure && source.trailingClosure == nil, let newTrailingClosure = source.arguments.last?.expression.as(ClosureExprSyntax.self) {
|
|
194
|
+
newFunctionCall.trailingClosure = newTrailingClosure
|
|
195
|
+
}
|
|
196
|
+
return [.replace(oldNode: Syntax(source), newNode: Syntax(newFunctionCall))]
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
private func _knownMatchingFunction(_ structure: FunctionStructure) -> FunctionStructure? {
|
|
201
|
+
knownSupportedFunctions.first {
|
|
202
|
+
$0.matches(structure)
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
private func _suggestionForUnknownFunction(_ structure: FunctionStructure) -> FunctionStructure? {
|
|
207
|
+
guard let key = supportedFunctionSuggestions.keys.first(where: { $0.matches(structure) }) else {
|
|
208
|
+
return nil
|
|
209
|
+
}
|
|
210
|
+
return supportedFunctionSuggestions[key]
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
private class ShorthandArgumentIdentifierDetector: SyntaxVisitor {
|
|
214
|
+
var found = false
|
|
215
|
+
|
|
216
|
+
override func visit(_ node: DeclReferenceExprSyntax) -> SyntaxVisitorContinueKind {
|
|
217
|
+
// Look for identifiers such as $0, $1, etc.
|
|
218
|
+
if case let .dollarIdentifier(identifier) = node.baseName.tokenKind, identifier.dropFirst().allSatisfy(\.isNumber) {
|
|
219
|
+
found = true
|
|
220
|
+
return .skipChildren
|
|
221
|
+
} else {
|
|
222
|
+
return .visitChildren
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
extension SyntaxProtocol {
|
|
228
|
+
var containsShorthandArgumentIdentifiers: Bool {
|
|
229
|
+
let visitor = ShorthandArgumentIdentifierDetector(viewMode: .all)
|
|
230
|
+
visitor.walk(self)
|
|
231
|
+
return visitor.found
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
private protocol PredicateSyntaxRewriter : SyntaxRewriter {
|
|
236
|
+
var success: Bool { get }
|
|
237
|
+
var ignorable: Bool { get }
|
|
238
|
+
var diagnostics: [Diagnostic] { get }
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
extension PredicateSyntaxRewriter {
|
|
242
|
+
var success: Bool { true }
|
|
243
|
+
var ignorable: Bool { false }
|
|
244
|
+
var diagnostics: [Diagnostic] { [] }
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
extension SyntaxProtocol {
|
|
248
|
+
fileprivate func rewrite(with rewriter: some PredicateSyntaxRewriter) throws -> Syntax {
|
|
249
|
+
let translated = rewriter.rewrite(self)
|
|
250
|
+
guard rewriter.success else {
|
|
251
|
+
throw DiagnosticsError(diagnostics: rewriter.diagnostics)
|
|
252
|
+
}
|
|
253
|
+
guard !rewriter.ignorable else {
|
|
254
|
+
return Syntax(self)
|
|
255
|
+
}
|
|
256
|
+
return translated
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
private class OptionalChainRewriter: SyntaxRewriter, PredicateSyntaxRewriter {
|
|
261
|
+
var withinValidChainingTreeStart = true
|
|
262
|
+
var withinChainingTree = false
|
|
263
|
+
var optionalInput: ExprSyntax? = nil
|
|
264
|
+
var ignorable = true
|
|
265
|
+
|
|
266
|
+
private func _prePossibleTopOfTree() -> Bool {
|
|
267
|
+
if !withinChainingTree && withinValidChainingTreeStart {
|
|
268
|
+
withinChainingTree = true
|
|
269
|
+
return true
|
|
270
|
+
}
|
|
271
|
+
return false
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
private func _postTopOfTree(_ node: ExprSyntax) -> ExprSyntax {
|
|
275
|
+
assert(withinChainingTree)
|
|
276
|
+
withinChainingTree = false
|
|
277
|
+
if let input = optionalInput {
|
|
278
|
+
optionalInput = nil
|
|
279
|
+
ignorable = false
|
|
280
|
+
let visited = self.visit(input)
|
|
281
|
+
let closure = ClosureExprSyntax(statements: [CodeBlockItemSyntax(item: CodeBlockItemSyntax.Item(node))])
|
|
282
|
+
let functionMember = MemberAccessExprSyntax(base: visited, name: "flatMap")
|
|
283
|
+
let functionCall = FunctionCallExprSyntax(calledExpression: functionMember, leftParen: .leftParenToken(), arguments: [], rightParen: .rightParenToken(), trailingClosure: closure)
|
|
284
|
+
return ExprSyntax(functionCall)
|
|
285
|
+
}
|
|
286
|
+
return node
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
override func visit(_ node: ClosureExprSyntax) -> ExprSyntax {
|
|
290
|
+
guard withinChainingTree else {
|
|
291
|
+
// If we're not already in a chaining tree, just keep progressing with our current rewriter
|
|
292
|
+
return super.visit(node)
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
// We're in the middle of a potential tree, so rewrite the closure with a fresh state
|
|
296
|
+
// This ensures potential chaining in the closure isn't rewritten outside of the closure
|
|
297
|
+
let nestedRewriter = OptionalChainRewriter()
|
|
298
|
+
guard let rewritten = (try? node.rewrite(with: nestedRewriter))?.as(ExprSyntax.self) else {
|
|
299
|
+
// If rewriting the closure failed, just leave the closure as-is
|
|
300
|
+
return ExprSyntax(node)
|
|
301
|
+
}
|
|
302
|
+
if ignorable {
|
|
303
|
+
ignorable = nestedRewriter.ignorable
|
|
304
|
+
}
|
|
305
|
+
return rewritten
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
override func visit(_ node: FunctionCallExprSyntax) -> ExprSyntax {
|
|
309
|
+
let priorValidTreeStart = withinValidChainingTreeStart
|
|
310
|
+
defer { withinValidChainingTreeStart = priorValidTreeStart }
|
|
311
|
+
|
|
312
|
+
if node.arguments.containsShorthandArgumentIdentifiers {
|
|
313
|
+
withinValidChainingTreeStart = false
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
let topOfTree = _prePossibleTopOfTree()
|
|
317
|
+
let visited = super.visit(node)
|
|
318
|
+
if topOfTree {
|
|
319
|
+
return _postTopOfTree(visited)
|
|
320
|
+
} else {
|
|
321
|
+
return visited
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
override func visit(_ node: MemberAccessExprSyntax) -> ExprSyntax {
|
|
326
|
+
let topOfTree = _prePossibleTopOfTree()
|
|
327
|
+
let visited = super.visit(node)
|
|
328
|
+
if topOfTree {
|
|
329
|
+
return _postTopOfTree(visited)
|
|
330
|
+
} else {
|
|
331
|
+
return visited
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
override func visit(_ node: OptionalChainingExprSyntax) -> ExprSyntax {
|
|
336
|
+
guard withinChainingTree else {
|
|
337
|
+
return super.visit(node)
|
|
338
|
+
}
|
|
339
|
+
// Capture the optional input, and replace it in the output expression with a "$0"
|
|
340
|
+
optionalInput = node.expression
|
|
341
|
+
return .init(DeclReferenceExprSyntax(baseName: .dollarIdentifier("$0")))
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
extension CodeBlockItemListSyntax.Element.Item {
|
|
346
|
+
fileprivate var _expression: ExprSyntax? {
|
|
347
|
+
switch self {
|
|
348
|
+
case .expr(let expr): return expr
|
|
349
|
+
case .stmt(let stmt): return stmt.as(ExpressionStmtSyntax.self)?.expression
|
|
350
|
+
default: return nil
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
extension ConditionElementListSyntax {
|
|
356
|
+
fileprivate var optionalBindings: [OptionalBindingConditionSyntax]? {
|
|
357
|
+
var result = [OptionalBindingConditionSyntax]()
|
|
358
|
+
for element in self {
|
|
359
|
+
switch element.condition {
|
|
360
|
+
case let .optionalBinding(binding):
|
|
361
|
+
result.append(binding)
|
|
362
|
+
default:
|
|
363
|
+
return nil
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
return result
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
extension ClosureParameterListSyntax {
|
|
371
|
+
fileprivate var withVariableWrappedTypes: Self {
|
|
372
|
+
return Self(self.map {
|
|
373
|
+
if let type = $0.type {
|
|
374
|
+
$0.with(\.type, "PredicateExpressions.\(raw: moduleName())::Variable<\(type)>")
|
|
375
|
+
} else {
|
|
376
|
+
$0
|
|
377
|
+
}
|
|
378
|
+
})
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
extension KeyPathExprSyntax {
|
|
383
|
+
private enum KeyPathDirectExpressionRewritingError : Error {
|
|
384
|
+
case unknownKeypathComponentType
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
fileprivate func asDirectExpression(on base: some ExprSyntaxProtocol) -> ExprSyntax? {
|
|
388
|
+
var result = ExprSyntax(base)
|
|
389
|
+
for item in components {
|
|
390
|
+
switch item.component {
|
|
391
|
+
case .property(let prop):
|
|
392
|
+
result = ExprSyntax(MemberAccessExprSyntax(base: result, declName: prop.declName))
|
|
393
|
+
case .optional(let opt):
|
|
394
|
+
if opt.questionOrExclamationMark.tokenKind == .exclamationMark {
|
|
395
|
+
result = ExprSyntax(ForceUnwrapExprSyntax(expression: result))
|
|
396
|
+
} else {
|
|
397
|
+
result = ExprSyntax(OptionalChainingExprSyntax(expression: result))
|
|
398
|
+
}
|
|
399
|
+
case .subscript(let sub):
|
|
400
|
+
result = ExprSyntax(SubscriptCallExprSyntax(calledExpression: result, arguments: sub.arguments))
|
|
401
|
+
@unknown default:
|
|
402
|
+
return nil
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
return result
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
private class PredicateQueryRewriter: SyntaxRewriter, PredicateSyntaxRewriter {
|
|
410
|
+
private let indentWidth: Trivia = .spaces(4)
|
|
411
|
+
private var indentLevel = 0
|
|
412
|
+
private var indent: Trivia {
|
|
413
|
+
Trivia(pieces: Array(repeating: .spaces(4), count: indentLevel))
|
|
414
|
+
}
|
|
415
|
+
var validOptionalChainingTree = true
|
|
416
|
+
var diagnostics: [Diagnostic] = []
|
|
417
|
+
var success: Bool { diagnostics.isEmpty }
|
|
418
|
+
let kind: ExpansionKind
|
|
419
|
+
|
|
420
|
+
init(kind: ExpansionKind) {
|
|
421
|
+
self.kind = kind
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
private func diagnose(node: SyntaxProtocol, message: PredicateExpansionDiagnostic, fixIts: [FixIt] = []) {
|
|
425
|
+
diagnostics.append(.init(node: Syntax(node), message: message, fixIts: fixIts))
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
private func makeArgument(label: String?, _ expression: ExprSyntax, shouldVisit: Bool = true, shouldIndent: Bool = true) -> LabeledExprSyntax {
|
|
429
|
+
if shouldIndent {
|
|
430
|
+
indentLevel += 1
|
|
431
|
+
}
|
|
432
|
+
defer {
|
|
433
|
+
if shouldIndent {
|
|
434
|
+
indentLevel -= 1
|
|
435
|
+
}
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
let labelSyntax = label.map {
|
|
439
|
+
TokenSyntax(.identifier($0), presence: .present)
|
|
440
|
+
}?.with(\.leadingTrivia, indent)
|
|
441
|
+
|
|
442
|
+
let colonSyntax = label.map { _ in
|
|
443
|
+
TokenSyntax(.colon, presence: .present)
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
var argument = shouldVisit ? visit(expression) : expression
|
|
447
|
+
|
|
448
|
+
if shouldVisit && argument == expression {
|
|
449
|
+
argument = "PredicateExpressions.\(raw: moduleName())::build_Arg(\(expression.with(\.leadingTrivia, []).with(\.trailingTrivia, [])))"
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
argument = argument.with(\.leadingTrivia, label == nil ? indent : .space)
|
|
453
|
+
return .init(label: labelSyntax,
|
|
454
|
+
colon: colonSyntax,
|
|
455
|
+
expression: argument,
|
|
456
|
+
trailingComma: nil)
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
override func visit(_ node: PrefixOperatorExprSyntax) -> ExprSyntax {
|
|
460
|
+
switch node.operator.text {
|
|
461
|
+
case "!":
|
|
462
|
+
let syntax: ExprSyntax =
|
|
463
|
+
"""
|
|
464
|
+
\(raw: indent)PredicateExpressions.\(raw: moduleName())::build_Negation(
|
|
465
|
+
\(makeArgument(label: nil, node.expression))
|
|
466
|
+
\(raw: indent))
|
|
467
|
+
"""
|
|
468
|
+
|
|
469
|
+
return syntax
|
|
470
|
+
case "-":
|
|
471
|
+
let syntax: ExprSyntax =
|
|
472
|
+
"""
|
|
473
|
+
\(raw: indent)PredicateExpressions.\(raw: moduleName())::build_UnaryMinus(
|
|
474
|
+
\(makeArgument(label: nil, node.expression))
|
|
475
|
+
\(raw: indent))
|
|
476
|
+
"""
|
|
477
|
+
|
|
478
|
+
return syntax
|
|
479
|
+
default:
|
|
480
|
+
diagnose(node: node.operator, message: "The '\(node.operator.text)' operator is not supported in this \(kind.keyword)")
|
|
481
|
+
return ExprSyntax(node)
|
|
482
|
+
}
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
override func visit(_ node: InfixOperatorExprSyntax) -> ExprSyntax {
|
|
486
|
+
let lhsOp = node.leftOperand
|
|
487
|
+
let rhsOp = node.rightOperand
|
|
488
|
+
let opExpr = node.operator
|
|
489
|
+
|
|
490
|
+
guard let opSyntax = opExpr.as(BinaryOperatorExprSyntax.self) else {
|
|
491
|
+
diagnose(node: opExpr, message: "The '\(opExpr.description)' operator is not supported in this \(kind.keyword)")
|
|
492
|
+
return ExprSyntax(node)
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
let (lhsLabel, rhsLabel) = switch opSyntax.operator.text {
|
|
496
|
+
case "...", "..<": ("lower", "upper")
|
|
497
|
+
default: ("lhs", "rhs")
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
let lhsArgument = makeArgument(label: lhsLabel, lhsOp).with(\.trailingTrivia, [])
|
|
501
|
+
let rhsArgument = makeArgument(label: rhsLabel, rhsOp).with(\.trailingTrivia, [])
|
|
502
|
+
|
|
503
|
+
switch (opSyntax.operator.text) {
|
|
504
|
+
case "==":
|
|
505
|
+
let syntax: ExprSyntax =
|
|
506
|
+
"""
|
|
507
|
+
\(raw: indent)PredicateExpressions.\(raw: moduleName())::build_Equal(
|
|
508
|
+
\(lhsArgument),
|
|
509
|
+
\(rhsArgument)
|
|
510
|
+
\(raw: indent))
|
|
511
|
+
"""
|
|
512
|
+
|
|
513
|
+
return syntax
|
|
514
|
+
case "!=":
|
|
515
|
+
let syntax: ExprSyntax =
|
|
516
|
+
"""
|
|
517
|
+
\(raw: indent)PredicateExpressions.\(raw: moduleName())::build_NotEqual(
|
|
518
|
+
\(lhsArgument),
|
|
519
|
+
\(rhsArgument)
|
|
520
|
+
\(raw: indent))
|
|
521
|
+
"""
|
|
522
|
+
|
|
523
|
+
return syntax
|
|
524
|
+
case "<":
|
|
525
|
+
let syntax: ExprSyntax =
|
|
526
|
+
"""
|
|
527
|
+
\(raw: indent)PredicateExpressions.\(raw: moduleName())::build_Comparison(
|
|
528
|
+
\(lhsArgument),
|
|
529
|
+
\(rhsArgument),
|
|
530
|
+
\(raw: indent + indentWidth)op: .lessThan
|
|
531
|
+
\(raw: indent))
|
|
532
|
+
"""
|
|
533
|
+
|
|
534
|
+
return syntax
|
|
535
|
+
case "<=":
|
|
536
|
+
let syntax: ExprSyntax =
|
|
537
|
+
"""
|
|
538
|
+
\(raw: indent)PredicateExpressions.\(raw: moduleName())::build_Comparison(
|
|
539
|
+
\(lhsArgument),
|
|
540
|
+
\(rhsArgument),
|
|
541
|
+
\(raw: indent + indentWidth)op: .lessThanOrEqual
|
|
542
|
+
\(raw: indent))
|
|
543
|
+
"""
|
|
544
|
+
|
|
545
|
+
return syntax
|
|
546
|
+
case ">":
|
|
547
|
+
let syntax: ExprSyntax =
|
|
548
|
+
"""
|
|
549
|
+
\(raw: indent)PredicateExpressions.\(raw: moduleName())::build_Comparison(
|
|
550
|
+
\(lhsArgument),
|
|
551
|
+
\(rhsArgument),
|
|
552
|
+
\(raw: indent + indentWidth)op: .greaterThan
|
|
553
|
+
\(raw: indent))
|
|
554
|
+
"""
|
|
555
|
+
|
|
556
|
+
return syntax
|
|
557
|
+
case ">=":
|
|
558
|
+
let syntax: ExprSyntax =
|
|
559
|
+
"""
|
|
560
|
+
\(raw: indent)PredicateExpressions.\(raw: moduleName())::build_Comparison(
|
|
561
|
+
\(lhsArgument),
|
|
562
|
+
\(rhsArgument),
|
|
563
|
+
\(raw: indent + indentWidth)op: .greaterThanOrEqual
|
|
564
|
+
\(raw: indent))
|
|
565
|
+
"""
|
|
566
|
+
|
|
567
|
+
return syntax
|
|
568
|
+
case "||":
|
|
569
|
+
let syntax: ExprSyntax =
|
|
570
|
+
"""
|
|
571
|
+
\(raw: indent)PredicateExpressions.\(raw: moduleName())::build_Disjunction(
|
|
572
|
+
\(lhsArgument),
|
|
573
|
+
\(rhsArgument)
|
|
574
|
+
\(raw: indent))
|
|
575
|
+
"""
|
|
576
|
+
|
|
577
|
+
return syntax
|
|
578
|
+
case "&&":
|
|
579
|
+
let syntax: ExprSyntax =
|
|
580
|
+
"""
|
|
581
|
+
\(raw: indent)PredicateExpressions.\(raw: moduleName())::build_Conjunction(
|
|
582
|
+
\(lhsArgument),
|
|
583
|
+
\(rhsArgument)
|
|
584
|
+
\(raw: indent))
|
|
585
|
+
"""
|
|
586
|
+
|
|
587
|
+
return syntax
|
|
588
|
+
case "+":
|
|
589
|
+
let syntax: ExprSyntax =
|
|
590
|
+
"""
|
|
591
|
+
\(raw: indent)PredicateExpressions.\(raw: moduleName())::build_Arithmetic(
|
|
592
|
+
\(lhsArgument),
|
|
593
|
+
\(rhsArgument),
|
|
594
|
+
\(raw: indent + indentWidth)op: .add
|
|
595
|
+
\(raw: indent))
|
|
596
|
+
"""
|
|
597
|
+
|
|
598
|
+
return syntax
|
|
599
|
+
case "-":
|
|
600
|
+
let syntax: ExprSyntax =
|
|
601
|
+
"""
|
|
602
|
+
\(raw: indent)PredicateExpressions.\(raw: moduleName())::build_Arithmetic(
|
|
603
|
+
\(lhsArgument),
|
|
604
|
+
\(rhsArgument),
|
|
605
|
+
\(raw: indent + indentWidth)op: .subtract
|
|
606
|
+
\(raw: indent))
|
|
607
|
+
"""
|
|
608
|
+
|
|
609
|
+
return syntax
|
|
610
|
+
case "*":
|
|
611
|
+
let syntax: ExprSyntax =
|
|
612
|
+
"""
|
|
613
|
+
\(raw: indent)PredicateExpressions.\(raw: moduleName())::build_Arithmetic(
|
|
614
|
+
\(lhsArgument),
|
|
615
|
+
\(rhsArgument),
|
|
616
|
+
\(raw: indent + indentWidth)op: .multiply
|
|
617
|
+
\(raw: indent))
|
|
618
|
+
"""
|
|
619
|
+
|
|
620
|
+
return syntax
|
|
621
|
+
case "/":
|
|
622
|
+
let syntax: ExprSyntax =
|
|
623
|
+
"""
|
|
624
|
+
\(raw: indent)PredicateExpressions.\(raw: moduleName())::build_Division(
|
|
625
|
+
\(lhsArgument),
|
|
626
|
+
\(rhsArgument)
|
|
627
|
+
\(raw: indent))
|
|
628
|
+
"""
|
|
629
|
+
|
|
630
|
+
return syntax
|
|
631
|
+
case "%":
|
|
632
|
+
let syntax: ExprSyntax =
|
|
633
|
+
"""
|
|
634
|
+
\(raw: indent)PredicateExpressions.\(raw: moduleName())::build_Remainder(
|
|
635
|
+
\(lhsArgument),
|
|
636
|
+
\(rhsArgument)
|
|
637
|
+
\(raw: indent))
|
|
638
|
+
"""
|
|
639
|
+
|
|
640
|
+
return syntax
|
|
641
|
+
case "??":
|
|
642
|
+
let syntax: ExprSyntax =
|
|
643
|
+
"""
|
|
644
|
+
\(raw: indent)PredicateExpressions.\(raw: moduleName())::build_NilCoalesce(
|
|
645
|
+
\(lhsArgument),
|
|
646
|
+
\(rhsArgument)
|
|
647
|
+
\(raw: indent))
|
|
648
|
+
"""
|
|
649
|
+
|
|
650
|
+
return syntax
|
|
651
|
+
|
|
652
|
+
case "...":
|
|
653
|
+
let syntax: ExprSyntax =
|
|
654
|
+
"""
|
|
655
|
+
\(raw: indent)PredicateExpressions.\(raw: moduleName())::build_ClosedRange(
|
|
656
|
+
\(lhsArgument),
|
|
657
|
+
\(rhsArgument)
|
|
658
|
+
\(raw: indent))
|
|
659
|
+
"""
|
|
660
|
+
|
|
661
|
+
return syntax
|
|
662
|
+
|
|
663
|
+
case "..<":
|
|
664
|
+
let syntax: ExprSyntax =
|
|
665
|
+
"""
|
|
666
|
+
\(raw: indent)PredicateExpressions.\(raw: moduleName())::build_Range(
|
|
667
|
+
\(lhsArgument),
|
|
668
|
+
\(rhsArgument)
|
|
669
|
+
\(raw: indent))
|
|
670
|
+
"""
|
|
671
|
+
|
|
672
|
+
return syntax
|
|
673
|
+
default:
|
|
674
|
+
diagnose(node: opSyntax, message: "The '\(opSyntax.operator.text)' operator is not supported in this \(kind.keyword)")
|
|
675
|
+
return ExprSyntax(node)
|
|
676
|
+
}
|
|
677
|
+
}
|
|
678
|
+
|
|
679
|
+
// We only hit this if our OptionalChainingRewriter was unable to rewrite them out of the expression tree
|
|
680
|
+
override func visit(_ node: OptionalChainingExprSyntax) -> ExprSyntax {
|
|
681
|
+
diagnose(node: node.questionMark, message: "Optional chaining is not supported here in this \(kind.keyword). Use the flatMap(_:) function explicitly instead.")
|
|
682
|
+
return .init(node)
|
|
683
|
+
}
|
|
684
|
+
|
|
685
|
+
override func visit(_ node: ForceUnwrapExprSyntax) -> ExprSyntax {
|
|
686
|
+
return """
|
|
687
|
+
\(raw: indent)PredicateExpressions.\(raw: moduleName())::build_ForcedUnwrap(
|
|
688
|
+
\(makeArgument(label: nil, node.expression))
|
|
689
|
+
\(raw: indent))
|
|
690
|
+
"""
|
|
691
|
+
}
|
|
692
|
+
|
|
693
|
+
override func visit(_ node: NilLiteralExprSyntax) -> ExprSyntax {
|
|
694
|
+
"PredicateExpressions.\(raw: moduleName())::build_NilLiteral()"
|
|
695
|
+
}
|
|
696
|
+
|
|
697
|
+
override func visit(_ node: MemberAccessExprSyntax) -> ExprSyntax {
|
|
698
|
+
guard let base = node.base else {
|
|
699
|
+
diagnose(node: node, message: "Member access without an explicit base is not supported in this \(kind.keyword)")
|
|
700
|
+
return .init(node)
|
|
701
|
+
}
|
|
702
|
+
|
|
703
|
+
let newPropertyComponent = KeyPathPropertyComponentSyntax(declName: node.declName)
|
|
704
|
+
let keyPath = KeyPathExprSyntax(components: [.init(period: TokenSyntax.periodToken(), component: .property(newPropertyComponent))])
|
|
705
|
+
return """
|
|
706
|
+
\(raw: indent)PredicateExpressions.\(raw: moduleName())::build_KeyPath(
|
|
707
|
+
\(makeArgument(label: "root", base)),
|
|
708
|
+
\(makeArgument(label: "keyPath", .init(keyPath), shouldVisit: false).with(\.trailingTrivia, []))
|
|
709
|
+
\(raw: indent))
|
|
710
|
+
"""
|
|
711
|
+
}
|
|
712
|
+
|
|
713
|
+
override func visit(_ node: FunctionCallExprSyntax) -> ExprSyntax {
|
|
714
|
+
let memberAccess = node.calledExpression.as(MemberAccessExprSyntax.self)
|
|
715
|
+
let base = memberAccess?.base
|
|
716
|
+
let funcName = memberAccess?.declName.baseName.with(\.leadingTrivia, []).with(\.trailingTrivia, []).text ?? node.calledExpression.as(DeclReferenceExprSyntax.self)!.baseName.text
|
|
717
|
+
return _processFunction(
|
|
718
|
+
base: base,
|
|
719
|
+
functionName: funcName,
|
|
720
|
+
argumentList: node.arguments,
|
|
721
|
+
trailingClosure: node.trailingClosure,
|
|
722
|
+
diagnosticPoint: .init(memberAccess?.declName) ?? .init(node),
|
|
723
|
+
functionCallExpr: node)
|
|
724
|
+
?? .init(node)
|
|
725
|
+
}
|
|
726
|
+
|
|
727
|
+
override func visit(_ node: SubscriptCallExprSyntax) -> ExprSyntax {
|
|
728
|
+
return _processFunction(
|
|
729
|
+
base: node.calledExpression,
|
|
730
|
+
functionName: "subscript",
|
|
731
|
+
argumentList: node.arguments,
|
|
732
|
+
trailingClosure: node.trailingClosure,
|
|
733
|
+
diagnosticPoint: .init(node.leftSquare))
|
|
734
|
+
?? .init(node)
|
|
735
|
+
}
|
|
736
|
+
|
|
737
|
+
private func _processFunction(base: ExprSyntax?, functionName: String, argumentList: LabeledExprListSyntax, trailingClosure: ClosureExprSyntax?, diagnosticPoint: Syntax, functionCallExpr: FunctionCallExprSyntax? = nil) -> ExprSyntax? {
|
|
738
|
+
// The provided base is nil when calling global functions functions
|
|
739
|
+
guard let base else {
|
|
740
|
+
diagnose(node: diagnosticPoint, message: "Global functions are not supported in this \(kind.keyword)")
|
|
741
|
+
return nil
|
|
742
|
+
}
|
|
743
|
+
|
|
744
|
+
// Check this function against our known list to provide rich diagnostics for functions we know we don't support
|
|
745
|
+
let name = TokenSyntax(.identifier(functionName), presence: .present).with(\.leadingTrivia, []).with(\.trailingTrivia, [])
|
|
746
|
+
let args = argumentList.map {
|
|
747
|
+
let isClosure = $0.expression.is(ClosureExprSyntax.self) || $0.expression.is(KeyPathExprSyntax.self)
|
|
748
|
+
return FunctionStructure.Argument(label: $0.label?.text, kind: isClosure ? .closure : .standard)
|
|
749
|
+
}
|
|
750
|
+
let structure = FunctionStructure(name.text, arguments: args, trailingClosure: trailingClosure != nil)
|
|
751
|
+
guard let knownFunc = _knownMatchingFunction(structure) else {
|
|
752
|
+
let diagnostic = PredicateExpansionDiagnostic("The \(structure.signature) function is not supported in this \(kind.keyword)")
|
|
753
|
+
var fixIts = [FixIt]()
|
|
754
|
+
if let functionCallExpr,
|
|
755
|
+
let suggestion = _suggestionForUnknownFunction(structure),
|
|
756
|
+
let changes = suggestion.fixItChanges(transformingFrom: functionCallExpr) {
|
|
757
|
+
fixIts.append(FixIt(message: PredicateExpansionDiagnostic("Use \(suggestion.signature)", severity: .note), changes: changes))
|
|
758
|
+
}
|
|
759
|
+
diagnose(node: diagnosticPoint, message: diagnostic, fixIts: fixIts)
|
|
760
|
+
return nil
|
|
761
|
+
}
|
|
762
|
+
|
|
763
|
+
var arguments: [LabeledExprSyntax] = []
|
|
764
|
+
func addArgument(_ argument: ExprSyntax, label: String?, withComma: Bool) {
|
|
765
|
+
arguments.append(
|
|
766
|
+
makeArgument(label: label, argument)
|
|
767
|
+
.with(\.trailingComma, withComma ? TokenSyntax(.comma, presence: .present) : nil)
|
|
768
|
+
.with(\.trailingTrivia, withComma ? .newline : [])
|
|
769
|
+
)
|
|
770
|
+
}
|
|
771
|
+
|
|
772
|
+
// Function arguments can contain dollar sign identifiers that can't be nested inside of a new closure
|
|
773
|
+
// Prevent this function call from being placed inside of a flatMap due to optionalChaining
|
|
774
|
+
let oldValidOptionalChainingTree = validOptionalChainingTree
|
|
775
|
+
validOptionalChainingTree = false
|
|
776
|
+
addArgument(base, label: nil, withComma: !argumentList.isEmpty)
|
|
777
|
+
validOptionalChainingTree = oldValidOptionalChainingTree
|
|
778
|
+
|
|
779
|
+
for (sourceArg, knownArgStructure) in zip(argumentList, knownFunc.arguments.expandingPackToMatchCount(argumentList.count)) {
|
|
780
|
+
var expression = sourceArg.expression
|
|
781
|
+
if knownArgStructure.kind == .closure, let kpExpr = sourceArg.expression.as(KeyPathExprSyntax.self) {
|
|
782
|
+
guard !kpExpr.containsShorthandArgumentIdentifiers,
|
|
783
|
+
let memberAccess = kpExpr.asDirectExpression(on: DeclReferenceExprSyntax(baseName: .dollarIdentifier("$0"))),
|
|
784
|
+
let preparedMemberAccess = try? memberAccess.rewrite(with: OptionalChainRewriter()) else {
|
|
785
|
+
diagnose(node: kpExpr, message: "This key path is not supported here in this \(kind.keyword). Use an explicit closure instead.")
|
|
786
|
+
return nil
|
|
787
|
+
}
|
|
788
|
+
expression = ExprSyntax(ClosureExprSyntax(statements: [CodeBlockItemSyntax(item: .expr(preparedMemberAccess.as(ExprSyntax.self)!))]))
|
|
789
|
+
}
|
|
790
|
+
addArgument(expression, label: sourceArg.label?.text, withComma: sourceArg.trailingComma != nil)
|
|
791
|
+
}
|
|
792
|
+
|
|
793
|
+
// SwiftData's builders are found without a module selector.
|
|
794
|
+
let buildModule = swiftDataFunctions.contains(name.text) ? "" : "\(moduleName())::"
|
|
795
|
+
if let closure = trailingClosure {
|
|
796
|
+
// Don't indent, because closures already get indented
|
|
797
|
+
let closureArg = makeArgument(label: nil, ExprSyntax(closure), shouldIndent: false)
|
|
798
|
+
return """
|
|
799
|
+
\(raw: indent)PredicateExpressions.\(raw: buildModule)build_\(name.with(\.leadingTrivia, []).with(\.trailingTrivia, []))(
|
|
800
|
+
\(LabeledExprListSyntax(arguments))
|
|
801
|
+
\(raw: indent))\(raw: Trivia.space)\(closureArg.with(\.leadingTrivia, []).with(\.trailingTrivia, []))
|
|
802
|
+
"""
|
|
803
|
+
} else {
|
|
804
|
+
return """
|
|
805
|
+
\(raw: indent)PredicateExpressions.\(raw: buildModule)build_\(name.with(\.leadingTrivia, []).with(\.trailingTrivia, []))(
|
|
806
|
+
\(LabeledExprListSyntax(arguments))
|
|
807
|
+
\(raw: indent))
|
|
808
|
+
"""
|
|
809
|
+
}
|
|
810
|
+
}
|
|
811
|
+
|
|
812
|
+
override func visit(_ node: TupleExprSyntax) -> ExprSyntax {
|
|
813
|
+
guard node.elements.count == 1, let element = node.elements.first else {
|
|
814
|
+
diagnose(node: node, message: "Tuples are not supported in this \(kind.keyword)")
|
|
815
|
+
return ExprSyntax(node)
|
|
816
|
+
}
|
|
817
|
+
|
|
818
|
+
// Support expressions like "(input as? Bool) == true" where parantheses used for grouping are treated like a single element tuple expression
|
|
819
|
+
return visit(element.expression)
|
|
820
|
+
}
|
|
821
|
+
|
|
822
|
+
// Processes a code block and guarantees that the returned code block only contains one item
|
|
823
|
+
func _processCodeBlock(_ statements: CodeBlockItemListSyntax, in node: Syntax, removeReturn: Bool = false) -> CodeBlockItemListSyntax? {
|
|
824
|
+
guard statements.count == 1 else {
|
|
825
|
+
diagnose(node: statements.isEmpty ? node : statements[statements.index(after: statements.startIndex)], message: "\(kind.capitalizedKeyword) body may only contain one expression")
|
|
826
|
+
return nil
|
|
827
|
+
}
|
|
828
|
+
|
|
829
|
+
indentLevel += 1
|
|
830
|
+
var body = visit(statements)
|
|
831
|
+
if success && body == statements {
|
|
832
|
+
let wrapped: ExprSyntax =
|
|
833
|
+
"""
|
|
834
|
+
\(raw: indent)PredicateExpressions.\(raw: moduleName())::build_Arg(
|
|
835
|
+
\(raw: indent + indentWidth)\(body.with(\.leadingTrivia, []).with(\.trailingTrivia, []))
|
|
836
|
+
\(raw: indent))
|
|
837
|
+
"""
|
|
838
|
+
body = [.init(item: .expr(wrapped))]
|
|
839
|
+
}
|
|
840
|
+
indentLevel -= 1
|
|
841
|
+
|
|
842
|
+
if removeReturn, let first = body.first, case .stmt(let statement) = first.item, let returnStmt = statement.as(ReturnStmtSyntax.self), let returnExpr = returnStmt.expression {
|
|
843
|
+
body = [.init(item: .expr(returnExpr.with(\.leadingTrivia, returnStmt.leadingTrivia)))]
|
|
844
|
+
}
|
|
845
|
+
return body
|
|
846
|
+
}
|
|
847
|
+
|
|
848
|
+
override func visit(_ node: CodeBlockSyntax) -> CodeBlockSyntax {
|
|
849
|
+
guard let body = _processCodeBlock(node.statements, in: .init(node)) else {
|
|
850
|
+
return node
|
|
851
|
+
}
|
|
852
|
+
return node.with(\.statements, body)
|
|
853
|
+
}
|
|
854
|
+
|
|
855
|
+
override func visit(_ node: ClosureExprSyntax) -> ExprSyntax {
|
|
856
|
+
guard let body = _processCodeBlock(node.statements, in: .init(node)) else {
|
|
857
|
+
return .init(node)
|
|
858
|
+
}
|
|
859
|
+
|
|
860
|
+
var resultingSignature = node.signature
|
|
861
|
+
if let signature = node.signature {
|
|
862
|
+
var visited = signature
|
|
863
|
+
visited.returnClause = nil
|
|
864
|
+
if case .parameterClause(let paramClause) = signature.parameterClause {
|
|
865
|
+
let newParamClause = paramClause.with(\.parameters, paramClause.parameters.withVariableWrappedTypes)
|
|
866
|
+
visited.parameterClause = .parameterClause(newParamClause)
|
|
867
|
+
}
|
|
868
|
+
resultingSignature = visited
|
|
869
|
+
}
|
|
870
|
+
|
|
871
|
+
return ExprSyntax(
|
|
872
|
+
node
|
|
873
|
+
.with(\.statements, body)
|
|
874
|
+
.with(\.leftBrace, node.leftBrace.with(\.trailingTrivia, node.signature == nil ? .newline : .space))
|
|
875
|
+
.with(\.signature, resultingSignature?.with(\.trailingTrivia, .newline))
|
|
876
|
+
.with(\.rightBrace, node.rightBrace.with(\.leadingTrivia, .newline + indent))
|
|
877
|
+
)
|
|
878
|
+
}
|
|
879
|
+
|
|
880
|
+
override func visit(_ node: TernaryExprSyntax) -> ExprSyntax {
|
|
881
|
+
let condition = node.condition
|
|
882
|
+
let firstChoice = node.thenExpression
|
|
883
|
+
let secondChoice = node.elseExpression
|
|
884
|
+
|
|
885
|
+
return """
|
|
886
|
+
\(raw: indent)PredicateExpressions.\(raw: moduleName())::build_Conditional(
|
|
887
|
+
\(makeArgument(label: nil, condition).with(\.trailingTrivia, [])),
|
|
888
|
+
\(makeArgument(label: nil, firstChoice).with(\.trailingTrivia, [])),
|
|
889
|
+
\(makeArgument(label: nil, secondChoice).with(\.trailingTrivia, []))
|
|
890
|
+
\(raw: indent))
|
|
891
|
+
"""
|
|
892
|
+
}
|
|
893
|
+
|
|
894
|
+
override func visit(_ node: IsExprSyntax) -> ExprSyntax {
|
|
895
|
+
return """
|
|
896
|
+
\(raw: indent)PredicateExpressions.\(raw: moduleName())::TypeCheck<_, \(node.type)>(
|
|
897
|
+
\(makeArgument(label: nil, node.expression).with(\.trailingTrivia, []))
|
|
898
|
+
\(raw: indent))
|
|
899
|
+
"""
|
|
900
|
+
}
|
|
901
|
+
|
|
902
|
+
override func visit(_ node: AsExprSyntax) -> ExprSyntax {
|
|
903
|
+
let castType: String
|
|
904
|
+
switch node.questionOrExclamationMark?.tokenKind {
|
|
905
|
+
case .none: fallthrough
|
|
906
|
+
case .some(.exclamationMark):
|
|
907
|
+
castType = "Force"
|
|
908
|
+
case .some(.postfixQuestionMark):
|
|
909
|
+
castType = "Conditional"
|
|
910
|
+
default:
|
|
911
|
+
fatalError("Unexpected question/exclamation mark token kind")
|
|
912
|
+
}
|
|
913
|
+
|
|
914
|
+
return """
|
|
915
|
+
\(raw: indent)PredicateExpressions.\(raw: moduleName())::\(raw: castType)Cast<_, \(node.type)>(
|
|
916
|
+
\(makeArgument(label: nil, node.expression).with(\.trailingTrivia, []))
|
|
917
|
+
\(raw: indent))
|
|
918
|
+
"""
|
|
919
|
+
}
|
|
920
|
+
|
|
921
|
+
override func visit(_ node: ReturnStmtSyntax) -> StmtSyntax {
|
|
922
|
+
guard let expression = node.expression else {
|
|
923
|
+
// No expansion needed when returning Void
|
|
924
|
+
return StmtSyntax(node)
|
|
925
|
+
}
|
|
926
|
+
|
|
927
|
+
let visited = visit(expression)
|
|
928
|
+
guard visited == expression else {
|
|
929
|
+
// No expansion needed when returning transformed expression
|
|
930
|
+
return StmtSyntax(node.with(\.expression, visited.with(\.leadingTrivia, [])).with(\.leadingTrivia, indent))
|
|
931
|
+
}
|
|
932
|
+
|
|
933
|
+
// Wrap constant return expressions in a build_Arg call
|
|
934
|
+
let wrapped: ExprSyntax =
|
|
935
|
+
"""
|
|
936
|
+
PredicateExpressions.\(raw: moduleName())::build_Arg(
|
|
937
|
+
\(visited.with(\.leadingTrivia, indent + indentWidth))
|
|
938
|
+
\(raw: indent))
|
|
939
|
+
"""
|
|
940
|
+
return StmtSyntax(node.with(\.expression, wrapped).with(\.leadingTrivia, indent))
|
|
941
|
+
}
|
|
942
|
+
|
|
943
|
+
override func visit(_ node: SwitchExprSyntax) -> ExprSyntax {
|
|
944
|
+
self.diagnose(node: node, message: "Switch expressions are not supported in this \(kind.keyword)")
|
|
945
|
+
return .init(node)
|
|
946
|
+
}
|
|
947
|
+
|
|
948
|
+
private func _rewriteConditionsAsExpression<C: BidirectionalCollection<ConditionElementListSyntax.Element>>(_ collection: C, in expr: IfExprSyntax) -> ExprSyntax? {
|
|
949
|
+
guard let last = collection.last else {
|
|
950
|
+
self.diagnose(node: expr, message: "This list of conditionals is unsupported in this \(kind.keyword)")
|
|
951
|
+
return nil
|
|
952
|
+
}
|
|
953
|
+
guard case .expression(let lastExpr) = last.condition else {
|
|
954
|
+
let type: String
|
|
955
|
+
switch last.condition {
|
|
956
|
+
case .availability(_):
|
|
957
|
+
type = "Availability conditions"
|
|
958
|
+
case .matchingPattern(_):
|
|
959
|
+
type = "Matching pattern conditions"
|
|
960
|
+
case .optionalBinding(_):
|
|
961
|
+
self.diagnose(node: last, message: "Mixing optional bindings with other conditions is not supported in this \(kind.keyword)")
|
|
962
|
+
return nil
|
|
963
|
+
default:
|
|
964
|
+
type = "These types of conditions"
|
|
965
|
+
}
|
|
966
|
+
self.diagnose(node: last, message: "\(type) are not supported in this \(kind.keyword)")
|
|
967
|
+
return nil
|
|
968
|
+
}
|
|
969
|
+
let rest = collection.dropLast()
|
|
970
|
+
if rest.isEmpty {
|
|
971
|
+
return lastExpr
|
|
972
|
+
} else {
|
|
973
|
+
guard let restRewritten = _rewriteConditionsAsExpression(rest, in: expr) else {
|
|
974
|
+
return nil
|
|
975
|
+
}
|
|
976
|
+
return .init(InfixOperatorExprSyntax(leftOperand: restRewritten, operator: BinaryOperatorExprSyntax(operator: .binaryOperator("&&")), rightOperand: lastExpr))
|
|
977
|
+
}
|
|
978
|
+
}
|
|
979
|
+
|
|
980
|
+
private func _rewriteIfAsFlatMap(bindings: [OptionalBindingConditionSyntax], body: ExprSyntax, else: ExprSyntax) -> ExprSyntax? {
|
|
981
|
+
indentLevel += bindings.count
|
|
982
|
+
|
|
983
|
+
var prior: ExprSyntax = body
|
|
984
|
+
for binding in bindings.reversed() {
|
|
985
|
+
guard let identifier = binding.pattern.as(IdentifierPatternSyntax.self)?.identifier else {
|
|
986
|
+
self.diagnose(node: binding.pattern, message: "This optional binding condition is not supported in this \(kind.keyword)")
|
|
987
|
+
return nil
|
|
988
|
+
}
|
|
989
|
+
let initializer = binding.initializer?.value ?? ExprSyntax(DeclReferenceExprSyntax(baseName: identifier))
|
|
990
|
+
|
|
991
|
+
prior = """
|
|
992
|
+
\(raw: indent)PredicateExpressions.\(raw: moduleName())::build_flatMap(
|
|
993
|
+
\(makeArgument(label: nil, initializer).with(\.trailingTrivia, []))
|
|
994
|
+
\(raw: indent)) { \(identifier.with(\.trailingTrivia, []).with(\.leadingTrivia, [])) in
|
|
995
|
+
\(makeArgument(label: nil, prior, shouldVisit: false).with(\.trailingTrivia, []))
|
|
996
|
+
\(raw: indent)}
|
|
997
|
+
"""
|
|
998
|
+
indentLevel -= 1
|
|
999
|
+
}
|
|
1000
|
+
|
|
1001
|
+
return """
|
|
1002
|
+
\(raw: indent)PredicateExpressions.\(raw: moduleName())::build_NilCoalesce(
|
|
1003
|
+
\(makeArgument(label: "lhs", prior, shouldVisit: false)),
|
|
1004
|
+
\(makeArgument(label: "rhs", `else`, shouldVisit: false))
|
|
1005
|
+
\(raw: indent))
|
|
1006
|
+
"""
|
|
1007
|
+
}
|
|
1008
|
+
|
|
1009
|
+
private func _processIfBody(_ node: IfExprSyntax) -> ExprSyntax? {
|
|
1010
|
+
guard let visitedBody = _processCodeBlock(node.body.statements, in: .init(node.body), removeReturn: true) else {
|
|
1011
|
+
return nil
|
|
1012
|
+
}
|
|
1013
|
+
|
|
1014
|
+
guard let bodyExpression = visitedBody.first?.item._expression else {
|
|
1015
|
+
self.diagnose(node: node.body, message: "This if expression body is not supported in this \(kind.keyword)")
|
|
1016
|
+
return nil
|
|
1017
|
+
}
|
|
1018
|
+
|
|
1019
|
+
return bodyExpression
|
|
1020
|
+
}
|
|
1021
|
+
|
|
1022
|
+
private func _processElseBody(_ node: IfExprSyntax) -> ExprSyntax? {
|
|
1023
|
+
guard let elseBody = node.elseBody else {
|
|
1024
|
+
self.diagnose(node: node, message: "If expressions without an else expression are not supported in this \(kind.keyword)")
|
|
1025
|
+
return nil
|
|
1026
|
+
}
|
|
1027
|
+
|
|
1028
|
+
let elseExpression: ExprSyntax
|
|
1029
|
+
switch elseBody {
|
|
1030
|
+
case .codeBlock(let codeBlock):
|
|
1031
|
+
guard let visitedElseBody = _processCodeBlock(codeBlock.statements, in: .init(codeBlock), removeReturn: true) else {
|
|
1032
|
+
return nil
|
|
1033
|
+
}
|
|
1034
|
+
guard let expr = visitedElseBody.first?.item._expression else {
|
|
1035
|
+
self.diagnose(node: node.body, message: "This if expression else body is not supported in this \(kind.keyword)")
|
|
1036
|
+
return nil
|
|
1037
|
+
}
|
|
1038
|
+
elseExpression = expr
|
|
1039
|
+
case .ifExpr(let ifExpr):
|
|
1040
|
+
elseExpression = visit(ifExpr)
|
|
1041
|
+
#if FOUNDATION_FRAMEWORK
|
|
1042
|
+
@unknown default:
|
|
1043
|
+
self.diagnose(node: elseBody, message: "This if expression else body is not supported in this \(kind.keyword)")
|
|
1044
|
+
return nil
|
|
1045
|
+
#endif
|
|
1046
|
+
}
|
|
1047
|
+
|
|
1048
|
+
return elseExpression
|
|
1049
|
+
}
|
|
1050
|
+
|
|
1051
|
+
override func visit(_ node: IfExprSyntax) -> ExprSyntax {
|
|
1052
|
+
if let bindings = node.conditions.optionalBindings {
|
|
1053
|
+
indentLevel += bindings.count
|
|
1054
|
+
guard let bodyExpression = _processIfBody(node) else {
|
|
1055
|
+
return .init(node)
|
|
1056
|
+
}
|
|
1057
|
+
indentLevel -= bindings.count
|
|
1058
|
+
guard let elseExpression = _processElseBody(node) else {
|
|
1059
|
+
return .init(node)
|
|
1060
|
+
}
|
|
1061
|
+
return _rewriteIfAsFlatMap(bindings: bindings, body: bodyExpression, else: elseExpression) ?? .init(node)
|
|
1062
|
+
}
|
|
1063
|
+
|
|
1064
|
+
guard let ifExpression = _rewriteConditionsAsExpression(node.conditions, in: node),
|
|
1065
|
+
let bodyExpression = _processIfBody(node),
|
|
1066
|
+
let elseExpression = _processElseBody(node) else {
|
|
1067
|
+
return .init(node)
|
|
1068
|
+
}
|
|
1069
|
+
|
|
1070
|
+
return """
|
|
1071
|
+
\(raw: indent)PredicateExpressions.\(raw: moduleName())::build_Conditional(
|
|
1072
|
+
\(makeArgument(label: nil, ifExpression).with(\.trailingTrivia, [])),
|
|
1073
|
+
\(makeArgument(label: nil, bodyExpression, shouldVisit: false).with(\.trailingTrivia, [])),
|
|
1074
|
+
\(makeArgument(label: nil, elseExpression, shouldVisit: false).with(\.trailingTrivia, []))
|
|
1075
|
+
\(raw: indent))
|
|
1076
|
+
"""
|
|
1077
|
+
}
|
|
1078
|
+
|
|
1079
|
+
override func visit(_ node: WhileStmtSyntax) -> StmtSyntax {
|
|
1080
|
+
self.diagnose(node: node, message: "While loops are not supported in this \(kind.keyword)")
|
|
1081
|
+
return .init(node)
|
|
1082
|
+
}
|
|
1083
|
+
|
|
1084
|
+
override func visit(_ node: ForStmtSyntax) -> StmtSyntax {
|
|
1085
|
+
self.diagnose(node: node, message: "For-in loops are not supported in this \(kind.keyword)")
|
|
1086
|
+
return .init(node)
|
|
1087
|
+
}
|
|
1088
|
+
|
|
1089
|
+
override func visit(_ node: DoStmtSyntax) -> StmtSyntax {
|
|
1090
|
+
self.diagnose(node: node, message: "Do statements are not supported in this \(kind.keyword)")
|
|
1091
|
+
return .init(node)
|
|
1092
|
+
}
|
|
1093
|
+
|
|
1094
|
+
override func visit(_ node: CatchClauseSyntax) -> CatchClauseSyntax {
|
|
1095
|
+
self.diagnose(node: node, message: "Catch clauses are not supported in this \(kind.keyword)")
|
|
1096
|
+
return node
|
|
1097
|
+
}
|
|
1098
|
+
|
|
1099
|
+
override func visit(_ node: RepeatStmtSyntax) -> StmtSyntax {
|
|
1100
|
+
self.diagnose(node: node, message: "Repeat-while loops are not supported in this \(kind.keyword)")
|
|
1101
|
+
return .init(node)
|
|
1102
|
+
}
|
|
1103
|
+
|
|
1104
|
+
override func visit(_ node: CodeBlockItemSyntax) -> CodeBlockItemSyntax {
|
|
1105
|
+
// At this point, we know we're the only item in the code block because predicates only support single-expression code blocks
|
|
1106
|
+
|
|
1107
|
+
// Diagnose any declarations
|
|
1108
|
+
if case .decl(_) = node.item {
|
|
1109
|
+
diagnose(node: node.item, message: "Declarations are not supported in this \(kind.keyword)")
|
|
1110
|
+
return node
|
|
1111
|
+
}
|
|
1112
|
+
|
|
1113
|
+
if case let .stmt(statement) = node.item {
|
|
1114
|
+
// Unwrap a do statement with valid expression bodies
|
|
1115
|
+
if let doStatement = statement.as(DoStmtSyntax.self) {
|
|
1116
|
+
if let catchClause = doStatement.catchClauses.first {
|
|
1117
|
+
diagnose(node: catchClause, message: "Catch clauses are not supported in this \(kind.keyword)")
|
|
1118
|
+
return node
|
|
1119
|
+
}
|
|
1120
|
+
indentLevel -= 1
|
|
1121
|
+
let visitedBody = self.visit(doStatement.body)
|
|
1122
|
+
indentLevel += 1
|
|
1123
|
+
guard success else {
|
|
1124
|
+
return node
|
|
1125
|
+
}
|
|
1126
|
+
guard let innerExpr = visitedBody.statements.first else {
|
|
1127
|
+
diagnose(node: doStatement, message: "Do statement is not supported here in this \(kind.keyword)")
|
|
1128
|
+
return node
|
|
1129
|
+
}
|
|
1130
|
+
return innerExpr
|
|
1131
|
+
}
|
|
1132
|
+
}
|
|
1133
|
+
|
|
1134
|
+
return super.visit(node)
|
|
1135
|
+
}
|
|
1136
|
+
}
|
|
1137
|
+
|
|
1138
|
+
private struct PredicateExpansionDiagnostic: DiagnosticMessage, FixItMessage, ExpressibleByStringLiteral, ExpressibleByStringInterpolation {
|
|
1139
|
+
let message: String
|
|
1140
|
+
let severity: DiagnosticSeverity
|
|
1141
|
+
let diagnosticID: MessageID = .init(domain: "FoundationMacros", id: "PredicateDiagnostic")
|
|
1142
|
+
var fixItID: MessageID { diagnosticID }
|
|
1143
|
+
|
|
1144
|
+
init(_ message: String, severity: DiagnosticSeverity = .error) {
|
|
1145
|
+
self.message = message
|
|
1146
|
+
self.severity = severity
|
|
1147
|
+
}
|
|
1148
|
+
|
|
1149
|
+
init(stringLiteral value: String) {
|
|
1150
|
+
self.init(value)
|
|
1151
|
+
}
|
|
1152
|
+
}
|
|
1153
|
+
|
|
1154
|
+
private func moduleName(internationalization: Bool = false) -> String {
|
|
1155
|
+
#if FOUNDATION_FRAMEWORK
|
|
1156
|
+
"Foundation"
|
|
1157
|
+
#else
|
|
1158
|
+
internationalization ? "FoundationInternationalization" : "FoundationEssentials"
|
|
1159
|
+
#endif
|
|
1160
|
+
}
|
|
1161
|
+
|
|
1162
|
+
private enum ExpansionKind {
|
|
1163
|
+
case predicate
|
|
1164
|
+
case expression
|
|
1165
|
+
|
|
1166
|
+
var keyword: String {
|
|
1167
|
+
switch self {
|
|
1168
|
+
case .predicate:
|
|
1169
|
+
"predicate"
|
|
1170
|
+
case .expression:
|
|
1171
|
+
"expression"
|
|
1172
|
+
}
|
|
1173
|
+
}
|
|
1174
|
+
|
|
1175
|
+
var capitalizedKeyword: String {
|
|
1176
|
+
let keyword = self.keyword
|
|
1177
|
+
let first = keyword.first!.uppercased()
|
|
1178
|
+
return "\(first)\(keyword.dropFirst())"
|
|
1179
|
+
}
|
|
1180
|
+
|
|
1181
|
+
var macroKeyword: String {
|
|
1182
|
+
"#\(capitalizedKeyword)"
|
|
1183
|
+
}
|
|
1184
|
+
|
|
1185
|
+
var qualifiedExpansionType: String {
|
|
1186
|
+
"\(moduleName()).\(capitalizedKeyword)"
|
|
1187
|
+
}
|
|
1188
|
+
}
|
|
1189
|
+
|
|
1190
|
+
private func predicateExpansion(of node: some FreestandingMacroExpansionSyntax, in context: some MacroExpansionContext, kind: ExpansionKind) throws -> ExprSyntax {
|
|
1191
|
+
guard let closure = node.trailingClosure else {
|
|
1192
|
+
let fixIts: [FixIt]
|
|
1193
|
+
if let argument = node.arguments.first?.expression.as(ClosureExprSyntax.self) {
|
|
1194
|
+
var newNode = node.with(\.leftParen, nil)
|
|
1195
|
+
.with(\.rightParen, nil)
|
|
1196
|
+
.with(\.trailingClosure, argument.with(\.leadingTrivia, [.spaces(1)]).with(\.trailingTrivia, []))
|
|
1197
|
+
newNode.arguments = []
|
|
1198
|
+
fixIts = [
|
|
1199
|
+
FixIt(message: PredicateExpansionDiagnostic("Use a trailing closure instead of a function parameter", severity: .note), changes: [
|
|
1200
|
+
.replace(oldNode: Syntax(node), newNode: Syntax(newNode))
|
|
1201
|
+
])
|
|
1202
|
+
]
|
|
1203
|
+
} else {
|
|
1204
|
+
fixIts = []
|
|
1205
|
+
}
|
|
1206
|
+
throw DiagnosticsError(diagnostics: [.init(
|
|
1207
|
+
node: Syntax(node),
|
|
1208
|
+
message: PredicateExpansionDiagnostic("\(kind.macroKeyword) macro expansion requires a trailing closure"),
|
|
1209
|
+
fixIts: fixIts
|
|
1210
|
+
)])
|
|
1211
|
+
}
|
|
1212
|
+
|
|
1213
|
+
let translatedClosure = try closure
|
|
1214
|
+
.rewrite(with: OptionalChainRewriter())
|
|
1215
|
+
.rewrite(with: PredicateQueryRewriter(kind: kind))
|
|
1216
|
+
.with(\.leadingTrivia, [])
|
|
1217
|
+
.with(\.trailingTrivia, [])
|
|
1218
|
+
|
|
1219
|
+
if let genericArgs = node.genericArgumentClause {
|
|
1220
|
+
let strippedGenericArgs = genericArgs
|
|
1221
|
+
.with(\.leadingTrivia, [])
|
|
1222
|
+
.with(\.trailingTrivia, [])
|
|
1223
|
+
return "\(raw: kind.qualifiedExpansionType)\(strippedGenericArgs)(\(translatedClosure))"
|
|
1224
|
+
} else {
|
|
1225
|
+
// When the macro is specified without generic args (ex. "#Predicate { ... }") initialize a Predicate without generic args so they can be inferred from context
|
|
1226
|
+
return "\(raw: kind.qualifiedExpansionType)(\(translatedClosure))"
|
|
1227
|
+
}
|
|
1228
|
+
}
|
|
1229
|
+
|
|
1230
|
+
public struct PredicateMacro: SwiftSyntaxMacros.ExpressionMacro, Sendable {
|
|
1231
|
+
public static var formatMode: FormatMode { .disabled }
|
|
1232
|
+
|
|
1233
|
+
public static func expansion(of node: some FreestandingMacroExpansionSyntax, in context: some MacroExpansionContext) throws -> ExprSyntax {
|
|
1234
|
+
try predicateExpansion(of: node, in: context, kind: .predicate)
|
|
1235
|
+
}
|
|
1236
|
+
}
|
|
1237
|
+
|
|
1238
|
+
public struct ExpressionMacro: SwiftSyntaxMacros.ExpressionMacro, Sendable {
|
|
1239
|
+
public static var formatMode: FormatMode { .disabled }
|
|
1240
|
+
|
|
1241
|
+
public static func expansion(of node: some FreestandingMacroExpansionSyntax, in context: some MacroExpansionContext) throws -> ExprSyntax {
|
|
1242
|
+
try predicateExpansion(of: node, in: context, kind: .expression)
|
|
1243
|
+
}
|
|
1244
|
+
}
|