stylelint / stylelint Goto Github PK
View Code? Open in Web Editor NEWA mighty CSS linter that helps you avoid errors and enforce conventions.
Home Page: https://stylelint.io
License: MIT License
A mighty CSS linter that helps you avoid errors and enforce conventions.
Home Page: https://stylelint.io
License: MIT License
I will take this one while we decide on #40.
I need to fix a bug and finish import to get smart labels :)
To replace number-trailing-zero
, as discussed in #64.
Can we result unsuccessfully with errors?(and successfully with warnings as well)
Do you have a plan to be the build to fail on errors?
I mean:
if (options === '2') {
result.error(
messages.unexpected,
{ node: decl }
)
})
} else if (options === '1') {
result.warn(
messages.unexpected,
{ node: decl }
)
})
}
https://github.com/CSSLint/csslint/blob/master/src/core/CSSLint.js#L89
Originally: selector-pseudo-element-two-colons
"always"|"never"
.
I was going to have a go at this one next. What do you guys think of renaming it to?:
selector-pseudo-element-colon-notation
: "single"|"double"
As it feels like it has more in common with something like string-quotes
: "single"|"double"
as the values are explicit. Whereas "never
" for selector-pseudo-element-two-colons
implies only a single colon, which feel odd and in contrast to something clear like declaration-block-trailing-semicolon
where always
and never
mean a semicolon must be present and must not be present respectively.
Also, there's a lot of pseudo-elements, but it looks like the single colon approach is only valid for a handful of them, "namely: :first-line
, :first-letter
, :before
and :after
". Am I right in thinking this rule should only flag warnings against these four pseudo-elements and not the rest.
I will work on this.
This is a continuation of PR 13 as there were a couple of things in there that I think are worth capturing for future reference.
We agreed that we shouldn't have built-in defaults, but we should instead, at some point, supply a mechanism to use or extend a recommended configuration.
If we provide an extends mechanism (like eslint does) then it follows that we might also need a means of disabling rules, right? e.g.
extends: recommended-suitcss, // example of a recommended styleguide config
rules: {
declaration-block-trailing-semicolon: disable?
// the user doesn't wish to enforce either option i.e always semi or never semi
}
We can either:
extends: recommended-suitcss
) and add extra rules to it (but they can not subtract rules from it - they'll need to build their config from scratch just like the power users do, if they want to do that).Related to this, as @MoOx pointed out in the PR, is the idea of severities e.g. it looks like eslint combines severities and disabling rules into one number system.
Scsslint also has severities and it got a mention over in the original Rules thread.
I don't know enough about this to decide whether the advantages of adding severities (e.g. easier integration into build systems) out weigh the disadvantages (e.g. more complexity), or not. Does anyone have a strong opinion on this?
I don't think we need to resolve this now though as this issue shouldn't affect how we write the rules themselves, right? Is it something that can be dealt with entirely in the stylelint index.js? If so, shall we carry on as we were and just keep this issue hanging around for future reference?
Vocabulary reference http://apps.workflower.fi/vocabs/css/en
Updated list
no-missing-eof-newline
: Disallow missing end-of-file newlineno-multiple-empty-lines
: Disallow multiple empty white linesno-eol-no-whitespace
: Disallow whitespace at the end of lineindentation
: Specify whitespace for indentationmax-line-length
: Specify maximum line lengthstring-quotes
: "double"|"single"
Specify quotes around strings
"double"
- strings must be doubled quoted"single"
- strings must be single quotednumber-leading-zero
: "always"|"never"
Require or disallow a leading zero before number
"always"
- a number must have a leading zero"never"
- a number must not have a leading zeronumber-no-trailing-zeros
: Disallow trailing zeros (e.g. 5.0px
)number-zero-length-no-unit
: Disallow units for zero length valuesnumber-max-precision
: int
Maximum number of digits after the "." in a numberfunction-comma-space-after
: "always"|"never"
function-comma-space-before
: "always"|"never"
function-parentheses-inside-space
: "always"|"never"
Specify space inside parentheses (after opening, before closing)function-space-after
: "always"|"never"
Specify space between the closing parenthesis of a function and the next valuefunction-token-no-space
: Disallow space between the function's name and its opening parenthesisfunction-calc-no-unspaced-operator
: Disallow operators without space on both sides in calc()
function-url-quotes
: "double"
, "single"
, "none"
Specify quotes around URLs (URLs, unlike strings, can be unquoted)
"double"
- URLs must be doubled quoted"single"
- URLs must be single quoted"none"
- URLs must be unquotedcolor-hex-length
: "short"|"long"
color-hex-case
: "lower"|"upper"
color-no-invalid-hex
: Disallow invalid hexcolor-no-named
: Disallow named colorscolor-no-hex
: Disallow hex colorscolor-function-blacklist
: array
Disallowed color functions e.g. ["rgba", "hsl", "hwb"]
color-function-whitelist
: array
Only allowed color functions e.g. ["gray", "color", "device-cmyk"]
root-no-standard-properties
: Disallow use of standard properties in :rootrule-no-single-line
: Disallow single line rule-setsrule-properties-order
: 1 dimension array
, string
(preset) - "alphabetical"
Order of properties within a rulerule-trailing-semicolon
: "always"|"never"
Trailing semicolon at the end of a rule
"always"
- there must be a trailing semicolon"never"
- there must not be a trailing semicolonrule-no-duplicate-properties
: Disallow duplicate properties within a rulerule-nested-empty-line-before
: Require or disallow an empty line before nested rulesrule-single-line-max-length
: int
The maximum length of a single line rulerule-single-line-max-declarations
: int
The maximum number of declaration within a single line ruleat-rule-no-vendor-prefix
: Disallow vendor prefixes in @rulesat-rule-empty-line-before
: Require or disallow an empty line before at-rulescustom-media-pattern
: string
Preset or regex pattern to use to check names are matching a given patternmedia-query-parenthesis-inside-space
: "always"|"never"
media-query-list-comma-space-after
: "always"|"never"
media-query-list-comma-space-before
: "always"|"never"
media-query-list-comma-newline-after
: "always"|"never"
media-query-list-comma-newline-before
: "always"|"never"
media-feature-colon-space-after
: "always"|"never"
media-feature-colon-space-before
: "always"|"never"
media-feature-range-operator-space-after
: "always"|"never"
media-feature-range-operator-space-before
: "always"|"never"
media-feature-colon-space-after
: "always"|"never"
media-feature-colon-space-before
: "always"|"never"
media-feature-range-operator-space-after
: "always"|"never"
media-feature-range-operator-space-before
: "always"|"never"
media-feature-name-no-vendor-prefix
: "always"|"never"
Disallow vendor prefixes for media feature namesselector-combinator-space-before
: string
Specify what space should be used before and after combinatorselector-combinator-space-after
: string
Specify what space should be used before and after combinatorselector-delimiter-space-after
: "always"|"never"
selector-delimiter-space-before
: "always"|"never"
selector-delimiter-newline-after
: "always"|"never"
selector-delimiter-newline-before
: "always"|"never"
selector-no-vendor-prefix
: Disallow vendor prefixes in selectorsselector-pseudo-element-notation
: Specify that pseudo element selectors need one or twoselector-root-no-composition
: Disallow use of :root
selector with others (in list, complex, or compound selectors)selector-no-id
: Disallow use of id in selectors e.g: #id
selector-no-type
: Disallow use of type in selectors e.g: div
selector-no-universal
: Disallow use of universal selector in selectors e.g: *
selector-no-attribute
: Disallow use of attributes in selectors e.g: [attr]
selector-no-combinator
: Disallow use of combinator in selectorsselector-no-qualified
: Disallow use of qualified selectors e.g: div#id
selector-no-pseudo-class
: Disallow use of pseudo-class in selectorsselector-no-pseudo-element
: Disallow use of pseudo-element in selectorsselector-no-delimiter
: Disallow use of delimiter in selectorsselector-pattern
: string
regex (eg: /\.([a-z]+-)?[A-Z][a-z]+(-[a-z][a-zA-Z]+)(--[a-z][a-zA-Z]+)/
to match .org-Block-eleMent--modifiercustom-selector-pattern
: string
Regex pattern to use to check names are matching a given patternblock-no-empty
: Disallow empty blocksblock-opening-brace-space-after
: "always"|"never"|"always-single-line"|"never-single-line"|"always-multi-line"|"never-multi-line"
block-opening-brace-space-before
: "always"|"never"|"always-single-line"|"never-single-line"|"always-multi-line"|"never-multi-line"
block-opening-brace-newline-after
: "always"|"never"|"always-multi-line"|"never-multi-line"
block-opening-brace-newline-before
: "always"|"never"|"always-single-line"|"never-single-line"|"always-multi-line"|"never-multi-line"
block-closing-brace-space-after
: "always"|"never"|"always-single-line"
block-closing-brace-space-before
: "always"|"never"|"always-single-line"|"never-single-line"|"always-multi-line"|"never-multi-line"
block-closing-brace-newline-after
: "always"|"never"|"always-single-line"|"never-single-line"|"always-multi-line"|"never-multi-line"
block-closing-brace-newline-before
: "always"|"never"|"always-multi-line"|"never-multi-line"
nesting-block-opening-brace-space-before
: "always"|"never"|"always-single-line"|"never-single-line"|"always-multi-line"|"never-multi-line"
nesting-block-opening-brace-newline-before
: "always"|"never"|"always-single-line"|"never-single-line"|"always-multi-line"|"never-multi-line"
declaration-no-important
: Disallow the use of !importantdeclaration-bang-space-after
: "always"|"never"
declaration-bang-space-before
: "always"|"never"
declaration-colon-space-after
: "always"|"never"
declaration-colon-space-before
: "always"|"never"
declaration-semicolon-space-after
: "always"|"never"|"always-single-line"|"never-single-line"
declaration-semicolon-space-before
: "always"|"never"|"always-single-line"|"never-single-line"
declaration-semicolon-newline-after
: "always"|"never"|"always-multi-line"|"never-multi-line"
declaration-semicolon-newline-before
: "always"|"never"|"always-multi-line"|"never-multi-line"
unit-blacklist
: array
Disallowed units e.g. ["px", "pt", "cm"]
unit-whitelist
: array
Only allowed units e.g. ["%", "rem", "em"]
property-no-vendor-prefix
: Disallow vendor prefixes in propertiesproperty-blacklist
: array
Disallowed properties e.g. ["tranform", "background-size"]
property-whitelist
: array
Only allowed properties e.g. ["height", "width", "font-size"]
property-unit-blacklist
: object
Disallowed units for specific properties e.g. {"width": ["%"], "height": ["%"]}
property-unit-whitelist
: object
Only allowed units for specific properties e.g. {"font-size": ["em", "rem"]}
custom-property-no-outside-root
: Disallow custom properties outside of :root
custom-property-pattern
: string
Regex pattern to use to check names are matching a given patternvalue-no-vendor-prefix
: Disallow vendor prefixes in valuesvalue-list-comma-space-after
: "always"|"never"|"always-single-line"|"never-single-line"
value-list-comma-space-before
: "always"|"never"|"always-single-line"|"never-single-line"
value-list-comma-newline-after
: "always"|"never"|"always-multi-line"|"never-multi-line"
value-list-comma-newline-before
: "always"|"never"|"always-multi-line"|"never-multi-line"
comment-space-inside
: string
- `"always"|"never"comment-empty-line-before
: Require or disallow an empty line before commentsI probably will spend some time writing more rules this coming weekend. I don't know if anybody else was thinking of contributing yet; but I want to make sure we don't overlap efforts. So I was thinking about the following workflow: Before starting work to add a rule, you should open an issue about that rule and state there that you are going to start working on it. If anybody doesn't check the issues before starting a rule and duplicates effort, that's their bad. But this should prevent that.
Sound ok?
Typical whitespace, probably.
Lots of something-before
and -after
will need to be revised to something-space
.
I'm pretty sure that's not being considered yet.
I don't understand this one. Am I right that it's trying to force the user to at some point use a background property on body
? If that's the intention, I don't think this will accomplish that. If the uses the body
selector twice in legitimate ways and only applies a background once, this will needlessly. Also, the user could never use the body
selector and thus bypass the intention without getting warned. (Or maybe there's another reason behind this rule?)
Given a rule like declaration-bang-space
--- so far I've been treating "never" to mean: "no whitespace in front of the bang". Because I'm thinking that if you want there to be no space in front of the !, you're also not going to want there to be a tab or newline or some other whitespace.
One implication of that treatment that I wanted to run by everybody is that "never" means the same, then, whether it's for a space rule or a newline rule. I was working on block-opening-brace-newline
, and realized that the tests for its "never" would be the same as for block-opening-brace-space
.
So does it seem that that's the right approach to everybody? Or should we instead make "never" mean "not this particular whitespace --- but other whitespaces we don't know.*
Typical whitespace --- but this one in combination with function-comma-space
makes me think I should write a general utility for finding things in values that are inside of (or outside of) functions.
@MoOx I think it would help clarify this rule if you could exemplify the complex options you proposed for this rule in #1. I have some guesses as to what is meant based on the discussion but it would be more straightforward with something like example pass/fail cases for each option. Does that make sense?
a logo needs to be done
Hello!
Do you have any Roadmap or something? is it #1?
I'm interested in preparation and implementing of rules.
I'm looking forward to try & counting on stylelint.:smile:
I'll have a go at this this weekend, if that's OK?
Expanded from #20 (comment)
It seems that in most whitespace rules in #1 it is suggested that users will be able to enter their own whitespace values. Maybe one space, three spaces, newline, carriage return, etc. I'm worried this will add a lot of overhead and complexity in order to accommodate rare edge cases.
Personally I have not yet seen standardized CSS where the convention was to use anything other than one or no spaces in most of those places (around combinators, colons, bang, commas, parentheses). Only braces have varied, and only by adding the possibility of a newline to that of a single space.
Maybe you don't buy that, and think that we need to allow for lots of variations? Anybody feel this way?
If you agree with me, I can think of a few possible ways simplify things:
space
rules which have before and after options. So instead of media-query-list-comma-before
and media-query-list-comma-after
we have media-query-list-comma-space
; and its options are either { before: [boolean], after: [boolean] }
(where true means always and false means never) or true
which must provides a standard default (for commas, that would be { before: false, after: true }
). If you don't like having before/after options, we could instead keep separate rules but make them space-specific, e.g. media-query-list-comma-space-before
and media-query-list-comma-space-after
.selector-delimiter-before
and selector-delimiter-after
(first of all, why not "comma" instead of "delimiter"?) ... so that might reasonably be either a space or a newline (though almost certainly not tab, carriage return, four spaces, etc.). We could make selector-delimiter-space
and selector-delimiter-newline
with before/after options; or, alternately, selector-delimiter-space-before
and selector-delimiter-newline-before
and their -after
counterparts.I just opened an issue on postcss that will helps a lot us. In fact that would make us just ready to drop rules as plugin & use this new message api.
Please give your opinion on this guys :)
I am generally a fan of tape, and I know @MoOx is, too; but I've been writing tests for block-opening-brace-before
(neverending ...) and for a few reasons I'm wondering if for this particular situation Mocha would be more useful.
At the bottom of the message I'll paste the test file I have so far, so you can see some context for what I'm talking about. Maybe you know of ways to solve these problems with tape?
describe()
functions would be good.plan()
. For example, I imagine writing utility functions for expectSuccess()
or (no warnings) or expectFailure()
(check for warning and correct message), and while I can think of a straightforward way to do this with callbacks and unlimited nesting of describe()
, I'm having some trouble thinking of such a way with plan()
and not-unlimited-nesting. (Also, callbacks might get around the need to change the number of planned tests whenever you add or remove tests, which is a big annoyance.)Those are my concerns. What do you think? Can we solve them with tape? Should we switch to Mocha?
I partly feel like the only reason not to switch to tape (unless these concerns are unfounded) would be some ideal of purity which we should probably ignore in favor of pragmatism... Maybe it's worth an experiment, at least.
Can anybody foresee problems with Mocha?
import test from "tape"
import testRule from "../../../testUtils/testRule"
import blockOpeningBraceBefore from ".."
import { messages } from ".."
const testRule = testRule(blockOpeningBraceBefore)
test("block-opening-brace-before success", t => {
t.test("with `space`", st => {
st.plan(4)
testRule("body { color: pink; }", "space", warnings => {
st.equal(warnings.length, 0, "single-line rule")
})
testRule("body {\n\tcolor: pink;\n}", "space", warnings => {
st.equal(warnings.length, 0, "multi-line rule")
})
testRule("@media print { color: pink; }", "space", warnings => {
st.equal(warnings.length, 0, "single-line at-rule")
})
testRule("@media print {\n\tcolor: pink;\n}", "space", warnings => {
st.equal(warnings.length, 0, "multi-line at-rule")
})
})
t.test("with `newline`", st => {
st.plan(2)
testRule("body\n{ color: pink; }", "newline", warnings => {
st.equal(warnings.length, 0, "multi-line rule")
})
testRule("@media print\n{\n\tcolor: pink;\n}", "newline", warnings => {
st.equal(warnings.length, 0, "multi-line at-rule")
})
})
t.test("with `{ singleLine: `space`, multiLine: `space` }`", st => {
const options = { singleLine: "space", multiLine: "space" }
st.plan(4)
testRule("body { color: pink; }", options, warnings => {
st.equal(warnings.length, 0, "single-line rule")
})
testRule("body {\n\tcolor: pink;\n}", options, warnings => {
st.equal(warnings.length, 0, "multi-line rule")
})
testRule("@media print { color: pink; }", options, warnings => {
st.equal(warnings.length, 0, "single-line at-rule")
})
testRule("@media print {\n\tcolor: pink;\n}", options, warnings => {
st.equal(warnings.length, 0, "multi-line at-rule")
})
})
t.test("with `{ singleLine: `space`, multiLine: `newline` }`", st => {
const options = { singleLine: "space", multiLine: "newline" }
st.plan(4)
testRule("body { color: pink; }", options, warnings => {
st.equal(warnings.length, 0, "single-line rule")
})
testRule("body\n{\n\tcolor: pink;\n}", options, warnings => {
st.equal(warnings.length, 0, "multi-line rule")
})
testRule("@media print { color: pink; }", options, warnings => {
st.equal(warnings.length, 0, "single-line at-rule")
})
testRule("@media print\n{\n\tcolor: pink;\n}", options, warnings => {
st.equal(warnings.length, 0, "multi-line at-rule")
})
})
t.end()
})
test.only("block-opening-brace-before failure", t => {
t.test("warns when there are no whitespaces before opening brace", st => {
st.plan(8)
testRule("body{ color: pink; }", "space", warnings => {
st.equal(warnings.length, 1, "with `space` setting and rule")
st.equal(warnings[0].text, messages.expected("space"), "warning contains expected test")
})
testRule("body{ color: pink; }", "newline", warnings => {
st.equal(warnings.length, 1, "with `newline` setting and rule")
st.equal(warnings[0].text, messages.expected("newline"), "warning contains expected test")
})
testRule("@media print{ color: pink; }", "space", warnings => {
st.equal(warnings.length, 1, "with `space` setting and at-rule")
st.equal(warnings[0].text, messages.expected("space"), "warning contains expected test")
})
testRule("@media print{ color: pink; }", "newline", warnings => {
st.equal(warnings.length, 1, "with `newline` setting and at-rule")
st.equal(warnings[0].text, messages.expected("newline"), "warning contains expected test")
})
})
t.test("when there are multiple whitespaces before opening brace", st => {
st.plan(8)
testRule("body { color: pink; }", "space", warnings => {
st.equal(warnings.length, 1, "warns with two spaces before brace of rule")
st.equal(warnings[0].text, messages.expected("space"), "warning contains expected test")
})
testRule("body\n\t{ color: pink; }", "newline", warnings => {
st.equal(warnings.length, 1, "warns with \\n\\t before brace of rule")
st.equal(warnings[0].text, messages.expected("newline"), "warning contains expected test")
})
testRule("@media print { color: pink; }", "space", warnings => {
st.equal(warnings.length, 1, "warns with two spaces before brace of at-rule")
st.equal(warnings[0].text, messages.expected("space"), "warning contains expected test")
})
testRule("@media print\n\t{ color: pink; }", "newline", warnings => {
st.equal(warnings.length, 1, "warns with \\n\\t before brace of at-rule")
st.equal(warnings[0].text, messages.expected("newline"), "warning contains expected test")
})
})
t.test("with `space`", st => {
st.plan(4)
testRule("body\n{ color: pink; }", "space", warnings => {
st.equal(warnings.length, 1, "warns if actual for rule is newline")
st.equal(warnings[0].text, messages.expected("space"), "warning contains expected test")
})
testRule("@media print\n{ color: pink; }", "space", warnings => {
st.equal(warnings.length, 1, "warns if actual for at-rule is newline")
st.equal(warnings[0].text, messages.expected("space"), "warning contains expected test")
})
})
t.test("with `newline`", st => {
st.plan(4)
testRule("body { color: pink; }", "newline", warnings => {
st.equal(warnings.length, 1, "warns if actual for rule is space")
st.equal(warnings[0].text, messages.expected("newline"), "warning contains expected test")
})
testRule("@media print { color: pink; }", "newline", warnings => {
st.equal(warnings.length, 1, "warns if actual for at-rule is space")
st.equal(warnings[0].text, messages.expected("newline"), "warning contains expected test")
})
})
t.test("with `{ singleLine: `space`, multiLine: `space` }`", st => {
const options = { singleLine: "space", multiLine: "space" }
st.plan(4)
testRule("body\n{\ncolor: pink; }", options, warnings => {
st.equal(warnings.length, 1, "warns if newline precedes multiline rule")
st.equal(warnings[0].text, messages.expected("space"), "warning contains expected test")
})
testRule("@media print\n{\ncolor: pink; }", options, warnings => {
st.equal(warnings.length, 1, "warns if newline precedes multiline at-rule")
st.equal(warnings[0].text, messages.expected("space"), "warning contains expected test")
})
})
t.end()
})
How about a testUtil/
directory in src/
, containing test utils like testRule
?
The current position (in src/rules/__tests__/utils
) seems to me very unintuitive and requires a long import like import testRule from "../../__tests__/utils/testRule"
.
Open to that?
We established this convention after that rule was written.
Standard whitespace rule.
All in src looks strange. That __tests__
directories...
__tests__
in src, __tests__
in rules, __tests__
in rules/declaration* and etc..
Also for things like that index.js
in rules directory you can use some of them
You should firstly start with that thing.
After writing a lot of tests now, I'm think that things would be simpler if we separated out before/after rules instead of using options. So we'd have, e.g., block-opening-brace-space-before
and block-opening-brace-space-after
(like JSCS).
The reasoning is this:
Any opposition?
Standard whitespace.
Can I try this one next please? It feels like a mix between my declaration-no-important
and @davidtheclark block-opening-brace-before
, so it'll help me familiarise myself with David's new testing infrastructure. I hope to start today.
We need some elegant handling of PostCSS syntax errors -- especially considering that it's kind of the first line of linting (will find errors in people's code even if they have not turned on any rules).
I will work on this very soon.
We established this convention after that rule was written.
Followup to discussion here: 64f72fe#commitcomment-11168302
Currently we are leaving lodash out because we don't want to include unnecessary dependencies, which is a good approach.
lodash author John-David Dalton says there should be perf benefits to using lodash even within Node.js or io.js: https://twitter.com/jdalton/status/598511373849530368?cn=cmVwbHk%3D&refsrc=email
Because we are going to be running lots and lots of checks on sometimes lots and lots of lines of CSS, I'd say that performance is a major priority, and we should seriously consider any perf benefits we can get.
I'm opening this issue so that somebody at some point might run some benchmarks and compare some of the native looping, mapping, reducing, etc. that we are already doing against the same procedures with lodash functions. If lodash performance beats out the (babel-compiled) native code, then that (on top of other things I like about lodash) should incline us to use it.
How are we going to inform users of faulty options?
e.g. Misspelled keywords, options that don't make sense together (e.g. for single-line rule blocks expect a newline character before braces), etc.
Should we just throw an error? Will that make it through to the user, despite the Promises in PostCSS?
I realize that I forgot about those when writing the tests.
What do you guys think about standardising the wording within the messages? They've diverged a little bit already.
The "Expected" approach that @davidtheclark's used in declaration-bang-space
and in declaration-block-trailing-semicolon
LGTM. It seems to be used a lot in eslint as well.
So, the current rules would look something like:
Note: always tending towards "expected" over "unexpected"...
declaration-colon/bang-space
: "Expected single space before "!"" and "Expected no space before "!"declaration-block-trailing-semicolon
: "Expected a trailing semicolon" and "Expected no trailing semicolon"number-leading-zero
: "Expected a leading zero for fractional value less than 1" and "Expected no leading zero for fractional value less than 1"And "unexpected" would be mainly used for *-no-*
rules e.g.
declaration-no-important
: "Unexpected !important"rule-set-no-single-line
: "Unexpected single-line rule-set"What do you think?
I'm still keen to keep the must always, must never, can, disallow, and enforce language in the documentation as I think it feels nice and clear. e.g. here and here.
Thoughts?
Disallow single line rule-sets (true/false).
I will work on this soon. For this and #18 I will write a utility function to test whether a block contains any line breaks.
Do we think it's reasonable that a person might want to require trailing zeros?
If not, maybe this should be number-no-trailing-zero
.
Following whitespace conventions.
Anybody have a preference about whether documentation for rules goes in the Readme or in a separate rules.md
file?
I guess I'm leaning towards rules.md
myself.
I could get that started.
A serious project need a website.
I will handle it the same way I will handle cssnext one (hopefully really soon)
We have a mistmatch in how booleans are used for options in the drafts in #1.
Case #1:
color-hex-shorthand: bool
Case #2:
color-no-named: bool Disallow named colors
The key is that sometimes false = "must not" and sometimes false = "can".
I can think of a couple of possible ways to clarify this:
false
always mean "must not" as in Case #1; so in Case #2 false
just wouldn't be a possibility --- if the user wants to not disallow named colors the user should turn the rule off, not leave it on and pass false.always
and never
instead of true
and false
in cases like Case #1. That would not clarify Case #2, though.(This applies to the existing declaration-no-important
as well as a bunch of other ones.)
What would you think about using exact versions for devDependencies
?
I have seen and run into problems with CI when using carets for these (CI installs later version than you have locally, that version was improperly versioned so has some breaking change, etc.); and at the same time I don't know of any advantage to using the caret for devDependencies, since people will only install them for development so we don't have to worry about overcomplicated the dependency tree. Seems to me clearer and less error prone to be exact. Thoughts?
I will work on these very soon.
The -after
suffix is because I don't think a user would likely require a newline before.
The question of whether this kind of suffix is a suitable convention I also brought up here: #21 (comment)
The vast majority of tests that we write for rules will be doing the exact same thing: check whether a given CSS string passes or causes a warning with an expected message.
So I'm thinking we should have some functions that make it very, very easy to run these standard tests and log meaningful messages. (Of course, if somebody has something different to do they can always not use these standard functions.)
This morning I worked out a possible approach, and I wanted to run it by you all before I went too far with it.
The following creates a ruleTester that exposes ok()
and notOk()
functions that check for no warnings or warnings (with correct messages) and logs in a meaningful way:
import postcss from "postcss"
import jsesc from "jsesc"
export default function ruleTester(rule) {
return {
ok: function (t, cssString, options) {
postcssProcess(cssString, options, result => {
t.comment(jsesc(cssString))
t.equal(result.warnings().length, 0, `no warnings`)
})
},
notOk: function (t, cssString, options, message) {
postcssProcess(cssString, options, result => {
const warnings = result.warnings()
t.comment(jsesc(cssString))
t.equal(warnings.length, 1, `one warning`)
t.equal(warnings[0].text, message, `correct warning message`)
})
},
}
function postcssProcess(cssString, options, callback) {
postcss()
.use(rule(options))
.process(cssString)
.then(callback)
}
}
I'd use it like this (the third test deliberately fails):
import test from "tape"
import { ruleTester, ruleTestTitle } from "../../../testUtils"
import blockOpeningBraceBefore, { ruleName, messages } from ".."
const testRule = ruleTester(blockOpeningBraceBefore)
test(ruleTestTitle(ruleName, "'space'"), t => {
testRule.ok(t, "body { color: pink; }", "space")
testRule.ok(t, "@media print { color: pink; }", "space")
testRule.notOk(t, "body\n{ color: pink; }", "newline", messages.expected("newline"))
testRule.notOk(t, "@media print\n{ color: pink; }", "space", messages.expected("space"))
t.end()
})
And that outputs TAP output like this:
TAP version 13
# block-opening-brace-before: 'space'
# body { color: pink; }
ok 1 no warnings
# @media print { color: pink; }
ok 2 no warnings
# body\n{ color: pink; }
not ok 3 one warning
---
operator: equal
expected: 1
actual: 0
...
# @media print\n{ color: pink; }
ok 4 one warning
ok 5 correct warning message
1..5
# tests 5
# pass 4
# fail 1
Or tap-spec output like this:
block-opening-brace-before: 'space'
body { color: pink; }
✓ no warnings
@media print { color: pink; }
✓ no warnings
body\n{ color: pink; }
✗ one warning
@media print\n{ color: pink; }
✓ one warning
✓ correct warning message
Or faucet output like this:
✓ block-opening-brace-before: 'space'
✓ body { color: pink; }
✓ @media print { color: pink; }
⨯ body\n{ color: pink; }
not ok 3 one warning
---
operator: equal
expected: 1
actual: 0
...
✓ @media print\n{ color: pink; }
# tests 5
# pass 4
⨯ fail 1
What do you think? Is that a useful abstraction for us? Are the error messages as clear as we can make them? Any suggestions for improvement?
I think it will be very handy as we write thousands of little tests to have functions that do something like this, at least ...
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.