Reglas avanzadas de linting con ESLint

Rate this content
Bookmark

Esta charla explorará formas más avanzadas de escribir reglas de análisis estático en ESLint utilizando las APIs de flujo de control de ESLint. Explicaré rápidamente qué es un grafo de flujo de control y cómo puedes usarlo para encontrar problemas en tu código. Te mostraré cómo detectar cuándo se asigna un valor a una variable de manera inútil y otros problemas lógicos que puedes detectar utilizando esta técnica.

10 min
21 Sep, 2023

AI Generated Video Summary

Tibor Blanesy de Sonar presenta técnicas avanzadas para el linting con ESLint, incluyendo el uso de ControlFlowGraph para detectar errores en el código. El algoritmo se basa en el análisis de vivacidad, que identifica las variables vivas en cualquier punto del programa. Además, la charla cubre el cálculo de conjuntos de bloques utilizando la diferencia entre el conjunto de salida y el conjunto de eliminación unido con genset.

1. Técnicas Avanzadas para Linting con ESLint

Short description:

¡Hola! Mi nombre es Tibor Blanesy, trabajo en el análisis estático de JavaScript en Sonar, y en esta charla me gustaría mostrarte algunas técnicas más avanzadas para el linting con ESLint. Echemos un vistazo a una función que devuelve un rango de números entre dos valores pasados como argumento. Si no se proporciona el argumento, asumirá que el rango debe comenzar desde cero. Utilizaremos una representación del código llamada ControlFlowGraph para detectar errores en el código. La base del algoritmo es el análisis de vivacidad, que nos dice qué variables están vivas en cualquier punto del programa.

Mi nombre es Tibor Blanesy, trabajo en el análisis estático de JavaScript en Sonar, y en esta charla me gustaría mostrarte algunas técnicas más avanzadas para el linting con ESLint. Echemos un vistazo a la siguiente función, que encontré en el código base de VS Code. Esta función devuelve un rango de números entre dos valores pasados como argumento.

Si no se proporciona el argumento, asumirá que el rango debe comenzar desde cero. Cuando utilizamos herramientas de análisis estático, como SonarQube, nos mostrará rápidamente que hay un problema con este código. Por alguna razón, el valor asignado a la variable 'from' nunca se utiliza más adelante en el código. La lógica que maneja los argumentos está duplicada.

Este tipo de errores, cuando el valor asignado a la variable no se utiliza, se llama un almacenamiento muerto. SonarQube proporciona la siguiente explicación de por qué esto es un problema. Un almacenamiento muerto ocurre cuando una variable local se le asigna un valor que no es leído por ninguna instrucción posterior. Calcular o recuperar un valor solo para luego sobrescribirlo o desecharlo podría indicar un error grave en el código. Incluso si no es un problema, es como mínimo un desperdicio de recursos. Por lo tanto, se deben utilizar valores sobrecalculados. En los próximos minutos intentaré explicar cómo se pueden detectar este tipo de errores con el análisis estático.

Primero, utilizaremos una representación del código llamada ControlFlowGraph. En esta representación, un nodo llamado bloques básicos contiene solo declaraciones que se ejecutan secuencialmente. Los saltos se representan como flechas entre los bloques. Así que aquí tenemos un ControlFlowGraph para la función que mostré anteriormente. Solo mostraremos una parte del grafo, que es relevante para el problema, para mantenerlo pequeño. En la siguiente diapositiva, tengo el mismo ControlFlowGraph anotado en rojo, con eventos que son proporcionados por ESLint cuando escribimos una regla personalizada. La API de ESLint proporciona dos objetos, CodePath, que representa el flujo de control de toda la función, y ControlPathSegment para cada bloque básico. Luego, ESLint dispara eventos para el inicio y fin de CodePath, y para el inicio y fin de cada bloque básico, que es un CodePathSegment.

Entonces, en el código, lo que escribiremos es el siguiente objeto, que contiene un controlador de eventos para los eventos de CodePath. No tenemos tiempo para entrar en detalles de implementación, pero en las siguientes diapositivas, describiré rápidamente los conceptos básicos del algoritmo. La base del algoritmo es el análisis de vivacidad, que nos dice qué variables están vivas en cualquier punto del programa. La variable está viva cuando el valor que contiene podría ser necesario en el futuro. Para cada bloque básico, calcularemos cuatro conjuntos de variables. El conjunto de inicio con las variables que se leen en el bloque básico, el conjunto de eliminación, que contiene las variables que se escriben en el bloque básico, el conjunto de entrada con las variables que están vivas al comienzo del bloque, y el conjunto de salida con las variables que están vivas al final del bloque. Para calcular estos conjuntos, utilizaremos las siguientes dos reglas. El conjunto de salida del bloque actual es la unión de todos los conjuntos de entrada de sus sucesores.

2. Cálculo de Conjuntos de Bloques

Short description:

El conjunto de entrada del bloque actual es la diferencia entre el conjunto de salida y el conjunto de eliminación, unido con genset. Calcularemos los valores de estos conjuntos comenzando desde el fondo del grafo y moviéndonos hacia los predecesores de cada bloque.

