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

lesshint

Package Overview
Dependencies
Maintainers
1
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 0.6.2 to 0.7.0-beta

test/data/excluded-files/exclude.css

3

lib/cli.js

@@ -35,2 +35,5 @@ 'use strict';

config = configLoader(program.config);
config = config || {};
config.excludedFiles = program.exclude ? [program.exclude] : [];
} catch (e) {

@@ -37,0 +40,0 @@ console.error('Something\'s wrong with the config file. Error: ' + e.message);

{
"fileExtensions": [".less"],
"excludedFiles": [],
"attributeQuotes": {

@@ -3,0 +7,0 @@ "enabled": true,

65

lib/lesshint.js
'use strict';
var configLoader = require('./config-loader');
var minimatch = require('minimatch');
var merge = require('lodash.merge');
var linter = require('./linter');
var path = require('path');
var fs = require('vow-fs');
var linter = require('./linter');
var Vow = require('vow');

@@ -11,6 +15,6 @@

Lesshint.prototype.checkDirectory = function (path) {
return fs.listDir(path).then(function (files) {
Lesshint.prototype.checkDirectory = function (checkPath) {
return fs.listDir(checkPath).then(function (files) {
files = files.map(function (file) {
var fullPath = path + '/' + file;
var fullPath = checkPath + '/' + file;

@@ -22,6 +26,12 @@ return fs.stat(fullPath).then(function (stats) {

if (file.substr(0, 1) === '.') {
// Check if the file should be excluded
if (this.isExcluded(fullPath)) {
return [];
}
// Check if the file has the correct extension
if (!this.hasAllowedExtension(file)) {
return [];
}
return this.checkFile(fullPath);

@@ -37,26 +47,51 @@ }, this);

Lesshint.prototype.checkFile = function (path) {
return fs.read(path, 'utf8').then(function (data) {
return this.checkString(data, path);
Lesshint.prototype.checkFile = function (checkPath) {
return fs.read(checkPath, 'utf8').then(function (data) {
return this.checkString(data, checkPath);
}, this);
};
Lesshint.prototype.checkPath = function (path) {
return fs.stat(path).then(function (stats) {
Lesshint.prototype.checkPath = function (checkPath) {
return fs.stat(checkPath).then(function (stats) {
if (stats.isDirectory()) {
return this.checkDirectory(path);
return this.checkDirectory(checkPath);
}
return this.checkFile(path);
return this.checkFile(checkPath);
}, this);
};
Lesshint.prototype.checkString = function (input, path) {
return linter.lint(input, path, this.config);
Lesshint.prototype.checkString = function (input, checkPath) {
return linter.lint(input, checkPath, this.config);
};
Lesshint.prototype.configure = function (config) {
this.config = config;
var defaultConfig = configLoader(__dirname + '/config/defaults.json');
this.config = merge(defaultConfig, config);
};
Lesshint.prototype.hasAllowedExtension = function (file) {
var fileExtensions;
if (!Array.isArray(this.config.fileExtensions) || this.config.fileExtensions === '*') {
return true;
}
// Make sure there is a leading dot
fileExtensions = this.config.fileExtensions.map(function (extension) {
return '.' + extension.replace(/^\./, '');
});
return fileExtensions.indexOf(path.extname(file)) !== -1;
};
Lesshint.prototype.isExcluded = function (checkPath) {
return this.config.excludedFiles.some(function (pattern) {
return minimatch(checkPath, pattern, {
matchBase: true
});
});
};
module.exports = Lesshint;
'use strict';
var configLoader = require('./config-loader');
var flatten = require('lodash.flatten');
var gonzales = require('gonzales-pe');
var merge = require('lodash.merge');

@@ -35,8 +33,5 @@ var linters = [

exports.lint = function (input, path, config) {
var defaultConfig = configLoader(__dirname + '/config/defaults.json');
var ast = this.parseAST(input);
var errors = [];
config = merge(defaultConfig, config);
ast.map(function (node) {

@@ -43,0 +38,0 @@ var i;

@@ -9,3 +9,4 @@ 'use strict';

var node = options.node;
var errors = [];
var message;
var value;

@@ -18,55 +19,36 @@ // Bail if the linter isn't wanted

// Not applicable, bail
if (node.type !== 'selector') {
if (node.type !== 'attribute') {
return null;
}
node.forEach('simpleSelector', function (selector) {
var attribute = selector.first('attribute');
var value;
// Use last ident when no quotes are present
value = node.first('string') || node.last('ident');
if (!attribute) {
return;
}
switch (config.attributeQuotes.style) {
case 'double':
if (!/".*"/.test(value.content)) {
message = 'Attribute selectors should use double quotes.';
}
// Use last ident when no quotes are present
value = attribute.first('string') || attribute.last('ident');
break;
case 'single':
if (!/'.*'/.test(value.content)) {
message = 'Attribute selectors should use single quotes.';
}
switch (config.attributeQuotes.style) {
case 'double':
if (!/".*"/.test(value.content)) {
errors.push({
message: 'Attribute selectors should use double quotes.',
column: value.start.column,
line: value.start.line
});
}
break;
default:
throw new Error(
'Invalid setting value for attributeQuotes: ' + config.attributeQuotes.style
);
}
break;
case 'single':
if (!/'.*'/.test(value.content)) {
errors.push({
message: 'Attribute selectors should use single quotes.',
column: value.start.column,
line: value.start.line
});
}
break;
default:
throw new Error(
'Invalid setting value for attributeQuotes: ' + config.attributeQuotes.style
);
}
});
if (errors.length) {
return errors.map(function (error) {
return {
column: error.column,
file: filename,
line: error.line,
linter: 'attributeQuotes',
message: error.message
};
});
if (message) {
return {
column: value.start.column,
file: filename,
line: value.start.line,
linter: 'attributeQuotes',
message: message
};
}

@@ -73,0 +55,0 @@

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

var node = options.node;
var errors = [];
var error = {};

@@ -18,63 +18,59 @@ // Bail if the linter isn't wanted

// Not applicable, bail
if (node.type !== 'selector') {
if (node.type !== 'simpleSelector') {
return null;
}
node.forEach('simpleSelector', function (simpleSelector) {
simpleSelector.content.forEach(function (selector, index) {
if (!simpleSelector.content[index - 1] || simpleSelector.content[index - 1].type !== 'ident') {
return;
}
node.content.forEach(function (selector, index) {
if (!node.content[index - 1] || node.content[index - 1].type !== 'ident') {
return;
}
switch (selector.type) {
case 'attribute':
if (config.qualifyingElement.allowWithAttribute) {
return;
}
switch (selector.type) {
case 'attribute':
if (config.qualifyingElement.allowWithAttribute) {
return;
}
errors.push({
message: 'Attribute selectors should not include a qualifying element.',
column: selector.start.column,
line: selector.start.line
});
error = {
message: 'Attribute selectors should not include a qualifying element.',
column: selector.start.column,
line: selector.start.line
};
break;
case 'class':
if (config.qualifyingElement.allowWithClass) {
return;
}
break;
case 'class':
if (config.qualifyingElement.allowWithClass) {
return;
}
errors.push({
message: 'Class selectors should not include a qualifying element.',
column: selector.start.column,
line: selector.start.line
});
error = {
message: 'Class selectors should not include a qualifying element.',
column: selector.start.column,
line: selector.start.line
};
break;
case 'id':
if (config.qualifyingElement.allowWithId) {
return;
}
break;
case 'id':
if (config.qualifyingElement.allowWithId) {
return;
}
errors.push({
message: 'ID selectors should not include a qualifying element.',
column: selector.start.column,
line: selector.start.line
});
error = {
message: 'ID selectors should not include a qualifying element.',
column: selector.start.column,
line: selector.start.line
};
break;
}
});
break;
}
});
if (errors.length) {
return errors.map(function (error) {
return {
column: error.column,
file: filename,
line: error.line,
linter: 'qualifyingElement',
message: error.message
};
});
if (error.message) {
return {
column: error.column,
file: filename,
line: error.line,
linter: 'qualifyingElement',
message: error.message
};
}

@@ -81,0 +77,0 @@

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

@@ -27,2 +27,3 @@ "author": {

"lodash.merge": "^3.3.1",
"minimatch": "^2.0.8",
"rcfinder": "^0.1.8",

@@ -29,0 +30,0 @@ "strip-json-comments": "^1.0.2",

@@ -14,2 +14,3 @@ # lesshint

* [Configuration](#configuration)
* [CLI usage](#cli-usage)
* [Known issues](#known-issues)

@@ -46,2 +47,6 @@

```js
"fileExtensions": [".less", ".css"],
"excludedFiles": ["vendor.less"],
"spaceAfterPropertyColon": {

@@ -53,4 +58,35 @@ "enabled": true,

If you're running `lesshint` from the command line, the `-c` or `--config` flags can be used to load any valid configuration file.
### Options
#### fileExtensions
Array of file extensions to check. Either an array of extensions or `"*"` to allow all files. For example:
```
"fileExtensions": [".less", ".css"] // Allow ".less" and ".css" files. Can be passed with or without a dot.
"fileExtensions": "*" // Allow all files
```
#### excludedFiles
Array of [minimatch glob patterns](https://github.com/isaacs/minimatch) or a file to exclude. For example:
```
"excludedFiles": ["vendor/*.less"] // Ignore all files in "vendor/"
"excludedFiles": ["vendor.less"] // Ignore a file named "vendor.less"
```
## CLI usage
Run `lesshint` from the command-line by passing one or more files/directories to recursively scan.
```
lesshint src/less/ lib/style.less
```
Available Flags | Description
--------------------|----------------------------------------------
`-c`/`--config` | Specify the configuration file to use (will be merged with defaults).
`-e`/`--exclude` | A [minimatch glob pattern](https://github.com/isaacs/minimatch) or a file to exclude form being linted.
`-V`/`--version` | Show version.
## Known issues

@@ -57,0 +93,0 @@ We are aware of some instances where some Less features won't be properly parsed. In those cases the whole file will simply be ignored by `lesshint`.

@@ -112,2 +112,15 @@ var assert = require('assert');

});
it('should ignore excluded files', function () {
var result;
result = cli({
args: [path.dirname(__dirname) + '/data/files'],
exclude: '*.less'
});
return result.then(function (status) {
assert.ok(status === 0);
});
});
});

@@ -7,2 +7,3 @@ var assert = require('assert');

var Lesshint = require('../../lib/lesshint');
var configLoader = require('../../lib/config-loader');

@@ -13,2 +14,4 @@ describe('checkDirectory', function () {

lesshint.configure();
return lesshint.checkDirectory(testDir).then(function (errors) {

@@ -20,5 +23,7 @@ assert.ok(errors.length === 2);

it('should ignore dotfiles', function () {
var testPath = path.dirname(__dirname) + '/data/ignored-files';
var lesshint = new Lesshint();
var testPath = path.dirname(__dirname) + '/data/ignored-files';
lesshint.configure();
return lesshint.checkDirectory(testPath).then(function (errors) {

@@ -28,2 +33,58 @@ assert.ok(errors.length === 0);

});
it('should ignore excluded files', function () {
var testPath = path.dirname(__dirname) + '/data/excluded-files';
var lesshint = new Lesshint();
var config = {
excludedFiles: ['vendor.less']
};
lesshint.configure(config);
return lesshint.checkDirectory(testPath).then(function (errors) {
assert.ok(errors.length === 0);
});
});
it('should only check files with the correct extension and a leading dot', function () {
var testPath = path.dirname(__dirname) + '/data/excluded-files';
var lesshint = new Lesshint();
var config = {
fileExtensions: ['.less']
};
lesshint.configure(config);
return lesshint.checkDirectory(testPath).then(function (errors) {
assert.ok(errors.length === 1);
});
});
it('should only check files with the correct extension and without a leading dot', function () {
var testPath = path.dirname(__dirname) + '/data/excluded-files';
var lesshint = new Lesshint();
var config = {
fileExtensions: ['less']
};
lesshint.configure(config);
return lesshint.checkDirectory(testPath).then(function (errors) {
assert.ok(errors.length === 1);
});
});
it('should allow all extensions when "*" is passed', function () {
var testPath = path.dirname(__dirname) + '/data/excluded-files';
var lesshint = new Lesshint();
var config = {
fileExtensions: '*'
};
lesshint.configure(config);
return lesshint.checkDirectory(testPath).then(function (errors) {
assert.ok(errors.length === 2);
});
});
});

@@ -35,2 +96,4 @@

lesshint.configure();
return lesshint.checkFile(testDir + '/file.less').then(function (errors) {

@@ -46,2 +109,4 @@ assert.ok(errors.length === 1);

lesshint.configure();
return lesshint.checkPath(testDir).then(function (errors) {

@@ -57,4 +122,8 @@ assert.ok(errors.length === 2);

var lesshint = new Lesshint();
var errors = lesshint.checkString(string);
var errors;
lesshint.configure();
errors = lesshint.checkString(string);
assert.ok(errors.length === 1);

@@ -66,15 +135,5 @@ });

it('should set the config to use', function () {
var expected = configLoader(path.resolve(process.cwd() + '/lib/config/defaults.json'));
var lesshint = new Lesshint();
var expected = {
spaceAfterPropertyColon: {
enabled: false,
style: 'one_space'
},
spaceBeforeBrace: {
enabled: true,
style: 'new_line'
}
};
lesshint.configure(expected);

@@ -81,0 +140,0 @@

@@ -20,3 +20,3 @@ var assert = require('assert');

ast = linter.parseAST(source);
ast = ast.first().first('selector');
ast = ast.first().first('selector').first('simpleSelector').first('attribute');

@@ -34,3 +34,3 @@ assert.strictEqual(true, attributeQuotes({

var expected = [{
var expected = {
column: 12,

@@ -41,3 +41,3 @@ file: 'test.less',

message: 'Attribute selectors should use single quotes.'
}];
};

@@ -52,3 +52,3 @@ var options = {

ast = linter.parseAST(source);
ast = ast.first().first('selector');
ast = ast.first().first('selector').first('simpleSelector').first('attribute');

@@ -69,3 +69,3 @@ actual = attributeQuotes({

var expected = [{
var expected = {
column: 12,

@@ -76,3 +76,3 @@ file: 'test.less',

message: 'Attribute selectors should use single quotes.'
}];
};

@@ -87,3 +87,3 @@ var options = {

ast = linter.parseAST(source);
ast = ast.first().first('selector');
ast = ast.first().first('selector').first('simpleSelector').first('attribute');

@@ -111,3 +111,3 @@ actual = attributeQuotes({

ast = linter.parseAST(source);
ast = ast.first().first('selector');
ast = ast.first().first('selector').first('simpleSelector').first('attribute');

@@ -125,3 +125,3 @@ assert.strictEqual(true, attributeQuotes({

var expected = [{
var expected = {
column: 12,

@@ -132,3 +132,3 @@ file: 'test.less',

message: 'Attribute selectors should use double quotes.'
}];
};

@@ -143,3 +143,3 @@ var options = {

ast = linter.parseAST(source);
ast = ast.first().first('selector');
ast = ast.first().first('selector').first('simpleSelector').first('attribute');

@@ -160,3 +160,3 @@ actual = attributeQuotes({

var expected = [{
var expected = {
column: 12,

@@ -167,3 +167,3 @@ file: 'test.less',

message: 'Attribute selectors should use double quotes.'
}];
};

@@ -178,3 +178,3 @@ var options = {

ast = linter.parseAST(source);
ast = ast.first().first('selector');
ast = ast.first().first('selector').first('simpleSelector').first('attribute');

@@ -200,3 +200,3 @@ actual = attributeQuotes({

ast = linter.parseAST(source);
ast = ast.first().first('selector');
ast = ast.first().first('selector').first('simpleSelector').first('attribute');

@@ -217,3 +217,3 @@ assert.equal(null, attributeQuotes({

ast = linter.parseAST(source);
ast = ast.first().first('selector');
ast = ast.first().first('selector').first('simpleSelector').first('attribute');

@@ -238,3 +238,3 @@ assert.equal(null, attributeQuotes({

ast = linter.parseAST(source);
ast = ast.first().first('selector');
ast = ast.first().first('selector').first('simpleSelector').first('attribute');

@@ -241,0 +241,0 @@ assert.throws(attributeQuotes.bind(null, {

@@ -19,3 +19,3 @@ var assert = require('assert');

ast = linter.parseAST(source);
ast = ast.first().first('selector');
ast = ast.first().first('selector').first('simpleSelector');

@@ -33,3 +33,3 @@ assert.strictEqual(true, qualifyingElement({

var expected = [{
var expected = {
column: 4,

@@ -40,3 +40,3 @@ file: 'test.less',

message: 'ID selectors should not include a qualifying element.'
}];
};

@@ -50,3 +50,3 @@ var options = {

ast = linter.parseAST(source);
ast = ast.first().first('selector');
ast = ast.first().first('selector').first('simpleSelector');

@@ -67,3 +67,3 @@ actual = qualifyingElement({

var expected = [{
var expected = {
column: 4,

@@ -74,3 +74,3 @@ file: 'test.less',

message: 'Class selectors should not include a qualifying element.'
}];
};

@@ -84,3 +84,3 @@ var options = {

ast = linter.parseAST(source);
ast = ast.first().first('selector');
ast = ast.first().first('selector').first('simpleSelector');

@@ -101,3 +101,3 @@ actual = qualifyingElement({

var expected = [{
var expected = {
column: 4,

@@ -108,3 +108,3 @@ file: 'test.less',

message: 'Attribute selectors should not include a qualifying element.'
}];
};

@@ -118,3 +118,3 @@ var options = {

ast = linter.parseAST(source);
ast = ast.first().first('selector');
ast = ast.first().first('selector').first('simpleSelector');

@@ -142,3 +142,3 @@ actual = qualifyingElement({

ast = linter.parseAST(source);
ast = ast.first().first('selector');
ast = ast.first().first('selector').first('simpleSelector');

@@ -163,3 +163,3 @@ assert.strictEqual(true, qualifyingElement({

ast = linter.parseAST(source);
ast = ast.first().first('selector');
ast = ast.first().first('selector').first('simpleSelector');

@@ -184,3 +184,3 @@ assert.strictEqual(true, qualifyingElement({

ast = linter.parseAST(source);
ast = ast.first().first('selector');
ast = ast.first().first('selector').first('simpleSelector');

@@ -198,3 +198,3 @@ assert.strictEqual(true, qualifyingElement({

var expected = [{
var expected = {
column: 9,

@@ -205,35 +205,4 @@ file: 'test.less',

message: 'Class selectors should not include a qualifying element.'
}];
var options = {
qualifyingElement: {
enabled: true
}
};
ast = linter.parseAST(source);
ast = ast.first().first('selector');
actual = qualifyingElement({
config: options,
node: ast,
path: 'test.less'
});
assert.deepEqual(actual, expected);
});
it('should not allow a class with a qualifying element in a selector group', function () {
var source = '.foo, div.bar {}';
var actual;
var ast;
var expected = [{
column: 10,
file: 'test.less',
line: 1,
linter: 'qualifyingElement',
message: 'Class selectors should not include a qualifying element.'
}];
var options = {

@@ -246,3 +215,3 @@ qualifyingElement: {

ast = linter.parseAST(source);
ast = ast.first().first('selector');
ast = ast.first().first('selector').first('simpleSelector');

@@ -268,3 +237,3 @@ actual = qualifyingElement({

ast = linter.parseAST(source);
ast = ast.first().first('selector');
ast = ast.first().first('selector').first('simpleSelector');

@@ -285,3 +254,3 @@ assert.equal(null, qualifyingElement({

ast = linter.parseAST(source);
ast = ast.first().first('selector');
ast = ast.first().first('selector').first('simpleSelector');

@@ -288,0 +257,0 @@ assert.equal(null, qualifyingElement({

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

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