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

@alu0101390161/espree-logging

v1.1.0

Published

Adds logs to javascript code

Downloads

10

Readme

Open in Codespaces

Lab: Espree logging

Información de la práctica

  • Universidad de La Laguna
  • Escuela Superior de Ingeniería y Tecnología
  • Grado en Ingeniería Informatica
  • Curso: 3º
  • Asignatura: Procesadores de Lenguajes
  • Fecha: 01/03/2023
  • Autor: Raimon Mejías Hernández
  • Correo: [email protected]

listado de las tareas a realizar

  • Utilizar commander para la línea de comandos
    • Opciones en la línea de comandos (-V(--version),, -o(--output), -h(--help))
  • Añadir mensaje de logs a la entrada de las funciones
    • Reto 1: Soportar las Arrow functions
    • Reto 2: Indicar el número de línea en la que se encuentra la función
  • Realizar test con Mocha
  • Realizar un estudio de cubrimiento con nyc
  • Realizar integración continua con GitHub Actions
  • Crear Scripts para ejecutar el programa
  • Documentar el código utilizando JSDoc
  • Publicar el paquete en npmjs
  • Redactar el informe

Tareas realizadas

A continuación se detallan paso a paso todas las tareas realizadas

Utilizar commander para la línea de comandos

Utilizando la librería commander se puede realizar el paso de argumentos al programa de una manera sencilla y rápida. Indicando en Program Todos los argumentos y opciones que nuestro programa permite, realizando por ultimo una lectura de los argumentos del programa.

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

program.parse(process.argv);

Opciones de la línea de comandos

  • Fichero que contiene una función escrita en JS, del cual se creara un AST
  • -V --version: Muestra la versión actual del programa
  • -o --output : Vuelca el nuevo código JS generado a partir de la modificación del AST original.
  • -h --help : Muestra la información de ayuda del programa

Añadir mensaje de logs a la entrada de las funciones

Utilizando la plantilla del fichero logging-espree.js, se ha procedido a rellenar las funciones con el código necesario:

export async function transpile(inputFile, outputFile) {
  try {
    const code = await fs.readFile(inputFile, 'utf-8');
    const ast = addLogging(code);
    if (!outputFile) { 
      console.log(ast); 
    } else {
      await fs.writeFile(outputFile, ast);
    }
  } catch (SyntaxError) {
    console.log('espree couldn\'t create the ast while transpiling the inputfile');
    console.log(`${SyntaxError.name}: ${SyntaxError.message} at line ${SyntaxError.lineNumber}`);
  }
}

La función transpile es muy parecida a la de las prácticas anteriores, con la única diferencia de realizar la llamada a la función addLogging, la cual es otra función que se debe implementar en esta práctica.

export function addLogging(code) {
  let ast = espree.parse(code, {ecmaVersion: 12, 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);
}

La función addLogging se encarga de general el AST del código JS leído originalmente, para luego utilizar la función traverse de la librería estraverse para realizar la modificación de los nodos de tipo función, llamando así a la función addBeforeCode.

function addBeforeCode(node) {
  const name = (node.id)? node.id.name : '<anonymous function>';
  const line = node.loc.start.line;
  let parameters = '';
  for (let i = 0; i < node.params.length; i++) { 
    parameters +=  '${ ' + node.params[i].name + ' }' + ((i < node.params.length - 1)? ', ' : '');
  }
  const beforeCode = `console.log(\`Entering ${name}(${parameters}) at line ${line}\`)`;
  const beforeNodes = espree.parse(beforeCode, {ecmaVersion: 12}).body;
  node.body.body = beforeNodes.concat(node.body.body);
}

La función addBeforeCode se encarga de conseguir toda la información necesaria para generar el console.log que se va a añadir justo debajo de la declaración de la función, por ultimo modifica el AST original añadiéndole a la función nuevos nodos en el body.

Indicar los valores de los argumentos

Como se puede observar en el código de la función addBeforeCode, se realiza un recorrido por los parametros de la función, obteniendo así los nombres de los parametros

  let parameters = '';
  for (let i = 0; i < node.params.length; i++) { 
    parameters +=  '${ ' + node.params[i].name + ' }' + ((i < node.params.length - 1)? ', ' : '');
  }

Reto 1: Soportar las funciones Arrow

Para permitir que el código de logging-espree.js soporte la aparición de expresiones del estilo:

a => { return a; }
(a, b) => { 
  let c = a + b;
  return c;
}

Se ha de añadir, a las condiciones del if dentro de la función traverse, la condición node.type === 'ArrowFunctionExpression' Permitiendo así detectar los nodos de dicho tipo y realizando la modificación pertinente.

Reto 2: Indicar el número de línea en la que se encuentra la función

Para obtener el número de línea en la que se encuentra la función detectada se ha incluir en los parámetros pasados a la función espree.parse() el objeto {loc: true} Obteniendo así un AST que contiene los campos loc.start.line, consiguiendo así el número de línea de la función.

let ast = espree.parse(code, {ecmaVersion: 12, loc: true}); // Función AddLogging
const line = node.loc.start.line; // Funcion addBeforeCode

Documentar el código utilizando JSDoc

Junto con el código creado se ha realizado una documentación exhaustiva del código, explicando toda la información necesaria para entender el código creado. Se ha utilizado el formato JSDoc para la realización de los comentarios de cabecera de las funciones y del programa.

/**
 * @desc It takes a string and convert it to an AST, then proceeds to 
 * insert the new console.log in each function that find
 * @param {String} code - An string that contain a function
 * @returns Returns the new JavaScript code generated from the modified AST
 */

Ejemplo de un comentario JSDoc para la función addLogging

Tests and Covering

Como se ha relizado en anteriores prácticas se ha utilizado la metodología de Stubbing para relizar modificaciones en el método console.log permitiendo así utilizarlo para realizar las comprobaciones de los tests.

async function calculate(outputLog, correctFile) {
  const correct = await fs.readFile(correctFile, 'utf-8');
  let log = console.log;
  let result = ' ';
  console.log = function (...space) { result += space.join(''); }
  eval(outputLog);
  console.log = log;
  return [result, correct];
}

Antes de realizar el calculo primero se debe realizar el transpile, para ello se llama a:

async function getLog(inputFile, outputFile, expectedFile) {
  await transpile(inputFile, outputFile);
  const output = await fs.readFile(outputFile, 'utf-8');
  const expected = await fs.readFile(expectedFile, 'utf-8');
  return [output, expected];  
}

Por ultimo se realizan iterativamente los tests que se encuentran definidos en el fichero test-description.mjs

Realización del covering con nyc

Para la realización de esta práctica se ha pedido que en el package.json se indique el campo "type" con "module". Esto tiene un efecto negativo en la ejecución del estudio de cubrimiento del código con nyc, realizando una búsqueda en internet se encuentra que nyc no soporta la ejecución con el tipo module:

problea_nyc

Realizar integración continua con GitHub Actions

Utilizando el fichero creado en la práctica anterior se ha realizado la integración continua automatica con GitHub Actions

Crear Scripts para ejecutar el programa

A continuación se listan todos los scripts que se pueden ejecutar en el package.json

  • npm run test: Realiza la ejecución de todos los tests
  • npm run cov: Realiza la ejecución de todos los tests dando como resultado el estudio de cobertura
  • npm run clear: Borra todos los ficheros temporales .js del directorio test/js

Publicar el paquete en npmjs

Para publicar el paquete enn npmjs primero se deben realizar los siguientes pasos:

  • Crear una cuenta en la página de npm
  • Modificar el package.json para añadir toda la información necesaria para el modulo
  • Comprobar que el modulo esta correctamente exportado
  • Crear una organización en npm
  • Ejecutar npm publish --access public la primera vez

publish

Comprobar si todo ha ido bien

Tras publicarlo se debe comprobar que el paquete npmjs se ha publicado correctamente, para ello se realiza npm install @alu0101390161/espree-logging Dando como resultado:

npm_install

Por ultimo para comprobar que se han exportado las funciones correctas se prueba el ejecutable generado utilizando npx funlog

npx_funlog

References