1. /**
    
  2.  * Copyright (c) Meta Platforms, Inc. and affiliates.
    
  3.  *
    
  4.  * This source code is licensed under the MIT license found in the
    
  5.  * LICENSE file in the root directory of this source tree.
    
  6.  *
    
  7.  * @flow
    
  8.  */
    
  9. 
    
  10. export function validateLinkPropsForStyleResource(props: any): boolean {
    
  11.   if (__DEV__) {
    
  12.     // This should only be called when we know we are opting into Resource semantics (i.e. precedence is not null)
    
  13.     const {href, onLoad, onError, disabled} = props;
    
  14.     const includedProps = [];
    
  15.     if (onLoad) includedProps.push('`onLoad`');
    
  16.     if (onError) includedProps.push('`onError`');
    
  17.     if (disabled != null) includedProps.push('`disabled`');
    
  18. 
    
  19.     let includedPropsPhrase = propNamesListJoin(includedProps, 'and');
    
  20.     includedPropsPhrase += includedProps.length === 1 ? ' prop' : ' props';
    
  21.     const withArticlePhrase =
    
  22.       includedProps.length === 1
    
  23.         ? 'an ' + includedPropsPhrase
    
  24.         : 'the ' + includedPropsPhrase;
    
  25. 
    
  26.     if (includedProps.length) {
    
  27.       console.error(
    
  28.         'React encountered a <link rel="stylesheet" href="%s" ... /> with a `precedence` prop that' +
    
  29.           ' also included %s. The presence of loading and error handlers indicates an intent to manage' +
    
  30.           ' the stylesheet loading state from your from your Component code and React will not hoist or' +
    
  31.           ' deduplicate this stylesheet. If your intent was to have React hoist and deduplciate this stylesheet' +
    
  32.           ' using the `precedence` prop remove the %s, otherwise remove the `precedence` prop.',
    
  33.         href,
    
  34.         withArticlePhrase,
    
  35.         includedPropsPhrase,
    
  36.       );
    
  37.       return true;
    
  38.     }
    
  39.   }
    
  40.   return false;
    
  41. }
    
  42. 
    
  43. function propNamesListJoin(
    
  44.   list: Array<string>,
    
  45.   combinator: 'and' | 'or',
    
  46. ): string {
    
  47.   switch (list.length) {
    
  48.     case 0:
    
  49.       return '';
    
  50.     case 1:
    
  51.       return list[0];
    
  52.     case 2:
    
  53.       return list[0] + ' ' + combinator + ' ' + list[1];
    
  54.     default:
    
  55.       return (
    
  56.         list.slice(0, -1).join(', ') +
    
  57.         ', ' +
    
  58.         combinator +
    
  59.         ' ' +
    
  60.         list[list.length - 1]
    
  61.       );
    
  62.   }
    
  63. }
    
  64. 
    
  65. export function getValueDescriptorExpectingObjectForWarning(
    
  66.   thing: any,
    
  67. ): string {
    
  68.   return thing === null
    
  69.     ? '`null`'
    
  70.     : thing === undefined
    
  71.     ? '`undefined`'
    
  72.     : thing === ''
    
  73.     ? 'an empty string'
    
  74.     : `something with type "${typeof thing}"`;
    
  75. }
    
  76. 
    
  77. export function getValueDescriptorExpectingEnumForWarning(thing: any): string {
    
  78.   return thing === null
    
  79.     ? '`null`'
    
  80.     : thing === undefined
    
  81.     ? '`undefined`'
    
  82.     : thing === ''
    
  83.     ? 'an empty string'
    
  84.     : typeof thing === 'string'
    
  85.     ? JSON.stringify(thing)
    
  86.     : `something with type "${typeof thing}"`;
    
  87. }