Desarrollo de Sistemas Informáticos - Grado en Ingeniería Informática - ULL

View project on GitHub

Práctica 8 - Aplicación para gamers

En esta práctica, tendrá que implementar una aplicación que permita almacenar información de los videojuegos pertenecientes a la colección de un gamer. En concreto, el sistema permitirá añadir, modificar, eliminar, listar y leer la información asociada a diferentes videojuegos. La información de cada videojuego se almacenará como un JSON en el sistema de ficheros de la máquina donde se ejecute la aplicación. Además, solo se podrá interactuar con la aplicación desde la línea de comandos (no existirá un menú interactivo).

Todo el código desarrollado deberá estar alojado en el repositorio generado tras la aceptación de la asignación de GitHub Classroom. En ese sentido, utilice en dicho repositorio una estructura de proyecto similar a la que hemos visto en clase.

Algunas tareas previas

  1. Acepte la asignación de GitHub Classroom asociada a esta práctica.
  2. Aprenda a utilizar los paquetes yargs y chalk, aunque más abajo se ilustran ejemplos de uso.
  3. Familiarícese con el API proporcionada por Node.js para trabajar con el sistema de ficheros.

Descripción de los requisitos de la aplicación

Los requisitos que debe cumplir la aplicación son los siguientes:

  1. La aplicación deberá permitir que múltiples usuarios interactúen con ella, pero no simultáneamente.

  2. En concreto, un videojuego vendrá descrito por los siguientes elementos mínimos de información que deberán ser almacenados:

    • ID. Debe ser un identificador único del videojuego.
    • Nombre. Debe ser una cadena de caracteres.
    • Descripción. Debe ser una cadena de caracteres.
    • Plataforma. Debe ser un enumerado con valores como, por ejemplo, PC, PlayStation 5, Xbox Series X/S, Nintendo Switch o Steam Deck, entre otros.
    • Género. Debe ser un enumerado con valores como, por ejemplo, Acción, Aventura, Rol, Estrategia, Deportes o Simulación, entre otros.
    • Desarrolladora. Debe ser una cadena de caracteres como, por ejemplo, Nintendo, FromSoftware, CD Projekt Red o Rockstar Games, entre otras.
    • Año de lanzamiento. Debe ser un valor numérico positivo.
    • Multijugador. Debe ser un valor booleano, esto es, verdadero en el caso de que el videojuego disponga de modo multijugador o falso en caso contrario.
    • Horas estimadas de juego. Debe ser un valor numérico positivo que indique una estimación de la duración del videojuego.
    • Valor de mercado. Debe ser un valor numérico positivo.
  3. Cada usuario tendrá su propia lista de videojuegos, con la que podrá llevar a cabo las siguientes operaciones:

    • Añadir un videojuego a la lista. Antes de añadir un videojuego a la lista se debe comprobar si ya existe un videojuego con el mismo ID. En caso de que así fuera, deberá mostrarse un mensaje de error por la consola. En caso contrario, se añadirá el nuevo videojuego a la lista y se mostrará un mensaje informativo por la consola.

    • Modificar un videojuego de la lista. Antes de modificar un videojuego, previamente se debe comprobar si ya existe un videojuego con el ID del videojuego a modificar en la lista. Si existe, se procede a su modificación y se emite un mensaje informativo por la consola. En caso contrario, debe mostrarse un mensaje de error por la consola.

    • Eliminar un videojuego de la lista. Antes de eliminar un videojuego, previamente se debe comprobar si existe un videojuego con el ID del videojuego a eliminar en la lista. Si existe, se procede a su eliminación y se emite un mensaje informativo por la consola. En caso contrario, debe mostrarse un mensaje de error por la consola.

    • Listar los videojuegos existentes en una lista. En este caso, deberá mostrarse la información asociada a cada videojuego existente en la lista por la consola. Además, deberá utilizar el paquete chalk para ello. Primero, deberá establecer rangos de valor de mercado. Luego, el valor de mercado de cada videojuego deberá mostrarse con colores diferentes. Por ejemplo, para aquellos videojuegos con un valor de mercado elevado, dicho valor deberá mostrarse en color verde, mientras que para los de menor valor de mercado, dicho valor se mostrará con color rojo. Establezca, al menos, cuatro rangos de valor de mercado diferentes.

    • Mostrar la información de un videojuego concreto existente en la lista. Antes de mostrar la información del videojuego, se debe comprobar que en la lista existe un videojuego cuyo ID sea el del videojuego a mostrar. Si existe, se mostrará toda su información, incluyendo el color de su valor de mercado. Para ello, use el paquete chalk. En caso contrario, se mostrará un mensaje de error por la consola.

  4. Todos los mensajes informativos se mostrarán con color verde, mientras que los mensajes de error se mostrarán con color rojo. Use el paquete chalk para ello.

  5. Hacer persistente la lista de videojuegos de cada usuario. Aquí es donde entra en juego el uso de la API de Node.js para trabajar con el sistema de ficheros:

    • Guardar cada videojuego de la lista en un fichero independiente con formato JSON. Los ficheros JSON correspondientes a los videojuegos de un usuario concreto deberán almacenarse en un directorio con el nombre de dicho usuario.

    • Cargar los videojuegos desde los diferentes ficheros con formato JSON almacenados en el directorio del usuario correspondiente.

  6. Un usuario solo puede interactuar con la aplicación a través de la línea de comandos. Los diferentes comandos, opciones de los mismos, así como manejadores asociados a cada uno de ellos deben gestionarse mediante el uso del paquete yargs.

