@icarusmx/creta 1.3.3 → 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 (39) 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/pr-tutorial.js +6 -0
  26. package/lib/templates/LevelModifier.js +287 -0
  27. package/lib/utils/file-utils.js +18 -0
  28. package/lib/utils/input.js +15 -0
  29. package/lib/utils/output.js +4 -0
  30. package/package.json +4 -1
  31. package/refactor.txt +581 -0
  32. package/test/enunciados.test.js +72 -0
  33. package/lessons/lesson1-system-decomposition.js +0 -313
  34. package/lessons/lesson2-object-requests.js +0 -309
  35. package/lessons/lesson3-only-way.js +0 -324
  36. package/lessons/lesson4-operation-signatures.js +0 -319
  37. package/lessons/lesson5-interface-set.js +0 -326
  38. package/lessons/lesson6-interface-design.js +0 -391
  39. package/lessons/lesson7-object-definition.js +0 -300
@@ -1,324 +0,0 @@
1
- #!/usr/bin/env node
2
-
3
- // LECCIÓN 3: Las solicitudes son la única forma de conseguir que un objeto lleve a cabo una operación
4
- // Enfoque práctico: Demostrar que NO hay alternativas a las solicitudes para ejecutar operaciones
5
-
6
- import { createInterface } from 'readline'
7
-
8
- export class Lesson3OnlyWay {
9
- constructor() {
10
- this.rl = createInterface({
11
- input: process.stdin,
12
- output: process.stdout
13
- })
14
- }
15
-
16
- async start() {
17
- console.log("\n💡 ¿Por qué ÚNICA forma?")
18
- console.log("- No puedes forzar a un objeto a ejecutar algo")
19
- console.log("- No puedes manipular directamente su estado interno")
20
- console.log("- Toda operación DEBE pasar por una solicitud")
21
- console.log("- El objeto decide si acepta o rechaza la solicitud")
22
-
23
- await this.waitForEnter("\nPresiona Enter para ver qué significa esto en la práctica...")
24
-
25
- await this.practicalExercise()
26
- await this.conclusion()
27
-
28
- this.rl.close()
29
- }
30
-
31
- async practicalExercise() {
32
- console.clear()
33
- console.log("🛠️ EJERCICIO PRÁCTICO: Caja Fuerte Digital")
34
- console.log("=" .repeat(50))
35
- console.log("🎯 Vamos a demostrar por qué las solicitudes son la ÚNICA forma")
36
- console.log("\nSistema: Una caja fuerte que protege documentos importantes")
37
- console.log("Objeto: DigitalSafe")
38
-
39
- await this.waitForEnter("\nPresiona Enter para ver todas las formas que NO funcionan...")
40
-
41
- await this.step1_ShowWhatDoesntWork()
42
- await this.step2_ShowOnlyWay()
43
- await this.step3_ObjectDecision()
44
- await this.step4_CompleteDemo()
45
- }
46
-
47
- async step1_ShowWhatDoesntWork() {
48
- console.clear()
49
- console.log("❌ FORMAS QUE NO FUNCIONAN")
50
- console.log("=" .repeat(35))
51
- console.log("Veamos todas las cosas que NO puedes hacer:")
52
-
53
- console.log("\n🚫 1. ACCESO DIRECTO A DATOS (Imposible)")
54
- console.log(`// ❌ Esto NO funciona en objetos bien diseñados
55
- class DigitalSafe {
56
- constructor() {
57
- this.#documents = [] // PRIVADO
58
- this.#isLocked = true // PRIVADO
59
- this.#password = "1234" // PRIVADO
60
- }
61
- }
62
-
63
- const safe = new DigitalSafe()
64
- // ❌ ERROR: No puedes acceder a datos privados
65
- console.log(safe.#documents) // SyntaxError!
66
- safe.#isLocked = false // SyntaxError!`)
67
-
68
- await this.waitForEnter("\nPresiona Enter para ver más formas que no funcionan...")
69
-
70
- console.log("\n🚫 2. MANIPULACIÓN EXTERNA (Imposible)")
71
- console.log(`// ❌ No puedes forzar cambios desde afuera
72
- safe.documents = ["documento_falso.pdf"] // undefined (no existe)
73
- safe.isLocked = false // undefined (no existe)
74
- safe.forceOpen() // TypeError: no es función
75
-
76
- // ❌ No puedes inyectar funciones
77
- safe.hackOpen = function() { this.#isLocked = false } // No funciona`)
78
-
79
- await this.waitForEnter("\nPresiona Enter para ver la última forma que no funciona...")
80
-
81
- console.log("\n🚫 3. HERENCIA FORZADA (Violación de diseño)")
82
- console.log(`// ❌ Incluso extendiendo la clase, no puedes saltarte las reglas
83
- class HackedSafe extends DigitalSafe {
84
- forceOpen() {
85
- // ❌ ERROR: No puedes acceder a campos privados del padre
86
- this.#isLocked = false // SyntaxError!
87
- return this.#documents // SyntaxError!
88
- }
89
- }`)
90
-
91
- console.log("\n💡 Observación clave:")
92
- console.log("El objeto está completamente protegido. No hay forma de")
93
- console.log("manipularlo externamente sin su consentimiento.")
94
-
95
- await this.waitForEnter("\nPresiona Enter para ver la ÚNICA forma que funciona...")
96
- }
97
-
98
- async step2_ShowOnlyWay() {
99
- console.clear()
100
- console.log("✅ LA ÚNICA FORMA: SOLICITUDES")
101
- console.log("=" .repeat(40))
102
- console.log("Solo hay UNA manera de que el objeto ejecute operaciones:")
103
-
104
- console.log("\n🔑 IMPLEMENTACIÓN COMPLETA:")
105
- console.log(`class DigitalSafe {
106
- constructor() {
107
- this.#documents = []
108
- this.#isLocked = true
109
- this.#password = "1234"
110
- this.#attempts = 0
111
- this.#maxAttempts = 3
112
- }
113
-
114
- // ✅ SOLICITUD: Intentar desbloquear
115
- unlock(password) {
116
- if (this.#attempts >= this.#maxAttempts) {
117
- return { success: false, message: "Bloqueado por seguridad" }
118
- }
119
-
120
- if (password === this.#password) {
121
- this.#isLocked = false
122
- this.#attempts = 0
123
- return { success: true, message: "Caja fuerte desbloqueada" }
124
- } else {
125
- this.#attempts++
126
- return {
127
- success: false,
128
- message: \`Contraseña incorrecta. Intentos restantes: \${this.#maxAttempts - this.#attempts}\`
129
- }
130
- }
131
- }
132
-
133
- // ✅ SOLICITUD: Agregar documento
134
- addDocument(document) {
135
- if (this.#isLocked) {
136
- return { success: false, message: "Caja fuerte bloqueada" }
137
- }
138
-
139
- this.#documents.push(document)
140
- return { success: true, message: "Documento agregado" }
141
- }
142
-
143
- // ✅ SOLICITUD: Obtener documentos
144
- getDocuments() {
145
- if (this.#isLocked) {
146
- return { success: false, message: "Caja fuerte bloqueada", documents: [] }
147
- }
148
-
149
- return { success: true, documents: [...this.#documents] }
150
- }
151
-
152
- // ✅ SOLICITUD: Bloquear
153
- lock() {
154
- this.#isLocked = true
155
- return { success: true, message: "Caja fuerte bloqueada" }
156
- }
157
-
158
- // ✅ SOLICITUD: Consultar estado
159
- getStatus() {
160
- return {
161
- isLocked: this.#isLocked,
162
- documentsCount: this.#documents.length,
163
- attemptsRemaining: this.#maxAttempts - this.#attempts
164
- }
165
- }
166
- }`)
167
-
168
- await this.waitForEnter("\nPresiona Enter para ver por qué esto es la ÚNICA forma...")
169
- }
170
-
171
- async step3_ObjectDecision() {
172
- console.clear()
173
- console.log("🧠 EL OBJETO DECIDE")
174
- console.log("=" .repeat(25))
175
- console.log("Observa que cada solicitud permite al objeto DECIDIR:")
176
-
177
- console.log("\n🔍 EJEMPLO 1: Solicitud aceptada")
178
- console.log(`const safe = new DigitalSafe()
179
-
180
- // SOLICITUD: unlock con contraseña correcta
181
- const result = safe.unlock("1234")
182
- console.log(result) // { success: true, message: "Caja fuerte desbloqueada" }
183
-
184
- // El OBJETO decidió aceptar la solicitud porque:
185
- // - La contraseña era correcta
186
- // - No se habían agotado los intentos`)
187
-
188
- await this.waitForEnter("\nPresiona Enter para ver una solicitud rechazada...")
189
-
190
- console.log("\n🚫 EJEMPLO 2: Solicitud rechazada")
191
- console.log(`// SOLICITUD: addDocument sin desbloquear
192
- const result2 = safe.addDocument("documento_secreto.pdf")
193
- console.log(result2) // { success: false, message: "Caja fuerte bloqueada" }
194
-
195
- // El OBJETO decidió rechazar la solicitud porque:
196
- // - La caja fuerte está bloqueada
197
- // - No cumple las condiciones internas`)
198
-
199
- await this.waitForEnter("\nPresiona Enter para ver el control total del objeto...")
200
-
201
- console.log("\n🛡️ EJEMPLO 3: Protección automática")
202
- console.log(`// Intentos fallidos múltiples
203
- safe.unlock("wrong1") // { success: false, message: "Contraseña incorrecta..." }
204
- safe.unlock("wrong2") // { success: false, message: "Contraseña incorrecta..." }
205
- safe.unlock("wrong3") // { success: false, message: "Contraseña incorrecta..." }
206
- safe.unlock("1234") // { success: false, message: "Bloqueado por seguridad" }
207
-
208
- // El OBJETO decidió bloquearse completamente porque:
209
- // - Se agotaron los intentos permitidos
210
- // - Sus reglas internas de seguridad se activaron`)
211
-
212
- console.log("\n💡 Punto clave:")
213
- console.log("Incluso con la contraseña correcta, el objeto puede rechazar")
214
- console.log("la solicitud si sus condiciones internas no se cumplen.")
215
-
216
- await this.waitForEnter("\nPresiona Enter para la demostración completa...")
217
- }
218
-
219
- async step4_CompleteDemo() {
220
- console.clear()
221
- console.log("🎭 DEMOSTRACIÓN: Flujo Completo")
222
- console.log("=" .repeat(40))
223
- console.log("Veamos un flujo completo de solicitudes:")
224
-
225
- console.log("\n// Crear caja fuerte")
226
- console.log("const safe = new DigitalSafe()")
227
- console.log("")
228
- console.log("// 🔍 SOLICITUD: Consultar estado inicial")
229
- console.log("console.log(safe.getStatus())")
230
- console.log("// { isLocked: true, documentsCount: 0, attemptsRemaining: 3 }")
231
- console.log("")
232
- console.log("// 🚫 SOLICITUD: Intentar agregar documento (será rechazada)")
233
- console.log("safe.addDocument('mi_testamento.pdf')")
234
- console.log("// { success: false, message: 'Caja fuerte bloqueada' }")
235
- console.log("")
236
- console.log("// 🔑 SOLICITUD: Desbloquear")
237
- console.log("safe.unlock('1234')")
238
- console.log("// { success: true, message: 'Caja fuerte desbloqueada' }")
239
- console.log("")
240
- console.log("// ✅ SOLICITUD: Ahora sí agregar documento")
241
- console.log("safe.addDocument('mi_testamento.pdf')")
242
- console.log("// { success: true, message: 'Documento agregado' }")
243
- console.log("")
244
- console.log("safe.addDocument('contrato_importante.pdf')")
245
- console.log("// { success: true, message: 'Documento agregado' }")
246
-
247
- await this.waitForEnter("\nPresiona Enter para ver la recuperación...")
248
-
249
- console.log("\n// 📄 SOLICITUD: Recuperar documentos")
250
- console.log("const docs = safe.getDocuments()")
251
- console.log("console.log(docs)")
252
- console.log("// { success: true, documents: ['mi_testamento.pdf', 'contrato_importante.pdf'] }")
253
- console.log("")
254
- console.log("// 🔒 SOLICITUD: Bloquear nuevamente")
255
- console.log("safe.lock()")
256
- console.log("// { success: true, message: 'Caja fuerte bloqueada' }")
257
- console.log("")
258
- console.log("// 🚫 SOLICITUD: Intentar recuperar (será rechazada)")
259
- console.log("safe.getDocuments()")
260
- console.log("// { success: false, message: 'Caja fuerte bloqueada', documents: [] }")
261
-
262
- console.log("\n🎯 Observaciones finales:")
263
- console.log("• Cada operación requirió una SOLICITUD específica")
264
- console.log("• El objeto controló completamente qué solicitudes aceptar")
265
- console.log("• No hubo forma de saltarse este mecanismo")
266
- console.log("• Las solicitudes son verdaderamente la ÚNICA forma")
267
-
268
- await this.waitForEnter("\nPresiona Enter para la conclusión...")
269
- }
270
-
271
- async conclusion() {
272
- console.clear()
273
- console.log("🎓 CONCLUSIÓN: Solicitudes como Única Forma")
274
- console.log("=" .repeat(50))
275
- console.log("🎯 Hemos demostrado que:")
276
-
277
- console.log("\n1️⃣ NO es posible acceder directamente a datos privados")
278
- console.log("2️⃣ NO es posible manipular el objeto externamente")
279
- console.log("3️⃣ NO es posible forzar operaciones sin consentimiento")
280
- console.log("4️⃣ Las SOLICITUDES son literalmente la única forma")
281
-
282
- console.log("\n🔑 Características de las solicitudes:")
283
- console.log("• El objeto DECIDE si acepta o rechaza")
284
- console.log("• Cada solicitud pasa por validaciones internas")
285
- console.log("• El objeto mantiene control total de su estado")
286
- console.log("• Las reglas internas se respetan siempre")
287
-
288
- console.log("\n🛡️ Beneficios de este diseño:")
289
- console.log("• Seguridad garantizada")
290
- console.log("• Integridad de datos preservada")
291
- console.log("• Comportamiento predecible")
292
- console.log("• Control total del objeto sobre sí mismo")
293
-
294
- console.log("\n📚 Conexión con otras lecciones:")
295
- console.log("• Lección 1: Los objetos que identificamos tienen este comportamiento")
296
- console.log("• Lección 2: Esas interacciones son siempre solicitudes")
297
- console.log("• Lección 3: ✅ Y son la ÚNICA forma de ejecutar operaciones")
298
- console.log("• Lecciones 4-6: Cómo definir formalmente estas solicitudes")
299
-
300
- console.log("\n💭 Reflexión:")
301
- console.log("Imagina que tu casa tuviera esta protección: nadie puede entrar")
302
- console.log("a menos que tú decidas abrir la puerta después de verificar")
303
- console.log("quién es. Los objetos funcionan exactamente igual.")
304
-
305
- console.log("\n🏆 Ahora entiendes por qué las solicitudes son la ÚNICA forma:")
306
- console.log("porque los objetos están diseñados para protegerse y decidir.")
307
-
308
- await this.waitForEnter("\n✨ ¡Lección 3 completada! Presiona Enter para salir...")
309
- }
310
-
311
- async waitForEnter(message) {
312
- return new Promise((resolve) => {
313
- this.rl.question(message, () => {
314
- resolve()
315
- })
316
- })
317
- }
318
- }
319
-
320
- // Para usar la lección independientemente
321
- if (import.meta.url === `file://${process.argv[1]}`) {
322
- const lesson = new Lesson3OnlyWay()
323
- await lesson.start()
324
- }
@@ -1,319 +0,0 @@
1
- #!/usr/bin/env node
2
-
3
- // LECCIÓN 4: Cada operación declarada por un objeto debe incluir: a) nombre de la operación; b) insumos necesarios para realizar la operación; c) el valor que regresa tras ejecutar la operación. Estos tres elementos constituyen la firma de operación.
4
- // Enfoque práctico: Diseñar firmas de operación precisas y completas
5
-
6
- import { createInterface } from 'readline'
7
-
8
- export class Lesson4OperationSignatures {
9
- constructor() {
10
- this.rl = createInterface({
11
- input: process.stdin,
12
- output: process.stdout
13
- })
14
- }
15
-
16
- async start() {
17
- console.log("\n💡 ¿Por qué son importantes las firmas?")
18
- console.log("- Define exactamente QUÉ hace la operación (nombre)")
19
- console.log("- Define exactamente QUÉ necesita (insumos)")
20
- console.log("- Define exactamente QUÉ devuelve (valor de retorno)")
21
- console.log("- Permite predecir el comportamiento sin ver la implementación")
22
-
23
- await this.waitForEnter("\nPresiona Enter para comenzar con ejemplos prácticos...")
24
-
25
- await this.practicalExercise()
26
- await this.conclusion()
27
-
28
- this.rl.close()
29
- }
30
-
31
- async practicalExercise() {
32
- console.clear()
33
- console.log("🛠️ EJERCICIO PRÁCTICO: Calculadora Financiera")
34
- console.log("=" .repeat(50))
35
- console.log("🎯 Vamos a diseñar firmas de operación precisas y completas")
36
- console.log("\nSistema: Calculadora para operaciones financieras")
37
- console.log("Objeto: FinancialCalculator")
38
-
39
- await this.waitForEnter("\nPresiona Enter para ver firmas mal diseñadas...")
40
-
41
- await this.step1_BadSignatures()
42
- await this.step2_GoodSignatures()
43
- await this.step3_SignatureAnalysis()
44
- await this.step4_CompleteExample()
45
- }
46
-
47
- async step1_BadSignatures() {
48
- console.clear()
49
- console.log("❌ FIRMAS MAL DISEÑADAS")
50
- console.log("=" .repeat(30))
51
- console.log("Veamos firmas incompletas o confusas:")
52
-
53
- console.log("\n🚫 PROBLEMA 1: Nombre poco claro")
54
- console.log(`// ❌ ¿Qué hace exactamente 'calc'?
55
- calc(x, y) → ?
56
-
57
- // ❌ ¿Es 'do' suma, resta, multiplicación?
58
- do(amount, rate) → ?`)
59
-
60
- console.log("\n🚫 PROBLEMA 2: Insumos ambiguos")
61
- console.log(`// ❌ ¿Qué tipo de datos espera?
62
- calculateInterest(amount, rate) → number
63
- // ¿amount es string o number?
64
- // ¿rate es porcentaje (0.05) o entero (5)?`)
65
-
66
- console.log("\n🚫 PROBLEMA 3: Valor de retorno incierto")
67
- console.log(`// ❌ ¿Qué devuelve exactamente?
68
- calculatePayment() → ?
69
- // ¿Un número? ¿Un objeto? ¿null si falla?
70
-
71
- // ❌ ¿Y si hay error?
72
- divideNumbers(a, b) → number
73
- // ¿Qué pasa si b es 0?`)
74
-
75
- await this.waitForEnter("\nPresiona Enter para ver más problemas...")
76
-
77
- console.log("\n🚫 PROBLEMA 4: Firmas inconsistentes")
78
- console.log(`// ❌ Métodos similares con firmas diferentes
79
- addMoney(amount) → boolean
80
- subtractCash(value, currency) → {success: boolean, balance: number}
81
- multiply(x, y, precision) → number | null
82
-
83
- // ❌ Imposible predecir qué esperar de cada método`)
84
-
85
- console.log("\n💥 Consecuencias:")
86
- console.log("• Imposible usar el objeto sin ver el código interno")
87
- console.log("• Errores constantes por malentender los parámetros")
88
- console.log("• Código frágil y difícil de mantener")
89
- console.log("• Colaboración entre objetos impredecible")
90
-
91
- await this.waitForEnter("\nPresiona Enter para ver cómo debe ser...")
92
- }
93
-
94
- async step2_GoodSignatures() {
95
- console.clear()
96
- console.log("✅ FIRMAS BIEN DISEÑADAS")
97
- console.log("=" .repeat(35))
98
- console.log("Ahora veamos firmas completas y precisas:")
99
-
100
- console.log("\n🎯 ELEMENTO A: Nombre claro y específico")
101
- console.log(`// ✅ Nombres que describen exactamente la operación
102
- calculateSimpleInterest(principal, rate, time) → number
103
- calculateCompoundInterest(principal, rate, time, frequency) → number
104
- calculateMonthlyPayment(loanAmount, interestRate, termInMonths) → number`)
105
-
106
- console.log("\n📥 ELEMENTO B: Insumos específicos y tipados")
107
- console.log(`// ✅ Cada parámetro claramente definido
108
- calculateSimpleInterest(
109
- principal: number, // Monto principal en pesos
110
- rate: number, // Tasa anual como decimal (0.05 = 5%)
111
- time: number // Tiempo en años
112
- ) → number
113
-
114
- calculateMonthlyPayment(
115
- loanAmount: number, // Monto del préstamo en pesos
116
- interestRate: number, // Tasa mensual como decimal
117
- termInMonths: number // Plazo en meses
118
- ) → number`)
119
-
120
- console.log("\n📤 ELEMENTO C: Valor de retorno específico")
121
- console.log(`// ✅ Especifica exactamente qué devuelve y cuándo
122
- calculateLoanPayment(amount, rate, term) → {
123
- success: boolean,
124
- monthlyPayment: number | null,
125
- totalInterest: number | null,
126
- error: string | null
127
- }
128
-
129
- validateLoanAmount(amount) → {
130
- isValid: boolean,
131
- minimumRequired: number,
132
- maximumAllowed: number
133
- }`)
134
-
135
- await this.waitForEnter("\nPresiona Enter para ver la implementación completa...")
136
- }
137
-
138
- async step3_SignatureAnalysis() {
139
- console.clear()
140
- console.log("🔍 ANÁLISIS DE FIRMAS COMPLETAS")
141
- console.log("=" .repeat(40))
142
- console.log("Examinemos cada elemento de las firmas:")
143
-
144
- console.log("\n💼 EJEMPLO: Calculadora financiera completa")
145
- console.log(`class FinancialCalculator {
146
- // 🎯 FIRMA 1: Interés simple
147
- calculateSimpleInterest(
148
- principal: number, // a) Monto principal en pesos
149
- rate: number, // b) Tasa anual (0.05 = 5%)
150
- time: number // c) Tiempo en años
151
- ): number { // RETORNA: Interés total calculado
152
- return principal * rate * time
153
- }
154
-
155
- // 🎯 FIRMA 2: Validación con resultado estructurado
156
- validateLoanApplication(
157
- income: number, // a) Ingreso mensual
158
- existingDebt: number, // b) Deuda actual
159
- requestedAmount: number // c) Monto solicitado
160
- ): { // RETORNA: Objeto con análisis completo
161
- approved: boolean,
162
- maxLoanAmount: number,
163
- debtToIncomeRatio: number,
164
- reasons: string[]
165
- }
166
-
167
- // 🎯 FIRMA 3: Cálculo que puede fallar
168
- calculateCompoundInterest(
169
- principal: number, // a) Monto principal
170
- rate: number, // b) Tasa anual
171
- time: number, // c) Años
172
- frequency: number // d) Frecuencia de composición
173
- ): number | null { // RETORNA: Resultado o null si hay error
174
- if (principal <= 0 || rate < 0 || time <= 0 || frequency <= 0) {
175
- return null
176
- }
177
- return principal * Math.pow(1 + rate/frequency, frequency * time)
178
- }
179
- }`)
180
-
181
- await this.waitForEnter("\nPresiona Enter para analizar cada firma...")
182
-
183
- console.log("\n📋 ANÁLISIS FIRMA POR FIRMA:")
184
- console.log("\n1️⃣ calculateSimpleInterest:")
185
- console.log(" • NOMBRE: 'calculateSimpleInterest' - claro y específico")
186
- console.log(" • INSUMOS: (principal, rate, time) - 3 números con propósito definido")
187
- console.log(" • RETORNO: number - interés calculado, siempre un número")
188
-
189
- console.log("\n2️⃣ validateLoanApplication:")
190
- console.log(" • NOMBRE: 'validateLoanApplication' - describe validación completa")
191
- console.log(" • INSUMOS: (income, existingDebt, requestedAmount) - datos financieros")
192
- console.log(" • RETORNO: objeto estructurado - análisis completo con múltiples campos")
193
-
194
- console.log("\n3️⃣ calculateCompoundInterest:")
195
- console.log(" • NOMBRE: 'calculateCompoundInterest' - específico del tipo de interés")
196
- console.log(" • INSUMOS: (principal, rate, time, frequency) - 4 parámetros necesarios")
197
- console.log(" • RETORNO: number | null - puede fallar si datos inválidos")
198
-
199
- await this.waitForEnter("\nPresiona Enter para ver cómo usar estas firmas...")
200
- }
201
-
202
- async step4_CompleteExample() {
203
- console.clear()
204
- console.log("🎭 DEMOSTRACIÓN: Uso con Firmas Claras")
205
- console.log("=" .repeat(45))
206
- console.log("Veamos cómo las firmas bien diseñadas facilitan el uso:")
207
-
208
- console.log("\n// Crear calculadora")
209
- console.log("const calc = new FinancialCalculator()")
210
- console.log("")
211
- console.log("// 💡 Con las firmas claras, sabemos exactamente qué esperar:")
212
- console.log("")
213
- console.log("// FIRMA: calculateSimpleInterest(principal, rate, time) → number")
214
- console.log("const interest = calc.calculateSimpleInterest(10000, 0.05, 2)")
215
- console.log("console.log(interest) // 1000 (siempre un número)")
216
-
217
- await this.waitForEnter("\nPresiona Enter para ver validación...")
218
-
219
- console.log("\n// FIRMA: validateLoanApplication(income, debt, amount) → objeto")
220
- console.log("const validation = calc.validateLoanApplication(5000, 1000, 50000)")
221
- console.log("console.log(validation)")
222
- console.log("// {")
223
- console.log("// approved: false,")
224
- console.log("// maxLoanAmount: 20000,")
225
- console.log("// debtToIncomeRatio: 0.2,")
226
- console.log("// reasons: ['Monto solicitado excede capacidad de pago']")
227
- console.log("// }")
228
- console.log("")
229
- console.log("// 💡 Podemos usar cada campo porque la firma nos dice qué esperar")
230
- console.log("if (validation.approved) {")
231
- console.log(" console.log('Préstamo aprobado!')")
232
- console.log("} else {")
233
- console.log(" console.log('Máximo permitido:', validation.maxLoanAmount)")
234
- console.log(" validation.reasons.forEach(reason => console.log('❌', reason))")
235
- console.log("}")
236
-
237
- await this.waitForEnter("\nPresiona Enter para ver manejo de errores...")
238
-
239
- console.log("\n// FIRMA: calculateCompoundInterest(...) → number | null")
240
- console.log("const compound1 = calc.calculateCompoundInterest(10000, 0.05, 2, 12)")
241
- console.log("const compound2 = calc.calculateCompoundInterest(-1000, 0.05, 2, 12)")
242
- console.log("")
243
- console.log("// 💡 La firma nos dice que puede retornar null, así que verificamos")
244
- console.log("if (compound1 !== null) {")
245
- console.log(" console.log('Interés compuesto:', compound1) // 11049.41")
246
- console.log("}")
247
- console.log("")
248
- console.log("if (compound2 === null) {")
249
- console.log(" console.log('Error: datos inválidos') // Se ejecuta")
250
- console.log("}")
251
-
252
- console.log("\n🎯 Beneficios observados:")
253
- console.log("• Sabemos exactamente qué pasar a cada método")
254
- console.log("• Sabemos exactamente qué esperar de vuelta")
255
- console.log("• Podemos manejar errores apropiadamente")
256
- console.log("• El código es predecible y confiable")
257
-
258
- await this.waitForEnter("\nPresiona Enter para la conclusión...")
259
- }
260
-
261
- async conclusion() {
262
- console.clear()
263
- console.log("🎓 CONCLUSIÓN: Firmas de Operación")
264
- console.log("=" .repeat(40))
265
- console.log("🎯 Hemos demostrado que cada firma debe incluir:")
266
-
267
- console.log("\n🎯 A) NOMBRE de la operación:")
268
- console.log(" • Claro y específico")
269
- console.log(" • Describe exactamente qué hace")
270
- console.log(" • Ejemplo: 'calculateSimpleInterest' vs 'calc'")
271
-
272
- console.log("\n📥 B) INSUMOS necesarios:")
273
- console.log(" • Tipo y propósito de cada parámetro")
274
- console.log(" • Valores esperados y restricciones")
275
- console.log(" • Ejemplo: 'rate: number (decimal, 0.05 = 5%)'")
276
-
277
- console.log("\n📤 C) VALOR de retorno:")
278
- console.log(" • Tipo exacto que retorna")
279
- console.log(" • Qué significa el valor")
280
- console.log(" • Cómo manejar casos de error")
281
- console.log(" • Ejemplo: 'number | null' vs solo 'number'")
282
-
283
- console.log("\n🌟 Beneficios de firmas completas:")
284
- console.log("• Predictibilidad total del comportamiento")
285
- console.log("• Colaboración segura entre objetos")
286
- console.log("• Código autodocumentado")
287
- console.log("• Detección temprana de errores")
288
-
289
- console.log("\n📚 Conexión con otras lecciones:")
290
- console.log("• Lección 1-3: Las operaciones que identificamos necesitan firmas")
291
- console.log("• Lección 4: ✅ Cada operación tiene nombre, insumos y retorno")
292
- console.log("• Lección 5: El conjunto de firmas forma la interfaz")
293
- console.log("• Lección 6: El énfasis está en diseñar estas firmas primero")
294
-
295
- console.log("\n💭 Reflexión:")
296
- console.log("¿Te imaginas usar una función de la que no sabes qué parámetros")
297
- console.log("espera ni qué devuelve? ¡Sería imposible! Las firmas son el")
298
- console.log("contrato que hace posible la colaboración entre objetos.")
299
-
300
- console.log("\n🏆 Ahora entiendes por qué cada operación necesita una firma")
301
- console.log("completa: es la base de la comunicación predecible.")
302
-
303
- await this.waitForEnter("\n✨ ¡Lección 4 completada! Presiona Enter para salir...")
304
- }
305
-
306
- async waitForEnter(message) {
307
- return new Promise((resolve) => {
308
- this.rl.question(message, () => {
309
- resolve()
310
- })
311
- })
312
- }
313
- }
314
-
315
- // Para usar la lección independientemente
316
- if (import.meta.url === `file://${process.argv[1]}`) {
317
- const lesson = new Lesson4OperationSignatures()
318
- await lesson.start()
319
- }