Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

postcss-bem-linter

Package Overview
Dependencies
Maintainers
3
Versions
31
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

postcss-bem-linter - npm Package Compare versions

Comparing version 2.7.1 to 3.0.0

11

CHANGELOG.md

@@ -0,1 +1,12 @@

=== HEAD
=== 3.0.0 (July 21, 2017)
* Update PostCSS to `^6.0.6` - Drops support for Node 0.12
* Ignore underscore on implicitComponent to allow Scss partials [#115](https://github.com/postcss/postcss-bem-linter/pull/115)
* Use parent directory for implicitComponent if filename is 'index.css' [commit](https://github.com/postcss/postcss-bem-linter/commit/ad0bd56ea0721a3522067dfcc6aec0d0880bbe2d)
* Lint rulesets that only have an @extend keyword [#119](https://github.com/postcss/postcss-bem-linter/pull/119)
* Switch to Jest for unit tests
* Use Airbnb ESLint configuration
=== 2.7.1 (June 06, 2017)

@@ -2,0 +13,0 @@

94

index.js

@@ -1,22 +0,27 @@

var postcss = require('postcss');
var validateCustomProperties = require('./lib/validate-custom-properties');
var validateUtilities = require('./lib/validate-utilities');
var validateSelectors = require('./lib/validate-selectors');
var generateConfig = require('./lib/generate-config');
var toRegexp = require('./lib/to-regexp');
var path = require('path');
var checkImplicit = require('./lib/check-implicit');
'use strict';
var DEFINE_VALUE = '([-_a-zA-Z0-9]+)\\s*(?:;\\s*(weak))?';
var DEFINE_DIRECTIVE = new RegExp(
'(?:\\*\\s*@define ' + DEFINE_VALUE + ')|' +
'(?:\\s*postcss-bem-linter: define ' + DEFINE_VALUE + ')\\s*'
const postcss = require('postcss');
const validateCustomProperties = require('./lib/validate-custom-properties');
const validateUtilities = require('./lib/validate-utilities');
const validateSelectors = require('./lib/validate-selectors');
const generateConfig = require('./lib/generate-config');
const toRegexp = require('./lib/to-regexp');
const path = require('path');
const checkImplicit = require('./lib/check-implicit');
const DEFINE_VALUE = '([-_a-zA-Z0-9]+)\\s*(?:;\\s*(weak))?';
const DEFINE_DIRECTIVE = new RegExp(
`(?:\\*\\s*@define ${DEFINE_VALUE})|(?:\\s*postcss-bem-linter: define ${DEFINE_VALUE})\\s*`
);
var END_DIRECTIVE = new RegExp(
const END_DIRECTIVE = new RegExp(
'(?:\\*\\s*@end\\s*)|' +
'(?:\\s*postcss-bem-linter: end)\\s*'
);
var UTILITIES_IDENT = 'utilities';
var WEAK_IDENT = 'weak';
const UTILITIES_IDENT = 'utilities';
const WEAK_IDENT = 'weak';
function stripUnderscore(str) {
return str.replace(/^_/, '');
}
/**

@@ -32,19 +37,19 @@ * Set things up and call the validators.

*/
module.exports = postcss.plugin('postcss-bem-linter', function(primaryOptions, secondaryOptions) {
var config = generateConfig(primaryOptions, secondaryOptions);
var patterns = config.patterns;
module.exports = postcss.plugin('postcss-bem-linter', (primaryOptions, secondaryOptions) => {
const config = generateConfig(primaryOptions, secondaryOptions);
const patterns = config.patterns;
return function(root, result) {
var ranges = findRanges(root);
return (root, result) => {
const ranges = findRanges(root);
root.walkRules(function(rule) {
root.walkRules((rule) => {
if (rule.parent && rule.parent.name === 'keyframes') return;
if (!rule.source) return;
var ruleStartLine = rule.source.start.line;
ranges.forEach(function(range) {
const ruleStartLine = rule.source.start.line;
ranges.forEach((range) => {
if (ruleStartLine < range.start) return;
if (range.end && ruleStartLine > range.end) return;
checkRule(rule, range);
})
});
});

@@ -61,6 +66,6 @@

validateUtilities({
rule: rule,
rule,
utilityPattern: toRegexp(patterns.utilitySelectors),
ignorePattern: toRegexp(patterns.ignoreSelectors),
result: result,
result,
});

@@ -77,9 +82,9 @@ return;

validateCustomProperties({
rule: rule,
rule,
componentName: range.defined,
result: result,
result,
ignorePattern: toRegexp(patterns.ignoreCustomProperties),
});
validateSelectors({
rule: rule,
rule,
componentName: range.defined,

@@ -90,3 +95,3 @@ weakMode: range.weakMode,

ignorePattern: toRegexp(patterns.ignoreSelectors),
result: result,
result,
});

@@ -96,6 +101,6 @@ }

function findRanges(root) {
var ranges = [];
const ranges = [];
if (root.source && root.source.input && root.source.input.file) {
var filename = root.source.input.file;
const filename = root.source.input.file;
if (checkImplicit.isImplicitUtilities(config.implicitUtilities, filename)) {

@@ -108,11 +113,14 @@ ranges.push({

} else if (checkImplicit.isImplicitComponent(config.implicitComponents, filename)) {
var defined = path.basename(filename).split('.')[0]
let defined = stripUnderscore(path.basename(filename).split('.')[0]);
if (defined === 'index') {
defined = path.basename(path.join(filename, '..'));
}
if (defined !== UTILITIES_IDENT && !toRegexp(config.componentNamePattern).test(defined)) {
result.warn(
'Invalid component name from implicit conversion from filename ' + filename
`Invalid component name from implicit conversion from filename ${filename}`
);
}
ranges.push({
defined: defined,
defined,
start: 0,

@@ -124,4 +132,4 @@ weakMode: false,

root.walkComments(function(comment) {
var commentStartLine = (comment.source) ? comment.source.start.line : null;
root.walkComments((comment) => {
const commentStartLine = (comment.source) ? comment.source.start.line : null;
if (!commentStartLine) return;

@@ -134,9 +142,9 @@

var directiveMatch = comment.text.match(DEFINE_DIRECTIVE);
const directiveMatch = comment.text.match(DEFINE_DIRECTIVE);
if (!directiveMatch) return;
var defined = (directiveMatch[1] || directiveMatch[3]).trim();
const defined = (directiveMatch[1] || directiveMatch[3]).trim();
if (defined !== UTILITIES_IDENT && !toRegexp(config.componentNamePattern).test(defined)) {
result.warn(
'Invalid component name in definition /*' + comment + '*/',
{ node: comment }
`Invalid component name in definition /*${comment}*/`,
{node: comment}
);

@@ -146,3 +154,3 @@ }

ranges.push({
defined: defined,
defined,
start: commentStartLine,

@@ -156,3 +164,3 @@ weakMode: directiveMatch[2] === WEAK_IDENT,

if (!ranges.length) return;
var lastRange = ranges[ranges.length - 1];
const lastRange = ranges[ranges.length - 1];
if (lastRange.end) return;

@@ -159,0 +167,0 @@ lastRange.end = line;

@@ -1,8 +0,8 @@

var path = require('path');
var minimatch = require('minimatch');
'use strict';
const path = require('path');
const minimatch = require('minimatch');
function minimatchList(path, patternList, options) {
return patternList.some(function(pattern) {
return minimatch(path, pattern, options)
});
return patternList.some(pattern => minimatch(path, pattern, options));
}

@@ -50,4 +50,4 @@

module.exports = {
isImplicitComponent: isImplicitComponent,
isImplicitUtilities: isImplicitUtilities,
isImplicitComponent,
isImplicitUtilities,
};

@@ -0,1 +1,3 @@

'use strict';
module.exports.IGNORE_COMMENT = 'postcss-bem-linter: ignore';

@@ -1,3 +0,5 @@

var presetPatterns = require('./preset-patterns');
'use strict';
const presetPatterns = require('./preset-patterns');
/**

@@ -19,4 +21,4 @@ * Given some user options, put together a config object that

*/
module.exports = function(primaryOptions, secondaryOptions) {
var patterns = primaryOptions || 'suit';
module.exports = (primaryOptions, secondaryOptions) => {
let patterns = primaryOptions || 'suit';
if (typeof patterns === 'string') {

@@ -45,3 +47,3 @@ patterns = presetPatterns[patterns];

var presetOptions = secondaryOptions || {};
let presetOptions = secondaryOptions || {};
if (primaryOptions && primaryOptions.presetOptions) {

@@ -51,18 +53,18 @@ presetOptions = primaryOptions.presetOptions;

var implicitComponents =
const implicitComponents =
getImplicitDefineValue('implicitComponents', primaryOptions, secondaryOptions);
var implicitUtilities =
const implicitUtilities =
getImplicitDefineValue('implicitUtilities', primaryOptions, secondaryOptions);
return {
patterns: patterns,
presetOptions: presetOptions,
patterns,
presetOptions,
componentNamePattern: patterns.componentName || /^[-_a-zA-Z0-9]+$/,
implicitComponents: implicitComponents,
implicitUtilities: implicitUtilities,
implicitComponents,
implicitUtilities,
};
}
};
function getImplicitDefineValue(key, primaryOptions, secondaryOptions) {
var implicitValue = false;
let implicitValue = false;

@@ -72,3 +74,3 @@ if (secondaryOptions && secondaryOptions[key] !== undefined) {

} else if (primaryOptions && primaryOptions[key]) {
implicitValue = primaryOptions[key]
implicitValue = primaryOptions[key];
}

@@ -81,2 +83,2 @@

return implicitValue;
}
}

@@ -1,19 +0,23 @@

var resolveNestedSelector = require('postcss-resolve-nested-selector');
'use strict';
function isTopLevel(node) {
return node.type === 'root';
}
const resolveNestedSelector = require('postcss-resolve-nested-selector');
function isNestedRule(node) {
return /(?:at)?rule/.test(node.parent.type)
return /(?:at)?rule/.test(node.parent.type);
}
function hasChildNodes(node) {
return node.nodes && node.nodes.length;
}
function hasNoDeclarations(node) {
return node.nodes && node.nodes.length && node.every(function(child) {
return child.type !== 'decl';
});
return hasChildNodes(node) && node.every(child => child.type !== 'decl');
}
function hasOnlyExtends(node) {
return hasChildNodes(node) && node.every(child => child.type === 'atrule' && child.name === 'extend');
}
function getComponentRootRule(node) {
while (!isTopLevel(node.parent)) {
while (node.root() !== node) {
node = node.parent;

@@ -25,7 +29,7 @@ }

function unWrapSelectors(parent, rule) {
var selectors = [];
parent.walkRules(function(node) {
let selectors = [];
parent.walkRules((node) => {
// Only unwrap as far as the current rule being linted
if (node.selector !== rule.selector) {return;}
node.selectors.forEach(function(selector) {
node.selectors.forEach((selector) => {
selectors = selectors.concat(resolveNestedSelector(selector, node));

@@ -39,4 +43,4 @@ });

// Skip validation on rules with no declarations
// as these don't exist after rules have been unwrapped
if (hasNoDeclarations(rule)) {
// as these don't exist after rules have been unwrapped (unless the selector contains only a @extend)
if (hasNoDeclarations(rule) && !hasOnlyExtends(rule)) {
return [];

@@ -46,4 +50,4 @@ }

if (isNestedRule(rule)) {
var componentRootRule = getComponentRootRule(rule);
var nestedSelectors = unWrapSelectors(componentRootRule, rule);
const componentRootRule = getComponentRootRule(rule);
const nestedSelectors = unWrapSelectors(componentRootRule, rule);
return nestedSelectors;

@@ -50,0 +54,0 @@ }

@@ -0,1 +1,3 @@

'use strict';
/**

@@ -14,9 +16,7 @@ * Extract an array of selector sequences from a selector string ---

*/
module.exports = function(selector) {
var withoutPseudos = selector.split(':')[0];
module.exports = (selector) => {
const withoutPseudos = selector.split(':')[0];
return withoutPseudos
.split(/[\s>+~]/)
.filter(function(s) {
return s !== '';
});
}
.filter(s => s !== '');
};

@@ -0,1 +1,3 @@

'use strict';
module.exports = {

@@ -20,13 +22,13 @@ suit: {

function suitSelector(componentName, presetOptions) {
var ns = (presetOptions && presetOptions.namespace) ? presetOptions.namespace + '-' : '';
var WORD = '[a-z0-9][a-zA-Z0-9]*';
var descendant = '(?:-' + WORD + ')?';
var modifier = '(?:--' + WORD + '(?:\\.' + ns + componentName + descendant + '--' + WORD + ')*)?';
var attribute = '(?:\\[.+\\])?';
var state = '(?:\\.is-' + WORD + ')*';
var body = descendant +
const ns = (presetOptions && presetOptions.namespace) ? `${presetOptions.namespace}-` : '';
const WORD = '[a-z0-9][a-zA-Z0-9]*';
const descendant = `(?:-${WORD})?`;
const modifier = `(?:--${WORD}(?:\\.${ns}${componentName}${descendant}--${WORD})*)?`;
const attribute = '(?:\\[.+\\])?';
const state = `(?:\\.is-${WORD})*`;
const body = descendant +
modifier +
attribute +
state;
return new RegExp('^\\.' + ns + componentName + '\\b' + body + '$');
return new RegExp(`^\\.${ns}${componentName}\\b${body}$`);
}

@@ -41,8 +43,8 @@

function bemSelector(block, presetOptions) {
var ns = (presetOptions && presetOptions.namespace) ? presetOptions.namespace + '-': '';
var WORD = '[a-zA-Z0-9]+(?:-[a-zA-Z0-9]+)*';
var element = '(?:__' + WORD + ')?';
var modifier = '(?:_' + WORD + '){0,2}';
var attribute = '(?:\\[.+\\])?';
return new RegExp('^\\.' + ns + block + element + modifier + attribute + '$');
const ns = (presetOptions && presetOptions.namespace) ? `${presetOptions.namespace}-` : '';
const WORD = '[a-zA-Z0-9]+(?:-[a-zA-Z0-9]+)*';
const element = `(?:__${WORD})?`;
const modifier = `(?:_${WORD}){0,2}`;
const attribute = '(?:\\[.+\\])?';
return new RegExp(`^\\.${ns}${block}${element}${modifier}${attribute}$`);
}

@@ -1,6 +0,8 @@

var constants = require('./constants');
'use strict';
const constants = require('./constants');
// patterns can be a single regexp or an array of regexps
module.exports = function(customProperty, declaration, patterns) {
var previousNode = declaration.prev();
module.exports = (customProperty, declaration, patterns) => {
const previousNode = declaration.prev();
if (

@@ -12,7 +14,5 @@ previousNode

if (!patterns) return;
if (!patterns) return false;
return [].concat(patterns).some(function(p) {
return p.test(customProperty);
});
}
return [].concat(patterns).some(p => p.test(customProperty));
};

@@ -1,5 +0,7 @@

var constants = require('./constants');
'use strict';
module.exports = function(rule) {
var previousNode = rule.prev();
const constants = require('./constants');
module.exports = (rule) => {
const previousNode = rule.prev();
return (

@@ -10,2 +12,2 @@ previousNode

);
}
};

@@ -0,7 +1,7 @@

'use strict';
// patterns can be a single regexp or an array of regexps
module.exports = function(selector, patterns) {
if (!patterns) return;
return [].concat(patterns).some(function(p) {
return p.test(selector);
});
}
module.exports = (selector, patterns) => {
if (!patterns) return false;
return [].concat(patterns).some(p => p.test(selector));
};

@@ -1,14 +0,15 @@

module.exports = function(source) {
'use strict';
module.exports = (source) => {
if (typeof source === 'string') {
var splitSource = source.split('{componentName}');
return function(componentName) {
const splitSource = source.split('{componentName}');
return (componentName) => {
try {
return new RegExp(splitSource.length > 1 ? splitSource[0] + componentName + splitSource[1] : splitSource[0]);
} catch (e) {
throw new Error('"' + source + '" does not produce a valid regular expression');
throw new Error(`"${source}" does not produce a valid regular expression`);
}
}
} else {
return source;
};
}
}
return source;
};

@@ -1,7 +0,8 @@

module.exports = function(source) {
'use strict';
module.exports = (source) => {
if (Array.isArray(source)) {
return source.map(regexpify);
} else {
return regexpify(source);
}
return regexpify(source);
};

@@ -18,3 +19,3 @@

} catch (e) {
throw new Error('"' + source + '" is not a valid regular expression');
throw new Error(`"${source}" is not a valid regular expression`);
}

@@ -21,0 +22,0 @@ } else {

@@ -1,3 +0,5 @@

var shouldIgnoreCustomProperty = require('./should-ignore-custom-property');
'use strict';
const shouldIgnoreCustomProperty = require('./should-ignore-custom-property');
/**

@@ -10,5 +12,5 @@ * @param {Object} config

*/
module.exports = function(config) {
config.rule.walkDecls(function(declaration) {
var property = declaration.prop;
module.exports = (config) => {
config.rule.walkDecls((declaration) => {
const property = declaration.prop;

@@ -19,11 +21,9 @@ if (property.indexOf('--') !== 0) return;

if (property.indexOf(config.componentName + '-') === 2) return;
if (property.indexOf(`${config.componentName}-`) === 2) return;
config.result.warn(
'Invalid custom property name "' + property + '": ' +
'a component\'s custom properties must start with the ' +
'component name',
{ node: declaration }
`Invalid custom property name "${property}": a component's custom properties must start with the component name`,
{node: declaration}
);
});
}
};

@@ -1,7 +0,9 @@

var listSequences = require('./list-sequences');
var shouldIgnoreRule = require('./should-ignore-rule');
var shouldIgnoreSelector = require('./should-ignore-selector');
var toInterpoloatedRegexp = require('./to-interpolated-regexp');
var getSelectors = require('./get-selectors');
'use strict';
const listSequences = require('./list-sequences');
const shouldIgnoreRule = require('./should-ignore-rule');
const shouldIgnoreSelector = require('./should-ignore-selector');
const toInterpoloatedRegexp = require('./to-interpolated-regexp');
const getSelectors = require('./get-selectors');
/**

@@ -17,21 +19,21 @@ * @param {Object} config

*/
module.exports = function(config) {
module.exports = (config) => {
if (shouldIgnoreRule(config.rule)) return;
var rule = config.rule;
const rule = config.rule;
var initialPattern = (config.selectorPattern.initial)
const initialPattern = (config.selectorPattern.initial)
? toInterpoloatedRegexp(config.selectorPattern.initial)(config.componentName, config.selectorPatternOptions)
: toInterpoloatedRegexp(config.selectorPattern)(config.componentName, config.selectorPatternOptions);
var combinedPattern = (config.selectorPattern.combined)
const combinedPattern = (config.selectorPattern.combined)
? toInterpoloatedRegexp(config.selectorPattern.combined)(config.componentName, config.selectorPatternOptions)
: toInterpoloatedRegexp(initialPattern);
var selectors = getSelectors(rule);
const selectors = getSelectors(rule);
selectors.forEach(function(selector) {
selectors.forEach((selector) => {
// Don't bother with :root
if (selector === ':root') return;
var allSequences = listSequences(selector);
var sequence;
for (var i = 0, l = allSequences.length; i < l; i++) {
const allSequences = listSequences(selector);
let sequence;
for (let i = 0, l = allSequences.length; i < l; i++) {
if (config.weakMode && i !== 0) return;

@@ -44,3 +46,3 @@ sequence = allSequences[i];

config.result.warn(
'Invalid component selector "' + selector + '"',
`Invalid component selector "${selector}"`,
{

@@ -54,2 +56,2 @@ node: rule,

});
}
};

@@ -1,6 +0,8 @@

var listSequences = require('./list-sequences');
var shouldIgnoreRule = require('./should-ignore-rule');
var shouldIgnoreSelector = require('./should-ignore-selector');
var getSelectors = require('./get-selectors');
'use strict';
const listSequences = require('./list-sequences');
const shouldIgnoreRule = require('./should-ignore-rule');
const shouldIgnoreSelector = require('./should-ignore-selector');
const getSelectors = require('./get-selectors');
/**

@@ -13,15 +15,13 @@ * @param {Object} config

*/
module.exports = function(config) {
module.exports = (config) => {
if (shouldIgnoreRule(config.rule)) return;
var selectors = getSelectors(config.rule)
const selectors = getSelectors(config.rule);
selectors.forEach(function(selector) {
var allSequences = listSequences(selector);
var sequence;
for (var i = 0, l = allSequences.length; i < l; i++) {
sequence = allSequences[i];
selectors.forEach((selector) => {
const allSequences = listSequences(selector);
for (const sequence of allSequences) {
if (config.ignorePattern && shouldIgnoreSelector(sequence, config.ignorePattern)) continue;
if (config.utilityPattern.test(sequence)) continue;
config.result.warn(
'Invalid utility selector "' + selector + '"',
`Invalid utility selector "${selector}"`,
{

@@ -35,2 +35,2 @@ node: config.rule,

});
}
};
{
"name": "postcss-bem-linter",
"version": "2.7.1",
"version": "3.0.0",
"description": "A BEM linter for postcss",

@@ -11,14 +11,26 @@ "files": [

"minimatch": "^3.0.3",
"postcss": "^5.0.0",
"postcss": "^6.0.6",
"postcss-resolve-nested-selector": "^0.1.1"
},
"devDependencies": {
"eslint": "1.7.3",
"mocha": "2.3.3"
"eslint": "^3.19.0",
"eslint-config-airbnb": "^15.0.2",
"eslint-plugin-import": "^2.7.0",
"eslint-plugin-jsx-a11y": "^5.1.1",
"eslint-plugin-react": "^7.1.0",
"jest": "^20.0.4"
},
"scripts": {
"lint": "eslint .",
"start": "mocha --reporter spec --watch",
"test": "npm run lint && mocha --no-colors test/index.js"
"lint": "eslint lib test index.js",
"start": "jest --watch",
"test": "jest",
"posttest": "npm run lint"
},
"jest": {
"testRegex": "test/.*\\.js",
"testPathIgnorePatterns": [
"/node_modules/",
"test-util"
]
},
"license": "MIT",

@@ -25,0 +37,0 @@ "repository": {

@@ -369,9 +369,9 @@ # postcss-bem-linter

```css
/* @define Foo */
/** @define Foo */
.Foo {}
/* @define Bar */
/** @define Bar */
.Bar {}
/* @define utilities */
/** @define utilities */
.u-something {}

@@ -381,8 +381,8 @@ ```

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

@@ -389,0 +389,0 @@ .something-something-something {}

SocketSocket SOC 2 Logo

Product

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

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc