@icarusmx/creta 1.3.4 → 1.3.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. package/bin/creta.js +8 -1576
  2. package/codex-refactor.txt +13 -0
  3. package/lib/builders/LessonBuilder.js +228 -0
  4. package/lib/builders/MenuBuilder.js +154 -0
  5. package/lib/builders/ProjectBuilder.js +56 -0
  6. package/lib/cli/index.js +81 -0
  7. package/lib/commands/help.js +5 -0
  8. package/lib/constants/paths.js +9 -0
  9. package/lib/data/enunciados.js +44 -0
  10. package/lib/data/lessons/index.js +25 -0
  11. package/lib/data/lessons/lesson1-system-decomposition.js +312 -0
  12. package/lib/data/lessons/lesson2-object-requests.js +318 -0
  13. package/lib/data/lessons/lesson3-only-way.js +349 -0
  14. package/lib/data/lessons/lesson4-operation-signatures.js +332 -0
  15. package/lib/data/lessons/lesson5-interface-set.js +341 -0
  16. package/lib/data/lessons/lesson6-interface-design.js +407 -0
  17. package/lib/data/lessons/lesson7-object-definition.js +375 -0
  18. package/lib/data/lessons/sintaxis/terminal-basico.js +46 -0
  19. package/lib/data/menus.js +43 -0
  20. package/lib/data/messages.js +28 -0
  21. package/lib/executors/enunciados-executor.js +63 -0
  22. package/lib/executors/portfolio-executor.js +167 -0
  23. package/lib/executors/proyectos-executor.js +23 -0
  24. package/lib/executors/sintaxis-executor.js +7 -0
  25. package/lib/templates/LevelModifier.js +287 -0
  26. package/lib/utils/file-utils.js +18 -0
  27. package/lib/utils/input.js +15 -0
  28. package/lib/utils/output.js +4 -0
  29. package/package.json +4 -1
  30. package/refactor.txt +581 -0
  31. package/test/enunciados.test.js +72 -0
  32. package/lessons/lesson1-system-decomposition.js +0 -313
  33. package/lessons/lesson2-object-requests.js +0 -309
  34. package/lessons/lesson3-only-way.js +0 -324
  35. package/lessons/lesson4-operation-signatures.js +0 -319
  36. package/lessons/lesson5-interface-set.js +0 -326
  37. package/lessons/lesson6-interface-design.js +0 -391
  38. package/lessons/lesson7-object-definition.js +0 -300
