mirror of
https://github.com/thangisme/notes.git
synced 2024-11-01 04:27:17 -04:00
120 lines
3.9 KiB
JavaScript
120 lines
3.9 KiB
JavaScript
"use strict"
|
|
|
|
const beforeBlockString = require("../../utils/beforeBlockString")
|
|
const blurComments = require("../../utils/blurComments")
|
|
const hasBlock = require("../../utils/hasBlock")
|
|
const report = require("../../utils/report")
|
|
const ruleMessages = require("../../utils/ruleMessages")
|
|
const validateOptions = require("../../utils/validateOptions")
|
|
const _ = require("lodash")
|
|
const keywordSets = require("../../reference/keywordSets")
|
|
const styleSearch = require("style-search")
|
|
const valueParser = require("postcss-value-parser")
|
|
|
|
const ruleName = "length-zero-no-unit"
|
|
|
|
const messages = ruleMessages(ruleName, {
|
|
rejected: "Unexpected unit",
|
|
})
|
|
|
|
const rule = function (actual) {
|
|
return (root, result) => {
|
|
const validOptions = validateOptions(result, ruleName, { actual })
|
|
if (!validOptions) {
|
|
return
|
|
}
|
|
|
|
root.walkDecls(decl => {
|
|
check(blurComments(decl.toString()), decl)
|
|
})
|
|
|
|
root.walkAtRules(atRule => {
|
|
const source = hasBlock(atRule) ? beforeBlockString(atRule, { noRawBefore: true }) : atRule.toString()
|
|
check(source, atRule)
|
|
})
|
|
|
|
function check(value, node) {
|
|
const ignorableIndexes = new Set()
|
|
|
|
styleSearch({ source: value, target: "0" }, match => {
|
|
const index = match.startIndex
|
|
|
|
// Given a 0 somewhere in the full property value (not in a string, thanks
|
|
// to styleSearch) we need to isolate the value that contains the zero.
|
|
// To do so, we'll find the last index before the 0 of a character that would
|
|
// divide one value in a list from another, and the next index of such a
|
|
// character; then we build a substring from those indexes, which we can
|
|
// assess.
|
|
|
|
// If a single value includes multiple 0's (e.g. 100.01px), we don't want
|
|
// each 0 to be treated as a separate value, possibly resulting in multiple
|
|
// warnings for the same value (e.g. 0.00px).
|
|
//
|
|
// This check prevents that from happening: we build and check against a
|
|
// Set containing all the indexes that are part of a value already validated.
|
|
if (ignorableIndexes.has(index)) {
|
|
return
|
|
}
|
|
|
|
const prevValueBreakIndex = _.findLastIndex(value.substr(0, index), char => {
|
|
return [
|
|
" ",
|
|
",",
|
|
")",
|
|
"(",
|
|
"#",
|
|
].indexOf(char) !== -1
|
|
})
|
|
|
|
// Ignore hex colors
|
|
if (value[prevValueBreakIndex] === "#") {
|
|
return
|
|
}
|
|
|
|
// If no prev break was found, this value starts at 0
|
|
const valueWithZeroStart = prevValueBreakIndex === -1 ? 0 : prevValueBreakIndex + 1
|
|
|
|
const nextValueBreakIndex = _.findIndex(value.substr(valueWithZeroStart), char => {
|
|
return [
|
|
" ",
|
|
",",
|
|
")",
|
|
].indexOf(char) !== -1
|
|
})
|
|
|
|
// If no next break was found, this value ends at the end of the string
|
|
const valueWithZeroEnd = nextValueBreakIndex === -1 ? value.length : nextValueBreakIndex + valueWithZeroStart
|
|
|
|
const valueWithZero = value.slice(valueWithZeroStart, valueWithZeroEnd)
|
|
const parsedValue = valueParser.unit(valueWithZero)
|
|
|
|
if (!parsedValue || parsedValue && !parsedValue.unit) {
|
|
return
|
|
}
|
|
|
|
// Add the indexes to ignorableIndexes so the same value will not
|
|
// be checked multiple times.
|
|
_.range(valueWithZeroStart, valueWithZeroEnd).forEach(i => ignorableIndexes.add(i))
|
|
|
|
// Only pay attention if the value parses to 0
|
|
// and units with lengths
|
|
if (parseFloat(valueWithZero, 10) !== 0 || !keywordSets.lengthUnits.has(parsedValue.unit.toLowerCase())) {
|
|
return
|
|
}
|
|
|
|
report({
|
|
message: messages.rejected,
|
|
node,
|
|
index: valueWithZeroEnd - parsedValue.unit.length,
|
|
result,
|
|
ruleName,
|
|
})
|
|
})
|
|
}
|
|
}
|
|
}
|
|
|
|
rule.ruleName = ruleName
|
|
rule.messages = messages
|
|
module.exports = rule
|