-
-
Notifications
You must be signed in to change notification settings - Fork 681
/
Copy pathno-static-inline-styles.js
138 lines (131 loc) · 4.21 KB
/
no-static-inline-styles.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
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
/**
* @author Yosuke Ota
* See LICENSE file in root directory for full license.
*/
'use strict'
const utils = require('../utils')
module.exports = {
meta: {
type: 'suggestion',
docs: {
description: 'disallow static inline `style` attributes',
category: undefined,
url: 'https://eslint.vuejs.org/rules/no-static-inline-styles.html'
},
fixable: null,
schema: [
{
type: 'object',
properties: {
allowBinding: {
type: 'boolean'
}
},
additionalProperties: false
}
],
messages: {
forbiddenStaticInlineStyle: 'Static inline `style` are forbidden.',
forbiddenStyleAttr: '`style` attributes are forbidden.'
}
},
create (context) {
/**
* Checks whether if the given property node is a static value.
* @param {AssignmentProperty} prop property node to check
* @returns {boolean} `true` if the given property node is a static value.
*/
function isStaticValue (prop) {
return (
!prop.computed &&
prop.value.type === 'Literal' &&
(prop.key.type === 'Identifier' || prop.key.type === 'Literal')
)
}
/**
* Gets the static properties of a given expression node.
* - If `SpreadElement` or computed property exists, it gets only the static properties before it.
* `:style="{ color: 'red', display: 'flex', ...spread, width: '16px' }"`
* ^^^^^^^^^^^^ ^^^^^^^^^^^^^^^
* - If non-static object exists, it gets only the static properties up to that object.
* `:style="[ { color: 'red' }, { display: 'flex', color, width: '16px' }, { height: '16px' } ]"`
* ^^^^^^^^^^^^ ^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^
* - If all properties are static properties, it returns one root node.
* `:style="[ { color: 'red' }, { display: 'flex', width: '16px' } ]"`
* ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
* @param {VAttribute} node `:style` node to check
* @returns {AssignmentProperty[] | [VAttribute]} the static properties.
*/
function getReportNodes (node) {
const { value } = node
if (!value) {
return []
}
const { expression } = value
if (!expression) {
return []
}
let elements
if (expression.type === 'ObjectExpression') {
elements = [expression]
} else if (expression.type === 'ArrayExpression') {
elements = expression.elements
} else {
return []
}
const staticProperties = []
for (const element of elements) {
if (!element) {
continue
}
if (element.type !== 'ObjectExpression') {
return staticProperties
}
let isAllStatic = true
for (const prop of element.properties) {
if (prop.type === 'SpreadElement' || prop.computed) {
// If `SpreadElement` or computed property exists, it gets only the static properties before it.
return staticProperties
}
if (isStaticValue(prop)) {
staticProperties.push(prop)
} else {
isAllStatic = false
}
}
if (!isAllStatic) {
// If non-static object exists, it gets only the static properties up to that object.
return staticProperties
}
}
// If all properties are static properties, it returns one root node.
return [node]
}
/**
* Reports if the value is static.
* @param {VAttribute} node `:style` node to check
*/
function verifyVBindStyle (node) {
for (const n of getReportNodes(node)) {
context.report({
node: n,
messageId: 'forbiddenStaticInlineStyle'
})
}
}
const visitor = {
"VAttribute[directive=false][key.name='style']" (node) {
context.report({
node,
messageId: 'forbiddenStyleAttr'
})
}
}
if (!context.options[0] || !context.options[0].allowBinding) {
visitor[
"VAttribute[directive=true][key.name.name='bind'][key.argument.name='style']"
] = verifyVBindStyle
}
return utils.defineTemplateBodyVisitor(context, visitor)
}
}