🚀 Big News: Socket Acquires Coana to Bring Reachability Analysis to Every Appsec Team.Learn more
Socket
DemoInstallSign in
Socket

stylelint-no-px

Package Overview
Dependencies
Maintainers
1
Versions
8
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

stylelint-no-px - npm Package Compare versions

Comparing version

to
2.0.0

2

index.js

@@ -1,1 +0,1 @@

module.exports = require('./lib/')
export {default} from './lib/index.js';

@@ -1,106 +0,155 @@

'use strict'
import stylelint from "stylelint";
import valueParser from "postcss-value-parser";
const stylelint = require('stylelint')
const valueParser = require('postcss-value-parser')
const ruleName = 'meowtec/no-px'
export const ruleName = "meowtec/no-px";
const messages = stylelint.utils.ruleMessages(ruleName, {
rem() {
return `Use rem instead of px`
export const meta = {
fixable: true,
};
export const messages = stylelint.utils.ruleMessages(ruleName, {
rem(remSize) {
if (remSize) {
return `Use rem instead of px. 'px' values have been converted to 'rem'.`;
}
return `Use rem instead of px. To enable automatic conversion, set the 'remSize' option in the plugin settings.`;
},
})
});
const defaultSecondaryOptions = {
ignore: ['1px']
ignore: ["1px"],
remSize: null,
};
function convertPxToRem(pxValue, baseSize) {
const numericValue = parseFloat(pxValue.replace("px", ""));
return `${(numericValue / baseSize).toFixed(5).replace(/\.?0+$/, "")}rem`;
}
const propInIgnoreList = (prop, list) => {
return prop && list.some(item => {
return prop.indexOf(item) > -1
})
function propInIgnoreList(prop, list) {
return (
prop &&
list.some((item) => {
return prop.indexOf(item) > -1;
})
);
}
const propAddXpxInIgnoreList = (prop, list, px) => {
const reg = new RegExp('\\s' + px)
return prop && list.some(item => {
return reg.test(item) && prop.indexOf(item.replace(reg, '')) > -1
})
function propAddXpxInIgnoreList(prop, list, px) {
const reg = new RegExp("\\s" + px);
return (
prop &&
list.some((item) => {
return reg.test(item) && prop.indexOf(item.replace(reg, "")) > -1;
})
);
}
/**
* check if a value has forbidden `px`
*/
const hasForbiddenPX = (node, options) => {
const type = node.type
const value = type === 'decl' ? node.value : node.params
const prop = type === 'decl' ? node.prop : null
function processValueNodes(nodes, prop, options) {
let hasPx = false;
const parsed = valueParser(value)
let hasPX = false
for (const valueNode of nodes) {
if (valueNode.type === "function") {
if (
valueNode.value === "url" ||
options.ignoreFunctions.indexOf(valueNode.value) > -1
) {
continue;
}
const ignore = options.ignore || defaultSecondaryOptions.ignore
const ignoreFunctions = options.ignoreFunctions || []
hasPx ||= processValueNodes(valueNode.nodes, prop, options);
}
if (type === 'atrule' && node.name === 'media') return
if (type === 'decl' && propInIgnoreList(node.prop, ignore)) return
parsed.walk(node => {
// if node is `url(xxx)`, prevent the traversal
let matched;
if (
node.type === 'function' &&
(
node.value === 'url' ||
ignoreFunctions.indexOf(node.value) > -1
)
valueNode.type === "word" &&
(matched = valueNode.value.match(/^([-,+]?\d+(\.\d+)?px)$/))
) {
return false
}
const px = matched[1];
// console.log('[[[node >>>]]]', node, '[[[<<< node]]]')
let matched
if (node.type === 'word' && (matched = node.value.match(/^([-,+]?\d+(\.\d+)?px)$/))) {
const px = matched[1]
if (px === '0px') {
return
if (px === "0px") {
continue;
}
if (
!propAddXpxInIgnoreList(prop, ignore, px) &&
ignore.indexOf(px) === -1
!propAddXpxInIgnoreList(prop, options.ignore, px) &&
options.ignore.indexOf(px) === -1
) {
hasPX = true
if (options.remSize) {
valueNode.value = convertPxToRem(px, options.remSize);
}
hasPx = true;
}
} else if (node.type === 'string' && /(@\{[\w-]+\})px\b/.test(node.value)) {
// eg. ~'@{width}px'
hasPX = true
} else if (
valueNode.type === "string" &&
/(@\{[\w-]+\})px\b/.test(valueNode.value)
) {
if (options.remSize) {
valueNode.value = convertPxToRem(valueNode.value, options.remSize);
}
hasPx = true;
}
})
}
return hasPX
return hasPx;
}
module.exports = stylelint.createPlugin(ruleName, (primaryOption, secondaryOptionObject) => {
primaryOption = primaryOption || ''
function processValue(value, prop, options) {
const parsed = valueParser(value);
const hasPx = processValueNodes(parsed.nodes, prop, options);
return {
newValue: valueParser.stringify(parsed.nodes),
hasPx,
};
}
function processDeclaration(declaration, options) {
if (propInIgnoreList(declaration.prop, options.ignore)) {
return;
}
const { newValue, hasPx } = processValue(
declaration.value,
declaration.prop,
options,
);
declaration.value = newValue;
return hasPx;
}
function processAtRule(atRule, options) {
if (atRule.type === "atrule" && atRule.name === "media") {
return;
}
const { newValue, hasPx } = processValue(atRule.params, null, options);
atRule.params = newValue;
atRule.value = newValue;
return hasPx;
}
function ruleFunction(primaryOption, secondaryOptionObject, context) {
primaryOption = primaryOption || "";
return (root, result) => {
if (!primaryOption) return
if (!primaryOption) return;
secondaryOptionObject = secondaryOptionObject || defaultSecondaryOptions
const {
ignore = defaultSecondaryOptions.ignore,
remSize = null,
ignoreFunctions = [],
} = secondaryOptionObject || defaultSecondaryOptions;
// const validOptions = stylelint.utils.validateOptions({
// ruleName: ruleName,
// result: result,
// actual: primaryOption,
// })
secondaryOptionObject = { ignore, remSize, ignoreFunctions };
// if (!validOptions) {
// return
// }
root.walkDecls(declaration => {
if (hasForbiddenPX(declaration, secondaryOptionObject)) {
root.walkDecls((declaration) => {
if (
processDeclaration(declaration, secondaryOptionObject) &&
!context.fix
) {
stylelint.utils.report({

@@ -110,9 +159,9 @@ ruleName: ruleName,

node: declaration,
message: messages.rem(),
})
message: messages.rem(secondaryOptionObject.remSize),
});
}
})
});
root.walkAtRules(atRule => {
if (hasForbiddenPX(atRule, secondaryOptionObject)) {
root.walkAtRules((atRule) => {
if (processAtRule(atRule, secondaryOptionObject) && !context.fix) {
stylelint.utils.report({

@@ -122,10 +171,13 @@ ruleName: ruleName,

node: atRule,
message: messages.rem(),
})
message: messages.rem(secondaryOptionObject.remSize),
});
}
})
}
})
});
};
}
module.exports.ruleName = ruleName
module.exports.messages = messages
ruleFunction.ruleName = ruleName;
ruleFunction.messages = messages;
ruleFunction.meta = meta;
export default stylelint.createPlugin(ruleName, ruleFunction);
{
"name": "stylelint-no-px",
"version": "1.0.1",
"version": "2.0.0",
"description": "A stylelint custom rule to ensure using rem instead of px",
"main": "index.js",
"type": "module",
"scripts": {
"test": "tape test"
"test": "node --experimental-vm-modules node_modules/jest/bin/jest.js"
},

@@ -33,12 +34,19 @@ "files": [

"devDependencies": {
"stylelint": "^8.0.0 || ^9.0.0 || ^10.0.0 || ^11.0.0",
"stylelint-test-rule-tape": "^0.2.0",
"tape": "^4.7.0"
"jest": "^29.7.0",
"jest-preset-stylelint": "^7.0.0",
"prettier": "^3.2.5",
"stylelint": "^16.0.0"
},
"dependencies": {
"postcss-value-parser": "^3.3.0 || ^4.0.2"
"postcss-less": "^6.0.0",
"postcss-value-parser": "^4.2.0"
},
"peerDependencies": {
"stylelint": ">= 8"
"stylelint": ">= 16"
},
"jest": {
"setupFiles": [
"<rootDir>/jest.setup.js"
]
}
}

@@ -50,4 +50,8 @@ # stylelint-no-px

ignore check for functions.
Ignore check for functions.
### remSize: number
Specify a base size for converting px to rem. If this option is provided, the plugin will automatically convert pixel values to rem using the provided base size.
### example(1) (the default options)

@@ -103,1 +107,14 @@

```
### example(4)
```javascript
// only `border + 1px` is ok
"meowtec/no-px": [true, { "ignore": ["1px"], "remSize": 16 }],
```
```less
.foo {
height: 16px; // error, auto converts to 1rem
}
```