postcss-rem2px-yuze
Version:
Convert rem units to px or rpx units using PostCSS (JavaScript version with include feature)
201 lines (179 loc) • 4.87 kB
JavaScript
const { defaultOptions } = require('./defaults')
const postcssPlugin = 'postcss-rem2px-yuze'
/**
* 深度合并配置选项
* @param {object} userOptions 用户配置
* @param {object} defaults 默认配置
* @returns {object} 合并后的配置
*/
function mergeConfig(userOptions = {}, defaults = defaultOptions) {
const result = { ...defaults }
for (const key in userOptions) {
if (userOptions.hasOwnProperty(key)) {
const userValue = userOptions[key]
const defaultValue = defaults[key]
// 如果都是数组,直接使用用户配置
if (Array.isArray(userValue) && Array.isArray(defaultValue)) {
result[key] = userValue
} else if (typeof userValue === 'object' && userValue !== null && !Array.isArray(userValue)) {
// 如果是对象,递归合并
result[key] = mergeConfig(userValue, defaultValue)
} else {
// 其他情况直接覆盖
result[key] = userValue
}
}
}
return result
}
/**
* 获取配置
* @param {object} options 用户配置选项
* @returns {object} 完整配置
*/
function getConfig(options) {
return mergeConfig(options, defaultOptions)
}
/**
* 数字精度处理
* @param {number} number 数字
* @param {number} precision 精度
* @returns {number} 处理后的数字
*/
function toFixed(number, precision) {
const multiplier = Math.pow(10, precision + 1)
const wholeNumber = Math.floor(number * multiplier)
return (Math.round(wholeNumber / 10) * 10) / multiplier
}
/**
* 创建rem替换函数
* @param {number} rootValue 根字体大小
* @param {number} unitPrecision 单位精度
* @param {number} minRemValue 最小rem值
* @param {string} transformUnit 转换单位
* @returns {function} 替换函数
*/
function createRemReplace(rootValue, unitPrecision, minRemValue, transformUnit = 'px') {
return function (match, remValue) {
if (!remValue) {
return match
}
const rems = parseFloat(remValue)
if (rems < minRemValue) {
return match
}
const fixedVal = toFixed(rems * rootValue, unitPrecision)
return fixedVal === 0 ? '0' : fixedVal + transformUnit
}
}
/**
* 检查声明是否已存在
* @param {object} rule CSS规则
* @param {string} prop 属性名
* @param {string} value 属性值
* @returns {boolean} 是否存在
*/
function declarationExists(rule, prop, value) {
return rule.some((decl) => {
return decl.prop === prop && decl.value === value
})
}
/**
* 检查选择器是否在黑名单中
* @param {array} blacklist 黑名单
* @param {string} selector 选择器
* @returns {boolean} 是否在黑名单中
*/
function blacklistedSelector(blacklist, selector) {
if (typeof selector !== 'string') {
return false
}
return blacklist.some((regex) => {
if (typeof regex === 'string') {
return selector.includes(regex)
}
return regex.test(selector)
})
}
/**
* 创建属性列表匹配器
* @param {array} propList 属性列表
* @returns {function} 匹配函数
*/
function createPropListMatcher(propList) {
const hasWild = propList.includes('*')
return function (prop) {
if (hasWild) {
return true
}
return propList.some((regex) => {
if (typeof regex === 'string') {
return prop.includes(regex)
}
return regex.test(prop)
})
}
}
/**
* 创建排除匹配器
* @param {array|function} exclude 排除规则
* @returns {function} 匹配函数
*/
function createExcludeMatcher(exclude) {
return function (filepath) {
if (filepath === undefined) {
return false
}
if (Array.isArray(exclude)) {
return exclude.some((regex) => {
if (typeof regex === 'string') {
return filepath.includes(regex)
}
return regex.test(filepath)
})
}
if (typeof exclude === 'function') {
return exclude(filepath)
}
return false
}
}
/**
* 创建包含匹配器
* @param {array|function} include 包含规则
* @returns {function} 匹配函数
*/
function createIncludeMatcher(include) {
return function (filepath) {
if (filepath === undefined) {
return false
}
// 如果include为空数组,则包含所有文件
if (Array.isArray(include) && include.length === 0) {
return true
}
if (Array.isArray(include)) {
return include.some((regex) => {
if (typeof regex === 'string') {
return filepath.includes(regex)
}
return regex.test(filepath)
})
}
if (typeof include === 'function') {
return include(filepath)
}
return false
}
}
module.exports = {
postcssPlugin,
getConfig,
toFixed,
createRemReplace,
declarationExists,
blacklistedSelector,
createPropListMatcher,
createExcludeMatcher,
createIncludeMatcher,
}