Socket
Socket
Sign inDemoInstall

stylelint

Package Overview
Dependencies
Maintainers
3
Versions
238
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

stylelint - npm Package Compare versions

Comparing version 5.2.1 to 5.3.0

dist/rules/declaration-block-no-ignored-properties/__test__/index.js

22

CHANGELOG.md

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

# 5.3.0
- Added: (experimental) support for [Less](http://lesscss.org/) syntax.
- Added: support for [SugarSS](https://github.com/postcss/sugarss) syntax.
- Added: exposed `stylelint.createRuleTester()`.
- Added: `function-max-empty-lines` rule.
- Added: `declaration-block-no-ignored-properties` rule.
- Added: `function-url-data-uris` rule.
- Fixed: `block-closing-brace-newline-after` use of "single space", rather than "newline", in its messages.
- Fixed: `function-comma-space-after`, `function-comma-space-before`, `function-parentheses-newline-inside` and `function-parentheses-space-inside` now ignore SCSS maps.
- Fixed: `property-value-blacklist` and `-whitelist` no longer error on properties without a corresponding list entry.
- Fixed: `font-weight-notation` now ignores `initial` value.
- Fixed: `selector-id-pattern` now ignores selectors with Sass interpolation.
- Fixed: `selector-class-pattern` now ignores selectors with Sass interpolation.
- Fixed: `no-unknown-animations` now ignores `none`, `initial`, `inherit`, `unset` values.
- Fixed: `max-line-length` options validation.
- Fixed: `function-calc-no-unspaced-operator` accepts newlines.
- Fixed: `block-closing-brace-newline-after` accepts single-line comments immediately after the closing brace.
- Fixed: `selector-no-id` now ignores keyframe selectors.
- Fixed: `unit-blacklist` and `unit-whitelist` now ignores `url` functions.
- Fixed: `function-*` rules should all now ignore all Sass maps and lists.
# 5.2.1

@@ -2,0 +24,0 @@

4

dist/cli.js

@@ -42,6 +42,6 @@ #!/usr/bin/env node

};
var syntaxOptions = ["scss"];
var syntaxOptions = ["scss", "less", "sugarss"];
var meowOptions = {
help: ["Usage", " stylelint [input] [options]", "", "Input", " Files(s) or glob(s).", " If an input argument is wrapped in quotation marks, it will be passed to node-glob", " for cross-platform glob support.", " `node_modules` and `bower_components` are always ignored.", " You can also pass no input and use stdin, instead.", "", "Options", " --config Path to a specific configuration file (JSON, YAML, or CommonJS),", " or the name of a module in `node_modules` that points to one.", " If no `--config` argument is provided, stylelint will search for", " configuration files in the following places, in this order:", " - a `stylelint` property in `package.json`", " - a `.stylelintrc` file (with or without filename extension:", " `.json`, `.yaml`, and `.js` are available)", " - a `stylelint.config.js` file exporting a JS object", " The search will begin in the working directory and move up the", " directory tree until a configuration file is found.", " --version Get the currently installed version of stylelint.", " --custom-formatter Path to a JS file exporting a custom formatting function", " -f, --formatter Specify a formatter: \"json\" or \"string\". Default is \"string\".", " -q, --quiet Only register warnings for rules with an \"error\"-level severity", " (ignore \"warning\"-level)", " -s, --syntax Specify a non-standard syntax that should be used to ", " parse source stylesheets. Options: \"scss\"", " -v, --verbose Get more stats"],
help: ["Usage", " stylelint [input] [options]", "", "Input", " Files(s) or glob(s).", " If an input argument is wrapped in quotation marks, it will be passed to node-glob", " for cross-platform glob support.", " `node_modules` and `bower_components` are always ignored.", " You can also pass no input and use stdin, instead.", "", "Options", " --config Path to a specific configuration file (JSON, YAML, or CommonJS),", " or the name of a module in `node_modules` that points to one.", " If no `--config` argument is provided, stylelint will search for", " configuration files in the following places, in this order:", " - a `stylelint` property in `package.json`", " - a `.stylelintrc` file (with or without filename extension:", " `.json`, `.yaml`, and `.js` are available)", " - a `stylelint.config.js` file exporting a JS object", " The search will begin in the working directory and move up the", " directory tree until a configuration file is found.", " --version Get the currently installed version of stylelint.", " --custom-formatter Path to a JS file exporting a custom formatting function", " -f, --formatter Specify a formatter: \"json\" or \"string\". Default is \"string\".", " -q, --quiet Only register warnings for rules with an \"error\"-level severity", " (ignore \"warning\"-level)", " -s, --syntax Specify a non-standard syntax that should be used to ", " parse source stylesheets. Options: \"scss\", \"less\", \"sugarss\"", " -v, --verbose Get more stats"],
pkg: "../package.json"

@@ -48,0 +48,0 @@ };

@@ -21,2 +21,4 @@ "use strict";

var _testUtils = require("./testUtils");
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }

@@ -36,3 +38,4 @@

stylelint.createPlugin = _createPlugin2.default;
stylelint.createRuleTester = _testUtils.createRuleTester;
module.exports = stylelint;

@@ -30,6 +30,2 @@ "use strict";

