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

lesshint

Package Overview
Dependencies
Maintainers
2
Versions
91
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

lesshint - npm Package Compare versions

Comparing version 1.3.1 to 1.4.0

lib/linters/depth_level.js

17

.eslintrc.json

@@ -20,6 +20,12 @@ {

"eqeqeq": 2,
"func-style": [2, "expression"],
"guard-for-in": 2,
"indent": [2, 4, { "SwitchCase": 1, "VariableDeclarator": 0 }],
"indent": [2, 4, {
"SwitchCase": 1,
"VariableDeclarator": 0
}],
"key-spacing": 2,
"keyword-spacing": [2, {
"after": true,
"before": true
}],
"newline-after-var": 2,

@@ -38,8 +44,9 @@ "no-caller": 2,

"semi": 2,
"space-after-keywords": 2,
"space-before-blocks": 2,
"space-before-function-paren": 2,
"space-in-parens": 2,
"space-return-throw-case": 2,
"space-unary-ops": [2, { "words": true, "nonwords": false }],
"space-unary-ops": [2, {
"nonwords": false,
"words": true
}],
"strict": [2, "global"],

@@ -46,0 +53,0 @@ "vars-on-top": 2,

# Changelog
## 1.4.0 (2016-03-01)
* Added the following linters:
* `depthLevel` ([18bb203](https://github.com/lesshint/lesshint/commit/18bb2038be240f9805b0a8a8756fe700cbe47526))
* Added support for configuration using inline comments. ([cf757cd](https://github.com/lesshint/lesshint/commit/cf757cd9741cffeef966885de76168d50dc58716))
* Added a `18f` option to `singleLinePerSelector`. ([2f65c31](https://github.com/lesshint/lesshint/commit/2f65c3175ff3bd1b2b56daa4250ac8c505602bfb))
* Fixed an issue where `singleLinePerProperty` would erroneously report mixins without semicolons. ([ef97361](https://github.com/lesshint/lesshint/commit/ef9736100f3b5b481140e2fc25aaca9c5374d3c1))
* Fixed an issue where `spaceAroundOperator` would erroneously report negative numbers. ([2569d73](https://github.com/lesshint/lesshint/commit/2569d7347f2aae6bb068b5edcddabca03a0df734))
* Fixed an issue where `trailingWhitespace` would output errors when checking empty files. ([26ba39b](https://github.com/lesshint/lesshint/commit/26ba39b9bebc815edc4bf3393a168a6dd8e84ca0))
* Fixed an issue where `importPath` would erroneously report files with different file extensions than `.less`. ([b7610dd](https://github.com/lesshint/lesshint/commit/b7610dd0355d296bcfe25c558d51990878a649eb))
* Fixed an issue where `singleLinePerSelector` would erroneously report selectors with the comma on a new line. ([637ff49](https://github.com/lesshint/lesshint/commit/637ff4917d5721d987b1baaeb273e80026058602))
* Fixed an issue where `finalNewline` would sometimes report the wrong line. ([12981cd](https://github.com/lesshint/lesshint/commit/12981cde36c02a5b81586debbab0c4f9533a701e))
* Updated ESLint to `2.x` ([4c14d3a](https://github.com/lesshint/lesshint/commit/4c14d3af674267bc22ccbfc6068e774c6c4eef69))
## 1.3.1 (2016-02-12)

@@ -3,0 +16,0 @@ * Fixed an issue where `spaceAroundOperator` would erroneously try to check negative values. ([fe37b21](https://github.com/lesshint/lesshint/commit/fe37b21b29c2d5ae9e1a18b5060a16ba4eec9168))

@@ -96,8 +96,2 @@ 'use strict';

if (!results.length) {
exitDefer.resolve(EXIT_CODES.OK);
return;
}
reporter = getReporter(program.reporter);

@@ -116,2 +110,8 @@

if (!results.length) {
exitDefer.resolve(EXIT_CODES.OK);
return;
}
hasError = results.some(function (result) {

@@ -118,0 +118,0 @@ return result.severity === 'error';

@@ -26,2 +26,7 @@ {

"depthLevel": {
"enabled": false,
"depth": 3
},
"duplicateProperty": {

@@ -108,3 +113,4 @@ "enabled": true,

"singleLinePerSelector": {
"enabled": true
"enabled": true,
"style": "none"
},

@@ -111,0 +117,0 @@

@@ -95,2 +95,3 @@ 'use strict';

file: path.basename(checkPath),
fullPath: checkPath,
line: lineNo,

@@ -97,0 +98,0 @@ linter: 'parse error',

@@ -6,2 +6,3 @@ 'use strict';

var merge = require('lodash.merge');
var helpers = require('./helpers');
var path = require('path');

@@ -14,2 +15,3 @@

require('./linters/decimal_zero'),
require('./linters/depth_level'),
require('./linters/duplicate_property'),

@@ -45,2 +47,44 @@ require('./linters/empty_rule'),

var parseRules = function (node) {
var rules = node.content.match(/^\s*lesshint\s+(.*)/);
if (!rules) {
return {};
}
rules = rules[1].trim();
rules = rules.replace(/([a-z0-9]+)\s*:/ig, '"$1":');
try {
rules = JSON.parse('{' + rules + '}');
} catch (e) {
throw new Error('Invalid inline option on line ' + node.start.line);
}
// If it's only shorthand enabled or disabled, account for that
Object.keys(rules).forEach(function (rule) {
if (typeof rules[rule] === 'boolean') {
rules[rule] = {
enabled: rules[rule]
};
}
});
return rules;
};
var getInlineOptions = function (node) {
var start;
node = helpers.ensureObject(node);
start = helpers.ensureObject(node.start);
// Not the first thing in the file, bail
if (start.line !== 1 && start.column !== 1) {
return {};
}
return parseRules(node);
};
exports.resultSeverity = {

@@ -53,3 +97,6 @@ error: 'error',

var filename = path.basename(fullPath);
var lineOptions = [];
var results = [];
var inlineOptions;
var firstComment;
var lines;

@@ -60,3 +107,2 @@ var ast;

lines = input.split('\n');
ast = this.parseAST(input);

@@ -67,2 +113,19 @@

// Fetch inline options and merge it with whatever passed
firstComment = ast.first('multilineComment') || ast.first('singlelineComment');
inlineOptions = getInlineOptions(firstComment);
config = merge(config, inlineOptions);
// Fetch all single line options before we start the actual linting
ast.traverseByTypes(['multilineComment', 'singlelineComment'], function (node) {
var option = parseRules(node);
var key = Object.keys(option)[0];
option[key] = merge(option[key], {
line: node.start.line
});
lineOptions.push(option);
});
ast.traverse(function (node) {

@@ -92,3 +155,16 @@ linters.forEach(function (linter) {

var line = piece.line || node.start.line;
var shouldIgnore = lineOptions.some(function (lineOption) {
lineOption = lineOption[linter.name];
if (!lineOption) {
return false;
}
return lineOption.line === line && !lineOption.enabled;
});
if (shouldIgnore) {
return;
}
/**

@@ -102,2 +178,3 @@ * Each piece of lint (linter result) can override

file: filename,
fullPath: fullPath,
line: line,

@@ -104,0 +181,0 @@ linter: linter.name,

@@ -13,4 +13,4 @@ 'use strict';

return [{
column: 0,
line: node.content.length,
column: maybeLine.end.column + 1,
line: maybeLine.end.line,
message: this.message

@@ -17,0 +17,0 @@ }];

@@ -46,3 +46,3 @@ 'use strict';

case false:
if (path.extname(file)) {
if (path.extname(file) === '.less') {
results.push({

@@ -49,0 +49,0 @@ column: value.start.column,

@@ -7,2 +7,3 @@ # Available linters

* [decimalZero](#decimalzero)
* [depthLevel](#depthLevel)
* [duplicateProperty](#duplicateproperty)

@@ -17,3 +18,2 @@ * [emptyRule](#emptyrule)

* [importPath](#importpath)
* [leadingZero](#leadingzero)
* [propertyOrdering](#propertyordering)

@@ -35,3 +35,2 @@ * [propertyUnits](#propertyunits)

* [trailingWhitespace](#trailingwhitespace)
* [trailingZero](#trailingzero)
* [urlFormat](#urlformat)

@@ -145,3 +144,38 @@ * [urlQuotes](#urlquotes)

```
## depthLevel
Sets the depth of nested styles in every parent style.
Option | Description
---------- | -------------
`depth` | From 1-'n' levels of Depth, 3 (**default**).
### invalid (depth 3)
```less
.foo {
margin-right: 0;
.foo-2 {
color: red;
.foo-3 {
width: 100%;
.foo-4 {
height: 100%;
}
}
}
}
```
### valid
```less
.foo {
margin-right: 0;
.foo-2 {
color: red;
.foo-3 {
width: 100%;
}
}
}
```
## duplicateProperty

@@ -487,2 +521,8 @@ There shouldn't be any duplicate properties since this is usually an error, causing unexpected bugs.

Option | Description
---------- | ----------
`style` | `18f`, `none` (**default**)
The `18f` option refers to the [18F Style Guide](https://pages.18f.gov/frontend/css-coding-styleguide/format/).
### invalid

@@ -493,2 +533,7 @@ ```less

}
// Style "18f"
.foobar, .baz {
color: red;
}
```

@@ -502,2 +547,7 @@

}
// Style "18f"
.foo, .bar {
color: red;
}
```

@@ -504,0 +554,0 @@

@@ -54,2 +54,4 @@ 'use strict';

next = helpers.ensureObject(node.get(index + 2));
} else if (!next.type) {
isValid = true;
}

@@ -56,0 +58,0 @@

'use strict';
var helpers = require('../helpers');
module.exports = {

@@ -9,2 +11,3 @@ name: 'singleLinePerSelector',

lint: function singleLinePerSelectorLinter (config, node) {
var report = false;
var results = [];

@@ -14,5 +17,29 @@ var self = this;

node.forEach('delimiter', function (element, index) {
element = node.get(index + 1);
element = helpers.ensureObject(node.get(index + 1));
if (element.content.indexOf('\n') === -1) {
// Check if the delimiter is on the next line
if (element.type !== 'space') {
element = helpers.ensureObject(node.get(index - 1));
}
switch (config.style) {
case '18f':
node.forEach('selector', function (selector) {
selector = helpers.ensureObject(selector.first().first('ident'));
selector = selector.content;
if (selector && selector.length >= 5) {
report = true;
return;
}
});
break;
default:
report = true;
break;
}
if (report && element.content.indexOf('\n') === -1) {
results.push({

@@ -19,0 +46,0 @@ column: element.start.column,

@@ -38,2 +38,8 @@ 'use strict';

// Ignore negative numbers/regular shorthand natations
if (element.content === '-' && prevElement.type === 'space' &&
['dimension', 'number', 'percentage'].indexOf(nextElement.type) !== -1) {
return;
}
switch (config.style) {

@@ -40,0 +46,0 @@ case 'both':

@@ -12,4 +12,10 @@ 'use strict';

//Ignore empty files
if (node.content.length === 0) {
return;
}
// We'll convert the AST to the Less source and just loop through each line
node = node.toString('less') || '';
node.split('\n').forEach(function (line, index) {

@@ -16,0 +22,0 @@ if (/[ \t]+$/g.test(line)) {

{
"name": "lesshint",
"description": "A tool to aid you in writing clean and consistent Less.",
"version": "1.3.1",
"version": "1.4.0",
"main": "./lib/lesshint.js",

@@ -39,3 +39,3 @@ "author": {

"gulp-debug-finder": "^1.0.0",
"gulp-eslint": "^1.1.1",
"gulp-eslint": "^2.0.0",
"gulp-istanbul": "^0.10.2",

@@ -42,0 +42,0 @@ "gulp-mocha": "^2.1.3",

@@ -45,2 +45,44 @@ # lesshint

### Inline configuration
Since `1.4.0` it's possible to configure rules using inline comments in your `.less` files. For example:
```less
// lesshint spaceBeforeBrace: false
.foo{ // This line won't be reported
color: red;
}
```
It's also possible to disable rules on a single line using a trailing comment:
```less
.bar {
color:red; // lesshint spaceAfterPropertyColon: false
}
```
If you wish to enable a rule that's disabled in your `.lesshintrc` you need to specify any other options too. But rules without options can be enabled by just setting it to `true`. For example:
`.lesshintrc`:
```json
{
"emptyRule": false,
"spaceAfterPropertyName": false
}
```
`file.less`
```less
// lesshint spaceAfterPropertyName: { enabled: true, style: "one_space" }, emptyRule: true
.foo {
color : red; // Won't report the extra space before ":"
}
.bar {
}
```
The options format is a less strict form of JSON. Keys doesn't need any quotes but string values need double quotes.
### Options

@@ -127,3 +169,4 @@

column: 5,
file: 'test.less',
file: 'file.less',
fullPath: 'path/to/file.less',
line: 1,

@@ -130,0 +173,0 @@ linter: 'spaceBeforeBrace',

'use strict';
var expect = require('chai').expect;
var path = require('path');
var fs = require('fs');

@@ -38,2 +40,3 @@ describe('linter', function () {

file: 'test.less',
fullPath: 'test.less',
line: 2,

@@ -66,2 +69,3 @@ linter: 'spaceAfterPropertyColon',

file: 'file.less',
fullPath: 'path/to/file.less',
line: 1,

@@ -94,2 +98,3 @@ linter: 'spaceBeforeBrace',

file: 'file.less',
fullPath: 'path/to/file.less',
line: 1,

@@ -104,2 +109,3 @@ linter: 'stringQuotes',

file: 'file.less',
fullPath: 'path/to/file.less',
line: 1,

@@ -114,2 +120,3 @@ linter: 'attributeQuotes',

file: 'file.less',
fullPath: 'path/to/file.less',
line: 3,

@@ -124,2 +131,3 @@ linter: 'propertyOrdering',

file: 'file.less',
fullPath: 'path/to/file.less',
line: 4,

@@ -211,2 +219,3 @@ linter: 'duplicateProperty',

file: 'test.less',
fullPath: 'test.less',
line: 1,

@@ -231,2 +240,135 @@ linter: 'spaceAfterPropertyColon',

});
it('should only care about the first inline comment', function () {
var source = fs.readFileSync(path.resolve(process.cwd(), './test/data/inline-options/file-options-enabled.less'), 'utf8');
var result;
var expected = [{
column: 5,
file: 'file-options-enabled.less',
fullPath: 'file-options-enabled.less',
line: 6,
linter: 'spaceBeforeBrace',
message: 'Opening curly brace should be preceded by one space.',
severity: 'warning',
source: '.bar{'
}];
var config = {
emptyRule: {
enabled: true
},
spaceAfterPropertyColon: {
enabled: true,
style: 'one_space'
},
spaceBeforeBrace: {
enabled: true,
style: 'one_space'
}
};
result = linter.lint(source, 'file-options-enabled.less', config);
expect(result).to.deep.equal(expected);
});
it('should not report rules that are disabled inline', function () {
var source = fs.readFileSync(path.resolve(process.cwd(), './test/data/inline-options/file-options-enabled.less'), 'utf8');
var result;
var expected = [{
column: 5,
file: 'rule-options.less',
fullPath: 'rule-options.less',
line: 6,
linter: 'spaceBeforeBrace',
message: 'Opening curly brace should be preceded by one space.',
severity: 'warning',
source: '.bar{'
}];
var config = {
emptyRule: {
enabled: true
},
spaceAfterPropertyColon: {
enabled: true,
style: 'one_space'
},
spaceBeforeBrace: {
enabled: true,
style: 'one_space'
}
};
result = linter.lint(source, 'rule-options.less', config);
expect(result).to.deep.equal(expected);
});
it('should allow disabled rules to be enabled inline', function () {
var source = fs.readFileSync(path.resolve(process.cwd(), './test/data/inline-options/file-options-disabled.less'), 'utf8');
var result;
var expected = [{
column: 11,
file: 'rule-options.less',
fullPath: 'rule-options.less',
line: 3,
linter: 'spaceAfterPropertyColon',
message: 'Colon after property name should be followed by one space.',
severity: 'warning',
source: ' color:red;'
}, {
column: 1,
file: 'rule-options.less',
fullPath: 'rule-options.less',
line: 6,
linter: 'emptyRule',
message: "There shouldn't be any empty rules present.",
severity: 'warning',
source: '.bar {'
}];
var config = {
emptyRule: {
enabled: false
},
spaceAfterPropertyColon: {
enabled: false
}
};
result = linter.lint(source, 'rule-options.less', config);
expect(result).to.deep.equal(expected);
});
it('should not report rules that are disabled on a single line', function () {
var source = fs.readFileSync(path.resolve(process.cwd(), './test/data/inline-options/line-options.less'), 'utf8');
var result;
var expected = [{
column: 5,
file: 'line-options.less',
fullPath: 'line-options.less',
line: 5,
linter: 'spaceBeforeBrace',
message: 'Opening curly brace should be preceded by one space.',
severity: 'warning',
source: '.bar{'
}];
var config = {
spaceBeforeBrace: {
enabled: true,
style: 'one_space'
}
};
result = linter.lint(source, 'line-options.less', config);
expect(result).to.deep.equal(expected);
});
});

@@ -233,0 +375,0 @@

@@ -28,3 +28,3 @@ 'use strict';

var expected = [{
column: 0,
column: 8,
line: 1,

@@ -52,3 +52,39 @@ message: 'Files should end with a newline.'

});
it('should report the correct line number even for large files. #123', function () {
var source = '';
var result;
var ast;
var expected = [{
column: 26,
line: 17,
message: 'Files should end with a newline.'
}];
source += '@import "something";\n';
source += '@import "something-else";\n';
source += '@import "something-else";\n';
source += '@import "something-else";\n';
source += '@import "something-else";\n';
source += '@import "something-else";\n';
source += '@import "something-else";\n';
source += '@import "something-else";\n';
source += '@import "something-else";\n';
source += '@import "something-else";\n';
source += '@import "something-else";\n';
source += '@import "something-else";\n';
source += '@import "something-else";\n';
source += '@import "something-else";\n';
source += '@import "something-else";\n';
source += '@import "something-else";\n';
source += '@import "something-else";';
ast = parseAST(source);
result = linter.lint({}, ast);
expect(result).to.deep.equal(expected);
});
});
});

@@ -28,2 +28,20 @@ 'use strict';

it('should allow filename with .css extension when "filenameExtension" is "false"', function () {
var source = '@import "foo.css";';
var result;
var ast;
var options = {
filenameExtension: false,
exclude: []
};
ast = parseAST(source);
ast = ast.first();
result = linter.lint(options, ast);
expect(result).to.be.undefined;
});
it('should not allow filename with extension when "filenameExtension" is "false"', function () {

@@ -30,0 +48,0 @@ var source = '@import "foo.less";';

@@ -376,3 +376,16 @@ 'use strict';

});
it('should not report mixins without a trailing semicolon. #132', function () {
var source = '.foo {\n .bar\n}';
var result;
var ast;
ast = parseAST(source);
ast = ast.first('ruleset').first('block');
result = linter.lint({}, ast);
expect(result).to.be.undefined;
});
});
});

@@ -41,3 +41,56 @@ 'use strict';

});
it('should allow the comma on a new line', function () {
var source = '.foo\n,.bar {}';
var result;
var ast;
ast = parseAST(source);
ast = ast.first('ruleset');
result = linter.lint({}, ast);
expect(result).to.be.undefined;
});
it('should allow selectors with short names on the same line when "style" is "18f"', function () {
var source = '.foo, .bar {}';
var result;
var ast;
var options = {
style: '18f'
};
ast = parseAST(source);
ast = ast.first('ruleset');
result = linter.lint(options, ast);
expect(result).to.be.undefined;
});
it('should not allow selectors with long names on the same line when "style" is "18f"', function () {
var source = '.foobar, .bar {}';
var result;
var ast;
var options = {
style: '18f'
};
var expected = [{
column: 9,
line: 1,
message: 'Each selector should be on its own line.'
}];
ast = parseAST(source);
ast = ast.first('ruleset');
result = linter.lint(options, ast);
expect(result).to.deep.equal(expected);
});
});
});

@@ -170,2 +170,38 @@ 'use strict';

describe('negative numbers when calculating', function () {
it('should not report on negative number in the end of whole value', function () {
var source = '@foo: (@bar / 3) * -1;';
var result;
var ast;
var options = {
style: 'both'
};
ast = parseAST(source);
ast = ast.first();
result = linter.lint(options, ast);
expect(result).to.be.undefined;
});
it('should not report on negative number in the end of brackets', function () {
var source = '@b: spin(@a, -2%);';
var result;
var ast;
var options = {
style: 'both'
};
ast = parseAST(source);
ast = ast.first();
result = linter.lint(options, ast);
expect(result).to.be.undefined;
});
});
it('should not report on minus values', function () {

@@ -188,17 +224,59 @@ var source = '.foo { margin-left: -10px; }';

it('should not report on font-size/line-height shorthand declaration', function () {
var source = '.foo { font: 12px/1.5 Arial; }';
var result;
var ast;
describe('shorthands', function () {
it('should not allow when there is space after operator', function () {
var source = '.foo { margin: 10px - 1px 0px 20px; }';
var result;
var ast;
var options = {
style: 'both'
};
var expected = [{
column: 20,
line: 1,
message: 'Operators should not be preceded nor followed by any space.'
}];
ast = parseAST(source);
ast = ast.first();
var options = {
style: 'none'
};
result = linter.lint(options, ast);
ast = parseAST(source);
ast = ast.first();
expect(result).to.be.undefined;
result = linter.lint(options, ast);
expect(result).to.deep.equal(expected);
});
it('should not report on minus shorthand values', function () {
var source = '.foo { margin:-10px -1px 0px 20px; }';
var result;
var ast;
var options = {
style: 'both'
};
ast = parseAST(source);
ast = ast.first();
result = linter.lint(options, ast);
expect(result).to.be.undefined;
});
it('should not report on font-size/line-height shorthand declaration', function () {
var source = '.foo { font: 12px/1.5 Arial; }';
var result;
var ast;
var options = {
style: 'both'
};
ast = parseAST(source);
ast = ast.first();
result = linter.lint(options, ast);
expect(result).to.be.undefined;
});
});

@@ -205,0 +283,0 @@

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