text: /**
   * @author Toru Nagashima
   * @copyright 2016 Toru Nagashima. All rights reserved.
   * See LICENSE file in root directory for full license.
   */
  'use strict'
  
  // ------------------------------------------------------------------------------
  // Requirements
  // ------------------------------------------------------------------------------
  
  const utils = require('../utils')
  
  // ------------------------------------------------------------------------------
  // Helpers
  // ------------------------------------------------------------------------------
  
  function getPhrase (lineBreaks) {
    switch (lineBreaks) {
      case 0: return 'no line breaks'
      case 1: return '1 line break'
      default: return `${lineBreaks} line breaks`
    }
  }
  
  // ------------------------------------------------------------------------------
  // Rule Definition
  // ------------------------------------------------------------------------------
  
  module.exports = {
    meta: {
      docs: {
        description: "require or disallow a line break before tag's closing brackets",
        category: undefined,
        url: 'https://github.com/vuejs/eslint-plugin-vue/blob/v4.5.0/docs/rules/html-closing-bracket-newline.md'
      },
      fixable: 'whitespace',
      schema: [{
        type: 'object',
        properties: {
          'singleline': { enum: ['always', 'never'] },
          'multiline': { enum: ['always', 'never'] }
        },
        additionalProperties: false
      }]
    },
  
    create (context) {
      const options = context.options[0] || {}
      const template = context.parserServices.getTemplateBodyTokenStore && context.parserServices.getTemplateBodyTokenStore()
  
      return utils.defineTemplateBodyVisitor(context, {
        'VStartTag, VEndTag' (node) {
          const closingBracketToken = template.getLastToken(node)
          if (closingBracketToken.type !== 'HTMLSelfClosingTagClose' && closingBracketToken.type !== 'HTMLTagClose') {
            return
          }
  
          const prevToken = template.getTokenBefore(closingBracketToken)
          const type = (node.loc.start.line === prevToken.loc.end.line) ? 'singleline' : 'multiline'
          const expectedLineBreaks = (options[type] === 'always') ? 1 : 0
          const actualLineBreaks = (closingBracketToken.loc.start.line - prevToken.loc.end.line)
  
          if (actualLineBreaks !== expectedLineBreaks) {
            context.report({
              node,
              loc: {
                start: prevToken.loc.end,
                end: closingBracketToken.loc.start
              },
              message: 'Expected {{expected}} before closing bracket, but {{actual}} found.',
              data: {
                expected: getPhrase(expectedLineBreaks),
                actual: getPhrase(actualLineBreaks)
              },
              fix (fixer) {
                const range = [prevToken.range[1], closingBracketToken.range[0]]
                const text = '\n'.repeat(expectedLineBreaks)
                return fixer.replaceTextRange(range, text)
              }
            })
          }
        }
      })
    }
  }
  