UNPKG

eslint-plugin-vue

Version:

Official ESLint plugin for Vue.js

298 lines (295 loc) 10.1 kB
'use strict'; const require_runtime = require('../_virtual/_rolldown/runtime.js'); const require_index = require('../utils/index.js'); //#region lib/rules/comment-directive.js /** * @author Toru Nagashima <https://github.com/mysticatea> */ var require_comment_directive = /* @__PURE__ */ require_runtime.__commonJSMin(((exports, module) => { const utils = require_index.default; /** * @typedef {object} RuleAndLocation * @property {string} RuleAndLocation.ruleId * @property {number} RuleAndLocation.index * @property {string} [RuleAndLocation.key] */ const COMMENT_DIRECTIVE_B = /^\s*(eslint-(?:en|dis)able)(?:\s+|$)/; const COMMENT_DIRECTIVE_L = /^\s*(eslint-disable(?:-next)?-line)(?:\s+|$)/; /** * Remove the ignored part from a given directive comment and trim it. * @param {string} value The comment text to strip. * @returns {string} The stripped text. */ function stripDirectiveComment(value) { return value.split(/\s-{2,}\s/u)[0]; } /** * Parse a given comment. * @param {RegExp} pattern The RegExp pattern to parse. * @param {string} comment The comment value to parse. * @returns {({type:string,rules:RuleAndLocation[]})|null} The parsing result. */ function parse(pattern, comment) { const text = stripDirectiveComment(comment); const match = pattern.exec(text); if (match == null) return null; const type = match[1]; /** @type {RuleAndLocation[]} */ const rules = []; const rulesRe = /([^\s,]+)[\s,]*/g; let startIndex = match[0].length; rulesRe.lastIndex = startIndex; let res; while (res = rulesRe.exec(text)) { const ruleId = res[1].trim(); rules.push({ ruleId, index: startIndex }); startIndex = rulesRe.lastIndex; } return { type, rules }; } /** * Enable rules. * @param {RuleContext} context The rule context. * @param {{line:number,column:number}} loc The location information to enable. * @param { 'block' | 'line' } group The group to enable. * @param {string | null} rule The rule ID to enable. * @returns {void} */ function enable(context, loc, group, rule) { if (rule) context.report({ loc, messageId: group === "block" ? "enableBlockRule" : "enableLineRule", data: { rule } }); else context.report({ loc, messageId: group === "block" ? "enableBlock" : "enableLine" }); } /** * Disable rules. * @param {RuleContext} context The rule context. * @param {{line:number,column:number}} loc The location information to disable. * @param { 'block' | 'line' } group The group to disable. * @param {string | null} rule The rule ID to disable. * @param {string} key The disable directive key. * @returns {void} */ function disable(context, loc, group, rule, key) { if (rule) context.report({ loc, messageId: group === "block" ? "disableBlockRule" : "disableLineRule", data: { rule, key } }); else context.report({ loc, messageId: group === "block" ? "disableBlock" : "disableLine", data: { key } }); } /** * Process a given comment token. * If the comment is `eslint-disable` or `eslint-enable` then it reports the comment. * @param {RuleContext} context The rule context. * @param {Token} comment The comment token to process. * @param {boolean} reportUnusedDisableDirectives To report unused eslint-disable comments. * @returns {void} */ function processBlock(context, comment, reportUnusedDisableDirectives) { const parsed = parse(COMMENT_DIRECTIVE_B, comment.value); if (parsed === null) return; if (parsed.type === "eslint-disable") if (parsed.rules.length > 0) { const rules = reportUnusedDisableDirectives ? reportUnusedRules(context, comment, parsed.type, parsed.rules) : parsed.rules; for (const rule of rules) disable(context, comment.loc.start, "block", rule.ruleId, rule.key || "*"); } else { const key = reportUnusedDisableDirectives ? reportUnused(context, comment, parsed.type) : ""; disable(context, comment.loc.start, "block", null, key); } else if (parsed.rules.length > 0) for (const rule of parsed.rules) enable(context, comment.loc.start, "block", rule.ruleId); else enable(context, comment.loc.start, "block", null); } /** * Process a given comment token. * If the comment is `eslint-disable-line` or `eslint-disable-next-line` then it reports the comment. * @param {RuleContext} context The rule context. * @param {Token} comment The comment token to process. * @param {boolean} reportUnusedDisableDirectives To report unused eslint-disable comments. * @returns {void} */ function processLine(context, comment, reportUnusedDisableDirectives) { const parsed = parse(COMMENT_DIRECTIVE_L, comment.value); if (parsed != null && comment.loc.start.line === comment.loc.end.line) { const line = comment.loc.start.line + (parsed.type === "eslint-disable-line" ? 0 : 1); const column = -1; if (parsed.rules.length > 0) { const rules = reportUnusedDisableDirectives ? reportUnusedRules(context, comment, parsed.type, parsed.rules) : parsed.rules; for (const rule of rules) { disable(context, { line, column }, "line", rule.ruleId, rule.key || ""); enable(context, { line: line + 1, column }, "line", rule.ruleId); } } else { const key = reportUnusedDisableDirectives ? reportUnused(context, comment, parsed.type) : ""; disable(context, { line, column }, "line", null, key); enable(context, { line: line + 1, column }, "line", null); } } } /** * Reports unused disable directive. * Do not check the use of directives here. Filter the directives used with postprocess. * @param {RuleContext} context The rule context. * @param {Token} comment The comment token to report. * @param {string} kind The comment directive kind. * @returns {string} The report key */ function reportUnused(context, comment, kind) { const loc = comment.loc; context.report({ loc, messageId: "unused", data: { kind } }); return locToKey(loc.start); } /** * Reports unused disable directive rules. * Do not check the use of directives here. Filter the directives used with postprocess. * @param {RuleContext} context The rule context. * @param {Token} comment The comment token to report. * @param {string} kind The comment directive kind. * @param {RuleAndLocation[]} rules To report rule. * @returns { { ruleId: string, key: string }[] } */ function reportUnusedRules(context, comment, kind, rules) { const sourceCode = context.sourceCode; const commentStart = comment.range[0] + 4; return rules.map((rule) => { const start = sourceCode.getLocFromIndex(commentStart + rule.index); const end = sourceCode.getLocFromIndex(commentStart + rule.index + rule.ruleId.length); context.report({ loc: { start, end }, messageId: "unusedRule", data: { rule: rule.ruleId, kind } }); return { ruleId: rule.ruleId, key: locToKey(start) }; }); } /** * Gets the key of location * @param {Position} location The location * @returns {string} The key */ function locToKey(location) { return `line:${location.line},column${location.column}`; } /** * Extracts the top-level elements in document fragment. * @param {VDocumentFragment} documentFragment The document fragment. * @returns {VElement[]} The top-level elements */ function extractTopLevelHTMLElements(documentFragment) { return documentFragment.children.filter(utils.isVElement); } /** * Extracts the top-level comments in document fragment. * @param {VDocumentFragment} documentFragment The document fragment. * @returns {Token[]} The top-level comments */ function extractTopLevelDocumentFragmentComments(documentFragment) { const elements = extractTopLevelHTMLElements(documentFragment); return documentFragment.comments.filter((comment) => elements.every((element) => comment.range[1] <= element.range[0] || element.range[1] <= comment.range[0])); } module.exports = { meta: { type: "problem", docs: { description: "support comment-directives in `<template>`", categories: ["base"], url: "https://eslint.vuejs.org/rules/comment-directive.html" }, schema: [{ type: "object", properties: { reportUnusedDisableDirectives: { type: "boolean" } }, additionalProperties: false }], messages: { disableBlock: "--block {{key}}", enableBlock: "++block", disableLine: "--line {{key}}", enableLine: "++line", disableBlockRule: "-block {{rule}} {{key}}", enableBlockRule: "+block {{rule}}", disableLineRule: "-line {{rule}} {{key}}", enableLineRule: "+line {{rule}}", clear: "clear", unused: "Unused {{kind}} directive (no problems were reported).", unusedRule: "Unused {{kind}} directive (no problems were reported from '{{rule}}')." } }, create(context) { /** @type {boolean} */ const reportUnusedDisableDirectives = (context.options[0] || {}).reportUnusedDisableDirectives; const sourceCode = context.sourceCode; const documentFragment = sourceCode.parserServices.getDocumentFragment && sourceCode.parserServices.getDocumentFragment(); return { Program(node) { if (node.templateBody) { for (const comment of node.templateBody.comments) { processBlock(context, comment, reportUnusedDisableDirectives); processLine(context, comment, reportUnusedDisableDirectives); } context.report({ loc: node.templateBody.loc.end, messageId: "clear" }); } if (documentFragment) { for (const comment of extractTopLevelDocumentFragmentComments(documentFragment)) { processBlock(context, comment, reportUnusedDisableDirectives); processLine(context, comment, reportUnusedDisableDirectives); } for (const element of extractTopLevelHTMLElements(documentFragment)) context.report({ loc: element.loc.end, messageId: "clear" }); } } }; } }; })); //#endregion Object.defineProperty(exports, 'default', { enumerable: true, get: function () { return require_comment_directive(); } });