forked from vuetifyjs/vuetify
-
Notifications
You must be signed in to change notification settings - Fork 0
/
eslint-local-rules.js
123 lines (115 loc) Β· 3.94 KB
/
eslint-local-rules.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
'use strict'
const path = require('path')
module.exports = {
'no-render-string-reference': {
create: require('./scripts/no-render-string-reference'),
},
'jsx-condition-key': {
create (context) {
return {
JSXExpressionContainer (node) {
if (!['LogicalExpression', 'ConditionalExpression'].includes(node.expression.type)) return
if (
node.parent.type !== 'JSXElement' ||
node.parent.children.slice(node.parent.children.indexOf(node))
.every(child => child === node || child.type === 'JSXText')
) return
const test = node.expression.type === 'LogicalExpression'
? node.expression.left
: node.expression.test
if (
(
test.type === 'ChainExpression' &&
test.expression.type === 'CallExpression' &&
test.expression.callee.type === 'MemberExpression' &&
test.expression.callee.object.name === 'slots'
) || (
test.type === 'MemberExpression' &&
test.object.name === 'slots'
) || (
test.type === 'CallExpression' &&
test.callee.type === 'MemberExpression' &&
test.callee.object.name === 'slots'
)
) return
const tags = node.expression.type === 'LogicalExpression'
? [node.expression.right]
: [node.expression.consequent, node.expression.alternate]
tags.forEach(tag => {
if (tag.type !== 'JSXElement') return
const key = tag.openingElement.attributes.find(attr => attr.type === 'JSXAttribute' && attr.name.name === 'key')
if (!key) {
context.report({
loc: {
start: tag.openingElement.loc.start,
end: tag.openingElement.name.loc.end,
},
message: 'Conditional JSX elements must have a key attribute',
})
}
})
},
}
},
},
'jest-global-imports': {
meta: {
fixable: 'code',
},
create (context) {
return {
Program (node) {
if (node.comments.some(comment => comment.value.trim() === 'eslint-disable')) return
const jestGlobalsImport = node.body.find(node => (
node.type === 'ImportDeclaration' &&
node.source.value === '@jest/globals'
))
if (!jestGlobalsImport) {
context.report({
loc: {
start: { line: 0, column: 0 },
end: { line: 0, column: 0 },
},
message: 'Missing @jest/globals import',
fix (fixer) {
const firstImport = node.body.find(node => node.type === 'ImportDeclaration')
return fixer.insertTextBefore(firstImport || node, `import { describe, expect, it } from '@jest/globals'\n`)
},
})
}
},
}
},
},
'cypress-types-reference': {
meta: {
fixable: 'code',
},
create (context) {
return {
Program (node) {
const referencePath = path.relative(
path.dirname(context.getFilename()),
path.resolve(__dirname, 'packages/vuetify/types/cypress')
)
const cypressTypesReference = node.comments.find(comment => (
comment.type === 'Line' &&
comment.value.trim() === `/ <reference types="${referencePath}" />`
))
if (!cypressTypesReference) {
context.report({
loc: {
start: { line: 0, column: 0 },
end: { line: 0, column: 0 },
},
message: 'Missing Cypress types reference',
fix (fixer) {
return fixer.insertTextAfterRange([0, 0], `/// <reference types="${referencePath}" />\n`)
},
})
}
},
}
},
},
}