create-marp-presentation 1.2.0 → 1.2.1

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.
@@ -0,0 +1,848 @@
1
+ # Create Marp Presentation Template - Implementation Plan
2
+
3
+ > **For Claude:** REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task.
4
+
5
+ **Goal:** Создать npm-пакет `create-marp-presentation`, который инициализирует готовый шаблон проекта для Marp-презентаций с поддержкой статических файлов и генерацией в HTML/PDF/PPTX.
6
+
7
+ **Architecture:** Мета-пакет с CLI-скриптом (`index.js`) который копирует шаблон из `template/` в новую папку. Шаблон содержит Marp-конфигурацию, скрипт копирования статики через `fast-glob`, и npm-скрипты для сборки через `@marp-team/marp-cli`.
8
+
9
+ **Tech Stack:** Node.js, npm, @marp-team/marp-cli v4.1.2, fast-glob v3.3.3, rimraf v6.0.0
10
+
11
+ ---
12
+
13
+ ## Task 1: Создание структуры проекта и базовых файлов
14
+
15
+ **Files:**
16
+ - Create: `template/package.json`
17
+ - Create: `template/marp.config.js`
18
+ - Create: `template/presentation.md`
19
+ - Create: `template/.gitignore`
20
+ - Create: `template/README.md`
21
+ - Create: `template/static/.gitkeep`
22
+
23
+ **Step 1: Создать template/package.json**
24
+
25
+ Создайте файл `template/package.json` с зависимостями и скриптами:
26
+
27
+ ```json
28
+ {
29
+ "name": "marp-presentation",
30
+ "version": "1.0.0",
31
+ "description": "Marp presentation",
32
+ "scripts": {
33
+ "dev": "marp -s . --html",
34
+ "build:html": "marp presentation.md -o output/index.html --html && npm run copy:static",
35
+ "build:pdf": "marp presentation.md -o output/presentation.pdf --allow-local-files && npm run copy:static",
36
+ "build:pptx": "marp presentation.md -o output/presentation.pptx --allow-local-files && npm run copy:static",
37
+ "build:all": "npm run build:html && npm run build:pdf && npm run build:pptx",
38
+ "copy:static": "node scripts/copy-static.js",
39
+ "clean": "rimraf output"
40
+ },
41
+ "devDependencies": {
42
+ "@marp-team/marp-cli": "^4.1.2",
43
+ "fast-glob": "^3.3.3",
44
+ "rimraf": "^6.0.0"
45
+ },
46
+ "engines": {
47
+ "node": ">=20.0.0"
48
+ }
49
+ }
50
+ ```
51
+
52
+ **Step 2: Создать template/marp.config.js**
53
+
54
+ ```javascript
55
+ module.exports = {
56
+ staticFolders: ['static/**', 'assets/**'],
57
+ outputDir: 'output',
58
+ };
59
+ ```
60
+
61
+ **Step 3: Создать template/presentation.md**
62
+
63
+ ```markdown
64
+ ---
65
+ marp: true
66
+ theme: default
67
+ paginate: true
68
+ ---
69
+
70
+ # Моя презентация
71
+
72
+ Добро пожаловать в вашу новую Marp презентацию!
73
+
74
+ ---
75
+
76
+ ## О Marp
77
+
78
+ Marp (Markdown Presentation Ecosystem) — это инструмент для создания презентаций на Markdown.
79
+
80
+ ---
81
+
82
+ ## Возможности
83
+
84
+ - **Простой Markdown** - пишите слайды в привычном формате
85
+ - **Темы** - используйте встроенные или создайте свою
86
+ - **Экспорт** - HTML, PDF, PowerPoint
87
+ - **Live preview** - мгновенный предпросмотр изменений
88
+
89
+ ---
90
+
91
+ ## Код с подсветкой
92
+
93
+ \`\`\`javascript
94
+ function hello() {
95
+ console.log('Hello, Marp!');
96
+ }
97
+ \`\`\`
98
+
99
+ ---
100
+
101
+ ## Изображения
102
+
103
+ Поместите изображения в папку `static/` и используйте их:
104
+
105
+ \`\`\`
106
+ ![alt text](static/image.png)
107
+ \`\`\`
108
+
109
+ ---
110
+
111
+ # Вопросы?
112
+
113
+ Документация: https://marp.app/
114
+ ```
115
+
116
+ **Step 4: Создать template/.gitignore**
117
+
118
+ ```
119
+ node_modules/
120
+ output/
121
+ .DS_Store
122
+ ```
123
+
124
+ **Step 5: Создать template/README.md**
125
+
126
+ ```markdown
127
+ # Marp Presentation
128
+
129
+ Шаблон для создания презентаций с Marp.
130
+
131
+ ## Начало работы
132
+
133
+ ### Live-предпросмотр
134
+
135
+ \`\`\`bash
136
+ npm run dev
137
+ \`\`\`
138
+
139
+ Откроется браузер с автообновлением при изменениях.
140
+
141
+ ### Создание слайдов
142
+
143
+ Редактируйте `presentation.md` — это главный файл презентации.
144
+
145
+ ## Сборка презентации
146
+
147
+ \`\`\`bash
148
+ npm run build:html # HTML презентация (интерактивная)
149
+ npm run build:pdf # PDF файл
150
+ npm run build:pptx # PowerPoint
151
+ npm run build:all # Все форматы сразу
152
+ \`\`\`
153
+
154
+ Результат появится в папке `output/`.
155
+
156
+ ## Статические файлы
157
+
158
+ Поместите изображения и другие файлы в папку, указанную в `marp.config.js`.
159
+
160
+ По умолчанию: `static/`
161
+
162
+ Вы можете добавить дополнительные папки в `marp.config.js`:
163
+
164
+ \`\`\`javascript
165
+ module.exports = {
166
+ staticFolders: ['static/**', 'assets/**', 'images/**'],
167
+ outputDir: 'output',
168
+ };
169
+ \`\`\`
170
+
171
+ ## Очистка
172
+
173
+ \`\`\`bash
174
+ npm run clean
175
+ \`\`\`
176
+
177
+ Удаляет папку `output/`.
178
+
179
+ ## Полезные ссылки
180
+
181
+ - [Marp Documentation](https://marp.app/)
182
+ - [Marp CLI](https://github.com/marp-team/marp-cli)
183
+ - [Markdown Guide](https://www.markdownguide.org/)
184
+ ```
185
+
186
+ **Step 6: Создать template/static/.gitkeep**
187
+
188
+ Создайте пустой файл для коммита папки `static/` в git.
189
+
190
+ **Step 7: Закоммитить структуру шаблона**
191
+
192
+ ```bash
193
+ git add template/
194
+ git commit -m "feat: add template structure with package.json, config, and example presentation"
195
+ ```
196
+
197
+ ---
198
+
199
+ ## Task 2: Скрипт копирования статических файлов
200
+
201
+ **Files:**
202
+ - Create: `template/scripts/copy-static.js`
203
+
204
+ **Step 1: Создать template/scripts/copy-static.js**
205
+
206
+ ```javascript
207
+ const fs = require('fs');
208
+ const path = require('path');
209
+ const { globSync } = require('fast-glob');
210
+
211
+ // Читаем конфиг с дефолтными значениями
212
+ let config;
213
+ try {
214
+ config = require('../marp.config.js');
215
+ } catch {
216
+ config = {};
217
+ }
218
+
219
+ const outputDir = config.outputDir || 'output';
220
+ const staticFolders = config.staticFolders || ['static/**'];
221
+
222
+ // Создаём output если нет
223
+ if (!fs.existsSync(outputDir)) {
224
+ fs.mkdirSync(outputDir, { recursive: true });
225
+ }
226
+
227
+ // Находим файлы по паттернам
228
+ const files = globSync(staticFolders);
229
+
230
+ if (files.length === 0) {
231
+ console.log('No static files found to copy.');
232
+ process.exit(0);
233
+ }
234
+
235
+ // Копируем с сохранением структуры
236
+ let copied = 0;
237
+ for (const file of files) {
238
+ const relativePath = path.relative(process.cwd(), file);
239
+ const destPath = path.join(outputDir, relativePath);
240
+
241
+ const destDir = path.dirname(destPath);
242
+ if (!fs.existsSync(destDir)) {
243
+ fs.mkdirSync(destDir, { recursive: true });
244
+ }
245
+
246
+ try {
247
+ fs.copyFileSync(file, destPath);
248
+ copied++;
249
+ } catch (err) {
250
+ console.warn(`Warning: Could not copy ${file}: ${err.message}`);
251
+ }
252
+ }
253
+
254
+ console.log(`✓ Copied ${copied} file(s) to ${outputDir}/`);
255
+ ```
256
+
257
+ **Step 2: Закоммитить скрипт копирования**
258
+
259
+ ```bash
260
+ git add template/scripts/copy-static.js
261
+ git commit -m "feat: add copy-static script for handling static files"
262
+ ```
263
+
264
+ ---
265
+
266
+ ## Task 3: CLI инициализатор (index.js)
267
+
268
+ **Files:**
269
+ - Create: `index.js`
270
+ - Create: `package.json` (мета-пакета)
271
+
272
+ **Step 1: Создать index.js**
273
+
274
+ ```javascript
275
+ #!/usr/bin/env node
276
+
277
+ const fs = require('fs');
278
+ const path = require('path');
279
+ const { spawnSync } = require('child_process');
280
+
281
+ const projectName = process.argv[2];
282
+
283
+ if (!projectName) {
284
+ console.error('Please provide a project name:');
285
+ console.error(' npx create-marp-presentation <project-name>');
286
+ process.exit(1);
287
+ }
288
+
289
+ // Валидация имени проекта
290
+ const validName = /^[a-z0-9][a-z0-9-]*[a-z0-9]$|^[a-z0-9]$/;
291
+ if (!validName.test(projectName)) {
292
+ console.error(`Invalid project name: "${projectName}"`);
293
+ console.error('Project name must be lowercase, contain only letters, numbers, and hyphens.');
294
+ process.exit(1);
295
+ }
296
+
297
+ const projectPath = path.resolve(projectName);
298
+
299
+ // Проверка существования папки
300
+ if (fs.existsSync(projectPath)) {
301
+ console.error(`Directory "${projectName}" already exists.`);
302
+ process.exit(1);
303
+ }
304
+
305
+ // Получаем путь к template
306
+ const templatePath = path.join(__dirname, 'template');
307
+
308
+ console.log(`Creating Marp presentation: ${projectName}`);
309
+ console.log();
310
+
311
+ try {
312
+ // Создаём папку проекта
313
+ fs.mkdirSync(projectPath, { recursive: true });
314
+
315
+ // Рекурсивно копируем template
316
+ const copyDir = (src, dest) => {
317
+ const entries = fs.readdirSync(src, { withFileTypes: true });
318
+
319
+ for (const entry of entries) {
320
+ const srcPath = path.join(src, entry.name);
321
+ const destPath = path.join(dest, entry.name);
322
+
323
+ if (entry.isDirectory()) {
324
+ fs.mkdirSync(destPath, { recursive: true });
325
+ copyDir(srcPath, destPath);
326
+ } else {
327
+ fs.copyFileSync(srcPath, destPath);
328
+ }
329
+ }
330
+ };
331
+
332
+ copyDir(templatePath, projectPath);
333
+
334
+ console.log('✓ Project created');
335
+ console.log();
336
+
337
+ // Запускаем npm install
338
+ console.log('Installing dependencies...');
339
+ const installResult = spawnSync('npm', ['install'], {
340
+ cwd: projectPath,
341
+ stdio: 'inherit',
342
+ shell: true,
343
+ });
344
+
345
+ if (installResult.status !== 0) {
346
+ console.error();
347
+ console.error('Failed to install dependencies.');
348
+ console.error('Please run "cd ' + projectName + ' && npm install" manually.');
349
+ process.exit(1);
350
+ }
351
+
352
+ console.log();
353
+ console.log('✓ Dependencies installed');
354
+ console.log();
355
+ console.log('Next steps:');
356
+ console.log(` cd ${projectName}`);
357
+ console.log(' npm run dev # Start live preview');
358
+ console.log(' npm run build:all # Build all formats');
359
+ console.log();
360
+
361
+ } catch (err) {
362
+ console.error('Error creating project:', err.message);
363
+ process.exit(1);
364
+ }
365
+ ```
366
+
367
+ **Step 2: Создать package.json мета-пакета**
368
+
369
+ ```json
370
+ {
371
+ "name": "create-marp-presentation",
372
+ "version": "1.0.0",
373
+ "description": "Create a new Marp presentation project with one command",
374
+ "bin": "./index.js",
375
+ "files": [
376
+ "index.js",
377
+ "template/"
378
+ ],
379
+ "keywords": [
380
+ "marp",
381
+ "presentation",
382
+ "markdown",
383
+ "slides",
384
+ "template",
385
+ "cli"
386
+ ],
387
+ "author": "",
388
+ "license": "MIT",
389
+ "engines": {
390
+ "node": ">=20.0.0"
391
+ }
392
+ }
393
+ ```
394
+
395
+ **Step 3: Добавить shebang и сделать index.js исполняемым**
396
+
397
+ ```bash
398
+ chmod +x index.js
399
+ ```
400
+
401
+ **Step 4: Закоммитить CLI**
402
+
403
+ ```bash
404
+ git add index.js package.json
405
+ git commit -m "feat: add CLI initializer with project scaffolding"
406
+ ```
407
+
408
+ ---
409
+
410
+ ## Task 4: Тестирование CLI инициализатора
411
+
412
+ **Files:**
413
+ - Create: `tests/cli.test.js`
414
+
415
+ **Step 1: Установить зависимости для тестирования**
416
+
417
+ ```bash
418
+ npm install --save-dev jest@^29.7.0
419
+ ```
420
+
421
+ **Step 2: Создать tests/cli.test.js**
422
+
423
+ ```javascript
424
+ const fs = require('fs');
425
+ const path = require('path');
426
+ const { spawnSync } = require('child_process');
427
+
428
+ describe('CLI Initializer', () => {
429
+ const testProjects = [];
430
+
431
+ afterEach(() => {
432
+ // Очистка тестовых проектов
433
+ for (const project of testProjects) {
434
+ if (fs.existsSync(project)) {
435
+ fs.rmSync(project, { recursive: true, force: true });
436
+ }
437
+ }
438
+ });
439
+
440
+ test('должен создать структуру проекта', () => {
441
+ const projectName = 'test-presentation';
442
+ testProjects.push(projectName);
443
+
444
+ const result = spawnSync('node', ['index.js', projectName], {
445
+ cwd: __dirname + '/..',
446
+ });
447
+
448
+ expect(result.status).toBe(0);
449
+ expect(fs.existsSync(path.join(projectName, 'package.json'))).toBe(true);
450
+ expect(fs.existsSync(path.join(projectName, 'marp.config.js'))).toBe(true);
451
+ expect(fs.existsSync(path.join(projectName, 'presentation.md'))).toBe(true);
452
+ expect(fs.existsSync(path.join(projectName, '.gitignore'))).toBe(true);
453
+ expect(fs.existsSync(path.join(projectName, 'README.md'))).toBe(true);
454
+ expect(fs.existsSync(path.join(projectName, 'static'))).toBe(true);
455
+ expect(fs.existsSync(path.join(projectName, 'scripts', 'copy-static.js'))).toBe(true);
456
+ });
457
+
458
+ test('должен отклонить невалидное имя проекта', () => {
459
+ const result = spawnSync('node', ['index.js', 'Invalid_Name'], {
460
+ cwd: __dirname + '/..',
461
+ });
462
+
463
+ expect(result.status).toBe(1);
464
+ expect(result.stderr.toString()).toContain('Invalid project name');
465
+ });
466
+
467
+ test('должен отклонить существующую папку', () => {
468
+ const projectName = 'existing-project';
469
+ testProjects.push(projectName);
470
+ fs.mkdirSync(projectName);
471
+
472
+ const result = spawnSync('node', ['index.js', projectName], {
473
+ cwd: __dirname + '/..',
474
+ });
475
+
476
+ expect(result.status).toBe(1);
477
+ expect(result.stderr.toString()).toContain('already exists');
478
+ });
479
+
480
+ test('должен требовать имя проекта', () => {
481
+ const result = spawnSync('node', ['index.js'], {
482
+ cwd: __dirname + '/..',
483
+ });
484
+
485
+ expect(result.status).toBe(1);
486
+ expect(result.stderr.toString()).toContain('Please provide a project name');
487
+ });
488
+ });
489
+ ```
490
+
491
+ **Step 3: Добавить jest секцию в package.json**
492
+
493
+ ```json
494
+ {
495
+ "scripts": {
496
+ "test": "jest"
497
+ },
498
+ "jest": {
499
+ "testEnvironment": "node",
500
+ "testMatch": ["**/tests/**/*.test.js"]
501
+ }
502
+ }
503
+ ```
504
+
505
+ **Step 4: Запустить тесты**
506
+
507
+ ```bash
508
+ npm test
509
+ ```
510
+
511
+ Ожидается: PASS
512
+
513
+ **Step 5: Закоммитить тесты**
514
+
515
+ ```bash
516
+ git add tests/ package.json
517
+ git commit -m "test: add CLI initializer tests"
518
+ ```
519
+
520
+ ---
521
+
522
+ ## Task 5: Тестирование скрипта копирования статики
523
+
524
+ **Files:**
525
+ - Create: `tests/copy-static.test.js`
526
+
527
+ **Step 1: Создать tests/copy-static.test.js**
528
+
529
+ ```javascript
530
+ const fs = require('fs');
531
+ const path = require('path');
532
+ const { execSync } = require('child_process');
533
+
534
+ describe('copy-static script', () => {
535
+ const testDir = path.join(__dirname, 'fixtures', 'copy-static');
536
+ const outputDir = path.join(testDir, 'output');
537
+
538
+ beforeEach(() => {
539
+ // Создаём тестовую структуру
540
+ fs.mkdirSync(testDir, { recursive: true });
541
+ fs.mkdirSync(path.join(testDir, 'static', 'images'), { recursive: true });
542
+ fs.mkdirSync(path.join(testDir, 'assets'), { recursive: true });
543
+
544
+ // Создаём тестовые файлы
545
+ fs.writeFileSync(path.join(testDir, 'static', 'image.png'), 'fake png');
546
+ fs.writeFileSync(path.join(testDir, 'static', 'images', 'photo.jpg'), 'fake jpg');
547
+ fs.writeFileSync(path.join(testDir, 'assets', 'style.css'), 'body {}');
548
+
549
+ // Создаём marp.config.js
550
+ fs.writeFileSync(
551
+ path.join(testDir, 'marp.config.js'),
552
+ `module.exports = {
553
+ staticFolders: ['static/**', 'assets/**'],
554
+ outputDir: 'output',
555
+ };`
556
+ );
557
+ });
558
+
559
+ afterEach(() => {
560
+ // Очистка
561
+ if (fs.existsSync(testDir)) {
562
+ fs.rmSync(testDir, { recursive: true, force: true });
563
+ }
564
+ });
565
+
566
+ test('должен копировать файлы по паттернам', () => {
567
+ // Копируем скрипт в тестовую директорию
568
+ fs.mkdirSync(path.join(testDir, 'scripts'), { recursive: true });
569
+ fs.copyFileSync(
570
+ path.join(__dirname, '..', 'template', 'scripts', 'copy-static.js'),
571
+ path.join(testDir, 'scripts', 'copy-static.js')
572
+ );
573
+
574
+ // Запускаем скрипт
575
+ execSync('node scripts/copy-static.js', { cwd: testDir });
576
+
577
+ // Проверяем результат
578
+ expect(fs.existsSync(outputDir)).toBe(true);
579
+ expect(fs.existsSync(path.join(outputDir, 'static', 'image.png'))).toBe(true);
580
+ expect(fs.existsSync(path.join(outputDir, 'static', 'images', 'photo.jpg'))).toBe(true);
581
+ expect(fs.existsSync(path.join(outputDir, 'assets', 'style.css'))).toBe(true);
582
+ });
583
+
584
+ test('должен работать с дефолтной конфигурацией без marp.config.js', () => {
585
+ // Удаляем marp.config.js для проверки дефолтных значений
586
+ fs.unlinkSync(path.join(testDir, 'marp.config.js'));
587
+
588
+ // Создаём static папку (дефолт)
589
+ fs.mkdirSync(path.join(testDir, 'static'), { recursive: true });
590
+ fs.writeFileSync(path.join(testDir, 'static', 'test.txt'), 'content');
591
+
592
+ // Копируем скрипт
593
+ fs.mkdirSync(path.join(testDir, 'scripts'), { recursive: true });
594
+ fs.copyFileSync(
595
+ path.join(__dirname, '..', 'template', 'scripts', 'copy-static.js'),
596
+ path.join(testDir, 'scripts', 'copy-static.js')
597
+ );
598
+
599
+ // Запускаем
600
+ execSync('node scripts/copy-static.js', { cwd: testDir });
601
+
602
+ // Проверяем
603
+ expect(fs.existsSync(path.join(outputDir, 'static', 'test.txt'))).toBe(true);
604
+ });
605
+ });
606
+ ```
607
+
608
+ **Step 2: Запустить тесты**
609
+
610
+ ```bash
611
+ npm test
612
+ ```
613
+
614
+ Ожидается: PASS
615
+
616
+ **Step 3: Закоммитить тесты копирования статики**
617
+
618
+ ```bash
619
+ git add tests/copy-static.test.js
620
+ git commit -m "test: add copy-static script tests"
621
+ ```
622
+
623
+ ---
624
+
625
+ ## Task 6: Интеграционное тестирование
626
+
627
+ **Step 1: Создать тестовый проект через CLI**
628
+
629
+ ```bash
630
+ node index.js test-integration
631
+ cd test-integration
632
+ ```
633
+
634
+ **Step 2: Проверить npm run dev**
635
+
636
+ Запустить:
637
+ ```bash
638
+ npm run dev
639
+ ```
640
+
641
+ Проверить: открывается браузер с live preview
642
+
643
+ Остановить: Ctrl+C
644
+
645
+ **Step 3: Создать статический файл для теста**
646
+
647
+ ```bash
648
+ echo "test content" > static/test.txt
649
+ ```
650
+
651
+ **Step 4: Проверить сборку HTML**
652
+
653
+ ```bash
654
+ npm run build:html
655
+ ```
656
+
657
+ Проверить:
658
+ - `output/index.html` существует
659
+ - `output/static/test.txt` скопирован
660
+
661
+ **Step 5: Проверить сборку всех форматов**
662
+
663
+ ```bash
664
+ npm run build:all
665
+ ```
666
+
667
+ Проверить:
668
+ - `output/index.html` существует
669
+ - `output/presentation.pdf` существует
670
+ - `output/presentation.pptx` существует
671
+ - Статика скопирована
672
+
673
+ **Step 6: Проверить очистку**
674
+
675
+ ```bash
676
+ npm run clean
677
+ ```
678
+
679
+ Проверить: `output/` удалена
680
+
681
+ **Step 7: Удалить тестовый проект**
682
+
683
+ ```bash
684
+ cd ..
685
+ rm -rf test-integration
686
+ ```
687
+
688
+ **Step 8: Закоммитить если были исправления**
689
+
690
+ ```bash
691
+ git add -A
692
+ git commit -m "fix: fixes from integration testing"
693
+ ```
694
+
695
+ ---
696
+
697
+ ## Task 7: Подготовка к публикации
698
+
699
+ **Step 1: Создать README.md для мета-пакета**
700
+
701
+ ```markdown
702
+ # Create Marp Presentation
703
+
704
+ Создайте новую Marp презентацию одной командой.
705
+
706
+ ## Установка
707
+
708
+ \`\`\`bash
709
+ npx create-marp-presentation my-presentation
710
+ \`\`\`
711
+
712
+ ## Использование
713
+
714
+ \`\`\`bash
715
+ cd my-presentation
716
+ npm run dev # Live preview
717
+ npm run build:all # Build all formats
718
+ \`\`\`
719
+
720
+ ## Возможности
721
+
722
+ - 🚀 One-command setup
723
+ - 📝 Markdown slides
724
+ - 🎨 Marp themes
725
+ - 📦 HTML, PDF, PPTX export
726
+ - 📁 Static files support
727
+ - 🔥 Live preview
728
+
729
+ ## Документация
730
+
731
+ После создания проекта читайте README в папке проекта.
732
+
733
+ ## Лицензия
734
+
735
+ MIT
736
+ ```
737
+
738
+ **Step 2: Создать LICENSE**
739
+
740
+ ```bash
741
+ # MIT License
742
+
743
+ Copyright (c) 2025
744
+
745
+ Permission is hereby granted, free of charge, to any person obtaining a copy
746
+ of this software and associated documentation files (the "Software"), to deal
747
+ in the Software without restriction, including without limitation the rights
748
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
749
+ copies of the Software, and to permit persons to whom the Software is
750
+ furnished to do so, subject to the following conditions:
751
+
752
+ The above copyright notice and this permission notice shall be included in all
753
+ copies or substantial portions of the Software.
754
+
755
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
756
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
757
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
758
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
759
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
760
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
761
+ SOFTWARE.
762
+ ```
763
+
764
+ **Step 3: Обновить package.json с полями для публикации**
765
+
766
+ ```json
767
+ {
768
+ "name": "create-marp-presentation",
769
+ "version": "1.0.0",
770
+ "description": "Create a new Marp presentation project with one command",
771
+ "bin": "./index.js",
772
+ "files": [
773
+ "index.js",
774
+ "template/"
775
+ ],
776
+ "keywords": [
777
+ "marp",
778
+ "presentation",
779
+ "markdown",
780
+ "slides",
781
+ "template",
782
+ "cli"
783
+ ],
784
+ "author": "",
785
+ "license": "MIT",
786
+ "repository": {
787
+ "type": "git",
788
+ "url": "https://github.com/YOUR_USERNAME/create-marp-presentation.git"
789
+ },
790
+ "homepage": "https://github.com/YOUR_USERNAME/create-marp-presentation#readme",
791
+ "bugs": {
792
+ "url": "https://github.com/YOUR_USERNAME/create-marp-presentation/issues"
793
+ },
794
+ "engines": {
795
+ "node": ">=20.0.0"
796
+ }
797
+ }
798
+ ```
799
+
800
+ **Step 4: Закоммитить финальные файлы**
801
+
802
+ ```bash
803
+ git add README.md LICENSE package.json
804
+ git commit -m "docs: add README and LICENSE for npm publication"
805
+ ```
806
+
807
+ ---
808
+
809
+ ## Task 8: Публикация в npm
810
+
811
+ **Step 1: Проверить версию**
812
+
813
+ ```bash
814
+ npm version patch
815
+ ```
816
+
817
+ **Step 2: Запустить все тесты**
818
+
819
+ ```bash
820
+ npm test
821
+ ```
822
+
823
+ **Step 3: Опционально: dry-run публикации**
824
+
825
+ ```bash
826
+ npm publish --dry-run
827
+ ```
828
+
829
+ **Step 4: Опубликовать в npm**
830
+
831
+ ```bash
832
+ npm publish
833
+ ```
834
+
835
+ **Step 5: Проверить установку**
836
+
837
+ ```bash
838
+ npx create-marp-presentation test-install
839
+ ```
840
+
841
+ **Step 6: Закоммитить версию**
842
+
843
+ ```bash
844
+ git add package.json package-lock.json
845
+ git commit -m "chore: bump version to 1.0.0"
846
+ git tag v1.0.0
847
+ git push && git push --tags
848
+ ```