UNPKG

eslint-plugin-vue

Version:

Official ESLint plugin for Vue.js

132 lines (129 loc) 4.64 kB
'use strict'; const require_rolldown_runtime = require('../_virtual/rolldown_runtime.js'); const require_index = require('../utils/index.js'); const require_casing$1 = require('../utils/casing.js'); //#region lib/rules/v-bind-style.js /** * @author Toru Nagashima * @copyright 2017 Toru Nagashima. All rights reserved. * See LICENSE file in root directory for full license. */ var require_v_bind_style = /* @__PURE__ */ require_rolldown_runtime.__commonJSMin(((exports, module) => { const utils = require_index.default; const casing = require_casing$1.default; /** * @typedef { VDirectiveKey & { name: VIdentifier & { name: 'bind' }, argument: VExpressionContainer | VIdentifier } } VBindDirectiveKey * @typedef { VDirective & { key: VBindDirectiveKey } } VBindDirective */ /** * @param {string} name * @returns {string} */ function kebabCaseToCamelCase(name) { return casing.isKebabCase(name) ? casing.camelCase(name) : name; } /** * @param {VBindDirective} node * @returns {boolean} */ function isSameName(node) { const attrName = node.key.argument.type === "VIdentifier" ? node.key.argument.rawName : null; const valueName = node.value?.expression?.type === "Identifier" ? node.value.expression.name : null; if (!attrName || !valueName) return false; return kebabCaseToCamelCase(attrName) === kebabCaseToCamelCase(valueName); } /** * @param {VBindDirectiveKey} key * @returns {number} */ function getCutStart(key) { const lastModifier = key.modifiers.at(-1); return lastModifier ? lastModifier.range[1] : key.argument.range[1]; } module.exports = { meta: { type: "suggestion", docs: { description: "enforce `v-bind` directive style", categories: ["vue3-strongly-recommended", "vue2-strongly-recommended"], url: "https://eslint.vuejs.org/rules/v-bind-style.html" }, fixable: "code", schema: [{ enum: ["shorthand", "longform"] }, { type: "object", properties: { sameNameShorthand: { enum: [ "always", "never", "ignore" ] } }, additionalProperties: false }], messages: { expectedLonghand: "Expected 'v-bind' before ':'.", unexpectedLonghand: "Unexpected 'v-bind' before ':'.", expectedLonghandForProp: "Expected 'v-bind:' instead of '.'.", expectedShorthand: "Expected same-name shorthand.", unexpectedShorthand: "Unexpected same-name shorthand." } }, create(context) { const preferShorthand = context.options[0] !== "longform"; /** @type {"always" | "never" | "ignore"} */ const sameNameShorthand = context.options[1]?.sameNameShorthand || "ignore"; /** @param {VBindDirective} node */ function checkAttributeStyle(node) { const shorthandProp = node.key.name.rawName === "."; if ((node.key.name.rawName === ":" || shorthandProp) === preferShorthand) return; let messageId = "expectedLonghand"; if (preferShorthand) messageId = "unexpectedLonghand"; else if (shorthandProp) messageId = "expectedLonghandForProp"; context.report({ node, loc: node.loc, messageId, *fix(fixer) { if (preferShorthand) yield fixer.remove(node.key.name); else { yield fixer.insertTextBefore(node, "v-bind"); if (shorthandProp) { yield fixer.replaceText(node.key.name, ":"); const modifier = node.key.modifiers[0]; if (modifier.name === "prop" && modifier.rawName === "") yield fixer.insertTextBefore(modifier, ".prop"); } } } }); } /** @param {VBindDirective} node */ function checkAttributeSameName(node) { if (sameNameShorthand === "ignore" || !isSameName(node)) return; const preferShorthand$1 = sameNameShorthand === "always"; if (utils.isVBindSameNameShorthand(node) === preferShorthand$1) return; const messageId = preferShorthand$1 ? "expectedShorthand" : "unexpectedShorthand"; context.report({ node, loc: node.loc, messageId, *fix(fixer) { if (preferShorthand$1) { /** @type {Range} */ const valueRange = [getCutStart(node.key), node.range[1]]; yield fixer.removeRange(valueRange); } else if (node.key.argument.type === "VIdentifier") yield fixer.insertTextAfter(node, `="${kebabCaseToCamelCase(node.key.argument.rawName)}"`); } }); } return utils.defineTemplateBodyVisitor(context, { "VAttribute[directive=true][key.name.name='bind'][key.argument!=null]"(node) { checkAttributeSameName(node); checkAttributeStyle(node); } }); } }; })); //#endregion Object.defineProperty(exports, 'default', { enumerable: true, get: function () { return require_v_bind_style(); } });