Lo primero en mi caso, fue plasmar en Notion las cosas que quería que tuviera mi software. Creo que es importante tener más o menos definido lo que quieres hacer antes de comenzar con el código, entre más puedas adelantar de lógica antes de comenzar a teclear mejor, aunque no siempre es posible eso.
En mi caso la lógica es muy sencilla:
Tomando un directorio base, entrar recursivamente a través de sus subcarpetas y archivos, revisando cada archivo para verificar si cumple con los criterios de organización.
Bastante simple, tenemos 2 factores básicos:
- Tendrá recursividad
- Y la lógica de organización
Ya con esto definido comienzo a darle forma a las estructuras.
Para este proyecto estoy utilizando Typescript, entonces, lo primero que quiero es darle un poco de forma a las opciones de organización:
- Contiene en el nombre
- Tiene extensión tal
- El nombre termina con
- El nombre comienza con
- Tiene alguna extensión de este grupo
Conditions
Esto lo haré utilizando los String Literal Types
de Typescript
// Conditions.ts
export type Conditions =
'File Name Contains'
| 'Extension'
| 'File Name Ends With'
| 'File Name Starts With'
Pattern
Después, solo para darle un poco de semántica a mis tipos, renombro el tipo string
como Pattern
.
Esto solo para poder identificar mejor qué es lo que representa ese string
y por si después tengo que agregar Branded Types
.
Un Pattern
va a ser una cadena que, en conjunto con las Conditions
, indicará qué condición debe cumplirse, por ejemplo, que el nombre de archivo contenga “Tarea”
// Pattern.ts
export type Pattern = string[]
PathString
Tomando en cuenta que una de las cosas que quiero hacer es mover archivos a otros directorios, creo que es buena ideas asegurarme que estos directorios existan, yo voy a asegurarme de que los directorios existan utilizando un BrandedType
en conjunto con una librería que he estado utilizando llamada NeverThrow para evitar lanzar excepciones y que el control de errores se sepa y maneje desde el tipado, es una librería bastante interesante.
import { Result, ok, err } from "neverthrow";
// Función de utilidad para verificar si un directorio existe
import { directoryExists } from "../Utils/Directory.ts";
// Creamos la Brand
type PathBrand = { readonly path: unique symbol }
// Definimos los posibles errores que pueden ocurrir
export type PathErrors = 'Directory Not Found'
// Creamos el Branded Type
export type PathString = string & PathBrand
// Función para crear el Branded Type, así aseguramos que el string tenga las características que deseamos
// en mi caso, que sea un directorio que exista y aparte, devolvemos un result, por si ocurriese algún error
export const createPathString = async (str: string): Promise<Result<PathString,PathErrors>> => {
const directoryExists_ = await directoryExists(str)
if(!directoryExists_) return err('Directory Not Found')
return ok(str as PathString)
}
Rule
Y nuestra última estructura básica, una Regla (Rule), que será la representación de lo que quiero hacer con archivo, por ejemplo,moverlo a otro directorio o borrarlo y también toda la información que se requiera para hacerlo, como la nueva ruta. Para mí luce así:
type MoveRule = {
action: 'Move To',
destination: PathString // Mover un archivo requiere saber a dónde, por eso incluyo esta propiedad
}
type DeleteRule = {
action: 'Delete' // Borrar un archivo no requiere ningún otro dato
}
Conclusiones
Este ha sido mi avance durante la semana, no he tenido tanto tiempo como quiera, pero va tomando forma, por ahora ya tengo definido el cómo se van a estructurar las acciones del programa, el siguiente paso es comenzar a darle un poco de comportamiento y test.
Este es una serie de artículos para documentar mi proceso de creación de software te dejo los links a la entrada anterior y a la siguiente: