@zohodesk/stylelint-plugin-standards
v0.0.3
Published
Stylelint plugin to enforce custom Zoho Desk CSS standards.
Downloads
96
Maintainers
Readme
@zohodesk/stylelint-plugin-standards
Stylelint plugin to enforce custom CSS standards for Zoho Desk projects.
Installation
npm install @zohodesk/stylelint-plugin-standards --save-devUsage
Add the plugin to your Stylelint configuration:
module.exports = {
plugins: ["@zohodesk/stylelint-plugin-standards"],
rules: {
"@zohodesk/use-common-class": [
"error",
{
commonFiles: [
"node_modules/@dot-system/css-utility/es/utilities.plain.css"
],
commonClassesFrom: "~@dot-system/css-utility/es/utilities.plain.css",
isCssModules: true,
match: "subset",
propertyAliases: {
"flex-grow": ["flex-positive", "box-flex"],
"flex-basis": ["flex-preferred-size"],
"align-items": ["flex-align", "box-align"],
"justify-content": ["flex-pack", "box-pack"],
"align-content": ["flex-line-pack"],
"align-self": ["flex-item-align"],
order: ["flex-order"]
},
valueAliases: {
display: {
flex: ["box", "flexbox"],
"inline-flex": ["inline-flexbox"]
},
"align-items": {
"flex-start": ["start"],
"flex-end": ["end"]
},
"justify-content": {
"flex-start": ["start"],
"flex-end": ["end"],
"space-between": ["justify"],
"space-around": ["distribute"]
}
},
excludeWhenPresent: {
"flex-direction": ["box-orient", "box-direction"]
}
}
]
}
};Project structure
Each rule lives in its own folder so new rules can be added independently:
stylelint-plugin-standards/
├── index.js # registers every rule (array of plugins)
├── rules/
│ └── use-common-class/
│ ├── use-common-class.js # rule implementation
│ └── utils/ # helpers scoped to this rule
└── test/
└── use-common-class.test.jsAdding a New Rule
- Create a new folder in
rules/(e.g.rules/my-new-rule/my-new-rule.js) along with any rule-specific helpers inrules/my-new-rule/utils/. - Export the rule as a Stylelint plugin:
const stylelint = require("stylelint");
const ruleName = "@zohodesk/my-new-rule";
const messages = stylelint.utils.ruleMessages(ruleName, { /* ... */ });
const ruleFunction = (primary, secondary = {}) => (root, result) => {
/* ... */
};
ruleFunction.ruleName = ruleName;
ruleFunction.messages = messages;
module.exports = stylelint.createPlugin(ruleName, ruleFunction);- Register it in
index.js:
const useCommonClass = require("./rules/use-common-class/use-common-class");
const myNewRule = require("./rules/my-new-rule/my-new-rule");
const plugins = [useCommonClass, myNewRule];
module.exports = plugins;Rules
use-common-class
Scans CSS / CSS Module files and reports declaration blocks that duplicate a class already defined in a shared utilities file (for example utilities.plain.css). Instead of redeclaring the same properties, apply the existing common class directly in your JSX / HTML.
"@zohodesk/use-common-class": [
"error",
{
commonFiles: [
"node_modules/@dot-system/css-utility/es/utilities.plain.css"
],
commonClassesFrom: "~@dot-system/css-utility/es/utilities.plain.css",
isCssModules: true,
match: "subset" // or "exact"
}
]Options
| Option | Required | Default | Description |
| --- | --- | --- | --- |
| commonFiles | Yes | — | Paths to shared utility CSS files used for comparison. |
| commonClassesFrom | No | first commonFiles entry | Import path shown in the lint message. |
| isCssModules | No | false | When true, only rules whose selectors are all plain single classes (.className) are checked. If any selector is complex (.a:hover, .a.b, .a::after, etc.), the whole block is skipped. |
| match | No | "subset" | "subset" flags each utility whose declarations are contained in the rule. "exact" flags only rules that exactly match a utility block. |
| propertyAliases | No | {} | Canonical property → old names (after vendor-prefix strip). Read from config; empty means prefix-strip only. |
| valueAliases | No | {} | Canonical value → old names, grouped by property. Read from config; empty means prefix-strip only. |
| excludeWhenPresent | No | {} | Canonical property → leftover old names to drop when that canonical property is present. Read from config; empty means nothing is dropped. |
@font-face and @keyframes blocks are ignored. You cannot apply / composes a common utility class inside those at-rules.
Vendor prefixes (-webkit-, -ms-, -moz-, -o-) are stripped automatically. Only names that do not become the modern property/value after that strip need an alias.
propertyAliases
Shape: { "<canonical-property>": ["<old-name>", ...] }
Omitted or {} → no property aliases (vendor prefixes are still stripped).
Example: -ms-flex-positive → strip prefix → flex-positive → flex-grow.
propertyAliases: {
"flex-grow": ["flex-positive", "box-flex"],
"flex-basis": ["flex-preferred-size"],
"align-items": ["flex-align", "box-align"],
"justify-content": ["flex-pack", "box-pack"],
"align-content": ["flex-line-pack"],
"align-self": ["flex-item-align"],
order: ["flex-order"]
}box-orient and box-direction are not 1:1 aliases (see excludeWhenPresent).
valueAliases
Shape: { "<property>": { "<canonical-value>": ["<old-value>", ...] } }
Omitted or {} → no value aliases (vendor prefixes are still stripped).
Example: display: -ms-flexbox → strip prefix → flexbox → flex.
valueAliases: {
display: {
flex: ["box", "flexbox"],
"inline-flex": ["inline-flexbox"]
},
"align-items": {
"flex-start": ["start"],
"flex-end": ["end"]
},
"justify-content": {
"flex-start": ["start"],
"flex-end": ["end"],
"space-between": ["justify"],
"space-around": ["distribute"]
}
}Do not list values that prefix-strip already handles (-webkit-inline-flex → inline-flex).
excludeWhenPresent
Use this when old names are leftover keys, not 1:1 aliases: two (or more) old properties together mean one modern property. If the canonical property is present after normalize, the leftovers are dropped so subset matching does not require them.
Shape: { "<canonical-property>": ["<leftover-property>", ...] }
Omitted or {} → nothing is dropped.
Example: a common class with flex-direction, -webkit-box-orient, and -webkit-box-direction normalizes to { flex-direction } only. A user rule that declares only flex-direction still matches.
excludeWhenPresent: {
"flex-direction": ["box-orient", "box-direction"]
}Example
Before (flagged):
.container {
box-sizing: border-box;
}Suggested fix — drop the duplicate CSS and apply the common class directly in your markup:
<div className="d-box-border" />Error message:
Instead of redeclaring box-sizing: border-box in ".container", apply the common class 'd-box-border' from '~@dot-system/css-utility/es/utilities.plain.css' directly in your JSX/HTMLWhen a rule mixes common and non-common declarations, only the ones matching a common class are flagged; the rest can stay in your CSS.
