/**
 * @author Yosuke Ota
 * See LICENSE file in root directory for full license.
 */
'use strict'

// ------------------------------------------------------------------------------
// Requirements
// ------------------------------------------------------------------------------

const utils = require('../utils')
const casing = require('../utils/casing')

/**
 * @typedef {import('../utils').ComponentProp} ComponentProp
 */

// ------------------------------------------------------------------------------
// Helpers
// ------------------------------------------------------------------------------

const RESERVED = {
  3: ['key', 'ref'],
  2: ['key', 'ref', 'is', 'slot', 'slot-scope', 'slotScope', 'class', 'style']
}

// ------------------------------------------------------------------------------
// Rule Definition
// ------------------------------------------------------------------------------

module.exports = {
  meta: {
    type: 'problem',
    docs: {
      description: 'disallow reserved names in props',
      categories: ['vue3-essential', 'essential'],
      url: 'https://eslint.vuejs.org/rules/no-reserved-props.html',
      defaultOptions: {
        vue2: [{ vueVersion: 2 }]
      }
    },
    fixable: null,
    schema: [
      {
        type: 'object',
        properties: {
          vueVersion: {
            enum: [2, 3]
          }
        },
        additionalProperties: false
      }
    ],
    messages: {
      reserved:
        "'{{propName}}' is a reserved attribute and cannot be used as props."
    }
  },
  /** @param {RuleContext} context */
  create(context) {
    const options = context.options[0] || {}
    /** @type {2|3} */
    const vueVersion = options.vueVersion || 3

    const reserved = new Set(RESERVED[vueVersion])

    /**
     * @param {ComponentProp[]} props
     */
    function processProps(props) {
      for (const prop of props) {
        if (prop.propName != null && reserved.has(prop.propName)) {
          context.report({
            node: prop.node,
            messageId: `reserved`,
            data: {
              propName: casing.kebabCase(prop.propName)
            }
          })
        }
      }
    }

    return utils.compositingVisitors(
      utils.defineScriptSetupVisitor(context, {
        onDefinePropsEnter(_node, props) {
          processProps(props)
        }
      }),
      utils.executeOnVue(context, (obj) => {
        processProps(utils.getComponentPropsFromOptions(obj))
      })
    )
  }
}
