@icarusmx/creta 0.8.1 → 0.9.0

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.
@@ -6,7 +6,8 @@
6
6
  "WebFetch(domain:github.com)",
7
7
  "Bash(npm install)",
8
8
  "Bash(npm run dev:*)",
9
- "Bash(rm:*)"
9
+ "Bash(rm:*)",
10
+ "Bash(npm publish:*)"
10
11
  ],
11
12
  "deny": [],
12
13
  "ask": []
package/bin/creta.js CHANGED
@@ -6,6 +6,7 @@ import fs from 'fs'
6
6
  import path from 'path'
7
7
  import { fileURLToPath } from 'url'
8
8
  import { CretaCodeSession } from '../lib/session.js'
9
+ import { Lesson6InterfaceDesign } from '../lessons/lesson6-interface-design.js'
9
10
 
10
11
  const ENUNCIADOS = [
11
12
  {
@@ -778,27 +779,7 @@ async function startEnunciadosSelectorInteractive() {
778
779
  const highlight = isSelected ? '\x1b[36m' : '\x1b[37m' // cyan for selected, white for normal
779
780
  const reset = '\x1b[0m'
780
781
 
781
- console.log(`${highlight}${prefix}${index + 1}. [${enunciado.nivel}] ${enunciado.enfoque}${reset}`)
782
-
783
- if (isSelected) {
784
- // Show full text for selected option with word wrapping
785
- const maxWidth = 66
786
- const words = enunciado.texto.split(' ')
787
- let currentLine = ' "'
788
-
789
- words.forEach(word => {
790
- if (currentLine.length + word.length + 1 <= maxWidth) {
791
- currentLine += (currentLine === ' "' ? '' : ' ') + word
792
- } else {
793
- console.log(`${highlight}${currentLine}${reset}`)
794
- currentLine = ' ' + word
795
- }
796
- })
797
-
798
- if (currentLine.length > 6) {
799
- console.log(`${highlight}${currentLine}"${reset}`)
800
- }
801
- }
782
+ console.log(`${highlight}${prefix}${index + 1}. ${enunciado.texto}${reset}`)
802
783
  console.log("")
803
784
  })
804
785
  }
