@samitouri / QOS-React-2 / commits / 4a1cc2ddd0

Fix logic around attribute seralization (#26526)

There was a bug in the attribute seralization for stylesheet resources injected by the Fizz runtime. For boolean properties the attribute value was set to an empty string but later immediately set to a string coerced value. This PR fixes that bug and refactors the code paths to be clearer

Josh Story committed Apr 3, 2023 at 09:34 UTC 4a1cc2ddd035f5c269e82ab6f7686e2e60d3b3ea
1 file changed +46 -38
packages/react-dom-bindings/src/server/ReactDOMServerFormatConfig.js
+46 -38
@@ -3926,48 +3926,51 @@ function writeStyleResourceAttributeInJS(
3926 return;
3927
3928 // Attribute renames
3929 - case 'className':
3929 + case 'className': {
3930 attributeName = 'class';
3931 + if (__DEV__) {
3932 + checkAttributeStringCoercion(value, attributeName);
3933 + }
3934 + attributeValue = '' + (value: any);
3935 break;
3932 -
3936 + }
3937 // Booleans
3934 - case 'hidden':
3938 + case 'hidden': {
3939 if (value === false) {
3940 return;
3941 }
3942 attributeValue = '';
3943 break;
3940 -
3944 + }
3945 // Santized URLs
3946 case 'src':
3947 case 'href': {
3948 + value = sanitizeURL(value);
3949 if (__DEV__) {
3950 checkAttributeStringCoercion(value, attributeName);
3951 }
3947 - value = sanitizeURL(value);
3952 + attributeValue = '' + (value: any);
3953 break;
3954 }
3955 default: {
3956 + if (
3957 + // unrecognized event handlers are not SSR'd and we (apparently)
3958 + // use on* as hueristic for these handler props
3959 + name.length > 2 &&
3960 + (name[0] === 'o' || name[0] === 'O') &&
3961 + (name[1] === 'n' || name[1] === 'N')
3962 + ) {
3963 + return;
3964 + }
3965 if (!isAttributeNameSafe(name)) {
3966 return;
3967 }
3968 + if (__DEV__) {
3969 + checkAttributeStringCoercion(value, attributeName);
3970 + }
3971 + attributeValue = '' + (value: any);
3972 }
3973 }
3956 -
3957 - if (
3958 - // shouldIgnoreAttribute
3959 - // We have already filtered out null/undefined and reserved words.
3960 - name.length > 2 &&
3961 - (name[0] === 'o' || name[0] === 'O') &&
3962 - (name[1] === 'n' || name[1] === 'N')
3963 - ) {
3964 - return;
3965 - }
3966 -
3967 - if (__DEV__) {
3968 - checkAttributeStringCoercion(value, attributeName);
3969 - }
3970 - attributeValue = '' + (value: any);
3974 writeChunk(destination, arrayInterstitial);
3975 writeChunk(
3976 destination,
@@ -4119,48 +4122,53 @@ function writeStyleResourceAttributeInAttr(
4122 return;
4123
4124 // Attribute renames
4122 - case 'className':
4125 + case 'className': {
4126 attributeName = 'class';
4127 + if (__DEV__) {
4128 + checkAttributeStringCoercion(value, attributeName);
4129 + }
4130 + attributeValue = '' + (value: any);
4131 break;
4132 + }
4133
4134 // Booleans
4127 - case 'hidden':
4135 + case 'hidden': {
4136 if (value === false) {
4137 return;
4138 }
4139 attributeValue = '';
4140 break;
4141 + }
4142
4143 // Santized URLs
4144 case 'src':
4145 case 'href': {
4146 + value = sanitizeURL(value);
4147 if (__DEV__) {
4148 checkAttributeStringCoercion(value, attributeName);
4149 }
4140 - value = sanitizeURL(value);
4150 + attributeValue = '' + (value: any);
4151 break;
4152 }
4153 default: {
4154 + if (
4155 + // unrecognized event handlers are not SSR'd and we (apparently)
4156 + // use on* as hueristic for these handler props
4157 + name.length > 2 &&
4158 + (name[0] === 'o' || name[0] === 'O') &&
4159 + (name[1] === 'n' || name[1] === 'N')
4160 + ) {
4161 + return;
4162 + }
4163 if (!isAttributeNameSafe(name)) {
4164 return;
4165 }
4166 + if (__DEV__) {
4167 + checkAttributeStringCoercion(value, attributeName);
4168 + }
4169 + attributeValue = '' + (value: any);
4170 }
4171 }
4149 -
4150 - if (
4151 - // shouldIgnoreAttribute
4152 - // We have already filtered out null/undefined and reserved words.
4153 - name.length > 2 &&
4154 - (name[0] === 'o' || name[0] === 'O') &&
4155 - (name[1] === 'n' || name[1] === 'N')
4156 - ) {
4157 - return;
4158 - }
4159 -
4160 - if (__DEV__) {
4161 - checkAttributeStringCoercion(value, attributeName);
4162 - }
4163 - attributeValue = '' + (value: any);
4172 writeChunk(destination, arrayInterstitial);
4173 writeChunk(
4174 destination,