Socket
Socket
Sign inDemoInstall

postcss-bem-linter

Package Overview
Dependencies
1
Maintainers
2
Versions
31
Alerts
File Explorer

Advanced tools

Install Socket

Detect and block malicious and high-risk dependencies

Install

postcss-bem-linter


Version published
Maintainers
2
Created

Changelog

Source

0.6.0 (August 8, 2015)

  • Support multiple definitions per file.
  • Support comments to end definition enforcement.
  • Support verbose comment syntax, e.g. /* postcss-bem-linter: define ComponentName */.

Readme

Source

postcss-bem-linter

Build Status

A PostCSS plugin to lint BEM-style CSS.

BEM-style describes CSS that follows a more-or-less strict set of conventions determining what selectors can be used. Typically, these conventions require that classes begin with the name of the component (or "block") that contains them, and that all characters after the component name follow a specified pattern. Original BEM methodology refers to "blocks", "elements", and "modifiers"; SUIT refers to "components", "descendants", and "modifiers". You might have your own terms for similar concepts.

With this plugin, you can check the validity of selectors against a set of BEM-style conventions. You can use preset patterns (SUIT and BEM, currently) or insert your own. The plugin will register warnings if it finds CSS that does not follow the specified conventions.

Installation

npm install postcss-bem-linter

This plugin registers warnings via PostCSS. Therefore, you'll want to use it with a PostCSS runner that prints warnings (e.g. gulp-postcss) or another PostCSS plugin that prints warnings (e.g. postcss-reporter).

Conformance tests

Default mode:

  • Only allow selector sequences that match the defined convention.
  • Only allow custom-property names that begin with the defined ComponentName.

Weak mode:

  • While initial selector sequences (before combinators) must match the defined convention, sequences after combinators are not held to any standard.

Prior to 0.5.0, this plugin checked two other details: that :root rules only contain custom-properties; and that the :root selector is not grouped or combined with other selectors. These checks can now be performed by stylelint. So from 0.5.0 onwards, this plugin leaves that business to stylelint to focus on its more unique task.

Use

bemLinter([pattern[, options]])

Defining your pattern

Patterns consist of regular expressions, and functions that return regular expressions, which describe valid selector sequences.

Please note that patterns describe sequences, not just simple selectors. So if, for example, you would like to be able to chain state classes to your component classes, as in .Component.is-open, your regular expression needs to allow for this chaining.

Also note that pseudo-classes and pseudo-elements will be ignored if they occur at the end of the sequence. Instead of .Component:first-child.is-open, you should use .Component.is-open:first-child. The former will trigger a warning unless you've written a silly complicated regular expression.

Preset Patterns

The following preset patterns are available:

  • 'suit' (default), as defined here. Options:
  • 'bem', as defined here.

You can use a preset pattern and its options in two ways:

  • pass the preset's name as the first argument, and, if needed, an options object as the second, e.g. bemLinter('suit', { namespace: 'twt' }).
  • pass an object as the first and only argument, with the preset's name as the preset property and, if needed, presetOptions, e.g. bemLinter({ preset: 'suit', presetOptions { namespace: 'twt' }).

'suit' is the default pattern; so if you do not pass any pattern argument, SUIT conventions will be enforced.

Custom Patterns

You can define a custom pattern by passing as your first and only argument an object with the following properties:

  • componentName (optional): A regular expression describing valid component names. Default is /[-_a-zA-Z0-9]+/.
  • componentSelectors: Either of the following:
    • A single function that accepts a component name and returns a regular expression describing all valid selector sequences for the stylesheet.
    • An object consisting of two methods, initial and combined. Both methods accept a component name and return a regular expression. initial returns a description of valid initial selector sequences — those occurring at the beginning of a selector, before any combinators. combined returns a description of valid selector sequences allowed after combinators. (Two things to note: If you do not specify a combined pattern, it is assumed that combined sequences must match the same pattern as initial sequences. And in weak mode, any combined sequences are accepted.)
  • utilitySelectors: A regular expression describing valid utility selectors. This will be use if the stylesheet defines a group of utilities, as explained below.

