UNPKG

2.32 kBJavaScriptView Raw
1// @ts-nocheck
2
3'use strict';
4
5const atRuleParamIndex = require('../../utils/atRuleParamIndex');
6const declarationValueIndex = require('../../utils/declarationValueIndex');
7const getUnitFromValueNode = require('../../utils/getUnitFromValueNode');
8const optionsMatches = require('../../utils/optionsMatches');
9const report = require('../../utils/report');
10const ruleMessages = require('../../utils/ruleMessages');
11const validateOptions = require('../../utils/validateOptions');
12
13const _ = require('lodash');
14const valueParser = require('postcss-value-parser');
15
16const ruleName = 'number-max-precision';
17
18const messages = ruleMessages(ruleName, {
19 expected: (number, precision) => `Expected "${number}" to be "${number.toFixed(precision)}"`,
20});
21
22function rule(precision, options) {
23 return (root, result) => {
24 const validOptions = validateOptions(
25 result,
26 ruleName,
27 {
28 actual: precision,
29 possible: [_.isNumber],
30 },
31 {
32 optional: true,
33 actual: options,
34 possible: {
35 ignoreUnits: [_.isString, _.isRegExp],
36 },
37 },
38 );
39
40 if (!validOptions) {
41 return;
42 }
43
44 root.walkAtRules((atRule) => {
45 if (atRule.name.toLowerCase() === 'import') {
46 return;
47 }
48
49 check(atRule, atRule.params, atRuleParamIndex);
50 });
51
52 root.walkDecls((decl) => check(decl, decl.value, declarationValueIndex));
53
54 function check(node, value, getIndex) {
55 // Get out quickly if there are no periods
56 if (!value.includes('.')) {
57 return;
58 }
59
60 valueParser(value).walk((valueNode) => {
61 const unit = getUnitFromValueNode(valueNode);
62
63 if (optionsMatches(options, 'ignoreUnits', unit)) {
64 return;
65 }
66
67 // Ignore `url` function
68 if (valueNode.type === 'function' && valueNode.value.toLowerCase() === 'url') {
69 return false;
70 }
71
72 // Ignore strings, comments, etc
73 if (valueNode.type !== 'word') {
74 return;
75 }
76
77 const match = /\d*\.(\d+)/.exec(valueNode.value);
78
79 if (match === null) {
80 return;
81 }
82
83 if (match[1].length <= precision) {
84 return;
85 }
86
87 report({
88 result,
89 ruleName,
90 node,
91 index: getIndex(node) + valueNode.sourceIndex + match.index,
92 message: messages.expected(parseFloat(match[0]), precision),
93 });
94 });
95 }
96 };
97}
98
99rule.ruleName = ruleName;
100rule.messages = messages;
101module.exports = rule;