3 const _ = require("lodash");
4 const hasBlock = require("../../utils/hasBlock");
5 const optionsMatches = require("../../utils/optionsMatches");
6 const report = require("../../utils/report");
7 const ruleMessages = require("../../utils/ruleMessages");
8 const validateOptions = require("../../utils/validateOptions");
10 const ruleName = "max-nesting-depth";
12 const messages = ruleMessages(ruleName, {
13 expected: depth => `Expected nesting depth to be no more than ${depth}`
16 const rule = function(max, options) {
17 const isIgnoreAtRule = node =>
18 node.type === "atrule" &&
19 optionsMatches(options, "ignoreAtRules", node.name);
21 return (root, result) => {
27 possible: [_.isNumber]
33 ignore: ["blockless-at-rules"],
34 ignoreAtRules: [_.isString]
39 root.walkRules(checkStatement);
40 root.walkAtRules(checkStatement);
42 function checkStatement(statement) {
43 if (isIgnoreAtRule(statement)) {
46 if (!hasBlock(statement)) {
49 const depth = nestingDepth(statement);
55 message: messages.expected(max)
61 function nestingDepth(node, level) {
63 const parent = node.parent;
65 if (isIgnoreAtRule(parent)) {
69 // The nesting depth level's computation has finished
70 // when this function, recursively called, receives
71 // a node that is not nested -- a direct child of the
74 parent.type === "root" ||
75 (parent.type === "atrule" && parent.parent.type === "root")
81 optionsMatches(options, "ignore", "blockless-at-rules") &&
82 node.type === "atrule" &&
83 node.every(child => child.type !== "decl")
85 return nestingDepth(parent, level);
88 // Unless any of the conditions above apply, we want to
89 // add 1 to the nesting depth level and then check the parent,
90 // continuing to add and move up the hierarchy
91 // until we hit the root node
92 return nestingDepth(parent, level + 1);
96 rule.ruleName = ruleName;
97 rule.messages = messages;
98 module.exports = rule;