stylelint-sassdoc
Version:
stylelint plugin to check scss files for a valid sassdoc documentation Credits to https://github.com/anneangersbach
131 lines (124 loc) • 5.34 kB
JavaScript
const stylelint = require('stylelint');
const {
adjacentLineIsSCSSComment,
checkCommentsForGroup,
checkCommentsForGroupName,
checkCommentsForPosterComment,
nodeToString,
regExCheck,
} = require('../../utils');
const ruleName = 'sassdoc/poster-comment';
const messages = stylelint.utils.ruleMessages(ruleName, {
noValidStart: 'SassDoc: Expected poster comment to be prefixed by ////.',
noValidEnd: (posterComments) => `SassDoc: Expected exactly one //// closing comment before continuing with non SassDoc lines, but found {${posterComments.length}}`,
invalidGroup: (resultsGroup) => `Sassdoc: Expected exactly one @group in poster comment, but found {${resultsGroup.length}}`,
invalidGroupName: (resultsGroupName) => `Sassdoc: Expected no more than one @group-name in poster comment, but found {${resultsGroupName.length}}`,
});
const posterRegEx = /^\/\/\/\/$/;
/*
http://sassdoc.com/file-level-annotations/
Usually, the poster comment goes on top of the file.
In order to be parsed as a poster, it has to be prefixed by ////.
You should have 4 slashes on the first and last lines (which are usually empty lines),
and any number of slashes in between (3, 4, 5…).
Also, you cannot have more than one poster per file. */
module.exports = stylelint.createPlugin(ruleName, (actual) => (root, result) => {
const validOptions = stylelint.utils.validateOptions(result, ruleName, {
actual,
});
if (!validOptions) {
return;
}
root.walkComments((node) => {
let resultsGroup = [];
let resultsGroupName = [];
let posterComments = [];
const nodeString = nodeToString(node);
// skipping comments nested in blocks
if (node.parent !== root) {
return;
}
// checking poster comment start
if (node === node.parent.first) {
// file start
if (regExCheck(nodeString, posterRegEx)) {
// next line is not a sassdoc comment, so poster comment is incomplete
if (!adjacentLineIsSCSSComment(node, false)) {
stylelint.utils.report({
message: messages.noValidEnd,
node,
result,
ruleName,
});
} else {
// counting @group occurences
resultsGroup = checkCommentsForGroup(node);
// counting @group-name occurences
resultsGroupName = checkCommentsForGroupName(node);
// counting '////' occurences
posterComments = checkCommentsForPosterComment(node);
// return error if more or less than one @group is found
}
if (resultsGroup.length < 1) {
stylelint.utils.report({
message: messages.invalidGroup(resultsGroup),
node,
result,
ruleName,
});
}
// 1 or more results
resultsGroup.forEach((returnComment) => {
if (resultsGroup.length !== 1) {
stylelint.utils.report({
message: messages.invalidGroup(resultsGroup),
node: returnComment.node,
result,
ruleName,
});
}
});
// return error if more than 1 @group-name is found
resultsGroupName.forEach((returnComment) => {
if (resultsGroupName.length > 1) {
stylelint.utils.report({
message: messages.invalidGroupName(resultsGroupName),
node: returnComment.node,
result,
ruleName,
});
}
});
// return error if more or less than one closing poster comment is found
if (posterComments.length !== 1) {
posterComments.forEach((returnComment) => {
stylelint.utils.report({
message: messages.noValidEnd(posterComments),
node: returnComment.node,
result,
ruleName,
});
});
if (posterComments.length === 0) {
stylelint.utils.report({
message: messages.noValidEnd(posterComments),
node,
result,
ruleName,
});
}
}
} else {
// return error if opening comment is not found.
stylelint.utils.report({
message: messages.noValidStart,
node,
result,
ruleName,
});
}
}
});
});
module.exports.ruleName = ruleName;
module.exports.messages = messages;