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

View File

@@ -0,0 +1,126 @@
# max-line-length
Limit the length of a line.
```css
a { color: red }
/** ↑
* The end */
```
Lines that exceed the maximum length but contain no whitespace (other than at the beginning of the line) are ignored.
When evaluating the line length, the arguments of any `url(...)` functions are excluded from the calculation, because typically you have no control over the length of these arguments. This means that long `url()` functions should not contribute to warnings.
## Options
`int`: Maximum number of characters allowed.
For example, with `20`:
The following patterns are considered warnings:
```css
a { color: 0; top: 0; }
```
```css
a {
background: linear-gradient(red, blue);
}
```
The following patterns are *not* considered warnings:
```css
a {
color: 0;
top: 0;
}
```
```css
a {
background: url(a-url-that-is-over-20-characters-long);
}
```
## Optional secondary options
### `ignore: ["non-comments"]`
Only enforce the line-length limit for lines within comments.
This does not apply to comments that are stuck in between other stuff, only to lines that begin at the beginning or in the middle of a comment.
For example, with a maximum length of `30`.
The following patterns are considered warnings:
Each have only one warning.
```css
/* This line is too long for my rule */
a { color: pink; background: orange; }
a { color: pink; /* this comment is also long but not on its own line */ }
```
```css
a { color: pink; background: orange; }
/**
* This line is short,
* but this line is too long for my liking,
* though this one is fine
*/
a { color: pink; /* this comment is also long but not on its own line */ }
```
### `ignore: ["comments"]`
Only enforce the line-length limit for lines that are not comments.
This also applies to comments that are between code on the same line.
For example, with a maximum length of `30`.
The following patterns are considered warnings:
```css
a { color: pink; } /* comment that is too long */
```
```css
a { /* this comment is too long for the max length */ }
```
The following patterns are *not* considered warnings:
```css
/* comment that is too long for my rule*/
a { color: pink; }
```
```css
/*
* comment that is too long the max length
* comment that is too long the max length
*
*/
a { color: pink; }
```
### `ignorePattern: ["/regex/"]`
Ignore any line that matches the given regex pattern, regardless of whether it is comment or not.
Given:
```js
["/^@import\\s+/"]
```
The following is *not* considered a warning regardless of line length:
```css
@import "../../../../another/css/or/scss/file/or/something.css";
```

View File

@@ -0,0 +1,136 @@
"use strict"
const execall = require("execall")
const optionsMatches = require("../../utils/optionsMatches")
const report = require("../../utils/report")
const ruleMessages = require("../../utils/ruleMessages")
const validateOptions = require("../../utils/validateOptions")
const _ = require("lodash")
const styleSearch = require("style-search")
const ruleName = "max-line-length"
const messages = ruleMessages(ruleName, {
expected: l => `Expected line length to be no more than ${l} characters`,
})
const rule = function (maxLength, options) {
return (root, result) => {
const validOptions = validateOptions(result, ruleName, {
actual: maxLength,
possible: _.isNumber,
}, {
actual: options,
possible: {
ignore: [
"non-comments",
"comments",
],
ignorePattern: [_.isString],
},
optional: true,
})
if (!validOptions) {
return
}
const rootString = root.source.input.css
const ignoreNonComments = optionsMatches(options, "ignore", "non-comments")
const ignoreComments = optionsMatches(options, "ignore", "comments")
// Check first line
checkNewline({ endIndex: 0 })
// Check subsequent lines
styleSearch({ source: rootString, target: ["\n"], comments: "check" }, checkNewline)
function complain(index) {
report({
index,
result,
ruleName,
message: messages.expected(maxLength),
node: root,
})
}
function checkNewline(match) {
let nextNewlineIndex = rootString.indexOf("\n", match.endIndex)
if (rootString[nextNewlineIndex - 1] === "\r") {
nextNewlineIndex -= 1
}
// Accommodate last line
if (nextNewlineIndex === -1) {
nextNewlineIndex = rootString.length
}
const rawLineLength = nextNewlineIndex - match.endIndex
const lineText = rootString.slice(match.endIndex, nextNewlineIndex)
if (optionsMatches(options, "ignorePattern", lineText)) {
return
}
const urlArgumentsLength = execall(/url\((.*)\)/ig, lineText).reduce((result, match) => {
return result + _.get(match, "sub[0].length", 0)
}, 0)
const importUrlsLength = execall(/\@import\s+(['"].*['"])/ig, lineText).reduce((result, match) => {
return result + _.get(match, "sub[0].length", 0)
}, 0)
// If the line's length is less than or equal to the specified
// max, ignore it ... So anything below is liable to be complained about.
// **Note that the length of any url arguments or import urls
// are excluded from the calculation.**
if (rawLineLength - urlArgumentsLength - importUrlsLength <= maxLength) {
return
}
const complaintIndex = nextNewlineIndex - 1
if (ignoreComments) {
if (match.insideComment) {
return
}
// This trimming business is to notice when the line starts a
// comment but that comment is indented, e.g.
// /* something here */
const nextTwoChars = rootString.slice(match.endIndex).trim().slice(0, 2)
if (nextTwoChars === "/*" || nextTwoChars === "//") {
return
}
}
if (ignoreNonComments) {
if (match.insideComment) {
return complain(complaintIndex)
}
// This trimming business is to notice when the line starts a
// comment but that comment is indented, e.g.
// /* something here */
const nextTwoChars = rootString.slice(match.endIndex).trim().slice(0, 2)
if (nextTwoChars !== "/*" && nextTwoChars !== "//") {
return
}
return complain(complaintIndex)
}
// If there are no spaces besides initial (indent) spaces, ignore it
const lineString = rootString.slice(match.endIndex, nextNewlineIndex)
if (lineString.replace(/^\s+/, "").indexOf(" ") === -1) {
return
}
return complain(complaintIndex)
}
}
}
rule.ruleName = ruleName
rule.messages = messages
module.exports = rule