stylelint-gamut 1.3.1 → 1.3.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,14 +1,17 @@
1
1
  {
2
2
  "name": "stylelint-gamut",
3
- "version": "1.3.1",
3
+ "version": "1.3.3",
4
4
  "description": "Stylelint plugin for working with different color spaces",
5
5
  "main": "src/index.js",
6
6
  "scripts": {
7
+ "format": "prettier --write",
8
+ "lint": "eslint --fix",
7
9
  "test": "jest",
8
10
  "prepare": "husky install"
9
11
  },
10
12
  "lint-staged": {
11
- "*.js": "eslint --fix"
13
+ "*.js": "npm run lint",
14
+ ".": "npm run format"
12
15
  },
13
16
  "engines": {
14
17
  "node": ">=16.0.0"
@@ -40,19 +43,21 @@
40
43
  "stylelint": "^14.0.0 || ^15.0.0"
41
44
  },
42
45
  "devDependencies": {
43
- "eslint": "^8.22.0",
44
- "eslint-config-standard": "^17.0.0",
45
- "eslint-plugin-import": "^2.26.0",
46
- "eslint-plugin-n": "^15.2.4",
47
- "eslint-plugin-promise": "^6.0.0",
48
- "husky": "^8.0.1",
49
- "jest": "^28.1.3",
50
- "jest-cli": "^28.1.3",
51
- "jest-preset-stylelint": "^5.0.4",
52
- "lint-staged": "^13.0.3",
53
- "stylelint": "^14.10.0"
46
+ "eslint": "^8.43.0",
47
+ "eslint-config-prettier": "^8.8.0",
48
+ "eslint-config-standard": "^17.1.0",
49
+ "eslint-plugin-import": "^2.27.5",
50
+ "eslint-plugin-n": "^16.0.0",
51
+ "eslint-plugin-promise": "^6.1.1",
52
+ "husky": "^8.0.3",
53
+ "jest": "^29.5.0",
54
+ "jest-cli": "^29.5.0",
55
+ "jest-preset-stylelint": "^6.1.0",
56
+ "lint-staged": "^13.2.2",
57
+ "prettier": "^2.8.8",
58
+ "stylelint": "^15.7.0"
54
59
  },
55
60
  "dependencies": {
56
- "colorjs.io": "^0.4.0"
61
+ "colorjs.io": "^0.4.5"
57
62
  }
58
63
  }
package/src/README.md CHANGED
@@ -4,9 +4,7 @@ Disallow out of gamut range colors.
4
4
 
5
5
  <!-- prettier-ignore -->
6
6
  ```css
7
- a { color: lch(48% 82 283) }
8
- /** ↑
9
- * This color is out of sRGB gamut range */
7
+ a { color: lch(48% 82 283) } /* This color is out of sRGB gamut range */
10
8
  ```
11
9
 
12
10
  Colors declared using lch, oklch, lab and oklab functions can move from sRGB to P3 or Rec2020 color spaces, which are not supported by most of screens right now. It can happen by mistake. For instance, by converting colors from one space to another.
@@ -17,20 +15,18 @@ This rule checks if the color is in sRGB, p3 or rec2020 space. If it's not in sR
17
15
  @media (color-gamut: p3) {
18
16
  a {
19
17
  color: lch(29.8% 42.5 109.485);
18
+ /* This color is in p3 gamut range */
20
19
  }
21
20
  }
22
- /** ↑
23
- * This color is in p3 gamut range */
24
21
  ```
25
22
 
26
23
  ```css
27
24
  @media (color-gamut: rec2020) {
28
25
  a {
29
26
  color: lch(25.1% 42.5 109.485);
27
+ /* This color is in rec2020 gamut range */
30
28
  }
31
29
  }
