react-native-windows 0.74.10 → 0.75.0-preview.1
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/.flowconfig +8 -2
- package/Common/Common.vcxproj +8 -0
- package/Common/Utilities.cpp +2 -2
- package/Directory.Build.targets +5 -0
- package/Folly/Folly.vcxproj +10 -2
- package/Folly/Folly.vcxproj.filters +0 -7
- package/Folly/TEMP_UntilFollyUpdate/ConstexprMath.h +970 -0
- package/Folly/TEMP_UntilFollyUpdate/json.cpp +1110 -0
- package/Folly/TEMP_UntilFollyUpdate/lang/ToAscii.cpp +4 -2
- package/Libraries/Animated/AnimatedImplementation.js +2 -0
- package/Libraries/Animated/NativeAnimatedHelper.js +4 -0
- package/Libraries/Animated/createAnimatedComponent.js +10 -4
- package/Libraries/Animated/useAnimatedProps.js +56 -28
- package/Libraries/BatchedBridge/MessageQueue.js +1 -0
- package/Libraries/Components/Button.js +10 -5
- package/Libraries/Components/DrawerAndroid/DrawerLayoutAndroid.android.js +11 -2
- package/Libraries/Components/Flyout/Flyout.js +10 -10
- package/Libraries/Components/Flyout/FlyoutNativeComponent.js +8 -7
- package/Libraries/Components/Pressable/Pressable.js +13 -6
- package/Libraries/Components/Pressable/Pressable.windows.js +13 -6
- package/Libraries/Components/ScrollView/AndroidHorizontalScrollViewNativeComponent.js +4 -0
- package/Libraries/Components/ScrollView/ScrollView.js +109 -29
- package/Libraries/Components/ScrollView/ScrollViewNativeComponent.js +6 -0
- package/Libraries/Components/ScrollView/ScrollViewNativeComponent.windows.js +6 -0
- package/Libraries/Components/ScrollView/ScrollViewStickyHeader.js +13 -1
- package/Libraries/Components/StatusBar/StatusBar.js +1 -21
- package/Libraries/Components/Switch/Switch.windows.js +2 -0
- package/Libraries/Components/TextInput/AndroidTextInputNativeComponent.js +0 -15
- package/Libraries/Components/TextInput/InputAccessoryView.js +10 -1
- package/Libraries/Components/TextInput/RCTTextInputViewConfig.js +0 -12
- package/Libraries/Components/TextInput/TextInput.d.ts +0 -19
- package/Libraries/Components/TextInput/TextInput.js +20 -73
- package/Libraries/Components/TextInput/TextInput.windows.js +21 -75
- package/Libraries/Components/TextInput/WindowsTextInputNativeComponent.js +27 -12
- package/Libraries/Components/Touchable/Touchable.js +2 -2
- package/Libraries/Components/Touchable/TouchableHighlight.d.ts +4 -10
- package/Libraries/Components/Touchable/TouchableHighlight.js +3 -1
- package/Libraries/Components/Touchable/TouchableHighlight.windows.js +3 -1
- package/Libraries/Components/Touchable/TouchableOpacity.d.ts +4 -32
- package/Libraries/Components/Touchable/TouchableOpacity.js +3 -1
- package/Libraries/Components/Touchable/TouchableOpacity.windows.js +3 -1
- package/Libraries/Components/Touchable/TouchableWithoutFeedback.d.ts +8 -0
- package/Libraries/Components/Touchable/TouchableWithoutFeedback.js +117 -111
- package/Libraries/Components/Touchable/TouchableWithoutFeedback.windows.js +129 -110
- package/Libraries/Components/View/ReactNativeStyleAttributes.js +6 -0
- package/Libraries/Components/View/ReactNativeViewAttributes.js +1 -0
- package/Libraries/Components/View/ReactNativeViewAttributes.windows.js +1 -0
- package/Libraries/Components/View/View.js +0 -11
- package/Libraries/Components/View/View.windows.js +0 -11
- package/Libraries/Components/View/ViewAccessibility.js +4 -4
- package/Libraries/Components/View/ViewAccessibility.windows.js +4 -4
- package/Libraries/Components/View/ViewPropTypes.d.ts +21 -59
- package/Libraries/Components/View/ViewPropTypes.js +7 -0
- package/Libraries/Components/View/ViewPropTypes.windows.js +7 -0
- package/Libraries/Core/Devtools/loadBundleFromServer.js +3 -3
- package/Libraries/Core/Devtools/loadBundleFromServer.windows.js +153 -0
- package/Libraries/Core/Devtools/parseErrorStack.js +5 -5
- package/Libraries/Core/Devtools/parseHermesStack.js +22 -16
- package/Libraries/Core/ErrorHandlers.js +116 -0
- package/Libraries/Core/ExceptionsManager.js +2 -2
- package/Libraries/Core/ReactNativeVersion.js +3 -3
- package/Libraries/Core/setUpDeveloperTools.js +3 -1
- package/Libraries/Core/setUpPerformance.js +6 -4
- package/Libraries/Core/setUpReactDevTools.js +70 -10
- package/Libraries/Core/setUpTimers.js +50 -31
- package/Libraries/Debugging/DebuggingOverlayRegistry.js +1 -1
- package/Libraries/Image/Image.android.js +23 -13
- package/Libraries/Image/Image.d.ts +14 -15
- package/Libraries/Image/Image.ios.js +21 -11
- package/Libraries/Image/Image.windows.js +21 -11
- package/Libraries/Image/ImageProps.js +16 -5
- package/Libraries/Image/ImageTypes.flow.js +7 -2
- package/Libraries/Image/ImageUtils.js +1 -0
- package/Libraries/Image/ImageViewNativeComponent.js +2 -1
- package/Libraries/Inspector/ElementBox.js +6 -3
- package/Libraries/Inspector/ElementProperties.js +1 -1
- package/Libraries/Interaction/TouchHistoryMath.js +4 -4
- package/Libraries/IntersectionObserver/IntersectionObserverManager.js +6 -26
- package/Libraries/JSInspector/NetworkAgent.js +1 -1
- package/Libraries/LogBox/Data/LogBoxData.js +39 -29
- package/Libraries/LogBox/Data/LogBoxLog.js +114 -2
- package/Libraries/LogBox/Data/parseLogBoxLog.js +168 -53
- package/Libraries/LogBox/LogBox.js +29 -12
- package/Libraries/LogBox/LogBoxNotificationContainer.js +4 -0
- package/Libraries/LogBox/UI/LogBoxInspector.js +8 -70
- package/Libraries/LogBox/UI/LogBoxInspectorBody.js +87 -0
- package/Libraries/LogBox/UI/LogBoxInspectorFooter.js +6 -42
- package/Libraries/LogBox/UI/LogBoxInspectorFooterButton.js +58 -0
- package/Libraries/LogBox/UI/LogBoxInspectorHeader.js +5 -66
- package/Libraries/LogBox/UI/LogBoxInspectorHeader.windows.js +5 -66
- package/Libraries/LogBox/UI/LogBoxInspectorHeaderButton.js +76 -0
- package/Libraries/LogBox/UI/LogBoxInspectorReactFrames.js +8 -5
- package/Libraries/LogBox/UI/LogBoxInspectorReactFrames.windows.js +8 -5
- package/Libraries/LogBox/UI/LogBoxNotification.js +13 -152
- package/Libraries/LogBox/UI/LogBoxNotificationCountBadge.js +63 -0
- package/Libraries/LogBox/UI/LogBoxNotificationDismissButton.js +67 -0
- package/Libraries/LogBox/UI/LogBoxNotificationMessage.js +57 -0
- package/Libraries/NativeComponent/BaseViewConfig.android.js +5 -0
- package/Libraries/NativeComponent/BaseViewConfig.ios.js +5 -0
- package/Libraries/NativeComponent/BaseViewConfig.windows.js +5 -0
- package/Libraries/NativeComponent/NativeComponentRegistry.js +12 -5
- package/Libraries/NativeComponent/StaticViewConfigValidator.js +3 -0
- package/Libraries/Network/XMLHttpRequest.js +5 -1
- package/Libraries/NewAppScreen/components/LearnMoreLinks.js +3 -3
- package/Libraries/Pressability/Pressability.js +3 -51
- package/Libraries/Pressability/Pressability.windows.js +3 -51
- package/Libraries/ReactNative/AppRegistry.d.ts +4 -0
- package/Libraries/ReactNative/AppRegistry.js +2 -4
- package/Libraries/ReactNative/BridgelessUIManager.js +1 -21
- package/Libraries/ReactNative/FabricUIManager.js +0 -51
- package/Libraries/ReactNative/ReactFabricPublicInstance/warnForStyleProps.js +1 -0
- package/Libraries/ReactNative/RendererImplementation.js +20 -2
- package/Libraries/ReactNative/UIManager.d.ts +0 -21
- package/Libraries/ReactNative/UIManagerProperties.js +0 -3
- package/Libraries/ReactNative/__mocks__/FabricUIManager.js +5 -341
- package/Libraries/ReactNative/getNativeComponentAttributes.js +8 -8
- package/Libraries/Renderer/implementations/ReactFabric-dev.js +15682 -27088
- package/Libraries/Renderer/implementations/ReactFabric-prod.js +5082 -4381
- package/Libraries/Renderer/implementations/ReactFabric-profiling.js +3480 -2571
- package/Libraries/Renderer/implementations/ReactNativeRenderer-dev.js +15943 -27543
- package/Libraries/Renderer/implementations/ReactNativeRenderer-prod.js +5303 -4606
- package/Libraries/Renderer/implementations/ReactNativeRenderer-profiling.js +3450 -2572
- package/Libraries/Renderer/shims/ReactFabric.js +2 -2
- package/Libraries/Renderer/shims/ReactFeatureFlags.js +2 -2
- package/Libraries/Renderer/shims/ReactNative.js +2 -3
- package/Libraries/Renderer/shims/ReactNativeTypes.js +24 -3
- package/Libraries/Renderer/shims/ReactNativeViewConfigRegistry.js +2 -2
- package/Libraries/Renderer/shims/createReactNativeComponentClass.js +2 -2
- package/Libraries/Share/Share.d.ts +16 -10
- package/Libraries/Share/Share.js +14 -15
- package/Libraries/StyleSheet/StyleSheet.d.ts +1 -1
- package/Libraries/StyleSheet/StyleSheet.js +3 -10
- package/Libraries/StyleSheet/StyleSheetTypes.d.ts +21 -21
- package/Libraries/StyleSheet/StyleSheetTypes.js +24 -18
- package/Libraries/StyleSheet/flattenStyle.js +1 -0
- package/Libraries/StyleSheet/processFilter.js +132 -0
- package/Libraries/StyleSheet/processTransform.js +18 -3
- package/Libraries/Text/Text.js +151 -128
- package/Libraries/Text/Text.windows.js +144 -127
- package/Libraries/Text/TextNativeComponent.js +5 -4
- package/Libraries/Text/TextProps.js +6 -6
- package/Libraries/Text/TextProps.windows.js +6 -6
- package/Libraries/TurboModule/TurboModuleRegistry.js +2 -1
- package/Libraries/Types/CodegenTypes.js +3 -0
- package/Libraries/Utilities/{LoadingView.android.js → DevLoadingView.js} +33 -11
- package/Libraries/Utilities/Dimensions.js +1 -0
- package/Libraries/Utilities/HMRClient.js +36 -8
- package/Libraries/Utilities/HMRClientProdShim.js +1 -0
- package/Libraries/Utilities/NativePlatformConstantsWin.js +2 -2
- package/Libraries/Utilities/Platform.android.js +4 -4
- package/Libraries/Utilities/RCTLog.js +1 -0
- package/Libraries/Utilities/ReactNativeTestTools.js +12 -24
- package/Libraries/Utilities/verifyComponentAttributeEquivalence.js +11 -6
- package/Libraries/__tests__/ViewWindows-test.js +6 -6
- package/Libraries/promiseRejectionTrackingOptions.js +1 -0
- package/Microsoft.ReactNative/Base/FollyIncludes.h +1 -1
- package/Microsoft.ReactNative/ComponentView.idl +0 -17
- package/Microsoft.ReactNative/Fabric/AbiState.cpp +3 -45
- package/Microsoft.ReactNative/Fabric/AbiState.h +0 -6
- package/Microsoft.ReactNative/Fabric/Composition/ImageComponentView.cpp +10 -6
- package/Microsoft.ReactNative/Fabric/Composition/ImageComponentView.h +4 -4
- package/Microsoft.ReactNative/Fabric/Composition/ReactNativeIsland.cpp +12 -3
- package/Microsoft.ReactNative/Fabric/Composition/ScrollViewComponentView.cpp +1 -1
- package/Microsoft.ReactNative/Fabric/Composition/TextInput/WindowsTextInputComponentView.cpp +7 -12
- package/Microsoft.ReactNative/Fabric/Composition/TextInput/WindowsTextInputShadowNode.cpp +1 -2
- package/Microsoft.ReactNative/Fabric/Composition/UriImageManager.cpp +9 -3
- package/Microsoft.ReactNative/Fabric/Composition/UriImageManager.h +1 -1
- package/Microsoft.ReactNative/Fabric/FabricUIManagerModule.cpp +11 -18
- package/Microsoft.ReactNative/Fabric/FabricUIManagerModule.h +3 -5
- package/Microsoft.ReactNative/Fabric/WindowsImageManager.cpp +23 -11
- package/Microsoft.ReactNative/Fabric/WindowsImageManager.h +5 -2
- package/Microsoft.ReactNative/Fabric/platform/react/renderer/components/view/HostPlatformViewEventEmitter.cpp +2 -10
- package/Microsoft.ReactNative/Fabric/platform/react/renderer/textlayoutmanager/TextLayoutManager.cpp +107 -36
- package/Microsoft.ReactNative/Fabric/platform/react/renderer/textlayoutmanager/TextLayoutManager.h +18 -12
- package/Microsoft.ReactNative/Modules/DevSettingsModule.cpp +4 -0
- package/Microsoft.ReactNative/Modules/DevSettingsModule.h +1 -0
- package/Microsoft.ReactNative/Modules/ImageViewManagerModule.cpp +1 -2
- package/Microsoft.ReactNative/Modules/NativeUIManager.cpp +7 -4
- package/Microsoft.ReactNative/Modules/NativeUIManager.h +1 -1
- package/Microsoft.ReactNative/Modules/PlatformConstantsWinModule.cpp +2 -2
- package/Microsoft.ReactNative/Modules/PlatformConstantsWinModule.h +3 -3
- package/Microsoft.ReactNative/ReactHost/ReactInstanceWin.cpp +11 -17
- package/Microsoft.ReactNative/ReactHost/ReactInstanceWin.h +1 -1
- package/Microsoft.ReactNative/Timer.idl +1 -3
- package/Microsoft.ReactNative/Utils/BatchingEventEmitter.cpp +1 -1
- package/Microsoft.ReactNative/Utils/LocalBundleReader.cpp +2 -3
- package/Microsoft.ReactNative/Utils/ValueUtils.cpp +1 -1
- package/Microsoft.ReactNative/Views/DynamicAutomationPeer.cpp +2 -2
- package/Microsoft.ReactNative/Views/TextInputViewManager.cpp +1 -1
- package/Microsoft.ReactNative/packages.lock.json +45 -72
- package/Microsoft.ReactNative.Cxx/JSI/LongLivedJsiValue.h +1 -1
- package/Microsoft.ReactNative.Cxx/Microsoft.ReactNative.Cxx.vcxitems +5 -0
- package/Microsoft.ReactNative.Cxx/Microsoft.ReactNative.Cxx.vcxitems.filters +1 -0
- package/Microsoft.ReactNative.Cxx/TurboModuleProvider.cpp +14 -6
- package/Microsoft.ReactNative.Cxx/TurboModuleProvider.h +2 -2
- package/Microsoft.ReactNative.Managed/Microsoft.ReactNative.Managed.csproj +1 -1
- package/Microsoft.ReactNative.Managed/packages.lock.json +3 -3
- package/PropertySheets/ARM64EC.props +13 -0
- package/PropertySheets/Application/ARM64EC.props +13 -0
- package/PropertySheets/DynamicLibrary/ARM64EC.props +13 -0
- package/PropertySheets/External/Microsoft.ReactNative.WindowsSdk.Default.props +4 -4
- package/PropertySheets/Generated/PackageVersion.g.props +4 -4
- package/PropertySheets/JSEngine.props +2 -0
- package/PropertySheets/StaticLibrary/ARM64EC.props +13 -0
- package/README.md +21 -21
- package/ReactCommon/ReactCommon.vcxproj +11 -1
- package/ReactCommon/ReactCommon.vcxproj.filters +19 -12
- package/ReactCommon/TEMP_UntilReactCommonUpdate/cxxreact/JSExecutor.cpp +67 -0
- package/ReactCommon/TEMP_UntilReactCommonUpdate/cxxreact/JSExecutor.h +180 -0
- package/ReactCommon/TEMP_UntilReactCommonUpdate/cxxreact/NativeToJsBridge.cpp +351 -0
- package/ReactCommon/TEMP_UntilReactCommonUpdate/jsi/jsi/test/testlib.cpp +6 -3
- package/ReactCommon/TEMP_UntilReactCommonUpdate/react/bridging/Base.h +152 -0
- package/ReactCommon/TEMP_UntilReactCommonUpdate/react/bridging/Bridging.h +2 -1
- package/ReactCommon/TEMP_UntilReactCommonUpdate/react/bridging/CallbackWrapper.h +13 -15
- package/ReactCommon/TEMP_UntilReactCommonUpdate/react/bridging/EventEmitter.h +137 -0
- package/ReactCommon/TEMP_UntilReactCommonUpdate/react/bridging/Function.h +283 -0
- package/ReactCommon/TEMP_UntilReactCommonUpdate/react/nativemodule/core/ReactCommon/TurboModule.cpp +7 -10
- package/ReactCommon/TEMP_UntilReactCommonUpdate/react/nativemodule/core/ReactCommon/TurboModule.h +162 -0
- package/ReactCommon/TEMP_UntilReactCommonUpdate/react/nativemodule/core/ReactCommon/TurboModuleUtils.h +2 -4
- package/ReactCommon/TEMP_UntilReactCommonUpdate/react/renderer/components/scrollview/ScrollViewProps.cpp +33 -8
- package/ReactCommon/TEMP_UntilReactCommonUpdate/react/runtime/JSRuntimeFactory.cpp +45 -0
- package/ReactCommon/TEMP_UntilReactCommonUpdate/react/runtime/JSRuntimeFactory.h +67 -0
- package/ReactCommon/TEMP_UntilReactCommonUpdate/react/runtime/ReactInstance.cpp +104 -74
- package/Scripts/StripAdditionalPlatformsFromNuspec.ps1 +1 -1
- package/Scripts/Tfs/Layout-MSRN-Headers.ps1 +10 -6
- package/Scripts/rnw-dependencies.ps1 +36 -23
- package/Shared/HermesRuntimeHolder.cpp +19 -1
- package/Shared/HermesRuntimeHolder.h +8 -1
- package/Shared/HermesSamplingProfiler.cpp +1 -2
- package/Shared/Networking/WinRTWebSocketResource.cpp +3 -3
- package/Shared/OInstance.cpp +1 -2
- package/Shared/Shared.vcxitems +21 -15
- package/Shared/Shared.vcxitems.filters +8 -3
- package/Shared/Threading/BatchingQueueThread.cpp +6 -2
- package/Shared/Threading/BatchingQueueThread.h +2 -2
- package/Shared/Utils/CppWinrtLessExceptions.h +2 -2
- package/codegen/NativeAppStateSpec.g.h +8 -8
- package/codegen/NativeBlobModuleSpec.g.h +0 -10
- package/codegen/NativeDOMSpec.g.h +136 -0
- package/codegen/NativeDevSettingsSpec.g.h +11 -5
- package/codegen/NativeIdleCallbacksSpec.g.h +64 -0
- package/codegen/NativeIntersectionObserverSpec.g.h +14 -14
- package/codegen/NativeMicrotasksSpec.g.h +34 -0
- package/codegen/NativePerformanceSpec.g.h +35 -7
- package/codegen/NativePlatformConstantsWindowsSpec.g.h +81 -0
- package/codegen/NativePushNotificationManagerIOSSpec.g.h +15 -19
- package/codegen/NativeReactNativeFeatureFlagsSpec.g.h +111 -39
- package/codegen/NativeUIManagerSpec.g.h +5 -17
- package/codegen/react/components/rnwcore/Props.cpp +1 -1
- package/codegen/react/components/rnwcore/Props.h +16 -12
- package/codegen/react/components/rnwcore/States.h +0 -26
- package/codegen/rnwcoreJSI-generated.cpp +688 -463
- package/codegen/rnwcoreJSI.h +1374 -2867
- package/fmt/TEMP_UntilFmtUpdate/core.h +2925 -0
- package/fmt/fmt.vcxproj +10 -2
- package/jest/mockComponent.js +7 -0
- package/jest/renderer.js +25 -14
- package/jest/setup.js +19 -13
- package/package.json +29 -27
- package/rn-get-polyfills.js +1 -0
- package/src/private/core/composeStyles.js +27 -0
- package/src/private/featureflags/ReactNativeFeatureFlags.js +93 -33
- package/src/private/featureflags/ReactNativeFeatureFlagsBase.js +23 -4
- package/src/private/featureflags/specs/NativeReactNativeFeatureFlags.js +56 -0
- package/src/private/fusebox/setUpFuseboxReactDevToolsDispatcher.js +108 -0
- package/src/private/specs/modules/NativeBlobModule.js +4 -2
- package/src/private/specs/modules/NativeDevSettings.js +1 -0
- package/src/private/specs/modules/NativePushNotificationManagerIOS.js +0 -4
- package/src/private/specs/modules/NativeUIManager.js +0 -7
- package/src/private/webapis/dom/geometry/DOMRectReadOnly.js +24 -24
- package/src/private/webapis/dom/nodes/ReactNativeElement.js +11 -14
- package/src/private/webapis/dom/nodes/ReadOnlyCharacterData.js +2 -3
- package/src/private/webapis/dom/nodes/ReadOnlyElement.js +24 -54
- package/src/private/webapis/dom/nodes/ReadOnlyNode.js +5 -13
- package/src/private/webapis/dom/nodes/specs/NativeDOM.js +468 -0
- package/src/private/webapis/dom/nodes/specs/__mocks__/NativeDOMMock.js +413 -0
- package/src/private/webapis/dom/oldstylecollections/DOMRectList.js +4 -4
- package/src/private/webapis/dom/oldstylecollections/HTMLCollection.js +4 -4
- package/src/private/webapis/dom/oldstylecollections/NodeList.js +5 -5
- package/src/private/webapis/idlecallbacks/specs/NativeIdleCallbacks.js +34 -0
- package/src/private/webapis/microtasks/specs/NativeMicrotasks.js +21 -0
- package/src/private/webapis/performance/EventCounts.js +1 -1
- package/src/private/webapis/performance/MemoryInfo.js +9 -9
- package/src/private/webapis/performance/Performance.js +10 -56
- package/src/private/webapis/performance/PerformanceObserver.js +30 -22
- package/src/private/webapis/performance/RawPerformanceEntry.js +2 -7
- package/src/private/webapis/performance/ReactNativeStartupTiming.js +18 -18
- package/src/private/webapis/performance/UserTiming.js +63 -0
- package/src/private/webapis/performance/{NativePerformance.js → specs/NativePerformance.js} +3 -2
- package/src/private/webapis/performance/{NativePerformanceObserver.js → specs/NativePerformanceObserver.js} +2 -2
- package/src/private/webapis/performance/{__mocks__ → specs/__mocks__}/NativePerformance.js +1 -1
- package/src/private/webapis/performance/{__mocks__ → specs/__mocks__}/NativePerformanceObserver.js +3 -4
- package/stubs/glog/logging.h +1 -0
- package/template/cpp-lib/proj/MyLib.vcxproj +1 -1
- package/template/cs-lib/proj/MyLib.csproj +1 -1
- package/template/metro.config.js +13 -2
- package/templates/cpp-app/template.config.js +1 -1
- package/templates/cpp-lib/example/metro.config.js +2 -2
- package/templates/cpp-lib/template.config.js +1 -1
- package/templates/old/generateWrapper.js +4 -1
- package/types/modules/globals.d.ts +4 -0
- package/Libraries/Lists/FlatList.windows.js +0 -717
- package/Libraries/NativeModules/specs/NativeAnimationsDebugModule.js +0 -13
- package/Libraries/Utilities/LoadingView.ios.js +0 -50
- package/Libraries/Utilities/LoadingView.js +0 -16
- package/ReactCommon/TEMP_UntilReactCommonUpdate/react/nativemodule/core/ReactCommon/TurboModuleBinding.cpp +0 -178
- package/ReactCommon/TEMP_UntilReactCommonUpdate/react/utils/jsi-utils.cpp +0 -39
- package/ReactCommon/TEMP_UntilReactCommonUpdate/react/utils/jsi-utils.h +0 -31
- package/ReactCommon/TEMP_UntilReactCommonUpdate/yoga/yoga/YGEnums.h +0 -137
- package/ReactCommon/TEMP_UntilReactCommonUpdate/yoga/yoga/algorithm/CalculateLayout.cpp +0 -2375
- package/ReactCommon/TEMP_UntilReactCommonUpdate/yoga/yoga/enums/ExperimentalFeature.h +0 -40
- package/codegen/NativeAnimationsDebugModuleSpec.g.h +0 -40
- package/codegen/NativePlatformConstantsWinSpec.g.h +0 -81
- package/jest/ReactNativeInternalFeatureFlagsMock.js +0 -13
- package/src/private/featureflags/NativeReactNativeFeatureFlags.js +0 -44
- package/src/private/featureflags/__tests__/ReactNativeFeatureFlags-test.js +0 -92
- package/src/private/specs/modules/NativeAnimationsDebugModule.js +0 -20
- package/src/private/webapis/dom/oldstylecollections/__tests__/DOMRectList-test.js +0 -85
- package/src/private/webapis/dom/oldstylecollections/__tests__/HTMLCollection-test.js +0 -80
- package/src/private/webapis/dom/oldstylecollections/__tests__/NodeList-test.js +0 -161
- package/src/private/webapis/performance/__tests__/EventCounts-test.js +0 -116
- package/src/private/webapis/performance/__tests__/NativePerformanceMock-test.js +0 -82
- package/src/private/webapis/performance/__tests__/NativePerformanceObserverMock-test.js +0 -108
- package/src/private/webapis/performance/__tests__/Performance-test.js +0 -117
- package/src/private/webapis/performance/__tests__/PerformanceObserver-test.js +0 -208
- package/template/metro.devMode.config.js +0 -56
- /package/src/private/specs/modules/{NativePlatformConstantsWin.js → NativePlatformConstantsWindows.js} +0 -0
|
@@ -0,0 +1,1110 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
3
|
+
*
|
|
4
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
* you may not use this file except in compliance with the License.
|
|
6
|
+
* You may obtain a copy of the License at
|
|
7
|
+
*
|
|
8
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
*
|
|
10
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
* See the License for the specific language governing permissions and
|
|
14
|
+
* limitations under the License.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
#include <folly/json.h>
|
|
18
|
+
|
|
19
|
+
#include <algorithm>
|
|
20
|
+
#include <functional>
|
|
21
|
+
#include <iterator>
|
|
22
|
+
#include <sstream>
|
|
23
|
+
#include <type_traits>
|
|
24
|
+
|
|
25
|
+
#include <boost/algorithm/string.hpp>
|
|
26
|
+
#include <glog/logging.h>
|
|
27
|
+
|
|
28
|
+
#include <folly/Conv.h>
|
|
29
|
+
#include <folly/Portability.h>
|
|
30
|
+
#include <folly/Range.h>
|
|
31
|
+
#include <folly/String.h>
|
|
32
|
+
#include <folly/Unicode.h>
|
|
33
|
+
#include <folly/Utility.h>
|
|
34
|
+
#include <folly/lang/Bits.h>
|
|
35
|
+
#include <folly/portability/Constexpr.h>
|
|
36
|
+
|
|
37
|
+
namespace folly {
|
|
38
|
+
|
|
39
|
+
//////////////////////////////////////////////////////////////////////
|
|
40
|
+
|
|
41
|
+
namespace json {
|
|
42
|
+
|
|
43
|
+
namespace {
|
|
44
|
+
|
|
45
|
+
parse_error make_parse_error(
|
|
46
|
+
unsigned int line,
|
|
47
|
+
std::string const& context,
|
|
48
|
+
std::string const& expected) {
|
|
49
|
+
return parse_error(to<std::string>(
|
|
50
|
+
"json parse error on line ",
|
|
51
|
+
line,
|
|
52
|
+
!context.empty() ? to<std::string>(" near `", context, '\'') : "",
|
|
53
|
+
": ",
|
|
54
|
+
expected));
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
struct Printer {
|
|
58
|
+
// Context class is allows to restore the path to element that we are about to
|
|
59
|
+
// print so that if error happens we can throw meaningful exception.
|
|
60
|
+
class Context {
|
|
61
|
+
public:
|
|
62
|
+
Context(const Context* parent_context, const dynamic& key)
|
|
63
|
+
: parent_context_(parent_context), key_(key), is_key_(false) {}
|
|
64
|
+
Context(const Context* parent_context, const dynamic& key, bool is_key)
|
|
65
|
+
: parent_context_(parent_context), key_(key), is_key_(is_key) {}
|
|
66
|
+
|
|
67
|
+
// Return location description of a context as a chain of keys
|
|
68
|
+
// ex., '"outherKey"->"innerKey"'.
|
|
69
|
+
std::string locationDescription() const {
|
|
70
|
+
std::vector<std::string> keys;
|
|
71
|
+
const Context* ptr = parent_context_;
|
|
72
|
+
while (ptr) {
|
|
73
|
+
keys.push_back(ptr->getName());
|
|
74
|
+
ptr = ptr->parent_context_;
|
|
75
|
+
}
|
|
76
|
+
keys.push_back(getName());
|
|
77
|
+
std::ostringstream stream;
|
|
78
|
+
std::reverse_copy(
|
|
79
|
+
keys.begin(),
|
|
80
|
+
keys.end() - 1,
|
|
81
|
+
std::ostream_iterator<std::string>(stream, "->"));
|
|
82
|
+
|
|
83
|
+
// Add current key.
|
|
84
|
+
stream << keys.back();
|
|
85
|
+
return stream.str();
|
|
86
|
+
}
|
|
87
|
+
std::string getName() const {
|
|
88
|
+
return Printer::toStringOr(key_, "<unprintable>");
|
|
89
|
+
}
|
|
90
|
+
std::string typeDescription() const { return is_key_ ? "key" : "value"; }
|
|
91
|
+
|
|
92
|
+
private:
|
|
93
|
+
const Context* const parent_context_;
|
|
94
|
+
const dynamic& key_;
|
|
95
|
+
bool is_key_;
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
explicit Printer(
|
|
99
|
+
std::string& out, unsigned* indentLevel, serialization_opts const* opts)
|
|
100
|
+
: out_(out), indentLevel_(indentLevel), opts_(*opts) {}
|
|
101
|
+
|
|
102
|
+
void operator()(dynamic const& v, const Context& context) const {
|
|
103
|
+
(*this)(v, &context);
|
|
104
|
+
}
|
|
105
|
+
void operator()(dynamic const& v, const Context* context) const {
|
|
106
|
+
switch (v.type()) {
|
|
107
|
+
case dynamic::DOUBLE:
|
|
108
|
+
if (!opts_.allow_nan_inf) {
|
|
109
|
+
if (std::isnan(v.asDouble())) {
|
|
110
|
+
throw json::print_error(
|
|
111
|
+
"folly::toJson: JSON object value was a NaN when serializing " +
|
|
112
|
+
contextDescription(context));
|
|
113
|
+
}
|
|
114
|
+
if (std::isinf(v.asDouble())) {
|
|
115
|
+
throw json::print_error(
|
|
116
|
+
"folly::toJson: JSON object value was an INF when serializing " +
|
|
117
|
+
contextDescription(context));
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
toAppend(
|
|
121
|
+
v.asDouble(),
|
|
122
|
+
&out_,
|
|
123
|
+
opts_.double_mode,
|
|
124
|
+
opts_.double_num_digits,
|
|
125
|
+
opts_.double_flags);
|
|
126
|
+
break;
|
|
127
|
+
case dynamic::INT64: {
|
|
128
|
+
auto intval = v.asInt();
|
|
129
|
+
if (opts_.javascript_safe) {
|
|
130
|
+
// Use folly::to to check that this integer can be represented
|
|
131
|
+
// as a double without loss of precision.
|
|
132
|
+
intval = int64_t(to<double>(intval));
|
|
133
|
+
}
|
|
134
|
+
toAppend(intval, &out_);
|
|
135
|
+
break;
|
|
136
|
+
}
|
|
137
|
+
case dynamic::BOOL:
|
|
138
|
+
out_ += v.asBool() ? "true" : "false";
|
|
139
|
+
break;
|
|
140
|
+
case dynamic::NULLT:
|
|
141
|
+
out_ += "null";
|
|
142
|
+
break;
|
|
143
|
+
case dynamic::STRING:
|
|
144
|
+
escapeString(v.stringPiece(), out_, opts_);
|
|
145
|
+
break;
|
|
146
|
+
case dynamic::OBJECT:
|
|
147
|
+
printObject(v, context);
|
|
148
|
+
break;
|
|
149
|
+
case dynamic::ARRAY:
|
|
150
|
+
printArray(v, context);
|
|
151
|
+
break;
|
|
152
|
+
default:
|
|
153
|
+
CHECK(0) << "Bad type " << v.type();
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
private:
|
|
158
|
+
void printKV(
|
|
159
|
+
dynamic const& o,
|
|
160
|
+
const std::pair<const dynamic, dynamic>& p,
|
|
161
|
+
const Context* context) const {
|
|
162
|
+
if (opts_.convert_int_keys && p.first.isInt()) {
|
|
163
|
+
auto strKey = p.first.asString();
|
|
164
|
+
if (o.count(strKey)) {
|
|
165
|
+
throw json::print_error(folly::to<std::string>(
|
|
166
|
+
"folly::toJson: Source object has integer and string keys "
|
|
167
|
+
"representing the same value: ",
|
|
168
|
+
p.first.asInt()));
|
|
169
|
+
}
|
|
170
|
+
(*this)(p.first.asString(), Context(context, p.first, true));
|
|
171
|
+
} else if (!opts_.allow_non_string_keys && !p.first.isString()) {
|
|
172
|
+
throw json::print_error(
|
|
173
|
+
"folly::toJson: JSON object key " +
|
|
174
|
+
toStringOr(p.first, "<unprintable key>") + " was not a string " +
|
|
175
|
+
(opts_.convert_int_keys ? "or integer " : "") +
|
|
176
|
+
"when serializing key at " +
|
|
177
|
+
Context(context, p.first, true).locationDescription());
|
|
178
|
+
} else {
|
|
179
|
+
(*this)(p.first, Context(context, p.first, true)); // Key
|
|
180
|
+
}
|
|
181
|
+
mapColon();
|
|
182
|
+
(*this)(p.second, Context(context, p.first, false)); // Value
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
template <typename Iterator>
|
|
186
|
+
void printKVPairs(
|
|
187
|
+
dynamic const& o,
|
|
188
|
+
Iterator begin,
|
|
189
|
+
Iterator end,
|
|
190
|
+
const Context* context) const {
|
|
191
|
+
printKV(o, *begin, context);
|
|
192
|
+
for (++begin; begin != end; ++begin) {
|
|
193
|
+
out_ += ',';
|
|
194
|
+
newline();
|
|
195
|
+
printKV(o, *begin, context);
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
void printObject(dynamic const& o, const Context* context) const {
|
|
200
|
+
if (o.empty()) {
|
|
201
|
+
out_ += "{}";
|
|
202
|
+
return;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
out_ += '{';
|
|
206
|
+
indent();
|
|
207
|
+
newline();
|
|
208
|
+
if (opts_.sort_keys || opts_.sort_keys_by) {
|
|
209
|
+
using ref = std::reference_wrapper<decltype(o.items())::value_type const>;
|
|
210
|
+
auto sort_keys_by = [&](auto begin, auto end, const auto& comp) {
|
|
211
|
+
std::sort(begin, end, [&](ref a, ref b) {
|
|
212
|
+
// Only compare keys. No ordering among identical keys.
|
|
213
|
+
return comp(a.get().first, b.get().first);
|
|
214
|
+
});
|
|
215
|
+
};
|
|
216
|
+
std::vector<ref> refs(o.items().begin(), o.items().end());
|
|
217
|
+
if (opts_.sort_keys_by) {
|
|
218
|
+
sort_keys_by(refs.begin(), refs.end(), opts_.sort_keys_by);
|
|
219
|
+
} else {
|
|
220
|
+
sort_keys_by(refs.begin(), refs.end(), std::less<>());
|
|
221
|
+
}
|
|
222
|
+
printKVPairs(o, refs.cbegin(), refs.cend(), context);
|
|
223
|
+
} else {
|
|
224
|
+
printKVPairs(o, o.items().begin(), o.items().end(), context);
|
|
225
|
+
}
|
|
226
|
+
outdent();
|
|
227
|
+
newline();
|
|
228
|
+
out_ += '}';
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
static std::string toStringOr(dynamic const& v, const char* placeholder) {
|
|
232
|
+
try {
|
|
233
|
+
std::string result;
|
|
234
|
+
unsigned indentLevel = 0;
|
|
235
|
+
serialization_opts opts;
|
|
236
|
+
opts.allow_nan_inf = true;
|
|
237
|
+
opts.allow_non_string_keys = true;
|
|
238
|
+
Printer printer(result, &indentLevel, &opts);
|
|
239
|
+
printer(v, nullptr);
|
|
240
|
+
return result;
|
|
241
|
+
} catch (...) {
|
|
242
|
+
return placeholder;
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
static std::string contextDescription(const Context* context) {
|
|
247
|
+
if (!context) {
|
|
248
|
+
return "<undefined location>";
|
|
249
|
+
}
|
|
250
|
+
return context->typeDescription() + " at " + context->locationDescription();
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
void printArray(dynamic const& a, const Context* context) const {
|
|
254
|
+
if (a.empty()) {
|
|
255
|
+
out_ += "[]";
|
|
256
|
+
return;
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
out_ += '[';
|
|
260
|
+
indent();
|
|
261
|
+
newline();
|
|
262
|
+
(*this)(a[0], Context(context, dynamic(0)));
|
|
263
|
+
for (auto it = std::next(a.begin()); it != a.end(); ++it) {
|
|
264
|
+
out_ += ',';
|
|
265
|
+
newline();
|
|
266
|
+
(*this)(*it, Context(context, dynamic(std::distance(a.begin(), it))));
|
|
267
|
+
}
|
|
268
|
+
outdent();
|
|
269
|
+
newline();
|
|
270
|
+
out_ += ']';
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
private:
|
|
274
|
+
void outdent() const {
|
|
275
|
+
if (indentLevel_) {
|
|
276
|
+
--*indentLevel_;
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
void indent() const {
|
|
281
|
+
if (indentLevel_) {
|
|
282
|
+
++*indentLevel_;
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
void newline() const {
|
|
287
|
+
if (indentLevel_) {
|
|
288
|
+
auto indent = *indentLevel_ * opts_.pretty_formatting_indent_width;
|
|
289
|
+
out_ += to<std::string>('\n', std::string(indent, ' '));
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
void mapColon() const { out_ += indentLevel_ ? ": " : ":"; }
|
|
294
|
+
|
|
295
|
+
private:
|
|
296
|
+
std::string& out_;
|
|
297
|
+
unsigned* const indentLevel_;
|
|
298
|
+
serialization_opts const& opts_;
|
|
299
|
+
};
|
|
300
|
+
|
|
301
|
+
//////////////////////////////////////////////////////////////////////
|
|
302
|
+
|
|
303
|
+
// Wraps our input buffer with some helper functions.
|
|
304
|
+
struct Input {
|
|
305
|
+
explicit Input(StringPiece range, json::serialization_opts const* opts)
|
|
306
|
+
: range_(range), opts_(*opts), lineNum_(0) {
|
|
307
|
+
storeCurrent();
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
Input(Input const&) = delete;
|
|
311
|
+
Input& operator=(Input const&) = delete;
|
|
312
|
+
|
|
313
|
+
char const* begin() const { return range_.begin(); }
|
|
314
|
+
|
|
315
|
+
unsigned getLineNum() const { return lineNum_; }
|
|
316
|
+
|
|
317
|
+
// Parse ahead for as long as the supplied predicate is satisfied,
|
|
318
|
+
// returning a range of what was skipped.
|
|
319
|
+
template <class Predicate>
|
|
320
|
+
StringPiece skipWhile(const Predicate& p) {
|
|
321
|
+
std::size_t skipped = 0;
|
|
322
|
+
for (; skipped < range_.size(); ++skipped) {
|
|
323
|
+
if (!p(range_[skipped])) {
|
|
324
|
+
break;
|
|
325
|
+
}
|
|
326
|
+
if (range_[skipped] == '\n') {
|
|
327
|
+
++lineNum_;
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
auto ret = range_.subpiece(0, skipped);
|
|
331
|
+
range_.advance(skipped);
|
|
332
|
+
storeCurrent();
|
|
333
|
+
return ret;
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
StringPiece skipDigits() {
|
|
337
|
+
return skipWhile([](char c) { return c >= '0' && c <= '9'; });
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
StringPiece skipMinusAndDigits() {
|
|
341
|
+
bool firstChar = true;
|
|
342
|
+
return skipWhile([&firstChar](char c) {
|
|
343
|
+
bool result = (c >= '0' && c <= '9') || (firstChar && c == '-');
|
|
344
|
+
firstChar = false;
|
|
345
|
+
return result;
|
|
346
|
+
});
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
void skipWhitespace() {
|
|
350
|
+
// [Windows #12703 - CodeQL patch]
|
|
351
|
+
std::size_t index = 0;
|
|
352
|
+
while (true) {
|
|
353
|
+
while (index < range_.size() && range_[index] == ' ') {
|
|
354
|
+
index++;
|
|
355
|
+
}
|
|
356
|
+
if (index < range_.size()) {
|
|
357
|
+
if (range_[index] == '\n') {
|
|
358
|
+
index++;
|
|
359
|
+
++lineNum_;
|
|
360
|
+
continue;
|
|
361
|
+
}
|
|
362
|
+
if (range_[index] == '\t' || range_[index] == '\r') {
|
|
363
|
+
index++;
|
|
364
|
+
continue;
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
break;
|
|
368
|
+
}
|
|
369
|
+
range_.advance(index);
|
|
370
|
+
storeCurrent();
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
void expect(char c) {
|
|
374
|
+
if (**this != c) {
|
|
375
|
+
throw json::make_parse_error(
|
|
376
|
+
lineNum_, context(), to<std::string>("expected '", c, '\''));
|
|
377
|
+
}
|
|
378
|
+
++*this;
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
std::size_t size() const { return range_.size(); }
|
|
382
|
+
|
|
383
|
+
int operator*() const { return current_; }
|
|
384
|
+
|
|
385
|
+
void operator++() {
|
|
386
|
+
range_.pop_front();
|
|
387
|
+
storeCurrent();
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
template <class T>
|
|
391
|
+
T extract() {
|
|
392
|
+
try {
|
|
393
|
+
return to<T>(&range_);
|
|
394
|
+
} catch (std::exception const& e) {
|
|
395
|
+
error(e.what());
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
bool consume(StringPiece str) {
|
|
400
|
+
if (boost::starts_with(range_, str)) {
|
|
401
|
+
range_.advance(str.size());
|
|
402
|
+
storeCurrent();
|
|
403
|
+
return true;
|
|
404
|
+
}
|
|
405
|
+
return false;
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
std::string context() const {
|
|
409
|
+
return range_.subpiece(0, 16 /* arbitrary */).toString();
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
[[noreturn]] dynamic error(char const* what) const {
|
|
413
|
+
throw json::make_parse_error(lineNum_, context(), what);
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
json::serialization_opts const& getOpts() { return opts_; }
|
|
417
|
+
|
|
418
|
+
void incrementRecursionLevel() {
|
|
419
|
+
if (currentRecursionLevel_ > opts_.recursion_limit) {
|
|
420
|
+
error("recursion limit exceeded");
|
|
421
|
+
}
|
|
422
|
+
currentRecursionLevel_++;
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
void decrementRecursionLevel() { currentRecursionLevel_--; }
|
|
426
|
+
|
|
427
|
+
private:
|
|
428
|
+
void storeCurrent() { current_ = range_.empty() ? EOF : range_.front(); }
|
|
429
|
+
|
|
430
|
+
private:
|
|
431
|
+
StringPiece range_;
|
|
432
|
+
json::serialization_opts const& opts_;
|
|
433
|
+
unsigned lineNum_;
|
|
434
|
+
int current_;
|
|
435
|
+
unsigned int currentRecursionLevel_{0};
|
|
436
|
+
};
|
|
437
|
+
|
|
438
|
+
class RecursionGuard {
|
|
439
|
+
public:
|
|
440
|
+
explicit RecursionGuard(Input& in) : in_(in) {
|
|
441
|
+
in_.incrementRecursionLevel();
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
~RecursionGuard() { in_.decrementRecursionLevel(); }
|
|
445
|
+
|
|
446
|
+
private:
|
|
447
|
+
Input& in_;
|
|
448
|
+
};
|
|
449
|
+
|
|
450
|
+
dynamic parseValue(Input& in, json::metadata_map* map);
|
|
451
|
+
std::string parseString(Input& in);
|
|
452
|
+
dynamic parseNumber(Input& in);
|
|
453
|
+
|
|
454
|
+
void parseObjectKeyValue(
|
|
455
|
+
Input& in,
|
|
456
|
+
dynamic& ret,
|
|
457
|
+
dynamic&& key,
|
|
458
|
+
json::metadata_map* map,
|
|
459
|
+
bool distinct) {
|
|
460
|
+
auto keyLineNumber = in.getLineNum();
|
|
461
|
+
in.skipWhitespace();
|
|
462
|
+
in.expect(':');
|
|
463
|
+
in.skipWhitespace();
|
|
464
|
+
auto valueLineNumber = in.getLineNum();
|
|
465
|
+
auto value = parseValue(in, map);
|
|
466
|
+
auto [it, inserted] = ret.try_emplace(std::move(key), std::move(value));
|
|
467
|
+
if (!inserted) {
|
|
468
|
+
if (distinct) {
|
|
469
|
+
in.error("duplicate key inserted");
|
|
470
|
+
}
|
|
471
|
+
it->second = std::move(value);
|
|
472
|
+
}
|
|
473
|
+
if (map) {
|
|
474
|
+
map->emplace(
|
|
475
|
+
&it->second,
|
|
476
|
+
json::parse_metadata{{{keyLineNumber}}, {{valueLineNumber}}});
|
|
477
|
+
}
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
dynamic parseObject(Input& in, json::metadata_map* map) {
|
|
481
|
+
DCHECK_EQ(*in, '{');
|
|
482
|
+
++in;
|
|
483
|
+
|
|
484
|
+
dynamic ret = dynamic::object;
|
|
485
|
+
|
|
486
|
+
in.skipWhitespace();
|
|
487
|
+
if (*in == '}') {
|
|
488
|
+
++in;
|
|
489
|
+
return ret;
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
const auto& opts = in.getOpts();
|
|
493
|
+
const bool distinct = opts.validate_keys || opts.convert_int_keys;
|
|
494
|
+
for (;;) {
|
|
495
|
+
if (opts.allow_trailing_comma && *in == '}') {
|
|
496
|
+
break;
|
|
497
|
+
}
|
|
498
|
+
dynamic key = parseValue(in, map);
|
|
499
|
+
if (opts.convert_int_keys && key.isInt()) {
|
|
500
|
+
key = key.asString();
|
|
501
|
+
} else if (!opts.allow_non_string_keys && !key.isString()) {
|
|
502
|
+
in.error(
|
|
503
|
+
opts.convert_int_keys ? "expected string or integer for object key"
|
|
504
|
+
: "expected string for object key");
|
|
505
|
+
}
|
|
506
|
+
parseObjectKeyValue(in, ret, std::move(key), map, distinct);
|
|
507
|
+
|
|
508
|
+
in.skipWhitespace();
|
|
509
|
+
if (*in != ',') {
|
|
510
|
+
break;
|
|
511
|
+
}
|
|
512
|
+
++in;
|
|
513
|
+
in.skipWhitespace();
|
|
514
|
+
}
|
|
515
|
+
in.expect('}');
|
|
516
|
+
|
|
517
|
+
return ret;
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
dynamic parseArray(Input& in, json::metadata_map* map) {
|
|
521
|
+
DCHECK_EQ(*in, '[');
|
|
522
|
+
++in;
|
|
523
|
+
|
|
524
|
+
dynamic ret = dynamic::array;
|
|
525
|
+
|
|
526
|
+
in.skipWhitespace();
|
|
527
|
+
if (*in == ']') {
|
|
528
|
+
++in;
|
|
529
|
+
return ret;
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
std::vector<uint32_t> lineNumbers;
|
|
533
|
+
for (;;) {
|
|
534
|
+
if (in.getOpts().allow_trailing_comma && *in == ']') {
|
|
535
|
+
break;
|
|
536
|
+
}
|
|
537
|
+
ret.push_back(parseValue(in, map));
|
|
538
|
+
if (map) {
|
|
539
|
+
lineNumbers.push_back(in.getLineNum());
|
|
540
|
+
}
|
|
541
|
+
in.skipWhitespace();
|
|
542
|
+
if (*in != ',') {
|
|
543
|
+
break;
|
|
544
|
+
}
|
|
545
|
+
++in;
|
|
546
|
+
in.skipWhitespace();
|
|
547
|
+
}
|
|
548
|
+
if (map) {
|
|
549
|
+
for (size_t i = 0, e = ret.size(); i < e; i++) {
|
|
550
|
+
map->emplace(&ret[i], json::parse_metadata{{{0}}, {{lineNumbers[i]}}});
|
|
551
|
+
}
|
|
552
|
+
}
|
|
553
|
+
in.expect(']');
|
|
554
|
+
|
|
555
|
+
return ret;
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
dynamic parseNumber(Input& in) {
|
|
559
|
+
bool const negative = (*in == '-');
|
|
560
|
+
if (negative && in.consume("-Infinity")) {
|
|
561
|
+
if (in.getOpts().parse_numbers_as_strings) {
|
|
562
|
+
return "-Infinity";
|
|
563
|
+
} else {
|
|
564
|
+
return -std::numeric_limits<double>::infinity();
|
|
565
|
+
}
|
|
566
|
+
}
|
|
567
|
+
|
|
568
|
+
auto integral = in.skipMinusAndDigits();
|
|
569
|
+
if (negative && integral.size() < 2) {
|
|
570
|
+
in.error("expected digits after `-'");
|
|
571
|
+
}
|
|
572
|
+
|
|
573
|
+
auto const wasE = *in == 'e' || *in == 'E';
|
|
574
|
+
|
|
575
|
+
if (*in != '.' && !wasE && in.getOpts().parse_numbers_as_strings) {
|
|
576
|
+
return integral;
|
|
577
|
+
}
|
|
578
|
+
|
|
579
|
+
constexpr const char* maxIntStr = "9223372036854775807";
|
|
580
|
+
constexpr const char* minIntStr = "-9223372036854775808";
|
|
581
|
+
constexpr auto maxIntLen = constexpr_strlen(maxIntStr);
|
|
582
|
+
constexpr auto minIntLen = constexpr_strlen(minIntStr);
|
|
583
|
+
auto extremaLen = negative ? minIntLen : maxIntLen;
|
|
584
|
+
auto extremaStr = negative ? minIntStr : maxIntStr;
|
|
585
|
+
if (*in != '.' && !wasE) {
|
|
586
|
+
if (FOLLY_LIKELY(
|
|
587
|
+
!in.getOpts().double_fallback || integral.size() < extremaLen) ||
|
|
588
|
+
(integral.size() == extremaLen && integral <= extremaStr)) {
|
|
589
|
+
auto val = to<int64_t>(integral);
|
|
590
|
+
in.skipWhitespace();
|
|
591
|
+
return val;
|
|
592
|
+
} else {
|
|
593
|
+
auto val = to<double>(integral);
|
|
594
|
+
in.skipWhitespace();
|
|
595
|
+
return val;
|
|
596
|
+
}
|
|
597
|
+
}
|
|
598
|
+
|
|
599
|
+
auto end = !wasE ? (++in, in.skipDigits().end()) : in.begin();
|
|
600
|
+
if (*in == 'e' || *in == 'E') {
|
|
601
|
+
++in;
|
|
602
|
+
if (*in == '+' || *in == '-') {
|
|
603
|
+
++in;
|
|
604
|
+
}
|
|
605
|
+
auto expPart = in.skipDigits();
|
|
606
|
+
end = expPart.end();
|
|
607
|
+
}
|
|
608
|
+
auto fullNum = range(integral.begin(), end);
|
|
609
|
+
if (in.getOpts().parse_numbers_as_strings) {
|
|
610
|
+
return fullNum;
|
|
611
|
+
}
|
|
612
|
+
auto val = to<double>(fullNum);
|
|
613
|
+
return val;
|
|
614
|
+
}
|
|
615
|
+
|
|
616
|
+
void decodeUnicodeEscape(Input& in, std::string& out) {
|
|
617
|
+
auto hexVal = [&](int c) -> uint16_t {
|
|
618
|
+
// clang-format off
|
|
619
|
+
return uint16_t(
|
|
620
|
+
c >= '0' && c <= '9' ? c - '0' :
|
|
621
|
+
c >= 'a' && c <= 'f' ? c - 'a' + 10 :
|
|
622
|
+
c >= 'A' && c <= 'F' ? c - 'A' + 10 :
|
|
623
|
+
(in.error("invalid hex digit"), 0));
|
|
624
|
+
// clang-format on
|
|
625
|
+
};
|
|
626
|
+
|
|
627
|
+
auto readHex = [&]() -> uint16_t {
|
|
628
|
+
if (in.size() < 4) {
|
|
629
|
+
in.error("expected 4 hex digits");
|
|
630
|
+
}
|
|
631
|
+
|
|
632
|
+
auto ret = uint16_t(hexVal(*in) * 4096);
|
|
633
|
+
++in;
|
|
634
|
+
ret += hexVal(*in) * 256;
|
|
635
|
+
++in;
|
|
636
|
+
ret += hexVal(*in) * 16;
|
|
637
|
+
++in;
|
|
638
|
+
ret += hexVal(*in);
|
|
639
|
+
++in;
|
|
640
|
+
return ret;
|
|
641
|
+
};
|
|
642
|
+
|
|
643
|
+
// If the value encoded is in the surrogate pair range, we need to make
|
|
644
|
+
// sure there is another escape that we can use also.
|
|
645
|
+
//
|
|
646
|
+
// See the explanation in folly/Unicode.h.
|
|
647
|
+
uint16_t prefix = readHex();
|
|
648
|
+
char32_t codePoint = prefix;
|
|
649
|
+
if (utf16_code_unit_is_high_surrogate(prefix)) {
|
|
650
|
+
if (!in.consume("\\u")) {
|
|
651
|
+
in.error(
|
|
652
|
+
"expected another unicode escape for second half of "
|
|
653
|
+
"surrogate pair");
|
|
654
|
+
}
|
|
655
|
+
uint16_t suffix = readHex();
|
|
656
|
+
if (!utf16_code_unit_is_low_surrogate(suffix)) {
|
|
657
|
+
in.error("second character in surrogate pair is invalid");
|
|
658
|
+
}
|
|
659
|
+
codePoint = unicode_code_point_from_utf16_surrogate_pair(prefix, suffix);
|
|
660
|
+
} else if (!utf16_code_unit_is_bmp(prefix)) {
|
|
661
|
+
in.error("invalid unicode code point (in range [0xdc00,0xdfff])");
|
|
662
|
+
}
|
|
663
|
+
|
|
664
|
+
appendCodePointToUtf8(codePoint, out);
|
|
665
|
+
}
|
|
666
|
+
|
|
667
|
+
std::string parseString(Input& in) {
|
|
668
|
+
DCHECK_EQ(*in, '\"');
|
|
669
|
+
++in;
|
|
670
|
+
|
|
671
|
+
std::string ret;
|
|
672
|
+
for (;;) {
|
|
673
|
+
auto range = in.skipWhile([](char c) { return c != '\"' && c != '\\'; });
|
|
674
|
+
ret.append(range.begin(), range.end());
|
|
675
|
+
|
|
676
|
+
if (*in == '\"') {
|
|
677
|
+
++in;
|
|
678
|
+
break;
|
|
679
|
+
}
|
|
680
|
+
if (*in == '\\') {
|
|
681
|
+
++in;
|
|
682
|
+
switch (*in) {
|
|
683
|
+
// clang-format off
|
|
684
|
+
case '\"': ret.push_back('\"'); ++in; break;
|
|
685
|
+
case '\\': ret.push_back('\\'); ++in; break;
|
|
686
|
+
case '/': ret.push_back('/'); ++in; break;
|
|
687
|
+
case 'b': ret.push_back('\b'); ++in; break;
|
|
688
|
+
case 'f': ret.push_back('\f'); ++in; break;
|
|
689
|
+
case 'n': ret.push_back('\n'); ++in; break;
|
|
690
|
+
case 'r': ret.push_back('\r'); ++in; break;
|
|
691
|
+
case 't': ret.push_back('\t'); ++in; break;
|
|
692
|
+
case 'u': ++in; decodeUnicodeEscape(in, ret); break;
|
|
693
|
+
// clang-format on
|
|
694
|
+
default:
|
|
695
|
+
in.error(
|
|
696
|
+
to<std::string>("unknown escape ", *in, " in string").c_str());
|
|
697
|
+
}
|
|
698
|
+
continue;
|
|
699
|
+
}
|
|
700
|
+
if (*in == EOF) {
|
|
701
|
+
in.error("unterminated string");
|
|
702
|
+
}
|
|
703
|
+
if (!*in) {
|
|
704
|
+
/*
|
|
705
|
+
* Apparently we're actually supposed to ban all control
|
|
706
|
+
* characters from strings. This seems unnecessarily
|
|
707
|
+
* restrictive, so we're only banning zero bytes. (Since the
|
|
708
|
+
* string is presumed to be UTF-8 encoded it's fine to just
|
|
709
|
+
* check this way.)
|
|
710
|
+
*/
|
|
711
|
+
in.error("null byte in string");
|
|
712
|
+
}
|
|
713
|
+
|
|
714
|
+
ret.push_back(char(*in));
|
|
715
|
+
++in;
|
|
716
|
+
}
|
|
717
|
+
|
|
718
|
+
return ret;
|
|
719
|
+
}
|
|
720
|
+
|
|
721
|
+
dynamic parseValue(Input& in, json::metadata_map* map) {
|
|
722
|
+
RecursionGuard guard(in);
|
|
723
|
+
|
|
724
|
+
in.skipWhitespace();
|
|
725
|
+
// clang-format off
|
|
726
|
+
return
|
|
727
|
+
*in == '[' ? parseArray(in, map) :
|
|
728
|
+
*in == '{' ? parseObject(in, map) :
|
|
729
|
+
*in == '\"' ? parseString(in) :
|
|
730
|
+
(*in == '-' || (*in >= '0' && *in <= '9')) ? parseNumber(in) :
|
|
731
|
+
in.consume("true") ? true :
|
|
732
|
+
in.consume("false") ? false :
|
|
733
|
+
in.consume("null") ? nullptr :
|
|
734
|
+
in.consume("Infinity") ?
|
|
735
|
+
(in.getOpts().parse_numbers_as_strings ? (dynamic)"Infinity" :
|
|
736
|
+
(dynamic)std::numeric_limits<double>::infinity()) :
|
|
737
|
+
in.consume("NaN") ?
|
|
738
|
+
(in.getOpts().parse_numbers_as_strings ? (dynamic)"NaN" :
|
|
739
|
+
(dynamic)std::numeric_limits<double>::quiet_NaN()) :
|
|
740
|
+
in.error("expected json value");
|
|
741
|
+
// clang-format on
|
|
742
|
+
}
|
|
743
|
+
|
|
744
|
+
} // namespace
|
|
745
|
+
|
|
746
|
+
//////////////////////////////////////////////////////////////////////
|
|
747
|
+
|
|
748
|
+
std::array<uint64_t, 2> buildExtraAsciiToEscapeBitmap(StringPiece chars) {
|
|
749
|
+
std::array<uint64_t, 2> escapes{{0, 0}};
|
|
750
|
+
for (auto b : ByteRange(chars)) {
|
|
751
|
+
if (b >= 0x20 && b < 0x80) {
|
|
752
|
+
escapes[b / 64] |= uint64_t(1) << (b % 64);
|
|
753
|
+
}
|
|
754
|
+
}
|
|
755
|
+
return escapes;
|
|
756
|
+
}
|
|
757
|
+
|
|
758
|
+
std::string serialize(dynamic const& dyn, serialization_opts const& opts) {
|
|
759
|
+
std::string ret;
|
|
760
|
+
unsigned indentLevel = 0;
|
|
761
|
+
Printer p(ret, opts.pretty_formatting ? &indentLevel : nullptr, &opts);
|
|
762
|
+
p(dyn, nullptr);
|
|
763
|
+
return ret;
|
|
764
|
+
}
|
|
765
|
+
|
|
766
|
+
// Fast path to determine the longest prefix that can be left
|
|
767
|
+
// unescaped in a string of sizeof(T) bytes packed in an integer of
|
|
768
|
+
// type T.
|
|
769
|
+
template <bool EnableExtraAsciiEscapes, class T>
|
|
770
|
+
size_t firstEscapableInWord(T s, const serialization_opts& opts) {
|
|
771
|
+
static_assert(std::is_unsigned<T>::value, "Unsigned integer required");
|
|
772
|
+
static constexpr T kOnes = ~T() / 255; // 0x...0101
|
|
773
|
+
static constexpr T kMsbs = kOnes * 0x80; // 0x...8080
|
|
774
|
+
|
|
775
|
+
// Sets the MSB of bytes < b. Precondition: b < 128.
|
|
776
|
+
auto isLess = [](T w, uint8_t b) {
|
|
777
|
+
// A byte is < b iff subtracting b underflows, so we check that
|
|
778
|
+
// the MSB wasn't set before and it's set after the subtraction.
|
|
779
|
+
return (w - kOnes * b) & ~w & kMsbs;
|
|
780
|
+
};
|
|
781
|
+
|
|
782
|
+
auto isChar = [&](uint8_t c) {
|
|
783
|
+
// A byte is == c iff it is 0 if xor'd with c.
|
|
784
|
+
return isLess(s ^ (kOnes * c), 1);
|
|
785
|
+
};
|
|
786
|
+
|
|
787
|
+
// The following masks have the MSB set for each byte of the word
|
|
788
|
+
// that satisfies the corresponding condition.
|
|
789
|
+
auto isHigh = s & kMsbs; // >= 128
|
|
790
|
+
auto isLow = isLess(s, 0x20); // <= 0x1f
|
|
791
|
+
auto needsEscape = isHigh | isLow | isChar('\\') | isChar('"');
|
|
792
|
+
|
|
793
|
+
if /* constexpr */ (EnableExtraAsciiEscapes) {
|
|
794
|
+
// Deal with optional bitmap for unicode escapes. Escapes can optionally be
|
|
795
|
+
// set for ascii characters 32 - 127, so the inner loop may run up to 96
|
|
796
|
+
// times. However, for the case where 0 or a handful of bits are set,
|
|
797
|
+
// looping will be minimal through use of findFirstSet.
|
|
798
|
+
for (size_t i = 0, e = opts.extra_ascii_to_escape_bitmap.size(); i < e;
|
|
799
|
+
++i) {
|
|
800
|
+
const auto offset = i * 64;
|
|
801
|
+
// Clear first 32 characters if this is the first index, since those are
|
|
802
|
+
// always escaped.
|
|
803
|
+
auto bitmap = opts.extra_ascii_to_escape_bitmap[i] &
|
|
804
|
+
(i == 0 ? uint64_t(-1) << 32 : ~0ULL);
|
|
805
|
+
while (bitmap) {
|
|
806
|
+
auto bit = folly::findFirstSet(bitmap);
|
|
807
|
+
needsEscape |= isChar(static_cast<uint8_t>(offset + bit - 1));
|
|
808
|
+
bitmap &= bitmap - 1;
|
|
809
|
+
}
|
|
810
|
+
}
|
|
811
|
+
}
|
|
812
|
+
|
|
813
|
+
if (!needsEscape) {
|
|
814
|
+
return sizeof(T);
|
|
815
|
+
}
|
|
816
|
+
|
|
817
|
+
if (folly::kIsLittleEndian) {
|
|
818
|
+
return folly::findFirstSet(needsEscape) / 8 - 1;
|
|
819
|
+
} else {
|
|
820
|
+
return sizeof(T) - folly::findLastSet(needsEscape) / 8;
|
|
821
|
+
}
|
|
822
|
+
}
|
|
823
|
+
|
|
824
|
+
// Escape a string so that it is legal to print it in JSON text.
|
|
825
|
+
template <bool EnableExtraAsciiEscapes>
|
|
826
|
+
void escapeStringImpl(
|
|
827
|
+
StringPiece input, std::string& out, const serialization_opts& opts) {
|
|
828
|
+
auto hexDigit = [](uint8_t c) -> char {
|
|
829
|
+
return c < 10 ? c + '0' : c - 10 + 'a';
|
|
830
|
+
};
|
|
831
|
+
|
|
832
|
+
out.push_back('\"');
|
|
833
|
+
|
|
834
|
+
auto* p = reinterpret_cast<const unsigned char*>(input.begin());
|
|
835
|
+
auto* q = reinterpret_cast<const unsigned char*>(input.begin());
|
|
836
|
+
auto* e = reinterpret_cast<const unsigned char*>(input.end());
|
|
837
|
+
|
|
838
|
+
while (p < e) {
|
|
839
|
+
// Find the longest prefix that does not need escaping, and copy
|
|
840
|
+
// it literally into the output string.
|
|
841
|
+
auto firstEsc = p;
|
|
842
|
+
while (firstEsc < e) {
|
|
843
|
+
auto avail = to_unsigned(e - firstEsc);
|
|
844
|
+
uint64_t word = 0;
|
|
845
|
+
if (avail >= 8) {
|
|
846
|
+
word = folly::loadUnaligned<uint64_t>(firstEsc);
|
|
847
|
+
} else {
|
|
848
|
+
word = folly::partialLoadUnaligned<uint64_t>(firstEsc, avail);
|
|
849
|
+
}
|
|
850
|
+
auto prefix = firstEscapableInWord<EnableExtraAsciiEscapes>(word, opts);
|
|
851
|
+
DCHECK_LE(prefix, avail);
|
|
852
|
+
firstEsc += prefix;
|
|
853
|
+
if (prefix < 8) {
|
|
854
|
+
break;
|
|
855
|
+
}
|
|
856
|
+
}
|
|
857
|
+
if (firstEsc > p) {
|
|
858
|
+
out.append(reinterpret_cast<const char*>(p), firstEsc - p);
|
|
859
|
+
p = firstEsc;
|
|
860
|
+
// We can't be in the middle of a multibyte sequence, so we can reset q.
|
|
861
|
+
q = p;
|
|
862
|
+
if (p == e) {
|
|
863
|
+
break;
|
|
864
|
+
}
|
|
865
|
+
}
|
|
866
|
+
|
|
867
|
+
// Handle the next byte that may need escaping.
|
|
868
|
+
|
|
869
|
+
// Since non-ascii encoding inherently does utf8 validation
|
|
870
|
+
// we explicitly validate utf8 only if non-ascii encoding is disabled.
|
|
871
|
+
if ((opts.validate_utf8 || opts.skip_invalid_utf8) &&
|
|
872
|
+
!opts.encode_non_ascii) {
|
|
873
|
+
// To achieve better spatial and temporal coherence
|
|
874
|
+
// we do utf8 validation progressively along with the
|
|
875
|
+
// string-escaping instead of two separate passes.
|
|
876
|
+
|
|
877
|
+
// As the encoding progresses, q will stay at or ahead of p.
|
|
878
|
+
CHECK_GE(q, p);
|
|
879
|
+
|
|
880
|
+
// As p catches up with q, move q forward.
|
|
881
|
+
if (q == p) {
|
|
882
|
+
// calling utf8_decode has the side effect of
|
|
883
|
+
// checking that utf8 encodings are valid
|
|
884
|
+
char32_t v = utf8ToCodePoint(q, e, opts.skip_invalid_utf8);
|
|
885
|
+
if (opts.skip_invalid_utf8 && v == U'\ufffd') {
|
|
886
|
+
out.append(reinterpret_cast<const char*>(u8"\ufffd"));
|
|
887
|
+
p = q;
|
|
888
|
+
continue;
|
|
889
|
+
}
|
|
890
|
+
}
|
|
891
|
+
}
|
|
892
|
+
|
|
893
|
+
auto encodeUnicode = opts.encode_non_ascii && (*p & 0x80);
|
|
894
|
+
if /* constexpr */ (EnableExtraAsciiEscapes) {
|
|
895
|
+
encodeUnicode = encodeUnicode ||
|
|
896
|
+
(*p >= 0x20 && *p < 0x80 &&
|
|
897
|
+
(opts.extra_ascii_to_escape_bitmap[*p / 64] &
|
|
898
|
+
(uint64_t(1) << (*p % 64))));
|
|
899
|
+
}
|
|
900
|
+
|
|
901
|
+
if (encodeUnicode) {
|
|
902
|
+
// note that this if condition captures utf8 chars
|
|
903
|
+
// with value > 127, so size > 1 byte (or they are whitelisted for
|
|
904
|
+
// Unicode encoding).
|
|
905
|
+
// NOTE: char32_t / char16_t are both unsigned.
|
|
906
|
+
char32_t cp = utf8ToCodePoint(p, e, opts.skip_invalid_utf8);
|
|
907
|
+
auto writeHex = [&](char16_t v) {
|
|
908
|
+
char buf[] = "\\u\0\0\0\0";
|
|
909
|
+
buf[2] = hexDigit((v >> 12) & 0x0f);
|
|
910
|
+
buf[3] = hexDigit((v >> 8) & 0x0f);
|
|
911
|
+
buf[4] = hexDigit((v >> 4) & 0x0f);
|
|
912
|
+
buf[5] = hexDigit(v & 0x0f);
|
|
913
|
+
out.append(buf, 6);
|
|
914
|
+
};
|
|
915
|
+
// From the ECMA-404 The JSON Data Interchange Syntax 2nd Edition Dec 2017
|
|
916
|
+
if (cp < 0x10000u) {
|
|
917
|
+
// If the code point is in the Basic Multilingual Plane (U+0000 through
|
|
918
|
+
// U+FFFF), then it may be represented as a six-character sequence:
|
|
919
|
+
// a reverse solidus, followed by the lowercase letter u, followed by
|
|
920
|
+
// four hexadecimal digits that encode the code point.
|
|
921
|
+
writeHex(static_cast<char16_t>(cp));
|
|
922
|
+
} else {
|
|
923
|
+
// To escape a code point that is not in the Basic Multilingual Plane,
|
|
924
|
+
// the character may be represented as a twelve-character sequence,
|
|
925
|
+
// encoding the UTF-16 surrogate pair corresponding to the code point.
|
|
926
|
+
writeHex(static_cast<char16_t>(
|
|
927
|
+
0xd800u + (((cp - 0x10000u) >> 10) & 0x3ffu)));
|
|
928
|
+
writeHex(static_cast<char16_t>(0xdc00u + ((cp - 0x10000u) & 0x3ffu)));
|
|
929
|
+
}
|
|
930
|
+
} else if (*p == '\\' || *p == '\"') {
|
|
931
|
+
char buf[] = "\\\0";
|
|
932
|
+
buf[1] = char(*p++);
|
|
933
|
+
out.append(buf, 2);
|
|
934
|
+
} else if (*p <= 0x1f) {
|
|
935
|
+
switch (*p) {
|
|
936
|
+
// clang-format off
|
|
937
|
+
case '\b': out.append("\\b"); p++; break;
|
|
938
|
+
case '\f': out.append("\\f"); p++; break;
|
|
939
|
+
case '\n': out.append("\\n"); p++; break;
|
|
940
|
+
case '\r': out.append("\\r"); p++; break;
|
|
941
|
+
case '\t': out.append("\\t"); p++; break;
|
|
942
|
+
// clang-format on
|
|
943
|
+
default:
|
|
944
|
+
// Note that this if condition captures non readable chars
|
|
945
|
+
// with value < 32, so size = 1 byte (e.g control chars).
|
|
946
|
+
char buf[] = "\\u00\0\0";
|
|
947
|
+
buf[4] = hexDigit(uint8_t((*p & 0xf0) >> 4));
|
|
948
|
+
buf[5] = hexDigit(uint8_t(*p & 0xf));
|
|
949
|
+
out.append(buf, 6);
|
|
950
|
+
p++;
|
|
951
|
+
}
|
|
952
|
+
} else {
|
|
953
|
+
out.push_back(char(*p++));
|
|
954
|
+
}
|
|
955
|
+
}
|
|
956
|
+
|
|
957
|
+
out.push_back('\"');
|
|
958
|
+
}
|
|
959
|
+
|
|
960
|
+
void escapeString(
|
|
961
|
+
StringPiece input, std::string& out, const serialization_opts& opts) {
|
|
962
|
+
if (FOLLY_UNLIKELY(
|
|
963
|
+
opts.extra_ascii_to_escape_bitmap[0] ||
|
|
964
|
+
opts.extra_ascii_to_escape_bitmap[1])) {
|
|
965
|
+
escapeStringImpl<true>(input, out, opts);
|
|
966
|
+
} else {
|
|
967
|
+
escapeStringImpl<false>(input, out, opts);
|
|
968
|
+
}
|
|
969
|
+
}
|
|
970
|
+
|
|
971
|
+
std::string stripComments(StringPiece jsonC) {
|
|
972
|
+
std::string result;
|
|
973
|
+
enum class State {
|
|
974
|
+
None,
|
|
975
|
+
InString,
|
|
976
|
+
InlineComment,
|
|
977
|
+
LineComment
|
|
978
|
+
} state = State::None;
|
|
979
|
+
|
|
980
|
+
for (size_t i = 0; i < jsonC.size(); ++i) {
|
|
981
|
+
auto s = jsonC.subpiece(i);
|
|
982
|
+
switch (state) {
|
|
983
|
+
case State::None:
|
|
984
|
+
if (s.startsWith("/*")) {
|
|
985
|
+
state = State::InlineComment;
|
|
986
|
+
++i;
|
|
987
|
+
continue;
|
|
988
|
+
} else if (s.startsWith("//")) {
|
|
989
|
+
state = State::LineComment;
|
|
990
|
+
++i;
|
|
991
|
+
continue;
|
|
992
|
+
} else if (s[0] == '\"') {
|
|
993
|
+
state = State::InString;
|
|
994
|
+
}
|
|
995
|
+
result.push_back(s[0]);
|
|
996
|
+
break;
|
|
997
|
+
case State::InString:
|
|
998
|
+
if (s[0] == '\\') {
|
|
999
|
+
if (FOLLY_UNLIKELY(s.size() == 1)) {
|
|
1000
|
+
throw std::logic_error("Invalid JSONC: string is not terminated");
|
|
1001
|
+
}
|
|
1002
|
+
result.push_back(s[0]);
|
|
1003
|
+
result.push_back(s[1]);
|
|
1004
|
+
++i;
|
|
1005
|
+
continue;
|
|
1006
|
+
} else if (s[0] == '\"') {
|
|
1007
|
+
state = State::None;
|
|
1008
|
+
}
|
|
1009
|
+
result.push_back(s[0]);
|
|
1010
|
+
break;
|
|
1011
|
+
case State::InlineComment:
|
|
1012
|
+
if (s.startsWith('\n')) {
|
|
1013
|
+
// preserve the line break to preserve the line count
|
|
1014
|
+
result.push_back(s[0]);
|
|
1015
|
+
} else if (s.startsWith("*/")) {
|
|
1016
|
+
state = State::None;
|
|
1017
|
+
++i;
|
|
1018
|
+
}
|
|
1019
|
+
break;
|
|
1020
|
+
case State::LineComment:
|
|
1021
|
+
if (s[0] == '\n') {
|
|
1022
|
+
// preserve the line break to preserve the line count
|
|
1023
|
+
result.push_back(s[0]);
|
|
1024
|
+
state = State::None;
|
|
1025
|
+
}
|
|
1026
|
+
break;
|
|
1027
|
+
default:
|
|
1028
|
+
throw std::logic_error("Unknown comment state");
|
|
1029
|
+
}
|
|
1030
|
+
}
|
|
1031
|
+
return result;
|
|
1032
|
+
}
|
|
1033
|
+
|
|
1034
|
+
} // namespace json
|
|
1035
|
+
|
|
1036
|
+
//////////////////////////////////////////////////////////////////////
|
|
1037
|
+
|
|
1038
|
+
dynamic parseJsonWithMetadata(StringPiece range, json::metadata_map* map) {
|
|
1039
|
+
return parseJsonWithMetadata(range, json::serialization_opts(), map);
|
|
1040
|
+
}
|
|
1041
|
+
|
|
1042
|
+
dynamic parseJsonWithMetadata(
|
|
1043
|
+
StringPiece range,
|
|
1044
|
+
json::serialization_opts const& opts,
|
|
1045
|
+
json::metadata_map* map) {
|
|
1046
|
+
json::Input in(range, &opts);
|
|
1047
|
+
|
|
1048
|
+
uint32_t n = in.getLineNum();
|
|
1049
|
+
auto ret = parseValue(in, map);
|
|
1050
|
+
if (map) {
|
|
1051
|
+
map->emplace(&ret, json::parse_metadata{{{0}}, {{n}}});
|
|
1052
|
+
}
|
|
1053
|
+
|
|
1054
|
+
in.skipWhitespace();
|
|
1055
|
+
if (in.size() && *in != '\0') {
|
|
1056
|
+
in.error("parsing didn't consume all input");
|
|
1057
|
+
}
|
|
1058
|
+
return ret;
|
|
1059
|
+
}
|
|
1060
|
+
|
|
1061
|
+
dynamic parseJson(StringPiece range) {
|
|
1062
|
+
return parseJson(range, json::serialization_opts());
|
|
1063
|
+
}
|
|
1064
|
+
|
|
1065
|
+
dynamic parseJson(StringPiece range, json::serialization_opts const& opts) {
|
|
1066
|
+
json::Input in(range, &opts);
|
|
1067
|
+
|
|
1068
|
+
auto ret = parseValue(in, nullptr);
|
|
1069
|
+
in.skipWhitespace();
|
|
1070
|
+
if (in.size() && *in != '\0') {
|
|
1071
|
+
in.error("parsing didn't consume all input");
|
|
1072
|
+
}
|
|
1073
|
+
return ret;
|
|
1074
|
+
}
|
|
1075
|
+
|
|
1076
|
+
std::string toJson(dynamic const& dyn) {
|
|
1077
|
+
return json::serialize(dyn, json::serialization_opts());
|
|
1078
|
+
}
|
|
1079
|
+
|
|
1080
|
+
std::string toPrettyJson(dynamic const& dyn) {
|
|
1081
|
+
json::serialization_opts opts;
|
|
1082
|
+
opts.pretty_formatting = true;
|
|
1083
|
+
opts.sort_keys = true;
|
|
1084
|
+
return json::serialize(dyn, opts);
|
|
1085
|
+
}
|
|
1086
|
+
|
|
1087
|
+
//////////////////////////////////////////////////////////////////////
|
|
1088
|
+
// dynamic::print_as_pseudo_json() is implemented here for header
|
|
1089
|
+
// ordering reasons (most of the dynamic implementation is in
|
|
1090
|
+
// dynamic-inl.h, which we don't want to include json.h).
|
|
1091
|
+
|
|
1092
|
+
void dynamic::print_as_pseudo_json(std::ostream& out) const {
|
|
1093
|
+
json::serialization_opts opts;
|
|
1094
|
+
opts.allow_non_string_keys = true;
|
|
1095
|
+
opts.allow_nan_inf = true;
|
|
1096
|
+
out << json::serialize(*this, opts);
|
|
1097
|
+
}
|
|
1098
|
+
|
|
1099
|
+
void PrintTo(const dynamic& dyn, std::ostream* os) {
|
|
1100
|
+
json::serialization_opts opts;
|
|
1101
|
+
opts.allow_nan_inf = true;
|
|
1102
|
+
opts.allow_non_string_keys = true;
|
|
1103
|
+
opts.pretty_formatting = true;
|
|
1104
|
+
opts.sort_keys = true;
|
|
1105
|
+
*os << json::serialize(dyn, opts);
|
|
1106
|
+
}
|
|
1107
|
+
|
|
1108
|
+
//////////////////////////////////////////////////////////////////////
|
|
1109
|
+
|
|
1110
|
+
} // namespace folly
|