UNPKG

2.9 kBJavaScriptView Raw
1// @ts-nocheck
2
3'use strict';
4
5const addEmptyLineBefore = require('../../utils/addEmptyLineBefore');
6const hasEmptyLine = require('../../utils/hasEmptyLine');
7const isAfterComment = require('../../utils/isAfterComment');
8const isFirstNested = require('../../utils/isFirstNested');
9const isFirstNodeOfRoot = require('../../utils/isFirstNodeOfRoot');
10const isSharedLineComment = require('../../utils/isSharedLineComment');
11const optionsMatches = require('../../utils/optionsMatches');
12const removeEmptyLinesBefore = require('../../utils/removeEmptyLinesBefore');
13const report = require('../../utils/report');
14const ruleMessages = require('../../utils/ruleMessages');
15const validateOptions = require('../../utils/validateOptions');
16
17const ruleName = 'comment-empty-line-before';
18
19const messages = ruleMessages(ruleName, {
20 expected: 'Expected empty line before comment',
21 rejected: 'Unexpected empty line before comment',
22});
23
24const stylelintCommandPrefix = 'stylelint-';
25
26function rule(expectation, options, context) {
27 return (root, result) => {
28 const validOptions = validateOptions(
29 result,
30 ruleName,
31 {
32 actual: expectation,
33 possible: ['always', 'never'],
34 },
35 {
36 actual: options,
37 possible: {
38 except: ['first-nested'],
39 ignore: ['stylelint-commands', 'after-comment'],
40 },
41 optional: true,
42 },
43 );
44
45 if (!validOptions) {
46 return;
47 }
48
49 root.walkComments((comment) => {
50 // Ignore the first node
51 if (isFirstNodeOfRoot(comment)) {
52 return;
53 }
54
55 // Optionally ignore stylelint commands
56 if (
57 comment.text.startsWith(stylelintCommandPrefix) &&
58 optionsMatches(options, 'ignore', 'stylelint-commands')
59 ) {
60 return;
61 }
62
63 // Optionally ignore newlines between comments
64 if (optionsMatches(options, 'ignore', 'after-comment') && isAfterComment(comment)) {
65 return;
66 }
67
68 // Ignore shared-line comments
69 if (isSharedLineComment(comment)) {
70 return;
71 }
72
73 // Ignore SCSS comments
74 if (comment.raws.inline || comment.inline) {
75 return;
76 }
77
78 const expectEmptyLineBefore = (() => {
79 if (optionsMatches(options, 'except', 'first-nested') && isFirstNested(comment)) {
80 return false;
81 }
82
83 return expectation === 'always';
84 })();
85
86 const before = comment.raws.before || '';
87 const hasEmptyLineBefore = hasEmptyLine(before);
88
89 // Return if the expectation is met
90 if (expectEmptyLineBefore === hasEmptyLineBefore) {
91 return;
92 }
93
94 // Fix
95 if (context.fix) {
96 if (expectEmptyLineBefore) {
97 addEmptyLineBefore(comment, context.newline);
98 } else {
99 removeEmptyLinesBefore(comment, context.newline);
100 }
101
102 return;
103 }
104
105 const message = expectEmptyLineBefore ? messages.expected : messages.rejected;
106
107 report({
108 message,
109 node: comment,
110 result,
111 ruleName,
112 });
113 });
114 };
115}
116
117rule.ruleName = ruleName;
118rule.messages = messages;
119module.exports = rule;