Press n or j to go to the next uncovered block, b, p or k for the previous block.
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 | 2x 2x 2x 2x 2x 2x 2x 14x 1x 13x 13x 7x 4x 13x 13x 13x 13x 13x 16x 5x 11x 11x 11x 13731x 13731x 13624x 13x 3x 3x 3x 3x 13x 13x 2x 1x 2x 13x 3x 13x 15x 15x 6x 5x 2x 13x 13x 4x 1x 13744x 13744x 6x 6x | const stylelint = require('stylelint') const {requirePrimerFile} = require('./lib/primer') const ruleName = 'primer/no-override' const CLASS_PATTERN = /(\.[-\w]+)/ const CLASS_PATTERN_ALL = new RegExp(CLASS_PATTERN, 'g') const CLASS_PATTERN_ONLY = /^\.[-\w]+(:{1,2}[-\w]+)?$/ module.exports = stylelint.createPlugin(ruleName, (enabled, options = {}) => { if (!enabled) { return noop } const {bundles = ['utilities'], ignoreSelectors = []} = options const isSelectorIgnored = typeof ignoreSelectors === 'function' ? ignoreSelectors : selector => { return ignoreSelectors.some(pattern => { return pattern instanceof RegExp ? pattern.test(selector) : selector.includes(pattern) }) } const primerMeta = requirePrimerFile('dist/meta.json') const availableBundles = Object.keys(primerMeta.bundles) // These map selectors to the bundle in which they're defined. // If there's no entry for a given selector, it means that it's not defined // in one of the *specified* bundles, since we're iterating over the list of // bundle names in the options. const immutableSelectors = new Map() const immutableClassSelectors = new Map() for (const bundle of bundles) { if (!availableBundles.includes(bundle)) { continue } const stats = requirePrimerFile(`dist/stats/${bundle}.json`) const selectors = stats.selectors.values for (const selector of selectors) { immutableSelectors.set(selector, bundle) for (const classSelector of getClassSelectors(selector)) { immutableClassSelectors.set(classSelector, bundle) } } } const messages = stylelint.utils.ruleMessages(ruleName, { rejected: ({rule, selector, bundle}) => { const definedIn = ` (defined in @primer/css/${bundle})` const ruleSelector = collapseWhitespace(rule.selector) const context = selector === rule.selector ? '' : ` in "${ruleSelector}"` return `"${collapseWhitespace(selector)}" should not be overridden${context}${definedIn}.` } }) return (root, result) => { if (!Array.isArray(bundles) || bundles.some(bundle => !availableBundles.includes(bundle))) { const invalidBundles = Array.isArray(bundles) ? `"${bundles.filter(bundle => !availableBundles.includes(bundle)).join('", "')}"` : '(not an array)' result.warn(`The "bundles" option must be an array of valid bundles; got: ${invalidBundles}`, { stylelintType: 'invalidOption', stylelintReference: 'https://github.com/primer/stylelint-config-primer#options' }) } const report = subject => stylelint.utils.report({ message: messages.rejected(subject), node: subject.rule, result, ruleName }) root.walkRules(rule => { const {selector} = rule if (immutableSelectors.has(selector)) { if (isClassSelector(selector)) { if (!isSelectorIgnored(selector)) { return report({ rule, bundle: immutableSelectors.get(selector), selector }) } } else { // console.log(`not a class selector: "${selector}"`) } } for (const classSelector of getClassSelectors(selector)) { if (immutableClassSelectors.has(classSelector)) { if (!isSelectorIgnored(classSelector)) { return report({ rule, bundle: immutableClassSelectors.get(classSelector), selector: classSelector }) } } } }) } }) function getClassSelectors(selector) { const match = selector.match(CLASS_PATTERN_ALL) return match ? [...match] : [] } function isClassSelector(selector) { return CLASS_PATTERN_ONLY.test(selector) } function collapseWhitespace(str) { return str.trim().replace(/\s+/g, ' ') } function noop() {} |