210536ebdf53392a35cf9244ba020ad782b97f430f5e058b3638d3a3a00253ef6779578b46b4fca5ef300488bde63b65b799bfe96fbc9e9bccd235f8f2f41b 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101
  1. /* @flow */
  2. import { makeMap } from 'shared/util'
  3. const isAttr = makeMap(
  4. 'accept,accept-charset,accesskey,action,align,alt,async,autocomplete,' +
  5. 'autofocus,autoplay,autosave,bgcolor,border,buffered,challenge,charset,' +
  6. 'checked,cite,class,code,codebase,color,cols,colspan,content,' +
  7. 'contenteditable,contextmenu,controls,coords,data,datetime,default,' +
  8. 'defer,dir,dirname,disabled,download,draggable,dropzone,enctype,for,' +
  9. 'form,formaction,headers,height,hidden,high,href,hreflang,http-equiv,' +
  10. 'icon,id,ismap,itemprop,keytype,kind,label,lang,language,list,loop,low,' +
  11. 'manifest,max,maxlength,media,method,GET,POST,min,multiple,email,file,' +
  12. 'muted,name,novalidate,open,optimum,pattern,ping,placeholder,poster,' +
  13. 'preload,radiogroup,readonly,rel,required,reversed,rows,rowspan,sandbox,' +
  14. 'scope,scoped,seamless,selected,shape,size,type,text,password,sizes,span,' +
  15. 'spellcheck,src,srcdoc,srclang,srcset,start,step,style,summary,tabindex,' +
  16. 'target,title,usemap,value,width,wrap'
  17. )
  18. const unsafeAttrCharRE = /[>/="'\u0009\u000a\u000c\u0020]/ // eslint-disable-line no-control-regex
  19. export const isSSRUnsafeAttr = (name: string): boolean => {
  20. return unsafeAttrCharRE.test(name)
  21. }
  22. /* istanbul ignore next */
  23. const isRenderableAttr = (name: string): boolean => {
  24. return (
  25. isAttr(name) ||
  26. name.indexOf('data-') === 0 ||
  27. name.indexOf('aria-') === 0
  28. )
  29. }
  30. export { isRenderableAttr }
  31. export const propsToAttrMap = {
  32. acceptCharset: 'accept-charset',
  33. className: 'class',
  34. htmlFor: 'for',
  35. httpEquiv: 'http-equiv'
  36. }
  37. const ESC = {
  38. '<': '&lt;',
  39. '>': '&gt;',
  40. '"': '&quot;',
  41. '&': '&amp;'
  42. }
  43. export function escape (s: string) {
  44. return s.replace(/[<>"&]/g, escapeChar)
  45. }
  46. function escapeChar (a) {
  47. return ESC[a] || a
  48. }
  49. export const noUnitNumericStyleProps = {
  50. "animation-iteration-count": true,
  51. "border-image-outset": true,
  52. "border-image-slice": true,
  53. "border-image-width": true,
  54. "box-flex": true,
  55. "box-flex-group": true,
  56. "box-ordinal-group": true,
  57. "column-count": true,
  58. "columns": true,
  59. "flex": true,
  60. "flex-grow": true,
  61. "flex-positive": true,
  62. "flex-shrink": true,
  63. "flex-negative": true,
  64. "flex-order": true,
  65. "grid-row": true,
  66. "grid-row-end": true,
  67. "grid-row-span": true,
  68. "grid-row-start": true,
  69. "grid-column": true,
  70. "grid-column-end": true,
  71. "grid-column-span": true,
  72. "grid-column-start": true,
  73. "font-weight": true,
  74. "line-clamp": true,
  75. "line-height": true,
  76. "opacity": true,
  77. "order": true,
  78. "orphans": true,
  79. "tab-size": true,
  80. "widows": true,
  81. "z-index": true,
  82. "zoom": true,
  83. // SVG
  84. "fill-opacity": true,
  85. "flood-opacity": true,
  86. "stop-opacity": true,
  87. "stroke-dasharray": true,
  88. "stroke-dashoffset": true,
  89. "stroke-miterlimit": true,
  90. "stroke-opacity": true,
  91. "stroke-width": true
  92. }