El paquete chalk

Al instalar este paquete como una dependencia de su proyecto ya se incluyen los tipos para poder utilizarlo con TypeScript.

npm i chalk

La última versión se trata de un módulo ES (ESM), por lo que tendrá que modificar su fichero package.json para establecer la propiedad type al valor module:

{
  "name": "videogames-app",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "type": "module",
...
}

Además, deberá modificar su fichero de configuración del compilador de TypeScript (tsconfig.json) para modificar la propiedad module, asígnándole el valor node16. De este modo, sus propios módulos también serán considerados como módulos ES.

El uso de este paquete es bastante sencillo. Un ejemplo básico sería el siguiente:

import chalk from "chalk";

const log = console.log;

// Combine styled and normal strings
log(chalk.blue("Hello") + " World" + chalk.red("!"));

// Compose multiple styles using the chainable API
log(chalk.blue.bgRed.bold("Hello world!"));

// Pass in multiple arguments
log(chalk.blue("Hello", "World!", "Foo", "bar", "biz", "baz"));

// Nest styles
log(chalk.red("Hello", chalk.underline.bgBlue("world") + "!"));

// Nest styles of the same type even (color, underline, background)
log(
  chalk.green(
    "I am a green line " +
      chalk.blue.underline.bold("with a blue substring") +
      " that becomes green again!"
  )
);

El paquete yargs

Además de instalar el paquete yargs en su última versión, también necesitaremos instalar la última versión del paquete @types/yargs para poder utilizarlo con TypeScript:

npm i yargs
npm i --save-dev @types/yargs

Yargs permite parsear diferentes argumentos pasados a un programa desde la línea de comandos. En concreto permite gestionar diferentes comandos, cada uno de ellos, con sus opciones y manejador correspondientes. El siguiente ejemplo muestra la configuración de un comando sencillo:

import yargs from 'yargs';
import { hideBin } from 'yargs/helpers';

yargs(hideBin(process.argv))
  .command('add', 'Adds a videogame', {
  id: {
   description: 'Videogame ID',
   type: 'number',
   demandOption: true
  }
 }, (argv) => {
  console.log(argv.id);
 })
 .help()
 .argv;