El conjunto de entrada del bloque actual es la diferencia entre el conjunto de salida y el conjunto de eliminación, unido con genset. Ahora pasaré por los bloques básicos de la función que mostré anteriormente, y calcularemos los valores de estos conjuntos. Así que comenzaremos desde el fondo del grafo para calcular los conjuntos de este bloque básico. Así que asumiremos que 'from' y 'to' se leen más adelante en la función, por lo que genset se establece en 'from' y 'to', y ignoraremos que hay algo escrito, por lo que el conjunto de eliminación estará vacío. A partir de esto, podemos calcular el conjunto de entrada como 'from' y 'to', y ahora nos moveremos a los predecesores de este bloque. Como el conjunto de entrada del bloque sucesor es 'from' y 'to', podemos decir que el conjunto de salida también es 'from' y 'to', siguiendo la primera regla. En este bloque básico, estamos leyendo el valor de 'arc', por lo que genset es 'arc' y estamos escribiendo los valores de 'from' y 'to', por lo que el conjunto de eliminación es 'from' y 'to'. A partir de esto, podemos calcular el conjunto de entrada como la diferencia entre el conjunto de salida y el conjunto de eliminación. Como estos conjuntos son iguales, la diferencia será vacía. El conjunto de entrada es la unión de vacío con genset, que contiene 'arc'. Por lo tanto, el conjunto de entrada será 'arc'. Ahora nos movemos a otro bloque donde nuevamente el conjunto de salida se establece como el conjunto de entrada del bloque sucesor, por lo que es 'from' y 'to'. Estamos leyendo el valor de 'arc', por lo que genset es 'arc' y estamos escribiendo el valor de 'from'. A partir de esto, podemos calcular que el conjunto de entrada es 'arc' y 'to'. Cuando nos movemos al predecesor de estos dos bloques, podemos establecer el conjunto de salida como la unión del conjunto de entrada de los bloques sucesores, por lo que es 'arc' y 'to'. Estamos leyendo el valor de 'to', por lo que genset es 'to' y no estamos escribiendo ninguna variable, por lo que el conjunto de eliminación está vacío. A partir de esto, podemos calcular el conjunto de entrada como la diferencia entre el conjunto de salida y el conjunto de eliminación, que es 'arc' y 'to', y unirlo con 'to', lo cual no cambia nada. A partir de aquí, nos movemos al predecesor de este bloque, por lo que sabemos que el conjunto de salida es 'arc' y 'to', estamos leyendo el valor de 'arc', por lo que genset es 'arc', estamos escribiendo el valor de 'from', por lo que el conjunto de eliminación contiene 'from', y a partir de esto podemos calcular el conjunto de entrada como 'arc' y 'to'. En el siguiente bloque, la situación es casi idéntica, el conjunto de salida es 'arc' y 'to', estamos escribiendo el valor de 'from', por lo que el conjunto de eliminación es 'from', no estamos leyendo ninguna variable, por lo que genset está vacío. A partir de esto, calculamos el conjunto de entrada como 'arc' y 'to'. Y ahora nos movemos al primer bloque donde el conjunto de salida es 'arc' y 'to', estamos leyendo el valor de 'to', por lo que genset es 'to', no estamos escribiendo ninguna variable, por lo que el conjunto de eliminación está vacío, por lo tanto, podemos calcular el conjunto de entrada como 'arc' y 'to'. Así que ahora hemos calculado los valores de estos bloques básicos. Cada vez que calculamos el conjunto de entrada del bloque, necesitamos recalcular los predecesores de los bloques. Esto es especialmente importante si hay bucles en el grafo, porque necesitaremos continuar hasta que los conjuntos no cambien más. Una vez que esto esté terminado, podemos analizar los valores calculados y detectar los problemas. Generaremos un problema para cada variable que forma parte del conjunto de eliminación, lo que significa que se está escribiendo, pero no forma parte del conjunto de salida del bloque, lo que significa que el valor nunca se necesita en los bloques posteriores. Por lo tanto, en este caso, en nuestra función, 'from()' se escribe al principio, pero no se lee en ningún bloque posterior porque se vuelve a escribir. Por eso generaremos un problema en esta llamada a 'from()'. Si quieres, puedes echar un vistazo a la implementación completa de este algoritmo en nuestro analizador de JavaScript, que es un proyecto de código abierto en GitHub, y el algoritmo se encuentra en la regla 18.54. Este analizador se utiliza en SonarQube, SonarCloud o SonarLink. Espero que hayas encontrado interesante esta charla, y gracias por tu atención. ¡Adiós!

Check out more articles and videos

We constantly think of articles and videos that might spark Git people interest / skill us up or help building a stellar career

JSNation 2023JSNation 2023
29 min
Modern Web Debugging
Few developers enjoy debugging, and debugging can be complex for modern web apps because of the multiple frameworks, languages, and libraries used. But, developer tools have come a long way in making the process easier. In this talk, Jecelyn will dig into the modern state of debugging, improvements in DevTools, and how you can use them to reliably debug your apps.
JSNation 2022JSNation 2022
21 min
The Future of Performance Tooling
Our understanding of performance & user-experience has heavily evolved over the years. Web Developer Tooling needs to similarly evolve to make sure it is user-centric, actionable and contextual where modern experiences are concerned. In this talk, Addy will walk you through Chrome and others have been thinking about this problem and what updates they've been making to performance tools to lower the friction for building great experiences on the web.
DevOps.js Conf 2022DevOps.js Conf 2022
31 min
pnpm – a Fast, Disk Space Efficient Package Manager for JavaScript
You will learn about one of the most popular package managers for JavaScript and its advantages over npm and Yarn.A brief history of JavaScript package managersThe isolated node_modules structure created pnpmWhat makes pnpm so fastWhat makes pnpm disk space efficientMonorepo supportManaging Node.js versions with pnpm
React Advanced Conference 2021React Advanced Conference 2021
20 min
Advanced Patterns for API Management in Large-Scale React Applications
In this talk, you will discover how to manage async operations and request cancellation implementing a maintainable and scalable API layer and enhancing it with de-coupled cancellation logic. You will also learn how to handle different API states in a clean and flexible manner.
React Advanced Conference 2021React Advanced Conference 2021
27 min
Beyond Virtual Lists: How to Render 100K Items with 100s of Updates/sec in React
There is generally a good understanding on how to render large (say, 100K items) datasets using virtual lists, …if they remain largely static. But what if new entries are being added or updated at a rate of hundreds per second? And what if the user should be able to filter and sort them freely? How can we stay responsive in such scenarios? In this talk we discuss how Flipper introduced map-reduce inspired FSRW transformations to handle such scenarios gracefully. By applying the techniques introduced in this talk Flipper frame rates increased at least 10-fold and we hope to open-source this approach soon.

Workshops on related topic

React Summit 2023React Summit 2023
170 min
React Performance Debugging Masterclass
Featured WorkshopFree
Ivan’s first attempts at performance debugging were chaotic. He would see a slow interaction, try a random optimization, see that it didn't help, and keep trying other optimizations until he found the right one (or gave up).
Back then, Ivan didn’t know how to use performance devtools well. He would do a recording in Chrome DevTools or React Profiler, poke around it, try clicking random things, and then close it in frustration a few minutes later. Now, Ivan knows exactly where and what to look for. And in this workshop, Ivan will teach you that too.
Here’s how this is going to work. We’ll take a slow app → debug it (using tools like Chrome DevTools, React Profiler, and why-did-you-render) → pinpoint the bottleneck → and then repeat, several times more. We won’t talk about the solutions (in 90% of the cases, it’s just the ol’ regular useMemo() or memo()). But we’ll talk about everything that comes before – and learn how to analyze any React performance problem, step by step.
(Note: This workshop is best suited for engineers who are already familiar with how useMemo() and memo() work – but want to get better at using the performance tools around React. Also, we’ll be covering interaction performance, not load speed, so you won’t hear a word about Lighthouse 🤐)
React Advanced Conference 2021React Advanced Conference 2021
174 min
React, TypeScript, and TDD
Featured WorkshopFree
ReactJS is wildly popular and thus wildly supported. TypeScript is increasingly popular, and thus increasingly supported.

The two together? Not as much. Given that they both change quickly, it's hard to find accurate learning materials.

React+TypeScript, with JetBrains IDEs? That three-part combination is the topic of this series. We'll show a little about a lot. Meaning, the key steps to getting productive, in the IDE, for React projects using TypeScript. Along the way we'll show test-driven development and emphasize tips-and-tricks in the IDE.
JSNation Live 2021JSNation Live 2021
86 min
Build React-like apps for internal tooling 10x faster with Retool
Workshop
Most businesses have to build custom software and bespoke interfaces to their data in order to power internal processes like user trial extensions, refunds, inventory management, user administration, etc. These applications have unique requirements and often, solving the problem quickly is more important than appearance. Retool makes it easy for js developers to rapidly build React-like apps for internal tools using prebuilt API and database interfaces as well as reusable UI components. In this workshop, we’ll walk through how some of the fastest growing businesses are doing internal tooling and build out some simple apps to explain how Retool works off of your existing JavaScript and ReactJS knowledge to enable rapid tool building.
Prerequisites:A free Retool.com trial accountSome minimal JavaScript and SQL/NoSQL database experience
Retool useful link: https://docs.retool.com/docs
GraphQL Galaxy 2021GraphQL Galaxy 2021
130 min
Everything You Need to Get Your GQL Server Production Ready
WorkshopFree
There are always a lot of questions and conference talks about bringing GraphQL servers into production, but there aren’t a lot of good concrete steps and actions to follow. In the workshop Uri (The founder of The Guild) will walk you through The Guild’s process of bringing GraphQL Server into production.

We will add:

- Powerful Caching
- Logging, Monitoring and tracing
- Security features like Auth, Error Masking, Persisted Operations, Depth and Rate limit
If you are planning to have your GraphQL server running in production, this is a must have workshop for you!