"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports["default"] = rule; exports.ruleName = exports.meta = exports.messages = void 0; var _stylelint = require("stylelint"); var _utils = require("../../utils"); var hasOwnProp = Object.prototype.hasOwnProperty; var ruleName = (0, _utils.namespace)("declaration-nested-properties"); exports.ruleName = ruleName; var messages = _stylelint.utils.ruleMessages(ruleName, { expected: function expected(prop) { return "Expected property \"".concat(prop, "\" to be in a nested form"); }, rejected: function rejected(prop) { return "Unexpected nested property \"".concat(prop, "\""); } }); exports.messages = messages; var meta = { url: (0, _utils.ruleUrl)(ruleName) }; exports.meta = meta; function rule(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-Z\d]+)-/.exec(prop); if (seekNamespace && seekNamespace[1]) { var ns = seekNamespace[1]; if (!hasOwnProp.call(warningCandidates, ns)) { warningCandidates[ns] = []; } warningCandidates[ns].push({ node: decl }); } } // Nested props, `prop: [value] { }` if (type === "rule" || type === "decl" && decl.isNested) { // `background:red {` - selector; // `background: red {` - nested prop; space is decisive here var testForProp = (0, _utils.parseNestedPropRoot)(selector || decl.toString()); if (testForProp && testForProp.propName !== undefined) { var _ns = testForProp.propName.value; if (!hasOwnProp.call(warningCandidates, _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 }); } } }); } }; } rule.ruleName = ruleName; rule.messages = messages; rule.meta = meta;