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

Allow to define sub-settings by module #6

Merged
merged 9 commits into from
Feb 9, 2017
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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# EditorConfig helps developers define and maintain consistent
# coding styles between different editors and IDEs
# editorconfig.org

root = true


[*]

# Change these settings to your own preference
indent_style = space
indent_size = 2

# We recommend you to keep these unchanged
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true

[*.md]
trim_trailing_whitespace = false
8 changes: 0 additions & 8 deletions TODO.md

This file was deleted.

30 changes: 27 additions & 3 deletions packages/bemlinter/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -101,11 +101,11 @@ default: `true`

To set the authorized class prefix

default: `['']`
default: `''`

```json
{
"classPrefix": ["c-"]
"classPrefix": "c-"
}
```

Expand All @@ -119,7 +119,31 @@ default: `'([^.]*)\.s?css'`

```json
{
"filePattern": "(?:project-)?([^.]*)\.scss"
"filePattern": "(?:module-)?([^.]*)\.scss"
}
```

### modules (option)

Allow to override global option for portions of your sources

:warning: A module should have, at least `name` and `sources` properties

default: `[]`

```json
{
"modules": [
{
"name": 'my-module',
"sources": [
"a/path/to/your/module/folder/*.scss",
"a/path/to/a/module/file.scss
]
"classPrefix": "mm-",
"filePattern": "my-module-([^.]*)\.scss"
}
]
}
```

Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,33 @@
exports[`Bemlinter of multiple files should lint with crossed error 1`] = `
" ✗ block
[block.scss:8] Error: \".c-other-block\" is incoherent with the file name.
other-block
[block.scss:8] Error: \".c-other-block\" should not be styled outside of its own stylesheet.
exports[`Bemlinter of crossed styled files should log error on both blocks 1`] = `
" ✗ external
[leak.scss:8] Error: \".c-external\" should not be styled outside of its own stylesheet.
leak
[leak.scss:8] Error: \".c-external\" is incoherent with the file name.

FAIL: bemlinter has detected 2 errors on 2 blocks."
`;

exports[`Bemlinter of multiple files should lint without the crossed error on the excluded block 1`] = `
" ✗ block
[block.scss:8] Error: \".c-other-block\" is incoherent with the file name.
exports[`Bemlinter of crossed styled files should not log error on the external block 1`] = `
" ✗ leak
[leak.scss:8] Error: \".c-external\" is incoherent with the file name.

FAIL: bemlinter has detected 1 error on 1 block."
`;

exports[`Bemlinter of multi-modules files should detect the module and the associate leak styles 1`] = `
" ✗ unprefixed
[unprefixed.scss:8] Error: \".c-prefixed\" is incoherent with the file name.
✗ module / prefixed
[unprefixed.scss:8] Error: \".c-prefixed\" should not be styled outside of its own stylesheet.

FAIL: bemlinter has detected 2 errors on 2 blocks."
`;

exports[`Bemlinter of multi-modules files should detect the module and the missing prefix 1`] = `
" ✗ unprefixed
[unprefixed.scss:8] Error: \".c-prefixed\" is incoherent with the file name.
✗ module / prefixed
[module-prefixed.scss:1] Error: \".c-prefixed\" is incoherent with the file name.

FAIL: bemlinter has detected 2 errors on 2 blocks."
`;
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
exports[`Bemlinter of ProjectAlright.scss should lint without error 1`] = `"OK: bemlinter has validated 1 block."`;
exports[`Bemlinter of ModuleAlright.scss should lint without error 1`] = `"OK: bemlinter has validated 1 block."`;

exports[`Bemlinter of alright.scss should lint without error 1`] = `"OK: bemlinter has validated 1 block."`;

Expand Down Expand Up @@ -31,8 +31,6 @@ exports[`Bemlinter of prefix.scss should lint with a missing prefix error 1`] =
FAIL: bemlinter has detected 1 error on 1 block."
`;

exports[`Bemlinter of prefix.scss should lint without error 1`] = `"OK: bemlinter has validated 1 block."`;

exports[`Bemlinter of syntax.scss should lint with 6 different syntax error 1`] = `
" ✗ syntax
[syntax.scss:21] Error: \".syntax---big\" modifier should have only 2 dashes.
Expand All @@ -56,6 +54,13 @@ exports[`Bemlinter of syntax.scss should lint without a lower case error 1`] = `
FAIL: bemlinter has detected 5 errors on 1 block."
`;

exports[`Bemlinter of unreadable.scss should log a block as unreadable 1`] = `
" ✗ unreadable
[unreadable.scss] Error: Can\'t handle character: \"Û\" (1:0)

FAIL: bemlinter has detected 1 error on 1 block."
`;

