From 00c3b991a4a5e784390075c90a06689ba16b4fdf Mon Sep 17 00:00:00 2001 From: Yosuke Ota Date: Mon, 18 Oct 2021 10:36:22 +0900 Subject: [PATCH 001/622] Improve no-use-computed-property-like-method rule (#1659) - Change to track variables to check types. - Change to track the conditional expression to check types. - Change condition to track branch and return to check types. - Change to check the expressions in template as well. - Fix known bugs. --- lib/rules/no-undef-properties.js | 15 +- lib/rules/no-unused-properties.js | 38 +- .../no-use-computed-property-like-method.js | 671 +++++++++++++----- lib/utils/index.js | 62 ++ lib/utils/property-references.js | 40 +- .../no-use-computed-property-like-method.js | 341 ++++++++- 6 files changed, 907 insertions(+), 260 deletions(-) diff --git a/lib/rules/no-undef-properties.js b/lib/rules/no-undef-properties.js index 0acf49f15..fdd506cc5 100644 --- a/lib/rules/no-undef-properties.js +++ b/lib/rules/no-undef-properties.js @@ -235,7 +235,7 @@ module.exports = { function getVueComponentContextForTemplate() { const keys = [...vueComponentContextMap.keys()] const exported = - keys.find(isScriptSetupProgram) || keys.find(isExportObject) + keys.find(isScriptSetupProgram) || keys.find(utils.isInExportDefault) return exported && vueComponentContextMap.get(exported) /** @@ -244,19 +244,6 @@ module.exports = { function isScriptSetupProgram(node) { return node === programNode } - /** - * @param {ASTNode} node - */ - function isExportObject(node) { - let parent = node.parent - while (parent) { - if (parent.type === 'ExportDefaultDeclaration') { - return true - } - parent = parent.parent - } - return false - } } /** diff --git a/lib/rules/no-unused-properties.js b/lib/rules/no-unused-properties.js index 00da49d63..0a36c6579 100644 --- a/lib/rules/no-unused-properties.js +++ b/lib/rules/no-unused-properties.js @@ -79,49 +79,13 @@ const PROPERTY_LABEL = { // Helpers // ------------------------------------------------------------------------------ -/** - * Find the variable of a given name. - * @param {RuleContext} context The rule context - * @param {Identifier} node The variable name to find. - * @returns {Variable|null} The found variable or null. - */ -function findVariable(context, node) { - return eslintUtils.findVariable(getScope(context, node), node) -} -/** - * Gets the scope for the current node - * @param {RuleContext} context The rule context - * @param {ESNode} currentNode The node to get the scope of - * @returns { import('eslint').Scope.Scope } The scope information for this node - */ -function getScope(context, currentNode) { - // On Program node, get the outermost scope to avoid return Node.js special function scope or ES modules scope. - const inner = currentNode.type !== 'Program' - const scopeManager = context.getSourceCode().scopeManager - - /** @type {ESNode | null} */ - let node = currentNode - for (; node; node = /** @type {ESNode | null} */ (node.parent)) { - const scope = scopeManager.acquire(node, inner) - - if (scope) { - if (scope.type === 'function-expression-name') { - return scope.childScopes[0] - } - return scope - } - } - - return scopeManager.scopes[0] -} - /** * @param {RuleContext} context * @param {Identifier} id * @returns {Expression} */ function findExpression(context, id) { - const variable = findVariable(context, id) + const variable = utils.findVariableByIdentifier(context, id) if (!variable) { return id } diff --git a/lib/rules/no-use-computed-property-like-method.js b/lib/rules/no-use-computed-property-like-method.js index c1c8ca765..d5c4430d7 100644 --- a/lib/rules/no-use-computed-property-like-method.js +++ b/lib/rules/no-use-computed-property-like-method.js @@ -11,21 +11,99 @@ const eslintUtils = require('eslint-utils') const utils = require('../utils') /** - * @typedef {import('../utils').ComponentPropertyData} ComponentPropertyData + * @typedef {import('eslint').Scope.Scope} Scope * @typedef {import('../utils').ComponentObjectPropertyData} ComponentObjectPropertyData * @typedef {import('../utils').GroupName} GroupName - * - * @typedef {{[key: string]: ComponentPropertyData & { valueType: { type: string | null } }}} PropertyMap */ + +/** + * @typedef {object} CallMember + * @property {string} name + * @property {CallExpression} node + */ + // ------------------------------------------------------------------------------ // Rule Definition // ------------------------------------------------------------------------------ +/** @type {Set} */ +const GROUPS = new Set(['data', 'props', 'computed', 'methods']) + +const NATIVE_NOT_FUNCTION_TYPES = new Set([ + 'String', + 'Number', + 'BigInt', + 'Boolean', + 'Object', + 'Array', + 'Symbol' +]) + +/** + * @param {RuleContext} context + * @param {Expression} node + * @returns {Set} + */ +function resolvedExpressions(context, node) { + /** @type {Map>} */ + const resolvedMap = new Map() + + return resolvedExpressionsInternal(node) + + /** + * @param {Expression} node + * @returns {Set} + */ + function resolvedExpressionsInternal(node) { + let resolvedSet = resolvedMap.get(node) + if (!resolvedSet) { + resolvedSet = new Set() + resolvedMap.set(node, resolvedSet) + for (const e of extractResolvedExpressions(node)) { + resolvedSet.add(e) + } + } + + if (!resolvedSet.size) { + resolvedSet.add(node) + } + + return resolvedSet + } + /** + * @param {Expression} node + * @returns {Iterable} + */ + function* extractResolvedExpressions(node) { + if (node.type === 'Identifier') { + const variable = utils.findVariableByIdentifier(context, node) + if (variable) { + for (const ref of variable.references) { + const id = ref.identifier + if (id.parent.type === 'VariableDeclarator') { + if (id.parent.id === id && id.parent.init) { + yield* resolvedExpressionsInternal(id.parent.init) + } + } else if (id.parent.type === 'AssignmentExpression') { + if (id.parent.left === id) { + yield* resolvedExpressionsInternal(id.parent.right) + } + } + } + } + } else if (node.type === 'ConditionalExpression') { + yield* resolvedExpressionsInternal(node.consequent) + yield* resolvedExpressionsInternal(node.alternate) + } + } +} + /** * Get type of props item. * Can't consider array props like: props: {propsA: [String, Number, Function]} - * @param {ComponentObjectPropertyData} property - * @return {string | null} + * @param {RuleContext} context + * @param {ComponentObjectPropertyData} prop + * @return {string[] | null} * * @example * props: { @@ -35,150 +113,367 @@ const utils = require('../utils') * }, * } */ -const getComponentPropsType = (property) => { +function getComponentPropsTypes(context, prop) { + const result = [] + for (const expr of resolvedExpressions(context, prop.property.value)) { + const types = getComponentPropsTypesFromExpression(expr) + if (types == null) { + return null + } + result.push(...types) + } + return result + /** - * Check basic props `props: { basicProps: ... }` + * @param {Expression} expr */ - if (property.property.value.type === 'Identifier') { - return property.property.value.name + function getComponentPropsTypesFromExpression(expr) { + let typeExprs + /** + * Check object props `props: { objectProps: {...} }` + */ + if (expr.type === 'ObjectExpression') { + const type = utils.findProperty(expr, 'type') + if (type == null) return null + + typeExprs = resolvedExpressions(context, type.value) + } else { + typeExprs = [expr] + } + + const result = [] + for (const typeExpr of typeExprs) { + const types = getComponentPropsTypesFromTypeExpression(typeExpr) + if (types == null) { + return null + } + result.push(...types) + } + return result } + /** - * Check object props `props: { objectProps: {...} }` + * @param {Expression} typeExpr */ - if (property.property.value.type === 'ObjectExpression') { - const typeProperty = utils.findProperty(property.property.value, 'type') - if (typeProperty == null) return null - - if (typeProperty.value.type === 'Identifier') return typeProperty.value.name + function getComponentPropsTypesFromTypeExpression(typeExpr) { + if (typeExpr.type === 'Identifier') { + return [typeExpr.name] + } + if (typeExpr.type === 'ArrayExpression') { + const types = [] + for (const element of typeExpr.elements) { + if (!element) { + continue + } + if (element.type === 'SpreadElement') { + return null + } + for (const elementExpr of resolvedExpressions(context, element)) { + if (elementExpr.type !== 'Identifier') { + return null + } + types.push(elementExpr.name) + } + } + return types + } + return null } - return null } /** - * - * @param {any} obj - */ -const getPrototypeType = (obj) => - Object.prototype.toString.call(obj).slice(8, -1) - -/** - * Get return type of property. - * @param {{ property: ComponentPropertyData, propertyMap?: PropertyMap }} args - * @returns {{type: string | null | 'ReturnStatementHasNotArgument'}} + * Check whether given expression may be a function. + * @param {RuleContext} context + * @param {Expression} node + * @returns {boolean} */ -const getValueType = ({ property, propertyMap }) => { - if (property.type === 'array') { - return { - type: null +function maybeFunction(context, node) { + for (const expr of resolvedExpressions(context, node)) { + if ( + expr.type === 'ObjectExpression' || + expr.type === 'ArrayExpression' || + expr.type === 'Literal' || + expr.type === 'TemplateLiteral' || + expr.type === 'BinaryExpression' || + expr.type === 'LogicalExpression' || + expr.type === 'UnaryExpression' || + expr.type === 'UpdateExpression' + ) { + continue } - } - - if (property.type === 'object') { - if (property.groupName === 'props') { - return { - type: getComponentPropsType(property) + if (expr.type === 'ConditionalExpression') { + if ( + !maybeFunction(context, expr.consequent) && + !maybeFunction(context, expr.alternate) + ) { + continue } } + const evaluated = eslintUtils.getStaticValue( + expr, + utils.getScope(context, expr) + ) + if (!evaluated) { + // It could be a function because we don't know what it is. + return true + } + if (typeof evaluated.value === 'function') { + return true + } + } + return false +} - if (property.groupName === 'computed' || property.groupName === 'methods') { - if ( - property.property.value.type === 'FunctionExpression' && - property.property.value.body.type === 'BlockStatement' - ) { - const blockStatement = property.property.value.body +class FunctionData { + /** + * @param {string} name + * @param {'methods' | 'computed'} kind + * @param {FunctionExpression | ArrowFunctionExpression} node + * @param {RuleContext} context + */ + constructor(name, kind, node, context) { + this.context = context + this.name = name + this.kind = kind + this.node = node + /** @type {(Expression | null)[]} */ + this.returnValues = [] + /** @type {boolean | null} */ + this.cacheMaybeReturnFunction = null + } - /** - * Only check return statement inside computed and methods - */ - const returnStatement = blockStatement.body.find( - (b) => b.type === 'ReturnStatement' - ) + /** + * @param {Expression | null} node + */ + addReturnValue(node) { + this.returnValues.push(node) + } - if (!returnStatement || returnStatement.type !== 'ReturnStatement') - return { - type: null - } + /** + * @param {ComponentStack} component + */ + maybeReturnFunction(component) { + if (this.cacheMaybeReturnFunction != null) { + return this.cacheMaybeReturnFunction + } + // Avoid infinite recursion. + this.cacheMaybeReturnFunction = true - if (returnStatement.argument === null) - return { - type: 'ReturnStatementHasNotArgument' - } + return (this.cacheMaybeReturnFunction = this.returnValues.some( + (returnValue) => + returnValue && component.maybeFunctionExpression(returnValue) + )) + } +} - if ( - property.groupName === 'computed' && - propertyMap && - propertyMap[property.name] && - returnStatement.argument - ) { - if ( - returnStatement.argument.type === 'MemberExpression' && - returnStatement.argument.object.type === 'ThisExpression' && - returnStatement.argument.property.type === 'Identifier' - ) - return { - type: propertyMap[returnStatement.argument.property.name] - .valueType.type - } +/** Component information class. */ +class ComponentStack { + /** + * @param {ObjectExpression} node + * @param {RuleContext} context + * @param {ComponentStack | null} upper + */ + constructor(node, context, upper) { + this.node = node + this.context = context + /** Upper scope component */ + this.upper = upper - if ( - returnStatement.argument.type === 'CallExpression' && - returnStatement.argument.callee.type === 'MemberExpression' && - returnStatement.argument.callee.object.type === 'ThisExpression' && - returnStatement.argument.callee.property.type === 'Identifier' - ) - return { - type: propertyMap[returnStatement.argument.callee.property.name] - .valueType.type - } - } + /** @type {Map} */ + const maybeFunctions = new Map() + /** @type {FunctionData[]} */ + const functions = [] - /** - * Use value as Object even if object includes method - */ - if ( - property.groupName === 'computed' && - returnStatement.argument.type === 'ObjectExpression' - ) { - return { - type: 'Object' + // Extract properties + for (const property of utils.iterateProperties(node, GROUPS)) { + if (property.type === 'array') { + continue + } + if (property.groupName === 'data') { + maybeFunctions.set( + property.name, + maybeFunction(context, property.property.value) + ) + } else if (property.groupName === 'props') { + const types = getComponentPropsTypes(context, property) + maybeFunctions.set( + property.name, + !types || types.some((type) => !NATIVE_NOT_FUNCTION_TYPES.has(type)) + ) + } else if (property.groupName === 'computed') { + let value = property.property.value + if (value.type === 'ObjectExpression') { + const getProp = utils.findProperty(value, 'get') + if (getProp) { + value = getProp.value } } + processFunction(property.name, value, 'computed') + } else if (property.groupName === 'methods') { + const value = property.property.value + processFunction(property.name, value, 'methods') + maybeFunctions.set(property.name, true) + } + } + this.maybeFunctions = maybeFunctions + this.functions = functions + /** @type {CallMember[]} */ + this.callMembers = [] + /** @type {Map} */ + this.cacheMaybeFunctionExpressions = new Map() - const evaluated = eslintUtils.getStaticValue(returnStatement.argument) - - if (evaluated) { - return { - type: getPrototypeType(evaluated.value) - } + /** + * @param {string} name + * @param {Expression} value + * @param {'methods' | 'computed'} kind + */ + function processFunction(name, value, kind) { + if (value.type === 'FunctionExpression') { + functions.push(new FunctionData(name, kind, value, context)) + } else if (value.type === 'ArrowFunctionExpression') { + const data = new FunctionData(name, kind, value, context) + if (value.expression) { + data.addReturnValue(value.body) } + functions.push(data) } } + } - const evaluated = eslintUtils.getStaticValue(property.property.value) - - if (evaluated) { - return { - type: getPrototypeType(evaluated.value) + /** + * Adds the given return statement to the return value of the function. + * @param {FunctionExpression | ArrowFunctionExpression | FunctionDeclaration} scopeFunction + * @param {ReturnStatement} returnNode + */ + addReturnStatement(scopeFunction, returnNode) { + for (const data of this.functions) { + if (data.node === scopeFunction) { + data.addReturnValue(returnNode.argument) + break } } } - return { - type: null + + verifyComponent() { + for (const call of this.callMembers) { + this.verifyCallMember(call) + } } -} -/** - * @param {Set} groups - * @param {ObjectExpression} vueNodeMap - * @param {PropertyMap} propertyMap - */ -const addPropertyMap = (groups, vueNodeMap, propertyMap) => { - const properties = utils.iterateProperties(vueNodeMap, groups) - for (const property of properties) { - propertyMap[property.name] = { - ...propertyMap[property.name], - ...property, - valueType: getValueType({ property, propertyMap }) + /** + * @param {CallMember} call + */ + verifyCallMember(call) { + const fnData = this.functions.find( + (data) => data.name === call.name && data.kind === 'computed' + ) + if (!fnData) { + // It is not computed, or unknown. + return + } + + if (!fnData.maybeReturnFunction(this)) { + const prefix = call.node.callee.type === 'MemberExpression' ? 'this.' : '' + this.context.report({ + node: call.node, + messageId: 'unexpected', + data: { + likeProperty: `${prefix}${call.name}`, + likeMethod: `${prefix}${call.name}()` + } + }) + } + } + + /** + * Check whether given expression may be a function. + * @param {Expression} node + * @returns {boolean} + */ + maybeFunctionExpression(node) { + const cache = this.cacheMaybeFunctionExpressions.get(node) + if (cache != null) { + return cache + } + // Avoid infinite recursion. + this.cacheMaybeFunctionExpressions.set(node, true) + + const result = maybeFunctionExpressionWithoutCache.call(this) + this.cacheMaybeFunctionExpressions.set(node, result) + return result + + /** + * @this {ComponentStack} + */ + function maybeFunctionExpressionWithoutCache() { + for (const expr of resolvedExpressions(this.context, node)) { + if (!maybeFunction(this.context, expr)) { + continue + } + if (expr.type === 'MemberExpression') { + if (utils.isThis(expr.object, this.context)) { + const name = utils.getStaticPropertyName(expr) + if (name && !this.maybeFunctionProperty(name)) { + continue + } + } + } else if (expr.type === 'CallExpression') { + if ( + expr.callee.type === 'MemberExpression' && + utils.isThis(expr.callee.object, this.context) + ) { + const name = utils.getStaticPropertyName(expr.callee) + const fnData = this.functions.find((data) => data.name === name) + if ( + fnData && + fnData.kind === 'methods' && + !fnData.maybeReturnFunction(this) + ) { + continue + } + } + } else if (expr.type === 'ConditionalExpression') { + if ( + !this.maybeFunctionExpression(expr.consequent) && + !this.maybeFunctionExpression(expr.alternate) + ) { + continue + } + } + // It could be a function because we don't know what it is. + return true + } + return false + } + } + + /** + * Check whether given property name may be a function. + * @param {string} name + * @returns {boolean} + */ + maybeFunctionProperty(name) { + const cache = this.maybeFunctions.get(name) + if (cache != null) { + return cache + } + // Avoid infinite recursion. + this.maybeFunctions.set(name, true) + + const result = maybeFunctionPropertyWithoutCache.call(this) + this.maybeFunctions.set(name, result) + return result + + /** + * @this {ComponentStack} + */ + function maybeFunctionPropertyWithoutCache() { + const fnData = this.functions.find((data) => data.name === name) + if (fnData && fnData.kind === 'computed') { + return fnData.maybeReturnFunction(this) + } + // It could be a function because we don't know what it is. + return true } } } @@ -199,63 +494,99 @@ module.exports = { }, /** @param {RuleContext} context */ create(context) { - /** @type {GroupName[]} */ - const GROUP_NAMES = ['data', 'props', 'computed', 'methods'] - const groups = new Set(GROUP_NAMES) - - /** @type {PropertyMap} */ - const propertyMap = Object.create(null) - - return utils.defineVueVisitor(context, { - onVueObjectEnter(node) { - const properties = utils.iterateProperties(node, groups) - - for (const property of properties) { - propertyMap[property.name] = { - ...propertyMap[property.name], - ...property, - valueType: getValueType({ property }) - } - } - }, + /** + * @typedef {object} ScopeStack + * @property {ScopeStack | null} upper + * @property {FunctionDeclaration | FunctionExpression | ArrowFunctionExpression} scopeNode + */ + /** @type {ScopeStack | null} */ + let scopeStack = null - /** @param {ThisExpression} node */ - 'CallExpression > MemberExpression > ThisExpression'( - node, - { node: vueNode } - ) { - addPropertyMap(groups, vueNode, propertyMap) + /** @type {ComponentStack | null} */ + let componentStack = null + /** @type {ComponentStack | null} */ + let templateComponent = null - if (node.parent.type !== 'MemberExpression') return - if (node.parent.property.type !== 'Identifier') return - if (node.parent.parent.type !== 'CallExpression') return - if (node.parent.parent.callee.type !== 'MemberExpression') return - if (!Object.is(node.parent.parent.callee, node.parent)) return - - const thisMember = node.parent.property.name + return utils.compositingVisitors( + {}, + utils.defineVueVisitor(context, { + onVueObjectEnter(node) { + componentStack = new ComponentStack(node, context, componentStack) + if (!templateComponent && utils.isInExportDefault(node)) { + templateComponent = componentStack + } + }, + onVueObjectExit() { + if (componentStack) { + componentStack.verifyComponent() + componentStack = componentStack.upper + } + }, + /** + * @param {FunctionExpression | FunctionDeclaration | ArrowFunctionExpression} node + */ + ':function'(node) { + scopeStack = { + upper: scopeStack, + scopeNode: node + } + }, + ReturnStatement(node) { + if (scopeStack && componentStack) { + componentStack.addReturnStatement(scopeStack.scopeNode, node) + } + }, + ':function:exit'() { + scopeStack = scopeStack && scopeStack.upper + }, - if ( - !propertyMap[thisMember] || - !propertyMap[thisMember].valueType || - !propertyMap[thisMember].valueType.type - ) - return - - if ( - propertyMap[thisMember].groupName === 'computed' && - propertyMap[thisMember].valueType.type !== 'Function' - ) { - context.report({ - node: node.parent.parent, - loc: node.parent.parent.loc, - messageId: 'unexpected', - data: { - likeProperty: `this.${thisMember}`, - likeMethod: `this.${thisMember}()` + /** + * @param {ThisExpression | Identifier} node + */ + 'ThisExpression, Identifier'(node) { + if ( + !componentStack || + node.parent.type !== 'MemberExpression' || + node.parent.object !== node || + node.parent.parent.type !== 'CallExpression' || + node.parent.parent.callee !== node.parent || + !utils.isThis(node, context) + ) { + return + } + const name = utils.getStaticPropertyName(node.parent) + if (name) { + componentStack.callMembers.push({ + name, + node: node.parent.parent + }) + } + } + }), + utils.defineTemplateBodyVisitor(context, { + /** + * @param {VExpressionContainer} node + */ + VExpressionContainer(node) { + if (!templateComponent) { + return + } + for (const id of node.references + .filter((ref) => ref.variable == null) + .map((ref) => ref.id)) { + if ( + id.parent.type !== 'CallExpression' || + id.parent.callee !== id + ) { + continue } - }) + templateComponent.verifyCallMember({ + name: id.name, + node: id.parent + }) + } } - } - }) + }) + ) } } diff --git a/lib/utils/index.js b/lib/utils/index.js index b17de0821..36614cd14 100644 --- a/lib/utils/index.js +++ b/lib/utils/index.js @@ -1717,6 +1717,14 @@ module.exports = { * Retrieve `ChainExpression#expression` value if the given node a `ChainExpression` node. Otherwise, pass through it. */ skipChainExpression, + findVariableByIdentifier, + getScope, + /** + * Checks whether the given node is in export default. + * @param {ASTNode} node + * @returns {boolean} + */ + isInExportDefault, /** * Check whether the given node is `this` or variable that stores `this`. @@ -2004,6 +2012,43 @@ function compositingVisitors(visitor, ...visitors) { // AST Helpers // ------------------------------------------------------------------------------ +/** + * Find the variable of a given identifier. + * @param {RuleContext} context The rule context + * @param {Identifier} node The variable name to find. + * @returns {Variable|null} The found variable or null. + */ +function findVariableByIdentifier(context, node) { + return findVariable(getScope(context, node), node) +} + +/** + * Gets the scope for the current node + * @param {RuleContext} context The rule context + * @param {ESNode} currentNode The node to get the scope of + * @returns { import('eslint').Scope.Scope } The scope information for this node + */ +function getScope(context, currentNode) { + // On Program node, get the outermost scope to avoid return Node.js special function scope or ES modules scope. + const inner = currentNode.type !== 'Program' + const scopeManager = context.getSourceCode().scopeManager + + /** @type {ESNode | null} */ + let node = currentNode + for (; node; node = /** @type {ESNode | null} */ (node.parent)) { + const scope = scopeManager.acquire(node, inner) + + if (scope) { + if (scope.type === 'function-expression-name') { + return scope.childScopes[0] + } + return scope + } + } + + return scopeManager.scopes[0] +} + /** * Finds the property with the given name from the given ObjectExpression node. * @param {ObjectExpression} node @@ -2081,6 +2126,23 @@ function isVElement(node) { return node.type === 'VElement' } +/** + * Checks whether the given node is in export default. + * @param {ASTNode} node + * @returns {boolean} + */ +function isInExportDefault(node) { + /** @type {ASTNode | null} */ + let parent = node.parent + while (parent) { + if (parent.type === 'ExportDefaultDeclaration') { + return true + } + parent = parent.parent + } + return false +} + /** * Retrieve `TSAsExpression#expression` value if the given node a `TSAsExpression` node. Otherwise, pass through it. * @template T Node type diff --git a/lib/utils/property-references.js b/lib/utils/property-references.js index f375170c3..37709ee0b 100644 --- a/lib/utils/property-references.js +++ b/lib/utils/property-references.js @@ -40,49 +40,13 @@ const NEVER = { getNest: () => NEVER } -/** - * Find the variable of a given name. - * @param {RuleContext} context The rule context - * @param {Identifier} node The variable name to find. - * @returns {Variable|null} The found variable or null. - */ -function findVariable(context, node) { - return eslintUtils.findVariable(getScope(context, node), node) -} -/** - * Gets the scope for the current node - * @param {RuleContext} context The rule context - * @param {ESNode} currentNode The node to get the scope of - * @returns { import('eslint').Scope.Scope } The scope information for this node - */ -function getScope(context, currentNode) { - // On Program node, get the outermost scope to avoid return Node.js special function scope or ES modules scope. - const inner = currentNode.type !== 'Program' - const scopeManager = context.getSourceCode().scopeManager - - /** @type {ESNode | null} */ - let node = currentNode - for (; node; node = /** @type {ESNode | null} */ (node.parent)) { - const scope = scopeManager.acquire(node, inner) - - if (scope) { - if (scope.type === 'function-expression-name') { - return scope.childScopes[0] - } - return scope - } - } - - return scopeManager.scopes[0] -} - /** * @param {RuleContext} context * @param {Identifier} id * @returns {FunctionExpression | ArrowFunctionExpression | FunctionDeclaration | null} */ function findFunction(context, id) { - const calleeVariable = findVariable(context, id) + const calleeVariable = utils.findVariableByIdentifier(context, id) if (!calleeVariable) { return null } @@ -420,7 +384,7 @@ function definePropertyReferenceExtractor(context) { * @returns {IPropertyReferences} */ function extractFromIdentifier(node) { - const variable = findVariable(context, node) + const variable = utils.findVariableByIdentifier(context, node) if (!variable) { return NEVER } diff --git a/tests/lib/rules/no-use-computed-property-like-method.js b/tests/lib/rules/no-use-computed-property-like-method.js index 902f29b19..539e6275a 100644 --- a/tests/lib/rules/no-use-computed-property-like-method.js +++ b/tests/lib/rules/no-use-computed-property-like-method.js @@ -16,7 +16,7 @@ const rule = require('../../../lib/rules/no-use-computed-property-like-method') const tester = new RuleTester({ parser: require.resolve('vue-eslint-parser'), - parserOptions: { ecmaVersion: 2015, sourceType: 'module' } + parserOptions: { ecmaVersion: 2020, sourceType: 'module' } }) tester.run('no-use-computed-property-like-method', rule, { @@ -438,6 +438,137 @@ tester.run('no-use-computed-property-like-method', rule, { } ` + }, + { + //https://github.com/vuejs/eslint-plugin-vue/issues/1649 + filename: 'test.vue', + code: ` + + ` + }, + { + filename: 'test.vue', + code: ` + + ` + }, + { + filename: 'test.vue', + code: ` + + ` + }, + { + filename: 'test.vue', + code: ` + + ` + }, + { + filename: 'test.vue', + code: ` + + ` + }, + { + filename: 'test.vue', + code: ` + + ` } ], invalid: [ @@ -762,6 +893,214 @@ tester.run('no-use-computed-property-like-method', rule, { 'Use this.computedReturnArray instead of this.computedReturnArray().', 'Use this.computedReturnArray2 instead of this.computedReturnArray2().' ] + }, + { + filename: 'test.vue', + code: ` + + `, + errors: ['Use this.x instead of this.x().'] + }, + { + filename: 'test.vue', + code: ` + + `, + errors: ['Use this.x instead of this.x().'] + }, + { + filename: 'test.vue', + code: ` + + `, + errors: ['Use this.x instead of this.x().'] + }, + { + filename: 'test.vue', + code: ` + + `, + errors: ['Use this.x instead of this.x().'] + }, + { + filename: 'test.vue', + code: ` + + `, + errors: ['Use this.x instead of this.x().'] + }, + { + filename: 'test.vue', + code: ` + + `, + errors: ['Use this.x instead of this.x().'] + }, + { + filename: 'test.vue', + code: ` + + `, + errors: ['Use this.x instead of this.x().'] + }, + { + filename: 'test.vue', + code: ` + + + `, + errors: ['Use x instead of x().'] } ] }) From 928e0c62f3370dd405e567eb8f5763b1678dfbb7 Mon Sep 17 00:00:00 2001 From: Yosuke Ota Date: Tue, 19 Oct 2021 08:30:45 +0900 Subject: [PATCH 002/622] Fix false positives for vars inside type in vue/valid-define-emits and vue/valid-define-props rules (#1658) --- lib/rules/valid-define-emits.js | 3 ++ lib/rules/valid-define-props.js | 3 ++ lib/utils/indent-ts.js | 40 ++--------------------- lib/utils/index.js | 24 +++++++++++++- lib/utils/ts-ast-utils.js | 46 +++++++++++++++++++++++++++ tests/lib/rules/valid-define-emits.js | 44 +++++++++++++++++++++++++ tests/lib/rules/valid-define-props.js | 44 +++++++++++++++++++++++++ 7 files changed, 165 insertions(+), 39 deletions(-) diff --git a/lib/rules/valid-define-emits.js b/lib/rules/valid-define-emits.js index 1fabbc025..b16fc300e 100644 --- a/lib/rules/valid-define-emits.js +++ b/lib/rules/valid-define-emits.js @@ -85,6 +85,9 @@ module.exports = { !utils.inRange(defineEmits.range, def.name) ) ) { + if (utils.withinTypeNode(node)) { + continue + } //`defineEmits` are referencing locally declared variables. context.report({ node, diff --git a/lib/rules/valid-define-props.js b/lib/rules/valid-define-props.js index b67af7c8c..273eae70a 100644 --- a/lib/rules/valid-define-props.js +++ b/lib/rules/valid-define-props.js @@ -86,6 +86,9 @@ module.exports = { !utils.inRange(defineProps.range, def.name) ) ) { + if (utils.withinTypeNode(node)) { + continue + } //`defineProps` are referencing locally declared variables. context.report({ node, diff --git a/lib/utils/indent-ts.js b/lib/utils/indent-ts.js index ed2080750..b98e9d105 100644 --- a/lib/utils/indent-ts.js +++ b/lib/utils/indent-ts.js @@ -12,6 +12,7 @@ const { isClosingBracketToken, isOpeningBracketToken } = require('eslint-utils') +const { isTypeNode } = require('./ts-ast-utils') /** * @typedef {import('../../typings/eslint-plugin-vue/util-types/indent-helper').TSNodeListener} TSNodeListener @@ -224,46 +225,9 @@ function defineVisitor({ */ // eslint-disable-next-line complexity -- ignore '*[type=/^TS/]'(node) { - if ( - node.type !== 'TSAnyKeyword' && - node.type !== 'TSArrayType' && - node.type !== 'TSBigIntKeyword' && - node.type !== 'TSBooleanKeyword' && - node.type !== 'TSConditionalType' && - node.type !== 'TSConstructorType' && - node.type !== 'TSFunctionType' && - node.type !== 'TSImportType' && - node.type !== 'TSIndexedAccessType' && - node.type !== 'TSInferType' && - node.type !== 'TSIntersectionType' && - node.type !== 'TSIntrinsicKeyword' && - node.type !== 'TSLiteralType' && - node.type !== 'TSMappedType' && - node.type !== 'TSNamedTupleMember' && - node.type !== 'TSNeverKeyword' && - node.type !== 'TSNullKeyword' && - node.type !== 'TSNumberKeyword' && - node.type !== 'TSObjectKeyword' && - node.type !== 'TSOptionalType' && - node.type !== 'TSRestType' && - node.type !== 'TSStringKeyword' && - node.type !== 'TSSymbolKeyword' && - node.type !== 'TSTemplateLiteralType' && - node.type !== 'TSThisType' && - node.type !== 'TSTupleType' && - node.type !== 'TSTypeLiteral' && - node.type !== 'TSTypeOperator' && - node.type !== 'TSTypePredicate' && - node.type !== 'TSTypeQuery' && - node.type !== 'TSTypeReference' && - node.type !== 'TSUndefinedKeyword' && - node.type !== 'TSUnionType' && - node.type !== 'TSUnknownKeyword' && - node.type !== 'TSVoidKeyword' - ) { + if (!isTypeNode(node)) { return } - /** @type {TypeNode} */ const typeNode = node if (/** @type {any} */ (typeNode.parent).type === 'TSParenthesizedType') { return diff --git a/lib/utils/index.js b/lib/utils/index.js index 36614cd14..5c49d15f2 100644 --- a/lib/utils/index.js +++ b/lib/utils/index.js @@ -54,7 +54,8 @@ const { traverseNodes, getFallbackKeys } = vueEslintParser.AST const { findVariable } = require('eslint-utils') const { getComponentPropsFromTypeDefine, - getComponentEmitsFromTypeDefine + getComponentEmitsFromTypeDefine, + isTypeNode } = require('./ts-ast-utils') /** @@ -1717,6 +1718,10 @@ module.exports = { * Retrieve `ChainExpression#expression` value if the given node a `ChainExpression` node. Otherwise, pass through it. */ skipChainExpression, + /** + * Checks whether the given node is in a type annotation. + */ + withinTypeNode, findVariableByIdentifier, getScope, /** @@ -2226,6 +2231,23 @@ function skipChainExpression(node) { return node } +/** + * Checks whether the given node is in a type annotation. + * @param {ESNode} node + * @returns {boolean} + */ +function withinTypeNode(node) { + /** @type {ASTNode | null} */ + let target = node + while (target) { + if (isTypeNode(target)) { + return true + } + target = target.parent + } + return false +} + /** * Gets the property name of a given node. * @param {Property|AssignmentProperty|MethodDefinition|MemberExpression} node - The node to get. diff --git a/lib/utils/ts-ast-utils.js b/lib/utils/ts-ast-utils.js index b801b6374..6777859b8 100644 --- a/lib/utils/ts-ast-utils.js +++ b/lib/utils/ts-ast-utils.js @@ -4,6 +4,7 @@ const { findVariable } = require('eslint-utils') * @typedef {import('@typescript-eslint/types').TSESTree.TSInterfaceBody} TSInterfaceBody * @typedef {import('@typescript-eslint/types').TSESTree.TSTypeLiteral} TSTypeLiteral * @typedef {import('@typescript-eslint/types').TSESTree.Parameter} TSESTreeParameter + * @typedef {import('@typescript-eslint/types').TSESTree.Node} Node * */ /** @@ -12,10 +13,55 @@ const { findVariable } = require('eslint-utils') */ module.exports = { + isTypeNode, getComponentPropsFromTypeDefine, getComponentEmitsFromTypeDefine } +/** + * @param {Node | ASTNode} node + * @returns {node is TypeNode} + */ +function isTypeNode(node) { + return ( + node.type === 'TSAnyKeyword' || + node.type === 'TSArrayType' || + node.type === 'TSBigIntKeyword' || + node.type === 'TSBooleanKeyword' || + node.type === 'TSConditionalType' || + node.type === 'TSConstructorType' || + node.type === 'TSFunctionType' || + node.type === 'TSImportType' || + node.type === 'TSIndexedAccessType' || + node.type === 'TSInferType' || + node.type === 'TSIntersectionType' || + node.type === 'TSIntrinsicKeyword' || + node.type === 'TSLiteralType' || + node.type === 'TSMappedType' || + node.type === 'TSNamedTupleMember' || + node.type === 'TSNeverKeyword' || + node.type === 'TSNullKeyword' || + node.type === 'TSNumberKeyword' || + node.type === 'TSObjectKeyword' || + node.type === 'TSOptionalType' || + node.type === 'TSRestType' || + node.type === 'TSStringKeyword' || + node.type === 'TSSymbolKeyword' || + node.type === 'TSTemplateLiteralType' || + node.type === 'TSThisType' || + node.type === 'TSTupleType' || + node.type === 'TSTypeLiteral' || + node.type === 'TSTypeOperator' || + node.type === 'TSTypePredicate' || + node.type === 'TSTypeQuery' || + node.type === 'TSTypeReference' || + node.type === 'TSUndefinedKeyword' || + node.type === 'TSUnionType' || + node.type === 'TSUnknownKeyword' || + node.type === 'TSVoidKeyword' + ) +} + /** * @param {TypeNode} node * @returns {node is TSTypeLiteral} diff --git a/tests/lib/rules/valid-define-emits.js b/tests/lib/rules/valid-define-emits.js index 542805848..557101d67 100644 --- a/tests/lib/rules/valid-define-emits.js +++ b/tests/lib/rules/valid-define-emits.js @@ -73,6 +73,50 @@ tester.run('valid-define-emits', rule, { }) ` + }, + { + // https://github.com/vuejs/eslint-plugin-vue/issues/1656 + filename: 'test.vue', + parserOptions: { + parser: require.resolve('@typescript-eslint/parser') + }, + code: ` + + ` + }, + { + filename: 'test.vue', + parserOptions: { + parser: require.resolve('@typescript-eslint/parser') + }, + code: ` + + ` } ], invalid: [ diff --git a/tests/lib/rules/valid-define-props.js b/tests/lib/rules/valid-define-props.js index cb1f50daf..10894e069 100644 --- a/tests/lib/rules/valid-define-props.js +++ b/tests/lib/rules/valid-define-props.js @@ -76,6 +76,50 @@ tester.run('valid-define-props', rule, { }) ` + }, + { + // https://github.com/vuejs/eslint-plugin-vue/issues/1656 + filename: 'test.vue', + parserOptions: { + parser: require.resolve('@typescript-eslint/parser') + }, + code: ` + + ` + }, + { + filename: 'test.vue', + parserOptions: { + parser: require.resolve('@typescript-eslint/parser') + }, + code: ` + + ` } ], invalid: [ From a74dd594fa1f9e72ae305a0bb07c620b96eeb8e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A1rton=20Csord=C3=A1s?= Date: Tue, 19 Oct 2021 01:42:28 +0200 Subject: [PATCH 003/622] Add `multi-word-component-names` rule (#1661) * Add `multi-word-component-names` rule * Fix review comments for `multi-word-component-names` rule --- docs/rules/README.md | 1 + docs/rules/multi-word-component-names.md | 84 ++++++ lib/index.js | 1 + lib/rules/multi-word-component-names.js | 115 ++++++++ tests/lib/rules/multi-word-component-names.js | 253 ++++++++++++++++++ 5 files changed, 454 insertions(+) create mode 100644 docs/rules/multi-word-component-names.md create mode 100644 lib/rules/multi-word-component-names.js create mode 100644 tests/lib/rules/multi-word-component-names.js diff --git a/docs/rules/README.md b/docs/rules/README.md index 3f65e92c4..401329378 100644 --- a/docs/rules/README.md +++ b/docs/rules/README.md @@ -296,6 +296,7 @@ For example: | [vue/html-comment-content-spacing](./html-comment-content-spacing.md) | enforce unified spacing in HTML comments | :wrench: | | [vue/html-comment-indent](./html-comment-indent.md) | enforce consistent indentation in HTML comments | :wrench: | | [vue/match-component-file-name](./match-component-file-name.md) | require component name property to match its file name | | +| [vue/multi-word-component-names](./multi-word-component-names.md) | require component names to be always multi-word | | | [vue/new-line-between-multi-line-property](./new-line-between-multi-line-property.md) | enforce new lines between multi-line properties in Vue components | :wrench: | | [vue/next-tick-style](./next-tick-style.md) | enforce Promise or callback style in `nextTick` | :wrench: | | [vue/no-bare-strings-in-template](./no-bare-strings-in-template.md) | disallow the use of bare strings in ``, v-bind:age="user.age">`, errors: ["'v-bind:age' should be on a new line."] }, - { - code: ``, - output: ``, - errors: [ - { - message: "'job' should be on a new line.", - type: 'VAttribute', - line: 1 - } - ] - }, { code: ``, options: [{ singleline: { max: 2 } }], @@ -164,70 +112,6 @@ job="Vet">`, } ] }, - { - code: ``, - options: [ - { singleline: 1, multiline: { max: 1, allowFirstLine: false } } - ], - output: ``, - errors: [ - { - message: "'age' should be on a new line.", - type: 'VAttribute', - line: 1 - }, - { - message: "'job' should be on a new line.", - type: 'VAttribute', - line: 1 - } - ] - }, - { - code: ``, - options: [ - { singleline: 3, multiline: { max: 1, allowFirstLine: false } } - ], - output: ``, - errors: [ - { - message: "'name' should be on a new line.", - type: 'VAttribute', - line: 1 - } - ] - }, - { - code: ``, - options: [ - { singleline: 3, multiline: { max: 1, allowFirstLine: false } } - ], - output: ``, - errors: [ - { - message: "'age' should be on a new line.", - type: 'VAttribute', - line: 2 - } - ] - }, { code: ``, - options: [ - { singleline: 3, multiline: { max: 2, allowFirstLine: false } } - ], - output: ``, - errors: [ - { - message: "'petname' should be on a new line.", - type: 'VAttribute', - line: 3 - } - ] - }, - { - code: ``, - options: [ - { singleline: 3, multiline: { max: 2, allowFirstLine: false } } - ], - output: ``, - errors: [ - { - message: "'petname' should be on a new line.", - type: 'VAttribute', - line: 3 - }, - { - message: "'extra' should be on a new line.", - type: 'VAttribute', - line: 3 - } - ] - }, - { - code: ``, - options: [{ singleline: { allowFirstLine: false } }], - output: ``, - errors: [ - { - message: "'name' should be on a new line.", - type: 'VAttribute', - line: 1 - } - ] } ] }) From bf771696172e07c05e2eb60533b6e4ce5922013a Mon Sep 17 00:00:00 2001 From: Yosuke Ota Date: Wed, 20 Oct 2021 14:14:26 +0900 Subject: [PATCH 009/622] Change presets configs. (#1603) * Change config * valid-next-tick to essential * update * Update --- docs/rules/README.md | 26 +++++++++++-------- docs/rules/multi-word-component-names.md | 2 ++ docs/rules/no-computed-properties-in-data.md | 2 ++ .../no-deprecated-router-link-tag-prop.md | 2 ++ docs/rules/no-deprecated-v-is.md | 1 + docs/rules/no-export-in-script-setup.md | 2 ++ docs/rules/no-useless-template-attributes.md | 2 ++ docs/rules/v-on-event-hyphenation.md | 1 + docs/rules/valid-define-emits.md | 2 ++ docs/rules/valid-define-props.md | 2 ++ docs/rules/valid-next-tick.md | 1 + docs/rules/valid-v-memo.md | 2 ++ lib/configs/essential.js | 4 +++ lib/configs/vue3-essential.js | 10 +++++++ lib/configs/vue3-strongly-recommended.js | 1 + lib/rules/multi-word-component-names.js | 2 +- lib/rules/no-computed-properties-in-data.js | 2 +- .../no-deprecated-router-link-tag-prop.js | 2 +- lib/rules/no-deprecated-v-is.js | 4 +-- lib/rules/no-export-in-script-setup.js | 4 +-- lib/rules/no-useless-template-attributes.js | 4 +-- lib/rules/v-on-event-hyphenation.js | 4 +-- lib/rules/valid-define-emits.js | 4 +-- lib/rules/valid-define-props.js | 4 +-- lib/rules/valid-next-tick.js | 3 +-- lib/rules/valid-v-is.js | 2 -- lib/rules/valid-v-memo.js | 4 +-- 27 files changed, 60 insertions(+), 39 deletions(-) diff --git a/docs/rules/README.md b/docs/rules/README.md index 40a6a6d28..04d9046c1 100644 --- a/docs/rules/README.md +++ b/docs/rules/README.md @@ -39,8 +39,10 @@ Enforce all the rules in this category, as well as all higher priority rules, wi | Rule ID | Description | | |:--------|:------------|:---| +| [vue/multi-word-component-names](./multi-word-component-names.md) | require component names to be always multi-word | | | [vue/no-arrow-functions-in-watch](./no-arrow-functions-in-watch.md) | disallow using arrow functions to define watcher | | | [vue/no-async-in-computed-properties](./no-async-in-computed-properties.md) | disallow asynchronous actions in computed properties | | +| [vue/no-computed-properties-in-data](./no-computed-properties-in-data.md) | disallow accessing computed properties in `data`. | | | [vue/no-deprecated-data-object-declaration](./no-deprecated-data-object-declaration.md) | disallow using deprecated object declaration on data (in Vue.js 3.0.0+) | :wrench: | | [vue/no-deprecated-destroyed-lifecycle](./no-deprecated-destroyed-lifecycle.md) | disallow using deprecated `destroyed` and `beforeDestroy` lifecycle hooks (in Vue.js 3.0.0+) | :wrench: | | [vue/no-deprecated-dollar-listeners-api](./no-deprecated-dollar-listeners-api.md) | disallow using deprecated `$listeners` (in Vue.js 3.0.0+) | | @@ -51,16 +53,19 @@ Enforce all the rules in this category, as well as all higher priority rules, wi | [vue/no-deprecated-html-element-is](./no-deprecated-html-element-is.md) | disallow using deprecated the `is` attribute on HTML elements (in Vue.js 3.0.0+) | | | [vue/no-deprecated-inline-template](./no-deprecated-inline-template.md) | disallow using deprecated `inline-template` attribute (in Vue.js 3.0.0+) | | | [vue/no-deprecated-props-default-this](./no-deprecated-props-default-this.md) | disallow deprecated `this` access in props default function (in Vue.js 3.0.0+) | | +| [vue/no-deprecated-router-link-tag-prop](./no-deprecated-router-link-tag-prop.md) | disallow using deprecated `tag` property on `RouterLink` (in Vue.js 3.0.0+) | | | [vue/no-deprecated-scope-attribute](./no-deprecated-scope-attribute.md) | disallow deprecated `scope` attribute (in Vue.js 2.5.0+) | :wrench: | | [vue/no-deprecated-slot-attribute](./no-deprecated-slot-attribute.md) | disallow deprecated `slot` attribute (in Vue.js 2.6.0+) | :wrench: | | [vue/no-deprecated-slot-scope-attribute](./no-deprecated-slot-scope-attribute.md) | disallow deprecated `slot-scope` attribute (in Vue.js 2.6.0+) | :wrench: | | [vue/no-deprecated-v-bind-sync](./no-deprecated-v-bind-sync.md) | disallow use of deprecated `.sync` modifier on `v-bind` directive (in Vue.js 3.0.0+) | :wrench: | +| [vue/no-deprecated-v-is](./no-deprecated-v-is.md) | disallow deprecated `v-is` directive (in Vue.js 3.1.0+) | :wrench: | | [vue/no-deprecated-v-on-native-modifier](./no-deprecated-v-on-native-modifier.md) | disallow using deprecated `.native` modifiers (in Vue.js 3.0.0+) | | | [vue/no-deprecated-v-on-number-modifiers](./no-deprecated-v-on-number-modifiers.md) | disallow using deprecated number (keycode) modifiers (in Vue.js 3.0.0+) | :wrench: | | [vue/no-deprecated-vue-config-keycodes](./no-deprecated-vue-config-keycodes.md) | disallow using deprecated `Vue.config.keyCodes` (in Vue.js 3.0.0+) | | | [vue/no-dupe-keys](./no-dupe-keys.md) | disallow duplication of field names | | | [vue/no-dupe-v-else-if](./no-dupe-v-else-if.md) | disallow duplicate conditions in `v-if` / `v-else-if` chains | | | [vue/no-duplicate-attributes](./no-duplicate-attributes.md) | disallow duplication of attributes | | +| [vue/no-export-in-script-setup](./no-export-in-script-setup.md) | disallow `export` in ` +``` + + + + + +```vue + +``` + + ## :books: Further Reading -- [Style guide - Multi-word component names](https://vuejs.org/v2/style-guide/#Multi-word-component-names-essential) +- [Style guide - Multi-word component names](https://v3.vuejs.org/style-guide/#multi-word-component-names-essential) ## :rocket: Version diff --git a/lib/rules/multi-word-component-names.js b/lib/rules/multi-word-component-names.js index 46e7bfac0..18cc79601 100644 --- a/lib/rules/multi-word-component-names.js +++ b/lib/rules/multi-word-component-names.js @@ -15,23 +15,6 @@ const RESERVED_NAMES_IN_VUE3 = new Set( require('../utils/vue3-builtin-components') ) -// ------------------------------------------------------------------------------ -// Helpers -// ------------------------------------------------------------------------------ - -/** - * Returns true if the given component name is valid, otherwise false. - * @param {string} name - * */ -function isValidComponentName(name) { - if (name.toLowerCase() === 'app' || RESERVED_NAMES_IN_VUE3.has(name)) { - return true - } else { - const elements = casing.kebabCase(name).split('-') - return elements.length > 1 - } -} - // ------------------------------------------------------------------------------ // Rule Definition // ------------------------------------------------------------------------------ @@ -44,22 +27,92 @@ module.exports = { categories: ['vue3-essential', 'essential'], url: 'https://eslint.vuejs.org/rules/multi-word-component-names.html' }, - schema: [], + schema: [ + { + type: 'object', + properties: { + ignores: { + type: 'array', + items: { type: 'string' }, + uniqueItems: true, + additionalItems: false + } + }, + additionalProperties: false + } + ], messages: { unexpected: 'Component name "{{value}}" should always be multi-word.' } }, /** @param {RuleContext} context */ create(context) { - const fileName = context.getFilename() - let componentName = fileName.replace(/\.[^/.]+$/, '') + /** @type {Set} */ + const ignores = new Set() + ignores.add('App') + ignores.add('app') + for (const ignore of (context.options[0] && context.options[0].ignores) || + []) { + ignores.add(ignore) + if (casing.isPascalCase(ignore)) { + // PascalCase + ignores.add(casing.kebabCase(ignore)) + } + } + let hasVue = false + let hasName = false + + /** + * Returns true if the given component name is valid, otherwise false. + * @param {string} name + * */ + function isValidComponentName(name) { + if (ignores.has(name) || RESERVED_NAMES_IN_VUE3.has(name)) { + return true + } + const elements = casing.kebabCase(name).split('-') + return elements.length > 1 + } + + /** + * @param {Expression | SpreadElement} nameNode + */ + function validateName(nameNode) { + if (nameNode.type !== 'Literal') return + const componentName = `${nameNode.value}` + if (!isValidComponentName(componentName)) { + context.report({ + node: nameNode, + messageId: 'unexpected', + data: { + value: componentName + } + }) + } + } return utils.compositingVisitors( + utils.executeOnCallVueComponent(context, (node) => { + hasVue = true + if (node.arguments.length !== 2) return + hasName = true + validateName(node.arguments[0]) + }), + utils.executeOnVue(context, (obj) => { + hasVue = true + const node = utils.findProperty(obj, 'name') + if (!node) return + hasName = true + validateName(node.value) + }), { /** @param {Program} node */ - Program(node) { + 'Program:exit'(node) { + if (hasName) return + if (!hasVue && node.body.length > 0) return + const fileName = context.getFilename() + const componentName = fileName.replace(/\.[^/.]+$/, '') if ( - !node.body.length && utils.isVueFile(fileName) && !isValidComponentName(componentName) ) { @@ -72,44 +125,7 @@ module.exports = { }) } } - }, - - utils.executeOnVue(context, (obj) => { - const node = utils.findProperty(obj, 'name') - - /** @type {SourceLocation | null} */ - let loc = null - - // Check if the component has a name property. - if (node) { - const valueNode = node.value - if (valueNode.type !== 'Literal') return - - componentName = `${valueNode.value}` - loc = node.loc - } else if ( - obj.parent.type === 'CallExpression' && - obj.parent.arguments.length === 2 - ) { - // The component is registered globally with 'Vue.component', where - // the first paremter is the component name. - const argument = obj.parent.arguments[0] - if (argument.type !== 'Literal') return - - componentName = `${argument.value}` - loc = argument.loc - } - - if (!isValidComponentName(componentName)) { - context.report({ - messageId: 'unexpected', - data: { - value: componentName - }, - loc: loc || { line: 1, column: 0 } - }) - } - }) + } ) } } diff --git a/tests/lib/rules/multi-word-component-names.js b/tests/lib/rules/multi-word-component-names.js index 65b777984..d143f6388 100644 --- a/tests/lib/rules/multi-word-component-names.js +++ b/tests/lib/rules/multi-word-component-names.js @@ -158,6 +158,17 @@ tester.run('multi-word-component-names', rule, { Vue.component('TheTest', {}) ` + }, + { + filename: 'test.vue', + options: [{ ignores: ['Todo'] }], + code: ` + + ` } ], invalid: [ @@ -248,6 +259,23 @@ tester.run('multi-word-component-names', rule, { line: 3 } ] + }, + { + filename: 'test.vue', + options: [{ ignores: ['Todo'] }], + code: ` + + `, + errors: [ + { + message: 'Component name "Item" should always be multi-word.', + line: 4 + } + ] } ] }) From 44ff0e02cd0fd08b8cd7dee0127dbb5590446323 Mon Sep 17 00:00:00 2001 From: Ivo Janssen Date: Thu, 28 Oct 2021 00:18:54 -0700 Subject: [PATCH 013/622] feat: add `setup-compiler-macros` environment for enabling ``, + errors: [ + { + message: "Variable 'i' is already declared in the upper scope.", + type: 'Identifier', + line: 2 + } + ] + }, { filename: 'test.vue', code: ` `, - options: ['always', { exceptions: ['+'] }], output: null, + options: ['always', { exceptions: ['+'] }], errors: [ 'Expected space after exception block.', 'Expected space before exception block.' @@ -300,8 +294,8 @@ tester.run('html-comment-content-spacing', rule, { `, - options: ['always', { exceptions: ['*'] }], output: null, + options: ['always', { exceptions: ['*'] }], errors: [ 'Expected space after exception block.', 'Expected space before exception block.' @@ -313,12 +307,12 @@ tester.run('html-comment-content-spacing', rule, { `, - options: ['always', { exceptions: ['#+#-'] }], output: ` `, + options: ['always', { exceptions: ['#+#-'] }], errors: [ 'Expected space after exception block.', "Expected space before '-->'." @@ -330,8 +324,8 @@ tester.run('html-comment-content-spacing', rule, { `, - options: ['always', { exceptions: ['*', '++'] }], output: null, + options: ['always', { exceptions: ['*', '++'] }], errors: [ 'Expected space after exception block.', { @@ -347,8 +341,8 @@ tester.run('html-comment-content-spacing', rule, { `, - options: ['always', { exceptions: ['*', '++'] }], output: null, + options: ['always', { exceptions: ['*', '++'] }], errors: [ 'Expected space after exception block.', { diff --git a/tests/lib/rules/html-comment-indent.js b/tests/lib/rules/html-comment-indent.js index 4ec5c6ee2..12880167e 100644 --- a/tests/lib/rules/html-comment-indent.js +++ b/tests/lib/rules/html-comment-indent.js @@ -16,23 +16,21 @@ const tester = new RuleTester({ }) tester.run('html-comment-indent', rule, { valid: [ - { - code: ` - + `, { code: ` + `, // IE conditional comments - { - code: ` - - ` - }, - { - code: ` - - ` - } + ` + + `, + ` + + ` ], invalid: [ @@ -232,7 +224,6 @@ tester.run('html-comment-indent', rule, { --> `, - options: ['tab'], output: ` `, + options: ['tab'], errors: [ { message: 'Expected relative indentation of 1 tab but found 0 tabs.', @@ -318,7 +310,6 @@ tester.run('html-comment-indent', rule, { --> `, - options: [4], output: ` `, + options: [4], errors: [ { message: @@ -407,7 +399,6 @@ tester.run('html-comment-indent', rule, { --> `, - options: [0], output: ` `, + options: [0], errors: [ { message: diff --git a/tests/lib/rules/html-end-tags.js b/tests/lib/rules/html-end-tags.js index b60c9848a..0d795875d 100644 --- a/tests/lib/rules/html-end-tags.js +++ b/tests/lib/rules/html-end-tags.js @@ -62,6 +62,7 @@ tester.run('html-end-tags', rule, { // https://github.com/vuejs/eslint-plugin-vue/issues/1403 { + filename: 'test.vue', code: ` - `, - filename: 'test.vue' + ` } ], invalid: [ diff --git a/tests/lib/rules/html-self-closing.js b/tests/lib/rules/html-self-closing.js index 5589c3da1..11ae3c6cf 100644 --- a/tests/lib/rules/html-self-closing.js +++ b/tests/lib/rules/html-self-closing.js @@ -69,6 +69,7 @@ tester.run('html-self-closing', rule, { // https://github.com/vuejs/eslint-plugin-vue/issues/1403 { + filename: 'test.vue', code: ` - `, - filename: 'test.vue' + ` } // other cases are in `invalid` tests. diff --git a/tests/lib/rules/jsx-uses-vars.js b/tests/lib/rules/jsx-uses-vars.js index 895093da7..3a2c7e82b 100644 --- a/tests/lib/rules/jsx-uses-vars.js +++ b/tests/lib/rules/jsx-uses-vars.js @@ -27,8 +27,7 @@ linter.defineRule('jsx-uses-vars', rule) describe('jsx-uses-vars', () => { ruleTester.run('no-unused-vars', ruleNoUnusedVars, { valid: [ - { - code: ` + ` /* eslint jsx-uses-vars: 1 */ import SomeComponent from './SomeComponent.jsx'; export default { @@ -38,10 +37,8 @@ describe('jsx-uses-vars', () => { ) }, }; + `, ` - }, - { - code: ` /* eslint jsx-uses-vars: 1 */ import SomeComponent from './SomeComponent.vue'; import OtherComponent from './OtherComponent.vue'; @@ -63,10 +60,8 @@ describe('jsx-uses-vars', () => { ) } } + `, ` - }, - { - code: ` /* eslint jsx-uses-vars: 1 */ export default { render () { @@ -76,7 +71,6 @@ describe('jsx-uses-vars', () => { } } ` - } ], invalid: [ diff --git a/tests/lib/rules/key-spacing.js b/tests/lib/rules/key-spacing.js index 519230e23..3d8d48a22 100644 --- a/tests/lib/rules/key-spacing.js +++ b/tests/lib/rules/key-spacing.js @@ -31,8 +31,8 @@ tester.run('key-spacing', rule, { }, { code: '', - options: [{ beforeColon: true }], output: '', + options: [{ beforeColon: true }], errors: [ "Missing space after key 'a'.", "Missing space before value for key 'a'." diff --git a/tests/lib/rules/keyword-spacing.js b/tests/lib/rules/keyword-spacing.js index dad5574e5..dadd553b7 100644 --- a/tests/lib/rules/keyword-spacing.js +++ b/tests/lib/rules/keyword-spacing.js @@ -101,7 +101,6 @@ tester.run('keyword-spacing', rule, { } " /> `, - options: [{ before: false, after: false }], output: ``, + options: [{ before: false, after: false }], errors: [ { message: 'Unexpected space(s) after "if".', diff --git a/tests/lib/rules/max-attributes-per-line.js b/tests/lib/rules/max-attributes-per-line.js index 252bd22c1..fdee711e7 100644 --- a/tests/lib/rules/max-attributes-per-line.js +++ b/tests/lib/rules/max-attributes-per-line.js @@ -14,23 +14,17 @@ const ruleTester = new RuleTester({ ruleTester.run('max-attributes-per-line', rule, { valid: [ - { - code: `` - }, - { - code: ``, + `` - }, - { - code: ``, + `` - }, + `, { code: ``, }, { code: ``, - options: [{ singleline: { max: 2 } }], output: ``, + options: [{ singleline: { max: 2 } }], errors: [ { message: "'job' should be on a new line.", @@ -110,13 +102,13 @@ job="Vet">`, job="Vet"> `, - options: [{ singleline: 3, multiline: 1 }], output: ``, + options: [{ singleline: 3, multiline: 1 }], errors: [ { message: "'age' should be on a new line.", @@ -131,13 +123,13 @@ age="30" job="Vet"> `, - options: [{ multiline: { max: 1 } }], output: ``, + options: [{ multiline: { max: 1 } }], errors: [ { message: "'age' should be on a new line.", diff --git a/tests/lib/rules/max-len.js b/tests/lib/rules/max-len.js index 3ff9f2dff..a1141ec22 100644 --- a/tests/lib/rules/max-len.js +++ b/tests/lib/rules/max-len.js @@ -1075,33 +1075,33 @@ var a = /regexploooooooooooooooooooooooooooooooooooooooooooooooooooooong/.test(b { filename: 'test.vue', code: ``, - errors: ['This line has a length of 41. Maximum allowed is 40.'], - options: [40] + options: [40], + errors: ['This line has a length of 41. Maximum allowed is 40.'] }, { filename: 'test.vue', code: ``, - errors: ['This line has a length of 41. Maximum allowed is 40.'], - options: [{ code: 40 }] + options: [{ code: 40 }], + errors: ['This line has a length of 41. Maximum allowed is 40.'] }, // tabWidth { filename: 'test.vue', code: ``, - errors: ['This line has a length of 45. Maximum allowed is 40.'], - options: [40, 4] + options: [40, 4], + errors: ['This line has a length of 45. Maximum allowed is 40.'] }, { filename: 'test.vue', code: ``, - errors: ['This line has a length of 45. Maximum allowed is 40.'], - options: [{ code: 40, tabWidth: 4 }] + options: [{ code: 40, tabWidth: 4 }], + errors: ['This line has a length of 45. Maximum allowed is 40.'] }, { filename: 'test.vue', code: ``, - errors: ['This line has a length of 44. Maximum allowed is 40.'], - options: [{ code: 40, tabWidth: 3 }] + options: [{ code: 40, tabWidth: 3 }], + errors: ['This line has a length of 44. Maximum allowed is 40.'] }, // comments { @@ -1122,6 +1122,7 @@ var a; // 41 cols comment * */ `, + options: [{ comments: 40 }], errors: [ { message: @@ -1148,8 +1149,7 @@ var a; // 41 cols comment * 'This line has a comment length of 41. Maximum allowed is 40.', line: 13 } - ], - options: [{ comments: 40 }] + ] }, // .js { @@ -1159,6 +1159,7 @@ var a = '81 columns ' var b = \`81 columns \`; /* 81 columns */ `, + options: [], errors: [ { message: 'This line has a length of 81. Maximum allowed is 80.', @@ -1172,8 +1173,7 @@ var b = \`81 columns message: 'This line has a length of 81. Maximum allowed is 80.', line: 4 } - ], - options: [] + ] }, { filename: 'test.js', @@ -1182,6 +1182,7 @@ var a = '81 columns ignoreStrings ' var b = \`81 columns \`; /* 81 columns */ `, + options: [{ ignoreStrings: true }], errors: [ { message: 'This line has a length of 81. Maximum allowed is 80.', @@ -1191,8 +1192,7 @@ var b = \`81 columns message: 'This line has a length of 81. Maximum allowed is 80.', line: 4 } - ], - options: [{ ignoreStrings: true }] + ] }, { filename: 'test.js', @@ -1201,6 +1201,7 @@ var a = '81 columns ' var b = \`81 columns \`; /* 81 columns */ `, + options: [{ ignoreComments: true }], errors: [ { message: 'This line has a length of 81. Maximum allowed is 80.', @@ -1210,8 +1211,7 @@ var b = \`81 columns message: 'This line has a length of 81. Maximum allowed is 80.', line: 3 } - ], - options: [{ ignoreComments: true }] + ] }, // only script comment { @@ -1222,6 +1222,7 @@ var b = \`81 columns 41 cols * */ `, + options: [{ comments: 40 }], errors: [ { message: @@ -1238,8 +1239,7 @@ var b = \`81 columns 'This line has a comment length of 41. Maximum allowed is 40.', line: 4 } - ], - options: [{ comments: 40 }] + ] } ] }) diff --git a/tests/lib/rules/multi-word-component-names.js b/tests/lib/rules/multi-word-component-names.js index 96302eec8..3d68364bc 100644 --- a/tests/lib/rules/multi-word-component-names.js +++ b/tests/lib/rules/multi-word-component-names.js @@ -165,14 +165,14 @@ tester.run('multi-word-component-names', rule, { }, { filename: 'test.vue', - options: [{ ignores: ['Todo'] }], code: ` - ` + `, + options: [{ ignores: ['Todo'] }] }, { filename: 'test.js', @@ -314,7 +314,6 @@ tester.run('multi-word-component-names', rule, { }, { filename: 'test.vue', - options: [{ ignores: ['Todo'] }], code: ` `, + options: [{ ignores: ['Todo'] }], errors: [ { message: 'Component name "Item" should always be multi-word.', diff --git a/tests/lib/rules/multiline-html-element-content-newline.js b/tests/lib/rules/multiline-html-element-content-newline.js index d06982955..2d68c7685 100644 --- a/tests/lib/rules/multiline-html-element-content-newline.js +++ b/tests/lib/rules/multiline-html-element-content-newline.js @@ -566,7 +566,6 @@ content
`, - options: [{ allowEmptyLines: true, ignoreWhenEmpty: false }], output: ` `, + options: [{ allowEmptyLines: true, ignoreWhenEmpty: false }], errors: [ 'Expected 1 line break after opening tag (`
`), but no line breaks found.' ] @@ -594,7 +594,6 @@ content content
`, - options: [{ allowEmptyLines: true }], output: ` `, + options: [{ allowEmptyLines: true }], errors: [ 'Expected 1 line break after opening tag (`
`), but no line breaks found.', 'Expected 1 line break before closing tag (`
`), but no line breaks found.' diff --git a/tests/lib/rules/multiline-ternary.js b/tests/lib/rules/multiline-ternary.js index 2922f0e65..d79e82eff 100644 --- a/tests/lib/rules/multiline-ternary.js +++ b/tests/lib/rules/multiline-ternary.js @@ -92,6 +92,7 @@ tester.run('multiline-ternary', rule, { ` : null, + options: ['always-multiline'], errors: [ { message: @@ -99,8 +100,7 @@ tester.run('multiline-ternary', rule, { line: 5, column: 15 } - ], - options: ['always-multiline'] + ] }, { filename: 'test.vue', @@ -123,6 +123,7 @@ tester.run('multiline-ternary', rule, { ` : null, + options: ['never'], errors: [ { message: @@ -130,8 +131,7 @@ tester.run('multiline-ternary', rule, { line: 4, column: 21 } - ], - options: ['never'] + ] }, { filename: 'test.vue', diff --git a/tests/lib/rules/new-line-between-multi-line-property.js b/tests/lib/rules/new-line-between-multi-line-property.js index a302cca7e..31983d7b0 100644 --- a/tests/lib/rules/new-line-between-multi-line-property.js +++ b/tests/lib/rules/new-line-between-multi-line-property.js @@ -280,7 +280,6 @@ ruleTester.run('new-line-between-multi-line-property', rule, { // test set insertLine and minLineOfMultilineProperty to 5 { filename: 'test.vue', - options: [{ minLineOfMultilineProperty: 5 }], code: ` `, + options: [{ minLineOfMultilineProperty: 5 }], errors: [ { message: @@ -331,7 +331,6 @@ ruleTester.run('new-line-between-multi-line-property', rule, { // test js comments { filename: 'test.vue', - options: [{ minLineOfMultilineProperty: 5 }], code: ` `, + options: [{ minLineOfMultilineProperty: 5 }], errors: [ { message: @@ -384,7 +384,6 @@ ruleTester.run('new-line-between-multi-line-property', rule, { // test js doc { filename: 'test.vue', - options: [], code: ` `, + options: [], errors: [ { message: diff --git a/tests/lib/rules/next-tick-style.js b/tests/lib/rules/next-tick-style.js index 24ef50a8e..28e2d338c 100644 --- a/tests/lib/rules/next-tick-style.js +++ b/tests/lib/rules/next-tick-style.js @@ -40,7 +40,6 @@ tester.run('next-tick-style', rule, { }, { filename: 'test.vue', - options: ['promise'], code: `` + }`, + options: ['promise'] }, { filename: 'test.vue', - options: ['callback'], code: `` + }`, + options: ['callback'] }, // https://github.com/vuejs/eslint-plugin-vue/pull/1400#discussion_r550937977 { filename: 'test.vue', - options: ['promise'], code: `` + }`, + options: ['promise'] }, { filename: 'test.vue', - options: ['callback'], code: `` + }`, + options: ['callback'] } ], invalid: [ @@ -173,7 +173,6 @@ tester.run('next-tick-style', rule, { }, { filename: 'test.vue', - options: ['promise'], code: ``, + options: ['promise'], errors: [ { message: @@ -239,7 +239,6 @@ tester.run('next-tick-style', rule, { }, { filename: 'test.vue', - options: ['callback'], code: ``, output: null, + options: ['callback'], errors: [ { message: diff --git a/tests/lib/rules/no-async-in-computed-properties.js b/tests/lib/rules/no-async-in-computed-properties.js index 31950ec5d..2e150b021 100644 --- a/tests/lib/rules/no-async-in-computed-properties.js +++ b/tests/lib/rules/no-async-in-computed-properties.js @@ -303,11 +303,6 @@ ruleTester.run('no-async-in-computed-properties', rule, { { // https://github.com/vuejs/eslint-plugin-vue/issues/1690 filename: 'test.vue', - parser, - parserOptions: { - sourceType: 'module', - ecmaVersion: 2020 - }, code: ` `, - output: ` - `, + output: null, errors: [ '`slot` attributes are deprecated.', '`slot` attributes are deprecated.' diff --git a/tests/lib/rules/no-deprecated-v-bind-sync.js b/tests/lib/rules/no-deprecated-v-bind-sync.js index 626993731..c02342a86 100644 --- a/tests/lib/rules/no-deprecated-v-bind-sync.js +++ b/tests/lib/rules/no-deprecated-v-bind-sync.js @@ -68,7 +68,7 @@ ruleTester.run('no-deprecated-v-bind-sync', rule, { { filename: 'test.vue', code: "", - output: "", + output: null, errors: [ "'.sync' modifier on 'v-bind' directive is deprecated. Use 'v-model:propName' instead." ] @@ -76,7 +76,7 @@ ruleTester.run('no-deprecated-v-bind-sync', rule, { { filename: 'test.vue', code: '', - output: '', + output: null, errors: [ "'.sync' modifier on 'v-bind' directive is deprecated. Use 'v-model:propName' instead." ] @@ -84,8 +84,7 @@ ruleTester.run('no-deprecated-v-bind-sync', rule, { { filename: 'test.vue', code: '', - output: - '', + output: null, errors: [ "'.sync' modifier on 'v-bind' directive is deprecated. Use 'v-model:propName' instead." ] diff --git a/tests/lib/rules/no-duplicate-attributes.js b/tests/lib/rules/no-duplicate-attributes.js index 25f6fe5dc..b47611184 100644 --- a/tests/lib/rules/no-duplicate-attributes.js +++ b/tests/lib/rules/no-duplicate-attributes.js @@ -73,26 +73,26 @@ tester.run('no-duplicate-attributes', rule, { { filename: 'test.vue', code: '', - errors: ["Duplicate attribute 'style'."], - options: [{ allowCoexistStyle: false }] + options: [{ allowCoexistStyle: false }], + errors: ["Duplicate attribute 'style'."] }, { filename: 'test.vue', code: '', - errors: ["Duplicate attribute 'class'."], - options: [{ allowCoexistClass: false }] + options: [{ allowCoexistClass: false }], + errors: ["Duplicate attribute 'class'."] }, { filename: 'test.vue', code: '', - errors: ["Duplicate attribute 'style'."], - options: [{ allowCoexistStyle: false }] + options: [{ allowCoexistStyle: false }], + errors: ["Duplicate attribute 'style'."] }, { filename: 'test.vue', code: '', - errors: ["Duplicate attribute 'class'."], - options: [{ allowCoexistClass: false }] + options: [{ allowCoexistClass: false }], + errors: ["Duplicate attribute 'class'."] } ] }) diff --git a/tests/lib/rules/no-multiple-template-root.js b/tests/lib/rules/no-multiple-template-root.js index 167dc6385..e57afd188 100644 --- a/tests/lib/rules/no-multiple-template-root.js +++ b/tests/lib/rules/no-multiple-template-root.js @@ -49,6 +49,7 @@ ruleTester.run('no-multiple-template-root', rule, { // https://github.com/vuejs/eslint-plugin-vue/issues/1439 { + filename: 'test.vue', code: ` - `, - filename: 'test.vue' + ` } ], invalid: [ diff --git a/tests/lib/rules/no-parsing-error.js b/tests/lib/rules/no-parsing-error.js index 7eb295c4b..54500f18c 100644 --- a/tests/lib/rules/no-parsing-error.js +++ b/tests/lib/rules/no-parsing-error.js @@ -206,6 +206,7 @@ tester.run('no-parsing-error', rule, { // https://github.com/vuejs/eslint-plugin-vue/issues/1403 { + filename: 'test.vue', code: ` - `, - filename: 'test.vue' + ` } ], invalid: [ diff --git a/tests/lib/rules/no-potential-component-option-typo.js b/tests/lib/rules/no-potential-component-option-typo.js index 2b85fc999..68ea21901 100644 --- a/tests/lib/rules/no-potential-component-option-typo.js +++ b/tests/lib/rules/no-potential-component-option-typo.js @@ -174,6 +174,7 @@ tester.run('no-potential-component-option-typo', rule, { method: {} } `, + options: [{ custom: ['data', 'methods'] }], errors: [ { message: "'dat' may be a typo, which is similar to option [data].", @@ -209,8 +210,7 @@ tester.run('no-potential-component-option-typo', rule, { } ] } - ], - options: [{ custom: ['data', 'methods'] }] + ] }, // test if user define custom rule is duplicate with presets // test custom option that is not available in the presets @@ -224,6 +224,9 @@ tester.run('no-potential-component-option-typo', rule, { custo: {} } `, + options: [ + { custom: ['data', 'methods', 'custom', 'foo'], presets: ['all'] } + ], errors: [ { message: "'dat' may be a typo, which is similar to option [data].", @@ -279,9 +282,6 @@ tester.run('no-potential-component-option-typo', rule, { } ] } - ], - options: [ - { custom: ['data', 'methods', 'custom', 'foo'], presets: ['all'] } ] }, // test if report correctly, only have preset option @@ -294,6 +294,7 @@ tester.run('no-potential-component-option-typo', rule, { method: {} } `, + options: [{ presets: ['vue'] }], errors: [ { message: "'dat' may be a typo, which is similar to option [data].", @@ -329,8 +330,7 @@ tester.run('no-potential-component-option-typo', rule, { } ] } - ], - options: [{ presets: ['vue'] }] + ] }, // multi preset report typo { @@ -343,6 +343,7 @@ tester.run('no-potential-component-option-typo', rule, { method: {} } `, + options: [{ presets: ['vue', 'vue-router'] }], errors: [ { message: "'dat' may be a typo, which is similar to option [data].", @@ -399,8 +400,7 @@ tester.run('no-potential-component-option-typo', rule, { } ] } - ], - options: [{ presets: ['vue', 'vue-router'] }] + ] }, // test multi suggestion { @@ -411,6 +411,7 @@ tester.run('no-potential-component-option-typo', rule, { method: {} } `, + options: [{ custom: ['data', 'methods'], threshold: 10, presets: [] }], errors: [ { message: `'method' may be a typo, which is similar to option [methods,data].`, @@ -437,8 +438,7 @@ tester.run('no-potential-component-option-typo', rule, { } ] } - ], - options: [{ custom: ['data', 'methods'], threshold: 10, presets: [] }] + ] } ] }) diff --git a/tests/lib/rules/no-ref-as-operand.js b/tests/lib/rules/no-ref-as-operand.js index 1cdbb1041..a932ff1c2 100644 --- a/tests/lib/rules/no-ref-as-operand.js +++ b/tests/lib/rules/no-ref-as-operand.js @@ -131,26 +131,21 @@ tester.run('no-ref-as-operand', rule, { const count = ref(0) const foo = count `, - { - code: ` + ` - ` - }, - { - code: ` + `, + ` - ` - }, - { - code: ` + `, + ` - ` - }, - { - code: ` + `, + ` - ` - } + ` ], invalid: [ { diff --git a/tests/lib/rules/no-required-prop-with-default.js b/tests/lib/rules/no-required-prop-with-default.js index 236de8cd4..ec1e749cc 100644 --- a/tests/lib/rules/no-required-prop-with-default.js +++ b/tests/lib/rules/no-required-prop-with-default.js @@ -196,7 +196,6 @@ tester.run('no-required-prop-with-default', rule, { ); `, - options: [{ autofix: true }], output: ` `, + options: [{ autofix: true }], parserOptions: { parser: require.resolve('@typescript-eslint/parser') }, @@ -237,7 +237,6 @@ tester.run('no-required-prop-with-default', rule, { ); `, - options: [{ autofix: true }], output: ` `, + options: [{ autofix: true }], parserOptions: { parser: require.resolve('@typescript-eslint/parser') }, @@ -647,7 +647,6 @@ tester.run('no-required-prop-with-default', rule, { ); `, - options: [{ autofix: true }], output: ` `, + options: [{ autofix: true }], parserOptions: { parser: require.resolve('@typescript-eslint/parser') }, @@ -868,19 +868,7 @@ tester.run('no-required-prop-with-default', rule, { }) `, - output: ` - - `, + output: null, errors: [ { message: 'Prop "name" should be optional.', diff --git a/tests/lib/rules/no-restricted-call-after-await.js b/tests/lib/rules/no-restricted-call-after-await.js index 69eaf3a42..5409f7f29 100644 --- a/tests/lib/rules/no-restricted-call-after-await.js +++ b/tests/lib/rules/no-restricted-call-after-await.js @@ -147,8 +147,8 @@ tester.run('no-restricted-call-after-await', rule, { useI18n() `, - parserOptions: { ecmaVersion: 2022 }, - options: [{ module: 'vue-i18n', path: 'useI18n' }] + options: [{ module: 'vue-i18n', path: 'useI18n' }], + parserOptions: { ecmaVersion: 2022 } } ], invalid: [ diff --git a/tests/lib/rules/no-restricted-class.js b/tests/lib/rules/no-restricted-class.js index 02815b2c6..2d53598c8 100644 --- a/tests/lib/rules/no-restricted-class.js +++ b/tests/lib/rules/no-restricted-class.js @@ -14,7 +14,7 @@ const ruleTester = new RuleTester({ ruleTester.run('no-restricted-class', rule, { valid: [ - { code: `` }, + ``, { code: ``, options: ['forbidden'] @@ -40,93 +40,93 @@ ruleTester.run('no-restricted-class', rule, { invalid: [ { code: ``, + options: ['forbidden'], errors: [ { message: "'forbidden' class is not allowed.", type: 'VAttribute' } - ], - options: ['forbidden'] + ] }, { code: ``, + options: ['forbidden'], errors: [ { message: "'forbidden' class is not allowed.", type: 'Literal' } - ], - options: ['forbidden'] + ] }, { code: ``, + options: ['forbidden'], errors: [ { message: "'forbidden' class is not allowed.", type: 'Literal' } - ], - options: ['forbidden'] + ] }, { code: ``, + options: ['forbidden'], errors: [ { message: "'forbidden' class is not allowed.", type: 'Identifier' } - ], - options: ['forbidden'] + ] }, { code: '', + options: ['forbidden'], errors: [ { message: "'forbidden' class is not allowed.", type: 'TemplateElement' } - ], - options: ['forbidden'] + ] }, { code: ``, + options: ['forbidden'], errors: [ { message: "'forbidden' class is not allowed.", type: 'Literal' } - ], - options: ['forbidden'] + ] }, { code: ``, + options: ['forbidden'], errors: [ { message: "'forbidden' class is not allowed.", type: 'Literal' } - ], - options: ['forbidden'] + ] }, { code: ``, + options: ['forbidden'], errors: [ { message: "'forbidden' class is not allowed.", type: 'Literal' } - ], - options: ['forbidden'] + ] }, { code: ``, + options: ['/^for(bidden|gotten)/'], errors: [ { message: "'forbidden' class is not allowed.", type: 'VAttribute' } - ], - options: ['/^for(bidden|gotten)/'] + ] } ] }) diff --git a/tests/lib/rules/no-restricted-html-elements.js b/tests/lib/rules/no-restricted-html-elements.js index 775d94580..3dee64643 100644 --- a/tests/lib/rules/no-restricted-html-elements.js +++ b/tests/lib/rules/no-restricted-html-elements.js @@ -38,38 +38,38 @@ tester.run('no-restricted-html-elements', rule, { { filename: 'test.vue', code: '', + options: ['button'], errors: [ { message: 'Unexpected use of forbidden HTML element button.', line: 1, column: 16 } - ], - options: ['button'] + ] }, { filename: 'test.vue', code: '', + options: ['div'], errors: [ { message: 'Unexpected use of forbidden HTML element div.', line: 1, column: 11 } - ], - options: ['div'] + ] }, { filename: 'test.vue', code: '', + options: [{ element: 'marquee', message: 'Custom error' }], errors: [ { message: 'Custom error', line: 1, column: 11 } - ], - options: [{ element: 'marquee', message: 'Custom error' }] + ] } ] }) diff --git a/tests/lib/rules/no-restricted-props.js b/tests/lib/rules/no-restricted-props.js index 0f1947ed1..934a255b0 100644 --- a/tests/lib/rules/no-restricted-props.js +++ b/tests/lib/rules/no-restricted-props.js @@ -386,10 +386,10 @@ tester.run('no-restricted-props', rule, { }>() `, + options: [{ name: 'foo', suggest: 'Foo' }], parserOptions: { parser: require.resolve('@typescript-eslint/parser') }, - options: [{ name: 'foo', suggest: 'Foo' }], errors: [ { message: 'Using `foo` props is not allowed.', diff --git a/tests/lib/rules/no-setup-props-destructure.js b/tests/lib/rules/no-setup-props-destructure.js index d990f8857..5e84a565e 100644 --- a/tests/lib/rules/no-setup-props-destructure.js +++ b/tests/lib/rules/no-setup-props-destructure.js @@ -160,12 +160,11 @@ tester.run('no-setup-props-destructure', rule, { ` }, - { - code: ` + ` Vue.component('test', { el: a = b - })` - }, + }) + `, { filename: 'test.vue', code: ` diff --git a/tests/lib/rules/no-side-effects-in-computed-properties.js b/tests/lib/rules/no-side-effects-in-computed-properties.js index cec6747f3..a72004060 100644 --- a/tests/lib/rules/no-side-effects-in-computed-properties.js +++ b/tests/lib/rules/no-side-effects-in-computed-properties.js @@ -19,8 +19,8 @@ const ruleTester = new RuleTester({ ruleTester.run('no-side-effects-in-computed-properties', rule, { valid: [ - { - code: `Vue.component('test', { + ` + Vue.component('test', { ...foo, computed: { ...test0({}), @@ -97,10 +97,10 @@ ruleTester.run('no-side-effects-in-computed-properties', rule, { this.someArray.forEach(arr => console.log(arr)) } } - })` - }, - { - code: `Vue.component('test', { + }) + `, + ` + Vue.component('test', { computed: { ...mapGetters(['example']), test1() { @@ -115,18 +115,18 @@ ruleTester.run('no-side-effects-in-computed-properties', rule, { return something.b } } - })` - }, - { - code: `Vue.component('test', { + }) + `, + ` + Vue.component('test', { name: 'something', data() { return {} } - })` - }, - { - code: `Vue.component('test', { + }) + `, + ` + Vue.component('test', { computed: { test () { let a; @@ -134,10 +134,10 @@ ruleTester.run('no-side-effects-in-computed-properties', rule, { return a }, } - })` - }, - { - code: `Vue.component('test', { + }) + `, + ` + Vue.component('test', { computed: { test () { return { @@ -153,32 +153,32 @@ ruleTester.run('no-side-effects-in-computed-properties', rule, { } }, } - })` - }, - { - code: `Vue.component('test', { + }) + `, + ` + Vue.component('test', { computed: { test () { return this.something['a']().reverse() }, } - })` - }, - { - code: `const test = { el: '#app' } + }) + `, + ` + const test = { el: '#app' } Vue.component('test', { el: test.el - })` - }, - { - code: `Vue.component('test', { + }) + `, + ` + Vue.component('test', { computed: { test () { return [...this.items].reverse() }, } - })` - }, + }) + `, { filename: 'test.vue', code: ` @@ -392,13 +392,13 @@ ruleTester.run('no-side-effects-in-computed-properties', rule, { } }); `, + parser: require.resolve('@typescript-eslint/parser'), errors: [ { line: 5, message: 'Unexpected side effect in "test1" computed property.' } - ], - parser: require.resolve('@typescript-eslint/parser') + ] }, { diff --git a/tests/lib/rules/no-template-target-blank.js b/tests/lib/rules/no-template-target-blank.js index 5445ae6d7..b9896d7ed 100644 --- a/tests/lib/rules/no-template-target-blank.js +++ b/tests/lib/rules/no-template-target-blank.js @@ -15,31 +15,21 @@ const ruleTester = new RuleTester({ ruleTester.run('no-template-target-blank', rule, { valid: [ - { code: '' }, - { code: '' }, - { code: '' }, - { - code: '' - }, - { code: '' }, - { - code: '' - }, - { - code: '' - }, + '', + '', + '', + '', + '', + '', + '', { code: '', options: [{ allowReferrer: true }] }, - { code: '' }, - { - code: '' - }, - { code: '' }, - { - code: '' - }, + '', + '', + '', + '', { code: '', options: [{ enforceDynamicLinks: 'never' }] diff --git a/tests/lib/rules/no-this-in-before-route-enter.js b/tests/lib/rules/no-this-in-before-route-enter.js index 1171959ae..f3861672e 100644 --- a/tests/lib/rules/no-this-in-before-route-enter.js +++ b/tests/lib/rules/no-this-in-before-route-enter.js @@ -83,8 +83,8 @@ export default { ], invalid: [ { - code: template(`this.xxx();`), filename: 'ValidComponent.vue', + code: template(`this.xxx();`), errors: [ { message: @@ -97,8 +97,8 @@ export default { ] }, { - code: functionTemplate('this.method();'), filename: 'ValidComponent.vue', + code: functionTemplate('this.method();'), errors: [ { message: @@ -111,8 +111,8 @@ export default { ] }, { - code: template('this.attr = this.method();'), filename: 'ValidComponent.vue', + code: template('this.attr = this.method();'), errors: [ { message: @@ -133,8 +133,8 @@ export default { ] }, { - code: functionTemplate('this.attr = this.method();'), filename: 'ValidComponent.vue', + code: functionTemplate('this.attr = this.method();'), errors: [ { message: @@ -155,10 +155,10 @@ export default { ] }, { + filename: 'ValidComponent.vue', code: template(` if (this.method()) {} `), - filename: 'ValidComponent.vue', errors: [ { message: @@ -171,10 +171,10 @@ export default { ] }, { + filename: 'ValidComponent.vue', code: functionTemplate(` if (true) { this.method(); } `), - filename: 'ValidComponent.vue', errors: [ { message: diff --git a/tests/lib/rules/no-undef-components.js b/tests/lib/rules/no-undef-components.js index f90cb56df..0941f003d 100644 --- a/tests/lib/rules/no-undef-components.js +++ b/tests/lib/rules/no-undef-components.js @@ -656,12 +656,12 @@ tester.run('no-undef-components', rule, { `, + parser: require.resolve('vue-eslint-parser'), parserOptions: { ecmaVersion: 6, sourceType: 'module', parser: require.resolve('@typescript-eslint/parser') - }, - parser: require.resolve('vue-eslint-parser') + } } ], invalid: [ @@ -803,12 +803,12 @@ tester.run('no-undef-components', rule, { `, + parser: require.resolve('vue-eslint-parser'), parserOptions: { ecmaVersion: 6, sourceType: 'module', parser: require.resolve('@typescript-eslint/parser') }, - parser: require.resolve('vue-eslint-parser'), errors: [ { message: diff --git a/tests/lib/rules/no-undef-properties.js b/tests/lib/rules/no-undef-properties.js index 9a97fe1a9..7ba344197 100644 --- a/tests/lib/rules/no-undef-properties.js +++ b/tests/lib/rules/no-undef-properties.js @@ -1169,13 +1169,13 @@ tester.run('no-undef-properties', rule, {
{{ foo }}
{{ unknown }}
`, - ...getTypeScriptFixtureTestOptions(), errors: [ { message: "'unknown' is not defined.", line: 11 } - ] + ], + ...getTypeScriptFixtureTestOptions() } ] }) diff --git a/tests/lib/rules/no-unsupported-features.js b/tests/lib/rules/no-unsupported-features.js index d12109311..77ee72055 100644 --- a/tests/lib/rules/no-unsupported-features.js +++ b/tests/lib/rules/no-unsupported-features.js @@ -45,7 +45,6 @@ tester.run('no-unsupported-features', rule, { `, - options: [{ version: '^2.5.0' }], output: ` `, + options: [{ version: '^2.5.0' }], errors: [ { message: '`v-slot` are not supported until Vue.js "2.6.0".', diff --git a/tests/lib/rules/no-unsupported-features/define-options.js b/tests/lib/rules/no-unsupported-features/define-options.js index 10b2069b2..a53bd776c 100644 --- a/tests/lib/rules/no-unsupported-features/define-options.js +++ b/tests/lib/rules/no-unsupported-features/define-options.js @@ -47,7 +47,6 @@ tester.run('no-unsupported-features/define-options', rule, { `, - options: buildOptions(), output: ` `, + options: buildOptions(), errors: [ { message: @@ -68,7 +68,6 @@ export default { name: 'Foo' } `, - options: buildOptions(), output: ` `, + options: buildOptions(), errors: [ { message: diff --git a/tests/lib/rules/no-unsupported-features/slot-scope-attribute.js b/tests/lib/rules/no-unsupported-features/slot-scope-attribute.js index 5307aa616..8f8b0b136 100644 --- a/tests/lib/rules/no-unsupported-features/slot-scope-attribute.js +++ b/tests/lib/rules/no-unsupported-features/slot-scope-attribute.js @@ -66,8 +66,8 @@ tester.run('no-unsupported-features/slot-scope-attribute', rule, { `, - options: buildOptions(), output: null, + options: buildOptions(), errors: [ { message: @@ -83,8 +83,8 @@ tester.run('no-unsupported-features/slot-scope-attribute', rule, { `, - options: buildOptions(), output: null, + options: buildOptions(), errors: [ { message: @@ -100,8 +100,8 @@ tester.run('no-unsupported-features/slot-scope-attribute', rule, { `, - options: buildOptions({ version: '^3.0.0' }), output: null, + options: buildOptions({ version: '^3.0.0' }), errors: [ { message: diff --git a/tests/lib/rules/no-unsupported-features/v-bind-prop-modifier-shorthand.js b/tests/lib/rules/no-unsupported-features/v-bind-prop-modifier-shorthand.js index 1cefc8ff1..58ffda146 100644 --- a/tests/lib/rules/no-unsupported-features/v-bind-prop-modifier-shorthand.js +++ b/tests/lib/rules/no-unsupported-features/v-bind-prop-modifier-shorthand.js @@ -63,11 +63,11 @@ tester.run('no-unsupported-features/v-bind-prop-modifier-shorthand', rule, { `, - options: buildOptions(), output: ` `, + options: buildOptions(), errors: [ { message: '`.prop` shorthand are not supported until Vue.js "3.2.0".', @@ -80,11 +80,11 @@ tester.run('no-unsupported-features/v-bind-prop-modifier-shorthand', rule, { `, - options: buildOptions({ version: '2.5.99' }), output: ` `, + options: buildOptions({ version: '2.5.99' }), errors: [ { message: '`.prop` shorthand are not supported until Vue.js "3.2.0".', @@ -97,11 +97,11 @@ tester.run('no-unsupported-features/v-bind-prop-modifier-shorthand', rule, { `, - options: buildOptions({ version: '3.1.0' }), output: ` `, + options: buildOptions({ version: '3.1.0' }), errors: [ { message: '`.prop` shorthand are not supported until Vue.js "3.2.0".', diff --git a/tests/lib/rules/no-unsupported-features/v-slot.js b/tests/lib/rules/no-unsupported-features/v-slot.js index 66b3b0b9e..a382a7eda 100644 --- a/tests/lib/rules/no-unsupported-features/v-slot.js +++ b/tests/lib/rules/no-unsupported-features/v-slot.js @@ -81,13 +81,13 @@ tester.run('no-unsupported-features/v-slot', rule, { `, - options: buildOptions(), output: ` `, + options: buildOptions(), errors: [ { message: '`v-slot` are not supported until Vue.js "2.6.0".', @@ -102,13 +102,13 @@ tester.run('no-unsupported-features/v-slot', rule, { `, - options: buildOptions(), output: ` `, + options: buildOptions(), errors: [ { message: '`v-slot` are not supported until Vue.js "2.6.0".', @@ -123,13 +123,13 @@ tester.run('no-unsupported-features/v-slot', rule, { `, - options: buildOptions(), output: ` `, + options: buildOptions(), errors: [ { message: '`v-slot` are not supported until Vue.js "2.6.0".', @@ -144,13 +144,13 @@ tester.run('no-unsupported-features/v-slot', rule, { `, - options: buildOptions(), output: ` `, + options: buildOptions(), errors: [ { message: '`v-slot` are not supported until Vue.js "2.6.0".', @@ -165,13 +165,13 @@ tester.run('no-unsupported-features/v-slot', rule, { `, - options: buildOptions(), output: ` `, + options: buildOptions(), errors: [ { message: '`v-slot` are not supported until Vue.js "2.6.0".', @@ -186,13 +186,13 @@ tester.run('no-unsupported-features/v-slot', rule, { `, - options: buildOptions(), output: ` `, + options: buildOptions(), errors: [ { message: '`v-slot` are not supported until Vue.js "2.6.0".', @@ -207,13 +207,13 @@ tester.run('no-unsupported-features/v-slot', rule, { `, - options: buildOptions(), output: ` `, + options: buildOptions(), errors: [ { message: '`v-slot` are not supported until Vue.js "2.6.0".', @@ -228,13 +228,13 @@ tester.run('no-unsupported-features/v-slot', rule, { `, - options: buildOptions(), output: ` `, + options: buildOptions(), errors: [ { message: '`v-slot` are not supported until Vue.js "2.6.0".', @@ -249,13 +249,13 @@ tester.run('no-unsupported-features/v-slot', rule, { `, - options: buildOptions(), output: ` `, + options: buildOptions(), errors: [ { message: '`v-slot` are not supported until Vue.js "2.6.0".', @@ -271,13 +271,13 @@ tester.run('no-unsupported-features/v-slot', rule, { `, - options: buildOptions(), output: ` `, + options: buildOptions(), errors: [ { message: '`v-slot` are not supported until Vue.js "2.6.0".', @@ -292,8 +292,8 @@ tester.run('no-unsupported-features/v-slot', rule, { `, - options: buildOptions(), output: null, + options: buildOptions(), errors: [ { message: '`v-slot` are not supported until Vue.js "2.6.0".', @@ -310,8 +310,8 @@ tester.run('no-unsupported-features/v-slot', rule, { `, - options: buildOptions(), output: null, + options: buildOptions(), errors: [ { message: '`v-slot` are not supported until Vue.js "2.6.0".', @@ -328,8 +328,8 @@ tester.run('no-unsupported-features/v-slot', rule, { `, - options: buildOptions(), output: null, + options: buildOptions(), errors: [ { message: '`v-slot` are not supported until Vue.js "2.6.0".', diff --git a/tests/lib/rules/no-unused-properties.js b/tests/lib/rules/no-unused-properties.js index 2db132c48..0139559b1 100644 --- a/tests/lib/rules/no-unused-properties.js +++ b/tests/lib/rules/no-unused-properties.js @@ -1651,9 +1651,6 @@ tester.run('no-unused-properties', rule, { { // https://github.com/vuejs/eslint-plugin-vue/issues/1643 filename: 'test.vue', - parserOptions: { - parser: '@typescript-eslint/parser' - }, code: ` `, - options: [ - 'never', - { - objectsInObjects: true - } - ], output: ` `, + options: [ + 'never', + { + objectsInObjects: true + } + ], errors: [ "There should be no space after '{'.", "There should be no space after '{'.", @@ -145,13 +145,13 @@ tester.run('object-curly-spacing', rule, { Hello World `, - options: ['never'], output: ` `, + options: ['never'], errors: [ "There should be no space after '{'.", "There should be no space after '{'.", diff --git a/tests/lib/rules/order-in-components.js b/tests/lib/rules/order-in-components.js index b12c41a33..669383e52 100644 --- a/tests/lib/rules/order-in-components.js +++ b/tests/lib/rules/order-in-components.js @@ -197,7 +197,6 @@ ruleTester.run('order-in-components', rule, { }, } `, - parserOptions, output: ` export default { name: 'app', @@ -211,6 +210,7 @@ ruleTester.run('order-in-components', rule, { }, } `, + parserOptions, errors: [ { message: @@ -239,11 +239,6 @@ ruleTester.run('order-in-components', rule, { }, } `, - parserOptions: { - ecmaVersion: 6, - sourceType: 'module', - ecmaFeatures: { jsx: true } - }, output: ` export default { name: 'app', @@ -262,6 +257,11 @@ ruleTester.run('order-in-components', rule, { }, } `, + parserOptions: { + ecmaVersion: 6, + sourceType: 'module', + ecmaFeatures: { jsx: true } + }, errors: [ { message: @@ -294,7 +294,6 @@ ruleTester.run('order-in-components', rule, { template: '
' }) `, - parserOptions: { ecmaVersion: 6 }, output: ` Vue.component('smart-list', { name: 'app', @@ -307,6 +306,7 @@ ruleTester.run('order-in-components', rule, { template: '
' }) `, + parserOptions: { ecmaVersion: 6 }, errors: [ { message: @@ -329,7 +329,6 @@ ruleTester.run('order-in-components', rule, { template: '
' }) `, - parserOptions: { ecmaVersion: 6 }, output: ` app.component('smart-list', { name: 'app', @@ -342,6 +341,7 @@ ruleTester.run('order-in-components', rule, { template: '
' }) `, + parserOptions: { ecmaVersion: 6 }, errors: [ { message: @@ -365,7 +365,6 @@ ruleTester.run('order-in-components', rule, { template: '
' }) `, - parserOptions: { ecmaVersion: 6 }, output: ` const { component } = Vue; component('smart-list', { @@ -379,6 +378,7 @@ ruleTester.run('order-in-components', rule, { template: '
' }) `, + parserOptions: { ecmaVersion: 6 }, errors: [ { message: @@ -402,7 +402,6 @@ ruleTester.run('order-in-components', rule, { template: '
' }) `, - parserOptions: { ecmaVersion: 6 }, output: ` new Vue({ el: '#app', @@ -416,6 +415,7 @@ ruleTester.run('order-in-components', rule, { template: '
' }) `, + parserOptions: { ecmaVersion: 6 }, errors: [ { message: @@ -449,7 +449,6 @@ ruleTester.run('order-in-components', rule, { name: 'burger', }; `, - parserOptions, output: ` export default { name: 'burger', @@ -468,6 +467,7 @@ ruleTester.run('order-in-components', rule, { }, }; `, + parserOptions, errors: [ { message: @@ -486,7 +486,6 @@ ruleTester.run('order-in-components', rule, { test: 'ok' }; `, - parserOptions, output: ` export default { data() { @@ -496,6 +495,7 @@ ruleTester.run('order-in-components', rule, { }; `, options: [{ order: ['data', 'test', 'name'] }], + parserOptions, errors: [ { message: @@ -515,7 +515,6 @@ ruleTester.run('order-in-components', rule, { name: 'burger' }; `, - parserOptions, output: ` export default { /** name of vue component */ @@ -525,6 +524,7 @@ ruleTester.run('order-in-components', rule, { } }; `, + parserOptions, errors: [ { message: @@ -544,7 +544,6 @@ ruleTester.run('order-in-components', rule, { name: 'burger' }; `, - parserOptions, output: ` export default { /** name of vue component */ @@ -554,6 +553,7 @@ ruleTester.run('order-in-components', rule, { }/*test*/ }; `, + parserOptions, errors: [ { message: @@ -565,8 +565,8 @@ ruleTester.run('order-in-components', rule, { { filename: 'example.vue', code: `export default {data(){},name:'burger'};`, - parserOptions, output: `export default {name:'burger',data(){}};`, + parserOptions, errors: [ { message: @@ -586,8 +586,8 @@ ruleTester.run('order-in-components', rule, { name: 'burger', }; `, - parserOptions, output: null, + parserOptions, errors: [ { message: @@ -607,8 +607,8 @@ ruleTester.run('order-in-components', rule, { name: 'burger', }; `, - parserOptions, output: null, + parserOptions, errors: [ { message: @@ -628,8 +628,8 @@ ruleTester.run('order-in-components', rule, { name: 'burger', }; `, - parserOptions, output: null, + parserOptions, errors: [ { message: @@ -649,8 +649,8 @@ ruleTester.run('order-in-components', rule, { name: 'burger', }; `, - parserOptions, output: null, + parserOptions, errors: [ { message: @@ -670,8 +670,8 @@ ruleTester.run('order-in-components', rule, { name: 'burger', }; `, - parserOptions, output: null, + parserOptions, errors: [ { message: @@ -691,8 +691,8 @@ ruleTester.run('order-in-components', rule, { name: 'burger', }; `, - parserOptions, output: null, + parserOptions, errors: [ { message: @@ -712,8 +712,8 @@ ruleTester.run('order-in-components', rule, { name: 'burger', }; `, - parserOptions, output: null, + parserOptions, errors: [ { message: @@ -733,8 +733,8 @@ ruleTester.run('order-in-components', rule, { name: 'burger', }; `, - parserOptions, output: null, + parserOptions, errors: [ { message: @@ -754,8 +754,8 @@ ruleTester.run('order-in-components', rule, { name: 'burger', }; `, - parserOptions, output: null, + parserOptions, errors: [ { message: @@ -775,8 +775,8 @@ ruleTester.run('order-in-components', rule, { name: 'burger', }; `, - parserOptions, output: null, + parserOptions, errors: [ { message: @@ -796,8 +796,8 @@ ruleTester.run('order-in-components', rule, { name: 'burger', }; `, - parserOptions, output: null, + parserOptions, errors: [ { message: @@ -817,8 +817,8 @@ ruleTester.run('order-in-components', rule, { name: 'burger', }; `, - parserOptions, output: null, + parserOptions, errors: [ { message: @@ -838,8 +838,8 @@ ruleTester.run('order-in-components', rule, { name: 'burger', }; `, - parserOptions, output: null, + parserOptions, errors: [ { message: @@ -859,7 +859,6 @@ ruleTester.run('order-in-components', rule, { test: fn(), }; `, - parserOptions, output: ` export default { name: 'burger', @@ -868,6 +867,7 @@ ruleTester.run('order-in-components', rule, { test: fn(), }; `, + parserOptions, errors: [ { message: @@ -896,7 +896,6 @@ ruleTester.run('order-in-components', rule, { name: 'burger', }; `, - parserOptions, output: ` export default { name: 'burger', @@ -914,6 +913,7 @@ ruleTester.run('order-in-components', rule, { testOptionalChaining: a?.b?.c, }; `, + parserOptions, errors: [ { message: @@ -934,11 +934,6 @@ ruleTester.run('order-in-components', rule, { }; `, - parser: require.resolve('vue-eslint-parser'), - parserOptions: { - ...parserOptions, - parser: { ts: require.resolve('@typescript-eslint/parser') } - }, output: ` `, + parser: require.resolve('vue-eslint-parser'), + parserOptions: { + ...parserOptions, + parser: { ts: require.resolve('@typescript-eslint/parser') } + }, errors: [ { message: @@ -967,8 +967,6 @@ ruleTester.run('order-in-components', rule, { }) `, - parser: require.resolve('vue-eslint-parser'), - parserOptions, output: ` `, + parser: require.resolve('vue-eslint-parser'), + parserOptions, errors: [ { message: diff --git a/tests/lib/rules/padding-line-between-blocks.js b/tests/lib/rules/padding-line-between-blocks.js index 622839bdc..f53461bae 100644 --- a/tests/lib/rules/padding-line-between-blocks.js +++ b/tests/lib/rules/padding-line-between-blocks.js @@ -125,12 +125,12 @@ tester.run('padding-line-between-blocks', rule, { `, - options: ['never'], output: ` `, + options: ['never'], errors: [ { message: 'Unexpected blank line before this block.', @@ -214,7 +214,6 @@ tester.run('padding-line-between-blocks', rule, { `, - options: ['never'], output: ` @@ -225,6 +224,7 @@ tester.run('padding-line-between-blocks', rule, { `, + options: ['never'], errors: [ { message: 'Unexpected blank line before this block.', @@ -290,7 +290,6 @@ tester.run('padding-line-between-blocks', rule, { `, - options: ['never'], output: ` @@ -304,6 +303,7 @@ tester.run('padding-line-between-blocks', rule, { TEXT `, + options: ['never'], errors: [ { message: 'Unexpected blank line before this block.', diff --git a/tests/lib/rules/padding-line-between-tags.js b/tests/lib/rules/padding-line-between-tags.js index 67aa6b228..70c7a57bb 100644 --- a/tests/lib/rules/padding-line-between-tags.js +++ b/tests/lib/rules/padding-line-between-tags.js @@ -498,18 +498,18 @@ tester.run('padding-line-between-tags', rule, { `, + options: [ + [ + { blankLine: 'always', prev: '*', next: '*' }, + { blankLine: 'never', prev: 'br', next: '*' } + ] + ], errors: [ { message: 'Expected blank line before this tag.', line: 7, column: 13 } - ], - options: [ - [ - { blankLine: 'always', prev: '*', next: '*' }, - { blankLine: 'never', prev: 'br', next: '*' } - ] ] }, { @@ -541,18 +541,18 @@ tester.run('padding-line-between-tags', rule, { `, + options: [ + [ + { blankLine: 'always', prev: '*', next: '*' }, + { blankLine: 'never', prev: '*', next: 'br' } + ] + ], errors: [ { message: 'Expected blank line before this tag.', line: 8, column: 13 } - ], - options: [ - [ - { blankLine: 'always', prev: '*', next: '*' }, - { blankLine: 'never', prev: '*', next: 'br' } - ] ] }, { @@ -586,6 +586,7 @@ tester.run('padding-line-between-tags', rule, { `, + options: [[{ blankLine: 'never', prev: '*', next: '*' }]], errors: [ { message: 'Unexpected blank line before this tag.', @@ -597,8 +598,7 @@ tester.run('padding-line-between-tags', rule, { line: 11, column: 13 } - ], - options: [[{ blankLine: 'never', prev: '*', next: '*' }]] + ] }, { filename: 'test.vue', @@ -624,6 +624,7 @@ tester.run('padding-line-between-tags', rule, { `, + options: [[{ blankLine: 'never', prev: '*', next: '*' }]], errors: [ { message: 'Unexpected blank line before this tag.', @@ -635,8 +636,7 @@ tester.run('padding-line-between-tags', rule, { line: 9, column: 11 } - ], - options: [[{ blankLine: 'never', prev: '*', next: '*' }]] + ] }, { filename: 'test.vue', @@ -669,18 +669,18 @@ tester.run('padding-line-between-tags', rule, { `, + options: [ + [ + { blankLine: 'never', prev: '*', next: '*' }, + { blankLine: 'always', prev: 'br', next: 'div' } + ] + ], errors: [ { message: 'Expected blank line before this tag.', line: 8, column: 13 } - ], - options: [ - [ - { blankLine: 'never', prev: '*', next: '*' }, - { blankLine: 'always', prev: 'br', next: 'div' } - ] ] }, { @@ -712,6 +712,13 @@ tester.run('padding-line-between-tags', rule, { `, + options: [ + [ + { blankLine: 'always', prev: '*', next: '*' }, + { blankLine: 'never', prev: 'br', next: 'div' }, + { blankLine: 'never', prev: 'br', next: 'img' } + ] + ], errors: [ { message: 'Expected blank line before this tag.', @@ -728,13 +735,6 @@ tester.run('padding-line-between-tags', rule, { line: 9, column: 11 } - ], - options: [ - [ - { blankLine: 'always', prev: '*', next: '*' }, - { blankLine: 'never', prev: 'br', next: 'div' }, - { blankLine: 'never', prev: 'br', next: 'img' } - ] ] }, { @@ -764,18 +764,18 @@ tester.run('padding-line-between-tags', rule, { `, + options: [ + [ + { blankLine: 'always', prev: 'br', next: 'div' }, + { blankLine: 'always', prev: 'div', next: 'br' } + ] + ], errors: [ { message: 'Expected blank line before this tag.', line: 8, column: 11 } - ], - options: [ - [ - { blankLine: 'always', prev: 'br', next: 'div' }, - { blankLine: 'always', prev: 'div', next: 'br' } - ] ] }, { @@ -805,18 +805,18 @@ tester.run('padding-line-between-tags', rule, { `, + options: [ + [ + { blankLine: 'always', prev: 'br', next: 'div' }, + { blankLine: 'always', prev: 'br', next: 'br' } + ] + ], errors: [ { message: 'Expected blank line before this tag.', line: 9, column: 11 } - ], - options: [ - [ - { blankLine: 'always', prev: 'br', next: 'div' }, - { blankLine: 'always', prev: 'br', next: 'br' } - ] ] }, { @@ -848,6 +848,12 @@ tester.run('padding-line-between-tags', rule, { `, + options: [ + [ + { blankLine: 'always', prev: '*', next: '*' }, + { blankLine: 'never', prev: 'br', next: 'br' } + ] + ], errors: [ { message: 'Expected blank line before this tag.', @@ -864,12 +870,6 @@ tester.run('padding-line-between-tags', rule, { line: 10, column: 11 } - ], - options: [ - [ - { blankLine: 'always', prev: '*', next: '*' }, - { blankLine: 'never', prev: 'br', next: 'br' } - ] ] }, { @@ -901,14 +901,14 @@ tester.run('padding-line-between-tags', rule, { `, + options: [[{ blankLine: 'never', prev: 'br', next: 'br' }]], errors: [ { message: 'Unexpected blank line before this tag.', line: 11, column: 11 } - ], - options: [[{ blankLine: 'never', prev: 'br', next: 'br' }]] + ] }, { filename: 'test.vue', @@ -935,14 +935,14 @@ tester.run('padding-line-between-tags', rule, { `, + options: [[{ blankLine: 'always', prev: '*', next: 'br' }]], errors: [ { message: 'Expected blank line before this tag.', line: 7, column: 11 } - ], - options: [[{ blankLine: 'always', prev: '*', next: 'br' }]] + ] }, { filename: 'test.vue', @@ -1015,14 +1015,14 @@ tester.run('padding-line-between-tags', rule, { `, + options: [[{ blankLine: 'never', prev: '*', next: '*' }]], errors: [ { message: 'Unexpected blank line before this tag.', line: 6, column: 12 } - ], - options: [[{ blankLine: 'never', prev: '*', next: '*' }]] + ] }, { filename: 'test.vue', @@ -1045,14 +1045,14 @@ tester.run('padding-line-between-tags', rule, { `, + options: [[{ blankLine: 'never', prev: '*', next: '*' }]], errors: [ { message: 'Unexpected blank line before this tag.', line: 7, column: 12 } - ], - options: [[{ blankLine: 'never', prev: '*', next: '*' }]] + ] }, { filename: 'test.vue', @@ -1076,14 +1076,14 @@ tester.run('padding-line-between-tags', rule, { `, + options: [[{ blankLine: 'never', prev: '*', next: '*' }]], errors: [ { message: 'Unexpected blank line before this tag.', line: 8, column: 12 } - ], - options: [[{ blankLine: 'never', prev: '*', next: '*' }]] + ] }, { filename: 'test.vue', @@ -1109,14 +1109,14 @@ tester.run('padding-line-between-tags', rule, { `, + options: [[{ blankLine: 'never', prev: '*', next: '*' }]], errors: [ { message: 'Unexpected blank line before this tag.', line: 10, column: 12 } - ], - options: [[{ blankLine: 'never', prev: '*', next: '*' }]] + ] }, { filename: 'test.vue', @@ -1147,14 +1147,14 @@ tester.run('padding-line-between-tags', rule, {
`, + options: [[{ blankLine: 'consistent', prev: '*', next: '*' }]], errors: [ { message: 'Expected blank line before this tag.', line: 7, column: 11 } - ], - options: [[{ blankLine: 'consistent', prev: '*', next: '*' }]] + ] }, { filename: 'test.vue', @@ -1191,6 +1191,7 @@ tester.run('padding-line-between-tags', rule, {
`, + options: [[{ blankLine: 'consistent', prev: '*', next: '*' }]], errors: [ { message: 'Expected blank line before this tag.', @@ -1207,8 +1208,7 @@ tester.run('padding-line-between-tags', rule, { line: 9, column: 11 } - ], - options: [[{ blankLine: 'consistent', prev: '*', next: '*' }]] + ] }, { filename: 'test.vue', @@ -1243,6 +1243,12 @@ tester.run('padding-line-between-tags', rule, { `, + options: [ + [ + { blankLine: 'consistent', prev: '*', next: '*' }, + { blankLine: 'never', prev: 'br', next: 'br' } + ] + ], errors: [ { message: 'Unexpected blank line before this tag.', @@ -1259,12 +1265,6 @@ tester.run('padding-line-between-tags', rule, { line: 13, column: 11 } - ], - options: [ - [ - { blankLine: 'consistent', prev: '*', next: '*' }, - { blankLine: 'never', prev: 'br', next: 'br' } - ] ] }, { @@ -1288,14 +1288,14 @@ tester.run('padding-line-between-tags', rule, { `, + options: [[{ blankLine: 'consistent', prev: '*', next: '*' }]], errors: [ { message: 'Unexpected blank line before this tag.', line: 7, column: 11 } - ], - options: [[{ blankLine: 'consistent', prev: '*', next: '*' }]] + ] } ] }) diff --git a/tests/lib/rules/prefer-true-attribute-shorthand.js b/tests/lib/rules/prefer-true-attribute-shorthand.js index e7d52ef7f..0bad5c173 100644 --- a/tests/lib/rules/prefer-true-attribute-shorthand.js +++ b/tests/lib/rules/prefer-true-attribute-shorthand.js @@ -157,6 +157,7 @@ tester.run('prefer-true-attribute-shorthand', rule, { `, + output: null, errors: [ { messageId: 'expectShort', @@ -172,8 +173,7 @@ tester.run('prefer-true-attribute-shorthand', rule, { } ] } - ], - output: null + ] }, { filename: 'test.vue', @@ -181,6 +181,7 @@ tester.run('prefer-true-attribute-shorthand', rule, { `, + output: null, errors: [ { messageId: 'expectShort', @@ -196,8 +197,7 @@ tester.run('prefer-true-attribute-shorthand', rule, { } ] } - ], - output: null + ] }, { filename: 'test.vue', @@ -205,6 +205,7 @@ tester.run('prefer-true-attribute-shorthand', rule, { `, + output: null, options: ['always'], errors: [ { @@ -221,8 +222,7 @@ tester.run('prefer-true-attribute-shorthand', rule, { } ] } - ], - output: null + ] }, { filename: 'test.vue', @@ -230,6 +230,7 @@ tester.run('prefer-true-attribute-shorthand', rule, { `, + output: null, options: ['always'], errors: [ { @@ -246,8 +247,7 @@ tester.run('prefer-true-attribute-shorthand', rule, { } ] } - ], - output: null + ] }, { filename: 'test.vue', @@ -255,6 +255,7 @@ tester.run('prefer-true-attribute-shorthand', rule, { `, + output: null, options: ['never'], errors: [ { @@ -276,8 +277,7 @@ tester.run('prefer-true-attribute-shorthand', rule, { } ] } - ], - output: null + ] } ] }) diff --git a/tests/lib/rules/require-emit-validator.js b/tests/lib/rules/require-emit-validator.js index 2b60e8910..d539b55ea 100644 --- a/tests/lib/rules/require-emit-validator.js +++ b/tests/lib/rules/require-emit-validator.js @@ -118,8 +118,8 @@ ruleTester.run('require-emit-validator', rule, { } }) `, - parserOptions: { ecmaVersion: 6, sourceType: 'module' }, - parser: require.resolve('@typescript-eslint/parser') + parser: require.resolve('@typescript-eslint/parser'), + parserOptions: { ecmaVersion: 6, sourceType: 'module' } }, { filename: 'test.vue', @@ -132,8 +132,8 @@ ruleTester.run('require-emit-validator', rule, { }, }) `, - parserOptions: { ecmaVersion: 6, sourceType: 'module' }, - parser: require.resolve('@typescript-eslint/parser') + parser: require.resolve('@typescript-eslint/parser'), + parserOptions: { ecmaVersion: 6, sourceType: 'module' } }, { filename: 'test.vue', @@ -333,8 +333,8 @@ ruleTester.run('require-emit-validator', rule, { } }); `, - parserOptions: { ecmaVersion: 6, sourceType: 'module' }, parser: require.resolve('@typescript-eslint/parser'), + parserOptions: { ecmaVersion: 6, sourceType: 'module' }, errors: [ { messageId: 'missing', diff --git a/tests/lib/rules/require-explicit-emits.js b/tests/lib/rules/require-explicit-emits.js index 43a3c2599..af90569dd 100644 --- a/tests/lib/rules/require-explicit-emits.js +++ b/tests/lib/rules/require-explicit-emits.js @@ -1975,14 +1975,14 @@ emits: {'foo': null} emit('baz') emit('qux') `, - ...getTypeScriptFixtureTestOptions(), errors: [ { message: 'The "qux" event has been triggered but not declared on `defineEmits`.', line: 8 } - ] + ], + ...getTypeScriptFixtureTestOptions() } ] }) diff --git a/tests/lib/rules/require-expose.js b/tests/lib/rules/require-expose.js index 64d073c24..76932cd95 100644 --- a/tests/lib/rules/require-expose.js +++ b/tests/lib/rules/require-expose.js @@ -95,15 +95,13 @@ tester.run('require-expose', rule, { ` }, - { - code: ` + ` Vue.mixin({ methods: { foo () {} } }) - ` - }, + `, { filename: 'test.vue', code: ` diff --git a/tests/lib/rules/require-macro-variable-name.js b/tests/lib/rules/require-macro-variable-name.js index c54c224a5..ed99a64e5 100644 --- a/tests/lib/rules/require-macro-variable-name.js +++ b/tests/lib/rules/require-macro-variable-name.js @@ -237,6 +237,7 @@ tester.run('require-macro-variable-name', rule, { const attrs = useAttrs({}) `, + options: [customOptions], errors: [ { message: `The variable name of "defineSlots" must be "${customOptions.defineSlots}".`, @@ -289,8 +290,7 @@ tester.run('require-macro-variable-name', rule, { } ] } - ], - options: [customOptions] + ] }, { filename: 'test.vue', @@ -300,6 +300,7 @@ tester.run('require-macro-variable-name', rule, { const attrsCustom = useAttrs({}) `, + options: [{ defineSlots: 'slotsCustom' }], errors: [ { message: `The variable name of "useAttrs" must be "attrs".`, @@ -317,8 +318,7 @@ tester.run('require-macro-variable-name', rule, { } ] } - ], - options: [{ defineSlots: 'slotsCustom' }] + ] } ] }) diff --git a/tests/lib/rules/require-prop-comment.js b/tests/lib/rules/require-prop-comment.js index 900f25ec3..3863abc3d 100644 --- a/tests/lib/rules/require-prop-comment.js +++ b/tests/lib/rules/require-prop-comment.js @@ -20,8 +20,7 @@ const tester = new RuleTester({ tester.run('require-prop-comment', rule, { valid: [ - { - code: ` + ` - ` - }, + `, { code: ` - ` - }, + `, { code: ` `, + parserOptions: { + parser: require.resolve('@typescript-eslint/parser') + }, errors: [ { line: 4, column: 9, message: 'The "a" property should have a JSDoc comment.' } - ], - parserOptions: { - parser: require.resolve('@typescript-eslint/parser') - } + ] } ] }) diff --git a/tests/lib/rules/require-prop-type-constructor.js b/tests/lib/rules/require-prop-type-constructor.js index 9cd4eae6e..a4d6766df 100644 --- a/tests/lib/rules/require-prop-type-constructor.js +++ b/tests/lib/rules/require-prop-type-constructor.js @@ -224,13 +224,13 @@ ruleTester.run('require-prop-type-constructor', rule, { } } `, + parser: require.resolve('@typescript-eslint/parser'), errors: [ { message: 'The "a" property should be a constructor.', line: 5 } - ], - parser: require.resolve('@typescript-eslint/parser') + ] }, { filename: 'ExtraCommas.vue', @@ -248,13 +248,13 @@ ruleTester.run('require-prop-type-constructor', rule, { } } `, + parser: require.resolve('@typescript-eslint/parser'), errors: [ { message: 'The "name" property should be a constructor.', line: 4 } - ], - parser: require.resolve('@typescript-eslint/parser') + ] }, { filename: 'LiteralsComponent.vue', diff --git a/tests/lib/rules/require-prop-types.js b/tests/lib/rules/require-prop-types.js index 9b7077fc1..fdb91dd30 100644 --- a/tests/lib/rules/require-prop-types.js +++ b/tests/lib/rules/require-prop-types.js @@ -137,8 +137,8 @@ ruleTester.run('require-prop-types', rule, { } }); `, - parserOptions: { ecmaVersion: 6, sourceType: 'module' }, - parser: require.resolve('@typescript-eslint/parser') + parser: require.resolve('@typescript-eslint/parser'), + parserOptions: { ecmaVersion: 6, sourceType: 'module' } }, { filename: 'test.vue', @@ -151,8 +151,8 @@ ruleTester.run('require-prop-types', rule, { } }); `, - parserOptions: { ecmaVersion: 6, sourceType: 'module' }, - parser: require.resolve('@typescript-eslint/parser') + parser: require.resolve('@typescript-eslint/parser'), + parserOptions: { ecmaVersion: 6, sourceType: 'module' } }, { filename: 'test.vue', @@ -163,8 +163,8 @@ ruleTester.run('require-prop-types', rule, { }) `, - parserOptions: { ecmaVersion: 6, sourceType: 'module' }, - parser: require.resolve('vue-eslint-parser') + parser: require.resolve('vue-eslint-parser'), + parserOptions: { ecmaVersion: 6, sourceType: 'module' } }, { filename: 'test.vue', @@ -173,12 +173,12 @@ ruleTester.run('require-prop-types', rule, { defineProps<{foo:string}>() `, + parser: require.resolve('vue-eslint-parser'), parserOptions: { ecmaVersion: 6, sourceType: 'module', parser: require.resolve('@typescript-eslint/parser') - }, - parser: require.resolve('vue-eslint-parser') + } }, { code: ` @@ -308,8 +308,8 @@ ruleTester.run('require-prop-types', rule, { } }); `, - parserOptions: { ecmaVersion: 6, sourceType: 'module' }, parser: require.resolve('@typescript-eslint/parser'), + parserOptions: { ecmaVersion: 6, sourceType: 'module' }, errors: [ { message: 'Prop "foo" should define at least its type.', @@ -326,8 +326,8 @@ ruleTester.run('require-prop-types', rule, { } }); `, - parserOptions: { ecmaVersion: 6, sourceType: 'module' }, parser: require.resolve('@typescript-eslint/parser'), + parserOptions: { ecmaVersion: 6, sourceType: 'module' }, errors: [ { message: 'Prop "foo" should define at least its type.', @@ -344,8 +344,8 @@ ruleTester.run('require-prop-types', rule, { }) `, - parserOptions: { ecmaVersion: 6, sourceType: 'module' }, parser: require.resolve('vue-eslint-parser'), + parserOptions: { ecmaVersion: 6, sourceType: 'module' }, errors: [ { message: 'Prop "foo" should define at least its type.', @@ -360,8 +360,8 @@ ruleTester.run('require-prop-types', rule, { defineProps(['foo']) `, - parserOptions: { ecmaVersion: 6, sourceType: 'module' }, parser: require.resolve('vue-eslint-parser'), + parserOptions: { ecmaVersion: 6, sourceType: 'module' }, errors: [ { message: 'Prop "foo" should define at least its type.', diff --git a/tests/lib/rules/require-typed-object-prop.js b/tests/lib/rules/require-typed-object-prop.js index 5d93965a5..f574e82d8 100644 --- a/tests/lib/rules/require-typed-object-prop.js +++ b/tests/lib/rules/require-typed-object-prop.js @@ -14,235 +14,235 @@ ruleTester.run('require-typed-object-prop', rule, { // empty { filename: 'test.vue', - parserOptions: { ecmaVersion: 6, sourceType: 'module' }, code: ` export default { props: {} } - ` + `, + parserOptions: { ecmaVersion: 6, sourceType: 'module' } }, { filename: 'test.vue', - parserOptions: { ecmaVersion: 6, sourceType: 'module' }, code: ` export default Vue.extend({ props: {} }); - ` + `, + parserOptions: { ecmaVersion: 6, sourceType: 'module' } }, { filename: 'test.vue', - parserOptions: { ecmaVersion: 6, sourceType: 'module' }, code: ` `, - parser: require.resolve('vue-eslint-parser') + parser: require.resolve('vue-eslint-parser'), + parserOptions: { ecmaVersion: 6, sourceType: 'module' } }, // array props { filename: 'test.vue', - parserOptions: { ecmaVersion: 6, sourceType: 'module' }, code: ` export default { props: ['foo'] } - ` + `, + parserOptions: { ecmaVersion: 6, sourceType: 'module' } }, { filename: 'test.vue', - parserOptions: { ecmaVersion: 6, sourceType: 'module' }, code: ` export default Vue.extend({ props: ['foo'] }); - ` + `, + parserOptions: { ecmaVersion: 6, sourceType: 'module' } }, { filename: 'test.vue', - parserOptions: { ecmaVersion: 6, sourceType: 'module' }, code: ` `, - parser: require.resolve('vue-eslint-parser') + parser: require.resolve('vue-eslint-parser'), + parserOptions: { ecmaVersion: 6, sourceType: 'module' } }, // primitive props { filename: 'test.vue', - parserOptions: { ecmaVersion: 6, sourceType: 'module' }, code: ` export default { props: { foo: String } } - ` + `, + parserOptions: { ecmaVersion: 6, sourceType: 'module' } }, { filename: 'test.vue', - parserOptions: { ecmaVersion: 6, sourceType: 'module' }, code: ` export default Vue.extend({ props: { foo: String } }); - ` + `, + parserOptions: { ecmaVersion: 6, sourceType: 'module' } }, { filename: 'test.vue', - parserOptions: { ecmaVersion: 6, sourceType: 'module' }, code: ` `, - parser: require.resolve('vue-eslint-parser') + parser: require.resolve('vue-eslint-parser'), + parserOptions: { ecmaVersion: 6, sourceType: 'module' } }, // union { filename: 'test.vue', - parserOptions: { ecmaVersion: 6, sourceType: 'module' }, code: ` export default { props: { foo: [Number, String, Boolean] } } - ` + `, + parserOptions: { ecmaVersion: 6, sourceType: 'module' } }, { filename: 'test.vue', - parserOptions: { ecmaVersion: 6, sourceType: 'module' }, code: ` export default Vue.extend({ props: { foo: [Number, String, Boolean] } }); - ` + `, + parserOptions: { ecmaVersion: 6, sourceType: 'module' } }, { filename: 'test.vue', - parserOptions: { ecmaVersion: 6, sourceType: 'module' }, code: ` `, - parser: require.resolve('vue-eslint-parser') + parser: require.resolve('vue-eslint-parser'), + parserOptions: { ecmaVersion: 6, sourceType: 'module' } }, // function { filename: 'test.vue', - parserOptions: { ecmaVersion: 6, sourceType: 'module' }, code: ` export default { props: { foo: someFunction() } } - ` + `, + parserOptions: { ecmaVersion: 6, sourceType: 'module' } }, { filename: 'test.vue', - parserOptions: { ecmaVersion: 6, sourceType: 'module' }, code: ` export default Vue.extend({ props: { foo: someFunction() } }); - ` + `, + parserOptions: { ecmaVersion: 6, sourceType: 'module' } }, { filename: 'test.vue', - parserOptions: { ecmaVersion: 6, sourceType: 'module' }, code: ` `, - parser: require.resolve('vue-eslint-parser') + parser: require.resolve('vue-eslint-parser'), + parserOptions: { ecmaVersion: 6, sourceType: 'module' } }, // typed object { filename: 'test.vue', - parserOptions: { ecmaVersion: 6, sourceType: 'module' }, code: ` export default { props: { foo: Object as PropType } } `, - parser: require.resolve('@typescript-eslint/parser') + parser: require.resolve('@typescript-eslint/parser'), + parserOptions: { ecmaVersion: 6, sourceType: 'module' } }, { filename: 'test.vue', - parserOptions: { ecmaVersion: 6, sourceType: 'module' }, code: ` export default { props: { foo: Array as PropType } } `, - parser: require.resolve('@typescript-eslint/parser') + parser: require.resolve('@typescript-eslint/parser'), + parserOptions: { ecmaVersion: 6, sourceType: 'module' } }, { filename: 'test.vue', - parserOptions: { ecmaVersion: 6, sourceType: 'module' }, code: ` export default Vue.extend({ props: { foo: Object as PropType } }); `, - parser: require.resolve('@typescript-eslint/parser') + parser: require.resolve('@typescript-eslint/parser'), + parserOptions: { ecmaVersion: 6, sourceType: 'module' } }, { filename: 'test.vue', - parserOptions: { - ecmaVersion: 6, - sourceType: 'module', - parser: require.resolve('@typescript-eslint/parser') - }, code: ` `, - parser: require.resolve('vue-eslint-parser') - }, - - { - filename: 'test.vue', + parser: require.resolve('vue-eslint-parser'), parserOptions: { ecmaVersion: 6, sourceType: 'module', parser: require.resolve('@typescript-eslint/parser') - }, + } + }, + + { + filename: 'test.vue', code: ` export default { props: { foo: Object as () => User } } `, - parser: require.resolve('@typescript-eslint/parser') - }, - { - filename: 'test.vue', + parser: require.resolve('@typescript-eslint/parser'), parserOptions: { ecmaVersion: 6, sourceType: 'module', parser: require.resolve('@typescript-eslint/parser') - }, + } + }, + { + filename: 'test.vue', code: ` export default Vue.extend({ props: { foo: Object as () => User } }); `, - parser: require.resolve('@typescript-eslint/parser') - }, - { - filename: 'test.vue', + parser: require.resolve('@typescript-eslint/parser'), parserOptions: { ecmaVersion: 6, sourceType: 'module', parser: require.resolve('@typescript-eslint/parser') - }, + } + }, + { + filename: 'test.vue', code: ` `, - parser: require.resolve('vue-eslint-parser') + parser: require.resolve('vue-eslint-parser'), + parserOptions: { + ecmaVersion: 6, + sourceType: 'module', + parser: require.resolve('@typescript-eslint/parser') + } }, // any { @@ -252,12 +252,12 @@ ruleTester.run('require-typed-object-prop', rule, { defineProps({ foo: { type: Object as any } }); `, + parser: require.resolve('vue-eslint-parser'), parserOptions: { ecmaVersion: 6, sourceType: 'module', parser: require.resolve('@typescript-eslint/parser') - }, - parser: require.resolve('vue-eslint-parser') + } }, { filename: 'test.vue', @@ -270,12 +270,12 @@ ruleTester.run('require-typed-object-prop', rule, { }; `, + parser: require.resolve('vue-eslint-parser'), parserOptions: { ecmaVersion: 6, sourceType: 'module', parser: require.resolve('@typescript-eslint/parser') - }, - parser: require.resolve('vue-eslint-parser') + } }, { filename: 'test.vue', @@ -288,12 +288,12 @@ ruleTester.run('require-typed-object-prop', rule, { }); `, + parser: require.resolve('vue-eslint-parser'), parserOptions: { ecmaVersion: 6, sourceType: 'module', parser: require.resolve('@typescript-eslint/parser') - }, - parser: require.resolve('vue-eslint-parser') + } }, // unknown { @@ -303,12 +303,12 @@ ruleTester.run('require-typed-object-prop', rule, { defineProps({ foo: { type: Object as unknown } }); `, + parser: require.resolve('vue-eslint-parser'), parserOptions: { ecmaVersion: 6, sourceType: 'module', parser: require.resolve('@typescript-eslint/parser') - }, - parser: require.resolve('vue-eslint-parser') + } }, { filename: 'test.vue', @@ -321,12 +321,12 @@ ruleTester.run('require-typed-object-prop', rule, { }; `, + parser: require.resolve('vue-eslint-parser'), parserOptions: { ecmaVersion: 6, sourceType: 'module', parser: require.resolve('@typescript-eslint/parser') - }, - parser: require.resolve('vue-eslint-parser') + } }, { filename: 'test.vue', @@ -339,12 +339,12 @@ ruleTester.run('require-typed-object-prop', rule, { }); `, + parser: require.resolve('vue-eslint-parser'), parserOptions: { ecmaVersion: 6, sourceType: 'module', parser: require.resolve('@typescript-eslint/parser') - }, - parser: require.resolve('vue-eslint-parser') + } } ], invalid: [ @@ -355,8 +355,8 @@ ruleTester.run('require-typed-object-prop', rule, { defineProps({ foo: Object }); `, - parserOptions: { ecmaVersion: 6, sourceType: 'module' }, parser: require.resolve('vue-eslint-parser'), + parserOptions: { ecmaVersion: 6, sourceType: 'module' }, errors: [ { messageId: 'expectedTypeAnnotation', @@ -394,8 +394,8 @@ ruleTester.run('require-typed-object-prop', rule, { defineProps({ foo: Array }); `, - parserOptions: { ecmaVersion: 6, sourceType: 'module' }, parser: require.resolve('vue-eslint-parser'), + parserOptions: { ecmaVersion: 6, sourceType: 'module' }, errors: [ { messageId: 'expectedTypeAnnotation', @@ -585,8 +585,8 @@ ruleTester.run('require-typed-object-prop', rule, { defineProps({ foo: { type: Object } }); `, - parserOptions: { ecmaVersion: 6, sourceType: 'module' }, parser: require.resolve('vue-eslint-parser'), + parserOptions: { ecmaVersion: 6, sourceType: 'module' }, errors: [ { messageId: 'expectedTypeAnnotation', diff --git a/tests/lib/rules/require-typed-ref.js b/tests/lib/rules/require-typed-ref.js index 571b5c5de..3da293b9a 100644 --- a/tests/lib/rules/require-typed-ref.js +++ b/tests/lib/rules/require-typed-ref.js @@ -75,13 +75,13 @@ tester.run('require-typed-ref', rule, { }, { filename: 'test.vue', - parser: require.resolve('vue-eslint-parser'), code: ` - ` + `, + parser: require.resolve('vue-eslint-parser') }, { filename: 'test.js', @@ -197,13 +197,13 @@ tester.run('require-typed-ref', rule, { }, { filename: 'test.vue', - parser: require.resolve('vue-eslint-parser'), code: ` `, + parser: require.resolve('vue-eslint-parser'), errors: [ { messageId: 'noType', diff --git a/tests/lib/rules/require-valid-default-prop.js b/tests/lib/rules/require-valid-default-prop.js index cec05ba05..1e6f7cd7a 100644 --- a/tests/lib/rules/require-valid-default-prop.js +++ b/tests/lib/rules/require-valid-default-prop.js @@ -122,8 +122,8 @@ ruleTester.run('require-valid-default-prop', rule, { } }); `, - parserOptions: { ecmaVersion: 6, sourceType: 'module' }, - parser: require.resolve('@typescript-eslint/parser') + parser: require.resolve('@typescript-eslint/parser'), + parserOptions: { ecmaVersion: 6, sourceType: 'module' } }, { filename: 'test.vue', @@ -214,8 +214,8 @@ ruleTester.run('require-valid-default-prop', rule, { } }); `, - parserOptions: { ecmaVersion: 6, sourceType: 'module' }, parser: require.resolve('@typescript-eslint/parser'), + parserOptions: { ecmaVersion: 6, sourceType: 'module' }, errors: errorMessage('function') }, { @@ -229,8 +229,8 @@ ruleTester.run('require-valid-default-prop', rule, { } }); `, - parserOptions: { ecmaVersion: 6, sourceType: 'module' }, parser: require.resolve('@typescript-eslint/parser'), + parserOptions: { ecmaVersion: 6, sourceType: 'module' }, errors: errorMessage('function') }, { @@ -244,8 +244,8 @@ ruleTester.run('require-valid-default-prop', rule, { } }); `, - parserOptions: { ecmaVersion: 6, sourceType: 'module' }, parser: require.resolve('@typescript-eslint/parser'), + parserOptions: { ecmaVersion: 6, sourceType: 'module' }, errors: errorMessage('function') }, { @@ -264,12 +264,12 @@ ruleTester.run('require-valid-default-prop', rule, { num: 1 }); `, + parser: require.resolve('vue-eslint-parser'), parserOptions: { ecmaVersion: 6, sourceType: 'module', parser: require.resolve('@typescript-eslint/parser') - }, - parser: require.resolve('vue-eslint-parser') + } }, { code: ` @@ -614,8 +614,8 @@ ruleTester.run('require-valid-default-prop', rule, { } as PropOptions } });`, - parserOptions: { ecmaVersion: 6, sourceType: 'module' }, parser: require.resolve('@typescript-eslint/parser'), + parserOptions: { ecmaVersion: 6, sourceType: 'module' }, errors: errorMessage('function or number') }, @@ -874,8 +874,8 @@ ruleTester.run('require-valid-default-prop', rule, { } }); `, - parserOptions: { ecmaVersion: 6, sourceType: 'module' }, parser: require.resolve('@typescript-eslint/parser'), + parserOptions: { ecmaVersion: 6, sourceType: 'module' }, errors: errorMessage('function') }, { @@ -889,8 +889,8 @@ ruleTester.run('require-valid-default-prop', rule, { } }); `, - parserOptions: { ecmaVersion: 6, sourceType: 'module' }, parser: require.resolve('@typescript-eslint/parser'), + parserOptions: { ecmaVersion: 6, sourceType: 'module' }, errors: errorMessage('function') }, { @@ -904,8 +904,8 @@ ruleTester.run('require-valid-default-prop', rule, { } }); `, - parserOptions: { ecmaVersion: 6, sourceType: 'module' }, parser: require.resolve('@typescript-eslint/parser'), + parserOptions: { ecmaVersion: 6, sourceType: 'module' }, errors: errorMessage('function') }, { @@ -920,8 +920,8 @@ ruleTester.run('require-valid-default-prop', rule, { }) `, - parserOptions: { ecmaVersion: 6, sourceType: 'module' }, parser: require.resolve('vue-eslint-parser'), + parserOptions: { ecmaVersion: 6, sourceType: 'module' }, errors: [ { message: "Type of the default value for 'foo' prop must be a string.", @@ -938,12 +938,12 @@ ruleTester.run('require-valid-default-prop', rule, { }) `, + parser: require.resolve('vue-eslint-parser'), parserOptions: { ecmaVersion: 6, sourceType: 'module', parser: require.resolve('@typescript-eslint/parser') }, - parser: require.resolve('vue-eslint-parser'), errors: [ { message: "Type of the default value for 'foo' prop must be a string.", @@ -967,7 +967,6 @@ ruleTester.run('require-valid-default-prop', rule, { i: ['foo', 'bar'], }) `, - ...getTypeScriptFixtureTestOptions(), errors: [ { message: "Type of the default value for 'a' prop must be a string.", @@ -1006,7 +1005,8 @@ ruleTester.run('require-valid-default-prop', rule, { message: "Type of the default value for 'i' prop must be a function.", line: 13 } - ] + ], + ...getTypeScriptFixtureTestOptions() } ] }) diff --git a/tests/lib/rules/return-in-computed-property.js b/tests/lib/rules/return-in-computed-property.js index 9fbe2c84e..71afcc3eb 100644 --- a/tests/lib/rules/return-in-computed-property.js +++ b/tests/lib/rules/return-in-computed-property.js @@ -94,8 +94,8 @@ ruleTester.run('return-in-computed-property', rule, { } } `, - parserOptions, - options: [{ treatUndefinedAsUnspecified: false }] + options: [{ treatUndefinedAsUnspecified: false }], + parserOptions }, { filename: 'test.vue', @@ -144,8 +144,8 @@ ruleTester.run('return-in-computed-property', rule, { } } `, - parserOptions, - options: [{ treatUndefinedAsUnspecified: false }] + options: [{ treatUndefinedAsUnspecified: false }], + parserOptions } ], @@ -264,8 +264,8 @@ ruleTester.run('return-in-computed-property', rule, { } } `, - parserOptions, options: [{ treatUndefinedAsUnspecified: false }], + parserOptions, errors: [ { message: 'Expected to return a value in "foo" computed property.', @@ -284,8 +284,8 @@ ruleTester.run('return-in-computed-property', rule, { } } `, - parserOptions, options: [{ treatUndefinedAsUnspecified: true }], + parserOptions, errors: [ { message: 'Expected to return a value in "foo" computed property.', @@ -378,8 +378,8 @@ ruleTester.run('return-in-computed-property', rule, { } } `, - parserOptions, options: [{ treatUndefinedAsUnspecified: false }], + parserOptions, errors: [ { message: 'Expected to return a value in computed function.', diff --git a/tests/lib/rules/singleline-html-element-content-newline.js b/tests/lib/rules/singleline-html-element-content-newline.js index a740ff0ed..5bf2c9392 100644 --- a/tests/lib/rules/singleline-html-element-content-newline.js +++ b/tests/lib/rules/singleline-html-element-content-newline.js @@ -372,7 +372,6 @@ content
singleline content
`, - options: [{ ignoreWhenNoAttributes: false }], output: ` `, + options: [{ ignoreWhenNoAttributes: false }], errors: [ 'Expected 1 line break after opening tag (`
`), but no line breaks found.', 'Expected 1 line break before closing tag (`
`), but no line breaks found.' @@ -391,7 +391,6 @@ singleline content singlelinechildren `, - options: [{ ignoreWhenNoAttributes: false }], output: ` `, + options: [{ ignoreWhenNoAttributes: false }], errors: [ 'Expected 1 line break after opening tag (``), but no line breaks found.', 'Expected 1 line break after opening tag (``), but no line breaks found.', @@ -418,7 +418,6 @@ children
`, - options: [{ ignoreWhenNoAttributes: false }], output: ` `, + options: [{ ignoreWhenNoAttributes: false }], errors: [ 'Expected 1 line break after opening tag (`
`), but no line breaks found.', 'Expected 1 line break before closing tag (`
`), but no line breaks found.' @@ -437,7 +437,6 @@ children
singleline element
`, - options: [{ ignoreWhenNoAttributes: false }], output: ` `, + options: [{ ignoreWhenNoAttributes: false }], errors: [ 'Expected 1 line break after opening tag (`
`), but no line breaks found.', 'Expected 1 line break before closing tag (`
`), but no line breaks found.' @@ -456,13 +456,13 @@ singleline element
`, - options: [{ ignoreWhenEmpty: false, ignoreWhenNoAttributes: false }], output: ` `, + options: [{ ignoreWhenEmpty: false, ignoreWhenNoAttributes: false }], errors: [ 'Expected 1 line break after opening tag (`
`), but no line breaks found.' ] @@ -473,13 +473,13 @@ singleline element
`, - options: [{ ignoreWhenEmpty: false, ignoreWhenNoAttributes: false }], output: ` `, + options: [{ ignoreWhenEmpty: false, ignoreWhenNoAttributes: false }], errors: [ 'Expected 1 line break after opening tag (`
`), but no line breaks found.' ] diff --git a/tests/lib/rules/space-in-parens.js b/tests/lib/rules/space-in-parens.js index 8791652ed..ef6fe628e 100644 --- a/tests/lib/rules/space-in-parens.js +++ b/tests/lib/rules/space-in-parens.js @@ -94,13 +94,13 @@ tester.run('space-in-parens', rule, { @click="foo(arg)" /> `, - options: ['always'], output: ` `, + options: ['always'], errors: [ errorMessage({ messageId: 'missingOpeningSpace', @@ -143,13 +143,13 @@ tester.run('space-in-parens', rule, { :value="(1 + 2) + 3" > `, - options: ['always'], output: ` `, + options: ['always'], errors: [ errorMessage({ messageId: 'missingOpeningSpace', @@ -192,13 +192,13 @@ tester.run('space-in-parens', rule, { :[(1+2)]="(1 + 2) + 3" > `, - options: ['always'], output: ` `, + options: ['always'], errors: [ errorMessage({ messageId: 'missingOpeningSpace', diff --git a/tests/lib/rules/space-unary-ops.js b/tests/lib/rules/space-unary-ops.js index 6b3e7c25f..63539a5a7 100644 --- a/tests/lib/rules/space-unary-ops.js +++ b/tests/lib/rules/space-unary-ops.js @@ -50,8 +50,8 @@ tester.run('space-unary-ops', rule, { }, { code: '', - options: [{ nonwords: true }], output: '', + options: [{ nonwords: true }], errors: ["Unary operator '!' must be followed by whitespace."] }, diff --git a/tests/lib/rules/template-curly-spacing.js b/tests/lib/rules/template-curly-spacing.js index 6c4376969..0fe530511 100644 --- a/tests/lib/rules/template-curly-spacing.js +++ b/tests/lib/rules/template-curly-spacing.js @@ -41,14 +41,13 @@ tester.run('template-curly-spacing', rule, { }, // CSS vars injection - { - code: ` + ` ` - } + + ` ], invalid: [ { @@ -79,12 +78,12 @@ tester.run('template-curly-spacing', rule, {
`, - options: ['always'], output: ` `, + options: ['always'], errors: [ { message: "Expected space(s) after '${'.", diff --git a/tests/lib/rules/this-in-template.js b/tests/lib/rules/this-in-template.js index 904aa00c4..5686bf137 100644 --- a/tests/lib/rules/this-in-template.js +++ b/tests/lib/rules/this-in-template.js @@ -248,14 +248,14 @@ ruleTester.run('this-in-template', rule, { { code: ``, output: ``, - errors: ["Unexpected usage of 'this'."], - options: ['never'] + options: ['never'], + errors: ["Unexpected usage of 'this'."] }, { code: ``, output: ``, - errors: ["Unexpected usage of 'this'."], - options: ['never'] + options: ['never'], + errors: ["Unexpected usage of 'this'."] } ] }) diff --git a/tests/lib/rules/use-v-on-exact.js b/tests/lib/rules/use-v-on-exact.js index 73ac2408b..929fd746a 100644 --- a/tests/lib/rules/use-v-on-exact.js +++ b/tests/lib/rules/use-v-on-exact.js @@ -15,92 +15,48 @@ const ruleTester = new RuleTester({ ruleTester.run('use-v-on-exact', rule, { valid: [ - { - code: `` - }, - { - code: `` - }, - { - code: `` - }, - { - code: `` - }, - { - code: `` - }, - { - code: `` - }, - { - code: `` - }, - { - code: `` - }, - { - code: `` - }, - { - code: `` - }, - { - code: `` - }, - { - code: `` - }, - { - code: `` - }, - { - code: `` - }, - { - code: `` - }, - { - code: `` - }, - { - code: `` - }, - { - code: `` - }, - { - code: `` - }, - { - code: `` - }, - { - code: `` - }, - { - code: `` - }, - { - code: ` + ` ], invalid: [ diff --git a/tests/lib/rules/v-bind-style.js b/tests/lib/rules/v-bind-style.js index 2fd1ce7c2..0cb67f62f 100644 --- a/tests/lib/rules/v-bind-style.js +++ b/tests/lib/rules/v-bind-style.js @@ -67,44 +67,44 @@ tester.run('v-bind-style', rule, { }, { filename: 'test.vue', - options: ['shorthand'], code: '', output: '', + options: ['shorthand'], errors: ["Unexpected 'v-bind' before ':'."] }, { filename: 'test.vue', - options: ['longform'], code: '', output: '', + options: ['longform'], errors: ["Expected 'v-bind' before ':'."] }, { filename: 'test.vue', - options: ['longform'], code: '', output: '', + options: ['longform'], errors: ["Expected 'v-bind:' instead of '.'."] }, { filename: 'test.vue', - options: ['longform'], code: '', output: '', + options: ['longform'], errors: ["Expected 'v-bind:' instead of '.'."] }, { filename: 'test.vue', - options: ['longform'], code: '', output: '', + options: ['longform'], errors: ["Expected 'v-bind:' instead of '.'."] }, { filename: 'test.vue', - options: ['longform'], code: '', output: '', + options: ['longform'], errors: ["Expected 'v-bind:' instead of '.'."] } ] diff --git a/tests/lib/rules/v-for-delimiter-style.js b/tests/lib/rules/v-for-delimiter-style.js index b1500af50..23665a32c 100644 --- a/tests/lib/rules/v-for-delimiter-style.js +++ b/tests/lib/rules/v-for-delimiter-style.js @@ -94,9 +94,9 @@ tester.run('v-for-delimiter-style', rule, { }, { filename: 'test.vue', - options: ['in'], code: '', output: '', + options: ['in'], errors: [ { message: "Expected 'in' instead of 'of' in 'v-for'.", @@ -106,9 +106,9 @@ tester.run('v-for-delimiter-style', rule, { }, { filename: 'test.vue', - options: ['of'], code: '', output: '', + options: ['of'], errors: [ { message: "Expected 'of' instead of 'in' in 'v-for'.", diff --git a/tests/lib/rules/v-on-event-hyphenation.js b/tests/lib/rules/v-on-event-hyphenation.js index 087e5d00a..beaa5e3fa 100644 --- a/tests/lib/rules/v-on-event-hyphenation.js +++ b/tests/lib/rules/v-on-event-hyphenation.js @@ -73,12 +73,12 @@ tester.run('v-on-event-hyphenation', rule, { `, - options: ['always', { autofix: true }], output: ` `, + options: ['always', { autofix: true }], errors: [ { message: "v-on event '@customEvent' must be hyphenated.", @@ -95,12 +95,12 @@ tester.run('v-on-event-hyphenation', rule, { `, - options: ['never', { autofix: true }], output: ` `, + options: ['never', { autofix: true }], errors: ["v-on event 'v-on:custom-event' can't be hyphenated."] }, { @@ -110,13 +110,13 @@ tester.run('v-on-event-hyphenation', rule, { `, - options: ['always', { autofix: true }], output: ` `, + options: ['always', { autofix: true }], errors: ["v-on event '@update:modelValue' must be hyphenated."] }, { @@ -126,13 +126,13 @@ tester.run('v-on-event-hyphenation', rule, { `, - options: ['never', { autofix: true }], output: ` `, + options: ['never', { autofix: true }], errors: ["v-on event '@update:model-value' can't be hyphenated."] }, { @@ -144,7 +144,6 @@ tester.run('v-on-event-hyphenation', rule, { `, - options: ['always', { autofix: true }], output: ` `, + options: ['always', { autofix: true }], errors: [ "v-on event '@upDate:modelValue' must be hyphenated.", "v-on event '@up-date:modelValue' must be hyphenated.", @@ -168,7 +168,6 @@ tester.run('v-on-event-hyphenation', rule, { `, - options: ['never', { autofix: true }], output: ` `, + options: ['never', { autofix: true }], errors: [ "v-on event '@up-date:modelValue' can't be hyphenated.", "v-on event '@upDate:model-value' can't be hyphenated.", diff --git a/tests/lib/rules/v-on-function-call.js b/tests/lib/rules/v-on-function-call.js index d8486a448..d06bbe231 100644 --- a/tests/lib/rules/v-on-function-call.js +++ b/tests/lib/rules/v-on-function-call.js @@ -161,37 +161,37 @@ tester.run('v-on-function-call', rule, { filename: 'test.vue', code: '', output: null, + options: ['always'], errors: [ "Method calls inside of 'v-on' directives must have parentheses." - ], - options: ['always'] + ] }, { filename: 'test.vue', code: '', output: ``, + options: ['never'], errors: [ "Method calls without arguments inside of 'v-on' directives must not have parentheses." - ], - options: ['never'] + ] }, { filename: 'test.vue', code: '', output: ``, + options: ['never'], errors: [ "Method calls without arguments inside of 'v-on' directives must not have parentheses." - ], - options: ['never'] + ] }, { filename: 'test.vue', code: '', output: null, + options: ['never'], errors: [ "Method calls without arguments inside of 'v-on' directives must not have parentheses." - ], - options: ['never'] + ] }, { filename: 'test.vue', @@ -204,13 +204,13 @@ tester.run('v-on-function-call', rule, { ">
`, output: null, + options: ['never'], errors: [ "Method calls without arguments inside of 'v-on' directives must not have parentheses.", "Method calls without arguments inside of 'v-on' directives must not have parentheses.", "Method calls without arguments inside of 'v-on' directives must not have parentheses.", "Method calls without arguments inside of 'v-on' directives must not have parentheses." - ], - options: ['never'] + ] }, { filename: 'test.vue', @@ -222,10 +222,10 @@ tester.run('v-on-function-call', rule, { `, + options: ['never'], errors: [ "Method calls without arguments inside of 'v-on' directives must not have parentheses." - ], - options: ['never'] + ] }, { filename: 'test.vue', @@ -237,10 +237,10 @@ tester.run('v-on-function-call', rule, { `, + options: ['never'], errors: [ "Method calls without arguments inside of 'v-on' directives must not have parentheses." - ], - options: ['never'] + ] }, { filename: 'test.vue', @@ -254,11 +254,11 @@ tester.run('v-on-function-call', rule, {
`, + options: ['never'], errors: [ "Method calls without arguments inside of 'v-on' directives must not have parentheses.", "Method calls without arguments inside of 'v-on' directives must not have parentheses." - ], - options: ['never'] + ] }, { filename: 'test.vue', @@ -270,10 +270,10 @@ tester.run('v-on-function-call', rule, { `, + options: ['never'], errors: [ "Method calls without arguments inside of 'v-on' directives must not have parentheses." - ], - options: ['never'] + ] }, { filename: 'test.vue', @@ -285,19 +285,19 @@ tester.run('v-on-function-call', rule, { `, + options: ['never'], errors: [ "Method calls without arguments inside of 'v-on' directives must not have parentheses." - ], - options: ['never'] + ] }, { filename: 'test.vue', code: '', output: '', + options: ['never'], errors: [ "Method calls without arguments inside of 'v-on' directives must not have parentheses." - ], - options: ['never'] + ] }, { filename: 'test.vue', @@ -319,10 +319,10 @@ tester.run('v-on-function-call', rule, { } } `, + options: ['never'], errors: [ "Method calls without arguments inside of 'v-on' directives must not have parentheses." - ], - options: ['never'] + ] }, { filename: 'test.vue', @@ -344,10 +344,10 @@ tester.run('v-on-function-call', rule, { } } `, + options: ['never'], errors: [ "Method calls without arguments inside of 'v-on' directives must not have parentheses." - ], - options: ['never'] + ] } ] }) diff --git a/tests/lib/rules/v-on-handler-style.js b/tests/lib/rules/v-on-handler-style.js index e3afd05d5..314bbf8c8 100644 --- a/tests/lib/rules/v-on-handler-style.js +++ b/tests/lib/rules/v-on-handler-style.js @@ -78,12 +78,12 @@ tester.run('v-on-handler-style', rule, {