npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@adrian-alu0101024363/espree-logging-solution

v0.3.2

Published

Adds logs to javascript code

Downloads

13

Readme

Open in Codespaces

Práctica Espree logging

Docs module

Installation

npm i @adrian-alu0101024363/espree-logging-solution

Usage

import { transpile } from "@adrian-alu0101024363/espree-logging-solution";
let inputfile = "test1.js";
let outputfile = "out1.js";
transpile(inputfile, outputfile);

Test

npm test

Resumen de lo aprendido

Debugging con Chrome

  • Ejecutamos en la terminal
node --inspect-brk bin/log.js test/data/test1.js 

Puede ser cualquier test y cualquier opción pero para esta demostración usaré el test1.

brk

  • Abrimos Chrome y escribimos chrome://inspect resultando en la siguiente pantalla:

inspect

  • Le damos a inspect. Importante que hayamos puesto debugger en alguna línea de nuestro código ya que es el breakpoint para chrome

  • A partir de aquí podemos manejarnos como con cualquier otro debugger entrando en una función, ejecutando paso a paso, ejecución hasta el final, etc.

debug

  • Por ejemplo podemos ver aquí como lee la function foo, muestra que tiene dos parametros a y b, vemos su información del nodo type, start, etc y vemos que en beforeCode esta nuestra console.log string

foo

fooi

Descripción de las funciones

  • transpile se encarga de leer el archivo de input pasarle la información a la función addLogging y escribir el resultado en el argumento dado (por commander).
  • Tener en cuenta que necesitamos asegurarnos de que el archivo ha sido leído antes de hacer cualquier otra cosa así que la llamada a addLogging.
  if (inputFile) {
    let input = await fs.readFile(inputFile, 'utf-8');
    const output = addLogging(input);
    if (outputFile === undefined) {
      console.log(output);
      return;
    }
    await fs.writeFile(outputFile, output);
  } else program.help();
  ...
  • la función addLogging recoge este input añade los comentarios usando addBeforeCode y devuelve "javascript" con el resultado. Osea devuelve el texto de lo que debería ser el javascript.

  • addLogging primero genera el ast del código input, luego lo recorremos y por cada nodo de dicho árbol miramos si el tipo del nodo es alguno de los que nos interesa. Si es el caso llamamos a addBeforeCode pasandole dicho nodo. Hacemos esto con cada nodo y devolvemos el "código javascript" usando escodegen.generate

  • addBeforeCode primero comprueba si es función anonima o no para asignarle un nombre, luego usando map guardamos un vector con los parametros del nodo. Seguidamente creamos con dichas variables un console.log que va a ser insertado. Para insertarlo primero necesitamos parsear esta string y luego la insertamos en el body del body del node que ha sido pasado.

  • A tener en cuenta insertamos en el body porque es ahí donde esta todo el cuerpo del nodo. No debemos sobreescribir las otras partes del nodo.

  • Para que sea mas claro lo explicado sobre el body presento esta imagen:

ast

  • de este código:
function foo(a, b) {   
    var x = 'blah';   
    var y = (function () {
      return 3;
    })();
  }     
foo(1, 'wut', 3);

El ejecutable

El ejecutable está en bin/log.js este archivo simplemente implementa commander como será explicado en su sección y luego usa el método transpile de logging-espree.js

✗ bin/logging.js -h
Usage: jslogging [options] <filename>

Adds logs to javascript code

Arguments:
  filename                 file with the original code

Options:
  -V, --version            output the version number
  -o, --output <filename>  file in which to write the output (default: "output.js")
  -h, --help               display help for command
git:(main) ✗ cat test/test1.js 
function foo(a, b) {   
    var x = 'blah';   
    var y = (function () {
      return 3;
    })();
  }     
foo(1, 'wut', 3);
➜  git:(template) ✗ bin/logging.js test/test1.js -o salida.js
File read succesfully
Output written succesfully in salida.js
➜  git:(template) ✗ node salida.js
Entering foo(1, wut) at line 1
Entering <anonymous function>() at line 3

Usando un script de npm de nuestro package.json podemos ejecutar el programa también de esta manera:

npm run execute test/data/test1.js -- -o out.js

Podemos ejecutar cualquiera de la opciones por ejemplo -h:

help

eje

CLI con Commander.js

Commander.js nos permite simplificar tanto el control de argumentos pasados por consola como el de opciones. Tal y como se ve en el código siguiente si queremos un argumento obligatorio usamos .argument() si queremos una opción usamos .option() pasandole primero la sintaxis de la opción luego la descripción y por último la opción por defecto. En este caso es un archivo por defecto llamado output.js. Por último tenemos la acción con action() a la que cúal se le pasa una función (en este caso anónima) con lo que debería ejecutar (en este caso nuestro método transpile del archivo logging-espree.js). Version y description vienen dado por nuestro package.json el que ha sido requerido antes.

program
    .name("jslogging")
    .version(version)
    .description(description)
    .argument("<filename>", 'file with the original code')
    .option("-o, --output <filename>", "file in which to write the output", "output.js")
    .action((filename, options) => {
       transpile(filename, options.output);
    });

program.parse(process.argv);

Reto 1: Soportar funciones flecha

Para superar este reto necesitamos comprobar que el tipo del nodo es ArrowFunctionExpression para ello añadimos esta condición al if de cuando atravesamos el árbol. Además en la función addBeforeCode como la funciones flecha no tienen nombre(name) necesitamos cambiar la asignación de la variable name dependiendo de si el nodo tienen name o no de esta manera:

