-
Notifications
You must be signed in to change notification settings - Fork 22
/
box-shadow.js
89 lines (72 loc) · 2.62 KB
/
box-shadow.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
import stylelint from 'stylelint'
import {declarationValueIndex} from 'stylelint/lib/utils/nodeFieldIndices.cjs'
import {primitivesVariables} from './lib/utils.js'
const {
createPlugin,
utils: {report, ruleMessages, validateOptions},
} = stylelint
export const ruleName = 'primer/box-shadow'
export const messages = ruleMessages(ruleName, {
rejected: (value, replacement) => {
if (!replacement) {
return `Please use a Primer box-shadow variable instead of '${value}'. Consult the primer docs for a suitable replacement. https://primer.style/foundations/primitives/color#shadow or https://primer.style/foundations/primitives/size#border-size`
}
return `Please replace '${value}' with a Primer box-shadow variable '${replacement['name']}'. https://primer.style/foundations/primitives/color#shadow or https://primer.style/foundations/primitives/size#border-size`
},
})
const variables = primitivesVariables('box-shadow')
const shadows = []
for (const variable of variables) {
const name = variable['name']
// TODO: Decide if this is safe. Someday we might have variables that
// have 'shadow' in the name but aren't full box-shadows.
if (name.includes('shadow') || name.includes('boxShadow')) {
shadows.push(variable)
}
}
/** @type {import('stylelint').Rule} */
const ruleFunction = primary => {
return (root, result) => {
const validOptions = validateOptions(result, ruleName, {
actual: primary,
possible: [true],
})
const validValues = shadows
if (!validOptions) return
root.walkDecls(declNode => {
const {prop, value} = declNode
if (prop !== 'box-shadow') return
if (value === 'none') return
const checkForVariable = (vars, nodeValue) => {
return vars.some(variable =>
new RegExp(`${variable['name'].replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}\\b`).test(nodeValue),
)
}
if (checkForVariable(validValues, value)) {
return
}
const replacement = validValues.find(variable => variable.values.includes(value))
let fix = undefined
if (replacement) {
fix = () => {
declNode.value = value.replace(value, `var(${replacement['name']})`)
}
}
report({
index: declarationValueIndex(declNode),
endIndex: declarationValueIndex(declNode) + value.length,
message: messages.rejected(value, replacement),
node: declNode,
result,
ruleName,
fix,
})
})
}
}
ruleFunction.ruleName = ruleName
ruleFunction.messages = messages
ruleFunction.meta = {
fixable: true,
}
export default createPlugin(ruleName, ruleFunction)