create-openclass-uniminuto 1.4.1 → 1.4.2

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/package.json CHANGED
@@ -1,10 +1,10 @@
1
1
  {
2
2
  "name": "create-openclass-uniminuto",
3
- "version": "1.4.1",
3
+ "version": "1.4.2",
4
4
  "description": "Creador de proyectos Open Class UNIMINUTO basados en Slidev, con generación incremental por semanas y GitHub Pages.",
5
5
  "type": "module",
6
6
  "bin": {
7
- "create-openclass-uniminuto": "./bin/create-openclass-uniminuto.mjs"
7
+ "create-openclass-uniminuto": "bin/create-openclass-uniminuto.mjs"
8
8
  },
9
9
  "files": [
10
10
  "bin",
@@ -6,7 +6,6 @@ Este curso está diseñado para organizar una Open Class de **8 semanas**, con g
6
6
 
7
7
  ---
8
8
 
9
- <<<<<<< HEAD
10
9
 
11
10
  ## Crear el curso dentro de un repositorio ya creado en GitHub
12
11
 
@@ -36,8 +35,6 @@ git push
36
35
  ```
37
36
 
38
37
 
39
- =======
40
- >>>>>>> 55a9d4cb0e83dc9640a84aea0dc007a5379aba33
41
38
  ## 1. Primer uso
42
39
 
43
40
  Instala dependencias:
@@ -1,20 +1,12 @@
1
1
  {
2
2
  "name": "openclass-demo",
3
- <<<<<<< HEAD
4
3
  "version": "1.0.1",
5
- =======
6
- "version": "1.0.0",
7
- >>>>>>> 55a9d4cb0e83dc9640a84aea0dc007a5379aba33
8
4
  "lockfileVersion": 3,
9
5
  "requires": true,
10
6
  "packages": {
11
7
  "": {
12
8
  "name": "openclass-demo",
13
- <<<<<<< HEAD
14
9
  "version": "1.0.1",
15
- =======
16
- "version": "1.0.0",
17
- >>>>>>> 55a9d4cb0e83dc9640a84aea0dc007a5379aba33
18
10
  "dependencies": {
19
11
  "@fontsource/atkinson-hyperlegible": "^5.2.8",
20
12
  "@fontsource/merriweather-sans": "^5.2.7",
@@ -1,10 +1,6 @@
1
1
  {
2
2
  "name": "openclass-demo",
3
- <<<<<<< HEAD
4
3
  "version": "1.0.1",
5
- =======
6
- "version": "1.0.0",
7
- >>>>>>> 55a9d4cb0e83dc9640a84aea0dc007a5379aba33
8
4
  "description": "Presentaciones Open Class del curso Curso Open Class de ejemplo.",
9
5
  "type": "module",
10
6
  "private": true,
@@ -3,7 +3,6 @@
3
3
  *
4
4
  * Uso principal:
5
5
  * npm run config
6
- <<<<<<< HEAD
7
6
  * npm run semana -- 6
8
7
  * node scripts/generar-desde-config.mjs --config config/openclass.config.iot-ejemplo.json --force
9
8
  *
@@ -12,9 +11,6 @@
12
11
  * - Repara public/favicon.png si no existe.
13
12
  * - Elimina demo_semanaX.md cuando el curso ya tiene un nombre corto diferente de "demo".
14
13
  * - No sobrescribe el contenido académico ya editado en semanas/*.md salvo con --force.
15
- =======
16
- * node scripts/generar-desde-config.mjs --config config/openclass.config.iot-ejemplo.json --force
17
- >>>>>>> 55a9d4cb0e83dc9640a84aea0dc007a5379aba33
18
14
  */
19
15
  import fs from "node:fs";
20
16
  import path from "node:path";
@@ -24,22 +20,16 @@ const args = process.argv.slice(2);
24
20
  function valueAfter(flag, fallback) {
25
21
  const i = args.indexOf(flag);
26
22
  if (i >= 0 && args[i + 1]) return args[i + 1];
27
- <<<<<<< HEAD
28
23
 
29
24
  const pair = args.find((arg) => arg.startsWith(`${flag}=`));
30
25
  if (pair) return pair.slice(flag.length + 1);
31
26
 
32
- =======
33
- const pair = args.find((arg) => arg.startsWith(`${flag}=`));
34
- if (pair) return pair.slice(flag.length + 1);
35
- >>>>>>> 55a9d4cb0e83dc9640a84aea0dc007a5379aba33
36
27
  return fallback;
37
28
  }
38
29
 
39
30
  const configPath = valueAfter("--config", "openclass.config.json");
40
31
  const force = args.includes("--force") || args.includes("-f");
41
32
  const dryRun = args.includes("--dry-run");
42
- <<<<<<< HEAD
43
33
  const forceCleanDemo = args.includes("--clean-demo");
44
34
 
45
35
  /**
@@ -51,8 +41,6 @@ const forceCleanDemo = args.includes("--clean-demo");
51
41
  */
52
42
  const FALLBACK_FAVICON_PNG_BASE64 =
53
43
  "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mP8/x8AAwMCAO+/p9sAAAAASUVORK5CYII=";
54
- =======
55
- >>>>>>> 55a9d4cb0e83dc9640a84aea0dc007a5379aba33
56
44
 
57
45
  function fail(message) {
58
46
  console.error(`\n❌ ${message}\n`);
@@ -60,14 +48,10 @@ function fail(message) {
60
48
  }
61
49
 
62
50
  function readJson(filePath) {
63
- <<<<<<< HEAD
64
51
  if (!fs.existsSync(filePath)) {
65
52
  fail(`No se encontró el archivo de configuración: ${filePath}`);
66
53
  }
67
54
 
68
- =======
69
- if (!fs.existsSync(filePath)) fail(`No se encontró el archivo de configuración: ${filePath}`);
70
- >>>>>>> 55a9d4cb0e83dc9640a84aea0dc007a5379aba33
71
55
  try {
72
56
  return JSON.parse(fs.readFileSync(filePath, "utf-8"));
73
57
  } catch (error) {
@@ -92,7 +76,6 @@ function writeFileSafe(filePath, content, { overwrite = true, label = filePath }
92
76
  return true;
93
77
  }
94
78
 
95
- <<<<<<< HEAD
96
79
  function writeBinaryFileIfMissing(filePath, base64Content, { label = filePath } = {}) {
97
80
  ensureDir(path.dirname(filePath));
98
81
 
@@ -126,15 +109,6 @@ function cleanShortName(value) {
126
109
  .replace(/[^a-z0-9]+/g, "")
127
110
  .trim() || "curso"
128
111
  );
129
- =======
130
- function cleanShortName(value) {
131
- return String(value || "")
132
- .normalize("NFD")
133
- .replace(/[\u0300-\u036f]/g, "")
134
- .toLowerCase()
135
- .replace(/[^a-z0-9]+/g, "")
136
- .trim();
137
- >>>>>>> 55a9d4cb0e83dc9640a84aea0dc007a5379aba33
138
112
  }
139
113
 
140
114
  function asArray(value) {
@@ -152,16 +126,6 @@ function readTemplate(filePath, fallback) {
152
126
  return fs.existsSync(filePath) ? fs.readFileSync(filePath, "utf-8") : fallback;
153
127
  }
154
128
 
155
- <<<<<<< HEAD
156
- =======
157
- function normalizeBase(value) {
158
- let base = value || "/";
159
- if (!base.startsWith("/")) base = `/${base}`;
160
- if (!base.endsWith("/")) base = `${base}/`;
161
- return base;
162
- }
163
-
164
- >>>>>>> 55a9d4cb0e83dc9640a84aea0dc007a5379aba33
165
129
  const config = readJson(configPath);
166
130
  const course = config.course || {};
167
131
  const generation = config.generation || {};
@@ -175,23 +139,16 @@ const weeksTotal = Number(generation.weeksTotal || config.weeksTotal || config.t
175
139
 
176
140
  if (!courseShort) fail("El campo course.shortName es obligatorio.");
177
141
  if (!courseName) fail("El campo course.fullName es obligatorio.");
178
- <<<<<<< HEAD
179
142
  if (!Number.isInteger(weeksTotal) || weeksTotal < 1) {
180
143
  fail("generation.weeksTotal debe ser un número entero mayor o igual a 1.");
181
144
  }
182
- =======
183
- if (!Number.isInteger(weeksTotal) || weeksTotal < 1) fail("generation.weeksTotal debe ser un número entero mayor o igual a 1.");
184
- >>>>>>> 55a9d4cb0e83dc9640a84aea0dc007a5379aba33
185
145
 
186
146
  const configuredWeeks = new Map(asArray(config.weeks).map((week) => [Number(week.number), week]));
187
147
 
188
148
  function weekInfo(number) {
189
149
  const week = configuredWeeks.get(number) || {};
190
150
  const title = String(week.title || `Título semana ${number}`).trim();
191
- <<<<<<< HEAD
192
151
 
193
- =======
194
- >>>>>>> 55a9d4cb0e83dc9640a84aea0dc007a5379aba33
195
152
  return {
196
153
  number,
197
154
  title,
@@ -204,20 +161,14 @@ function weekInfo(number) {
204
161
  }
205
162
 
206
163
  const allWeeks = Array.from({ length: weeksTotal }, (_, i) => weekInfo(i + 1));
207
- <<<<<<< HEAD
208
164
 
209
- =======
210
- >>>>>>> 55a9d4cb0e83dc9640a84aea0dc007a5379aba33
211
165
  const activeWeeksRaw = asArray(generation.activeWeeks || config.activeWeeks);
212
166
  const activeWeekNumbers = activeWeeksRaw.length
213
167
  ? activeWeeksRaw.map(Number).filter((n) => Number.isInteger(n) && n >= 1 && n <= weeksTotal)
214
168
  : allWeeks.filter((week) => week.status !== "draft" && week.status !== "inactive").map((week) => week.number);
215
169
 
216
170
  const activeWeeks = allWeeks.filter((week) => activeWeekNumbers.includes(week.number));
217
- <<<<<<< HEAD
218
171
 
219
- =======
220
- >>>>>>> 55a9d4cb0e83dc9640a84aea0dc007a5379aba33
221
172
  const overwriteLaunchers = generation.overwriteLaunchers !== false || force;
222
173
  const overwritePortal = generation.overwritePortal !== false || force;
223
174
  const overwriteDecks = generation.overwriteDecks !== false || force;
@@ -225,7 +176,6 @@ const overwritePackageScripts = generation.overwritePackageScripts !== false ||
225
176
  const overwriteWeekContent = generation.overwriteWeekContent === true || force;
226
177
  const exportPortal = generation.exportPortal === true;
227
178
 
228
- <<<<<<< HEAD
229
179
  /**
230
180
  * Por defecto se eliminan los archivos demo cuando el curso ya no se llama "demo".
231
181
  * Puede desactivarse desde openclass.config.json:
@@ -255,16 +205,10 @@ Semana {{WEEK_NUMBER}} — {{WEEK_TITLE}}
255
205
  layout: slide-12-cierre
256
206
  ---
257
207
  `,
258
- =======
259
- const semanaTemplate = readTemplate(
260
- "plantillas/semana.md",
261
- `---\nlayout: slide-01-portada\n---\n\n::title::\n{{COURSE_NAME}}\n\n::week::\nSemana {{WEEK_NUMBER}} — {{WEEK_TITLE}}\n\n::date::\n{{WEEK_DATE}}\n\n---\nlayout: slide-12-cierre\n---\n`,
262
- >>>>>>> 55a9d4cb0e83dc9640a84aea0dc007a5379aba33
263
208
  );
264
209
 
265
210
  const launcherTemplate = readTemplate(
266
211
  "plantillas/launcher.md",
267
- <<<<<<< HEAD
268
212
  `---
269
213
  theme: ./theme/uniminuto
270
214
  title: {{COURSE_NAME}} — Semana {{WEEK_NUMBER}} — {{WEEK_TITLE}}
@@ -277,9 +221,6 @@ drawings:
277
221
  src: ./semanas/{{COURSE_SHORT}}_semana{{WEEK_NUMBER}}.md
278
222
  ---
279
223
  `,
280
- =======
281
- `---\ntheme: ./theme/uniminuto\ntitle: {{COURSE_NAME}} — Semana {{WEEK_NUMBER}} — {{WEEK_TITLE}}\nfavicon: /favicon.png\ncodeCopy: true\ntransition: fade\nrouterMode: hash\ndrawings:\n persist: false\nsrc: ./semanas/{{COURSE_SHORT}}_semana{{WEEK_NUMBER}}.md\n---\n`,
282
- >>>>>>> 55a9d4cb0e83dc9640a84aea0dc007a5379aba33
283
224
  );
284
225
 
285
226
  function weekTokens(week) {
@@ -299,21 +240,16 @@ function weekTokens(week) {
299
240
 
300
241
  function portalWeekItem(week) {
301
242
  const slug = `${courseShort}_semana${week.number}`;
302
- <<<<<<< HEAD
303
243
 
304
244
  return `### **Semana ${week.number}**
305
245
 
306
246
  <a href="./semanas/${slug}/#/1" target="_self">${week.title}</a>
307
247
 
308
248
  <a href="./descargas/${slug}.pdf" download>Descargar PDF</a> · <a href="./descargas/${slug}.pptx" download>Descargar PPTX</a>`;
309
- =======
310
- return `### **Semana ${week.number}**\n\n<a href="./semanas/${slug}/#/1" target="_self">${week.title}</a>\n\n<a href="./descargas/${slug}.pdf" download>Descargar PDF</a> · <a href="./descargas/${slug}.pptx" download>Descargar PPTX</a>`;
311
- >>>>>>> 55a9d4cb0e83dc9640a84aea0dc007a5379aba33
312
249
  }
313
250
 
314
251
  function buildPortal() {
315
252
  const left = activeWeeks.length
316
- <<<<<<< HEAD
317
253
  ? activeWeeks
318
254
  .filter((_, index) => index < Math.ceil(activeWeeks.length / 2))
319
255
  .map(portalWeekItem)
@@ -387,18 +323,10 @@ ${right}
387
323
  layout: slide-12-cierre
388
324
  ---
389
325
  `;
390
- =======
391
- ? activeWeeks.filter((_, index) => index < Math.ceil(activeWeeks.length / 2)).map(portalWeekItem).join("\n\n")
392
- : "### Sin semanas activas\n\nEjecuta `npm run semana -- 1` para generar la primera semana.";
393
- const right = activeWeeks.filter((_, index) => index >= Math.ceil(activeWeeks.length / 2)).map(portalWeekItem).join("\n\n") || "### Próximamente\n\nActiva más semanas con `npm run semana -- 2`, `npm run semana -- 3` y así sucesivamente.";
394
-
395
- return `---\ntheme: ./theme/uniminuto\ntitle: ${courseName} — ${openClassLabel}\nfavicon: /favicon.png\ncodeCopy: true\ntransition: fade\nrouterMode: hash\ndrawings:\n persist: false\nlayout: slide-01-portada\n---\n\n::title::\n${courseName}\n\n::week::\n${openClassLabel}\n\n::date::\n${courseYear}\n\n---\nlayout: slide-08-titulo-texto\n---\n\n::title::\nDescripción general del curso\n\n::content::\n${description}\n\n---\nlayout: slide-08-titulo-texto\n---\n\n::title::\nRuta de aprendizaje\n\n::content::\nEl curso se organiza en semanas. Cada semana cuenta con un lanzador raíz y un archivo interno en la carpeta \`semanas/\`.\n\nLas presentaciones activas se controlan desde \`openclass.config.json\` mediante el campo \`generation.activeWeeks\`.\n\n---\nlayout: slide-10-titulo-dos-columnas\n---\n\n::title::\nPresentaciones disponibles\n\n::left::\n${left}\n\n::right::\n${right}\n\n---\nlayout: slide-12-cierre\n---\n`;
396
- >>>>>>> 55a9d4cb0e83dc9640a84aea0dc007a5379aba33
397
326
  }
398
327
 
399
328
  function buildDecks() {
400
329
  const entries = [
401
- <<<<<<< HEAD
402
330
  `function normalizeBase(value) {
403
331
  let base = value || "/";
404
332
  if (!base.startsWith("/")) base = \`/\${base}\`;
@@ -420,14 +348,10 @@ export const decks = [
420
348
  base: SITE_BASE,
421
349
  exportable: ${exportPortal ? "true" : "false"},
422
350
  },`,
423
- =======
424
- `function normalizeBase(value) {\n let base = value || "/";\n if (!base.startsWith("/")) base = \`/\${base}\`;\n if (!base.endsWith("/")) base = \`\${base}/\`;\n return base;\n}\n\nconst SITE_BASE = normalizeBase(process.env.SITE_BASE || "/");\n\nfunction withBase(path = "") {\n return \`\${SITE_BASE}\${path.replace(/^\\/+/, "")}\`;\n}\n\nexport const decks = [\n {\n name: "openclass-${courseShort}",\n entry: "slides.md",\n out: "dist",\n base: SITE_BASE,\n exportable: ${exportPortal ? "true" : "false"},\n },`,
425
- >>>>>>> 55a9d4cb0e83dc9640a84aea0dc007a5379aba33
426
351
  ];
427
352
 
428
353
  for (const week of activeWeeks) {
429
354
  const slug = `${courseShort}_semana${week.number}`;
430
- <<<<<<< HEAD
431
355
 
432
356
  entries.push(` {
433
357
  name: "${slug}",
@@ -436,9 +360,6 @@ export const decks = [
436
360
  base: withBase("semanas/${slug}/"),
437
361
  exportable: true,
438
362
  },`);
439
- =======
440
- entries.push(` {\n name: "${slug}",\n entry: "${slug}.md",\n out: "dist/semanas/${slug}",\n base: withBase("semanas/${slug}/"),\n exportable: true,\n },`);
441
- >>>>>>> 55a9d4cb0e83dc9640a84aea0dc007a5379aba33
442
363
  }
443
364
 
444
365
  entries.push(`];\n`);
@@ -459,11 +380,7 @@ function buildScripts() {
459
380
  }
460
381
 
461
382
  scripts.clean = "node -e \"require('fs').rmSync('dist',{recursive:true,force:true})\"";
462
- <<<<<<< HEAD
463
383
  scripts["clean:downloads"] = "node -e \"require('fs').rmSync('public/descargas',{recursive:true,force:true}); require('fs').mkdirSync('public/descargas',{recursive:true})\"";
464
- =======
465
- scripts["clean:downloads"] = "node -e \"require('fs').rmSync('public/descargas',{recursive:true,force:true})\"";
466
- >>>>>>> 55a9d4cb0e83dc9640a84aea0dc007a5379aba33
467
384
  scripts["clean:cache"] = "node -e \"require('fs').rmSync('.slidev',{recursive:true,force:true}); require('fs').rmSync('node_modules/.vite',{recursive:true,force:true})\"";
468
385
  scripts["build:index"] = "slidev build slides.md --out dist --base / --without-notes";
469
386
 
@@ -489,7 +406,6 @@ function buildScripts() {
489
406
  return scripts;
490
407
  }
491
408
 
492
- <<<<<<< HEAD
493
409
  function ensureProjectAssets() {
494
410
  ensureDir("public");
495
411
  ensureDir("public/descargas");
@@ -520,8 +436,6 @@ function cleanLegacyDemoFiles() {
520
436
  }
521
437
  }
522
438
 
523
- =======
524
- >>>>>>> 55a9d4cb0e83dc9640a84aea0dc007a5379aba33
525
439
  console.log("\n┌──────────────────────────────────────────────┐");
526
440
  console.log("│ Generador Open Class UNIMINUTO desde config │");
527
441
  console.log("└──────────────────────────────────────────────┘\n");
@@ -532,7 +446,6 @@ console.log(`Semanas : ${weeksTotal}`);
532
446
  console.log(`Activas : ${activeWeeks.map((w) => w.number).join(", ") || "ninguna"}\n`);
533
447
 
534
448
  ensureDir("semanas");
535
- <<<<<<< HEAD
536
449
  ensureProjectAssets();
537
450
  cleanLegacyDemoFiles();
538
451
 
@@ -545,30 +458,16 @@ writeFileSafe("scripts/decks.mjs", buildDecks(), {
545
458
  overwrite: overwriteDecks,
546
459
  label: "scripts/decks.mjs",
547
460
  });
548
- =======
549
- ensureDir("public/descargas");
550
- ensureDir("public/imagenes");
551
- ensureDir("public/videos");
552
-
553
- writeFileSafe("slides.md", buildPortal(), { overwrite: overwritePortal, label: "slides.md" });
554
- writeFileSafe("scripts/decks.mjs", buildDecks(), { overwrite: overwriteDecks, label: "scripts/decks.mjs" });
555
- >>>>>>> 55a9d4cb0e83dc9640a84aea0dc007a5379aba33
556
461
 
557
462
  for (const week of allWeeks) {
558
463
  const slug = `${courseShort}_semana${week.number}`;
559
464
  const tokens = weekTokens(week);
560
- <<<<<<< HEAD
561
465
 
562
- =======
563
- >>>>>>> 55a9d4cb0e83dc9640a84aea0dc007a5379aba33
564
466
  writeFileSafe(`${slug}.md`, replaceTokens(launcherTemplate, tokens), {
565
467
  overwrite: overwriteLaunchers,
566
468
  label: `${slug}.md`,
567
469
  });
568
- <<<<<<< HEAD
569
470
 
570
- =======
571
- >>>>>>> 55a9d4cb0e83dc9640a84aea0dc007a5379aba33
572
471
  writeFileSafe(path.join("semanas", `${slug}.md`), replaceTokens(semanaTemplate, tokens), {
573
472
  overwrite: overwriteWeekContent,
574
473
  label: path.join("semanas", `${slug}.md`),
@@ -577,7 +476,6 @@ for (const week of allWeeks) {
577
476
 
578
477
  if (overwritePackageScripts && fs.existsSync("package.json")) {
579
478
  const pkg = JSON.parse(fs.readFileSync("package.json", "utf-8"));
580
- <<<<<<< HEAD
581
479
 
582
480
  pkg.name = `openclass-${courseShort}`;
583
481
  pkg.description = `Presentaciones Open Class del curso ${courseName}.`;
@@ -587,46 +485,27 @@ if (overwritePackageScripts && fs.existsSync("package.json")) {
587
485
  overwrite: true,
588
486
  label: "package.json",
589
487
  });
590
- =======
591
- pkg.name = `openclass-${courseShort}`;
592
- pkg.description = `Presentaciones Open Class del curso ${courseName}.`;
593
- pkg.scripts = buildScripts();
594
- writeFileSafe("package.json", JSON.stringify(pkg, null, 2) + "\n", { overwrite: true, label: "package.json" });
595
- >>>>>>> 55a9d4cb0e83dc9640a84aea0dc007a5379aba33
596
488
  }
597
489
 
598
490
  if (fs.existsSync("package-lock.json")) {
599
491
  try {
600
492
  const lock = JSON.parse(fs.readFileSync("package-lock.json", "utf-8"));
601
- <<<<<<< HEAD
602
493
 
603
- =======
604
- >>>>>>> 55a9d4cb0e83dc9640a84aea0dc007a5379aba33
605
494
  lock.name = `openclass-${courseShort}`;
606
495
  if (lock.packages && lock.packages[""]) {
607
496
  lock.packages[""].name = `openclass-${courseShort}`;
608
497
  }
609
- <<<<<<< HEAD
610
498
 
611
499
  writeFileSafe("package-lock.json", JSON.stringify(lock, null, 2) + "\n", {
612
500
  overwrite: true,
613
501
  label: "package-lock.json",
614
502
  });
615
- =======
616
- writeFileSafe("package-lock.json", JSON.stringify(lock, null, 2) + "\n", { overwrite: true, label: "package-lock.json" });
617
- >>>>>>> 55a9d4cb0e83dc9640a84aea0dc007a5379aba33
618
503
  } catch {
619
504
  console.log("⚠️ package-lock.json no se actualizó porque no parece ser JSON válido.");
620
505
  }
621
506
  }
622
507
 
623
508
  console.log("\n✅ Configuración generada.");
624
- <<<<<<< HEAD
625
509
  console.log(" Vista de una semana: npm run dev:s1");
626
510
  console.log(" Vista completa: npm run vista");
627
- console.log(" Exportar PDF/PPTX: npm run export:downloads\n");
628
- =======
629
- console.log(" Próximo paso sugerido: npm install");
630
- console.log(" Vista de una semana: npm run dev:s1");
631
- console.log(" Vista completa: npm run vista\n");
632
- >>>>>>> 55a9d4cb0e83dc9640a84aea0dc007a5379aba33
511
+ console.log(" Exportar PDF/PPTX: npm run export:downloads\n");