@icarusmx/creta 1.0.23 → 1.1.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.
@@ -7,7 +7,8 @@
7
7
  "Bash(npm install)",
8
8
  "Bash(npm run dev:*)",
9
9
  "Bash(rm:*)",
10
- "Bash(npm publish:*)"
10
+ "Bash(npm publish:*)",
11
+ "Bash(npm view:*)"
11
12
  ],
12
13
  "deny": [],
13
14
  "ask": []
package/bin/creta.js CHANGED
@@ -12,6 +12,7 @@ import { Lesson3OnlyWay } from '../lessons/lesson3-only-way.js'
12
12
  import { Lesson4OperationSignatures } from '../lessons/lesson4-operation-signatures.js'
13
13
  import { Lesson5InterfaceSet } from '../lessons/lesson5-interface-set.js'
14
14
  import { Lesson6InterfaceDesign } from '../lessons/lesson6-interface-design.js'
15
+ import { Lesson7ObjectDefinition } from '../lessons/lesson7-object-definition.js'
15
16
 
16
17
  const ENUNCIADOS = [
17
18
  {
@@ -49,6 +50,12 @@ const ENUNCIADOS = [
49
50
  texto: "El énfasis al diseñar los objetos debe estar en la definición de sus solicitudes e interfaces.",
50
51
  nivel: "Diseño",
51
52
  enfoque: "Metodología de desarrollo"
53
+ },
54
+ {
55
+ id: 7,
56
+ texto: "Un objeto es un conjunto de datos y procedimientos que operan sobre esos datos.",
57
+ nivel: "Definición",
58
+ enfoque: "Naturaleza del objeto"
52
59
  }
53
60
  ]
54
61
 
@@ -579,8 +586,8 @@ async function unstuckProject(level) {
579
586
 
580
587
  function showHelp() {
581
588
  console.log("\n📚 Comandos disponibles:")
582
- console.log(" creta - Explora los 6 enunciados fundamentales (comando principal) 🧠")
583
- console.log(" creta enunciados - Explora los 6 enunciados fundamentales 🧠")
589
+ console.log(" creta - Explora los 7 enunciados fundamentales (comando principal) 🧠")
590
+ console.log(" creta enunciados - Explora los 7 enunciados fundamentales 🧠")
584
591
  console.log(" creta portafolio - Crea tu portafolio personal (reto completo)")
585
592
  console.log(" creta portafolio-1 - Desbloquea nivel 1 (navbar) 🔓")
586
593
  console.log(" creta portafolio-2 - Desbloquea nivel 2 (navbar + hero) 🔓")
@@ -822,8 +829,8 @@ async function startEnunciadosSelectorInteractive() {
822
829
  let formattedText = enunciado.texto
823
830
  if (enunciado.id === 4) {
824
831
  // Special formatting for enunciado 4 with list items
825
- formattedText = formattedText.replace(/\n([abc])\)/g, '\n $1)')
826
- formattedText = formattedText.replace(/\n\nEstos tres elementos/g, '\n\n Estos tres elementos')
832
+ formattedText = formattedText.replace(/\n([abc])\)/g, '\n $1)')
833
+ formattedText = formattedText.replace(/\n\nEstos tres elementos/g, '\n\n Estos tres elementos')
827
834
  }
828
835
  console.log(`${highlight}${prefix}${index + 1}. ${formattedText}${reset}`)
829
836
  console.log("")
@@ -965,6 +972,22 @@ async function startEnunciadosSelectorInteractive() {
965
972
  console.log("- Proyectos específicos para internalizar la idea")
966
973
  await returnToMainMenu()
967
974
  }
975
+ } else if (enunciadoSeleccionado.id === 7) {
976
+ console.log(`${enunciadoSeleccionado.texto}`)
977
+ await new Promise(resolve => setTimeout(resolve, 1500)) // Brief pause
978
+
979
+ try {
980
+ const lesson7 = new Lesson7ObjectDefinition()
981
+ await lesson7.start()
982
+ await returnToMainMenu()
983
+ } catch (error) {
984
+ console.error("\n❌ Error al ejecutar la lección:", error.message)
985
+ console.log("\n🚀 Próximamente:")
986
+ console.log("- Sesiones de estudio dirigidas basadas en este enunciado")
987
+ console.log("- Ejercicios prácticos que ilustren el concepto")
988
+ console.log("- Proyectos específicos para internalizar la idea")
989
+ await returnToMainMenu()
990
+ }
968
991
  } else {
969
992
  console.log("\n🚀 Próximamente:")
970
993
  console.log("- Sesiones de estudio dirigidas basadas en este enunciado")
@@ -1028,7 +1051,7 @@ async function startEnunciadosSelectorFallback() {
1028
1051
  console.log("")
1029
1052
  })
1030
1053
 
1031
- const respuesta = await askQuestion("Elige un número (1-6) o 'q' para salir: ")
1054
+ const respuesta = await askQuestion("Elige un número (1-7) o 'q' para salir: ")
1032
1055
 
1033
1056
  if (respuesta.toLowerCase() === 'q') {
1034
1057
  console.log("¡Hasta la vista! 👋")
@@ -1038,7 +1061,7 @@ async function startEnunciadosSelectorFallback() {
1038
1061
 
1039
1062
  const numeroSeleccionado = parseInt(respuesta)
1040
1063
 
1041
- if (numeroSeleccionado >= 1 && numeroSeleccionado <= 6) {
1064
+ if (numeroSeleccionado >= 1 && numeroSeleccionado <= 7) {
1042
1065
  const enunciadoSeleccionado = ENUNCIADOS[numeroSeleccionado - 1]
1043
1066
 
1044
1067
  // Check if we have a lesson implementation for this enunciado
@@ -1154,6 +1177,22 @@ async function startEnunciadosSelectorFallback() {
1154
1177
  console.log("- Proyectos específicos para internalizar la idea")
1155
1178
  }
1156
1179
  return
1180
+ } else if (enunciadoSeleccionado.id === 7) {
1181
+ console.log(`${enunciadoSeleccionado.texto}`)
1182
+ rl.close()
1183
+ await new Promise(resolve => setTimeout(resolve, 1500)) // Brief pause
1184
+
1185
+ try {
1186
+ const lesson7 = new Lesson7ObjectDefinition()
1187
+ await lesson7.start()
1188
+ } catch (error) {
1189
+ console.error("\n❌ Error al ejecutar la lección:", error.message)
1190
+ console.log("\n🚀 Próximamente:")
1191
+ console.log("- Sesiones de estudio dirigidas basadas en este enunciado")
1192
+ console.log("- Ejercicios prácticos que ilustren el concepto")
1193
+ console.log("- Proyectos específicos para internalizar la idea")
1194
+ }
1195
+ return
1157
1196
  } else {
1158
1197
  console.log("\n🚀 Próximamente:")
1159
1198
  console.log("- Sesiones de estudio dirigidas basadas en este enunciado")
@@ -1165,7 +1204,7 @@ async function startEnunciadosSelectorFallback() {
1165
1204
  }
1166
1205
 
1167
1206
  } else {
1168
- console.log("❌ Opción no válida. Elige un número entre 1 y 6.")
1207
+ console.log("❌ Opción no válida. Elige un número entre 1 y 7.")
1169
1208
  }
1170
1209
 
1171
1210
  rl.close()
@@ -0,0 +1,393 @@
1
+ #!/usr/bin/env node
2
+
3
+ // LECCIÓN 7: Un objeto es un conjunto de datos y procedimientos que operan sobre esos datos
4
+ // Enfoque práctico: Comparación entre código procedural vs orientado a objetos
5
+
6
+ import { createInterface } from 'readline'
7
+
8
+ export class Lesson7ObjectDefinition {
9
+ constructor() {
10
+ this.rl = createInterface({
11
+ input: process.stdin,
12
+ output: process.stdout
13
+ })
14
+ }
15
+
16
+ async start() {
17
+ await this.waitForEnter("\nPresiona Enter para comenzar...")
18
+
19
+ await this.practicalExercise()
20
+ await this.conclusion()
21
+
22
+ this.rl.close()
23
+ }
24
+
25
+ async practicalExercise() {
26
+ console.clear()
27
+ console.log("Exploraremos qué ES un objeto comparando dos enfoques:")
28
+ console.log("1. Datos separados + funciones sueltas")
29
+ console.log("2. Objeto = datos + procedimientos unidos")
30
+
31
+ await this.waitForEnter("\nPresiona Enter para continuar...")
32
+
33
+ await this.step1_ProceduralApproach()
34
+ await this.step2_ObjectOrientedApproach()
35
+ await this.step3_ComparisonAndBenefits()
36
+ }
37
+
38
+ async step1_ProceduralApproach() {
39
+ console.clear()
40
+ console.log("🔧 Enfoque Procedural: Datos Separados")
41
+ console.log("=" .repeat(50))
42
+
43
+ console.log("\n💳 Ejemplo: Sistema de Cuenta Bancaria")
44
+ console.log("\n📊 Datos sueltos:")
45
+
46
+ const dataCode = `// Datos de la cuenta
47
+ let accountNumber = "001-234567"
48
+ let ownerName = "María González"
49
+ let balance = 5000
50
+ let isActive = true`
51
+
52
+ this.printCodeWithColors("Variables globales", dataCode)
53
+
54
+ await this.waitForEnter("\nPresiona Enter para ver las funciones...")
55
+
56
+ console.log("\n⚙️ Funciones separadas que operan sobre esos datos:")
57
+
58
+ const functionsCode = `function deposit(amount) {
59
+ if (!isActive) {
60
+ console.log("Cuenta inactiva")
61
+ return false
62
+ }
63
+ if (amount <= 0) {
64
+ console.log("Cantidad inválida")
65
+ return false
66
+ }
67
+ balance += amount
68
+ return true
69
+ }
70
+
71
+ function withdraw(amount) {
72
+ if (!isActive) return false
73
+ if (amount <= 0) return false
74
+ if (amount > balance) {
75
+ console.log("Fondos insuficientes")
76
+ return false
77
+ }
78
+ balance -= amount
79
+ return true
80
+ }
81
+
82
+ function getBalance() {
83
+ return isActive ? balance : 0
84
+ }
85
+
86
+ function deactivate() {
87
+ isActive = false
88
+ }`
89
+
90
+ this.printCodeWithColors("Funciones sueltas", functionsCode)
91
+
92
+ await this.waitForEnter("\nPresiona Enter para ver el problema...")
93
+
94
+ console.clear()
95
+ console.log("❌ Problemas del enfoque procedural:")
96
+ console.log("=" .repeat(50))
97
+
98
+ console.log("\n1️⃣ Datos expuestos globalmente:")
99
+ console.log(" • Cualquier código puede modificar 'balance' directamente")
100
+ console.log(" • No hay protección de los datos")
101
+
102
+ console.log("\n2️⃣ Funciones no están vinculadas a datos:")
103
+ console.log(" • deposit() asume que 'balance' existe")
104
+ console.log(" • ¿Qué pasa si necesitamos múltiples cuentas?")
105
+
106
+ console.log("\n3️⃣ Difícil de escalar:")
107
+
108
+ const problemCode = `// ¿Cómo manejamos dos cuentas?
109
+ let balance1 = 5000
110
+ let balance2 = 3000
111
+ let accountNumber1 = "001"
112
+ let accountNumber2 = "002"
113
+
114
+ // Las funciones solo trabajan con una cuenta
115
+ deposit(100) // ¿A cuál cuenta?`
116
+
117
+ this.printCodeWithColors("Escalabilidad problemática", problemCode)
118
+
119
+ await this.waitForEnter("\nPresiona Enter para ver la solución...")
120
+ }
121
+
122
+ async step2_ObjectOrientedApproach() {
123
+ console.clear()
124
+ console.log("✨ Enfoque Orientado a Objetos: Datos + Procedimientos")
125
+ console.log("=" .repeat(50))
126
+
127
+ console.log("\n💡 Un objeto AGRUPA datos y procedimientos")
128
+ console.log("Los datos se convierten en PROPIEDADES")
129
+ console.log("Los procedimientos se convierten en MÉTODOS")
130
+
131
+ await this.waitForEnter("\nPresiona Enter para ver el código...")
132
+
133
+ const objectCode = `class BankAccount {
134
+ // Constructor: inicializa los DATOS del objeto
135
+ constructor(accountNumber, ownerName, initialBalance) {
136
+ this.accountNumber = accountNumber
137
+ this.ownerName = ownerName
138
+ this.balance = initialBalance
139
+ this.isActive = true
140
+ }
141
+
142
+ // PROCEDIMIENTOS que operan sobre ESTOS datos específicos
143
+ deposit(amount) {
144
+ if (!this.isActive) {
145
+ console.log("Cuenta inactiva")
146
+ return false
147
+ }
148
+ if (amount <= 0) {
149
+ console.log("Cantidad inválida")
150
+ return false
151
+ }
152
+ this.balance += amount
153
+ return true
154
+ }
155
+
156
+ withdraw(amount) {
157
+ if (!this.isActive) return false
158
+ if (amount <= 0) return false
159
+ if (amount > this.balance) {
160
+ console.log("Fondos insuficientes")
161
+ return false
162
+ }
163
+ this.balance -= amount
164
+ return true
165
+ }
166
+
167
+ getBalance() {
168
+ return this.isActive ? this.balance : 0
169
+ }
170
+
171
+ deactivate() {
172
+ this.isActive = false
173
+ }
174
+
175
+ getAccountInfo() {
176
+ return {
177
+ number: this.accountNumber,
178
+ owner: this.ownerName,
179
+ balance: this.getBalance(),
180
+ status: this.isActive ? 'Activa' : 'Inactiva'
181
+ }
182
+ }
183
+ }`
184
+
185
+ this.printCodeWithColors("Clase BankAccount", objectCode)
186
+
187
+ await this.waitForEnter("\nPresiona Enter para ver múltiples instancias...")
188
+
189
+ console.clear()
190
+ console.log("🎯 Múltiples objetos = Múltiples conjuntos de datos")
191
+ console.log("=" .repeat(50))
192
+
193
+ const usageCode = `// Crear múltiples cuentas es simple
194
+ const account1 = new BankAccount("001-234567", "María González", 5000)
195
+ const account2 = new BankAccount("001-789012", "Juan Pérez", 3000)
196
+
197
+ // Cada objeto tiene SUS PROPIOS datos
198
+ account1.deposit(500)
199
+ account2.withdraw(200)
200
+
201
+ console.log(account1.getBalance()) // 5500
202
+ console.log(account2.getBalance()) // 2800
203
+
204
+ // Los procedimientos operan sobre los datos del objeto específico
205
+ account1.deactivate()
206
+ console.log(account1.isActive) // false
207
+ console.log(account2.isActive) // true ← No afectado`
208
+
209
+ this.printCodeWithColors("Uso del objeto", usageCode)
210
+
211
+ await this.waitForEnter("\nPresiona Enter para ver las ventajas...")
212
+ }
213
+
214
+ async step3_ComparisonAndBenefits() {
215
+ console.clear()
216
+ console.log("📊 Comparación Directa")
217
+ console.log("=" .repeat(50))
218
+
219
+ console.log("\n🔴 Enfoque Procedural:")
220
+ console.log(" Datos: let balance = 5000")
221
+ console.log(" Procedimiento: function deposit(amount) { balance += amount }")
222
+ console.log(" ❌ Separados, sin relación formal")
223
+
224
+ console.log("\n🟢 Enfoque Orientado a Objetos:")
225
+ console.log(" Datos: this.balance = 5000")
226
+ console.log(" Procedimiento: deposit(amount) { this.balance += amount }")
227
+ console.log(" ✅ Unidos en el MISMO objeto")
228
+
229
+ await this.waitForEnter("\nPresiona Enter para ver ejemplo visual...")
230
+
231
+ console.clear()
232
+ console.log("🎨 Visualización del Concepto")
233
+ console.log("=" .repeat(50))
234
+
235
+ console.log("\n┌─────────────────────────────────────┐")
236
+ console.log("│ OBJETO: account1 │")
237
+ console.log("├─────────────────────────────────────┤")
238
+ console.log("│ DATOS: │")
239
+ console.log("│ • accountNumber = \"001-234567\" │")
240
+ console.log("│ • ownerName = \"María González\" │")
241
+ console.log("│ • balance = 5000 │")
242
+ console.log("│ • isActive = true │")
243
+ console.log("├─────────────────────────────────────┤")
244
+ console.log("│ PROCEDIMIENTOS: │")
245
+ console.log("│ • deposit(amount) │")
246
+ console.log("│ • withdraw(amount) │")
247
+ console.log("│ • getBalance() │")
248
+ console.log("│ • deactivate() │")
249
+ console.log("└─────────────────────────────────────┘")
250
+
251
+ console.log("\n📌 Nota clave:")
252
+ console.log("Los procedimientos SOLO operan sobre los datos de ESTE objeto")
253
+ console.log("account1.deposit() modifica account1.balance")
254
+ console.log("account2.deposit() modifica account2.balance")
255
+
256
+ await this.waitForEnter("\nPresiona Enter para ver otro ejemplo...")
257
+
258
+ console.clear()
259
+ console.log("🎮 Ejemplo 2: Sistema de Carrito de Compras")
260
+ console.log("=" .repeat(50))
261
+
262
+ const cartCode = `class ShoppingCart {
263
+ // DATOS del carrito
264
+ constructor(userId) {
265
+ this.userId = userId
266
+ this.items = []
267
+ this.totalAmount = 0
268
+ }
269
+
270
+ // PROCEDIMIENTOS que operan sobre estos datos
271
+ addItem(product, quantity) {
272
+ const item = { product, quantity, price: product.price * quantity }
273
+ this.items.push(item)
274
+ this.totalAmount += item.price
275
+ }
276
+
277
+ removeItem(productId) {
278
+ const itemIndex = this.items.findIndex(i => i.product.id === productId)
279
+ if (itemIndex > -1) {
280
+ this.totalAmount -= this.items[itemIndex].price
281
+ this.items.splice(itemIndex, 1)
282
+ }
283
+ }
284
+
285
+ getTotal() {
286
+ return this.totalAmount
287
+ }
288
+
289
+ getItemCount() {
290
+ return this.items.reduce((sum, item) => sum + item.quantity, 0)
291
+ }
292
+
293
+ clear() {
294
+ this.items = []
295
+ this.totalAmount = 0
296
+ }
297
+ }
298
+
299
+ // Uso
300
+ const cart = new ShoppingCart("user123")
301
+ cart.addItem({ id: 1, name: "Libro", price: 299 }, 2)
302
+ cart.addItem({ id: 2, name: "Café", price: 85 }, 1)
303
+
304
+ console.log(cart.getTotal()) // 683
305
+ console.log(cart.getItemCount()) // 3`
306
+
307
+ this.printCodeWithColors("Clase ShoppingCart", cartCode)
308
+
309
+ await this.waitForEnter("\nPresiona Enter para la conclusión...")
310
+ }
311
+
312
+ async conclusion() {
313
+ console.clear()
314
+ console.log("🎓 Conclusión: Definición del Objeto")
315
+ console.log("=" .repeat(50))
316
+
317
+ console.log("\n💎 Enunciado fundamental:")
318
+ console.log("'Un objeto es un conjunto de datos y procedimientos")
319
+ console.log(" que operan sobre esos datos'")
320
+
321
+ console.log("\n🔍 Desglose:")
322
+ console.log("1️⃣ CONJUNTO → agrupación unificada")
323
+ console.log("2️⃣ DATOS → propiedades del objeto (this.property)")
324
+ console.log("3️⃣ PROCEDIMIENTOS → métodos del objeto")
325
+ console.log("4️⃣ OPERAN SOBRE → los métodos modifican/leen las propiedades")
326
+
327
+ console.log("\n✅ Ventajas demostradas:")
328
+ console.log("• Encapsulación: datos y operaciones juntos")
329
+ console.log("• Modularidad: cada objeto es independiente")
330
+ console.log("• Escalabilidad: múltiples instancias fácilmente")
331
+ console.log("• Organización: responsabilidades claras")
332
+
333
+ console.log("\n📚 Ejemplos vistos:")
334
+ console.log("• BankAccount: balance + deposit/withdraw")
335
+ console.log("• ShoppingCart: items + addItem/removeItem")
336
+
337
+ console.log("\n🔗 Conexión con otros enunciados:")
338
+ console.log("• Enunciado 1: Estos objetos son los que descomponemos del sistema")
339
+ console.log("• Enunciado 2: Estos objetos interactúan mediante solicitudes")
340
+ console.log("• Enunciado 5: La interfaz expone los procedimientos disponibles")
341
+
342
+ console.log("\n💭 Reflexión:")
343
+ console.log("Antes de diseñar cómo los objetos interactúan,")
344
+ console.log("debemos entender QUÉ ES un objeto:")
345
+ console.log("datos + procedimientos, unidos e inseparables.")
346
+
347
+ await this.waitForEnter("\n✨ ¡Lección 7 completada! Presiona Enter para continuar...")
348
+ }
349
+
350
+ formatCode(code) {
351
+ const colors = {
352
+ keyword: '\x1b[35m',
353
+ property: '\x1b[32m',
354
+ string: '\x1b[33m',
355
+ comment: '\x1b[90m',
356
+ reset: '\x1b[0m'
357
+ }
358
+
359
+ return code
360
+ .replace(/\b(class|constructor|return|if|const|let|new|function)\b/g, `${colors.keyword}$1${colors.reset}`)
361
+ .replace(/\bthis\./g, `${colors.property}this.${colors.reset}`)
362
+ .replace(/'([^']*)'/g, `${colors.string}'$1'${colors.reset}`)
363
+ .replace(/"([^"]*)"/g, `${colors.string}"$1"${colors.reset}`)
364
+ .replace(/\/\/.*$/gm, `${colors.comment}$&${colors.reset}`)
365
+ }
366
+
367
+ printCodeWithColors(title, code) {
368
+ console.log(`\n${title}`)
369
+ console.log("━".repeat(50))
370
+
371
+ code.split('\n').forEach(line => {
372
+ const formattedLine = this.formatCode(line)
373
+ console.log(formattedLine)
374
+ })
375
+
376
+ console.log("━".repeat(50))
377
+ }
378
+
379
+ async waitForEnter(message) {
380
+ return new Promise((resolve) => {
381
+ this.rl.question(message, () => {
382
+ console.log("\n\n")
383
+ resolve()
384
+ })
385
+ })
386
+ }
387
+ }
388
+
389
+ // Para usar la lección independientemente
390
+ if (import.meta.url === `file://${process.argv[1]}`) {
391
+ const lesson = new Lesson7ObjectDefinition()
392
+ await lesson.start()
393
+ }
package/package.json CHANGED
@@ -1,14 +1,22 @@
1
1
  {
2
2
  "name": "@icarusmx/creta",
3
- "version": "1.0.23",
3
+ "version": "1.1.0",
4
4
  "description": "Salgamos de este laberinto.",
5
5
  "type": "module",
6
6
  "bin": {
7
7
  "creta": "./bin/creta.js"
8
8
  },
9
- "keywords": ["cli", "icarus", "creta", "scythe", "software school"],
9
+ "keywords": [
10
+ "cli",
11
+ "icarus",
12
+ "creta",
13
+ "scythe",
14
+ "software school"
15
+ ],
10
16
  "author": "Guillermo Rodríguez López",
11
- "publishConfig": { "access": "public" },
17
+ "publishConfig": {
18
+ "access": "public"
19
+ },
12
20
  "license": "MIT",
13
21
  "dependencies": {
14
22
  "chalk": "^5.3.0",