So you might call the plugin in any of the following ways:

// use 'suit' conventions
bemLinter();
bemLinter('suit');
bemLinter('suit', { namespace: 'twt' });
bemLinter({ preset: 'suit', presetOptions: { namespace: 'twt' }});

// use 'bem' conventions
bemLinter('bem');

// define a RegExp for component names
bemLinter({
  componentName: /[A-Z]+/
});

// define a single RegExp for all selector sequences, initial or combined
bemLinter({
  componentSelectors: function(componentName) {
    return new RegExp('^\\.' + componentName + '(?:-[a-z]+)?$');
  }
});

// define separate `componentName`, `initial`, `combined`, and `utilities` RegExps
bemLinter({
  componentName: /[A-Z]+/,
  componentSelectors: {
    initial: function(componentName) {
      return new RegExp('^\\.' + componentName + '(?:-[a-z]+)?$');
    },
    combined: function(componentName) {
      return new RegExp('^\\.combined-' + componentName + '-[a-z]+$');
    }
  },
  utilitySelectors: /^\.util-[a-z]+$/
});

Defining a component

The plugin will only run if it finds special comments that define a named component or a group of utilities.

These definitions can be provided in two syntaxes: concise and verbose.

  • Concise definition syntax: /** @define ComponentName */ or /** @define utilities */
  • Verbose definition syntax: /* postcss-bem-linter: define ComponentName */ or /* postcss-bem-linter: define utilities */.

Weak mode is turned on by adding ; weak to a definition, e.g. /** @define ComponentName; weak */ or /* postcss-bem-linter: define ComponentName; weak */.

Concise syntax:

/** @define MyComponent */

:root {
  --MyComponent-property: value;
}

.MyComponent {}

.MyComponent-other {}

Verbose syntax:

/** postcss-bem-linter: define FancyComponent */

:root {
  --FancyComponent-property: value;
}

.FancyComponent {}

.FancyComponent-other {}

Weak mode:

/** @define MyComponent; weak */

:root {
  --MyComponent-property: value;
}

.MyComponent {}

.MyComponent .other {}

Utilities:

/** @define utilities */

.u-sizeFill {}

.u-sm-horse {}

If a component is defined and the component name does not match your componentName pattern, the plugin will throw an error.

Multiple definitions

It's recommended that you keep each defined group of rules in a distinct file, with the definition at the top of the file. If, however, you have a good reason for multiple definitions within a single file, you can do that.

Successive definitions override each other. So the following works:

/* @define Foo */
.Foo {}

/* @define Bar */
.Bar {}

/* @define utilities */
.u-something {}

You can also deliberately end the enforcement of a definition with the following special comments: /* @end */ or /* postcss-bem-linter: end */.

/* @define Foo */
.Foo {}
/* @end */

.something-something-something {}

One use-case for this functionality is when linting files after concatenation performed by a CSS processor like Less or Sass, whose syntax is not always compatible with PostCSS. See issue #57.

Ignoring specific selectors

If you need to ignore a specific selector but do not want to ignore the entire stylesheet or end the enforcement of a definition, you can do so by preceding the selector with this comment: /* postcss-bem-linter: ignore */.

/** @define MyComponent */

.MyComponent {
  display: flex;
}

/* postcss-bem-linter: ignore */
.no-flexbox .Component {
  display: block;
}

This will cause the linter to ignore only the very next selector.

Testing CSS files

Pass your individual CSS files through the plugin. It will register warnings for conformance failures, which you can print to the console using postcss-reporter or relying on a PostCSS runner (such as gulp-postcss).

var postcss = require('postcss');
var bemLinter = require('postcss-bem-linter');
var reporter = require('postcss-reporter');

files.forEach(function(file) {
  var css = fs.readFileSync(file, 'utf-8');
  postcss()
    .use(bemLinter())
    .use(reporter())
    .process(css)
    .then(function(result) { .. });
});

Development

Install the dependencies.

npm install

Run the tests.

npm test

Watch and automatically re-run the unit tests.

npm start

Keywords

FAQs

Last updated on 09 Aug 2015

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap

Packages

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc