You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
247 lines
5.6 KiB
247 lines
5.6 KiB
// @ts-nocheck |
|
|
|
'use strict'; |
|
|
|
const declarationValueIndex = require('../../utils/declarationValueIndex'); |
|
const getDeclarationValue = require('../../utils/getDeclarationValue'); |
|
const isSingleLineString = require('../../utils/isSingleLineString'); |
|
const isStandardSyntaxFunction = require('../../utils/isStandardSyntaxFunction'); |
|
const report = require('../../utils/report'); |
|
const ruleMessages = require('../../utils/ruleMessages'); |
|
const setDeclarationValue = require('../../utils/setDeclarationValue'); |
|
const validateOptions = require('../../utils/validateOptions'); |
|
const valueParser = require('postcss-value-parser'); |
|
|
|
const ruleName = 'function-parentheses-newline-inside'; |
|
|
|
const messages = ruleMessages(ruleName, { |
|
expectedOpening: 'Expected newline after "("', |
|
expectedClosing: 'Expected newline before ")"', |
|
expectedOpeningMultiLine: 'Expected newline after "(" in a multi-line function', |
|
rejectedOpeningMultiLine: 'Unexpected whitespace after "(" in a multi-line function', |
|
expectedClosingMultiLine: 'Expected newline before ")" in a multi-line function', |
|
rejectedClosingMultiLine: 'Unexpected whitespace before ")" in a multi-line function', |
|
}); |
|
|
|
function rule(expectation, options, context) { |
|
return (root, result) => { |
|
const validOptions = validateOptions(result, ruleName, { |
|
actual: expectation, |
|
possible: ['always', 'always-multi-line', 'never-multi-line'], |
|
}); |
|
|
|
if (!validOptions) { |
|
return; |
|
} |
|
|
|
root.walkDecls((decl) => { |
|
if (!decl.value.includes('(')) { |
|
return; |
|
} |
|
|
|
let hasFixed = false; |
|
const declValue = getDeclarationValue(decl); |
|
const parsedValue = valueParser(declValue); |
|
|
|
parsedValue.walk((valueNode) => { |
|
if (valueNode.type !== 'function') { |
|
return; |
|
} |
|
|
|
if (!isStandardSyntaxFunction(valueNode)) { |
|
return; |
|
} |
|
|
|
const functionString = valueParser.stringify(valueNode); |
|
const isMultiLine = !isSingleLineString(functionString); |
|
|
|
function containsNewline(str) { |
|
return str.includes('\n'); |
|
} |
|
|
|
// Check opening ... |
|
|
|
const openingIndex = valueNode.sourceIndex + valueNode.value.length + 1; |
|
const checkBefore = getCheckBefore(valueNode); |
|
|
|
if (expectation === 'always' && !containsNewline(checkBefore)) { |
|
if (context.fix) { |
|
hasFixed = true; |
|
fixBeforeForAlways(valueNode, context.newline); |
|
} else { |
|
complain(messages.expectedOpening, openingIndex); |
|
} |
|
} |
|
|
|
if (isMultiLine && expectation === 'always-multi-line' && !containsNewline(checkBefore)) { |
|
if (context.fix) { |
|
hasFixed = true; |
|
fixBeforeForAlways(valueNode, context.newline); |
|
} else { |
|
complain(messages.expectedOpeningMultiLine, openingIndex); |
|
} |
|
} |
|
|
|
if (isMultiLine && expectation === 'never-multi-line' && checkBefore !== '') { |
|
if (context.fix) { |
|
hasFixed = true; |
|
fixBeforeForNever(valueNode); |
|
} else { |
|
complain(messages.rejectedOpeningMultiLine, openingIndex); |
|
} |
|
} |
|
|
|
// Check closing ... |
|
|
|
const closingIndex = valueNode.sourceIndex + functionString.length - 2; |
|
const checkAfter = getCheckAfter(valueNode); |
|
|
|
if (expectation === 'always' && !containsNewline(checkAfter)) { |
|
if (context.fix) { |
|
hasFixed = true; |
|
fixAfterForAlways(valueNode, context.newline); |
|
} else { |
|
complain(messages.expectedClosing, closingIndex); |
|
} |
|
} |
|
|
|
if (isMultiLine && expectation === 'always-multi-line' && !containsNewline(checkAfter)) { |
|
if (context.fix) { |
|
hasFixed = true; |
|
fixAfterForAlways(valueNode, context.newline); |
|
} else { |
|
complain(messages.expectedClosingMultiLine, closingIndex); |
|
} |
|
} |
|
|
|
if (isMultiLine && expectation === 'never-multi-line' && checkAfter !== '') { |
|
if (context.fix) { |
|
hasFixed = true; |
|
fixAfterForNever(valueNode); |
|
} else { |
|
complain(messages.rejectedClosingMultiLine, closingIndex); |
|
} |
|
} |
|
}); |
|
|
|
if (hasFixed) { |
|
setDeclarationValue(decl, parsedValue.toString()); |
|
} |
|
|
|
function complain(message, offset) { |
|
report({ |
|
ruleName, |
|
result, |
|
message, |
|
node: decl, |
|
index: declarationValueIndex(decl) + offset, |
|
}); |
|
} |
|
}); |
|
}; |
|
} |
|
|
|
function getCheckBefore(valueNode) { |
|
let before = valueNode.before; |
|
|
|
for (const node of valueNode.nodes) { |
|
if (node.type === 'comment') { |
|
continue; |
|
} |
|
|
|
if (node.type === 'space') { |
|
before += node.value; |
|
continue; |
|
} |
|
|
|
break; |
|
} |
|
|
|
return before; |
|
} |
|
|
|
function getCheckAfter(valueNode) { |
|
let after = ''; |
|
|
|
for (const node of valueNode.nodes.slice().reverse()) { |
|
if (node.type === 'comment') { |
|
continue; |
|
} |
|
|
|
if (node.type === 'space') { |
|
after = node.value + after; |
|
continue; |
|
} |
|
|
|
break; |
|
} |
|
|
|
after += valueNode.after; |
|
|
|
return after; |
|
} |
|
|
|
function fixBeforeForAlways(valueNode, newline) { |
|
let target; |
|
|
|
for (const node of valueNode.nodes) { |
|
if (node.type === 'comment') { |
|
continue; |
|
} |
|
|
|
if (node.type === 'space') { |
|
target = node; |
|
continue; |
|
} |
|
|
|
break; |
|
} |
|
|
|
if (target) { |
|
target.value = newline + target.value; |
|
} else { |
|
valueNode.before = newline + valueNode.before; |
|
} |
|
} |
|
|
|
function fixBeforeForNever(valueNode) { |
|
valueNode.before = ''; |
|
|
|
for (const node of valueNode.nodes) { |
|
if (node.type === 'comment') { |
|
continue; |
|
} |
|
|
|
if (node.type === 'space') { |
|
node.value = ''; |
|
continue; |
|
} |
|
|
|
break; |
|
} |
|
} |
|
|
|
function fixAfterForAlways(valueNode, newline) { |
|
valueNode.after = newline + valueNode.after; |
|
} |
|
|
|
function fixAfterForNever(valueNode) { |
|
valueNode.after = ''; |
|
|
|
for (const node of valueNode.nodes.slice().reverse()) { |
|
if (node.type === 'comment') { |
|
continue; |
|
} |
|
|
|
if (node.type === 'space') { |
|
node.value = ''; |
|
continue; |
|
} |
|
|
|
break; |
|
} |
|
} |
|
|
|
rule.ruleName = ruleName; |
|
rule.messages = messages; |
|
module.exports = rule;
|
|
|