123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268 |
- "use strict";
- Object.defineProperty(exports, "__esModule", {
- value: true
- });
- exports.calculationOperatorSpaceChecker = calculationOperatorSpaceChecker;
- exports["default"] = rule;
- exports.ruleName = exports.meta = exports.messages = void 0;
- var _postcssMediaQueryParser = _interopRequireDefault(require("postcss-media-query-parser"));
- var _stylelint = require("stylelint");
- var _utils = require("../../utils");
- function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; }
- var ruleName = (0, _utils.namespace)("operator-no-unspaced");
- exports.ruleName = ruleName;
- var messages = _stylelint.utils.ruleMessages(ruleName, {
- expectedAfter: function expectedAfter(operator) {
- return "Expected single space after \"".concat(operator, "\"");
- },
- expectedBefore: function expectedBefore(operator) {
- return "Expected single space before \"".concat(operator, "\"");
- }
- });
- exports.messages = messages;
- var meta = {
- url: (0, _utils.ruleUrl)(ruleName)
- };
- /**
- * The actual check for are there (un)necessary whitespaces
- */
- exports.meta = meta;
- 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;
- }
- function rule(expectation) {
- return function (root, result) {
- var validOptions = _stylelint.utils.validateOptions(result, ruleName, {
- actual: expectation
- });
- if (!validOptions) {
- return;
- }
- (0, _utils.eachRoot)(root, checkRoot);
- function checkRoot(root) {
- var rootString = root.source.input.css;
- if (rootString.trim() === "") {
- return;
- }
- calculationOperatorSpaceChecker({
- root: root,
- result: result,
- checker: checkSpaces
- });
- }
- };
- }
- rule.ruleName = ruleName;
- rule.messages = messages;
- rule.meta = meta;
- /**
- * 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 symbol to inspect
- * {number} cbArgs.endIndex -- the end index of a symbol 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 occurrences of Sass interpolation in it, then
- * finds all operators inside that interpolation
- *
- * @return {array} An array of objects { string, operators } - effectively,
- * a list of operators for each Sass interpolation occurrence
- */
- 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;
- }
- var dataURIRegex = /^url\(\s*['"]?data:.+['"]?\s*\)/;
- root.walk(function (item) {
- if (item.prop === "unicode-range") {
- return;
- }
- var results = [];
- // Check a value (`10px` in `width: 10px;`)
- if (item.value !== undefined) {
- if (dataURIRegex.test(item.value)) {
- return results;
- }
- 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") {
- // @forward, @use and @at-root
- if (item.name === "forward" || item.name === "use" || item.name === "at-root") {
- return;
- }
- // Media queries
- if (item.name === "media" || item.name === "import") {
- (0, _postcssMediaQueryParser["default"])(item.params).walk(function (node) {
- var type = node.type;
- if (["keyword", "media-type", "media-feature"].includes(type)) {
- results = results.concat(findInterpolation(node.value, (0, _utils.atRuleParamIndex)(item) + node.sourceIndex));
- } else if (type === "value") {
- results.push({
- source: node.value,
- operators: (0, _utils.findOperators)({
- string: node.value,
- globalIndex: (0, _utils.atRuleParamIndex)(item) + node.sourceIndex,
- isAfterColon: true
- })
- });
- } else if (type === "url") {
- var isQuoted = node.value[0] === '"' || node.value[0] === "'";
- var containsWhitespace = node.value.search(/\s/) > -1;
- if (isQuoted || containsWhitespace) {
- // The argument to the url function is only parsed as SassScript if it is a quoted
- // string, or a _valid_ unquoted URL [1].
- //
- // [1] https://sass-lang.com/documentation/syntax/special-functions#url
- 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
- });
- });
- }
- });
- });
- }
|