Code Monkey home page Code Monkey logo

postcss-bem-linter's Introduction

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 stylesheets against a set of BEM-style conventions. You can use preset patterns (SUIT and BEM, currently) or insert your own. The plugin will throw an error if it finds CSS that does not follow the specified conventions.

Installation

npm install postcss-bem-linter

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

Conformance tests

Default mode:

  • Only allow selectors sequences that match the defined convention.
  • Only allow custom-property names that begin with the defined ComponentName.
  • The :root selector can only contain custom-properties.
  • The :root cannot be combined with other selectors.

Weak mode:

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

Use

postcss().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 must be at the end of sequences, and will be ignored. Instead of .Component:first-child.is-open you should use .Component.is-open:first-child. The former will cause an error.

Preset Patterns

You can use a preset pattern by passing a string as the pattern, and, if needed, an options object, as in bemLinter('suit', { namespace: 'twt' }). Options are pattern-specific.

The following preset patterns are available:

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

'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 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 uses /** @define 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' });

// 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 against files that explicitly declare that they are defining either a named component or utilities, using either /** @define ComponentName */ or /** @define utilities */ in the first line of the file.

Weak mode is turned on by adding ; weak to this definition, e.g. /** @define ComponentName; weak */.

/** @define MyComponent */

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

.MyComponent {}

.MyComponent-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.

Testing CSS files

Pass your individual CSS files through the plugin. It will throw errors for conformance failures, which you can log when caught by your build tools.

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

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

Development

Install the dependencies.

npm install

Run the tests.

npm test

Watch and automatically re-run the unit tests.

npm start

postcss-bem-linter's People

Contributors

davidtheclark avatar necolas avatar

Watchers

 avatar James Cloos avatar  avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.