Mercurial
comparison third_party/bun/node_modules/react-dom/cjs/react-dom-server-legacy.node.development.js @ 12:de54585a40f1
Adding bun and node modules.
| author | June Park <parkjune1995@gmail.com> |
|---|---|
| date | Thu, 02 Oct 2025 14:39:48 -0700 |
| parents | |
| children |
comparison
equal
deleted
inserted
replaced
| 11:f33d9ff8b6e8 | 12:de54585a40f1 |
|---|---|
| 1 /** | |
| 2 * @license React | |
| 3 * react-dom-server-legacy.node.development.js | |
| 4 * | |
| 5 * Copyright (c) Facebook, Inc. and its affiliates. | |
| 6 * | |
| 7 * This source code is licensed under the MIT license found in the | |
| 8 * LICENSE file in the root directory of this source tree. | |
| 9 */ | |
| 10 | |
| 11 'use strict'; | |
| 12 | |
| 13 if (process.env.NODE_ENV !== "production") { | |
| 14 (function() { | |
| 15 'use strict'; | |
| 16 | |
| 17 var React = require('react'); | |
| 18 var stream = require('stream'); | |
| 19 | |
| 20 var ReactVersion = '18.3.1'; | |
| 21 | |
| 22 var ReactSharedInternals = React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED; | |
| 23 | |
| 24 // by calls to these methods by a Babel plugin. | |
| 25 // | |
| 26 // In PROD (or in packages without access to React internals), | |
| 27 // they are left as they are instead. | |
| 28 | |
| 29 function warn(format) { | |
| 30 { | |
| 31 { | |
| 32 for (var _len = arguments.length, args = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) { | |
| 33 args[_key - 1] = arguments[_key]; | |
| 34 } | |
| 35 | |
| 36 printWarning('warn', format, args); | |
| 37 } | |
| 38 } | |
| 39 } | |
| 40 function error(format) { | |
| 41 { | |
| 42 { | |
| 43 for (var _len2 = arguments.length, args = new Array(_len2 > 1 ? _len2 - 1 : 0), _key2 = 1; _key2 < _len2; _key2++) { | |
| 44 args[_key2 - 1] = arguments[_key2]; | |
| 45 } | |
| 46 | |
| 47 printWarning('error', format, args); | |
| 48 } | |
| 49 } | |
| 50 } | |
| 51 | |
| 52 function printWarning(level, format, args) { | |
| 53 // When changing this logic, you might want to also | |
| 54 // update consoleWithStackDev.www.js as well. | |
| 55 { | |
| 56 var ReactDebugCurrentFrame = ReactSharedInternals.ReactDebugCurrentFrame; | |
| 57 var stack = ReactDebugCurrentFrame.getStackAddendum(); | |
| 58 | |
| 59 if (stack !== '') { | |
| 60 format += '%s'; | |
| 61 args = args.concat([stack]); | |
| 62 } // eslint-disable-next-line react-internal/safe-string-coercion | |
| 63 | |
| 64 | |
| 65 var argsWithFormat = args.map(function (item) { | |
| 66 return String(item); | |
| 67 }); // Careful: RN currently depends on this prefix | |
| 68 | |
| 69 argsWithFormat.unshift('Warning: ' + format); // We intentionally don't use spread (or .apply) directly because it | |
| 70 // breaks IE9: https://github.com/facebook/react/issues/13610 | |
| 71 // eslint-disable-next-line react-internal/no-production-logging | |
| 72 | |
| 73 Function.prototype.apply.call(console[level], console, argsWithFormat); | |
| 74 } | |
| 75 } | |
| 76 | |
| 77 function scheduleWork(callback) { | |
| 78 callback(); | |
| 79 } | |
| 80 function beginWriting(destination) {} | |
| 81 function writeChunk(destination, chunk) { | |
| 82 writeChunkAndReturn(destination, chunk); | |
| 83 } | |
| 84 function writeChunkAndReturn(destination, chunk) { | |
| 85 return destination.push(chunk); | |
| 86 } | |
| 87 function completeWriting(destination) {} | |
| 88 function close(destination) { | |
| 89 destination.push(null); | |
| 90 } | |
| 91 function stringToChunk(content) { | |
| 92 return content; | |
| 93 } | |
| 94 function stringToPrecomputedChunk(content) { | |
| 95 return content; | |
| 96 } | |
| 97 function closeWithError(destination, error) { | |
| 98 // $FlowFixMe: This is an Error object or the destination accepts other types. | |
| 99 destination.destroy(error); | |
| 100 } | |
| 101 | |
| 102 /* | |
| 103 * The `'' + value` pattern (used in in perf-sensitive code) throws for Symbol | |
| 104 * and Temporal.* types. See https://github.com/facebook/react/pull/22064. | |
| 105 * | |
| 106 * The functions in this module will throw an easier-to-understand, | |
| 107 * easier-to-debug exception with a clear errors message message explaining the | |
| 108 * problem. (Instead of a confusing exception thrown inside the implementation | |
| 109 * of the `value` object). | |
| 110 */ | |
| 111 // $FlowFixMe only called in DEV, so void return is not possible. | |
| 112 function typeName(value) { | |
| 113 { | |
| 114 // toStringTag is needed for namespaced types like Temporal.Instant | |
| 115 var hasToStringTag = typeof Symbol === 'function' && Symbol.toStringTag; | |
| 116 var type = hasToStringTag && value[Symbol.toStringTag] || value.constructor.name || 'Object'; | |
| 117 return type; | |
| 118 } | |
| 119 } // $FlowFixMe only called in DEV, so void return is not possible. | |
| 120 | |
| 121 | |
| 122 function willCoercionThrow(value) { | |
| 123 { | |
| 124 try { | |
| 125 testStringCoercion(value); | |
| 126 return false; | |
| 127 } catch (e) { | |
| 128 return true; | |
| 129 } | |
| 130 } | |
| 131 } | |
| 132 | |
| 133 function testStringCoercion(value) { | |
| 134 // If you ended up here by following an exception call stack, here's what's | |
| 135 // happened: you supplied an object or symbol value to React (as a prop, key, | |
| 136 // DOM attribute, CSS property, string ref, etc.) and when React tried to | |
| 137 // coerce it to a string using `'' + value`, an exception was thrown. | |
| 138 // | |
| 139 // The most common types that will cause this exception are `Symbol` instances | |
| 140 // and Temporal objects like `Temporal.Instant`. But any object that has a | |
| 141 // `valueOf` or `[Symbol.toPrimitive]` method that throws will also cause this | |
| 142 // exception. (Library authors do this to prevent users from using built-in | |
| 143 // numeric operators like `+` or comparison operators like `>=` because custom | |
| 144 // methods are needed to perform accurate arithmetic or comparison.) | |
| 145 // | |
| 146 // To fix the problem, coerce this object or symbol value to a string before | |
| 147 // passing it to React. The most reliable way is usually `String(value)`. | |
| 148 // | |
| 149 // To find which value is throwing, check the browser or debugger console. | |
| 150 // Before this exception was thrown, there should be `console.error` output | |
| 151 // that shows the type (Symbol, Temporal.PlainDate, etc.) that caused the | |
| 152 // problem and how that type was used: key, atrribute, input value prop, etc. | |
| 153 // In most cases, this console output also shows the component and its | |
| 154 // ancestor components where the exception happened. | |
| 155 // | |
| 156 // eslint-disable-next-line react-internal/safe-string-coercion | |
| 157 return '' + value; | |
| 158 } | |
| 159 | |
| 160 function checkAttributeStringCoercion(value, attributeName) { | |
| 161 { | |
| 162 if (willCoercionThrow(value)) { | |
| 163 error('The provided `%s` attribute is an unsupported type %s.' + ' This value must be coerced to a string before before using it here.', attributeName, typeName(value)); | |
| 164 | |
| 165 return testStringCoercion(value); // throw (to help callers find troubleshooting comments) | |
| 166 } | |
| 167 } | |
| 168 } | |
| 169 function checkCSSPropertyStringCoercion(value, propName) { | |
| 170 { | |
| 171 if (willCoercionThrow(value)) { | |
| 172 error('The provided `%s` CSS property is an unsupported type %s.' + ' This value must be coerced to a string before before using it here.', propName, typeName(value)); | |
| 173 | |
| 174 return testStringCoercion(value); // throw (to help callers find troubleshooting comments) | |
| 175 } | |
| 176 } | |
| 177 } | |
| 178 function checkHtmlStringCoercion(value) { | |
| 179 { | |
| 180 if (willCoercionThrow(value)) { | |
| 181 error('The provided HTML markup uses a value of unsupported type %s.' + ' This value must be coerced to a string before before using it here.', typeName(value)); | |
| 182 | |
| 183 return testStringCoercion(value); // throw (to help callers find troubleshooting comments) | |
| 184 } | |
| 185 } | |
| 186 } | |
| 187 | |
| 188 var hasOwnProperty = Object.prototype.hasOwnProperty; | |
| 189 | |
| 190 // A reserved attribute. | |
| 191 // It is handled by React separately and shouldn't be written to the DOM. | |
| 192 var RESERVED = 0; // A simple string attribute. | |
| 193 // Attributes that aren't in the filter are presumed to have this type. | |
| 194 | |
| 195 var STRING = 1; // A string attribute that accepts booleans in React. In HTML, these are called | |
| 196 // "enumerated" attributes with "true" and "false" as possible values. | |
| 197 // When true, it should be set to a "true" string. | |
| 198 // When false, it should be set to a "false" string. | |
| 199 | |
| 200 var BOOLEANISH_STRING = 2; // A real boolean attribute. | |
| 201 // When true, it should be present (set either to an empty string or its name). | |
| 202 // When false, it should be omitted. | |
| 203 | |
| 204 var BOOLEAN = 3; // An attribute that can be used as a flag as well as with a value. | |
| 205 // When true, it should be present (set either to an empty string or its name). | |
| 206 // When false, it should be omitted. | |
| 207 // For any other value, should be present with that value. | |
| 208 | |
| 209 var OVERLOADED_BOOLEAN = 4; // An attribute that must be numeric or parse as a numeric. | |
| 210 // When falsy, it should be removed. | |
| 211 | |
| 212 var NUMERIC = 5; // An attribute that must be positive numeric or parse as a positive numeric. | |
| 213 // When falsy, it should be removed. | |
| 214 | |
| 215 var POSITIVE_NUMERIC = 6; | |
| 216 | |
| 217 /* eslint-disable max-len */ | |
| 218 var ATTRIBUTE_NAME_START_CHAR = ":A-Z_a-z\\u00C0-\\u00D6\\u00D8-\\u00F6\\u00F8-\\u02FF\\u0370-\\u037D\\u037F-\\u1FFF\\u200C-\\u200D\\u2070-\\u218F\\u2C00-\\u2FEF\\u3001-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFFD"; | |
| 219 /* eslint-enable max-len */ | |
| 220 | |
| 221 var ATTRIBUTE_NAME_CHAR = ATTRIBUTE_NAME_START_CHAR + "\\-.0-9\\u00B7\\u0300-\\u036F\\u203F-\\u2040"; | |
| 222 var VALID_ATTRIBUTE_NAME_REGEX = new RegExp('^[' + ATTRIBUTE_NAME_START_CHAR + '][' + ATTRIBUTE_NAME_CHAR + ']*$'); | |
| 223 var illegalAttributeNameCache = {}; | |
| 224 var validatedAttributeNameCache = {}; | |
| 225 function isAttributeNameSafe(attributeName) { | |
| 226 if (hasOwnProperty.call(validatedAttributeNameCache, attributeName)) { | |
| 227 return true; | |
| 228 } | |
| 229 | |
| 230 if (hasOwnProperty.call(illegalAttributeNameCache, attributeName)) { | |
| 231 return false; | |
| 232 } | |
| 233 | |
| 234 if (VALID_ATTRIBUTE_NAME_REGEX.test(attributeName)) { | |
| 235 validatedAttributeNameCache[attributeName] = true; | |
| 236 return true; | |
| 237 } | |
| 238 | |
| 239 illegalAttributeNameCache[attributeName] = true; | |
| 240 | |
| 241 { | |
| 242 error('Invalid attribute name: `%s`', attributeName); | |
| 243 } | |
| 244 | |
| 245 return false; | |
| 246 } | |
| 247 function shouldRemoveAttributeWithWarning(name, value, propertyInfo, isCustomComponentTag) { | |
| 248 if (propertyInfo !== null && propertyInfo.type === RESERVED) { | |
| 249 return false; | |
| 250 } | |
| 251 | |
| 252 switch (typeof value) { | |
| 253 case 'function': // $FlowIssue symbol is perfectly valid here | |
| 254 | |
| 255 case 'symbol': | |
| 256 // eslint-disable-line | |
| 257 return true; | |
| 258 | |
| 259 case 'boolean': | |
| 260 { | |
| 261 if (isCustomComponentTag) { | |
| 262 return false; | |
| 263 } | |
| 264 | |
| 265 if (propertyInfo !== null) { | |
| 266 return !propertyInfo.acceptsBooleans; | |
| 267 } else { | |
| 268 var prefix = name.toLowerCase().slice(0, 5); | |
| 269 return prefix !== 'data-' && prefix !== 'aria-'; | |
| 270 } | |
| 271 } | |
| 272 | |
| 273 default: | |
| 274 return false; | |
| 275 } | |
| 276 } | |
| 277 function getPropertyInfo(name) { | |
| 278 return properties.hasOwnProperty(name) ? properties[name] : null; | |
| 279 } | |
| 280 | |
| 281 function PropertyInfoRecord(name, type, mustUseProperty, attributeName, attributeNamespace, sanitizeURL, removeEmptyString) { | |
| 282 this.acceptsBooleans = type === BOOLEANISH_STRING || type === BOOLEAN || type === OVERLOADED_BOOLEAN; | |
| 283 this.attributeName = attributeName; | |
| 284 this.attributeNamespace = attributeNamespace; | |
| 285 this.mustUseProperty = mustUseProperty; | |
| 286 this.propertyName = name; | |
| 287 this.type = type; | |
| 288 this.sanitizeURL = sanitizeURL; | |
| 289 this.removeEmptyString = removeEmptyString; | |
| 290 } // When adding attributes to this list, be sure to also add them to | |
| 291 // the `possibleStandardNames` module to ensure casing and incorrect | |
| 292 // name warnings. | |
| 293 | |
| 294 | |
| 295 var properties = {}; // These props are reserved by React. They shouldn't be written to the DOM. | |
| 296 | |
| 297 var reservedProps = ['children', 'dangerouslySetInnerHTML', // TODO: This prevents the assignment of defaultValue to regular | |
| 298 // elements (not just inputs). Now that ReactDOMInput assigns to the | |
| 299 // defaultValue property -- do we need this? | |
| 300 'defaultValue', 'defaultChecked', 'innerHTML', 'suppressContentEditableWarning', 'suppressHydrationWarning', 'style']; | |
| 301 | |
| 302 reservedProps.forEach(function (name) { | |
| 303 properties[name] = new PropertyInfoRecord(name, RESERVED, false, // mustUseProperty | |
| 304 name, // attributeName | |
| 305 null, // attributeNamespace | |
| 306 false, // sanitizeURL | |
| 307 false); | |
| 308 }); // A few React string attributes have a different name. | |
| 309 // This is a mapping from React prop names to the attribute names. | |
| 310 | |
| 311 [['acceptCharset', 'accept-charset'], ['className', 'class'], ['htmlFor', 'for'], ['httpEquiv', 'http-equiv']].forEach(function (_ref) { | |
| 312 var name = _ref[0], | |
| 313 attributeName = _ref[1]; | |
| 314 properties[name] = new PropertyInfoRecord(name, STRING, false, // mustUseProperty | |
| 315 attributeName, // attributeName | |
| 316 null, // attributeNamespace | |
| 317 false, // sanitizeURL | |
| 318 false); | |
| 319 }); // These are "enumerated" HTML attributes that accept "true" and "false". | |
| 320 // In React, we let users pass `true` and `false` even though technically | |
| 321 // these aren't boolean attributes (they are coerced to strings). | |
| 322 | |
| 323 ['contentEditable', 'draggable', 'spellCheck', 'value'].forEach(function (name) { | |
| 324 properties[name] = new PropertyInfoRecord(name, BOOLEANISH_STRING, false, // mustUseProperty | |
| 325 name.toLowerCase(), // attributeName | |
| 326 null, // attributeNamespace | |
| 327 false, // sanitizeURL | |
| 328 false); | |
| 329 }); // These are "enumerated" SVG attributes that accept "true" and "false". | |
| 330 // In React, we let users pass `true` and `false` even though technically | |
| 331 // these aren't boolean attributes (they are coerced to strings). | |
| 332 // Since these are SVG attributes, their attribute names are case-sensitive. | |
| 333 | |
| 334 ['autoReverse', 'externalResourcesRequired', 'focusable', 'preserveAlpha'].forEach(function (name) { | |
| 335 properties[name] = new PropertyInfoRecord(name, BOOLEANISH_STRING, false, // mustUseProperty | |
| 336 name, // attributeName | |
| 337 null, // attributeNamespace | |
| 338 false, // sanitizeURL | |
| 339 false); | |
| 340 }); // These are HTML boolean attributes. | |
| 341 | |
| 342 ['allowFullScreen', 'async', // Note: there is a special case that prevents it from being written to the DOM | |
| 343 // on the client side because the browsers are inconsistent. Instead we call focus(). | |
| 344 'autoFocus', 'autoPlay', 'controls', 'default', 'defer', 'disabled', 'disablePictureInPicture', 'disableRemotePlayback', 'formNoValidate', 'hidden', 'loop', 'noModule', 'noValidate', 'open', 'playsInline', 'readOnly', 'required', 'reversed', 'scoped', 'seamless', // Microdata | |
| 345 'itemScope'].forEach(function (name) { | |
| 346 properties[name] = new PropertyInfoRecord(name, BOOLEAN, false, // mustUseProperty | |
| 347 name.toLowerCase(), // attributeName | |
| 348 null, // attributeNamespace | |
| 349 false, // sanitizeURL | |
| 350 false); | |
| 351 }); // These are the few React props that we set as DOM properties | |
| 352 // rather than attributes. These are all booleans. | |
| 353 | |
| 354 ['checked', // Note: `option.selected` is not updated if `select.multiple` is | |
| 355 // disabled with `removeAttribute`. We have special logic for handling this. | |
| 356 'multiple', 'muted', 'selected' // NOTE: if you add a camelCased prop to this list, | |
| 357 // you'll need to set attributeName to name.toLowerCase() | |
| 358 // instead in the assignment below. | |
| 359 ].forEach(function (name) { | |
| 360 properties[name] = new PropertyInfoRecord(name, BOOLEAN, true, // mustUseProperty | |
| 361 name, // attributeName | |
| 362 null, // attributeNamespace | |
| 363 false, // sanitizeURL | |
| 364 false); | |
| 365 }); // These are HTML attributes that are "overloaded booleans": they behave like | |
| 366 // booleans, but can also accept a string value. | |
| 367 | |
| 368 ['capture', 'download' // NOTE: if you add a camelCased prop to this list, | |
| 369 // you'll need to set attributeName to name.toLowerCase() | |
| 370 // instead in the assignment below. | |
| 371 ].forEach(function (name) { | |
| 372 properties[name] = new PropertyInfoRecord(name, OVERLOADED_BOOLEAN, false, // mustUseProperty | |
| 373 name, // attributeName | |
| 374 null, // attributeNamespace | |
| 375 false, // sanitizeURL | |
| 376 false); | |
| 377 }); // These are HTML attributes that must be positive numbers. | |
| 378 | |
| 379 ['cols', 'rows', 'size', 'span' // NOTE: if you add a camelCased prop to this list, | |
| 380 // you'll need to set attributeName to name.toLowerCase() | |
| 381 // instead in the assignment below. | |
| 382 ].forEach(function (name) { | |
| 383 properties[name] = new PropertyInfoRecord(name, POSITIVE_NUMERIC, false, // mustUseProperty | |
| 384 name, // attributeName | |
| 385 null, // attributeNamespace | |
| 386 false, // sanitizeURL | |
| 387 false); | |
| 388 }); // These are HTML attributes that must be numbers. | |
| 389 | |
| 390 ['rowSpan', 'start'].forEach(function (name) { | |
| 391 properties[name] = new PropertyInfoRecord(name, NUMERIC, false, // mustUseProperty | |
| 392 name.toLowerCase(), // attributeName | |
| 393 null, // attributeNamespace | |
| 394 false, // sanitizeURL | |
| 395 false); | |
| 396 }); | |
| 397 var CAMELIZE = /[\-\:]([a-z])/g; | |
| 398 | |
| 399 var capitalize = function (token) { | |
| 400 return token[1].toUpperCase(); | |
| 401 }; // This is a list of all SVG attributes that need special casing, namespacing, | |
| 402 // or boolean value assignment. Regular attributes that just accept strings | |
| 403 // and have the same names are omitted, just like in the HTML attribute filter. | |
| 404 // Some of these attributes can be hard to find. This list was created by | |
| 405 // scraping the MDN documentation. | |
| 406 | |
| 407 | |
| 408 ['accent-height', 'alignment-baseline', 'arabic-form', 'baseline-shift', 'cap-height', 'clip-path', 'clip-rule', 'color-interpolation', 'color-interpolation-filters', 'color-profile', 'color-rendering', 'dominant-baseline', 'enable-background', 'fill-opacity', 'fill-rule', 'flood-color', 'flood-opacity', 'font-family', 'font-size', 'font-size-adjust', 'font-stretch', 'font-style', 'font-variant', 'font-weight', 'glyph-name', 'glyph-orientation-horizontal', 'glyph-orientation-vertical', 'horiz-adv-x', 'horiz-origin-x', 'image-rendering', 'letter-spacing', 'lighting-color', 'marker-end', 'marker-mid', 'marker-start', 'overline-position', 'overline-thickness', 'paint-order', 'panose-1', 'pointer-events', 'rendering-intent', 'shape-rendering', 'stop-color', 'stop-opacity', 'strikethrough-position', 'strikethrough-thickness', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'text-anchor', 'text-decoration', 'text-rendering', 'underline-position', 'underline-thickness', 'unicode-bidi', 'unicode-range', 'units-per-em', 'v-alphabetic', 'v-hanging', 'v-ideographic', 'v-mathematical', 'vector-effect', 'vert-adv-y', 'vert-origin-x', 'vert-origin-y', 'word-spacing', 'writing-mode', 'xmlns:xlink', 'x-height' // NOTE: if you add a camelCased prop to this list, | |
| 409 // you'll need to set attributeName to name.toLowerCase() | |
| 410 // instead in the assignment below. | |
| 411 ].forEach(function (attributeName) { | |
| 412 var name = attributeName.replace(CAMELIZE, capitalize); | |
| 413 properties[name] = new PropertyInfoRecord(name, STRING, false, // mustUseProperty | |
| 414 attributeName, null, // attributeNamespace | |
| 415 false, // sanitizeURL | |
| 416 false); | |
| 417 }); // String SVG attributes with the xlink namespace. | |
| 418 | |
| 419 ['xlink:actuate', 'xlink:arcrole', 'xlink:role', 'xlink:show', 'xlink:title', 'xlink:type' // NOTE: if you add a camelCased prop to this list, | |
| 420 // you'll need to set attributeName to name.toLowerCase() | |
| 421 // instead in the assignment below. | |
| 422 ].forEach(function (attributeName) { | |
| 423 var name = attributeName.replace(CAMELIZE, capitalize); | |
| 424 properties[name] = new PropertyInfoRecord(name, STRING, false, // mustUseProperty | |
| 425 attributeName, 'http://www.w3.org/1999/xlink', false, // sanitizeURL | |
| 426 false); | |
| 427 }); // String SVG attributes with the xml namespace. | |
| 428 | |
| 429 ['xml:base', 'xml:lang', 'xml:space' // NOTE: if you add a camelCased prop to this list, | |
| 430 // you'll need to set attributeName to name.toLowerCase() | |
| 431 // instead in the assignment below. | |
| 432 ].forEach(function (attributeName) { | |
| 433 var name = attributeName.replace(CAMELIZE, capitalize); | |
| 434 properties[name] = new PropertyInfoRecord(name, STRING, false, // mustUseProperty | |
| 435 attributeName, 'http://www.w3.org/XML/1998/namespace', false, // sanitizeURL | |
| 436 false); | |
| 437 }); // These attribute exists both in HTML and SVG. | |
| 438 // The attribute name is case-sensitive in SVG so we can't just use | |
| 439 // the React name like we do for attributes that exist only in HTML. | |
| 440 | |
| 441 ['tabIndex', 'crossOrigin'].forEach(function (attributeName) { | |
| 442 properties[attributeName] = new PropertyInfoRecord(attributeName, STRING, false, // mustUseProperty | |
| 443 attributeName.toLowerCase(), // attributeName | |
| 444 null, // attributeNamespace | |
| 445 false, // sanitizeURL | |
| 446 false); | |
| 447 }); // These attributes accept URLs. These must not allow javascript: URLS. | |
| 448 // These will also need to accept Trusted Types object in the future. | |
| 449 | |
| 450 var xlinkHref = 'xlinkHref'; | |
| 451 properties[xlinkHref] = new PropertyInfoRecord('xlinkHref', STRING, false, // mustUseProperty | |
| 452 'xlink:href', 'http://www.w3.org/1999/xlink', true, // sanitizeURL | |
| 453 false); | |
| 454 ['src', 'href', 'action', 'formAction'].forEach(function (attributeName) { | |
| 455 properties[attributeName] = new PropertyInfoRecord(attributeName, STRING, false, // mustUseProperty | |
| 456 attributeName.toLowerCase(), // attributeName | |
| 457 null, // attributeNamespace | |
| 458 true, // sanitizeURL | |
| 459 true); | |
| 460 }); | |
| 461 | |
| 462 /** | |
| 463 * CSS properties which accept numbers but are not in units of "px". | |
| 464 */ | |
| 465 var isUnitlessNumber = { | |
| 466 animationIterationCount: true, | |
| 467 aspectRatio: true, | |
| 468 borderImageOutset: true, | |
| 469 borderImageSlice: true, | |
| 470 borderImageWidth: true, | |
| 471 boxFlex: true, | |
| 472 boxFlexGroup: true, | |
| 473 boxOrdinalGroup: true, | |
| 474 columnCount: true, | |
| 475 columns: true, | |
| 476 flex: true, | |
| 477 flexGrow: true, | |
| 478 flexPositive: true, | |
| 479 flexShrink: true, | |
| 480 flexNegative: true, | |
| 481 flexOrder: true, | |
| 482 gridArea: true, | |
| 483 gridRow: true, | |
| 484 gridRowEnd: true, | |
| 485 gridRowSpan: true, | |
| 486 gridRowStart: true, | |
| 487 gridColumn: true, | |
| 488 gridColumnEnd: true, | |
| 489 gridColumnSpan: true, | |
| 490 gridColumnStart: true, | |
| 491 fontWeight: true, | |
| 492 lineClamp: true, | |
| 493 lineHeight: true, | |
| 494 opacity: true, | |
| 495 order: true, | |
| 496 orphans: true, | |
| 497 tabSize: true, | |
| 498 widows: true, | |
| 499 zIndex: true, | |
| 500 zoom: true, | |
| 501 // SVG-related properties | |
| 502 fillOpacity: true, | |
| 503 floodOpacity: true, | |
| 504 stopOpacity: true, | |
| 505 strokeDasharray: true, | |
| 506 strokeDashoffset: true, | |
| 507 strokeMiterlimit: true, | |
| 508 strokeOpacity: true, | |
| 509 strokeWidth: true | |
| 510 }; | |
| 511 /** | |
| 512 * @param {string} prefix vendor-specific prefix, eg: Webkit | |
| 513 * @param {string} key style name, eg: transitionDuration | |
| 514 * @return {string} style name prefixed with `prefix`, properly camelCased, eg: | |
| 515 * WebkitTransitionDuration | |
| 516 */ | |
| 517 | |
| 518 function prefixKey(prefix, key) { | |
| 519 return prefix + key.charAt(0).toUpperCase() + key.substring(1); | |
| 520 } | |
| 521 /** | |
| 522 * Support style names that may come passed in prefixed by adding permutations | |
| 523 * of vendor prefixes. | |
| 524 */ | |
| 525 | |
| 526 | |
| 527 var prefixes = ['Webkit', 'ms', 'Moz', 'O']; // Using Object.keys here, or else the vanilla for-in loop makes IE8 go into an | |
| 528 // infinite loop, because it iterates over the newly added props too. | |
| 529 | |
| 530 Object.keys(isUnitlessNumber).forEach(function (prop) { | |
| 531 prefixes.forEach(function (prefix) { | |
| 532 isUnitlessNumber[prefixKey(prefix, prop)] = isUnitlessNumber[prop]; | |
| 533 }); | |
| 534 }); | |
| 535 | |
| 536 var hasReadOnlyValue = { | |
| 537 button: true, | |
| 538 checkbox: true, | |
| 539 image: true, | |
| 540 hidden: true, | |
| 541 radio: true, | |
| 542 reset: true, | |
| 543 submit: true | |
| 544 }; | |
| 545 function checkControlledValueProps(tagName, props) { | |
| 546 { | |
| 547 if (!(hasReadOnlyValue[props.type] || props.onChange || props.onInput || props.readOnly || props.disabled || props.value == null)) { | |
| 548 error('You provided a `value` prop to a form field without an ' + '`onChange` handler. This will render a read-only field. If ' + 'the field should be mutable use `defaultValue`. Otherwise, ' + 'set either `onChange` or `readOnly`.'); | |
| 549 } | |
| 550 | |
| 551 if (!(props.onChange || props.readOnly || props.disabled || props.checked == null)) { | |
| 552 error('You provided a `checked` prop to a form field without an ' + '`onChange` handler. This will render a read-only field. If ' + 'the field should be mutable use `defaultChecked`. Otherwise, ' + 'set either `onChange` or `readOnly`.'); | |
| 553 } | |
| 554 } | |
| 555 } | |
| 556 | |
| 557 function isCustomComponent(tagName, props) { | |
| 558 if (tagName.indexOf('-') === -1) { | |
| 559 return typeof props.is === 'string'; | |
| 560 } | |
| 561 | |
| 562 switch (tagName) { | |
| 563 // These are reserved SVG and MathML elements. | |
| 564 // We don't mind this list too much because we expect it to never grow. | |
| 565 // The alternative is to track the namespace in a few places which is convoluted. | |
| 566 // https://w3c.github.io/webcomponents/spec/custom/#custom-elements-core-concepts | |
| 567 case 'annotation-xml': | |
| 568 case 'color-profile': | |
| 569 case 'font-face': | |
| 570 case 'font-face-src': | |
| 571 case 'font-face-uri': | |
| 572 case 'font-face-format': | |
| 573 case 'font-face-name': | |
| 574 case 'missing-glyph': | |
| 575 return false; | |
| 576 | |
| 577 default: | |
| 578 return true; | |
| 579 } | |
| 580 } | |
| 581 | |
| 582 var ariaProperties = { | |
| 583 'aria-current': 0, | |
| 584 // state | |
| 585 'aria-description': 0, | |
| 586 'aria-details': 0, | |
| 587 'aria-disabled': 0, | |
| 588 // state | |
| 589 'aria-hidden': 0, | |
| 590 // state | |
| 591 'aria-invalid': 0, | |
| 592 // state | |
| 593 'aria-keyshortcuts': 0, | |
| 594 'aria-label': 0, | |
| 595 'aria-roledescription': 0, | |
| 596 // Widget Attributes | |
| 597 'aria-autocomplete': 0, | |
| 598 'aria-checked': 0, | |
| 599 'aria-expanded': 0, | |
| 600 'aria-haspopup': 0, | |
| 601 'aria-level': 0, | |
| 602 'aria-modal': 0, | |
| 603 'aria-multiline': 0, | |
| 604 'aria-multiselectable': 0, | |
| 605 'aria-orientation': 0, | |
| 606 'aria-placeholder': 0, | |
| 607 'aria-pressed': 0, | |
| 608 'aria-readonly': 0, | |
| 609 'aria-required': 0, | |
| 610 'aria-selected': 0, | |
| 611 'aria-sort': 0, | |
| 612 'aria-valuemax': 0, | |
| 613 'aria-valuemin': 0, | |
| 614 'aria-valuenow': 0, | |
| 615 'aria-valuetext': 0, | |
| 616 // Live Region Attributes | |
| 617 'aria-atomic': 0, | |
| 618 'aria-busy': 0, | |
| 619 'aria-live': 0, | |
| 620 'aria-relevant': 0, | |
| 621 // Drag-and-Drop Attributes | |
| 622 'aria-dropeffect': 0, | |
| 623 'aria-grabbed': 0, | |
| 624 // Relationship Attributes | |
| 625 'aria-activedescendant': 0, | |
| 626 'aria-colcount': 0, | |
| 627 'aria-colindex': 0, | |
| 628 'aria-colspan': 0, | |
| 629 'aria-controls': 0, | |
| 630 'aria-describedby': 0, | |
| 631 'aria-errormessage': 0, | |
| 632 'aria-flowto': 0, | |
| 633 'aria-labelledby': 0, | |
| 634 'aria-owns': 0, | |
| 635 'aria-posinset': 0, | |
| 636 'aria-rowcount': 0, | |
| 637 'aria-rowindex': 0, | |
| 638 'aria-rowspan': 0, | |
| 639 'aria-setsize': 0 | |
| 640 }; | |
| 641 | |
| 642 var warnedProperties = {}; | |
| 643 var rARIA = new RegExp('^(aria)-[' + ATTRIBUTE_NAME_CHAR + ']*$'); | |
| 644 var rARIACamel = new RegExp('^(aria)[A-Z][' + ATTRIBUTE_NAME_CHAR + ']*$'); | |
| 645 | |
| 646 function validateProperty(tagName, name) { | |
| 647 { | |
| 648 if (hasOwnProperty.call(warnedProperties, name) && warnedProperties[name]) { | |
| 649 return true; | |
| 650 } | |
| 651 | |
| 652 if (rARIACamel.test(name)) { | |
| 653 var ariaName = 'aria-' + name.slice(4).toLowerCase(); | |
| 654 var correctName = ariaProperties.hasOwnProperty(ariaName) ? ariaName : null; // If this is an aria-* attribute, but is not listed in the known DOM | |
| 655 // DOM properties, then it is an invalid aria-* attribute. | |
| 656 | |
| 657 if (correctName == null) { | |
| 658 error('Invalid ARIA attribute `%s`. ARIA attributes follow the pattern aria-* and must be lowercase.', name); | |
| 659 | |
| 660 warnedProperties[name] = true; | |
| 661 return true; | |
| 662 } // aria-* attributes should be lowercase; suggest the lowercase version. | |
| 663 | |
| 664 | |
| 665 if (name !== correctName) { | |
| 666 error('Invalid ARIA attribute `%s`. Did you mean `%s`?', name, correctName); | |
| 667 | |
| 668 warnedProperties[name] = true; | |
| 669 return true; | |
| 670 } | |
| 671 } | |
| 672 | |
| 673 if (rARIA.test(name)) { | |
| 674 var lowerCasedName = name.toLowerCase(); | |
| 675 var standardName = ariaProperties.hasOwnProperty(lowerCasedName) ? lowerCasedName : null; // If this is an aria-* attribute, but is not listed in the known DOM | |
| 676 // DOM properties, then it is an invalid aria-* attribute. | |
| 677 | |
| 678 if (standardName == null) { | |
| 679 warnedProperties[name] = true; | |
| 680 return false; | |
| 681 } // aria-* attributes should be lowercase; suggest the lowercase version. | |
| 682 | |
| 683 | |
| 684 if (name !== standardName) { | |
| 685 error('Unknown ARIA attribute `%s`. Did you mean `%s`?', name, standardName); | |
| 686 | |
| 687 warnedProperties[name] = true; | |
| 688 return true; | |
| 689 } | |
| 690 } | |
| 691 } | |
| 692 | |
| 693 return true; | |
| 694 } | |
| 695 | |
| 696 function warnInvalidARIAProps(type, props) { | |
| 697 { | |
| 698 var invalidProps = []; | |
| 699 | |
| 700 for (var key in props) { | |
| 701 var isValid = validateProperty(type, key); | |
| 702 | |
| 703 if (!isValid) { | |
| 704 invalidProps.push(key); | |
| 705 } | |
| 706 } | |
| 707 | |
| 708 var unknownPropString = invalidProps.map(function (prop) { | |
| 709 return '`' + prop + '`'; | |
| 710 }).join(', '); | |
| 711 | |
| 712 if (invalidProps.length === 1) { | |
| 713 error('Invalid aria prop %s on <%s> tag. ' + 'For details, see https://reactjs.org/link/invalid-aria-props', unknownPropString, type); | |
| 714 } else if (invalidProps.length > 1) { | |
| 715 error('Invalid aria props %s on <%s> tag. ' + 'For details, see https://reactjs.org/link/invalid-aria-props', unknownPropString, type); | |
| 716 } | |
| 717 } | |
| 718 } | |
| 719 | |
| 720 function validateProperties(type, props) { | |
| 721 if (isCustomComponent(type, props)) { | |
| 722 return; | |
| 723 } | |
| 724 | |
| 725 warnInvalidARIAProps(type, props); | |
| 726 } | |
| 727 | |
| 728 var didWarnValueNull = false; | |
| 729 function validateProperties$1(type, props) { | |
| 730 { | |
| 731 if (type !== 'input' && type !== 'textarea' && type !== 'select') { | |
| 732 return; | |
| 733 } | |
| 734 | |
| 735 if (props != null && props.value === null && !didWarnValueNull) { | |
| 736 didWarnValueNull = true; | |
| 737 | |
| 738 if (type === 'select' && props.multiple) { | |
| 739 error('`value` prop on `%s` should not be null. ' + 'Consider using an empty array when `multiple` is set to `true` ' + 'to clear the component or `undefined` for uncontrolled components.', type); | |
| 740 } else { | |
| 741 error('`value` prop on `%s` should not be null. ' + 'Consider using an empty string to clear the component or `undefined` ' + 'for uncontrolled components.', type); | |
| 742 } | |
| 743 } | |
| 744 } | |
| 745 } | |
| 746 | |
| 747 // When adding attributes to the HTML or SVG allowed attribute list, be sure to | |
| 748 // also add them to this module to ensure casing and incorrect name | |
| 749 // warnings. | |
| 750 var possibleStandardNames = { | |
| 751 // HTML | |
| 752 accept: 'accept', | |
| 753 acceptcharset: 'acceptCharset', | |
| 754 'accept-charset': 'acceptCharset', | |
| 755 accesskey: 'accessKey', | |
| 756 action: 'action', | |
| 757 allowfullscreen: 'allowFullScreen', | |
| 758 alt: 'alt', | |
| 759 as: 'as', | |
| 760 async: 'async', | |
| 761 autocapitalize: 'autoCapitalize', | |
| 762 autocomplete: 'autoComplete', | |
| 763 autocorrect: 'autoCorrect', | |
| 764 autofocus: 'autoFocus', | |
| 765 autoplay: 'autoPlay', | |
| 766 autosave: 'autoSave', | |
| 767 capture: 'capture', | |
| 768 cellpadding: 'cellPadding', | |
| 769 cellspacing: 'cellSpacing', | |
| 770 challenge: 'challenge', | |
| 771 charset: 'charSet', | |
| 772 checked: 'checked', | |
| 773 children: 'children', | |
| 774 cite: 'cite', | |
| 775 class: 'className', | |
| 776 classid: 'classID', | |
| 777 classname: 'className', | |
| 778 cols: 'cols', | |
| 779 colspan: 'colSpan', | |
| 780 content: 'content', | |
| 781 contenteditable: 'contentEditable', | |
| 782 contextmenu: 'contextMenu', | |
| 783 controls: 'controls', | |
| 784 controlslist: 'controlsList', | |
| 785 coords: 'coords', | |
| 786 crossorigin: 'crossOrigin', | |
| 787 dangerouslysetinnerhtml: 'dangerouslySetInnerHTML', | |
| 788 data: 'data', | |
| 789 datetime: 'dateTime', | |
| 790 default: 'default', | |
| 791 defaultchecked: 'defaultChecked', | |
| 792 defaultvalue: 'defaultValue', | |
| 793 defer: 'defer', | |
| 794 dir: 'dir', | |
| 795 disabled: 'disabled', | |
| 796 disablepictureinpicture: 'disablePictureInPicture', | |
| 797 disableremoteplayback: 'disableRemotePlayback', | |
| 798 download: 'download', | |
| 799 draggable: 'draggable', | |
| 800 enctype: 'encType', | |
| 801 enterkeyhint: 'enterKeyHint', | |
| 802 for: 'htmlFor', | |
| 803 form: 'form', | |
| 804 formmethod: 'formMethod', | |
| 805 formaction: 'formAction', | |
| 806 formenctype: 'formEncType', | |
| 807 formnovalidate: 'formNoValidate', | |
| 808 formtarget: 'formTarget', | |
| 809 frameborder: 'frameBorder', | |
| 810 headers: 'headers', | |
| 811 height: 'height', | |
| 812 hidden: 'hidden', | |
| 813 high: 'high', | |
| 814 href: 'href', | |
| 815 hreflang: 'hrefLang', | |
| 816 htmlfor: 'htmlFor', | |
| 817 httpequiv: 'httpEquiv', | |
| 818 'http-equiv': 'httpEquiv', | |
| 819 icon: 'icon', | |
| 820 id: 'id', | |
| 821 imagesizes: 'imageSizes', | |
| 822 imagesrcset: 'imageSrcSet', | |
| 823 innerhtml: 'innerHTML', | |
| 824 inputmode: 'inputMode', | |
| 825 integrity: 'integrity', | |
| 826 is: 'is', | |
| 827 itemid: 'itemID', | |
| 828 itemprop: 'itemProp', | |
| 829 itemref: 'itemRef', | |
| 830 itemscope: 'itemScope', | |
| 831 itemtype: 'itemType', | |
| 832 keyparams: 'keyParams', | |
| 833 keytype: 'keyType', | |
| 834 kind: 'kind', | |
| 835 label: 'label', | |
| 836 lang: 'lang', | |
| 837 list: 'list', | |
| 838 loop: 'loop', | |
| 839 low: 'low', | |
| 840 manifest: 'manifest', | |
| 841 marginwidth: 'marginWidth', | |
| 842 marginheight: 'marginHeight', | |
| 843 max: 'max', | |
| 844 maxlength: 'maxLength', | |
| 845 media: 'media', | |
| 846 mediagroup: 'mediaGroup', | |
| 847 method: 'method', | |
| 848 min: 'min', | |
| 849 minlength: 'minLength', | |
| 850 multiple: 'multiple', | |
| 851 muted: 'muted', | |
| 852 name: 'name', | |
| 853 nomodule: 'noModule', | |
| 854 nonce: 'nonce', | |
| 855 novalidate: 'noValidate', | |
| 856 open: 'open', | |
| 857 optimum: 'optimum', | |
| 858 pattern: 'pattern', | |
| 859 placeholder: 'placeholder', | |
| 860 playsinline: 'playsInline', | |
| 861 poster: 'poster', | |
| 862 preload: 'preload', | |
| 863 profile: 'profile', | |
| 864 radiogroup: 'radioGroup', | |
| 865 readonly: 'readOnly', | |
| 866 referrerpolicy: 'referrerPolicy', | |
| 867 rel: 'rel', | |
| 868 required: 'required', | |
| 869 reversed: 'reversed', | |
| 870 role: 'role', | |
| 871 rows: 'rows', | |
| 872 rowspan: 'rowSpan', | |
| 873 sandbox: 'sandbox', | |
| 874 scope: 'scope', | |
| 875 scoped: 'scoped', | |
| 876 scrolling: 'scrolling', | |
| 877 seamless: 'seamless', | |
| 878 selected: 'selected', | |
| 879 shape: 'shape', | |
| 880 size: 'size', | |
| 881 sizes: 'sizes', | |
| 882 span: 'span', | |
| 883 spellcheck: 'spellCheck', | |
| 884 src: 'src', | |
| 885 srcdoc: 'srcDoc', | |
| 886 srclang: 'srcLang', | |
| 887 srcset: 'srcSet', | |
| 888 start: 'start', | |
| 889 step: 'step', | |
| 890 style: 'style', | |
| 891 summary: 'summary', | |
| 892 tabindex: 'tabIndex', | |
| 893 target: 'target', | |
| 894 title: 'title', | |
| 895 type: 'type', | |
| 896 usemap: 'useMap', | |
| 897 value: 'value', | |
| 898 width: 'width', | |
| 899 wmode: 'wmode', | |
| 900 wrap: 'wrap', | |
| 901 // SVG | |
| 902 about: 'about', | |
| 903 accentheight: 'accentHeight', | |
| 904 'accent-height': 'accentHeight', | |
| 905 accumulate: 'accumulate', | |
| 906 additive: 'additive', | |
| 907 alignmentbaseline: 'alignmentBaseline', | |
| 908 'alignment-baseline': 'alignmentBaseline', | |
| 909 allowreorder: 'allowReorder', | |
| 910 alphabetic: 'alphabetic', | |
| 911 amplitude: 'amplitude', | |
| 912 arabicform: 'arabicForm', | |
| 913 'arabic-form': 'arabicForm', | |
| 914 ascent: 'ascent', | |
| 915 attributename: 'attributeName', | |
| 916 attributetype: 'attributeType', | |
| 917 autoreverse: 'autoReverse', | |
| 918 azimuth: 'azimuth', | |
| 919 basefrequency: 'baseFrequency', | |
| 920 baselineshift: 'baselineShift', | |
| 921 'baseline-shift': 'baselineShift', | |
| 922 baseprofile: 'baseProfile', | |
| 923 bbox: 'bbox', | |
| 924 begin: 'begin', | |
| 925 bias: 'bias', | |
| 926 by: 'by', | |
| 927 calcmode: 'calcMode', | |
| 928 capheight: 'capHeight', | |
| 929 'cap-height': 'capHeight', | |
| 930 clip: 'clip', | |
| 931 clippath: 'clipPath', | |
| 932 'clip-path': 'clipPath', | |
| 933 clippathunits: 'clipPathUnits', | |
| 934 cliprule: 'clipRule', | |
| 935 'clip-rule': 'clipRule', | |
| 936 color: 'color', | |
| 937 colorinterpolation: 'colorInterpolation', | |
| 938 'color-interpolation': 'colorInterpolation', | |
| 939 colorinterpolationfilters: 'colorInterpolationFilters', | |
| 940 'color-interpolation-filters': 'colorInterpolationFilters', | |
| 941 colorprofile: 'colorProfile', | |
| 942 'color-profile': 'colorProfile', | |
| 943 colorrendering: 'colorRendering', | |
| 944 'color-rendering': 'colorRendering', | |
| 945 contentscripttype: 'contentScriptType', | |
| 946 contentstyletype: 'contentStyleType', | |
| 947 cursor: 'cursor', | |
| 948 cx: 'cx', | |
| 949 cy: 'cy', | |
| 950 d: 'd', | |
| 951 datatype: 'datatype', | |
| 952 decelerate: 'decelerate', | |
| 953 descent: 'descent', | |
| 954 diffuseconstant: 'diffuseConstant', | |
| 955 direction: 'direction', | |
| 956 display: 'display', | |
| 957 divisor: 'divisor', | |
| 958 dominantbaseline: 'dominantBaseline', | |
| 959 'dominant-baseline': 'dominantBaseline', | |
| 960 dur: 'dur', | |
| 961 dx: 'dx', | |
| 962 dy: 'dy', | |
| 963 edgemode: 'edgeMode', | |
| 964 elevation: 'elevation', | |
| 965 enablebackground: 'enableBackground', | |
| 966 'enable-background': 'enableBackground', | |
| 967 end: 'end', | |
| 968 exponent: 'exponent', | |
| 969 externalresourcesrequired: 'externalResourcesRequired', | |
| 970 fill: 'fill', | |
| 971 fillopacity: 'fillOpacity', | |
| 972 'fill-opacity': 'fillOpacity', | |
| 973 fillrule: 'fillRule', | |
| 974 'fill-rule': 'fillRule', | |
| 975 filter: 'filter', | |
| 976 filterres: 'filterRes', | |
| 977 filterunits: 'filterUnits', | |
| 978 floodopacity: 'floodOpacity', | |
| 979 'flood-opacity': 'floodOpacity', | |
| 980 floodcolor: 'floodColor', | |
| 981 'flood-color': 'floodColor', | |
| 982 focusable: 'focusable', | |
| 983 fontfamily: 'fontFamily', | |
| 984 'font-family': 'fontFamily', | |
| 985 fontsize: 'fontSize', | |
| 986 'font-size': 'fontSize', | |
| 987 fontsizeadjust: 'fontSizeAdjust', | |
| 988 'font-size-adjust': 'fontSizeAdjust', | |
| 989 fontstretch: 'fontStretch', | |
| 990 'font-stretch': 'fontStretch', | |
| 991 fontstyle: 'fontStyle', | |
| 992 'font-style': 'fontStyle', | |
| 993 fontvariant: 'fontVariant', | |
| 994 'font-variant': 'fontVariant', | |
| 995 fontweight: 'fontWeight', | |
| 996 'font-weight': 'fontWeight', | |
| 997 format: 'format', | |
| 998 from: 'from', | |
| 999 fx: 'fx', | |
| 1000 fy: 'fy', | |
| 1001 g1: 'g1', | |
| 1002 g2: 'g2', | |
| 1003 glyphname: 'glyphName', | |
| 1004 'glyph-name': 'glyphName', | |
| 1005 glyphorientationhorizontal: 'glyphOrientationHorizontal', | |
| 1006 'glyph-orientation-horizontal': 'glyphOrientationHorizontal', | |
| 1007 glyphorientationvertical: 'glyphOrientationVertical', | |
| 1008 'glyph-orientation-vertical': 'glyphOrientationVertical', | |
| 1009 glyphref: 'glyphRef', | |
| 1010 gradienttransform: 'gradientTransform', | |
| 1011 gradientunits: 'gradientUnits', | |
| 1012 hanging: 'hanging', | |
| 1013 horizadvx: 'horizAdvX', | |
| 1014 'horiz-adv-x': 'horizAdvX', | |
| 1015 horizoriginx: 'horizOriginX', | |
| 1016 'horiz-origin-x': 'horizOriginX', | |
| 1017 ideographic: 'ideographic', | |
| 1018 imagerendering: 'imageRendering', | |
| 1019 'image-rendering': 'imageRendering', | |
| 1020 in2: 'in2', | |
| 1021 in: 'in', | |
| 1022 inlist: 'inlist', | |
| 1023 intercept: 'intercept', | |
| 1024 k1: 'k1', | |
| 1025 k2: 'k2', | |
| 1026 k3: 'k3', | |
| 1027 k4: 'k4', | |
| 1028 k: 'k', | |
| 1029 kernelmatrix: 'kernelMatrix', | |
| 1030 kernelunitlength: 'kernelUnitLength', | |
| 1031 kerning: 'kerning', | |
| 1032 keypoints: 'keyPoints', | |
| 1033 keysplines: 'keySplines', | |
| 1034 keytimes: 'keyTimes', | |
| 1035 lengthadjust: 'lengthAdjust', | |
| 1036 letterspacing: 'letterSpacing', | |
| 1037 'letter-spacing': 'letterSpacing', | |
| 1038 lightingcolor: 'lightingColor', | |
| 1039 'lighting-color': 'lightingColor', | |
| 1040 limitingconeangle: 'limitingConeAngle', | |
| 1041 local: 'local', | |
| 1042 markerend: 'markerEnd', | |
| 1043 'marker-end': 'markerEnd', | |
| 1044 markerheight: 'markerHeight', | |
| 1045 markermid: 'markerMid', | |
| 1046 'marker-mid': 'markerMid', | |
| 1047 markerstart: 'markerStart', | |
| 1048 'marker-start': 'markerStart', | |
| 1049 markerunits: 'markerUnits', | |
| 1050 markerwidth: 'markerWidth', | |
| 1051 mask: 'mask', | |
| 1052 maskcontentunits: 'maskContentUnits', | |
| 1053 maskunits: 'maskUnits', | |
| 1054 mathematical: 'mathematical', | |
| 1055 mode: 'mode', | |
| 1056 numoctaves: 'numOctaves', | |
| 1057 offset: 'offset', | |
| 1058 opacity: 'opacity', | |
| 1059 operator: 'operator', | |
| 1060 order: 'order', | |
| 1061 orient: 'orient', | |
| 1062 orientation: 'orientation', | |
| 1063 origin: 'origin', | |
| 1064 overflow: 'overflow', | |
| 1065 overlineposition: 'overlinePosition', | |
| 1066 'overline-position': 'overlinePosition', | |
| 1067 overlinethickness: 'overlineThickness', | |
| 1068 'overline-thickness': 'overlineThickness', | |
| 1069 paintorder: 'paintOrder', | |
| 1070 'paint-order': 'paintOrder', | |
| 1071 panose1: 'panose1', | |
| 1072 'panose-1': 'panose1', | |
| 1073 pathlength: 'pathLength', | |
| 1074 patterncontentunits: 'patternContentUnits', | |
| 1075 patterntransform: 'patternTransform', | |
| 1076 patternunits: 'patternUnits', | |
| 1077 pointerevents: 'pointerEvents', | |
| 1078 'pointer-events': 'pointerEvents', | |
| 1079 points: 'points', | |
| 1080 pointsatx: 'pointsAtX', | |
| 1081 pointsaty: 'pointsAtY', | |
| 1082 pointsatz: 'pointsAtZ', | |
| 1083 prefix: 'prefix', | |
| 1084 preservealpha: 'preserveAlpha', | |
| 1085 preserveaspectratio: 'preserveAspectRatio', | |
| 1086 primitiveunits: 'primitiveUnits', | |
| 1087 property: 'property', | |
| 1088 r: 'r', | |
| 1089 radius: 'radius', | |
| 1090 refx: 'refX', | |
| 1091 refy: 'refY', | |
| 1092 renderingintent: 'renderingIntent', | |
| 1093 'rendering-intent': 'renderingIntent', | |
| 1094 repeatcount: 'repeatCount', | |
| 1095 repeatdur: 'repeatDur', | |
| 1096 requiredextensions: 'requiredExtensions', | |
| 1097 requiredfeatures: 'requiredFeatures', | |
| 1098 resource: 'resource', | |
| 1099 restart: 'restart', | |
| 1100 result: 'result', | |
| 1101 results: 'results', | |
| 1102 rotate: 'rotate', | |
| 1103 rx: 'rx', | |
| 1104 ry: 'ry', | |
| 1105 scale: 'scale', | |
| 1106 security: 'security', | |
| 1107 seed: 'seed', | |
| 1108 shaperendering: 'shapeRendering', | |
| 1109 'shape-rendering': 'shapeRendering', | |
| 1110 slope: 'slope', | |
| 1111 spacing: 'spacing', | |
| 1112 specularconstant: 'specularConstant', | |
| 1113 specularexponent: 'specularExponent', | |
| 1114 speed: 'speed', | |
| 1115 spreadmethod: 'spreadMethod', | |
| 1116 startoffset: 'startOffset', | |
| 1117 stddeviation: 'stdDeviation', | |
| 1118 stemh: 'stemh', | |
| 1119 stemv: 'stemv', | |
| 1120 stitchtiles: 'stitchTiles', | |
| 1121 stopcolor: 'stopColor', | |
| 1122 'stop-color': 'stopColor', | |
| 1123 stopopacity: 'stopOpacity', | |
| 1124 'stop-opacity': 'stopOpacity', | |
| 1125 strikethroughposition: 'strikethroughPosition', | |
| 1126 'strikethrough-position': 'strikethroughPosition', | |
| 1127 strikethroughthickness: 'strikethroughThickness', | |
| 1128 'strikethrough-thickness': 'strikethroughThickness', | |
| 1129 string: 'string', | |
| 1130 stroke: 'stroke', | |
| 1131 strokedasharray: 'strokeDasharray', | |
| 1132 'stroke-dasharray': 'strokeDasharray', | |
| 1133 strokedashoffset: 'strokeDashoffset', | |
| 1134 'stroke-dashoffset': 'strokeDashoffset', | |
| 1135 strokelinecap: 'strokeLinecap', | |
| 1136 'stroke-linecap': 'strokeLinecap', | |
| 1137 strokelinejoin: 'strokeLinejoin', | |
| 1138 'stroke-linejoin': 'strokeLinejoin', | |
| 1139 strokemiterlimit: 'strokeMiterlimit', | |
| 1140 'stroke-miterlimit': 'strokeMiterlimit', | |
| 1141 strokewidth: 'strokeWidth', | |
| 1142 'stroke-width': 'strokeWidth', | |
| 1143 strokeopacity: 'strokeOpacity', | |
| 1144 'stroke-opacity': 'strokeOpacity', | |
| 1145 suppresscontenteditablewarning: 'suppressContentEditableWarning', | |
| 1146 suppresshydrationwarning: 'suppressHydrationWarning', | |
| 1147 surfacescale: 'surfaceScale', | |
| 1148 systemlanguage: 'systemLanguage', | |
| 1149 tablevalues: 'tableValues', | |
| 1150 targetx: 'targetX', | |
| 1151 targety: 'targetY', | |
| 1152 textanchor: 'textAnchor', | |
| 1153 'text-anchor': 'textAnchor', | |
| 1154 textdecoration: 'textDecoration', | |
| 1155 'text-decoration': 'textDecoration', | |
| 1156 textlength: 'textLength', | |
| 1157 textrendering: 'textRendering', | |
| 1158 'text-rendering': 'textRendering', | |
| 1159 to: 'to', | |
| 1160 transform: 'transform', | |
| 1161 typeof: 'typeof', | |
| 1162 u1: 'u1', | |
| 1163 u2: 'u2', | |
| 1164 underlineposition: 'underlinePosition', | |
| 1165 'underline-position': 'underlinePosition', | |
| 1166 underlinethickness: 'underlineThickness', | |
| 1167 'underline-thickness': 'underlineThickness', | |
| 1168 unicode: 'unicode', | |
| 1169 unicodebidi: 'unicodeBidi', | |
| 1170 'unicode-bidi': 'unicodeBidi', | |
| 1171 unicoderange: 'unicodeRange', | |
| 1172 'unicode-range': 'unicodeRange', | |
| 1173 unitsperem: 'unitsPerEm', | |
| 1174 'units-per-em': 'unitsPerEm', | |
| 1175 unselectable: 'unselectable', | |
| 1176 valphabetic: 'vAlphabetic', | |
| 1177 'v-alphabetic': 'vAlphabetic', | |
| 1178 values: 'values', | |
| 1179 vectoreffect: 'vectorEffect', | |
| 1180 'vector-effect': 'vectorEffect', | |
| 1181 version: 'version', | |
| 1182 vertadvy: 'vertAdvY', | |
| 1183 'vert-adv-y': 'vertAdvY', | |
| 1184 vertoriginx: 'vertOriginX', | |
| 1185 'vert-origin-x': 'vertOriginX', | |
| 1186 vertoriginy: 'vertOriginY', | |
| 1187 'vert-origin-y': 'vertOriginY', | |
| 1188 vhanging: 'vHanging', | |
| 1189 'v-hanging': 'vHanging', | |
| 1190 videographic: 'vIdeographic', | |
| 1191 'v-ideographic': 'vIdeographic', | |
| 1192 viewbox: 'viewBox', | |
| 1193 viewtarget: 'viewTarget', | |
| 1194 visibility: 'visibility', | |
| 1195 vmathematical: 'vMathematical', | |
| 1196 'v-mathematical': 'vMathematical', | |
| 1197 vocab: 'vocab', | |
| 1198 widths: 'widths', | |
| 1199 wordspacing: 'wordSpacing', | |
| 1200 'word-spacing': 'wordSpacing', | |
| 1201 writingmode: 'writingMode', | |
| 1202 'writing-mode': 'writingMode', | |
| 1203 x1: 'x1', | |
| 1204 x2: 'x2', | |
| 1205 x: 'x', | |
| 1206 xchannelselector: 'xChannelSelector', | |
| 1207 xheight: 'xHeight', | |
| 1208 'x-height': 'xHeight', | |
| 1209 xlinkactuate: 'xlinkActuate', | |
| 1210 'xlink:actuate': 'xlinkActuate', | |
| 1211 xlinkarcrole: 'xlinkArcrole', | |
| 1212 'xlink:arcrole': 'xlinkArcrole', | |
| 1213 xlinkhref: 'xlinkHref', | |
| 1214 'xlink:href': 'xlinkHref', | |
| 1215 xlinkrole: 'xlinkRole', | |
| 1216 'xlink:role': 'xlinkRole', | |
| 1217 xlinkshow: 'xlinkShow', | |
| 1218 'xlink:show': 'xlinkShow', | |
| 1219 xlinktitle: 'xlinkTitle', | |
| 1220 'xlink:title': 'xlinkTitle', | |
| 1221 xlinktype: 'xlinkType', | |
| 1222 'xlink:type': 'xlinkType', | |
| 1223 xmlbase: 'xmlBase', | |
| 1224 'xml:base': 'xmlBase', | |
| 1225 xmllang: 'xmlLang', | |
| 1226 'xml:lang': 'xmlLang', | |
| 1227 xmlns: 'xmlns', | |
| 1228 'xml:space': 'xmlSpace', | |
| 1229 xmlnsxlink: 'xmlnsXlink', | |
| 1230 'xmlns:xlink': 'xmlnsXlink', | |
| 1231 xmlspace: 'xmlSpace', | |
| 1232 y1: 'y1', | |
| 1233 y2: 'y2', | |
| 1234 y: 'y', | |
| 1235 ychannelselector: 'yChannelSelector', | |
| 1236 z: 'z', | |
| 1237 zoomandpan: 'zoomAndPan' | |
| 1238 }; | |
| 1239 | |
| 1240 var validateProperty$1 = function () {}; | |
| 1241 | |
| 1242 { | |
| 1243 var warnedProperties$1 = {}; | |
| 1244 var EVENT_NAME_REGEX = /^on./; | |
| 1245 var INVALID_EVENT_NAME_REGEX = /^on[^A-Z]/; | |
| 1246 var rARIA$1 = new RegExp('^(aria)-[' + ATTRIBUTE_NAME_CHAR + ']*$'); | |
| 1247 var rARIACamel$1 = new RegExp('^(aria)[A-Z][' + ATTRIBUTE_NAME_CHAR + ']*$'); | |
| 1248 | |
| 1249 validateProperty$1 = function (tagName, name, value, eventRegistry) { | |
| 1250 if (hasOwnProperty.call(warnedProperties$1, name) && warnedProperties$1[name]) { | |
| 1251 return true; | |
| 1252 } | |
| 1253 | |
| 1254 var lowerCasedName = name.toLowerCase(); | |
| 1255 | |
| 1256 if (lowerCasedName === 'onfocusin' || lowerCasedName === 'onfocusout') { | |
| 1257 error('React uses onFocus and onBlur instead of onFocusIn and onFocusOut. ' + 'All React events are normalized to bubble, so onFocusIn and onFocusOut ' + 'are not needed/supported by React.'); | |
| 1258 | |
| 1259 warnedProperties$1[name] = true; | |
| 1260 return true; | |
| 1261 } // We can't rely on the event system being injected on the server. | |
| 1262 | |
| 1263 | |
| 1264 if (eventRegistry != null) { | |
| 1265 var registrationNameDependencies = eventRegistry.registrationNameDependencies, | |
| 1266 possibleRegistrationNames = eventRegistry.possibleRegistrationNames; | |
| 1267 | |
| 1268 if (registrationNameDependencies.hasOwnProperty(name)) { | |
| 1269 return true; | |
| 1270 } | |
| 1271 | |
| 1272 var registrationName = possibleRegistrationNames.hasOwnProperty(lowerCasedName) ? possibleRegistrationNames[lowerCasedName] : null; | |
| 1273 | |
| 1274 if (registrationName != null) { | |
| 1275 error('Invalid event handler property `%s`. Did you mean `%s`?', name, registrationName); | |
| 1276 | |
| 1277 warnedProperties$1[name] = true; | |
| 1278 return true; | |
| 1279 } | |
| 1280 | |
| 1281 if (EVENT_NAME_REGEX.test(name)) { | |
| 1282 error('Unknown event handler property `%s`. It will be ignored.', name); | |
| 1283 | |
| 1284 warnedProperties$1[name] = true; | |
| 1285 return true; | |
| 1286 } | |
| 1287 } else if (EVENT_NAME_REGEX.test(name)) { | |
| 1288 // If no event plugins have been injected, we are in a server environment. | |
| 1289 // So we can't tell if the event name is correct for sure, but we can filter | |
| 1290 // out known bad ones like `onclick`. We can't suggest a specific replacement though. | |
| 1291 if (INVALID_EVENT_NAME_REGEX.test(name)) { | |
| 1292 error('Invalid event handler property `%s`. ' + 'React events use the camelCase naming convention, for example `onClick`.', name); | |
| 1293 } | |
| 1294 | |
| 1295 warnedProperties$1[name] = true; | |
| 1296 return true; | |
| 1297 } // Let the ARIA attribute hook validate ARIA attributes | |
| 1298 | |
| 1299 | |
| 1300 if (rARIA$1.test(name) || rARIACamel$1.test(name)) { | |
| 1301 return true; | |
| 1302 } | |
| 1303 | |
| 1304 if (lowerCasedName === 'innerhtml') { | |
| 1305 error('Directly setting property `innerHTML` is not permitted. ' + 'For more information, lookup documentation on `dangerouslySetInnerHTML`.'); | |
| 1306 | |
| 1307 warnedProperties$1[name] = true; | |
| 1308 return true; | |
| 1309 } | |
| 1310 | |
| 1311 if (lowerCasedName === 'aria') { | |
| 1312 error('The `aria` attribute is reserved for future use in React. ' + 'Pass individual `aria-` attributes instead.'); | |
| 1313 | |
| 1314 warnedProperties$1[name] = true; | |
| 1315 return true; | |
| 1316 } | |
| 1317 | |
| 1318 if (lowerCasedName === 'is' && value !== null && value !== undefined && typeof value !== 'string') { | |
| 1319 error('Received a `%s` for a string attribute `is`. If this is expected, cast ' + 'the value to a string.', typeof value); | |
| 1320 | |
| 1321 warnedProperties$1[name] = true; | |
| 1322 return true; | |
| 1323 } | |
| 1324 | |
| 1325 if (typeof value === 'number' && isNaN(value)) { | |
| 1326 error('Received NaN for the `%s` attribute. If this is expected, cast ' + 'the value to a string.', name); | |
| 1327 | |
| 1328 warnedProperties$1[name] = true; | |
| 1329 return true; | |
| 1330 } | |
| 1331 | |
| 1332 var propertyInfo = getPropertyInfo(name); | |
| 1333 var isReserved = propertyInfo !== null && propertyInfo.type === RESERVED; // Known attributes should match the casing specified in the property config. | |
| 1334 | |
| 1335 if (possibleStandardNames.hasOwnProperty(lowerCasedName)) { | |
| 1336 var standardName = possibleStandardNames[lowerCasedName]; | |
| 1337 | |
| 1338 if (standardName !== name) { | |
| 1339 error('Invalid DOM property `%s`. Did you mean `%s`?', name, standardName); | |
| 1340 | |
| 1341 warnedProperties$1[name] = true; | |
| 1342 return true; | |
| 1343 } | |
| 1344 } else if (!isReserved && name !== lowerCasedName) { | |
| 1345 // Unknown attributes should have lowercase casing since that's how they | |
| 1346 // will be cased anyway with server rendering. | |
| 1347 error('React does not recognize the `%s` prop on a DOM element. If you ' + 'intentionally want it to appear in the DOM as a custom ' + 'attribute, spell it as lowercase `%s` instead. ' + 'If you accidentally passed it from a parent component, remove ' + 'it from the DOM element.', name, lowerCasedName); | |
| 1348 | |
| 1349 warnedProperties$1[name] = true; | |
| 1350 return true; | |
| 1351 } | |
| 1352 | |
| 1353 if (typeof value === 'boolean' && shouldRemoveAttributeWithWarning(name, value, propertyInfo, false)) { | |
| 1354 if (value) { | |
| 1355 error('Received `%s` for a non-boolean attribute `%s`.\n\n' + 'If you want to write it to the DOM, pass a string instead: ' + '%s="%s" or %s={value.toString()}.', value, name, name, value, name); | |
| 1356 } else { | |
| 1357 error('Received `%s` for a non-boolean attribute `%s`.\n\n' + 'If you want to write it to the DOM, pass a string instead: ' + '%s="%s" or %s={value.toString()}.\n\n' + 'If you used to conditionally omit it with %s={condition && value}, ' + 'pass %s={condition ? value : undefined} instead.', value, name, name, value, name, name, name); | |
| 1358 } | |
| 1359 | |
| 1360 warnedProperties$1[name] = true; | |
| 1361 return true; | |
| 1362 } // Now that we've validated casing, do not validate | |
| 1363 // data types for reserved props | |
| 1364 | |
| 1365 | |
| 1366 if (isReserved) { | |
| 1367 return true; | |
| 1368 } // Warn when a known attribute is a bad type | |
| 1369 | |
| 1370 | |
| 1371 if (shouldRemoveAttributeWithWarning(name, value, propertyInfo, false)) { | |
| 1372 warnedProperties$1[name] = true; | |
| 1373 return false; | |
| 1374 } // Warn when passing the strings 'false' or 'true' into a boolean prop | |
| 1375 | |
| 1376 | |
| 1377 if ((value === 'false' || value === 'true') && propertyInfo !== null && propertyInfo.type === BOOLEAN) { | |
| 1378 error('Received the string `%s` for the boolean attribute `%s`. ' + '%s ' + 'Did you mean %s={%s}?', value, name, value === 'false' ? 'The browser will interpret it as a truthy value.' : 'Although this works, it will not work as expected if you pass the string "false".', name, value); | |
| 1379 | |
| 1380 warnedProperties$1[name] = true; | |
| 1381 return true; | |
| 1382 } | |
| 1383 | |
| 1384 return true; | |
| 1385 }; | |
| 1386 } | |
| 1387 | |
| 1388 var warnUnknownProperties = function (type, props, eventRegistry) { | |
| 1389 { | |
| 1390 var unknownProps = []; | |
| 1391 | |
| 1392 for (var key in props) { | |
| 1393 var isValid = validateProperty$1(type, key, props[key], eventRegistry); | |
| 1394 | |
| 1395 if (!isValid) { | |
| 1396 unknownProps.push(key); | |
| 1397 } | |
| 1398 } | |
| 1399 | |
| 1400 var unknownPropString = unknownProps.map(function (prop) { | |
| 1401 return '`' + prop + '`'; | |
| 1402 }).join(', '); | |
| 1403 | |
| 1404 if (unknownProps.length === 1) { | |
| 1405 error('Invalid value for prop %s on <%s> tag. Either remove it from the element, ' + 'or pass a string or number value to keep it in the DOM. ' + 'For details, see https://reactjs.org/link/attribute-behavior ', unknownPropString, type); | |
| 1406 } else if (unknownProps.length > 1) { | |
| 1407 error('Invalid values for props %s on <%s> tag. Either remove them from the element, ' + 'or pass a string or number value to keep them in the DOM. ' + 'For details, see https://reactjs.org/link/attribute-behavior ', unknownPropString, type); | |
| 1408 } | |
| 1409 } | |
| 1410 }; | |
| 1411 | |
| 1412 function validateProperties$2(type, props, eventRegistry) { | |
| 1413 if (isCustomComponent(type, props)) { | |
| 1414 return; | |
| 1415 } | |
| 1416 | |
| 1417 warnUnknownProperties(type, props, eventRegistry); | |
| 1418 } | |
| 1419 | |
| 1420 var warnValidStyle = function () {}; | |
| 1421 | |
| 1422 { | |
| 1423 // 'msTransform' is correct, but the other prefixes should be capitalized | |
| 1424 var badVendoredStyleNamePattern = /^(?:webkit|moz|o)[A-Z]/; | |
| 1425 var msPattern = /^-ms-/; | |
| 1426 var hyphenPattern = /-(.)/g; // style values shouldn't contain a semicolon | |
| 1427 | |
| 1428 var badStyleValueWithSemicolonPattern = /;\s*$/; | |
| 1429 var warnedStyleNames = {}; | |
| 1430 var warnedStyleValues = {}; | |
| 1431 var warnedForNaNValue = false; | |
| 1432 var warnedForInfinityValue = false; | |
| 1433 | |
| 1434 var camelize = function (string) { | |
| 1435 return string.replace(hyphenPattern, function (_, character) { | |
| 1436 return character.toUpperCase(); | |
| 1437 }); | |
| 1438 }; | |
| 1439 | |
| 1440 var warnHyphenatedStyleName = function (name) { | |
| 1441 if (warnedStyleNames.hasOwnProperty(name) && warnedStyleNames[name]) { | |
| 1442 return; | |
| 1443 } | |
| 1444 | |
| 1445 warnedStyleNames[name] = true; | |
| 1446 | |
| 1447 error('Unsupported style property %s. Did you mean %s?', name, // As Andi Smith suggests | |
| 1448 // (http://www.andismith.com/blog/2012/02/modernizr-prefixed/), an `-ms` prefix | |
| 1449 // is converted to lowercase `ms`. | |
| 1450 camelize(name.replace(msPattern, 'ms-'))); | |
| 1451 }; | |
| 1452 | |
| 1453 var warnBadVendoredStyleName = function (name) { | |
| 1454 if (warnedStyleNames.hasOwnProperty(name) && warnedStyleNames[name]) { | |
| 1455 return; | |
| 1456 } | |
| 1457 | |
| 1458 warnedStyleNames[name] = true; | |
| 1459 | |
| 1460 error('Unsupported vendor-prefixed style property %s. Did you mean %s?', name, name.charAt(0).toUpperCase() + name.slice(1)); | |
| 1461 }; | |
| 1462 | |
| 1463 var warnStyleValueWithSemicolon = function (name, value) { | |
| 1464 if (warnedStyleValues.hasOwnProperty(value) && warnedStyleValues[value]) { | |
| 1465 return; | |
| 1466 } | |
| 1467 | |
| 1468 warnedStyleValues[value] = true; | |
| 1469 | |
| 1470 error("Style property values shouldn't contain a semicolon. " + 'Try "%s: %s" instead.', name, value.replace(badStyleValueWithSemicolonPattern, '')); | |
| 1471 }; | |
| 1472 | |
| 1473 var warnStyleValueIsNaN = function (name, value) { | |
| 1474 if (warnedForNaNValue) { | |
| 1475 return; | |
| 1476 } | |
| 1477 | |
| 1478 warnedForNaNValue = true; | |
| 1479 | |
| 1480 error('`NaN` is an invalid value for the `%s` css style property.', name); | |
| 1481 }; | |
| 1482 | |
| 1483 var warnStyleValueIsInfinity = function (name, value) { | |
| 1484 if (warnedForInfinityValue) { | |
| 1485 return; | |
| 1486 } | |
| 1487 | |
| 1488 warnedForInfinityValue = true; | |
| 1489 | |
| 1490 error('`Infinity` is an invalid value for the `%s` css style property.', name); | |
| 1491 }; | |
| 1492 | |
| 1493 warnValidStyle = function (name, value) { | |
| 1494 if (name.indexOf('-') > -1) { | |
| 1495 warnHyphenatedStyleName(name); | |
| 1496 } else if (badVendoredStyleNamePattern.test(name)) { | |
| 1497 warnBadVendoredStyleName(name); | |
| 1498 } else if (badStyleValueWithSemicolonPattern.test(value)) { | |
| 1499 warnStyleValueWithSemicolon(name, value); | |
| 1500 } | |
| 1501 | |
| 1502 if (typeof value === 'number') { | |
| 1503 if (isNaN(value)) { | |
| 1504 warnStyleValueIsNaN(name, value); | |
| 1505 } else if (!isFinite(value)) { | |
| 1506 warnStyleValueIsInfinity(name, value); | |
| 1507 } | |
| 1508 } | |
| 1509 }; | |
| 1510 } | |
| 1511 | |
| 1512 var warnValidStyle$1 = warnValidStyle; | |
| 1513 | |
| 1514 // code copied and modified from escape-html | |
| 1515 var matchHtmlRegExp = /["'&<>]/; | |
| 1516 /** | |
| 1517 * Escapes special characters and HTML entities in a given html string. | |
| 1518 * | |
| 1519 * @param {string} string HTML string to escape for later insertion | |
| 1520 * @return {string} | |
| 1521 * @public | |
| 1522 */ | |
| 1523 | |
| 1524 function escapeHtml(string) { | |
| 1525 { | |
| 1526 checkHtmlStringCoercion(string); | |
| 1527 } | |
| 1528 | |
| 1529 var str = '' + string; | |
| 1530 var match = matchHtmlRegExp.exec(str); | |
| 1531 | |
| 1532 if (!match) { | |
| 1533 return str; | |
| 1534 } | |
| 1535 | |
| 1536 var escape; | |
| 1537 var html = ''; | |
| 1538 var index; | |
| 1539 var lastIndex = 0; | |
| 1540 | |
| 1541 for (index = match.index; index < str.length; index++) { | |
| 1542 switch (str.charCodeAt(index)) { | |
| 1543 case 34: | |
| 1544 // " | |
| 1545 escape = '"'; | |
| 1546 break; | |
| 1547 | |
| 1548 case 38: | |
| 1549 // & | |
| 1550 escape = '&'; | |
| 1551 break; | |
| 1552 | |
| 1553 case 39: | |
| 1554 // ' | |
| 1555 escape = '''; // modified from escape-html; used to be ''' | |
| 1556 | |
| 1557 break; | |
| 1558 | |
| 1559 case 60: | |
| 1560 // < | |
| 1561 escape = '<'; | |
| 1562 break; | |
| 1563 | |
| 1564 case 62: | |
| 1565 // > | |
| 1566 escape = '>'; | |
| 1567 break; | |
| 1568 | |
| 1569 default: | |
| 1570 continue; | |
| 1571 } | |
| 1572 | |
| 1573 if (lastIndex !== index) { | |
| 1574 html += str.substring(lastIndex, index); | |
| 1575 } | |
| 1576 | |
| 1577 lastIndex = index + 1; | |
| 1578 html += escape; | |
| 1579 } | |
| 1580 | |
| 1581 return lastIndex !== index ? html + str.substring(lastIndex, index) : html; | |
| 1582 } // end code copied and modified from escape-html | |
| 1583 | |
| 1584 /** | |
| 1585 * Escapes text to prevent scripting attacks. | |
| 1586 * | |
| 1587 * @param {*} text Text value to escape. | |
| 1588 * @return {string} An escaped string. | |
| 1589 */ | |
| 1590 | |
| 1591 | |
| 1592 function escapeTextForBrowser(text) { | |
| 1593 if (typeof text === 'boolean' || typeof text === 'number') { | |
| 1594 // this shortcircuit helps perf for types that we know will never have | |
| 1595 // special characters, especially given that this function is used often | |
| 1596 // for numeric dom ids. | |
| 1597 return '' + text; | |
| 1598 } | |
| 1599 | |
| 1600 return escapeHtml(text); | |
| 1601 } | |
| 1602 | |
| 1603 var uppercasePattern = /([A-Z])/g; | |
| 1604 var msPattern$1 = /^ms-/; | |
| 1605 /** | |
| 1606 * Hyphenates a camelcased CSS property name, for example: | |
| 1607 * | |
| 1608 * > hyphenateStyleName('backgroundColor') | |
| 1609 * < "background-color" | |
| 1610 * > hyphenateStyleName('MozTransition') | |
| 1611 * < "-moz-transition" | |
| 1612 * > hyphenateStyleName('msTransition') | |
| 1613 * < "-ms-transition" | |
| 1614 * | |
| 1615 * As Modernizr suggests (http://modernizr.com/docs/#prefixed), an `ms` prefix | |
| 1616 * is converted to `-ms-`. | |
| 1617 */ | |
| 1618 | |
| 1619 function hyphenateStyleName(name) { | |
| 1620 return name.replace(uppercasePattern, '-$1').toLowerCase().replace(msPattern$1, '-ms-'); | |
| 1621 } | |
| 1622 | |
| 1623 // and any newline or tab are filtered out as if they're not part of the URL. | |
| 1624 // https://url.spec.whatwg.org/#url-parsing | |
| 1625 // Tab or newline are defined as \r\n\t: | |
| 1626 // https://infra.spec.whatwg.org/#ascii-tab-or-newline | |
| 1627 // A C0 control is a code point in the range \u0000 NULL to \u001F | |
| 1628 // INFORMATION SEPARATOR ONE, inclusive: | |
| 1629 // https://infra.spec.whatwg.org/#c0-control-or-space | |
| 1630 | |
| 1631 /* eslint-disable max-len */ | |
| 1632 | |
| 1633 var isJavaScriptProtocol = /^[\u0000-\u001F ]*j[\r\n\t]*a[\r\n\t]*v[\r\n\t]*a[\r\n\t]*s[\r\n\t]*c[\r\n\t]*r[\r\n\t]*i[\r\n\t]*p[\r\n\t]*t[\r\n\t]*\:/i; | |
| 1634 var didWarn = false; | |
| 1635 | |
| 1636 function sanitizeURL(url) { | |
| 1637 { | |
| 1638 if (!didWarn && isJavaScriptProtocol.test(url)) { | |
| 1639 didWarn = true; | |
| 1640 | |
| 1641 error('A future version of React will block javascript: URLs as a security precaution. ' + 'Use event handlers instead if you can. If you need to generate unsafe HTML try ' + 'using dangerouslySetInnerHTML instead. React was passed %s.', JSON.stringify(url)); | |
| 1642 } | |
| 1643 } | |
| 1644 } | |
| 1645 | |
| 1646 var isArrayImpl = Array.isArray; // eslint-disable-next-line no-redeclare | |
| 1647 | |
| 1648 function isArray(a) { | |
| 1649 return isArrayImpl(a); | |
| 1650 } | |
| 1651 | |
| 1652 var startInlineScript = stringToPrecomputedChunk('<script>'); | |
| 1653 var endInlineScript = stringToPrecomputedChunk('</script>'); | |
| 1654 var startScriptSrc = stringToPrecomputedChunk('<script src="'); | |
| 1655 var startModuleSrc = stringToPrecomputedChunk('<script type="module" src="'); | |
| 1656 var endAsyncScript = stringToPrecomputedChunk('" async=""></script>'); | |
| 1657 /** | |
| 1658 * This escaping function is designed to work with bootstrapScriptContent only. | |
| 1659 * because we know we are escaping the entire script. We can avoid for instance | |
| 1660 * escaping html comment string sequences that are valid javascript as well because | |
| 1661 * if there are no sebsequent <script sequences the html parser will never enter | |
| 1662 * script data double escaped state (see: https://www.w3.org/TR/html53/syntax.html#script-data-double-escaped-state) | |
| 1663 * | |
| 1664 * While untrusted script content should be made safe before using this api it will | |
| 1665 * ensure that the script cannot be early terminated or never terminated state | |
| 1666 */ | |
| 1667 | |
| 1668 function escapeBootstrapScriptContent(scriptText) { | |
| 1669 { | |
| 1670 checkHtmlStringCoercion(scriptText); | |
| 1671 } | |
| 1672 | |
| 1673 return ('' + scriptText).replace(scriptRegex, scriptReplacer); | |
| 1674 } | |
| 1675 | |
| 1676 var scriptRegex = /(<\/|<)(s)(cript)/gi; | |
| 1677 | |
| 1678 var scriptReplacer = function (match, prefix, s, suffix) { | |
| 1679 return "" + prefix + (s === 's' ? "\\u0073" : "\\u0053") + suffix; | |
| 1680 }; // Allows us to keep track of what we've already written so we can refer back to it. | |
| 1681 | |
| 1682 | |
| 1683 function createResponseState(identifierPrefix, nonce, bootstrapScriptContent, bootstrapScripts, bootstrapModules) { | |
| 1684 var idPrefix = identifierPrefix === undefined ? '' : identifierPrefix; | |
| 1685 var inlineScriptWithNonce = nonce === undefined ? startInlineScript : stringToPrecomputedChunk('<script nonce="' + escapeTextForBrowser(nonce) + '">'); | |
| 1686 var bootstrapChunks = []; | |
| 1687 | |
| 1688 if (bootstrapScriptContent !== undefined) { | |
| 1689 bootstrapChunks.push(inlineScriptWithNonce, stringToChunk(escapeBootstrapScriptContent(bootstrapScriptContent)), endInlineScript); | |
| 1690 } | |
| 1691 | |
| 1692 if (bootstrapScripts !== undefined) { | |
| 1693 for (var i = 0; i < bootstrapScripts.length; i++) { | |
| 1694 bootstrapChunks.push(startScriptSrc, stringToChunk(escapeTextForBrowser(bootstrapScripts[i])), endAsyncScript); | |
| 1695 } | |
| 1696 } | |
| 1697 | |
| 1698 if (bootstrapModules !== undefined) { | |
| 1699 for (var _i = 0; _i < bootstrapModules.length; _i++) { | |
| 1700 bootstrapChunks.push(startModuleSrc, stringToChunk(escapeTextForBrowser(bootstrapModules[_i])), endAsyncScript); | |
| 1701 } | |
| 1702 } | |
| 1703 | |
| 1704 return { | |
| 1705 bootstrapChunks: bootstrapChunks, | |
| 1706 startInlineScript: inlineScriptWithNonce, | |
| 1707 placeholderPrefix: stringToPrecomputedChunk(idPrefix + 'P:'), | |
| 1708 segmentPrefix: stringToPrecomputedChunk(idPrefix + 'S:'), | |
| 1709 boundaryPrefix: idPrefix + 'B:', | |
| 1710 idPrefix: idPrefix, | |
| 1711 nextSuspenseID: 0, | |
| 1712 sentCompleteSegmentFunction: false, | |
| 1713 sentCompleteBoundaryFunction: false, | |
| 1714 sentClientRenderFunction: false | |
| 1715 }; | |
| 1716 } // Constants for the insertion mode we're currently writing in. We don't encode all HTML5 insertion | |
| 1717 // modes. We only include the variants as they matter for the sake of our purposes. | |
| 1718 // We don't actually provide the namespace therefore we use constants instead of the string. | |
| 1719 | |
| 1720 var ROOT_HTML_MODE = 0; // Used for the root most element tag. | |
| 1721 | |
| 1722 var HTML_MODE = 1; | |
| 1723 var SVG_MODE = 2; | |
| 1724 var MATHML_MODE = 3; | |
| 1725 var HTML_TABLE_MODE = 4; | |
| 1726 var HTML_TABLE_BODY_MODE = 5; | |
| 1727 var HTML_TABLE_ROW_MODE = 6; | |
| 1728 var HTML_COLGROUP_MODE = 7; // We have a greater than HTML_TABLE_MODE check elsewhere. If you add more cases here, make sure it | |
| 1729 // still makes sense | |
| 1730 | |
| 1731 function createFormatContext(insertionMode, selectedValue) { | |
| 1732 return { | |
| 1733 insertionMode: insertionMode, | |
| 1734 selectedValue: selectedValue | |
| 1735 }; | |
| 1736 } | |
| 1737 function getChildFormatContext(parentContext, type, props) { | |
| 1738 switch (type) { | |
| 1739 case 'select': | |
| 1740 return createFormatContext(HTML_MODE, props.value != null ? props.value : props.defaultValue); | |
| 1741 | |
| 1742 case 'svg': | |
| 1743 return createFormatContext(SVG_MODE, null); | |
| 1744 | |
| 1745 case 'math': | |
| 1746 return createFormatContext(MATHML_MODE, null); | |
| 1747 | |
| 1748 case 'foreignObject': | |
| 1749 return createFormatContext(HTML_MODE, null); | |
| 1750 // Table parents are special in that their children can only be created at all if they're | |
| 1751 // wrapped in a table parent. So we need to encode that we're entering this mode. | |
| 1752 | |
| 1753 case 'table': | |
| 1754 return createFormatContext(HTML_TABLE_MODE, null); | |
| 1755 | |
| 1756 case 'thead': | |
| 1757 case 'tbody': | |
| 1758 case 'tfoot': | |
| 1759 return createFormatContext(HTML_TABLE_BODY_MODE, null); | |
| 1760 | |
| 1761 case 'colgroup': | |
| 1762 return createFormatContext(HTML_COLGROUP_MODE, null); | |
| 1763 | |
| 1764 case 'tr': | |
| 1765 return createFormatContext(HTML_TABLE_ROW_MODE, null); | |
| 1766 } | |
| 1767 | |
| 1768 if (parentContext.insertionMode >= HTML_TABLE_MODE) { | |
| 1769 // Whatever tag this was, it wasn't a table parent or other special parent, so we must have | |
| 1770 // entered plain HTML again. | |
| 1771 return createFormatContext(HTML_MODE, null); | |
| 1772 } | |
| 1773 | |
| 1774 if (parentContext.insertionMode === ROOT_HTML_MODE) { | |
| 1775 // We've emitted the root and is now in plain HTML mode. | |
| 1776 return createFormatContext(HTML_MODE, null); | |
| 1777 } | |
| 1778 | |
| 1779 return parentContext; | |
| 1780 } | |
| 1781 var UNINITIALIZED_SUSPENSE_BOUNDARY_ID = null; | |
| 1782 function assignSuspenseBoundaryID(responseState) { | |
| 1783 var generatedID = responseState.nextSuspenseID++; | |
| 1784 return stringToPrecomputedChunk(responseState.boundaryPrefix + generatedID.toString(16)); | |
| 1785 } | |
| 1786 function makeId(responseState, treeId, localId) { | |
| 1787 var idPrefix = responseState.idPrefix; | |
| 1788 var id = ':' + idPrefix + 'R' + treeId; // Unless this is the first id at this level, append a number at the end | |
| 1789 // that represents the position of this useId hook among all the useId | |
| 1790 // hooks for this fiber. | |
| 1791 | |
| 1792 if (localId > 0) { | |
| 1793 id += 'H' + localId.toString(32); | |
| 1794 } | |
| 1795 | |
| 1796 return id + ':'; | |
| 1797 } | |
| 1798 | |
| 1799 function encodeHTMLTextNode(text) { | |
| 1800 return escapeTextForBrowser(text); | |
| 1801 } | |
| 1802 | |
| 1803 var textSeparator = stringToPrecomputedChunk('<!-- -->'); | |
| 1804 function pushTextInstance(target, text, responseState, textEmbedded) { | |
| 1805 if (text === '') { | |
| 1806 // Empty text doesn't have a DOM node representation and the hydration is aware of this. | |
| 1807 return textEmbedded; | |
| 1808 } | |
| 1809 | |
| 1810 if (textEmbedded) { | |
| 1811 target.push(textSeparator); | |
| 1812 } | |
| 1813 | |
| 1814 target.push(stringToChunk(encodeHTMLTextNode(text))); | |
| 1815 return true; | |
| 1816 } // Called when Fizz is done with a Segment. Currently the only purpose is to conditionally | |
| 1817 // emit a text separator when we don't know for sure it is safe to omit | |
| 1818 | |
| 1819 function pushSegmentFinale(target, responseState, lastPushedText, textEmbedded) { | |
| 1820 if (lastPushedText && textEmbedded) { | |
| 1821 target.push(textSeparator); | |
| 1822 } | |
| 1823 } | |
| 1824 var styleNameCache = new Map(); | |
| 1825 | |
| 1826 function processStyleName(styleName) { | |
| 1827 var chunk = styleNameCache.get(styleName); | |
| 1828 | |
| 1829 if (chunk !== undefined) { | |
| 1830 return chunk; | |
| 1831 } | |
| 1832 | |
| 1833 var result = stringToPrecomputedChunk(escapeTextForBrowser(hyphenateStyleName(styleName))); | |
| 1834 styleNameCache.set(styleName, result); | |
| 1835 return result; | |
| 1836 } | |
| 1837 | |
| 1838 var styleAttributeStart = stringToPrecomputedChunk(' style="'); | |
| 1839 var styleAssign = stringToPrecomputedChunk(':'); | |
| 1840 var styleSeparator = stringToPrecomputedChunk(';'); | |
| 1841 | |
| 1842 function pushStyle(target, responseState, style) { | |
| 1843 if (typeof style !== 'object') { | |
| 1844 throw new Error('The `style` prop expects a mapping from style properties to values, ' + "not a string. For example, style={{marginRight: spacing + 'em'}} when " + 'using JSX.'); | |
| 1845 } | |
| 1846 | |
| 1847 var isFirst = true; | |
| 1848 | |
| 1849 for (var styleName in style) { | |
| 1850 if (!hasOwnProperty.call(style, styleName)) { | |
| 1851 continue; | |
| 1852 } // If you provide unsafe user data here they can inject arbitrary CSS | |
| 1853 // which may be problematic (I couldn't repro this): | |
| 1854 // https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet | |
| 1855 // http://www.thespanner.co.uk/2007/11/26/ultimate-xss-css-injection/ | |
| 1856 // This is not an XSS hole but instead a potential CSS injection issue | |
| 1857 // which has lead to a greater discussion about how we're going to | |
| 1858 // trust URLs moving forward. See #2115901 | |
| 1859 | |
| 1860 | |
| 1861 var styleValue = style[styleName]; | |
| 1862 | |
| 1863 if (styleValue == null || typeof styleValue === 'boolean' || styleValue === '') { | |
| 1864 // TODO: We used to set empty string as a style with an empty value. Does that ever make sense? | |
| 1865 continue; | |
| 1866 } | |
| 1867 | |
| 1868 var nameChunk = void 0; | |
| 1869 var valueChunk = void 0; | |
| 1870 var isCustomProperty = styleName.indexOf('--') === 0; | |
| 1871 | |
| 1872 if (isCustomProperty) { | |
| 1873 nameChunk = stringToChunk(escapeTextForBrowser(styleName)); | |
| 1874 | |
| 1875 { | |
| 1876 checkCSSPropertyStringCoercion(styleValue, styleName); | |
| 1877 } | |
| 1878 | |
| 1879 valueChunk = stringToChunk(escapeTextForBrowser(('' + styleValue).trim())); | |
| 1880 } else { | |
| 1881 { | |
| 1882 warnValidStyle$1(styleName, styleValue); | |
| 1883 } | |
| 1884 | |
| 1885 nameChunk = processStyleName(styleName); | |
| 1886 | |
| 1887 if (typeof styleValue === 'number') { | |
| 1888 if (styleValue !== 0 && !hasOwnProperty.call(isUnitlessNumber, styleName)) { | |
| 1889 valueChunk = stringToChunk(styleValue + 'px'); // Presumes implicit 'px' suffix for unitless numbers | |
| 1890 } else { | |
| 1891 valueChunk = stringToChunk('' + styleValue); | |
| 1892 } | |
| 1893 } else { | |
| 1894 { | |
| 1895 checkCSSPropertyStringCoercion(styleValue, styleName); | |
| 1896 } | |
| 1897 | |
| 1898 valueChunk = stringToChunk(escapeTextForBrowser(('' + styleValue).trim())); | |
| 1899 } | |
| 1900 } | |
| 1901 | |
| 1902 if (isFirst) { | |
| 1903 isFirst = false; // If it's first, we don't need any separators prefixed. | |
| 1904 | |
| 1905 target.push(styleAttributeStart, nameChunk, styleAssign, valueChunk); | |
| 1906 } else { | |
| 1907 target.push(styleSeparator, nameChunk, styleAssign, valueChunk); | |
| 1908 } | |
| 1909 } | |
| 1910 | |
| 1911 if (!isFirst) { | |
| 1912 target.push(attributeEnd); | |
| 1913 } | |
| 1914 } | |
| 1915 | |
| 1916 var attributeSeparator = stringToPrecomputedChunk(' '); | |
| 1917 var attributeAssign = stringToPrecomputedChunk('="'); | |
| 1918 var attributeEnd = stringToPrecomputedChunk('"'); | |
| 1919 var attributeEmptyString = stringToPrecomputedChunk('=""'); | |
| 1920 | |
| 1921 function pushAttribute(target, responseState, name, value) { | |
| 1922 switch (name) { | |
| 1923 case 'style': | |
| 1924 { | |
| 1925 pushStyle(target, responseState, value); | |
| 1926 return; | |
| 1927 } | |
| 1928 | |
| 1929 case 'defaultValue': | |
| 1930 case 'defaultChecked': // These shouldn't be set as attributes on generic HTML elements. | |
| 1931 | |
| 1932 case 'innerHTML': // Must use dangerouslySetInnerHTML instead. | |
| 1933 | |
| 1934 case 'suppressContentEditableWarning': | |
| 1935 case 'suppressHydrationWarning': | |
| 1936 // Ignored. These are built-in to React on the client. | |
| 1937 return; | |
| 1938 } | |
| 1939 | |
| 1940 if ( // shouldIgnoreAttribute | |
| 1941 // We have already filtered out null/undefined and reserved words. | |
| 1942 name.length > 2 && (name[0] === 'o' || name[0] === 'O') && (name[1] === 'n' || name[1] === 'N')) { | |
| 1943 return; | |
| 1944 } | |
| 1945 | |
| 1946 var propertyInfo = getPropertyInfo(name); | |
| 1947 | |
| 1948 if (propertyInfo !== null) { | |
| 1949 // shouldRemoveAttribute | |
| 1950 switch (typeof value) { | |
| 1951 case 'function': // $FlowIssue symbol is perfectly valid here | |
| 1952 | |
| 1953 case 'symbol': | |
| 1954 // eslint-disable-line | |
| 1955 return; | |
| 1956 | |
| 1957 case 'boolean': | |
| 1958 { | |
| 1959 if (!propertyInfo.acceptsBooleans) { | |
| 1960 return; | |
| 1961 } | |
| 1962 } | |
| 1963 } | |
| 1964 | |
| 1965 var attributeName = propertyInfo.attributeName; | |
| 1966 var attributeNameChunk = stringToChunk(attributeName); // TODO: If it's known we can cache the chunk. | |
| 1967 | |
| 1968 switch (propertyInfo.type) { | |
| 1969 case BOOLEAN: | |
| 1970 if (value) { | |
| 1971 target.push(attributeSeparator, attributeNameChunk, attributeEmptyString); | |
| 1972 } | |
| 1973 | |
| 1974 return; | |
| 1975 | |
| 1976 case OVERLOADED_BOOLEAN: | |
| 1977 if (value === true) { | |
| 1978 target.push(attributeSeparator, attributeNameChunk, attributeEmptyString); | |
| 1979 } else if (value === false) ; else { | |
| 1980 target.push(attributeSeparator, attributeNameChunk, attributeAssign, stringToChunk(escapeTextForBrowser(value)), attributeEnd); | |
| 1981 } | |
| 1982 | |
| 1983 return; | |
| 1984 | |
| 1985 case NUMERIC: | |
| 1986 if (!isNaN(value)) { | |
| 1987 target.push(attributeSeparator, attributeNameChunk, attributeAssign, stringToChunk(escapeTextForBrowser(value)), attributeEnd); | |
| 1988 } | |
| 1989 | |
| 1990 break; | |
| 1991 | |
| 1992 case POSITIVE_NUMERIC: | |
| 1993 if (!isNaN(value) && value >= 1) { | |
| 1994 target.push(attributeSeparator, attributeNameChunk, attributeAssign, stringToChunk(escapeTextForBrowser(value)), attributeEnd); | |
| 1995 } | |
| 1996 | |
| 1997 break; | |
| 1998 | |
| 1999 default: | |
| 2000 if (propertyInfo.sanitizeURL) { | |
| 2001 { | |
| 2002 checkAttributeStringCoercion(value, attributeName); | |
| 2003 } | |
| 2004 | |
| 2005 value = '' + value; | |
| 2006 sanitizeURL(value); | |
| 2007 } | |
| 2008 | |
| 2009 target.push(attributeSeparator, attributeNameChunk, attributeAssign, stringToChunk(escapeTextForBrowser(value)), attributeEnd); | |
| 2010 } | |
| 2011 } else if (isAttributeNameSafe(name)) { | |
| 2012 // shouldRemoveAttribute | |
| 2013 switch (typeof value) { | |
| 2014 case 'function': // $FlowIssue symbol is perfectly valid here | |
| 2015 | |
| 2016 case 'symbol': | |
| 2017 // eslint-disable-line | |
| 2018 return; | |
| 2019 | |
| 2020 case 'boolean': | |
| 2021 { | |
| 2022 var prefix = name.toLowerCase().slice(0, 5); | |
| 2023 | |
| 2024 if (prefix !== 'data-' && prefix !== 'aria-') { | |
| 2025 return; | |
| 2026 } | |
| 2027 } | |
| 2028 } | |
| 2029 | |
| 2030 target.push(attributeSeparator, stringToChunk(name), attributeAssign, stringToChunk(escapeTextForBrowser(value)), attributeEnd); | |
| 2031 } | |
| 2032 } | |
| 2033 | |
| 2034 var endOfStartTag = stringToPrecomputedChunk('>'); | |
| 2035 var endOfStartTagSelfClosing = stringToPrecomputedChunk('/>'); | |
| 2036 | |
| 2037 function pushInnerHTML(target, innerHTML, children) { | |
| 2038 if (innerHTML != null) { | |
| 2039 if (children != null) { | |
| 2040 throw new Error('Can only set one of `children` or `props.dangerouslySetInnerHTML`.'); | |
| 2041 } | |
| 2042 | |
| 2043 if (typeof innerHTML !== 'object' || !('__html' in innerHTML)) { | |
| 2044 throw new Error('`props.dangerouslySetInnerHTML` must be in the form `{__html: ...}`. ' + 'Please visit https://reactjs.org/link/dangerously-set-inner-html ' + 'for more information.'); | |
| 2045 } | |
| 2046 | |
| 2047 var html = innerHTML.__html; | |
| 2048 | |
| 2049 if (html !== null && html !== undefined) { | |
| 2050 { | |
| 2051 checkHtmlStringCoercion(html); | |
| 2052 } | |
| 2053 | |
| 2054 target.push(stringToChunk('' + html)); | |
| 2055 } | |
| 2056 } | |
| 2057 } // TODO: Move these to ResponseState so that we warn for every request. | |
| 2058 // It would help debugging in stateful servers (e.g. service worker). | |
| 2059 | |
| 2060 | |
| 2061 var didWarnDefaultInputValue = false; | |
| 2062 var didWarnDefaultChecked = false; | |
| 2063 var didWarnDefaultSelectValue = false; | |
| 2064 var didWarnDefaultTextareaValue = false; | |
| 2065 var didWarnInvalidOptionChildren = false; | |
| 2066 var didWarnInvalidOptionInnerHTML = false; | |
| 2067 var didWarnSelectedSetOnOption = false; | |
| 2068 | |
| 2069 function checkSelectProp(props, propName) { | |
| 2070 { | |
| 2071 var value = props[propName]; | |
| 2072 | |
| 2073 if (value != null) { | |
| 2074 var array = isArray(value); | |
| 2075 | |
| 2076 if (props.multiple && !array) { | |
| 2077 error('The `%s` prop supplied to <select> must be an array if ' + '`multiple` is true.', propName); | |
| 2078 } else if (!props.multiple && array) { | |
| 2079 error('The `%s` prop supplied to <select> must be a scalar ' + 'value if `multiple` is false.', propName); | |
| 2080 } | |
| 2081 } | |
| 2082 } | |
| 2083 } | |
| 2084 | |
| 2085 function pushStartSelect(target, props, responseState) { | |
| 2086 { | |
| 2087 checkControlledValueProps('select', props); | |
| 2088 checkSelectProp(props, 'value'); | |
| 2089 checkSelectProp(props, 'defaultValue'); | |
| 2090 | |
| 2091 if (props.value !== undefined && props.defaultValue !== undefined && !didWarnDefaultSelectValue) { | |
| 2092 error('Select elements must be either controlled or uncontrolled ' + '(specify either the value prop, or the defaultValue prop, but not ' + 'both). Decide between using a controlled or uncontrolled select ' + 'element and remove one of these props. More info: ' + 'https://reactjs.org/link/controlled-components'); | |
| 2093 | |
| 2094 didWarnDefaultSelectValue = true; | |
| 2095 } | |
| 2096 } | |
| 2097 | |
| 2098 target.push(startChunkForTag('select')); | |
| 2099 var children = null; | |
| 2100 var innerHTML = null; | |
| 2101 | |
| 2102 for (var propKey in props) { | |
| 2103 if (hasOwnProperty.call(props, propKey)) { | |
| 2104 var propValue = props[propKey]; | |
| 2105 | |
| 2106 if (propValue == null) { | |
| 2107 continue; | |
| 2108 } | |
| 2109 | |
| 2110 switch (propKey) { | |
| 2111 case 'children': | |
| 2112 children = propValue; | |
| 2113 break; | |
| 2114 | |
| 2115 case 'dangerouslySetInnerHTML': | |
| 2116 // TODO: This doesn't really make sense for select since it can't use the controlled | |
| 2117 // value in the innerHTML. | |
| 2118 innerHTML = propValue; | |
| 2119 break; | |
| 2120 | |
| 2121 case 'defaultValue': | |
| 2122 case 'value': | |
| 2123 // These are set on the Context instead and applied to the nested options. | |
| 2124 break; | |
| 2125 | |
| 2126 default: | |
| 2127 pushAttribute(target, responseState, propKey, propValue); | |
| 2128 break; | |
| 2129 } | |
| 2130 } | |
| 2131 } | |
| 2132 | |
| 2133 target.push(endOfStartTag); | |
| 2134 pushInnerHTML(target, innerHTML, children); | |
| 2135 return children; | |
| 2136 } | |
| 2137 | |
| 2138 function flattenOptionChildren(children) { | |
| 2139 var content = ''; // Flatten children and warn if they aren't strings or numbers; | |
| 2140 // invalid types are ignored. | |
| 2141 | |
| 2142 React.Children.forEach(children, function (child) { | |
| 2143 if (child == null) { | |
| 2144 return; | |
| 2145 } | |
| 2146 | |
| 2147 content += child; | |
| 2148 | |
| 2149 { | |
| 2150 if (!didWarnInvalidOptionChildren && typeof child !== 'string' && typeof child !== 'number') { | |
| 2151 didWarnInvalidOptionChildren = true; | |
| 2152 | |
| 2153 error('Cannot infer the option value of complex children. ' + 'Pass a `value` prop or use a plain string as children to <option>.'); | |
| 2154 } | |
| 2155 } | |
| 2156 }); | |
| 2157 return content; | |
| 2158 } | |
| 2159 | |
| 2160 var selectedMarkerAttribute = stringToPrecomputedChunk(' selected=""'); | |
| 2161 | |
| 2162 function pushStartOption(target, props, responseState, formatContext) { | |
| 2163 var selectedValue = formatContext.selectedValue; | |
| 2164 target.push(startChunkForTag('option')); | |
| 2165 var children = null; | |
| 2166 var value = null; | |
| 2167 var selected = null; | |
| 2168 var innerHTML = null; | |
| 2169 | |
| 2170 for (var propKey in props) { | |
| 2171 if (hasOwnProperty.call(props, propKey)) { | |
| 2172 var propValue = props[propKey]; | |
| 2173 | |
| 2174 if (propValue == null) { | |
| 2175 continue; | |
| 2176 } | |
| 2177 | |
| 2178 switch (propKey) { | |
| 2179 case 'children': | |
| 2180 children = propValue; | |
| 2181 break; | |
| 2182 | |
| 2183 case 'selected': | |
| 2184 // ignore | |
| 2185 selected = propValue; | |
| 2186 | |
| 2187 { | |
| 2188 // TODO: Remove support for `selected` in <option>. | |
| 2189 if (!didWarnSelectedSetOnOption) { | |
| 2190 error('Use the `defaultValue` or `value` props on <select> instead of ' + 'setting `selected` on <option>.'); | |
| 2191 | |
| 2192 didWarnSelectedSetOnOption = true; | |
| 2193 } | |
| 2194 } | |
| 2195 | |
| 2196 break; | |
| 2197 | |
| 2198 case 'dangerouslySetInnerHTML': | |
| 2199 innerHTML = propValue; | |
| 2200 break; | |
| 2201 // eslint-disable-next-line-no-fallthrough | |
| 2202 | |
| 2203 case 'value': | |
| 2204 value = propValue; | |
| 2205 // We intentionally fallthrough to also set the attribute on the node. | |
| 2206 // eslint-disable-next-line-no-fallthrough | |
| 2207 | |
| 2208 default: | |
| 2209 pushAttribute(target, responseState, propKey, propValue); | |
| 2210 break; | |
| 2211 } | |
| 2212 } | |
| 2213 } | |
| 2214 | |
| 2215 if (selectedValue != null) { | |
| 2216 var stringValue; | |
| 2217 | |
| 2218 if (value !== null) { | |
| 2219 { | |
| 2220 checkAttributeStringCoercion(value, 'value'); | |
| 2221 } | |
| 2222 | |
| 2223 stringValue = '' + value; | |
| 2224 } else { | |
| 2225 { | |
| 2226 if (innerHTML !== null) { | |
| 2227 if (!didWarnInvalidOptionInnerHTML) { | |
| 2228 didWarnInvalidOptionInnerHTML = true; | |
| 2229 | |
| 2230 error('Pass a `value` prop if you set dangerouslyInnerHTML so React knows ' + 'which value should be selected.'); | |
| 2231 } | |
| 2232 } | |
| 2233 } | |
| 2234 | |
| 2235 stringValue = flattenOptionChildren(children); | |
| 2236 } | |
| 2237 | |
| 2238 if (isArray(selectedValue)) { | |
| 2239 // multiple | |
| 2240 for (var i = 0; i < selectedValue.length; i++) { | |
| 2241 { | |
| 2242 checkAttributeStringCoercion(selectedValue[i], 'value'); | |
| 2243 } | |
| 2244 | |
| 2245 var v = '' + selectedValue[i]; | |
| 2246 | |
| 2247 if (v === stringValue) { | |
| 2248 target.push(selectedMarkerAttribute); | |
| 2249 break; | |
| 2250 } | |
| 2251 } | |
| 2252 } else { | |
| 2253 { | |
| 2254 checkAttributeStringCoercion(selectedValue, 'select.value'); | |
| 2255 } | |
| 2256 | |
| 2257 if ('' + selectedValue === stringValue) { | |
| 2258 target.push(selectedMarkerAttribute); | |
| 2259 } | |
| 2260 } | |
| 2261 } else if (selected) { | |
| 2262 target.push(selectedMarkerAttribute); | |
| 2263 } | |
| 2264 | |
| 2265 target.push(endOfStartTag); | |
| 2266 pushInnerHTML(target, innerHTML, children); | |
| 2267 return children; | |
| 2268 } | |
| 2269 | |
| 2270 function pushInput(target, props, responseState) { | |
| 2271 { | |
| 2272 checkControlledValueProps('input', props); | |
| 2273 | |
| 2274 if (props.checked !== undefined && props.defaultChecked !== undefined && !didWarnDefaultChecked) { | |
| 2275 error('%s contains an input of type %s with both checked and defaultChecked props. ' + 'Input elements must be either controlled or uncontrolled ' + '(specify either the checked prop, or the defaultChecked prop, but not ' + 'both). Decide between using a controlled or uncontrolled input ' + 'element and remove one of these props. More info: ' + 'https://reactjs.org/link/controlled-components', 'A component', props.type); | |
| 2276 | |
| 2277 didWarnDefaultChecked = true; | |
| 2278 } | |
| 2279 | |
| 2280 if (props.value !== undefined && props.defaultValue !== undefined && !didWarnDefaultInputValue) { | |
| 2281 error('%s contains an input of type %s with both value and defaultValue props. ' + 'Input elements must be either controlled or uncontrolled ' + '(specify either the value prop, or the defaultValue prop, but not ' + 'both). Decide between using a controlled or uncontrolled input ' + 'element and remove one of these props. More info: ' + 'https://reactjs.org/link/controlled-components', 'A component', props.type); | |
| 2282 | |
| 2283 didWarnDefaultInputValue = true; | |
| 2284 } | |
| 2285 } | |
| 2286 | |
| 2287 target.push(startChunkForTag('input')); | |
| 2288 var value = null; | |
| 2289 var defaultValue = null; | |
| 2290 var checked = null; | |
| 2291 var defaultChecked = null; | |
| 2292 | |
| 2293 for (var propKey in props) { | |
| 2294 if (hasOwnProperty.call(props, propKey)) { | |
| 2295 var propValue = props[propKey]; | |
| 2296 | |
| 2297 if (propValue == null) { | |
| 2298 continue; | |
| 2299 } | |
| 2300 | |
| 2301 switch (propKey) { | |
| 2302 case 'children': | |
| 2303 case 'dangerouslySetInnerHTML': | |
| 2304 throw new Error('input' + " is a self-closing tag and must neither have `children` nor " + 'use `dangerouslySetInnerHTML`.'); | |
| 2305 // eslint-disable-next-line-no-fallthrough | |
| 2306 | |
| 2307 case 'defaultChecked': | |
| 2308 defaultChecked = propValue; | |
| 2309 break; | |
| 2310 | |
| 2311 case 'defaultValue': | |
| 2312 defaultValue = propValue; | |
| 2313 break; | |
| 2314 | |
| 2315 case 'checked': | |
| 2316 checked = propValue; | |
| 2317 break; | |
| 2318 | |
| 2319 case 'value': | |
| 2320 value = propValue; | |
| 2321 break; | |
| 2322 | |
| 2323 default: | |
| 2324 pushAttribute(target, responseState, propKey, propValue); | |
| 2325 break; | |
| 2326 } | |
| 2327 } | |
| 2328 } | |
| 2329 | |
| 2330 if (checked !== null) { | |
| 2331 pushAttribute(target, responseState, 'checked', checked); | |
| 2332 } else if (defaultChecked !== null) { | |
| 2333 pushAttribute(target, responseState, 'checked', defaultChecked); | |
| 2334 } | |
| 2335 | |
| 2336 if (value !== null) { | |
| 2337 pushAttribute(target, responseState, 'value', value); | |
| 2338 } else if (defaultValue !== null) { | |
| 2339 pushAttribute(target, responseState, 'value', defaultValue); | |
| 2340 } | |
| 2341 | |
| 2342 target.push(endOfStartTagSelfClosing); | |
| 2343 return null; | |
| 2344 } | |
| 2345 | |
| 2346 function pushStartTextArea(target, props, responseState) { | |
| 2347 { | |
| 2348 checkControlledValueProps('textarea', props); | |
| 2349 | |
| 2350 if (props.value !== undefined && props.defaultValue !== undefined && !didWarnDefaultTextareaValue) { | |
| 2351 error('Textarea elements must be either controlled or uncontrolled ' + '(specify either the value prop, or the defaultValue prop, but not ' + 'both). Decide between using a controlled or uncontrolled textarea ' + 'and remove one of these props. More info: ' + 'https://reactjs.org/link/controlled-components'); | |
| 2352 | |
| 2353 didWarnDefaultTextareaValue = true; | |
| 2354 } | |
| 2355 } | |
| 2356 | |
| 2357 target.push(startChunkForTag('textarea')); | |
| 2358 var value = null; | |
| 2359 var defaultValue = null; | |
| 2360 var children = null; | |
| 2361 | |
| 2362 for (var propKey in props) { | |
| 2363 if (hasOwnProperty.call(props, propKey)) { | |
| 2364 var propValue = props[propKey]; | |
| 2365 | |
| 2366 if (propValue == null) { | |
| 2367 continue; | |
| 2368 } | |
| 2369 | |
| 2370 switch (propKey) { | |
| 2371 case 'children': | |
| 2372 children = propValue; | |
| 2373 break; | |
| 2374 | |
| 2375 case 'value': | |
| 2376 value = propValue; | |
| 2377 break; | |
| 2378 | |
| 2379 case 'defaultValue': | |
| 2380 defaultValue = propValue; | |
| 2381 break; | |
| 2382 | |
| 2383 case 'dangerouslySetInnerHTML': | |
| 2384 throw new Error('`dangerouslySetInnerHTML` does not make sense on <textarea>.'); | |
| 2385 // eslint-disable-next-line-no-fallthrough | |
| 2386 | |
| 2387 default: | |
| 2388 pushAttribute(target, responseState, propKey, propValue); | |
| 2389 break; | |
| 2390 } | |
| 2391 } | |
| 2392 } | |
| 2393 | |
| 2394 if (value === null && defaultValue !== null) { | |
| 2395 value = defaultValue; | |
| 2396 } | |
| 2397 | |
| 2398 target.push(endOfStartTag); // TODO (yungsters): Remove support for children content in <textarea>. | |
| 2399 | |
| 2400 if (children != null) { | |
| 2401 { | |
| 2402 error('Use the `defaultValue` or `value` props instead of setting ' + 'children on <textarea>.'); | |
| 2403 } | |
| 2404 | |
| 2405 if (value != null) { | |
| 2406 throw new Error('If you supply `defaultValue` on a <textarea>, do not pass children.'); | |
| 2407 } | |
| 2408 | |
| 2409 if (isArray(children)) { | |
| 2410 if (children.length > 1) { | |
| 2411 throw new Error('<textarea> can only have at most one child.'); | |
| 2412 } // TODO: remove the coercion and the DEV check below because it will | |
| 2413 // always be overwritten by the coercion several lines below it. #22309 | |
| 2414 | |
| 2415 | |
| 2416 { | |
| 2417 checkHtmlStringCoercion(children[0]); | |
| 2418 } | |
| 2419 | |
| 2420 value = '' + children[0]; | |
| 2421 } | |
| 2422 | |
| 2423 { | |
| 2424 checkHtmlStringCoercion(children); | |
| 2425 } | |
| 2426 | |
| 2427 value = '' + children; | |
| 2428 } | |
| 2429 | |
| 2430 if (typeof value === 'string' && value[0] === '\n') { | |
| 2431 // text/html ignores the first character in these tags if it's a newline | |
| 2432 // Prefer to break application/xml over text/html (for now) by adding | |
| 2433 // a newline specifically to get eaten by the parser. (Alternately for | |
| 2434 // textareas, replacing "^\n" with "\r\n" doesn't get eaten, and the first | |
| 2435 // \r is normalized out by HTMLTextAreaElement#value.) | |
| 2436 // See: <http://www.w3.org/TR/html-polyglot/#newlines-in-textarea-and-pre> | |
| 2437 // See: <http://www.w3.org/TR/html5/syntax.html#element-restrictions> | |
| 2438 // See: <http://www.w3.org/TR/html5/syntax.html#newlines> | |
| 2439 // See: Parsing of "textarea" "listing" and "pre" elements | |
| 2440 // from <http://www.w3.org/TR/html5/syntax.html#parsing-main-inbody> | |
| 2441 target.push(leadingNewline); | |
| 2442 } // ToString and push directly instead of recurse over children. | |
| 2443 // We don't really support complex children in the value anyway. | |
| 2444 // This also currently avoids a trailing comment node which breaks textarea. | |
| 2445 | |
| 2446 | |
| 2447 if (value !== null) { | |
| 2448 { | |
| 2449 checkAttributeStringCoercion(value, 'value'); | |
| 2450 } | |
| 2451 | |
| 2452 target.push(stringToChunk(encodeHTMLTextNode('' + value))); | |
| 2453 } | |
| 2454 | |
| 2455 return null; | |
| 2456 } | |
| 2457 | |
| 2458 function pushSelfClosing(target, props, tag, responseState) { | |
| 2459 target.push(startChunkForTag(tag)); | |
| 2460 | |
| 2461 for (var propKey in props) { | |
| 2462 if (hasOwnProperty.call(props, propKey)) { | |
| 2463 var propValue = props[propKey]; | |
| 2464 | |
| 2465 if (propValue == null) { | |
| 2466 continue; | |
| 2467 } | |
| 2468 | |
| 2469 switch (propKey) { | |
| 2470 case 'children': | |
| 2471 case 'dangerouslySetInnerHTML': | |
| 2472 throw new Error(tag + " is a self-closing tag and must neither have `children` nor " + 'use `dangerouslySetInnerHTML`.'); | |
| 2473 // eslint-disable-next-line-no-fallthrough | |
| 2474 | |
| 2475 default: | |
| 2476 pushAttribute(target, responseState, propKey, propValue); | |
| 2477 break; | |
| 2478 } | |
| 2479 } | |
| 2480 } | |
| 2481 | |
| 2482 target.push(endOfStartTagSelfClosing); | |
| 2483 return null; | |
| 2484 } | |
| 2485 | |
| 2486 function pushStartMenuItem(target, props, responseState) { | |
| 2487 target.push(startChunkForTag('menuitem')); | |
| 2488 | |
| 2489 for (var propKey in props) { | |
| 2490 if (hasOwnProperty.call(props, propKey)) { | |
| 2491 var propValue = props[propKey]; | |
| 2492 | |
| 2493 if (propValue == null) { | |
| 2494 continue; | |
| 2495 } | |
| 2496 | |
| 2497 switch (propKey) { | |
| 2498 case 'children': | |
| 2499 case 'dangerouslySetInnerHTML': | |
| 2500 throw new Error('menuitems cannot have `children` nor `dangerouslySetInnerHTML`.'); | |
| 2501 // eslint-disable-next-line-no-fallthrough | |
| 2502 | |
| 2503 default: | |
| 2504 pushAttribute(target, responseState, propKey, propValue); | |
| 2505 break; | |
| 2506 } | |
| 2507 } | |
| 2508 } | |
| 2509 | |
| 2510 target.push(endOfStartTag); | |
| 2511 return null; | |
| 2512 } | |
| 2513 | |
| 2514 function pushStartTitle(target, props, responseState) { | |
| 2515 target.push(startChunkForTag('title')); | |
| 2516 var children = null; | |
| 2517 | |
| 2518 for (var propKey in props) { | |
| 2519 if (hasOwnProperty.call(props, propKey)) { | |
| 2520 var propValue = props[propKey]; | |
| 2521 | |
| 2522 if (propValue == null) { | |
| 2523 continue; | |
| 2524 } | |
| 2525 | |
| 2526 switch (propKey) { | |
| 2527 case 'children': | |
| 2528 children = propValue; | |
| 2529 break; | |
| 2530 | |
| 2531 case 'dangerouslySetInnerHTML': | |
| 2532 throw new Error('`dangerouslySetInnerHTML` does not make sense on <title>.'); | |
| 2533 // eslint-disable-next-line-no-fallthrough | |
| 2534 | |
| 2535 default: | |
| 2536 pushAttribute(target, responseState, propKey, propValue); | |
| 2537 break; | |
| 2538 } | |
| 2539 } | |
| 2540 } | |
| 2541 | |
| 2542 target.push(endOfStartTag); | |
| 2543 | |
| 2544 { | |
| 2545 var child = Array.isArray(children) && children.length < 2 ? children[0] || null : children; | |
| 2546 | |
| 2547 if (Array.isArray(children) && children.length > 1) { | |
| 2548 error('A title element received an array with more than 1 element as children. ' + 'In browsers title Elements can only have Text Nodes as children. If ' + 'the children being rendered output more than a single text node in aggregate the browser ' + 'will display markup and comments as text in the title and hydration will likely fail and ' + 'fall back to client rendering'); | |
| 2549 } else if (child != null && child.$$typeof != null) { | |
| 2550 error('A title element received a React element for children. ' + 'In the browser title Elements can only have Text Nodes as children. If ' + 'the children being rendered output more than a single text node in aggregate the browser ' + 'will display markup and comments as text in the title and hydration will likely fail and ' + 'fall back to client rendering'); | |
| 2551 } else if (child != null && typeof child !== 'string' && typeof child !== 'number') { | |
| 2552 error('A title element received a value that was not a string or number for children. ' + 'In the browser title Elements can only have Text Nodes as children. If ' + 'the children being rendered output more than a single text node in aggregate the browser ' + 'will display markup and comments as text in the title and hydration will likely fail and ' + 'fall back to client rendering'); | |
| 2553 } | |
| 2554 } | |
| 2555 | |
| 2556 return children; | |
| 2557 } | |
| 2558 | |
| 2559 function pushStartGenericElement(target, props, tag, responseState) { | |
| 2560 target.push(startChunkForTag(tag)); | |
| 2561 var children = null; | |
| 2562 var innerHTML = null; | |
| 2563 | |
| 2564 for (var propKey in props) { | |
| 2565 if (hasOwnProperty.call(props, propKey)) { | |
| 2566 var propValue = props[propKey]; | |
| 2567 | |
| 2568 if (propValue == null) { | |
| 2569 continue; | |
| 2570 } | |
| 2571 | |
| 2572 switch (propKey) { | |
| 2573 case 'children': | |
| 2574 children = propValue; | |
| 2575 break; | |
| 2576 | |
| 2577 case 'dangerouslySetInnerHTML': | |
| 2578 innerHTML = propValue; | |
| 2579 break; | |
| 2580 | |
| 2581 default: | |
| 2582 pushAttribute(target, responseState, propKey, propValue); | |
| 2583 break; | |
| 2584 } | |
| 2585 } | |
| 2586 } | |
| 2587 | |
| 2588 target.push(endOfStartTag); | |
| 2589 pushInnerHTML(target, innerHTML, children); | |
| 2590 | |
| 2591 if (typeof children === 'string') { | |
| 2592 // Special case children as a string to avoid the unnecessary comment. | |
| 2593 // TODO: Remove this special case after the general optimization is in place. | |
| 2594 target.push(stringToChunk(encodeHTMLTextNode(children))); | |
| 2595 return null; | |
| 2596 } | |
| 2597 | |
| 2598 return children; | |
| 2599 } | |
| 2600 | |
| 2601 function pushStartCustomElement(target, props, tag, responseState) { | |
| 2602 target.push(startChunkForTag(tag)); | |
| 2603 var children = null; | |
| 2604 var innerHTML = null; | |
| 2605 | |
| 2606 for (var propKey in props) { | |
| 2607 if (hasOwnProperty.call(props, propKey)) { | |
| 2608 var propValue = props[propKey]; | |
| 2609 | |
| 2610 if (propValue == null) { | |
| 2611 continue; | |
| 2612 } | |
| 2613 | |
| 2614 switch (propKey) { | |
| 2615 case 'children': | |
| 2616 children = propValue; | |
| 2617 break; | |
| 2618 | |
| 2619 case 'dangerouslySetInnerHTML': | |
| 2620 innerHTML = propValue; | |
| 2621 break; | |
| 2622 | |
| 2623 case 'style': | |
| 2624 pushStyle(target, responseState, propValue); | |
| 2625 break; | |
| 2626 | |
| 2627 case 'suppressContentEditableWarning': | |
| 2628 case 'suppressHydrationWarning': | |
| 2629 // Ignored. These are built-in to React on the client. | |
| 2630 break; | |
| 2631 | |
| 2632 default: | |
| 2633 if (isAttributeNameSafe(propKey) && typeof propValue !== 'function' && typeof propValue !== 'symbol') { | |
| 2634 target.push(attributeSeparator, stringToChunk(propKey), attributeAssign, stringToChunk(escapeTextForBrowser(propValue)), attributeEnd); | |
| 2635 } | |
| 2636 | |
| 2637 break; | |
| 2638 } | |
| 2639 } | |
| 2640 } | |
| 2641 | |
| 2642 target.push(endOfStartTag); | |
| 2643 pushInnerHTML(target, innerHTML, children); | |
| 2644 return children; | |
| 2645 } | |
| 2646 | |
| 2647 var leadingNewline = stringToPrecomputedChunk('\n'); | |
| 2648 | |
| 2649 function pushStartPreformattedElement(target, props, tag, responseState) { | |
| 2650 target.push(startChunkForTag(tag)); | |
| 2651 var children = null; | |
| 2652 var innerHTML = null; | |
| 2653 | |
| 2654 for (var propKey in props) { | |
| 2655 if (hasOwnProperty.call(props, propKey)) { | |
| 2656 var propValue = props[propKey]; | |
| 2657 | |
| 2658 if (propValue == null) { | |
| 2659 continue; | |
| 2660 } | |
| 2661 | |
| 2662 switch (propKey) { | |
| 2663 case 'children': | |
| 2664 children = propValue; | |
| 2665 break; | |
| 2666 | |
| 2667 case 'dangerouslySetInnerHTML': | |
| 2668 innerHTML = propValue; | |
| 2669 break; | |
| 2670 | |
| 2671 default: | |
| 2672 pushAttribute(target, responseState, propKey, propValue); | |
| 2673 break; | |
| 2674 } | |
| 2675 } | |
| 2676 } | |
| 2677 | |
| 2678 target.push(endOfStartTag); // text/html ignores the first character in these tags if it's a newline | |
| 2679 // Prefer to break application/xml over text/html (for now) by adding | |
| 2680 // a newline specifically to get eaten by the parser. (Alternately for | |
| 2681 // textareas, replacing "^\n" with "\r\n" doesn't get eaten, and the first | |
| 2682 // \r is normalized out by HTMLTextAreaElement#value.) | |
| 2683 // See: <http://www.w3.org/TR/html-polyglot/#newlines-in-textarea-and-pre> | |
| 2684 // See: <http://www.w3.org/TR/html5/syntax.html#element-restrictions> | |
| 2685 // See: <http://www.w3.org/TR/html5/syntax.html#newlines> | |
| 2686 // See: Parsing of "textarea" "listing" and "pre" elements | |
| 2687 // from <http://www.w3.org/TR/html5/syntax.html#parsing-main-inbody> | |
| 2688 // TODO: This doesn't deal with the case where the child is an array | |
| 2689 // or component that returns a string. | |
| 2690 | |
| 2691 if (innerHTML != null) { | |
| 2692 if (children != null) { | |
| 2693 throw new Error('Can only set one of `children` or `props.dangerouslySetInnerHTML`.'); | |
| 2694 } | |
| 2695 | |
| 2696 if (typeof innerHTML !== 'object' || !('__html' in innerHTML)) { | |
| 2697 throw new Error('`props.dangerouslySetInnerHTML` must be in the form `{__html: ...}`. ' + 'Please visit https://reactjs.org/link/dangerously-set-inner-html ' + 'for more information.'); | |
| 2698 } | |
| 2699 | |
| 2700 var html = innerHTML.__html; | |
| 2701 | |
| 2702 if (html !== null && html !== undefined) { | |
| 2703 if (typeof html === 'string' && html.length > 0 && html[0] === '\n') { | |
| 2704 target.push(leadingNewline, stringToChunk(html)); | |
| 2705 } else { | |
| 2706 { | |
| 2707 checkHtmlStringCoercion(html); | |
| 2708 } | |
| 2709 | |
| 2710 target.push(stringToChunk('' + html)); | |
| 2711 } | |
| 2712 } | |
| 2713 } | |
| 2714 | |
| 2715 if (typeof children === 'string' && children[0] === '\n') { | |
| 2716 target.push(leadingNewline); | |
| 2717 } | |
| 2718 | |
| 2719 return children; | |
| 2720 } // We accept any tag to be rendered but since this gets injected into arbitrary | |
| 2721 // HTML, we want to make sure that it's a safe tag. | |
| 2722 // http://www.w3.org/TR/REC-xml/#NT-Name | |
| 2723 | |
| 2724 | |
| 2725 var VALID_TAG_REGEX = /^[a-zA-Z][a-zA-Z:_\.\-\d]*$/; // Simplified subset | |
| 2726 | |
| 2727 var validatedTagCache = new Map(); | |
| 2728 | |
| 2729 function startChunkForTag(tag) { | |
| 2730 var tagStartChunk = validatedTagCache.get(tag); | |
| 2731 | |
| 2732 if (tagStartChunk === undefined) { | |
| 2733 if (!VALID_TAG_REGEX.test(tag)) { | |
| 2734 throw new Error("Invalid tag: " + tag); | |
| 2735 } | |
| 2736 | |
| 2737 tagStartChunk = stringToPrecomputedChunk('<' + tag); | |
| 2738 validatedTagCache.set(tag, tagStartChunk); | |
| 2739 } | |
| 2740 | |
| 2741 return tagStartChunk; | |
| 2742 } | |
| 2743 | |
| 2744 var DOCTYPE = stringToPrecomputedChunk('<!DOCTYPE html>'); | |
| 2745 function pushStartInstance(target, type, props, responseState, formatContext) { | |
| 2746 { | |
| 2747 validateProperties(type, props); | |
| 2748 validateProperties$1(type, props); | |
| 2749 validateProperties$2(type, props, null); | |
| 2750 | |
| 2751 if (!props.suppressContentEditableWarning && props.contentEditable && props.children != null) { | |
| 2752 error('A component is `contentEditable` and contains `children` managed by ' + 'React. It is now your responsibility to guarantee that none of ' + 'those nodes are unexpectedly modified or duplicated. This is ' + 'probably not intentional.'); | |
| 2753 } | |
| 2754 | |
| 2755 if (formatContext.insertionMode !== SVG_MODE && formatContext.insertionMode !== MATHML_MODE) { | |
| 2756 if (type.indexOf('-') === -1 && typeof props.is !== 'string' && type.toLowerCase() !== type) { | |
| 2757 error('<%s /> is using incorrect casing. ' + 'Use PascalCase for React components, ' + 'or lowercase for HTML elements.', type); | |
| 2758 } | |
| 2759 } | |
| 2760 } | |
| 2761 | |
| 2762 switch (type) { | |
| 2763 // Special tags | |
| 2764 case 'select': | |
| 2765 return pushStartSelect(target, props, responseState); | |
| 2766 | |
| 2767 case 'option': | |
| 2768 return pushStartOption(target, props, responseState, formatContext); | |
| 2769 | |
| 2770 case 'textarea': | |
| 2771 return pushStartTextArea(target, props, responseState); | |
| 2772 | |
| 2773 case 'input': | |
| 2774 return pushInput(target, props, responseState); | |
| 2775 | |
| 2776 case 'menuitem': | |
| 2777 return pushStartMenuItem(target, props, responseState); | |
| 2778 | |
| 2779 case 'title': | |
| 2780 return pushStartTitle(target, props, responseState); | |
| 2781 // Newline eating tags | |
| 2782 | |
| 2783 case 'listing': | |
| 2784 case 'pre': | |
| 2785 { | |
| 2786 return pushStartPreformattedElement(target, props, type, responseState); | |
| 2787 } | |
| 2788 // Omitted close tags | |
| 2789 | |
| 2790 case 'area': | |
| 2791 case 'base': | |
| 2792 case 'br': | |
| 2793 case 'col': | |
| 2794 case 'embed': | |
| 2795 case 'hr': | |
| 2796 case 'img': | |
| 2797 case 'keygen': | |
| 2798 case 'link': | |
| 2799 case 'meta': | |
| 2800 case 'param': | |
| 2801 case 'source': | |
| 2802 case 'track': | |
| 2803 case 'wbr': | |
| 2804 { | |
| 2805 return pushSelfClosing(target, props, type, responseState); | |
| 2806 } | |
| 2807 // These are reserved SVG and MathML elements, that are never custom elements. | |
| 2808 // https://w3c.github.io/webcomponents/spec/custom/#custom-elements-core-concepts | |
| 2809 | |
| 2810 case 'annotation-xml': | |
| 2811 case 'color-profile': | |
| 2812 case 'font-face': | |
| 2813 case 'font-face-src': | |
| 2814 case 'font-face-uri': | |
| 2815 case 'font-face-format': | |
| 2816 case 'font-face-name': | |
| 2817 case 'missing-glyph': | |
| 2818 { | |
| 2819 return pushStartGenericElement(target, props, type, responseState); | |
| 2820 } | |
| 2821 | |
| 2822 case 'html': | |
| 2823 { | |
| 2824 if (formatContext.insertionMode === ROOT_HTML_MODE) { | |
| 2825 // If we're rendering the html tag and we're at the root (i.e. not in foreignObject) | |
| 2826 // then we also emit the DOCTYPE as part of the root content as a convenience for | |
| 2827 // rendering the whole document. | |
| 2828 target.push(DOCTYPE); | |
| 2829 } | |
| 2830 | |
| 2831 return pushStartGenericElement(target, props, type, responseState); | |
| 2832 } | |
| 2833 | |
| 2834 default: | |
| 2835 { | |
| 2836 if (type.indexOf('-') === -1 && typeof props.is !== 'string') { | |
| 2837 // Generic element | |
| 2838 return pushStartGenericElement(target, props, type, responseState); | |
| 2839 } else { | |
| 2840 // Custom element | |
| 2841 return pushStartCustomElement(target, props, type, responseState); | |
| 2842 } | |
| 2843 } | |
| 2844 } | |
| 2845 } | |
| 2846 var endTag1 = stringToPrecomputedChunk('</'); | |
| 2847 var endTag2 = stringToPrecomputedChunk('>'); | |
| 2848 function pushEndInstance(target, type, props) { | |
| 2849 switch (type) { | |
| 2850 // Omitted close tags | |
| 2851 // TODO: Instead of repeating this switch we could try to pass a flag from above. | |
| 2852 // That would require returning a tuple. Which might be ok if it gets inlined. | |
| 2853 case 'area': | |
| 2854 case 'base': | |
| 2855 case 'br': | |
| 2856 case 'col': | |
| 2857 case 'embed': | |
| 2858 case 'hr': | |
| 2859 case 'img': | |
| 2860 case 'input': | |
| 2861 case 'keygen': | |
| 2862 case 'link': | |
| 2863 case 'meta': | |
| 2864 case 'param': | |
| 2865 case 'source': | |
| 2866 case 'track': | |
| 2867 case 'wbr': | |
| 2868 { | |
| 2869 // No close tag needed. | |
| 2870 break; | |
| 2871 } | |
| 2872 | |
| 2873 default: | |
| 2874 { | |
| 2875 target.push(endTag1, stringToChunk(type), endTag2); | |
| 2876 } | |
| 2877 } | |
| 2878 } | |
| 2879 function writeCompletedRoot(destination, responseState) { | |
| 2880 var bootstrapChunks = responseState.bootstrapChunks; | |
| 2881 var i = 0; | |
| 2882 | |
| 2883 for (; i < bootstrapChunks.length - 1; i++) { | |
| 2884 writeChunk(destination, bootstrapChunks[i]); | |
| 2885 } | |
| 2886 | |
| 2887 if (i < bootstrapChunks.length) { | |
| 2888 return writeChunkAndReturn(destination, bootstrapChunks[i]); | |
| 2889 } | |
| 2890 | |
| 2891 return true; | |
| 2892 } // Structural Nodes | |
| 2893 // A placeholder is a node inside a hidden partial tree that can be filled in later, but before | |
| 2894 // display. It's never visible to users. We use the template tag because it can be used in every | |
| 2895 // type of parent. <script> tags also work in every other tag except <colgroup>. | |
| 2896 | |
| 2897 var placeholder1 = stringToPrecomputedChunk('<template id="'); | |
| 2898 var placeholder2 = stringToPrecomputedChunk('"></template>'); | |
| 2899 function writePlaceholder(destination, responseState, id) { | |
| 2900 writeChunk(destination, placeholder1); | |
| 2901 writeChunk(destination, responseState.placeholderPrefix); | |
| 2902 var formattedID = stringToChunk(id.toString(16)); | |
| 2903 writeChunk(destination, formattedID); | |
| 2904 return writeChunkAndReturn(destination, placeholder2); | |
| 2905 } // Suspense boundaries are encoded as comments. | |
| 2906 | |
| 2907 var startCompletedSuspenseBoundary = stringToPrecomputedChunk('<!--$-->'); | |
| 2908 var startPendingSuspenseBoundary1 = stringToPrecomputedChunk('<!--$?--><template id="'); | |
| 2909 var startPendingSuspenseBoundary2 = stringToPrecomputedChunk('"></template>'); | |
| 2910 var startClientRenderedSuspenseBoundary = stringToPrecomputedChunk('<!--$!-->'); | |
| 2911 var endSuspenseBoundary = stringToPrecomputedChunk('<!--/$-->'); | |
| 2912 var clientRenderedSuspenseBoundaryError1 = stringToPrecomputedChunk('<template'); | |
| 2913 var clientRenderedSuspenseBoundaryErrorAttrInterstitial = stringToPrecomputedChunk('"'); | |
| 2914 var clientRenderedSuspenseBoundaryError1A = stringToPrecomputedChunk(' data-dgst="'); | |
| 2915 var clientRenderedSuspenseBoundaryError1B = stringToPrecomputedChunk(' data-msg="'); | |
| 2916 var clientRenderedSuspenseBoundaryError1C = stringToPrecomputedChunk(' data-stck="'); | |
| 2917 var clientRenderedSuspenseBoundaryError2 = stringToPrecomputedChunk('></template>'); | |
| 2918 function writeStartCompletedSuspenseBoundary(destination, responseState) { | |
| 2919 return writeChunkAndReturn(destination, startCompletedSuspenseBoundary); | |
| 2920 } | |
| 2921 function writeStartPendingSuspenseBoundary(destination, responseState, id) { | |
| 2922 writeChunk(destination, startPendingSuspenseBoundary1); | |
| 2923 | |
| 2924 if (id === null) { | |
| 2925 throw new Error('An ID must have been assigned before we can complete the boundary.'); | |
| 2926 } | |
| 2927 | |
| 2928 writeChunk(destination, id); | |
| 2929 return writeChunkAndReturn(destination, startPendingSuspenseBoundary2); | |
| 2930 } | |
| 2931 function writeStartClientRenderedSuspenseBoundary(destination, responseState, errorDigest, errorMesssage, errorComponentStack) { | |
| 2932 var result; | |
| 2933 result = writeChunkAndReturn(destination, startClientRenderedSuspenseBoundary); | |
| 2934 writeChunk(destination, clientRenderedSuspenseBoundaryError1); | |
| 2935 | |
| 2936 if (errorDigest) { | |
| 2937 writeChunk(destination, clientRenderedSuspenseBoundaryError1A); | |
| 2938 writeChunk(destination, stringToChunk(escapeTextForBrowser(errorDigest))); | |
| 2939 writeChunk(destination, clientRenderedSuspenseBoundaryErrorAttrInterstitial); | |
| 2940 } | |
| 2941 | |
| 2942 { | |
| 2943 if (errorMesssage) { | |
| 2944 writeChunk(destination, clientRenderedSuspenseBoundaryError1B); | |
| 2945 writeChunk(destination, stringToChunk(escapeTextForBrowser(errorMesssage))); | |
| 2946 writeChunk(destination, clientRenderedSuspenseBoundaryErrorAttrInterstitial); | |
| 2947 } | |
| 2948 | |
| 2949 if (errorComponentStack) { | |
| 2950 writeChunk(destination, clientRenderedSuspenseBoundaryError1C); | |
| 2951 writeChunk(destination, stringToChunk(escapeTextForBrowser(errorComponentStack))); | |
| 2952 writeChunk(destination, clientRenderedSuspenseBoundaryErrorAttrInterstitial); | |
| 2953 } | |
| 2954 } | |
| 2955 | |
| 2956 result = writeChunkAndReturn(destination, clientRenderedSuspenseBoundaryError2); | |
| 2957 return result; | |
| 2958 } | |
| 2959 function writeEndCompletedSuspenseBoundary(destination, responseState) { | |
| 2960 return writeChunkAndReturn(destination, endSuspenseBoundary); | |
| 2961 } | |
| 2962 function writeEndPendingSuspenseBoundary(destination, responseState) { | |
| 2963 return writeChunkAndReturn(destination, endSuspenseBoundary); | |
| 2964 } | |
| 2965 function writeEndClientRenderedSuspenseBoundary(destination, responseState) { | |
| 2966 return writeChunkAndReturn(destination, endSuspenseBoundary); | |
| 2967 } | |
| 2968 var startSegmentHTML = stringToPrecomputedChunk('<div hidden id="'); | |
| 2969 var startSegmentHTML2 = stringToPrecomputedChunk('">'); | |
| 2970 var endSegmentHTML = stringToPrecomputedChunk('</div>'); | |
| 2971 var startSegmentSVG = stringToPrecomputedChunk('<svg aria-hidden="true" style="display:none" id="'); | |
| 2972 var startSegmentSVG2 = stringToPrecomputedChunk('">'); | |
| 2973 var endSegmentSVG = stringToPrecomputedChunk('</svg>'); | |
| 2974 var startSegmentMathML = stringToPrecomputedChunk('<math aria-hidden="true" style="display:none" id="'); | |
| 2975 var startSegmentMathML2 = stringToPrecomputedChunk('">'); | |
| 2976 var endSegmentMathML = stringToPrecomputedChunk('</math>'); | |
| 2977 var startSegmentTable = stringToPrecomputedChunk('<table hidden id="'); | |
| 2978 var startSegmentTable2 = stringToPrecomputedChunk('">'); | |
| 2979 var endSegmentTable = stringToPrecomputedChunk('</table>'); | |
| 2980 var startSegmentTableBody = stringToPrecomputedChunk('<table hidden><tbody id="'); | |
| 2981 var startSegmentTableBody2 = stringToPrecomputedChunk('">'); | |
| 2982 var endSegmentTableBody = stringToPrecomputedChunk('</tbody></table>'); | |
| 2983 var startSegmentTableRow = stringToPrecomputedChunk('<table hidden><tr id="'); | |
| 2984 var startSegmentTableRow2 = stringToPrecomputedChunk('">'); | |
| 2985 var endSegmentTableRow = stringToPrecomputedChunk('</tr></table>'); | |
| 2986 var startSegmentColGroup = stringToPrecomputedChunk('<table hidden><colgroup id="'); | |
| 2987 var startSegmentColGroup2 = stringToPrecomputedChunk('">'); | |
| 2988 var endSegmentColGroup = stringToPrecomputedChunk('</colgroup></table>'); | |
| 2989 function writeStartSegment(destination, responseState, formatContext, id) { | |
| 2990 switch (formatContext.insertionMode) { | |
| 2991 case ROOT_HTML_MODE: | |
| 2992 case HTML_MODE: | |
| 2993 { | |
| 2994 writeChunk(destination, startSegmentHTML); | |
| 2995 writeChunk(destination, responseState.segmentPrefix); | |
| 2996 writeChunk(destination, stringToChunk(id.toString(16))); | |
| 2997 return writeChunkAndReturn(destination, startSegmentHTML2); | |
| 2998 } | |
| 2999 | |
| 3000 case SVG_MODE: | |
| 3001 { | |
| 3002 writeChunk(destination, startSegmentSVG); | |
| 3003 writeChunk(destination, responseState.segmentPrefix); | |
| 3004 writeChunk(destination, stringToChunk(id.toString(16))); | |
| 3005 return writeChunkAndReturn(destination, startSegmentSVG2); | |
| 3006 } | |
| 3007 | |
| 3008 case MATHML_MODE: | |
| 3009 { | |
| 3010 writeChunk(destination, startSegmentMathML); | |
| 3011 writeChunk(destination, responseState.segmentPrefix); | |
| 3012 writeChunk(destination, stringToChunk(id.toString(16))); | |
| 3013 return writeChunkAndReturn(destination, startSegmentMathML2); | |
| 3014 } | |
| 3015 | |
| 3016 case HTML_TABLE_MODE: | |
| 3017 { | |
| 3018 writeChunk(destination, startSegmentTable); | |
| 3019 writeChunk(destination, responseState.segmentPrefix); | |
| 3020 writeChunk(destination, stringToChunk(id.toString(16))); | |
| 3021 return writeChunkAndReturn(destination, startSegmentTable2); | |
| 3022 } | |
| 3023 // TODO: For the rest of these, there will be extra wrapper nodes that never | |
| 3024 // get deleted from the document. We need to delete the table too as part | |
| 3025 // of the injected scripts. They are invisible though so it's not too terrible | |
| 3026 // and it's kind of an edge case to suspend in a table. Totally supported though. | |
| 3027 | |
| 3028 case HTML_TABLE_BODY_MODE: | |
| 3029 { | |
| 3030 writeChunk(destination, startSegmentTableBody); | |
| 3031 writeChunk(destination, responseState.segmentPrefix); | |
| 3032 writeChunk(destination, stringToChunk(id.toString(16))); | |
| 3033 return writeChunkAndReturn(destination, startSegmentTableBody2); | |
| 3034 } | |
| 3035 | |
| 3036 case HTML_TABLE_ROW_MODE: | |
| 3037 { | |
| 3038 writeChunk(destination, startSegmentTableRow); | |
| 3039 writeChunk(destination, responseState.segmentPrefix); | |
| 3040 writeChunk(destination, stringToChunk(id.toString(16))); | |
| 3041 return writeChunkAndReturn(destination, startSegmentTableRow2); | |
| 3042 } | |
| 3043 | |
| 3044 case HTML_COLGROUP_MODE: | |
| 3045 { | |
| 3046 writeChunk(destination, startSegmentColGroup); | |
| 3047 writeChunk(destination, responseState.segmentPrefix); | |
| 3048 writeChunk(destination, stringToChunk(id.toString(16))); | |
| 3049 return writeChunkAndReturn(destination, startSegmentColGroup2); | |
| 3050 } | |
| 3051 | |
| 3052 default: | |
| 3053 { | |
| 3054 throw new Error('Unknown insertion mode. This is a bug in React.'); | |
| 3055 } | |
| 3056 } | |
| 3057 } | |
| 3058 function writeEndSegment(destination, formatContext) { | |
| 3059 switch (formatContext.insertionMode) { | |
| 3060 case ROOT_HTML_MODE: | |
| 3061 case HTML_MODE: | |
| 3062 { | |
| 3063 return writeChunkAndReturn(destination, endSegmentHTML); | |
| 3064 } | |
| 3065 | |
| 3066 case SVG_MODE: | |
| 3067 { | |
| 3068 return writeChunkAndReturn(destination, endSegmentSVG); | |
| 3069 } | |
| 3070 | |
| 3071 case MATHML_MODE: | |
| 3072 { | |
| 3073 return writeChunkAndReturn(destination, endSegmentMathML); | |
| 3074 } | |
| 3075 | |
| 3076 case HTML_TABLE_MODE: | |
| 3077 { | |
| 3078 return writeChunkAndReturn(destination, endSegmentTable); | |
| 3079 } | |
| 3080 | |
| 3081 case HTML_TABLE_BODY_MODE: | |
| 3082 { | |
| 3083 return writeChunkAndReturn(destination, endSegmentTableBody); | |
| 3084 } | |
| 3085 | |
| 3086 case HTML_TABLE_ROW_MODE: | |
| 3087 { | |
| 3088 return writeChunkAndReturn(destination, endSegmentTableRow); | |
| 3089 } | |
| 3090 | |
| 3091 case HTML_COLGROUP_MODE: | |
| 3092 { | |
| 3093 return writeChunkAndReturn(destination, endSegmentColGroup); | |
| 3094 } | |
| 3095 | |
| 3096 default: | |
| 3097 { | |
| 3098 throw new Error('Unknown insertion mode. This is a bug in React.'); | |
| 3099 } | |
| 3100 } | |
| 3101 } // Instruction Set | |
| 3102 // The following code is the source scripts that we then minify and inline below, | |
| 3103 // with renamed function names that we hope don't collide: | |
| 3104 // const COMMENT_NODE = 8; | |
| 3105 // const SUSPENSE_START_DATA = '$'; | |
| 3106 // const SUSPENSE_END_DATA = '/$'; | |
| 3107 // const SUSPENSE_PENDING_START_DATA = '$?'; | |
| 3108 // const SUSPENSE_FALLBACK_START_DATA = '$!'; | |
| 3109 // | |
| 3110 // function clientRenderBoundary(suspenseBoundaryID, errorDigest, errorMsg, errorComponentStack) { | |
| 3111 // // Find the fallback's first element. | |
| 3112 // const suspenseIdNode = document.getElementById(suspenseBoundaryID); | |
| 3113 // if (!suspenseIdNode) { | |
| 3114 // // The user must have already navigated away from this tree. | |
| 3115 // // E.g. because the parent was hydrated. | |
| 3116 // return; | |
| 3117 // } | |
| 3118 // // Find the boundary around the fallback. This is always the previous node. | |
| 3119 // const suspenseNode = suspenseIdNode.previousSibling; | |
| 3120 // // Tag it to be client rendered. | |
| 3121 // suspenseNode.data = SUSPENSE_FALLBACK_START_DATA; | |
| 3122 // // assign error metadata to first sibling | |
| 3123 // let dataset = suspenseIdNode.dataset; | |
| 3124 // if (errorDigest) dataset.dgst = errorDigest; | |
| 3125 // if (errorMsg) dataset.msg = errorMsg; | |
| 3126 // if (errorComponentStack) dataset.stck = errorComponentStack; | |
| 3127 // // Tell React to retry it if the parent already hydrated. | |
| 3128 // if (suspenseNode._reactRetry) { | |
| 3129 // suspenseNode._reactRetry(); | |
| 3130 // } | |
| 3131 // } | |
| 3132 // | |
| 3133 // function completeBoundary(suspenseBoundaryID, contentID) { | |
| 3134 // // Find the fallback's first element. | |
| 3135 // const suspenseIdNode = document.getElementById(suspenseBoundaryID); | |
| 3136 // const contentNode = document.getElementById(contentID); | |
| 3137 // // We'll detach the content node so that regardless of what happens next we don't leave in the tree. | |
| 3138 // // This might also help by not causing recalcing each time we move a child from here to the target. | |
| 3139 // contentNode.parentNode.removeChild(contentNode); | |
| 3140 // if (!suspenseIdNode) { | |
| 3141 // // The user must have already navigated away from this tree. | |
| 3142 // // E.g. because the parent was hydrated. That's fine there's nothing to do | |
| 3143 // // but we have to make sure that we already deleted the container node. | |
| 3144 // return; | |
| 3145 // } | |
| 3146 // // Find the boundary around the fallback. This is always the previous node. | |
| 3147 // const suspenseNode = suspenseIdNode.previousSibling; | |
| 3148 // | |
| 3149 // // Clear all the existing children. This is complicated because | |
| 3150 // // there can be embedded Suspense boundaries in the fallback. | |
| 3151 // // This is similar to clearSuspenseBoundary in ReactDOMHostConfig. | |
| 3152 // // TODO: We could avoid this if we never emitted suspense boundaries in fallback trees. | |
| 3153 // // They never hydrate anyway. However, currently we support incrementally loading the fallback. | |
| 3154 // const parentInstance = suspenseNode.parentNode; | |
| 3155 // let node = suspenseNode.nextSibling; | |
| 3156 // let depth = 0; | |
| 3157 // do { | |
| 3158 // if (node && node.nodeType === COMMENT_NODE) { | |
| 3159 // const data = node.data; | |
| 3160 // if (data === SUSPENSE_END_DATA) { | |
| 3161 // if (depth === 0) { | |
| 3162 // break; | |
| 3163 // } else { | |
| 3164 // depth--; | |
| 3165 // } | |
| 3166 // } else if ( | |
| 3167 // data === SUSPENSE_START_DATA || | |
| 3168 // data === SUSPENSE_PENDING_START_DATA || | |
| 3169 // data === SUSPENSE_FALLBACK_START_DATA | |
| 3170 // ) { | |
| 3171 // depth++; | |
| 3172 // } | |
| 3173 // } | |
| 3174 // | |
| 3175 // const nextNode = node.nextSibling; | |
| 3176 // parentInstance.removeChild(node); | |
| 3177 // node = nextNode; | |
| 3178 // } while (node); | |
| 3179 // | |
| 3180 // const endOfBoundary = node; | |
| 3181 // | |
| 3182 // // Insert all the children from the contentNode between the start and end of suspense boundary. | |
| 3183 // while (contentNode.firstChild) { | |
| 3184 // parentInstance.insertBefore(contentNode.firstChild, endOfBoundary); | |
| 3185 // } | |
| 3186 // suspenseNode.data = SUSPENSE_START_DATA; | |
| 3187 // if (suspenseNode._reactRetry) { | |
| 3188 // suspenseNode._reactRetry(); | |
| 3189 // } | |
| 3190 // } | |
| 3191 // | |
| 3192 // function completeSegment(containerID, placeholderID) { | |
| 3193 // const segmentContainer = document.getElementById(containerID); | |
| 3194 // const placeholderNode = document.getElementById(placeholderID); | |
| 3195 // // We always expect both nodes to exist here because, while we might | |
| 3196 // // have navigated away from the main tree, we still expect the detached | |
| 3197 // // tree to exist. | |
| 3198 // segmentContainer.parentNode.removeChild(segmentContainer); | |
| 3199 // while (segmentContainer.firstChild) { | |
| 3200 // placeholderNode.parentNode.insertBefore( | |
| 3201 // segmentContainer.firstChild, | |
| 3202 // placeholderNode, | |
| 3203 // ); | |
| 3204 // } | |
| 3205 // placeholderNode.parentNode.removeChild(placeholderNode); | |
| 3206 // } | |
| 3207 | |
| 3208 var completeSegmentFunction = 'function $RS(a,b){a=document.getElementById(a);b=document.getElementById(b);for(a.parentNode.removeChild(a);a.firstChild;)b.parentNode.insertBefore(a.firstChild,b);b.parentNode.removeChild(b)}'; | |
| 3209 var completeBoundaryFunction = 'function $RC(a,b){a=document.getElementById(a);b=document.getElementById(b);b.parentNode.removeChild(b);if(a){a=a.previousSibling;var f=a.parentNode,c=a.nextSibling,e=0;do{if(c&&8===c.nodeType){var d=c.data;if("/$"===d)if(0===e)break;else e--;else"$"!==d&&"$?"!==d&&"$!"!==d||e++}d=c.nextSibling;f.removeChild(c);c=d}while(c);for(;b.firstChild;)f.insertBefore(b.firstChild,c);a.data="$";a._reactRetry&&a._reactRetry()}}'; | |
| 3210 var clientRenderFunction = 'function $RX(b,c,d,e){var a=document.getElementById(b);a&&(b=a.previousSibling,b.data="$!",a=a.dataset,c&&(a.dgst=c),d&&(a.msg=d),e&&(a.stck=e),b._reactRetry&&b._reactRetry())}'; | |
| 3211 var completeSegmentScript1Full = stringToPrecomputedChunk(completeSegmentFunction + ';$RS("'); | |
| 3212 var completeSegmentScript1Partial = stringToPrecomputedChunk('$RS("'); | |
| 3213 var completeSegmentScript2 = stringToPrecomputedChunk('","'); | |
| 3214 var completeSegmentScript3 = stringToPrecomputedChunk('")</script>'); | |
| 3215 function writeCompletedSegmentInstruction(destination, responseState, contentSegmentID) { | |
| 3216 writeChunk(destination, responseState.startInlineScript); | |
| 3217 | |
| 3218 if (!responseState.sentCompleteSegmentFunction) { | |
| 3219 // The first time we write this, we'll need to include the full implementation. | |
| 3220 responseState.sentCompleteSegmentFunction = true; | |
| 3221 writeChunk(destination, completeSegmentScript1Full); | |
| 3222 } else { | |
| 3223 // Future calls can just reuse the same function. | |
| 3224 writeChunk(destination, completeSegmentScript1Partial); | |
| 3225 } | |
| 3226 | |
| 3227 writeChunk(destination, responseState.segmentPrefix); | |
| 3228 var formattedID = stringToChunk(contentSegmentID.toString(16)); | |
| 3229 writeChunk(destination, formattedID); | |
| 3230 writeChunk(destination, completeSegmentScript2); | |
| 3231 writeChunk(destination, responseState.placeholderPrefix); | |
| 3232 writeChunk(destination, formattedID); | |
| 3233 return writeChunkAndReturn(destination, completeSegmentScript3); | |
| 3234 } | |
| 3235 var completeBoundaryScript1Full = stringToPrecomputedChunk(completeBoundaryFunction + ';$RC("'); | |
| 3236 var completeBoundaryScript1Partial = stringToPrecomputedChunk('$RC("'); | |
| 3237 var completeBoundaryScript2 = stringToPrecomputedChunk('","'); | |
| 3238 var completeBoundaryScript3 = stringToPrecomputedChunk('")</script>'); | |
| 3239 function writeCompletedBoundaryInstruction(destination, responseState, boundaryID, contentSegmentID) { | |
| 3240 writeChunk(destination, responseState.startInlineScript); | |
| 3241 | |
| 3242 if (!responseState.sentCompleteBoundaryFunction) { | |
| 3243 // The first time we write this, we'll need to include the full implementation. | |
| 3244 responseState.sentCompleteBoundaryFunction = true; | |
| 3245 writeChunk(destination, completeBoundaryScript1Full); | |
| 3246 } else { | |
| 3247 // Future calls can just reuse the same function. | |
| 3248 writeChunk(destination, completeBoundaryScript1Partial); | |
| 3249 } | |
| 3250 | |
| 3251 if (boundaryID === null) { | |
| 3252 throw new Error('An ID must have been assigned before we can complete the boundary.'); | |
| 3253 } | |
| 3254 | |
| 3255 var formattedContentID = stringToChunk(contentSegmentID.toString(16)); | |
| 3256 writeChunk(destination, boundaryID); | |
| 3257 writeChunk(destination, completeBoundaryScript2); | |
| 3258 writeChunk(destination, responseState.segmentPrefix); | |
| 3259 writeChunk(destination, formattedContentID); | |
| 3260 return writeChunkAndReturn(destination, completeBoundaryScript3); | |
| 3261 } | |
| 3262 var clientRenderScript1Full = stringToPrecomputedChunk(clientRenderFunction + ';$RX("'); | |
| 3263 var clientRenderScript1Partial = stringToPrecomputedChunk('$RX("'); | |
| 3264 var clientRenderScript1A = stringToPrecomputedChunk('"'); | |
| 3265 var clientRenderScript2 = stringToPrecomputedChunk(')</script>'); | |
| 3266 var clientRenderErrorScriptArgInterstitial = stringToPrecomputedChunk(','); | |
| 3267 function writeClientRenderBoundaryInstruction(destination, responseState, boundaryID, errorDigest, errorMessage, errorComponentStack) { | |
| 3268 writeChunk(destination, responseState.startInlineScript); | |
| 3269 | |
| 3270 if (!responseState.sentClientRenderFunction) { | |
| 3271 // The first time we write this, we'll need to include the full implementation. | |
| 3272 responseState.sentClientRenderFunction = true; | |
| 3273 writeChunk(destination, clientRenderScript1Full); | |
| 3274 } else { | |
| 3275 // Future calls can just reuse the same function. | |
| 3276 writeChunk(destination, clientRenderScript1Partial); | |
| 3277 } | |
| 3278 | |
| 3279 if (boundaryID === null) { | |
| 3280 throw new Error('An ID must have been assigned before we can complete the boundary.'); | |
| 3281 } | |
| 3282 | |
| 3283 writeChunk(destination, boundaryID); | |
| 3284 writeChunk(destination, clientRenderScript1A); | |
| 3285 | |
| 3286 if (errorDigest || errorMessage || errorComponentStack) { | |
| 3287 writeChunk(destination, clientRenderErrorScriptArgInterstitial); | |
| 3288 writeChunk(destination, stringToChunk(escapeJSStringsForInstructionScripts(errorDigest || ''))); | |
| 3289 } | |
| 3290 | |
| 3291 if (errorMessage || errorComponentStack) { | |
| 3292 writeChunk(destination, clientRenderErrorScriptArgInterstitial); | |
| 3293 writeChunk(destination, stringToChunk(escapeJSStringsForInstructionScripts(errorMessage || ''))); | |
| 3294 } | |
| 3295 | |
| 3296 if (errorComponentStack) { | |
| 3297 writeChunk(destination, clientRenderErrorScriptArgInterstitial); | |
| 3298 writeChunk(destination, stringToChunk(escapeJSStringsForInstructionScripts(errorComponentStack))); | |
| 3299 } | |
| 3300 | |
| 3301 return writeChunkAndReturn(destination, clientRenderScript2); | |
| 3302 } | |
| 3303 var regexForJSStringsInScripts = /[<\u2028\u2029]/g; | |
| 3304 | |
| 3305 function escapeJSStringsForInstructionScripts(input) { | |
| 3306 var escaped = JSON.stringify(input); | |
| 3307 return escaped.replace(regexForJSStringsInScripts, function (match) { | |
| 3308 switch (match) { | |
| 3309 // santizing breaking out of strings and script tags | |
| 3310 case '<': | |
| 3311 return "\\u003c"; | |
| 3312 | |
| 3313 case "\u2028": | |
| 3314 return "\\u2028"; | |
| 3315 | |
| 3316 case "\u2029": | |
| 3317 return "\\u2029"; | |
| 3318 | |
| 3319 default: | |
| 3320 { | |
| 3321 // eslint-disable-next-line react-internal/prod-error-codes | |
| 3322 throw new Error('escapeJSStringsForInstructionScripts encountered a match it does not know how to replace. this means the match regex and the replacement characters are no longer in sync. This is a bug in React'); | |
| 3323 } | |
| 3324 } | |
| 3325 }); | |
| 3326 } | |
| 3327 | |
| 3328 function createResponseState$1(generateStaticMarkup, identifierPrefix) { | |
| 3329 var responseState = createResponseState(identifierPrefix, undefined); | |
| 3330 return { | |
| 3331 // Keep this in sync with ReactDOMServerFormatConfig | |
| 3332 bootstrapChunks: responseState.bootstrapChunks, | |
| 3333 startInlineScript: responseState.startInlineScript, | |
| 3334 placeholderPrefix: responseState.placeholderPrefix, | |
| 3335 segmentPrefix: responseState.segmentPrefix, | |
| 3336 boundaryPrefix: responseState.boundaryPrefix, | |
| 3337 idPrefix: responseState.idPrefix, | |
| 3338 nextSuspenseID: responseState.nextSuspenseID, | |
| 3339 sentCompleteSegmentFunction: responseState.sentCompleteSegmentFunction, | |
| 3340 sentCompleteBoundaryFunction: responseState.sentCompleteBoundaryFunction, | |
| 3341 sentClientRenderFunction: responseState.sentClientRenderFunction, | |
| 3342 // This is an extra field for the legacy renderer | |
| 3343 generateStaticMarkup: generateStaticMarkup | |
| 3344 }; | |
| 3345 } | |
| 3346 function createRootFormatContext() { | |
| 3347 return { | |
| 3348 insertionMode: HTML_MODE, | |
| 3349 // We skip the root mode because we don't want to emit the DOCTYPE in legacy mode. | |
| 3350 selectedValue: null | |
| 3351 }; | |
| 3352 } | |
| 3353 function pushTextInstance$1(target, text, responseState, textEmbedded) { | |
| 3354 if (responseState.generateStaticMarkup) { | |
| 3355 target.push(stringToChunk(escapeTextForBrowser(text))); | |
| 3356 return false; | |
| 3357 } else { | |
| 3358 return pushTextInstance(target, text, responseState, textEmbedded); | |
| 3359 } | |
| 3360 } | |
| 3361 function pushSegmentFinale$1(target, responseState, lastPushedText, textEmbedded) { | |
| 3362 if (responseState.generateStaticMarkup) { | |
| 3363 return; | |
| 3364 } else { | |
| 3365 return pushSegmentFinale(target, responseState, lastPushedText, textEmbedded); | |
| 3366 } | |
| 3367 } | |
| 3368 function writeStartCompletedSuspenseBoundary$1(destination, responseState) { | |
| 3369 if (responseState.generateStaticMarkup) { | |
| 3370 // A completed boundary is done and doesn't need a representation in the HTML | |
| 3371 // if we're not going to be hydrating it. | |
| 3372 return true; | |
| 3373 } | |
| 3374 | |
| 3375 return writeStartCompletedSuspenseBoundary(destination); | |
| 3376 } | |
| 3377 function writeStartClientRenderedSuspenseBoundary$1(destination, responseState, // flushing these error arguments are not currently supported in this legacy streaming format. | |
| 3378 errorDigest, errorMessage, errorComponentStack) { | |
| 3379 if (responseState.generateStaticMarkup) { | |
| 3380 // A client rendered boundary is done and doesn't need a representation in the HTML | |
| 3381 // since we'll never hydrate it. This is arguably an error in static generation. | |
| 3382 return true; | |
| 3383 } | |
| 3384 | |
| 3385 return writeStartClientRenderedSuspenseBoundary(destination, responseState, errorDigest, errorMessage, errorComponentStack); | |
| 3386 } | |
| 3387 function writeEndCompletedSuspenseBoundary$1(destination, responseState) { | |
| 3388 if (responseState.generateStaticMarkup) { | |
| 3389 return true; | |
| 3390 } | |
| 3391 | |
| 3392 return writeEndCompletedSuspenseBoundary(destination); | |
| 3393 } | |
| 3394 function writeEndClientRenderedSuspenseBoundary$1(destination, responseState) { | |
| 3395 if (responseState.generateStaticMarkup) { | |
| 3396 return true; | |
| 3397 } | |
| 3398 | |
| 3399 return writeEndClientRenderedSuspenseBoundary(destination); | |
| 3400 } | |
| 3401 | |
| 3402 var assign = Object.assign; | |
| 3403 | |
| 3404 // ATTENTION | |
| 3405 // When adding new symbols to this file, | |
| 3406 // Please consider also adding to 'react-devtools-shared/src/backend/ReactSymbols' | |
| 3407 // The Symbol used to tag the ReactElement-like types. | |
| 3408 var REACT_ELEMENT_TYPE = Symbol.for('react.element'); | |
| 3409 var REACT_PORTAL_TYPE = Symbol.for('react.portal'); | |
| 3410 var REACT_FRAGMENT_TYPE = Symbol.for('react.fragment'); | |
| 3411 var REACT_STRICT_MODE_TYPE = Symbol.for('react.strict_mode'); | |
| 3412 var REACT_PROFILER_TYPE = Symbol.for('react.profiler'); | |
| 3413 var REACT_PROVIDER_TYPE = Symbol.for('react.provider'); | |
| 3414 var REACT_CONTEXT_TYPE = Symbol.for('react.context'); | |
| 3415 var REACT_FORWARD_REF_TYPE = Symbol.for('react.forward_ref'); | |
| 3416 var REACT_SUSPENSE_TYPE = Symbol.for('react.suspense'); | |
| 3417 var REACT_SUSPENSE_LIST_TYPE = Symbol.for('react.suspense_list'); | |
| 3418 var REACT_MEMO_TYPE = Symbol.for('react.memo'); | |
| 3419 var REACT_LAZY_TYPE = Symbol.for('react.lazy'); | |
| 3420 var REACT_SCOPE_TYPE = Symbol.for('react.scope'); | |
| 3421 var REACT_DEBUG_TRACING_MODE_TYPE = Symbol.for('react.debug_trace_mode'); | |
| 3422 var REACT_LEGACY_HIDDEN_TYPE = Symbol.for('react.legacy_hidden'); | |
| 3423 var REACT_SERVER_CONTEXT_DEFAULT_VALUE_NOT_LOADED = Symbol.for('react.default_value'); | |
| 3424 var MAYBE_ITERATOR_SYMBOL = Symbol.iterator; | |
| 3425 var FAUX_ITERATOR_SYMBOL = '@@iterator'; | |
| 3426 function getIteratorFn(maybeIterable) { | |
| 3427 if (maybeIterable === null || typeof maybeIterable !== 'object') { | |
| 3428 return null; | |
| 3429 } | |
| 3430 | |
| 3431 var maybeIterator = MAYBE_ITERATOR_SYMBOL && maybeIterable[MAYBE_ITERATOR_SYMBOL] || maybeIterable[FAUX_ITERATOR_SYMBOL]; | |
| 3432 | |
| 3433 if (typeof maybeIterator === 'function') { | |
| 3434 return maybeIterator; | |
| 3435 } | |
| 3436 | |
| 3437 return null; | |
| 3438 } | |
| 3439 | |
| 3440 function getWrappedName(outerType, innerType, wrapperName) { | |
| 3441 var displayName = outerType.displayName; | |
| 3442 | |
| 3443 if (displayName) { | |
| 3444 return displayName; | |
| 3445 } | |
| 3446 | |
| 3447 var functionName = innerType.displayName || innerType.name || ''; | |
| 3448 return functionName !== '' ? wrapperName + "(" + functionName + ")" : wrapperName; | |
| 3449 } // Keep in sync with react-reconciler/getComponentNameFromFiber | |
| 3450 | |
| 3451 | |
| 3452 function getContextName(type) { | |
| 3453 return type.displayName || 'Context'; | |
| 3454 } // Note that the reconciler package should generally prefer to use getComponentNameFromFiber() instead. | |
| 3455 | |
| 3456 | |
| 3457 function getComponentNameFromType(type) { | |
| 3458 if (type == null) { | |
| 3459 // Host root, text node or just invalid type. | |
| 3460 return null; | |
| 3461 } | |
| 3462 | |
| 3463 { | |
| 3464 if (typeof type.tag === 'number') { | |
| 3465 error('Received an unexpected object in getComponentNameFromType(). ' + 'This is likely a bug in React. Please file an issue.'); | |
| 3466 } | |
| 3467 } | |
| 3468 | |
| 3469 if (typeof type === 'function') { | |
| 3470 return type.displayName || type.name || null; | |
| 3471 } | |
| 3472 | |
| 3473 if (typeof type === 'string') { | |
| 3474 return type; | |
| 3475 } | |
| 3476 | |
| 3477 switch (type) { | |
| 3478 case REACT_FRAGMENT_TYPE: | |
| 3479 return 'Fragment'; | |
| 3480 | |
| 3481 case REACT_PORTAL_TYPE: | |
| 3482 return 'Portal'; | |
| 3483 | |
| 3484 case REACT_PROFILER_TYPE: | |
| 3485 return 'Profiler'; | |
| 3486 | |
| 3487 case REACT_STRICT_MODE_TYPE: | |
| 3488 return 'StrictMode'; | |
| 3489 | |
| 3490 case REACT_SUSPENSE_TYPE: | |
| 3491 return 'Suspense'; | |
| 3492 | |
| 3493 case REACT_SUSPENSE_LIST_TYPE: | |
| 3494 return 'SuspenseList'; | |
| 3495 | |
| 3496 } | |
| 3497 | |
| 3498 if (typeof type === 'object') { | |
| 3499 switch (type.$$typeof) { | |
| 3500 case REACT_CONTEXT_TYPE: | |
| 3501 var context = type; | |
| 3502 return getContextName(context) + '.Consumer'; | |
| 3503 | |
| 3504 case REACT_PROVIDER_TYPE: | |
| 3505 var provider = type; | |
| 3506 return getContextName(provider._context) + '.Provider'; | |
| 3507 | |
| 3508 case REACT_FORWARD_REF_TYPE: | |
| 3509 return getWrappedName(type, type.render, 'ForwardRef'); | |
| 3510 | |
| 3511 case REACT_MEMO_TYPE: | |
| 3512 var outerName = type.displayName || null; | |
| 3513 | |
| 3514 if (outerName !== null) { | |
| 3515 return outerName; | |
| 3516 } | |
| 3517 | |
| 3518 return getComponentNameFromType(type.type) || 'Memo'; | |
| 3519 | |
| 3520 case REACT_LAZY_TYPE: | |
| 3521 { | |
| 3522 var lazyComponent = type; | |
| 3523 var payload = lazyComponent._payload; | |
| 3524 var init = lazyComponent._init; | |
| 3525 | |
| 3526 try { | |
| 3527 return getComponentNameFromType(init(payload)); | |
| 3528 } catch (x) { | |
| 3529 return null; | |
| 3530 } | |
| 3531 } | |
| 3532 | |
| 3533 // eslint-disable-next-line no-fallthrough | |
| 3534 } | |
| 3535 } | |
| 3536 | |
| 3537 return null; | |
| 3538 } | |
| 3539 | |
| 3540 // Helpers to patch console.logs to avoid logging during side-effect free | |
| 3541 // replaying on render function. This currently only patches the object | |
| 3542 // lazily which won't cover if the log function was extracted eagerly. | |
| 3543 // We could also eagerly patch the method. | |
| 3544 var disabledDepth = 0; | |
| 3545 var prevLog; | |
| 3546 var prevInfo; | |
| 3547 var prevWarn; | |
| 3548 var prevError; | |
| 3549 var prevGroup; | |
| 3550 var prevGroupCollapsed; | |
| 3551 var prevGroupEnd; | |
| 3552 | |
| 3553 function disabledLog() {} | |
| 3554 | |
| 3555 disabledLog.__reactDisabledLog = true; | |
| 3556 function disableLogs() { | |
| 3557 { | |
| 3558 if (disabledDepth === 0) { | |
| 3559 /* eslint-disable react-internal/no-production-logging */ | |
| 3560 prevLog = console.log; | |
| 3561 prevInfo = console.info; | |
| 3562 prevWarn = console.warn; | |
| 3563 prevError = console.error; | |
| 3564 prevGroup = console.group; | |
| 3565 prevGroupCollapsed = console.groupCollapsed; | |
| 3566 prevGroupEnd = console.groupEnd; // https://github.com/facebook/react/issues/19099 | |
| 3567 | |
| 3568 var props = { | |
| 3569 configurable: true, | |
| 3570 enumerable: true, | |
| 3571 value: disabledLog, | |
| 3572 writable: true | |
| 3573 }; // $FlowFixMe Flow thinks console is immutable. | |
| 3574 | |
| 3575 Object.defineProperties(console, { | |
| 3576 info: props, | |
| 3577 log: props, | |
| 3578 warn: props, | |
| 3579 error: props, | |
| 3580 group: props, | |
| 3581 groupCollapsed: props, | |
| 3582 groupEnd: props | |
| 3583 }); | |
| 3584 /* eslint-enable react-internal/no-production-logging */ | |
| 3585 } | |
| 3586 | |
| 3587 disabledDepth++; | |
| 3588 } | |
| 3589 } | |
| 3590 function reenableLogs() { | |
| 3591 { | |
| 3592 disabledDepth--; | |
| 3593 | |
| 3594 if (disabledDepth === 0) { | |
| 3595 /* eslint-disable react-internal/no-production-logging */ | |
| 3596 var props = { | |
| 3597 configurable: true, | |
| 3598 enumerable: true, | |
| 3599 writable: true | |
| 3600 }; // $FlowFixMe Flow thinks console is immutable. | |
| 3601 | |
| 3602 Object.defineProperties(console, { | |
| 3603 log: assign({}, props, { | |
| 3604 value: prevLog | |
| 3605 }), | |
| 3606 info: assign({}, props, { | |
| 3607 value: prevInfo | |
| 3608 }), | |
| 3609 warn: assign({}, props, { | |
| 3610 value: prevWarn | |
| 3611 }), | |
| 3612 error: assign({}, props, { | |
| 3613 value: prevError | |
| 3614 }), | |
| 3615 group: assign({}, props, { | |
| 3616 value: prevGroup | |
| 3617 }), | |
| 3618 groupCollapsed: assign({}, props, { | |
| 3619 value: prevGroupCollapsed | |
| 3620 }), | |
| 3621 groupEnd: assign({}, props, { | |
| 3622 value: prevGroupEnd | |
| 3623 }) | |
| 3624 }); | |
| 3625 /* eslint-enable react-internal/no-production-logging */ | |
| 3626 } | |
| 3627 | |
| 3628 if (disabledDepth < 0) { | |
| 3629 error('disabledDepth fell below zero. ' + 'This is a bug in React. Please file an issue.'); | |
| 3630 } | |
| 3631 } | |
| 3632 } | |
| 3633 | |
| 3634 var ReactCurrentDispatcher = ReactSharedInternals.ReactCurrentDispatcher; | |
| 3635 var prefix; | |
| 3636 function describeBuiltInComponentFrame(name, source, ownerFn) { | |
| 3637 { | |
| 3638 if (prefix === undefined) { | |
| 3639 // Extract the VM specific prefix used by each line. | |
| 3640 try { | |
| 3641 throw Error(); | |
| 3642 } catch (x) { | |
| 3643 var match = x.stack.trim().match(/\n( *(at )?)/); | |
| 3644 prefix = match && match[1] || ''; | |
| 3645 } | |
| 3646 } // We use the prefix to ensure our stacks line up with native stack frames. | |
| 3647 | |
| 3648 | |
| 3649 return '\n' + prefix + name; | |
| 3650 } | |
| 3651 } | |
| 3652 var reentry = false; | |
| 3653 var componentFrameCache; | |
| 3654 | |
| 3655 { | |
| 3656 var PossiblyWeakMap = typeof WeakMap === 'function' ? WeakMap : Map; | |
| 3657 componentFrameCache = new PossiblyWeakMap(); | |
| 3658 } | |
| 3659 | |
| 3660 function describeNativeComponentFrame(fn, construct) { | |
| 3661 // If something asked for a stack inside a fake render, it should get ignored. | |
| 3662 if ( !fn || reentry) { | |
| 3663 return ''; | |
| 3664 } | |
| 3665 | |
| 3666 { | |
| 3667 var frame = componentFrameCache.get(fn); | |
| 3668 | |
| 3669 if (frame !== undefined) { | |
| 3670 return frame; | |
| 3671 } | |
| 3672 } | |
| 3673 | |
| 3674 var control; | |
| 3675 reentry = true; | |
| 3676 var previousPrepareStackTrace = Error.prepareStackTrace; // $FlowFixMe It does accept undefined. | |
| 3677 | |
| 3678 Error.prepareStackTrace = undefined; | |
| 3679 var previousDispatcher; | |
| 3680 | |
| 3681 { | |
| 3682 previousDispatcher = ReactCurrentDispatcher.current; // Set the dispatcher in DEV because this might be call in the render function | |
| 3683 // for warnings. | |
| 3684 | |
| 3685 ReactCurrentDispatcher.current = null; | |
| 3686 disableLogs(); | |
| 3687 } | |
| 3688 | |
| 3689 try { | |
| 3690 // This should throw. | |
| 3691 if (construct) { | |
| 3692 // Something should be setting the props in the constructor. | |
| 3693 var Fake = function () { | |
| 3694 throw Error(); | |
| 3695 }; // $FlowFixMe | |
| 3696 | |
| 3697 | |
| 3698 Object.defineProperty(Fake.prototype, 'props', { | |
| 3699 set: function () { | |
| 3700 // We use a throwing setter instead of frozen or non-writable props | |
| 3701 // because that won't throw in a non-strict mode function. | |
| 3702 throw Error(); | |
| 3703 } | |
| 3704 }); | |
| 3705 | |
| 3706 if (typeof Reflect === 'object' && Reflect.construct) { | |
| 3707 // We construct a different control for this case to include any extra | |
| 3708 // frames added by the construct call. | |
| 3709 try { | |
| 3710 Reflect.construct(Fake, []); | |
| 3711 } catch (x) { | |
| 3712 control = x; | |
| 3713 } | |
| 3714 | |
| 3715 Reflect.construct(fn, [], Fake); | |
| 3716 } else { | |
| 3717 try { | |
| 3718 Fake.call(); | |
| 3719 } catch (x) { | |
| 3720 control = x; | |
| 3721 } | |
| 3722 | |
| 3723 fn.call(Fake.prototype); | |
| 3724 } | |
| 3725 } else { | |
| 3726 try { | |
| 3727 throw Error(); | |
| 3728 } catch (x) { | |
| 3729 control = x; | |
| 3730 } | |
| 3731 | |
| 3732 fn(); | |
| 3733 } | |
| 3734 } catch (sample) { | |
| 3735 // This is inlined manually because closure doesn't do it for us. | |
| 3736 if (sample && control && typeof sample.stack === 'string') { | |
| 3737 // This extracts the first frame from the sample that isn't also in the control. | |
| 3738 // Skipping one frame that we assume is the frame that calls the two. | |
| 3739 var sampleLines = sample.stack.split('\n'); | |
| 3740 var controlLines = control.stack.split('\n'); | |
| 3741 var s = sampleLines.length - 1; | |
| 3742 var c = controlLines.length - 1; | |
| 3743 | |
| 3744 while (s >= 1 && c >= 0 && sampleLines[s] !== controlLines[c]) { | |
| 3745 // We expect at least one stack frame to be shared. | |
| 3746 // Typically this will be the root most one. However, stack frames may be | |
| 3747 // cut off due to maximum stack limits. In this case, one maybe cut off | |
| 3748 // earlier than the other. We assume that the sample is longer or the same | |
| 3749 // and there for cut off earlier. So we should find the root most frame in | |
| 3750 // the sample somewhere in the control. | |
| 3751 c--; | |
| 3752 } | |
| 3753 | |
| 3754 for (; s >= 1 && c >= 0; s--, c--) { | |
| 3755 // Next we find the first one that isn't the same which should be the | |
| 3756 // frame that called our sample function and the control. | |
| 3757 if (sampleLines[s] !== controlLines[c]) { | |
| 3758 // In V8, the first line is describing the message but other VMs don't. | |
| 3759 // If we're about to return the first line, and the control is also on the same | |
| 3760 // line, that's a pretty good indicator that our sample threw at same line as | |
| 3761 // the control. I.e. before we entered the sample frame. So we ignore this result. | |
| 3762 // This can happen if you passed a class to function component, or non-function. | |
| 3763 if (s !== 1 || c !== 1) { | |
| 3764 do { | |
| 3765 s--; | |
| 3766 c--; // We may still have similar intermediate frames from the construct call. | |
| 3767 // The next one that isn't the same should be our match though. | |
| 3768 | |
| 3769 if (c < 0 || sampleLines[s] !== controlLines[c]) { | |
| 3770 // V8 adds a "new" prefix for native classes. Let's remove it to make it prettier. | |
| 3771 var _frame = '\n' + sampleLines[s].replace(' at new ', ' at '); // If our component frame is labeled "<anonymous>" | |
| 3772 // but we have a user-provided "displayName" | |
| 3773 // splice it in to make the stack more readable. | |
| 3774 | |
| 3775 | |
| 3776 if (fn.displayName && _frame.includes('<anonymous>')) { | |
| 3777 _frame = _frame.replace('<anonymous>', fn.displayName); | |
| 3778 } | |
| 3779 | |
| 3780 { | |
| 3781 if (typeof fn === 'function') { | |
| 3782 componentFrameCache.set(fn, _frame); | |
| 3783 } | |
| 3784 } // Return the line we found. | |
| 3785 | |
| 3786 | |
| 3787 return _frame; | |
| 3788 } | |
| 3789 } while (s >= 1 && c >= 0); | |
| 3790 } | |
| 3791 | |
| 3792 break; | |
| 3793 } | |
| 3794 } | |
| 3795 } | |
| 3796 } finally { | |
| 3797 reentry = false; | |
| 3798 | |
| 3799 { | |
| 3800 ReactCurrentDispatcher.current = previousDispatcher; | |
| 3801 reenableLogs(); | |
| 3802 } | |
| 3803 | |
| 3804 Error.prepareStackTrace = previousPrepareStackTrace; | |
| 3805 } // Fallback to just using the name if we couldn't make it throw. | |
| 3806 | |
| 3807 | |
| 3808 var name = fn ? fn.displayName || fn.name : ''; | |
| 3809 var syntheticFrame = name ? describeBuiltInComponentFrame(name) : ''; | |
| 3810 | |
| 3811 { | |
| 3812 if (typeof fn === 'function') { | |
| 3813 componentFrameCache.set(fn, syntheticFrame); | |
| 3814 } | |
| 3815 } | |
| 3816 | |
| 3817 return syntheticFrame; | |
| 3818 } | |
| 3819 | |
| 3820 function describeClassComponentFrame(ctor, source, ownerFn) { | |
| 3821 { | |
| 3822 return describeNativeComponentFrame(ctor, true); | |
| 3823 } | |
| 3824 } | |
| 3825 function describeFunctionComponentFrame(fn, source, ownerFn) { | |
| 3826 { | |
| 3827 return describeNativeComponentFrame(fn, false); | |
| 3828 } | |
| 3829 } | |
| 3830 | |
| 3831 function shouldConstruct(Component) { | |
| 3832 var prototype = Component.prototype; | |
| 3833 return !!(prototype && prototype.isReactComponent); | |
| 3834 } | |
| 3835 | |
| 3836 function describeUnknownElementTypeFrameInDEV(type, source, ownerFn) { | |
| 3837 | |
| 3838 if (type == null) { | |
| 3839 return ''; | |
| 3840 } | |
| 3841 | |
| 3842 if (typeof type === 'function') { | |
| 3843 { | |
| 3844 return describeNativeComponentFrame(type, shouldConstruct(type)); | |
| 3845 } | |
| 3846 } | |
| 3847 | |
| 3848 if (typeof type === 'string') { | |
| 3849 return describeBuiltInComponentFrame(type); | |
| 3850 } | |
| 3851 | |
| 3852 switch (type) { | |
| 3853 case REACT_SUSPENSE_TYPE: | |
| 3854 return describeBuiltInComponentFrame('Suspense'); | |
| 3855 | |
| 3856 case REACT_SUSPENSE_LIST_TYPE: | |
| 3857 return describeBuiltInComponentFrame('SuspenseList'); | |
| 3858 } | |
| 3859 | |
| 3860 if (typeof type === 'object') { | |
| 3861 switch (type.$$typeof) { | |
| 3862 case REACT_FORWARD_REF_TYPE: | |
| 3863 return describeFunctionComponentFrame(type.render); | |
| 3864 | |
| 3865 case REACT_MEMO_TYPE: | |
| 3866 // Memo may contain any component type so we recursively resolve it. | |
| 3867 return describeUnknownElementTypeFrameInDEV(type.type, source, ownerFn); | |
| 3868 | |
| 3869 case REACT_LAZY_TYPE: | |
| 3870 { | |
| 3871 var lazyComponent = type; | |
| 3872 var payload = lazyComponent._payload; | |
| 3873 var init = lazyComponent._init; | |
| 3874 | |
| 3875 try { | |
| 3876 // Lazy may contain any component type so we recursively resolve it. | |
| 3877 return describeUnknownElementTypeFrameInDEV(init(payload), source, ownerFn); | |
| 3878 } catch (x) {} | |
| 3879 } | |
| 3880 } | |
| 3881 } | |
| 3882 | |
| 3883 return ''; | |
| 3884 } | |
| 3885 | |
| 3886 var loggedTypeFailures = {}; | |
| 3887 var ReactDebugCurrentFrame = ReactSharedInternals.ReactDebugCurrentFrame; | |
| 3888 | |
| 3889 function setCurrentlyValidatingElement(element) { | |
| 3890 { | |
| 3891 if (element) { | |
| 3892 var owner = element._owner; | |
| 3893 var stack = describeUnknownElementTypeFrameInDEV(element.type, element._source, owner ? owner.type : null); | |
| 3894 ReactDebugCurrentFrame.setExtraStackFrame(stack); | |
| 3895 } else { | |
| 3896 ReactDebugCurrentFrame.setExtraStackFrame(null); | |
| 3897 } | |
| 3898 } | |
| 3899 } | |
| 3900 | |
| 3901 function checkPropTypes(typeSpecs, values, location, componentName, element) { | |
| 3902 { | |
| 3903 // $FlowFixMe This is okay but Flow doesn't know it. | |
| 3904 var has = Function.call.bind(hasOwnProperty); | |
| 3905 | |
| 3906 for (var typeSpecName in typeSpecs) { | |
| 3907 if (has(typeSpecs, typeSpecName)) { | |
| 3908 var error$1 = void 0; // Prop type validation may throw. In case they do, we don't want to | |
| 3909 // fail the render phase where it didn't fail before. So we log it. | |
| 3910 // After these have been cleaned up, we'll let them throw. | |
| 3911 | |
| 3912 try { | |
| 3913 // This is intentionally an invariant that gets caught. It's the same | |
| 3914 // behavior as without this statement except with a better message. | |
| 3915 if (typeof typeSpecs[typeSpecName] !== 'function') { | |
| 3916 // eslint-disable-next-line react-internal/prod-error-codes | |
| 3917 var err = Error((componentName || 'React class') + ': ' + location + ' type `' + typeSpecName + '` is invalid; ' + 'it must be a function, usually from the `prop-types` package, but received `' + typeof typeSpecs[typeSpecName] + '`.' + 'This often happens because of typos such as `PropTypes.function` instead of `PropTypes.func`.'); | |
| 3918 err.name = 'Invariant Violation'; | |
| 3919 throw err; | |
| 3920 } | |
| 3921 | |
| 3922 error$1 = typeSpecs[typeSpecName](values, typeSpecName, componentName, location, null, 'SECRET_DO_NOT_PASS_THIS_OR_YOU_WILL_BE_FIRED'); | |
| 3923 } catch (ex) { | |
| 3924 error$1 = ex; | |
| 3925 } | |
| 3926 | |
| 3927 if (error$1 && !(error$1 instanceof Error)) { | |
| 3928 setCurrentlyValidatingElement(element); | |
| 3929 | |
| 3930 error('%s: type specification of %s' + ' `%s` is invalid; the type checker ' + 'function must return `null` or an `Error` but returned a %s. ' + 'You may have forgotten to pass an argument to the type checker ' + 'creator (arrayOf, instanceOf, objectOf, oneOf, oneOfType, and ' + 'shape all require an argument).', componentName || 'React class', location, typeSpecName, typeof error$1); | |
| 3931 | |
| 3932 setCurrentlyValidatingElement(null); | |
| 3933 } | |
| 3934 | |
| 3935 if (error$1 instanceof Error && !(error$1.message in loggedTypeFailures)) { | |
| 3936 // Only monitor this failure once because there tends to be a lot of the | |
| 3937 // same error. | |
| 3938 loggedTypeFailures[error$1.message] = true; | |
| 3939 setCurrentlyValidatingElement(element); | |
| 3940 | |
| 3941 error('Failed %s type: %s', location, error$1.message); | |
| 3942 | |
| 3943 setCurrentlyValidatingElement(null); | |
| 3944 } | |
| 3945 } | |
| 3946 } | |
| 3947 } | |
| 3948 } | |
| 3949 | |
| 3950 var warnedAboutMissingGetChildContext; | |
| 3951 | |
| 3952 { | |
| 3953 warnedAboutMissingGetChildContext = {}; | |
| 3954 } | |
| 3955 | |
| 3956 var emptyContextObject = {}; | |
| 3957 | |
| 3958 { | |
| 3959 Object.freeze(emptyContextObject); | |
| 3960 } | |
| 3961 | |
| 3962 function getMaskedContext(type, unmaskedContext) { | |
| 3963 { | |
| 3964 var contextTypes = type.contextTypes; | |
| 3965 | |
| 3966 if (!contextTypes) { | |
| 3967 return emptyContextObject; | |
| 3968 } | |
| 3969 | |
| 3970 var context = {}; | |
| 3971 | |
| 3972 for (var key in contextTypes) { | |
| 3973 context[key] = unmaskedContext[key]; | |
| 3974 } | |
| 3975 | |
| 3976 { | |
| 3977 var name = getComponentNameFromType(type) || 'Unknown'; | |
| 3978 checkPropTypes(contextTypes, context, 'context', name); | |
| 3979 } | |
| 3980 | |
| 3981 return context; | |
| 3982 } | |
| 3983 } | |
| 3984 function processChildContext(instance, type, parentContext, childContextTypes) { | |
| 3985 { | |
| 3986 // TODO (bvaughn) Replace this behavior with an invariant() in the future. | |
| 3987 // It has only been added in Fiber to match the (unintentional) behavior in Stack. | |
| 3988 if (typeof instance.getChildContext !== 'function') { | |
| 3989 { | |
| 3990 var componentName = getComponentNameFromType(type) || 'Unknown'; | |
| 3991 | |
| 3992 if (!warnedAboutMissingGetChildContext[componentName]) { | |
| 3993 warnedAboutMissingGetChildContext[componentName] = true; | |
| 3994 | |
| 3995 error('%s.childContextTypes is specified but there is no getChildContext() method ' + 'on the instance. You can either define getChildContext() on %s or remove ' + 'childContextTypes from it.', componentName, componentName); | |
| 3996 } | |
| 3997 } | |
| 3998 | |
| 3999 return parentContext; | |
| 4000 } | |
| 4001 | |
| 4002 var childContext = instance.getChildContext(); | |
| 4003 | |
| 4004 for (var contextKey in childContext) { | |
| 4005 if (!(contextKey in childContextTypes)) { | |
| 4006 throw new Error((getComponentNameFromType(type) || 'Unknown') + ".getChildContext(): key \"" + contextKey + "\" is not defined in childContextTypes."); | |
| 4007 } | |
| 4008 } | |
| 4009 | |
| 4010 { | |
| 4011 var name = getComponentNameFromType(type) || 'Unknown'; | |
| 4012 checkPropTypes(childContextTypes, childContext, 'child context', name); | |
| 4013 } | |
| 4014 | |
| 4015 return assign({}, parentContext, childContext); | |
| 4016 } | |
| 4017 } | |
| 4018 | |
| 4019 var rendererSigil; | |
| 4020 | |
| 4021 { | |
| 4022 // Use this to detect multiple renderers using the same context | |
| 4023 rendererSigil = {}; | |
| 4024 } // Used to store the parent path of all context overrides in a shared linked list. | |
| 4025 // Forming a reverse tree. | |
| 4026 | |
| 4027 | |
| 4028 var rootContextSnapshot = null; // We assume that this runtime owns the "current" field on all ReactContext instances. | |
| 4029 // This global (actually thread local) state represents what state all those "current", | |
| 4030 // fields are currently in. | |
| 4031 | |
| 4032 var currentActiveSnapshot = null; | |
| 4033 | |
| 4034 function popNode(prev) { | |
| 4035 { | |
| 4036 prev.context._currentValue2 = prev.parentValue; | |
| 4037 } | |
| 4038 } | |
| 4039 | |
| 4040 function pushNode(next) { | |
| 4041 { | |
| 4042 next.context._currentValue2 = next.value; | |
| 4043 } | |
| 4044 } | |
| 4045 | |
| 4046 function popToNearestCommonAncestor(prev, next) { | |
| 4047 if (prev === next) ; else { | |
| 4048 popNode(prev); | |
| 4049 var parentPrev = prev.parent; | |
| 4050 var parentNext = next.parent; | |
| 4051 | |
| 4052 if (parentPrev === null) { | |
| 4053 if (parentNext !== null) { | |
| 4054 throw new Error('The stacks must reach the root at the same time. This is a bug in React.'); | |
| 4055 } | |
| 4056 } else { | |
| 4057 if (parentNext === null) { | |
| 4058 throw new Error('The stacks must reach the root at the same time. This is a bug in React.'); | |
| 4059 } | |
| 4060 | |
| 4061 popToNearestCommonAncestor(parentPrev, parentNext); | |
| 4062 } // On the way back, we push the new ones that weren't common. | |
| 4063 | |
| 4064 | |
| 4065 pushNode(next); | |
| 4066 } | |
| 4067 } | |
| 4068 | |
| 4069 function popAllPrevious(prev) { | |
| 4070 popNode(prev); | |
| 4071 var parentPrev = prev.parent; | |
| 4072 | |
| 4073 if (parentPrev !== null) { | |
| 4074 popAllPrevious(parentPrev); | |
| 4075 } | |
| 4076 } | |
| 4077 | |
| 4078 function pushAllNext(next) { | |
| 4079 var parentNext = next.parent; | |
| 4080 | |
| 4081 if (parentNext !== null) { | |
| 4082 pushAllNext(parentNext); | |
| 4083 } | |
| 4084 | |
| 4085 pushNode(next); | |
| 4086 } | |
| 4087 | |
| 4088 function popPreviousToCommonLevel(prev, next) { | |
| 4089 popNode(prev); | |
| 4090 var parentPrev = prev.parent; | |
| 4091 | |
| 4092 if (parentPrev === null) { | |
| 4093 throw new Error('The depth must equal at least at zero before reaching the root. This is a bug in React.'); | |
| 4094 } | |
| 4095 | |
| 4096 if (parentPrev.depth === next.depth) { | |
| 4097 // We found the same level. Now we just need to find a shared ancestor. | |
| 4098 popToNearestCommonAncestor(parentPrev, next); | |
| 4099 } else { | |
| 4100 // We must still be deeper. | |
| 4101 popPreviousToCommonLevel(parentPrev, next); | |
| 4102 } | |
| 4103 } | |
| 4104 | |
| 4105 function popNextToCommonLevel(prev, next) { | |
| 4106 var parentNext = next.parent; | |
| 4107 | |
| 4108 if (parentNext === null) { | |
| 4109 throw new Error('The depth must equal at least at zero before reaching the root. This is a bug in React.'); | |
| 4110 } | |
| 4111 | |
| 4112 if (prev.depth === parentNext.depth) { | |
| 4113 // We found the same level. Now we just need to find a shared ancestor. | |
| 4114 popToNearestCommonAncestor(prev, parentNext); | |
| 4115 } else { | |
| 4116 // We must still be deeper. | |
| 4117 popNextToCommonLevel(prev, parentNext); | |
| 4118 } | |
| 4119 | |
| 4120 pushNode(next); | |
| 4121 } // Perform context switching to the new snapshot. | |
| 4122 // To make it cheap to read many contexts, while not suspending, we make the switch eagerly by | |
| 4123 // updating all the context's current values. That way reads, always just read the current value. | |
| 4124 // At the cost of updating contexts even if they're never read by this subtree. | |
| 4125 | |
| 4126 | |
| 4127 function switchContext(newSnapshot) { | |
| 4128 // The basic algorithm we need to do is to pop back any contexts that are no longer on the stack. | |
| 4129 // We also need to update any new contexts that are now on the stack with the deepest value. | |
| 4130 // The easiest way to update new contexts is to just reapply them in reverse order from the | |
| 4131 // perspective of the backpointers. To avoid allocating a lot when switching, we use the stack | |
| 4132 // for that. Therefore this algorithm is recursive. | |
| 4133 // 1) First we pop which ever snapshot tree was deepest. Popping old contexts as we go. | |
| 4134 // 2) Then we find the nearest common ancestor from there. Popping old contexts as we go. | |
| 4135 // 3) Then we reapply new contexts on the way back up the stack. | |
| 4136 var prev = currentActiveSnapshot; | |
| 4137 var next = newSnapshot; | |
| 4138 | |
| 4139 if (prev !== next) { | |
| 4140 if (prev === null) { | |
| 4141 // $FlowFixMe: This has to be non-null since it's not equal to prev. | |
| 4142 pushAllNext(next); | |
| 4143 } else if (next === null) { | |
| 4144 popAllPrevious(prev); | |
| 4145 } else if (prev.depth === next.depth) { | |
| 4146 popToNearestCommonAncestor(prev, next); | |
| 4147 } else if (prev.depth > next.depth) { | |
| 4148 popPreviousToCommonLevel(prev, next); | |
| 4149 } else { | |
| 4150 popNextToCommonLevel(prev, next); | |
| 4151 } | |
| 4152 | |
| 4153 currentActiveSnapshot = next; | |
| 4154 } | |
| 4155 } | |
| 4156 function pushProvider(context, nextValue) { | |
| 4157 var prevValue; | |
| 4158 | |
| 4159 { | |
| 4160 prevValue = context._currentValue2; | |
| 4161 context._currentValue2 = nextValue; | |
| 4162 | |
| 4163 { | |
| 4164 if (context._currentRenderer2 !== undefined && context._currentRenderer2 !== null && context._currentRenderer2 !== rendererSigil) { | |
| 4165 error('Detected multiple renderers concurrently rendering the ' + 'same context provider. This is currently unsupported.'); | |
| 4166 } | |
| 4167 | |
| 4168 context._currentRenderer2 = rendererSigil; | |
| 4169 } | |
| 4170 } | |
| 4171 | |
| 4172 var prevNode = currentActiveSnapshot; | |
| 4173 var newNode = { | |
| 4174 parent: prevNode, | |
| 4175 depth: prevNode === null ? 0 : prevNode.depth + 1, | |
| 4176 context: context, | |
| 4177 parentValue: prevValue, | |
| 4178 value: nextValue | |
| 4179 }; | |
| 4180 currentActiveSnapshot = newNode; | |
| 4181 return newNode; | |
| 4182 } | |
| 4183 function popProvider(context) { | |
| 4184 var prevSnapshot = currentActiveSnapshot; | |
| 4185 | |
| 4186 if (prevSnapshot === null) { | |
| 4187 throw new Error('Tried to pop a Context at the root of the app. This is a bug in React.'); | |
| 4188 } | |
| 4189 | |
| 4190 { | |
| 4191 if (prevSnapshot.context !== context) { | |
| 4192 error('The parent context is not the expected context. This is probably a bug in React.'); | |
| 4193 } | |
| 4194 } | |
| 4195 | |
| 4196 { | |
| 4197 var _value = prevSnapshot.parentValue; | |
| 4198 | |
| 4199 if (_value === REACT_SERVER_CONTEXT_DEFAULT_VALUE_NOT_LOADED) { | |
| 4200 prevSnapshot.context._currentValue2 = prevSnapshot.context._defaultValue; | |
| 4201 } else { | |
| 4202 prevSnapshot.context._currentValue2 = _value; | |
| 4203 } | |
| 4204 | |
| 4205 { | |
| 4206 if (context._currentRenderer2 !== undefined && context._currentRenderer2 !== null && context._currentRenderer2 !== rendererSigil) { | |
| 4207 error('Detected multiple renderers concurrently rendering the ' + 'same context provider. This is currently unsupported.'); | |
| 4208 } | |
| 4209 | |
| 4210 context._currentRenderer2 = rendererSigil; | |
| 4211 } | |
| 4212 } | |
| 4213 | |
| 4214 return currentActiveSnapshot = prevSnapshot.parent; | |
| 4215 } | |
| 4216 function getActiveContext() { | |
| 4217 return currentActiveSnapshot; | |
| 4218 } | |
| 4219 function readContext(context) { | |
| 4220 var value = context._currentValue2; | |
| 4221 return value; | |
| 4222 } | |
| 4223 | |
| 4224 /** | |
| 4225 * `ReactInstanceMap` maintains a mapping from a public facing stateful | |
| 4226 * instance (key) and the internal representation (value). This allows public | |
| 4227 * methods to accept the user facing instance as an argument and map them back | |
| 4228 * to internal methods. | |
| 4229 * | |
| 4230 * Note that this module is currently shared and assumed to be stateless. | |
| 4231 * If this becomes an actual Map, that will break. | |
| 4232 */ | |
| 4233 function get(key) { | |
| 4234 return key._reactInternals; | |
| 4235 } | |
| 4236 function set(key, value) { | |
| 4237 key._reactInternals = value; | |
| 4238 } | |
| 4239 | |
| 4240 var didWarnAboutNoopUpdateForComponent = {}; | |
| 4241 var didWarnAboutDeprecatedWillMount = {}; | |
| 4242 var didWarnAboutUninitializedState; | |
| 4243 var didWarnAboutGetSnapshotBeforeUpdateWithoutDidUpdate; | |
| 4244 var didWarnAboutLegacyLifecyclesAndDerivedState; | |
| 4245 var didWarnAboutUndefinedDerivedState; | |
| 4246 var warnOnUndefinedDerivedState; | |
| 4247 var warnOnInvalidCallback; | |
| 4248 var didWarnAboutDirectlyAssigningPropsToState; | |
| 4249 var didWarnAboutContextTypeAndContextTypes; | |
| 4250 var didWarnAboutInvalidateContextType; | |
| 4251 | |
| 4252 { | |
| 4253 didWarnAboutUninitializedState = new Set(); | |
| 4254 didWarnAboutGetSnapshotBeforeUpdateWithoutDidUpdate = new Set(); | |
| 4255 didWarnAboutLegacyLifecyclesAndDerivedState = new Set(); | |
| 4256 didWarnAboutDirectlyAssigningPropsToState = new Set(); | |
| 4257 didWarnAboutUndefinedDerivedState = new Set(); | |
| 4258 didWarnAboutContextTypeAndContextTypes = new Set(); | |
| 4259 didWarnAboutInvalidateContextType = new Set(); | |
| 4260 var didWarnOnInvalidCallback = new Set(); | |
| 4261 | |
| 4262 warnOnInvalidCallback = function (callback, callerName) { | |
| 4263 if (callback === null || typeof callback === 'function') { | |
| 4264 return; | |
| 4265 } | |
| 4266 | |
| 4267 var key = callerName + '_' + callback; | |
| 4268 | |
| 4269 if (!didWarnOnInvalidCallback.has(key)) { | |
| 4270 didWarnOnInvalidCallback.add(key); | |
| 4271 | |
| 4272 error('%s(...): Expected the last optional `callback` argument to be a ' + 'function. Instead received: %s.', callerName, callback); | |
| 4273 } | |
| 4274 }; | |
| 4275 | |
| 4276 warnOnUndefinedDerivedState = function (type, partialState) { | |
| 4277 if (partialState === undefined) { | |
| 4278 var componentName = getComponentNameFromType(type) || 'Component'; | |
| 4279 | |
| 4280 if (!didWarnAboutUndefinedDerivedState.has(componentName)) { | |
| 4281 didWarnAboutUndefinedDerivedState.add(componentName); | |
| 4282 | |
| 4283 error('%s.getDerivedStateFromProps(): A valid state object (or null) must be returned. ' + 'You have returned undefined.', componentName); | |
| 4284 } | |
| 4285 } | |
| 4286 }; | |
| 4287 } | |
| 4288 | |
| 4289 function warnNoop(publicInstance, callerName) { | |
| 4290 { | |
| 4291 var _constructor = publicInstance.constructor; | |
| 4292 var componentName = _constructor && getComponentNameFromType(_constructor) || 'ReactClass'; | |
| 4293 var warningKey = componentName + '.' + callerName; | |
| 4294 | |
| 4295 if (didWarnAboutNoopUpdateForComponent[warningKey]) { | |
| 4296 return; | |
| 4297 } | |
| 4298 | |
| 4299 error('%s(...): Can only update a mounting component. ' + 'This usually means you called %s() outside componentWillMount() on the server. ' + 'This is a no-op.\n\nPlease check the code for the %s component.', callerName, callerName, componentName); | |
| 4300 | |
| 4301 didWarnAboutNoopUpdateForComponent[warningKey] = true; | |
| 4302 } | |
| 4303 } | |
| 4304 | |
| 4305 var classComponentUpdater = { | |
| 4306 isMounted: function (inst) { | |
| 4307 return false; | |
| 4308 }, | |
| 4309 enqueueSetState: function (inst, payload, callback) { | |
| 4310 var internals = get(inst); | |
| 4311 | |
| 4312 if (internals.queue === null) { | |
| 4313 warnNoop(inst, 'setState'); | |
| 4314 } else { | |
| 4315 internals.queue.push(payload); | |
| 4316 | |
| 4317 { | |
| 4318 if (callback !== undefined && callback !== null) { | |
| 4319 warnOnInvalidCallback(callback, 'setState'); | |
| 4320 } | |
| 4321 } | |
| 4322 } | |
| 4323 }, | |
| 4324 enqueueReplaceState: function (inst, payload, callback) { | |
| 4325 var internals = get(inst); | |
| 4326 internals.replace = true; | |
| 4327 internals.queue = [payload]; | |
| 4328 | |
| 4329 { | |
| 4330 if (callback !== undefined && callback !== null) { | |
| 4331 warnOnInvalidCallback(callback, 'setState'); | |
| 4332 } | |
| 4333 } | |
| 4334 }, | |
| 4335 enqueueForceUpdate: function (inst, callback) { | |
| 4336 var internals = get(inst); | |
| 4337 | |
| 4338 if (internals.queue === null) { | |
| 4339 warnNoop(inst, 'forceUpdate'); | |
| 4340 } else { | |
| 4341 { | |
| 4342 if (callback !== undefined && callback !== null) { | |
| 4343 warnOnInvalidCallback(callback, 'setState'); | |
| 4344 } | |
| 4345 } | |
| 4346 } | |
| 4347 } | |
| 4348 }; | |
| 4349 | |
| 4350 function applyDerivedStateFromProps(instance, ctor, getDerivedStateFromProps, prevState, nextProps) { | |
| 4351 var partialState = getDerivedStateFromProps(nextProps, prevState); | |
| 4352 | |
| 4353 { | |
| 4354 warnOnUndefinedDerivedState(ctor, partialState); | |
| 4355 } // Merge the partial state and the previous state. | |
| 4356 | |
| 4357 | |
| 4358 var newState = partialState === null || partialState === undefined ? prevState : assign({}, prevState, partialState); | |
| 4359 return newState; | |
| 4360 } | |
| 4361 | |
| 4362 function constructClassInstance(ctor, props, maskedLegacyContext) { | |
| 4363 var context = emptyContextObject; | |
| 4364 var contextType = ctor.contextType; | |
| 4365 | |
| 4366 { | |
| 4367 if ('contextType' in ctor) { | |
| 4368 var isValid = // Allow null for conditional declaration | |
| 4369 contextType === null || contextType !== undefined && contextType.$$typeof === REACT_CONTEXT_TYPE && contextType._context === undefined; // Not a <Context.Consumer> | |
| 4370 | |
| 4371 if (!isValid && !didWarnAboutInvalidateContextType.has(ctor)) { | |
| 4372 didWarnAboutInvalidateContextType.add(ctor); | |
| 4373 var addendum = ''; | |
| 4374 | |
| 4375 if (contextType === undefined) { | |
| 4376 addendum = ' However, it is set to undefined. ' + 'This can be caused by a typo or by mixing up named and default imports. ' + 'This can also happen due to a circular dependency, so ' + 'try moving the createContext() call to a separate file.'; | |
| 4377 } else if (typeof contextType !== 'object') { | |
| 4378 addendum = ' However, it is set to a ' + typeof contextType + '.'; | |
| 4379 } else if (contextType.$$typeof === REACT_PROVIDER_TYPE) { | |
| 4380 addendum = ' Did you accidentally pass the Context.Provider instead?'; | |
| 4381 } else if (contextType._context !== undefined) { | |
| 4382 // <Context.Consumer> | |
| 4383 addendum = ' Did you accidentally pass the Context.Consumer instead?'; | |
| 4384 } else { | |
| 4385 addendum = ' However, it is set to an object with keys {' + Object.keys(contextType).join(', ') + '}.'; | |
| 4386 } | |
| 4387 | |
| 4388 error('%s defines an invalid contextType. ' + 'contextType should point to the Context object returned by React.createContext().%s', getComponentNameFromType(ctor) || 'Component', addendum); | |
| 4389 } | |
| 4390 } | |
| 4391 } | |
| 4392 | |
| 4393 if (typeof contextType === 'object' && contextType !== null) { | |
| 4394 context = readContext(contextType); | |
| 4395 } else { | |
| 4396 context = maskedLegacyContext; | |
| 4397 } | |
| 4398 | |
| 4399 var instance = new ctor(props, context); | |
| 4400 | |
| 4401 { | |
| 4402 if (typeof ctor.getDerivedStateFromProps === 'function' && (instance.state === null || instance.state === undefined)) { | |
| 4403 var componentName = getComponentNameFromType(ctor) || 'Component'; | |
| 4404 | |
| 4405 if (!didWarnAboutUninitializedState.has(componentName)) { | |
| 4406 didWarnAboutUninitializedState.add(componentName); | |
| 4407 | |
| 4408 error('`%s` uses `getDerivedStateFromProps` but its initial state is ' + '%s. This is not recommended. Instead, define the initial state by ' + 'assigning an object to `this.state` in the constructor of `%s`. ' + 'This ensures that `getDerivedStateFromProps` arguments have a consistent shape.', componentName, instance.state === null ? 'null' : 'undefined', componentName); | |
| 4409 } | |
| 4410 } // If new component APIs are defined, "unsafe" lifecycles won't be called. | |
| 4411 // Warn about these lifecycles if they are present. | |
| 4412 // Don't warn about react-lifecycles-compat polyfilled methods though. | |
| 4413 | |
| 4414 | |
| 4415 if (typeof ctor.getDerivedStateFromProps === 'function' || typeof instance.getSnapshotBeforeUpdate === 'function') { | |
| 4416 var foundWillMountName = null; | |
| 4417 var foundWillReceivePropsName = null; | |
| 4418 var foundWillUpdateName = null; | |
| 4419 | |
| 4420 if (typeof instance.componentWillMount === 'function' && instance.componentWillMount.__suppressDeprecationWarning !== true) { | |
| 4421 foundWillMountName = 'componentWillMount'; | |
| 4422 } else if (typeof instance.UNSAFE_componentWillMount === 'function') { | |
| 4423 foundWillMountName = 'UNSAFE_componentWillMount'; | |
| 4424 } | |
| 4425 | |
| 4426 if (typeof instance.componentWillReceiveProps === 'function' && instance.componentWillReceiveProps.__suppressDeprecationWarning !== true) { | |
| 4427 foundWillReceivePropsName = 'componentWillReceiveProps'; | |
| 4428 } else if (typeof instance.UNSAFE_componentWillReceiveProps === 'function') { | |
| 4429 foundWillReceivePropsName = 'UNSAFE_componentWillReceiveProps'; | |
| 4430 } | |
| 4431 | |
| 4432 if (typeof instance.componentWillUpdate === 'function' && instance.componentWillUpdate.__suppressDeprecationWarning !== true) { | |
| 4433 foundWillUpdateName = 'componentWillUpdate'; | |
| 4434 } else if (typeof instance.UNSAFE_componentWillUpdate === 'function') { | |
| 4435 foundWillUpdateName = 'UNSAFE_componentWillUpdate'; | |
| 4436 } | |
| 4437 | |
| 4438 if (foundWillMountName !== null || foundWillReceivePropsName !== null || foundWillUpdateName !== null) { | |
| 4439 var _componentName = getComponentNameFromType(ctor) || 'Component'; | |
| 4440 | |
| 4441 var newApiName = typeof ctor.getDerivedStateFromProps === 'function' ? 'getDerivedStateFromProps()' : 'getSnapshotBeforeUpdate()'; | |
| 4442 | |
| 4443 if (!didWarnAboutLegacyLifecyclesAndDerivedState.has(_componentName)) { | |
| 4444 didWarnAboutLegacyLifecyclesAndDerivedState.add(_componentName); | |
| 4445 | |
| 4446 error('Unsafe legacy lifecycles will not be called for components using new component APIs.\n\n' + '%s uses %s but also contains the following legacy lifecycles:%s%s%s\n\n' + 'The above lifecycles should be removed. Learn more about this warning here:\n' + 'https://reactjs.org/link/unsafe-component-lifecycles', _componentName, newApiName, foundWillMountName !== null ? "\n " + foundWillMountName : '', foundWillReceivePropsName !== null ? "\n " + foundWillReceivePropsName : '', foundWillUpdateName !== null ? "\n " + foundWillUpdateName : ''); | |
| 4447 } | |
| 4448 } | |
| 4449 } | |
| 4450 } | |
| 4451 | |
| 4452 return instance; | |
| 4453 } | |
| 4454 | |
| 4455 function checkClassInstance(instance, ctor, newProps) { | |
| 4456 { | |
| 4457 var name = getComponentNameFromType(ctor) || 'Component'; | |
| 4458 var renderPresent = instance.render; | |
| 4459 | |
| 4460 if (!renderPresent) { | |
| 4461 if (ctor.prototype && typeof ctor.prototype.render === 'function') { | |
| 4462 error('%s(...): No `render` method found on the returned component ' + 'instance: did you accidentally return an object from the constructor?', name); | |
| 4463 } else { | |
| 4464 error('%s(...): No `render` method found on the returned component ' + 'instance: you may have forgotten to define `render`.', name); | |
| 4465 } | |
| 4466 } | |
| 4467 | |
| 4468 if (instance.getInitialState && !instance.getInitialState.isReactClassApproved && !instance.state) { | |
| 4469 error('getInitialState was defined on %s, a plain JavaScript class. ' + 'This is only supported for classes created using React.createClass. ' + 'Did you mean to define a state property instead?', name); | |
| 4470 } | |
| 4471 | |
| 4472 if (instance.getDefaultProps && !instance.getDefaultProps.isReactClassApproved) { | |
| 4473 error('getDefaultProps was defined on %s, a plain JavaScript class. ' + 'This is only supported for classes created using React.createClass. ' + 'Use a static property to define defaultProps instead.', name); | |
| 4474 } | |
| 4475 | |
| 4476 if (instance.propTypes) { | |
| 4477 error('propTypes was defined as an instance property on %s. Use a static ' + 'property to define propTypes instead.', name); | |
| 4478 } | |
| 4479 | |
| 4480 if (instance.contextType) { | |
| 4481 error('contextType was defined as an instance property on %s. Use a static ' + 'property to define contextType instead.', name); | |
| 4482 } | |
| 4483 | |
| 4484 { | |
| 4485 if (instance.contextTypes) { | |
| 4486 error('contextTypes was defined as an instance property on %s. Use a static ' + 'property to define contextTypes instead.', name); | |
| 4487 } | |
| 4488 | |
| 4489 if (ctor.contextType && ctor.contextTypes && !didWarnAboutContextTypeAndContextTypes.has(ctor)) { | |
| 4490 didWarnAboutContextTypeAndContextTypes.add(ctor); | |
| 4491 | |
| 4492 error('%s declares both contextTypes and contextType static properties. ' + 'The legacy contextTypes property will be ignored.', name); | |
| 4493 } | |
| 4494 } | |
| 4495 | |
| 4496 if (typeof instance.componentShouldUpdate === 'function') { | |
| 4497 error('%s has a method called ' + 'componentShouldUpdate(). Did you mean shouldComponentUpdate()? ' + 'The name is phrased as a question because the function is ' + 'expected to return a value.', name); | |
| 4498 } | |
| 4499 | |
| 4500 if (ctor.prototype && ctor.prototype.isPureReactComponent && typeof instance.shouldComponentUpdate !== 'undefined') { | |
| 4501 error('%s has a method called shouldComponentUpdate(). ' + 'shouldComponentUpdate should not be used when extending React.PureComponent. ' + 'Please extend React.Component if shouldComponentUpdate is used.', getComponentNameFromType(ctor) || 'A pure component'); | |
| 4502 } | |
| 4503 | |
| 4504 if (typeof instance.componentDidUnmount === 'function') { | |
| 4505 error('%s has a method called ' + 'componentDidUnmount(). But there is no such lifecycle method. ' + 'Did you mean componentWillUnmount()?', name); | |
| 4506 } | |
| 4507 | |
| 4508 if (typeof instance.componentDidReceiveProps === 'function') { | |
| 4509 error('%s has a method called ' + 'componentDidReceiveProps(). But there is no such lifecycle method. ' + 'If you meant to update the state in response to changing props, ' + 'use componentWillReceiveProps(). If you meant to fetch data or ' + 'run side-effects or mutations after React has updated the UI, use componentDidUpdate().', name); | |
| 4510 } | |
| 4511 | |
| 4512 if (typeof instance.componentWillRecieveProps === 'function') { | |
| 4513 error('%s has a method called ' + 'componentWillRecieveProps(). Did you mean componentWillReceiveProps()?', name); | |
| 4514 } | |
| 4515 | |
| 4516 if (typeof instance.UNSAFE_componentWillRecieveProps === 'function') { | |
| 4517 error('%s has a method called ' + 'UNSAFE_componentWillRecieveProps(). Did you mean UNSAFE_componentWillReceiveProps()?', name); | |
| 4518 } | |
| 4519 | |
| 4520 var hasMutatedProps = instance.props !== newProps; | |
| 4521 | |
| 4522 if (instance.props !== undefined && hasMutatedProps) { | |
| 4523 error('%s(...): When calling super() in `%s`, make sure to pass ' + "up the same props that your component's constructor was passed.", name, name); | |
| 4524 } | |
| 4525 | |
| 4526 if (instance.defaultProps) { | |
| 4527 error('Setting defaultProps as an instance property on %s is not supported and will be ignored.' + ' Instead, define defaultProps as a static property on %s.', name, name); | |
| 4528 } | |
| 4529 | |
| 4530 if (typeof instance.getSnapshotBeforeUpdate === 'function' && typeof instance.componentDidUpdate !== 'function' && !didWarnAboutGetSnapshotBeforeUpdateWithoutDidUpdate.has(ctor)) { | |
| 4531 didWarnAboutGetSnapshotBeforeUpdateWithoutDidUpdate.add(ctor); | |
| 4532 | |
| 4533 error('%s: getSnapshotBeforeUpdate() should be used with componentDidUpdate(). ' + 'This component defines getSnapshotBeforeUpdate() only.', getComponentNameFromType(ctor)); | |
| 4534 } | |
| 4535 | |
| 4536 if (typeof instance.getDerivedStateFromProps === 'function') { | |
| 4537 error('%s: getDerivedStateFromProps() is defined as an instance method ' + 'and will be ignored. Instead, declare it as a static method.', name); | |
| 4538 } | |
| 4539 | |
| 4540 if (typeof instance.getDerivedStateFromError === 'function') { | |
| 4541 error('%s: getDerivedStateFromError() is defined as an instance method ' + 'and will be ignored. Instead, declare it as a static method.', name); | |
| 4542 } | |
| 4543 | |
| 4544 if (typeof ctor.getSnapshotBeforeUpdate === 'function') { | |
| 4545 error('%s: getSnapshotBeforeUpdate() is defined as a static method ' + 'and will be ignored. Instead, declare it as an instance method.', name); | |
| 4546 } | |
| 4547 | |
| 4548 var _state = instance.state; | |
| 4549 | |
| 4550 if (_state && (typeof _state !== 'object' || isArray(_state))) { | |
| 4551 error('%s.state: must be set to an object or null', name); | |
| 4552 } | |
| 4553 | |
| 4554 if (typeof instance.getChildContext === 'function' && typeof ctor.childContextTypes !== 'object') { | |
| 4555 error('%s.getChildContext(): childContextTypes must be defined in order to ' + 'use getChildContext().', name); | |
| 4556 } | |
| 4557 } | |
| 4558 } | |
| 4559 | |
| 4560 function callComponentWillMount(type, instance) { | |
| 4561 var oldState = instance.state; | |
| 4562 | |
| 4563 if (typeof instance.componentWillMount === 'function') { | |
| 4564 { | |
| 4565 if ( instance.componentWillMount.__suppressDeprecationWarning !== true) { | |
| 4566 var componentName = getComponentNameFromType(type) || 'Unknown'; | |
| 4567 | |
| 4568 if (!didWarnAboutDeprecatedWillMount[componentName]) { | |
| 4569 warn( // keep this warning in sync with ReactStrictModeWarning.js | |
| 4570 'componentWillMount has been renamed, and is not recommended for use. ' + 'See https://reactjs.org/link/unsafe-component-lifecycles for details.\n\n' + '* Move code from componentWillMount to componentDidMount (preferred in most cases) ' + 'or the constructor.\n' + '\nPlease update the following components: %s', componentName); | |
| 4571 | |
| 4572 didWarnAboutDeprecatedWillMount[componentName] = true; | |
| 4573 } | |
| 4574 } | |
| 4575 } | |
| 4576 | |
| 4577 instance.componentWillMount(); | |
| 4578 } | |
| 4579 | |
| 4580 if (typeof instance.UNSAFE_componentWillMount === 'function') { | |
| 4581 instance.UNSAFE_componentWillMount(); | |
| 4582 } | |
| 4583 | |
| 4584 if (oldState !== instance.state) { | |
| 4585 { | |
| 4586 error('%s.componentWillMount(): Assigning directly to this.state is ' + "deprecated (except inside a component's " + 'constructor). Use setState instead.', getComponentNameFromType(type) || 'Component'); | |
| 4587 } | |
| 4588 | |
| 4589 classComponentUpdater.enqueueReplaceState(instance, instance.state, null); | |
| 4590 } | |
| 4591 } | |
| 4592 | |
| 4593 function processUpdateQueue(internalInstance, inst, props, maskedLegacyContext) { | |
| 4594 if (internalInstance.queue !== null && internalInstance.queue.length > 0) { | |
| 4595 var oldQueue = internalInstance.queue; | |
| 4596 var oldReplace = internalInstance.replace; | |
| 4597 internalInstance.queue = null; | |
| 4598 internalInstance.replace = false; | |
| 4599 | |
| 4600 if (oldReplace && oldQueue.length === 1) { | |
| 4601 inst.state = oldQueue[0]; | |
| 4602 } else { | |
| 4603 var nextState = oldReplace ? oldQueue[0] : inst.state; | |
| 4604 var dontMutate = true; | |
| 4605 | |
| 4606 for (var i = oldReplace ? 1 : 0; i < oldQueue.length; i++) { | |
| 4607 var partial = oldQueue[i]; | |
| 4608 var partialState = typeof partial === 'function' ? partial.call(inst, nextState, props, maskedLegacyContext) : partial; | |
| 4609 | |
| 4610 if (partialState != null) { | |
| 4611 if (dontMutate) { | |
| 4612 dontMutate = false; | |
| 4613 nextState = assign({}, nextState, partialState); | |
| 4614 } else { | |
| 4615 assign(nextState, partialState); | |
| 4616 } | |
| 4617 } | |
| 4618 } | |
| 4619 | |
| 4620 inst.state = nextState; | |
| 4621 } | |
| 4622 } else { | |
| 4623 internalInstance.queue = null; | |
| 4624 } | |
| 4625 } // Invokes the mount life-cycles on a previously never rendered instance. | |
| 4626 | |
| 4627 | |
| 4628 function mountClassInstance(instance, ctor, newProps, maskedLegacyContext) { | |
| 4629 { | |
| 4630 checkClassInstance(instance, ctor, newProps); | |
| 4631 } | |
| 4632 | |
| 4633 var initialState = instance.state !== undefined ? instance.state : null; | |
| 4634 instance.updater = classComponentUpdater; | |
| 4635 instance.props = newProps; | |
| 4636 instance.state = initialState; // We don't bother initializing the refs object on the server, since we're not going to resolve them anyway. | |
| 4637 // The internal instance will be used to manage updates that happen during this mount. | |
| 4638 | |
| 4639 var internalInstance = { | |
| 4640 queue: [], | |
| 4641 replace: false | |
| 4642 }; | |
| 4643 set(instance, internalInstance); | |
| 4644 var contextType = ctor.contextType; | |
| 4645 | |
| 4646 if (typeof contextType === 'object' && contextType !== null) { | |
| 4647 instance.context = readContext(contextType); | |
| 4648 } else { | |
| 4649 instance.context = maskedLegacyContext; | |
| 4650 } | |
| 4651 | |
| 4652 { | |
| 4653 if (instance.state === newProps) { | |
| 4654 var componentName = getComponentNameFromType(ctor) || 'Component'; | |
| 4655 | |
| 4656 if (!didWarnAboutDirectlyAssigningPropsToState.has(componentName)) { | |
| 4657 didWarnAboutDirectlyAssigningPropsToState.add(componentName); | |
| 4658 | |
| 4659 error('%s: It is not recommended to assign props directly to state ' + "because updates to props won't be reflected in state. " + 'In most cases, it is better to use props directly.', componentName); | |
| 4660 } | |
| 4661 } | |
| 4662 } | |
| 4663 | |
| 4664 var getDerivedStateFromProps = ctor.getDerivedStateFromProps; | |
| 4665 | |
| 4666 if (typeof getDerivedStateFromProps === 'function') { | |
| 4667 instance.state = applyDerivedStateFromProps(instance, ctor, getDerivedStateFromProps, initialState, newProps); | |
| 4668 } // In order to support react-lifecycles-compat polyfilled components, | |
| 4669 // Unsafe lifecycles should not be invoked for components using the new APIs. | |
| 4670 | |
| 4671 | |
| 4672 if (typeof ctor.getDerivedStateFromProps !== 'function' && typeof instance.getSnapshotBeforeUpdate !== 'function' && (typeof instance.UNSAFE_componentWillMount === 'function' || typeof instance.componentWillMount === 'function')) { | |
| 4673 callComponentWillMount(ctor, instance); // If we had additional state updates during this life-cycle, let's | |
| 4674 // process them now. | |
| 4675 | |
| 4676 processUpdateQueue(internalInstance, instance, newProps, maskedLegacyContext); | |
| 4677 } | |
| 4678 } | |
| 4679 | |
| 4680 // Ids are base 32 strings whose binary representation corresponds to the | |
| 4681 // position of a node in a tree. | |
| 4682 // Every time the tree forks into multiple children, we add additional bits to | |
| 4683 // the left of the sequence that represent the position of the child within the | |
| 4684 // current level of children. | |
| 4685 // | |
| 4686 // 00101 00010001011010101 | |
| 4687 // ╰─┬─╯ ╰───────┬───────╯ | |
| 4688 // Fork 5 of 20 Parent id | |
| 4689 // | |
| 4690 // The leading 0s are important. In the above example, you only need 3 bits to | |
| 4691 // represent slot 5. However, you need 5 bits to represent all the forks at | |
| 4692 // the current level, so we must account for the empty bits at the end. | |
| 4693 // | |
| 4694 // For this same reason, slots are 1-indexed instead of 0-indexed. Otherwise, | |
| 4695 // the zeroth id at a level would be indistinguishable from its parent. | |
| 4696 // | |
| 4697 // If a node has only one child, and does not materialize an id (i.e. does not | |
| 4698 // contain a useId hook), then we don't need to allocate any space in the | |
| 4699 // sequence. It's treated as a transparent indirection. For example, these two | |
| 4700 // trees produce the same ids: | |
| 4701 // | |
| 4702 // <> <> | |
| 4703 // <Indirection> <A /> | |
| 4704 // <A /> <B /> | |
| 4705 // </Indirection> </> | |
| 4706 // <B /> | |
| 4707 // </> | |
| 4708 // | |
| 4709 // However, we cannot skip any node that materializes an id. Otherwise, a parent | |
| 4710 // id that does not fork would be indistinguishable from its child id. For | |
| 4711 // example, this tree does not fork, but the parent and child must have | |
| 4712 // different ids. | |
| 4713 // | |
| 4714 // <Parent> | |
| 4715 // <Child /> | |
| 4716 // </Parent> | |
| 4717 // | |
| 4718 // To handle this scenario, every time we materialize an id, we allocate a | |
| 4719 // new level with a single slot. You can think of this as a fork with only one | |
| 4720 // prong, or an array of children with length 1. | |
| 4721 // | |
| 4722 // It's possible for the size of the sequence to exceed 32 bits, the max | |
| 4723 // size for bitwise operations. When this happens, we make more room by | |
| 4724 // converting the right part of the id to a string and storing it in an overflow | |
| 4725 // variable. We use a base 32 string representation, because 32 is the largest | |
| 4726 // power of 2 that is supported by toString(). We want the base to be large so | |
| 4727 // that the resulting ids are compact, and we want the base to be a power of 2 | |
| 4728 // because every log2(base) bits corresponds to a single character, i.e. every | |
| 4729 // log2(32) = 5 bits. That means we can lop bits off the end 5 at a time without | |
| 4730 // affecting the final result. | |
| 4731 var emptyTreeContext = { | |
| 4732 id: 1, | |
| 4733 overflow: '' | |
| 4734 }; | |
| 4735 function getTreeId(context) { | |
| 4736 var overflow = context.overflow; | |
| 4737 var idWithLeadingBit = context.id; | |
| 4738 var id = idWithLeadingBit & ~getLeadingBit(idWithLeadingBit); | |
| 4739 return id.toString(32) + overflow; | |
| 4740 } | |
| 4741 function pushTreeContext(baseContext, totalChildren, index) { | |
| 4742 var baseIdWithLeadingBit = baseContext.id; | |
| 4743 var baseOverflow = baseContext.overflow; // The leftmost 1 marks the end of the sequence, non-inclusive. It's not part | |
| 4744 // of the id; we use it to account for leading 0s. | |
| 4745 | |
| 4746 var baseLength = getBitLength(baseIdWithLeadingBit) - 1; | |
| 4747 var baseId = baseIdWithLeadingBit & ~(1 << baseLength); | |
| 4748 var slot = index + 1; | |
| 4749 var length = getBitLength(totalChildren) + baseLength; // 30 is the max length we can store without overflowing, taking into | |
| 4750 // consideration the leading 1 we use to mark the end of the sequence. | |
| 4751 | |
| 4752 if (length > 30) { | |
| 4753 // We overflowed the bitwise-safe range. Fall back to slower algorithm. | |
| 4754 // This branch assumes the length of the base id is greater than 5; it won't | |
| 4755 // work for smaller ids, because you need 5 bits per character. | |
| 4756 // | |
| 4757 // We encode the id in multiple steps: first the base id, then the | |
| 4758 // remaining digits. | |
| 4759 // | |
| 4760 // Each 5 bit sequence corresponds to a single base 32 character. So for | |
| 4761 // example, if the current id is 23 bits long, we can convert 20 of those | |
| 4762 // bits into a string of 4 characters, with 3 bits left over. | |
| 4763 // | |
| 4764 // First calculate how many bits in the base id represent a complete | |
| 4765 // sequence of characters. | |
| 4766 var numberOfOverflowBits = baseLength - baseLength % 5; // Then create a bitmask that selects only those bits. | |
| 4767 | |
| 4768 var newOverflowBits = (1 << numberOfOverflowBits) - 1; // Select the bits, and convert them to a base 32 string. | |
| 4769 | |
| 4770 var newOverflow = (baseId & newOverflowBits).toString(32); // Now we can remove those bits from the base id. | |
| 4771 | |
| 4772 var restOfBaseId = baseId >> numberOfOverflowBits; | |
| 4773 var restOfBaseLength = baseLength - numberOfOverflowBits; // Finally, encode the rest of the bits using the normal algorithm. Because | |
| 4774 // we made more room, this time it won't overflow. | |
| 4775 | |
| 4776 var restOfLength = getBitLength(totalChildren) + restOfBaseLength; | |
| 4777 var restOfNewBits = slot << restOfBaseLength; | |
| 4778 var id = restOfNewBits | restOfBaseId; | |
| 4779 var overflow = newOverflow + baseOverflow; | |
| 4780 return { | |
| 4781 id: 1 << restOfLength | id, | |
| 4782 overflow: overflow | |
| 4783 }; | |
| 4784 } else { | |
| 4785 // Normal path | |
| 4786 var newBits = slot << baseLength; | |
| 4787 | |
| 4788 var _id = newBits | baseId; | |
| 4789 | |
| 4790 var _overflow = baseOverflow; | |
| 4791 return { | |
| 4792 id: 1 << length | _id, | |
| 4793 overflow: _overflow | |
| 4794 }; | |
| 4795 } | |
| 4796 } | |
| 4797 | |
| 4798 function getBitLength(number) { | |
| 4799 return 32 - clz32(number); | |
| 4800 } | |
| 4801 | |
| 4802 function getLeadingBit(id) { | |
| 4803 return 1 << getBitLength(id) - 1; | |
| 4804 } // TODO: Math.clz32 is supported in Node 12+. Maybe we can drop the fallback. | |
| 4805 | |
| 4806 | |
| 4807 var clz32 = Math.clz32 ? Math.clz32 : clz32Fallback; // Count leading zeros. | |
| 4808 // Based on: | |
| 4809 // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/clz32 | |
| 4810 | |
| 4811 var log = Math.log; | |
| 4812 var LN2 = Math.LN2; | |
| 4813 | |
| 4814 function clz32Fallback(x) { | |
| 4815 var asUint = x >>> 0; | |
| 4816 | |
| 4817 if (asUint === 0) { | |
| 4818 return 32; | |
| 4819 } | |
| 4820 | |
| 4821 return 31 - (log(asUint) / LN2 | 0) | 0; | |
| 4822 } | |
| 4823 | |
| 4824 /** | |
| 4825 * inlined Object.is polyfill to avoid requiring consumers ship their own | |
| 4826 * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is | |
| 4827 */ | |
| 4828 function is(x, y) { | |
| 4829 return x === y && (x !== 0 || 1 / x === 1 / y) || x !== x && y !== y // eslint-disable-line no-self-compare | |
| 4830 ; | |
| 4831 } | |
| 4832 | |
| 4833 var objectIs = typeof Object.is === 'function' ? Object.is : is; | |
| 4834 | |
| 4835 var currentlyRenderingComponent = null; | |
| 4836 var currentlyRenderingTask = null; | |
| 4837 var firstWorkInProgressHook = null; | |
| 4838 var workInProgressHook = null; // Whether the work-in-progress hook is a re-rendered hook | |
| 4839 | |
| 4840 var isReRender = false; // Whether an update was scheduled during the currently executing render pass. | |
| 4841 | |
| 4842 var didScheduleRenderPhaseUpdate = false; // Counts the number of useId hooks in this component | |
| 4843 | |
| 4844 var localIdCounter = 0; // Lazily created map of render-phase updates | |
| 4845 | |
| 4846 var renderPhaseUpdates = null; // Counter to prevent infinite loops. | |
| 4847 | |
| 4848 var numberOfReRenders = 0; | |
| 4849 var RE_RENDER_LIMIT = 25; | |
| 4850 var isInHookUserCodeInDev = false; // In DEV, this is the name of the currently executing primitive hook | |
| 4851 | |
| 4852 var currentHookNameInDev; | |
| 4853 | |
| 4854 function resolveCurrentlyRenderingComponent() { | |
| 4855 if (currentlyRenderingComponent === null) { | |
| 4856 throw new Error('Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for' + ' one of the following reasons:\n' + '1. You might have mismatching versions of React and the renderer (such as React DOM)\n' + '2. You might be breaking the Rules of Hooks\n' + '3. You might have more than one copy of React in the same app\n' + 'See https://reactjs.org/link/invalid-hook-call for tips about how to debug and fix this problem.'); | |
| 4857 } | |
| 4858 | |
| 4859 { | |
| 4860 if (isInHookUserCodeInDev) { | |
| 4861 error('Do not call Hooks inside useEffect(...), useMemo(...), or other built-in Hooks. ' + 'You can only call Hooks at the top level of your React function. ' + 'For more information, see ' + 'https://reactjs.org/link/rules-of-hooks'); | |
| 4862 } | |
| 4863 } | |
| 4864 | |
| 4865 return currentlyRenderingComponent; | |
| 4866 } | |
| 4867 | |
| 4868 function areHookInputsEqual(nextDeps, prevDeps) { | |
| 4869 if (prevDeps === null) { | |
| 4870 { | |
| 4871 error('%s received a final argument during this render, but not during ' + 'the previous render. Even though the final argument is optional, ' + 'its type cannot change between renders.', currentHookNameInDev); | |
| 4872 } | |
| 4873 | |
| 4874 return false; | |
| 4875 } | |
| 4876 | |
| 4877 { | |
| 4878 // Don't bother comparing lengths in prod because these arrays should be | |
| 4879 // passed inline. | |
| 4880 if (nextDeps.length !== prevDeps.length) { | |
| 4881 error('The final argument passed to %s changed size between renders. The ' + 'order and size of this array must remain constant.\n\n' + 'Previous: %s\n' + 'Incoming: %s', currentHookNameInDev, "[" + nextDeps.join(', ') + "]", "[" + prevDeps.join(', ') + "]"); | |
| 4882 } | |
| 4883 } | |
| 4884 | |
| 4885 for (var i = 0; i < prevDeps.length && i < nextDeps.length; i++) { | |
| 4886 if (objectIs(nextDeps[i], prevDeps[i])) { | |
| 4887 continue; | |
| 4888 } | |
| 4889 | |
| 4890 return false; | |
| 4891 } | |
| 4892 | |
| 4893 return true; | |
| 4894 } | |
| 4895 | |
| 4896 function createHook() { | |
| 4897 if (numberOfReRenders > 0) { | |
| 4898 throw new Error('Rendered more hooks than during the previous render'); | |
| 4899 } | |
| 4900 | |
| 4901 return { | |
| 4902 memoizedState: null, | |
| 4903 queue: null, | |
| 4904 next: null | |
| 4905 }; | |
| 4906 } | |
| 4907 | |
| 4908 function createWorkInProgressHook() { | |
| 4909 if (workInProgressHook === null) { | |
| 4910 // This is the first hook in the list | |
| 4911 if (firstWorkInProgressHook === null) { | |
| 4912 isReRender = false; | |
| 4913 firstWorkInProgressHook = workInProgressHook = createHook(); | |
| 4914 } else { | |
| 4915 // There's already a work-in-progress. Reuse it. | |
| 4916 isReRender = true; | |
| 4917 workInProgressHook = firstWorkInProgressHook; | |
| 4918 } | |
| 4919 } else { | |
| 4920 if (workInProgressHook.next === null) { | |
| 4921 isReRender = false; // Append to the end of the list | |
| 4922 | |
| 4923 workInProgressHook = workInProgressHook.next = createHook(); | |
| 4924 } else { | |
| 4925 // There's already a work-in-progress. Reuse it. | |
| 4926 isReRender = true; | |
| 4927 workInProgressHook = workInProgressHook.next; | |
| 4928 } | |
| 4929 } | |
| 4930 | |
| 4931 return workInProgressHook; | |
| 4932 } | |
| 4933 | |
| 4934 function prepareToUseHooks(task, componentIdentity) { | |
| 4935 currentlyRenderingComponent = componentIdentity; | |
| 4936 currentlyRenderingTask = task; | |
| 4937 | |
| 4938 { | |
| 4939 isInHookUserCodeInDev = false; | |
| 4940 } // The following should have already been reset | |
| 4941 // didScheduleRenderPhaseUpdate = false; | |
| 4942 // localIdCounter = 0; | |
| 4943 // firstWorkInProgressHook = null; | |
| 4944 // numberOfReRenders = 0; | |
| 4945 // renderPhaseUpdates = null; | |
| 4946 // workInProgressHook = null; | |
| 4947 | |
| 4948 | |
| 4949 localIdCounter = 0; | |
| 4950 } | |
| 4951 function finishHooks(Component, props, children, refOrContext) { | |
| 4952 // This must be called after every function component to prevent hooks from | |
| 4953 // being used in classes. | |
| 4954 while (didScheduleRenderPhaseUpdate) { | |
| 4955 // Updates were scheduled during the render phase. They are stored in | |
| 4956 // the `renderPhaseUpdates` map. Call the component again, reusing the | |
| 4957 // work-in-progress hooks and applying the additional updates on top. Keep | |
| 4958 // restarting until no more updates are scheduled. | |
| 4959 didScheduleRenderPhaseUpdate = false; | |
| 4960 localIdCounter = 0; | |
| 4961 numberOfReRenders += 1; // Start over from the beginning of the list | |
| 4962 | |
| 4963 workInProgressHook = null; | |
| 4964 children = Component(props, refOrContext); | |
| 4965 } | |
| 4966 | |
| 4967 resetHooksState(); | |
| 4968 return children; | |
| 4969 } | |
| 4970 function checkDidRenderIdHook() { | |
| 4971 // This should be called immediately after every finishHooks call. | |
| 4972 // Conceptually, it's part of the return value of finishHooks; it's only a | |
| 4973 // separate function to avoid using an array tuple. | |
| 4974 var didRenderIdHook = localIdCounter !== 0; | |
| 4975 return didRenderIdHook; | |
| 4976 } // Reset the internal hooks state if an error occurs while rendering a component | |
| 4977 | |
| 4978 function resetHooksState() { | |
| 4979 { | |
| 4980 isInHookUserCodeInDev = false; | |
| 4981 } | |
| 4982 | |
| 4983 currentlyRenderingComponent = null; | |
| 4984 currentlyRenderingTask = null; | |
| 4985 didScheduleRenderPhaseUpdate = false; | |
| 4986 firstWorkInProgressHook = null; | |
| 4987 numberOfReRenders = 0; | |
| 4988 renderPhaseUpdates = null; | |
| 4989 workInProgressHook = null; | |
| 4990 } | |
| 4991 | |
| 4992 function readContext$1(context) { | |
| 4993 { | |
| 4994 if (isInHookUserCodeInDev) { | |
| 4995 error('Context can only be read while React is rendering. ' + 'In classes, you can read it in the render method or getDerivedStateFromProps. ' + 'In function components, you can read it directly in the function body, but not ' + 'inside Hooks like useReducer() or useMemo().'); | |
| 4996 } | |
| 4997 } | |
| 4998 | |
| 4999 return readContext(context); | |
| 5000 } | |
| 5001 | |
| 5002 function useContext(context) { | |
| 5003 { | |
| 5004 currentHookNameInDev = 'useContext'; | |
| 5005 } | |
| 5006 | |
| 5007 resolveCurrentlyRenderingComponent(); | |
| 5008 return readContext(context); | |
| 5009 } | |
| 5010 | |
| 5011 function basicStateReducer(state, action) { | |
| 5012 // $FlowFixMe: Flow doesn't like mixed types | |
| 5013 return typeof action === 'function' ? action(state) : action; | |
| 5014 } | |
| 5015 | |
| 5016 function useState(initialState) { | |
| 5017 { | |
| 5018 currentHookNameInDev = 'useState'; | |
| 5019 } | |
| 5020 | |
| 5021 return useReducer(basicStateReducer, // useReducer has a special case to support lazy useState initializers | |
| 5022 initialState); | |
| 5023 } | |
| 5024 function useReducer(reducer, initialArg, init) { | |
| 5025 { | |
| 5026 if (reducer !== basicStateReducer) { | |
| 5027 currentHookNameInDev = 'useReducer'; | |
| 5028 } | |
| 5029 } | |
| 5030 | |
| 5031 currentlyRenderingComponent = resolveCurrentlyRenderingComponent(); | |
| 5032 workInProgressHook = createWorkInProgressHook(); | |
| 5033 | |
| 5034 if (isReRender) { | |
| 5035 // This is a re-render. Apply the new render phase updates to the previous | |
| 5036 // current hook. | |
| 5037 var queue = workInProgressHook.queue; | |
| 5038 var dispatch = queue.dispatch; | |
| 5039 | |
| 5040 if (renderPhaseUpdates !== null) { | |
| 5041 // Render phase updates are stored in a map of queue -> linked list | |
| 5042 var firstRenderPhaseUpdate = renderPhaseUpdates.get(queue); | |
| 5043 | |
| 5044 if (firstRenderPhaseUpdate !== undefined) { | |
| 5045 renderPhaseUpdates.delete(queue); | |
| 5046 var newState = workInProgressHook.memoizedState; | |
| 5047 var update = firstRenderPhaseUpdate; | |
| 5048 | |
| 5049 do { | |
| 5050 // Process this render phase update. We don't have to check the | |
| 5051 // priority because it will always be the same as the current | |
| 5052 // render's. | |
| 5053 var action = update.action; | |
| 5054 | |
| 5055 { | |
| 5056 isInHookUserCodeInDev = true; | |
| 5057 } | |
| 5058 | |
| 5059 newState = reducer(newState, action); | |
| 5060 | |
| 5061 { | |
| 5062 isInHookUserCodeInDev = false; | |
| 5063 } | |
| 5064 | |
| 5065 update = update.next; | |
| 5066 } while (update !== null); | |
| 5067 | |
| 5068 workInProgressHook.memoizedState = newState; | |
| 5069 return [newState, dispatch]; | |
| 5070 } | |
| 5071 } | |
| 5072 | |
| 5073 return [workInProgressHook.memoizedState, dispatch]; | |
| 5074 } else { | |
| 5075 { | |
| 5076 isInHookUserCodeInDev = true; | |
| 5077 } | |
| 5078 | |
| 5079 var initialState; | |
| 5080 | |
| 5081 if (reducer === basicStateReducer) { | |
| 5082 // Special case for `useState`. | |
| 5083 initialState = typeof initialArg === 'function' ? initialArg() : initialArg; | |
| 5084 } else { | |
| 5085 initialState = init !== undefined ? init(initialArg) : initialArg; | |
| 5086 } | |
| 5087 | |
| 5088 { | |
| 5089 isInHookUserCodeInDev = false; | |
| 5090 } | |
| 5091 | |
| 5092 workInProgressHook.memoizedState = initialState; | |
| 5093 | |
| 5094 var _queue = workInProgressHook.queue = { | |
| 5095 last: null, | |
| 5096 dispatch: null | |
| 5097 }; | |
| 5098 | |
| 5099 var _dispatch = _queue.dispatch = dispatchAction.bind(null, currentlyRenderingComponent, _queue); | |
| 5100 | |
| 5101 return [workInProgressHook.memoizedState, _dispatch]; | |
| 5102 } | |
| 5103 } | |
| 5104 | |
| 5105 function useMemo(nextCreate, deps) { | |
| 5106 currentlyRenderingComponent = resolveCurrentlyRenderingComponent(); | |
| 5107 workInProgressHook = createWorkInProgressHook(); | |
| 5108 var nextDeps = deps === undefined ? null : deps; | |
| 5109 | |
| 5110 if (workInProgressHook !== null) { | |
| 5111 var prevState = workInProgressHook.memoizedState; | |
| 5112 | |
| 5113 if (prevState !== null) { | |
| 5114 if (nextDeps !== null) { | |
| 5115 var prevDeps = prevState[1]; | |
| 5116 | |
| 5117 if (areHookInputsEqual(nextDeps, prevDeps)) { | |
| 5118 return prevState[0]; | |
| 5119 } | |
| 5120 } | |
| 5121 } | |
| 5122 } | |
| 5123 | |
| 5124 { | |
| 5125 isInHookUserCodeInDev = true; | |
| 5126 } | |
| 5127 | |
| 5128 var nextValue = nextCreate(); | |
| 5129 | |
| 5130 { | |
| 5131 isInHookUserCodeInDev = false; | |
| 5132 } | |
| 5133 | |
| 5134 workInProgressHook.memoizedState = [nextValue, nextDeps]; | |
| 5135 return nextValue; | |
| 5136 } | |
| 5137 | |
| 5138 function useRef(initialValue) { | |
| 5139 currentlyRenderingComponent = resolveCurrentlyRenderingComponent(); | |
| 5140 workInProgressHook = createWorkInProgressHook(); | |
| 5141 var previousRef = workInProgressHook.memoizedState; | |
| 5142 | |
| 5143 if (previousRef === null) { | |
| 5144 var ref = { | |
| 5145 current: initialValue | |
| 5146 }; | |
| 5147 | |
| 5148 { | |
| 5149 Object.seal(ref); | |
| 5150 } | |
| 5151 | |
| 5152 workInProgressHook.memoizedState = ref; | |
| 5153 return ref; | |
| 5154 } else { | |
| 5155 return previousRef; | |
| 5156 } | |
| 5157 } | |
| 5158 | |
| 5159 function useLayoutEffect(create, inputs) { | |
| 5160 { | |
| 5161 currentHookNameInDev = 'useLayoutEffect'; | |
| 5162 | |
| 5163 error('useLayoutEffect does nothing on the server, because its effect cannot ' + "be encoded into the server renderer's output format. This will lead " + 'to a mismatch between the initial, non-hydrated UI and the intended ' + 'UI. To avoid this, useLayoutEffect should only be used in ' + 'components that render exclusively on the client. ' + 'See https://reactjs.org/link/uselayouteffect-ssr for common fixes.'); | |
| 5164 } | |
| 5165 } | |
| 5166 | |
| 5167 function dispatchAction(componentIdentity, queue, action) { | |
| 5168 if (numberOfReRenders >= RE_RENDER_LIMIT) { | |
| 5169 throw new Error('Too many re-renders. React limits the number of renders to prevent ' + 'an infinite loop.'); | |
| 5170 } | |
| 5171 | |
| 5172 if (componentIdentity === currentlyRenderingComponent) { | |
| 5173 // This is a render phase update. Stash it in a lazily-created map of | |
| 5174 // queue -> linked list of updates. After this render pass, we'll restart | |
| 5175 // and apply the stashed updates on top of the work-in-progress hook. | |
| 5176 didScheduleRenderPhaseUpdate = true; | |
| 5177 var update = { | |
| 5178 action: action, | |
| 5179 next: null | |
| 5180 }; | |
| 5181 | |
| 5182 if (renderPhaseUpdates === null) { | |
| 5183 renderPhaseUpdates = new Map(); | |
| 5184 } | |
| 5185 | |
| 5186 var firstRenderPhaseUpdate = renderPhaseUpdates.get(queue); | |
| 5187 | |
| 5188 if (firstRenderPhaseUpdate === undefined) { | |
| 5189 renderPhaseUpdates.set(queue, update); | |
| 5190 } else { | |
| 5191 // Append the update to the end of the list. | |
| 5192 var lastRenderPhaseUpdate = firstRenderPhaseUpdate; | |
| 5193 | |
| 5194 while (lastRenderPhaseUpdate.next !== null) { | |
| 5195 lastRenderPhaseUpdate = lastRenderPhaseUpdate.next; | |
| 5196 } | |
| 5197 | |
| 5198 lastRenderPhaseUpdate.next = update; | |
| 5199 } | |
| 5200 } | |
| 5201 } | |
| 5202 | |
| 5203 function useCallback(callback, deps) { | |
| 5204 return useMemo(function () { | |
| 5205 return callback; | |
| 5206 }, deps); | |
| 5207 } // TODO Decide on how to implement this hook for server rendering. | |
| 5208 // If a mutation occurs during render, consider triggering a Suspense boundary | |
| 5209 // and falling back to client rendering. | |
| 5210 | |
| 5211 function useMutableSource(source, getSnapshot, subscribe) { | |
| 5212 resolveCurrentlyRenderingComponent(); | |
| 5213 return getSnapshot(source._source); | |
| 5214 } | |
| 5215 | |
| 5216 function useSyncExternalStore(subscribe, getSnapshot, getServerSnapshot) { | |
| 5217 if (getServerSnapshot === undefined) { | |
| 5218 throw new Error('Missing getServerSnapshot, which is required for ' + 'server-rendered content. Will revert to client rendering.'); | |
| 5219 } | |
| 5220 | |
| 5221 return getServerSnapshot(); | |
| 5222 } | |
| 5223 | |
| 5224 function useDeferredValue(value) { | |
| 5225 resolveCurrentlyRenderingComponent(); | |
| 5226 return value; | |
| 5227 } | |
| 5228 | |
| 5229 function unsupportedStartTransition() { | |
| 5230 throw new Error('startTransition cannot be called during server rendering.'); | |
| 5231 } | |
| 5232 | |
| 5233 function useTransition() { | |
| 5234 resolveCurrentlyRenderingComponent(); | |
| 5235 return [false, unsupportedStartTransition]; | |
| 5236 } | |
| 5237 | |
| 5238 function useId() { | |
| 5239 var task = currentlyRenderingTask; | |
| 5240 var treeId = getTreeId(task.treeContext); | |
| 5241 var responseState = currentResponseState; | |
| 5242 | |
| 5243 if (responseState === null) { | |
| 5244 throw new Error('Invalid hook call. Hooks can only be called inside of the body of a function component.'); | |
| 5245 } | |
| 5246 | |
| 5247 var localId = localIdCounter++; | |
| 5248 return makeId(responseState, treeId, localId); | |
| 5249 } | |
| 5250 | |
| 5251 function noop() {} | |
| 5252 | |
| 5253 var Dispatcher = { | |
| 5254 readContext: readContext$1, | |
| 5255 useContext: useContext, | |
| 5256 useMemo: useMemo, | |
| 5257 useReducer: useReducer, | |
| 5258 useRef: useRef, | |
| 5259 useState: useState, | |
| 5260 useInsertionEffect: noop, | |
| 5261 useLayoutEffect: useLayoutEffect, | |
| 5262 useCallback: useCallback, | |
| 5263 // useImperativeHandle is not run in the server environment | |
| 5264 useImperativeHandle: noop, | |
| 5265 // Effects are not run in the server environment. | |
| 5266 useEffect: noop, | |
| 5267 // Debugging effect | |
| 5268 useDebugValue: noop, | |
| 5269 useDeferredValue: useDeferredValue, | |
| 5270 useTransition: useTransition, | |
| 5271 useId: useId, | |
| 5272 // Subscriptions are not setup in a server environment. | |
| 5273 useMutableSource: useMutableSource, | |
| 5274 useSyncExternalStore: useSyncExternalStore | |
| 5275 }; | |
| 5276 | |
| 5277 var currentResponseState = null; | |
| 5278 function setCurrentResponseState(responseState) { | |
| 5279 currentResponseState = responseState; | |
| 5280 } | |
| 5281 | |
| 5282 function getStackByComponentStackNode(componentStack) { | |
| 5283 try { | |
| 5284 var info = ''; | |
| 5285 var node = componentStack; | |
| 5286 | |
| 5287 do { | |
| 5288 switch (node.tag) { | |
| 5289 case 0: | |
| 5290 info += describeBuiltInComponentFrame(node.type, null, null); | |
| 5291 break; | |
| 5292 | |
| 5293 case 1: | |
| 5294 info += describeFunctionComponentFrame(node.type, null, null); | |
| 5295 break; | |
| 5296 | |
| 5297 case 2: | |
| 5298 info += describeClassComponentFrame(node.type, null, null); | |
| 5299 break; | |
| 5300 } | |
| 5301 | |
| 5302 node = node.parent; | |
| 5303 } while (node); | |
| 5304 | |
| 5305 return info; | |
| 5306 } catch (x) { | |
| 5307 return '\nError generating stack: ' + x.message + '\n' + x.stack; | |
| 5308 } | |
| 5309 } | |
| 5310 | |
| 5311 var ReactCurrentDispatcher$1 = ReactSharedInternals.ReactCurrentDispatcher; | |
| 5312 var ReactDebugCurrentFrame$1 = ReactSharedInternals.ReactDebugCurrentFrame; | |
| 5313 var PENDING = 0; | |
| 5314 var COMPLETED = 1; | |
| 5315 var FLUSHED = 2; | |
| 5316 var ABORTED = 3; | |
| 5317 var ERRORED = 4; | |
| 5318 var OPEN = 0; | |
| 5319 var CLOSING = 1; | |
| 5320 var CLOSED = 2; | |
| 5321 // This is a default heuristic for how to split up the HTML content into progressive | |
| 5322 // loading. Our goal is to be able to display additional new content about every 500ms. | |
| 5323 // Faster than that is unnecessary and should be throttled on the client. It also | |
| 5324 // adds unnecessary overhead to do more splits. We don't know if it's a higher or lower | |
| 5325 // end device but higher end suffer less from the overhead than lower end does from | |
| 5326 // not getting small enough pieces. We error on the side of low end. | |
| 5327 // We base this on low end 3G speeds which is about 500kbits per second. We assume | |
| 5328 // that there can be a reasonable drop off from max bandwidth which leaves you with | |
| 5329 // as little as 80%. We can receive half of that each 500ms - at best. In practice, | |
| 5330 // a little bandwidth is lost to processing and contention - e.g. CSS and images that | |
| 5331 // are downloaded along with the main content. So we estimate about half of that to be | |
| 5332 // the lower end throughput. In other words, we expect that you can at least show | |
| 5333 // about 12.5kb of content per 500ms. Not counting starting latency for the first | |
| 5334 // paint. | |
| 5335 // 500 * 1024 / 8 * .8 * 0.5 / 2 | |
| 5336 var DEFAULT_PROGRESSIVE_CHUNK_SIZE = 12800; | |
| 5337 | |
| 5338 function defaultErrorHandler(error) { | |
| 5339 console['error'](error); // Don't transform to our wrapper | |
| 5340 | |
| 5341 return null; | |
| 5342 } | |
| 5343 | |
| 5344 function noop$1() {} | |
| 5345 | |
| 5346 function createRequest(children, responseState, rootFormatContext, progressiveChunkSize, onError, onAllReady, onShellReady, onShellError, onFatalError) { | |
| 5347 var pingedTasks = []; | |
| 5348 var abortSet = new Set(); | |
| 5349 var request = { | |
| 5350 destination: null, | |
| 5351 responseState: responseState, | |
| 5352 progressiveChunkSize: progressiveChunkSize === undefined ? DEFAULT_PROGRESSIVE_CHUNK_SIZE : progressiveChunkSize, | |
| 5353 status: OPEN, | |
| 5354 fatalError: null, | |
| 5355 nextSegmentId: 0, | |
| 5356 allPendingTasks: 0, | |
| 5357 pendingRootTasks: 0, | |
| 5358 completedRootSegment: null, | |
| 5359 abortableTasks: abortSet, | |
| 5360 pingedTasks: pingedTasks, | |
| 5361 clientRenderedBoundaries: [], | |
| 5362 completedBoundaries: [], | |
| 5363 partialBoundaries: [], | |
| 5364 onError: onError === undefined ? defaultErrorHandler : onError, | |
| 5365 onAllReady: onAllReady === undefined ? noop$1 : onAllReady, | |
| 5366 onShellReady: onShellReady === undefined ? noop$1 : onShellReady, | |
| 5367 onShellError: onShellError === undefined ? noop$1 : onShellError, | |
| 5368 onFatalError: onFatalError === undefined ? noop$1 : onFatalError | |
| 5369 }; // This segment represents the root fallback. | |
| 5370 | |
| 5371 var rootSegment = createPendingSegment(request, 0, null, rootFormatContext, // Root segments are never embedded in Text on either edge | |
| 5372 false, false); // There is no parent so conceptually, we're unblocked to flush this segment. | |
| 5373 | |
| 5374 rootSegment.parentFlushed = true; | |
| 5375 var rootTask = createTask(request, children, null, rootSegment, abortSet, emptyContextObject, rootContextSnapshot, emptyTreeContext); | |
| 5376 pingedTasks.push(rootTask); | |
| 5377 return request; | |
| 5378 } | |
| 5379 | |
| 5380 function pingTask(request, task) { | |
| 5381 var pingedTasks = request.pingedTasks; | |
| 5382 pingedTasks.push(task); | |
| 5383 | |
| 5384 if (pingedTasks.length === 1) { | |
| 5385 scheduleWork(function () { | |
| 5386 return performWork(request); | |
| 5387 }); | |
| 5388 } | |
| 5389 } | |
| 5390 | |
| 5391 function createSuspenseBoundary(request, fallbackAbortableTasks) { | |
| 5392 return { | |
| 5393 id: UNINITIALIZED_SUSPENSE_BOUNDARY_ID, | |
| 5394 rootSegmentID: -1, | |
| 5395 parentFlushed: false, | |
| 5396 pendingTasks: 0, | |
| 5397 forceClientRender: false, | |
| 5398 completedSegments: [], | |
| 5399 byteSize: 0, | |
| 5400 fallbackAbortableTasks: fallbackAbortableTasks, | |
| 5401 errorDigest: null | |
| 5402 }; | |
| 5403 } | |
| 5404 | |
| 5405 function createTask(request, node, blockedBoundary, blockedSegment, abortSet, legacyContext, context, treeContext) { | |
| 5406 request.allPendingTasks++; | |
| 5407 | |
| 5408 if (blockedBoundary === null) { | |
| 5409 request.pendingRootTasks++; | |
| 5410 } else { | |
| 5411 blockedBoundary.pendingTasks++; | |
| 5412 } | |
| 5413 | |
| 5414 var task = { | |
| 5415 node: node, | |
| 5416 ping: function () { | |
| 5417 return pingTask(request, task); | |
| 5418 }, | |
| 5419 blockedBoundary: blockedBoundary, | |
| 5420 blockedSegment: blockedSegment, | |
| 5421 abortSet: abortSet, | |
| 5422 legacyContext: legacyContext, | |
| 5423 context: context, | |
| 5424 treeContext: treeContext | |
| 5425 }; | |
| 5426 | |
| 5427 { | |
| 5428 task.componentStack = null; | |
| 5429 } | |
| 5430 | |
| 5431 abortSet.add(task); | |
| 5432 return task; | |
| 5433 } | |
| 5434 | |
| 5435 function createPendingSegment(request, index, boundary, formatContext, lastPushedText, textEmbedded) { | |
| 5436 return { | |
| 5437 status: PENDING, | |
| 5438 id: -1, | |
| 5439 // lazily assigned later | |
| 5440 index: index, | |
| 5441 parentFlushed: false, | |
| 5442 chunks: [], | |
| 5443 children: [], | |
| 5444 formatContext: formatContext, | |
| 5445 boundary: boundary, | |
| 5446 lastPushedText: lastPushedText, | |
| 5447 textEmbedded: textEmbedded | |
| 5448 }; | |
| 5449 } // DEV-only global reference to the currently executing task | |
| 5450 | |
| 5451 | |
| 5452 var currentTaskInDEV = null; | |
| 5453 | |
| 5454 function getCurrentStackInDEV() { | |
| 5455 { | |
| 5456 if (currentTaskInDEV === null || currentTaskInDEV.componentStack === null) { | |
| 5457 return ''; | |
| 5458 } | |
| 5459 | |
| 5460 return getStackByComponentStackNode(currentTaskInDEV.componentStack); | |
| 5461 } | |
| 5462 } | |
| 5463 | |
| 5464 function pushBuiltInComponentStackInDEV(task, type) { | |
| 5465 { | |
| 5466 task.componentStack = { | |
| 5467 tag: 0, | |
| 5468 parent: task.componentStack, | |
| 5469 type: type | |
| 5470 }; | |
| 5471 } | |
| 5472 } | |
| 5473 | |
| 5474 function pushFunctionComponentStackInDEV(task, type) { | |
| 5475 { | |
| 5476 task.componentStack = { | |
| 5477 tag: 1, | |
| 5478 parent: task.componentStack, | |
| 5479 type: type | |
| 5480 }; | |
| 5481 } | |
| 5482 } | |
| 5483 | |
| 5484 function pushClassComponentStackInDEV(task, type) { | |
| 5485 { | |
| 5486 task.componentStack = { | |
| 5487 tag: 2, | |
| 5488 parent: task.componentStack, | |
| 5489 type: type | |
| 5490 }; | |
| 5491 } | |
| 5492 } | |
| 5493 | |
| 5494 function popComponentStackInDEV(task) { | |
| 5495 { | |
| 5496 if (task.componentStack === null) { | |
| 5497 error('Unexpectedly popped too many stack frames. This is a bug in React.'); | |
| 5498 } else { | |
| 5499 task.componentStack = task.componentStack.parent; | |
| 5500 } | |
| 5501 } | |
| 5502 } // stash the component stack of an unwinding error until it is processed | |
| 5503 | |
| 5504 | |
| 5505 var lastBoundaryErrorComponentStackDev = null; | |
| 5506 | |
| 5507 function captureBoundaryErrorDetailsDev(boundary, error) { | |
| 5508 { | |
| 5509 var errorMessage; | |
| 5510 | |
| 5511 if (typeof error === 'string') { | |
| 5512 errorMessage = error; | |
| 5513 } else if (error && typeof error.message === 'string') { | |
| 5514 errorMessage = error.message; | |
| 5515 } else { | |
| 5516 // eslint-disable-next-line react-internal/safe-string-coercion | |
| 5517 errorMessage = String(error); | |
| 5518 } | |
| 5519 | |
| 5520 var errorComponentStack = lastBoundaryErrorComponentStackDev || getCurrentStackInDEV(); | |
| 5521 lastBoundaryErrorComponentStackDev = null; | |
| 5522 boundary.errorMessage = errorMessage; | |
| 5523 boundary.errorComponentStack = errorComponentStack; | |
| 5524 } | |
| 5525 } | |
| 5526 | |
| 5527 function logRecoverableError(request, error) { | |
| 5528 // If this callback errors, we intentionally let that error bubble up to become a fatal error | |
| 5529 // so that someone fixes the error reporting instead of hiding it. | |
| 5530 var errorDigest = request.onError(error); | |
| 5531 | |
| 5532 if (errorDigest != null && typeof errorDigest !== 'string') { | |
| 5533 // eslint-disable-next-line react-internal/prod-error-codes | |
| 5534 throw new Error("onError returned something with a type other than \"string\". onError should return a string and may return null or undefined but must not return anything else. It received something of type \"" + typeof errorDigest + "\" instead"); | |
| 5535 } | |
| 5536 | |
| 5537 return errorDigest; | |
| 5538 } | |
| 5539 | |
| 5540 function fatalError(request, error) { | |
| 5541 // This is called outside error handling code such as if the root errors outside | |
| 5542 // a suspense boundary or if the root suspense boundary's fallback errors. | |
| 5543 // It's also called if React itself or its host configs errors. | |
| 5544 var onShellError = request.onShellError; | |
| 5545 onShellError(error); | |
| 5546 var onFatalError = request.onFatalError; | |
| 5547 onFatalError(error); | |
| 5548 | |
| 5549 if (request.destination !== null) { | |
| 5550 request.status = CLOSED; | |
| 5551 closeWithError(request.destination, error); | |
| 5552 } else { | |
| 5553 request.status = CLOSING; | |
| 5554 request.fatalError = error; | |
| 5555 } | |
| 5556 } | |
| 5557 | |
| 5558 function renderSuspenseBoundary(request, task, props) { | |
| 5559 pushBuiltInComponentStackInDEV(task, 'Suspense'); | |
| 5560 var parentBoundary = task.blockedBoundary; | |
| 5561 var parentSegment = task.blockedSegment; // Each time we enter a suspense boundary, we split out into a new segment for | |
| 5562 // the fallback so that we can later replace that segment with the content. | |
| 5563 // This also lets us split out the main content even if it doesn't suspend, | |
| 5564 // in case it ends up generating a large subtree of content. | |
| 5565 | |
| 5566 var fallback = props.fallback; | |
| 5567 var content = props.children; | |
| 5568 var fallbackAbortSet = new Set(); | |
| 5569 var newBoundary = createSuspenseBoundary(request, fallbackAbortSet); | |
| 5570 var insertionIndex = parentSegment.chunks.length; // The children of the boundary segment is actually the fallback. | |
| 5571 | |
| 5572 var boundarySegment = createPendingSegment(request, insertionIndex, newBoundary, parentSegment.formatContext, // boundaries never require text embedding at their edges because comment nodes bound them | |
| 5573 false, false); | |
| 5574 parentSegment.children.push(boundarySegment); // The parentSegment has a child Segment at this index so we reset the lastPushedText marker on the parent | |
| 5575 | |
| 5576 parentSegment.lastPushedText = false; // This segment is the actual child content. We can start rendering that immediately. | |
| 5577 | |
| 5578 var contentRootSegment = createPendingSegment(request, 0, null, parentSegment.formatContext, // boundaries never require text embedding at their edges because comment nodes bound them | |
| 5579 false, false); // We mark the root segment as having its parent flushed. It's not really flushed but there is | |
| 5580 // no parent segment so there's nothing to wait on. | |
| 5581 | |
| 5582 contentRootSegment.parentFlushed = true; // Currently this is running synchronously. We could instead schedule this to pingedTasks. | |
| 5583 // I suspect that there might be some efficiency benefits from not creating the suspended task | |
| 5584 // and instead just using the stack if possible. | |
| 5585 // TODO: Call this directly instead of messing with saving and restoring contexts. | |
| 5586 // We can reuse the current context and task to render the content immediately without | |
| 5587 // context switching. We just need to temporarily switch which boundary and which segment | |
| 5588 // we're writing to. If something suspends, it'll spawn new suspended task with that context. | |
| 5589 | |
| 5590 task.blockedBoundary = newBoundary; | |
| 5591 task.blockedSegment = contentRootSegment; | |
| 5592 | |
| 5593 try { | |
| 5594 // We use the safe form because we don't handle suspending here. Only error handling. | |
| 5595 renderNode(request, task, content); | |
| 5596 pushSegmentFinale$1(contentRootSegment.chunks, request.responseState, contentRootSegment.lastPushedText, contentRootSegment.textEmbedded); | |
| 5597 contentRootSegment.status = COMPLETED; | |
| 5598 queueCompletedSegment(newBoundary, contentRootSegment); | |
| 5599 | |
| 5600 if (newBoundary.pendingTasks === 0) { | |
| 5601 // This must have been the last segment we were waiting on. This boundary is now complete. | |
| 5602 // Therefore we won't need the fallback. We early return so that we don't have to create | |
| 5603 // the fallback. | |
| 5604 popComponentStackInDEV(task); | |
| 5605 return; | |
| 5606 } | |
| 5607 } catch (error) { | |
| 5608 contentRootSegment.status = ERRORED; | |
| 5609 newBoundary.forceClientRender = true; | |
| 5610 newBoundary.errorDigest = logRecoverableError(request, error); | |
| 5611 | |
| 5612 { | |
| 5613 captureBoundaryErrorDetailsDev(newBoundary, error); | |
| 5614 } // We don't need to decrement any task numbers because we didn't spawn any new task. | |
| 5615 // We don't need to schedule any task because we know the parent has written yet. | |
| 5616 // We do need to fallthrough to create the fallback though. | |
| 5617 | |
| 5618 } finally { | |
| 5619 task.blockedBoundary = parentBoundary; | |
| 5620 task.blockedSegment = parentSegment; | |
| 5621 } // We create suspended task for the fallback because we don't want to actually work | |
| 5622 // on it yet in case we finish the main content, so we queue for later. | |
| 5623 | |
| 5624 | |
| 5625 var suspendedFallbackTask = createTask(request, fallback, parentBoundary, boundarySegment, fallbackAbortSet, task.legacyContext, task.context, task.treeContext); | |
| 5626 | |
| 5627 { | |
| 5628 suspendedFallbackTask.componentStack = task.componentStack; | |
| 5629 } // TODO: This should be queued at a separate lower priority queue so that we only work | |
| 5630 // on preparing fallbacks if we don't have any more main content to task on. | |
| 5631 | |
| 5632 | |
| 5633 request.pingedTasks.push(suspendedFallbackTask); | |
| 5634 popComponentStackInDEV(task); | |
| 5635 } | |
| 5636 | |
| 5637 function renderHostElement(request, task, type, props) { | |
| 5638 pushBuiltInComponentStackInDEV(task, type); | |
| 5639 var segment = task.blockedSegment; | |
| 5640 var children = pushStartInstance(segment.chunks, type, props, request.responseState, segment.formatContext); | |
| 5641 segment.lastPushedText = false; | |
| 5642 var prevContext = segment.formatContext; | |
| 5643 segment.formatContext = getChildFormatContext(prevContext, type, props); // We use the non-destructive form because if something suspends, we still | |
| 5644 // need to pop back up and finish this subtree of HTML. | |
| 5645 | |
| 5646 renderNode(request, task, children); // We expect that errors will fatal the whole task and that we don't need | |
| 5647 // the correct context. Therefore this is not in a finally. | |
| 5648 | |
| 5649 segment.formatContext = prevContext; | |
| 5650 pushEndInstance(segment.chunks, type); | |
| 5651 segment.lastPushedText = false; | |
| 5652 popComponentStackInDEV(task); | |
| 5653 } | |
| 5654 | |
| 5655 function shouldConstruct$1(Component) { | |
| 5656 return Component.prototype && Component.prototype.isReactComponent; | |
| 5657 } | |
| 5658 | |
| 5659 function renderWithHooks(request, task, Component, props, secondArg) { | |
| 5660 var componentIdentity = {}; | |
| 5661 prepareToUseHooks(task, componentIdentity); | |
| 5662 var result = Component(props, secondArg); | |
| 5663 return finishHooks(Component, props, result, secondArg); | |
| 5664 } | |
| 5665 | |
| 5666 function finishClassComponent(request, task, instance, Component, props) { | |
| 5667 var nextChildren = instance.render(); | |
| 5668 | |
| 5669 { | |
| 5670 if (instance.props !== props) { | |
| 5671 if (!didWarnAboutReassigningProps) { | |
| 5672 error('It looks like %s is reassigning its own `this.props` while rendering. ' + 'This is not supported and can lead to confusing bugs.', getComponentNameFromType(Component) || 'a component'); | |
| 5673 } | |
| 5674 | |
| 5675 didWarnAboutReassigningProps = true; | |
| 5676 } | |
| 5677 } | |
| 5678 | |
| 5679 { | |
| 5680 var childContextTypes = Component.childContextTypes; | |
| 5681 | |
| 5682 if (childContextTypes !== null && childContextTypes !== undefined) { | |
| 5683 var previousContext = task.legacyContext; | |
| 5684 var mergedContext = processChildContext(instance, Component, previousContext, childContextTypes); | |
| 5685 task.legacyContext = mergedContext; | |
| 5686 renderNodeDestructive(request, task, nextChildren); | |
| 5687 task.legacyContext = previousContext; | |
| 5688 return; | |
| 5689 } | |
| 5690 } | |
| 5691 | |
| 5692 renderNodeDestructive(request, task, nextChildren); | |
| 5693 } | |
| 5694 | |
| 5695 function renderClassComponent(request, task, Component, props) { | |
| 5696 pushClassComponentStackInDEV(task, Component); | |
| 5697 var maskedContext = getMaskedContext(Component, task.legacyContext) ; | |
| 5698 var instance = constructClassInstance(Component, props, maskedContext); | |
| 5699 mountClassInstance(instance, Component, props, maskedContext); | |
| 5700 finishClassComponent(request, task, instance, Component, props); | |
| 5701 popComponentStackInDEV(task); | |
| 5702 } | |
| 5703 | |
| 5704 var didWarnAboutBadClass = {}; | |
| 5705 var didWarnAboutModulePatternComponent = {}; | |
| 5706 var didWarnAboutContextTypeOnFunctionComponent = {}; | |
| 5707 var didWarnAboutGetDerivedStateOnFunctionComponent = {}; | |
| 5708 var didWarnAboutReassigningProps = false; | |
| 5709 var didWarnAboutDefaultPropsOnFunctionComponent = {}; | |
| 5710 var didWarnAboutGenerators = false; | |
| 5711 var didWarnAboutMaps = false; | |
| 5712 var hasWarnedAboutUsingContextAsConsumer = false; // This would typically be a function component but we still support module pattern | |
| 5713 // components for some reason. | |
| 5714 | |
| 5715 function renderIndeterminateComponent(request, task, Component, props) { | |
| 5716 var legacyContext; | |
| 5717 | |
| 5718 { | |
| 5719 legacyContext = getMaskedContext(Component, task.legacyContext); | |
| 5720 } | |
| 5721 | |
| 5722 pushFunctionComponentStackInDEV(task, Component); | |
| 5723 | |
| 5724 { | |
| 5725 if (Component.prototype && typeof Component.prototype.render === 'function') { | |
| 5726 var componentName = getComponentNameFromType(Component) || 'Unknown'; | |
| 5727 | |
| 5728 if (!didWarnAboutBadClass[componentName]) { | |
| 5729 error("The <%s /> component appears to have a render method, but doesn't extend React.Component. " + 'This is likely to cause errors. Change %s to extend React.Component instead.', componentName, componentName); | |
| 5730 | |
| 5731 didWarnAboutBadClass[componentName] = true; | |
| 5732 } | |
| 5733 } | |
| 5734 } | |
| 5735 | |
| 5736 var value = renderWithHooks(request, task, Component, props, legacyContext); | |
| 5737 var hasId = checkDidRenderIdHook(); | |
| 5738 | |
| 5739 { | |
| 5740 // Support for module components is deprecated and is removed behind a flag. | |
| 5741 // Whether or not it would crash later, we want to show a good message in DEV first. | |
| 5742 if (typeof value === 'object' && value !== null && typeof value.render === 'function' && value.$$typeof === undefined) { | |
| 5743 var _componentName = getComponentNameFromType(Component) || 'Unknown'; | |
| 5744 | |
| 5745 if (!didWarnAboutModulePatternComponent[_componentName]) { | |
| 5746 error('The <%s /> component appears to be a function component that returns a class instance. ' + 'Change %s to a class that extends React.Component instead. ' + "If you can't use a class try assigning the prototype on the function as a workaround. " + "`%s.prototype = React.Component.prototype`. Don't use an arrow function since it " + 'cannot be called with `new` by React.', _componentName, _componentName, _componentName); | |
| 5747 | |
| 5748 didWarnAboutModulePatternComponent[_componentName] = true; | |
| 5749 } | |
| 5750 } | |
| 5751 } | |
| 5752 | |
| 5753 if ( // Run these checks in production only if the flag is off. | |
| 5754 // Eventually we'll delete this branch altogether. | |
| 5755 typeof value === 'object' && value !== null && typeof value.render === 'function' && value.$$typeof === undefined) { | |
| 5756 { | |
| 5757 var _componentName2 = getComponentNameFromType(Component) || 'Unknown'; | |
| 5758 | |
| 5759 if (!didWarnAboutModulePatternComponent[_componentName2]) { | |
| 5760 error('The <%s /> component appears to be a function component that returns a class instance. ' + 'Change %s to a class that extends React.Component instead. ' + "If you can't use a class try assigning the prototype on the function as a workaround. " + "`%s.prototype = React.Component.prototype`. Don't use an arrow function since it " + 'cannot be called with `new` by React.', _componentName2, _componentName2, _componentName2); | |
| 5761 | |
| 5762 didWarnAboutModulePatternComponent[_componentName2] = true; | |
| 5763 } | |
| 5764 } | |
| 5765 | |
| 5766 mountClassInstance(value, Component, props, legacyContext); | |
| 5767 finishClassComponent(request, task, value, Component, props); | |
| 5768 } else { | |
| 5769 | |
| 5770 { | |
| 5771 validateFunctionComponentInDev(Component); | |
| 5772 } // We're now successfully past this task, and we don't have to pop back to | |
| 5773 // the previous task every again, so we can use the destructive recursive form. | |
| 5774 | |
| 5775 | |
| 5776 if (hasId) { | |
| 5777 // This component materialized an id. We treat this as its own level, with | |
| 5778 // a single "child" slot. | |
| 5779 var prevTreeContext = task.treeContext; | |
| 5780 var totalChildren = 1; | |
| 5781 var index = 0; | |
| 5782 task.treeContext = pushTreeContext(prevTreeContext, totalChildren, index); | |
| 5783 | |
| 5784 try { | |
| 5785 renderNodeDestructive(request, task, value); | |
| 5786 } finally { | |
| 5787 task.treeContext = prevTreeContext; | |
| 5788 } | |
| 5789 } else { | |
| 5790 renderNodeDestructive(request, task, value); | |
| 5791 } | |
| 5792 } | |
| 5793 | |
| 5794 popComponentStackInDEV(task); | |
| 5795 } | |
| 5796 | |
| 5797 function validateFunctionComponentInDev(Component) { | |
| 5798 { | |
| 5799 if (Component) { | |
| 5800 if (Component.childContextTypes) { | |
| 5801 error('%s(...): childContextTypes cannot be defined on a function component.', Component.displayName || Component.name || 'Component'); | |
| 5802 } | |
| 5803 } | |
| 5804 | |
| 5805 if ( Component.defaultProps !== undefined) { | |
| 5806 var componentName = getComponentNameFromType(Component) || 'Unknown'; | |
| 5807 | |
| 5808 if (!didWarnAboutDefaultPropsOnFunctionComponent[componentName]) { | |
| 5809 error('%s: Support for defaultProps will be removed from function components ' + 'in a future major release. Use JavaScript default parameters instead.', componentName); | |
| 5810 | |
| 5811 didWarnAboutDefaultPropsOnFunctionComponent[componentName] = true; | |
| 5812 } | |
| 5813 } | |
| 5814 | |
| 5815 if (typeof Component.getDerivedStateFromProps === 'function') { | |
| 5816 var _componentName3 = getComponentNameFromType(Component) || 'Unknown'; | |
| 5817 | |
| 5818 if (!didWarnAboutGetDerivedStateOnFunctionComponent[_componentName3]) { | |
| 5819 error('%s: Function components do not support getDerivedStateFromProps.', _componentName3); | |
| 5820 | |
| 5821 didWarnAboutGetDerivedStateOnFunctionComponent[_componentName3] = true; | |
| 5822 } | |
| 5823 } | |
| 5824 | |
| 5825 if (typeof Component.contextType === 'object' && Component.contextType !== null) { | |
| 5826 var _componentName4 = getComponentNameFromType(Component) || 'Unknown'; | |
| 5827 | |
| 5828 if (!didWarnAboutContextTypeOnFunctionComponent[_componentName4]) { | |
| 5829 error('%s: Function components do not support contextType.', _componentName4); | |
| 5830 | |
| 5831 didWarnAboutContextTypeOnFunctionComponent[_componentName4] = true; | |
| 5832 } | |
| 5833 } | |
| 5834 } | |
| 5835 } | |
| 5836 | |
| 5837 function resolveDefaultProps(Component, baseProps) { | |
| 5838 if (Component && Component.defaultProps) { | |
| 5839 // Resolve default props. Taken from ReactElement | |
| 5840 var props = assign({}, baseProps); | |
| 5841 var defaultProps = Component.defaultProps; | |
| 5842 | |
| 5843 for (var propName in defaultProps) { | |
| 5844 if (props[propName] === undefined) { | |
| 5845 props[propName] = defaultProps[propName]; | |
| 5846 } | |
| 5847 } | |
| 5848 | |
| 5849 return props; | |
| 5850 } | |
| 5851 | |
| 5852 return baseProps; | |
| 5853 } | |
| 5854 | |
| 5855 function renderForwardRef(request, task, type, props, ref) { | |
| 5856 pushFunctionComponentStackInDEV(task, type.render); | |
| 5857 var children = renderWithHooks(request, task, type.render, props, ref); | |
| 5858 var hasId = checkDidRenderIdHook(); | |
| 5859 | |
| 5860 if (hasId) { | |
| 5861 // This component materialized an id. We treat this as its own level, with | |
| 5862 // a single "child" slot. | |
| 5863 var prevTreeContext = task.treeContext; | |
| 5864 var totalChildren = 1; | |
| 5865 var index = 0; | |
| 5866 task.treeContext = pushTreeContext(prevTreeContext, totalChildren, index); | |
| 5867 | |
| 5868 try { | |
| 5869 renderNodeDestructive(request, task, children); | |
| 5870 } finally { | |
| 5871 task.treeContext = prevTreeContext; | |
| 5872 } | |
| 5873 } else { | |
| 5874 renderNodeDestructive(request, task, children); | |
| 5875 } | |
| 5876 | |
| 5877 popComponentStackInDEV(task); | |
| 5878 } | |
| 5879 | |
| 5880 function renderMemo(request, task, type, props, ref) { | |
| 5881 var innerType = type.type; | |
| 5882 var resolvedProps = resolveDefaultProps(innerType, props); | |
| 5883 renderElement(request, task, innerType, resolvedProps, ref); | |
| 5884 } | |
| 5885 | |
| 5886 function renderContextConsumer(request, task, context, props) { | |
| 5887 // The logic below for Context differs depending on PROD or DEV mode. In | |
| 5888 // DEV mode, we create a separate object for Context.Consumer that acts | |
| 5889 // like a proxy to Context. This proxy object adds unnecessary code in PROD | |
| 5890 // so we use the old behaviour (Context.Consumer references Context) to | |
| 5891 // reduce size and overhead. The separate object references context via | |
| 5892 // a property called "_context", which also gives us the ability to check | |
| 5893 // in DEV mode if this property exists or not and warn if it does not. | |
| 5894 { | |
| 5895 if (context._context === undefined) { | |
| 5896 // This may be because it's a Context (rather than a Consumer). | |
| 5897 // Or it may be because it's older React where they're the same thing. | |
| 5898 // We only want to warn if we're sure it's a new React. | |
| 5899 if (context !== context.Consumer) { | |
| 5900 if (!hasWarnedAboutUsingContextAsConsumer) { | |
| 5901 hasWarnedAboutUsingContextAsConsumer = true; | |
| 5902 | |
| 5903 error('Rendering <Context> directly is not supported and will be removed in ' + 'a future major release. Did you mean to render <Context.Consumer> instead?'); | |
| 5904 } | |
| 5905 } | |
| 5906 } else { | |
| 5907 context = context._context; | |
| 5908 } | |
| 5909 } | |
| 5910 | |
| 5911 var render = props.children; | |
| 5912 | |
| 5913 { | |
| 5914 if (typeof render !== 'function') { | |
| 5915 error('A context consumer was rendered with multiple children, or a child ' + "that isn't a function. A context consumer expects a single child " + 'that is a function. If you did pass a function, make sure there ' + 'is no trailing or leading whitespace around it.'); | |
| 5916 } | |
| 5917 } | |
| 5918 | |
| 5919 var newValue = readContext(context); | |
| 5920 var newChildren = render(newValue); | |
| 5921 renderNodeDestructive(request, task, newChildren); | |
| 5922 } | |
| 5923 | |
| 5924 function renderContextProvider(request, task, type, props) { | |
| 5925 var context = type._context; | |
| 5926 var value = props.value; | |
| 5927 var children = props.children; | |
| 5928 var prevSnapshot; | |
| 5929 | |
| 5930 { | |
| 5931 prevSnapshot = task.context; | |
| 5932 } | |
| 5933 | |
| 5934 task.context = pushProvider(context, value); | |
| 5935 renderNodeDestructive(request, task, children); | |
| 5936 task.context = popProvider(context); | |
| 5937 | |
| 5938 { | |
| 5939 if (prevSnapshot !== task.context) { | |
| 5940 error('Popping the context provider did not return back to the original snapshot. This is a bug in React.'); | |
| 5941 } | |
| 5942 } | |
| 5943 } | |
| 5944 | |
| 5945 function renderLazyComponent(request, task, lazyComponent, props, ref) { | |
| 5946 pushBuiltInComponentStackInDEV(task, 'Lazy'); | |
| 5947 var payload = lazyComponent._payload; | |
| 5948 var init = lazyComponent._init; | |
| 5949 var Component = init(payload); | |
| 5950 var resolvedProps = resolveDefaultProps(Component, props); | |
| 5951 renderElement(request, task, Component, resolvedProps, ref); | |
| 5952 popComponentStackInDEV(task); | |
| 5953 } | |
| 5954 | |
| 5955 function renderElement(request, task, type, props, ref) { | |
| 5956 if (typeof type === 'function') { | |
| 5957 if (shouldConstruct$1(type)) { | |
| 5958 renderClassComponent(request, task, type, props); | |
| 5959 return; | |
| 5960 } else { | |
| 5961 renderIndeterminateComponent(request, task, type, props); | |
| 5962 return; | |
| 5963 } | |
| 5964 } | |
| 5965 | |
| 5966 if (typeof type === 'string') { | |
| 5967 renderHostElement(request, task, type, props); | |
| 5968 return; | |
| 5969 } | |
| 5970 | |
| 5971 switch (type) { | |
| 5972 // TODO: LegacyHidden acts the same as a fragment. This only works | |
| 5973 // because we currently assume that every instance of LegacyHidden is | |
| 5974 // accompanied by a host component wrapper. In the hidden mode, the host | |
| 5975 // component is given a `hidden` attribute, which ensures that the | |
| 5976 // initial HTML is not visible. To support the use of LegacyHidden as a | |
| 5977 // true fragment, without an extra DOM node, we would have to hide the | |
| 5978 // initial HTML in some other way. | |
| 5979 // TODO: Add REACT_OFFSCREEN_TYPE here too with the same capability. | |
| 5980 case REACT_LEGACY_HIDDEN_TYPE: | |
| 5981 case REACT_DEBUG_TRACING_MODE_TYPE: | |
| 5982 case REACT_STRICT_MODE_TYPE: | |
| 5983 case REACT_PROFILER_TYPE: | |
| 5984 case REACT_FRAGMENT_TYPE: | |
| 5985 { | |
| 5986 renderNodeDestructive(request, task, props.children); | |
| 5987 return; | |
| 5988 } | |
| 5989 | |
| 5990 case REACT_SUSPENSE_LIST_TYPE: | |
| 5991 { | |
| 5992 pushBuiltInComponentStackInDEV(task, 'SuspenseList'); // TODO: SuspenseList should control the boundaries. | |
| 5993 | |
| 5994 renderNodeDestructive(request, task, props.children); | |
| 5995 popComponentStackInDEV(task); | |
| 5996 return; | |
| 5997 } | |
| 5998 | |
| 5999 case REACT_SCOPE_TYPE: | |
| 6000 { | |
| 6001 | |
| 6002 throw new Error('ReactDOMServer does not yet support scope components.'); | |
| 6003 } | |
| 6004 // eslint-disable-next-line-no-fallthrough | |
| 6005 | |
| 6006 case REACT_SUSPENSE_TYPE: | |
| 6007 { | |
| 6008 { | |
| 6009 renderSuspenseBoundary(request, task, props); | |
| 6010 } | |
| 6011 | |
| 6012 return; | |
| 6013 } | |
| 6014 } | |
| 6015 | |
| 6016 if (typeof type === 'object' && type !== null) { | |
| 6017 switch (type.$$typeof) { | |
| 6018 case REACT_FORWARD_REF_TYPE: | |
| 6019 { | |
| 6020 renderForwardRef(request, task, type, props, ref); | |
| 6021 return; | |
| 6022 } | |
| 6023 | |
| 6024 case REACT_MEMO_TYPE: | |
| 6025 { | |
| 6026 renderMemo(request, task, type, props, ref); | |
| 6027 return; | |
| 6028 } | |
| 6029 | |
| 6030 case REACT_PROVIDER_TYPE: | |
| 6031 { | |
| 6032 renderContextProvider(request, task, type, props); | |
| 6033 return; | |
| 6034 } | |
| 6035 | |
| 6036 case REACT_CONTEXT_TYPE: | |
| 6037 { | |
| 6038 renderContextConsumer(request, task, type, props); | |
| 6039 return; | |
| 6040 } | |
| 6041 | |
| 6042 case REACT_LAZY_TYPE: | |
| 6043 { | |
| 6044 renderLazyComponent(request, task, type, props); | |
| 6045 return; | |
| 6046 } | |
| 6047 } | |
| 6048 } | |
| 6049 | |
| 6050 var info = ''; | |
| 6051 | |
| 6052 { | |
| 6053 if (type === undefined || typeof type === 'object' && type !== null && Object.keys(type).length === 0) { | |
| 6054 info += ' You likely forgot to export your component from the file ' + "it's defined in, or you might have mixed up default and " + 'named imports.'; | |
| 6055 } | |
| 6056 } | |
| 6057 | |
| 6058 throw new Error('Element type is invalid: expected a string (for built-in ' + 'components) or a class/function (for composite components) ' + ("but got: " + (type == null ? type : typeof type) + "." + info)); | |
| 6059 } | |
| 6060 | |
| 6061 function validateIterable(iterable, iteratorFn) { | |
| 6062 { | |
| 6063 // We don't support rendering Generators because it's a mutation. | |
| 6064 // See https://github.com/facebook/react/issues/12995 | |
| 6065 if (typeof Symbol === 'function' && // $FlowFixMe Flow doesn't know about toStringTag | |
| 6066 iterable[Symbol.toStringTag] === 'Generator') { | |
| 6067 if (!didWarnAboutGenerators) { | |
| 6068 error('Using Generators as children is unsupported and will likely yield ' + 'unexpected results because enumerating a generator mutates it. ' + 'You may convert it to an array with `Array.from()` or the ' + '`[...spread]` operator before rendering. Keep in mind ' + 'you might need to polyfill these features for older browsers.'); | |
| 6069 } | |
| 6070 | |
| 6071 didWarnAboutGenerators = true; | |
| 6072 } // Warn about using Maps as children | |
| 6073 | |
| 6074 | |
| 6075 if (iterable.entries === iteratorFn) { | |
| 6076 if (!didWarnAboutMaps) { | |
| 6077 error('Using Maps as children is not supported. ' + 'Use an array of keyed ReactElements instead.'); | |
| 6078 } | |
| 6079 | |
| 6080 didWarnAboutMaps = true; | |
| 6081 } | |
| 6082 } | |
| 6083 } | |
| 6084 | |
| 6085 function renderNodeDestructive(request, task, node) { | |
| 6086 { | |
| 6087 // In Dev we wrap renderNodeDestructiveImpl in a try / catch so we can capture | |
| 6088 // a component stack at the right place in the tree. We don't do this in renderNode | |
| 6089 // becuase it is not called at every layer of the tree and we may lose frames | |
| 6090 try { | |
| 6091 return renderNodeDestructiveImpl(request, task, node); | |
| 6092 } catch (x) { | |
| 6093 if (typeof x === 'object' && x !== null && typeof x.then === 'function') ; else { | |
| 6094 // This is an error, stash the component stack if it is null. | |
| 6095 lastBoundaryErrorComponentStackDev = lastBoundaryErrorComponentStackDev !== null ? lastBoundaryErrorComponentStackDev : getCurrentStackInDEV(); | |
| 6096 } // rethrow so normal suspense logic can handle thrown value accordingly | |
| 6097 | |
| 6098 | |
| 6099 throw x; | |
| 6100 } | |
| 6101 } | |
| 6102 } // This function by it self renders a node and consumes the task by mutating it | |
| 6103 // to update the current execution state. | |
| 6104 | |
| 6105 | |
| 6106 function renderNodeDestructiveImpl(request, task, node) { | |
| 6107 // Stash the node we're working on. We'll pick up from this task in case | |
| 6108 // something suspends. | |
| 6109 task.node = node; // Handle object types | |
| 6110 | |
| 6111 if (typeof node === 'object' && node !== null) { | |
| 6112 switch (node.$$typeof) { | |
| 6113 case REACT_ELEMENT_TYPE: | |
| 6114 { | |
| 6115 var element = node; | |
| 6116 var type = element.type; | |
| 6117 var props = element.props; | |
| 6118 var ref = element.ref; | |
| 6119 renderElement(request, task, type, props, ref); | |
| 6120 return; | |
| 6121 } | |
| 6122 | |
| 6123 case REACT_PORTAL_TYPE: | |
| 6124 throw new Error('Portals are not currently supported by the server renderer. ' + 'Render them conditionally so that they only appear on the client render.'); | |
| 6125 // eslint-disable-next-line-no-fallthrough | |
| 6126 | |
| 6127 case REACT_LAZY_TYPE: | |
| 6128 { | |
| 6129 var lazyNode = node; | |
| 6130 var payload = lazyNode._payload; | |
| 6131 var init = lazyNode._init; | |
| 6132 var resolvedNode; | |
| 6133 | |
| 6134 { | |
| 6135 try { | |
| 6136 resolvedNode = init(payload); | |
| 6137 } catch (x) { | |
| 6138 if (typeof x === 'object' && x !== null && typeof x.then === 'function') { | |
| 6139 // this Lazy initializer is suspending. push a temporary frame onto the stack so it can be | |
| 6140 // popped off in spawnNewSuspendedTask. This aligns stack behavior between Lazy in element position | |
| 6141 // vs Component position. We do not want the frame for Errors so we exclusively do this in | |
| 6142 // the wakeable branch | |
| 6143 pushBuiltInComponentStackInDEV(task, 'Lazy'); | |
| 6144 } | |
| 6145 | |
| 6146 throw x; | |
| 6147 } | |
| 6148 } | |
| 6149 | |
| 6150 renderNodeDestructive(request, task, resolvedNode); | |
| 6151 return; | |
| 6152 } | |
| 6153 } | |
| 6154 | |
| 6155 if (isArray(node)) { | |
| 6156 renderChildrenArray(request, task, node); | |
| 6157 return; | |
| 6158 } | |
| 6159 | |
| 6160 var iteratorFn = getIteratorFn(node); | |
| 6161 | |
| 6162 if (iteratorFn) { | |
| 6163 { | |
| 6164 validateIterable(node, iteratorFn); | |
| 6165 } | |
| 6166 | |
| 6167 var iterator = iteratorFn.call(node); | |
| 6168 | |
| 6169 if (iterator) { | |
| 6170 // We need to know how many total children are in this set, so that we | |
| 6171 // can allocate enough id slots to acommodate them. So we must exhaust | |
| 6172 // the iterator before we start recursively rendering the children. | |
| 6173 // TODO: This is not great but I think it's inherent to the id | |
| 6174 // generation algorithm. | |
| 6175 var step = iterator.next(); // If there are not entries, we need to push an empty so we start by checking that. | |
| 6176 | |
| 6177 if (!step.done) { | |
| 6178 var children = []; | |
| 6179 | |
| 6180 do { | |
| 6181 children.push(step.value); | |
| 6182 step = iterator.next(); | |
| 6183 } while (!step.done); | |
| 6184 | |
| 6185 renderChildrenArray(request, task, children); | |
| 6186 return; | |
| 6187 } | |
| 6188 | |
| 6189 return; | |
| 6190 } | |
| 6191 } | |
| 6192 | |
| 6193 var childString = Object.prototype.toString.call(node); | |
| 6194 throw new Error("Objects are not valid as a React child (found: " + (childString === '[object Object]' ? 'object with keys {' + Object.keys(node).join(', ') + '}' : childString) + "). " + 'If you meant to render a collection of children, use an array ' + 'instead.'); | |
| 6195 } | |
| 6196 | |
| 6197 if (typeof node === 'string') { | |
| 6198 var segment = task.blockedSegment; | |
| 6199 segment.lastPushedText = pushTextInstance$1(task.blockedSegment.chunks, node, request.responseState, segment.lastPushedText); | |
| 6200 return; | |
| 6201 } | |
| 6202 | |
| 6203 if (typeof node === 'number') { | |
| 6204 var _segment = task.blockedSegment; | |
| 6205 _segment.lastPushedText = pushTextInstance$1(task.blockedSegment.chunks, '' + node, request.responseState, _segment.lastPushedText); | |
| 6206 return; | |
| 6207 } | |
| 6208 | |
| 6209 { | |
| 6210 if (typeof node === 'function') { | |
| 6211 error('Functions are not valid as a React child. This may happen if ' + 'you return a Component instead of <Component /> from render. ' + 'Or maybe you meant to call this function rather than return it.'); | |
| 6212 } | |
| 6213 } | |
| 6214 } | |
| 6215 | |
| 6216 function renderChildrenArray(request, task, children) { | |
| 6217 var totalChildren = children.length; | |
| 6218 | |
| 6219 for (var i = 0; i < totalChildren; i++) { | |
| 6220 var prevTreeContext = task.treeContext; | |
| 6221 task.treeContext = pushTreeContext(prevTreeContext, totalChildren, i); | |
| 6222 | |
| 6223 try { | |
| 6224 // We need to use the non-destructive form so that we can safely pop back | |
| 6225 // up and render the sibling if something suspends. | |
| 6226 renderNode(request, task, children[i]); | |
| 6227 } finally { | |
| 6228 task.treeContext = prevTreeContext; | |
| 6229 } | |
| 6230 } | |
| 6231 } | |
| 6232 | |
| 6233 function spawnNewSuspendedTask(request, task, x) { | |
| 6234 // Something suspended, we'll need to create a new segment and resolve it later. | |
| 6235 var segment = task.blockedSegment; | |
| 6236 var insertionIndex = segment.chunks.length; | |
| 6237 var newSegment = createPendingSegment(request, insertionIndex, null, segment.formatContext, // Adopt the parent segment's leading text embed | |
| 6238 segment.lastPushedText, // Assume we are text embedded at the trailing edge | |
| 6239 true); | |
| 6240 segment.children.push(newSegment); // Reset lastPushedText for current Segment since the new Segment "consumed" it | |
| 6241 | |
| 6242 segment.lastPushedText = false; | |
| 6243 var newTask = createTask(request, task.node, task.blockedBoundary, newSegment, task.abortSet, task.legacyContext, task.context, task.treeContext); | |
| 6244 | |
| 6245 { | |
| 6246 if (task.componentStack !== null) { | |
| 6247 // We pop one task off the stack because the node that suspended will be tried again, | |
| 6248 // which will add it back onto the stack. | |
| 6249 newTask.componentStack = task.componentStack.parent; | |
| 6250 } | |
| 6251 } | |
| 6252 | |
| 6253 var ping = newTask.ping; | |
| 6254 x.then(ping, ping); | |
| 6255 } // This is a non-destructive form of rendering a node. If it suspends it spawns | |
| 6256 // a new task and restores the context of this task to what it was before. | |
| 6257 | |
| 6258 | |
| 6259 function renderNode(request, task, node) { | |
| 6260 // TODO: Store segment.children.length here and reset it in case something | |
| 6261 // suspended partially through writing something. | |
| 6262 // Snapshot the current context in case something throws to interrupt the | |
| 6263 // process. | |
| 6264 var previousFormatContext = task.blockedSegment.formatContext; | |
| 6265 var previousLegacyContext = task.legacyContext; | |
| 6266 var previousContext = task.context; | |
| 6267 var previousComponentStack = null; | |
| 6268 | |
| 6269 { | |
| 6270 previousComponentStack = task.componentStack; | |
| 6271 } | |
| 6272 | |
| 6273 try { | |
| 6274 return renderNodeDestructive(request, task, node); | |
| 6275 } catch (x) { | |
| 6276 resetHooksState(); | |
| 6277 | |
| 6278 if (typeof x === 'object' && x !== null && typeof x.then === 'function') { | |
| 6279 spawnNewSuspendedTask(request, task, x); // Restore the context. We assume that this will be restored by the inner | |
| 6280 // functions in case nothing throws so we don't use "finally" here. | |
| 6281 | |
| 6282 task.blockedSegment.formatContext = previousFormatContext; | |
| 6283 task.legacyContext = previousLegacyContext; | |
| 6284 task.context = previousContext; // Restore all active ReactContexts to what they were before. | |
| 6285 | |
| 6286 switchContext(previousContext); | |
| 6287 | |
| 6288 { | |
| 6289 task.componentStack = previousComponentStack; | |
| 6290 } | |
| 6291 | |
| 6292 return; | |
| 6293 } else { | |
| 6294 // Restore the context. We assume that this will be restored by the inner | |
| 6295 // functions in case nothing throws so we don't use "finally" here. | |
| 6296 task.blockedSegment.formatContext = previousFormatContext; | |
| 6297 task.legacyContext = previousLegacyContext; | |
| 6298 task.context = previousContext; // Restore all active ReactContexts to what they were before. | |
| 6299 | |
| 6300 switchContext(previousContext); | |
| 6301 | |
| 6302 { | |
| 6303 task.componentStack = previousComponentStack; | |
| 6304 } // We assume that we don't need the correct context. | |
| 6305 // Let's terminate the rest of the tree and don't render any siblings. | |
| 6306 | |
| 6307 | |
| 6308 throw x; | |
| 6309 } | |
| 6310 } | |
| 6311 } | |
| 6312 | |
| 6313 function erroredTask(request, boundary, segment, error) { | |
| 6314 // Report the error to a global handler. | |
| 6315 var errorDigest = logRecoverableError(request, error); | |
| 6316 | |
| 6317 if (boundary === null) { | |
| 6318 fatalError(request, error); | |
| 6319 } else { | |
| 6320 boundary.pendingTasks--; | |
| 6321 | |
| 6322 if (!boundary.forceClientRender) { | |
| 6323 boundary.forceClientRender = true; | |
| 6324 boundary.errorDigest = errorDigest; | |
| 6325 | |
| 6326 { | |
| 6327 captureBoundaryErrorDetailsDev(boundary, error); | |
| 6328 } // Regardless of what happens next, this boundary won't be displayed, | |
| 6329 // so we can flush it, if the parent already flushed. | |
| 6330 | |
| 6331 | |
| 6332 if (boundary.parentFlushed) { | |
| 6333 // We don't have a preference where in the queue this goes since it's likely | |
| 6334 // to error on the client anyway. However, intentionally client-rendered | |
| 6335 // boundaries should be flushed earlier so that they can start on the client. | |
| 6336 // We reuse the same queue for errors. | |
| 6337 request.clientRenderedBoundaries.push(boundary); | |
| 6338 } | |
| 6339 } | |
| 6340 } | |
| 6341 | |
| 6342 request.allPendingTasks--; | |
| 6343 | |
| 6344 if (request.allPendingTasks === 0) { | |
| 6345 var onAllReady = request.onAllReady; | |
| 6346 onAllReady(); | |
| 6347 } | |
| 6348 } | |
| 6349 | |
| 6350 function abortTaskSoft(task) { | |
| 6351 // This aborts task without aborting the parent boundary that it blocks. | |
| 6352 // It's used for when we didn't need this task to complete the tree. | |
| 6353 // If task was needed, then it should use abortTask instead. | |
| 6354 var request = this; | |
| 6355 var boundary = task.blockedBoundary; | |
| 6356 var segment = task.blockedSegment; | |
| 6357 segment.status = ABORTED; | |
| 6358 finishedTask(request, boundary, segment); | |
| 6359 } | |
| 6360 | |
| 6361 function abortTask(task, request, reason) { | |
| 6362 // This aborts the task and aborts the parent that it blocks, putting it into | |
| 6363 // client rendered mode. | |
| 6364 var boundary = task.blockedBoundary; | |
| 6365 var segment = task.blockedSegment; | |
| 6366 segment.status = ABORTED; | |
| 6367 | |
| 6368 if (boundary === null) { | |
| 6369 request.allPendingTasks--; // We didn't complete the root so we have nothing to show. We can close | |
| 6370 // the request; | |
| 6371 | |
| 6372 if (request.status !== CLOSED) { | |
| 6373 request.status = CLOSED; | |
| 6374 | |
| 6375 if (request.destination !== null) { | |
| 6376 close(request.destination); | |
| 6377 } | |
| 6378 } | |
| 6379 } else { | |
| 6380 boundary.pendingTasks--; | |
| 6381 | |
| 6382 if (!boundary.forceClientRender) { | |
| 6383 boundary.forceClientRender = true; | |
| 6384 | |
| 6385 var _error = reason === undefined ? new Error('The render was aborted by the server without a reason.') : reason; | |
| 6386 | |
| 6387 boundary.errorDigest = request.onError(_error); | |
| 6388 | |
| 6389 { | |
| 6390 var errorPrefix = 'The server did not finish this Suspense boundary: '; | |
| 6391 | |
| 6392 if (_error && typeof _error.message === 'string') { | |
| 6393 _error = errorPrefix + _error.message; | |
| 6394 } else { | |
| 6395 // eslint-disable-next-line react-internal/safe-string-coercion | |
| 6396 _error = errorPrefix + String(_error); | |
| 6397 } | |
| 6398 | |
| 6399 var previousTaskInDev = currentTaskInDEV; | |
| 6400 currentTaskInDEV = task; | |
| 6401 | |
| 6402 try { | |
| 6403 captureBoundaryErrorDetailsDev(boundary, _error); | |
| 6404 } finally { | |
| 6405 currentTaskInDEV = previousTaskInDev; | |
| 6406 } | |
| 6407 } | |
| 6408 | |
| 6409 if (boundary.parentFlushed) { | |
| 6410 request.clientRenderedBoundaries.push(boundary); | |
| 6411 } | |
| 6412 } // If this boundary was still pending then we haven't already cancelled its fallbacks. | |
| 6413 // We'll need to abort the fallbacks, which will also error that parent boundary. | |
| 6414 | |
| 6415 | |
| 6416 boundary.fallbackAbortableTasks.forEach(function (fallbackTask) { | |
| 6417 return abortTask(fallbackTask, request, reason); | |
| 6418 }); | |
| 6419 boundary.fallbackAbortableTasks.clear(); | |
| 6420 request.allPendingTasks--; | |
| 6421 | |
| 6422 if (request.allPendingTasks === 0) { | |
| 6423 var onAllReady = request.onAllReady; | |
| 6424 onAllReady(); | |
| 6425 } | |
| 6426 } | |
| 6427 } | |
| 6428 | |
| 6429 function queueCompletedSegment(boundary, segment) { | |
| 6430 if (segment.chunks.length === 0 && segment.children.length === 1 && segment.children[0].boundary === null) { | |
| 6431 // This is an empty segment. There's nothing to write, so we can instead transfer the ID | |
| 6432 // to the child. That way any existing references point to the child. | |
| 6433 var childSegment = segment.children[0]; | |
| 6434 childSegment.id = segment.id; | |
| 6435 childSegment.parentFlushed = true; | |
| 6436 | |
| 6437 if (childSegment.status === COMPLETED) { | |
| 6438 queueCompletedSegment(boundary, childSegment); | |
| 6439 } | |
| 6440 } else { | |
| 6441 var completedSegments = boundary.completedSegments; | |
| 6442 completedSegments.push(segment); | |
| 6443 } | |
| 6444 } | |
| 6445 | |
| 6446 function finishedTask(request, boundary, segment) { | |
| 6447 if (boundary === null) { | |
| 6448 if (segment.parentFlushed) { | |
| 6449 if (request.completedRootSegment !== null) { | |
| 6450 throw new Error('There can only be one root segment. This is a bug in React.'); | |
| 6451 } | |
| 6452 | |
| 6453 request.completedRootSegment = segment; | |
| 6454 } | |
| 6455 | |
| 6456 request.pendingRootTasks--; | |
| 6457 | |
| 6458 if (request.pendingRootTasks === 0) { | |
| 6459 // We have completed the shell so the shell can't error anymore. | |
| 6460 request.onShellError = noop$1; | |
| 6461 var onShellReady = request.onShellReady; | |
| 6462 onShellReady(); | |
| 6463 } | |
| 6464 } else { | |
| 6465 boundary.pendingTasks--; | |
| 6466 | |
| 6467 if (boundary.forceClientRender) ; else if (boundary.pendingTasks === 0) { | |
| 6468 // This must have been the last segment we were waiting on. This boundary is now complete. | |
| 6469 if (segment.parentFlushed) { | |
| 6470 // Our parent segment already flushed, so we need to schedule this segment to be emitted. | |
| 6471 // If it is a segment that was aborted, we'll write other content instead so we don't need | |
| 6472 // to emit it. | |
| 6473 if (segment.status === COMPLETED) { | |
| 6474 queueCompletedSegment(boundary, segment); | |
| 6475 } | |
| 6476 } | |
| 6477 | |
| 6478 if (boundary.parentFlushed) { | |
| 6479 // The segment might be part of a segment that didn't flush yet, but if the boundary's | |
| 6480 // parent flushed, we need to schedule the boundary to be emitted. | |
| 6481 request.completedBoundaries.push(boundary); | |
| 6482 } // We can now cancel any pending task on the fallback since we won't need to show it anymore. | |
| 6483 // This needs to happen after we read the parentFlushed flags because aborting can finish | |
| 6484 // work which can trigger user code, which can start flushing, which can change those flags. | |
| 6485 | |
| 6486 | |
| 6487 boundary.fallbackAbortableTasks.forEach(abortTaskSoft, request); | |
| 6488 boundary.fallbackAbortableTasks.clear(); | |
| 6489 } else { | |
| 6490 if (segment.parentFlushed) { | |
| 6491 // Our parent already flushed, so we need to schedule this segment to be emitted. | |
| 6492 // If it is a segment that was aborted, we'll write other content instead so we don't need | |
| 6493 // to emit it. | |
| 6494 if (segment.status === COMPLETED) { | |
| 6495 queueCompletedSegment(boundary, segment); | |
| 6496 var completedSegments = boundary.completedSegments; | |
| 6497 | |
| 6498 if (completedSegments.length === 1) { | |
| 6499 // This is the first time since we last flushed that we completed anything. | |
| 6500 // We can schedule this boundary to emit its partially completed segments early | |
| 6501 // in case the parent has already been flushed. | |
| 6502 if (boundary.parentFlushed) { | |
| 6503 request.partialBoundaries.push(boundary); | |
| 6504 } | |
| 6505 } | |
| 6506 } | |
| 6507 } | |
| 6508 } | |
| 6509 } | |
| 6510 | |
| 6511 request.allPendingTasks--; | |
| 6512 | |
| 6513 if (request.allPendingTasks === 0) { | |
| 6514 // This needs to be called at the very end so that we can synchronously write the result | |
| 6515 // in the callback if needed. | |
| 6516 var onAllReady = request.onAllReady; | |
| 6517 onAllReady(); | |
| 6518 } | |
| 6519 } | |
| 6520 | |
| 6521 function retryTask(request, task) { | |
| 6522 var segment = task.blockedSegment; | |
| 6523 | |
| 6524 if (segment.status !== PENDING) { | |
| 6525 // We completed this by other means before we had a chance to retry it. | |
| 6526 return; | |
| 6527 } // We restore the context to what it was when we suspended. | |
| 6528 // We don't restore it after we leave because it's likely that we'll end up | |
| 6529 // needing a very similar context soon again. | |
| 6530 | |
| 6531 | |
| 6532 switchContext(task.context); | |
| 6533 var prevTaskInDEV = null; | |
| 6534 | |
| 6535 { | |
| 6536 prevTaskInDEV = currentTaskInDEV; | |
| 6537 currentTaskInDEV = task; | |
| 6538 } | |
| 6539 | |
| 6540 try { | |
| 6541 // We call the destructive form that mutates this task. That way if something | |
| 6542 // suspends again, we can reuse the same task instead of spawning a new one. | |
| 6543 renderNodeDestructive(request, task, task.node); | |
| 6544 pushSegmentFinale$1(segment.chunks, request.responseState, segment.lastPushedText, segment.textEmbedded); | |
| 6545 task.abortSet.delete(task); | |
| 6546 segment.status = COMPLETED; | |
| 6547 finishedTask(request, task.blockedBoundary, segment); | |
| 6548 } catch (x) { | |
| 6549 resetHooksState(); | |
| 6550 | |
| 6551 if (typeof x === 'object' && x !== null && typeof x.then === 'function') { | |
| 6552 // Something suspended again, let's pick it back up later. | |
| 6553 var ping = task.ping; | |
| 6554 x.then(ping, ping); | |
| 6555 } else { | |
| 6556 task.abortSet.delete(task); | |
| 6557 segment.status = ERRORED; | |
| 6558 erroredTask(request, task.blockedBoundary, segment, x); | |
| 6559 } | |
| 6560 } finally { | |
| 6561 { | |
| 6562 currentTaskInDEV = prevTaskInDEV; | |
| 6563 } | |
| 6564 } | |
| 6565 } | |
| 6566 | |
| 6567 function performWork(request) { | |
| 6568 if (request.status === CLOSED) { | |
| 6569 return; | |
| 6570 } | |
| 6571 | |
| 6572 var prevContext = getActiveContext(); | |
| 6573 var prevDispatcher = ReactCurrentDispatcher$1.current; | |
| 6574 ReactCurrentDispatcher$1.current = Dispatcher; | |
| 6575 var prevGetCurrentStackImpl; | |
| 6576 | |
| 6577 { | |
| 6578 prevGetCurrentStackImpl = ReactDebugCurrentFrame$1.getCurrentStack; | |
| 6579 ReactDebugCurrentFrame$1.getCurrentStack = getCurrentStackInDEV; | |
| 6580 } | |
| 6581 | |
| 6582 var prevResponseState = currentResponseState; | |
| 6583 setCurrentResponseState(request.responseState); | |
| 6584 | |
| 6585 try { | |
| 6586 var pingedTasks = request.pingedTasks; | |
| 6587 var i; | |
| 6588 | |
| 6589 for (i = 0; i < pingedTasks.length; i++) { | |
| 6590 var task = pingedTasks[i]; | |
| 6591 retryTask(request, task); | |
| 6592 } | |
| 6593 | |
| 6594 pingedTasks.splice(0, i); | |
| 6595 | |
| 6596 if (request.destination !== null) { | |
| 6597 flushCompletedQueues(request, request.destination); | |
| 6598 } | |
| 6599 } catch (error) { | |
| 6600 logRecoverableError(request, error); | |
| 6601 fatalError(request, error); | |
| 6602 } finally { | |
| 6603 setCurrentResponseState(prevResponseState); | |
| 6604 ReactCurrentDispatcher$1.current = prevDispatcher; | |
| 6605 | |
| 6606 { | |
| 6607 ReactDebugCurrentFrame$1.getCurrentStack = prevGetCurrentStackImpl; | |
| 6608 } | |
| 6609 | |
| 6610 if (prevDispatcher === Dispatcher) { | |
| 6611 // This means that we were in a reentrant work loop. This could happen | |
| 6612 // in a renderer that supports synchronous work like renderToString, | |
| 6613 // when it's called from within another renderer. | |
| 6614 // Normally we don't bother switching the contexts to their root/default | |
| 6615 // values when leaving because we'll likely need the same or similar | |
| 6616 // context again. However, when we're inside a synchronous loop like this | |
| 6617 // we'll to restore the context to what it was before returning. | |
| 6618 switchContext(prevContext); | |
| 6619 } | |
| 6620 } | |
| 6621 } | |
| 6622 | |
| 6623 function flushSubtree(request, destination, segment) { | |
| 6624 segment.parentFlushed = true; | |
| 6625 | |
| 6626 switch (segment.status) { | |
| 6627 case PENDING: | |
| 6628 { | |
| 6629 // We're emitting a placeholder for this segment to be filled in later. | |
| 6630 // Therefore we'll need to assign it an ID - to refer to it by. | |
| 6631 var segmentID = segment.id = request.nextSegmentId++; // When this segment finally completes it won't be embedded in text since it will flush separately | |
| 6632 | |
| 6633 segment.lastPushedText = false; | |
| 6634 segment.textEmbedded = false; | |
| 6635 return writePlaceholder(destination, request.responseState, segmentID); | |
| 6636 } | |
| 6637 | |
| 6638 case COMPLETED: | |
| 6639 { | |
| 6640 segment.status = FLUSHED; | |
| 6641 var r = true; | |
| 6642 var chunks = segment.chunks; | |
| 6643 var chunkIdx = 0; | |
| 6644 var children = segment.children; | |
| 6645 | |
| 6646 for (var childIdx = 0; childIdx < children.length; childIdx++) { | |
| 6647 var nextChild = children[childIdx]; // Write all the chunks up until the next child. | |
| 6648 | |
| 6649 for (; chunkIdx < nextChild.index; chunkIdx++) { | |
| 6650 writeChunk(destination, chunks[chunkIdx]); | |
| 6651 } | |
| 6652 | |
| 6653 r = flushSegment(request, destination, nextChild); | |
| 6654 } // Finally just write all the remaining chunks | |
| 6655 | |
| 6656 | |
| 6657 for (; chunkIdx < chunks.length - 1; chunkIdx++) { | |
| 6658 writeChunk(destination, chunks[chunkIdx]); | |
| 6659 } | |
| 6660 | |
| 6661 if (chunkIdx < chunks.length) { | |
| 6662 r = writeChunkAndReturn(destination, chunks[chunkIdx]); | |
| 6663 } | |
| 6664 | |
| 6665 return r; | |
| 6666 } | |
| 6667 | |
| 6668 default: | |
| 6669 { | |
| 6670 throw new Error('Aborted, errored or already flushed boundaries should not be flushed again. This is a bug in React.'); | |
| 6671 } | |
| 6672 } | |
| 6673 } | |
| 6674 | |
| 6675 function flushSegment(request, destination, segment) { | |
| 6676 var boundary = segment.boundary; | |
| 6677 | |
| 6678 if (boundary === null) { | |
| 6679 // Not a suspense boundary. | |
| 6680 return flushSubtree(request, destination, segment); | |
| 6681 } | |
| 6682 | |
| 6683 boundary.parentFlushed = true; // This segment is a Suspense boundary. We need to decide whether to | |
| 6684 // emit the content or the fallback now. | |
| 6685 | |
| 6686 if (boundary.forceClientRender) { | |
| 6687 // Emit a client rendered suspense boundary wrapper. | |
| 6688 // We never queue the inner boundary so we'll never emit its content or partial segments. | |
| 6689 writeStartClientRenderedSuspenseBoundary$1(destination, request.responseState, boundary.errorDigest, boundary.errorMessage, boundary.errorComponentStack); // Flush the fallback. | |
| 6690 | |
| 6691 flushSubtree(request, destination, segment); | |
| 6692 return writeEndClientRenderedSuspenseBoundary$1(destination, request.responseState); | |
| 6693 } else if (boundary.pendingTasks > 0) { | |
| 6694 // This boundary is still loading. Emit a pending suspense boundary wrapper. | |
| 6695 // Assign an ID to refer to the future content by. | |
| 6696 boundary.rootSegmentID = request.nextSegmentId++; | |
| 6697 | |
| 6698 if (boundary.completedSegments.length > 0) { | |
| 6699 // If this is at least partially complete, we can queue it to be partially emitted early. | |
| 6700 request.partialBoundaries.push(boundary); | |
| 6701 } /// This is the first time we should have referenced this ID. | |
| 6702 | |
| 6703 | |
| 6704 var id = boundary.id = assignSuspenseBoundaryID(request.responseState); | |
| 6705 writeStartPendingSuspenseBoundary(destination, request.responseState, id); // Flush the fallback. | |
| 6706 | |
| 6707 flushSubtree(request, destination, segment); | |
| 6708 return writeEndPendingSuspenseBoundary(destination, request.responseState); | |
| 6709 } else if (boundary.byteSize > request.progressiveChunkSize) { | |
| 6710 // This boundary is large and will be emitted separately so that we can progressively show | |
| 6711 // other content. We add it to the queue during the flush because we have to ensure that | |
| 6712 // the parent flushes first so that there's something to inject it into. | |
| 6713 // We also have to make sure that it's emitted into the queue in a deterministic slot. | |
| 6714 // I.e. we can't insert it here when it completes. | |
| 6715 // Assign an ID to refer to the future content by. | |
| 6716 boundary.rootSegmentID = request.nextSegmentId++; | |
| 6717 request.completedBoundaries.push(boundary); // Emit a pending rendered suspense boundary wrapper. | |
| 6718 | |
| 6719 writeStartPendingSuspenseBoundary(destination, request.responseState, boundary.id); // Flush the fallback. | |
| 6720 | |
| 6721 flushSubtree(request, destination, segment); | |
| 6722 return writeEndPendingSuspenseBoundary(destination, request.responseState); | |
| 6723 } else { | |
| 6724 // We can inline this boundary's content as a complete boundary. | |
| 6725 writeStartCompletedSuspenseBoundary$1(destination, request.responseState); | |
| 6726 var completedSegments = boundary.completedSegments; | |
| 6727 | |
| 6728 if (completedSegments.length !== 1) { | |
| 6729 throw new Error('A previously unvisited boundary must have exactly one root segment. This is a bug in React.'); | |
| 6730 } | |
| 6731 | |
| 6732 var contentSegment = completedSegments[0]; | |
| 6733 flushSegment(request, destination, contentSegment); | |
| 6734 return writeEndCompletedSuspenseBoundary$1(destination, request.responseState); | |
| 6735 } | |
| 6736 } | |
| 6737 | |
| 6738 function flushClientRenderedBoundary(request, destination, boundary) { | |
| 6739 return writeClientRenderBoundaryInstruction(destination, request.responseState, boundary.id, boundary.errorDigest, boundary.errorMessage, boundary.errorComponentStack); | |
| 6740 } | |
| 6741 | |
| 6742 function flushSegmentContainer(request, destination, segment) { | |
| 6743 writeStartSegment(destination, request.responseState, segment.formatContext, segment.id); | |
| 6744 flushSegment(request, destination, segment); | |
| 6745 return writeEndSegment(destination, segment.formatContext); | |
| 6746 } | |
| 6747 | |
| 6748 function flushCompletedBoundary(request, destination, boundary) { | |
| 6749 var completedSegments = boundary.completedSegments; | |
| 6750 var i = 0; | |
| 6751 | |
| 6752 for (; i < completedSegments.length; i++) { | |
| 6753 var segment = completedSegments[i]; | |
| 6754 flushPartiallyCompletedSegment(request, destination, boundary, segment); | |
| 6755 } | |
| 6756 | |
| 6757 completedSegments.length = 0; | |
| 6758 return writeCompletedBoundaryInstruction(destination, request.responseState, boundary.id, boundary.rootSegmentID); | |
| 6759 } | |
| 6760 | |
| 6761 function flushPartialBoundary(request, destination, boundary) { | |
| 6762 var completedSegments = boundary.completedSegments; | |
| 6763 var i = 0; | |
| 6764 | |
| 6765 for (; i < completedSegments.length; i++) { | |
| 6766 var segment = completedSegments[i]; | |
| 6767 | |
| 6768 if (!flushPartiallyCompletedSegment(request, destination, boundary, segment)) { | |
| 6769 i++; | |
| 6770 completedSegments.splice(0, i); // Only write as much as the buffer wants. Something higher priority | |
| 6771 // might want to write later. | |
| 6772 | |
| 6773 return false; | |
| 6774 } | |
| 6775 } | |
| 6776 | |
| 6777 completedSegments.splice(0, i); | |
| 6778 return true; | |
| 6779 } | |
| 6780 | |
| 6781 function flushPartiallyCompletedSegment(request, destination, boundary, segment) { | |
| 6782 if (segment.status === FLUSHED) { | |
| 6783 // We've already flushed this inline. | |
| 6784 return true; | |
| 6785 } | |
| 6786 | |
| 6787 var segmentID = segment.id; | |
| 6788 | |
| 6789 if (segmentID === -1) { | |
| 6790 // This segment wasn't previously referred to. This happens at the root of | |
| 6791 // a boundary. We make kind of a leap here and assume this is the root. | |
| 6792 var rootSegmentID = segment.id = boundary.rootSegmentID; | |
| 6793 | |
| 6794 if (rootSegmentID === -1) { | |
| 6795 throw new Error('A root segment ID must have been assigned by now. This is a bug in React.'); | |
| 6796 } | |
| 6797 | |
| 6798 return flushSegmentContainer(request, destination, segment); | |
| 6799 } else { | |
| 6800 flushSegmentContainer(request, destination, segment); | |
| 6801 return writeCompletedSegmentInstruction(destination, request.responseState, segmentID); | |
| 6802 } | |
| 6803 } | |
| 6804 | |
| 6805 function flushCompletedQueues(request, destination) { | |
| 6806 | |
| 6807 try { | |
| 6808 // The structure of this is to go through each queue one by one and write | |
| 6809 // until the sink tells us to stop. When we should stop, we still finish writing | |
| 6810 // that item fully and then yield. At that point we remove the already completed | |
| 6811 // items up until the point we completed them. | |
| 6812 // TODO: Emit preloading. | |
| 6813 // TODO: It's kind of unfortunate to keep checking this array after we've already | |
| 6814 // emitted the root. | |
| 6815 var completedRootSegment = request.completedRootSegment; | |
| 6816 | |
| 6817 if (completedRootSegment !== null && request.pendingRootTasks === 0) { | |
| 6818 flushSegment(request, destination, completedRootSegment); | |
| 6819 request.completedRootSegment = null; | |
| 6820 writeCompletedRoot(destination, request.responseState); | |
| 6821 } // We emit client rendering instructions for already emitted boundaries first. | |
| 6822 // This is so that we can signal to the client to start client rendering them as | |
| 6823 // soon as possible. | |
| 6824 | |
| 6825 | |
| 6826 var clientRenderedBoundaries = request.clientRenderedBoundaries; | |
| 6827 var i; | |
| 6828 | |
| 6829 for (i = 0; i < clientRenderedBoundaries.length; i++) { | |
| 6830 var boundary = clientRenderedBoundaries[i]; | |
| 6831 | |
| 6832 if (!flushClientRenderedBoundary(request, destination, boundary)) { | |
| 6833 request.destination = null; | |
| 6834 i++; | |
| 6835 clientRenderedBoundaries.splice(0, i); | |
| 6836 return; | |
| 6837 } | |
| 6838 } | |
| 6839 | |
| 6840 clientRenderedBoundaries.splice(0, i); // Next we emit any complete boundaries. It's better to favor boundaries | |
| 6841 // that are completely done since we can actually show them, than it is to emit | |
| 6842 // any individual segments from a partially complete boundary. | |
| 6843 | |
| 6844 var completedBoundaries = request.completedBoundaries; | |
| 6845 | |
| 6846 for (i = 0; i < completedBoundaries.length; i++) { | |
| 6847 var _boundary = completedBoundaries[i]; | |
| 6848 | |
| 6849 if (!flushCompletedBoundary(request, destination, _boundary)) { | |
| 6850 request.destination = null; | |
| 6851 i++; | |
| 6852 completedBoundaries.splice(0, i); | |
| 6853 return; | |
| 6854 } | |
| 6855 } | |
| 6856 | |
| 6857 completedBoundaries.splice(0, i); // Allow anything written so far to flush to the underlying sink before | |
| 6858 // we continue with lower priorities. | |
| 6859 | |
| 6860 completeWriting(destination); | |
| 6861 beginWriting(destination); // TODO: Here we'll emit data used by hydration. | |
| 6862 // Next we emit any segments of any boundaries that are partially complete | |
| 6863 // but not deeply complete. | |
| 6864 | |
| 6865 var partialBoundaries = request.partialBoundaries; | |
| 6866 | |
| 6867 for (i = 0; i < partialBoundaries.length; i++) { | |
| 6868 var _boundary2 = partialBoundaries[i]; | |
| 6869 | |
| 6870 if (!flushPartialBoundary(request, destination, _boundary2)) { | |
| 6871 request.destination = null; | |
| 6872 i++; | |
| 6873 partialBoundaries.splice(0, i); | |
| 6874 return; | |
| 6875 } | |
| 6876 } | |
| 6877 | |
| 6878 partialBoundaries.splice(0, i); // Next we check the completed boundaries again. This may have had | |
| 6879 // boundaries added to it in case they were too larged to be inlined. | |
| 6880 // New ones might be added in this loop. | |
| 6881 | |
| 6882 var largeBoundaries = request.completedBoundaries; | |
| 6883 | |
| 6884 for (i = 0; i < largeBoundaries.length; i++) { | |
| 6885 var _boundary3 = largeBoundaries[i]; | |
| 6886 | |
| 6887 if (!flushCompletedBoundary(request, destination, _boundary3)) { | |
| 6888 request.destination = null; | |
| 6889 i++; | |
| 6890 largeBoundaries.splice(0, i); | |
| 6891 return; | |
| 6892 } | |
| 6893 } | |
| 6894 | |
| 6895 largeBoundaries.splice(0, i); | |
| 6896 } finally { | |
| 6897 | |
| 6898 if (request.allPendingTasks === 0 && request.pingedTasks.length === 0 && request.clientRenderedBoundaries.length === 0 && request.completedBoundaries.length === 0 // We don't need to check any partially completed segments because | |
| 6899 // either they have pending task or they're complete. | |
| 6900 ) { | |
| 6901 { | |
| 6902 if (request.abortableTasks.size !== 0) { | |
| 6903 error('There was still abortable task at the root when we closed. This is a bug in React.'); | |
| 6904 } | |
| 6905 } // We're done. | |
| 6906 | |
| 6907 | |
| 6908 close(destination); | |
| 6909 } | |
| 6910 } | |
| 6911 } | |
| 6912 | |
| 6913 function startWork(request) { | |
| 6914 scheduleWork(function () { | |
| 6915 return performWork(request); | |
| 6916 }); | |
| 6917 } | |
| 6918 function startFlowing(request, destination) { | |
| 6919 if (request.status === CLOSING) { | |
| 6920 request.status = CLOSED; | |
| 6921 closeWithError(destination, request.fatalError); | |
| 6922 return; | |
| 6923 } | |
| 6924 | |
| 6925 if (request.status === CLOSED) { | |
| 6926 return; | |
| 6927 } | |
| 6928 | |
| 6929 if (request.destination !== null) { | |
| 6930 // We're already flowing. | |
| 6931 return; | |
| 6932 } | |
| 6933 | |
| 6934 request.destination = destination; | |
| 6935 | |
| 6936 try { | |
| 6937 flushCompletedQueues(request, destination); | |
| 6938 } catch (error) { | |
| 6939 logRecoverableError(request, error); | |
| 6940 fatalError(request, error); | |
| 6941 } | |
| 6942 } // This is called to early terminate a request. It puts all pending boundaries in client rendered state. | |
| 6943 | |
| 6944 function abort(request, reason) { | |
| 6945 try { | |
| 6946 var abortableTasks = request.abortableTasks; | |
| 6947 abortableTasks.forEach(function (task) { | |
| 6948 return abortTask(task, request, reason); | |
| 6949 }); | |
| 6950 abortableTasks.clear(); | |
| 6951 | |
| 6952 if (request.destination !== null) { | |
| 6953 flushCompletedQueues(request, request.destination); | |
| 6954 } | |
| 6955 } catch (error) { | |
| 6956 logRecoverableError(request, error); | |
| 6957 fatalError(request, error); | |
| 6958 } | |
| 6959 } | |
| 6960 | |
| 6961 function onError() {// Non-fatal errors are ignored. | |
| 6962 } | |
| 6963 | |
| 6964 function renderToStringImpl(children, options, generateStaticMarkup, abortReason) { | |
| 6965 var didFatal = false; | |
| 6966 var fatalError = null; | |
| 6967 var result = ''; | |
| 6968 var destination = { | |
| 6969 push: function (chunk) { | |
| 6970 if (chunk !== null) { | |
| 6971 result += chunk; | |
| 6972 } | |
| 6973 | |
| 6974 return true; | |
| 6975 }, | |
| 6976 destroy: function (error) { | |
| 6977 didFatal = true; | |
| 6978 fatalError = error; | |
| 6979 } | |
| 6980 }; | |
| 6981 var readyToStream = false; | |
| 6982 | |
| 6983 function onShellReady() { | |
| 6984 readyToStream = true; | |
| 6985 } | |
| 6986 | |
| 6987 var request = createRequest(children, createResponseState$1(generateStaticMarkup, options ? options.identifierPrefix : undefined), createRootFormatContext(), Infinity, onError, undefined, onShellReady, undefined, undefined); | |
| 6988 startWork(request); // If anything suspended and is still pending, we'll abort it before writing. | |
| 6989 // That way we write only client-rendered boundaries from the start. | |
| 6990 | |
| 6991 abort(request, abortReason); | |
| 6992 startFlowing(request, destination); | |
| 6993 | |
| 6994 if (didFatal) { | |
| 6995 throw fatalError; | |
| 6996 } | |
| 6997 | |
| 6998 if (!readyToStream) { | |
| 6999 // Note: This error message is the one we use on the client. It doesn't | |
| 7000 // really make sense here. But this is the legacy server renderer, anyway. | |
| 7001 // We're going to delete it soon. | |
| 7002 throw new Error('A component suspended while responding to synchronous input. This ' + 'will cause the UI to be replaced with a loading indicator. To fix, ' + 'updates that suspend should be wrapped with startTransition.'); | |
| 7003 } | |
| 7004 | |
| 7005 return result; | |
| 7006 } | |
| 7007 | |
| 7008 function _inheritsLoose(subClass, superClass) { | |
| 7009 subClass.prototype = Object.create(superClass.prototype); | |
| 7010 subClass.prototype.constructor = subClass; | |
| 7011 subClass.__proto__ = superClass; | |
| 7012 } | |
| 7013 | |
| 7014 var ReactMarkupReadableStream = /*#__PURE__*/function (_Readable) { | |
| 7015 _inheritsLoose(ReactMarkupReadableStream, _Readable); | |
| 7016 | |
| 7017 function ReactMarkupReadableStream() { | |
| 7018 var _this; | |
| 7019 | |
| 7020 // Calls the stream.Readable(options) constructor. Consider exposing built-in | |
| 7021 // features like highWaterMark in the future. | |
| 7022 _this = _Readable.call(this, {}) || this; | |
| 7023 _this.request = null; | |
| 7024 _this.startedFlowing = false; | |
| 7025 return _this; | |
| 7026 } | |
| 7027 | |
| 7028 var _proto = ReactMarkupReadableStream.prototype; | |
| 7029 | |
| 7030 _proto._destroy = function _destroy(err, callback) { | |
| 7031 abort(this.request); // $FlowFixMe: The type definition for the callback should allow undefined and null. | |
| 7032 | |
| 7033 callback(err); | |
| 7034 }; | |
| 7035 | |
| 7036 _proto._read = function _read(size) { | |
| 7037 if (this.startedFlowing) { | |
| 7038 startFlowing(this.request, this); | |
| 7039 } | |
| 7040 }; | |
| 7041 | |
| 7042 return ReactMarkupReadableStream; | |
| 7043 }(stream.Readable); | |
| 7044 | |
| 7045 function onError$1() {// Non-fatal errors are ignored. | |
| 7046 } | |
| 7047 | |
| 7048 function renderToNodeStreamImpl(children, options, generateStaticMarkup) { | |
| 7049 function onAllReady() { | |
| 7050 // We wait until everything has loaded before starting to write. | |
| 7051 // That way we only end up with fully resolved HTML even if we suspend. | |
| 7052 destination.startedFlowing = true; | |
| 7053 startFlowing(request, destination); | |
| 7054 } | |
| 7055 | |
| 7056 var destination = new ReactMarkupReadableStream(); | |
| 7057 var request = createRequest(children, createResponseState$1(false, options ? options.identifierPrefix : undefined), createRootFormatContext(), Infinity, onError$1, onAllReady, undefined, undefined); | |
| 7058 destination.request = request; | |
| 7059 startWork(request); | |
| 7060 return destination; | |
| 7061 } | |
| 7062 | |
| 7063 function renderToNodeStream(children, options) { | |
| 7064 { | |
| 7065 error('renderToNodeStream is deprecated. Use renderToPipeableStream instead.'); | |
| 7066 } | |
| 7067 | |
| 7068 return renderToNodeStreamImpl(children, options); | |
| 7069 } | |
| 7070 | |
| 7071 function renderToStaticNodeStream(children, options) { | |
| 7072 { | |
| 7073 error('ReactDOMServer.renderToStaticNodeStream() is deprecated.' + ' Use ReactDOMServer.renderToPipeableStream() and wait to `pipe` until the `onAllReady`' + ' callback has been called instead.'); | |
| 7074 } | |
| 7075 | |
| 7076 return renderToNodeStreamImpl(children, options); | |
| 7077 } | |
| 7078 | |
| 7079 function renderToString(children, options) { | |
| 7080 return renderToStringImpl(children, options, false, 'The server used "renderToString" which does not support Suspense. If you intended for this Suspense boundary to render the fallback content on the server consider throwing an Error somewhere within the Suspense boundary. If you intended to have the server wait for the suspended component please switch to "renderToPipeableStream" which supports Suspense on the server'); | |
| 7081 } | |
| 7082 | |
| 7083 function renderToStaticMarkup(children, options) { | |
| 7084 return renderToStringImpl(children, options, true, 'The server used "renderToStaticMarkup" which does not support Suspense. If you intended to have the server wait for the suspended component please switch to "renderToPipeableStream" which supports Suspense on the server'); | |
| 7085 } | |
| 7086 | |
| 7087 exports.renderToNodeStream = renderToNodeStream; | |
| 7088 exports.renderToStaticMarkup = renderToStaticMarkup; | |
| 7089 exports.renderToStaticNodeStream = renderToStaticNodeStream; | |
| 7090 exports.renderToString = renderToString; | |
| 7091 exports.version = ReactVersion; | |
| 7092 })(); | |
| 7093 } |