postcss / postcss-bem-linter

A BEM linter for postcss
MIT License
572 stars 35 forks source link

valid component selectors detected as invalid, and reported line numbers are also incorrect. #138

Closed foresightyj closed 5 years ago

foresightyj commented 5 years ago

I experienced this problem while using stylelint-selector-bem-pattern. But this problem is completely reproducible in postcss-bem-linter so I raised the issue here.

In my project, I am migrating an existing scss code base into BEM. Because there are many css rules involving primitive html tags directly like my-component h1 {}, I am trying to relax the rules a little bit so that tags with stronger semantics (like a, h1-h6, ul, li, etc) are allowed in combined position.

Here is my config and code:

let scss = `/** @define top-bar */
.top-bar {
    div {} /*not ok, tag with weak semantics*/
    a {} /* ok */
    ul {} /* ok too */
}

/** @define notification */
.notification {
    a {} /*ok*/
    .notification__board {} /*ok typical BEM */
}
`
const postcss = require('postcss')
const bemLinter = require('postcss-bem-linter');

const allowedTags = ["h[1-6]", "ul", "li", "a"].join("|")

const linter = bemLinter({
    componentName: "^[A-Za-z-]+",
    componentSelectors: {
        initial: `^\\.{componentName}(?:(__|--)\\w[\\w-_]*)?$`,
        combined: `^(\\.{componentName}(?:(__|--)\\w[\\w-_]*)?|${allowedTags})$`
    }
  });

postcss()
    .use(linter)
    .process(scss, {from:undefined})
    .then(result => {
        for(const msg of result.messages){
            console.log(msg.text, `line:${msg.line}`)
        }
    });

package versions:

  "dependencies": {
    "node-sass": "^4.9.3",
    "sass": "^1.10.4",
    "stylelint": "^8.3.1",
    "stylelint-config-standard": "^18.0.0",
    "stylelint-scss": "^2.2.0"
  },
  "devDependencies": {
    "postcss-bem-linter": "^3.1.0",
    "stylelint-selector-bem-pattern": "^2.0.0"
  }

However, when running, the result is:

image

Invalid component selector ".top-bar div" line:3 // This is expected.
Invalid component selector ".notification a" line:4 //Should not be an error/warning, and also wrong line number
Invalid component selector ".top-bar a" line:10 //same as above

It seems that the problem only exists, when I have two BEM components in the same file. If I delete the line from /** @define notification */ till the end, no more errors. But I do prefer multiple BEMs in the same files or the team members may complain about the troubles.

In vscode with stylelint, I have:

image

What did I do wrong, or is my use case not supported?

foresightyj commented 5 years ago

To fix my problem, all I have to do is to replace getComponentRootRule in get-selectors.js :

function getComponentRootRule(node) {
  while (node.root() !== node) {
    node = node.parent;
  }
  return node;
}

by:

function getComponentRootRule(node) {
  while (node.root() !== node.parent) {
    node = node.parent;
  }
  return node;
}

The original getComponentRootRule returns the top level node that has type root which in my case I only want to reach to the top level node that has type rule.

simonsmith commented 5 years ago

Closed by #139