no-multiple-template-root.js 2.6 KB

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