UNPKG

2.88 kBJavaScriptView Raw
1'use strict';
2
3const atRuleParamIndex = require('../../utils/atRuleParamIndex');
4const functionArgumentsSearch = require('../../utils/functionArgumentsSearch');
5const isStandardSyntaxUrl = require('../../utils/isStandardSyntaxUrl');
6const optionsMatches = require('../../utils/optionsMatches');
7const report = require('../../utils/report');
8const ruleMessages = require('../../utils/ruleMessages');
9const validateOptions = require('../../utils/validateOptions');
10
11const ruleName = 'function-url-quotes';
12
13const messages = ruleMessages(ruleName, {
14 expected: () => 'Expected quotes',
15 rejected: () => 'Unexpected quotes',
16});
17
18function rule(expectation, options) {
19 return (root, result) => {
20 const validOptions = validateOptions(
21 result,
22 ruleName,
23 {
24 actual: expectation,
25 possible: ['always', 'never'],
26 },
27 {
28 actual: options,
29 possible: {
30 except: ['empty'],
31 },
32 optional: true,
33 },
34 );
35
36 if (!validOptions) {
37 return;
38 }
39
40 root.walkAtRules(checkAtRuleParams);
41 root.walkDecls(checkDeclParams);
42
43 function checkDeclParams(decl) {
44 functionArgumentsSearch(decl.toString().toLowerCase(), 'url', (args, index) => {
45 checkArgs(args, decl, index, 'url');
46 });
47 }
48
49 function checkAtRuleParams(atRule) {
50 const atRuleParamsLowerCase = atRule.params.toLowerCase();
51
52 functionArgumentsSearch(atRuleParamsLowerCase, 'url', (args, index) => {
53 checkArgs(args, atRule, index + atRuleParamIndex(atRule), 'url');
54 });
55 functionArgumentsSearch(atRuleParamsLowerCase, 'url-prefix', (args, index) => {
56 checkArgs(args, atRule, index + atRuleParamIndex(atRule), 'url-prefix');
57 });
58 functionArgumentsSearch(atRuleParamsLowerCase, 'domain', (args, index) => {
59 checkArgs(args, atRule, index + atRuleParamIndex(atRule), 'domain');
60 });
61 }
62
63 function checkArgs(args, node, index, functionName) {
64 let shouldHasQuotes = expectation === 'always';
65
66 const leftTrimmedArgs = args.trimLeft();
67
68 if (!isStandardSyntaxUrl(leftTrimmedArgs)) {
69 return;
70 }
71
72 const complaintIndex = index + args.length - leftTrimmedArgs.length;
73 const hasQuotes = leftTrimmedArgs.startsWith("'") || leftTrimmedArgs.startsWith('"');
74
75 const trimmedArg = args.trim();
76 const isEmptyArgument = ['', "''", '""'].includes(trimmedArg);
77
78 if (optionsMatches(options, 'except', 'empty') && isEmptyArgument) {
79 shouldHasQuotes = !shouldHasQuotes;
80 }
81
82 if (shouldHasQuotes) {
83 if (hasQuotes) {
84 return;
85 }
86
87 complain(messages.expected(functionName), node, complaintIndex);
88 } else {
89 if (!hasQuotes) {
90 return;
91 }
92
93 complain(messages.rejected(functionName), node, complaintIndex);
94 }
95 }
96
97 function complain(message, node, index) {
98 report({
99 message,
100 node,
101 index,
102 result,
103 ruleName,
104 });
105 }
106 };
107}
108
109rule.ruleName = ruleName;
110rule.messages = messages;
111module.exports = rule;