background
I did a little share before – [optimize] remember to use tools to reduce Git conflicts. Reduce collisions by using Git hooks to sort related code before committing it.
Last time my colleague reminded me that this Eslint can do it. I went back and looked it up, and it did. See sort-keys for details. If this rule is used, it requires that objects be written in a certain order. For example, if this rule is enabled, the following code will default to an error:
let obj = {a: 1.c: 3.b: 2};
Copy the code
Should be as follows:
let obj = {a: 1.b: 2.c: 3};
Copy the code
But there’s another scenario that we’re appealing to, and that’s object arrays. For example, in the following scenario, I need to determine the order of the objects in the array based on the label (note: the order of the array in our scenario has no effect on the business), Eslint does nothing.
const FlowList = [
{ value: '5'.label: 'a' },
{ value: '2'.label: 'C' },
{ value: '1'.label: 'B'}];Copy the code
Also, we know that ESLint rules can apply to a folder or file, but can they apply only to a block of code?
So how do we implement these points with the capabilities that Eslint exposes to us?
What is ESLint?
Official:
ESLint is a tool for identifying and reporting pattern matches in ECMAScript/JavaScript code with the goal of ensuring code consistency and avoiding errors
ESLint has the following features:
- Parse JavaScript using Espree.
- use
AST
To analyze patterns in your code. - Fully plug-in. Each rule is a plug-in that provides enough extensibility to allow us to better define usage rules.
To talk about ESlint we can’t do without the AST (Abstract syntax tree), we can use AstExplorer to see the structure of the AST generated after Espree processing. Var a = 1; As follows:
And if we know its structure, we can test it to see if it’s legal.
An important concept for AST Selectors is that it is a string used to match nodes in an abstract syntax tree (AST). This is useful for describing specific syntactic patterns in your code. The syntax of AST selectors is similar to that of CSS selectors. If you’ve used CSS selectors before, the syntax of AST selectors should be easy to understand. This will be important when we customize the rules later. The syntax can be found in the official documentation.
The principle of ESlint
To start writing our rules, let’s take a look at the implementation of ESlint in detail (only how individual rules are written is shown here, the overall ESlint action flow is not expanded here). Take sort-Keys as an example.
Each rule has three important files:
lib/rules
The directory is the source file, and the verification logic can be written here.tests/lib/rules
In the directory are the test files that write specific test cases.docs/rules
Document directory.
The source code for the above rule can be found in lib/rules/sort-keys.js. The source file for the rule exports objects with the following properties. Similar to the following:
module.exports = {
// Contains metadata for the rule
meta: {
// Rule type
type: "suggestion"./ / documentation
docs: {
description: "require object keys to be sorted".category: "Stylistic Issues".recommended: false.url: "https://eslint.org/docs/rules/sort-keys",},schema: [
// Some parameters that can be passed
{
enum: ["asc"."desc"],}],// Prompt message
messages: {
sortKeys:
"Expected object keys to be in {{natural}}{{insensitive}}{{order}}ending order. '{{thisName}}' should be before '{{prevName}}'.",}},create(context) {
return{}; }};Copy the code
-
Meta: The metadata that represents this rule, such as its category, document, schema of accepted parameters, etc., is described in detail in the official documentation and will not be described here.
-
Create: Meta expresses what we want to do, so create expresses how the rule will analyze the code.
Create returns an object, and the key is that AST Selector that we mentioned above, and in that AST Selector, we can get the selected thing, and then we can make a judgment about the selected thing, and see if it meets our rules, and if it doesn’t, We can throw a problem with context.report(), and ESLint will use our configuration to render the thrown content differently.
Add :exit at the end of the AST Selector to cause the listener to be called when the matching node is exited during traversal, rather than when the matching node is entered.
Custom ESlint plug-ins
You can quickly create ESLint plugin projects using the Yeoman Generator, a scaffolding tool that helps you quickly build your projects.
NPM i-g yo NPM i-g generator-eslint // Create a plugin yo eslint:plugin // Create a rule yo eslint:ruleCopy the code
The directory structure I created is as follows:
├─ ├─ ├─ exercises, exercises, exercises, exercises, exercises, exercises, exercises, exercises, exercises Rules file │ ├ ─ ─ index. Js │ └ ─ ─ rules │ ├ ─ ─ array - sort - object. Js │ └ ─ ─ sort. Js ├ ─ ─ package. The json ├ ─ ─ tests # unit test file │ └ ─ ─ lib │ └ ─ ─ rules │ ├ ─ ─ array - sort - object. Js │ └ ─ ─ sort. Js └ ─ ─ yarn. The lockCopy the code
How to test only part of the code?
We know that ESlint’s checks can specify file dimensions, but we want to check only parts of code. Otherwise like object array order, if all checks are turned on, there will be a lot of errors or warnings.
There are methods, and as we discovered, ESlint is an array of all comment markers in a given node that can be retrieved from an AST Selector using the getCommentsInside method. For example:
const FlowList = [
// eslint sortBy:'label'
{ value: '5'.label: 'a' },
{ value: '2'.label: 'C' },
{ value: '1'.label: 'B'}];Copy the code
create: function (context) {
// Get the sequential configuration. Default is ascending
const order = context.options[0] | |"asc";
// variables should be defined here
return {
ArrayExpression: (node) = > {
console.log('getCommentsBefore:', context.getCommentsInside(node))
}
}
Copy the code
The printed result is as follows, and we can use this information for processing. Only deal with the code if the comment hits a rule
Implement object array sort
The overall implementation code is as follows, the implementation is not difficult. Overall idea:
-
Get the field to compare (such as label in the example above).
// 获取到 comment const comment = context.getCommentsInside(node); if(! comment)return; // Get the sorted fields const field = comment[0] && comment[0].value && comment[0].value.split("'") [1]; if(! field)return; Copy the code
-
Get the value of each target field in the array ([‘a’, ‘C’, ‘B’]).
// take the median value of each sort object let fieldValueArr = node.elements.map(item= > { const target = (item.properties.find((prop) = > { return prop.key.name === field }) || { value: ' ' }); return target.value && target.value.value; }); Copy the code
-
The array is then tested sequentially, and if it does not match, we report an error.
// Sort by ascending order by default for (let i = 1; i < fieldValueArr.length; i++) { let reportError = false; if (order === 'asc' && String(fieldValueArr[i]).localeCompare(String(fieldValueArr[i - 1]))"0) { reportError = true; } else if (order === 'desc' && String(fieldValueArr[i]).localeCompare(String(fieldValueArr[i - 1)) >0) { reportError = true; } // Check if it is descending if (reportError) { context.report({ node, message: The array is not sorted correctly. Please according to${field}Field sort '});break; }}Copy the code
conclusion
Eslint is very important to a team’s code specification. Eslint comes with a lot of useful rules on its own. This article describes the fundamentals of Eslint and how to customize Eslint plugins to solve the problem of sorting object arrays. Welcome to join the discussion
reference
- Discusses how ESLint works
- Custom ESLint rules to keep code beautiful