@@ -806,7 +787,7 @@ async function startEnunciadosSelectorInteractive() {
806
787
  return new Promise((resolve) => {
807
788
  renderOptions()
808
789
 
809
- const onKeyPress = (key) => {
790
+ const onKeyPress = async (key) => {
810
791
  if (key === 'q' || key === '\x03') { // q or Ctrl+C
811
792
  process.stdin.setRawMode(false)
812
793
  process.stdin.removeListener('data', onKeyPress)
@@ -830,13 +811,30 @@ async function startEnunciadosSelectorInteractive() {
830
811
  console.log(`\n💡 Enfoque: ${enunciadoSeleccionado.enfoque}`)
831
812
  console.log(`📚 Nivel: ${enunciadoSeleccionado.nivel}`)
832
813
 
833
- console.log("\n🚀 Próximamente:")
834
- console.log("- Sesiones de estudio dirigidas basadas en este enunciado")
835
- console.log("- Ejercicios prácticos que ilustren el concepto")
836
- console.log("- Proyectos específicos para internalizar la idea")
814
+ // Check if we have a lesson implementation for this enunciado
815
+ if (enunciadoSeleccionado.id === 6) {
816
+ console.log("\n🚀 ¡Lección disponible! Iniciando sesión de estudio dirigida...")
817
+ await new Promise(resolve => setTimeout(resolve, 1500)) // Brief pause
818
+
819
+ try {
820
+ const lesson6 = new Lesson6InterfaceDesign()
821
+ await lesson6.start()
822
+ } catch (error) {
823
+ console.error("\n❌ Error al ejecutar la lección:", error.message)
824
+ console.log("\n🚀 Próximamente:")
825
+ console.log("- Sesiones de estudio dirigidas basadas en este enunciado")
826
+ console.log("- Ejercicios prácticos que ilustren el concepto")
827
+ console.log("- Proyectos específicos para internalizar la idea")
828
+ }
829
+ } else {
830
+ console.log("\n🚀 Próximamente:")
831
+ console.log("- Sesiones de estudio dirigidas basadas en este enunciado")
832
+ console.log("- Ejercicios prácticos que ilustren el concepto")
833
+ console.log("- Proyectos específicos para internalizar la idea")
837
834
 
838
- console.log("\n💭 Por ahora, reflexiona: ¿qué parte específica de este enunciado")
839
- console.log(" te genera más curiosidad o confusión?")
835
+ console.log("\n💭 Por ahora, reflexiona: ¿qué parte específica de este enunciado")
836
+ console.log(" te genera más curiosidad o confusión?")
837
+ }
840
838
 
841
839
  resolve()
842
840
  return
@@ -874,8 +872,7 @@ async function startEnunciadosSelectorFallback() {
874
872
  console.log("")
875
873
 
876
874
  ENUNCIADOS.forEach((enunciado, index) => {
877
- console.log(`${index + 1}. [${enunciado.nivel}] ${enunciado.enfoque}`)
878
- console.log(` "${enunciado.texto}"`)
875
+ console.log(`${index + 1}. ${enunciado.texto}`)
879
876
  console.log("")
880
877
  })
881
878
 
@@ -897,13 +894,32 @@ async function startEnunciadosSelectorFallback() {
897
894
  console.log(`\n💡 Enfoque: ${enunciadoSeleccionado.enfoque}`)
898
895
  console.log(`📚 Nivel: ${enunciadoSeleccionado.nivel}`)
899
896
 
900
- console.log("\n🚀 Próximamente:")
901
- console.log("- Sesiones de estudio dirigidas basadas en este enunciado")
902
- console.log("- Ejercicios prácticos que ilustren el concepto")
903
- console.log("- Proyectos específicos para internalizar la idea")
897
+ // Check if we have a lesson implementation for this enunciado
898
+ if (enunciadoSeleccionado.id === 6) {
899
+ console.log("\n🚀 ¡Lección disponible! Iniciando sesión de estudio dirigida...")
900
+ rl.close()
901
+ await new Promise(resolve => setTimeout(resolve, 1500)) // Brief pause
902
+
903
+ try {
904
+ const lesson6 = new Lesson6InterfaceDesign()
905
+ await lesson6.start()
906
+ } catch (error) {
907
+ console.error("\n❌ Error al ejecutar la lección:", error.message)
908
+ console.log("\n🚀 Próximamente:")
909
+ console.log("- Sesiones de estudio dirigidas basadas en este enunciado")
910
+ console.log("- Ejercicios prácticos que ilustren el concepto")
911
+ console.log("- Proyectos específicos para internalizar la idea")
912
+ }
913
+ return
914
+ } else {
915
+ console.log("\n🚀 Próximamente:")
916
+ console.log("- Sesiones de estudio dirigidas basadas en este enunciado")
917
+ console.log("- Ejercicios prácticos que ilustren el concepto")
918
+ console.log("- Proyectos específicos para internalizar la idea")
904
919
 
905
- console.log("\n💭 Por ahora, reflexiona: ¿qué parte específica de este enunciado")
906
- console.log(" te genera más curiosidad o confusión?")
920
+ console.log("\n💭 Por ahora, reflexiona: ¿qué parte específica de este enunciado")
921
+ console.log(" te genera más curiosidad o confusión?")
922
+ }
907
923
 
908
924
  } else {
909
925
  console.log("❌ Opción no válida. Elige un número entre 1 y 6.")
@@ -0,0 +1,306 @@
1
+ #!/usr/bin/env node
2
+
3
+ // LECCIÓN 6: El énfasis al diseñar los objetos debe estar en la definición de sus solicitudes e interfaces
4
+ // Enfoque práctico: Sistema de gestión de tareas con diseño interface-first
5
+
6
+ import { createInterface } from 'readline'
7
+
8
+ export class Lesson6InterfaceDesign {
9
+ constructor() {
10
+ this.rl = createInterface({
11
+ input: process.stdin,
12
+ output: process.stdout
13
+ })
14
+ }
15
+
16
+ async start() {
17
+ console.log("🎯 LECCIÓN 6: Diseño basado en Interfaces")
18
+ console.log("=" .repeat(50))
19
+ console.log("📚 Concepto: El énfasis al diseñar los objetos debe estar en la definición de sus solicitudes e interfaces.")
20
+ console.log("\n💡 ¿Por qué es importante?")
21
+ console.log("- Las interfaces definen QUÉ hace un objeto, no CÓMO lo hace")
22
+ console.log("- Facilita la colaboración entre objetos")
23
+ console.log("- Permite cambiar implementaciones sin afectar otros objetos")
24
+ console.log("- Hace el código más mantenible y extensible")
25
+
26
+ await this.waitForEnter("\nPresiona Enter para comenzar el ejercicio práctico...")
27
+
28
+ await this.practicalExercise()
29
+ await this.conclusion()
30
+
31
+ this.rl.close()
32
+ }
33
+
34
+ async practicalExercise() {
35
+ console.clear()
36
+ console.log("🛠️ EJERCICIO PRÁCTICO: Sistema de Gestión de Tareas")
37
+ console.log("=" .repeat(50))
38
+ console.log("🎯 Objetivo: Diseñar interfaces ANTES de implementar")
39
+ console.log("\nVamos a crear un sistema donde:")
40
+ console.log("- TaskManager gestiona una colección de tareas")
41
+ console.log("- Task representa una tarea individual")
42
+ console.log("- TaskStorage guarda y recupera tareas")
43
+
44
+ await this.waitForEnter("\nPresiona Enter para ver cómo diseñar las interfaces...")
45
+
46
+ await this.step1_DefineRequests()
47
+ await this.step2_DefineInterfaces()
48
+ await this.step3_ImplementObjects()
49
+ await this.step4_TestInteraction()
50
+ }
51
+
52
+ async step1_DefineRequests() {
53
+ console.clear()
54
+ console.log("📋 PASO 1: Definir las Solicitudes")
55
+ console.log("=" .repeat(40))
56
+ console.log("Antes de escribir código, pensemos: ¿Qué solicitudes debe manejar cada objeto?")
57
+ console.log("\n🎯 TaskManager debe poder:")
58
+ console.log(" - Crear una nueva tarea")
59
+ console.log(" - Listar todas las tareas")
60
+ console.log(" - Marcar tarea como completada")
61
+ console.log(" - Eliminar una tarea")
62
+
63
+ console.log("\n📝 Task debe poder:")
64
+ console.log(" - Proporcionar su información")
65
+ console.log(" - Cambiar su estado (pendiente/completada)")
66
+ console.log(" - Validar si está completada")
67
+
68
+ console.log("\n💾 TaskStorage debe poder:")
69
+ console.log(" - Guardar una tarea")
70
+ console.log(" - Recuperar todas las tareas")
71
+ console.log(" - Eliminar una tarea específica")
72
+
73
+ await this.waitForEnter("\n✅ ¡Excelente! Ya definimos QUÉ debe hacer cada objeto. Presiona Enter para definir las interfaces...")
74
+ }
75
+
76
+ async step2_DefineInterfaces() {
77
+ console.clear()
78
+ console.log("🔌 PASO 2: Definir las Interfaces (Firmas de Operación)")
79
+ console.log("=" .repeat(50))
80
+ console.log("Ahora especifiquemos CÓMO se solicitan estas operaciones:")
81
+
82
+ console.log("\n// TaskManager Interface")
83
+ console.log("class TaskManager {")
84
+ console.log(" createTask(title, description) → Task")
85
+ console.log(" getAllTasks() → Array<Task>")
86
+ console.log(" completeTask(taskId) → boolean")
87
+ console.log(" deleteTask(taskId) → boolean")
88
+ console.log("}")
89
+
90
+ console.log("\n// Task Interface")
91
+ console.log("class Task {")
92
+ console.log(" constructor(id, title, description) → Task")
93
+ console.log(" getInfo() → {id, title, description, completed}")
94
+ console.log(" markCompleted() → void")
95
+ console.log(" isCompleted() → boolean")
96
+ console.log("}")
97
+
98
+ console.log("\n// TaskStorage Interface")
99
+ console.log("class TaskStorage {")
100
+ console.log(" save(task) → void")
101
+ console.log(" findAll() → Array<Task>")
102
+ console.log(" remove(taskId) → boolean")
103
+ console.log("}")
104
+
105
+ console.log("\n💡 Observa que cada operación especifica:")
106
+ console.log(" a) Nombre de la operación (createTask, save, etc.)")
107
+ console.log(" b) Insumos necesarios (title, description, taskId, etc.)")
108
+ console.log(" c) Valor que regresa (Task, boolean, Array, etc.)")
109
+
110
+ await this.waitForEnter("\n✅ Interfaces definidas. Presiona Enter para implementar...")
111
+ }
112
+
113
+ async step3_ImplementObjects() {
114
+ console.clear()
115
+ console.log("⚙️ PASO 3: Implementar los Objetos")
116
+ console.log("=" .repeat(40))
117
+ console.log("Ahora que tenemos las interfaces claras, implementemos:")
118
+
119
+ console.log("\n// Implementación de Task")
120
+ console.log(`class Task {
121
+ constructor(id, title, description) {
122
+ this.id = id
123
+ this.title = title
124
+ this.description = description
125
+ this.completed = false
126
+ }
127
+
128
+ getInfo() {
129
+ return {
130
+ id: this.id,
131
+ title: this.title,
132
+ description: this.description,
133
+ completed: this.completed
134
+ }
135
+ }
136
+
137
+ markCompleted() {
138
+ this.completed = true
139
+ }
140
+
141
+ isCompleted() {
142
+ return this.completed
143
+ }
144
+ }`)
145
+
146
+ await this.waitForEnter("\nPresiona Enter para ver TaskStorage...")
147
+
148
+ console.log("\n// Implementación de TaskStorage")
149
+ console.log(`class TaskStorage {
150
+ constructor() {
151
+ this.tasks = []
152
+ }
153
+
154
+ save(task) {
155
+ this.tasks.push(task)
156
+ }
157
+
158
+ findAll() {
159
+ return [...this.tasks]
160
+ }
161
+
162
+ remove(taskId) {
163
+ const index = this.tasks.findIndex(t => t.id === taskId)
164
+ if (index !== -1) {
165
+ this.tasks.splice(index, 1)
166
+ return true
167
+ }
168
+ return false
169
+ }
170
+ }`)
171
+
172
+ await this.waitForEnter("\nPresiona Enter para ver TaskManager...")
173
+
174
+ console.log("\n// Implementación de TaskManager")
175
+ console.log(`class TaskManager {
176
+ constructor(storage) {
177
+ this.storage = storage
178
+ this.nextId = 1
179
+ }
180
+
181
+ createTask(title, description) {
182
+ const task = new Task(this.nextId++, title, description)
183
+ this.storage.save(task)
184
+ return task
185
+ }
186
+
187
+ getAllTasks() {
188
+ return this.storage.findAll()
189
+ }
190
+
191
+ completeTask(taskId) {
192
+ const tasks = this.storage.findAll()
193
+ const task = tasks.find(t => t.id === taskId)
194
+ if (task) {
195
+ task.markCompleted()
196
+ return true
197
+ }
198
+ return false
199
+ }
200
+
201
+ deleteTask(taskId) {
202
+ return this.storage.remove(taskId)
203
+ }
204
+ }`)
205
+
206
+ await this.waitForEnter("\n✅ Implementación completa. Presiona Enter para probar la interacción...")
207
+ }
208
+
209
+ async step4_TestInteraction() {
210
+ console.clear()
211
+ console.log("🧪 PASO 4: Probar la Interacción entre Objetos")
212
+ console.log("=" .repeat(45))
213
+ console.log("Veamos cómo los objetos colaboran usando sus interfaces:")
214
+
215
+ console.log("\n// Crear el sistema")
216
+ console.log("const storage = new TaskStorage()")
217
+ console.log("const manager = new TaskManager(storage)")
218
+ console.log("")
219
+ console.log("// Los objetos interactúan a través de solicitudes")
220
+ console.log("const task1 = manager.createTask('Estudiar OOP', 'Completar lección 6')")
221
+ console.log("const task2 = manager.createTask('Practicar código', 'Implementar sistema de tareas')")
222
+ console.log("")
223
+ console.log("// Cada solicitud respeta la interfaz definida")
224
+ console.log("manager.completeTask(task1.id)")
225
+ console.log("const allTasks = manager.getAllTasks()")
226
+ console.log("")
227
+ console.log("allTasks.forEach(task => {")
228
+ console.log(" const info = task.getInfo() // Solicitud a Task")
229
+ console.log(" console.log(`${info.title}: ${info.completed ? '✅' : '❌'}`)")
230
+ console.log("})")
231
+
232
+ console.log("\n🎯 Resultado esperado:")
233
+ console.log("Estudiar OOP: ✅")
234
+ console.log("Practicar código: ❌")
235
+
236
+ await this.waitForEnter("\nPresiona Enter para ver los beneficios de este enfoque...")
237
+
238
+ console.clear()
239
+ console.log("🌟 BENEFICIOS DEL DISEÑO INTERFACE-FIRST")
240
+ console.log("=" .repeat(45))
241
+ console.log("1. 🎯 Claridad: Cada objeto tiene responsabilidades bien definidas")
242
+ console.log("2. 🔗 Colaboración: Los objetos saben exactamente cómo solicitar operaciones")
243
+ console.log("3. 🔄 Flexibilidad: Podemos cambiar TaskStorage por DatabaseStorage sin afectar TaskManager")
244
+ console.log("4. 🧪 Testeable: Podemos crear mocks fácilmente para testing")
245
+ console.log("5. 📚 Mantenible: Las interfaces documentan el contrato de cada objeto")
246
+
247
+ console.log("\n💡 Ejemplo de extensibilidad:")
248
+ console.log("// Podemos cambiar el storage sin modificar TaskManager")
249
+ console.log("class DatabaseStorage {")
250
+ console.log(" save(task) { /* guardar en BD */ }")
251
+ console.log(" findAll() { /* consultar BD */ }")
252
+ console.log(" remove(taskId) { /* eliminar de BD */ }")
253
+ console.log("}")
254
+ console.log("")
255
+ console.log("// TaskManager sigue funcionando igual!")
256
+ console.log("const dbStorage = new DatabaseStorage()")
257
+ console.log("const manager = new TaskManager(dbStorage)")
258
+
259
+ await this.waitForEnter("\nPresiona Enter para continuar con la conclusión...")
260
+ }
261
+
262
+ async conclusion() {
263
+ console.clear()
264
+ console.log("🎓 CONCLUSIÓN: Diseño basado en Interfaces")
265
+ console.log("=" .repeat(45))
266
+ console.log("🎯 Hemos demostrado que:")
267
+ console.log("\n1. El ÉNFASIS debe estar en definir QUÉ solicitudes maneja cada objeto")
268
+ console.log("2. Las INTERFACES especifican cómo hacer estas solicitudes")
269
+ console.log("3. La IMPLEMENTACIÓN viene después, siguiendo el contrato")
270
+ console.log("4. Los objetos COLABORAN a través de estas interfaces bien definidas")
271
+
272
+ console.log("\n📚 Conexión con lecciones anteriores:")
273
+ console.log("• Lección 2: Los objetos interactúan a través de solicitudes ✓")
274
+ console.log("• Lección 3: Las solicitudes son la única forma de ejecutar operaciones ✓")
275
+ console.log("• Lección 4: Cada operación tiene nombre, insumos y valor de retorno ✓")
276
+ console.log("• Lección 5: La interfaz es el conjunto de todas las firmas ✓")
277
+ console.log("• Lección 6: El énfasis está en definir solicitudes e interfaces ✓")
278
+
279
+ console.log("\n🚀 Próximo paso:")
280
+ console.log("Practica este enfoque en tus propios proyectos:")
281
+ console.log("1. Define primero QUÉ debe hacer cada objeto")
282
+ console.log("2. Especifica las interfaces (firmas de operación)")
283
+ console.log("3. Implementa respetando esos contratos")
284
+ console.log("4. Haz que los objetos colaboren a través de solicitudes")
285
+
286
+ console.log("\n💭 Reflexión final:")
287
+ console.log("¿Cómo cambiaría tu forma de programar si siempre empezaras")
288
+ console.log("definiendo las interfaces antes de la implementación?")
289
+
290
+ await this.waitForEnter("\n✨ ¡Lección 6 completada! Presiona Enter para salir...")
291
+ }
292
+
293
+ async waitForEnter(message) {
294
+ return new Promise((resolve) => {
295
+ this.rl.question(message, () => {
296
+ resolve()
297
+ })
298
+ })
299
+ }
300
+ }
301
+
302
+ // Para usar la lección independientemente
303
+ if (import.meta.url === `file://${process.argv[1]}`) {
304
+ const lesson = new Lesson6InterfaceDesign()
305
+ await lesson.start()
306
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@icarusmx/creta",
3
- "version": "0.8.1",
3
+ "version": "0.9.0",
4
4
  "description": "Salgamos de este laberinto.",
5
5
  "type": "module",
6
6
  "bin": {