当前位置:网站首页>Develop stylelint rules from zero (plug-ins)
Develop stylelint rules from zero (plug-ins)
2022-06-30 06:00:00 【Front end Kakashi】
This article , We develop a custom... From scratch Stylelint Plug in project .
For the full project address, see
One 、 Preparation stage
- PostCss Official website (Stylelint Use PostCss First the css The content is parsed into AST Abstract syntax tree , Pass again AST Perform analytical processing , Achieve desired results . you 're right Eslint In the same way );
- Stylelint Official website ( Want to learn a technology , First look at its official website )
- StylelintGitHub ( Copy sth. without catching its spirit )
- development environment :macOs-12.1 Apple M1 Pro( Less important , It may be related to later plug-ins )
Two 、 The development phase
1. Create directory
Open the terminal tool ( I am using iterm),cd To the directory where items are normally stored ;
type mkdir stylelint-plugin Create a file called stylelint-plugin Folder ;
2. npm initialization
cd Into the stylelint-plugin Catalog , type npm init , Then all the way back , According to the prompt Just enter the content ;
After this step , There will be a new package.json file ;
3. Construct the project structure
Modelled on the StylelintGitHub The structure of the construction project is as follows :
├── lib // The relevant contents of the rules are put in `lib` Catalog
│ ├── index.js
│ ├── rules
│ │ ├── index.js
│ │ └── selector-class-no-elements // Under each folder is a rule , The folder name is the rule name
│ │ └── index.js // The content of the rules
│ └── utils
├── package.json
└── README.md
4. The installation part depends on
npm install stylelint postcss-selector-parser -D
- We develop
selector-class-no-elementsRule as an example , Write code .
The meaning of this rule is :class Selectors cannot be in the form of ’elements-' start
Because third-party component libraries (ElementUI、Ant Design etc. ), The component name starts with ’elements-' start , Do not override styles for these three-party components during development , So as not to cause unpredictable bug.
======================================
Let's plug in here , Have a look first css What is the parsed content
step 4 in Installed postcss-selector-parser plug-in unit , It's parsing css Selector in ,
First create a in the root directory test.js file , The contents are as follows :
const SelectorParser = require('postcss-selector-parser');
const transform = selectors => {
selectors.walk(node => {
console.log(node);
})
}
SelectorParser(transform).processSync('#app');
And then run node test.js, log give the result as follows :
The former “Selector” type Express Selectors ;
the latter “ID” type Express ID Selectors
======================================
5. Formal development :
lib/rules/selector-class-no-elements/index.js The contents are as follows :
/* * @Desc: class Selectors cannot be in the form of "elements-" start * @Author: Front end Kakashi * @Date: 2022-06-25 17:10:14 */
const {
nameSpace, newMessage, validateOptions, report } = require('../../utils');
const parseSelector = require("../../utils/parseSelector");
const ruleName = nameSpace('selector-class-no-elements');
const messages = newMessage(ruleName, {
expected: (selector => `Expected CLASS selector ".${
selector}" not to contain "elements-"`)
})
const rule = primary => {
return (postcssRoot, postcssResult) => {
const validOptions = validateOptions(postcssRoot, postcssResult, {
actual: primary
})
if (!validOptions) return;
// walkRules To traverse all Rule Types of nodes
postcssRoot.walkRules(ruleNode => {
const selector = ruleNode.selector;
parseSelector(selector, postcssResult, ruleNode, (fullSelector) => {
// walk Is traversal , Same as forEach
fullSelector.walk(selectorNode => {
// Screening class Selectors
if (selectorNode.type !== 'class') return;
const {
value, sourceIndex} = selectorNode;
// Filter to "elements-" The opening selector
if (value.indexOf('elements') !== 0) return;
// Mark the end of the prompt
const endIndex = sourceIndex + value.length;
// Prompt user information
report({
result: postcssResult,
ruleName,
message: messages.expected(value),
node: ruleNode,
index: sourceIndex,
endIndex
})
})
})
})
}
}
rule.ruleName = ruleName;
rule.messages = messages;
module.exports = rule;
lib/utils/index.js The contents are as follows
const stylelint = require("stylelint")
function nameSpace(ruleName) {
// The prefix depends on the individual
return `stylelint-plugin/${
ruleName}`;
}
function newMessage(ruleName, options) {
return stylelint.utils.ruleMessages(ruleName, options);
}
function validateOptions(result, ruleName, options) {
return stylelint.utils.validateOptions(result, ruleName, options);
}
function report(problem) {
console.log({
problem});
return stylelint.utils.report(problem);
}
module.exports = {
nameSpace,
newMessage,
validateOptions,
report
}
lib/utils/parseSelector.js The contents are as follows :
const SelectorParser = require("postcss-selector-parser");
module.exports = function parseSelector(selector, result, node, callback) {
try {
return SelectorParser(callback).processSync(selector);
} catch(err) {
result.warn(`Cannot parse selector (${
err})`, {
node, stylelintType: 'parseError' });
return undefined;
}
}
lib/rules/index.js The contents are as follows :
const selectorClassNoElements = require('./selector-class-no-elements');
const rules = {
"selector-class-no-elements": selectorClassNoElements
}
module.exports = rules;
lib/index.js The contents are as follows :
const {
createPlugin } = require("stylelint");
const {
nameSpace } = require("./utils");
const rules = require("./rules");
// adopt createPlugin establish plugin
const rulesPlugins = Object.keys(rules).map(ruleName => {
return createPlugin(nameSpace(ruleName), rules[ruleName])
})
module.exports = rulesPlugins;
6. Write test cases
The test case With the help of jest Tools .
- Install the corresponding dependencies first :
npm i jest jest-preset-stylelint -D
- To configure jest, stay
package.jsonThe following configuration is added in :
...
"jest": {
"clearMocks": true,
"collectCoverage": false,
"collectCoverageFrom": [
"lib/**/*.js"
],
"coverageDirectory": "./.coverage/",
"coverageReporters": [
"lcov",
"text"
],
"coverageThreshold": {
"global": {
"branches": 75,
"functions": 75,
"lines": 75,
"statements": 75
}
},
"setupFiles": [
"./jest-setup.js"
],
"testEnvironment": "node",
"roots": [
"lib"
],
"testRegex": ".*\\.test\\.js$|lib/.*/__tests__/.*\\.js$"
},
...
- Created in the root directory
jest-setup.jsfile , The contents are as follows :
const getTestRule = require('jest-preset-stylelint/getTestRule');
global.testRule = getTestRule({
plugins: ["./lib"] });
lib/rules/selector-class-no-elements/__tests__/index.jsWrite test code in :( Add one under each rule __tests__/index.js Test case file )
const {
messages, ruleName} = require("..");
testRule({
ruleName,
config: true,
// Use cases can be used
accept: [
{
code: '.app {}' }
],
// Not through use cases
reject: [
{
code: '.elements-app {}',
message: messages.expected('elements-app'),
line: 1, // Prompt to start line
column: 1, // Prompt start position
endLine: 1, // Prompt end line
endColumn: 13 // Prompt end position
}
]
})
7. npm run test
package.json To configure :
...
"scripts": {
"test": "jest"
},
...
function npm run test
The result is as follows. , Be accomplished .
8. The final directory structure
├── jest-setup.js
├── lib
│ ├── index.js
│ ├── rules
│ │ ├── index.js
│ │ └── selector-class-no-elements
│ │ ├── __tests__
│ │ │ └── index.js
│ │ └── index.js
│ └── utils
│ ├── index.js
│ └── parseSelector.js
├── package-lock.json
├── package.json
├── test.js
└── README.md
3、 ... and 、 Project coverage testing
Rule development is complete , You need to find a project for coverage testing . Generally, this kind of tool project is directly published to NPM Warehouse , Use through npm install xxx install .
To not publish npm package , Local testing Can pass npm link command , At the local node_modules Generate a soft link in , Link to the Development Directory .
- Execute... In the directory above
npm linkGenerate soft links
If npm link Later error reporting :npm ERR! Error: EACCES: permission denied, Because of permission , You can use sudo npm link retry .
cd To test engineering ,“ install ” stylelint-plugin rely on

Open thenode_modules, You can see :
Configure the test project
.stylelintrc.js
module.exports = {
...
"plugins":[
"stylelint-plugin"
...
],
rules: {
'stylelint-plugin/selector-class-no-elements': true,
...
},
};
边栏推荐
- Finally someone can make the server so straightforward
- 86. separate linked list
- MySQL advanced SQL statement
- 股票在网上开户安全吗?在网上能不能开户炒股呢?
- Xi'an Jiaotong 21st autumn online expansion resources of online trade and marketing (II)
- 动态规划--怪盗基德的滑翔翼
- Learning automation ppt
- 2022年,谁在推动音视频产业的新拐点?
- 【学习强化学习】总目录
- luoguP2756 飞行员配对方案问题(最大流)
猜你喜欢

What do you think of the deleted chat records? How to restore the deleted chat records on wechat?

【板栗糖GIS】global mapper—如何把栅格的高程值赋予给点
![[ansible series] fundamentals 02 module debug](/img/99/c53be8e2a42c7cb5b4a9a7ef4ad98c.jpg)
[ansible series] fundamentals 02 module debug
![09- [istio] istio service entry](/img/48/86f8ec916201eefc6ca09c45a60a6a.jpg)
09- [istio] istio service entry

Strlen and sizeof, array length and string length, don't be silly

C语言基础小操作

token 过期后,如何自动续期?
![[GPU] basic operation of GPU (I)](/img/ce/0ca8c63525038fea64c40aabd17fc6.jpg)
[GPU] basic operation of GPU (I)

雲服務器部署 Web 項目

Mysql database user management
随机推荐
Sword finger offer 18 Delete the node of the linked list
You don't know how to deduce the location where HashSet stores elements?
Intelligent deodorizer embedded development
旋转标注工具roLabelImg
Who is promoting the new inflection point of audio and video industry in 2022?
PC viewing WiFi password
[MD editing required] welcome to the CSDN markdown editor
Voting vault: a new primitive for defi and Governance
After getting these performance test decomposition operations, your test path will be more smooth
We strongly recommend more than a dozen necessary plug-ins for idea development
09- [istio] istio service entry
[Alibaba cloud] student growth plan answers
At the beginning of 2022, people who are ready to change jobs should pay attention to
How does WPS cancel automatic numbering? Four options
About modifying dual system default startup item settings
[OSPF] comparison between rip and OSPF
谁不想要一个自己的博客网站呢 - 搭建博客网站wordpress
hashlips_ art_ Engine-1.0.6 usage
Related applications of priority queue
Shenzhou ares tx6 boot logo modification tutorial