mirror of
https://github.com/vuejs/vue-cli.git
synced 2026-05-11 22:39:13 -05:00
feat: rework eslint configuration tab to display all rules (#2008)
* feat(cli-plugin-eslint): Add configuration tab * chore(vue-cli-plugin-eslint): Add missing translations, extract UI descriptors * fix(vue-cli-plugin-eslint): Import rules from CWD * feat(vue-cli-plugin-eslint): Add uncategorized category, add tests * test(vue-cli-plugin-eslint): Add missing tests * fix(vue-cli-plugin-eslint): Escape html from rules' descriptions * chore(vue-cli): Add --ci flag in tests * chore(vue-cli-plugin-eslint): Remove snapshot
This commit is contained in:
committed by
Guillaume Chau
parent
495c25a019
commit
7953d8300f
@@ -0,0 +1,155 @@
|
||||
const configDescriptor = require('../ui/configDescriptor')
|
||||
const { getEslintConfigName, getDefaultValue, getEslintPrompts } = configDescriptor
|
||||
|
||||
describe('getEslintConfigName', () => {
|
||||
describe('for "extend" of string type', () => {
|
||||
it('returns null if it doesn\'t extend vue plugin config', () => {
|
||||
expect(getEslintConfigName({
|
||||
extends: 'eslint:recommended'
|
||||
})).toBe(null)
|
||||
})
|
||||
|
||||
it('returns vue config used', () => {
|
||||
expect(getEslintConfigName({
|
||||
extends: 'plugin:vue/recommended'
|
||||
})).toBe('plugin:vue/recommended')
|
||||
})
|
||||
})
|
||||
|
||||
describe('for "extend" of array type', () => {
|
||||
it('returns null if it doesn\'t extend vue plugin config', () => {
|
||||
expect(getEslintConfigName({
|
||||
extends: ['eslint:recommended', 'standard']
|
||||
})).toBe(null)
|
||||
})
|
||||
|
||||
it('returns vue config used', () => {
|
||||
expect(getEslintConfigName({
|
||||
extends: ['eslint:recommended', 'plugin:vue/recommended']
|
||||
})).toBe('plugin:vue/recommended')
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('getDefaultValue', () => {
|
||||
const getResult = (config, ruleCategory) => {
|
||||
const rule = {
|
||||
meta: {
|
||||
docs: {
|
||||
category: ruleCategory
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const data = {
|
||||
eslint: {
|
||||
extends: config
|
||||
}
|
||||
}
|
||||
|
||||
return getDefaultValue(rule, data)
|
||||
}
|
||||
|
||||
it('returns "ERROR" value if the rule belongs to the selected configuration', () => {
|
||||
expect(getResult('plugin:vue/base', 'base')).toBe('error')
|
||||
expect(getResult('plugin:vue/essential', 'base')).toBe('error')
|
||||
expect(getResult('plugin:vue/essential', 'essential')).toBe('error')
|
||||
expect(getResult('plugin:vue/strongly-recommended', 'base')).toBe('error')
|
||||
expect(getResult('plugin:vue/strongly-recommended', 'essential')).toBe('error')
|
||||
expect(getResult('plugin:vue/strongly-recommended', 'strongly-recommended')).toBe('error')
|
||||
expect(getResult('plugin:vue/recommended', 'base')).toBe('error')
|
||||
expect(getResult('plugin:vue/recommended', 'essential')).toBe('error')
|
||||
expect(getResult('plugin:vue/recommended', 'strongly-recommended')).toBe('error')
|
||||
expect(getResult('plugin:vue/recommended', 'recommended')).toBe('error')
|
||||
})
|
||||
|
||||
it('returns "OFF" value if the rule doesn\'t belong to the selected configuration', () => {
|
||||
expect(getResult('plugin:vue/base', 'essential')).toBe('off')
|
||||
expect(getResult('plugin:vue/base', 'strongly-recommended')).toBe('off')
|
||||
expect(getResult('plugin:vue/base', 'recommended')).toBe('off')
|
||||
expect(getResult('plugin:vue/essential', 'strongly-recommended')).toBe('off')
|
||||
expect(getResult('plugin:vue/essential', 'recommended')).toBe('off')
|
||||
expect(getResult('plugin:vue/strongly-recommended', 'recommended')).toBe('off')
|
||||
expect(getResult('plugin:vue/base', undefined)).toBe('off')
|
||||
expect(getResult('plugin:vue/essential', undefined)).toBe('off')
|
||||
expect(getResult('plugin:vue/strongly-recommended', undefined)).toBe('off')
|
||||
expect(getResult('plugin:vue/recommended', undefined)).toBe('off')
|
||||
})
|
||||
})
|
||||
|
||||
describe('getEslintPrompts', () => {
|
||||
// project configuration
|
||||
const data = {
|
||||
eslint: {
|
||||
extends: 'plugin:vue/recommended',
|
||||
rules: {
|
||||
'vue/lorem': ['error', ['asd']], // custom setting
|
||||
'vue/ipsum': 'warning'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// all rules
|
||||
const rules = {
|
||||
'lorem': {
|
||||
meta: {
|
||||
docs: {
|
||||
category: undefined,
|
||||
description: 'Lorem description',
|
||||
url: 'http://test.com/lorem'
|
||||
}
|
||||
}
|
||||
},
|
||||
'ipsum': {
|
||||
meta: {
|
||||
docs: {
|
||||
category: 'recommended',
|
||||
description: 'Ipsum description',
|
||||
url: 'http://test.com/ipsum'
|
||||
}
|
||||
}
|
||||
},
|
||||
'dolor': {
|
||||
meta: {
|
||||
docs: {
|
||||
category: 'base',
|
||||
description: 'Dolor description',
|
||||
url: 'http://test.com/dolor'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const prompts = getEslintPrompts(data, rules)
|
||||
|
||||
it('creates an array with three settings', () => {
|
||||
expect(prompts).toHaveLength(3)
|
||||
})
|
||||
|
||||
it('creates an array which order matches eslint categories', () => {
|
||||
expect(prompts[0].name).toBe('vue/dolor')
|
||||
expect(prompts[1].name).toBe('vue/ipsum')
|
||||
expect(prompts[2].name).toBe('vue/lorem')
|
||||
})
|
||||
|
||||
it('doesn\'t set value on prompt item, if the rule wasn\'t set in project\'s eslint config', () => {
|
||||
expect(prompts[0].value).toBe(undefined)
|
||||
})
|
||||
|
||||
it('sets value on prompt item, if the rule was set in project\'s eslint config', () => {
|
||||
expect(prompts[1].value).toBe('"warning"')
|
||||
expect(prompts[2].value).toBe('["error",["asd"]]')
|
||||
})
|
||||
|
||||
it('generates an extra choice for rules that have a custom setting', () => {
|
||||
expect(prompts[0].choices).toHaveLength(3)
|
||||
expect(prompts[1].choices).toHaveLength(3)
|
||||
expect(prompts[2].choices).toHaveLength(4)
|
||||
})
|
||||
|
||||
it('sets a default value to "ERROR" for rule that belong to the choosen config', () => {
|
||||
expect(prompts[0].default).toBe('"error"')
|
||||
expect(prompts[1].default).toBe('"error"')
|
||||
expect(prompts[2].default).toBe('"off"')
|
||||
})
|
||||
})
|
||||
@@ -1,264 +0,0 @@
|
||||
module.exports = api => {
|
||||
const CONFIG = 'org.vue.eslintrc'
|
||||
|
||||
// Config file
|
||||
api.describeConfig({
|
||||
id: CONFIG,
|
||||
name: 'ESLint configuration',
|
||||
description: 'org.vue.eslint.config.eslint.description',
|
||||
link: 'https://github.com/vuejs/eslint-plugin-vue',
|
||||
files: {
|
||||
eslint: {
|
||||
js: ['.eslintrc.js'],
|
||||
json: ['.eslintrc', '.eslintrc.json'],
|
||||
yaml: ['.eslintrc.yaml', '.eslintrc.yml'],
|
||||
package: 'eslintConfig'
|
||||
},
|
||||
vue: {
|
||||
js: ['vue.config.js']
|
||||
}
|
||||
},
|
||||
onRead: ({ data }) => ({
|
||||
tabs: [
|
||||
{
|
||||
id: 'vue',
|
||||
label: 'org.vue.eslint.config.eslint.vue.label',
|
||||
prompts: [
|
||||
{
|
||||
name: 'vue/attribute-hyphenation',
|
||||
type: 'list',
|
||||
message: 'Attribute hyphenation',
|
||||
group: 'org.vue.eslint.config.eslint.groups.strongly-recommended',
|
||||
description: 'Enforce attribute naming style in template (`my-prop` or `myProp`)',
|
||||
link: 'https://github.com/vuejs/eslint-plugin-vue/blob/master/docs/rules/attribute-hyphenation.md',
|
||||
default: JSON.stringify('off'),
|
||||
choices: [
|
||||
{
|
||||
name: 'Off',
|
||||
value: JSON.stringify('off')
|
||||
},
|
||||
{
|
||||
name: 'Never',
|
||||
value: JSON.stringify(['error', 'never'])
|
||||
},
|
||||
{
|
||||
name: 'Always',
|
||||
value: JSON.stringify(['error', 'always'])
|
||||
}
|
||||
],
|
||||
value: data.eslint && data.eslint.rules && JSON.stringify(data.eslint.rules['vue/attribute-hyphenation'])
|
||||
},
|
||||
{
|
||||
name: 'vue/html-end-tags',
|
||||
type: 'confirm',
|
||||
message: 'Template end tags style',
|
||||
group: 'org.vue.eslint.config.eslint.groups.strongly-recommended',
|
||||
description: 'End tag on Void elements, end tags and self-closing opening tags',
|
||||
link: 'https://github.com/vuejs/eslint-plugin-vue/blob/master/docs/rules/html-end-tags.md',
|
||||
default: false,
|
||||
value: data.eslint && data.eslint.rules && data.eslint.rules['vue/html-end-tags'] === 'error',
|
||||
filter: input => JSON.stringify(input ? 'error' : 'off'),
|
||||
transformer: input => input === JSON.stringify('error')
|
||||
},
|
||||
{
|
||||
name: 'vue/html-indent',
|
||||
type: 'list',
|
||||
message: 'Template indentation',
|
||||
group: 'org.vue.eslint.config.eslint.groups.strongly-recommended',
|
||||
description: 'Enforce indentation in template',
|
||||
link: 'https://github.com/vuejs/eslint-plugin-vue/blob/master/docs/rules/html-indent.md',
|
||||
default: JSON.stringify('off'),
|
||||
choices: [
|
||||
{
|
||||
name: 'Off',
|
||||
value: JSON.stringify('off')
|
||||
},
|
||||
{
|
||||
name: 'Tabs',
|
||||
value: JSON.stringify(['error', 'tab'])
|
||||
},
|
||||
{
|
||||
name: '2 spaces',
|
||||
value: JSON.stringify(['error', 2])
|
||||
},
|
||||
{
|
||||
name: '4 spaces',
|
||||
value: JSON.stringify(['error', 4])
|
||||
},
|
||||
{
|
||||
name: '8 spaces',
|
||||
value: JSON.stringify(['error', 8])
|
||||
}
|
||||
],
|
||||
value: data.eslint && data.eslint.rules && JSON.stringify(data.eslint.rules['vue/html-indent'])
|
||||
},
|
||||
{
|
||||
name: 'vue/html-self-closing',
|
||||
type: 'confirm',
|
||||
message: 'Template tag self-closing style',
|
||||
group: 'org.vue.eslint.config.eslint.groups.strongly-recommended',
|
||||
description: 'Self-close any component or non-Void element tags',
|
||||
link: 'https://github.com/vuejs/eslint-plugin-vue/blob/master/docs/rules/html-self-closing.md',
|
||||
default: false,
|
||||
value: data.eslint && data.eslint.rules && data.eslint.rules['vue/html-self-closing'] === 'error',
|
||||
filter: input => JSON.stringify(input ? 'error' : 'off'),
|
||||
transformer: input => input === JSON.stringify('error')
|
||||
},
|
||||
{
|
||||
name: 'vue/require-default-prop',
|
||||
type: 'confirm',
|
||||
message: 'Require default in required props',
|
||||
group: 'org.vue.eslint.config.eslint.groups.strongly-recommended',
|
||||
description: 'This rule requires default value to be set for each props that are not marked as `required`',
|
||||
link: 'https://github.com/vuejs/eslint-plugin-vue/blob/master/docs/rules/require-default-prop.md',
|
||||
default: false,
|
||||
value: data.eslint && data.eslint.rules && data.eslint.rules['vue/require-default-prop'] === 'error',
|
||||
filter: input => JSON.stringify(input ? 'error' : 'off'),
|
||||
transformer: input => input === JSON.stringify('error')
|
||||
},
|
||||
{
|
||||
name: 'vue/require-prop-types',
|
||||
type: 'confirm',
|
||||
message: 'Require types for props',
|
||||
group: 'org.vue.eslint.config.eslint.groups.strongly-recommended',
|
||||
description: 'In committed code, prop definitions should always be as detailed as possible, specifying at least type(s)',
|
||||
link: 'https://github.com/vuejs/eslint-plugin-vue/blob/master/docs/rules/require-prop-types.md',
|
||||
default: false,
|
||||
value: data.eslint && data.eslint.rules && data.eslint.rules['vue/require-prop-types'] === 'error',
|
||||
filter: input => JSON.stringify(input ? 'error' : 'off'),
|
||||
transformer: input => input === JSON.stringify('error')
|
||||
},
|
||||
{
|
||||
name: 'vue/attributes-order',
|
||||
type: 'confirm',
|
||||
message: 'Attribute order',
|
||||
group: 'org.vue.eslint.config.eslint.groups.recommended',
|
||||
description: 'This rule aims to enforce ordering of component attributes (the default order is specified in the Vue style guide)',
|
||||
link: 'https://github.com/vuejs/eslint-plugin-vue/blob/master/docs/rules/attributes-order.md',
|
||||
default: false,
|
||||
value: data.eslint && data.eslint.rules && data.eslint.rules['vue/attributes-order'] === 'error',
|
||||
filter: input => JSON.stringify(input ? 'error' : 'off'),
|
||||
transformer: input => input === JSON.stringify('error')
|
||||
},
|
||||
{
|
||||
name: 'vue/html-quotes',
|
||||
type: 'list',
|
||||
message: 'Attribute quote style',
|
||||
group: 'org.vue.eslint.config.eslint.groups.recommended',
|
||||
description: 'Enforce style of the attribute quotes in templates',
|
||||
link: 'https://github.com/vuejs/eslint-plugin-vue/blob/master/docs/rules/html-quotes.md',
|
||||
default: JSON.stringify('off'),
|
||||
choices: [
|
||||
{
|
||||
name: 'Off',
|
||||
value: JSON.stringify('off')
|
||||
},
|
||||
{
|
||||
name: 'Double quotes',
|
||||
value: JSON.stringify(['error', 'double'])
|
||||
},
|
||||
{
|
||||
name: 'Single quotes',
|
||||
value: JSON.stringify(['error', 'single'])
|
||||
}
|
||||
],
|
||||
value: data.eslint && data.eslint.rules && JSON.stringify(data.eslint.rules['vue/html-quotes'])
|
||||
},
|
||||
{
|
||||
name: 'vue/order-in-components',
|
||||
type: 'confirm',
|
||||
message: 'Component options order',
|
||||
group: 'org.vue.eslint.config.eslint.groups.recommended',
|
||||
description: 'This rule aims to enforce ordering of component options (the default order is specified in the Vue style guide)',
|
||||
link: 'https://github.com/vuejs/eslint-plugin-vue/blob/master/docs/rules/order-in-components.md',
|
||||
default: false,
|
||||
value: data.eslint && data.eslint.rules && data.eslint.rules['vue/order-in-components'] === 'error',
|
||||
filter: input => JSON.stringify(input ? 'error' : 'off'),
|
||||
transformer: input => input === JSON.stringify('error')
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
id: 'extra',
|
||||
label: 'org.vue.eslint.config.eslint.extra.label',
|
||||
prompts: [
|
||||
{
|
||||
name: 'lintOnSave',
|
||||
type: 'confirm',
|
||||
message: 'org.vue.eslint.config.eslint.extra.lintOnSave.message',
|
||||
description: 'org.vue.eslint.config.eslint.extra.lintOnSave.description',
|
||||
link: 'https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-eslint#configuration',
|
||||
default: true,
|
||||
value: data.vue && data.vue.lintOnSave
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}),
|
||||
onWrite: async ({ api, prompts }) => {
|
||||
const eslintData = {}
|
||||
const vueData = {}
|
||||
for (const prompt of prompts) {
|
||||
// eslintrc
|
||||
if (prompt.id.indexOf('vue/') === 0) {
|
||||
eslintData[`rules.${prompt.id}`] = await api.getAnswer(prompt.id, JSON.parse)
|
||||
} else {
|
||||
// vue.config.js
|
||||
vueData[prompt.id] = await api.getAnswer(prompt.id)
|
||||
}
|
||||
}
|
||||
api.setData('eslint', eslintData)
|
||||
api.setData('vue', vueData)
|
||||
}
|
||||
})
|
||||
|
||||
// Tasks
|
||||
api.describeTask({
|
||||
match: /vue-cli-service lint/,
|
||||
description: 'org.vue.eslint.tasks.lint.description',
|
||||
link: 'https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-eslint#injected-commands',
|
||||
prompts: [
|
||||
{
|
||||
name: 'noFix',
|
||||
type: 'confirm',
|
||||
default: false,
|
||||
description: 'org.vue.eslint.tasks.lint.noFix'
|
||||
}
|
||||
],
|
||||
onBeforeRun: ({ answers, args }) => {
|
||||
if (answers.noFix) args.push('--no-fix')
|
||||
}
|
||||
})
|
||||
|
||||
const OPEN_ESLINTRC = 'org.vue.eslint.open-eslintrc'
|
||||
|
||||
api.onViewOpen(({ view }) => {
|
||||
if (view.id !== 'vue-project-configurations') {
|
||||
removeSuggestions()
|
||||
}
|
||||
})
|
||||
|
||||
api.onConfigRead(({ config }) => {
|
||||
if (config.id === CONFIG) {
|
||||
api.addSuggestion({
|
||||
id: OPEN_ESLINTRC,
|
||||
type: 'action',
|
||||
label: 'org.vue.eslint.suggestions.open-eslintrc.label',
|
||||
handler () {
|
||||
const file = config.foundFiles.eslint.path
|
||||
const launch = require('launch-editor')
|
||||
launch(file)
|
||||
return {
|
||||
keep: true
|
||||
}
|
||||
}
|
||||
})
|
||||
} else {
|
||||
removeSuggestions()
|
||||
}
|
||||
})
|
||||
|
||||
function removeSuggestions () {
|
||||
[OPEN_ESLINTRC].forEach(id => api.removeSuggestion(id))
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,190 @@
|
||||
const CONFIG = 'org.vue.eslintrc'
|
||||
|
||||
const CATEGORIES = [
|
||||
'base',
|
||||
'essential',
|
||||
'strongly-recommended',
|
||||
'recommended',
|
||||
'uncategorized'
|
||||
]
|
||||
|
||||
const DEFAULT_CATEGORY = 'essential'
|
||||
const RULE_SETTING_OFF = 'off'
|
||||
const RULE_SETTING_ERROR = 'error'
|
||||
const RULE_SETTING_WARNING = 'warning'
|
||||
const RULE_SETTINGS = [RULE_SETTING_OFF, RULE_SETTING_ERROR, RULE_SETTING_WARNING]
|
||||
|
||||
const defaultChoices = [
|
||||
{
|
||||
name: 'org.vue.eslint.config.eslint.setting.off',
|
||||
value: JSON.stringify(RULE_SETTING_OFF)
|
||||
},
|
||||
{
|
||||
name: 'org.vue.eslint.config.eslint.setting.error',
|
||||
value: JSON.stringify(RULE_SETTING_ERROR)
|
||||
},
|
||||
{
|
||||
name: 'org.vue.eslint.config.eslint.setting.warning',
|
||||
value: JSON.stringify(RULE_SETTING_WARNING)
|
||||
}
|
||||
]
|
||||
|
||||
function escapeHTML (text) {
|
||||
return text.replace(/</g, '<').replace(/>/g, '>')
|
||||
}
|
||||
|
||||
function getEslintConfigName (eslint) {
|
||||
let config = eslint.extends
|
||||
|
||||
if (eslint.extends instanceof Array) {
|
||||
config = eslint.extends.find(configName => configName.startsWith('plugin:vue/'))
|
||||
}
|
||||
|
||||
return config && config.startsWith('plugin:vue/') ? config : null
|
||||
}
|
||||
|
||||
// Sets default value regarding selected global config
|
||||
function getDefaultValue (rule, data) {
|
||||
const { category: ruleCategory } = rule.meta.docs
|
||||
const currentCategory = getEslintConfigName(data.eslint)
|
||||
|
||||
if (!currentCategory || ruleCategory === undefined) return RULE_SETTING_OFF
|
||||
|
||||
return CATEGORIES.indexOf(ruleCategory) <= CATEGORIES.indexOf(currentCategory.split('/')[1])
|
||||
? RULE_SETTING_ERROR
|
||||
: RULE_SETTING_OFF
|
||||
}
|
||||
|
||||
function getEslintPrompts (data, rules) {
|
||||
const allRules = Object.keys(rules)
|
||||
.map(ruleKey => ({
|
||||
...rules[ruleKey],
|
||||
name: `vue/${ruleKey}`
|
||||
}))
|
||||
|
||||
return CATEGORIES
|
||||
.map(category =>
|
||||
allRules.filter(rule =>
|
||||
rule.meta.docs.category === category || (
|
||||
category === 'uncategorized' &&
|
||||
rule.meta.docs.category === undefined
|
||||
)
|
||||
)
|
||||
)
|
||||
.reduce((acc, rulesArr) => [...acc, ...rulesArr], [])
|
||||
.map(rule => {
|
||||
const value = data.eslint &&
|
||||
data.eslint.rules &&
|
||||
data.eslint.rules[rule.name]
|
||||
|
||||
return {
|
||||
name: rule.name,
|
||||
type: 'list',
|
||||
message: rule.name,
|
||||
group: `org.vue.eslint.config.eslint.groups.${rule.meta.docs.category || 'uncategorized'}`,
|
||||
description: escapeHTML(rule.meta.docs.description),
|
||||
link: rule.meta.docs.url,
|
||||
default: JSON.stringify(getDefaultValue(rule, data)),
|
||||
value: JSON.stringify(value),
|
||||
choices: !value || RULE_SETTINGS.indexOf(value) > -1
|
||||
? defaultChoices
|
||||
: [...defaultChoices, {
|
||||
name: 'org.vue.eslint.config.eslint.setting.custom',
|
||||
value: JSON.stringify(value)
|
||||
}]
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
function onRead ({ data, cwd }) {
|
||||
const rules = require(`${cwd}/node_modules/eslint-plugin-vue`).rules
|
||||
|
||||
return {
|
||||
tabs: [
|
||||
{
|
||||
id: 'general',
|
||||
label: 'org.vue.eslint.config.eslint.general.label',
|
||||
prompts: [
|
||||
{
|
||||
name: 'lintOnSave',
|
||||
type: 'confirm',
|
||||
message: 'org.vue.eslint.config.eslint.general.lintOnSave.message',
|
||||
description: 'org.vue.eslint.config.eslint.general.lintOnSave.description',
|
||||
link: 'https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-eslint#configuration',
|
||||
default: true,
|
||||
value: data.vue && data.vue.lintOnSave
|
||||
},
|
||||
{
|
||||
name: 'config',
|
||||
type: 'list',
|
||||
message: 'org.vue.eslint.config.eslint.general.config.message',
|
||||
description: 'org.vue.eslint.config.eslint.general.config.description',
|
||||
link: 'https://github.com/vuejs/eslint-plugin-vue',
|
||||
default: `plugin:vue/${DEFAULT_CATEGORY}`,
|
||||
choices: CATEGORIES.filter(category => category !== 'uncategorized').map(category => ({
|
||||
name: `org.vue.eslint.config.eslint.groups.${category}`,
|
||||
value: `plugin:vue/${category}`
|
||||
})),
|
||||
value: getEslintConfigName(data.eslint)
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
id: 'rules',
|
||||
label: 'org.vue.eslint.config.eslint.rules.label',
|
||||
prompts: getEslintPrompts(data, rules)
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
async function onWrite ({ data, api, prompts }) {
|
||||
const eslintData = { ...data.eslint }
|
||||
const vueData = {}
|
||||
for (const prompt of prompts) {
|
||||
// eslintrc
|
||||
if (prompt.id === 'config') {
|
||||
if (eslintData.extends instanceof Array) {
|
||||
const vueEslintConfig = eslintData.extends.find(config => config.indexOf('plugin:vue/') === 0)
|
||||
const index = eslintData.extends.indexOf(vueEslintConfig)
|
||||
eslintData.extends[index] = JSON.parse(prompt.value)
|
||||
} else {
|
||||
eslintData.extends = JSON.parse(prompt.value)
|
||||
}
|
||||
} else if (prompt.id.indexOf('vue/') === 0) {
|
||||
eslintData[`rules.${prompt.id}`] = await api.getAnswer(prompt.id, JSON.parse)
|
||||
} else {
|
||||
// vue.config.js
|
||||
vueData[prompt.id] = await api.getAnswer(prompt.id)
|
||||
}
|
||||
}
|
||||
api.setData('eslint', eslintData)
|
||||
api.setData('vue', vueData)
|
||||
}
|
||||
|
||||
const config = {
|
||||
id: CONFIG,
|
||||
name: 'ESLint configuration',
|
||||
description: 'org.vue.eslint.config.eslint.description',
|
||||
link: 'https://github.com/vuejs/eslint-plugin-vue',
|
||||
files: {
|
||||
eslint: {
|
||||
js: ['.eslintrc.js'],
|
||||
json: ['.eslintrc', '.eslintrc.json'],
|
||||
yaml: ['.eslintrc.yaml', '.eslintrc.yml'],
|
||||
package: 'eslintConfig'
|
||||
},
|
||||
vue: {
|
||||
js: ['vue.config.js']
|
||||
}
|
||||
},
|
||||
onRead,
|
||||
onWrite
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
config,
|
||||
getEslintConfigName,
|
||||
getDefaultValue,
|
||||
getEslintPrompts
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
const configDescriptor = require('./configDescriptor')
|
||||
const taskDescriptor = require('./taskDescriptor')
|
||||
|
||||
const CONFIG = 'org.vue.eslintrc'
|
||||
const OPEN_ESLINTRC = 'org.vue.eslint.open-eslintrc'
|
||||
|
||||
module.exports = api => {
|
||||
api.describeConfig(configDescriptor.config)
|
||||
api.describeTask(taskDescriptor.task)
|
||||
|
||||
api.onViewOpen(({ view }) => {
|
||||
if (view.id !== 'vue-project-configurations') {
|
||||
removeSuggestions()
|
||||
}
|
||||
})
|
||||
|
||||
api.onConfigRead(({ config }) => {
|
||||
if (config.id === CONFIG) {
|
||||
api.addSuggestion({
|
||||
id: OPEN_ESLINTRC,
|
||||
type: 'action',
|
||||
label: 'org.vue.eslint.suggestions.open-eslintrc.label',
|
||||
handler () {
|
||||
const file = config.foundFiles.eslint.path
|
||||
const launch = require('launch-editor')
|
||||
launch(file)
|
||||
return {
|
||||
keep: true
|
||||
}
|
||||
}
|
||||
})
|
||||
} else {
|
||||
removeSuggestions()
|
||||
}
|
||||
})
|
||||
|
||||
function removeSuggestions () {
|
||||
[OPEN_ESLINTRC].forEach(id => api.removeSuggestion(id))
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
const task = {
|
||||
match: /vue-cli-service lint/,
|
||||
description: 'org.vue.eslint.tasks.lint.description',
|
||||
link: 'https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-eslint#injected-commands',
|
||||
prompts: [
|
||||
{
|
||||
name: 'noFix',
|
||||
type: 'confirm',
|
||||
default: false,
|
||||
description: 'org.vue.eslint.tasks.lint.noFix'
|
||||
}
|
||||
],
|
||||
onBeforeRun: ({ answers, args }) => {
|
||||
if (answers.noFix) args.push('--no-fix')
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
task
|
||||
}
|
||||
@@ -580,18 +580,32 @@
|
||||
"eslint": {
|
||||
"description": "Error checking & Code quality",
|
||||
"groups": {
|
||||
"base": "Base",
|
||||
"essential": "Essential",
|
||||
"strongly-recommended": "Strongly recommended",
|
||||
"recommended": "Recommended"
|
||||
"recommended": "Recommended",
|
||||
"use-with-caution": "Use with caution",
|
||||
"uncategorized": "Uncategorized"
|
||||
},
|
||||
"vue": {
|
||||
"label": "Vue"
|
||||
"setting": {
|
||||
"off": "Off",
|
||||
"error": "Error",
|
||||
"warning": "Warning",
|
||||
"custom": "Custom"
|
||||
},
|
||||
"extra": {
|
||||
"label": "Extra",
|
||||
"general": {
|
||||
"label": "General",
|
||||
"lintOnSave": {
|
||||
"message": "Lint on save",
|
||||
"description": "Automatically lint source files when saved"
|
||||
},
|
||||
"config": {
|
||||
"message": "Select config",
|
||||
"description": "Select pre-defined configuration"
|
||||
}
|
||||
},
|
||||
"rules": {
|
||||
"label": "Rules"
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -686,4 +700,4 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user