32
- /** ↑
33
- * This color is in rec2020 gamut range */
34
30
  ```
35
31
 
36
32
  In case of **css custom properties** you should wrap either the custom property declaration:
package/src/index.js CHANGED
@@ -1,87 +1,108 @@
1
- 'use strict'
1
+ "use strict";
2
2
 
3
- const stylelint = require('stylelint')
4
- const Color = require('colorjs.io').default
5
- const { isInColorGamutP3MediaQuery, isStandardSyntaxProperty, declarationValueIndex, isInColorGamutRec2020MediaQuery } = require('./utils')
3
+ const stylelint = require("stylelint");
4
+ const Color = require("colorjs.io").default;
5
+ const {
6
+ isInColorGamutP3MediaQuery,
7
+ isStandardSyntaxProperty,
8
+ declarationValueIndex,
9
+ isInColorGamutRec2020MediaQuery,
10
+ startsWithNumber,
11
+ } = require("./utils");
6
12
 
7
- const ruleName = 'gamut/color-no-out-gamut-range'
13
+ const ruleName = "gamut/color-no-out-gamut-range";
8
14
 
9
15
  const messages = stylelint.utils.ruleMessages(ruleName, {
10
- rejected: (color) => `Unexpected color out of gamut range "${color}"`
11
- })
16
+ rejected: color => `Unexpected color out of gamut range "${color}"`,
17
+ });
12
18
 
13
19
  const meta = {
14
- url: 'https://github.com/fpetrakov/stylelint-gamut/blob/master/src/README.md'
15
- }
20
+ url: "https://github.com/fpetrakov/stylelint-gamut/blob/master/src/README.md",
21
+ };
16
22
 
17
23
  /** @type {import('stylelint').Rule} */
18
- const ruleFunction = (primary) => {
19
- return (root, result) => {
20
- const validOptions = stylelint.utils.validateOptions(result, ruleName, {
21
- actual: primary
22
- })
23
-
24
- if (!validOptions) {
25
- return
26
- }
27
-
28
- const customProperties = {}
29
-
30
- root.walkDecls((decl) => {
31
- if (!isStandardSyntaxProperty(decl.prop)) return
32
-
33
- const values = decl.value.match(/(oklch|oklab|lab|lch|var)\([^)]+\)/g)
34
- if (values) {
35
- for (const value of values) {
36
- check(value)
37
- }
38
- }
39
-
40
- function check (value) {
41
- if (!value.startsWith('var(--') && value.includes('var(--')) return
42
-
43
- let customPropValue
44
- if (value.startsWith('var(--')) {
45
- const varName = value.slice(4, -1)
46
-
47
- if (customProperties[varName] && !customProperties[varName].inQuery) {
48
- customPropValue = customProperties[varName].value
49
- } else {
50
- return
51
- }
52
- }
53
-
54
- const color = new Color(customPropValue || value)
55
-
56
- if (color.inGamut('srgb')) return
57
-
58
- if (color.inGamut('p3') && isInColorGamutP3MediaQuery(decl)) return
59
-
60
- if (color.inGamut('rec2020') && isInColorGamutRec2020MediaQuery(decl)) return
61
-
62
- if (decl.prop && decl.prop.startsWith('--')) {
63
- customProperties[decl.prop] = { value: decl.value.trim(), inQuery: false }
64
- return
65
- }
66
-
67
- const index = declarationValueIndex(decl)
68
- const endIndex = index + decl.value.length
69
-
70
- stylelint.utils.report({
71
- message: messages.rejected(value),
72
- node: decl,
73
- index,
74
- endIndex,
75
- result,
76
- ruleName
77
- })
78
- }
79
- })
80
- }
81
- }
82
-
83
- ruleFunction.ruleName = ruleName
84
- ruleFunction.messages = messages
85
- ruleFunction.meta = meta
86
-
87
- module.exports = stylelint.createPlugin(ruleName, ruleFunction)
24
+ const ruleFunction = primary => {
25
+ return (root, result) => {
26
+ const validOptions = stylelint.utils.validateOptions(result, ruleName, {
27
+ actual: primary,
28
+ });
29
+
30
+ if (!validOptions) {
31
+ return;
32
+ }
33
+
34
+ const customProperties = {};
35
+
36
+ root.walkDecls(decl => {
37
+ if (!isStandardSyntaxProperty(decl.prop)) return;
38
+
39
+ const values = decl.value.match(
40
+ /(oklch|oklab|lab|lch|var)\([^)]+\)/g,
41
+ );
42
+ if (values) {
43
+ for (const value of values) {
44
+ check(value);
45
+ }
46
+ }
47
+
48
+ // value is e.g. lch(48% 82 283 / 67%)
49
+ function check(value) {
50
+ const shouldBeIgnored =
51
+ !value.startsWith("var(--") &&
52
+ (value.includes("var(--") ||
53
+ !startsWithNumber(value.split("(")[1]));
54
+
55
+ if (shouldBeIgnored) return;
56
+
57
+ let customPropValue;
58
+ if (value.startsWith("var(--")) {
59
+ const varName = value.slice(4, -1);
60
+ if (
61
+ customProperties[varName] &&
62
+ !customProperties[varName].inQuery
63
+ ) {
64
+ customPropValue = customProperties[varName].value;
65
+ } else {
66
+ return;
67
+ }
68
+ }
69
+
70
+ const color = new Color(customPropValue || value);
71
+
72
+ if (color.inGamut("srgb")) return;
73
+ if (color.inGamut("p3") && isInColorGamutP3MediaQuery(decl))
74
+ return;
75
+ if (
76
+ color.inGamut("rec2020") &&
77
+ isInColorGamutRec2020MediaQuery(decl)
78
+ )
79
+ return;
80
+
81
+ if (decl.prop && decl.prop.startsWith("--")) {
82
+ customProperties[decl.prop] = {
83
+ value: decl.value.trim(),
84
+ inQuery: false,
85
+ };
86
+ return;
87
+ }
88
+
89
+ const index = declarationValueIndex(decl);
90
+ const endIndex = index + decl.value.length;
91
+ stylelint.utils.report({
92
+ message: messages.rejected(value),
93
+ node: decl,
94
+ index,
95
+ endIndex,
96
+ result,
97
+ ruleName,
98
+ });
99
+ }
100
+ });
101
+ };
102
+ };
103
+
104
+ ruleFunction.ruleName = ruleName;
105
+ ruleFunction.messages = messages;
106
+ ruleFunction.meta = meta;
107
+
108
+ module.exports = stylelint.createPlugin(ruleName, ruleFunction);
package/src/utils.js CHANGED
@@ -1,4 +1,4 @@
1
- 'use strict'
1
+ "use strict";
2
2
 
3
3
  /**
4
4
  * Get the index of a declaration's value
@@ -6,26 +6,22 @@
6
6
  * @param {import('postcss').Declaration} decl
7
7
  * @returns {number}
8
8
  */
9
- function declarationValueIndex (decl) {
10
- const raws = decl.raws
11
-
12
- return [
13
- // @ts-expect-error -- TS2571: Object is of type 'unknown'.
14
- raws.prop && raws.prop.prefix,
15
- // @ts-expect-error -- TS2571: Object is of type 'unknown'.
16
- (raws.prop && raws.prop.raw) || decl.prop,
17
- // @ts-expect-error -- TS2571: Object is of type 'unknown'.
18
- raws.prop && raws.prop.suffix,
19
- raws.between || ':',
20
- // @ts-expect-error -- TS2339: Property 'prefix' does not exist on type '{ value: string; raw: string; }'.
21
- raws.value && raws.value.prefix
22
- ].reduce((count, str) => {
23
- if (str) {
24
- return count + str.length
25
- }
26
-
27
- return count
28
- }, 0)
9
+ function declarationValueIndex(decl) {
10
+ const raws = decl.raws;
11
+
12
+ return [
13
+ raws.prop && raws.prop.prefix,
14
+ (raws.prop && raws.prop.raw) || decl.prop,
15
+ raws.prop && raws.prop.suffix,
16
+ raws.between || ":",
17
+ raws.value && raws.value.prefix,
18
+ ].reduce((count, str) => {
19
+ if (str) {
20
+ return count + str.length;
21
+ }
22
+
23
+ return count;
24
+ }, 0);
29
25
  }
30
26
 
31
27
  /**
@@ -34,78 +30,89 @@ function declarationValueIndex (decl) {
34
30
  * @param {string} property
35
31
  * @return {boolean} If `true`, the property is standard
36
32
  */
37
- function isStandardSyntaxProperty (property) {
38
- // SCSS var (e.g. $var: x), list (e.g. $list: (x)) or map (e.g. $map: (key:value))
39
- if (property.startsWith('$')) {
40
- return false
41
- }
42
-
43
- // Less var (e.g. @var: x)
44
- if (property.startsWith('@')) {
45
- return false
46
- }
47
-
48
- // SCSS or Less interpolation
49
- if (/#{.+?}|@{.+?}|\$\(.+?\)/.test(property)) {
50
- return false
51
- }
52
-
53
- return true
33
+ function isStandardSyntaxProperty(property) {
34
+ // SCSS var (e.g. $var: x), list (e.g. $list: (x)) or map (e.g. $map: (key:value))
35
+ if (property.startsWith("$")) {
36
+ return false;
37
+ }
38
+
39
+ // Less var (e.g. @var: x)
40
+ if (property.startsWith("@")) {
41
+ return false;
42
+ }
43
+
44
+ // SCSS or Less interpolation
45
+ if (/#{.+?}|@{.+?}|\$\(.+?\)/.test(property)) {
46
+ return false;
47
+ }
48
+
49
+ return true;
54
50
  }
55
51
 
56
52
  /**
57
53
  * @param {import('postcss').Declaration} decl
58
54
  * @returns {boolean}
59
55
  */
60
- function isInColorGamutP3MediaQuery (decl) {
61
- const parentMediaQuery = getMediaQueryParent(decl)
56
+ function isInColorGamutP3MediaQuery(decl) {
57
+ const parentMediaQuery = getMediaQueryParent(decl);
62
58
 
63
- if (parentMediaQuery && /\(color-gamut:\s*p3\)/.test(parentMediaQuery.params)) {
64
- return true
65
- }
59
+ if (
60
+ parentMediaQuery &&
61
+ /\(color-gamut:\s*p3\)/.test(parentMediaQuery.params)
62
+ ) {
63
+ return true;
64
+ }
66
65
 
67
- return false
66
+ return false;
68
67
  }
69
68
 
70
69
  /**
71
70
  * @param {import('postcss').Declaration} decl
72
71
  * @returns {boolean}
73
72
  */
74
- function isInColorGamutRec2020MediaQuery (decl) {
75
- const parentMediaQuery = getMediaQueryParent(decl)
73
+ function isInColorGamutRec2020MediaQuery(decl) {
74
+ const parentMediaQuery = getMediaQueryParent(decl);
76
75
 
77
- if (parentMediaQuery && /\(color-gamut:\s*rec2020\)/.test(parentMediaQuery.params)) {
78
- return true
79
- }
76
+ if (
77
+ parentMediaQuery &&
78
+ /\(color-gamut:\s*rec2020\)/.test(parentMediaQuery.params)
79
+ ) {
80
+ return true;
81
+ }
80
82
 
81
- return false
83
+ return false;
82
84
  }
83
85
 
84
86
  /**
85
87
  * @param {import('postcss').Declaration} decl
86
88
  * @returns {boolean | decl}
87
89
  */
88
- function getMediaQueryParent (decl) {
89
- let parent = decl.parent
90
+ function getMediaQueryParent(decl) {
91
+ let parent = decl.parent;
90
92
 
91
- if (parent && isMediaQuery(parent)) return parent
93
+ if (parent && isMediaQuery(parent)) return parent;
92
94
 
93
- parent = parent.parent
95
+ parent = parent.parent;
94
96
 
95
- return isMediaQuery(parent) && parent
97
+ return isMediaQuery(parent) && parent;
96
98
  }
97
99
 
98
100
  /**
99
101
  * @param {import('postcss').Declaration} decl
100
102
  * @returns {boolean}
101
103
  */
102
- function isMediaQuery (decl) {
103
- return decl.type === 'atrule' && decl.name === 'media'
104
+ function isMediaQuery(decl) {
105
+ return decl.type === "atrule" && decl.name === "media";
104
106
  }
105
107
 
106
- module.exports = {
107
- isStandardSyntaxProperty,
108
- declarationValueIndex,
109
- isInColorGamutP3MediaQuery,
110
- isInColorGamutRec2020MediaQuery
108
+ function startsWithNumber(str) {
109
+ return /^\d/.test(str);
111
110
  }
111
+
112
+ module.exports = {
113
+ isStandardSyntaxProperty,
114
+ declarationValueIndex,
115
+ isInColorGamutP3MediaQuery,
116
+ isInColorGamutRec2020MediaQuery,
117
+ startsWithNumber,
118
+ };