-
Notifications
You must be signed in to change notification settings - Fork 2
/
index.js
122 lines (105 loc) · 3.04 KB
/
index.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
const {findVariable, variablesInScope} = require('eslint-plugin-react/lib/util/variable')
const htmlTags = require('html-tags')
const svgTags = require('svg-tags')
const standardTags = new Set(htmlTags.concat(svgTags))
/**
* Check the factory function is imported if JSX is being used
*/
const factoryInScopeRule = context => {
const config = context.options[0] || {}
const name = config.pragma || 'JSX'
return {
JSXOpeningElement: function(node) {
var variables = variablesInScope(context)
if (findVariable(variables, name)) return
context.report({
message: `'${name}' must be in scope when using JSX syntax`,
node: node
})
}
}
}
factoryInScopeRule.schema = [{
type: 'object',
properties: {
pragma: {type: 'string'}
},
additionalProperties: false
}]
/**
* Prevent the JSX factory function from being marked as unused
* if it will be in the compiled source
*/
const usesFactoryRule = context => {
const config = context.options[0] || {}
const id = config.pragma || 'JSX'
return {
JSXElement() {
context.markVariableAsUsed(id)
}
}
}
usesFactoryRule.schema = factoryInScopeRule.schema
/**
* Prevent variables used in JSX to be marked as unused
*/
const markUsedRule = context => {
return {
JSXOpeningElement(node) {
var name = node.name
if (name.type == 'JSXMemberExpression') name = name.object
if (name.type == 'JSXNamespacedName') name = name.namespace
context.markVariableAsUsed(name.name)
},
JSXAttribute(attr) {
if (attr.value == null) context.markVariableAsUsed(attr.name.name)
}
}
}
/**
* Disallow undeclared variables in JSX
*/
const noUndefRule = context => {
const config = context.options[0] || {}
const ignoreAttributes = !!config.ignoreAttributes
const ignored = config.varsIgnorePattern && new RegExp(config.varsIgnorePattern)
const isIgnored = ignored
? name => ignored.test(name)
: () => false
return {
JSXOpeningElement(node) {
var name = node.name
if (name.type == 'JSXMemberExpression') name = name.object
if (name.type == 'JSXNamespacedName') name = name.namespace
const variables = variablesInScope(context)
if (!ignoreAttributes) {
node.attributes.forEach(attr => {
if (attr.type == 'JSXSpreadAttribute') return
if (attr.value == null && !isIgnored(attr.name.name)) checkDefined(context, variables, attr.name)
})
}
if (!standardTags.has(name.name) && !isIgnored(name.name)) checkDefined(context, variables, name)
}
}
}
const checkDefined = (context, variables, node) => {
if (findVariable(variables, node.name)) return
context.report({
message: `'${node.name}' is not defined`,
node: node
})
}
const rules = {
'uses-factory': usesFactoryRule,
'factory-in-scope': factoryInScopeRule,
'mark-used-vars': markUsedRule,
'no-undef': noUndefRule
}
// enable all by default
const rulesConfig = {
'uses-factory': 1,
'factory-in-scope': 1,
'mark-used-vars': 1,
'no-undef': 1
}
export {rules,rulesConfig}