UNPKG

2.93 kBJavaScriptView Raw
1// @ts-nocheck
2
3'use strict';
4
5const blurFunctionArguments = require('../../utils/blurFunctionArguments');
6const report = require('../../utils/report');
7const ruleMessages = require('../../utils/ruleMessages');
8const styleSearch = require('style-search');
9const validateOptions = require('../../utils/validateOptions');
10
11const ruleName = 'color-hex-length';
12
13const messages = ruleMessages(ruleName, {
14 expected: (actual, expected) => `Expected "${actual}" to be "${expected}"`,
15});
16
17function rule(expectation, _, context) {
18 return (root, result) => {
19 const validOptions = validateOptions(result, ruleName, {
20 actual: expectation,
21 possible: ['short', 'long'],
22 });
23
24 if (!validOptions) {
25 return;
26 }
27
28 root.walkDecls((decl) => {
29 const declString = blurFunctionArguments(decl.toString(), 'url');
30 const fixPositions = [];
31
32 styleSearch({ source: declString, target: '#' }, (match) => {
33 const hexMatch = /^#[0-9A-Za-z]+/.exec(declString.substr(match.startIndex));
34
35 if (!hexMatch) {
36 return;
37 }
38
39 const hexValue = hexMatch[0];
40
41 if (expectation === 'long' && hexValue.length !== 4 && hexValue.length !== 5) {
42 return;
43 }
44
45 if (expectation === 'short' && (hexValue.length < 6 || !canShrink(hexValue))) {
46 return;
47 }
48
49 const variant = expectation === 'long' ? longer : shorter;
50 const expectedHex = variant(hexValue);
51
52 if (context.fix) {
53 fixPositions.unshift({
54 expectedHex,
55 currentHex: hexValue,
56 startIndex: match.startIndex,
57 });
58
59 return;
60 }
61
62 report({
63 message: messages.expected(hexValue, expectedHex),
64 node: decl,
65 index: match.startIndex,
66 result,
67 ruleName,
68 });
69 });
70
71 if (fixPositions.length) {
72 const declProp = decl.prop;
73 const declBetween = decl.raws.between;
74
75 fixPositions.forEach((fixPosition) => {
76 // 1 — it's a # length
77 decl.value = replaceHex(
78 decl.value,
79 fixPosition.currentHex,
80 fixPosition.expectedHex,
81 fixPosition.startIndex - declProp.length - declBetween.length - 1,
82 );
83 });
84 }
85 });
86 };
87}
88
89function canShrink(hex) {
90 hex = hex.toLowerCase();
91
92 return (
93 hex[1] === hex[2] &&
94 hex[3] === hex[4] &&
95 hex[5] === hex[6] &&
96 (hex.length === 7 || (hex.length === 9 && hex[7] === hex[8]))
97 );
98}
99
100function shorter(hex) {
101 let hexVariant = '#';
102
103 for (let i = 1; i < hex.length; i += 2) {
104 hexVariant += hex[i];
105 }
106
107 return hexVariant;
108}
109
110function longer(hex) {
111 let hexVariant = '#';
112
113 for (let i = 1; i < hex.length; i++) {
114 hexVariant += hex[i] + hex[i];
115 }
116
117 return hexVariant;
118}
119
120function replaceHex(input, searchString, replaceString, startIndex) {
121 const offset = startIndex + 1;
122 const stringStart = input.slice(0, offset);
123 const stringEnd = input.slice(offset + searchString.length);
124
125 return stringStart + replaceString + stringEnd;
126}
127
128rule.ruleName = ruleName;
129rule.messages = messages;
130module.exports = rule;