function check(statement) {
var nextNode = statement.next();
if (!nextNode) {
return;
}
if (!(0, _utils.cssStatementHasBlock)(statement)) {

@@ -42,6 +38,19 @@ return;

var nextNode = statement.next();
if (!nextNode) {
return;
}
// Allow an end-of-line comment x spaces after the brace
var nextNodeIsSingleLineComment = nextNode.type === "comment" && !/[^ ]/.test(nextNode.raw("before")) && nextNode.toString().indexOf("\n") === -1;
var nodeToCheck = nextNodeIsSingleLineComment ? nextNode.next() : nextNode;
if (!nodeToCheck) {
return;
}
// Only check one after, because there might be other
// spaces handled by the indentation rule
checker.afterOneOnly({
source: (0, _utils.rawNodeString)(nextNode),
source: (0, _utils.rawNodeString)(nodeToCheck),
index: -1,

@@ -76,3 +85,3 @@ lineCheckStr: (0, _utils.cssStatementBlockString)(statement),

expectedAfterSingleLine: function expectedAfterSingleLine() {
return "Expected single space after \"}\" of a single-line block";
return "Expected newline after \"}\" of a single-line block";
},

@@ -83,3 +92,3 @@ rejectedAfterSingleLine: function rejectedAfterSingleLine() {

expectedAfterMultiLine: function expectedAfterMultiLine() {
return "Expected single space after \"}\" of a multi-line block";
return "Expected newline after \"}\" of a multi-line block";
},

@@ -86,0 +95,0 @@ rejectedAfterMultiLine: function rejectedAfterMultiLine() {

@@ -31,3 +31,3 @@ "use strict";

// Allow an end-of-line comment x spaces after the semicolon
// Allow an end-of-line comment x spaces after the brace
var firstNode = statement.first;

@@ -34,0 +34,0 @@ var firstNodeIsAcceptableComment = firstNode.type === "comment" && !/[^ ]/.test(firstNode.raw("before")) && firstNode.toString().indexOf("\n") === -1;

@@ -35,24 +35,34 @@ "use strict";

complain(messages.rejected(value), decl, (0, _utils.declarationValueIndexOffset)(decl) + sourceIndex);
return;
}
// Check "always-where-possible" option
if (expectation === "always-where-possible") {
// First by checking for alternative color function representations
if (type === "function" && FUNC_REPRESENTATION.indexOf(value) !== -1) {
(function () {
var cssString = _postcssValueParser2.default.stringify(node).replace(/\s+/g, "");
namedColors.forEach(function (namedColor) {
if (_representations2.default[namedColor].func.indexOf(cssString) !== -1) {
complain(messages.expected(namedColor, cssString), decl, (0, _utils.declarationValueIndexOffset)(decl) + sourceIndex);
}
});
// Then by checking for alternative hex representations
})();
} else {
namedColors.forEach(function (namedColor) {
if (_representations2.default[namedColor].hex.indexOf(value) !== -1) {
complain(messages.expected(namedColor, value), decl, (0, _utils.declarationValueIndexOffset)(decl) + sourceIndex);
}
});
// Check "always-where-possible" option ...
if (expectation !== "always-where-possible") {
return;
}
// First by checking for alternative color function representations ...
if (type === "function" && FUNC_REPRESENTATIONS.indexOf(value) !== -1) {
// Remove all spaces to match what's in `representations`
var normalizedFunctionString = _postcssValueParser2.default.stringify(node).replace(/\s+/g, "");
var _namedColor = void 0;
for (var i = 0, l = namedColors.length; i < l; i++) {
_namedColor = namedColors[i];
if (_representations2.default[_namedColor].func.indexOf(normalizedFunctionString) !== -1) {
complain(messages.expected(_namedColor, normalizedFunctionString), decl, (0, _utils.declarationValueIndexOffset)(decl) + sourceIndex);
return; // Exit as soon as a problem is found
}
}
return;
}
// Then by checking for alternative hex representations
var namedColor = void 0;
for (var _i = 0, _l = namedColors.length; _i < _l; _i++) {
namedColor = namedColors[_i];
if (_representations2.default[namedColor].hex.indexOf(value) !== -1) {
complain(messages.expected(namedColor, value), decl, (0, _utils.declarationValueIndexOffset)(decl) + sourceIndex);
return; // Exit as soon as a problem is found
}
}
});

@@ -85,2 +95,3 @@ });

// import _ from "lodash"
var ruleName = exports.ruleName = "color-named";

@@ -97,3 +108,3 @@

var FUNC_REPRESENTATION = ["rgb", "rgba", "hsl", "hsla", "hwb", "gray"];
var FUNC_REPRESENTATIONS = ["rgb", "rgba", "hsl", "hsla", "hwb", "gray"];
var NODE_TYPES = ["word", "function"];

@@ -43,3 +43,3 @@ "use strict";

if (comment.raws.inline) {
if (comment.raws.inline || comment.inline) {
return;

@@ -46,0 +46,0 @@ }

@@ -20,3 +20,3 @@ "use strict";

if (comment.raws.inline) {
if (comment.raws.inline || comment.inline) {
return;

@@ -23,0 +23,0 @@ }

@@ -74,3 +74,3 @@ "use strict";

}
if (weightValue === INHERIT_KEYWORD) {
if (weightValue === INHERIT_KEYWORD || weightValue === INITIAL_KEYWORD) {
return;

@@ -140,2 +140,3 @@ }

var INHERIT_KEYWORD = "inherit";
var INITIAL_KEYWORD = "initial";
var NORMAL_KEYWORD = "normal";

@@ -142,0 +143,0 @@ var RELATIVE_NAMED_WEIGHTS = ["bolder", "lighter"];

@@ -9,4 +9,2 @@ "use strict";

exports.default = function (actual) {
var checker = (0, _utils.whitespaceChecker)("space", "always", messages);
return function (root, result) {

@@ -18,2 +16,6 @@ var validOptions = (0, _utils.validateOptions)(result, ruleName, { actual: actual });

function complain(message, node, index) {
(0, _utils.report)({ message: message, node: node, index: index, result: result, ruleName: ruleName });
}
root.walkDecls(function (decl) {

@@ -36,3 +38,9 @@ (0, _postcssValueParser2.default)(decl.value).walk(function (node) {

function checkSymbol(symbol) {
(0, _utils.styleSearch)({ source: expression, target: symbol, outsideFunctionalNotation: true }, function (match) {
var styleSearchOptions = {
source: expression,
target: symbol,
outsideFunctionalNotation: true
};
(0, _utils.styleSearch)(styleSearchOptions, function (match) {
var index = match.startIndex;

@@ -45,2 +53,3 @@

var expressionBeforeSign = expression.substr(0, index);
// Ignore signs at the beginning of the expression

@@ -56,39 +65,17 @@ if (/^\s*$/.test(expressionBeforeSign)) {

(0, _utils.report)({
message: messages.expectedOperatorBeforeSign(symbol),
node: decl,
index: expressionIndex + index,
result: result,
ruleName: ruleName
});
// And if not, complain
complain(messages.expectedOperatorBeforeSign(symbol), decl, expressionIndex + index);
return;
}
checker.after({
index: index,
source: expression,
err: function err(m) {
(0, _utils.report)({
message: m,
node: decl,
index: expressionIndex + index,
result: result,
ruleName: ruleName
});
}
});
checker.before({
index: index,
source: expression,
err: function err(m) {
(0, _utils.report)({
message: m,
node: decl,
index: expressionIndex + index,
result: result,
ruleName: ruleName
});
}
});
var beforeOk = expression[index - 1] === " " && !(0, _utils.isWhitespace)(expression[index - 2]) || newlineBefore(expression, index - 1);
if (!beforeOk) {
complain(messages.expectedBefore(symbol), decl, expressionIndex + index);
}
var afterOk = expression[index + 1] === " " && !(0, _utils.isWhitespace)(expression[index + 2]) || expression[index + 1] === "\n" || expression.substr(index + 1, 2) === "\r\n";
if (!afterOk) {
complain(messages.expectedAfter(symbol), decl, expressionIndex + index);
}
});

@@ -129,2 +116,11 @@ }

return source.replace(/[\$@][^\)\s]+/g, "0");
}
function newlineBefore(str, startIndex) {
var index = startIndex;
while (index && (0, _utils.isWhitespace)(str[index])) {
if (str[index] === "\n") return true;
index--;
}
return false;
}

@@ -62,2 +62,6 @@ "use strict";

root.walkDecls(function (decl) {
if ((0, _utils.cssDeclarationIsMap)(decl)) {
return;
}
(0, _postcssValueParser2.default)(decl.value).walk(function (valueNode) {

@@ -68,2 +72,7 @@ if (valueNode.type !== "function") {

// Function nodes without names are things in parentheses like Sass lists
if (!valueNode.value) {
return;
}
// Ignore `url()` arguments, which may contain data URIs or other funky stuff

@@ -70,0 +79,0 @@ if (valueNode.value === "url") {

@@ -19,2 +19,6 @@ "use strict";

root.walkDecls(function (decl) {
if ((0, _utils.cssDeclarationIsMap)(decl)) {
return;
}
if (decl.value.indexOf("(") === -1) {

@@ -29,2 +33,7 @@ return;

// Function nodes without names are things in parentheses like Sass lists
if (!valueNode.value) {
return;
}
var functionString = _postcssValueParser2.default.stringify(valueNode);

@@ -31,0 +40,0 @@ var isMultiLine = !(0, _utils.isSingleLineString)(functionString);

@@ -19,2 +19,6 @@ "use strict";

root.walkDecls(function (decl) {
if ((0, _utils.cssDeclarationIsMap)(decl)) {
return;
}
if (decl.value.indexOf("(") === -1) {

@@ -29,2 +33,7 @@ return;

// Function nodes without names are things in parentheses like Sass lists
if (!valueNode.value) {
return;
}
var functionString = _postcssValueParser2.default.stringify(valueNode);

@@ -31,0 +40,0 @@ var isSingleLine = (0, _utils.isSingleLineString)(functionString);

@@ -22,11 +22,18 @@ "use strict";

(0, _postcssValueParser2.default)(value).walk(function (node) {
if (node.type === "function" && whitelist.indexOf(_postcss.vendor.unprefixed(node.value)) === -1) {
(0, _utils.report)({
message: messages.rejected(node.value),
node: decl,
index: (0, _utils.declarationValueIndexOffset)(decl) + node.sourceIndex,
result: result,
ruleName: ruleName
});
if (node.type !== "function") {
return;
}
if (!node.value) {
return;
}
if (whitelist.indexOf(_postcss.vendor.unprefixed(node.value)) !== -1) {
return;
}
(0, _utils.report)({
message: messages.rejected(node.value),
node: decl,
index: (0, _utils.declarationValueIndexOffset)(decl) + node.sourceIndex,
result: result,
ruleName: ruleName
});
});

@@ -33,0 +40,0 @@ });

@@ -21,3 +21,3 @@ "use strict";

(0, _utils.styleSearch)({ source: declString, target: ")" }, function (match) {
(0, _utils.styleSearch)({ source: declString, target: ")", withinFunctionalNotation: true }, function (match) {
checkClosingParen(declString, match.startIndex, decl);

@@ -24,0 +24,0 @@ });

@@ -111,2 +111,6 @@ "use strict";

var _declarationBlockNoIgnoredProperties = require("./declaration-block-no-ignored-properties");
var _declarationBlockNoIgnoredProperties2 = _interopRequireDefault(_declarationBlockNoIgnoredProperties);
var _declarationBlockNoShorthandPropertyOverrides = require("./declaration-block-no-shorthand-property-overrides");

@@ -196,2 +200,6 @@

var _functionMaxEmptyLines = require("./function-max-empty-lines");
var _functionMaxEmptyLines2 = _interopRequireDefault(_functionMaxEmptyLines);
var _functionParenthesesNewlineInside = require("./function-parentheses-newline-inside");

@@ -205,2 +213,6 @@

var _functionUrlDataUris = require("./function-url-data-uris");
var _functionUrlDataUris2 = _interopRequireDefault(_functionUrlDataUris);
var _functionUrlQuotes = require("./function-url-quotes");

@@ -515,2 +527,3 @@

"declaration-block-no-duplicate-properties": _declarationBlockNoDuplicateProperties2.default,
"declaration-block-no-ignored-properties": _declarationBlockNoIgnoredProperties2.default,
"declaration-block-no-shorthand-property-overrides": _declarationBlockNoShorthandPropertyOverrides2.default,

@@ -537,4 +550,6 @@ "declaration-block-properties-order": _declarationBlockPropertiesOrder2.default,

"function-linear-gradient-no-nonstandard-direction": _functionLinearGradientNoNonstandardDirection2.default,
"function-max-empty-lines": _functionMaxEmptyLines2.default,
"function-parentheses-newline-inside": _functionParenthesesNewlineInside2.default,
"function-parentheses-space-inside": _functionParenthesesSpaceInside2.default,
"function-url-data-uris": _functionUrlDataUris2.default,
"function-url-quotes": _functionUrlQuotes2.default,

@@ -541,0 +556,0 @@ "function-whitelist": _functionWhitelist2.default,

@@ -21,4 +21,7 @@ "use strict";

var rootString = root.toString();
var repeatLFNewLines = (0, _lodash.repeat)("\n", maxAdjacentNewlines);
var repeatCRLFNewLines = (0, _lodash.repeat)("\r\n", maxAdjacentNewlines);
(0, _utils.styleSearch)({ source: rootString, target: "\n", checkComments: true }, function (match) {
if (rootString.substr(match.startIndex + 1, maxAdjacentNewlines) === (0, _lodash.repeat)("\n", maxAdjacentNewlines) || rootString.substr(match.startIndex + 1, maxAdjacentNewlines * 2) === (0, _lodash.repeat)("\r\n", maxAdjacentNewlines)) {
if (rootString.substr(match.startIndex + 1, maxAdjacentNewlines) === repeatLFNewLines || rootString.substr(match.startIndex + 1, maxAdjacentNewlines * 2) === repeatCRLFNewLines) {
(0, _utils.report)({

@@ -25,0 +28,0 @@ message: messages.rejected,

@@ -11,3 +11,4 @@ "use strict";

var validOptions = (0, _utils.validateOptions)(result, ruleName, {
maxLength: _lodash.isNumber
actual: maxLength,
possible: _lodash.isNumber
}, {

@@ -28,2 +29,4 @@ actual: options,

var ignoreNonComments = (0, _utils.optionsHaveIgnored)(options, "non-comments");
// Check first line

@@ -35,2 +38,12 @@ checkNewline({ endIndex: 0 });

function complain(index) {
(0, _utils.report)({
index: index,
result: result,
ruleName: ruleName,
message: messages.expected(maxLength),
node: root
});
}
function checkNewline(match) {

@@ -45,3 +58,3 @@ var nextNewlineIndex = rootString.indexOf("\n", match.endIndex);

// If the line's length is less than or equal to the specified
// max, ignore it
// max, ignore it ... So anything below is liable to be complained about
if (nextNewlineIndex - match.endIndex <= maxLength) {

@@ -51,9 +64,9 @@ return;

// If there are no spaces besides initial (indent) spaces, ignore it
var lineString = rootString.slice(match.endIndex, nextNewlineIndex);
if (lineString.replace(/^\s+/, "").indexOf(" ") === -1) {
return;
}
var complaintIndex = nextNewlineIndex - 1;
if ((0, _utils.optionsHaveIgnored)(options, "non-comments")) {
if (ignoreNonComments) {
if (match.insideComment) {
return complain(complaintIndex);
}
// This trimming business is to notice when the line starts a

@@ -63,14 +76,15 @@ // comment but that comment is indented, e.g.

var nextTwoChars = rootString.slice(match.endIndex).trim().slice(0, 2);
if (!match.insideComment && nextTwoChars !== "/*" && nextTwoChars !== "//") {
if (nextTwoChars !== "/*" && nextTwoChars !== "//") {
return;
}
return complain(complaintIndex);
}
(0, _utils.report)({
message: messages.expected(maxLength),
node: root,
index: nextNewlineIndex - 1,
result: result,
ruleName: ruleName
});
// If there are no spaces besides initial (indent) spaces, ignore it
var lineString = rootString.slice(match.endIndex, nextNewlineIndex);
if (lineString.replace(/^\s+/, "").indexOf(" ") === -1) {
return;
}
return complain(complaintIndex);
}

@@ -77,0 +91,0 @@ };

@@ -23,4 +23,3 @@ "use strict";

// Return early if the rule contains a keyframe selector
if (rule.parent.type === "atrule" && rule.parent.name === "keyframes") {
if ((0, _utils.cssRuleIsKeyframe)(rule)) {
return;

@@ -27,0 +26,0 @@ }

@@ -21,3 +21,3 @@ "use strict";

root.walkDecls(function (decl) {
if (decl.prop === "animation-name") {
if (decl.prop === "animation-name" && !animationNameKeywords.has(decl.value)) {
checkAnimationName(decl.value, decl);

@@ -108,2 +108,4 @@ }

// cf. https://developer.mozilla.org/en-US/docs/Web/CSS/animation
var animationShorthandKeywords = new Set(["infinite", "normal", "reverse", "alternate", "alternate-reverse", "none", "forwards", "backwards", "both", "running", "paused", "linear", "ease-in", "ease-out", "ease-in-out", "step-start", "step-end"]);
var animationShorthandKeywords = new Set(["infinite", "normal", "reverse", "alternate", "alternate-reverse", "none", "initial", "inherit", "unset", "forwards", "backwards", "both", "running", "paused", "linear", "ease-in", "ease-out", "ease-in-out", "step-start", "step-end"]);
var animationNameKeywords = new Set(["none", "initial", "inherit", "unset"]);

@@ -27,2 +27,6 @@ "use strict";

if ((0, _lodash.isEmpty)(propBlacklist)) {
return;
}
if ((0, _utils.matchesStringOrRegExp)(value, propBlacklist)) {

@@ -29,0 +33,0 @@ (0, _utils.report)({

@@ -27,2 +27,6 @@ "use strict";

if ((0, _lodash.isEmpty)(propWhitelist)) {
return;
}
if (!(0, _utils.matchesStringOrRegExp)(value, propWhitelist)) {

@@ -29,0 +33,0 @@ (0, _utils.report)({

@@ -32,2 +32,7 @@ "use strict";

// Ignore Sass intepolation possibilities
if (/#{.+}/.test(rule.selector)) {
return;
}
// Only bother resolving selectors that have an interpolating &

@@ -34,0 +39,0 @@ if (shouldResolveNestedSelectors && hasInterpolatingAmpersand(rule.selector)) {

@@ -21,2 +21,7 @@ "use strict";

root.walkRules(function (rule) {
// Ignore Sass intepolation possibilities
if (/#{.+}/.test(rule.selector)) {
return;
}
if ((0, _utils.cssRuleHasSelectorEndingWithColon)(rule)) {

@@ -23,0 +28,0 @@ return;

@@ -16,3 +16,3 @@ "use strict";

root.walkRules(function (rule) {
if ((0, _utils.cssRuleHasSelectorEndingWithColon)(rule)) {
if ((0, _utils.cssRuleHasSelectorEndingWithColon)(rule) || (0, _utils.cssRuleIsKeyframe)(rule)) {
return;

@@ -19,0 +19,0 @@ }

@@ -22,8 +22,4 @@ "use strict";

root.walkRules(function (rule) {
// Ignore keyframe selectors
if (rule.parent.type === "atrule" && rule.parent.name === "keyframes") {
return;
}
if ((0, _utils.cssRuleHasSelectorEndingWithColon)(rule)) {
if ((0, _utils.cssRuleHasSelectorEndingWithColon)(rule) || (0, _utils.cssRuleIsKeyframe)(rule)) {
return;

@@ -30,0 +26,0 @@ }

@@ -19,8 +19,4 @@ "use strict";

root.walkRules(function (rule) {
// Ignore keyframe selectors
if (rule.parent.type === "atrule" && rule.parent.name === "keyframes") {
return;
}
if ((0, _utils.cssRuleHasSelectorEndingWithColon)(rule)) {
if ((0, _utils.cssRuleHasSelectorEndingWithColon)(rule) || (0, _utils.cssRuleIsKeyframe)(rule)) {
return;

@@ -27,0 +23,0 @@ }

"use strict";
var _stylelintTestRuleTape = require("../../../testUtils/stylelint-test-rule-tape");
var _testRule = require("../../../testUtils/testRule");
var _stylelintTestRuleTape2 = _interopRequireDefault(_stylelintTestRuleTape);
var _testRule2 = _interopRequireDefault(_testRule);

@@ -13,3 +13,3 @@ var _ = require("..");

(0, _stylelintTestRuleTape2.default)(_2.default, {
(0, _testRule2.default)(_2.default, {
ruleName: _.ruleName,

@@ -68,3 +68,3 @@ config: ["always-before"],

(0, _stylelintTestRuleTape2.default)(_2.default, {
(0, _testRule2.default)(_2.default, {
ruleName: _.ruleName,

@@ -71,0 +71,0 @@ config: ["always-after"],

@@ -24,2 +24,6 @@ "use strict";

(0, _postcssValueParser2.default)(value).walk(function (node) {
if (node.type === "function" && node.value === "url") {
return false;
}
var unit = _postcssValueParser2.default.unit(node.value).unit;

@@ -26,0 +30,0 @@

@@ -24,2 +24,6 @@ "use strict";

(0, _postcssValueParser2.default)(value).walk(function (node) {
if (node.type === "function" && node.value === "url") {
return false;
}
var unit = _postcssValueParser2.default.unit(node.value).unit;

@@ -26,0 +30,0 @@

@@ -79,4 +79,13 @@ "use strict";

}
if (syntax === "scss") {
postcssProcessOptions.syntax = _postcssScss2.default;
switch (syntax) {
case "scss":
postcssProcessOptions.syntax = _postcssScss2.default;
break;
case "less":
postcssProcessOptions.syntax = _postcssLess2.default;
break;
case "sugarss":
postcssProcessOptions.syntax = _sugarss2.default;
break;
}

@@ -148,2 +157,10 @@

var _postcssLess = require("postcss-less");
var _postcssLess2 = _interopRequireDefault(_postcssLess);
var _sugarss = require("sugarss");
var _sugarss2 = _interopRequireDefault(_sugarss);
var _postcssPlugin = require("./postcssPlugin");

@@ -150,0 +167,0 @@

@@ -7,21 +7,30 @@ "use strict";

function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; }
var _createRuleTester = require("./createRuleTester");
var _postcss = require("postcss");
var _createRuleTester2 = _interopRequireDefault(_createRuleTester);
var _postcss2 = _interopRequireDefault(_postcss);
var _tape = require("tape");
exports["default"] = function (rule) {
return function (cssString, options, callback) {
if (typeof options === "function") {
callback = options;
options = null;
}
var _tape2 = _interopRequireDefault(_tape);
_postcss2["default"]().use(rule(options)).process(cssString).then(function (result) {
callback(result.warnings());
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
// This code is included here instead of using stylelint-test-rule-tape
// because tests performs significantly faster this way
function assertEquality(processCss, context) {
var testFn = context.only ? _tape2.default.only : _tape2.default;
testFn(context.caseDescription, function (t) {
t.plan(context.comparisonCount);
processCss.then(function (comparisons) {
comparisons.forEach(function (_ref) {
var actual = _ref.actual;
var expected = _ref.expected;
var description = _ref.description;
t.equal(actual, expected, description);
});
});
};
};
});
}
module.exports = exports["default"];
exports.default = (0, _createRuleTester2.default)(assertEquality);

@@ -97,2 +97,11 @@ "use strict";

var _cssRuleIsKeyframe = require("./cssRuleIsKeyframe");
Object.defineProperty(exports, "cssRuleIsKeyframe", {
enumerable: true,
get: function get() {
return _interopRequireDefault(_cssRuleIsKeyframe).default;
}
});
var _cssStatementStringBeforeBlock = require("./cssStatementStringBeforeBlock");

@@ -99,0 +108,0 @@

@@ -28,11 +28,11 @@ "use strict";

// If the target is an array of strings, though, we have to
// check whether some index of the source mathces *any* of
// check whether some index of the source matches *any* of
// those target strings (stopping after the first match).
var checkAgainstTarget = function () {
var getMatch = function () {
if (!targetIsArray) {
return checkChar.bind(null, target);
return getMatchBase.bind(null, target);
}
return function (index) {
for (var ti = 0, tl = target.length; ti < tl; ti++) {
var checkResult = checkChar(target[ti], index);
var checkResult = getMatchBase(target[ti], index);
if (checkResult) {

@@ -46,3 +46,3 @@ return checkResult;

function checkChar(targetString, index) {
function getMatchBase(targetString, index) {
var targetStringLength = targetString.length;

@@ -71,3 +71,2 @@

for (var i = 0, l = source.length; i < l; i++) {
var currentChar = source[i];

@@ -78,2 +77,3 @@

) {
// standard comments
if (source[i + 1] === "*") {

@@ -83,3 +83,3 @@ insideComment = true;

}
// single-line
// single-line comments
if (source[i + 1] === "/") {

@@ -92,3 +92,3 @@ insideComment = true;

// Register the end of a (standard) comment
// Register the end of a standard comment
if (insideComment && !insideSingleLineComment && currentChar === "*" && source[i - 1] !== "\\" // escaping

@@ -121,3 +121,3 @@ && source[i + 1] === "/") {

if (target === currentChar) {
matchFound(checkAgainstTarget(i));
handleMatch(getMatch(i));
}

@@ -148,5 +148,11 @@ continue;

openingParenCount++;
insideFunction = true;
// Only inside a function if there is a function name
// before the opening paren
if (/[a-zA-Z]/.test(source[i - 1])) {
insideFunction = true;
}
if (target === "(") {
matchFound(checkAgainstTarget(i));
handleMatch(getMatch(i));
}

@@ -159,8 +165,9 @@ continue;

openingParenCount--;
// Do this here so it's still technically inside a function
if (target === ")") {
handleMatch(getMatch(i));
}
if (openingParenCount === 0) {
insideFunction = false;
}
if (target === ")") {
matchFound(checkAgainstTarget(i));
}
continue;

@@ -174,3 +181,3 @@ }

var match = checkAgainstTarget(i);
var match = getMatch(i);

@@ -193,3 +200,3 @@ if (!match) {

}
matchFound(match);
handleMatch(match);
if (options.onlyOne) {

@@ -200,3 +207,3 @@ return;

function matchFound(match) {
function handleMatch(match) {
matchCount++;

@@ -203,0 +210,0 @@ callback(match, matchCount);

@@ -6,1 +6,3 @@ # Developer guide

- [Formatters](/docs/developer-guide/formatters.md) - writing your own formatters.
- [Rule Testers](/docs/developer-guide/rule-testers.md) - using and writing rule testers.
- [Benchmarks](/docs/developer-guide/benchmarks.md) - running benchmarks on rules.

@@ -35,4 +35,10 @@ # Working on rules

The most typical secondary options are `"ignores"` and `"except"`; but anything is possible.
The most typical secondary options are `"ignore": []` and `"except": []`; but anything is possible.
`"ignore"` and `"except"` accept an array of predefined keyword options e.g. `["relative", "first-nested", "descendant"]`. Use `"ignore"` when you want the rule to simply skip-over a particular pattern, and use `except` when you want to invert the primary option for a particular pattern.
Use a more specific secondary option name when accepting a *user-defined* list of things to ignore. For example, use `"ignoreAtRules": []` if a rule checks at-rules and you want to allow a user to specify which particular at-rule types to ignore.
A rule's secondary option can be anything if you're not ignoring or making exceptions. As an example, `resolveNestedSelectors: true|false` is used within some `selector-*` rules to change how the rule processes nested selectors.
*Use explicit, rather than implicit, options.* For example:

@@ -39,0 +45,0 @@

@@ -13,5 +13,5 @@ # User guide

- [Rules](/docs/user-guide/rules.md) - a list of all the rules that are available to you, and an explanation of the naming convention.
- [Example config](/docs/user-guide/example-config.md) - an example config that you can use as a foundation for crafting your own config.
- [Example Config](/docs/user-guide/example-config.md) - an example config that you can use as a foundation for crafting your own config.
- [Plugins](/docs/user-guide/plugins.md) - a brief introduction to plugins, followed by a list of what's available.
- [CSS Processors](/docs/user-guide/css-processors.md) - how to use the linter with CSS processors, like SCSS or PostCSS plugins.
- [Complementary Tools](/docs/user-guide/complementary-tools.md) - editor plugins (e.g. Atom and Sublime) and other linters.

@@ -39,2 +39,4 @@ # The stylelint CLI

The above can be slightly altered to read Less or SugarSS syntax: `--syntax less`, `--syntax sugarss`.
## Exit codes

@@ -41,0 +43,0 @@

@@ -12,12 +12,18 @@ # CSS processors

## Parsing SCSS
## Parsing non-standard syntax
The linter can *parse* SCSS syntax.
The linter can *parse* any the following non-standard syntaxes by using special PostCSS parsers:
- SCSS (using [`postcss-scss`](https://github.com/postcss/postcss-scss))
- Less (using [postcss-less](https://github.com/webschik/postcss-less))
- SugarSS (using [`sugarss`](https://github.com/postcss/sugarss))
(Whenever someone writes a PostCSS parser for another syntax, stylelint can easily add support for that.)
Both the [CLI](/docs/user-guide/cli.md) and the [Node API](docs/user-guide/cli.md) expose a `syntax` option.
- If you're using the CLI, use the `syntax` flag like so: `stylelint --syntax scss ...`
- If you're using the Node API, pass in the `syntax` option like so: `stylelint.lint({ syntax: "scss", ... })`.
- If you're using the Node API, pass in the `syntax` option like so: `stylelint.lint({ syntax: "sugarss", ... })`.
If you're using the linter as a [PostCSS Plugin](/docs/user-guide/postcss-plugin.md), you'll need to use [postcss-scss](https://github.com/postcss/postcss-scss) directly with PostCSS's `syntax` option like so:
If you're using the linter as a [PostCSS Plugin](/docs/user-guide/postcss-plugin.md), you'll need to use the special parser directly with PostCSS's `syntax` option like so:

@@ -27,2 +33,3 @@ ```js

var scss = require("postcss-scss")
// or use "postcss-less" or "sugarss"

@@ -29,0 +36,0 @@ postcss([

@@ -36,2 +36,3 @@ # Example config

"declaration-block-no-duplicate-properties": true,
"declaration-block-no-ignored-properties": true,
"declaration-block-no-shorthand-property-overrides": true,

@@ -60,2 +61,3 @@ "declaration-block-properties-order": "alphabetical"|[],

"function-parentheses-space-inside": "always"|"never"|"always-single-line"|"never-single-line",
"function-url-data-uris": "always"|"never",
"function-url-quotes": "single"|"double"|"none",

@@ -62,0 +64,0 @@ "function-whitelist": string|[],

@@ -66,3 +66,3 @@ # The stylelint Node API

Options: `"scss"`.
Options: `"scss"|"less"|"sugarss"`.

@@ -139,1 +139,3 @@ Specify a non-standard syntax that should be used to parse source stylesheets.

}).then(function() { .. });
The same pattern can be used to read Less or [SugarSS](https://github.com/postcss/sugarss) syntax.

@@ -87,3 +87,3 @@ # The stylelint PostCSS Plugin

Using the plugin with [`gulp-postcss`](https://github.com/postcss/gulp-postcss) and [`postcss-scss`](https://github.com/postcss/postcss-scss) to lint SCSS, and as part of the build task:
Using the plugin with [`gulp-postcss`](https://github.com/postcss/gulp-postcss) and [`postcss-less`](https://github.com/webschik/postcss-less) to lint Less, and as part of the build task:

@@ -95,7 +95,7 @@ *Note: the stylelint PostCSS plugin, unlike the stylelint CLI and node API, doesn't have a `syntax` option. Instead, the syntax must be set within the [PostCSS options](https://github.com/postcss/postcss#options) as there can only be one parser/syntax in a pipeline.*

var reporter = require("postcss-reporter")
var scss = require("postcss-scss")
var less = require("postcss-less")
var stylelint = require("stylelint")
gulp.task("build:scss", function () {
return gulp.src("src/**/*.scss")
gulp.task("build:less", function () {
return gulp.src("src/**/*.less")
.pipe(postcss([

@@ -106,3 +106,3 @@ stylelint({ /* your options */ }),

], {
syntax: scss
syntax: less
}))

@@ -112,2 +112,4 @@ })

The same pattern can be used to read SCSS or [SugarSS](https://github.com/postcss/sugarss) syntax.
### Example D

@@ -114,0 +116,0 @@

@@ -38,4 +38,6 @@ # Rules

- [`function-linear-gradient-no-nonstandard-direction`](../../src/rules/function-linear-gradient-no-nonstandard-direction/README.md): Disallow direction values in `linear-gradient()` calls that are not valid according to the [standard syntax](https://developer.mozilla.org/en-US/docs/Web/CSS/linear-gradient#Syntax).
- [`function-max-empty-lines`](../../src/rules/function-max-empty-lines/README.md): Limit the number of adjacent empty lines within functions.
- [`function-parentheses-newline-inside`](../../src/rules/function-parentheses-newline-inside/README.md): Require a newline or disallow whitespace on the inside of the parentheses of functions.
- [`function-parentheses-space-inside`](../../src/rules/function-parentheses-space-inside/README.md): Require a single space or disallow whitespace on the inside of the parentheses of functions.
- [`function-url-data-uris`](../../src/rules/function-url-data-uris/README.md): Require or disallow data URIs for urls.
- [`function-url-quotes`](../../src/rules/function-url-quotes/README.md): Specify single, double or no quotes for urls.

@@ -104,2 +106,3 @@ - [`function-whitelist`](../../src/rules/function-whitelist/README.md): Specify a whitelist of allowed functions.

- [`declaration-block-no-duplicate-properties`](../../src/rules/declaration-block-no-duplicate-properties/README.md): Disallow duplicate properties within declaration blocks.
- [`declaration-block-no-ignored-properties`](../../src/rules/declaration-block-no-ignored-properties/README.md): Disallow property values that are ignored due to another property value in the same rule.
- [`declaration-block-no-shorthand-property-overrides`](../../src/rules/declaration-block-no-shorthand-property-overrides/README.md): Disallow shorthand properties that override related longhand properties within declaration blocks.

@@ -106,0 +109,0 @@ - [`declaration-block-properties-order`](../../src/rules/declaration-block-properties-order/README.md): Specify the order of properties within declaration blocks.

{
"name": "stylelint",
"version": "5.2.1",
"version": "5.3.0",
"description": "Modern CSS linter",

@@ -48,2 +48,3 @@ "keywords": [

"postcss": "^5.0.4",
"postcss-less": "^0.8.0",
"postcss-reporter": "^1.3.0",

@@ -56,3 +57,4 @@ "postcss-resolve-nested-selector": "^0.1.1",

"specificity": "^0.1.5",
"stylehacks": "^2.3.0"
"stylehacks": "^2.3.0",
"sugarss": "^0.1.2"
},

@@ -63,2 +65,3 @@ "devDependencies": {

"babel-tape-runner": "^2.0.0",
"benchmark": "^2.1.0",
"eslint": "^2.4.0",

@@ -70,2 +73,4 @@ "eslint-config-stylelint": "^1.0.0",

"remark-lint": "^3.0.0",
"request": "^2.69.0",
"rimraf": "^2.5.2",
"sinon": "^1.16.1",

@@ -76,2 +81,4 @@ "tape": "^4.2.0",

"scripts": {
"benchmark-rule": "babel-node benchmark-rule.js",
"prebuild": "rimraf dist",
"build": "babel src --out-dir dist",

@@ -102,2 +109,3 @@ "prepublish": "npm run build",

"lint": {
"list-item-content-indent": false,
"list-item-indent": "space",

@@ -107,2 +115,3 @@ "list-item-spacing": false,

"maximum-line-length": false,
"no-missing-blank-lines": false,
"no-multiple-toplevel-headings": false

@@ -109,0 +118,0 @@ }

@@ -13,3 +13,3 @@ # stylelint

- **Support for the latest CSS syntax:** Including custom properties, range context for media features, calc() and nesting.
- **Understands *CSS-like* syntaxes:** The linter is powered by [PostCSS](https://github.com/postcss/postcss), so it understands any syntax that PostCSS can parse, including SCSS.
- **Understands *CSS-like* syntaxes:** The linter is powered by [PostCSS](https://github.com/postcss/postcss), so it understands any syntax that PostCSS can parse, including SCSS, [SugarSS](https://github.com/postcss/sugarss), and *experimental support* for Less.
- **Completely unopinionated:** Only enable the rules you want, and configure them with options that tailor the linter to your needs.

@@ -32,5 +32,5 @@ - **Shareable configs:** If you don't want to craft your own config, you can extend a shareable config.

- If you want to use a pre-written config, just find one and extend it. We recommend trying [`stylelint-config-standard`](https://github.com/stylelint/stylelint-config-standard), which includes around 60 of stylelint's rules with sensible defaults. (You can always override specific rules after extending a config.)
- To craft your own from the ground up, just learn about [some rules](/docs/user-guide/rules.md). *All of the rules are off by default*, so you only have to learn about the rules you want to turn on and enforce. That way you can start small, growing your config over time as you have a chance to explore more of the rules. Alternately, copy-paste [this example configuration](/docs/user-guide/example-config.md), which lists all of stylelint's rules and their primary options, then remove (or turn off) the rules you don't want and edit the primary option of each rule to your liking.
- To craft your own from the ground up, learn about [some rules](/docs/user-guide/rules.md) and how [they work together](/docs/user-guide/configuration.md#rules-work-together). *All of the rules are off by default*, so you only have to learn about the rules you want to turn on and enforce. That way you can start small, growing your config over time as you have a chance to explore more of the rules. Alternately, copy-paste [this example configuration](/docs/user-guide/example-config.md), which lists all of stylelint's rules and their primary options, then remove (or turn off) the rules you don't want and edit the primary option of each rule to your liking.
3. Create your [configuration](/docs/user-guide/configuration.md), probably as a `.stylelintrc` file.
4. Decide whether to use the [CLI](/docs/user-guide/cli.md), [Node API](/docs/user-guide/node-api.md), or [PostCSS plugin](/docs/user-guide/postcss-plugin.md). Be sure to [specify the syntax](/docs/user-guide/css-processors.md#parsing-scss) if you're using SCSS.
4. Decide whether to use the [CLI](/docs/user-guide/cli.md), [Node API](/docs/user-guide/node-api.md), or [PostCSS plugin](/docs/user-guide/postcss-plugin.md). Be sure to [specify the syntax](/docs/user-guide/css-processors.md) if you're using non-standard code (e.g. SCSS, SugarSS or Less).
5. Lint!

@@ -56,2 +56,3 @@

- Add new tests to *absolutely anything*.
- Work on [improving performance of rules](docs/developer-guide/benchmarks.md).
- Create or contribute to ecosystem tools, like the plugins for Atom and Sublime Text.

@@ -58,0 +59,0 @@ - Spread the word.

@@ -24,3 +24,3 @@ #!/usr/bin/env node

}
const syntaxOptions = ["scss"]
const syntaxOptions = [ "scss", "less", "sugarss" ]

@@ -56,3 +56,3 @@ const meowOptions = {

" -s, --syntax Specify a non-standard syntax that should be used to ",
" parse source stylesheets. Options: \"scss\"",
" parse source stylesheets. Options: \"scss\", \"less\", \"sugarss\"",
" -v, --verbose Get more stats",

@@ -59,0 +59,0 @@ ],

@@ -11,2 +11,5 @@ import postcssPlugin from "./postcssPlugin"

} from "./utils"
import {
createRuleTester,
} from "./testUtils"

@@ -25,3 +28,4 @@ const stylelint = postcssPlugin

stylelint.createPlugin = createPlugin
stylelint.createRuleTester = createRuleTester
module.exports = stylelint

@@ -18,5 +18,5 @@ import { isString } from "lodash"

expectedAfter: () => "Expected newline after \"}\"",
expectedAfterSingleLine: () => "Expected single space after \"}\" of a single-line block",
expectedAfterSingleLine: () => "Expected newline after \"}\" of a single-line block",
rejectedAfterSingleLine: () => "Unexpected whitespace after \"}\" of a single-line block",
expectedAfterMultiLine: () => "Expected single space after \"}\" of a multi-line block",
expectedAfterMultiLine: () => "Expected newline after \"}\" of a multi-line block",
rejectedAfterMultiLine: () => "Unexpected whitespace after \"}\" of a multi-line block",

@@ -51,11 +51,22 @@ })

function check(statement) {
const nextNode = statement.next()
if (!nextNode) { return }
if (!cssStatementHasBlock(statement)) { return }
if (cssStatementIsIgnoredAtRule(statement, options)) { return }
const nextNode = statement.next()
if (!nextNode) { return }
// Allow an end-of-line comment x spaces after the brace
const nextNodeIsSingleLineComment = (
nextNode.type === "comment"
&& !/[^ ]/.test(nextNode.raw("before"))
&& nextNode.toString().indexOf("\n") === -1
)
const nodeToCheck = (nextNodeIsSingleLineComment) ? nextNode.next() : nextNode
if (!nodeToCheck) { return }
// Only check one after, because there might be other
// spaces handled by the indentation rule
checker.afterOneOnly({
source: rawNodeString(nextNode),
source: rawNodeString(nodeToCheck),
index: -1,

@@ -62,0 +73,0 @@ lineCheckStr: cssStatementBlockString(statement),

@@ -12,2 +12,10 @@ # block-closing-brace-newline-after

This rule allows an end-of-line comment separated from the closing brace by spaces, as long as the comment contains no newlines. For example,
```css
a {
color: pink;
} /* end-of-line comment */
```
## Options

@@ -14,0 +22,0 @@

@@ -44,3 +44,3 @@ import {

// Allow an end-of-line comment x spaces after the semicolon
// Allow an end-of-line comment x spaces after the brace
const firstNode = statement.first

@@ -47,0 +47,0 @@ const firstNodeIsAcceptableComment = (

import valueParser from "postcss-value-parser"
// import _ from "lodash"
import {

@@ -22,3 +22,3 @@ declarationValueIndexOffset,

const FUNC_REPRESENTATION = [ "rgb", "rgba", "hsl", "hsla", "hwb", "gray" ]
const FUNC_REPRESENTATIONS = [ "rgb", "rgba", "hsl", "hsla", "hwb", "gray" ]
const NODE_TYPES = [ "word", "function" ]

@@ -48,5 +48,5 @@

if (
expectation === "never" &&
type === "word" &&
namedColors.indexOf(value) !== -1
expectation === "never"
&& type === "word"
&& namedColors.indexOf(value) !== -1
) {

@@ -58,33 +58,43 @@ complain(

)
return
}
// Check "always-where-possible" option
if (expectation === "always-where-possible") {
// First by checking for alternative color function representations
if (
type === "function" &&
FUNC_REPRESENTATION.indexOf(value) !== -1
) {
const cssString = valueParser.stringify(node).replace(/\s+/g, "")
namedColors.forEach(namedColor => {
if (representations[namedColor].func.indexOf(cssString) !== -1) {
complain(
messages.expected(namedColor, cssString),
decl,
declarationValueIndexOffset(decl) + sourceIndex
)
}
})
// Then by checking for alternative hex representations
} else {
namedColors.forEach(namedColor => {
if (representations[namedColor].hex.indexOf(value) !== -1) {
complain(
messages.expected(namedColor, value),
decl,
declarationValueIndexOffset(decl) + sourceIndex
)
}
})
// Check "always-where-possible" option ...
if (expectation !== "always-where-possible") { return }
// First by checking for alternative color function representations ...
if (
type === "function"
&& FUNC_REPRESENTATIONS.indexOf(value) !== -1
) {
// Remove all spaces to match what's in `representations`
const normalizedFunctionString = valueParser.stringify(node).replace(/\s+/g, "")
let namedColor
for (let i = 0, l = namedColors.length; i < l; i++) {
namedColor = namedColors[i]
if (representations[namedColor].func.indexOf(normalizedFunctionString) !== -1) {
complain(
messages.expected(namedColor, normalizedFunctionString),
decl,
declarationValueIndexOffset(decl) + sourceIndex
)
return // Exit as soon as a problem is found
}
}
return
}
// Then by checking for alternative hex representations
let namedColor
for (let i = 0, l = namedColors.length; i < l; i++) {
namedColor = namedColors[i]
if (representations[namedColor].hex.indexOf(value) !== -1) {
complain(
messages.expected(namedColor, value),
decl,
declarationValueIndexOffset(decl) + sourceIndex
)
return // Exit as soon as a problem is found
}
}
})

@@ -91,0 +101,0 @@ })

@@ -104,1 +104,5 @@ # color-named

```
```less
a { color: @blue; }
```

@@ -57,3 +57,3 @@ import {

if (comment.raws.inline) { return }
if (comment.raws.inline || comment.inline) { return }

@@ -60,0 +60,0 @@ const before = comment.raw("before")

@@ -30,3 +30,3 @@ import {

if (comment.raws.inline) { return }
if (comment.raws.inline || comment.inline) { return }

@@ -33,0 +33,0 @@ const rawComment = comment.toString()

@@ -21,2 +21,3 @@ import postcss from "postcss"

const INHERIT_KEYWORD = "inherit"
const INITIAL_KEYWORD = "initial"
const NORMAL_KEYWORD = "normal"

@@ -75,3 +76,3 @@ const RELATIVE_NAMED_WEIGHTS = [ "bolder", "lighter" ]

if (cssWordIsVariable(weightValue)) { return }
if (weightValue === INHERIT_KEYWORD) { return }
if (weightValue === INHERIT_KEYWORD || weightValue === INITIAL_KEYWORD) { return }

@@ -78,0 +79,0 @@ if (optionsHaveIgnored(options, "relative") &&

import {
isWhitespace,
report,

@@ -6,3 +7,2 @@ ruleMessages,

validateOptions,
whitespaceChecker,
} from "../../utils"

@@ -21,4 +21,2 @@ import valueParser from "postcss-value-parser"

export default function (actual) {
const checker = whitespaceChecker("space", "always", messages)
return (root, result) => {

@@ -28,2 +26,6 @@ const validOptions = validateOptions(result, ruleName, { actual })

function complain(message, node, index) {
report({ message, node, index, result, ruleName })
}
root.walkDecls(decl => {

@@ -47,3 +49,9 @@ valueParser(decl.value).walk(node => {

function checkSymbol(symbol) {
styleSearch({ source: expression, target: symbol, outsideFunctionalNotation: true }, match => {
const styleSearchOptions = {
source: expression,
target: symbol,
outsideFunctionalNotation: true,
}
styleSearch(styleSearchOptions, match => {
const index = match.startIndex

@@ -56,2 +64,3 @@

const expressionBeforeSign = expression.substr(0, index)
// Ignore signs at the beginning of the expression

@@ -63,39 +72,24 @@ if (/^\s*$/.test(expressionBeforeSign)) { return }

report({
message: messages.expectedOperatorBeforeSign(symbol),
node: decl,
index: expressionIndex + index,
result,
ruleName,
})
// And if not, complain
complain(messages.expectedOperatorBeforeSign(symbol), decl, expressionIndex + index)
return
}
checker.after({
index,
source: expression,
err: m => {
report({
message: m,
node: decl,
index: expressionIndex + index,
result,
ruleName,
})
},
})
checker.before({
index,
source: expression,
err: m => {
report({
message: m,
node: decl,
index: expressionIndex + index,
result,
ruleName,
})
},
})
const beforeOk = (
(expression[index - 1] === " " && !isWhitespace(expression[index - 2]))
|| newlineBefore(expression, index - 1)
)
if (!beforeOk) {
complain(messages.expectedBefore(symbol), decl, expressionIndex + index)
}
const afterOk = (
(expression[index + 1] === " " && !isWhitespace(expression[index + 2]))
|| expression[index + 1] === "\n"
|| expression.substr(index + 1, 2) === "\r\n"
)
if (!afterOk) {
complain(messages.expectedAfter(symbol), decl, expressionIndex + index)
}
})

@@ -111,1 +105,10 @@ }

}
function newlineBefore(str, startIndex) {
let index = startIndex
while (index && isWhitespace(str[index])) {
if (str[index] === "\n") return true
index--
}
return false
}

@@ -11,2 +11,4 @@ # function-calc-no-unspaced-operator

Before the operator, there must be a single whitespace or a newline plus indentation. After the operator, there must be a single whitespace or a newline.
The following patterns are considered warnings:

@@ -31,1 +33,11 @@

```
```css
margin-top: calc(var(--some-variable) +
var(--some-other-variable));
```
```css
margin-top: calc(var(--some-variable)
+ var(--some-other-variable));
```
import valueParser from "postcss-value-parser"
import {
cssDeclarationIsMap,
declarationValueIndexOffset,

@@ -45,5 +46,10 @@ report,

root.walkDecls(decl => {
if (cssDeclarationIsMap(decl)) { return }
valueParser(decl.value).walk(valueNode => {
if (valueNode.type !== "function") { return }
// Function nodes without names are things in parentheses like Sass lists
if (!valueNode.value) { return }
// Ignore `url()` arguments, which may contain data URIs or other funky stuff

@@ -50,0 +56,0 @@ if (valueNode.value === "url") { return }

import valueParser from "postcss-value-parser"
import {
cssDeclarationIsMap,
isSingleLineString,

@@ -34,2 +35,4 @@ declarationValueIndexOffset,

root.walkDecls(decl => {
if (cssDeclarationIsMap(decl)) { return }
if (decl.value.indexOf("(") === -1) { return }

@@ -40,2 +43,5 @@

// Function nodes without names are things in parentheses like Sass lists
if (!valueNode.value) { return }
const functionString = valueParser.stringify(valueNode)

@@ -42,0 +48,0 @@ const isMultiLine = !isSingleLineString(functionString)

import valueParser from "postcss-value-parser"
import {
cssDeclarationIsMap,
declarationValueIndexOffset,

@@ -37,2 +38,4 @@ isSingleLineString,

root.walkDecls(decl => {
if (cssDeclarationIsMap(decl)) { return }
if (decl.value.indexOf("(") === -1) { return }

@@ -43,2 +46,5 @@

// Function nodes without names are things in parentheses like Sass lists
if (!valueNode.value) { return }
const functionString = valueParser.stringify(valueNode)

@@ -45,0 +51,0 @@ const isSingleLine = isSingleLineString(functionString)

@@ -29,11 +29,12 @@ import { isString } from "lodash"

valueParser(value).walk(function (node) {
if (node.type === "function" && whitelist.indexOf(vendor.unprefixed(node.value)) === -1) {
report({
message: messages.rejected(node.value),
node: decl,
index: declarationValueIndexOffset(decl) + node.sourceIndex,
result,
ruleName,
})
}
if (node.type !== "function") { return }
if (!node.value) { return }
if (whitelist.indexOf(vendor.unprefixed(node.value)) !== -1) { return }
report({
message: messages.rejected(node.value),
node: decl,
index: declarationValueIndexOffset(decl) + node.sourceIndex,
result,
ruleName,
})
})

@@ -40,0 +41,0 @@ })

@@ -30,3 +30,3 @@ import {

styleSearch({ source: declString, target: ")" }, match => {
styleSearch({ source: declString, target: ")", withinFunctionalNotation: true }, match => {
checkClosingParen(declString, match.startIndex, decl)

@@ -33,0 +33,0 @@ })

@@ -62,2 +62,9 @@ # function-whitespace-after

```less
/* notice the )}, with no space after the closing parenthesis */
h1 {
max-height: ((@line-height) * (@lines-to-show))em;
}
```
### `"never"`

@@ -64,0 +71,0 @@

@@ -27,2 +27,3 @@ import atRuleSemicolonNewlineAfter from "./at-rule-semicolon-newline-after"

import declarationBlockNoDuplicateProperties from "./declaration-block-no-duplicate-properties"
import declarationBlockNoIgnoredProperties from "./declaration-block-no-ignored-properties"
import declarationBlockNoShorthandPropertyOverrides from "./declaration-block-no-shorthand-property-overrides"

@@ -49,4 +50,6 @@ import declarationBlockPropertiesOrder from "./declaration-block-properties-order"

import functionLinearGradientNoNonstandardDirection from "./function-linear-gradient-no-nonstandard-direction"
import functionMaxEmptyLines from "./function-max-empty-lines"
import functionParenthesesNewlineInside from "./function-parentheses-newline-inside"
import functionParenthesesSpaceInside from "./function-parentheses-space-inside"
import functionUrlDataUris from "./function-url-data-uris"
import functionUrlQuotes from "./function-url-quotes"

@@ -150,2 +153,3 @@ import functionWhitelist from "./function-whitelist"

"declaration-block-no-duplicate-properties": declarationBlockNoDuplicateProperties,
"declaration-block-no-ignored-properties": declarationBlockNoIgnoredProperties,
"declaration-block-no-shorthand-property-overrides": declarationBlockNoShorthandPropertyOverrides,

@@ -172,4 +176,6 @@ "declaration-block-properties-order": declarationBlockPropertiesOrder,

"function-linear-gradient-no-nonstandard-direction": functionLinearGradientNoNonstandardDirection,
"function-max-empty-lines": functionMaxEmptyLines,
"function-parentheses-newline-inside": functionParenthesesNewlineInside,
"function-parentheses-space-inside": functionParenthesesSpaceInside,
"function-url-data-uris": functionUrlDataUris,
"function-url-quotes": functionUrlQuotes,

@@ -176,0 +182,0 @@ "function-whitelist": functionWhitelist,

@@ -26,6 +26,9 @@ import { isNumber, repeat } from "lodash"

const rootString = root.toString()
const repeatLFNewLines = repeat("\n", maxAdjacentNewlines)
const repeatCRLFNewLines = repeat("\r\n", maxAdjacentNewlines)
styleSearch({ source: rootString, target: "\n", checkComments: true }, match => {
if (
rootString.substr(match.startIndex + 1, maxAdjacentNewlines) === repeat("\n", maxAdjacentNewlines)
|| rootString.substr(match.startIndex + 1, maxAdjacentNewlines * 2) === repeat("\r\n", maxAdjacentNewlines)
rootString.substr(match.startIndex + 1, maxAdjacentNewlines) === repeatLFNewLines
|| rootString.substr(match.startIndex + 1, maxAdjacentNewlines * 2) === repeatCRLFNewLines
) {

@@ -32,0 +35,0 @@ report({

@@ -19,3 +19,4 @@ import { isNumber } from "lodash"

const validOptions = validateOptions(result, ruleName, {
maxLength: isNumber,
actual: maxLength,
possible: isNumber,
}, {

@@ -34,2 +35,4 @@ actual: options,

const ignoreNonComments = optionsHaveIgnored(options, "non-comments")
// Check first line

@@ -41,2 +44,12 @@ checkNewline({ endIndex: 0 })

function complain(index) {
report({
index,
result,
ruleName,
message: messages.expected(maxLength),
node: root,
})
}
function checkNewline(match) {

@@ -51,12 +64,12 @@ let nextNewlineIndex = rootString.indexOf("\n", match.endIndex)

// If the line's length is less than or equal to the specified
// max, ignore it
// max, ignore it ... So anything below is liable to be complained about
if (nextNewlineIndex - match.endIndex <= maxLength) { return }
// If there are no spaces besides initial (indent) spaces, ignore it
const lineString = rootString.slice(match.endIndex, nextNewlineIndex)
if (lineString.replace(/^\s+/, "").indexOf(" ") === -1) {
return
}
const complaintIndex = nextNewlineIndex - 1
if (optionsHaveIgnored(options, "non-comments")) {
if (ignoreNonComments) {
if (match.insideComment) {
return complain(complaintIndex)
}
// This trimming business is to notice when the line starts a

@@ -66,17 +79,15 @@ // comment but that comment is indented, e.g.

const nextTwoChars = rootString.slice(match.endIndex).trim().slice(0, 2)
if (
!match.insideComment
&& (nextTwoChars !== "/*" && nextTwoChars !== "//")
) { return }
if (nextTwoChars !== "/*" && nextTwoChars !== "//") { return }
return complain(complaintIndex)
}
report({
message: messages.expected(maxLength),
node: root,
index: nextNewlineIndex - 1,
result,
ruleName,
})
// If there are no spaces besides initial (indent) spaces, ignore it
const lineString = rootString.slice(match.endIndex, nextNewlineIndex)
if (lineString.replace(/^\s+/, "").indexOf(" ") === -1) {
return
}
return complain(complaintIndex)
}
}
}

@@ -6,2 +6,3 @@ import { includes, union } from "lodash"

cssNodeContextLookup,
cssRuleIsKeyframe,
findAtRuleContext,

@@ -32,4 +33,3 @@ ruleMessages,

// Return early if the rule contains a keyframe selector
if (rule.parent.type === "atrule" && rule.parent.name === "keyframes") { return }
if (cssRuleIsKeyframe(rule)) { return }

@@ -36,0 +36,0 @@ const contextSelectorSet = selectorContextLookup.getContext(rule, findAtRuleContext(rule))

@@ -20,6 +20,10 @@ import postcss from "postcss"

"infinite", "normal", "reverse", "alternate", "alternate-reverse",
"none", "forwards", "backwards", "both", "running", "paused",
"none", "initial", "inherit", "unset", "forwards", "backwards", "both", "running", "paused",
"linear", "ease-in", "ease-out", "ease-in-out", "step-start", "step-end",
])
const animationNameKeywords = new Set([
"none", "initial", "inherit", "unset",
])
export default function (actual) {

@@ -36,3 +40,3 @@ return (root, result) => {

root.walkDecls(decl => {
if (decl.prop === "animation-name") {
if (decl.prop === "animation-name" && !animationNameKeywords.has(decl.value)) {
checkAnimationName(decl.value, decl)

@@ -39,0 +43,0 @@ }

import { vendor } from "postcss"
import { isObject, find } from "lodash"
import { isObject, isEmpty, find } from "lodash"
import {

@@ -30,2 +30,4 @@ report,

if (isEmpty(propBlacklist)) { return }
if (matchesStringOrRegExp(value, propBlacklist)) {

@@ -32,0 +34,0 @@ report({

import { vendor } from "postcss"
import { isObject, find } from "lodash"
import { isObject, isEmpty, find } from "lodash"
import {

@@ -30,2 +30,4 @@ report,

if (isEmpty(propWhitelist)) { return }
if (!matchesStringOrRegExp(value, propWhitelist)) {

@@ -32,0 +34,0 @@ report({

@@ -39,2 +39,5 @@ import resolveNestedSelector from "postcss-resolve-nested-selector"

// Ignore Sass intepolation possibilities
if (/#{.+}/.test(rule.selector)) { return }
// Only bother resolving selectors that have an interpolating &

@@ -41,0 +44,0 @@ if (shouldResolveNestedSelectors && hasInterpolatingAmpersand(rule.selector)) {

@@ -27,2 +27,5 @@ import selectorParser from "postcss-selector-parser"

root.walkRules(rule => {
// Ignore Sass intepolation possibilities
if (/#{.+}/.test(rule.selector)) { return }
if (cssRuleHasSelectorEndingWithColon(rule)) { return }

@@ -29,0 +32,0 @@ selectorParser(checkSelector).process(rule.selector)

import selectorParser from "postcss-selector-parser"
import {
cssRuleHasSelectorEndingWithColon,
cssRuleIsKeyframe,
report,

@@ -21,3 +22,6 @@ ruleMessages,

root.walkRules(rule => {
if (cssRuleHasSelectorEndingWithColon(rule)) { return }
if (
cssRuleHasSelectorEndingWithColon(rule)
|| cssRuleIsKeyframe(rule)
) { return }
selectorParser(selectorAST => {

@@ -24,0 +28,0 @@ selectorAST.eachId(idNode => {

@@ -5,2 +5,3 @@ import selectorParser from "postcss-selector-parser"

cssRuleHasSelectorEndingWithColon,
cssRuleIsKeyframe,
optionsHaveIgnored,

@@ -30,8 +31,7 @@ report,

root.walkRules(rule => {
// Ignore keyframe selectors
if (rule.parent.type === "atrule" && rule.parent.name === "keyframes") {
return
}
if (cssRuleHasSelectorEndingWithColon(rule)) { return }
if (
cssRuleHasSelectorEndingWithColon(rule)
|| cssRuleIsKeyframe(rule)
) { return }

@@ -38,0 +38,0 @@ selectorParser(checkSelector).process(rule.selector)

import selectorParser from "postcss-selector-parser"
import {
cssRuleHasSelectorEndingWithColon,
cssRuleIsKeyframe,
report,

@@ -27,8 +28,7 @@ ruleMessages,

root.walkRules(rule => {
// Ignore keyframe selectors
if (rule.parent.type === "atrule" && rule.parent.name === "keyframes") {
return
}
if (cssRuleHasSelectorEndingWithColon(rule)) { return }
if (
cssRuleHasSelectorEndingWithColon(rule)
|| cssRuleIsKeyframe(rule)
) { return }

@@ -48,3 +48,3 @@ function checkSelector(selectorAST) {

// & is not a type selector: it's used for nesting
// & is not a type selector: it's used for nesting
if (value[0] === "&") { return }

@@ -65,6 +65,6 @@

}
selectorParser(checkSelector).process(rule.selector)
})
}
}
}

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

import testRule from "../../../testUtils/stylelint-test-rule-tape"
import testRule from "../../../testUtils/testRule"
import rule, { ruleName, messages } from ".."

@@ -3,0 +4,0 @@

@@ -30,2 +30,4 @@ import { isString } from "lodash"

valueParser(value).walk(function (node) {
if (node.type === "function" && node.value === "url") { return false }
const unit = valueParser.unit(node.value).unit

@@ -32,0 +34,0 @@

@@ -30,2 +30,4 @@ import { isString } from "lodash"

valueParser(value).walk(function (node) {
if (node.type === "function" && node.value === "url") { return false }
const unit = valueParser.unit(node.value).unit

@@ -32,0 +34,0 @@

@@ -6,2 +6,4 @@ import postcss from "postcss"

import scssSyntax from "postcss-scss"
import lessSyntax from "postcss-less"
import sugarss from "sugarss"
import stylelintPostcssPlugin from "./postcssPlugin"

@@ -80,4 +82,13 @@ import * as formatters from "./formatters"

}
if (syntax === "scss") {
postcssProcessOptions.syntax = scssSyntax
switch (syntax) {
case "scss":
postcssProcessOptions.syntax = scssSyntax
break
case "less":
postcssProcessOptions.syntax = lessSyntax
break
case "sugarss":
postcssProcessOptions.syntax = sugarss
break
}

@@ -84,0 +95,0 @@

@@ -11,2 +11,3 @@ export { default as blurComments } from "./blurComments"

export { default as cssStatementHasEmptyBlock } from "./cssStatementHasEmptyBlock"
export { default as cssRuleIsKeyframe } from "./cssRuleIsKeyframe"
export { default as cssStatementStringBeforeBlock } from "./cssStatementStringBeforeBlock"

@@ -13,0 +14,0 @@ export { default as cssWordIsVariable } from "./cssWordIsVariable"

@@ -60,11 +60,11 @@ /**

// If the target is an array of strings, though, we have to
// check whether some index of the source mathces *any* of
// check whether some index of the source matches *any* of
// those target strings (stopping after the first match).
const checkAgainstTarget = (function () {
const getMatch = (function () {
if (!targetIsArray) {
return checkChar.bind(null, target)
return getMatchBase.bind(null, target)
}
return (index) => {
for (let ti = 0, tl = target.length; ti < tl; ti++) {
const checkResult = checkChar(target[ti], index)
const checkResult = getMatchBase(target[ti], index)
if (checkResult) { return checkResult }

@@ -76,3 +76,3 @@ }

function checkChar(targetString, index) {
function getMatchBase(targetString, index) {
const targetStringLength = targetString.length

@@ -101,3 +101,2 @@

for (let i = 0, l = source.length; i < l; i++) {
const currentChar = source[i]

@@ -111,2 +110,3 @@

) {
// standard comments
if (source[i + 1] === "*") {

@@ -116,3 +116,3 @@ insideComment = true

}
// single-line
// single-line comments
if (source[i + 1] === "/") {

@@ -125,3 +125,3 @@ insideComment = true

// Register the end of a (standard) comment
// Register the end of a standard comment
if (

@@ -156,3 +156,3 @@ insideComment && !insideSingleLineComment

// For string-quotes rule
if (target === currentChar) { matchFound(checkAgainstTarget(i)) }
if (target === currentChar) { handleMatch(getMatch(i)) }
continue

@@ -178,4 +178,10 @@ }

openingParenCount++
insideFunction = true
if (target === "(") { matchFound(checkAgainstTarget(i)) }
// Only inside a function if there is a function name
// before the opening paren
if (/[a-zA-Z]/.test(source[i - 1])) {
insideFunction = true
}
if (target === "(") { handleMatch(getMatch(i)) }
continue

@@ -187,6 +193,7 @@ }

openingParenCount--
// Do this here so it's still technically inside a function
if (target === ")") { handleMatch(getMatch(i)) }
if (openingParenCount === 0) {
insideFunction = false
}
if (target === ")") { matchFound(checkAgainstTarget(i)) }
continue

@@ -200,3 +207,3 @@ }

const match = checkAgainstTarget(i)
const match = getMatch(i)

@@ -209,7 +216,7 @@ if (!match) { continue }

if (options.withinComments && !insideComment) { continue }
matchFound(match)
handleMatch(match)
if (options.onlyOne) { return }
}
function matchFound(match) {
function handleMatch(match) {
matchCount++

@@ -216,0 +223,0 @@ callback(match, matchCount)

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