2020-05-19 11:43:42 +03:00

142 lines
3.9 KiB
JavaScript

const stylelint = require('stylelint');
const postcss = require('postcss');
const postcssSorting = require('postcss-sorting');
const { isProperty } = require('../../utils');
const checkEmptyLineBefore = require('./checkEmptyLineBefore');
const checkEmptyLineBeforeFirstProp = require('./checkEmptyLineBeforeFirstProp');
const checkOrder = require('./checkOrder');
const getNodeData = require('./getNodeData');
const createFlatOrder = require('./createFlatOrder');
module.exports = function checkNode(node, sharedInfo, originalNode) {
// First, check order
let allPropData = getAllPropData(node);
if (!sharedInfo.isFixEnabled) {
allPropData.forEach(checkEveryPropForOrder);
}
if (sharedInfo.isFixEnabled) {
let shouldFixOrder = false;
// Check if there order violation to avoid running re-ordering unnecessery
allPropData.forEach(function checkEveryPropForOrder2(propData, index) {
// Skip first decl
if (index === 0) {
return;
}
// return early if we know there is a violation and auto fix should be applied
if (shouldFixOrder) {
return;
}
let previousPropData = allPropData[index - 1];
let checkedOrder = checkOrder({
firstPropData: previousPropData,
secondPropData: propData,
unspecified: sharedInfo.unspecified,
allPropData: allPropData.slice(0, index),
});
if (!checkedOrder.isCorrect) {
shouldFixOrder = true;
}
});
if (shouldFixOrder) {
let sortingOptions = {
'properties-order': createFlatOrder(sharedInfo.primaryOption),
'unspecified-properties-position':
sharedInfo.unspecified === 'ignore' ? 'bottom' : sharedInfo.unspecified,
};
// creating PostCSS Root node with current node as a child,
// so PostCSS Sorting can process it
let tempRoot = postcss.root({ nodes: [originalNode] });
postcssSorting(sortingOptions)(tempRoot);
let allPropData2 = getAllPropData(node);
allPropData2.forEach(checkEveryPropForOrder);
}
}
// Second, check emptyLineBefore
sharedInfo.lastKnownSeparatedGroup = 1;
let propsCount = node.nodes.filter(item => isProperty(item)).length;
let allNodesData = node.nodes.map(function collectDataForEveryNode(child) {
return getNodeData(child, sharedInfo.expectedOrder);
});
allNodesData.forEach(function checkEveryPropForEmptyLine(nodeData, index) {
let previousNodeData = allNodesData[index - 1];
// if previous node is shared-line comment, use second previous node
if (
previousNodeData &&
previousNodeData.node.type === 'comment' &&
!previousNodeData.node.raw('before').includes('\n')
) {
previousNodeData = allNodesData[index - 2];
}
// skip first decl
if (!previousNodeData) {
return;
}
// Nodes should be standard declarations
if (!isProperty(previousNodeData.node) || !isProperty(nodeData.node)) {
return;
}
checkEmptyLineBefore(previousNodeData, nodeData, sharedInfo, propsCount);
});
// Check if empty line before first prop should be removed
if (isProperty(allNodesData[0].node)) {
checkEmptyLineBeforeFirstProp(allNodesData[0], sharedInfo);
}
function checkEveryPropForOrder(propData, index, listOfProps) {
// Skip first decl
if (index === 0) {
return;
}
const previousPropData = listOfProps[index - 1];
const checkedOrder = checkOrder({
firstPropData: previousPropData,
secondPropData: propData,
unspecified: sharedInfo.unspecified,
allPropData: listOfProps.slice(0, index),
});
if (!checkedOrder.isCorrect) {
const { orderData } = checkedOrder.secondNode;
stylelint.utils.report({
message: sharedInfo.messages.expected(
checkedOrder.secondNode.name,
checkedOrder.firstNode.name,
orderData && orderData.groupName
),
node: checkedOrder.secondNode.node,
result: sharedInfo.result,
ruleName: sharedInfo.ruleName,
});
}
}
function getAllPropData(inputNode) {
return inputNode.nodes
.filter(item => isProperty(item))
.map(item => getNodeData(item, sharedInfo.expectedOrder));
}
};