From dd886dfad68019191f1699e1ca087348f5b73398 Mon Sep 17 00:00:00 2001 From: Richard Hallows Date: Sat, 25 Feb 2017 09:16:23 +0000 Subject: [PATCH 01/15] Add min rules --- docs/user-guide/about-rules.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/user-guide/about-rules.md b/docs/user-guide/about-rules.md index d0ce75aece..13e8319417 100644 --- a/docs/user-guide/about-rules.md +++ b/docs/user-guide/about-rules.md @@ -56,9 +56,9 @@ a { } Notice how, for a rule like this, it does not make sense to have an option to enforce the opposite i.e. that every block *must* be empty. -### Max rules +### Max and min rules -`*-max-*` is used when a rule is *setting a limit* to something. +`*-max-*` and `*-min-*` rules are used when a rule is *setting a limit* to something. For example, specifying the maximum number of digits after the "." in a number: From d2909a0f2665bc8d113363fbf1553099e2abf6f4 Mon Sep 17 00:00:00 2001 From: Richard Hallows Date: Sun, 26 Feb 2017 00:07:18 +0000 Subject: [PATCH 02/15] Update stylelint-disable-reason changelog entry (#2393) --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7ec7969ddb..10bc08b5a8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -31,7 +31,7 @@ - `root-no-standard-properties` - `selector-root-no-composition`. - The following rules did not work well. - - `stylelint-disable-reason`. Please consider contributing to [#2292](https://github.com/stylelint/stylelint/issues/2292) for a replacement. + - `stylelint-disable-reason` could not enforce providing a reason. - `declaration-block-no-ignored-properties` could not reliably account for *replaced elements*. - Deprecated: 4 options ([#2213](https://github.com/stylelint/stylelint/pull/2213)). - `"all-nested"` option for `at-rule-empty-line-before`. Use the `"inside-block"` option instead. From 2e7a1bd55e6c146482a543e2f085d1f3d9502682 Mon Sep 17 00:00:00 2001 From: Evilebot Tnawi Date: Sun, 26 Feb 2017 22:15:35 +0300 Subject: [PATCH 03/15] Tests: improved tests for `no-missing-end-of-source-newline` rule. (#2384) --- .../__tests__/index.js | 30 +++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) diff --git a/lib/rules/no-missing-end-of-source-newline/__tests__/index.js b/lib/rules/no-missing-end-of-source-newline/__tests__/index.js index 8a79f99e7e..c654be1481 100644 --- a/lib/rules/no-missing-end-of-source-newline/__tests__/index.js +++ b/lib/rules/no-missing-end-of-source-newline/__tests__/index.js @@ -17,8 +17,12 @@ testRule(rule, { code: "\n", }, { code: "a { color: pink; }\n", + }, { + code: "a { color: pink; }\r\n", }, { code: "a { color: pink; }\n\n\n", + }, { + code: "a { color: pink; }\r\n\r\n\r\n", } ], reject: [ { @@ -31,6 +35,21 @@ testRule(rule, { message: messages.rejected, line: 4, column: 19, + }, { + code: "a { color: pink; }\r\n\r\n\r\nb{ color: orange; }", + message: messages.rejected, + line: 4, + column: 19, + }, { + code: "&.active {\n top:\n .tab {}\n}", + message: messages.rejected, + line: 4, + column: 1, + }, { + code: "&.active {\r\n top:\r\n .tab {}\r\n}", + message: messages.rejected, + line: 4, + column: 1, } ], }) @@ -40,9 +59,11 @@ testRule(rule, { skipBasicChecks: true, syntax: "sugarss", - accept: [{ + accept: [ { code: "a\n", - }], + }, { + code: "a\r\n", + } ], reject: [ { code: "a", @@ -54,5 +75,10 @@ testRule(rule, { message: messages.rejected, line: 2, column: 17, + }, { + code: "body\r\n padding: 5% 2% 5%", + message: messages.rejected, + line: 2, + column: 17, } ], }) From 1dca9aeca0245826db7e89517446a9e9b393c5d2 Mon Sep 17 00:00:00 2001 From: Casey Ydenberg Date: Sun, 26 Feb 2017 17:29:23 -0700 Subject: [PATCH 04/15] Print out filenames/globs when files do not exist (#2328) --- lib/__tests__/standalone.test.js | 78 ++++++++++++++++++++++++++++++-- lib/standalone.js | 14 +++++- 2 files changed, 87 insertions(+), 5 deletions(-) diff --git a/lib/__tests__/standalone.test.js b/lib/__tests__/standalone.test.js index b62971e6ac..5dfe1663db 100644 --- a/lib/__tests__/standalone.test.js +++ b/lib/__tests__/standalone.test.js @@ -79,7 +79,7 @@ it("standalone without input css and file(s) should throw error", () => { }) it("standalone with non-existent-file should throw error with code 80", () => { - const expectedError = new Error("Files glob patterns specified did not match any files") + const expectedError = new Error(`${fixturesPath}/non-existent-file.css does not match any files`) expectedError.code = 80 return standalone({ @@ -87,13 +87,13 @@ it("standalone with non-existent-file should throw error with code 80", () => { config: configBlockNoEmpty, }).then(() => { throw new Error("should not have succeeded") - }).catch(actualError => { + }, actualError => { expect(actualError).toEqual(expectedError) }) }) it("standalone with non-existent-file and allowEmptyInput false should throw error with code 80", () => { - const expectedError = new Error("Files glob patterns specified did not match any files") + const expectedError = new Error(`${fixturesPath}/non-existent-file.css does not match any files`) expectedError.code = 80 return standalone({ @@ -102,7 +102,77 @@ it("standalone with non-existent-file and allowEmptyInput false should throw err allowEmptyInput: false, }).then(() => { throw new Error("should not have succeeded") - }).catch(actualError => { + }, actualError => { + expect(actualError).toEqual(expectedError) + }) +}) + +it("standalone with two non-existent-files false should throw error with code 80", () => { + const expectedError = new Error(`${fixturesPath}/non-existent-file.css and ${fixturesPath}/another-non-existent-file.css do not match any files`) + expectedError.code = 80 + + return standalone({ + files: [ `${fixturesPath}/non-existent-file.css`, `${fixturesPath}/another-non-existent-file.css` ], + config: configBlockNoEmpty, + }).then(() => { + throw new Error("should not have succeeded") + }, actualError => { + expect(actualError).toEqual(expectedError) + }) +}) + +it("standalone with three or more non-existent-files false should throw error with code 80", () => { + const expectedError = new Error(`${fixturesPath}/non-existent-file.css, ${fixturesPath}/another-non-existent-file.css and ${fixturesPath}/third-non-existent-file.css do not match any files`) + expectedError.code = 80 + + return standalone({ + files: [ `${fixturesPath}/non-existent-file.css`, `${fixturesPath}/another-non-existent-file.css`, `${fixturesPath}/third-non-existent-file.css` ], + config: configBlockNoEmpty, + }).then(() => { + throw new Error("should not have succeeded") + }, actualError => { + expect(actualError).toEqual(expectedError) + }) +}) + +it("standalone with a glob that doesn't match anything false should throw error with code 80", () => { + const expectedError = new Error(`${fixturesPath}/nodir/**/*.css does not match any files`) + expectedError.code = 80 + + return standalone({ + files: [`${fixturesPath}/nodir/**/*.css`], + config: configBlockNoEmpty, + }).then(() => { + throw new Error("should not have succeeded") + }, actualError => { + expect(actualError).toEqual(expectedError) + }) +}) + +it("standalone with two globs that don't match anything should throw error with code 80", () => { + const expectedError = new Error(`${fixturesPath}/nodir/**/*.css and ${fixturesPath}/anotherdir/**/*.css do not match any files`) + expectedError.code = 80 + + return standalone({ + files: [ `${fixturesPath}/nodir/**/*.css`, `${fixturesPath}/anotherdir/**/*.css` ], + config: configBlockNoEmpty, + }).then(() => { + throw new Error("should not have succeeded") + }, actualError => { + expect(actualError).toEqual(expectedError) + }) +}) + +it("standalone with three globs that don't match anything false should throw error with code 80", () => { + const expectedError = new Error(`${fixturesPath}/nodir/**/*.css, ${fixturesPath}/anotherdir/**/*.css and ${fixturesPath}/athird/**/*.css do not match any files`) + expectedError.code = 80 + + return standalone({ + files: [ `${fixturesPath}/nodir/**/*.css`, `${fixturesPath}/anotherdir/**/*.css`, `${fixturesPath}/athird/**/*.css` ], + config: configBlockNoEmpty, + }).then(() => { + throw new Error("should not have succeeded") + }, actualError => { expect(actualError).toEqual(expectedError) }) }) diff --git a/lib/standalone.js b/lib/standalone.js index f9c8df3d60..b8ef347d03 100644 --- a/lib/standalone.js +++ b/lib/standalone.js @@ -77,7 +77,19 @@ module.exports = function (options/*: Object */)/*: Promise { if (!filePaths.length) { if (allowEmptyInput === undefined || !allowEmptyInput) { - const err/*: Object*/ = new Error("Files glob patterns specified did not match any files") + const message = (files => { + if (typeof files === "string") { + return `${files} does` + } + // seperate files into last (last file) and initial) all the others + const initial = files.slice(0) + const last = initial.pop() + // join into a comma seperated string of file names + const ending = (files.length > 1 ? `and ${last} do` : `${last} does`) + return `${initial.join(", ")} ${ending}`.trim() + })(files) + " not match any files" + + const err/*: Object*/ = new Error(message) err.code = 80 throw err } else { From 4568bbb7054540a5581ff2c8c37f1f6c9f82af56 Mon Sep 17 00:00:00 2001 From: David Clark Date: Sun, 26 Feb 2017 19:30:55 -0500 Subject: [PATCH 05/15] Update CHANGELOG.md --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 10bc08b5a8..1e8fc71a66 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,7 @@ # Head - Added: support for asynchronous plugin rules ([#2351](https://github.com/stylelint/stylelint/pull/2351)). +- Fixed: more helpful messages when file globs do not match any files ([#2328](https://github.com/stylelint/stylelint/pull/2328)). # 7.9.0 From 9c7c38a7785fbfeb96fff1f75b68b5babb960847 Mon Sep 17 00:00:00 2001 From: Casey Ydenberg Date: Tue, 28 Feb 2017 06:17:15 -0700 Subject: [PATCH 06/15] Add at-rule-semicolon-space-before rule (#2388) * Add README for at-rule-semicolon-space-before * Wrote failing tests for at-rule-semicolon-space-before * Add edge case tests * Set up boilerplate for at-rule-semicolon-space-before * Logic there - a few problems * Check carefully column counts * Set skipBasicChecks to true for the 'always' tests * Add at-rule-semicolon-space-before to documentation * Add some more multiline tests * Amend documentation for at-rule-semicolon-space-before --- docs/user-guide/example-config.md | 1 + docs/user-guide/rules.md | 1 + .../at-rule-semicolon-space-before/README.md | 45 +++++++ .../__tests__/index.js | 120 ++++++++++++++++++ .../at-rule-semicolon-space-before/index.js | 57 +++++++++ lib/rules/index.js | 2 + 6 files changed, 226 insertions(+) create mode 100644 lib/rules/at-rule-semicolon-space-before/README.md create mode 100644 lib/rules/at-rule-semicolon-space-before/__tests__/index.js create mode 100644 lib/rules/at-rule-semicolon-space-before/index.js diff --git a/docs/user-guide/example-config.md b/docs/user-guide/example-config.md index 40069135f3..a3babaa01a 100644 --- a/docs/user-guide/example-config.md +++ b/docs/user-guide/example-config.md @@ -15,6 +15,7 @@ You might want to learn a little about [how rules are named and how they work to "at-rule-no-unknown": true, "at-rule-no-vendor-prefix": true, "at-rule-semicolon-newline-after": "always", + "at-rule-semicolon-space-before": "always"|"never", "at-rule-whitelist": string|[], "block-closing-brace-empty-line-before": "always-multi-line"|"never", "block-closing-brace-newline-after": "always"|"always-single-line"|"never-single-line"|"always-multi-line"|"never-multi-line", diff --git a/docs/user-guide/rules.md b/docs/user-guide/rules.md index 0d67b7eab5..508e9bad0b 100644 --- a/docs/user-guide/rules.md +++ b/docs/user-guide/rules.md @@ -238,6 +238,7 @@ Here are all the rules within stylelint, grouped by the [*thing*](http://apps.wo - [`at-rule-no-unknown`](../../lib/rules/at-rule-no-unknown/README.md): Disallow unknown at-rules. - [`at-rule-no-vendor-prefix`](../../lib/rules/at-rule-no-vendor-prefix/README.md): Disallow vendor prefixes for at-rules. - [`at-rule-semicolon-newline-after`](../../lib/rules/at-rule-semicolon-newline-after/README.md): Require a newline after the semicolon of at-rules. +- [`at-rule-semicolon-space-before`](../../lib/rules/at-rule-semicolon-space-before/README.md): Require a single space or disallow whitespace before the semicolons of at rules. - [`at-rule-whitelist`](../../lib/rules/at-rule-whitelist/README.md): Specify a whitelist of allowed at-rules. ### `stylelint-disable` comment diff --git a/lib/rules/at-rule-semicolon-space-before/README.md b/lib/rules/at-rule-semicolon-space-before/README.md new file mode 100644 index 0000000000..b8258f8bb2 --- /dev/null +++ b/lib/rules/at-rule-semicolon-space-before/README.md @@ -0,0 +1,45 @@ +# at-rule-semicolon-space-before + +Require a single space or disallow whitespace before the semicolons at-rules. + +```css +@import "components/buttons"; +/** ↑ + * The space before this semicolon */ +``` + +## Options + +`string`: `"always"|"never"` + +### `"always"` + +There *must always* be a single space before the semicolons. + +The following patterns is considered a warning: + +```css +@import "components/buttons"; +``` + +The following pattern is *not* considered a warning: + +```css +@import "components/buttons" ; +``` + +### `"never"` + +There *must never* be a single space before the semicolons. + +The following patterns is considered a warning: + +```css +@import "components/buttons" ; +``` + +The following pattern is *not* considered a warning: + +```css +@import "components/buttons"; +``` diff --git a/lib/rules/at-rule-semicolon-space-before/__tests__/index.js b/lib/rules/at-rule-semicolon-space-before/__tests__/index.js new file mode 100644 index 0000000000..b4386712cc --- /dev/null +++ b/lib/rules/at-rule-semicolon-space-before/__tests__/index.js @@ -0,0 +1,120 @@ +"use strict" + +const messages = require("..").messages +const ruleName = require("..").ruleName +const rules = require("../../../rules") + +const rule = rules[ruleName] + +testRule(rule, { + ruleName, + config: ["always"], + skipBasicChecks: true, + + accept: [ { + code: "@import \"styles/mystyle\" ;", + }, { + code: "@font-face {\n font-family: \"MyFont\"; src: url(\"myfont.woff2\") format(\"woff2\");\n}", + }, { + code: "@font-face {\n font-family: \"MyFont\"; src: url(\"myfont.woff2\") format(\"woff2\");\n};", + }, { + code: "a { color: @brand-primary; }", + }, { + code: "@myatrule \"valuehassemicolon;\" ;", + }, { + code: "@import url(http://www.example.com/alocation;withsemicolon) ;", + }, { + code: "@import /*my styles;*/ \"styles/mystyle\" ;", + }, { + code: "@import\nurl('landscape.css')\nprojection ;", + } ], + + reject: [ { + code: "@import \"styles/mystyle\";", + message: messages.expectedBefore(), + line: 1, + column: 24, + }, { + code: "@import \"styles/mystyle\" ;", + message: messages.expectedBefore(), + line: 1, + column: 26, + }, { + code: "@import \"styles/mystyle\"\t;", + message: messages.expectedBefore(), + line: 1, + column: 25, + }, { + code: "@import \"styles/mystyle\"\n;", + message: messages.expectedBefore(), + line: 1, + column: 25, + }, { + code: "@import \"styles/mystyle\"\r\n;", + description: "CRLF", + message: messages.expectedBefore(), + line: 1, + column: 26, + }, { + code: "@import\nurl('landscape.css')\nprojection;", + message: messages.expectedBefore(), + line: 3, + column: 10, + } ], +}) + +testRule(rule, { + ruleName, + config: ["never"], + + accept: [ { + code: "@import \"styles/mystyle\";", + }, { + code: "@font-face {\n font-family: \"MyFont\" ; src: url(\"myfont.woff2\") format(\"woff2\") ;\n}", + }, { + code: "@font-face {\n font-family: \"MyFont\" ; src: url(\"myfont.woff2\") format(\"woff2\") ;\n} ;", + }, { + code: "a { color: @brand-primary ; }", + }, { + code: "@myatrule \"valuehassemicolon ;\";", + }, { + code: "@import url(http://www.example.com/alocation+;withsemicolon);", + }, { + code: "@import /*my styles ;*/ \"styles/mystyle\";", + }, { + code: "@import\nurl('landscape.css')\nprojection;", + } ], + + reject: [ { + code: "@import \"styles/mystyle\" ;", + message: messages.rejectedBefore(), + line: 1, + column: 25, + }, { + code: "@import \"styles/mystyle\" ;", + message: messages.rejectedBefore(), + line: 1, + column: 26, + }, { + code: "@import \"styles/mystyle\"\t;", + message: messages.rejectedBefore(), + line: 1, + column: 25, + }, { + code: "@import \"styles/mystyle\"\n;", + message: messages.rejectedBefore(), + line: 1, + column: 25, + }, { + code: "@import \"styles/mystyle\"\r\n;", + description: "CRLF", + message: messages.rejectedBefore(), + line: 1, + column: 26, + }, { + code: "@import\nurl('landscape.css')\nprojection ;", + message: messages.rejectedBefore(), + line: 3, + column: 11, + } ], +}) diff --git a/lib/rules/at-rule-semicolon-space-before/index.js b/lib/rules/at-rule-semicolon-space-before/index.js new file mode 100644 index 0000000000..436f23cf48 --- /dev/null +++ b/lib/rules/at-rule-semicolon-space-before/index.js @@ -0,0 +1,57 @@ +"use strict" + +const hasBlock = require("../../utils/hasBlock") +const rawNodeString = require("../../utils/rawNodeString") +const report = require("../../utils/report") +const ruleMessages = require("../../utils/ruleMessages") +const validateOptions = require("../../utils/validateOptions") +const whitespaceChecker = require("../../utils/whitespaceChecker") + +const ruleName = "at-rule-semicolon-space-before" + +const messages = ruleMessages(ruleName, { + expectedBefore: () => "Expected single space before \";\"", + rejectedBefore: () => "Unexpected whitespace before \";\"", +}) + +const rule = function (expectation) { + const checker = whitespaceChecker("space", expectation, messages) + + return (root, result) => { + const validOptions = validateOptions(result, ruleName, { + actual: expectation, + possible: [ + "always", + "never", + ], + }) + if (!validOptions) { + return + } + + root.walkAtRules(atRule => { + if (hasBlock(atRule)) { + return + } + const nodeString = rawNodeString(atRule) + + checker.before({ + source: nodeString, + index: nodeString.length, + err: m => { + report({ + message: m, + node: atRule, + index: nodeString.length - 1, + result, + ruleName, + }) + }, + }) + }) + } +} + +rule.ruleName = ruleName +rule.messages = messages +module.exports = rule diff --git a/lib/rules/index.js b/lib/rules/index.js index 6e1ffbbf63..edfed29805 100644 --- a/lib/rules/index.js +++ b/lib/rules/index.js @@ -4,6 +4,7 @@ const atRuleBlacklist = require("./at-rule-blacklist") const atRuleEmptyLineBefore = require("./at-rule-empty-line-before") const atRuleNameCase = require("./at-rule-name-case") const atRuleNameNewlineAfter = require("./at-rule-name-newline-after") +const atRuleSemicolonSpaceBefore = require("./at-rule-semicolon-space-before") const atRuleNameSpaceAfter = require("./at-rule-name-space-after") const atRuleNoUnknown = require("./at-rule-no-unknown") const atRuleNoVendorPrefix = require("./at-rule-no-vendor-prefix") @@ -180,6 +181,7 @@ module.exports = { "at-rule-empty-line-before": atRuleEmptyLineBefore, "at-rule-name-case": atRuleNameCase, "at-rule-name-newline-after": atRuleNameNewlineAfter, + "at-rule-semicolon-space-before": atRuleSemicolonSpaceBefore, "at-rule-name-space-after": atRuleNameSpaceAfter, "at-rule-no-unknown": atRuleNoUnknown, "at-rule-no-vendor-prefix": atRuleNoVendorPrefix, From 46062db432ff92a3b2c206a5df8812335dc019c1 Mon Sep 17 00:00:00 2001 From: David Clark Date: Tue, 28 Feb 2017 08:17:45 -0500 Subject: [PATCH 07/15] Update CHANGELOG.md --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1e8fc71a66..eb32450ee1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,7 @@ # Head - Added: support for asynchronous plugin rules ([#2351](https://github.com/stylelint/stylelint/pull/2351)). +- Added: `at-rule-semicolon-space-before rule` rulel ([#2388](https://github.com/stylelint/stylelint/pull/2388)). - Fixed: more helpful messages when file globs do not match any files ([#2328](https://github.com/stylelint/stylelint/pull/2328)). # 7.9.0 From 6a260b82ab0567a5a28efe7c18c4aa9b09e4475b Mon Sep 17 00:00:00 2001 From: Richard Hallows Date: Tue, 28 Feb 2017 13:52:08 +0000 Subject: [PATCH 08/15] Update CHANGELOG.md --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index eb32450ee1..045358f9dc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,7 +1,7 @@ # Head - Added: support for asynchronous plugin rules ([#2351](https://github.com/stylelint/stylelint/pull/2351)). -- Added: `at-rule-semicolon-space-before rule` rulel ([#2388](https://github.com/stylelint/stylelint/pull/2388)). +- Added: `at-rule-semicolon-space-before` rule ([#2388](https://github.com/stylelint/stylelint/pull/2388)). - Fixed: more helpful messages when file globs do not match any files ([#2328](https://github.com/stylelint/stylelint/pull/2328)). # 7.9.0 From b7bd2cbe954fe2c74ce46bdea3e5383f68411eb7 Mon Sep 17 00:00:00 2001 From: Aleks Hudochenkov Date: Fri, 3 Mar 2017 04:11:06 +0300 Subject: [PATCH 09/15] Fix the example for Custom Message in docs (#2409) --- docs/user-guide/configuration.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/user-guide/configuration.md b/docs/user-guide/configuration.md index 47f78a36a3..1138b622ac 100644 --- a/docs/user-guide/configuration.md +++ b/docs/user-guide/configuration.md @@ -162,7 +162,7 @@ All rules accept a `message` secondary option that, if provided, will be substit "message": "Lowercase letters are easier to distinguish from numbers" } ], "indentation": [ 2, { - "ignore": ["block"], + "except": ["block"], "message": "Please use 2 spaces for indentation. Tabs make The Architect grumpy.", "severity": "warning" } ] From e54956e9fc2b9fd821e7378be34b948930499d6e Mon Sep 17 00:00:00 2001 From: "greenkeeper[bot]" Date: Fri, 3 Mar 2017 22:41:28 +0000 Subject: [PATCH 10/15] chore(package): update eslint to version 3.17.0 https://greenkeeper.io/ --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 443871de6a..91b15042a4 100644 --- a/package.json +++ b/package.json @@ -75,7 +75,7 @@ "common-tags": "^1.3.0", "coveralls": "^2.11.9", "d3-queue": "^3.0.3", - "eslint": "~3.16.0", + "eslint": "~3.17.0", "eslint-config-stylelint": "^6.0.0", "flow-bin": "^0.40.0", "jest": "^19.0.1", From a7b03023b5c9f659ce7b5e5ac1bb089bb86363a7 Mon Sep 17 00:00:00 2001 From: "greenkeeper[bot]" Date: Sun, 5 Mar 2017 01:14:37 +0000 Subject: [PATCH 11/15] chore(package): update flow-bin to version 0.41.0 https://greenkeeper.io/ --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 443871de6a..a75f5cd65e 100644 --- a/package.json +++ b/package.json @@ -77,7 +77,7 @@ "d3-queue": "^3.0.3", "eslint": "~3.16.0", "eslint-config-stylelint": "^6.0.0", - "flow-bin": "^0.40.0", + "flow-bin": "^0.41.0", "jest": "^19.0.1", "npm-run-all": "^4.0.0", "npmpub": "^3.0.1", From be17873db6dfffbfb42c4b214bae4a4d11451be3 Mon Sep 17 00:00:00 2001 From: Jakub Wilk Date: Tue, 7 Mar 2017 14:44:03 +0100 Subject: [PATCH 12/15] Fix typos (#2412) --- CHANGELOG.md | 6 +++--- docs/developer-guide/plugins.md | 4 ++-- docs/developer-guide/rules.md | 4 ++-- docs/user-guide/about-rules.md | 2 +- docs/user-guide/complementary-tools.md | 2 +- docs/user-guide/configuration.md | 2 +- docs/user-guide/faq.md | 2 +- lib/rules/selector-class-pattern/README.md | 2 +- 8 files changed, 12 insertions(+), 12 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 045358f9dc..c2633b0ece 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -400,7 +400,7 @@ - Added: `selector-no-qualifying-type` rule. - Fixed: `number-leading-zero` will not check `@import` at-rules. -- Fixed: `selector-class-pattern` now ignores non-ouputting Less mixin definitions and called Less mixins. +- Fixed: `selector-class-pattern` now ignores non-outputting Less mixin definitions and called Less mixins. - Fixed: `value-keyword-case` now accounts for camelCase keywords (e.g. `optimizeSpeed`, `optimizeLegibility` and `geometricPrecision`) when the `lower` option is used. - Fixed: `testUtils` and `stylelint.createRuleTester` module mistakes. @@ -721,11 +721,11 @@ - support for YAML `.stylelintrc` - support for `stylelint.config.js` - support for `stylelint` property in `package.json` - - alternate config loading system, which stops at the first config foun + - alternate config loading system, which stops at the first config found - Added: asynchronicity to the PostCSS plugin. - Added: `ignoreFiles` option to config. - Added: `configFile` option to Node.js API. -- Fixed: `comment-whitespace-inside` now ignores ignores copyright (`/*! `) and sourcemap (`/*# `) comments. +- Fixed: `comment-whitespace-inside` now ignores copyright (`/*! `) and sourcemap (`/*# `) comments. - Fixed: `rule-no-duplicate-properties` now ignores the `src` property. # 2.3.7 diff --git a/docs/developer-guide/plugins.md b/docs/developer-guide/plugins.md index 43e69d4628..ef523e69a1 100644 --- a/docs/developer-guide/plugins.md +++ b/docs/developer-guide/plugins.md @@ -32,7 +32,7 @@ Your plugin's rule name must be namespaced, e.g. `your-namespace/your-rule-name` `stylelint.createPlugin(ruleName, ruleFunction)` ensures that your plugin will be setup properly alongside other rules. -In order for your plugin rule to work with the [standard configuration format](../user-guide/configuration.md#rules), `ruleFunction` should accept 2 arguments: the primary option and, optionally, an secondary options object. +In order for your plugin rule to work with the [standard configuration format](../user-guide/configuration.md#rules), `ruleFunction` should accept 2 arguments: the primary option and, optionally, a secondary options object. `ruleFunction` should return a function that is essentially a little [PostCSS plugin](https://github.com/postcss/postcss/blob/master/docs/writing-a-plugin.md): it takes 2 arguments: the PostCSS Root (the parsed AST), and the PostCSS LazyResult. You'll have to [learn about the PostCSS API](https://github.com/postcss/postcss/blob/master/docs/api.md). @@ -159,7 +159,7 @@ In addition to the standard parsers mentioned in the ["Working on rules"](rules. - [postcss-resolve-nested-selector](https://github.com/davidtheclark/postcss-resolve-nested-selector): Given a (nested) selector in a PostCSS AST, return an array of resolved selectors. - [style-search](https://github.com/davidtheclark/style-search): Search CSS (and CSS-like) strings, with sensitivity to whether matches occur inside strings, comments, and functions. -Have a look through [stylelint's internal utils](https://github.com/stylelint/stylelint/tree/master/lib/utils) and if you come across one that you need in your plugin, then please consider helping us extract it out into a external module. +Have a look through [stylelint's internal utils](https://github.com/stylelint/stylelint/tree/master/lib/utils) and if you come across one that you need in your plugin, then please consider helping us extract it out into an external module. ## Testing plugins diff --git a/docs/developer-guide/rules.md b/docs/developer-guide/rules.md index 26bc68cd2a..3f0d015a63 100644 --- a/docs/developer-guide/rules.md +++ b/docs/developer-guide/rules.md @@ -178,7 +178,7 @@ Take the form of: - Use complete CSS patterns i.e. avoid ellipses (`...`) - Use standard CSS syntax (and use `css` code fences) by default. -- Use the minimum amount of code possible to communicate the patten e.g. if the rule targets selectors then use an empty rule e.g. `{}`. +- Use the minimum amount of code possible to communicate the pattern e.g. if the rule targets selectors then use an empty rule e.g. `{}`. - Use `{}`, rather than `{ }` for empty rules. - Use the `a` type selector by default. - Use the `@media` at-rules by default. @@ -195,7 +195,7 @@ The final step is to add references to the new rule in the following places: Once you have something to show, you'll create a [pull request](https://github.com/stylelint/stylelint/compare) to continue the conversation. -## Adding a option to an existing rule +## Adding an option to an existing rule First, open [an issue](https://github.com/stylelint/stylelint/issues/new) about the option you wish to add. We'll discuss its functionality and name there. diff --git a/docs/user-guide/about-rules.md b/docs/user-guide/about-rules.md index 13e8319417..ecc26ce8b7 100644 --- a/docs/user-guide/about-rules.md +++ b/docs/user-guide/about-rules.md @@ -354,7 +354,7 @@ Say you want to disallow the value `none` for the `border` properties. You can d Most `` values are *functions*. As such, they can be (dis)allowed using either the `function-blacklist` or `function-whitelist` rules. There are two other color representations that aren't functions: named colors and hex colors. There are two specific rules that (dis)allow these: `color-named` and `color-no-hex`, respectively. -Say you want to enforce using a named color *if one exists for your chosen color* and use `hwb` color if one does not, e.g: +Say you want to enforce using a named color *if one exists for your chosen color* and use `hwb` color if one does not, e.g.: ```css a { diff --git a/docs/user-guide/complementary-tools.md b/docs/user-guide/complementary-tools.md index 68668e1af3..3d9f87d2f6 100644 --- a/docs/user-guide/complementary-tools.md +++ b/docs/user-guide/complementary-tools.md @@ -13,7 +13,7 @@ A list of complementary tools built and maintained by the community. ## Build tool plugins - [broccoli-stylelint](https://github.com/billybonks/broccoli-stylelint): A Broccoli plugin for stylelint. -- [ember-cli-stylelint](https://github.com/billybonks/ember-cli-stylelint): A Ember CLI plugin for stylelint. +- [ember-cli-stylelint](https://github.com/billybonks/ember-cli-stylelint): An Ember CLI plugin for stylelint. - [grunt-stylelint](https://github.com/wikimedia/grunt-stylelint): A Grunt plugin for stylelint. - [gulp-stylelint](https://github.com/olegskl/gulp-stylelint): A gulp plugin for stylelint. - [stylelint-webpack-plugin](https://github.com/vieron/stylelint-webpack-plugin): A webpack plugin for stylelint. diff --git a/docs/user-guide/configuration.md b/docs/user-guide/configuration.md index 1138b622ac..be23057ae8 100644 --- a/docs/user-guide/configuration.md +++ b/docs/user-guide/configuration.md @@ -203,7 +203,7 @@ Or starting with `stylelint-config-standard`, then layering `myExtendableConfig` } ``` -The value of `"extends"` is a "locater" (or an array of "locaters") that is ultimately `require()`d, so can fit whatever format works with Node's `require.resolve()` algorithm. That means the a "locater" can be: +The value of `"extends"` is a "locater" (or an array of "locaters") that is ultimately `require()`d, so can fit whatever format works with Node's `require.resolve()` algorithm. That means a "locater" can be: - The name of a module in `node_modules` (e.g. `stylelint-config-standard`; that module's `main` file must be a valid JSON configuration) - An absolute path to a file (which makes sense if you're creating a JS object in a Node context and passing it in) with a `.js` or `.json` extension. diff --git a/docs/user-guide/faq.md b/docs/user-guide/faq.md index 8117a3a52d..cd6f2617ed 100644 --- a/docs/user-guide/faq.md +++ b/docs/user-guide/faq.md @@ -144,7 +144,7 @@ All these patterns disallow CSS identifiers that start with a digit, two hyphens Use the [`defaultSeverity`](configuration.md#defaultseverity) configuration option. -## Can I bundle more than one sharable config within a npm package? +## Can I bundle more than one sharable config within an npm package? A user can `require()` any file in your npm package, so all you need to do is document which paths point to configs (e.g. `require('my-package/config-2')`). diff --git a/lib/rules/selector-class-pattern/README.md b/lib/rules/selector-class-pattern/README.md index ee9f9ae662..f6cb4daedb 100644 --- a/lib/rules/selector-class-pattern/README.md +++ b/lib/rules/selector-class-pattern/README.md @@ -8,7 +8,7 @@ Specify a pattern for class selectors. * These class selectors */ ``` -This rule ignores non-ouputting Less mixin definitions and called Less mixins. +This rule ignores non-outputting Less mixin definitions and called Less mixins. ## Options From 329d0aadd381d0de350c6f8b69aaf82c1db86ac8 Mon Sep 17 00:00:00 2001 From: Aleks Hudochenkov Date: Tue, 7 Mar 2017 16:54:37 +0300 Subject: [PATCH 13/15] Fix custom properties sets followed by comments in no-extra-semicolons (#2396) * Add tests for no-extra-semicolons * Fixed: it is break my mind :sob:. * Remove extra parentheses --- .../no-extra-semicolons/__tests__/index.js | 22 +++++++++++++++++++ lib/rules/no-extra-semicolons/index.js | 21 ++++++++++++++++-- 2 files changed, 41 insertions(+), 2 deletions(-) diff --git a/lib/rules/no-extra-semicolons/__tests__/index.js b/lib/rules/no-extra-semicolons/__tests__/index.js index d0d30a825b..6256c9110e 100644 --- a/lib/rules/no-extra-semicolons/__tests__/index.js +++ b/lib/rules/no-extra-semicolons/__tests__/index.js @@ -40,6 +40,8 @@ testRule(rule, { code: ":root { --foo: red; --bar: blue; }", }, { code: ":root { --foo: { color: red }; --bar: { color: blue }; --foo-bar: { color: blue }; --bar-foo: { color: red }; }", + }, { + code: ":root { --foo: { color: red }; /* comment */ --bar: { color: blue };/* comment */ --foo-bar: { color: blue }; --bar-foo: { color: red }; }", } ], reject: [ { @@ -502,6 +504,26 @@ testRule(rule, { message: messages.rejected, line: 1, column: 55, + }, { + code: ":root { --foo: { color: red };/* comment */;}", + message: messages.rejected, + line: 1, + column: 44, + }, { + code: ":root { --foo: { color: red };/* comment */; --bar: { color: blue }; --bar-foo: { color: red }; }", + message: messages.rejected, + line: 1, + column: 44, + }, { + code: ":root { --foo: { color: red }; --bar: { color: blue };/* comment 1 */ /* comment 2 */; --bar-foo: { color: red }; }", + message: messages.rejected, + line: 1, + column: 86, + }, { + code: ":root { --foo: { color: red }; --bar: { color: blue }/* comment 1 */; /* comment 2 */; --bar-foo: { color: red }; }", + message: messages.rejected, + line: 1, + column: 86, }, { code: ":root { --foo: { color: red }; --bar: { color: blue }; --bar-foo: { color: red };; }", message: messages.rejected, diff --git a/lib/rules/no-extra-semicolons/index.js b/lib/rules/no-extra-semicolons/index.js index da7b52c27d..0ed3cf8951 100644 --- a/lib/rules/no-extra-semicolons/index.js +++ b/lib/rules/no-extra-semicolons/index.js @@ -14,7 +14,7 @@ const messages = ruleMessages(ruleName, { }) function getOffsetByNode(node) { - const string = node.root().toString() + const string = node.root().source.input.css const nodeColumn = node.source.start.column const nodeLine = node.source.start.line let line = 1 @@ -54,7 +54,7 @@ const rule = function (actual) { } root.walk(node => { - const rawBeforeNode = node.raws.before + let rawBeforeNode = node.raws.before if (rawBeforeNode && rawBeforeNode.trim().length !== 0) { let allowedSemi = 0 @@ -64,6 +64,23 @@ const rule = function (actual) { allowedSemi = 1 } + const next = node.next() + + // Ignore semicolon before comment if next node is custom properties sets or comment + if (node.type === "comment" && next + && (isCustomPropertySet(next) && node.parent.index(next) > 0 || next.type === "comment") + ) { + allowedSemi = 1 + } + + const prev = node.prev() + + // Adding previous node string to custom properties set if previous node is comment + if (isCustomPropertySet(node) && node.parent.index(node) > 0 && prev && prev.type === "comment") { + rawBeforeNode = prev.toString() + rawBeforeNode + allowedSemi = 0 + } + styleSearch({ source: rawBeforeNode, target: ";" }, (match, count) => { if (count === allowedSemi) { return From c8b30d761200b0c49ffe14456f08e78a48716ba4 Mon Sep 17 00:00:00 2001 From: David Clark Date: Tue, 7 Mar 2017 06:55:31 -0700 Subject: [PATCH 14/15] Update CHANGELOG.md --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index c2633b0ece..4ab6422756 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ - Added: support for asynchronous plugin rules ([#2351](https://github.com/stylelint/stylelint/pull/2351)). - Added: `at-rule-semicolon-space-before` rule ([#2388](https://github.com/stylelint/stylelint/pull/2388)). - Fixed: more helpful messages when file globs do not match any files ([#2328](https://github.com/stylelint/stylelint/pull/2328)). +- Fixed: `no-extra-semicolons` false positives for comments are custom property sets ([#2396](https://github.com/stylelint/stylelint/pull/2396)). # 7.9.0 From 16e8cc79f8d08cd9502fd9ab58f9d137c08709b5 Mon Sep 17 00:00:00 2001 From: Ivan Zusko Date: Wed, 8 Mar 2017 15:33:31 +0200 Subject: [PATCH 15/15] Add flow comments annotation to function signatures (#2319) * add flow comments annotation * chore(annotations): removed constants annotations; add more specificity to returning object; * feat(flow): add postcss type; remove redundant annotations; --- decls/postcss.js | 11 +++++++++++ lib/assignDisabledRanges.js | 2 +- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/decls/postcss.js b/decls/postcss.js index 782847f374..8de2232398 100644 --- a/decls/postcss.js +++ b/decls/postcss.js @@ -32,3 +32,14 @@ export type postcss$rule = { parent: Object, nodes: Array, } + +export type postcss$result = { + css: string, + root: Object, + stylelint: { + disabledRanges: disabledRangeObject, + ruleSeverities?: Object, + customMessages?: Object, + quiet?: boolean, + }, +} diff --git a/lib/assignDisabledRanges.js b/lib/assignDisabledRanges.js index ae34aeb877..e2452c6383 100644 --- a/lib/assignDisabledRanges.js +++ b/lib/assignDisabledRanges.js @@ -20,7 +20,7 @@ const ALL_RULES = "all" module.exports = function ( root/*: Object*/, result/*: Object*/ -) { +)/*: postcss$result*/ { result.stylelint = result.stylelint || {} // Most of the functions below work via side effects mutating