UNPKG

3.01 kBJavaScriptView Raw
1// @ts-nocheck
2
3'use strict';
4
5const valueParser = require('postcss-value-parser');
6
7const declarationValueIndex = require('../../utils/declarationValueIndex');
8const isStandardSyntaxDeclaration = require('../../utils/isStandardSyntaxDeclaration');
9const report = require('../../utils/report');
10const ruleMessages = require('../../utils/ruleMessages');
11const validateOptions = require('../../utils/validateOptions');
12
13const ruleName = 'color-function-notation';
14
15const messages = ruleMessages(ruleName, {
16 expected: (primary) => `Expected ${primary} color-function notation`,
17});
18
19const LEGACY_FUNCS = ['rgba', 'hsla'];
20const LEGACY_NOTATION_FUNCS = ['rgb', 'rgba', 'hsl', 'hsla'];
21
22function rule(primary, secondary, context) {
23 return (root, result) => {
24 const validOptions = validateOptions(result, ruleName, {
25 actual: primary,
26 possible: ['modern', 'legacy'],
27 });
28
29 if (!validOptions) return;
30
31 root.walkDecls((decl) => {
32 if (!isStandardSyntaxDeclaration(decl)) return;
33
34 let needsFix = false;
35 const parsedValue = valueParser(getValue(decl));
36
37 parsedValue.walk((node) => {
38 const { value, type, sourceIndex, nodes } = node;
39
40 if (type !== 'function') return;
41
42 if (!LEGACY_NOTATION_FUNCS.includes(value.toLowerCase())) return;
43
44 if (primary === 'modern' && !hasCommas(node)) return;
45
46 if (primary === 'legacy' && hasCommas(node)) return;
47
48 if (context.fix && primary === 'modern') {
49 let commaCount = 0;
50
51 // Convert punctuation
52 node.nodes = nodes.map((childNode) => {
53 if (isComma(childNode)) {
54 // Non-alpha commas to space and alpha commas to slashes
55 if (commaCount < 2) {
56 childNode.type = 'space';
57 childNode.value = atLeastOneSpace(childNode.after);
58 commaCount++;
59 } else {
60 childNode.value = '/';
61 childNode.before = atLeastOneSpace(childNode.before);
62 childNode.after = atLeastOneSpace(childNode.after);
63 }
64 }
65
66 return childNode;
67 });
68
69 // Remove trailing 'a' from legacy function name
70 if (LEGACY_FUNCS.includes(node.value.toLowerCase())) {
71 node.value = node.value.slice(0, -1);
72 }
73
74 needsFix = true;
75
76 return;
77 }
78
79 report({
80 message: messages.expected(primary),
81 node: decl,
82 index: declarationValueIndex(decl) + sourceIndex,
83 result,
84 ruleName,
85 });
86 });
87
88 if (needsFix) {
89 setValue(decl, parsedValue.toString());
90 }
91 });
92 };
93}
94
95function atLeastOneSpace(whitespace) {
96 return whitespace !== '' ? whitespace : ' ';
97}
98
99function isComma(node) {
100 return node.type === 'div' && node.value === ',';
101}
102
103function hasCommas(node) {
104 return node.nodes && node.nodes.some((childNode) => isComma(childNode));
105}
106
107function getValue(decl) {
108 return decl.raws.value ? decl.raws.value.raw : decl.value;
109}
110
111function setValue(decl, value) {
112 if (decl.raws.value) decl.raws.value.raw = value;
113 else decl.value = value;
114
115 return decl;
116}
117
118rule.ruleName = ruleName;
119rule.messages = messages;
120module.exports = rule;