Reglas
CWF viene con un conjunto de reglas de formato integradas que pueden combinarse para aplicar un estilo de código consistente en tus proyectos.
Reglas Principales
indentation
Propósito: Normaliza la indentación del código a espacios o tabuladores con tamaño configurable.
Opciones:
style:"space"|"tab"(por defecto:"space")size: number (por defecto:2, solo aplicable cuandostylees"space")
Cómo funciona:
- Detecta patrones de indentación existentes en el código
- Convierte toda la indentación al estilo especificado
- Mantiene los niveles de indentación relativos
- Preserva las líneas vacías
Ejemplos:
// Entrada (indentación mixta)
function hello() {
if (true) {
console.log('world');
}
}
// Salida con { style: 'space', size: 2 }
function hello() {
if (true) {
console.log('world');
}
}
// Salida con { style: 'tab' }
function hello() {
if (true) {
console.log('world');
}
}Configuración:
{
"name": "indentation",
"enabled": true,
"options": {
"style": "space",
"size": 2
}
}line-ending
Propósito: Normaliza los finales de línea a un formato consistente (LF, CRLF, o CR).
Opciones:
style:"lf"|"crlf"|"cr"(por defecto:"lf")
Cómo funciona:
- Escanea el archivo en busca de todos los caracteres de final de línea
- Reemplaza todos los finales de línea con el estilo especificado
- Maneja finales de línea mixtos en el mismo archivo
Ejemplos:
// Entrada (finales de línea mixtos)
line1\r\n
line2\n
line3\r
// Salida con { style: 'lf' } (Unix)
line1\n
line2\n
line3\n
// Salida con { style: 'crlf' } (Windows)
line1\r\n
line2\r\n
line3\r\nConfiguración:
{
"name": "line-ending",
"enabled": true,
"options": {
"style": "lf"
}
}Casos de uso:
- Proyectos multiplataforma (normalizar a LF para git)
- Proyectos específicos de Windows (usar CRLF)
- Proyectos legacy de Mac (usar CR, rara vez necesario)
trailing-whitespace
Propósito: Elimina caracteres de espacios en blanco al final de las líneas.
Opciones: Ninguna
Cómo funciona:
- Procesa cada línea independientemente
- Elimina todos los caracteres de espacio y tabulador de los finales de línea
- Preserva líneas vacías intencionalmente
- No afecta espacios en blanco dentro de las líneas
Ejemplos:
// Entrada (• representa espacios)
const name = 'John';••
const age = 30;•••••
// Salida
const name = 'John';
const age = 30;Configuración:
{
"name": "trailing-whitespace",
"enabled": true
}Beneficios:
- Diffs más limpios en control de versiones
- Reduce el tamaño del archivo
- Previene advertencias del editor
- Mejor práctica de la industria
final-newline
Propósito: Asegura que los archivos terminen con exactamente un carácter de nueva línea (o lo elimina).
Opciones:
insert: boolean (por defecto:true)
Cómo funciona:
- Verifica si el archivo termina con una nueva línea
- Agrega o elimina la nueva línea final basándose en la opción
insert - Elimina múltiples nuevas líneas finales cuando
insert: true - Asegura un final de archivo limpio
Ejemplos:
// Entrada (sin nueva línea final)
const name = 'John';[EOF]
// Salida con { insert: true }
const name = 'John';
[EOF]
// Entrada (múltiples nuevas líneas finales)
const name = 'John';
[EOF]
// Salida con { insert: true }
const name = 'John';
[EOF]Configuración:
{
"name": "final-newline",
"enabled": true,
"options": {
"insert": true
}
}Estándares:
- El estándar POSIX requiere nueva línea final
- Muchos linters y editores lo aplican
- Previene problemas con herramientas que leen archivos línea por línea
max-line-length
Propósito: Valida o envuelve líneas que exceden una longitud máxima.
Opciones:
length: number (por defecto:80)action:"warn"|"wrap"(por defecto:"warn")
Cómo funciona:
- Mide el conteo de caracteres de cada línea
- Con
action: "warn": Registra advertencias pero no modifica el contenido - Con
action: "wrap": Intenta romper líneas largas en espacios
Ejemplos:
// Entrada (línea larga)
const message = 'Este es un string muy largo que excede la longitud máxima de línea configurada en el formateador';
// Salida con { length: 80, action: 'warn' }
// ⚠️ Advertencia: La línea 1 excede 80 caracteres (95)
// (contenido sin cambios)
// Salida con { length: 80, action: 'wrap' }
const message = 'Este es un string muy largo que excede la longitud máxima
de línea configurada en el formateador';Configuración:
{
"name": "max-line-length",
"enabled": true,
"options": {
"length": 80,
"action": "warn"
}
}Notas:
- El modo
wrapes básico y puede no funcionar bien con todas las estructuras de código - Usa el modo
warnpara linting, el modowrapcon precaución - Longitudes comunes: 80 (clásico), 100 (moderno), 120 (pantalla ancha)
Orden de Aplicación de Reglas
Las reglas se aplican secuencialmente en el orden en que aparecen en tu configuración. Cada regla recibe como entrada la salida de la regla anterior.
Ejemplo de flujo de ejecución:
Contenido Original
↓
Regla de Indentación (normaliza espacios)
↓
Regla de Final de Línea (normaliza a LF)
↓
Regla de Espacios al Final (elimina)
↓
Regla de Nueva Línea Final (inserta)
↓
Regla de Longitud Máxima (valida/envuelve)
↓
Contenido Final FormateadoMejor Práctica: Ordena las reglas de más a menos invasivas:
indentation- Afecta la estructuraline-ending- Afecta los saltos de líneatrailing-whitespace- Limpiezafinal-newline- Toque finalmax-line-length- Validación al final
Creando Reglas Personalizadas
El sistema de plugins de CWF te permite crear reglas de formato personalizadas.
Interfaz de Regla
import { BaseFormattingRule } from '@codewaveinnovation/formatter';
import { FormatContext } from '@codewaveinnovation/formatter';
export class MiReglaPersonalizada extends BaseFormattingRule {
readonly name = 'mi-regla-personalizada';
readonly description = 'Descripción de lo que hace esta regla';
protected format(context: FormatContext): string {
// Acceder al contenido actual
const { content } = context;
// Acceder a la configuración de esta regla
const ruleConfig = context.config.rules.find(r => r.name === this.name);
const options = ruleConfig?.options || {};
// Transformar contenido
const transformed = content; // Tu lógica de transformación
// Retornar nuevo contenido (inmutable)
return transformed;
}
}Creando un Plugin
import { BasePlugin } from '@codewaveinnovation/formatter';
import { IFormattingRule } from '@codewaveinnovation/formatter';
import { MiReglaPersonalizada } from './MiReglaPersonalizada';
export class MiPlugin extends BasePlugin {
readonly name = 'mi-plugin';
readonly version = '1.0.0';
getRules(): IFormattingRule[] {
return [
new MiReglaPersonalizada()
];
}
}Usando Plugin Personalizado
import { createFormatter, RuleRegistry } from '@codewaveinnovation/formatter';
import { PluginManager } from '@codewaveinnovation/formatter';
import { MiPlugin } from './MiPlugin';
const registry = new RuleRegistry();
const pluginManager = new PluginManager(registry);
// Cargar plugin personalizado
pluginManager.loadPlugin(new MiPlugin());
// Crear formateador
const formatter = new CodeFormatter(registry);
// Usar con configuración
const config = {
rules: [
{ name: 'mi-regla-personalizada', enabled: true, options: {} }
]
};
const result = await formatter.format(content, config);Mejores Prácticas de Reglas
1. Mantén las Reglas Simples
Cada regla debe hacer una cosa bien. Evita combinar múltiples responsabilidades.
// ✅ Bueno - Responsabilidad única
export class TrailingWhitespaceRule extends BaseFormattingRule {
protected format(context: FormatContext): string {
return context.content
.split('\n')
.map(line => line.replace(/\s+$/, ''))
.join('\n');
}
}
// ❌ Malo - Múltiples responsabilidades
export class WhitespaceRule extends BaseFormattingRule {
protected format(context: FormatContext): string {
// Elimina espacios al final Y normaliza espacios Y corrige indentación
// ¡Demasiado en una regla!
}
}2. Haz las Reglas Inmutables
Siempre retorna nuevo contenido en lugar de modificar la entrada.
// ✅ Bueno - Inmutable
protected format(context: FormatContext): string {
return context.content.replace(/foo/g, 'bar');
}
// ❌ Malo - Muta la entrada
protected format(context: FormatContext): string {
context.content = context.content.replace(/foo/g, 'bar'); // ¡Nunca hagas esto!
return context.content;
}3. Maneja Casos Extremos
protected format(context: FormatContext): string {
const { content } = context;
// Manejar contenido vacío
if (!content || content.length === 0) {
return content;
}
// Manejar línea única
if (!content.includes('\n')) {
return this.processLine(content);
}
// Procesar múltiples líneas
return content
.split('\n')
.map(line => this.processLine(line))
.join('\n');
}4. Documenta las Opciones
/**
* Controla el estilo de comillas en el código
*
* @options
* - style: 'single' | 'double' - Tipo de comillas a usar (por defecto: 'single')
* - avoidEscape: boolean - Preferir comillas que minimicen escapes (por defecto: true)
*
* @example
* // Entrada con comillas dobles
* const name = "John";
*
* // Salida con { style: 'single' }
* const name = 'John';
*/
export class QuoteStyleRule extends BaseFormattingRule {
// Implementación
}Próximos Pasos
- Guía de Configuración - Aprende cómo configurar reglas
- Referencia de API - Uso programático
- Empezando - Guía de inicio rápido