You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
svelte-kit-vice/scripts/normalize-context-pattern.ts

180 lines
4.9 KiB

/**
* Normaliza todos los componentes al patrño .ctx
* Convierte: const XxxContext = createTerraContext(...)
* A: class XxxState { static readonly ctx = createTerraContext(...) }
*/
import { readFileSync, writeFileSync, readdirSync, existsSync } from 'node:fs';
import { resolve, dirname, join } from 'node:path';
import { fileURLToPath } from 'node:url';
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
const terraDir = resolve(__dirname, '../src/uix/terra');
interface ContextDef {
name: string;
className: string;
fullMatch: string;
lineNumber: number;
}
function findContextDefinitions(content: string): ContextDef[] {
const contexts: ContextDef[] = [];
const lines = content.split('\n');
// Patrón para: const XxxContext = createTerraContext<XxxState>("...")
const regex =
/const\s+(\w+Context)\s*=\s*createTerraContext\s*<\s*(\w+)\s*\>\s*\(\s*["']([^"']+)["']\s*\)/g;
let match;
while ((match = regex.exec(content)) !== null) {
const contextName = match[1];
const className = match[2];
const fullMatch = match[0];
// Encontrar número de línea
const beforeMatch = content.substring(0, match.index);
const lineNumber = beforeMatch.split('\n').length;
contexts.push({
name: contextName,
className,
fullMatch,
lineNumber
});
}
return contexts;
}
function findClassDeclaration(
content: string,
className: string
): { start: number; end: number } | null {
const classRegex = new RegExp(`export\\s+class\\s+${className}\\s*\\{`, 'g');
const match = classRegex.exec(content);
if (!match) return null;
const start = match.index;
const openBraces = [start];
let end = start + 1;
let depth = 1;
// Encontrar el cierre de la clase
while (end < content.length && depth > 0) {
if (content[end] === '{') depth++;
else if (content[end] === '}') depth--;
end++;
}
return { start, end };
}
function convertToCtxPattern(content: string, contexts: ContextDef[]): string {
let modified = content;
// Ordenar por número de línea descendente (para modificar de atrás hacia adelante)
contexts.sort((a, b) => b.lineNumber - a.lineNumber);
for (const ctx of contexts) {
console.log(` Procesando: ${ctx.name} -> ${ctx.className}.ctx`);
// 1. Eliminar la definición del contexto externo
modified = modified.replace(ctx.fullMatch, '');
// 2. Encontrar la clase y agregar static readonly ctx
const classInfo = findClassDeclaration(modified, ctx.className);
if (!classInfo) {
console.log(` ⚠️ No se encontró la clase ${ctx.className}`);
continue;
}
// Buscar el primer { de la clase
const classStart = modified.indexOf('{', classInfo.start);
if (classStart === -1 || classStart > classInfo.end) continue;
// Insertar static readonly ctx después de la llave de apertura
const indent = ' '; // Usar tabs como el resto del archivo
const ctxProperty = `${indent}static readonly ctx = createTerraContext<${ctx.className}>('${ctx.className}');\n`;
modified =
modified.slice(0, classStart + 1) + '\n' + ctxProperty + modified.slice(classStart + 1);
// 3. Reemplazar XxxContext.get() por XxxState.ctx.get()
modified = modified.replace(
new RegExp(`\\b${ctx.name}\\.get\\(\\)`, 'g'),
`${ctx.className}.ctx.get()`
);
// 4. Reemplazar XxxContext.set() por XxxState.ctx.set()
modified = modified.replace(
new RegExp(`\\b${ctx.name}\\.set\\(`, 'g'),
`${ctx.className}.ctx.set(`
);
// 5. Reemplazar XxxContext.getOr() por XxxState.ctx.getOr()
modified = modified.replace(
new RegExp(`\\b${ctx.name}\\.getOr\\(`, 'g'),
`${ctx.className}.ctx.getOr(`
);
}
return modified;
}
function processFile(filePath: string): boolean {
const content = readFileSync(filePath, 'utf-8');
const original = content;
const contexts = findContextDefinitions(content);
if (contexts.length === 0) return false;
console.log(`📄 ${filePath}`);
const modified = convertToCtxPattern(content, contexts);
if (modified !== original) {
writeFileSync(filePath, modified, 'utf-8');
console.log(` ✅ ${contexts.length} contexto(s) convertido(s)\n`);
return true;
}
return false;
}
// Buscar todos los archivos .svelte.ts en terra/
function findAllTsFiles(dir: string): string[] {
const files: string[] = [];
const entries = readdirSync(dir, { withFileTypes: true });
for (const entry of entries) {
const fullPath = join(dir, entry.name);
if (entry.isDirectory() && !entry.name.startsWith('.')) {
files.push(...findAllTsFiles(fullPath));
} else if (entry.isFile() && entry.name.endsWith('.svelte.ts')) {
files.push(fullPath);
}
}
return files;
}
const files = findAllTsFiles(terraDir);
let modified = 0;
let skipped = 0;
console.log('🔧 Normalizando al patrón .ctx...\n');
for (const file of files) {
if (processFile(file)) {
modified++;
} else {
skipped++;
}
}
console.log(`\n📊 Resumen:`);
console.log(` Modificados: ${modified}`);
console.log(` Skippeados: ${skipped}`);
console.log(` Total: ${modified + skipped}`);

Powered by TurnKey Linux.