const name = node.id ? node.id.name : '<anonymous function>';
function addLogging(code) {
  let ast = espree.parse(code, {ecmaVersion:6, loc:true});
  estraverse.traverse(ast, {
      enter: function(node, parent) {
          if (node.type === 'FunctionDeclaration' ||
              node.type === 'FunctionExpression' ||
              node.type === 'ArrowFunctionExpression') {
              addBeforeCode(node);
          }
      }
  });
  return escodegen.generate(ast);
}

Reto 2: Añadir el número de línea

Para conseguir este reto necesitamos primero añadir al parse la opción loc:true (o al menos la necesite para que me aceptará luego node.loc.start.line) este parse se encuentra en la función addLogging. Luego en la función addBeforeCode necesitamos añadir a nuestra string beforeCode el número de línea usando node.loc.start.line. A continuación se muestra el cambio y la función addBeforeCode:

  let ast = espree.parse(code, {ecmaVersion:6, loc:true});
function addBeforeCode(node) {
  const name = node.id ? node.id.name : '<anonymous function>';
  const parameters = node.params.map(param => `\$\{${param.name}\}`);
  const beforeCode = `console.log(\`Entering ${name}(${parameters}) at line ${node.loc.start.line}\`);`;
  const beforeNodes = espree.parse(beforeCode,{ecmaVersion:6}).body;
  node.body.body = beforeNodes.concat(node.body.body);
}

Tests

Primero se han probado a mano con varios test el correcto funcionamiento del programa. Luego usando npm scripts se ha automatizado el proceso. Simplemente ejecutando npm test se realizan todos los test disponibles en la carpeta test. Esto simplemente hace una diferencia de ficheros entre el que genera el programa y el "correcto" por tanto si queremos añadir tests nuevos necesitamos añadir el "correcto" también. Esto funciona así por ser una práctica de la asignatura PL. Veamos los tests y los resultados:

Test 1

function foo(a, b) {   
    var x = 'blah';   
    var y = (function () {
      return 3;
    })();
  }     
foo(1, 'wut', 3);
// Result
function foo(a, b) {
    console.log(`Entering foo(${ a },${ b }) at line 1`);
    var x = 'blah';
    var y = function () {
        console.log(`Entering <anonymous function>() at line 3`);
        return 3;
    }();
}
foo(1, 'wut', 3);

Test 2

function foo(a, b) {
  var x = 'blah';
  var y = (function (z) {
    return z+3;
  })(2);
}
foo(1, 'wut', 3);
// Result
function foo(a, b) {
    console.log(`Entering foo(${ a },${ b }) at line 1`);
    var x = 'blah';
    var y = function (z) {
        console.log(`Entering <anonymous function>(${ z }) at line 3`);
        return z + 3;
    }(2);
}
foo(1, 'wut', 3);

Test 3

function foo(a, b, c) {
    let x = 'tutu';
    let y = (function (x) { return x*x })(2);
    let z = (e => { return e +1 })(4);
    console.log(x,y,z);
  }
foo(1, 'wut', 3);
// Result
function foo(a, b, c) {   
    console.log(`Entering foo(${ a },${ b },${ c }) at line 1`);
    let x = 'tutu';
    let y = function (x) {
        console.log(`Entering <anonymous function>(${ x }) at line 3`);
        return x * x;
    }(2);
    let z = (e => {
        console.log(`Entering <anonymous function>(${ e }) at line 4`);
        return e + 1;
    })(4);
    console.log(x, y, z);
}
foo(1, 'wut', 3);

Ejecución conjunta con npm test

test

...

Coverage

cov

Indicar los valores de los argumentos

Se ha modificado el código de logging-espree.js para que el log también indique los valores de los argumentos que se pasaron a la función. Ejemplo:

function foo(a, b) {
  var x = 'blah';
  var y = (function (z) {
    return z+3;
  })(2);
}
foo(1, 'wut', 3);
function foo(a, b) {
    console.log(`Entering foo(${ a }, ${ b })`);
    var x = 'blah';
    var y = function (z) {
        console.log(`Entering <anonymous function>(${ z })`);
        return z + 3;
    }(2);
}
foo(1, 'wut', 3);

Publicación en npm

  • Primero debemos logearnos (o crear una cuenta) en la web o bien seguimos los siguientes pasos.
  • Por consola sería primeramente configurar npm con estos comandos:
npm set init.author.name "Casiano Rodriguez-Leon"
npm set init.author.email "[email protected]"
npm set init.author.url "https://github.com/crguezl"
  • Y añadimos el usuario al registry con npm adduser
  • Logeamos con npm login y comprobamos que estamos dentro con npm whoami
  • Para evitar conflictos debemos usar un scope bajo el que publicaremos nuestros módulos npm.
  • Para ello añadimos @username/project-name (rellenado con los datos correctos) en el name del package.json
  • Por último publicamos con:
npm publish --access=public

-- Con npm version patch/minor/major podemos cambiar el versionado -- Y al hacer esto se crean las tags correspondientes -- Para probar simplemente tras linkear o instalar el modulo ponemos en la consola funlog inputfile Enlace de este mismo módulo publicado: https://www.npmjs.com/package/@adrian-alu0101024363/espree-logging-solution

Enlace de pages: https://ull-esit-pl-2223.github.io/espree-logging-adrian-fleitas-de_la_rosa-alu0101024363/