Skip to content

Introduce Prettier and update eslint config #1161

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
May 25, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ workflows:
- node-v10
- node-v12
- node-v14
- lint

version: 2
jobs:
Expand Down Expand Up @@ -61,3 +62,25 @@ jobs:
<<: *node-base
docker:
- image: node:14

lint:
docker:
- image: node:14
steps:
- run:
name: Versions
command: npm version
- checkout
- restore_cache:
keys:
- v2-npm-lock-{{ .Branch }}-{{ .Environment.CIRCLE_JOB }}-{{ checksum "package.json" }}
- run:
name: Install dependencies
command: npm install
- save_cache:
key: v2-npm-lock-{{ .Branch }}-{{ .Environment.CIRCLE_JOB }}-{{ checksum "package.json" }}
paths:
- node_modules
- run:
name: Test
command: npm run lint
88 changes: 69 additions & 19 deletions .eslintrc.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
'use strict'

module.exports = {
// https://github.com/eslint/eslint/issues/11888
root: false,
root: true,
parserOptions: {
ecmaVersion: 6
},
Expand All @@ -12,28 +11,79 @@ module.exports = {
},
extends: [
'plugin:eslint-plugin/recommended',
'plugin:vue-libs/recommended'
],
plugins: [
'eslint-plugin'
'plugin:vue-libs/recommended',
'prettier'
],
plugins: ['eslint-plugin', 'prettier'],
rules: {
'eslint-plugin/report-message-format': ['error', '^[A-Z`\'{].*\\.$'],
'prettier/prettier': 'error',
'eslint-plugin/report-message-format': ['error', "^[A-Z`'{].*\\.$"],
'eslint-plugin/prefer-placeholders': 'error',
'eslint-plugin/consistent-output': 'error',
'no-mixed-operators': 'error'

'no-debugger': 'error',
'no-console': 'error',
'no-alert': 'error',
'no-void': 'error',

'no-warning-comments': 'warn',
'no-var': 'error',
'prefer-template': 'error',
'object-shorthand': 'error',
'prefer-rest-params': 'error',
'prefer-arrow-callback': 'error',
'prefer-spread': 'error',

'dot-notation': 'error'
},
overrides: [
// Introduce prettier. but ignore files to avoid conflicts with PR.
{
files: [
// https://github.com/vuejs/eslint-plugin-vue/pull/1107
'lib/rules/order-in-components.js',
'tests/lib/rules/order-in-components.js',
// https://github.com/vuejs/eslint-plugin-vue/pull/1090
'lib/rules/require-direct-export.js',
'tests/lib/rules/require-direct-export.js',
'lib/utils/index.js',
'tests/lib/utils/vue-component.js',
// https://github.com/vuejs/eslint-plugin-vue/pull/1017
'lib/utils/indent-common.js',
'tests/lib/rules/html-indent.js',
'tests/lib/rules/script-indent.js',
// https://github.com/vuejs/eslint-plugin-vue/pull/982
'lib/rules/attributes-order.js',
'tests/lib/rules/attributes-order.js',
// https://github.com/vuejs/eslint-plugin-vue/pull/819
'lib/rules/attributes-order.js',
'tests/lib/rules/attributes-order.js'
],
extends: [
'plugin:eslint-plugin/recommended',
'plugin:vue-libs/recommended'
],
rules: {
'prettier/prettier': 'off',

overrides: [{
files: ['lib/rules/*.js'],
rules: {
'consistent-docs-description': 'error',
'no-invalid-meta': 'error',
'no-invalid-meta-docs-categories': 'error',
'eslint-plugin/require-meta-type': 'error',
'require-meta-docs-url': ['error', {
'pattern': `https://eslint.vuejs.org/rules/{{name}}.html`
}]
'rest-spread-spacing': 'error',
'no-mixed-operators': 'error'
}
},
{
files: ['lib/rules/*.js'],
rules: {
'consistent-docs-description': 'error',
'no-invalid-meta': 'error',
'no-invalid-meta-docs-categories': 'error',
'eslint-plugin/require-meta-type': 'error',
'require-meta-docs-url': [
'error',
{
pattern: `https://eslint.vuejs.org/rules/{{name}}.html`
}
]
}
}
}]
]
}
4 changes: 4 additions & 0 deletions .prettierrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
semi: false
singleQuote: true
printWidth: 80
trailingComma: none
74 changes: 54 additions & 20 deletions docs/.vuepress/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,32 +6,62 @@

const rules = require('../../tools/lib/rules')

const uncategorizedRules = rules.filter(rule => !rule.meta.docs.categories && !rule.meta.deprecated)
const deprecatedRules = rules.filter(rule => rule.meta.deprecated)
const uncategorizedRules = rules.filter(
(rule) => !rule.meta.docs.categories && !rule.meta.deprecated
)
const deprecatedRules = rules.filter((rule) => rule.meta.deprecated)

const sidebarCategories = [
{ title: 'Base Rules', categoryIds: ['base'] },
{ title: 'Priority A: Essential', categoryIds: ['vue3-essential', 'essential'] },
{ title: 'Priority A: Essential for Vue.js 3.x', categoryIds: ['vue3-essential'] },
{
title: 'Priority A: Essential',
categoryIds: ['vue3-essential', 'essential']
},
{
title: 'Priority A: Essential for Vue.js 3.x',
categoryIds: ['vue3-essential']
},
{ title: 'Priority A: Essential for Vue.js 2.x', categoryIds: ['essential'] },
{ title: 'Priority B: Strongly Recommended', categoryIds: ['vue3-strongly-recommended', 'strongly-recommended'] },
{ title: 'Priority B: Strongly Recommended for Vue.js 3.x', categoryIds: ['vue3-strongly-recommended'] },
{ title: 'Priority B: Strongly Recommended for Vue.js 2.x', categoryIds: ['strongly-recommended'] },
{ title: 'Priority C: Recommended', categoryIds: ['vue3-recommended', 'recommended'] },
{ title: 'Priority C: Recommended for Vue.js 3.x', categoryIds: ['vue3-recommended'] },
{ title: 'Priority C: Recommended for Vue.js 2.x', categoryIds: ['recommended'] }
{
title: 'Priority B: Strongly Recommended',
categoryIds: ['vue3-strongly-recommended', 'strongly-recommended']
},
{
title: 'Priority B: Strongly Recommended for Vue.js 3.x',
categoryIds: ['vue3-strongly-recommended']
},
{
title: 'Priority B: Strongly Recommended for Vue.js 2.x',
categoryIds: ['strongly-recommended']
},
{
title: 'Priority C: Recommended',
categoryIds: ['vue3-recommended', 'recommended']
},
{
title: 'Priority C: Recommended for Vue.js 3.x',
categoryIds: ['vue3-recommended']
},
{
title: 'Priority C: Recommended for Vue.js 2.x',
categoryIds: ['recommended']
}
]

const categorizedRules = []
for (const { title, categoryIds } of sidebarCategories) {
const categoryRules = rules
.filter(rule => rule.meta.docs.categories && !rule.meta.deprecated)
.filter(rule => categoryIds
.every(categoryId => rule.meta.docs.categories.includes(categoryId))
.filter((rule) => rule.meta.docs.categories && !rule.meta.deprecated)
.filter((rule) =>
categoryIds.every((categoryId) =>
rule.meta.docs.categories.includes(categoryId)
)
)
const children = categoryRules
.filter(({ ruleId }) => {
const exists = categorizedRules.some(({ children }) => children.some(([, alreadyRuleId]) => alreadyRuleId === ruleId))
const exists = categorizedRules.some(({ children }) =>
children.some(([, alreadyRuleId]) => alreadyRuleId === ruleId)
)
return !exists
})
.map(({ ruleId, name }) => [`/rules/${name}`, ruleId])
Expand All @@ -51,19 +81,25 @@ if (uncategorizedRules.length > 0) {
extraCategories.push({
title: 'Uncategorized',
collapsable: false,
children: uncategorizedRules.map(({ ruleId, name }) => [`/rules/${name}`, ruleId])
children: uncategorizedRules.map(({ ruleId, name }) => [
`/rules/${name}`,
ruleId
])
})
}
if (deprecatedRules.length > 0) {
extraCategories.push({
title: 'Deprecated',
collapsable: false,
children: deprecatedRules.map(({ ruleId, name }) => [`/rules/${name}`, ruleId])
children: deprecatedRules.map(({ ruleId, name }) => [
`/rules/${name}`,
ruleId
])
})
}

module.exports = {
configureWebpack (_config, _isServer) {
configureWebpack(_config, _isServer) {
return {
resolve: {
alias: {
Expand All @@ -77,9 +113,7 @@ module.exports = {
title: 'eslint-plugin-vue',
description: 'Official ESLint plugin for Vue.js',
evergreen: true,
head: [
['link', { rel: 'icon', href: '/favicon.png' }]
],
head: [['link', { rel: 'icon', href: '/favicon.png' }]],

plugins: {
'@vuepress/pwa': {
Expand Down
42 changes: 22 additions & 20 deletions eslint-internal-rules/consistent-docs-description.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,7 @@

'use strict'

const ALLOWED_FIRST_WORDS = [
'enforce',
'require',
'disallow'
]
const ALLOWED_FIRST_WORDS = ['enforce', 'require', 'disallow']

// ------------------------------------------------------------------------------
// Helpers
Expand All @@ -22,7 +18,7 @@ const ALLOWED_FIRST_WORDS = [
* @param {ASTNode} node The ObjectExpression node.
* @returns {ASTNode} The Property node or null if not found.
*/
function getPropertyFromObject (property, node) {
function getPropertyFromObject(property, node) {
if (node && node.type === 'ObjectExpression') {
const properties = node.properties

Expand All @@ -42,15 +38,17 @@ function getPropertyFromObject (property, node) {
* @param {ASTNode} exportsNode ObjectExpression node that the rule exports.
* @returns {void}
*/
function checkMetaDocsDescription (context, exportsNode) {
function checkMetaDocsDescription(context, exportsNode) {
if (exportsNode.type !== 'ObjectExpression') {
// if the exported node is not the correct format, "internal-no-invalid-meta" will already report this.
return
}

const metaProperty = getPropertyFromObject('meta', exportsNode)
const metaDocs = metaProperty && getPropertyFromObject('docs', metaProperty.value)
const metaDocsDescription = metaDocs && getPropertyFromObject('description', metaDocs.value)
const metaDocs =
metaProperty && getPropertyFromObject('docs', metaProperty.value)
const metaDocsDescription =
metaDocs && getPropertyFromObject('description', metaDocs.value)

if (!metaDocsDescription) {
// if there is no `meta.docs.description` property, "internal-no-invalid-meta" will already report this.
Expand Down Expand Up @@ -88,7 +86,8 @@ function checkMetaDocsDescription (context, exportsNode) {
if (ALLOWED_FIRST_WORDS.indexOf(firstWord) === -1) {
context.report({
node: metaDocsDescription.value,
message: '`meta.docs.description` should start with one of the following words: {{ allowedWords }}. Started with "{{ firstWord }}" instead.',
message:
'`meta.docs.description` should start with one of the following words: {{ allowedWords }}. Started with "{{ firstWord }}" instead.',
data: {
allowedWords: ALLOWED_FIRST_WORDS.join(', '),
firstWord
Expand All @@ -100,7 +99,7 @@ function checkMetaDocsDescription (context, exportsNode) {
context.report({
node: metaDocsDescription.value,
message: '`meta.docs.description` should not end with `.`.',
fix (fixer) {
fix(fixer) {
const pos = metaDocsDescription.range[1] - 2
return fixer.removeRange([pos, pos + 1])
}
Expand All @@ -115,22 +114,25 @@ function checkMetaDocsDescription (context, exportsNode) {
module.exports = {
meta: {
docs: {
description: 'enforce correct conventions of `meta.docs.description` property in core rules',
description:
'enforce correct conventions of `meta.docs.description` property in core rules',
categories: ['Internal']
},
fixable: 'code',
schema: []
},

create (context) {
create(context) {
return {
AssignmentExpression (node) {
if (node.left &&
node.right &&
node.left.type === 'MemberExpression' &&
node.left.object.name === 'module' &&
node.left.property.name === 'exports' &&
node.right.type === 'ObjectExpression') {
AssignmentExpression(node) {
if (
node.left &&
node.right &&
node.left.type === 'MemberExpression' &&
node.left.object.name === 'module' &&
node.left.property.name === 'exports' &&
node.right.type === 'ObjectExpression'
) {
checkMetaDocsDescription(context, node.right)
}
}
Expand Down
Loading