Initial commit

This commit is contained in:
Patrick Marsceill
2017-03-09 13:16:08 -05:00
commit b7b0d0d7bf
4147 changed files with 401224 additions and 0 deletions

100
node_modules/stylelint-scss/CHANGELOG.md generated vendored Normal file
View File

@@ -0,0 +1,100 @@
# 1.4.3
- Fixed: `at-mixin-no-argumentless-call-parentheses` messages
# 1.4.2:
- Fixed: false positives in inline comment detecting by `findCommentsInRaws` if a comment is the first/last in a file/line
- Fixed: `findCommentsInRaws` error in function detection
# 1.4.1
- Fixed: mixed import names for `at-else-closing-brace-space-after` and `at-else-empty-line-before` rules.
- Fixed: false positives for nested props rules (`:not()`-like selectors, strings, numbers).
# 1.4.0
- Added: `at-else-closing-brace-newline-after` rule.
- Added: `at-else-closing-brace-space-after` rule.
- Added: `at-if-closing-brace-newline-after` rule.
- Added: `at-if-closing-brace-space-after` rule.
- Added: `at-else-empty-line-before` rule.
- Added: `declaration-nested-properties` rule.
- Added: `declaration-nested-properties-no-divided-groups` rule.
- Added: `dollar-variable-empty-line-before` rule.
- Added: `ignore: "local"|"global"` to the `dollar-variable-pattern` rule.
- Added: `docs` folder to `npm` package.
- Removed: `src` folder from `npm` package.
- Removed: NodeJS 0.12.x support, stylelint-scss now requires NodeJS > 4.2.1 LTS or greater
# 1.3.4
- Fixed: parsing `-` and `+` at the operation start in `operator-` rules.
- Fixed: `findCommentsInRaws` false positives on comments inside strings (applicable to rules `double-slash-comment-inline`, `double-slash-comment-whitespace-inside`, `operator-no-unspaced`).
# 1.3.3
- Fixed: parsing `%` character by `operator-` rules.
- Fixed: false positives on `operator-` rules.
# 1.3.2
- Fixed: `findCommentsInRaws` fail on parsing selectors like `p:not(.not-p)` (applicable to rules `double-slash-comment-inline`, `double-slash-comment-whitespace-inside`, `operator-no-unspaced`).
- Fixed: 'double-slash-comment-whitespace-inside' false positives on empty comments (e.g. `//`).
- Fixed: `findCommentsInRaws` giving wrong column number (applicable to rules `double-slash-comment-inline`, `double-slash-comment-whitespace-inside`, `operator-no-unspaced`).
# 1.3.1
- Fixed: `findCommentsInRaws` for multiline CSS comments and text for //-comments (`double-slash-comment-` rules and `operator-no-unspaced` rule).
# 1.3.0
- Added: `at-mixin-argumentless-call-parentheses` rule (with "always"/"never" behavior as a replacement for `at-mixin-no-argumentless-call-parentheses`).
- Added: `dollar-variable-colon-newline-after` rule.
- Added: `dollar-variable-colon-space-after` rule.
- Added: `dollar-variable-colon-space-before` rule.
- Added: `double-slash-comment-empty-line-before` rule.
- Added: `double-slash-comment-inline` rule.
- Added: `double-slash-comment-whitespace-inside` rule.
- Added: `operator-no-newline-after` rule.
- Added: `operator-no-newline-before` rule.
- Added: `operator-no-unspaced` rule.
- Deprecated: `at-mixin-no-argumentless-call-parentheses`.
- Fixed: `partial-no-import` failing when linting a code string (not in an actual file, e.g. via stylelilnt Node API).
- Updated stylelint dependency to version 7.
# 1.2.1
- Fixed: `at-function-pattern`, `at-mixin-pattern` failing if there are parens inside a parameters list.
# 1.2.0
- Added: `partial-no-import` rule.
- Added: `media-feature-value-dollar-variable` rule.
- Added: `at-import-partial-extension-blacklist` rule.
- Added: `at-import-partial-extension-whitelist` rule.
- Deprecated: `at-import-no-partial-extension` rule.
- Fixed: `dollar-variable-no-missing-interpolation` was throwing an error on older Node.js versions.
# 1.1.1
- Fixed: newlines inside braces in `at-function-pattern`, `at-mixin-pattern`.
- Fixed: false positives and false negatives in `selector-no-redundant-nesting-selector`.
# 1.1.0
- Added: `at-mixin-no-argumentless-call-parentheses` rule.
- Added: `at-import-no-partial-leading-underscore` rule.
- Added: `at-import-no-partial-extension` rule.
- Added: `percent-placeholder-pattern` rule.
- Fixed: `selector-no-redundant-nesting-selector` no longer warns about BEM syntax.
- Fixed: bug causing rules to ignore severity levels `warning` / `error` and report `ignore` instead.
# 1.0.0
- Added: `at-extend-no-missing-placeholder` rule.
- Added: `at-function-pattern` rule.
- Added: `at-mixin-pattern` rule.
- Added: `dollar-variable-no-missing-interpolation` rule.
- Added: `dollar-variable-pattern` rule.
- Added: `selector-no-redundant-nesting-selector` rule.

21
node_modules/stylelint-scss/LICENSE generated vendored Normal file
View File

@@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) 2016 Krister Kari
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

147
node_modules/stylelint-scss/README.md generated vendored Normal file
View File