Tal y como puede observarse, hemos configurado un comando add con una opción --id que es obligatoria cuando se usa el comando add y que, además, es de tipo number. También se ha definido un manejador de dicho comando que recibe como argumento un objeto argv que contiene los pares opción-valor del comando. El manejador incluye el código fuente a ejecutar asociado a un comando y sus opciones correspondientes. En nuestro ejemplo, el comando add define una opción --id a cuyo valor puede accederse mediante argv.id desde el manejador. Puede añadir más opciones a un comando concreto añadiendo más pares opción-valor al objeto de opciones (tercer argumento del método command).

Cada comando con el que pretenda interactuar con la aplicación desde la línea de comandos debe configurarse haciendo algo similar a lo anterior (se pueden encadenar múltiples invocaciones al método command).

API de Node.js para trabajar con el sistema de ficheros

Tendremos que instalar el paquete @types/node como dependencia de desarrollo para poder hacer uso de cualquiera de los módulos proporcionados por el API de Node.js. En concreto, para esta aplicación se utilizará el API del sistema de ficheros.

import fs from 'fs';

Recuerde que es importante consultar la documentación de Node.js cuya versión coincida con la versión instalada en la máquina donde vayamos a desarrollar la aplicación. En cualquier caso, se recomienda tener instalada la última versión.

Ejemplos de uso de la aplicación

$node dist/videogames-app.js add --user "edusegre" --id 1 --name "The Legend of Zelda: Breath of the Wild" --desc "An open-world adventure game" --platform "Nintendo Switch" --genre "Adventure" --developer "Nintendo" --year 2017 --multiplayer false --hours 50 --value 45
New videogame added to edusegre collection!

$node dist/videogames-app.js add --user "edusegre" --id 1 --name "The Legend of Zelda: Breath of the Wild" --desc "An open-world adventure game" --platform "Nintendo Switch" --genre "Adventure" --developer "Nintendo" --year 2017 --multiplayer false --hours 50 --value 45
Videogame already exists at edusegre collection!

$node dist/videogames-app.js list --user "edusegre"
edusegre videogame collection
--------------------------------
ID: 1
Name: The Legend of Zelda: Breath of the Wild
Description: An open-world adventure game
Platform: Nintendo Switch
Genre: Adventure
Developer: Nintendo
Year: 2017
Multiplayer: false
Estimated hours: 50
Market value: 45
--------------------------------
ID: 2
...

$node dist/videogames-app.js update --user "edusegre" --id 1 --name "The Legend of Zelda: Breath of the Wild" --desc "An acclaimed open-world adventure game" --platform "Nintendo Switch" --genre "Adventure" --developer "Nintendo" --year 2017 --multiplayer false --hours 60 --value 50
Videogame updated at edusegre collection!

$node dist/videogames-app.js update --user "edusegre" --id 3 --name "The Legend of Zelda: Breath of the Wild" --desc "An acclaimed open-world adventure game" --platform "Nintendo Switch" --genre "Adventure" --developer "Nintendo" --year 2017 --multiplayer false --hours 60 --value 50
Videogame not found at edusegre collection!

$node dist/videogames-app.js read --user "edusegre" --id 1
ID: 1
Name: The Legend of Zelda: Breath of the Wild
Description: An acclaimed open-world adventure game
Platform: Nintendo Switch
Genre: Adventure
Developer: Nintendo
Year: 2017
Multiplayer: false
Estimated hours: 60
Market value: 50

$node dist/videogames-app.js read --user "edusegre" --id 3
Videogame not found at edusegre collection!

$node dist/videogames-app.js remove --user "edusegre" --id 1
Videogame removed from edusegre collection!

$node dist/videogames-app.js remove --user "edusegre" --id 3
Videogame not found at edusegre collection!

Incluya documentación mediante el uso de TSDoc. Escriba pruebas unitarias con Vitest. Incluya flujos de trabajo de GitHub para llevar a cabo las pruebas en diferentes entornos con diferentes versiones de Node.js, enviar los datos de cubrimiento a Coveralls, así como realizar un análisis de la calidad y seguridad de su código fuente a través de GitHub Code Quality.