diff --git a/.changeset/beige-teams-camp.md b/.changeset/beige-teams-camp.md
new file mode 100644
index 000000000..49c2a317b
--- /dev/null
+++ b/.changeset/beige-teams-camp.md
@@ -0,0 +1,5 @@
+---
+'eslint-plugin-vue': minor
+---
+
+Added `ignoreParents` option to [`vue/no-deprecated-slot-attribute`](https://eslint.vuejs.org/rules/no-deprecated-slot-attribute.html)
diff --git a/.changeset/eight-camels-refuse.md b/.changeset/eight-camels-refuse.md
new file mode 100644
index 000000000..527b123e4
--- /dev/null
+++ b/.changeset/eight-camels-refuse.md
@@ -0,0 +1,5 @@
+---
+"eslint-plugin-vue": patch
+---
+
+Resolved TypeScript compatibility issues introduced by eslint-typegen
diff --git a/.changeset/strong-masks-fetch.md b/.changeset/strong-masks-fetch.md
new file mode 100644
index 000000000..b7b3b22a0
--- /dev/null
+++ b/.changeset/strong-masks-fetch.md
@@ -0,0 +1,5 @@
+---
+'eslint-plugin-vue': patch
+---
+
+Fixed inconsistent quotes in [`vue/block-lang`](https://eslint.vuejs.org/rules/block-lang.html) error messages
diff --git a/.changeset/true-pumas-open.md b/.changeset/true-pumas-open.md
new file mode 100644
index 000000000..7a49b0f25
--- /dev/null
+++ b/.changeset/true-pumas-open.md
@@ -0,0 +1,5 @@
+---
+'eslint-plugin-vue': minor
+---
+
+Added new [`vue/no-negated-condition`](https://eslint.vuejs.org/rules/no-negated-condition.html) rule
diff --git a/docs/developer-guide/index.md b/docs/developer-guide/index.md
index 2e1bb7da9..9bfc68007 100644
--- a/docs/developer-guide/index.md
+++ b/docs/developer-guide/index.md
@@ -8,6 +8,15 @@ If you think you’ve found a bug in ESLint, please [create a new issue](https:/
Please include as much detail as possible to help us properly address your issue. If we need to triage issues and constantly ask people for more detail, that’s time taken away from actually fixing issues. Help us be as efficient as possible by including a lot of detail in your issues.
+## :seedling: Project Setup
+
+To develop locally, fork the eslint-plugin-vue repository and clone it in your local machine. Use the [npm](https://www.npmjs.com/) package manager to install and link dependencies and the LTS version of [Node.js](https://nodejs.org/).
+
+To develop and test the `eslint-plugin-vue` package:
+
+1. Run `npm install` in the project's root folder.
+2. Run `npm test` to make sure everything is set up correctly.
+
## :sparkles: Proposing a new rule or a rule change
In order to add a new rule or a rule change, you should:
diff --git a/docs/rules/index.md b/docs/rules/index.md
index 6423ef365..34462fba0 100644
--- a/docs/rules/index.md
+++ b/docs/rules/index.md
@@ -327,6 +327,7 @@ The following rules extend the rules provided by ESLint itself and apply them to
| [vue/no-implicit-coercion] | Disallow shorthand type conversions in `` | :wrench::bulb: | :hammer: |
| [vue/no-irregular-whitespace] | disallow irregular whitespace in `.vue` files | | :warning: |
| [vue/no-loss-of-precision] | Disallow literal numbers that lose precision in `` | | :warning: |
+| [vue/no-negated-condition] | Disallow negated conditions in `` | | :hammer: |
| [vue/no-restricted-syntax] | Disallow specified syntax in `` | | :hammer: |
| [vue/no-sparse-arrays] | Disallow sparse arrays in `` | | :warning: |
| [vue/no-useless-concat] | Disallow unnecessary concatenation of literals or template literals in `` | | :hammer: |
@@ -482,6 +483,7 @@ The following rules extend the rules provided by ESLint itself and apply them to
[vue/no-multiple-slot-args]: ./no-multiple-slot-args.md
[vue/no-multiple-template-root]: ./no-multiple-template-root.md
[vue/no-mutating-props]: ./no-mutating-props.md
+[vue/no-negated-condition]: ./no-negated-condition.md
[vue/no-parsing-error]: ./no-parsing-error.md
[vue/no-potential-component-option-typo]: ./no-potential-component-option-typo.md
[vue/no-ref-as-operand]: ./no-ref-as-operand.md
diff --git a/docs/rules/no-deprecated-slot-attribute.md b/docs/rules/no-deprecated-slot-attribute.md
index df4575cc4..34f941ec4 100644
--- a/docs/rules/no-deprecated-slot-attribute.md
+++ b/docs/rules/no-deprecated-slot-attribute.md
@@ -43,16 +43,18 @@ This rule reports deprecated `slot` attribute in Vue.js v2.6.0+.
```json
{
"vue/no-deprecated-slot-attribute": ["error", {
- "ignore": ["my-component"]
+ "ignore": ["my-component"],
+ "ignoreParents": ["my-web-component"],
}]
}
```
- `"ignore"` (`string[]`) An array of tags or regular expression patterns (e.g. `/^custom-/`) that ignore these rules. This option will check both kebab-case and PascalCase versions of the given tag names. Default is empty.
+- `"ignoreParents"` (`string[]`) An array of tags or regular expression patterns (e.g. `/^custom-/`) for parents that ignore these rules. This option is especially useful for [Web-Components](https://developer.mozilla.org/en-US/docs/Web/API/Web_components). Default is empty.
### `"ignore": ["my-component"]`
-
+
```vue
@@ -81,9 +83,41 @@ This rule reports deprecated `slot` attribute in Vue.js v2.6.0+.
+### `"ignoreParents": ["my-web-component"]`
+
+
+
+```vue
+
+
+
+
+ {{ props.title }}
+
+
+
+
+
+
+ {{ props.title }}
+
+
+
+
+
+
+ {{ props.title }}
+
+
+
+```
+
+
+
## :books: Further Reading
- [API - slot](https://v2.vuejs.org/v2/api/#slot-deprecated)
+- [Web - slot](https://developer.mozilla.org/en-US/docs/Web/API/Element/slot)
## :rocket: Version
diff --git a/docs/rules/no-negated-condition.md b/docs/rules/no-negated-condition.md
new file mode 100644
index 000000000..e389172ae
--- /dev/null
+++ b/docs/rules/no-negated-condition.md
@@ -0,0 +1,33 @@
+---
+pageClass: rule-details
+sidebarDepth: 0
+title: vue/no-negated-condition
+description: Disallow negated conditions in ``
+---
+
+# vue/no-negated-condition
+
+> Disallow negated conditions in ``
+
+- :exclamation: _**This rule has not been released yet.**_
+
+## :book: Rule Details
+
+This rule is the same rule as core [no-negated-condition] rule but it applies to the expressions in ``.
+
+## :couple: Related Rules
+
+- [unicorn/no-negated-condition](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/no-negated-condition.md)
+
+## :books: Further Reading
+
+- [no-negated-condition]
+
+[no-negated-condition]: https://eslint.org/docs/rules/no-negated-condition
+
+## :mag: Implementation
+
+- [Rule source](https://github.com/vuejs/eslint-plugin-vue/blob/master/lib/rules/no-negated-condition.js)
+- [Test source](https://github.com/vuejs/eslint-plugin-vue/blob/master/tests/lib/rules/no-negated-condition.js)
+
+Taken with ❤️ [from ESLint core](https://eslint.org/docs/latest/rules/no-negated-condition)
diff --git a/docs/rules/padding-line-between-blocks.md b/docs/rules/padding-line-between-blocks.md
index 4f3ee0290..645efeac7 100644
--- a/docs/rules/padding-line-between-blocks.md
+++ b/docs/rules/padding-line-between-blocks.md
@@ -14,7 +14,7 @@ since: v6.2.0
## :book: Rule Details
-This rule requires or disallows blank lines between the given 2 blocks. Properly blank lines help developers to understand the code.
+This rule requires or disallows blank lines between blocks. Properly placed blank lines help developers understand the code.
diff --git a/lib/index.js b/lib/index.js
index e511536fa..bfc35b11a 100644
--- a/lib/index.js
+++ b/lib/index.js
@@ -141,6 +141,7 @@ const plugin = {
'no-multiple-slot-args': require('./rules/no-multiple-slot-args'),
'no-multiple-template-root': require('./rules/no-multiple-template-root'),
'no-mutating-props': require('./rules/no-mutating-props'),
+ 'no-negated-condition': require('./rules/no-negated-condition'),
'no-parsing-error': require('./rules/no-parsing-error'),
'no-potential-component-option-typo': require('./rules/no-potential-component-option-typo'),
'no-ref-as-operand': require('./rules/no-ref-as-operand'),
diff --git a/lib/rules/attribute-hyphenation.js b/lib/rules/attribute-hyphenation.js
index 65d096cd4..45e7ca687 100644
--- a/lib/rules/attribute-hyphenation.js
+++ b/lib/rules/attribute-hyphenation.js
@@ -6,7 +6,7 @@
const utils = require('../utils')
const casing = require('../utils/casing')
-const { toRegExp } = require('../utils/regexp')
+const { toRegExpGroupMatcher } = require('../utils/regexp')
const svgAttributes = require('../utils/svg-attributes-weird-case.json')
/**
@@ -79,11 +79,7 @@ module.exports = {
const option = context.options[0]
const optionsPayload = context.options[1]
const useHyphenated = option !== 'never'
- /** @type {RegExp[]} */
- const ignoredTagsRegexps = (
- (optionsPayload && optionsPayload.ignoreTags) ||
- []
- ).map(toRegExp)
+ const isIgnoredTagName = toRegExpGroupMatcher(optionsPayload?.ignoreTags)
const ignoredAttributes = ['data-', 'aria-', 'slot-scope', ...svgAttributes]
if (optionsPayload && optionsPayload.ignore) {
@@ -142,11 +138,6 @@ module.exports = {
return useHyphenated ? value.toLowerCase() === value : !/-/.test(value)
}
- /** @param {string} name */
- function isIgnoredTagName(name) {
- return ignoredTagsRegexps.some((re) => re.test(name))
- }
-
return utils.defineTemplateBodyVisitor(context, {
VAttribute(node) {
const element = node.parent.parent
diff --git a/lib/rules/block-lang.js b/lib/rules/block-lang.js
index 2190b17cb..8fccd29f9 100644
--- a/lib/rules/block-lang.js
+++ b/lib/rules/block-lang.js
@@ -40,7 +40,7 @@ const DEFAULT_LANGUAGES = {
* @param {NonNullable} lang
*/
function getAllowsLangPhrase(lang) {
- const langs = [...lang].map((s) => `"${s}"`)
+ const langs = [...lang].map((s) => `'${s}'`)
switch (langs.length) {
case 1: {
return langs[0]
@@ -157,7 +157,7 @@ module.exports = {
missing: "The 'lang' attribute of '<{{tag}}>' is missing.",
unexpected: "Do not specify the 'lang' attribute of '<{{tag}}>'.",
useOrNot:
- "Only {{allows}} can be used for the 'lang' attribute of '<{{tag}}>'. Or, not specifying the `lang` attribute is allowed.",
+ "Only {{allows}} can be used for the 'lang' attribute of '<{{tag}}>'. Or, not specifying the 'lang' attribute is allowed.",
unexpectedDefault:
"Do not explicitly specify the default language for the 'lang' attribute of '<{{tag}}>'."
}
diff --git a/lib/rules/component-name-in-template-casing.js b/lib/rules/component-name-in-template-casing.js
index d330f60da..c7267cd49 100644
--- a/lib/rules/component-name-in-template-casing.js
+++ b/lib/rules/component-name-in-template-casing.js
@@ -6,7 +6,7 @@
const utils = require('../utils')
const casing = require('../utils/casing')
-const { toRegExp } = require('../utils/regexp')
+const { toRegExpGroupMatcher } = require('../utils/regexp')
const allowedCaseOptions = ['PascalCase', 'kebab-case']
const defaultCase = 'PascalCase'
@@ -81,8 +81,7 @@ module.exports = {
const caseType = allowedCaseOptions.includes(caseOption)
? caseOption
: defaultCase
- /** @type {RegExp[]} */
- const ignores = (options.ignores || []).map(toRegExp)
+ const isIgnored = toRegExpGroupMatcher(options.ignores)
/** @type {string[]} */
const globals = (options.globals || []).map(casing.pascalCase)
const registeredComponentsOnly = options.registeredComponentsOnly !== false
@@ -116,7 +115,7 @@ module.exports = {
* @returns {boolean} `true` if the given node is the verification target node.
*/
function isVerifyTarget(node) {
- if (ignores.some((re) => re.test(node.rawName))) {
+ if (isIgnored(node.rawName)) {
// ignore
return false
}
diff --git a/lib/rules/custom-event-name-casing.js b/lib/rules/custom-event-name-casing.js
index aff4609b5..c63b4e9d9 100644
--- a/lib/rules/custom-event-name-casing.js
+++ b/lib/rules/custom-event-name-casing.js
@@ -7,7 +7,7 @@
const { findVariable } = require('@eslint-community/eslint-utils')
const utils = require('../utils')
const casing = require('../utils/casing')
-const { toRegExp } = require('../utils/regexp')
+const { toRegExpGroupMatcher } = require('../utils/regexp')
/**
* @typedef {import('../utils').VueObjectData} VueObjectData
@@ -92,8 +92,7 @@ module.exports = {
const caseType = context.options[0] || DEFAULT_CASE
const objectOption = context.options[1] || {}
const caseChecker = casing.getChecker(caseType)
- /** @type {RegExp[]} */
- const ignores = (objectOption.ignores || []).map(toRegExp)
+ const isIgnored = toRegExpGroupMatcher(objectOption.ignores)
/**
* Check whether the given event name is valid.
@@ -109,7 +108,7 @@ module.exports = {
*/
function verify(nameWithLoc) {
const name = nameWithLoc.name
- if (isValidEventName(name) || ignores.some((re) => re.test(name))) {
+ if (isValidEventName(name) || isIgnored(name)) {
return
}
context.report({
diff --git a/lib/rules/no-deprecated-slot-attribute.js b/lib/rules/no-deprecated-slot-attribute.js
index 664c14353..44f3b68c1 100644
--- a/lib/rules/no-deprecated-slot-attribute.js
+++ b/lib/rules/no-deprecated-slot-attribute.js
@@ -25,6 +25,11 @@ module.exports = {
type: 'array',
items: { type: 'string' },
uniqueItems: true
+ },
+ ignoreParents: {
+ type: 'array',
+ items: { type: 'string' },
+ uniqueItems: true
}
},
additionalProperties: false
diff --git a/lib/rules/no-negated-condition.js b/lib/rules/no-negated-condition.js
new file mode 100644
index 000000000..22a9a6fca
--- /dev/null
+++ b/lib/rules/no-negated-condition.js
@@ -0,0 +1,12 @@
+/**
+ * @author Wayne Zhang
+ * See LICENSE file in root directory for full license.
+ */
+'use strict'
+
+const { wrapCoreRule } = require('../utils')
+
+// eslint-disable-next-line internal/no-invalid-meta
+module.exports = wrapCoreRule('no-negated-condition', {
+ applyDocument: true
+})
diff --git a/lib/rules/no-restricted-block.js b/lib/rules/no-restricted-block.js
index 87b4bda3e..000e2c7b8 100644
--- a/lib/rules/no-restricted-block.js
+++ b/lib/rules/no-restricted-block.js
@@ -12,30 +12,16 @@ const regexp = require('../utils/regexp')
* @property {string} [message]
*/
-/**
- * @param {string} str
- * @returns {(str: string) => boolean}
- */
-function buildMatcher(str) {
- if (regexp.isRegExp(str)) {
- const re = regexp.toRegExp(str)
- return (s) => {
- re.lastIndex = 0
- return re.test(s)
- }
- }
- return (s) => s === str
-}
/**
* @param {any} option
* @returns {ParsedOption}
*/
function parseOption(option) {
if (typeof option === 'string') {
- const matcher = buildMatcher(option)
+ const matcher = regexp.toRegExp(option, { remove: 'g' })
return {
test(block) {
- return matcher(block.rawName)
+ return matcher.test(block.rawName)
}
}
}
diff --git a/lib/rules/no-restricted-class.js b/lib/rules/no-restricted-class.js
index 41d30df2d..1a74fd249 100644
--- a/lib/rules/no-restricted-class.js
+++ b/lib/rules/no-restricted-class.js
@@ -12,20 +12,10 @@ const regexp = require('../utils/regexp')
* @param {string} className
* @param {*} node
* @param {RuleContext} context
- * @param {Set} forbiddenClasses
- * @param {Array} forbiddenClassesRegexps
+ * @param {(name: string) => boolean} isForbiddenClass
*/
-const reportForbiddenClass = (
- className,
- node,
- context,
- forbiddenClasses,
- forbiddenClassesRegexps
-) => {
- if (
- forbiddenClasses.has(className) ||
- forbiddenClassesRegexps.some((re) => re.test(className))
- ) {
+const reportForbiddenClass = (className, node, context, isForbiddenClass) => {
+ if (isForbiddenClass(className)) {
const loc = node.value ? node.value.loc : node.loc
context.report({
node,
@@ -123,10 +113,8 @@ module.exports = {
/** @param {RuleContext} context */
create(context) {
- const forbiddenClasses = new Set(context.options || [])
- const forbiddenClassesRegexps = (context.options || [])
- .filter((cl) => regexp.isRegExp(cl))
- .map((cl) => regexp.toRegExp(cl))
+ const { options = [] } = context
+ const isForbiddenClass = regexp.toRegExpGroupMatcher(options)
return utils.defineTemplateBodyVisitor(context, {
/**
@@ -134,13 +122,7 @@ module.exports = {
*/
'VAttribute[directive=false][key.name="class"][value!=null]'(node) {
for (const className of node.value.value.split(/\s+/)) {
- reportForbiddenClass(
- className,
- node,
- context,
- forbiddenClasses,
- forbiddenClassesRegexps
- )
+ reportForbiddenClass(className, node, context, isForbiddenClass)
}
},
@@ -155,13 +137,7 @@ module.exports = {
for (const { className, reportNode } of extractClassNames(
/** @type {Expression} */ (node.expression)
)) {
- reportForbiddenClass(
- className,
- reportNode,
- context,
- forbiddenClasses,
- forbiddenClassesRegexps
- )
+ reportForbiddenClass(className, reportNode, context, isForbiddenClass)
}
}
})
diff --git a/lib/rules/no-restricted-component-names.js b/lib/rules/no-restricted-component-names.js
index e5111a748..df5ad4a23 100644
--- a/lib/rules/no-restricted-component-names.js
+++ b/lib/rules/no-restricted-component-names.js
@@ -22,7 +22,7 @@ const { isRegExp, toRegExp } = require('../utils/regexp')
*/
function buildMatcher(str) {
if (isRegExp(str)) {
- const regex = toRegExp(str)
+ const regex = toRegExp(str, { remove: 'g' })
return (s) => regex.test(s)
}
return (s) => s === casing.pascalCase(str) || s === casing.kebabCase(str)
diff --git a/lib/rules/no-restricted-component-options.js b/lib/rules/no-restricted-component-options.js
index b8563a92b..227a89382 100644
--- a/lib/rules/no-restricted-component-options.js
+++ b/lib/rules/no-restricted-component-options.js
@@ -23,21 +23,6 @@ const regexp = require('../utils/regexp')
* @typedef { (node: Property | SpreadElement) => (MatchResult | null) } Tester
*/
-/**
- * @param {string} str
- * @returns {Matcher}
- */
-function buildMatcher(str) {
- if (regexp.isRegExp(str)) {
- const re = regexp.toRegExp(str)
- return (s) => {
- re.lastIndex = 0
- return re.test(s)
- }
- }
- return (s) => s === str
-}
-
/**
* @param {string | string[] | { name: string | string[], message?: string } } option
* @returns {ParsedOption}
@@ -65,7 +50,8 @@ function parseOption(option) {
if (name === '*') {
steps.push({ wildcard: true })
} else {
- steps.push({ test: buildMatcher(name) })
+ const matcher = regexp.toRegExp(name, { remove: 'g' })
+ steps.push({ test: (value) => matcher.test(value) })
}
}
const message = option.message
diff --git a/lib/rules/no-restricted-custom-event.js b/lib/rules/no-restricted-custom-event.js
index 5ddda037f..93c1aa764 100644
--- a/lib/rules/no-restricted-custom-event.js
+++ b/lib/rules/no-restricted-custom-event.js
@@ -15,30 +15,16 @@ const regexp = require('../utils/regexp')
* @property {string|undefined} [suggest]
*/
-/**
- * @param {string} str
- * @returns {(str: string) => boolean}
- */
-function buildMatcher(str) {
- if (regexp.isRegExp(str)) {
- const re = regexp.toRegExp(str)
- return (s) => {
- re.lastIndex = 0
- return re.test(s)
- }
- }
- return (s) => s === str
-}
/**
* @param {string|{event: string, message?: string, suggest?: string}} option
* @returns {ParsedOption}
*/
function parseOption(option) {
if (typeof option === 'string') {
- const matcher = buildMatcher(option)
+ const matcher = regexp.toRegExp(option, { remove: 'g' })
return {
test(name) {
- return matcher(name)
+ return matcher.test(name)
}
}
}
diff --git a/lib/rules/no-restricted-props.js b/lib/rules/no-restricted-props.js
index 2d2f74bb0..e0684393d 100644
--- a/lib/rules/no-restricted-props.js
+++ b/lib/rules/no-restricted-props.js
@@ -18,30 +18,16 @@ const regexp = require('../utils/regexp')
* @property {string|undefined} [suggest]
*/
-/**
- * @param {string} str
- * @returns {(str: string) => boolean}
- */
-function buildMatcher(str) {
- if (regexp.isRegExp(str)) {
- const re = regexp.toRegExp(str)
- return (s) => {
- re.lastIndex = 0
- return re.test(s)
- }
- }
- return (s) => s === str
-}
/**
* @param {string|{name:string, message?: string, suggest?:string}} option
* @returns {ParsedOption}
*/
function parseOption(option) {
if (typeof option === 'string') {
- const matcher = buildMatcher(option)
+ const matcher = regexp.toRegExp(option, { remove: 'g' })
return {
test(name) {
- return matcher(name)
+ return matcher.test(name)
}
}
}
diff --git a/lib/rules/no-restricted-static-attribute.js b/lib/rules/no-restricted-static-attribute.js
index d9241620b..d7223044a 100644
--- a/lib/rules/no-restricted-static-attribute.js
+++ b/lib/rules/no-restricted-static-attribute.js
@@ -15,30 +15,16 @@ const regexp = require('../utils/regexp')
* @property {string} [message]
*/
-/**
- * @param {string} str
- * @returns {(str: string) => boolean}
- */
-function buildMatcher(str) {
- if (regexp.isRegExp(str)) {
- const re = regexp.toRegExp(str)
- return (s) => {
- re.lastIndex = 0
- return re.test(s)
- }
- }
- return (s) => s === str
-}
/**
* @param {any} option
* @returns {ParsedOption}
*/
function parseOption(option) {
if (typeof option === 'string') {
- const matcher = buildMatcher(option)
+ const matcher = regexp.toRegExp(option, { remove: 'g' })
return {
test({ key }) {
- return matcher(key.rawName)
+ return matcher.test(key.rawName)
}
}
}
@@ -53,25 +39,25 @@ function parseOption(option) {
return node.value == null || node.value.value === node.key.rawName
}
} else {
- const valueMatcher = buildMatcher(option.value)
+ const valueMatcher = regexp.toRegExp(option.value, { remove: 'g' })
parsed.test = (node) => {
if (!keyTest(node)) {
return false
}
- return node.value != null && valueMatcher(node.value.value)
+ return node.value != null && valueMatcher.test(node.value.value)
}
}
parsed.useValue = true
}
if (option.element) {
const argTest = parsed.test
- const tagMatcher = buildMatcher(option.element)
+ const tagMatcher = regexp.toRegExp(option.element, { remove: 'g' })
parsed.test = (node) => {
if (!argTest(node)) {
return false
}
const element = node.parent.parent
- return tagMatcher(element.rawName)
+ return tagMatcher.test(element.rawName)
}
parsed.useElement = true
}
diff --git a/lib/rules/no-restricted-v-bind.js b/lib/rules/no-restricted-v-bind.js
index f9bf5462b..e16622174 100644
--- a/lib/rules/no-restricted-v-bind.js
+++ b/lib/rules/no-restricted-v-bind.js
@@ -22,33 +22,19 @@ const DEFAULT_OPTIONS = [
}
]
-/**
- * @param {string} str
- * @returns {(str: string) => boolean}
- */
-function buildMatcher(str) {
- if (regexp.isRegExp(str)) {
- const re = regexp.toRegExp(str)
- return (s) => {
- re.lastIndex = 0
- return re.test(s)
- }
- }
- return (s) => s === str
-}
/**
* @param {any} option
* @returns {ParsedOption}
*/
function parseOption(option) {
if (typeof option === 'string') {
- const matcher = buildMatcher(option)
+ const matcher = regexp.toRegExp(option, { remove: 'g' })
return {
test(key) {
return Boolean(
key.argument &&
key.argument.type === 'VIdentifier' &&
- matcher(key.argument.rawName)
+ matcher.test(key.argument.rawName)
)
},
modifiers: []
@@ -77,13 +63,13 @@ function parseOption(option) {
}
if (option.element) {
const argTest = parsed.test
- const tagMatcher = buildMatcher(option.element)
+ const tagMatcher = regexp.toRegExp(option.element, { remove: 'g' })
parsed.test = (key) => {
if (!argTest(key)) {
return false
}
const element = key.parent.parent.parent
- return tagMatcher(element.rawName)
+ return tagMatcher.test(element.rawName)
}
parsed.useElement = true
}
diff --git a/lib/rules/no-restricted-v-on.js b/lib/rules/no-restricted-v-on.js
index 2379df349..893d511a6 100644
--- a/lib/rules/no-restricted-v-on.js
+++ b/lib/rules/no-restricted-v-on.js
@@ -15,34 +15,19 @@ const regexp = require('../utils/regexp')
* @property {string} [message]
*/
-/**
- * @param {string} str
- * @returns {(str: string) => boolean}
- */
-function buildMatcher(str) {
- if (regexp.isRegExp(str)) {
- const re = regexp.toRegExp(str)
- return (s) => {
- re.lastIndex = 0
- return re.test(s)
- }
- }
- return (s) => s === str
-}
-
/**
* @param {any} option
* @returns {ParsedOption}
*/
function parseOption(option) {
if (typeof option === 'string') {
- const matcher = buildMatcher(option)
+ const matcher = regexp.toRegExp(option, { remove: 'g' })
return {
test(key) {
return Boolean(
key.argument &&
key.argument.type === 'VIdentifier' &&
- matcher(key.argument.rawName)
+ matcher.test(key.argument.rawName)
)
}
}
@@ -70,12 +55,12 @@ function parseOption(option) {
}
if (option.element) {
const argTest = parsed.test
- const tagMatcher = buildMatcher(option.element)
+ const tagMatcher = regexp.toRegExp(option.element, { remove: 'g' })
parsed.test = (key) => {
if (!argTest(key)) {
return false
}
- return tagMatcher(key.parent.parent.parent.rawName)
+ return tagMatcher.test(key.parent.parent.parent.rawName)
}
parsed.useElement = true
}
diff --git a/lib/rules/no-undef-properties.js b/lib/rules/no-undef-properties.js
index 711c2ed22..3ff49bd83 100644
--- a/lib/rules/no-undef-properties.js
+++ b/lib/rules/no-undef-properties.js
@@ -6,7 +6,7 @@
const utils = require('../utils')
const reserved = require('../utils/vue-reserved.json')
-const { toRegExp } = require('../utils/regexp')
+const { toRegExpGroupMatcher } = require('../utils/regexp')
const { getStyleVariablesContext } = require('../utils/style-variables')
const {
definePropertyReferenceExtractor
@@ -106,9 +106,8 @@ module.exports = {
/** @param {RuleContext} context */
create(context) {
const options = context.options[0] || {}
- const ignores = /** @type {string[]} */ (
- options.ignores || [String.raw`/^\$/`]
- ).map(toRegExp)
+ const { ignores = [String.raw`/^\$/`] } = options
+ const isIgnored = toRegExpGroupMatcher(ignores)
const propertyReferenceExtractor = definePropertyReferenceExtractor(context)
const programNode = context.getSourceCode().ast
/**
@@ -190,7 +189,7 @@ module.exports = {
report(node, name, messageId = 'undef') {
if (
reserved.includes(name) ||
- ignores.some((ignore) => ignore.test(name)) ||
+ isIgnored(name) ||
propertiesDefinedByStoreHelpers.has(name)
) {
return
diff --git a/lib/rules/prefer-true-attribute-shorthand.js b/lib/rules/prefer-true-attribute-shorthand.js
index 817525d1d..3f5446bda 100644
--- a/lib/rules/prefer-true-attribute-shorthand.js
+++ b/lib/rules/prefer-true-attribute-shorthand.js
@@ -4,7 +4,7 @@
*/
'use strict'
-const { toRegExp } = require('../utils/regexp')
+const { toRegExpGroupMatcher } = require('../utils/regexp')
const utils = require('../utils')
/**
@@ -99,8 +99,7 @@ module.exports = {
create(context) {
/** @type {'always' | 'never'} */
const option = context.options[0] || 'always'
- /** @type {RegExp[]} */
- const exceptReg = (context.options[1]?.except || []).map(toRegExp)
+ const exceptMatcher = toRegExpGroupMatcher(context.options[1]?.except)
/**
* @param {VAttribute | VDirective} node
@@ -155,7 +154,7 @@ module.exports = {
const name = getAttributeName(node)
if (name === null) return
- const isExcepted = exceptReg.some((re) => re.test(name))
+ const isExcepted = exceptMatcher(name)
if (shouldConvertToLongForm(node, isExcepted, option)) {
const key = /** @type {VIdentifier} */ (node.key)
diff --git a/lib/rules/prop-name-casing.js b/lib/rules/prop-name-casing.js
index fd4f0dc31..7121c66c6 100644
--- a/lib/rules/prop-name-casing.js
+++ b/lib/rules/prop-name-casing.js
@@ -6,7 +6,7 @@
const utils = require('../utils')
const casing = require('../utils/casing')
-const { toRegExp } = require('../utils/regexp')
+const { toRegExpGroupMatcher } = require('../utils/regexp')
const allowedCaseOptions = ['camelCase', 'snake_case']
/**
@@ -16,8 +16,7 @@ const allowedCaseOptions = ['camelCase', 'snake_case']
/** @param {RuleContext} context */
function create(context) {
const options = context.options[0]
- /** @type {RegExp[]} */
- const ignoreProps = (context.options[1]?.ignoreProps || []).map(toRegExp)
+ const isIgnoredProp = toRegExpGroupMatcher(context.options[1]?.ignoreProps)
const caseType = allowedCaseOptions.includes(options) ? options : 'camelCase'
const checker = casing.getChecker(caseType)
@@ -30,7 +29,7 @@ function create(context) {
if (propName == null) {
continue
}
- if (!checker(propName) && !ignoreProps.some((re) => re.test(propName))) {
+ if (!checker(propName) && !isIgnoredProp(propName)) {
context.report({
node: item.node,
messageId: 'invalidCase',
diff --git a/lib/rules/restricted-component-names.js b/lib/rules/restricted-component-names.js
index 636224db6..89d04bfad 100644
--- a/lib/rules/restricted-component-names.js
+++ b/lib/rules/restricted-component-names.js
@@ -5,7 +5,7 @@
'use strict'
const utils = require('../utils')
-const { toRegExp } = require('../utils/regexp')
+const { toRegExpGroupMatcher } = require('../utils/regexp')
const htmlElements = require('../utils/html-elements.json')
const deprecatedHtmlElements = require('../utils/deprecated-html-elements.json')
@@ -51,12 +51,11 @@ module.exports = {
/** @param {RuleContext} context */
create(context) {
const options = context.options[0] || {}
- /** @type {RegExp[]} */
- const allow = (options.allow || []).map(toRegExp)
+ const isAllowed = toRegExpGroupMatcher(options.allow)
/** @param {string} name */
function isAllowedTarget(name) {
- return reservedNames.has(name) || allow.some((re) => re.test(name))
+ return reservedNames.has(name) || isAllowed(name)
}
return utils.defineTemplateBodyVisitor(context, {
diff --git a/lib/rules/syntaxes/slot-attribute.js b/lib/rules/syntaxes/slot-attribute.js
index b77fc6c20..87fe9404c 100644
--- a/lib/rules/syntaxes/slot-attribute.js
+++ b/lib/rules/syntaxes/slot-attribute.js
@@ -7,17 +7,18 @@
const canConvertToVSlot = require('./utils/can-convert-to-v-slot')
const regexp = require('../../utils/regexp')
const casing = require('../../utils/casing')
+const { isVElement } = require('../../utils')
module.exports = {
deprecated: '2.6.0',
supported: '<3.0.0',
/** @param {RuleContext} context @returns {TemplateListener} */
createTemplateBodyVisitor(context) {
- /** @type {{ ignore: string[] }} */
+ /** @type {{ ignore: string[], ignoreParents: string[] }} */
const options = context.options[0] || {}
- const { ignore = [] } = options
- /** @type {RegExp[]} */
- const ignorePatterns = ignore.map(regexp.toRegExp)
+ const { ignore = [], ignoreParents = [] } = options
+ const isAnyIgnored = regexp.toRegExpGroupMatcher(ignore)
+ const isParentIgnored = regexp.toRegExpGroupMatcher(ignoreParents)
const sourceCode = context.getSourceCode()
const tokenStore =
@@ -124,21 +125,25 @@ module.exports = {
* @returns {void}
*/
function reportSlot(slotAttr) {
- const componentName = slotAttr.parent.parent.rawName
- const componentNamePascalCase = casing.pascalCase(componentName)
- const componentNameKebabCase = casing.kebabCase(componentName)
+ const component = slotAttr.parent.parent
+ const componentName = component.rawName
if (
- ignorePatterns.some(
- (pattern) =>
- pattern.test(componentName) ||
- pattern.test(componentNamePascalCase) ||
- pattern.test(componentNameKebabCase)
+ isAnyIgnored(
+ componentName,
+ casing.pascalCase(componentName),
+ casing.kebabCase(componentName)
)
) {
return
}
+ const parent = component.parent
+ const parentName = isVElement(parent) ? parent.rawName : null
+ if (parentName && isParentIgnored(parentName)) {
+ return
+ }
+
context.report({
node: slotAttr.key,
messageId: 'forbiddenSlotAttribute',
diff --git a/lib/rules/v-on-event-hyphenation.js b/lib/rules/v-on-event-hyphenation.js
index c9fac76e8..056890fa0 100644
--- a/lib/rules/v-on-event-hyphenation.js
+++ b/lib/rules/v-on-event-hyphenation.js
@@ -2,7 +2,7 @@
const utils = require('../utils')
const casing = require('../utils/casing')
-const { toRegExp } = require('../utils/regexp')
+const { toRegExpGroupMatcher } = require('../utils/regexp')
module.exports = {
meta: {
@@ -63,11 +63,7 @@ module.exports = {
const useHyphenated = option !== 'never'
/** @type {string[]} */
const ignoredAttributes = (optionsPayload && optionsPayload.ignore) || []
- /** @type {RegExp[]} */
- const ignoredTagsRegexps = (
- (optionsPayload && optionsPayload.ignoreTags) ||
- []
- ).map(toRegExp)
+ const isIgnoredTag = toRegExpGroupMatcher(optionsPayload?.ignoreTags)
const autofix = Boolean(optionsPayload && optionsPayload.autofix)
const caseConverter = casing.getConverter(
@@ -111,17 +107,12 @@ module.exports = {
return useHyphenated ? value.toLowerCase() === value : !/-/.test(value)
}
- /** @param {string} name */
- function isIgnoredTagName(name) {
- return ignoredTagsRegexps.some((re) => re.test(name))
- }
-
return utils.defineTemplateBodyVisitor(context, {
"VAttribute[directive=true][key.name.name='on']"(node) {
const element = node.parent.parent
if (
!utils.isCustomComponent(element) ||
- isIgnoredTagName(element.rawName)
+ isIgnoredTag(element.rawName)
) {
return
}
diff --git a/lib/utils/index.js b/lib/utils/index.js
index f83b000f7..f3f14cd8a 100644
--- a/lib/utils/index.js
+++ b/lib/utils/index.js
@@ -2462,7 +2462,7 @@ function isAssignmentProperty(node) {
}
/**
* Checks whether the given node is VElement.
- * @param {VElement | VExpressionContainer | VText} node
+ * @param {VElement | VExpressionContainer | VText | VDocumentFragment} node
* @returns {node is VElement}
*/
function isVElement(node) {
diff --git a/lib/utils/regexp.js b/lib/utils/regexp.js
index 3ee40ae41..006568067 100644
--- a/lib/utils/regexp.js
+++ b/lib/utils/regexp.js
@@ -22,14 +22,25 @@ function escape(string) {
* Strings like `"/^foo/i"` are converted to `/^foo/i` of `RegExp`.
*
* @param {string} string The string to convert.
+ * @param {{add?: string, remove?: string}} [flags] The flags to add or remove.
+ * - `add`: Flags to add to the `RegExp` (e.g. `'i'` for case-insensitive).
+ * - `remove`: Flags to remove from the `RegExp` (e.g. `'g'` to remove global matching).
* @returns {RegExp} Returns the `RegExp`.
*/
-function toRegExp(string) {
+function toRegExp(string, flags = {}) {
const parts = RE_REGEXP_STR.exec(string)
+ const { add: forceAddFlags = '', remove: forceRemoveFlags = '' } =
+ typeof flags === 'object' ? flags : {} // Avoid issues when this is called directly from array.map
if (parts) {
- return new RegExp(parts[1], parts[2])
+ return new RegExp(
+ parts[1],
+ parts[2].replace(
+ new RegExp(`[${forceAddFlags}${forceRemoveFlags}]`, 'g'),
+ ''
+ ) + forceAddFlags
+ )
}
- return new RegExp(`^${escape(string)}$`)
+ return new RegExp(`^${escape(string)}$`, forceAddFlags)
}
/**
@@ -41,8 +52,32 @@ function isRegExp(string) {
return RE_REGEXP_STR.test(string)
}
+/**
+ * Converts an array of strings to a singular function to match any of them.
+ * This function converts each string to a `RegExp` and returns a function that checks all of them.
+ *
+ * @param {string[]} [patterns] The strings or regular expression strings to match.
+ * @returns {(...toCheck: string[]) => boolean} Returns a function that checks if any string matches any of the given patterns.
+ */
+function toRegExpGroupMatcher(patterns = []) {
+ if (patterns.length === 0) {
+ return () => false
+ }
+
+ // In the future, we could optimize this by joining expressions with identical flags.
+ const regexps = patterns.map((pattern) => toRegExp(pattern, { remove: 'g' }))
+
+ if (regexps.length === 1) {
+ return (...toCheck) => toCheck.some((str) => regexps[0].test(str))
+ }
+
+ return (...toCheck) =>
+ regexps.some((regexp) => toCheck.some((str) => regexp.test(str)))
+}
+
module.exports = {
escape,
toRegExp,
- isRegExp
+ isRegExp,
+ toRegExpGroupMatcher
}
diff --git a/tests/fixtures/typescript/src/test01.ts b/tests/fixtures/typescript/src/test01.ts
index d14550843..917643c67 100644
--- a/tests/fixtures/typescript/src/test01.ts
+++ b/tests/fixtures/typescript/src/test01.ts
@@ -18,3 +18,8 @@ export type Props2 = {
h?: string[]
i?: readonly string[]
}
+
+export type Slots1 = {
+ default(props: { msg: string }): any
+ foo(props: { msg: string }): any
+}
diff --git a/tests/lib/rules/array-bracket-newline.js b/tests/lib/rules/array-bracket-newline.js
index 380f61e4f..0334d2942 100644
--- a/tests/lib/rules/array-bracket-newline.js
+++ b/tests/lib/rules/array-bracket-newline.js
@@ -40,61 +40,145 @@ tester.run('array-bracket-newline', rule, {
{
code: '',
output: '',
- errors: ["There should be no linebreak after '['."]
+ errors: [
+ {
+ message: "There should be no linebreak after '['.",
+ line: 1,
+ column: 23,
+ endLine: 1,
+ endColumn: 24
+ }
+ ]
},
{
code: '',
output: '',
- errors: ["There should be no linebreak before ']'."]
+ errors: [
+ {
+ message: "There should be no linebreak before ']'.",
+ line: 2,
+ column: 1,
+ endLine: 2,
+ endColumn: 2
+ }
+ ]
},
{
code: '',
output: '',
errors: [
- "There should be no linebreak after '['.",
- "There should be no linebreak before ']'."
+ {
+ message: "There should be no linebreak after '['.",
+ line: 1,
+ column: 23,
+ endLine: 1,
+ endColumn: 24
+ },
+ {
+ message: "There should be no linebreak before ']'.",
+ line: 3,
+ column: 1,
+ endLine: 3,
+ endColumn: 2
+ }
]
},
{
code: '',
output: '',
options: ['never'],
- errors: ["There should be no linebreak after '['."]
+ errors: [
+ {
+ message: "There should be no linebreak after '['.",
+ line: 1,
+ column: 23,
+ endLine: 1,
+ endColumn: 24
+ }
+ ]
},
{
code: '',
output: '',
options: ['never'],
- errors: ["There should be no linebreak before ']'."]
+ errors: [
+ {
+ message: "There should be no linebreak before ']'.",
+ line: 2,
+ column: 1,
+ endLine: 2,
+ endColumn: 2
+ }
+ ]
},
{
code: '',
output: '',
options: ['never'],
errors: [
- "There should be no linebreak after '['.",
- "There should be no linebreak before ']'."
+ {
+ message: "There should be no linebreak after '['.",
+ line: 1,
+ column: 23,
+ endLine: 1,
+ endColumn: 24
+ },
+ {
+ message: "There should be no linebreak before ']'.",
+ line: 3,
+ column: 1,
+ endLine: 3,
+ endColumn: 2
+ }
]
},
{
code: '',
output: '',
options: ['always'],
- errors: ["A linebreak is required before ']'."]
+ errors: [
+ {
+ message: "A linebreak is required before ']'.",
+ line: 2,
+ column: 2,
+ endLine: 2,
+ endColumn: 3
+ }
+ ]
},
{
code: '',
output: '',
options: ['always'],
- errors: ["A linebreak is required after '['."]
+ errors: [
+ {
+ message: "A linebreak is required after '['.",
+ line: 1,
+ column: 23,
+ endLine: 1,
+ endColumn: 24
+ }
+ ]
},
{
code: '',
output: '',
options: ['always'],
errors: [
- "A linebreak is required after '['.",
- "A linebreak is required before ']'."
+ {
+ message: "A linebreak is required after '['.",
+ line: 1,
+ column: 23,
+ endLine: 1,
+ endColumn: 24
+ },
+ {
+ message: "A linebreak is required before ']'.",
+ line: 1,
+ column: 25,
+ endLine: 1,
+ endColumn: 26
+ }
]
},
{
@@ -102,8 +186,20 @@ tester.run('array-bracket-newline', rule, {
output: '',
options: ['always'],
errors: [
- "A linebreak is required after '['.",
- "A linebreak is required before ']'."
+ {
+ message: "A linebreak is required after '['.",
+ line: 1,
+ column: 27,
+ endLine: 1,
+ endColumn: 28
+ },
+ {
+ message: "A linebreak is required before ']'.",
+ line: 1,
+ column: 29,
+ endLine: 1,
+ endColumn: 30
+ }
]
}
]
diff --git a/tests/lib/rules/array-bracket-spacing.js b/tests/lib/rules/array-bracket-spacing.js
index 1eea108e6..6218d232e 100644
--- a/tests/lib/rules/array-bracket-spacing.js
+++ b/tests/lib/rules/array-bracket-spacing.js
@@ -39,61 +39,145 @@ tester.run('array-bracket-spacing', rule, {
{
code: '',
output: '',
- errors: ["There should be no space after '['."]
+ errors: [
+ {
+ message: "There should be no space after '['.",
+ line: 1,
+ column: 24,
+ endLine: 1,
+ endColumn: 25
+ }
+ ]
},
{
code: '',
output: '',
- errors: ["There should be no space before ']'."]
+ errors: [
+ {
+ message: "There should be no space before ']'.",
+ line: 1,
+ column: 25,
+ endLine: 1,
+ endColumn: 26
+ }
+ ]
},
{
code: '',
output: '',
errors: [
- "There should be no space after '['.",
- "There should be no space before ']'."
+ {
+ message: "There should be no space after '['.",
+ line: 1,
+ column: 24,
+ endLine: 1,
+ endColumn: 25
+ },
+ {
+ message: "There should be no space before ']'.",
+ line: 1,
+ column: 26,
+ endLine: 1,
+ endColumn: 27
+ }
]
},
{
code: '',
output: '',
options: ['never'],
- errors: ["There should be no space after '['."]
+ errors: [
+ {
+ message: "There should be no space after '['.",
+ line: 1,
+ column: 24,
+ endLine: 1,
+ endColumn: 25
+ }
+ ]
},
{
code: '',
output: '',
options: ['never'],
- errors: ["There should be no space before ']'."]
+ errors: [
+ {
+ message: "There should be no space before ']'.",
+ line: 1,
+ column: 25,
+ endLine: 1,
+ endColumn: 26
+ }
+ ]
},
{
code: '',
output: '',
options: ['never'],
errors: [
- "There should be no space after '['.",
- "There should be no space before ']'."
+ {
+ message: "There should be no space after '['.",
+ line: 1,
+ column: 24,
+ endLine: 1,
+ endColumn: 25
+ },
+ {
+ message: "There should be no space before ']'.",
+ line: 1,
+ column: 26,
+ endLine: 1,
+ endColumn: 27
+ }
]
},
{
code: '',
output: '',
options: ['always'],
- errors: ["A space is required before ']'."]
+ errors: [
+ {
+ message: "A space is required before ']'.",
+ line: 1,
+ column: 26,
+ endLine: 1,
+ endColumn: 27
+ }
+ ]
},
{
code: '',
output: '',
options: ['always'],
- errors: ["A space is required after '['."]
+ errors: [
+ {
+ message: "A space is required after '['.",
+ line: 1,
+ column: 23,
+ endLine: 1,
+ endColumn: 24
+ }
+ ]
},
{
code: '',
output: '',
options: ['always'],
errors: [
- "A space is required after '['.",
- "A space is required before ']'."
+ {
+ message: "A space is required after '['.",
+ line: 1,
+ column: 23,
+ endLine: 1,
+ endColumn: 24
+ },
+ {
+ message: "A space is required before ']'.",
+ line: 1,
+ column: 25,
+ endLine: 1,
+ endColumn: 26
+ }
]
},
{
@@ -101,8 +185,20 @@ tester.run('array-bracket-spacing', rule, {
output: '',
options: ['always'],
errors: [
- "A space is required after '['.",
- "A space is required before ']'."
+ {
+ message: "A space is required after '['.",
+ line: 1,
+ column: 27,
+ endLine: 1,
+ endColumn: 28
+ },
+ {
+ message: "A space is required before ']'.",
+ line: 1,
+ column: 29,
+ endLine: 1,
+ endColumn: 30
+ }
]
}
]
diff --git a/tests/lib/rules/arrow-spacing.js b/tests/lib/rules/arrow-spacing.js
index d80c255e8..d05c9f269 100644
--- a/tests/lib/rules/arrow-spacing.js
+++ b/tests/lib/rules/arrow-spacing.js
@@ -48,11 +48,17 @@ tester.run('arrow-spacing', rule, {
errors: [
{
message: 'Missing space before =>.',
- line: 3
+ line: 3,
+ column: 24,
+ endLine: 3,
+ endColumn: 25
},
{
message: 'Missing space after =>.',
- line: 3
+ line: 3,
+ column: 27,
+ endLine: 3,
+ endColumn: 28
}
]
},
@@ -68,11 +74,17 @@ tester.run('arrow-spacing', rule, {
errors: [
{
message: 'Missing space before =>.',
- line: 3
+ line: 3,
+ column: 25,
+ endLine: 3,
+ endColumn: 26
},
{
message: 'Missing space after =>.',
- line: 3
+ line: 3,
+ column: 28,
+ endLine: 3,
+ endColumn: 29
}
]
},
@@ -94,11 +106,17 @@ tester.run('arrow-spacing', rule, {
errors: [
{
message: 'Missing space before =>.',
- line: 4
+ line: 4,
+ column: 25,
+ endLine: 4,
+ endColumn: 26
},
{
message: 'Missing space after =>.',
- line: 4
+ line: 4,
+ column: 28,
+ endLine: 4,
+ endColumn: 29
}
]
},
@@ -115,11 +133,17 @@ tester.run('arrow-spacing', rule, {
errors: [
{
message: 'Unexpected space before =>.',
- line: 3
+ line: 3,
+ column: 24,
+ endLine: 3,
+ endColumn: 25
},
{
message: 'Unexpected space after =>.',
- line: 3
+ line: 3,
+ column: 29,
+ endLine: 3,
+ endColumn: 30
}
]
}
diff --git a/tests/lib/rules/attribute-hyphenation.js b/tests/lib/rules/attribute-hyphenation.js
index 738d59ae9..eac974e4e 100644
--- a/tests/lib/rules/attribute-hyphenation.js
+++ b/tests/lib/rules/attribute-hyphenation.js
@@ -118,7 +118,10 @@ ruleTester.run('attribute-hyphenation', rule, {
{
message: "Attribute 'my-prop' can't be hyphenated.",
type: 'VIdentifier',
- line: 1
+ line: 1,
+ column: 24,
+ endLine: 1,
+ endColumn: 37
}
]
},
@@ -131,7 +134,10 @@ ruleTester.run('attribute-hyphenation', rule, {
{
message: "Attribute 'MyProp' must be hyphenated.",
type: 'VIdentifier',
- line: 1
+ line: 1,
+ column: 24,
+ endLine: 1,
+ endColumn: 36
}
]
},
@@ -145,7 +151,10 @@ ruleTester.run('attribute-hyphenation', rule, {
{
message: "Attribute ':my-prop' can't be hyphenated.",
type: 'VDirectiveKey',
- line: 1
+ line: 1,
+ column: 24,
+ endLine: 1,
+ endColumn: 39
}
]
},
@@ -158,7 +167,10 @@ ruleTester.run('attribute-hyphenation', rule, {
{
message: "Attribute ':MyProp' must be hyphenated.",
type: 'VDirectiveKey',
- line: 1
+ line: 1,
+ column: 24,
+ endLine: 1,
+ endColumn: 38
}
]
},
@@ -172,7 +184,10 @@ ruleTester.run('attribute-hyphenation', rule, {
{
message: "Attribute 'v-bind:my-prop' can't be hyphenated.",
type: 'VDirectiveKey',
- line: 1
+ line: 1,
+ column: 24,
+ endLine: 1,
+ endColumn: 45
}
]
},
@@ -185,7 +200,10 @@ ruleTester.run('attribute-hyphenation', rule, {
{
message: "Attribute 'v-bind:MyProp' must be hyphenated.",
type: 'VDirectiveKey',
- line: 1
+ line: 1,
+ column: 24,
+ endLine: 1,
+ endColumn: 44
}
]
},
@@ -198,7 +216,10 @@ ruleTester.run('attribute-hyphenation', rule, {
{
message: "Attribute 'v-bind:MyProp' must be hyphenated.",
type: 'VDirectiveKey',
- line: 1
+ line: 1,
+ column: 24,
+ endLine: 1,
+ endColumn: 44
}
]
},
@@ -212,7 +233,10 @@ ruleTester.run('attribute-hyphenation', rule, {
{
message: "Attribute ':second-prop' can't be hyphenated.",
type: 'VDirectiveKey',
- line: 1
+ line: 1,
+ column: 46,
+ endLine: 1,
+ endColumn: 65
}
]
},
@@ -226,7 +250,10 @@ ruleTester.run('attribute-hyphenation', rule, {
{
message: "Attribute 'v-bind:myProp' must be hyphenated.",
type: 'VDirectiveKey',
- line: 1
+ line: 1,
+ column: 24,
+ endLine: 1,
+ endColumn: 44
}
]
},
@@ -240,7 +267,10 @@ ruleTester.run('attribute-hyphenation', rule, {
{
message: "Attribute 'v-bind:propID' must be hyphenated.",
type: 'VDirectiveKey',
- line: 1
+ line: 1,
+ column: 24,
+ endLine: 1,
+ endColumn: 44
}
]
},
@@ -255,7 +285,10 @@ ruleTester.run('attribute-hyphenation', rule, {
{
message: "Attribute 'v-model:my-prop' can't be hyphenated.",
type: 'VDirectiveKey',
- line: 1
+ line: 1,
+ column: 24,
+ endLine: 1,
+ endColumn: 46
}
]
},
@@ -269,7 +302,10 @@ ruleTester.run('attribute-hyphenation', rule, {
{
message: "Attribute 'v-model:myProp' must be hyphenated.",
type: 'VDirectiveKey',
- line: 1
+ line: 1,
+ column: 24,
+ endLine: 1,
+ endColumn: 45
}
]
},
@@ -282,7 +318,10 @@ ruleTester.run('attribute-hyphenation', rule, {
{
message: "Attribute 'v-model:MyProp' must be hyphenated.",
type: 'VDirectiveKey',
- line: 1
+ line: 1,
+ column: 24,
+ endLine: 1,
+ endColumn: 45
}
]
},
@@ -307,7 +346,10 @@ ruleTester.run('attribute-hyphenation', rule, {
{
message: "Attribute 'third-custom' can't be hyphenated.",
type: 'VIdentifier',
- line: 3
+ line: 3,
+ column: 111,
+ endLine: 3,
+ endColumn: 129
}
]
},
@@ -332,12 +374,18 @@ ruleTester.run('attribute-hyphenation', rule, {
{
message: "Attribute 'custom-hyphen' can't be hyphenated.",
type: 'VIdentifier',
- line: 3
+ line: 3,
+ column: 71,
+ endLine: 3,
+ endColumn: 90
},
{
message: "Attribute 'second-custom' can't be hyphenated.",
type: 'VIdentifier',
- line: 3
+ line: 3,
+ column: 91,
+ endLine: 3,
+ endColumn: 110
}
]
},
@@ -350,7 +398,10 @@ ruleTester.run('attribute-hyphenation', rule, {
{
message: "Attribute 'my-prop' can't be hyphenated.",
type: 'VIdentifier',
- line: 1
+ line: 1,
+ column: 22,
+ endLine: 1,
+ endColumn: 35
}
]
},
@@ -363,7 +414,10 @@ ruleTester.run('attribute-hyphenation', rule, {
{
message: "Attribute 'MyProp' must be hyphenated.",
type: 'VIdentifier',
- line: 1
+ line: 1,
+ column: 22,
+ endLine: 1,
+ endColumn: 34
}
]
},
@@ -376,7 +430,10 @@ ruleTester.run('attribute-hyphenation', rule, {
{
message: "Attribute ':attr_Gg' must be hyphenated.",
type: 'VDirectiveKey',
- line: 1
+ line: 1,
+ column: 24,
+ endLine: 1,
+ endColumn: 39
}
]
},
@@ -389,7 +446,10 @@ ruleTester.run('attribute-hyphenation', rule, {
{
message: "Attribute ':Attr_Hh' must be hyphenated.",
type: 'VDirectiveKey',
- line: 1
+ line: 1,
+ column: 24,
+ endLine: 1,
+ endColumn: 39
}
]
},
@@ -402,7 +462,10 @@ ruleTester.run('attribute-hyphenation', rule, {
{
message: "Attribute ':_attr_Jj' must be hyphenated.",
type: 'VDirectiveKey',
- line: 1
+ line: 1,
+ column: 24,
+ endLine: 1,
+ endColumn: 40
}
]
},
@@ -415,7 +478,10 @@ ruleTester.run('attribute-hyphenation', rule, {
{
message: "Attribute ':_attrKk' must be hyphenated.",
type: 'VDirectiveKey',
- line: 1
+ line: 1,
+ column: 24,
+ endLine: 1,
+ endColumn: 39
}
]
},
@@ -428,7 +494,10 @@ ruleTester.run('attribute-hyphenation', rule, {
{
message: "Attribute ':_AttrLl' must be hyphenated.",
type: 'VDirectiveKey',
- line: 1
+ line: 1,
+ column: 24,
+ endLine: 1,
+ endColumn: 39
}
]
},
@@ -441,7 +510,10 @@ ruleTester.run('attribute-hyphenation', rule, {
{
message: "Attribute ':my-custom_prop' can't be hyphenated.",
type: 'VDirectiveKey',
- line: 1
+ line: 1,
+ column: 24,
+ endLine: 1,
+ endColumn: 46
}
]
},
@@ -454,7 +526,10 @@ ruleTester.run('attribute-hyphenation', rule, {
{
message: "Attribute ':myAge.sync' must be hyphenated.",
type: 'VDirectiveKey',
- line: 1
+ line: 1,
+ column: 24,
+ endLine: 1,
+ endColumn: 42
}
]
},
@@ -467,7 +542,10 @@ ruleTester.run('attribute-hyphenation', rule, {
{
message: "Attribute ':my-age.sync' can't be hyphenated.",
type: 'VDirectiveKey',
- line: 1
+ line: 1,
+ column: 24,
+ endLine: 1,
+ endColumn: 43
}
]
},
@@ -490,7 +568,9 @@ ruleTester.run('attribute-hyphenation', rule, {
message: "Attribute 'my-prop' can't be hyphenated.",
type: 'VIdentifier',
line: 3,
- column: 17
+ column: 17,
+ endLine: 3,
+ endColumn: 24
}
]
},
@@ -513,7 +593,9 @@ ruleTester.run('attribute-hyphenation', rule, {
message: "Attribute 'myProp' must be hyphenated.",
type: 'VIdentifier',
line: 3,
- column: 17
+ column: 17,
+ endLine: 3,
+ endColumn: 23
}
]
}
diff --git a/tests/lib/rules/attributes-order.js b/tests/lib/rules/attributes-order.js
index 79ab47627..eb4543d1d 100644
--- a/tests/lib/rules/attributes-order.js
+++ b/tests/lib/rules/attributes-order.js
@@ -628,7 +628,11 @@ tester.run('attributes-order', rule, {
errors: [
{
message: 'Attribute "is" should go before "v-cloak".',
- type: 'VAttribute'
+ type: 'VAttribute',
+ line: 1,
+ column: 24,
+ endLine: 1,
+ endColumn: 35
}
]
},
@@ -639,7 +643,11 @@ tester.run('attributes-order', rule, {
errors: [
{
message: 'Attribute "v-cloak" should go before "id".',
- type: 'VAttribute'
+ type: 'VAttribute',
+ line: 1,
+ column: 30,
+ endLine: 1,
+ endColumn: 37
}
]
},
@@ -664,11 +672,19 @@ tester.run('attributes-order', rule, {
errors: [
{
message: 'Attribute "v-model" should go before "model".',
- type: 'VAttribute'
+ type: 'VAttribute',
+ line: 4,
+ column: 15,
+ endLine: 4,
+ endColumn: 31
},
{
message: 'Attribute ":id" should go before "propOne".',
- type: 'VAttribute'
+ type: 'VAttribute',
+ line: 6,
+ column: 15,
+ endLine: 6,
+ endColumn: 24
}
]
},
@@ -695,11 +711,19 @@ tester.run('attributes-order', rule, {
errors: [
{
message: 'Attribute "v-model" should go before "v-on".',
- type: 'VAttribute'
+ type: 'VAttribute',
+ line: 6,
+ column: 15,
+ endLine: 6,
+ endColumn: 31
},
{
message: 'Attribute "propOne" should go before "v-on".',
- type: 'VAttribute'
+ type: 'VAttribute',
+ line: 7,
+ column: 15,
+ endLine: 7,
+ endColumn: 28
}
]
},
@@ -711,7 +735,11 @@ tester.run('attributes-order', rule, {
errors: [
{
message: 'Attribute "is" should go before "aria-test".',
- type: 'VAttribute'
+ type: 'VAttribute',
+ line: 1,
+ column: 46,
+ endLine: 1,
+ endColumn: 57
}
]
},
@@ -740,7 +768,11 @@ tester.run('attributes-order', rule, {
errors: [
{
message: 'Attribute "is" should go before "propone".',
- type: 'VAttribute'
+ type: 'VAttribute',
+ line: 1,
+ column: 44,
+ endLine: 1,
+ endColumn: 55
}
]
},
@@ -759,7 +791,11 @@ tester.run('attributes-order', rule, {
errors: [
{
message: 'Attribute "is" should go before "v-cloak".',
- type: 'VAttribute'
+ type: 'VAttribute',
+ line: 3,
+ column: 15,
+ endLine: 3,
+ endColumn: 26
}
]
},
@@ -798,27 +834,51 @@ tester.run('attributes-order', rule, {
errors: [
{
message: 'Attribute "v-for" should go before "v-if".',
- type: 'VAttribute'
+ type: 'VAttribute',
+ line: 4,
+ column: 15,
+ endLine: 4,
+ endColumn: 36
},
{
message: 'Attribute "is" should go before "v-once".',
- type: 'VAttribute'
+ type: 'VAttribute',
+ line: 6,
+ column: 15,
+ endLine: 6,
+ endColumn: 26
},
{
message: 'Attribute "ref" should go before "v-on:click".',
- type: 'VAttribute'
+ type: 'VAttribute',
+ line: 8,
+ column: 15,
+ endLine: 8,
+ endColumn: 27
},
{
message: 'Attribute ":prop" should go before "v-on:click".',
- type: 'VAttribute'
+ type: 'VAttribute',
+ line: 9,
+ column: 15,
+ endLine: 9,
+ endColumn: 33
},
{
message: 'Attribute "id" should go before "v-text".',
- type: 'VAttribute'
+ type: 'VAttribute',
+ line: 11,
+ column: 15,
+ endLine: 11,
+ endColumn: 28
},
{
message: 'Attribute "myProp" should go before "v-text".',
- type: 'VAttribute'
+ type: 'VAttribute',
+ line: 12,
+ column: 15,
+ endLine: 12,
+ endColumn: 28
}
]
},
@@ -874,23 +934,43 @@ tester.run('attributes-order', rule, {
errors: [
{
message: 'Attribute "is" should go before "v-once".',
- type: 'VAttribute'
+ type: 'VAttribute',
+ line: 6,
+ column: 15,
+ endLine: 6,
+ endColumn: 26
},
{
message: 'Attribute "v-on:click" should go before "v-once".',
- type: 'VAttribute'
+ type: 'VAttribute',
+ line: 7,
+ column: 15,
+ endLine: 7,
+ endColumn: 40
},
{
message: 'Attribute "ref" should go before "v-once".',
- type: 'VAttribute'
+ type: 'VAttribute',
+ line: 8,
+ column: 15,
+ endLine: 8,
+ endColumn: 27
},
{
message: 'Attribute "id" should go before "v-text".',
- type: 'VAttribute'
+ type: 'VAttribute',
+ line: 11,
+ column: 15,
+ endLine: 11,
+ endColumn: 28
},
{
message: 'Attribute "myProp" should go before "v-text".',
- type: 'VAttribute'
+ type: 'VAttribute',
+ line: 12,
+ column: 15,
+ endLine: 12,
+ endColumn: 28
}
]
},
@@ -931,7 +1011,11 @@ tester.run('attributes-order', rule, {
errors: [
{
message: 'Attribute "v-if" should go before "class".',
- type: 'VAttribute'
+ type: 'VAttribute',
+ line: 4,
+ column: 15,
+ endLine: 4,
+ endColumn: 30
}
]
},
@@ -955,7 +1039,11 @@ tester.run('attributes-order', rule, {
errors: [
{
message: 'Attribute "v-slot" should go before "v-model".',
- type: 'VAttribute'
+ type: 'VAttribute',
+ line: 5,
+ column: 15,
+ endLine: 5,
+ endColumn: 35
}
]
},
@@ -977,7 +1065,11 @@ tester.run('attributes-order', rule, {
errors: [
{
message: 'Attribute "a-prop" should go before "z-prop".',
- type: 'VAttribute'
+ type: 'VAttribute',
+ line: 4,
+ column: 13,
+ endLine: 4,
+ endColumn: 23
}
]
},
@@ -999,7 +1091,11 @@ tester.run('attributes-order', rule, {
errors: [
{
message: 'Attribute ":a-prop" should go before ":z-prop".',
- type: 'VAttribute'
+ type: 'VAttribute',
+ line: 4,
+ column: 13,
+ endLine: 4,
+ endColumn: 24
}
]
},
@@ -1021,7 +1117,11 @@ tester.run('attributes-order', rule, {
errors: [
{
message: 'Attribute "@change" should go before "@input".',
- type: 'VAttribute'
+ type: 'VAttribute',
+ line: 4,
+ column: 13,
+ endLine: 4,
+ endColumn: 26
}
]
},
@@ -1043,7 +1143,11 @@ tester.run('attributes-order', rule, {
errors: [
{
message: 'Attribute "boolean-prop" should go before "z-prop".',
- type: 'VAttribute'
+ type: 'VAttribute',
+ line: 4,
+ column: 13,
+ endLine: 4,
+ endColumn: 25
}
]
},
@@ -1065,7 +1169,11 @@ tester.run('attributes-order', rule, {
errors: [
{
message: 'Attribute "v-on:[c]" should go before "v-on:click".',
- type: 'VAttribute'
+ type: 'VAttribute',
+ line: 4,
+ column: 13,
+ endLine: 4,
+ endColumn: 36
}
]
},
@@ -1087,7 +1195,11 @@ tester.run('attributes-order', rule, {
errors: [
{
message: 'Attribute "v-on:click" should go before "v-text".',
- type: 'VAttribute'
+ type: 'VAttribute',
+ line: 4,
+ column: 13,
+ endLine: 4,
+ endColumn: 38
}
]
},
@@ -1108,7 +1220,11 @@ tester.run('attributes-order', rule, {
options: [{ alphabetical: true }],
errors: [
{
- message: 'Attribute "class" should go before ":class".'
+ message: 'Attribute "class" should go before ":class".',
+ line: 4,
+ column: 13,
+ endLine: 4,
+ endColumn: 24
}
]
},
@@ -1129,7 +1245,11 @@ tester.run('attributes-order', rule, {
options: [{ alphabetical: true }],
errors: [
{
- message: 'Attribute "v-if" should go before "v-show".'
+ message: 'Attribute "v-if" should go before "v-show".',
+ line: 4,
+ column: 13,
+ endLine: 4,
+ endColumn: 23
}
]
},
@@ -1150,7 +1270,11 @@ tester.run('attributes-order', rule, {
options: [{ alphabetical: true }],
errors: [
{
- message: 'Attribute "v-bar" should go before "v-foo".'
+ message: 'Attribute "v-bar" should go before "v-foo".',
+ line: 4,
+ column: 13,
+ endLine: 4,
+ endColumn: 24
}
]
},
@@ -1171,7 +1295,11 @@ tester.run('attributes-order', rule, {
options: [{ alphabetical: true }],
errors: [
{
- message: 'Attribute "v-foo.a" should go before "v-foo.b".'
+ message: 'Attribute "v-foo.a" should go before "v-foo.b".',
+ line: 4,
+ column: 13,
+ endLine: 4,
+ endColumn: 24
}
]
},
@@ -1182,7 +1310,11 @@ tester.run('attributes-order', rule, {
output: '',
errors: [
{
- message: 'Attribute "v-is" should go before "v-cloak".'
+ message: 'Attribute "v-is" should go before "v-cloak".',
+ line: 1,
+ column: 24,
+ endLine: 1,
+ endColumn: 34
}
]
},
@@ -1206,7 +1338,15 @@ tester.run('attributes-order', rule, {
v-bind="b">
`,
- errors: ['Attribute "v-if" should go before "v-bind:id".']
+ errors: [
+ {
+ message: 'Attribute "v-if" should go before "v-bind:id".',
+ line: 6,
+ column: 11,
+ endLine: 6,
+ endColumn: 19
+ }
+ ]
},
{
filename: 'test.vue',
@@ -1226,7 +1366,15 @@ tester.run('attributes-order', rule, {
v-bind="b">
`,
- errors: ['Attribute "v-if" should go before "v-bind:id".']
+ errors: [
+ {
+ message: 'Attribute "v-if" should go before "v-bind:id".',
+ line: 5,
+ column: 11,
+ endLine: 5,
+ endColumn: 19
+ }
+ ]
},
{
filename: 'test.vue',
@@ -1246,7 +1394,15 @@ tester.run('attributes-order', rule, {
v-bind:id="a">
`,
- errors: ['Attribute "v-if" should go before "v-bind:id".']
+ errors: [
+ {
+ message: 'Attribute "v-if" should go before "v-bind:id".',
+ line: 6,
+ column: 11,
+ endLine: 6,
+ endColumn: 19
+ }
+ ]
},
{
filename: 'test.vue',
@@ -1267,7 +1423,15 @@ tester.run('attributes-order', rule, {
`,
options: [{ alphabetical: true }],
- errors: ['Attribute "v-bind:id" should go before "v-on:click".']
+ errors: [
+ {
+ message: 'Attribute "v-bind:id" should go before "v-on:click".',
+ line: 5,
+ column: 11,
+ endLine: 5,
+ endColumn: 24
+ }
+ ]
},
{
filename: 'test.vue',
@@ -1288,7 +1452,15 @@ tester.run('attributes-order', rule, {
`,
options: [{ alphabetical: true }],
- errors: ['Attribute "v-bind" should go before "v-on:click".']
+ errors: [
+ {
+ message: 'Attribute "v-bind" should go before "v-on:click".',
+ line: 6,
+ column: 11,
+ endLine: 6,
+ endColumn: 21
+ }
+ ]
},
{
filename: 'test.vue',
@@ -1309,7 +1481,15 @@ tester.run('attributes-order', rule, {
`,
options: [{ alphabetical: true }],
- errors: ['Attribute "v-bind:id" should go before "v-on:click".']
+ errors: [
+ {
+ message: 'Attribute "v-bind:id" should go before "v-on:click".',
+ line: 6,
+ column: 11,
+ endLine: 6,
+ endColumn: 24
+ }
+ ]
},
{
filename: 'test.vue',
@@ -1333,8 +1513,20 @@ tester.run('attributes-order', rule, {
`,
options: [{ alphabetical: true }],
errors: [
- 'Attribute "v-bind:a" should go before "v-on:click".',
- 'Attribute "v-if" should go before "v-on:click".'
+ {
+ message: 'Attribute "v-bind:a" should go before "v-on:click".',
+ line: 5,
+ column: 11,
+ endLine: 5,
+ endColumn: 23
+ },
+ {
+ message: 'Attribute "v-if" should go before "v-on:click".',
+ line: 7,
+ column: 11,
+ endLine: 7,
+ endColumn: 19
+ }
]
},
{
@@ -1359,8 +1551,20 @@ tester.run('attributes-order', rule, {
`,
options: [{ alphabetical: true }],
errors: [
- 'Attribute "v-bind" should go before "v-on:click".',
- 'Attribute "v-if" should go before "v-on:click".'
+ {
+ message: 'Attribute "v-bind" should go before "v-on:click".',
+ line: 6,
+ column: 11,
+ endLine: 6,
+ endColumn: 21
+ },
+ {
+ message: 'Attribute "v-if" should go before "v-on:click".',
+ line: 7,
+ column: 11,
+ endLine: 7,
+ endColumn: 19
+ }
]
},
{
@@ -1382,7 +1586,15 @@ tester.run('attributes-order', rule, {
`,
options: [{ alphabetical: true }],
- errors: ['Attribute "v-if" should go before "a".']
+ errors: [
+ {
+ message: 'Attribute "v-if" should go before "a".',
+ line: 6,
+ column: 11,
+ endLine: 6,
+ endColumn: 19
+ }
+ ]
},
{
filename: 'test.vue',
@@ -1404,8 +1616,20 @@ tester.run('attributes-order', rule, {
`,
options: [{ alphabetical: true }],
errors: [
- 'Attribute "v-bind" should go before "v-on:click".',
- 'Attribute "v-if" should go before "v-on:click".'
+ {
+ message: 'Attribute "v-bind" should go before "v-on:click".',
+ line: 5,
+ column: 11,
+ endLine: 5,
+ endColumn: 21
+ },
+ {
+ message: 'Attribute "v-if" should go before "v-on:click".',
+ line: 6,
+ column: 11,
+ endLine: 6,
+ endColumn: 19
+ }
]
},
{
@@ -1428,7 +1652,15 @@ tester.run('attributes-order', rule, {
v-bind:value="a">
`,
- errors: ['Attribute "v-model" should go before "v-custom-directive".']
+ errors: [
+ {
+ message: 'Attribute "v-model" should go before "v-custom-directive".',
+ line: 6,
+ column: 11,
+ endLine: 6,
+ endColumn: 22
+ }
+ ]
},
{
filename: 'test.vue',
@@ -1450,7 +1682,15 @@ tester.run('attributes-order', rule, {
v-model="c">
`,
- errors: ['Attribute "v-bind:id" should go before "v-model".']
+ errors: [
+ {
+ message: 'Attribute "v-bind:id" should go before "v-model".',
+ line: 7,
+ column: 11,
+ endLine: 7,
+ endColumn: 24
+ }
+ ]
},
// omit order
@@ -1473,7 +1713,15 @@ tester.run('attributes-order', rule, {
`,
options: [{ order: ['LIST_RENDERING', 'CONDITIONALS'] }],
- errors: ['Attribute "v-for" should go before "v-if".']
+ errors: [
+ {
+ message: 'Attribute "v-for" should go before "v-if".',
+ line: 6,
+ column: 11,
+ endLine: 6,
+ endColumn: 29
+ }
+ ]
},
{
filename: 'test.vue',
@@ -1494,7 +1742,15 @@ tester.run('attributes-order', rule, {
`,
options: [{ order: ['LIST_RENDERING', 'CONDITIONALS'] }],
- errors: ['Attribute "v-for" should go before "v-if".']
+ errors: [
+ {
+ message: 'Attribute "v-for" should go before "v-if".',
+ line: 6,
+ column: 11,
+ endLine: 6,
+ endColumn: 29
+ }
+ ]
},
// slot
@@ -1523,7 +1779,11 @@ tester.run('attributes-order', rule, {
],
errors: [
{
- message: 'Attribute "bar" should go before "v-slot".'
+ message: 'Attribute "bar" should go before "v-slot".',
+ line: 1,
+ column: 43,
+ endLine: 1,
+ endColumn: 52
}
]
},
@@ -1553,7 +1813,11 @@ tester.run('attributes-order', rule, {
],
errors: [
{
- message: 'Attribute "ref" should go before "bar".'
+ message: 'Attribute "ref" should go before "bar".',
+ line: 1,
+ column: 26,
+ endLine: 1,
+ endColumn: 35
}
]
},
@@ -1579,8 +1843,20 @@ tester.run('attributes-order', rule, {
@click="handleClick"/>
`,
errors: [
- 'Attribute "v-if" should go before "v-bind".',
- 'Attribute "ref" should go before "v-model".'
+ {
+ message: 'Attribute "v-if" should go before "v-bind".',
+ line: 5,
+ column: 11,
+ endLine: 5,
+ endColumn: 22
+ },
+ {
+ message: 'Attribute "ref" should go before "v-model".',
+ line: 7,
+ column: 11,
+ endLine: 7,
+ endColumn: 20
+ }
]
},
@@ -1598,7 +1874,15 @@ tester.run('attributes-order', rule, {
v-bind="object"
@click="handleClick"/>
`,
- errors: ['Attribute "v-bind" should go before "@click".']
+ errors: [
+ {
+ message: 'Attribute "v-bind" should go before "@click".',
+ line: 5,
+ column: 11,
+ endLine: 5,
+ endColumn: 26
+ }
+ ]
},
{
@@ -1619,7 +1903,15 @@ tester.run('attributes-order', rule, {
@click="handleClick"
@input="handleInput"/>
`,
- errors: ['Attribute "v-bind" should go before "@click".']
+ errors: [
+ {
+ message: 'Attribute "v-bind" should go before "@click".',
+ line: 6,
+ column: 11,
+ endLine: 6,
+ endColumn: 26
+ }
+ ]
},
{
@@ -1641,7 +1933,15 @@ tester.run('attributes-order', rule, {
v-bind="object"/>
`,
options: [{ order: ['UNIQUE', 'EVENTS', 'OTHER_ATTR'] }],
- errors: ['Attribute "@input" should go before "v-bind".']
+ errors: [
+ {
+ message: 'Attribute "@input" should go before "v-bind".',
+ line: 7,
+ column: 11,
+ endLine: 7,
+ endColumn: 31
+ }
+ ]
},
{
@@ -1661,7 +1961,15 @@ tester.run('attributes-order', rule, {
attr="foo"/>
`,
options: [{ order: ['UNIQUE', 'EVENTS', 'OTHER_ATTR'] }],
- errors: ['Attribute "@click" should go before "v-bind".']
+ errors: [
+ {
+ message: 'Attribute "@click" should go before "v-bind".',
+ line: 5,
+ column: 11,
+ endLine: 5,
+ endColumn: 31
+ }
+ ]
},
{
@@ -1681,7 +1989,15 @@ tester.run('attributes-order', rule, {
:prop-three="c"/>
`,
options: [{ order: ['ATTR_STATIC', 'ATTR_DYNAMIC'] }],
- errors: ['Attribute "prop-two" should go before "v-bind:prop-one".']
+ errors: [
+ {
+ message: 'Attribute "prop-two" should go before "v-bind:prop-one".',
+ line: 5,
+ column: 11,
+ endLine: 5,
+ endColumn: 23
+ }
+ ]
},
{
@@ -1722,8 +2038,20 @@ tester.run('attributes-order', rule, {
}
],
errors: [
- 'Attribute "v-model" should go before ":prop-one".',
- 'Attribute ":prop-three" should go before "prop-two".'
+ {
+ message: 'Attribute "v-model" should go before ":prop-one".',
+ line: 5,
+ column: 11,
+ endLine: 5,
+ endColumn: 26
+ },
+ {
+ message: 'Attribute ":prop-three" should go before "prop-two".',
+ line: 7,
+ column: 11,
+ endLine: 7,
+ endColumn: 26
+ }
]
},
@@ -1765,7 +2093,15 @@ tester.run('attributes-order', rule, {
]
}
],
- errors: ['Attribute "v-model" should go before ":prop-one".']
+ errors: [
+ {
+ message: 'Attribute "v-model" should go before ":prop-one".',
+ line: 5,
+ column: 11,
+ endLine: 5,
+ endColumn: 26
+ }
+ ]
}
]
})
diff --git a/tests/lib/rules/block-lang.js b/tests/lib/rules/block-lang.js
index 5f7851b54..af8b837d6 100644
--- a/tests/lib/rules/block-lang.js
+++ b/tests/lib/rules/block-lang.js
@@ -42,9 +42,12 @@ tester.run('block-lang', rule, {
options: [{ script: { lang: 'ts' } }],
errors: [
{
- message: `Only "ts" can be used for the 'lang' attribute of '`
},
+ {
+ filename: 'test.vue',
+ code: `
+
+
+
+
+
+
+ `,
+ ...getTypeScriptFixtureTestOptions()
+ },
{
filename: 'test.vue',
code: `
@@ -656,6 +674,28 @@ tester.run('require-explicit-slots', rule, {
}
]
},
+ {
+ filename: 'test.vue',
+ code: `
+
+
+
+
+
+
+ `,
+ errors: [
+ {
+ message: 'Slots must be explicitly defined.',
+ line: 5,
+ column: 11
+ }
+ ],
+ ...getTypeScriptFixtureTestOptions()
+ },
{
// ignore attribute binding except string literal
filename: 'test.vue',
diff --git a/tests/lib/utils/regexp.js b/tests/lib/utils/regexp.js
index 830fa2a11..e27a0596f 100644
--- a/tests/lib/utils/regexp.js
+++ b/tests/lib/utils/regexp.js
@@ -1,6 +1,10 @@
'use strict'
-const { escape, toRegExp } = require('../../../lib/utils/regexp')
+const {
+ escape,
+ toRegExp,
+ toRegExpGroupMatcher
+} = require('../../../lib/utils/regexp')
const assert = require('assert')
const ESCAPED = '\\^\\$\\.\\*\\+\\?\\(\\)\\[\\]\\{\\}\\|\\\\'
@@ -35,4 +39,120 @@ describe('toRegExp()', () => {
assert.deepEqual(toRegExp(`${/^bar/i}`), /^bar/i)
assert.deepEqual(toRegExp(`${/[\sA-Z]+/u}`), /[\sA-Z]+/u)
})
+
+ it('should handle simple patterns', () => {
+ const regex = toRegExp('foo')
+ assert.strictEqual(regex.test('foo'), true)
+ assert.strictEqual(regex.test('bar'), false)
+ assert.strictEqual(regex.test('foobar'), false)
+ assert.strictEqual(regex.test('afoo'), false)
+ assert.strictEqual(regex.test('afoobar'), false)
+ assert.strictEqual(regex.test('Foo'), false)
+ })
+
+ it('should handle simple patterns with added flags', () => {
+ const regex = toRegExp('foo', { add: 'i' })
+ assert.strictEqual(regex.test('foo'), true)
+ assert.strictEqual(regex.test('bar'), false)
+ assert.strictEqual(regex.test('foobar'), false)
+ assert.strictEqual(regex.test('afoo'), false)
+ assert.strictEqual(regex.test('afoobar'), false)
+ assert.strictEqual(regex.test('Foo'), true)
+ })
+
+ it('should handle regexp patterns', () => {
+ const regex = toRegExp('/^foo/')
+ assert.strictEqual(regex.test('foo'), true)
+ assert.strictEqual(regex.test('bar'), false)
+ assert.strictEqual(regex.test('foobar'), true)
+ assert.strictEqual(regex.test('afoo'), false)
+ assert.strictEqual(regex.test('afoobar'), false)
+ assert.strictEqual(regex.test('Foo'), false)
+ })
+
+ it('should handle regexp patterns with attached flags', () => {
+ const regex = toRegExp('/^foo/i')
+ assert.strictEqual(regex.test('foo'), true)
+ assert.strictEqual(regex.test('bar'), false)
+ assert.strictEqual(regex.test('foobar'), true)
+ assert.strictEqual(regex.test('afoo'), false)
+ assert.strictEqual(regex.test('afoobar'), false)
+ assert.strictEqual(regex.test('Foo'), true)
+ })
+
+ it('should handle regexp patterns with added flags', () => {
+ const regex = toRegExp('/^foo/', { add: 'i' })
+ assert.deepEqual(regex, /^foo/i)
+ assert.strictEqual(regex.test('foo'), true)
+ assert.strictEqual(regex.test('bar'), false)
+ assert.strictEqual(regex.test('foobar'), true)
+ assert.strictEqual(regex.test('afoo'), false)
+ assert.strictEqual(regex.test('afoobar'), false)
+ assert.strictEqual(regex.test('Foo'), true)
+ })
+
+ it('should handle regexp patterns with removed flags', () => {
+ const regex = toRegExp('/^foo/i', { remove: 'i' })
+ assert.deepEqual(regex, /^foo/)
+ assert.strictEqual(regex.test('foo'), true)
+ assert.strictEqual(regex.test('bar'), false)
+ assert.strictEqual(regex.test('foobar'), true)
+ assert.strictEqual(regex.test('afoo'), false)
+ assert.strictEqual(regex.test('afoobar'), false)
+ assert.strictEqual(regex.test('Foo'), false)
+ })
+})
+
+describe('toRegExpGroupMatcher()', () => {
+ it('should return a function missing input', () => {
+ const groupMatcher = toRegExpGroupMatcher()
+ assert.strictEqual(groupMatcher(''), false)
+ assert.strictEqual(groupMatcher('foo'), false)
+ assert.strictEqual(groupMatcher('bar'), false)
+ })
+
+ it('should return a function for empty array', () => {
+ const groupMatcher = toRegExpGroupMatcher([])
+ assert.strictEqual(groupMatcher(''), false)
+ assert.strictEqual(groupMatcher('foo'), false)
+ assert.strictEqual(groupMatcher('bar'), false)
+ })
+
+ it('should return a function for single simple pattern', () => {
+ const groupMatcher = toRegExpGroupMatcher(['foo'])
+ assert.strictEqual(groupMatcher(''), false)
+ assert.strictEqual(groupMatcher('foo'), true)
+ assert.strictEqual(groupMatcher('foo', 'early'), true)
+ assert.strictEqual(groupMatcher('late', 'matches', 'foo'), true)
+ assert.strictEqual(groupMatcher('foobar'), false)
+ assert.strictEqual(groupMatcher('afoo', 'fooa', 'afooa', 'bar'), false)
+ })
+
+ it('should return a function for multiple simple patterns', () => {
+ const groupMatcher = toRegExpGroupMatcher(['foo', 'bar'])
+ assert.strictEqual(groupMatcher('foo'), true)
+ assert.strictEqual(groupMatcher('bar', 'early'), true)
+ assert.strictEqual(groupMatcher('late', 'matches', 'foo'), true)
+ assert.strictEqual(groupMatcher('foobar'), false)
+ assert.strictEqual(groupMatcher('afoo', 'fooa', 'afooa'), false)
+ })
+
+ it('should return a function for single regexp pattern', () => {
+ const groupMatcher = toRegExpGroupMatcher(['/^foo/g'])
+ assert.strictEqual(groupMatcher(''), false)
+ assert.strictEqual(groupMatcher('foo'), true)
+ assert.strictEqual(groupMatcher('fooa', 'early'), true)
+ assert.strictEqual(groupMatcher('late', 'matches', 'fooa'), true)
+ assert.strictEqual(groupMatcher('barfoo'), false)
+ assert.strictEqual(groupMatcher('afoo', 'afooa', 'bar'), false)
+ })
+
+ it('should return a function for multiple regexp patterns', () => {
+ const groupMatcher = toRegExpGroupMatcher(['/^foo/', '/bar$/gi'])
+ assert.strictEqual(groupMatcher('foo'), true)
+ assert.strictEqual(groupMatcher('Bar', 'early'), true)
+ assert.strictEqual(groupMatcher('late', 'matches', 'foo'), true)
+ assert.strictEqual(groupMatcher('barfoo'), false)
+ assert.strictEqual(groupMatcher('afoo', 'afooa', 'bara'), false)
+ })
})
diff --git a/tools/generate-typegen.mjs b/tools/generate-typegen.mjs
index 5bcb325a5..1f3b4a129 100644
--- a/tools/generate-typegen.mjs
+++ b/tools/generate-typegen.mjs
@@ -2,8 +2,13 @@ import fs from 'node:fs/promises'
import { pluginsToRulesDTS } from 'eslint-typegen/core'
import plugin from '../lib/index.js'
-const dts = await pluginsToRulesDTS({
- vue: plugin
-})
+const dts = await pluginsToRulesDTS(
+ {
+ vue: plugin
+ },
+ {
+ includeAugmentation: false
+ }
+)
await fs.writeFile('lib/eslint-typegen.d.ts', dts)
pFad - Phonifier reborn
Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.
Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.
Alternative Proxies:
Alternative Proxy
pFad Proxy
pFad v3 Proxy
pFad v4 Proxy