preface
As the project grows larger, the number of people in charge of the project will increase or change, which means that people with different code styles will participate in the same project development at the same time, which will lead to “a hundred flowers bloom” in the code style of the project.
The question is, how do you maintain a uniform code style?
Isn’t that easy?
Use the ESLint plugin to load various rules to verify git commit in real time.
The problem is that when the rules provided by the community do not meet some of the more customized specifications, we need to use the ESLint plugin mechanism to validate the custom rules.
Some time ago, a plugin named ESlint-plugin-imports -sorter was implemented for some of the group’s more specific specifications, providing the following validation.
-
Check import sequence: Third-party library/official library > Absolute Path Resource > Relative path Resource
// error import React from 'react' import { BarEnum } from '.. /.. /const' import style from '.. /index.less' import utils from 'src/utils' import { pick } from 'loadsh' // right import React from 'react' import { pick } from 'loadsh' import utils from 'src/utils' import { BarEnum } from '.. /.. /const' import style from '.. /index.less' Copy the code
-
Different import order newline split (configurable)
import React from 'react' import { pick } from 'loadsh' import utils from 'src/utils' import { BarEnum } from '.. /.. /const' import style from '.. /index.less' Copy the code
-
Same import order, hierarchical sort (configurable)
import React from 'react' import { pick } from 'loadsh' import utils from 'src/utils' import style from '.. /index.less' import { BarEnum } from '.. /.. /const' Copy the code
-
Absolute path resource configuration alias
Since the automatic repair logic is provided, the configuration with VsCode (seeVsCode configures ESLint to save fixes), the following effects can be achieved.
The ESLint verification process
Here’s a preview of some general properties in ESLint configurations that affect final rule validation.
extends
Each item in ESLint eventually points to an object with the same configuration rules as ESLint itself, and thenESLint
All inherited configurations are merged recursivelyESLint
At its core are rules (rule
), each rule is independent of the other.- The final check is the combination
extends
,rule
,Nodes included by the ESLint comment command
While the generated configuration finally takes effect, callrunRules
Generated throughoutAST
Verify the node specified in the rule.
1. Obtain the rule configuration that takes effect
For example, 🌰
For rule no-var
Inherited rule :no-var:2
User-defined rule: no-var:1
User-defined command modification rule: no-var:0
Finally, no-var:0 takes effect
eslint/lib/linter/linter.js
The configuration structure of a custom command is as follows
/* Custom directive configuration generated according to AST+ annotations */
const commentDirectivesConfg = {
/* Partially modify the configuration information of some rules */
configuredRules: {},
/* Exported variableName specifies the exposed variables */
enabledGlobals: {},
exportedVariables: {},
problems: [].disableDirectives: [{type: 'disable-next-line'.line: xxx,
column: xxx,
ruleId: 'ruleId'}}]Copy the code
2,runRules
All rules are traversed and verified
Finally, each rule sets a listener to verify the current node.
conclusion
- Plug-ins integrate rules + rule configuration, and the implementation of the core logic of rules is
create
Methods. ESLint
The essence of the verification process is that the type node selected by the rule is traversed and verified based on all the valid rule configurations.
Ii. Disassemble into AST (omitted)
AST Explorer
3. Plug-in development process
2.1 To do a good job, you must sharpen your tools
Here we use the Yeoman scaffolding and the generator-ESLint generator to generate the default development template for the ESLint plug-in.
- Install dependencies
// Install Yeoman (sudo) NPM i-g yo // Install ESLint plugin template generator (sudo) NPM i-g generator-esLintCopy the code
- Create a template
// Find the folder where you want to create the plugin // initialize the template Yo eslint:pluginCopy the code
- Create a rule template
yo eslint:rule
Copy the code
Add some information about the rules
Note: Plugins are usually named eslint-plugin-xxx, but @xx/eslint-plugin-xx is also supported. In plug-in configuration, you only need to omit the beginning or middle eslint-plugin-xxx
-
The directory structure
Once generated, our default template should look like this figure.
Just a quick explanation of what these directories do
-docs /rules: lib/rules - Tests /libs/rules: unit tests under lib/rules - lib/rules: all rules - lib/index: plug-in configurationCopy the code
2.2 Local Real-time Debugging
Due to some limitations in the strings-only code that don’t fit perfectly into the real-world ESLint validation process, you need to link 🔗 locally to test.
// In the plugin project sudo NPM linkCopy the code
When the link is successful, we get the following result
// Switch to project project NPM link XXXXCopy the code
Next, the changes we make in the plug-in are synchronized to the project
2.3 Write rule logic
1. Configure plug-in parameters (click me to view) : specify which configuration items can be accepted by this rule, whether it can be automatically repaired, document link address, error message copywriting, etc.
Some of the more important parameters
- meta
- docs
- It: the rulesThe configuration fileIn the
"extends": "eslint:recommended"
Property whether to enable the rule.
- It: the rulesThe configuration fileIn the
- Fixable: Whether the error behavior provides a fix. If there is no
fixable
Property, even if the rule is implementedfix
Functionality, ESLint doesn’t eitherTo repair. If the rule is not fixable, omit itfixable
Properties. - Schema: Specifies the types of rule configuration parameters
- docs
interface Config {
/* The default value is true */
isCheckEmptyLine: boolean
/* Parity level: default false */
isCheckDeepth: boolean
/* Absolute path alias: default [' SRC ','@'] */
alias: Array<string>}Copy the code
The configuration items are in the following format when used
-
Create (function) returns an object containing the methods ESLint uses to access nodes while iterating through the abstract syntax tree AST (the AST defined by ESTree) of JavaScript code.
- If a key is a node type or selector, ESLint calls the visitor function while iterating down the tree
- If a key is a node type orselectorwith
:exit
In theupwardESLint is called when traversing the treevisitorfunction - If a key is an event name, ESLint calls handler functions for code path analysis
2, find the verification rule failure condition (click let me see)
- Firstly, it is relatively important for me to make clear which kind of node the scene to be verified is on.
Some rules can be implemented in multiple ways, but the cost of implementation depends to some extent on the type of AST node you set
// Here are all the node types supported by ESlint, which can be viewed at [https://astexplorer.net/]
const KNOWN_NODES = new Set([
"AssignmentExpression"."AssignmentPattern"."ArrayExpression"."ArrayPattern"."ArrowFunctionExpression"."AwaitExpression"."BlockStatement"."BinaryExpression"."BreakStatement"."CallExpression"."CatchClause"."ChainExpression"."ClassBody"."ClassDeclaration"."ClassExpression"."ConditionalExpression"."ContinueStatement"."DoWhileStatement"."DebuggerStatement"."EmptyStatement"."ExperimentalRestProperty"."ExperimentalSpreadProperty"."ExpressionStatement"."ForStatement"."ForInStatement"."ForOfStatement"."FunctionDeclaration"."FunctionExpression"."Identifier"."IfStatement"."Literal"."LabeledStatement"."LogicalExpression"."MemberExpression"."MetaProperty"."MethodDefinition"."NewExpression"."ObjectExpression"."ObjectPattern"."Program"."Property"."RestElement"."ReturnStatement"."SequenceExpression"."SpreadElement"."Super"."SwitchCase"."SwitchStatement"."TaggedTemplateExpression"."TemplateElement"."TemplateLiteral"."ThisExpression"."ThrowStatement"."TryStatement"."UnaryExpression"."UpdateExpression"."VariableDeclaration"."VariableDeclarator"."WhileStatement"."WithStatement"."YieldExpression"."JSXFragment"."JSXOpeningFragment"."JSXClosingFragment"."JSXIdentifier"."JSXNamespacedName"."JSXMemberExpression"."JSXEmptyExpression"."JSXExpressionContainer"."JSXElement"."JSXClosingElement"."JSXOpeningElement"."JSXAttribute"."JSXSpreadAttribute"."JSXText"."ExportDefaultDeclaration"."ExportNamedDeclaration"."ExportAllDeclaration"."ExportSpecifier"."ImportDeclaration"."ImportSpecifier"."ImportDefaultSpecifier"."ImportNamespaceSpecifier"."ImportExpression"
]);
Copy the code
- Read configuration items and write the logic for error determination. (Depending on the function of your rule)
3, throw error message and repair behavior (click me to view)
Whether the rule can be repaired depends on whether the cause of verification failure is subjective.
For example, 🌰
Scenario 1: During debugging, modify some variables and parameters temporarily for easy debugging. But occasionally I forget to revise it back.
/* esLint :todo */
The error with plugins like the one above is that they tend to be subjective, and you can’t be sure from context that the error can be fixed.
Specify the fix function when you use context.report(). The fix function takes an argument, a Fixer object, that you can use to fix. Such as:
context.report({
node: node,
message: "Missing semicolon".fix: function(fixer) {
return fixer.insertTextAfter(node, ";"); }});Copy the code
Important: ESLint will not fixa rule unless it outputs a meta.fixable attribute, even if the rule implements the fix function.
Note âš :
- Avoid any fixes that could change the runtime behavior of your code and cause it to stop working.
- Make as small a fix as possible. Fixes that are not necessary may conflict with other fixes and should be avoided.
- Make each message have only one fix. It’s mandatory because you have to go from
fix()
Returns the result of the repair operation.
reference
- Discusses how ESLint works
- Eslint.bootcss.com/docs/develo…