@primer/stylelint-config 12.9.2 → 13.0.0-rc.095cb19
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +0 -5
- package/dist/index.cjs +1154 -0
- package/dist/index.mjs +1151 -0
- package/package.json +61 -26
- package/plugins/README.md +1 -157
- package/plugins/borders.js +2 -2
- package/plugins/box-shadow.js +2 -2
- package/plugins/colors.js +2 -2
- package/plugins/lib/decl-validator.js +4 -4
- package/plugins/lib/primitives.js +36 -0
- package/plugins/lib/variable-rules.js +7 -22
- package/plugins/no-display-colors.js +5 -8
- package/plugins/responsive-widths.js +6 -9
- package/plugins/spacing.js +71 -69
- package/plugins/typography.js +2 -2
- package/property-order.js +1 -1
- package/browsers.js +0 -7
- package/index.js +0 -106
- package/plugins/lib/primer-utilities.js +0 -526
- package/plugins/lib/primer.js +0 -26
- package/plugins/new-color-vars-have-fallback.js +0 -39
- package/plugins/no-deprecated-colors.js +0 -103
- package/plugins/no-experimental-vars.js +0 -47
- package/plugins/no-override.js +0 -120
- package/plugins/no-scale-colors.js +0 -54
- package/plugins/no-undefined-vars.js +0 -121
- package/plugins/no-unused-vars.js +0 -96
- package/plugins/utilities.js +0 -55
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
const stylelint = require('stylelint')
|
|
2
|
-
const declarationValueIndex = require('stylelint/lib/utils/declarationValueIndex')
|
|
3
|
-
|
|
4
|
-
const ruleName = 'primer/no-experimental-vars'
|
|
5
|
-
const messages = stylelint.utils.ruleMessages(ruleName, {
|
|
6
|
-
rejected: value => {
|
|
7
|
-
return `Do not use experimental variable \`var(--${value})\`. Experimental variables are undergoing testing, see https://github.com/github/primer/issues/889 for more details.`
|
|
8
|
-
},
|
|
9
|
-
})
|
|
10
|
-
|
|
11
|
-
// eslint-disable-next-line no-unused-vars
|
|
12
|
-
module.exports = stylelint.createPlugin(ruleName, (enabled, options = {}, context) => {
|
|
13
|
-
if (!enabled) {
|
|
14
|
-
return noop
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
// eslint-disable-next-line import/no-dynamic-require
|
|
18
|
-
const designTokens = require(options.designTokens)
|
|
19
|
-
|
|
20
|
-
let experimentalVars = null
|
|
21
|
-
for (const tokenType of Object.keys(designTokens)) {
|
|
22
|
-
experimentalVars = new Set(designTokens[tokenType].map(t => t['name']))
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
const lintResult = (root, result) => {
|
|
26
|
-
root.walkDecls(decl => {
|
|
27
|
-
for (const expVar of experimentalVars) {
|
|
28
|
-
if (decl.value.includes(`var(--${expVar})`)) {
|
|
29
|
-
stylelint.utils.report({
|
|
30
|
-
index: declarationValueIndex(decl),
|
|
31
|
-
message: messages.rejected(expVar),
|
|
32
|
-
node: decl,
|
|
33
|
-
result,
|
|
34
|
-
ruleName,
|
|
35
|
-
})
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
})
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
return lintResult
|
|
42
|
-
})
|
|
43
|
-
|
|
44
|
-
function noop() {}
|
|
45
|
-
|
|
46
|
-
module.exports.ruleName = ruleName
|
|
47
|
-
module.exports.messages = messages
|
package/plugins/no-override.js
DELETED
|
@@ -1,120 +0,0 @@
|
|
|
1
|
-
const stylelint = require('stylelint')
|
|
2
|
-
const {requirePrimerFile} = require('./lib/primer')
|
|
3
|
-
|
|
4
|
-
const ruleName = 'primer/no-override'
|
|
5
|
-
const CLASS_PATTERN = /(\.[-\w]+)/
|
|
6
|
-
const CLASS_PATTERN_ALL = new RegExp(CLASS_PATTERN, 'g')
|
|
7
|
-
const CLASS_PATTERN_ONLY = /^\.[-\w]+(:{1,2}[-\w]+)?$/
|
|
8
|
-
|
|
9
|
-
module.exports = stylelint.createPlugin(ruleName, (enabled, options = {}) => {
|
|
10
|
-
if (!enabled) {
|
|
11
|
-
return noop
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
const {bundles = ['utilities'], ignoreSelectors = []} = options
|
|
15
|
-
|
|
16
|
-
const isSelectorIgnored =
|
|
17
|
-
typeof ignoreSelectors === 'function'
|
|
18
|
-
? ignoreSelectors
|
|
19
|
-
: selector => {
|
|
20
|
-
return ignoreSelectors.some(pattern => {
|
|
21
|
-
return pattern instanceof RegExp ? pattern.test(selector) : selector.includes(pattern)
|
|
22
|
-
})
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
const primerMeta = requirePrimerFile('dist/meta.json')
|
|
26
|
-
const availableBundles = Object.keys(primerMeta.bundles)
|
|
27
|
-
|
|
28
|
-
// These map selectors to the bundle in which they're defined.
|
|
29
|
-
// If there's no entry for a given selector, it means that it's not defined
|
|
30
|
-
// in one of the *specified* bundles, since we're iterating over the list of
|
|
31
|
-
// bundle names in the options.
|
|
32
|
-
const immutableSelectors = new Map()
|
|
33
|
-
const immutableClassSelectors = new Map()
|
|
34
|
-
|
|
35
|
-
for (const bundle of bundles) {
|
|
36
|
-
if (!availableBundles.includes(bundle)) {
|
|
37
|
-
continue
|
|
38
|
-
}
|
|
39
|
-
const stats = requirePrimerFile(`dist/stats/${bundle}.json`)
|
|
40
|
-
const selectors = stats.selectors.values
|
|
41
|
-
for (const selector of selectors) {
|
|
42
|
-
immutableSelectors.set(selector, bundle)
|
|
43
|
-
for (const classSelector of getClassSelectors(selector)) {
|
|
44
|
-
immutableClassSelectors.set(classSelector, bundle)
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
const messages = stylelint.utils.ruleMessages(ruleName, {
|
|
50
|
-
rejected: ({rule, selector, bundle}) => {
|
|
51
|
-
const definedIn = ` (defined in @primer/css/${bundle})`
|
|
52
|
-
const ruleSelector = collapseWhitespace(rule.selector)
|
|
53
|
-
const context = selector === rule.selector ? '' : ` in "${ruleSelector}"`
|
|
54
|
-
return `"${collapseWhitespace(selector)}" should not be overridden${context}${definedIn}.`
|
|
55
|
-
},
|
|
56
|
-
})
|
|
57
|
-
|
|
58
|
-
return (root, result) => {
|
|
59
|
-
if (!Array.isArray(bundles) || bundles.some(bundle => !availableBundles.includes(bundle))) {
|
|
60
|
-
const invalidBundles = Array.isArray(bundles)
|
|
61
|
-
? `"${bundles.filter(bundle => !availableBundles.includes(bundle)).join('", "')}"`
|
|
62
|
-
: '(not an array)'
|
|
63
|
-
result.warn(`The "bundles" option must be an array of valid bundles; got: ${invalidBundles}`, {
|
|
64
|
-
stylelintType: 'invalidOption',
|
|
65
|
-
stylelintReference: 'https://github.com/primer/stylelint-config#options',
|
|
66
|
-
})
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
const report = subject =>
|
|
70
|
-
stylelint.utils.report({
|
|
71
|
-
message: messages.rejected(subject),
|
|
72
|
-
node: subject.rule,
|
|
73
|
-
result,
|
|
74
|
-
ruleName,
|
|
75
|
-
})
|
|
76
|
-
|
|
77
|
-
root.walkRules(rule => {
|
|
78
|
-
const {selector} = rule
|
|
79
|
-
if (immutableSelectors.has(selector)) {
|
|
80
|
-
if (isClassSelector(selector)) {
|
|
81
|
-
if (!isSelectorIgnored(selector)) {
|
|
82
|
-
return report({
|
|
83
|
-
rule,
|
|
84
|
-
bundle: immutableSelectors.get(selector),
|
|
85
|
-
selector,
|
|
86
|
-
})
|
|
87
|
-
}
|
|
88
|
-
} else {
|
|
89
|
-
// console.log(`not a class selector: "${selector}"`)
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
for (const classSelector of getClassSelectors(selector)) {
|
|
93
|
-
if (immutableClassSelectors.has(classSelector)) {
|
|
94
|
-
if (!isSelectorIgnored(classSelector)) {
|
|
95
|
-
return report({
|
|
96
|
-
rule,
|
|
97
|
-
bundle: immutableClassSelectors.get(classSelector),
|
|
98
|
-
selector: classSelector,
|
|
99
|
-
})
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
})
|
|
104
|
-
}
|
|
105
|
-
})
|
|
106
|
-
|
|
107
|
-
function getClassSelectors(selector) {
|
|
108
|
-
const match = selector.match(CLASS_PATTERN_ALL)
|
|
109
|
-
return match ? [...match] : []
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
function isClassSelector(selector) {
|
|
113
|
-
return CLASS_PATTERN_ONLY.test(selector)
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
function collapseWhitespace(str) {
|
|
117
|
-
return str.trim().replace(/\s+/g, ' ')
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
function noop() {}
|
|
@@ -1,54 +0,0 @@
|
|
|
1
|
-
const stylelint = require('stylelint')
|
|
2
|
-
const matchAll = require('string.prototype.matchall')
|
|
3
|
-
|
|
4
|
-
const ruleName = 'primer/no-scale-colors'
|
|
5
|
-
const messages = stylelint.utils.ruleMessages(ruleName, {
|
|
6
|
-
rejected: varName =>
|
|
7
|
-
`${varName} is a non-functional scale color and cannot be used without being wrapped in the color-variables mixin`,
|
|
8
|
-
})
|
|
9
|
-
|
|
10
|
-
// Match CSS variable references (e.g var(--color-text-primary))
|
|
11
|
-
// eslint-disable-next-line no-useless-escape
|
|
12
|
-
const variableReferenceRegex = /var\(([^\),]+)(,.*)?\)/g
|
|
13
|
-
|
|
14
|
-
module.exports = stylelint.createPlugin(ruleName, (enabled, options = {}) => {
|
|
15
|
-
if (!enabled) {
|
|
16
|
-
return noop
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
const {verbose = false} = options
|
|
20
|
-
// eslint-disable-next-line no-console
|
|
21
|
-
const log = verbose ? (...args) => console.warn(...args) : noop
|
|
22
|
-
|
|
23
|
-
// Keep track of declarations we've already seen
|
|
24
|
-
const seen = new WeakMap()
|
|
25
|
-
|
|
26
|
-
return (root, result) => {
|
|
27
|
-
root.walkRules(rule => {
|
|
28
|
-
rule.walkDecls(decl => {
|
|
29
|
-
if (seen.has(decl)) {
|
|
30
|
-
return
|
|
31
|
-
} else {
|
|
32
|
-
seen.set(decl, true)
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
for (const [, variableName] of matchAll(decl.value, variableReferenceRegex)) {
|
|
36
|
-
log(`Found variable reference ${variableName}`)
|
|
37
|
-
if (variableName.match(/^--color-(scale|auto)-/)) {
|
|
38
|
-
stylelint.utils.report({
|
|
39
|
-
message: messages.rejected(variableName),
|
|
40
|
-
node: decl,
|
|
41
|
-
result,
|
|
42
|
-
ruleName,
|
|
43
|
-
})
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
})
|
|
47
|
-
})
|
|
48
|
-
}
|
|
49
|
-
})
|
|
50
|
-
|
|
51
|
-
function noop() {}
|
|
52
|
-
|
|
53
|
-
module.exports.ruleName = ruleName
|
|
54
|
-
module.exports.messages = messages
|
|
@@ -1,121 +0,0 @@
|
|
|
1
|
-
const fs = require('fs')
|
|
2
|
-
const stylelint = require('stylelint')
|
|
3
|
-
const matchAll = require('string.prototype.matchall')
|
|
4
|
-
const globby = require('globby')
|
|
5
|
-
const TapMap = require('tap-map')
|
|
6
|
-
|
|
7
|
-
const ruleName = 'primer/no-undefined-vars'
|
|
8
|
-
const messages = stylelint.utils.ruleMessages(ruleName, {
|
|
9
|
-
rejected: varName => `${varName} is not defined`,
|
|
10
|
-
})
|
|
11
|
-
|
|
12
|
-
// Match CSS variable definitions (e.g. --color-text-primary:)
|
|
13
|
-
const variableDefinitionRegex = /^\s*(--[\w|-]+):/gm
|
|
14
|
-
|
|
15
|
-
// Match CSS variables defined with the color-variables mixin
|
|
16
|
-
const colorModeVariableDefinitionRegex = /^[^/\n]*\(["']?([^'"\s,]+)["']?,\s*\(light|dark:/gm
|
|
17
|
-
|
|
18
|
-
// Match CSS variable references (e.g var(--color-text-primary))
|
|
19
|
-
// eslint-disable-next-line no-useless-escape
|
|
20
|
-
const variableReferenceRegex = /var\(([^\),]+)(,.*)?\)/g
|
|
21
|
-
|
|
22
|
-
module.exports = stylelint.createPlugin(ruleName, (enabled, options = {}) => {
|
|
23
|
-
if (!enabled) {
|
|
24
|
-
return noop
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
const {files = ['**/*.scss', '!node_modules'], verbose = false} = options
|
|
28
|
-
// eslint-disable-next-line no-console
|
|
29
|
-
const log = verbose ? (...args) => console.warn(...args) : noop
|
|
30
|
-
const globalDefinedVariables = getDefinedVariables(files, log)
|
|
31
|
-
// Keep track of declarations we've already seen
|
|
32
|
-
const seen = new WeakMap()
|
|
33
|
-
|
|
34
|
-
return (root, result) => {
|
|
35
|
-
const fileDefinedVariables = new Set()
|
|
36
|
-
|
|
37
|
-
function checkVariable(variableName, node, allowed) {
|
|
38
|
-
if (!allowed.has(variableName)) {
|
|
39
|
-
stylelint.utils.report({
|
|
40
|
-
message: messages.rejected(variableName),
|
|
41
|
-
node,
|
|
42
|
-
result,
|
|
43
|
-
ruleName,
|
|
44
|
-
})
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
root.walkAtRules(rule => {
|
|
49
|
-
if (rule.name === 'include' && rule.params.startsWith('color-variables')) {
|
|
50
|
-
const innerMatch = [...matchAll(rule.params, variableReferenceRegex)]
|
|
51
|
-
if (!innerMatch.length) {
|
|
52
|
-
return
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
for (const [, variableName] of innerMatch) {
|
|
56
|
-
checkVariable(variableName, rule, new Set([...globalDefinedVariables, ...fileDefinedVariables]))
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
})
|
|
60
|
-
|
|
61
|
-
root.walkRules(rule => {
|
|
62
|
-
const scopeDefinedVaribles = new Set()
|
|
63
|
-
|
|
64
|
-
rule.walkDecls(decl => {
|
|
65
|
-
// Add CSS variable declarations within the source text to the list of allowed variables
|
|
66
|
-
if (decl.prop.startsWith('--')) {
|
|
67
|
-
scopeDefinedVaribles.add(decl.prop)
|
|
68
|
-
if (decl.parent.selector === ':root' || decl.parent.selector === ':host') {
|
|
69
|
-
fileDefinedVariables.add(decl.prop)
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
if (seen.has(decl)) {
|
|
74
|
-
return
|
|
75
|
-
} else {
|
|
76
|
-
seen.set(decl, true)
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
for (const [, variableName] of matchAll(decl.value, variableReferenceRegex)) {
|
|
80
|
-
checkVariable(
|
|
81
|
-
variableName,
|
|
82
|
-
decl,
|
|
83
|
-
new Set([...globalDefinedVariables, ...fileDefinedVariables, ...scopeDefinedVaribles]),
|
|
84
|
-
)
|
|
85
|
-
}
|
|
86
|
-
})
|
|
87
|
-
})
|
|
88
|
-
}
|
|
89
|
-
})
|
|
90
|
-
|
|
91
|
-
const cwd = process.cwd()
|
|
92
|
-
const cache = new TapMap()
|
|
93
|
-
|
|
94
|
-
function getDefinedVariables(globs, log) {
|
|
95
|
-
const cacheKey = JSON.stringify({globs, cwd})
|
|
96
|
-
return cache.tap(cacheKey, () => {
|
|
97
|
-
const definedVariables = new Set()
|
|
98
|
-
|
|
99
|
-
const files = globby.sync(globs)
|
|
100
|
-
log(`Scanning ${files.length} SCSS files for CSS variables`)
|
|
101
|
-
for (const file of files) {
|
|
102
|
-
log(`==========\nLooking for CSS variable definitions in ${file}`)
|
|
103
|
-
const css = fs.readFileSync(file, 'utf-8')
|
|
104
|
-
for (const [, variableName] of matchAll(css, variableDefinitionRegex)) {
|
|
105
|
-
log(`${variableName} defined in ${file}`)
|
|
106
|
-
definedVariables.add(variableName)
|
|
107
|
-
}
|
|
108
|
-
for (const [, variableName] of matchAll(css, colorModeVariableDefinitionRegex)) {
|
|
109
|
-
log(`--color-${variableName} defined via color-variables in ${file}`)
|
|
110
|
-
definedVariables.add(`--color-${variableName}`)
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
return definedVariables
|
|
115
|
-
})
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
function noop() {}
|
|
119
|
-
|
|
120
|
-
module.exports.ruleName = ruleName
|
|
121
|
-
module.exports.messages = messages
|
|
@@ -1,96 +0,0 @@
|
|
|
1
|
-
const TapMap = require('tap-map')
|
|
2
|
-
const globby = require('globby')
|
|
3
|
-
const matchAll = require('string.prototype.matchall')
|
|
4
|
-
const stylelint = require('stylelint')
|
|
5
|
-
const {readFileSync} = require('fs')
|
|
6
|
-
|
|
7
|
-
const ruleName = 'primer/no-unused-vars'
|
|
8
|
-
|
|
9
|
-
const cwd = process.cwd()
|
|
10
|
-
const COLON = ':'
|
|
11
|
-
const SCSS_VARIABLE_PATTERN = /(\$[-\w]+)/g
|
|
12
|
-
|
|
13
|
-
const messages = stylelint.utils.ruleMessages(ruleName, {
|
|
14
|
-
rejected: name => `The variable "${name}" is not referenced.`,
|
|
15
|
-
})
|
|
16
|
-
|
|
17
|
-
const cache = new TapMap()
|
|
18
|
-
|
|
19
|
-
module.exports = stylelint.createPlugin(ruleName, (enabled, options = {}) => {
|
|
20
|
-
if (!enabled) {
|
|
21
|
-
return noop
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
const {files = ['**/*.scss', '!node_modules'], variablePattern = SCSS_VARIABLE_PATTERN, verbose = false} = options
|
|
25
|
-
// eslint-disable-next-line no-console
|
|
26
|
-
const log = verbose ? (...args) => console.warn(...args) : noop
|
|
27
|
-
const cacheOptions = {files, variablePattern, cwd}
|
|
28
|
-
const {refs} = getCachedVariables(cacheOptions, log)
|
|
29
|
-
|
|
30
|
-
return (root, result) => {
|
|
31
|
-
root.walkDecls(decl => {
|
|
32
|
-
for (const [name] of matchAll(decl.prop, variablePattern)) {
|
|
33
|
-
if (!refs.has(name)) {
|
|
34
|
-
stylelint.utils.report({
|
|
35
|
-
message: messages.rejected(name),
|
|
36
|
-
node: decl,
|
|
37
|
-
result,
|
|
38
|
-
ruleName,
|
|
39
|
-
})
|
|
40
|
-
} else {
|
|
41
|
-
const path = stripCwd(decl.source.input.file)
|
|
42
|
-
log(`${name} declared in ${path} ref'd in ${pluralize(refs.get(name).size, 'file')}`)
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
})
|
|
46
|
-
}
|
|
47
|
-
})
|
|
48
|
-
|
|
49
|
-
function getCachedVariables(options, log) {
|
|
50
|
-
const key = JSON.stringify(options)
|
|
51
|
-
return cache.tap(key, () => {
|
|
52
|
-
const {files, variablePattern} = options
|
|
53
|
-
const decls = new TapMap()
|
|
54
|
-
const refs = new TapMap()
|
|
55
|
-
|
|
56
|
-
log(`Looking for variables in ${files} ...`)
|
|
57
|
-
for (const file of globby.sync(files)) {
|
|
58
|
-
const css = readFileSync(file, 'utf8')
|
|
59
|
-
for (const match of matchAll(css, variablePattern)) {
|
|
60
|
-
const after = css.substr(match.index + match[0].length)
|
|
61
|
-
const name = match[0]
|
|
62
|
-
if (after.startsWith(COLON)) {
|
|
63
|
-
decls.tap(name, set).add(file)
|
|
64
|
-
} else {
|
|
65
|
-
refs.tap(name, set).add(file)
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
log(`Found ${decls.size} declarations, ${pluralize(refs.size, 'reference')}.`)
|
|
70
|
-
|
|
71
|
-
for (const [name, filesList] of decls.entries()) {
|
|
72
|
-
const fileRefs = refs.get(name)
|
|
73
|
-
if (fileRefs) {
|
|
74
|
-
log(`variable "${name}" declared in ${pluralize(filesList.size, 'file')}, ref'd in ${fileRefs.size}`)
|
|
75
|
-
} else {
|
|
76
|
-
log(`[!] variable "${name}" declared in ${Array.from(filesList)[0]} is not referenced`)
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
return {decls, refs}
|
|
81
|
-
})
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
function noop() {}
|
|
85
|
-
|
|
86
|
-
function set() {
|
|
87
|
-
return new Set()
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
function stripCwd(path) {
|
|
91
|
-
return path.startsWith(cwd) ? path.substr(cwd.length + 1) : path
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
function pluralize(num, str, plural = `${str}s`) {
|
|
95
|
-
return num === 1 ? `${num} ${str}` : `${num} ${plural}`
|
|
96
|
-
}
|
package/plugins/utilities.js
DELETED
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
const stylelint = require('stylelint')
|
|
2
|
-
const utilities = require('./lib/primer-utilities')
|
|
3
|
-
|
|
4
|
-
const ruleName = 'primer/utilities'
|
|
5
|
-
|
|
6
|
-
const messages = stylelint.utils.ruleMessages(ruleName, {
|
|
7
|
-
rejected: (selector, utilityClass) => {
|
|
8
|
-
return `Consider using the Primer utility '.${utilityClass}' instead of the selector '${selector}' in your html. https://primer.style/css/utilities`
|
|
9
|
-
},
|
|
10
|
-
})
|
|
11
|
-
|
|
12
|
-
// eslint-disable-next-line no-unused-vars
|
|
13
|
-
module.exports = stylelint.createPlugin(ruleName, (enabled, options = {}, context) => {
|
|
14
|
-
if (!enabled) {
|
|
15
|
-
return noop
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
const utilityReplacement = (declaration, value) => {
|
|
19
|
-
const declarationUtilities = utilities[declaration]
|
|
20
|
-
if (declarationUtilities) {
|
|
21
|
-
return declarationUtilities.find(utility => {
|
|
22
|
-
return utility.value === value
|
|
23
|
-
})
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
const lintResult = (root, result) => {
|
|
28
|
-
root.walkRules(rule => {
|
|
29
|
-
if (!/^\.[\w\-_]+$/.exec(rule.selector)) {
|
|
30
|
-
return
|
|
31
|
-
}
|
|
32
|
-
const decls = rule.nodes.filter(decl => decl.type === 'decl')
|
|
33
|
-
|
|
34
|
-
if (decls.length === 1) {
|
|
35
|
-
const replacement = utilityReplacement(decls[0].prop, decls[0].value)
|
|
36
|
-
if (replacement) {
|
|
37
|
-
stylelint.utils.report({
|
|
38
|
-
index: rule.sourceIndex,
|
|
39
|
-
message: messages.rejected(rule.selector, replacement.utilityClass),
|
|
40
|
-
node: rule,
|
|
41
|
-
result,
|
|
42
|
-
ruleName,
|
|
43
|
-
})
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
})
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
return lintResult
|
|
50
|
-
})
|
|
51
|
-
|
|
52
|
-
function noop() {}
|
|
53
|
-
|
|
54
|
-
module.exports.ruleName = ruleName
|
|
55
|
-
module.exports.messages = messages
|