no-multiple-template-root.js 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101
  1. /**
  2. * @fileoverview disallow adding multiple root nodes to the template
  3. * @author Przemyslaw Falowski (@przemkow)
  4. */
  5. 'use strict'
  6. // ------------------------------------------------------------------------------
  7. // Requirements
  8. // ------------------------------------------------------------------------------
  9. const utils = require('../utils')
  10. // ------------------------------------------------------------------------------
  11. // Rule Definition
  12. // ------------------------------------------------------------------------------
  13. module.exports = {
  14. meta: {
  15. type: 'problem',
  16. docs: {
  17. description: 'disallow adding multiple root nodes to the template',
  18. categories: ['essential'],
  19. url: 'https://eslint.vuejs.org/rules/no-multiple-template-root.html'
  20. },
  21. fixable: null,
  22. schema: []
  23. },
  24. /**
  25. * @param {RuleContext} context - The rule context.
  26. * @returns {RuleListener} AST event handlers.
  27. */
  28. create(context) {
  29. const sourceCode = context.getSourceCode()
  30. return {
  31. Program(program) {
  32. const element = program.templateBody
  33. if (element == null) {
  34. return
  35. }
  36. const rootElements = []
  37. let extraText = null
  38. let extraElement = null
  39. let vIf = false
  40. for (const child of element.children) {
  41. if (child.type === 'VElement') {
  42. if (rootElements.length === 0) {
  43. rootElements.push(child)
  44. vIf = utils.hasDirective(child, 'if')
  45. } else if (vIf && utils.hasDirective(child, 'else-if')) {
  46. rootElements.push(child)
  47. } else if (vIf && utils.hasDirective(child, 'else')) {
  48. rootElements.push(child)
  49. vIf = false
  50. } else {
  51. extraElement = child
  52. }
  53. } else if (sourceCode.getText(child).trim() !== '') {
  54. extraText = child
  55. }
  56. }
  57. if (extraText != null) {
  58. context.report({
  59. node: extraText,
  60. loc: extraText.loc,
  61. message: 'The template root requires an element rather than texts.'
  62. })
  63. } else if (extraElement != null) {
  64. context.report({
  65. node: extraElement,
  66. loc: extraElement.loc,
  67. message: 'The template root requires exactly one element.'
  68. })
  69. } else {
  70. for (const element of rootElements) {
  71. const tag = element.startTag
  72. const name = element.name
  73. if (name === 'template' || name === 'slot') {
  74. context.report({
  75. node: tag,
  76. loc: tag.loc,
  77. message: "The template root disallows '<{{name}}>' elements.",
  78. data: { name }
  79. })
  80. }
  81. if (utils.hasDirective(element, 'for')) {
  82. context.report({
  83. node: tag,
  84. loc: tag.loc,
  85. message: "The template root disallows 'v-for' directives."
  86. })
  87. }
  88. }
  89. }
  90. }
  91. }
  92. }
  93. }