@@ -0,0 +1,147 @@
# stylelint-scss
[![NPM version](https://img.shields.io/npm/v/stylelint-scss.svg)](https://www.npmjs.com/package/stylelint-scss)
[![Build Status](https://travis-ci.org/kristerkari/stylelint-scss.svg?branch=master)](https://travis-ci.org/kristerkari/stylelint-scss)
[![Build status](https://ci.appveyor.com/api/projects/status/xa12kju6qmvmqs1n/branch/master?svg=true)](https://ci.appveyor.com/project/kristerkari/stylelint-scss/branch/master)
[![Coverage Status](https://coveralls.io/repos/github/kristerkari/stylelint-scss/badge.svg?branch=master)](https://coveralls.io/github/kristerkari/stylelint-scss?branch=master)
[![v1.4.0 progress](http://progressed.io/bar/100?title=v1.4.0)](https://github.com/kristerkari/stylelint-scss/milestones/1.4.0)
A collection of SCSS specific linting rules for [stylelint](https://github.com/stylelint/stylelint) (in a form of a plugin).
## Purpose
stylelint by itself supports [SCSS syntax](http://stylelint.io/user-guide/css-processors/#parsing-non-standard-syntax) very well (as well as other preprocessors' syntaxes). Moreover, it introduces some specific rules that can be used to lint SCSS, e.g. to limit [`nesting`](http://stylelint.io/user-guide/rules/max-nesting-depth/), control the way [`@-rules`](http://stylelint.io/user-guide/rules/#at-rule) are written. Yet stylelint is in general focused on standard CSS.
stylelint-scss introduces rules specific to SCSS syntax. That said, the rules from this plugin can be used with other syntaxes, like Less or some PostCSS syntaxes. That's why the rules' names are not tied to SCSS only (`at-function-pattern` instead of `scss-function-pattern`).
The plugin follows stylelint's guidelines (about [rule names](http://stylelint.io/user-guide/about-rules/), testing and [so on](https://github.com/stylelint/stylelint/tree/master/docs/developer-guide)).
## Installation and usage
stylelint-scss is a plugin for [stylelint](http://stylelint.io/user-guide/), so it's meant to be used with it.
**Node.js v4.2.1 or newer** is required. That's because stylelint itself [doesn't support Node.js versions below 4](https://github.com/stylelint/stylelint/blob/master/package.json#L32).
First, install stylelint-scss (and stylelint, if you haven't done so yet) via NPM:
```
npm install stylelint stylelint-scss
```
Create the `.stylelintrc.json` config file (or open the existing one), add `stylelint-scss` to the plugins array and the rules you need to the rules list. All rules from stylelint-scss need to be namespaced with `scss`.
```json
{
"plugins": [
"stylelint-scss"
],
"rules": {
"scss/dollar-variable-pattern": "^foo",
"scss/selector-no-redundant-nesting-selector": true,
...
}
}
```
Please refer to [stylelint docs](http://stylelint.io/user-guide/) for the detailed info on using this linter.
## List of rules
Here are stylelint-scss' rules, grouped by the [*thing*](http://apps.workflower.fi/vocabs/css/en) they apply to (just like in [stylelint](http://stylelint.io/user-guide/about-rules/)).
Please also see the [example configs](./docs/examples/) for special cases.
### `@`-else
- [`at-else-closing-brace-newline-after`](./src/rules/at-else-closing-brace-newline-after/README.md): Require or disallow a newline after the closing brace of `@else` statements.
- [`at-else-closing-brace-space-after`](./src/rules/at-else-closing-brace-space-after/README.md): Require a single space or disallow whitespace after the closing brace of `@else` statements.
- [`at-else-empty-line-before`](./src/rules/at-else-empty-line-before/README.md): Require an empty line or disallow empty lines before `@`-else.
### `@`-extend
- [`at-extend-no-missing-placeholder`](./src/rules/at-extend-no-missing-placeholder/README.md): Disallow at-extends (`@extend`) with missing placeholders.
### `@`-function
- [`at-function-pattern`](./src/rules/at-function-pattern/README.md): Specify a pattern for Sass/SCSS-like function names.
### `@`-if
- [`at-if-closing-brace-newline-after`](./src/rules/at-if-closing-brace-newline-after/README.md): Require or disallow a newline after the closing brace of `@if` statements.
- [`at-if-closing-brace-space-after`](./src/rules/at-if-closing-brace-space-after/README.md): Require a single space or disallow whitespace after the closing brace of `@if` statements.
### `@`-import
- [`at-import-no-partial-leading-underscore`](./src/rules/at-import-no-partial-leading-underscore/README.md): Disallow leading underscore in partial names in `@import`.
- [`at-import-partial-extension-blacklist`](./src/rules/at-import-partial-extension-blacklist/README.md): Specify blacklist of disallowed file extensions for partial names in `@import` commands.
- [`at-import-partial-extension-whitelist`](./src/rules/at-import-partial-extension-whitelist/README.md): Specify whitelist of allowed file extensions for partial names in `@import` commands.
### `@`-mixin
- [`at-mixin-argumentless-call-parentheses`](./src/rules/at-mixin-argumentless-call-parentheses/README.md): Require or disallow parentheses in argumentless `@mixin` calls.
- [`at-mixin-pattern`](./src/rules/at-mixin-pattern/README.md): Specify a pattern for Sass/SCSS-like mixin names.
### `$`-variable
- [`dollar-variable-colon-newline-after`](./src/rules/dollar-variable-colon-newline-after/README.md): Require a newline after the colon in `$`-variable declarations.
- [`dollar-variable-colon-space-after`](./src/rules/dollar-variable-colon-space-after/README.md): Require a single space or disallow whitespace after the colon in `$`-variable declarations.
- [`dollar-variable-colon-space-before`](./src/rules/dollar-variable-colon-space-before/README.md): Require a single space or disallow whitespace before the colon in `$`-variable declarations.
- [`dollar-variable-empty-line-before`](./src/rules/dollar-variable-empty-line-before/README.md): Require a single empty line or disallow empty lines before `$`-variable declarations.
- [`dollar-variable-no-missing-interpolation`](./src/rules/dollar-variable-no-missing-interpolation/README.md): Disallow Sass variables that are used without interpolation with CSS features that use custom identifiers.
- [`dollar-variable-pattern`](./src/rules/dollar-variable-pattern/README.md): Specify a pattern for Sass-like variables.
### `%`-placeholder
- [`percent-placeholder-pattern`](./src/rules/percent-placeholder-pattern/README.md): Specify a pattern for `%`-placeholders.
### `//`-comment
- [`double-slash-comment-empty-line-before`](./src/rules/double-slash-comment-empty-line-before/README.md): Require or disallow an empty line before `//`-comments.
- [`double-slash-comment-inline`](./src/rules/double-slash-comment-inline/README.md): Require or disallow `//`-comments to be inline comments.
- [`double-slash-comment-whitespace-inside`](./src/rules/double-slash-comment-whitespace-inside/README.md): Require or disallow whitespace after the `//` in `//`-comments
### Declaration
- [`declaration-nested-properties`](./src/rules/declaration-nested-properties/README.md): Require or disallow properties with `-` in their names to be in a form of a nested group.
- [`declaration-nested-properties-no-divided-groups`](./src/rules/declaration-nested-properties-no-divided-groups/README.md): Disallow nested properties of the same "namespace" be divided into multiple groups.
### Media feature
- [`media-feature-value-dollar-variable`](./src/rules/media-feature-value-dollar-variable/README.md): Require a media feature value be a `$`-variable or disallow `$`-variables in media feature values.
### Operator
- [`operator-no-newline-after`](./src/rules/operator-no-newline-after/README.md): Disallow linebreaks after Sass operators.
- [`operator-no-newline-before`](./src/rules/operator-no-newline-before/README.md): Disallow linebreaks before Sass operators.
- [`operator-no-unspaced`](./src/rules/operator-no-unspaced/README.md): Disallow unspaced operators in Sass operations.
### Partial
- [`partial-no-import`](./src/rules/partial-no-import/README.md): Disallow non-CSS `@import`s in partial files.
### Selector
- [`selector-no-redundant-nesting-selector`](./src/rules/selector-no-redundant-nesting-selector/README.md): Disallow redundant nesting selectors (`&`).
## Help out
There work on the plugin's rules is still in progress, so if you feel like it, you're welcome to help out in any of these (the plugin follows stylelint guidelines so most part of this is based on its docs):
* Create, enhance, and debug rules (see stylelint's guide to "[Working on rules](https://github.com/stylelint/stylelint/blob/master/docs/developer-guide/rules.md)").
* Improve documentation.
* Chime in on any open issue or pull request.
* Open new issues about your ideas on new rules, or for how to improve the existing ones, and pull requests to show us how your idea works.
* Add new tests to absolutely anything.
* Work on improving performance of rules.
* Contribute to [stylelint](https://github.com/stylelint/stylelint)
* Spread the word.
We communicate via [issues](https://github.com/kristerkari/stylelint-scss/issues) and [pull requests](https://github.com/kristerkari/stylelint-scss/pulls).
There is also [stackoverflow](http://stackoverflow.com/questions/tagged/stylelint), which would be the preferred QA forum.
## Important documents
- [Changelog](./CHANGELOG.md)
- [Contributing](./CONTRIBUTING.md)
- [License](./LICENSE)

21
node_modules/stylelint-scss/dist/index.js generated vendored Normal file
View File

@@ -0,0 +1,21 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
var _stylelint = require("stylelint");
var _utils = require("./utils");
var _rules = require("./rules");
var _rules2 = _interopRequireDefault(_rules);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
var rulesPlugins = Object.keys(_rules2.default).map(function (ruleName) {
return (0, _stylelint.createPlugin)((0, _utils.namespace)(ruleName), _rules2.default[ruleName]);
});
exports.default = rulesPlugins;

View File

@@ -0,0 +1,33 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.messages = exports.ruleName = undefined;
exports.default = function (expectation) {
return function (root, result) {
var validOptions = _stylelint.utils.validateOptions(result, ruleName, {
actual: expectation,
possible: ["always-last-in-chain"]
});
if (!validOptions) {
return;
}
(0, _atIfClosingBraceNewlineAfter.sassConditionalBraceNLAfterChecker)({ root: root, result: result, ruleName: ruleName, atRuleName: "else", expectation: expectation, messages: messages });
};
};
var _utils = require("../../utils");
var _stylelint = require("stylelint");
var _atIfClosingBraceNewlineAfter = require("../at-if-closing-brace-newline-after");
var ruleName = exports.ruleName = (0, _utils.namespace)("at-else-closing-brace-newline-after");
var messages = exports.messages = _stylelint.utils.ruleMessages(ruleName, {
expected: "Expected newline after \"}\" of @else statement",
rejected: "Unexpected newline after \"}\" of @else statement"
});

View File

@@ -0,0 +1,33 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.messages = exports.ruleName = undefined;
exports.default = function (expectation) {
return function (root, result) {
var validOptions = _stylelint.utils.validateOptions(result, ruleName, {
actual: expectation,
possible: ["always-intermediate", "never-intermediate"]
});
if (!validOptions) {
return;
}
(0, _atIfClosingBraceSpaceAfter.sassConditionalBraceSpaceAfterChecker)({ root: root, result: result, ruleName: ruleName, atRuleName: "else", expectation: expectation, messages: messages });
};
};
var _utils = require("../../utils");
var _stylelint = require("stylelint");
var _atIfClosingBraceSpaceAfter = require("../at-if-closing-brace-space-after");
var ruleName = exports.ruleName = (0, _utils.namespace)("at-else-closing-brace-space-after");
var messages = exports.messages = _stylelint.utils.ruleMessages(ruleName, {
expected: "Expected single space after \"}\" of @else statement",
rejected: "Unexpected space after \"}\" of @else statement"
});

View File

@@ -0,0 +1,49 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.messages = exports.ruleName = undefined;
exports.default = function (expectation) {
return function (root, result) {
var validOptions = _stylelint.utils.validateOptions(result, ruleName, {
actual: expectation,
possible: ["never"]
});
if (!validOptions) {
return;
}
root.walkAtRules(function (atrule) {
if (atrule.name !== "else") {
return;
}
// Don't need to ignore "the first rule in a stylesheet", etc, cases
// because @else should always go after @if
if (!(0, _utils.hasEmptyLine)(atrule.raws.before)) {
return;
}
_stylelint.utils.report({
message: messages.rejected,
node: atrule,
result: result,
ruleName: ruleName
});
});
};
};
var _utils = require("../../utils");
var _stylelint = require("stylelint");
var ruleName = exports.ruleName = (0, _utils.namespace)("at-else-empty-line-before");
var messages = exports.messages = _stylelint.utils.ruleMessages(ruleName, {
rejected: "Unxpected empty line before @else"
});

View File

@@ -0,0 +1,39 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.messages = exports.ruleName = undefined;
exports.default = function (actual) {
return function (root, result) {
var validOptions = _stylelint.utils.validateOptions(result, ruleName, { actual: actual });
if (!validOptions) {
return;
}
root.walkAtRules("extend", function (atrule) {
var isPlaceholder = atrule.params.trim()[0] === "%";
var isInterpolation = /^#{.+}/.test(atrule.params.trim());
if (!isPlaceholder && !isInterpolation) {
_stylelint.utils.report({
ruleName: ruleName,
result: result,
node: atrule,
message: messages.rejected
});
}
});
};
};
var _stylelint = require("stylelint");
var _utils = require("../../utils");
var ruleName = exports.ruleName = (0, _utils.namespace)("at-extend-no-missing-placeholder");
var messages = exports.messages = _stylelint.utils.ruleMessages(ruleName, {
rejected: "Expected a placeholder selector (e.g. %placeholder) to be used in @extend"
});

View File

@@ -0,0 +1,51 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.messages = exports.ruleName = undefined;
exports.default = function (pattern) {
return function (root, result) {
var validOptions = _stylelint.utils.validateOptions(result, ruleName, {
actual: pattern,
possible: [_lodash.isRegExp, _lodash.isString]
});
if (!validOptions) {
return;
}
var regexpPattern = (0, _lodash.isString)(pattern) ? new RegExp(pattern) : pattern;
root.walkAtRules(function (decl) {
if (decl.name !== "function") {
return;
}
// Stripping the function of its arguments
var funcName = decl.params.replace(/(\s*?)\((?:\s|\S)*\)/g, "");
if (regexpPattern.test(funcName)) {
return;
}
_stylelint.utils.report({
message: messages.expected,
node: decl,
result: result,
ruleName: ruleName
});
});
};
};
var _lodash = require("lodash");
var _stylelint = require("stylelint");
var _utils = require("../../utils");
var ruleName = exports.ruleName = (0, _utils.namespace)("at-function-pattern");
var messages = exports.messages = _stylelint.utils.ruleMessages(ruleName, {
expected: "Expected @function name to match specified pattern"
});

View File

@@ -0,0 +1,93 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.messages = exports.ruleName = undefined;
exports.default = function (expectation) {
return function (root, result) {
var validOptions = _stylelint.utils.validateOptions(result, ruleName, {
actual: expectation,
possible: ["always-last-in-chain"]
});
if (!validOptions) {
return;
}
sassConditionalBraceNLAfterChecker({ root: root, result: result, ruleName: ruleName, atRuleName: "if", expectation: expectation, messages: messages });
};
};
exports.sassConditionalBraceNLAfterChecker = sassConditionalBraceNLAfterChecker;
var _utils = require("../../utils");
var _stylelint = require("stylelint");
var ruleName = exports.ruleName = (0, _utils.namespace)("at-if-closing-brace-newline-after");
var messages = exports.messages = _stylelint.utils.ruleMessages(ruleName, {
expected: "Expected newline after \"}\" of @if statement",
rejected: "Unexpected newline after \"}\" of @if statement"
});
/**
* The core logic for this rule. Can be imported by other rules with similar
* logic, namely at-else-closing-brace-newline-after
*
* @param {Object} args -- Named arguments object
* @param {PostCSS root} args.root
* @param {PostCSS result} args.result
* @param {String ruleName} args.ruleName - needed for `report` function
* @param {String} args.atRuleName - the name of the at-rule to be checked, e.g. "if", "else"
* @param {Object} args.messages - returned by stylelint.utils.ruleMessages
* @return {undefined}
*/
function sassConditionalBraceNLAfterChecker(_ref) {
var root = _ref.root,
result = _ref.result,
ruleName = _ref.ruleName,
atRuleName = _ref.atRuleName,
expectation = _ref.expectation,
messages = _ref.messages;
function complain(node, message, index) {
_stylelint.utils.report({
result: result,
ruleName: ruleName,
node: node,
message: message,
index: index
});
}
root.walkAtRules(function (atrule) {
// Do nothing if it's not an @if
if (atrule.name !== atRuleName) {
return;
}
var nextNode = atrule.next();
if (!nextNode) {
return;
}
var nextBefore = nextNode.raws.before;
var hasNewLinesBeforeNext = nextBefore && !(0, _utils.isSingleLineString)(nextBefore);
var reportIndex = atrule.toString().length;
if (expectation === "always-last-in-chain") {
// If followed by @else, no newline is needed
if (nextNode.type === "atrule" && nextNode.name === "else") {
if (hasNewLinesBeforeNext) {
complain(atrule, messages.rejected, reportIndex);
}
} else {
if (!hasNewLinesBeforeNext) {
complain(atrule, messages.expected, reportIndex);
}
}
}
});
}

View File

@@ -0,0 +1,87 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.messages = exports.ruleName = undefined;
exports.default = function (expectation) {
return function (root, result) {
var validOptions = _stylelint.utils.validateOptions(result, ruleName, {
actual: expectation,
possible: ["always-intermediate", "never-intermediate"]
});
if (!validOptions) {
return;
}
sassConditionalBraceSpaceAfterChecker({ root: root, result: result, ruleName: ruleName, atRuleName: "if", expectation: expectation, messages: messages });
};
};
exports.sassConditionalBraceSpaceAfterChecker = sassConditionalBraceSpaceAfterChecker;
var _utils = require("../../utils");
var _stylelint = require("stylelint");
var ruleName = exports.ruleName = (0, _utils.namespace)("at-if-closing-brace-space-after");
var messages = exports.messages = _stylelint.utils.ruleMessages(ruleName, {
expected: "Expected single space after \"}\" of @if statement",
rejected: "Unexpected space after \"}\" of @if statement"
});
/**
* The core logic for this rule. Can be imported by other rules with similar
* logic, namely at-else-closing-brace-space-after
*
* @param {Object} args -- Named arguments object
* @param {PostCSS root} args.root
* @param {PostCSS result} args.result
* @param {String ruleName} args.ruleName - needed for `report` function
* @param {String} args.atRuleName - the name of the at-rule to be checked, e.g. "if", "else"
* @param {Object} args.messages - returned by stylelint.utils.ruleMessages
* @return {undefined}
*/
function sassConditionalBraceSpaceAfterChecker(_ref) {
var root = _ref.root,
result = _ref.result,
ruleName = _ref.ruleName,
atRuleName = _ref.atRuleName,
expectation = _ref.expectation,
messages = _ref.messages;
function complain(node, message, index) {
_stylelint.utils.report({
result: result,
ruleName: ruleName,
node: node,
message: message,
index: index
});
}
root.walkAtRules(function (atrule) {
// Do nothing if it's not an @if
if (atrule.name !== atRuleName) {
return;
}
var nextNode = atrule.next();
var hasSpaceAfter = nextNode && nextNode.raws.before === " ";
var hasWhiteSpaceAfter = nextNode && nextNode.raws.before !== "";
var reportIndex = atrule.toString().length;
// When followed by an @else
if (nextNode && nextNode.type === "atrule" && nextNode.name === "else") {
// A single space is needed
if (expectation === "always-intermediate" && !hasSpaceAfter) {
complain(atrule, messages.expected, reportIndex);
} else if (expectation === "never-intermediate" && hasWhiteSpaceAfter) {
// No whitespace is needed
complain(atrule, messages.rejected, reportIndex);
}
}
});
}

View File

@@ -0,0 +1,88 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.messages = exports.ruleName = undefined;
exports.default = function (on, options) {
return function (root, result) {
var validOptions = _stylelint.utils.validateOptions(result, ruleName, {
actual: on
}, {
actual: options,
possible: {
// Accepting array of either strings or regular expressions
ignoreExtensions: function ignoreExtensions(str) {
return (0, _lodash.isRegExp)(str) || (0, _lodash.isString)(str);
}
},
optional: true
});
if (!validOptions) {
return;
}
result.warn("The 'at-import-no-partial-extension' rule has been deprecated, " + "and will be removed in '2.0'. Instead, use 'at-import-partial-extension-blacklist' or 'at-import-partial-extension-whitelist' rules.", {
stylelintType: "deprecation"
});
function checkPathForUnderscore(path, decl) {
// Stripping trailing quotes and whitespaces, if any
var pathStripped = path.replace(/^\s*?("|')\s*/, "").replace(/\s*("|')\s*?$/, "");
var extension = _path2.default.extname(pathStripped).slice(1);
// If the extension is not empty
if (!extension) {
return;
}
// Skipping importing CSS: url(), ".css", URI with a protocol, media
if (pathStripped.slice(0, 4) === "url(" || pathStripped.slice(-4) === ".css" || pathStripped.search("//") !== -1 || pathStripped.search(/(?:\s|[,)"'])\w+$/) !== -1) {
return;
}
if (options && options.ignoreExtensions) {
// Return if...
if (options.ignoreExtensions.some(function (ignoredExt) {
// the extension matches one of the ignored strings or Regexps
return (0, _lodash.isString)(ignoredExt) && ignoredExt === extension || (0, _lodash.isRegExp)(ignoredExt) && extension.search(ignoredExt) !== -1;
})) {
return;
}
}
_stylelint.utils.report({
message: messages.expected,
node: decl,
result: result,
ruleName: ruleName
});
}
root.walkAtRules("import", function (atRule) {
// Processing comma-separated lists of import paths
atRule.params.split(",").forEach(function (path) {
checkPathForUnderscore(path, atRule);
});
});
};
};
var _lodash = require("lodash");
var _stylelint = require("stylelint");
var _utils = require("../../utils");
var _path = require("path");
var _path2 = _interopRequireDefault(_path);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
var ruleName = exports.ruleName = (0, _utils.namespace)("at-import-no-partial-extension");
var messages = exports.messages = _stylelint.utils.ruleMessages(ruleName, {
expected: "Unexpected file extension in imported partial name"
});

View File

@@ -0,0 +1,54 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.messages = exports.ruleName = undefined;
exports.default = function (actual) {
return function (root, result) {
var validOptions = _stylelint.utils.validateOptions(result, ruleName, { actual: actual });
if (!validOptions) {
return;
}
function checkPathForUnderscore(path, decl) {
// Stripping trailing quotes and whitespaces, if any
var pathStripped = path.replace(/^\s*?("|')\s*/, "").replace(/\s*("|')\s*?$/, "");
// Searching a _ at the start of filename
if (pathStripped.search(/(?:^|\/|\\)_[^/]+$/) === -1) {
return;
}
// Skipping importing CSS: url(), ".css", URI with a protocol, media
if (pathStripped.slice(0, 4) === "url(" || pathStripped.slice(-4) === ".css" || pathStripped.search("//") !== -1 || pathStripped.search(/(?:\s|[,)"'])\w+$/) !== -1) {
return;
}
_stylelint.utils.report({
message: messages.expected,
node: decl,
result: result,
ruleName: ruleName
});
}
root.walkAtRules("import", function (decl) {
// Processing comma-separated lists of import paths
decl.params.split(",").forEach(function (path) {
checkPathForUnderscore(path, decl);
});
});
};
};
var _stylelint = require("stylelint");
var _utils = require("../../utils");
var ruleName = exports.ruleName = (0, _utils.namespace)("at-import-no-partial-leading-underscore");
var messages = exports.messages = _stylelint.utils.ruleMessages(ruleName, {
expected: "Unexpected leading underscore in imported partial name"
});

View File

@@ -0,0 +1,76 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.messages = exports.ruleName = undefined;
exports.default = function (blacklistOption) {
var blacklist = [].concat(blacklistOption);
return function (root, result) {
var validOptions = _stylelint.utils.validateOptions(result, ruleName, {
actual: blacklistOption,
possible: [_lodash.isString, _lodash.isRegExp]
});
if (!validOptions) {
return;
}
function checkPathForUnderscore(path, decl) {
// Stripping trailing quotes and whitespaces, if any
var pathStripped = path.replace(/^\s*?("|')\s*/, "").replace(/\s*("|')\s*?$/, "");
var extension = _path2.default.extname(pathStripped).slice(1);
// Save this separately to be able to pass the original string to report()
var extensionNormalized = extension.toLowerCase();
// If the extension is empty
if (!extension) {
return;
}
// Skipping importing CSS: url(), ".css", URI with a protocol, media
if (pathStripped.slice(0, 4) === "url(" || pathStripped.slice(-4) === ".css" || pathStripped.search("//") !== -1 || pathStripped.search(/(?:\s|[,)"'])\w+$/) !== -1) {
return;
}
blacklist.forEach(function (ext) {
if ((0, _lodash.isString)(ext) && extensionNormalized === ext || (0, _lodash.isRegExp)(ext) && extensionNormalized.search(ext) !== -1) {
_stylelint.utils.report({
message: messages.rejected(extension),
node: decl,
word: extension,
result: result,
ruleName: ruleName
});
}
});
}
root.walkAtRules("import", function (atRule) {
// Processing comma-separated lists of import paths
atRule.params.split(",").forEach(function (path) {
checkPathForUnderscore(path, atRule);
});
});
};
};
var _lodash = require("lodash");
var _stylelint = require("stylelint");
var _utils = require("../../utils");
var _path = require("path");
var _path2 = _interopRequireDefault(_path);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
var ruleName = exports.ruleName = (0, _utils.namespace)("at-import-partial-extension-blacklist");
var messages = exports.messages = _stylelint.utils.ruleMessages(ruleName, {
rejected: function rejected(ext) {
return "Unexpected extension \"." + ext + "\" in imported partial name";
}
});

View File

@@ -0,0 +1,78 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.messages = exports.ruleName = undefined;
exports.default = function (whitelistOption) {
var whitelist = [].concat(whitelistOption);
return function (root, result) {
var validOptions = _stylelint.utils.validateOptions(result, ruleName, {
actual: whitelistOption,
possible: [_lodash.isString, _lodash.isRegExp]
});
if (!validOptions) {
return;
}
function checkPathForUnderscore(path, decl) {
// Stripping trailing quotes and whitespaces, if any
var pathStripped = path.replace(/^\s*?("|')\s*/, "").replace(/\s*("|')\s*?$/, "");
var extension = _path2.default.extname(pathStripped).slice(1);
// Save this separately to be able to pass the original string to report()
var extensionNormalized = extension.toLowerCase();
// If the extension is empty
if (!extension) {
return;
}
// Skipping importing CSS: url(), ".css", URI with a protocol, media
if (pathStripped.slice(0, 4) === "url(" || pathStripped.slice(-4) === ".css" || pathStripped.search("//") !== -1 || pathStripped.search(/(?:\s|[,)"'])\w+$/) !== -1) {
return;
}
if (whitelist.some(function (ext) {
return (0, _lodash.isString)(ext) && extensionNormalized === ext || (0, _lodash.isRegExp)(ext) && extensionNormalized.search(ext) !== -1;
})) {
return;
}
_stylelint.utils.report({
message: messages.rejected(extension),
node: decl,
word: extension,
result: result,
ruleName: ruleName
});
}
root.walkAtRules("import", function (atRule) {
// Processing comma-separated lists of import paths
atRule.params.split(",").forEach(function (path) {
checkPathForUnderscore(path, atRule);
});
});
};
};
var _lodash = require("lodash");
var _stylelint = require("stylelint");
var _utils = require("../../utils");
var _path = require("path");
var _path2 = _interopRequireDefault(_path);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
var ruleName = exports.ruleName = (0, _utils.namespace)("at-import-partial-extension-whitelist");
var messages = exports.messages = _stylelint.utils.ruleMessages(ruleName, {
rejected: function rejected(ext) {
return "Unexpected extension \"." + ext + "\" in imported partial name";
}
});

View File

@@ -0,0 +1,53 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.messages = exports.ruleName = undefined;
exports.default = function (value) {
return function (root, result) {
var validOptions = _stylelint.utils.validateOptions(result, ruleName, {
actual: value,
possible: ["always", "never"]
});
if (!validOptions) {
return;
}
root.walkAtRules("include", function (mixinCall) {
// If it is "No parens in argumentless calls"
if (value === "never" && mixinCall.params.search(/\(\s*?\)\s*?$/) === -1) {
return;
}
// If it is "Always use parens"
if (value === "always" && mixinCall.params.search(/\(/) !== -1) {
return;
}
var mixinName = /\s*(\S*?)\s*(?:\(|$)/.exec(mixinCall.params)[1];
_stylelint.utils.report({
message: messages[value === "never" ? "rejected" : "expected"](mixinName),
node: mixinCall,
result: result,
ruleName: ruleName
});
});
};
};
var _stylelint = require("stylelint");
var _utils = require("../../utils");
var ruleName = exports.ruleName = (0, _utils.namespace)("at-mixin-no-argumentless-call-parentheses");
var messages = exports.messages = _stylelint.utils.ruleMessages(ruleName, {
expected: function expected(mixin) {
return "Expected parentheses in mixin \"" + mixin + "\" call";
},
rejected: function rejected(mixin) {
return "Unexpected parentheses in argumentless mixin \"" + mixin + "\" call";
}
});

View File

@@ -0,0 +1,38 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.messages = exports.ruleName = undefined;
exports.default = function (actual) {
return function (root, result) {
var validOptions = _stylelint.utils.validateOptions(result, ruleName, { actual: actual });
if (!validOptions) {
return;
}
root.walkAtRules("include", function (decl) {
if (decl.params.search(/\(\s*?\)\s*?$/) === -1) {
return;
}
_stylelint.utils.report({
message: messages.expected,
node: decl,
result: result,
ruleName: ruleName
});
});
};
};
var _stylelint = require("stylelint");
var _utils = require("../../utils");
var ruleName = exports.ruleName = (0, _utils.namespace)("at-mixin-no-argumentless-call-parentheses");
var messages = exports.messages = _stylelint.utils.ruleMessages(ruleName, {
expected: "Unexpected parentheses in argumentless @mixin call"
});

View File

@@ -0,0 +1,51 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.messages = exports.ruleName = undefined;
exports.default = function (pattern) {
return function (root, result) {
var validOptions = _stylelint.utils.validateOptions(result, ruleName, {
actual: pattern,
possible: [_lodash.isRegExp, _lodash.isString]
});
if (!validOptions) {
return;
}
var regexpPattern = (0, _lodash.isString)(pattern) ? new RegExp(pattern) : pattern;
root.walkAtRules(function (decl) {
if (decl.name !== "mixin") {
return;
}
// Stripping the mixin of its arguments
var mixinName = decl.params.replace(/(\s*?)\((?:\s|\S)*\)/g, "");
if (regexpPattern.test(mixinName)) {
return;
}
_stylelint.utils.report({
message: messages.expected,
node: decl,
result: result,
ruleName: ruleName
});
});
};
};
var _lodash = require("lodash");
var _stylelint = require("stylelint");
var _utils = require("../../utils");
var ruleName = exports.ruleName = (0, _utils.namespace)("at-mixin-pattern");
var messages = exports.messages = _stylelint.utils.ruleMessages(ruleName, {
expected: "Expected @mixin name to match specified pattern"
});

View File

@@ -0,0 +1,68 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.messages = exports.ruleName = undefined;
exports.default = function (expectation) {
return function (root, result) {
var validOptions = _stylelint.utils.validateOptions(result, ruleName, {
actual: expectation
});
if (!validOptions) {
return;
}
root.walk(function (item) {
if (item.type !== "rule" && item.type !== "atrule") {
return;
}
var nestedGroups = {};
// Find all nested property groups
item.each(function (decl) {
if (decl.type !== "rule") {
return;
}
var testForProp = (0, _utils.parseNestedPropRoot)(decl.selector);
if (testForProp && testForProp.propName !== undefined) {
var ns = testForProp.propName.value;
if (!nestedGroups.hasOwnProperty(ns)) {
nestedGroups[ns] = [];
}
nestedGroups[ns].push(decl);
}
});
Object.keys(nestedGroups).forEach(function (namespace) {
// Only warn if there are more than one nested groups with equal namespaces
if (nestedGroups[namespace].length === 1) {
return;
}
nestedGroups[namespace].forEach(function (group) {
_stylelint.utils.report({
message: messages.expected(namespace),
node: group,
result: result,
ruleName: ruleName
});
});
});
});
};
};
var _utils = require("../../utils");
var _stylelint = require("stylelint");
var ruleName = exports.ruleName = (0, _utils.namespace)("declaration-nested-properties-no-divided-groups");
var messages = exports.messages = _stylelint.utils.ruleMessages(ruleName, {
expected: function expected(prop) {
return "Expected all nested properties of \"" + prop + "\" namespace to be in one nested group";
}
});

View File

@@ -0,0 +1,146 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.messages = exports.ruleName = undefined;
exports.default = function (expectation, options) {
return function (root, result) {
var validOptions = _stylelint.utils.validateOptions(result, ruleName, {
actual: expectation,
possible: ["always", "never"]
}, {
actual: options,
possible: {
except: ["only-of-namespace"]
},
optional: true
});
if (!validOptions) {
return;
}
if (expectation === "always") {
root.walk(function (item) {
if (item.type !== "rule" && item.type !== "atrule") {
return;
}
var warningCandidates = {};
item.each(function (decl) {
var prop = decl.prop,
type = decl.type,
selector = decl.selector;
// Looking for namespaced non-nested properties
// Namespaced prop is basically a prop with a `-` in a name, e.g. `margin-top`
if (type === "decl") {
if (!(0, _utils.isStandardSyntaxProperty)(prop)) {
return;
}
// Add simple namespaced prop decls to warningCandidates.ns
// (prop names with browser prefixes are ignored)
var seekNamespace = /^([a-zA-Z0-9]+)-/.exec(prop);
if (seekNamespace && seekNamespace[1]) {
var ns = seekNamespace[1];
if (!warningCandidates.hasOwnProperty(ns)) {
warningCandidates[ns] = [];
}
warningCandidates[ns].push({ node: decl });
}
}
// Nested props, `prop: [value] { <nested decls> }`
if (type === "rule") {
// `background:red {` - selector;
// `background: red {` - nested prop; space is decisive here
var testForProp = (0, _utils.parseNestedPropRoot)(selector);
if (testForProp && testForProp.propName !== undefined) {
var _ns = testForProp.propName.value;
if (!warningCandidates.hasOwnProperty(_ns)) {
warningCandidates[_ns] = [];
}
warningCandidates[_ns].push({
node: decl,
nested: true
});
}
}
});
// Now check if the found properties deserve warnings
Object.keys(warningCandidates).forEach(function (namespace) {
var exceptIfOnlyOfNs = (0, _utils.optionsHaveException)(options, "only-of-namespace");
var moreThanOneProp = warningCandidates[namespace].length > 1;
warningCandidates[namespace].forEach(function (candidate) {
if (candidate.nested === true) {
if (exceptIfOnlyOfNs) {
// If there is only one prop inside a nested prop - warn (reverse "always")
if (candidate.nested === true && candidate.node.nodes.length === 1) {
_stylelint.utils.report({
message: messages.rejected(namespace),
node: candidate.node,
result: result,
ruleName: ruleName
});
}
}
} else {
// Don't warn on non-nested namespaced props if there are
// less than 2 of them, and except: "only-of-namespace" is set
if (exceptIfOnlyOfNs && !moreThanOneProp) {
return;
}
_stylelint.utils.report({
message: messages.expected(candidate.node.prop),
node: candidate.node,
result: result,
ruleName: ruleName
});
}
});
});
});
} else if (expectation === "never") {
root.walk(function (item) {
// Just check if there are ANY nested props
if (item.type === "rule") {
// `background:red {` - selector;
// `background: red {` - nested prop; space is decisive here
var testForProp = (0, _utils.parseNestedPropRoot)(item.selector);
if (testForProp && testForProp.propName !== undefined) {
_stylelint.utils.report({
message: messages.rejected(testForProp.propName.value),
result: result,
ruleName: ruleName,
node: item
});
}
}
});
}
};
};
var _utils = require("../../utils");
var _stylelint = require("stylelint");
var ruleName = exports.ruleName = (0, _utils.namespace)("declaration-nested-properties");
var messages = exports.messages = _stylelint.utils.ruleMessages(ruleName, {
expected: function expected(prop) {
return "Expected property \"" + prop + "\" to be in a nested form";
},
rejected: function rejected(prop) {
return "Unexpected nested property \"" + prop + "\"";
}
});

View File

@@ -0,0 +1,79 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.messages = exports.ruleName = undefined;
exports.default = function (expectation) {
var checker = (0, _utils.whitespaceChecker)("newline", expectation, messages);
return function (root, result) {
var validOptions = _stylelint.utils.validateOptions(result, ruleName, {
actual: expectation,
possible: ["always", "always-multi-line"]
});
if (!validOptions) {
return;
}
root.walkDecls(function (decl) {
if (!decl.prop || decl.prop[0] !== "$") {
return;
}
// Get the raw $var, and only that
var endOfPropIndex = (0, _utils.declarationValueIndex)(decl) + decl.raw("between").length - 1;
// `$var:`, `$var :`
var propPlusColon = decl.toString().slice(0, endOfPropIndex);
var _loop = function _loop(i, l) {
if (propPlusColon[i] !== ":") {
return "continue";
}
var indexToCheck = propPlusColon.substr(propPlusColon[i], 3) === "/*" ? propPlusColon.indexOf("*/", i) + 1 : i;
checker.afterOneOnly({
source: propPlusColon,
index: indexToCheck,
lineCheckStr: decl.value,
err: function err(m) {
_stylelint.utils.report({
message: m,
node: decl,
index: indexToCheck,
result: result,
ruleName: ruleName
});
}
});
return "break";
};
_loop2: for (var i = 0, l = propPlusColon.length; i < l; i++) {
var _ret = _loop(i, l);
switch (_ret) {
case "continue":
continue;
case "break":
break _loop2;}
}
});
};
};
var _utils = require("../../utils");
var _stylelint = require("stylelint");
var ruleName = exports.ruleName = (0, _utils.namespace)("dollar-variable-colon-newline-after");
var messages = exports.messages = _stylelint.utils.ruleMessages(ruleName, {
expectedAfter: function expectedAfter() {
return "Expected newline after \":\"";
},
expectedAfterMultiLine: function expectedAfterMultiLine() {
return "Expected newline after \":\" with a multi-line value";
}
});

View File

@@ -0,0 +1,97 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.messages = exports.ruleName = undefined;
exports.default = function (expectation) {
var checker = (0, _utils.whitespaceChecker)("space", expectation, messages);
return function (root, result) {
var validOptions = _stylelint.utils.validateOptions(result, ruleName, {
actual: expectation,
possible: ["always", "never", "always-single-line"]
});
if (!validOptions) {
return;
}
variableColonSpaceChecker({
root: root,
result: result,
locationChecker: checker.after,
checkedRuleName: ruleName
});
};
};
exports.variableColonSpaceChecker = variableColonSpaceChecker;
var _utils = require("../../utils");
var _stylelint = require("stylelint");
var ruleName = exports.ruleName = (0, _utils.namespace)("dollar-variable-colon-space-after");
var messages = exports.messages = _stylelint.utils.ruleMessages(ruleName, {
expectedAfter: function expectedAfter() {
return "Expected single space after \":\"";
},
rejectedAfter: function rejectedAfter() {
return "Unexpected whitespace after \":\"";
},
expectedAfterSingleLine: function expectedAfterSingleLine() {
return "Expected single space after \":\" with a single-line value";
}
});
function variableColonSpaceChecker(_ref) {
var locationChecker = _ref.locationChecker,
root = _ref.root,
result = _ref.result,
checkedRuleName = _ref.checkedRuleName;
root.walkDecls(function (decl) {
if (decl.prop === undefined || decl.prop[0] !== "$") {
return;
}
// Get the raw $var, and only that
var endOfPropIndex = (0, _utils.declarationValueIndex)(decl) + decl.raw("between").length - 1;
// `$var:`, `$var :`
var propPlusColon = decl.toString().slice(0, endOfPropIndex);
var _loop = function _loop(i) {
if (propPlusColon[i] !== ":") {
return "continue";
}
locationChecker({
source: propPlusColon,
index: i,
lineCheckStr: decl.value,
err: function err(m) {
_stylelint.utils.report({
message: m,
node: decl,
index: i,
result: result,
ruleName: checkedRuleName
});
}
});
return "break";
};
_loop2: for (var i = 0; i < propPlusColon.length; i++) {
var _ret = _loop(i);
switch (_ret) {
case "continue":
continue;
case "break":
break _loop2;}
}
});
}

View File

@@ -0,0 +1,43 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.messages = exports.ruleName = undefined;
exports.default = function (expectation) {
var checker = (0, _utils.whitespaceChecker)("space", expectation, messages);
return function (root, result) {
var validOptions = _stylelint.utils.validateOptions(result, ruleName, {
actual: expectation,
possible: ["always", "never"]
});
if (!validOptions) {
return;
}
(0, _dollarVariableColonSpaceAfter.variableColonSpaceChecker)({
root: root,
result: result,
locationChecker: checker.before,
checkedRuleName: ruleName
});
};
};
var _utils = require("../../utils");
var _stylelint = require("stylelint");
var _dollarVariableColonSpaceAfter = require("../dollar-variable-colon-space-after");
var ruleName = exports.ruleName = (0, _utils.namespace)("dollar-variable-colon-space-before");
var messages = exports.messages = _stylelint.utils.ruleMessages(ruleName, {
expectedBefore: function expectedBefore() {
return "Expected single space before \":\"";
},
rejectedBefore: function rejectedBefore() {
return "Unexpected whitespace before \":\"";
}
});

View File

@@ -0,0 +1,90 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.messages = exports.ruleName = undefined;
exports.default = function (expectation, options) {
return function (root, result) {
var validOptions = _stylelint.utils.validateOptions(result, ruleName, {
actual: expectation,
possible: ["always", "never"]
}, {
actual: options,
possible: {
except: ["first-nested", "after-comment", "after-dollar-variable"],
ignore: ["after-comment", "inside-single-line-block"]
},
optional: true
});
if (!validOptions) {
return;
}
root.walkDecls(function (decl) {
if (!isDollarVar(decl)) {
return;
}
// Always ignore the first $var in a stylesheet
if (decl === root.first) {
return;
}
// If ignoring vars after comments is set
if ((0, _utils.optionsHaveIgnored)(options, "after-comment") && decl.prev() && decl.prev().type === "comment") {
return;
}
// If ignoring single-line blocks
if ((0, _utils.optionsHaveIgnored)(options, "inside-single-line-block") && decl.parent.type !== "root" && (0, _utils.isSingleLineString)((0, _utils.blockString)(decl.parent))) {
return;
}
var expectHasEmptyLineBefore = expectation === "always";
// Reverse for a variable that is a first child of its parent
if ((0, _utils.optionsHaveException)(options, "first-nested") && decl === decl.parent.first) {
expectHasEmptyLineBefore = !expectHasEmptyLineBefore;
}
// Reverse if after a comment
if ((0, _utils.optionsHaveException)(options, "after-comment") && decl.prev() && decl.prev().type === "comment") {
expectHasEmptyLineBefore = !expectHasEmptyLineBefore;
}
// Reverse if after another $-variable
if ((0, _utils.optionsHaveException)(options, "after-dollar-variable") && decl.prev() && isDollarVar(decl.prev())) {
expectHasEmptyLineBefore = !expectHasEmptyLineBefore;
}
if (expectHasEmptyLineBefore === (0, _utils.hasEmptyLine)(decl.raws.before)) {
return;
}
_stylelint.utils.report({
message: expectHasEmptyLineBefore ? messages.expected : messages.rejected,
node: decl,
result: result,
ruleName: ruleName
});
});
};
};
var _utils = require("../../utils");
var _stylelint = require("stylelint");
var ruleName = exports.ruleName = (0, _utils.namespace)("dollar-variable-empty-line-before");
var messages = exports.messages = _stylelint.utils.ruleMessages(ruleName, {
expected: "Expected an empty line before $-variable",
rejected: "Unxpected empty line before $-variable"
});
function isDollarVar(node) {
return node.prop && node.prop[0] === "$";
}

View File

@@ -0,0 +1,146 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.messages = exports.ruleName = undefined;
exports.default = function (actual) {
return function (root, result) {
var validOptions = _stylelint.utils.validateOptions(result, ruleName, { actual: actual });
if (!validOptions) {
return;
}
var stringVars = [];
var vars = [];
function findVars(node) {
node.walkDecls(function (decl) {
var prop = decl.prop,
value = decl.value;
if (!isSassVar(prop) || (0, _lodash.includes)(vars, prop)) {
return;
}
if (isStringVal(value)) {
stringVars.push(prop);
}
vars.push(prop);
});
}
findVars(root);
root.walkRules(findVars);
if (!vars.length) {
return;
}
function shouldReport(node, value) {
if (isAtSupports(node) || isCustomIdentProp(node)) {
return (0, _lodash.includes)(stringVars, value);
}
if (isCustomIdentAtRule(node)) {
return (0, _lodash.includes)(vars, value);
}
return false;
}
function report(node, value) {
var name = node.name,
prop = node.prop,
type = node.type;
var nodeName = isAtRule(type) ? "@" + name : prop;
_stylelint.utils.report({
ruleName: ruleName,
result: result,
node: node,
message: messages.rejected(nodeName, value)
});
}
function exitEarly(node) {
return node.type !== "word" || !node.value;
}
function walkValues(node, value) {
(0, _postcssValueParser2.default)(value).walk(function (valNode) {
var value = valNode.value;
if (exitEarly(valNode) || !shouldReport(node, value)) {
return;
}
report(node, value);
});
}
root.walkDecls(toRegex(customIdentProps), function (decl) {
walkValues(decl, decl.value);
});
root.walkAtRules(toRegex(customIdentAtRules), function (atRule) {
walkValues(atRule, atRule.params);
});
};
};
var _lodash = require("lodash");
var _stylelint = require("stylelint");
var _utils = require("../../utils");
var _postcssValueParser = require("postcss-value-parser");
var _postcssValueParser2 = _interopRequireDefault(_postcssValueParser);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
var ruleName = exports.ruleName = (0, _utils.namespace)("dollar-variable-no-missing-interpolation");
var messages = exports.messages = _stylelint.utils.ruleMessages(ruleName, {
rejected: function rejected(n, v) {
return "Expected variable " + v + " to be interpolated when using it with " + n;
}
});
// https://developer.mozilla.org/en/docs/Web/CSS/custom-ident#Lists_of_excluded_values
var customIdentProps = ["animation", "animation-name", "counter-reset", "counter-increment", "list-style-type", "will-change"];
// https://developer.mozilla.org/en/docs/Web/CSS/At-rule
var customIdentAtRules = ["counter-style", "keyframes", "supports"];
function isAtRule(type) {
return type === "atrule";
}
function isCustomIdentAtRule(node) {
return isAtRule(node.type) && (0, _lodash.includes)(customIdentAtRules, node.name);
}
function isCustomIdentProp(node) {
return (0, _lodash.includes)(customIdentProps, node.prop);
}
function isAtSupports(node) {
return isAtRule(node.type) && node.name === "supports";
}
function isSassVar(value) {
return value[0] === "$";
}
function isStringVal(value) {
return (/^("|').*("|')$/.test(value)
);
}
function toRegex(arr) {
return new RegExp("(" + arr.join("|") + ")");
}

View File

@@ -0,0 +1,61 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.messages = exports.ruleName = undefined;
exports.default = function (pattern, options) {
return function (root, result) {
var validOptions = _stylelint.utils.validateOptions(result, ruleName, {
actual: pattern,
possible: [_lodash.isRegExp, _lodash.isString]
}, {
actual: options,
possible: {
ignore: ["local", "global"]
},
optional: true
});
if (!validOptions) {
return;
}
var regexpPattern = (0, _lodash.isString)(pattern) ? new RegExp(pattern) : pattern;
root.walkDecls(function (decl) {
var prop = decl.prop;
if (prop[0] !== "$") {
return;
}
// If local or global variables need to be ignored
if ((0, _utils.optionsHaveIgnored)(options, "global") && decl.parent.type === "root" || (0, _utils.optionsHaveIgnored)(options, "local") && decl.parent.type !== "root") {
return;
}
if (regexpPattern.test(prop.slice(1))) {
return;
}
_stylelint.utils.report({
message: messages.expected,
node: decl,
result: result,
ruleName: ruleName
});
});
};
};
var _lodash = require("lodash");
var _stylelint = require("stylelint");
var _utils = require("../../utils");
var ruleName = exports.ruleName = (0, _utils.namespace)("dollar-variable-pattern");
var messages = exports.messages = _stylelint.utils.ruleMessages(ruleName, {
expected: "Expected $ variable name to match specified pattern"
});

View File

@@ -0,0 +1,91 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.messages = exports.ruleName = undefined;
exports.default = function (expectation, options) {
return function (root, result) {
var validOptions = _stylelint.utils.validateOptions(result, ruleName, {
actual: expectation,
possible: ["always", "never"]
}, {
actual: options,
possible: {
except: ["first-nested"],
ignore: ["stylelint-commands", "between-comments"]
},
optional: true
});
if (!validOptions) {
return;
}
root.walkComments(function (comment) {
// Only process // comments
if (!comment.raws.inline && !comment.inline) {
return;
}
if ((0, _utils.isInlineComment)(comment)) {
return;
}
// Ignore the first node
if (comment === root.first) {
return;
}
// Optionally ignore stylelint commands
if (comment.text.indexOf(stylelintCommandPrefix) === 0 && (0, _utils.optionsHaveIgnored)(options, "stylelint-commands")) {
return;
}
// Optionally ignore newlines between comments
var prev = comment.prev();
if (prev && prev.type === "comment" && (0, _utils.optionsHaveIgnored)(options, "between-comments")) {
return;
}
var before = comment.raw("before");
var expectEmptyLineBefore = function () {
if ((0, _utils.optionsHaveException)(options, "first-nested") && comment.parent !== root && comment === comment.parent.first) {
return false;
}
return expectation === "always";
}();
var hasEmptyLineBefore = before.search(/\n\s*?\n/) !== -1;
// Return if the expectation is met
if (expectEmptyLineBefore === hasEmptyLineBefore) {
return;
}
var message = expectEmptyLineBefore ? messages.expected : messages.rejected;
_stylelint.utils.report({
message: message,
node: comment,
result: result,
ruleName: ruleName
});
});
};
};
var _utils = require("../../utils");
var _stylelint = require("stylelint");
var ruleName = exports.ruleName = (0, _utils.namespace)("double-slash-comment-empty-line-before");
var messages = exports.messages = _stylelint.utils.ruleMessages(ruleName, {
expected: "Expected empty line before comment",
rejected: "Unexpected empty line before comment"
});
var stylelintCommandPrefix = "stylelint-";

View File

@@ -0,0 +1,69 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.messages = exports.ruleName = undefined;
exports.default = function (expectation, options) {
return function (root, result) {
var validOptions = _stylelint.utils.validateOptions(result, ruleName, {
actual: expectation,
possible: ["always", "never"]
}, {
actual: options,
possible: {
ignore: ["stylelint-commands"]
},
optional: true
});
if (!validOptions) {
return;
}
var comments = (0, _utils.findCommentsInRaws)(root.source.input.css);
comments.forEach(function (comment) {
// Only process // comments
if (comment.type !== "double-slash") {
return;
}
// Optionally ignore stylelint commands
if (comment.text.indexOf(stylelintCommandPrefix) === 0 && (0, _utils.optionsHaveIgnored)(options, "stylelint-commands")) {
return;
}
var isInline = comment.inlineAfter || comment.inlineBefore;
var message = void 0;
if (isInline && expectation === "never") {
message = messages.rejected;
} else if (!isInline && expectation === "always") {
message = messages.expected;
} else {
return;
}
_stylelint.utils.report({
message: message,
node: root,
index: comment.source.start,
result: result,
ruleName: ruleName
});
});
};
};
var _utils = require("../../utils");
var _stylelint = require("stylelint");
var ruleName = exports.ruleName = (0, _utils.namespace)("double-slash-comment-inline");
var messages = exports.messages = _stylelint.utils.ruleMessages(ruleName, {
expected: "Expected //-comment to be inline comment",
rejected: "Unexpected inline //-comment"
});
var stylelintCommandPrefix = "stylelint-";

View File

@@ -0,0 +1,60 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.messages = exports.ruleName = undefined;
exports.default = function (expectation) {
return function (root, result) {
var validOptions = _stylelint.utils.validateOptions(result, ruleName, {
actual: expectation,
possible: ["always", "never"]
});
if (!validOptions) {
return;
}
var comments = (0, _utils.findCommentsInRaws)(root.source.input.css);
comments.forEach(function (comment) {
// Only process // comments
if (comment.type !== "double-slash") {
return;
}
// if it's `//` - no warning whatsoever; if `// ` - then trailing
// whitespace rule will govern this
if (comment.text === "") {
return;
}
var message = void 0;
if (expectation === "never" && comment.raws.left !== "") {
message = messages.rejected;
} else if (comment.raws.left === "" && expectation === "always") {
message = messages.expected;
} else {
return;
}
_stylelint.utils.report({
message: message,
node: root,
index: comment.source.start + comment.raws.startToken.length,
result: result,
ruleName: ruleName
});
});
};
};
var _utils = require("../../utils");
var _stylelint = require("stylelint");
var ruleName = exports.ruleName = (0, _utils.namespace)("double-slash-comment-whitespace-inside");
var messages = exports.messages = _stylelint.utils.ruleMessages(ruleName, {
expected: "Expected a space after //",
rejected: "Unexpected space after //"
});

170
node_modules/stylelint-scss/dist/rules/index.js generated vendored Normal file
View File

@@ -0,0 +1,170 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
var _atExtendNoMissingPlaceholder = require("./at-extend-no-missing-placeholder");
var _atExtendNoMissingPlaceholder2 = _interopRequireDefault(_atExtendNoMissingPlaceholder);
var _atElseClosingBraceNewlineAfter = require("./at-else-closing-brace-newline-after");
var _atElseClosingBraceNewlineAfter2 = _interopRequireDefault(_atElseClosingBraceNewlineAfter);
var _atElseClosingBraceSpaceAfter = require("./at-else-closing-brace-space-after");
var _atElseClosingBraceSpaceAfter2 = _interopRequireDefault(_atElseClosingBraceSpaceAfter);
var _atElseEmptyLineBefore = require("./at-else-empty-line-before");
var _atElseEmptyLineBefore2 = _interopRequireDefault(_atElseEmptyLineBefore);
var _atFunctionPattern = require("./at-function-pattern");
var _atFunctionPattern2 = _interopRequireDefault(_atFunctionPattern);
var _atIfClosingBraceNewlineAfter = require("./at-if-closing-brace-newline-after");
var _atIfClosingBraceNewlineAfter2 = _interopRequireDefault(_atIfClosingBraceNewlineAfter);
var _atIfClosingBraceSpaceAfter = require("./at-if-closing-brace-space-after");
var _atIfClosingBraceSpaceAfter2 = _interopRequireDefault(_atIfClosingBraceSpaceAfter);
var _atImportNoPartialExtension = require("./at-import-no-partial-extension");
var _atImportNoPartialExtension2 = _interopRequireDefault(_atImportNoPartialExtension);
var _atImportNoPartialLeadingUnderscore = require("./at-import-no-partial-leading-underscore");
var _atImportNoPartialLeadingUnderscore2 = _interopRequireDefault(_atImportNoPartialLeadingUnderscore);
var _atImportPartialExtensionBlacklist = require("./at-import-partial-extension-blacklist");
var _atImportPartialExtensionBlacklist2 = _interopRequireDefault(_atImportPartialExtensionBlacklist);
var _atImportPartialExtensionWhitelist = require("./at-import-partial-extension-whitelist");
var _atImportPartialExtensionWhitelist2 = _interopRequireDefault(_atImportPartialExtensionWhitelist);
var _atMixinArgumentlessCallParentheses = require("./at-mixin-argumentless-call-parentheses");
var _atMixinArgumentlessCallParentheses2 = _interopRequireDefault(_atMixinArgumentlessCallParentheses);
var _atMixinNoArgumentlessCallParentheses = require("./at-mixin-no-argumentless-call-parentheses");
var _atMixinNoArgumentlessCallParentheses2 = _interopRequireDefault(_atMixinNoArgumentlessCallParentheses);
var _atMixinPattern = require("./at-mixin-pattern");
var _atMixinPattern2 = _interopRequireDefault(_atMixinPattern);
var _declarationNestedProperties = require("./declaration-nested-properties");
var _declarationNestedProperties2 = _interopRequireDefault(_declarationNestedProperties);
var _declarationNestedPropertiesNoDividedGroups = require("./declaration-nested-properties-no-divided-groups");
var _declarationNestedPropertiesNoDividedGroups2 = _interopRequireDefault(_declarationNestedPropertiesNoDividedGroups);
var _dollarVariableColonNewlineAfter = require("./dollar-variable-colon-newline-after");
var _dollarVariableColonNewlineAfter2 = _interopRequireDefault(_dollarVariableColonNewlineAfter);
var _dollarVariableColonSpaceAfter = require("./dollar-variable-colon-space-after");
var _dollarVariableColonSpaceAfter2 = _interopRequireDefault(_dollarVariableColonSpaceAfter);
var _dollarVariableColonSpaceBefore = require("./dollar-variable-colon-space-before");
var _dollarVariableColonSpaceBefore2 = _interopRequireDefault(_dollarVariableColonSpaceBefore);
var _dollarVariableEmptyLineBefore = require("./dollar-variable-empty-line-before");
var _dollarVariableEmptyLineBefore2 = _interopRequireDefault(_dollarVariableEmptyLineBefore);
var _dollarVariableNoMissingInterpolation = require("./dollar-variable-no-missing-interpolation");
var _dollarVariableNoMissingInterpolation2 = _interopRequireDefault(_dollarVariableNoMissingInterpolation);
var _dollarVariablePattern = require("./dollar-variable-pattern");
var _dollarVariablePattern2 = _interopRequireDefault(_dollarVariablePattern);
var _doubleSlashCommentEmptyLineBefore = require("./double-slash-comment-empty-line-before");
var _doubleSlashCommentEmptyLineBefore2 = _interopRequireDefault(_doubleSlashCommentEmptyLineBefore);
var _doubleSlashCommentInline = require("./double-slash-comment-inline");
var _doubleSlashCommentInline2 = _interopRequireDefault(_doubleSlashCommentInline);
var _doubleSlashCommentWhitespaceInside = require("./double-slash-comment-whitespace-inside");
var _doubleSlashCommentWhitespaceInside2 = _interopRequireDefault(_doubleSlashCommentWhitespaceInside);
var _mediaFeatureValueDollarVariable = require("./media-feature-value-dollar-variable");
var _mediaFeatureValueDollarVariable2 = _interopRequireDefault(_mediaFeatureValueDollarVariable);
var _operatorNoNewlineAfter = require("./operator-no-newline-after");
var _operatorNoNewlineAfter2 = _interopRequireDefault(_operatorNoNewlineAfter);
var _operatorNoNewlineBefore = require("./operator-no-newline-before");
var _operatorNoNewlineBefore2 = _interopRequireDefault(_operatorNoNewlineBefore);
var _operatorNoUnspaced = require("./operator-no-unspaced");
var _operatorNoUnspaced2 = _interopRequireDefault(_operatorNoUnspaced);
var _partialNoImport = require("./partial-no-import");
var _partialNoImport2 = _interopRequireDefault(_partialNoImport);
var _percentPlaceholderPattern = require("./percent-placeholder-pattern");
var _percentPlaceholderPattern2 = _interopRequireDefault(_percentPlaceholderPattern);
var _selectorNoRedundantNestingSelector = require("./selector-no-redundant-nesting-selector");
var _selectorNoRedundantNestingSelector2 = _interopRequireDefault(_selectorNoRedundantNestingSelector);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
exports.default = {
"at-extend-no-missing-placeholder": _atExtendNoMissingPlaceholder2.default,
"at-else-closing-brace-newline-after": _atElseClosingBraceNewlineAfter2.default,
"at-else-closing-brace-space-after": _atElseClosingBraceSpaceAfter2.default,
"at-else-empty-line-before": _atElseEmptyLineBefore2.default,
"at-function-pattern": _atFunctionPattern2.default,
"at-if-closing-brace-newline-after": _atIfClosingBraceNewlineAfter2.default,
"at-if-closing-brace-space-after": _atIfClosingBraceSpaceAfter2.default,
"at-import-no-partial-extension": _atImportNoPartialExtension2.default,
"at-import-no-partial-leading-underscore": _atImportNoPartialLeadingUnderscore2.default,
"at-import-partial-extension-blacklist": _atImportPartialExtensionBlacklist2.default,
"at-import-partial-extension-whitelist": _atImportPartialExtensionWhitelist2.default,
"at-mixin-argumentless-call-parentheses": _atMixinArgumentlessCallParentheses2.default,
"at-mixin-no-argumentless-call-parentheses": _atMixinNoArgumentlessCallParentheses2.default,
"at-mixin-pattern": _atMixinPattern2.default,
"declaration-nested-properties": _declarationNestedProperties2.default,
"declaration-nested-properties-no-divided-groups": _declarationNestedPropertiesNoDividedGroups2.default,
"dollar-variable-colon-newline-after": _dollarVariableColonNewlineAfter2.default,
"dollar-variable-colon-space-after": _dollarVariableColonSpaceAfter2.default,
"dollar-variable-colon-space-before": _dollarVariableColonSpaceBefore2.default,
"dollar-variable-empty-line-before": _dollarVariableEmptyLineBefore2.default,
"dollar-variable-no-missing-interpolation": _dollarVariableNoMissingInterpolation2.default,
"dollar-variable-pattern": _dollarVariablePattern2.default,
"double-slash-comment-empty-line-before": _doubleSlashCommentEmptyLineBefore2.default,
"double-slash-comment-inline": _doubleSlashCommentInline2.default,
"double-slash-comment-whitespace-inside": _doubleSlashCommentWhitespaceInside2.default,
"media-feature-value-dollar-variable": _mediaFeatureValueDollarVariable2.default,
"operator-no-newline-after": _operatorNoNewlineAfter2.default,
"operator-no-newline-before": _operatorNoNewlineBefore2.default,
"operator-no-unspaced": _operatorNoUnspaced2.default,
"percent-placeholder-pattern": _percentPlaceholderPattern2.default,
"partial-no-import": _partialNoImport2.default,
"selector-no-redundant-nesting-selector": _selectorNoRedundantNestingSelector2.default
};

View File

@@ -0,0 +1,71 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.messages = exports.ruleName = undefined;
exports.default = function (expectation) {
return function (root, result) {
var validOptions = _stylelint.utils.validateOptions(result, ruleName, {
actual: expectation,
possible: ["always", "never"]
});
if (!validOptions) {
return;
}
var valueRegex = /:(?:\s*?)(\S.+?)(:?\s*?)\)/;
// In `(max-width: 10px )` find `: 10px )`.
// Got to go with that (the global search doesn't remember parens' insides)
// and parse it again afterwards to remove trailing junk
var valueRegexGlobal = new RegExp(valueRegex.source, "g");
// `$var-name_sth`
var variableRegex = /^\$[A-Za-z_0-9-]+$/;
// `#{$var-name_sth}`
var interpolationVarRegex = /^#\{\s*?\$[A-Za-z_0-9]+\s*?\}$/;
root.walkAtRules("media", function (atRule) {
var found = atRule.params.match(valueRegexGlobal);
// If there are no values
if (!found || !found.length) {
return;
}
found.forEach(function (found) {
// ... parse `: 10px )` to `10px`
var valueParsed = found.match(valueRegex)[1];
// Just a shorthand to stylelint.utils.report()
function complain(message) {
_stylelint.utils.report({
ruleName: ruleName,
result: result,
node: atRule,
word: valueParsed,
message: message
});
}
// A value should be a single variable
// or it should be a single variable inside Sass interpolation
if (expectation === "always" && !(valueParsed.search(variableRegex) !== -1 || valueParsed.search(interpolationVarRegex) !== -1)) {
complain(messages.expected);
} else if (expectation === "never" && valueParsed.indexOf("$") !== -1) {
// "Never" means no variables at all (functions allowed)
complain(messages.rejected);
}
});
});
};
};
var _stylelint = require("stylelint");
var _utils = require("../../utils");
var ruleName = exports.ruleName = (0, _utils.namespace)("media-feature-value-dollar-variable");
var messages = exports.messages = _stylelint.utils.ruleMessages(ruleName, {
rejected: "Unexpected dollar-variable as a media feature value",
expected: "Expected a dollar-variable (e.g. $var) to be used as a media feature value"
});

View File

@@ -0,0 +1,71 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.messages = exports.ruleName = undefined;
exports.default = function (expectation) {
return function (root, result) {
var validOptions = _stylelint.utils.validateOptions(result, ruleName, {
actual: expectation
});
if (!validOptions) {
return;
}
(0, _operatorNoUnspaced.calculationOperatorSpaceChecker)({
root: root,
result: result,
checker: checkNewlineBefore
});
};
};
var _stylelint = require("stylelint");
var _utils = require("../../utils");
var _operatorNoUnspaced = require("../operator-no-unspaced");
var ruleName = exports.ruleName = (0, _utils.namespace)("operator-no-newline-after");
var messages = exports.messages = _stylelint.utils.ruleMessages(ruleName, {
rejected: function rejected(operator) {
return "Unexpected newline after \"" + operator + "\"";
}
});
/**
* The checker function: whether there is a newline before THAT operator.
*/
function checkNewlineBefore(_ref) {
var string = _ref.string,
globalIndex = _ref.globalIndex,
startIndex = _ref.startIndex,
endIndex = _ref.endIndex,
node = _ref.node,
result = _ref.result;
var symbol = string.substring(startIndex, endIndex + 1);
var newLineBefore = false;
var index = endIndex + 1;
while (index && (0, _utils.isWhitespace)(string[index])) {
if (string[index] === "\n") {
newLineBefore = true;
break;
}
index++;
}
if (newLineBefore) {
_stylelint.utils.report({
ruleName: ruleName,
result: result,
node: node,
message: messages.rejected(symbol),
index: endIndex + globalIndex
});
}
}

View File

@@ -0,0 +1,71 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.messages = exports.ruleName = undefined;
exports.default = function (expectation) {
return function (root, result) {
var validOptions = _stylelint.utils.validateOptions(result, ruleName, {
actual: expectation
});
if (!validOptions) {
return;
}
(0, _operatorNoUnspaced.calculationOperatorSpaceChecker)({
root: root,
result: result,
checker: checkNewlineBefore
});
};
};
var _stylelint = require("stylelint");
var _utils = require("../../utils");
var _operatorNoUnspaced = require("../operator-no-unspaced");
var ruleName = exports.ruleName = (0, _utils.namespace)("operator-no-newline-before");
var messages = exports.messages = _stylelint.utils.ruleMessages(ruleName, {
rejected: function rejected(operator) {
return "Unexpected newline before \"" + operator + "\"";
}
});
/**
* The checker function: whether there is a newline before THAT operator.
*/
function checkNewlineBefore(_ref) {
var string = _ref.string,
globalIndex = _ref.globalIndex,
startIndex = _ref.startIndex,
endIndex = _ref.endIndex,
node = _ref.node,
result = _ref.result;
var symbol = string.substring(startIndex, endIndex + 1);
var newLineBefore = false;
var index = startIndex - 1;
while (index && (0, _utils.isWhitespace)(string[index])) {
if (string[index] === "\n") {
newLineBefore = true;
break;
}
index--;
}
if (newLineBefore) {
_stylelint.utils.report({
ruleName: ruleName,
result: result,
node: node,
message: messages.rejected(symbol),
index: endIndex + globalIndex
});
}
}

View File

@@ -0,0 +1,243 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.messages = exports.ruleName = undefined;
exports.default = function (expectation) {
return function (root, result) {
var validOptions = _stylelint.utils.validateOptions(result, ruleName, {
actual: expectation
});
if (!validOptions) {
return;
}
calculationOperatorSpaceChecker({
root: root,
result: result,
checker: checkSpaces
});
};
};
exports.calculationOperatorSpaceChecker = calculationOperatorSpaceChecker;
var _stylelint = require("stylelint");
var _utils = require("../../utils");
var _postcssMediaQueryParser = require("postcss-media-query-parser");
var _postcssMediaQueryParser2 = _interopRequireDefault(_postcssMediaQueryParser);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
var ruleName = exports.ruleName = (0, _utils.namespace)("operator-no-unspaced");
var messages = exports.messages = _stylelint.utils.ruleMessages(ruleName, {
expectedAfter: function expectedAfter(operator) {
return "Expected single space after \"" + operator + "\"";
},
expectedBefore: function expectedBefore(operator) {
return "Expected single space before \"" + operator + "\"";
}
});
/**
* The actual check for are there (un)necessary whitespaces
*/
function checkSpaces(_ref) {
var string = _ref.string,
globalIndex = _ref.globalIndex,
startIndex = _ref.startIndex,
endIndex = _ref.endIndex,
node = _ref.node,
result = _ref.result;
var symbol = string.substring(startIndex, endIndex + 1);
var beforeOk = string[startIndex - 1] === " " && !(0, _utils.isWhitespace)(string[startIndex - 2]) || newlineBefore(string, startIndex - 1);
if (!beforeOk) {
_stylelint.utils.report({
ruleName: ruleName,
result: result,
node: node,
message: messages.expectedBefore(symbol),
index: startIndex + globalIndex
});
}
var afterOk = string[endIndex + 1] === " " && !(0, _utils.isWhitespace)(string[endIndex + 2]) || string[endIndex + 1] === "\n" || string.substr(endIndex + 1, 2) === "\r\n";
if (!afterOk) {
_stylelint.utils.report({
ruleName: ruleName,
result: result,
node: node,
message: messages.expectedAfter(symbol),
index: endIndex + globalIndex
});
}
}
function newlineBefore(str, startIndex) {
var index = startIndex;
while (index && (0, _utils.isWhitespace)(str[index])) {
if (str[index] === "\n") return true;
index--;
}
return false;
}
/**
* The core rule logic function. This one can be imported by some other rules
* that work with Sass operators
*
* @param {Object} args -- Named arguments object
* @param {PostCSS Root} args.root
* @param {PostCSS Result} args.result
* @param {function} args.checker -- the function that is run against all the
* operators found in the input. Takes these arguments:
* {Object} cbArgs -- Named arguments object
* {string} cbArgs.string -- the input string (suspected operation)
* {number} cbArgs.globalIndex -- the string's index in a global input
* {number} cbArgs.startIndex -- the start index of a sybmol to inspect
* {number} cbArgs.endIndex -- the end index of a sybmol to inspect
* (two indexes needed to allow for `==`, `!=`, etc.)
* {PostCSS Node} cbArgs.node -- for stylelint.utils.report
* {PostCSS Result} cbArgs.result -- for stylelint.utils.report
*/
function calculationOperatorSpaceChecker(_ref2) {
var root = _ref2.root,
result = _ref2.result,
checker = _ref2.checker;
/**
* Takes a string, finds all occurencies of Sass interpolaion in it, then
* finds all operators inside that interpolation
*
* @return {array} An array of ojbects { string, operators } - effectively,
* a list of operators for each Sass interpolation occurence
*/
function findInterpolation(string, startIndex) {
var interpolationRegex = /#{(.*?)}/g;
var results = [];
// Searching for interpolation
var match = interpolationRegex.exec(string);
startIndex = !isNaN(startIndex) ? Number(startIndex) : 0;
while (match !== null) {
results.push({
source: match[0],
operators: (0, _utils.findOperators)({
string: match[0],
globalIndex: match.index + startIndex
})
});
match = interpolationRegex.exec(string);
}
return results;
}
root.walk(function (item) {
var results = [];
// Check a value (`10px` in `width: 10px;`)
if (item.value !== undefined) {
results.push({
source: item.value,
operators: (0, _utils.findOperators)({
string: item.value,
globalIndex: (0, _utils.declarationValueIndex)(item),
// For Sass variable values some special rules apply
isAfterColon: item.prop[0] === "$"
})
});
}
// Property name
if (item.prop !== undefined) {
results = results.concat(findInterpolation(item.prop));
}
// Selector
if (item.selector !== undefined) {
results = results.concat(findInterpolation(item.selector));
}
if (item.type === "atrule") {
// Media queries
if (item.name === "media" || item.name === "import") {
(0, _postcssMediaQueryParser2.default)(item.params).walk(function (node) {
var type = node.type;
if (["keyword", "media-type", "media-feature"].indexOf(type) !== -1) {
results = results.concat(findInterpolation(node.value, (0, _utils.atRuleParamIndex)(item) + node.sourceIndex));
} else if (["value", "url"].indexOf(type) !== -1) {
results.push({
source: node.value,
operators: (0, _utils.findOperators)({
string: node.value,
globalIndex: (0, _utils.atRuleParamIndex)(item) + node.sourceIndex,
isAfterColon: true
})
});
}
});
} else {
// Function and mixin definitions and other rules
results.push({
source: item.params,
operators: (0, _utils.findOperators)({
string: item.params,
globalIndex: (0, _utils.atRuleParamIndex)(item),
isAfterColon: true
})
});
}
}
// All the strings have been parsed, now run whitespace checking
results.forEach(function (el) {
// Only if there are operators within a string
if (el.operators && el.operators.length > 0) {
el.operators.forEach(function (operator) {
checker({
string: el.source,
globalIndex: operator.globalIndex,
startIndex: operator.startIndex,
endIndex: operator.endIndex,
node: item,
result: result
});
});
}
});
});
// Checking interpolation inside comments
// We have to give up on PostCSS here because it skips some inline comments
(0, _utils.findCommentsInRaws)(root.source.input.css).forEach(function (comment) {
var startIndex = comment.source.start + comment.raws.startToken.length + comment.raws.left.length;
if (comment.type !== "css") {
return;
}
findInterpolation(comment.text).forEach(function (el) {
// Only if there are operators within a string
if (el.operators && el.operators.length > 0) {
el.operators.forEach(function (operator) {
checker({
string: el.source,
globalIndex: operator.globalIndex + startIndex,
startIndex: operator.startIndex,
endIndex: operator.endIndex,
node: root,
result: result
});
});
}
});
});
}

View File

@@ -0,0 +1,75 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.messages = exports.ruleName = undefined;
exports.default = function (on) {
return function (root, result) {
var validOptions = _stylelint.utils.validateOptions(result, ruleName, {
actual: on
});
if (!validOptions) {
return;
}
if (root.source.input.file === undefined || !root.source.input.file) {
result.warn("The 'partial-no-import' rule won't work if linting in a code string without an actual file.");
return;
}
var fileName = _path2.default.basename(root.source.input.file);
var extName = _path2.default.extname(root.source.input.file);
function checkImportForCSS(path, decl) {
// Stripping trailing quotes and whitespaces, if any
var pathStripped = path.replace(/^\s*?("|')\s*/, "").replace(/\s*("|')\s*?$/, "");
// Skipping importing CSS: url(), ".css", URI with a protocol, media
if (pathStripped.slice(0, 4) === "url(" || pathStripped.slice(-4) === ".css" || pathStripped.search("//") !== -1 || pathStripped.search(/(?:\s|[,)"'])\w+$/) !== -1) {
return;
}
_stylelint.utils.report({
message: messages.expected,
node: decl,
result: result,
ruleName: ruleName
});
}
// Usual CSS file
if (extName === ".css") {
return;
}
// Not a partial
if (fileName[0] !== "_") {
return;
}
root.walkAtRules("import", function (mixinCall) {
// Check if @import is treated as CSS import; report only if not
// Processing comma-separated lists of import paths
mixinCall.params.split(",").forEach(function (path) {
checkImportForCSS(path, mixinCall);
});
});
};
};
var _stylelint = require("stylelint");
var _utils = require("../../utils");
var _path = require("path");
var _path2 = _interopRequireDefault(_path);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
var ruleName = exports.ruleName = (0, _utils.namespace)("partial-no-import");
var messages = exports.messages = _stylelint.utils.ruleMessages(ruleName, {
expected: "Unexpected @import in a partial"
});

View File

@@ -0,0 +1,96 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.messages = exports.ruleName = undefined;
exports.default = function (pattern) {
return function (root, result) {
var validOptions = _stylelint.utils.validateOptions(result, ruleName, {
actual: pattern,
possible: [_lodash.isRegExp, _lodash.isString]
});
if (!validOptions) {
return;
}
var placeholderPattern = (0, _lodash.isString)(pattern) ? new RegExp(pattern) : pattern;
// Checking placeholder definitions (looking among regular rules)
root.walkRules(function (rule) {
var selector = rule.selector;
// Just a shorthand for calling `parseSelector`
function parse(selector) {
(0, _utils.parseSelector)(selector, result, rule, function (s) {
return checkSelector(s, rule);
});
}
// If it's a custom prop or a less mixin
if (!(0, _utils.isStandardRule)(rule)) {
return;
}
// If the selector has interpolation
if (!(0, _utils.isStandardSelector)(selector)) {
return;
}
// Nested selectors are processed in steps, as nesting levels are resolved.
// Here we skip processing intermediate parts of selectors (to process only fully resolved selectors)
// if (rule.nodes.some(node => node.type === "rule" || node.type === "atrule")) { return }
// Only resolve selectors that have an interpolating "&"
if ((0, _utils.hasInterpolatingAmpersand)(selector)) {
(0, _postcssResolveNestedSelector2.default)(selector, rule).forEach(parse);
} else {
parse(selector);
}
});
function checkSelector(fullSelector, rule) {
// postcss-selector-parser gives %placeholders' nodes a "tag" type
fullSelector.walkTags(function (compoundSelector) {
var value = compoundSelector.value,
sourceIndex = compoundSelector.sourceIndex;
if (value[0] !== "%") {
return;
}
var placeholder = value.slice(1);
if (placeholderPattern.test(placeholder)) {
return;
}
_stylelint.utils.report({
result: result,
ruleName: ruleName,
message: messages.expected(placeholder),
node: rule,
index: sourceIndex
});
});
}
};
};
var _lodash = require("lodash");
var _postcssResolveNestedSelector = require("postcss-resolve-nested-selector");
var _postcssResolveNestedSelector2 = _interopRequireDefault(_postcssResolveNestedSelector);
var _stylelint = require("stylelint");
var _utils = require("../../utils");
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
var ruleName = exports.ruleName = (0, _utils.namespace)("percent-placeholder-pattern");
var messages = exports.messages = _stylelint.utils.ruleMessages(ruleName, {
expected: function expected(placeholder) {
return "Expected %-placeholder \"%" + placeholder + "\" to match specified pattern";
}
});

View File

@@ -0,0 +1,41 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.messages = exports.ruleName = undefined;
exports.default = function (actual) {
return function (root, result) {
var validOptions = _stylelint.utils.validateOptions(result, ruleName, { actual: actual });
if (!validOptions) {
return;
}
root.walkRules(/&/, function (rule) {
var selector = rule.selector;
// "Ampersand followed by a combinator followed by non-combinator non-ampersand and not the selector end"
var regex = /^&\s*[>+~ ]\s*[^>+~ {&]+/;
if (selector === "&" || regex.test(selector)) {
_stylelint.utils.report({
ruleName: ruleName,
result: result,
node: rule,
message: messages.rejected
});
}
});
};
};
var _stylelint = require("stylelint");
var _utils = require("../../utils");
var ruleName = exports.ruleName = (0, _utils.namespace)("selector-no-redundant-nesting-selector");
var messages = exports.messages = _stylelint.utils.ruleMessages(ruleName, {
rejected: "Unnecessary nesting selector (&)"
});

View File

@@ -0,0 +1,14 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = function (atRule) {
// Initial 1 is for the `@`
var index = 1 + atRule.name.length;
if (atRule.raw("afterName")) {
index += atRule.raw("afterName").length;
}
return index;
};

View File

@@ -0,0 +1,32 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = function (statement) {
var _ref = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {},
noRawBefore = _ref.noRawBefore;
var result = "";
if (statement.type !== "rule" && statement.type !== "atrule") {
return result;
}
if (!noRawBefore) {
result += statement.raws.before;
}
if (statement.type === "rule") {
result += statement.selector;
} else {
result += "@" + statement.name + statement.raws.afterName + statement.params;
}
var between = statement.raws.between;
if (between !== undefined) {
result += between;
}
return result;
};

26
node_modules/stylelint-scss/dist/utils/blockString.js generated vendored Normal file
View File

@@ -0,0 +1,26 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = function (statement) {
if (!(0, _hasBlock2.default)(statement)) {
return;
}
return (0, _rawNodeString2.default)(statement).slice((0, _beforeBlockString2.default)(statement).length);
};
var _beforeBlockString = require("./beforeBlockString");
var _beforeBlockString2 = _interopRequireDefault(_beforeBlockString);
var _hasBlock = require("./hasBlock");
var _hasBlock2 = _interopRequireDefault(_hasBlock);
var _rawNodeString = require("./rawNodeString");
var _rawNodeString2 = _interopRequireDefault(_rawNodeString);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }

View File

@@ -0,0 +1,11 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = function (text) {
var err = new Error(text);
err.code = 78;
return err;
};

View File

@@ -0,0 +1,11 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = function (decl) {
var beforeColon = decl.toString().indexOf(":");
var afterColon = decl.raw("between").length - decl.raw("between").indexOf(":");
return beforeColon + afterColon;
};

View File

@@ -0,0 +1,218 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = findCommentsInRaws;
var _lodash = require("lodash");
var _lodash2 = _interopRequireDefault(_lodash);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
/**
* Finds comments, both CSS comments and double slash ones, in a CSS string
* This helper exists because PostCSS drops some inline comments (those
* between seelctors, property values, etc.)
* https://github.com/postcss/postcss/issues/845#issuecomment-232306259
*
* @param [string] rawString -- the source raw CSS string
* @return [array] array of objects with these props:
* <20> type -- "css" or "double-slash"
* <20> source: { start, end }
* IMPORTANT: the function itself considers \r as a character, and counts
* it for `start` and `end`. But if their values are passed to PostCSS's
* result.warn(), than "\r\n" is consideren ONE CHAR (newline)!
* <20> raws
* raws.startToken -- `/*`, `/**`, `/**!`, etc.
* raws.left -- whitespace after the comment opening marker
* raws.text -- the full comment, including markers (//, /*)
* raws.right -- whitespace before the comment closing marker
* raws.endToken -- `*\/`, `**\/` for CSS comments
* <20> text -- the comment text only, excluding //, /*, trailing whitespaces
* <20> inlineAfter -- true, if there is something before the comment on
* the same line
* <20> inlineBefore -- true, if there is something after the comment on
* the same line
*/
function findCommentsInRaws(rawString) {
var result = [];
var comment = {};
// Keeps track of which structure the parser is inside (string, comment,
// url function, parens). E.g., /* comment */ inside a string doesn't
// constitute a comment, so as url(//path)
var modesEntered = [{
mode: "normal",
character: null
}];
var commentStart = null;
// postcss-scss transforms //-comments into CSS comments, like so:
// `// comment` -> `/* comment*/`. So to have a correct intex we need to
// keep track on the added `*/` sequences
var offset = 0;
for (var i = 0; i < rawString.length; i++) {
var character = rawString[i];
var prevChar = i > 0 ? rawString[i - 1] : null;
var nextChar = i + 1 < rawString.length ? rawString[i + 1] : null;
var lastModeIndex = modesEntered.length - 1;
var mode = modesEntered[lastModeIndex].mode;
switch (character) {
// If entering/exiting a string
case "\"":
case "'":
{
if (mode === "comment") {
break;
}
if (mode === "string" && modesEntered[lastModeIndex].character === character && prevChar !== "\\") {
// Exiting a string
modesEntered.pop();
} else {
// Entering a string
modesEntered.push({
mode: "string",
character: character
});
}
break;
}
// Entering url, other function or parens (only url matters)
case "(":
{
if (mode === "comment" || mode === "string") {
break;
}
var functionNameRegSearch = /(?:^|(?:\n)|(?:\r)|(?:\s-)|[:\s,.(){}*+/%])([a-zA-Z0-9_-]*)$/.exec(rawString.substring(0, i));
// A `\S(` can be in, say, `@media(`
if (!functionNameRegSearch) {
modesEntered.push({
mode: "parens",
character: "("
});
break;
}
var functionName = functionNameRegSearch[1];
modesEntered.push({
mode: functionName === "url" ? "url" : "parens",
character: "("
});
break;
}
// Exiting url, other function or parens
case ")":
{
if (mode === "comment" || mode === "string") {
break;
}
modesEntered.pop();
break;
}
// checking for comment
case "/":
{
// Break if the / is inside a comment because we leap over the second
// slash in // and in */, so the / is not from a marker. Also break
// if inside a string
if (mode === "comment" || mode === "string") {
break;
}
if (nextChar === "*") {
modesEntered.push({
mode: "comment",
character: "/*"
});
comment = {
type: "css",
source: { start: i + offset },
// If i is 0 then the file/the line starts with this comment
inlineAfter: i > 0 && rawString.substring(0, i).search(/\n\s*$/) === -1
};
commentStart = i;
// Skip the next iteration as the * is already checked
i++;
} else if (nextChar === "/") {
// `url(//path/to/file)` has no comment
if (mode === "url") {
break;
}
modesEntered.push({
mode: "comment",
character: "//"
});
comment = {
type: "double-slash",
source: { start: i + offset },
// If i is 0 then the file/the line starts with this comment
inlineAfter: i > 0 && rawString.substring(0, i).search(/\n\s*$/) === -1
};
commentStart = i;
// Skip the next iteration as the second slash in // is already checked
i++;
}
break;
}
// Might be a closing `*/`
case "*":
{
if (mode === "comment" && modesEntered[lastModeIndex].character === "/*" && nextChar === "/") {
comment.source.end = i + 1 + offset;
var commentRaw = rawString.substring(commentStart, i + 2);
var matches = /^(\/\*+[!#]{0,1})(\s*)([\s\S]*?)(\s*?)(\*+\/)$/.exec(commentRaw);
modesEntered.pop();
comment.raws = {
startToken: matches[1],
left: matches[2],
text: commentRaw,
right: matches[4],
endToken: matches[5]
};
comment.text = matches[3];
comment.inlineBefore = rawString.substring(i + 2).search(/^\s*?\S+\s*?\n/) !== -1;
result.push(_lodash2.default.assign({}, comment));
comment = {};
// Skip the next loop as the / in */ is already checked
i++;
}
break;
}
default:
{
var isNewline = character === "\r" && rawString[i + 1] === "\n" || character === "\n" && rawString[i - 1] !== "\r";
// //-comments end before newline and if the code string ends
if (isNewline || i === rawString.length - 1) {
if (mode === "comment" && modesEntered[lastModeIndex].character === "//") {
comment.source.end = (isNewline ? i - 1 : i) + offset;
var _commentRaw = rawString.substring(commentStart, isNewline ? i : i + 1);
var _matches = /^(\/+)(\s*)(.*?)(\s*?)$/.exec(_commentRaw);
modesEntered.pop();
comment.raws = {
startToken: _matches[1],
left: _matches[2],
text: _commentRaw,
right: _matches[4]
};
comment.text = _matches[3];
comment.inlineBefore = false;
result.push(_lodash2.default.assign({}, comment));
comment = {};
// Compensate for the `*/` added by postcss-scss
offset += 2;
}
}
break;
}
}
}
return result;
}

9
node_modules/stylelint-scss/dist/utils/hasBlock.js generated vendored Normal file
View File

@@ -0,0 +1,9 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = function (statement) {
return statement.nodes !== undefined;
};

View File

@@ -0,0 +1,9 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = function (string) {
return string && (string.indexOf("\n\n") !== -1 || string.indexOf("\n\r\n") !== -1);
};

View File

@@ -0,0 +1,41 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = function (selector) {
for (var i = 0; i < selector.length; i++) {
if (selector[i] !== "&") {
continue;
}
if (!_lodash2.default.isUndefined(selector[i - 1]) && !isCombinator(selector[i - 1])) {
return true;
}
if (!_lodash2.default.isUndefined(selector[i + 1]) && !isCombinator(selector[i + 1])) {
return true;
}
}
return false;
};
var _lodash = require("lodash");
var _lodash2 = _interopRequireDefault(_lodash);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function isCombinator(x) {
return (/[\s+>~]/.test(x)
);
}
/**
* Check whether a selector has an interpolating ampersand
* An "interpolating ampersand" is an "&" used to interpolate within another
* simple selector (e.g. `&-modifier`), rather than an "&" that stands
* on its own as a simple selector (e.g. `& .child`)
*
* @param {string} selector
* @return {boolean} If `true`, the selector has an interpolating ampersand
*/

205
node_modules/stylelint-scss/dist/utils/index.js generated vendored Normal file
View File

@@ -0,0 +1,205 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
var _atRuleParamIndex = require("./atRuleParamIndex");
Object.defineProperty(exports, "atRuleParamIndex", {
enumerable: true,
get: function get() {
return _interopRequireDefault(_atRuleParamIndex).default;
}
});
var _beforeBlockString = require("./beforeBlockString");
Object.defineProperty(exports, "beforeBlockString", {
enumerable: true,
get: function get() {
return _interopRequireDefault(_beforeBlockString).default;
}
});
var _blockString = require("./blockString");
Object.defineProperty(exports, "blockString", {
enumerable: true,
get: function get() {
return _interopRequireDefault(_blockString).default;
}
});
var _declarationValueIndex = require("./declarationValueIndex");
Object.defineProperty(exports, "declarationValueIndex", {
enumerable: true,
get: function get() {
return _interopRequireDefault(_declarationValueIndex).default;
}
});
var _findCommentsInRaws = require("./findCommentsInRaws");
Object.defineProperty(exports, "findCommentsInRaws", {
enumerable: true,
get: function get() {
return _interopRequireDefault(_findCommentsInRaws).default;
}
});
var _hasInterpolatingAmpersand = require("./hasInterpolatingAmpersand");
Object.defineProperty(exports, "hasInterpolatingAmpersand", {
enumerable: true,
get: function get() {
return _interopRequireDefault(_hasInterpolatingAmpersand).default;
}
});
var _hasBlock = require("./hasBlock");
Object.defineProperty(exports, "hasBlock", {
enumerable: true,
get: function get() {
return _interopRequireDefault(_hasBlock).default;
}
});
var _hasEmptyLine = require("./hasEmptyLine");
Object.defineProperty(exports, "hasEmptyLine", {
enumerable: true,
get: function get() {
return _interopRequireDefault(_hasEmptyLine).default;
}
});
var _isInlineComment = require("./isInlineComment");
Object.defineProperty(exports, "isInlineComment", {
enumerable: true,
get: function get() {
return _interopRequireDefault(_isInlineComment).default;
}
});
var _isSingleLineString = require("./isSingleLineString");
Object.defineProperty(exports, "isSingleLineString", {
enumerable: true,
get: function get() {
return _interopRequireDefault(_isSingleLineString).default;
}
});
var _isStandardRule = require("./isStandardRule");
Object.defineProperty(exports, "isStandardRule", {
enumerable: true,
get: function get() {
return _interopRequireDefault(_isStandardRule).default;
}
});
var _isStandardSelector = require("./isStandardSelector");
Object.defineProperty(exports, "isStandardSelector", {
enumerable: true,
get: function get() {
return _interopRequireDefault(_isStandardSelector).default;
}
});
var _isStandardSyntaxProperty = require("./isStandardSyntaxProperty");
Object.defineProperty(exports, "isStandardSyntaxProperty", {
enumerable: true,
get: function get() {
return _interopRequireDefault(_isStandardSyntaxProperty).default;
}
});
var _isWhitespace = require("./isWhitespace");
Object.defineProperty(exports, "isWhitespace", {
enumerable: true,
get: function get() {
return _interopRequireDefault(_isWhitespace).default;
}
});
var _namespace = require("./namespace");
Object.defineProperty(exports, "namespace", {
enumerable: true,
get: function get() {
return _interopRequireDefault(_namespace).default;
}
});
var _optionsHaveException = require("./optionsHaveException");
Object.defineProperty(exports, "optionsHaveException", {
enumerable: true,
get: function get() {
return _interopRequireDefault(_optionsHaveException).default;
}
});
var _optionsHaveIgnored = require("./optionsHaveIgnored");
Object.defineProperty(exports, "optionsHaveIgnored", {
enumerable: true,
get: function get() {
return _interopRequireDefault(_optionsHaveIgnored).default;
}
});
var _parseNestedPropRoot = require("./parseNestedPropRoot");
Object.defineProperty(exports, "parseNestedPropRoot", {
enumerable: true,
get: function get() {
return _interopRequireDefault(_parseNestedPropRoot).default;
}
});
var _parseSelector = require("./parseSelector");
Object.defineProperty(exports, "parseSelector", {
enumerable: true,
get: function get() {
return _interopRequireDefault(_parseSelector).default;
}
});
var _sassValueParser = require("./sassValueParser");
Object.defineProperty(exports, "findOperators", {
enumerable: true,
get: function get() {
return _interopRequireDefault(_sassValueParser).default;
}
});
var _rawNodeString = require("./rawNodeString");
Object.defineProperty(exports, "rawNodeString", {
enumerable: true,
get: function get() {
return _interopRequireDefault(_rawNodeString).default;
}
});
var _whitespaceChecker = require("./whitespaceChecker");
Object.defineProperty(exports, "whitespaceChecker", {
enumerable: true,
get: function get() {
return _interopRequireDefault(_whitespaceChecker).default;
}
});
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }

View File

@@ -0,0 +1,22 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = isInlineComment;
/**
* Check if a comment is inline one (i.e. on the same line as some non-comment
* code). Only works with comments that are not ignored by PostCSS. To work
* with those that are ignored use `findCommentInRaws`
*
* @param {Comment} comment - PostCSS comment node
* @return {boolean} true, if the comment is an inline one
*/
function isInlineComment(comment) {
var nextNode = comment.next();
var isBeforeSomething = !!nextNode && nextNode.type !== "comment" && comment.source.end.line === nextNode.source.start.line;
var isAfterSomething = comment.raws.before.search(/\n/) === -1;
return isAfterSomething || isBeforeSomething;
}

View File

@@ -0,0 +1,9 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = function (input) {
return !/[\n\r]/.test(input);
};

View File

@@ -0,0 +1,34 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = function (rule) {
// Get full selector
var selector = _lodash2.default.get(rule, "raws.selector.raw", rule.selector);
// Custom property set (e.g. --custom-property-set: {})
if (_lodash2.default.endsWith(selector, ":")) {
return false;
}
// Called Less mixin (e.g. a { .mixin() })
if (rule.ruleWithoutBody) {
return false;
}
// Non-outputting Less mixin definition (e.g. .mixin() {})
if (_lodash2.default.endsWith(selector, ")") && !_lodash2.default.includes(selector, ":")) {
return false;
}
return true;
};
var _lodash = require("lodash");
var _lodash2 = _interopRequireDefault(_lodash);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }

View File

@@ -0,0 +1,15 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = function (selector) {
// SCSS or Less interpolation
if (/#{.+?}|@{.+?}|\$\(.+?\)/.test(selector)) {
return false;
}
return true;
};

View File

@@ -0,0 +1,25 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = function (property) {
// SCSS var (e.g. $var: x), list (e.g. $list: (x)) or map (e.g. $map: (key:value))
if (property[0] === "$") {
return false;
}
// Less var (e.g. @var: x)
if (property[0] === "@") {
return false;
}
// SCSS or Less interpolation
if (/#{.+?}|@{.+?}|\$\(.+?\)/.test(property)) {
return false;
}
return true;
};

View File

@@ -0,0 +1,9 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = function (char) {
return [" ", "\n", "\t", "\r", "\f"].indexOf(char) !== -1;
};

11
node_modules/stylelint-scss/dist/utils/namespace.js generated vendored Normal file
View File

@@ -0,0 +1,11 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = namespace;
var prefix = "scss";
function namespace(ruleName) {
return prefix + "/" + ruleName;
}

View File

@@ -0,0 +1,9 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = function (options, exceptionName) {
return options && options.except && options.except.indexOf(exceptionName) !== -1;
};

View File

@@ -0,0 +1,9 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = function (options, ignoredName) {
return options && options.ignore && options.ignore.indexOf(ignoredName) !== -1;
};

View File

@@ -0,0 +1,88 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = parseNestedPropRoot;
/**
* Attempts to parse a selector as if it"s a root for a group of nested props
* E.g.: `margin: {`, `font: 10px/1.1 Arial {` ("{" excluded)
*/
function parseNestedPropRoot(propString) {
var modesEntered = [{
mode: "normal",
character: null,
isCalculationEnabled: true
}];
var result = {};
var lastModeIndex = 0;
var propName = "";
for (var i = 0; i < propString.length; i++) {
var character = propString[i];
// If entering/exiting a string
if (character === "\"" || character === "'") {
if (modesEntered[lastModeIndex].isCalculationEnabled === true) {
modesEntered.push({
mode: "string",
isCalculationEnabled: false,
character: character
});
lastModeIndex++;
} else if (modesEntered[lastModeIndex].mode === "string" && modesEntered[lastModeIndex].character === character && propString[i - 1] !== "\\") {
modesEntered.pop();
lastModeIndex--;
}
}
// If entering/exiting interpolation
if (character === "{") {
modesEntered.push({
mode: "interpolation",
isCalculationEnabled: true
});
lastModeIndex++;
} else if (character === "}") {
modesEntered.pop();
lastModeIndex--;
}
// Check for : outside fn call, string or interpolation. It must be at the
// end of a string or have a whitespace between it and following value
if (modesEntered[lastModeIndex].mode === "normal" && character === ":") {
var propValueStr = propString.substring(i + 1);
if (propValueStr.length) {
var propValue = {
before: /^(\s*)/.exec(propValueStr)[1],
value: propValueStr.trim()
};
// It's a declaration if 1) there is a whitespace after :, or
// 2) the value is a number with/without a unit (starts with a number
// or a dot), or
// 3) the value is a variable (starts with $), or
// 4) the value a string, surprisingly
if (propValue.before === "" && !/^[0-9.$'"]/.test(propValue.value)) {
return null;
}
// +1 for the colon
propValue.sourceIndex = propValue.before.length + i + 1;
result.propValue = propValue;
}
result.propName = {
after: /(\s*)$/.exec(propName)[1],
value: propName.trim()
};
return result;
}
propName += character;
}
return null;
}

View File

@@ -0,0 +1,19 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = function (selector, result, node, cb) {
try {
(0, _postcssSelectorParser2.default)(cb).process(selector);
} catch (e) {
result.warn("Cannot parse selector", { node: node });
}
};
var _postcssSelectorParser = require("postcss-selector-parser");
var _postcssSelectorParser2 = _interopRequireDefault(_postcssSelectorParser);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }

View File

@@ -0,0 +1,14 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = function (node) {
var result = "";
if (node.raws.before) {
result += node.raws.before;
}
result += node.toString();
return result;
};

View File

@@ -0,0 +1,860 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = findOperators;
exports.mathOperatorCharType = mathOperatorCharType;
/**
* Processes a string and finds Sass operators in it
*
* @param {Object} args - Named arguments object
* @param {String} args.string - the input string
* @param {Number} args.index - the position of args.string from the start of the line
* @param {Boolean} args.isAfterColon - pass "true" if the string is
* a variable value, a mixin/function parameter default.
* In such cases + and / tend to be operations more often
* @param {Function} args.callback - will be called on every instance of
* an operator. Accepts parameters:
* • string - the default source string
* • globalIndex - the string's position in the outer input
* • startIndex - index in string, where the operator starts
* • endIndex - index in string, where the operator ends (for `==`, etc.)
*
* @return {Array} array of { symbol, globalIndex, startIndex, endIndex }
* for each operator found within a string
*/
function findOperators(_ref) {
var string = _ref.string,
globalIndex = _ref.globalIndex,
isAfterColon = _ref.isAfterColon,
callback = _ref.callback;
var mathOperators = ["+", "/", "-", "*", "%"];
// A stack of modes activated for the current char: string, interpolation
// Calculations inside strings are not processed, so spaces are not linted
var modesEntered = [{
mode: "normal",
isCalculationEnabled: true,
character: null
}];
var result = [];
var lastModeIndex = 0;
for (var i = 0; i < string.length; i++) {
var character = string[i];
var substringStartingWithIndex = string.substring(i);
// If entering/exiting a string
if (character === "\"" || character === "'") {
if (modesEntered[lastModeIndex].isCalculationEnabled === true) {
modesEntered.push({
mode: "string",
isCalculationEnabled: false,
character: character
});
lastModeIndex++;
} else if (modesEntered[lastModeIndex].mode === "string" && modesEntered[lastModeIndex].character === character && string[i - 1] !== "\\") {
modesEntered.pop();
lastModeIndex--;
}
}
// If entering/exiting interpolation (may be inside a string)
// Comparing with length-2 because `#{` at the very end doesnt matter
if (character === "#" && i + 1 < string.length - 2 && string[i + 1] === "{") {
modesEntered.push({
mode: "interpolation",
isCalculationEnabled: true
});
lastModeIndex++;
} else if (character === "}") {
modesEntered.pop();
lastModeIndex--;
}
// Don't lint if inside a string
if (modesEntered[lastModeIndex].isCalculationEnabled === false) {
continue;
}
// If it's a math operator
if (mathOperators.indexOf(character) !== -1 && mathOperatorCharType(string, i, isAfterColon) === "op" ||
// or is "<" or ">"
substringStartingWithIndex.search(/^[<>]([^=]|$)/) !== -1) {
result.push({
symbol: string[i],
globalIndex: globalIndex,
startIndex: i,
endIndex: i
});
if (callback) {
callback(string, globalIndex, i, i);
}
}
// "<=", ">=", "!=", "=="
if (substringStartingWithIndex.search(/^[><=!]=/) !== -1) {
result.push({
symbol: string[i],
globalIndex: globalIndex,
startIndex: i,
endIndex: i + 1
});
if (callback) {
callback(string, globalIndex, i, i + 1);
}
}
}
// result.length > 0 && console.log(string, result)
return result;
}
/**
* Checks if a character is an operator, a sign (+ or -), or part of a string
*
* @param {String} string - the source string
* @param {Number} index - the index of the character in string to check
* @param {Boolean} isAfterColon - if the value string a variable
* value, a mixin/function parameter default. In such cases + and / tend
* to be operations more often
* @return {String|false}
* • "op", if the character is a operator in a math/string operation
* • "sign" if it is a + or - before a numeric,
* • "char" if it is a part of a string,
* • false - if it is none from above (most likely an error)
*/
function mathOperatorCharType(string, index, isAfterColon) {
// !Checking here to prevent unnecessary calculations and deep recursion
// when calling isPrecedingOperator()
if (["+", "/", "-", "*", "%"].indexOf(string[index]) === -1) {
return "char";
}
var character = string[index];
// console.log(string)
// ---- Processing + characters
if (character === "+") {
// console.log('checking plus')
return checkPlus(string, index, isAfterColon);
}
// ---- Processing - characters
if (character === "-") {
return checkMinus(string, index);
}
// ---- Processing * character
if (character === "*") {
return "op";
}
// ---- Processing % character
if (character === "%") {
return checkPercent(string, index);
}
// ---- Processing / character
// http://sass-lang.com/documentation/file.SASS_REFERENCE.html#division-and-slash
if (character === "/") {
return checkSlash(string, index, isAfterColon);
}
// console.log("nothing applies")
return "char";
}
// --------------------------------------------------------------------------
// Functions for checking particular characterd (+, -, /)
// --------------------------------------------------------------------------
/**
* Checks the specified `+` char type: operator, sign (+ or -), part of string
*
* @param {String} string - the source string
* @param {Number} index - the index of the character in string to check
* @param {Boolean} isAftercolon - if the value string a variable
* value, a mixin/function parameter default. In such cases + is always an
* operator if surrounded by numbers/values with units
* @return {String|false}
* • "op", if the character is a operator in a math/string operation
* • "sign" if it is a sign before a positive number,
* • false - if it is none from above (most likely an error)
*/
function checkPlus(string, index, isAftercolon) {
var before = string.substring(0, index);
var after = string.substring(index + 1);
// If the character is at the beginning of the input
var isAtStart_ = isAtStart(string, index);
// If the character is at the end of the input
var isAtEnd_ = isAtEnd(string, index);
var isWhitespaceBefore = before.search(/\s$/) !== -1;
var isWhitespaceAfter = after.search(/^\s/) !== -1;
var isValueWithUnitAfter_ = isValueWithUnitAfter(after);
var isNumberAfter_ = isNumberAfter(after);
var isInterpolationAfter_ = isInterpolationAfter(after);
// The early check above helps prevent deep recursion here
var isPrecedingOperator_ = isPrecedingOperator(string, index);
if (isAtStart_) {
// console.log("+, `+<sth>` or `+ <sth>`")
return "sign";
}
// E.g. `1+1`, `string+#fff`
if (!isAtStart_ && !isWhitespaceBefore && !isAtEnd_ && !isWhitespaceAfter) {
// E.g. `1-+1`
if (isPrecedingOperator_) {
// console.log('1+1')
return "sign";
}
// console.log("+, no spaces")
return "op";
}
// e.g. `something +something`
if (!isAtEnd_ && !isWhitespaceAfter) {
// e.g. `+something`, ` ... , +something`, etc.
if (isNoOperandBefore(string, index)) {
// console.log("+, nothing before")
return "sign";
}
// e.g. `sth +10px`, `sth +1`
if (isValueWithUnitAfter_.is && !isValueWithUnitAfter_.opsBetween || isNumberAfter_.is && !isNumberAfter_.opsBetween) {
if (isAftercolon === true) {
// console.log(": 10px +1")
return "op";
}
// e.g. `(sth +10px)`, `fun(sth +1)`
if (isInsideParens(string, index) || isInsideFunctionCall(string, index).is) {
// console.log("+10px or +1, inside function or parens")
return "op";
}
// e.g. `#{10px +1}`
if (isInsideInterpolation(string, index)) {
// console.log('+, #{10px +1}')
return "op";
}
// console.log('+, default')
return "sign";
}
// e.g. `sth +#fff`, `sth +string`, `sth +#{...}`, `sth +$var`
if (isStringAfter(after) || isHexColorAfter(after) || after[0] === "$" || isInterpolationAfter_.is && !isInterpolationAfter_.opsBefore) {
// e.g. `sth+ +string`
if (isPrecedingOperator_) {
// console.log("+10px or +1, before is an operator")
return "sign";
}
// console.log("+#000, +string, +#{sth}, +$var")
return "op";
}
// console.log('sth +sth, default')
return "op";
}
// If the + is after a value, e.g. `$var+`
if (!isAtStart_ && !isWhitespaceBefore) {
// It is always an operator. Prior to Sass 4, `#{...}+` was differernt,
// but that's not logical and had been fixed.
// console.log('1+ sth')
return "op";
}
// If it has whitespaces on both sides
// console.log('sth + sth')
return "op";
}
/**
* Checks the specified `-` character: operator, sign (+ or -), part of string
*
* @param {String} string - the source string
* @param {Number} index - the index of the character in string to check
* @return {String|false}
* • "op", if the character is a operator in a math/string operation
* • "sign" if it is a sign before a negative number,
* • "char" if it is a part of a string or identifier,
* • false - if it is none from above (most likely an error)
*/
function checkMinus(string, index) {
var before = string.substring(0, index);
var after = string.substring(index + 1);
// If the character is at the beginning of the input
var isAtStart_ = isAtStart(string, index);
// If the character is at the end of the input
var isAtEnd_ = isAtEnd(string, index);
var isWhitespaceBefore = before.search(/\s$/) !== -1;
var isWhitespaceAfter = after.search(/^\s/) !== -1;
var isValueWithUnitAfter_ = isValueWithUnitAfter(after);
var isValueWithUnitBefore_ = isValueWithUnitBefore(before);
var isNumberAfter_ = isNumberAfter(after);
var isNumberBefore_ = isNumberBefore(before);
var isInterpolationAfter_ = isInterpolationAfter(after);
var isParensAfter_ = isParensAfter(after);
var isParensBefore_ = isParensBefore(before);
// The early check above helps prevent deep recursion here
var isPrecedingOperator_ = isPrecedingOperator(string, index);
if (isAtStart_) {
// console.log("-, -<sth> or - <sth>")
return "sign";
}
// `10 - 11`
if (!isAtEnd_ && !isAtStart_ && isWhitespaceBefore && isWhitespaceAfter) {
// console.log("-, Op: 10px - 10px")
return "op";
}
// e.g. `something -10px`
if (!isAtEnd_ && !isAtStart_ && isWhitespaceBefore && !isWhitespaceAfter) {
if (isParensAfter_.is && !isParensAfter_.opsBefore) {
// console.log("-, Op: <sth> -(...)")
return "op";
}
// e.g. `sth -1px`, `sth -1`.
// Always a sign, even inside parens/function args
if (isValueWithUnitAfter_.is && !isValueWithUnitAfter_.opsBetween || isNumberAfter_.is && !isNumberAfter_.opsBetween) {
// console.log("-, sign: -1px or -1")
return "sign";
}
// e.g. `sth --1`, `sth +-2px`
if (isValueWithUnitAfter_.is && isValueWithUnitAfter_.opsBetween || isNumberAfter_.is && isNumberAfter_.opsBetween) {
// console.log("-, op: --1px or --1")
return "op";
}
// `<sth> -string`, `<sth> -#{...}`
if (isStringAfter(after) || isInterpolationAfter_.is && !isInterpolationAfter_.opsBefore) {
// console.log("-, char: -#{...}")
return "char";
}
// e.g. `#0af -#f0a`, and edge-cases can take a hike
if (isHexColorAfter(after) && isHexColorBefore(before.trim())) {
// console.log("-, op: #fff-, -#fff")
return "op";
}
// If the - is before a variable, than it's most likely an operator
if (after[0] === "$") {
if (isPrecedingOperator_) {
// console.log("-, sign: -$var, another operator before")
return "sign";
}
// console.log("-, op: -$var, NO other operator before")
return "op";
}
// By default let's make it an sign for now
// console.log('-, sign: default in <sth> -<sth>')
return "sign";
}
// No whitespace before,
// e.g. `10x- something`
if (!isAtEnd_ && !isAtStart_ && !isWhitespaceBefore && isWhitespaceAfter) {
if (isParensBefore_) {
// console.log('-, op: `(...)- <sth>`')
return "op";
}
if (isNumberBefore(before) || isHexColorBefore(before)) {
// console.log('`-, op: 10- <sth>, #aff- <sth>`')
return "op";
}
// console.log('-, char: default in <sth>- <sth>')
return "char";
}
// NO Whitespace,
// e.g. `10px-1`
if (!isAtEnd_ && !isAtStart_ && !isWhitespaceBefore && !isWhitespaceAfter) {
// console.log('no spaces')
// `<something>-1`, `<something>-10px`
if (isValueWithUnitAfter_.is && !isValueWithUnitAfter_.opsBetween || isNumberAfter_.is && !isNumberAfter_.opsBetween) {
// `10px-1`, `1-10px`, `1-1`, `1x-1x`
if (isValueWithUnitBefore_ || isNumberBefore_) {
// console.log("-, op: 1-10px")
return "op";
}
// The - could be a "sign" here, but for now "char" does the job
}
// `1-$var`
if (isNumberBefore_ && after[0] === "$") {
// console.log("-, op: 1-$var")
return "op";
}
// `fn()-10px`
if (isFunctionBefore(before) && (isNumberAfter_.is && !isNumberAfter_.opsBetween || isValueWithUnitAfter_.is && !isValueWithUnitAfter_.opsBetween)) {
// console.log("-, op: fn()-10px")
return "op";
}
}
// And in all the other cases it's a characher inside a string
// console.log("-, default: char")
return "char";
}
/**
* Checks the specified `/` character: operator, sign (+ or -), part of string
*
* @param {String} string - the source string
* @param {Number} index - the index of the character in string to check
* @param {Boolean} isAfterColon - if the value string a variable
* value, a mixin/function parameter default. In such cases / is always an
* operator if surrounded by numbers/values with units
* @return {String|false}
* • "op", if the character is a operator in a math/string operation
* • "char" if it gets compiled as-is, e.g. `font: 10px/1.2;`,
* • false - if it is none from above (most likely an error)
*/
function checkSlash(string, index, isAftercolon) {
// Trimming these, as spaces before/after a slash don't matter
var before = string.substring(0, index).trim();
var after = string.substring(index + 1).trim();
var isValueWithUnitAfter_ = isValueWithUnitAfter(after);
var isValueWithUnitBefore_ = isValueWithUnitBefore(before);
var isNumberAfter_ = isNumberAfter(after);
var isNumberBefore_ = isNumberBefore(before);
var isParensAfter_ = isParensAfter(after);
var isParensBefore_ = isParensBefore(before);
// FIRST OFF. Interpolation on any of the sides is a NO-GO for division op
if (isInterpolationBefore(before).is || isInterpolationAfter(after).is) {
// console.log("/, interpolation")
return "char";
}
// e.g. `10px/normal`
if (isStringBefore(before).is || isStringAfter(after)) {
// console.log("/, string")
return "char";
}
// For all other value options (numbers, value+unit, hex color)
// `$var/1`, `#fff/-$var`
// Here we don't care if there is a sign before the var
if (isVariableBefore(before) || isVariableAfter(after).is) {
// console.log("/, variable")
return "op";
}
if (isFunctionBefore(before) || isFunctionAfter(after).is) {
// console.log("/, function as operand")
return "op";
}
if (isParensBefore_ || isParensAfter_.is) {
// console.log("/, function as operand")
return "op";
}
// `$var: 10px/2; // 5px`
if (isAftercolon === true && (isValueWithUnitAfter_.is || isNumberAfter_.is) && (isValueWithUnitBefore_ || isNumberBefore_)) {
return "op";
}
// Quick check of the following operator symbol - if it is a math operator
if (
// +, *, % count as operators unless after interpolation or at the start
before.search(/[^{,(}\s]\s*[+*%]\s*[^(){},]+$/) !== -1 ||
// We consider minus as op only if surrounded by whitespaces (` - `);
before.search(/[^{,(}\s]\s+-\s+[^(){},]+$/) !== -1 ||
// `10/2 * 3`, `10/2 % 3`, with or without spaces
after.search(/^[^(){},]+[*%]/) !== -1 ||
// `10px/2px+1`, `10px/2px+ 1`
after.search(/^[^(){},\s]+[+]/) !== -1 ||
// Anything but `10px/2px +1`, `10px/2px +1px`
after.search(/^[^(){},\s]+\s+(\+\D)/) !== -1 ||
// Following ` -`: only if `$var` after (`10/10 -$var`)
after.search(/^[^(){},\s]+\s+-(\$|\s)/) !== -1 ||
// Following `-`: only if number after (`10s/10s-10`, `10s/10s-.1`)
after.search(/^[^(){},\s]+-(\.){0,1}\d/) !== -1 ||
// Or if there is a number before anything but string after (not `10s/1-str`,)
after.search(/^(\d*\.){0,1}\d+-\s*[^#a-zA-Z_\s]/) !== -1) {
// console.log("/, math op around")
return "op";
}
// e.g. `(1px/1)`, `fn(7 / 15)`, but not `url(8/11)`
var isInsideFn = isInsideFunctionCall(string, index);
if (isInsideParens(string, index) || isInsideFn.is && isInsideFn.fn !== "url") {
// console.log("/, parens or function arg")
return "op";
}
// console.log("/, default")
return "char";
}
/**
* Checks the specified `%` character: operator or part of value
*
* @param {String} string - the source string
* @param {Number} index - the index of the character in string to check
* @return {String|false}
* • "op", if the character is a operator in a math/string operation
* • "char" if it gets compiled as-is, e.g. `width: 10%`,
* • false - if it is none from above (most likely an error)
*/
function checkPercent(string, index) {
// Trimming these, as spaces before/after a slash don't matter
var before = string.substring(0, index);
var after = string.substring(index + 1);
// If the character is at the beginning of the input
var isAtStart_ = isAtStart(string, index);
// If the character is at the end of the input
var isAtEnd_ = isAtEnd(string, index);
var isWhitespaceBefore = before.search(/\s$/) !== -1;
var isWhitespaceAfter = after.search(/^\s/) !== -1;
var isParensBefore_ = isParensBefore(before);
// FIRST OFF. Interpolation on any of the sides is a NO-GO
if (isInterpolationBefore(before.trim()).is || isInterpolationAfter(after.trim()).is) {
// console.log("%, interpolation")
return "char";
}
if (isAtStart_ || isAtEnd_) {
// console.log("%, start/end")
return "char";
}
// In `<sth> %<sth>` it's most likely an operator (except for inteprolation
// checked above)
if (isWhitespaceBefore && !isWhitespaceAfter) {
// console.log("%, `<sth> %<sth>`")
return "op";
}
// `$var% 1`, `$var%1`, `$var%-1`
if (isVariableBefore(before) || isParensBefore_) {
// console.log("%, after a variable, function or parens")
return "op";
}
// in all other cases in `<sth>% <sth>` it is most likely a unit
if (!isWhitespaceBefore && isWhitespaceAfter) {
// console.log("%, `<sth>% <sth>`")
return "char";
}
// console.log("%, default")
return "char";
}
// --------------------------------------------------------------------------
// Lots of elementary helpers
// --------------------------------------------------------------------------
function isAtStart(string, index) {
var before = string.substring(0, index).trim();
return before.length === 0 || before.search(/[({,]$/) !== -1;
}
function isAtEnd(string, index) {
var after = string.substring(index + 1).trim();
return after.length === 0 || after.search(/^[,)}]/) !== -1;
}
function isInsideParens(string, index) {
var before = string.substring(0, index).trim();
var after = string.substring(index + 1).trim();
if (before.search(/(?:^|[,{]|\s)\(\s*[^(){},]+$/) !== -1 && after.search(/^[^(){},\s]+\s*\)/) !== -1) {
return true;
}
return false;
}
function isInsideInterpolation(string, index) {
var before = string.substring(0, index).trim();
if (before.search(/#\{[^}]*$/) !== -1) {
return true;
}
return false;
}
/**
* Checks if the character is inside a function agruments
*
* @param {String} string - the input string
* @param {Number} index - current character index
* @return {Object} return
* {Boolean} return.is - if inside a function arguments
* {String} return.fn - function name
*/
function isInsideFunctionCall(string, index) {
var result = { is: false, fn: null };
var before = string.substring(0, index).trim();
var after = string.substring(index + 1).trim();
var beforeMatch = before.match(/([a-zA-Z_-][a-zA-Z0-9_-]*)\([^(){},]+$/);
if (beforeMatch && beforeMatch[0] && after.search(/^[^({},]+\)/) !== -1) {
result.is = true;
result.fn = beforeMatch[1];
}
return result;
}
/**
* Checks if there is a string before the character.
* Also checks if there is a math operator in between
*
* @param {String} before - the input string that preceses the character
* @return {Object} return
* {Boolean} return.is - if there is a string
* {String} return.opsBetween - if there are operators in between
*/
function isStringBefore(before) {
var result = { is: false, opsBetween: false };
var stringOpsClipped = before.replace(/(\s*[+/*%]|\s+-)+$/, "");
if (stringOpsClipped !== before) {
result.opsBetween = true;
}
// If it is quoted
if (stringOpsClipped[stringOpsClipped.length - 1] == "\"" || stringOpsClipped[stringOpsClipped.length - 1] == "'") {
result.is = true;
} else if (stringOpsClipped.search(/(?:^|[/(){},: ])([a-zA-Z_][a-zA-Z_0-9-]*|-+[a-zA-Z_]+[a-zA-Z_0-9-]*)$/) !== -1) {
// First pattern: a1, a1a, a-1,
result.is = true;
}
return result;
}
function isStringAfter(after) {
var stringTrimmed = after.trim();
// If it is quoted
if (stringTrimmed[0] == "\"" || stringTrimmed[0] == "'") return true;
// e.g. `a1`, `a1a`, `a-1`, and even `--s323`
if (stringTrimmed.search(/^([a-zA-Z_][a-zA-Z_0-9-]*|-+[a-zA-Z_]+[a-zA-Z_0-9-]*)(?:$|[)}, ])/) !== -1) return true;
return false;
}
function isInterpolationAfter(after) {
var result = { is: false, opsBetween: false };
var matches = after.match(/^\s*([+/*%-]\s*)*#{/);
if (matches) {
if (matches[0]) {
result.is = true;
}
if (matches[1]) {
result.opsBetween = true;
}
}
return result;
}
function isParensAfter(after) {
var result = { is: false, opsBetween: false };
var matches = after.match(/^\s*([+/*%-]\s*)*\(/);
if (matches) {
if (matches[0]) {
result.is = true;
}
if (matches[1]) {
result.opsBetween = true;
}
}
return result;
}
function isParensBefore(before) {
return before.search(/\)\s*$/) !== -1;
}
/**
* Checks if there is an interpolation before the character.
* Also checks if there is a math operator in between
*
* @param {String} before - the input string that preceses the character
* @return {Object} return
* {Boolean} return.is - if there is an interpolation
* {String} return.opsBetween - if there are operators in between
*/
function isInterpolationBefore(before) {
var result = { is: false, opsBetween: false };
// Removing preceding operators if any
var beforeOpsClipped = before.replace(/(\s*[+/*%-])+$/, "");
if (beforeOpsClipped !== before) {
result.opsBetween = true;
}
if (beforeOpsClipped[beforeOpsClipped.length - 1] === "}") {
result.is = true;
}
return result;
}
function isValueWithUnitBefore(before) {
// 1px, 0.1p-x, .2p-, 11.2pdf-df1df_
// Surprisingly, ` d.10px` - .10px is separated from a sequence
// and is considered a value with a unit
if (before.trim().search(/(^|[/(, ]|\.)\d[a-zA-Z_0-9-]+$/) !== -1) {
return true;
}
return false;
}
function isValueWithUnitAfter(after) {
var result = { is: false, opsBetween: false };
// 1px, 0.1p-x, .2p-, 11.2pdf-dfd1f_
// Again, ` d.10px` - .10px is separated from a sequence
// and is considered a value with a unit
var matches = after.match(/^\s*([+/*%-]\s*)*(\d+(\.\d+){0,1}|\.\d+)[a-zA-Z_0-9-]+(?:$|[)}, ])/);
if (matches) {
if (matches[0]) {
result.is = true;
}
if (matches[1]) {
result.opsBetween = true;
}
}
return result;
}
function isNumberAfter(after) {
var result = { is: false, opsBetween: false };
var matches = after.match(/^\s*([+/*%-]\s*)*(\d+(\.\d+){0,1}|\.\d+)(?:$|[)}, ])/);
if (matches) {
if (matches[0]) {
result.is = true;
}
if (matches[1]) {
result.opsBetween = true;
}
}
return result;
}
function isNumberBefore(before) {
if (before.trim().search(/(?:^|[/(){},\s])(\d+(\.\d+){0,1}|\.\d+)$/) !== -1) {
return true;
}
return false;
}
function isVariableBefore(before) {
return before.trim().search(/\$[a-zA-Z_0-9-]+$/) !== -1;
}
function isVariableAfter(after) {
var result = { is: false, opsBetween: false };
var matches = after.match(/^\s*([+/*%-]\s*)*\$/);
if (matches) {
if (matches[0]) {
result.is = true;
}
if (matches[1]) {
result.opsBetween = true;
}
}
return result;
}
function isFunctionBefore(before) {
return before.trim().search(/[a-zA-Z0-9_-]\(.*?\)\s*$/) !== -1;
}
function isFunctionAfter(after) {
var result = { is: false, opsBetween: false };
// `-fn()` is a valid function name, so if a - should be a sign/operator,
// it must have a space after
var matches = after.match(/^\s*(-\s+|[+/*%]\s*)*[a-zA_Z_-][a-zA-Z_0-9-]*\(/);
if (matches) {
if (matches[0]) {
result.is = true;
}
if (matches[1]) {
result.opsBetween = true;
}
}
return result;
}
/**
* Checks if the input string is a hex color value
*
* @param {String} string - the input
* @return {Boolean} true, if the input is a hex color
*/
function isHexColor(string) {
return string.trim().search(/^#([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$/) !== -1;
}
function isHexColorAfter(after) {
var afterTrimmed = after.match(/(.*?)(?:[)},+/*%-]|\s|$)/)[1].trim();
return isHexColor(afterTrimmed);
}
function isHexColorBefore(before) {
if (before.search(/(?:[/(){},+/*%-\s]|^)#([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$/) !== -1) {
return true;
}
return false;
}
/**
* Checks if there is no operand before the currenc char
* In other words, the current char is at the start of a possible operation,
* e.g. at the string start, after the opening paren or after a comma
*
* @param {String} string - the input string
* @param {Number} index - current char's position in string
* @return {Boolean}
*/
function isNoOperandBefore(string, index) {
var before = string.substring(0, index).trim();
return before.length === 0 || before.search(/[({,]&/) !== -1;
}
function isPrecedingOperator(string, index) {
var prevCharIndex = -1;
for (var i = index - 1; i >= 0; i--) {
if (string[i].search(/\s/) === -1) {
prevCharIndex = i;
break;
}
}
if (prevCharIndex === -1) {
return false;
}
if (mathOperatorCharType(string, prevCharIndex) === "op") {
return true;
}
return false;
}

View File

@@ -0,0 +1,339 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = function (targetWhitespace, expectation, messages) {
// Keep track of active arguments in order to avoid passing
// too much stuff around, making signatures long and confusing.
// This variable gets reset anytime a checking function is called.
var activeArgs = void 0;
/**
* Check for whitespace *before* a character.
*
* @param {object} args - Named arguments object
* @param {string} args.source - The source string
* @param {number} args.index - The index of the character to check before
* @param {function} args.err - If a violation is found, this callback
* will be invoked with the relevant warning message.
* Typically this callback will report() the violation.
* @param {function} args.errTarget - If a violation is found, this string
* will be sent to the relevant warning message.
* @param {string} [args.lineCheckStr] - Single- and multi-line checkers
* will use this string to determine whether they should proceed,
* i.e. if this string is one line only, single-line checkers will check,
* multi-line checkers will ignore.
* If none is passed, they will use `source`.
* @param {boolean} [args.onlyOneChar=false] - Only check *one* character before.
* By default, "always-*" checks will look for the `targetWhitespace` one
* before and then ensure there is no whitespace two before. This option
* bypasses that second check.
* @param {boolean} [args.allowIndentation=false] - Allow arbitrary indentation
* between the `targetWhitespace` (almost definitely a newline) and the `index`.
* With this option, the checker will see if a newline *begins* the whitespace before
* the `index`.
*/
function before(_ref) {
var source = _ref.source,
index = _ref.index,
err = _ref.err,
errTarget = _ref.errTarget,
lineCheckStr = _ref.lineCheckStr,
_ref$onlyOneChar = _ref.onlyOneChar,
onlyOneChar = _ref$onlyOneChar === undefined ? false : _ref$onlyOneChar,
_ref$allowIndentation = _ref.allowIndentation,
allowIndentation = _ref$allowIndentation === undefined ? false : _ref$allowIndentation;
activeArgs = { source: source, index: index, err: err, errTarget: errTarget, onlyOneChar: onlyOneChar, allowIndentation: allowIndentation };
switch (expectation) {
case "always":
expectBefore();
break;
case "never":
rejectBefore();
break;
case "always-single-line":
if (!(0, _isSingleLineString2.default)(lineCheckStr || source)) {
return;
}
expectBefore(messages.expectedBeforeSingleLine);
break;
case "never-single-line":
if (!(0, _isSingleLineString2.default)(lineCheckStr || source)) {
return;
}
rejectBefore(messages.rejectedBeforeSingleLine);
break;
case "always-multi-line":
if ((0, _isSingleLineString2.default)(lineCheckStr || source)) {
return;
}
expectBefore(messages.expectedBeforeMultiLine);
break;
case "never-multi-line":
if ((0, _isSingleLineString2.default)(lineCheckStr || source)) {
return;
}
rejectBefore(messages.rejectedBeforeMultiLine);
break;
default:
throw (0, _configurationError2.default)("Unknown expectation \"" + expectation + "\"");
}
}
/**
* Check for whitespace *after* a character.
*
* Parameters are pretty much the same as for `before()`, above, just substitute
* the word "after" for "before".
*/
function after(_ref2) {
var source = _ref2.source,
index = _ref2.index,
err = _ref2.err,
errTarget = _ref2.errTarget,
lineCheckStr = _ref2.lineCheckStr,
_ref2$onlyOneChar = _ref2.onlyOneChar,
onlyOneChar = _ref2$onlyOneChar === undefined ? false : _ref2$onlyOneChar;
activeArgs = { source: source, index: index, err: err, errTarget: errTarget, onlyOneChar: onlyOneChar };
switch (expectation) {
case "always":
expectAfter();
break;
case "never":
rejectAfter();
break;
case "always-single-line":
if (!(0, _isSingleLineString2.default)(lineCheckStr || source)) {
return;
}
expectAfter(messages.expectedAfterSingleLine);
break;
case "never-single-line":
if (!(0, _isSingleLineString2.default)(lineCheckStr || source)) {
return;
}
rejectAfter(messages.rejectedAfterSingleLine);
break;
case "always-multi-line":
if ((0, _isSingleLineString2.default)(lineCheckStr || source)) {
return;
}
expectAfter(messages.expectedAfterMultiLine);
break;
case "never-multi-line":
if ((0, _isSingleLineString2.default)(lineCheckStr || source)) {
return;
}
rejectAfter(messages.rejectedAfterMultiLine);
break;
default:
throw (0, _configurationError2.default)("Unknown expectation \"" + expectation + "\"");
}
}
function beforeAllowingIndentation(obj) {
before((0, _lodash.assign)({}, obj, { allowIndentation: true }));
}
function expectBefore() {
var messageFunc = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : messages.expectedBefore;
if (activeArgs.allowIndentation) {
expectBeforeAllowingIndentation(messageFunc);
return;
}
var _activeArgs = activeArgs,
source = _activeArgs.source,
index = _activeArgs.index;
var oneCharBefore = source[index - 1];
var twoCharsBefore = source[index - 2];
if (!isValue(oneCharBefore)) {
return;
}
if (targetWhitespace === "newline") {
// If index is preceeded by a Windows CR-LF ...
if (oneCharBefore === "\n" && twoCharsBefore === "\r") {
if (activeArgs.onlyOneChar || !(0, _isWhitespace2.default)(source[index - 3])) {
return;
}
}
// If index is followed by a Unix LF ...
if (oneCharBefore === "\n" && twoCharsBefore !== "\r") {
if (activeArgs.onlyOneChar || !(0, _isWhitespace2.default)(twoCharsBefore)) {
return;
}
}
}
if (targetWhitespace === "space" && oneCharBefore === " ") {
if (activeArgs.onlyOneChar || !(0, _isWhitespace2.default)(twoCharsBefore)) {
return;
}
}
activeArgs.err(messageFunc(activeArgs.errTarget ? activeArgs.errTarget : source[index]));
}
function expectBeforeAllowingIndentation() {
var messageFunc = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : messages.expectedBefore;
var _activeArgs2 = activeArgs,
source = _activeArgs2.source,
index = _activeArgs2.index,
err = _activeArgs2.err;
var expectedChar = function () {
if (targetWhitespace === "newline") {
return "\n";
}
if (targetWhitespace === "space") {
return " ";
}
}();
var i = index - 1;
while (source[i] !== expectedChar) {
if (source[i] === "\t" || source[i] === " ") {
i--;
continue;
}
err(messageFunc(activeArgs.errTarget ? activeArgs.errTarget : source[index]));
return;
}
}
function rejectBefore() {
var messageFunc = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : messages.rejectedBefore;
var _activeArgs3 = activeArgs,
source = _activeArgs3.source,
index = _activeArgs3.index;
var oneCharBefore = source[index - 1];
if (isValue(oneCharBefore) && (0, _isWhitespace2.default)(oneCharBefore)) {
activeArgs.err(messageFunc(activeArgs.errTarget ? activeArgs.errTarget : source[index]));
}
}
function afterOneOnly(obj) {
after((0, _lodash.assign)({}, obj, { onlyOneChar: true }));
}
function expectAfter() {
var messageFunc = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : messages.expectedAfter;
var _activeArgs4 = activeArgs,
source = _activeArgs4.source,
index = _activeArgs4.index;
var oneCharAfter = index + 1 < source.length ? source[index + 1] : "";
var twoCharsAfter = index + 2 < source.length ? source[index + 2] : "";
if (!isValue(oneCharAfter)) {
return;
}
if (targetWhitespace === "newline") {
// If index is followed by a Windows CR-LF ...
if (oneCharAfter === "\r" && twoCharsAfter === "\n") {
var threeCharsAfter = index + 3 < source.length ? source[index + 3] : "";
if (activeArgs.onlyOneChar || !(0, _isWhitespace2.default)(threeCharsAfter)) {
return;
}
}
// If index is followed by a Unix LF ...
if (oneCharAfter === "\n") {
if (activeArgs.onlyOneChar || !(0, _isWhitespace2.default)(twoCharsAfter)) {
return;
}
}
}
if (targetWhitespace === "space" && oneCharAfter === " ") {
if (activeArgs.onlyOneChar || !(0, _isWhitespace2.default)(twoCharsAfter)) {
return;
}
}
activeArgs.err(messageFunc(activeArgs.errTarget ? activeArgs.errTarget : source[index]));
}
function rejectAfter() {
var messageFunc = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : messages.rejectedAfter;
var _activeArgs5 = activeArgs,
source = _activeArgs5.source,
index = _activeArgs5.index;
var oneCharAfter = index + 1 < source.length ? source[index + 1] : "";
if (isValue(oneCharAfter) && (0, _isWhitespace2.default)(oneCharAfter)) {
activeArgs.err(messageFunc(activeArgs.errTarget ? activeArgs.errTarget : source[index]));
}
}
return {
before: before,
beforeAllowingIndentation: beforeAllowingIndentation,
after: after,
afterOneOnly: afterOneOnly
};
};
var _lodash = require("lodash");
var _isWhitespace = require("./isWhitespace");
var _isWhitespace2 = _interopRequireDefault(_isWhitespace);
var _isSingleLineString = require("./isSingleLineString");
var _isSingleLineString2 = _interopRequireDefault(_isSingleLineString);
var _configurationError = require("./configurationError");
var _configurationError2 = _interopRequireDefault(_configurationError);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function isValue(x) {
return x !== undefined && x !== null;
}
/**
* Create a whitespaceChecker, which exposes the following functions:
* - `before()`
* - `beforeAllowingIndentation()`
* - `after()`
* - `afterOneOnly()`
*
* @param {"space"|"newline"} targetWhitespace - This is a keyword instead
* of the actual character (e.g. " ") in order to accommodate
* different styles of newline ("\n" vs "\r\n")
* @param {
* "always"|"never"
* |"always-single-line"|"always-multi-line"
* | "never-single-line"|"never-multi-line"
* } expectation
* @param {object} messages - An object of message functions;
* calling `before*()` or `after*()` and the `expectation` that is passed
* determines which message functions are required
* @param {function} [messages.exectedBefore]
* @param {function} [messages.rejectedBefore]
* @param {function} [messages.expectedAfter]
* @param {function} [messages.rejectedAfter]
* @param {function} [messages.expectedBeforeSingleLine]
* @param {function} [messages.rejectedBeforeSingleLine]
* @param {function} [messages.expectedBeforeMultiLine]
* @param {function} [messages.rejectedBeforeMultiLine]
* @return {object} The checker, with its exposed checking functions
*/

5
node_modules/stylelint-scss/docs/examples/README.md generated vendored Normal file
View File

@@ -0,0 +1,5 @@
# Example configs
This dir contains examples of `.stylelintrc` configuration file for several use cases.
* [Rules for `@if`/`@else` statements](./if-else.md)

149
node_modules/stylelint-scss/docs/examples/if-else.md generated vendored Normal file
View File

@@ -0,0 +1,149 @@
# `@if`/`@else`
A stylesheet author might want to treat `@if` and `@else` in a special manner, for example `@else` should be on the same line as its `@if`'s closing brace while all the other blocks and at-rules has to have newline after their closing brace. stylelint-scss has some rules for this, but from the core stylelint's point of view, `@if` and `@else` SCSS statements are pretty much regular at-rules, so they comply to corresponding `at-rule-...` and `block-...` rules. Below are some configurations that might help you achieve the needed patterns.
---
**Config 1**: `@else` is on the same line as the preceding `@if`/`@else`'s `}`, space between them. Empty line before all at-rules (except `@else`), space before `{`, newline after all `}` except `@if`'s and `@else`'s.
```json
{
"plugins": [
"stylelint-scss"
],
"rules": {
"at-rule-empty-line-before": [
"always", {
"ignoreAtRules": [ "else" ]
}
],
"block-opening-brace-space-before": "always",
"block-closing-brace-newline-after": [
"always", {
"ignoreAtRules": [ "if", "else" ]
}
],
"at-rule-name-space-after": "always",
"rule-non-nested-empty-line-before": "always",
"scss/at-else-closing-brace-newline-after": "always-last-in-chain",
"scss/at-else-closing-brace-space-after": "always-intermediate",
"scss/at-else-closing-brace-space-after": "always-intermediate",
"scss/at-if-closing-brace-newline-after": "always-last-in-chain",
"scss/at-if-closing-brace-space-after": "always-intermediate"
}
}
```
This code is considered **valid**
```scss
@if {
// ...
}
a {}
@if {
// ...
} @else {
// ...
}
a {}
@if {
// ...
} @else if {
// ...
} @else {
// ...
}
@if {
// ...
} @else
if {
// ...
} @else {
// ...
}
a {}
```
These patterns are considered **non-valid**:
```scss
@if {
// ...
} a {}
```
```scss
@if {
// ...
}@else {
// ...
}
```
```scss
@if {
// ...
} @else if{
// ...
} @else {
// ...
}
```
```scss
@if {
// ...
} @else if{
// ...
} @else {
// ...
}
```
---
**Config 2**: `@else` is on a newline, no empty line before it.
```json
{
"plugins": [
"stylelint-scss"
],
"rules": {
"at-rule-empty-line-before": [
"always", {
"ignoreAtRules": [ "else" ]
}
],
"at-rule-name-space-after": "always",
"block-opening-brace-space-before": "always",
"block-closing-brace-newline-after": "always",
"at-else-empty-line-before": "never"
}
}
```
This code is considered **valid**:
```scss
@if {
// ...
}
@else {
// ...
}
```
This code is considered **non-valid**:
```scss
@if {
// ...
}
@else {
// ...
}
```

147
node_modules/stylelint-scss/package.json generated vendored Normal file
View File

@@ -0,0 +1,147 @@
{
"_args": [
[
"stylelint-scss@^1.4.1",
"/Users/pmarsceill/_projects/just-the-docs/node_modules/stylelint-config-primer"
]
],
"_from": "stylelint-scss@>=1.4.1 <2.0.0",
"_id": "stylelint-scss@1.4.3",
"_inCache": true,
"_installable": true,
"_location": "/stylelint-scss",
"_nodeVersion": "4.4.0",
"_npmOperationalInternal": {
"host": "packages-12-west.internal.npmjs.com",
"tmp": "tmp/stylelint-scss-1.4.3.tgz_1487496594851_0.1983909138944"
},
"_npmUser": {
"email": "dryoma-npm@yandex.ru",
"name": "dryoma"
},
"_npmVersion": "3.8.1",
"_phantomChildren": {},
"_requested": {
"name": "stylelint-scss",
"raw": "stylelint-scss@^1.4.1",
"rawSpec": "^1.4.1",
"scope": null,
"spec": ">=1.4.1 <2.0.0",
"type": "range"
},
"_requiredBy": [
"/stylelint-config-primer"
],
"_resolved": "https://registry.npmjs.org/stylelint-scss/-/stylelint-scss-1.4.3.tgz",
"_shasum": "6069ddba951345514ad6abcc6beed7d32f1c799d",
"_shrinkwrap": null,
"_spec": "stylelint-scss@^1.4.1",
"_where": "/Users/pmarsceill/_projects/just-the-docs/node_modules/stylelint-config-primer",
"author": {
"name": "Krister Kari"
},
"babel": {
"presets": [
"es2015"
]
},
"bugs": {
"url": "https://github.com/kristerkari/stylelint-scss/issues"
},
"dependencies": {
"lodash": "^4.11.1",
"postcss-media-query-parser": "^0.2.3",
"postcss-resolve-nested-selector": "^0.1.1",
"postcss-selector-parser": "^2.0.0",
"postcss-value-parser": "^3.3.0",
"stylelint": "^7.0.3"
},
"description": "A collection of SCSS specific rules for stylelint",
"devDependencies": {
"babel-cli": "^6.14.0",
"babel-preset-es2015": "^6.14.0",
"babel-register": "^6.14.0",
"coveralls": "^2.11.14",
"eslint": "^2.3.0",
"eslint-config-stylelint": "^1.0.0",
"npmpub": "^3.0.3",
"nyc": "^8.3.1",
"postcss": "^5.0.21",
"postcss-scss": "^0.1.7",
"replace": "^0.3.0",
"request": "^2.72.0",
"rimraf": "^2.5.2",
"semver": "^5.1.0",
"stylelint-test-rule-tape": "^0.2.0",
"table": "3.7.9",
"tap-spec": "^4.1.1",
"tape": "^4.6.0"
},
"directories": {},
"dist": {
"shasum": "6069ddba951345514ad6abcc6beed7d32f1c799d",
"tarball": "https://registry.npmjs.org/stylelint-scss/-/stylelint-scss-1.4.3.tgz"
},
"engines": {
"node": ">=4.2.1"
},
"eslintConfig": {
"extends": "stylelint",
"rules": {
"arrow-spacing": 2,
"no-var": 2,
"object-shorthand": 2,
"prefer-const": 2,
"template-curly-spacing": 2
}
},
"files": [
"!**/__tests__",
"dist",
"docs",
"src/**/README.md"
],
"gitHead": "483052e9f29f79218b6a48a9171d5c17aeefc57b",
"homepage": "https://github.com/kristerkari/stylelint-scss#readme",
"keywords": [
"css",
"csslint",
"lint",
"linter",
"stylelint",
"stylelint-plugin"
],
"license": "MIT",
"main": "dist/index.js",
"maintainers": [
{
"name": "dryoma",
"email": "dryoma-npm@yandex.ru"
},
{
"name": "kristerkari",
"email": "krister.kari@webtehdas.fi"
}
],
"name": "stylelint-scss",
"optionalDependencies": {},
"readme": "ERROR: No README data found!",
"repository": {
"type": "git",
"url": "git+https://github.com/kristerkari/stylelint-scss.git"
},
"scripts": {
"build": "babel src --out-dir dist",
"coveralls": "nyc report --reporter=text-lcov | coveralls",
"lint": "eslint . --ignore-path .gitignore",
"milestone": "node scripts/update-milestone.js",
"prebuild": "rimraf dist",
"prepublish": "npm run build",
"pretest": "npm run lint",
"release": "npmpub",
"test": "nyc tape -r babel-register \"src/**/__tests__/*.js\" | tap-spec",
"test-rule": "node ./scripts/test-rule.js",
"test-util": "node ./scripts/test-util.js"
},
"version": "1.4.3"
}

View File

@@ -0,0 +1,66 @@
# at-else-closing-brace-newline-after
Require or disallow a newline after the closing brace of `@else` statements.
```scss
@if (@a == 0) {
} @else if (@a == 1){ }
@else { }
/**
* The newline after these braces */
```
This rule might have conflicts with stylelint's core rule [`block-closing-brace-newline-after`](http://stylelint.io/user-guide/rules/block-closing-brace-newline-after/) if it doesn't have `"ignoreAtRules": ["else"]` in a `.stylelintrc` config file. That's because an `@else { ... }` statement can be successfully parsed as an at-rule with a block. You might also want to set `"ignoreAtRules": ["else"]` for another stylelint's core rule - [`at-rule-empty-line-before`](http://stylelint.io/user-guide/rules/at-rule-empty-line-before/) that could be forcing empty lines before at-rules (including `@else`s that follow `@if`s or other `@else`s).
This rule doesn't have usual `"always"` and `"never"` main option values, because if you don't need special behavior for `@if` and `@else` you could just use [`block-closing-brace-newline-after`](http://stylelint.io/user-guide/rules/block-closing-brace-newline-after/) set to `"always"` or any other value.
## Options
`string`: `"always-last-in-chain"`
### `"always-last-in-chain"`
There *must always* be a newline after the closing brace of `@else` that is the last statement in a conditional statement chain (i.e. has no `@else` right after it). If it's not, there *must not* be a newline.
The following patterns are considered warnings:
```scss
a {
@if ($x == 1) {
// ...
} @else {
// ...
} width: 10px; // No @else after, so should have a newline
}
@if ($x == 1) {
// ...
} @else if { } // Has @else after it, so shouldn't have a newline
@else { }
```
The following patterns are *not* considered warnings:
```scss
a {
@if ($x == 1) {} @else {}
width: 10px;
}
a {
@if ($x == 1) {
// ...
} @else if {
// ...
} @else {}
width: 10px;
}
a {
@if ($x == 1) { } @else if { }@else { }
width: 10px;
}
```

View File

@@ -0,0 +1,129 @@
# at-else-closing-brace-space-after
Require a single space or disallow whitespace after the closing brace of `@else` statements.
```scss
@if ($a == 0) { }
@else if ($x == 2) { }
/**
* The space after this brace */
```
This rule might have conflicts with stylelint's core [`block-closing-brace-space-after`](http://stylelint.io/user-guide/rules/block-closing-brace-space-after/) rule if the latter is set up in your `.stylelintrc` config file.
## Options
`string`: `"always-intermediate"|"never-intermediate"`
### `"always-intermediate"`
There *must always* be a single space after the closing brace of `@else` that is not the last statement in a conditional statement chain (i.e. does have another `@else` right after it).
The following patterns are considered warnings:
```scss
@if ($x == 1) {
// ...
} @else if ($x == 2) {
// ...
}@else {}
@if ($x == 1) {
// ...
} @else if ($x == 2) {
// ...
}
@else { }
// `@else if` has a space and a newline after the closing brace
@if ($x == 1) {
// ...
} @else if ($x == 2) {
// ...
}
@else { }
@if ($x == 1) {
// ...
} @else if ($x == 2) {
// ...
} @else { } // Two spaces
```
The following patterns are *not* considered warnings:
```scss
@if ($x == 1) {
// ...
} @else if ($x == 2) {
// ...
} @else {}
a {
@if ($x == 1) {
// ...
} @else ($x == 2) {
// ...
}
width: 10px;
}
@if ($x == 1) { } @else if ($x == 2) {
// ...
} @include x;
@if ($x == 1) {
// ...
} @else if ($x == 2) {
// ...
} @include x;
```
### `"never-intermediate"`
There *must never* be a whitespace after the closing brace of `@else` that is not the last statement in a conditional statement chain (i.e. does have another `@else` right after it).
The following patterns are considered warnings:
```scss
@if ($x == 1) {
// ...
} @else if ($x == 2) {
// ...
} @else {}
@if ($x == 1) {
// ...
} @else if ($x == 2) {
// ...
}
@else { }
```
The following patterns are *not* considered warnings:
```scss
@if ($x == 1) {
// ...
}@else {}
a {
@if ($x == 1) {
// ...
} @else if ($x == 2) {
// ...
}
width: 10px;
}
@if ($x == 1) { } @else if ($x == 2) {
// ...
}@include x;
@if ($x == 1) {
// ...
} @else if ($x == 2) {
// ...
} @include x;
```

View File

@@ -0,0 +1,63 @@
# at-else-empty-line-before
Require an empty line or disallow empty lines before `@`-else.
```scss
@if ($a == 0) { }
/* ← */
@else if ($x == 2) { }
/**
* This empty line */
```
`@if` and `@else` statements might need to have different behavior than all the other at-rules. For that you might need to set `"ignoreAtRules": ["else"]` for stylelint's core rule [`at-rule-empty-line-before`](http://stylelint.io/user-guide/rules/at-rule-empty-line-before/). But that would make you unable to disallow empty lines before `@else` while forcing it to be on a new line. This rule is designed to solve exactly that.
## Options
`string`: `"never"`
There is no `"always"`, `"always-single-line"` options, because for such cases stylelint's `at-rule-empty-line-before` would work.
### `"never"`
There *must never* be an empty line before `@else` statements.
The following patterns are considered warnings:
```scss
@if ($x == 1) {
// ...
}
@else {}
```
```scss
@if ($x == 1) {
// ...
} @else if ($x == 2) {
// ...
}
@else { }
```
The following patterns are *not* considered warnings:
```scss
@if ($x == 1) {
// ...
} @else if ($x == 2) {
// ...
} @else {}
a {
@if ($x == 1) {
// ...
}
@else ($x == 2) {
// ...
}
}
```

View File

@@ -0,0 +1,49 @@
# at-extend-no-missing-placeholder
Disallow at-extends (`@extend`) with missing placeholders.
Using a class selector with the `@extend` directive usually results in more generated CSS than when using a placeholder selector. Furthermore, Sass specifically introduced placeholder selectors in order to be used with `@extend`.
See [Mastering Sass extends and placeholders](http://8gramgorilla.com/mastering-sass-extends-and-placeholders/).
```scss
.foo {
@extend %bar
//
// This is a placeholder selector
}
```
The following patterns are considered warnings:
```scss
p {
@extend .some-class;
}
```
```scss
p {
@extend #some-identifer;
}
```
```scss
p {
@extend .blah-#{$dynamically_generated_name};
}
```
The following patterns are *not* considered warnings:
```scss
p {
@extend %placeholder;
}
```
```scss
p {
@extend #{$dynamically_generated_placeholder_name};
}
```

View File

@@ -0,0 +1,29 @@
# at-function-pattern
Specify a pattern for Sass/SCSS-like function names.
```scss
@function grid-width($n) {
/** ↑
* The pattern of this */
```
## Options
`regex` or `string`
A string will be translated into a RegExp like so `new RegExp(yourString)` — so be sure to escape properly.
### E.g. `/foo-.+/`
The following patterns are considered warnings:
```scss
@function boo-bar ($n) {
```
The following patterns are *not* considered warnings:
```scss
@function foo-bar ($n){
```

View File

@@ -0,0 +1,53 @@
# at-if-closing-brace-newline-after
Require or disallow a newline after the closing brace of `@if` statements.
```scss
@if ($a == 0) { }
/**
* The newline after this brace */
```
This rule might have conflicts with stylelint's core rule [`block-closing-brace-newline-after`](http://stylelint.io/user-guide/rules/block-closing-brace-newline-after/) if it doesn't have `"ignoreAtRules": ["if"]` in a `.stylelintrc` config file. That's because an `@if { ... }` statement can be successfully parsed as an at-rule with a block. You might also want to set `"ignoreAtRules": ["else"]` for another stylelint's core rule - [`at-rule-empty-line-before`](http://stylelint.io/user-guide/rules/at-rule-empty-line-before/) that could be forcing empty lines before at-rules (including `@else`s that follow `@if`s or other `@else`s).
This rule doesn't have usual `"always"` and `"never"` main option values, because if you don't need special behavior for `@if` and `@else` you could just use [`block-closing-brace-newline-after`](http://stylelint.io/user-guide/rules/block-closing-brace-newline-after/) set to `"always"` or any other value.
## Options
`string`: `"always-last-in-chain"`
### `"always-last-in-chain"`
There *must always* be a newline after the closing brace of `@if` that is the last statement in a conditional statement chain (i.e. has no `@else` right after it). If it's not, there *must not* be a newline.
The following patterns are considered warnings:
```scss
a {
@if ($x == 1) {
// ...
} width: 10px; // No @else - should have a newline
}
@if ($x == 1) {
// ...
} // Has @else - shouldn't have a newline
@else { }
```
The following patterns are *not* considered warnings:
```scss
a {
@if ($x == 1) {}
width: 10px;
}
@if ($x == 1) {
// ...
} @else {} // Has @else, so no newline needed
@if ($x == 1) { }@else { }
```

View File

@@ -0,0 +1,98 @@
# at-if-closing-brace-space-after
Require a single space or disallow whitespace after the closing brace of `@if` statements.
```scss
@if ($a == 0) { }
/**
* The space after this brace */
```
This rule might have conflicts with stylelint's core [`block-closing-brace-space-after`](http://stylelint.io/user-guide/rules/block-closing-brace-space-after/) rule if the latter is set up in your `.stylelintrc` config file.
## Options
`string`: `"always-intermediate"|"never-intermediate"`
### `"always-intermediate"`
There *must always* be a single space after the closing brace of `@if` that is not the last statement in a conditional statement chain (i.e. does have `@else` right after it).
The following patterns are considered warnings:
```scss
@if ($x == 1) {
// ...
}@else {}
@if ($x == 1) {
// ...
}
@else { }
// `@if` has a space and a newline after the closing brace
@if ($x == 1) {
// ...
}
@else { }
@if ($x == 1) {
// ...
} @else { } // Two spaces
```
The following patterns are *not* considered warnings:
```scss
@if ($x == 1) {
// ...
} @else {}
a {
@if ($x == 1) {}
width: 10px;
}
@if ($x == 1) { }@include x;
@if ($x == 1) {
// ...
} @include x;
```
### `"never-intermediate"`
There *must never* be a whitespace after the closing brace of `@if` that is not the last statement in a conditional statement chain (i.e. does have `@else` right after it).
The following patterns are considered warnings:
```scss
@if ($x == 1) {
// ...
} @else {}
@if ($x == 1) {
// ...
}
@else { }
```
The following patterns are *not* considered warnings:
```scss
@if ($x == 1) {
// ...
}@else {}
a {
@if ($x == 1) {}
width: 10px;
}
@if ($x == 1) { }@include x;
@if ($x == 1) {
// ...
} @include x;
```

View File

@@ -0,0 +1,76 @@
# at-import-no-partial-extension
Disallow file extensions in partial names in `@import`.
**Deprecated. Use [`at-import-partial-extension-blacklist`](/src/rules/at-import-partial-extension-blacklist/README.md) or [`at-import-partial-extension-whitelist`](/src/rules/at-import-partial-extension-whitelist/README.md) instead**
```scss
@import "path/to/file.scss"
/** ↑
* Disallow this */
```
The rule ignores [cases](http://sass-lang.com/documentation/file.SASS_REFERENCE.html#import) when Sass considers an `@import` command just a plain CSS import:
* If the files extension is `.css`.
* If the filename begins with `http://` (or any other protocol).
* If the filename is a `url()`.
* If the `@import` has any media queries.
The following patterns are considered warnings:
```scss
@import "foo.scss";
```
```scss
@import "path/fff.less";
```
```scss
@import "path\\fff.supa";
```
```scss
@import "df/fff", '1.scss';
```
The following patterns are *not* considered warnings:
```scss
@import "path/fff";
```
```scss
@import url("path/_file.css"); /* has url(), so doesn't count as a partial @import */
```
```scss
@import "file.css"; /* Has ".css" extension, so doesn't count as a partial @import */
```
```scss
/* Both are URIs, so don't count as partial @imports */
@import "http://_file.scss";
@import "//_file.scss";
```
```scss
@import "file.scss" screen; /* Has a media query, so doesn't count as a partial @import */
```
## Optional Options
### `ignoreExtensions: [ string or regexp ]`
An array of extensions to ignore, elements *don't need the dot at the start*. If an element is a string, only extensions that match that string are ignored. If an element is a regular expression, then extensions are tested against it and ignored if the test is successful.
For example, with `ignoreExtensions: [ "scss", /^my/ ] ]`, the following are no longer warnings:
```scss
@import "path/fff.scss";
```
```scss
@import "path/fff.my01";
```

View File

@@ -0,0 +1,59 @@
# at-import-no-partial-leading-underscore
Disallow leading underscore in partial names in `@import`.
```scss
@import "path/to/_file"
/** ↑
* Disallow this */
```
The rule ignores [cases](http://sass-lang.com/documentation/file.SASS_REFERENCE.html#import) when Sass considers an `@import` command just a plain CSS import:
* If the files extension is `.css`.
* If the filename begins with `http://` (or any other protocol).
* If the filename is a `url()`.
* If the `@import` has any media queries.
The following patterns are considered warnings:
```scss
@import "_foo";
```
```scss
@import "path/_fff";
```
```scss
@import "path\\_fff"; /* Windows delimiters */
```
```scss
@import "df/fff", '_1.scss';
```
The following patterns are *not* considered warnings:
```scss
@import "_path/fff"; /* underscore in a directory name, not in a partial name */
```
```scss
@import url("path/_file.css"); /* has url(), so doesn't count as a partial @import */
```
```scss
@import "_file.css"; /* Has ".css" extension, so doesn't count as a partial @import */
```
```scss
/* Both are URIs, so don't count as partial @imports */
@import "http://_file.scss";
@import "//_file.scss";
```
```scss
@import "_file.scss" screen; /* Has a media query, so doesn't count as a partial @import */
```

View File

@@ -0,0 +1,70 @@
# at-import-partial-extension-blacklist
Specify blacklist of disallowed file extensions for partial names in `@import` commands.
```scss
@import "file.scss"
/** ↑
* Blacklist of these */
```
The rule ignores [cases](http://sass-lang.com/documentation/file.SASS_REFERENCE.html#import) when Sass considers an `@import` command just a plain CSS import:
* If the files extension is `.css`.
* If the filename begins with `http://` (or any other protocol).
* If the filename is a `url()`.
* If the `@import` has any media queries.
## Options
`array`: `["array", "of", "extensions"]`
Each value is either a string or a regexp.
Given:
```js
["scss", /less/]
```
The following patterns are considered warnings:
```scss
@import "foo.scss";
```
```scss
@import "path/fff.less";
```
```scss
@import "path\\fff.ruthless";
```
```scss
@import "df/fff", '1.SCSS';
```
The following patterns are *not* considered warnings:
```scss
@import "path/fff";
```
```scss
@import url("path/_file.css"); /* has url(), so doesn't count as a partial @import */
```
```scss
@import "file.css"; /* Has ".css" extension, so doesn't count as a partial @import */
```
```scss
/* Both are URIs, so don't count as partial @imports */
@import "http://_file.scss";
@import "//_file.scss";
```
```scss
@import "file.scss" screen; /* Has a media query, so doesn't count as a partial @import */
```

View File

@@ -0,0 +1,78 @@
# at-import-partial-extension-whitelist
Specify whitelist of allowed file extensions for partial names in `@import` commands.
```scss
@import "file.scss"
/** ↑
* Whitelist of these */
```
The rule ignores [cases](http://sass-lang.com/documentation/file.SASS_REFERENCE.html#import) when Sass considers an `@import` command just a plain CSS import:
* If the files extension is `.css`.
* If the filename begins with `http://` (or any other protocol).
* If the filename is a `url()`.
* If the `@import` has any media queries.
## Options
`array`: `["array", "of", "extensions"]`
Each value is either a string or a regexp.
Given:
```js
["scss", /less/]
```
The following patterns are considered warnings:
```scss
@import "file.sass";
```
```scss
@import "file1", "file.stylus";
```
The following patterns are *not* considered warnings:
```scss
@import "path/fff";
```
```scss
@import "foo.scss";
```
```scss
@import "path/fff.less";
```
```scss
@import "path\\fff.ruthless";
```
```scss
@import "df/fff", '1.SCSS';
```
```scss
@import url("path/_file.css"); /* has url(), so doesn't count as a partial @import */
```
```scss
@import "file.css"; /* Has ".css" extension, so doesn't count as a partial @import */
```
```scss
/* Both are URIs, so don't count as partial @imports */
@import "http://_file.scss";
@import "//_file.scss";
```
```scss
@import "file.scss" screen; /* Has a media query, so doesn't count as a partial @import */
```

View File

@@ -0,0 +1,45 @@
# at-mixin-argumentless-call-parentheses
Require or disallow parentheses in argumentless `@mixin` calls.
```scss
@include mixin-name() {
/** ↑
* Such mixin calls */
```
## Options
`string`: `"always"|"never"`
### `"always"`
There *must always* be parentheses in mixin calls, even if no arguments are passed.
The following patterns are considered warnings:
```scss
@include mixin-name;
```
The following patterns are *not* considered warnings:
```scss
@include mixin-name();
```
### `"never"`
There *must never* be parentheses when calling a mixin without arguments.
The following patterns are considered warnings:
```scss
@include mixin-name();
```
The following patterns are *not* considered warnings:
```scss
@include mixin-name;
```

View File

@@ -0,0 +1,23 @@
# at-mixin-no-argumentless-call-parentheses
**Deprecated. Use [`at-mixin-argumentless-call-parentheses`](../at-mixin-argumentless-call-parentheses/README.md) instead.**
Disallow parentheses in argumentless `@mixin` calls.
```scss
@include mixin-name() {
/** ↑
* Such mixin calls */
```
The following patterns are considered warnings:
```scss
@include mixin-name() {
```
The following patterns are *not* considered warnings:
```scss
@include mixin-name {
```

View File

@@ -0,0 +1,29 @@
# at-mixin-pattern
Specify a pattern for Sass/SCSS-like mixin names.
```scss
@mixin complex-object ($items: 10) {
/** ↑
* The pattern of this */
```
## Options
`regex` or `string`
A string will be translated into a RegExp like so `new RegExp(yourString)` so be sure to escape properly.
### E.g. `/foo-.+/`
The following patterns are considered warnings:
```scss
@mixin boo-bar {
```
The following patterns are *not* considered warnings:
```scss
@mixin foo-bar {
```

View File

@@ -0,0 +1,68 @@
# declaration-nested-properties-no-divided-groups
Disallow nested properties of the same "namespace" be divided into multiple groups.
```scss
/* Such groups: */
font: { /* `font` is a "namespace" */
size: 16px;
weight: 700;
}
```
A "namespace" is everything before the first `-` in property names, e.g. `margin` in `margin-bottom`. It is the "namespace" that is used as a root identifier for a nested properties group (`font` in the example above).
[Sass official docs on nested properties](http://sass-lang.com/documentation/file.SASS_REFERENCE.html#nested_properties).
The following patterns are considered warnings:
```scss
a {
background: url(img.png) center {
size: auto;
}
background: {
repeat: no-repeat;
}
}
```
The following patterns are *not* considered warnings:
```scss
a {
background: url(img.png) center {
size: auto;
}
background-repeat: no-repeat;
}
```
```scss
a {
background: url(img.png) center no-repeat {
color: red;
}
margin: 10px {
left: 1px;
}
}
```
```scss
a {
background: url(img.png) center {
size: auto;
}
background :red {
repeat: no-repeat;
}
}
/* There is no space after the colon in `background :red` so it is considered A SELECTOR and is compiled into:
a background :red {
color: blue;
}
*/
```

View File

@@ -0,0 +1,153 @@
# declaration-nested-properties
Require or disallow properties with `-` in their names to be in a form of a nested group.
```scss
/* This is properties nesting: */
font: {
size: 16px;
weight: 700;
}
```
[Sass official docs on nested properties](http://sass-lang.com/documentation/file.SASS_REFERENCE.html#nested_properties).
## Options
`string`: `"always"|"never"`
### `"always"`
*Every property* with a `-` in its name *must be* inside a nested property group.
Property names with browser prefixes are ignored with `always`.
The following patterns are considered warnings:
```scss
a {
margin-left: 10px;
}
```
```scss
a {
font: {
size: 10px;
}
font-weight: 400; // This one should be nested either
}
```
The following patterns are *not* considered warnings:
```scss
a {
margin: {
left: 10px;
}
}
```
```scss
a {
font: 10px/1.1 Arial {
weight: bold;
}
}
```
```scss
a {
-webkit-box-sizing: border-box;
-webkit-box-shadow: 1px 0 0 red;
}
```
### `"never"`
Nested properties are not allowed.
The following patterns are considered warnings:
```scss
a {
margin: {
left: 10px;
}
}
```
```scss
a {
background: red {
repeat: no-repeat;
}
}
```
The following patterns are *not* considered warnings:
```scss
a {
background-color: red;
background-repeat: no-repeat;
}
```
```scss
a {
background:red {
color: blue;
}
}
/* There is no space after the colon in `background:red` so it is considered A SELECTOR and is compiled into:
a background:red {
color: blue;
}
*/
```
## Optional options
### `except: ["only-of-namespace"]`
*Works only* with `"always"` and reverses its effect for a property if it is the only one with the corresponding "namespace" (e.g. `margin` in `margin-top`) in a ruleset.
The following patterns are considered warnings:
```scss
a {
font-family: Arial, sans-serif;
font-size: 10px;
}
```
```scss
a {
font: {
size: 10px; // Only one rule nested (reverse "always")
}
}
```
```scss
a {
font: {
size: 10px; // Prop 1, ...
}
font-weight: 400; // ... prop 2, so must be nested as well
}
```
The following patterns are *not* considered warnings:
```scss
a {
position: absolute;
background-color: red; // no other `background-` properties in a ruleset
}
```

View File

@@ -0,0 +1,77 @@
# dollar-variable-colon-newline-after
Require a newline after the colon in `$`-variable declarations.
```scss
$box-shadow:
0 0 0 1px #5b9dd9,
0 0 2px 1px rgba(30, 140, 190, 0.8);
/* ↑ */
/** ↑
* The newline after this colon */
```
## Options
`string`: `"always"|"always-multi-line"`
### `"always"`
There *must always* be a newline after the colon.
The following patterns are considered warnings:
```scss
$var:100px;
```
```scss
a { $var:100px; }
```
```scss
$var: 100px;
```
The following patterns are *not* considered warnings:
```scss
$var:
100px;
```
```scss
a {
$var:
100px;
}
```
### `"always-multi-line"`
There *must always* be a newline after the colon *if the variable value is multi-line*.
The following patterns are considered warnings:
```scss
$box-shadow: 0 0 0 1px #5b9dd9,
0 0 2px 1px rgba(30, 140, 190, 0.8);
```
The following patterns are *not* considered warnings:
```scss
$box-shadow:
0 0 0 1px #5b9dd9,
0 0 2px 1px rgba(30, 140, 190, 0.8);
```
```scss
$box-shadow:
0 0 0 1px #5b9dd9, 0 0 2px 1px rgba(30, 140, 190, 0.8);
// The VALUE is single-line, so a newline after the colon is ignored by this rule.
```
```scss
$var: 100px;
```

View File

@@ -0,0 +1,103 @@
# dollar-variable-colon-space-after
Require a single space or disallow whitespace after the colon in `$`-variable declarations.
```scss
$variable: 10px;
/** ↑
* The space after this colon */
```
## Options
`string`: `"always"|"never"|"always-single-line"`
### `"always"`
There *must always* be a single space after the colon.
The following patterns are considered warnings:
```scss
a { $var :10px }
```
```scss
$var:10px;
```
```scss
$var:
10px;
// a newline is not a space
```
The following patterns are *not* considered warnings:
```scss
a { $var : 10px }
```
```scss
$var: 10px;
```
### `"never"`
There *must never* be whitespace after the colon.
The following patterns are considered warnings:
```scss
$var: 10px;
```
```scss
$var:
10px;
```
```scss
a { $var :10px }
```
The following patterns are *not* considered warnings:
```scss
$var :10px;
```
```scss
a { $var:10px }
```
### `"always-single-line"`
There *must always* be a single space after the colon *if the variable value is single-line*.
The following patterns are considered warnings:
```scss
$box-shadow:0 0 0 1px #5b9dd9, 0 0 2px 1px rgba(30, 140, 190, 0.8);
```
The following patterns are *not* considered warnings:
```scss
a {
$box-shadow: 0 0 0 1px #5b9dd9, 0 0 2px 1px rgba(30, 140, 190, 0.8);
}
```
```scss
$box-shadow:
0 0 0 1px #5b9dd9,
0 0 2px 1px rgba(30, 140, 190, 0.8);
```
```scss
a {
$box-shadow:0 0 0 1px #5b9dd9,
0 0 2px 1px rgba(30, 140, 190, 0.8);
}
```

View File

@@ -0,0 +1,71 @@
# dollar-variable-colon-space-before
Require a single space or disallow whitespace before the colon in `$`-variable declarations.
```scss
$variable: 10px;
/** ↑
* The space before this colon */
```
## Options
`string`: `"always"|"never"
### `"always"`
There *must always* be a single space before the colon.
The following patterns are considered warnings:
```scss
a { $var: 10px }
```
```scss
$var:10px;
```
```scss
$var :10px;
```
```scss
$var
:10px;
```
The following patterns are *not* considered warnings:
```scss
a { $var : 10px }
```
```scss
$var :10px;
```
### `"never"`
There *must never* be whitespace before the colon.
The following patterns are considered warnings:
```scss
$var :10px;
```
```scss
a { $var
:10px }
```
The following patterns are *not* considered warnings:
```scss
$var:10px;
```
```scss
a { $var: 10px }
```

View File

@@ -0,0 +1,199 @@
# dollar-variable-empty-line-before
Require an empty line or disallow empty lines before `$`-variable declarations.
If the `$`-variable declaration is the first declaration in a file, it's ignored.
```scss
/* ← */
$width: 10px;
/**
* This empty line */
```
## Options
`string`: `"always"|"never"`
### `"always"`
There *must always* be one empty line before a `$`-variable declaration.
The following patterns are considered warnings:
```scss
@import '1.css';
$var2: 200px;
```
```scss
a {
$var: 1;
}
```
The following patterns are *not* considered warnings:
```scss
$var: 100px; // The first declaration in a stylesheet
```
```scss
a { color: red; }
$var: 1;
```
### `"never"`
There *must never* be an empty line before a `$`-variable declaration.
The following patterns are considered warnings:
```scss
a { color: red; }
$var: 1;
```
The following patterns are *not* considered warnings:
```scss
$var: 100px;
$var2: 200px;
```
```scss
a {
width: auto;
}
$var: 1;
```
## Optional secondary options
### `except: ["first-nested", "after-comment", "after-dollar-variable"]`
### `"first-nested"`
Reverse the primary option for a `$`-variable declaration if it's the first child of its parent.
For example, with `"always"`:
The following patterns are considered warnings:
```scss
a {
$var: 1;
color: red;
}
b {
color: red;
$var: 1;
}
```
The following patterns are *not* considered warnings:
```scss
a {
$var: 1;
color: red;
}
b {
color: red;
$var: 1;
}
```
### `"after-comment"`
Reverse the primary option for `$`-variable declarations that go after comments.
For example, with `"always"`:
The following patterns are considered warnings:
```scss
a {
// comment
$var: 1;
}
b {
/* comment */
$var: 1;
}
```
The following patterns are *not* considered warnings:
```scss
a {
// comment
$var: 1;
}
```
### `"after-dollar-variable"`
Reverse the primary option for `$`-variable declarations that go right after another `$`-variable declaration.
For example, with `"always"`:
The following patterns are considered warnings:
```scss
a {
$var: 1; // this one is ok
$var1: 2; // and this one shouldn't have a preceding empty line
}
```
The following patterns are *not* considered warnings:
```scss
a {
$var: 1;
$var1: 2;
}
```
### `ignore: ["after-comment", "inside-single-line-block"]`
### `"after-comment"`
Ignore `$`-variables that go after a comment.
For example, with `"always"`:
The following patterns are *not* considered warnings:
```scss
// comment
$var: 1
/* comment */
$var2: 1;
```
### `"inside-single-line-block"`
Ignore `$`-variables that are inside single-line blocks.
For example, with `"always"`:
The following patterns are *not* considered warnings:
```scss
a { $var: 10; }
```

View File

@@ -0,0 +1,111 @@
# dollar-variable-no-missing-interpolation
Disallow Sass variables that are used without interpolation with CSS features that use custom identifiers.
```scss
.class {
$var: "my-anim";
animation-name: $var;
// ↑
// This variable needs to be interpolated
// because its value is a string
}
```
Sass variables that contain a custom identifier as a string always require interpolation when used. Some CSS [at-rules](https://css-tricks.com/the-at-rules-of-css/) require variable interpolation even when the custom identifier value is not a string.
For example, your CSS animation could look like this:
```scss
animation: myAnim 5s;
```
When you store your custom identifier as string in a Sass variable...
```scss
$myVar: "myAnim";
```
...then you need to make sure that the variable is interpolated when it gets used:
```scss
animation: #{$myVar} 5s;
```
If you do not interpolate the variable, Sass will compile your animation name to a string, producing invalid CSS:
```scss
animation: "myAnim" 5s;
```
This rule can only check for variables that are defined inside the same file where they are used.
The following patterns are considered warnings:
```scss
$var: my-anim;
@keyframes $var {}
```
```scss
$var: "circled-digits";
@counter-style $var {
system: fixed;
symbols: ;
suffix: ' ';
speak-as: numbers;
}
```
```scss
$var: "my-counter";
body {
counter-reset: $var;
}
```
```scss
$var: "my-anim";
@supports (animation-name: $var) {
@keyframes {}
}
```
The following patterns are *not* considered warnings:
```scss
$var: my-anim;
@keyframes #{$var} {}
```
```scss
$var: circled-digits;
@counter-style #{$var} {
system: fixed;
symbols: ;
suffix: ' ';
speak-as: numbers;
}
```
```scss
$var: my-counter;
body {
counter-reset: $var;
}
```
```scss
$var: my-anim;
@supports (animation-name: $var) {
@keyframes {}
}
```

View File

@@ -0,0 +1,69 @@
# dollar-variable-pattern
Specify a pattern for Sass-like variables.
```scss
a { $foo: 1px; }
/** ↑
* The pattern of this */
```
## Options
`regex` or `string`
A string will be translated into a RegExp like so `new RegExp(yourString)` so be sure to escape properly.
### E.g. `/foo-.+/`
The following patterns are considered warnings:
```scss
a { $boo-bar: 0; }
```
The following patterns are *not* considered warnings:
```scss
a { $foo-bar: 0; }
```
## Optional Options
### `ignore: "local"|"global"`
#### `"local"`
Makes this rule ignore local variables (variables defined inside a rule/mixin/function, etc.).
For example, with `/^foo-/`:
The following patterns are *not* considered warnings:
```scss
$foo-name00: 10px;
```
```scss
a {
$bar-name01: 10px;
}
```
#### `"global"`
Makes this rule ignore global variables (variables defined in the stylesheet root).
For example, with `/^foo-/`:
The following patterns are *not* considered warnings:
```scss
$bar-name01: 10px;
```
```scss
a {
$foo-name02: 10px;
}
```

View File

@@ -0,0 +1,149 @@
# double-slash-comment-empty-line-before
Require or disallow an empty line before `//`-comments.
```scss
a {}
/* ← */
// comment /* ↑ */
/** ↑
* This line */
```
This rule only works with SCSS-like [single-line comments](http://sass-lang.com/documentation/file.SASS_REFERENCE.html#comments) and ignores:
* comments that are the very first nodes in a file;
* CSS comments (`/* */`);
* comments that are on the same line as some non-comment code (inline comments).
## Options
`string`: `"always"|"never"`
### `"always"`
There *must always* be an empty line before `//`-comments.
The following patterns are considered warnings:
```scss
a {}
// comment
```
The following patterns are *not* considered warnings:
```scss
a {}
// comment
```
```scss
a {} // comment
```
### `"never"`
There *must never* be an empty line before `//`-comments.
The following patterns are considered warnings:
```scss
a {}
// comment
```
The following patterns are *not* considered warnings:
```scss
a {}
// comment
```
```scss
a {} // comment
```
## Optional options
### `except: ["first-nested"]`
Reverse the primary option for `//`-comments that are nested and the first child of their parent node.
For example, with `"always"`:
The following patterns are considered warnings:
```scss
a {
// comment
color: pink;
}
```
The following patterns are *not* considered warnings:
```scss
a {
// comment
color: pink;
}
```
### `ignore: ["between-comments", "stylelint-commands"]`
#### `"between-comments"`
Don't require an empty line before `//`-comments that are placed after other `//`-comments or CSS comments.
For example, with `"always"`:
The following patterns are *not* considered warnings:
```scss
a {
background: pink;
// comment
// comment
color: #eee;
}
```
```scss
a {
background: pink;
/* comment */
// comment
color: #eee;
}
```
#### `"stylelint-commands"`
Ignore `//`-comments that deliver commands to stylelint, e.g. `// stylelint-disable color-no-hex`.
For example, with `"always"`:
The following patterns are considered warnings:
```scss
a {
background: pink;
// not a stylelint command
color: #eee;
}
```
The following patterns are *not* considered warnings:
```scss
a {
background: pink;
// stylelint-disable color-no-hex
color: pink;
}
```

View File

@@ -0,0 +1,110 @@
# double-slash-comment-inline
Require or disallow `//`-comments to be inline comments.
```scss
a {
width: 10px; // inline-comment
/* ↑
* Such comments */
```
An inline comment in terms of this rule is a comment that is placed on the same line with any other code, either before or after it.
This rule only works with SCSS-like [single-line comments](http://sass-lang.com/documentation/file.SASS_REFERENCE.html#comments) and ignores CSS comments (`/* */`).
## Options
`string`: `"always"|"never"`
### `"always"`
`//`-comments *must always* be inline comments.
The following patterns are considered warnings:
```scss
// comment
a { width: 10px; }
```
```scss
a {
// comment
width: 10px;
}
```
The following patterns are *not* considered warnings:
```scss
a { // comment
width: 10px;
}
```
```scss
a {
width: 10px; // comment
}
```
```scss
a, // comment
b {
width: 10px;
}
```
### `"never"`
`//`-comments *must never* be inline comments.
The following patterns are considered warnings:
```scss
a {
width: 10px; // comment
}
```
```scss
a, // comment
b {
width: 10px;
}
```
The following patterns are *not* considered warnings:
```scss
// comment
a { width: 10px; }
```
```scss
a {
// comment
width: 10px;
}
```
## Optional options
### `ignore: ["stylelint-commands"]`
#### `"stylelint-commands"`
Ignore `//`-comments that deliver commands to stylelint, e.g. `// stylelint-disable color-no-hex`.
For example, with `"always"`:
The following patterns are *not* considered warnings:
```scss
a {
background: pink;
// stylelint-disable color-no-hex
color: pink;
}
```

View File

@@ -0,0 +1,60 @@
# double-slash-comment-whitespace-inside
Require or disallow whitespace after the `//` in `//`-comments
```scss
a {
width: 10px; // inline-comment
/* ↑
* Such whitespace */
```
This rule only works with SCSS-like [single-line comments](http://sass-lang.com/documentation/file.SASS_REFERENCE.html#comments) and ignores CSS comments (`/* */`).
Any number of slases are allowed at the beginning of the comment. So `/// comment` is treated the same way as `// comment`.
Note that a newline is not possible as a whitespace in terms of this rule as `//`-comments are intended to be single-line.
## Options
`string`: `"always"|"never"`
### `"always"`
There *must always* be whitespace after the `//` inside `//`-comments.
The following patterns are considered warnings:
```scss
//comment
```
The following patterns are *not* considered warnings:
```scss
// comment
```
```scss
/// comment
```
### `"never"`
There *must never* be whitespace after the `//` inside `//`-comments.
The following patterns are considered warnings:
```scss
// comment
```
The following patterns are *not* considered warnings:
```scss
//comment
```
```scss
///comment
```

View File

@@ -0,0 +1,86 @@
# media-feature-value-dollar-variable
Require a media feature value be a `$`-variable or disallow `$`-variables in media feature values.
```scss
@media (max-width: $var) { a { color: red; } }
// ↑
// Require or disallow this
}
```
## Options
`string`: `"always"|"never"`
### `"always"`
A media feature value *must consist* of just a single `$`-variable (possibly with inteprolation).
The following patterns are considered warnings:
```scss
@media (max-width: 300px) { b { color: red; } }
```
```scss
@media (max-width: $var + 10px) { b { color: red; } }
```
```scss
@media screen and (max-width: $var), or (min-width: 100px){ b { color: red; } }
```
```scss
@media screen and (max-width: #{$val} + 10px) { a { display: none; } }
```
```scss
@media screen and (max-width: #{$val + $x} ) { a { display: none; } }
```
```scss
@media screen and (min-width: funcName($p)){ b { color: red; } }
```
The following patterns are *not* considered warnings:
```scss
@media ( max-width: $var ) {b { color: red; }}
```
```scss
@media ( max-width: #{$var}) {b { color: red; }}
```
### `"never"`
There *must never* be a `$`-variable in a media feature value. Even as a parameter to a function call.
The following patterns are considered warnings:
```scss
@media screen and (min-width: $var){ b { color: red; } }
```
```scss
@media screen and (min-width: 100px + $var){ b { color: red; } }
```
```scss
@media screen and (min-width: funcName($var)){ b { color: red; } }
```
The following patterns are *not* considered warnings:
```scss
@media screen and (min-width: 100px){ b { color: red; } }
```
```scss
@media screen and (min-width: 100px + 10px){ b { color: red; } }
```
```scss
@media screen and (min-width: funcName(10px)){ b { color: red; } }
```

View File

@@ -0,0 +1,54 @@
# operator-no-newline-after
Disallow linebreaks after Sass operators.
```scss
a { width: 10px + $n; }
/** ↑
* Linebreaks after this */
```
This rule checks math operators (`+`, `-`, `/`, `*`, `%`) and comparison operators (`>`, `<`, `!=`, `==`, `>=`, `<=`).
Not all symbols that correspond to math operators are actually considered operators by Sass. Some of the exceptions are:
* `+` and `-` as signs before values;
* `+` and `-` as signs in [space-delimited lists](http://sass-lang.com/documentation/file.SASS_REFERENCE.html#string_operations);
* `-` as part of [a string](http://sass-lang.com/documentation/file.SASS_REFERENCE.html#string_operations) or [a Sass identifier](http://sass-lang.com/documentation/file.SASS_REFERENCE.html#subtraction), e.g. a variable;
* `/` as a CSS delimiter in property values like `font: 10px/1.2 Arial;` ([read more](http://sass-lang.com/documentation/file.SASS_REFERENCE.html#division-and-slash)).
For more details refer to [Sass official documentation](http://sass-lang.com/documentation/file.SASS_REFERENCE.html). An online Sass compiler - [Sassmeister](http://www.sassmeister.com/) - could also come in handy.
The following patterns are considered warnings:
```scss
a { width: 10 +
1; }
```
```scss
a {
width: 10 +
1;
}
```
The following patterns are *not* considered warnings:
```scss
a {
width: str- // not a math operator, ignored
some;
}
```
```scss
a { width: 10px - 1; }
```
```scss
a {
width: 10px * 1.7 // the newline is not right after the operator
+ 1;
}
```

View File

@@ -0,0 +1,55 @@
# operator-no-newline-before
Disallow linebreaks before Sass operators.
```scss
a { width: 10px
+ $n; }
/** ↑
* Linebreaks before this */
```
This rule checks math operators (`+`, `-`, `/`, `*`, `%`) and comparison operators (`>`, `<`, `!=`, `==`, `>=`, `<=`).
Not all symbols that correspond to math operators are actually considered operators by Sass. Some of the exceptions are:
* `+` and `-` as signs before values;
* `+` and `-` as signs in [space-delimited lists](http://sass-lang.com/documentation/file.SASS_REFERENCE.html#string_operations);
* `-` as part of [a string](http://sass-lang.com/documentation/file.SASS_REFERENCE.html#string_operations) or [a Sass identifier](http://sass-lang.com/documentation/file.SASS_REFERENCE.html#subtraction), e.g. a variable;
* `/` as a CSS delimiter in property values like `font: 10px/1.2 Arial;` ([read more](http://sass-lang.com/documentation/file.SASS_REFERENCE.html#division-and-slash)).
For more details refer to [Sass official documentation](http://sass-lang.com/documentation/file.SASS_REFERENCE.html). An online Sass compiler - [Sassmeister](http://www.sassmeister.com/) - could also come in handy.
The following patterns are considered warnings:
```scss
a { width: 10
+ 1; }
```
```scss
a {
width: 10
+ 1;
}
```
The following patterns are *not* considered warnings:
```scss
a {
width: 10px
-1; // not a math operator, ignored
}
```
```scss
a { width: 10px - 1; }
```
```scss
a {
width: 100px +
$var * 0.5625; // the newline is not right before the operator
}
```

View File

@@ -0,0 +1,100 @@
# operator-no-unspaced
Disallow unspaced operators in Sass operations.
```scss
a { width: 10px*$n; }
/** ↑
* The space around this operator */
```
This rule checks math operators (`+`, `-`, `/`, `*`, `%`) and comparison operators (`>`, `<`, `!=`, `==`, `>=`, `<=`).
Not all symbols that correspond to math operators are actually considered operators by Sass. Some of the exceptions are:
* `+` and `-` as signs before values;
* `+` and `-` as signs in [space-delimited lists](http://sass-lang.com/documentation/file.SASS_REFERENCE.html#string_operations);
* `-` as part of [a string](http://sass-lang.com/documentation/file.SASS_REFERENCE.html#string_operations) or [a Sass identifier](http://sass-lang.com/documentation/file.SASS_REFERENCE.html#subtraction), e.g. a variable;
* `/` as a CSS delimiter in property values like `font: 10px/1.2 Arial;` ([read more](http://sass-lang.com/documentation/file.SASS_REFERENCE.html#division-and-slash)).
For more details refer to [Sass official documentation](http://sass-lang.com/documentation/file.SASS_REFERENCE.html). An online Sass compiler - [Sassmeister](http://www.sassmeister.com/) - could also come in handy.
The following patterns are considered warnings:
```scss
a { width: 10+1; }
```
```scss
a { width: 10+ 1; }
```
```scss
a { width: 10-1; }
```
```scss
a { width: 10px* 1.5; }
```
```scss
@if ($var==10) { ... }
```
```scss
a { width: 10px * 1.5; } // More than one space
```
```scss
a { width: (10) /1; } // Has a value inside parens on one side, so is an operation
```
```scss
// Operations can be inside interpolation in selectors, property names, etc.
.class#{1 +1}name {
color: red;
}
p {
background-#{\"col\" +\"or\"}: red;
}
```
The following patterns are *not* considered warnings:
```scss
a { width: 10 * 1; }
```
```scss
a { width: 10 +1; } // A space-delimited Sass list
```
```scss
// A space-delimited Sass list, in "10px-" "10" is a number, "px-" is a unit
a { width: 10px- 1; }
```
```scss
a { width: 10px/1; } // Compiled as CSS, as in "font: 10px/1 ..."
```
```scss
a { width: (10) /#{1}; } // Has interpolation on one of the sides, so not an operation
```
```scss
a { width: $var-1; } // "$var-1" is a variable name
```
```scss
a { width: "10*1"; } // Inside a string, ignored
```
```scss
// Linebreak will do as a whitespace; indentation before "-" and trailing spaces after "1" are left to the corresponding stylelint rules
a {
width: 1
- a;
}
```

View File

@@ -0,0 +1,69 @@
# partial-no-import
Disallow non-CSS `@import`s in partial files.
```scss
// path/to/_file.scss:
/* ↑ in partial files */
@import "path/to/file.scss"
/*↑ Disallow imports */
```
The rule skips CSS files (doesn't report any `@import`s in them).
The rule also ignores [cases](http://sass-lang.com/documentation/file.SASS_REFERENCE.html#import) when Sass considers an `@import` command just a plain CSS import:
* If the files extension is `.css`.
* If the filename begins with `http://` (or any other protocol).
* If the filename is a `url()`.
* If the `@import` has any media queries.
The following patterns are considered warnings:
```scss
// path/to/_file.scss:
@import "foo.scss";
```
```scss
// path/to/_file.less:
@import "path/fff.less";
```
```scss
// path/to/_file.scss:
@import "path\\fff.supa";
```
The following patterns are *not* considered warnings:
```scss
// path/to/file.scss:
@import "path/fff";
/* @import in a file that is not a partial */
```
```scss
// path/to/_file.scss:
@import url("path/_file.css"); /* has url(), so doesn't count as a partial @import */
```
```scss
// path/to/_file.scss:
@import "file.css"; /* Has ".css" extension, so doesn't count as a partial @import */
```
```scss
// path/to/_file.scss:
@import "http://_file.scss";
@import "//_file.scss";
/* Both are URIs, so don't count as partial @imports */
```
```scss
// path/to/_file.scss:
@import "file.scss" screen; /* Has a media query, so doesn't count as a partial @import */
```

View File

@@ -0,0 +1,57 @@
# percent-placeholder-pattern
Specify a pattern for `%`-placeholders.
```scss
%foobar { display: flex; }
/** ↑
* The pattern of this */
```
## Options
`regex` or `string`
A string will be translated into a RegExp like so `new RegExp(yourString)` so be sure to escape properly.
Nested selectors will be resolved before checking.
The selector value *after `%`* will be checked. No need to include `%` in your pattern.
### E.g. `/^foo-[a-z]+$/`
The following patterns are considered warnings:
```scss
%myriad { display: flex; }
```
```scss
%foo-bar {
&-supa { display: flex; } /* %foo-bar matches, but %foo-bar-supa doesn't */
}
```
```scss
%foo- { /* %foo- on the 1st leves doesn't match */
&bar { display: flex; }
}
```
The following patterns are *not* considered warnings:
```scss
%foo-aimp { display: flex; }
```
```scss
%foo-bar {
&lignt { display: flex; }
}
```
```scss
.p {
@extend %mathy; // The rule only checks placeholder definitions
}
```

View File

@@ -0,0 +1,61 @@
# selector-no-redundant-nesting-selector
Disallow redundant nesting selectors (`&`).
```scss
p {
& a {}
//↑
// This type of selector
}
```
The following patterns are considered warnings:
```scss
p {
& a {}
}
```
```scss
p {
& > a {}
}
```
```scss
p {
& .class {}
}
```
```scss
p {
& + .foo {}
}
```
The following patterns are *not* considered warnings:
```scss
p {
&.foo {}
}
```
```scss
p {
.foo > & {}
}
```
```scss
p {
&,
.foo,
.bar {
margin: 0;
}
}
```