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.
180 lines
4.9 KiB
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}`);
|