Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve primer/no-override to match classes, better reporting #37

Merged
merged 3 commits into from Sep 9, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
8 changes: 5 additions & 3 deletions __tests__/no-override.js
Expand Up @@ -5,7 +5,7 @@ describe('primer/no-override', () => {
return lint('.text-gray { color: #111; }').then(data => {
expect(data).toHaveErrored()
expect(data).toHaveWarningsLength(1)
expect(data).toHaveWarnings([`The selector ".text-gray" should not be overridden. (primer/no-override)`])
expect(data).toHaveWarnings([`".text-gray" should not be overridden (found in utilities). (primer/no-override)`])
})
})

Expand All @@ -14,7 +14,7 @@ describe('primer/no-override', () => {
return lint(`${selector} { color: #f00; }`).then(data => {
expect(data).toHaveErrored()
expect(data).toHaveWarningsLength(1)
expect(data).toHaveWarnings([`The selector "${selector}" should not be overridden. (primer/no-override)`])
expect(data).toHaveWarnings([`"${selector}" should not be overridden (found in utilities). (primer/no-override)`])
})
})

Expand All @@ -23,7 +23,9 @@ describe('primer/no-override', () => {
return lint(`.foo ${selector}:focus { color: #f00; }`).then(data => {
expect(data).toHaveErrored()
expect(data).toHaveWarningsLength(1)
expect(data).toHaveWarnings([`The selector "${selector}" should not be overridden. (primer/no-override)`])
expect(data).toHaveWarnings([
`"${selector}" should not be overridden in ".foo ${selector}:focus" (found in utilities). (primer/no-override)`
])
})
})

Expand Down
41 changes: 25 additions & 16 deletions plugins/no-override.js
Expand Up @@ -2,11 +2,8 @@ const stylelint = require('stylelint')
const {requirePrimerFile} = require('../src/primer')

const ruleName = 'primer/no-override'
const CLASS_PATTERN = /(\.[-\w]+)/g

const messages = stylelint.utils.ruleMessages(ruleName, {
rejected: selector => `The selector "${selector}" should not be overridden.`
})
const CLASS_PATTERN = /(\.[-\w]+)/
const CLASS_PATTERN_ALL = new RegExp(CLASS_PATTERN, 'g')

module.exports = stylelint.createPlugin(ruleName, (enabled, options = {}) => {
if (!enabled) {
Expand All @@ -18,22 +15,30 @@ module.exports = stylelint.createPlugin(ruleName, (enabled, options = {}) => {
const primerMeta = requirePrimerFile('dist/meta.json')
const availableBundles = Object.keys(primerMeta.bundles)

const immutableSelectors = new Set()
const immutableClassSelectors = new Set()
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`)
for (const selector of stats.selectors.values) {
immutableSelectors.add(selector)
const selectors = stats.selectors.values.filter(selector => CLASS_PATTERN.test(selector))
for (const selector of selectors) {
immutableSelectors.set(selector, bundle)
for (const classSelector of getClassSelectors(selector)) {
immutableClassSelectors.add(classSelector)
immutableClassSelectors.set(classSelector, bundle)
}
}
}

// console.warn(`Got ${immutableSelectors.size} immutable selectors from: "${bundles.join('", "')}"`)
const messages = stylelint.utils.ruleMessages(ruleName, {
rejected: (rule, {selector, bundle}) => {
const suffix = bundle ? ` (found in ${bundle})` : ''
return selector
? `"${selector}" should not be overridden in "${rule.selector}"${suffix}.`
shawnbot marked this conversation as resolved.
Show resolved Hide resolved
: `"${rule.selector}" should not be overridden${suffix}.`
}
})

return (root, result) => {
if (!Array.isArray(bundles) || bundles.some(bundle => !availableBundles.includes(bundle))) {
Expand All @@ -50,21 +55,25 @@ module.exports = stylelint.createPlugin(ruleName, (enabled, options = {}) => {
return
}

const report = (rule, selector) =>
const report = (rule, subject) =>
stylelint.utils.report({
message: messages.rejected(selector),
message: messages.rejected(rule, subject),
node: rule,
result,
ruleName
})

root.walkRules(rule => {
const subject = {rule}
if (immutableSelectors.has(rule.selector)) {
report(rule, rule.selector)
subject.bundle = immutableSelectors.get(rule.selector)
report(rule, subject)
} else {
for (const classSelector of getClassSelectors(rule.selector)) {
if (immutableClassSelectors.has(classSelector)) {
report(rule, classSelector)
subject.bundle = immutableClassSelectors.get(classSelector)
subject.selector = classSelector
report(rule, subject)
}
}
}
Expand All @@ -73,7 +82,7 @@ module.exports = stylelint.createPlugin(ruleName, (enabled, options = {}) => {
})

function getClassSelectors(selector) {
const match = selector.match(CLASS_PATTERN)
const match = selector.match(CLASS_PATTERN_ALL)
return match ? [...match] : []
}

Expand Down