@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.
- package/bin/creta.js +8 -1576
- package/codex-refactor.txt +13 -0
- package/lib/builders/LessonBuilder.js +228 -0
- package/lib/builders/MenuBuilder.js +154 -0
- package/lib/builders/ProjectBuilder.js +56 -0
- package/lib/cli/index.js +81 -0
- package/lib/commands/help.js +5 -0
- package/lib/constants/paths.js +9 -0
- package/lib/data/enunciados.js +44 -0
- package/lib/data/lessons/index.js +25 -0
- package/lib/data/lessons/lesson1-system-decomposition.js +312 -0
- package/lib/data/lessons/lesson2-object-requests.js +318 -0
- package/lib/data/lessons/lesson3-only-way.js +349 -0
- package/lib/data/lessons/lesson4-operation-signatures.js +332 -0
- package/lib/data/lessons/lesson5-interface-set.js +341 -0
- package/lib/data/lessons/lesson6-interface-design.js +407 -0
- package/lib/data/lessons/lesson7-object-definition.js +375 -0
- package/lib/data/lessons/sintaxis/terminal-basico.js +46 -0
- package/lib/data/menus.js +43 -0
- package/lib/data/messages.js +28 -0
- package/lib/executors/enunciados-executor.js +63 -0
- package/lib/executors/portfolio-executor.js +167 -0
- package/lib/executors/proyectos-executor.js +23 -0
- package/lib/executors/sintaxis-executor.js +7 -0
- package/lib/pr-tutorial.js +6 -0
- package/lib/templates/LevelModifier.js +287 -0
- package/lib/utils/file-utils.js +18 -0
- package/lib/utils/input.js +15 -0
- package/lib/utils/output.js +4 -0
- package/package.json +4 -1
- package/refactor.txt +581 -0
- package/test/enunciados.test.js +72 -0
- package/lessons/lesson1-system-decomposition.js +0 -313
- package/lessons/lesson2-object-requests.js +0 -309
- package/lessons/lesson3-only-way.js +0 -324
- package/lessons/lesson4-operation-signatures.js +0 -319
- package/lessons/lesson5-interface-set.js +0 -326
- package/lessons/lesson6-interface-design.js +0 -391
- package/lessons/lesson7-object-definition.js +0 -300
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# creta cli refactor - progress log
|
|
2
|
+
|
|
3
|
+
## 2025-02-14
|
|
4
|
+
- restored `bin/creta.js` to the original working version so the CLI behaved correctly again.
|
|
5
|
+
- extracted reusable data for the welcome banner, help text, and enunciados into `lib/data/messages.js` and `lib/data/enunciados.js`.
|
|
6
|
+
- added initial utilities (`lib/utils/input.js`, `lib/utils/output.js`, `lib/utils/file-utils.js`) plus `lib/templates/LevelModifier.js` to reuse template logic.
|
|
7
|
+
|
|
8
|
+
## 2025-02-15
|
|
9
|
+
- introduced Discord-style builders (`lib/builders/MenuBuilder.js`, `lib/builders/ProjectBuilder.js`).
|
|
10
|
+
- defined menu configurations in `lib/data/menus.js` and template paths in `lib/constants/paths.js`.
|
|
11
|
+
- created executors for enunciados, sintaxis, proyectos, and portafolio to encapsulate orchestration logic.
|
|
12
|
+
- added `lib/cli/index.js` as the central command router and reduced `bin/creta.js` to a minimal entry point (<20 lines).
|
|
13
|
+
- verified primary commands (`help`, `portafolio-*`, invalid command handling) after restructuring.
|
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
import { createPromptInterface, askQuestion } from '../utils/input.js'
|
|
2
|
+
import { clearConsole } from '../utils/output.js'
|
|
3
|
+
|
|
4
|
+
const DEFAULT_WAIT_MESSAGE = '\nPresiona Enter para continuar...'
|
|
5
|
+
|
|
6
|
+
export class LessonBuilder {
|
|
7
|
+
constructor(lessonData) {
|
|
8
|
+
this.lesson = lessonData
|
|
9
|
+
this.rl = null
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
async start() {
|
|
13
|
+
if (!this.lesson) {
|
|
14
|
+
throw new Error('Se requiere un objeto de lección para ejecutar el LessonBuilder')
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
this.rl = createPromptInterface()
|
|
18
|
+
|
|
19
|
+
try {
|
|
20
|
+
const flow = this.collectActions()
|
|
21
|
+
await this.executeActions(flow)
|
|
22
|
+
} finally {
|
|
23
|
+
this.rl.close()
|
|
24
|
+
this.rl = null
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
collectActions() {
|
|
29
|
+
const actions = []
|
|
30
|
+
|
|
31
|
+
const parts = [
|
|
32
|
+
this.lesson.title && { type: 'text', text: this.lesson.title },
|
|
33
|
+
this.lesson.subtitle && { type: 'text', text: this.lesson.subtitle },
|
|
34
|
+
this.lesson.intro && { type: 'intro', ...this.lesson.intro },
|
|
35
|
+
this.lesson.flow,
|
|
36
|
+
this.lesson.actions,
|
|
37
|
+
this.lesson.sections,
|
|
38
|
+
this.lesson.steps,
|
|
39
|
+
this.lesson.body,
|
|
40
|
+
this.lesson.conclusion
|
|
41
|
+
]
|
|
42
|
+
|
|
43
|
+
for (const part of parts) {
|
|
44
|
+
if (!part) continue
|
|
45
|
+
|
|
46
|
+
if (Array.isArray(part)) {
|
|
47
|
+
actions.push(...part)
|
|
48
|
+
} else if (Array.isArray(part.actions)) {
|
|
49
|
+
actions.push(...part.actions)
|
|
50
|
+
} else {
|
|
51
|
+
actions.push(part)
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
return actions
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
async executeActions(actions = []) {
|
|
59
|
+
for (const action of actions) {
|
|
60
|
+
if (!action) continue
|
|
61
|
+
await this.executeAction(action)
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
async executeAction(action) {
|
|
66
|
+
const type = action.type || 'text'
|
|
67
|
+
|
|
68
|
+
switch (type) {
|
|
69
|
+
case 'clear':
|
|
70
|
+
this.handleClear(action)
|
|
71
|
+
break
|
|
72
|
+
case 'intro':
|
|
73
|
+
await this.handleIntro(action)
|
|
74
|
+
break
|
|
75
|
+
case 'pause':
|
|
76
|
+
case 'wait':
|
|
77
|
+
await this.handlePause(action)
|
|
78
|
+
break
|
|
79
|
+
case 'code':
|
|
80
|
+
this.handleCode(action)
|
|
81
|
+
break
|
|
82
|
+
case 'sleep':
|
|
83
|
+
await this.handleSleep(action)
|
|
84
|
+
break
|
|
85
|
+
case 'command-intro':
|
|
86
|
+
await this.handleCommandIntro(action)
|
|
87
|
+
break
|
|
88
|
+
case 'text':
|
|
89
|
+
default:
|
|
90
|
+
this.handleText(action)
|
|
91
|
+
break
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
handleClear(action) {
|
|
96
|
+
if (action.message) {
|
|
97
|
+
console.log(action.message)
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
if (typeof action.useConsoleClear === 'boolean' && action.useConsoleClear) {
|
|
101
|
+
console.clear()
|
|
102
|
+
return
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
clearConsole()
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
handleText(action) {
|
|
109
|
+
const lines = this.normalizeLines(action)
|
|
110
|
+
lines.forEach(line => console.log(line))
|
|
111
|
+
if (action.extraNewLine) {
|
|
112
|
+
console.log('')
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
handleCode(action) {
|
|
117
|
+
if (action.title) {
|
|
118
|
+
console.log(`\n${action.title}`)
|
|
119
|
+
console.log('━'.repeat(action.width || 50))
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
const lines = typeof action.code === 'string' ? action.code.split('\n') : []
|
|
123
|
+
lines.forEach(line => console.log(this.formatCode(line)))
|
|
124
|
+
|
|
125
|
+
if (action.title) {
|
|
126
|
+
console.log('━'.repeat(action.width || 50))
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
if (action.after) {
|
|
130
|
+
const afterLines = Array.isArray(action.after) ? action.after : [action.after]
|
|
131
|
+
afterLines.forEach(line => console.log(line))
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
async handlePause(action) {
|
|
136
|
+
const message = action.message || DEFAULT_WAIT_MESSAGE
|
|
137
|
+
await askQuestion(this.rl, message)
|
|
138
|
+
if (action.appendNewLines !== false) {
|
|
139
|
+
console.log('\n')
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
async handleSleep(action) {
|
|
144
|
+
const duration = typeof action.duration === 'number' ? action.duration : 800
|
|
145
|
+
await new Promise(resolve => setTimeout(resolve, duration))
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
normalizeLines(action) {
|
|
149
|
+
if (Array.isArray(action.lines)) {
|
|
150
|
+
return action.lines.map(item => (item === null || item === undefined ? '' : String(item)))
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
if (typeof action.lines === 'string') {
|
|
154
|
+
return action.lines.split('\n')
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
if (Array.isArray(action.text)) {
|
|
158
|
+
return action.text.map(item => (item === null || item === undefined ? '' : String(item)))
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
if (typeof action.text === 'string') {
|
|
162
|
+
return action.text.split('\n')
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
if (typeof action.text !== 'undefined') {
|
|
166
|
+
return [String(action.text)]
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
return []
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
formatCode(line = '') {
|
|
173
|
+
const colors = {
|
|
174
|
+
keyword: '\u001b[35m',
|
|
175
|
+
property: '\u001b[32m',
|
|
176
|
+
string: '\u001b[33m',
|
|
177
|
+
comment: '\u001b[90m',
|
|
178
|
+
reset: '\u001b[0m'
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
return line
|
|
182
|
+
.replace(/\b(class|constructor|return|if|const|let|new|async|await|throw|try|catch)\b/g, `${colors.keyword}$1${colors.reset}`)
|
|
183
|
+
.replace(/\bthis\./g, `${colors.property}this.${colors.reset}`)
|
|
184
|
+
.replace(/'([^']*)'/g, (_, inner) => `${colors.string}'${inner}'${colors.reset}`)
|
|
185
|
+
.replace(/"([^\"]*)"/g, (_, inner) => `${colors.string}"${inner}"${colors.reset}`)
|
|
186
|
+
.replace(/`([^`]*)`/g, (_, inner) => `${colors.string}\`${inner}\`${colors.reset}`)
|
|
187
|
+
.replace(/\/\/.*$/g, match => `${colors.comment}${match}${colors.reset}`)
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
async handleIntro(action) {
|
|
191
|
+
// Show definition first
|
|
192
|
+
if (action.definition) {
|
|
193
|
+
console.log(action.definition)
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
// Wait for Enter
|
|
197
|
+
await askQuestion(this.rl, '\nPresiona Enter para comenzar...')
|
|
198
|
+
|
|
199
|
+
// Show explanation and detail
|
|
200
|
+
if (action.explanation) {
|
|
201
|
+
console.log(`\n${action.explanation}`)
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
if (action.detail) {
|
|
205
|
+
console.log('')
|
|
206
|
+
console.log(action.detail)
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
async handleCommandIntro(action) {
|
|
211
|
+
console.log('')
|
|
212
|
+
console.log(action.description)
|
|
213
|
+
console.log('')
|
|
214
|
+
console.log(action.explanation)
|
|
215
|
+
|
|
216
|
+
if (action.example) {
|
|
217
|
+
console.log('')
|
|
218
|
+
console.log(`Ejemplo: ${action.example}`)
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
console.log('')
|
|
222
|
+
console.log(action.instruction)
|
|
223
|
+
|
|
224
|
+
if (!action.exitOnComplete) {
|
|
225
|
+
await askQuestion(this.rl, DEFAULT_WAIT_MESSAGE)
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
}
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
import { createPromptInterface, askQuestion } from '../utils/input.js'
|
|
2
|
+
import { clearConsole } from '../utils/output.js'
|
|
3
|
+
|
|
4
|
+
export class MenuBuilder {
|
|
5
|
+
constructor(config) {
|
|
6
|
+
this.config = config
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
async show() {
|
|
10
|
+
if (this.config?.options?.length === 0) {
|
|
11
|
+
return null
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
if (!process.stdin.isTTY) {
|
|
15
|
+
return this.showFallback()
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
try {
|
|
19
|
+
return await this.showInteractive()
|
|
20
|
+
} catch (error) {
|
|
21
|
+
console.log('\nModo interactivo no disponible, usando selección numérica...\n')
|
|
22
|
+
return await this.showFallback()
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
renderHeader() {
|
|
27
|
+
clearConsole()
|
|
28
|
+
|
|
29
|
+
if (this.config.banner) {
|
|
30
|
+
console.log(this.config.banner)
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
if (this.config.description) {
|
|
34
|
+
const lines = Array.isArray(this.config.description)
|
|
35
|
+
? this.config.description
|
|
36
|
+
: [this.config.description]
|
|
37
|
+
lines.forEach(line => console.log(line))
|
|
38
|
+
console.log('')
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
if (this.config.title) {
|
|
42
|
+
console.log(this.config.title)
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
renderOption(option, isSelected, index) {
|
|
47
|
+
const prefix = isSelected ? '▶ ' : ' '
|
|
48
|
+
const label = option.title || option.label || `Opción ${index + 1}`
|
|
49
|
+
|
|
50
|
+
if (isSelected) {
|
|
51
|
+
console.log(`\x1b[36m${prefix}${label}\x1b[0m`)
|
|
52
|
+
} else {
|
|
53
|
+
console.log(`${prefix}${label}`)
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
if (option.description) {
|
|
57
|
+
console.log(` ${option.description}`)
|
|
58
|
+
}
|
|
59
|
+
console.log('')
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
async showInteractive() {
|
|
63
|
+
if (typeof process.stdin.setRawMode !== 'function') {
|
|
64
|
+
throw new Error('setRawMode not available')
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
let selectedIndex = 0
|
|
68
|
+
|
|
69
|
+
const render = () => {
|
|
70
|
+
this.renderHeader()
|
|
71
|
+
this.config.options.forEach((option, index) => {
|
|
72
|
+
this.renderOption(option, index === selectedIndex, index)
|
|
73
|
+
})
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
return new Promise((resolve) => {
|
|
77
|
+
process.stdin.setRawMode(true)
|
|
78
|
+
process.stdin.resume()
|
|
79
|
+
process.stdin.setEncoding('utf8')
|
|
80
|
+
|
|
81
|
+
const onKeyPress = (key) => {
|
|
82
|
+
if (key === 'q' || key === '\u0003') {
|
|
83
|
+
cleanup()
|
|
84
|
+
resolve(null)
|
|
85
|
+
return
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
if (key === '\r' || key === '\n') {
|
|
89
|
+
const choice = this.config.options[selectedIndex]
|
|
90
|
+
cleanup()
|
|
91
|
+
resolve(choice)
|
|
92
|
+
return
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
if (key === '\u001b[A') {
|
|
96
|
+
selectedIndex = selectedIndex > 0 ? selectedIndex - 1 : this.config.options.length - 1
|
|
97
|
+
render()
|
|
98
|
+
} else if (key === '\u001b[B') {
|
|
99
|
+
selectedIndex = selectedIndex < this.config.options.length - 1 ? selectedIndex + 1 : 0
|
|
100
|
+
render()
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
const cleanup = () => {
|
|
105
|
+
process.stdin.setRawMode(false)
|
|
106
|
+
process.stdin.removeListener('data', onKeyPress)
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
process.stdin.on('data', onKeyPress)
|
|
110
|
+
render()
|
|
111
|
+
})
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
async showFallback() {
|
|
115
|
+
const rl = createPromptInterface()
|
|
116
|
+
|
|
117
|
+
if (this.config.banner) {
|
|
118
|
+
console.log(this.config.banner)
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
if (this.config.description) {
|
|
122
|
+
const lines = Array.isArray(this.config.description)
|
|
123
|
+
? this.config.description
|
|
124
|
+
: [this.config.description]
|
|
125
|
+
lines.forEach(line => console.log(line))
|
|
126
|
+
console.log('')
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
if (this.config.title) {
|
|
130
|
+
console.log(this.config.title)
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
this.config.options.forEach((option, index) => {
|
|
134
|
+
const label = option.title || option.label || `Opción ${index + 1}`
|
|
135
|
+
console.log(`${index + 1}. ${label}`)
|
|
136
|
+
if (option.description) {
|
|
137
|
+
console.log(` ${option.description}`)
|
|
138
|
+
}
|
|
139
|
+
})
|
|
140
|
+
|
|
141
|
+
console.log('')
|
|
142
|
+
const answer = await askQuestion(rl, `Elige una opción (1-${this.config.options.length}) o 'q' para salir: `)
|
|
143
|
+
|
|
144
|
+
if (answer.toLowerCase() === 'q') {
|
|
145
|
+
rl.close()
|
|
146
|
+
return null
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
const selectedIndex = parseInt(answer, 10) - 1
|
|
150
|
+
const choice = this.config.options[selectedIndex]
|
|
151
|
+
rl.close()
|
|
152
|
+
return choice || null
|
|
153
|
+
}
|
|
154
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import fs from 'fs'
|
|
2
|
+
import path from 'path'
|
|
3
|
+
import { isBinaryFile } from '../utils/file-utils.js'
|
|
4
|
+
import { LevelModifier } from '../templates/LevelModifier.js'
|
|
5
|
+
|
|
6
|
+
export class ProjectBuilder {
|
|
7
|
+
constructor(templatePath) {
|
|
8
|
+
this.templatePath = templatePath
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
createProject(targetDir, projectName, studentName, level) {
|
|
12
|
+
if (!fs.existsSync(this.templatePath)) {
|
|
13
|
+
throw new Error(`Template no encontrado en: ${this.templatePath}`)
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
if (fs.existsSync(targetDir)) {
|
|
17
|
+
throw new Error(`El directorio ${projectName} ya existe`)
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
fs.mkdirSync(targetDir, { recursive: true })
|
|
21
|
+
const modifier = new LevelModifier(level)
|
|
22
|
+
this.copyDirectory(this.templatePath, targetDir, projectName, studentName, modifier)
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
applyPlaceholders(content, projectName, studentName) {
|
|
26
|
+
return content
|
|
27
|
+
.replace(/\{\{PROJECT_NAME\}\}/g, projectName)
|
|
28
|
+
.replace(/\{\{STUDENT_NAME\}\}/g, studentName)
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
copyDirectory(source, target, projectName, studentName, modifier) {
|
|
32
|
+
const entries = fs.readdirSync(source)
|
|
33
|
+
|
|
34
|
+
for (const entry of entries) {
|
|
35
|
+
const sourcePath = path.join(source, entry)
|
|
36
|
+
const targetPath = path.join(target, entry)
|
|
37
|
+
const stats = fs.statSync(sourcePath)
|
|
38
|
+
|
|
39
|
+
if (stats.isDirectory()) {
|
|
40
|
+
fs.mkdirSync(targetPath, { recursive: true })
|
|
41
|
+
this.copyDirectory(sourcePath, targetPath, projectName, studentName, modifier)
|
|
42
|
+
continue
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
if (isBinaryFile(sourcePath)) {
|
|
46
|
+
fs.copyFileSync(sourcePath, targetPath)
|
|
47
|
+
continue
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
let content = fs.readFileSync(sourcePath, 'utf8')
|
|
51
|
+
content = modifier.apply(content, entry)
|
|
52
|
+
content = this.applyPlaceholders(content, projectName, studentName)
|
|
53
|
+
fs.writeFileSync(targetPath, content)
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
package/lib/cli/index.js
ADDED
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { MenuBuilder } from '../builders/MenuBuilder.js'
|
|
2
|
+
import { MAIN_MENU_CONFIG } from '../data/menus.js'
|
|
3
|
+
import { executeEnunciados } from '../executors/enunciados-executor.js'
|
|
4
|
+
import { executeProyectos } from '../executors/proyectos-executor.js'
|
|
5
|
+
import { executeSintaxis } from '../executors/sintaxis-executor.js'
|
|
6
|
+
import { executePortfolio } from '../executors/portfolio-executor.js'
|
|
7
|
+
import { showHelp } from '../commands/help.js'
|
|
8
|
+
import { CretaCodeSession } from '../session.js'
|
|
9
|
+
|
|
10
|
+
async function executeMainMenu() {
|
|
11
|
+
const menu = new MenuBuilder(MAIN_MENU_CONFIG)
|
|
12
|
+
|
|
13
|
+
while (true) {
|
|
14
|
+
const choice = await menu.show()
|
|
15
|
+
if (!choice) {
|
|
16
|
+
console.log('\nHecho con <3 por icarus.mx')
|
|
17
|
+
return
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
if (choice.id === 'sintaxis') {
|
|
21
|
+
await executeSintaxis()
|
|
22
|
+
} else if (choice.id === 'enunciados') {
|
|
23
|
+
await executeEnunciados()
|
|
24
|
+
} else if (choice.id === 'proyectos') {
|
|
25
|
+
await executeProyectos()
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
async function runCodeSession() {
|
|
31
|
+
const session = new CretaCodeSession()
|
|
32
|
+
await session.start()
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const COMMANDS = new Map([
|
|
36
|
+
['enunciados', () => executeEnunciados()],
|
|
37
|
+
['sintaxis', () => executeSintaxis()],
|
|
38
|
+
['proyectos', () => executeProyectos()],
|
|
39
|
+
['portafolio', () => executePortfolio(0)],
|
|
40
|
+
['code', () => runCodeSession()],
|
|
41
|
+
['help', () => showHelp()],
|
|
42
|
+
['ayuda', () => showHelp()]
|
|
43
|
+
])
|
|
44
|
+
|
|
45
|
+
export async function handleCommand(command, args = []) {
|
|
46
|
+
if (!command) {
|
|
47
|
+
return true
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
const normalized = command.toLowerCase()
|
|
51
|
+
|
|
52
|
+
if (normalized.startsWith('portafolio')) {
|
|
53
|
+
const levelPart = normalized.split('-')[1]
|
|
54
|
+
const level = levelPart ? parseInt(levelPart, 10) : 0
|
|
55
|
+
await executePortfolio(Number.isNaN(level) ? 0 : level)
|
|
56
|
+
return true
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const handler = COMMANDS.get(normalized)
|
|
60
|
+
|
|
61
|
+
if (!handler) {
|
|
62
|
+
console.log(`Comando no reconocido: ${command}`)
|
|
63
|
+
console.log("Escribe 'creta help' para ver comandos disponibles")
|
|
64
|
+
return false
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
await handler(args)
|
|
68
|
+
return true
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
export async function runCLI(args = []) {
|
|
72
|
+
const [command, ...rest] = args
|
|
73
|
+
|
|
74
|
+
if (!command) {
|
|
75
|
+
await executeMainMenu()
|
|
76
|
+
return 0
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
const handled = await handleCommand(command, rest)
|
|
80
|
+
return handled ? 0 : 1
|
|
81
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import path from 'path'
|
|
2
|
+
import { fileURLToPath } from 'url'
|
|
3
|
+
|
|
4
|
+
const __filename = fileURLToPath(import.meta.url)
|
|
5
|
+
const __dirname = path.dirname(__filename)
|
|
6
|
+
|
|
7
|
+
export const CLI_ROOT = path.resolve(__dirname, '../..')
|
|
8
|
+
export const TEMPLATES_ROOT = path.join(CLI_ROOT, 'templates')
|
|
9
|
+
export const SVELTEKIT_PORTFOLIO_TEMPLATE_PATH = path.join(TEMPLATES_ROOT, 'sveltekit-portfolio')
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
export const ENUNCIADOS = [
|
|
2
|
+
{
|
|
3
|
+
id: 1,
|
|
4
|
+
texto: "La parte difícil del diseño orientado a objetos es descomponer un sistema como un conjunto de objetos que interactúan entre sí.",
|
|
5
|
+
nivel: "Fundacional",
|
|
6
|
+
enfoque: "Descomposición de sistemas"
|
|
7
|
+
},
|
|
8
|
+
{
|
|
9
|
+
id: 2,
|
|
10
|
+
texto: "Los objetos interactúan entre sí a través de solicitudes.",
|
|
11
|
+
nivel: "Interacción",
|
|
12
|
+
enfoque: "Comunicación entre objetos"
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
id: 3,
|
|
16
|
+
texto: "Las solicitudes son la única forma de conseguir que un objeto lleve a cabo una operación.",
|
|
17
|
+
nivel: "Operaciones",
|
|
18
|
+
enfoque: "Mecanismo de ejecución"
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
id: 4,
|
|
22
|
+
texto: "Cada operación declarada por un objeto debe incluir:\na) nombre de la operación\nb) insumos necesarios para realizar la operación\nc) el valor que regresa tras ejecutar la operación\n\nEstos tres elementos constituyen la firma de operación.",
|
|
23
|
+
nivel: "Firmas",
|
|
24
|
+
enfoque: "Contratos de operación"
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
id: 5,
|
|
28
|
+
texto: "La interfaz de un objeto es el conjunto de todas sus firmas de operación.",
|
|
29
|
+
nivel: "Interfaces",
|
|
30
|
+
enfoque: "Definición de contratos"
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
id: 6,
|
|
34
|
+
texto: "El énfasis al diseñar los objetos debe estar en la definición de sus solicitudes e interfaces.",
|
|
35
|
+
nivel: "Diseño",
|
|
36
|
+
enfoque: "Metodología de desarrollo"
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
id: 7,
|
|
40
|
+
texto: "Un objeto es un conjunto de datos y procedimientos que operan sobre esos datos.",
|
|
41
|
+
nivel: "Definición",
|
|
42
|
+
enfoque: "Naturaleza del objeto"
|
|
43
|
+
}
|
|
44
|
+
]
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
export { LESSON_1_SYSTEM_DECOMPOSITION } from './lesson1-system-decomposition.js'
|
|
2
|
+
export { LESSON_2_OBJECT_REQUESTS } from './lesson2-object-requests.js'
|
|
3
|
+
export { LESSON_3_ONLY_WAY } from './lesson3-only-way.js'
|
|
4
|
+
export { LESSON_4_OPERATION_SIGNATURES } from './lesson4-operation-signatures.js'
|
|
5
|
+
export { LESSON_5_INTERFACE_SET } from './lesson5-interface-set.js'
|
|
6
|
+
export { LESSON_6_INTERFACE_DESIGN } from './lesson6-interface-design.js'
|
|
7
|
+
export { LESSON_7_OBJECT_DEFINITION } from './lesson7-object-definition.js'
|
|
8
|
+
|
|
9
|
+
import { LESSON_1_SYSTEM_DECOMPOSITION } from './lesson1-system-decomposition.js'
|
|
10
|
+
import { LESSON_2_OBJECT_REQUESTS } from './lesson2-object-requests.js'
|
|
11
|
+
import { LESSON_3_ONLY_WAY } from './lesson3-only-way.js'
|
|
12
|
+
import { LESSON_4_OPERATION_SIGNATURES } from './lesson4-operation-signatures.js'
|
|
13
|
+
import { LESSON_5_INTERFACE_SET } from './lesson5-interface-set.js'
|
|
14
|
+
import { LESSON_6_INTERFACE_DESIGN } from './lesson6-interface-design.js'
|
|
15
|
+
import { LESSON_7_OBJECT_DEFINITION } from './lesson7-object-definition.js'
|
|
16
|
+
|
|
17
|
+
export const LESSONS_BY_ID = new Map([
|
|
18
|
+
[1, LESSON_1_SYSTEM_DECOMPOSITION],
|
|
19
|
+
[2, LESSON_2_OBJECT_REQUESTS],
|
|
20
|
+
[3, LESSON_3_ONLY_WAY],
|
|
21
|
+
[4, LESSON_4_OPERATION_SIGNATURES],
|
|
22
|
+
[5, LESSON_5_INTERFACE_SET],
|
|
23
|
+
[6, LESSON_6_INTERFACE_DESIGN],
|
|
24
|
+
[7, LESSON_7_OBJECT_DEFINITION]
|
|
25
|
+
])
|