.gitignore added
[dotfiles/.git] / .config / coc / extensions / node_modules / coc-prettier / node_modules / stylelint / lib / rules / max-line-length / index.js
1 "use strict";
2
3 const _ = require("lodash");
4 const execall = require("execall");
5 const optionsMatches = require("../../utils/optionsMatches");
6 const report = require("../../utils/report");
7 const ruleMessages = require("../../utils/ruleMessages");
8 const styleSearch = require("style-search");
9 const validateOptions = require("../../utils/validateOptions");
10
11 const ruleName = "max-line-length";
12
13 const messages = ruleMessages(ruleName, {
14   expected: max =>
15     `Expected line length to be no more than ${max} ${
16       max === 1 ? "character" : "characters"
17     }`
18 });
19
20 const rule = function(maxLength, options) {
21   return (root, result) => {
22     const validOptions = validateOptions(
23       result,
24       ruleName,
25       {
26         actual: maxLength,
27         possible: _.isNumber
28       },
29       {
30         actual: options,
31         possible: {
32           ignore: ["non-comments", "comments"],
33           ignorePattern: [_.isString]
34         },
35         optional: true
36       }
37     );
38     if (!validOptions) {
39       return;
40     }
41
42     const rootString = root.source.input.css;
43
44     const ignoreNonComments = optionsMatches(options, "ignore", "non-comments");
45     const ignoreComments = optionsMatches(options, "ignore", "comments");
46
47     // Check first line
48     checkNewline({ endIndex: 0 });
49
50     // Check subsequent lines
51     styleSearch(
52       { source: rootString, target: ["\n"], comments: "check" },
53       checkNewline
54     );
55
56     function complain(index) {
57       report({
58         index,
59         result,
60         ruleName,
61         message: messages.expected(maxLength),
62         node: root
63       });
64     }
65
66     function checkNewline(match) {
67       let nextNewlineIndex = rootString.indexOf("\n", match.endIndex);
68       if (rootString[nextNewlineIndex - 1] === "\r") {
69         nextNewlineIndex -= 1;
70       }
71
72       // Accommodate last line
73       if (nextNewlineIndex === -1) {
74         nextNewlineIndex = rootString.length;
75       }
76
77       const rawLineLength = nextNewlineIndex - match.endIndex;
78       const lineText = rootString.slice(match.endIndex, nextNewlineIndex);
79
80       // Case sensitive ignorePattern match
81       if (optionsMatches(options, "ignorePattern", lineText)) {
82         return;
83       }
84
85       const urlArgumentsLength = execall(/url\((.*)\)/gi, lineText).reduce(
86         (result, match) => {
87           return result + _.get(match, "sub[0].length", 0);
88         },
89         0
90       );
91
92       const importUrlsLength = execall(
93         /@import\s+(['"].*['"])/gi,
94         lineText
95       ).reduce((result, match) => {
96         return result + _.get(match, "sub[0].length", 0);
97       }, 0);
98
99       // If the line's length is less than or equal to the specified
100       // max, ignore it ... So anything below is liable to be complained about.
101       // **Note that the length of any url arguments or import urls
102       // are excluded from the calculation.**
103       if (rawLineLength - urlArgumentsLength - importUrlsLength <= maxLength) {
104         return;
105       }
106
107       const complaintIndex = nextNewlineIndex - 1;
108
109       if (ignoreComments) {
110         if (match.insideComment) {
111           return;
112         }
113
114         // This trimming business is to notice when the line starts a
115         // comment but that comment is indented, e.g.
116         //       /* something here */
117         const nextTwoChars = rootString
118           .slice(match.endIndex)
119           .trim()
120           .slice(0, 2);
121         if (nextTwoChars === "/*" || nextTwoChars === "//") {
122           return;
123         }
124       }
125
126       if (ignoreNonComments) {
127         if (match.insideComment) {
128           return complain(complaintIndex);
129         }
130
131         // This trimming business is to notice when the line starts a
132         // comment but that comment is indented, e.g.
133         //       /* something here */
134         const nextTwoChars = rootString
135           .slice(match.endIndex)
136           .trim()
137           .slice(0, 2);
138         if (nextTwoChars !== "/*" && nextTwoChars !== "//") {
139           return;
140         }
141         return complain(complaintIndex);
142       }
143
144       // If there are no spaces besides initial (indent) spaces, ignore it
145       const lineString = rootString.slice(match.endIndex, nextNewlineIndex);
146       if (lineString.replace(/^\s+/, "").indexOf(" ") === -1) {
147         return;
148       }
149
150       return complain(complaintIndex);
151     }
152   };
153 };
154
155 rule.ruleName = ruleName;
156 rule.messages = messages;
157 module.exports = rule;