exports[`Bemlinter of warning.scss should warn the use of an external block 1`] = `
" ✓ warning
[warning.scss:21] Warning: \".external-block\" is only tolerated in this stylesheet.
Expand Down
29 changes: 24 additions & 5 deletions packages/bemlinter/__tests__/multiple-files.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,30 @@ const snap = (fileName, done, options = {}) => {
;
};

describe('Bemlinter of multiple files', () => {
it('should lint with crossed error', done => snap('cross-styling/*.scss', done, {classPrefix: ['c-']}));
describe('Bemlinter of crossed styled files', () => {
it('should log error on both blocks', done => snap('cross-styling/*.scss', done, {classPrefix: 'c-'}));

it('should lint without the crossed error on the excluded block', done => snap('cross-styling/*.scss', done, {
excludeBlock: ['other-block'],
classPrefix: ['c-']
it('should not log error on the external block', done => snap('cross-styling/*.scss', done, {
excludeBlock: ['external'],
classPrefix: 'c-'
}));
});

describe('Bemlinter of multi-modules files', () => {
it('should detect the module and the missing prefix', done => snap('mixed-settings/*.scss', done, {
modules: [{
name: 'module',
sources: [`${__dirname}/sources/mixed-settings/module-prefixed.scss`],
filePattern: 'module-([^.]*)\.scss'
}]
}));

it('should detect the module and the associate leak styles', done => snap('mixed-settings/*.scss', done, {
modules: [{
name: 'module',
sources: [`${__dirname}/sources/mixed-settings/module-prefixed.scss`],
classPrefix: 'c-',
filePattern: 'module-([^.]*)\.scss'
}]
}));
});
14 changes: 8 additions & 6 deletions packages/bemlinter/__tests__/single-file.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,9 @@ describe('Bemlinter of alright.scss', () => {
it('should lint without error', done => snap(`alright.scss`, done));
});

describe('Bemlinter of ProjectAlright.scss', () => {
it('should lint without error', done => snap(`ProjectAlright.scss`, done, {
filePattern: '(?:Project)?([^.]*)\.scss'
describe('Bemlinter of ModuleAlright.scss', () => {
it('should lint without error', done => snap(`ModuleAlright.scss`, done, {
filePattern: '(?:Module)?([^.]*)\.scss'
}));
});

Expand All @@ -29,9 +29,7 @@ describe('Bemlinter of warning.scss', () => {
});

describe('Bemlinter of prefix.scss', () => {
it('should lint with a missing prefix error', done => snap(`prefix.scss`, done, {classPrefix: ['c-']}));

it('should lint without error', done => snap(`prefix.scss`, done, {classPrefix: ['', 'c-']}));
it('should lint with a missing prefix error', done => snap(`prefix.scss`, done, {classPrefix: 'c-'}));
});

describe('Bemlinter of leak.scss', () => {
Expand All @@ -50,4 +48,8 @@ describe('Bemlinter of syntax.scss', () => {

describe('Bemlinter of class-concat.scss', () => {
it('should detect class concatenation', done => snap(`class-concat.scss`, done));
});

describe('Bemlinter of unreadable.scss', () => {
it('should log a block as unreadable', done => snap(`unreadable.scss`, done));
});
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
.c-other-block {
.c-external {
display: block;
position: absolute;
z-index: 10;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
.c-block {
.c-leak {
display: block;
position: absolute;
z-index: 10;
top: 50%;
transform: translateY(-50%);

.c-other-block {
.c-external {
display: none;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
.c-prefixed {
display: block;
position: absolute;
z-index: 10;
top: 50%;
transform: translateY(-50%);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
.unprefixed {
display: block;
position: absolute;
z-index: 10;
top: 50%;
transform: translateY(-50%);

.c-prefixed {
display: none;
}
}
1 change: 1 addition & 0 deletions packages/bemlinter/__tests__/sources/unreadable.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Û*$ù$
46 changes: 18 additions & 28 deletions packages/bemlinter/src/bem.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,61 +2,51 @@ const _ = require('lodash');
const path = require('path');
const paramCase = require('param-case');

module.exports = function (classPrefixList, blockRegExp) {
module.exports = function (options) {
const blockRegExp = new RegExp(options.filePattern);

function getBlockNameFromFile(filePath) {
const fileName = path.basename(filePath);
const match = blockRegExp.exec(fileName);
if (!match) {
console.error(`No block name found for this ${fileName}. Is your filePattern option correct?`);
return fileName;
} else if (match.length > 2) {
console.error('Only one capturing group is authorized in filePattern!');
return fileName;
}

return paramCase(match[1]);
}

function getBlockNameFromClass(className) {
function getBlockNameFromClass(className, classPrefix = options.classPrefix) {
const blockName = className.split('__')[0].split('--')[0];
const currentClassPrefix = _.find(classPrefixList, classPrefix => _.startsWith(className, classPrefix));
if (!currentClassPrefix) {
return blockName;
if (_.startsWith(className, classPrefix)) {
return blockName.slice(classPrefix.length);
}
return blockName.slice(currentClassPrefix.length);
return blockName;
}

function isBlockName(className, blockName, withPrefixList = classPrefixList) {
return _.some(withPrefixList, classPrefix => {
const prefixedBlockName = `${classPrefix}${blockName}`;
return (
className === prefixedBlockName ||
_.startsWith(className, `${prefixedBlockName}--`) ||
_.startsWith(className, `${prefixedBlockName}__`)
);
});
function isBlockName(className, blockName, classPrefix = options.classPrefix) {
const prefixedBlockName = `${classPrefix}${blockName}`;
return (
className === prefixedBlockName ||
_.startsWith(className, `${prefixedBlockName}--`) ||
_.startsWith(className, `${prefixedBlockName}__`)
);
}

function isClassPrefixMissing(className, blockName) {
return (
classPrefixList.indexOf('') === -1 &&
isBlockName(className, blockName, [''])
options.classPrefix !== '' &&
isBlockName(className, blockName, '')
);
}

function isAnotherBlockName(className, blockList, actualBlockName) {
return _.some(blockList, blockName => {
return (
blockName !== actualBlockName &&
isBlockName(className, blockName, classPrefixList)
);
});
}

return {
getBlockNameFromFile,
getBlockNameFromClass,
isBlockName,
isClassPrefixMissing,
isAnotherBlockName
isClassPrefixMissing
};
};
Loading