You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

443 lines
7.8 KiB

5 years ago
  1. // similar to _.uniq
  2. const uniq = l => l.filter((x, i, a) => a.indexOf(x) === i)
  3. /**
  4. * SVG void elements that cannot be auto-closed and shouldn't contain child nodes.
  5. * @const {Array}
  6. */
  7. export const VOID_SVG_TAGS_LIST = [
  8. 'circle',
  9. 'ellipse',
  10. 'line',
  11. 'path',
  12. 'polygon',
  13. 'polyline',
  14. 'rect',
  15. 'stop',
  16. 'use'
  17. ]
  18. /**
  19. * List of html elements where the value attribute is allowed
  20. * @type {Array}
  21. */
  22. export const HTML_ELEMENTS_HAVING_VALUE_ATTRIBUTE_LIST = [
  23. 'button',
  24. 'data',
  25. 'input',
  26. 'select',
  27. 'li',
  28. 'meter',
  29. 'option',
  30. 'output',
  31. 'progress',
  32. 'textarea',
  33. 'param'
  34. ]
  35. /**
  36. * List of all the available svg tags
  37. * @const {Array}
  38. * @see {@link https://github.com/wooorm/svg-tag-names}
  39. */
  40. export const SVG_TAGS_LIST = uniq([
  41. 'a',
  42. 'altGlyph',
  43. 'altGlyphDef',
  44. 'altGlyphItem',
  45. 'animate',
  46. 'animateColor',
  47. 'animateMotion',
  48. 'animateTransform',
  49. 'animation',
  50. 'audio',
  51. 'canvas',
  52. 'clipPath',
  53. 'color-profile',
  54. 'cursor',
  55. 'defs',
  56. 'desc',
  57. 'discard',
  58. 'feBlend',
  59. 'feColorMatrix',
  60. 'feComponentTransfer',
  61. 'feComposite',
  62. 'feConvolveMatrix',
  63. 'feDiffuseLighting',
  64. 'feDisplacementMap',
  65. 'feDistantLight',
  66. 'feDropShadow',
  67. 'feFlood',
  68. 'feFuncA',
  69. 'feFuncB',
  70. 'feFuncG',
  71. 'feFuncR',
  72. 'feGaussianBlur',
  73. 'feImage',
  74. 'feMerge',
  75. 'feMergeNode',
  76. 'feMorphology',
  77. 'feOffset',
  78. 'fePointLight',
  79. 'feSpecularLighting',
  80. 'feSpotLight',
  81. 'feTile',
  82. 'feTurbulence',
  83. 'filter',
  84. 'font',
  85. 'font-face',
  86. 'font-face-format',
  87. 'font-face-name',
  88. 'font-face-src',
  89. 'font-face-uri',
  90. 'foreignObject',
  91. 'g',
  92. 'glyph',
  93. 'glyphRef',
  94. 'handler',
  95. 'hatch',
  96. 'hatchpath',
  97. 'hkern',
  98. 'iframe',
  99. 'image',
  100. 'linearGradient',
  101. 'listener',
  102. 'marker',
  103. 'mask',
  104. 'mesh',
  105. 'meshgradient',
  106. 'meshpatch',
  107. 'meshrow',
  108. 'metadata',
  109. 'missing-glyph',
  110. 'mpath',
  111. 'pattern',
  112. 'prefetch',
  113. 'radialGradient',
  114. 'script',
  115. 'set',
  116. 'solidColor',
  117. 'solidcolor',
  118. 'style',
  119. 'svg',
  120. 'switch',
  121. 'symbol',
  122. 'tbreak',
  123. 'text',
  124. 'textArea',
  125. 'textPath',
  126. 'title',
  127. 'tref',
  128. 'tspan',
  129. 'unknown',
  130. 'video',
  131. 'view',
  132. 'vkern'
  133. ].concat(VOID_SVG_TAGS_LIST)).sort()
  134. /**
  135. * HTML void elements that cannot be auto-closed and shouldn't contain child nodes.
  136. * @type {Array}
  137. * @see {@link http://www.w3.org/TR/html-markup/syntax.html#syntax-elements}
  138. * @see {@link http://www.w3.org/TR/html5/syntax.html#void-elements}
  139. */
  140. export const VOID_HTML_TAGS_LIST = [
  141. 'area',
  142. 'base',
  143. 'br',
  144. 'col',
  145. 'embed',
  146. 'hr',
  147. 'img',
  148. 'input',
  149. 'keygen',
  150. 'link',
  151. 'menuitem',
  152. 'meta',
  153. 'param',
  154. 'source',
  155. 'track',
  156. 'wbr'
  157. ]
  158. /**
  159. * List of all the html tags
  160. * @const {Array}
  161. * @see {@link https://github.com/sindresorhus/html-tags}
  162. */
  163. export const HTML_TAGS_LIST = uniq([
  164. 'a',
  165. 'abbr',
  166. 'address',
  167. 'article',
  168. 'aside',
  169. 'audio',
  170. 'b',
  171. 'bdi',
  172. 'bdo',
  173. 'blockquote',
  174. 'body',
  175. 'canvas',
  176. 'caption',
  177. 'cite',
  178. 'code',
  179. 'colgroup',
  180. 'datalist',
  181. 'dd',
  182. 'del',
  183. 'details',
  184. 'dfn',
  185. 'dialog',
  186. 'div',
  187. 'dl',
  188. 'dt',
  189. 'em',
  190. 'fieldset',
  191. 'figcaption',
  192. 'figure',
  193. 'footer',
  194. 'form',
  195. 'h1',
  196. 'h2',
  197. 'h3',
  198. 'h4',
  199. 'h5',
  200. 'h6',
  201. 'head',
  202. 'header',
  203. 'hgroup',
  204. 'html',
  205. 'i',
  206. 'iframe',
  207. 'ins',
  208. 'kbd',
  209. 'label',
  210. 'legend',
  211. 'main',
  212. 'map',
  213. 'mark',
  214. 'math',
  215. 'menu',
  216. 'nav',
  217. 'noscript',
  218. 'object',
  219. 'ol',
  220. 'optgroup',
  221. 'p',
  222. 'picture',
  223. 'pre',
  224. 'q',
  225. 'rb',
  226. 'rp',
  227. 'rt',
  228. 'rtc',
  229. 'ruby',
  230. 's',
  231. 'samp',
  232. 'script',
  233. 'section',
  234. 'select',
  235. 'slot',
  236. 'small',
  237. 'span',
  238. 'strong',
  239. 'style',
  240. 'sub',
  241. 'summary',
  242. 'sup',
  243. 'svg',
  244. 'table',
  245. 'tbody',
  246. 'td',
  247. 'template',
  248. 'tfoot',
  249. 'th',
  250. 'thead',
  251. 'time',
  252. 'title',
  253. 'tr',
  254. 'u',
  255. 'ul',
  256. 'var',
  257. 'video'
  258. ]
  259. .concat(VOID_HTML_TAGS_LIST)
  260. .concat(HTML_ELEMENTS_HAVING_VALUE_ATTRIBUTE_LIST)
  261. ).sort()
  262. /**
  263. * List of all boolean HTML attributes
  264. * @const {RegExp}
  265. * @see {@link https://www.w3.org/TR/html5/infrastructure.html#sec-boolean-attributes}
  266. */
  267. export const BOOLEAN_ATTRIBUTES_LIST = [
  268. 'disabled',
  269. 'visible',
  270. 'checked',
  271. 'readonly',
  272. 'required',
  273. 'allowfullscreen',
  274. 'autofocus',
  275. 'autoplay',
  276. 'compact',
  277. 'controls',
  278. 'default',
  279. 'formnovalidate',
  280. 'hidden',
  281. 'ismap',
  282. 'itemscope',
  283. 'loop',
  284. 'multiple',
  285. 'muted',
  286. 'noresize',
  287. 'noshade',
  288. 'novalidate',
  289. 'nowrap',
  290. 'open',
  291. 'reversed',
  292. 'seamless',
  293. 'selected',
  294. 'sortable',
  295. 'truespeed',
  296. 'typemustmatch'
  297. ]
  298. /**
  299. * Join a list of items with the pipe symbol (usefull for regex list concatenation)
  300. * @private
  301. * @param {Array} list - list of strings
  302. * @returns {string} the list received joined with pipes
  303. */
  304. function joinWithPipe(list) {
  305. return list.join('|')
  306. }
  307. /**
  308. * Convert list of strings to regex in order to test against it ignoring the cases
  309. * @private
  310. * @param {...Array} lists - array of strings
  311. * @returns {RegExp} regex that will match all the strings in the array received ignoring the cases
  312. */
  313. function listsToRegex(...lists) {
  314. return new RegExp(`^/?(?:${joinWithPipe(lists.map(joinWithPipe))})$`, 'i')
  315. }
  316. /**
  317. * Regex matching all the html tags ignoring the cases
  318. * @const {RegExp}
  319. */
  320. export const HTML_TAGS_RE = listsToRegex(HTML_TAGS_LIST)
  321. /**
  322. * Regex matching all the svg tags ignoring the cases
  323. * @const {RegExp}
  324. */
  325. export const SVG_TAGS_RE = listsToRegex(SVG_TAGS_LIST)
  326. /**
  327. * Regex matching all the void html tags ignoring the cases
  328. * @const {RegExp}
  329. */
  330. export const VOID_HTML_TAGS_RE = listsToRegex(VOID_HTML_TAGS_LIST)
  331. /**
  332. * Regex matching all the void svg tags ignoring the cases
  333. * @const {RegExp}
  334. */
  335. export const VOID_SVG_TAGS_RE = listsToRegex(VOID_SVG_TAGS_LIST)
  336. /**
  337. * Regex matching all the html tags where the value tag is allowed
  338. * @const {RegExp}
  339. */
  340. export const HTML_ELEMENTS_HAVING_VALUE_ATTRIBUTE_RE = listsToRegex(HTML_ELEMENTS_HAVING_VALUE_ATTRIBUTE_LIST)
  341. /**
  342. * Regex matching all the boolean attributes
  343. * @const {RegExp}
  344. */
  345. export const BOOLEAN_ATTRIBUTES_RE = listsToRegex(BOOLEAN_ATTRIBUTES_LIST)
  346. /**
  347. * True if it's a self closing tag
  348. * @param {string} tag - test tag
  349. * @returns {boolean} true if void
  350. * @example
  351. * isVoid('meta') // true
  352. * isVoid('circle') // true
  353. * isVoid('IMG') // true
  354. * isVoid('div') // false
  355. * isVoid('mask') // false
  356. */
  357. export function isVoid(tag) {
  358. return [
  359. VOID_HTML_TAGS_RE,
  360. VOID_SVG_TAGS_RE
  361. ].some(r => r.test(tag))
  362. }
  363. /**
  364. * True if it's a known HTML tag
  365. * @param {string} tag - test tag
  366. * @returns {boolean} true if html tag
  367. * @example
  368. * isHtml('img') // true
  369. * isHtml('IMG') // true
  370. * isHtml('Img') // true
  371. * isHtml('path') // false
  372. */
  373. export function isHtml(tag) {
  374. return HTML_TAGS_RE.test(tag)
  375. }
  376. /**
  377. * True if it's a known SVG tag
  378. * @param {string} tag - test tag
  379. * @returns {boolean} true if svg tag
  380. * @example
  381. * isSvg('g') // true
  382. * isSvg('radialGradient') // true
  383. * isSvg('radialgradient') // true
  384. * isSvg('div') // false
  385. */
  386. export function isSvg(tag) {
  387. return SVG_TAGS_RE.test(tag)
  388. }
  389. /**
  390. * True if it's not SVG nor a HTML known tag
  391. * @param {string} tag - test tag
  392. * @returns {boolean} true if custom element
  393. * @example
  394. * isCustom('my-component') // true
  395. * isCustom('div') // false
  396. */
  397. export function isCustom(tag) {
  398. return [
  399. HTML_TAGS_RE,
  400. SVG_TAGS_RE
  401. ].every(l => !l.test(tag))
  402. }
  403. /**
  404. * True if the value attribute is allowed on this tag
  405. * @param {string} tag - test tag
  406. * @returns {boolean} true if the value attribute is allowed
  407. * @example
  408. * hasValueAttribute('input') // true
  409. * hasValueAttribute('div') // false
  410. */
  411. export function hasValueAttribute(tag) {
  412. return HTML_ELEMENTS_HAVING_VALUE_ATTRIBUTE_RE.test(tag)
  413. }
  414. /**
  415. * True if it's a boolean attribute
  416. * @param {string} attribute - test attribute
  417. * @returns {boolean} true if the attribute is a boolean type
  418. * @example
  419. * isBoolAttribute('selected') // true
  420. * isBoolAttribute('class') // false
  421. */
  422. export function isBoolAttribute(attribute) {
  423. return BOOLEAN_ATTRIBUTES_RE.test(attribute)
  424. }