@@ -0,0 +1,407 @@
1
+ export const LESSON_6_INTERFACE_DESIGN = {
2
+ id: 6,
3
+ title: 'LECCIÓN 6: El énfasis al diseñar los objetos debe estar en la definición de sus solicitudes e interfaces',
4
+ subtitle: 'Enfoque práctico: Sistema bancario con diseño interface-first y encapsulación',
5
+ flow: [
6
+ {
7
+ lines: [
8
+ '\n💡 ¿Por qué es importante?',
9
+ '- Las interfaces definen QUÉ hace un objeto, no CÓMO lo hace',
10
+ '- Facilita la colaboración entre objetos',
11
+ '- Permite cambiar implementaciones sin afectar otros objetos',
12
+ '- Hace el código más mantenible y extensible'
13
+ ],
14
+ type: 'text'
15
+ },
16
+ {
17
+ message: '\nPresiona Enter para comenzar el ejercicio práctico...',
18
+ type: 'pause'
19
+ },
20
+ {
21
+ type: 'clear'
22
+ },
23
+ {
24
+ lines: [
25
+ '🛠️ EJERCICIO PRÁCTICO: Sistema Bancario',
26
+ '==================================================',
27
+ '🎯 Objetivo: Diseñar interfaces ANTES de implementar',
28
+ '\nVamos a crear un sistema bancario donde:',
29
+ '- BankAccount representa una cuenta con balance privado',
30
+ '- Transaction registra movimientos entre cuentas',
31
+ '- Bank gestiona múltiples cuentas y validaciones'
32
+ ],
33
+ type: 'text'
34
+ },
35
+ {
36
+ message: '\nPresiona Enter para ver cómo diseñar las interfaces...',
37
+ type: 'pause'
38
+ },
39
+ {
40
+ type: 'clear'
41
+ },
42
+ {
43
+ lines: [
44
+ '📋 PASO 1: Definir las Solicitudes',
45
+ '========================================',
46
+ 'Antes de escribir código, pensemos: ¿Qué solicitudes debe manejar cada objeto?',
47
+ '\n🏦 BankAccount debe poder:',
48
+ ' - Consultar balance (sin exponer el dato interno)',
49
+ ' - Recibir dinero (depósito)',
50
+ ' - Enviar dinero (con validación interna)',
51
+ ' - Proporcionar información de la cuenta',
52
+ '\n📊 Transaction debe poder:',
53
+ ' - Registrar origen, destino y monto',
54
+ ' - Proporcionar detalles del movimiento',
55
+ ' - Validar si la transacción es válida',
56
+ '\n🏛️ Bank debe poder:',
57
+ ' - Crear nuevas cuentas',
58
+ ' - Procesar transferencias entre cuentas',
59
+ ' - Validar operaciones antes de ejecutarlas',
60
+ ' - Llevar registro de todas las transacciones'
61
+ ],
62
+ type: 'text'
63
+ },
64
+ {
65
+ message: '\n' +
66
+ '✅ ¡Excelente! Ya definimos QUÉ debe hacer cada objeto. Presiona Enter para definir las interfaces...',
67
+ type: 'pause'
68
+ },
69
+ {
70
+ type: 'clear'
71
+ },
72
+ {
73
+ lines: [
74
+ '🔌 PASO 2: Definir las Interfaces (Firmas de Operación)',
75
+ '==================================================',
76
+ 'Ahora especifiquemos CÓMO se solicitan estas operaciones:',
77
+ '\n// BankAccount Interface',
78
+ 'class BankAccount {',
79
+ ' constructor(accountNumber, ownerName, initialBalance) → BankAccount',
80
+ ' getBalance() → number // ⚠️ ENCAPSULACIÓN: acceso controlado',
81
+ ' getAccountInfo() → {number, owner, balance}',
82
+ ' deposit(amount) → boolean',
83
+ ' send(amount, targetAccount) → boolean // ⚠️ VALIDACIÓN interna',
84
+ '}',
85
+ '\n// Transaction Interface',
86
+ 'class Transaction {',
87
+ ' constructor(from, to, amount, timestamp) → Transaction',
88
+ ' getDetails() → {from, to, amount, timestamp, status}',
89
+ ' isValid() → boolean',
90
+ '}',
91
+ '\n// Bank Interface',
92
+ 'class Bank {',
93
+ ' createAccount(ownerName, initialBalance) → BankAccount',
94
+ ' transfer(fromAccount, toAccount, amount) → Transaction',
95
+ ' getAllTransactions() → Array<Transaction>',
96
+ ' validateOperation(account, amount) → boolean',
97
+ '}',
98
+ '\n💡 Observa que cada operación especifica:',
99
+ ' a) Nombre de la operación (getBalance, send, transfer, etc.)',
100
+ ' b) Insumos necesarios (amount, targetAccount, etc.)',
101
+ ' c) Valor que regresa (boolean, Transaction, etc.)',
102
+ '\n' +
103
+ '🔒 Nota especial: getBalance() encapsula el acceso al estado interno',
104
+ '🛡️ Nota especial: send() incluirá validación antes de ejecutar'
105
+ ],
106
+ type: 'text'
107
+ },
108
+ {
109
+ message: '\n✅ Interfaces definidas. Presiona Enter para implementar...',
110
+ type: 'pause'
111
+ },
112
+ {
113
+ type: 'clear'
114
+ },
115
+ {
116
+ lines: [
117
+ '⚙️ PASO 3: Implementar los Objetos',
118
+ '========================================',
119
+ 'Ahora que tenemos las interfaces claras, implementemos:',
120
+ '\n// Implementación de BankAccount',
121
+ 'class BankAccount {\n' +
122
+ ' constructor(accountNumber, ownerName, initialBalance) {\n' +
123
+ ' this.accountNumber = accountNumber\n' +
124
+ ' this.ownerName = ownerName\n' +
125
+ ' this.#balance = initialBalance // 🔒 PRIVADO: no se accede directamente\n' +
126
+ ' }\n' +
127
+ '\n' +
128
+ ' // 🔑 ENCAPSULACIÓN: método GET para acceder al balance\n' +
129
+ ' getBalance() {\n' +
130
+ ' return this.#balance\n' +
131
+ ' }\n' +
132
+ '\n' +
133
+ ' getAccountInfo() {\n' +
134
+ ' return {\n' +
135
+ ' number: this.accountNumber,\n' +
136
+ ' owner: this.ownerName,\n' +
137
+ ' balance: this.#balance // Controlamos qué se expone\n' +
138
+ ' }\n' +
139
+ ' }\n' +
140
+ '\n' +
141
+ ' deposit(amount) {\n' +
142
+ ' if (amount > 0) {\n' +
143
+ ' this.#balance += amount\n' +
144
+ ' return true\n' +
145
+ ' }\n' +
146
+ ' return false\n' +
147
+ ' }\n' +
148
+ '\n' +
149
+ ' // 🛡️ VALIDACIÓN: método SEND con lógica interna\n' +
150
+ ' send(amount, targetAccount) {\n' +
151
+ ' // Validación interna ANTES de ejecutar\n' +
152
+ ' if (amount > 0 && this.#balance >= amount) {\n' +
153
+ ' this.#balance -= amount\n' +
154
+ ' targetAccount.deposit(amount)\n' +
155
+ ' return true\n' +
156
+ ' }\n' +
157
+ ' return false // Fondos insuficientes o monto inválido\n' +
158
+ ' }\n' +
159
+ '}'
160
+ ],
161
+ type: 'text'
162
+ },
163
+ {
164
+ message: '\nPresiona Enter para ver Transaction...',
165
+ type: 'pause'
166
+ },
167
+ {
168
+ lines: [
169
+ '\n// Implementación de Transaction',
170
+ 'class Transaction {\n' +
171
+ ' constructor(fromAccount, toAccount, amount) {\n' +
172
+ ' this.fromAccount = fromAccount\n' +
173
+ ' this.toAccount = toAccount\n' +
174
+ ' this.amount = amount\n' +
175
+ ' this.timestamp = new Date()\n' +
176
+ " this.status = 'pending'\n" +
177
+ ' }\n' +
178
+ '\n' +
179
+ ' getDetails() {\n' +
180
+ ' return {\n' +
181
+ ' from: this.fromAccount.accountNumber,\n' +
182
+ ' to: this.toAccount.accountNumber,\n' +
183
+ ' amount: this.amount,\n' +
184
+ ' timestamp: this.timestamp,\n' +
185
+ ' status: this.status\n' +
186
+ ' }\n' +
187
+ ' }\n' +
188
+ '\n' +
189
+ ' isValid() {\n' +
190
+ ' return this.amount > 0 &&\n' +
191
+ ' this.fromAccount.getBalance() >= this.amount\n' +
192
+ ' }\n' +
193
+ '\n' +
194
+ ' execute() {\n' +
195
+ ' if (this.isValid()) {\n' +
196
+ ' const success = this.fromAccount.send(this.amount, this.toAccount)\n' +
197
+ " this.status = success ? 'completed' : 'failed'\n" +
198
+ ' return success\n' +
199
+ ' }\n' +
200
+ " this.status = 'failed'\n" +
201
+ ' return false\n' +
202
+ ' }\n' +
203
+ '}'
204
+ ],
205
+ type: 'text'
206
+ },
207
+ {
208
+ message: '\nPresiona Enter para ver Bank...',
209
+ type: 'pause'
210
+ },
211
+ {
212
+ lines: [
213
+ '\n// Implementación de Bank',
214
+ 'class Bank {\n' +
215
+ ' constructor() {\n' +
216
+ ' this.accounts = []\n' +
217
+ ' this.transactions = []\n' +
218
+ ' this.nextAccountNumber = 1000\n' +
219
+ ' }\n' +
220
+ '\n' +
221
+ ' createAccount(ownerName, initialBalance) {\n' +
222
+ ' const account = new BankAccount(\n' +
223
+ ' this.nextAccountNumber++,\n' +
224
+ ' ownerName,\n' +
225
+ ' initialBalance\n' +
226
+ ' )\n' +
227
+ ' this.accounts.push(account)\n' +
228
+ ' return account\n' +
229
+ ' }\n' +
230
+ '\n' +
231
+ ' transfer(fromAccount, toAccount, amount) {\n' +
232
+ ' const transaction = new Transaction(fromAccount, toAccount, amount)\n' +
233
+ '\n' +
234
+ ' // El Bank valida ANTES de ejecutar\n' +
235
+ ' if (this.validateOperation(fromAccount, amount)) {\n' +
236
+ ' const success = transaction.execute()\n' +
237
+ ' this.transactions.push(transaction)\n' +
238
+ ' return transaction\n' +
239
+ ' }\n' +
240
+ '\n' +
241
+ " transaction.status = 'failed'\n" +
242
+ ' this.transactions.push(transaction)\n' +
243
+ ' return transaction\n' +
244
+ ' }\n' +
245
+ '\n' +
246
+ ' validateOperation(account, amount) {\n' +
247
+ ' return amount > 0 && account.getBalance() >= amount\n' +
248
+ ' }\n' +
249
+ '\n' +
250
+ ' getAllTransactions() {\n' +
251
+ ' return [...this.transactions]\n' +
252
+ ' }\n' +
253
+ '}'
254
+ ],
255
+ type: 'text'
256
+ },
257
+ {
258
+ message: '\n' +
259
+ '✅ Implementación completa. Presiona Enter para probar la interacción...',
260
+ type: 'pause'
261
+ },
262
+ {
263
+ type: 'clear'
264
+ },
265
+ {
266
+ lines: [
267
+ '🧪 PASO 4: Probar la Interacción entre Objetos',
268
+ '=============================================',
269
+ 'Veamos cómo los objetos colaboran usando sus interfaces:',
270
+ '\n// Crear el sistema bancario',
271
+ 'const bank = new Bank()',
272
+ "const cuenta1 = bank.createAccount('Ana García', 1000)",
273
+ "const cuenta2 = bank.createAccount('Carlos López', 500)",
274
+ '',
275
+ '// 🔑 ENCAPSULACIÓN: Solo podemos acceder al balance via getBalance()',
276
+ "console.log('Balance Ana:', cuenta1.getBalance()) // 1000",
277
+ "console.log('Balance Carlos:', cuenta2.getBalance()) // 500",
278
+ '',
279
+ '// 🛡️ VALIDACIÓN: send() verifica internamente antes de ejecutar',
280
+ 'const exitoso = cuenta1.send(300, cuenta2) // ✅ Tiene fondos',
281
+ "console.log('Transferencia exitosa:', exitoso) // true",
282
+ '',
283
+ 'const fallido = cuenta1.send(1500, cuenta2) // ❌ Fondos insuficientes',
284
+ "console.log('Transferencia fallida:', fallido) // false",
285
+ '',
286
+ '// El estado interno se mantiene íntegro',
287
+ "console.log('Balance final Ana:', cuenta1.getBalance()) // 700",
288
+ "console.log('Balance final Carlos:', cuenta2.getBalance()) // 800",
289
+ '\n🎯 Resultado esperado:',
290
+ 'Balance Ana: 1000',
291
+ 'Balance Carlos: 500',
292
+ 'Transferencia exitosa: true',
293
+ 'Transferencia fallida: false',
294
+ 'Balance final Ana: 700',
295
+ 'Balance final Carlos: 800'
296
+ ],
297
+ type: 'text'
298
+ },
299
+ {
300
+ message: '\nPresiona Enter para ver los beneficios de este enfoque...',
301
+ type: 'pause'
302
+ },
303
+ {
304
+ type: 'clear'
305
+ },
306
+ {
307
+ lines: [
308
+ '🌟 BENEFICIOS DEL DISEÑO INTERFACE-FIRST EN SISTEMAS BANCARIOS',
309
+ '============================================================',
310
+ '1. 🔒 Encapsulación: El balance está protegido, solo accesible via getBalance()',
311
+ '2. 🛡️ Validación: send() incluye lógica de negocio interna',
312
+ '3. 🎯 Claridad: Cada objeto tiene responsabilidades financieras bien definidas',
313
+ '4. 🔗 Colaboración: Los objetos saben exactamente cómo solicitar operaciones',
314
+ '5. 🧪 Testeable: Podemos simular cuentas y transacciones fácilmente',
315
+ '6. 📚 Mantenible: Las interfaces documentan el contrato bancario',
316
+ '\n💡 Ejemplo de extensibilidad:',
317
+ '// Podemos crear diferentes tipos de cuenta sin cambiar Bank',
318
+ 'class SavingsAccount extends BankAccount {',
319
+ ' getBalance() {',
320
+ ' return super.getBalance() + this.calculateInterest()',
321
+ ' }',
322
+ '}',
323
+ '',
324
+ 'class CreditAccount extends BankAccount {',
325
+ ' send(amount, target) {',
326
+ ' // Permite sobregiro hasta el límite de crédito',
327
+ ' if (amount > 0 && (this.getBalance() + this.creditLimit) >= amount) {',
328
+ ' // ... lógica específica',
329
+ ' }',
330
+ ' }',
331
+ '}',
332
+ '',
333
+ '// Las cuentas pueden enviarse dinero directamente!',
334
+ "const savingsAcc = new SavingsAccount(123, 'María', 1000)",
335
+ "const creditAcc = new CreditAccount(456, 'Juan', 500, 2000) // límite crédito",
336
+ 'savingsAcc.send(300, creditAcc) // ¡Funciona con cualquier tipo de cuenta!',
337
+ '',
338
+ '// O podemos usar el Bank para registro completo:',
339
+ 'bank.transfer(savingsAcc, creditAcc, 300) // Crea Transaction automáticamente'
340
+ ],
341
+ type: 'text'
342
+ },
343
+ {
344
+ message: '\nPresiona Enter para continuar con la conclusión...',
345
+ type: 'pause'
346
+ },
347
+ {
348
+ type: 'clear'
349
+ },
350
+ {
351
+ lines: [
352
+ '🎓 CONCLUSIÓN: Diseño basado en Interfaces (Sistema Bancario)',
353
+ '=======================================================',
354
+ '🎯 Hemos demostrado que:',
355
+ '\n' +
356
+ '1. El ÉNFASIS debe estar en definir QUÉ solicitudes maneja cada objeto',
357
+ '2. Las INTERFACES son el CONJUNTO de todas las firmas de operación',
358
+ '3. Cada FIRMA especifica: nombre, insumos y valor de retorno',
359
+ '4. La IMPLEMENTACIÓN viene después, siguiendo el contrato',
360
+ '5. Los objetos COLABORAN a través de estas interfaces bien definidas',
361
+ '\n📋 Firmas de operación en nuestro ejemplo:',
362
+ '• BankAccount.getBalance() → number',
363
+ '• BankAccount.send(amount, targetAccount) → boolean',
364
+ '• Bank.createAccount(ownerName, initialBalance) → BankAccount',
365
+ '• Bank.transfer(fromAccount, toAccount, amount) → Transaction',
366
+ '• Transaction.getDetails() → {from, to, amount, timestamp, status}',
367
+ '\n🔑 La interfaz de BankAccount es el CONJUNTO completo:',
368
+ ' {getBalance, getAccountInfo, deposit, send}',
369
+ '🔑 La interfaz de Bank es el CONJUNTO completo:',
370
+ ' {createAccount, transfer, getAllTransactions, validateOperation}',
371
+ '\n💡 Beneficios de este enfoque:',
372
+ '• ENCAPSULACIÓN: getBalance() protege el acceso al estado interno',
373
+ '• VALIDACIÓN: send() ejecuta lógica de negocio antes de operar',
374
+ '• CONTRATO CLARO: Cada firma especifica exactamente qué esperar',
375
+ '• COLABORACIÓN: Los objetos conocen las firmas de otros objetos',
376
+ '\n📚 Conexión con lecciones anteriores:',
377
+ '• Lección 2: Los objetos interactúan a través de solicitudes ✓',
378
+ '• Lección 3: Las solicitudes son la única forma de ejecutar operaciones ✓',
379
+ '• Lección 4: Cada operación tiene nombre, insumos y valor de retorno ✓',
380
+ '• Lección 5: La interfaz es el conjunto de todas las firmas ✓',
381
+ '• Lección 6: El énfasis está en definir solicitudes e interfaces ✓',
382
+ '\n🚀 Próximo paso:',
383
+ 'Practica este enfoque en tus propios proyectos:',
384
+ '1. Define primero QUÉ debe hacer cada objeto',
385
+ '2. Especifica las interfaces (firmas de operación)',
386
+ '3. Incluye validaciones internas en tus métodos',
387
+ '4. Encapsula el estado, expón solo lo necesario',
388
+ '5. Haz que los objetos colaboren a través de solicitudes',
389
+ '\n💭 Reflexión final:',
390
+ 'Antes de implementar cualquier objeto, pregúntate:',
391
+ '• ¿Cuáles son TODAS las firmas de operación que necesito?',
392
+ '• ¿Qué nombre, insumos y valor de retorno tendrá cada firma?',
393
+ '• ¿Cómo van a colaborar los objetos usando estas firmas?',
394
+ '• ¿El CONJUNTO de firmas forma una interfaz coherente?',
395
+ '\n' +
396
+ '🏆 ¡Has completado el ejemplo más importante del diseño orientado a objetos!',
397
+ 'Ahora entiendes que el ÉNFASIS debe estar en definir el CONJUNTO',
398
+ 'completo de firmas de operación ANTES de implementar.'
399
+ ],
400
+ type: 'text'
401
+ },
402
+ {
403
+ message: '\n✨ ¡Lección 6 completada! Presiona Enter para salir...',
404
+ type: 'pause'
405
+ }
406
+ ]
407
+ }