@icarusmx/creta 1.4.10 → 1.4.12

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.
package/lib/data/menus.js CHANGED
@@ -2,15 +2,43 @@ import { ENUNCIADOS } from './enunciados.js'
2
2
  import { UNLOCK_CONFIG, isUnlocked, hasCompletedLesson } from './progression.js'
3
3
  import { UserState } from '../utils/user-state.js'
4
4
 
5
- export const SINTAXIS_MENU_CONFIG = {
6
- title: 'Elige qué lección de sintaxis te gustaría explorar:',
7
- description: 'Aprende los comandos fundamentales de terminal y git.',
8
- options: [
9
- { id: 'terminal-basico', title: '1. Terminal básico', description: 'ls, cd, mkdir' },
10
- { id: 'git-basico', title: '2. Git básico', description: 'init, status, add, commit' },
11
- { id: 'bash-scripts', title: '3. Bash Scripts', description: 'variables, sed, condicionales' },
12
- { id: 'piping-redireccion', title: '4. Piping y Redirección', description: '|, >, <, <<<' }
13
- ]
5
+ export const SINTAXIS_LESSONS = [
6
+ {
7
+ id: 'terminal-basico',
8
+ title: '1. Terminal básico',
9
+ description: '',
10
+ unlockAfter: null
11
+ },
12
+ {
13
+ id: 'git-basico',
14
+ title: '2. Git básico',
15
+ description: '',
16
+ unlockAfter: 'terminal-basico'
17
+ },
18
+ {
19
+ id: 'piping-redireccion',
20
+ title: '3. Piping y Redirección',
21
+ description: '',
22
+ unlockAfter: 'git-basico'
23
+ },
24
+ {
25
+ id: 'bash-scripts',
26
+ title: '4. Bash Scripts',
27
+ description: '',
28
+ unlockAfter: 'piping-redireccion'
29
+ }
30
+ ]
31
+
32
+ export function getSintaxisMenuConfig(state = UserState.get()) {
33
+ const options = SINTAXIS_LESSONS
34
+ .filter((lesson) => !lesson.unlockAfter || hasCompletedLesson(lesson.unlockAfter, state))
35
+ .map(({ id, title, description }) => ({ id, title, description }))
36
+
37
+ return {
38
+ title: 'Elige qué lección de sintaxis te gustaría explorar:',
39
+ description: 'Aprende los comandos fundamentales de terminal y git.',
40
+ options
41
+ }
14
42
  }
15
43
 
16
44
  const MENU_ITEMS = {
@@ -19,14 +47,13 @@ const MENU_ITEMS = {
19
47
  proyectos: { baseTitle: 'Construir proyectos' }
20
48
  }
21
49
 
22
- export function getMainMenuConfig() {
23
- const state = UserState.get()
50
+ export function getMainMenuConfig(state = UserState.get()) {
24
51
  const options = []
25
52
 
26
53
  for (const [id, itemConfig] of Object.entries(MENU_ITEMS)) {
27
54
  const unlockConfig = UNLOCK_CONFIG.mainMenu[id]
28
55
 
29
- if (!isUnlocked(id, unlockConfig)) continue
56
+ if (!isUnlocked(id, unlockConfig, state)) continue
30
57
 
31
58
  const showNew = typeof unlockConfig.showNewIndicator === 'function'
32
59
  ? unlockConfig.showNewIndicator(state)
@@ -45,7 +72,9 @@ export function getMainMenuConfig() {
45
72
 
46
73
  return {
47
74
  clearConsole: false,
48
- title: 'Te ofrecemos las siguientes opciones:',
75
+ title: options.length === 1
76
+ ? 'Empecemos por aquí:'
77
+ : 'Te ofrecemos las siguientes opciones:',
49
78
  options
50
79
  }
51
80
  }
@@ -1,9 +1,9 @@
1
1
  // Centralized progression and unlock logic
2
2
  import { UserState } from '../utils/user-state.js'
3
3
 
4
- export function hasCompletedLesson(lessonId) {
5
- const state = UserState.get()
6
- return state.lessonsCompleted.some(
4
+ export function hasCompletedLesson(lessonId, state = UserState.get()) {
5
+ const lessonsCompleted = state?.lessonsCompleted || []
6
+ return lessonsCompleted.some(
7
7
  lesson => typeof lesson === 'object' ? lesson.id === lessonId : lesson === lessonId
8
8
  )
9
9
  }
@@ -14,9 +14,9 @@ export const UNLOCK_CONFIG = {
14
14
  sintaxis: {
15
15
  alwaysVisible: true,
16
16
  showNewIndicator: (state) =>
17
- hasCompletedLesson('terminal-basico') && !hasCompletedLesson('git-basico'),
17
+ hasCompletedLesson('terminal-basico', state) && !hasCompletedLesson('git-basico', state),
18
18
  description: (state) =>
19
- hasCompletedLesson('terminal-basico') && !hasCompletedLesson('git-basico')
19
+ hasCompletedLesson('terminal-basico', state) && !hasCompletedLesson('git-basico', state)
20
20
  ? 'Git básico desbloqueado'
21
21
  : undefined
22
22
  },
@@ -33,12 +33,12 @@ export const UNLOCK_CONFIG = {
33
33
  },
34
34
  sintaxis: {
35
35
  directToLesson: (state) =>
36
- !hasCompletedLesson('terminal-basico') ? 'terminal-basico' : null
36
+ !hasCompletedLesson('terminal-basico', state) ? 'terminal-basico' : null
37
37
  }
38
38
  }
39
39
 
40
- export function isUnlocked(itemKey, config) {
40
+ export function isUnlocked(itemKey, config, state = UserState.get()) {
41
41
  if (config.alwaysVisible) return true
42
42
  if (!config.unlockAfter) return true
43
- return hasCompletedLesson(config.unlockAfter)
43
+ return hasCompletedLesson(config.unlockAfter, state)
44
44
  }
@@ -1,5 +1,5 @@
1
1
  import { MenuBuilder } from '../builders/MenuBuilder.js'
2
- import { SINTAXIS_MENU_CONFIG } from '../data/menus.js'
2
+ import { getSintaxisMenuConfig, SINTAXIS_LESSONS } from '../data/menus.js'
3
3
  import { LessonBuilder } from '../builders/LessonBuilder.js'
4
4
  import { TERMINAL_BASICO } from '../data/lessons/sintaxis/terminal-basico.js'
5
5
  import { GIT_BASICO } from '../data/lessons/sintaxis/git-basico.js'
@@ -53,18 +53,30 @@ export async function executeSintaxis() {
53
53
  const directLesson = UNLOCK_CONFIG.sintaxis.directToLesson(state)
54
54
 
55
55
  if (directLesson) {
56
- await runLesson(directLesson, 'Terminal básico')
56
+ const lessonMeta = SINTAXIS_LESSONS.find((lesson) => lesson.id === directLesson)
57
+ const lessonTitle = lessonMeta?.title || 'Lección de sintaxis'
58
+
59
+ await runLesson(directLesson, lessonTitle)
60
+
61
+ const nextLesson = SINTAXIS_LESSONS.find((lesson) => lesson.unlockAfter === directLesson)
62
+ if (nextLesson) {
63
+ console.log(`\n✨ ${nextLesson.title} desbloqueado.`)
64
+ console.log(' Vuelve al menú de sintaxis para explorarlo.')
65
+ }
57
66
 
58
- // After completing, show what was unlocked
59
- console.log('\n✨ Ahora puedes acceder al menú de sintaxis para aprender Git básico')
60
67
  await waitForEnter()
61
68
  return
62
69
  }
63
70
 
64
- // Show menu
65
- const menu = new MenuBuilder(SINTAXIS_MENU_CONFIG)
66
-
67
71
  while (true) {
72
+ const menuConfig = getSintaxisMenuConfig()
73
+
74
+ if (menuConfig.options.length === 0) {
75
+ console.log('\nPor ahora no hay lecciones disponibles en este camino.')
76
+ return
77
+ }
78
+
79
+ const menu = new MenuBuilder(menuConfig)
68
80
  const choice = await menu.show()
69
81
  if (!choice) {
70
82
  return
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@icarusmx/creta",
3
- "version": "1.4.10",
3
+ "version": "1.4.12",
4
4
  "description": "Salgamos de este laberinto.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -0,0 +1,45 @@
1
+ import assert from 'node:assert/strict'
2
+ import test from 'node:test'
3
+
4
+ import { getSintaxisMenuConfig, getMainMenuConfig } from '../lib/data/menus.js'
5
+
6
+ const baseState = {
7
+ lessonsCompleted: []
8
+ }
9
+
10
+ test('sintaxis menu shows only terminal básico for new users', () => {
11
+ const menu = getSintaxisMenuConfig(baseState)
12
+ assert.equal(menu.options.length, 1)
13
+ assert.equal(menu.options[0].id, 'terminal-basico')
14
+ })
15
+
16
+ test('sintaxis menu unlocks git básico after completing terminal básico', () => {
17
+ const state = {
18
+ lessonsCompleted: [{ id: 'terminal-basico' }]
19
+ }
20
+ const menu = getSintaxisMenuConfig(state)
21
+ assert.equal(menu.options.length, 2)
22
+ assert.deepEqual(menu.options.map(option => option.id), ['terminal-basico', 'git-basico'])
23
+ })
24
+
25
+ test('sintaxis menu unlocks bash scripts after completing git básico', () => {
26
+ const state = {
27
+ lessonsCompleted: [
28
+ { id: 'terminal-basico' },
29
+ { id: 'git-basico' }
30
+ ]
31
+ }
32
+ const menu = getSintaxisMenuConfig(state)
33
+ assert.equal(menu.options.length, 3)
34
+ assert.deepEqual(menu.options.map(option => option.id), ['terminal-basico', 'git-basico', 'bash-scripts'])
35
+ })
36
+
37
+ test('main menu title changes when only one option is available', () => {
38
+ const config = getMainMenuConfig({ lessonsCompleted: [] })
39
+ assert.equal(config.title, 'Empecemos por aquí:')
40
+ })
41
+
42
+ test('main menu title defaults once multiple options unlock', () => {
43
+ const config = getMainMenuConfig({ lessonsCompleted: [{ id: 'terminal-basico' }] })
44
+ assert.equal(config.title, 'Te ofrecemos las siguientes opciones:')
45
+ })